summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--apct-tests/perftests/contentcapture/src/android/view/contentcapture/MyContentCaptureService.java11
-rw-r--r--apct-tests/perftests/core/src/android/app/ResourcesManagerPerfTest.java19
-rw-r--r--apct-tests/perftests/utils/src/android/perftests/utils/BenchmarkState.java43
-rw-r--r--apct-tests/perftests/windowmanager/AndroidManifest.xml4
-rw-r--r--apct-tests/perftests/windowmanager/AndroidTest.xml4
-rw-r--r--apct-tests/perftests/windowmanager/README.md8
-rw-r--r--apct-tests/perftests/windowmanager/src/android/wm/InternalWindowOperationPerfTest.java40
-rw-r--r--apct-tests/perftests/windowmanager/src/android/wm/RecentsAnimationPerfTest.java20
-rw-r--r--apct-tests/perftests/windowmanager/src/android/wm/RelayoutPerfTest.java18
-rw-r--r--apct-tests/perftests/windowmanager/src/android/wm/WindowAddRemovePerfTest.java6
-rw-r--r--apct-tests/perftests/windowmanager/src/android/wm/WindowManagerPerfTestBase.java36
-rw-r--r--apct-tests/perftests/windowmanager/src/android/wm/WmPerfRunListener.java29
-rw-r--r--apex/jobscheduler/service/java/com/android/server/alarm/Alarm.java211
-rw-r--r--apex/jobscheduler/service/java/com/android/server/alarm/AlarmManagerService.java1580
-rw-r--r--apex/jobscheduler/service/java/com/android/server/alarm/AlarmStore.java127
-rw-r--r--apex/jobscheduler/service/java/com/android/server/alarm/BatchingAlarmStore.java379
-rw-r--r--apex/jobscheduler/service/java/com/android/server/job/controllers/ConnectivityController.java71
-rw-r--r--apex/jobscheduler/service/java/com/android/server/usage/AppStandbyController.java2
-rw-r--r--apex/statsd/Android.bp4
-rw-r--r--api/current.txt24
-rwxr-xr-xapi/system-current.txt65
-rw-r--r--api/test-current.txt56
-rw-r--r--cmds/idmap2/tests/ResultTests.cpp3
-rw-r--r--cmds/statsd/src/condition/CombinationConditionTracker.cpp48
-rw-r--r--cmds/statsd/src/condition/CombinationConditionTracker.h10
-rw-r--r--cmds/statsd/src/condition/ConditionTracker.h41
-rw-r--r--cmds/statsd/src/condition/SimpleConditionTracker.cpp98
-rw-r--r--cmds/statsd/src/condition/SimpleConditionTracker.h19
-rw-r--r--cmds/statsd/src/metrics/CountMetricProducer.cpp5
-rw-r--r--cmds/statsd/src/metrics/CountMetricProducer.h6
-rw-r--r--cmds/statsd/src/metrics/DurationMetricProducer.cpp7
-rw-r--r--cmds/statsd/src/metrics/DurationMetricProducer.h9
-rw-r--r--cmds/statsd/src/metrics/EventMetricProducer.cpp5
-rw-r--r--cmds/statsd/src/metrics/EventMetricProducer.h6
-rw-r--r--cmds/statsd/src/metrics/GaugeMetricProducer.cpp9
-rw-r--r--cmds/statsd/src/metrics/GaugeMetricProducer.h13
-rw-r--r--cmds/statsd/src/metrics/MetricProducer.cpp3
-rw-r--r--cmds/statsd/src/metrics/MetricProducer.h21
-rw-r--r--cmds/statsd/src/metrics/MetricsManager.cpp19
-rw-r--r--cmds/statsd/src/metrics/MetricsManager.h11
-rw-r--r--cmds/statsd/src/metrics/ValueMetricProducer.cpp53
-rw-r--r--cmds/statsd/src/metrics/ValueMetricProducer.h44
-rw-r--r--cmds/statsd/src/metrics/parsing_utils/config_update_utils.cpp247
-rw-r--r--cmds/statsd/src/metrics/parsing_utils/config_update_utils.h90
-rw-r--r--cmds/statsd/src/metrics/parsing_utils/metrics_manager_util.cpp193
-rw-r--r--cmds/statsd/src/metrics/parsing_utils/metrics_manager_util.h23
-rw-r--r--cmds/statsd/tests/condition/SimpleConditionTracker_test.cpp18
-rw-r--r--cmds/statsd/tests/metrics/CountMetricProducer_test.cpp19
-rw-r--r--cmds/statsd/tests/metrics/DurationMetricProducer_test.cpp61
-rw-r--r--cmds/statsd/tests/metrics/EventMetricProducer_test.cpp12
-rw-r--r--cmds/statsd/tests/metrics/GaugeMetricProducer_test.cpp52
-rw-r--r--cmds/statsd/tests/metrics/ValueMetricProducer_test.cpp795
-rw-r--r--cmds/statsd/tests/metrics/parsing_utils/config_update_utils_test.cpp495
-rw-r--r--cmds/statsd/tests/metrics/parsing_utils/metrics_manager_util_test.cpp190
-rw-r--r--config/Android.bp4
-rwxr-xr-xconfig/generate-preloaded-classes.sh6
-rw-r--r--config/preloaded-classes-denylist (renamed from config/preloaded-classes-blacklist)0
-rw-r--r--core/java/android/app/ActivityThread.java10
-rw-r--r--core/java/android/app/AppOpsManager.java25
-rw-r--r--core/java/android/app/ApplicationPackageManager.java44
-rw-r--r--core/java/android/app/ContextImpl.java20
-rw-r--r--core/java/android/app/IActivityManager.aidl10
-rw-r--r--core/java/android/app/Notification.java6
-rw-r--r--core/java/android/app/ResourcesManager.java36
-rw-r--r--core/java/android/app/SystemServiceRegistry.java10
-rw-r--r--core/java/android/app/admin/DevicePolicyManager.java18
-rw-r--r--core/java/android/app/admin/IDevicePolicyManager.aidl1
-rw-r--r--core/java/android/app/prediction/AppPredictor.java4
-rw-r--r--core/java/android/app/prediction/IPredictionManager.aidl2
-rw-r--r--core/java/android/app/timezonedetector/ITimeZoneConfigurationListener.aidl2
-rw-r--r--core/java/android/app/timezonedetector/ITimeZoneDetectorService.aidl6
-rw-r--r--core/java/android/app/timezonedetector/TEST_MAPPING12
-rw-r--r--core/java/android/app/timezonedetector/TimeZoneCapabilities.java109
-rw-r--r--core/java/android/app/timezonedetector/TimeZoneConfiguration.java148
-rw-r--r--core/java/android/app/timezonedetector/TimeZoneDetector.java42
-rw-r--r--core/java/android/app/timezonedetector/TimeZoneDetectorImpl.java21
-rw-r--r--core/java/android/companion/TEST_MAPPING12
-rw-r--r--core/java/android/content/Context.java11
-rw-r--r--core/java/android/content/pm/FileChecksum.aidl20
-rw-r--r--core/java/android/content/pm/FileChecksum.java238
-rw-r--r--core/java/android/content/pm/IPackageManager.aidl2
-rw-r--r--core/java/android/content/pm/PackageInstaller.java20
-rw-r--r--core/java/android/content/pm/PackageManager.java130
-rw-r--r--core/java/android/content/pm/RegisteredServicesCache.java6
-rw-r--r--core/java/android/inputmethodservice/InputMethodService.java14
-rw-r--r--core/java/android/inputmethodservice/TEST_MAPPING7
-rw-r--r--core/java/android/net/SocketKeepalive.java6
-rw-r--r--core/java/android/os/BinderProxy.java14
-rw-r--r--core/java/android/os/Process.java2
-rw-r--r--core/java/android/os/UserManager.java56
-rw-r--r--core/java/android/os/image/DynamicSystemManager.java13
-rw-r--r--core/java/android/os/image/IDynamicSystemService.aidl7
-rw-r--r--core/java/android/os/incremental/IIncrementalService.aidl13
-rw-r--r--core/java/android/os/incremental/IncrementalStorage.java31
-rw-r--r--core/java/android/preference/DialogPreference.java23
-rw-r--r--core/java/android/preference/EditTextPreference.java18
-rw-r--r--core/java/android/preference/OWNERS1
-rw-r--r--core/java/android/provider/CallLog.java2
-rw-r--r--core/java/android/provider/DocumentsProvider.java17
-rw-r--r--core/java/android/provider/Settings.java11
-rw-r--r--core/java/android/speech/tts/TextToSpeech.java33
-rw-r--r--core/java/android/telephony/PhoneStateListener.java18
-rw-r--r--core/java/android/text/OWNERS3
-rw-r--r--core/java/android/util/apk/ApkSignatureSchemeV2Verifier.java2
-rw-r--r--core/java/android/util/apk/ApkSignatureSchemeV3Verifier.java2
-rw-r--r--core/java/android/util/apk/ApkSignatureVerifier.java73
-rw-r--r--core/java/android/util/apk/ApkSigningBlockUtils.java73
-rw-r--r--core/java/android/util/apk/SignatureInfo.java13
-rw-r--r--core/java/android/util/apk/VerityBuilder.java62
-rw-r--r--core/java/android/view/FrameMetrics.java7
-rw-r--r--core/java/android/view/InputEventReceiver.java14
-rw-r--r--core/java/android/view/NotificationHeaderView.java4
-rw-r--r--core/java/android/view/ViewRootImpl.java77
-rw-r--r--core/java/android/view/WindowManager.java6
-rw-r--r--core/java/android/view/accessibility/IWindowMagnificationConnection.aidl8
-rw-r--r--core/java/android/view/inputmethod/TEST_MAPPING18
-rw-r--r--core/java/android/widget/ProgressBar.java8
-rw-r--r--core/java/android/window/ITaskOrganizerController.aidl3
-rw-r--r--core/java/android/window/TaskOrganizer.java5
-rw-r--r--core/java/android/window/TaskOrganizerTaskEmbedder.java2
-rw-r--r--core/java/com/android/internal/config/sysui/SystemUiDeviceConfigFlags.java5
-rw-r--r--core/java/com/android/internal/content/FileSystemProvider.java11
-rw-r--r--core/java/com/android/internal/jank/FrameTracker.java223
-rw-r--r--core/java/com/android/internal/jank/InteractionJankMonitor.java203
-rw-r--r--core/java/com/android/internal/jank/PerfettoTrigger.java115
-rw-r--r--core/java/com/android/internal/protolog/BaseProtoLogImpl.java397
-rw-r--r--core/java/com/android/internal/protolog/ProtoLogGroup.java15
-rw-r--r--core/java/com/android/internal/protolog/ProtoLogImpl.java371
-rw-r--r--core/java/com/android/internal/protolog/ProtoLogViewerConfigReader.java89
-rw-r--r--core/java/com/android/internal/util/LatencyTracker.java50
-rw-r--r--core/java/com/android/internal/util/StatLogger.java13
-rw-r--r--core/java/com/android/internal/view/ScrollCaptureViewHelper.java37
-rw-r--r--core/java/com/android/internal/view/ScrollCaptureViewSupport.java94
-rw-r--r--core/java/com/android/internal/view/ScrollViewCaptureHelper.java40
-rw-r--r--core/java/com/android/internal/widget/LocalImageResolver.java17
-rw-r--r--core/java/com/android/internal/widget/LockPatternUtils.java6
-rw-r--r--core/jni/android_hardware_camera2_CameraMetadata.cpp21
-rw-r--r--core/jni/android_media_AudioSystem.cpp83
-rw-r--r--core/jni/android_media_AudioTrack.cpp76
-rw-r--r--core/jni/android_util_Process.cpp19
-rw-r--r--core/jni/android_view_InputEventReceiver.cpp118
-rw-r--r--core/jni/android_view_KeyCharacterMap.cpp54
-rw-r--r--core/jni/android_view_KeyCharacterMap.h2
-rw-r--r--core/jni/android_view_KeyEvent.cpp1
-rw-r--r--core/jni/android_view_MotionEvent.cpp5
-rw-r--r--core/proto/android/app/settings_enums.proto10
-rw-r--r--core/res/AndroidManifest.xml3
-rw-r--r--core/res/res/values-cs/strings.xml6
-rw-r--r--core/res/res/values-da/strings.xml2
-rw-r--r--core/res/res/values-eu/strings.xml4
-rw-r--r--core/res/res/values-in/strings.xml2
-rw-r--r--core/res/res/values-ne/strings.xml16
-rw-r--r--core/tests/coretests/src/android/app/timezonedetector/TimeZoneCapabilitiesTest.java84
-rw-r--r--core/tests/coretests/src/android/app/timezonedetector/TimeZoneConfigurationTest.java53
-rw-r--r--core/tests/coretests/src/android/text/OWNERS3
-rw-r--r--core/tests/coretests/src/android/view/ViewRootImplTest.java11
-rw-r--r--core/tests/coretests/src/com/android/internal/jank/FrameTrackerTest.java184
-rw-r--r--core/tests/coretests/src/com/android/internal/jank/InteractionJankMonitorTest.java120
-rw-r--r--core/tests/coretests/src/com/android/internal/view/ScrollViewCaptureHelperTest.java200
-rw-r--r--core/tests/hosttests/test-apps/MultiDexLegacyTestApp/Android.mk4
-rw-r--r--core/tests/hosttests/test-apps/MultiDexLegacyTestServices/Android.mk2
-rw-r--r--core/tests/hosttests/test-apps/MultiDexLegacyVersionedTestApp_v1/Android.mk2
-rw-r--r--core/tests/hosttests/test-apps/MultiDexLegacyVersionedTestApp_v2/Android.mk2
-rw-r--r--core/tests/hosttests/test-apps/MultiDexLegacyVersionedTestApp_v3/Android.mk2
-rw-r--r--data/etc/services.core.protolog.json581
-rw-r--r--data/keyboards/Generic.kcm26
-rw-r--r--graphics/java/android/graphics/Bitmap.java4
-rw-r--r--keystore/TEST_MAPPING74
-rw-r--r--libs/WindowManager/Shell/Android.bp89
-rw-r--r--libs/WindowManager/Shell/proto/wm_shell_trace.proto (renamed from libs/WindowManager/Shell/tests/src/com/android/wm/shell/WindowManagerShellTest.java)23
-rw-r--r--libs/WindowManager/Shell/res/anim/forced_resizable_enter.xml (renamed from packages/SystemUI/res/anim/forced_resizable_enter.xml)0
-rw-r--r--libs/WindowManager/Shell/res/anim/forced_resizable_exit.xml (renamed from packages/SystemUI/res/anim/forced_resizable_exit.xml)0
-rw-r--r--libs/WindowManager/Shell/res/layout/divider.xml (renamed from packages/SystemUI/res/layout/divider.xml)0
-rw-r--r--libs/WindowManager/Shell/res/layout/docked_stack_divider.xml (renamed from packages/SystemUI/res/layout/docked_stack_divider.xml)8
-rw-r--r--libs/WindowManager/Shell/res/layout/forced_resizable_activity.xml (renamed from packages/SystemUI/res/layout/forced_resizable_activity.xml)0
-rw-r--r--libs/WindowManager/Shell/res/layout/pip_menu.xml (renamed from libs/WindowManager/Shell/res/layout/pip_menu_activity.xml)0
-rw-r--r--libs/WindowManager/Shell/res/raw/wm_shell_protolog.json46
-rw-r--r--libs/WindowManager/Shell/res/values-land/dimens.xml21
-rw-r--r--libs/WindowManager/Shell/res/values-land/styles.xml35
-rw-r--r--libs/WindowManager/Shell/res/values-sw600dp/config.xml25
-rw-r--r--libs/WindowManager/Shell/res/values/colors.xml25
-rw-r--r--libs/WindowManager/Shell/res/values/config.xml3
-rw-r--r--libs/WindowManager/Shell/res/values/dimen.xml6
-rw-r--r--libs/WindowManager/Shell/res/values/ids.xml7
-rw-r--r--libs/WindowManager/Shell/res/values/strings.xml35
-rw-r--r--libs/WindowManager/Shell/res/values/styles.xml49
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/ShellTaskOrganizer.java22
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/animation/FlingAnimationUtils.java (renamed from packages/SystemUI/src/com/android/systemui/statusbar/FlingAnimationUtils.java)134
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/animation/Interpolators.java45
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/common/SyncTransactionQueue.java (renamed from packages/SystemUI/src/com/android/systemui/stackdivider/SyncTransactionQueue.java)25
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/protolog/ShellProtoLogGroup.java92
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/protolog/ShellProtoLogImpl.java138
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/DividerHandleView.java (renamed from packages/SystemUI/src/com/android/systemui/stackdivider/DividerHandleView.java)68
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/DividerImeController.java (renamed from packages/SystemUI/src/com/android/systemui/stackdivider/DividerImeController.java)5
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/DividerState.java (renamed from packages/SystemUI/src/com/android/systemui/stackdivider/DividerState.java)6
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/DividerView.java (renamed from packages/SystemUI/src/com/android/systemui/stackdivider/DividerView.java)45
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/DividerWindowManager.java (renamed from packages/SystemUI/src/com/android/systemui/stackdivider/DividerWindowManager.java)16
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/ForcedResizableInfoActivity.java (renamed from packages/SystemUI/src/com/android/systemui/stackdivider/ForcedResizableInfoActivity.java)6
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/ForcedResizableInfoActivityController.java (renamed from packages/SystemUI/src/com/android/systemui/stackdivider/ForcedResizableInfoActivityController.java)24
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/MinimizedDockShadow.java (renamed from packages/SystemUI/src/com/android/systemui/stackdivider/MinimizedDockShadow.java)8
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/SplitDisplayLayout.java (renamed from packages/SystemUI/src/com/android/systemui/stackdivider/SplitDisplayLayout.java)2
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/SplitScreen.java91
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/SplitScreenController.java (renamed from packages/SystemUI/src/com/android/systemui/stackdivider/SplitScreenController.java)35
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/SplitScreenTaskOrganizer.java (renamed from packages/SystemUI/src/com/android/systemui/stackdivider/SplitScreenTaskOrganizer.java)2
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/WindowManagerProxy.java (renamed from packages/SystemUI/src/com/android/systemui/stackdivider/WindowManagerProxy.java)3
-rw-r--r--libs/WindowManager/Shell/tests/README.md15
-rw-r--r--libs/WindowManager/Shell/tests/flicker/Android.bp34
-rw-r--r--libs/WindowManager/Shell/tests/flicker/AndroidManifest.xml43
-rw-r--r--libs/WindowManager/Shell/tests/flicker/AndroidTest.xml40
-rw-r--r--libs/WindowManager/Shell/tests/flicker/README.md10
-rw-r--r--libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/CommonAssertions.kt153
-rw-r--r--libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/FlickerTestBase.kt130
-rw-r--r--libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/NonRotationTestBase.kt36
-rw-r--r--libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/helpers/FlickerAppHelper.kt31
-rw-r--r--libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/helpers/PipAppHelper.kt45
-rw-r--r--libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/EnterPipTest.kt121
-rw-r--r--libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/PipTestBase.kt31
-rw-r--r--libs/WindowManager/Shell/tests/flicker/test-apps/Android.bp0
-rw-r--r--libs/WindowManager/Shell/tests/flicker/test-apps/flickerapp/Android.bp20
-rw-r--r--libs/WindowManager/Shell/tests/flicker/test-apps/flickerapp/AndroidManifest.xml37
-rw-r--r--libs/WindowManager/Shell/tests/flicker/test-apps/flickerapp/res/layout/activity_pip.xml26
-rw-r--r--libs/WindowManager/Shell/tests/flicker/test-apps/flickerapp/src/com/android/wm/shell/flicker/testapp/PipActivity.java45
-rw-r--r--libs/WindowManager/Shell/tests/unittest/Android.bp (renamed from libs/WindowManager/Shell/tests/Android.bp)2
-rw-r--r--libs/WindowManager/Shell/tests/unittest/AndroidManifest.xml (renamed from libs/WindowManager/Shell/tests/AndroidManifest.xml)0
-rw-r--r--libs/WindowManager/Shell/tests/unittest/AndroidTest.xml (renamed from libs/WindowManager/Shell/tests/AndroidTest.xml)4
-rw-r--r--libs/WindowManager/Shell/tests/unittest/res/values/config.xml (renamed from libs/WindowManager/Shell/tests/res/values/config.xml)0
-rw-r--r--libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/ShellTaskOrganizerTests.java (renamed from libs/WindowManager/Shell/tests/src/com/android/wm/shell/ShellTaskOrganizerTests.java)0
-rw-r--r--libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/common/DisplayLayoutTest.java (renamed from libs/WindowManager/Shell/tests/src/com/android/wm/shell/common/DisplayLayoutTest.java)0
-rw-r--r--libs/hwui/RecordingCanvas.cpp1
-rw-r--r--libs/hwui/jni/Picture.cpp2
-rw-r--r--libs/hwui/renderthread/VulkanManager.cpp14
-rw-r--r--libs/hwui/renderthread/VulkanManager.h1
-rw-r--r--libs/hwui/tests/unit/SkiaCanvasTests.cpp4
-rw-r--r--libs/input/MouseCursorController.cpp51
-rw-r--r--libs/input/MouseCursorController.h11
-rw-r--r--libs/input/PointerController.cpp24
-rw-r--r--libs/input/PointerController.h1
-rw-r--r--libs/input/PointerControllerContext.cpp135
-rw-r--r--libs/input/PointerControllerContext.h43
-rw-r--r--libs/input/TouchSpotController.cpp36
-rw-r--r--libs/input/TouchSpotController.h8
-rw-r--r--location/java/android/location/LocationManager.java4
-rw-r--r--media/java/android/media/AudioDeviceAttributes.java19
-rw-r--r--media/java/android/media/AudioDeviceInfo.java37
-rwxr-xr-xmedia/java/android/media/AudioManager.java343
-rw-r--r--media/java/android/media/AudioSystem.java146
-rw-r--r--media/java/android/media/AudioTrack.java9
-rwxr-xr-xmedia/java/android/media/IAudioService.aidl13
-rw-r--r--media/java/android/media/ICapturePresetDevicesRoleDispatcher.aidl31
-rw-r--r--media/java/android/media/MediaPlayer.java5
-rw-r--r--media/java/android/media/MediaRecorder.java26
-rw-r--r--media/java/android/media/MediaTranscodeManager.java386
-rw-r--r--media/java/android/media/PlayerBase.java5
-rw-r--r--media/java/android/media/session/MediaSession.java2
-rw-r--r--media/jni/Android.bp23
-rw-r--r--media/jni/android_media_MediaPlayer.cpp9
-rw-r--r--media/jni/android_media_MediaTranscodeManager.cpp125
-rw-r--r--media/jni/android_media_tv_Tuner.cpp4
-rw-r--r--media/packages/BluetoothMidiService/Android.bp1
-rw-r--r--media/packages/BluetoothMidiService/AndroidManifest.xml2
-rw-r--r--media/packages/BluetoothMidiService/AndroidManifestBase.xml2
-rw-r--r--media/tests/MediaTranscodingTest/Android.bp1
-rw-r--r--media/tests/MediaTranscodingTest/build_and_run_unit_tests.sh5
-rw-r--r--media/tests/MediaTranscodingTest/src/com/android/mediatranscodingtest/MediaTranscodeManagerDiedTest.java255
-rw-r--r--media/tests/MediaTranscodingTest/src/com/android/mediatranscodingtest/MediaTranscodeManagerTest.java282
-rw-r--r--media/tests/MediaTranscodingTest/src/com/android/mediatranscodingtest/MediaTranscodeManagerWithMockServiceTest.java503
-rw-r--r--media/tests/MediaTranscodingTest/src/com/android/mediatranscodingtest/MediaTranscodingBenchmark.java39
-rw-r--r--media/tests/MediaTranscodingTest/src/com/android/mediatranscodingtest/MediaTranscodingTestRunner.java2
-rw-r--r--non-updatable-api/current.txt21
-rw-r--r--non-updatable-api/system-current.txt65
-rw-r--r--packages/CarSystemUI/res/drawable/car_ic_apps.xml12
-rw-r--r--packages/CarSystemUI/res/drawable/car_ic_apps_selected.xml6
-rw-r--r--packages/CarSystemUI/res/drawable/car_ic_home.xml25
-rw-r--r--packages/CarSystemUI/res/drawable/car_ic_home_selected.xml25
-rw-r--r--packages/CarSystemUI/res/drawable/car_ic_hvac.xml44
-rw-r--r--packages/CarSystemUI/res/drawable/car_ic_hvac_selected.xml25
-rw-r--r--packages/CarSystemUI/res/drawable/car_ic_notification.xml8
-rw-r--r--packages/CarSystemUI/res/drawable/car_ic_user_icon.xml25
-rw-r--r--packages/CarSystemUI/res/drawable/hvac_decrease_button.xml53
-rw-r--r--packages/CarSystemUI/res/drawable/hvac_increase_button.xml53
-rw-r--r--packages/CarSystemUI/res/drawable/ic_mic_white.xml10
-rw-r--r--packages/CarSystemUI/res/layout/adjustable_temperature_view.xml50
-rw-r--r--packages/CarSystemUI/res/layout/car_navigation_bar.xml203
-rw-r--r--packages/CarSystemUI/res/layout/car_top_navigation_bar.xml100
-rw-r--r--packages/CarSystemUI/res/layout/car_top_navigation_bar_unprovisioned.xml8
-rw-r--r--packages/CarSystemUI/res/values/colors.xml3
-rw-r--r--packages/CarSystemUI/res/values/config.xml1
-rw-r--r--packages/CarSystemUI/res/values/dimens.xml15
-rw-r--r--packages/CarSystemUI/res/values/strings.xml2
-rw-r--r--packages/CarSystemUI/res/values/styles.xml24
-rw-r--r--packages/CarSystemUI/src/com/android/systemui/CarGlobalRootComponent.java6
-rw-r--r--packages/CarSystemUI/src/com/android/systemui/CarSysUIComponent.java6
-rw-r--r--packages/CarSystemUI/src/com/android/systemui/CarSystemUIBinder.java14
-rw-r--r--packages/CarSystemUI/src/com/android/systemui/CarSystemUIModule.java4
-rw-r--r--packages/CarSystemUI/src/com/android/systemui/car/CarDeviceProvisionedControllerImpl.java64
-rw-r--r--packages/CarSystemUI/src/com/android/systemui/car/hvac/AdjustableTemperatureView.java108
-rw-r--r--packages/CarSystemUI/src/com/android/systemui/car/hvac/AnimatedTemperatureView.java48
-rw-r--r--packages/CarSystemUI/src/com/android/systemui/car/hvac/HvacController.java175
-rw-r--r--packages/CarSystemUI/src/com/android/systemui/car/hvac/TemperatureTextView.java29
-rw-r--r--packages/CarSystemUI/src/com/android/systemui/car/hvac/TemperatureView.java29
-rw-r--r--packages/CarSystemUI/src/com/android/systemui/car/keyguard/CarKeyguardViewController.java38
-rw-r--r--packages/CarSystemUI/src/com/android/systemui/car/navigationbar/CarNavigationBar.java6
-rw-r--r--packages/CarSystemUI/src/com/android/systemui/car/navigationbar/CarNavigationBarController.java6
-rw-r--r--packages/CarSystemUI/src/com/android/systemui/car/navigationbar/SystemBarConfigs.java179
-rw-r--r--packages/CarSystemUI/src/com/android/systemui/car/notification/NotificationPanelViewController.java20
-rw-r--r--packages/CarSystemUI/src/com/android/systemui/car/statusbar/UserNameViewController.java132
-rw-r--r--packages/CarSystemUI/src/com/android/systemui/car/userswitcher/UserGridRecyclerView.java4
-rw-r--r--packages/CarSystemUI/src/com/android/systemui/car/window/OverlayPanelViewController.java59
-rw-r--r--packages/CarSystemUI/src/com/android/systemui/wmshell/CarWMShellModule.java10
-rw-r--r--packages/CarSystemUI/tests/src/com/android/systemui/car/hvac/AdjustableTemperatureViewTest.java174
-rw-r--r--packages/CarSystemUI/tests/src/com/android/systemui/car/hvac/HvacControllerTest.java76
-rw-r--r--packages/CarSystemUI/tests/src/com/android/systemui/car/hvac/TemperatureTextViewTest.java107
-rw-r--r--packages/CarSystemUI/tests/src/com/android/systemui/car/keyguard/CarKeyguardViewControllerTest.java61
-rw-r--r--packages/CarSystemUI/tests/src/com/android/systemui/car/navigationbar/CarNavigationBarControllerTest.java19
-rw-r--r--packages/CarSystemUI/tests/src/com/android/systemui/car/navigationbar/SystemBarConfigsTest.java48
-rw-r--r--packages/CarSystemUI/tests/src/com/android/systemui/car/statusbar/UserNameViewControllerTest.java155
-rw-r--r--packages/CarSystemUI/tests/src/com/android/systemui/car/window/OverlayPanelViewControllerTest.java2
-rw-r--r--packages/CompanionDeviceManager/TEST_MAPPING12
-rw-r--r--packages/DynamicSystemInstallationService/src/com/android/dynsystem/InstallationAsyncTask.java11
-rw-r--r--packages/ExternalStorageProvider/src/com/android/externalstorage/ExternalStorageProvider.java7
-rw-r--r--packages/PrintSpooler/res/values-fa/strings.xml2
-rw-r--r--packages/PrintSpooler/res/values-uz/strings.xml2
-rw-r--r--packages/SettingsLib/res/drawable/ic_show_x_wifi_signal_0.xml31
-rw-r--r--packages/SettingsLib/res/drawable/ic_show_x_wifi_signal_1.xml27
-rw-r--r--packages/SettingsLib/res/drawable/ic_show_x_wifi_signal_2.xml27
-rw-r--r--packages/SettingsLib/res/drawable/ic_show_x_wifi_signal_3.xml27
-rw-r--r--packages/SettingsLib/res/drawable/ic_show_x_wifi_signal_4.xml27
-rw-r--r--packages/SettingsLib/res/values-fa/strings.xml2
-rw-r--r--packages/SettingsLib/src/com/android/settingslib/Utils.java58
-rw-r--r--packages/SettingsLib/src/com/android/settingslib/bluetooth/BluetoothUtils.java18
-rw-r--r--packages/SettingsLib/src/com/android/settingslib/media/MediaOutputSliceConstants.java24
-rw-r--r--packages/SettingsLib/src/com/android/settingslib/wifi/WifiEntryPreference.java20
-rw-r--r--packages/SettingsLib/src/com/android/settingslib/wifi/WifiStatusTracker.java5
-rw-r--r--packages/SettingsLib/tests/robotests/src/com/android/settingslib/wifi/WifiEntryPreferenceTest.java98
-rw-r--r--packages/SettingsProvider/src/com/android/providers/settings/SettingsProvider.java8
-rw-r--r--packages/SoundPicker/res/values-cs/strings.xml8
-rw-r--r--packages/SystemUI/Android.bp9
-rw-r--r--packages/SystemUI/AndroidManifest.xml18
-rw-r--r--packages/SystemUI/README.md8
-rw-r--r--packages/SystemUI/plugin/src/com/android/systemui/plugins/FalsingManager.java5
-rw-r--r--packages/SystemUI/plugin/src/com/android/systemui/plugins/statusbar/NotificationSwipeActionHelper.java11
-rw-r--r--packages/SystemUI/proguard.flags5
-rw-r--r--packages/SystemUI/res/drawable-mcc310-mnc004/ic_5g_plus_mobiledata.xml36
-rw-r--r--packages/SystemUI/res/drawable-mcc311-mnc480/ic_5g_plus_mobiledata.xml36
-rw-r--r--packages/SystemUI/res/layout-land-television/volume_dialog.xml9
-rw-r--r--packages/SystemUI/res/layout-land-television/volume_dialog_row.xml39
-rw-r--r--packages/SystemUI/res/layout/controls_management.xml5
-rw-r--r--packages/SystemUI/res/layout/controls_management_favorites.xml2
-rw-r--r--packages/SystemUI/res/layout/controls_structure_page.xml2
-rw-r--r--packages/SystemUI/res/layout/media_view.xml3
-rw-r--r--packages/SystemUI/res/values-af/strings.xml2
-rw-r--r--packages/SystemUI/res/values-am/strings.xml2
-rw-r--r--packages/SystemUI/res/values-ar/strings.xml2
-rw-r--r--packages/SystemUI/res/values-as/strings.xml2
-rw-r--r--packages/SystemUI/res/values-az/strings.xml4
-rw-r--r--packages/SystemUI/res/values-b+sr+Latn/strings.xml2
-rw-r--r--packages/SystemUI/res/values-be/strings.xml2
-rw-r--r--packages/SystemUI/res/values-bg/strings.xml2
-rw-r--r--packages/SystemUI/res/values-bn/strings.xml2
-rw-r--r--packages/SystemUI/res/values-bs/strings.xml2
-rw-r--r--packages/SystemUI/res/values-ca/strings.xml2
-rw-r--r--packages/SystemUI/res/values-cs/strings.xml4
-rw-r--r--packages/SystemUI/res/values-da/strings.xml2
-rw-r--r--packages/SystemUI/res/values-de/strings.xml2
-rw-r--r--packages/SystemUI/res/values-el/strings.xml4
-rw-r--r--packages/SystemUI/res/values-en-rAU/strings.xml2
-rw-r--r--packages/SystemUI/res/values-en-rCA/strings.xml2
-rw-r--r--packages/SystemUI/res/values-en-rGB/strings.xml2
-rw-r--r--packages/SystemUI/res/values-en-rIN/strings.xml2
-rw-r--r--packages/SystemUI/res/values-en-rXC/strings.xml2
-rw-r--r--packages/SystemUI/res/values-es-rUS/strings.xml2
-rw-r--r--packages/SystemUI/res/values-es/strings.xml2
-rw-r--r--packages/SystemUI/res/values-et/strings.xml2
-rw-r--r--packages/SystemUI/res/values-eu/strings.xml4
-rw-r--r--packages/SystemUI/res/values-fa/strings.xml2
-rw-r--r--packages/SystemUI/res/values-fi/strings.xml2
-rw-r--r--packages/SystemUI/res/values-fr-rCA/strings.xml2
-rw-r--r--packages/SystemUI/res/values-fr/strings.xml2
-rw-r--r--packages/SystemUI/res/values-gl/strings.xml2
-rw-r--r--packages/SystemUI/res/values-gu/strings.xml2
-rw-r--r--packages/SystemUI/res/values-hi/strings.xml2
-rw-r--r--packages/SystemUI/res/values-hr/strings.xml2
-rw-r--r--packages/SystemUI/res/values-hu/strings.xml2
-rw-r--r--packages/SystemUI/res/values-hy/strings.xml4
-rw-r--r--packages/SystemUI/res/values-in/strings.xml2
-rw-r--r--packages/SystemUI/res/values-is/strings.xml2
-rw-r--r--packages/SystemUI/res/values-it/strings.xml2
-rw-r--r--packages/SystemUI/res/values-iw/strings.xml2
-rw-r--r--packages/SystemUI/res/values-ja/strings.xml2
-rw-r--r--packages/SystemUI/res/values-ka/strings.xml2
-rw-r--r--packages/SystemUI/res/values-kk/strings.xml2
-rw-r--r--packages/SystemUI/res/values-km/strings.xml2
-rw-r--r--packages/SystemUI/res/values-kn/strings.xml2
-rw-r--r--packages/SystemUI/res/values-ko/strings.xml2
-rw-r--r--packages/SystemUI/res/values-ky/strings.xml2
-rw-r--r--packages/SystemUI/res/values-land-television/dimens.xml5
-rw-r--r--packages/SystemUI/res/values-land/dimens.xml11
-rw-r--r--packages/SystemUI/res/values-lo/strings.xml2
-rw-r--r--packages/SystemUI/res/values-lt/strings.xml2
-rw-r--r--packages/SystemUI/res/values-lv/strings.xml2
-rw-r--r--packages/SystemUI/res/values-mcc310-mnc004/strings.xml22
-rw-r--r--packages/SystemUI/res/values-mcc311-mnc480/strings.xml22
-rw-r--r--packages/SystemUI/res/values-mk/strings.xml4
-rw-r--r--packages/SystemUI/res/values-ml/strings.xml2
-rw-r--r--packages/SystemUI/res/values-mn/strings.xml2
-rw-r--r--packages/SystemUI/res/values-mr/strings.xml2
-rw-r--r--packages/SystemUI/res/values-ms/strings.xml4
-rw-r--r--packages/SystemUI/res/values-my/strings.xml2
-rw-r--r--packages/SystemUI/res/values-nb/strings.xml2
-rw-r--r--packages/SystemUI/res/values-ne/strings.xml10
-rw-r--r--packages/SystemUI/res/values-nl/strings.xml4
-rw-r--r--packages/SystemUI/res/values-or/strings.xml2
-rw-r--r--packages/SystemUI/res/values-pa/strings.xml2
-rw-r--r--packages/SystemUI/res/values-pl/strings.xml2
-rw-r--r--packages/SystemUI/res/values-pt-rBR/strings.xml2
-rw-r--r--packages/SystemUI/res/values-pt-rPT/strings.xml2
-rw-r--r--packages/SystemUI/res/values-pt/strings.xml2
-rw-r--r--packages/SystemUI/res/values-ro/strings.xml2
-rw-r--r--packages/SystemUI/res/values-ru/strings.xml2
-rw-r--r--packages/SystemUI/res/values-si/strings.xml2
-rw-r--r--packages/SystemUI/res/values-sk/strings.xml2
-rw-r--r--packages/SystemUI/res/values-sl/strings.xml2
-rw-r--r--packages/SystemUI/res/values-sq/strings.xml4
-rw-r--r--packages/SystemUI/res/values-sr/strings.xml2
-rw-r--r--packages/SystemUI/res/values-sv/strings.xml2
-rw-r--r--packages/SystemUI/res/values-sw/strings.xml2
-rw-r--r--packages/SystemUI/res/values-sw600dp/config.xml3
-rw-r--r--packages/SystemUI/res/values-ta/strings.xml2
-rw-r--r--packages/SystemUI/res/values-te/strings.xml2
-rw-r--r--packages/SystemUI/res/values-television/config.xml2
-rw-r--r--packages/SystemUI/res/values-television/integers.xml7
-rw-r--r--packages/SystemUI/res/values-th/strings.xml2
-rw-r--r--packages/SystemUI/res/values-tl/strings.xml2
-rw-r--r--packages/SystemUI/res/values-tr/strings.xml2
-rw-r--r--packages/SystemUI/res/values-uk/strings.xml2
-rw-r--r--packages/SystemUI/res/values-ur/strings.xml2
-rw-r--r--packages/SystemUI/res/values-uz/strings.xml4
-rw-r--r--packages/SystemUI/res/values-vi/strings.xml2
-rw-r--r--packages/SystemUI/res/values-zh-rCN/strings.xml2
-rw-r--r--packages/SystemUI/res/values-zh-rHK/strings.xml2
-rw-r--r--packages/SystemUI/res/values-zh-rTW/strings.xml2
-rw-r--r--packages/SystemUI/res/values-zu/strings.xml2
-rw-r--r--packages/SystemUI/res/values/config.xml5
-rw-r--r--packages/SystemUI/res/values/dimens.xml12
-rw-r--r--packages/SystemUI/res/values/ids.xml7
-rw-r--r--packages/SystemUI/res/values/strings.xml35
-rw-r--r--packages/SystemUI/res/values/styles.xml32
-rw-r--r--packages/SystemUI/src/com/android/keyguard/KeyguardClockSwitch.java2
-rw-r--r--packages/SystemUI/src/com/android/keyguard/KeyguardClockSwitchController.java26
-rw-r--r--packages/SystemUI/src/com/android/keyguard/KeyguardDisplayManager.java20
-rw-r--r--packages/SystemUI/src/com/android/keyguard/KeyguardSecurityContainer.java10
-rw-r--r--packages/SystemUI/src/com/android/keyguard/KeyguardSliceView.java200
-rw-r--r--packages/SystemUI/src/com/android/keyguard/KeyguardSliceViewController.java239
-rw-r--r--packages/SystemUI/src/com/android/keyguard/KeyguardStatusView.java11
-rw-r--r--packages/SystemUI/src/com/android/keyguard/KeyguardUpdateMonitor.java10
-rw-r--r--packages/SystemUI/src/com/android/keyguard/KeyguardViewController.java8
-rw-r--r--packages/SystemUI/src/com/android/keyguard/dagger/ContainerView.java (renamed from packages/SystemUI/src/com/android/systemui/pip/phone/dagger/PipMenuActivityClass.java)6
-rw-r--r--packages/SystemUI/src/com/android/keyguard/dagger/KeyguardBouncerComponent.java42
-rw-r--r--packages/SystemUI/src/com/android/keyguard/dagger/KeyguardBouncerScope.java32
-rw-r--r--packages/SystemUI/src/com/android/keyguard/dagger/KeyguardStatusViewComponent.java39
-rw-r--r--packages/SystemUI/src/com/android/keyguard/dagger/KeyguardStatusViewModule.java39
-rw-r--r--packages/SystemUI/src/com/android/keyguard/dagger/KeyguardStatusViewScope.java32
-rw-r--r--packages/SystemUI/src/com/android/systemui/Dependency.java6
-rw-r--r--packages/SystemUI/src/com/android/systemui/ExpandHelper.java2
-rw-r--r--packages/SystemUI/src/com/android/systemui/Prefs.java4
-rw-r--r--packages/SystemUI/src/com/android/systemui/SwipeHelper.java30
-rw-r--r--packages/SystemUI/src/com/android/systemui/SystemUIFactory.java40
-rw-r--r--packages/SystemUI/src/com/android/systemui/accessibility/MagnificationModeSwitch.java70
-rw-r--r--packages/SystemUI/src/com/android/systemui/accessibility/WindowMagnification.java22
-rw-r--r--packages/SystemUI/src/com/android/systemui/accessibility/WindowMagnificationAnimationController.java80
-rw-r--r--packages/SystemUI/src/com/android/systemui/appops/dagger/AppOpsModule.java (renamed from packages/SystemUI/src/com/android/systemui/pip/phone/dagger/PipModule.java)20
-rw-r--r--packages/SystemUI/src/com/android/systemui/bubbles/BubbleController.java15
-rw-r--r--packages/SystemUI/src/com/android/systemui/bubbles/dagger/BubbleModule.java4
-rw-r--r--packages/SystemUI/src/com/android/systemui/classifier/FalsingManagerFake.java2
-rw-r--r--packages/SystemUI/src/com/android/systemui/classifier/FalsingManagerImpl.java2
-rw-r--r--packages/SystemUI/src/com/android/systemui/classifier/FalsingManagerProxy.java4
-rw-r--r--packages/SystemUI/src/com/android/systemui/classifier/brightline/BrightLineFalsingManager.java3
-rw-r--r--packages/SystemUI/src/com/android/systemui/classifier/brightline/FalsingDataProvider.java5
-rw-r--r--packages/SystemUI/src/com/android/systemui/dagger/DependencyBinder.java268
-rw-r--r--packages/SystemUI/src/com/android/systemui/dagger/DependencyProvider.java21
-rw-r--r--packages/SystemUI/src/com/android/systemui/dagger/FrameworkServicesModule.java (renamed from packages/SystemUI/src/com/android/systemui/dagger/SystemServicesModule.java)107
-rw-r--r--packages/SystemUI/src/com/android/systemui/dagger/GlobalModule.java48
-rw-r--r--packages/SystemUI/src/com/android/systemui/dagger/GlobalRootComponent.java8
-rw-r--r--packages/SystemUI/src/com/android/systemui/dagger/PluginModule.java74
-rw-r--r--packages/SystemUI/src/com/android/systemui/dagger/SysUIComponent.java8
-rw-r--r--packages/SystemUI/src/com/android/systemui/dagger/SystemUIBinder.java14
-rw-r--r--packages/SystemUI/src/com/android/systemui/dagger/SystemUIDefaultModule.java4
-rw-r--r--packages/SystemUI/src/com/android/systemui/dagger/SystemUIModule.java23
-rw-r--r--packages/SystemUI/src/com/android/systemui/dagger/WMComponent.java17
-rw-r--r--packages/SystemUI/src/com/android/systemui/doze/DozeScreenBrightness.java4
-rw-r--r--packages/SystemUI/src/com/android/systemui/doze/DozeTriggers.java6
-rw-r--r--packages/SystemUI/src/com/android/systemui/doze/dagger/DozeModule.java3
-rw-r--r--packages/SystemUI/src/com/android/systemui/globalactions/GlobalActionsDialog.java10
-rw-r--r--packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewMediator.java17
-rw-r--r--packages/SystemUI/src/com/android/systemui/keyguard/dagger/KeyguardModule.java10
-rw-r--r--packages/SystemUI/src/com/android/systemui/media/MediaCarouselController.kt1
-rw-r--r--packages/SystemUI/src/com/android/systemui/media/MediaCarouselScrollHandler.kt4
-rw-r--r--packages/SystemUI/src/com/android/systemui/media/MediaDataManager.kt5
-rw-r--r--packages/SystemUI/src/com/android/systemui/media/SeekBarObserver.kt19
-rw-r--r--packages/SystemUI/src/com/android/systemui/navigationbar/NavigationBar.java24
-rw-r--r--packages/SystemUI/src/com/android/systemui/navigationbar/NavigationBarController.java10
-rw-r--r--packages/SystemUI/src/com/android/systemui/navigationbar/NavigationBarView.java39
-rw-r--r--packages/SystemUI/src/com/android/systemui/navigationbar/gestural/EdgeBackGestureHandler.java2
-rw-r--r--packages/SystemUI/src/com/android/systemui/onehanded/OneHanded.java80
-rw-r--r--packages/SystemUI/src/com/android/systemui/onehanded/OneHandedController.java437
-rw-r--r--packages/SystemUI/src/com/android/systemui/onehanded/OneHandedDisplayAreaOrganizer.java7
-rw-r--r--packages/SystemUI/src/com/android/systemui/onehanded/OneHandedGestureHandler.java27
-rw-r--r--packages/SystemUI/src/com/android/systemui/onehanded/OneHandedTimeoutHandler.java8
-rw-r--r--packages/SystemUI/src/com/android/systemui/onehanded/OneHandedTouchHandler.java13
-rw-r--r--packages/SystemUI/src/com/android/systemui/onehanded/OneHandedTutorialHandler.java11
-rw-r--r--packages/SystemUI/src/com/android/systemui/onehanded/OneHandedUI.java340
-rw-r--r--packages/SystemUI/src/com/android/systemui/pip/BasePipManager.java35
-rw-r--r--packages/SystemUI/src/com/android/systemui/pip/Pip.java170
-rw-r--r--packages/SystemUI/src/com/android/systemui/pip/PipTaskOrganizer.java89
-rw-r--r--packages/SystemUI/src/com/android/systemui/pip/PipUI.java122
-rw-r--r--packages/SystemUI/src/com/android/systemui/pip/phone/PipController.java (renamed from packages/SystemUI/src/com/android/systemui/pip/phone/PipManager.java)84
-rw-r--r--packages/SystemUI/src/com/android/systemui/pip/phone/PipMenuActivityController.java375
-rw-r--r--packages/SystemUI/src/com/android/systemui/pip/phone/PipMenuView.java (renamed from packages/SystemUI/src/com/android/systemui/pip/phone/PipMenuActivity.java)399
-rw-r--r--packages/SystemUI/src/com/android/systemui/pip/phone/PipMotionHelper.java14
-rw-r--r--packages/SystemUI/src/com/android/systemui/pip/phone/PipResizeGestureHandler.java13
-rw-r--r--packages/SystemUI/src/com/android/systemui/pip/phone/PipTouchHandler.java9
-rw-r--r--packages/SystemUI/src/com/android/systemui/pip/tv/PipController.java (renamed from packages/SystemUI/src/com/android/systemui/pip/tv/PipManager.java)103
-rw-r--r--packages/SystemUI/src/com/android/systemui/pip/tv/PipControlsViewController.java56
-rw-r--r--packages/SystemUI/src/com/android/systemui/pip/tv/PipMenuActivity.java36
-rw-r--r--packages/SystemUI/src/com/android/systemui/pip/tv/PipNotification.java62
-rw-r--r--packages/SystemUI/src/com/android/systemui/pip/tv/dagger/PipModule.java46
-rw-r--r--packages/SystemUI/src/com/android/systemui/power/dagger/PowerModule.java32
-rw-r--r--packages/SystemUI/src/com/android/systemui/qs/dagger/QSModule.java7
-rw-r--r--packages/SystemUI/src/com/android/systemui/qs/tiles/CellularTile.java3
-rw-r--r--packages/SystemUI/src/com/android/systemui/recents/OverviewProxyRecentsImpl.java10
-rw-r--r--packages/SystemUI/src/com/android/systemui/recents/OverviewProxyService.java77
-rw-r--r--packages/SystemUI/src/com/android/systemui/screenrecord/RecordingService.java12
-rw-r--r--packages/SystemUI/src/com/android/systemui/screenrecord/ScreenRecordDialog.java10
-rw-r--r--packages/SystemUI/src/com/android/systemui/screenshot/GlobalScreenshot.java7
-rw-r--r--packages/SystemUI/src/com/android/systemui/screenshot/ScreenshotEvent.java4
-rw-r--r--packages/SystemUI/src/com/android/systemui/settings/CurrentUserContextTracker.kt74
-rw-r--r--packages/SystemUI/src/com/android/systemui/settings/UserContentResolverProvider.kt (renamed from packages/SystemUI/src/com/android/systemui/settings/CurrentUserContentResolverProvider.kt)7
-rw-r--r--packages/SystemUI/src/com/android/systemui/settings/UserContextProvider.kt26
-rw-r--r--packages/SystemUI/src/com/android/systemui/settings/UserTracker.kt74
-rw-r--r--packages/SystemUI/src/com/android/systemui/settings/UserTrackerImpl.kt240
-rw-r--r--packages/SystemUI/src/com/android/systemui/settings/dagger/SettingsModule.java43
-rw-r--r--packages/SystemUI/src/com/android/systemui/shortcut/ShortcutKeyDispatcher.java18
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/AlertingNotificationManager.java1
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/DragDownHelper.java4
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/KeyguardAffordanceView.java1
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/NotificationMediaManager.java20
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/NotificationPresenter.java8
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/NotificationShelfController.java4
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/NotificationViewHierarchyManager.java25
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/PulseExpansionHandler.kt3
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/dagger/StatusBarDependenciesModule.java36
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/notification/ConversationNotifications.kt4
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/notification/InstantAppNotifier.java11
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationEntryManager.java6
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationFilter.java3
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/NotificationEntry.java13
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/NotificationRankingManager.kt6
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/ConversationCoordinator.kt3
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/HeadsUpCoordinator.java4
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/inflation/LowPriorityInflationHelper.java8
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/inflation/NotificationRowBinderImpl.java3
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/legacy/NotificationGroupManagerLegacy.java (renamed from packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationGroupManager.java)191
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/notifcollection/NotifLifetimeExtender.java6
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/provider/HighPriorityProvider.java28
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/render/GroupExpansionManager.java66
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/render/GroupExpansionManagerImpl.java113
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/render/GroupMembershipManager.java73
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/render/GroupMembershipManagerImpl.java80
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/render/ShadeViewManager.kt1
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/notification/dagger/NotificationsModule.java35
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/notification/init/NotificationsControllerImpl.kt11
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/notification/people/PeopleHubNotificationListener.kt4
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/notification/people/PeopleNotificationIdentifier.kt38
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ExpandableNotificationRow.java70
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ExpandableNotificationRowController.java32
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationContentView.java29
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationGutsManager.java8
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationMenuRow.java4
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/AmbientState.java25
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayout.java666
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayoutController.java528
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationSwipeHelper.java58
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/phone/HeadsUpManagerPhone.java9
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardAffordanceHelper.java7
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardBouncer.java8
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationGroupAlertTransferHelper.java19
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelViewController.java230
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationShadeWindowControllerImpl.java1
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationShadeWindowViewController.java8
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/phone/PanelViewController.java26
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/phone/ScrimController.java15
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBar.java56
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarKeyguardViewManager.java18
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarNotificationActivityStarter.java49
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarNotificationPresenter.java17
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarRemoteInputCallback.java14
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/phone/dagger/StatusBarPhoneModule.java9
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/policy/BluetoothControllerImpl.java12
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/policy/DeviceProvisionedControllerImpl.java38
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/policy/MobileSignalController.java4
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/policy/NetworkController.java1
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/policy/NetworkControllerImpl.java6
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/policy/UserSwitcherController.java2
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/policy/dagger/StatusBarPolicyModule.java112
-rw-r--r--packages/SystemUI/src/com/android/systemui/tracing/sysui_trace.proto3
-rw-r--r--packages/SystemUI/src/com/android/systemui/tuner/dagger/TunerModule.java31
-rw-r--r--packages/SystemUI/src/com/android/systemui/tv/TvGlobalRootComponent.java8
-rw-r--r--packages/SystemUI/src/com/android/systemui/tv/TvSysUIComponent.java4
-rw-r--r--packages/SystemUI/src/com/android/systemui/tv/TvSystemUIBinder.java3
-rw-r--r--packages/SystemUI/src/com/android/systemui/tv/TvSystemUIModule.java8
-rw-r--r--packages/SystemUI/src/com/android/systemui/util/InjectionInflationController.java6
-rw-r--r--packages/SystemUI/src/com/android/systemui/util/concurrency/GlobalConcurrencyModule.java70
-rw-r--r--packages/SystemUI/src/com/android/systemui/util/concurrency/SysUIConcurrencyModule.java (renamed from packages/SystemUI/src/com/android/systemui/util/concurrency/ConcurrencyModule.java)37
-rw-r--r--packages/SystemUI/src/com/android/systemui/util/dagger/UtilModule.java31
-rw-r--r--packages/SystemUI/src/com/android/systemui/util/settings/SettingsProxy.java66
-rw-r--r--packages/SystemUI/src/com/android/systemui/volume/VolumeDialogImpl.java50
-rw-r--r--packages/SystemUI/src/com/android/systemui/volume/dagger/VolumeModule.java32
-rw-r--r--packages/SystemUI/src/com/android/systemui/wmshell/TvWMShellModule.java108
-rw-r--r--packages/SystemUI/src/com/android/systemui/wmshell/WMShell.java237
-rw-r--r--packages/SystemUI/src/com/android/systemui/wmshell/WMShellBaseModule.java30
-rw-r--r--packages/SystemUI/src/com/android/systemui/wmshell/WMShellModule.java67
-rw-r--r--packages/SystemUI/tests/src/com/android/keyguard/KeyguardClockSwitchControllerTest.java29
-rw-r--r--packages/SystemUI/tests/src/com/android/keyguard/KeyguardPresentationTest.java16
-rw-r--r--packages/SystemUI/tests/src/com/android/keyguard/KeyguardSliceViewControllerTest.java99
-rw-r--r--packages/SystemUI/tests/src/com/android/keyguard/KeyguardSliceViewTest.java81
-rw-r--r--packages/SystemUI/tests/src/com/android/keyguard/KeyguardStatusViewTest.java5
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/accessibility/IWindowMagnificationConnectionTest.java30
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/accessibility/MagnificationModeSwitchTest.java172
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/accessibility/WindowMagnificationAnimationControllerTest.java169
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/bubbles/BubbleControllerTest.java4
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/bubbles/NewNotifPipelineBubbleControllerTest.java4
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/bubbles/TestableBubbleController.java4
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/globalactions/GlobalActionsDialogTest.java8
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/keyguard/KeyguardViewMediatorTest.java6
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/navigationbar/NavigationBarControllerTest.java4
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/navigationbar/NavigationBarTest.java4
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/onehanded/OneHandedControllerTest.java62
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/onehanded/OneHandedGestureHandlerTest.java54
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/onehanded/OneHandedTestCase.java9
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/onehanded/OneHandedTouchHandlerTest.java27
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/onehanded/OneHandedTutorialHandlerTest.java16
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/onehanded/OneHandedUITest.java136
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/screenrecord/RecordingServiceTest.java6
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/settings/CurrentUserContextTrackerTest.kt92
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/settings/UserTrackerImplTest.kt292
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/statusbar/NonPhoneDependencyTest.java2
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/statusbar/NotificationViewHierarchyManagerTest.java35
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/NotificationEntryManagerTest.java7
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/NotificationFilterTest.java6
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/HighPriorityProviderTest.java52
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/NotificationRankingManagerTest.kt22
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/coordinator/ConversationCoordinatorTest.kt4
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/NotificationEntryManagerInflationTest.java12
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/NotificationGutsManagerTest.java4
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/NotificationTestHelper.java20
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayoutTest.java106
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollerControllerTest.java95
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/stack/NotificationSwipeHelperTest.java4
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/HeadsUpManagerPhoneTest.java5
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/NotificationGroupAlertTransferHelperTest.java7
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/NotificationGroupManagerLegacyTest.java (renamed from packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/NotificationGroupManagerTest.java)25
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/NotificationPanelViewTest.java32
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/NotificationShadeWindowViewTest.java6
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarKeyguardViewManagerTest.java67
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarNotificationActivityStarterTest.java7
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarRemoteInputCallbackTest.java3
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarTest.java8
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/BluetoothControllerImplTest.java4
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/NetworkControllerDataTest.java22
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/util/settings/FakeSettings.java10
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/utils/leaks/FakeNetworkController.java5
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/wmshell/WMShellTest.java118
-rw-r--r--services/accessibility/java/com/android/server/accessibility/gestures/EventDispatcher.java74
-rw-r--r--services/accessibility/java/com/android/server/accessibility/gestures/MultiFingerSwipe.java2
-rw-r--r--services/accessibility/java/com/android/server/accessibility/gestures/TouchExplorer.java118
-rw-r--r--services/accessibility/java/com/android/server/accessibility/magnification/WindowMagnificationConnectionWrapper.java11
-rw-r--r--services/accessibility/java/com/android/server/accessibility/magnification/WindowMagnificationGestureHandler.java6
-rw-r--r--services/accessibility/java/com/android/server/accessibility/magnification/WindowMagnificationManager.java102
-rw-r--r--services/appprediction/java/com/android/server/appprediction/AppPredictionManagerService.java7
-rw-r--r--services/appprediction/java/com/android/server/appprediction/AppPredictionPerUserService.java135
-rw-r--r--services/companion/TEST_MAPPING12
-rw-r--r--services/companion/java/com/android/server/companion/CompanionDeviceManagerService.java10
-rw-r--r--services/core/java/android/content/pm/PackageManagerInternal.java15
-rw-r--r--services/core/java/com/android/server/DynamicSystemService.java10
-rw-r--r--services/core/java/com/android/server/StorageManagerService.java2
-rw-r--r--services/core/java/com/android/server/UiModeManagerService.java9
-rw-r--r--services/core/java/com/android/server/VibratorService.java128
-rw-r--r--services/core/java/com/android/server/accounts/AccountManagerService.java6
-rw-r--r--services/core/java/com/android/server/am/ActiveServices.java18
-rw-r--r--services/core/java/com/android/server/am/ActivityManagerService.java125
-rw-r--r--services/core/java/com/android/server/am/AppErrors.java142
-rw-r--r--services/core/java/com/android/server/am/BroadcastQueue.java39
-rw-r--r--services/core/java/com/android/server/am/CachedAppOptimizer.java77
-rw-r--r--services/core/java/com/android/server/am/ContentProviderHelper.java141
-rw-r--r--services/core/java/com/android/server/am/OomAdjuster.java184
-rw-r--r--services/core/java/com/android/server/am/ProcessList.java50
-rw-r--r--services/core/java/com/android/server/audio/AudioDeviceBroker.java53
-rw-r--r--services/core/java/com/android/server/audio/AudioDeviceInventory.java77
-rw-r--r--services/core/java/com/android/server/audio/AudioEventLogger.java31
-rwxr-xr-xservices/core/java/com/android/server/audio/AudioService.java231
-rw-r--r--services/core/java/com/android/server/audio/AudioSystemAdapter.java34
-rw-r--r--services/core/java/com/android/server/biometrics/sensors/AuthenticationClient.java2
-rw-r--r--services/core/java/com/android/server/biometrics/sensors/ClientMonitor.java5
-rw-r--r--services/core/java/com/android/server/biometrics/sensors/face/Face10.java6
-rw-r--r--services/core/java/com/android/server/biometrics/sensors/fingerprint/Fingerprint21.java2
-rw-r--r--services/core/java/com/android/server/connectivity/KeepaliveTracker.java50
-rw-r--r--services/core/java/com/android/server/connectivity/PermissionMonitor.java2
-rw-r--r--services/core/java/com/android/server/connectivity/Vpn.java2
-rw-r--r--services/core/java/com/android/server/content/SyncManager.java4
-rw-r--r--services/core/java/com/android/server/display/DisplayManagerService.java24
-rw-r--r--services/core/java/com/android/server/hdmi/ActiveSourceAction.java2
-rw-r--r--services/core/java/com/android/server/hdmi/ActiveSourceHandler.java8
-rw-r--r--services/core/java/com/android/server/hdmi/HdmiCecController.java12
-rwxr-xr-xservices/core/java/com/android/server/hdmi/HdmiCecLocalDevice.java59
-rw-r--r--services/core/java/com/android/server/hdmi/HdmiCecLocalDeviceAudioSystem.java3
-rw-r--r--services/core/java/com/android/server/hdmi/HdmiCecLocalDevicePlayback.java6
-rw-r--r--services/core/java/com/android/server/hdmi/HdmiCecLocalDeviceSource.java12
-rw-r--r--services/core/java/com/android/server/hdmi/HdmiCecLocalDeviceTv.java16
-rw-r--r--services/core/java/com/android/server/hdmi/HdmiCecMessageBuilder.java2
-rw-r--r--services/core/java/com/android/server/hdmi/HdmiCecMessageValidator.java5
-rw-r--r--services/core/java/com/android/server/hdmi/HdmiControlService.java33
-rw-r--r--services/core/java/com/android/server/inputmethod/InputMethodManagerService.java41
-rw-r--r--services/core/java/com/android/server/inputmethod/TEST_MAPPING7
-rw-r--r--services/core/java/com/android/server/integrity/AppIntegrityManagerServiceImpl.java28
-rw-r--r--services/core/java/com/android/server/location/LocationManagerService.java43
-rw-r--r--services/core/java/com/android/server/location/LocationProviderManager.java330
-rw-r--r--services/core/java/com/android/server/location/geofence/GeofenceManager.java22
-rw-r--r--services/core/java/com/android/server/location/gnss/GnssListenerMultiplexer.java20
-rw-r--r--services/core/java/com/android/server/location/gnss/GnssLocationProvider.java27
-rw-r--r--services/core/java/com/android/server/location/listeners/BinderListenerRegistration.java4
-rw-r--r--services/core/java/com/android/server/location/listeners/ListenerMultiplexer.java187
-rw-r--r--services/core/java/com/android/server/location/listeners/ListenerRegistration.java54
-rw-r--r--services/core/java/com/android/server/location/listeners/PendingIntentListenerRegistration.java2
-rw-r--r--services/core/java/com/android/server/location/listeners/RemoteListenerRegistration.java75
-rw-r--r--services/core/java/com/android/server/location/listeners/RemovableListenerRegistration.java10
-rw-r--r--services/core/java/com/android/server/locksettings/LockSettingsService.java10
-rw-r--r--services/core/java/com/android/server/locksettings/LockSettingsStorage.java2
-rw-r--r--services/core/java/com/android/server/net/NetworkPolicyManagerService.java29
-rw-r--r--services/core/java/com/android/server/notification/ManagedServices.java2
-rwxr-xr-xservices/core/java/com/android/server/notification/NotificationManagerService.java101
-rw-r--r--services/core/java/com/android/server/om/OverlayManagerService.java2
-rw-r--r--services/core/java/com/android/server/pm/ApkChecksums.java510
-rw-r--r--services/core/java/com/android/server/pm/AppsFilter.java4
-rw-r--r--services/core/java/com/android/server/pm/ComponentResolver.java83
-rw-r--r--services/core/java/com/android/server/pm/CrossProfileAppsServiceImpl.java2
-rw-r--r--services/core/java/com/android/server/pm/PackageInstallerService.java32
-rw-r--r--services/core/java/com/android/server/pm/PackageInstallerSession.java73
-rw-r--r--services/core/java/com/android/server/pm/PackageManagerService.java206
-rw-r--r--services/core/java/com/android/server/pm/PackageManagerServiceUtils.java13
-rw-r--r--services/core/java/com/android/server/pm/PackageManagerShellCommand.java100
-rw-r--r--services/core/java/com/android/server/pm/ShortcutService.java2
-rw-r--r--services/core/java/com/android/server/pm/StagingManager.java126
-rw-r--r--services/core/java/com/android/server/pm/TEST_MAPPING3
-rw-r--r--services/core/java/com/android/server/pm/UserManagerService.java175
-rw-r--r--services/core/java/com/android/server/pm/permission/DefaultPermissionGrantPolicy.java15
-rw-r--r--services/core/java/com/android/server/pm/permission/PermissionManagerService.java14
-rw-r--r--services/core/java/com/android/server/policy/PhoneWindowManager.java24
-rw-r--r--services/core/java/com/android/server/policy/WindowManagerPolicy.java246
-rw-r--r--services/core/java/com/android/server/security/VerityUtils.java18
-rw-r--r--services/core/java/com/android/server/slice/SliceFullAccessList.java2
-rw-r--r--services/core/java/com/android/server/soundtrigger_middleware/SoundTriggerHw2Watchdog.java3
-rw-r--r--services/core/java/com/android/server/soundtrigger_middleware/SoundTriggerModule.java13
-rw-r--r--services/core/java/com/android/server/timezonedetector/CallerIdentityInjector.java62
-rw-r--r--services/core/java/com/android/server/timezonedetector/ConfigurationChangeListener.java26
-rw-r--r--services/core/java/com/android/server/timezonedetector/ConfigurationInternal.java288
-rw-r--r--services/core/java/com/android/server/timezonedetector/TEST_MAPPING12
-rw-r--r--services/core/java/com/android/server/timezonedetector/TimeZoneDetectorCallbackImpl.java213
-rw-r--r--services/core/java/com/android/server/timezonedetector/TimeZoneDetectorInternal.java6
-rw-r--r--services/core/java/com/android/server/timezonedetector/TimeZoneDetectorInternalImpl.java37
-rw-r--r--services/core/java/com/android/server/timezonedetector/TimeZoneDetectorService.java184
-rw-r--r--services/core/java/com/android/server/timezonedetector/TimeZoneDetectorStrategy.java88
-rw-r--r--services/core/java/com/android/server/timezonedetector/TimeZoneDetectorStrategyImpl.java286
-rw-r--r--services/core/java/com/android/server/trust/TrustManagerService.java8
-rw-r--r--services/core/java/com/android/server/uri/UriGrantsManagerService.java17
-rw-r--r--services/core/java/com/android/server/webkit/WebViewUpdateService.java4
-rw-r--r--services/core/java/com/android/server/wm/AccessibilityController.java12
-rw-r--r--services/core/java/com/android/server/wm/ActivityRecord.java348
-rw-r--r--services/core/java/com/android/server/wm/ActivityStackSupervisor.java6
-rw-r--r--services/core/java/com/android/server/wm/ActivityStarter.java28
-rw-r--r--services/core/java/com/android/server/wm/ActivityTaskManagerDebugConfig.java6
-rw-r--r--services/core/java/com/android/server/wm/ActivityTaskManagerService.java86
-rw-r--r--services/core/java/com/android/server/wm/BarController.java8
-rw-r--r--services/core/java/com/android/server/wm/CompatModePackages.java7
-rw-r--r--services/core/java/com/android/server/wm/DisplayAreaOrganizerController.java14
-rw-r--r--services/core/java/com/android/server/wm/DisplayContent.java97
-rw-r--r--services/core/java/com/android/server/wm/DisplayPolicy.java647
-rw-r--r--services/core/java/com/android/server/wm/DragDropController.java2
-rw-r--r--services/core/java/com/android/server/wm/ImeInsetsSourceProvider.java2
-rw-r--r--services/core/java/com/android/server/wm/InputManagerCallback.java5
-rw-r--r--services/core/java/com/android/server/wm/InputMonitor.java25
-rw-r--r--services/core/java/com/android/server/wm/InsetsSourceProvider.java6
-rw-r--r--services/core/java/com/android/server/wm/KeyguardController.java11
-rw-r--r--services/core/java/com/android/server/wm/LockTaskController.java32
-rw-r--r--services/core/java/com/android/server/wm/RecentTasks.java7
-rw-r--r--services/core/java/com/android/server/wm/ResetTargetTaskHelper.java8
-rw-r--r--services/core/java/com/android/server/wm/RootWindowContainer.java72
-rw-r--r--services/core/java/com/android/server/wm/RunningTasks.java5
-rw-r--r--services/core/java/com/android/server/wm/SurfaceAnimator.java22
-rw-r--r--services/core/java/com/android/server/wm/Task.java91
-rw-r--r--services/core/java/com/android/server/wm/TaskOrganizerController.java52
-rw-r--r--services/core/java/com/android/server/wm/TaskSnapshotController.java2
-rw-r--r--services/core/java/com/android/server/wm/WallpaperController.java4
-rw-r--r--services/core/java/com/android/server/wm/WindowManagerService.java94
-rw-r--r--services/core/java/com/android/server/wm/WindowOrganizerController.java14
-rw-r--r--services/core/java/com/android/server/wm/WindowProcessController.java20
-rw-r--r--services/core/java/com/android/server/wm/WindowState.java241
-rw-r--r--services/core/java/com/android/server/wm/WindowStateAnimator.java10
-rw-r--r--services/core/jni/Android.bp1
-rw-r--r--services/core/jni/com_android_server_VibratorService.cpp232
-rw-r--r--services/core/jni/com_android_server_am_CachedAppOptimizer.cpp18
-rw-r--r--services/core/jni/com_android_server_input_InputManagerService.cpp15
-rw-r--r--services/core/jni/com_android_server_location_GnssLocationProvider.cpp23
-rw-r--r--services/core/jni/com_android_server_security_VerityUtils.cpp36
-rw-r--r--services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java22
-rw-r--r--services/devicepolicy/java/com/android/server/devicepolicy/Owners.java2
-rw-r--r--services/incremental/Android.bp6
-rw-r--r--services/incremental/BinderIncrementalService.cpp15
-rw-r--r--services/incremental/BinderIncrementalService.h5
-rw-r--r--services/incremental/IncrementalService.cpp85
-rw-r--r--services/incremental/IncrementalService.h9
-rw-r--r--services/incremental/ServiceWrappers.cpp49
-rw-r--r--services/incremental/ServiceWrappers.h16
-rw-r--r--services/incremental/test/IncrementalServiceTest.cpp250
-rw-r--r--services/robotests/src/com/android/server/pm/CrossProfileAppsServiceImplRoboTest.java4
-rw-r--r--services/tests/mockingservicestests/src/com/android/server/alarm/AlarmManagerServiceTest.java4
-rw-r--r--services/tests/mockingservicestests/src/com/android/server/alarm/AlarmStoreTest.java193
-rw-r--r--services/tests/mockingservicestests/src/com/android/server/alarm/BackgroundRestrictedAlarmsTest.java1
-rw-r--r--services/tests/mockingservicestests/src/com/android/server/location/LocationProviderManagerTest.java57
-rw-r--r--services/tests/mockingservicestests/src/com/android/server/location/listeners/ListenerMultiplexerTest.java12
-rw-r--r--services/tests/servicestests/src/com/android/server/VibratorServiceTest.java89
-rw-r--r--services/tests/servicestests/src/com/android/server/accessibility/gestures/TouchExplorerTest.java5
-rw-r--r--services/tests/servicestests/src/com/android/server/accessibility/magnification/MockWindowMagnificationConnection.java23
-rw-r--r--services/tests/servicestests/src/com/android/server/accessibility/magnification/WindowMagnificationConnectionWrapperTest.java13
-rw-r--r--services/tests/servicestests/src/com/android/server/accessibility/magnification/WindowMagnificationGestureHandlerTest.java4
-rw-r--r--services/tests/servicestests/src/com/android/server/accessibility/magnification/WindowMagnificationManagerTest.java83
-rw-r--r--services/tests/servicestests/src/com/android/server/audio/NoOpAudioSystemAdapter.java17
-rw-r--r--services/tests/servicestests/src/com/android/server/devicepolicy/MockSystemServices.java3
-rw-r--r--services/tests/servicestests/src/com/android/server/display/DisplayManagerServiceTest.java106
-rw-r--r--services/tests/servicestests/src/com/android/server/hdmi/HdmiCecLocalDevicePlaybackTest.java79
-rw-r--r--services/tests/servicestests/src/com/android/server/hdmi/HdmiCecMessageBuilderTest.java26
-rw-r--r--services/tests/servicestests/src/com/android/server/hdmi/HdmiControlServiceTest.java79
-rw-r--r--services/tests/servicestests/src/com/android/server/pm/AppsFilterTest.java23
-rw-r--r--services/tests/servicestests/src/com/android/server/timezonedetector/ConfigurationInternalTest.java182
-rw-r--r--services/tests/servicestests/src/com/android/server/timezonedetector/FakeTimeZoneDetectorStrategy.java83
-rw-r--r--services/tests/servicestests/src/com/android/server/timezonedetector/TestCallerIdentityInjector.java53
-rw-r--r--services/tests/servicestests/src/com/android/server/timezonedetector/TimeZoneDetectorInternalImplTest.java13
-rw-r--r--services/tests/servicestests/src/com/android/server/timezonedetector/TimeZoneDetectorServiceTest.java95
-rw-r--r--services/tests/servicestests/src/com/android/server/timezonedetector/TimeZoneDetectorStrategyImplTest.java681
-rw-r--r--services/tests/servicestests/src/com/android/server/uri/UriGrantsMockContext.java12
-rw-r--r--services/tests/uiservicestests/src/com/android/server/notification/ManagedServicesTest.java1
-rw-r--r--services/tests/uiservicestests/src/com/android/server/notification/NotificationAssistantsTest.java2
-rwxr-xr-xservices/tests/uiservicestests/src/com/android/server/notification/NotificationManagerServiceTest.java63
-rw-r--r--services/tests/wmtests/src/com/android/server/wm/ActivityRecordTests.java75
-rw-r--r--services/tests/wmtests/src/com/android/server/wm/ActivityStackTests.java19
-rw-r--r--services/tests/wmtests/src/com/android/server/wm/ActivityStarterTests.java2
-rw-r--r--services/tests/wmtests/src/com/android/server/wm/DisplayContentTests.java2
-rw-r--r--services/tests/wmtests/src/com/android/server/wm/DisplayPolicyLayoutTests.java204
-rw-r--r--services/tests/wmtests/src/com/android/server/wm/DisplayPolicyTests.java4
-rw-r--r--services/tests/wmtests/src/com/android/server/wm/DisplayPolicyTestsBase.java2
-rw-r--r--services/tests/wmtests/src/com/android/server/wm/InsetsSourceProviderTest.java28
-rw-r--r--services/tests/wmtests/src/com/android/server/wm/RecentTasksTest.java27
-rw-r--r--services/tests/wmtests/src/com/android/server/wm/RootActivityContainerTests.java18
-rw-r--r--services/tests/wmtests/src/com/android/server/wm/RootWindowContainerTests.java2
-rw-r--r--services/tests/wmtests/src/com/android/server/wm/SizeCompatTests.java44
-rw-r--r--services/tests/wmtests/src/com/android/server/wm/TaskStackChangedListenerTest.java56
-rw-r--r--services/tests/wmtests/src/com/android/server/wm/TestWindowManagerPolicy.java10
-rw-r--r--services/tests/wmtests/src/com/android/server/wm/WallpaperControllerTests.java6
-rw-r--r--services/tests/wmtests/src/com/android/server/wm/WindowFrameTests.java82
-rw-r--r--services/tests/wmtests/src/com/android/server/wm/WindowManagerServiceTests.java12
-rw-r--r--services/tests/wmtests/src/com/android/server/wm/WindowOrganizerTests.java17
-rw-r--r--services/tests/wmtests/src/com/android/server/wm/WindowStateTests.java14
-rw-r--r--services/tests/wmtests/src/com/android/server/wm/WindowTestsBase.java2
-rw-r--r--services/usage/java/com/android/server/usage/UsageStatsService.java43
-rwxr-xr-xtelephony/java/android/telephony/CarrierConfigManager.java10
-rw-r--r--tests/FlickerTests/Android.bp23
-rw-r--r--tests/FlickerTests/AndroidTestPhysicalDevices.xml (renamed from tests/FlickerTests/AndroidTest.xml)1
-rw-r--r--tests/FlickerTests/AndroidTestVirtualDevices.xml41
-rw-r--r--tests/FlickerTests/src/com/android/server/wm/flicker/ime/CloseImeAutoOpenWindowToAppTest.kt4
-rw-r--r--tests/FlickerTests/src/com/android/server/wm/flicker/ime/CloseImeAutoOpenWindowToHomeTest.kt4
-rw-r--r--tests/FlickerTests/src/com/android/server/wm/flicker/ime/CloseImeWindowToAppTest.kt4
-rw-r--r--tests/FlickerTests/src/com/android/server/wm/flicker/ime/CloseImeWindowToHomeTest.kt4
-rw-r--r--tests/FlickerTests/src/com/android/server/wm/flicker/ime/OpenImeWindowTest.kt4
-rw-r--r--tests/FlickerTests/src/com/android/server/wm/flicker/launch/OpenAppColdTest.kt4
-rw-r--r--tests/FlickerTests/src/com/android/server/wm/flicker/launch/OpenAppWarmTest.kt4
-rw-r--r--tests/FlickerTests/src/com/android/server/wm/flicker/pip/EnterPipTest.kt4
-rw-r--r--tests/FlickerTests/src/com/android/server/wm/flicker/pip/PipToAppTest.kt4
-rw-r--r--tests/FlickerTests/src/com/android/server/wm/flicker/pip/PipToHomeTest.kt4
-rw-r--r--tests/FlickerTests/src/com/android/server/wm/flicker/rotation/ChangeAppRotationTest.kt4
-rw-r--r--tests/FlickerTests/src/com/android/server/wm/flicker/rotation/SeamlessAppRotationTest.kt5
-rw-r--r--tests/FlickerTests/src/com/android/server/wm/flicker/splitscreen/OpenAppToSplitScreenTest.kt4
-rw-r--r--tests/FlickerTests/src/com/android/server/wm/flicker/splitscreen/ResizeSplitScreenTest.kt4
-rw-r--r--tests/FlickerTests/src/com/android/server/wm/flicker/splitscreen/SplitScreenToLauncherTest.kt4
-rw-r--r--tests/RollbackTest/Android.bp1
-rw-r--r--tests/RollbackTest/RollbackTest/src/com/android/tests/rollback/RollbackTest.java2
-rw-r--r--tests/SilkFX/Android.bp6
-rw-r--r--tests/SilkFX/AndroidManifest.xml3
-rw-r--r--tests/SilkFX/res/drawable-hdpi/background1.jpegbin0 -> 200459 bytes
-rw-r--r--tests/SilkFX/res/drawable-hdpi/background2.jpegbin0 -> 110703 bytes
-rw-r--r--tests/SilkFX/res/drawable-hdpi/background3.jpegbin0 -> 318853 bytes
-rw-r--r--tests/SilkFX/res/drawable-hdpi/noise.pngbin0 -> 494875 bytes
-rw-r--r--tests/SilkFX/res/layout/activity_glass.xml246
-rw-r--r--tests/SilkFX/src/com/android/test/silkfx/Main.kt4
-rw-r--r--tests/SilkFX/src/com/android/test/silkfx/materials/GlassActivity.kt126
-rw-r--r--tests/SilkFX/src/com/android/test/silkfx/materials/GlassView.kt117
-rw-r--r--tests/StagedInstallTest/Android.bp3
-rw-r--r--tests/StagedInstallTest/app/src/com/android/tests/stagedinstallinternal/StagedInstallInternalTest.java4
-rw-r--r--tests/StagedInstallTest/src/com/android/tests/stagedinstallinternal/host/StagedInstallInternalTest.java72
-rw-r--r--tests/net/java/com/android/server/ConnectivityServiceTest.java4
-rw-r--r--tests/net/java/com/android/server/connectivity/PermissionMonitorTest.java2
-rw-r--r--tests/net/java/com/android/server/connectivity/VpnTest.java5
-rw-r--r--tools/preload-check/Android.bp2
-rw-r--r--tools/preload-check/src/com/android/preload/check/PreloadCheck.java6
-rw-r--r--tools/validatekeymaps/Main.cpp16
-rw-r--r--wifi/api/current.txt3
-rw-r--r--wifi/java/android/net/wifi/ScanResult.java10
-rw-r--r--wifi/java/android/net/wifi/WifiNetworkSuggestion.java85
-rw-r--r--wifi/tests/src/android/net/wifi/ScanResultTest.java8
-rw-r--r--wifi/tests/src/android/net/wifi/WifiNetworkSuggestionTest.java62
918 files changed, 27225 insertions, 14160 deletions
diff --git a/apct-tests/perftests/contentcapture/src/android/view/contentcapture/MyContentCaptureService.java b/apct-tests/perftests/contentcapture/src/android/view/contentcapture/MyContentCaptureService.java
index b1dbb28c9501..d07ed375b2ab 100644
--- a/apct-tests/perftests/contentcapture/src/android/view/contentcapture/MyContentCaptureService.java
+++ b/apct-tests/perftests/contentcapture/src/android/view/contentcapture/MyContentCaptureService.java
@@ -51,13 +51,14 @@ public class MyContentCaptureService extends ContentCaptureService {
sServiceWatcher = null;
}
- public static void clearServiceWatcher() {
- if (sServiceWatcher != null) {
- if (sServiceWatcher.mReadyToClear) {
- sServiceWatcher.mService = null;
+ private static void clearServiceWatcher() {
+ final ServiceWatcher sw = sServiceWatcher;
+ if (sw != null) {
+ if (sw.mReadyToClear) {
+ sw.mService = null;
sServiceWatcher = null;
} else {
- sServiceWatcher.mReadyToClear = true;
+ sw.mReadyToClear = true;
}
}
}
diff --git a/apct-tests/perftests/core/src/android/app/ResourcesManagerPerfTest.java b/apct-tests/perftests/core/src/android/app/ResourcesManagerPerfTest.java
index 050fecde8213..d3938f4c0926 100644
--- a/apct-tests/perftests/core/src/android/app/ResourcesManagerPerfTest.java
+++ b/apct-tests/perftests/core/src/android/app/ResourcesManagerPerfTest.java
@@ -17,7 +17,6 @@ package android.app;
import android.content.Context;
import android.content.res.Configuration;
-import android.content.res.Resources;
import android.perftests.utils.BenchmarkState;
import android.perftests.utils.PerfStatusReporter;
import android.view.Display;
@@ -136,4 +135,22 @@ public class ResourcesManagerPerfTest {
}
}
}
+
+ @Test
+ public void getDisplayMetrics() {
+ ResourcesManager resourcesManager = ResourcesManager.getInstance();
+
+ final BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
+ while (state.keepRunning()) {
+ state.pauseTiming();
+ // Invalidate cache.
+ resourcesManager.applyConfigurationToResourcesLocked(
+ resourcesManager.getConfiguration(), null);
+ state.resumeTiming();
+
+ // Invoke twice for testing cache.
+ resourcesManager.getDisplayMetrics();
+ resourcesManager.getDisplayMetrics();
+ }
+ }
}
diff --git a/apct-tests/perftests/utils/src/android/perftests/utils/BenchmarkState.java b/apct-tests/perftests/utils/src/android/perftests/utils/BenchmarkState.java
index 93bf541d02b4..e1928615211a 100644
--- a/apct-tests/perftests/utils/src/android/perftests/utils/BenchmarkState.java
+++ b/apct-tests/perftests/utils/src/android/perftests/utils/BenchmarkState.java
@@ -53,7 +53,8 @@ public final class BenchmarkState {
private static final int NOT_STARTED = 0; // The benchmark has not started yet.
private static final int WARMUP = 1; // The benchmark is warming up.
private static final int RUNNING = 2; // The benchmark is running.
- private static final int FINISHED = 3; // The benchmark has stopped.
+ private static final int RUNNING_CUSTOMIZED = 3; // Running for customized measurement.
+ private static final int FINISHED = 4; // The benchmark has stopped.
private int mState = NOT_STARTED; // Current benchmark state.
@@ -76,6 +77,14 @@ public final class BenchmarkState {
private int mRepeatCount = 0;
+ /**
+ * Additional iteration that used to apply customized measurement. The result during these
+ * iterations won't be counted into {@link #mStats}.
+ */
+ private int mMaxCustomizedIterations;
+ private int mCustomizedIterations;
+ private CustomizedIterationListener mCustomizedIterationListener;
+
// Statistics. These values will be filled when the benchmark has finished.
// The computation needs double precision, but long int is fine for final reporting.
private Stats mStats;
@@ -110,6 +119,15 @@ public final class BenchmarkState {
mPaused = false;
}
+ /**
+ * This is used to run the benchmark with more information by enabling some debug mechanism but
+ * we don't want to account the special runs (slower) in the stats report.
+ */
+ public void setCustomizedIterations(int iterations, CustomizedIterationListener listener) {
+ mMaxCustomizedIterations = iterations;
+ mCustomizedIterationListener = listener;
+ }
+
private void beginWarmup() {
mStartTimeNs = System.nanoTime();
mIteration = 0;
@@ -141,6 +159,11 @@ public final class BenchmarkState {
Debug.stopMethodTracing();
}
mStats = new Stats(mResults);
+ if (mMaxCustomizedIterations > 0 && mCustomizedIterationListener != null) {
+ mState = RUNNING_CUSTOMIZED;
+ mCustomizedIterationListener.onStart(mCustomizedIterations);
+ return true;
+ }
mState = FINISHED;
return false;
}
@@ -180,6 +203,15 @@ public final class BenchmarkState {
"Resume the benchmark before finishing each step.");
}
return true;
+ case RUNNING_CUSTOMIZED:
+ mCustomizedIterationListener.onFinished(mCustomizedIterations);
+ mCustomizedIterations++;
+ if (mCustomizedIterations >= mMaxCustomizedIterations) {
+ mState = FINISHED;
+ return false;
+ }
+ mCustomizedIterationListener.onStart(mCustomizedIterations);
+ return true;
case FINISHED:
throw new IllegalStateException("The benchmark has finished.");
default:
@@ -240,4 +272,13 @@ public final class BenchmarkState {
status.putLong(key + "_standardDeviation", standardDeviation());
instrumentation.sendStatus(Activity.RESULT_OK, status);
}
+
+ /** The interface to receive the events of customized iteration. */
+ public interface CustomizedIterationListener {
+ /** The customized iteration starts. */
+ void onStart(int iteration);
+
+ /** The customized iteration finished. */
+ void onFinished(int iteration);
+ }
}
diff --git a/apct-tests/perftests/windowmanager/AndroidManifest.xml b/apct-tests/perftests/windowmanager/AndroidManifest.xml
index 85fd7176c33a..95ede345fbee 100644
--- a/apct-tests/perftests/windowmanager/AndroidManifest.xml
+++ b/apct-tests/perftests/windowmanager/AndroidManifest.xml
@@ -29,5 +29,7 @@
</application>
<instrumentation android:name="androidx.test.runner.AndroidJUnitRunner"
- android:targetPackage="com.android.perftests.wm"/>
+ android:targetPackage="com.android.perftests.wm">
+ <meta-data android:name="listener" android:value="android.wm.WmPerfRunListener" />
+ </instrumentation>
</manifest>
diff --git a/apct-tests/perftests/windowmanager/AndroidTest.xml b/apct-tests/perftests/windowmanager/AndroidTest.xml
index aee02c7ab767..6ac9f9373f8c 100644
--- a/apct-tests/perftests/windowmanager/AndroidTest.xml
+++ b/apct-tests/perftests/windowmanager/AndroidTest.xml
@@ -42,7 +42,7 @@
<option name="hidden-api-checks" value="false"/>
<!-- Listener related args for collecting the traces and waiting for the device to stabilize. -->
- <option name="device-listeners" value="android.wm.WmPerfRunListener,android.device.collectors.ProcLoadListener,android.device.collectors.PerfettoListener" />
+ <option name="device-listeners" value="android.device.collectors.ProcLoadListener,android.device.collectors.PerfettoListener" />
<!-- Guarantee that user defined RunListeners will be running before any of the default listeners defined in this runner. -->
<option name="instrumentation-arg" key="newRunListenerMode" value="true" />
@@ -57,8 +57,6 @@
<!-- PerfettoListener related arguments -->
<option name="instrumentation-arg" key="perfetto_config_text_proto" value="true" />
<option name="instrumentation-arg" key="perfetto_config_file" value="trace_config.textproto" />
-
- <option name="instrumentation-arg" key="newRunListenerMode" value="true" />
</test>
<metrics_collector class="com.android.tradefed.device.metric.FilePullerLogCollector">
diff --git a/apct-tests/perftests/windowmanager/README.md b/apct-tests/perftests/windowmanager/README.md
index 05fa6279a949..8b5292fd02a5 100644
--- a/apct-tests/perftests/windowmanager/README.md
+++ b/apct-tests/perftests/windowmanager/README.md
@@ -25,3 +25,11 @@ adb shell am instrument -w -r -e class android.wm.RelayoutPerfTest \
com.android.perftests.wm/androidx.test.runner.AndroidJUnitRunner
```
* `kill-bg` is optional.
+
+Test arguments
+ - kill-bg
+ * boolean: Kill background process before running test.
+ - profiling-iterations
+ * int: Run the extra iterations with enabling method profiling.
+ - profiling-sampling
+ * int: The interval (0=trace each method, default is 10) of sample profiling in microseconds.
diff --git a/apct-tests/perftests/windowmanager/src/android/wm/InternalWindowOperationPerfTest.java b/apct-tests/perftests/windowmanager/src/android/wm/InternalWindowOperationPerfTest.java
index 4ed3b4e09d11..5c09ec2e760f 100644
--- a/apct-tests/perftests/windowmanager/src/android/wm/InternalWindowOperationPerfTest.java
+++ b/apct-tests/perftests/windowmanager/src/android/wm/InternalWindowOperationPerfTest.java
@@ -41,7 +41,8 @@ import java.util.concurrent.TimeUnit;
/** Measure the performance of internal methods in window manager service by trace tag. */
@LargeTest
-public class InternalWindowOperationPerfTest extends WindowManagerPerfTestBase {
+public class InternalWindowOperationPerfTest extends WindowManagerPerfTestBase
+ implements ManualBenchmarkState.CustomizedIterationListener {
private static final String TAG = InternalWindowOperationPerfTest.class.getSimpleName();
@Rule
@@ -68,6 +69,9 @@ public class InternalWindowOperationPerfTest extends WindowManagerPerfTestBase {
"finishActivity",
"startActivityInner");
+ private boolean mIsProfiling;
+ private boolean mIsTraceStarted;
+
@Test
@ManualBenchmarkTest(
targetTestDurationNs = 20 * TIME_1_S_IN_NS,
@@ -76,13 +80,13 @@ public class InternalWindowOperationPerfTest extends WindowManagerPerfTestBase {
| StatsReport.FLAG_MAX | StatsReport.FLAG_COEFFICIENT_VAR))
public void testLaunchAndFinishActivity() throws Throwable {
final ManualBenchmarkState state = mPerfStatusReporter.getBenchmarkState();
+ state.setCustomizedIterations(getProfilingIterations(), this);
long measuredTimeNs = 0;
- boolean isTraceStarted = false;
while (state.keepRunning(measuredTimeNs)) {
- if (!isTraceStarted && !state.isWarmingUp()) {
+ if (!mIsTraceStarted && !mIsProfiling && !state.isWarmingUp()) {
startAsyncAtrace();
- isTraceStarted = true;
+ mIsTraceStarted = true;
}
final long startTime = SystemClock.elapsedRealtimeNanos();
mActivityRule.launchActivity();
@@ -91,7 +95,9 @@ public class InternalWindowOperationPerfTest extends WindowManagerPerfTestBase {
measuredTimeNs = SystemClock.elapsedRealtimeNanos() - startTime;
}
- stopAsyncAtrace();
+ if (mIsTraceStarted) {
+ stopAsyncAtrace();
+ }
mTraceMarkParser.forAllSlices((key, slices) -> {
for (TraceMarkSlice slice : slices) {
@@ -108,7 +114,7 @@ public class InternalWindowOperationPerfTest extends WindowManagerPerfTestBase {
SystemClock.sleep(TimeUnit.NANOSECONDS.toMillis(TIME_1_S_IN_NS));
}
- private void stopAsyncAtrace() throws IOException {
+ private void stopAsyncAtrace() {
final ParcelFileDescriptor pfd = sUiAutomation.executeShellCommand("atrace --async_stop");
final InputStream inputStream = new ParcelFileDescriptor.AutoCloseInputStream(pfd);
try (BufferedReader reader = new BufferedReader(new InputStreamReader(inputStream))) {
@@ -116,6 +122,28 @@ public class InternalWindowOperationPerfTest extends WindowManagerPerfTestBase {
while ((line = reader.readLine()) != null) {
mTraceMarkParser.visit(line);
}
+ } catch (IOException e) {
+ Log.w(TAG, "Failed to read the result of stopped atrace", e);
+ }
+ }
+
+ @Override
+ public void onStart(int iteration) {
+ if (mIsTraceStarted) {
+ // Do not capture trace when profiling because the result will be much slower.
+ stopAsyncAtrace();
+ mIsTraceStarted = false;
+ }
+ mIsProfiling = true;
+ startProfiling(InternalWindowOperationPerfTest.class.getSimpleName()
+ + "_MethodTracing_" + iteration + ".trace");
+ }
+
+ @Override
+ public void onFinished(int iteration) {
+ stopProfiling();
+ if (iteration >= getProfilingIterations() - 1) {
+ mIsProfiling = false;
}
}
}
diff --git a/apct-tests/perftests/windowmanager/src/android/wm/RecentsAnimationPerfTest.java b/apct-tests/perftests/windowmanager/src/android/wm/RecentsAnimationPerfTest.java
index 6122ef254855..efcabd817109 100644
--- a/apct-tests/perftests/windowmanager/src/android/wm/RecentsAnimationPerfTest.java
+++ b/apct-tests/perftests/windowmanager/src/android/wm/RecentsAnimationPerfTest.java
@@ -62,7 +62,8 @@ import java.util.concurrent.TimeUnit;
@RunWith(Parameterized.class)
@LargeTest
-public class RecentsAnimationPerfTest extends WindowManagerPerfTestBase {
+public class RecentsAnimationPerfTest extends WindowManagerPerfTestBase
+ implements ManualBenchmarkState.CustomizedIterationListener {
private static Intent sRecentsIntent;
@Rule
@@ -162,6 +163,7 @@ public class RecentsAnimationPerfTest extends WindowManagerPerfTestBase {
| StatsReport.FLAG_COEFFICIENT_VAR))
public void testRecentsAnimation() throws Throwable {
final ManualBenchmarkState state = mPerfStatusReporter.getBenchmarkState();
+ state.setCustomizedIterations(getProfilingIterations(), this);
final IActivityTaskManager atm = ActivityTaskManager.getService();
final ArrayList<Pair<String, Boolean>> finishCases = new ArrayList<>();
@@ -230,7 +232,21 @@ public class RecentsAnimationPerfTest extends WindowManagerPerfTestBase {
state.addExtraResult("start", elapsedTimeNsOfStart);
// Ensure the animation callback is done.
- Assume.assumeTrue(recentsSemaphore.tryAcquire(TIME_5_S_IN_NS, TimeUnit.NANOSECONDS));
+ Assume.assumeTrue(recentsSemaphore.tryAcquire(
+ sIsProfilingMethod ? 10 * TIME_5_S_IN_NS : TIME_5_S_IN_NS,
+ TimeUnit.NANOSECONDS));
}
}
+
+ @Override
+ public void onStart(int iteration) {
+ startProfiling(RecentsAnimationPerfTest.class.getSimpleName()
+ + "_interval_" + intervalBetweenOperations
+ + "_MethodTracing_" + iteration + ".trace");
+ }
+
+ @Override
+ public void onFinished(int iteration) {
+ stopProfiling();
+ }
}
diff --git a/apct-tests/perftests/windowmanager/src/android/wm/RelayoutPerfTest.java b/apct-tests/perftests/windowmanager/src/android/wm/RelayoutPerfTest.java
index cff5663e9d9e..269742854cb0 100644
--- a/apct-tests/perftests/windowmanager/src/android/wm/RelayoutPerfTest.java
+++ b/apct-tests/perftests/windowmanager/src/android/wm/RelayoutPerfTest.java
@@ -54,7 +54,8 @@ import java.util.function.IntSupplier;
@RunWith(Parameterized.class)
@LargeTest
@Presubmit
-public class RelayoutPerfTest extends WindowManagerPerfTestBase {
+public class RelayoutPerfTest extends WindowManagerPerfTestBase
+ implements BenchmarkState.CustomizedIterationListener {
private int mIteration;
@Rule
@@ -93,9 +94,22 @@ public class RelayoutPerfTest extends WindowManagerPerfTestBase {
mActivityRule.runOnUiThread(() -> activity.setContentView(contentView));
getInstrumentation().waitForIdleSync();
+ final BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
+ state.setCustomizedIterations(getProfilingIterations(), this);
final RelayoutRunner relayoutRunner = new RelayoutRunner(activity, contentView.getWindow(),
() -> visibilities[mIteration++ % visibilities.length]);
- relayoutRunner.runBenchmark(mPerfStatusReporter.getBenchmarkState());
+ relayoutRunner.runBenchmark(state);
+ }
+
+ @Override
+ public void onStart(int iteration) {
+ startProfiling(RelayoutPerfTest.class.getSimpleName() + "_" + testName
+ + "_MethodTracing_" + iteration + ".trace");
+ }
+
+ @Override
+ public void onFinished(int iteration) {
+ stopProfiling();
}
/** A dummy view to get IWindow. */
diff --git a/apct-tests/perftests/windowmanager/src/android/wm/WindowAddRemovePerfTest.java b/apct-tests/perftests/windowmanager/src/android/wm/WindowAddRemovePerfTest.java
index c72cc9d635e0..c52b1300aedc 100644
--- a/apct-tests/perftests/windowmanager/src/android/wm/WindowAddRemovePerfTest.java
+++ b/apct-tests/perftests/windowmanager/src/android/wm/WindowAddRemovePerfTest.java
@@ -48,8 +48,6 @@ import org.junit.Test;
public class WindowAddRemovePerfTest extends WindowManagerPerfTestBase
implements ManualBenchmarkState.CustomizedIterationListener {
- private static final int PROFILED_ITERATIONS = 2;
-
@Rule
public final PerfManualStatusReporter mPerfStatusReporter = new PerfManualStatusReporter();
@@ -64,7 +62,7 @@ public class WindowAddRemovePerfTest extends WindowManagerPerfTestBase
sUiAutomation.dropShellPermissionIdentity();
}
- /** The last {@link #PROFILED_ITERATIONS} will provide the information of method profiling. */
+ /** The last customized iterations will provide the information of method profiling. */
@Override
public void onStart(int iteration) {
startProfiling(WindowAddRemovePerfTest.class.getSimpleName()
@@ -80,7 +78,7 @@ public class WindowAddRemovePerfTest extends WindowManagerPerfTestBase
@ManualBenchmarkTest(warmupDurationNs = TIME_1_S_IN_NS, targetTestDurationNs = TIME_5_S_IN_NS)
public void testAddRemoveWindow() throws Throwable {
final ManualBenchmarkState state = mPerfStatusReporter.getBenchmarkState();
- state.setCustomizedIterations(PROFILED_ITERATIONS, this);
+ state.setCustomizedIterations(getProfilingIterations(), this);
new TestWindow().runBenchmark(state);
}
diff --git a/apct-tests/perftests/windowmanager/src/android/wm/WindowManagerPerfTestBase.java b/apct-tests/perftests/windowmanager/src/android/wm/WindowManagerPerfTestBase.java
index cc0e939a2a80..b51a9a8fb0dd 100644
--- a/apct-tests/perftests/windowmanager/src/android/wm/WindowManagerPerfTestBase.java
+++ b/apct-tests/perftests/windowmanager/src/android/wm/WindowManagerPerfTestBase.java
@@ -32,6 +32,7 @@ import androidx.test.runner.lifecycle.ActivityLifecycleCallback;
import androidx.test.runner.lifecycle.ActivityLifecycleMonitorRegistry;
import androidx.test.runner.lifecycle.Stage;
+import org.junit.After;
import org.junit.BeforeClass;
import org.junit.runner.Description;
import org.junit.runners.model.Statement;
@@ -52,18 +53,17 @@ public class WindowManagerPerfTestBase {
/**
* The out directory matching the directory-keys of collector in AndroidTest.xml. The directory
- * is in /data because while enabling method profling of system server, it cannot write the
+ * is in /data because while enabling method profiling of system server, it cannot write the
* trace to external storage.
*/
static final File BASE_OUT_PATH = new File("/data/local/tmp/WmPerfTests");
+ static boolean sIsProfilingMethod;
+
@BeforeClass
public static void setUpOnce() {
final Context context = getInstrumentation().getContext();
- if (!BASE_OUT_PATH.exists()) {
- executeShellCommand("mkdir -p " + BASE_OUT_PATH);
- }
if (!context.getSystemService(PowerManager.class).isInteractive()
|| context.getSystemService(KeyguardManager.class).isKeyguardLocked()) {
executeShellCommand("input keyevent KEYCODE_WAKEUP");
@@ -73,6 +73,14 @@ public class WindowManagerPerfTestBase {
.addCategory(Intent.CATEGORY_HOME).setFlags(Intent.FLAG_ACTIVITY_NEW_TASK));
}
+ @After
+ public void tearDown() {
+ // Make sure that profiling is stopped if test fails.
+ if (sIsProfilingMethod) {
+ stopProfiling();
+ }
+ }
+
/**
* Executes shell command with reading the output. It may also used to block until the current
* command is completed.
@@ -93,12 +101,26 @@ public class WindowManagerPerfTestBase {
}
/** Starts method tracing on system server. */
- void startProfiling(String subPath) {
- executeShellCommand("am profile start system " + new File(BASE_OUT_PATH, subPath));
+ static void startProfiling(String subPath) {
+ if (!BASE_OUT_PATH.exists()) {
+ executeShellCommand("mkdir -p " + BASE_OUT_PATH);
+ }
+ final String samplingArg = WmPerfRunListener.sSamplingIntervalUs > 0
+ ? ("--sampling " + WmPerfRunListener.sSamplingIntervalUs)
+ : "";
+ executeShellCommand("am profile start " + samplingArg + " system "
+ + new File(BASE_OUT_PATH, subPath));
+ sIsProfilingMethod = true;
}
- void stopProfiling() {
+ static void stopProfiling() {
executeShellCommand("am profile stop system");
+ sIsProfilingMethod = false;
+ }
+
+ /** Returns how many iterations should run with method tracing. */
+ static int getProfilingIterations() {
+ return WmPerfRunListener.sProfilingIterations;
}
static void runWithShellPermissionIdentity(Runnable runnable) {
diff --git a/apct-tests/perftests/windowmanager/src/android/wm/WmPerfRunListener.java b/apct-tests/perftests/windowmanager/src/android/wm/WmPerfRunListener.java
index 6eb85aacb4e8..d955289e5f49 100644
--- a/apct-tests/perftests/windowmanager/src/android/wm/WmPerfRunListener.java
+++ b/apct-tests/perftests/windowmanager/src/android/wm/WmPerfRunListener.java
@@ -31,6 +31,7 @@ import android.os.BatteryManager;
import android.os.Bundle;
import android.os.SystemClock;
import android.provider.Settings;
+import android.util.Log;
import android.view.WindowManagerPolicyConstants;
import android.wm.WindowManagerPerfTestBase.SettingsSession;
@@ -46,10 +47,22 @@ import java.util.List;
/** Prepare the preconditions before running performance test. */
public class WmPerfRunListener extends RunListener {
-
- private static final String OPTION_KILL_BACKGROUND = "kill-bg";
+ private static final String TAG = WmPerfRunListener.class.getSimpleName();
+
+ private static final String ARGUMENT_LOG_ONLY = "log";
+ private static final String ARGUMENT_KILL_BACKGROUND = "kill-bg";
+ private static final String ARGUMENT_PROFILING_ITERATIONS = "profiling-iterations";
+ private static final String ARGUMENT_PROFILING_SAMPLING = "profiling-sampling";
+ private static final String DEFAULT_PROFILING_ITERATIONS = "0";
+ private static final String DEFAULT_PROFILING_SAMPLING_US = "10";
private static final long KILL_BACKGROUND_WAIT_MS = 3000;
+ /** The requested iterations to run with method profiling. */
+ static int sProfilingIterations;
+
+ /** The interval of sample profiling in microseconds. */
+ static int sSamplingIntervalUs;
+
private final Context mContext = InstrumentationRegistry.getInstrumentation().getContext();
private long mWaitPreconditionDoneMs = 500;
@@ -83,6 +96,16 @@ public class WmPerfRunListener extends RunListener {
@Override
public void testRunStarted(Description description) {
final Bundle arguments = InstrumentationRegistry.getArguments();
+ // If true, it only logs the method names without running.
+ final boolean skip = Boolean.parseBoolean(arguments.getString(ARGUMENT_LOG_ONLY, "false"));
+ Log.i(TAG, "arguments=" + arguments);
+ if (skip) {
+ return;
+ }
+ sProfilingIterations = Integer.parseInt(
+ arguments.getString(ARGUMENT_PROFILING_ITERATIONS, DEFAULT_PROFILING_ITERATIONS));
+ sSamplingIntervalUs = Integer.parseInt(
+ arguments.getString(ARGUMENT_PROFILING_SAMPLING, DEFAULT_PROFILING_SAMPLING_US));
// Use gesture navigation for consistency.
mNavigationModeSetting.set(WindowManagerPolicyConstants.NAV_BAR_MODE_GESTURAL);
@@ -97,7 +120,7 @@ public class WmPerfRunListener extends RunListener {
});
PhoneWindow.sendCloseSystemWindows(mContext, "WmPerfTests");
- if (Boolean.parseBoolean(arguments.getString(OPTION_KILL_BACKGROUND))) {
+ if (Boolean.parseBoolean(arguments.getString(ARGUMENT_KILL_BACKGROUND))) {
runWithShellPermissionIdentity(this::killBackgroundProcesses);
mWaitPreconditionDoneMs = KILL_BACKGROUND_WAIT_MS;
}
diff --git a/apex/jobscheduler/service/java/com/android/server/alarm/Alarm.java b/apex/jobscheduler/service/java/com/android/server/alarm/Alarm.java
new file mode 100644
index 000000000000..f672e4b711c4
--- /dev/null
+++ b/apex/jobscheduler/service/java/com/android/server/alarm/Alarm.java
@@ -0,0 +1,211 @@
+/*
+ * 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.alarm;
+
+import static android.app.AlarmManager.ELAPSED_REALTIME_WAKEUP;
+import static android.app.AlarmManager.RTC;
+import static android.app.AlarmManager.RTC_WAKEUP;
+
+import android.app.AlarmManager;
+import android.app.IAlarmListener;
+import android.app.PendingIntent;
+import android.os.WorkSource;
+import android.util.IndentingPrintWriter;
+import android.util.TimeUtils;
+import android.util.proto.ProtoOutputStream;
+
+import java.io.PrintWriter;
+import java.text.SimpleDateFormat;
+import java.util.Date;
+
+class Alarm {
+ public final int type;
+ public final long origWhen;
+ public final boolean wakeup;
+ public final PendingIntent operation;
+ public final IAlarmListener listener;
+ public final String listenerTag;
+ public final String statsTag;
+ public final WorkSource workSource;
+ public final int flags;
+ public final AlarmManager.AlarmClockInfo alarmClock;
+ public final int uid;
+ public final int creatorUid;
+ public final String packageName;
+ public final String sourcePackage;
+ public int count;
+ public long when;
+ public long windowLength;
+ public long whenElapsed; // 'when' in the elapsed time base
+ public long maxWhenElapsed; // also in the elapsed time base
+ // Expected alarm expiry time before app standby deferring is applied.
+ public long expectedWhenElapsed;
+ public long expectedMaxWhenElapsed;
+ public long repeatInterval;
+ public AlarmManagerService.PriorityClass priorityClass;
+
+ Alarm(int _type, long _when, long _whenElapsed, long _windowLength, long _maxWhen,
+ long _interval, PendingIntent _op, IAlarmListener _rec, String _listenerTag,
+ WorkSource _ws, int _flags, AlarmManager.AlarmClockInfo _info,
+ int _uid, String _pkgName) {
+ type = _type;
+ origWhen = _when;
+ wakeup = _type == AlarmManager.ELAPSED_REALTIME_WAKEUP
+ || _type == AlarmManager.RTC_WAKEUP;
+ when = _when;
+ whenElapsed = _whenElapsed;
+ expectedWhenElapsed = _whenElapsed;
+ windowLength = _windowLength;
+ maxWhenElapsed = expectedMaxWhenElapsed = AlarmManagerService.clampPositive(_maxWhen);
+ repeatInterval = _interval;
+ operation = _op;
+ listener = _rec;
+ listenerTag = _listenerTag;
+ statsTag = makeTag(_op, _listenerTag, _type);
+ workSource = _ws;
+ flags = _flags;
+ alarmClock = _info;
+ uid = _uid;
+ packageName = _pkgName;
+ sourcePackage = (operation != null) ? operation.getCreatorPackage() : packageName;
+ creatorUid = (operation != null) ? operation.getCreatorUid() : uid;
+ }
+
+ public static String makeTag(PendingIntent pi, String tag, int type) {
+ final String alarmString = type == ELAPSED_REALTIME_WAKEUP || type == RTC_WAKEUP
+ ? "*walarm*:" : "*alarm*:";
+ return (pi != null) ? pi.getTag(alarmString) : (alarmString + tag);
+ }
+
+ public AlarmManagerService.WakeupEvent makeWakeupEvent(long nowRTC) {
+ return new AlarmManagerService.WakeupEvent(nowRTC, creatorUid,
+ (operation != null)
+ ? operation.getIntent().getAction()
+ : ("<listener>:" + listenerTag));
+ }
+
+ // Returns true if either matches
+ public boolean matches(PendingIntent pi, IAlarmListener rec) {
+ return (operation != null)
+ ? operation.equals(pi)
+ : rec != null && listener.asBinder().equals(rec.asBinder());
+ }
+
+ public boolean matches(String packageName) {
+ return packageName.equals(sourcePackage);
+ }
+
+ @Override
+ public String toString() {
+ StringBuilder sb = new StringBuilder(128);
+ sb.append("Alarm{");
+ sb.append(Integer.toHexString(System.identityHashCode(this)));
+ sb.append(" type ");
+ sb.append(type);
+ sb.append(" when ");
+ sb.append(when);
+ sb.append(" ");
+ sb.append(" whenElapsed ");
+ sb.append(whenElapsed);
+ sb.append(" ");
+ sb.append(sourcePackage);
+ sb.append('}');
+ return sb.toString();
+ }
+
+ /**
+ * @deprecated Use {{@link #dump(IndentingPrintWriter, long, SimpleDateFormat)}} instead.
+ */
+ @Deprecated
+ public void dump(PrintWriter pw, String prefix, long nowELAPSED, SimpleDateFormat sdf) {
+ final IndentingPrintWriter ipw = new IndentingPrintWriter(pw, prefix, prefix);
+ dump(ipw, nowELAPSED, sdf);
+ }
+
+ public void dump(IndentingPrintWriter ipw, long nowELAPSED, SimpleDateFormat sdf) {
+ final boolean isRtc = (type == RTC || type == RTC_WAKEUP);
+ ipw.print("tag=");
+ ipw.println(statsTag);
+
+ ipw.print("type=");
+ ipw.print(type);
+ ipw.print(" expectedWhenElapsed=");
+ TimeUtils.formatDuration(expectedWhenElapsed, nowELAPSED, ipw);
+ ipw.print(" expectedMaxWhenElapsed=");
+ TimeUtils.formatDuration(expectedMaxWhenElapsed, nowELAPSED, ipw);
+ ipw.print(" whenElapsed=");
+ TimeUtils.formatDuration(whenElapsed, nowELAPSED, ipw);
+ ipw.print(" maxWhenElapsed=");
+ TimeUtils.formatDuration(maxWhenElapsed, nowELAPSED, ipw);
+ ipw.print(" when=");
+ if (isRtc) {
+ ipw.print(sdf.format(new Date(when)));
+ } else {
+ TimeUtils.formatDuration(when, nowELAPSED, ipw);
+ }
+ ipw.println();
+
+ ipw.print("window=");
+ TimeUtils.formatDuration(windowLength, ipw);
+ ipw.print(" repeatInterval=");
+ ipw.print(repeatInterval);
+ ipw.print(" count=");
+ ipw.print(count);
+ ipw.print(" flags=0x");
+ ipw.println(Integer.toHexString(flags));
+
+ if (alarmClock != null) {
+ ipw.println("Alarm clock:");
+
+ ipw.print(" triggerTime=");
+ ipw.println(sdf.format(new Date(alarmClock.getTriggerTime())));
+
+ ipw.print(" showIntent=");
+ ipw.println(alarmClock.getShowIntent());
+ }
+ ipw.print("operation=");
+ ipw.println(operation);
+
+ if (listener != null) {
+ ipw.print("listener=");
+ ipw.println(listener.asBinder());
+ }
+ }
+
+ public void dumpDebug(ProtoOutputStream proto, long fieldId, long nowElapsed) {
+ final long token = proto.start(fieldId);
+
+ proto.write(AlarmProto.TAG, statsTag);
+ proto.write(AlarmProto.TYPE, type);
+ proto.write(AlarmProto.TIME_UNTIL_WHEN_ELAPSED_MS, whenElapsed - nowElapsed);
+ proto.write(AlarmProto.WINDOW_LENGTH_MS, windowLength);
+ proto.write(AlarmProto.REPEAT_INTERVAL_MS, repeatInterval);
+ proto.write(AlarmProto.COUNT, count);
+ proto.write(AlarmProto.FLAGS, flags);
+ if (alarmClock != null) {
+ alarmClock.dumpDebug(proto, AlarmProto.ALARM_CLOCK);
+ }
+ if (operation != null) {
+ operation.dumpDebug(proto, AlarmProto.OPERATION);
+ }
+ if (listener != null) {
+ proto.write(AlarmProto.LISTENER, listener.asBinder().toString());
+ }
+
+ proto.end(token);
+ }
+}
diff --git a/apex/jobscheduler/service/java/com/android/server/alarm/AlarmManagerService.java b/apex/jobscheduler/service/java/com/android/server/alarm/AlarmManagerService.java
index e2f13c560879..ec7e99e78cb3 100644
--- a/apex/jobscheduler/service/java/com/android/server/alarm/AlarmManagerService.java
+++ b/apex/jobscheduler/service/java/com/android/server/alarm/AlarmManagerService.java
@@ -75,6 +75,7 @@ import android.text.format.DateFormat;
import android.text.format.DateUtils;
import android.util.ArrayMap;
import android.util.ArraySet;
+import android.util.IndentingPrintWriter;
import android.util.KeyValueListParser;
import android.util.Log;
import android.util.LongArrayQueue;
@@ -91,10 +92,8 @@ import android.util.proto.ProtoOutputStream;
import com.android.internal.annotations.GuardedBy;
import com.android.internal.annotations.VisibleForTesting;
-import com.android.internal.util.ArrayUtils;
import com.android.internal.util.DumpUtils;
import com.android.internal.util.FrameworkStatsLog;
-import com.android.internal.util.IndentingPrintWriter;
import com.android.internal.util.LocalLog;
import com.android.internal.util.StatLogger;
import com.android.server.AlarmManagerInternal;
@@ -109,7 +108,6 @@ import com.android.server.SystemServiceManager;
import com.android.server.usage.AppStandbyInternal;
import com.android.server.usage.AppStandbyInternal.AppIdleStateChangeListener;
-import java.io.ByteArrayOutputStream;
import java.io.FileDescriptor;
import java.io.PrintWriter;
import java.text.SimpleDateFormat;
@@ -121,7 +119,6 @@ import java.util.Collections;
import java.util.Comparator;
import java.util.Date;
import java.util.HashMap;
-import java.util.LinkedList;
import java.util.Locale;
import java.util.Random;
import java.util.TimeZone;
@@ -132,23 +129,18 @@ import java.util.function.Predicate;
* Alarm manager implementation.
*
* Unit test:
- atest $ANDROID_BUILD_TOP/frameworks/base/services/tests/servicestests/src/com/android/server/AlarmManagerServiceTest.java
+ * atest FrameworksMockingServicesTests:com.android.server.alarm.AlarmManagerServiceTest
*/
public class AlarmManagerService extends SystemService {
private static final int RTC_WAKEUP_MASK = 1 << RTC_WAKEUP;
- private static final int RTC_MASK = 1 << RTC;
private static final int ELAPSED_REALTIME_WAKEUP_MASK = 1 << ELAPSED_REALTIME_WAKEUP;
- private static final int ELAPSED_REALTIME_MASK = 1 << ELAPSED_REALTIME;
static final int TIME_CHANGED_MASK = 1 << 16;
- static final int IS_WAKEUP_MASK = RTC_WAKEUP_MASK|ELAPSED_REALTIME_WAKEUP_MASK;
-
- // Mask for testing whether a given alarm type is wakeup vs non-wakeup
- static final int TYPE_NONWAKEUP_MASK = 0x1; // low bit => non-wakeup
+ static final int IS_WAKEUP_MASK = RTC_WAKEUP_MASK | ELAPSED_REALTIME_WAKEUP_MASK;
static final String TAG = "AlarmManager";
+ static final String TIME_TICK_TAG = "TIME_TICK";
static final boolean localLOGV = false;
static final boolean DEBUG_BATCH = localLOGV || false;
- static final boolean DEBUG_VALIDATE = localLOGV || false;
static final boolean DEBUG_ALARM_CLOCK = localLOGV || false;
static final boolean DEBUG_LISTENER_CALLBACK = localLOGV || false;
static final boolean DEBUG_WAKELOCK = localLOGV || false;
@@ -170,9 +162,6 @@ public class AlarmManagerService extends SystemService {
private final Intent mBackgroundIntent
= new Intent().addFlags(Intent.FLAG_FROM_BACKGROUND);
- static final IncreasingTimeOrder sIncreasingTimeOrder = new IncreasingTimeOrder();
-
- static final boolean WAKEUP_STATS = false;
private static final Intent NEXT_ALARM_CLOCK_CHANGED_INTENT =
new Intent(AlarmManager.ACTION_NEXT_ALARM_CLOCK_CHANGED)
@@ -199,8 +188,6 @@ public class AlarmManagerService extends SystemService {
private long mLastTickSet;
private long mLastTickReceived;
- private long mLastTickAdded;
- private long mLastTickRemoved;
// ring buffer of recent TIME_TICK issuance, in the elapsed timebase
private final long[] mTickHistory = new long[TICK_HISTORY_DEPTH];
private int mNextTickHistory;
@@ -250,6 +237,10 @@ public class AlarmManagerService extends SystemService {
*/
final SparseBooleanArray mUseAllowWhileIdleShortTime = new SparseBooleanArray();
+ static boolean isTimeTickAlarm(Alarm a) {
+ return a.uid == Process.SYSTEM_UID && TIME_TICK_TAG.equals(a.listenerTag);
+ }
+
final static class IdleDispatchEntry {
int uid;
String pkg;
@@ -261,12 +252,10 @@ public class AlarmManagerService extends SystemService {
final ArrayList<IdleDispatchEntry> mAllowWhileIdleDispatches = new ArrayList();
interface Stats {
- int REBATCH_ALL_ALARMS = 0;
int REORDER_ALARMS_FOR_STANDBY = 1;
}
- private final StatLogger mStatLogger = new StatLogger(new String[] {
- "REBATCH_ALL_ALARMS",
+ private final StatLogger mStatLogger = new StatLogger("Alarm manager stats", new String[]{
"REORDER_ALARMS_FOR_STANDBY",
});
@@ -342,7 +331,7 @@ public class AlarmManagerService extends SystemService {
/**
* @param n The desired nth-last wakeup
- * (1=1st-last=the ultimate wakeup and 2=2nd-last=the penultimate wakeup)
+ * (1=1st-last=the ultimate wakeup and 2=2nd-last=the penultimate wakeup)
*/
long getNthLastWakeupForPackage(String packageName, int userId, int n) {
final LongArrayQueue history = mPackageHistory.get(Pair.create(packageName, userId));
@@ -423,8 +412,8 @@ public class AlarmManagerService extends SystemService {
private static final long DEFAULT_MIN_INTERVAL = 60 * 1000;
private static final long DEFAULT_MAX_INTERVAL = 365 * DateUtils.DAY_IN_MILLIS;
private static final long DEFAULT_ALLOW_WHILE_IDLE_SHORT_TIME = DEFAULT_MIN_FUTURITY;
- private static final long DEFAULT_ALLOW_WHILE_IDLE_LONG_TIME = 9*60*1000;
- private static final long DEFAULT_ALLOW_WHILE_IDLE_WHITELIST_DURATION = 10*1000;
+ private static final long DEFAULT_ALLOW_WHILE_IDLE_LONG_TIME = 9 * 60 * 1000;
+ private static final long DEFAULT_ALLOW_WHILE_IDLE_WHITELIST_DURATION = 10 * 1000;
private static final long DEFAULT_LISTENER_TIMEOUT = 5 * 1000;
private static final int DEFAULT_MAX_ALARMS_PER_UID = 500;
private static final long DEFAULT_APP_STANDBY_WINDOW = 60 * 60 * 1000; // 1 hr
@@ -571,50 +560,62 @@ public class AlarmManagerService extends SystemService {
pw.increaseIndent();
- pw.print(KEY_MIN_FUTURITY); pw.print("=");
+ pw.print(KEY_MIN_FUTURITY);
+ pw.print("=");
TimeUtils.formatDuration(MIN_FUTURITY, pw);
pw.println();
- pw.print(KEY_MIN_INTERVAL); pw.print("=");
+ pw.print(KEY_MIN_INTERVAL);
+ pw.print("=");
TimeUtils.formatDuration(MIN_INTERVAL, pw);
pw.println();
- pw.print(KEY_MAX_INTERVAL); pw.print("=");
+ pw.print(KEY_MAX_INTERVAL);
+ pw.print("=");
TimeUtils.formatDuration(MAX_INTERVAL, pw);
pw.println();
- pw.print(KEY_LISTENER_TIMEOUT); pw.print("=");
+ pw.print(KEY_LISTENER_TIMEOUT);
+ pw.print("=");
TimeUtils.formatDuration(LISTENER_TIMEOUT, pw);
pw.println();
- pw.print(KEY_ALLOW_WHILE_IDLE_SHORT_TIME); pw.print("=");
+ pw.print(KEY_ALLOW_WHILE_IDLE_SHORT_TIME);
+ pw.print("=");
TimeUtils.formatDuration(ALLOW_WHILE_IDLE_SHORT_TIME, pw);
pw.println();
- pw.print(KEY_ALLOW_WHILE_IDLE_LONG_TIME); pw.print("=");
+ pw.print(KEY_ALLOW_WHILE_IDLE_LONG_TIME);
+ pw.print("=");
TimeUtils.formatDuration(ALLOW_WHILE_IDLE_LONG_TIME, pw);
pw.println();
- pw.print(KEY_ALLOW_WHILE_IDLE_WHITELIST_DURATION); pw.print("=");
+ pw.print(KEY_ALLOW_WHILE_IDLE_WHITELIST_DURATION);
+ pw.print("=");
TimeUtils.formatDuration(ALLOW_WHILE_IDLE_WHITELIST_DURATION, pw);
pw.println();
- pw.print(KEY_MAX_ALARMS_PER_UID); pw.print("=");
+ pw.print(KEY_MAX_ALARMS_PER_UID);
+ pw.print("=");
pw.println(MAX_ALARMS_PER_UID);
- pw.print(KEY_APP_STANDBY_WINDOW); pw.print("=");
+ pw.print(KEY_APP_STANDBY_WINDOW);
+ pw.print("=");
TimeUtils.formatDuration(APP_STANDBY_WINDOW, pw);
pw.println();
for (int i = 0; i < KEYS_APP_STANDBY_QUOTAS.length; i++) {
- pw.print(KEYS_APP_STANDBY_QUOTAS[i]); pw.print("=");
+ pw.print(KEYS_APP_STANDBY_QUOTAS[i]);
+ pw.print("=");
pw.println(APP_STANDBY_QUOTAS[i]);
}
- pw.print(KEY_APP_STANDBY_RESTRICTED_QUOTA); pw.print("=");
+ pw.print(KEY_APP_STANDBY_RESTRICTED_QUOTA);
+ pw.print("=");
pw.println(APP_STANDBY_RESTRICTED_QUOTA);
- pw.print(KEY_APP_STANDBY_RESTRICTED_WINDOW); pw.print("=");
+ pw.print(KEY_APP_STANDBY_RESTRICTED_WINDOW);
+ pw.print("=");
TimeUtils.formatDuration(APP_STANDBY_RESTRICTED_WINDOW, pw);
pw.println();
@@ -671,182 +672,6 @@ public class AlarmManagerService extends SystemService {
}
}
- final LinkedList<WakeupEvent> mRecentWakeups = new LinkedList<WakeupEvent>();
- final long RECENT_WAKEUP_PERIOD = 1000L * 60 * 60 * 24; // one day
-
- final class Batch {
- long start; // These endpoints are always in ELAPSED
- long end;
- int flags; // Flags for alarms, such as FLAG_STANDALONE.
-
- final ArrayList<Alarm> alarms = new ArrayList<Alarm>();
-
- Batch(Alarm seed) {
- start = seed.whenElapsed;
- end = clampPositive(seed.maxWhenElapsed);
- flags = seed.flags;
- alarms.add(seed);
- if (seed.listener == mTimeTickTrigger) {
- mLastTickAdded = mInjector.getCurrentTimeMillis();
- }
- }
-
- int size() {
- return alarms.size();
- }
-
- Alarm get(int index) {
- return alarms.get(index);
- }
-
- boolean canHold(long whenElapsed, long maxWhen) {
- return (end >= whenElapsed) && (start <= maxWhen);
- }
-
- boolean add(Alarm alarm) {
- boolean newStart = false;
- // narrows the batch if necessary; presumes that canHold(alarm) is true
- int index = Collections.binarySearch(alarms, alarm, sIncreasingTimeOrder);
- if (index < 0) {
- index = 0 - index - 1;
- }
- alarms.add(index, alarm);
- if (alarm.listener == mTimeTickTrigger) {
- mLastTickAdded = mInjector.getCurrentTimeMillis();
- }
- if (DEBUG_BATCH) {
- Slog.v(TAG, "Adding " + alarm + " to " + this);
- }
- if (alarm.whenElapsed > start) {
- start = alarm.whenElapsed;
- newStart = true;
- }
- if (alarm.maxWhenElapsed < end) {
- end = alarm.maxWhenElapsed;
- }
- flags |= alarm.flags;
-
- if (DEBUG_BATCH) {
- Slog.v(TAG, " => now " + this);
- }
- return newStart;
- }
-
- /**
- * Remove an alarm from this batch.
- * <p> <b> Should be used only while re-ordering the alarm within the service </b> as it
- * does not update {@link #mAlarmsPerUid}
- */
- boolean remove(Alarm alarm) {
- return remove(a -> (a == alarm), true);
- }
-
- boolean remove(Predicate<Alarm> predicate, boolean reOrdering) {
- boolean didRemove = false;
- long newStart = 0; // recalculate endpoints as we go
- long newEnd = Long.MAX_VALUE;
- int newFlags = 0;
- for (int i = 0; i < alarms.size(); ) {
- Alarm alarm = alarms.get(i);
- if (predicate.test(alarm)) {
- alarms.remove(i);
- if (!reOrdering) {
- decrementAlarmCount(alarm.uid, 1);
- }
- didRemove = true;
- if (alarm.alarmClock != null) {
- mNextAlarmClockMayChange = true;
- }
- if (alarm.listener == mTimeTickTrigger) {
- mLastTickRemoved = mInjector.getCurrentTimeMillis();
- }
- } else {
- if (alarm.whenElapsed > newStart) {
- newStart = alarm.whenElapsed;
- }
- if (alarm.maxWhenElapsed < newEnd) {
- newEnd = alarm.maxWhenElapsed;
- }
- newFlags |= alarm.flags;
- i++;
- }
- }
- if (didRemove) {
- // commit the new batch bounds
- start = newStart;
- end = newEnd;
- flags = newFlags;
- }
- return didRemove;
- }
-
- boolean hasPackage(final String packageName) {
- final int N = alarms.size();
- for (int i = 0; i < N; i++) {
- Alarm a = alarms.get(i);
- if (a.matches(packageName)) {
- return true;
- }
- }
- return false;
- }
-
- boolean hasWakeups() {
- final int N = alarms.size();
- for (int i = 0; i < N; i++) {
- Alarm a = alarms.get(i);
- // non-wakeup alarms are types 1 and 3, i.e. have the low bit set
- if ((a.type & TYPE_NONWAKEUP_MASK) == 0) {
- return true;
- }
- }
- return false;
- }
-
- @Override
- public String toString() {
- StringBuilder b = new StringBuilder(40);
- b.append("Batch{"); b.append(Integer.toHexString(this.hashCode()));
- b.append(" num="); b.append(size());
- b.append(" start="); b.append(start);
- b.append(" end="); b.append(end);
- if (flags != 0) {
- b.append(" flgs=0x");
- b.append(Integer.toHexString(flags));
- }
- b.append('}');
- return b.toString();
- }
-
- public void dumpDebug(ProtoOutputStream proto, long fieldId, long nowElapsed,
- long nowRTC) {
- final long token = proto.start(fieldId);
-
- proto.write(BatchProto.START_REALTIME, start);
- proto.write(BatchProto.END_REALTIME, end);
- proto.write(BatchProto.FLAGS, flags);
- for (Alarm a : alarms) {
- a.dumpDebug(proto, BatchProto.ALARMS, nowElapsed, nowRTC);
- }
-
- proto.end(token);
- }
- }
-
- static class BatchTimeOrder implements Comparator<Batch> {
- public int compare(Batch b1, Batch b2) {
- long when1 = b1.start;
- long when2 = b2.start;
- if (when1 > when2) {
- return 1;
- }
- if (when1 < when2) {
- return -1;
- }
- return 0;
- }
- }
-
final Comparator<Alarm> mAlarmDispatchComparator = new Comparator<Alarm>() {
@Override
public int compare(Alarm lhs, Alarm rhs) {
@@ -909,8 +734,8 @@ public class AlarmManagerService extends SystemService {
// minimum recurrence period or alarm futurity for us to be able to fuzz it
static final long MIN_FUZZABLE_INTERVAL = 10000;
- static final BatchTimeOrder sBatchOrder = new BatchTimeOrder();
- final ArrayList<Batch> mAlarmBatches = new ArrayList<>();
+ @GuardedBy("mLock")
+ final AlarmStore mAlarmStore;
// set to non-null if in idle mode; while in this mode, any alarms we don't want
// to run during this time are placed in mPendingWhileIdleAlarms
@@ -922,6 +747,7 @@ public class AlarmManagerService extends SystemService {
AlarmManagerService(Context context, Injector injector) {
super(context);
mInjector = injector;
+ mAlarmStore = new BatchingAlarmStore(() -> mNextAlarmClockMayChange = true);
}
public AlarmManagerService(Context context) {
@@ -949,171 +775,45 @@ public class AlarmManagerService extends SystemService {
if (futurity < MIN_FUZZABLE_INTERVAL) {
futurity = 0;
}
- return clampPositive(triggerAtTime + (long)(.75 * futurity));
- }
-
- // returns true if the batch was added at the head
- static boolean addBatchLocked(ArrayList<Batch> list, Batch newBatch) {
- int index = Collections.binarySearch(list, newBatch, sBatchOrder);
- if (index < 0) {
- index = 0 - index - 1;
- }
- list.add(index, newBatch);
- return (index == 0);
- }
-
- private void insertAndBatchAlarmLocked(Alarm alarm) {
- final int whichBatch = ((alarm.flags & AlarmManager.FLAG_STANDALONE) != 0) ? -1
- : attemptCoalesceLocked(alarm.whenElapsed, alarm.maxWhenElapsed);
-
- if (whichBatch < 0) {
- addBatchLocked(mAlarmBatches, new Batch(alarm));
- } else {
- final Batch batch = mAlarmBatches.get(whichBatch);
- if (batch.add(alarm)) {
- // The start time of this batch advanced, so batch ordering may
- // have just been broken. Move it to where it now belongs.
- mAlarmBatches.remove(whichBatch);
- addBatchLocked(mAlarmBatches, batch);
- }
- }
- }
-
- // Return the index of the matching batch, or -1 if none found.
- int attemptCoalesceLocked(long whenElapsed, long maxWhen) {
- final int N = mAlarmBatches.size();
- for (int i = 0; i < N; i++) {
- Batch b = mAlarmBatches.get(i);
- if ((b.flags&AlarmManager.FLAG_STANDALONE) == 0 && b.canHold(whenElapsed, maxWhen)) {
- return i;
- }
- }
- return -1;
- }
- /** @return total count of the alarms in a set of alarm batches. */
- static int getAlarmCount(ArrayList<Batch> batches) {
- int ret = 0;
-
- final int size = batches.size();
- for (int i = 0; i < size; i++) {
- ret += batches.get(i).size();
- }
- return ret;
- }
-
- boolean haveAlarmsTimeTickAlarm(ArrayList<Alarm> alarms) {
- if (alarms.size() == 0) {
- return false;
- }
- final int batchSize = alarms.size();
- for (int j = 0; j < batchSize; j++) {
- if (alarms.get(j).listener == mTimeTickTrigger) {
- return true;
- }
- }
- return false;
+ return clampPositive(triggerAtTime + (long) (.75 * futurity));
}
- boolean haveBatchesTimeTickAlarm(ArrayList<Batch> batches) {
- final int numBatches = batches.size();
- for (int i = 0; i < numBatches; i++) {
- if (haveAlarmsTimeTickAlarm(batches.get(i).alarms)) {
- return true;
- }
- }
- return false;
- }
-
- // The RTC clock has moved arbitrarily, so we need to recalculate all the batching
- void rebatchAllAlarms() {
+ // The RTC clock has moved arbitrarily, so we need to recalculate all the RTC alarm deliveries.
+ void reevaluateRtcAlarms(final long nowElapsed) {
synchronized (mLock) {
- rebatchAllAlarmsLocked(true);
- }
- }
-
- void rebatchAllAlarmsLocked(boolean doValidate) {
- final long start = mStatLogger.getTime();
- final int oldCount =
- getAlarmCount(mAlarmBatches) + ArrayUtils.size(mPendingWhileIdleAlarms);
- final boolean oldHasTick = haveBatchesTimeTickAlarm(mAlarmBatches)
- || haveAlarmsTimeTickAlarm(mPendingWhileIdleAlarms);
-
- ArrayList<Batch> oldSet = (ArrayList<Batch>) mAlarmBatches.clone();
- mAlarmBatches.clear();
- Alarm oldPendingIdleUntil = mPendingIdleUntil;
- final long nowElapsed = mInjector.getElapsedRealtime();
- final int oldBatches = oldSet.size();
- for (int batchNum = 0; batchNum < oldBatches; batchNum++) {
- Batch batch = oldSet.get(batchNum);
- final int N = batch.size();
- for (int i = 0; i < N; i++) {
- reAddAlarmLocked(batch.get(i), nowElapsed, doValidate);
- }
- }
- if (oldPendingIdleUntil != null && oldPendingIdleUntil != mPendingIdleUntil) {
- Slog.wtf(TAG, "Rebatching: idle until changed from " + oldPendingIdleUntil
- + " to " + mPendingIdleUntil);
- if (mPendingIdleUntil == null) {
- // Somehow we lost this... we need to restore all of the pending alarms.
- restorePendingWhileIdleAlarmsLocked();
+ final ArrayList<Alarm> rtcAlarms = mAlarmStore.remove(a -> (a.type == RTC
+ || a.type == RTC_WAKEUP));
+ for (final Alarm a : rtcAlarms) {
+ restoreAlarmLocked(a, nowElapsed);
+ setImplLocked(a);
}
}
- final int newCount =
- getAlarmCount(mAlarmBatches) + ArrayUtils.size(mPendingWhileIdleAlarms);
- final boolean newHasTick = haveBatchesTimeTickAlarm(mAlarmBatches)
- || haveAlarmsTimeTickAlarm(mPendingWhileIdleAlarms);
-
- if (oldCount != newCount) {
- Slog.wtf(TAG, "Rebatching: total count changed from " + oldCount + " to " + newCount);
- }
- if (oldHasTick != newHasTick) {
- Slog.wtf(TAG, "Rebatching: hasTick changed from " + oldHasTick + " to " + newHasTick);
- }
-
- rescheduleKernelAlarmsLocked();
- updateNextAlarmClockLocked();
- mStatLogger.logDurationStat(Stats.REBATCH_ALL_ALARMS, start);
}
/**
- * Re-orders the alarm batches based on newly evaluated send times based on the current
- * app-standby buckets
+ * Recalculates alarm send times based on the current app-standby buckets
+ *
* @param targetPackages [Package, User] pairs for which alarms need to be re-evaluated,
* null indicates all
* @return True if there was any reordering done to the current list.
*/
boolean reorderAlarmsBasedOnStandbyBuckets(ArraySet<Pair<String, Integer>> targetPackages) {
final long start = mStatLogger.getTime();
- final ArrayList<Alarm> rescheduledAlarms = new ArrayList<>();
-
- for (int batchIndex = mAlarmBatches.size() - 1; batchIndex >= 0; batchIndex--) {
- final Batch batch = mAlarmBatches.get(batchIndex);
- for (int alarmIndex = batch.size() - 1; alarmIndex >= 0; alarmIndex--) {
- final Alarm alarm = batch.get(alarmIndex);
- final Pair<String, Integer> packageUser =
- Pair.create(alarm.sourcePackage, UserHandle.getUserId(alarm.creatorUid));
- if (targetPackages != null && !targetPackages.contains(packageUser)) {
- continue;
- }
- if (adjustDeliveryTimeBasedOnBucketLocked(alarm)) {
- batch.remove(alarm);
- rescheduledAlarms.add(alarm);
- }
- }
- if (batch.size() == 0) {
- mAlarmBatches.remove(batchIndex);
+
+ final boolean changed = mAlarmStore.recalculateAlarmDeliveries(a -> {
+ final Pair<String, Integer> packageUser =
+ Pair.create(a.sourcePackage, UserHandle.getUserId(a.creatorUid));
+ if (targetPackages != null && !targetPackages.contains(packageUser)) {
+ return false;
}
- }
- for (int i = 0; i < rescheduledAlarms.size(); i++) {
- final Alarm a = rescheduledAlarms.get(i);
- insertAndBatchAlarmLocked(a);
- }
+ return adjustDeliveryTimeBasedOnBucketLocked(a);
+ });
mStatLogger.logDurationStat(Stats.REORDER_ALARMS_FOR_STANDBY, start);
- return rescheduledAlarms.size() > 0;
+ return changed;
}
- void reAddAlarmLocked(Alarm a, long nowElapsed, boolean doValidate) {
+ private void restoreAlarmLocked(Alarm a, long nowElapsed) {
a.when = a.origWhen;
long whenElapsed = convertToElapsed(a.when, a.type);
final long maxElapsed;
@@ -1130,7 +830,6 @@ public class AlarmManagerService extends SystemService {
}
a.expectedWhenElapsed = a.whenElapsed = whenElapsed;
a.expectedMaxWhenElapsed = a.maxWhenElapsed = maxElapsed;
- setImplLocked(a, true, doValidate);
}
static long clampPositive(long val) {
@@ -1141,7 +840,7 @@ public class AlarmManagerService extends SystemService {
* Sends alarms that were blocked due to user applied background restrictions - either because
* the user lifted those or the uid came to foreground.
*
- * @param uid uid to filter on
+ * @param uid uid to filter on
* @param packageName package to filter on, or null for all packages in uid
*/
void sendPendingBackgroundAlarmsLocked(int uid, String packageName) {
@@ -1236,7 +935,7 @@ public class AlarmManagerService extends SystemService {
final long nextElapsed = alarm.expectedWhenElapsed + delta;
setImplLocked(alarm.type, alarm.when + delta, nextElapsed, alarm.windowLength,
maxTriggerTime(nowELAPSED, nextElapsed, alarm.repeatInterval),
- alarm.repeatInterval, alarm.operation, null, null, alarm.flags, true,
+ alarm.repeatInterval, alarm.operation, null, null, alarm.flags,
alarm.workSource, alarm.alarmClock, alarm.uid, alarm.packageName);
// Kernel alarms will be rescheduled as needed in setImplLocked
}
@@ -1246,7 +945,7 @@ public class AlarmManagerService extends SystemService {
if (mPendingNonWakeupAlarms.size() == 0) {
mStartCurrentDelayTime = nowELAPSED;
mNextNonWakeupDeliveryTime = nowELAPSED
- + ((currentNonWakeupFuzzLocked(nowELAPSED)*3)/2);
+ + ((currentNonWakeupFuzzLocked(nowELAPSED) * 3) / 2);
}
mPendingNonWakeupAlarms.addAll(alarms);
mNumDelayedAlarms += alarms.size();
@@ -1284,9 +983,10 @@ public class AlarmManagerService extends SystemService {
ArrayList<Alarm> alarms = mPendingWhileIdleAlarms;
mPendingWhileIdleAlarms = new ArrayList<>();
final long nowElapsed = mInjector.getElapsedRealtime();
- for (int i=alarms.size() - 1; i >= 0; i--) {
+ for (int i = alarms.size() - 1; i >= 0; i--) {
Alarm a = alarms.get(i);
- reAddAlarmLocked(a, nowElapsed, false);
+ restoreAlarmLocked(a, nowElapsed);
+ setImplLocked(a);
}
}
@@ -1511,7 +1211,7 @@ public class AlarmManagerService extends SystemService {
// Ensure that we're booting with a halfway sensible current time. Use the
// most recent of Build.TIME, the root file system's timestamp, and the
// value of the ro.build.date.utc system property (which is in seconds).
- final long systemBuildTime = Long.max(
+ final long systemBuildTime = Long.max(
1000L * SystemProperties.getLong("ro.build.date.utc", -1L),
Long.max(Environment.getRootDirectory().lastModified(), Build.TIME));
if (mInjector.getCurrentTimeMillis() < systemBuildTime) {
@@ -1529,8 +1229,8 @@ public class AlarmManagerService extends SystemService {
mTimeTickIntent = new Intent(Intent.ACTION_TIME_TICK).addFlags(
Intent.FLAG_RECEIVER_REGISTERED_ONLY
- | Intent.FLAG_RECEIVER_FOREGROUND
- | Intent.FLAG_RECEIVER_VISIBLE_TO_INSTANT_APPS);
+ | Intent.FLAG_RECEIVER_FOREGROUND
+ | Intent.FLAG_RECEIVER_VISIBLE_TO_INSTANT_APPS);
mTimeTickTrigger = new IAlarmListener.Stub() {
@Override
@@ -1688,7 +1388,6 @@ public class AlarmManagerService extends SystemService {
PendingIntent operation, IAlarmListener directReceiver, String listenerTag,
int flags, WorkSource workSource, AlarmManager.AlarmClockInfo alarmClock,
int callingUid, String callingPackage) {
- // must be *either* PendingIntent or AlarmReceiver, but not both
if ((operation == null && directReceiver == null)
|| (operation != null && directReceiver != null)) {
Slog.w(TAG, "Alarms must either supply a PendingIntent or an AlarmReceiver");
@@ -1720,7 +1419,7 @@ public class AlarmManagerService extends SystemService {
final long minInterval = mConstants.MIN_INTERVAL;
if (interval > 0 && interval < minInterval) {
Slog.w(TAG, "Suspiciously short interval " + interval
- + " millis; expanding to " + (minInterval/1000)
+ + " millis; expanding to " + (minInterval / 1000)
+ " seconds");
interval = minInterval;
} else if (interval > mConstants.MAX_INTERVAL) {
@@ -1773,14 +1472,14 @@ public class AlarmManagerService extends SystemService {
throw new IllegalStateException(errorMsg);
}
setImplLocked(type, triggerAtTime, triggerElapsed, windowLength, maxElapsed,
- interval, operation, directReceiver, listenerTag, flags, true, workSource,
+ interval, operation, directReceiver, listenerTag, flags, workSource,
alarmClock, callingUid, callingPackage);
}
}
private void setImplLocked(int type, long when, long whenElapsed, long windowLength,
long maxWhen, long interval, PendingIntent operation, IAlarmListener directReceiver,
- String listenerTag, int flags, boolean doValidate, WorkSource workSource,
+ String listenerTag, int flags, WorkSource workSource,
AlarmManager.AlarmClockInfo alarmClock, int callingUid, String callingPackage) {
Alarm a = new Alarm(type, when, whenElapsed, windowLength, maxWhen, interval,
operation, directReceiver, listenerTag, workSource, flags, alarmClock,
@@ -1792,7 +1491,7 @@ public class AlarmManagerService extends SystemService {
}
removeLocked(operation, directReceiver);
incrementAlarmCount(a.uid);
- setImplLocked(a, false, doValidate);
+ setImplLocked(a);
}
/**
@@ -1817,7 +1516,46 @@ public class AlarmManagerService extends SystemService {
}
/**
+ * Adjusts the idle-until alarm delivery time based on the upcoming wake-from-idle alarm.
+ *
+ * @param alarm The alarm to adjust
+ * @return true if the alarm delivery time was updated.
+ */
+ private boolean adjustIdleUntilTime(Alarm alarm) {
+ if ((alarm.flags & AlarmManager.FLAG_IDLE_UNTIL) != 0) {
+ return false;
+ }
+ // This is a special alarm that will put the system into idle until it goes off.
+ // The caller has given the time they want this to happen at, however we need
+ // to pull that earlier if there are existing alarms that have requested to
+ // bring us out of idle at an earlier time.
+ if (mNextWakeFromIdle != null && alarm.whenElapsed > mNextWakeFromIdle.whenElapsed) {
+ alarm.when = alarm.whenElapsed = alarm.maxWhenElapsed = mNextWakeFromIdle.whenElapsed;
+ }
+ // Add fuzz to make the alarm go off some time before the actual desired time.
+ final long nowElapsed = mInjector.getElapsedRealtime();
+ final int fuzz = fuzzForDuration(alarm.whenElapsed - nowElapsed);
+ if (fuzz > 0) {
+ if (mRandom == null) {
+ mRandom = new Random();
+ }
+ final int delta = mRandom.nextInt(fuzz);
+ alarm.whenElapsed -= delta;
+ if (false) {
+ Slog.d(TAG, "Alarm when: " + alarm.whenElapsed);
+ Slog.d(TAG, "Delta until alarm: " + (alarm.whenElapsed - nowElapsed));
+ Slog.d(TAG, "Applied fuzz: " + fuzz);
+ Slog.d(TAG, "Final delta: " + delta);
+ Slog.d(TAG, "Final when: " + alarm.whenElapsed);
+ }
+ alarm.when = alarm.maxWhenElapsed = alarm.whenElapsed;
+ }
+ return true;
+ }
+
+ /**
* Adjusts the alarm delivery time based on the current app standby bucket.
+ *
* @param alarm The alarm to adjust
* @return true if the alarm delivery time was updated.
*/
@@ -1892,47 +1630,17 @@ public class AlarmManagerService extends SystemService {
return (oldWhenElapsed != alarm.whenElapsed || oldMaxWhenElapsed != alarm.maxWhenElapsed);
}
- private void setImplLocked(Alarm a, boolean rebatching, boolean doValidate) {
- if ((a.flags&AlarmManager.FLAG_IDLE_UNTIL) != 0) {
- // This is a special alarm that will put the system into idle until it goes off.
- // The caller has given the time they want this to happen at, however we need
- // to pull that earlier if there are existing alarms that have requested to
- // bring us out of idle at an earlier time.
- if (mNextWakeFromIdle != null && a.whenElapsed > mNextWakeFromIdle.whenElapsed) {
- a.when = a.whenElapsed = a.maxWhenElapsed = mNextWakeFromIdle.whenElapsed;
- }
- // Add fuzz to make the alarm go off some time before the actual desired time.
- final long nowElapsed = mInjector.getElapsedRealtime();
- final int fuzz = fuzzForDuration(a.whenElapsed-nowElapsed);
- if (fuzz > 0) {
- if (mRandom == null) {
- mRandom = new Random();
- }
- final int delta = mRandom.nextInt(fuzz);
- a.whenElapsed -= delta;
- if (false) {
- Slog.d(TAG, "Alarm when: " + a.whenElapsed);
- Slog.d(TAG, "Delta until alarm: " + (a.whenElapsed-nowElapsed));
- Slog.d(TAG, "Applied fuzz: " + fuzz);
- Slog.d(TAG, "Final delta: " + delta);
- Slog.d(TAG, "Final when: " + a.whenElapsed);
- }
- a.when = a.maxWhenElapsed = a.whenElapsed;
- }
+ private static boolean isAllowedWhileIdle(Alarm a) {
+ return ((a.flags & (AlarmManager.FLAG_ALLOW_WHILE_IDLE
+ | AlarmManager.FLAG_ALLOW_WHILE_IDLE_UNRESTRICTED
+ | AlarmManager.FLAG_WAKE_FROM_IDLE)) != 0);
+ }
- } else if (mPendingIdleUntil != null) {
- // We currently have an idle until alarm scheduled; if the new alarm has
- // not explicitly stated it wants to run while idle, then put it on hold.
- if ((a.flags&(AlarmManager.FLAG_ALLOW_WHILE_IDLE
- | AlarmManager.FLAG_ALLOW_WHILE_IDLE_UNRESTRICTED
- | AlarmManager.FLAG_WAKE_FROM_IDLE))
- == 0) {
- mPendingWhileIdleAlarms.add(a);
- return;
- }
- }
- if (RECORD_DEVICE_IDLE_ALARMS) {
- if ((a.flags & AlarmManager.FLAG_ALLOW_WHILE_IDLE) != 0) {
+ private void setImplLocked(Alarm a) {
+ if ((a.flags & AlarmManager.FLAG_IDLE_UNTIL) != 0) {
+ adjustIdleUntilTime(a);
+
+ if (RECORD_DEVICE_IDLE_ALARMS) {
IdleDispatchEntry ent = new IdleDispatchEntry();
ent.uid = a.uid;
ent.pkg = a.operation.getCreatorPackage();
@@ -1941,67 +1649,55 @@ public class AlarmManagerService extends SystemService {
ent.elapsedRealtime = mInjector.getElapsedRealtime();
ent.argRealtime = a.whenElapsed;
mAllowWhileIdleDispatches.add(ent);
- }
- }
- adjustDeliveryTimeBasedOnBucketLocked(a);
- insertAndBatchAlarmLocked(a);
-
- if (a.alarmClock != null) {
- mNextAlarmClockMayChange = true;
- }
-
- boolean needRebatch = false;
-
- if ((a.flags&AlarmManager.FLAG_IDLE_UNTIL) != 0) {
- if (RECORD_DEVICE_IDLE_ALARMS) {
if (mPendingIdleUntil == null) {
- IdleDispatchEntry ent = new IdleDispatchEntry();
- ent.uid = 0;
- ent.pkg = "START IDLE";
- ent.elapsedRealtime = mInjector.getElapsedRealtime();
- mAllowWhileIdleDispatches.add(ent);
+ IdleDispatchEntry ent2 = new IdleDispatchEntry();
+ ent2.uid = 0;
+ ent2.pkg = "START IDLE";
+ ent2.elapsedRealtime = mInjector.getElapsedRealtime();
+ mAllowWhileIdleDispatches.add(ent2);
}
}
if ((mPendingIdleUntil != a) && (mPendingIdleUntil != null)) {
Slog.wtfStack(TAG, "setImplLocked: idle until changed from " + mPendingIdleUntil
+ " to " + a);
}
-
mPendingIdleUntil = a;
- needRebatch = true;
- } else if ((a.flags&AlarmManager.FLAG_WAKE_FROM_IDLE) != 0) {
+ final ArrayList<Alarm> notAllowedWhileIdleAlarms = mAlarmStore.remove(
+ alarm -> !isAllowedWhileIdle(alarm));
+ mPendingWhileIdleAlarms.addAll(notAllowedWhileIdleAlarms);
+ } else if (mPendingIdleUntil != null) {
+ // We currently have an idle until alarm scheduled; if the new alarm has
+ // not explicitly stated it wants to run while idle, then put it on hold.
+ if (!isAllowedWhileIdle(a)) {
+ mPendingWhileIdleAlarms.add(a);
+ return;
+ }
+ }
+ if ((a.flags & AlarmManager.FLAG_WAKE_FROM_IDLE) != 0) {
if (mNextWakeFromIdle == null || mNextWakeFromIdle.whenElapsed > a.whenElapsed) {
mNextWakeFromIdle = a;
// If this wake from idle is earlier than whatever was previously scheduled,
// and we are currently idling, then we need to rebatch alarms in case the idle
// until time needs to be updated.
if (mPendingIdleUntil != null) {
- needRebatch = true;
+ final long nowElapsed = mInjector.getElapsedRealtime();
+ mAlarmStore.recalculateAlarmDeliveries(alarm -> {
+ if (alarm != mPendingIdleUntil) {
+ return false;
+ }
+ restoreAlarmLocked(alarm, nowElapsed);
+ return adjustIdleUntilTime(alarm);
+ });
}
}
}
-
- if (!rebatching) {
- if (DEBUG_VALIDATE) {
- if (doValidate && !validateConsistencyLocked()) {
- Slog.v(TAG, "Tipping-point operation: type=" + a.type + " when=" + a.when
- + " when(hex)=" + Long.toHexString(a.when)
- + " whenElapsed=" + a.whenElapsed
- + " maxWhenElapsed=" + a.maxWhenElapsed
- + " interval=" + a.repeatInterval + " op=" + a.operation
- + " flags=0x" + Integer.toHexString(a.flags));
- rebatchAllAlarmsLocked(false);
- needRebatch = false;
- }
- }
-
- if (needRebatch) {
- rebatchAllAlarmsLocked(false);
- }
-
- rescheduleKernelAlarmsLocked();
- updateNextAlarmClockLocked();
+ if (a.alarmClock != null) {
+ mNextAlarmClockMayChange = true;
}
+ adjustDeliveryTimeBasedOnBucketLocked(a);
+ mAlarmStore.add(a);
+ rescheduleKernelAlarmsLocked();
+ updateNextAlarmClockLocked();
}
/**
@@ -2051,7 +1747,8 @@ public class AlarmManagerService extends SystemService {
// Repeating alarms must use PendingIntent, not direct listener
if (interval != 0) {
if (directReceiver != null) {
- throw new IllegalArgumentException("Repeating alarms cannot use AlarmReceivers");
+ throw new IllegalArgumentException(
+ "Repeating alarms cannot use AlarmReceivers");
}
}
@@ -2194,17 +1891,27 @@ public class AlarmManagerService extends SystemService {
final long nowRTC = mInjector.getCurrentTimeMillis();
SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss.SSS");
- pw.print(" nowRTC="); pw.print(nowRTC);
- pw.print("="); pw.print(sdf.format(new Date(nowRTC)));
- pw.print(" nowELAPSED="); pw.print(nowELAPSED);
+ pw.print(" nowRTC=");
+ pw.print(nowRTC);
+ pw.print("=");
+ pw.print(sdf.format(new Date(nowRTC)));
+ pw.print(" nowELAPSED=");
+ pw.print(nowELAPSED);
pw.println();
- pw.print(" mLastTimeChangeClockTime="); pw.print(mLastTimeChangeClockTime);
- pw.print("="); pw.println(sdf.format(new Date(mLastTimeChangeClockTime)));
- pw.print(" mLastTimeChangeRealtime="); pw.println(mLastTimeChangeRealtime);
- pw.print(" mLastTickReceived="); pw.println(sdf.format(new Date(mLastTickReceived)));
- pw.print(" mLastTickSet="); pw.println(sdf.format(new Date(mLastTickSet)));
- pw.print(" mLastTickAdded="); pw.println(sdf.format(new Date(mLastTickAdded)));
- pw.print(" mLastTickRemoved="); pw.println(sdf.format(new Date(mLastTickRemoved)));
+
+ pw.print(" mLastTimeChangeClockTime=");
+ pw.print(mLastTimeChangeClockTime);
+ pw.print("=");
+ pw.println(sdf.format(new Date(mLastTimeChangeClockTime)));
+
+ pw.print(" mLastTimeChangeRealtime=");
+ pw.println(mLastTimeChangeRealtime);
+
+ pw.print(" mLastTickReceived=");
+ pw.println(sdf.format(new Date(mLastTickReceived)));
+
+ pw.print(" mLastTickSet=");
+ pw.println(sdf.format(new Date(mLastTickSet)));
if (RECORD_ALARMS_IN_HISTORY) {
pw.println();
@@ -2258,16 +1965,23 @@ public class AlarmManagerService extends SystemService {
long nextWakeupRTC = mNextWakeup + (nowRTC - nowELAPSED);
long nextNonWakeupRTC = mNextNonWakeup + (nowRTC - nowELAPSED);
pw.print(" Next non-wakeup alarm: ");
- TimeUtils.formatDuration(mNextNonWakeup, nowELAPSED, pw);
- pw.print(" = "); pw.print(mNextNonWakeup);
- pw.print(" = "); pw.println(sdf.format(new Date(nextNonWakeupRTC)));
- pw.print(" set at "); TimeUtils.formatDuration(mNextNonWakeUpSetAt, nowELAPSED, pw);
+ TimeUtils.formatDuration(mNextNonWakeup, nowELAPSED, pw);
+ pw.print(" = ");
+ pw.print(mNextNonWakeup);
+ pw.print(" = ");
+ pw.println(sdf.format(new Date(nextNonWakeupRTC)));
+ pw.print(" set at ");
+ TimeUtils.formatDuration(mNextNonWakeUpSetAt, nowELAPSED, pw);
+ pw.println();
+ pw.print(" Next wakeup alarm: ");
+ TimeUtils.formatDuration(mNextWakeup, nowELAPSED, pw);
+ pw.print(" = ");
+ pw.print(mNextWakeup);
+ pw.print(" = ");
+ pw.println(sdf.format(new Date(nextWakeupRTC)));
+ pw.print(" set at ");
+ TimeUtils.formatDuration(mNextWakeUpSetAt, nowELAPSED, pw);
pw.println();
- pw.print(" Next wakeup alarm: "); TimeUtils.formatDuration(mNextWakeup, nowELAPSED, pw);
- pw.print(" = "); pw.print(mNextWakeup);
- pw.print(" = "); pw.println(sdf.format(new Date(nextWakeupRTC)));
- pw.print(" set at "); TimeUtils.formatDuration(mNextWakeUpSetAt, nowELAPSED, pw);
- pw.println();
pw.print(" Next kernel non-wakeup alarm: ");
TimeUtils.formatDuration(mInjector.getNextAlarm(ELAPSED_REALTIME), pw);
@@ -2276,11 +1990,16 @@ public class AlarmManagerService extends SystemService {
TimeUtils.formatDuration(mInjector.getNextAlarm(ELAPSED_REALTIME_WAKEUP), pw);
pw.println();
- pw.print(" Last wakeup: "); TimeUtils.formatDuration(mLastWakeup, nowELAPSED, pw);
- pw.print(" = "); pw.println(mLastWakeup);
- pw.print(" Last trigger: "); TimeUtils.formatDuration(mLastTrigger, nowELAPSED, pw);
- pw.print(" = "); pw.println(mLastTrigger);
- pw.print(" Num time change events: "); pw.println(mNumTimeChanged);
+ pw.print(" Last wakeup: ");
+ TimeUtils.formatDuration(mLastWakeup, nowELAPSED, pw);
+ pw.print(" = ");
+ pw.println(mLastWakeup);
+ pw.print(" Last trigger: ");
+ TimeUtils.formatDuration(mLastTrigger, nowELAPSED, pw);
+ pw.print(" = ");
+ pw.println(mLastTrigger);
+ pw.print(" Num time change events: ");
+ pw.println(mNumTimeChanged);
pw.println();
pw.println(" Next alarm clock information: ");
@@ -2295,23 +2014,24 @@ public class AlarmManagerService extends SystemService {
final AlarmManager.AlarmClockInfo next = mNextAlarmClockForUser.get(user);
final long time = next != null ? next.getTriggerTime() : 0;
final boolean pendingSend = mPendingSendNextAlarmClockChangedForUser.get(user);
- pw.print(" user:"); pw.print(user);
- pw.print(" pendingSend:"); pw.print(pendingSend);
- pw.print(" time:"); pw.print(time);
+ pw.print(" user:");
+ pw.print(user);
+ pw.print(" pendingSend:");
+ pw.print(pendingSend);
+ pw.print(" time:");
+ pw.print(time);
if (time > 0) {
- pw.print(" = "); pw.print(sdf.format(new Date(time)));
- pw.print(" = "); TimeUtils.formatDuration(time, nowRTC, pw);
+ pw.print(" = ");
+ pw.print(sdf.format(new Date(time)));
+ pw.print(" = ");
+ TimeUtils.formatDuration(time, nowRTC, pw);
}
pw.println();
}
- if (mAlarmBatches.size() > 0) {
+ if (mAlarmStore.size() > 0) {
pw.println();
- pw.print(" Pending alarm batches: ");
- pw.println(mAlarmBatches.size());
- for (Batch b : mAlarmBatches) {
- pw.print(b); pw.println(':');
- dumpAlarmList(pw, b.alarms, " ", nowELAPSED, nowRTC, sdf);
- }
+ final IndentingPrintWriter ipw = new IndentingPrintWriter(pw, " ", " ");
+ mAlarmStore.dump(ipw, nowELAPSED, sdf);
}
pw.println();
pw.println(" Pending user blocked background alarms: ");
@@ -2320,7 +2040,7 @@ public class AlarmManagerService extends SystemService {
final ArrayList<Alarm> blockedAlarms = mPendingBackgroundAlarms.valueAt(i);
if (blockedAlarms != null && blockedAlarms.size() > 0) {
blocked = true;
- dumpAlarmList(pw, blockedAlarms, " ", nowELAPSED, nowRTC, sdf);
+ dumpAlarmList(pw, blockedAlarms, " ", nowELAPSED, sdf);
}
}
if (!blocked) {
@@ -2347,47 +2067,58 @@ public class AlarmManagerService extends SystemService {
pw.print(" Idling until: ");
if (mPendingIdleUntil != null) {
pw.println(mPendingIdleUntil);
- mPendingIdleUntil.dump(pw, " ", nowELAPSED, nowRTC, sdf);
+ mPendingIdleUntil.dump(pw, " ", nowELAPSED, sdf);
} else {
pw.println("null");
}
pw.println(" Pending alarms:");
- dumpAlarmList(pw, mPendingWhileIdleAlarms, " ", nowELAPSED, nowRTC, sdf);
+ dumpAlarmList(pw, mPendingWhileIdleAlarms, " ", nowELAPSED, sdf);
}
if (mNextWakeFromIdle != null) {
pw.println();
- pw.print(" Next wake from idle: "); pw.println(mNextWakeFromIdle);
- mNextWakeFromIdle.dump(pw, " ", nowELAPSED, nowRTC, sdf);
+ pw.print(" Next wake from idle: ");
+ pw.println(mNextWakeFromIdle);
+ mNextWakeFromIdle.dump(pw, " ", nowELAPSED, sdf);
}
pw.println();
pw.print(" Past-due non-wakeup alarms: ");
if (mPendingNonWakeupAlarms.size() > 0) {
pw.println(mPendingNonWakeupAlarms.size());
- dumpAlarmList(pw, mPendingNonWakeupAlarms, " ", nowELAPSED, nowRTC, sdf);
+ dumpAlarmList(pw, mPendingNonWakeupAlarms, " ", nowELAPSED, sdf);
} else {
pw.println("(none)");
}
- pw.print(" Number of delayed alarms: "); pw.print(mNumDelayedAlarms);
- pw.print(", total delay time: "); TimeUtils.formatDuration(mTotalDelayTime, pw);
+ pw.print(" Number of delayed alarms: ");
+ pw.print(mNumDelayedAlarms);
+ pw.print(", total delay time: ");
+ TimeUtils.formatDuration(mTotalDelayTime, pw);
pw.println();
- pw.print(" Max delay time: "); TimeUtils.formatDuration(mMaxDelayTime, pw);
+ pw.print(" Max delay time: ");
+ TimeUtils.formatDuration(mMaxDelayTime, pw);
pw.print(", max non-interactive time: ");
TimeUtils.formatDuration(mNonInteractiveTime, pw);
pw.println();
pw.println();
- pw.print(" Broadcast ref count: "); pw.println(mBroadcastRefCount);
- pw.print(" PendingIntent send count: "); pw.println(mSendCount);
- pw.print(" PendingIntent finish count: "); pw.println(mSendFinishCount);
- pw.print(" Listener send count: "); pw.println(mListenerCount);
- pw.print(" Listener finish count: "); pw.println(mListenerFinishCount);
+ pw.print(" Broadcast ref count: ");
+ pw.println(mBroadcastRefCount);
+ pw.print(" PendingIntent send count: ");
+ pw.println(mSendCount);
+ pw.print(" PendingIntent finish count: ");
+ pw.println(mSendFinishCount);
+ pw.print(" Listener send count: ");
+ pw.println(mListenerCount);
+ pw.print(" Listener finish count: ");
+ pw.println(mListenerFinishCount);
pw.println();
if (mInFlight.size() > 0) {
pw.println("Outstanding deliveries:");
for (int i = 0; i < mInFlight.size(); i++) {
- pw.print(" #"); pw.print(i); pw.print(": ");
+ pw.print(" #");
+ pw.print(i);
+ pw.print(": ");
pw.println(mInFlight.get(i));
}
pw.println();
@@ -2395,7 +2126,7 @@ public class AlarmManagerService extends SystemService {
if (mLastAllowWhileIdleDispatch.size() > 0) {
pw.println(" Last allow while idle dispatch times:");
- for (int i=0; i<mLastAllowWhileIdleDispatch.size(); i++) {
+ for (int i = 0; i < mLastAllowWhileIdleDispatch.size(); i++) {
pw.print(" UID ");
final int uid = mLastAllowWhileIdleDispatch.keyAt(i);
UserHandle.formatUid(pw, uid);
@@ -2442,11 +2173,11 @@ public class AlarmManagerService extends SystemService {
};
int len = 0;
// Get the top 10 FilterStats, ordered by aggregateTime.
- for (int iu=0; iu<mBroadcastStats.size(); iu++) {
+ for (int iu = 0; iu < mBroadcastStats.size(); iu++) {
ArrayMap<String, BroadcastStats> uidStats = mBroadcastStats.valueAt(iu);
- for (int ip=0; ip<uidStats.size(); ip++) {
+ for (int ip = 0; ip < uidStats.size(); ip++) {
BroadcastStats bs = uidStats.valueAt(ip);
- for (int is=0; is<bs.filterStats.size(); is++) {
+ for (int is = 0; is < bs.filterStats.size(); is++) {
FilterStats fs = bs.filterStats.valueAt(is);
int pos = len > 0
? Arrays.binarySearch(topFilters, 0, len, fs, comparator) : 0;
@@ -2456,7 +2187,7 @@ public class AlarmManagerService extends SystemService {
if (pos < topFilters.length) {
int copylen = topFilters.length - pos - 1;
if (copylen > 0) {
- System.arraycopy(topFilters, pos, topFilters, pos+1, copylen);
+ System.arraycopy(topFilters, pos, topFilters, pos + 1, copylen);
}
topFilters[pos] = fs;
if (len < topFilters.length) {
@@ -2468,17 +2199,22 @@ public class AlarmManagerService extends SystemService {
}
if (len > 0) {
pw.println(" Top Alarms:");
- for (int i=0; i<len; i++) {
+ for (int i = 0; i < len; i++) {
FilterStats fs = topFilters[i];
pw.print(" ");
if (fs.nesting > 0) pw.print("*ACTIVE* ");
TimeUtils.formatDuration(fs.aggregateTime, pw);
- pw.print(" running, "); pw.print(fs.numWakeup);
- pw.print(" wakeups, "); pw.print(fs.count);
- pw.print(" alarms: "); UserHandle.formatUid(pw, fs.mBroadcastStats.mUid);
- pw.print(":"); pw.print(fs.mBroadcastStats.mPackageName);
+ pw.print(" running, ");
+ pw.print(fs.numWakeup);
+ pw.print(" wakeups, ");
+ pw.print(fs.count);
+ pw.print(" alarms: ");
+ UserHandle.formatUid(pw, fs.mBroadcastStats.mUid);
+ pw.print(":");
+ pw.print(fs.mBroadcastStats.mPackageName);
pw.println();
- pw.print(" "); pw.print(fs.mTag);
+ pw.print(" ");
+ pw.print(fs.mTag);
pw.println();
}
}
@@ -2486,36 +2222,40 @@ public class AlarmManagerService extends SystemService {
pw.println(" ");
pw.println(" Alarm Stats:");
final ArrayList<FilterStats> tmpFilters = new ArrayList<FilterStats>();
- for (int iu=0; iu<mBroadcastStats.size(); iu++) {
+ for (int iu = 0; iu < mBroadcastStats.size(); iu++) {
ArrayMap<String, BroadcastStats> uidStats = mBroadcastStats.valueAt(iu);
- for (int ip=0; ip<uidStats.size(); ip++) {
+ for (int ip = 0; ip < uidStats.size(); ip++) {
BroadcastStats bs = uidStats.valueAt(ip);
pw.print(" ");
if (bs.nesting > 0) pw.print("*ACTIVE* ");
UserHandle.formatUid(pw, bs.mUid);
pw.print(":");
pw.print(bs.mPackageName);
- pw.print(" "); TimeUtils.formatDuration(bs.aggregateTime, pw);
- pw.print(" running, "); pw.print(bs.numWakeup);
- pw.println(" wakeups:");
+ pw.print(" ");
+ TimeUtils.formatDuration(bs.aggregateTime, pw);
+ pw.print(" running, ");
+ pw.print(bs.numWakeup);
+ pw.println(" wakeups:");
tmpFilters.clear();
- for (int is=0; is<bs.filterStats.size(); is++) {
+ for (int is = 0; is < bs.filterStats.size(); is++) {
tmpFilters.add(bs.filterStats.valueAt(is));
}
Collections.sort(tmpFilters, comparator);
- for (int i=0; i<tmpFilters.size(); i++) {
+ for (int i = 0; i < tmpFilters.size(); i++) {
FilterStats fs = tmpFilters.get(i);
pw.print(" ");
- if (fs.nesting > 0) pw.print("*ACTIVE* ");
- TimeUtils.formatDuration(fs.aggregateTime, pw);
- pw.print(" "); pw.print(fs.numWakeup);
- pw.print(" wakes " ); pw.print(fs.count);
- pw.print(" alarms, last ");
- TimeUtils.formatDuration(fs.lastTime, nowELAPSED, pw);
- pw.println(":");
+ if (fs.nesting > 0) pw.print("*ACTIVE* ");
+ TimeUtils.formatDuration(fs.aggregateTime, pw);
+ pw.print(" ");
+ pw.print(fs.numWakeup);
+ pw.print(" wakes ");
+ pw.print(fs.count);
+ pw.print(" alarms, last ");
+ TimeUtils.formatDuration(fs.lastTime, nowELAPSED, pw);
+ pw.println(":");
pw.print(" ");
- pw.print(fs.mTag);
- pw.println();
+ pw.print(fs.mTag);
+ pw.println();
}
}
}
@@ -2547,26 +2287,6 @@ public class AlarmManagerService extends SystemService {
}
}
}
-
- if (WAKEUP_STATS) {
- pw.println();
- pw.println(" Recent Wakeup History:");
- long last = -1;
- for (WakeupEvent event : mRecentWakeups) {
- pw.print(" "); pw.print(sdf.format(new Date(event.when)));
- pw.print('|');
- if (last < 0) {
- pw.print('0');
- } else {
- pw.print(event.when - last);
- }
- last = event.when;
- pw.print('|'); pw.print(event.uid);
- pw.print('|'); pw.print(event.action);
- pw.println();
- }
- pw.println();
- }
}
}
@@ -2626,42 +2346,41 @@ public class AlarmManagerService extends SystemService {
final AlarmManager.AlarmClockInfo next = mNextAlarmClockForUser.get(user);
final long time = next != null ? next.getTriggerTime() : 0;
final boolean pendingSend = mPendingSendNextAlarmClockChangedForUser.get(user);
- final long aToken = proto.start(AlarmManagerServiceDumpProto.NEXT_ALARM_CLOCK_METADATA);
+ final long aToken = proto.start(
+ AlarmManagerServiceDumpProto.NEXT_ALARM_CLOCK_METADATA);
proto.write(AlarmClockMetadataProto.USER, user);
proto.write(AlarmClockMetadataProto.IS_PENDING_SEND, pendingSend);
proto.write(AlarmClockMetadataProto.TRIGGER_TIME_MS, time);
proto.end(aToken);
}
- for (Batch b : mAlarmBatches) {
- b.dumpDebug(proto, AlarmManagerServiceDumpProto.PENDING_ALARM_BATCHES,
- nowElapsed, nowRTC);
- }
+ mAlarmStore.dumpProto(proto, nowElapsed);
+
for (int i = 0; i < mPendingBackgroundAlarms.size(); i++) {
final ArrayList<Alarm> blockedAlarms = mPendingBackgroundAlarms.valueAt(i);
if (blockedAlarms != null) {
for (Alarm a : blockedAlarms) {
a.dumpDebug(proto,
AlarmManagerServiceDumpProto.PENDING_USER_BLOCKED_BACKGROUND_ALARMS,
- nowElapsed, nowRTC);
+ nowElapsed);
}
}
}
if (mPendingIdleUntil != null) {
mPendingIdleUntil.dumpDebug(
- proto, AlarmManagerServiceDumpProto.PENDING_IDLE_UNTIL, nowElapsed, nowRTC);
+ proto, AlarmManagerServiceDumpProto.PENDING_IDLE_UNTIL, nowElapsed);
}
for (Alarm a : mPendingWhileIdleAlarms) {
a.dumpDebug(proto, AlarmManagerServiceDumpProto.PENDING_WHILE_IDLE_ALARMS,
- nowElapsed, nowRTC);
+ nowElapsed);
}
if (mNextWakeFromIdle != null) {
mNextWakeFromIdle.dumpDebug(proto, AlarmManagerServiceDumpProto.NEXT_WAKE_FROM_IDLE,
- nowElapsed, nowRTC);
+ nowElapsed);
}
for (Alarm a : mPendingNonWakeupAlarms) {
a.dumpDebug(proto, AlarmManagerServiceDumpProto.PAST_DUE_NON_WAKEUP_ALARMS,
- nowElapsed, nowRTC);
+ nowElapsed);
}
proto.write(AlarmManagerServiceDumpProto.DELAYED_ALARM_COUNT, mNumDelayedAlarms);
@@ -2687,7 +2406,8 @@ public class AlarmManagerService extends SystemService {
final long lastTime = mLastAllowWhileIdleDispatch.valueAt(i);
proto.write(AlarmManagerServiceDumpProto.LastAllowWhileIdleDispatch.UID, uid);
- proto.write(AlarmManagerServiceDumpProto.LastAllowWhileIdleDispatch.TIME_MS, lastTime);
+ proto.write(AlarmManagerServiceDumpProto.LastAllowWhileIdleDispatch.TIME_MS,
+ lastTime);
proto.write(AlarmManagerServiceDumpProto.LastAllowWhileIdleDispatch.NEXT_ALLOWED_MS,
lastTime + getWhileIdleMinIntervalLocked(uid));
proto.end(token);
@@ -2730,7 +2450,7 @@ public class AlarmManagerService extends SystemService {
if (pos < topFilters.length) {
int copylen = topFilters.length - pos - 1;
if (copylen > 0) {
- System.arraycopy(topFilters, pos, topFilters, pos+1, copylen);
+ System.arraycopy(topFilters, pos, topFilters, pos + 1, copylen);
}
topFilters[pos] = fs;
if (len < topFilters.length) {
@@ -2792,68 +2512,11 @@ public class AlarmManagerService extends SystemService {
proto.end(token);
}
}
-
- if (WAKEUP_STATS) {
- for (WakeupEvent event : mRecentWakeups) {
- final long token = proto.start(AlarmManagerServiceDumpProto.RECENT_WAKEUP_HISTORY);
- proto.write(WakeupEventProto.UID, event.uid);
- proto.write(WakeupEventProto.ACTION, event.action);
- proto.write(WakeupEventProto.WHEN, event.when);
- proto.end(token);
- }
- }
}
proto.flush();
}
- private void logBatchesLocked(SimpleDateFormat sdf) {
- ByteArrayOutputStream bs = new ByteArrayOutputStream(2048);
- PrintWriter pw = new PrintWriter(bs);
- final long nowRTC = mInjector.getCurrentTimeMillis();
- final long nowELAPSED = mInjector.getElapsedRealtime();
- final int NZ = mAlarmBatches.size();
- for (int iz = 0; iz < NZ; iz++) {
- Batch bz = mAlarmBatches.get(iz);
- pw.append("Batch "); pw.print(iz); pw.append(": "); pw.println(bz);
- dumpAlarmList(pw, bz.alarms, " ", nowELAPSED, nowRTC, sdf);
- pw.flush();
- Slog.v(TAG, bs.toString());
- bs.reset();
- }
- }
-
- private boolean validateConsistencyLocked() {
- if (DEBUG_VALIDATE) {
- long lastTime = Long.MIN_VALUE;
- final int N = mAlarmBatches.size();
- for (int i = 0; i < N; i++) {
- Batch b = mAlarmBatches.get(i);
- if (b.start >= lastTime) {
- // duplicate start times are okay because of standalone batches
- lastTime = b.start;
- } else {
- Slog.e(TAG, "CONSISTENCY FAILURE: Batch " + i + " is out of order");
- SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
- logBatchesLocked(sdf);
- return false;
- }
- }
- }
- return true;
- }
-
- private Batch findFirstWakeupBatchLocked() {
- final int N = mAlarmBatches.size();
- for (int i = 0; i < N; i++) {
- Batch b = mAlarmBatches.get(i);
- if (b.hasWakeups()) {
- return b;
- }
- }
- return null;
- }
-
long getNextWakeFromIdleTimeImpl() {
synchronized (mLock) {
return mNextWakeFromIdle != null ? mNextWakeFromIdle.whenElapsed : Long.MAX_VALUE;
@@ -2881,41 +2544,34 @@ public class AlarmManagerService extends SystemService {
}
mNextAlarmClockMayChange = false;
- SparseArray<AlarmManager.AlarmClockInfo> nextForUser = mTmpSparseAlarmClockArray;
+ final SparseArray<AlarmManager.AlarmClockInfo> nextForUser = mTmpSparseAlarmClockArray;
nextForUser.clear();
- final int N = mAlarmBatches.size();
- for (int i = 0; i < N; i++) {
- ArrayList<Alarm> alarms = mAlarmBatches.get(i).alarms;
- final int M = alarms.size();
-
- for (int j = 0; j < M; j++) {
- Alarm a = alarms.get(j);
- if (a.alarmClock != null) {
- final int userId = UserHandle.getUserId(a.uid);
- AlarmManager.AlarmClockInfo current = mNextAlarmClockForUser.get(userId);
-
- if (DEBUG_ALARM_CLOCK) {
- Log.v(TAG, "Found AlarmClockInfo " + a.alarmClock + " at " +
- formatNextAlarm(getContext(), a.alarmClock, userId) +
- " for user " + userId);
- }
+ final ArrayList<Alarm> allAlarms = mAlarmStore.asList();
+ for (final Alarm a : allAlarms) {
+ if (a.alarmClock != null) {
+ final int userId = UserHandle.getUserId(a.uid);
+ final AlarmManager.AlarmClockInfo current = mNextAlarmClockForUser.get(userId);
- // Alarms and batches are sorted by time, no need to compare times here.
- if (nextForUser.get(userId) == null) {
- nextForUser.put(userId, a.alarmClock);
- } else if (a.alarmClock.equals(current)
- && current.getTriggerTime() <= nextForUser.get(userId).getTriggerTime()) {
- // same/earlier time and it's the one we cited before, so stick with it
- nextForUser.put(userId, current);
- }
+ if (DEBUG_ALARM_CLOCK) {
+ Log.v(TAG, "Found AlarmClockInfo " + a.alarmClock + " at "
+ + formatNextAlarm(getContext(), a.alarmClock, userId)
+ + " for user " + userId);
+ }
+
+ // AlarmClocks are sorted by time, so no need to compare times here.
+ if (nextForUser.get(userId) == null) {
+ nextForUser.put(userId, a.alarmClock);
+ } else if (a.alarmClock.equals(current)
+ && current.getTriggerTime() <= nextForUser.get(userId).getTriggerTime()) {
+ // same/earlier time and it's the one we cited before, so stick with it
+ nextForUser.put(userId, current);
}
}
}
- // Update mNextAlarmForUser with new values.
- final int NN = nextForUser.size();
- for (int i = 0; i < NN; i++) {
+ final int newUserCount = nextForUser.size();
+ for (int i = 0; i < newUserCount; i++) {
AlarmManager.AlarmClockInfo newAlarm = nextForUser.valueAt(i);
int userId = nextForUser.keyAt(i);
AlarmManager.AlarmClockInfo currentAlarm = mNextAlarmClockForUser.get(userId);
@@ -2924,9 +2580,8 @@ public class AlarmManagerService extends SystemService {
}
}
- // Remove users without any alarm clocks scheduled.
- final int NNN = mNextAlarmClockForUser.size();
- for (int i = NNN - 1; i >= 0; i--) {
+ final int oldUserCount = mNextAlarmClockForUser.size();
+ for (int i = oldUserCount - 1; i >= 0; i--) {
int userId = mNextAlarmClockForUser.keyAt(i);
if (nextForUser.get(userId) == null) {
updateNextAlarmInfoForUserLocked(userId, null);
@@ -2967,16 +2622,16 @@ public class AlarmManagerService extends SystemService {
pendingUsers.clear();
synchronized (mLock) {
- final int N = mPendingSendNextAlarmClockChangedForUser.size();
- for (int i = 0; i < N; i++) {
+ final int n = mPendingSendNextAlarmClockChangedForUser.size();
+ for (int i = 0; i < n; i++) {
int userId = mPendingSendNextAlarmClockChangedForUser.keyAt(i);
pendingUsers.append(userId, mNextAlarmClockForUser.get(userId));
}
mPendingSendNextAlarmClockChangedForUser.clear();
}
- final int N = pendingUsers.size();
- for (int i = 0; i < N; i++) {
+ final int n = pendingUsers.size();
+ for (int i = 0; i < n; i++) {
int userId = pendingUsers.keyAt(i);
AlarmManager.AlarmClockInfo alarmClock = pendingUsers.valueAt(i);
Settings.System.putStringForUser(getContext().getContentResolver(),
@@ -3005,16 +2660,16 @@ public class AlarmManagerService extends SystemService {
// prior to that which contains no wakeups, we schedule that as well.
final long nowElapsed = mInjector.getElapsedRealtime();
long nextNonWakeup = 0;
- if (mAlarmBatches.size() > 0) {
- final Batch firstWakeup = findFirstWakeupBatchLocked();
- final Batch firstBatch = mAlarmBatches.get(0);
- if (firstWakeup != null) {
- mNextWakeup = firstWakeup.start;
+ if (mAlarmStore.size() > 0) {
+ final long firstWakeup = mAlarmStore.getNextWakeupDeliveryTime();
+ final long first = mAlarmStore.getNextDeliveryTime();
+ if (firstWakeup != 0) {
+ mNextWakeup = firstWakeup;
mNextWakeUpSetAt = nowElapsed;
- setLocked(ELAPSED_REALTIME_WAKEUP, firstWakeup.start);
+ setLocked(ELAPSED_REALTIME_WAKEUP, firstWakeup);
}
- if (firstBatch != firstWakeup) {
- nextNonWakeup = firstBatch.start;
+ if (first != firstWakeup) {
+ nextNonWakeup = first;
}
}
if (mPendingNonWakeupAlarms.size() > 0) {
@@ -3038,15 +2693,13 @@ public class AlarmManagerService extends SystemService {
return;
}
- boolean didRemove = false;
final Predicate<Alarm> whichAlarms = (Alarm a) -> a.matches(operation, directReceiver);
- for (int i = mAlarmBatches.size() - 1; i >= 0; i--) {
- Batch b = mAlarmBatches.get(i);
- didRemove |= b.remove(whichAlarms, false);
- if (b.size() == 0) {
- mAlarmBatches.remove(i);
- }
+ final ArrayList<Alarm> removedAlarms = mAlarmStore.remove(whichAlarms);
+ for (final Alarm removed : removedAlarms) {
+ decrementAlarmCount(removed.uid, 1);
}
+ final boolean didRemove = !removedAlarms.isEmpty();
+
for (int i = mPendingWhileIdleAlarms.size() - 1; i >= 0; i--) {
final Alarm alarm = mPendingWhileIdleAlarms.get(i);
if (alarm.matches(operation, directReceiver)) {
@@ -3080,11 +2733,18 @@ public class AlarmManagerService extends SystemService {
}
if (mNextWakeFromIdle != null && mNextWakeFromIdle.matches(operation, directReceiver)) {
mNextWakeFromIdle = null;
+ mAlarmStore.recalculateAlarmDeliveries(alarm -> {
+ if (alarm != mPendingIdleUntil) {
+ return false;
+ }
+ restoreAlarmLocked(alarm, mInjector.getElapsedRealtime());
+ return adjustIdleUntilTime(alarm);
+ });
}
- rebatchAllAlarmsLocked(true);
if (restorePending) {
restorePendingWhileIdleAlarmsLocked();
}
+ rescheduleKernelAlarmsLocked();
updateNextAlarmClockLocked();
}
}
@@ -3094,15 +2754,14 @@ public class AlarmManagerService extends SystemService {
// If a force-stop occurs for a system-uid package, ignore it.
return;
}
- boolean didRemove = false;
+
final Predicate<Alarm> whichAlarms = (Alarm a) -> a.uid == uid;
- for (int i = mAlarmBatches.size() - 1; i >= 0; i--) {
- Batch b = mAlarmBatches.get(i);
- didRemove |= b.remove(whichAlarms, false);
- if (b.size() == 0) {
- mAlarmBatches.remove(i);
- }
+ final ArrayList<Alarm> removed = mAlarmStore.remove(whichAlarms);
+ final boolean didRemove = !removed.isEmpty();
+ if (didRemove) {
+ decrementAlarmCount(uid, removed.size());
}
+
for (int i = mPendingWhileIdleAlarms.size() - 1; i >= 0; i--) {
final Alarm a = mPendingWhileIdleAlarms.get(i);
if (a.uid == uid) {
@@ -3111,7 +2770,7 @@ public class AlarmManagerService extends SystemService {
decrementAlarmCount(uid, 1);
}
}
- for (int i = mPendingBackgroundAlarms.size() - 1; i >= 0; i --) {
+ for (int i = mPendingBackgroundAlarms.size() - 1; i >= 0; i--) {
final ArrayList<Alarm> alarmsForUid = mPendingBackgroundAlarms.valueAt(i);
for (int j = alarmsForUid.size() - 1; j >= 0; j--) {
if (alarmsForUid.get(j).uid == uid) {
@@ -3127,17 +2786,24 @@ public class AlarmManagerService extends SystemService {
// make sure to reset to other triggers.
if (mNextWakeFromIdle != null && mNextWakeFromIdle.uid == uid) {
mNextWakeFromIdle = null;
+ mAlarmStore.recalculateAlarmDeliveries(alarm -> {
+ if (alarm != mPendingIdleUntil) {
+ return false;
+ }
+ restoreAlarmLocked(alarm, mInjector.getElapsedRealtime());
+ return adjustIdleUntilTime(alarm);
+ });
}
if (mPendingIdleUntil != null && mPendingIdleUntil.uid == uid) {
// Should never happen - only the system uid is allowed to set idle-until alarms
Slog.wtf(TAG, "Removed app uid " + uid + " set idle-until alarm!");
mPendingIdleUntil = null;
+ restorePendingWhileIdleAlarmsLocked();
}
if (didRemove) {
if (DEBUG_BATCH) {
Slog.v(TAG, "remove(uid) changed bounds; rebatching");
}
- rebatchAllAlarmsLocked(true);
rescheduleKernelAlarmsLocked();
updateNextAlarmClockLocked();
}
@@ -3152,7 +2818,6 @@ public class AlarmManagerService extends SystemService {
return;
}
- boolean didRemove = false;
final MutableBoolean removedNextWakeFromIdle = new MutableBoolean(false);
final Predicate<Alarm> whichAlarms = (Alarm a) -> {
final boolean didMatch = a.matches(packageName);
@@ -3161,17 +2826,11 @@ public class AlarmManagerService extends SystemService {
}
return didMatch;
};
- final boolean oldHasTick = haveBatchesTimeTickAlarm(mAlarmBatches);
- for (int i = mAlarmBatches.size() - 1; i >= 0; i--) {
- Batch b = mAlarmBatches.get(i);
- didRemove |= b.remove(whichAlarms, false);
- if (b.size() == 0) {
- mAlarmBatches.remove(i);
- }
- }
- final boolean newHasTick = haveBatchesTimeTickAlarm(mAlarmBatches);
- if (oldHasTick != newHasTick) {
- Slog.wtf(TAG, "removeLocked: hasTick changed from " + oldHasTick + " to " + newHasTick);
+
+ final ArrayList<Alarm> removed = mAlarmStore.remove(whichAlarms);
+ final boolean didRemove = !removed.isEmpty();
+ if (didRemove) {
+ decrementAlarmCount(removed.get(0).uid, removed.size());
}
for (int i = mPendingWhileIdleAlarms.size() - 1; i >= 0; i--) {
@@ -3182,7 +2841,7 @@ public class AlarmManagerService extends SystemService {
decrementAlarmCount(a.uid, 1);
}
}
- for (int i = mPendingBackgroundAlarms.size() - 1; i >= 0; i --) {
+ for (int i = mPendingBackgroundAlarms.size() - 1; i >= 0; i--) {
final ArrayList<Alarm> alarmsForUid = mPendingBackgroundAlarms.valueAt(i);
for (int j = alarmsForUid.size() - 1; j >= 0; j--) {
final Alarm alarm = alarmsForUid.get(j);
@@ -3199,12 +2858,18 @@ public class AlarmManagerService extends SystemService {
// make sure to reset to other triggers.
if (removedNextWakeFromIdle.value) {
mNextWakeFromIdle = null;
+ mAlarmStore.recalculateAlarmDeliveries(alarm -> {
+ if (alarm != mPendingIdleUntil) {
+ return false;
+ }
+ restoreAlarmLocked(alarm, mInjector.getElapsedRealtime());
+ return adjustIdleUntilTime(alarm);
+ });
}
if (didRemove) {
if (DEBUG_BATCH) {
Slog.v(TAG, "remove(package) changed bounds; rebatching");
}
- rebatchAllAlarmsLocked(true);
rescheduleKernelAlarmsLocked();
updateNextAlarmClockLocked();
}
@@ -3216,16 +2881,14 @@ public class AlarmManagerService extends SystemService {
// If a force-stop occurs for a system-uid package, ignore it.
return;
}
- boolean didRemove = false;
final Predicate<Alarm> whichAlarms = (a) -> (a.uid == uid
&& mActivityManagerInternal.isAppStartModeDisabled(uid, a.packageName));
- for (int i = mAlarmBatches.size() - 1; i >= 0; i--) {
- Batch b = mAlarmBatches.get(i);
- didRemove |= b.remove(whichAlarms, false);
- if (b.size() == 0) {
- mAlarmBatches.remove(i);
- }
+ final ArrayList<Alarm> removed = mAlarmStore.remove(whichAlarms);
+ final boolean didRemove = !removed.isEmpty();
+ if (didRemove) {
+ decrementAlarmCount(uid, removed.size());
}
+
for (int i = mPendingWhileIdleAlarms.size() - 1; i >= 0; i--) {
final Alarm a = mPendingWhileIdleAlarms.get(i);
if (a.uid == uid) {
@@ -3247,7 +2910,6 @@ public class AlarmManagerService extends SystemService {
if (DEBUG_BATCH) {
Slog.v(TAG, "remove(package) changed bounds; rebatching");
}
- rebatchAllAlarmsLocked(true);
rescheduleKernelAlarmsLocked();
updateNextAlarmClockLocked();
}
@@ -3258,16 +2920,14 @@ public class AlarmManagerService extends SystemService {
// If we're told we're removing the system user, ignore it.
return;
}
- boolean didRemove = false;
final Predicate<Alarm> whichAlarms =
(Alarm a) -> UserHandle.getUserId(a.creatorUid) == userHandle;
- for (int i = mAlarmBatches.size() - 1; i >= 0; i--) {
- Batch b = mAlarmBatches.get(i);
- didRemove |= b.remove(whichAlarms, false);
- if (b.size() == 0) {
- mAlarmBatches.remove(i);
- }
+ final ArrayList<Alarm> removedAlarms = mAlarmStore.remove(whichAlarms);
+ for (final Alarm removed : removedAlarms) {
+ decrementAlarmCount(removed.uid, 1);
}
+ final boolean didRemove = !removedAlarms.isEmpty();
+
for (int i = mPendingWhileIdleAlarms.size() - 1; i >= 0; i--) {
if (UserHandle.getUserId(mPendingWhileIdleAlarms.get(i).creatorUid)
== userHandle) {
@@ -3297,7 +2957,6 @@ public class AlarmManagerService extends SystemService {
if (DEBUG_BATCH) {
Slog.v(TAG, "remove(user) changed bounds; rebatching");
}
- rebatchAllAlarmsLocked(true);
rescheduleKernelAlarmsLocked();
updateNextAlarmClockLocked();
}
@@ -3333,9 +2992,9 @@ public class AlarmManagerService extends SystemService {
}
boolean lookForPackageLocked(String packageName) {
- for (int i = 0; i < mAlarmBatches.size(); i++) {
- Batch b = mAlarmBatches.get(i);
- if (b.hasPackage(packageName)) {
+ final ArrayList<Alarm> allAlarms = mAlarmStore.asList();
+ for (final Alarm alarm : allAlarms) {
+ if (alarm.matches(packageName)) {
return true;
}
}
@@ -3360,34 +3019,39 @@ public class AlarmManagerService extends SystemService {
}
}
- private static final void dumpAlarmList(PrintWriter pw, ArrayList<Alarm> list,
- String prefix, String label, long nowELAPSED, long nowRTC, SimpleDateFormat sdf) {
- for (int i=list.size()-1; i>=0; i--) {
- Alarm a = list.get(i);
- pw.print(prefix); pw.print(label); pw.print(" #"); pw.print(i);
- pw.print(": "); pw.println(a);
- a.dump(pw, prefix + " ", nowELAPSED, nowRTC, sdf);
- }
- }
-
private static final String labelForType(int type) {
switch (type) {
- case RTC: return "RTC";
- case RTC_WAKEUP : return "RTC_WAKEUP";
- case ELAPSED_REALTIME : return "ELAPSED";
- case ELAPSED_REALTIME_WAKEUP: return "ELAPSED_WAKEUP";
+ case RTC:
+ return "RTC";
+ case RTC_WAKEUP:
+ return "RTC_WAKEUP";
+ case ELAPSED_REALTIME:
+ return "ELAPSED";
+ case ELAPSED_REALTIME_WAKEUP:
+ return "ELAPSED_WAKEUP";
}
return "--unknown--";
}
private static final void dumpAlarmList(PrintWriter pw, ArrayList<Alarm> list,
- String prefix, long nowELAPSED, long nowRTC, SimpleDateFormat sdf) {
- for (int i=list.size()-1; i>=0; i--) {
- Alarm a = list.get(i);
+ String prefix, long nowELAPSED, SimpleDateFormat sdf) {
+ final IndentingPrintWriter ipw = new IndentingPrintWriter(pw, prefix, prefix);
+ dumpAlarmList(ipw, list, nowELAPSED, sdf);
+ }
+
+ static final void dumpAlarmList(IndentingPrintWriter ipw, ArrayList<Alarm> list,
+ long nowELAPSED, SimpleDateFormat sdf) {
+ for (int i = list.size() - 1; i >= 0; i--) {
+ final Alarm a = list.get(i);
final String label = labelForType(a.type);
- pw.print(prefix); pw.print(label); pw.print(" #"); pw.print(i);
- pw.print(": "); pw.println(a);
- a.dump(pw, prefix + " ", nowELAPSED, nowRTC, sdf);
+ ipw.print(label);
+ ipw.print(" #");
+ ipw.print(i);
+ ipw.print(": ");
+ ipw.println(a);
+ ipw.increaseIndent();
+ a.dump(ipw, nowELAPSED, sdf);
+ ipw.decreaseIndent();
}
}
@@ -3442,105 +3106,93 @@ public class AlarmManagerService extends SystemService {
boolean triggerAlarmsLocked(ArrayList<Alarm> triggerList, final long nowELAPSED) {
boolean hasWakeup = false;
- // batches are temporally sorted, so we need only pull from the
- // start of the list until we either empty it or hit a batch
- // that is not yet deliverable
- while (mAlarmBatches.size() > 0) {
- Batch batch = mAlarmBatches.get(0);
- if (batch.start > nowELAPSED) {
- // Everything else is scheduled for the future
- break;
- }
-
- // We will (re)schedule some alarms now; don't let that interfere
- // with delivery of this current batch
- mAlarmBatches.remove(0);
-
- final int N = batch.size();
- for (int i = 0; i < N; i++) {
- Alarm alarm = batch.get(i);
-
- if ((alarm.flags&AlarmManager.FLAG_ALLOW_WHILE_IDLE) != 0) {
- // If this is an ALLOW_WHILE_IDLE alarm, we constrain how frequently the app can
- // schedule such alarms. The first such alarm from an app is always delivered.
- final long lastTime = mLastAllowWhileIdleDispatch.get(alarm.creatorUid, -1);
- final long minTime = lastTime + getWhileIdleMinIntervalLocked(alarm.creatorUid);
- if (lastTime >= 0 && nowELAPSED < minTime) {
- // Whoops, it hasn't been long enough since the last ALLOW_WHILE_IDLE
- // alarm went off for this app. Reschedule the alarm to be in the
- // correct time period.
- alarm.expectedWhenElapsed = alarm.whenElapsed = minTime;
- if (alarm.maxWhenElapsed < minTime) {
- alarm.maxWhenElapsed = minTime;
- }
- alarm.expectedMaxWhenElapsed = alarm.maxWhenElapsed;
- if (RECORD_DEVICE_IDLE_ALARMS) {
- IdleDispatchEntry ent = new IdleDispatchEntry();
- ent.uid = alarm.uid;
- ent.pkg = alarm.operation.getCreatorPackage();
- ent.tag = alarm.operation.getTag("");
- ent.op = "RESCHEDULE";
- ent.elapsedRealtime = nowELAPSED;
- ent.argRealtime = lastTime;
- mAllowWhileIdleDispatches.add(ent);
- }
- setImplLocked(alarm, true, false);
- continue;
+ final ArrayList<Alarm> pendingAlarms = mAlarmStore.removePendingAlarms(nowELAPSED);
+ for (final Alarm alarm : pendingAlarms) {
+ if ((alarm.flags & AlarmManager.FLAG_ALLOW_WHILE_IDLE) != 0) {
+ // If this is an ALLOW_WHILE_IDLE alarm, we constrain how frequently the app can
+ // schedule such alarms. The first such alarm from an app is always delivered.
+ final long lastTime = mLastAllowWhileIdleDispatch.get(alarm.creatorUid, -1);
+ final long minTime = lastTime + getWhileIdleMinIntervalLocked(alarm.creatorUid);
+ if (lastTime >= 0 && nowELAPSED < minTime) {
+ // Whoops, it hasn't been long enough since the last ALLOW_WHILE_IDLE
+ // alarm went off for this app. Reschedule the alarm to be in the
+ // correct time period.
+ alarm.expectedWhenElapsed = alarm.whenElapsed = minTime;
+ if (alarm.maxWhenElapsed < minTime) {
+ alarm.maxWhenElapsed = minTime;
}
- }
- if (isBackgroundRestricted(alarm)) {
- // Alarms with FLAG_WAKE_FROM_IDLE or mPendingIdleUntil alarm are not deferred
- if (DEBUG_BG_LIMIT) {
- Slog.d(TAG, "Deferring alarm " + alarm + " due to user forced app standby");
+ alarm.expectedMaxWhenElapsed = alarm.maxWhenElapsed;
+ if (RECORD_DEVICE_IDLE_ALARMS) {
+ IdleDispatchEntry ent = new IdleDispatchEntry();
+ ent.uid = alarm.uid;
+ ent.pkg = alarm.operation.getCreatorPackage();
+ ent.tag = alarm.operation.getTag("");
+ ent.op = "RESCHEDULE";
+ ent.elapsedRealtime = nowELAPSED;
+ ent.argRealtime = lastTime;
+ mAllowWhileIdleDispatches.add(ent);
}
- ArrayList<Alarm> alarmsForUid = mPendingBackgroundAlarms.get(alarm.creatorUid);
- if (alarmsForUid == null) {
- alarmsForUid = new ArrayList<>();
- mPendingBackgroundAlarms.put(alarm.creatorUid, alarmsForUid);
- }
- alarmsForUid.add(alarm);
+ setImplLocked(alarm);
continue;
}
-
- alarm.count = 1;
- triggerList.add(alarm);
- if ((alarm.flags&AlarmManager.FLAG_WAKE_FROM_IDLE) != 0) {
- EventLogTags.writeDeviceIdleWakeFromIdle(mPendingIdleUntil != null ? 1 : 0,
- alarm.statsTag);
- }
- if (mPendingIdleUntil == alarm) {
- mPendingIdleUntil = null;
- rebatchAllAlarmsLocked(false);
- restorePendingWhileIdleAlarmsLocked();
+ }
+ if (isBackgroundRestricted(alarm)) {
+ // Alarms with FLAG_WAKE_FROM_IDLE or mPendingIdleUntil alarm are not deferred
+ if (DEBUG_BG_LIMIT) {
+ Slog.d(TAG, "Deferring alarm " + alarm + " due to user forced app standby");
}
- if (mNextWakeFromIdle == alarm) {
- mNextWakeFromIdle = null;
- rebatchAllAlarmsLocked(false);
+ ArrayList<Alarm> alarmsForUid = mPendingBackgroundAlarms.get(alarm.creatorUid);
+ if (alarmsForUid == null) {
+ alarmsForUid = new ArrayList<>();
+ mPendingBackgroundAlarms.put(alarm.creatorUid, alarmsForUid);
}
+ alarmsForUid.add(alarm);
+ continue;
+ }
- // Recurring alarms may have passed several alarm intervals while the
- // phone was asleep or off, so pass a trigger count when sending them.
- if (alarm.repeatInterval > 0) {
- // this adjustment will be zero if we're late by
- // less than one full repeat interval
- alarm.count += (nowELAPSED - alarm.expectedWhenElapsed) / alarm.repeatInterval;
- // Also schedule its next recurrence
- final long delta = alarm.count * alarm.repeatInterval;
- final long nextElapsed = alarm.expectedWhenElapsed + delta;
- setImplLocked(alarm.type, alarm.when + delta, nextElapsed, alarm.windowLength,
- maxTriggerTime(nowELAPSED, nextElapsed, alarm.repeatInterval),
- alarm.repeatInterval, alarm.operation, null, null, alarm.flags, true,
- alarm.workSource, alarm.alarmClock, alarm.uid, alarm.packageName);
- }
+ alarm.count = 1;
+ triggerList.add(alarm);
+ if ((alarm.flags & AlarmManager.FLAG_WAKE_FROM_IDLE) != 0) {
+ EventLogTags.writeDeviceIdleWakeFromIdle(mPendingIdleUntil != null ? 1 : 0,
+ alarm.statsTag);
+ }
+ if (mPendingIdleUntil == alarm) {
+ mPendingIdleUntil = null;
+ restorePendingWhileIdleAlarmsLocked();
+ }
+ if (mNextWakeFromIdle == alarm) {
+ mNextWakeFromIdle = null;
+ mAlarmStore.recalculateAlarmDeliveries(a -> {
+ if (a != mPendingIdleUntil) {
+ return false;
+ }
+ restoreAlarmLocked(a, nowELAPSED);
+ return adjustIdleUntilTime(a);
+ });
+ }
- if (alarm.wakeup) {
- hasWakeup = true;
- }
+ // Recurring alarms may have passed several alarm intervals while the
+ // phone was asleep or off, so pass a trigger count when sending them.
+ if (alarm.repeatInterval > 0) {
+ // this adjustment will be zero if we're late by
+ // less than one full repeat interval
+ alarm.count += (nowELAPSED - alarm.expectedWhenElapsed) / alarm.repeatInterval;
+ // Also schedule its next recurrence
+ final long delta = alarm.count * alarm.repeatInterval;
+ final long nextElapsed = alarm.expectedWhenElapsed + delta;
+ setImplLocked(alarm.type, alarm.when + delta, nextElapsed, alarm.windowLength,
+ maxTriggerTime(nowELAPSED, nextElapsed, alarm.repeatInterval),
+ alarm.repeatInterval, alarm.operation, null, null, alarm.flags,
+ alarm.workSource, alarm.alarmClock, alarm.uid, alarm.packageName);
+ }
- // We removed an alarm clock. Let the caller recompute the next alarm clock.
- if (alarm.alarmClock != null) {
- mNextAlarmClockMayChange = true;
- }
+ if (alarm.wakeup) {
+ hasWakeup = true;
+ }
+
+ // We removed an alarm clock. Let the caller recompute the next alarm clock.
+ if (alarm.alarmClock != null) {
+ mNextAlarmClockMayChange = true;
}
}
@@ -3551,7 +3203,7 @@ public class AlarmManagerService extends SystemService {
Collections.sort(triggerList, mAlarmDispatchComparator);
if (localLOGV) {
- for (int i=0; i<triggerList.size(); i++) {
+ for (int i = 0; i < triggerList.size(); i++) {
Slog.v(TAG, "Triggering alarm #" + i + ": " + triggerList.get(i));
}
}
@@ -3559,218 +3211,31 @@ public class AlarmManagerService extends SystemService {
return hasWakeup;
}
- /**
- * This Comparator sorts Alarms into increasing time order.
- */
- public static class IncreasingTimeOrder implements Comparator<Alarm> {
- public int compare(Alarm a1, Alarm a2) {
- long when1 = a1.whenElapsed;
- long when2 = a2.whenElapsed;
- if (when1 > when2) {
- return 1;
- }
- if (when1 < when2) {
- return -1;
- }
- return 0;
- }
- }
-
- @VisibleForTesting
- static class Alarm {
- public final int type;
- public final long origWhen;
- public final boolean wakeup;
- public final PendingIntent operation;
- public final IAlarmListener listener;
- public final String listenerTag;
- public final String statsTag;
- public final WorkSource workSource;
- public final int flags;
- public final AlarmManager.AlarmClockInfo alarmClock;
- public final int uid;
- public final int creatorUid;
- public final String packageName;
- public final String sourcePackage;
- public int count;
- public long when;
- public long windowLength;
- public long whenElapsed; // 'when' in the elapsed time base
- public long maxWhenElapsed; // also in the elapsed time base
- // Expected alarm expiry time before app standby deferring is applied.
- public long expectedWhenElapsed;
- public long expectedMaxWhenElapsed;
- public long repeatInterval;
- public PriorityClass priorityClass;
-
- public Alarm(int _type, long _when, long _whenElapsed, long _windowLength, long _maxWhen,
- long _interval, PendingIntent _op, IAlarmListener _rec, String _listenerTag,
- WorkSource _ws, int _flags, AlarmManager.AlarmClockInfo _info,
- int _uid, String _pkgName) {
- type = _type;
- origWhen = _when;
- wakeup = _type == AlarmManager.ELAPSED_REALTIME_WAKEUP
- || _type == AlarmManager.RTC_WAKEUP;
- when = _when;
- whenElapsed = _whenElapsed;
- expectedWhenElapsed = _whenElapsed;
- windowLength = _windowLength;
- maxWhenElapsed = expectedMaxWhenElapsed = clampPositive(_maxWhen);
- repeatInterval = _interval;
- operation = _op;
- listener = _rec;
- listenerTag = _listenerTag;
- statsTag = makeTag(_op, _listenerTag, _type);
- workSource = _ws;
- flags = _flags;
- alarmClock = _info;
- uid = _uid;
- packageName = _pkgName;
- sourcePackage = (operation != null) ? operation.getCreatorPackage() : packageName;
- creatorUid = (operation != null) ? operation.getCreatorUid() : uid;
- }
-
- public static String makeTag(PendingIntent pi, String tag, int type) {
- final String alarmString = type == ELAPSED_REALTIME_WAKEUP || type == RTC_WAKEUP
- ? "*walarm*:" : "*alarm*:";
- return (pi != null) ? pi.getTag(alarmString) : (alarmString + tag);
- }
-
- public WakeupEvent makeWakeupEvent(long nowRTC) {
- return new WakeupEvent(nowRTC, creatorUid,
- (operation != null)
- ? operation.getIntent().getAction()
- : ("<listener>:" + listenerTag));
- }
-
- // Returns true if either matches
- public boolean matches(PendingIntent pi, IAlarmListener rec) {
- return (operation != null)
- ? operation.equals(pi)
- : rec != null && listener.asBinder().equals(rec.asBinder());
- }
-
- public boolean matches(String packageName) {
- return packageName.equals(sourcePackage);
- }
-
- @Override
- public String toString() {
- StringBuilder sb = new StringBuilder(128);
- sb.append("Alarm{");
- sb.append(Integer.toHexString(System.identityHashCode(this)));
- sb.append(" type ");
- sb.append(type);
- sb.append(" when ");
- sb.append(when);
- sb.append(" ");
- sb.append(sourcePackage);
- sb.append('}');
- return sb.toString();
- }
-
- public void dump(PrintWriter pw, String prefix, long nowELAPSED, long nowRTC,
- SimpleDateFormat sdf) {
- final boolean isRtc = (type == RTC || type == RTC_WAKEUP);
- pw.print(prefix); pw.print("tag="); pw.println(statsTag);
- pw.print(prefix); pw.print("type="); pw.print(type);
- pw.print(" expectedWhenElapsed="); TimeUtils.formatDuration(
- expectedWhenElapsed, nowELAPSED, pw);
- pw.print(" expectedMaxWhenElapsed="); TimeUtils.formatDuration(
- expectedMaxWhenElapsed, nowELAPSED, pw);
- pw.print(" whenElapsed="); TimeUtils.formatDuration(whenElapsed,
- nowELAPSED, pw);
- pw.print(" maxWhenElapsed="); TimeUtils.formatDuration(maxWhenElapsed,
- nowELAPSED, pw);
- pw.print(" when=");
- if (isRtc) {
- pw.print(sdf.format(new Date(when)));
- } else {
- TimeUtils.formatDuration(when, nowELAPSED, pw);
- }
- pw.println();
- pw.print(prefix); pw.print("window="); TimeUtils.formatDuration(windowLength, pw);
- pw.print(" repeatInterval="); pw.print(repeatInterval);
- pw.print(" count="); pw.print(count);
- pw.print(" flags=0x"); pw.println(Integer.toHexString(flags));
- if (alarmClock != null) {
- pw.print(prefix); pw.println("Alarm clock:");
- pw.print(prefix); pw.print(" triggerTime=");
- pw.println(sdf.format(new Date(alarmClock.getTriggerTime())));
- pw.print(prefix); pw.print(" showIntent="); pw.println(alarmClock.getShowIntent());
- }
- pw.print(prefix); pw.print("operation="); pw.println(operation);
- if (listener != null) {
- pw.print(prefix); pw.print("listener="); pw.println(listener.asBinder());
- }
- }
-
- public void dumpDebug(ProtoOutputStream proto, long fieldId, long nowElapsed,
- long nowRTC) {
- final long token = proto.start(fieldId);
-
- proto.write(AlarmProto.TAG, statsTag);
- proto.write(AlarmProto.TYPE, type);
- proto.write(AlarmProto.TIME_UNTIL_WHEN_ELAPSED_MS, whenElapsed - nowElapsed);
- proto.write(AlarmProto.WINDOW_LENGTH_MS, windowLength);
- proto.write(AlarmProto.REPEAT_INTERVAL_MS, repeatInterval);
- proto.write(AlarmProto.COUNT, count);
- proto.write(AlarmProto.FLAGS, flags);
- if (alarmClock != null) {
- alarmClock.dumpDebug(proto, AlarmProto.ALARM_CLOCK);
- }
- if (operation != null) {
- operation.dumpDebug(proto, AlarmProto.OPERATION);
- }
- if (listener != null) {
- proto.write(AlarmProto.LISTENER, listener.asBinder().toString());
- }
-
- proto.end(token);
- }
- }
-
- void recordWakeupAlarms(ArrayList<Batch> batches, long nowELAPSED, long nowRTC) {
- final int numBatches = batches.size();
- for (int nextBatch = 0; nextBatch < numBatches; nextBatch++) {
- Batch b = batches.get(nextBatch);
- if (b.start > nowELAPSED) {
- break;
- }
-
- final int numAlarms = b.alarms.size();
- for (int nextAlarm = 0; nextAlarm < numAlarms; nextAlarm++) {
- Alarm a = b.alarms.get(nextAlarm);
- mRecentWakeups.add(a.makeWakeupEvent(nowRTC));
- }
- }
- }
-
long currentNonWakeupFuzzLocked(long nowELAPSED) {
long timeSinceOn = nowELAPSED - mNonInteractiveStartTime;
- if (timeSinceOn < 5*60*1000) {
+ if (timeSinceOn < 5 * 60 * 1000) {
// If the screen has been off for 5 minutes, only delay by at most two minutes.
- return 2*60*1000;
- } else if (timeSinceOn < 30*60*1000) {
+ return 2 * 60 * 1000;
+ } else if (timeSinceOn < 30 * 60 * 1000) {
// If the screen has been off for 30 minutes, only delay by at most 15 minutes.
- return 15*60*1000;
+ return 15 * 60 * 1000;
} else {
// Otherwise, we will delay by at most an hour.
- return 60*60*1000;
+ return 60 * 60 * 1000;
}
}
static int fuzzForDuration(long duration) {
- if (duration < 15*60*1000) {
+ if (duration < 15 * 60 * 1000) {
// If the duration until the time is less than 15 minutes, the maximum fuzz
// is the duration.
- return (int)duration;
- } else if (duration < 90*60*1000) {
+ return (int) duration;
+ } else if (duration < 90 * 60 * 1000) {
// If duration is less than 1 1/2 hours, the maximum fuzz is 15 minutes,
- return 15*60*1000;
+ return 15 * 60 * 1000;
} else {
// Otherwise, we will fuzz by at most half an hour.
- return 30*60*1000;
+ return 30 * 60 * 1000;
}
}
@@ -3793,13 +3258,15 @@ public class AlarmManagerService extends SystemService {
void deliverAlarmsLocked(ArrayList<Alarm> triggerList, long nowELAPSED) {
mLastAlarmDeliveryTime = nowELAPSED;
- for (int i=0; i<triggerList.size(); i++) {
+ for (int i = 0; i < triggerList.size(); i++) {
Alarm alarm = triggerList.get(i);
- final boolean allowWhileIdle = (alarm.flags&AlarmManager.FLAG_ALLOW_WHILE_IDLE) != 0;
+ final boolean allowWhileIdle = (alarm.flags & AlarmManager.FLAG_ALLOW_WHILE_IDLE) != 0;
if (alarm.wakeup) {
- Trace.traceBegin(Trace.TRACE_TAG_POWER, "Dispatch wakeup alarm to " + alarm.packageName);
+ Trace.traceBegin(Trace.TRACE_TAG_POWER,
+ "Dispatch wakeup alarm to " + alarm.packageName);
} else {
- Trace.traceBegin(Trace.TRACE_TAG_POWER, "Dispatch non-wakeup alarm to " + alarm.packageName);
+ Trace.traceBegin(Trace.TRACE_TAG_POWER,
+ "Dispatch non-wakeup alarm to " + alarm.packageName);
}
try {
if (localLOGV) {
@@ -3909,23 +3376,20 @@ public class AlarmManagerService extends SystemService {
}
}
- private class AlarmThread extends Thread
- {
+ private class AlarmThread extends Thread {
private int mFalseWakeups;
private int mWtfThreshold;
- public AlarmThread()
- {
+
+ AlarmThread() {
super("AlarmManager");
mFalseWakeups = 0;
mWtfThreshold = 100;
}
- public void run()
- {
+ public void run() {
ArrayList<Alarm> triggerList = new ArrayList<Alarm>();
- while (true)
- {
+ while (true) {
int result = mInjector.waitForAlarm();
final long nowRTC = mInjector.getCurrentTimeMillis();
final long nowELAPSED = mInjector.getElapsedRealtime();
@@ -3948,8 +3412,8 @@ public class AlarmManagerService extends SystemService {
expectedClockTime = lastTimeChangeClockTime
+ (nowELAPSED - mLastTimeChangeRealtime);
}
- if (lastTimeChangeClockTime == 0 || nowRTC < (expectedClockTime-1000)
- || nowRTC > (expectedClockTime+1000)) {
+ if (lastTimeChangeClockTime == 0 || nowRTC < (expectedClockTime - 1000)
+ || nowRTC > (expectedClockTime + 1000)) {
// The change is by at least +/- 1000 ms (or this is the first change),
// let's do it!
if (DEBUG_BATCH) {
@@ -3959,7 +3423,7 @@ public class AlarmManagerService extends SystemService {
FrameworkStatsLog.write(FrameworkStatsLog.WALL_CLOCK_TIME_SHIFTED, nowRTC);
removeImpl(null, mTimeTickTrigger);
removeImpl(mDateChangeSender, null);
- rebatchAllAlarms();
+ reevaluateRtcAlarms(nowELAPSED);
mClockReceiver.scheduleTimeTickEvent();
mClockReceiver.scheduleDateChangedEvent();
synchronized (mLock) {
@@ -3984,24 +3448,9 @@ public class AlarmManagerService extends SystemService {
// If this was anything besides just a time change, then figure what if
// anything to do about alarms.
synchronized (mLock) {
- if (localLOGV) Slog.v(
- TAG, "Checking for alarms... rtc=" + nowRTC
- + ", elapsed=" + nowELAPSED);
-
- if (WAKEUP_STATS) {
- if ((result & IS_WAKEUP_MASK) != 0) {
- long newEarliest = nowRTC - RECENT_WAKEUP_PERIOD;
- int n = 0;
- for (WakeupEvent event : mRecentWakeups) {
- if (event.when > newEarliest) break;
- n++; // number of now-stale entries at the list head
- }
- for (int i = 0; i < n; i++) {
- mRecentWakeups.remove();
- }
-
- recordWakeupAlarms(mAlarmBatches, nowELAPSED, nowRTC);
- }
+ if (localLOGV) {
+ Slog.v(TAG, "Checking for alarms... rtc=" + nowRTC
+ + ", elapsed=" + nowELAPSED);
}
mLastTrigger = nowELAPSED;
@@ -4012,7 +3461,7 @@ public class AlarmManagerService extends SystemService {
if (mPendingNonWakeupAlarms.size() == 0) {
mStartCurrentDelayTime = nowELAPSED;
mNextNonWakeupDeliveryTime = nowELAPSED
- + ((currentNonWakeupFuzzLocked(nowELAPSED)*3)/2);
+ + ((currentNonWakeupFuzzLocked(nowELAPSED) * 3) / 2);
}
mPendingNonWakeupAlarms.addAll(triggerList);
mNumDelayedAlarms += triggerList.size();
@@ -4074,7 +3523,8 @@ public class AlarmManagerService extends SystemService {
/**
* Attribute blame for a WakeLock.
- * @param ws WorkSource to attribute blame.
+ *
+ * @param ws WorkSource to attribute blame.
* @param knownUid attribution uid; < 0 values are ignored.
*/
void setWakelockWorkSource(WorkSource ws, int knownUid, String tag, boolean first) {
@@ -4135,7 +3585,7 @@ public class AlarmManagerService extends SystemService {
}
// now trigger the alarms without the lock held
- for (int i=0; i<triggerList.size(); i++) {
+ for (int i = 0; i < triggerList.size(); i++) {
Alarm alarm = triggerList.get(i);
try {
alarm.operation.send();
@@ -4262,7 +3712,7 @@ public class AlarmManagerService extends SystemService {
final WorkSource workSource = null; // Let system take blame for time tick events.
setImpl(ELAPSED_REALTIME, mInjector.getElapsedRealtime() + tickEventDelay, 0,
- 0, null, mTimeTickTrigger, "TIME_TICK", AlarmManager.FLAG_STANDALONE,
+ 0, null, mTimeTickTrigger, TIME_TICK_TAG, AlarmManager.FLAG_STANDALONE,
workSource, null, Process.myUid(), "android");
// Finally, remember when we set the tick alarm
@@ -4312,7 +3762,7 @@ public class AlarmManagerService extends SystemService {
filter.addAction(Intent.ACTION_QUERY_PACKAGE_RESTART);
filter.addDataScheme(IntentFilter.SCHEME_PACKAGE);
getContext().registerReceiver(this, filter);
- // Register for events related to sdcard installation.
+ // Register for events related to sdcard installation.
IntentFilter sdFilter = new IntentFilter();
sdFilter.addAction(Intent.ACTION_EXTERNAL_APPLICATIONS_UNAVAILABLE);
sdFilter.addAction(Intent.ACTION_USER_STOPPED);
@@ -4378,7 +3828,7 @@ public class AlarmManagerService extends SystemService {
removeLocked(pkg);
}
mPriorities.remove(pkg);
- for (int i=mBroadcastStats.size()-1; i>=0; i--) {
+ for (int i = mBroadcastStats.size() - 1; i >= 0; i--) {
ArrayMap<String, BroadcastStats> uidStats = mBroadcastStats.valueAt(i);
if (uidStats.remove(pkg) != null) {
if (uidStats.size() <= 0) {
@@ -4545,7 +3995,7 @@ public class AlarmManagerService extends SystemService {
if (mInFlight.size() > 0) {
mLog.w("Finished all dispatches with " + mInFlight.size()
+ " remaining inflights");
- for (int i=0; i<mInFlight.size(); i++) {
+ for (int i = 0; i < mInFlight.size(); i++) {
mLog.w(" Remaining #" + i + ": " + mInFlight.get(i));
}
mInFlight.clear();
diff --git a/apex/jobscheduler/service/java/com/android/server/alarm/AlarmStore.java b/apex/jobscheduler/service/java/com/android/server/alarm/AlarmStore.java
new file mode 100644
index 000000000000..9fdbb8bbffc7
--- /dev/null
+++ b/apex/jobscheduler/service/java/com/android/server/alarm/AlarmStore.java
@@ -0,0 +1,127 @@
+/*
+ * 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.alarm;
+
+import android.os.SystemClock;
+import android.util.IndentingPrintWriter;
+import android.util.proto.ProtoOutputStream;
+
+import java.io.FileDescriptor;
+import java.text.SimpleDateFormat;
+import java.util.ArrayList;
+import java.util.function.Predicate;
+
+/**
+ * Used by {@link AlarmManagerService} to store alarms.
+ * Besides basic add and remove operations, supports querying the next upcoming alarm times,
+ * and all the alarms that are due at a given time.
+ */
+public interface AlarmStore {
+
+ /**
+ * Adds the given alarm.
+ *
+ * @param a The alarm to add.
+ */
+ void add(Alarm a);
+
+ /**
+ * Removes alarms that pass the given predicate.
+ *
+ * @param whichAlarms The predicate describing the alarms to remove.
+ * @return a list containing alarms that were removed.
+ */
+ ArrayList<Alarm> remove(Predicate<Alarm> whichAlarms);
+
+ /**
+ * Returns the total number of alarms in this store.
+ */
+ int size();
+
+ /**
+ * Get the next wakeup delivery time of all alarms in this store.
+ *
+ * @return a long timestamp in the {@link SystemClock#elapsedRealtime() elapsed}
+ * timebase.
+ */
+ long getNextWakeupDeliveryTime();
+
+ /**
+ * Get the next delivery time of all alarms in this store.
+ *
+ * @return a long timestamp in the {@link SystemClock#elapsedRealtime() elapsed}
+ * timebase. May or may not be the same as {{@link #getNextWakeupDeliveryTime()}}.
+ */
+ long getNextDeliveryTime();
+
+ /**
+ * Removes all alarms that are pending delivery at the given time.
+ *
+ * @param nowElapsed The time at which delivery eligibility is evaluated.
+ * @return The list of alarms pending at the given time.
+ */
+ ArrayList<Alarm> removePendingAlarms(long nowElapsed);
+
+ /**
+ * Adjusts alarm deliveries for all alarms according to the passed
+ * {@link AlarmDeliveryCalculator}
+ *
+ * @return {@code true} if any of the alarm deliveries changed due to this call.
+ */
+ boolean recalculateAlarmDeliveries(AlarmDeliveryCalculator deliveryCalculator);
+
+ /**
+ * Returns all the alarms in the form of a list.
+ */
+ ArrayList<Alarm> asList();
+
+ /**
+ * Dumps the state of this alarm store into the passed print writer. Also accepts the current
+ * timestamp and a {@link SimpleDateFormat} to format the timestamps as human readable delta
+ * from the current time.
+ *
+ * Primary useful for debugging. Can be called from the
+ * {@link android.os.Binder#dump(FileDescriptor PrintWriter, String[]) dump} method of the
+ * caller.
+ * @param ipw The {@link IndentingPrintWriter} to write to.
+ * @param nowElapsed the time when the dump is requested in the
+ * {@link SystemClock#elapsedRealtime()
+ * elapsed} timebase.
+ * @param sdf the date format to print timestamps in.
+ */
+ void dump(IndentingPrintWriter ipw, long nowElapsed, SimpleDateFormat sdf);
+
+ /**
+ * Dump the state of this alarm store as a proto buffer to the given stream.
+ */
+ void dumpProto(ProtoOutputStream pos, long nowElapsed);
+
+ /**
+ * A functional interface used to update the alarm. Used to describe the update in
+ * {@link #recalculateAlarmDeliveries(AlarmDeliveryCalculator)}
+ */
+ @FunctionalInterface
+ interface AlarmDeliveryCalculator {
+ /**
+ * Updates the given alarm's delivery time.
+ *
+ * @param a the alarm to update.
+ * @return {@code true} if any change was made, {@code false} otherwise.
+ */
+ boolean updateAlarmDelivery(Alarm a);
+ }
+}
diff --git a/apex/jobscheduler/service/java/com/android/server/alarm/BatchingAlarmStore.java b/apex/jobscheduler/service/java/com/android/server/alarm/BatchingAlarmStore.java
new file mode 100644
index 000000000000..a08c22213c1f
--- /dev/null
+++ b/apex/jobscheduler/service/java/com/android/server/alarm/BatchingAlarmStore.java
@@ -0,0 +1,379 @@
+/*
+ * 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.alarm;
+
+import static com.android.server.alarm.AlarmManagerService.DEBUG_BATCH;
+import static com.android.server.alarm.AlarmManagerService.TAG;
+import static com.android.server.alarm.AlarmManagerService.clampPositive;
+import static com.android.server.alarm.AlarmManagerService.dumpAlarmList;
+import static com.android.server.alarm.AlarmManagerService.isTimeTickAlarm;
+
+import android.app.AlarmManager;
+import android.util.IndentingPrintWriter;
+import android.util.Slog;
+import android.util.proto.ProtoOutputStream;
+
+import com.android.internal.util.StatLogger;
+
+import java.text.SimpleDateFormat;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.Comparator;
+import java.util.function.Predicate;
+
+/**
+ * Batching implementation of an Alarm Store.
+ * This keeps the alarms in batches, which are sorted on the start time of their delivery window.
+ */
+public class BatchingAlarmStore implements AlarmStore {
+
+ private ArrayList<Batch> mAlarmBatches = new ArrayList<>();
+ private int mSize;
+ private AlarmClockRemovalListener mAlarmClockRemovalListener;
+
+ interface Stats {
+ int REBATCH_ALL_ALARMS = 1;
+ }
+
+ final StatLogger mStatLogger = new StatLogger("Alarm store stats", new String[]{
+ "REBATCH_ALL_ALARMS",
+ });
+
+ private static final Comparator<Batch> sBatchOrder = (b1, b2) -> {
+ long when1 = b1.mStart;
+ long when2 = b2.mStart;
+ if (when1 > when2) {
+ return 1;
+ }
+ if (when1 < when2) {
+ return -1;
+ }
+ return 0;
+ };
+
+ private static final Comparator<Alarm> sIncreasingTimeOrder = (a1, a2) -> {
+ long when1 = a1.whenElapsed;
+ long when2 = a2.whenElapsed;
+ if (when1 > when2) {
+ return 1;
+ }
+ if (when1 < when2) {
+ return -1;
+ }
+ return 0;
+ };
+
+ BatchingAlarmStore(AlarmClockRemovalListener listener) {
+ mAlarmClockRemovalListener = listener;
+ }
+
+ @Override
+ public void add(Alarm a) {
+ insertAndBatchAlarm(a);
+ mSize++;
+ }
+
+ @Override
+ public ArrayList<Alarm> remove(Predicate<Alarm> whichAlarms) {
+ final ArrayList<Alarm> removed = new ArrayList<>();
+ for (int i = mAlarmBatches.size() - 1; i >= 0; i--) {
+ final Batch b = mAlarmBatches.get(i);
+ removed.addAll(b.remove(whichAlarms));
+ if (b.size() == 0) {
+ mAlarmBatches.remove(i);
+ }
+ }
+ if (!removed.isEmpty()) {
+ mSize -= removed.size();
+ rebatchAllAlarms();
+ }
+ return removed;
+ }
+
+ private void rebatchAllAlarms() {
+ final long start = mStatLogger.getTime();
+ final ArrayList<Batch> oldBatches = (ArrayList<Batch>) mAlarmBatches.clone();
+ mAlarmBatches.clear();
+ for (final Batch batch : oldBatches) {
+ for (int i = 0; i < batch.size(); i++) {
+ insertAndBatchAlarm(batch.get(i));
+ }
+ }
+ mStatLogger.logDurationStat(Stats.REBATCH_ALL_ALARMS, start);
+ }
+
+ @Override
+ public int size() {
+ return mSize;
+ }
+
+ @Override
+ public long getNextWakeupDeliveryTime() {
+ for (Batch b : mAlarmBatches) {
+ if (b.hasWakeups()) {
+ return b.mStart;
+ }
+ }
+ return 0;
+ }
+
+ @Override
+ public long getNextDeliveryTime() {
+ if (mAlarmBatches.size() > 0) {
+ return mAlarmBatches.get(0).mStart;
+ }
+ return 0;
+ }
+
+ @Override
+ public ArrayList<Alarm> removePendingAlarms(long nowElapsed) {
+ final ArrayList<Alarm> removedAlarms = new ArrayList<>();
+ while (mAlarmBatches.size() > 0) {
+ final Batch batch = mAlarmBatches.get(0);
+ if (batch.mStart > nowElapsed) {
+ break;
+ }
+ mAlarmBatches.remove(0);
+ for (int i = 0; i < batch.size(); i++) {
+ removedAlarms.add(batch.get(i));
+ }
+ }
+ mSize -= removedAlarms.size();
+ return removedAlarms;
+ }
+
+ @Override
+ public boolean recalculateAlarmDeliveries(AlarmDeliveryCalculator deliveryCalculator) {
+ boolean changed = false;
+ for (final Batch b : mAlarmBatches) {
+ for (int i = 0; i < b.size(); i++) {
+ changed |= deliveryCalculator.updateAlarmDelivery(b.get(i));
+ }
+ }
+ if (changed) {
+ rebatchAllAlarms();
+ }
+ return changed;
+ }
+
+ @Override
+ public ArrayList<Alarm> asList() {
+ final ArrayList<Alarm> allAlarms = new ArrayList<>();
+ for (final Batch batch : mAlarmBatches) {
+ for (int i = 0; i < batch.size(); i++) {
+ allAlarms.add(batch.get(i));
+ }
+ }
+ return allAlarms;
+ }
+
+ @Override
+ public void dump(IndentingPrintWriter ipw, long nowElapsed, SimpleDateFormat sdf) {
+ ipw.print("Pending alarm batches: ");
+ ipw.println(mAlarmBatches.size());
+ for (Batch b : mAlarmBatches) {
+ ipw.print(b);
+ ipw.println(':');
+ ipw.increaseIndent();
+ dumpAlarmList(ipw, b.mAlarms, nowElapsed, sdf);
+ ipw.decreaseIndent();
+ }
+ mStatLogger.dump(ipw);
+ }
+
+ @Override
+ public void dumpProto(ProtoOutputStream pos, long nowElapsed) {
+ for (Batch b : mAlarmBatches) {
+ b.dumpDebug(pos, AlarmManagerServiceDumpProto.PENDING_ALARM_BATCHES, nowElapsed);
+ }
+ }
+
+ private void insertAndBatchAlarm(Alarm alarm) {
+ final int whichBatch = ((alarm.flags & AlarmManager.FLAG_STANDALONE) != 0) ? -1
+ : attemptCoalesce(alarm.whenElapsed, alarm.maxWhenElapsed);
+
+ if (whichBatch < 0) {
+ addBatch(mAlarmBatches, new Batch(alarm));
+ } else {
+ final Batch batch = mAlarmBatches.get(whichBatch);
+ if (batch.add(alarm)) {
+ // The start time of this batch advanced, so batch ordering may
+ // have just been broken. Move it to where it now belongs.
+ mAlarmBatches.remove(whichBatch);
+ addBatch(mAlarmBatches, batch);
+ }
+ }
+ }
+
+ static void addBatch(ArrayList<Batch> list, Batch newBatch) {
+ int index = Collections.binarySearch(list, newBatch, sBatchOrder);
+ if (index < 0) {
+ index = 0 - index - 1;
+ }
+ list.add(index, newBatch);
+ }
+
+ // Return the index of the matching batch, or -1 if none found.
+ private int attemptCoalesce(long whenElapsed, long maxWhen) {
+ final int n = mAlarmBatches.size();
+ for (int i = 0; i < n; i++) {
+ Batch b = mAlarmBatches.get(i);
+ if ((b.mFlags & AlarmManager.FLAG_STANDALONE) == 0 && b.canHold(whenElapsed, maxWhen)) {
+ return i;
+ }
+ }
+ return -1;
+ }
+
+ final class Batch {
+ long mStart; // These endpoints are always in ELAPSED
+ long mEnd;
+ int mFlags; // Flags for alarms, such as FLAG_STANDALONE.
+
+ final ArrayList<Alarm> mAlarms = new ArrayList<>();
+
+ Batch(Alarm seed) {
+ mStart = seed.whenElapsed;
+ mEnd = clampPositive(seed.maxWhenElapsed);
+ mFlags = seed.flags;
+ mAlarms.add(seed);
+ }
+
+ int size() {
+ return mAlarms.size();
+ }
+
+ Alarm get(int index) {
+ return mAlarms.get(index);
+ }
+
+ boolean canHold(long whenElapsed, long maxWhen) {
+ return (mEnd >= whenElapsed) && (mStart <= maxWhen);
+ }
+
+ boolean add(Alarm alarm) {
+ boolean newStart = false;
+ // narrows the batch if necessary; presumes that canHold(alarm) is true
+ int index = Collections.binarySearch(mAlarms, alarm, sIncreasingTimeOrder);
+ if (index < 0) {
+ index = 0 - index - 1;
+ }
+ mAlarms.add(index, alarm);
+ if (DEBUG_BATCH) {
+ Slog.v(TAG, "Adding " + alarm + " to " + this);
+ }
+ if (alarm.whenElapsed > mStart) {
+ mStart = alarm.whenElapsed;
+ newStart = true;
+ }
+ if (alarm.maxWhenElapsed < mEnd) {
+ mEnd = alarm.maxWhenElapsed;
+ }
+ mFlags |= alarm.flags;
+
+ if (DEBUG_BATCH) {
+ Slog.v(TAG, " => now " + this);
+ }
+ return newStart;
+ }
+
+ ArrayList<Alarm> remove(Predicate<Alarm> predicate) {
+ final ArrayList<Alarm> removed = new ArrayList<>();
+ long newStart = 0; // recalculate endpoints as we go
+ long newEnd = Long.MAX_VALUE;
+ int newFlags = 0;
+ for (int i = 0; i < mAlarms.size(); ) {
+ Alarm alarm = mAlarms.get(i);
+ if (predicate.test(alarm)) {
+ removed.add(mAlarms.remove(i));
+ if (alarm.alarmClock != null && mAlarmClockRemovalListener != null) {
+ mAlarmClockRemovalListener.onRemoved();
+ }
+ if (isTimeTickAlarm(alarm)) {
+ // This code path is not invoked when delivering alarms, only when removing
+ // alarms due to the caller cancelling it or getting uninstalled, etc.
+ Slog.wtf(TAG, "Removed TIME_TICK alarm");
+ }
+ } else {
+ if (alarm.whenElapsed > newStart) {
+ newStart = alarm.whenElapsed;
+ }
+ if (alarm.maxWhenElapsed < newEnd) {
+ newEnd = alarm.maxWhenElapsed;
+ }
+ newFlags |= alarm.flags;
+ i++;
+ }
+ }
+ if (!removed.isEmpty()) {
+ // commit the new batch bounds
+ mStart = newStart;
+ mEnd = newEnd;
+ mFlags = newFlags;
+ }
+ return removed;
+ }
+
+ boolean hasWakeups() {
+ final int n = mAlarms.size();
+ for (int i = 0; i < n; i++) {
+ Alarm a = mAlarms.get(i);
+ if (a.wakeup) {
+ return true;
+ }
+ }
+ return false;
+ }
+
+ @Override
+ public String toString() {
+ StringBuilder b = new StringBuilder(40);
+ b.append("Batch{");
+ b.append(Integer.toHexString(this.hashCode()));
+ b.append(" num=");
+ b.append(size());
+ b.append(" start=");
+ b.append(mStart);
+ b.append(" end=");
+ b.append(mEnd);
+ if (mFlags != 0) {
+ b.append(" flgs=0x");
+ b.append(Integer.toHexString(mFlags));
+ }
+ b.append('}');
+ return b.toString();
+ }
+
+ public void dumpDebug(ProtoOutputStream proto, long fieldId, long nowElapsed) {
+ final long token = proto.start(fieldId);
+
+ proto.write(BatchProto.START_REALTIME, mStart);
+ proto.write(BatchProto.END_REALTIME, mEnd);
+ proto.write(BatchProto.FLAGS, mFlags);
+ for (Alarm a : mAlarms) {
+ a.dumpDebug(proto, BatchProto.ALARMS, nowElapsed);
+ }
+
+ proto.end(token);
+ }
+ }
+
+ @FunctionalInterface
+ interface AlarmClockRemovalListener {
+ void onRemoved();
+ }
+}
diff --git a/apex/jobscheduler/service/java/com/android/server/job/controllers/ConnectivityController.java b/apex/jobscheduler/service/java/com/android/server/job/controllers/ConnectivityController.java
index f1c624d1d9f5..67997cf31501 100644
--- a/apex/jobscheduler/service/java/com/android/server/job/controllers/ConnectivityController.java
+++ b/apex/jobscheduler/service/java/com/android/server/job/controllers/ConnectivityController.java
@@ -22,6 +22,7 @@ import static android.net.NetworkCapabilities.NET_CAPABILITY_NOT_METERED;
import static com.android.server.job.JobSchedulerService.RESTRICTED_INDEX;
+import android.annotation.Nullable;
import android.app.job.JobInfo;
import android.net.ConnectivityManager;
import android.net.ConnectivityManager.NetworkCallback;
@@ -86,9 +87,12 @@ public final class ConnectivityController extends RestrictingController implemen
@GuardedBy("mLock")
private final SparseArray<ArraySet<JobStatus>> mRequestedWhitelistJobs = new SparseArray<>();
- /** List of currently available networks. */
+ /**
+ * Set of currently available networks mapped to their latest network capabilities. Cache the
+ * latest capabilities to avoid unnecessary calls into ConnectivityManager.
+ */
@GuardedBy("mLock")
- private final ArraySet<Network> mAvailableNetworks = new ArraySet<>();
+ private final ArrayMap<Network, NetworkCapabilities> mAvailableNetworks = new ArrayMap<>();
private static final int MSG_DATA_SAVER_TOGGLED = 0;
private static final int MSG_UID_RULES_CHANGES = 1;
@@ -165,9 +169,8 @@ public final class ConnectivityController extends RestrictingController implemen
public boolean isNetworkAvailable(JobStatus job) {
synchronized (mLock) {
for (int i = 0; i < mAvailableNetworks.size(); ++i) {
- final Network network = mAvailableNetworks.valueAt(i);
- final NetworkCapabilities capabilities = mConnManager.getNetworkCapabilities(
- network);
+ final Network network = mAvailableNetworks.keyAt(i);
+ final NetworkCapabilities capabilities = mAvailableNetworks.valueAt(i);
final boolean satisfied = isSatisfied(job, network, capabilities, mConstants);
if (DEBUG) {
Slog.v(TAG, "isNetworkAvailable(" + job + ") with network " + network
@@ -427,9 +430,33 @@ public final class ConnectivityController extends RestrictingController implemen
return false;
}
+ @Nullable
+ private NetworkCapabilities getNetworkCapabilities(@Nullable Network network) {
+ if (network == null) {
+ return null;
+ }
+ synchronized (mLock) {
+ // There is technically a race here if the Network object is reused. This can happen
+ // only if that Network disconnects and the auto-incrementing network ID in
+ // ConnectivityService wraps. This should no longer be a concern if/when we only make
+ // use of asynchronous calls.
+ if (mAvailableNetworks.get(network) != null) {
+ return mAvailableNetworks.get(network);
+ }
+
+ // This should almost never happen because any time a new network connects, the
+ // NetworkCallback would populate mAvailableNetworks. However, it's currently necessary
+ // because we also call synchronous methods such as getActiveNetworkForUid.
+ // TODO(134978280): remove after switching to callback-based APIs
+ final NetworkCapabilities capabilities = mConnManager.getNetworkCapabilities(network);
+ mAvailableNetworks.put(network, capabilities);
+ return capabilities;
+ }
+ }
+
private boolean updateConstraintsSatisfied(JobStatus jobStatus) {
final Network network = mConnManager.getActiveNetworkForUid(jobStatus.getSourceUid());
- final NetworkCapabilities capabilities = mConnManager.getNetworkCapabilities(network);
+ final NetworkCapabilities capabilities = getNetworkCapabilities(network);
return updateConstraintsSatisfied(jobStatus, network, capabilities);
}
@@ -470,19 +497,13 @@ public final class ConnectivityController extends RestrictingController implemen
*/
private void updateTrackedJobs(int filterUid, Network filterNetwork) {
synchronized (mLock) {
- // Since this is a really hot codepath, temporarily cache any
- // answers that we get from ConnectivityManager.
- final ArrayMap<Network, NetworkCapabilities> networkToCapabilities = new ArrayMap<>();
-
boolean changed = false;
if (filterUid == -1) {
for (int i = mTrackedJobs.size() - 1; i >= 0; i--) {
- changed |= updateTrackedJobsLocked(mTrackedJobs.valueAt(i),
- filterNetwork, networkToCapabilities);
+ changed |= updateTrackedJobsLocked(mTrackedJobs.valueAt(i), filterNetwork);
}
} else {
- changed = updateTrackedJobsLocked(mTrackedJobs.get(filterUid),
- filterNetwork, networkToCapabilities);
+ changed = updateTrackedJobsLocked(mTrackedJobs.get(filterUid), filterNetwork);
}
if (changed) {
mStateChangedListener.onControllerStateChanged();
@@ -490,18 +511,13 @@ public final class ConnectivityController extends RestrictingController implemen
}
}
- private boolean updateTrackedJobsLocked(ArraySet<JobStatus> jobs, Network filterNetwork,
- ArrayMap<Network, NetworkCapabilities> networkToCapabilities) {
+ private boolean updateTrackedJobsLocked(ArraySet<JobStatus> jobs, Network filterNetwork) {
if (jobs == null || jobs.size() == 0) {
return false;
}
final Network network = mConnManager.getActiveNetworkForUid(jobs.valueAt(0).getSourceUid());
- NetworkCapabilities capabilities = networkToCapabilities.get(network);
- if (capabilities == null) {
- capabilities = mConnManager.getNetworkCapabilities(network);
- networkToCapabilities.put(network, capabilities);
- }
+ final NetworkCapabilities capabilities = getNetworkCapabilities(network);
final boolean networkMatch = (filterNetwork == null
|| Objects.equals(filterNetwork, network));
@@ -544,9 +560,9 @@ public final class ConnectivityController extends RestrictingController implemen
@Override
public void onAvailable(Network network) {
if (DEBUG) Slog.v(TAG, "onAvailable: " + network);
- synchronized (mLock) {
- mAvailableNetworks.add(network);
- }
+ // Documentation says not to call getNetworkCapabilities here but wait for
+ // onCapabilitiesChanged instead. onCapabilitiesChanged should be called immediately
+ // after this, so no need to update mAvailableNetworks here.
}
@Override
@@ -554,6 +570,9 @@ public final class ConnectivityController extends RestrictingController implemen
if (DEBUG) {
Slog.v(TAG, "onCapabilitiesChanged: " + network);
}
+ synchronized (mLock) {
+ mAvailableNetworks.put(network, capabilities);
+ }
updateTrackedJobs(-1, network);
}
@@ -630,6 +649,8 @@ public final class ConnectivityController extends RestrictingController implemen
pw.println("Available networks:");
pw.increaseIndent();
for (int i = 0; i < mAvailableNetworks.size(); i++) {
+ pw.print(mAvailableNetworks.keyAt(i));
+ pw.print(": ");
pw.println(mAvailableNetworks.valueAt(i));
}
pw.decreaseIndent();
@@ -667,7 +688,7 @@ public final class ConnectivityController extends RestrictingController implemen
mRequestedWhitelistJobs.keyAt(i));
}
for (int i = 0; i < mAvailableNetworks.size(); i++) {
- Network network = mAvailableNetworks.valueAt(i);
+ Network network = mAvailableNetworks.keyAt(i);
if (network != null) {
network.dumpDebug(proto,
StateControllerProto.ConnectivityController.AVAILABLE_NETWORKS);
diff --git a/apex/jobscheduler/service/java/com/android/server/usage/AppStandbyController.java b/apex/jobscheduler/service/java/com/android/server/usage/AppStandbyController.java
index 6bc95bf8bc75..c033138d5f20 100644
--- a/apex/jobscheduler/service/java/com/android/server/usage/AppStandbyController.java
+++ b/apex/jobscheduler/service/java/com/android/server/usage/AppStandbyController.java
@@ -2131,7 +2131,7 @@ public class AppStandbyController implements AppStandbyInternal {
}
public List<UserHandle> getValidCrossProfileTargets(String pkg, int userId) {
- final int uid = mPackageManagerInternal.getPackageUidInternal(pkg, 0, userId);
+ final int uid = mPackageManagerInternal.getPackageUid(pkg, /* flags= */ 0, userId);
final AndroidPackage aPkg = mPackageManagerInternal.getPackage(uid);
if (uid < 0
|| aPkg == null
diff --git a/apex/statsd/Android.bp b/apex/statsd/Android.bp
index e75fa88c54fe..ede8852c5905 100644
--- a/apex/statsd/Android.bp
+++ b/apex/statsd/Android.bp
@@ -19,8 +19,10 @@ apex {
}
apex_defaults {
- native_shared_libs: [
+ jni_libs: [
"libstats_jni",
+ ],
+ native_shared_libs: [
"libstatspull",
"libstatssocket",
],
diff --git a/api/current.txt b/api/current.txt
index 68d3dbe86f93..a1629f1a937e 100644
--- a/api/current.txt
+++ b/api/current.txt
@@ -11617,6 +11617,16 @@ package android.content.pm {
field public int version;
}
+ public final class FileChecksum implements android.os.Parcelable {
+ method public int describeContents();
+ method public int getKind();
+ method @Nullable public java.security.cert.Certificate getSourceCertificate() throws java.security.cert.CertificateException;
+ method @Nullable public String getSplitName();
+ method @NonNull public byte[] getValue();
+ method public void writeToParcel(@NonNull android.os.Parcel, int);
+ field @NonNull public static final android.os.Parcelable.Creator<android.content.pm.FileChecksum> CREATOR;
+ }
+
public final class InstallSourceInfo implements android.os.Parcelable {
method public int describeContents();
method @Nullable public String getInitiatingPackageName();
@@ -11992,6 +12002,7 @@ package android.content.pm {
method @Nullable public abstract android.graphics.drawable.Drawable getApplicationLogo(@NonNull String) throws android.content.pm.PackageManager.NameNotFoundException;
method @NonNull public CharSequence getBackgroundPermissionOptionLabel();
method @Nullable public abstract android.content.pm.ChangedPackages getChangedPackages(@IntRange(from=0) int);
+ method public void getChecksums(@NonNull String, boolean, int, @Nullable java.util.List<java.security.cert.Certificate>, @NonNull android.content.IntentSender) throws java.security.cert.CertificateEncodingException, java.io.IOException, android.content.pm.PackageManager.NameNotFoundException;
method public abstract int getComponentEnabledSetting(@NonNull android.content.ComponentName);
method @NonNull public abstract android.graphics.drawable.Drawable getDefaultActivityIcon();
method @Nullable public abstract android.graphics.drawable.Drawable getDrawable(@NonNull String, @DrawableRes int, @Nullable android.content.pm.ApplicationInfo);
@@ -12082,6 +12093,7 @@ package android.content.pm {
field public static final int COMPONENT_ENABLED_STATE_DISABLED_USER = 3; // 0x3
field public static final int COMPONENT_ENABLED_STATE_ENABLED = 1; // 0x1
field public static final int DONT_KILL_APP = 1; // 0x1
+ field public static final String EXTRA_CHECKSUMS = "android.content.pm.extra.CHECKSUMS";
field public static final String EXTRA_VERIFICATION_ID = "android.content.pm.extra.VERIFICATION_ID";
field public static final String EXTRA_VERIFICATION_RESULT = "android.content.pm.extra.VERIFICATION_RESULT";
field public static final String FEATURE_ACTIVITIES_ON_SECONDARY_DISPLAYS = "android.software.activities_on_secondary_displays";
@@ -12236,6 +12248,8 @@ package android.content.pm {
field public static final int MATCH_SYSTEM_ONLY = 1048576; // 0x100000
field public static final int MATCH_UNINSTALLED_PACKAGES = 8192; // 0x2000
field public static final long MAXIMUM_VERIFICATION_TIMEOUT = 3600000L; // 0x36ee80L
+ field public static final int PARTIAL_MERKLE_ROOT_1M_SHA256 = 32; // 0x20
+ field public static final int PARTIAL_MERKLE_ROOT_1M_SHA512 = 64; // 0x40
field public static final int PERMISSION_DENIED = -1; // 0xffffffff
field public static final int PERMISSION_GRANTED = 0; // 0x0
field public static final int SIGNATURE_FIRST_NOT_SIGNED = -1; // 0xffffffff
@@ -12245,9 +12259,16 @@ package android.content.pm {
field public static final int SIGNATURE_SECOND_NOT_SIGNED = -2; // 0xfffffffe
field public static final int SIGNATURE_UNKNOWN_PACKAGE = -4; // 0xfffffffc
field public static final int SYNCHRONOUS = 2; // 0x2
+ field @Nullable public static final java.util.List<java.security.cert.Certificate> TRUST_ALL;
+ field @NonNull public static final java.util.List<java.security.cert.Certificate> TRUST_NONE;
field public static final int VERIFICATION_ALLOW = 1; // 0x1
field public static final int VERIFICATION_REJECT = -1; // 0xffffffff
field public static final int VERSION_CODE_HIGHEST = -1; // 0xffffffff
+ field public static final int WHOLE_MD5 = 2; // 0x2
+ field public static final int WHOLE_MERKLE_ROOT_4K_SHA256 = 1; // 0x1
+ field public static final int WHOLE_SHA1 = 4; // 0x4
+ field public static final int WHOLE_SHA256 = 8; // 0x8
+ field public static final int WHOLE_SHA512 = 16; // 0x10
}
public static class PackageManager.NameNotFoundException extends android.util.AndroidException {
@@ -31624,6 +31645,7 @@ package android.net.wifi {
method @Nullable public String getPassphrase();
method @Nullable public android.net.wifi.hotspot2.PasspointConfiguration getPasspointConfig();
method @IntRange(from=0) public int getPriority();
+ method public int getPriorityGroup();
method @Nullable public String getSsid();
method public boolean isAppInteractionRequired();
method public boolean isCredentialSharedWithUser();
@@ -31643,6 +31665,7 @@ package android.net.wifi {
method @NonNull public android.net.wifi.WifiNetworkSuggestion.Builder setBssid(@NonNull android.net.MacAddress);
method @NonNull public android.net.wifi.WifiNetworkSuggestion.Builder setCredentialSharedWithUser(boolean);
method @NonNull public android.net.wifi.WifiNetworkSuggestion.Builder setIsAppInteractionRequired(boolean);
+ method @NonNull public android.net.wifi.WifiNetworkSuggestion.Builder setIsEnhancedMacRandomizationEnabled(boolean);
method @NonNull public android.net.wifi.WifiNetworkSuggestion.Builder setIsEnhancedOpen(boolean);
method @NonNull public android.net.wifi.WifiNetworkSuggestion.Builder setIsHiddenSsid(boolean);
method @NonNull public android.net.wifi.WifiNetworkSuggestion.Builder setIsInitialAutojoinEnabled(boolean);
@@ -31650,6 +31673,7 @@ package android.net.wifi {
method @NonNull public android.net.wifi.WifiNetworkSuggestion.Builder setIsUserInteractionRequired(boolean);
method @NonNull public android.net.wifi.WifiNetworkSuggestion.Builder setPasspointConfig(@NonNull android.net.wifi.hotspot2.PasspointConfiguration);
method @NonNull public android.net.wifi.WifiNetworkSuggestion.Builder setPriority(@IntRange(from=0) int);
+ method @NonNull public android.net.wifi.WifiNetworkSuggestion.Builder setPriorityGroup(int);
method @NonNull public android.net.wifi.WifiNetworkSuggestion.Builder setSsid(@NonNull String);
method @NonNull public android.net.wifi.WifiNetworkSuggestion.Builder setUntrusted(boolean);
method @NonNull public android.net.wifi.WifiNetworkSuggestion.Builder setWapiEnterpriseConfig(@NonNull android.net.wifi.WifiEnterpriseConfig);
diff --git a/api/system-current.txt b/api/system-current.txt
index 41e859363581..62503d73defa 100755
--- a/api/system-current.txt
+++ b/api/system-current.txt
@@ -219,6 +219,7 @@ package android {
field public static final String SET_WALLPAPER_COMPONENT = "android.permission.SET_WALLPAPER_COMPONENT";
field public static final String SHOW_KEYGUARD_MESSAGE = "android.permission.SHOW_KEYGUARD_MESSAGE";
field public static final String SHUTDOWN = "android.permission.SHUTDOWN";
+ field public static final String STATUS_BAR_SERVICE = "android.permission.STATUS_BAR_SERVICE";
field public static final String STOP_APP_SWITCHES = "android.permission.STOP_APP_SWITCHES";
field public static final String SUBSTITUTE_NOTIFICATION_APP_NAME = "android.permission.SUBSTITUTE_NOTIFICATION_APP_NAME";
field public static final String SUBSTITUTE_SHARE_TARGET_APP_NAME_AND_ICON = "android.permission.SUBSTITUTE_SHARE_TARGET_APP_NAME_AND_ICON";
@@ -1740,6 +1741,7 @@ package android.content {
field public static final String ETHERNET_SERVICE = "ethernet";
field public static final String EUICC_CARD_SERVICE = "euicc_card";
field public static final String HDMI_CONTROL_SERVICE = "hdmi_control";
+ field public static final String MEDIA_TRANSCODING_SERVICE = "media_transcoding";
field public static final String NETD_SERVICE = "netd";
field public static final String NETWORK_SCORE_SERVICE = "network_score";
field public static final String OEM_LOCK_SERVICE = "oem_lock";
@@ -4197,8 +4199,10 @@ package android.media {
public class AudioManager {
method @Deprecated public int abandonAudioFocus(android.media.AudioManager.OnAudioFocusChangeListener, android.media.AudioAttributes);
method @Deprecated @RequiresPermission(android.Manifest.permission.MODIFY_AUDIO_ROUTING) public void addOnPreferredDeviceForStrategyChangedListener(@NonNull java.util.concurrent.Executor, @NonNull android.media.AudioManager.OnPreferredDeviceForStrategyChangedListener) throws java.lang.SecurityException;
+ method @RequiresPermission(android.Manifest.permission.MODIFY_AUDIO_ROUTING) public void addOnPreferredDevicesForCapturePresetChangedListener(@NonNull java.util.concurrent.Executor, @NonNull android.media.AudioManager.OnPreferredDevicesForCapturePresetChangedListener) throws java.lang.SecurityException;
method @RequiresPermission(android.Manifest.permission.MODIFY_AUDIO_ROUTING) public void addOnPreferredDevicesForStrategyChangedListener(@NonNull java.util.concurrent.Executor, @NonNull android.media.AudioManager.OnPreferredDevicesForStrategyChangedListener) throws java.lang.SecurityException;
method public void clearAudioServerStateCallback();
+ method @RequiresPermission(android.Manifest.permission.MODIFY_AUDIO_ROUTING) public boolean clearPreferredDevicesForCapturePreset(int);
method @RequiresPermission(android.Manifest.permission.MODIFY_AUDIO_ROUTING) public int dispatchAudioFocusChange(@NonNull android.media.AudioFocusInfo, int, @NonNull android.media.audiopolicy.AudioPolicy);
method @IntRange(from=0) public long getAdditionalOutputDeviceDelay(@NonNull android.media.AudioDeviceInfo);
method @NonNull @RequiresPermission(android.Manifest.permission.MODIFY_AUDIO_ROUTING) public static java.util.List<android.media.audiopolicy.AudioProductStrategy> getAudioProductStrategies();
@@ -4209,6 +4213,7 @@ package android.media {
method @IntRange(from=0) @RequiresPermission(android.Manifest.permission.MODIFY_AUDIO_ROUTING) public int getMaxVolumeIndexForAttributes(@NonNull android.media.AudioAttributes);
method @IntRange(from=0) @RequiresPermission(android.Manifest.permission.MODIFY_AUDIO_ROUTING) public int getMinVolumeIndexForAttributes(@NonNull android.media.AudioAttributes);
method @Nullable @RequiresPermission(android.Manifest.permission.MODIFY_AUDIO_ROUTING) public android.media.AudioDeviceAttributes getPreferredDeviceForStrategy(@NonNull android.media.audiopolicy.AudioProductStrategy);
+ method @NonNull @RequiresPermission(android.Manifest.permission.MODIFY_AUDIO_ROUTING) public java.util.List<android.media.AudioDeviceAttributes> getPreferredDevicesForCapturePreset(int);
method @NonNull @RequiresPermission(android.Manifest.permission.MODIFY_AUDIO_ROUTING) public java.util.List<android.media.AudioDeviceAttributes> getPreferredDevicesForStrategy(@NonNull android.media.audiopolicy.AudioProductStrategy);
method @NonNull @RequiresPermission(android.Manifest.permission.MODIFY_AUDIO_ROUTING) public int[] getSupportedSystemUsages();
method @IntRange(from=0) @RequiresPermission(android.Manifest.permission.MODIFY_AUDIO_ROUTING) public int getVolumeIndexForAttributes(@NonNull android.media.AudioAttributes);
@@ -4217,6 +4222,7 @@ package android.media {
method @RequiresPermission(android.Manifest.permission.MODIFY_AUDIO_ROUTING) public int registerAudioPolicy(@NonNull android.media.audiopolicy.AudioPolicy);
method public void registerVolumeGroupCallback(@NonNull java.util.concurrent.Executor, @NonNull android.media.AudioManager.VolumeGroupCallback);
method @Deprecated @RequiresPermission(android.Manifest.permission.MODIFY_AUDIO_ROUTING) public void removeOnPreferredDeviceForStrategyChangedListener(@NonNull android.media.AudioManager.OnPreferredDeviceForStrategyChangedListener);
+ method @RequiresPermission(android.Manifest.permission.MODIFY_AUDIO_ROUTING) public void removeOnPreferredDevicesForCapturePresetChangedListener(@NonNull android.media.AudioManager.OnPreferredDevicesForCapturePresetChangedListener);
method @RequiresPermission(android.Manifest.permission.MODIFY_AUDIO_ROUTING) public void removeOnPreferredDevicesForStrategyChangedListener(@NonNull android.media.AudioManager.OnPreferredDevicesForStrategyChangedListener);
method @RequiresPermission(android.Manifest.permission.MODIFY_AUDIO_ROUTING) public boolean removePreferredDeviceForStrategy(@NonNull android.media.audiopolicy.AudioProductStrategy);
method @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) public int requestAudioFocus(android.media.AudioManager.OnAudioFocusChangeListener, @NonNull android.media.AudioAttributes, int, int) throws java.lang.IllegalArgumentException;
@@ -4226,6 +4232,7 @@ package android.media {
method public void setAudioServerStateCallback(@NonNull java.util.concurrent.Executor, @NonNull android.media.AudioManager.AudioServerStateCallback);
method @RequiresPermission(android.Manifest.permission.MODIFY_AUDIO_ROUTING) public void setDeviceVolumeBehavior(@NonNull android.media.AudioDeviceAttributes, int);
method @RequiresPermission(android.Manifest.permission.MODIFY_AUDIO_ROUTING) public void setFocusRequestResult(@NonNull android.media.AudioFocusInfo, int, @NonNull android.media.audiopolicy.AudioPolicy);
+ method @RequiresPermission(android.Manifest.permission.MODIFY_AUDIO_ROUTING) public boolean setPreferredDeviceForCapturePreset(int, @NonNull android.media.AudioDeviceAttributes);
method @RequiresPermission(android.Manifest.permission.MODIFY_AUDIO_ROUTING) public boolean setPreferredDeviceForStrategy(@NonNull android.media.audiopolicy.AudioProductStrategy, @NonNull android.media.AudioDeviceAttributes);
method @RequiresPermission(android.Manifest.permission.MODIFY_AUDIO_ROUTING) public boolean setPreferredDevicesForStrategy(@NonNull android.media.audiopolicy.AudioProductStrategy, @NonNull java.util.List<android.media.AudioDeviceAttributes>);
method @RequiresPermission(android.Manifest.permission.MODIFY_AUDIO_ROUTING) public void setSupportedSystemUsages(@NonNull int[]);
@@ -4255,6 +4262,10 @@ package android.media {
method @Deprecated public void onPreferredDeviceForStrategyChanged(@NonNull android.media.audiopolicy.AudioProductStrategy, @Nullable android.media.AudioDeviceAttributes);
}
+ public static interface AudioManager.OnPreferredDevicesForCapturePresetChangedListener {
+ method public void onPreferredDevicesForCapturePresetChanged(int, @NonNull java.util.List<android.media.AudioDeviceAttributes>);
+ }
+
public static interface AudioManager.OnPreferredDevicesForStrategyChangedListener {
method public void onPreferredDevicesForStrategyChanged(@NonNull android.media.audiopolicy.AudioProductStrategy, @NonNull java.util.List<android.media.AudioDeviceAttributes>);
}
@@ -4332,6 +4343,60 @@ package android.media {
field @RequiresPermission(android.Manifest.permission.CAPTURE_AUDIO_OUTPUT) public static final int RADIO_TUNER = 1998; // 0x7ce
}
+ public final class MediaTranscodeManager implements java.lang.AutoCloseable {
+ method public void close();
+ method @NonNull public android.media.MediaTranscodeManager.TranscodingJob enqueueRequest(@NonNull android.media.MediaTranscodeManager.TranscodingRequest, @NonNull java.util.concurrent.Executor, @NonNull android.media.MediaTranscodeManager.OnTranscodingFinishedListener) throws java.io.FileNotFoundException;
+ method protected void finalize();
+ field public static final int PRIORITY_OFFLINE = 2; // 0x2
+ field public static final int PRIORITY_REALTIME = 1; // 0x1
+ field public static final int TRANSCODING_TYPE_VIDEO = 1; // 0x1
+ }
+
+ @java.lang.FunctionalInterface public static interface MediaTranscodeManager.OnTranscodingFinishedListener {
+ method public void onTranscodingFinished(@NonNull android.media.MediaTranscodeManager.TranscodingJob);
+ }
+
+ public static final class MediaTranscodeManager.TranscodingJob {
+ method public void cancel();
+ method public int getJobId();
+ method @IntRange(from=0, to=100) public int getProgress();
+ method public int getResult();
+ method public int getStatus();
+ method public boolean retry();
+ method public void setOnProgressUpdateListener(@NonNull java.util.concurrent.Executor, @Nullable android.media.MediaTranscodeManager.TranscodingJob.OnProgressUpdateListener);
+ method public void setOnProgressUpdateListener(int, @NonNull java.util.concurrent.Executor, @Nullable android.media.MediaTranscodeManager.TranscodingJob.OnProgressUpdateListener);
+ field public static final int RESULT_CANCELED = 4; // 0x4
+ field public static final int RESULT_ERROR = 3; // 0x3
+ field public static final int RESULT_NONE = 1; // 0x1
+ field public static final int RESULT_SUCCESS = 2; // 0x2
+ field public static final int STATUS_FINISHED = 3; // 0x3
+ field public static final int STATUS_PAUSED = 4; // 0x4
+ field public static final int STATUS_PENDING = 1; // 0x1
+ field public static final int STATUS_RUNNING = 2; // 0x2
+ }
+
+ @java.lang.FunctionalInterface public static interface MediaTranscodeManager.TranscodingJob.OnProgressUpdateListener {
+ method public void onProgressUpdate(@IntRange(from=0, to=100) int);
+ }
+
+ public static final class MediaTranscodeManager.TranscodingRequest {
+ method @NonNull public android.net.Uri getDestinationUri();
+ method public int getPriority();
+ method @NonNull public android.net.Uri getSourceUri();
+ method public int getType();
+ method @Nullable public android.media.MediaFormat getVideoTrackFormat();
+ }
+
+ public static final class MediaTranscodeManager.TranscodingRequest.Builder {
+ ctor public MediaTranscodeManager.TranscodingRequest.Builder();
+ method @NonNull public android.media.MediaTranscodeManager.TranscodingRequest build();
+ method @NonNull public android.media.MediaTranscodeManager.TranscodingRequest.Builder setDestinationUri(@NonNull android.net.Uri);
+ method @NonNull public android.media.MediaTranscodeManager.TranscodingRequest.Builder setPriority(int);
+ method @NonNull public android.media.MediaTranscodeManager.TranscodingRequest.Builder setSourceUri(@NonNull android.net.Uri);
+ method @NonNull public android.media.MediaTranscodeManager.TranscodingRequest.Builder setType(int);
+ method @NonNull public android.media.MediaTranscodeManager.TranscodingRequest.Builder setVideoTrackFormat(@NonNull android.media.MediaFormat);
+ }
+
public class PlayerProxy {
method public void pause();
method public void setPan(float);
diff --git a/api/test-current.txt b/api/test-current.txt
index 529dcf71ef6e..2dd740924275 100644
--- a/api/test-current.txt
+++ b/api/test-current.txt
@@ -1819,6 +1819,60 @@ package android.media {
method @NonNull public String getOriginalId();
}
+ public final class MediaTranscodeManager implements java.lang.AutoCloseable {
+ method public void close();
+ method @NonNull public android.media.MediaTranscodeManager.TranscodingJob enqueueRequest(@NonNull android.media.MediaTranscodeManager.TranscodingRequest, @NonNull java.util.concurrent.Executor, @NonNull android.media.MediaTranscodeManager.OnTranscodingFinishedListener) throws java.io.FileNotFoundException;
+ method protected void finalize();
+ field public static final int PRIORITY_OFFLINE = 2; // 0x2
+ field public static final int PRIORITY_REALTIME = 1; // 0x1
+ field public static final int TRANSCODING_TYPE_VIDEO = 1; // 0x1
+ }
+
+ @java.lang.FunctionalInterface public static interface MediaTranscodeManager.OnTranscodingFinishedListener {
+ method public void onTranscodingFinished(@NonNull android.media.MediaTranscodeManager.TranscodingJob);
+ }
+
+ public static final class MediaTranscodeManager.TranscodingJob {
+ method public void cancel();
+ method public int getJobId();
+ method @IntRange(from=0, to=100) public int getProgress();
+ method public int getResult();
+ method public int getStatus();
+ method public boolean retry();
+ method public void setOnProgressUpdateListener(@NonNull java.util.concurrent.Executor, @Nullable android.media.MediaTranscodeManager.TranscodingJob.OnProgressUpdateListener);
+ method public void setOnProgressUpdateListener(int, @NonNull java.util.concurrent.Executor, @Nullable android.media.MediaTranscodeManager.TranscodingJob.OnProgressUpdateListener);
+ field public static final int RESULT_CANCELED = 4; // 0x4
+ field public static final int RESULT_ERROR = 3; // 0x3
+ field public static final int RESULT_NONE = 1; // 0x1
+ field public static final int RESULT_SUCCESS = 2; // 0x2
+ field public static final int STATUS_FINISHED = 3; // 0x3
+ field public static final int STATUS_PAUSED = 4; // 0x4
+ field public static final int STATUS_PENDING = 1; // 0x1
+ field public static final int STATUS_RUNNING = 2; // 0x2
+ }
+
+ @java.lang.FunctionalInterface public static interface MediaTranscodeManager.TranscodingJob.OnProgressUpdateListener {
+ method public void onProgressUpdate(@IntRange(from=0, to=100) int);
+ }
+
+ public static final class MediaTranscodeManager.TranscodingRequest {
+ method @NonNull public android.net.Uri getDestinationUri();
+ method public int getPriority();
+ method @NonNull public android.net.Uri getSourceUri();
+ method public int getType();
+ method @Nullable public android.media.MediaFormat getVideoTrackFormat();
+ }
+
+ public static final class MediaTranscodeManager.TranscodingRequest.Builder {
+ ctor public MediaTranscodeManager.TranscodingRequest.Builder();
+ method @NonNull public android.media.MediaTranscodeManager.TranscodingRequest build();
+ method @NonNull public android.media.MediaTranscodeManager.TranscodingRequest.Builder setDestinationUri(@NonNull android.net.Uri);
+ method @NonNull public android.media.MediaTranscodeManager.TranscodingRequest.Builder setPriority(int);
+ method @NonNull public android.media.MediaTranscodeManager.TranscodingRequest.Builder setSourceUri(@NonNull android.net.Uri);
+ method @NonNull public android.media.MediaTranscodeManager.TranscodingRequest.Builder setType(int);
+ method @NonNull public android.media.MediaTranscodeManager.TranscodingRequest.Builder setVideoTrackFormat(@NonNull android.media.MediaFormat);
+ }
+
public final class PlaybackParams implements android.os.Parcelable {
method public int getAudioStretchMode();
method public android.media.PlaybackParams setAudioStretchMode(int);
@@ -5579,7 +5633,7 @@ package android.window {
method @BinderThread public void onTaskInfoChanged(@NonNull android.app.ActivityManager.RunningTaskInfo);
method @BinderThread public void onTaskVanished(@NonNull android.app.ActivityManager.RunningTaskInfo);
method @RequiresPermission(android.Manifest.permission.MANAGE_ACTIVITY_STACKS) public final void registerOrganizer();
- method @RequiresPermission(android.Manifest.permission.MANAGE_ACTIVITY_STACKS) public void setInterceptBackPressedOnTaskRoot(boolean);
+ method @RequiresPermission(android.Manifest.permission.MANAGE_ACTIVITY_STACKS) public void setInterceptBackPressedOnTaskRoot(@NonNull android.window.WindowContainerToken, boolean);
method @RequiresPermission(android.Manifest.permission.MANAGE_ACTIVITY_STACKS) public static void setLaunchRoot(int, @NonNull android.window.WindowContainerToken);
method @RequiresPermission(android.Manifest.permission.MANAGE_ACTIVITY_STACKS) public final void unregisterOrganizer();
}
diff --git a/cmds/idmap2/tests/ResultTests.cpp b/cmds/idmap2/tests/ResultTests.cpp
index cbced0ae32fb..f2f8854cec3a 100644
--- a/cmds/idmap2/tests/ResultTests.cpp
+++ b/cmds/idmap2/tests/ResultTests.cpp
@@ -260,7 +260,8 @@ TEST(ResultTests, CascadeError) {
struct NoCopyContainer {
uint32_t value; // NOLINT(misc-non-private-member-variables-in-classes)
- DISALLOW_COPY_AND_ASSIGN(NoCopyContainer);
+ NoCopyContainer(const NoCopyContainer&) = delete;
+ NoCopyContainer& operator=(const NoCopyContainer&) = delete;
};
Result<std::unique_ptr<NoCopyContainer>> CreateNoCopyContainer(bool succeed) {
diff --git a/cmds/statsd/src/condition/CombinationConditionTracker.cpp b/cmds/statsd/src/condition/CombinationConditionTracker.cpp
index 3b65f8225ee9..4574b2e34547 100644
--- a/cmds/statsd/src/condition/CombinationConditionTracker.cpp
+++ b/cmds/statsd/src/condition/CombinationConditionTracker.cpp
@@ -25,8 +25,9 @@ namespace statsd {
using std::unordered_map;
using std::vector;
-CombinationConditionTracker::CombinationConditionTracker(const int64_t& id, const int index)
- : ConditionTracker(id, index) {
+CombinationConditionTracker::CombinationConditionTracker(const int64_t& id, const int index,
+ const uint64_t protoHash)
+ : ConditionTracker(id, index, protoHash) {
VLOG("creating CombinationConditionTracker %lld", (long long)mConditionId);
}
@@ -122,6 +123,49 @@ bool CombinationConditionTracker::init(const vector<Predicate>& allConditionConf
return true;
}
+bool CombinationConditionTracker::onConfigUpdated(
+ const vector<Predicate>& allConditionProtos, const int index,
+ const vector<sp<ConditionTracker>>& allConditionTrackers,
+ const unordered_map<int64_t, int>& atomMatchingTrackerMap,
+ const unordered_map<int64_t, int>& conditionTrackerMap) {
+ ConditionTracker::onConfigUpdated(allConditionProtos, index, allConditionTrackers,
+ atomMatchingTrackerMap, conditionTrackerMap);
+ mTrackerIndex.clear();
+ mChildren.clear();
+ mUnSlicedChildren.clear();
+ mSlicedChildren.clear();
+ Predicate_Combination combinationCondition = allConditionProtos[mIndex].combination();
+
+ for (const int64_t child : combinationCondition.predicate()) {
+ const auto& it = conditionTrackerMap.find(child);
+
+ if (it == conditionTrackerMap.end()) {
+ ALOGW("Predicate %lld not found in the config", (long long)child);
+ return false;
+ }
+
+ int childIndex = it->second;
+ const sp<ConditionTracker>& childTracker = allConditionTrackers[childIndex];
+
+ // Ensures that the child's tracker indices are updated.
+ if (!childTracker->onConfigUpdated(allConditionProtos, childIndex, allConditionTrackers,
+ atomMatchingTrackerMap, conditionTrackerMap)) {
+ ALOGW("Child update failed %lld ", (long long)child);
+ return false;
+ }
+
+ if (allConditionTrackers[childIndex]->isSliced()) {
+ mSlicedChildren.push_back(childIndex);
+ } else {
+ mUnSlicedChildren.push_back(childIndex);
+ }
+ mChildren.push_back(childIndex);
+ mTrackerIndex.insert(childTracker->getAtomMatchingTrackerIndex().begin(),
+ childTracker->getAtomMatchingTrackerIndex().end());
+ }
+ return true;
+}
+
void CombinationConditionTracker::isConditionMet(
const ConditionKey& conditionParameters, const vector<sp<ConditionTracker>>& allConditions,
const bool isPartialLink,
diff --git a/cmds/statsd/src/condition/CombinationConditionTracker.h b/cmds/statsd/src/condition/CombinationConditionTracker.h
index a7fac3deaabe..672d61c82268 100644
--- a/cmds/statsd/src/condition/CombinationConditionTracker.h
+++ b/cmds/statsd/src/condition/CombinationConditionTracker.h
@@ -24,9 +24,9 @@ namespace android {
namespace os {
namespace statsd {
-class CombinationConditionTracker : public virtual ConditionTracker {
+class CombinationConditionTracker : public ConditionTracker {
public:
- CombinationConditionTracker(const int64_t& id, const int index);
+ CombinationConditionTracker(const int64_t& id, const int index, const uint64_t protoHash);
~CombinationConditionTracker();
@@ -35,6 +35,11 @@ public:
const std::unordered_map<int64_t, int>& conditionIdIndexMap, std::vector<bool>& stack,
std::vector<ConditionState>& conditionCache) override;
+ bool onConfigUpdated(const std::vector<Predicate>& allConditionProtos, const int index,
+ const std::vector<sp<ConditionTracker>>& allConditionTrackers,
+ const std::unordered_map<int64_t, int>& atomMatchingTrackerMap,
+ const std::unordered_map<int64_t, int>& conditionTrackerMap) override;
+
void evaluateCondition(const LogEvent& event,
const std::vector<MatchingState>& eventMatcherValues,
const std::vector<sp<ConditionTracker>>& mAllConditions,
@@ -102,6 +107,7 @@ private:
std::vector<int> mSlicedChildren;
std::vector<int> mUnSlicedChildren;
+ FRIEND_TEST(ConfigUpdateTest, TestUpdateConditions);
};
} // namespace statsd
diff --git a/cmds/statsd/src/condition/ConditionTracker.h b/cmds/statsd/src/condition/ConditionTracker.h
index 4e1253506be7..3bf4e636be89 100644
--- a/cmds/statsd/src/condition/ConditionTracker.h
+++ b/cmds/statsd/src/condition/ConditionTracker.h
@@ -31,18 +31,17 @@ namespace statsd {
class ConditionTracker : public virtual RefBase {
public:
- ConditionTracker(const int64_t& id, const int index)
+ ConditionTracker(const int64_t& id, const int index, const uint64_t protoHash)
: mConditionId(id),
mIndex(index),
mInitialized(false),
mTrackerIndex(),
mUnSlicedPartCondition(ConditionState::kUnknown),
- mSliced(false){};
+ mSliced(false),
+ mProtoHash(protoHash){};
virtual ~ConditionTracker(){};
- inline const int64_t& getId() { return mConditionId; }
-
// Initialize this ConditionTracker. This initialization is done recursively (DFS). It can also
// be done in the constructor, but we do it separately because (1) easy to return a bool to
// indicate whether the initialization is successful. (2) makes unit test easier.
@@ -50,7 +49,7 @@ public:
// fill the condition cache with the current condition.
// allConditionConfig: the list of all Predicate config from statsd_config.
// allConditionTrackers: the list of all ConditionTrackers (this is needed because we may also
- // need to call init() on children conditions)
+ // need to call init() on child conditions)
// conditionIdIndexMap: the mapping from condition id to its index.
// stack: a bit map to keep track which nodes have been visited on the stack in the recursion.
// conditionCache: tracks initial conditions of all ConditionTrackers. returns the
@@ -60,6 +59,26 @@ public:
const std::unordered_map<int64_t, int>& conditionIdIndexMap,
std::vector<bool>& stack, std::vector<ConditionState>& conditionCache) = 0;
+ // Update appropriate state on config updates. Primarily, all indices need to be updated.
+ // This predicate and all of its children are guaranteed to be preserved across the update.
+ // This function is recursive and will call onConfigUpdated on child conditions. It does not
+ // manage cycle detection since all preserved conditions should not have any cycles.
+ //
+ // allConditionProtos: the new predicates.
+ // index: the new index of this tracker in allConditionProtos and allConditionTrackers.
+ // allConditionTrackers: the list of all ConditionTrackers (this is needed because we may also
+ // need to call onConfigUpdated() on child conditions)
+ // [atomMatchingTrackerMap]: map of atom matcher id to index after the config update
+ // [conditionTrackerMap]: map of condition tracker id to index after the config update.
+ // returns whether or not the update is successful
+ virtual bool onConfigUpdated(const std::vector<Predicate>& allConditionProtos, const int index,
+ const std::vector<sp<ConditionTracker>>& allConditionTrackers,
+ const std::unordered_map<int64_t, int>& atomMatchingTrackerMap,
+ const std::unordered_map<int64_t, int>& conditionTrackerMap) {
+ mIndex = index;
+ return true;
+ }
+
// evaluate current condition given the new event.
// event: the new log event
// eventMatcherValues: the results of the AtomMatchingTrackers. AtomMatchingTrackers always
@@ -112,6 +131,10 @@ public:
return mConditionId;
}
+ inline uint64_t getProtoHash() const {
+ return mProtoHash;
+ }
+
virtual void getTrueSlicedDimensions(
const std::vector<sp<ConditionTracker>>& allConditions,
std::set<HashableDimensionKey>* dimensions) const = 0;
@@ -133,7 +156,7 @@ protected:
const int64_t mConditionId;
// the index of this condition in the manager's condition list.
- const int mIndex;
+ int mIndex;
// if it's properly initialized.
bool mInitialized;
@@ -151,6 +174,12 @@ protected:
ConditionState mUnSlicedPartCondition;
bool mSliced;
+
+ // Hash of the Predicate's proto bytes from StatsdConfig.
+ // Used to determine if the definition of this condition has changed across a config update.
+ const uint64_t mProtoHash;
+
+ FRIEND_TEST(ConfigUpdateTest, TestUpdateConditions);
};
} // namespace statsd
diff --git a/cmds/statsd/src/condition/SimpleConditionTracker.cpp b/cmds/statsd/src/condition/SimpleConditionTracker.cpp
index f45759b6a77e..1dcc8f96131a 100644
--- a/cmds/statsd/src/condition/SimpleConditionTracker.cpp
+++ b/cmds/statsd/src/condition/SimpleConditionTracker.cpp
@@ -27,54 +27,21 @@ namespace statsd {
using std::unordered_map;
SimpleConditionTracker::SimpleConditionTracker(
- const ConfigKey& key, const int64_t& id, const int index,
+ const ConfigKey& key, const int64_t& id, const uint64_t protoHash, const int index,
const SimplePredicate& simplePredicate,
- const unordered_map<int64_t, int>& trackerNameIndexMap)
- : ConditionTracker(id, index), mConfigKey(key), mContainANYPositionInInternalDimensions(false) {
+ const unordered_map<int64_t, int>& atomMatchingTrackerMap)
+ : ConditionTracker(id, index, protoHash),
+ mConfigKey(key),
+ mContainANYPositionInInternalDimensions(false) {
VLOG("creating SimpleConditionTracker %lld", (long long)mConditionId);
mCountNesting = simplePredicate.count_nesting();
- if (simplePredicate.has_start()) {
- auto pair = trackerNameIndexMap.find(simplePredicate.start());
- if (pair == trackerNameIndexMap.end()) {
- ALOGW("Start matcher %lld not found in the config", (long long)simplePredicate.start());
- return;
- }
- mStartLogMatcherIndex = pair->second;
- mTrackerIndex.insert(mStartLogMatcherIndex);
- } else {
- mStartLogMatcherIndex = -1;
- }
-
- if (simplePredicate.has_stop()) {
- auto pair = trackerNameIndexMap.find(simplePredicate.stop());
- if (pair == trackerNameIndexMap.end()) {
- ALOGW("Stop matcher %lld not found in the config", (long long)simplePredicate.stop());
- return;
- }
- mStopLogMatcherIndex = pair->second;
- mTrackerIndex.insert(mStopLogMatcherIndex);
- } else {
- mStopLogMatcherIndex = -1;
- }
-
- if (simplePredicate.has_stop_all()) {
- auto pair = trackerNameIndexMap.find(simplePredicate.stop_all());
- if (pair == trackerNameIndexMap.end()) {
- ALOGW("Stop all matcher %lld found in the config", (long long)simplePredicate.stop_all());
- return;
- }
- mStopAllLogMatcherIndex = pair->second;
- mTrackerIndex.insert(mStopAllLogMatcherIndex);
- } else {
- mStopAllLogMatcherIndex = -1;
- }
+ setMatcherIndices(simplePredicate, atomMatchingTrackerMap);
if (simplePredicate.has_dimensions()) {
translateFieldMatcher(simplePredicate.dimensions(), &mOutputDimensions);
if (mOutputDimensions.size() > 0) {
mSliced = true;
- mDimensionTag = mOutputDimensions[0].mMatcher.getTag();
}
mContainANYPositionInInternalDimensions = HasPositionANY(simplePredicate.dimensions());
}
@@ -106,6 +73,59 @@ bool SimpleConditionTracker::init(const vector<Predicate>& allConditionConfig,
return mInitialized;
}
+bool SimpleConditionTracker::onConfigUpdated(
+ const vector<Predicate>& allConditionProtos, const int index,
+ const vector<sp<ConditionTracker>>& allConditionTrackers,
+ const unordered_map<int64_t, int>& atomMatchingTrackerMap,
+ const unordered_map<int64_t, int>& conditionTrackerMap) {
+ ConditionTracker::onConfigUpdated(allConditionProtos, index, allConditionTrackers,
+ atomMatchingTrackerMap, conditionTrackerMap);
+ setMatcherIndices(allConditionProtos[index].simple_predicate(), atomMatchingTrackerMap);
+ return true;
+}
+
+void SimpleConditionTracker::setMatcherIndices(
+ const SimplePredicate& simplePredicate,
+ const unordered_map<int64_t, int>& atomMatchingTrackerMap) {
+ mTrackerIndex.clear();
+ if (simplePredicate.has_start()) {
+ auto pair = atomMatchingTrackerMap.find(simplePredicate.start());
+ if (pair == atomMatchingTrackerMap.end()) {
+ ALOGW("Start matcher %lld not found in the config", (long long)simplePredicate.start());
+ return;
+ }
+ mStartLogMatcherIndex = pair->second;
+ mTrackerIndex.insert(mStartLogMatcherIndex);
+ } else {
+ mStartLogMatcherIndex = -1;
+ }
+
+ if (simplePredicate.has_stop()) {
+ auto pair = atomMatchingTrackerMap.find(simplePredicate.stop());
+ if (pair == atomMatchingTrackerMap.end()) {
+ ALOGW("Stop matcher %lld not found in the config", (long long)simplePredicate.stop());
+ return;
+ }
+ mStopLogMatcherIndex = pair->second;
+ mTrackerIndex.insert(mStopLogMatcherIndex);
+ } else {
+ mStopLogMatcherIndex = -1;
+ }
+
+ if (simplePredicate.has_stop_all()) {
+ auto pair = atomMatchingTrackerMap.find(simplePredicate.stop_all());
+ if (pair == atomMatchingTrackerMap.end()) {
+ ALOGW("Stop all matcher %lld found in the config",
+ (long long)simplePredicate.stop_all());
+ return;
+ }
+ mStopAllLogMatcherIndex = pair->second;
+ mTrackerIndex.insert(mStopAllLogMatcherIndex);
+ } else {
+ mStopAllLogMatcherIndex = -1;
+ }
+}
+
void SimpleConditionTracker::dumpState() {
VLOG("%lld DUMP:", (long long)mConditionId);
for (const auto& pair : mSlicedConditionState) {
diff --git a/cmds/statsd/src/condition/SimpleConditionTracker.h b/cmds/statsd/src/condition/SimpleConditionTracker.h
index 1a9e35e38207..7a8b40108448 100644
--- a/cmds/statsd/src/condition/SimpleConditionTracker.h
+++ b/cmds/statsd/src/condition/SimpleConditionTracker.h
@@ -27,11 +27,11 @@ namespace android {
namespace os {
namespace statsd {
-class SimpleConditionTracker : public virtual ConditionTracker {
+class SimpleConditionTracker : public ConditionTracker {
public:
- SimpleConditionTracker(const ConfigKey& key, const int64_t& id, const int index,
- const SimplePredicate& simplePredicate,
- const std::unordered_map<int64_t, int>& trackerNameIndexMap);
+ SimpleConditionTracker(const ConfigKey& key, const int64_t& id, const uint64_t protoHash,
+ const int index, const SimplePredicate& simplePredicate,
+ const std::unordered_map<int64_t, int>& atomMatchingTrackerMap);
~SimpleConditionTracker();
@@ -40,6 +40,11 @@ public:
const std::unordered_map<int64_t, int>& conditionIdIndexMap, std::vector<bool>& stack,
std::vector<ConditionState>& conditionCache) override;
+ bool onConfigUpdated(const std::vector<Predicate>& allConditionProtos, const int index,
+ const std::vector<sp<ConditionTracker>>& allConditionTrackers,
+ const std::unordered_map<int64_t, int>& atomMatchingTrackerMap,
+ const std::unordered_map<int64_t, int>& conditionTrackerMap) override;
+
void evaluateCondition(const LogEvent& event,
const std::vector<MatchingState>& eventMatcherValues,
const std::vector<sp<ConditionTracker>>& mAllConditions,
@@ -112,10 +117,11 @@ private:
std::set<HashableDimensionKey> mLastChangedToTrueDimensions;
std::set<HashableDimensionKey> mLastChangedToFalseDimensions;
- int mDimensionTag;
-
std::map<HashableDimensionKey, int> mSlicedConditionState;
+ void setMatcherIndices(const SimplePredicate& predicate,
+ const std::unordered_map<int64_t, int>& logTrackerMap);
+
void handleStopAll(std::vector<ConditionState>& conditionCache,
std::vector<bool>& changedCache);
@@ -129,6 +135,7 @@ private:
FRIEND_TEST(SimpleConditionTrackerTest, TestSlicedCondition);
FRIEND_TEST(SimpleConditionTrackerTest, TestSlicedWithNoOutputDim);
FRIEND_TEST(SimpleConditionTrackerTest, TestStopAll);
+ FRIEND_TEST(ConfigUpdateTest, TestUpdateConditions);
};
} // namespace statsd
diff --git a/cmds/statsd/src/metrics/CountMetricProducer.cpp b/cmds/statsd/src/metrics/CountMetricProducer.cpp
index 573961276e5b..3dbb6ed47ff8 100644
--- a/cmds/statsd/src/metrics/CountMetricProducer.cpp
+++ b/cmds/statsd/src/metrics/CountMetricProducer.cpp
@@ -69,13 +69,14 @@ const int FIELD_ID_END_BUCKET_ELAPSED_MILLIS = 6;
CountMetricProducer::CountMetricProducer(
const ConfigKey& key, const CountMetric& metric, const int conditionIndex,
const vector<ConditionState>& initialConditionCache, const sp<ConditionWizard>& wizard,
- const int64_t timeBaseNs, const int64_t startTimeNs,
+ const uint64_t protoHash, const int64_t timeBaseNs, const int64_t startTimeNs,
const unordered_map<int, shared_ptr<Activation>>& eventActivationMap,
const unordered_map<int, vector<shared_ptr<Activation>>>& eventDeactivationMap,
const vector<int>& slicedStateAtoms,
const unordered_map<int, unordered_map<int, int64_t>>& stateGroupMap)
: MetricProducer(metric.id(), key, timeBaseNs, conditionIndex, initialConditionCache, wizard,
- eventActivationMap, eventDeactivationMap, slicedStateAtoms, stateGroupMap) {
+ protoHash, eventActivationMap, eventDeactivationMap, slicedStateAtoms,
+ stateGroupMap) {
if (metric.has_bucket()) {
mBucketSizeNs =
TimeUnitToBucketSizeInMillisGuardrailed(key.GetUid(), metric.bucket()) * 1000000;
diff --git a/cmds/statsd/src/metrics/CountMetricProducer.h b/cmds/statsd/src/metrics/CountMetricProducer.h
index f05fb061ccc1..6b2f2ca61ecc 100644
--- a/cmds/statsd/src/metrics/CountMetricProducer.h
+++ b/cmds/statsd/src/metrics/CountMetricProducer.h
@@ -44,7 +44,7 @@ public:
CountMetricProducer(
const ConfigKey& key, const CountMetric& countMetric, const int conditionIndex,
const vector<ConditionState>& initialConditionCache, const sp<ConditionWizard>& wizard,
- const int64_t timeBaseNs, const int64_t startTimeNs,
+ const uint64_t protoHash, const int64_t timeBaseNs, const int64_t startTimeNs,
const std::unordered_map<int, std::shared_ptr<Activation>>& eventActivationMap = {},
const std::unordered_map<int, std::vector<std::shared_ptr<Activation>>>&
eventDeactivationMap = {},
@@ -57,6 +57,10 @@ public:
const HashableDimensionKey& primaryKey, const FieldValue& oldState,
const FieldValue& newState) override;
+ MetricType getMetricType() const override {
+ return METRIC_TYPE_COUNT;
+ }
+
protected:
void onMatchedLogEventInternalLocked(
const size_t matcherIndex, const MetricDimensionKey& eventKey,
diff --git a/cmds/statsd/src/metrics/DurationMetricProducer.cpp b/cmds/statsd/src/metrics/DurationMetricProducer.cpp
index e9b043876d3d..3acafaa3560e 100644
--- a/cmds/statsd/src/metrics/DurationMetricProducer.cpp
+++ b/cmds/statsd/src/metrics/DurationMetricProducer.cpp
@@ -66,14 +66,15 @@ DurationMetricProducer::DurationMetricProducer(
const ConfigKey& key, const DurationMetric& metric, const int conditionIndex,
const vector<ConditionState>& initialConditionCache, const size_t startIndex,
const size_t stopIndex, const size_t stopAllIndex, const bool nesting,
- const sp<ConditionWizard>& wizard, const FieldMatcher& internalDimensions,
- const int64_t timeBaseNs, const int64_t startTimeNs,
+ 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,
const unordered_map<int, vector<shared_ptr<Activation>>>& eventDeactivationMap,
const vector<int>& slicedStateAtoms,
const unordered_map<int, unordered_map<int, int64_t>>& stateGroupMap)
: MetricProducer(metric.id(), key, timeBaseNs, conditionIndex, initialConditionCache, wizard,
- eventActivationMap, eventDeactivationMap, slicedStateAtoms, stateGroupMap),
+ protoHash, eventActivationMap, eventDeactivationMap, slicedStateAtoms,
+ stateGroupMap),
mAggregationType(metric.aggregation_type()),
mStartIndex(startIndex),
mStopIndex(stopIndex),
diff --git a/cmds/statsd/src/metrics/DurationMetricProducer.h b/cmds/statsd/src/metrics/DurationMetricProducer.h
index bfe1010c89de..3a94d9c775aa 100644
--- a/cmds/statsd/src/metrics/DurationMetricProducer.h
+++ b/cmds/statsd/src/metrics/DurationMetricProducer.h
@@ -42,8 +42,9 @@ public:
const ConfigKey& key, const DurationMetric& durationMetric, const int conditionIndex,
const vector<ConditionState>& initialConditionCache, const size_t startIndex,
const size_t stopIndex, const size_t stopAllIndex, const bool nesting,
- const sp<ConditionWizard>& wizard, const FieldMatcher& internalDimensions,
- const int64_t timeBaseNs, const int64_t startTimeNs,
+ 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 = {},
const unordered_map<int, vector<shared_ptr<Activation>>>& eventDeactivationMap = {},
const vector<int>& slicedStateAtoms = {},
@@ -58,6 +59,10 @@ public:
const HashableDimensionKey& primaryKey, const FieldValue& oldState,
const FieldValue& newState) override;
+ MetricType getMetricType() const override {
+ return METRIC_TYPE_DURATION;
+ }
+
protected:
void onMatchedLogEventLocked(const size_t matcherIndex, const LogEvent& event) override;
diff --git a/cmds/statsd/src/metrics/EventMetricProducer.cpp b/cmds/statsd/src/metrics/EventMetricProducer.cpp
index dc0036a687f3..dfe4559b05fb 100644
--- a/cmds/statsd/src/metrics/EventMetricProducer.cpp
+++ b/cmds/statsd/src/metrics/EventMetricProducer.cpp
@@ -55,13 +55,14 @@ const int FIELD_ID_ATOMS = 2;
EventMetricProducer::EventMetricProducer(
const ConfigKey& key, const EventMetric& metric, const int conditionIndex,
const vector<ConditionState>& initialConditionCache, const sp<ConditionWizard>& wizard,
- const int64_t startTimeNs,
+ const uint64_t protoHash, const int64_t startTimeNs,
const unordered_map<int, shared_ptr<Activation>>& eventActivationMap,
const unordered_map<int, vector<shared_ptr<Activation>>>& eventDeactivationMap,
const vector<int>& slicedStateAtoms,
const unordered_map<int, unordered_map<int, int64_t>>& stateGroupMap)
: MetricProducer(metric.id(), key, startTimeNs, conditionIndex, initialConditionCache, wizard,
- eventActivationMap, eventDeactivationMap, slicedStateAtoms, stateGroupMap) {
+ protoHash, eventActivationMap, eventDeactivationMap, slicedStateAtoms,
+ stateGroupMap) {
if (metric.links().size() > 0) {
for (const auto& link : metric.links()) {
Metric2Condition mc;
diff --git a/cmds/statsd/src/metrics/EventMetricProducer.h b/cmds/statsd/src/metrics/EventMetricProducer.h
index bfb2de36fad4..e828dddcbb18 100644
--- a/cmds/statsd/src/metrics/EventMetricProducer.h
+++ b/cmds/statsd/src/metrics/EventMetricProducer.h
@@ -36,7 +36,7 @@ public:
EventMetricProducer(
const ConfigKey& key, const EventMetric& eventMetric, const int conditionIndex,
const vector<ConditionState>& initialConditionCache, const sp<ConditionWizard>& wizard,
- const int64_t startTimeNs,
+ const uint64_t protoHash, const int64_t startTimeNs,
const std::unordered_map<int, std::shared_ptr<Activation>>& eventActivationMap = {},
const std::unordered_map<int, std::vector<std::shared_ptr<Activation>>>&
eventDeactivationMap = {},
@@ -45,6 +45,10 @@ public:
virtual ~EventMetricProducer();
+ MetricType getMetricType() const override {
+ return METRIC_TYPE_EVENT;
+ }
+
private:
void onMatchedLogEventInternalLocked(
const size_t matcherIndex, const MetricDimensionKey& eventKey,
diff --git a/cmds/statsd/src/metrics/GaugeMetricProducer.cpp b/cmds/statsd/src/metrics/GaugeMetricProducer.cpp
index 020f4b638f4d..9dda248a6d1f 100644
--- a/cmds/statsd/src/metrics/GaugeMetricProducer.cpp
+++ b/cmds/statsd/src/metrics/GaugeMetricProducer.cpp
@@ -71,13 +71,14 @@ const int FIELD_ID_END_BUCKET_ELAPSED_MILLIS = 8;
GaugeMetricProducer::GaugeMetricProducer(
const ConfigKey& key, const GaugeMetric& metric, const int conditionIndex,
const vector<ConditionState>& initialConditionCache, const sp<ConditionWizard>& wizard,
- const int whatMatcherIndex, const sp<EventMatcherWizard>& matcherWizard,
- const int pullTagId, const int triggerAtomId, const int atomId, const int64_t timeBaseNs,
- const int64_t startTimeNs, const sp<StatsPullerManager>& pullerManager,
+ const uint64_t protoHash, const int whatMatcherIndex,
+ const sp<EventMatcherWizard>& matcherWizard, const int pullTagId, const int triggerAtomId,
+ const int atomId, const int64_t timeBaseNs, const int64_t startTimeNs,
+ const sp<StatsPullerManager>& pullerManager,
const unordered_map<int, shared_ptr<Activation>>& eventActivationMap,
const unordered_map<int, vector<shared_ptr<Activation>>>& eventDeactivationMap)
: MetricProducer(metric.id(), key, timeBaseNs, conditionIndex, initialConditionCache, wizard,
- eventActivationMap, eventDeactivationMap, /*slicedStateAtoms=*/{},
+ protoHash, eventActivationMap, eventDeactivationMap, /*slicedStateAtoms=*/{},
/*stateGroupMap=*/{}),
mWhatMatcherIndex(whatMatcherIndex),
mEventMatcherWizard(matcherWizard),
diff --git a/cmds/statsd/src/metrics/GaugeMetricProducer.h b/cmds/statsd/src/metrics/GaugeMetricProducer.h
index ef3a24a43dcc..e933d4b19716 100644
--- a/cmds/statsd/src/metrics/GaugeMetricProducer.h
+++ b/cmds/statsd/src/metrics/GaugeMetricProducer.h
@@ -59,10 +59,11 @@ public:
GaugeMetricProducer(
const ConfigKey& key, const GaugeMetric& gaugeMetric, const int conditionIndex,
const vector<ConditionState>& initialConditionCache,
- const sp<ConditionWizard>& conditionWizard, const int whatMatcherIndex,
- const sp<EventMatcherWizard>& matcherWizard, const int pullTagId,
- const int triggerAtomId, const int atomId, const int64_t timeBaseNs,
- const int64_t startTimeNs, const sp<StatsPullerManager>& pullerManager,
+ const sp<ConditionWizard>& conditionWizard, const uint64_t protoHash,
+ const int whatMatcherIndex, const sp<EventMatcherWizard>& matcherWizard,
+ const int pullTagId, const int triggerAtomId, const int atomId,
+ const int64_t timeBaseNs, const int64_t startTimeNs,
+ const sp<StatsPullerManager>& pullerManager,
const std::unordered_map<int, std::shared_ptr<Activation>>& eventActivationMap = {},
const std::unordered_map<int, std::vector<std::shared_ptr<Activation>>>&
eventDeactivationMap = {});
@@ -96,6 +97,10 @@ public:
}
};
+ MetricType getMetricType() const override {
+ return METRIC_TYPE_GAUGE;
+ }
+
protected:
void onMatchedLogEventInternalLocked(
const size_t matcherIndex, const MetricDimensionKey& eventKey,
diff --git a/cmds/statsd/src/metrics/MetricProducer.cpp b/cmds/statsd/src/metrics/MetricProducer.cpp
index fe143e496373..c1c1d20f00e2 100644
--- a/cmds/statsd/src/metrics/MetricProducer.cpp
+++ b/cmds/statsd/src/metrics/MetricProducer.cpp
@@ -46,13 +46,14 @@ const int FIELD_ID_ACTIVE_EVENT_ACTIVATION_STATE = 3;
MetricProducer::MetricProducer(
const int64_t& metricId, const ConfigKey& key, const int64_t timeBaseNs,
const int conditionIndex, const vector<ConditionState>& initialConditionCache,
- const sp<ConditionWizard>& wizard,
+ const sp<ConditionWizard>& wizard, const uint64_t protoHash,
const std::unordered_map<int, std::shared_ptr<Activation>>& eventActivationMap,
const std::unordered_map<int, std::vector<std::shared_ptr<Activation>>>&
eventDeactivationMap,
const vector<int>& slicedStateAtoms,
const unordered_map<int, unordered_map<int, int64_t>>& stateGroupMap)
: mMetricId(metricId),
+ mProtoHash(protoHash),
mConfigKey(key),
mTimeBaseNs(timeBaseNs),
mCurrentBucketStartTimeNs(timeBaseNs),
diff --git a/cmds/statsd/src/metrics/MetricProducer.h b/cmds/statsd/src/metrics/MetricProducer.h
index be4cd6724bb1..bb590aac54d6 100644
--- a/cmds/statsd/src/metrics/MetricProducer.h
+++ b/cmds/statsd/src/metrics/MetricProducer.h
@@ -87,6 +87,13 @@ enum BucketDropReason {
NO_DATA = 9
};
+enum MetricType {
+ METRIC_TYPE_EVENT = 1,
+ METRIC_TYPE_COUNT = 2,
+ METRIC_TYPE_DURATION = 3,
+ METRIC_TYPE_GAUGE = 4,
+ METRIC_TYPE_VALUE = 5,
+};
struct Activation {
Activation(const ActivationType& activationType, const int64_t ttlNs)
: ttl_ns(ttlNs),
@@ -130,7 +137,7 @@ class MetricProducer : public virtual android::RefBase, public virtual StateList
public:
MetricProducer(const int64_t& metricId, const ConfigKey& key, const int64_t timeBaseNs,
const int conditionIndex, const vector<ConditionState>& initialConditionCache,
- const sp<ConditionWizard>& wizard,
+ const sp<ConditionWizard>& wizard, const uint64_t protoHash,
const std::unordered_map<int, std::shared_ptr<Activation>>& eventActivationMap,
const std::unordered_map<int, std::vector<std::shared_ptr<Activation>>>&
eventDeactivationMap,
@@ -259,10 +266,16 @@ public:
int64_t currentTimeNs, const DumpReportReason reason, ProtoOutputStream* proto);
// Start: getters/setters
- inline const int64_t& getMetricId() const {
+ inline int64_t getMetricId() const {
return mMetricId;
}
+ inline uint64_t getProtoHash() const {
+ return mProtoHash;
+ }
+
+ virtual MetricType getMetricType() const = 0;
+
// For test only.
inline int64_t getCurrentBucketNum() const {
return mCurrentBucketNum;
@@ -400,6 +413,10 @@ protected:
const int64_t mMetricId;
+ // Hash of the Metric's proto bytes from StatsdConfig, including any activations.
+ // Used to determine if the definition of this metric has changed across a config update.
+ const uint64_t mProtoHash;
+
const ConfigKey mConfigKey;
// The time when this metric producer was first created. The end time for the current bucket
diff --git a/cmds/statsd/src/metrics/MetricsManager.cpp b/cmds/statsd/src/metrics/MetricsManager.cpp
index 5a520326116a..39806890c42d 100644
--- a/cmds/statsd/src/metrics/MetricsManager.cpp
+++ b/cmds/statsd/src/metrics/MetricsManager.cpp
@@ -80,11 +80,11 @@ MetricsManager::MetricsManager(const ConfigKey& key, const StatsdConfig& config,
mConfigValid = initStatsdConfig(
key, config, uidMap, pullerManager, anomalyAlarmMonitor, periodicAlarmMonitor,
timeBaseNs, currentTimeNs, mTagIds, mAllAtomMatchingTrackers, mAtomMatchingTrackerMap,
- mAllConditionTrackers, mAllMetricProducers, mAllAnomalyTrackers,
- mAllPeriodicAlarmTrackers, mConditionToMetricMap, mTrackerToMetricMap,
- mTrackerToConditionMap, mActivationAtomTrackerToMetricMap,
+ mAllConditionTrackers, mConditionTrackerMap, mAllMetricProducers, mMetricProducerMap,
+ mAllAnomalyTrackers, mAllPeriodicAlarmTrackers, mConditionToMetricMap,
+ mTrackerToMetricMap, mTrackerToConditionMap, mActivationAtomTrackerToMetricMap,
mDeactivationAtomTrackerToMetricMap, mAlertTrackerMap, mMetricIndexesWithActivation,
- mNoReportMetricIds);
+ mStateProtoHashes, mNoReportMetricIds);
mHashStringsInReport = config.hash_strings_in_metric_report();
mVersionStringsInReport = config.version_strings_in_metric_report();
@@ -204,13 +204,20 @@ bool MetricsManager::updateConfig(const StatsdConfig& config, const int64_t time
const sp<AlarmMonitor>& periodicAlarmMonitor) {
vector<sp<AtomMatchingTracker>> newAtomMatchingTrackers;
unordered_map<int64_t, int> newAtomMatchingTrackerMap;
+ vector<sp<ConditionTracker>> newConditionTrackers;
+ unordered_map<int64_t, int> newConditionTrackerMap;
mTagIds.clear();
+ mTrackerToConditionMap.clear();
mConfigValid = updateStatsdConfig(
mConfigKey, config, mUidMap, mPullerManager, anomalyAlarmMonitor, periodicAlarmMonitor,
- timeBaseNs, currentTimeNs, mAllAtomMatchingTrackers, mAtomMatchingTrackerMap, mTagIds,
- newAtomMatchingTrackers, newAtomMatchingTrackerMap);
+ timeBaseNs, currentTimeNs, mAllAtomMatchingTrackers, mAtomMatchingTrackerMap,
+ mAllConditionTrackers, mConditionTrackerMap, mTagIds, newAtomMatchingTrackers,
+ newAtomMatchingTrackerMap, newConditionTrackers, newConditionTrackerMap,
+ mTrackerToConditionMap);
mAllAtomMatchingTrackers = newAtomMatchingTrackers;
mAtomMatchingTrackerMap = newAtomMatchingTrackerMap;
+ mAllConditionTrackers = newConditionTrackers;
+ mConditionTrackerMap = newConditionTrackerMap;
return mConfigValid;
}
diff --git a/cmds/statsd/src/metrics/MetricsManager.h b/cmds/statsd/src/metrics/MetricsManager.h
index 6f4b2d7e9fa4..27f3d51b07ce 100644
--- a/cmds/statsd/src/metrics/MetricsManager.h
+++ b/cmds/statsd/src/metrics/MetricsManager.h
@@ -242,9 +242,15 @@ private:
// To make updating configs faster, we map the id of a AtomMatchingTracker, MetricProducer, and
// ConditionTracker to its index in the corresponding vector.
- // Maps the id of an atom matcher to its index in mAllAtomMatchingTrackers.
+ // Maps the id of an atom matching tracker to its index in mAllAtomMatchingTrackers.
std::unordered_map<int64_t, int> mAtomMatchingTrackerMap;
+ // Maps the id of a condition tracker to its index in mAllConditionTrackers.
+ std::unordered_map<int64_t, int> mConditionTrackerMap;
+
+ // Maps the id of a metric producer to its index in mAllMetricProducers.
+ std::unordered_map<int64_t, int> mMetricProducerMap;
+
// To make the log processing more efficient, we want to do as much filtering as possible
// before we go into individual trackers and conditions to match.
@@ -292,6 +298,9 @@ private:
// The config is always active if any metric in the config does not have an activation signal.
bool mIsAlwaysActive;
+ // Hashes of the States used in this config, keyed by the state id, used in config updates.
+ std::map<int64_t, uint64_t> mStateProtoHashes;
+
FRIEND_TEST(WakelockDurationE2eTest, TestAggregatedPredicateDimensions);
FRIEND_TEST(MetricConditionLinkE2eTest, TestMultiplePredicatesAndLinks);
FRIEND_TEST(AttributionE2eTest, TestAttributionMatchAndSliceByFirstUid);
diff --git a/cmds/statsd/src/metrics/ValueMetricProducer.cpp b/cmds/statsd/src/metrics/ValueMetricProducer.cpp
index 9b684f1248c5..39ae9a47f2bf 100644
--- a/cmds/statsd/src/metrics/ValueMetricProducer.cpp
+++ b/cmds/statsd/src/metrics/ValueMetricProducer.cpp
@@ -79,16 +79,17 @@ const Value ZERO_DOUBLE((int64_t)0);
ValueMetricProducer::ValueMetricProducer(
const ConfigKey& key, const ValueMetric& metric, const int conditionIndex,
const vector<ConditionState>& initialConditionCache,
- const sp<ConditionWizard>& conditionWizard, const int whatMatcherIndex,
- const sp<EventMatcherWizard>& matcherWizard, const int pullTagId, const int64_t timeBaseNs,
- const int64_t startTimeNs, const sp<StatsPullerManager>& pullerManager,
+ const sp<ConditionWizard>& conditionWizard, const uint64_t protoHash,
+ const int whatMatcherIndex, const sp<EventMatcherWizard>& matcherWizard,
+ const int pullTagId, const int64_t timeBaseNs, const int64_t startTimeNs,
+ const sp<StatsPullerManager>& pullerManager,
const unordered_map<int, shared_ptr<Activation>>& eventActivationMap,
const unordered_map<int, vector<shared_ptr<Activation>>>& eventDeactivationMap,
const vector<int>& slicedStateAtoms,
const unordered_map<int, unordered_map<int, int64_t>>& stateGroupMap)
: MetricProducer(metric.id(), key, timeBaseNs, conditionIndex, initialConditionCache,
- conditionWizard, eventActivationMap, eventDeactivationMap, slicedStateAtoms,
- stateGroupMap),
+ conditionWizard, protoHash, eventActivationMap, eventDeactivationMap,
+ slicedStateAtoms, stateGroupMap),
mWhatMatcherIndex(whatMatcherIndex),
mEventMatcherWizard(matcherWizard),
mPullerManager(pullerManager),
@@ -411,7 +412,7 @@ void ValueMetricProducer::skipCurrentBucket(const int64_t dropTimeNs,
void ValueMetricProducer::resetBase() {
for (auto& slice : mCurrentBaseInfo) {
- for (auto& baseInfo : slice.second) {
+ for (auto& baseInfo : slice.second.baseInfos) {
baseInfo.hasBase = false;
}
}
@@ -623,7 +624,7 @@ void ValueMetricProducer::accumulateEvents(const std::vector<std::shared_ptr<Log
mMatchedMetricDimensionKeys.find(whatKey) != mMatchedMetricDimensionKeys.end();
if (!presentInPulledData && whatKey.contains(mStateChangePrimaryKey.second)) {
auto it = mCurrentBaseInfo.find(whatKey);
- for (auto& baseInfo : it->second) {
+ for (auto& baseInfo : it->second.baseInfos) {
baseInfo.hasBase = false;
}
}
@@ -652,7 +653,7 @@ void ValueMetricProducer::dumpStatesLocked(FILE* out, bool verbose) const {
(unsigned long)mCurrentSlicedBucket.size());
if (verbose) {
for (const auto& it : mCurrentSlicedBucket) {
- for (const auto& interval : it.second) {
+ for (const auto& interval : it.second.intervals) {
fprintf(out, "\t(what)%s\t(states)%s (value)%s\n",
it.first.getDimensionKeyInWhat().toString().c_str(),
it.first.getStateValuesKey().toString().c_str(),
@@ -788,23 +789,23 @@ void ValueMetricProducer::onMatchedLogEventInternalLocked(
return;
}
- vector<BaseInfo>& baseInfos = mCurrentBaseInfo[whatKey];
+ DimensionsInWhatInfo& dimensionsInWhatInfo = mCurrentBaseInfo[whatKey];
+ vector<BaseInfo>& baseInfos = dimensionsInWhatInfo.baseInfos;
if (baseInfos.size() < mFieldMatchers.size()) {
VLOG("Resizing number of intervals to %d", (int)mFieldMatchers.size());
baseInfos.resize(mFieldMatchers.size());
}
- for (BaseInfo& baseInfo : baseInfos) {
- if (!baseInfo.hasCurrentState) {
- baseInfo.currentState = getUnknownStateKey();
- baseInfo.hasCurrentState = true;
- }
+ if (!dimensionsInWhatInfo.hasCurrentState) {
+ dimensionsInWhatInfo.currentState = getUnknownStateKey();
+ dimensionsInWhatInfo.hasCurrentState = true;
}
// We need to get the intervals stored with the previous state key so we can
// close these value intervals.
- const auto oldStateKey = baseInfos[0].currentState;
- vector<Interval>& intervals = mCurrentSlicedBucket[MetricDimensionKey(whatKey, oldStateKey)];
+ const auto oldStateKey = dimensionsInWhatInfo.currentState;
+ vector<Interval>& intervals =
+ mCurrentSlicedBucket[MetricDimensionKey(whatKey, oldStateKey)].intervals;
if (intervals.size() < mFieldMatchers.size()) {
VLOG("Resizing number of intervals to %d", (int)mFieldMatchers.size());
intervals.resize(mFieldMatchers.size());
@@ -818,14 +819,14 @@ void ValueMetricProducer::onMatchedLogEventInternalLocked(
// Discussion here: http://ag/6124370.
bool useAnomalyDetection = true;
+ dimensionsInWhatInfo.hasCurrentState = true;
+ dimensionsInWhatInfo.currentState = stateKey;
for (int i = 0; i < (int)mFieldMatchers.size(); i++) {
const Matcher& matcher = mFieldMatchers[i];
BaseInfo& baseInfo = baseInfos[i];
Interval& interval = intervals[i];
interval.valueIndex = i;
Value value;
- baseInfo.hasCurrentState = true;
- baseInfo.currentState = stateKey;
if (!getDoubleOrLong(event, matcher, value)) {
VLOG("Failed to get value %d from event %s", i, event.ToString().c_str());
StatsdStats::getInstance().noteBadValueType(mMetricId);
@@ -990,7 +991,7 @@ void ValueMetricProducer::flushCurrentBucketLocked(const int64_t& eventTimeNs,
bool bucketHasData = false;
// The current bucket is large enough to keep.
for (const auto& slice : mCurrentSlicedBucket) {
- ValueBucket bucket = buildPartialBucket(bucketEndTime, slice.second);
+ PastValueBucket bucket = buildPartialBucket(bucketEndTime, slice.second.intervals);
bucket.mConditionTrueNs = conditionTrueDuration;
// it will auto create new vector of ValuebucketInfo if the key is not found.
if (bucket.valueIndex.size() > 0) {
@@ -1030,9 +1031,9 @@ void ValueMetricProducer::flushCurrentBucketLocked(const int64_t& eventTimeNs,
mCurrentBucketNum += numBucketsForward;
}
-ValueBucket ValueMetricProducer::buildPartialBucket(int64_t bucketEndTime,
- const std::vector<Interval>& intervals) {
- ValueBucket bucket;
+PastValueBucket ValueMetricProducer::buildPartialBucket(int64_t bucketEndTime,
+ const std::vector<Interval>& intervals) {
+ PastValueBucket bucket;
bucket.mBucketStartNs = mCurrentBucketStartTimeNs;
bucket.mBucketEndNs = bucketEndTime;
for (const auto& interval : intervals) {
@@ -1059,7 +1060,7 @@ void ValueMetricProducer::initCurrentSlicedBucket(int64_t nextBucketStartTimeNs)
// Cleanup data structure to aggregate values.
for (auto it = mCurrentSlicedBucket.begin(); it != mCurrentSlicedBucket.end();) {
bool obsolete = true;
- for (auto& interval : it->second) {
+ for (auto& interval : it->second.intervals) {
interval.hasValue = false;
interval.sampleSize = 0;
if (interval.seenNewData) {
@@ -1107,7 +1108,7 @@ void ValueMetricProducer::appendToFullBucket(const bool isFullBucketReached) {
continue;
}
// TODO: fix this when anomaly can accept double values
- auto& interval = slice.second[0];
+ auto& interval = slice.second.intervals[0];
if (interval.hasValue) {
mCurrentFullBucket[slice.first] += interval.value.long_value;
}
@@ -1126,7 +1127,7 @@ void ValueMetricProducer::appendToFullBucket(const bool isFullBucketReached) {
for (auto& tracker : mAnomalyTrackers) {
if (tracker != nullptr) {
// TODO: fix this when anomaly can accept double values
- auto& interval = slice.second[0];
+ auto& interval = slice.second.intervals[0];
if (interval.hasValue) {
tracker->addPastBucket(slice.first, interval.value.long_value,
mCurrentBucketNum);
@@ -1139,7 +1140,7 @@ void ValueMetricProducer::appendToFullBucket(const bool isFullBucketReached) {
// Accumulate partial bucket.
for (const auto& slice : mCurrentSlicedBucket) {
// TODO: fix this when anomaly can accept double values
- auto& interval = slice.second[0];
+ auto& interval = slice.second.intervals[0];
if (interval.hasValue) {
mCurrentFullBucket[slice.first] += interval.value.long_value;
}
diff --git a/cmds/statsd/src/metrics/ValueMetricProducer.h b/cmds/statsd/src/metrics/ValueMetricProducer.h
index e72002e88533..4b2599bdb517 100644
--- a/cmds/statsd/src/metrics/ValueMetricProducer.h
+++ b/cmds/statsd/src/metrics/ValueMetricProducer.h
@@ -31,7 +31,7 @@ namespace android {
namespace os {
namespace statsd {
-struct ValueBucket {
+struct PastValueBucket {
int64_t mBucketStartNs;
int64_t mBucketEndNs;
std::vector<int> valueIndex;
@@ -41,7 +41,6 @@ struct ValueBucket {
int64_t mConditionTrueNs;
};
-
// Aggregates values within buckets.
//
// There are different events that might complete a bucket
@@ -53,9 +52,9 @@ public:
ValueMetricProducer(
const ConfigKey& key, const ValueMetric& valueMetric, const int conditionIndex,
const vector<ConditionState>& initialConditionCache,
- const sp<ConditionWizard>& conditionWizard, const int whatMatcherIndex,
- const sp<EventMatcherWizard>& matcherWizard, const int pullTagId,
- const int64_t timeBaseNs, const int64_t startTimeNs,
+ const sp<ConditionWizard>& conditionWizard, const uint64_t protoHash,
+ const int whatMatcherIndex, const sp<EventMatcherWizard>& matcherWizard,
+ const int pullTagId, const int64_t timeBaseNs, const int64_t startTimeNs,
const sp<StatsPullerManager>& pullerManager,
const std::unordered_map<int, std::shared_ptr<Activation>>& eventActivationMap = {},
const std::unordered_map<int, std::vector<std::shared_ptr<Activation>>>&
@@ -93,6 +92,10 @@ public:
void onStateChanged(int64_t eventTimeNs, int32_t atomId, const HashableDimensionKey& primaryKey,
const FieldValue& oldState, const FieldValue& newState) override;
+ MetricType getMetricType() const override {
+ return METRIC_TYPE_VALUE;
+ }
+
protected:
void onMatchedLogEventInternalLocked(
const size_t matcherIndex, const MetricDimensionKey& eventKey,
@@ -173,7 +176,7 @@ private:
// if this is pulled metric
const bool mIsPulled;
- // internal state of an ongoing aggregation bucket.
+ // Tracks the value information of one value field.
typedef struct {
// Index in multi value aggregation.
int valueIndex;
@@ -188,25 +191,40 @@ private:
bool seenNewData = false;
} Interval;
+ // Internal state of an ongoing aggregation bucket.
+ typedef struct CurrentValueBucket {
+ // Value information for each value field of the metric.
+ std::vector<Interval> intervals;
+ } CurrentValueBucket;
+
+ // Holds base information for diffing values from one value field.
typedef struct {
// Holds current base value of the dimension. Take diff and update if necessary.
Value base;
// Whether there is a base to diff to.
bool hasBase;
+ } BaseInfo;
+
+ // State key and base information for a specific DimensionsInWhat key.
+ typedef struct {
+ std::vector<BaseInfo> baseInfos;
// Last seen state value(s).
HashableDimensionKey currentState;
// Whether this dimensions in what key has a current state key.
bool hasCurrentState;
- } BaseInfo;
+ } DimensionsInWhatInfo;
- std::unordered_map<MetricDimensionKey, std::vector<Interval>> mCurrentSlicedBucket;
+ // Tracks the internal state in the ongoing aggregation bucket for each DimensionsInWhat
+ // key and StateValuesKey pair.
+ std::unordered_map<MetricDimensionKey, CurrentValueBucket> mCurrentSlicedBucket;
- std::unordered_map<HashableDimensionKey, std::vector<BaseInfo>> mCurrentBaseInfo;
+ // Tracks current state key and base information for each DimensionsInWhat key.
+ std::unordered_map<HashableDimensionKey, DimensionsInWhatInfo> mCurrentBaseInfo;
std::unordered_map<MetricDimensionKey, int64_t> mCurrentFullBucket;
// Save the past buckets and we can clear when the StatsLogReport is dumped.
- std::unordered_map<MetricDimensionKey, std::vector<ValueBucket>> mPastBuckets;
+ std::unordered_map<MetricDimensionKey, std::vector<PastValueBucket>> mPastBuckets;
const int64_t mMinBucketSizeNs;
@@ -224,8 +242,8 @@ private:
void accumulateEvents(const std::vector<std::shared_ptr<LogEvent>>& allData,
int64_t originalPullTimeNs, int64_t eventElapsedTimeNs);
- ValueBucket buildPartialBucket(int64_t bucketEndTime,
- const std::vector<Interval>& intervals);
+ PastValueBucket buildPartialBucket(int64_t bucketEndTime,
+ const std::vector<Interval>& intervals);
void initCurrentSlicedBucket(int64_t nextBucketStartTimeNs);
@@ -234,7 +252,7 @@ private:
// Reset diff base and mHasGlobalBase
void resetBase();
- static const size_t kBucketSize = sizeof(ValueBucket{});
+ static const size_t kBucketSize = sizeof(PastValueBucket{});
const size_t mDimensionSoftLimit;
diff --git a/cmds/statsd/src/metrics/parsing_utils/config_update_utils.cpp b/cmds/statsd/src/metrics/parsing_utils/config_update_utils.cpp
index 0983dc0b2c83..bd60b6bfcb8e 100644
--- a/cmds/statsd/src/metrics/parsing_utils/config_update_utils.cpp
+++ b/cmds/statsd/src/metrics/parsing_utils/config_update_utils.cpp
@@ -15,6 +15,7 @@
*/
#define DEBUG false // STOPSHIP if true
+#include "Log.h"
#include "config_update_utils.h"
@@ -44,7 +45,7 @@ bool determineMatcherUpdateStatus(const StatsdConfig& config, const int matcherI
// Check if new matcher.
const auto& oldAtomMatchingTrackerIt = oldAtomMatchingTrackerMap.find(id);
if (oldAtomMatchingTrackerIt == oldAtomMatchingTrackerMap.end()) {
- matchersToUpdate[matcherIdx] = UPDATE_REPLACE;
+ matchersToUpdate[matcherIdx] = UPDATE_NEW;
return true;
}
@@ -103,11 +104,13 @@ bool determineMatcherUpdateStatus(const StatsdConfig& config, const int matcherI
return true;
}
-bool updateAtomTrackers(const StatsdConfig& config, const sp<UidMap>& uidMap,
- const unordered_map<int64_t, int>& oldAtomMatchingTrackerMap,
- const vector<sp<AtomMatchingTracker>>& oldAtomMatchingTrackers,
- set<int>& allTagIds, unordered_map<int64_t, int>& newAtomMatchingTrackerMap,
- vector<sp<AtomMatchingTracker>>& newAtomMatchingTrackers) {
+bool updateAtomMatchingTrackers(const StatsdConfig& config, const sp<UidMap>& uidMap,
+ const unordered_map<int64_t, int>& oldAtomMatchingTrackerMap,
+ const vector<sp<AtomMatchingTracker>>& oldAtomMatchingTrackers,
+ set<int>& allTagIds,
+ unordered_map<int64_t, int>& newAtomMatchingTrackerMap,
+ vector<sp<AtomMatchingTracker>>& newAtomMatchingTrackers,
+ set<int64_t>& replacedMatchers) {
const int atomMatcherCount = config.atom_matcher_size();
vector<AtomMatcher> matcherProtos;
@@ -157,7 +160,10 @@ bool updateAtomTrackers(const StatsdConfig& config, const sp<UidMap>& uidMap,
newAtomMatchingTrackers.push_back(tracker);
break;
}
- case UPDATE_REPLACE: {
+ case UPDATE_REPLACE:
+ replacedMatchers.insert(id);
+ [[fallthrough]]; // Intentionally fallthrough to create the new matcher.
+ case UPDATE_NEW: {
sp<AtomMatchingTracker> tracker = createAtomMatchingTracker(matcher, i, uidMap);
if (tracker == nullptr) {
return false;
@@ -187,6 +193,207 @@ bool updateAtomTrackers(const StatsdConfig& config, const sp<UidMap>& uidMap,
return true;
}
+// Recursive function to determine if a condition needs to be updated. Populates conditionsToUpdate.
+// Returns whether the function was successful or not.
+bool determineConditionUpdateStatus(const StatsdConfig& config, const int conditionIdx,
+ const unordered_map<int64_t, int>& oldConditionTrackerMap,
+ const vector<sp<ConditionTracker>>& oldConditionTrackers,
+ const unordered_map<int64_t, int>& newConditionTrackerMap,
+ const set<int64_t>& replacedMatchers,
+ vector<UpdateStatus>& conditionsToUpdate,
+ vector<bool>& cycleTracker) {
+ // Have already examined this condition.
+ if (conditionsToUpdate[conditionIdx] != UPDATE_UNKNOWN) {
+ return true;
+ }
+
+ const Predicate& predicate = config.predicate(conditionIdx);
+ int64_t id = predicate.id();
+ // Check if new condition.
+ const auto& oldConditionTrackerIt = oldConditionTrackerMap.find(id);
+ if (oldConditionTrackerIt == oldConditionTrackerMap.end()) {
+ conditionsToUpdate[conditionIdx] = UPDATE_NEW;
+ return true;
+ }
+
+ // This is an existing condition. Check if it has changed.
+ string serializedCondition;
+ if (!predicate.SerializeToString(&serializedCondition)) {
+ ALOGE("Unable to serialize matcher %lld", (long long)id);
+ return false;
+ }
+ uint64_t newProtoHash = Hash64(serializedCondition);
+ if (newProtoHash != oldConditionTrackers[oldConditionTrackerIt->second]->getProtoHash()) {
+ conditionsToUpdate[conditionIdx] = UPDATE_REPLACE;
+ return true;
+ }
+
+ switch (predicate.contents_case()) {
+ case Predicate::ContentsCase::kSimplePredicate: {
+ // Need to check if any of the underlying matchers changed.
+ const SimplePredicate& simplePredicate = predicate.simple_predicate();
+ if (simplePredicate.has_start()) {
+ if (replacedMatchers.find(simplePredicate.start()) != replacedMatchers.end()) {
+ conditionsToUpdate[conditionIdx] = UPDATE_REPLACE;
+ return true;
+ }
+ }
+ if (simplePredicate.has_stop()) {
+ if (replacedMatchers.find(simplePredicate.stop()) != replacedMatchers.end()) {
+ conditionsToUpdate[conditionIdx] = UPDATE_REPLACE;
+ return true;
+ }
+ }
+ if (simplePredicate.has_stop_all()) {
+ if (replacedMatchers.find(simplePredicate.stop_all()) != replacedMatchers.end()) {
+ conditionsToUpdate[conditionIdx] = UPDATE_REPLACE;
+ return true;
+ }
+ }
+ conditionsToUpdate[conditionIdx] = UPDATE_PRESERVE;
+ return true;
+ }
+ case Predicate::ContentsCase::kCombination: {
+ // Need to recurse on the children to see if any of the child predicates changed.
+ cycleTracker[conditionIdx] = true;
+ UpdateStatus status = UPDATE_PRESERVE;
+ for (const int64_t childPredicateId : predicate.combination().predicate()) {
+ const auto& childIt = newConditionTrackerMap.find(childPredicateId);
+ if (childIt == newConditionTrackerMap.end()) {
+ ALOGW("Predicate %lld not found in the config", (long long)childPredicateId);
+ return false;
+ }
+ const int childIdx = childIt->second;
+ if (cycleTracker[childIdx]) {
+ ALOGE("Cycle detected in predicate config");
+ return false;
+ }
+ if (!determineConditionUpdateStatus(config, childIdx, oldConditionTrackerMap,
+ oldConditionTrackers, newConditionTrackerMap,
+ replacedMatchers, conditionsToUpdate,
+ cycleTracker)) {
+ return false;
+ }
+
+ if (conditionsToUpdate[childIdx] == UPDATE_REPLACE) {
+ status = UPDATE_REPLACE;
+ break;
+ }
+ }
+ conditionsToUpdate[conditionIdx] = status;
+ cycleTracker[conditionIdx] = false;
+ return true;
+ }
+ default: {
+ ALOGE("Predicate \"%lld\" malformed", (long long)id);
+ return false;
+ }
+ }
+
+ return true;
+}
+
+bool updateConditions(const ConfigKey& key, const StatsdConfig& config,
+ const unordered_map<int64_t, int>& atomMatchingTrackerMap,
+ const set<int64_t>& replacedMatchers,
+ const unordered_map<int64_t, int>& oldConditionTrackerMap,
+ const vector<sp<ConditionTracker>>& oldConditionTrackers,
+ unordered_map<int64_t, int>& newConditionTrackerMap,
+ vector<sp<ConditionTracker>>& newConditionTrackers,
+ unordered_map<int, vector<int>>& trackerToConditionMap,
+ vector<ConditionState>& conditionCache, set<int64_t>& replacedConditions) {
+ vector<Predicate> conditionProtos;
+ const int conditionTrackerCount = config.predicate_size();
+ conditionProtos.reserve(conditionTrackerCount);
+ newConditionTrackers.reserve(conditionTrackerCount);
+ conditionCache.assign(conditionTrackerCount, ConditionState::kNotEvaluated);
+
+ for (int i = 0; i < conditionTrackerCount; i++) {
+ const Predicate& condition = config.predicate(i);
+ if (newConditionTrackerMap.find(condition.id()) != newConditionTrackerMap.end()) {
+ ALOGE("Duplicate Predicate found!");
+ return false;
+ }
+ newConditionTrackerMap[condition.id()] = i;
+ conditionProtos.push_back(condition);
+ }
+
+ vector<UpdateStatus> conditionsToUpdate(conditionTrackerCount, UPDATE_UNKNOWN);
+ vector<bool> cycleTracker(conditionTrackerCount, false);
+ for (int i = 0; i < conditionTrackerCount; i++) {
+ if (!determineConditionUpdateStatus(config, i, oldConditionTrackerMap, oldConditionTrackers,
+ newConditionTrackerMap, replacedMatchers,
+ conditionsToUpdate, cycleTracker)) {
+ return false;
+ }
+ }
+
+ // Update status has been determined for all conditions. Now perform the update.
+ set<int> preservedConditions;
+ for (int i = 0; i < conditionTrackerCount; i++) {
+ const Predicate& predicate = config.predicate(i);
+ const int64_t id = predicate.id();
+ switch (conditionsToUpdate[i]) {
+ case UPDATE_PRESERVE: {
+ preservedConditions.insert(i);
+ const auto& oldConditionTrackerIt = oldConditionTrackerMap.find(id);
+ if (oldConditionTrackerIt == oldConditionTrackerMap.end()) {
+ ALOGE("Could not find Predicate %lld in the previous config, but expected it "
+ "to be there",
+ (long long)id);
+ return false;
+ }
+ const int oldIndex = oldConditionTrackerIt->second;
+ newConditionTrackers.push_back(oldConditionTrackers[oldIndex]);
+ break;
+ }
+ case UPDATE_REPLACE:
+ replacedConditions.insert(id);
+ [[fallthrough]]; // Intentionally fallthrough to create the new condition tracker.
+ case UPDATE_NEW: {
+ sp<ConditionTracker> tracker =
+ createConditionTracker(key, predicate, i, atomMatchingTrackerMap);
+ if (tracker == nullptr) {
+ return false;
+ }
+ newConditionTrackers.push_back(tracker);
+ break;
+ }
+ default: {
+ ALOGE("Condition \"%lld\" update state is unknown. This should never happen",
+ (long long)id);
+ return false;
+ }
+ }
+ }
+
+ // Update indices of preserved predicates.
+ for (const int conditionIndex : preservedConditions) {
+ if (!newConditionTrackers[conditionIndex]->onConfigUpdated(
+ conditionProtos, conditionIndex, newConditionTrackers, atomMatchingTrackerMap,
+ newConditionTrackerMap)) {
+ ALOGE("Failed to update condition %lld",
+ (long long)newConditionTrackers[conditionIndex]->getConditionId());
+ return false;
+ }
+ }
+
+ std::fill(cycleTracker.begin(), cycleTracker.end(), false);
+ for (int conditionIndex = 0; conditionIndex < conditionTrackerCount; conditionIndex++) {
+ const sp<ConditionTracker>& conditionTracker = newConditionTrackers[conditionIndex];
+ // Calling init on preserved conditions is OK. It is needed to fill the condition cache.
+ if (!conditionTracker->init(conditionProtos, newConditionTrackers, newConditionTrackerMap,
+ cycleTracker, conditionCache)) {
+ return false;
+ }
+ for (const int trackerIndex : conditionTracker->getAtomMatchingTrackerIndex()) {
+ vector<int>& conditionList = trackerToConditionMap[trackerIndex];
+ conditionList.push_back(conditionIndex);
+ }
+ }
+ return true;
+}
+
bool updateStatsdConfig(const ConfigKey& key, const StatsdConfig& config, const sp<UidMap>& uidMap,
const sp<StatsPullerManager>& pullerManager,
const sp<AlarmMonitor>& anomalyAlarmMonitor,
@@ -194,14 +401,34 @@ bool updateStatsdConfig(const ConfigKey& key, const StatsdConfig& config, const
const int64_t currentTimeNs,
const vector<sp<AtomMatchingTracker>>& oldAtomMatchingTrackers,
const unordered_map<int64_t, int>& oldAtomMatchingTrackerMap,
+ const vector<sp<ConditionTracker>>& oldConditionTrackers,
+ const unordered_map<int64_t, int>& oldConditionTrackerMap,
set<int>& allTagIds,
vector<sp<AtomMatchingTracker>>& newAtomMatchingTrackers,
- unordered_map<int64_t, int>& newAtomMatchingTrackerMap) {
- if (!updateAtomTrackers(config, uidMap, oldAtomMatchingTrackerMap, oldAtomMatchingTrackers,
- allTagIds, newAtomMatchingTrackerMap, newAtomMatchingTrackers)) {
+ unordered_map<int64_t, int>& newAtomMatchingTrackerMap,
+ vector<sp<ConditionTracker>>& newConditionTrackers,
+ unordered_map<int64_t, int>& newConditionTrackerMap,
+ unordered_map<int, vector<int>>& trackerToConditionMap) {
+ set<int64_t> replacedMatchers;
+ set<int64_t> replacedConditions;
+ vector<ConditionState> conditionCache;
+
+ if (!updateAtomMatchingTrackers(config, uidMap, oldAtomMatchingTrackerMap,
+ oldAtomMatchingTrackers, allTagIds, newAtomMatchingTrackerMap,
+ newAtomMatchingTrackers, replacedMatchers)) {
ALOGE("updateAtomMatchingTrackers failed");
return false;
}
+ VLOG("updateAtomMatchingTrackers succeeded");
+
+ if (!updateConditions(key, config, newAtomMatchingTrackerMap, replacedMatchers,
+ oldConditionTrackerMap, oldConditionTrackers, newConditionTrackerMap,
+ newConditionTrackers, trackerToConditionMap, conditionCache,
+ replacedConditions)) {
+ ALOGE("updateConditions failed");
+ return false;
+ }
+ VLOG("updateConditions succeeded");
return true;
}
diff --git a/cmds/statsd/src/metrics/parsing_utils/config_update_utils.h b/cmds/statsd/src/metrics/parsing_utils/config_update_utils.h
index ae7b2162e034..7ba684a65e88 100644
--- a/cmds/statsd/src/metrics/parsing_utils/config_update_utils.h
+++ b/cmds/statsd/src/metrics/parsing_utils/config_update_utils.h
@@ -19,6 +19,7 @@
#include <vector>
#include "anomaly/AlarmMonitor.h"
+#include "condition/ConditionTracker.h"
#include "external/StatsPullerManager.h"
#include "matchers/AtomMatchingTracker.h"
@@ -31,30 +32,33 @@ namespace statsd {
// All other functions are intermediate steps, created to make unit testing easier.
// Possible update states for a component. PRESERVE means we should keep the existing one.
-// REPLACE means we should create a new one, either because it didn't exist or it changed.
+// REPLACE means we should create a new one because the existing one changed
+// NEW means we should create a new one because one does not currently exist.
enum UpdateStatus {
UPDATE_UNKNOWN = 0,
UPDATE_PRESERVE = 1,
UPDATE_REPLACE = 2,
+ UPDATE_NEW = 3,
};
// Recursive function to determine if a matcher needs to be updated.
// input:
// [config]: the input StatsdConfig
// [matcherIdx]: the index of the current matcher to be updated
-// [newAtomMatchingTrackerMap]: matcher id to index mapping in the input StatsdConfig
// [oldAtomMatchingTrackerMap]: matcher id to index mapping in the existing MetricsManager
// [oldAtomMatchingTrackers]: stores the existing AtomMatchingTrackers
+// [newAtomMatchingTrackerMap]: matcher id to index mapping in the input StatsdConfig
// output:
// [matchersToUpdate]: vector of the update status of each matcher. The matcherIdx index will
// be updated from UPDATE_UNKNOWN after this call.
// [cycleTracker]: intermediate param used during recursion.
-bool determineMatcherUpdateStatus(const StatsdConfig& config, const int matcherIdx,
- const unordered_map<int64_t, int>& oldAtomMatchingTrackerMap,
- const vector<sp<AtomMatchingTracker>>& oldAtomMatchingTrackers,
- const unordered_map<int64_t, int>& newAtomMatchingTrackerMap,
- vector<UpdateStatus>& matchersToUpdate,
- vector<bool>& cycleTracker);
+// Returns whether the function was successful or not.
+bool determineMatcherUpdateStatus(
+ const StatsdConfig& config, const int matcherIdx,
+ const std::unordered_map<int64_t, int>& oldAtomMatchingTrackerMap,
+ const std::vector<sp<AtomMatchingTracker>>& oldAtomMatchingTrackers,
+ const std::unordered_map<int64_t, int>& newAtomMatchingTrackerMap,
+ std::vector<UpdateStatus>& matchersToUpdate, std::vector<bool>& cycleTracker);
// Updates the AtomMatchingTrackers.
// input:
@@ -64,12 +68,61 @@ bool determineMatcherUpdateStatus(const StatsdConfig& config, const int matcherI
// output:
// [allTagIds]: contains the set of all interesting tag ids to this config.
// [newAtomMatchingTrackerMap]: new matcher id to index mapping
-// [newAtomMatchers]: stores the new AtomMatchingTrackers
-bool updateAtomTrackers(const StatsdConfig& config, const sp<UidMap>& uidMap,
- const unordered_map<int64_t, int>& oldAtomMatchingTrackerMap,
- const vector<sp<AtomMatchingTracker>>& oldAtomMatchingTrackers,
- set<int>& allTagIds, unordered_map<int64_t, int>& newAtomMatchingTrackerMap,
- vector<sp<AtomMatchingTracker>>& newAtomMatchingTrackers);
+// [newAtomMatchingTrackers]: stores the new AtomMatchingTrackers
+// [replacedMatchers]: set of matcher ids that changed and have been replaced
+bool updateAtomMatchingTrackers(const StatsdConfig& config, const sp<UidMap>& uidMap,
+ const std::unordered_map<int64_t, int>& oldAtomMatchingTrackerMap,
+ const std::vector<sp<AtomMatchingTracker>>& oldAtomMatchingTrackers,
+ std::set<int>& allTagIds,
+ std::unordered_map<int64_t, int>& newAtomMatchingTrackerMap,
+ std::vector<sp<AtomMatchingTracker>>& newAtomMatchingTrackers,
+ std::set<int64_t>& replacedMatchers);
+
+// Recursive function to determine if a condition needs to be updated.
+// input:
+// [config]: the input StatsdConfig
+// [conditionIdx]: the index of the current condition to be updated
+// [oldConditionTrackerMap]: condition id to index mapping in the existing MetricsManager
+// [oldConditionTrackers]: stores the existing ConditionTrackers
+// [newConditionTrackerMap]: condition id to index mapping in the input StatsdConfig
+// [replacedMatchers]: set of replaced matcher ids. conditions using these matchers must be replaced
+// output:
+// [conditionsToUpdate]: vector of the update status of each condition. The conditionIdx index will
+// be updated from UPDATE_UNKNOWN after this call.
+// [cycleTracker]: intermediate param used during recursion.
+// Returns whether the function was successful or not.
+bool determineConditionUpdateStatus(const StatsdConfig& config, const int conditionIdx,
+ const std::unordered_map<int64_t, int>& oldConditionTrackerMap,
+ const std::vector<sp<ConditionTracker>>& oldConditionTrackers,
+ const std::unordered_map<int64_t, int>& newConditionTrackerMap,
+ const std::set<int64_t>& replacedMatchers,
+ std::vector<UpdateStatus>& conditionsToUpdate,
+ std::vector<bool>& cycleTracker);
+
+// Updates ConditionTrackers
+// input:
+// [config]: the input config
+// [atomMatchingTrackerMap]: AtomMatchingTracker name to index mapping from previous step.
+// [replacedMatchers]: ids of replaced matchers. conditions depending on these must also be replaced
+// [oldConditionTrackerMap]: existing matcher id to index mapping
+// [oldConditionTrackers]: stores the existing ConditionTrackers
+// output:
+// [newConditionTrackerMap]: new condition id to index mapping
+// [newConditionTrackers]: stores the sp to all the ConditionTrackers
+// [trackerToConditionMap]: contains the mapping from the index of an atom matcher
+// to indices of condition trackers that use the matcher
+// [conditionCache]: stores the current conditions for each ConditionTracker
+// [replacedConditions]: set of matcher ids that have changed and have been replaced
+bool updateConditions(const ConfigKey& key, const StatsdConfig& config,
+ const std::unordered_map<int64_t, int>& atomMatchingTrackerMap,
+ const std::set<int64_t>& replacedMatchers,
+ const std::unordered_map<int64_t, int>& oldConditionTrackerMap,
+ const std::vector<sp<ConditionTracker>>& oldConditionTrackers,
+ std::unordered_map<int64_t, int>& newConditionTrackerMap,
+ std::vector<sp<ConditionTracker>>& newConditionTrackers,
+ std::unordered_map<int, std::vector<int>>& trackerToConditionMap,
+ std::vector<ConditionState>& conditionCache,
+ std::set<int64_t>& replacedConditions);
// Updates the existing MetricsManager from a new StatsdConfig.
// Parameters are the members of MetricsManager. See MetricsManager for declaration.
@@ -79,10 +132,15 @@ bool updateStatsdConfig(const ConfigKey& key, const StatsdConfig& config, const
const sp<AlarmMonitor>& periodicAlarmMonitor, const int64_t timeBaseNs,
const int64_t currentTimeNs,
const std::vector<sp<AtomMatchingTracker>>& oldAtomMatchingTrackers,
- const unordered_map<int64_t, int>& oldAtomMatchingTrackerMap,
+ const std::unordered_map<int64_t, int>& oldAtomMatchingTrackerMap,
+ const std::vector<sp<ConditionTracker>>& oldConditionTrackers,
+ const std::unordered_map<int64_t, int>& oldConditionTrackerMap,
std::set<int>& allTagIds,
std::vector<sp<AtomMatchingTracker>>& newAtomMatchingTrackers,
- unordered_map<int64_t, int>& newAtomMatchingTrackerMap);
+ std::unordered_map<int64_t, int>& newAtomMatchingTrackerMap,
+ std::vector<sp<ConditionTracker>>& newConditionTrackers,
+ std::unordered_map<int64_t, int>& newConditionTrackerMap,
+ std::unordered_map<int, std::vector<int>>& trackerToConditionMap);
} // namespace statsd
} // namespace os
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 e40fbdb250f1..3f40c90d515a 100644
--- a/cmds/statsd/src/metrics/parsing_utils/metrics_manager_util.cpp
+++ b/cmds/statsd/src/metrics/parsing_utils/metrics_manager_util.cpp
@@ -38,6 +38,7 @@
#include "state/StateManager.h"
#include "stats_util.h"
+using google::protobuf::MessageLite;
using std::set;
using std::unordered_map;
using std::vector;
@@ -60,6 +61,20 @@ bool hasLeafNode(const FieldMatcher& matcher) {
return true;
}
+bool getMetricProtoHash(const MessageLite& metric, const int64_t id, const bool hasActivation,
+ const uint64_t activationHash, uint64_t& metricHash) {
+ string serializedMetric;
+ if (!metric.SerializeToString(&serializedMetric)) {
+ ALOGE("Unable to serialize metric %lld", (long long)id);
+ return false;
+ }
+ metricHash = Hash64(serializedMetric);
+ if (hasActivation) {
+ metricHash = Hash64(to_string(metricHash).append(to_string(activationHash)));
+ }
+ return true;
+}
+
} // namespace
sp<AtomMatchingTracker> createAtomMatchingTracker(const AtomMatcher& logMatcher, const int index,
@@ -74,16 +89,37 @@ sp<AtomMatchingTracker> createAtomMatchingTracker(const AtomMatcher& logMatcher,
case AtomMatcher::ContentsCase::kSimpleAtomMatcher:
return new SimpleAtomMatchingTracker(logMatcher.id(), index, protoHash,
logMatcher.simple_atom_matcher(), uidMap);
- break;
case AtomMatcher::ContentsCase::kCombination:
return new CombinationAtomMatchingTracker(logMatcher.id(), index, protoHash);
- break;
default:
ALOGE("Matcher \"%lld\" malformed", (long long)logMatcher.id());
return nullptr;
}
}
+sp<ConditionTracker> createConditionTracker(
+ const ConfigKey& key, const Predicate& predicate, const int index,
+ const unordered_map<int64_t, int>& atomMatchingTrackerMap) {
+ string serializedPredicate;
+ if (!predicate.SerializeToString(&serializedPredicate)) {
+ ALOGE("Unable to serialize predicate %lld", (long long)predicate.id());
+ return nullptr;
+ }
+ uint64_t protoHash = Hash64(serializedPredicate);
+ switch (predicate.contents_case()) {
+ case Predicate::ContentsCase::kSimplePredicate: {
+ return new SimpleConditionTracker(key, predicate.id(), protoHash, index,
+ predicate.simple_predicate(), atomMatchingTrackerMap);
+ }
+ case Predicate::ContentsCase::kCombination: {
+ return new CombinationConditionTracker(predicate.id(), index, protoHash);
+ }
+ default:
+ ALOGE("Predicate \"%lld\" malformed", (long long)predicate.id());
+ return nullptr;
+ }
+}
+
bool handleMetricWithAtomMatchingTrackers(
const int64_t what, const int metricIndex, const bool usedForDimension,
const vector<sp<AtomMatchingTracker>>& allAtomMatchingTrackers,
@@ -207,19 +243,31 @@ bool handleMetricWithStateLink(const FieldMatcher& stateMatcher,
bool handleMetricActivation(
const StatsdConfig& config, const int64_t metricId, const int metricIndex,
const unordered_map<int64_t, int>& metricToActivationMap,
- const unordered_map<int64_t, int>& atomMatchingTrackerMap,
+ const unordered_map<int64_t, int>& atomMatchingTrackerMap, bool& hasActivation,
unordered_map<int, vector<int>>& activationAtomTrackerToMetricMap,
unordered_map<int, vector<int>>& deactivationAtomTrackerToMetricMap,
vector<int>& metricsWithActivation,
unordered_map<int, shared_ptr<Activation>>& eventActivationMap,
- unordered_map<int, vector<shared_ptr<Activation>>>& eventDeactivationMap) {
+ unordered_map<int, vector<shared_ptr<Activation>>>& eventDeactivationMap,
+ uint64_t& activationHash) {
// Check if metric has an associated activation
auto itr = metricToActivationMap.find(metricId);
- if (itr == metricToActivationMap.end()) return true;
+ if (itr == metricToActivationMap.end()) {
+ hasActivation = false;
+ return true;
+ }
+ hasActivation = true;
int activationIndex = itr->second;
const MetricActivation& metricActivation = config.metric_activation(activationIndex);
+ string serializedActivation;
+ if (!metricActivation.SerializeToString(&serializedActivation)) {
+ ALOGE("Unable to serialize metric activation for metric %lld", (long long)metricId);
+ return false;
+ }
+ activationHash = Hash64(serializedActivation);
+
for (int i = 0; i < metricActivation.event_activation_size(); i++) {
const EventActivation& activation = metricActivation.event_activation(i);
@@ -266,8 +314,7 @@ bool initAtomMatchingTrackers(const StatsdConfig& config, const sp<UidMap>& uidM
for (int i = 0; i < atomMatcherCount; i++) {
const AtomMatcher& logMatcher = config.atom_matcher(i);
- int index = allAtomMatchingTrackers.size();
- sp<AtomMatchingTracker> tracker = createAtomMatchingTracker(logMatcher, index, uidMap);
+ sp<AtomMatchingTracker> tracker = createAtomMatchingTracker(logMatcher, i, uidMap);
if (tracker == nullptr) {
return false;
}
@@ -276,7 +323,7 @@ bool initAtomMatchingTrackers(const StatsdConfig& config, const sp<UidMap>& uidM
ALOGE("Duplicate AtomMatcher found!");
return false;
}
- atomMatchingTrackerMap[logMatcher.id()] = index;
+ atomMatchingTrackerMap[logMatcher.id()] = i;
matcherConfigs.push_back(logMatcher);
}
@@ -307,28 +354,17 @@ bool initConditions(const ConfigKey& key, const StatsdConfig& config,
for (int i = 0; i < conditionTrackerCount; i++) {
const Predicate& condition = config.predicate(i);
- int index = allConditionTrackers.size();
- switch (condition.contents_case()) {
- case Predicate::ContentsCase::kSimplePredicate: {
- allConditionTrackers.push_back(new SimpleConditionTracker(
- key, condition.id(), index, condition.simple_predicate(),
- atomMatchingTrackerMap));
- break;
- }
- case Predicate::ContentsCase::kCombination: {
- allConditionTrackers.push_back(
- new CombinationConditionTracker(condition.id(), index));
- break;
- }
- default:
- ALOGE("Predicate \"%lld\" malformed", (long long)condition.id());
- return false;
+ sp<ConditionTracker> tracker =
+ createConditionTracker(key, condition, i, atomMatchingTrackerMap);
+ if (tracker == nullptr) {
+ return false;
}
+ allConditionTrackers.push_back(tracker);
if (conditionTrackerMap.find(condition.id()) != conditionTrackerMap.end()) {
ALOGE("Duplicate Predicate found!");
return false;
}
- conditionTrackerMap[condition.id()] = index;
+ conditionTrackerMap[condition.id()] = i;
conditionConfigs.push_back(condition);
}
@@ -348,12 +384,20 @@ bool initConditions(const ConfigKey& key, const StatsdConfig& config,
}
bool initStates(const StatsdConfig& config, unordered_map<int64_t, int>& stateAtomIdMap,
- unordered_map<int64_t, unordered_map<int, int64_t>>& allStateGroupMaps) {
+ unordered_map<int64_t, unordered_map<int, int64_t>>& allStateGroupMaps,
+ map<int64_t, uint64_t>& stateProtoHashes) {
for (int i = 0; i < config.state_size(); i++) {
const State& state = config.state(i);
const int64_t stateId = state.id();
stateAtomIdMap[stateId] = state.atom_id();
+ string serializedState;
+ if (!state.SerializeToString(&serializedState)) {
+ ALOGE("Unable to serialize state %lld", (long long)stateId);
+ return false;
+ }
+ stateProtoHashes[stateId] = Hash64(serializedState);
+
const StateMap& stateMap = state.map();
for (auto group : stateMap.group()) {
for (auto value : group.value()) {
@@ -448,18 +492,25 @@ bool initMetrics(const ConfigKey& key, const StatsdConfig& config, const int64_t
}
}
+ bool hasActivation = false;
unordered_map<int, shared_ptr<Activation>> eventActivationMap;
unordered_map<int, vector<shared_ptr<Activation>>> eventDeactivationMap;
+ uint64_t activationHash;
bool success = handleMetricActivation(
config, metric.id(), metricIndex, metricToActivationMap, atomMatchingTrackerMap,
- activationAtomTrackerToMetricMap, deactivationAtomTrackerToMetricMap,
- metricsWithActivation, eventActivationMap, eventDeactivationMap);
+ hasActivation, activationAtomTrackerToMetricMap, deactivationAtomTrackerToMetricMap,
+ metricsWithActivation, eventActivationMap, eventDeactivationMap, activationHash);
if (!success) return false;
- sp<MetricProducer> countProducer =
- new CountMetricProducer(key, metric, conditionIndex, initialConditionCache, wizard,
- timeBaseTimeNs, currentTimeNs, eventActivationMap,
- eventDeactivationMap, slicedStateAtoms, stateGroupMap);
+ uint64_t metricHash;
+ if (!getMetricProtoHash(metric, metric.id(), hasActivation, activationHash, metricHash)) {
+ return false;
+ }
+
+ sp<MetricProducer> countProducer = new CountMetricProducer(
+ key, metric, conditionIndex, initialConditionCache, wizard, metricHash,
+ timeBaseTimeNs, currentTimeNs, eventActivationMap, eventDeactivationMap,
+ slicedStateAtoms, stateGroupMap);
allMetricProducers.push_back(countProducer);
}
@@ -557,19 +608,26 @@ bool initMetrics(const ConfigKey& key, const StatsdConfig& config, const int64_t
}
}
+ bool hasActivation = false;
unordered_map<int, shared_ptr<Activation>> eventActivationMap;
unordered_map<int, vector<shared_ptr<Activation>>> eventDeactivationMap;
+ uint64_t activationHash;
bool success = handleMetricActivation(
config, metric.id(), metricIndex, metricToActivationMap, atomMatchingTrackerMap,
- activationAtomTrackerToMetricMap, deactivationAtomTrackerToMetricMap,
- metricsWithActivation, eventActivationMap, eventDeactivationMap);
+ hasActivation, activationAtomTrackerToMetricMap, deactivationAtomTrackerToMetricMap,
+ metricsWithActivation, eventActivationMap, eventDeactivationMap, activationHash);
if (!success) return false;
+ uint64_t metricHash;
+ if (!getMetricProtoHash(metric, metric.id(), hasActivation, activationHash, metricHash)) {
+ return false;
+ }
+
sp<MetricProducer> durationMetric = new DurationMetricProducer(
key, metric, conditionIndex, initialConditionCache, trackerIndices[0],
- trackerIndices[1], trackerIndices[2], nesting, wizard, internalDimensions,
- timeBaseTimeNs, currentTimeNs, eventActivationMap, eventDeactivationMap,
- slicedStateAtoms, stateGroupMap);
+ trackerIndices[1], trackerIndices[2], nesting, wizard, metricHash,
+ internalDimensions, timeBaseTimeNs, currentTimeNs, eventActivationMap,
+ eventDeactivationMap, slicedStateAtoms, stateGroupMap);
allMetricProducers.push_back(durationMetric);
}
@@ -605,17 +663,24 @@ bool initMetrics(const ConfigKey& key, const StatsdConfig& config, const int64_t
}
}
+ bool hasActivation = false;
unordered_map<int, shared_ptr<Activation>> eventActivationMap;
unordered_map<int, vector<shared_ptr<Activation>>> eventDeactivationMap;
+ uint64_t activationHash;
bool success = handleMetricActivation(
config, metric.id(), metricIndex, metricToActivationMap, atomMatchingTrackerMap,
- activationAtomTrackerToMetricMap, deactivationAtomTrackerToMetricMap,
- metricsWithActivation, eventActivationMap, eventDeactivationMap);
+ hasActivation, activationAtomTrackerToMetricMap, deactivationAtomTrackerToMetricMap,
+ metricsWithActivation, eventActivationMap, eventDeactivationMap, activationHash);
if (!success) return false;
- sp<MetricProducer> eventMetric =
- new EventMetricProducer(key, metric, conditionIndex, initialConditionCache, wizard,
- timeBaseTimeNs, eventActivationMap, eventDeactivationMap);
+ uint64_t metricHash;
+ if (!getMetricProtoHash(metric, metric.id(), hasActivation, activationHash, metricHash)) {
+ return false;
+ }
+
+ sp<MetricProducer> eventMetric = new EventMetricProducer(
+ key, metric, conditionIndex, initialConditionCache, wizard, metricHash,
+ timeBaseTimeNs, eventActivationMap, eventDeactivationMap);
allMetricProducers.push_back(eventMetric);
}
@@ -694,18 +759,26 @@ bool initMetrics(const ConfigKey& key, const StatsdConfig& config, const int64_t
}
}
+ bool hasActivation = false;
unordered_map<int, shared_ptr<Activation>> eventActivationMap;
unordered_map<int, vector<shared_ptr<Activation>>> eventDeactivationMap;
+ uint64_t activationHash;
bool success = handleMetricActivation(
config, metric.id(), metricIndex, metricToActivationMap, atomMatchingTrackerMap,
- activationAtomTrackerToMetricMap, deactivationAtomTrackerToMetricMap,
- metricsWithActivation, eventActivationMap, eventDeactivationMap);
+ hasActivation, activationAtomTrackerToMetricMap, deactivationAtomTrackerToMetricMap,
+ metricsWithActivation, eventActivationMap, eventDeactivationMap, activationHash);
if (!success) return false;
+ uint64_t metricHash;
+ if (!getMetricProtoHash(metric, metric.id(), hasActivation, activationHash, metricHash)) {
+ return false;
+ }
+
sp<MetricProducer> valueProducer = new ValueMetricProducer(
- key, metric, conditionIndex, initialConditionCache, wizard, trackerIndex,
- matcherWizard, pullTagId, timeBaseTimeNs, currentTimeNs, pullerManager,
- eventActivationMap, eventDeactivationMap, slicedStateAtoms, stateGroupMap);
+ key, metric, conditionIndex, initialConditionCache, wizard, metricHash,
+ trackerIndex, matcherWizard, pullTagId, timeBaseTimeNs, currentTimeNs,
+ pullerManager, eventActivationMap, eventDeactivationMap, slicedStateAtoms,
+ stateGroupMap);
allMetricProducers.push_back(valueProducer);
}
@@ -790,18 +863,25 @@ bool initMetrics(const ConfigKey& key, const StatsdConfig& config, const int64_t
}
}
+ bool hasActivation = false;
unordered_map<int, shared_ptr<Activation>> eventActivationMap;
unordered_map<int, vector<shared_ptr<Activation>>> eventDeactivationMap;
+ uint64_t activationHash;
bool success = handleMetricActivation(
config, metric.id(), metricIndex, metricToActivationMap, atomMatchingTrackerMap,
- activationAtomTrackerToMetricMap, deactivationAtomTrackerToMetricMap,
- metricsWithActivation, eventActivationMap, eventDeactivationMap);
+ hasActivation, activationAtomTrackerToMetricMap, deactivationAtomTrackerToMetricMap,
+ metricsWithActivation, eventActivationMap, eventDeactivationMap, activationHash);
if (!success) return false;
+ uint64_t metricHash;
+ if (!getMetricProtoHash(metric, metric.id(), hasActivation, activationHash, metricHash)) {
+ return false;
+ }
+
sp<MetricProducer> gaugeProducer = new GaugeMetricProducer(
- key, metric, conditionIndex, initialConditionCache, wizard, trackerIndex,
- matcherWizard, pullTagId, triggerAtomId, atomTagId, timeBaseTimeNs, currentTimeNs,
- pullerManager, eventActivationMap, eventDeactivationMap);
+ key, metric, conditionIndex, initialConditionCache, wizard, metricHash,
+ trackerIndex, matcherWizard, pullTagId, triggerAtomId, atomTagId, timeBaseTimeNs,
+ currentTimeNs, pullerManager, eventActivationMap, eventDeactivationMap);
allMetricProducers.push_back(gaugeProducer);
}
for (int i = 0; i < config.no_report_metric_size(); ++i) {
@@ -934,7 +1014,9 @@ bool initStatsdConfig(const ConfigKey& key, const StatsdConfig& config, const sp
vector<sp<AtomMatchingTracker>>& allAtomMatchingTrackers,
unordered_map<int64_t, int>& atomMatchingTrackerMap,
vector<sp<ConditionTracker>>& allConditionTrackers,
+ unordered_map<int64_t, int>& conditionTrackerMap,
vector<sp<MetricProducer>>& allMetricProducers,
+ unordered_map<int64_t, int>& metricProducerMap,
vector<sp<AnomalyTracker>>& allAnomalyTrackers,
vector<sp<AlarmTracker>>& allPeriodicAlarmTrackers,
unordered_map<int, std::vector<int>>& conditionToMetricMap,
@@ -943,10 +1025,9 @@ bool initStatsdConfig(const ConfigKey& key, const StatsdConfig& config, const sp
unordered_map<int, std::vector<int>>& activationAtomTrackerToMetricMap,
unordered_map<int, std::vector<int>>& deactivationAtomTrackerToMetricMap,
unordered_map<int64_t, int>& alertTrackerMap,
- vector<int>& metricsWithActivation, std::set<int64_t>& noReportMetricIds) {
- unordered_map<int64_t, int> conditionTrackerMap;
+ vector<int>& metricsWithActivation, map<int64_t, uint64_t>& stateProtoHashes,
+ set<int64_t>& noReportMetricIds) {
vector<ConditionState> initialConditionCache;
- unordered_map<int64_t, int> metricProducerMap;
unordered_map<int64_t, int> stateAtomIdMap;
unordered_map<int64_t, unordered_map<int, int64_t>> allStateGroupMaps;
@@ -963,7 +1044,7 @@ bool initStatsdConfig(const ConfigKey& key, const StatsdConfig& config, const sp
return false;
}
- if (!initStates(config, stateAtomIdMap, allStateGroupMaps)) {
+ if (!initStates(config, stateAtomIdMap, allStateGroupMaps, stateProtoHashes)) {
ALOGE("initStates failed");
return false;
}
diff --git a/cmds/statsd/src/metrics/parsing_utils/metrics_manager_util.h b/cmds/statsd/src/metrics/parsing_utils/metrics_manager_util.h
index 4cfd1b0465ea..4979c3051133 100644
--- a/cmds/statsd/src/metrics/parsing_utils/metrics_manager_util.h
+++ b/cmds/statsd/src/metrics/parsing_utils/metrics_manager_util.h
@@ -42,6 +42,17 @@ namespace statsd {
sp<AtomMatchingTracker> createAtomMatchingTracker(const AtomMatcher& logMatcher, const int index,
const sp<UidMap>& uidMap);
+// Create a ConditionTracker.
+// input:
+// [predicate]: the input Predicate from the StatsdConfig
+// [index]: the index of the condition tracker
+// [atomMatchingTrackerMap]: map of atom matcher id to its index in allAtomMatchingTrackers
+// output:
+// new ConditionTracker, or null if the tracker is unable to be created
+sp<ConditionTracker> createConditionTracker(
+ const ConfigKey& key, const Predicate& predicate, const int index,
+ const unordered_map<int64_t, int>& atomMatchingTrackerMap);
+
// Helper functions for MetricsManager to initialize from StatsdConfig.
// *Note*: only initStatsdConfig() should be called from outside.
// All other functions are intermediate
@@ -77,7 +88,6 @@ bool initConditions(const ConfigKey& key, const StatsdConfig& config,
std::unordered_map<int64_t, int>& conditionTrackerMap,
std::vector<sp<ConditionTracker>>& allConditionTrackers,
std::unordered_map<int, std::vector<int>>& trackerToConditionMap,
- std::unordered_map<int, std::vector<MetricConditionLink>>& eventConditionLinks,
std::vector<ConditionState>& initialConditionCache);
// Initialize State maps using State protos in the config. These maps will
@@ -88,8 +98,10 @@ bool initConditions(const ConfigKey& key, const StatsdConfig& config,
// [stateAtomIdMap]: this map should contain the mapping from state ids to atom ids
// [allStateGroupMaps]: this map should contain the mapping from states ids and state
// values to state group ids for all states
+// [stateProtoHashes]: contains a map of state id to the hash of the State proto from the config
bool initStates(const StatsdConfig& config, unordered_map<int64_t, int>& stateAtomIdMap,
- unordered_map<int64_t, unordered_map<int, int64_t>>& allStateGroupMaps);
+ unordered_map<int64_t, unordered_map<int, int64_t>>& allStateGroupMaps,
+ std::map<int64_t, uint64_t>& stateProtoHashes);
// Initialize MetricProducers.
// input:
@@ -111,7 +123,6 @@ bool initMetrics(
const int64_t currentTimeNs, const sp<StatsPullerManager>& pullerManager,
const std::unordered_map<int64_t, int>& atomMatchingTrackerMap,
const std::unordered_map<int64_t, int>& conditionTrackerMap,
- const std::unordered_map<int, std::vector<MetricConditionLink>>& eventConditionLinks,
const vector<sp<AtomMatchingTracker>>& allAtomMatchingTrackers,
const unordered_map<int64_t, int>& stateAtomIdMap,
const unordered_map<int64_t, unordered_map<int, int64_t>>& allStateGroupMaps,
@@ -135,7 +146,9 @@ bool initStatsdConfig(const ConfigKey& key, const StatsdConfig& config, const sp
std::vector<sp<AtomMatchingTracker>>& allAtomMatchingTrackers,
std::unordered_map<int64_t, int>& atomMatchingTrackerMap,
std::vector<sp<ConditionTracker>>& allConditionTrackers,
+ std::unordered_map<int64_t, int>& conditionTrackerMap,
std::vector<sp<MetricProducer>>& allMetricProducers,
+ std::unordered_map<int64_t, int>& metricProducerMap,
vector<sp<AnomalyTracker>>& allAnomalyTrackers,
vector<sp<AlarmTracker>>& allPeriodicAlarmTrackers,
std::unordered_map<int, std::vector<int>>& conditionToMetricMap,
@@ -144,7 +157,9 @@ bool initStatsdConfig(const ConfigKey& key, const StatsdConfig& config, const sp
unordered_map<int, std::vector<int>>& activationAtomTrackerToMetricMap,
unordered_map<int, std::vector<int>>& deactivationAtomTrackerToMetricMap,
std::unordered_map<int64_t, int>& alertTrackerMap,
- vector<int>& metricsWithActivation, std::set<int64_t>& noReportMetricIds);
+ vector<int>& metricsWithActivation,
+ std::map<int64_t, uint64_t>& stateProtoHashes,
+ std::set<int64_t>& noReportMetricIds);
} // namespace statsd
} // namespace os
diff --git a/cmds/statsd/tests/condition/SimpleConditionTracker_test.cpp b/cmds/statsd/tests/condition/SimpleConditionTracker_test.cpp
index 07b5311b1207..8998b5f98df5 100644
--- a/cmds/statsd/tests/condition/SimpleConditionTracker_test.cpp
+++ b/cmds/statsd/tests/condition/SimpleConditionTracker_test.cpp
@@ -39,6 +39,7 @@ const ConfigKey kConfigKey(0, 12345);
const int ATTRIBUTION_NODE_FIELD_ID = 1;
const int ATTRIBUTION_UID_FIELD_ID = 1;
const int TAG_ID = 1;
+const uint64_t protoHash = 0x123456789;
SimplePredicate getWakeLockHeldCondition(bool countNesting, bool defaultFalse,
bool outputSlicedUid, Position position) {
@@ -123,7 +124,7 @@ TEST(SimpleConditionTrackerTest, TestNonSlicedInitialValueFalse) {
trackerNameIndexMap[StringToId("SCREEN_TURNED_ON")] = 0;
trackerNameIndexMap[StringToId("SCREEN_TURNED_OFF")] = 1;
- SimpleConditionTracker conditionTracker(kConfigKey, StringToId("SCREEN_IS_ON"),
+ SimpleConditionTracker conditionTracker(kConfigKey, StringToId("SCREEN_IS_ON"), protoHash,
0 /*tracker index*/, simplePredicate,
trackerNameIndexMap);
@@ -177,7 +178,7 @@ TEST(SimpleConditionTrackerTest, TestNonSlicedInitialValueUnknown) {
trackerNameIndexMap[StringToId("SCREEN_TURNED_ON")] = 0;
trackerNameIndexMap[StringToId("SCREEN_TURNED_OFF")] = 1;
- SimpleConditionTracker conditionTracker(kConfigKey, StringToId("SCREEN_IS_ON"),
+ SimpleConditionTracker conditionTracker(kConfigKey, StringToId("SCREEN_IS_ON"), protoHash,
0 /*tracker index*/, simplePredicate,
trackerNameIndexMap);
@@ -231,8 +232,9 @@ TEST(SimpleConditionTrackerTest, TestNonSlicedCondition) {
trackerNameIndexMap[StringToId("SCREEN_TURNED_ON")] = 0;
trackerNameIndexMap[StringToId("SCREEN_TURNED_OFF")] = 1;
- SimpleConditionTracker conditionTracker(kConfigKey, StringToId("SCREEN_IS_ON"), 0 /*tracker index*/,
- simplePredicate, trackerNameIndexMap);
+ SimpleConditionTracker conditionTracker(kConfigKey, StringToId("SCREEN_IS_ON"), protoHash,
+ 0 /*tracker index*/, simplePredicate,
+ trackerNameIndexMap);
EXPECT_FALSE(conditionTracker.isSliced());
// This event is not accessed in this test besides dimensions which is why this is okay.
@@ -317,7 +319,7 @@ TEST(SimpleConditionTrackerTest, TestNonSlicedConditionNestCounting) {
trackerNameIndexMap[StringToId("SCREEN_TURNED_ON")] = 0;
trackerNameIndexMap[StringToId("SCREEN_TURNED_OFF")] = 1;
- SimpleConditionTracker conditionTracker(kConfigKey, StringToId("SCREEN_IS_ON"),
+ SimpleConditionTracker conditionTracker(kConfigKey, StringToId("SCREEN_IS_ON"), protoHash,
0 /*condition tracker index*/, simplePredicate,
trackerNameIndexMap);
EXPECT_FALSE(conditionTracker.isSliced());
@@ -392,7 +394,7 @@ TEST(SimpleConditionTrackerTest, TestSlicedCondition) {
trackerNameIndexMap[StringToId("WAKE_LOCK_RELEASE")] = 1;
trackerNameIndexMap[StringToId("RELEASE_ALL")] = 2;
- SimpleConditionTracker conditionTracker(kConfigKey, StringToId(conditionName),
+ SimpleConditionTracker conditionTracker(kConfigKey, StringToId(conditionName), protoHash,
0 /*condition tracker index*/, simplePredicate,
trackerNameIndexMap);
@@ -514,7 +516,7 @@ TEST(SimpleConditionTrackerTest, TestSlicedWithNoOutputDim) {
trackerNameIndexMap[StringToId("WAKE_LOCK_RELEASE")] = 1;
trackerNameIndexMap[StringToId("RELEASE_ALL")] = 2;
- SimpleConditionTracker conditionTracker(kConfigKey, StringToId(conditionName),
+ SimpleConditionTracker conditionTracker(kConfigKey, StringToId(conditionName), protoHash,
0 /*condition tracker index*/, simplePredicate,
trackerNameIndexMap);
@@ -610,7 +612,7 @@ TEST(SimpleConditionTrackerTest, TestStopAll) {
trackerNameIndexMap[StringToId("WAKE_LOCK_RELEASE")] = 1;
trackerNameIndexMap[StringToId("RELEASE_ALL")] = 2;
- SimpleConditionTracker conditionTracker(kConfigKey, StringToId(conditionName),
+ SimpleConditionTracker conditionTracker(kConfigKey, StringToId(conditionName), protoHash,
0 /*condition tracker index*/, simplePredicate,
trackerNameIndexMap);
diff --git a/cmds/statsd/tests/metrics/CountMetricProducer_test.cpp b/cmds/statsd/tests/metrics/CountMetricProducer_test.cpp
index bb8e7bfd90f4..8e2864c6fba8 100644
--- a/cmds/statsd/tests/metrics/CountMetricProducer_test.cpp
+++ b/cmds/statsd/tests/metrics/CountMetricProducer_test.cpp
@@ -41,6 +41,7 @@ namespace statsd {
namespace {
const ConfigKey kConfigKey(0, 12345);
+const uint64_t protoHash = 0x1234567890;
void makeLogEvent(LogEvent* logEvent, int64_t timestampNs, int atomId) {
AStatsEvent* statsEvent = AStatsEvent_obtain();
@@ -75,7 +76,7 @@ TEST(CountMetricProducerTest, TestFirstBucket) {
sp<MockConditionWizard> wizard = new NaggyMock<MockConditionWizard>();
CountMetricProducer countProducer(kConfigKey, metric, -1 /*-1 meaning no condition*/, {},
- wizard, 5, 600 * NS_PER_SEC + NS_PER_SEC / 2);
+ wizard, protoHash, 5, 600 * NS_PER_SEC + NS_PER_SEC / 2);
EXPECT_EQ(600500000000, countProducer.mCurrentBucketStartTimeNs);
EXPECT_EQ(10, countProducer.mCurrentBucketNum);
EXPECT_EQ(660000000005, countProducer.getCurrentBucketEndTimeNs());
@@ -95,7 +96,7 @@ TEST(CountMetricProducerTest, TestNonDimensionalEvents) {
sp<MockConditionWizard> wizard = new NaggyMock<MockConditionWizard>();
CountMetricProducer countProducer(kConfigKey, metric, -1 /*-1 meaning no condition*/, {},
- wizard, bucketStartTimeNs, bucketStartTimeNs);
+ wizard, protoHash, bucketStartTimeNs, bucketStartTimeNs);
// 2 events in bucket 1.
LogEvent event1(/*uid=*/0, /*pid=*/0);
@@ -158,7 +159,7 @@ TEST(CountMetricProducerTest, TestEventsWithNonSlicedCondition) {
sp<MockConditionWizard> wizard = new NaggyMock<MockConditionWizard>();
CountMetricProducer countProducer(kConfigKey, metric, 0, {ConditionState::kUnknown}, wizard,
- bucketStartTimeNs, bucketStartTimeNs);
+ protoHash, bucketStartTimeNs, bucketStartTimeNs);
countProducer.onConditionChanged(true, bucketStartTimeNs);
@@ -226,8 +227,8 @@ TEST(CountMetricProducerTest, TestEventsWithSlicedCondition) {
EXPECT_CALL(*wizard, query(_, key2, _)).WillOnce(Return(ConditionState::kTrue));
CountMetricProducer countProducer(kConfigKey, metric, 0 /*condition tracker index*/,
- {ConditionState::kUnknown}, wizard, bucketStartTimeNs,
- bucketStartTimeNs);
+ {ConditionState::kUnknown}, wizard, protoHash,
+ bucketStartTimeNs, bucketStartTimeNs);
countProducer.onMatchedLogEvent(1 /*log matcher index*/, event1);
countProducer.flushIfNeededLocked(bucketStartTimeNs + 1);
@@ -265,7 +266,7 @@ TEST_P(CountMetricProducerTest_PartialBucket, TestSplitInCurrentBucket) {
sp<MockConditionWizard> wizard = new NaggyMock<MockConditionWizard>();
CountMetricProducer countProducer(kConfigKey, metric, -1 /* no condition */, {}, wizard,
- bucketStartTimeNs, bucketStartTimeNs);
+ protoHash, bucketStartTimeNs, bucketStartTimeNs);
sp<AnomalyTracker> anomalyTracker = countProducer.addAnomalyTracker(alert, alarmMonitor);
EXPECT_TRUE(anomalyTracker != nullptr);
@@ -332,7 +333,7 @@ TEST_P(CountMetricProducerTest_PartialBucket, TestSplitInNextBucket) {
sp<MockConditionWizard> wizard = new NaggyMock<MockConditionWizard>();
CountMetricProducer countProducer(kConfigKey, metric, -1 /* no condition */, {}, wizard,
- bucketStartTimeNs, bucketStartTimeNs);
+ protoHash, bucketStartTimeNs, bucketStartTimeNs);
// Bucket is flushed yet.
LogEvent event1(/*uid=*/0, /*pid=*/0);
@@ -397,7 +398,7 @@ TEST(CountMetricProducerTest, TestAnomalyDetectionUnSliced) {
sp<MockConditionWizard> wizard = new NaggyMock<MockConditionWizard>();
CountMetricProducer countProducer(kConfigKey, metric, -1 /*-1 meaning no condition*/, {},
- wizard, bucketStartTimeNs, bucketStartTimeNs);
+ wizard, protoHash, bucketStartTimeNs, bucketStartTimeNs);
sp<AnomalyTracker> anomalyTracker = countProducer.addAnomalyTracker(alert, alarmMonitor);
@@ -459,7 +460,7 @@ TEST(CountMetricProducerTest, TestOneWeekTimeUnit) {
int64_t fiveWeeksNs = 5 * 7 * oneDayNs;
CountMetricProducer countProducer(kConfigKey, metric, -1 /* meaning no condition */, {}, wizard,
- oneDayNs, fiveWeeksNs);
+ protoHash, oneDayNs, fiveWeeksNs);
int64_t fiveWeeksOneDayNs = fiveWeeksNs + oneDayNs;
diff --git a/cmds/statsd/tests/metrics/DurationMetricProducer_test.cpp b/cmds/statsd/tests/metrics/DurationMetricProducer_test.cpp
index 05cfa37b0ee1..d1f89775ed6a 100644
--- a/cmds/statsd/tests/metrics/DurationMetricProducer_test.cpp
+++ b/cmds/statsd/tests/metrics/DurationMetricProducer_test.cpp
@@ -45,6 +45,7 @@ namespace statsd {
namespace {
const ConfigKey kConfigKey(0, 12345);
+const uint64_t protoHash = 0x1234567890;
void makeLogEvent(LogEvent* logEvent, int64_t timestampNs, int atomId) {
AStatsEvent* statsEvent = AStatsEvent_obtain();
AStatsEvent_setAtomId(statsEvent, atomId);
@@ -71,10 +72,10 @@ 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,
- dimensions, 5, 600 * NS_PER_SEC + NS_PER_SEC / 2);
+ 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);
EXPECT_EQ(600500000000, durationProducer.mCurrentBucketStartTimeNs);
EXPECT_EQ(10, durationProducer.mCurrentBucketNum);
@@ -99,10 +100,10 @@ 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,
- dimensions, bucketStartTimeNs, bucketStartTimeNs);
+ DurationMetricProducer durationProducer(
+ kConfigKey, metric, -1 /*no condition*/, {}, 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,7 +146,7 @@ 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, dimensions, bucketStartTimeNs, bucketStartTimeNs);
+ wizard, protoHash, dimensions, bucketStartTimeNs, bucketStartTimeNs);
durationProducer.mCondition = ConditionState::kFalse;
EXPECT_FALSE(durationProducer.mCondition);
@@ -195,7 +196,7 @@ 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, dimensions, bucketStartTimeNs, bucketStartTimeNs);
+ wizard, protoHash, dimensions, bucketStartTimeNs, bucketStartTimeNs);
EXPECT_EQ(ConditionState::kUnknown, durationProducer.mCondition);
EXPECT_FALSE(durationProducer.isConditionSliced());
@@ -238,10 +239,10 @@ TEST_P(DurationMetricProducerTest_PartialBucket, TestSumDuration) {
sp<MockConditionWizard> wizard = new NaggyMock<MockConditionWizard>();
FieldMatcher dimensions;
- DurationMetricProducer durationProducer(kConfigKey, metric, -1 /* no condition */, {},
- 1 /* start index */, 2 /* stop index */,
- 3 /* stop_all index */, false /*nesting*/, wizard,
- dimensions, bucketStartTimeNs, bucketStartTimeNs);
+ DurationMetricProducer durationProducer(
+ kConfigKey, metric, -1 /* no condition */, {}, 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);
@@ -301,10 +302,10 @@ TEST_P(DurationMetricProducerTest_PartialBucket, TestSumDurationWithSplitInFollo
sp<MockConditionWizard> wizard = new NaggyMock<MockConditionWizard>();
FieldMatcher dimensions;
- DurationMetricProducer durationProducer(kConfigKey, metric, -1 /* no condition */, {},
- 1 /* start index */, 2 /* stop index */,
- 3 /* stop_all index */, false /*nesting*/, wizard,
- dimensions, bucketStartTimeNs, bucketStartTimeNs);
+ DurationMetricProducer durationProducer(
+ kConfigKey, metric, -1 /* no condition */, {}, 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);
@@ -365,10 +366,10 @@ TEST_P(DurationMetricProducerTest_PartialBucket, TestSumDurationAnomaly) {
sp<MockConditionWizard> wizard = new NaggyMock<MockConditionWizard>();
FieldMatcher dimensions;
- DurationMetricProducer durationProducer(kConfigKey, metric, -1 /* no condition */, {},
- 1 /* start index */, 2 /* stop index */,
- 3 /* stop_all index */, false /*nesting*/, wizard,
- dimensions, bucketStartTimeNs, bucketStartTimeNs);
+ DurationMetricProducer durationProducer(
+ kConfigKey, metric, -1 /* no condition */, {}, 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);
@@ -411,10 +412,10 @@ TEST_P(DurationMetricProducerTest_PartialBucket, TestMaxDuration) {
sp<MockConditionWizard> wizard = new NaggyMock<MockConditionWizard>();
FieldMatcher dimensions;
- DurationMetricProducer durationProducer(kConfigKey, metric, -1 /* no condition */, {},
- 1 /* start index */, 2 /* stop index */,
- 3 /* stop_all index */, false /*nesting*/, wizard,
- dimensions, bucketStartTimeNs, bucketStartTimeNs);
+ DurationMetricProducer durationProducer(
+ kConfigKey, metric, -1 /* no condition */, {}, 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);
@@ -465,10 +466,10 @@ TEST_P(DurationMetricProducerTest_PartialBucket, TestMaxDurationWithSplitInNextB
sp<MockConditionWizard> wizard = new NaggyMock<MockConditionWizard>();
FieldMatcher dimensions;
- DurationMetricProducer durationProducer(kConfigKey, metric, -1 /* no condition */, {},
- 1 /* start index */, 2 /* stop index */,
- 3 /* stop_all index */, false /*nesting*/, wizard,
- dimensions, bucketStartTimeNs, bucketStartTimeNs);
+ DurationMetricProducer durationProducer(
+ kConfigKey, metric, -1 /* no condition */, {}, 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/EventMetricProducer_test.cpp b/cmds/statsd/tests/metrics/EventMetricProducer_test.cpp
index dfbb9da568b0..4bbbd2cb36ad 100644
--- a/cmds/statsd/tests/metrics/EventMetricProducer_test.cpp
+++ b/cmds/statsd/tests/metrics/EventMetricProducer_test.cpp
@@ -36,9 +36,11 @@ namespace android {
namespace os {
namespace statsd {
-const ConfigKey kConfigKey(0, 12345);
namespace {
+const ConfigKey kConfigKey(0, 12345);
+const uint64_t protoHash = 0x1234567890;
+
void makeLogEvent(LogEvent* logEvent, int32_t atomId, int64_t timestampNs, string str) {
AStatsEvent* statsEvent = AStatsEvent_obtain();
AStatsEvent_setAtomId(statsEvent, atomId);
@@ -66,7 +68,7 @@ TEST(EventMetricProducerTest, TestNoCondition) {
sp<MockConditionWizard> wizard = new NaggyMock<MockConditionWizard>();
EventMetricProducer eventProducer(kConfigKey, metric, -1 /*-1 meaning no condition*/, {},
- wizard, bucketStartTimeNs);
+ wizard, protoHash, bucketStartTimeNs);
eventProducer.onMatchedLogEvent(1 /*matcher index*/, event1);
eventProducer.onMatchedLogEvent(1 /*matcher index*/, event2);
@@ -102,7 +104,8 @@ TEST(EventMetricProducerTest, TestEventsWithNonSlicedCondition) {
sp<MockConditionWizard> wizard = new NaggyMock<MockConditionWizard>();
EventMetricProducer eventProducer(kConfigKey, metric, 0 /*condition index*/,
- {ConditionState::kUnknown}, wizard, bucketStartTimeNs);
+ {ConditionState::kUnknown}, wizard, protoHash,
+ bucketStartTimeNs);
eventProducer.onConditionChanged(true /*condition*/, bucketStartTimeNs);
eventProducer.onMatchedLogEvent(1 /*matcher index*/, event1);
@@ -157,7 +160,8 @@ TEST(EventMetricProducerTest, TestEventsWithSlicedCondition) {
EXPECT_CALL(*wizard, query(_, key2, _)).WillOnce(Return(ConditionState::kTrue));
EventMetricProducer eventProducer(kConfigKey, metric, 0 /*condition index*/,
- {ConditionState::kUnknown}, wizard, bucketStartTimeNs);
+ {ConditionState::kUnknown}, wizard, protoHash,
+ bucketStartTimeNs);
eventProducer.onMatchedLogEvent(1 /*matcher index*/, event1);
eventProducer.onMatchedLogEvent(1 /*matcher index*/, event2);
diff --git a/cmds/statsd/tests/metrics/GaugeMetricProducer_test.cpp b/cmds/statsd/tests/metrics/GaugeMetricProducer_test.cpp
index ba919f1e0ad8..10606810d806 100644
--- a/cmds/statsd/tests/metrics/GaugeMetricProducer_test.cpp
+++ b/cmds/statsd/tests/metrics/GaugeMetricProducer_test.cpp
@@ -47,6 +47,7 @@ namespace {
const ConfigKey kConfigKey(0, 12345);
const int tagId = 1;
const int64_t metricId = 123;
+const uint64_t protoHash = 0x123456789;
const int logEventMatcherIndex = 0;
const int64_t bucketStartTimeNs = 10 * NS_PER_SEC;
const int64_t bucketSizeNs = TimeUnitToBucketSizeInMillis(ONE_MINUTE) * 1000000LL;
@@ -101,8 +102,9 @@ TEST(GaugeMetricProducerTest, TestFirstBucket) {
// statsd started long ago.
// The metric starts in the middle of the bucket
GaugeMetricProducer gaugeProducer(kConfigKey, metric, -1 /*-1 meaning no condition*/, {},
- wizard, logEventMatcherIndex, eventMatcherWizard, -1, -1,
- tagId, 5, 600 * NS_PER_SEC + NS_PER_SEC / 2, pullerManager);
+ wizard, protoHash, logEventMatcherIndex, eventMatcherWizard,
+ -1, -1, tagId, 5, 600 * NS_PER_SEC + NS_PER_SEC / 2,
+ pullerManager);
gaugeProducer.prepareFirstBucket();
EXPECT_EQ(600500000000, gaugeProducer.mCurrentBucketStartTimeNs);
@@ -139,8 +141,9 @@ TEST(GaugeMetricProducerTest, TestPulledEventsNoCondition) {
}));
GaugeMetricProducer gaugeProducer(kConfigKey, metric, -1 /*-1 meaning no condition*/, {},
- wizard, logEventMatcherIndex, eventMatcherWizard, tagId, -1,
- tagId, bucketStartTimeNs, bucketStartTimeNs, pullerManager);
+ wizard, protoHash, logEventMatcherIndex, eventMatcherWizard,
+ tagId, -1, tagId, bucketStartTimeNs, bucketStartTimeNs,
+ pullerManager);
gaugeProducer.prepareFirstBucket();
vector<shared_ptr<LogEvent>> allData;
@@ -213,7 +216,7 @@ TEST_P(GaugeMetricProducerTest_PartialBucket, TestPushedEvents) {
createEventMatcherWizard(tagId, logEventMatcherIndex);
GaugeMetricProducer gaugeProducer(kConfigKey, metric, -1 /*-1 meaning no condition*/, {},
- wizard, logEventMatcherIndex, eventMatcherWizard,
+ wizard, protoHash, logEventMatcherIndex, eventMatcherWizard,
-1 /* -1 means no pulling */, -1, tagId, bucketStartTimeNs,
bucketStartTimeNs, pullerManager);
gaugeProducer.prepareFirstBucket();
@@ -306,8 +309,9 @@ TEST_P(GaugeMetricProducerTest_PartialBucket, TestPulled) {
}));
GaugeMetricProducer gaugeProducer(kConfigKey, metric, -1 /*-1 meaning no condition*/, {},
- wizard, logEventMatcherIndex, eventMatcherWizard, tagId, -1,
- tagId, bucketStartTimeNs, bucketStartTimeNs, pullerManager);
+ wizard, protoHash, logEventMatcherIndex, eventMatcherWizard,
+ tagId, -1, tagId, bucketStartTimeNs, bucketStartTimeNs,
+ pullerManager);
gaugeProducer.prepareFirstBucket();
vector<shared_ptr<LogEvent>> allData;
@@ -373,8 +377,9 @@ TEST(GaugeMetricProducerTest, TestPulledWithAppUpgradeDisabled) {
.WillOnce(Return(false));
GaugeMetricProducer gaugeProducer(kConfigKey, metric, -1 /*-1 meaning no condition*/, {},
- wizard, logEventMatcherIndex, eventMatcherWizard, tagId, -1,
- tagId, bucketStartTimeNs, bucketStartTimeNs, pullerManager);
+ wizard, protoHash, logEventMatcherIndex, eventMatcherWizard,
+ tagId, -1, tagId, bucketStartTimeNs, bucketStartTimeNs,
+ pullerManager);
gaugeProducer.prepareFirstBucket();
vector<shared_ptr<LogEvent>> allData;
@@ -426,9 +431,9 @@ TEST(GaugeMetricProducerTest, TestPulledEventsWithCondition) {
}));
GaugeMetricProducer gaugeProducer(kConfigKey, metric, 0 /*condition index*/,
- {ConditionState::kUnknown}, wizard, logEventMatcherIndex,
- eventMatcherWizard, tagId, -1, tagId, bucketStartTimeNs,
- bucketStartTimeNs, pullerManager);
+ {ConditionState::kUnknown}, wizard, protoHash,
+ logEventMatcherIndex, eventMatcherWizard, tagId, -1, tagId,
+ bucketStartTimeNs, bucketStartTimeNs, pullerManager);
gaugeProducer.prepareFirstBucket();
gaugeProducer.onConditionChanged(true, conditionChangeNs);
@@ -509,9 +514,9 @@ TEST(GaugeMetricProducerTest, TestPulledEventsWithSlicedCondition) {
}));
GaugeMetricProducer gaugeProducer(kConfigKey, metric, 0 /*condition index*/,
- {ConditionState::kUnknown}, wizard, logEventMatcherIndex,
- eventMatcherWizard, tagId, -1, tagId, bucketStartTimeNs,
- bucketStartTimeNs, pullerManager);
+ {ConditionState::kUnknown}, wizard, protoHash,
+ logEventMatcherIndex, eventMatcherWizard, tagId, -1, tagId,
+ bucketStartTimeNs, bucketStartTimeNs, pullerManager);
gaugeProducer.prepareFirstBucket();
gaugeProducer.onSlicedConditionMayChange(true, sliceConditionChangeNs);
@@ -554,8 +559,9 @@ TEST(GaugeMetricProducerTest, TestPulledEventsAnomalyDetection) {
createEventMatcherWizard(tagId, logEventMatcherIndex);
GaugeMetricProducer gaugeProducer(kConfigKey, metric, -1 /*-1 meaning no condition*/, {},
- wizard, logEventMatcherIndex, eventMatcherWizard, tagId, -1,
- tagId, bucketStartTimeNs, bucketStartTimeNs, pullerManager);
+ wizard, protoHash, logEventMatcherIndex, eventMatcherWizard,
+ tagId, -1, tagId, bucketStartTimeNs, bucketStartTimeNs,
+ pullerManager);
gaugeProducer.prepareFirstBucket();
Alert alert;
@@ -649,8 +655,8 @@ TEST(GaugeMetricProducerTest, TestPullOnTrigger) {
int triggerId = 5;
GaugeMetricProducer gaugeProducer(kConfigKey, metric, -1 /*-1 meaning no condition*/, {},
- wizard, logEventMatcherIndex, eventMatcherWizard, tagId,
- triggerId, tagId, bucketStartTimeNs, bucketStartTimeNs,
+ wizard, protoHash, logEventMatcherIndex, eventMatcherWizard,
+ tagId, triggerId, tagId, bucketStartTimeNs, bucketStartTimeNs,
pullerManager);
gaugeProducer.prepareFirstBucket();
@@ -724,8 +730,8 @@ TEST(GaugeMetricProducerTest, TestRemoveDimensionInOutput) {
int triggerId = 5;
GaugeMetricProducer gaugeProducer(kConfigKey, metric, -1 /*-1 meaning no condition*/, {},
- wizard, logEventMatcherIndex, eventMatcherWizard, tagId,
- triggerId, tagId, bucketStartTimeNs, bucketStartTimeNs,
+ wizard, protoHash, logEventMatcherIndex, eventMatcherWizard,
+ tagId, triggerId, tagId, bucketStartTimeNs, bucketStartTimeNs,
pullerManager);
gaugeProducer.prepareFirstBucket();
@@ -783,8 +789,8 @@ TEST(GaugeMetricProducerTest_BucketDrop, TestBucketDropWhenBucketTooSmall) {
int triggerId = 5;
GaugeMetricProducer gaugeProducer(kConfigKey, metric, -1 /*-1 meaning no condition*/, {},
- wizard, logEventMatcherIndex, eventMatcherWizard, tagId,
- triggerId, tagId, bucketStartTimeNs, bucketStartTimeNs,
+ wizard, protoHash, logEventMatcherIndex, eventMatcherWizard,
+ tagId, triggerId, tagId, bucketStartTimeNs, bucketStartTimeNs,
pullerManager);
gaugeProducer.prepareFirstBucket();
diff --git a/cmds/statsd/tests/metrics/ValueMetricProducer_test.cpp b/cmds/statsd/tests/metrics/ValueMetricProducer_test.cpp
index 1000aea14868..b166cc1fe04e 100644
--- a/cmds/statsd/tests/metrics/ValueMetricProducer_test.cpp
+++ b/cmds/statsd/tests/metrics/ValueMetricProducer_test.cpp
@@ -46,6 +46,7 @@ namespace {
const ConfigKey kConfigKey(0, 12345);
const int tagId = 1;
const int64_t metricId = 123;
+const uint64_t protoHash = 0x1234567890;
const int logEventMatcherIndex = 0;
const int64_t bucketStartTimeNs = 10000000000;
const int64_t bucketSizeNs = TimeUnitToBucketSizeInMillis(ONE_MINUTE) * 1000000LL;
@@ -57,7 +58,7 @@ const int64_t bucket6StartTimeNs = bucketStartTimeNs + 5 * bucketSizeNs;
double epsilon = 0.001;
static void assertPastBucketValuesSingleKey(
- const std::unordered_map<MetricDimensionKey, std::vector<ValueBucket>>& mPastBuckets,
+ const std::unordered_map<MetricDimensionKey, std::vector<PastValueBucket>>& mPastBuckets,
const std::initializer_list<int>& expectedValuesList,
const std::initializer_list<int64_t>& expectedDurationNsList,
const std::initializer_list<int64_t>& expectedStartTimeNsList,
@@ -79,7 +80,7 @@ static void assertPastBucketValuesSingleKey(
ASSERT_EQ(1, mPastBuckets.size());
ASSERT_EQ(expectedValues.size(), mPastBuckets.begin()->second.size());
- const vector<ValueBucket>& buckets = mPastBuckets.begin()->second;
+ const vector<PastValueBucket>& buckets = mPastBuckets.begin()->second;
for (int i = 0; i < expectedValues.size(); i++) {
EXPECT_EQ(expectedValues[i], buckets[i].values[0].long_value)
<< "Values differ at index " << i;
@@ -108,8 +109,8 @@ public:
sp<ValueMetricProducer> valueProducer =
new ValueMetricProducer(kConfigKey, metric, -1 /*-1 meaning no condition*/, {},
- wizard, logEventMatcherIndex, eventMatcherWizard, tagId,
- bucketStartTimeNs, bucketStartTimeNs, pullerManager);
+ wizard, protoHash, logEventMatcherIndex, eventMatcherWizard,
+ tagId, bucketStartTimeNs, bucketStartTimeNs, pullerManager);
valueProducer->prepareFirstBucket();
return valueProducer;
}
@@ -127,7 +128,7 @@ public:
sp<ValueMetricProducer> valueProducer = new ValueMetricProducer(
kConfigKey, metric, 0 /*condition index*/, {ConditionState::kUnknown}, wizard,
- logEventMatcherIndex, eventMatcherWizard, tagId, bucketStartTimeNs,
+ protoHash, logEventMatcherIndex, eventMatcherWizard, tagId, bucketStartTimeNs,
bucketStartTimeNs, pullerManager);
valueProducer->prepareFirstBucket();
valueProducer->mCondition = conditionAfterFirstBucketPrepared;
@@ -147,9 +148,9 @@ public:
.WillRepeatedly(Return());
sp<ValueMetricProducer> valueProducer = new ValueMetricProducer(
- kConfigKey, metric, -1 /* no condition */, {}, wizard, logEventMatcherIndex,
- eventMatcherWizard, tagId, bucketStartTimeNs, bucketStartTimeNs, pullerManager, {},
- {}, slicedStateAtoms, stateGroupMap);
+ kConfigKey, metric, -1 /* no condition */, {}, wizard, protoHash,
+ logEventMatcherIndex, eventMatcherWizard, tagId, bucketStartTimeNs,
+ bucketStartTimeNs, pullerManager, {}, {}, slicedStateAtoms, stateGroupMap);
valueProducer->prepareFirstBucket();
return valueProducer;
}
@@ -169,8 +170,9 @@ public:
sp<ValueMetricProducer> valueProducer = new ValueMetricProducer(
kConfigKey, metric, 0 /* condition tracker index */, {ConditionState::kUnknown},
- wizard, logEventMatcherIndex, eventMatcherWizard, tagId, bucketStartTimeNs,
- bucketStartTimeNs, pullerManager, {}, {}, slicedStateAtoms, stateGroupMap);
+ wizard, protoHash, logEventMatcherIndex, eventMatcherWizard, tagId,
+ bucketStartTimeNs, bucketStartTimeNs, pullerManager, {}, {}, slicedStateAtoms,
+ stateGroupMap);
valueProducer->prepareFirstBucket();
valueProducer->mCondition = conditionAfterFirstBucketPrepared;
return valueProducer;
@@ -228,8 +230,8 @@ TEST(ValueMetricProducerTest, TestCalcPreviousBucketEndTime) {
// statsd started long ago.
// The metric starts in the middle of the bucket
ValueMetricProducer valueProducer(kConfigKey, metric, -1 /*-1 meaning no condition*/, {},
- wizard, logEventMatcherIndex, eventMatcherWizard, -1,
- startTimeBase, 22, pullerManager);
+ wizard, protoHash, logEventMatcherIndex, eventMatcherWizard,
+ -1, startTimeBase, 22, pullerManager);
valueProducer.prepareFirstBucket();
EXPECT_EQ(startTimeBase, valueProducer.calcPreviousBucketEndTime(60 * NS_PER_SEC + 10));
@@ -254,8 +256,8 @@ TEST(ValueMetricProducerTest, TestFirstBucket) {
// statsd started long ago.
// The metric starts in the middle of the bucket
ValueMetricProducer valueProducer(kConfigKey, metric, -1 /*-1 meaning no condition*/, {},
- wizard, logEventMatcherIndex, eventMatcherWizard, -1, 5,
- 600 * NS_PER_SEC + NS_PER_SEC / 2, pullerManager);
+ wizard, protoHash, logEventMatcherIndex, eventMatcherWizard,
+ -1, 5, 600 * NS_PER_SEC + NS_PER_SEC / 2, pullerManager);
valueProducer.prepareFirstBucket();
EXPECT_EQ(600500000000, valueProducer.mCurrentBucketStartTimeNs);
@@ -288,8 +290,9 @@ TEST(ValueMetricProducerTest, TestPulledEventsNoCondition) {
// has one slice
ASSERT_EQ(1UL, valueProducer->mCurrentSlicedBucket.size());
ValueMetricProducer::Interval curInterval =
- valueProducer->mCurrentSlicedBucket.begin()->second[0];
- ValueMetricProducer::BaseInfo curBaseInfo = valueProducer->mCurrentBaseInfo.begin()->second[0];
+ valueProducer->mCurrentSlicedBucket.begin()->second.intervals[0];
+ ValueMetricProducer::BaseInfo curBaseInfo =
+ valueProducer->mCurrentBaseInfo.begin()->second.baseInfos[0];
EXPECT_EQ(true, curBaseInfo.hasBase);
EXPECT_EQ(11, curBaseInfo.base.long_value);
@@ -304,8 +307,8 @@ TEST(ValueMetricProducerTest, TestPulledEventsNoCondition) {
valueProducer->onDataPulled(allData, /** succeed */ true, bucket3StartTimeNs);
// has one slice
ASSERT_EQ(1UL, valueProducer->mCurrentSlicedBucket.size());
- curInterval = valueProducer->mCurrentSlicedBucket.begin()->second[0];
- curBaseInfo = valueProducer->mCurrentBaseInfo.begin()->second[0];
+ curInterval = valueProducer->mCurrentSlicedBucket.begin()->second.intervals[0];
+ curBaseInfo = valueProducer->mCurrentBaseInfo.begin()->second.baseInfos[0];
EXPECT_EQ(true, curBaseInfo.hasBase);
EXPECT_EQ(23, curBaseInfo.base.long_value);
@@ -322,8 +325,8 @@ TEST(ValueMetricProducerTest, TestPulledEventsNoCondition) {
allData.push_back(CreateRepeatedValueLogEvent(tagId, bucket4StartTimeNs + 1, 36));
valueProducer->onDataPulled(allData, /** succeed */ true, bucket4StartTimeNs);
ASSERT_EQ(1UL, valueProducer->mCurrentSlicedBucket.size());
- curInterval = valueProducer->mCurrentSlicedBucket.begin()->second[0];
- curBaseInfo = valueProducer->mCurrentBaseInfo.begin()->second[0];
+ curInterval = valueProducer->mCurrentSlicedBucket.begin()->second.intervals[0];
+ curBaseInfo = valueProducer->mCurrentBaseInfo.begin()->second.baseInfos[0];
EXPECT_EQ(true, curBaseInfo.hasBase);
EXPECT_EQ(36, curBaseInfo.base.long_value);
@@ -413,9 +416,10 @@ TEST(ValueMetricProducerTest, TestPulledEventsWithFiltering) {
return true;
}));
- sp<ValueMetricProducer> valueProducer = new ValueMetricProducer(
- kConfigKey, metric, -1 /*-1 meaning no condition*/, {}, wizard, logEventMatcherIndex,
- eventMatcherWizard, tagId, bucketStartTimeNs, bucketStartTimeNs, pullerManager);
+ sp<ValueMetricProducer> valueProducer =
+ new ValueMetricProducer(kConfigKey, metric, -1 /*-1 meaning no condition*/, {}, wizard,
+ protoHash, logEventMatcherIndex, eventMatcherWizard, tagId,
+ bucketStartTimeNs, bucketStartTimeNs, pullerManager);
valueProducer->prepareFirstBucket();
vector<shared_ptr<LogEvent>> allData;
@@ -426,8 +430,9 @@ TEST(ValueMetricProducerTest, TestPulledEventsWithFiltering) {
// has one slice
ASSERT_EQ(1UL, valueProducer->mCurrentSlicedBucket.size());
ValueMetricProducer::Interval curInterval =
- valueProducer->mCurrentSlicedBucket.begin()->second[0];
- ValueMetricProducer::BaseInfo curBaseInfo = valueProducer->mCurrentBaseInfo.begin()->second[0];
+ valueProducer->mCurrentSlicedBucket.begin()->second.intervals[0];
+ ValueMetricProducer::BaseInfo curBaseInfo =
+ valueProducer->mCurrentBaseInfo.begin()->second.baseInfos[0];
EXPECT_EQ(true, curBaseInfo.hasBase);
EXPECT_EQ(11, curBaseInfo.base.long_value);
@@ -455,8 +460,8 @@ TEST(ValueMetricProducerTest, TestPulledEventsWithFiltering) {
allData.push_back(CreateTwoValueLogEvent(tagId, bucket4StartTimeNs + 1, 3, 36));
valueProducer->onDataPulled(allData, /** succeed */ true, bucket4StartTimeNs);
ASSERT_EQ(1UL, valueProducer->mCurrentSlicedBucket.size());
- curInterval = valueProducer->mCurrentSlicedBucket.begin()->second[0];
- curBaseInfo = valueProducer->mCurrentBaseInfo.begin()->second[0];
+ curInterval = valueProducer->mCurrentSlicedBucket.begin()->second.intervals[0];
+ curBaseInfo = valueProducer->mCurrentBaseInfo.begin()->second.baseInfos[0];
// the base was reset
EXPECT_EQ(true, curBaseInfo.hasBase);
@@ -489,8 +494,9 @@ TEST(ValueMetricProducerTest, TestPulledEventsTakeAbsoluteValueOnReset) {
// has one slice
ASSERT_EQ(1UL, valueProducer->mCurrentSlicedBucket.size());
ValueMetricProducer::Interval curInterval =
- valueProducer->mCurrentSlicedBucket.begin()->second[0];
- ValueMetricProducer::BaseInfo curBaseInfo = valueProducer->mCurrentBaseInfo.begin()->second[0];
+ valueProducer->mCurrentSlicedBucket.begin()->second.intervals[0];
+ ValueMetricProducer::BaseInfo curBaseInfo =
+ valueProducer->mCurrentBaseInfo.begin()->second.baseInfos[0];
EXPECT_EQ(true, curBaseInfo.hasBase);
EXPECT_EQ(11, curBaseInfo.base.long_value);
@@ -502,8 +508,8 @@ TEST(ValueMetricProducerTest, TestPulledEventsTakeAbsoluteValueOnReset) {
valueProducer->onDataPulled(allData, /** succeed */ true, bucket3StartTimeNs);
// has one slice
ASSERT_EQ(1UL, valueProducer->mCurrentSlicedBucket.size());
- curInterval = valueProducer->mCurrentSlicedBucket.begin()->second[0];
- curBaseInfo = valueProducer->mCurrentBaseInfo.begin()->second[0];
+ curInterval = valueProducer->mCurrentSlicedBucket.begin()->second.intervals[0];
+ curBaseInfo = valueProducer->mCurrentBaseInfo.begin()->second.baseInfos[0];
EXPECT_EQ(true, curBaseInfo.hasBase);
EXPECT_EQ(10, curBaseInfo.base.long_value);
EXPECT_EQ(false, curInterval.hasValue);
@@ -516,8 +522,8 @@ TEST(ValueMetricProducerTest, TestPulledEventsTakeAbsoluteValueOnReset) {
allData.push_back(CreateRepeatedValueLogEvent(tagId, bucket4StartTimeNs + 1, 36));
valueProducer->onDataPulled(allData, /** succeed */ true, bucket4StartTimeNs);
ASSERT_EQ(1UL, valueProducer->mCurrentSlicedBucket.size());
- curInterval = valueProducer->mCurrentSlicedBucket.begin()->second[0];
- curBaseInfo = valueProducer->mCurrentBaseInfo.begin()->second[0];
+ curInterval = valueProducer->mCurrentSlicedBucket.begin()->second.intervals[0];
+ curBaseInfo = valueProducer->mCurrentBaseInfo.begin()->second.baseInfos[0];
EXPECT_EQ(true, curBaseInfo.hasBase);
EXPECT_EQ(36, curBaseInfo.base.long_value);
EXPECT_EQ(false, curInterval.hasValue);
@@ -549,8 +555,9 @@ TEST(ValueMetricProducerTest, TestPulledEventsTakeZeroOnReset) {
// has one slice
ASSERT_EQ(1UL, valueProducer->mCurrentSlicedBucket.size());
ValueMetricProducer::Interval curInterval =
- valueProducer->mCurrentSlicedBucket.begin()->second[0];
- ValueMetricProducer::BaseInfo curBaseInfo = valueProducer->mCurrentBaseInfo.begin()->second[0];
+ valueProducer->mCurrentSlicedBucket.begin()->second.intervals[0];
+ ValueMetricProducer::BaseInfo curBaseInfo =
+ valueProducer->mCurrentBaseInfo.begin()->second.baseInfos[0];
EXPECT_EQ(true, curBaseInfo.hasBase);
EXPECT_EQ(11, curBaseInfo.base.long_value);
@@ -562,8 +569,8 @@ TEST(ValueMetricProducerTest, TestPulledEventsTakeZeroOnReset) {
valueProducer->onDataPulled(allData, /** succeed */ true, bucket3StartTimeNs);
// has one slice
ASSERT_EQ(1UL, valueProducer->mCurrentSlicedBucket.size());
- curInterval = valueProducer->mCurrentSlicedBucket.begin()->second[0];
- curBaseInfo = valueProducer->mCurrentBaseInfo.begin()->second[0];
+ curInterval = valueProducer->mCurrentSlicedBucket.begin()->second.intervals[0];
+ curBaseInfo = valueProducer->mCurrentBaseInfo.begin()->second.baseInfos[0];
EXPECT_EQ(true, curBaseInfo.hasBase);
EXPECT_EQ(10, curBaseInfo.base.long_value);
EXPECT_EQ(false, curInterval.hasValue);
@@ -573,8 +580,8 @@ TEST(ValueMetricProducerTest, TestPulledEventsTakeZeroOnReset) {
allData.push_back(CreateRepeatedValueLogEvent(tagId, bucket4StartTimeNs + 1, 36));
valueProducer->onDataPulled(allData, /** succeed */ true, bucket4StartTimeNs);
ASSERT_EQ(1UL, valueProducer->mCurrentSlicedBucket.size());
- curInterval = valueProducer->mCurrentSlicedBucket.begin()->second[0];
- curBaseInfo = valueProducer->mCurrentBaseInfo.begin()->second[0];
+ curInterval = valueProducer->mCurrentSlicedBucket.begin()->second.intervals[0];
+ curBaseInfo = valueProducer->mCurrentBaseInfo.begin()->second.baseInfos[0];
EXPECT_EQ(true, curBaseInfo.hasBase);
EXPECT_EQ(36, curBaseInfo.base.long_value);
EXPECT_EQ(false, curInterval.hasValue);
@@ -624,8 +631,9 @@ TEST(ValueMetricProducerTest, TestEventsWithNonSlicedCondition) {
// has one slice
ASSERT_EQ(1UL, valueProducer->mCurrentSlicedBucket.size());
ValueMetricProducer::Interval curInterval =
- valueProducer->mCurrentSlicedBucket.begin()->second[0];
- ValueMetricProducer::BaseInfo curBaseInfo = valueProducer->mCurrentBaseInfo.begin()->second[0];
+ valueProducer->mCurrentSlicedBucket.begin()->second.intervals[0];
+ ValueMetricProducer::BaseInfo curBaseInfo =
+ valueProducer->mCurrentBaseInfo.begin()->second.baseInfos[0];
// startUpdated:false sum:0 start:100
EXPECT_EQ(true, curBaseInfo.hasBase);
EXPECT_EQ(100, curBaseInfo.base.long_value);
@@ -641,8 +649,8 @@ TEST(ValueMetricProducerTest, TestEventsWithNonSlicedCondition) {
// has one slice
ASSERT_EQ(1UL, valueProducer->mCurrentSlicedBucket.size());
- curInterval = valueProducer->mCurrentSlicedBucket.begin()->second[0];
- curBaseInfo = valueProducer->mCurrentBaseInfo.begin()->second[0];
+ curInterval = valueProducer->mCurrentSlicedBucket.begin()->second.intervals[0];
+ curBaseInfo = valueProducer->mCurrentBaseInfo.begin()->second.baseInfos[0];
EXPECT_EQ(true, curBaseInfo.hasBase);
EXPECT_EQ(110, curBaseInfo.base.long_value);
EXPECT_EQ(false, curInterval.hasValue);
@@ -654,8 +662,8 @@ TEST(ValueMetricProducerTest, TestEventsWithNonSlicedCondition) {
// has one slice
ASSERT_EQ(1UL, valueProducer->mCurrentSlicedBucket.size());
- curInterval = valueProducer->mCurrentSlicedBucket.begin()->second[0];
- curBaseInfo = valueProducer->mCurrentBaseInfo.begin()->second[0];
+ curInterval = valueProducer->mCurrentSlicedBucket.begin()->second.intervals[0];
+ curBaseInfo = valueProducer->mCurrentBaseInfo.begin()->second.baseInfos[0];
EXPECT_EQ(true, curInterval.hasValue);
EXPECT_EQ(20, curInterval.value.long_value);
EXPECT_EQ(false, curBaseInfo.hasBase);
@@ -674,9 +682,9 @@ TEST_P(ValueMetricProducerTest_PartialBucket, TestPushedEvents) {
sp<MockConditionWizard> wizard = new NaggyMock<MockConditionWizard>();
sp<MockStatsPullerManager> pullerManager = new StrictMock<MockStatsPullerManager>();
- ValueMetricProducer valueProducer(kConfigKey, metric, -1, {}, wizard, logEventMatcherIndex,
- eventMatcherWizard, -1, bucketStartTimeNs, bucketStartTimeNs,
- pullerManager);
+ ValueMetricProducer valueProducer(kConfigKey, metric, -1, {}, wizard, protoHash,
+ logEventMatcherIndex, eventMatcherWizard, -1,
+ bucketStartTimeNs, bucketStartTimeNs, pullerManager);
valueProducer.prepareFirstBucket();
LogEvent event1(/*uid=*/0, /*pid=*/0);
@@ -744,9 +752,9 @@ TEST_P(ValueMetricProducerTest_PartialBucket, TestPulledValue) {
return true;
}));
- ValueMetricProducer valueProducer(kConfigKey, metric, -1, {}, wizard, logEventMatcherIndex,
- eventMatcherWizard, tagId, bucketStartTimeNs,
- bucketStartTimeNs, pullerManager);
+ ValueMetricProducer valueProducer(kConfigKey, metric, -1, {}, wizard, protoHash,
+ logEventMatcherIndex, eventMatcherWizard, tagId,
+ bucketStartTimeNs, bucketStartTimeNs, pullerManager);
valueProducer.prepareFirstBucket();
vector<shared_ptr<LogEvent>> allData;
@@ -792,9 +800,9 @@ TEST(ValueMetricProducerTest, TestPulledWithAppUpgradeDisabled) {
EXPECT_CALL(*pullerManager, Pull(tagId, kConfigKey, bucketStartTimeNs, _))
.WillOnce(Return(true));
- ValueMetricProducer valueProducer(kConfigKey, metric, -1, {}, wizard, logEventMatcherIndex,
- eventMatcherWizard, tagId, bucketStartTimeNs,
- bucketStartTimeNs, pullerManager);
+ ValueMetricProducer valueProducer(kConfigKey, metric, -1, {}, wizard, protoHash,
+ logEventMatcherIndex, eventMatcherWizard, tagId,
+ bucketStartTimeNs, bucketStartTimeNs, pullerManager);
valueProducer.prepareFirstBucket();
vector<shared_ptr<LogEvent>> allData;
@@ -864,9 +872,9 @@ TEST(ValueMetricProducerTest, TestPushedEventsWithoutCondition) {
sp<MockConditionWizard> wizard = new NaggyMock<MockConditionWizard>();
sp<MockStatsPullerManager> pullerManager = new StrictMock<MockStatsPullerManager>();
- ValueMetricProducer valueProducer(kConfigKey, metric, -1, {}, wizard, logEventMatcherIndex,
- eventMatcherWizard, -1, bucketStartTimeNs, bucketStartTimeNs,
- pullerManager);
+ ValueMetricProducer valueProducer(kConfigKey, metric, -1, {}, wizard, protoHash,
+ logEventMatcherIndex, eventMatcherWizard, -1,
+ bucketStartTimeNs, bucketStartTimeNs, pullerManager);
valueProducer.prepareFirstBucket();
LogEvent event1(/*uid=*/0, /*pid=*/0);
@@ -879,8 +887,9 @@ TEST(ValueMetricProducerTest, TestPushedEventsWithoutCondition) {
// has one slice
ASSERT_EQ(1UL, valueProducer.mCurrentSlicedBucket.size());
ValueMetricProducer::Interval curInterval =
- valueProducer.mCurrentSlicedBucket.begin()->second[0];
- ValueMetricProducer::BaseInfo curBaseInfo = valueProducer.mCurrentBaseInfo.begin()->second[0];
+ valueProducer.mCurrentSlicedBucket.begin()->second.intervals[0];
+ ValueMetricProducer::BaseInfo curBaseInfo =
+ valueProducer.mCurrentBaseInfo.begin()->second.baseInfos[0];
EXPECT_EQ(10, curInterval.value.long_value);
EXPECT_EQ(true, curInterval.hasValue);
@@ -888,7 +897,7 @@ TEST(ValueMetricProducerTest, TestPushedEventsWithoutCondition) {
// has one slice
ASSERT_EQ(1UL, valueProducer.mCurrentSlicedBucket.size());
- curInterval = valueProducer.mCurrentSlicedBucket.begin()->second[0];
+ curInterval = valueProducer.mCurrentSlicedBucket.begin()->second.intervals[0];
EXPECT_EQ(30, curInterval.value.long_value);
valueProducer.flushIfNeededLocked(bucket2StartTimeNs);
@@ -905,7 +914,7 @@ TEST(ValueMetricProducerTest, TestPushedEventsWithCondition) {
sp<MockStatsPullerManager> pullerManager = new StrictMock<MockStatsPullerManager>();
ValueMetricProducer valueProducer(kConfigKey, metric, 0, {ConditionState::kUnknown}, wizard,
- logEventMatcherIndex, eventMatcherWizard, -1,
+ protoHash, logEventMatcherIndex, eventMatcherWizard, -1,
bucketStartTimeNs, bucketStartTimeNs, pullerManager);
valueProducer.prepareFirstBucket();
valueProducer.mCondition = ConditionState::kFalse;
@@ -925,8 +934,8 @@ TEST(ValueMetricProducerTest, TestPushedEventsWithCondition) {
// has one slice
ASSERT_EQ(1UL, valueProducer.mCurrentSlicedBucket.size());
ValueMetricProducer::Interval curInterval =
- valueProducer.mCurrentSlicedBucket.begin()->second[0];
- curInterval = valueProducer.mCurrentSlicedBucket.begin()->second[0];
+ valueProducer.mCurrentSlicedBucket.begin()->second.intervals[0];
+ curInterval = valueProducer.mCurrentSlicedBucket.begin()->second.intervals[0];
EXPECT_EQ(20, curInterval.value.long_value);
LogEvent event3(/*uid=*/0, /*pid=*/0);
@@ -935,7 +944,7 @@ TEST(ValueMetricProducerTest, TestPushedEventsWithCondition) {
// has one slice
ASSERT_EQ(1UL, valueProducer.mCurrentSlicedBucket.size());
- curInterval = valueProducer.mCurrentSlicedBucket.begin()->second[0];
+ curInterval = valueProducer.mCurrentSlicedBucket.begin()->second.intervals[0];
EXPECT_EQ(50, curInterval.value.long_value);
valueProducer.onConditionChangedLocked(false, bucketStartTimeNs + 35);
@@ -946,7 +955,7 @@ TEST(ValueMetricProducerTest, TestPushedEventsWithCondition) {
// has one slice
ASSERT_EQ(1UL, valueProducer.mCurrentSlicedBucket.size());
- curInterval = valueProducer.mCurrentSlicedBucket.begin()->second[0];
+ curInterval = valueProducer.mCurrentSlicedBucket.begin()->second.intervals[0];
EXPECT_EQ(50, curInterval.value.long_value);
valueProducer.flushIfNeededLocked(bucket2StartTimeNs);
@@ -972,7 +981,7 @@ TEST(ValueMetricProducerTest, TestAnomalyDetection) {
sp<MockStatsPullerManager> pullerManager = new StrictMock<MockStatsPullerManager>();
ValueMetricProducer valueProducer(kConfigKey, metric, -1 /*-1 meaning no condition*/, {},
- wizard, logEventMatcherIndex, eventMatcherWizard,
+ wizard, protoHash, logEventMatcherIndex, eventMatcherWizard,
-1 /*not pulled*/, bucketStartTimeNs, bucketStartTimeNs,
pullerManager);
valueProducer.prepareFirstBucket();
@@ -1089,8 +1098,9 @@ TEST(ValueMetricProducerTest, TestBucketBoundaryNoCondition) {
// has one slice
ASSERT_EQ(1UL, valueProducer->mCurrentSlicedBucket.size());
ValueMetricProducer::Interval curInterval =
- valueProducer->mCurrentSlicedBucket.begin()->second[0];
- ValueMetricProducer::BaseInfo curBaseInfo = valueProducer->mCurrentBaseInfo.begin()->second[0];
+ valueProducer->mCurrentSlicedBucket.begin()->second.intervals[0];
+ ValueMetricProducer::BaseInfo curBaseInfo =
+ valueProducer->mCurrentBaseInfo.begin()->second.baseInfos[0];
// startUpdated:true sum:0 start:11
EXPECT_EQ(true, curBaseInfo.hasBase);
@@ -1104,8 +1114,8 @@ TEST(ValueMetricProducerTest, TestBucketBoundaryNoCondition) {
valueProducer->onDataPulled(allData, /** succeed */ true, bucket3StartTimeNs);
// has one slice
ASSERT_EQ(1UL, valueProducer->mCurrentSlicedBucket.size());
- curInterval = valueProducer->mCurrentSlicedBucket.begin()->second[0];
- curBaseInfo = valueProducer->mCurrentBaseInfo.begin()->second[0];
+ curInterval = valueProducer->mCurrentSlicedBucket.begin()->second.intervals[0];
+ curBaseInfo = valueProducer->mCurrentBaseInfo.begin()->second.baseInfos[0];
// tartUpdated:false sum:12
EXPECT_EQ(true, curBaseInfo.hasBase);
EXPECT_EQ(23, curBaseInfo.base.long_value);
@@ -1121,8 +1131,8 @@ TEST(ValueMetricProducerTest, TestBucketBoundaryNoCondition) {
allData.push_back(CreateRepeatedValueLogEvent(tagId, bucket6StartTimeNs + 1, 36));
valueProducer->onDataPulled(allData, /** succeed */ true, bucket6StartTimeNs);
ASSERT_EQ(1UL, valueProducer->mCurrentSlicedBucket.size());
- curInterval = valueProducer->mCurrentSlicedBucket.begin()->second[0];
- curBaseInfo = valueProducer->mCurrentBaseInfo.begin()->second[0];
+ curInterval = valueProducer->mCurrentSlicedBucket.begin()->second.intervals[0];
+ curBaseInfo = valueProducer->mCurrentBaseInfo.begin()->second.baseInfos[0];
// startUpdated:false sum:12
EXPECT_EQ(true, curBaseInfo.hasBase);
EXPECT_EQ(36, curBaseInfo.base.long_value);
@@ -1180,8 +1190,9 @@ TEST(ValueMetricProducerTest, TestBucketBoundaryWithCondition) {
// has one slice
ASSERT_EQ(1UL, valueProducer->mCurrentSlicedBucket.size());
ValueMetricProducer::Interval curInterval =
- valueProducer->mCurrentSlicedBucket.begin()->second[0];
- ValueMetricProducer::BaseInfo curBaseInfo = valueProducer->mCurrentBaseInfo.begin()->second[0];
+ valueProducer->mCurrentSlicedBucket.begin()->second.intervals[0];
+ ValueMetricProducer::BaseInfo curBaseInfo =
+ valueProducer->mCurrentBaseInfo.begin()->second.baseInfos[0];
EXPECT_EQ(true, curBaseInfo.hasBase);
EXPECT_EQ(100, curBaseInfo.base.long_value);
EXPECT_EQ(false, curInterval.hasValue);
@@ -1189,8 +1200,8 @@ TEST(ValueMetricProducerTest, TestBucketBoundaryWithCondition) {
// pull on bucket boundary come late, condition change happens before it
valueProducer->onConditionChanged(false, bucket2StartTimeNs + 1);
- curInterval = valueProducer->mCurrentSlicedBucket.begin()->second[0];
- curBaseInfo = valueProducer->mCurrentBaseInfo.begin()->second[0];
+ curInterval = valueProducer->mCurrentSlicedBucket.begin()->second.intervals[0];
+ curBaseInfo = valueProducer->mCurrentBaseInfo.begin()->second.baseInfos[0];
assertPastBucketValuesSingleKey(valueProducer->mPastBuckets, {20}, {bucketSizeNs - 8},
{bucketStartTimeNs}, {bucket2StartTimeNs});
EXPECT_EQ(false, curBaseInfo.hasBase);
@@ -1203,8 +1214,8 @@ TEST(ValueMetricProducerTest, TestBucketBoundaryWithCondition) {
assertPastBucketValuesSingleKey(valueProducer->mPastBuckets, {20}, {bucketSizeNs - 8},
{bucketStartTimeNs}, {bucket2StartTimeNs});
- curInterval = valueProducer->mCurrentSlicedBucket.begin()->second[0];
- curBaseInfo = valueProducer->mCurrentBaseInfo.begin()->second[0];
+ curInterval = valueProducer->mCurrentSlicedBucket.begin()->second.intervals[0];
+ curBaseInfo = valueProducer->mCurrentBaseInfo.begin()->second.baseInfos[0];
EXPECT_EQ(false, curBaseInfo.hasBase);
EXPECT_EQ(false, curInterval.hasValue);
}
@@ -1252,8 +1263,9 @@ TEST(ValueMetricProducerTest, TestBucketBoundaryWithCondition2) {
// has one slice
ASSERT_EQ(1UL, valueProducer->mCurrentSlicedBucket.size());
ValueMetricProducer::Interval curInterval =
- valueProducer->mCurrentSlicedBucket.begin()->second[0];
- ValueMetricProducer::BaseInfo curBaseInfo = valueProducer->mCurrentBaseInfo.begin()->second[0];
+ valueProducer->mCurrentSlicedBucket.begin()->second.intervals[0];
+ ValueMetricProducer::BaseInfo curBaseInfo =
+ valueProducer->mCurrentBaseInfo.begin()->second.baseInfos[0];
// startUpdated:false sum:0 start:100
EXPECT_EQ(true, curBaseInfo.hasBase);
EXPECT_EQ(100, curBaseInfo.base.long_value);
@@ -1265,8 +1277,8 @@ TEST(ValueMetricProducerTest, TestBucketBoundaryWithCondition2) {
assertPastBucketValuesSingleKey(valueProducer->mPastBuckets, {20}, {bucketSizeNs - 8},
{bucketStartTimeNs}, {bucket2StartTimeNs});
ASSERT_EQ(1UL, valueProducer->mCurrentSlicedBucket.size());
- curInterval = valueProducer->mCurrentSlicedBucket.begin()->second[0];
- curBaseInfo = valueProducer->mCurrentBaseInfo.begin()->second[0];
+ curInterval = valueProducer->mCurrentSlicedBucket.begin()->second.intervals[0];
+ curBaseInfo = valueProducer->mCurrentBaseInfo.begin()->second.baseInfos[0];
EXPECT_EQ(false, curBaseInfo.hasBase);
EXPECT_EQ(false, curInterval.hasValue);
@@ -1274,8 +1286,8 @@ TEST(ValueMetricProducerTest, TestBucketBoundaryWithCondition2) {
valueProducer->onConditionChanged(true, bucket2StartTimeNs + 25);
assertPastBucketValuesSingleKey(valueProducer->mPastBuckets, {20}, {bucketSizeNs - 8},
{bucketStartTimeNs}, {bucket2StartTimeNs});
- curInterval = valueProducer->mCurrentSlicedBucket.begin()->second[0];
- curBaseInfo = valueProducer->mCurrentBaseInfo.begin()->second[0];
+ curInterval = valueProducer->mCurrentSlicedBucket.begin()->second.intervals[0];
+ curBaseInfo = valueProducer->mCurrentBaseInfo.begin()->second.baseInfos[0];
EXPECT_EQ(true, curBaseInfo.hasBase);
EXPECT_EQ(130, curBaseInfo.base.long_value);
EXPECT_EQ(false, curInterval.hasValue);
@@ -1286,8 +1298,8 @@ TEST(ValueMetricProducerTest, TestBucketBoundaryWithCondition2) {
allData.push_back(CreateRepeatedValueLogEvent(tagId, bucket2StartTimeNs + 50, 140));
valueProducer->onDataPulled(allData, /** succeed */ true, bucket2StartTimeNs + 50);
- curInterval = valueProducer->mCurrentSlicedBucket.begin()->second[0];
- curBaseInfo = valueProducer->mCurrentBaseInfo.begin()->second[0];
+ curInterval = valueProducer->mCurrentSlicedBucket.begin()->second.intervals[0];
+ curBaseInfo = valueProducer->mCurrentBaseInfo.begin()->second.baseInfos[0];
EXPECT_EQ(true, curBaseInfo.hasBase);
EXPECT_EQ(140, curBaseInfo.base.long_value);
EXPECT_EQ(true, curInterval.hasValue);
@@ -1312,9 +1324,9 @@ TEST(ValueMetricProducerTest, TestPushedAggregateMin) {
sp<MockConditionWizard> wizard = new NaggyMock<MockConditionWizard>();
sp<MockStatsPullerManager> pullerManager = new StrictMock<MockStatsPullerManager>();
- ValueMetricProducer valueProducer(kConfigKey, metric, -1, {}, wizard, logEventMatcherIndex,
- eventMatcherWizard, -1, bucketStartTimeNs, bucketStartTimeNs,
- pullerManager);
+ ValueMetricProducer valueProducer(kConfigKey, metric, -1, {}, wizard, protoHash,
+ logEventMatcherIndex, eventMatcherWizard, -1,
+ bucketStartTimeNs, bucketStartTimeNs, pullerManager);
valueProducer.prepareFirstBucket();
LogEvent event1(/*uid=*/0, /*pid=*/0);
@@ -1327,7 +1339,7 @@ TEST(ValueMetricProducerTest, TestPushedAggregateMin) {
// has one slice
ASSERT_EQ(1UL, valueProducer.mCurrentSlicedBucket.size());
ValueMetricProducer::Interval curInterval =
- valueProducer.mCurrentSlicedBucket.begin()->second[0];
+ valueProducer.mCurrentSlicedBucket.begin()->second.intervals[0];
EXPECT_EQ(10, curInterval.value.long_value);
EXPECT_EQ(true, curInterval.hasValue);
@@ -1335,7 +1347,7 @@ TEST(ValueMetricProducerTest, TestPushedAggregateMin) {
// has one slice
ASSERT_EQ(1UL, valueProducer.mCurrentSlicedBucket.size());
- curInterval = valueProducer.mCurrentSlicedBucket.begin()->second[0];
+ curInterval = valueProducer.mCurrentSlicedBucket.begin()->second.intervals[0];
EXPECT_EQ(10, curInterval.value.long_value);
valueProducer.flushIfNeededLocked(bucket2StartTimeNs);
@@ -1352,9 +1364,9 @@ TEST(ValueMetricProducerTest, TestPushedAggregateMax) {
sp<MockConditionWizard> wizard = new NaggyMock<MockConditionWizard>();
sp<MockStatsPullerManager> pullerManager = new StrictMock<MockStatsPullerManager>();
- ValueMetricProducer valueProducer(kConfigKey, metric, -1, {}, wizard, logEventMatcherIndex,
- eventMatcherWizard, -1, bucketStartTimeNs, bucketStartTimeNs,
- pullerManager);
+ ValueMetricProducer valueProducer(kConfigKey, metric, -1, {}, wizard, protoHash,
+ logEventMatcherIndex, eventMatcherWizard, -1,
+ bucketStartTimeNs, bucketStartTimeNs, pullerManager);
valueProducer.prepareFirstBucket();
LogEvent event1(/*uid=*/0, /*pid=*/0);
@@ -1364,7 +1376,7 @@ TEST(ValueMetricProducerTest, TestPushedAggregateMax) {
// has one slice
ASSERT_EQ(1UL, valueProducer.mCurrentSlicedBucket.size());
ValueMetricProducer::Interval curInterval =
- valueProducer.mCurrentSlicedBucket.begin()->second[0];
+ valueProducer.mCurrentSlicedBucket.begin()->second.intervals[0];
EXPECT_EQ(10, curInterval.value.long_value);
EXPECT_EQ(true, curInterval.hasValue);
@@ -1374,7 +1386,7 @@ TEST(ValueMetricProducerTest, TestPushedAggregateMax) {
// has one slice
ASSERT_EQ(1UL, valueProducer.mCurrentSlicedBucket.size());
- curInterval = valueProducer.mCurrentSlicedBucket.begin()->second[0];
+ curInterval = valueProducer.mCurrentSlicedBucket.begin()->second.intervals[0];
EXPECT_EQ(20, curInterval.value.long_value);
valueProducer.flushIfNeededLocked(bucket2StartTimeNs);
@@ -1391,9 +1403,9 @@ TEST(ValueMetricProducerTest, TestPushedAggregateAvg) {
sp<MockConditionWizard> wizard = new NaggyMock<MockConditionWizard>();
sp<MockStatsPullerManager> pullerManager = new StrictMock<MockStatsPullerManager>();
- ValueMetricProducer valueProducer(kConfigKey, metric, -1, {}, wizard, logEventMatcherIndex,
- eventMatcherWizard, -1, bucketStartTimeNs, bucketStartTimeNs,
- pullerManager);
+ ValueMetricProducer valueProducer(kConfigKey, metric, -1, {}, wizard, protoHash,
+ logEventMatcherIndex, eventMatcherWizard, -1,
+ bucketStartTimeNs, bucketStartTimeNs, pullerManager);
valueProducer.prepareFirstBucket();
LogEvent event1(/*uid=*/0, /*pid=*/0);
@@ -1405,7 +1417,7 @@ TEST(ValueMetricProducerTest, TestPushedAggregateAvg) {
// has one slice
ASSERT_EQ(1UL, valueProducer.mCurrentSlicedBucket.size());
ValueMetricProducer::Interval curInterval;
- curInterval = valueProducer.mCurrentSlicedBucket.begin()->second[0];
+ curInterval = valueProducer.mCurrentSlicedBucket.begin()->second.intervals[0];
EXPECT_EQ(10, curInterval.value.long_value);
EXPECT_EQ(true, curInterval.hasValue);
EXPECT_EQ(1, curInterval.sampleSize);
@@ -1414,7 +1426,7 @@ TEST(ValueMetricProducerTest, TestPushedAggregateAvg) {
// has one slice
ASSERT_EQ(1UL, valueProducer.mCurrentSlicedBucket.size());
- curInterval = valueProducer.mCurrentSlicedBucket.begin()->second[0];
+ curInterval = valueProducer.mCurrentSlicedBucket.begin()->second.intervals[0];
EXPECT_EQ(25, curInterval.value.long_value);
EXPECT_EQ(2, curInterval.sampleSize);
@@ -1435,9 +1447,9 @@ TEST(ValueMetricProducerTest, TestPushedAggregateSum) {
sp<MockConditionWizard> wizard = new NaggyMock<MockConditionWizard>();
sp<MockStatsPullerManager> pullerManager = new StrictMock<MockStatsPullerManager>();
- ValueMetricProducer valueProducer(kConfigKey, metric, -1, {}, wizard, logEventMatcherIndex,
- eventMatcherWizard, -1, bucketStartTimeNs, bucketStartTimeNs,
- pullerManager);
+ ValueMetricProducer valueProducer(kConfigKey, metric, -1, {}, wizard, protoHash,
+ logEventMatcherIndex, eventMatcherWizard, -1,
+ bucketStartTimeNs, bucketStartTimeNs, pullerManager);
valueProducer.prepareFirstBucket();
LogEvent event1(/*uid=*/0, /*pid=*/0);
@@ -1449,7 +1461,7 @@ TEST(ValueMetricProducerTest, TestPushedAggregateSum) {
// has one slice
ASSERT_EQ(1UL, valueProducer.mCurrentSlicedBucket.size());
ValueMetricProducer::Interval curInterval =
- valueProducer.mCurrentSlicedBucket.begin()->second[0];
+ valueProducer.mCurrentSlicedBucket.begin()->second.intervals[0];
EXPECT_EQ(10, curInterval.value.long_value);
EXPECT_EQ(true, curInterval.hasValue);
@@ -1457,7 +1469,7 @@ TEST(ValueMetricProducerTest, TestPushedAggregateSum) {
// has one slice
ASSERT_EQ(1UL, valueProducer.mCurrentSlicedBucket.size());
- curInterval = valueProducer.mCurrentSlicedBucket.begin()->second[0];
+ curInterval = valueProducer.mCurrentSlicedBucket.begin()->second.intervals[0];
EXPECT_EQ(25, curInterval.value.long_value);
valueProducer.flushIfNeededLocked(bucket2StartTimeNs);
@@ -1475,9 +1487,9 @@ TEST(ValueMetricProducerTest, TestSkipZeroDiffOutput) {
sp<MockConditionWizard> wizard = new NaggyMock<MockConditionWizard>();
sp<MockStatsPullerManager> pullerManager = new StrictMock<MockStatsPullerManager>();
- ValueMetricProducer valueProducer(kConfigKey, metric, -1, {}, wizard, logEventMatcherIndex,
- eventMatcherWizard, -1, bucketStartTimeNs, bucketStartTimeNs,
- pullerManager);
+ ValueMetricProducer valueProducer(kConfigKey, metric, -1, {}, wizard, protoHash,
+ logEventMatcherIndex, eventMatcherWizard, -1,
+ bucketStartTimeNs, bucketStartTimeNs, pullerManager);
valueProducer.prepareFirstBucket();
LogEvent event1(/*uid=*/0, /*pid=*/0);
@@ -1487,8 +1499,9 @@ TEST(ValueMetricProducerTest, TestSkipZeroDiffOutput) {
// has one slice
ASSERT_EQ(1UL, valueProducer.mCurrentSlicedBucket.size());
ValueMetricProducer::Interval curInterval =
- valueProducer.mCurrentSlicedBucket.begin()->second[0];
- ValueMetricProducer::BaseInfo curBaseInfo = valueProducer.mCurrentBaseInfo.begin()->second[0];
+ valueProducer.mCurrentSlicedBucket.begin()->second.intervals[0];
+ ValueMetricProducer::BaseInfo curBaseInfo =
+ valueProducer.mCurrentBaseInfo.begin()->second.baseInfos[0];
EXPECT_EQ(true, curBaseInfo.hasBase);
EXPECT_EQ(10, curBaseInfo.base.long_value);
EXPECT_EQ(false, curInterval.hasValue);
@@ -1499,7 +1512,7 @@ TEST(ValueMetricProducerTest, TestSkipZeroDiffOutput) {
// has one slice
ASSERT_EQ(1UL, valueProducer.mCurrentSlicedBucket.size());
- curInterval = valueProducer.mCurrentSlicedBucket.begin()->second[0];
+ curInterval = valueProducer.mCurrentSlicedBucket.begin()->second.intervals[0];
EXPECT_EQ(true, curInterval.hasValue);
EXPECT_EQ(5, curInterval.value.long_value);
@@ -1509,8 +1522,8 @@ TEST(ValueMetricProducerTest, TestSkipZeroDiffOutput) {
valueProducer.onMatchedLogEvent(1 /*log matcher index*/, event3);
ASSERT_EQ(1UL, valueProducer.mCurrentSlicedBucket.size());
- curInterval = valueProducer.mCurrentSlicedBucket.begin()->second[0];
- curBaseInfo = valueProducer.mCurrentBaseInfo.begin()->second[0];
+ curInterval = valueProducer.mCurrentSlicedBucket.begin()->second.intervals[0];
+ curBaseInfo = valueProducer.mCurrentBaseInfo.begin()->second.baseInfos[0];
EXPECT_EQ(true, curBaseInfo.hasBase);
EXPECT_EQ(15, curBaseInfo.base.long_value);
EXPECT_EQ(true, curInterval.hasValue);
@@ -1520,8 +1533,8 @@ TEST(ValueMetricProducerTest, TestSkipZeroDiffOutput) {
CreateRepeatedValueLogEvent(&event4, tagId, bucket2StartTimeNs + 15, 15);
valueProducer.onMatchedLogEvent(1 /*log matcher index*/, event4);
ASSERT_EQ(1UL, valueProducer.mCurrentSlicedBucket.size());
- curInterval = valueProducer.mCurrentSlicedBucket.begin()->second[0];
- curBaseInfo = valueProducer.mCurrentBaseInfo.begin()->second[0];
+ curInterval = valueProducer.mCurrentSlicedBucket.begin()->second.intervals[0];
+ curBaseInfo = valueProducer.mCurrentBaseInfo.begin()->second.baseInfos[0];
EXPECT_EQ(true, curBaseInfo.hasBase);
EXPECT_EQ(15, curBaseInfo.base.long_value);
EXPECT_EQ(true, curInterval.hasValue);
@@ -1543,9 +1556,9 @@ TEST(ValueMetricProducerTest, TestSkipZeroDiffOutputMultiValue) {
sp<MockConditionWizard> wizard = new NaggyMock<MockConditionWizard>();
sp<MockStatsPullerManager> pullerManager = new StrictMock<MockStatsPullerManager>();
- ValueMetricProducer valueProducer(kConfigKey, metric, -1, {}, wizard, logEventMatcherIndex,
- eventMatcherWizard, -1, bucketStartTimeNs, bucketStartTimeNs,
- pullerManager);
+ ValueMetricProducer valueProducer(kConfigKey, metric, -1, {}, wizard, protoHash,
+ logEventMatcherIndex, eventMatcherWizard, -1,
+ bucketStartTimeNs, bucketStartTimeNs, pullerManager);
valueProducer.prepareFirstBucket();
LogEvent event1(/*uid=*/0, /*pid=*/0);
@@ -1558,12 +1571,13 @@ TEST(ValueMetricProducerTest, TestSkipZeroDiffOutputMultiValue) {
// has one slice
ASSERT_EQ(1UL, valueProducer.mCurrentSlicedBucket.size());
ValueMetricProducer::Interval curInterval =
- valueProducer.mCurrentSlicedBucket.begin()->second[0];
- ValueMetricProducer::BaseInfo curBaseInfo = valueProducer.mCurrentBaseInfo.begin()->second[0];
+ valueProducer.mCurrentSlicedBucket.begin()->second.intervals[0];
+ ValueMetricProducer::BaseInfo curBaseInfo =
+ valueProducer.mCurrentBaseInfo.begin()->second.baseInfos[0];
EXPECT_EQ(true, curBaseInfo.hasBase);
EXPECT_EQ(10, curBaseInfo.base.long_value);
EXPECT_EQ(false, curInterval.hasValue);
- curBaseInfo = valueProducer.mCurrentBaseInfo.begin()->second[1];
+ curBaseInfo = valueProducer.mCurrentBaseInfo.begin()->second.baseInfos[1];
EXPECT_EQ(true, curBaseInfo.hasBase);
EXPECT_EQ(20, curBaseInfo.base.long_value);
EXPECT_EQ(false, curInterval.hasValue);
@@ -1572,12 +1586,12 @@ TEST(ValueMetricProducerTest, TestSkipZeroDiffOutputMultiValue) {
// has one slice
ASSERT_EQ(1UL, valueProducer.mCurrentSlicedBucket.size());
- curInterval = valueProducer.mCurrentSlicedBucket.begin()->second[0];
- curBaseInfo = valueProducer.mCurrentBaseInfo.begin()->second[0];
+ curInterval = valueProducer.mCurrentSlicedBucket.begin()->second.intervals[0];
+ curBaseInfo = valueProducer.mCurrentBaseInfo.begin()->second.baseInfos[0];
EXPECT_EQ(true, curInterval.hasValue);
EXPECT_EQ(5, curInterval.value.long_value);
- curInterval = valueProducer.mCurrentSlicedBucket.begin()->second[1];
- curBaseInfo = valueProducer.mCurrentBaseInfo.begin()->second[1];
+ curInterval = valueProducer.mCurrentSlicedBucket.begin()->second.intervals[1];
+ curBaseInfo = valueProducer.mCurrentBaseInfo.begin()->second.baseInfos[1];
EXPECT_EQ(true, curInterval.hasValue);
EXPECT_EQ(2, curInterval.value.long_value);
@@ -1587,14 +1601,14 @@ TEST(ValueMetricProducerTest, TestSkipZeroDiffOutputMultiValue) {
valueProducer.onMatchedLogEvent(1 /*log matcher index*/, event3);
ASSERT_EQ(1UL, valueProducer.mCurrentSlicedBucket.size());
- curInterval = valueProducer.mCurrentSlicedBucket.begin()->second[0];
- curBaseInfo = valueProducer.mCurrentBaseInfo.begin()->second[0];
+ curInterval = valueProducer.mCurrentSlicedBucket.begin()->second.intervals[0];
+ curBaseInfo = valueProducer.mCurrentBaseInfo.begin()->second.baseInfos[0];
EXPECT_EQ(true, curBaseInfo.hasBase);
EXPECT_EQ(15, curBaseInfo.base.long_value);
EXPECT_EQ(true, curInterval.hasValue);
- curInterval = valueProducer.mCurrentSlicedBucket.begin()->second[1];
- curBaseInfo = valueProducer.mCurrentBaseInfo.begin()->second[1];
+ curInterval = valueProducer.mCurrentSlicedBucket.begin()->second.intervals[1];
+ curBaseInfo = valueProducer.mCurrentBaseInfo.begin()->second.baseInfos[1];
EXPECT_EQ(true, curBaseInfo.hasBase);
EXPECT_EQ(25, curBaseInfo.base.long_value);
EXPECT_EQ(true, curInterval.hasValue);
@@ -1604,13 +1618,13 @@ TEST(ValueMetricProducerTest, TestSkipZeroDiffOutputMultiValue) {
valueProducer.onMatchedLogEvent(1 /*log matcher index*/, event4);
ASSERT_EQ(1UL, valueProducer.mCurrentSlicedBucket.size());
- curInterval = valueProducer.mCurrentSlicedBucket.begin()->second[0];
- curBaseInfo = valueProducer.mCurrentBaseInfo.begin()->second[0];
+ curInterval = valueProducer.mCurrentSlicedBucket.begin()->second.intervals[0];
+ curBaseInfo = valueProducer.mCurrentBaseInfo.begin()->second.baseInfos[0];
EXPECT_EQ(true, curBaseInfo.hasBase);
EXPECT_EQ(15, curBaseInfo.base.long_value);
EXPECT_EQ(true, curInterval.hasValue);
- curInterval = valueProducer.mCurrentSlicedBucket.begin()->second[1];
- curBaseInfo = valueProducer.mCurrentBaseInfo.begin()->second[1];
+ curInterval = valueProducer.mCurrentSlicedBucket.begin()->second.intervals[1];
+ curBaseInfo = valueProducer.mCurrentBaseInfo.begin()->second.baseInfos[1];
EXPECT_EQ(true, curBaseInfo.hasBase);
EXPECT_EQ(29, curBaseInfo.base.long_value);
EXPECT_EQ(true, curInterval.hasValue);
@@ -1656,9 +1670,9 @@ TEST(ValueMetricProducerTest, TestUseZeroDefaultBase) {
ASSERT_EQ(1UL, valueProducer->mCurrentSlicedBucket.size());
auto iter = valueProducer->mCurrentSlicedBucket.begin();
- auto& interval1 = iter->second[0];
+ auto& interval1 = iter->second.intervals[0];
auto iterBase = valueProducer->mCurrentBaseInfo.begin();
- auto& baseInfo1 = iterBase->second[0];
+ auto& baseInfo1 = iterBase->second.baseInfos[0];
EXPECT_EQ(1, iter->first.getDimensionKeyInWhat().getValues()[0].mValue.int_value);
EXPECT_EQ(true, baseInfo1.hasBase);
EXPECT_EQ(3, baseInfo1.base.long_value);
@@ -1692,8 +1706,8 @@ TEST(ValueMetricProducerTest, TestUseZeroDefaultBase) {
}
EXPECT_TRUE(it != iter);
EXPECT_TRUE(itBase != iterBase);
- auto& interval2 = it->second[0];
- auto& baseInfo2 = itBase->second[0];
+ auto& interval2 = it->second.intervals[0];
+ auto& baseInfo2 = itBase->second.baseInfos[0];
EXPECT_EQ(2, it->first.getDimensionKeyInWhat().getValues()[0].mValue.int_value);
EXPECT_EQ(true, baseInfo2.hasBase);
EXPECT_EQ(4, baseInfo2.base.long_value);
@@ -1732,9 +1746,10 @@ TEST(ValueMetricProducerTest, TestUseZeroDefaultBaseWithPullFailures) {
ASSERT_EQ(1UL, valueProducer->mCurrentSlicedBucket.size());
const auto& it = valueProducer->mCurrentSlicedBucket.begin();
- ValueMetricProducer::Interval& interval1 = it->second[0];
+ ValueMetricProducer::Interval& interval1 = it->second.intervals[0];
ValueMetricProducer::BaseInfo& baseInfo1 =
- valueProducer->mCurrentBaseInfo.find(it->first.getDimensionKeyInWhat())->second[0];
+ valueProducer->mCurrentBaseInfo.find(it->first.getDimensionKeyInWhat())
+ ->second.baseInfos[0];
EXPECT_EQ(1, it->first.getDimensionKeyInWhat().getValues()[0].mValue.int_value);
EXPECT_EQ(true, baseInfo1.hasBase);
EXPECT_EQ(3, baseInfo1.base.long_value);
@@ -1761,9 +1776,10 @@ TEST(ValueMetricProducerTest, TestUseZeroDefaultBaseWithPullFailures) {
}
}
EXPECT_TRUE(it2 != it);
- ValueMetricProducer::Interval& interval2 = it2->second[0];
+ ValueMetricProducer::Interval& interval2 = it2->second.intervals[0];
ValueMetricProducer::BaseInfo& baseInfo2 =
- valueProducer->mCurrentBaseInfo.find(it2->first.getDimensionKeyInWhat())->second[0];
+ valueProducer->mCurrentBaseInfo.find(it2->first.getDimensionKeyInWhat())
+ ->second.baseInfos[0];
EXPECT_EQ(2, it2->first.getDimensionKeyInWhat().getValues()[0].mValue.int_value);
EXPECT_EQ(true, baseInfo2.hasBase);
EXPECT_EQ(4, baseInfo2.base.long_value);
@@ -1792,14 +1808,16 @@ TEST(ValueMetricProducerTest, TestUseZeroDefaultBaseWithPullFailures) {
// Get new references now that entries have been deleted from the map
const auto& it3 = valueProducer->mCurrentSlicedBucket.begin();
const auto& it4 = std::next(valueProducer->mCurrentSlicedBucket.begin());
- ASSERT_EQ(it3->second.size(), 1);
- ASSERT_EQ(it4->second.size(), 1);
- ValueMetricProducer::Interval& interval3 = it3->second[0];
- ValueMetricProducer::Interval& interval4 = it4->second[0];
+ ASSERT_EQ(it3->second.intervals.size(), 1);
+ ASSERT_EQ(it4->second.intervals.size(), 1);
+ ValueMetricProducer::Interval& interval3 = it3->second.intervals[0];
+ ValueMetricProducer::Interval& interval4 = it4->second.intervals[0];
ValueMetricProducer::BaseInfo& baseInfo3 =
- valueProducer->mCurrentBaseInfo.find(it3->first.getDimensionKeyInWhat())->second[0];
+ valueProducer->mCurrentBaseInfo.find(it3->first.getDimensionKeyInWhat())
+ ->second.baseInfos[0];
ValueMetricProducer::BaseInfo& baseInfo4 =
- valueProducer->mCurrentBaseInfo.find(it4->first.getDimensionKeyInWhat())->second[0];
+ valueProducer->mCurrentBaseInfo.find(it4->first.getDimensionKeyInWhat())
+ ->second.baseInfos[0];
EXPECT_EQ(true, baseInfo3.hasBase);
EXPECT_EQ(5, baseInfo3.base.long_value);
@@ -1837,9 +1855,9 @@ TEST(ValueMetricProducerTest, TestTrimUnusedDimensionKey) {
ASSERT_EQ(1UL, valueProducer->mCurrentSlicedBucket.size());
auto iter = valueProducer->mCurrentSlicedBucket.begin();
- auto& interval1 = iter->second[0];
+ auto& interval1 = iter->second.intervals[0];
auto iterBase = valueProducer->mCurrentBaseInfo.begin();
- auto& baseInfo1 = iterBase->second[0];
+ auto& baseInfo1 = iterBase->second.baseInfos[0];
EXPECT_EQ(1, iter->first.getDimensionKeyInWhat().getValues()[0].mValue.int_value);
EXPECT_EQ(true, baseInfo1.hasBase);
EXPECT_EQ(3, baseInfo1.base.long_value);
@@ -1875,8 +1893,8 @@ TEST(ValueMetricProducerTest, TestTrimUnusedDimensionKey) {
}
EXPECT_TRUE(it != iter);
EXPECT_TRUE(itBase != iterBase);
- auto interval2 = it->second[0];
- auto baseInfo2 = itBase->second[0];
+ auto interval2 = it->second.intervals[0];
+ auto baseInfo2 = itBase->second.baseInfos[0];
EXPECT_EQ(2, it->first.getDimensionKeyInWhat().getValues()[0].mValue.int_value);
EXPECT_EQ(true, baseInfo2.hasBase);
EXPECT_EQ(4, baseInfo2.base.long_value);
@@ -1889,8 +1907,8 @@ TEST(ValueMetricProducerTest, TestTrimUnusedDimensionKey) {
valueProducer->onDataPulled(allData, /** succeed */ true, bucket4StartTimeNs);
// Only one interval left. One was trimmed.
ASSERT_EQ(1UL, valueProducer->mCurrentSlicedBucket.size());
- interval2 = valueProducer->mCurrentSlicedBucket.begin()->second[0];
- baseInfo2 = valueProducer->mCurrentBaseInfo.begin()->second[0];
+ interval2 = valueProducer->mCurrentSlicedBucket.begin()->second.intervals[0];
+ baseInfo2 = valueProducer->mCurrentBaseInfo.begin()->second.baseInfos[0];
EXPECT_EQ(2, it->first.getDimensionKeyInWhat().getValues()[0].mValue.int_value);
EXPECT_EQ(true, baseInfo2.hasBase);
EXPECT_EQ(5, baseInfo2.base.long_value);
@@ -1903,8 +1921,8 @@ TEST(ValueMetricProducerTest, TestTrimUnusedDimensionKey) {
allData.push_back(CreateTwoValueLogEvent(tagId, bucket5StartTimeNs + 1, 2, 14));
valueProducer->onDataPulled(allData, /** succeed */ true, bucket5StartTimeNs);
- interval2 = valueProducer->mCurrentSlicedBucket.begin()->second[0];
- baseInfo2 = valueProducer->mCurrentBaseInfo.begin()->second[0];
+ interval2 = valueProducer->mCurrentSlicedBucket.begin()->second.intervals[0];
+ baseInfo2 = valueProducer->mCurrentBaseInfo.begin()->second.baseInfos[0];
EXPECT_EQ(true, baseInfo2.hasBase);
EXPECT_EQ(14, baseInfo2.base.long_value);
EXPECT_EQ(false, interval2.hasValue);
@@ -1943,8 +1961,9 @@ TEST(ValueMetricProducerTest, TestResetBaseOnPullFailAfterConditionChange_EndOfB
// has one slice
ASSERT_EQ(1UL, valueProducer->mCurrentSlicedBucket.size());
ValueMetricProducer::Interval& curInterval =
- valueProducer->mCurrentSlicedBucket.begin()->second[0];
- ValueMetricProducer::BaseInfo& curBaseInfo = valueProducer->mCurrentBaseInfo.begin()->second[0];
+ valueProducer->mCurrentSlicedBucket.begin()->second.intervals[0];
+ ValueMetricProducer::BaseInfo& curBaseInfo =
+ valueProducer->mCurrentBaseInfo.begin()->second.baseInfos[0];
EXPECT_EQ(true, curBaseInfo.hasBase);
EXPECT_EQ(100, curBaseInfo.base.long_value);
EXPECT_EQ(false, curInterval.hasValue);
@@ -1980,8 +1999,9 @@ TEST(ValueMetricProducerTest, TestResetBaseOnPullFailAfterConditionChange) {
// has one slice
ASSERT_EQ(1UL, valueProducer->mCurrentSlicedBucket.size());
ValueMetricProducer::Interval& curInterval =
- valueProducer->mCurrentSlicedBucket.begin()->second[0];
- ValueMetricProducer::BaseInfo& curBaseInfo = valueProducer->mCurrentBaseInfo.begin()->second[0];
+ valueProducer->mCurrentSlicedBucket.begin()->second.intervals[0];
+ ValueMetricProducer::BaseInfo& curBaseInfo =
+ valueProducer->mCurrentBaseInfo.begin()->second.baseInfos[0];
EXPECT_EQ(true, curBaseInfo.hasBase);
EXPECT_EQ(100, curBaseInfo.base.long_value);
EXPECT_EQ(false, curInterval.hasValue);
@@ -2030,8 +2050,9 @@ TEST(ValueMetricProducerTest, TestResetBaseOnPullFailBeforeConditionChange) {
valueProducer->onConditionChanged(false, bucketStartTimeNs + 1);
ASSERT_EQ(1UL, valueProducer->mCurrentSlicedBucket.size());
ValueMetricProducer::Interval& curInterval =
- valueProducer->mCurrentSlicedBucket.begin()->second[0];
- ValueMetricProducer::BaseInfo curBaseInfo = valueProducer->mCurrentBaseInfo.begin()->second[0];
+ valueProducer->mCurrentSlicedBucket.begin()->second.intervals[0];
+ ValueMetricProducer::BaseInfo curBaseInfo =
+ valueProducer->mCurrentBaseInfo.begin()->second.baseInfos[0];
EXPECT_EQ(false, curBaseInfo.hasBase);
EXPECT_EQ(false, curInterval.hasValue);
EXPECT_EQ(false, valueProducer->mHasGlobalBase);
@@ -2071,7 +2092,7 @@ TEST(ValueMetricProducerTest, TestResetBaseOnPullTooLate) {
EXPECT_CALL(*pullerManager, UnRegisterReceiver(tagId, kConfigKey, _)).WillRepeatedly(Return());
ValueMetricProducer valueProducer(kConfigKey, metric, 0, {ConditionState::kUnknown}, wizard,
- logEventMatcherIndex, eventMatcherWizard, tagId,
+ protoHash, logEventMatcherIndex, eventMatcherWizard, tagId,
bucket2StartTimeNs, bucket2StartTimeNs, pullerManager);
valueProducer.prepareFirstBucket();
valueProducer.mCondition = ConditionState::kFalse;
@@ -2103,8 +2124,9 @@ TEST(ValueMetricProducerTest, TestBaseSetOnConditionChange) {
valueProducer->mHasGlobalBase = true;
ASSERT_EQ(1UL, valueProducer->mCurrentSlicedBucket.size());
ValueMetricProducer::Interval& curInterval =
- valueProducer->mCurrentSlicedBucket.begin()->second[0];
- ValueMetricProducer::BaseInfo curBaseInfo = valueProducer->mCurrentBaseInfo.begin()->second[0];
+ valueProducer->mCurrentSlicedBucket.begin()->second.intervals[0];
+ ValueMetricProducer::BaseInfo curBaseInfo =
+ valueProducer->mCurrentBaseInfo.begin()->second.baseInfos[0];
EXPECT_EQ(true, curBaseInfo.hasBase);
EXPECT_EQ(100, curBaseInfo.base.long_value);
EXPECT_EQ(false, curInterval.hasValue);
@@ -2156,8 +2178,9 @@ TEST(ValueMetricProducerTest_BucketDrop, TestInvalidBucketWhenOneConditionFailed
// Contains base from last pull which was successful.
ASSERT_EQ(1UL, valueProducer->mCurrentSlicedBucket.size());
ValueMetricProducer::Interval& curInterval =
- valueProducer->mCurrentSlicedBucket.begin()->second[0];
- ValueMetricProducer::BaseInfo curBaseInfo = valueProducer->mCurrentBaseInfo.begin()->second[0];
+ valueProducer->mCurrentSlicedBucket.begin()->second.intervals[0];
+ ValueMetricProducer::BaseInfo curBaseInfo =
+ valueProducer->mCurrentBaseInfo.begin()->second.baseInfos[0];
EXPECT_EQ(true, curBaseInfo.hasBase);
EXPECT_EQ(140, curBaseInfo.base.long_value);
EXPECT_EQ(false, curInterval.hasValue);
@@ -2294,8 +2317,9 @@ TEST(ValueMetricProducerTest_BucketDrop, TestInvalidBucketWhenInitialPullFailed)
// Contains base from last pull which was successful.
ASSERT_EQ(1UL, valueProducer->mCurrentSlicedBucket.size());
ValueMetricProducer::Interval& curInterval =
- valueProducer->mCurrentSlicedBucket.begin()->second[0];
- ValueMetricProducer::BaseInfo curBaseInfo = valueProducer->mCurrentBaseInfo.begin()->second[0];
+ valueProducer->mCurrentSlicedBucket.begin()->second.intervals[0];
+ ValueMetricProducer::BaseInfo curBaseInfo =
+ valueProducer->mCurrentBaseInfo.begin()->second.baseInfos[0];
EXPECT_EQ(true, curBaseInfo.hasBase);
EXPECT_EQ(140, curBaseInfo.base.long_value);
EXPECT_EQ(false, curInterval.hasValue);
@@ -2373,8 +2397,9 @@ TEST(ValueMetricProducerTest_BucketDrop, TestInvalidBucketWhenLastPullFailed) {
// Last pull failed so base has been reset.
ASSERT_EQ(1UL, valueProducer->mCurrentSlicedBucket.size());
ValueMetricProducer::Interval& curInterval =
- valueProducer->mCurrentSlicedBucket.begin()->second[0];
- ValueMetricProducer::BaseInfo curBaseInfo = valueProducer->mCurrentBaseInfo.begin()->second[0];
+ valueProducer->mCurrentSlicedBucket.begin()->second.intervals[0];
+ ValueMetricProducer::BaseInfo curBaseInfo =
+ valueProducer->mCurrentBaseInfo.begin()->second.baseInfos[0];
EXPECT_EQ(false, curBaseInfo.hasBase);
EXPECT_EQ(false, curInterval.hasValue);
EXPECT_EQ(false, valueProducer->mHasGlobalBase);
@@ -2460,8 +2485,9 @@ TEST(ValueMetricProducerTest, TestEmptyDataResetsBase_onConditionChanged) {
valueProducer->onConditionChanged(true, bucketStartTimeNs + 10);
ASSERT_EQ(1UL, valueProducer->mCurrentSlicedBucket.size());
ValueMetricProducer::Interval& curInterval =
- valueProducer->mCurrentSlicedBucket.begin()->second[0];
- ValueMetricProducer::BaseInfo curBaseInfo = valueProducer->mCurrentBaseInfo.begin()->second[0];
+ valueProducer->mCurrentSlicedBucket.begin()->second.intervals[0];
+ ValueMetricProducer::BaseInfo curBaseInfo =
+ valueProducer->mCurrentBaseInfo.begin()->second.baseInfos[0];
EXPECT_EQ(true, curBaseInfo.hasBase);
EXPECT_EQ(false, curInterval.hasValue);
EXPECT_EQ(true, valueProducer->mHasGlobalBase);
@@ -2469,8 +2495,8 @@ TEST(ValueMetricProducerTest, TestEmptyDataResetsBase_onConditionChanged) {
// Empty pull.
valueProducer->onConditionChanged(false, bucketStartTimeNs + 10);
ASSERT_EQ(1UL, valueProducer->mCurrentSlicedBucket.size());
- curInterval = valueProducer->mCurrentSlicedBucket.begin()->second[0];
- curBaseInfo = valueProducer->mCurrentBaseInfo.begin()->second[0];
+ curInterval = valueProducer->mCurrentSlicedBucket.begin()->second.intervals[0];
+ curBaseInfo = valueProducer->mCurrentBaseInfo.begin()->second.baseInfos[0];
EXPECT_EQ(false, curBaseInfo.hasBase);
EXPECT_EQ(false, curInterval.hasValue);
EXPECT_EQ(false, valueProducer->mHasGlobalBase);
@@ -2513,8 +2539,9 @@ TEST(ValueMetricProducerTest, TestEmptyDataResetsBase_onBucketBoundary) {
valueProducer->onConditionChanged(true, bucketStartTimeNs + 12);
ASSERT_EQ(1UL, valueProducer->mCurrentSlicedBucket.size());
ValueMetricProducer::Interval& curInterval =
- valueProducer->mCurrentSlicedBucket.begin()->second[0];
- ValueMetricProducer::BaseInfo curBaseInfo = valueProducer->mCurrentBaseInfo.begin()->second[0];
+ valueProducer->mCurrentSlicedBucket.begin()->second.intervals[0];
+ ValueMetricProducer::BaseInfo curBaseInfo =
+ valueProducer->mCurrentBaseInfo.begin()->second.baseInfos[0];
EXPECT_EQ(true, curBaseInfo.hasBase);
EXPECT_EQ(true, curInterval.hasValue);
EXPECT_EQ(true, valueProducer->mHasGlobalBase);
@@ -2524,8 +2551,8 @@ TEST(ValueMetricProducerTest, TestEmptyDataResetsBase_onBucketBoundary) {
allData.clear();
valueProducer->onDataPulled(allData, /** succeed */ true, bucket2StartTimeNs);
ASSERT_EQ(1UL, valueProducer->mCurrentSlicedBucket.size());
- curInterval = valueProducer->mCurrentSlicedBucket.begin()->second[0];
- curBaseInfo = valueProducer->mCurrentBaseInfo.begin()->second[0];
+ curInterval = valueProducer->mCurrentSlicedBucket.begin()->second.intervals[0];
+ curBaseInfo = valueProducer->mCurrentBaseInfo.begin()->second.baseInfos[0];
// Data is empty, base should be reset.
EXPECT_EQ(false, curBaseInfo.hasBase);
EXPECT_EQ(5, curBaseInfo.base.long_value);
@@ -2570,14 +2597,14 @@ TEST(ValueMetricProducerTest, TestPartialResetOnBucketBoundaries) {
ASSERT_EQ(2UL, valueProducer->mCurrentSlicedBucket.size());
auto iterator = valueProducer->mCurrentSlicedBucket.begin();
auto baseInfoIter = valueProducer->mCurrentBaseInfo.begin();
- EXPECT_EQ(true, baseInfoIter->second[0].hasBase);
- EXPECT_EQ(2, baseInfoIter->second[0].base.long_value);
- EXPECT_EQ(false, iterator->second[0].hasValue);
+ EXPECT_EQ(true, baseInfoIter->second.baseInfos[0].hasBase);
+ EXPECT_EQ(2, baseInfoIter->second.baseInfos[0].base.long_value);
+ EXPECT_EQ(false, iterator->second.intervals[0].hasValue);
iterator++;
baseInfoIter++;
- EXPECT_EQ(false, baseInfoIter->second[0].hasBase);
- EXPECT_EQ(1, baseInfoIter->second[0].base.long_value);
- EXPECT_EQ(false, iterator->second[0].hasValue);
+ EXPECT_EQ(false, baseInfoIter->second.baseInfos[0].hasBase);
+ EXPECT_EQ(1, baseInfoIter->second.baseInfos[0].base.long_value);
+ EXPECT_EQ(false, iterator->second.intervals[0].hasValue);
EXPECT_EQ(true, valueProducer->mHasGlobalBase);
}
@@ -2676,8 +2703,8 @@ TEST(ValueMetricProducerTest, TestBucketBoundariesOnConditionChange) {
valueProducer->onConditionChanged(true, bucket2StartTimeNs + 10);
ASSERT_EQ(1UL, valueProducer->mCurrentSlicedBucket.size());
- auto curInterval = valueProducer->mCurrentSlicedBucket.begin()->second[0];
- auto curBaseInfo = valueProducer->mCurrentBaseInfo.begin()->second[0];
+ auto curInterval = valueProducer->mCurrentSlicedBucket.begin()->second.intervals[0];
+ auto curBaseInfo = valueProducer->mCurrentBaseInfo.begin()->second.baseInfos[0];
EXPECT_EQ(true, curBaseInfo.hasBase);
EXPECT_EQ(5, curBaseInfo.base.long_value);
EXPECT_EQ(false, curInterval.hasValue);
@@ -2811,8 +2838,8 @@ TEST(ValueMetricProducerTest, TestDataIsNotUpdatedWhenNoConditionChanged) {
valueProducer->onConditionChanged(false, bucketStartTimeNs + 12);
ASSERT_EQ(1UL, valueProducer->mCurrentSlicedBucket.size());
- auto curInterval = valueProducer->mCurrentSlicedBucket.begin()->second[0];
- auto curBaseInfo = valueProducer->mCurrentBaseInfo.begin()->second[0];
+ auto curInterval = valueProducer->mCurrentSlicedBucket.begin()->second.intervals[0];
+ auto curBaseInfo = valueProducer->mCurrentBaseInfo.begin()->second.baseInfos[0];
EXPECT_EQ(true, curInterval.hasValue);
EXPECT_EQ(2, curInterval.value.long_value);
@@ -2898,9 +2925,9 @@ TEST(ValueMetricProducerTest, TestPullNeededFastDump) {
return true;
}));
- ValueMetricProducer valueProducer(kConfigKey, metric, -1, {}, wizard, logEventMatcherIndex,
- eventMatcherWizard, tagId, bucketStartTimeNs,
- bucketStartTimeNs, pullerManager);
+ ValueMetricProducer valueProducer(kConfigKey, metric, -1, {}, wizard, protoHash,
+ logEventMatcherIndex, eventMatcherWizard, tagId,
+ bucketStartTimeNs, bucketStartTimeNs, pullerManager);
valueProducer.prepareFirstBucket();
ProtoOutputStream output;
@@ -2932,9 +2959,9 @@ TEST(ValueMetricProducerTest, TestFastDumpWithoutCurrentBucket) {
return true;
}));
- ValueMetricProducer valueProducer(kConfigKey, metric, -1, {}, wizard, logEventMatcherIndex,
- eventMatcherWizard, tagId, bucketStartTimeNs,
- bucketStartTimeNs, pullerManager);
+ ValueMetricProducer valueProducer(kConfigKey, metric, -1, {}, wizard, protoHash,
+ logEventMatcherIndex, eventMatcherWizard, tagId,
+ bucketStartTimeNs, bucketStartTimeNs, pullerManager);
valueProducer.prepareFirstBucket();
vector<shared_ptr<LogEvent>> allData;
@@ -2981,9 +3008,9 @@ TEST(ValueMetricProducerTest, TestPullNeededNoTimeConstraints) {
return true;
}));
- ValueMetricProducer valueProducer(kConfigKey, metric, -1, {}, wizard, logEventMatcherIndex,
- eventMatcherWizard, tagId, bucketStartTimeNs,
- bucketStartTimeNs, pullerManager);
+ ValueMetricProducer valueProducer(kConfigKey, metric, -1, {}, wizard, protoHash,
+ logEventMatcherIndex, eventMatcherWizard, tagId,
+ bucketStartTimeNs, bucketStartTimeNs, pullerManager);
valueProducer.prepareFirstBucket();
ProtoOutputStream output;
@@ -3045,8 +3072,9 @@ TEST(ValueMetricProducerTest, TestPulledData_noDiff_withMultipleConditionChanges
// has one slice
ASSERT_EQ(1UL, valueProducer->mCurrentSlicedBucket.size());
ValueMetricProducer::Interval curInterval =
- valueProducer->mCurrentSlicedBucket.begin()->second[0];
- ValueMetricProducer::BaseInfo curBaseInfo = valueProducer->mCurrentBaseInfo.begin()->second[0];
+ valueProducer->mCurrentSlicedBucket.begin()->second.intervals[0];
+ ValueMetricProducer::BaseInfo curBaseInfo =
+ valueProducer->mCurrentBaseInfo.begin()->second.baseInfos[0];
EXPECT_EQ(false, curBaseInfo.hasBase);
EXPECT_EQ(true, curInterval.hasValue);
EXPECT_EQ(20, curInterval.value.long_value);
@@ -3058,8 +3086,8 @@ TEST(ValueMetricProducerTest, TestPulledData_noDiff_withMultipleConditionChanges
assertPastBucketValuesSingleKey(valueProducer->mPastBuckets, {20}, {50 - 8},
{bucketStartTimeNs}, {bucket2StartTimeNs});
- curInterval = valueProducer->mCurrentSlicedBucket.begin()->second[0];
- curBaseInfo = valueProducer->mCurrentBaseInfo.begin()->second[0];
+ curInterval = valueProducer->mCurrentSlicedBucket.begin()->second.intervals[0];
+ curBaseInfo = valueProducer->mCurrentBaseInfo.begin()->second.baseInfos[0];
EXPECT_EQ(false, curBaseInfo.hasBase);
EXPECT_EQ(false, curInterval.hasValue);
}
@@ -3091,8 +3119,9 @@ TEST(ValueMetricProducerTest, TestPulledData_noDiff_bucketBoundaryTrue) {
assertPastBucketValuesSingleKey(valueProducer->mPastBuckets, {30}, {bucketSizeNs - 8},
{bucketStartTimeNs}, {bucket2StartTimeNs});
ValueMetricProducer::Interval curInterval =
- valueProducer->mCurrentSlicedBucket.begin()->second[0];
- ValueMetricProducer::BaseInfo curBaseInfo = valueProducer->mCurrentBaseInfo.begin()->second[0];
+ valueProducer->mCurrentSlicedBucket.begin()->second.intervals[0];
+ ValueMetricProducer::BaseInfo curBaseInfo =
+ valueProducer->mCurrentBaseInfo.begin()->second.baseInfos[0];
EXPECT_EQ(false, curBaseInfo.hasBase);
EXPECT_EQ(false, curInterval.hasValue);
}
@@ -3984,18 +4013,18 @@ TEST(ValueMetricProducerTest, TestSlicedState) {
// Base for dimension key {}
auto it = valueProducer->mCurrentSlicedBucket.begin();
auto itBase = valueProducer->mCurrentBaseInfo.find(it->first.getDimensionKeyInWhat());
- EXPECT_TRUE(itBase->second[0].hasBase);
- EXPECT_EQ(3, itBase->second[0].base.long_value);
- EXPECT_TRUE(itBase->second[0].hasCurrentState);
- ASSERT_EQ(1, itBase->second[0].currentState.getValues().size());
+ EXPECT_TRUE(itBase->second.baseInfos[0].hasBase);
+ EXPECT_EQ(3, itBase->second.baseInfos[0].base.long_value);
+ EXPECT_TRUE(itBase->second.hasCurrentState);
+ ASSERT_EQ(1, itBase->second.currentState.getValues().size());
EXPECT_EQ(-1 /* StateTracker::kStateUnknown */,
- itBase->second[0].currentState.getValues()[0].mValue.int_value);
+ itBase->second.currentState.getValues()[0].mValue.int_value);
// Value for dimension, state key {{}, kStateUnknown}
EXPECT_EQ(0, it->first.getDimensionKeyInWhat().getValues().size());
ASSERT_EQ(1, it->first.getStateValuesKey().getValues().size());
EXPECT_EQ(-1 /* StateTracker::kStateUnknown */,
it->first.getStateValuesKey().getValues()[0].mValue.int_value);
- EXPECT_FALSE(it->second[0].hasValue);
+ EXPECT_FALSE(it->second.intervals[0].hasValue);
// Bucket status after screen state change kStateUnknown->ON.
auto screenEvent = CreateScreenStateChangedEvent(
@@ -4005,19 +4034,19 @@ TEST(ValueMetricProducerTest, TestSlicedState) {
// Base for dimension key {}
it = valueProducer->mCurrentSlicedBucket.begin();
itBase = valueProducer->mCurrentBaseInfo.find(it->first.getDimensionKeyInWhat());
- EXPECT_TRUE(itBase->second[0].hasBase);
- EXPECT_EQ(5, itBase->second[0].base.long_value);
- EXPECT_TRUE(itBase->second[0].hasCurrentState);
- ASSERT_EQ(1, itBase->second[0].currentState.getValues().size());
+ EXPECT_TRUE(itBase->second.baseInfos[0].hasBase);
+ EXPECT_EQ(5, itBase->second.baseInfos[0].base.long_value);
+ EXPECT_TRUE(itBase->second.hasCurrentState);
+ ASSERT_EQ(1, itBase->second.currentState.getValues().size());
EXPECT_EQ(android::view::DisplayStateEnum::DISPLAY_STATE_ON,
- itBase->second[0].currentState.getValues()[0].mValue.int_value);
+ itBase->second.currentState.getValues()[0].mValue.int_value);
// Value for dimension, state key {{}, kStateUnknown}
EXPECT_EQ(0, it->first.getDimensionKeyInWhat().getValues().size());
ASSERT_EQ(1, it->first.getStateValuesKey().getValues().size());
EXPECT_EQ(-1 /* StateTracker::kStateUnknown */,
it->first.getStateValuesKey().getValues()[0].mValue.int_value);
- EXPECT_TRUE(it->second[0].hasValue);
- EXPECT_EQ(2, it->second[0].value.long_value);
+ EXPECT_TRUE(it->second.intervals[0].hasValue);
+ EXPECT_EQ(2, it->second.intervals[0].value.long_value);
// Bucket status after screen state change ON->OFF.
screenEvent = CreateScreenStateChangedEvent(bucketStartTimeNs + 10,
@@ -4027,26 +4056,26 @@ TEST(ValueMetricProducerTest, TestSlicedState) {
// Base for dimension key {}
it = valueProducer->mCurrentSlicedBucket.begin();
itBase = valueProducer->mCurrentBaseInfo.find(it->first.getDimensionKeyInWhat());
- EXPECT_TRUE(itBase->second[0].hasBase);
- EXPECT_EQ(9, itBase->second[0].base.long_value);
- EXPECT_TRUE(itBase->second[0].hasCurrentState);
+ EXPECT_TRUE(itBase->second.baseInfos[0].hasBase);
+ EXPECT_EQ(9, itBase->second.baseInfos[0].base.long_value);
+ EXPECT_TRUE(itBase->second.hasCurrentState);
EXPECT_EQ(android::view::DisplayStateEnum::DISPLAY_STATE_OFF,
- itBase->second[0].currentState.getValues()[0].mValue.int_value);
+ itBase->second.currentState.getValues()[0].mValue.int_value);
// Value for dimension, state key {{}, ON}
EXPECT_EQ(0, it->first.getDimensionKeyInWhat().getValues().size());
ASSERT_EQ(1, it->first.getStateValuesKey().getValues().size());
EXPECT_EQ(android::view::DisplayStateEnum::DISPLAY_STATE_ON,
it->first.getStateValuesKey().getValues()[0].mValue.int_value);
- EXPECT_TRUE(it->second[0].hasValue);
- EXPECT_EQ(4, it->second[0].value.long_value);
+ EXPECT_TRUE(it->second.intervals[0].hasValue);
+ EXPECT_EQ(4, it->second.intervals[0].value.long_value);
// Value for dimension, state key {{}, kStateUnknown}
it++;
EXPECT_EQ(0, it->first.getDimensionKeyInWhat().getValues().size());
ASSERT_EQ(1, it->first.getStateValuesKey().getValues().size());
EXPECT_EQ(-1 /* StateTracker::kStateUnknown */,
it->first.getStateValuesKey().getValues()[0].mValue.int_value);
- EXPECT_TRUE(it->second[0].hasValue);
- EXPECT_EQ(2, it->second[0].value.long_value);
+ EXPECT_TRUE(it->second.intervals[0].hasValue);
+ EXPECT_EQ(2, it->second.intervals[0].value.long_value);
// Bucket status after screen state change OFF->ON.
screenEvent = CreateScreenStateChangedEvent(bucketStartTimeNs + 15,
@@ -4056,35 +4085,35 @@ TEST(ValueMetricProducerTest, TestSlicedState) {
// Base for dimension key {}
it = valueProducer->mCurrentSlicedBucket.begin();
itBase = valueProducer->mCurrentBaseInfo.find(it->first.getDimensionKeyInWhat());
- EXPECT_TRUE(itBase->second[0].hasBase);
- EXPECT_EQ(21, itBase->second[0].base.long_value);
- EXPECT_TRUE(itBase->second[0].hasCurrentState);
- ASSERT_EQ(1, itBase->second[0].currentState.getValues().size());
+ EXPECT_TRUE(itBase->second.baseInfos[0].hasBase);
+ EXPECT_EQ(21, itBase->second.baseInfos[0].base.long_value);
+ EXPECT_TRUE(itBase->second.hasCurrentState);
+ ASSERT_EQ(1, itBase->second.currentState.getValues().size());
EXPECT_EQ(android::view::DisplayStateEnum::DISPLAY_STATE_ON,
- itBase->second[0].currentState.getValues()[0].mValue.int_value);
+ itBase->second.currentState.getValues()[0].mValue.int_value);
// Value for dimension, state key {{}, OFF}
EXPECT_EQ(0, it->first.getDimensionKeyInWhat().getValues().size());
ASSERT_EQ(1, it->first.getStateValuesKey().getValues().size());
EXPECT_EQ(android::view::DisplayStateEnum::DISPLAY_STATE_OFF,
it->first.getStateValuesKey().getValues()[0].mValue.int_value);
- EXPECT_TRUE(it->second[0].hasValue);
- EXPECT_EQ(12, it->second[0].value.long_value);
+ EXPECT_TRUE(it->second.intervals[0].hasValue);
+ EXPECT_EQ(12, it->second.intervals[0].value.long_value);
// Value for dimension, state key {{}, ON}
it++;
EXPECT_EQ(0, it->first.getDimensionKeyInWhat().getValues().size());
ASSERT_EQ(1, it->first.getStateValuesKey().getValues().size());
EXPECT_EQ(android::view::DisplayStateEnum::DISPLAY_STATE_ON,
it->first.getStateValuesKey().getValues()[0].mValue.int_value);
- EXPECT_TRUE(it->second[0].hasValue);
- EXPECT_EQ(4, it->second[0].value.long_value);
+ EXPECT_TRUE(it->second.intervals[0].hasValue);
+ EXPECT_EQ(4, it->second.intervals[0].value.long_value);
// Value for dimension, state key {{}, kStateUnknown}
it++;
EXPECT_EQ(0, it->first.getDimensionKeyInWhat().getValues().size());
ASSERT_EQ(1, it->first.getStateValuesKey().getValues().size());
EXPECT_EQ(-1 /* StateTracker::kStateUnknown */,
it->first.getStateValuesKey().getValues()[0].mValue.int_value);
- EXPECT_TRUE(it->second[0].hasValue);
- EXPECT_EQ(2, it->second[0].value.long_value);
+ EXPECT_TRUE(it->second.intervals[0].hasValue);
+ EXPECT_EQ(2, it->second.intervals[0].value.long_value);
// Start dump report and check output.
ProtoOutputStream output;
@@ -4195,18 +4224,18 @@ TEST(ValueMetricProducerTest, TestSlicedStateWithMap) {
// Base for dimension key {}
auto it = valueProducer->mCurrentSlicedBucket.begin();
auto itBase = valueProducer->mCurrentBaseInfo.find(it->first.getDimensionKeyInWhat());
- EXPECT_TRUE(itBase->second[0].hasBase);
- EXPECT_EQ(3, itBase->second[0].base.long_value);
- EXPECT_TRUE(itBase->second[0].hasCurrentState);
- ASSERT_EQ(1, itBase->second[0].currentState.getValues().size());
+ EXPECT_TRUE(itBase->second.baseInfos[0].hasBase);
+ EXPECT_EQ(3, itBase->second.baseInfos[0].base.long_value);
+ EXPECT_TRUE(itBase->second.hasCurrentState);
+ ASSERT_EQ(1, itBase->second.currentState.getValues().size());
EXPECT_EQ(-1 /* StateTracker::kStateUnknown */,
- itBase->second[0].currentState.getValues()[0].mValue.int_value);
+ itBase->second.currentState.getValues()[0].mValue.int_value);
// Value for dimension, state key {{}, {kStateUnknown}}
EXPECT_EQ(0, it->first.getDimensionKeyInWhat().getValues().size());
ASSERT_EQ(1, it->first.getStateValuesKey().getValues().size());
EXPECT_EQ(-1 /* StateTracker::kStateUnknown */,
it->first.getStateValuesKey().getValues()[0].mValue.int_value);
- EXPECT_FALSE(it->second[0].hasValue);
+ EXPECT_FALSE(it->second.intervals[0].hasValue);
// Bucket status after screen state change kStateUnknown->ON.
auto screenEvent = CreateScreenStateChangedEvent(
@@ -4216,19 +4245,19 @@ TEST(ValueMetricProducerTest, TestSlicedStateWithMap) {
// Base for dimension key {}
it = valueProducer->mCurrentSlicedBucket.begin();
itBase = valueProducer->mCurrentBaseInfo.find(it->first.getDimensionKeyInWhat());
- EXPECT_TRUE(itBase->second[0].hasBase);
- EXPECT_EQ(5, itBase->second[0].base.long_value);
- EXPECT_TRUE(itBase->second[0].hasCurrentState);
- ASSERT_EQ(1, itBase->second[0].currentState.getValues().size());
+ EXPECT_TRUE(itBase->second.baseInfos[0].hasBase);
+ EXPECT_EQ(5, itBase->second.baseInfos[0].base.long_value);
+ EXPECT_TRUE(itBase->second.hasCurrentState);
+ ASSERT_EQ(1, itBase->second.currentState.getValues().size());
EXPECT_EQ(screenOnGroup.group_id(),
- itBase->second[0].currentState.getValues()[0].mValue.long_value);
+ itBase->second.currentState.getValues()[0].mValue.long_value);
// Value for dimension, state key {{}, kStateUnknown}
EXPECT_EQ(0, it->first.getDimensionKeyInWhat().getValues().size());
ASSERT_EQ(1, it->first.getStateValuesKey().getValues().size());
EXPECT_EQ(-1 /* StateTracker::kStateUnknown */,
it->first.getStateValuesKey().getValues()[0].mValue.int_value);
- EXPECT_TRUE(it->second[0].hasValue);
- EXPECT_EQ(2, it->second[0].value.long_value);
+ EXPECT_TRUE(it->second.intervals[0].hasValue);
+ EXPECT_EQ(2, it->second.intervals[0].value.long_value);
// Bucket status after screen state change ON->VR.
// Both ON and VR are in the same state group, so the base should not change.
@@ -4239,19 +4268,19 @@ TEST(ValueMetricProducerTest, TestSlicedStateWithMap) {
// Base for dimension key {}
it = valueProducer->mCurrentSlicedBucket.begin();
itBase = valueProducer->mCurrentBaseInfo.find(it->first.getDimensionKeyInWhat());
- EXPECT_TRUE(itBase->second[0].hasBase);
- EXPECT_EQ(5, itBase->second[0].base.long_value);
- EXPECT_TRUE(itBase->second[0].hasCurrentState);
- ASSERT_EQ(1, itBase->second[0].currentState.getValues().size());
+ EXPECT_TRUE(itBase->second.baseInfos[0].hasBase);
+ EXPECT_EQ(5, itBase->second.baseInfos[0].base.long_value);
+ EXPECT_TRUE(itBase->second.hasCurrentState);
+ ASSERT_EQ(1, itBase->second.currentState.getValues().size());
EXPECT_EQ(screenOnGroup.group_id(),
- itBase->second[0].currentState.getValues()[0].mValue.int_value);
+ itBase->second.currentState.getValues()[0].mValue.int_value);
// Value for dimension, state key {{}, kStateUnknown}
EXPECT_EQ(0, it->first.getDimensionKeyInWhat().getValues().size());
ASSERT_EQ(1, it->first.getStateValuesKey().getValues().size());
EXPECT_EQ(-1 /* StateTracker::kStateUnknown */,
it->first.getStateValuesKey().getValues()[0].mValue.int_value);
- EXPECT_TRUE(it->second[0].hasValue);
- EXPECT_EQ(2, it->second[0].value.long_value);
+ EXPECT_TRUE(it->second.intervals[0].hasValue);
+ EXPECT_EQ(2, it->second.intervals[0].value.long_value);
// Bucket status after screen state change VR->ON.
// Both ON and VR are in the same state group, so the base should not change.
@@ -4262,19 +4291,19 @@ TEST(ValueMetricProducerTest, TestSlicedStateWithMap) {
// Base for dimension key {}
it = valueProducer->mCurrentSlicedBucket.begin();
itBase = valueProducer->mCurrentBaseInfo.find(it->first.getDimensionKeyInWhat());
- EXPECT_TRUE(itBase->second[0].hasBase);
- EXPECT_EQ(5, itBase->second[0].base.long_value);
- EXPECT_TRUE(itBase->second[0].hasCurrentState);
- ASSERT_EQ(1, itBase->second[0].currentState.getValues().size());
+ EXPECT_TRUE(itBase->second.baseInfos[0].hasBase);
+ EXPECT_EQ(5, itBase->second.baseInfos[0].base.long_value);
+ EXPECT_TRUE(itBase->second.hasCurrentState);
+ ASSERT_EQ(1, itBase->second.currentState.getValues().size());
EXPECT_EQ(screenOnGroup.group_id(),
- itBase->second[0].currentState.getValues()[0].mValue.int_value);
+ itBase->second.currentState.getValues()[0].mValue.int_value);
// Value for dimension, state key {{}, kStateUnknown}
EXPECT_EQ(0, it->first.getDimensionKeyInWhat().getValues().size());
ASSERT_EQ(1, it->first.getStateValuesKey().getValues().size());
EXPECT_EQ(-1 /* StateTracker::kStateUnknown */,
it->first.getStateValuesKey().getValues()[0].mValue.int_value);
- EXPECT_TRUE(it->second[0].hasValue);
- EXPECT_EQ(2, it->second[0].value.long_value);
+ EXPECT_TRUE(it->second.intervals[0].hasValue);
+ EXPECT_EQ(2, it->second.intervals[0].value.long_value);
// Bucket status after screen state change VR->OFF.
screenEvent = CreateScreenStateChangedEvent(bucketStartTimeNs + 15,
@@ -4284,27 +4313,27 @@ TEST(ValueMetricProducerTest, TestSlicedStateWithMap) {
// Base for dimension key {}
it = valueProducer->mCurrentSlicedBucket.begin();
itBase = valueProducer->mCurrentBaseInfo.find(it->first.getDimensionKeyInWhat());
- EXPECT_TRUE(itBase->second[0].hasBase);
- EXPECT_EQ(21, itBase->second[0].base.long_value);
- EXPECT_TRUE(itBase->second[0].hasCurrentState);
- ASSERT_EQ(1, itBase->second[0].currentState.getValues().size());
+ EXPECT_TRUE(itBase->second.baseInfos[0].hasBase);
+ EXPECT_EQ(21, itBase->second.baseInfos[0].base.long_value);
+ EXPECT_TRUE(itBase->second.hasCurrentState);
+ ASSERT_EQ(1, itBase->second.currentState.getValues().size());
EXPECT_EQ(screenOffGroup.group_id(),
- itBase->second[0].currentState.getValues()[0].mValue.int_value);
+ itBase->second.currentState.getValues()[0].mValue.int_value);
// Value for dimension, state key {{}, ON GROUP}
EXPECT_EQ(0, it->first.getDimensionKeyInWhat().getValues().size());
ASSERT_EQ(1, it->first.getStateValuesKey().getValues().size());
EXPECT_EQ(screenOnGroup.group_id(),
it->first.getStateValuesKey().getValues()[0].mValue.long_value);
- EXPECT_TRUE(it->second[0].hasValue);
- EXPECT_EQ(16, it->second[0].value.long_value);
+ EXPECT_TRUE(it->second.intervals[0].hasValue);
+ EXPECT_EQ(16, it->second.intervals[0].value.long_value);
// Value for dimension, state key {{}, kStateUnknown}
it++;
EXPECT_EQ(0, it->first.getDimensionKeyInWhat().getValues().size());
ASSERT_EQ(1, it->first.getStateValuesKey().getValues().size());
EXPECT_EQ(-1 /* StateTracker::kStateUnknown */,
it->first.getStateValuesKey().getValues()[0].mValue.int_value);
- EXPECT_TRUE(it->second[0].hasValue);
- EXPECT_EQ(2, it->second[0].value.long_value);
+ EXPECT_TRUE(it->second.intervals[0].hasValue);
+ EXPECT_EQ(2, it->second.intervals[0].value.long_value);
// Start dump report and check output.
ProtoOutputStream output;
@@ -4447,35 +4476,35 @@ TEST(ValueMetricProducerTest, TestSlicedStateWithPrimaryField_WithDimensions) {
// Base for dimension key {uid 1}.
auto it = valueProducer->mCurrentSlicedBucket.begin();
auto itBase = valueProducer->mCurrentBaseInfo.find(it->first.getDimensionKeyInWhat());
- EXPECT_TRUE(itBase->second[0].hasBase);
- EXPECT_EQ(3, itBase->second[0].base.long_value);
- EXPECT_TRUE(itBase->second[0].hasCurrentState);
- ASSERT_EQ(1, itBase->second[0].currentState.getValues().size());
+ EXPECT_TRUE(itBase->second.baseInfos[0].hasBase);
+ EXPECT_EQ(3, itBase->second.baseInfos[0].base.long_value);
+ EXPECT_TRUE(itBase->second.hasCurrentState);
+ ASSERT_EQ(1, itBase->second.currentState.getValues().size());
EXPECT_EQ(-1 /* StateTracker::kStateUnknown */,
- itBase->second[0].currentState.getValues()[0].mValue.int_value);
+ itBase->second.currentState.getValues()[0].mValue.int_value);
// Value for dimension, state key {{uid 1}, kStateUnknown}
ASSERT_EQ(1, it->first.getDimensionKeyInWhat().getValues().size());
EXPECT_EQ(1, it->first.getDimensionKeyInWhat().getValues()[0].mValue.int_value);
ASSERT_EQ(1, it->first.getStateValuesKey().getValues().size());
EXPECT_EQ(-1 /* StateTracker::kStateUnknown */,
it->first.getStateValuesKey().getValues()[0].mValue.int_value);
- EXPECT_FALSE(it->second[0].hasValue);
+ EXPECT_FALSE(it->second.intervals[0].hasValue);
// Base for dimension key {uid 2}
it++;
itBase = valueProducer->mCurrentBaseInfo.find(it->first.getDimensionKeyInWhat());
- EXPECT_TRUE(itBase->second[0].hasBase);
- EXPECT_EQ(7, itBase->second[0].base.long_value);
- EXPECT_TRUE(itBase->second[0].hasCurrentState);
- ASSERT_EQ(1, itBase->second[0].currentState.getValues().size());
+ EXPECT_TRUE(itBase->second.baseInfos[0].hasBase);
+ EXPECT_EQ(7, itBase->second.baseInfos[0].base.long_value);
+ EXPECT_TRUE(itBase->second.hasCurrentState);
+ ASSERT_EQ(1, itBase->second.currentState.getValues().size());
EXPECT_EQ(-1 /* StateTracker::kStateUnknown */,
- itBase->second[0].currentState.getValues()[0].mValue.int_value);
+ itBase->second.currentState.getValues()[0].mValue.int_value);
// Value for dimension, state key {{uid 2}, kStateUnknown}
ASSERT_EQ(1, it->first.getDimensionKeyInWhat().getValues().size());
EXPECT_EQ(2, it->first.getDimensionKeyInWhat().getValues()[0].mValue.int_value);
ASSERT_EQ(1, it->first.getStateValuesKey().getValues().size());
EXPECT_EQ(-1 /* StateTracker::kStateUnknown */,
it->first.getStateValuesKey().getValues()[0].mValue.int_value);
- EXPECT_FALSE(it->second[0].hasValue);
+ EXPECT_FALSE(it->second.intervals[0].hasValue);
// Bucket status after uid 1 process state change kStateUnknown -> Foreground.
auto uidProcessEvent = CreateUidProcessStateChangedEvent(
@@ -4485,36 +4514,36 @@ TEST(ValueMetricProducerTest, TestSlicedStateWithPrimaryField_WithDimensions) {
// Base for dimension key {uid 1}.
it = valueProducer->mCurrentSlicedBucket.begin();
itBase = valueProducer->mCurrentBaseInfo.find(it->first.getDimensionKeyInWhat());
- EXPECT_TRUE(itBase->second[0].hasBase);
- EXPECT_EQ(6, itBase->second[0].base.long_value);
- EXPECT_TRUE(itBase->second[0].hasCurrentState);
- ASSERT_EQ(1, itBase->second[0].currentState.getValues().size());
+ EXPECT_TRUE(itBase->second.baseInfos[0].hasBase);
+ EXPECT_EQ(6, itBase->second.baseInfos[0].base.long_value);
+ EXPECT_TRUE(itBase->second.hasCurrentState);
+ ASSERT_EQ(1, itBase->second.currentState.getValues().size());
EXPECT_EQ(android::app::PROCESS_STATE_IMPORTANT_FOREGROUND,
- itBase->second[0].currentState.getValues()[0].mValue.int_value);
+ itBase->second.currentState.getValues()[0].mValue.int_value);
// Value for key {uid 1, kStateUnknown}.
ASSERT_EQ(1, it->first.getDimensionKeyInWhat().getValues().size());
EXPECT_EQ(1, it->first.getDimensionKeyInWhat().getValues()[0].mValue.int_value);
ASSERT_EQ(1, it->first.getStateValuesKey().getValues().size());
EXPECT_EQ(-1 /* StateTracker::kStateUnknown */,
it->first.getStateValuesKey().getValues()[0].mValue.int_value);
- EXPECT_TRUE(it->second[0].hasValue);
- EXPECT_EQ(3, it->second[0].value.long_value);
+ EXPECT_TRUE(it->second.intervals[0].hasValue);
+ EXPECT_EQ(3, it->second.intervals[0].value.long_value);
// Base for dimension key {uid 2}
it++;
itBase = valueProducer->mCurrentBaseInfo.find(it->first.getDimensionKeyInWhat());
- EXPECT_TRUE(itBase->second[0].hasBase);
- EXPECT_EQ(7, itBase->second[0].base.long_value);
- EXPECT_TRUE(itBase->second[0].hasCurrentState);
- ASSERT_EQ(1, itBase->second[0].currentState.getValues().size());
+ EXPECT_TRUE(itBase->second.baseInfos[0].hasBase);
+ EXPECT_EQ(7, itBase->second.baseInfos[0].base.long_value);
+ EXPECT_TRUE(itBase->second.hasCurrentState);
+ ASSERT_EQ(1, itBase->second.currentState.getValues().size());
EXPECT_EQ(-1 /* StateTracker::kStateUnknown */,
- itBase->second[0].currentState.getValues()[0].mValue.int_value);
+ itBase->second.currentState.getValues()[0].mValue.int_value);
// Value for key {uid 2, kStateUnknown}
ASSERT_EQ(1, it->first.getDimensionKeyInWhat().getValues().size());
EXPECT_EQ(2, it->first.getDimensionKeyInWhat().getValues()[0].mValue.int_value);
ASSERT_EQ(1, it->first.getStateValuesKey().getValues().size());
EXPECT_EQ(-1, it->first.getStateValuesKey().getValues()[0].mValue.int_value);
- EXPECT_FALSE(it->second[0].hasValue);
+ EXPECT_FALSE(it->second.intervals[0].hasValue);
// Bucket status after uid 2 process state change kStateUnknown -> Background.
uidProcessEvent = CreateUidProcessStateChangedEvent(
@@ -4524,36 +4553,36 @@ TEST(ValueMetricProducerTest, TestSlicedStateWithPrimaryField_WithDimensions) {
// Base for dimension key {uid 1}.
it = valueProducer->mCurrentSlicedBucket.begin();
itBase = valueProducer->mCurrentBaseInfo.find(it->first.getDimensionKeyInWhat());
- EXPECT_TRUE(itBase->second[0].hasBase);
- EXPECT_EQ(6, itBase->second[0].base.long_value);
- EXPECT_TRUE(itBase->second[0].hasCurrentState);
- ASSERT_EQ(1, itBase->second[0].currentState.getValues().size());
+ EXPECT_TRUE(itBase->second.baseInfos[0].hasBase);
+ EXPECT_EQ(6, itBase->second.baseInfos[0].base.long_value);
+ EXPECT_TRUE(itBase->second.hasCurrentState);
+ ASSERT_EQ(1, itBase->second.currentState.getValues().size());
EXPECT_EQ(android::app::PROCESS_STATE_IMPORTANT_FOREGROUND,
- itBase->second[0].currentState.getValues()[0].mValue.int_value);
+ itBase->second.currentState.getValues()[0].mValue.int_value);
// Value for key {uid 1, kStateUnknown}.
ASSERT_EQ(1, it->first.getDimensionKeyInWhat().getValues().size());
EXPECT_EQ(1, it->first.getDimensionKeyInWhat().getValues()[0].mValue.int_value);
ASSERT_EQ(1, it->first.getStateValuesKey().getValues().size());
EXPECT_EQ(-1, it->first.getStateValuesKey().getValues()[0].mValue.int_value);
- EXPECT_TRUE(it->second[0].hasValue);
- EXPECT_EQ(3, it->second[0].value.long_value);
+ EXPECT_TRUE(it->second.intervals[0].hasValue);
+ EXPECT_EQ(3, it->second.intervals[0].value.long_value);
// Base for dimension key {uid 2}
it++;
itBase = valueProducer->mCurrentBaseInfo.find(it->first.getDimensionKeyInWhat());
- EXPECT_TRUE(itBase->second[0].hasBase);
- EXPECT_EQ(9, itBase->second[0].base.long_value);
- EXPECT_TRUE(itBase->second[0].hasCurrentState);
- ASSERT_EQ(1, itBase->second[0].currentState.getValues().size());
+ EXPECT_TRUE(itBase->second.baseInfos[0].hasBase);
+ EXPECT_EQ(9, itBase->second.baseInfos[0].base.long_value);
+ EXPECT_TRUE(itBase->second.hasCurrentState);
+ ASSERT_EQ(1, itBase->second.currentState.getValues().size());
EXPECT_EQ(android::app::PROCESS_STATE_IMPORTANT_BACKGROUND,
- itBase->second[0].currentState.getValues()[0].mValue.int_value);
+ itBase->second.currentState.getValues()[0].mValue.int_value);
// Value for key {uid 2, kStateUnknown}
ASSERT_EQ(1, it->first.getDimensionKeyInWhat().getValues().size());
EXPECT_EQ(2, it->first.getDimensionKeyInWhat().getValues()[0].mValue.int_value);
ASSERT_EQ(1, it->first.getStateValuesKey().getValues().size());
EXPECT_EQ(-1, it->first.getStateValuesKey().getValues()[0].mValue.int_value);
- EXPECT_TRUE(it->second[0].hasValue);
- EXPECT_EQ(2, it->second[0].value.long_value);
+ EXPECT_TRUE(it->second.intervals[0].hasValue);
+ EXPECT_EQ(2, it->second.intervals[0].value.long_value);
// Pull at end of first bucket.
vector<shared_ptr<LogEvent>> allData;
@@ -4570,36 +4599,36 @@ TEST(ValueMetricProducerTest, TestSlicedStateWithPrimaryField_WithDimensions) {
it = valueProducer->mCurrentSlicedBucket.begin();
EXPECT_EQ(2, it->first.getDimensionKeyInWhat().getValues()[0].mValue.int_value);
itBase = valueProducer->mCurrentBaseInfo.find(it->first.getDimensionKeyInWhat());
- EXPECT_TRUE(itBase->second[0].hasBase);
- EXPECT_EQ(15, itBase->second[0].base.long_value);
- EXPECT_TRUE(itBase->second[0].hasCurrentState);
- ASSERT_EQ(1, itBase->second[0].currentState.getValues().size());
+ EXPECT_TRUE(itBase->second.baseInfos[0].hasBase);
+ EXPECT_EQ(15, itBase->second.baseInfos[0].base.long_value);
+ EXPECT_TRUE(itBase->second.hasCurrentState);
+ ASSERT_EQ(1, itBase->second.currentState.getValues().size());
EXPECT_EQ(android::app::PROCESS_STATE_IMPORTANT_BACKGROUND,
- itBase->second[0].currentState.getValues()[0].mValue.int_value);
+ itBase->second.currentState.getValues()[0].mValue.int_value);
// Value for key {uid 2, BACKGROUND}.
ASSERT_EQ(1, it->first.getDimensionKeyInWhat().getValues().size());
EXPECT_EQ(2, it->first.getDimensionKeyInWhat().getValues()[0].mValue.int_value);
ASSERT_EQ(1, it->first.getStateValuesKey().getValues().size());
EXPECT_EQ(android::app::PROCESS_STATE_IMPORTANT_BACKGROUND,
it->first.getStateValuesKey().getValues()[0].mValue.int_value);
- EXPECT_FALSE(it->second[0].hasValue);
+ EXPECT_FALSE(it->second.intervals[0].hasValue);
// Base for dimension key {uid 1}
it++;
itBase = valueProducer->mCurrentBaseInfo.find(it->first.getDimensionKeyInWhat());
- EXPECT_TRUE(itBase->second[0].hasBase);
- EXPECT_EQ(10, itBase->second[0].base.long_value);
- EXPECT_TRUE(itBase->second[0].hasCurrentState);
- ASSERT_EQ(1, itBase->second[0].currentState.getValues().size());
+ EXPECT_TRUE(itBase->second.baseInfos[0].hasBase);
+ EXPECT_EQ(10, itBase->second.baseInfos[0].base.long_value);
+ EXPECT_TRUE(itBase->second.hasCurrentState);
+ ASSERT_EQ(1, itBase->second.currentState.getValues().size());
EXPECT_EQ(android::app::PROCESS_STATE_IMPORTANT_FOREGROUND,
- itBase->second[0].currentState.getValues()[0].mValue.int_value);
+ itBase->second.currentState.getValues()[0].mValue.int_value);
// Value for key {uid 1, kStateUnknown}
ASSERT_EQ(1, it->first.getDimensionKeyInWhat().getValues().size());
EXPECT_EQ(1, it->first.getDimensionKeyInWhat().getValues()[0].mValue.int_value);
ASSERT_EQ(1, it->first.getStateValuesKey().getValues().size());
EXPECT_EQ(-1 /* kStateTracker::kUnknown */,
it->first.getStateValuesKey().getValues()[0].mValue.int_value);
- EXPECT_FALSE(it->second[0].hasValue);
+ EXPECT_FALSE(it->second.intervals[0].hasValue);
// Value for key {uid 1, FOREGROUND}
it++;
@@ -4608,7 +4637,7 @@ TEST(ValueMetricProducerTest, TestSlicedStateWithPrimaryField_WithDimensions) {
ASSERT_EQ(1, it->first.getStateValuesKey().getValues().size());
EXPECT_EQ(android::app::PROCESS_STATE_IMPORTANT_FOREGROUND,
it->first.getStateValuesKey().getValues()[0].mValue.int_value);
- EXPECT_FALSE(it->second[0].hasValue);
+ EXPECT_FALSE(it->second.intervals[0].hasValue);
// Value for key {uid 2, kStateUnknown}
it++;
@@ -4617,7 +4646,7 @@ TEST(ValueMetricProducerTest, TestSlicedStateWithPrimaryField_WithDimensions) {
ASSERT_EQ(1, it->first.getStateValuesKey().getValues().size());
EXPECT_EQ(-1 /* kStateTracker::kUnknown */,
it->first.getStateValuesKey().getValues()[0].mValue.int_value);
- EXPECT_FALSE(it->second[0].hasValue);
+ EXPECT_FALSE(it->second.intervals[0].hasValue);
// Bucket status after uid 1 process state change from Foreground -> Background.
uidProcessEvent = CreateUidProcessStateChangedEvent(
@@ -4630,35 +4659,35 @@ TEST(ValueMetricProducerTest, TestSlicedStateWithPrimaryField_WithDimensions) {
// Base for dimension key {uid 2}.
it = valueProducer->mCurrentSlicedBucket.begin();
itBase = valueProducer->mCurrentBaseInfo.find(it->first.getDimensionKeyInWhat());
- EXPECT_TRUE(itBase->second[0].hasBase);
- EXPECT_EQ(15, itBase->second[0].base.long_value);
- EXPECT_TRUE(itBase->second[0].hasCurrentState);
- ASSERT_EQ(1, itBase->second[0].currentState.getValues().size());
+ EXPECT_TRUE(itBase->second.baseInfos[0].hasBase);
+ EXPECT_EQ(15, itBase->second.baseInfos[0].base.long_value);
+ EXPECT_TRUE(itBase->second.hasCurrentState);
+ ASSERT_EQ(1, itBase->second.currentState.getValues().size());
EXPECT_EQ(android::app::PROCESS_STATE_IMPORTANT_BACKGROUND,
- itBase->second[0].currentState.getValues()[0].mValue.int_value);
+ itBase->second.currentState.getValues()[0].mValue.int_value);
// Value for key {uid 2, BACKGROUND}.
ASSERT_EQ(1, it->first.getDimensionKeyInWhat().getValues().size());
EXPECT_EQ(2, it->first.getDimensionKeyInWhat().getValues()[0].mValue.int_value);
ASSERT_EQ(1, it->first.getStateValuesKey().getValues().size());
EXPECT_EQ(android::app::PROCESS_STATE_IMPORTANT_BACKGROUND,
it->first.getStateValuesKey().getValues()[0].mValue.int_value);
- EXPECT_FALSE(it->second[0].hasValue);
+ EXPECT_FALSE(it->second.intervals[0].hasValue);
// Base for dimension key {uid 1}
it++;
itBase = valueProducer->mCurrentBaseInfo.find(it->first.getDimensionKeyInWhat());
- EXPECT_TRUE(itBase->second[0].hasBase);
- EXPECT_EQ(13, itBase->second[0].base.long_value);
- EXPECT_TRUE(itBase->second[0].hasCurrentState);
- ASSERT_EQ(1, itBase->second[0].currentState.getValues().size());
+ EXPECT_TRUE(itBase->second.baseInfos[0].hasBase);
+ EXPECT_EQ(13, itBase->second.baseInfos[0].base.long_value);
+ EXPECT_TRUE(itBase->second.hasCurrentState);
+ ASSERT_EQ(1, itBase->second.currentState.getValues().size());
EXPECT_EQ(android::app::PROCESS_STATE_IMPORTANT_BACKGROUND,
- itBase->second[0].currentState.getValues()[0].mValue.int_value);
+ itBase->second.currentState.getValues()[0].mValue.int_value);
// Value for key {uid 1, kStateUnknown}
ASSERT_EQ(1, it->first.getDimensionKeyInWhat().getValues().size());
EXPECT_EQ(1, it->first.getDimensionKeyInWhat().getValues()[0].mValue.int_value);
ASSERT_EQ(1, it->first.getStateValuesKey().getValues().size());
EXPECT_EQ(-1 /* StateTracker::kStateUnknown */,
it->first.getStateValuesKey().getValues()[0].mValue.int_value);
- EXPECT_FALSE(it->second[0].hasValue);
+ EXPECT_FALSE(it->second.intervals[0].hasValue);
// Value for key {uid 1, FOREGROUND}
it++;
ASSERT_EQ(1, it->first.getDimensionKeyInWhat().getValues().size());
@@ -4666,8 +4695,8 @@ TEST(ValueMetricProducerTest, TestSlicedStateWithPrimaryField_WithDimensions) {
ASSERT_EQ(1, it->first.getStateValuesKey().getValues().size());
EXPECT_EQ(android::app::PROCESS_STATE_IMPORTANT_FOREGROUND,
it->first.getStateValuesKey().getValues()[0].mValue.int_value);
- EXPECT_TRUE(it->second[0].hasValue);
- EXPECT_EQ(3, it->second[0].value.long_value);
+ EXPECT_TRUE(it->second.intervals[0].hasValue);
+ EXPECT_EQ(3, it->second.intervals[0].value.long_value);
// Value for key {uid 2, kStateUnknown}
it++;
ASSERT_EQ(1, it->first.getDimensionKeyInWhat().getValues().size());
@@ -4675,7 +4704,7 @@ TEST(ValueMetricProducerTest, TestSlicedStateWithPrimaryField_WithDimensions) {
ASSERT_EQ(1, it->first.getStateValuesKey().getValues().size());
EXPECT_EQ(-1 /* StateTracker::kStateUnknown */,
it->first.getStateValuesKey().getValues()[0].mValue.int_value);
- EXPECT_FALSE(it->second[0].hasValue);
+ EXPECT_FALSE(it->second.intervals[0].hasValue);
// Bucket status after uid 1 process state change Background->Foreground.
uidProcessEvent = CreateUidProcessStateChangedEvent(
@@ -4687,36 +4716,36 @@ TEST(ValueMetricProducerTest, TestSlicedStateWithPrimaryField_WithDimensions) {
// Base for dimension key {uid 2}
it = valueProducer->mCurrentSlicedBucket.begin();
itBase = valueProducer->mCurrentBaseInfo.find(it->first.getDimensionKeyInWhat());
- EXPECT_TRUE(itBase->second[0].hasBase);
- EXPECT_EQ(15, itBase->second[0].base.long_value);
- EXPECT_TRUE(itBase->second[0].hasCurrentState);
- ASSERT_EQ(1, itBase->second[0].currentState.getValues().size());
+ EXPECT_TRUE(itBase->second.baseInfos[0].hasBase);
+ EXPECT_EQ(15, itBase->second.baseInfos[0].base.long_value);
+ EXPECT_TRUE(itBase->second.hasCurrentState);
+ ASSERT_EQ(1, itBase->second.currentState.getValues().size());
EXPECT_EQ(android::app::PROCESS_STATE_IMPORTANT_BACKGROUND,
- itBase->second[0].currentState.getValues()[0].mValue.int_value);
+ itBase->second.currentState.getValues()[0].mValue.int_value);
// Value for key {uid 2, BACKGROUND}
ASSERT_EQ(1, it->first.getDimensionKeyInWhat().getValues().size());
EXPECT_EQ(2, it->first.getDimensionKeyInWhat().getValues()[0].mValue.int_value);
ASSERT_EQ(1, it->first.getStateValuesKey().getValues().size());
EXPECT_EQ(android::app::PROCESS_STATE_IMPORTANT_BACKGROUND,
it->first.getStateValuesKey().getValues()[0].mValue.int_value);
- EXPECT_FALSE(it->second[0].hasValue);
+ EXPECT_FALSE(it->second.intervals[0].hasValue);
// Base for dimension key {uid 1}
it++;
itBase = valueProducer->mCurrentBaseInfo.find(it->first.getDimensionKeyInWhat());
- EXPECT_TRUE(itBase->second[0].hasBase);
- EXPECT_EQ(17, itBase->second[0].base.long_value);
- EXPECT_TRUE(itBase->second[0].hasCurrentState);
- ASSERT_EQ(1, itBase->second[0].currentState.getValues().size());
+ EXPECT_TRUE(itBase->second.baseInfos[0].hasBase);
+ EXPECT_EQ(17, itBase->second.baseInfos[0].base.long_value);
+ EXPECT_TRUE(itBase->second.hasCurrentState);
+ ASSERT_EQ(1, itBase->second.currentState.getValues().size());
EXPECT_EQ(android::app::PROCESS_STATE_IMPORTANT_FOREGROUND,
- itBase->second[0].currentState.getValues()[0].mValue.int_value);
+ itBase->second.currentState.getValues()[0].mValue.int_value);
// Value for key {uid 1, kStateUnknown}
ASSERT_EQ(1, it->first.getDimensionKeyInWhat().getValues().size());
EXPECT_EQ(1, it->first.getDimensionKeyInWhat().getValues()[0].mValue.int_value);
ASSERT_EQ(1, it->first.getStateValuesKey().getValues().size());
EXPECT_EQ(-1 /* StateTracker::kStateUnknown */,
it->first.getStateValuesKey().getValues()[0].mValue.int_value);
- EXPECT_FALSE(it->second[0].hasValue);
+ EXPECT_FALSE(it->second.intervals[0].hasValue);
// Value for key {uid 1, BACKGROUND}
it++;
@@ -4725,8 +4754,8 @@ TEST(ValueMetricProducerTest, TestSlicedStateWithPrimaryField_WithDimensions) {
ASSERT_EQ(1, it->first.getStateValuesKey().getValues().size());
EXPECT_EQ(android::app::PROCESS_STATE_IMPORTANT_BACKGROUND,
it->first.getStateValuesKey().getValues()[0].mValue.int_value);
- EXPECT_TRUE(it->second[0].hasValue);
- EXPECT_EQ(4, it->second[0].value.long_value);
+ EXPECT_TRUE(it->second.intervals[0].hasValue);
+ EXPECT_EQ(4, it->second.intervals[0].value.long_value);
// Value for key {uid 1, FOREGROUND}
it++;
@@ -4735,8 +4764,8 @@ TEST(ValueMetricProducerTest, TestSlicedStateWithPrimaryField_WithDimensions) {
ASSERT_EQ(1, it->first.getStateValuesKey().getValues().size());
EXPECT_EQ(android::app::PROCESS_STATE_IMPORTANT_FOREGROUND,
it->first.getStateValuesKey().getValues()[0].mValue.int_value);
- EXPECT_TRUE(it->second[0].hasValue);
- EXPECT_EQ(3, it->second[0].value.long_value);
+ EXPECT_TRUE(it->second.intervals[0].hasValue);
+ EXPECT_EQ(3, it->second.intervals[0].value.long_value);
// Value for key {uid 2, kStateUnknown}
it++;
@@ -4857,23 +4886,23 @@ TEST(ValueMetricProducerTest, TestSlicedStateWithCondition) {
valueProducer->onConditionChanged(true, bucketStartTimeNs + 20 * NS_PER_SEC);
// Base for dimension key {}
ASSERT_EQ(1UL, valueProducer->mCurrentBaseInfo.size());
- std::unordered_map<HashableDimensionKey, std::vector<ValueMetricProducer::BaseInfo>>::iterator
+ std::unordered_map<HashableDimensionKey, ValueMetricProducer::DimensionsInWhatInfo>::iterator
itBase = valueProducer->mCurrentBaseInfo.find(DEFAULT_DIMENSION_KEY);
- EXPECT_TRUE(itBase->second[0].hasBase);
- EXPECT_EQ(3, itBase->second[0].base.long_value);
- EXPECT_TRUE(itBase->second[0].hasCurrentState);
- ASSERT_EQ(1, itBase->second[0].currentState.getValues().size());
+ EXPECT_TRUE(itBase->second.baseInfos[0].hasBase);
+ EXPECT_EQ(3, itBase->second.baseInfos[0].base.long_value);
+ EXPECT_TRUE(itBase->second.hasCurrentState);
+ ASSERT_EQ(1, itBase->second.currentState.getValues().size());
EXPECT_EQ(BatterySaverModeStateChanged::ON,
- itBase->second[0].currentState.getValues()[0].mValue.int_value);
+ itBase->second.currentState.getValues()[0].mValue.int_value);
// Value for key {{}, -1}
ASSERT_EQ(1UL, valueProducer->mCurrentSlicedBucket.size());
- std::unordered_map<MetricDimensionKey, std::vector<ValueMetricProducer::Interval>>::iterator
- it = valueProducer->mCurrentSlicedBucket.begin();
+ std::unordered_map<MetricDimensionKey, ValueMetricProducer::CurrentValueBucket>::iterator it =
+ valueProducer->mCurrentSlicedBucket.begin();
EXPECT_EQ(0, it->first.getDimensionKeyInWhat().getValues().size());
ASSERT_EQ(1, it->first.getStateValuesKey().getValues().size());
EXPECT_EQ(-1 /*StateTracker::kUnknown*/,
it->first.getStateValuesKey().getValues()[0].mValue.int_value);
- EXPECT_FALSE(it->second[0].hasValue);
+ EXPECT_FALSE(it->second.intervals[0].hasValue);
// Bucket status after battery saver mode OFF event.
unique_ptr<LogEvent> batterySaverOffEvent =
@@ -4882,12 +4911,12 @@ TEST(ValueMetricProducerTest, TestSlicedStateWithCondition) {
// Base for dimension key {}
ASSERT_EQ(1UL, valueProducer->mCurrentBaseInfo.size());
itBase = valueProducer->mCurrentBaseInfo.find(DEFAULT_DIMENSION_KEY);
- EXPECT_TRUE(itBase->second[0].hasBase);
- EXPECT_EQ(5, itBase->second[0].base.long_value);
- EXPECT_TRUE(itBase->second[0].hasCurrentState);
- ASSERT_EQ(1, itBase->second[0].currentState.getValues().size());
+ EXPECT_TRUE(itBase->second.baseInfos[0].hasBase);
+ EXPECT_EQ(5, itBase->second.baseInfos[0].base.long_value);
+ EXPECT_TRUE(itBase->second.hasCurrentState);
+ ASSERT_EQ(1, itBase->second.currentState.getValues().size());
EXPECT_EQ(BatterySaverModeStateChanged::OFF,
- itBase->second[0].currentState.getValues()[0].mValue.int_value);
+ itBase->second.currentState.getValues()[0].mValue.int_value);
// Value for key {{}, ON}
ASSERT_EQ(2UL, valueProducer->mCurrentSlicedBucket.size());
it = valueProducer->mCurrentSlicedBucket.begin();
@@ -4895,8 +4924,8 @@ TEST(ValueMetricProducerTest, TestSlicedStateWithCondition) {
ASSERT_EQ(1, it->first.getStateValuesKey().getValues().size());
EXPECT_EQ(BatterySaverModeStateChanged::ON,
it->first.getStateValuesKey().getValues()[0].mValue.int_value);
- EXPECT_TRUE(it->second[0].hasValue);
- EXPECT_EQ(2, it->second[0].value.long_value);
+ EXPECT_TRUE(it->second.intervals[0].hasValue);
+ EXPECT_EQ(2, it->second.intervals[0].value.long_value);
// Pull at end of first bucket.
vector<shared_ptr<LogEvent>> allData;
@@ -4909,23 +4938,23 @@ TEST(ValueMetricProducerTest, TestSlicedStateWithCondition) {
// Base for dimension key {}
ASSERT_EQ(1UL, valueProducer->mCurrentBaseInfo.size());
itBase = valueProducer->mCurrentBaseInfo.find(DEFAULT_DIMENSION_KEY);
- EXPECT_TRUE(itBase->second[0].hasBase);
- EXPECT_EQ(11, itBase->second[0].base.long_value);
- EXPECT_TRUE(itBase->second[0].hasCurrentState);
- ASSERT_EQ(1, itBase->second[0].currentState.getValues().size());
+ EXPECT_TRUE(itBase->second.baseInfos[0].hasBase);
+ EXPECT_EQ(11, itBase->second.baseInfos[0].base.long_value);
+ EXPECT_TRUE(itBase->second.hasCurrentState);
+ ASSERT_EQ(1, itBase->second.currentState.getValues().size());
EXPECT_EQ(BatterySaverModeStateChanged::OFF,
- itBase->second[0].currentState.getValues()[0].mValue.int_value);
+ itBase->second.currentState.getValues()[0].mValue.int_value);
// Bucket 2 status after condition change to false.
valueProducer->onConditionChanged(false, bucket2StartTimeNs + 10 * NS_PER_SEC);
// Base for dimension key {}
ASSERT_EQ(1UL, valueProducer->mCurrentBaseInfo.size());
itBase = valueProducer->mCurrentBaseInfo.find(DEFAULT_DIMENSION_KEY);
- EXPECT_FALSE(itBase->second[0].hasBase);
- EXPECT_TRUE(itBase->second[0].hasCurrentState);
- ASSERT_EQ(1, itBase->second[0].currentState.getValues().size());
+ EXPECT_FALSE(itBase->second.baseInfos[0].hasBase);
+ EXPECT_TRUE(itBase->second.hasCurrentState);
+ ASSERT_EQ(1, itBase->second.currentState.getValues().size());
EXPECT_EQ(BatterySaverModeStateChanged::OFF,
- itBase->second[0].currentState.getValues()[0].mValue.int_value);
+ itBase->second.currentState.getValues()[0].mValue.int_value);
// Value for key {{}, OFF}
ASSERT_EQ(3UL, valueProducer->mCurrentSlicedBucket.size());
it = valueProducer->mCurrentSlicedBucket.begin();
@@ -4933,8 +4962,8 @@ TEST(ValueMetricProducerTest, TestSlicedStateWithCondition) {
ASSERT_EQ(1, it->first.getStateValuesKey().getValues().size());
EXPECT_EQ(BatterySaverModeStateChanged::OFF,
it->first.getStateValuesKey().getValues()[0].mValue.int_value);
- EXPECT_TRUE(it->second[0].hasValue);
- EXPECT_EQ(4, it->second[0].value.long_value);
+ EXPECT_TRUE(it->second.intervals[0].hasValue);
+ EXPECT_EQ(4, it->second.intervals[0].value.long_value);
// Start dump report and check output.
ProtoOutputStream output;
diff --git a/cmds/statsd/tests/metrics/parsing_utils/config_update_utils_test.cpp b/cmds/statsd/tests/metrics/parsing_utils/config_update_utils_test.cpp
index 8c698eb15d8d..843d836a2c0b 100644
--- a/cmds/statsd/tests/metrics/parsing_utils/config_update_utils_test.cpp
+++ b/cmds/statsd/tests/metrics/parsing_utils/config_update_utils_test.cpp
@@ -14,6 +14,7 @@
#include "src/metrics/parsing_utils/config_update_utils.h"
+#include <gmock/gmock.h>
#include <gtest/gtest.h>
#include <private/android_filesystem_config.h>
#include <stdio.h>
@@ -23,6 +24,8 @@
#include <vector>
#include "frameworks/base/cmds/statsd/src/statsd_config.pb.h"
+#include "src/condition/CombinationConditionTracker.h"
+#include "src/condition/SimpleConditionTracker.h"
#include "src/matchers/CombinationAtomMatchingTracker.h"
#include "src/metrics/parsing_utils/metrics_manager_util.h"
#include "tests/statsd_test_util.h"
@@ -53,7 +56,9 @@ set<int> allTagIds;
vector<sp<AtomMatchingTracker>> oldAtomMatchingTrackers;
unordered_map<int64_t, int> oldAtomMatchingTrackerMap;
vector<sp<ConditionTracker>> oldConditionTrackers;
+unordered_map<int64_t, int> oldConditionTrackerMap;
vector<sp<MetricProducer>> oldMetricProducers;
+unordered_map<int64_t, int> oldMetricProducerMap;
std::vector<sp<AnomalyTracker>> oldAnomalyTrackers;
std::vector<sp<AlarmTracker>> oldAlarmTrackers;
unordered_map<int, std::vector<int>> conditionToMetricMap;
@@ -63,6 +68,7 @@ unordered_map<int, std::vector<int>> activationAtomTrackerToMetricMap;
unordered_map<int, std::vector<int>> deactivationAtomTrackerToMetricMap;
unordered_map<int64_t, int> alertTrackerMap;
vector<int> metricsWithActivation;
+map<int64_t, uint64_t> oldStateHashes;
std::set<int64_t> noReportMetricIds;
class ConfigUpdateTest : public ::testing::Test {
@@ -75,7 +81,9 @@ public:
oldAtomMatchingTrackers.clear();
oldAtomMatchingTrackerMap.clear();
oldConditionTrackers.clear();
+ oldConditionTrackerMap.clear();
oldMetricProducers.clear();
+ oldMetricProducerMap.clear();
oldAnomalyTrackers.clear();
oldAlarmTrackers.clear();
conditionToMetricMap.clear();
@@ -85,6 +93,7 @@ public:
deactivationAtomTrackerToMetricMap.clear();
alertTrackerMap.clear();
metricsWithActivation.clear();
+ oldStateHashes.clear();
noReportMetricIds.clear();
}
};
@@ -93,10 +102,11 @@ bool initConfig(const StatsdConfig& config) {
return initStatsdConfig(
key, config, uidMap, pullerManager, anomalyAlarmMonitor, periodicAlarmMonitor,
timeBaseNs, timeBaseNs, allTagIds, oldAtomMatchingTrackers, oldAtomMatchingTrackerMap,
- oldConditionTrackers, oldMetricProducers, oldAnomalyTrackers, oldAlarmTrackers,
- conditionToMetricMap, trackerToMetricMap, trackerToConditionMap,
- activationAtomTrackerToMetricMap, deactivationAtomTrackerToMetricMap, alertTrackerMap,
- metricsWithActivation, noReportMetricIds);
+ oldConditionTrackers, oldConditionTrackerMap, oldMetricProducers, oldMetricProducerMap,
+ oldAnomalyTrackers, oldAlarmTrackers, conditionToMetricMap, trackerToMetricMap,
+ trackerToConditionMap, activationAtomTrackerToMetricMap,
+ deactivationAtomTrackerToMetricMap, alertTrackerMap, metricsWithActivation,
+ oldStateHashes, noReportMetricIds);
}
} // anonymous namespace
@@ -144,6 +154,30 @@ TEST_F(ConfigUpdateTest, TestSimpleMatcherReplace) {
EXPECT_EQ(matchersToUpdate[0], UPDATE_REPLACE);
}
+TEST_F(ConfigUpdateTest, TestSimpleMatcherNew) {
+ StatsdConfig config;
+ AtomMatcher matcher = CreateSimpleAtomMatcher("TEST", /*atom=*/10);
+ *config.add_atom_matcher() = matcher;
+
+ EXPECT_TRUE(initConfig(config));
+
+ StatsdConfig newConfig;
+ // Different id, so should be a new matcher.
+ AtomMatcher newMatcher = CreateSimpleAtomMatcher("DIFFERENT_NAME", /*atom=*/10);
+ int64_t matcherId = newMatcher.id();
+ EXPECT_NE(matcherId, matcher.id());
+ *newConfig.add_atom_matcher() = newMatcher;
+
+ vector<UpdateStatus> matchersToUpdate(1, UPDATE_UNKNOWN);
+ vector<bool> cycleTracker(1, false);
+ unordered_map<int64_t, int> newAtomMatchingTrackerMap;
+ newAtomMatchingTrackerMap[matcherId] = 0;
+ EXPECT_TRUE(determineMatcherUpdateStatus(newConfig, 0, oldAtomMatchingTrackerMap,
+ oldAtomMatchingTrackers, newAtomMatchingTrackerMap,
+ matchersToUpdate, cycleTracker));
+ EXPECT_EQ(matchersToUpdate[0], UPDATE_NEW);
+}
+
TEST_F(ConfigUpdateTest, TestCombinationMatcherPreserve) {
StatsdConfig config;
AtomMatcher matcher1 = CreateSimpleAtomMatcher("TEST1", /*atom=*/10);
@@ -338,9 +372,10 @@ TEST_F(ConfigUpdateTest, TestUpdateMatchers) {
set<int> newTagIds;
unordered_map<int64_t, int> newAtomMatchingTrackerMap;
vector<sp<AtomMatchingTracker>> newAtomMatchingTrackers;
- EXPECT_TRUE(updateAtomTrackers(newConfig, uidMap, oldAtomMatchingTrackerMap,
- oldAtomMatchingTrackers, newTagIds, newAtomMatchingTrackerMap,
- newAtomMatchingTrackers));
+ set<int64_t> replacedMatchers;
+ EXPECT_TRUE(updateAtomMatchingTrackers(
+ newConfig, uidMap, oldAtomMatchingTrackerMap, oldAtomMatchingTrackers, newTagIds,
+ newAtomMatchingTrackerMap, newAtomMatchingTrackers, replacedMatchers));
ASSERT_EQ(newTagIds.size(), 3);
EXPECT_EQ(newTagIds.count(10), 1);
@@ -405,8 +440,454 @@ TEST_F(ConfigUpdateTest, TestUpdateMatchers) {
EXPECT_EQ(childMatchers->size(), 2);
EXPECT_NE(std::find(childMatchers->begin(), childMatchers->end(), 1), childMatchers->end());
EXPECT_NE(std::find(childMatchers->begin(), childMatchers->end(), 4), childMatchers->end());
+
+ // Expect replacedMatchers to have simple2 and combination2
+ ASSERT_EQ(replacedMatchers.size(), 2);
+ EXPECT_NE(replacedMatchers.find(simple2Id), replacedMatchers.end());
+ EXPECT_NE(replacedMatchers.find(combination2Id), replacedMatchers.end());
+}
+
+TEST_F(ConfigUpdateTest, TestSimpleConditionPreserve) {
+ StatsdConfig config;
+ AtomMatcher startMatcher = CreateScreenTurnedOnAtomMatcher();
+ *config.add_atom_matcher() = startMatcher;
+ AtomMatcher stopMatcher = CreateScreenTurnedOffAtomMatcher();
+ *config.add_atom_matcher() = stopMatcher;
+
+ Predicate predicate = CreateScreenIsOnPredicate();
+ *config.add_predicate() = predicate;
+
+ // Create an initial config.
+ EXPECT_TRUE(initConfig(config));
+
+ set<int64_t> replacedMatchers;
+ vector<UpdateStatus> conditionsToUpdate(1, UPDATE_UNKNOWN);
+ vector<bool> cycleTracker(1, false);
+ unordered_map<int64_t, int> newConditionTrackerMap;
+ newConditionTrackerMap[predicate.id()] = 0;
+ EXPECT_TRUE(determineConditionUpdateStatus(config, 0, oldConditionTrackerMap,
+ oldConditionTrackers, newConditionTrackerMap,
+ replacedMatchers, conditionsToUpdate, cycleTracker));
+ EXPECT_EQ(conditionsToUpdate[0], UPDATE_PRESERVE);
+}
+
+TEST_F(ConfigUpdateTest, TestSimpleConditionReplace) {
+ StatsdConfig config;
+ AtomMatcher startMatcher = CreateScreenTurnedOnAtomMatcher();
+ *config.add_atom_matcher() = startMatcher;
+ AtomMatcher stopMatcher = CreateScreenTurnedOffAtomMatcher();
+ *config.add_atom_matcher() = stopMatcher;
+
+ Predicate predicate = CreateScreenIsOnPredicate();
+ *config.add_predicate() = predicate;
+
+ EXPECT_TRUE(initConfig(config));
+
+ // Modify the predicate.
+ config.mutable_predicate(0)->mutable_simple_predicate()->set_count_nesting(true);
+
+ set<int64_t> replacedMatchers;
+ vector<UpdateStatus> conditionsToUpdate(1, UPDATE_UNKNOWN);
+ vector<bool> cycleTracker(1, false);
+ unordered_map<int64_t, int> newConditionTrackerMap;
+ newConditionTrackerMap[predicate.id()] = 0;
+ EXPECT_TRUE(determineConditionUpdateStatus(config, 0, oldConditionTrackerMap,
+ oldConditionTrackers, newConditionTrackerMap,
+ replacedMatchers, conditionsToUpdate, cycleTracker));
+ EXPECT_EQ(conditionsToUpdate[0], UPDATE_REPLACE);
+}
+
+TEST_F(ConfigUpdateTest, TestSimpleConditionDepsChange) {
+ StatsdConfig config;
+ AtomMatcher startMatcher = CreateScreenTurnedOnAtomMatcher();
+ int64_t startMatcherId = startMatcher.id();
+ *config.add_atom_matcher() = startMatcher;
+ AtomMatcher stopMatcher = CreateScreenTurnedOffAtomMatcher();
+ *config.add_atom_matcher() = stopMatcher;
+
+ Predicate predicate = CreateScreenIsOnPredicate();
+ *config.add_predicate() = predicate;
+
+ EXPECT_TRUE(initConfig(config));
+
+ // Start matcher was replaced.
+ set<int64_t> replacedMatchers;
+ replacedMatchers.insert(startMatcherId);
+
+ vector<UpdateStatus> conditionsToUpdate(1, UPDATE_UNKNOWN);
+ vector<bool> cycleTracker(1, false);
+ unordered_map<int64_t, int> newConditionTrackerMap;
+ newConditionTrackerMap[predicate.id()] = 0;
+ EXPECT_TRUE(determineConditionUpdateStatus(config, 0, oldConditionTrackerMap,
+ oldConditionTrackers, newConditionTrackerMap,
+ replacedMatchers, conditionsToUpdate, cycleTracker));
+ EXPECT_EQ(conditionsToUpdate[0], UPDATE_REPLACE);
+}
+
+TEST_F(ConfigUpdateTest, TestCombinationConditionPreserve) {
+ StatsdConfig config;
+ AtomMatcher screenOnMatcher = CreateScreenTurnedOnAtomMatcher();
+ *config.add_atom_matcher() = screenOnMatcher;
+ AtomMatcher screenOffMatcher = CreateScreenTurnedOffAtomMatcher();
+ *config.add_atom_matcher() = screenOffMatcher;
+
+ Predicate simple1 = CreateScreenIsOnPredicate();
+ *config.add_predicate() = simple1;
+ Predicate simple2 = CreateScreenIsOffPredicate();
+ *config.add_predicate() = simple2;
+
+ Predicate combination1;
+ combination1.set_id(StringToId("COMBINATION1"));
+ Predicate_Combination* combinationInternal = combination1.mutable_combination();
+ combinationInternal->set_operation(LogicalOperation::NAND);
+ combinationInternal->add_predicate(simple1.id());
+ combinationInternal->add_predicate(simple2.id());
+ *config.add_predicate() = combination1;
+
+ EXPECT_TRUE(initConfig(config));
+
+ // Same predicates, different order
+ StatsdConfig newConfig;
+ unordered_map<int64_t, int> newConditionTrackerMap;
+ *newConfig.add_predicate() = combination1;
+ newConditionTrackerMap[combination1.id()] = 0;
+ *newConfig.add_predicate() = simple2;
+ newConditionTrackerMap[simple2.id()] = 1;
+ *newConfig.add_predicate() = simple1;
+ newConditionTrackerMap[simple1.id()] = 2;
+
+ set<int64_t> replacedMatchers;
+ vector<UpdateStatus> conditionsToUpdate(3, UPDATE_UNKNOWN);
+ vector<bool> cycleTracker(3, false);
+ // Only update the combination. It should recurse the two child predicates and preserve all 3.
+ EXPECT_TRUE(determineConditionUpdateStatus(newConfig, 0, oldConditionTrackerMap,
+ oldConditionTrackers, newConditionTrackerMap,
+ replacedMatchers, conditionsToUpdate, cycleTracker));
+ EXPECT_EQ(conditionsToUpdate[0], UPDATE_PRESERVE);
+ EXPECT_EQ(conditionsToUpdate[1], UPDATE_PRESERVE);
+ EXPECT_EQ(conditionsToUpdate[2], UPDATE_PRESERVE);
}
+TEST_F(ConfigUpdateTest, TestCombinationConditionReplace) {
+ StatsdConfig config;
+ AtomMatcher screenOnMatcher = CreateScreenTurnedOnAtomMatcher();
+ *config.add_atom_matcher() = screenOnMatcher;
+ AtomMatcher screenOffMatcher = CreateScreenTurnedOffAtomMatcher();
+ *config.add_atom_matcher() = screenOffMatcher;
+
+ Predicate simple1 = CreateScreenIsOnPredicate();
+ *config.add_predicate() = simple1;
+ Predicate simple2 = CreateScreenIsOffPredicate();
+ *config.add_predicate() = simple2;
+
+ Predicate combination1;
+ combination1.set_id(StringToId("COMBINATION1"));
+ Predicate_Combination* combinationInternal = combination1.mutable_combination();
+ combinationInternal->set_operation(LogicalOperation::NAND);
+ combinationInternal->add_predicate(simple1.id());
+ combinationInternal->add_predicate(simple2.id());
+ *config.add_predicate() = combination1;
+
+ EXPECT_TRUE(initConfig(config));
+
+ // Changing the logical operation changes the predicate definition, so it should be replaced.
+ combination1.mutable_combination()->set_operation(LogicalOperation::OR);
+
+ StatsdConfig newConfig;
+ unordered_map<int64_t, int> newConditionTrackerMap;
+ *newConfig.add_predicate() = combination1;
+ newConditionTrackerMap[combination1.id()] = 0;
+ *newConfig.add_predicate() = simple2;
+ newConditionTrackerMap[simple2.id()] = 1;
+ *newConfig.add_predicate() = simple1;
+ newConditionTrackerMap[simple1.id()] = 2;
+
+ set<int64_t> replacedMatchers;
+ vector<UpdateStatus> conditionsToUpdate(3, UPDATE_UNKNOWN);
+ vector<bool> cycleTracker(3, false);
+ // Only update the combination. The simple conditions should not be evaluated.
+ EXPECT_TRUE(determineConditionUpdateStatus(newConfig, 0, oldConditionTrackerMap,
+ oldConditionTrackers, newConditionTrackerMap,
+ replacedMatchers, conditionsToUpdate, cycleTracker));
+ EXPECT_EQ(conditionsToUpdate[0], UPDATE_REPLACE);
+ EXPECT_EQ(conditionsToUpdate[1], UPDATE_UNKNOWN);
+ EXPECT_EQ(conditionsToUpdate[2], UPDATE_UNKNOWN);
+}
+
+TEST_F(ConfigUpdateTest, TestCombinationConditionDepsChange) {
+ StatsdConfig config;
+ AtomMatcher screenOnMatcher = CreateScreenTurnedOnAtomMatcher();
+ *config.add_atom_matcher() = screenOnMatcher;
+ AtomMatcher screenOffMatcher = CreateScreenTurnedOffAtomMatcher();
+ *config.add_atom_matcher() = screenOffMatcher;
+
+ Predicate simple1 = CreateScreenIsOnPredicate();
+ *config.add_predicate() = simple1;
+ Predicate simple2 = CreateScreenIsOffPredicate();
+ *config.add_predicate() = simple2;
+
+ Predicate combination1;
+ combination1.set_id(StringToId("COMBINATION1"));
+ Predicate_Combination* combinationInternal = combination1.mutable_combination();
+ combinationInternal->set_operation(LogicalOperation::NAND);
+ combinationInternal->add_predicate(simple1.id());
+ combinationInternal->add_predicate(simple2.id());
+ *config.add_predicate() = combination1;
+
+ EXPECT_TRUE(initConfig(config));
+
+ simple2.mutable_simple_predicate()->set_count_nesting(false);
+
+ StatsdConfig newConfig;
+ unordered_map<int64_t, int> newConditionTrackerMap;
+ *newConfig.add_predicate() = combination1;
+ newConditionTrackerMap[combination1.id()] = 0;
+ *newConfig.add_predicate() = simple2;
+ newConditionTrackerMap[simple2.id()] = 1;
+ *newConfig.add_predicate() = simple1;
+ newConditionTrackerMap[simple1.id()] = 2;
+
+ set<int64_t> replacedMatchers;
+ vector<UpdateStatus> conditionsToUpdate(3, UPDATE_UNKNOWN);
+ vector<bool> cycleTracker(3, false);
+ // Only update the combination. Simple2 and combination1 must be evaluated.
+ EXPECT_TRUE(determineConditionUpdateStatus(newConfig, 0, oldConditionTrackerMap,
+ oldConditionTrackers, newConditionTrackerMap,
+ replacedMatchers, conditionsToUpdate, cycleTracker));
+ EXPECT_EQ(conditionsToUpdate[0], UPDATE_REPLACE);
+ EXPECT_EQ(conditionsToUpdate[1], UPDATE_REPLACE);
+}
+
+TEST_F(ConfigUpdateTest, TestUpdateConditions) {
+ StatsdConfig config;
+
+ // Add atom matchers. These are mostly needed for initStatsdConfig
+ AtomMatcher matcher1 = CreateScreenTurnedOnAtomMatcher();
+ int64_t matcher1Id = matcher1.id();
+ *config.add_atom_matcher() = matcher1;
+
+ AtomMatcher matcher2 = CreateScreenTurnedOffAtomMatcher();
+ int64_t matcher2Id = matcher2.id();
+ *config.add_atom_matcher() = matcher2;
+
+ AtomMatcher matcher3 = CreateStartScheduledJobAtomMatcher();
+ int64_t matcher3Id = matcher3.id();
+ *config.add_atom_matcher() = matcher3;
+
+ AtomMatcher matcher4 = CreateFinishScheduledJobAtomMatcher();
+ int64_t matcher4Id = matcher4.id();
+ *config.add_atom_matcher() = matcher4;
+
+ AtomMatcher matcher5 = CreateBatterySaverModeStartAtomMatcher();
+ int64_t matcher5Id = matcher5.id();
+ *config.add_atom_matcher() = matcher5;
+
+ AtomMatcher matcher6 = CreateBatterySaverModeStopAtomMatcher();
+ int64_t matcher6Id = matcher6.id();
+ *config.add_atom_matcher() = matcher6;
+
+ // Add the predicates.
+ // Will be preserved.
+ Predicate simple1 = CreateScreenIsOnPredicate();
+ int64_t simple1Id = simple1.id();
+ *config.add_predicate() = simple1;
+
+ // Will be preserved.
+ Predicate simple2 = CreateScheduledJobPredicate();
+ int64_t simple2Id = simple2.id();
+ *config.add_predicate() = simple2;
+
+ // Will be replaced.
+ Predicate simple3 = CreateBatterySaverModePredicate();
+ int64_t simple3Id = simple3.id();
+ *config.add_predicate() = simple3;
+
+ // Will be preserved
+ Predicate combination1;
+ combination1.set_id(StringToId("COMBINATION1"));
+ combination1.mutable_combination()->set_operation(LogicalOperation::AND);
+ combination1.mutable_combination()->add_predicate(simple1Id);
+ combination1.mutable_combination()->add_predicate(simple2Id);
+ int64_t combination1Id = combination1.id();
+ *config.add_predicate() = combination1;
+
+ // Will be replaced since simple3 will be replaced.
+ Predicate combination2;
+ combination2.set_id(StringToId("COMBINATION2"));
+ combination2.mutable_combination()->set_operation(LogicalOperation::OR);
+ combination2.mutable_combination()->add_predicate(simple1Id);
+ combination2.mutable_combination()->add_predicate(simple3Id);
+ int64_t combination2Id = combination2.id();
+ *config.add_predicate() = combination2;
+
+ // Will be removed.
+ Predicate combination3;
+ combination3.set_id(StringToId("COMBINATION3"));
+ combination3.mutable_combination()->set_operation(LogicalOperation::NOT);
+ combination3.mutable_combination()->add_predicate(simple2Id);
+ int64_t combination3Id = combination3.id();
+ *config.add_predicate() = combination3;
+
+ EXPECT_TRUE(initConfig(config));
+
+ // Mark marcher 5 as replaced. Causes simple3, and therefore combination2 to be replaced.
+ set<int64_t> replacedMatchers;
+ replacedMatchers.insert(matcher6Id);
+
+ // Change the condition of simple1 to true.
+ ASSERT_EQ(oldConditionTrackers[0]->getConditionId(), simple1Id);
+ LogEvent event(/*uid=*/0, /*pid=*/0); // Empty event is fine since there are no dimensions.
+ // Mark the stop matcher as matched, condition should be false.
+ vector<MatchingState> eventMatcherValues(6, MatchingState::kNotMatched);
+ eventMatcherValues[1] = MatchingState::kMatched;
+ vector<ConditionState> tmpConditionCache(6, ConditionState::kNotEvaluated);
+ vector<bool> conditionChangeCache(6, false);
+ oldConditionTrackers[0]->evaluateCondition(event, eventMatcherValues, oldConditionTrackers,
+ tmpConditionCache, conditionChangeCache);
+ EXPECT_EQ(tmpConditionCache[0], ConditionState::kFalse);
+ EXPECT_EQ(conditionChangeCache[0], true);
+
+ // New combination matcher. Should have an initial condition of true since it is NOT(simple1).
+ Predicate combination4;
+ combination4.set_id(StringToId("COMBINATION4"));
+ combination4.mutable_combination()->set_operation(LogicalOperation::NOT);
+ combination4.mutable_combination()->add_predicate(simple1Id);
+ int64_t combination4Id = combination4.id();
+ *config.add_predicate() = combination4;
+
+ // Map the matchers in reverse order to force the indices to change.
+ std::unordered_map<int64_t, int> newAtomMatchingTrackerMap;
+ const int matcher6Index = 0;
+ newAtomMatchingTrackerMap[matcher6Id] = 0;
+ const int matcher5Index = 1;
+ newAtomMatchingTrackerMap[matcher5Id] = 1;
+ const int matcher4Index = 2;
+ newAtomMatchingTrackerMap[matcher4Id] = 2;
+ const int matcher3Index = 3;
+ newAtomMatchingTrackerMap[matcher3Id] = 3;
+ const int matcher2Index = 4;
+ newAtomMatchingTrackerMap[matcher2Id] = 4;
+ const int matcher1Index = 5;
+ newAtomMatchingTrackerMap[matcher1Id] = 5;
+
+ StatsdConfig newConfig;
+ *newConfig.add_predicate() = simple3;
+ const int simple3Index = 0;
+ *newConfig.add_predicate() = combination2;
+ const int combination2Index = 1;
+ *newConfig.add_predicate() = combination4;
+ const int combination4Index = 2;
+ *newConfig.add_predicate() = simple2;
+ const int simple2Index = 3;
+ *newConfig.add_predicate() = combination1;
+ const int combination1Index = 4;
+ *newConfig.add_predicate() = simple1;
+ const int simple1Index = 5;
+
+ unordered_map<int64_t, int> newConditionTrackerMap;
+ vector<sp<ConditionTracker>> newConditionTrackers;
+ unordered_map<int, vector<int>> trackerToConditionMap;
+ std::vector<ConditionState> conditionCache;
+ std::set<int64_t> replacedConditions;
+ EXPECT_TRUE(updateConditions(key, newConfig, newAtomMatchingTrackerMap, replacedMatchers,
+ oldConditionTrackerMap, oldConditionTrackers,
+ newConditionTrackerMap, newConditionTrackers,
+ trackerToConditionMap, conditionCache, replacedConditions));
+
+ unordered_map<int64_t, int> expectedConditionTrackerMap = {
+ {simple1Id, simple1Index}, {simple2Id, simple2Index},
+ {simple3Id, simple3Index}, {combination1Id, combination1Index},
+ {combination2Id, combination2Index}, {combination4Id, combination4Index},
+ };
+ EXPECT_THAT(newConditionTrackerMap, ContainerEq(expectedConditionTrackerMap));
+
+ ASSERT_EQ(newConditionTrackers.size(), 6);
+ // Make sure all conditions are initialized:
+ for (const sp<ConditionTracker>& tracker : newConditionTrackers) {
+ EXPECT_TRUE(tracker->mInitialized);
+ }
+
+ // Make sure preserved conditions are the same.
+ EXPECT_EQ(oldConditionTrackers[oldConditionTrackerMap.at(simple1Id)],
+ newConditionTrackers[newConditionTrackerMap.at(simple1Id)]);
+ EXPECT_EQ(oldConditionTrackers[oldConditionTrackerMap.at(simple2Id)],
+ newConditionTrackers[newConditionTrackerMap.at(simple2Id)]);
+ EXPECT_EQ(oldConditionTrackers[oldConditionTrackerMap.at(combination1Id)],
+ newConditionTrackers[newConditionTrackerMap.at(combination1Id)]);
+
+ // Make sure replaced conditions are different and included in replacedConditions.
+ EXPECT_NE(oldConditionTrackers[oldConditionTrackerMap.at(simple3Id)],
+ newConditionTrackers[newConditionTrackerMap.at(simple3Id)]);
+ EXPECT_NE(oldConditionTrackers[oldConditionTrackerMap.at(combination2Id)],
+ newConditionTrackers[newConditionTrackerMap.at(combination2Id)]);
+ EXPECT_THAT(replacedConditions, ContainerEq(set({simple3Id, combination2Id})));
+
+ // Verify the trackerToConditionMap
+ ASSERT_EQ(trackerToConditionMap.size(), 6);
+ const vector<int>& matcher1Conditions = trackerToConditionMap[matcher1Index];
+ EXPECT_THAT(matcher1Conditions, UnorderedElementsAre(simple1Index, combination1Index,
+ combination2Index, combination4Index));
+ const vector<int>& matcher2Conditions = trackerToConditionMap[matcher2Index];
+ EXPECT_THAT(matcher2Conditions, UnorderedElementsAre(simple1Index, combination1Index,
+ combination2Index, combination4Index));
+ const vector<int>& matcher3Conditions = trackerToConditionMap[matcher3Index];
+ EXPECT_THAT(matcher3Conditions, UnorderedElementsAre(simple2Index, combination1Index));
+ const vector<int>& matcher4Conditions = trackerToConditionMap[matcher4Index];
+ EXPECT_THAT(matcher4Conditions, UnorderedElementsAre(simple2Index, combination1Index));
+ const vector<int>& matcher5Conditions = trackerToConditionMap[matcher5Index];
+ EXPECT_THAT(matcher5Conditions, UnorderedElementsAre(simple3Index, combination2Index));
+ const vector<int>& matcher6Conditions = trackerToConditionMap[matcher6Index];
+ EXPECT_THAT(matcher6Conditions, UnorderedElementsAre(simple3Index, combination2Index));
+
+ // Verify the conditionCache. Specifically, simple1 is false and combination4 is true.
+ ASSERT_EQ(conditionCache.size(), 6);
+ EXPECT_EQ(conditionCache[simple1Index], ConditionState::kFalse);
+ EXPECT_EQ(conditionCache[simple2Index], ConditionState::kUnknown);
+ EXPECT_EQ(conditionCache[simple3Index], ConditionState::kUnknown);
+ EXPECT_EQ(conditionCache[combination1Index], ConditionState::kUnknown);
+ EXPECT_EQ(conditionCache[combination2Index], ConditionState::kUnknown);
+ EXPECT_EQ(conditionCache[combination4Index], ConditionState::kTrue);
+
+ // Verify tracker indices/ids are correct.
+ EXPECT_EQ(newConditionTrackers[simple1Index]->getConditionId(), simple1Id);
+ EXPECT_EQ(newConditionTrackers[simple1Index]->mIndex, simple1Index);
+ EXPECT_TRUE(newConditionTrackers[simple1Index]->IsSimpleCondition());
+ EXPECT_EQ(newConditionTrackers[simple2Index]->getConditionId(), simple2Id);
+ EXPECT_EQ(newConditionTrackers[simple2Index]->mIndex, simple2Index);
+ EXPECT_TRUE(newConditionTrackers[simple2Index]->IsSimpleCondition());
+ EXPECT_EQ(newConditionTrackers[simple3Index]->getConditionId(), simple3Id);
+ EXPECT_EQ(newConditionTrackers[simple3Index]->mIndex, simple3Index);
+ EXPECT_TRUE(newConditionTrackers[simple3Index]->IsSimpleCondition());
+ EXPECT_EQ(newConditionTrackers[combination1Index]->getConditionId(), combination1Id);
+ EXPECT_EQ(newConditionTrackers[combination1Index]->mIndex, combination1Index);
+ EXPECT_FALSE(newConditionTrackers[combination1Index]->IsSimpleCondition());
+ EXPECT_EQ(newConditionTrackers[combination2Index]->getConditionId(), combination2Id);
+ EXPECT_EQ(newConditionTrackers[combination2Index]->mIndex, combination2Index);
+ EXPECT_FALSE(newConditionTrackers[combination2Index]->IsSimpleCondition());
+ EXPECT_EQ(newConditionTrackers[combination4Index]->getConditionId(), combination4Id);
+ EXPECT_EQ(newConditionTrackers[combination4Index]->mIndex, combination4Index);
+ EXPECT_FALSE(newConditionTrackers[combination4Index]->IsSimpleCondition());
+
+ // Verify preserved trackers have indices updated.
+ SimpleConditionTracker* simpleTracker1 =
+ static_cast<SimpleConditionTracker*>(newConditionTrackers[simple1Index].get());
+ EXPECT_EQ(simpleTracker1->mStartLogMatcherIndex, matcher1Index);
+ EXPECT_EQ(simpleTracker1->mStopLogMatcherIndex, matcher2Index);
+ EXPECT_EQ(simpleTracker1->mStopAllLogMatcherIndex, -1);
+
+ SimpleConditionTracker* simpleTracker2 =
+ static_cast<SimpleConditionTracker*>(newConditionTrackers[simple2Index].get());
+ EXPECT_EQ(simpleTracker2->mStartLogMatcherIndex, matcher3Index);
+ EXPECT_EQ(simpleTracker2->mStopLogMatcherIndex, matcher4Index);
+ EXPECT_EQ(simpleTracker2->mStopAllLogMatcherIndex, -1);
+
+ CombinationConditionTracker* combinationTracker1 = static_cast<CombinationConditionTracker*>(
+ newConditionTrackers[combination1Index].get());
+ EXPECT_THAT(combinationTracker1->mChildren, UnorderedElementsAre(simple1Index, simple2Index));
+ EXPECT_THAT(combinationTracker1->mUnSlicedChildren,
+ UnorderedElementsAre(simple1Index, simple2Index));
+ EXPECT_THAT(combinationTracker1->mSlicedChildren, IsEmpty());
+}
} // namespace statsd
} // namespace os
} // namespace android
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 d6db4c12ae4d..0d0a8960043e 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
@@ -14,6 +14,7 @@
#include "src/metrics/parsing_utils/metrics_manager_util.h"
+#include <gmock/gmock.h>
#include <gtest/gtest.h>
#include <private/android_filesystem_config.h>
#include <stdio.h>
@@ -384,9 +385,11 @@ TEST(MetricsManagerTest, TestInitialConditions) {
StatsdConfig config = buildConfigWithDifferentPredicates();
set<int> allTagIds;
vector<sp<AtomMatchingTracker>> allAtomMatchingTrackers;
- unordered_map<int64_t, int> logTrackerMap;
+ unordered_map<int64_t, int> atomMatchingTrackerMap;
vector<sp<ConditionTracker>> allConditionTrackers;
+ unordered_map<int64_t, int> conditionTrackerMap;
vector<sp<MetricProducer>> allMetricProducers;
+ unordered_map<int64_t, int> metricProducerMap;
std::vector<sp<AnomalyTracker>> allAnomalyTrackers;
std::vector<sp<AlarmTracker>> allAlarmTrackers;
unordered_map<int, std::vector<int>> conditionToMetricMap;
@@ -396,15 +399,17 @@ TEST(MetricsManagerTest, TestInitialConditions) {
unordered_map<int, std::vector<int>> deactivationAtomTrackerToMetricMap;
unordered_map<int64_t, int> alertTrackerMap;
vector<int> metricsWithActivation;
+ map<int64_t, uint64_t> stateProtoHashes;
std::set<int64_t> noReportMetricIds;
EXPECT_TRUE(initStatsdConfig(
kConfigKey, config, uidMap, pullerManager, anomalyAlarmMonitor, periodicAlarmMonitor,
- timeBaseSec, timeBaseSec, allTagIds, allAtomMatchingTrackers, logTrackerMap,
- allConditionTrackers, allMetricProducers, allAnomalyTrackers, allAlarmTrackers,
- conditionToMetricMap, trackerToMetricMap, trackerToConditionMap,
- activationAtomTrackerToMetricMap, deactivationAtomTrackerToMetricMap, alertTrackerMap,
- metricsWithActivation, noReportMetricIds));
+ timeBaseSec, timeBaseSec, allTagIds, allAtomMatchingTrackers, atomMatchingTrackerMap,
+ allConditionTrackers, conditionTrackerMap, allMetricProducers, metricProducerMap,
+ allAnomalyTrackers, allAlarmTrackers, conditionToMetricMap, trackerToMetricMap,
+ trackerToConditionMap, activationAtomTrackerToMetricMap,
+ deactivationAtomTrackerToMetricMap, alertTrackerMap, metricsWithActivation,
+ stateProtoHashes, noReportMetricIds));
ASSERT_EQ(4u, allMetricProducers.size());
ASSERT_EQ(5u, allConditionTrackers.size());
@@ -433,9 +438,11 @@ TEST(MetricsManagerTest, TestGoodConfig) {
StatsdConfig config = buildGoodConfig();
set<int> allTagIds;
vector<sp<AtomMatchingTracker>> allAtomMatchingTrackers;
- unordered_map<int64_t, int> logTrackerMap;
+ unordered_map<int64_t, int> atomMatchingTrackerMap;
vector<sp<ConditionTracker>> allConditionTrackers;
+ unordered_map<int64_t, int> conditionTrackerMap;
vector<sp<MetricProducer>> allMetricProducers;
+ unordered_map<int64_t, int> metricProducerMap;
std::vector<sp<AnomalyTracker>> allAnomalyTrackers;
std::vector<sp<AlarmTracker>> allAlarmTrackers;
unordered_map<int, std::vector<int>> conditionToMetricMap;
@@ -445,16 +452,19 @@ TEST(MetricsManagerTest, TestGoodConfig) {
unordered_map<int, std::vector<int>> deactivationAtomTrackerToMetricMap;
unordered_map<int64_t, int> alertTrackerMap;
vector<int> metricsWithActivation;
+ map<int64_t, uint64_t> stateProtoHashes;
std::set<int64_t> noReportMetricIds;
EXPECT_TRUE(initStatsdConfig(
kConfigKey, config, uidMap, pullerManager, anomalyAlarmMonitor, periodicAlarmMonitor,
- timeBaseSec, timeBaseSec, allTagIds, allAtomMatchingTrackers, logTrackerMap,
- allConditionTrackers, allMetricProducers, allAnomalyTrackers, allAlarmTrackers,
- conditionToMetricMap, trackerToMetricMap, trackerToConditionMap,
- activationAtomTrackerToMetricMap, deactivationAtomTrackerToMetricMap, alertTrackerMap,
- metricsWithActivation, noReportMetricIds));
+ timeBaseSec, timeBaseSec, allTagIds, allAtomMatchingTrackers, atomMatchingTrackerMap,
+ allConditionTrackers, conditionTrackerMap, allMetricProducers, metricProducerMap,
+ allAnomalyTrackers, allAlarmTrackers, conditionToMetricMap, trackerToMetricMap,
+ trackerToConditionMap, activationAtomTrackerToMetricMap,
+ deactivationAtomTrackerToMetricMap, alertTrackerMap, metricsWithActivation,
+ stateProtoHashes, noReportMetricIds));
ASSERT_EQ(1u, allMetricProducers.size());
+ EXPECT_THAT(metricProducerMap, UnorderedElementsAre(Pair(config.count_metric(0).id(), 0)));
ASSERT_EQ(1u, allAnomalyTrackers.size());
ASSERT_EQ(1u, noReportMetricIds.size());
ASSERT_EQ(1u, alertTrackerMap.size());
@@ -470,9 +480,11 @@ TEST(MetricsManagerTest, TestDimensionMetricsWithMultiTags) {
StatsdConfig config = buildDimensionMetricsWithMultiTags();
set<int> allTagIds;
vector<sp<AtomMatchingTracker>> allAtomMatchingTrackers;
- unordered_map<int64_t, int> logTrackerMap;
+ unordered_map<int64_t, int> atomMatchingTrackerMap;
vector<sp<ConditionTracker>> allConditionTrackers;
+ unordered_map<int64_t, int> conditionTrackerMap;
vector<sp<MetricProducer>> allMetricProducers;
+ unordered_map<int64_t, int> metricProducerMap;
std::vector<sp<AnomalyTracker>> allAnomalyTrackers;
std::vector<sp<AlarmTracker>> allAlarmTrackers;
unordered_map<int, std::vector<int>> conditionToMetricMap;
@@ -482,15 +494,17 @@ TEST(MetricsManagerTest, TestDimensionMetricsWithMultiTags) {
unordered_map<int, std::vector<int>> deactivationAtomTrackerToMetricMap;
unordered_map<int64_t, int> alertTrackerMap;
vector<int> metricsWithActivation;
+ map<int64_t, uint64_t> stateProtoHashes;
std::set<int64_t> noReportMetricIds;
EXPECT_FALSE(initStatsdConfig(
kConfigKey, config, uidMap, pullerManager, anomalyAlarmMonitor, periodicAlarmMonitor,
- timeBaseSec, timeBaseSec, allTagIds, allAtomMatchingTrackers, logTrackerMap,
- allConditionTrackers, allMetricProducers, allAnomalyTrackers, allAlarmTrackers,
- conditionToMetricMap, trackerToMetricMap, trackerToConditionMap,
- activationAtomTrackerToMetricMap, deactivationAtomTrackerToMetricMap, alertTrackerMap,
- metricsWithActivation, noReportMetricIds));
+ timeBaseSec, timeBaseSec, allTagIds, allAtomMatchingTrackers, atomMatchingTrackerMap,
+ allConditionTrackers, conditionTrackerMap, allMetricProducers, metricProducerMap,
+ allAnomalyTrackers, allAlarmTrackers, conditionToMetricMap, trackerToMetricMap,
+ trackerToConditionMap, activationAtomTrackerToMetricMap,
+ deactivationAtomTrackerToMetricMap, alertTrackerMap, metricsWithActivation,
+ stateProtoHashes, noReportMetricIds));
}
TEST(MetricsManagerTest, TestCircleLogMatcherDependency) {
@@ -501,9 +515,11 @@ TEST(MetricsManagerTest, TestCircleLogMatcherDependency) {
StatsdConfig config = buildCircleMatchers();
set<int> allTagIds;
vector<sp<AtomMatchingTracker>> allAtomMatchingTrackers;
- unordered_map<int64_t, int> logTrackerMap;
+ unordered_map<int64_t, int> atomMatchingTrackerMap;
vector<sp<ConditionTracker>> allConditionTrackers;
+ unordered_map<int64_t, int> conditionTrackerMap;
vector<sp<MetricProducer>> allMetricProducers;
+ unordered_map<int64_t, int> metricProducerMap;
std::vector<sp<AnomalyTracker>> allAnomalyTrackers;
std::vector<sp<AlarmTracker>> allAlarmTrackers;
unordered_map<int, std::vector<int>> conditionToMetricMap;
@@ -513,15 +529,17 @@ TEST(MetricsManagerTest, TestCircleLogMatcherDependency) {
unordered_map<int, std::vector<int>> deactivationAtomTrackerToMetricMap;
unordered_map<int64_t, int> alertTrackerMap;
vector<int> metricsWithActivation;
+ map<int64_t, uint64_t> stateProtoHashes;
std::set<int64_t> noReportMetricIds;
EXPECT_FALSE(initStatsdConfig(
kConfigKey, config, uidMap, pullerManager, anomalyAlarmMonitor, periodicAlarmMonitor,
- timeBaseSec, timeBaseSec, allTagIds, allAtomMatchingTrackers, logTrackerMap,
- allConditionTrackers, allMetricProducers, allAnomalyTrackers, allAlarmTrackers,
- conditionToMetricMap, trackerToMetricMap, trackerToConditionMap,
- activationAtomTrackerToMetricMap, deactivationAtomTrackerToMetricMap, alertTrackerMap,
- metricsWithActivation, noReportMetricIds));
+ timeBaseSec, timeBaseSec, allTagIds, allAtomMatchingTrackers, atomMatchingTrackerMap,
+ allConditionTrackers, conditionTrackerMap, allMetricProducers, metricProducerMap,
+ allAnomalyTrackers, allAlarmTrackers, conditionToMetricMap, trackerToMetricMap,
+ trackerToConditionMap, activationAtomTrackerToMetricMap,
+ deactivationAtomTrackerToMetricMap, alertTrackerMap, metricsWithActivation,
+ stateProtoHashes, noReportMetricIds));
}
TEST(MetricsManagerTest, TestMissingMatchers) {
@@ -532,9 +550,11 @@ TEST(MetricsManagerTest, TestMissingMatchers) {
StatsdConfig config = buildMissingMatchers();
set<int> allTagIds;
vector<sp<AtomMatchingTracker>> allAtomMatchingTrackers;
- unordered_map<int64_t, int> logTrackerMap;
+ unordered_map<int64_t, int> atomMatchingTrackerMap;
vector<sp<ConditionTracker>> allConditionTrackers;
+ unordered_map<int64_t, int> conditionTrackerMap;
vector<sp<MetricProducer>> allMetricProducers;
+ unordered_map<int64_t, int> metricProducerMap;
std::vector<sp<AnomalyTracker>> allAnomalyTrackers;
std::vector<sp<AlarmTracker>> allAlarmTrackers;
unordered_map<int, std::vector<int>> conditionToMetricMap;
@@ -544,14 +564,16 @@ TEST(MetricsManagerTest, TestMissingMatchers) {
unordered_map<int, std::vector<int>> deactivationAtomTrackerToMetricMap;
unordered_map<int64_t, int> alertTrackerMap;
vector<int> metricsWithActivation;
+ map<int64_t, uint64_t> stateProtoHashes;
std::set<int64_t> noReportMetricIds;
EXPECT_FALSE(initStatsdConfig(
kConfigKey, config, uidMap, pullerManager, anomalyAlarmMonitor, periodicAlarmMonitor,
- timeBaseSec, timeBaseSec, allTagIds, allAtomMatchingTrackers, logTrackerMap,
- allConditionTrackers, allMetricProducers, allAnomalyTrackers, allAlarmTrackers,
- conditionToMetricMap, trackerToMetricMap, trackerToConditionMap,
- activationAtomTrackerToMetricMap, deactivationAtomTrackerToMetricMap, alertTrackerMap,
- metricsWithActivation, noReportMetricIds));
+ timeBaseSec, timeBaseSec, allTagIds, allAtomMatchingTrackers, atomMatchingTrackerMap,
+ allConditionTrackers, conditionTrackerMap, allMetricProducers, metricProducerMap,
+ allAnomalyTrackers, allAlarmTrackers, conditionToMetricMap, trackerToMetricMap,
+ trackerToConditionMap, activationAtomTrackerToMetricMap,
+ deactivationAtomTrackerToMetricMap, alertTrackerMap, metricsWithActivation,
+ stateProtoHashes, noReportMetricIds));
}
TEST(MetricsManagerTest, TestMissingPredicate) {
@@ -562,9 +584,11 @@ TEST(MetricsManagerTest, TestMissingPredicate) {
StatsdConfig config = buildMissingPredicate();
set<int> allTagIds;
vector<sp<AtomMatchingTracker>> allAtomMatchingTrackers;
- unordered_map<int64_t, int> logTrackerMap;
+ unordered_map<int64_t, int> atomMatchingTrackerMap;
vector<sp<ConditionTracker>> allConditionTrackers;
+ unordered_map<int64_t, int> conditionTrackerMap;
vector<sp<MetricProducer>> allMetricProducers;
+ unordered_map<int64_t, int> metricProducerMap;
std::vector<sp<AnomalyTracker>> allAnomalyTrackers;
std::vector<sp<AlarmTracker>> allAlarmTrackers;
unordered_map<int, std::vector<int>> conditionToMetricMap;
@@ -574,14 +598,16 @@ TEST(MetricsManagerTest, TestMissingPredicate) {
unordered_map<int, std::vector<int>> deactivationAtomTrackerToMetricMap;
unordered_map<int64_t, int> alertTrackerMap;
vector<int> metricsWithActivation;
+ map<int64_t, uint64_t> stateProtoHashes;
std::set<int64_t> noReportMetricIds;
EXPECT_FALSE(initStatsdConfig(
kConfigKey, config, uidMap, pullerManager, anomalyAlarmMonitor, periodicAlarmMonitor,
- timeBaseSec, timeBaseSec, allTagIds, allAtomMatchingTrackers, logTrackerMap,
- allConditionTrackers, allMetricProducers, allAnomalyTrackers, allAlarmTrackers,
- conditionToMetricMap, trackerToMetricMap, trackerToConditionMap,
- activationAtomTrackerToMetricMap, deactivationAtomTrackerToMetricMap, alertTrackerMap,
- metricsWithActivation, noReportMetricIds));
+ timeBaseSec, timeBaseSec, allTagIds, allAtomMatchingTrackers, atomMatchingTrackerMap,
+ allConditionTrackers, conditionTrackerMap, allMetricProducers, metricProducerMap,
+ allAnomalyTrackers, allAlarmTrackers, conditionToMetricMap, trackerToMetricMap,
+ trackerToConditionMap, activationAtomTrackerToMetricMap,
+ deactivationAtomTrackerToMetricMap, alertTrackerMap, metricsWithActivation,
+ stateProtoHashes, noReportMetricIds));
}
TEST(MetricsManagerTest, TestCirclePredicateDependency) {
@@ -592,9 +618,11 @@ TEST(MetricsManagerTest, TestCirclePredicateDependency) {
StatsdConfig config = buildCirclePredicates();
set<int> allTagIds;
vector<sp<AtomMatchingTracker>> allAtomMatchingTrackers;
- unordered_map<int64_t, int> logTrackerMap;
+ unordered_map<int64_t, int> atomMatchingTrackerMap;
vector<sp<ConditionTracker>> allConditionTrackers;
+ unordered_map<int64_t, int> conditionTrackerMap;
vector<sp<MetricProducer>> allMetricProducers;
+ unordered_map<int64_t, int> metricProducerMap;
std::vector<sp<AnomalyTracker>> allAnomalyTrackers;
std::vector<sp<AlarmTracker>> allAlarmTrackers;
unordered_map<int, std::vector<int>> conditionToMetricMap;
@@ -604,15 +632,17 @@ TEST(MetricsManagerTest, TestCirclePredicateDependency) {
unordered_map<int, std::vector<int>> deactivationAtomTrackerToMetricMap;
unordered_map<int64_t, int> alertTrackerMap;
vector<int> metricsWithActivation;
+ map<int64_t, uint64_t> stateProtoHashes;
std::set<int64_t> noReportMetricIds;
EXPECT_FALSE(initStatsdConfig(
kConfigKey, config, uidMap, pullerManager, anomalyAlarmMonitor, periodicAlarmMonitor,
- timeBaseSec, timeBaseSec, allTagIds, allAtomMatchingTrackers, logTrackerMap,
- allConditionTrackers, allMetricProducers, allAnomalyTrackers, allAlarmTrackers,
- conditionToMetricMap, trackerToMetricMap, trackerToConditionMap,
- activationAtomTrackerToMetricMap, deactivationAtomTrackerToMetricMap, alertTrackerMap,
- metricsWithActivation, noReportMetricIds));
+ timeBaseSec, timeBaseSec, allTagIds, allAtomMatchingTrackers, atomMatchingTrackerMap,
+ allConditionTrackers, conditionTrackerMap, allMetricProducers, metricProducerMap,
+ allAnomalyTrackers, allAlarmTrackers, conditionToMetricMap, trackerToMetricMap,
+ trackerToConditionMap, activationAtomTrackerToMetricMap,
+ deactivationAtomTrackerToMetricMap, alertTrackerMap, metricsWithActivation,
+ stateProtoHashes, noReportMetricIds));
}
TEST(MetricsManagerTest, testAlertWithUnknownMetric) {
@@ -623,9 +653,11 @@ TEST(MetricsManagerTest, testAlertWithUnknownMetric) {
StatsdConfig config = buildAlertWithUnknownMetric();
set<int> allTagIds;
vector<sp<AtomMatchingTracker>> allAtomMatchingTrackers;
- unordered_map<int64_t, int> logTrackerMap;
+ unordered_map<int64_t, int> atomMatchingTrackerMap;
vector<sp<ConditionTracker>> allConditionTrackers;
+ unordered_map<int64_t, int> conditionTrackerMap;
vector<sp<MetricProducer>> allMetricProducers;
+ unordered_map<int64_t, int> metricProducerMap;
std::vector<sp<AnomalyTracker>> allAnomalyTrackers;
std::vector<sp<AlarmTracker>> allAlarmTrackers;
unordered_map<int, std::vector<int>> conditionToMetricMap;
@@ -635,20 +667,23 @@ TEST(MetricsManagerTest, testAlertWithUnknownMetric) {
unordered_map<int, std::vector<int>> deactivationAtomTrackerToMetricMap;
unordered_map<int64_t, int> alertTrackerMap;
vector<int> metricsWithActivation;
+ map<int64_t, uint64_t> stateProtoHashes;
std::set<int64_t> noReportMetricIds;
EXPECT_FALSE(initStatsdConfig(
kConfigKey, config, uidMap, pullerManager, anomalyAlarmMonitor, periodicAlarmMonitor,
- timeBaseSec, timeBaseSec, allTagIds, allAtomMatchingTrackers, logTrackerMap,
- allConditionTrackers, allMetricProducers, allAnomalyTrackers, allAlarmTrackers,
- conditionToMetricMap, trackerToMetricMap, trackerToConditionMap,
- activationAtomTrackerToMetricMap, deactivationAtomTrackerToMetricMap, alertTrackerMap,
- metricsWithActivation, noReportMetricIds));
+ timeBaseSec, timeBaseSec, allTagIds, allAtomMatchingTrackers, atomMatchingTrackerMap,
+ allConditionTrackers, conditionTrackerMap, allMetricProducers, metricProducerMap,
+ allAnomalyTrackers, allAlarmTrackers, conditionToMetricMap, trackerToMetricMap,
+ trackerToConditionMap, activationAtomTrackerToMetricMap,
+ deactivationAtomTrackerToMetricMap, alertTrackerMap, metricsWithActivation,
+ stateProtoHashes, noReportMetricIds));
}
TEST(MetricsManagerTest, TestCreateAtomMatchingTrackerInvalidMatcher) {
sp<UidMap> uidMap = new UidMap();
AtomMatcher matcher;
+ // Matcher has no contents_case (simple/combination), so it is invalid.
matcher.set_id(21);
EXPECT_EQ(createAtomMatchingTracker(matcher, 0, uidMap), nullptr);
}
@@ -699,6 +734,65 @@ TEST(MetricsManagerTest, TestCreateAtomMatchingTrackerCombination) {
ASSERT_EQ(atomIds.size(), 0);
}
+TEST(MetricsManagerTest, TestCreateConditionTrackerInvalid) {
+ const ConfigKey key(123, 456);
+ // Predicate has no contents_case (simple/combination), so it is invalid.
+ Predicate predicate;
+ predicate.set_id(21);
+ unordered_map<int64_t, int> atomTrackerMap;
+ EXPECT_EQ(createConditionTracker(key, predicate, 0, atomTrackerMap), nullptr);
+}
+
+TEST(MetricsManagerTest, TestCreateConditionTrackerSimple) {
+ int index = 1;
+ int64_t id = 987;
+ const ConfigKey key(123, 456);
+
+ int startMatcherIndex = 2, stopMatcherIndex = 0, stopAllMatcherIndex = 1;
+ int64_t startMatcherId = 246, stopMatcherId = 153, stopAllMatcherId = 975;
+
+ Predicate predicate;
+ predicate.set_id(id);
+ SimplePredicate* simplePredicate = predicate.mutable_simple_predicate();
+ simplePredicate->set_start(startMatcherId);
+ simplePredicate->set_stop(stopMatcherId);
+ simplePredicate->set_stop_all(stopAllMatcherId);
+
+ unordered_map<int64_t, int> atomTrackerMap;
+ atomTrackerMap[startMatcherId] = startMatcherIndex;
+ atomTrackerMap[stopMatcherId] = stopMatcherIndex;
+ atomTrackerMap[stopAllMatcherId] = stopAllMatcherIndex;
+
+ sp<ConditionTracker> tracker = createConditionTracker(key, predicate, index, atomTrackerMap);
+ EXPECT_EQ(tracker->getConditionId(), id);
+ EXPECT_EQ(tracker->isSliced(), false);
+ EXPECT_TRUE(tracker->IsSimpleCondition());
+ const set<int>& interestedMatchers = tracker->getAtomMatchingTrackerIndex();
+ ASSERT_EQ(interestedMatchers.size(), 3);
+ ASSERT_EQ(interestedMatchers.count(startMatcherIndex), 1);
+ ASSERT_EQ(interestedMatchers.count(stopMatcherIndex), 1);
+ ASSERT_EQ(interestedMatchers.count(stopAllMatcherIndex), 1);
+}
+
+TEST(MetricsManagerTest, TestCreateConditionTrackerCombination) {
+ int index = 1;
+ int64_t id = 987;
+ const ConfigKey key(123, 456);
+
+ Predicate predicate;
+ predicate.set_id(id);
+ Predicate_Combination* combinationPredicate = predicate.mutable_combination();
+ combinationPredicate->set_operation(LogicalOperation::AND);
+ combinationPredicate->add_predicate(888);
+ combinationPredicate->add_predicate(777);
+
+ // Combination conditions must be initialized to set most state.
+ unordered_map<int64_t, int> atomTrackerMap;
+ sp<ConditionTracker> tracker = createConditionTracker(key, predicate, index, atomTrackerMap);
+ EXPECT_EQ(tracker->getConditionId(), id);
+ EXPECT_FALSE(tracker->IsSimpleCondition());
+}
+
} // namespace statsd
} // namespace os
} // namespace android
diff --git a/config/Android.bp b/config/Android.bp
index 0fb56cb3410a..8dd409b51eee 100644
--- a/config/Android.bp
+++ b/config/Android.bp
@@ -13,6 +13,6 @@
// limitations under the License.
filegroup {
- name: "preloaded-classes-blacklist",
- srcs: ["preloaded-classes-blacklist"],
+ name: "preloaded-classes-denylist",
+ srcs: ["preloaded-classes-denylist"],
}
diff --git a/config/generate-preloaded-classes.sh b/config/generate-preloaded-classes.sh
index 0ad3a0263d95..b17a3660e1f1 100755
--- a/config/generate-preloaded-classes.sh
+++ b/config/generate-preloaded-classes.sh
@@ -14,7 +14,7 @@
# See the License for the specific language governing permissions and
# limitations under the License.
if [ "$#" -lt 2 ]; then
- echo "Usage $0 <input classes file> <blacklist file> [extra classes files]"
+ echo "Usage $0 <input classes file> <denylist file> [extra classes files]"
exit 1
fi
@@ -31,9 +31,9 @@ echo "# Preloaded-classes filter file for phones.
#"
input=$1
-blacklist=$2
+denylist=$2
shift 2
extra_classes_files=("$@")
# Disable locale to enable lexicographical sorting
-LC_ALL=C sort "$input" "${extra_classes_files[@]}" | uniq | grep -f "$blacklist" -v -F -x | grep -v "\$NoPreloadHolder"
+LC_ALL=C sort "$input" "${extra_classes_files[@]}" | uniq | grep -f "$denylist" -v -F -x | grep -v "\$NoPreloadHolder"
diff --git a/config/preloaded-classes-blacklist b/config/preloaded-classes-denylist
index 8ab5273cd755..8ab5273cd755 100644
--- a/config/preloaded-classes-blacklist
+++ b/config/preloaded-classes-denylist
diff --git a/core/java/android/app/ActivityThread.java b/core/java/android/app/ActivityThread.java
index f6b045349219..caca05a9e3b3 100644
--- a/core/java/android/app/ActivityThread.java
+++ b/core/java/android/app/ActivityThread.java
@@ -5656,6 +5656,11 @@ public final class ActivityThread extends ClientTransactionHandler {
throw new IllegalArgumentException("Activity token not set. Is the activity attached?");
}
+ // WindowConfiguration differences aren't considered as public, check it separately.
+ // multi-window / pip mode changes, if any, should be sent before the configuration
+ // change callback, see also PinnedStackTests#testConfigurationChangeOrderDuringTransition
+ handleWindowingModeChangeIfNeeded(activity, newConfig);
+
final boolean movedToDifferentDisplay = isDifferentDisplay(activity, displayId);
boolean shouldReportChange = false;
if (activity.mCurrentConfig == null) {
@@ -5708,11 +5713,6 @@ public final class ActivityThread extends ClientTransactionHandler {
}
if (shouldReportChange) {
- // multi-window / pip mode changes, if any, should be sent before the configuration
- // change callback, see also
- // PinnedStackTests#testConfigurationChangeOrderDuringTransition
- handleWindowingModeChangeIfNeeded(activity, newConfig);
-
activity.mCalled = false;
activity.onConfigurationChanged(configToReport);
if (!activity.mCalled) {
diff --git a/core/java/android/app/AppOpsManager.java b/core/java/android/app/AppOpsManager.java
index 00557114bab0..7087b60d75dd 100644
--- a/core/java/android/app/AppOpsManager.java
+++ b/core/java/android/app/AppOpsManager.java
@@ -1160,9 +1160,17 @@ public class AppOpsManager {
// TODO: Add as AppProtoEnums
public static final int OP_PHONE_CALL_CAMERA = 101;
+ /**
+ * Audio is being recorded for hotword detection.
+ *
+ * @hide
+ */
+ // TODO: Add as AppProtoEnums
+ public static final int OP_RECORD_AUDIO_HOTWORD = 102;
+
/** @hide */
@UnsupportedAppUsage
- public static final int _NUM_OP = 102;
+ public static final int _NUM_OP = 103;
/** Access to coarse location information. */
public static final String OPSTR_COARSE_LOCATION = "android:coarse_location";
@@ -1497,6 +1505,13 @@ public class AppOpsManager {
*/
public static final String OPSTR_PHONE_CALL_CAMERA = "android:phone_call_camera";
+ /**
+ * Audio is being recorded for hotword detection.
+ *
+ * @hide
+ */
+ public static final String OPSTR_RECORD_AUDIO_HOTWORD = "android:record_audio_hotword";
+
/** {@link #sAppOpsToNote} not initialized yet for this op */
private static final byte SHOULD_COLLECT_NOTE_OP_NOT_INITIALIZED = 0;
/** Should not collect noting of this app-op in {@link #sAppOpsToNote} */
@@ -1688,6 +1703,7 @@ public class AppOpsManager {
OP_NO_ISOLATED_STORAGE, // NO_ISOLATED_STORAGE
OP_PHONE_CALL_MICROPHONE, // OP_PHONE_CALL_MICROPHONE
OP_PHONE_CALL_CAMERA, // OP_PHONE_CALL_CAMERA
+ OP_RECORD_AUDIO_HOTWORD, // RECORD_AUDIO_HOTWORD
};
/**
@@ -1796,6 +1812,7 @@ public class AppOpsManager {
OPSTR_NO_ISOLATED_STORAGE,
OPSTR_PHONE_CALL_MICROPHONE,
OPSTR_PHONE_CALL_CAMERA,
+ OPSTR_RECORD_AUDIO_HOTWORD,
};
/**
@@ -1905,6 +1922,7 @@ public class AppOpsManager {
"NO_ISOLATED_STORAGE",
"PHONE_CALL_MICROPHONE",
"PHONE_CALL_CAMERA",
+ "RECORD_AUDIO_HOTWORD",
};
/**
@@ -2015,6 +2033,7 @@ public class AppOpsManager {
null, // no permission for OP_NO_ISOLATED_STORAGE
null, // no permission for OP_PHONE_CALL_MICROPHONE
null, // no permission for OP_PHONE_CALL_CAMERA
+ null, // no permission for OP_RECORD_AUDIO_HOTWORD
};
/**
@@ -2125,6 +2144,7 @@ public class AppOpsManager {
null, // NO_ISOLATED_STORAGE
null, // PHONE_CALL_MICROPHONE
null, // PHONE_CALL_MICROPHONE
+ null, // RECORD_AUDIO_HOTWORD
};
/**
@@ -2234,6 +2254,7 @@ public class AppOpsManager {
null, // NO_ISOLATED_STORAGE
null, // PHONE_CALL_MICROPHONE
null, // PHONE_CALL_CAMERA
+ null, // RECORD_AUDIO_HOTWORD
};
/**
@@ -2342,6 +2363,7 @@ public class AppOpsManager {
AppOpsManager.MODE_ERRORED, // OP_NO_ISOLATED_STORAGE
AppOpsManager.MODE_ALLOWED, // PHONE_CALL_MICROPHONE
AppOpsManager.MODE_ALLOWED, // PHONE_CALL_CAMERA
+ AppOpsManager.MODE_ALLOWED, // OP_RECORD_AUDIO_HOTWORD
};
/**
@@ -2454,6 +2476,7 @@ public class AppOpsManager {
true, // NO_ISOLATED_STORAGE
false, // PHONE_CALL_MICROPHONE
false, // PHONE_CALL_CAMERA
+ false, // RECORD_AUDIO_HOTWORD
};
/**
diff --git a/core/java/android/app/ApplicationPackageManager.java b/core/java/android/app/ApplicationPackageManager.java
index 340d5a12f92e..2780036d8102 100644
--- a/core/java/android/app/ApplicationPackageManager.java
+++ b/core/java/android/app/ApplicationPackageManager.java
@@ -73,6 +73,7 @@ import android.os.Bundle;
import android.os.Handler;
import android.os.Looper;
import android.os.Message;
+import android.os.ParcelableException;
import android.os.PersistableBundle;
import android.os.Process;
import android.os.RemoteException;
@@ -107,7 +108,11 @@ import dalvik.system.VMRuntime;
import libcore.util.EmptyArray;
+import java.io.IOException;
import java.lang.ref.WeakReference;
+import java.security.cert.Certificate;
+import java.security.cert.CertificateEncodingException;
+import java.security.cert.X509Certificate;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
@@ -135,6 +140,12 @@ public class ApplicationPackageManager extends PackageManager {
// Default flags to use with PackageManager when no flags are given.
private static final int sDefaultFlags = GET_SHARED_LIBRARY_FILES;
+ /** Default set of checksums - includes all available checksums.
+ * @see PackageManager#getChecksums */
+ private static final int DEFAULT_CHECKSUMS =
+ WHOLE_MERKLE_ROOT_4K_SHA256 | WHOLE_MD5 | WHOLE_SHA1 | WHOLE_SHA256 | WHOLE_SHA512
+ | PARTIAL_MERKLE_ROOT_1M_SHA256 | PARTIAL_MERKLE_ROOT_1M_SHA512;
+
// Name of the resource which provides background permission button string
public static final String APP_PERMISSION_BUTTON_ALLOW_ALWAYS =
"app_permission_button_allow_always";
@@ -945,6 +956,39 @@ public class ApplicationPackageManager extends PackageManager {
}
}
+ private static List<byte[]> encodeCertificates(List<Certificate> certs) throws
+ CertificateEncodingException {
+ if (certs == null) {
+ return null;
+ }
+ List<byte[]> result = new ArrayList<>(certs.size());
+ for (Certificate cert : certs) {
+ if (!(cert instanceof X509Certificate)) {
+ throw new CertificateEncodingException("Only X509 certificates supported.");
+ }
+ result.add(cert.getEncoded());
+ }
+ return result;
+ }
+
+ @Override
+ public void getChecksums(@NonNull String packageName, boolean includeSplits,
+ @FileChecksumKind int required, @Nullable List<Certificate> trustedInstallers,
+ @NonNull IntentSender statusReceiver)
+ throws CertificateEncodingException, IOException, NameNotFoundException {
+ Objects.requireNonNull(packageName);
+ Objects.requireNonNull(statusReceiver);
+ try {
+ mPM.getChecksums(packageName, includeSplits, DEFAULT_CHECKSUMS, required,
+ encodeCertificates(trustedInstallers), statusReceiver, getUserId());
+ } catch (ParcelableException e) {
+ e.maybeRethrow(PackageManager.NameNotFoundException.class);
+ throw new RuntimeException(e);
+ } catch (RemoteException e) {
+ throw e.rethrowFromSystemServer();
+ }
+ }
+
/**
* Wrap the cached value in a class that does deep compares on string
* arrays. The comparison is needed only for the verification mode of
diff --git a/core/java/android/app/ContextImpl.java b/core/java/android/app/ContextImpl.java
index cee607fd7428..fef8d1005e29 100644
--- a/core/java/android/app/ContextImpl.java
+++ b/core/java/android/app/ContextImpl.java
@@ -1924,10 +1924,8 @@ class ContextImpl extends Context {
@Override
public Object getSystemService(String name) {
if (vmIncorrectContextUseEnabled()) {
- // We may override this API from outer context.
- final boolean isUiContext = isUiContext() || isOuterUiContext();
// Check incorrect Context usage.
- if (isUiComponent(name) && !isUiContext) {
+ if (isUiComponent(name) && !isSelfOrOuterUiContext()) {
final String errorMessage = "Tried to access visual service "
+ SystemServiceRegistry.getSystemServiceClassName(name)
+ " from a non-visual Context:" + getOuterContext();
@@ -1944,15 +1942,17 @@ class ContextImpl extends Context {
return SystemServiceRegistry.getSystemService(this, name);
}
- private boolean isOuterUiContext() {
- return getOuterContext() != null && getOuterContext().isUiContext();
- }
-
@Override
public String getSystemServiceName(Class<?> serviceClass) {
return SystemServiceRegistry.getSystemServiceName(serviceClass);
}
+ // TODO(b/149463653): check if we still need this method after migrating IMS to WindowContext.
+ private boolean isSelfOrOuterUiContext() {
+ // We may override outer context's isUiContext
+ return isUiContext() || getOuterContext() != null && getOuterContext().isUiContext();
+ }
+
/** @hide */
@Override
public boolean isUiContext() {
@@ -2413,7 +2413,7 @@ class ContextImpl extends Context {
context.setResources(createResources(mToken, mPackageInfo, mSplitName, overrideDisplayId,
overrideConfiguration, getDisplayAdjustments(displayId).getCompatibilityInfo(),
mResources.getLoaders()));
- context.mIsUiContext = isUiContext() || isOuterUiContext();
+ context.mIsUiContext = isSelfOrOuterUiContext();
return context;
}
@@ -2529,9 +2529,9 @@ class ContextImpl extends Context {
@Override
public Display getDisplay() {
- if (!mIsSystemOrSystemUiContext && !mIsAssociatedWithDisplay) {
+ if (!mIsSystemOrSystemUiContext && !mIsAssociatedWithDisplay && !isSelfOrOuterUiContext()) {
throw new UnsupportedOperationException("Tried to obtain display from a Context not "
- + "associated with one. Only visual Contexts (such as Activity or one created "
+ + "associated with one. Only visual Contexts (such as Activity or one created "
+ "with Context#createWindowContext) or ones created with "
+ "Context#createDisplayContext are associated with displays. Other types of "
+ "Contexts are typically related to background entities and may return an "
diff --git a/core/java/android/app/IActivityManager.aidl b/core/java/android/app/IActivityManager.aidl
index 0a47248e3b70..cd9e02d30d05 100644
--- a/core/java/android/app/IActivityManager.aidl
+++ b/core/java/android/app/IActivityManager.aidl
@@ -695,4 +695,14 @@ interface IActivityManager {
* android.permission.RESET_APP_ERRORS.
*/
void resetAppErrors();
+
+ /**
+ * Control the app freezer state. Returns true in case of success, false if the operation
+ * didn't succeed (for example, when the app freezer isn't supported).
+ * Handling the freezer state via this method is reentrant, that is it can be
+ * disabled and re-enabled multiple times in parallel. As long as there's a 1:1 disable to
+ * enable match, the freezer is re-enabled at last enable only.
+ * @param enable set it to true to enable the app freezer, false to disable it.
+ */
+ boolean enableAppFreezer(in boolean enable);
}
diff --git a/core/java/android/app/Notification.java b/core/java/android/app/Notification.java
index 6737972dc34e..1ff48f6baa6a 100644
--- a/core/java/android/app/Notification.java
+++ b/core/java/android/app/Notification.java
@@ -207,7 +207,7 @@ public class Notification implements Parcelable
* <p>
* Avoids spamming the system with overly large strings such as full e-mails.
*/
- private static final int MAX_CHARSEQUENCE_LENGTH = 5 * 1024;
+ private static final int MAX_CHARSEQUENCE_LENGTH = 1024;
/**
* Maximum entries of reply text that are accepted by Builder and friends.
@@ -7863,7 +7863,7 @@ public class Notification implements Parcelable
*/
public Message(@NonNull CharSequence text, long timestamp, @Nullable Person sender,
boolean remoteInputHistory) {
- mText = text;
+ mText = safeCharSequence(text);
mTimestamp = timestamp;
mSender = sender;
mRemoteInputHistory = remoteInputHistory;
@@ -7977,7 +7977,7 @@ public class Notification implements Parcelable
bundle.putLong(KEY_TIMESTAMP, mTimestamp);
if (mSender != null) {
// Legacy listeners need this
- bundle.putCharSequence(KEY_SENDER, mSender.getName());
+ bundle.putCharSequence(KEY_SENDER, safeCharSequence(mSender.getName()));
bundle.putParcelable(KEY_SENDER_PERSON, mSender);
}
if (mDataMimeType != null) {
diff --git a/core/java/android/app/ResourcesManager.java b/core/java/android/app/ResourcesManager.java
index 7cd3fcad177b..9e4ab33c6aa0 100644
--- a/core/java/android/app/ResourcesManager.java
+++ b/core/java/android/app/ResourcesManager.java
@@ -54,6 +54,7 @@ import java.io.IOException;
import java.io.PrintWriter;
import java.lang.ref.Reference;
import java.lang.ref.ReferenceQueue;
+import java.lang.ref.SoftReference;
import java.lang.ref.WeakReference;
import java.util.ArrayList;
import java.util.Arrays;
@@ -245,7 +246,7 @@ public class ResourcesManager {
/**
* A cache of DisplayId, DisplayAdjustments to Display.
*/
- private final ArrayMap<Pair<Integer, DisplayAdjustments>, WeakReference<Display>>
+ private final ArrayMap<Pair<Integer, DisplayAdjustments>, SoftReference<Display>>
mAdjustedDisplays = new ArrayMap<>();
/**
@@ -373,25 +374,28 @@ public class ResourcesManager {
? new DisplayAdjustments(displayAdjustments) : new DisplayAdjustments();
final Pair<Integer, DisplayAdjustments> key =
Pair.create(displayId, displayAdjustmentsCopy);
+ SoftReference<Display> sd;
synchronized (this) {
- WeakReference<Display> wd = mAdjustedDisplays.get(key);
- if (wd != null) {
- final Display display = wd.get();
- if (display != null) {
- return display;
- }
- }
- final DisplayManagerGlobal dm = DisplayManagerGlobal.getInstance();
- if (dm == null) {
- // may be null early in system startup
- return null;
- }
- final Display display = dm.getCompatibleDisplay(displayId, key.second);
+ sd = mAdjustedDisplays.get(key);
+ }
+ if (sd != null) {
+ final Display display = sd.get();
if (display != null) {
- mAdjustedDisplays.put(key, new WeakReference<>(display));
+ return display;
+ }
+ }
+ final DisplayManagerGlobal dm = DisplayManagerGlobal.getInstance();
+ if (dm == null) {
+ // may be null early in system startup
+ return null;
+ }
+ final Display display = dm.getCompatibleDisplay(displayId, key.second);
+ if (display != null) {
+ synchronized (this) {
+ mAdjustedDisplays.put(key, new SoftReference<>(display));
}
- return display;
}
+ return display;
}
/**
diff --git a/core/java/android/app/SystemServiceRegistry.java b/core/java/android/app/SystemServiceRegistry.java
index 59997ccab687..3b11b0d80da5 100644
--- a/core/java/android/app/SystemServiceRegistry.java
+++ b/core/java/android/app/SystemServiceRegistry.java
@@ -103,6 +103,7 @@ import android.location.LocationManager;
import android.media.AudioManager;
import android.media.MediaFrameworkInitializer;
import android.media.MediaRouter;
+import android.media.MediaTranscodeManager;
import android.media.midi.IMidiManager;
import android.media.midi.MidiManager;
import android.media.projection.MediaProjectionManager;
@@ -305,6 +306,15 @@ public final class SystemServiceRegistry {
return new AudioManager(ctx);
}});
+ registerService(Context.MEDIA_TRANSCODING_SERVICE, MediaTranscodeManager.class,
+ new CachedServiceFetcher<MediaTranscodeManager>() {
+ @Override
+ public MediaTranscodeManager createService(ContextImpl ctx)
+ throws ServiceNotFoundException {
+ return new MediaTranscodeManager(ctx);
+ }
+ });
+
registerService(Context.MEDIA_ROUTER_SERVICE, MediaRouter.class,
new CachedServiceFetcher<MediaRouter>() {
@Override
diff --git a/core/java/android/app/admin/DevicePolicyManager.java b/core/java/android/app/admin/DevicePolicyManager.java
index c61426d5c172..7b3d9f113bda 100644
--- a/core/java/android/app/admin/DevicePolicyManager.java
+++ b/core/java/android/app/admin/DevicePolicyManager.java
@@ -9751,21 +9751,6 @@ public class DevicePolicyManager {
}
/**
- * @hide
- * Return if this user is a system-only user. An admin can manage a device from a system only
- * user by calling {@link #ACTION_PROVISION_MANAGED_SHAREABLE_DEVICE}.
- * @param admin Which device owner this request is associated with.
- * @return if this user is a system-only user.
- */
- public boolean isSystemOnlyUser(@NonNull ComponentName admin) {
- try {
- return mService.isSystemOnlyUser(admin);
- } catch (RemoteException re) {
- throw re.rethrowFromSystemServer();
- }
- }
-
- /**
* Called by device owner, or profile owner on organization-owned device, to get the MAC
* address of the Wi-Fi device.
*
@@ -12007,6 +11992,9 @@ public class DevicePolicyManager {
* </ul>
* Common Criteria mode is disabled by default.
*
+ * <p><em>Note:</em> if Common Critera mode is turned off after being enabled previously,
+ * all existing WiFi configurations will be lost.
+ *
* @param admin which {@link DeviceAdminReceiver} this request is associated with.
* @param enabled whether Common Criteria mode should be enabled or not.
*/
diff --git a/core/java/android/app/admin/IDevicePolicyManager.aidl b/core/java/android/app/admin/IDevicePolicyManager.aidl
index 9c6a274ccf8c..1c7b617e6d9a 100644
--- a/core/java/android/app/admin/IDevicePolicyManager.aidl
+++ b/core/java/android/app/admin/IDevicePolicyManager.aidl
@@ -345,7 +345,6 @@ interface IDevicePolicyManager {
void setKeepUninstalledPackages(in ComponentName admin, in String callerPackage, in List<String> packageList);
List<String> getKeepUninstalledPackages(in ComponentName admin, in String callerPackage);
boolean isManagedProfile(in ComponentName admin);
- boolean isSystemOnlyUser(in ComponentName admin);
String getWifiMacAddress(in ComponentName admin);
void reboot(in ComponentName admin);
diff --git a/core/java/android/app/prediction/AppPredictor.java b/core/java/android/app/prediction/AppPredictor.java
index 7f436401dbf4..fa135b10ae1f 100644
--- a/core/java/android/app/prediction/AppPredictor.java
+++ b/core/java/android/app/prediction/AppPredictor.java
@@ -83,6 +83,8 @@ public final class AppPredictor {
private final AppPredictionSessionId mSessionId;
private final ArrayMap<Callback, CallbackWrapper> mRegisteredCallbacks = new ArrayMap<>();
+ private final IBinder mToken = new Binder();
+
/**
* Creates a new Prediction client.
* <p>
@@ -98,7 +100,7 @@ public final class AppPredictor {
mSessionId = new AppPredictionSessionId(
context.getPackageName() + ":" + UUID.randomUUID().toString(), context.getUserId());
try {
- mPredictionManager.createPredictionSession(predictionContext, mSessionId);
+ mPredictionManager.createPredictionSession(predictionContext, mSessionId, mToken);
} catch (RemoteException e) {
Log.e(TAG, "Failed to create predictor", e);
e.rethrowAsRuntimeException();
diff --git a/core/java/android/app/prediction/IPredictionManager.aidl b/core/java/android/app/prediction/IPredictionManager.aidl
index 587e3fd52377..863fc6f952dd 100644
--- a/core/java/android/app/prediction/IPredictionManager.aidl
+++ b/core/java/android/app/prediction/IPredictionManager.aidl
@@ -29,7 +29,7 @@ import android.content.pm.ParceledListSlice;
interface IPredictionManager {
void createPredictionSession(in AppPredictionContext context,
- in AppPredictionSessionId sessionId);
+ in AppPredictionSessionId sessionId, in IBinder token);
void notifyAppTargetEvent(in AppPredictionSessionId sessionId, in AppTargetEvent event);
diff --git a/core/java/android/app/timezonedetector/ITimeZoneConfigurationListener.aidl b/core/java/android/app/timezonedetector/ITimeZoneConfigurationListener.aidl
index af77fe05b902..6d0fe72b9de1 100644
--- a/core/java/android/app/timezonedetector/ITimeZoneConfigurationListener.aidl
+++ b/core/java/android/app/timezonedetector/ITimeZoneConfigurationListener.aidl
@@ -20,5 +20,5 @@ import android.app.timezonedetector.TimeZoneConfiguration;
/** {@hide} */
oneway interface ITimeZoneConfigurationListener {
- void onChange(in TimeZoneConfiguration configuration);
+ void onChange();
} \ No newline at end of file
diff --git a/core/java/android/app/timezonedetector/ITimeZoneDetectorService.aidl b/core/java/android/app/timezonedetector/ITimeZoneDetectorService.aidl
index 6e93af6a053b..4f7e1f62928a 100644
--- a/core/java/android/app/timezonedetector/ITimeZoneDetectorService.aidl
+++ b/core/java/android/app/timezonedetector/ITimeZoneDetectorService.aidl
@@ -32,17 +32,15 @@ import android.app.timezonedetector.TimeZoneConfiguration;
* this Binder interface directly. See {@link android.app.timezonedetector.TimeZoneDetectorService}
* for more complete documentation.
*
- *
* {@hide}
*/
interface ITimeZoneDetectorService {
TimeZoneCapabilities getCapabilities();
-
- TimeZoneConfiguration getConfiguration();
- boolean updateConfiguration(in TimeZoneConfiguration configuration);
void addConfigurationListener(ITimeZoneConfigurationListener listener);
void removeConfigurationListener(ITimeZoneConfigurationListener listener);
+ boolean updateConfiguration(in TimeZoneConfiguration configuration);
+
boolean suggestManualTimeZone(in ManualTimeZoneSuggestion timeZoneSuggestion);
void suggestTelephonyTimeZone(in TelephonyTimeZoneSuggestion timeZoneSuggestion);
}
diff --git a/core/java/android/app/timezonedetector/TEST_MAPPING b/core/java/android/app/timezonedetector/TEST_MAPPING
new file mode 100644
index 000000000000..46f2319d69ba
--- /dev/null
+++ b/core/java/android/app/timezonedetector/TEST_MAPPING
@@ -0,0 +1,12 @@
+{
+ "presubmit": [
+ {
+ "name": "FrameworksCoreTests",
+ "options": [
+ {
+ "include-filter": "android.app.timezonedetector."
+ }
+ ]
+ }
+ ]
+}
diff --git a/core/java/android/app/timezonedetector/TimeZoneCapabilities.java b/core/java/android/app/timezonedetector/TimeZoneCapabilities.java
index cc0af3f97e49..09fffe9f4f25 100644
--- a/core/java/android/app/timezonedetector/TimeZoneCapabilities.java
+++ b/core/java/android/app/timezonedetector/TimeZoneCapabilities.java
@@ -16,9 +16,12 @@
package android.app.timezonedetector;
+import static android.app.timezonedetector.TimeZoneConfiguration.SETTING_AUTO_DETECTION_ENABLED;
+import static android.app.timezonedetector.TimeZoneConfiguration.SETTING_GEO_DETECTION_ENABLED;
+
import android.annotation.IntDef;
import android.annotation.NonNull;
-import android.annotation.UserIdInt;
+import android.annotation.Nullable;
import android.os.Parcel;
import android.os.Parcelable;
@@ -38,9 +41,9 @@ import java.util.Objects;
*
* <p>Actions have associated methods, see the documentation for each action for details.
*
- * <p>For configuration capabilities, the associated current configuration value can be retrieved
- * using {@link TimeZoneDetector#getConfiguration()} and may be changed using
- * {@link TimeZoneDetector#updateConfiguration(TimeZoneConfiguration)}.
+ * <p>For configuration settings capabilities, the associated settings value can be found via
+ * {@link #getConfiguration()} and may be changed using {@link
+ * TimeZoneDetector#updateConfiguration(TimeZoneConfiguration)} (if the user's capabilities allow).
*
* <p>Note: Capabilities are independent of app permissions required to call the associated APIs.
*
@@ -60,7 +63,8 @@ public final class TimeZoneCapabilities implements Parcelable {
public static final int CAPABILITY_NOT_SUPPORTED = 10;
/**
- * Indicates that a capability is supported on this device, but not allowed for the user.
+ * Indicates that a capability is supported on this device, but not allowed for the user, e.g.
+ * if the capability relates to the ability to modify settings the user is not able to.
* This could be because of the user's type (e.g. maybe it applies to the primary user only) or
* device policy. Depending on the capability, this could mean the associated UI
* should be hidden, or displayed but disabled.
@@ -68,9 +72,11 @@ public final class TimeZoneCapabilities implements Parcelable {
public static final int CAPABILITY_NOT_ALLOWED = 20;
/**
- * Indicates that a capability is possessed but not applicable, e.g. if it is configuration,
- * the current configuration or device state renders it irrelevant. The associated UI may be
- * hidden, disabled, or left visible (but ineffective) depending on requirements.
+ * Indicates that a capability is possessed but not currently applicable, e.g. if the
+ * capability relates to the ability to modify settings, the user has the ability to modify
+ * it, but it is currently rendered irrelevant by other settings or other device state (flags,
+ * resource config, etc.). The associated UI may be hidden, disabled, or left visible (but
+ * ineffective) depending on requirements.
*/
public static final int CAPABILITY_NOT_APPLICABLE = 30;
@@ -89,13 +95,13 @@ public final class TimeZoneCapabilities implements Parcelable {
};
- private final @UserIdInt int mUserId;
+ @NonNull private final TimeZoneConfiguration mConfiguration;
private final @CapabilityState int mConfigureAutoDetectionEnabled;
private final @CapabilityState int mConfigureGeoDetectionEnabled;
private final @CapabilityState int mSuggestManualTimeZone;
private TimeZoneCapabilities(@NonNull Builder builder) {
- this.mUserId = builder.mUserId;
+ this.mConfiguration = Objects.requireNonNull(builder.mConfiguration);
this.mConfigureAutoDetectionEnabled = builder.mConfigureAutoDetectionEnabled;
this.mConfigureGeoDetectionEnabled = builder.mConfigureGeoDetectionEnabled;
this.mSuggestManualTimeZone = builder.mSuggestManualTimeZone;
@@ -103,7 +109,8 @@ public final class TimeZoneCapabilities implements Parcelable {
@NonNull
private static TimeZoneCapabilities createFromParcel(Parcel in) {
- return new TimeZoneCapabilities.Builder(in.readInt())
+ return new TimeZoneCapabilities.Builder()
+ .setConfiguration(in.readParcelable(null))
.setConfigureAutoDetectionEnabled(in.readInt())
.setConfigureGeoDetectionEnabled(in.readInt())
.setSuggestManualTimeZone(in.readInt())
@@ -112,21 +119,24 @@ public final class TimeZoneCapabilities implements Parcelable {
@Override
public void writeToParcel(@NonNull Parcel dest, int flags) {
- dest.writeInt(mUserId);
+ dest.writeParcelable(mConfiguration, flags);
dest.writeInt(mConfigureAutoDetectionEnabled);
dest.writeInt(mConfigureGeoDetectionEnabled);
dest.writeInt(mSuggestManualTimeZone);
}
- /** Returns the user ID the capabilities are for. */
- public @UserIdInt int getUserId() {
- return mUserId;
+ /**
+ * Returns the user's time zone behavior configuration.
+ */
+ public @NonNull TimeZoneConfiguration getConfiguration() {
+ return mConfiguration;
}
/**
- * Returns the user's capability state for controlling whether automatic time zone detection is
- * enabled via {@link TimeZoneDetector#updateConfiguration(TimeZoneConfiguration)} and {@link
- * TimeZoneConfiguration#isAutoDetectionEnabled()}.
+ * Returns the capability state associated with the user's ability to modify the automatic time
+ * zone detection setting. The setting can be updated via {@link
+ * TimeZoneDetector#updateConfiguration(TimeZoneConfiguration)} and accessed via {@link
+ * #getConfiguration()}.
*/
@CapabilityState
public int getConfigureAutoDetectionEnabled() {
@@ -134,9 +144,10 @@ public final class TimeZoneCapabilities implements Parcelable {
}
/**
- * Returns the user's capability state for controlling whether geolocation can be used to detect
- * time zone via {@link TimeZoneDetector#updateConfiguration(TimeZoneConfiguration)} and {@link
- * TimeZoneConfiguration#isGeoDetectionEnabled()}.
+ * Returns the capability state associated with the user's ability to modify the geolocation
+ * detection setting. The setting can be updated via {@link
+ * TimeZoneDetector#updateConfiguration(TimeZoneConfiguration)} and accessed via {@link
+ * #getConfiguration()}.
*/
@CapabilityState
public int getConfigureGeoDetectionEnabled() {
@@ -144,8 +155,8 @@ public final class TimeZoneCapabilities implements Parcelable {
}
/**
- * Returns the user's capability state for manually setting the time zone on a device via
- * {@link TimeZoneDetector#suggestManualTimeZone(ManualTimeZoneSuggestion)}.
+ * Returns the capability state associated with the user's ability to manually set the time zone
+ * on a device via {@link TimeZoneDetector#suggestManualTimeZone(ManualTimeZoneSuggestion)}.
*
* <p>The suggestion will be ignored in all cases unless the value is {@link
* #CAPABILITY_POSSESSED}. See also {@link TimeZoneConfiguration#isAutoDetectionEnabled()}.
@@ -155,6 +166,38 @@ public final class TimeZoneCapabilities implements Parcelable {
return mSuggestManualTimeZone;
}
+ /**
+ * Constructs a new {@link TimeZoneConfiguration} from an {@code oldConfiguration} and a set of
+ * {@code requestedChanges}, if the current capabilities allow. The new configuration is
+ * returned and the capabilities are left unchanged. If the capabilities do not permit one or
+ * more of the changes then {@code null} is returned.
+ */
+ @Nullable
+ public TimeZoneConfiguration applyUpdate(TimeZoneConfiguration requestedChanges) {
+ if (requestedChanges.getUserId() != mConfiguration.getUserId()) {
+ throw new IllegalArgumentException("User does not match:"
+ + " this=" + mConfiguration + ", other=" + requestedChanges);
+ }
+
+ TimeZoneConfiguration.Builder newConfigBuilder =
+ new TimeZoneConfiguration.Builder(mConfiguration);
+ if (requestedChanges.hasSetting(SETTING_AUTO_DETECTION_ENABLED)) {
+ if (getConfigureAutoDetectionEnabled() < CAPABILITY_NOT_APPLICABLE) {
+ return null;
+ }
+ newConfigBuilder.setAutoDetectionEnabled(requestedChanges.isAutoDetectionEnabled());
+ }
+
+ if (requestedChanges.hasSetting(SETTING_GEO_DETECTION_ENABLED)) {
+ if (getConfigureGeoDetectionEnabled() < CAPABILITY_NOT_APPLICABLE) {
+ return null;
+ }
+ newConfigBuilder.setGeoDetectionEnabled(requestedChanges.isGeoDetectionEnabled());
+ }
+
+ return newConfigBuilder.build();
+ }
+
@Override
public int describeContents() {
return 0;
@@ -169,7 +212,7 @@ public final class TimeZoneCapabilities implements Parcelable {
return false;
}
TimeZoneCapabilities that = (TimeZoneCapabilities) o;
- return mUserId == that.mUserId
+ return Objects.equals(mConfiguration, that.mConfiguration)
&& mConfigureAutoDetectionEnabled == that.mConfigureAutoDetectionEnabled
&& mConfigureGeoDetectionEnabled == that.mConfigureGeoDetectionEnabled
&& mSuggestManualTimeZone == that.mSuggestManualTimeZone;
@@ -177,7 +220,7 @@ public final class TimeZoneCapabilities implements Parcelable {
@Override
public int hashCode() {
- return Objects.hash(mUserId,
+ return Objects.hash(mConfiguration,
mConfigureAutoDetectionEnabled,
mConfigureGeoDetectionEnabled,
mSuggestManualTimeZone);
@@ -186,7 +229,7 @@ public final class TimeZoneCapabilities implements Parcelable {
@Override
public String toString() {
return "TimeZoneDetectorCapabilities{"
- + "mUserId=" + mUserId
+ + "mConfiguration=" + mConfiguration
+ ", mConfigureAutomaticDetectionEnabled=" + mConfigureAutoDetectionEnabled
+ ", mConfigureGeoDetectionEnabled=" + mConfigureGeoDetectionEnabled
+ ", mSuggestManualTimeZone=" + mSuggestManualTimeZone
@@ -196,16 +239,18 @@ public final class TimeZoneCapabilities implements Parcelable {
/** @hide */
public static class Builder {
- private final @UserIdInt int mUserId;
+ private TimeZoneConfiguration mConfiguration;
private @CapabilityState int mConfigureAutoDetectionEnabled;
private @CapabilityState int mConfigureGeoDetectionEnabled;
private @CapabilityState int mSuggestManualTimeZone;
- /**
- * Creates a new Builder with no properties set.
- */
- public Builder(@UserIdInt int userId) {
- mUserId = userId;
+ /** Sets the user-visible configuration settings. */
+ public Builder setConfiguration(@NonNull TimeZoneConfiguration configuration) {
+ if (!configuration.isComplete()) {
+ throw new IllegalArgumentException(configuration + " is not complete");
+ }
+ this.mConfiguration = configuration;
+ return this;
}
/** Sets the state for the automatic time zone detection enabled config. */
diff --git a/core/java/android/app/timezonedetector/TimeZoneConfiguration.java b/core/java/android/app/timezonedetector/TimeZoneConfiguration.java
index 6f84ee22a985..95db0a26cc6e 100644
--- a/core/java/android/app/timezonedetector/TimeZoneConfiguration.java
+++ b/core/java/android/app/timezonedetector/TimeZoneConfiguration.java
@@ -18,6 +18,7 @@ package android.app.timezonedetector;
import android.annotation.NonNull;
import android.annotation.StringDef;
+import android.annotation.UserIdInt;
import android.os.Bundle;
import android.os.Parcel;
import android.os.Parcelable;
@@ -27,21 +28,20 @@ import java.lang.annotation.RetentionPolicy;
import java.util.Objects;
/**
- * Configuration that controls the behavior of the time zone detector associated with a specific
- * user.
+ * User visible settings that control the behavior of the time zone detector / manual time zone
+ * entry.
*
- * <p>Configuration consists of a set of known properties. When reading configuration via
- * {@link TimeZoneDetector#getConfiguration()} values for all known properties will be provided. In
- * some cases, such as when the configuration relies on optional hardware, the values may be
- * meaningless / defaulted to safe values.
+ * <p>When reading the configuration, values for all settings will be provided. In some cases, such
+ * as when the device behavior relies on optional hardware / OEM configuration, or the value of
+ * several settings, the device behavior may not be directly affected by the setting value.
*
- * <p>Configuration properties can be left absent when updating configuration via {@link
- * TimeZoneDetector#updateConfiguration(TimeZoneConfiguration)} and those values will not be
- * changed. Not all configuration properties can be modified by all users. See {@link
- * TimeZoneDetector#getCapabilities()} and {@link TimeZoneCapabilities}.
+ * <p>Settings can be left absent when updating configuration via {@link
+ * TimeZoneDetector#updateConfiguration(TimeZoneConfiguration)} and those settings will not be
+ * changed. Not all configuration settings can be modified by all users: see {@link
+ * TimeZoneDetector#getCapabilities()} and {@link TimeZoneCapabilities} for details.
*
- * <p>See {@link #isComplete()} to tell if all known properties are present, and {@link
- * #hasProperty(String)} with {@code PROPERTY_} constants for testing individual properties.
+ * <p>See {@link #hasSetting(String)} with {@code PROPERTY_} constants for testing for the presence
+ * of individual settings.
*
* @hide
*/
@@ -59,80 +59,82 @@ public final class TimeZoneConfiguration implements Parcelable {
};
/** All configuration properties */
- @StringDef(PROPERTY_AUTO_DETECTION_ENABLED)
+ @StringDef({ SETTING_AUTO_DETECTION_ENABLED, SETTING_GEO_DETECTION_ENABLED })
@Retention(RetentionPolicy.SOURCE)
- @interface Property {}
+ @interface Setting {}
/** See {@link TimeZoneConfiguration#isAutoDetectionEnabled()} for details. */
- @Property
- public static final String PROPERTY_AUTO_DETECTION_ENABLED = "autoDetectionEnabled";
+ @Setting
+ public static final String SETTING_AUTO_DETECTION_ENABLED = "autoDetectionEnabled";
/** See {@link TimeZoneConfiguration#isGeoDetectionEnabled()} for details. */
- @Property
- public static final String PROPERTY_GEO_DETECTION_ENABLED = "geoDetectionEnabled";
+ @Setting
+ public static final String SETTING_GEO_DETECTION_ENABLED = "geoDetectionEnabled";
- private final Bundle mBundle;
+ private final @UserIdInt int mUserId;
+ @NonNull private final Bundle mBundle;
private TimeZoneConfiguration(Builder builder) {
- this.mBundle = builder.mBundle;
+ this.mUserId = builder.mUserId;
+ this.mBundle = Objects.requireNonNull(builder.mBundle);
}
private static TimeZoneConfiguration createFromParcel(Parcel in) {
- return new TimeZoneConfiguration.Builder()
+ return new TimeZoneConfiguration.Builder(in.readInt())
.setPropertyBundleInternal(in.readBundle())
.build();
}
@Override
public void writeToParcel(@NonNull Parcel dest, int flags) {
+ dest.writeInt(mUserId);
dest.writeBundle(mBundle);
}
- /** Returns {@code true} if all known properties are set. */
+ /** Returns the ID of the user this configuration is associated with. */
+ public @UserIdInt int getUserId() {
+ return mUserId;
+ }
+
+ /** Returns {@code true} if all known settings are present. */
public boolean isComplete() {
- return hasProperty(PROPERTY_AUTO_DETECTION_ENABLED)
- && hasProperty(PROPERTY_GEO_DETECTION_ENABLED);
+ return hasSetting(SETTING_AUTO_DETECTION_ENABLED)
+ && hasSetting(SETTING_GEO_DETECTION_ENABLED);
}
- /** Returns true if the specified property is set. */
- public boolean hasProperty(@Property String property) {
- return mBundle.containsKey(property);
+ /** Returns true if the specified setting is set. */
+ public boolean hasSetting(@Setting String setting) {
+ return mBundle.containsKey(setting);
}
/**
- * Returns the value of the {@link #PROPERTY_AUTO_DETECTION_ENABLED} property. This
+ * Returns the value of the {@link #SETTING_AUTO_DETECTION_ENABLED} setting. This
* controls whether a device will attempt to determine the time zone automatically using
- * contextual information.
+ * contextual information if the device supports auto detection.
+ *
+ * <p>This setting is global and can be updated by some users.
*
- * @throws IllegalStateException if the field has not been set
+ * @throws IllegalStateException if the setting has not been set
*/
public boolean isAutoDetectionEnabled() {
- if (!mBundle.containsKey(PROPERTY_AUTO_DETECTION_ENABLED)) {
- throw new IllegalStateException(PROPERTY_AUTO_DETECTION_ENABLED + " is not set");
- }
- return mBundle.getBoolean(PROPERTY_AUTO_DETECTION_ENABLED);
+ enforceSettingPresent(SETTING_AUTO_DETECTION_ENABLED);
+ return mBundle.getBoolean(SETTING_AUTO_DETECTION_ENABLED);
}
/**
- * Returns the value of the {@link #PROPERTY_GEO_DETECTION_ENABLED} property. This
- * controls whether a device can use location to determine time zone. Only used when
- * {@link #isAutoDetectionEnabled()} is true.
+ * Returns the value of the {@link #SETTING_GEO_DETECTION_ENABLED} setting. This
+ * controls whether a device can use geolocation to determine time zone. Only used when
+ * {@link #isAutoDetectionEnabled()} is {@code true} and when the user has allowed their
+ * location to be used.
+ *
+ * <p>This setting is user-scoped and can be updated by some users.
+ * See {@link TimeZoneCapabilities#getConfigureGeoDetectionEnabled()}.
*
- * @throws IllegalStateException if the field has not been set
+ * @throws IllegalStateException if the setting has not been set
*/
public boolean isGeoDetectionEnabled() {
- if (!mBundle.containsKey(PROPERTY_GEO_DETECTION_ENABLED)) {
- throw new IllegalStateException(PROPERTY_GEO_DETECTION_ENABLED + " is not set");
- }
- return mBundle.getBoolean(PROPERTY_GEO_DETECTION_ENABLED);
- }
-
- /**
- * Convenience method to merge this with another. The argument configuration properties have
- * precedence.
- */
- public TimeZoneConfiguration with(TimeZoneConfiguration other) {
- return new Builder(this).mergeProperties(other).build();
+ enforceSettingPresent(SETTING_GEO_DETECTION_ENABLED);
+ return mBundle.getBoolean(SETTING_GEO_DETECTION_ENABLED);
}
@Override
@@ -149,43 +151,61 @@ public final class TimeZoneConfiguration implements Parcelable {
return false;
}
TimeZoneConfiguration that = (TimeZoneConfiguration) o;
- return mBundle.kindofEquals(that.mBundle);
+ return mUserId == that.mUserId
+ && mBundle.kindofEquals(that.mBundle);
}
@Override
public int hashCode() {
- return Objects.hash(mBundle);
+ return Objects.hash(mUserId, mBundle);
}
@Override
public String toString() {
return "TimeZoneDetectorConfiguration{"
+ + "mUserId=" + mUserId
+ "mBundle=" + mBundle
+ '}';
}
+ private void enforceSettingPresent(@Setting String setting) {
+ if (!mBundle.containsKey(setting)) {
+ throw new IllegalStateException(setting + " is not set");
+ }
+ }
+
/** @hide */
public static class Builder {
- private Bundle mBundle = new Bundle();
+ private final @UserIdInt int mUserId;
+ private final Bundle mBundle = new Bundle();
/**
- * Creates a new Builder with no properties set.
+ * Creates a new Builder for a userId with no settings held.
*/
- public Builder() {}
+ public Builder(@UserIdInt int userId) {
+ mUserId = userId;
+ }
/**
- * Creates a new Builder by copying properties from an existing instance.
+ * Creates a new Builder by copying the user ID and settings from an existing instance.
*/
public Builder(TimeZoneConfiguration toCopy) {
+ this.mUserId = toCopy.mUserId;
mergeProperties(toCopy);
}
/**
- * Merges {@code other} properties into this instances, replacing existing values in this
- * where the properties appear in both.
+ * Merges {@code other} settings into this instances, replacing existing values in this
+ * where the settings appear in both.
*/
public Builder mergeProperties(TimeZoneConfiguration other) {
+ if (mUserId != other.mUserId) {
+ throw new IllegalArgumentException(
+ "Cannot merge configurations for different user IDs."
+ + " this.mUserId=" + this.mUserId
+ + ", other.mUserId=" + other.mUserId);
+ }
this.mBundle.putAll(other.mBundle);
return this;
}
@@ -195,15 +215,19 @@ public final class TimeZoneConfiguration implements Parcelable {
return this;
}
- /** Sets the desired state of the automatic time zone detection property. */
+ /**
+ * Sets the state of the {@link #SETTING_AUTO_DETECTION_ENABLED} setting.
+ */
public Builder setAutoDetectionEnabled(boolean enabled) {
- this.mBundle.putBoolean(PROPERTY_AUTO_DETECTION_ENABLED, enabled);
+ this.mBundle.putBoolean(SETTING_AUTO_DETECTION_ENABLED, enabled);
return this;
}
- /** Sets the desired state of the geolocation time zone detection enabled property. */
+ /**
+ * Sets the state of the {@link #SETTING_GEO_DETECTION_ENABLED} setting.
+ */
public Builder setGeoDetectionEnabled(boolean enabled) {
- this.mBundle.putBoolean(PROPERTY_GEO_DETECTION_ENABLED, enabled);
+ this.mBundle.putBoolean(SETTING_GEO_DETECTION_ENABLED, enabled);
return this;
}
diff --git a/core/java/android/app/timezonedetector/TimeZoneDetector.java b/core/java/android/app/timezonedetector/TimeZoneDetector.java
index 7885613bfb59..2b1cbf259c55 100644
--- a/core/java/android/app/timezonedetector/TimeZoneDetector.java
+++ b/core/java/android/app/timezonedetector/TimeZoneDetector.java
@@ -37,37 +37,29 @@ public interface TimeZoneDetector {
TimeZoneCapabilities getCapabilities();
/**
- * Returns the current user's complete time zone configuration. See {@link
- * TimeZoneConfiguration}.
- */
- @RequiresPermission(android.Manifest.permission.WRITE_SECURE_SETTINGS)
- @NonNull
- TimeZoneConfiguration getConfiguration();
-
- /**
* Modifies the time zone detection configuration.
*
- * <p>Configuration properties vary in scope: some may be device-wide, others may be specific to
- * the current user.
+ * <p>Configuration settings vary in scope: some may be global (affect all users), others may be
+ * specific to the current user.
*
- * <p>The ability to modify configuration properties can be subject to restrictions. For
+ * <p>The ability to modify configuration settings can be subject to restrictions. For
* example, they may be determined by device hardware, general policy (i.e. only the primary
- * user can set them), or by a managed device policy. See {@link #getCapabilities()} to obtain
+ * user can set them), or by a managed device policy. Use {@link #getCapabilities()} to obtain
* information at runtime about the user's capabilities.
*
- * <p>Attempts to set configuration with capabilities that are {@link
+ * <p>Attempts to modify configuration settings with capabilities that are {@link
* TimeZoneCapabilities#CAPABILITY_NOT_SUPPORTED} or {@link
* TimeZoneCapabilities#CAPABILITY_NOT_ALLOWED} will have no effect and a {@code false}
- * will be returned. Setting configuration with capabilities that are {@link
+ * will be returned. Modifying configuration settings with capabilities that are {@link
* TimeZoneCapabilities#CAPABILITY_NOT_APPLICABLE} or {@link
* TimeZoneCapabilities#CAPABILITY_POSSESSED} will succeed. See {@link
* TimeZoneCapabilities} for further details.
*
- * <p>If the configuration is not "complete", then only the specified properties will be
- * updated (where the user's capabilities allow) and other settings will be left unchanged. See
- * {@link TimeZoneConfiguration#isComplete()}.
+ * <p>If the supplied configuration only has some values set, then only the specified settings
+ * will be updated (where the user's capabilities allow) and other settings will be left
+ * unchanged.
*
- * @return {@code true} if all the configuration properties specified have been set to the
+ * @return {@code true} if all the configuration settings specified have been set to the
* new values, {@code false} if none have
*/
@RequiresPermission(android.Manifest.permission.WRITE_SECURE_SETTINGS)
@@ -76,14 +68,20 @@ public interface TimeZoneDetector {
/**
* An interface that can be used to listen for changes to the time zone detector configuration.
*/
+ @FunctionalInterface
interface TimeZoneConfigurationListener {
- /** Called when the configuration changes. There are no guarantees about the thread used. */
- void onChange(@NonNull TimeZoneConfiguration configuration);
+ /**
+ * Called when something about the time zone configuration on the device has changed.
+ * This could be because the current user has changed, one of the device's relevant settings
+ * has changed, or something that could affect a user's capabilities has changed.
+ * There are no guarantees about the thread used.
+ */
+ void onChange();
}
/**
- * Registers a listener that will be informed when the configuration changes. The complete
- * configuration is passed to the listener, not just the properties that have changed.
+ * Registers a listener that will be informed when something about the time zone configuration
+ * changes.
*/
@RequiresPermission(android.Manifest.permission.WRITE_SECURE_SETTINGS)
void addConfigurationListener(@NonNull TimeZoneConfigurationListener listener);
diff --git a/core/java/android/app/timezonedetector/TimeZoneDetectorImpl.java b/core/java/android/app/timezonedetector/TimeZoneDetectorImpl.java
index 0770aff4e9bb..4c69732abec9 100644
--- a/core/java/android/app/timezonedetector/TimeZoneDetectorImpl.java
+++ b/core/java/android/app/timezonedetector/TimeZoneDetectorImpl.java
@@ -57,19 +57,6 @@ public final class TimeZoneDetectorImpl implements TimeZoneDetector {
}
@Override
- @NonNull
- public TimeZoneConfiguration getConfiguration() {
- if (DEBUG) {
- Log.d(TAG, "getConfiguration called");
- }
- try {
- return mITimeZoneDetectorService.getConfiguration();
- } catch (RemoteException e) {
- throw e.rethrowFromSystemServer();
- }
- }
-
- @Override
public boolean updateConfiguration(@NonNull TimeZoneConfiguration configuration) {
if (DEBUG) {
Log.d(TAG, "updateConfiguration called: " + configuration);
@@ -94,8 +81,8 @@ public final class TimeZoneDetectorImpl implements TimeZoneDetector {
ITimeZoneConfigurationListener iListener =
new ITimeZoneConfigurationListener.Stub() {
@Override
- public void onChange(@NonNull TimeZoneConfiguration configuration) {
- notifyConfigurationListeners(configuration);
+ public void onChange() {
+ notifyConfigurationListeners();
}
};
mConfigurationReceiver = iListener;
@@ -116,14 +103,14 @@ public final class TimeZoneDetectorImpl implements TimeZoneDetector {
}
}
- private void notifyConfigurationListeners(@NonNull TimeZoneConfiguration configuration) {
+ private void notifyConfigurationListeners() {
final ArraySet<TimeZoneConfigurationListener> configurationListeners;
synchronized (this) {
configurationListeners = new ArraySet<>(mConfigurationListeners);
}
int size = configurationListeners.size();
for (int i = 0; i < size; i++) {
- configurationListeners.valueAt(i).onChange(configuration);
+ configurationListeners.valueAt(i).onChange();
}
}
diff --git a/core/java/android/companion/TEST_MAPPING b/core/java/android/companion/TEST_MAPPING
new file mode 100644
index 000000000000..63f54fa35158
--- /dev/null
+++ b/core/java/android/companion/TEST_MAPPING
@@ -0,0 +1,12 @@
+{
+ "presubmit": [
+ {
+ "name": "CtsOsTestCases",
+ "options": [
+ {
+ "include-filter": "android.os.cts.CompanionDeviceManagerTest"
+ }
+ ]
+ }
+ ]
+}
diff --git a/core/java/android/content/Context.java b/core/java/android/content/Context.java
index 52b04675b7a5..98f78878ec15 100644
--- a/core/java/android/content/Context.java
+++ b/core/java/android/content/Context.java
@@ -4195,6 +4195,17 @@ public abstract class Context {
public static final String AUDIO_SERVICE = "audio";
/**
+ * Use with {@link #getSystemService(String)} to retrieve a {@link
+ * android.media.MediaTranscodeManager} for transcoding media.
+ *
+ * @hide
+ * @see #getSystemService(String)
+ * @see android.media.MediaTranscodeManager
+ */
+ @SystemApi
+ public static final String MEDIA_TRANSCODING_SERVICE = "media_transcoding";
+
+ /**
* AuthService orchestrates biometric and PIN/pattern/password authentication.
*
* BiometricService was split into two services, AuthService and BiometricService, where
diff --git a/core/java/android/content/pm/FileChecksum.aidl b/core/java/android/content/pm/FileChecksum.aidl
new file mode 100644
index 000000000000..109f211033c1
--- /dev/null
+++ b/core/java/android/content/pm/FileChecksum.aidl
@@ -0,0 +1,20 @@
+/*
+ * 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.content.pm;
+
+parcelable FileChecksum;
+
diff --git a/core/java/android/content/pm/FileChecksum.java b/core/java/android/content/pm/FileChecksum.java
new file mode 100644
index 000000000000..55430c2b877b
--- /dev/null
+++ b/core/java/android/content/pm/FileChecksum.java
@@ -0,0 +1,238 @@
+/*
+ * 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.content.pm;
+
+import android.annotation.NonNull;
+import android.annotation.Nullable;
+import android.content.IntentSender;
+import android.os.Parcel;
+import android.os.Parcelable;
+
+import com.android.internal.util.DataClass;
+
+import java.io.ByteArrayInputStream;
+import java.io.InputStream;
+import java.security.cert.Certificate;
+import java.security.cert.CertificateEncodingException;
+import java.security.cert.CertificateException;
+import java.security.cert.CertificateFactory;
+import java.security.cert.X509Certificate;
+import java.util.List;
+
+/**
+ * A typed checksum.
+ *
+ * @see PackageManager#getChecksums(String, boolean, int, List, IntentSender)
+ */
+@DataClass(genHiddenConstructor = true)
+public final class FileChecksum implements Parcelable {
+ /**
+ * Checksum for which split. Null indicates base.apk.
+ */
+ private final @Nullable String mSplitName;
+ /**
+ * Checksum kind.
+ */
+ private final @PackageManager.FileChecksumKind int mKind;
+ /**
+ * Checksum value.
+ */
+ private final @NonNull byte[] mValue;
+ /**
+ * For Installer-provided checksums, certificate of the Installer/AppStore.
+ */
+ private final @Nullable byte[] mSourceCertificate;
+
+ /**
+ * Constructor, internal use only
+ *
+ * @hide
+ */
+ public FileChecksum(@Nullable String splitName, @PackageManager.FileChecksumKind int kind,
+ @NonNull byte[] value) {
+ this(splitName, kind, value, (byte[]) null);
+ }
+
+ /**
+ * Constructor, internal use only
+ *
+ * @hide
+ */
+ public FileChecksum(@Nullable String splitName, @PackageManager.FileChecksumKind int kind,
+ @NonNull byte[] value, @Nullable Certificate sourceCertificate)
+ throws CertificateEncodingException {
+ this(splitName, kind, value,
+ (sourceCertificate != null) ? sourceCertificate.getEncoded() : null);
+ }
+
+ /**
+ * Certificate of the source of this checksum.
+ * @throws CertificateException in case when certificate can't be re-created from serialized
+ * data.
+ */
+ public @Nullable Certificate getSourceCertificate() throws CertificateException {
+ if (mSourceCertificate == null) {
+ return null;
+ }
+ final CertificateFactory cf = CertificateFactory.getInstance("X.509");
+ final InputStream is = new ByteArrayInputStream(mSourceCertificate);
+ final X509Certificate cert = (X509Certificate) cf.generateCertificate(is);
+ return cert;
+ }
+
+
+
+ // Code below generated by codegen v1.0.15.
+ //
+ // DO NOT MODIFY!
+ // CHECKSTYLE:OFF Generated code
+ //
+ // To regenerate run:
+ // $ codegen $ANDROID_BUILD_TOP/frameworks/base/core/java/android/content/pm/FileChecksum.java
+ //
+ // To exclude the generated code from IntelliJ auto-formatting enable (one-time):
+ // Settings > Editor > Code Style > Formatter Control
+ //@formatter:off
+
+
+ /**
+ * Creates a new FileChecksum.
+ *
+ * @param splitName
+ * Checksum for which split. Null indicates base.apk.
+ * @param kind
+ * Checksum kind.
+ * @param value
+ * Checksum value.
+ * @param sourceCertificate
+ * For Installer-provided checksums, certificate of the Installer/AppStore.
+ * @hide
+ */
+ @DataClass.Generated.Member
+ public FileChecksum(
+ @Nullable String splitName,
+ @PackageManager.FileChecksumKind int kind,
+ @NonNull byte[] value,
+ @Nullable byte[] sourceCertificate) {
+ this.mSplitName = splitName;
+ this.mKind = kind;
+ com.android.internal.util.AnnotationValidations.validate(
+ PackageManager.FileChecksumKind.class, null, mKind);
+ this.mValue = value;
+ com.android.internal.util.AnnotationValidations.validate(
+ NonNull.class, null, mValue);
+ this.mSourceCertificate = sourceCertificate;
+
+ // onConstructed(); // You can define this method to get a callback
+ }
+
+ /**
+ * Checksum for which split. Null indicates base.apk.
+ */
+ @DataClass.Generated.Member
+ public @Nullable String getSplitName() {
+ return mSplitName;
+ }
+
+ /**
+ * Checksum kind.
+ */
+ @DataClass.Generated.Member
+ public @PackageManager.FileChecksumKind int getKind() {
+ return mKind;
+ }
+
+ /**
+ * Checksum value.
+ */
+ @DataClass.Generated.Member
+ public @NonNull byte[] getValue() {
+ return mValue;
+ }
+
+ @Override
+ @DataClass.Generated.Member
+ public void writeToParcel(@NonNull Parcel dest, int flags) {
+ // You can override field parcelling by defining methods like:
+ // void parcelFieldName(Parcel dest, int flags) { ... }
+
+ byte flg = 0;
+ if (mSplitName != null) flg |= 0x1;
+ if (mSourceCertificate != null) flg |= 0x8;
+ dest.writeByte(flg);
+ if (mSplitName != null) dest.writeString(mSplitName);
+ dest.writeInt(mKind);
+ dest.writeByteArray(mValue);
+ if (mSourceCertificate != null) dest.writeByteArray(mSourceCertificate);
+ }
+
+ @Override
+ @DataClass.Generated.Member
+ public int describeContents() { return 0; }
+
+ /** @hide */
+ @SuppressWarnings({"unchecked", "RedundantCast"})
+ @DataClass.Generated.Member
+ /* package-private */ FileChecksum(@NonNull Parcel in) {
+ // You can override field unparcelling by defining methods like:
+ // static FieldType unparcelFieldName(Parcel in) { ... }
+
+ byte flg = in.readByte();
+ String splitName = (flg & 0x1) == 0 ? null : in.readString();
+ int kind = in.readInt();
+ byte[] value = in.createByteArray();
+ byte[] sourceCertificate = (flg & 0x8) == 0 ? null : in.createByteArray();
+
+ this.mSplitName = splitName;
+ this.mKind = kind;
+ com.android.internal.util.AnnotationValidations.validate(
+ PackageManager.FileChecksumKind.class, null, mKind);
+ this.mValue = value;
+ com.android.internal.util.AnnotationValidations.validate(
+ NonNull.class, null, mValue);
+ this.mSourceCertificate = sourceCertificate;
+
+ // onConstructed(); // You can define this method to get a callback
+ }
+
+ @DataClass.Generated.Member
+ public static final @NonNull Parcelable.Creator<FileChecksum> CREATOR
+ = new Parcelable.Creator<FileChecksum>() {
+ @Override
+ public FileChecksum[] newArray(int size) {
+ return new FileChecksum[size];
+ }
+
+ @Override
+ public FileChecksum createFromParcel(@NonNull Parcel in) {
+ return new FileChecksum(in);
+ }
+ };
+
+ @DataClass.Generated(
+ time = 1598322801861L,
+ codegenVersion = "1.0.15",
+ sourceFile = "frameworks/base/core/java/android/content/pm/FileChecksum.java",
+ inputSignatures = "private final @android.annotation.Nullable java.lang.String mSplitName\nprivate final @android.content.pm.PackageManager.FileChecksumKind int mKind\nprivate final @android.annotation.NonNull byte[] mValue\nprivate final @android.annotation.Nullable byte[] mSourceCertificate\npublic @android.annotation.Nullable java.security.cert.Certificate getSourceCertificate()\nclass FileChecksum extends java.lang.Object implements [android.os.Parcelable]\n@com.android.internal.util.DataClass(genHiddenConstructor=true)")
+ @Deprecated
+ private void __metadata() {}
+
+
+ //@formatter:on
+ // End of generated code
+
+}
diff --git a/core/java/android/content/pm/IPackageManager.aidl b/core/java/android/content/pm/IPackageManager.aidl
index 6a8dd81051eb..1f8cee25be51 100644
--- a/core/java/android/content/pm/IPackageManager.aidl
+++ b/core/java/android/content/pm/IPackageManager.aidl
@@ -743,6 +743,8 @@ interface IPackageManager {
void notifyPackagesReplacedReceived(in String[] packages);
+ void getChecksums(in String packageName, boolean includeSplits, int optional, int required, in List trustedInstallers, in IntentSender statusReceiver, int userId);
+
//------------------------------------------------------------------------
//
// The following binder interfaces have been moved to IPermissionManager
diff --git a/core/java/android/content/pm/PackageInstaller.java b/core/java/android/content/pm/PackageInstaller.java
index b7c3289b6e66..e6ea04433114 100644
--- a/core/java/android/content/pm/PackageInstaller.java
+++ b/core/java/android/content/pm/PackageInstaller.java
@@ -2512,12 +2512,16 @@ public class PackageInstaller {
}
/**
- * If {@link SessionParams#setInstallAsInstantApp(boolean)} was called with {@code true},
- * return true. If it was called with {@code false} or if it was not called return false.
+ * Get if this session is to be installed as Instant Apps.
*
- * @hide
+ * @param isInstantApp an unused parameter and is ignored.
+ * @return {@code true} if {@link SessionParams#setInstallAsInstantApp(boolean)} was called
+ * with {@code true}; {@code false} if it was called with {@code false} or if it was not
+ * called.
*
* @see #getInstallAsFullApp
+ *
+ * @hide
*/
@SystemApi
public boolean getInstallAsInstantApp(boolean isInstantApp) {
@@ -2525,12 +2529,16 @@ public class PackageInstaller {
}
/**
- * If {@link SessionParams#setInstallAsInstantApp(boolean)} was called with {@code false},
- * return true. If it was called with {@code true} or if it was not called return false.
+ * Get if this session is to be installed as full apps.
*
- * @hide
+ * @param isInstantApp an unused parameter and is ignored.
+ * @return {@code true} if {@link SessionParams#setInstallAsInstantApp(boolean)} was called
+ * with {@code false}; {code false} if it was called with {@code true} or if it was not
+ * called.
*
* @see #getInstallAsInstantApp
+ *
+ * @hide
*/
@SystemApi
public boolean getInstallAsFullApp(boolean isInstantApp) {
diff --git a/core/java/android/content/pm/PackageManager.java b/core/java/android/content/pm/PackageManager.java
index 7b2955db3318..d2395ec9f69f 100644
--- a/core/java/android/content/pm/PackageManager.java
+++ b/core/java/android/content/pm/PackageManager.java
@@ -79,8 +79,11 @@ import com.android.internal.util.ArrayUtils;
import dalvik.system.VMRuntime;
import java.io.File;
+import java.io.IOException;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
+import java.security.cert.Certificate;
+import java.security.cert.CertificateEncodingException;
import java.util.Collections;
import java.util.List;
import java.util.Locale;
@@ -785,7 +788,6 @@ public abstract class PackageManager {
INSTALL_ENABLE_ROLLBACK,
INSTALL_ALLOW_DOWNGRADE,
INSTALL_STAGED,
- INSTALL_DRY_RUN,
})
@Retention(RetentionPolicy.SOURCE)
public @interface InstallFlags {}
@@ -963,14 +965,6 @@ public abstract class PackageManager {
*/
public static final int INSTALL_STAGED = 0x00200000;
- /**
- * Flag parameter for {@link #installPackage} to indicate that package should only be verified
- * but not installed.
- *
- * @hide
- */
- public static final int INSTALL_DRY_RUN = 0x00800000;
-
/** @hide */
@IntDef(flag = true, value = {
DONT_KILL_APP,
@@ -1161,7 +1155,8 @@ public abstract class PackageManager {
/**
* Installation return code: this is passed in the {@link PackageInstaller#EXTRA_LEGACY_STATUS}
- * if the new package uses a shared library that is not available.
+ * when the package being replaced is a system app and the caller didn't provide the
+ * {@link #DELETE_SYSTEM_APP} flag.
*
* @hide
*/
@@ -3305,6 +3300,13 @@ public abstract class PackageManager {
public static final String EXTRA_FAILURE_EXISTING_PERMISSION
= "android.content.pm.extra.FAILURE_EXISTING_PERMISSION";
+ /**
+ * Extra field name for the ID of a package pending verification. Passed to
+ * a package verifier and is used to call back to
+ * @see #getChecksums
+ */
+ public static final String EXTRA_CHECKSUMS = "android.content.pm.extra.CHECKSUMS";
+
/**
* Permission flag: The permission is set in its current state
* by the user and apps can still request it at runtime.
@@ -7842,6 +7844,114 @@ public abstract class PackageManager {
}
/**
+ * Root SHA256 hash of a 4K Merkle tree computed over all file bytes.
+ * <a href="https://source.android.com/security/apksigning/v4">See APK Signature Scheme V4</a>.
+ * <a href="https://git.kernel.org/pub/scm/fs/fscrypt/fscrypt.git/tree/Documentation/filesystems/fsverity.rst">See fs-verity</a>.
+ *
+ * @see #getChecksums
+ */
+ public static final int WHOLE_MERKLE_ROOT_4K_SHA256 = 0x00000001;
+
+ /**
+ * MD5 hash computed over all file bytes.
+ *
+ * @see #getChecksums
+ */
+ public static final int WHOLE_MD5 = 0x00000002;
+
+ /**
+ * SHA1 hash computed over all file bytes.
+ *
+ * @see #getChecksums
+ */
+ public static final int WHOLE_SHA1 = 0x00000004;
+
+ /**
+ * SHA256 hash computed over all file bytes.
+ *
+ * @see #getChecksums
+ */
+ public static final int WHOLE_SHA256 = 0x00000008;
+
+ /**
+ * SHA512 hash computed over all file bytes.
+ *
+ * @see #getChecksums
+ */
+ public static final int WHOLE_SHA512 = 0x00000010;
+
+ /**
+ * Root SHA256 hash of a 1M Merkle tree computed over protected content.
+ * Excludes signing block.
+ * <a href="https://source.android.com/security/apksigning/v2">See APK Signature Scheme V2</a>.
+ *
+ * @see #getChecksums
+ */
+ public static final int PARTIAL_MERKLE_ROOT_1M_SHA256 = 0x00000020;
+
+ /**
+ * Root SHA512 hash of a 1M Merkle tree computed over protected content.
+ * Excludes signing block.
+ * <a href="https://source.android.com/security/apksigning/v2">See APK Signature Scheme V2</a>.
+ *
+ * @see #getChecksums
+ */
+ public static final int PARTIAL_MERKLE_ROOT_1M_SHA512 = 0x00000040;
+
+ /** @hide */
+ @IntDef(flag = true, prefix = {"WHOLE_", "PARTIAL_"}, value = {
+ WHOLE_MERKLE_ROOT_4K_SHA256,
+ WHOLE_MD5,
+ WHOLE_SHA1,
+ WHOLE_SHA256,
+ WHOLE_SHA512,
+ PARTIAL_MERKLE_ROOT_1M_SHA256,
+ PARTIAL_MERKLE_ROOT_1M_SHA512,
+ })
+ @Retention(RetentionPolicy.SOURCE)
+ public @interface FileChecksumKind {}
+
+ /**
+ * Trust any Installer to provide checksums for the package.
+ * @see #getChecksums
+ */
+ public static final @Nullable List<Certificate> TRUST_ALL = null;
+
+ /**
+ * Don't trust any Installer to provide checksums for the package.
+ * This effectively disables optimized Installer-enforced checksums.
+ * @see #getChecksums
+ */
+ public static final @NonNull List<Certificate> TRUST_NONE = Collections.emptyList();
+
+ /**
+ * Returns the checksums for APKs within a package.
+ *
+ * By default returns all readily available checksums:
+ * - enforced by platform,
+ * - enforced by installer.
+ * If caller needs a specific checksum kind, they can specify it as required.
+ *
+ * @param packageName whose checksums to return.
+ * @param includeSplits whether to include checksums for non-base splits.
+ * @param required explicitly request the checksum kinds. Will incur significant
+ * CPU/memory/disk usage.
+ * @param trustedInstallers for checksums enforced by Installer, which ones to be trusted.
+ * {@link #TRUST_ALL} will return checksums from any Installer,
+ * {@link #TRUST_NONE} disables optimized Installer-enforced checksums.
+ * @param statusReceiver called once when the results are available as
+ * {@link #EXTRA_CHECKSUMS} of type FileChecksum[].
+ * @throws CertificateEncodingException if an encoding error occurs for trustedInstallers.
+ * @throws NameNotFoundException if a package with the given name cannot be found on the system.
+ */
+ public void getChecksums(@NonNull String packageName, boolean includeSplits,
+ @FileChecksumKind int required, @Nullable List<Certificate> trustedInstallers,
+ @NonNull IntentSender statusReceiver)
+ throws CertificateEncodingException, IOException, NameNotFoundException {
+ throw new UnsupportedOperationException("getChecksums not implemented in subclass");
+ }
+
+ /**
* @return the default text classifier package name, or null if there's none.
*
* @hide
diff --git a/core/java/android/content/pm/RegisteredServicesCache.java b/core/java/android/content/pm/RegisteredServicesCache.java
index bd909c7a3f59..192470e964e0 100644
--- a/core/java/android/content/pm/RegisteredServicesCache.java
+++ b/core/java/android/content/pm/RegisteredServicesCache.java
@@ -43,11 +43,11 @@ import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.util.ArrayUtils;
import com.android.internal.util.FastXmlSerializer;
-import libcore.io.IoUtils;
-
import com.google.android.collect.Lists;
import com.google.android.collect.Maps;
+import libcore.io.IoUtils;
+
import org.xmlpull.v1.XmlPullParser;
import org.xmlpull.v1.XmlPullParserException;
import org.xmlpull.v1.XmlSerializer;
@@ -793,7 +793,7 @@ public abstract class RegisteredServicesCache<V> {
@VisibleForTesting
protected List<UserInfo> getUsers() {
- return UserManager.get(mContext).getUsers(true);
+ return UserManager.get(mContext).getAliveUsers();
}
@VisibleForTesting
diff --git a/core/java/android/inputmethodservice/InputMethodService.java b/core/java/android/inputmethodservice/InputMethodService.java
index 7250801eec81..55afefed734e 100644
--- a/core/java/android/inputmethodservice/InputMethodService.java
+++ b/core/java/android/inputmethodservice/InputMethodService.java
@@ -1210,15 +1210,19 @@ public class InputMethodService extends AbstractInputMethodService {
mWindow.getWindow().getAttributes().setFitInsetsIgnoringVisibility(true);
// IME layout should always be inset by navigation bar, no matter its current visibility,
- // unless automotive requests it, since automotive may hide the navigation bar.
+ // unless automotive requests it. Automotive devices may request the navigation bar to be
+ // hidden when the IME shows up (controlled via config_automotiveHideNavBarForKeyboard)
+ // in order to maximize the visible screen real estate. When this happens, the IME window
+ // should animate from the bottom of the screen to reduce the jank that happens from the
+ // lack of synchronization between the bottom system window and the IME window.
+ if (mIsAutomotive && mAutomotiveHideNavBarForKeyboard) {
+ mWindow.getWindow().setDecorFitsSystemWindows(false);
+ }
mWindow.getWindow().getDecorView().setOnApplyWindowInsetsListener(
(v, insets) -> v.onApplyWindowInsets(
new WindowInsets.Builder(insets).setInsets(
navigationBars(),
- mIsAutomotive && mAutomotiveHideNavBarForKeyboard
- ? android.graphics.Insets.NONE
- : insets.getInsetsIgnoringVisibility(navigationBars())
- )
+ insets.getInsetsIgnoringVisibility(navigationBars()))
.build()));
// For ColorView in DecorView to work, FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS needs to be set
diff --git a/core/java/android/inputmethodservice/TEST_MAPPING b/core/java/android/inputmethodservice/TEST_MAPPING
new file mode 100644
index 000000000000..0ccd75dcbdce
--- /dev/null
+++ b/core/java/android/inputmethodservice/TEST_MAPPING
@@ -0,0 +1,7 @@
+{
+ "imports": [
+ {
+ "path": "frameworks/base/core/java/android/view/inputmethod"
+ }
+ ]
+}
diff --git a/core/java/android/net/SocketKeepalive.java b/core/java/android/net/SocketKeepalive.java
index 46aef10258d9..a7dce18a4ff9 100644
--- a/core/java/android/net/SocketKeepalive.java
+++ b/core/java/android/net/SocketKeepalive.java
@@ -85,6 +85,12 @@ public abstract class SocketKeepalive implements AutoCloseable {
public static final int ERROR_INVALID_SOCKET = -25;
/** The target socket is not idle. */
public static final int ERROR_SOCKET_NOT_IDLE = -26;
+ /**
+ * The stop reason is uninitialized. This should only be internally used as initial state
+ * of stop reason, instead of propagating to application.
+ * @hide
+ */
+ public static final int ERROR_STOP_REASON_UNINITIALIZED = -27;
/** The device does not support this request. */
public static final int ERROR_UNSUPPORTED = -30;
diff --git a/core/java/android/os/BinderProxy.java b/core/java/android/os/BinderProxy.java
index 683993f762c0..0185ba444ca4 100644
--- a/core/java/android/os/BinderProxy.java
+++ b/core/java/android/os/BinderProxy.java
@@ -18,6 +18,7 @@ package android.os;
import android.annotation.NonNull;
import android.annotation.Nullable;
+import android.app.ActivityManager;
import android.app.AppOpsManager;
import android.util.Log;
import android.util.SparseIntArray;
@@ -255,7 +256,12 @@ public final class BinderProxy implements IBinder {
// out of system_server to all processes hosting binder objects it holds a reference to;
// since some of those processes might be frozen, we don't want to block here
// forever. Disable the freezer.
- Process.enableFreezer(false);
+ try {
+ ActivityManager.getService().enableAppFreezer(false);
+ } catch (RemoteException e) {
+ Log.e(Binder.TAG, "RemoteException while disabling app freezer");
+ }
+
for (WeakReference<BinderProxy> weakRef : proxiesToQuery) {
BinderProxy bp = weakRef.get();
String key;
@@ -278,7 +284,11 @@ public final class BinderProxy implements IBinder {
counts.put(key, i + 1);
}
}
- Process.enableFreezer(true);
+ try {
+ ActivityManager.getService().enableAppFreezer(true);
+ } catch (RemoteException e) {
+ Log.e(Binder.TAG, "RemoteException while re-enabling app freezer");
+ }
Map.Entry<String, Integer>[] sorted = counts.entrySet().toArray(
new Map.Entry[counts.size()]);
diff --git a/core/java/android/os/Process.java b/core/java/android/os/Process.java
index a4077fbee892..efea9537c4cf 100644
--- a/core/java/android/os/Process.java
+++ b/core/java/android/os/Process.java
@@ -947,7 +947,7 @@ public class Process {
/**
* Enable or disable the freezer. When enable == false all frozen processes are unfrozen,
- * but aren't removed from the freezer. Processes can still be added or removed
+ * but aren't removed from the freezer. While in this state, processes can be added or removed
* by using setProcessFrozen, but they won't actually be frozen until the freezer is enabled
* again. If enable == true the freezer is enabled again, and all processes
* in the freezer (including the ones added while the freezer was disabled) are frozen.
diff --git a/core/java/android/os/UserManager.java b/core/java/android/os/UserManager.java
index 2465b0e41876..81ffefd05b19 100644
--- a/core/java/android/os/UserManager.java
+++ b/core/java/android/os/UserManager.java
@@ -43,7 +43,6 @@ import android.content.IntentFilter;
import android.content.IntentSender;
import android.content.pm.UserInfo;
import android.content.pm.UserInfo.UserInfoFlag;
-import android.content.res.Configuration;
import android.content.res.Resources;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
@@ -1294,7 +1293,7 @@ public class UserManager {
* in {@link UserManager} & {@link DevicePolicyManager}.
* Note: This is slightly different from the real set of user restrictions listed in {@link
* com.android.server.pm.UserRestrictionsUtils#USER_RESTRICTIONS}. For example
- * {@link #KEY_RESTRICTIONS_PENDING} is not a real user restriction, but is a a legitimate
+ * {@link #KEY_RESTRICTIONS_PENDING} is not a real user restriction, but is a legitimate
* value that can be passed into {@link #hasUserRestriction(String)}.
* @hide
*/
@@ -3174,28 +3173,55 @@ public class UserManager {
}
/**
- * Returns information for all users on this device, including ones marked for deletion.
- * To retrieve only users that are alive, use {@link #getUsers(boolean)}.
+ * Returns information for all fully-created users on this device, including ones marked for
+ * deletion.
+ *
+ * <p>To retrieve only users that are not marked for deletion, use {@link #getAliveUsers()}.
+ *
+ * <p>To retrieve *all* users (including partial and pre-created users), use
+ * {@link #getUsers(boolean, boolean, boolean)) getUsers(false, false, false)}.
+ *
+ * <p>To retrieve a more specific list of users, use
+ * {@link #getUsers(boolean, boolean, boolean)}.
+ *
+ * @return the list of users that were created.
*
- * @return the list of users that exist on the device.
* @hide
*/
@UnsupportedAppUsage
@RequiresPermission(android.Manifest.permission.MANAGE_USERS)
public List<UserInfo> getUsers() {
- return getUsers(/* excludeDying= */ false);
+ return getUsers(/*excludePartial= */ true, /* excludeDying= */ false,
+ /* excludePreCreated= */ true);
}
/**
- * Returns information for all users on this device. Requires
- * {@link android.Manifest.permission#MANAGE_USERS} permission.
+ * Returns information for all "usable" users on this device (i.e, it excludes users that are
+ * marked for deletion, pre-created users, etc...).
+ *
+ * <p>To retrieve all fully-created users, use {@link #getUsers()}.
+ *
+ * <p>To retrieve a more specific list of users, use
+ * {@link #getUsers(boolean, boolean, boolean)}.
*
- * @param excludeDying specify if the list should exclude users being
- * removed.
* @return the list of users that were created.
* @hide
*/
+ @RequiresPermission(android.Manifest.permission.MANAGE_USERS)
+ public @NonNull List<UserInfo> getAliveUsers() {
+ return getUsers(/*excludePartial= */ true, /* excludeDying= */ true,
+ /* excludePreCreated= */ true);
+ }
+
+ /**
+ * @deprecated use {@link #getAliveUsers()} for {@code getUsers(true)}, or
+ * {@link #getUsers()} for @code getUsers(false)}.
+ *
+ * @hide
+ */
+ @Deprecated
@UnsupportedAppUsage
+ @RequiresPermission(android.Manifest.permission.MANAGE_USERS)
public @NonNull List<UserInfo> getUsers(boolean excludeDying) {
return getUsers(/*excludePartial= */ true, excludeDying,
/* excludePreCreated= */ true);
@@ -3226,7 +3252,8 @@ public class UserManager {
@SystemApi
@RequiresPermission(android.Manifest.permission.MANAGE_USERS)
public @NonNull List<UserHandle> getUserHandles(boolean excludeDying) {
- List<UserInfo> users = getUsers(excludeDying);
+ List<UserInfo> users = getUsers(/* excludePartial= */ true, excludeDying,
+ /* excludePreCreated= */ true);
List<UserHandle> result = new ArrayList<>(users.size());
for (UserInfo user : users) {
result.add(user.getUserHandle());
@@ -3244,7 +3271,8 @@ public class UserManager {
@SystemApi
@RequiresPermission(android.Manifest.permission.MANAGE_USERS)
public long[] getSerialNumbersOfUsers(boolean excludeDying) {
- List<UserInfo> users = getUsers(excludeDying);
+ List<UserInfo> users = getUsers(/* excludePartial= */ true, excludeDying,
+ /* excludePreCreated= */ true);
long[] result = new long[users.size()];
for (int i = 0; i < result.length; i++) {
result[i] = users.get(i).serialNumber;
@@ -3310,7 +3338,7 @@ public class UserManager {
public boolean canAddMoreUsers() {
// TODO(b/142482943): UMS has different logic, excluding Demo and Profile from counting. Why
// not here? The logic is inconsistent. See UMS.canAddMoreManagedProfiles
- final List<UserInfo> users = getUsers(true);
+ final List<UserInfo> users = getAliveUsers();
final int totalUserCount = users.size();
int aliveUserCount = 0;
for (int i = 0; i < totalUserCount; i++) {
@@ -4118,7 +4146,7 @@ public class UserManager {
/** Returns whether there are any users (other than the current user) to which to switch. */
private boolean areThereUsersToWhichToSwitch() {
- final List<UserInfo> users = getUsers(true);
+ final List<UserInfo> users = getAliveUsers();
if (users == null) {
return false;
}
diff --git a/core/java/android/os/image/DynamicSystemManager.java b/core/java/android/os/image/DynamicSystemManager.java
index 17851adac51b..7f01cad940ec 100644
--- a/core/java/android/os/image/DynamicSystemManager.java
+++ b/core/java/android/os/image/DynamicSystemManager.java
@@ -155,6 +155,19 @@ public class DynamicSystemManager {
}
}
/**
+ * Complete the current partition installation.
+ *
+ * @return true if the partition installation completes without error.
+ */
+ @RequiresPermission(android.Manifest.permission.MANAGE_DYNAMIC_SYSTEM)
+ public boolean closePartition() {
+ try {
+ return mService.closePartition();
+ } catch (RemoteException e) {
+ throw new RuntimeException(e.toString());
+ }
+ }
+ /**
* Finish a previously started installation. Installations without a cooresponding
* finishInstallation() will be cleaned up during device boot.
*/
diff --git a/core/java/android/os/image/IDynamicSystemService.aidl b/core/java/android/os/image/IDynamicSystemService.aidl
index a1f927266de3..df0a69b47225 100644
--- a/core/java/android/os/image/IDynamicSystemService.aidl
+++ b/core/java/android/os/image/IDynamicSystemService.aidl
@@ -39,6 +39,13 @@ interface IDynamicSystemService
boolean createPartition(@utf8InCpp String name, long size, boolean readOnly);
/**
+ * Complete the current partition installation.
+ *
+ * @return true if the partition installation completes without error.
+ */
+ boolean closePartition();
+
+ /**
* Finish a previously started installation. Installations without
* a cooresponding finishInstallation() will be cleaned up during device boot.
*/
diff --git a/core/java/android/os/incremental/IIncrementalService.aidl b/core/java/android/os/incremental/IIncrementalService.aidl
index 61e6a05fce37..f351c7df8d5d 100644
--- a/core/java/android/os/incremental/IIncrementalService.aidl
+++ b/core/java/android/os/incremental/IIncrementalService.aidl
@@ -90,9 +90,18 @@ interface IIncrementalService {
int unlink(int storageId, in @utf8InCpp String path);
/**
- * Checks if a file's certain range is loaded. File is specified by its path.
+ * Checks if a file is fully loaded. File is specified by its path.
+ * 0 - fully loaded
+ * >0 - certain pages missing
+ * <0 - -errcode
*/
- boolean isFileRangeLoaded(int storageId, in @utf8InCpp String path, long start, long end);
+ int isFileFullyLoaded(int storageId, in @utf8InCpp String path);
+
+ /**
+ * Returns overall loading progress of all the files on a storage, progress value between [0,1].
+ * Returns a negative value on error.
+ */
+ float getLoadingProgress(int storageId);
/**
* Reads the metadata of a file. File is specified by either its path or 16 byte id.
diff --git a/core/java/android/os/incremental/IncrementalStorage.java b/core/java/android/os/incremental/IncrementalStorage.java
index ca6114f29b9c..ed386f79882f 100644
--- a/core/java/android/os/incremental/IncrementalStorage.java
+++ b/core/java/android/os/incremental/IncrementalStorage.java
@@ -309,24 +309,35 @@ public final class IncrementalStorage {
* @param path The relative path of the file.
* @return True if the file is fully loaded.
*/
- public boolean isFileFullyLoaded(@NonNull String path) {
- return isFileRangeLoaded(path, 0, -1);
+ public boolean isFileFullyLoaded(@NonNull String path) throws IOException {
+ try {
+ int res = mService.isFileFullyLoaded(mId, path);
+ if (res < 0) {
+ throw new IOException("isFileFullyLoaded() failed, errno " + -res);
+ }
+ return res == 0;
+ } catch (RemoteException e) {
+ e.rethrowFromSystemServer();
+ return false;
+ }
}
/**
- * Checks whether a range in a file if loaded.
+ * Returns the loading progress of a storage
*
- * @param path The relative path of the file.
- * @param start The starting offset of the range.
- * @param end The ending offset of the range.
- * @return True if the file is fully loaded.
+ * @return progress value between [0, 1].
*/
- public boolean isFileRangeLoaded(@NonNull String path, long start, long end) {
+ public float getLoadingProgress() throws IOException {
try {
- return mService.isFileRangeLoaded(mId, path, start, end);
+ final float res = mService.getLoadingProgress(mId);
+ if (res < 0) {
+ throw new IOException(
+ "getLoadingProgress() failed at querying loading progress, errno " + -res);
+ }
+ return res;
} catch (RemoteException e) {
e.rethrowFromSystemServer();
- return false;
+ return 0;
}
}
diff --git a/core/java/android/preference/DialogPreference.java b/core/java/android/preference/DialogPreference.java
index dfdb57c4e3f8..fb7b2320915c 100644
--- a/core/java/android/preference/DialogPreference.java
+++ b/core/java/android/preference/DialogPreference.java
@@ -36,8 +36,6 @@ import android.text.TextUtils;
import android.util.AttributeSet;
import android.view.LayoutInflater;
import android.view.View;
-import android.view.Window;
-import android.view.WindowManager;
import android.widget.TextView;
/**
@@ -337,9 +335,6 @@ public abstract class DialogPreference extends Preference implements
if (state != null) {
dialog.onRestoreInstanceState(state);
}
- if (needInputMethod()) {
- requestInputMethod(dialog);
- }
dialog.setOnShowListener(new DialogInterface.OnShowListener() {
@Override
public void onShow(DialogInterface dialog) {
@@ -380,24 +375,6 @@ public abstract class DialogPreference extends Preference implements
}
/**
- * Returns whether the preference needs to display a soft input method when the dialog
- * is displayed. Default is false. Subclasses should override this method if they need
- * the soft input method brought up automatically.
- * @hide
- */
- protected boolean needInputMethod() {
- return false;
- }
-
- /**
- * Sets the required flags on the dialog window to enable input method window to show up.
- */
- private void requestInputMethod(Dialog dialog) {
- Window window = dialog.getWindow();
- window.setSoftInputMode(WindowManager.LayoutParams.SOFT_INPUT_STATE_ALWAYS_VISIBLE);
- }
-
- /**
* Creates the content view for the dialog (if a custom content view is
* required). By default, it inflates the dialog layout resource if it is
* set.
diff --git a/core/java/android/preference/EditTextPreference.java b/core/java/android/preference/EditTextPreference.java
index af6f18416870..75c5102d04f5 100644
--- a/core/java/android/preference/EditTextPreference.java
+++ b/core/java/android/preference/EditTextPreference.java
@@ -21,6 +21,7 @@ import android.compat.annotation.UnsupportedAppUsage;
import android.content.Context;
import android.content.SharedPreferences;
import android.content.res.TypedArray;
+import android.os.Bundle;
import android.os.Parcel;
import android.os.Parcelable;
import android.text.TextUtils;
@@ -28,6 +29,7 @@ import android.util.AttributeSet;
import android.view.View;
import android.view.ViewGroup;
import android.view.ViewParent;
+import android.view.WindowInsets;
import android.widget.EditText;
/**
@@ -123,7 +125,7 @@ public class EditTextPreference extends DialogPreference {
EditText editText = mEditText;
editText.setText(getText());
-
+
ViewParent oldParent = editText.getParent();
if (oldParent != view) {
if (oldParent != null) {
@@ -133,6 +135,13 @@ public class EditTextPreference extends DialogPreference {
}
}
+ @Override
+ protected void showDialog(Bundle state) {
+ super.showDialog(state);
+ mEditText.requestFocus();
+ mEditText.getWindowInsetsController().show(WindowInsets.Type.ime());
+ }
+
/**
* Adds the EditText widget of this preference to the dialog's view.
*
@@ -183,13 +192,6 @@ public class EditTextPreference extends DialogPreference {
return mEditText;
}
- /** @hide */
- @Override
- protected boolean needInputMethod() {
- // We want the input method to show, if possible, when dialog is displayed
- return true;
- }
-
@Override
protected Parcelable onSaveInstanceState() {
final Parcelable superState = super.onSaveInstanceState();
diff --git a/core/java/android/preference/OWNERS b/core/java/android/preference/OWNERS
index d20511fcfdf2..827134e8fc9d 100644
--- a/core/java/android/preference/OWNERS
+++ b/core/java/android/preference/OWNERS
@@ -1,2 +1,3 @@
+lpf@google.com
pavlis@google.com
clarabayarri@google.com
diff --git a/core/java/android/provider/CallLog.java b/core/java/android/provider/CallLog.java
index 276f16216b4d..c3b6d8e2cfe3 100644
--- a/core/java/android/provider/CallLog.java
+++ b/core/java/android/provider/CallLog.java
@@ -870,7 +870,7 @@ public class CallLog {
// Otherwise, insert to all other users that are running and unlocked.
- final List<UserInfo> users = userManager.getUsers(true);
+ final List<UserInfo> users = userManager.getAliveUsers();
final int count = users.size();
for (int i = 0; i < count; i++) {
diff --git a/core/java/android/provider/DocumentsProvider.java b/core/java/android/provider/DocumentsProvider.java
index 327bca268a7b..d55fc511fc77 100644
--- a/core/java/android/provider/DocumentsProvider.java
+++ b/core/java/android/provider/DocumentsProvider.java
@@ -218,8 +218,15 @@ public abstract class DocumentsProvider extends ContentProvider {
}
/** {@hide} */
- private void enforceTree(Uri documentUri) {
- if (isTreeUri(documentUri)) {
+ private void enforceTreeForExtraUris(Bundle extras) {
+ enforceTree(extras.getParcelable(DocumentsContract.EXTRA_URI));
+ enforceTree(extras.getParcelable(DocumentsContract.EXTRA_PARENT_URI));
+ enforceTree(extras.getParcelable(DocumentsContract.EXTRA_TARGET_URI));
+ }
+
+ /** {@hide} */
+ private void enforceTree(@Nullable Uri documentUri) {
+ if (documentUri != null && isTreeUri(documentUri)) {
final String parent = getTreeDocumentId(documentUri);
final String child = getDocumentId(documentUri);
if (Objects.equals(parent, child)) {
@@ -1076,6 +1083,9 @@ public abstract class DocumentsProvider extends ContentProvider {
final Context context = getContext();
final Bundle out = new Bundle();
+ // If the URI is a tree URI performs some validation.
+ enforceTreeForExtraUris(extras);
+
if (METHOD_EJECT_ROOT.equals(method)) {
// Given that certain system apps can hold MOUNT_UNMOUNT permission, but only apps
// signed with platform signature can hold MANAGE_DOCUMENTS, we are going to check for
@@ -1099,9 +1109,6 @@ public abstract class DocumentsProvider extends ContentProvider {
"Requested authority " + authority + " doesn't match provider " + mAuthority);
}
- // If the URI is a tree URI performs some validation.
- enforceTree(documentUri);
-
if (METHOD_IS_CHILD_DOCUMENT.equals(method)) {
enforceReadPermissionInner(documentUri, getCallingPackage(),
getCallingAttributionTag(), null);
diff --git a/core/java/android/provider/Settings.java b/core/java/android/provider/Settings.java
index c302def19298..03cf0cf2ca78 100644
--- a/core/java/android/provider/Settings.java
+++ b/core/java/android/provider/Settings.java
@@ -6404,6 +6404,17 @@ public final class Settings {
public static final int LOCATION_MODE_ON = LOCATION_MODE_HIGH_ACCURACY;
/**
+ * The current location time zone detection enabled state for the user.
+ *
+ * See {@link
+ * android.app.timezonedetector.TimeZoneDetector#getCapabilities} for access. See {@link
+ * android.app.timezonedetector.TimeZoneDetector#updateConfiguration} to update.
+ * @hide
+ */
+ public static final String LOCATION_TIME_ZONE_DETECTION_ENABLED =
+ "location_time_zone_detection_enabled";
+
+ /**
* The accuracy in meters used for coarsening location for clients with only the coarse
* location permission.
*
diff --git a/core/java/android/speech/tts/TextToSpeech.java b/core/java/android/speech/tts/TextToSpeech.java
index 3fcb36193c60..3ed7f6c517d4 100644
--- a/core/java/android/speech/tts/TextToSpeech.java
+++ b/core/java/android/speech/tts/TextToSpeech.java
@@ -62,17 +62,17 @@ import java.util.Set;
* to release the native resources used by the TextToSpeech engine.
*
* Apps targeting Android 11 that use text-to-speech should declare {@link
- * TextToSpeech.Engine#INTENT_ACTION_TTS_SERVICE} in the <code><queries></code> elements of their
+ * TextToSpeech.Engine#INTENT_ACTION_TTS_SERVICE} in the {@code queries} elements of their
* manifest:
*
- * <code>
- * <queries>
+ * <pre>
+ * &lt;queries&gt;
* ...
- * <intent>
- * <action android:name="android.intent.action.TTS_SERVICE" />
- * </intent>
- * </queries>
- * </code>
+ * &lt;intent&gt;
+ * &lt;action android:name="android.intent.action.TTS_SERVICE" /&gt;
+ * &lt;/intent&gt;
+ * &lt;/queries&gt;
+ * </pre>
*/
public class TextToSpeech {
@@ -254,18 +254,17 @@ public class TextToSpeech {
* </ul>
*
* Apps targeting Android 11 that use text-to-speech should declare {@link
- * #INTENT_ACTION_TTS_SERVICE} in the <code><queries></code> elements of their
+ * TextToSpeech.Engine#INTENT_ACTION_TTS_SERVICE} in the {@code queries} elements of their
* manifest:
*
- * <code>
- * <queries>
+ * <pre>
+ * &lt;queries&gt;
* ...
- * <intent>
- * <action android:name="android.intent.action.TTS_SERVICE" />
- * </intent>
- * </queries>
- * </code>
-
+ * &lt;intent&gt;
+ * &lt;action android:name="android.intent.action.TTS_SERVICE" /&gt;
+ * &lt;/intent&gt;
+ * &lt;/queries&gt;
+ * </pre>
*/
public class Engine {
diff --git a/core/java/android/telephony/PhoneStateListener.java b/core/java/android/telephony/PhoneStateListener.java
index b80718018652..cbc304b3293a 100644
--- a/core/java/android/telephony/PhoneStateListener.java
+++ b/core/java/android/telephony/PhoneStateListener.java
@@ -950,10 +950,6 @@ public class PhoneStateListener {
* This method will be called when an emergency call is placed on any subscription (including
* the no-SIM case), regardless of which subscription this listener was registered on.
*
- * This method is deprecated. Both this method and the new
- * {@link #onOutgoingEmergencyCall(EmergencyNumber, int)} will be called when an outgoing
- * emergency call is placed.
- *
* @param placedEmergencyNumber The {@link EmergencyNumber} the emergency call was placed to.
*
* @deprecated Use {@link #onOutgoingEmergencyCall(EmergencyNumber, int)}.
@@ -972,22 +968,24 @@ public class PhoneStateListener {
* This method will be called when an emergency call is placed on any subscription (including
* the no-SIM case), regardless of which subscription this listener was registered on.
*
- * Both this method and the deprecated {@link #onOutgoingEmergencyCall(EmergencyNumber)} will be
- * called when an outgoing emergency call is placed. You should only implement one of these
- * methods.
+ * The default implementation of this method calls
+ * {@link #onOutgoingEmergencyCall(EmergencyNumber)} for backwards compatibility purposes. Do
+ * not call {@code super(...)} from within your implementation unless you want
+ * {@link #onOutgoingEmergencyCall(EmergencyNumber)} to be called as well.
*
* @param placedEmergencyNumber The {@link EmergencyNumber} the emergency call was placed to.
* @param subscriptionId The subscription ID used to place the emergency call. If the
* emergency call was placed without a valid subscription (e.g. when there
* are no SIM cards in the device), this will be equal to
* {@link SubscriptionManager#INVALID_SUBSCRIPTION_ID}.
- *
* @hide
*/
@SystemApi
@TestApi
public void onOutgoingEmergencyCall(@NonNull EmergencyNumber placedEmergencyNumber,
int subscriptionId) {
+ // Default implementation for backwards compatibility
+ onOutgoingEmergencyCall(placedEmergencyNumber);
}
/**
@@ -1375,10 +1373,6 @@ public class PhoneStateListener {
Binder.withCleanCallingIdentity(
() -> mExecutor.execute(
- () -> psl.onOutgoingEmergencyCall(placedEmergencyNumber)));
-
- Binder.withCleanCallingIdentity(
- () -> mExecutor.execute(
() -> psl.onOutgoingEmergencyCall(placedEmergencyNumber,
subscriptionId)));
}
diff --git a/core/java/android/text/OWNERS b/core/java/android/text/OWNERS
index e56137119c28..0b51b2d90b79 100644
--- a/core/java/android/text/OWNERS
+++ b/core/java/android/text/OWNERS
@@ -1,5 +1,4 @@
set noparent
siyamed@google.com
-nona@google.com
-clarabayarri@google.com
+nona@google.com \ No newline at end of file
diff --git a/core/java/android/util/apk/ApkSignatureSchemeV2Verifier.java b/core/java/android/util/apk/ApkSignatureSchemeV2Verifier.java
index 6e34666aea84..f74990a82327 100644
--- a/core/java/android/util/apk/ApkSignatureSchemeV2Verifier.java
+++ b/core/java/android/util/apk/ApkSignatureSchemeV2Verifier.java
@@ -149,7 +149,7 @@ public class ApkSignatureSchemeV2Verifier {
* @throws SignatureNotFoundException if the APK is not signed using APK Signature Scheme v2.
* @throws IOException if an I/O error occurs while reading the APK file.
*/
- private static SignatureInfo findSignature(RandomAccessFile apk)
+ public static SignatureInfo findSignature(RandomAccessFile apk)
throws IOException, SignatureNotFoundException {
return ApkSigningBlockUtils.findSignature(apk, APK_SIGNATURE_SCHEME_V2_BLOCK_ID);
}
diff --git a/core/java/android/util/apk/ApkSignatureSchemeV3Verifier.java b/core/java/android/util/apk/ApkSignatureSchemeV3Verifier.java
index 93572857796c..5f963b019335 100644
--- a/core/java/android/util/apk/ApkSignatureSchemeV3Verifier.java
+++ b/core/java/android/util/apk/ApkSignatureSchemeV3Verifier.java
@@ -142,7 +142,7 @@ public class ApkSignatureSchemeV3Verifier {
* @throws SignatureNotFoundException if the APK is not signed using APK Signature Scheme v3.
* @throws IOException if an I/O error occurs while reading the APK file.
*/
- private static SignatureInfo findSignature(RandomAccessFile apk)
+ public static SignatureInfo findSignature(RandomAccessFile apk)
throws IOException, SignatureNotFoundException {
return ApkSigningBlockUtils.findSignature(apk, APK_SIGNATURE_SCHEME_V3_BLOCK_ID);
}
diff --git a/core/java/android/util/apk/ApkSignatureVerifier.java b/core/java/android/util/apk/ApkSignatureVerifier.java
index e0258f7657b2..02edb7ed50a5 100644
--- a/core/java/android/util/apk/ApkSignatureVerifier.java
+++ b/core/java/android/util/apk/ApkSignatureVerifier.java
@@ -92,6 +92,20 @@ public class ApkSignatureVerifier {
private static PackageParser.SigningDetails verifySignatures(String apkPath,
@SignatureSchemeVersion int minSignatureSchemeVersion, boolean verifyFull)
throws PackageParserException {
+ return verifySignaturesInternal(apkPath, minSignatureSchemeVersion,
+ verifyFull).signingDetails;
+ }
+
+ /**
+ * Verifies the provided APK using all allowed signing schemas.
+ * @return the certificates associated with each signer and content digests.
+ * @param verifyFull whether to verify all contents of this APK or just collect certificates.
+ * @throws PackageParserException if there was a problem collecting certificates
+ * @hide
+ */
+ public static SigningDetailsWithDigests verifySignaturesInternal(String apkPath,
+ @SignatureSchemeVersion int minSignatureSchemeVersion, boolean verifyFull)
+ throws PackageParserException {
if (minSignatureSchemeVersion > SignatureSchemeVersion.SIGNING_BLOCK_V4) {
// V3 and before are older than the requested minimum signing version
@@ -121,7 +135,7 @@ public class ApkSignatureVerifier {
return verifyV3AndBelowSignatures(apkPath, minSignatureSchemeVersion, verifyFull);
}
- private static PackageParser.SigningDetails verifyV3AndBelowSignatures(String apkPath,
+ private static SigningDetailsWithDigests verifyV3AndBelowSignatures(String apkPath,
@SignatureSchemeVersion int minSignatureSchemeVersion, boolean verifyFull)
throws PackageParserException {
// try v3
@@ -174,7 +188,7 @@ public class ApkSignatureVerifier {
* @throws SignatureNotFoundException if there are no V4 signatures in the APK
* @throws PackageParserException if there was a problem collecting certificates
*/
- private static PackageParser.SigningDetails verifyV4Signature(String apkPath,
+ private static SigningDetailsWithDigests verifyV4Signature(String apkPath,
@SignatureSchemeVersion int minSignatureSchemeVersion, boolean verifyFull)
throws SignatureNotFoundException, PackageParserException {
Trace.traceBegin(TRACE_TAG_PACKAGE_MANAGER, verifyFull ? "verifyV4" : "certsOnlyV4");
@@ -234,8 +248,8 @@ public class ApkSignatureVerifier {
}
}
- return new PackageParser.SigningDetails(signerSigs,
- SignatureSchemeVersion.SIGNING_BLOCK_V4);
+ return new SigningDetailsWithDigests(new PackageParser.SigningDetails(signerSigs,
+ SignatureSchemeVersion.SIGNING_BLOCK_V4), vSigner.contentDigests);
} catch (SignatureNotFoundException e) {
throw e;
} catch (Exception e) {
@@ -256,8 +270,8 @@ public class ApkSignatureVerifier {
* @throws SignatureNotFoundException if there are no V3 signatures in the APK
* @throws PackageParserException if there was a problem collecting certificates
*/
- private static PackageParser.SigningDetails verifyV3Signature(String apkPath,
- boolean verifyFull) throws SignatureNotFoundException, PackageParserException {
+ private static SigningDetailsWithDigests verifyV3Signature(String apkPath, boolean verifyFull)
+ throws SignatureNotFoundException, PackageParserException {
Trace.traceBegin(TRACE_TAG_PACKAGE_MANAGER, verifyFull ? "verifyV3" : "certsOnlyV3");
try {
ApkSignatureSchemeV3Verifier.VerifiedSigner vSigner =
@@ -275,8 +289,9 @@ public class ApkSignatureVerifier {
pastSignerSigs[i].setFlags(vSigner.por.flagsList.get(i));
}
}
- return new PackageParser.SigningDetails(signerSigs,
- SignatureSchemeVersion.SIGNING_BLOCK_V3, pastSignerSigs);
+ return new SigningDetailsWithDigests(new PackageParser.SigningDetails(signerSigs,
+ SignatureSchemeVersion.SIGNING_BLOCK_V3, pastSignerSigs),
+ vSigner.contentDigests);
} catch (SignatureNotFoundException e) {
throw e;
} catch (Exception e) {
@@ -297,15 +312,16 @@ public class ApkSignatureVerifier {
* @throws SignatureNotFoundException if there are no V2 signatures in the APK
* @throws PackageParserException if there was a problem collecting certificates
*/
- private static PackageParser.SigningDetails verifyV2Signature(String apkPath,
- boolean verifyFull) throws SignatureNotFoundException, PackageParserException {
+ private static SigningDetailsWithDigests verifyV2Signature(String apkPath, boolean verifyFull)
+ throws SignatureNotFoundException, PackageParserException {
Trace.traceBegin(TRACE_TAG_PACKAGE_MANAGER, verifyFull ? "verifyV2" : "certsOnlyV2");
try {
- Certificate[][] signerCerts = verifyFull ? ApkSignatureSchemeV2Verifier.verify(apkPath)
- : ApkSignatureSchemeV2Verifier.unsafeGetCertsWithoutVerification(apkPath);
+ ApkSignatureSchemeV2Verifier.VerifiedSigner vSigner =
+ ApkSignatureSchemeV2Verifier.verify(apkPath, verifyFull);
+ Certificate[][] signerCerts = vSigner.certs;
Signature[] signerSigs = convertToSignatures(signerCerts);
- return new PackageParser.SigningDetails(signerSigs,
- SignatureSchemeVersion.SIGNING_BLOCK_V2);
+ return new SigningDetailsWithDigests(new PackageParser.SigningDetails(signerSigs,
+ SignatureSchemeVersion.SIGNING_BLOCK_V2), vSigner.contentDigests);
} catch (SignatureNotFoundException e) {
throw e;
} catch (Exception e) {
@@ -324,8 +340,7 @@ public class ApkSignatureVerifier {
* @param verifyFull whether to verify all contents of this APK or just collect certificates.
* @throws PackageParserException if there was a problem collecting certificates
*/
- private static PackageParser.SigningDetails verifyV1Signature(
- String apkPath, boolean verifyFull)
+ private static SigningDetailsWithDigests verifyV1Signature(String apkPath, boolean verifyFull)
throws PackageParserException {
StrictJarFile jarFile = null;
@@ -391,7 +406,8 @@ public class ApkSignatureVerifier {
}
}
}
- return new PackageParser.SigningDetails(lastSigs, SignatureSchemeVersion.JAR);
+ return new SigningDetailsWithDigests(
+ new PackageParser.SigningDetails(lastSigs, SignatureSchemeVersion.JAR), null);
} catch (GeneralSecurityException e) {
throw new PackageParserException(INSTALL_PARSE_FAILED_CERTIFICATE_ENCODING,
"Failed to collect certificates from " + apkPath, e);
@@ -542,4 +558,27 @@ public class ApkSignatureVerifier {
return null;
}
}
+
+ /**
+ * Extended signing details.
+ * @hide for internal use only.
+ */
+ public static class SigningDetailsWithDigests {
+ public final PackageParser.SigningDetails signingDetails;
+
+ /**
+ * APK Signature Schemes v2/v3/v4 might contain multiple content digests.
+ * SignatureVerifier usually chooses one of them to verify.
+ * For certain signature schemes, e.g. v4, this digest is verified continuously.
+ * For others, e.g. v2, the caller has to specify if they want to verify.
+ * Please refer to documentation for more details.
+ */
+ public final Map<Integer, byte[]> contentDigests;
+
+ SigningDetailsWithDigests(PackageParser.SigningDetails signingDetails,
+ Map<Integer, byte[]> contentDigests) {
+ this.signingDetails = signingDetails;
+ this.contentDigests = contentDigests;
+ }
+ }
}
diff --git a/core/java/android/util/apk/ApkSigningBlockUtils.java b/core/java/android/util/apk/ApkSigningBlockUtils.java
index 990092caa833..021f232979ef 100644
--- a/core/java/android/util/apk/ApkSigningBlockUtils.java
+++ b/core/java/android/util/apk/ApkSigningBlockUtils.java
@@ -39,7 +39,7 @@ import java.util.Map;
*
* @hide for internal use only.
*/
-final class ApkSigningBlockUtils {
+public final class ApkSigningBlockUtils {
private ApkSigningBlockUtils() {
}
@@ -146,6 +146,37 @@ final class ApkSigningBlockUtils {
Map<Integer, byte[]> expectedDigests,
FileDescriptor apkFileDescriptor,
SignatureInfo signatureInfo) throws SecurityException {
+ int[] digestAlgorithms = new int[expectedDigests.size()];
+ int digestAlgorithmCount = 0;
+ for (int digestAlgorithm : expectedDigests.keySet()) {
+ digestAlgorithms[digestAlgorithmCount] = digestAlgorithm;
+ digestAlgorithmCount++;
+ }
+ byte[][] actualDigests;
+ try {
+ actualDigests = computeContentDigestsPer1MbChunk(digestAlgorithms, apkFileDescriptor,
+ signatureInfo);
+ } catch (DigestException e) {
+ throw new SecurityException("Failed to compute digest(s) of contents", e);
+ }
+ for (int i = 0; i < digestAlgorithms.length; i++) {
+ int digestAlgorithm = digestAlgorithms[i];
+ byte[] expectedDigest = expectedDigests.get(digestAlgorithm);
+ byte[] actualDigest = actualDigests[i];
+ if (!MessageDigest.isEqual(expectedDigest, actualDigest)) {
+ throw new SecurityException(
+ getContentDigestAlgorithmJcaDigestAlgorithm(digestAlgorithm)
+ + " digest of contents did not verify");
+ }
+ }
+ }
+
+ /**
+ * Calculate digests using digestAlgorithms for apkFileDescriptor.
+ * This will skip signature block described by signatureInfo.
+ */
+ public static byte[][] computeContentDigestsPer1MbChunk(int[] digestAlgorithms,
+ FileDescriptor apkFileDescriptor, SignatureInfo signatureInfo) throws DigestException {
// We need to verify the integrity of the following three sections of the file:
// 1. Everything up to the start of the APK Signing Block.
// 2. ZIP Central Directory.
@@ -156,6 +187,7 @@ final class ApkSigningBlockUtils {
// avoid wasting physical memory. In most APK verification scenarios, the contents of the
// APK are already there in the OS's page cache and thus mmap does not use additional
// physical memory.
+
DataSource beforeApkSigningBlock =
new MemoryMappedFileDataSource(apkFileDescriptor, 0,
signatureInfo.apkSigningBlockOffset);
@@ -171,31 +203,8 @@ final class ApkSigningBlockUtils {
ZipUtils.setZipEocdCentralDirectoryOffset(eocdBuf, signatureInfo.apkSigningBlockOffset);
DataSource eocd = new ByteBufferDataSource(eocdBuf);
- int[] digestAlgorithms = new int[expectedDigests.size()];
- int digestAlgorithmCount = 0;
- for (int digestAlgorithm : expectedDigests.keySet()) {
- digestAlgorithms[digestAlgorithmCount] = digestAlgorithm;
- digestAlgorithmCount++;
- }
- byte[][] actualDigests;
- try {
- actualDigests =
- computeContentDigestsPer1MbChunk(
- digestAlgorithms,
- new DataSource[] {beforeApkSigningBlock, centralDir, eocd});
- } catch (DigestException e) {
- throw new SecurityException("Failed to compute digest(s) of contents", e);
- }
- for (int i = 0; i < digestAlgorithms.length; i++) {
- int digestAlgorithm = digestAlgorithms[i];
- byte[] expectedDigest = expectedDigests.get(digestAlgorithm);
- byte[] actualDigest = actualDigests[i];
- if (!MessageDigest.isEqual(expectedDigest, actualDigest)) {
- throw new SecurityException(
- getContentDigestAlgorithmJcaDigestAlgorithm(digestAlgorithm)
- + " digest of contents did not verify");
- }
- }
+ return computeContentDigestsPer1MbChunk(digestAlgorithms,
+ new DataSource[]{beforeApkSigningBlock, centralDir, eocd});
}
private static byte[][] computeContentDigestsPer1MbChunk(
@@ -417,14 +426,10 @@ final class ApkSigningBlockUtils {
static final int SIGNATURE_VERITY_ECDSA_WITH_SHA256 = 0x0423;
static final int SIGNATURE_VERITY_DSA_WITH_SHA256 = 0x0425;
- static final int CONTENT_DIGEST_CHUNKED_SHA256 = 1;
- static final int CONTENT_DIGEST_CHUNKED_SHA512 = 2;
- static final int CONTENT_DIGEST_VERITY_CHUNKED_SHA256 = 3;
- static final int CONTENT_DIGEST_SHA256 = 4;
-
- private static final int[] V4_CONTENT_DIGEST_ALGORITHMS =
- {CONTENT_DIGEST_CHUNKED_SHA512, CONTENT_DIGEST_VERITY_CHUNKED_SHA256,
- CONTENT_DIGEST_CHUNKED_SHA256};
+ public static final int CONTENT_DIGEST_CHUNKED_SHA256 = 1;
+ public static final int CONTENT_DIGEST_CHUNKED_SHA512 = 2;
+ public static final int CONTENT_DIGEST_VERITY_CHUNKED_SHA256 = 3;
+ public static final int CONTENT_DIGEST_SHA256 = 4;
static int compareSignatureAlgorithm(int sigAlgorithm1, int sigAlgorithm2) {
int digestAlgorithm1 = getSignatureAlgorithmContentDigestAlgorithm(sigAlgorithm1);
diff --git a/core/java/android/util/apk/SignatureInfo.java b/core/java/android/util/apk/SignatureInfo.java
index 8e1233af34a1..7638293618ba 100644
--- a/core/java/android/util/apk/SignatureInfo.java
+++ b/core/java/android/util/apk/SignatureInfo.java
@@ -16,15 +16,18 @@
package android.util.apk;
+import android.annotation.NonNull;
+
import java.nio.ByteBuffer;
/**
* APK Signature Scheme v2 block and additional information relevant to verifying the signatures
* contained in the block against the file.
+ * @hide
*/
-class SignatureInfo {
+public class SignatureInfo {
/** Contents of APK Signature Scheme v2 block. */
- public final ByteBuffer signatureBlock;
+ public final @NonNull ByteBuffer signatureBlock;
/** Position of the APK Signing Block in the file. */
public final long apkSigningBlockOffset;
@@ -36,10 +39,10 @@ class SignatureInfo {
public final long eocdOffset;
/** Contents of ZIP End of Central Directory (EoCD) of the file. */
- public final ByteBuffer eocd;
+ public final @NonNull ByteBuffer eocd;
- SignatureInfo(ByteBuffer signatureBlock, long apkSigningBlockOffset, long centralDirOffset,
- long eocdOffset, ByteBuffer eocd) {
+ SignatureInfo(@NonNull ByteBuffer signatureBlock, long apkSigningBlockOffset,
+ long centralDirOffset, long eocdOffset, @NonNull ByteBuffer eocd) {
this.signatureBlock = signatureBlock;
this.apkSigningBlockOffset = apkSigningBlockOffset;
this.centralDirOffset = centralDirOffset;
diff --git a/core/java/android/util/apk/VerityBuilder.java b/core/java/android/util/apk/VerityBuilder.java
index e81e3f7b38d6..4596c6e8f83d 100644
--- a/core/java/android/util/apk/VerityBuilder.java
+++ b/core/java/android/util/apk/VerityBuilder.java
@@ -116,6 +116,34 @@ public abstract class VerityBuilder {
}
/**
+ * Generates the fs-verity hash tree. It is the actual verity tree format on disk, as is
+ * re-generated on device.
+ *
+ * The tree is built bottom up. The bottom level has 256-bit digest for each 4 KB block in the
+ * input file. If the total size is larger than 4 KB, take this level as input and repeat the
+ * same procedure, until the level is within 4 KB. If salt is given, it will apply to each
+ * digestion before the actual data.
+ *
+ * The returned root hash is calculated from the last level of 4 KB chunk, similarly with salt.
+ *
+ * @return the root hash of the generated hash tree.
+ */
+ public static byte[] generateFsVerityRootHash(@NonNull String apkPath, byte[] salt,
+ @NonNull ByteBufferFactory bufferFactory)
+ throws IOException, NoSuchAlgorithmException, DigestException {
+ try (RandomAccessFile apk = new RandomAccessFile(apkPath, "r")) {
+ int[] levelOffset = calculateVerityLevelOffset(apk.length());
+ int merkleTreeSize = levelOffset[levelOffset.length - 1];
+
+ ByteBuffer output = bufferFactory.create(
+ merkleTreeSize
+ + CHUNK_SIZE_BYTES); // maximum size of apk-verity metadata
+ output.order(ByteOrder.LITTLE_ENDIAN);
+ ByteBuffer tree = slice(output, 0, merkleTreeSize);
+ return generateFsVerityTreeInternal(apk, salt, levelOffset, tree);
+ }
+ }
+ /**
* Calculates the apk-verity root hash for integrity measurement. This needs to be consistent
* to what kernel returns.
*/
@@ -259,9 +287,10 @@ public abstract class VerityBuilder {
// thus the syscall overhead is not too big.
private static final int MMAP_REGION_SIZE_BYTES = 1024 * 1024;
- private static void generateFsVerityDigestAtLeafLevel(RandomAccessFile file, ByteBuffer output)
+ private static void generateFsVerityDigestAtLeafLevel(RandomAccessFile file,
+ @Nullable byte[] salt, ByteBuffer output)
throws IOException, NoSuchAlgorithmException, DigestException {
- BufferedDigester digester = new BufferedDigester(null /* salt */, output);
+ BufferedDigester digester = new BufferedDigester(salt, output);
// 1. Digest the whole file by chunks.
consumeByChunk(digester,
@@ -325,6 +354,35 @@ public abstract class VerityBuilder {
}
@NonNull
+ private static byte[] generateFsVerityTreeInternal(@NonNull RandomAccessFile apk,
+ @Nullable byte[] salt, @NonNull int[] levelOffset, @NonNull ByteBuffer output)
+ throws IOException, NoSuchAlgorithmException, DigestException {
+ // 1. Digest the apk to generate the leaf level hashes.
+ generateFsVerityDigestAtLeafLevel(apk, salt,
+ slice(output, levelOffset[levelOffset.length - 2],
+ levelOffset[levelOffset.length - 1]));
+
+ // 2. Digest the lower level hashes bottom up.
+ for (int level = levelOffset.length - 3; level >= 0; level--) {
+ ByteBuffer inputBuffer = slice(output, levelOffset[level + 1], levelOffset[level + 2]);
+ ByteBuffer outputBuffer = slice(output, levelOffset[level], levelOffset[level + 1]);
+
+ DataSource source = new ByteBufferDataSource(inputBuffer);
+ BufferedDigester digester = new BufferedDigester(salt, outputBuffer);
+ consumeByChunk(digester, source, CHUNK_SIZE_BYTES);
+ digester.assertEmptyBuffer();
+ digester.fillUpLastOutputChunk();
+ }
+
+ // 3. Digest the first block (i.e. first level) to generate the root hash.
+ byte[] rootHash = new byte[DIGEST_SIZE_BYTES];
+ BufferedDigester digester = new BufferedDigester(salt, ByteBuffer.wrap(rootHash));
+ digester.consume(slice(output, 0, CHUNK_SIZE_BYTES));
+ digester.assertEmptyBuffer();
+ return rootHash;
+ }
+
+ @NonNull
private static byte[] generateVerityTreeInternal(@NonNull RandomAccessFile apk,
@Nullable SignatureInfo signatureInfo, @Nullable byte[] salt,
@NonNull int[] levelOffset, @NonNull ByteBuffer output)
diff --git a/core/java/android/view/FrameMetrics.java b/core/java/android/view/FrameMetrics.java
index 054dff726ca1..32cc30be8de4 100644
--- a/core/java/android/view/FrameMetrics.java
+++ b/core/java/android/view/FrameMetrics.java
@@ -250,8 +250,11 @@ public final class FrameMetrics {
Index.INTENDED_VSYNC, Index.FRAME_COMPLETED,
};
+ /**
+ * @hide
+ */
@UnsupportedAppUsage
- /* package */ final long[] mTimingData;
+ public final long[] mTimingData;
/**
* Constructs a FrameMetrics object as a copy.
@@ -270,7 +273,7 @@ public final class FrameMetrics {
/**
* @hide
*/
- FrameMetrics() {
+ public FrameMetrics() {
mTimingData = new long[Index.FRAME_STATS_COUNT];
}
diff --git a/core/java/android/view/InputEventReceiver.java b/core/java/android/view/InputEventReceiver.java
index 25a4108c612c..a06a0c68e241 100644
--- a/core/java/android/view/InputEventReceiver.java
+++ b/core/java/android/view/InputEventReceiver.java
@@ -25,6 +25,7 @@ import android.util.SparseIntArray;
import dalvik.system.CloseGuard;
+import java.io.PrintWriter;
import java.lang.ref.Reference;
import java.lang.ref.WeakReference;
@@ -53,6 +54,7 @@ public abstract class InputEventReceiver {
private static native void nativeFinishInputEvent(long receiverPtr, int seq, boolean handled);
private static native boolean nativeConsumeBatchedInputEvents(long receiverPtr,
long frameTimeNanos);
+ private static native String nativeDump(long receiverPtr, String prefix);
/**
* Creates an input event receiver bound to the specified input channel.
@@ -221,6 +223,18 @@ public abstract class InputEventReceiver {
}
/**
+ * Dump the state of this InputEventReceiver to the writer.
+ * @param prefix the prefix (typically whitespace padding) to append in front of each line
+ * @param writer the writer where the dump should be written
+ */
+ public void dump(String prefix, PrintWriter writer) {
+ writer.println(prefix + getClass().getName());
+ writer.println(prefix + " mInputChannel: " + mInputChannel);
+ writer.println(prefix + " mSeqMap: " + mSeqMap);
+ writer.println(prefix + " mReceiverPtr:\n" + nativeDump(mReceiverPtr, prefix + " "));
+ }
+
+ /**
* Factory for InputEventReceiver
*/
public interface Factory {
diff --git a/core/java/android/view/NotificationHeaderView.java b/core/java/android/view/NotificationHeaderView.java
index 6136a80978b7..0c3d61f31dfb 100644
--- a/core/java/android/view/NotificationHeaderView.java
+++ b/core/java/android/view/NotificationHeaderView.java
@@ -456,8 +456,8 @@ public class NotificationHeaderView extends ViewGroup {
case MotionEvent.ACTION_UP:
if (mTrackGesture) {
if (mFeedbackIcon.isVisibleToUser()
- && (mFeedbackRect.contains((int) x, (int) y))
- || mFeedbackRect.contains((int) mDownX, (int) mDownY)) {
+ && (mFeedbackRect.contains((int) x, (int) y)
+ || mFeedbackRect.contains((int) mDownX, (int) mDownY))) {
mFeedbackIcon.performClick();
return true;
}
diff --git a/core/java/android/view/ViewRootImpl.java b/core/java/android/view/ViewRootImpl.java
index 5d20381242bd..03071cd5e814 100644
--- a/core/java/android/view/ViewRootImpl.java
+++ b/core/java/android/view/ViewRootImpl.java
@@ -53,6 +53,9 @@ import static android.view.WindowManager.LayoutParams.PRIVATE_FLAG_APPEARANCE_CO
import static android.view.WindowManager.LayoutParams.PRIVATE_FLAG_BEHAVIOR_CONTROLLED;
import static android.view.WindowManager.LayoutParams.PRIVATE_FLAG_FIT_INSETS_CONTROLLED;
import static android.view.WindowManager.LayoutParams.PRIVATE_FLAG_FORCE_DECOR_VIEW_VISIBILITY;
+import static android.view.WindowManager.LayoutParams.PRIVATE_FLAG_INSET_PARENT_FRAME_BY_IME;
+import static android.view.WindowManager.LayoutParams.SOFT_INPUT_ADJUST_RESIZE;
+import static android.view.WindowManager.LayoutParams.SOFT_INPUT_MASK_ADJUST;
import static android.view.WindowManager.LayoutParams.TYPE_INPUT_METHOD;
import static android.view.WindowManager.LayoutParams.TYPE_STATUS_BAR_ADDITIONAL;
import static android.view.WindowManager.LayoutParams.TYPE_SYSTEM_ALERT;
@@ -1439,11 +1442,10 @@ public final class ViewRootImpl implements ViewParent,
}
// Don't lose the mode we last auto-computed.
- if ((attrs.softInputMode & WindowManager.LayoutParams.SOFT_INPUT_MASK_ADJUST)
+ if ((attrs.softInputMode & SOFT_INPUT_MASK_ADJUST)
== WindowManager.LayoutParams.SOFT_INPUT_ADJUST_UNSPECIFIED) {
mWindowAttributes.softInputMode = (mWindowAttributes.softInputMode
- & ~WindowManager.LayoutParams.SOFT_INPUT_MASK_ADJUST)
- | (oldSoftInputMode & WindowManager.LayoutParams.SOFT_INPUT_MASK_ADJUST);
+ & ~SOFT_INPUT_MASK_ADJUST) | (oldSoftInputMode & SOFT_INPUT_MASK_ADJUST);
}
if ((changes & LayoutParams.SOFT_INPUT_MODE_CHANGED) != 0) {
@@ -2063,6 +2065,7 @@ public final class ViewRootImpl implements ViewParent,
final int sysUiVis = inOutParams.systemUiVisibility | inOutParams.subtreeSystemUiVisibility;
final int flags = inOutParams.flags;
final int type = inOutParams.type;
+ final int adjust = inOutParams.softInputMode & SOFT_INPUT_MASK_ADJUST;
if ((inOutParams.privateFlags & PRIVATE_FLAG_APPEARANCE_CONTROLLED) == 0) {
inOutParams.insetsFlags.appearance = 0;
@@ -2088,12 +2091,13 @@ public final class ViewRootImpl implements ViewParent,
}
}
+ inOutParams.privateFlags &= ~PRIVATE_FLAG_INSET_PARENT_FRAME_BY_IME;
+
if ((inOutParams.privateFlags & PRIVATE_FLAG_FIT_INSETS_CONTROLLED) != 0) {
return;
}
int types = inOutParams.getFitInsetsTypes();
- int sides = inOutParams.getFitInsetsSides();
boolean ignoreVis = inOutParams.isFitInsetsIgnoringVisibility();
if (((sysUiVis & SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN) != 0
@@ -2108,10 +2112,13 @@ public final class ViewRootImpl implements ViewParent,
if (type == TYPE_TOAST || type == TYPE_SYSTEM_ALERT) {
ignoreVis = true;
} else if ((types & Type.systemBars()) == Type.systemBars()) {
- types |= Type.ime();
+ if (adjust == SOFT_INPUT_ADJUST_RESIZE) {
+ types |= Type.ime();
+ } else {
+ inOutParams.privateFlags |= PRIVATE_FLAG_INSET_PARENT_FRAME_BY_IME;
+ }
}
inOutParams.setFitInsetsTypes(types);
- inOutParams.setFitInsetsSides(sides);
inOutParams.setFitInsetsIgnoringVisibility(ignoreVis);
// The fitting of insets are not really controlled by the clients, so we remove the flag.
@@ -2481,8 +2488,7 @@ public final class ViewRootImpl implements ViewParent,
if (mFirst || mAttachInfo.mViewVisibilityChanged) {
mAttachInfo.mViewVisibilityChanged = false;
- int resizeMode = mSoftInputMode &
- WindowManager.LayoutParams.SOFT_INPUT_MASK_ADJUST;
+ int resizeMode = mSoftInputMode & SOFT_INPUT_MASK_ADJUST;
// If we are in auto resize mode, then we need to determine
// what mode to use now.
if (resizeMode == WindowManager.LayoutParams.SOFT_INPUT_ADJUST_UNSPECIFIED) {
@@ -2495,11 +2501,8 @@ public final class ViewRootImpl implements ViewParent,
if (resizeMode == 0) {
resizeMode = WindowManager.LayoutParams.SOFT_INPUT_ADJUST_PAN;
}
- if ((lp.softInputMode &
- WindowManager.LayoutParams.SOFT_INPUT_MASK_ADJUST) != resizeMode) {
- lp.softInputMode = (lp.softInputMode &
- ~WindowManager.LayoutParams.SOFT_INPUT_MASK_ADJUST) |
- resizeMode;
+ if ((lp.softInputMode & SOFT_INPUT_MASK_ADJUST) != resizeMode) {
+ lp.softInputMode = (lp.softInputMode & ~SOFT_INPUT_MASK_ADJUST) | resizeMode;
params = lp;
}
}
@@ -3234,8 +3237,8 @@ public final class ViewRootImpl implements ViewParent,
// Note: must be done after the focus change callbacks,
// so all of the view state is set up correctly.
- mImeFocusController.onPostWindowFocus(mView.findFocus(), hasWindowFocus,
- mWindowAttributes);
+ mImeFocusController.onPostWindowFocus(mView != null ? mView.findFocus() : null,
+ hasWindowFocus, mWindowAttributes);
if (hasWindowFocus) {
// Clear the forward bit. We can just do this directly, since
@@ -7532,36 +7535,36 @@ public final class ViewRootImpl implements ViewParent,
public void dump(String prefix, FileDescriptor fd, PrintWriter writer, String[] args) {
String innerPrefix = prefix + " ";
- writer.print(prefix); writer.println("ViewRoot:");
- writer.print(innerPrefix); writer.print("mAdded="); writer.print(mAdded);
- writer.print(" mRemoved="); writer.println(mRemoved);
- writer.print(innerPrefix); writer.print("mConsumeBatchedInputScheduled=");
- writer.println(mConsumeBatchedInputScheduled);
- writer.print(innerPrefix); writer.print("mConsumeBatchedInputImmediatelyScheduled=");
- writer.println(mConsumeBatchedInputImmediatelyScheduled);
- writer.print(innerPrefix); writer.print("mPendingInputEventCount=");
- writer.println(mPendingInputEventCount);
- writer.print(innerPrefix); writer.print("mProcessInputEventsScheduled=");
- writer.println(mProcessInputEventsScheduled);
- writer.print(innerPrefix); writer.print("mTraversalScheduled=");
- writer.print(mTraversalScheduled);
- writer.print(innerPrefix); writer.print("mIsAmbientMode=");
- writer.print(mIsAmbientMode);
- writer.print(innerPrefix); writer.print("mUnbufferedInputSource=");
- writer.print(Integer.toHexString(mUnbufferedInputSource));
-
+ writer.println(prefix + "ViewRoot:");
+ writer.println(innerPrefix + "mAdded=" + mAdded);
+ writer.println(innerPrefix + "mRemoved=" + mRemoved);
+ writer.println(innerPrefix + "mStopped=" + mStopped);
+ writer.println(innerPrefix + "mConsumeBatchedInputScheduled="
+ + mConsumeBatchedInputScheduled);
+ writer.println(innerPrefix + "mConsumeBatchedInputImmediatelyScheduled="
+ + mConsumeBatchedInputImmediatelyScheduled);
+ writer.println(innerPrefix + "mPendingInputEventCount=" + mPendingInputEventCount);
+ writer.println(innerPrefix + "mProcessInputEventsScheduled="
+ + mProcessInputEventsScheduled);
+ writer.println(innerPrefix + "mTraversalScheduled=" + mTraversalScheduled);
if (mTraversalScheduled) {
- writer.print(" (barrier="); writer.print(mTraversalBarrier); writer.println(")");
- } else {
- writer.println();
+ writer.println(innerPrefix + " (barrier=" + mTraversalBarrier + ")");
}
+ writer.println(innerPrefix + "mIsAmbientMode=" + mIsAmbientMode);
+ writer.println(innerPrefix + "mUnbufferedInputSource="
+ + Integer.toHexString(mUnbufferedInputSource));
+
mFirstInputStage.dump(innerPrefix, writer);
+ if (mInputEventReceiver != null) {
+ mInputEventReceiver.dump(innerPrefix, writer);
+ }
+
mChoreographer.dump(prefix, writer);
mInsetsController.dump(prefix, writer);
- writer.print(prefix); writer.println("View Hierarchy:");
+ writer.println(prefix + "View Hierarchy:");
dumpViewHierarchy(innerPrefix, writer, mView);
}
diff --git a/core/java/android/view/WindowManager.java b/core/java/android/view/WindowManager.java
index 32ee290a0f47..0d62da6bc8e3 100644
--- a/core/java/android/view/WindowManager.java
+++ b/core/java/android/view/WindowManager.java
@@ -2105,6 +2105,12 @@ public interface WindowManager extends ViewManager {
public static final int PRIVATE_FLAG_TRUSTED_OVERLAY = 0x20000000;
/**
+ * Flag to indicate that the parent frame of a window should be inset by IME.
+ * @hide
+ */
+ public static final int PRIVATE_FLAG_INSET_PARENT_FRAME_BY_IME = 0x40000000;
+
+ /**
* An internal annotation for flags that can be specified to {@link #softInputMode}.
*
* @hide
diff --git a/core/java/android/view/accessibility/IWindowMagnificationConnection.aidl b/core/java/android/view/accessibility/IWindowMagnificationConnection.aidl
index eb67191e5f54..ae853e952d25 100644
--- a/core/java/android/view/accessibility/IWindowMagnificationConnection.aidl
+++ b/core/java/android/view/accessibility/IWindowMagnificationConnection.aidl
@@ -18,6 +18,7 @@ package android.view.accessibility;
import android.graphics.PointF;
import android.graphics.Rect;
+import android.os.RemoteCallback;
import android.view.accessibility.IWindowMagnificationConnectionCallback;
/**
@@ -37,8 +38,10 @@ oneway interface IWindowMagnificationConnection {
* or {@link Float#NaN} to leave unchanged.
* @param centerY the screen-relative Y coordinate around which to center,
* or {@link Float#NaN} to leave unchanged.
+ * @param endCallback The callback called when the animation is completed.
*/
- void enableWindowMagnification(int displayId, float scale, float centerX, float centerY);
+ void enableWindowMagnification(int displayId, float scale, float centerX, float centerY,
+ in RemoteCallback endCallback);
/**
* Sets the scale of the window magnifier on specified display.
@@ -52,8 +55,9 @@ oneway interface IWindowMagnificationConnection {
* Disables window magnification on specified display with animation.
*
* @param displayId The logical display id.
+ * @param endCallback The callback called when the animation is completed.
*/
- void disableWindowMagnification(int displayId);
+ void disableWindowMagnification(int displayId, in RemoteCallback endCallback);
/**
* Moves the window magnifier on the specified display. It has no effect while animating.
diff --git a/core/java/android/view/inputmethod/TEST_MAPPING b/core/java/android/view/inputmethod/TEST_MAPPING
new file mode 100644
index 000000000000..4b2ea1a096c8
--- /dev/null
+++ b/core/java/android/view/inputmethod/TEST_MAPPING
@@ -0,0 +1,18 @@
+{
+ "presubmit": [
+ {
+ "name": "CtsAutoFillServiceTestCases",
+ "options": [
+ {
+ "include-filter": "android.autofillservice.cts.inline"
+ },
+ {
+ "exclude-annotation": "androidx.test.filters.FlakyTest"
+ },
+ {
+ "exclude-annotation": "android.platform.test.annotations.AppModeFull"
+ }
+ ]
+ }
+ ]
+}
diff --git a/core/java/android/widget/ProgressBar.java b/core/java/android/widget/ProgressBar.java
index 35605c4c6f6e..796654a4dc99 100644
--- a/core/java/android/widget/ProgressBar.java
+++ b/core/java/android/widget/ProgressBar.java
@@ -54,6 +54,7 @@ import android.view.View;
import android.view.ViewDebug;
import android.view.ViewHierarchyEncoder;
import android.view.accessibility.AccessibilityEvent;
+import android.view.accessibility.AccessibilityManager;
import android.view.accessibility.AccessibilityNodeInfo;
import android.view.animation.AlphaAnimation;
import android.view.animation.Animation;
@@ -314,9 +315,6 @@ public class ProgressBar extends View {
setMax(a.getInt(R.styleable.ProgressBar_max, mMax));
setProgress(a.getInt(R.styleable.ProgressBar_progress, mProgress));
- // onProgressRefresh() is only called when the progress changes. So we should set
- // stateDescription during initialization here.
- super.setStateDescription(formatStateDescription(mProgress));
setSecondaryProgress(a.getInt(
R.styleable.ProgressBar_secondaryProgress, mSecondaryProgress));
@@ -1627,7 +1625,8 @@ public class ProgressBar extends View {
}
void onProgressRefresh(float scale, boolean fromUser, int progress) {
- if (mCustomStateDescription == null) {
+ if (AccessibilityManager.getInstance(mContext).isEnabled()
+ && mCustomStateDescription == null) {
super.setStateDescription(formatStateDescription(mProgress));
}
}
@@ -2351,6 +2350,7 @@ public class ProgressBar extends View {
AccessibilityNodeInfo.RangeInfo.RANGE_TYPE_INT, getMin(), getMax(),
getProgress());
info.setRangeInfo(rangeInfo);
+ info.setStateDescription(formatStateDescription(mProgress));
}
}
diff --git a/core/java/android/window/ITaskOrganizerController.aidl b/core/java/android/window/ITaskOrganizerController.aidl
index 92fa80e40caf..12b16ff6645c 100644
--- a/core/java/android/window/ITaskOrganizerController.aidl
+++ b/core/java/android/window/ITaskOrganizerController.aidl
@@ -60,5 +60,6 @@ interface ITaskOrganizerController {
* Requests that the given task organizer is notified when back is pressed on the root activity
* of one of its controlled tasks.
*/
- void setInterceptBackPressedOnTaskRoot(ITaskOrganizer organizer, boolean interceptBackPressed);
+ void setInterceptBackPressedOnTaskRoot(in WindowContainerToken task,
+ boolean interceptBackPressed);
}
diff --git a/core/java/android/window/TaskOrganizer.java b/core/java/android/window/TaskOrganizer.java
index 7ec4f99ce959..38fb023a0822 100644
--- a/core/java/android/window/TaskOrganizer.java
+++ b/core/java/android/window/TaskOrganizer.java
@@ -149,9 +149,10 @@ public class TaskOrganizer extends WindowOrganizer {
* of one of its controlled tasks.
*/
@RequiresPermission(android.Manifest.permission.MANAGE_ACTIVITY_STACKS)
- public void setInterceptBackPressedOnTaskRoot(boolean interceptBackPressed) {
+ public void setInterceptBackPressedOnTaskRoot(@NonNull WindowContainerToken task,
+ boolean interceptBackPressed) {
try {
- getController().setInterceptBackPressedOnTaskRoot(mInterface, interceptBackPressed);
+ getController().setInterceptBackPressedOnTaskRoot(task, interceptBackPressed);
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
}
diff --git a/core/java/android/window/TaskOrganizerTaskEmbedder.java b/core/java/android/window/TaskOrganizerTaskEmbedder.java
index 46c72f88e14b..eb9dfed7f644 100644
--- a/core/java/android/window/TaskOrganizerTaskEmbedder.java
+++ b/core/java/android/window/TaskOrganizerTaskEmbedder.java
@@ -74,7 +74,7 @@ public class TaskOrganizerTaskEmbedder extends TaskEmbedder {
// windowing mode tasks. Plan is to migrate this to a wm-shell front-end when that
// infrastructure is ready.
// mTaskOrganizer.registerOrganizer();
- mTaskOrganizer.setInterceptBackPressedOnTaskRoot(true);
+ // mTaskOrganizer.setInterceptBackPressedOnTaskRoot(true);
return super.onInitialize();
}
diff --git a/core/java/com/android/internal/config/sysui/SystemUiDeviceConfigFlags.java b/core/java/com/android/internal/config/sysui/SystemUiDeviceConfigFlags.java
index eb59f0f59be1..da26930ca727 100644
--- a/core/java/com/android/internal/config/sysui/SystemUiDeviceConfigFlags.java
+++ b/core/java/com/android/internal/config/sysui/SystemUiDeviceConfigFlags.java
@@ -409,6 +409,11 @@ public final class SystemUiDeviceConfigFlags {
*/
public static final String BACK_GESTURE_SLOP_MULTIPLIER = "back_gesture_slop_multiplier";
+ /**
+ * (long) Screenshot keychord delay (how long the buttons must be pressed), in ms
+ */
+ public static final String SCREENSHOT_KEYCHORD_DELAY = "screenshot_keychord_delay";
+
private SystemUiDeviceConfigFlags() {
}
}
diff --git a/core/java/com/android/internal/content/FileSystemProvider.java b/core/java/com/android/internal/content/FileSystemProvider.java
index a50a52219c74..3b5fecfc600a 100644
--- a/core/java/com/android/internal/content/FileSystemProvider.java
+++ b/core/java/com/android/internal/content/FileSystemProvider.java
@@ -113,6 +113,14 @@ public abstract class FileSystemProvider extends DocumentsProvider {
// Default is no-op
}
+ /**
+ * Callback indicating that the given document has been deleted or moved. This gives
+ * the provider a hook to revoke the uri permissions.
+ */
+ protected void onDocIdDeleted(String docId) {
+ // Default is no-op
+ }
+
@Override
public boolean onCreate() {
throw new UnsupportedOperationException(
@@ -283,6 +291,7 @@ public abstract class FileSystemProvider extends DocumentsProvider {
final String afterDocId = getDocIdForFile(after);
onDocIdChanged(docId);
+ onDocIdDeleted(docId);
onDocIdChanged(afterDocId);
final File afterVisibleFile = getFileForDocId(afterDocId, true);
@@ -312,6 +321,7 @@ public abstract class FileSystemProvider extends DocumentsProvider {
final String docId = getDocIdForFile(after);
onDocIdChanged(sourceDocumentId);
+ onDocIdDeleted(sourceDocumentId);
onDocIdChanged(docId);
moveInMediaStore(visibleFileBefore, getFileForDocId(docId, true));
@@ -343,6 +353,7 @@ public abstract class FileSystemProvider extends DocumentsProvider {
}
onDocIdChanged(docId);
+ onDocIdDeleted(docId);
removeFromMediaStore(visibleFile);
}
diff --git a/core/java/com/android/internal/jank/FrameTracker.java b/core/java/com/android/internal/jank/FrameTracker.java
new file mode 100644
index 000000000000..e5c845059a0d
--- /dev/null
+++ b/core/java/com/android/internal/jank/FrameTracker.java
@@ -0,0 +1,223 @@
+/*
+ * 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.internal.jank;
+
+import android.annotation.NonNull;
+import android.graphics.HardwareRendererObserver;
+import android.os.Handler;
+import android.os.Trace;
+import android.util.Log;
+import android.view.FrameMetrics;
+import android.view.ThreadedRenderer;
+
+import com.android.internal.annotations.VisibleForTesting;
+import com.android.internal.jank.InteractionJankMonitor.Session;
+import com.android.internal.util.FrameworkStatsLog;
+
+/**
+ * @hide
+ */
+public class FrameTracker implements HardwareRendererObserver.OnFrameMetricsAvailableListener {
+ private static final String TAG = FrameTracker.class.getSimpleName();
+ private static final boolean DEBUG = false;
+ //TODO (163431584): need also consider other refresh rates.
+ private static final long JANK_THRESHOLD_NANOS = 1000000000 / 60;
+ private static final long UNKNOWN_TIMESTAMP = -1;
+
+ private final HardwareRendererObserver mObserver;
+ private final ThreadedRendererWrapper mRendererWrapper;
+ private final FrameMetricsWrapper mMetricsWrapper;
+
+ private long mBeginTime = UNKNOWN_TIMESTAMP;
+ private long mEndTime = UNKNOWN_TIMESTAMP;
+ private boolean mShouldTriggerTrace;
+ private long mTotalFramesCount = 0;
+ private long mMissedFramesCount = 0;
+ private long mMaxFrameTimeNanos = 0;
+
+ private Session mSession;
+
+ public FrameTracker(@NonNull Session session,
+ @NonNull Handler handler, @NonNull ThreadedRenderer renderer) {
+ mSession = session;
+ mRendererWrapper = new ThreadedRendererWrapper(renderer);
+ mMetricsWrapper = new FrameMetricsWrapper();
+ mObserver = new HardwareRendererObserver(this, mMetricsWrapper.getTiming(), handler);
+ }
+
+ /**
+ * This constructor is only for unit tests.
+ * @param session a trace session.
+ * @param renderer a test double for ThreadedRenderer
+ * @param metrics a test double for FrameMetrics
+ */
+ @VisibleForTesting
+ public FrameTracker(@NonNull Session session, Handler handler,
+ @NonNull ThreadedRendererWrapper renderer, @NonNull FrameMetricsWrapper metrics) {
+ mSession = session;
+ mRendererWrapper = renderer;
+ mMetricsWrapper = metrics;
+ mObserver = new HardwareRendererObserver(this, mMetricsWrapper.getTiming(), handler);
+ }
+
+ /**
+ * Begin a trace session of the CUJ.
+ */
+ public void begin() {
+ long timestamp = System.nanoTime();
+ if (DEBUG) {
+ Log.d(TAG, "begin: time(ns)=" + timestamp + ", begin(ns)=" + mBeginTime
+ + ", end(ns)=" + mEndTime + ", session=" + mSession);
+ }
+ if (mBeginTime != UNKNOWN_TIMESTAMP && mEndTime == UNKNOWN_TIMESTAMP) {
+ // We have an ongoing tracing already, skip subsequent calls.
+ return;
+ }
+ mBeginTime = timestamp;
+ mEndTime = UNKNOWN_TIMESTAMP;
+ Trace.beginAsyncSection(mSession.getName(), (int) mBeginTime);
+ mRendererWrapper.addObserver(mObserver);
+ }
+
+ /**
+ * End the trace session of the CUJ.
+ */
+ public void end() {
+ long timestamp = System.nanoTime();
+ if (DEBUG) {
+ Log.d(TAG, "end: time(ns)=" + timestamp + ", begin(ns)=" + mBeginTime
+ + ", end(ns)=" + mEndTime + ", session=" + mSession);
+ }
+ if (mBeginTime == UNKNOWN_TIMESTAMP || mEndTime != UNKNOWN_TIMESTAMP) {
+ // We haven't started a trace yet.
+ return;
+ }
+ mEndTime = timestamp;
+ Trace.endAsyncSection(mSession.getName(), (int) mBeginTime);
+ }
+
+ @Override
+ public void onFrameMetricsAvailable(int dropCountSinceLastInvocation) {
+ // Since this callback might come a little bit late after the end() call.
+ // We should keep tracking the begin / end timestamp.
+ // Then compare with vsync timestamp to check if the frame is in the duration of the CUJ.
+
+ if (mBeginTime == UNKNOWN_TIMESTAMP) return; // We haven't started tracing yet.
+ long vsyncTimestamp = mMetricsWrapper.getMetric(FrameMetrics.VSYNC_TIMESTAMP);
+ if (vsyncTimestamp < mBeginTime) return; // The tracing has been started.
+
+ // If the end time has not been set, we are still in the tracing.
+ if (mEndTime != UNKNOWN_TIMESTAMP && vsyncTimestamp > mEndTime) {
+ // The tracing has been ended, remove the observer, see if need to trigger perfetto.
+ mRendererWrapper.removeObserver(mObserver);
+ // Trigger perfetto if necessary.
+ if (mShouldTriggerTrace) {
+ if (DEBUG) {
+ Log.v(TAG, "Found janky frame, triggering perfetto.");
+ }
+ triggerPerfetto();
+ }
+ if (mSession.logToStatsd()) {
+ FrameworkStatsLog.write(
+ FrameworkStatsLog.UI_INTERACTION_FRAME_INFO_REPORTED,
+ mSession.getStatsdInteractionType(),
+ mTotalFramesCount,
+ mMissedFramesCount,
+ mMaxFrameTimeNanos);
+ }
+ return;
+ }
+
+ long totalDurationNanos = mMetricsWrapper.getMetric(FrameMetrics.TOTAL_DURATION);
+ boolean isFirstFrame = mMetricsWrapper.getMetric(FrameMetrics.FIRST_DRAW_FRAME) == 1;
+ boolean isJankyFrame = !isFirstFrame && totalDurationNanos > JANK_THRESHOLD_NANOS;
+
+ mTotalFramesCount += 1;
+
+ if (!isFirstFrame) {
+ mMaxFrameTimeNanos = Math.max(totalDurationNanos, mMaxFrameTimeNanos);
+ }
+
+ if (isJankyFrame) {
+ mMissedFramesCount += 1;
+ mShouldTriggerTrace = true;
+ }
+ }
+
+ /**
+ * Trigger the prefetto daemon.
+ */
+ @VisibleForTesting
+ public void triggerPerfetto() {
+ InteractionJankMonitor.trigger();
+ }
+
+ /**
+ * A wrapper class that we can spy FrameMetrics (a final class) in unit tests.
+ */
+ public static class FrameMetricsWrapper {
+ private FrameMetrics mFrameMetrics;
+
+ public FrameMetricsWrapper() {
+ mFrameMetrics = new FrameMetrics();
+ }
+
+ /**
+ * Wrapper method.
+ * @return timing data of the metrics
+ */
+ public long[] getTiming() {
+ return mFrameMetrics.mTimingData;
+ }
+
+ /**
+ * Wrapper method.
+ * @param index specific index of the timing data
+ * @return the timing data of the specified index
+ */
+ public long getMetric(int index) {
+ return mFrameMetrics.getMetric(index);
+ }
+ }
+
+ /**
+ * A wrapper class that we can spy ThreadedRenderer (a final class) in unit tests.
+ */
+ public static class ThreadedRendererWrapper {
+ private ThreadedRenderer mRenderer;
+
+ public ThreadedRendererWrapper(ThreadedRenderer renderer) {
+ mRenderer = renderer;
+ }
+
+ /**
+ * Wrapper method.
+ * @param observer observer
+ */
+ public void addObserver(HardwareRendererObserver observer) {
+ mRenderer.addObserver(observer);
+ }
+
+ /**
+ * Wrapper method.
+ * @param observer observer
+ */
+ public void removeObserver(HardwareRendererObserver observer) {
+ mRenderer.removeObserver(observer);
+ }
+ }
+}
diff --git a/core/java/com/android/internal/jank/InteractionJankMonitor.java b/core/java/com/android/internal/jank/InteractionJankMonitor.java
new file mode 100644
index 000000000000..5a0cbf9e93e4
--- /dev/null
+++ b/core/java/com/android/internal/jank/InteractionJankMonitor.java
@@ -0,0 +1,203 @@
+/*
+ * 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.internal.jank;
+
+import static com.android.internal.util.FrameworkStatsLog.UIINTERACTION_FRAME_INFO_REPORTED__INTERACTION_TYPE__NOTIFICATION_SHADE_SWIPE;
+
+import android.annotation.IntDef;
+import android.annotation.NonNull;
+import android.os.HandlerThread;
+import android.view.ThreadedRenderer;
+import android.view.View;
+
+import com.android.internal.annotations.VisibleForTesting;
+
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.util.HashMap;
+import java.util.Map;
+
+/**
+ * This class let users to begin and end the always on tracing mechanism.
+ * @hide
+ */
+public class InteractionJankMonitor {
+ private static final String TAG = InteractionJankMonitor.class.getSimpleName();
+ private static final boolean DEBUG = false;
+ private static final Object LOCK = new Object();
+
+ // Every value must have a corresponding entry in CUJ_STATSD_INTERACTION_TYPE.
+ public static final int CUJ_NOTIFICATION_SHADE_MOTION = 0;
+ public static final int CUJ_NOTIFICATION_SHADE_GESTURE = 1;
+
+ private static final int NO_STATSD_LOGGING = -1;
+
+ // Used to convert CujType to InteractionType enum value for statsd logging.
+ // Use NO_STATSD_LOGGING in case the measurement for a given CUJ should not be logged to statsd.
+ private static final int[] CUJ_TO_STATSD_INTERACTION_TYPE = {
+ NO_STATSD_LOGGING,
+ UIINTERACTION_FRAME_INFO_REPORTED__INTERACTION_TYPE__NOTIFICATION_SHADE_SWIPE,
+ };
+
+ private static ThreadedRenderer sRenderer;
+ private static Map<String, FrameTracker> sRunningTracker;
+ private static HandlerThread sWorker;
+ private static boolean sInitialized;
+
+ /** @hide */
+ @IntDef({
+ CUJ_NOTIFICATION_SHADE_MOTION,
+ CUJ_NOTIFICATION_SHADE_GESTURE
+ })
+ @Retention(RetentionPolicy.SOURCE)
+ public @interface CujType {}
+
+ /**
+ * @param view Any view in the view tree to get context and ThreadedRenderer.
+ */
+ public static void init(@NonNull View view) {
+ init(view, null, null, null);
+ }
+
+ /**
+ * Should be only invoked internally or from unit tests.
+ */
+ @VisibleForTesting
+ public static void init(@NonNull View view, @NonNull ThreadedRenderer renderer,
+ @NonNull Map<String, FrameTracker> map, @NonNull HandlerThread worker) {
+ //TODO (163505250): This should be no-op if not in droid food rom.
+ synchronized (LOCK) {
+ if (!sInitialized) {
+ if (!view.isAttachedToWindow()) {
+ throw new IllegalStateException("View is not attached!");
+ }
+ sRenderer = renderer == null ? view.getThreadedRenderer() : renderer;
+ sRunningTracker = map == null ? new HashMap<>() : map;
+ sWorker = worker == null ? new HandlerThread("Aot-Worker") : worker;
+ sWorker.start();
+ sInitialized = true;
+ }
+ }
+ }
+
+ /**
+ * Must invoke init() before invoking this method.
+ */
+ public static void begin(@NonNull @CujType int cujType) {
+ begin(cujType, null);
+ }
+
+ /**
+ * Should be only invoked internally or from unit tests.
+ */
+ @VisibleForTesting
+ public static void begin(@NonNull @CujType int cujType, FrameTracker tracker) {
+ //TODO (163505250): This should be no-op if not in droid food rom.
+ //TODO (163510843): Remove synchronized, add @UiThread if only invoked from ui threads.
+ synchronized (LOCK) {
+ checkInitStateLocked();
+ Session session = new Session(cujType);
+ FrameTracker currentTracker = getTracker(session.getName());
+ if (currentTracker != null) return;
+ if (tracker == null) {
+ tracker = new FrameTracker(session, sWorker.getThreadHandler(), sRenderer);
+ }
+ sRunningTracker.put(session.getName(), tracker);
+ tracker.begin();
+ }
+ }
+
+ /**
+ * Must invoke init() before invoking this method.
+ */
+ public static void end(@NonNull @CujType int cujType) {
+ //TODO (163505250): This should be no-op if not in droid food rom.
+ //TODO (163510843): Remove synchronized, add @UiThread if only invoked from ui threads.
+ synchronized (LOCK) {
+ checkInitStateLocked();
+ Session session = new Session(cujType);
+ FrameTracker tracker = getTracker(session.getName());
+ if (tracker != null) {
+ tracker.end();
+ sRunningTracker.remove(session.getName());
+ }
+ }
+ }
+
+ private static void checkInitStateLocked() {
+ if (!sInitialized) {
+ throw new IllegalStateException("InteractionJankMonitor not initialized!");
+ }
+ }
+
+ /**
+ * Should be only invoked from unit tests.
+ */
+ @VisibleForTesting
+ public static void reset() {
+ sInitialized = false;
+ sRenderer = null;
+ sRunningTracker = null;
+ if (sWorker != null) {
+ sWorker.quit();
+ sWorker = null;
+ }
+ }
+
+ private static FrameTracker getTracker(String sessionName) {
+ synchronized (LOCK) {
+ return sRunningTracker.get(sessionName);
+ }
+ }
+
+ /**
+ * Trigger the perfetto daemon to collect and upload data.
+ */
+ public static void trigger() {
+ sWorker.getThreadHandler().post(
+ () -> PerfettoTrigger.trigger(PerfettoTrigger.TRIGGER_TYPE_JANK));
+ }
+
+ /**
+ * A class to represent a session.
+ */
+ public static class Session {
+ private @CujType int mId;
+
+ public Session(@CujType int session) {
+ mId = session;
+ }
+
+ public int getId() {
+ return mId;
+ }
+
+ public int getStatsdInteractionType() {
+ return CUJ_TO_STATSD_INTERACTION_TYPE[mId];
+ }
+
+ /** Describes whether the measurement from this session should be written to statsd. */
+ public boolean logToStatsd() {
+ return getStatsdInteractionType() != NO_STATSD_LOGGING;
+ }
+
+ public String getName() {
+ return "CujType<" + mId + ">";
+ }
+ }
+
+}
diff --git a/core/java/com/android/internal/jank/PerfettoTrigger.java b/core/java/com/android/internal/jank/PerfettoTrigger.java
new file mode 100644
index 000000000000..6c8d3cdcf5ae
--- /dev/null
+++ b/core/java/com/android/internal/jank/PerfettoTrigger.java
@@ -0,0 +1,115 @@
+/*
+ * 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.
+ */
+
+//TODO (165884885): Make PerfettoTrigger more generic and move it to another package.
+package com.android.internal.jank;
+
+import android.annotation.IntDef;
+import android.annotation.NonNull;
+import android.util.Log;
+
+import java.io.BufferedReader;
+import java.io.IOException;
+import java.io.InputStreamReader;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+
+/**
+ * A trigger implementation with perfetto backend.
+ * @hide
+ */
+public class PerfettoTrigger {
+ private static final String TAG = PerfettoTrigger.class.getSimpleName();
+ private static final boolean DEBUG = false;
+ private static final String TRIGGER_COMMAND = "/system/bin/trigger_perfetto";
+ private static final String[] TRIGGER_TYPE_NAMES = new String[] { "jank-tracker" };
+ public static final int TRIGGER_TYPE_JANK = 0;
+
+ /** @hide */
+ @IntDef({
+ TRIGGER_TYPE_JANK
+ })
+ @Retention(RetentionPolicy.SOURCE)
+ public @interface TriggerType {}
+
+ /**
+ * @param type the trigger type
+ */
+ public static void trigger(@NonNull @TriggerType int type) {
+ try {
+ Token token = new Token(type, TRIGGER_TYPE_NAMES[type]);
+ ProcessBuilder pb = new ProcessBuilder(TRIGGER_COMMAND, token.getName());
+ if (DEBUG) {
+ StringBuilder sb = new StringBuilder();
+ for (String arg : pb.command()) {
+ sb.append(arg).append(" ");
+ }
+ Log.d(TAG, "Triggering " + sb.toString());
+ }
+ Process process = pb.start();
+ if (DEBUG) {
+ readConsoleOutput(process);
+ }
+ } catch (IOException | InterruptedException e) {
+ Log.w(TAG, "Failed to trigger " + type, e);
+ }
+ }
+
+ private static void readConsoleOutput(@NonNull Process process)
+ throws IOException, InterruptedException {
+ process.waitFor();
+ try (BufferedReader errReader =
+ new BufferedReader(new InputStreamReader(process.getErrorStream()))) {
+ StringBuilder errLine = new StringBuilder();
+ String line;
+ while ((line = errReader.readLine()) != null) {
+ errLine.append(line).append("\n");
+ }
+ errLine.append(", code=").append(process.exitValue());
+ Log.d(TAG, "err message=" + errLine.toString());
+ }
+ }
+
+ /**
+ * Token which is used to trigger perfetto.
+ */
+ public static class Token {
+ private int mType;
+ private String mName;
+
+ Token(@TriggerType int type, String name) {
+ mType = type;
+ mName = name;
+ }
+
+ /**
+ * Get trigger type.
+ * @return trigger type, should be @TriggerType
+ */
+ public int getType() {
+ return mType;
+ }
+
+ /**
+ * Get name of this token as the argument while triggering perfetto.
+ * @return name
+ */
+ public String getName() {
+ return mName;
+ }
+ }
+
+}
diff --git a/core/java/com/android/internal/protolog/BaseProtoLogImpl.java b/core/java/com/android/internal/protolog/BaseProtoLogImpl.java
new file mode 100644
index 000000000000..8a4eb4a9ca71
--- /dev/null
+++ b/core/java/com/android/internal/protolog/BaseProtoLogImpl.java
@@ -0,0 +1,397 @@
+/*
+ * 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.internal.protolog;
+
+import static com.android.internal.protolog.ProtoLogFileProto.LOG;
+import static com.android.internal.protolog.ProtoLogFileProto.MAGIC_NUMBER;
+import static com.android.internal.protolog.ProtoLogFileProto.MAGIC_NUMBER_H;
+import static com.android.internal.protolog.ProtoLogFileProto.MAGIC_NUMBER_L;
+import static com.android.internal.protolog.ProtoLogFileProto.REAL_TIME_TO_ELAPSED_TIME_OFFSET_MILLIS;
+import static com.android.internal.protolog.ProtoLogFileProto.VERSION;
+import static com.android.internal.protolog.ProtoLogMessage.BOOLEAN_PARAMS;
+import static com.android.internal.protolog.ProtoLogMessage.DOUBLE_PARAMS;
+import static com.android.internal.protolog.ProtoLogMessage.ELAPSED_REALTIME_NANOS;
+import static com.android.internal.protolog.ProtoLogMessage.MESSAGE_HASH;
+import static com.android.internal.protolog.ProtoLogMessage.SINT64_PARAMS;
+import static com.android.internal.protolog.ProtoLogMessage.STR_PARAMS;
+
+import android.annotation.Nullable;
+import android.os.ShellCommand;
+import android.os.SystemClock;
+import android.util.Slog;
+import android.util.proto.ProtoOutputStream;
+
+import com.android.internal.annotations.VisibleForTesting;
+import com.android.internal.protolog.common.IProtoLogGroup;
+import com.android.internal.protolog.common.LogDataType;
+import com.android.internal.util.TraceBuffer;
+
+import java.io.File;
+import java.io.IOException;
+import java.io.PrintWriter;
+import java.util.ArrayList;
+import java.util.IllegalFormatConversionException;
+import java.util.TreeMap;
+import java.util.stream.Collectors;
+
+
+/**
+ * A service for the ProtoLog logging system.
+ */
+public class BaseProtoLogImpl {
+ protected static final TreeMap<String, IProtoLogGroup> LOG_GROUPS = new TreeMap<>();
+
+ /**
+ * A runnable to update the cached output of {@link #isEnabled}.
+ *
+ * Must be invoked after every action that could change the result of {@link #isEnabled}, eg.
+ * starting / stopping proto log, or enabling / disabling log groups.
+ */
+ public static Runnable sCacheUpdater = () -> { };
+
+ protected static void addLogGroupEnum(IProtoLogGroup[] config) {
+ for (IProtoLogGroup group : config) {
+ LOG_GROUPS.put(group.name(), group);
+ }
+ }
+
+ private static final String TAG = "ProtoLog";
+ private static final long MAGIC_NUMBER_VALUE = ((long) MAGIC_NUMBER_H << 32) | MAGIC_NUMBER_L;
+ static final String PROTOLOG_VERSION = "1.0.0";
+
+ private final File mLogFile;
+ private final String mViewerConfigFilename;
+ private final TraceBuffer mBuffer;
+ protected final ProtoLogViewerConfigReader mViewerConfig;
+
+ private boolean mProtoLogEnabled;
+ private boolean mProtoLogEnabledLockFree;
+ private final Object mProtoLogEnabledLock = new Object();
+
+ @VisibleForTesting
+ public enum LogLevel {
+ DEBUG, VERBOSE, INFO, WARN, ERROR, WTF
+ }
+
+ /**
+ * Main log method, do not call directly.
+ */
+ @VisibleForTesting
+ public void log(LogLevel level, IProtoLogGroup group, int messageHash, int paramsMask,
+ @Nullable String messageString, Object[] args) {
+ if (group.isLogToProto()) {
+ logToProto(messageHash, paramsMask, args);
+ }
+ if (group.isLogToLogcat()) {
+ logToLogcat(group.getTag(), level, messageHash, messageString, args);
+ }
+ }
+
+ private void logToLogcat(String tag, LogLevel level, int messageHash,
+ @Nullable String messageString, Object[] args) {
+ String message = null;
+ if (messageString == null) {
+ messageString = mViewerConfig.getViewerString(messageHash);
+ }
+ if (messageString != null) {
+ try {
+ message = String.format(messageString, args);
+ } catch (IllegalFormatConversionException ex) {
+ Slog.w(TAG, "Invalid ProtoLog format string.", ex);
+ }
+ }
+ if (message == null) {
+ StringBuilder builder = new StringBuilder("UNKNOWN MESSAGE (" + messageHash + ")");
+ for (Object o : args) {
+ builder.append(" ").append(o);
+ }
+ message = builder.toString();
+ }
+ passToLogcat(tag, level, message);
+ }
+
+ /**
+ * SLog wrapper.
+ */
+ @VisibleForTesting
+ public void passToLogcat(String tag, LogLevel level, String message) {
+ switch (level) {
+ case DEBUG:
+ Slog.d(tag, message);
+ break;
+ case VERBOSE:
+ Slog.v(tag, message);
+ break;
+ case INFO:
+ Slog.i(tag, message);
+ break;
+ case WARN:
+ Slog.w(tag, message);
+ break;
+ case ERROR:
+ Slog.e(tag, message);
+ break;
+ case WTF:
+ Slog.wtf(tag, message);
+ break;
+ }
+ }
+
+ private void logToProto(int messageHash, int paramsMask, Object[] args) {
+ if (!isProtoEnabled()) {
+ return;
+ }
+ try {
+ ProtoOutputStream os = new ProtoOutputStream();
+ long token = os.start(LOG);
+ os.write(MESSAGE_HASH, messageHash);
+ os.write(ELAPSED_REALTIME_NANOS, SystemClock.elapsedRealtimeNanos());
+
+ if (args != null) {
+ int argIndex = 0;
+ ArrayList<Long> longParams = new ArrayList<>();
+ ArrayList<Double> doubleParams = new ArrayList<>();
+ ArrayList<Boolean> booleanParams = new ArrayList<>();
+ for (Object o : args) {
+ int type = LogDataType.bitmaskToLogDataType(paramsMask, argIndex);
+ try {
+ switch (type) {
+ case LogDataType.STRING:
+ os.write(STR_PARAMS, o.toString());
+ break;
+ case LogDataType.LONG:
+ longParams.add(((Number) o).longValue());
+ break;
+ case LogDataType.DOUBLE:
+ doubleParams.add(((Number) o).doubleValue());
+ break;
+ case LogDataType.BOOLEAN:
+ booleanParams.add((boolean) o);
+ break;
+ }
+ } catch (ClassCastException ex) {
+ // Should not happen unless there is an error in the ProtoLogTool.
+ os.write(STR_PARAMS, "(INVALID PARAMS_MASK) " + o.toString());
+ Slog.e(TAG, "Invalid ProtoLog paramsMask", ex);
+ }
+ argIndex++;
+ }
+ if (longParams.size() > 0) {
+ os.writePackedSInt64(SINT64_PARAMS,
+ longParams.stream().mapToLong(i -> i).toArray());
+ }
+ if (doubleParams.size() > 0) {
+ os.writePackedDouble(DOUBLE_PARAMS,
+ doubleParams.stream().mapToDouble(i -> i).toArray());
+ }
+ if (booleanParams.size() > 0) {
+ boolean[] arr = new boolean[booleanParams.size()];
+ for (int i = 0; i < booleanParams.size(); i++) {
+ arr[i] = booleanParams.get(i);
+ }
+ os.writePackedBool(BOOLEAN_PARAMS, arr);
+ }
+ }
+ os.end(token);
+ mBuffer.add(os);
+ } catch (Exception e) {
+ Slog.e(TAG, "Exception while logging to proto", e);
+ }
+ }
+
+ public BaseProtoLogImpl(File file, String viewerConfigFilename, int bufferCapacity,
+ ProtoLogViewerConfigReader viewerConfig) {
+ mLogFile = file;
+ mBuffer = new TraceBuffer(bufferCapacity);
+ mViewerConfigFilename = viewerConfigFilename;
+ mViewerConfig = viewerConfig;
+ }
+
+ /**
+ * Starts the logging a circular proto buffer.
+ *
+ * @param pw Print writer
+ */
+ public void startProtoLog(@Nullable PrintWriter pw) {
+ if (isProtoEnabled()) {
+ return;
+ }
+ synchronized (mProtoLogEnabledLock) {
+ logAndPrintln(pw, "Start logging to " + mLogFile + ".");
+ mBuffer.resetBuffer();
+ mProtoLogEnabled = true;
+ mProtoLogEnabledLockFree = true;
+ }
+ sCacheUpdater.run();
+ }
+
+ /**
+ * Stops logging to proto.
+ *
+ * @param pw Print writer
+ * @param writeToFile If the current buffer should be written to disk or not
+ */
+ public void stopProtoLog(@Nullable PrintWriter pw, boolean writeToFile) {
+ if (!isProtoEnabled()) {
+ return;
+ }
+ synchronized (mProtoLogEnabledLock) {
+ logAndPrintln(pw, "Stop logging to " + mLogFile + ". Waiting for log to flush.");
+ mProtoLogEnabled = mProtoLogEnabledLockFree = false;
+ if (writeToFile) {
+ writeProtoLogToFileLocked();
+ logAndPrintln(pw, "Log written to " + mLogFile + ".");
+ }
+ if (mProtoLogEnabled) {
+ logAndPrintln(pw, "ERROR: logging was re-enabled while waiting for flush.");
+ throw new IllegalStateException("logging enabled while waiting for flush.");
+ }
+ }
+ sCacheUpdater.run();
+ }
+
+ /**
+ * Returns {@code true} iff logging to proto is enabled.
+ */
+ public boolean isProtoEnabled() {
+ return mProtoLogEnabledLockFree;
+ }
+
+ protected int setLogging(boolean setTextLogging, boolean value, PrintWriter pw,
+ String... groups) {
+ for (int i = 0; i < groups.length; i++) {
+ String group = groups[i];
+ IProtoLogGroup g = LOG_GROUPS.get(group);
+ if (g != null) {
+ System.out.println("G: "+ g);
+ if (setTextLogging) {
+ g.setLogToLogcat(value);
+ } else {
+ g.setLogToProto(value);
+ }
+ } else {
+ logAndPrintln(pw, "No IProtoLogGroup named " + group);
+ return -1;
+ }
+ }
+ sCacheUpdater.run();
+ return 0;
+ }
+
+ private int unknownCommand(PrintWriter pw) {
+ pw.println("Unknown command");
+ pw.println("Window manager logging options:");
+ pw.println(" start: Start proto logging");
+ pw.println(" stop: Stop proto logging");
+ pw.println(" enable [group...]: Enable proto logging for given groups");
+ pw.println(" disable [group...]: Disable proto logging for given groups");
+ pw.println(" enable-text [group...]: Enable logcat logging for given groups");
+ pw.println(" disable-text [group...]: Disable logcat logging for given groups");
+ return -1;
+ }
+
+ /**
+ * Responds to a shell command.
+ */
+ public int onShellCommand(ShellCommand shell) {
+ PrintWriter pw = shell.getOutPrintWriter();
+ String cmd = shell.getNextArg();
+ if (cmd == null) {
+ return unknownCommand(pw);
+ }
+ ArrayList<String> args = new ArrayList<>();
+ String arg;
+ while ((arg = shell.getNextArg()) != null) {
+ args.add(arg);
+ }
+ String[] groups = args.toArray(new String[args.size()]);
+ switch (cmd) {
+ case "start":
+ startProtoLog(pw);
+ return 0;
+ case "stop":
+ stopProtoLog(pw, true);
+ return 0;
+ case "status":
+ logAndPrintln(pw, getStatus());
+ return 0;
+ case "enable":
+ return setLogging(false, true, pw, groups);
+ case "enable-text":
+ mViewerConfig.loadViewerConfig(pw, mViewerConfigFilename);
+ return setLogging(true, true, pw, groups);
+ case "disable":
+ return setLogging(false, false, pw, groups);
+ case "disable-text":
+ return setLogging(true, false, pw, groups);
+ default:
+ return unknownCommand(pw);
+ }
+ }
+
+ /**
+ * Returns a human-readable ProtoLog status text.
+ */
+ public String getStatus() {
+ return "ProtoLog status: "
+ + ((isProtoEnabled()) ? "Enabled" : "Disabled")
+ + "\nEnabled log groups: \n Proto: "
+ + LOG_GROUPS.values().stream().filter(
+ it -> it.isEnabled() && it.isLogToProto())
+ .map(IProtoLogGroup::name).collect(Collectors.joining(" "))
+ + "\n Logcat: "
+ + LOG_GROUPS.values().stream().filter(
+ it -> it.isEnabled() && it.isLogToLogcat())
+ .map(IProtoLogGroup::name).collect(Collectors.joining(" "))
+ + "\nLogging definitions loaded: " + mViewerConfig.knownViewerStringsNumber();
+ }
+
+ /**
+ * Writes the log buffer to a new file for the bugreport.
+ *
+ * This method is synchronized with {@code #startProtoLog(PrintWriter)} and
+ * {@link #stopProtoLog(PrintWriter, boolean)}.
+ */
+ public void writeProtoLogToFile() {
+ synchronized (mProtoLogEnabledLock) {
+ writeProtoLogToFileLocked();
+ }
+ }
+
+ private void writeProtoLogToFileLocked() {
+ try {
+ long offset =
+ (System.currentTimeMillis() - (SystemClock.elapsedRealtimeNanos() / 1000000));
+ ProtoOutputStream proto = new ProtoOutputStream();
+ proto.write(MAGIC_NUMBER, MAGIC_NUMBER_VALUE);
+ proto.write(VERSION, PROTOLOG_VERSION);
+ proto.write(REAL_TIME_TO_ELAPSED_TIME_OFFSET_MILLIS, offset);
+ mBuffer.writeTraceToFile(mLogFile, proto);
+ } catch (IOException e) {
+ Slog.e(TAG, "Unable to write buffer to file", e);
+ }
+ }
+
+ static void logAndPrintln(@Nullable PrintWriter pw, String msg) {
+ Slog.i(TAG, msg);
+ if (pw != null) {
+ pw.println(msg);
+ pw.flush();
+ }
+ }
+}
+
diff --git a/core/java/com/android/internal/protolog/ProtoLogGroup.java b/core/java/com/android/internal/protolog/ProtoLogGroup.java
index 73d148c1f233..9f7436a13bdc 100644
--- a/core/java/com/android/internal/protolog/ProtoLogGroup.java
+++ b/core/java/com/android/internal/protolog/ProtoLogGroup.java
@@ -36,7 +36,18 @@ public enum ProtoLogGroup implements IProtoLogGroup {
Consts.TAG_WM),
WM_DEBUG_ADD_REMOVE(Consts.ENABLE_DEBUG, Consts.ENABLE_LOG_TO_PROTO_DEBUG, false,
Consts.TAG_WM),
- WM_DEBUG_FOCUS(Consts.ENABLE_DEBUG, Consts.ENABLE_LOG_TO_PROTO_DEBUG, false, Consts.TAG_WM),
+ WM_DEBUG_CONFIGURATION(Consts.ENABLE_DEBUG, Consts.ENABLE_LOG_TO_PROTO_DEBUG, false,
+ Consts.TAG_WM),
+ WM_DEBUG_SWITCH(Consts.ENABLE_DEBUG, Consts.ENABLE_LOG_TO_PROTO_DEBUG, false,
+ Consts.TAG_WM),
+ WM_DEBUG_CONTAINERS(Consts.ENABLE_DEBUG, Consts.ENABLE_LOG_TO_PROTO_DEBUG, false,
+ Consts.TAG_WM),
+ WM_DEBUG_FOCUS(Consts.ENABLE_DEBUG, Consts.ENABLE_LOG_TO_PROTO_DEBUG, false,
+ Consts.TAG_WM),
+ WM_DEBUG_IMMERSIVE(Consts.ENABLE_DEBUG, Consts.ENABLE_LOG_TO_PROTO_DEBUG, false,
+ Consts.TAG_WM),
+ WM_DEBUG_LOCKTASK(Consts.ENABLE_DEBUG, Consts.ENABLE_LOG_TO_PROTO_DEBUG, false,
+ Consts.TAG_WM),
WM_DEBUG_STARTING_WINDOW(Consts.ENABLE_DEBUG, Consts.ENABLE_LOG_TO_PROTO_DEBUG, false,
Consts.TAG_WM),
WM_SHOW_TRANSACTIONS(Consts.ENABLE_DEBUG, Consts.ENABLE_LOG_TO_PROTO_DEBUG, false,
@@ -59,6 +70,8 @@ public enum ProtoLogGroup implements IProtoLogGroup {
Consts.TAG_WM),
WM_DEBUG_IME(Consts.ENABLE_DEBUG, Consts.ENABLE_LOG_TO_PROTO_DEBUG, false,
Consts.TAG_WM),
+ WM_DEBUG_WINDOW_ORGANIZER(Consts.ENABLE_DEBUG, Consts.ENABLE_LOG_TO_PROTO_DEBUG, false,
+ Consts.TAG_WM),
TEST_GROUP(true, true, false, "WindowManagetProtoLogTest");
private final boolean mEnabled;
diff --git a/core/java/com/android/internal/protolog/ProtoLogImpl.java b/core/java/com/android/internal/protolog/ProtoLogImpl.java
index 6874f10e6abc..10224a4b9db6 100644
--- a/core/java/com/android/internal/protolog/ProtoLogImpl.java
+++ b/core/java/com/android/internal/protolog/ProtoLogImpl.java
@@ -16,58 +16,22 @@
package com.android.internal.protolog;
-import static com.android.internal.protolog.ProtoLogFileProto.LOG;
-import static com.android.internal.protolog.ProtoLogFileProto.MAGIC_NUMBER;
-import static com.android.internal.protolog.ProtoLogFileProto.MAGIC_NUMBER_H;
-import static com.android.internal.protolog.ProtoLogFileProto.MAGIC_NUMBER_L;
-import static com.android.internal.protolog.ProtoLogFileProto.REAL_TIME_TO_ELAPSED_TIME_OFFSET_MILLIS;
-import static com.android.internal.protolog.ProtoLogFileProto.VERSION;
-import static com.android.internal.protolog.ProtoLogMessage.BOOLEAN_PARAMS;
-import static com.android.internal.protolog.ProtoLogMessage.DOUBLE_PARAMS;
-import static com.android.internal.protolog.ProtoLogMessage.ELAPSED_REALTIME_NANOS;
-import static com.android.internal.protolog.ProtoLogMessage.MESSAGE_HASH;
-import static com.android.internal.protolog.ProtoLogMessage.SINT64_PARAMS;
-import static com.android.internal.protolog.ProtoLogMessage.STR_PARAMS;
-
import android.annotation.Nullable;
-import android.os.ShellCommand;
-import android.os.SystemClock;
-import android.util.Slog;
-import android.util.proto.ProtoOutputStream;
import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.protolog.common.IProtoLogGroup;
-import com.android.internal.protolog.common.LogDataType;
-import com.android.internal.util.TraceBuffer;
import java.io.File;
-import java.io.IOException;
-import java.io.PrintWriter;
-import java.util.ArrayList;
-import java.util.IllegalFormatConversionException;
-import java.util.TreeMap;
-import java.util.stream.Collectors;
-
/**
* A service for the ProtoLog logging system.
*/
-public class ProtoLogImpl {
- private static final TreeMap<String, IProtoLogGroup> LOG_GROUPS = new TreeMap<>();
-
- /**
- * A runnable to update the cached output of {@link #isEnabled}.
- *
- * Must be invoked after every action that could change the result of {@link #isEnabled}, eg.
- * starting / stopping proto log, or enabling / disabling log groups.
- */
- public static Runnable sCacheUpdater = () -> { };
+public class ProtoLogImpl extends BaseProtoLogImpl {
+ private static final int BUFFER_CAPACITY = 1024 * 1024;
+ private static final String LOG_FILENAME = "/data/misc/wmtrace/wm_log.pb";
+ private static final String VIEWER_CONFIG_FILENAME = "/system/etc/protolog.conf.json.gz";
- private static void addLogGroupEnum(IProtoLogGroup[] config) {
- for (IProtoLogGroup group : config) {
- LOG_GROUPS.put(group.name(), group);
- }
- }
+ private static ProtoLogImpl sServiceInstance = null;
static {
addLogGroupEnum(ProtoLogGroup.values());
@@ -124,30 +88,13 @@ public class ProtoLogImpl {
|| (group.isLogToProto() && getSingleInstance().isProtoEnabled());
}
- private static final int BUFFER_CAPACITY = 1024 * 1024;
- private static final String LOG_FILENAME = "/data/misc/wmtrace/wm_log.pb";
- private static final String VIEWER_CONFIG_FILENAME = "/system/etc/protolog.conf.json.gz";
- private static final String TAG = "ProtoLog";
- private static final long MAGIC_NUMBER_VALUE = ((long) MAGIC_NUMBER_H << 32) | MAGIC_NUMBER_L;
- static final String PROTOLOG_VERSION = "1.0.0";
-
- private final File mLogFile;
- private final TraceBuffer mBuffer;
- private final ProtoLogViewerConfigReader mViewerConfig;
-
- private boolean mProtoLogEnabled;
- private boolean mProtoLogEnabledLockFree;
- private final Object mProtoLogEnabledLock = new Object();
-
- private static ProtoLogImpl sServiceInstance = null;
-
/**
* Returns the single instance of the ProtoLogImpl singleton class.
*/
public static synchronized ProtoLogImpl getSingleInstance() {
if (sServiceInstance == null) {
- sServiceInstance = new ProtoLogImpl(new File(LOG_FILENAME), BUFFER_CAPACITY,
- new ProtoLogViewerConfigReader());
+ sServiceInstance = new ProtoLogImpl(
+ new File(LOG_FILENAME), BUFFER_CAPACITY, new ProtoLogViewerConfigReader());
}
return sServiceInstance;
}
@@ -157,307 +104,9 @@ public class ProtoLogImpl {
sServiceInstance = instance;
}
- @VisibleForTesting
- public enum LogLevel {
- DEBUG, VERBOSE, INFO, WARN, ERROR, WTF
- }
-
- /**
- * Main log method, do not call directly.
- */
- @VisibleForTesting
- public void log(LogLevel level, IProtoLogGroup group, int messageHash, int paramsMask,
- @Nullable String messageString, Object[] args) {
- if (group.isLogToProto()) {
- logToProto(messageHash, paramsMask, args);
- }
- if (group.isLogToLogcat()) {
- logToLogcat(group.getTag(), level, messageHash, messageString, args);
- }
- }
-
- private void logToLogcat(String tag, LogLevel level, int messageHash,
- @Nullable String messageString, Object[] args) {
- String message = null;
- if (messageString == null) {
- messageString = mViewerConfig.getViewerString(messageHash);
- }
- if (messageString != null) {
- try {
- message = String.format(messageString, args);
- } catch (IllegalFormatConversionException ex) {
- Slog.w(TAG, "Invalid ProtoLog format string.", ex);
- }
- }
- if (message == null) {
- StringBuilder builder = new StringBuilder("UNKNOWN MESSAGE (" + messageHash + ")");
- for (Object o : args) {
- builder.append(" ").append(o);
- }
- message = builder.toString();
- }
- passToLogcat(tag, level, message);
- }
-
- /**
- * SLog wrapper.
- */
- @VisibleForTesting
- public void passToLogcat(String tag, LogLevel level, String message) {
- switch (level) {
- case DEBUG:
- Slog.d(tag, message);
- break;
- case VERBOSE:
- Slog.v(tag, message);
- break;
- case INFO:
- Slog.i(tag, message);
- break;
- case WARN:
- Slog.w(tag, message);
- break;
- case ERROR:
- Slog.e(tag, message);
- break;
- case WTF:
- Slog.wtf(tag, message);
- break;
- }
- }
-
- private void logToProto(int messageHash, int paramsMask, Object[] args) {
- if (!isProtoEnabled()) {
- return;
- }
- try {
- ProtoOutputStream os = new ProtoOutputStream();
- long token = os.start(LOG);
- os.write(MESSAGE_HASH, messageHash);
- os.write(ELAPSED_REALTIME_NANOS, SystemClock.elapsedRealtimeNanos());
-
- if (args != null) {
- int argIndex = 0;
- ArrayList<Long> longParams = new ArrayList<>();
- ArrayList<Double> doubleParams = new ArrayList<>();
- ArrayList<Boolean> booleanParams = new ArrayList<>();
- for (Object o : args) {
- int type = LogDataType.bitmaskToLogDataType(paramsMask, argIndex);
- try {
- switch (type) {
- case LogDataType.STRING:
- os.write(STR_PARAMS, o.toString());
- break;
- case LogDataType.LONG:
- longParams.add(((Number) o).longValue());
- break;
- case LogDataType.DOUBLE:
- doubleParams.add(((Number) o).doubleValue());
- break;
- case LogDataType.BOOLEAN:
- booleanParams.add((boolean) o);
- break;
- }
- } catch (ClassCastException ex) {
- // Should not happen unless there is an error in the ProtoLogTool.
- os.write(STR_PARAMS, "(INVALID PARAMS_MASK) " + o.toString());
- Slog.e(TAG, "Invalid ProtoLog paramsMask", ex);
- }
- argIndex++;
- }
- if (longParams.size() > 0) {
- os.writePackedSInt64(SINT64_PARAMS,
- longParams.stream().mapToLong(i -> i).toArray());
- }
- if (doubleParams.size() > 0) {
- os.writePackedDouble(DOUBLE_PARAMS,
- doubleParams.stream().mapToDouble(i -> i).toArray());
- }
- if (booleanParams.size() > 0) {
- boolean[] arr = new boolean[booleanParams.size()];
- for (int i = 0; i < booleanParams.size(); i++) {
- arr[i] = booleanParams.get(i);
- }
- os.writePackedBool(BOOLEAN_PARAMS, arr);
- }
- }
- os.end(token);
- mBuffer.add(os);
- } catch (Exception e) {
- Slog.e(TAG, "Exception while logging to proto", e);
- }
- }
-
- public ProtoLogImpl(File file, int bufferCapacity, ProtoLogViewerConfigReader viewerConfig) {
- mLogFile = file;
- mBuffer = new TraceBuffer(bufferCapacity);
- mViewerConfig = viewerConfig;
- }
-
- /**
- * Starts the logging a circular proto buffer.
- *
- * @param pw Print writer
- */
- public void startProtoLog(@Nullable PrintWriter pw) {
- if (isProtoEnabled()) {
- return;
- }
- synchronized (mProtoLogEnabledLock) {
- logAndPrintln(pw, "Start logging to " + mLogFile + ".");
- mBuffer.resetBuffer();
- mProtoLogEnabled = true;
- mProtoLogEnabledLockFree = true;
- }
- sCacheUpdater.run();
- }
-
- /**
- * Stops logging to proto.
- *
- * @param pw Print writer
- * @param writeToFile If the current buffer should be written to disk or not
- */
- public void stopProtoLog(@Nullable PrintWriter pw, boolean writeToFile) {
- if (!isProtoEnabled()) {
- return;
- }
- synchronized (mProtoLogEnabledLock) {
- logAndPrintln(pw, "Stop logging to " + mLogFile + ". Waiting for log to flush.");
- mProtoLogEnabled = mProtoLogEnabledLockFree = false;
- if (writeToFile) {
- writeProtoLogToFileLocked();
- logAndPrintln(pw, "Log written to " + mLogFile + ".");
- }
- if (mProtoLogEnabled) {
- logAndPrintln(pw, "ERROR: logging was re-enabled while waiting for flush.");
- throw new IllegalStateException("logging enabled while waiting for flush.");
- }
- }
- sCacheUpdater.run();
- }
-
- /**
- * Returns {@code true} iff logging to proto is enabled.
- */
- public boolean isProtoEnabled() {
- return mProtoLogEnabledLockFree;
- }
-
- private int setLogging(ShellCommand shell, boolean setTextLogging, boolean value) {
- String group;
- while ((group = shell.getNextArg()) != null) {
- IProtoLogGroup g = LOG_GROUPS.get(group);
- if (g != null) {
- if (setTextLogging) {
- g.setLogToLogcat(value);
- } else {
- g.setLogToProto(value);
- }
- } else {
- logAndPrintln(shell.getOutPrintWriter(), "No IProtoLogGroup named " + group);
- return -1;
- }
- }
- sCacheUpdater.run();
- return 0;
- }
-
- private int unknownCommand(PrintWriter pw) {
- pw.println("Unknown command");
- pw.println("Window manager logging options:");
- pw.println(" start: Start proto logging");
- pw.println(" stop: Stop proto logging");
- pw.println(" enable [group...]: Enable proto logging for given groups");
- pw.println(" disable [group...]: Disable proto logging for given groups");
- pw.println(" enable-text [group...]: Enable logcat logging for given groups");
- pw.println(" disable-text [group...]: Disable logcat logging for given groups");
- return -1;
- }
-
- /**
- * Responds to a shell command.
- */
- public int onShellCommand(ShellCommand shell) {
- PrintWriter pw = shell.getOutPrintWriter();
- String cmd = shell.getNextArg();
- if (cmd == null) {
- return unknownCommand(pw);
- }
- switch (cmd) {
- case "start":
- startProtoLog(pw);
- return 0;
- case "stop":
- stopProtoLog(pw, true);
- return 0;
- case "status":
- logAndPrintln(pw, getStatus());
- return 0;
- case "enable":
- return setLogging(shell, false, true);
- case "enable-text":
- mViewerConfig.loadViewerConfig(pw, VIEWER_CONFIG_FILENAME);
- return setLogging(shell, true, true);
- case "disable":
- return setLogging(shell, false, false);
- case "disable-text":
- return setLogging(shell, true, false);
- default:
- return unknownCommand(pw);
- }
- }
-
- /**
- * Returns a human-readable ProtoLog status text.
- */
- public String getStatus() {
- return "ProtoLog status: "
- + ((isProtoEnabled()) ? "Enabled" : "Disabled")
- + "\nEnabled log groups: \n Proto: "
- + LOG_GROUPS.values().stream().filter(
- it -> it.isEnabled() && it.isLogToProto())
- .map(IProtoLogGroup::name).collect(Collectors.joining(" "))
- + "\n Logcat: "
- + LOG_GROUPS.values().stream().filter(
- it -> it.isEnabled() && it.isLogToLogcat())
- .map(IProtoLogGroup::name).collect(Collectors.joining(" "))
- + "\nLogging definitions loaded: " + mViewerConfig.knownViewerStringsNumber();
- }
-
- /**
- * Writes the log buffer to a new file for the bugreport.
- *
- * This method is synchronized with {@code #startProtoLog(PrintWriter)} and
- * {@link #stopProtoLog(PrintWriter, boolean)}.
- */
- public void writeProtoLogToFile() {
- synchronized (mProtoLogEnabledLock) {
- writeProtoLogToFileLocked();
- }
- }
-
- private void writeProtoLogToFileLocked() {
- try {
- long offset =
- (System.currentTimeMillis() - (SystemClock.elapsedRealtimeNanos() / 1000000));
- ProtoOutputStream proto = new ProtoOutputStream();
- proto.write(MAGIC_NUMBER, MAGIC_NUMBER_VALUE);
- proto.write(VERSION, PROTOLOG_VERSION);
- proto.write(REAL_TIME_TO_ELAPSED_TIME_OFFSET_MILLIS, offset);
- mBuffer.writeTraceToFile(mLogFile, proto);
- } catch (IOException e) {
- Slog.e(TAG, "Unable to write buffer to file", e);
- }
- }
-
-
- static void logAndPrintln(@Nullable PrintWriter pw, String msg) {
- Slog.i(TAG, msg);
- if (pw != null) {
- pw.println(msg);
- pw.flush();
- }
+ public ProtoLogImpl(File logFile, int bufferCapacity,
+ ProtoLogViewerConfigReader viewConfigReader) {
+ super(logFile, VIEWER_CONFIG_FILENAME, bufferCapacity, viewConfigReader);
}
}
diff --git a/core/java/com/android/internal/protolog/ProtoLogViewerConfigReader.java b/core/java/com/android/internal/protolog/ProtoLogViewerConfigReader.java
index e381d30da524..aa30a7723ad9 100644
--- a/core/java/com/android/internal/protolog/ProtoLogViewerConfigReader.java
+++ b/core/java/com/android/internal/protolog/ProtoLogViewerConfigReader.java
@@ -16,6 +16,9 @@
package com.android.internal.protolog;
+import android.annotation.Nullable;
+import android.util.Slog;
+
import org.json.JSONException;
import org.json.JSONObject;
@@ -23,6 +26,7 @@ import java.io.BufferedReader;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
+import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.PrintWriter;
import java.util.Iterator;
@@ -34,6 +38,7 @@ import java.util.zip.GZIPInputStream;
* Handles loading and parsing of ProtoLog viewer configuration.
*/
public class ProtoLogViewerConfigReader {
+ private static final String TAG = "ProtoLogViewerConfigReader";
private Map<Integer, String> mLogMessageMap = null;
/** Returns message format string for its hash or null if unavailable. */
@@ -49,48 +54,54 @@ public class ProtoLogViewerConfigReader {
* Reads the specified viewer configuration file. Does nothing if the config is already loaded.
*/
public synchronized void loadViewerConfig(PrintWriter pw, String viewerConfigFilename) {
- if (mLogMessageMap != null) {
- return;
- }
try {
- InputStreamReader config = new InputStreamReader(
- new GZIPInputStream(new FileInputStream(viewerConfigFilename)));
- BufferedReader reader = new BufferedReader(config);
- StringBuilder builder = new StringBuilder();
- String line;
- while ((line = reader.readLine()) != null) {
- builder.append(line).append('\n');
- }
- reader.close();
- JSONObject json = new JSONObject(builder.toString());
- JSONObject messages = json.getJSONObject("messages");
-
- mLogMessageMap = new TreeMap<>();
- Iterator it = messages.keys();
- while (it.hasNext()) {
- String key = (String) it.next();
- try {
- int hash = Integer.parseInt(key);
- JSONObject val = messages.getJSONObject(key);
- String msg = val.getString("message");
- mLogMessageMap.put(hash, msg);
- } catch (NumberFormatException expected) {
- // Not a messageHash - skip it
- }
- }
- ProtoLogImpl.logAndPrintln(pw, "Loaded " + mLogMessageMap.size()
+ loadViewerConfig(new GZIPInputStream(new FileInputStream(viewerConfigFilename)));
+ logAndPrintln(pw, "Loaded " + mLogMessageMap.size()
+ " log definitions from " + viewerConfigFilename);
} catch (FileNotFoundException e) {
- ProtoLogImpl.logAndPrintln(pw, "Unable to load log definitions: File "
+ logAndPrintln(pw, "Unable to load log definitions: File "
+ viewerConfigFilename + " not found." + e);
} catch (IOException e) {
- ProtoLogImpl.logAndPrintln(pw,
- "Unable to load log definitions: IOException while reading "
+ logAndPrintln(pw, "Unable to load log definitions: IOException while reading "
+ viewerConfigFilename + ". " + e);
} catch (JSONException e) {
- ProtoLogImpl.logAndPrintln(pw,
- "Unable to load log definitions: JSON parsing exception while reading "
- + viewerConfigFilename + ". " + e);
+ logAndPrintln(pw, "Unable to load log definitions: JSON parsing exception while reading "
+ + viewerConfigFilename + ". " + e);
+ }
+ }
+
+ /**
+ * Reads the specified viewer configuration input stream.
+ * Does nothing if the config is already loaded.
+ */
+ public synchronized void loadViewerConfig(InputStream viewerConfigInputStream)
+ throws IOException, JSONException {
+ if (mLogMessageMap != null) {
+ return;
+ }
+ InputStreamReader config = new InputStreamReader(viewerConfigInputStream);
+ BufferedReader reader = new BufferedReader(config);
+ StringBuilder builder = new StringBuilder();
+ String line;
+ while ((line = reader.readLine()) != null) {
+ builder.append(line).append('\n');
+ }
+ reader.close();
+ JSONObject json = new JSONObject(builder.toString());
+ JSONObject messages = json.getJSONObject("messages");
+
+ mLogMessageMap = new TreeMap<>();
+ Iterator it = messages.keys();
+ while (it.hasNext()) {
+ String key = (String) it.next();
+ try {
+ int hash = Integer.parseInt(key);
+ JSONObject val = messages.getJSONObject(key);
+ String msg = val.getString("message");
+ mLogMessageMap.put(hash, msg);
+ } catch (NumberFormatException expected) {
+ // Not a messageHash - skip it
+ }
}
}
@@ -103,4 +114,12 @@ public class ProtoLogViewerConfigReader {
}
return 0;
}
+
+ static void logAndPrintln(@Nullable PrintWriter pw, String msg) {
+ Slog.i(TAG, msg);
+ if (pw != null) {
+ pw.println(msg);
+ pw.flush();
+ }
+ }
}
diff --git a/core/java/com/android/internal/util/LatencyTracker.java b/core/java/com/android/internal/util/LatencyTracker.java
index 67cfc3a7dd49..555f62c53387 100644
--- a/core/java/com/android/internal/util/LatencyTracker.java
+++ b/core/java/com/android/internal/util/LatencyTracker.java
@@ -14,13 +14,9 @@
package com.android.internal.util;
-import android.content.BroadcastReceiver;
import android.content.Context;
-import android.content.Intent;
-import android.content.IntentFilter;
import android.os.Build;
import android.os.SystemClock;
-import android.os.SystemProperties;
import android.os.Trace;
import android.util.EventLog;
import android.util.Log;
@@ -29,18 +25,14 @@ import android.util.SparseLongArray;
import com.android.internal.logging.EventLogTags;
/**
- * Class to track various latencies in SystemUI. It then outputs the latency to logcat so these
- * latencies can be captured by tests and then used for dashboards.
+ * Class to track various latencies in SystemUI. It then writes the latency to statsd and also
+ * outputs it to logcat so these latencies can be captured by tests and then used for dashboards.
* <p>
* This is currently only in Keyguard so it can be shared between SystemUI and Keyguard, but
* eventually we'd want to merge these two packages together so Keyguard can use common classes
* that are shared with SystemUI.
*/
public class LatencyTracker {
-
- private static final String ACTION_RELOAD_PROPERTY =
- "com.android.systemui.RELOAD_LATENCY_TRACKER_PROPERTY";
-
private static final String TAG = "LatencyTracker";
/**
@@ -82,7 +74,7 @@ public class LatencyTracker {
/*
* Time between we get a face acquired signal until we start with the unlock animation
*/
- public static final int ACTION_FACE_WAKE_AND_UNLOCK = 6;
+ public static final int ACTION_FACE_WAKE_AND_UNLOCK = 7;
private static final String[] NAMES = new String[] {
"expand panel",
@@ -94,38 +86,34 @@ public class LatencyTracker {
"rotate the screen",
"face wake-and-unlock" };
+ private static final int[] STATSD_ACTION = new int[] {
+ FrameworkStatsLog.UIACTION_LATENCY_REPORTED__ACTION__ACTION_EXPAND_PANEL,
+ FrameworkStatsLog.UIACTION_LATENCY_REPORTED__ACTION__ACTION_TOGGLE_RECENTS,
+ FrameworkStatsLog.UIACTION_LATENCY_REPORTED__ACTION__ACTION_FINGERPRINT_WAKE_AND_UNLOCK,
+ FrameworkStatsLog.UIACTION_LATENCY_REPORTED__ACTION__ACTION_CHECK_CREDENTIAL,
+ FrameworkStatsLog.UIACTION_LATENCY_REPORTED__ACTION__ACTION_CHECK_CREDENTIAL_UNLOCKED,
+ FrameworkStatsLog.UIACTION_LATENCY_REPORTED__ACTION__ACTION_TURN_ON_SCREEN,
+ FrameworkStatsLog.UIACTION_LATENCY_REPORTED__ACTION__ACTION_ROTATE_SCREEN,
+ FrameworkStatsLog.UIACTION_LATENCY_REPORTED__ACTION__ACTION_FACE_WAKE_AND_UNLOCK,
+ };
+
private static LatencyTracker sLatencyTracker;
private final SparseLongArray mStartRtc = new SparseLongArray();
- private boolean mEnabled;
public static LatencyTracker getInstance(Context context) {
if (sLatencyTracker == null) {
- sLatencyTracker = new LatencyTracker(context.getApplicationContext());
+ sLatencyTracker = new LatencyTracker();
}
return sLatencyTracker;
}
- private LatencyTracker(Context context) {
- context.registerReceiver(new BroadcastReceiver() {
- @Override
- public void onReceive(Context context, Intent intent) {
- reloadProperty();
- }
- }, new IntentFilter(ACTION_RELOAD_PROPERTY));
- reloadProperty();
- }
-
- private void reloadProperty() {
- mEnabled = SystemProperties.getBoolean("debug.systemui.latency_tracking", false);
- }
-
public static boolean isEnabled(Context ctx) {
return getInstance(ctx).isEnabled();
}
public boolean isEnabled() {
- return Build.IS_DEBUGGABLE && mEnabled;
+ return Build.IS_DEBUGGABLE;
}
/**
@@ -134,7 +122,7 @@ public class LatencyTracker {
* @param action The action to start. One of the ACTION_* values.
*/
public void onActionStart(int action) {
- if (!mEnabled) {
+ if (!isEnabled()) {
return;
}
Trace.asyncTraceBegin(Trace.TRACE_TAG_APP, NAMES[action], 0);
@@ -147,7 +135,7 @@ public class LatencyTracker {
* @param action The action to end. One of the ACTION_* values.
*/
public void onActionEnd(int action) {
- if (!mEnabled) {
+ if (!isEnabled()) {
return;
}
long endRtc = SystemClock.elapsedRealtime();
@@ -169,5 +157,7 @@ public class LatencyTracker {
public static void logAction(int action, int duration) {
Log.i(TAG, "action=" + action + " latency=" + duration);
EventLog.writeEvent(EventLogTags.SYSUI_LATENCY, action, duration);
+ FrameworkStatsLog.write(
+ FrameworkStatsLog.UI_ACTION_LATENCY_REPORTED, STATSD_ACTION[action], duration);
}
}
diff --git a/core/java/com/android/internal/util/StatLogger.java b/core/java/com/android/internal/util/StatLogger.java
index 2d65090ce51e..1622f7ddb971 100644
--- a/core/java/com/android/internal/util/StatLogger.java
+++ b/core/java/com/android/internal/util/StatLogger.java
@@ -17,6 +17,7 @@
package com.android.internal.util;
import android.os.SystemClock;
+import android.text.TextUtils;
import android.util.IndentingPrintWriter;
import android.util.Slog;
import android.util.proto.ProtoOutputStream;
@@ -65,8 +66,14 @@ public class StatLogger {
private long mNextTickTime = SystemClock.elapsedRealtime() + 1000;
private final String[] mLabels;
+ private final String mStatsTag;
public StatLogger(String[] eventLabels) {
+ this(null, eventLabels);
+ }
+
+ public StatLogger(String statsTag, String[] eventLabels) {
+ mStatsTag = statsTag;
SIZE = eventLabels.length;
mCountStats = new int[SIZE];
mDurationStats = new long[SIZE];
@@ -135,7 +142,11 @@ public class StatLogger {
public void dump(IndentingPrintWriter pw) {
synchronized (mLock) {
- pw.println("Stats:");
+ if (!TextUtils.isEmpty(mStatsTag)) {
+ pw.println(mStatsTag + ":");
+ } else {
+ pw.println("Stats:");
+ }
pw.increaseIndent();
for (int i = 0; i < SIZE; i++) {
final int count = mCountStats[i];
diff --git a/core/java/com/android/internal/view/ScrollCaptureViewHelper.java b/core/java/com/android/internal/view/ScrollCaptureViewHelper.java
index 9f100bd6440f..a92e978b2fc1 100644
--- a/core/java/com/android/internal/view/ScrollCaptureViewHelper.java
+++ b/core/java/com/android/internal/view/ScrollCaptureViewHelper.java
@@ -26,6 +26,36 @@ interface ScrollCaptureViewHelper<V extends View> {
int DOWN = 1;
/**
+ * Contains the result of a scroll request.
+ */
+ class ScrollResult {
+ /**
+ * The area requested in pixels, within {@link #onComputeScrollBounds scroll bounds}, with
+ * top/bottom relative to the scroll position at the start of capture.
+ */
+ public Rect requestedArea;
+ /**
+ * The area, in pixels of the request which is visible and available for capture. In the
+ * same coordinate space as {@link #requestedArea}.
+ */
+ public Rect availableArea;
+ /**
+ * The updated scroll delta (the relative distance, in pixels that the scroll position has
+ * moved from the starting position since capture started).
+ */
+ public int scrollDelta; // visible top offset from start
+
+ @Override
+ public String toString() {
+ return "ScrollResult{"
+ + "requestedArea=" + requestedArea
+ + ", availableArea=" + availableArea
+ + ", scrollDelta=" + scrollDelta
+ + '}';
+ }
+ }
+
+ /**
* Verifies that the view is still visible and scrollable. If true is returned here, expect a
* call to {@link #onComputeScrollBounds(View)} to follow.
*
@@ -48,6 +78,7 @@ interface ScrollCaptureViewHelper<V extends View> {
view.getWidth() - view.getPaddingRight(),
view.getHeight() - view.getPaddingBottom());
}
+
/**
* Adjust the target for capture.
* <p>
@@ -67,14 +98,14 @@ interface ScrollCaptureViewHelper<V extends View> {
* needed and return the resulting rectangle describing the position and bounds of the area
* which is visible.
*
+ * @param view the view being captured
* @param scrollBounds the area in which scrolling content moves, local to the {@code containing
* view}
* @param requestRect the area relative to {@code scrollBounds} which describes the location of
* content to capture for the request
- * @return the visible area within scrollBounds of the requested rectangle, return {@code null}
- * in the case of an unrecoverable error condition, to abort the capture process
+ * @return the result of the request as a {@link ScrollResult}
*/
- Rect onScrollRequested(@NonNull V view, Rect scrollBounds, Rect requestRect);
+ ScrollResult onScrollRequested(@NonNull V view, Rect scrollBounds, Rect requestRect);
/**
* Restore the target after capture.
diff --git a/core/java/com/android/internal/view/ScrollCaptureViewSupport.java b/core/java/com/android/internal/view/ScrollCaptureViewSupport.java
index 4087eda944e0..7b4f73ffde2b 100644
--- a/core/java/com/android/internal/view/ScrollCaptureViewSupport.java
+++ b/core/java/com/android/internal/view/ScrollCaptureViewSupport.java
@@ -30,21 +30,24 @@ import android.view.ScrollCaptureSession;
import android.view.Surface;
import android.view.View;
+import com.android.internal.view.ScrollCaptureViewHelper.ScrollResult;
+
import java.lang.ref.WeakReference;
import java.util.function.Consumer;
/**
- * Provides a ScrollCaptureCallback implementation for to handle arbitrary View-based scrolling
- * containers.
- * <p>
- * To use this class, supply the target view and an implementation of {@ScrollCaptureViewHelper}
- * to the callback.
+ * Provides a base ScrollCaptureCallback implementation to handle arbitrary View-based scrolling
+ * containers. This class handles the bookkeeping aspects of {@link ScrollCaptureCallback}
+ * including rendering output using HWUI. Adaptable to any {@link View} using
+ * {@link ScrollCaptureViewHelper}.
*
* @param <V> the specific View subclass handled
- * @hide
+ * @see ScrollCaptureViewHelper
*/
public class ScrollCaptureViewSupport<V extends View> implements ScrollCaptureCallback {
+ private static final String TAG = "ScrollCaptureViewSupport";
+
private final WeakReference<V> mWeakView;
private final ScrollCaptureViewHelper<V> mViewHelper;
private ViewRenderer mRenderer;
@@ -52,11 +55,6 @@ public class ScrollCaptureViewSupport<V extends View> implements ScrollCaptureCa
private boolean mStarted;
private boolean mEnded;
- static <V extends View> ScrollCaptureCallback createCallback(V view,
- ScrollCaptureViewHelper<V> impl) {
- return new ScrollCaptureViewSupport<>(view, impl);
- }
-
ScrollCaptureViewSupport(V containingView, ScrollCaptureViewHelper<V> viewHelper) {
mWeakView = new WeakReference<>(containingView);
mRenderer = new ViewRenderer();
@@ -82,6 +80,7 @@ public class ScrollCaptureViewSupport<V extends View> implements ScrollCaptureCa
@Override
public final void onScrollCaptureStart(ScrollCaptureSession session, Runnable onReady) {
V view = mWeakView.get();
+
mEnded = false;
mStarted = true;
@@ -103,21 +102,30 @@ public class ScrollCaptureViewSupport<V extends View> implements ScrollCaptureCa
session.notifyBufferSent(0, null);
return;
}
- Rect captureArea = mViewHelper.onScrollRequested(view, session.getScrollBounds(),
+ // Ask the view to scroll as needed to bring this area into view.
+ ScrollResult scrollResult = mViewHelper.onScrollRequested(view, session.getScrollBounds(),
requestRect);
- mRenderer.renderFrame(view, captureArea, mUiHandler,
- () -> session.notifyBufferSent(0, captureArea));
+ view.invalidate(); // don't wait for vsync
+
+ // For image capture, shift back by scrollDelta to arrive at the location within the view
+ // where the requested content will be drawn
+ Rect viewCaptureArea = new Rect(scrollResult.availableArea);
+ viewCaptureArea.offset(0, -scrollResult.scrollDelta);
+
+ mRenderer.renderView(view, viewCaptureArea, mUiHandler,
+ (frameNumber) -> session.notifyBufferSent(frameNumber, scrollResult.availableArea));
}
@Override
public final void onScrollCaptureEnd(Runnable onReady) {
V view = mWeakView.get();
if (mStarted && !mEnded) {
- mViewHelper.onPrepareForEnd(view);
- /* empty */
+ if (view != null) {
+ mViewHelper.onPrepareForEnd(view);
+ view.invalidate();
+ }
mEnded = true;
- mRenderer.trimMemory();
- mRenderer.setSurface(null);
+ mRenderer.destroy();
}
onReady.run();
}
@@ -142,7 +150,7 @@ public class ScrollCaptureViewSupport<V extends View> implements ScrollCaptureCa
private static final String TAG = "ViewRenderer";
private HardwareRenderer mRenderer;
- private RenderNode mRootRenderNode;
+ private RenderNode mCaptureRenderNode;
private final RectF mTempRectF = new RectF();
private final Rect mSourceRect = new Rect();
private final Rect mTempRect = new Rect();
@@ -151,10 +159,14 @@ public class ScrollCaptureViewSupport<V extends View> implements ScrollCaptureCa
private long mLastRenderedSourceDrawingId = -1;
+ public interface FrameCompleteListener {
+ void onFrameComplete(long frameNumber);
+ }
+
ViewRenderer() {
mRenderer = new HardwareRenderer();
- mRootRenderNode = new RenderNode("ScrollCaptureRoot");
- mRenderer.setContentRoot(mRootRenderNode);
+ mCaptureRenderNode = new RenderNode("ScrollCaptureRoot");
+ mRenderer.setContentRoot(mCaptureRenderNode);
// TODO: Figure out a way to flip this on when we are sure the source window is opaque
mRenderer.setOpaque(false);
@@ -193,18 +205,36 @@ public class ScrollCaptureViewSupport<V extends View> implements ScrollCaptureCa
// Enable shadows for elevation/Z
mRenderer.setLightSourceGeometry(lightX, lightY, lightZ, lightRadius);
mRenderer.setLightSourceAlpha(AMBIENT_SHADOW_ALPHA, SPOT_SHADOW_ALPHA);
+ }
+
+ private void updateRootNode(View source, Rect localSourceRect) {
+ final View rootView = source.getRootView();
+ transformToRoot(source, localSourceRect, mTempRect);
+
+ mCaptureRenderNode.setPosition(0, 0, mTempRect.width(), mTempRect.height());
+ RecordingCanvas canvas = mCaptureRenderNode.beginRecording();
+ canvas.enableZ();
+ canvas.translate(-mTempRect.left, -mTempRect.top);
+ RenderNode rootViewRenderNode = rootView.updateDisplayListIfDirty();
+ if (rootViewRenderNode.hasDisplayList()) {
+ canvas.drawRenderNode(rootViewRenderNode);
+ }
+ mCaptureRenderNode.endRecording();
}
- public void renderFrame(View localReference, Rect sourceRect, Handler handler,
- Runnable onFrameCommitted) {
- if (updateForView(localReference)) {
- setupLighting(localReference);
+ public void renderView(View view, Rect sourceRect, Handler handler,
+ FrameCompleteListener frameListener) {
+ if (updateForView(view)) {
+ setupLighting(view);
}
- buildRootDisplayList(localReference, sourceRect);
+ view.invalidate();
+ updateRootNode(view, sourceRect);
HardwareRenderer.FrameRenderRequest request = mRenderer.createRenderRequest();
request.setVsyncTime(SystemClock.elapsedRealtimeNanos());
- request.setFrameCommitCallback(handler::post, onFrameCommitted);
+ // private API b/c request.setFrameCommitCallback does not provide access to frameNumber
+ mRenderer.setFrameCompleteCallback(
+ frameNr -> handler.post(() -> frameListener.onFrameComplete(frameNr)));
request.setWaitForPresent(true);
request.syncAndDraw();
}
@@ -225,15 +255,5 @@ public class ScrollCaptureViewSupport<V extends View> implements ScrollCaptureCa
mTempRectF.round(outRect);
}
- private void buildRootDisplayList(View source, Rect localSourceRect) {
- final View captureSource = source.getRootView();
- transformToRoot(source, localSourceRect, mTempRect);
- mRootRenderNode.setPosition(0, 0, mTempRect.width(), mTempRect.height());
- RecordingCanvas canvas = mRootRenderNode.beginRecording(mTempRect.width(),
- mTempRect.height());
- canvas.translate(-mTempRect.left, -mTempRect.top);
- canvas.drawRenderNode(captureSource.updateDisplayListIfDirty());
- mRootRenderNode.endRecording();
- }
}
}
diff --git a/core/java/com/android/internal/view/ScrollViewCaptureHelper.java b/core/java/com/android/internal/view/ScrollViewCaptureHelper.java
index 12bd461f810b..1514b9a285dd 100644
--- a/core/java/com/android/internal/view/ScrollViewCaptureHelper.java
+++ b/core/java/com/android/internal/view/ScrollViewCaptureHelper.java
@@ -35,13 +35,14 @@ import android.view.ViewParent;
* <li>correctly implements {@link ViewParent#requestChildRectangleOnScreen(View,
* Rect, boolean)}
* </ul>
+ *
+ * @see ScrollCaptureViewSupport
*/
public class ScrollViewCaptureHelper implements ScrollCaptureViewHelper<ViewGroup> {
private int mStartScrollY;
private boolean mScrollBarEnabled;
private int mOverScrollMode;
- /** @see ScrollCaptureViewHelper#onPrepareForStart(View, Rect) */
public void onPrepareForStart(@NonNull ViewGroup view, Rect scrollBounds) {
mStartScrollY = view.getScrollY();
mOverScrollMode = view.getOverScrollMode();
@@ -54,8 +55,8 @@ public class ScrollViewCaptureHelper implements ScrollCaptureViewHelper<ViewGrou
}
}
- /** @see ScrollCaptureViewHelper#onScrollRequested(View, Rect, Rect) */
- public Rect onScrollRequested(@NonNull ViewGroup view, Rect scrollBounds, Rect requestRect) {
+ public ScrollResult onScrollRequested(@NonNull ViewGroup view, Rect scrollBounds,
+ Rect requestRect) {
final View contentView = view.getChildAt(0); // returns null, does not throw IOOBE
if (contentView == null) {
return null;
@@ -87,6 +88,9 @@ public class ScrollViewCaptureHelper implements ScrollCaptureViewHelper<ViewGrou
\__ Requested Bounds[0,300 - 200,400] (200x100)
*/
+ ScrollResult result = new ScrollResult();
+ result.requestedArea = new Rect(requestRect);
+
// 0) adjust the requestRect to account for scroll change since start
//
// Scroll Bounds[50,50 - 250,250] (w=200,h=200)
@@ -117,8 +121,6 @@ public class ScrollViewCaptureHelper implements ScrollCaptureViewHelper<ViewGrou
view.getScrollX() - contentView.getLeft(),
view.getScrollY() - contentView.getTop());
-
-
// requestRect is now local to contentView as requestedContentBounds
// contentView (and each parent in turn if possible) will be scrolled
// (if necessary) to make all of requestedContent visible, (if possible!)
@@ -126,35 +128,37 @@ public class ScrollViewCaptureHelper implements ScrollCaptureViewHelper<ViewGrou
// update new offset between starting and current scroll position
scrollDelta = view.getScrollY() - mStartScrollY;
+ result.scrollDelta = scrollDelta;
-
- // TODO: adjust to avoid occlusions/minimize scroll changes
+ // TODO: crop capture area to avoid occlusions/minimize scroll changes
Point offset = new Point();
- final Rect capturedRect = new Rect(requestedContentBounds); // empty
- if (!view.getChildVisibleRect(contentView, capturedRect, offset)) {
- capturedRect.setEmpty();
- return capturedRect;
+ final Rect available = new Rect(requestedContentBounds); // empty
+ if (!view.getChildVisibleRect(contentView, available, offset)) {
+ available.setEmpty();
+ result.availableArea = available;
+ return result;
}
// Transform back from global to content-view local
- capturedRect.offset(-offset.x, -offset.y);
+ available.offset(-offset.x, -offset.y);
// Then back to container view
- capturedRect.offset(
+ available.offset(
contentView.getLeft() - view.getScrollX(),
contentView.getTop() - view.getScrollY());
// And back to relative to scrollBounds
- capturedRect.offset(-scrollBounds.left, -scrollBounds.top);
+ available.offset(-scrollBounds.left, -scrollBounds.top);
- // Apply scrollDelta again to return to make capturedRect relative to scrollBounds at
+ // Apply scrollDelta again to return to make `available` relative to `scrollBounds` at
// the scroll position at start of capture.
- capturedRect.offset(0, scrollDelta);
- return capturedRect;
+ available.offset(0, scrollDelta);
+
+ result.availableArea = new Rect(available);
+ return result;
}
- /** @see ScrollCaptureViewHelper#onPrepareForEnd(View) */
public void onPrepareForEnd(@NonNull ViewGroup view) {
view.scrollTo(0, mStartScrollY);
if (mOverScrollMode != View.OVER_SCROLL_NEVER) {
diff --git a/core/java/com/android/internal/widget/LocalImageResolver.java b/core/java/com/android/internal/widget/LocalImageResolver.java
index 2302de2cd058..b4e108faee2d 100644
--- a/core/java/com/android/internal/widget/LocalImageResolver.java
+++ b/core/java/com/android/internal/widget/LocalImageResolver.java
@@ -23,6 +23,7 @@ import android.graphics.BitmapFactory;
import android.graphics.drawable.BitmapDrawable;
import android.graphics.drawable.Drawable;
import android.net.Uri;
+import android.util.Log;
import java.io.IOException;
import java.io.InputStream;
@@ -31,6 +32,7 @@ import java.io.InputStream;
* A class to extract Bitmaps from a MessagingStyle message.
*/
public class LocalImageResolver {
+ private static final String TAG = LocalImageResolver.class.getSimpleName();
private static final int MAX_SAFE_ICON_SIZE_PX = 480;
@@ -60,11 +62,18 @@ public class LocalImageResolver {
private static BitmapFactory.Options getBoundsOptionsForImage(Uri uri, Context context)
throws IOException {
- InputStream input = context.getContentResolver().openInputStream(uri);
BitmapFactory.Options onlyBoundsOptions = new BitmapFactory.Options();
- onlyBoundsOptions.inJustDecodeBounds = true;
- BitmapFactory.decodeStream(input, null, onlyBoundsOptions);
- input.close();
+ try (InputStream input = context.getContentResolver().openInputStream(uri)) {
+ if (input == null) {
+ throw new IllegalArgumentException();
+ }
+ onlyBoundsOptions.inJustDecodeBounds = true;
+ BitmapFactory.decodeStream(input, null, onlyBoundsOptions);
+ } catch (IllegalArgumentException iae) {
+ onlyBoundsOptions.outWidth = -1;
+ onlyBoundsOptions.outHeight = -1;
+ Log.e(TAG, "error loading image", iae);
+ }
return onlyBoundsOptions;
}
diff --git a/core/java/com/android/internal/widget/LockPatternUtils.java b/core/java/com/android/internal/widget/LockPatternUtils.java
index 960c11f4c55c..08a9f48ec0b4 100644
--- a/core/java/com/android/internal/widget/LockPatternUtils.java
+++ b/core/java/com/android/internal/widget/LockPatternUtils.java
@@ -680,7 +680,7 @@ public class LockPatternUtils {
*/
public boolean setLockCredential(@NonNull LockscreenCredential newCredential,
@NonNull LockscreenCredential savedCredential, int userHandle) {
- if (!hasSecureLockScreen()) {
+ if (!hasSecureLockScreen() && newCredential.getType() != CREDENTIAL_TYPE_NONE) {
throw new UnsupportedOperationException(
"This operation requires the lock screen feature.");
}
@@ -775,7 +775,7 @@ public class LockPatternUtils {
/** Update the encryption password if it is enabled **/
private void updateEncryptionPassword(final int type, final byte[] password) {
- if (!hasSecureLockScreen()) {
+ if (!hasSecureLockScreen() && password != null && password.length != 0) {
throw new UnsupportedOperationException(
"This operation requires the lock screen feature.");
}
@@ -1575,7 +1575,7 @@ public class LockPatternUtils {
*/
public boolean setLockCredentialWithToken(@NonNull LockscreenCredential credential,
long tokenHandle, byte[] token, int userHandle) {
- if (!hasSecureLockScreen()) {
+ if (!hasSecureLockScreen() && credential.getType() != CREDENTIAL_TYPE_NONE) {
throw new UnsupportedOperationException(
"This operation requires the lock screen feature.");
}
diff --git a/core/jni/android_hardware_camera2_CameraMetadata.cpp b/core/jni/android_hardware_camera2_CameraMetadata.cpp
index 9ad4cd9e9ae8..859b40afb7c4 100644
--- a/core/jni/android_hardware_camera2_CameraMetadata.cpp
+++ b/core/jni/android_hardware_camera2_CameraMetadata.cpp
@@ -501,6 +501,15 @@ static void CameraMetadata_readFromParcel(JNIEnv *env, jclass thiz, jobject parc
"Failed to read from parcel (error code %d)", err);
return;
}
+
+ // Update vendor descriptor cache if necessary
+ auto vendorId = metadata->getVendorId();
+ if ((vendorId != CAMERA_METADATA_INVALID_VENDOR_ID) &&
+ !VendorTagDescriptorCache::isVendorCachePresent(vendorId)) {
+ ALOGW("%s: Tag vendor id missing or cache not initialized, trying to update!",
+ __FUNCTION__);
+ CameraMetadata_setupGlobalVendorTagDescriptor(env, thiz);
+ }
}
static void CameraMetadata_writeToParcel(JNIEnv *env, jclass thiz, jobject parcel, jlong ptr) {
@@ -642,9 +651,7 @@ static jint CameraMetadata_getTypeFromTagLocal(JNIEnv *env, jclass thiz, jlong p
CameraMetadata* metadata = CameraMetadata_getPointerNoThrow(ptr);
metadata_vendor_id_t vendorId = CAMERA_METADATA_INVALID_VENDOR_ID;
if (metadata) {
- const camera_metadata_t *metaBuffer = metadata->getAndLock();
- vendorId = get_camera_metadata_vendor_id(metaBuffer);
- metadata->unlock(metaBuffer);
+ vendorId = metadata->getVendorId();
}
int tagType = get_local_camera_metadata_tag_type_vendor_id(tag, vendorId);
@@ -673,9 +680,7 @@ static jint CameraMetadata_getTagFromKeyLocal(JNIEnv *env, jclass thiz, jlong pt
if (metadata) {
sp<VendorTagDescriptorCache> cache = VendorTagDescriptorCache::getGlobalVendorTagCache();
if (cache.get()) {
- const camera_metadata_t *metaBuffer = metadata->getAndLock();
- metadata_vendor_id_t vendorId = get_camera_metadata_vendor_id(metaBuffer);
- metadata->unlock(metaBuffer);
+ auto vendorId = metadata->getVendorId();
cache->getVendorTagDescriptor(vendorId, &vTags);
}
}
@@ -703,10 +708,8 @@ static jobject CameraMetadata_getAllVendorKeys(JNIEnv* env, jclass thiz, jlong p
CameraMetadata* metadata = CameraMetadata_getPointerThrow(env, ptr);
if (metadata == NULL) return NULL;
- const camera_metadata_t *metaBuffer = metadata->getAndLock();
- vendorId = get_camera_metadata_vendor_id(metaBuffer);
+ vendorId = metadata->getVendorId();
cache->getVendorTagDescriptor(vendorId, &vTags);
- metadata->unlock(metaBuffer);
if (vTags.get() == nullptr) {
return nullptr;
}
diff --git a/core/jni/android_media_AudioSystem.cpp b/core/jni/android_media_AudioSystem.cpp
index 3f39478ffd43..5c4c5099bf4c 100644
--- a/core/jni/android_media_AudioSystem.cpp
+++ b/core/jni/android_media_AudioSystem.cpp
@@ -2407,6 +2407,79 @@ static jint android_media_AudioSystem_getDevicesForRoleAndStrategy(JNIEnv *env,
return AUDIO_JAVA_SUCCESS;
}
+static jint android_media_AudioSystem_setDevicesRoleForCapturePreset(
+ JNIEnv *env, jobject thiz, jint capturePreset, jint role, jintArray jDeviceTypes,
+ jobjectArray jDeviceAddresses) {
+ AudioDeviceTypeAddrVector nDevices;
+ jint results = getVectorOfAudioDeviceTypeAddr(env, jDeviceTypes, jDeviceAddresses, nDevices);
+ if (results != NO_ERROR) {
+ return results;
+ }
+ int status = check_AudioSystem_Command(
+ AudioSystem::setDevicesRoleForCapturePreset((audio_source_t)capturePreset,
+ (device_role_t)role, nDevices));
+ return (jint)status;
+}
+
+static jint android_media_AudioSystem_addDevicesRoleForCapturePreset(
+ JNIEnv *env, jobject thiz, jint capturePreset, jint role, jintArray jDeviceTypes,
+ jobjectArray jDeviceAddresses) {
+ AudioDeviceTypeAddrVector nDevices;
+ jint results = getVectorOfAudioDeviceTypeAddr(env, jDeviceTypes, jDeviceAddresses, nDevices);
+ if (results != NO_ERROR) {
+ return results;
+ }
+ int status = check_AudioSystem_Command(
+ AudioSystem::addDevicesRoleForCapturePreset((audio_source_t)capturePreset,
+ (device_role_t)role, nDevices));
+ return (jint)status;
+}
+
+static jint android_media_AudioSystem_removeDevicesRoleForCapturePreset(
+ JNIEnv *env, jobject thiz, jint capturePreset, jint role, jintArray jDeviceTypes,
+ jobjectArray jDeviceAddresses) {
+ AudioDeviceTypeAddrVector nDevices;
+ jint results = getVectorOfAudioDeviceTypeAddr(env, jDeviceTypes, jDeviceAddresses, nDevices);
+ if (results != NO_ERROR) {
+ return results;
+ }
+ int status = check_AudioSystem_Command(
+ AudioSystem::removeDevicesRoleForCapturePreset((audio_source_t)capturePreset,
+ (device_role_t)role, nDevices));
+ return (jint)status;
+}
+
+static jint android_media_AudioSystem_clearDevicesRoleForCapturePreset(JNIEnv *env, jobject thiz,
+ jint capturePreset,
+ jint role) {
+ return (jint)check_AudioSystem_Command(
+ AudioSystem::clearDevicesRoleForCapturePreset((audio_source_t)capturePreset,
+ (device_role_t)role));
+}
+
+static jint android_media_AudioSystem_getDevicesForRoleAndCapturePreset(JNIEnv *env, jobject thiz,
+ jint capturePreset,
+ jint role,
+ jobject jDevices) {
+ AudioDeviceTypeAddrVector nDevices;
+ status_t status = check_AudioSystem_Command(
+ AudioSystem::getDevicesForRoleAndCapturePreset((audio_source_t)capturePreset,
+ (device_role_t)role, nDevices));
+ if (status != NO_ERROR) {
+ return (jint)status;
+ }
+ for (const auto &device : nDevices) {
+ jobject jAudioDeviceAttributes = NULL;
+ jint jStatus = createAudioDeviceAttributesFromNative(env, &jAudioDeviceAttributes, &device);
+ if (jStatus != AUDIO_JAVA_SUCCESS) {
+ return jStatus;
+ }
+ env->CallBooleanMethod(jDevices, gListMethods.add, jAudioDeviceAttributes);
+ env->DeleteLocalRef(jAudioDeviceAttributes);
+ }
+ return AUDIO_JAVA_SUCCESS;
+}
+
static jint
android_media_AudioSystem_getDevicesForAttributes(JNIEnv *env, jobject thiz,
jobject jaa, jobjectArray jDeviceArray)
@@ -2558,6 +2631,16 @@ static const JNINativeMethod gMethods[] =
(void *)android_media_AudioSystem_removeDevicesRoleForStrategy},
{"getDevicesForRoleAndStrategy", "(IILjava/util/List;)I",
(void *)android_media_AudioSystem_getDevicesForRoleAndStrategy},
+ {"setDevicesRoleForCapturePreset", "(II[I[Ljava/lang/String;)I",
+ (void *)android_media_AudioSystem_setDevicesRoleForCapturePreset},
+ {"addDevicesRoleForCapturePreset", "(II[I[Ljava/lang/String;)I",
+ (void *)android_media_AudioSystem_addDevicesRoleForCapturePreset},
+ {"removeDevicesRoleForCapturePreset", "(II[I[Ljava/lang/String;)I",
+ (void *)android_media_AudioSystem_removeDevicesRoleForCapturePreset},
+ {"clearDevicesRoleForCapturePreset", "(II)I",
+ (void *)android_media_AudioSystem_clearDevicesRoleForCapturePreset},
+ {"getDevicesForRoleAndCapturePreset", "(IILjava/util/List;)I",
+ (void *)android_media_AudioSystem_getDevicesForRoleAndCapturePreset},
{"getDevicesForAttributes",
"(Landroid/media/AudioAttributes;[Landroid/media/AudioDeviceAttributes;)I",
(void *)android_media_AudioSystem_getDevicesForAttributes},
diff --git a/core/jni/android_media_AudioTrack.cpp b/core/jni/android_media_AudioTrack.cpp
index 5c045b65be22..7a5c38385f32 100644
--- a/core/jni/android_media_AudioTrack.cpp
+++ b/core/jni/android_media_AudioTrack.cpp
@@ -20,6 +20,7 @@
#include "android_media_AudioTrack.h"
#include <nativehelper/JNIHelp.h>
+#include <nativehelper/ScopedUtfChars.h>
#include "core_jni_helpers.h"
#include <utils/Log.h>
@@ -251,7 +252,7 @@ static jint android_media_AudioTrack_setup(JNIEnv *env, jobject thiz, jobject we
jint audioFormat, jint buffSizeInBytes, jint memoryMode,
jintArray jSession, jlong nativeAudioTrack,
jboolean offload, jint encapsulationMode,
- jobject tunerConfiguration) {
+ jobject tunerConfiguration, jstring opPackageName) {
ALOGV("sampleRates=%p, channel mask=%x, index mask=%x, audioFormat(Java)=%d, buffSize=%d,"
" nativeAudioTrack=0x%" PRIX64 ", offload=%d encapsulationMode=%d tuner=%p",
jSampleRate, channelPositionMask, channelIndexMask, audioFormat, buffSizeInBytes,
@@ -337,7 +338,8 @@ static jint android_media_AudioTrack_setup(JNIEnv *env, jobject thiz, jobject we
}
// create the native AudioTrack object
- lpTrack = new AudioTrack();
+ ScopedUtfChars opPackageNameStr(env, opPackageName);
+ lpTrack = new AudioTrack(opPackageNameStr.c_str());
// read the AudioAttributes values
auto paa = JNIAudioAttributeHelper::makeUnique();
@@ -371,23 +373,24 @@ static jint android_media_AudioTrack_setup(JNIEnv *env, jobject thiz, jobject we
status_t status = NO_ERROR;
switch (memoryMode) {
case MODE_STREAM:
- status = lpTrack->set(
- AUDIO_STREAM_DEFAULT,// stream type, but more info conveyed in paa (last argument)
- sampleRateInHertz,
- format,// word length, PCM
- nativeChannelMask,
- offload ? 0 : frameCount,
- offload ? AUDIO_OUTPUT_FLAG_COMPRESS_OFFLOAD : AUDIO_OUTPUT_FLAG_NONE,
- audioCallback, &(lpJniStorage->mCallbackData),//callback, callback data (user)
- 0,// notificationFrames == 0 since not using EVENT_MORE_DATA to feed the AudioTrack
- 0,// shared mem
- true,// thread can call Java
- sessionId,// audio session ID
- offload ? AudioTrack::TRANSFER_SYNC_NOTIF_CALLBACK : AudioTrack::TRANSFER_SYNC,
- offload ? &offloadInfo : NULL,
- -1, -1, // default uid, pid values
- paa.get());
-
+ status = lpTrack->set(AUDIO_STREAM_DEFAULT, // stream type, but more info conveyed
+ // in paa (last argument)
+ sampleRateInHertz,
+ format, // word length, PCM
+ nativeChannelMask, offload ? 0 : frameCount,
+ offload ? AUDIO_OUTPUT_FLAG_COMPRESS_OFFLOAD
+ : AUDIO_OUTPUT_FLAG_NONE,
+ audioCallback,
+ &(lpJniStorage->mCallbackData), // callback, callback data (user)
+ 0, // notificationFrames == 0 since not using EVENT_MORE_DATA
+ // to feed the AudioTrack
+ 0, // shared mem
+ true, // thread can call Java
+ sessionId, // audio session ID
+ offload ? AudioTrack::TRANSFER_SYNC_NOTIF_CALLBACK
+ : AudioTrack::TRANSFER_SYNC,
+ offload ? &offloadInfo : NULL, -1, -1, // default uid, pid values
+ paa.get());
break;
case MODE_STATIC:
@@ -398,22 +401,22 @@ static jint android_media_AudioTrack_setup(JNIEnv *env, jobject thiz, jobject we
goto native_init_failure;
}
- status = lpTrack->set(
- AUDIO_STREAM_DEFAULT,// stream type, but more info conveyed in paa (last argument)
- sampleRateInHertz,
- format,// word length, PCM
- nativeChannelMask,
- frameCount,
- AUDIO_OUTPUT_FLAG_NONE,
- audioCallback, &(lpJniStorage->mCallbackData),//callback, callback data (user));
- 0,// notificationFrames == 0 since not using EVENT_MORE_DATA to feed the AudioTrack
- lpJniStorage->mMemBase,// shared mem
- true,// thread can call Java
- sessionId,// audio session ID
- AudioTrack::TRANSFER_SHARED,
- NULL, // default offloadInfo
- -1, -1, // default uid, pid values
- paa.get());
+ status = lpTrack->set(AUDIO_STREAM_DEFAULT, // stream type, but more info conveyed
+ // in paa (last argument)
+ sampleRateInHertz,
+ format, // word length, PCM
+ nativeChannelMask, frameCount, AUDIO_OUTPUT_FLAG_NONE,
+ audioCallback,
+ &(lpJniStorage->mCallbackData), // callback, callback data (user)
+ 0, // notificationFrames == 0 since not using EVENT_MORE_DATA
+ // to feed the AudioTrack
+ lpJniStorage->mMemBase, // shared mem
+ true, // thread can call Java
+ sessionId, // audio session ID
+ AudioTrack::TRANSFER_SHARED,
+ NULL, // default offloadInfo
+ -1, -1, // default uid, pid values
+ paa.get());
break;
default:
@@ -1428,7 +1431,8 @@ static const JNINativeMethod gMethods[] = {
{"native_stop", "()V", (void *)android_media_AudioTrack_stop},
{"native_pause", "()V", (void *)android_media_AudioTrack_pause},
{"native_flush", "()V", (void *)android_media_AudioTrack_flush},
- {"native_setup", "(Ljava/lang/Object;Ljava/lang/Object;[IIIIII[IJZILjava/lang/Object;)I",
+ {"native_setup",
+ "(Ljava/lang/Object;Ljava/lang/Object;[IIIIII[IJZILjava/lang/Object;Ljava/lang/String;)I",
(void *)android_media_AudioTrack_setup},
{"native_finalize", "()V", (void *)android_media_AudioTrack_finalize},
{"native_release", "()V", (void *)android_media_AudioTrack_release},
diff --git a/core/jni/android_util_Process.cpp b/core/jni/android_util_Process.cpp
index 23af70a7cc18..c51f334f1f2e 100644
--- a/core/jni/android_util_Process.cpp
+++ b/core/jni/android_util_Process.cpp
@@ -372,22 +372,6 @@ void android_os_Process_setProcessFrozen(
}
}
-void android_os_Process_enableFreezer(
- JNIEnv *env, jobject clazz, jboolean enable)
-{
- bool success = true;
-
- if (enable) {
- success = SetTaskProfiles(0, {"FreezerFrozen"}, true);
- } else {
- success = SetTaskProfiles(0, {"FreezerThawed"}, true);
- }
-
- if (!success) {
- jniThrowException(env, "java/lang/RuntimeException", "Unknown error");
- }
-}
-
jint android_os_Process_getProcessGroup(JNIEnv* env, jobject clazz, jint pid)
{
SchedPolicy sp;
@@ -613,7 +597,7 @@ void android_os_Process_setThreadPriority(JNIEnv* env, jobject clazz,
}
// Do not change sched policy cgroup after boot complete.
- rc = androidSetThreadPriority(pid, pri, !boot_completed);
+ rc = androidSetThreadPriorityAndPolicy(pid, pri, !boot_completed);
if (rc != 0) {
if (rc == INVALID_OPERATION) {
signalExceptionForPriorityError(env, errno, pid);
@@ -1424,7 +1408,6 @@ static const JNINativeMethod methods[] = {
{"sendSignal", "(II)V", (void*)android_os_Process_sendSignal},
{"sendSignalQuiet", "(II)V", (void*)android_os_Process_sendSignalQuiet},
{"setProcessFrozen", "(IIZ)V", (void*)android_os_Process_setProcessFrozen},
- {"enableFreezer", "(Z)V", (void*)android_os_Process_enableFreezer},
{"getFreeMemory", "()J", (void*)android_os_Process_getFreeMemory},
{"getTotalMemory", "()J", (void*)android_os_Process_getTotalMemory},
{"readProcLines", "(Ljava/lang/String;[Ljava/lang/String;[J)V",
diff --git a/core/jni/android_view_InputEventReceiver.cpp b/core/jni/android_view_InputEventReceiver.cpp
index 979a69aa3ce2..9ed71ac0fb7b 100644
--- a/core/jni/android_view_InputEventReceiver.cpp
+++ b/core/jni/android_view_InputEventReceiver.cpp
@@ -22,11 +22,12 @@
#include <nativehelper/JNIHelp.h>
+#include <android-base/stringprintf.h>
#include <android_runtime/AndroidRuntime.h>
+#include <input/InputTransport.h>
#include <log/log.h>
#include <utils/Looper.h>
-#include <utils/Vector.h>
-#include <input/InputTransport.h>
+#include <vector>
#include "android_os_MessageQueue.h"
#include "android_view_InputChannel.h"
#include "android_view_KeyEvent.h"
@@ -52,6 +53,21 @@ static struct {
jmethodID onBatchedInputEventPending;
} gInputEventReceiverClassInfo;
+// Add prefix to the beginning of each line in 'str'
+static std::string addPrefix(std::string str, std::string_view prefix) {
+ str.insert(0, prefix); // insert at the beginning of the first line
+ const size_t prefixLength = prefix.length();
+ size_t pos = prefixLength; // just inserted prefix. start at the end of it
+ while (true) { // process all newline characters in 'str'
+ pos = str.find('\n', pos);
+ if (pos == std::string::npos) {
+ break;
+ }
+ str.insert(pos + 1, prefix); // insert prefix just after the '\n' character
+ pos += prefixLength + 1; // advance the position past the newly inserted prefix
+ }
+ return str;
+}
class NativeInputEventReceiver : public LooperCallback {
public:
@@ -64,6 +80,7 @@ public:
status_t finishInputEvent(uint32_t seq, bool handled);
status_t consumeEvents(JNIEnv* env, bool consumeBatches, nsecs_t frameTime,
bool* outConsumedBatch);
+ std::string dump(const char* prefix);
protected:
virtual ~NativeInputEventReceiver();
@@ -80,7 +97,7 @@ private:
PreallocatedInputEventFactory mInputEventFactory;
bool mBatchedInputEventPending;
int mFdEvents;
- Vector<Finish> mFinishQueue;
+ std::vector<Finish> mFinishQueue;
void setFdEvents(int events);
@@ -128,7 +145,7 @@ status_t NativeInputEventReceiver::finishInputEvent(uint32_t seq, bool handled)
}
status_t status = mInputConsumer.sendFinishedSignal(seq, handled);
- if (status) {
+ if (status != OK) {
if (status == WOULD_BLOCK) {
if (kDebugDispatchCycle) {
ALOGD("channel '%s' ~ Could not send finished signal immediately. "
@@ -137,7 +154,7 @@ status_t NativeInputEventReceiver::finishInputEvent(uint32_t seq, bool handled)
Finish finish;
finish.seq = seq;
finish.handled = handled;
- mFinishQueue.add(finish);
+ mFinishQueue.push_back(finish);
if (mFinishQueue.size() == 1) {
setFdEvents(ALOOPER_EVENT_INPUT | ALOOPER_EVENT_OUTPUT);
}
@@ -162,6 +179,9 @@ void NativeInputEventReceiver::setFdEvents(int events) {
}
int NativeInputEventReceiver::handleEvent(int receiveFd, int events, void* data) {
+ // Allowed return values of this function as documented in LooperCallback::handleEvent
+ constexpr int REMOVE_CALLBACK = 0;
+ constexpr int KEEP_CALLBACK = 1;
if (events & (ALOOPER_EVENT_ERROR | ALOOPER_EVENT_HANGUP)) {
// This error typically occurs when the publisher has closed the input channel
// as part of removing a window or finishing an IME session, in which case
@@ -170,41 +190,42 @@ int NativeInputEventReceiver::handleEvent(int receiveFd, int events, void* data)
ALOGD("channel '%s' ~ Publisher closed input channel or an error occurred. "
"events=0x%x", getInputChannelName().c_str(), events);
}
- return 0; // remove the callback
+ return REMOVE_CALLBACK;
}
if (events & ALOOPER_EVENT_INPUT) {
JNIEnv* env = AndroidRuntime::getJNIEnv();
status_t status = consumeEvents(env, false /*consumeBatches*/, -1, nullptr);
mMessageQueue->raiseAndClearException(env, "handleReceiveCallback");
- return status == OK || status == NO_MEMORY ? 1 : 0;
+ return status == OK || status == NO_MEMORY ? KEEP_CALLBACK : REMOVE_CALLBACK;
}
if (events & ALOOPER_EVENT_OUTPUT) {
for (size_t i = 0; i < mFinishQueue.size(); i++) {
- const Finish& finish = mFinishQueue.itemAt(i);
+ const Finish& finish = mFinishQueue[i];
status_t status = mInputConsumer.sendFinishedSignal(finish.seq, finish.handled);
- if (status) {
- mFinishQueue.removeItemsAt(0, i);
+ if (status != OK) {
+ mFinishQueue.erase(mFinishQueue.begin(), mFinishQueue.begin() + i);
if (status == WOULD_BLOCK) {
if (kDebugDispatchCycle) {
ALOGD("channel '%s' ~ Sent %zu queued finish events; %zu left.",
- getInputChannelName().c_str(), i, mFinishQueue.size());
+ getInputChannelName().c_str(), i, mFinishQueue.size());
}
- return 1; // keep the callback, try again later
+ return KEEP_CALLBACK; // try again later
}
ALOGW("Failed to send finished signal on channel '%s'. status=%d",
getInputChannelName().c_str(), status);
if (status != DEAD_OBJECT) {
JNIEnv* env = AndroidRuntime::getJNIEnv();
- String8 message;
- message.appendFormat("Failed to finish input event. status=%d", status);
- jniThrowRuntimeException(env, message.string());
+ std::string message =
+ android::base::StringPrintf("Failed to finish input event. status=%d",
+ status);
+ jniThrowRuntimeException(env, message.c_str());
mMessageQueue->raiseAndClearException(env, "finishInputEvent");
}
- return 0; // remove the callback
+ return REMOVE_CALLBACK;
}
}
if (kDebugDispatchCycle) {
@@ -213,12 +234,12 @@ int NativeInputEventReceiver::handleEvent(int receiveFd, int events, void* data)
}
mFinishQueue.clear();
setFdEvents(ALOOPER_EVENT_INPUT);
- return 1;
+ return KEEP_CALLBACK;
}
ALOGW("channel '%s' ~ Received spurious callback for unhandled poll event. "
"events=0x%x", getInputChannelName().c_str(), events);
- return 1;
+ return KEEP_CALLBACK;
}
status_t NativeInputEventReceiver::consumeEvents(JNIEnv* env,
@@ -354,6 +375,23 @@ status_t NativeInputEventReceiver::consumeEvents(JNIEnv* env,
}
}
+std::string NativeInputEventReceiver::dump(const char* prefix) {
+ std::string out;
+ std::string consumerDump = addPrefix(mInputConsumer.dump(), " ");
+ out = out + "mInputConsumer:\n" + consumerDump + "\n";
+
+ out += android::base::StringPrintf("mBatchedInputEventPending: %s\n",
+ toString(mBatchedInputEventPending));
+ out = out + "mFinishQueue:\n";
+ for (const Finish& finish : mFinishQueue) {
+ out += android::base::StringPrintf(" seq=%" PRIu32 " handled=%s\n", finish.seq,
+ toString(finish.handled));
+ }
+ if (mFinishQueue.empty()) {
+ out = out + " <empty>\n";
+ }
+ return addPrefix(out, prefix);
+}
static jlong nativeInit(JNIEnv* env, jclass clazz, jobject receiverWeak,
jobject inputChannelObj, jobject messageQueueObj) {
@@ -374,9 +412,10 @@ static jlong nativeInit(JNIEnv* env, jclass clazz, jobject receiverWeak,
receiverWeak, inputChannel, messageQueue);
status_t status = receiver->initialize();
if (status) {
- String8 message;
- message.appendFormat("Failed to initialize input event receiver. status=%d", status);
- jniThrowRuntimeException(env, message.string());
+ std::string message =
+ android::base::StringPrintf("Failed to initialize input event receiver. status=%d",
+ status);
+ jniThrowRuntimeException(env, message.c_str());
return 0;
}
@@ -397,9 +436,9 @@ static void nativeFinishInputEvent(JNIEnv* env, jclass clazz, jlong receiverPtr,
reinterpret_cast<NativeInputEventReceiver*>(receiverPtr);
status_t status = receiver->finishInputEvent(seq, handled);
if (status && status != DEAD_OBJECT) {
- String8 message;
- message.appendFormat("Failed to finish input event. status=%d", status);
- jniThrowRuntimeException(env, message.string());
+ std::string message =
+ android::base::StringPrintf("Failed to finish input event. status=%d", status);
+ jniThrowRuntimeException(env, message.c_str());
}
}
@@ -411,26 +450,31 @@ static jboolean nativeConsumeBatchedInputEvents(JNIEnv* env, jclass clazz, jlong
status_t status = receiver->consumeEvents(env, true /*consumeBatches*/, frameTimeNanos,
&consumedBatch);
if (status && status != DEAD_OBJECT && !env->ExceptionCheck()) {
- String8 message;
- message.appendFormat("Failed to consume batched input event. status=%d", status);
- jniThrowRuntimeException(env, message.string());
+ std::string message =
+ android::base::StringPrintf("Failed to consume batched input event. status=%d",
+ status);
+ jniThrowRuntimeException(env, message.c_str());
return JNI_FALSE;
}
return consumedBatch ? JNI_TRUE : JNI_FALSE;
}
+static jstring nativeDump(JNIEnv* env, jclass clazz, jlong receiverPtr, jstring prefix) {
+ sp<NativeInputEventReceiver> receiver =
+ reinterpret_cast<NativeInputEventReceiver*>(receiverPtr);
+ ScopedUtfChars prefixChars(env, prefix);
+ return env->NewStringUTF(receiver->dump(prefixChars.c_str()).c_str());
+}
static const JNINativeMethod gMethods[] = {
- /* name, signature, funcPtr */
- { "nativeInit",
- "(Ljava/lang/ref/WeakReference;Landroid/view/InputChannel;Landroid/os/MessageQueue;)J",
- (void*)nativeInit },
- { "nativeDispose", "(J)V",
- (void*)nativeDispose },
- { "nativeFinishInputEvent", "(JIZ)V",
- (void*)nativeFinishInputEvent },
- { "nativeConsumeBatchedInputEvents", "(JJ)Z",
- (void*)nativeConsumeBatchedInputEvents },
+ /* name, signature, funcPtr */
+ {"nativeInit",
+ "(Ljava/lang/ref/WeakReference;Landroid/view/InputChannel;Landroid/os/MessageQueue;)J",
+ (void*)nativeInit},
+ {"nativeDispose", "(J)V", (void*)nativeDispose},
+ {"nativeFinishInputEvent", "(JIZ)V", (void*)nativeFinishInputEvent},
+ {"nativeConsumeBatchedInputEvents", "(JJ)Z", (void*)nativeConsumeBatchedInputEvents},
+ {"nativeDump", "(JLjava/lang/String;)Ljava/lang/String;", (void*)nativeDump},
};
int register_android_view_InputEventReceiver(JNIEnv* env) {
diff --git a/core/jni/android_view_KeyCharacterMap.cpp b/core/jni/android_view_KeyCharacterMap.cpp
index 586b26ef328f..cbce38e12d25 100644
--- a/core/jni/android_view_KeyCharacterMap.cpp
+++ b/core/jni/android_view_KeyCharacterMap.cpp
@@ -1,18 +1,18 @@
/*
* Copyright 2006, 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
+ * 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
+ * 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
+ * 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_runtime/AndroidRuntime.h>
@@ -47,9 +47,8 @@ static struct {
class NativeKeyCharacterMap {
public:
- NativeKeyCharacterMap(int32_t deviceId, const sp<KeyCharacterMap>& map) :
- mDeviceId(deviceId), mMap(map) {
- }
+ NativeKeyCharacterMap(int32_t deviceId, std::shared_ptr<KeyCharacterMap> map)
+ : mDeviceId(deviceId), mMap(std::move(map)) {}
~NativeKeyCharacterMap() {
}
@@ -58,26 +57,22 @@ public:
return mDeviceId;
}
- inline const sp<KeyCharacterMap>& getMap() const {
- return mMap;
- }
+ inline const std::shared_ptr<KeyCharacterMap> getMap() const { return mMap; }
private:
int32_t mDeviceId;
- sp<KeyCharacterMap> mMap;
+ std::shared_ptr<KeyCharacterMap> mMap;
};
-
jobject android_view_KeyCharacterMap_create(JNIEnv* env, int32_t deviceId,
- const sp<KeyCharacterMap>& kcm) {
- NativeKeyCharacterMap* map = new NativeKeyCharacterMap(deviceId,
- kcm.get() ? kcm : KeyCharacterMap::empty());
- if (!map) {
- return NULL;
+ const std::shared_ptr<KeyCharacterMap> kcm) {
+ NativeKeyCharacterMap* nativeMap = new NativeKeyCharacterMap(deviceId, kcm);
+ if (!nativeMap) {
+ return nullptr;
}
return env->NewObject(gKeyCharacterMapClassInfo.clazz, gKeyCharacterMapClassInfo.ctor,
- reinterpret_cast<jlong>(map));
+ reinterpret_cast<jlong>(nativeMap));
}
static jlong nativeReadFromParcel(JNIEnv *env, jobject clazz, jobject parcelObj) {
@@ -91,7 +86,7 @@ static jlong nativeReadFromParcel(JNIEnv *env, jobject clazz, jobject parcelObj)
return 0;
}
- sp<KeyCharacterMap> kcm = KeyCharacterMap::readFromParcel(parcel);
+ std::shared_ptr<KeyCharacterMap> kcm = KeyCharacterMap::readFromParcel(parcel);
if (!kcm.get()) {
return 0;
}
@@ -102,6 +97,9 @@ static jlong nativeReadFromParcel(JNIEnv *env, jobject clazz, jobject parcelObj)
static void nativeWriteToParcel(JNIEnv* env, jobject clazz, jlong ptr, jobject parcelObj) {
NativeKeyCharacterMap* map = reinterpret_cast<NativeKeyCharacterMap*>(ptr);
+ if (!map->getMap()) {
+ return;
+ }
Parcel* parcel = parcelForJavaObject(env, parcelObj);
if (parcel) {
parcel->writeInt32(map->getDeviceId());
@@ -150,9 +148,8 @@ static jchar nativeGetMatch(JNIEnv *env, jobject clazz, jlong ptr, jint keyCode,
return 0;
}
- char16_t result = map->getMap()->getMatch(
- keyCode, reinterpret_cast<char16_t*>(chars), size_t(numChars),
- metaState);
+ char16_t result = map->getMap()->getMatch(keyCode, reinterpret_cast<char16_t*>(chars),
+ size_t(numChars), metaState);
env->ReleasePrimitiveArrayCritical(charsArray, chars, JNI_ABORT);
return result;
@@ -180,8 +177,7 @@ static jobjectArray nativeGetEvents(JNIEnv *env, jobject clazz, jlong ptr,
Vector<KeyEvent> events;
jobjectArray result = NULL;
- if (map->getMap()->getEvents(map->getDeviceId(),
- reinterpret_cast<char16_t*>(chars),
+ if (map->getMap()->getEvents(map->getDeviceId(), reinterpret_cast<char16_t*>(chars),
size_t(numChars), events)) {
result = env->NewObjectArray(jsize(events.size()), gKeyEventClassInfo.clazz, NULL);
if (result) {
diff --git a/core/jni/android_view_KeyCharacterMap.h b/core/jni/android_view_KeyCharacterMap.h
index e8465c2a33e3..be0335380f87 100644
--- a/core/jni/android_view_KeyCharacterMap.h
+++ b/core/jni/android_view_KeyCharacterMap.h
@@ -25,7 +25,7 @@ namespace android {
/* Creates a KeyCharacterMap object from the given information. */
extern jobject android_view_KeyCharacterMap_create(JNIEnv* env, int32_t deviceId,
- const sp<KeyCharacterMap>& map);
+ const std::shared_ptr<KeyCharacterMap> kcm);
} // namespace android
diff --git a/core/jni/android_view_KeyEvent.cpp b/core/jni/android_view_KeyEvent.cpp
index 54567e5010c5..8177ec6df803 100644
--- a/core/jni/android_view_KeyEvent.cpp
+++ b/core/jni/android_view_KeyEvent.cpp
@@ -20,6 +20,7 @@
#include <android_runtime/AndroidRuntime.h>
#include <android_runtime/Log.h>
+#include <attestation/HmacKeyManager.h>
#include <input/Input.h>
#include <nativehelper/ScopedPrimitiveArray.h>
#include <nativehelper/ScopedUtfChars.h>
diff --git a/core/jni/android_view_MotionEvent.cpp b/core/jni/android_view_MotionEvent.cpp
index 2e396f247979..ce8b59941a5a 100644
--- a/core/jni/android_view_MotionEvent.cpp
+++ b/core/jni/android_view_MotionEvent.cpp
@@ -21,12 +21,13 @@
#include <android/graphics/matrix.h>
#include <android_runtime/AndroidRuntime.h>
#include <android_runtime/Log.h>
-#include <utils/Log.h>
+#include <attestation/HmacKeyManager.h>
#include <input/Input.h>
#include <nativehelper/ScopedUtfChars.h>
+#include <utils/Log.h>
#include "android_os_Parcel.h"
-#include "android_view_MotionEvent.h"
#include "android_util_Binder.h"
+#include "android_view_MotionEvent.h"
#include "core_jni_helpers.h"
diff --git a/core/proto/android/app/settings_enums.proto b/core/proto/android/app/settings_enums.proto
index 6eb89040998a..6212bcbbc05f 100644
--- a/core/proto/android/app/settings_enums.proto
+++ b/core/proto/android/app/settings_enums.proto
@@ -2738,4 +2738,14 @@ enum PageId {
// CATEGORY: SETTINGS
// OS: S
SETTINGS_COLUMBUS = 1848;
+
+ // OPEN: Settings > Accessibility > Magnification > Settings > Magnification area > Magnification switch shortcut dialog
+ // CATEGORY: SETTINGS
+ // OS: S
+ DIALOG_MAGNIFICATION_SWITCH_SHORTCUT = 1849;
+
+ // OPEN: Settings > Network & internet > Adaptive connectivity
+ // CATEGORY: SETTINGS
+ // OS: R QPR
+ ADAPTIVE_CONNECTIVITY_CATEGORY = 1850;
}
diff --git a/core/res/AndroidManifest.xml b/core/res/AndroidManifest.xml
index 57c1fcf7bfb4..cdcb24b6a247 100644
--- a/core/res/AndroidManifest.xml
+++ b/core/res/AndroidManifest.xml
@@ -3094,7 +3094,8 @@
android:protectionLevel="signature" />
<!-- Allows an application to be the status bar. Currently used only by SystemUI.apk
- @hide -->
+ @hide
+ @SystemApi -->
<permission android:name="android.permission.STATUS_BAR_SERVICE"
android:protectionLevel="signature" />
diff --git a/core/res/res/values-cs/strings.xml b/core/res/res/values-cs/strings.xml
index 34e6efb2bf78..fcf9b837cfa1 100644
--- a/core/res/res/values-cs/strings.xml
+++ b/core/res/res/values-cs/strings.xml
@@ -1261,7 +1261,7 @@
<string name="volume_ringtone" msgid="134784084629229029">"Hlasitost vyzvánění"</string>
<string name="volume_music" msgid="7727274216734955095">"Hlasitost médií"</string>
<string name="volume_music_hint_playing_through_bluetooth" msgid="2614142915948898228">"Přehrávání pomocí rozhraní Bluetooth"</string>
- <string name="volume_music_hint_silent_ringtone_selected" msgid="1514829655029062233">"Je nastaven tichý vyzváněcí tón"</string>
+ <string name="volume_music_hint_silent_ringtone_selected" msgid="1514829655029062233">"Je nastaven tichý vyzvánění"</string>
<string name="volume_call" msgid="7625321655265747433">"Hlasitost hovoru"</string>
<string name="volume_bluetooth_call" msgid="2930204618610115061">"Hlasitost příchozích hovorů při připojení Bluetooth"</string>
<string name="volume_alarm" msgid="4486241060751798448">"Hlasitost budíku"</string>
@@ -1272,10 +1272,10 @@
<string name="volume_icon_description_incall" msgid="4491255105381227919">"Hlasitost hovoru"</string>
<string name="volume_icon_description_media" msgid="4997633254078171233">"Hlasitost médií"</string>
<string name="volume_icon_description_notification" msgid="579091344110747279">"Hlasitost oznámení"</string>
- <string name="ringtone_default" msgid="9118299121288174597">"Výchozí vyzváněcí tón"</string>
+ <string name="ringtone_default" msgid="9118299121288174597">"Výchozí vyzvánění"</string>
<string name="ringtone_default_with_actual" msgid="2709686194556159773">"Výchozí (<xliff:g id="ACTUAL_RINGTONE">%1$s</xliff:g>)"</string>
<string name="ringtone_silent" msgid="397111123930141876">"Žádný"</string>
- <string name="ringtone_picker_title" msgid="667342618626068253">"Vyzváněcí tóny"</string>
+ <string name="ringtone_picker_title" msgid="667342618626068253">"Vyzvánění"</string>
<string name="ringtone_picker_title_alarm" msgid="7438934548339024767">"Zvuky budíku"</string>
<string name="ringtone_picker_title_notification" msgid="6387191794719608122">"Zvuky upozornění"</string>
<string name="ringtone_unknown" msgid="5059495249862816475">"Neznámé"</string>
diff --git a/core/res/res/values-da/strings.xml b/core/res/res/values-da/strings.xml
index 117fecb0ffd0..0b7e396839ef 100644
--- a/core/res/res/values-da/strings.xml
+++ b/core/res/res/values-da/strings.xml
@@ -657,7 +657,7 @@
<string name="permlab_accessNetworkConditions" msgid="1270732533356286514">"observer netværksforhold"</string>
<string name="permdesc_accessNetworkConditions" msgid="2959269186741956109">"Tillader, at en applikation observerer netværksforhold. Bør aldrig være nødvendigt for almindelige apps."</string>
<string name="permlab_setInputCalibration" msgid="932069700285223434">"skift kalibrering for inputenheden"</string>
- <string name="permdesc_setInputCalibration" msgid="2937872391426631726">"Tillader, at appen ændrer kalibreringsparametrene for berøringsskærmen. Dette bør aldrig være nødvendigt for almindelige apps."</string>
+ <string name="permdesc_setInputCalibration" msgid="2937872391426631726">"Tillader, at appen ændrer kalibreringsparametrene for touchskærmen. Dette bør aldrig være nødvendigt for almindelige apps."</string>
<string name="permlab_accessDrmCertificates" msgid="6473765454472436597">"få adgang til DRM-certifikater"</string>
<string name="permdesc_accessDrmCertificates" msgid="6983139753493781941">"Tillader, at en applikation provisionerer og anvender DRM-certifikater. Dette bør aldrig være nødvendigt for almindelige apps."</string>
<string name="permlab_handoverStatus" msgid="7620438488137057281">"modtag status for Android Beam-overførsler"</string>
diff --git a/core/res/res/values-eu/strings.xml b/core/res/res/values-eu/strings.xml
index ecce980c613f..c93dbbfda5ef 100644
--- a/core/res/res/values-eu/strings.xml
+++ b/core/res/res/values-eu/strings.xml
@@ -484,8 +484,8 @@
<string name="permdesc_setTimeZone" product="default" msgid="4611828585759488256">"Telefonoaren ordu-zona aldatzeko baimena ematen die aplikazioei."</string>
<string name="permlab_getAccounts" msgid="5304317160463582791">"bilatu gailuko kontuak"</string>
<string name="permdesc_getAccounts" product="tablet" msgid="1784452755887604512">"Tabletak ezagutzen dituen kontuen zerrenda lortzeko baimena ematen die aplikazioei. Instalatuta dauzkazun aplikazioek sortutako kontuak har daitezke barnean."</string>
- <string name="permdesc_getAccounts" product="tv" msgid="437604680436540822">"Android TV gailuak ezagutzen dituen kontuen zerrenda lortzeko baimena ematen die aplikazioei. Kontu horien artean, instalatuta dituzun aplikazioek sortutako kontuak egon litezke."</string>
- <string name="permdesc_getAccounts" product="default" msgid="2491273043569751867">"Telefonoak ezagutzen dituen kontuen zerrenda lortzeko baimena ematen die aplikazioei. Instalatuta dituzun aplikazioek sortutako kontuak har daitezke barnean."</string>
+ <string name="permdesc_getAccounts" product="tv" msgid="437604680436540822">"Android TV gailuak ezagutzen dituen kontuen zerrenda lortzeko baimena ematen die aplikazioei. Kontu horien artean, instalatuta dauzkazun aplikazioek sortutako kontuak egon litezke."</string>
+ <string name="permdesc_getAccounts" product="default" msgid="2491273043569751867">"Telefonoak ezagutzen dituen kontuen zerrenda lortzeko baimena ematen die aplikazioei. Instalatuta dauzkazun aplikazioek sortutako kontuak har daitezke barnean."</string>
<string name="permlab_accessNetworkState" msgid="2349126720783633918">"ikusi sareko konexioak"</string>
<string name="permdesc_accessNetworkState" msgid="4394564702881662849">"Sareko konexioei buruzko informazioa ikusteko baimena ematen die aplikazioei; adibidez, zer sare dauden eta zeintzuk dauden konektatuta."</string>
<string name="permlab_createNetworkSockets" msgid="3224420491603590541">"izan sarerako sarbide osoa"</string>
diff --git a/core/res/res/values-in/strings.xml b/core/res/res/values-in/strings.xml
index f9e3e2fa97e7..f4fb83deba39 100644
--- a/core/res/res/values-in/strings.xml
+++ b/core/res/res/values-in/strings.xml
@@ -2035,7 +2035,7 @@
<string name="usb_device_resolve_prompt_warn" msgid="325871329788064199">"Aplikasi ini tidak diberi izin merekam, tetapi dapat merekam audio melalui perangkat USB ini."</string>
<string name="accessibility_system_action_home_label" msgid="3234748160850301870">"Beranda"</string>
<string name="accessibility_system_action_back_label" msgid="4205361367345537608">"Kembali"</string>
- <string name="accessibility_system_action_recents_label" msgid="4782875610281649728">"Aplikasi yang Baru Dipakai"</string>
+ <string name="accessibility_system_action_recents_label" msgid="4782875610281649728">"Aplikasi Terbaru"</string>
<string name="accessibility_system_action_notifications_label" msgid="6083767351772162010">"Notifikasi"</string>
<string name="accessibility_system_action_quick_settings_label" msgid="4583900123506773783">"Setelan Cepat"</string>
<string name="accessibility_system_action_power_dialog_label" msgid="8095341821683910781">"Dialog Daya"</string>
diff --git a/core/res/res/values-ne/strings.xml b/core/res/res/values-ne/strings.xml
index bb79c2193a36..ee0362e4a184 100644
--- a/core/res/res/values-ne/strings.xml
+++ b/core/res/res/values-ne/strings.xml
@@ -304,13 +304,13 @@
<string name="permgrouplab_sms" msgid="795737735126084874">"SMS"</string>
<string name="permgroupdesc_sms" msgid="5726462398070064542">"SMS सन्देशहरू पठाउनुहोस् र हेर्नुहोस्"</string>
<string name="permgrouplab_storage" msgid="1938416135375282333">"फाइल र मिडिया"</string>
- <string name="permgroupdesc_storage" msgid="6351503740613026600">"तपाईंको यन्त्रमा तस्बिर, मिडिया, र फाइलहरूमाथि पहुँच गर्नुहोस्"</string>
+ <string name="permgroupdesc_storage" msgid="6351503740613026600">"तपाईंको यन्त्रमा फोटो, मिडिया, र फाइलहरूमाथि पहुँच गर्नुहोस्"</string>
<string name="permgrouplab_microphone" msgid="2480597427667420076">"माइक्रोफोन"</string>
<string name="permgroupdesc_microphone" msgid="1047786732792487722">"अडियो रेकर्ड गर्नुहोस्"</string>
<string name="permgrouplab_activityRecognition" msgid="3324466667921775766">"शारीरिक क्रियाकलाप"</string>
<string name="permgroupdesc_activityRecognition" msgid="4725624819457670704">"आफ्नो शारीरिक क्रियाकलापको डेटामाथि पहुँच राख्नु"</string>
<string name="permgrouplab_camera" msgid="9090413408963547706">"क्यामेरा"</string>
- <string name="permgroupdesc_camera" msgid="7585150538459320326">"तस्बिर खिच्नुका साथै भिडियो रेकर्ड गर्नुहोस्"</string>
+ <string name="permgroupdesc_camera" msgid="7585150538459320326">"फोटो खिच्नुका साथै भिडियो रेकर्ड गर्नुहोस्"</string>
<string name="permgrouplab_calllog" msgid="7926834372073550288">"कलका लगहरू"</string>
<string name="permgroupdesc_calllog" msgid="2026996642917801803">"फोन कलको लग पढ्नुहोस् र लेख्नुहोस्"</string>
<string name="permgrouplab_phone" msgid="570318944091926620">"फोन"</string>
@@ -437,10 +437,10 @@
<string name="permdesc_sim_communication" msgid="4179799296415957960">"SIM लाई आदेश पठाउन एपलाई अनुमति दिन्छ। यो निकै खतरनाक हुन्छ।"</string>
<string name="permlab_activityRecognition" msgid="1782303296053990884">"शारीरिक गतिविधि पहिचान गर्नुहोस्‌"</string>
<string name="permdesc_activityRecognition" msgid="8667484762991357519">"यो अनुप्रयोगले तपाईंको शारीरिक गतिविधिको पहिचान गर्न सक्छ।"</string>
- <string name="permlab_camera" msgid="6320282492904119413">"तस्बिरहरू र भिडियोहरू लिनुहोस्।"</string>
- <string name="permdesc_camera" msgid="1354600178048761499">"यस अनुप्रयोगले जुनसुकै समय क्यामेराको प्रयोग गरी तस्बिर खिच्न र भिडियो रेकर्ड गर्न सक्छ।"</string>
- <string name="permlab_systemCamera" msgid="3642917457796210580">"एप वा सेवालाई तस्बिर र भिडियो खिच्न प्रणालीका क्यामेराहरूमाथि पहुँच राख्न दिनुहोस्"</string>
- <string name="permdesc_systemCamera" msgid="5938360914419175986">"प्रणालीको यस विशेषाधिकार प्राप्त अनुप्रयोगले जुनसुकै बेला प्रणालीको क्यामेरा प्रयोग गरी तस्बिर खिच्न र भिडियो रेकर्ड गर्न सक्छ। अनुप्रयोगसँग पनि android.permission.CAMERA प्रयोग गर्ने अनुमति हुनु पर्छ"</string>
+ <string name="permlab_camera" msgid="6320282492904119413">"फोटोहरू र भिडियोहरू लिनुहोस्।"</string>
+ <string name="permdesc_camera" msgid="1354600178048761499">"यस अनुप्रयोगले जुनसुकै समय क्यामेराको प्रयोग गरी फोटो खिच्न र भिडियो रेकर्ड गर्न सक्छ।"</string>
+ <string name="permlab_systemCamera" msgid="3642917457796210580">"एप वा सेवालाई फोटो र भिडियो खिच्न प्रणालीका क्यामेराहरूमाथि पहुँच राख्न दिनुहोस्"</string>
+ <string name="permdesc_systemCamera" msgid="5938360914419175986">"प्रणालीको यस विशेषाधिकार प्राप्त अनुप्रयोगले जुनसुकै बेला प्रणालीको क्यामेरा प्रयोग गरी फोटो खिच्न र भिडियो रेकर्ड गर्न सक्छ। अनुप्रयोगसँग पनि android.permission.CAMERA प्रयोग गर्ने अनुमति हुनु पर्छ"</string>
<string name="permlab_cameraOpenCloseListener" msgid="5548732769068109315">"कुनै एप वा सेवालाई खोलिँदै वा बन्द गरिँदै गरेका क्यामेरा यन्त्रहरूका बारेमा कलब्याक प्राप्त गर्ने अनुमति दिनुहोस्।"</string>
<string name="permdesc_cameraOpenCloseListener" msgid="2002636131008772908">"कुनै क्यामेरा यन्त्र खोलिँदा (कुन अनुप्रयोगले खोलेको भन्ने बारेमा) वा बन्द गरिँदा यो अनुप्रयोगले कलब्याक प्राप्त गर्न सक्छ।"</string>
<string name="permlab_vibrate" msgid="8596800035791962017">"कम्पन नियन्त्रण गर्नुहोस्"</string>
@@ -1347,7 +1347,7 @@
<string name="ext_media_new_notification_title" product="automotive" msgid="9085349544984742727">"<xliff:g id="NAME">%s</xliff:g> ले काम गरिरहेको छैन"</string>
<string name="ext_media_new_notification_message" msgid="6095403121990786986">"सेटअप गर्न ट्याप गर्नुहोस्"</string>
<string name="ext_media_new_notification_message" product="automotive" msgid="5140127881613227162">"तपाईंले यो यन्त्र पुनः फर्म्याट गर्नु पर्ने हुन सक्छ। यो यन्त्र हटाउन ट्याप गर्नुहोस्।"</string>
- <string name="ext_media_ready_notification_message" msgid="777258143284919261">"तस्बिरहरू र मिडिया स्थानान्तरणका लागि"</string>
+ <string name="ext_media_ready_notification_message" msgid="777258143284919261">"फोटोहरू र मिडिया स्थानान्तरणका लागि"</string>
<string name="ext_media_unmountable_notification_title" msgid="4895444667278979910">"<xliff:g id="NAME">%s</xliff:g> मा समस्या देखियो"</string>
<string name="ext_media_unmountable_notification_title" product="automotive" msgid="3142723758949023280">"<xliff:g id="NAME">%s</xliff:g> ले काम गरिरहेको छैन"</string>
<string name="ext_media_unmountable_notification_message" msgid="3256290114063126205">"समस्या समाधान गर्न ट्याप गर्नुहोस्"</string>
@@ -1914,7 +1914,7 @@
<string name="app_category_game" msgid="4534216074910244790">"खेलहरू"</string>
<string name="app_category_audio" msgid="8296029904794676222">"सङ्गीत तथा अडियो"</string>
<string name="app_category_video" msgid="2590183854839565814">"चलचित्र तथा भिडियो"</string>
- <string name="app_category_image" msgid="7307840291864213007">"तस्बिर तथा छविहरू"</string>
+ <string name="app_category_image" msgid="7307840291864213007">"फोटो तथा छविहरू"</string>
<string name="app_category_social" msgid="2278269325488344054">"सामाजिक तथा सञ्चार"</string>
<string name="app_category_news" msgid="1172762719574964544">"समाचार तथा पत्रिकाहरू"</string>
<string name="app_category_maps" msgid="6395725487922533156">"नक्सा तथा नेभिगेसन"</string>
diff --git a/core/tests/coretests/src/android/app/timezonedetector/TimeZoneCapabilitiesTest.java b/core/tests/coretests/src/android/app/timezonedetector/TimeZoneCapabilitiesTest.java
index 72391f4d7dec..db127c6cb9ed 100644
--- a/core/tests/coretests/src/android/app/timezonedetector/TimeZoneCapabilitiesTest.java
+++ b/core/tests/coretests/src/android/app/timezonedetector/TimeZoneCapabilitiesTest.java
@@ -22,6 +22,7 @@ import static android.app.timezonedetector.TimeZoneCapabilities.CAPABILITY_POSSE
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNotEquals;
+import static org.junit.Assert.assertNull;
import org.junit.Test;
@@ -31,11 +32,22 @@ public class TimeZoneCapabilitiesTest {
@Test
public void testEquals() {
- TimeZoneCapabilities.Builder builder1 = new TimeZoneCapabilities.Builder(ARBITRARY_USER_ID)
+ TimeZoneConfiguration configuration1 = new TimeZoneConfiguration.Builder(ARBITRARY_USER_ID)
+ .setAutoDetectionEnabled(true)
+ .setGeoDetectionEnabled(true)
+ .build();
+ TimeZoneConfiguration configuration2 = new TimeZoneConfiguration.Builder(ARBITRARY_USER_ID)
+ .setAutoDetectionEnabled(false)
+ .setGeoDetectionEnabled(false)
+ .build();
+
+ TimeZoneCapabilities.Builder builder1 = new TimeZoneCapabilities.Builder()
+ .setConfiguration(configuration1)
.setConfigureAutoDetectionEnabled(CAPABILITY_POSSESSED)
.setConfigureGeoDetectionEnabled(CAPABILITY_POSSESSED)
.setSuggestManualTimeZone(CAPABILITY_POSSESSED);
- TimeZoneCapabilities.Builder builder2 = new TimeZoneCapabilities.Builder(ARBITRARY_USER_ID)
+ TimeZoneCapabilities.Builder builder2 = new TimeZoneCapabilities.Builder()
+ .setConfiguration(configuration1)
.setConfigureAutoDetectionEnabled(CAPABILITY_POSSESSED)
.setConfigureGeoDetectionEnabled(CAPABILITY_POSSESSED)
.setSuggestManualTimeZone(CAPABILITY_POSSESSED);
@@ -45,6 +57,20 @@ public class TimeZoneCapabilitiesTest {
assertEquals(one, two);
}
+ builder2.setConfiguration(configuration2);
+ {
+ TimeZoneCapabilities one = builder1.build();
+ TimeZoneCapabilities two = builder2.build();
+ assertNotEquals(one, two);
+ }
+
+ builder1.setConfiguration(configuration2);
+ {
+ TimeZoneCapabilities one = builder1.build();
+ TimeZoneCapabilities two = builder2.build();
+ assertEquals(one, two);
+ }
+
builder2.setConfigureAutoDetectionEnabled(CAPABILITY_NOT_ALLOWED);
{
TimeZoneCapabilities one = builder1.build();
@@ -90,7 +116,12 @@ public class TimeZoneCapabilitiesTest {
@Test
public void testParcelable() {
- TimeZoneCapabilities.Builder builder = new TimeZoneCapabilities.Builder(ARBITRARY_USER_ID)
+ TimeZoneConfiguration configuration = new TimeZoneConfiguration.Builder(ARBITRARY_USER_ID)
+ .setAutoDetectionEnabled(true)
+ .setGeoDetectionEnabled(true)
+ .build();
+ TimeZoneCapabilities.Builder builder = new TimeZoneCapabilities.Builder()
+ .setConfiguration(configuration)
.setConfigureAutoDetectionEnabled(CAPABILITY_POSSESSED)
.setConfigureGeoDetectionEnabled(CAPABILITY_POSSESSED)
.setSuggestManualTimeZone(CAPABILITY_POSSESSED);
@@ -105,4 +136,51 @@ public class TimeZoneCapabilitiesTest {
builder.setSuggestManualTimeZone(CAPABILITY_NOT_ALLOWED);
assertRoundTripParcelable(builder.build());
}
+
+ @Test
+ public void testApplyUpdate_permitted() {
+ TimeZoneConfiguration oldConfiguration =
+ new TimeZoneConfiguration.Builder(ARBITRARY_USER_ID)
+ .setAutoDetectionEnabled(true)
+ .setGeoDetectionEnabled(true)
+ .build();
+ TimeZoneCapabilities capabilities = new TimeZoneCapabilities.Builder()
+ .setConfiguration(oldConfiguration)
+ .setConfigureAutoDetectionEnabled(CAPABILITY_POSSESSED)
+ .setConfigureGeoDetectionEnabled(CAPABILITY_POSSESSED)
+ .setSuggestManualTimeZone(CAPABILITY_POSSESSED)
+ .build();
+ assertEquals(oldConfiguration, capabilities.getConfiguration());
+
+ TimeZoneConfiguration configChange = new TimeZoneConfiguration.Builder(ARBITRARY_USER_ID)
+ .setAutoDetectionEnabled(false)
+ .build();
+
+ TimeZoneConfiguration expected = new TimeZoneConfiguration.Builder(oldConfiguration)
+ .setAutoDetectionEnabled(false)
+ .build();
+ assertEquals(expected, capabilities.applyUpdate(configChange));
+ }
+
+ @Test
+ public void testApplyUpdate_notPermitted() {
+ TimeZoneConfiguration oldConfiguration =
+ new TimeZoneConfiguration.Builder(ARBITRARY_USER_ID)
+ .setAutoDetectionEnabled(true)
+ .setGeoDetectionEnabled(true)
+ .build();
+ TimeZoneCapabilities capabilities = new TimeZoneCapabilities.Builder()
+ .setConfiguration(oldConfiguration)
+ .setConfigureAutoDetectionEnabled(CAPABILITY_NOT_ALLOWED)
+ .setConfigureGeoDetectionEnabled(CAPABILITY_NOT_ALLOWED)
+ .setSuggestManualTimeZone(CAPABILITY_NOT_ALLOWED)
+ .build();
+ assertEquals(oldConfiguration, capabilities.getConfiguration());
+
+ TimeZoneConfiguration configChange = new TimeZoneConfiguration.Builder(ARBITRARY_USER_ID)
+ .setAutoDetectionEnabled(false)
+ .build();
+
+ assertNull(capabilities.applyUpdate(configChange));
+ }
}
diff --git a/core/tests/coretests/src/android/app/timezonedetector/TimeZoneConfigurationTest.java b/core/tests/coretests/src/android/app/timezonedetector/TimeZoneConfigurationTest.java
index 00dc73ed269f..faf908de8d4a 100644
--- a/core/tests/coretests/src/android/app/timezonedetector/TimeZoneConfigurationTest.java
+++ b/core/tests/coretests/src/android/app/timezonedetector/TimeZoneConfigurationTest.java
@@ -27,11 +27,14 @@ import org.junit.Test;
public class TimeZoneConfigurationTest {
+ private static final int ARBITRARY_USER_ID = 9876;
+
@Test
public void testBuilder_copyConstructor() {
- TimeZoneConfiguration.Builder builder1 = new TimeZoneConfiguration.Builder()
- .setAutoDetectionEnabled(true)
- .setGeoDetectionEnabled(true);
+ TimeZoneConfiguration.Builder builder1 =
+ new TimeZoneConfiguration.Builder(ARBITRARY_USER_ID)
+ .setAutoDetectionEnabled(true)
+ .setGeoDetectionEnabled(true);
TimeZoneConfiguration configuration1 = builder1.build();
TimeZoneConfiguration configuration2 =
@@ -41,28 +44,28 @@ public class TimeZoneConfigurationTest {
}
@Test
- public void testIsComplete() {
- TimeZoneConfiguration.Builder builder =
- new TimeZoneConfiguration.Builder();
- assertFalse(builder.build().isComplete());
-
- builder.setAutoDetectionEnabled(true);
- assertFalse(builder.build().isComplete());
+ public void testIntrospectionMethods() {
+ TimeZoneConfiguration empty = new TimeZoneConfiguration.Builder(ARBITRARY_USER_ID).build();
+ assertFalse(empty.isComplete());
+ assertFalse(empty.hasSetting(TimeZoneConfiguration.SETTING_AUTO_DETECTION_ENABLED));
- builder.setGeoDetectionEnabled(true);
- assertTrue(builder.build().isComplete());
+ TimeZoneConfiguration completeConfig = new TimeZoneConfiguration.Builder(ARBITRARY_USER_ID)
+ .setAutoDetectionEnabled(true)
+ .setGeoDetectionEnabled(true)
+ .build();
+ assertTrue(completeConfig.isComplete());
+ assertTrue(completeConfig.hasSetting(TimeZoneConfiguration.SETTING_AUTO_DETECTION_ENABLED));
}
@Test
public void testBuilder_mergeProperties() {
- TimeZoneConfiguration configuration1 =
- new TimeZoneConfiguration.Builder()
- .setAutoDetectionEnabled(true)
- .build();
+ TimeZoneConfiguration configuration1 = new TimeZoneConfiguration.Builder(ARBITRARY_USER_ID)
+ .setAutoDetectionEnabled(true)
+ .build();
{
TimeZoneConfiguration mergedEmptyAnd1 =
- new TimeZoneConfiguration.Builder()
+ new TimeZoneConfiguration.Builder(ARBITRARY_USER_ID)
.mergeProperties(configuration1)
.build();
assertEquals(configuration1, mergedEmptyAnd1);
@@ -70,7 +73,7 @@ public class TimeZoneConfigurationTest {
{
TimeZoneConfiguration configuration2 =
- new TimeZoneConfiguration.Builder()
+ new TimeZoneConfiguration.Builder(ARBITRARY_USER_ID)
.setAutoDetectionEnabled(false)
.build();
@@ -87,14 +90,22 @@ public class TimeZoneConfigurationTest {
@Test
public void testEquals() {
TimeZoneConfiguration.Builder builder1 =
- new TimeZoneConfiguration.Builder();
+ new TimeZoneConfiguration.Builder(ARBITRARY_USER_ID);
{
TimeZoneConfiguration one = builder1.build();
assertEquals(one, one);
}
+ {
+ TimeZoneConfiguration.Builder differentUserBuilder =
+ new TimeZoneConfiguration.Builder(ARBITRARY_USER_ID + 1);
+ TimeZoneConfiguration one = builder1.build();
+ TimeZoneConfiguration two = differentUserBuilder.build();
+ assertNotEquals(one, two);
+ }
+
TimeZoneConfiguration.Builder builder2 =
- new TimeZoneConfiguration.Builder();
+ new TimeZoneConfiguration.Builder(ARBITRARY_USER_ID);
{
TimeZoneConfiguration one = builder1.build();
TimeZoneConfiguration two = builder2.build();
@@ -148,7 +159,7 @@ public class TimeZoneConfigurationTest {
@Test
public void testParcelable() {
TimeZoneConfiguration.Builder builder =
- new TimeZoneConfiguration.Builder();
+ new TimeZoneConfiguration.Builder(ARBITRARY_USER_ID);
assertRoundTripParcelable(builder.build());
builder.setAutoDetectionEnabled(true);
diff --git a/core/tests/coretests/src/android/text/OWNERS b/core/tests/coretests/src/android/text/OWNERS
index a35c6042bf53..0b51b2d90b79 100644
--- a/core/tests/coretests/src/android/text/OWNERS
+++ b/core/tests/coretests/src/android/text/OWNERS
@@ -1,5 +1,4 @@
set noparent
siyamed@google.com
-nona@google.com
-clarabayarri@google.com \ No newline at end of file
+nona@google.com \ No newline at end of file
diff --git a/core/tests/coretests/src/android/view/ViewRootImplTest.java b/core/tests/coretests/src/android/view/ViewRootImplTest.java
index 5c16772488d0..4cf6715ba0ca 100644
--- a/core/tests/coretests/src/android/view/ViewRootImplTest.java
+++ b/core/tests/coretests/src/android/view/ViewRootImplTest.java
@@ -24,6 +24,7 @@ import static android.view.View.SYSTEM_UI_FLAG_LIGHT_STATUS_BAR;
import static android.view.View.SYSTEM_UI_FLAG_LOW_PROFILE;
import static android.view.WindowInsetsController.BEHAVIOR_SHOW_BARS_BY_TOUCH;
import static android.view.WindowManager.LayoutParams.FLAG_LAYOUT_IN_SCREEN;
+import static android.view.WindowManager.LayoutParams.SOFT_INPUT_ADJUST_RESIZE;
import static android.view.WindowManager.LayoutParams.TYPE_APPLICATION;
import static android.view.WindowManager.LayoutParams.TYPE_SYSTEM_ALERT;
import static android.view.WindowManager.LayoutParams.TYPE_TOAST;
@@ -117,7 +118,15 @@ public class ViewRootImplTest {
final WindowManager.LayoutParams attrs = new WindowManager.LayoutParams(TYPE_APPLICATION);
ViewRootImpl.adjustLayoutParamsForCompatibility(attrs);
- // A window which fits system bars must fit IME, unless its type is toast or system alert.
+ assertEquals(Type.systemBars(), attrs.getFitInsetsTypes());
+ }
+
+ @Test
+ public void adjustLayoutParamsForCompatibility_fitSystemBarsAndIme() {
+ final WindowManager.LayoutParams attrs = new WindowManager.LayoutParams(TYPE_APPLICATION);
+ attrs.softInputMode |= SOFT_INPUT_ADJUST_RESIZE;
+ ViewRootImpl.adjustLayoutParamsForCompatibility(attrs);
+
assertEquals(Type.systemBars() | Type.ime(), attrs.getFitInsetsTypes());
}
diff --git a/core/tests/coretests/src/com/android/internal/jank/FrameTrackerTest.java b/core/tests/coretests/src/com/android/internal/jank/FrameTrackerTest.java
new file mode 100644
index 000000000000..ece5037de15f
--- /dev/null
+++ b/core/tests/coretests/src/com/android/internal/jank/FrameTrackerTest.java
@@ -0,0 +1,184 @@
+/*
+ * 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.internal.jank;
+
+import static com.android.internal.jank.InteractionJankMonitor.CUJ_NOTIFICATION_SHADE_GESTURE;
+
+import static com.google.common.truth.Truth.assertThat;
+
+import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.Mockito.doNothing;
+import static org.mockito.Mockito.doReturn;
+import static org.mockito.Mockito.never;
+import static org.mockito.Mockito.only;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.when;
+
+import android.os.Handler;
+import android.view.FrameMetrics;
+import android.view.View;
+import android.view.ViewAttachTestActivity;
+
+import androidx.test.filters.SmallTest;
+import androidx.test.rule.ActivityTestRule;
+
+import com.android.internal.jank.FrameTracker.FrameMetricsWrapper;
+import com.android.internal.jank.FrameTracker.ThreadedRendererWrapper;
+import com.android.internal.jank.InteractionJankMonitor.Session;
+
+import org.junit.Before;
+import org.junit.Rule;
+import org.junit.Test;
+import org.mockito.Mockito;
+
+import java.util.concurrent.TimeUnit;
+
+@SmallTest
+public class FrameTrackerTest {
+ private ViewAttachTestActivity mActivity;
+
+ @Rule
+ public ActivityTestRule<ViewAttachTestActivity> mRule =
+ new ActivityTestRule<>(ViewAttachTestActivity.class);
+
+ private FrameTracker mTracker;
+ private ThreadedRendererWrapper mRenderer;
+ private FrameMetricsWrapper mWrapper;
+
+ @Before
+ public void setup() {
+ // Prepare an activity for getting ThreadedRenderer later.
+ mActivity = mRule.getActivity();
+ View view = mActivity.getWindow().getDecorView();
+ assertThat(view.isAttachedToWindow()).isTrue();
+
+ Handler handler = mRule.getActivity().getMainThreadHandler();
+ mWrapper = Mockito.spy(new FrameMetricsWrapper());
+ // For simplicity - provide current timestamp anytime mWrapper asked for VSYNC_TIMESTAMP
+ when(mWrapper.getMetric(FrameMetrics.VSYNC_TIMESTAMP))
+ .then(unusedInvocation -> System.nanoTime());
+ mRenderer = Mockito.spy(new ThreadedRendererWrapper(view.getThreadedRenderer()));
+ doNothing().when(mRenderer).addObserver(any());
+ doNothing().when(mRenderer).removeObserver(any());
+
+ Session session = new Session(CUJ_NOTIFICATION_SHADE_GESTURE);
+ mTracker = Mockito.spy(new FrameTracker(session, handler, mRenderer, mWrapper));
+ doNothing().when(mTracker).triggerPerfetto();
+ }
+
+ @Test
+ public void testIgnoresSecondBegin() {
+ // Observer should be only added once in continuous calls.
+ mTracker.begin();
+ mTracker.begin();
+ verify(mRenderer, only()).addObserver(any());
+ }
+
+ @Test
+ public void testOnlyFirstFrameOverThreshold() {
+ // Just provide current timestamp anytime mWrapper asked for VSYNC_TIMESTAMP
+ when(mWrapper.getMetric(FrameMetrics.VSYNC_TIMESTAMP))
+ .then(unusedInvocation -> System.nanoTime());
+
+ mTracker.begin();
+ verify(mRenderer, only()).addObserver(any());
+
+ // send first frame with a long duration - should not be taken into account
+ setupFirstFrameMockWithDuration(100);
+ mTracker.onFrameMetricsAvailable(0);
+
+ // send another frame with a short duration - should not be considered janky
+ setupOtherFrameMockWithDuration(5);
+ mTracker.onFrameMetricsAvailable(0);
+
+ // end the trace session, the last janky frame is after the end() so is discarded.
+ mTracker.end();
+ setupOtherFrameMockWithDuration(500);
+ mTracker.onFrameMetricsAvailable(0);
+
+ verify(mRenderer).removeObserver(any());
+ verify(mTracker, never()).triggerPerfetto();
+ }
+
+ @Test
+ public void testOtherFrameOverThreshold() {
+ mTracker.begin();
+ verify(mRenderer, only()).addObserver(any());
+
+ // send first frame - not janky
+ setupFirstFrameMockWithDuration(4);
+ mTracker.onFrameMetricsAvailable(0);
+
+ // send another frame - should be considered janky
+ setupOtherFrameMockWithDuration(40);
+ mTracker.onFrameMetricsAvailable(0);
+
+ // end the trace session
+ mTracker.end();
+ setupOtherFrameMockWithDuration(5);
+ mTracker.onFrameMetricsAvailable(0);
+
+ verify(mRenderer).removeObserver(any());
+
+ // We detected a janky frame - trigger Perfetto
+ verify(mTracker).triggerPerfetto();
+ }
+
+ @Test
+ public void testLastFrameOverThresholdBeforeEnd() {
+ mTracker.begin();
+ verify(mRenderer, only()).addObserver(any());
+
+ // send first frame - not janky
+ setupFirstFrameMockWithDuration(4);
+ mTracker.onFrameMetricsAvailable(0);
+
+ // send another frame - not janky
+ setupOtherFrameMockWithDuration(4);
+ mTracker.onFrameMetricsAvailable(0);
+
+ // end the trace session, simulate one more valid callback came after the end call.
+ when(mWrapper.getMetric(FrameMetrics.VSYNC_TIMESTAMP))
+ .thenReturn(System.nanoTime());
+ setupOtherFrameMockWithDuration(50);
+ mTracker.end();
+ mTracker.onFrameMetricsAvailable(0);
+
+ // One more callback with VSYNC after the end() timestamp.
+ when(mWrapper.getMetric(FrameMetrics.VSYNC_TIMESTAMP))
+ .thenReturn(System.nanoTime());
+ setupOtherFrameMockWithDuration(5);
+ mTracker.onFrameMetricsAvailable(0);
+
+ verify(mRenderer).removeObserver(any());
+
+ // We detected a janky frame - trigger Perfetto
+ verify(mTracker).triggerPerfetto();
+ }
+
+ private void setupFirstFrameMockWithDuration(long durationMillis) {
+ doReturn(1L).when(mWrapper).getMetric(FrameMetrics.FIRST_DRAW_FRAME);
+ doReturn(TimeUnit.MILLISECONDS.toNanos(durationMillis))
+ .when(mWrapper).getMetric(FrameMetrics.TOTAL_DURATION);
+ }
+
+ private void setupOtherFrameMockWithDuration(long durationMillis) {
+ doReturn(0L).when(mWrapper).getMetric(FrameMetrics.FIRST_DRAW_FRAME);
+ doReturn(TimeUnit.MILLISECONDS.toNanos(durationMillis))
+ .when(mWrapper).getMetric(FrameMetrics.TOTAL_DURATION);
+ }
+}
diff --git a/core/tests/coretests/src/com/android/internal/jank/InteractionJankMonitorTest.java b/core/tests/coretests/src/com/android/internal/jank/InteractionJankMonitorTest.java
new file mode 100644
index 000000000000..5c0b0c94f6d0
--- /dev/null
+++ b/core/tests/coretests/src/com/android/internal/jank/InteractionJankMonitorTest.java
@@ -0,0 +1,120 @@
+/*
+ * 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.internal.jank;
+
+import static com.android.internal.jank.InteractionJankMonitor.CUJ_NOTIFICATION_SHADE_GESTURE;
+
+import static com.google.common.truth.Truth.assertThat;
+
+import static org.mockito.Mockito.doNothing;
+import static org.mockito.Mockito.verify;
+
+import android.os.Handler;
+import android.os.HandlerThread;
+import android.view.View;
+import android.view.ViewAttachTestActivity;
+
+import androidx.test.filters.SmallTest;
+import androidx.test.rule.ActivityTestRule;
+
+import com.android.internal.jank.FrameTracker.FrameMetricsWrapper;
+import com.android.internal.jank.FrameTracker.ThreadedRendererWrapper;
+import com.android.internal.jank.InteractionJankMonitor.Session;
+
+import org.junit.Before;
+import org.junit.Rule;
+import org.junit.Test;
+import org.mockito.Mockito;
+import org.testng.Assert;
+
+import java.util.HashMap;
+import java.util.Map;
+
+@SmallTest
+public class InteractionJankMonitorTest {
+ private ViewAttachTestActivity mActivity;
+ private View mView;
+ private FrameTracker mTracker;
+
+ @Rule
+ public ActivityTestRule<ViewAttachTestActivity> mRule =
+ new ActivityTestRule<>(ViewAttachTestActivity.class);
+
+ @Before
+ public void setup() {
+ // Prepare an activity for getting ThreadedRenderer later.
+ mActivity = mRule.getActivity();
+ mView = mActivity.getWindow().getDecorView();
+ assertThat(mView.isAttachedToWindow()).isTrue();
+
+ InteractionJankMonitor.reset();
+
+ // Prepare a FrameTracker to inject.
+ Session session = new Session(CUJ_NOTIFICATION_SHADE_GESTURE);
+ FrameMetricsWrapper wrapper = Mockito.spy(new FrameTracker.FrameMetricsWrapper());
+ ThreadedRendererWrapper renderer =
+ Mockito.spy(new ThreadedRendererWrapper(mView.getThreadedRenderer()));
+ Handler handler = mActivity.getMainThreadHandler();
+ mTracker = Mockito.spy(new FrameTracker(session, handler, renderer, wrapper));
+ }
+
+ @Test
+ public void testBeginEnd() {
+ // Should throw exception if the view is not attached.
+ Assert.assertThrows(IllegalStateException.class,
+ () -> InteractionJankMonitor.init(new View(mActivity)));
+
+ // Verify we init InteractionJankMonitor correctly.
+ Map<String, FrameTracker> map = new HashMap<>();
+ HandlerThread worker = Mockito.spy(new HandlerThread("Aot-test"));
+ doNothing().when(worker).start();
+ InteractionJankMonitor.init(mView, mView.getThreadedRenderer(), map, worker);
+ verify(worker).start();
+
+ // Simulate a trace session and see if begin / end are invoked.
+ Session session = new Session(CUJ_NOTIFICATION_SHADE_GESTURE);
+ assertThat(map.get(session.getName())).isNull();
+ InteractionJankMonitor.begin(CUJ_NOTIFICATION_SHADE_GESTURE, mTracker);
+ verify(mTracker).begin();
+ assertThat(map.get(session.getName())).isEqualTo(mTracker);
+ InteractionJankMonitor.end(CUJ_NOTIFICATION_SHADE_GESTURE);
+ verify(mTracker).end();
+ assertThat(map.get(session.getName())).isNull();
+ }
+
+ @Test
+ public void testCheckInitState() {
+ // Should throw exception if invoking begin / end without init invocation.
+ Assert.assertThrows(IllegalStateException.class,
+ () -> InteractionJankMonitor.begin(CUJ_NOTIFICATION_SHADE_GESTURE));
+ Assert.assertThrows(IllegalStateException.class,
+ () -> InteractionJankMonitor.end(CUJ_NOTIFICATION_SHADE_GESTURE));
+
+ // Everything should be fine if invoking init first.
+ boolean thrown = false;
+ try {
+ InteractionJankMonitor.init(mActivity.getWindow().getDecorView());
+ InteractionJankMonitor.begin(CUJ_NOTIFICATION_SHADE_GESTURE);
+ InteractionJankMonitor.end(CUJ_NOTIFICATION_SHADE_GESTURE);
+ } catch (Exception ex) {
+ thrown = true;
+ } finally {
+ assertThat(thrown).isFalse();
+ }
+ }
+
+}
diff --git a/core/tests/coretests/src/com/android/internal/view/ScrollViewCaptureHelperTest.java b/core/tests/coretests/src/com/android/internal/view/ScrollViewCaptureHelperTest.java
index 63a68e99b788..ab13fd7d81e0 100644
--- a/core/tests/coretests/src/com/android/internal/view/ScrollViewCaptureHelperTest.java
+++ b/core/tests/coretests/src/com/android/internal/view/ScrollViewCaptureHelperTest.java
@@ -21,12 +21,11 @@ import static android.view.ViewGroup.LayoutParams.WRAP_CONTENT;
import static android.view.WindowManager.LayoutParams.FLAG_NOT_TOUCHABLE;
import static android.view.WindowManager.LayoutParams.TYPE_APPLICATION_OVERLAY;
-import static androidx.test.InstrumentationRegistry.getContext;
-
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertTrue;
import static org.junit.Assert.fail;
+import android.content.Context;
import android.graphics.Color;
import android.graphics.PixelFormat;
import android.graphics.Rect;
@@ -40,10 +39,12 @@ import android.widget.ScrollView;
import android.widget.TextView;
import androidx.test.annotation.UiThreadTest;
+import androidx.test.platform.app.InstrumentationRegistry;
+
+import com.android.internal.view.ScrollCaptureViewHelper.ScrollResult;
import org.junit.After;
import org.junit.Before;
-import org.junit.BeforeClass;
import org.junit.Test;
import java.util.Random;
@@ -67,28 +68,27 @@ public class ScrollViewCaptureHelperTest {
private Random mRandom;
- private static float sDensity;
-
- @BeforeClass
- public static void setUpClass() {
- sDensity = getContext().getResources().getDisplayMetrics().density;
- }
+ private Context mContext;
+ private float mDensity;
@Before
@UiThreadTest
public void setUp() {
+ mContext = InstrumentationRegistry.getInstrumentation().getContext();
+ mDensity = mContext.getResources().getDisplayMetrics().density;
+
mRandom = new Random();
- mParent = new FrameLayout(getContext());
+ mParent = new FrameLayout(mContext);
- mTarget = new ScrollView(getContext());
+ mTarget = new ScrollView(mContext);
mParent.addView(mTarget, new ViewGroup.LayoutParams(MATCH_PARENT, MATCH_PARENT));
- mContent = new LinearLayout(getContext());
+ mContent = new LinearLayout(mContext);
mContent.setOrientation(LinearLayout.VERTICAL);
mTarget.addView(mContent, new ViewGroup.LayoutParams(MATCH_PARENT, WRAP_CONTENT));
for (int i = 0; i < CHILD_VIEWS; i++) {
- TextView view = new TextView(getContext());
+ TextView view = new TextView(mContext);
view.setText("Child #" + i);
view.setTextColor(Color.WHITE);
view.setTextSize(30f);
@@ -99,7 +99,7 @@ public class ScrollViewCaptureHelperTest {
// Window -> Parent -> Target -> Content
- mWm = getContext().getSystemService(WindowManager.class);
+ mWm = mContext.getSystemService(WindowManager.class);
// Setup the window that we are going to use
mWindowLayoutParams = new WindowManager.LayoutParams(WINDOW_WIDTH, WINDOW_HEIGHT,
@@ -123,58 +123,6 @@ public class ScrollViewCaptureHelperTest {
svc.onPrepareForStart(mTarget, scrollBounds);
}
- static void assertEmpty(Rect r) {
- if (r != null && !r.isEmpty()) {
- fail("Not true that " + r + " is empty");
- }
- }
-
- static void assertContains(Rect parent, Rect child) {
- if (!parent.contains(child)) {
- fail("Not true that " + parent + " contains " + child);
- }
- }
-
- static void assertRectEquals(Rect parent, Rect child) {
- if (!parent.equals(child)) {
- fail("Not true that " + parent + " is equal to " + child);
- }
- }
-
- static Rect getVisibleRect(View v) {
- Rect r = new Rect(0, 0, v.getWidth(), v.getHeight());
- v.getLocalVisibleRect(r);
- return r;
- }
-
-
- static int assertScrollToY(View v, int scrollY) {
- v.scrollTo(0, scrollY);
- int dest = v.getScrollY();
- assertEquals(scrollY, dest);
- return scrollY;
- }
-
-
- static void assertCapturedAreaCompletelyVisible(int startScrollY, Rect requestRect,
- Rect localVisibleNow) {
- Rect captured = new Rect(localVisibleNow);
- captured.offset(0, -startScrollY); // make relative
-
- if (!captured.contains(requestRect)) {
- fail("Not true that all of " + requestRect + " is contained by " + captured);
- }
- }
- static void assertCapturedAreaPartiallyVisible(int startScrollY, Rect requestRect,
- Rect localVisibleNow) {
- Rect captured = new Rect(localVisibleNow);
- captured.offset(0, -startScrollY); // make relative
-
- if (!Rect.intersects(captured, requestRect)) {
- fail("Not true that any of " + requestRect + " intersects " + captured);
- }
- }
-
@Test
@UiThreadTest
public void onScrollRequested_up_fromTop() {
@@ -188,12 +136,13 @@ public class ScrollViewCaptureHelperTest {
Rect request = new Rect(0, -CAPTURE_HEIGHT, scrollBounds.width(), 0);
- Rect result = svc.onScrollRequested(mTarget, scrollBounds, request);
+ ScrollResult scrollResult = svc.onScrollRequested(mTarget,
+ scrollBounds, request);
// The result is an empty rectangle and no scrolling, since it
// is not possible to physically scroll further up to make the
// requested area visible at all (it doesn't exist).
- assertEmpty(result);
+ assertEmpty(scrollResult.availableArea);
}
@Test
@@ -201,7 +150,6 @@ public class ScrollViewCaptureHelperTest {
public void onScrollRequested_down_fromTop() {
final int startScrollY = assertScrollToY(mTarget, 0);
-
ScrollViewCaptureHelper svc = new ScrollViewCaptureHelper();
Rect scrollBounds = svc.onComputeScrollBounds(mTarget);
svc.onPrepareForStart(mTarget, scrollBounds);
@@ -212,13 +160,13 @@ public class ScrollViewCaptureHelperTest {
Rect request = new Rect(0, WINDOW_HEIGHT, scrollBounds.width(),
WINDOW_HEIGHT + CAPTURE_HEIGHT);
- Rect result = svc.onScrollRequested(mTarget, scrollBounds, request);
- assertRectEquals(request, result);
-
- assertCapturedAreaCompletelyVisible(startScrollY, request, getVisibleRect(mContent));
+ ScrollResult scrollResult = svc.onScrollRequested(mTarget, scrollBounds, request);
+ assertRectEquals(request, scrollResult.requestedArea);
+ assertRectEquals(request, scrollResult.availableArea);
+ assertRequestedRectCompletelyVisible(startScrollY, request, getVisibleRect(mContent));
+ assertEquals(CAPTURE_HEIGHT, scrollResult.scrollDelta);
}
-
@Test
@UiThreadTest
public void onScrollRequested_up_fromMiddle() {
@@ -230,12 +178,11 @@ public class ScrollViewCaptureHelperTest {
Rect request = new Rect(0, -CAPTURE_HEIGHT, scrollBounds.width(), 0);
-
- Rect result = svc.onScrollRequested(mTarget, scrollBounds, request);
-
- assertRectEquals(request, result);
-
- assertCapturedAreaCompletelyVisible(startScrollY, request, getVisibleRect(mContent));
+ ScrollResult scrollResult = svc.onScrollRequested(mTarget, scrollBounds, request);
+ assertRectEquals(request, scrollResult.requestedArea);
+ assertRectEquals(request, scrollResult.availableArea);
+ assertRequestedRectCompletelyVisible(startScrollY, request, getVisibleRect(mContent));
+ assertEquals(-CAPTURE_HEIGHT, scrollResult.scrollDelta);
}
@Test
@@ -250,10 +197,12 @@ public class ScrollViewCaptureHelperTest {
Rect request = new Rect(0, WINDOW_HEIGHT, scrollBounds.width(),
WINDOW_HEIGHT + CAPTURE_HEIGHT);
- Rect result = svc.onScrollRequested(mTarget, scrollBounds, request);
- assertRectEquals(request, result);
+ ScrollResult scrollResult = svc.onScrollRequested(mTarget, scrollBounds, request);
+ assertRectEquals(request, scrollResult.requestedArea);
+ assertRectEquals(request, scrollResult.availableArea);
+ assertRequestedRectCompletelyVisible(startScrollY, request, getVisibleRect(mContent));
+ assertEquals(CAPTURE_HEIGHT, scrollResult.scrollDelta);
- assertCapturedAreaCompletelyVisible(startScrollY, request, getVisibleRect(mContent));
}
@Test
@@ -267,10 +216,11 @@ public class ScrollViewCaptureHelperTest {
Rect request = new Rect(0, -CAPTURE_HEIGHT, scrollBounds.width(), 0);
- Rect result = svc.onScrollRequested(mTarget, scrollBounds, request);
- assertRectEquals(request, result);
-
- assertCapturedAreaCompletelyVisible(startScrollY, request, getVisibleRect(mContent));
+ ScrollResult scrollResult = svc.onScrollRequested(mTarget, scrollBounds, request);
+ assertRectEquals(request, scrollResult.requestedArea);
+ assertRectEquals(request, scrollResult.availableArea);
+ assertRequestedRectCompletelyVisible(startScrollY, request, getVisibleRect(mContent));
+ assertEquals(-CAPTURE_HEIGHT, scrollResult.scrollDelta);
}
@Test
@@ -285,12 +235,14 @@ public class ScrollViewCaptureHelperTest {
Rect request = new Rect(0, WINDOW_HEIGHT, scrollBounds.width(),
WINDOW_HEIGHT + CAPTURE_HEIGHT);
- Rect result = svc.onScrollRequested(mTarget, scrollBounds, request);
+ ScrollResult scrollResult = svc.onScrollRequested(mTarget, scrollBounds, request);
+ assertRectEquals(request, scrollResult.requestedArea);
// The result is an empty rectangle and no scrolling, since it
// is not possible to physically scroll further down to make the
// requested area visible at all (it doesn't exist).
- assertEmpty(result);
+ assertEmpty(scrollResult.availableArea);
+ assertEquals(0, scrollResult.scrollDelta);
}
@Test
@@ -309,12 +261,16 @@ public class ScrollViewCaptureHelperTest {
0, top - (CAPTURE_HEIGHT / 2),
scrollBounds.width(), top + (CAPTURE_HEIGHT / 2));
- Rect result = svc.onScrollRequested(mTarget, scrollBounds, request);
+ ScrollResult scrollResult = svc.onScrollRequested(mTarget, scrollBounds, request);
+ assertRectEquals(request, scrollResult.requestedArea);
+
+ ScrollResult result = svc.onScrollRequested(mTarget, scrollBounds, request);
// The result is a partial result
Rect expectedResult = new Rect(request);
expectedResult.top += 300; // top half clipped
- assertRectEquals(expectedResult, result);
- assertCapturedAreaPartiallyVisible(startScrollY, request, getVisibleRect(mContent));
+ assertRectEquals(expectedResult, result.availableArea);
+ assertRequestedRectPartiallyVisible(startScrollY, request, getVisibleRect(mContent));
+ assertEquals(0, scrollResult.scrollDelta);
}
@Test
@@ -334,13 +290,13 @@ public class ScrollViewCaptureHelperTest {
0, bottom - (CAPTURE_HEIGHT / 2),
scrollBounds.width(), bottom + (CAPTURE_HEIGHT / 2));
- Rect result = svc.onScrollRequested(mTarget, scrollBounds, request);
+ ScrollResult result = svc.onScrollRequested(mTarget, scrollBounds, request);
Rect expectedResult = new Rect(request);
expectedResult.bottom -= 300; // bottom half clipped
- assertRectEquals(expectedResult, result);
- assertCapturedAreaPartiallyVisible(startScrollY, request, getVisibleRect(mContent));
-
+ assertRectEquals(expectedResult, result.availableArea);
+ assertRequestedRectPartiallyVisible(startScrollY, request, getVisibleRect(mContent));
+ assertEquals(0, result.scrollDelta);
}
@Test
@@ -349,4 +305,56 @@ public class ScrollViewCaptureHelperTest {
ScrollViewCaptureHelper svc = new ScrollViewCaptureHelper();
svc.onPrepareForEnd(mTarget);
}
+
+
+ static void assertEmpty(Rect r) {
+ if (r != null && !r.isEmpty()) {
+ fail("Not true that " + r + " is empty");
+ }
+ }
+
+ static void assertContains(Rect parent, Rect child) {
+ if (!parent.contains(child)) {
+ fail("Not true that " + parent + " contains " + child);
+ }
+ }
+
+ static void assertRectEquals(Rect parent, Rect child) {
+ if (!parent.equals(child)) {
+ fail("Not true that " + parent + " is equal to " + child);
+ }
+ }
+
+ static Rect getVisibleRect(View v) {
+ Rect r = new Rect(0, 0, v.getWidth(), v.getHeight());
+ v.getLocalVisibleRect(r);
+ return r;
+ }
+
+
+ static int assertScrollToY(View v, int scrollY) {
+ v.scrollTo(0, scrollY);
+ int dest = v.getScrollY();
+ assertEquals(scrollY, dest);
+ return scrollY;
+ }
+
+ static void assertRequestedRectCompletelyVisible(int startScrollY, Rect requestRect,
+ Rect localVisibleNow) {
+ Rect captured = new Rect(localVisibleNow);
+ captured.offset(0, -startScrollY); // make relative
+
+ if (!captured.contains(requestRect)) {
+ fail("Not true that all of " + requestRect + " is contained by " + captured);
+ }
+ }
+ static void assertRequestedRectPartiallyVisible(int startScrollY, Rect requestRect,
+ Rect localVisibleNow) {
+ Rect captured = new Rect(localVisibleNow);
+ captured.offset(0, -startScrollY); // make relative
+
+ if (!Rect.intersects(captured, requestRect)) {
+ fail("Not true that any of " + requestRect + " intersects " + captured);
+ }
+ }
}
diff --git a/core/tests/hosttests/test-apps/MultiDexLegacyTestApp/Android.mk b/core/tests/hosttests/test-apps/MultiDexLegacyTestApp/Android.mk
index c577eeffd488..fe7c944ebd30 100644
--- a/core/tests/hosttests/test-apps/MultiDexLegacyTestApp/Android.mk
+++ b/core/tests/hosttests/test-apps/MultiDexLegacyTestApp/Android.mk
@@ -29,6 +29,8 @@ LOCAL_PACKAGE_NAME := MultiDexLegacyTestApp
LOCAL_DEX_PREOPT := false
+LOCAL_EMMA_INSTRUMENT := false
+
mainDexList:= \
$(call intermediates-dir-for,APPS,$(LOCAL_PACKAGE_NAME),$(LOCAL_IS_HOST_MODULE),common)/maindex.list
@@ -60,6 +62,8 @@ LOCAL_PACKAGE_NAME := MultiDexLegacyTestApp2
LOCAL_DEX_PREOPT := false
+LOCAL_EMMA_INSTRUMENT := false
+
mainDexList2:= \
$(call intermediates-dir-for,APPS,$(LOCAL_PACKAGE_NAME),$(LOCAL_IS_HOST_MODULE),common)/maindex.list
diff --git a/core/tests/hosttests/test-apps/MultiDexLegacyTestServices/Android.mk b/core/tests/hosttests/test-apps/MultiDexLegacyTestServices/Android.mk
index da40940e92e9..3636c73ffc9c 100644
--- a/core/tests/hosttests/test-apps/MultiDexLegacyTestServices/Android.mk
+++ b/core/tests/hosttests/test-apps/MultiDexLegacyTestServices/Android.mk
@@ -33,6 +33,8 @@ LOCAL_DX_FLAGS := --multi-dex --main-dex-list=$(mainDexList) --minimal-main-dex
LOCAL_DEX_PREOPT := false
+LOCAL_EMMA_INSTRUMENT := false
+
include $(BUILD_PACKAGE)
$(mainDexList): $(full_classes_pre_proguard_jar) $(MAINDEXCLASSES) $(PROGUARD_DEPS)
diff --git a/core/tests/hosttests/test-apps/MultiDexLegacyVersionedTestApp_v1/Android.mk b/core/tests/hosttests/test-apps/MultiDexLegacyVersionedTestApp_v1/Android.mk
index 665e22d5a0bc..67f1fa574c07 100644
--- a/core/tests/hosttests/test-apps/MultiDexLegacyVersionedTestApp_v1/Android.mk
+++ b/core/tests/hosttests/test-apps/MultiDexLegacyVersionedTestApp_v1/Android.mk
@@ -28,6 +28,8 @@ LOCAL_STATIC_JAVA_LIBRARIES := android-support-multidex
LOCAL_DEX_PREOPT := false
+LOCAL_EMMA_INSTRUMENT := false
+
mainDexList:= \
$(call intermediates-dir-for,APPS,$(LOCAL_PACKAGE_NAME),$(LOCAL_IS_HOST_MODULE),common)/maindex.list
diff --git a/core/tests/hosttests/test-apps/MultiDexLegacyVersionedTestApp_v2/Android.mk b/core/tests/hosttests/test-apps/MultiDexLegacyVersionedTestApp_v2/Android.mk
index c827fa80ebcd..33871e527820 100644
--- a/core/tests/hosttests/test-apps/MultiDexLegacyVersionedTestApp_v2/Android.mk
+++ b/core/tests/hosttests/test-apps/MultiDexLegacyVersionedTestApp_v2/Android.mk
@@ -28,6 +28,8 @@ LOCAL_STATIC_JAVA_LIBRARIES := android-support-multidex
LOCAL_DEX_PREOPT := false
+LOCAL_EMMA_INSTRUMENT := false
+
mainDexList:= \
$(call intermediates-dir-for,APPS,$(LOCAL_PACKAGE_NAME),$(LOCAL_IS_HOST_MODULE),common)/maindex.list
diff --git a/core/tests/hosttests/test-apps/MultiDexLegacyVersionedTestApp_v3/Android.mk b/core/tests/hosttests/test-apps/MultiDexLegacyVersionedTestApp_v3/Android.mk
index 3d6ad7d1aa57..1b267ee93cce 100644
--- a/core/tests/hosttests/test-apps/MultiDexLegacyVersionedTestApp_v3/Android.mk
+++ b/core/tests/hosttests/test-apps/MultiDexLegacyVersionedTestApp_v3/Android.mk
@@ -31,6 +31,8 @@ mainDexList:= \
LOCAL_DEX_PREOPT := false
+LOCAL_EMMA_INSTRUMENT := false
+
LOCAL_DX_FLAGS := --multi-dex --main-dex-list=$(mainDexList) --minimal-main-dex
include $(BUILD_PACKAGE)
diff --git a/data/etc/services.core.protolog.json b/data/etc/services.core.protolog.json
index 73296987adde..a2a2216028ac 100644
--- a/data/etc/services.core.protolog.json
+++ b/data/etc/services.core.protolog.json
@@ -13,6 +13,12 @@
"group": "WM_DEBUG_STARTING_WINDOW",
"at": "com\/android\/server\/wm\/ActivityRecord.java"
},
+ "-2121056984": {
+ "message": "%s",
+ "level": "WARN",
+ "group": "WM_DEBUG_LOCKTASK",
+ "at": "com\/android\/server\/wm\/LockTaskController.java"
+ },
"-2109936758": {
"message": "removeAppToken make exiting: %s",
"level": "VERBOSE",
@@ -37,12 +43,24 @@
"group": "WM_ERROR",
"at": "com\/android\/server\/wm\/WindowManagerService.java"
},
+ "-2049725903": {
+ "message": "Task back pressed on root taskId=%d",
+ "level": "VERBOSE",
+ "group": "WM_DEBUG_WINDOW_ORGANIZER",
+ "at": "com\/android\/server\/wm\/TaskOrganizerController.java"
+ },
"-2039580386": {
"message": "Attempted to add input method window with unknown token %s. Aborting.",
"level": "WARN",
"group": "WM_ERROR",
"at": "com\/android\/server\/wm\/WindowManagerService.java"
},
+ "-2029985709": {
+ "message": "setFocusedTask: taskId=%d",
+ "level": "DEBUG",
+ "group": "WM_DEBUG_FOCUS",
+ "at": "com\/android\/server\/wm\/ActivityTaskManagerService.java"
+ },
"-2024464438": {
"message": "app-onAnimationFinished(): mOuter=%s",
"level": "DEBUG",
@@ -73,6 +91,12 @@
"group": "WM_DEBUG_STARTING_WINDOW",
"at": "com\/android\/server\/wm\/TaskSnapshotSurface.java"
},
+ "-1980468143": {
+ "message": "DisplayArea appeared name=%s",
+ "level": "VERBOSE",
+ "group": "WM_DEBUG_WINDOW_ORGANIZER",
+ "at": "com\/android\/server\/wm\/DisplayAreaOrganizerController.java"
+ },
"-1976930686": {
"message": "Attempted to add Accessibility overlay window with bad token %s. Aborting.",
"level": "WARN",
@@ -91,6 +115,12 @@
"group": "WM_ERROR",
"at": "com\/android\/server\/wm\/WindowManagerService.java"
},
+ "-1939861963": {
+ "message": "Create root task displayId=%d winMode=%d",
+ "level": "VERBOSE",
+ "group": "WM_DEBUG_WINDOW_ORGANIZER",
+ "at": "com\/android\/server\/wm\/TaskOrganizerController.java"
+ },
"-1939358269": {
"message": "mRecentScreenshotAnimator finish",
"level": "DEBUG",
@@ -115,6 +145,12 @@
"group": "WM_ERROR",
"at": "com\/android\/server\/wm\/WindowManagerService.java"
},
+ "-1895337367": {
+ "message": "Delete root task display=%d winMode=%d",
+ "level": "VERBOSE",
+ "group": "WM_DEBUG_WINDOW_ORGANIZER",
+ "at": "com\/android\/server\/wm\/TaskOrganizerController.java"
+ },
"-1884933373": {
"message": "enableScreenAfterBoot: mDisplayEnabled=%b mForceDisplayEnabled=%b mShowingBootMessages=%b mSystemBooted=%b. %s",
"level": "INFO",
@@ -139,6 +175,12 @@
"group": "WM_DEBUG_ORIENTATION",
"at": "com\/android\/server\/wm\/DisplayRotation.java"
},
+ "-1868048288": {
+ "message": "Updating to new configuration after starting activity.",
+ "level": "VERBOSE",
+ "group": "WM_DEBUG_CONFIGURATION",
+ "at": "com\/android\/server\/wm\/ActivityStarter.java"
+ },
"-1862269827": {
"message": "applyAnimation: anim=%s transit=%s isEntrance=%b Callers=%s",
"level": "VERBOSE",
@@ -163,6 +205,24 @@
"group": "WM_DEBUG_RESIZE",
"at": "com\/android\/server\/wm\/WindowState.java"
},
+ "-1810446914": {
+ "message": "Trying to update display configuration for system\/invalid process.",
+ "level": "WARN",
+ "group": "WM_DEBUG_CONFIGURATION",
+ "at": "com\/android\/server\/wm\/ActivityTaskManagerService.java"
+ },
+ "-1792633344": {
+ "message": "Register task organizer=%s uid=%d",
+ "level": "VERBOSE",
+ "group": "WM_DEBUG_WINDOW_ORGANIZER",
+ "at": "com\/android\/server\/wm\/TaskOrganizerController.java"
+ },
+ "-1791031393": {
+ "message": "Ensuring correct configuration: %s",
+ "level": "VERBOSE",
+ "group": "WM_DEBUG_CONFIGURATION",
+ "at": "com\/android\/server\/wm\/ActivityRecord.java"
+ },
"-1782453012": {
"message": "Checking theme of starting window: 0x%x",
"level": "VERBOSE",
@@ -211,6 +271,12 @@
"group": "WM_DEBUG_ORIENTATION",
"at": "com\/android\/server\/wm\/DisplayContent.java"
},
+ "-1699018375": {
+ "message": "Adding activity %s to task %s callers: %s",
+ "level": "INFO",
+ "group": "WM_DEBUG_ADD_REMOVE",
+ "at": "com\/android\/server\/wm\/Task.java"
+ },
"-1698815688": {
"message": "Resetting app token %s of replacing window marks.",
"level": "DEBUG",
@@ -229,24 +295,36 @@
"group": "WM_ERROR",
"at": "com\/android\/server\/wm\/WindowManagerService.java"
},
+ "-1638958146": {
+ "message": "Removing activity %s from task=%s adding to task=%s Callers=%s",
+ "level": "INFO",
+ "group": "WM_DEBUG_ADD_REMOVE",
+ "at": "com\/android\/server\/wm\/ResetTargetTaskHelper.java"
+ },
"-1632122349": {
"message": "Changing surface while display frozen: %s",
"level": "VERBOSE",
"group": "WM_DEBUG_ORIENTATION",
"at": "com\/android\/server\/wm\/WindowManagerService.java"
},
+ "-1630752478": {
+ "message": "removeLockedTask: removed %s",
+ "level": "DEBUG",
+ "group": "WM_DEBUG_LOCKTASK",
+ "at": "com\/android\/server\/wm\/LockTaskController.java"
+ },
+ "-1598452494": {
+ "message": "activityDestroyedLocked: r=%s",
+ "level": "DEBUG",
+ "group": "WM_DEBUG_CONTAINERS",
+ "at": "com\/android\/server\/wm\/ActivityRecord.java"
+ },
"-1596995693": {
"message": "startAnimation",
"level": "DEBUG",
"group": "WM_DEBUG_REMOTE_ANIMATIONS",
"at": "com\/android\/server\/wm\/RemoteAnimationController.java"
},
- "-1587841219": {
- "message": "Focus moving from %s to %s displayId=%d",
- "level": "INFO",
- "group": "WM_DEBUG_FOCUS_LIGHT",
- "at": "com\/android\/server\/wm\/WindowManagerService.java"
- },
"-1568331821": {
"message": "Enabling listeners",
"level": "VERBOSE",
@@ -307,6 +385,18 @@
"group": "WM_DEBUG_REMOTE_ANIMATIONS",
"at": "com\/android\/server\/wm\/RemoteAnimationController.java"
},
+ "-1495062622": {
+ "message": "Can't report activity moved to display - client not running, activityRecord=%s, displayId=%d",
+ "level": "WARN",
+ "group": "WM_DEBUG_SWITCH",
+ "at": "com\/android\/server\/wm\/ActivityRecord.java"
+ },
+ "-1492881555": {
+ "message": "Starting activity when config will change = %b",
+ "level": "VERBOSE",
+ "group": "WM_DEBUG_CONFIGURATION",
+ "at": "com\/android\/server\/wm\/ActivityStarter.java"
+ },
"-1471946192": {
"message": "Marking app token %s with replacing child windows.",
"level": "DEBUG",
@@ -319,6 +409,12 @@
"group": "WM_ERROR",
"at": "com\/android\/server\/wm\/WindowManagerService.java"
},
+ "-1438175584": {
+ "message": "Input focus has changed to %s display=%d",
+ "level": "VERBOSE",
+ "group": "WM_DEBUG_FOCUS_LIGHT",
+ "at": "com\/android\/server\/wm\/InputMonitor.java"
+ },
"-1434147454": {
"message": "cleanupAnimation(): Notify animation finished mPendingAnimations=%d reorderMode=%d",
"level": "DEBUG",
@@ -355,6 +451,12 @@
"group": "WM_ERROR",
"at": "com\/android\/server\/wm\/WindowManagerService.java"
},
+ "-1364754753": {
+ "message": "Task vanished taskId=%d",
+ "level": "VERBOSE",
+ "group": "WM_DEBUG_WINDOW_ORGANIZER",
+ "at": "com\/android\/server\/wm\/TaskOrganizerController.java"
+ },
"-1352076759": {
"message": "Removing app token: %s",
"level": "VERBOSE",
@@ -379,6 +481,12 @@
"group": "WM_DEBUG_IME",
"at": "com\/android\/server\/wm\/WindowState.java"
},
+ "-1305755880": {
+ "message": "Initial config: %s",
+ "level": "VERBOSE",
+ "group": "WM_DEBUG_CONFIGURATION",
+ "at": "com\/android\/server\/wm\/ActivityTaskManagerService.java"
+ },
"-1292329638": {
"message": "Added starting %s: startingWindow=%s startingView=%s",
"level": "VERBOSE",
@@ -445,12 +553,24 @@
"group": "WM_DEBUG_RECENTS_ANIMATIONS",
"at": "com\/android\/server\/wm\/RecentsAnimation.java"
},
+ "-1155279885": {
+ "message": "Frontmost changed immersion: %s",
+ "level": "DEBUG",
+ "group": "WM_DEBUG_IMMERSIVE",
+ "at": "com\/android\/server\/wm\/ActivityTaskManagerService.java"
+ },
"-1144293044": {
"message": "SURFACE SET FREEZE LAYER: %s",
"level": "INFO",
"group": "WM_SHOW_TRANSACTIONS",
"at": "com\/android\/server\/wm\/WindowStateAnimator.java"
},
+ "-1142279614": {
+ "message": "Looking for focus: %s, flags=%d, canReceive=%b, reason=%s",
+ "level": "VERBOSE",
+ "group": "WM_DEBUG_FOCUS",
+ "at": "com\/android\/server\/wm\/DisplayContent.java"
+ },
"-1130891072": {
"message": "Orientation continue waiting for draw in %s",
"level": "VERBOSE",
@@ -475,6 +595,12 @@
"group": "WM_DEBUG_ORIENTATION",
"at": "com\/android\/server\/wm\/DisplayRotation.java"
},
+ "-1115019498": {
+ "message": "Configuration & display unchanged in %s",
+ "level": "VERBOSE",
+ "group": "WM_DEBUG_CONFIGURATION",
+ "at": "com\/android\/server\/wm\/ActivityRecord.java"
+ },
"-1113134997": {
"message": "Attempted to add application window with unknown token %s. Aborting.",
"level": "WARN",
@@ -559,12 +685,36 @@
"group": "WM_DEBUG_STARTING_WINDOW",
"at": "com\/android\/server\/wm\/WindowState.java"
},
+ "-951939129": {
+ "message": "Unregister task organizer=%s uid=%d",
+ "level": "VERBOSE",
+ "group": "WM_DEBUG_WINDOW_ORGANIZER",
+ "at": "com\/android\/server\/wm\/TaskOrganizerController.java"
+ },
+ "-930893991": {
+ "message": "Set sync ready, syncId=%d",
+ "level": "VERBOSE",
+ "group": "WM_DEBUG_WINDOW_ORGANIZER",
+ "at": "com\/android\/server\/wm\/WindowOrganizerController.java"
+ },
+ "-929676529": {
+ "message": "Configuration changes for %s, allChanges=%s",
+ "level": "VERBOSE",
+ "group": "WM_DEBUG_CONFIGURATION",
+ "at": "com\/android\/server\/wm\/ActivityRecord.java"
+ },
"-928291778": {
"message": "applyAnimation: anim=%s nextAppTransition=%d transit=%s Callers=%s",
"level": "VERBOSE",
"group": "WM_DEBUG_APP_TRANSITIONS_ANIM",
"at": "com\/android\/server\/wm\/AppTransition.java"
},
+ "-927199900": {
+ "message": "Updating global configuration to: %s",
+ "level": "INFO",
+ "group": "WM_DEBUG_CONFIGURATION",
+ "at": "com\/android\/server\/wm\/ActivityTaskManagerService.java"
+ },
"-916108501": {
"message": "Adding %s to %s",
"level": "VERBOSE",
@@ -619,12 +769,24 @@
"group": "WM_ERROR",
"at": "com\/android\/server\/wm\/WindowManagerService.java"
},
+ "-846078709": {
+ "message": "Configuration doesn't matter in finishing %s",
+ "level": "VERBOSE",
+ "group": "WM_DEBUG_CONFIGURATION",
+ "at": "com\/android\/server\/wm\/ActivityRecord.java"
+ },
"-809771899": {
"message": "findFocusedWindow: Reached focused app=%s",
"level": "VERBOSE",
"group": "WM_DEBUG_FOCUS_LIGHT",
"at": "com\/android\/server\/wm\/DisplayContent.java"
},
+ "-804217032": {
+ "message": "Skipping config check (will change): %s",
+ "level": "VERBOSE",
+ "group": "WM_DEBUG_CONFIGURATION",
+ "at": "com\/android\/server\/wm\/ActivityRecord.java"
+ },
"-793346159": {
"message": "New transit into wallpaper: %s",
"level": "VERBOSE",
@@ -643,12 +805,6 @@
"group": "WM_DEBUG_ORIENTATION",
"at": "com\/android\/server\/wm\/WindowManagerService.java"
},
- "-771282525": {
- "message": "Losing focus: %s",
- "level": "INFO",
- "group": "WM_DEBUG_FOCUS_LIGHT",
- "at": "com\/android\/server\/wm\/WindowManagerService.java"
- },
"-771177730": {
"message": "Removing focused app token:%s displayId=%d",
"level": "VERBOSE",
@@ -673,11 +829,17 @@
"group": "WM_DEBUG_SCREEN_ON",
"at": "com\/android\/server\/wm\/WindowManagerService.java"
},
- "-714291355": {
- "message": "Losing delayed focus: %s",
- "level": "INFO",
- "group": "WM_DEBUG_FOCUS_LIGHT",
- "at": "com\/android\/server\/wm\/WindowManagerService.java"
+ "-743431900": {
+ "message": "Configuration no differences in %s",
+ "level": "VERBOSE",
+ "group": "WM_DEBUG_CONFIGURATION",
+ "at": "com\/android\/server\/wm\/ActivityRecord.java"
+ },
+ "-716565534": {
+ "message": "moveActivityStackToFront: unfocusable activity=%s",
+ "level": "DEBUG",
+ "group": "WM_DEBUG_FOCUS",
+ "at": "com\/android\/server\/wm\/ActivityRecord.java"
},
"-694710814": {
"message": "Pausing rotation during drag",
@@ -685,12 +847,6 @@
"group": "WM_DEBUG_ORIENTATION",
"at": "com\/android\/server\/wm\/DragState.java"
},
- "-687185281": {
- "message": "New topFocusedDisplayId=%d",
- "level": "VERBOSE",
- "group": "WM_DEBUG_FOCUS_LIGHT",
- "at": "com\/android\/server\/wm\/RootWindowContainer.java"
- },
"-668956537": {
"message": " THUMBNAIL %s: CREATE",
"level": "INFO",
@@ -715,6 +871,12 @@
"group": "WM_ERROR",
"at": "com\/android\/server\/wm\/WindowToken.java"
},
+ "-639217716": {
+ "message": "setFocusedApp %s displayId=%d Callers=%s",
+ "level": "INFO",
+ "group": "WM_DEBUG_FOCUS_LIGHT",
+ "at": "com\/android\/server\/wm\/DisplayContent.java"
+ },
"-635082269": {
"message": "******** booted=%b msg=%b haveBoot=%b haveApp=%b haveWall=%b wallEnabled=%b haveKeyguard=%b",
"level": "INFO",
@@ -733,11 +895,11 @@
"group": "WM_DEBUG_BOOT",
"at": "com\/android\/server\/wm\/WindowManagerService.java"
},
- "-603199586": {
- "message": "Clearing focused app, displayId=%d",
+ "-593535526": {
+ "message": "Binding proc %s with config %s",
"level": "VERBOSE",
- "group": "WM_DEBUG_FOCUS_LIGHT",
- "at": "com\/android\/server\/wm\/DisplayContent.java"
+ "group": "WM_DEBUG_CONFIGURATION",
+ "at": "com\/android\/server\/am\/ActivityManagerService.java"
},
"-583031528": {
"message": "%s",
@@ -751,12 +913,24 @@
"group": "WM_DEBUG_ORIENTATION",
"at": "com\/android\/server\/wm\/DisplayRotation.java"
},
+ "-561092364": {
+ "message": "onPointerDownOutsideFocusLocked called on %s",
+ "level": "INFO",
+ "group": "WM_DEBUG_FOCUS_LIGHT",
+ "at": "com\/android\/server\/wm\/WindowManagerService.java"
+ },
"-549028919": {
"message": "enableScreenIfNeededLocked: mDisplayEnabled=%b mForceDisplayEnabled=%b mShowingBootMessages=%b mSystemBooted=%b. %s",
"level": "INFO",
"group": "WM_DEBUG_BOOT",
"at": "com\/android\/server\/wm\/WindowManagerService.java"
},
+ "-548282316": {
+ "message": "setLockTaskMode: Locking to %s Callers=%s",
+ "level": "WARN",
+ "group": "WM_DEBUG_LOCKTASK",
+ "at": "com\/android\/server\/wm\/LockTaskController.java"
+ },
"-547111355": {
"message": "hideIme Control target: %s ",
"level": "DEBUG",
@@ -781,6 +955,18 @@
"group": "WM_ERROR",
"at": "com\/android\/server\/wm\/WindowManagerService.java"
},
+ "-503656156": {
+ "message": "Update process config of %s to new config %s",
+ "level": "VERBOSE",
+ "group": "WM_DEBUG_CONFIGURATION",
+ "at": "com\/android\/server\/wm\/ActivityTaskManagerService.java"
+ },
+ "-497620140": {
+ "message": "Transaction ready, syncId=%d",
+ "level": "VERBOSE",
+ "group": "WM_DEBUG_WINDOW_ORGANIZER",
+ "at": "com\/android\/server\/wm\/WindowOrganizerController.java"
+ },
"-496681057": {
"message": "Attempted to get remove mode of a display that does not exist: %d",
"level": "WARN",
@@ -799,6 +985,12 @@
"group": "WM_SHOW_SURFACE_ALLOC",
"at": "com\/android\/server\/wm\/WindowStateAnimator.java"
},
+ "-449118559": {
+ "message": "Trying to update display configuration for invalid process, pid=%d",
+ "level": "WARN",
+ "group": "WM_DEBUG_CONFIGURATION",
+ "at": "com\/android\/server\/wm\/ActivityTaskManagerService.java"
+ },
"-445944810": {
"message": "finish(%b): mCanceled=%b",
"level": "DEBUG",
@@ -835,6 +1027,12 @@
"group": "WM_DEBUG_STARTING_WINDOW",
"at": "com\/android\/server\/wm\/TaskSnapshotSurface.java"
},
+ "-401282500": {
+ "message": "destroyIfPossible: r=%s destroy returned removed=%s",
+ "level": "DEBUG",
+ "group": "WM_DEBUG_CONTAINERS",
+ "at": "com\/android\/server\/wm\/ActivityRecord.java"
+ },
"-395922585": {
"message": "InsetsSource setWin %s",
"level": "DEBUG",
@@ -907,18 +1105,42 @@
"group": "WM_DEBUG_ADD_REMOVE",
"at": "com\/android\/server\/wm\/WindowState.java"
},
+ "-317194205": {
+ "message": "clearLockedTasks: %s",
+ "level": "INFO",
+ "group": "WM_DEBUG_LOCKTASK",
+ "at": "com\/android\/server\/wm\/LockTaskController.java"
+ },
"-303497363": {
"message": "reparent: moving activity=%s to task=%d at %d",
"level": "INFO",
"group": "WM_DEBUG_ADD_REMOVE",
"at": "com\/android\/server\/wm\/ActivityRecord.java"
},
+ "-272719931": {
+ "message": "startLockTaskModeLocked: %s",
+ "level": "WARN",
+ "group": "WM_DEBUG_LOCKTASK",
+ "at": "com\/android\/server\/wm\/ActivityTaskManagerService.java"
+ },
+ "-260960989": {
+ "message": "Removing and adding activity %s to stack at top callers=%s",
+ "level": "INFO",
+ "group": "WM_DEBUG_ADD_REMOVE",
+ "at": "com\/android\/server\/wm\/Task.java"
+ },
"-251259736": {
"message": "No longer freezing: %s",
"level": "VERBOSE",
"group": "WM_DEBUG_ORIENTATION",
"at": "com\/android\/server\/wm\/ActivityRecord.java"
},
+ "-235225312": {
+ "message": "Skipping config check for initializing activity: %s",
+ "level": "VERBOSE",
+ "group": "WM_DEBUG_CONFIGURATION",
+ "at": "com\/android\/server\/wm\/ActivityRecord.java"
+ },
"-198463978": {
"message": "updateRotationUnchecked: alwaysSendConfiguration=%b forceRelayout=%b",
"level": "VERBOSE",
@@ -943,6 +1165,12 @@
"group": "WM_DEBUG_RECENTS_ANIMATIONS",
"at": "com\/android\/server\/wm\/RecentsAnimationController.java"
},
+ "-168799453": {
+ "message": "Allowing features %d:0x%s",
+ "level": "WARN",
+ "group": "WM_DEBUG_LOCKTASK",
+ "at": "com\/android\/server\/wm\/ActivityTaskManagerService.java"
+ },
"-167822951": {
"message": "Attempted to add starting window to token with already existing starting window",
"level": "WARN",
@@ -973,11 +1201,11 @@
"group": "WM_DEBUG_RECENTS_ANIMATIONS",
"at": "com\/android\/server\/wm\/RecentsAnimation.java"
},
- "-96848838": {
- "message": "Gaining focus: %s",
- "level": "INFO",
- "group": "WM_DEBUG_FOCUS_LIGHT",
- "at": "com\/android\/server\/wm\/WindowManagerService.java"
+ "-90559682": {
+ "message": "Config is skipping already pausing %s",
+ "level": "VERBOSE",
+ "group": "WM_DEBUG_CONFIGURATION",
+ "at": "com\/android\/server\/wm\/ActivityRecord.java"
},
"-87705714": {
"message": "findFocusedWindow: focusedApp=null using new focus @ %s",
@@ -1129,6 +1357,12 @@
"group": "WM_DEBUG_STARTING_WINDOW",
"at": "com\/android\/server\/wm\/ActivityRecord.java"
},
+ "115358443": {
+ "message": "Focus changing: %s -> %s",
+ "level": "INFO",
+ "group": "WM_DEBUG_FOCUS_LIGHT",
+ "at": "com\/android\/server\/wm\/WindowManagerService.java"
+ },
"123161180": {
"message": "SEVER CHILDREN",
"level": "INFO",
@@ -1159,6 +1393,12 @@
"group": "WM_SHOW_SURFACE_ALLOC",
"at": "com\/android\/server\/wm\/BlackFrame.java"
},
+ "174572959": {
+ "message": "DisplayArea info changed name=%s",
+ "level": "VERBOSE",
+ "group": "WM_DEBUG_WINDOW_ORGANIZER",
+ "at": "com\/android\/server\/wm\/DisplayAreaOrganizerController.java"
+ },
"184362060": {
"message": "screenshotTask(%d): mCanceled=%b",
"level": "DEBUG",
@@ -1201,6 +1441,12 @@
"group": "WM_DEBUG_KEEP_SCREEN_ON",
"at": "com\/android\/server\/wm\/RootWindowContainer.java"
},
+ "232317536": {
+ "message": "Set intercept back pressed on root=%b",
+ "level": "VERBOSE",
+ "group": "WM_DEBUG_WINDOW_ORGANIZER",
+ "at": "com\/android\/server\/wm\/TaskOrganizerController.java"
+ },
"241961619": {
"message": "Adding %s to %s",
"level": "VERBOSE",
@@ -1219,6 +1465,12 @@
"group": "WM_DEBUG_REMOTE_ANIMATIONS",
"at": "com\/android\/server\/wm\/RemoteAnimationController.java"
},
+ "251812577": {
+ "message": "Register display organizer=%s uid=%d",
+ "level": "VERBOSE",
+ "group": "WM_DEBUG_WINDOW_ORGANIZER",
+ "at": "com\/android\/server\/wm\/DisplayAreaOrganizerController.java"
+ },
"254883724": {
"message": "addWindowToken: Attempted to add binder token: %s for already created window token: %s displayId=%d",
"level": "WARN",
@@ -1243,12 +1495,6 @@
"group": "WM_DEBUG_APP_TRANSITIONS_ANIM",
"at": "com\/android\/server\/wm\/AppTransition.java"
},
- "285317231": {
- "message": "Input focus has changed to %s",
- "level": "DEBUG",
- "group": "WM_DEBUG_FOCUS_LIGHT",
- "at": "com\/android\/server\/wm\/InputMonitor.java"
- },
"288485303": {
"message": "Attempted to set remove mode to a display that does not exist: %d",
"level": "WARN",
@@ -1267,6 +1513,12 @@
"group": "WM_DEBUG_ORIENTATION",
"at": "com\/android\/server\/wm\/DisplayRotation.java"
},
+ "302969511": {
+ "message": "Task info changed taskId=%d",
+ "level": "VERBOSE",
+ "group": "WM_DEBUG_WINDOW_ORGANIZER",
+ "at": "com\/android\/server\/wm\/TaskOrganizerController.java"
+ },
"302992539": {
"message": "addAnimation(%s)",
"level": "DEBUG",
@@ -1279,6 +1531,12 @@
"group": "WM_SHOW_TRANSACTIONS",
"at": "com\/android\/server\/wm\/WindowSurfaceController.java"
},
+ "312030608": {
+ "message": "New topFocusedDisplayId=%d",
+ "level": "DEBUG",
+ "group": "WM_DEBUG_FOCUS_LIGHT",
+ "at": "com\/android\/server\/wm\/RootWindowContainer.java"
+ },
"315395835": {
"message": "Trying to add window with invalid user=%d",
"level": "WARN",
@@ -1303,6 +1561,12 @@
"group": "WM_DEBUG_ORIENTATION",
"at": "com\/android\/server\/wm\/WindowManagerService.java"
},
+ "355940361": {
+ "message": "Config is destroying non-running %s",
+ "level": "VERBOSE",
+ "group": "WM_DEBUG_CONFIGURATION",
+ "at": "com\/android\/server\/wm\/ActivityRecord.java"
+ },
"371641947": {
"message": "Window Manager Crash %s",
"level": "WTF",
@@ -1315,18 +1579,18 @@
"group": "WM_ERROR",
"at": "com\/android\/server\/wm\/WindowManagerService.java"
},
+ "374506950": {
+ "message": "Reporting activity moved to display, activityRecord=%s, displayId=%d, config=%s",
+ "level": "VERBOSE",
+ "group": "WM_DEBUG_SWITCH",
+ "at": "com\/android\/server\/wm\/ActivityRecord.java"
+ },
"374972436": {
"message": "performEnableScreen: Waiting for anim complete",
"level": "INFO",
"group": "WM_DEBUG_BOOT",
"at": "com\/android\/server\/wm\/WindowManagerService.java"
},
- "385096046": {
- "message": "Delaying loss of focus...",
- "level": "INFO",
- "group": "WM_DEBUG_FOCUS_LIGHT",
- "at": "com\/android\/server\/wm\/WindowManagerService.java"
- },
"399841913": {
"message": "SURFACE RECOVER DESTROY: %s",
"level": "INFO",
@@ -1375,6 +1639,12 @@
"group": "WM_DEBUG_RECENTS_ANIMATIONS",
"at": "com\/android\/server\/wm\/RecentsAnimation.java"
},
+ "487621047": {
+ "message": "DisplayArea vanished name=%s",
+ "level": "VERBOSE",
+ "group": "WM_DEBUG_WINDOW_ORGANIZER",
+ "at": "com\/android\/server\/wm\/DisplayAreaOrganizerController.java"
+ },
"490877640": {
"message": "onStackOrderChanged(): stack=%s",
"level": "DEBUG",
@@ -1411,6 +1681,12 @@
"group": "WM_DEBUG_BOOT",
"at": "com\/android\/server\/wm\/WindowManagerService.java"
},
+ "556758086": {
+ "message": "Applying new update lock state '%s' for %s",
+ "level": "DEBUG",
+ "group": "WM_DEBUG_IMMERSIVE",
+ "at": "com\/android\/server\/wm\/ActivityTaskManagerService.java"
+ },
"557227556": {
"message": "onAnimationFinished(): Notify animation finished:",
"level": "DEBUG",
@@ -1423,12 +1699,6 @@
"group": "WM_SHOW_TRANSACTIONS",
"at": "com\/android\/server\/wm\/WindowSurfaceController.java"
},
- "584499099": {
- "message": "Set focused app to: %s moveFocusNow=%b displayId=%d",
- "level": "VERBOSE",
- "group": "WM_DEBUG_FOCUS_LIGHT",
- "at": "com\/android\/server\/wm\/DisplayContent.java"
- },
"585096182": {
"message": "SURFACE isColorSpaceAgnostic=%b: %s",
"level": "INFO",
@@ -1471,6 +1741,12 @@
"group": "WM_ERROR",
"at": "com\/android\/server\/wm\/WindowManagerService.java"
},
+ "620519522": {
+ "message": "findFocusedWindow: No focusable windows, display=%d",
+ "level": "VERBOSE",
+ "group": "WM_DEBUG_FOCUS_LIGHT",
+ "at": "com\/android\/server\/wm\/DisplayContent.java"
+ },
"628276090": {
"message": "Delaying app transition for screen rotation animation to finish",
"level": "VERBOSE",
@@ -1531,12 +1807,6 @@
"group": "WM_DEBUG_SCREEN_ON",
"at": "com\/android\/server\/wm\/WindowManagerService.java"
},
- "676824470": {
- "message": "Test completed successfully: %b %d %o %x %e %g %f %% %s.",
- "level": "ERROR",
- "group": "TEST_GROUP",
- "at": "com\/android\/server\/wm\/ProtoLogGroup.java"
- },
"685047360": {
"message": "Resizing window %s",
"level": "VERBOSE",
@@ -1561,6 +1831,18 @@
"group": "WM_ERROR",
"at": "com\/android\/server\/wm\/WindowManagerService.java"
},
+ "715749922": {
+ "message": "Allowlisting %d:%s",
+ "level": "WARN",
+ "group": "WM_DEBUG_LOCKTASK",
+ "at": "com\/android\/server\/wm\/ActivityTaskManagerService.java"
+ },
+ "736692676": {
+ "message": "Config is relaunching %s",
+ "level": "VERBOSE",
+ "group": "WM_DEBUG_CONFIGURATION",
+ "at": "com\/android\/server\/wm\/ActivityRecord.java"
+ },
"745391677": {
"message": " CREATE SURFACE %s IN SESSION %s: pid=%d format=%d flags=0x%x \/ %s",
"level": "INFO",
@@ -1615,6 +1897,18 @@
"group": "WM_DEBUG_RECENTS_ANIMATIONS",
"at": "com\/android\/server\/wm\/RecentsAnimation.java"
},
+ "869266572": {
+ "message": "Removing activity %s from stack, reason= %s callers=%s",
+ "level": "INFO",
+ "group": "WM_DEBUG_ADD_REMOVE",
+ "at": "com\/android\/server\/wm\/ActivityRecord.java"
+ },
+ "872933199": {
+ "message": "Changing focus from %s to %s displayId=%d Callers=%s",
+ "level": "DEBUG",
+ "group": "WM_DEBUG_FOCUS_LIGHT",
+ "at": "com\/android\/server\/wm\/DisplayContent.java"
+ },
"873914452": {
"message": "goodToGo()",
"level": "DEBUG",
@@ -1633,6 +1927,12 @@
"group": "WM_ERROR",
"at": "com\/android\/server\/wm\/WindowManagerService.java"
},
+ "906215061": {
+ "message": "Apply window transaction, syncId=%d",
+ "level": "VERBOSE",
+ "group": "WM_DEBUG_WINDOW_ORGANIZER",
+ "at": "com\/android\/server\/wm\/WindowOrganizerController.java"
+ },
"913494177": {
"message": "removeAllWindowsIfPossible: removing win=%s",
"level": "WARN",
@@ -1645,12 +1945,30 @@
"group": "WM_DEBUG_ORIENTATION",
"at": "com\/android\/server\/wm\/WindowStateAnimator.java"
},
+ "950074526": {
+ "message": "setLockTaskMode: Can't lock due to auth",
+ "level": "WARN",
+ "group": "WM_DEBUG_LOCKTASK",
+ "at": "com\/android\/server\/wm\/LockTaskController.java"
+ },
"954470154": {
"message": "FORCED DISPLAY SCALING DISABLED",
"level": "INFO",
"group": "WM_ERROR",
"at": "com\/android\/server\/wm\/WindowManagerService.java"
},
+ "956374481": {
+ "message": "removeLockedTask: task=%s last task, reverting locktask mode. Callers=%s",
+ "level": "DEBUG",
+ "group": "WM_DEBUG_LOCKTASK",
+ "at": "com\/android\/server\/wm\/LockTaskController.java"
+ },
+ "969323241": {
+ "message": "Sending new config to %s, config: %s",
+ "level": "VERBOSE",
+ "group": "WM_DEBUG_CONFIGURATION",
+ "at": "com\/android\/server\/wm\/ActivityRecord.java"
+ },
"972354148": {
"message": "\tcontainer=%s",
"level": "DEBUG",
@@ -1663,12 +1981,24 @@
"group": "WM_ERROR",
"at": "com\/android\/server\/wm\/WindowManagerService.java"
},
+ "1040675582": {
+ "message": "Can't report activity configuration update - client not running, activityRecord=%s",
+ "level": "WARN",
+ "group": "WM_DEBUG_CONFIGURATION",
+ "at": "com\/android\/server\/wm\/ActivityRecord.java"
+ },
"1046922686": {
"message": "requestScrollCapture: caught exception dispatching callback: %s",
"level": "WARN",
"group": "WM_ERROR",
"at": "com\/android\/server\/wm\/WindowManagerService.java"
},
+ "1049367566": {
+ "message": "Sending to proc %s new config %s",
+ "level": "VERBOSE",
+ "group": "WM_DEBUG_CONFIGURATION",
+ "at": "com\/android\/server\/wm\/WindowProcessController.java"
+ },
"1051545910": {
"message": "Exit animation finished in %s: remove=%b",
"level": "VERBOSE",
@@ -1681,6 +2011,12 @@
"group": "WM_DEBUG_REMOTE_ANIMATIONS",
"at": "com\/android\/server\/wm\/WallpaperAnimationAdapter.java"
},
+ "1088929964": {
+ "message": "onLockTaskPackagesUpdated: starting new locktask task=%s",
+ "level": "DEBUG",
+ "group": "WM_DEBUG_LOCKTASK",
+ "at": "com\/android\/server\/wm\/LockTaskController.java"
+ },
"1089714158": {
"message": " FREEZE %s: DESTROY",
"level": "INFO",
@@ -1705,6 +2041,12 @@
"group": "WM_DEBUG_SCREEN_ON",
"at": "com\/android\/server\/wm\/DisplayPolicy.java"
},
+ "1149424314": {
+ "message": "Unregister display organizer=%s uid=%d",
+ "level": "VERBOSE",
+ "group": "WM_DEBUG_WINDOW_ORGANIZER",
+ "at": "com\/android\/server\/wm\/DisplayAreaOrganizerController.java"
+ },
"1160771501": {
"message": "Resize reasons for w=%s: %s surfaceResized=%b configChanged=%b dragResizingChanged=%b reportOrientationChanged=%b",
"level": "VERBOSE",
@@ -1789,17 +2131,23 @@
"group": "WM_ERROR",
"at": "com\/android\/server\/wm\/WindowManagerService.java"
},
+ "1337596507": {
+ "message": "Sending to proc %s new compat %s",
+ "level": "VERBOSE",
+ "group": "WM_DEBUG_CONFIGURATION",
+ "at": "com\/android\/server\/wm\/CompatModePackages.java"
+ },
"1346895820": {
"message": "ScreenRotation still animating: type: %d\nmDisplayAnimator: %s\nmEnterBlackFrameAnimator: %s\nmRotateScreenAnimator: %s\nmScreenshotRotationAnimator: %s",
"level": "VERBOSE",
"group": "WM_DEBUG_ORIENTATION",
"at": "com\/android\/server\/wm\/ScreenRotationAnimation.java"
},
- "1358462645": {
- "message": "Looking for focus: %s, flags=%d, canReceive=%b",
- "level": "VERBOSE",
- "group": "WM_DEBUG_FOCUS",
- "at": "com\/android\/server\/wm\/DisplayContent.java"
+ "1360551978": {
+ "message": "Trying to update display configuration for non-existing displayId=%d",
+ "level": "WARN",
+ "group": "WM_DEBUG_CONFIGURATION",
+ "at": "com\/android\/server\/wm\/ActivityTaskManagerService.java"
},
"1364498663": {
"message": "notifyAppResumed: wasStopped=%b %s",
@@ -1819,6 +2167,12 @@
"group": "WM_DEBUG_ORIENTATION",
"at": "com\/android\/server\/wm\/TaskDisplayArea.java"
},
+ "1401295262": {
+ "message": "Mode default, asking user",
+ "level": "WARN",
+ "group": "WM_DEBUG_LOCKTASK",
+ "at": "com\/android\/server\/wm\/LockTaskController.java"
+ },
"1401700824": {
"message": "Window drawn win=%s",
"level": "DEBUG",
@@ -1879,12 +2233,6 @@
"group": "WM_DEBUG_APP_TRANSITIONS_ANIM",
"at": "com\/android\/server\/wm\/AppTransitionController.java"
},
- "1469292670": {
- "message": "Changing focus from %s to %s displayId=%d Callers=%s",
- "level": "VERBOSE",
- "group": "WM_DEBUG_FOCUS_LIGHT",
- "at": "com\/android\/server\/wm\/DisplayContent.java"
- },
"1495525537": {
"message": "createWallpaperAnimations()",
"level": "DEBUG",
@@ -1927,6 +2275,12 @@
"group": "WM_ERROR",
"at": "com\/android\/server\/wm\/WindowManagerService.java"
},
+ "1522489371": {
+ "message": "moveActivityStackToFront: activity=%s",
+ "level": "DEBUG",
+ "group": "WM_DEBUG_FOCUS",
+ "at": "com\/android\/server\/wm\/ActivityRecord.java"
+ },
"1525976603": {
"message": "cancelAnimation(): reason=%s",
"level": "DEBUG",
@@ -1951,6 +2305,12 @@
"group": "WM_ERROR",
"at": "com\/android\/server\/wm\/WindowManagerService.java"
},
+ "1576607724": {
+ "message": "Report configuration: %s %s %s",
+ "level": "VERBOSE",
+ "group": "WM_DEBUG_CONFIGURATION",
+ "at": "com\/android\/server\/wm\/ActivityTaskManagerService.java"
+ },
"1577579529": {
"message": "win=%s destroySurfaces: appStopped=%b win.mWindowRemovalAllowed=%b win.mRemoveOnExit=%b",
"level": "ERROR",
@@ -1981,6 +2341,12 @@
"group": "WM_DEBUG_ORIENTATION",
"at": "com\/android\/server\/wm\/WindowManagerService.java"
},
+ "1635062046": {
+ "message": "Skipping config check invisible: %s",
+ "level": "VERBOSE",
+ "group": "WM_DEBUG_CONFIGURATION",
+ "at": "com\/android\/server\/wm\/ActivityRecord.java"
+ },
"1635462459": {
"message": "onMovedByResize: Moving %s",
"level": "DEBUG",
@@ -2023,6 +2389,12 @@
"group": "WM_DEBUG_STARTING_WINDOW",
"at": "com\/android\/server\/wm\/ActivityRecord.java"
},
+ "1679569477": {
+ "message": "Configuration doesn't matter not running %s",
+ "level": "VERBOSE",
+ "group": "WM_DEBUG_CONFIGURATION",
+ "at": "com\/android\/server\/wm\/ActivityRecord.java"
+ },
"1720229827": {
"message": "Creating animation bounds layer",
"level": "INFO",
@@ -2077,12 +2449,30 @@
"group": "WM_ERROR",
"at": "com\/android\/server\/wm\/WindowManagerService.java"
},
+ "1789603530": {
+ "message": "Removing activity %s hasSavedState=%b stateNotNeeded=%s finishing=%b state=%s callers=%s",
+ "level": "INFO",
+ "group": "WM_DEBUG_ADD_REMOVE",
+ "at": "com\/android\/server\/wm\/ActivityRecord.java"
+ },
"1822843721": {
"message": "Aborted starting %s: startingData=%s",
"level": "VERBOSE",
"group": "WM_DEBUG_STARTING_WINDOW",
"at": "com\/android\/server\/wm\/ActivityRecord.java"
},
+ "1824105730": {
+ "message": "setLockTaskAuth: task=%s mLockTaskAuth=%s",
+ "level": "DEBUG",
+ "group": "WM_DEBUG_LOCKTASK",
+ "at": "com\/android\/server\/wm\/Task.java"
+ },
+ "1829094918": {
+ "message": "onLockTaskPackagesUpdated: removing %s mLockTaskAuth()=%s",
+ "level": "DEBUG",
+ "group": "WM_DEBUG_LOCKTASK",
+ "at": "com\/android\/server\/wm\/LockTaskController.java"
+ },
"1831008694": {
"message": "Loading animation for app transition. transit=%s enter=%b frame=%s insets=%s surfaceInsets=%s",
"level": "DEBUG",
@@ -2131,6 +2521,12 @@
"group": "WM_DEBUG_ADD_REMOVE",
"at": "com\/android\/server\/wm\/ActivityRecord.java"
},
+ "1918448345": {
+ "message": "Task appeared taskId=%d",
+ "level": "VERBOSE",
+ "group": "WM_DEBUG_WINDOW_ORGANIZER",
+ "at": "com\/android\/server\/wm\/TaskOrganizerController.java"
+ },
"1921821199": {
"message": "Preserving %s until the new one is added",
"level": "VERBOSE",
@@ -2161,6 +2557,12 @@
"group": "WM_DEBUG_APP_TRANSITIONS",
"at": "com\/android\/server\/wm\/AppTransitionController.java"
},
+ "1975793405": {
+ "message": "setFocusedStack: stackId=%d",
+ "level": "DEBUG",
+ "group": "WM_DEBUG_FOCUS",
+ "at": "com\/android\/server\/wm\/ActivityTaskManagerService.java"
+ },
"1984470582": {
"message": "Creating TaskScreenshotAnimatable: task: %s width: %d height: %d",
"level": "DEBUG",
@@ -2173,6 +2575,12 @@
"group": "WM_SHOW_TRANSACTIONS",
"at": "com\/android\/server\/wm\/WindowAnimator.java"
},
+ "1995093920": {
+ "message": "Checking to restart %s: changed=0x%s, handles=0x%s, mLastReportedConfiguration=%s",
+ "level": "VERBOSE",
+ "group": "WM_DEBUG_CONFIGURATION",
+ "at": "com\/android\/server\/wm\/ActivityRecord.java"
+ },
"2016061474": {
"message": "Prepare app transition: transit=%s %s alwaysKeepCurrent=%b displayId=%d Callers=%s",
"level": "VERBOSE",
@@ -2191,6 +2599,12 @@
"group": "WM_DEBUG_STARTING_WINDOW",
"at": "com\/android\/server\/wm\/ActivityRecord.java"
},
+ "2022322588": {
+ "message": "Adding activity %s to stack to task %s callers: %s",
+ "level": "INFO",
+ "group": "WM_DEBUG_ADD_REMOVE",
+ "at": "com\/android\/server\/wm\/Task.java"
+ },
"2022422429": {
"message": "createAnimationAdapter(): container=%s",
"level": "DEBUG",
@@ -2257,18 +2671,18 @@
"group": "WM_DEBUG_IME",
"at": "com\/android\/server\/wm\/DisplayContent.java"
},
- "2128604122": {
- "message": "findFocusedWindow: No focusable windows.",
- "level": "VERBOSE",
- "group": "WM_DEBUG_FOCUS_LIGHT",
- "at": "com\/android\/server\/wm\/DisplayContent.java"
- },
"2128917433": {
"message": "onProposedRotationChanged, rotation=%d",
"level": "VERBOSE",
"group": "WM_DEBUG_ORIENTATION",
"at": "com\/android\/server\/wm\/DisplayRotation.java"
},
+ "2134999275": {
+ "message": "moveActivityStackToFront: already on top, activity=%s",
+ "level": "DEBUG",
+ "group": "WM_DEBUG_FOCUS",
+ "at": "com\/android\/server\/wm\/ActivityRecord.java"
+ },
"2137411379": {
"message": "applyAnimation: anim=%s animAttr=0x%x transit=%s isEntrance=%b Callers=%s",
"level": "VERBOSE",
@@ -2277,9 +2691,6 @@
}
},
"groups": {
- "TEST_GROUP": {
- "tag": "WindowManagetProtoLogTest"
- },
"WM_DEBUG_ADD_REMOVE": {
"tag": "WindowManager"
},
@@ -2292,6 +2703,12 @@
"WM_DEBUG_BOOT": {
"tag": "WindowManager"
},
+ "WM_DEBUG_CONFIGURATION": {
+ "tag": "WindowManager"
+ },
+ "WM_DEBUG_CONTAINERS": {
+ "tag": "WindowManager"
+ },
"WM_DEBUG_DRAW": {
"tag": "WindowManager"
},
@@ -2304,9 +2721,15 @@
"WM_DEBUG_IME": {
"tag": "WindowManager"
},
+ "WM_DEBUG_IMMERSIVE": {
+ "tag": "WindowManager"
+ },
"WM_DEBUG_KEEP_SCREEN_ON": {
"tag": "WindowManager"
},
+ "WM_DEBUG_LOCKTASK": {
+ "tag": "WindowManager"
+ },
"WM_DEBUG_ORIENTATION": {
"tag": "WindowManager"
},
@@ -2325,9 +2748,15 @@
"WM_DEBUG_STARTING_WINDOW": {
"tag": "WindowManager"
},
+ "WM_DEBUG_SWITCH": {
+ "tag": "WindowManager"
+ },
"WM_DEBUG_WINDOW_MOVEMENT": {
"tag": "WindowManager"
},
+ "WM_DEBUG_WINDOW_ORGANIZER": {
+ "tag": "WindowManager"
+ },
"WM_ERROR": {
"tag": "WindowManager"
},
diff --git a/data/keyboards/Generic.kcm b/data/keyboards/Generic.kcm
index 1ab4c6385ac1..fe6eeeb66e40 100644
--- a/data/keyboards/Generic.kcm
+++ b/data/keyboards/Generic.kcm
@@ -28,12 +28,14 @@ key A {
label: 'A'
base: 'a'
shift, capslock: 'A'
+ shift+capslock: 'a'
}
key B {
label: 'B'
base: 'b'
shift, capslock: 'B'
+ shift+capslock: 'b'
}
key C {
@@ -42,12 +44,14 @@ key C {
shift, capslock: 'C'
alt: '\u00e7'
shift+alt: '\u00c7'
+ shift+capslock: 'c'
}
key D {
label: 'D'
base: 'd'
shift, capslock: 'D'
+ shift+capslock: 'd'
}
key E {
@@ -55,24 +59,28 @@ key E {
base: 'e'
shift, capslock: 'E'
alt: '\u0301'
+ shift+capslock: 'e'
}
key F {
label: 'F'
base: 'f'
shift, capslock: 'F'
+ shift+capslock: 'f'
}
key G {
label: 'G'
base: 'g'
shift, capslock: 'G'
+ shift+capslock: 'g'
}
key H {
label: 'H'
base: 'h'
shift, capslock: 'H'
+ shift+capslock: 'h'
}
key I {
@@ -80,30 +88,35 @@ key I {
base: 'i'
shift, capslock: 'I'
alt: '\u0302'
+ shift+capslock: 'i'
}
key J {
label: 'J'
base: 'j'
shift, capslock: 'J'
+ shift+capslock: 'j'
}
key K {
label: 'K'
base: 'k'
shift, capslock: 'K'
+ shift+capslock: 'k'
}
key L {
label: 'L'
base: 'l'
shift, capslock: 'L'
+ shift+capslock: 'l'
}
key M {
label: 'M'
base: 'm'
shift, capslock: 'M'
+ shift+capslock: 'm'
}
key N {
@@ -111,30 +124,35 @@ key N {
base: 'n'
shift, capslock: 'N'
alt: '\u0303'
+ shift+capslock: 'n'
}
key O {
label: 'O'
base: 'o'
shift, capslock: 'O'
+ shift+capslock: 'o'
}
key P {
label: 'P'
base: 'p'
shift, capslock: 'P'
+ shift+capslock: 'p'
}
key Q {
label: 'Q'
base: 'q'
shift, capslock: 'Q'
+ shift+capslock: 'q'
}
key R {
label: 'R'
base: 'r'
shift, capslock: 'R'
+ shift+capslock: 'r'
}
key S {
@@ -142,12 +160,14 @@ key S {
base: 's'
shift, capslock: 'S'
alt: '\u00df'
+ shift+capslock: 's'
}
key T {
label: 'T'
base: 't'
shift, capslock: 'T'
+ shift+capslock: 't'
}
key U {
@@ -155,36 +175,42 @@ key U {
base: 'u'
shift, capslock: 'U'
alt: '\u0308'
+ shift+capslock: 'u'
}
key V {
label: 'V'
base: 'v'
shift, capslock: 'V'
+ shift+capslock: 'v'
}
key W {
label: 'W'
base: 'w'
shift, capslock: 'W'
+ shift+capslock: 'w'
}
key X {
label: 'X'
base: 'x'
shift, capslock: 'X'
+ shift+capslock: 'x'
}
key Y {
label: 'Y'
base: 'y'
shift, capslock: 'Y'
+ shift+capslock: 'y'
}
key Z {
label: 'Z'
base: 'z'
shift, capslock: 'Z'
+ shift+capslock: 'z'
}
key 0 {
diff --git a/graphics/java/android/graphics/Bitmap.java b/graphics/java/android/graphics/Bitmap.java
index f41049058a62..4f95a53e0ec8 100644
--- a/graphics/java/android/graphics/Bitmap.java
+++ b/graphics/java/android/graphics/Bitmap.java
@@ -684,15 +684,13 @@ public final class Bitmap implements Parcelable {
return b;
}
- // FIXME: The maxTargetSdk should be R, once R is no longer set to
- // CUR_DEVELOPMENT.
/**
* Creates a new immutable bitmap backed by ashmem which can efficiently
* be passed between processes.
*
* @hide
*/
- @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.Q,
+ @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R,
publicAlternatives = "Use {@link #asShared()} instead")
public Bitmap createAshmemBitmap() {
checkRecycled("Can't copy a recycled bitmap");
diff --git a/keystore/TEST_MAPPING b/keystore/TEST_MAPPING
new file mode 100644
index 000000000000..0511967a229b
--- /dev/null
+++ b/keystore/TEST_MAPPING
@@ -0,0 +1,74 @@
+{
+ "presubmit": [
+ {
+ "name": "CtsKeystoreTestCases",
+ "options": [
+ {
+ "include-annotation": "android.platform.test.annotations.RequiresDevice"
+ },
+ {
+ "exclude-filter": "android.keystore.cts.SignatureTest"
+ },
+ {
+ "exclude-filter": "android.keystore.cts.RsaSignaturePerformanceTest"
+ },
+ {
+ "exclude-filter": "android.keystore.cts.RsaKeyGenPerformanceTest"
+ },
+ {
+ "exclude-filter": "android.keystore.cts.RsaCipherPerformanceTest"
+ },
+ {
+ "exclude-filter": "android.keystore.cts.MacTest#testLargeMsgKat"
+ },
+ {
+ "exclude-filter": "android.keystore.cts.KeyPairGeneratorTest"
+ },
+ {
+ "exclude-filter": "android.keystore.cts.KeyGeneratorTest#testHmacKeySupportedSizes"
+ },
+ {
+ "exclude-filter": "android.keystore.cts.HmacMacPerformanceTest"
+ },
+ {
+ "exclude-filter": "android.keystore.cts.EcdsaSignaturePerformanceTest"
+ },
+ {
+ "exclude-filter": "android.keystore.cts.EcKeyGenPerformanceTest"
+ },
+ {
+ "exclude-filter": "android.keystore.cts.DesCipherPerformanceTest"
+ },
+ {
+ "exclude-filter": "android.keystore.cts.CipherTest"
+ },
+ {
+ "exclude-filter": "android.keystore.cts.AttestationPerformanceTest"
+ },
+ {
+ "exclude-filter": "android.keystore.cts.AndroidKeyStoreTest"
+ },
+ {
+ "exclude-filter": "android.keystore.cts.AesCipherPerformanceTest"
+ },
+ {
+ "exclude-filter": "android.keystore.cts.AESCipherNistCavpKatTest"
+ },
+ {
+ "exclude-filter": "android.keystore.cts.DESedeECBPKCS7PaddingCipherTest"
+ },
+ {
+ "exclude-filter": "android.keystore.cts.DESedeECBNoPaddingCipherTest"
+ },
+ {
+ "exclude-filter": "android.keystore.cts.DESedeECBPKCS7PaddingCipherTest"
+ }
+ ]
+ }
+ ],
+ "postsubmit": [
+ {
+ "name": "CtsKeystoreTestCases"
+ }
+ ]
+}
diff --git a/libs/WindowManager/Shell/Android.bp b/libs/WindowManager/Shell/Android.bp
index 843b17703676..16b87c43fc58 100644
--- a/libs/WindowManager/Shell/Android.bp
+++ b/libs/WindowManager/Shell/Android.bp
@@ -12,14 +12,99 @@
// See the License for the specific language governing permissions and
// limitations under the License.
+// Begin ProtoLog
+java_library {
+ name: "wm_shell_protolog-groups",
+ srcs: [
+ "src/com/android/wm/shell/protolog/ShellProtoLogGroup.java",
+ ":protolog-common-src",
+ ],
+}
+
+filegroup {
+ name: "wm_shell-sources",
+ srcs: ["src/**/*.java"],
+ path: "src",
+}
+
+genrule {
+ name: "wm_shell_protolog_src",
+ srcs: [
+ ":wm_shell_protolog-groups",
+ ":wm_shell-sources",
+ ],
+ tools: ["protologtool"],
+ cmd: "$(location protologtool) transform-protolog-calls " +
+ "--protolog-class com.android.internal.protolog.common.ProtoLog " +
+ "--protolog-impl-class com.android.wm.shell.protolog.ShellProtoLogImpl " +
+ "--protolog-cache-class com.android.wm.shell.protolog.ShellProtoLogCache " +
+ "--loggroups-class com.android.wm.shell.protolog.ShellProtoLogGroup " +
+ "--loggroups-jar $(location :wm_shell_protolog-groups) " +
+ "--output-srcjar $(out) " +
+ "$(locations :wm_shell-sources)",
+ out: ["wm_shell_protolog.srcjar"],
+}
+
+genrule {
+ name: "generate-wm_shell_protolog.json",
+ srcs: [
+ ":wm_shell_protolog-groups",
+ ":wm_shell-sources",
+ ],
+ tools: ["protologtool"],
+ cmd: "$(location protologtool) generate-viewer-config " +
+ "--protolog-class com.android.internal.protolog.common.ProtoLog " +
+ "--loggroups-class com.android.wm.shell.protolog.ShellProtoLogGroup " +
+ "--loggroups-jar $(location :wm_shell_protolog-groups) " +
+ "--viewer-conf $(out) " +
+ "$(locations :wm_shell-sources)",
+ out: ["wm_shell_protolog.json"],
+}
+
+filegroup {
+ name: "wm_shell_protolog.json",
+ srcs: ["res/raw/wm_shell_protolog.json"],
+}
+
+genrule {
+ name: "checked-wm_shell_protolog.json",
+ srcs: [
+ ":generate-wm_shell_protolog.json",
+ ":wm_shell_protolog.json",
+ ],
+ cmd: "cp $(location :generate-wm_shell_protolog.json) $(out) && " +
+ "{ ! (diff $(out) $(location :wm_shell_protolog.json) | grep -q '^<') || " +
+ "{ echo -e '\\n\\n################################################################\\n#\\n" +
+ "# ERROR: ProtoLog viewer config is stale. To update it, run:\\n#\\n" +
+ "# cp $(location :generate-wm_shell_protolog.json) " +
+ "$(location :wm_shell_protolog.json)\\n#\\n" +
+ "################################################################\\n\\n' >&2 && false; } }",
+ out: ["wm_shell_protolog.json"],
+}
+// End ProtoLog
+
+java_library {
+ name: "WindowManager-Shell-proto",
+
+ srcs: ["proto/*.proto"],
+
+ proto: {
+ type: "nano",
+ },
+}
+
android_library {
name: "WindowManager-Shell",
srcs: [
- "src/**/*.java",
+ ":wm_shell_protolog_src",
"src/**/I*.aidl",
],
resource_dirs: [
"res",
],
+ static_libs: [
+ "protolog-lib",
+ "WindowManager-Shell-proto",
+ ],
manifest: "AndroidManifest.xml",
-}
+} \ No newline at end of file
diff --git a/libs/WindowManager/Shell/tests/src/com/android/wm/shell/WindowManagerShellTest.java b/libs/WindowManager/Shell/proto/wm_shell_trace.proto
index f1ead3c8a441..b9e72525f32b 100644
--- a/libs/WindowManager/Shell/tests/src/com/android/wm/shell/WindowManagerShellTest.java
+++ b/libs/WindowManager/Shell/proto/wm_shell_trace.proto
@@ -14,25 +14,14 @@
* limitations under the License.
*/
-package com.android.wm.shell;
-
-import androidx.test.ext.junit.runners.AndroidJUnit4;
-import androidx.test.filters.SmallTest;
+syntax = "proto2";
-import org.junit.Test;
-import org.junit.runner.RunWith;
+package com.android.wm.shell;
-/**
- * Tests for the shell.
- */
-@SmallTest
-@RunWith(AndroidJUnit4.class)
-public class WindowManagerShellTest {
+option java_multiple_files = true;
- WindowManagerShell mShell;
+message WmShellTraceProto {
- @Test
- public void testNothing() {
- // Do nothing
- }
+ // Not used, just a test value
+ optional bool test_value = 1;
}
diff --git a/packages/SystemUI/res/anim/forced_resizable_enter.xml b/libs/WindowManager/Shell/res/anim/forced_resizable_enter.xml
index 01b8fdbe4437..01b8fdbe4437 100644
--- a/packages/SystemUI/res/anim/forced_resizable_enter.xml
+++ b/libs/WindowManager/Shell/res/anim/forced_resizable_enter.xml
diff --git a/packages/SystemUI/res/anim/forced_resizable_exit.xml b/libs/WindowManager/Shell/res/anim/forced_resizable_exit.xml
index 6f316a75dbed..6f316a75dbed 100644
--- a/packages/SystemUI/res/anim/forced_resizable_exit.xml
+++ b/libs/WindowManager/Shell/res/anim/forced_resizable_exit.xml
diff --git a/packages/SystemUI/res/layout/divider.xml b/libs/WindowManager/Shell/res/layout/divider.xml
index f1f0df054240..f1f0df054240 100644
--- a/packages/SystemUI/res/layout/divider.xml
+++ b/libs/WindowManager/Shell/res/layout/divider.xml
diff --git a/packages/SystemUI/res/layout/docked_stack_divider.xml b/libs/WindowManager/Shell/res/layout/docked_stack_divider.xml
index 70e5451eed57..ad870252d819 100644
--- a/packages/SystemUI/res/layout/docked_stack_divider.xml
+++ b/libs/WindowManager/Shell/res/layout/docked_stack_divider.xml
@@ -14,7 +14,7 @@
limitations under the License.
-->
-<com.android.systemui.stackdivider.DividerView
+<com.android.wm.shell.splitscreen.DividerView
xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_height="match_parent"
android:layout_width="match_parent">
@@ -24,15 +24,15 @@
android:id="@+id/docked_divider_background"
android:background="@color/docked_divider_background"/>
- <com.android.systemui.stackdivider.MinimizedDockShadow
+ <com.android.wm.shell.splitscreen.MinimizedDockShadow
style="@style/DockedDividerMinimizedShadow"
android:id="@+id/minimized_dock_shadow"
android:alpha="0"/>">
- <com.android.systemui.stackdivider.DividerHandleView
+ <com.android.wm.shell.splitscreen.DividerHandleView
style="@style/DockedDividerHandle"
android:id="@+id/docked_divider_handle"
android:contentDescription="@string/accessibility_divider"
android:background="@null"/>
-</com.android.systemui.stackdivider.DividerView>
+</com.android.wm.shell.splitscreen.DividerView>
diff --git a/packages/SystemUI/res/layout/forced_resizable_activity.xml b/libs/WindowManager/Shell/res/layout/forced_resizable_activity.xml
index 3c778c431a2e..3c778c431a2e 100644
--- a/packages/SystemUI/res/layout/forced_resizable_activity.xml
+++ b/libs/WindowManager/Shell/res/layout/forced_resizable_activity.xml
diff --git a/libs/WindowManager/Shell/res/layout/pip_menu_activity.xml b/libs/WindowManager/Shell/res/layout/pip_menu.xml
index 2e0a5e09e34f..2e0a5e09e34f 100644
--- a/libs/WindowManager/Shell/res/layout/pip_menu_activity.xml
+++ b/libs/WindowManager/Shell/res/layout/pip_menu.xml
diff --git a/libs/WindowManager/Shell/res/raw/wm_shell_protolog.json b/libs/WindowManager/Shell/res/raw/wm_shell_protolog.json
new file mode 100644
index 000000000000..7242793580f9
--- /dev/null
+++ b/libs/WindowManager/Shell/res/raw/wm_shell_protolog.json
@@ -0,0 +1,46 @@
+{
+ "version": "1.0.0",
+ "messages": {
+ "-1340279385": {
+ "message": "Remove listener=%s",
+ "level": "VERBOSE",
+ "group": "WM_SHELL_TASK_ORG",
+ "at": "com\/android\/wm\/shell\/ShellTaskOrganizer.java"
+ },
+ "-880817403": {
+ "message": "Task vanished taskId=%d",
+ "level": "VERBOSE",
+ "group": "WM_SHELL_TASK_ORG",
+ "at": "com\/android\/wm\/shell\/ShellTaskOrganizer.java"
+ },
+ "-460572385": {
+ "message": "Task appeared taskId=%d",
+ "level": "VERBOSE",
+ "group": "WM_SHELL_TASK_ORG",
+ "at": "com\/android\/wm\/shell\/ShellTaskOrganizer.java"
+ },
+ "-242812822": {
+ "message": "Add listener for modes=%s listener=%s",
+ "level": "VERBOSE",
+ "group": "WM_SHELL_TASK_ORG",
+ "at": "com\/android\/wm\/shell\/ShellTaskOrganizer.java"
+ },
+ "157713005": {
+ "message": "Task info changed taskId=%d",
+ "level": "VERBOSE",
+ "group": "WM_SHELL_TASK_ORG",
+ "at": "com\/android\/wm\/shell\/ShellTaskOrganizer.java"
+ },
+ "980952660": {
+ "message": "Task root back pressed taskId=%d",
+ "level": "VERBOSE",
+ "group": "WM_SHELL_TASK_ORG",
+ "at": "com\/android\/wm\/shell\/ShellTaskOrganizer.java"
+ }
+ },
+ "groups": {
+ "WM_SHELL_TASK_ORG": {
+ "tag": "WindowManagerShell"
+ }
+ }
+}
diff --git a/libs/WindowManager/Shell/res/values-land/dimens.xml b/libs/WindowManager/Shell/res/values-land/dimens.xml
new file mode 100644
index 000000000000..77a601ddf440
--- /dev/null
+++ b/libs/WindowManager/Shell/res/values-land/dimens.xml
@@ -0,0 +1,21 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ * 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.
+*/
+-->
+<resources>
+ <dimen name="docked_divider_handle_width">2dp</dimen>
+ <dimen name="docked_divider_handle_height">16dp</dimen>
+</resources> \ No newline at end of file
diff --git a/libs/WindowManager/Shell/res/values-land/styles.xml b/libs/WindowManager/Shell/res/values-land/styles.xml
new file mode 100644
index 000000000000..863bb69d4034
--- /dev/null
+++ b/libs/WindowManager/Shell/res/values-land/styles.xml
@@ -0,0 +1,35 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- 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.
+-->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android">
+ <style name="DockedDividerBackground">
+ <item name="android:layout_width">10dp</item>
+ <item name="android:layout_height">match_parent</item>
+ <item name="android:layout_gravity">center_horizontal</item>
+ </style>
+
+ <style name="DockedDividerHandle">
+ <item name="android:layout_gravity">center_vertical</item>
+ <item name="android:layout_width">48dp</item>
+ <item name="android:layout_height">96dp</item>
+ </style>
+
+ <style name="DockedDividerMinimizedShadow">
+ <item name="android:layout_width">8dp</item>
+ <item name="android:layout_height">match_parent</item>
+ </style>
+</resources>
+
diff --git a/libs/WindowManager/Shell/res/values-sw600dp/config.xml b/libs/WindowManager/Shell/res/values-sw600dp/config.xml
new file mode 100644
index 000000000000..f194532f1e0d
--- /dev/null
+++ b/libs/WindowManager/Shell/res/values-sw600dp/config.xml
@@ -0,0 +1,25 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+/*
+** 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.
+*/
+-->
+
+<!-- These resources are around just to allow their values to be customized
+ for different hardware and product builds. -->
+<resources>
+ <!-- Animation duration when using long press on recents to dock -->
+ <integer name="long_press_dock_anim_duration">290</integer>
+</resources> \ No newline at end of file
diff --git a/libs/WindowManager/Shell/res/values/colors.xml b/libs/WindowManager/Shell/res/values/colors.xml
new file mode 100644
index 000000000000..6a19083e3788
--- /dev/null
+++ b/libs/WindowManager/Shell/res/values/colors.xml
@@ -0,0 +1,25 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+/*
+ * 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.
+ */
+-->
+<resources>
+ <color name="docked_divider_background">#ff000000</color>
+ <color name="docked_divider_handle">#ffffff</color>
+ <drawable name="forced_resizable_background">#59000000</drawable>
+ <color name="minimize_dock_shadow_start">#60000000</color>
+ <color name="minimize_dock_shadow_end">#00000000</color>
+</resources> \ No newline at end of file
diff --git a/libs/WindowManager/Shell/res/values/config.xml b/libs/WindowManager/Shell/res/values/config.xml
index 245c0725c2a8..39efd0768eaa 100644
--- a/libs/WindowManager/Shell/res/values/config.xml
+++ b/libs/WindowManager/Shell/res/values/config.xml
@@ -26,4 +26,7 @@
<!-- Allow PIP to enable round corner, see also R.dimen.pip_corner_radius -->
<bool name="config_pipEnableRoundCorner">false</bool>
+
+ <!-- Animation duration when using long press on recents to dock -->
+ <integer name="long_press_dock_anim_duration">250</integer>
</resources>
diff --git a/libs/WindowManager/Shell/res/values/dimen.xml b/libs/WindowManager/Shell/res/values/dimen.xml
index 1c1217681b9f..ce690281b491 100644
--- a/libs/WindowManager/Shell/res/values/dimen.xml
+++ b/libs/WindowManager/Shell/res/values/dimen.xml
@@ -56,4 +56,10 @@
<dimen name="pip_resize_handle_size">12dp</dimen>
<dimen name="pip_resize_handle_margin">4dp</dimen>
<dimen name="pip_resize_handle_padding">0dp</dimen>
+
+ <!-- How high we lift the divider when touching -->
+ <dimen name="docked_stack_divider_lift_elevation">4dp</dimen>
+
+ <dimen name="docked_divider_handle_width">16dp</dimen>
+ <dimen name="docked_divider_handle_height">2dp</dimen>
</resources>
diff --git a/libs/WindowManager/Shell/res/values/ids.xml b/libs/WindowManager/Shell/res/values/ids.xml
index ed20398f309d..fb892388cf74 100644
--- a/libs/WindowManager/Shell/res/values/ids.xml
+++ b/libs/WindowManager/Shell/res/values/ids.xml
@@ -16,4 +16,11 @@
-->
<resources>
<item type="id" name="action_pip_resize" />
+
+ <!-- Accessibility actions for the docked stack divider -->
+ <item type="id" name="action_move_tl_full" />
+ <item type="id" name="action_move_tl_70" />
+ <item type="id" name="action_move_tl_50" />
+ <item type="id" name="action_move_tl_30" />
+ <item type="id" name="action_move_rb_full" />
</resources>
diff --git a/libs/WindowManager/Shell/res/values/strings.xml b/libs/WindowManager/Shell/res/values/strings.xml
index 6752b56fcdf3..cad924771cd3 100644
--- a/libs/WindowManager/Shell/res/values/strings.xml
+++ b/libs/WindowManager/Shell/res/values/strings.xml
@@ -53,4 +53,39 @@
<!-- TODO Deprecated. Label for PIP the drag to dismiss hint. DO NOT TRANSLATE [CHAR LIMIT=NONE]-->
<string name="pip_phone_dismiss_hint">Drag down to dismiss</string>
+
+ <!-- Multi-Window strings -->
+ <!-- Text that gets shown on top of current activity to inform the user that the system force-resized the current activity to be displayed in split-screen and that things might crash/not work properly [CHAR LIMIT=NONE] -->
+ <string name="dock_forced_resizable">App may not work with split-screen.</string>
+ <!-- Warning message when we try to dock a non-resizeable task and launch it in fullscreen instead. -->
+ <string name="dock_non_resizeble_failed_to_dock_text">App does not support split-screen.</string>
+ <!-- Text that gets shown on top of current activity to inform the user that the system force-resized the current activity to be displayed on a secondary display and that things might crash/not work properly [CHAR LIMIT=NONE] -->
+ <string name="forced_resizable_secondary_display">App may not work on a secondary display.</string>
+ <!-- Warning message when we try to launch a non-resizeable activity on a secondary display and launch it on the primary instead. -->
+ <string name="activity_launch_on_secondary_display_failed_text">App does not support launch on secondary displays.</string>
+
+ <!-- Accessibility label for the divider that separates the windows in split-screen mode [CHAR LIMIT=NONE] -->
+ <string name="accessibility_divider">Split-screen divider</string>
+
+ <!-- Accessibility action for moving docked stack divider to make the left screen full screen [CHAR LIMIT=NONE] -->
+ <string name="accessibility_action_divider_left_full">Left full screen</string>
+ <!-- Accessibility action for moving docked stack divider to make the left screen 70% [CHAR LIMIT=NONE] -->
+ <string name="accessibility_action_divider_left_70">Left 70%</string>
+ <!-- Accessibility action for moving docked stack divider to make the left screen 50% [CHAR LIMIT=NONE] -->
+ <string name="accessibility_action_divider_left_50">Left 50%</string>
+ <!-- Accessibility action for moving docked stack divider to make the left screen 30% [CHAR LIMIT=NONE] -->
+ <string name="accessibility_action_divider_left_30">Left 30%</string>
+ <!-- Accessibility action for moving docked stack divider to make the right screen full screen [CHAR LIMIT=NONE] -->
+ <string name="accessibility_action_divider_right_full">Right full screen</string>
+
+ <!-- Accessibility action for moving docked stack divider to make the top screen full screen [CHAR LIMIT=NONE] -->
+ <string name="accessibility_action_divider_top_full">Top full screen</string>
+ <!-- Accessibility action for moving docked stack divider to make the top screen 70% [CHAR LIMIT=NONE] -->
+ <string name="accessibility_action_divider_top_70">Top 70%</string>
+ <!-- Accessibility action for moving docked stack divider to make the top screen 50% [CHAR LIMIT=NONE] -->
+ <string name="accessibility_action_divider_top_50">Top 50%</string>
+ <!-- Accessibility action for moving docked stack divider to make the top screen 30% [CHAR LIMIT=NONE] -->
+ <string name="accessibility_action_divider_top_30">Top 30%</string>
+ <!-- Accessibility action for moving docked stack divider to make the bottom screen full screen [CHAR LIMIT=NONE] -->
+ <string name="accessibility_action_divider_bottom_full">Bottom full screen</string>
</resources>
diff --git a/libs/WindowManager/Shell/res/values/styles.xml b/libs/WindowManager/Shell/res/values/styles.xml
new file mode 100644
index 000000000000..fffcd33f7992
--- /dev/null
+++ b/libs/WindowManager/Shell/res/values/styles.xml
@@ -0,0 +1,49 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- 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.
+-->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android">
+ <!-- Theme used for the activity that shows when the system forced an app to be resizable -->
+ <style name="ForcedResizableTheme" parent="@android:style/Theme.Translucent.NoTitleBar">
+ <item name="android:windowBackground">@drawable/forced_resizable_background</item>
+ <item name="android:statusBarColor">@android:color/transparent</item>
+ <item name="android:windowAnimationStyle">@style/Animation.ForcedResizable</item>
+ </style>
+
+ <style name="Animation.ForcedResizable" parent="@android:style/Animation">
+ <item name="android:activityOpenEnterAnimation">@anim/forced_resizable_enter</item>
+
+ <!-- If the target stack doesn't have focus, we do a task to front animation. -->
+ <item name="android:taskToFrontEnterAnimation">@anim/forced_resizable_enter</item>
+ <item name="android:activityCloseExitAnimation">@anim/forced_resizable_exit</item>
+ </style>
+
+ <style name="DockedDividerBackground">
+ <item name="android:layout_width">match_parent</item>
+ <item name="android:layout_height">10dp</item>
+ <item name="android:layout_gravity">center_vertical</item>
+ </style>
+
+ <style name="DockedDividerMinimizedShadow">
+ <item name="android:layout_width">match_parent</item>
+ <item name="android:layout_height">8dp</item>
+ </style>
+
+ <style name="DockedDividerHandle">
+ <item name="android:layout_gravity">center_horizontal</item>
+ <item name="android:layout_width">96dp</item>
+ <item name="android:layout_height">48dp</item>
+ </style>
+</resources>
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/ShellTaskOrganizer.java b/libs/WindowManager/Shell/src/com/android/wm/shell/ShellTaskOrganizer.java
index 126374829a18..ea9576a511e9 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/ShellTaskOrganizer.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/ShellTaskOrganizer.java
@@ -17,17 +17,20 @@
package com.android.wm.shell;
import android.app.ActivityManager.RunningTaskInfo;
+import android.app.WindowConfiguration;
+import android.content.Context;
import android.util.Log;
import android.util.Pair;
import android.util.SparseArray;
-import android.util.SparseIntArray;
-import android.view.Surface;
import android.view.SurfaceControl;
import android.window.TaskOrganizer;
+import com.android.internal.protolog.common.ProtoLog;
+import com.android.wm.shell.protolog.ShellProtoLogGroup;
+import com.android.wm.shell.protolog.ShellProtoLogImpl;
+
import java.util.ArrayList;
-import java.util.LinkedList;
-import java.util.concurrent.CopyOnWriteArrayList;
+import java.util.Arrays;
/**
* Unified task organizer for all components in the shell.
@@ -57,6 +60,8 @@ public class ShellTaskOrganizer extends TaskOrganizer {
* Adds a listener for tasks in a specific windowing mode.
*/
public void addListener(TaskListener listener, int... windowingModes) {
+ ProtoLog.v(ShellProtoLogGroup.WM_SHELL_TASK_ORG, "Add listener for modes=%s listener=%s",
+ Arrays.toString(windowingModes), listener);
for (int winMode : windowingModes) {
ArrayList<TaskListener> listeners = mListenersByWindowingMode.get(winMode);
if (listeners == null) {
@@ -84,6 +89,7 @@ public class ShellTaskOrganizer extends TaskOrganizer {
* Removes a registered listener.
*/
public void removeListener(TaskListener listener) {
+ ProtoLog.v(ShellProtoLogGroup.WM_SHELL_TASK_ORG, "Remove listener=%s", listener);
for (int i = 0; i < mListenersByWindowingMode.size(); i++) {
mListenersByWindowingMode.valueAt(i).remove(listener);
}
@@ -91,6 +97,8 @@ public class ShellTaskOrganizer extends TaskOrganizer {
@Override
public void onTaskAppeared(RunningTaskInfo taskInfo, SurfaceControl leash) {
+ ProtoLog.v(ShellProtoLogGroup.WM_SHELL_TASK_ORG, "Task appeared taskId=%d",
+ taskInfo.taskId);
mTasks.put(taskInfo.taskId, new Pair<>(taskInfo, leash));
ArrayList<TaskListener> listeners = mListenersByWindowingMode.get(
getWindowingMode(taskInfo));
@@ -103,6 +111,8 @@ public class ShellTaskOrganizer extends TaskOrganizer {
@Override
public void onTaskInfoChanged(RunningTaskInfo taskInfo) {
+ ProtoLog.v(ShellProtoLogGroup.WM_SHELL_TASK_ORG, "Task info changed taskId=%d",
+ taskInfo.taskId);
Pair<RunningTaskInfo, SurfaceControl> data = mTasks.get(taskInfo.taskId);
int winMode = getWindowingMode(taskInfo);
int prevWinMode = getWindowingMode(data.first);
@@ -134,6 +144,8 @@ public class ShellTaskOrganizer extends TaskOrganizer {
@Override
public void onBackPressedOnTaskRoot(RunningTaskInfo taskInfo) {
+ ProtoLog.v(ShellProtoLogGroup.WM_SHELL_TASK_ORG, "Task root back pressed taskId=%d",
+ taskInfo.taskId);
ArrayList<TaskListener> listeners = mListenersByWindowingMode.get(
getWindowingMode(taskInfo));
if (listeners != null) {
@@ -145,6 +157,8 @@ public class ShellTaskOrganizer extends TaskOrganizer {
@Override
public void onTaskVanished(RunningTaskInfo taskInfo) {
+ ProtoLog.v(ShellProtoLogGroup.WM_SHELL_TASK_ORG, "Task vanished taskId=%d",
+ taskInfo.taskId);
int prevWinMode = getWindowingMode(mTasks.get(taskInfo.taskId).first);
mTasks.remove(taskInfo.taskId);
ArrayList<TaskListener> listeners = mListenersByWindowingMode.get(prevWinMode);
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/FlingAnimationUtils.java b/libs/WindowManager/Shell/src/com/android/wm/shell/animation/FlingAnimationUtils.java
index 12749fd8fce2..357f777e1270 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/FlingAnimationUtils.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/animation/FlingAnimationUtils.java
@@ -11,10 +11,10 @@
* 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
+ * limitations under the License.
*/
-package com.android.systemui.statusbar;
+package com.android.wm.shell.animation;
import android.animation.Animator;
import android.util.DisplayMetrics;
@@ -23,11 +23,6 @@ import android.view.ViewPropertyAnimator;
import android.view.animation.Interpolator;
import android.view.animation.PathInterpolator;
-import com.android.systemui.Interpolators;
-import com.android.systemui.statusbar.notification.NotificationUtils;
-
-import javax.inject.Inject;
-
/**
* Utility class to calculate general fling animation when the finger is released.
*/
@@ -63,9 +58,9 @@ public class FlingAnimationUtils {
/**
* @param maxLengthSeconds the longest duration an animation can become in seconds
- * @param speedUpFactor a factor from 0 to 1 how much the slow down should be shifted towards
- * the end of the animation. 0 means it's at the beginning and no
- * acceleration will take place.
+ * @param speedUpFactor a factor from 0 to 1 how much the slow down should be shifted towards
+ * the end of the animation. 0 means it's at the beginning and no
+ * acceleration will take place.
*/
public FlingAnimationUtils(DisplayMetrics displayMetrics, float maxLengthSeconds,
float speedUpFactor) {
@@ -74,19 +69,19 @@ public class FlingAnimationUtils {
/**
* @param maxLengthSeconds the longest duration an animation can become in seconds
- * @param speedUpFactor a factor from 0 to 1 how much the slow down should be shifted towards
- * the end of the animation. 0 means it's at the beginning and no
- * acceleration will take place.
- * @param x2 the x value to take for the second point of the bezier spline. If a value below 0
- * is provided, the value is automatically calculated.
- * @param y2 the y value to take for the second point of the bezier spline
+ * @param speedUpFactor a factor from 0 to 1 how much the slow down should be shifted towards
+ * the end of the animation. 0 means it's at the beginning and no
+ * acceleration will take place.
+ * @param x2 the x value to take for the second point of the bezier spline. If a
+ * value below 0 is provided, the value is automatically calculated.
+ * @param y2 the y value to take for the second point of the bezier spline
*/
public FlingAnimationUtils(DisplayMetrics displayMetrics, float maxLengthSeconds,
float speedUpFactor, float x2, float y2) {
mMaxLengthSeconds = maxLengthSeconds;
mSpeedUpFactor = speedUpFactor;
if (x2 < 0) {
- mLinearOutSlowInX2 = NotificationUtils.interpolate(LINEAR_OUT_SLOW_IN_X2,
+ mLinearOutSlowInX2 = interpolate(LINEAR_OUT_SLOW_IN_X2,
LINEAR_OUT_SLOW_IN_X2_MAX,
mSpeedUpFactor);
} else {
@@ -102,10 +97,10 @@ public class FlingAnimationUtils {
* Applies the interpolator and length to the animator, such that the fling animation is
* consistent with the finger motion.
*
- * @param animator the animator to apply
+ * @param animator the animator to apply
* @param currValue the current value
- * @param endValue the end value of the animator
- * @param velocity the current velocity of the motion
+ * @param endValue the end value of the animator
+ * @param velocity the current velocity of the motion
*/
public void apply(Animator animator, float currValue, float endValue, float velocity) {
apply(animator, currValue, endValue, velocity, Math.abs(endValue - currValue));
@@ -115,10 +110,10 @@ public class FlingAnimationUtils {
* Applies the interpolator and length to the animator, such that the fling animation is
* consistent with the finger motion.
*
- * @param animator the animator to apply
+ * @param animator the animator to apply
* @param currValue the current value
- * @param endValue the end value of the animator
- * @param velocity the current velocity of the motion
+ * @param endValue the end value of the animator
+ * @param velocity the current velocity of the motion
*/
public void apply(ViewPropertyAnimator animator, float currValue, float endValue,
float velocity) {
@@ -129,10 +124,10 @@ public class FlingAnimationUtils {
* Applies the interpolator and length to the animator, such that the fling animation is
* consistent with the finger motion.
*
- * @param animator the animator to apply
- * @param currValue the current value
- * @param endValue the end value of the animator
- * @param velocity the current velocity of the motion
+ * @param animator the animator to apply
+ * @param currValue the current value
+ * @param endValue the end value of the animator
+ * @param velocity the current velocity of the motion
* @param maxDistance the maximum distance for this interaction; the maximum animation length
* gets multiplied by the ratio between the actual distance and this value
*/
@@ -140,18 +135,18 @@ public class FlingAnimationUtils {
float maxDistance) {
AnimatorProperties properties = getProperties(currValue, endValue, velocity,
maxDistance);
- animator.setDuration(properties.duration);
- animator.setInterpolator(properties.interpolator);
+ animator.setDuration(properties.mDuration);
+ animator.setInterpolator(properties.mInterpolator);
}
/**
* Applies the interpolator and length to the animator, such that the fling animation is
* consistent with the finger motion.
*
- * @param animator the animator to apply
- * @param currValue the current value
- * @param endValue the end value of the animator
- * @param velocity the current velocity of the motion
+ * @param animator the animator to apply
+ * @param currValue the current value
+ * @param endValue the end value of the animator
+ * @param velocity the current velocity of the motion
* @param maxDistance the maximum distance for this interaction; the maximum animation length
* gets multiplied by the ratio between the actual distance and this value
*/
@@ -159,8 +154,8 @@ public class FlingAnimationUtils {
float velocity, float maxDistance) {
AnimatorProperties properties = getProperties(currValue, endValue, velocity,
maxDistance);
- animator.setDuration(properties.duration);
- animator.setInterpolator(properties.interpolator);
+ animator.setDuration(properties.mDuration);
+ animator.setInterpolator(properties.mInterpolator);
}
private AnimatorProperties getProperties(float currValue,
@@ -171,28 +166,28 @@ public class FlingAnimationUtils {
float velAbs = Math.abs(velocity);
float velocityFactor = mSpeedUpFactor == 0.0f
? 1.0f : Math.min(velAbs / HIGH_VELOCITY_DP_PER_SECOND, 1.0f);
- float startGradient = NotificationUtils.interpolate(LINEAR_OUT_SLOW_IN_START_GRADIENT,
+ float startGradient = interpolate(LINEAR_OUT_SLOW_IN_START_GRADIENT,
mY2 / mLinearOutSlowInX2, velocityFactor);
float durationSeconds = startGradient * diff / velAbs;
Interpolator slowInInterpolator = getInterpolator(startGradient, velocityFactor);
if (durationSeconds <= maxLengthSeconds) {
- mAnimatorProperties.interpolator = slowInInterpolator;
+ mAnimatorProperties.mInterpolator = slowInInterpolator;
} else if (velAbs >= mMinVelocityPxPerSecond) {
// Cross fade between fast-out-slow-in and linear interpolator with current velocity.
durationSeconds = maxLengthSeconds;
- VelocityInterpolator velocityInterpolator
- = new VelocityInterpolator(durationSeconds, velAbs, diff);
+ VelocityInterpolator velocityInterpolator = new VelocityInterpolator(
+ durationSeconds, velAbs, diff);
InterpolatorInterpolator superInterpolator = new InterpolatorInterpolator(
velocityInterpolator, slowInInterpolator, Interpolators.LINEAR_OUT_SLOW_IN);
- mAnimatorProperties.interpolator = superInterpolator;
+ mAnimatorProperties.mInterpolator = superInterpolator;
} else {
// Just use a normal interpolator which doesn't take the velocity into account.
durationSeconds = maxLengthSeconds;
- mAnimatorProperties.interpolator = Interpolators.FAST_OUT_SLOW_IN;
+ mAnimatorProperties.mInterpolator = Interpolators.FAST_OUT_SLOW_IN;
}
- mAnimatorProperties.duration = (long) (durationSeconds * 1000);
+ mAnimatorProperties.mDuration = (long) (durationSeconds * 1000);
return mAnimatorProperties;
}
@@ -225,10 +220,10 @@ public class FlingAnimationUtils {
* consistent with the finger motion for the case when the animation is making something
* disappear.
*
- * @param animator the animator to apply
- * @param currValue the current value
- * @param endValue the end value of the animator
- * @param velocity the current velocity of the motion
+ * @param animator the animator to apply
+ * @param currValue the current value
+ * @param endValue the end value of the animator
+ * @param velocity the current velocity of the motion
* @param maxDistance the maximum distance for this interaction; the maximum animation length
* gets multiplied by the ratio between the actual distance and this value
*/
@@ -236,8 +231,8 @@ public class FlingAnimationUtils {
float velocity, float maxDistance) {
AnimatorProperties properties = getDismissingProperties(currValue, endValue, velocity,
maxDistance);
- animator.setDuration(properties.duration);
- animator.setInterpolator(properties.interpolator);
+ animator.setDuration(properties.mDuration);
+ animator.setInterpolator(properties.mInterpolator);
}
/**
@@ -245,10 +240,10 @@ public class FlingAnimationUtils {
* consistent with the finger motion for the case when the animation is making something
* disappear.
*
- * @param animator the animator to apply
- * @param currValue the current value
- * @param endValue the end value of the animator
- * @param velocity the current velocity of the motion
+ * @param animator the animator to apply
+ * @param currValue the current value
+ * @param endValue the end value of the animator
+ * @param velocity the current velocity of the motion
* @param maxDistance the maximum distance for this interaction; the maximum animation length
* gets multiplied by the ratio between the actual distance and this value
*/
@@ -256,8 +251,8 @@ public class FlingAnimationUtils {
float velocity, float maxDistance) {
AnimatorProperties properties = getDismissingProperties(currValue, endValue, velocity,
maxDistance);
- animator.setDuration(properties.duration);
- animator.setInterpolator(properties.interpolator);
+ animator.setDuration(properties.mDuration);
+ animator.setInterpolator(properties.mInterpolator);
}
private AnimatorProperties getDismissingProperties(float currValue, float endValue,
@@ -272,24 +267,24 @@ public class FlingAnimationUtils {
Interpolator mLinearOutFasterIn = new PathInterpolator(0, 0, LINEAR_OUT_FASTER_IN_X2, y2);
float durationSeconds = startGradient * diff / velAbs;
if (durationSeconds <= maxLengthSeconds) {
- mAnimatorProperties.interpolator = mLinearOutFasterIn;
+ mAnimatorProperties.mInterpolator = mLinearOutFasterIn;
} else if (velAbs >= mMinVelocityPxPerSecond) {
// Cross fade between linear-out-faster-in and linear interpolator with current
// velocity.
durationSeconds = maxLengthSeconds;
- VelocityInterpolator velocityInterpolator
- = new VelocityInterpolator(durationSeconds, velAbs, diff);
+ VelocityInterpolator velocityInterpolator = new VelocityInterpolator(
+ durationSeconds, velAbs, diff);
InterpolatorInterpolator superInterpolator = new InterpolatorInterpolator(
velocityInterpolator, mLinearOutFasterIn, Interpolators.LINEAR_OUT_SLOW_IN);
- mAnimatorProperties.interpolator = superInterpolator;
+ mAnimatorProperties.mInterpolator = superInterpolator;
} else {
// Just use a normal interpolator which doesn't take the velocity into account.
durationSeconds = maxLengthSeconds;
- mAnimatorProperties.interpolator = Interpolators.FAST_OUT_LINEAR_IN;
+ mAnimatorProperties.mInterpolator = Interpolators.FAST_OUT_LINEAR_IN;
}
- mAnimatorProperties.duration = (long) (durationSeconds * 1000);
+ mAnimatorProperties.mDuration = (long) (durationSeconds * 1000);
return mAnimatorProperties;
}
@@ -361,10 +356,11 @@ public class FlingAnimationUtils {
}
private static class AnimatorProperties {
- Interpolator interpolator;
- long duration;
+ Interpolator mInterpolator;
+ long mDuration;
}
+ /** Builder for {@link #FlingAnimationUtils}. */
public static class Builder {
private final DisplayMetrics mDisplayMetrics;
float mMaxLengthSeconds;
@@ -372,32 +368,39 @@ public class FlingAnimationUtils {
float mX2;
float mY2;
- @Inject
public Builder(DisplayMetrics displayMetrics) {
mDisplayMetrics = displayMetrics;
reset();
}
+ /** Sets the longest duration an animation can become in seconds. */
public Builder setMaxLengthSeconds(float maxLengthSeconds) {
mMaxLengthSeconds = maxLengthSeconds;
return this;
}
+ /**
+ * Sets the factor for how much the slow down should be shifted towards the end of the
+ * animation.
+ */
public Builder setSpeedUpFactor(float speedUpFactor) {
mSpeedUpFactor = speedUpFactor;
return this;
}
+ /** Sets the x value to take for the second point of the bezier spline. */
public Builder setX2(float x2) {
mX2 = x2;
return this;
}
+ /** Sets the y value to take for the second point of the bezier spline. */
public Builder setY2(float y2) {
mY2 = y2;
return this;
}
+ /** Resets all parameters of the builder. */
public Builder reset() {
mMaxLengthSeconds = 0;
mSpeedUpFactor = 0.0f;
@@ -407,9 +410,14 @@ public class FlingAnimationUtils {
return this;
}
+ /** Builds {@link #FlingAnimationUtils}. */
public FlingAnimationUtils build() {
return new FlingAnimationUtils(mDisplayMetrics, mMaxLengthSeconds, mSpeedUpFactor,
mX2, mY2);
}
}
+
+ private static float interpolate(float start, float end, float amount) {
+ return start * (1.0f - amount) + end * amount;
+ }
}
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/animation/Interpolators.java b/libs/WindowManager/Shell/src/com/android/wm/shell/animation/Interpolators.java
new file mode 100644
index 000000000000..b794b91568fc
--- /dev/null
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/animation/Interpolators.java
@@ -0,0 +1,45 @@
+/*
+ * 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.animation;
+
+import android.view.animation.Interpolator;
+import android.view.animation.PathInterpolator;
+
+/**
+ * Common interpolators used in wm shell library.
+ */
+public class Interpolators {
+ /**
+ * Interpolator for fast out linear in animation.
+ */
+ public static final Interpolator FAST_OUT_LINEAR_IN = new PathInterpolator(0.4f, 0f, 1f, 1f);
+
+ /**
+ * Interpolator for fast out slow in animation.
+ */
+ public static final Interpolator FAST_OUT_SLOW_IN = new PathInterpolator(0.4f, 0f, 0.2f, 1f);
+
+ /**
+ * Interpolator for linear out slow in animation.
+ */
+ public static final Interpolator LINEAR_OUT_SLOW_IN = new PathInterpolator(0f, 0f, 0.2f, 1f);
+
+ /**
+ * Interpolator to be used when animating a move based on a click. Pair with enough duration.
+ */
+ public static final Interpolator TOUCH_RESPONSE = new PathInterpolator(0.3f, 0f, 0.1f, 1f);
+}
diff --git a/packages/SystemUI/src/com/android/systemui/stackdivider/SyncTransactionQueue.java b/libs/WindowManager/Shell/src/com/android/wm/shell/common/SyncTransactionQueue.java
index 13ed02e9513e..9cb125087cd9 100644
--- a/packages/SystemUI/src/com/android/systemui/stackdivider/SyncTransactionQueue.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/common/SyncTransactionQueue.java
@@ -14,8 +14,9 @@
* limitations under the License.
*/
-package com.android.systemui.stackdivider;
+package com.android.wm.shell.common;
+import android.annotation.NonNull;
import android.os.Handler;
import android.util.Slog;
import android.view.SurfaceControl;
@@ -23,17 +24,13 @@ import android.window.WindowContainerTransaction;
import android.window.WindowContainerTransactionCallback;
import android.window.WindowOrganizer;
-import androidx.annotation.NonNull;
-
-import com.android.wm.shell.common.TransactionPool;
-
import java.util.ArrayList;
/**
* Helper for serializing sync-transactions and corresponding callbacks.
*/
-class SyncTransactionQueue {
- private static final boolean DEBUG = SplitScreenController.DEBUG;
+public final class SyncTransactionQueue {
+ private static final boolean DEBUG = false;
private static final String TAG = "SyncTransactionQueue";
// Just a little longer than the sync-engine timeout of 5s
@@ -58,7 +55,7 @@ class SyncTransactionQueue {
}
};
- SyncTransactionQueue(TransactionPool pool, Handler handler) {
+ public SyncTransactionQueue(TransactionPool pool, Handler handler) {
mTransactionPool = pool;
mHandler = handler;
}
@@ -66,7 +63,7 @@ class SyncTransactionQueue {
/**
* Queues a sync transaction to be sent serially to WM.
*/
- void queue(WindowContainerTransaction wct) {
+ public void queue(WindowContainerTransaction wct) {
SyncCallback cb = new SyncCallback(wct);
synchronized (mQueue) {
if (DEBUG) Slog.d(TAG, "Queueing up " + wct);
@@ -82,7 +79,7 @@ class SyncTransactionQueue {
* Otherwise just returns without queueing.
* @return {@code true} if queued, {@code false} if not.
*/
- boolean queueIfWaiting(WindowContainerTransaction wct) {
+ public boolean queueIfWaiting(WindowContainerTransaction wct) {
synchronized (mQueue) {
if (mQueue.isEmpty()) {
if (DEBUG) Slog.d(TAG, "Nothing in queue, so skip queueing up " + wct);
@@ -102,7 +99,7 @@ class SyncTransactionQueue {
* Runs a runnable in sync with sync transactions (ie. when the current in-flight transaction
* returns. If there are no transactions in-flight, runnable executes immediately.
*/
- void runInSync(TransactionRunnable runnable) {
+ public void runInSync(TransactionRunnable runnable) {
synchronized (mQueue) {
if (DEBUG) Slog.d(TAG, "Run in sync. mInFlight=" + mInFlight);
if (mInFlight != null) {
@@ -127,7 +124,9 @@ class SyncTransactionQueue {
t.close();
}
- interface TransactionRunnable {
+ /** Task to run with transaction. */
+ public interface TransactionRunnable {
+ /** Runs with transaction. */
void runWithTransaction(SurfaceControl.Transaction t);
}
@@ -154,7 +153,7 @@ class SyncTransactionQueue {
@Override
public void onTransactionReady(int id,
- @androidx.annotation.NonNull SurfaceControl.Transaction t) {
+ @NonNull SurfaceControl.Transaction t) {
mHandler.post(() -> {
synchronized (mQueue) {
if (mId != id) {
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/protolog/ShellProtoLogGroup.java b/libs/WindowManager/Shell/src/com/android/wm/shell/protolog/ShellProtoLogGroup.java
new file mode 100644
index 000000000000..ae0975467e3f
--- /dev/null
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/protolog/ShellProtoLogGroup.java
@@ -0,0 +1,92 @@
+/*
+ * 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.protolog;
+
+import com.android.internal.protolog.common.IProtoLogGroup;
+
+/**
+ * Defines logging groups for ProtoLog.
+ *
+ * This file is used by the ProtoLogTool to generate optimized logging code.
+ */
+public enum ShellProtoLogGroup implements IProtoLogGroup {
+ WM_SHELL_TASK_ORG(Consts.ENABLE_DEBUG, Consts.ENABLE_LOG_TO_PROTO_DEBUG, false,
+ Consts.TAG_WM_SHELL),
+ TEST_GROUP(true, true, false, "WindowManagerShellProtoLogTest");
+
+ private final boolean mEnabled;
+ private volatile boolean mLogToProto;
+ private volatile boolean mLogToLogcat;
+ private final String mTag;
+
+ /**
+ * @param enabled set to false to exclude all log statements for this group from
+ * compilation,
+ * they will not be available in runtime.
+ * @param logToProto enable binary logging for the group
+ * @param logToLogcat enable text logging for the group
+ * @param tag name of the source of the logged message
+ */
+ ShellProtoLogGroup(boolean enabled, boolean logToProto, boolean logToLogcat, String tag) {
+ this.mEnabled = enabled;
+ this.mLogToProto = logToProto;
+ this.mLogToLogcat = logToLogcat;
+ this.mTag = tag;
+ }
+
+ @Override
+ public boolean isEnabled() {
+ return mEnabled;
+ }
+
+ @Override
+ public boolean isLogToProto() {
+ return mLogToProto;
+ }
+
+ @Override
+ public boolean isLogToLogcat() {
+ return mLogToLogcat;
+ }
+
+ @Override
+ public boolean isLogToAny() {
+ return mLogToLogcat || mLogToProto;
+ }
+
+ @Override
+ public String getTag() {
+ return mTag;
+ }
+
+ @Override
+ public void setLogToProto(boolean logToProto) {
+ this.mLogToProto = logToProto;
+ }
+
+ @Override
+ public void setLogToLogcat(boolean logToLogcat) {
+ this.mLogToLogcat = logToLogcat;
+ }
+
+ private static class Consts {
+ private static final String TAG_WM_SHELL = "WindowManagerShell";
+
+ private static final boolean ENABLE_DEBUG = true;
+ private static final boolean ENABLE_LOG_TO_PROTO_DEBUG = true;
+ }
+}
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/protolog/ShellProtoLogImpl.java b/libs/WindowManager/Shell/src/com/android/wm/shell/protolog/ShellProtoLogImpl.java
new file mode 100644
index 000000000000..6a925e74e847
--- /dev/null
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/protolog/ShellProtoLogImpl.java
@@ -0,0 +1,138 @@
+/*
+ * 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.protolog;
+
+import android.annotation.Nullable;
+import android.content.Context;
+import android.util.Log;
+
+import com.android.internal.annotations.VisibleForTesting;
+import com.android.internal.protolog.BaseProtoLogImpl;
+import com.android.internal.protolog.ProtoLogViewerConfigReader;
+import com.android.internal.protolog.common.IProtoLogGroup;
+import com.android.wm.shell.R;
+
+import java.io.File;
+import java.io.IOException;
+import java.io.PrintWriter;
+
+import org.json.JSONException;
+
+
+/**
+ * A service for the ProtoLog logging system.
+ */
+public class ShellProtoLogImpl extends BaseProtoLogImpl {
+ private static final String TAG = "ProtoLogImpl";
+ private static final int BUFFER_CAPACITY = 1024 * 1024;
+ // TODO: Get the right path for the proto log file when we initialize the shell components
+ private static final String LOG_FILENAME = new File("wm_shell_log.pb").getAbsolutePath();
+
+ private static ShellProtoLogImpl sServiceInstance = null;
+
+ private final PrintWriter mSystemOutWriter;
+
+ static {
+ addLogGroupEnum(ShellProtoLogGroup.values());
+ }
+
+ /** Used by the ProtoLogTool, do not call directly - use {@code ProtoLog} class instead. */
+ public static void d(IProtoLogGroup group, int messageHash, int paramsMask,
+ @Nullable String messageString,
+ Object... args) {
+ getSingleInstance()
+ .log(LogLevel.DEBUG, group, messageHash, paramsMask, messageString, args);
+ }
+
+ /** Used by the ProtoLogTool, do not call directly - use {@code ProtoLog} class instead. */
+ public static void v(IProtoLogGroup group, int messageHash, int paramsMask,
+ @Nullable String messageString,
+ Object... args) {
+ getSingleInstance().log(LogLevel.VERBOSE, group, messageHash, paramsMask, messageString,
+ args);
+ }
+
+ /** Used by the ProtoLogTool, do not call directly - use {@code ProtoLog} class instead. */
+ public static void i(IProtoLogGroup group, int messageHash, int paramsMask,
+ @Nullable String messageString,
+ Object... args) {
+ getSingleInstance().log(LogLevel.INFO, group, messageHash, paramsMask, messageString, args);
+ }
+
+ /** Used by the ProtoLogTool, do not call directly - use {@code ProtoLog} class instead. */
+ public static void w(IProtoLogGroup group, int messageHash, int paramsMask,
+ @Nullable String messageString,
+ Object... args) {
+ getSingleInstance().log(LogLevel.WARN, group, messageHash, paramsMask, messageString, args);
+ }
+
+ /** Used by the ProtoLogTool, do not call directly - use {@code ProtoLog} class instead. */
+ public static void e(IProtoLogGroup group, int messageHash, int paramsMask,
+ @Nullable String messageString,
+ Object... args) {
+ getSingleInstance()
+ .log(LogLevel.ERROR, group, messageHash, paramsMask, messageString, args);
+ }
+
+ /** Used by the ProtoLogTool, do not call directly - use {@code ProtoLog} class instead. */
+ public static void wtf(IProtoLogGroup group, int messageHash, int paramsMask,
+ @Nullable String messageString,
+ Object... args) {
+ getSingleInstance().log(LogLevel.WTF, group, messageHash, paramsMask, messageString, args);
+ }
+
+ /** Returns true iff logging is enabled for the given {@code IProtoLogGroup}. */
+ public static boolean isEnabled(IProtoLogGroup group) {
+ return group.isLogToLogcat()
+ || (group.isLogToProto() && getSingleInstance().isProtoEnabled());
+ }
+
+ /**
+ * Returns the single instance of the ProtoLogImpl singleton class.
+ */
+ public static synchronized ShellProtoLogImpl getSingleInstance() {
+ if (sServiceInstance == null) {
+ sServiceInstance = new ShellProtoLogImpl();
+ }
+ return sServiceInstance;
+ }
+
+ public void startTextLogging(Context context, String... groups) {
+ try {
+ mViewerConfig.loadViewerConfig(
+ context.getResources().openRawResource(R.raw.wm_shell_protolog));
+ setLogging(true /* setTextLogging */, true, mSystemOutWriter, groups);
+ } catch (IOException e) {
+ Log.i(TAG, "Unable to load log definitions: IOException while reading "
+ + "wm_shell_protolog. " + e);
+ } catch (JSONException e) {
+ Log.i(TAG, "Unable to load log definitions: JSON parsing exception while reading "
+ + "wm_shell_protolog. " + e);
+ }
+ }
+
+ public void stopTextLogging(String... groups) {
+ setLogging(true /* setTextLogging */, false, mSystemOutWriter, groups);
+ }
+
+ private ShellProtoLogImpl() {
+ super(new File(LOG_FILENAME), null, BUFFER_CAPACITY,
+ new ProtoLogViewerConfigReader());
+ mSystemOutWriter = new PrintWriter(System.out, true);
+ }
+}
+
diff --git a/packages/SystemUI/src/com/android/systemui/stackdivider/DividerHandleView.java b/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/DividerHandleView.java
index a10242a689a2..2cb1fff4cde6 100644
--- a/packages/SystemUI/src/com/android/systemui/stackdivider/DividerHandleView.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/DividerHandleView.java
@@ -14,7 +14,7 @@
* limitations under the License.
*/
-package com.android.systemui.stackdivider;
+package com.android.wm.shell.splitscreen;
import android.animation.Animator;
import android.animation.AnimatorListenerAdapter;
@@ -28,43 +28,41 @@ import android.util.AttributeSet;
import android.util.Property;
import android.view.View;
-import com.android.systemui.Interpolators;
-import com.android.systemui.R;
+import com.android.wm.shell.R;
+import com.android.wm.shell.animation.Interpolators;
/**
* View for the handle in the docked stack divider.
*/
-class DividerHandleView extends View {
-
- private final static Property<DividerHandleView, Integer> WIDTH_PROPERTY
- = new Property<DividerHandleView, Integer>(Integer.class, "width") {
-
- @Override
- public Integer get(DividerHandleView object) {
- return object.mCurrentWidth;
- }
-
- @Override
- public void set(DividerHandleView object, Integer value) {
- object.mCurrentWidth = value;
- object.invalidate();
- }
- };
-
- private final static Property<DividerHandleView, Integer> HEIGHT_PROPERTY
- = new Property<DividerHandleView, Integer>(Integer.class, "height") {
-
- @Override
- public Integer get(DividerHandleView object) {
- return object.mCurrentHeight;
- }
-
- @Override
- public void set(DividerHandleView object, Integer value) {
- object.mCurrentHeight = value;
- object.invalidate();
- }
- };
+public class DividerHandleView extends View {
+
+ private static final Property<DividerHandleView, Integer> WIDTH_PROPERTY =
+ new Property<DividerHandleView, Integer>(Integer.class, "width") {
+ @Override
+ public Integer get(DividerHandleView object) {
+ return object.mCurrentWidth;
+ }
+
+ @Override
+ public void set(DividerHandleView object, Integer value) {
+ object.mCurrentWidth = value;
+ object.invalidate();
+ }
+ };
+
+ private static final Property<DividerHandleView, Integer> HEIGHT_PROPERTY =
+ new Property<DividerHandleView, Integer>(Integer.class, "height") {
+ @Override
+ public Integer get(DividerHandleView object) {
+ return object.mCurrentHeight;
+ }
+
+ @Override
+ public void set(DividerHandleView object, Integer value) {
+ object.mCurrentHeight = value;
+ object.invalidate();
+ }
+ };
private final Paint mPaint = new Paint();
private final int mWidth;
@@ -86,7 +84,7 @@ class DividerHandleView extends View {
mCircleDiameter = (mWidth + mHeight) / 3;
}
- public void setTouching(boolean touching, boolean animate) {
+ void setTouching(boolean touching, boolean animate) {
if (touching == mTouching) {
return;
}
diff --git a/packages/SystemUI/src/com/android/systemui/stackdivider/DividerImeController.java b/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/DividerImeController.java
index 64ee7ed5e0e0..92cee8a1a874 100644
--- a/packages/SystemUI/src/com/android/systemui/stackdivider/DividerImeController.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/DividerImeController.java
@@ -14,7 +14,7 @@
* limitations under the License.
*/
-package com.android.systemui.stackdivider;
+package com.android.wm.shell.splitscreen;
import static android.content.res.Configuration.SCREEN_HEIGHT_DP_UNDEFINED;
import static android.content.res.Configuration.SCREEN_WIDTH_DP_UNDEFINED;
@@ -22,6 +22,7 @@ import static android.content.res.Configuration.SCREEN_WIDTH_DP_UNDEFINED;
import android.animation.Animator;
import android.animation.AnimatorListenerAdapter;
import android.animation.ValueAnimator;
+import android.annotation.Nullable;
import android.graphics.Rect;
import android.os.Handler;
import android.util.Slog;
@@ -31,8 +32,6 @@ import android.window.WindowContainerToken;
import android.window.WindowContainerTransaction;
import android.window.WindowOrganizer;
-import androidx.annotation.Nullable;
-
import com.android.wm.shell.common.DisplayImeController;
import com.android.wm.shell.common.TransactionPool;
diff --git a/packages/SystemUI/src/com/android/systemui/stackdivider/DividerState.java b/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/DividerState.java
index 8e79d51ee209..23d86a00d4bf 100644
--- a/packages/SystemUI/src/com/android/systemui/stackdivider/DividerState.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/DividerState.java
@@ -11,15 +11,15 @@
* 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
+ * limitations under the License.
*/
-package com.android.systemui.stackdivider;
+package com.android.wm.shell.splitscreen;
/**
* Class to hold state of divider that needs to persist across configuration changes.
*/
-public class DividerState {
+final class DividerState {
public boolean animateAfterRecentsDrawn;
public float mRatioPositionBeforeMinimized;
}
diff --git a/packages/SystemUI/src/com/android/systemui/stackdivider/DividerView.java b/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/DividerView.java
index 95f048b0b06d..79bfda92bd92 100644
--- a/packages/SystemUI/src/com/android/systemui/stackdivider/DividerView.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/DividerView.java
@@ -14,7 +14,7 @@
* limitations under the License.
*/
-package com.android.systemui.stackdivider;
+package com.android.wm.shell.splitscreen;
import static android.view.PointerIcon.TYPE_HORIZONTAL_DOUBLE_ARROW;
import static android.view.PointerIcon.TYPE_VERTICAL_DOUBLE_ARROW;
@@ -62,11 +62,9 @@ import com.android.internal.logging.nano.MetricsProto.MetricsEvent;
import com.android.internal.policy.DividerSnapAlgorithm;
import com.android.internal.policy.DividerSnapAlgorithm.SnapTarget;
import com.android.internal.policy.DockedDividerUtils;
-import com.android.systemui.Dependency;
-import com.android.systemui.Interpolators;
-import com.android.systemui.R;
-import com.android.systemui.recents.OverviewProxyService;
-import com.android.systemui.statusbar.FlingAnimationUtils;
+import com.android.wm.shell.R;
+import com.android.wm.shell.animation.FlingAnimationUtils;
+import com.android.wm.shell.animation.Interpolators;
import java.util.function.Consumer;
@@ -78,7 +76,7 @@ public class DividerView extends FrameLayout implements OnTouchListener,
private static final String TAG = "DividerView";
private static final boolean DEBUG = SplitScreenController.DEBUG;
- public interface DividerCallbacks {
+ interface DividerCallbacks {
void onDraggingStart();
void onDraggingEnd();
}
@@ -138,6 +136,7 @@ public class DividerView extends FrameLayout implements OnTouchListener,
private final Rect mOtherInsetRect = new Rect();
private final Rect mLastResizeRect = new Rect();
private final Rect mTmpRect = new Rect();
+ private SplitScreenController mSplitScreenController;
private WindowManagerProxy mWindowManagerProxy;
private DividerWindowManager mWindowManager;
private VelocityTracker mVelocityTracker;
@@ -188,7 +187,7 @@ public class DividerView extends FrameLayout implements OnTouchListener,
if (snapAlgorithm.showMiddleSplitTargetForAccessibility()) {
// Only show the middle target if there are more than 1 split target
info.addAction(new AccessibilityAction(R.id.action_move_tl_50,
- mContext.getString(R.string.accessibility_action_divider_top_50)));
+ mContext.getString(R.string.accessibility_action_divider_top_50)));
}
if (snapAlgorithm.isLastSplitTargetAvailable()) {
info.addAction(new AccessibilityAction(R.id.action_move_tl_30,
@@ -206,7 +205,7 @@ public class DividerView extends FrameLayout implements OnTouchListener,
if (snapAlgorithm.showMiddleSplitTargetForAccessibility()) {
// Only show the middle target if there are more than 1 split target
info.addAction(new AccessibilityAction(R.id.action_move_tl_50,
- mContext.getString(R.string.accessibility_action_divider_left_50)));
+ mContext.getString(R.string.accessibility_action_divider_left_50)));
}
if (snapAlgorithm.isLastSplitTargetAvailable()) {
info.addAction(new AccessibilityAction(R.id.action_move_tl_30,
@@ -353,9 +352,11 @@ public class DividerView extends FrameLayout implements OnTouchListener,
}
}
- public void injectDependencies(DividerWindowManager windowManager, DividerState dividerState,
+ void injectDependencies(SplitScreenController splitScreenController,
+ DividerWindowManager windowManager, DividerState dividerState,
DividerCallbacks callback, SplitScreenTaskOrganizer tiles, SplitDisplayLayout sdl,
DividerImeController imeController, WindowManagerProxy wmProxy) {
+ mSplitScreenController = splitScreenController;
mWindowManager = windowManager;
mState = dividerState;
mCallback = callback;
@@ -372,6 +373,7 @@ public class DividerView extends FrameLayout implements OnTouchListener,
}
}
+ /** Gets non-minimized secondary bounds of split screen. */
public Rect getNonMinimizedSplitScreenSecondaryBounds() {
mOtherTaskRect.set(mSplitLayout.mSecondary);
return mOtherTaskRect;
@@ -408,6 +410,7 @@ public class DividerView extends FrameLayout implements OnTouchListener,
return mSurfaceHidden;
}
+ /** Starts dragging the divider bar. */
public boolean startDragging(boolean animate, boolean touching) {
cancelFlingAnimation();
if (touching) {
@@ -426,6 +429,7 @@ public class DividerView extends FrameLayout implements OnTouchListener,
return inSplitMode();
}
+ /** Stops dragging the divider bar. */
public void stopDragging(int position, float velocity, boolean avoidDismissStart,
boolean logMetrics) {
mHandle.setTouching(false, true /* animate */);
@@ -697,8 +701,7 @@ public class DividerView extends FrameLayout implements OnTouchListener,
mTmpRect.top = 0;
break;
}
- Dependency.get(OverviewProxyService.class)
- .notifySplitScreenBoundsChanged(mOtherTaskRect, mTmpRect);
+ mSplitScreenController.notifyBoundsChanged(mOtherTaskRect, mTmpRect);
}
private void cancelFlingAnimation() {
@@ -889,7 +892,7 @@ public class DividerView extends FrameLayout implements OnTouchListener,
WindowManagerProxy.applyResizeSplits(midPos, mSplitLayout);
}
- public void setMinimizedDockStack(boolean minimized, long animDuration,
+ void setMinimizedDockStack(boolean minimized, long animDuration,
boolean isHomeStackResizable) {
if (DEBUG) Slog.d(TAG, "setMinDock: " + mDockedStackMinimized + "->" + minimized);
mHomeStackResizable = isHomeStackResizable;
@@ -925,7 +928,7 @@ public class DividerView extends FrameLayout implements OnTouchListener,
}
}
- public void setAdjustedForIme(boolean adjustedForIme, long animDuration) {
+ void setAdjustedForIme(boolean adjustedForIme, long animDuration) {
if (mAdjustedForIme == adjustedForIme) {
return;
}
@@ -952,8 +955,8 @@ public class DividerView extends FrameLayout implements OnTouchListener,
private void saveSnapTargetBeforeMinimized(SnapTarget target) {
mSnapTargetBeforeMinimized = target;
- mState.mRatioPositionBeforeMinimized = (float) target.position /
- (isHorizontalDivision() ? mSplitLayout.mDisplayLayout.height()
+ mState.mRatioPositionBeforeMinimized = (float) target.position
+ / (isHorizontalDivision() ? mSplitLayout.mDisplayLayout.height()
: mSplitLayout.mDisplayLayout.width());
}
@@ -971,8 +974,8 @@ public class DividerView extends FrameLayout implements OnTouchListener,
}
private void repositionSnapTargetBeforeMinimized() {
- int position = (int) (mState.mRatioPositionBeforeMinimized *
- (isHorizontalDivision() ? mSplitLayout.mDisplayLayout.height()
+ int position = (int) (mState.mRatioPositionBeforeMinimized
+ * (isHorizontalDivision() ? mSplitLayout.mDisplayLayout.height()
: mSplitLayout.mDisplayLayout.width()));
// Set the snap target before minimized but do not save until divider is attached and not
@@ -1011,7 +1014,7 @@ public class DividerView extends FrameLayout implements OnTouchListener,
containingRect.right, containingRect.bottom);
}
- public void calculateBoundsForPosition(int position, int dockSide, Rect outRect) {
+ private void calculateBoundsForPosition(int position, int dockSide, Rect outRect) {
DockedDividerUtils.calculateBoundsForPosition(position, dockSide, outRect,
mSplitLayout.mDisplayLayout.width(), mSplitLayout.mDisplayLayout.height(),
mDividerSize);
@@ -1240,8 +1243,8 @@ public class DividerView extends FrameLayout implements OnTouchListener,
if (dismissTarget != null && fraction > 0f
&& isDismissing(splitTarget, position, dockSide)) {
fraction = calculateParallaxDismissingFraction(fraction, dockSide);
- int offsetPosition = (int) (start +
- fraction * (dismissTarget.position - splitTarget.position));
+ int offsetPosition = (int) (start + fraction
+ * (dismissTarget.position - splitTarget.position));
int width = taskRect.width();
int height = taskRect.height();
switch (dockSide) {
diff --git a/packages/SystemUI/src/com/android/systemui/stackdivider/DividerWindowManager.java b/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/DividerWindowManager.java
index d869333e11a7..0b4e17c27398 100644
--- a/packages/SystemUI/src/com/android/systemui/stackdivider/DividerWindowManager.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/DividerWindowManager.java
@@ -14,7 +14,7 @@
* limitations under the License.
*/
-package com.android.systemui.stackdivider;
+package com.android.wm.shell.splitscreen;
import static android.view.WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE;
import static android.view.WindowManager.LayoutParams.FLAG_NOT_TOUCHABLE;
@@ -37,7 +37,7 @@ import com.android.wm.shell.common.SystemWindows;
/**
* Manages the window parameters of the docked stack divider.
*/
-public class DividerWindowManager {
+final class DividerWindowManager {
private static final String WINDOW_TITLE = "DockedStackDivider";
@@ -45,12 +45,12 @@ public class DividerWindowManager {
private WindowManager.LayoutParams mLp;
private View mView;
- public DividerWindowManager(SystemWindows systemWindows) {
+ DividerWindowManager(SystemWindows systemWindows) {
mSystemWindows = systemWindows;
}
/** Add a divider view */
- public void add(View view, int width, int height, int displayId) {
+ void add(View view, int width, int height, int displayId) {
mLp = new WindowManager.LayoutParams(
width, height, TYPE_DOCK_DIVIDER,
FLAG_NOT_FOCUSABLE | FLAG_NOT_TOUCH_MODAL
@@ -67,14 +67,14 @@ public class DividerWindowManager {
mView = view;
}
- public void remove() {
+ void remove() {
if (mView != null) {
mSystemWindows.removeView(mView);
}
mView = null;
}
- public void setSlippery(boolean slippery) {
+ void setSlippery(boolean slippery) {
boolean changed = false;
if (slippery && (mLp.flags & FLAG_SLIPPERY) == 0) {
mLp.flags |= FLAG_SLIPPERY;
@@ -88,7 +88,7 @@ public class DividerWindowManager {
}
}
- public void setTouchable(boolean touchable) {
+ void setTouchable(boolean touchable) {
if (mView == null) {
return;
}
@@ -106,7 +106,7 @@ public class DividerWindowManager {
}
/** Sets the touch region to `touchRegion`. Use null to unset.*/
- public void setTouchRegion(Region touchRegion) {
+ void setTouchRegion(Region touchRegion) {
if (mView == null) {
return;
}
diff --git a/packages/SystemUI/src/com/android/systemui/stackdivider/ForcedResizableInfoActivity.java b/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/ForcedResizableInfoActivity.java
index 02f75050c061..7a1633530148 100644
--- a/packages/SystemUI/src/com/android/systemui/stackdivider/ForcedResizableInfoActivity.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/ForcedResizableInfoActivity.java
@@ -11,10 +11,10 @@
* 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
+ * limitations under the License.
*/
-package com.android.systemui.stackdivider;
+package com.android.wm.shell.splitscreen;
import static android.app.ITaskStackListener.FORCED_RESIZEABLE_REASON_SECONDARY_DISPLAY;
import static android.app.ITaskStackListener.FORCED_RESIZEABLE_REASON_SPLIT_SCREEN;
@@ -29,7 +29,7 @@ import android.view.View;
import android.view.View.OnTouchListener;
import android.widget.TextView;
-import com.android.systemui.R;
+import com.android.wm.shell.R;
/**
* Translucent activity that gets started on top of a task in multi-window to inform the user that
diff --git a/packages/SystemUI/src/com/android/systemui/stackdivider/ForcedResizableInfoActivityController.java b/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/ForcedResizableInfoActivityController.java
index 4c26694cc22a..1ef142dacb9e 100644
--- a/packages/SystemUI/src/com/android/systemui/stackdivider/ForcedResizableInfoActivityController.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/ForcedResizableInfoActivityController.java
@@ -11,13 +11,13 @@
* 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
+ * limitations under the License.
*/
-package com.android.systemui.stackdivider;
+package com.android.wm.shell.splitscreen;
-import static com.android.systemui.stackdivider.ForcedResizableInfoActivity
- .EXTRA_FORCED_RESIZEABLE_REASON;
+
+import static com.android.wm.shell.splitscreen.ForcedResizableInfoActivity.EXTRA_FORCED_RESIZEABLE_REASON;
import android.app.ActivityOptions;
import android.content.Context;
@@ -27,7 +27,7 @@ import android.os.UserHandle;
import android.util.ArraySet;
import android.widget.Toast;
-import com.android.systemui.R;
+import com.android.wm.shell.R;
import java.util.function.Consumer;
@@ -55,20 +55,20 @@ final class ForcedResizableInfoActivityController implements DividerView.Divider
/** Record of force resized task that's pending to be handled. */
private class PendingTaskRecord {
- int taskId;
+ int mTaskId;
/**
* {@link android.app.ITaskStackListener#FORCED_RESIZEABLE_REASON_SPLIT_SCREEN} or
* {@link android.app.ITaskStackListener#FORCED_RESIZEABLE_REASON_SECONDARY_DISPLAY}
*/
- int reason;
+ int mReason;
PendingTaskRecord(int taskId, int reason) {
- this.taskId = taskId;
- this.reason = reason;
+ this.mTaskId = taskId;
+ this.mReason = reason;
}
}
- public ForcedResizableInfoActivityController(Context context,
+ ForcedResizableInfoActivityController(Context context,
SplitScreenController splitScreenController) {
mContext = context;
splitScreenController.registerInSplitScreenListener(mDockedStackExistsListener);
@@ -116,11 +116,11 @@ final class ForcedResizableInfoActivityController implements DividerView.Divider
PendingTaskRecord pendingRecord = mPendingTasks.valueAt(i);
Intent intent = new Intent(mContext, ForcedResizableInfoActivity.class);
ActivityOptions options = ActivityOptions.makeBasic();
- options.setLaunchTaskId(pendingRecord.taskId);
+ options.setLaunchTaskId(pendingRecord.mTaskId);
// Set as task overlay and allow to resume, so that when an app enters split-screen and
// becomes paused, the overlay will still be shown.
options.setTaskOverlay(true, true /* canResume */);
- intent.putExtra(EXTRA_FORCED_RESIZEABLE_REASON, pendingRecord.reason);
+ intent.putExtra(EXTRA_FORCED_RESIZEABLE_REASON, pendingRecord.mReason);
mContext.startActivityAsUser(intent, options.toBundle(), UserHandle.CURRENT);
}
mPendingTasks.clear();
diff --git a/packages/SystemUI/src/com/android/systemui/stackdivider/MinimizedDockShadow.java b/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/MinimizedDockShadow.java
index ecff54fd907d..06f4ef109193 100644
--- a/packages/SystemUI/src/com/android/systemui/stackdivider/MinimizedDockShadow.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/MinimizedDockShadow.java
@@ -11,10 +11,10 @@
* 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
+ * limitations under the License.
*/
-package com.android.systemui.stackdivider;
+package com.android.wm.shell.splitscreen;
import android.annotation.Nullable;
import android.content.Context;
@@ -27,7 +27,7 @@ import android.util.AttributeSet;
import android.view.View;
import android.view.WindowManager;
-import com.android.systemui.R;
+import com.android.wm.shell.R;
/**
* Shadow for the minimized dock state on homescreen.
@@ -42,7 +42,7 @@ public class MinimizedDockShadow extends View {
super(context, attrs);
}
- public void setDockSide(int dockSide) {
+ void setDockSide(int dockSide) {
if (dockSide != mDockSide) {
mDockSide = dockSide;
updatePaint(getLeft(), getTop(), getRight(), getBottom());
diff --git a/packages/SystemUI/src/com/android/systemui/stackdivider/SplitDisplayLayout.java b/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/SplitDisplayLayout.java
index a34e85517953..3c0f93906795 100644
--- a/packages/SystemUI/src/com/android/systemui/stackdivider/SplitDisplayLayout.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/SplitDisplayLayout.java
@@ -14,7 +14,7 @@
* limitations under the License.
*/
-package com.android.systemui.stackdivider;
+package com.android.wm.shell.splitscreen;
import static android.content.res.Configuration.ORIENTATION_LANDSCAPE;
import static android.content.res.Configuration.ORIENTATION_PORTRAIT;
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/SplitScreen.java b/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/SplitScreen.java
new file mode 100644
index 000000000000..184342f14d4f
--- /dev/null
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/SplitScreen.java
@@ -0,0 +1,91 @@
+/*
+ * 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.splitscreen;
+
+import android.graphics.Rect;
+import android.window.WindowContainerToken;
+
+import java.io.PrintWriter;
+import java.util.function.BiConsumer;
+import java.util.function.Consumer;
+
+/**
+ * Interface to engage split screen feature.
+ */
+public interface SplitScreen {
+ /** Returns {@code true} if split screen is supported on the device. */
+ boolean isSplitScreenSupported();
+
+ /** Called when keyguard showing state changed. */
+ void onKeyguardVisibilityChanged(boolean isShowing);
+
+ /** Returns {@link DividerView}. */
+ DividerView getDividerView();
+
+ /** Returns {@code true} if one of the split screen is in minimized mode. */
+ boolean isMinimized();
+
+ /** Returns {@code true} if the home stack is resizable. */
+ boolean isHomeStackResizable();
+
+ /** Returns {@code true} if the divider is visible. */
+ boolean isDividerVisible();
+
+ /** Switch to minimized state if appropriate. */
+ void setMinimized(boolean minimized);
+
+ /**
+ * Workaround for b/62528361, at the time recents has drawn, it may happen before a
+ * configuration change to the Divider, and internally, the event will be posted to the
+ * subscriber, or DividerView, which has been removed and prevented from resizing. Instead,
+ * register the event handler here and proxy the event to the current DividerView.
+ */
+ void onRecentsDrawn();
+
+ /** Called when there's an activity forced resizable. */
+ void onActivityForcedResizable(String packageName, int taskId, int reason);
+
+ /** Called when there's an activity dismissing split screen. */
+ void onActivityDismissingSplitScreen();
+
+ /** Called when there's an activity launch on secondary display failed. */
+ void onActivityLaunchOnSecondaryDisplayFailed();
+
+ /** Called when there's a task undocking. */
+ void onUndockingTask();
+
+ /** Called when the first docked animation frame rendered. */
+ void onDockedFirstAnimationFrame();
+
+ /** Called when top task docked. */
+ void onDockedTopTask();
+
+ /** Called when app transition finished. */
+ void onAppTransitionFinished();
+
+ /** Dumps current status of Split Screen. */
+ void dump(PrintWriter pw);
+
+ /** Registers listener that gets called whenever the existence of the divider changes. */
+ void registerInSplitScreenListener(Consumer<Boolean> listener);
+
+ /** Registers listener that gets called whenever the split screen bounds changes. */
+ void registerBoundsChangeListener(BiConsumer<Rect, Rect> listener);
+
+ /** @return the container token for the secondary split root task. */
+ WindowContainerToken getSecondaryRoot();
+}
diff --git a/packages/SystemUI/src/com/android/systemui/stackdivider/SplitScreenController.java b/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/SplitScreenController.java
index 4cba9c7752eb..d5326d4845a3 100644
--- a/packages/SystemUI/src/com/android/systemui/stackdivider/SplitScreenController.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/SplitScreenController.java
@@ -14,7 +14,7 @@
* limitations under the License.
*/
-package com.android.systemui.stackdivider;
+package com.android.wm.shell.splitscreen;
import static android.app.WindowConfiguration.ACTIVITY_TYPE_UNDEFINED;
import static android.content.res.Configuration.ORIENTATION_LANDSCAPE;
@@ -34,7 +34,7 @@ import android.window.WindowContainerTransaction;
import android.window.WindowOrganizer;
import com.android.internal.policy.DividerSnapAlgorithm;
-import com.android.systemui.R;
+import com.android.wm.shell.R;
import com.android.wm.shell.ShellTaskOrganizer;
import com.android.wm.shell.common.DisplayChangeController;
import com.android.wm.shell.common.DisplayController;
@@ -46,13 +46,14 @@ import com.android.wm.shell.common.TransactionPool;
import java.io.PrintWriter;
import java.lang.ref.WeakReference;
import java.util.ArrayList;
+import java.util.function.BiConsumer;
import java.util.function.Consumer;
/**
- * Controls split screen.
+ * Controls split screen feature.
*/
-// TODO(b/161116823): Extract as an interface to expose to SysUISingleton scope.
-public class SplitScreenController implements DisplayController.OnDisplaysChangedListener {
+public class SplitScreenController implements SplitScreen,
+ DisplayController.OnDisplaysChangedListener {
static final boolean DEBUG = false;
private static final String TAG = "Divider";
@@ -73,6 +74,8 @@ public class SplitScreenController implements DisplayController.OnDisplaysChange
private final ArrayList<WeakReference<Consumer<Boolean>>> mDockedStackExistsListeners =
new ArrayList<>();
+ private final ArrayList<WeakReference<BiConsumer<Rect, Rect>>> mBoundsChangedListeners =
+ new ArrayList<>();
private DividerWindowManager mWindowManager;
@@ -257,8 +260,8 @@ public class SplitScreenController implements DisplayController.OnDisplaysChange
mView = (DividerView)
LayoutInflater.from(dctx).inflate(R.layout.docked_stack_divider, null);
DisplayLayout displayLayout = mDisplayController.getDisplayLayout(mContext.getDisplayId());
- mView.injectDependencies(mWindowManager, mDividerState, mForcedResizableController, mSplits,
- mSplitLayout, mImePositionProcessor, mWindowManagerProxy);
+ mView.injectDependencies(this, mWindowManager, mDividerState, mForcedResizableController,
+ mSplits, mSplitLayout, mImePositionProcessor, mWindowManagerProxy);
mView.setVisibility(mVisible ? View.VISIBLE : View.INVISIBLE);
mView.setMinimizedDockStack(mMinimized, mHomeStackResizable, null /* transaction */);
final int size = dctx.getResources().getDimensionPixelSize(
@@ -466,6 +469,24 @@ public class SplitScreenController implements DisplayController.OnDisplaysChange
}
}
+ @Override
+ public void registerBoundsChangeListener(BiConsumer<Rect, Rect> listener) {
+ synchronized (mBoundsChangedListeners) {
+ mBoundsChangedListeners.add(new WeakReference<>(listener));
+ }
+ }
+
+ /** Notifies the bounds of split screen changed. */
+ void notifyBoundsChanged(Rect secondaryWindowBounds, Rect secondaryWindowInsets) {
+ synchronized (mBoundsChangedListeners) {
+ mBoundsChangedListeners.removeIf(wf -> {
+ BiConsumer<Rect, Rect> l = wf.get();
+ if (l != null) l.accept(secondaryWindowBounds, secondaryWindowInsets);
+ return l == null;
+ });
+ }
+ }
+
void startEnterSplit() {
update(mDisplayController.getDisplayContext(
mContext.getDisplayId()).getResources().getConfiguration());
diff --git a/packages/SystemUI/src/com/android/systemui/stackdivider/SplitScreenTaskOrganizer.java b/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/SplitScreenTaskOrganizer.java
index 325c5597f9d8..6d28c5e17d42 100644
--- a/packages/SystemUI/src/com/android/systemui/stackdivider/SplitScreenTaskOrganizer.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/SplitScreenTaskOrganizer.java
@@ -14,7 +14,7 @@
* limitations under the License.
*/
-package com.android.systemui.stackdivider;
+package com.android.wm.shell.splitscreen;
import static android.app.WindowConfiguration.ACTIVITY_TYPE_HOME;
import static android.app.WindowConfiguration.ACTIVITY_TYPE_RECENTS;
diff --git a/packages/SystemUI/src/com/android/systemui/stackdivider/WindowManagerProxy.java b/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/WindowManagerProxy.java
index 82b10bd40b17..cd96676ad1fe 100644
--- a/packages/SystemUI/src/com/android/systemui/stackdivider/WindowManagerProxy.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/WindowManagerProxy.java
@@ -14,7 +14,7 @@
* limitations under the License.
*/
-package com.android.systemui.stackdivider;
+package com.android.wm.shell.splitscreen;
import static android.app.WindowConfiguration.ACTIVITY_TYPE_HOME;
import static android.app.WindowConfiguration.ACTIVITY_TYPE_RECENTS;
@@ -40,6 +40,7 @@ import android.window.WindowContainerTransaction;
import android.window.WindowOrganizer;
import com.android.internal.annotations.GuardedBy;
+import com.android.wm.shell.common.SyncTransactionQueue;
import com.android.wm.shell.common.TransactionPool;
import java.util.ArrayList;
diff --git a/libs/WindowManager/Shell/tests/README.md b/libs/WindowManager/Shell/tests/README.md
new file mode 100644
index 000000000000..c19db76a358c
--- /dev/null
+++ b/libs/WindowManager/Shell/tests/README.md
@@ -0,0 +1,15 @@
+# WM Shell Test
+
+This contains all tests written for WM (WindowManager) Shell and it's currently
+divided into 3 categories
+
+- unittest, tests against individual functions, usually @SmallTest and do not
+ require UI automation nor real device to run
+- integration, this maybe a mix of functional and integration tests. Contains
+ tests verify the WM Shell as a whole, like talking to WM core. This usually
+ involves mocking the window manager service or even talking to the real one.
+ Due to this nature, test cases in this package is normally annotated as
+ @LargeTest and runs with UI automation on real device
+- flicker, similar to functional tests with its sole focus on flickerness. See
+ [WM Shell Flicker Test Package](http://cs/android/framework/base/libs/WindowManager/Shell/tests/flicker/)
+ for more details
diff --git a/libs/WindowManager/Shell/tests/flicker/Android.bp b/libs/WindowManager/Shell/tests/flicker/Android.bp
new file mode 100644
index 000000000000..587902221826
--- /dev/null
+++ b/libs/WindowManager/Shell/tests/flicker/Android.bp
@@ -0,0 +1,34 @@
+//
+// 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.
+//
+
+android_test {
+ name: "WMShellFlickerTests",
+ srcs: ["src/**/*.java", "src/**/*.kt"],
+ manifest: "AndroidManifest.xml",
+ test_config: "AndroidTest.xml",
+ platform_apis: true,
+ certificate: "platform",
+ test_suites: ["device-tests"],
+ libs: ["android.test.runner"],
+ static_libs: [
+ "androidx.test.ext.junit",
+ "flickerlib",
+ "truth-prebuilt",
+ "app-helpers-core",
+ "launcher-helper-lib",
+ "launcher-aosp-tapl"
+ ],
+}
diff --git a/libs/WindowManager/Shell/tests/flicker/AndroidManifest.xml b/libs/WindowManager/Shell/tests/flicker/AndroidManifest.xml
new file mode 100644
index 000000000000..8b2f6681554a
--- /dev/null
+++ b/libs/WindowManager/Shell/tests/flicker/AndroidManifest.xml
@@ -0,0 +1,43 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- 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.
+-->
+
+<manifest xmlns:android="http://schemas.android.com/apk/res/android"
+ package="com.android.wm.shell.flicker">
+
+ <uses-sdk android:minSdkVersion="29" android:targetSdkVersion="29"/>
+ <!-- Read and write traces from external storage -->
+ <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
+ <uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
+ <!-- Write secure settings -->
+ <uses-permission android:name="android.permission.WRITE_SECURE_SETTINGS" />
+ <!-- Capture screen contents -->
+ <uses-permission android:name="android.permission.ACCESS_SURFACE_FLINGER" />
+ <!-- Enable / Disable tracing !-->
+ <uses-permission android:name="android.permission.DUMP" />
+ <!-- Run layers trace -->
+ <uses-permission android:name="android.permission.HARDWARE_TEST"/>
+ <!-- Workaround grant runtime permission exception from b/152733071 -->
+ <uses-permission android:name="android.permission.PACKAGE_USAGE_STATS"/>
+ <uses-permission android:name="android.permission.READ_LOGS"/>
+ <application>
+ <uses-library android:name="android.test.runner"/>
+ </application>
+
+ <instrumentation android:name="androidx.test.runner.AndroidJUnitRunner"
+ android:targetPackage="com.android.wm.shell.flicker"
+ android:label="WindowManager Shell Flicker Tests">
+ </instrumentation>
+</manifest>
diff --git a/libs/WindowManager/Shell/tests/flicker/AndroidTest.xml b/libs/WindowManager/Shell/tests/flicker/AndroidTest.xml
new file mode 100644
index 000000000000..526fc502c0fb
--- /dev/null
+++ b/libs/WindowManager/Shell/tests/flicker/AndroidTest.xml
@@ -0,0 +1,40 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ * Copyright 2020 Google Inc. All Rights Reserved.
+ -->
+<configuration description="Runs WindowManager Shell Flicker Tests">
+ <option name="test-tag" value="FlickerTests" />
+ <target_preparer class="com.android.tradefed.targetprep.DeviceSetup">
+ <!-- keeps the screen on during tests -->
+ <option name="screen-always-on" value="on" />
+ <!-- prevents the phone from restarting -->
+ <option name="force-skip-system-props" value="true" />
+ <!-- set WM tracing verbose level to all -->
+ <option name="run-command" value="cmd window tracing level all" />
+ <!-- inform WM to log all transactions -->
+ <option name="run-command" value="cmd window tracing transaction" />
+ <!-- restart launcher to activate TAPL -->
+ <option name="run-command" value="setprop ro.test_harness 1 ; am force-stop com.google.android.apps.nexuslauncher" />
+ </target_preparer>
+ <target_preparer class="com.android.tradefed.targetprep.DeviceCleaner">
+ <!-- reboot the device to teardown any crashed tests -->
+ <option name="cleanup-action" value="REBOOT" />
+ </target_preparer>
+ <target_preparer class="com.android.tradefed.targetprep.suite.SuiteApkInstaller">
+ <option name="cleanup-apks" value="true"/>
+ <option name="test-file-name" value="WMShellFlickerTests.apk"/>
+ <option name="test-file-name" value="WMShellFlickerTestApp.apk" />
+ </target_preparer>
+ <test class="com.android.tradefed.testtype.AndroidJUnitTest">
+ <option name="package" value="com.android.wm.shell.flicker"/>
+ <option name="exclude-annotation" value="androidx.test.filters.FlakyTest" />
+ <option name="shell-timeout" value="6600s" />
+ <option name="test-timeout" value="6000s" />
+ <option name="hidden-api-checks" value="false" />
+ </test>
+ <metrics_collector class="com.android.tradefed.device.metric.FilePullerLogCollector">
+ <option name="directory-keys" value="/storage/emulated/0/Android/data/com.android.wm.shell.flicker/files" />
+ <option name="collect-on-run-ended-only" value="true" />
+ <option name="clean-up" value="true" />
+ </metrics_collector>
+</configuration>
diff --git a/libs/WindowManager/Shell/tests/flicker/README.md b/libs/WindowManager/Shell/tests/flicker/README.md
new file mode 100644
index 000000000000..4502d498a65b
--- /dev/null
+++ b/libs/WindowManager/Shell/tests/flicker/README.md
@@ -0,0 +1,10 @@
+# WM Shell Flicker Test Package
+
+Please reference the following links
+
+- [Introduction to Flicker Test Library](http://cs/android/platform_testing/libraries/flicker/)
+- [Flicker Test in frameworks/base](http://cs/android/frameworks/base/tests/FlickerTests/)
+
+on what is Flicker Test and how to write a Flicker Test
+
+To run the Flicker Tests for WM Shell, simply run `atest WMShellFlickerTests`
diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/CommonAssertions.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/CommonAssertions.kt
new file mode 100644
index 000000000000..4ff2bfca3a4a
--- /dev/null
+++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/CommonAssertions.kt
@@ -0,0 +1,153 @@
+/*
+ * 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
+
+import com.android.server.wm.flicker.dsl.EventLogAssertion
+import com.android.server.wm.flicker.dsl.LayersAssertion
+import com.android.server.wm.flicker.dsl.WmAssertion
+import com.android.server.wm.flicker.helpers.WindowUtils
+
+@JvmOverloads
+fun WmAssertion.statusBarWindowIsAlwaysVisible(
+ bugId: Int = 0,
+ enabled: Boolean = bugId == 0
+) {
+ all("statusBarWindowIsAlwaysVisible", enabled, bugId) {
+ this.showsAboveAppWindow(FlickerTestBase.STATUS_BAR_WINDOW_TITLE)
+ }
+}
+
+@JvmOverloads
+fun WmAssertion.navBarWindowIsAlwaysVisible(
+ bugId: Int = 0,
+ enabled: Boolean = bugId == 0
+) {
+ all("navBarWindowIsAlwaysVisible", enabled, bugId) {
+ this.showsAboveAppWindow(FlickerTestBase.NAVIGATION_BAR_WINDOW_TITLE)
+ }
+}
+
+@JvmOverloads
+fun LayersAssertion.noUncoveredRegions(
+ beginRotation: Int,
+ endRotation: Int = beginRotation,
+ allStates: Boolean = true,
+ bugId: Int = 0,
+ enabled: Boolean = bugId == 0
+) {
+ val startingBounds = WindowUtils.getDisplayBounds(beginRotation)
+ val endingBounds = WindowUtils.getDisplayBounds(endRotation)
+ if (allStates) {
+ all("noUncoveredRegions", enabled, bugId) {
+ if (startingBounds == endingBounds) {
+ this.coversAtLeastRegion(startingBounds)
+ } else {
+ this.coversAtLeastRegion(startingBounds)
+ .then()
+ .coversAtLeastRegion(endingBounds)
+ }
+ }
+ } else {
+ start("noUncoveredRegions_StartingPos") {
+ this.coversAtLeastRegion(startingBounds)
+ }
+ end("noUncoveredRegions_EndingPos") {
+ this.coversAtLeastRegion(endingBounds)
+ }
+ }
+}
+
+@JvmOverloads
+fun LayersAssertion.navBarLayerIsAlwaysVisible(
+ bugId: Int = 0,
+ enabled: Boolean = bugId == 0
+) {
+ all("navBarLayerIsAlwaysVisible", enabled, bugId) {
+ this.showsLayer(FlickerTestBase.NAVIGATION_BAR_WINDOW_TITLE)
+ }
+}
+
+@JvmOverloads
+fun LayersAssertion.statusBarLayerIsAlwaysVisible(
+ bugId: Int = 0,
+ enabled: Boolean = bugId == 0
+) {
+ all("statusBarLayerIsAlwaysVisible", enabled, bugId) {
+ this.showsLayer(FlickerTestBase.STATUS_BAR_WINDOW_TITLE)
+ }
+}
+
+@JvmOverloads
+fun LayersAssertion.navBarLayerRotatesAndScales(
+ beginRotation: Int,
+ endRotation: Int = beginRotation,
+ bugId: Int = 0,
+ enabled: Boolean = bugId == 0
+) {
+ val startingPos = WindowUtils.getNavigationBarPosition(beginRotation)
+ val endingPos = WindowUtils.getNavigationBarPosition(endRotation)
+
+ start("navBarLayerRotatesAndScales_StartingPos", enabled, bugId) {
+ this.hasVisibleRegion(FlickerTestBase.NAVIGATION_BAR_WINDOW_TITLE, startingPos)
+ }
+ end("navBarLayerRotatesAndScales_EndingPost", enabled, bugId) {
+ this.hasVisibleRegion(FlickerTestBase.NAVIGATION_BAR_WINDOW_TITLE, endingPos)
+ }
+
+ if (startingPos == endingPos) {
+ all("navBarLayerRotatesAndScales", enabled, bugId) {
+ this.hasVisibleRegion(FlickerTestBase.NAVIGATION_BAR_WINDOW_TITLE, startingPos)
+ }
+ }
+}
+
+@JvmOverloads
+fun LayersAssertion.statusBarLayerRotatesScales(
+ beginRotation: Int,
+ endRotation: Int = beginRotation,
+ bugId: Int = 0,
+ enabled: Boolean = bugId == 0
+) {
+ val startingPos = WindowUtils.getStatusBarPosition(beginRotation)
+ val endingPos = WindowUtils.getStatusBarPosition(endRotation)
+
+ start("statusBarLayerRotatesScales_StartingPos", enabled, bugId) {
+ this.hasVisibleRegion(FlickerTestBase.STATUS_BAR_WINDOW_TITLE, startingPos)
+ }
+ end("statusBarLayerRotatesScales_EndingPos", enabled, bugId) {
+ this.hasVisibleRegion(FlickerTestBase.STATUS_BAR_WINDOW_TITLE, endingPos)
+ }
+}
+
+fun EventLogAssertion.focusChanges(
+ vararg windows: String,
+ bugId: Int = 0,
+ enabled: Boolean = bugId == 0
+) {
+ all(enabled = enabled, bugId = bugId) {
+ this.focusChanges(windows)
+ }
+}
+
+fun EventLogAssertion.focusDoesNotChange(
+ bugId: Int = 0,
+ enabled: Boolean = bugId == 0
+) {
+ all(enabled = enabled, bugId = bugId) {
+ this.focusDoesNotChange()
+ }
+}
diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/FlickerTestBase.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/FlickerTestBase.kt
new file mode 100644
index 000000000000..99f824bb8341
--- /dev/null
+++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/FlickerTestBase.kt
@@ -0,0 +1,130 @@
+/*
+ * 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
+
+import android.os.RemoteException
+import android.os.SystemClock
+import android.platform.helpers.IAppHelper
+import android.view.Surface
+import androidx.test.platform.app.InstrumentationRegistry
+import androidx.test.uiautomator.UiDevice
+import com.android.server.wm.flicker.Flicker
+
+/**
+ * Base class of all Flicker test that performs common functions for all flicker tests:
+ *
+ *
+ * - Caches transitions so that a transition is run once and the transition results are used by
+ * tests multiple times. This is needed for parameterized tests which call the BeforeClass methods
+ * multiple times.
+ * - Keeps track of all test artifacts and deletes ones which do not need to be reviewed.
+ * - Fails tests if results are not available for any test due to jank.
+ */
+abstract class FlickerTestBase {
+ val instrumentation by lazy {
+ InstrumentationRegistry.getInstrumentation()
+ }
+ val uiDevice by lazy {
+ UiDevice.getInstance(instrumentation)
+ }
+
+ /**
+ * Build a test tag for the test
+ * @param testName Name of the transition(s) being tested
+ * @param app App being launcher
+ * @param rotation Initial screen rotation
+ *
+ * @return test tag with pattern <NAME>__<APP>__<ROTATION>
+ </ROTATION></APP></NAME> */
+ protected fun buildTestTag(testName: String, app: IAppHelper, rotation: Int): String {
+ return buildTestTag(
+ testName, app, rotation, rotation, app2 = null, extraInfo = "")
+ }
+
+ /**
+ * Build a test tag for the test
+ * @param testName Name of the transition(s) being tested
+ * @param app App being launcher
+ * @param beginRotation Initial screen rotation
+ * @param endRotation End screen rotation (if any, otherwise use same as initial)
+ *
+ * @return test tag with pattern <NAME>__<APP>__<BEGIN_ROTATION>-<END_ROTATION>
+ </END_ROTATION></BEGIN_ROTATION></APP></NAME> */
+ protected fun buildTestTag(
+ testName: String,
+ app: IAppHelper,
+ beginRotation: Int,
+ endRotation: Int
+ ): String {
+ return buildTestTag(
+ testName, app, beginRotation, endRotation, app2 = null, extraInfo = "")
+ }
+
+ /**
+ * Build a test tag for the test
+ * @param testName Name of the transition(s) being tested
+ * @param app App being launcher
+ * @param app2 Second app being launched (if any)
+ * @param beginRotation Initial screen rotation
+ * @param endRotation End screen rotation (if any, otherwise use same as initial)
+ * @param extraInfo Additional information to append to the tag
+ *
+ * @return test tag with pattern <NAME>__<APP></APP>(S)>__<ROTATION></ROTATION>(S)>[__<EXTRA>]
+ </EXTRA></NAME> */
+ protected fun buildTestTag(
+ testName: String,
+ app: IAppHelper,
+ beginRotation: Int,
+ endRotation: Int,
+ app2: IAppHelper?,
+ extraInfo: String
+ ): String {
+ var testTag = "${testName}__${app.launcherName}"
+ if (app2 != null) {
+ testTag += "-${app2.launcherName}"
+ }
+ testTag += "__${Surface.rotationToString(beginRotation)}"
+ if (endRotation != beginRotation) {
+ testTag += "-${Surface.rotationToString(endRotation)}"
+ }
+ if (extraInfo.isNotEmpty()) {
+ testTag += "__$extraInfo"
+ }
+ return testTag
+ }
+
+ protected fun Flicker.setRotation(rotation: Int) {
+ try {
+ when (rotation) {
+ Surface.ROTATION_270 -> device.setOrientationLeft()
+ Surface.ROTATION_90 -> device.setOrientationRight()
+ Surface.ROTATION_0 -> device.setOrientationNatural()
+ else -> device.setOrientationNatural()
+ }
+ // Wait for animation to complete
+ SystemClock.sleep(1000)
+ } catch (e: RemoteException) {
+ throw RuntimeException(e)
+ }
+ }
+
+ companion object {
+ const val NAVIGATION_BAR_WINDOW_TITLE = "NavigationBar"
+ const val STATUS_BAR_WINDOW_TITLE = "StatusBar"
+ const val DOCKED_STACK_DIVIDER = "DockedStackDivider"
+ }
+}
diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/NonRotationTestBase.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/NonRotationTestBase.kt
new file mode 100644
index 000000000000..90334ae91e9d
--- /dev/null
+++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/NonRotationTestBase.kt
@@ -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.
+ */
+
+package com.android.wm.shell.flicker
+
+import android.view.Surface
+import org.junit.runners.Parameterized
+
+abstract class NonRotationTestBase(
+ protected val rotationName: String,
+ protected val rotation: Int
+) : FlickerTestBase() {
+ companion object {
+ const val SCREENSHOT_LAYER = "RotationLayer"
+
+ @Parameterized.Parameters(name = "{0}")
+ @JvmStatic
+ fun getParams(): Collection<Array<Any>> {
+ val supportedRotations = intArrayOf(Surface.ROTATION_0, Surface.ROTATION_90)
+ return supportedRotations.map { arrayOf(Surface.rotationToString(it), it) }
+ }
+ }
+}
diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/helpers/FlickerAppHelper.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/helpers/FlickerAppHelper.kt
new file mode 100644
index 000000000000..308a36efef87
--- /dev/null
+++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/helpers/FlickerAppHelper.kt
@@ -0,0 +1,31 @@
+/*
+ * 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.helpers
+
+import android.app.Instrumentation
+import android.support.test.launcherhelper.ILauncherStrategy
+import com.android.server.wm.flicker.StandardAppHelper
+
+abstract class FlickerAppHelper(
+ instr: Instrumentation,
+ launcherName: String,
+ launcherStrategy: ILauncherStrategy
+) : StandardAppHelper(instr, sFlickerPackage, launcherName, launcherStrategy) {
+ companion object {
+ var sFlickerPackage = "com.android.wm.shell.flicker.testapp"
+ }
+}
diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/helpers/PipAppHelper.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/helpers/PipAppHelper.kt
new file mode 100644
index 000000000000..539170202b8a
--- /dev/null
+++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/helpers/PipAppHelper.kt
@@ -0,0 +1,45 @@
+/*
+ * 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.helpers
+
+import android.app.Instrumentation
+import android.support.test.launcherhelper.ILauncherStrategy
+import android.support.test.launcherhelper.LauncherStrategyFactory
+import androidx.test.uiautomator.By
+import androidx.test.uiautomator.UiDevice
+import com.android.server.wm.flicker.helpers.hasPipWindow
+import com.android.server.wm.flicker.helpers.closePipWindow
+import org.junit.Assert
+
+class PipAppHelper(
+ instr: Instrumentation,
+ launcherStrategy: ILauncherStrategy = LauncherStrategyFactory
+ .getInstance(instr)
+ .launcherStrategy
+) : FlickerAppHelper(instr, "PipApp", launcherStrategy) {
+ fun clickEnterPipButton(device: UiDevice) {
+ val enterPipButton = device.findObject(By.res(getPackage(), "enter_pip"))
+ Assert.assertNotNull("Pip button not found, this usually happens when the device " +
+ "was left in an unknown state (e.g. in split screen)", enterPipButton)
+ enterPipButton.click()
+ device.hasPipWindow()
+ }
+
+ fun closePipWindow(device: UiDevice) {
+ device.closePipWindow()
+ }
+}
diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/EnterPipTest.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/EnterPipTest.kt
new file mode 100644
index 000000000000..4b04449bdbc2
--- /dev/null
+++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/EnterPipTest.kt
@@ -0,0 +1,121 @@
+/*
+ * 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.pip
+
+import android.view.Surface
+import androidx.test.filters.FlakyTest
+import androidx.test.filters.LargeTest
+import com.android.server.wm.flicker.dsl.flicker
+import com.android.server.wm.flicker.helpers.closePipWindow
+import com.android.server.wm.flicker.helpers.expandPipWindow
+import com.android.server.wm.flicker.helpers.hasPipWindow
+import com.android.server.wm.flicker.helpers.wakeUpAndGoToHomeScreen
+import com.android.wm.shell.flicker.navBarLayerIsAlwaysVisible
+import com.android.wm.shell.flicker.navBarLayerRotatesAndScales
+import com.android.wm.shell.flicker.navBarWindowIsAlwaysVisible
+import com.android.wm.shell.flicker.noUncoveredRegions
+import com.android.wm.shell.flicker.statusBarLayerIsAlwaysVisible
+import com.android.wm.shell.flicker.statusBarLayerRotatesScales
+import com.android.wm.shell.flicker.statusBarWindowIsAlwaysVisible
+import org.junit.FixMethodOrder
+import org.junit.Test
+import org.junit.runner.RunWith
+import org.junit.runners.MethodSorters
+import org.junit.runners.Parameterized
+
+/**
+ * Test Pip launch.
+ * To run this test: `atest FlickerTests:PipToAppTest`
+ */
+@LargeTest
+@RunWith(Parameterized::class)
+@FixMethodOrder(MethodSorters.NAME_ASCENDING)
+@FlakyTest(bugId = 152738416)
+class EnterPipTest(
+ rotationName: String,
+ rotation: Int
+) : PipTestBase(rotationName, rotation) {
+ @Test
+ fun test() {
+ flicker(instrumentation) {
+ withTag { buildTestTag("enterPip", testApp, rotation) }
+ repeat { 1 }
+ setup {
+ test {
+ device.wakeUpAndGoToHomeScreen()
+ }
+ eachRun {
+ device.pressHome()
+ testApp.open()
+ this.setRotation(rotation)
+ }
+ }
+ teardown {
+ eachRun {
+ if (device.hasPipWindow()) {
+ device.closePipWindow()
+ }
+ testApp.exit()
+ this.setRotation(Surface.ROTATION_0)
+ }
+ test {
+ if (device.hasPipWindow()) {
+ device.closePipWindow()
+ }
+ }
+ }
+ transitions {
+ testApp.clickEnterPipButton(device)
+ device.expandPipWindow()
+ }
+ assertions {
+ windowManagerTrace {
+ navBarWindowIsAlwaysVisible()
+ statusBarWindowIsAlwaysVisible()
+ all("pipWindowBecomesVisible") {
+ this.showsAppWindow(testApp.`package`)
+ .then()
+ .showsAppWindow(sPipWindowTitle)
+ }
+ }
+
+ layersTrace {
+ navBarLayerIsAlwaysVisible()
+ statusBarLayerIsAlwaysVisible()
+ noUncoveredRegions(rotation, Surface.ROTATION_0, allStates = false)
+ navBarLayerRotatesAndScales(rotation, Surface.ROTATION_0)
+ statusBarLayerRotatesScales(rotation, Surface.ROTATION_0)
+
+ all("pipLayerBecomesVisible") {
+ this.showsLayer(testApp.launcherName)
+ .then()
+ .showsLayer(sPipWindowTitle)
+ }
+ }
+ }
+ }
+ }
+
+ companion object {
+ @Parameterized.Parameters(name = "{0}")
+ @JvmStatic
+ fun getParams(): Collection<Array<Any>> {
+ val supportedRotations = intArrayOf(Surface.ROTATION_0)
+ return supportedRotations.map { arrayOf(Surface.rotationToString(it), it) }
+ }
+ }
+}
diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/PipTestBase.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/PipTestBase.kt
new file mode 100644
index 000000000000..3822d69a65f5
--- /dev/null
+++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/PipTestBase.kt
@@ -0,0 +1,31 @@
+/*
+ * 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.pip
+
+import com.android.wm.shell.flicker.NonRotationTestBase
+import com.android.wm.shell.flicker.helpers.PipAppHelper
+
+abstract class PipTestBase(
+ rotationName: String,
+ rotation: Int
+) : NonRotationTestBase(rotationName, rotation) {
+ protected val testApp = PipAppHelper(instrumentation)
+
+ companion object {
+ const val sPipWindowTitle = "PipMenuActivity"
+ }
+}
diff --git a/libs/WindowManager/Shell/tests/flicker/test-apps/Android.bp b/libs/WindowManager/Shell/tests/flicker/test-apps/Android.bp
new file mode 100644
index 000000000000..e69de29bb2d1
--- /dev/null
+++ b/libs/WindowManager/Shell/tests/flicker/test-apps/Android.bp
diff --git a/libs/WindowManager/Shell/tests/flicker/test-apps/flickerapp/Android.bp b/libs/WindowManager/Shell/tests/flicker/test-apps/flickerapp/Android.bp
new file mode 100644
index 000000000000..d12b49245277
--- /dev/null
+++ b/libs/WindowManager/Shell/tests/flicker/test-apps/flickerapp/Android.bp
@@ -0,0 +1,20 @@
+// 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.
+
+android_test {
+ name: "WMShellFlickerTestApp",
+ srcs: ["**/*.java"],
+ sdk_version: "current",
+ test_suites: ["device-tests"],
+}
diff --git a/libs/WindowManager/Shell/tests/flicker/test-apps/flickerapp/AndroidManifest.xml b/libs/WindowManager/Shell/tests/flicker/test-apps/flickerapp/AndroidManifest.xml
new file mode 100644
index 000000000000..95dc1d48eee8
--- /dev/null
+++ b/libs/WindowManager/Shell/tests/flicker/test-apps/flickerapp/AndroidManifest.xml
@@ -0,0 +1,37 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- 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.
+-->
+
+<manifest xmlns:android="http://schemas.android.com/apk/res/android"
+ package="com.android.wm.shell.flicker.testapp">
+
+ <uses-sdk android:minSdkVersion="29"
+ android:targetSdkVersion="29"/>
+ <application android:allowBackup="false"
+ android:supportsRtl="true">
+ <activity android:name=".PipActivity"
+ android:resizeableActivity="true"
+ android:supportsPictureInPicture="true"
+ android:configChanges="screenSize|smallestScreenSize|screenLayout|orientation"
+ android:taskAffinity="com.android.wm.shell.flicker.testapp.PipActivity"
+ android:label="PipApp"
+ android:exported="true">
+ <intent-filter>
+ <action android:name="android.intent.action.MAIN"/>
+ <category android:name="android.intent.category.LAUNCHER"/>
+ </intent-filter>
+ </activity>
+ </application>
+</manifest>
diff --git a/libs/WindowManager/Shell/tests/flicker/test-apps/flickerapp/res/layout/activity_pip.xml b/libs/WindowManager/Shell/tests/flicker/test-apps/flickerapp/res/layout/activity_pip.xml
new file mode 100644
index 000000000000..e1870d9c523d
--- /dev/null
+++ b/libs/WindowManager/Shell/tests/flicker/test-apps/flickerapp/res/layout/activity_pip.xml
@@ -0,0 +1,26 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ 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.
+-->
+<LinearLayout
+ xmlns:android="http://schemas.android.com/apk/res/android"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent"
+ android:background="@android:color/holo_blue_bright">
+ <Button android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:id="@+id/enter_pip"
+ android:text="Enter PIP"/>
+</LinearLayout>
diff --git a/libs/WindowManager/Shell/tests/flicker/test-apps/flickerapp/src/com/android/wm/shell/flicker/testapp/PipActivity.java b/libs/WindowManager/Shell/tests/flicker/test-apps/flickerapp/src/com/android/wm/shell/flicker/testapp/PipActivity.java
new file mode 100644
index 000000000000..305281691e11
--- /dev/null
+++ b/libs/WindowManager/Shell/tests/flicker/test-apps/flickerapp/src/com/android/wm/shell/flicker/testapp/PipActivity.java
@@ -0,0 +1,45 @@
+/*
+ * 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.testapp;
+
+import android.app.Activity;
+import android.app.PictureInPictureParams;
+import android.graphics.Rect;
+import android.os.Bundle;
+import android.util.Rational;
+import android.view.WindowManager;
+import android.widget.Button;
+
+public class PipActivity extends Activity {
+ @Override
+ public void onCreate(Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
+ WindowManager.LayoutParams p = getWindow().getAttributes();
+ p.layoutInDisplayCutoutMode = WindowManager.LayoutParams
+ .LAYOUT_IN_DISPLAY_CUTOUT_MODE_SHORT_EDGES;
+ getWindow().setAttributes(p);
+ setContentView(R.layout.activity_pip);
+ Button enterPip = (Button) findViewById(R.id.enter_pip);
+
+ PictureInPictureParams params = new PictureInPictureParams.Builder()
+ .setAspectRatio(new Rational(1, 1))
+ .setSourceRectHint(new Rect(0, 0, 100, 100))
+ .build();
+
+ enterPip.setOnClickListener((v) -> enterPictureInPictureMode(params));
+ }
+}
diff --git a/libs/WindowManager/Shell/tests/Android.bp b/libs/WindowManager/Shell/tests/unittest/Android.bp
index 9868879cebb9..692e2fa88fc3 100644
--- a/libs/WindowManager/Shell/tests/Android.bp
+++ b/libs/WindowManager/Shell/tests/unittest/Android.bp
@@ -13,7 +13,7 @@
// limitations under the License.
android_test {
- name: "WindowManagerShellTests",
+ name: "WMShellUnitTests",
srcs: ["**/*.java"],
diff --git a/libs/WindowManager/Shell/tests/AndroidManifest.xml b/libs/WindowManager/Shell/tests/unittest/AndroidManifest.xml
index a8f795ec8a8d..a8f795ec8a8d 100644
--- a/libs/WindowManager/Shell/tests/AndroidManifest.xml
+++ b/libs/WindowManager/Shell/tests/unittest/AndroidManifest.xml
diff --git a/libs/WindowManager/Shell/tests/AndroidTest.xml b/libs/WindowManager/Shell/tests/unittest/AndroidTest.xml
index 4dce4db360e4..21ed2c075dff 100644
--- a/libs/WindowManager/Shell/tests/AndroidTest.xml
+++ b/libs/WindowManager/Shell/tests/unittest/AndroidTest.xml
@@ -17,12 +17,12 @@
<target_preparer class="com.android.tradefed.targetprep.suite.SuiteApkInstaller">
<option name="cleanup-apks" value="true" />
<option name="install-arg" value="-t" />
- <option name="test-file-name" value="WindowManagerShellTests.apk" />
+ <option name="test-file-name" value="WMShellUnitTests.apk" />
</target_preparer>
<option name="test-suite-tag" value="apct" />
<option name="test-suite-tag" value="framework-base-presubmit" />
- <option name="test-tag" value="WindowManagerShellTests" />
+ <option name="test-tag" value="WMShellUnitTests" />
<test class="com.android.tradefed.testtype.AndroidJUnitTest" >
<option name="package" value="com.android.wm.shell.tests" />
<option name="runner" value="androidx.test.runner.AndroidJUnitRunner" />
diff --git a/libs/WindowManager/Shell/tests/res/values/config.xml b/libs/WindowManager/Shell/tests/unittest/res/values/config.xml
index c894eb0133b5..c894eb0133b5 100644
--- a/libs/WindowManager/Shell/tests/res/values/config.xml
+++ b/libs/WindowManager/Shell/tests/unittest/res/values/config.xml
diff --git a/libs/WindowManager/Shell/tests/src/com/android/wm/shell/ShellTaskOrganizerTests.java b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/ShellTaskOrganizerTests.java
index 10672c8d87ad..10672c8d87ad 100644
--- a/libs/WindowManager/Shell/tests/src/com/android/wm/shell/ShellTaskOrganizerTests.java
+++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/ShellTaskOrganizerTests.java
diff --git a/libs/WindowManager/Shell/tests/src/com/android/wm/shell/common/DisplayLayoutTest.java b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/common/DisplayLayoutTest.java
index 2b5b77e49e3a..2b5b77e49e3a 100644
--- a/libs/WindowManager/Shell/tests/src/com/android/wm/shell/common/DisplayLayoutTest.java
+++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/common/DisplayLayoutTest.java
diff --git a/libs/hwui/RecordingCanvas.cpp b/libs/hwui/RecordingCanvas.cpp
index 892d43a763a9..473dc53dc4bf 100644
--- a/libs/hwui/RecordingCanvas.cpp
+++ b/libs/hwui/RecordingCanvas.cpp
@@ -524,6 +524,7 @@ void* DisplayListData::push(size_t pod, Args&&... args) {
// Next greater multiple of SKLITEDL_PAGE.
fReserved = (fUsed + skip + SKLITEDL_PAGE) & ~(SKLITEDL_PAGE - 1);
fBytes.realloc(fReserved);
+ LOG_ALWAYS_FATAL_IF(fBytes.get() == nullptr, "realloc(%zd) failed", fReserved);
}
SkASSERT(fUsed + skip <= fReserved);
auto op = (T*)(fBytes.get() + fUsed);
diff --git a/libs/hwui/jni/Picture.cpp b/libs/hwui/jni/Picture.cpp
index d1b952130e88..8e4203c0b115 100644
--- a/libs/hwui/jni/Picture.cpp
+++ b/libs/hwui/jni/Picture.cpp
@@ -111,7 +111,7 @@ sk_sp<SkPicture> Picture::makePartialCopy() const {
SkPictureRecorder reRecorder;
- SkCanvas* canvas = reRecorder.beginRecording(mWidth, mHeight, NULL, 0);
+ SkCanvas* canvas = reRecorder.beginRecording(mWidth, mHeight);
mRecorder->partialReplay(canvas);
return reRecorder.finishRecordingAsPicture();
}
diff --git a/libs/hwui/renderthread/VulkanManager.cpp b/libs/hwui/renderthread/VulkanManager.cpp
index 0c5cf682e566..76ec078ce3c9 100644
--- a/libs/hwui/renderthread/VulkanManager.cpp
+++ b/libs/hwui/renderthread/VulkanManager.cpp
@@ -361,20 +361,6 @@ void VulkanManager::initialize() {
mGetDeviceQueue(mDevice, mGraphicsQueueIndex, 0, &mGraphicsQueue);
mGetDeviceQueue(mDevice, mGraphicsQueueIndex, 1, &mAHBUploadQueue);
- // create the command pool for the command buffers
- if (VK_NULL_HANDLE == mCommandPool) {
- VkCommandPoolCreateInfo commandPoolInfo;
- memset(&commandPoolInfo, 0, sizeof(VkCommandPoolCreateInfo));
- commandPoolInfo.sType = VK_STRUCTURE_TYPE_COMMAND_POOL_CREATE_INFO;
- // this needs to be on the render queue
- commandPoolInfo.queueFamilyIndex = mGraphicsQueueIndex;
- commandPoolInfo.flags = VK_COMMAND_POOL_CREATE_RESET_COMMAND_BUFFER_BIT;
- SkDEBUGCODE(VkResult res =)
- mCreateCommandPool(mDevice, &commandPoolInfo, nullptr, &mCommandPool);
- SkASSERT(VK_SUCCESS == res);
- }
- LOG_ALWAYS_FATAL_IF(mCommandPool == VK_NULL_HANDLE);
-
mGetDeviceQueue(mDevice, mPresentQueueIndex, 0, &mPresentQueue);
if (Properties::enablePartialUpdates && Properties::useBufferAge) {
diff --git a/libs/hwui/renderthread/VulkanManager.h b/libs/hwui/renderthread/VulkanManager.h
index 13335f32ef06..75c05b828e5d 100644
--- a/libs/hwui/renderthread/VulkanManager.h
+++ b/libs/hwui/renderthread/VulkanManager.h
@@ -165,7 +165,6 @@ private:
VkQueue mAHBUploadQueue = VK_NULL_HANDLE;
uint32_t mPresentQueueIndex;
VkQueue mPresentQueue = VK_NULL_HANDLE;
- VkCommandPool mCommandPool = VK_NULL_HANDLE;
// Variables saved to populate VkFunctorInitParams.
static const uint32_t mAPIVersion = VK_MAKE_VERSION(1, 1, 0);
diff --git a/libs/hwui/tests/unit/SkiaCanvasTests.cpp b/libs/hwui/tests/unit/SkiaCanvasTests.cpp
index fcc64fdd0be6..f77ca2a8c06c 100644
--- a/libs/hwui/tests/unit/SkiaCanvasTests.cpp
+++ b/libs/hwui/tests/unit/SkiaCanvasTests.cpp
@@ -73,7 +73,7 @@ TEST(SkiaCanvas, colorSpaceXform) {
// Test picture recording.
SkPictureRecorder recorder;
- SkCanvas* skPicCanvas = recorder.beginRecording(1, 1, NULL, 0);
+ SkCanvas* skPicCanvas = recorder.beginRecording(1, 1);
SkiaCanvas picCanvas(skPicCanvas);
picCanvas.drawBitmap(*adobeBitmap, 0, 0, nullptr);
sk_sp<SkPicture> picture = recorder.finishRecordingAsPicture();
@@ -104,7 +104,7 @@ TEST(SkiaCanvas, captureCanvasState) {
// Create a picture canvas.
SkPictureRecorder recorder;
- SkCanvas* skPicCanvas = recorder.beginRecording(1, 1, NULL, 0);
+ SkCanvas* skPicCanvas = recorder.beginRecording(1, 1);
SkiaCanvas picCanvas(skPicCanvas);
state = picCanvas.captureCanvasState();
diff --git a/libs/input/MouseCursorController.cpp b/libs/input/MouseCursorController.cpp
index 80b555be97dd..45da008c3e8e 100644
--- a/libs/input/MouseCursorController.cpp
+++ b/libs/input/MouseCursorController.cpp
@@ -168,7 +168,7 @@ void MouseCursorController::fade(PointerControllerInterface::Transition transiti
updatePointerLocked();
} else {
mLocked.pointerFadeDirection = -1;
- mContext.startAnimation();
+ startAnimationLocked();
}
}
@@ -185,7 +185,7 @@ void MouseCursorController::unfade(PointerControllerInterface::Transition transi
updatePointerLocked();
} else {
mLocked.pointerFadeDirection = 1;
- mContext.startAnimation();
+ startAnimationLocked();
}
}
@@ -312,10 +312,9 @@ void MouseCursorController::setCustomPointerIcon(const SpriteIcon& icon) {
updatePointerLocked();
}
-bool MouseCursorController::doFadingAnimation(nsecs_t timestamp, bool keepAnimating) {
+bool MouseCursorController::doFadingAnimationLocked(nsecs_t timestamp) REQUIRES(mLock) {
nsecs_t frameDelay = timestamp - mContext.getAnimationTime();
-
- std::scoped_lock lock(mLock);
+ bool keepAnimating = false;
// Animate pointer fade.
if (mLocked.pointerFadeDirection < 0) {
@@ -337,13 +336,10 @@ bool MouseCursorController::doFadingAnimation(nsecs_t timestamp, bool keepAnimat
}
updatePointerLocked();
}
-
return keepAnimating;
}
-bool MouseCursorController::doBitmapAnimation(nsecs_t timestamp) {
- std::scoped_lock lock(mLock);
-
+bool MouseCursorController::doBitmapAnimationLocked(nsecs_t timestamp) REQUIRES(mLock) {
std::map<int32_t, PointerAnimation>::const_iterator iter =
mLocked.animationResources.find(mLocked.requestedPointerType);
if (iter == mLocked.animationResources.end()) {
@@ -364,7 +360,6 @@ bool MouseCursorController::doBitmapAnimation(nsecs_t timestamp) {
spriteController->closeTransaction();
}
-
// Keep animating.
return true;
}
@@ -399,7 +394,7 @@ void MouseCursorController::updatePointerLocked() REQUIRES(mLock) {
if (anim_iter != mLocked.animationResources.end()) {
mLocked.animationFrameIndex = 0;
mLocked.lastFrameUpdatedTime = systemTime(SYSTEM_TIME_MONOTONIC);
- mContext.startAnimation();
+ startAnimationLocked();
}
mLocked.pointerSprite->setIcon(iter->second);
} else {
@@ -457,4 +452,38 @@ bool MouseCursorController::resourcesLoaded() {
return mLocked.resourcesLoaded;
}
+bool MouseCursorController::doAnimations(nsecs_t timestamp) {
+ std::scoped_lock lock(mLock);
+ bool keepFading = doFadingAnimationLocked(timestamp);
+ bool keepBitmap = doBitmapAnimationLocked(timestamp);
+ bool keepAnimating = keepFading || keepBitmap;
+ if (!keepAnimating) {
+ /*
+ * We know that this callback will be removed before another
+ * is added. mLock in PointerAnimator will not be released
+ * until after this is removed, and adding another callback
+ * requires that lock. Thus it's safe to set mLocked.animating
+ * here.
+ */
+ mLocked.animating = false;
+ }
+ return keepAnimating;
+}
+
+void MouseCursorController::startAnimationLocked() REQUIRES(mLock) {
+ using namespace std::placeholders;
+
+ if (mLocked.animating) {
+ return;
+ }
+ mLocked.animating = true;
+
+ std::function<bool(nsecs_t)> func = std::bind(&MouseCursorController::doAnimations, this, _1);
+ /*
+ * Using -1 for displayId here to avoid removing the callback
+ * if a TouchSpotController with the same display is removed.
+ */
+ mContext.addAnimationCallback(-1, func);
+}
+
} // namespace android
diff --git a/libs/input/MouseCursorController.h b/libs/input/MouseCursorController.h
index 448165b5ac46..e6dfc4c6f99a 100644
--- a/libs/input/MouseCursorController.h
+++ b/libs/input/MouseCursorController.h
@@ -25,6 +25,7 @@
#include <utils/Looper.h>
#include <utils/RefBase.h>
+#include <functional>
#include <map>
#include <memory>
#include <vector>
@@ -61,8 +62,7 @@ public:
void getAdditionalMouseResources();
bool isViewportValid();
- bool doBitmapAnimation(nsecs_t timestamp);
- bool doFadingAnimation(nsecs_t timestamp, bool keepAnimating);
+ bool doAnimations(nsecs_t timestamp);
bool resourcesLoaded();
@@ -96,6 +96,8 @@ private:
int32_t buttonState;
+ bool animating{false};
+
} mLocked GUARDED_BY(mLock);
bool getBoundsLocked(float* outMinX, float* outMinY, float* outMaxX, float* outMaxY) const;
@@ -104,6 +106,11 @@ private:
void updatePointerLocked();
void loadResourcesLocked(bool getAdditionalMouseResources);
+
+ bool doBitmapAnimationLocked(nsecs_t timestamp);
+ bool doFadingAnimationLocked(nsecs_t timestamp);
+
+ void startAnimationLocked();
};
} // namespace android
diff --git a/libs/input/PointerController.cpp b/libs/input/PointerController.cpp
index 14c96cefd462..8f04cfb70469 100644
--- a/libs/input/PointerController.cpp
+++ b/libs/input/PointerController.cpp
@@ -57,7 +57,6 @@ std::shared_ptr<PointerController> PointerController::create(
controller->mContext.setHandlerController(controller);
controller->mContext.setCallbackController(controller);
- controller->mContext.initializeDisplayEventReceiver();
return controller;
}
@@ -189,24 +188,6 @@ void PointerController::setCustomPointerIcon(const SpriteIcon& icon) {
mCursorController.setCustomPointerIcon(icon);
}
-void PointerController::doAnimate(nsecs_t timestamp) {
- std::scoped_lock lock(mLock);
-
- mContext.setAnimationPending(false);
-
- bool keepFading = false;
- keepFading = mCursorController.doFadingAnimation(timestamp, keepFading);
-
- for (auto& [displayID, spotController] : mLocked.spotControllers) {
- keepFading = spotController.doFadingAnimation(timestamp, keepFading);
- }
-
- bool keepBitmapFlipping = mCursorController.doBitmapAnimation(timestamp);
- if (keepFading || keepBitmapFlipping) {
- mContext.startAnimation();
- }
-}
-
void PointerController::doInactivityTimeout() {
fade(Transition::GRADUAL);
}
@@ -221,6 +202,11 @@ void PointerController::onDisplayViewportsUpdated(std::vector<DisplayViewport>&
for (auto it = mLocked.spotControllers.begin(); it != mLocked.spotControllers.end();) {
int32_t displayID = it->first;
if (!displayIdSet.count(displayID)) {
+ /*
+ * Ensures that an in-progress animation won't dereference
+ * a null pointer to TouchSpotController.
+ */
+ mContext.removeAnimationCallback(displayID);
it = mLocked.spotControllers.erase(it);
} else {
++it;
diff --git a/libs/input/PointerController.h b/libs/input/PointerController.h
index 1f561da333b1..827fcf1e1bc1 100644
--- a/libs/input/PointerController.h
+++ b/libs/input/PointerController.h
@@ -70,7 +70,6 @@ public:
void setCustomPointerIcon(const SpriteIcon& icon);
void setInactivityTimeout(InactivityTimeout inactivityTimeout);
void doInactivityTimeout();
- void doAnimate(nsecs_t timestamp);
void reloadPointerResources();
void onDisplayViewportsUpdated(std::vector<DisplayViewport>& viewports);
diff --git a/libs/input/PointerControllerContext.cpp b/libs/input/PointerControllerContext.cpp
index 2d7e22b01112..f30e8d8e33a5 100644
--- a/libs/input/PointerControllerContext.cpp
+++ b/libs/input/PointerControllerContext.cpp
@@ -38,10 +38,10 @@ PointerControllerContext::PointerControllerContext(
mSpriteController(spriteController),
mHandler(new MessageHandler()),
mCallback(new LooperCallback()),
- mController(controller) {
+ mController(controller),
+ mAnimator(*this) {
std::scoped_lock lock(mLock);
mLocked.inactivityTimeout = InactivityTimeout::NORMAL;
- mLocked.animationPending = false;
}
PointerControllerContext::~PointerControllerContext() {
@@ -57,15 +57,6 @@ void PointerControllerContext::setInactivityTimeout(InactivityTimeout inactivity
}
}
-void PointerControllerContext::startAnimation() {
- std::scoped_lock lock(mLock);
- if (!mLocked.animationPending) {
- mLocked.animationPending = true;
- mLocked.animationTime = systemTime(SYSTEM_TIME_MONOTONIC);
- mDisplayEventReceiver.requestNextVsync();
- }
-}
-
void PointerControllerContext::resetInactivityTimeout() {
std::scoped_lock lock(mLock);
resetInactivityTimeoutLocked();
@@ -85,14 +76,8 @@ void PointerControllerContext::removeInactivityTimeout() {
mLooper->removeMessages(mHandler, MessageHandler::MSG_INACTIVITY_TIMEOUT);
}
-void PointerControllerContext::setAnimationPending(bool animationPending) {
- std::scoped_lock lock(mLock);
- mLocked.animationPending = animationPending;
-}
-
-nsecs_t PointerControllerContext::getAnimationTime() {
- std::scoped_lock lock(mLock);
- return mLocked.animationTime;
+nsecs_t PointerControllerContext::getAnimationTime() REQUIRES(mAnimator.mLock) {
+ return mAnimator.getAnimationTimeLocked();
}
void PointerControllerContext::setHandlerController(std::shared_ptr<PointerController> controller) {
@@ -112,31 +97,8 @@ sp<SpriteController> PointerControllerContext::getSpriteController() {
return mSpriteController;
}
-void PointerControllerContext::initializeDisplayEventReceiver() {
- if (mDisplayEventReceiver.initCheck() == NO_ERROR) {
- mLooper->addFd(mDisplayEventReceiver.getFd(), Looper::POLL_CALLBACK, Looper::EVENT_INPUT,
- mCallback, nullptr);
- } else {
- ALOGE("Failed to initialize DisplayEventReceiver.");
- }
-}
-
void PointerControllerContext::handleDisplayEvents() {
- bool gotVsync = false;
- ssize_t n;
- nsecs_t timestamp;
- DisplayEventReceiver::Event buf[EVENT_BUFFER_SIZE];
- while ((n = mDisplayEventReceiver.getEvents(buf, EVENT_BUFFER_SIZE)) > 0) {
- for (size_t i = 0; i < static_cast<size_t>(n); ++i) {
- if (buf[i].header.type == DisplayEventReceiver::DISPLAY_EVENT_VSYNC) {
- timestamp = buf[i].header.timestamp;
- gotVsync = true;
- }
- }
- }
- if (gotVsync) {
- mController.doAnimate(timestamp);
- }
+ mAnimator.handleVsyncEvents();
}
void PointerControllerContext::MessageHandler::handleMessage(const Message& message) {
@@ -176,4 +138,91 @@ int PointerControllerContext::LooperCallback::handleEvent(int /* fd */, int even
return 1; // keep the callback
}
+void PointerControllerContext::addAnimationCallback(int32_t displayId,
+ std::function<bool(nsecs_t)> callback) {
+ mAnimator.addCallback(displayId, callback);
+}
+
+void PointerControllerContext::removeAnimationCallback(int32_t displayId) {
+ mAnimator.removeCallback(displayId);
+}
+
+PointerControllerContext::PointerAnimator::PointerAnimator(PointerControllerContext& context)
+ : mContext(context) {
+ initializeDisplayEventReceiver();
+}
+
+void PointerControllerContext::PointerAnimator::initializeDisplayEventReceiver() {
+ if (mDisplayEventReceiver.initCheck() == NO_ERROR) {
+ mContext.mLooper->addFd(mDisplayEventReceiver.getFd(), Looper::POLL_CALLBACK,
+ Looper::EVENT_INPUT, mContext.mCallback, nullptr);
+ } else {
+ ALOGE("Failed to initialize DisplayEventReceiver.");
+ }
+}
+
+void PointerControllerContext::PointerAnimator::addCallback(int32_t displayId,
+ std::function<bool(nsecs_t)> callback) {
+ std::scoped_lock lock(mLock);
+ mLocked.callbacks[displayId] = callback;
+ startAnimationLocked();
+}
+
+void PointerControllerContext::PointerAnimator::removeCallback(int32_t displayId) {
+ std::scoped_lock lock(mLock);
+ auto it = mLocked.callbacks.find(displayId);
+ if (it == mLocked.callbacks.end()) {
+ return;
+ }
+ mLocked.callbacks.erase(it);
+}
+
+void PointerControllerContext::PointerAnimator::handleVsyncEvents() {
+ bool gotVsync = false;
+ ssize_t n;
+ nsecs_t timestamp;
+ DisplayEventReceiver::Event buf[EVENT_BUFFER_SIZE];
+ while ((n = mDisplayEventReceiver.getEvents(buf, EVENT_BUFFER_SIZE)) > 0) {
+ for (size_t i = 0; i < static_cast<size_t>(n); ++i) {
+ if (buf[i].header.type == DisplayEventReceiver::DISPLAY_EVENT_VSYNC) {
+ timestamp = buf[i].header.timestamp;
+ gotVsync = true;
+ }
+ }
+ }
+ if (gotVsync) {
+ std::scoped_lock lock(mLock);
+ mLocked.animationPending = false;
+ handleCallbacksLocked(timestamp);
+ }
+}
+
+nsecs_t PointerControllerContext::PointerAnimator::getAnimationTimeLocked() REQUIRES(mLock) {
+ return mLocked.animationTime;
+}
+
+void PointerControllerContext::PointerAnimator::startAnimationLocked() REQUIRES(mLock) {
+ if (!mLocked.animationPending) {
+ mLocked.animationPending = true;
+ mLocked.animationTime = systemTime(SYSTEM_TIME_MONOTONIC);
+ mDisplayEventReceiver.requestNextVsync();
+ }
+}
+
+void PointerControllerContext::PointerAnimator::handleCallbacksLocked(nsecs_t timestamp)
+ REQUIRES(mLock) {
+ for (auto it = mLocked.callbacks.begin(); it != mLocked.callbacks.end();) {
+ bool keepCallback = it->second(timestamp);
+ if (!keepCallback) {
+ it = mLocked.callbacks.erase(it);
+ } else {
+ ++it;
+ }
+ }
+
+ if (!mLocked.callbacks.empty()) {
+ startAnimationLocked();
+ }
+}
+
} // namespace android
diff --git a/libs/input/PointerControllerContext.h b/libs/input/PointerControllerContext.h
index 92e1bda25f56..98073fea323e 100644
--- a/libs/input/PointerControllerContext.h
+++ b/libs/input/PointerControllerContext.h
@@ -26,6 +26,7 @@
#include <utils/Looper.h>
#include <utils/RefBase.h>
+#include <functional>
#include <map>
#include <memory>
#include <vector>
@@ -35,6 +36,8 @@
namespace android {
class PointerController;
+class MouseCursorController;
+class TouchSpotController;
/*
* Pointer resources.
@@ -96,7 +99,6 @@ public:
void startAnimation();
void setInactivityTimeout(InactivityTimeout inactivityTimeout);
- void setAnimationPending(bool animationPending);
nsecs_t getAnimationTime();
void clearSpotsByDisplay(int32_t displayId);
@@ -107,9 +109,11 @@ public:
sp<PointerControllerPolicyInterface> getPolicy();
sp<SpriteController> getSpriteController();
- void initializeDisplayEventReceiver();
void handleDisplayEvents();
+ void addAnimationCallback(int32_t displayId, std::function<bool(nsecs_t)> callback);
+ void removeAnimationCallback(int32_t displayId);
+
class MessageHandler : public virtual android::MessageHandler {
public:
enum {
@@ -127,22 +131,47 @@ public:
};
private:
+ class PointerAnimator {
+ public:
+ PointerAnimator(PointerControllerContext& context);
+
+ void addCallback(int32_t displayId, std::function<bool(nsecs_t)> callback);
+ void removeCallback(int32_t displayId);
+ void handleVsyncEvents();
+ nsecs_t getAnimationTimeLocked();
+
+ mutable std::mutex mLock;
+
+ private:
+ struct Locked {
+ bool animationPending{false};
+ nsecs_t animationTime{systemTime(SYSTEM_TIME_MONOTONIC)};
+
+ std::unordered_map<int32_t, std::function<bool(nsecs_t)>> callbacks;
+ } mLocked GUARDED_BY(mLock);
+
+ DisplayEventReceiver mDisplayEventReceiver;
+
+ PointerControllerContext& mContext;
+
+ void initializeDisplayEventReceiver();
+ void startAnimationLocked();
+ void handleCallbacksLocked(nsecs_t timestamp);
+ };
+
sp<PointerControllerPolicyInterface> mPolicy;
sp<Looper> mLooper;
sp<SpriteController> mSpriteController;
sp<MessageHandler> mHandler;
sp<LooperCallback> mCallback;
- DisplayEventReceiver mDisplayEventReceiver;
-
PointerController& mController;
+ PointerAnimator mAnimator;
+
mutable std::mutex mLock;
struct Locked {
- bool animationPending;
- nsecs_t animationTime;
-
InactivityTimeout inactivityTimeout;
} mLocked GUARDED_BY(mLock);
diff --git a/libs/input/TouchSpotController.cpp b/libs/input/TouchSpotController.cpp
index c7430ceead41..f7c685ff8ba6 100644
--- a/libs/input/TouchSpotController.cpp
+++ b/libs/input/TouchSpotController.cpp
@@ -142,7 +142,8 @@ TouchSpotController::Spot* TouchSpotController::getSpot(uint32_t id,
}
TouchSpotController::Spot* TouchSpotController::createAndAddSpotLocked(uint32_t id,
- std::vector<Spot*>& spots) {
+ std::vector<Spot*>& spots)
+ REQUIRES(mLock) {
// Remove spots until we have fewer than MAX_SPOTS remaining.
while (spots.size() >= MAX_SPOTS) {
Spot* spot = removeFirstFadingSpotLocked(spots);
@@ -186,14 +187,13 @@ void TouchSpotController::releaseSpotLocked(Spot* spot) REQUIRES(mLock) {
if (mLocked.recycledSprites.size() < MAX_RECYCLED_SPRITES) {
mLocked.recycledSprites.push_back(spot->sprite);
}
-
delete spot;
}
void TouchSpotController::fadeOutAndReleaseSpotLocked(Spot* spot) REQUIRES(mLock) {
if (spot->id != Spot::INVALID_ID) {
spot->id = Spot::INVALID_ID;
- mContext.startAnimation();
+ startAnimationLocked();
}
}
@@ -209,8 +209,24 @@ void TouchSpotController::reloadSpotResources() {
mContext.getPolicy()->loadPointerResources(&mResources, mDisplayId);
}
-bool TouchSpotController::doFadingAnimation(nsecs_t timestamp, bool keepAnimating) {
+bool TouchSpotController::doAnimations(nsecs_t timestamp) {
std::scoped_lock lock(mLock);
+ bool keepAnimating = doFadingAnimationLocked(timestamp);
+ if (!keepAnimating) {
+ /*
+ * We know that this callback will be removed before another
+ * is added. mLock in PointerAnimator will not be released
+ * until after this is removed, and adding another callback
+ * requires that lock. Thus it's safe to set mLocked.animating
+ * here.
+ */
+ mLocked.animating = false;
+ }
+ return keepAnimating;
+}
+
+bool TouchSpotController::doFadingAnimationLocked(nsecs_t timestamp) REQUIRES(mLock) {
+ bool keepAnimating = false;
nsecs_t animationTime = mContext.getAnimationTime();
nsecs_t frameDelay = timestamp - animationTime;
size_t numSpots = mLocked.displaySpots.size();
@@ -233,4 +249,16 @@ bool TouchSpotController::doFadingAnimation(nsecs_t timestamp, bool keepAnimatin
return keepAnimating;
}
+void TouchSpotController::startAnimationLocked() REQUIRES(mLock) {
+ using namespace std::placeholders;
+
+ if (mLocked.animating) {
+ return;
+ }
+ mLocked.animating = true;
+
+ std::function<bool(nsecs_t)> func = std::bind(&TouchSpotController::doAnimations, this, _1);
+ mContext.addAnimationCallback(mDisplayId, func);
+}
+
} // namespace android
diff --git a/libs/input/TouchSpotController.h b/libs/input/TouchSpotController.h
index f3b355010bee..703de3603f48 100644
--- a/libs/input/TouchSpotController.h
+++ b/libs/input/TouchSpotController.h
@@ -17,6 +17,8 @@
#ifndef _UI_TOUCH_SPOT_CONTROLLER_H
#define _UI_TOUCH_SPOT_CONTROLLER_H
+#include <functional>
+
#include "PointerControllerContext.h"
namespace android {
@@ -34,7 +36,7 @@ public:
void clearSpots();
void reloadSpotResources();
- bool doFadingAnimation(nsecs_t timestamp, bool keepAnimating);
+ bool doAnimations(nsecs_t timestamp);
private:
struct Spot {
@@ -76,6 +78,8 @@ private:
std::vector<Spot*> displaySpots;
std::vector<sp<Sprite>> recycledSprites;
+ bool animating{false};
+
} mLocked GUARDED_BY(mLock);
Spot* getSpot(uint32_t id, const std::vector<Spot*>& spots);
@@ -84,6 +88,8 @@ private:
void releaseSpotLocked(Spot* spot);
void fadeOutAndReleaseSpotLocked(Spot* spot);
void fadeOutAndReleaseAllSpotsLocked();
+ bool doFadingAnimationLocked(nsecs_t timestamp);
+ void startAnimationLocked();
};
} // namespace android
diff --git a/location/java/android/location/LocationManager.java b/location/java/android/location/LocationManager.java
index 1803027743f6..6fc702e4a068 100644
--- a/location/java/android/location/LocationManager.java
+++ b/location/java/android/location/LocationManager.java
@@ -29,6 +29,8 @@ import android.annotation.NonNull;
import android.annotation.Nullable;
import android.annotation.RequiresFeature;
import android.annotation.RequiresPermission;
+import android.annotation.SdkConstant;
+import android.annotation.SdkConstant.SdkConstantType;
import android.annotation.SystemApi;
import android.annotation.SystemService;
import android.annotation.TestApi;
@@ -215,6 +217,7 @@ public class LocationManager {
* @see #EXTRA_PROVIDER_ENABLED
* @see #isProviderEnabled(String)
*/
+ @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
public static final String PROVIDERS_CHANGED_ACTION = "android.location.PROVIDERS_CHANGED";
/**
@@ -243,6 +246,7 @@ public class LocationManager {
* @see #EXTRA_LOCATION_ENABLED
* @see #isLocationEnabled()
*/
+ @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
public static final String MODE_CHANGED_ACTION = "android.location.MODE_CHANGED";
/**
diff --git a/media/java/android/media/AudioDeviceAttributes.java b/media/java/android/media/AudioDeviceAttributes.java
index 0ab62c14ab9f..5096bf616a1f 100644
--- a/media/java/android/media/AudioDeviceAttributes.java
+++ b/media/java/android/media/AudioDeviceAttributes.java
@@ -72,6 +72,11 @@ public final class AudioDeviceAttributes implements Parcelable {
private final @Role int mRole;
/**
+ * The internal audio device type
+ */
+ private final int mNativeType;
+
+ /**
* @hide
* Constructor from a valid {@link AudioDeviceInfo}
* @param deviceInfo the connected audio device from which to obtain the device-identifying
@@ -83,6 +88,7 @@ public final class AudioDeviceAttributes implements Parcelable {
mRole = deviceInfo.isSink() ? ROLE_OUTPUT : ROLE_INPUT;
mType = deviceInfo.getType();
mAddress = deviceInfo.getAddress();
+ mNativeType = deviceInfo.getPort().type();
}
/**
@@ -109,12 +115,14 @@ public final class AudioDeviceAttributes implements Parcelable {
mRole = role;
mType = type;
mAddress = address;
+ mNativeType = AudioSystem.DEVICE_NONE;
}
/*package*/ AudioDeviceAttributes(int nativeType, @NonNull String address) {
mRole = (nativeType & AudioSystem.DEVICE_BIT_IN) != 0 ? ROLE_INPUT : ROLE_OUTPUT;
mType = AudioDeviceInfo.convertInternalDeviceToDeviceType(nativeType);
mAddress = address;
+ mNativeType = nativeType;
}
/**
@@ -147,6 +155,15 @@ public final class AudioDeviceAttributes implements Parcelable {
return mAddress;
}
+ /**
+ * @hide
+ * Returns the internal device type of a device
+ * @return the internal device type
+ */
+ public int getInternalType() {
+ return mNativeType;
+ }
+
@Override
public int hashCode() {
return Objects.hash(mRole, mType, mAddress);
@@ -189,12 +206,14 @@ public final class AudioDeviceAttributes implements Parcelable {
dest.writeInt(mRole);
dest.writeInt(mType);
dest.writeString(mAddress);
+ dest.writeInt(mNativeType);
}
private AudioDeviceAttributes(@NonNull Parcel in) {
mRole = in.readInt();
mType = in.readInt();
mAddress = in.readString();
+ mNativeType = in.readInt();
}
public static final @NonNull Parcelable.Creator<AudioDeviceAttributes> CREATOR =
diff --git a/media/java/android/media/AudioDeviceInfo.java b/media/java/android/media/AudioDeviceInfo.java
index d4fb1be56890..ba880cc58888 100644
--- a/media/java/android/media/AudioDeviceInfo.java
+++ b/media/java/android/media/AudioDeviceInfo.java
@@ -513,10 +513,21 @@ public final class AudioDeviceInfo {
return INT_TO_EXT_DEVICE_MAPPING.get(intDevice, TYPE_UNKNOWN);
}
+ /** @hide */
+ public static int convertDeviceTypeToInternalInputDevice(int deviceType) {
+ return EXT_TO_INT_INPUT_DEVICE_MAPPING.get(deviceType, AudioSystem.DEVICE_NONE);
+ }
+
private static final SparseIntArray INT_TO_EXT_DEVICE_MAPPING;
private static final SparseIntArray EXT_TO_INT_DEVICE_MAPPING;
+ /**
+ * EXT_TO_INT_INPUT_DEVICE_MAPPING aims at mapping external device type to internal input device
+ * type.
+ */
+ private static final SparseIntArray EXT_TO_INT_INPUT_DEVICE_MAPPING;
+
static {
INT_TO_EXT_DEVICE_MAPPING = new SparseIntArray();
INT_TO_EXT_DEVICE_MAPPING.put(AudioSystem.DEVICE_OUT_EARPIECE, TYPE_BUILTIN_EARPIECE);
@@ -601,6 +612,32 @@ public final class AudioDeviceInfo {
EXT_TO_INT_DEVICE_MAPPING.put(TYPE_REMOTE_SUBMIX, AudioSystem.DEVICE_OUT_REMOTE_SUBMIX);
EXT_TO_INT_DEVICE_MAPPING.put(TYPE_BLE_HEADSET, AudioSystem.DEVICE_OUT_BLE_HEADSET);
EXT_TO_INT_DEVICE_MAPPING.put(TYPE_BLE_SPEAKER, AudioSystem.DEVICE_OUT_BLE_SPEAKER);
+
+ // privileges mapping to input device
+ EXT_TO_INT_INPUT_DEVICE_MAPPING = new SparseIntArray();
+ EXT_TO_INT_INPUT_DEVICE_MAPPING.put(TYPE_BUILTIN_MIC, AudioSystem.DEVICE_IN_BUILTIN_MIC);
+ EXT_TO_INT_INPUT_DEVICE_MAPPING.put(
+ TYPE_BLUETOOTH_SCO, AudioSystem.DEVICE_IN_BLUETOOTH_SCO_HEADSET);
+ EXT_TO_INT_INPUT_DEVICE_MAPPING.put(
+ TYPE_WIRED_HEADSET, AudioSystem.DEVICE_IN_WIRED_HEADSET);
+ EXT_TO_INT_INPUT_DEVICE_MAPPING.put(TYPE_HDMI, AudioSystem.DEVICE_IN_HDMI);
+ EXT_TO_INT_INPUT_DEVICE_MAPPING.put(TYPE_TELEPHONY, AudioSystem.DEVICE_IN_TELEPHONY_RX);
+ EXT_TO_INT_INPUT_DEVICE_MAPPING.put(TYPE_DOCK, AudioSystem.DEVICE_IN_ANLG_DOCK_HEADSET);
+ EXT_TO_INT_INPUT_DEVICE_MAPPING.put(
+ TYPE_USB_ACCESSORY, AudioSystem.DEVICE_IN_USB_ACCESSORY);
+ EXT_TO_INT_INPUT_DEVICE_MAPPING.put(TYPE_USB_DEVICE, AudioSystem.DEVICE_IN_USB_DEVICE);
+ EXT_TO_INT_INPUT_DEVICE_MAPPING.put(TYPE_USB_HEADSET, AudioSystem.DEVICE_IN_USB_HEADSET);
+ EXT_TO_INT_INPUT_DEVICE_MAPPING.put(TYPE_FM_TUNER, AudioSystem.DEVICE_IN_FM_TUNER);
+ EXT_TO_INT_INPUT_DEVICE_MAPPING.put(TYPE_TV_TUNER, AudioSystem.DEVICE_IN_TV_TUNER);
+ EXT_TO_INT_INPUT_DEVICE_MAPPING.put(TYPE_LINE_ANALOG, AudioSystem.DEVICE_IN_LINE);
+ EXT_TO_INT_INPUT_DEVICE_MAPPING.put(TYPE_LINE_DIGITAL, AudioSystem.DEVICE_IN_SPDIF);
+ EXT_TO_INT_INPUT_DEVICE_MAPPING.put(
+ TYPE_BLUETOOTH_A2DP, AudioSystem.DEVICE_IN_BLUETOOTH_A2DP);
+ EXT_TO_INT_INPUT_DEVICE_MAPPING.put(TYPE_IP, AudioSystem.DEVICE_IN_IP);
+ EXT_TO_INT_INPUT_DEVICE_MAPPING.put(TYPE_BUS, AudioSystem.DEVICE_IN_BUS);
+ EXT_TO_INT_INPUT_DEVICE_MAPPING.put(
+ TYPE_REMOTE_SUBMIX, AudioSystem.DEVICE_IN_REMOTE_SUBMIX);
+ EXT_TO_INT_INPUT_DEVICE_MAPPING.put(TYPE_BLE_HEADSET, AudioSystem.DEVICE_IN_BLE_HEADSET);
}
}
diff --git a/media/java/android/media/AudioManager.java b/media/java/android/media/AudioManager.java
index a16e063fe969..aa2ff17a307b 100755
--- a/media/java/android/media/AudioManager.java
+++ b/media/java/android/media/AudioManager.java
@@ -1949,6 +1949,349 @@ public class AudioManager {
}
//====================================================================
+ // Audio Capture Preset routing
+
+ /**
+ * @hide
+ * Set the preferred device for a given capture preset, i.e. the audio routing to be used by
+ * this capture preset. Note that the device may not be available at the time the preferred
+ * device is set, but it will be used once made available.
+ * <p>Use {@link #clearPreferredDevicesForCapturePreset(int)} to cancel setting this preference
+ * for this capture preset.</p>
+ * @param capturePreset the audio capture preset whose routing will be affected
+ * @param device the audio device to route to when available
+ * @return true if the operation was successful, false otherwise
+ */
+ @SystemApi
+ @RequiresPermission(android.Manifest.permission.MODIFY_AUDIO_ROUTING)
+ public boolean setPreferredDeviceForCapturePreset(int capturePreset,
+ @NonNull AudioDeviceAttributes device) {
+ return setPreferredDevicesForCapturePreset(capturePreset, Arrays.asList(device));
+ }
+
+ /**
+ * @hide
+ * Remove all the preferred audio devices previously set
+ * @param capturePreset the audio capture preset whose routing will be affected
+ * @return true if the operation was successful, false otherwise (invalid capture preset, or no
+ * device set for example)
+ */
+ @SystemApi
+ @RequiresPermission(android.Manifest.permission.MODIFY_AUDIO_ROUTING)
+ public boolean clearPreferredDevicesForCapturePreset(int capturePreset) {
+ if (!MediaRecorder.isValidAudioSource(capturePreset)) {
+ return false;
+ }
+ try {
+ final int status = getService().clearPreferredDevicesForCapturePreset(capturePreset);
+ return status == AudioSystem.SUCCESS;
+ } catch (RemoteException e) {
+ throw e.rethrowFromSystemServer();
+ }
+ }
+
+ /**
+ * @hide
+ * Return the preferred devices for an audio capture preset, previously set with
+ * {@link #setPreferredDeviceForCapturePreset(int, AudioDeviceAttributes)}
+ * @param capturePreset the capture preset to query
+ * @return a list that contains preferred devices for that capture preset.
+ */
+ @NonNull
+ @SystemApi
+ @RequiresPermission(android.Manifest.permission.MODIFY_AUDIO_ROUTING)
+ public List<AudioDeviceAttributes> getPreferredDevicesForCapturePreset(int capturePreset) {
+ if (!MediaRecorder.isValidAudioSource(capturePreset)) {
+ return new ArrayList<AudioDeviceAttributes>();
+ }
+ try {
+ return getService().getPreferredDevicesForCapturePreset(capturePreset);
+ } catch (RemoteException e) {
+ throw e.rethrowFromSystemServer();
+ }
+ }
+
+ private boolean setPreferredDevicesForCapturePreset(
+ int capturePreset, @NonNull List<AudioDeviceAttributes> devices) {
+ Objects.requireNonNull(devices);
+ if (!MediaRecorder.isValidAudioSource(capturePreset)) {
+ return false;
+ }
+ if (devices.size() != 1) {
+ throw new IllegalArgumentException(
+ "Only support setting one preferred devices for capture preset");
+ }
+ for (AudioDeviceAttributes device : devices) {
+ Objects.requireNonNull(device);
+ }
+ try {
+ final int status =
+ getService().setPreferredDevicesForCapturePreset(capturePreset, devices);
+ return status == AudioSystem.SUCCESS;
+ } catch (RemoteException e) {
+ throw e.rethrowFromSystemServer();
+ }
+ }
+
+ /**
+ * @hide
+ * Interface to be notified of changes in the preferred audio devices set for a given capture
+ * preset.
+ * <p>Note that this listener will only be invoked whenever
+ * {@link #setPreferredDeviceForCapturePreset(int, AudioDeviceAttributes)} or
+ * {@link #clearPreferredDevicesForCapturePreset(int)} causes a change in
+ * preferred device. It will not be invoked directly after registration with
+ * {@link #addOnPreferredDevicesForCapturePresetChangedListener(
+ * Executor, OnPreferredDevicesForCapturePresetChangedListener)}
+ * to indicate which strategies had preferred devices at the time of registration.</p>
+ * @see #setPreferredDeviceForCapturePreset(int, AudioDeviceAttributes)
+ * @see #clearPreferredDevicesForCapturePreset(int)
+ * @see #getPreferredDevicesForCapturePreset(int)
+ */
+ @SystemApi
+ public interface OnPreferredDevicesForCapturePresetChangedListener {
+ /**
+ * Called on the listener to indicate that the preferred audio devices for the given
+ * capture preset has changed.
+ * @param capturePreset the capture preset whose preferred device changed
+ * @param devices a list of newly set preferred audio devices
+ */
+ void onPreferredDevicesForCapturePresetChanged(
+ int capturePreset, @NonNull List<AudioDeviceAttributes> devices);
+ }
+
+ /**
+ * @hide
+ * Adds a listener for being notified of changes to the capture-preset-preferred audio device.
+ * @param executor
+ * @param listener
+ * @throws SecurityException if the caller doesn't hold the required permission
+ */
+ @SystemApi
+ @RequiresPermission(android.Manifest.permission.MODIFY_AUDIO_ROUTING)
+ public void addOnPreferredDevicesForCapturePresetChangedListener(
+ @NonNull @CallbackExecutor Executor executor,
+ @NonNull OnPreferredDevicesForCapturePresetChangedListener listener)
+ throws SecurityException {
+ Objects.requireNonNull(executor);
+ Objects.requireNonNull(listener);
+ int status = addOnDevRoleForCapturePresetChangedListener(
+ executor, listener, AudioSystem.DEVICE_ROLE_PREFERRED);
+ if (status == AudioSystem.ERROR) {
+ // This must not happen
+ throw new RuntimeException("Unknown error happened");
+ }
+ if (status == AudioSystem.BAD_VALUE) {
+ throw new IllegalArgumentException(
+ "attempt to call addOnPreferredDevicesForCapturePresetChangedListener() "
+ + "on a previously registered listener");
+ }
+ }
+
+ /**
+ * @hide
+ * Removes a previously added listener of changes to the capture-preset-preferred audio device.
+ * @param listener
+ */
+ @SystemApi
+ @RequiresPermission(android.Manifest.permission.MODIFY_AUDIO_ROUTING)
+ public void removeOnPreferredDevicesForCapturePresetChangedListener(
+ @NonNull OnPreferredDevicesForCapturePresetChangedListener listener) {
+ Objects.requireNonNull(listener);
+ int status = removeOnDevRoleForCapturePresetChangedListener(
+ listener, AudioSystem.DEVICE_ROLE_PREFERRED);
+ if (status == AudioSystem.ERROR) {
+ // This must not happen
+ throw new RuntimeException("Unknown error happened");
+ }
+ if (status == AudioSystem.BAD_VALUE) {
+ throw new IllegalArgumentException(
+ "attempt to call removeOnPreferredDevicesForCapturePresetChangedListener() "
+ + "on an unregistered listener");
+ }
+ }
+
+ private <T> int addOnDevRoleForCapturePresetChangedListener(
+ @NonNull @CallbackExecutor Executor executor,
+ @NonNull T listener, int deviceRole) {
+ Objects.requireNonNull(executor);
+ Objects.requireNonNull(listener);
+ DevRoleListeners<T> devRoleListeners =
+ (DevRoleListeners<T>) mDevRoleForCapturePresetListeners.get(deviceRole);
+ if (devRoleListeners == null) {
+ return AudioSystem.ERROR;
+ }
+ synchronized (devRoleListeners.mDevRoleListenersLock) {
+ if (devRoleListeners.hasDevRoleListener(listener)) {
+ return AudioSystem.BAD_VALUE;
+ }
+ // lazy initialization of the list of device role listener
+ if (devRoleListeners.mListenerInfos == null) {
+ devRoleListeners.mListenerInfos = new ArrayList<>();
+ }
+ final int oldCbCount = devRoleListeners.mListenerInfos.size();
+ devRoleListeners.mListenerInfos.add(new DevRoleListenerInfo<T>(executor, listener));
+ if (oldCbCount == 0 && devRoleListeners.mListenerInfos.size() > 0) {
+ // register binder for callbacks
+ synchronized (mDevRoleForCapturePresetListenersLock) {
+ int deviceRoleListenerStatus = mDeviceRoleListenersStatus;
+ mDeviceRoleListenersStatus |= (1 << deviceRole);
+ if (deviceRoleListenerStatus != 0) {
+ // There are already device role changed listeners active.
+ return AudioSystem.SUCCESS;
+ }
+ if (mDevicesRoleForCapturePresetDispatcherStub == null) {
+ mDevicesRoleForCapturePresetDispatcherStub =
+ new CapturePresetDevicesRoleDispatcherStub();
+ }
+ try {
+ getService().registerCapturePresetDevicesRoleDispatcher(
+ mDevicesRoleForCapturePresetDispatcherStub);
+ } catch (RemoteException e) {
+ throw e.rethrowFromSystemServer();
+ }
+ }
+ }
+ }
+ return AudioSystem.SUCCESS;
+ }
+
+ private <T> int removeOnDevRoleForCapturePresetChangedListener(
+ @NonNull T listener, int deviceRole) {
+ Objects.requireNonNull(listener);
+ DevRoleListeners<T> devRoleListeners =
+ (DevRoleListeners<T>) mDevRoleForCapturePresetListeners.get(deviceRole);
+ if (devRoleListeners == null) {
+ return AudioSystem.ERROR;
+ }
+ synchronized (devRoleListeners.mDevRoleListenersLock) {
+ if (!devRoleListeners.removeDevRoleListener(listener)) {
+ return AudioSystem.BAD_VALUE;
+ }
+ if (devRoleListeners.mListenerInfos.size() == 0) {
+ // unregister binder for callbacks
+ synchronized (mDevRoleForCapturePresetListenersLock) {
+ mDeviceRoleListenersStatus ^= (1 << deviceRole);
+ if (mDeviceRoleListenersStatus != 0) {
+ // There are some other device role changed listeners active.
+ return AudioSystem.SUCCESS;
+ }
+ try {
+ getService().unregisterCapturePresetDevicesRoleDispatcher(
+ mDevicesRoleForCapturePresetDispatcherStub);
+ } catch (RemoteException e) {
+ throw e.rethrowFromSystemServer();
+ }
+ }
+ }
+ }
+ return AudioSystem.SUCCESS;
+ }
+
+ private final Map<Integer, Object> mDevRoleForCapturePresetListeners = new HashMap<>(){{
+ put(AudioSystem.DEVICE_ROLE_PREFERRED,
+ new DevRoleListeners<OnPreferredDevicesForCapturePresetChangedListener>());
+ }};
+
+ private class DevRoleListenerInfo<T> {
+ final @NonNull Executor mExecutor;
+ final @NonNull T mListener;
+ DevRoleListenerInfo(Executor executor, T listener) {
+ mExecutor = executor;
+ mListener = listener;
+ }
+ }
+
+ private class DevRoleListeners<T> {
+ private final Object mDevRoleListenersLock = new Object();
+ @GuardedBy("mDevRoleListenersLock")
+ private @Nullable ArrayList<DevRoleListenerInfo<T>> mListenerInfos;
+
+ @GuardedBy("mDevRoleListenersLock")
+ private @Nullable DevRoleListenerInfo<T> getDevRoleListenerInfo(T listener) {
+ if (mListenerInfos == null) {
+ return null;
+ }
+ for (DevRoleListenerInfo<T> listenerInfo : mListenerInfos) {
+ if (listenerInfo.mListener == listener) {
+ return listenerInfo;
+ }
+ }
+ return null;
+ }
+
+ @GuardedBy("mDevRoleListenersLock")
+ private boolean hasDevRoleListener(T listener) {
+ return getDevRoleListenerInfo(listener) != null;
+ }
+
+ @GuardedBy("mDevRoleListenersLock")
+ private boolean removeDevRoleListener(T listener) {
+ final DevRoleListenerInfo<T> infoToRemove = getDevRoleListenerInfo(listener);
+ if (infoToRemove != null) {
+ mListenerInfos.remove(infoToRemove);
+ return true;
+ }
+ return false;
+ }
+ }
+
+ private final Object mDevRoleForCapturePresetListenersLock = new Object();
+ /**
+ * Record if there is a listener added for device role change. If there is a listener added for
+ * a specified device role change, the bit at position `1 << device_role` is set.
+ */
+ @GuardedBy("mDevRoleForCapturePresetListenersLock")
+ private int mDeviceRoleListenersStatus = 0;
+ @GuardedBy("mDevRoleForCapturePresetListenersLock")
+ private CapturePresetDevicesRoleDispatcherStub mDevicesRoleForCapturePresetDispatcherStub;
+
+ private final class CapturePresetDevicesRoleDispatcherStub
+ extends ICapturePresetDevicesRoleDispatcher.Stub {
+
+ @Override
+ public void dispatchDevicesRoleChanged(
+ int capturePreset, int role, List<AudioDeviceAttributes> devices) {
+ final Object listenersObj = mDevRoleForCapturePresetListeners.get(role);
+ if (listenersObj == null) {
+ return;
+ }
+ switch (role) {
+ case AudioSystem.DEVICE_ROLE_PREFERRED: {
+ final DevRoleListeners<OnPreferredDevicesForCapturePresetChangedListener>
+ listeners =
+ (DevRoleListeners<OnPreferredDevicesForCapturePresetChangedListener>)
+ listenersObj;
+ final ArrayList<DevRoleListenerInfo<
+ OnPreferredDevicesForCapturePresetChangedListener>> prefDevListeners;
+ synchronized (listeners.mDevRoleListenersLock) {
+ if (listeners.mListenerInfos.isEmpty()) {
+ return;
+ }
+ prefDevListeners = (ArrayList<DevRoleListenerInfo<
+ OnPreferredDevicesForCapturePresetChangedListener>>)
+ listeners.mListenerInfos.clone();
+ }
+ final long ident = Binder.clearCallingIdentity();
+ try {
+ for (DevRoleListenerInfo<
+ OnPreferredDevicesForCapturePresetChangedListener> info :
+ prefDevListeners) {
+ info.mExecutor.execute(() ->
+ info.mListener.onPreferredDevicesForCapturePresetChanged(
+ capturePreset, devices));
+ }
+ } finally {
+ Binder.restoreCallingIdentity(ident);
+ }
+ } break;
+ default:
+ break;
+ }
+ }
+ }
+
+ //====================================================================
// Offload query
/**
* Returns whether offloaded playback of an audio format is supported on the device.
diff --git a/media/java/android/media/AudioSystem.java b/media/java/android/media/AudioSystem.java
index 243ec1f1fcd0..279ba0a55be0 100644
--- a/media/java/android/media/AudioSystem.java
+++ b/media/java/android/media/AudioSystem.java
@@ -27,6 +27,7 @@ import android.media.audiofx.AudioEffect;
import android.media.audiopolicy.AudioMix;
import android.telephony.TelephonyManager;
import android.util.Log;
+import android.util.Pair;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
@@ -524,6 +525,7 @@ public class AudioSystem
/** @hide Media server died. see ErrorCallback */
public static final int AUDIO_STATUS_SERVER_DIED = 100;
+ // all accesses must be synchronized (AudioSystem.class)
private static ErrorCallback sErrorCallback;
/** @hide
@@ -560,11 +562,9 @@ public class AudioSystem
@UnsupportedAppUsage
private static void errorCallbackFromNative(int error)
{
- ErrorCallback errorCallback = null;
+ ErrorCallback errorCallback;
synchronized (AudioSystem.class) {
- if (sErrorCallback != null) {
- errorCallback = sErrorCallback;
- }
+ errorCallback = sErrorCallback;
}
if (errorCallback != null) {
errorCallback.onError(error);
@@ -584,6 +584,7 @@ public class AudioSystem
//keep in sync with include/media/AudioPolicy.h
private final static int DYNAMIC_POLICY_EVENT_MIX_STATE_UPDATE = 0;
+ // all accesses must be synchronized (AudioSystem.class)
private static DynamicPolicyCallback sDynPolicyCallback;
/** @hide */
@@ -598,11 +599,9 @@ public class AudioSystem
@UnsupportedAppUsage
private static void dynamicPolicyCallbackFromNative(int event, String regId, int val)
{
- DynamicPolicyCallback cb = null;
+ DynamicPolicyCallback cb;
synchronized (AudioSystem.class) {
- if (sDynPolicyCallback != null) {
- cb = sDynPolicyCallback;
- }
+ cb = sDynPolicyCallback;
}
if (cb != null) {
switch(event) {
@@ -646,6 +645,7 @@ public class AudioSystem
int activeSource, String packName);
}
+ // all accesses must be synchronized (AudioSystem.class)
private static AudioRecordingCallback sRecordingCallback;
/** @hide */
@@ -678,7 +678,7 @@ public class AudioSystem
int source, int portId, boolean silenced, int[] recordingFormat,
AudioEffect.Descriptor[] clientEffects, AudioEffect.Descriptor[] effects,
int activeSource) {
- AudioRecordingCallback cb = null;
+ AudioRecordingCallback cb;
synchronized (AudioSystem.class) {
cb = sRecordingCallback;
}
@@ -1756,6 +1756,134 @@ public class AudioSystem
public static native int getDevicesForRoleAndStrategy(
int strategy, int role, @NonNull List<AudioDeviceAttributes> devices);
+ // use case routing by capture preset
+
+ private static Pair<int[], String[]> populateInputDevicesTypeAndAddress(
+ @NonNull List<AudioDeviceAttributes> devices) {
+ int[] types = new int[devices.size()];
+ String[] addresses = new String[devices.size()];
+ for (int i = 0; i < devices.size(); ++i) {
+ types[i] = devices.get(i).getInternalType();
+ if (types[i] == AudioSystem.DEVICE_NONE) {
+ types[i] = AudioDeviceInfo.convertDeviceTypeToInternalInputDevice(
+ devices.get(i).getType());
+ }
+ addresses[i] = devices.get(i).getAddress();
+ }
+ return new Pair<int[], String[]>(types, addresses);
+ }
+
+ /**
+ * @hide
+ * Set devices as role for capture preset.
+ * @param capturePreset the capture preset to configure
+ * @param role the role of the devices
+ * @param devices the list of devices to be set as role for the given capture preset
+ * @return {@link #SUCCESS} if successfully set
+ */
+ public static int setDevicesRoleForCapturePreset(
+ int capturePreset, int role, @NonNull List<AudioDeviceAttributes> devices) {
+ if (devices.isEmpty()) {
+ return BAD_VALUE;
+ }
+ Pair<int[], String[]> typeAddresses = populateInputDevicesTypeAndAddress(devices);
+ return setDevicesRoleForCapturePreset(
+ capturePreset, role, typeAddresses.first, typeAddresses.second);
+ }
+
+ /**
+ * @hide
+ * Set devices as role for capture preset.
+ * @param capturePreset the capture preset to configure
+ * @param role the role of the devices
+ * @param types all device types
+ * @param addresses all device addresses
+ * @return {@link #SUCCESS} if successfully set
+ */
+ private static native int setDevicesRoleForCapturePreset(
+ int capturePreset, int role, @NonNull int[] types, @NonNull String[] addresses);
+
+ /**
+ * @hide
+ * Add devices as role for capture preset.
+ * @param capturePreset the capture preset to configure
+ * @param role the role of the devices
+ * @param devices the list of devices to be added as role for the given capture preset
+ * @return {@link #SUCCESS} if successfully add
+ */
+ public static int addDevicesRoleForCapturePreset(
+ int capturePreset, int role, @NonNull List<AudioDeviceAttributes> devices) {
+ if (devices.isEmpty()) {
+ return BAD_VALUE;
+ }
+ Pair<int[], String[]> typeAddresses = populateInputDevicesTypeAndAddress(devices);
+ return addDevicesRoleForCapturePreset(
+ capturePreset, role, typeAddresses.first, typeAddresses.second);
+ }
+
+ /**
+ * @hide
+ * Add devices as role for capture preset.
+ * @param capturePreset the capture preset to configure
+ * @param role the role of the devices
+ * @param types all device types
+ * @param addresses all device addresses
+ * @return {@link #SUCCESS} if successfully set
+ */
+ private static native int addDevicesRoleForCapturePreset(
+ int capturePreset, int role, @NonNull int[] types, @NonNull String[] addresses);
+
+ /**
+ * @hide
+ * Remove devices as role for the capture preset
+ * @param capturePreset the capture preset to configure
+ * @param role the role of the devices
+ * @param devices the devices to be removed
+ * @return {@link #SUCCESS} if successfully removed
+ */
+ public static int removeDevicesRoleForCapturePreset(
+ int capturePreset, int role, @NonNull List<AudioDeviceAttributes> devices) {
+ if (devices.isEmpty()) {
+ return BAD_VALUE;
+ }
+ Pair<int[], String[]> typeAddresses = populateInputDevicesTypeAndAddress(devices);
+ return removeDevicesRoleForCapturePreset(
+ capturePreset, role, typeAddresses.first, typeAddresses.second);
+ }
+
+ /**
+ * @hide
+ * Remove devices as role for capture preset.
+ * @param capturePreset the capture preset to configure
+ * @param role the role of the devices
+ * @param types all device types
+ * @param addresses all device addresses
+ * @return {@link #SUCCESS} if successfully set
+ */
+ private static native int removeDevicesRoleForCapturePreset(
+ int capturePreset, int role, @NonNull int[] types, @NonNull String[] addresses);
+
+ /**
+ * @hide
+ * Remove all devices as role for the capture preset
+ * @param capturePreset the capture preset to configure
+ * @param role the role of the devices
+ * @return {@link #SUCCESS} if successfully removed
+ */
+ public static native int clearDevicesRoleForCapturePreset(int capturePreset, int role);
+
+ /**
+ * @hide
+ * Query previously set devices as role for a capture preset
+ * @param capturePreset the capture preset to query for
+ * @param role the role of the devices
+ * @param devices a list that will contain the devices of role
+ * @return {@link #SUCCESS} if there is a preferred device and it was successfully retrieved
+ * and written to the array
+ */
+ public static native int getDevicesForRoleAndCapturePreset(
+ int capturePreset, int role, @NonNull List<AudioDeviceAttributes> devices);
+
// Items shared with audio service
/**
diff --git a/media/java/android/media/AudioTrack.java b/media/java/android/media/AudioTrack.java
index 1c0a526f536c..de2a7b2c15e3 100644
--- a/media/java/android/media/AudioTrack.java
+++ b/media/java/android/media/AudioTrack.java
@@ -807,7 +807,8 @@ public class AudioTrack extends PlayerBase
int initResult = native_setup(new WeakReference<AudioTrack>(this), mAttributes,
sampleRate, mChannelMask, mChannelIndexMask, mAudioFormat,
mNativeBufferSizeInBytes, mDataLoadMode, session, 0 /*nativeTrackInJavaObj*/,
- offload, encapsulationMode, tunerConfiguration);
+ offload, encapsulationMode, tunerConfiguration,
+ getCurrentOpPackageName());
if (initResult != SUCCESS) {
loge("Error code "+initResult+" when initializing AudioTrack.");
return; // with mState == STATE_UNINITIALIZED
@@ -893,7 +894,8 @@ public class AudioTrack extends PlayerBase
nativeTrackInJavaObj,
false /*offload*/,
ENCAPSULATION_MODE_NONE,
- null /* tunerConfiguration */);
+ null /* tunerConfiguration */,
+ "" /* opPackagename */);
if (initResult != SUCCESS) {
loge("Error code "+initResult+" when initializing AudioTrack.");
return; // with mState == STATE_UNINITIALIZED
@@ -4062,7 +4064,8 @@ public class AudioTrack extends PlayerBase
Object /*AudioAttributes*/ attributes,
int[] sampleRate, int channelMask, int channelIndexMask, int audioFormat,
int buffSizeInBytes, int mode, int[] sessionId, long nativeAudioTrack,
- boolean offload, int encapsulationMode, Object tunerConfiguration);
+ boolean offload, int encapsulationMode, Object tunerConfiguration,
+ @NonNull String opPackageName);
private native final void native_finalize();
diff --git a/media/java/android/media/IAudioService.aidl b/media/java/android/media/IAudioService.aidl
index ef8b0edb1fe5..85fb67df82d4 100755
--- a/media/java/android/media/IAudioService.aidl
+++ b/media/java/android/media/IAudioService.aidl
@@ -26,6 +26,7 @@ import android.media.AudioRoutesInfo;
import android.media.IAudioFocusDispatcher;
import android.media.IAudioRoutesObserver;
import android.media.IAudioServerStateDispatcher;
+import android.media.ICapturePresetDevicesRoleDispatcher;
import android.media.IPlaybackConfigDispatcher;
import android.media.IRecordingConfigDispatcher;
import android.media.IRingtonePlayer;
@@ -307,4 +308,16 @@ interface IAudioService {
// code via IAudioManager.h need to be added to the top section.
oneway void setMultiAudioFocusEnabled(in boolean enabled);
+
+ int setPreferredDevicesForCapturePreset(
+ in int capturePreset, in List<AudioDeviceAttributes> devices);
+
+ int clearPreferredDevicesForCapturePreset(in int capturePreset);
+
+ List<AudioDeviceAttributes> getPreferredDevicesForCapturePreset(in int capturePreset);
+
+ void registerCapturePresetDevicesRoleDispatcher(ICapturePresetDevicesRoleDispatcher dispatcher);
+
+ oneway void unregisterCapturePresetDevicesRoleDispatcher(
+ ICapturePresetDevicesRoleDispatcher dispatcher);
}
diff --git a/media/java/android/media/ICapturePresetDevicesRoleDispatcher.aidl b/media/java/android/media/ICapturePresetDevicesRoleDispatcher.aidl
new file mode 100644
index 000000000000..5e03e632c4ff
--- /dev/null
+++ b/media/java/android/media/ICapturePresetDevicesRoleDispatcher.aidl
@@ -0,0 +1,31 @@
+/*
+ * 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.media;
+
+import android.media.AudioDeviceAttributes;
+
+/**
+ * AIDL for AudioService to signal devices role for capture preset updates.
+ *
+ * {@hide}
+ */
+oneway interface ICapturePresetDevicesRoleDispatcher {
+
+ void dispatchDevicesRoleChanged(
+ int capturePreset, int role, in List<AudioDeviceAttributes> devices);
+
+}
diff --git a/media/java/android/media/MediaPlayer.java b/media/java/android/media/MediaPlayer.java
index 49e416080041..36ae3ec75a99 100644
--- a/media/java/android/media/MediaPlayer.java
+++ b/media/java/android/media/MediaPlayer.java
@@ -672,7 +672,8 @@ public class MediaPlayer extends PlayerBase
/* Native setup requires a weak reference to our object.
* It's easier to create it here than in C++.
*/
- native_setup(new WeakReference<MediaPlayer>(this));
+ native_setup(new WeakReference<MediaPlayer>(this),
+ getCurrentOpPackageName());
baseRegisterPlayer();
}
@@ -2378,7 +2379,7 @@ public class MediaPlayer extends PlayerBase
private native final int native_setMetadataFilter(Parcel request);
private static native final void native_init();
- private native final void native_setup(Object mediaplayer_this);
+ private native void native_setup(Object mediaplayerThis, @NonNull String opPackageName);
private native final void native_finalize();
/**
diff --git a/media/java/android/media/MediaRecorder.java b/media/java/android/media/MediaRecorder.java
index 4198d7917932..1db02beaea1a 100644
--- a/media/java/android/media/MediaRecorder.java
+++ b/media/java/android/media/MediaRecorder.java
@@ -404,6 +404,32 @@ public class MediaRecorder implements AudioRouting,
}
}
+ /**
+ * @hide
+ * @param source An audio source to test
+ * @return true if the source is a valid one
+ */
+ public static boolean isValidAudioSource(int source) {
+ switch(source) {
+ case AudioSource.MIC:
+ case AudioSource.VOICE_UPLINK:
+ case AudioSource.VOICE_DOWNLINK:
+ case AudioSource.VOICE_CALL:
+ case AudioSource.CAMCORDER:
+ case AudioSource.VOICE_RECOGNITION:
+ case AudioSource.VOICE_COMMUNICATION:
+ case AudioSource.REMOTE_SUBMIX:
+ case AudioSource.UNPROCESSED:
+ case AudioSource.VOICE_PERFORMANCE:
+ case AudioSource.ECHO_REFERENCE:
+ case AudioSource.RADIO_TUNER:
+ case AudioSource.HOTWORD:
+ return true;
+ default:
+ return false;
+ }
+ }
+
/** @hide */
public static final String toLogFriendlyAudioSource(int source) {
switch(source) {
diff --git a/media/java/android/media/MediaTranscodeManager.java b/media/java/android/media/MediaTranscodeManager.java
index e1bff03f6833..cf61152c4775 100644
--- a/media/java/android/media/MediaTranscodeManager.java
+++ b/media/java/android/media/MediaTranscodeManager.java
@@ -18,8 +18,11 @@ package android.media;
import android.annotation.CallbackExecutor;
import android.annotation.IntDef;
+import android.annotation.IntRange;
import android.annotation.NonNull;
import android.annotation.Nullable;
+import android.annotation.SystemApi;
+import android.annotation.TestApi;
import android.content.ContentResolver;
import android.content.Context;
import android.content.res.AssetFileDescriptor;
@@ -36,7 +39,10 @@ import com.android.internal.annotations.VisibleForTesting;
import java.io.FileNotFoundException;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
+import java.util.ArrayList;
import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
import java.util.Objects;
import java.util.concurrent.Executor;
import java.util.concurrent.ExecutorService;
@@ -94,11 +100,19 @@ import java.util.concurrent.Executors;
TODO(hkuang): Clarify whether supports framerate conversion.
@hide
*/
-public final class MediaTranscodeManager {
+@TestApi
+@SystemApi
+public final class MediaTranscodeManager implements AutoCloseable {
private static final String TAG = "MediaTranscodeManager";
private static final String MEDIA_TRANSCODING_SERVICE = "media.transcoding";
+ /** Maximum number of retry to connect to the service. */
+ private static final int CONNECT_SERVICE_RETRY_COUNT = 100;
+
+ /** Interval between trying to reconnect to the service. */
+ private static final int INTERVAL_CONNECT_SERVICE_RETRY_MS = 40;
+
/**
* Default transcoding type.
* @hide
@@ -117,6 +131,28 @@ public final class MediaTranscodeManager {
*/
public static final int TRANSCODING_TYPE_IMAGE = 2;
+ @Override
+ public void close() {
+ release();
+ }
+
+ /**
+ * Releases the MediaTranscodeManager.
+ */
+ private void release() {
+ synchronized (mLock) {
+ try {
+ if (mTranscodingClient != null) {
+ mTranscodingClient.unregister();
+ }
+ } catch (Exception ex) {
+ Log.e(TAG, "Failed to unregister the client");
+ } finally {
+ mTranscodingClient = null;
+ }
+ }
+ }
+
/** @hide */
@IntDef(prefix = {"TRANSCODING_TYPE_"}, value = {
TRANSCODING_TYPE_UNKNOWN,
@@ -181,10 +217,12 @@ public final class MediaTranscodeManager {
private final String mPackageName;
private final int mPid;
private final int mUid;
- private final ExecutorService mCallbackExecutor = Executors.newSingleThreadExecutor();
- private static MediaTranscodeManager sMediaTranscodeManager;
+ private final ExecutorService mExecutor = Executors.newSingleThreadExecutor();
private final HashMap<Integer, TranscodingJob> mPendingTranscodingJobs = new HashMap();
- @NonNull private ITranscodingClient mTranscodingClient;
+ private final Object mLock = new Object();
+ @GuardedBy("mLock")
+ @NonNull private ITranscodingClient mTranscodingClient = null;
+ private static MediaTranscodeManager sMediaTranscodeManager;
private void handleTranscodingFinished(int jobId, TranscodingResultParcel result) {
synchronized (mPendingTranscodingJobs) {
@@ -209,7 +247,7 @@ public final class MediaTranscodeManager {
}
}
- private void handleTranscodingFailed(int jobId, int errorCodec) {
+ private void handleTranscodingFailed(int jobId, int errorCode) {
synchronized (mPendingTranscodingJobs) {
// Gets the job associated with the jobId and removes it from
// mPendingTranscodingJobs.
@@ -254,6 +292,98 @@ public final class MediaTranscodeManager {
}
}
+ private static IMediaTranscodingService getService(boolean retry) {
+ int retryCount = !retry ? 1 : CONNECT_SERVICE_RETRY_COUNT;
+ Log.i(TAG, "get service with rety " + retryCount);
+ for (int count = 1; count <= retryCount; count++) {
+ Log.d(TAG, "Trying to connect to service. Try count: " + count);
+ IMediaTranscodingService service = IMediaTranscodingService.Stub.asInterface(
+ ServiceManager.getService(MEDIA_TRANSCODING_SERVICE));
+ if (service != null) {
+ return service;
+ }
+ try {
+ // Sleep a bit before retry.
+ Thread.sleep(INTERVAL_CONNECT_SERVICE_RETRY_MS);
+ } catch (InterruptedException ie) {
+ /* ignore */
+ }
+ }
+
+ throw new UnsupportedOperationException("Failed to connect to MediaTranscoding service");
+ }
+
+ /*
+ * Handle client binder died event.
+ * Upon receiving a binder died event of the client, we will do the following:
+ * 1) For the job that is running, notify the client that the job is failed with error code,
+ * so client could choose to retry the job or not.
+ * TODO(hkuang): Add a new error code to signal service died error.
+ * 2) For the jobs that is still pending or paused, we will resubmit the job internally once
+ * we successfully reconnect to the service and register a new client.
+ * 3) When trying to connect to the service and register a new client. The service may need time
+ * to reboot or never boot up again. So we will retry for a number of times. If we still
+ * could not connect, we will notify client job failure for the pending and paused jobs.
+ */
+ private void onClientDied() {
+ synchronized (mLock) {
+ mTranscodingClient = null;
+ }
+
+ // Delegates the job notification and retry to the executor as it may take some time.
+ mExecutor.execute(() -> {
+ // List to track the jobs that we want to retry.
+ List<TranscodingJob> retryJobs = new ArrayList<TranscodingJob>();
+
+ // First notify the client of job failure for all the running jobs.
+ synchronized (mPendingTranscodingJobs) {
+ for (Map.Entry<Integer, TranscodingJob> entry :
+ mPendingTranscodingJobs.entrySet()) {
+ TranscodingJob job = entry.getValue();
+
+ if (job.getStatus() == TranscodingJob.STATUS_RUNNING) {
+ job.updateStatusAndResult(TranscodingJob.STATUS_FINISHED,
+ TranscodingJob.RESULT_ERROR);
+
+ // Remove the job from pending jobs.
+ mPendingTranscodingJobs.remove(entry.getKey());
+
+ if (job.mListener != null && job.mListenerExecutor != null) {
+ Log.i(TAG, "Notify client job failed");
+ job.mListenerExecutor.execute(
+ () -> job.mListener.onTranscodingFinished(job));
+ }
+ } else if (job.getStatus() == TranscodingJob.STATUS_PENDING
+ || job.getStatus() == TranscodingJob.STATUS_PAUSED) {
+ // Add the job to retryJobs to handle them later.
+ retryJobs.add(job);
+ }
+ }
+ }
+
+ // Try to register with the service once it boots up.
+ IMediaTranscodingService service = getService(true /*retry*/);
+ boolean haveTranscodingClient = false;
+ if (service != null) {
+ synchronized (mLock) {
+ mTranscodingClient = registerClient(service);
+ if (mTranscodingClient != null) {
+ haveTranscodingClient = true;
+ }
+ }
+ }
+
+ for (TranscodingJob job : retryJobs) {
+ // Notify the job failure if we fails to connect to the service or fail
+ // to retry the job.
+ if (!haveTranscodingClient || !job.retry()) {
+ // TODO(hkuang): Return correct error code to the client.
+ handleTranscodingFailed(job.getJobId(), 0 /*unused */);
+ }
+ }
+ });
+ }
+
private void updateStatus(int jobId, int status) {
synchronized (mPendingTranscodingJobs) {
final TranscodingJob job = mPendingTranscodingJobs.get(jobId);
@@ -336,29 +466,47 @@ public final class MediaTranscodeManager {
}
};
- /* Private constructor. */
- private MediaTranscodeManager(@NonNull Context context,
- IMediaTranscodingService transcodingService) {
+ private ITranscodingClient registerClient(IMediaTranscodingService service)
+ throws UnsupportedOperationException {
+ synchronized (mLock) {
+ try {
+ // Registers the client with MediaTranscoding service.
+ mTranscodingClient = service.registerClient(
+ mTranscodingClientCallback,
+ mPackageName,
+ mPackageName,
+ IMediaTranscodingService.USE_CALLING_UID,
+ IMediaTranscodingService.USE_CALLING_PID);
+
+ if (mTranscodingClient != null) {
+ mTranscodingClient.asBinder().linkToDeath(() -> onClientDied(), /* flags */ 0);
+ }
+ return mTranscodingClient;
+ } catch (RemoteException re) {
+ Log.e(TAG, "Failed to register new client due to exception " + re);
+ mTranscodingClient = null;
+ }
+ }
+ throw new UnsupportedOperationException("Failed to register new client");
+ }
+
+ /**
+ * @hide
+ */
+ public MediaTranscodeManager(@NonNull Context context) {
mContext = context;
mContentResolver = mContext.getContentResolver();
mPackageName = mContext.getPackageName();
mPid = Os.getuid();
mUid = Os.getpid();
-
- try {
- // Registers the client with MediaTranscoding service.
- mTranscodingClient = transcodingService.registerClient(
- mTranscodingClientCallback,
- mPackageName,
- mPackageName,
- IMediaTranscodingService.USE_CALLING_UID,
- IMediaTranscodingService.USE_CALLING_PID);
- } catch (RemoteException re) {
- Log.e(TAG, "Failed to register new client due to exception " + re);
- throw new UnsupportedOperationException("Failed to register new client");
- }
+ IMediaTranscodingService service = getService(false /*retry*/);
+ mTranscodingClient = registerClient(service);
}
+ @Override
+ protected void finalize() {
+ release();
+ }
public static final class TranscodingRequest {
/** Uri of the source media file. */
@@ -413,25 +561,25 @@ public final class MediaTranscodeManager {
/** Return the type of the transcoding. */
@TranscodingType
- int getType() {
+ public int getType() {
return mType;
}
/** Return source uri of the transcoding. */
@NonNull
- Uri getSourceUri() {
+ public Uri getSourceUri() {
return mSourceUri;
}
/** Return destination uri of the transcoding. */
@NonNull
- Uri getDestinationUri() {
+ public Uri getDestinationUri() {
return mDestinationUri;
}
/** Return priority of the transcoding. */
@TranscodingPriority
- int getPriority() {
+ public int getPriority() {
return mPriority;
}
@@ -439,10 +587,20 @@ public final class MediaTranscodeManager {
* Return the video track format of the transcoding.
* This will be null is the transcoding is not for video transcoding.
*/
- MediaFormat getVideoTrackFormat() {
+ @Nullable
+ public MediaFormat getVideoTrackFormat() {
return mVideoTrackFormat;
}
+ /**
+ * Return TestConfig of the transcoding.
+ * @hide
+ */
+ @Nullable
+ public TranscodingTestConfig getTestConfig() {
+ return mTestConfig;
+ }
+
/* Writes the TranscodingRequest to a parcel. */
private TranscodingRequestParcel writeToParcel() {
TranscodingRequestParcel parcel = new TranscodingRequestParcel();
@@ -523,7 +681,7 @@ public final class MediaTranscodeManager {
* Builder class for {@link TranscodingRequest} objects.
* Use this class to configure and create a <code>TranscodingRequest</code> instance.
*/
- public static class Builder {
+ public static final class Builder {
private @NonNull Uri mSourceUri;
private @NonNull Uri mDestinationUri;
private @TranscodingType int mType = TRANSCODING_TYPE_UNKNOWN;
@@ -542,7 +700,7 @@ public final class MediaTranscodeManager {
*/
// TODO(hkuang): Add documentation on how the app could generate the correct Uri.
@NonNull
- public Builder setSourceUri(@NonNull Uri sourceUri) throws IllegalArgumentException {
+ public Builder setSourceUri(@NonNull Uri sourceUri) {
if (sourceUri == null || Uri.EMPTY.equals(sourceUri)) {
throw new IllegalArgumentException(
"You must specify a non-empty source Uri.");
@@ -559,8 +717,7 @@ public final class MediaTranscodeManager {
* @throws IllegalArgumentException if Uri is null or empty.
*/
@NonNull
- public Builder setDestinationUri(@NonNull Uri destinationUri)
- throws IllegalArgumentException {
+ public Builder setDestinationUri(@NonNull Uri destinationUri) {
if (destinationUri == null || Uri.EMPTY.equals(destinationUri)) {
throw new IllegalArgumentException(
"You must specify a non-empty destination Uri.");
@@ -577,8 +734,7 @@ public final class MediaTranscodeManager {
* @throws IllegalArgumentException if flags is invalid.
*/
@NonNull
- public Builder setPriority(@TranscodingPriority int priority)
- throws IllegalArgumentException {
+ public Builder setPriority(@TranscodingPriority int priority) {
if (priority != PRIORITY_OFFLINE && priority != PRIORITY_REALTIME) {
throw new IllegalArgumentException("Invalid priority: " + priority);
}
@@ -596,8 +752,7 @@ public final class MediaTranscodeManager {
* @throws IllegalArgumentException if flags is invalid.
*/
@NonNull
- public Builder setType(@TranscodingType int type)
- throws IllegalArgumentException {
+ public Builder setType(@TranscodingType int type) {
if (type != TRANSCODING_TYPE_VIDEO && type != TRANSCODING_TYPE_IMAGE) {
throw new IllegalArgumentException("Invalid transcoding type");
}
@@ -621,8 +776,7 @@ public final class MediaTranscodeManager {
* @throws IllegalArgumentException if videoFormat is invalid.
*/
@NonNull
- public Builder setVideoTrackFormat(@NonNull MediaFormat videoFormat)
- throws IllegalArgumentException {
+ public Builder setVideoTrackFormat(@NonNull MediaFormat videoFormat) {
if (videoFormat == null) {
throw new IllegalArgumentException("videoFormat must not be null");
}
@@ -642,9 +796,11 @@ public final class MediaTranscodeManager {
* Sets the delay in processing this request.
* @param config test config.
* @return The same builder instance.
+ * @hide
*/
@VisibleForTesting
- public Builder setTestConfig(TranscodingTestConfig config) {
+ @NonNull
+ public Builder setTestConfig(@NonNull TranscodingTestConfig config) {
mTestConfig = config;
return this;
}
@@ -657,7 +813,7 @@ public final class MediaTranscodeManager {
* device.
*/
@NonNull
- public TranscodingRequest build() throws UnsupportedOperationException {
+ public TranscodingRequest build() {
if (mSourceUri == null) {
throw new UnsupportedOperationException("Source URI must not be null");
}
@@ -701,6 +857,7 @@ public final class MediaTranscodeManager {
/** The job is paused. */
public static final int STATUS_PAUSED = 4;
+ /** @hide */
@IntDef(prefix = { "STATUS_" }, value = {
STATUS_PENDING,
STATUS_RUNNING,
@@ -719,6 +876,7 @@ public final class MediaTranscodeManager {
/** The job was canceled by the caller. */
public static final int RESULT_CANCELED = 4;
+ /** @hide */
@IntDef(prefix = { "RESULT_" }, value = {
RESULT_NONE,
RESULT_SUCCESS,
@@ -736,24 +894,26 @@ public final class MediaTranscodeManager {
* where 0 means that the job has not yet started and 100 means that it has finished.
* @param progress The new progress ranging from 0 ~ 100 inclusive.
*/
- void onProgressUpdate(int progress);
+ void onProgressUpdate(@IntRange(from = 0, to = 100) int progress);
}
private final ITranscodingClient mJobOwner;
private final Executor mListenerExecutor;
private final OnTranscodingFinishedListener mListener;
private int mJobId = -1;
- @GuardedBy("this")
+ // Lock for internal state.
+ private final Object mLock = new Object();
+ @GuardedBy("mLock")
private Executor mProgressUpdateExecutor = null;
- @GuardedBy("this")
+ @GuardedBy("mLock")
private OnProgressUpdateListener mProgressUpdateListener = null;
- @GuardedBy("this")
+ @GuardedBy("mLock")
private int mProgress = 0;
- @GuardedBy("this")
+ @GuardedBy("mLock")
private int mProgressUpdateInterval = 0;
- @GuardedBy("this")
+ @GuardedBy("mLock")
private @Status int mStatus = STATUS_PENDING;
- @GuardedBy("this")
+ @GuardedBy("mLock")
private @Result int mResult = RESULT_NONE;
private TranscodingJob(
@@ -790,20 +950,36 @@ public final class MediaTranscodeManager {
* @param executor The executor on which listener will be invoked.
* @param listener The progress listener.
*/
- public synchronized void setOnProgressUpdateListener(
+ public void setOnProgressUpdateListener(
int minProgressUpdateInterval,
@NonNull @CallbackExecutor Executor executor,
@Nullable OnProgressUpdateListener listener) {
- Objects.requireNonNull(executor, "listenerExecutor must not be null");
- Objects.requireNonNull(listener, "listener must not be null");
- mProgressUpdateExecutor = executor;
- mProgressUpdateListener = listener;
+ synchronized (mLock) {
+ Objects.requireNonNull(executor, "listenerExecutor must not be null");
+ Objects.requireNonNull(listener, "listener must not be null");
+ mProgressUpdateExecutor = executor;
+ mProgressUpdateListener = listener;
+ }
}
- private synchronized void updateStatusAndResult(@Status int jobStatus,
+ private void updateStatusAndResult(@Status int jobStatus,
@Result int jobResult) {
- mStatus = jobStatus;
- mResult = jobResult;
+ synchronized (mLock) {
+ mStatus = jobStatus;
+ mResult = jobResult;
+ }
+ }
+
+ /**
+ * Resubmit the transcoding job to the service.
+ *
+ * @return true if successfully resubmit the job to the service. False otherwise.
+ */
+ public boolean retry() {
+ synchronized (mLock) {
+ // TODO(hkuang): Implement this.
+ }
+ return true;
}
/**
@@ -811,38 +987,46 @@ public final class MediaTranscodeManager {
* If the job happened to finish before being canceled this call is effectively a no-op and
* will not update the result in that case.
*/
- public synchronized void cancel() {
- // Check if the job is finished already.
- if (mStatus != STATUS_FINISHED) {
- try {
- mJobOwner.cancelJob(mJobId);
- } catch (RemoteException re) {
- //TODO(hkuang): Find out what to do if failing to cancel the job.
- Log.e(TAG, "Failed to cancel the job due to exception: " + re);
- }
- mStatus = STATUS_FINISHED;
- mResult = RESULT_CANCELED;
+ public void cancel() {
+ synchronized (mLock) {
+ // Check if the job is finished already.
+ if (mStatus != STATUS_FINISHED) {
+ try {
+ mJobOwner.cancelJob(mJobId);
+ } catch (RemoteException re) {
+ //TODO(hkuang): Find out what to do if failing to cancel the job.
+ Log.e(TAG, "Failed to cancel the job due to exception: " + re);
+ }
+ mStatus = STATUS_FINISHED;
+ mResult = RESULT_CANCELED;
- // Notifies client the job is canceled.
- mListenerExecutor.execute(() -> mListener.onTranscodingFinished(this));
+ // Notifies client the job is canceled.
+ mListenerExecutor.execute(() -> mListener.onTranscodingFinished(this));
+ }
}
}
/**
- * Gets the progress of the transcoding job. The progress is between 0 and 1, where 0 means
- * that the job has not yet started and 1 means that it is finished.
+ * Gets the progress of the transcoding job. The progress is between 0 and 100, where 0
+ * means that the job has not yet started and 100 means that it is finished. For the
+ * cancelled job, the progress will be the last updated progress before it is cancelled.
* @return The progress.
*/
- public synchronized int getProgress() {
- return mProgress;
+ @IntRange(from = 0, to = 100)
+ public int getProgress() {
+ synchronized (mLock) {
+ return mProgress;
+ }
}
/**
* Gets the status of the transcoding job.
* @return The status.
*/
- public synchronized @Status int getStatus() {
- return mStatus;
+ public @Status int getStatus() {
+ synchronized (mLock) {
+ return mStatus;
+ }
}
/**
@@ -857,46 +1041,22 @@ public final class MediaTranscodeManager {
* Gets the result of the transcoding job.
* @return The result.
*/
- public synchronized @Result int getResult() {
- return mResult;
- }
-
- private synchronized void updateProgress(int newProgress) {
- mProgress = newProgress;
+ public @Result int getResult() {
+ synchronized (mLock) {
+ return mResult;
+ }
}
- private synchronized void updateStatus(int newStatus) {
- mStatus = newStatus;
+ private void updateProgress(int newProgress) {
+ synchronized (mLock) {
+ mProgress = newProgress;
+ }
}
- }
-
- /**
- * Gets the MediaTranscodeManager singleton instance.
- *
- * @param context The application context.
- * @return the {@link MediaTranscodeManager} singleton instance.
- * @throws UnsupportedOperationException if failing to acquire the MediaTranscodeManager.
- */
- public static MediaTranscodeManager getInstance(@NonNull Context context) {
- // Acquires the MediaTranscoding service.
- IMediaTranscodingService service = IMediaTranscodingService.Stub.asInterface(
- ServiceManager.getService(MEDIA_TRANSCODING_SERVICE));
- return getInstance(context, service);
- }
-
- /** Similar as above, but allow injecting transcodingService for testing. */
- @VisibleForTesting
- public static MediaTranscodeManager getInstance(@NonNull Context context,
- IMediaTranscodingService transcodingService) {
- Objects.requireNonNull(context, "context must not be null");
-
- synchronized (MediaTranscodeManager.class) {
- if (sMediaTranscodeManager == null) {
- sMediaTranscodeManager = new MediaTranscodeManager(context.getApplicationContext(),
- transcodingService);
+ private void updateStatus(int newStatus) {
+ synchronized (mLock) {
+ mStatus = newStatus;
}
- return sMediaTranscodeManager;
}
}
@@ -918,7 +1078,7 @@ public final class MediaTranscodeManager {
@NonNull TranscodingRequest transcodingRequest,
@NonNull @CallbackExecutor Executor listenerExecutor,
@NonNull OnTranscodingFinishedListener listener)
- throws UnsupportedOperationException, FileNotFoundException {
+ throws FileNotFoundException {
Log.i(TAG, "enqueueRequest called.");
Objects.requireNonNull(transcodingRequest, "transcodingRequest must not be null");
Objects.requireNonNull(listenerExecutor, "listenerExecutor must not be null");
@@ -933,8 +1093,14 @@ public final class MediaTranscodeManager {
// Synchronizes the access to mPendingTranscodingJobs to make sure the job Id is
// inserted in the mPendingTranscodingJobs in the callback handler.
synchronized (mPendingTranscodingJobs) {
- if (!mTranscodingClient.submitRequest(requestParcel, jobParcel)) {
- throw new UnsupportedOperationException("Failed to enqueue request");
+ synchronized (mLock) {
+ if (mTranscodingClient == null) {
+ // TODO(hkuang): Handle the case if client is temporarily unavailable.
+ }
+
+ if (!mTranscodingClient.submitRequest(requestParcel, jobParcel)) {
+ throw new UnsupportedOperationException("Failed to enqueue request");
+ }
}
// Wraps the TranscodingJobParcel into a TranscodingJob and returns it to client for
diff --git a/media/java/android/media/PlayerBase.java b/media/java/android/media/PlayerBase.java
index ee8f1b3eec77..df5e85edbc30 100644
--- a/media/java/android/media/PlayerBase.java
+++ b/media/java/android/media/PlayerBase.java
@@ -27,6 +27,7 @@ import android.os.Parcelable;
import android.os.Process;
import android.os.RemoteException;
import android.os.ServiceManager;
+import android.text.TextUtils;
import android.util.Log;
import com.android.internal.annotations.GuardedBy;
@@ -622,4 +623,8 @@ public abstract class PlayerBase {
Log.w(className, "See the documentation of " + opName + " for what to use instead with " +
"android.media.AudioAttributes to qualify your playback use case");
}
+
+ protected String getCurrentOpPackageName() {
+ return TextUtils.emptyIfNull(ActivityThread.currentOpPackageName());
+ }
}
diff --git a/media/java/android/media/session/MediaSession.java b/media/java/android/media/session/MediaSession.java
index 6c41f7bcd0bc..549e79353133 100644
--- a/media/java/android/media/session/MediaSession.java
+++ b/media/java/android/media/session/MediaSession.java
@@ -103,6 +103,8 @@ public final class MediaSession {
* System only flag for a session that needs to have priority over all other
* sessions. This flag ensures this session will receive media button events
* regardless of the current ordering in the system.
+ * If there are two or more sessions with this flag, the last session that sets this flag
+ * will be the global priority session.
*
* @hide
*/
diff --git a/media/jni/Android.bp b/media/jni/Android.bp
index 7518496287a8..1e9cf2c24c7c 100644
--- a/media/jni/Android.bp
+++ b/media/jni/Android.bp
@@ -166,26 +166,3 @@ cc_library_shared {
],
}
-cc_library_shared {
- name: "libmediatranscodemanager_jni",
- srcs: [
- "android_media_MediaTranscodeManager.cpp",
- ],
-
- shared_libs: [
- "libandroid_runtime",
- "libcutils",
- "liblog",
- "libmedia",
- ],
-
- export_include_dirs: ["."],
-
- cflags: [
- "-Wall",
- "-Werror",
- "-Wno-error=deprecated-declarations",
- "-Wunused",
- "-Wunreachable-code",
- ],
-}
diff --git a/media/jni/android_media_MediaPlayer.cpp b/media/jni/android_media_MediaPlayer.cpp
index 55aac09b0f65..bd8d2e9f77a4 100644
--- a/media/jni/android_media_MediaPlayer.cpp
+++ b/media/jni/android_media_MediaPlayer.cpp
@@ -33,6 +33,7 @@
#include <utils/threads.h>
#include "jni.h"
#include <nativehelper/JNIPlatformHelp.h>
+#include <nativehelper/ScopedUtfChars.h>
#include "android_runtime/AndroidRuntime.h"
#include "android_runtime/android_view_Surface.h"
#include "android_runtime/Log.h"
@@ -944,10 +945,12 @@ android_media_MediaPlayer_native_init(JNIEnv *env)
}
static void
-android_media_MediaPlayer_native_setup(JNIEnv *env, jobject thiz, jobject weak_this)
+android_media_MediaPlayer_native_setup(JNIEnv *env, jobject thiz, jobject weak_this,
+ jstring opPackageName)
{
ALOGV("native_setup");
- sp<MediaPlayer> mp = new MediaPlayer();
+ ScopedUtfChars opPackageNameStr(env, opPackageName);
+ sp<MediaPlayer> mp = new MediaPlayer(opPackageNameStr.c_str());
if (mp == NULL) {
jniThrowException(env, "java/lang/RuntimeException", "Out of memory");
return;
@@ -1403,7 +1406,7 @@ static const JNINativeMethod gMethods[] = {
{"native_setMetadataFilter", "(Landroid/os/Parcel;)I", (void *)android_media_MediaPlayer_setMetadataFilter},
{"native_getMetadata", "(ZZLandroid/os/Parcel;)Z", (void *)android_media_MediaPlayer_getMetadata},
{"native_init", "()V", (void *)android_media_MediaPlayer_native_init},
- {"native_setup", "(Ljava/lang/Object;)V", (void *)android_media_MediaPlayer_native_setup},
+ {"native_setup", "(Ljava/lang/Object;Ljava/lang/String;)V",(void *)android_media_MediaPlayer_native_setup},
{"native_finalize", "()V", (void *)android_media_MediaPlayer_native_finalize},
{"getAudioSessionId", "()I", (void *)android_media_MediaPlayer_get_audio_session_id},
{"setAudioSessionId", "(I)V", (void *)android_media_MediaPlayer_set_audio_session_id},
diff --git a/media/jni/android_media_MediaTranscodeManager.cpp b/media/jni/android_media_MediaTranscodeManager.cpp
deleted file mode 100644
index 6695f8511116..000000000000
--- a/media/jni/android_media_MediaTranscodeManager.cpp
+++ /dev/null
@@ -1,125 +0,0 @@
-/*
- * Copyright 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.
- */
-//#define LOG_NDEBUG 0
-#define LOG_TAG "MediaTranscodeManager_JNI"
-
-#include "android_runtime/AndroidRuntime.h"
-#include "jni.h"
-
-#include <nativehelper/JNIHelp.h>
-#include <utils/Log.h>
-
-namespace {
-
-// NOTE: Keep these enums in sync with their equivalents in MediaTranscodeManager.java.
-enum {
- ID_INVALID = -1
-};
-
-enum {
- EVENT_JOB_STARTED = 1,
- EVENT_JOB_PROGRESSED = 2,
- EVENT_JOB_FINISHED = 3,
-};
-
-enum {
- RESULT_NONE = 1,
- RESULT_SUCCESS = 2,
- RESULT_ERROR = 3,
- RESULT_CANCELED = 4,
-};
-
-struct {
- jmethodID postEventFromNative;
-} gMediaTranscodeManagerClassInfo;
-
-using namespace android;
-
-void android_media_MediaTranscodeManager_native_init(JNIEnv *env, jclass clazz) {
- ALOGV("android_media_MediaTranscodeManager_native_init");
-
- gMediaTranscodeManagerClassInfo.postEventFromNative = env->GetMethodID(
- clazz, "postEventFromNative", "(IJI)V");
- LOG_ALWAYS_FATAL_IF(gMediaTranscodeManagerClassInfo.postEventFromNative == NULL,
- "can't find android/media/MediaTranscodeManager.postEventFromNative");
-}
-
-jlong android_media_MediaTranscodeManager_requestUniqueJobID(
- JNIEnv *env __unused, jobject thiz __unused) {
- ALOGV("android_media_MediaTranscodeManager_reserveUniqueJobID");
- static std::atomic_int32_t sJobIDCounter{0};
- jlong id = (jlong)++sJobIDCounter;
- return id;
-}
-
-jboolean android_media_MediaTranscodeManager_enqueueTranscodingRequest(
- JNIEnv *env, jobject thiz, jlong id, jobject request, jobject context __unused) {
- ALOGV("android_media_MediaTranscodeManager_enqueueTranscodingRequest");
- if (!request) {
- return ID_INVALID;
- }
-
- env->CallVoidMethod(thiz, gMediaTranscodeManagerClassInfo.postEventFromNative,
- EVENT_JOB_FINISHED, id, RESULT_ERROR);
- return true;
-}
-
-void android_media_MediaTranscodeManager_cancelTranscodingRequest(
- JNIEnv *env __unused, jobject thiz __unused, jlong jobID __unused) {
- ALOGV("android_media_MediaTranscodeManager_cancelTranscodingRequest");
-}
-
-const JNINativeMethod gMethods[] = {
- { "native_init", "()V",
- (void *)android_media_MediaTranscodeManager_native_init },
- { "native_requestUniqueJobID", "()J",
- (void *)android_media_MediaTranscodeManager_requestUniqueJobID },
- { "native_enqueueTranscodingRequest",
- "(JLandroid/media/MediaTranscodeManager$TranscodingRequest;Landroid/content/Context;)Z",
- (void *)android_media_MediaTranscodeManager_enqueueTranscodingRequest },
- { "native_cancelTranscodingRequest", "(J)V",
- (void *)android_media_MediaTranscodeManager_cancelTranscodingRequest },
-};
-
-} // namespace anonymous
-
-int register_android_media_MediaTranscodeManager(JNIEnv *env) {
- return AndroidRuntime::registerNativeMethods(env,
- "android/media/MediaTranscodeManager", gMethods, NELEM(gMethods));
-}
-
-jint JNI_OnLoad(JavaVM* vm, void* /* reserved */)
-{
- JNIEnv* env = NULL;
- jint result = -1;
-
- if (vm->GetEnv((void**) &env, JNI_VERSION_1_4) != JNI_OK) {
- ALOGE("ERROR: GetEnv failed\n");
- return result;
- }
- assert(env != NULL);
-
- if (register_android_media_MediaTranscodeManager(env) < 0) {
- ALOGE("ERROR: MediaTranscodeManager native registration failed");
- goto bail;
- }
-
- /* success -- return valid version number */
- result = JNI_VERSION_1_4;
-
-bail:
- return result;
-}
diff --git a/media/jni/android_media_tv_Tuner.cpp b/media/jni/android_media_tv_Tuner.cpp
index 5770c6797404..5db672993df1 100644
--- a/media/jni/android_media_tv_Tuner.cpp
+++ b/media/jni/android_media_tv_Tuner.cpp
@@ -2060,7 +2060,7 @@ static FrontendSettings getDvbcFrontendSettings(JNIEnv *env, const jobject& sett
env->GetIntField(settings, env->GetFieldID(clazz, "mModulation", "I")));
FrontendInnerFec innerFec =
static_cast<FrontendInnerFec>(
- env->GetLongField(settings, env->GetFieldID(clazz, "mFec", "J")));
+ env->GetLongField(settings, env->GetFieldID(clazz, "mInnerFec", "J")));
uint32_t symbolRate =
static_cast<uint32_t>(
env->GetIntField(settings, env->GetFieldID(clazz, "mSymbolRate", "I")));
@@ -2069,7 +2069,7 @@ static FrontendSettings getDvbcFrontendSettings(JNIEnv *env, const jobject& sett
env->GetIntField(settings, env->GetFieldID(clazz, "mOuterFec", "I")));
FrontendDvbcAnnex annex =
static_cast<FrontendDvbcAnnex>(
- env->GetByteField(settings, env->GetFieldID(clazz, "mAnnex", "B")));
+ env->GetIntField(settings, env->GetFieldID(clazz, "mAnnex", "I")));
FrontendDvbcSpectralInversion spectralInversion =
static_cast<FrontendDvbcSpectralInversion>(
env->GetIntField(
diff --git a/media/packages/BluetoothMidiService/Android.bp b/media/packages/BluetoothMidiService/Android.bp
index 48fc329276bd..25c34c3631dc 100644
--- a/media/packages/BluetoothMidiService/Android.bp
+++ b/media/packages/BluetoothMidiService/Android.bp
@@ -29,6 +29,5 @@ android_app {
"src/**/*.java",
],
platform_apis: true,
- certificate: "platform",
manifest: "AndroidManifest.xml",
}
diff --git a/media/packages/BluetoothMidiService/AndroidManifest.xml b/media/packages/BluetoothMidiService/AndroidManifest.xml
index b88bf2a0b2b7..fc96fd926e2d 100644
--- a/media/packages/BluetoothMidiService/AndroidManifest.xml
+++ b/media/packages/BluetoothMidiService/AndroidManifest.xml
@@ -19,8 +19,6 @@
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
package="com.android.bluetoothmidiservice"
- android:versionCode="1"
- android:versionName="R-initial"
>
<uses-sdk android:minSdkVersion="29" android:targetSdkVersion="29" />
diff --git a/media/packages/BluetoothMidiService/AndroidManifestBase.xml b/media/packages/BluetoothMidiService/AndroidManifestBase.xml
index ebe62b039434..bfb05469adb9 100644
--- a/media/packages/BluetoothMidiService/AndroidManifestBase.xml
+++ b/media/packages/BluetoothMidiService/AndroidManifestBase.xml
@@ -18,8 +18,6 @@
-->
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.android.bluetoothmidiservice"
- android:versionCode="1"
- android:versionName="R-initial"
>
<uses-sdk android:minSdkVersion="29" android:targetSdkVersion="29" />
<application
diff --git a/media/tests/MediaTranscodingTest/Android.bp b/media/tests/MediaTranscodingTest/Android.bp
index fcf8f11f6625..907c3c8b4933 100644
--- a/media/tests/MediaTranscodingTest/Android.bp
+++ b/media/tests/MediaTranscodingTest/Android.bp
@@ -8,6 +8,7 @@ android_test {
static_libs: [
"androidx.test.ext.junit",
"androidx.test.rules",
+ "androidx.test.uiautomator_uiautomator",
"android-support-test",
"testng"
],
diff --git a/media/tests/MediaTranscodingTest/build_and_run_unit_tests.sh b/media/tests/MediaTranscodingTest/build_and_run_unit_tests.sh
index 43db3530a16b..c8fb3a63fe2c 100644
--- a/media/tests/MediaTranscodingTest/build_and_run_unit_tests.sh
+++ b/media/tests/MediaTranscodingTest/build_and_run_unit_tests.sh
@@ -31,6 +31,9 @@ do
adb push --sync $file /data/user/0/com.android.mediatranscodingtest/cache/
done
-echo "[==========] running real transcoding tests"
+echo "[==========] running MediaTranscodeManagerTest"
adb shell am instrument -e class com.android.mediatranscodingtest.MediaTranscodeManagerTest -w com.android.mediatranscodingtest/.MediaTranscodingTestRunner
+echo "[==========] running MediaTranscodeManagerDiedTest"
+adb shell am instrument -e class com.android.mediatranscodingtest.MediaTranscodeManagerDiedTest -w com.android.mediatranscodingtest/.MediaTranscodingTestRunner
+
diff --git a/media/tests/MediaTranscodingTest/src/com/android/mediatranscodingtest/MediaTranscodeManagerDiedTest.java b/media/tests/MediaTranscodingTest/src/com/android/mediatranscodingtest/MediaTranscodeManagerDiedTest.java
new file mode 100644
index 000000000000..6ea573ea7d3c
--- /dev/null
+++ b/media/tests/MediaTranscodingTest/src/com/android/mediatranscodingtest/MediaTranscodeManagerDiedTest.java
@@ -0,0 +1,255 @@
+/*
+ * 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.mediatranscodingtest;
+
+import android.content.ContentResolver;
+import android.content.Context;
+import android.media.MediaFormat;
+import android.media.MediaTranscodeManager;
+import android.media.MediaTranscodeManager.TranscodingJob;
+import android.media.MediaTranscodeManager.TranscodingRequest;
+import android.net.Uri;
+import android.os.Bundle;
+import android.os.FileUtils;
+import android.os.ParcelFileDescriptor;
+import android.test.ActivityInstrumentationTestCase2;
+import android.util.Log;
+
+import androidx.test.InstrumentationRegistry;
+import androidx.test.uiautomator.UiDevice;
+
+import org.junit.Test;
+
+import java.io.BufferedReader;
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.InputStreamReader;
+import java.io.OutputStream;
+import java.util.concurrent.Executor;
+import java.util.concurrent.Executors;
+import java.util.concurrent.Semaphore;
+import java.util.concurrent.TimeUnit;
+import java.util.concurrent.atomic.AtomicInteger;
+
+/*
+ * Service died tests for MediaTranscodeManager in the media framework.
+ *
+ * To run this test suite:
+ make frameworks/base/media/tests/MediaTranscodingTest
+ make mediatranscodingtest
+
+ adb install -r testcases/mediatranscodingtest/arm64/mediatranscodingtest.apk
+
+ adb shell am instrument -e class \
+ com.android.mediatranscodingtest.MediaTranscodeManagerDiedTest \
+ -w com.android.mediatranscodingtest/.MediaTranscodingTestRunner
+ *
+ */
+public class MediaTranscodeManagerDiedTest
+ extends ActivityInstrumentationTestCase2<MediaTranscodingTest> {
+ private static final String TAG = "MediaTranscodeManagerDiedTest";
+ /** The time to wait for the transcode operation to complete before failing the test. */
+ private static final int TRANSCODE_TIMEOUT_SECONDS = 10;
+
+ /** Maximum number of retry to connect to the service. */
+ private static final int CONNECT_SERVICE_RETRY_COUNT = 100;
+
+ /** Interval between trying to reconnect to the service. */
+ private static final int INTERVAL_CONNECT_SERVICE_RETRY_MS = 40;
+
+ private Context mContext;
+ private MediaTranscodeManager mMediaTranscodeManager = null;
+ private Uri mSourceHEVCVideoUri = null;
+ private Uri mSourceAVCVideoUri = null;
+ private Uri mDestinationUri = null;
+
+ // Setting for transcoding to H.264.
+ private static final String MIME_TYPE = MediaFormat.MIMETYPE_VIDEO_AVC;
+ private static final int BIT_RATE = 20000000; // 20Mbps
+ private static final int WIDTH = 1920;
+ private static final int HEIGHT = 1080;
+
+ public MediaTranscodeManagerDiedTest() {
+ super("com.android.MediaTranscodeManagerTest", MediaTranscodingTest.class);
+ }
+
+ // Copy the resource to cache.
+ private Uri resourceToUri(Context context, int resId, String name) throws IOException {
+ Uri resUri = new Uri.Builder()
+ .scheme(ContentResolver.SCHEME_ANDROID_RESOURCE)
+ .authority(context.getResources().getResourcePackageName(resId))
+ .appendPath(context.getResources().getResourceTypeName(resId))
+ .appendPath(context.getResources().getResourceEntryName(resId))
+ .build();
+
+ Uri cacheUri = Uri.parse(ContentResolver.SCHEME_FILE + "://"
+ + mContext.getCacheDir().getAbsolutePath() + "/" + name);
+
+ InputStream is = mContext.getResources().openRawResource(resId);
+ OutputStream os = mContext.getContentResolver().openOutputStream(cacheUri);
+
+ FileUtils.copy(is, os);
+
+ return cacheUri;
+ }
+
+ private static Uri generateNewUri(Context context, String filename) {
+ File outFile = new File(context.getExternalCacheDir(), filename);
+ return Uri.fromFile(outFile);
+ }
+
+ /**
+ * Creates a MediaFormat with the basic set of values.
+ */
+ private static MediaFormat createMediaFormat() {
+ MediaFormat format = MediaFormat.createVideoFormat(MIME_TYPE, WIDTH, HEIGHT);
+ format.setInteger(MediaFormat.KEY_BIT_RATE, BIT_RATE);
+ return format;
+ }
+
+ private MediaTranscodeManager getManager() {
+ for (int count = 1; count <= CONNECT_SERVICE_RETRY_COUNT; count++) {
+ Log.d(TAG, "Trying to connect to service. Try count: " + count);
+ MediaTranscodeManager manager = mContext.getSystemService(MediaTranscodeManager.class);
+ if (manager != null) {
+ return manager;
+ }
+ try {
+ // Sleep a bit before retry.
+ Thread.sleep(INTERVAL_CONNECT_SERVICE_RETRY_MS);
+ } catch (InterruptedException ie) {
+ /* ignore */
+ }
+ }
+
+ throw new UnsupportedOperationException("Failed to acquire MediaTranscodeManager");
+ }
+
+ @Override
+ public void setUp() throws Exception {
+ Log.d(TAG, "setUp");
+ super.setUp();
+
+ mContext = getInstrumentation().getContext();
+ mMediaTranscodeManager = getManager();
+ assertNotNull(mMediaTranscodeManager);
+ androidx.test.InstrumentationRegistry.registerInstance(getInstrumentation(), new Bundle());
+
+ // Setup source HEVC file uri.
+ mSourceHEVCVideoUri = resourceToUri(mContext, R.raw.VideoOnlyHEVC, "VideoOnlyHEVC.mp4");
+
+ // Setup source AVC file uri.
+ mSourceAVCVideoUri = resourceToUri(mContext, R.raw.VideoOnlyAVC,
+ "VideoOnlyAVC.mp4");
+
+ // Setup destination file.
+ mDestinationUri = generateNewUri(mContext, "transcoded.mp4");
+ }
+
+ @Override
+ public void tearDown() throws Exception {
+ super.tearDown();
+ }
+
+ // [[ $(adb shell whoami) == "root" ]]
+ private boolean checkIfRoot() {
+ try (ParcelFileDescriptor result = getInstrumentation().getUiAutomation()
+ .executeShellCommand("whoami");
+ BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(
+ new FileInputStream(result.getFileDescriptor())))) {
+ String line;
+ while ((line = bufferedReader.readLine()) != null) {
+ if (line.contains("root")) {
+ return true;
+ }
+ }
+ } catch (IOException ie) {
+ return false;
+ }
+ return false;
+ }
+
+ private String executeShellCommand(String cmd) throws Exception {
+ return UiDevice.getInstance(
+ InstrumentationRegistry.getInstrumentation()).executeShellCommand(cmd);
+ }
+
+ @Test
+ public void testHandleTranscoderServiceDied() throws Exception {
+ if (!checkIfRoot()) {
+ throw new AssertionError("must be root to run this test; try adb root?");
+ }
+
+ Semaphore transcodeCompleteSemaphore = new Semaphore(0);
+ Semaphore jobStartedSemaphore = new Semaphore(0);
+
+ // Transcode a 15 seconds video, so that the transcoding is not finished when we kill the
+ // service.
+ Uri srcUri = Uri.parse(ContentResolver.SCHEME_FILE + "://"
+ + mContext.getCacheDir().getAbsolutePath() + "/longtest_15s.mp4");
+ Uri destinationUri = Uri.parse(ContentResolver.SCHEME_FILE + "://"
+ + mContext.getCacheDir().getAbsolutePath() + "/HevcTranscode.mp4");
+
+ TranscodingRequest request =
+ new TranscodingRequest.Builder()
+ .setSourceUri(mSourceHEVCVideoUri)
+ .setDestinationUri(destinationUri)
+ .setType(MediaTranscodeManager.TRANSCODING_TYPE_VIDEO)
+ .setPriority(MediaTranscodeManager.PRIORITY_REALTIME)
+ .setVideoTrackFormat(createMediaFormat())
+ .build();
+ Executor listenerExecutor = Executors.newSingleThreadExecutor();
+
+ Log.i(TAG, "transcoding to " + createMediaFormat());
+
+ TranscodingJob job = mMediaTranscodeManager.enqueueRequest(request, listenerExecutor,
+ transcodingJob -> {
+ Log.d(TAG, "Transcoding completed with result: " + transcodingJob.getResult());
+ transcodeCompleteSemaphore.release();
+ });
+ assertNotNull(job);
+
+ AtomicInteger progressUpdateCount = new AtomicInteger(0);
+
+ // Set progress update executor and use the same executor as result listener.
+ job.setOnProgressUpdateListener(listenerExecutor,
+ new TranscodingJob.OnProgressUpdateListener() {
+ @Override
+ public void onProgressUpdate(int newProgress) {
+ if (newProgress > 0) {
+ jobStartedSemaphore.release();
+ }
+ }
+ });
+
+ // Wait for progress update so the job is in running state.
+ jobStartedSemaphore.tryAcquire(TRANSCODE_TIMEOUT_SECONDS, TimeUnit.SECONDS);
+ assertTrue("Job is not running", job.getStatus() == TranscodingJob.STATUS_RUNNING);
+
+ // Kills the service and expects receiving failure of the job.
+ executeShellCommand("pkill -f media.transcoding");
+
+ Log.d(TAG, "testMediaTranscodeManager - Waiting for transcode result.");
+ boolean finishedOnTime = transcodeCompleteSemaphore.tryAcquire(
+ TRANSCODE_TIMEOUT_SECONDS, TimeUnit.SECONDS);
+ assertTrue("Invalid job status", job.getStatus() == TranscodingJob.STATUS_FINISHED);
+ assertTrue("Invalid job result", job.getResult()== TranscodingJob.RESULT_ERROR);
+ }
+}
+
diff --git a/media/tests/MediaTranscodingTest/src/com/android/mediatranscodingtest/MediaTranscodeManagerTest.java b/media/tests/MediaTranscodingTest/src/com/android/mediatranscodingtest/MediaTranscodeManagerTest.java
index 8fe10888cab6..a54655d16dd3 100644
--- a/media/tests/MediaTranscodingTest/src/com/android/mediatranscodingtest/MediaTranscodeManagerTest.java
+++ b/media/tests/MediaTranscodingTest/src/com/android/mediatranscodingtest/MediaTranscodeManagerTest.java
@@ -16,22 +16,33 @@
package com.android.mediatranscodingtest;
+import static org.testng.Assert.assertThrows;
+
import android.content.ContentResolver;
import android.content.Context;
import android.media.MediaFormat;
import android.media.MediaTranscodeManager;
import android.media.MediaTranscodeManager.TranscodingJob;
import android.media.MediaTranscodeManager.TranscodingRequest;
+import android.media.TranscodingTestConfig;
import android.net.Uri;
+import android.os.Bundle;
import android.os.FileUtils;
+import android.os.ParcelFileDescriptor;
import android.test.ActivityInstrumentationTestCase2;
import android.util.Log;
+import androidx.test.InstrumentationRegistry;
+import androidx.test.uiautomator.UiDevice;
+
import org.junit.Test;
+import java.io.BufferedReader;
import java.io.File;
+import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
+import java.io.InputStreamReader;
import java.io.OutputStream;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.Executor;
@@ -61,6 +72,13 @@ public class MediaTranscodeManagerTest
private static final String TAG = "MediaTranscodeManagerTest";
/** The time to wait for the transcode operation to complete before failing the test. */
private static final int TRANSCODE_TIMEOUT_SECONDS = 10;
+
+ /** Maximum number of retry to connect to the service. */
+ private static final int CONNECT_SERVICE_RETRY_COUNT = 100;
+
+ /** Interval between trying to reconnect to the service. */
+ private static final int INTERVAL_CONNECT_SERVICE_RETRY_MS = 40;
+
private Context mContext;
private MediaTranscodeManager mMediaTranscodeManager = null;
private Uri mSourceHEVCVideoUri = null;
@@ -121,14 +139,33 @@ public class MediaTranscodeManagerTest
return format;
}
+ private MediaTranscodeManager getManager() {
+ for (int count = 1; count <= CONNECT_SERVICE_RETRY_COUNT; count++) {
+ Log.d(TAG, "Trying to connect to service. Try count: " + count);
+ MediaTranscodeManager manager = mContext.getSystemService(MediaTranscodeManager.class);
+ if (manager != null) {
+ return manager;
+ }
+ try {
+ // Sleep a bit before retry.
+ Thread.sleep(INTERVAL_CONNECT_SERVICE_RETRY_MS);
+ } catch (InterruptedException ie) {
+ /* ignore */
+ }
+ }
+
+ throw new UnsupportedOperationException("Failed to acquire MediaTranscodeManager");
+ }
+
@Override
public void setUp() throws Exception {
Log.d(TAG, "setUp");
super.setUp();
mContext = getInstrumentation().getContext();
- mMediaTranscodeManager = MediaTranscodeManager.getInstance(mContext);
+ mMediaTranscodeManager = getManager();
assertNotNull(mMediaTranscodeManager);
+ androidx.test.InstrumentationRegistry.registerInstance(getInstrumentation(), new Bundle());
// Setup source HEVC file uri.
mSourceHEVCVideoUri = resourceToUri(mContext, R.raw.VideoOnlyHEVC, "VideoOnlyHEVC.mp4");
@@ -146,10 +183,229 @@ public class MediaTranscodeManagerTest
super.tearDown();
}
+
+ /**
+ * Verify that setting null destination uri will throw exception.
+ */
@Test
- public void testTranscodingFromHevcToAvc() throws Exception {
+ public void testCreateTranscodingRequestWithNullDestinationUri() throws Exception {
+ assertThrows(IllegalArgumentException.class, () -> {
+ TranscodingRequest request =
+ new TranscodingRequest.Builder()
+ .setSourceUri(mSourceHEVCVideoUri)
+ .setDestinationUri(null)
+ .setType(MediaTranscodeManager.TRANSCODING_TYPE_VIDEO)
+ .setPriority(MediaTranscodeManager.PRIORITY_REALTIME)
+ .setVideoTrackFormat(createMediaFormat())
+ .build();
+ });
+ }
+
+ /**
+ * Verify that setting null source uri will throw exception.
+ */
+ @Test
+ public void testCreateTranscodingRequestWithNullSourceUri() throws Exception {
+ assertThrows(IllegalArgumentException.class, () -> {
+ TranscodingRequest request =
+ new TranscodingRequest.Builder()
+ .setSourceUri(null)
+ .setDestinationUri(mDestinationUri)
+ .setPriority(MediaTranscodeManager.PRIORITY_REALTIME)
+ .setType(MediaTranscodeManager.TRANSCODING_TYPE_VIDEO)
+ .build();
+ });
+ }
+
+ /**
+ * Verify that not setting source uri will throw exception.
+ */
+ @Test
+ public void testCreateTranscodingRequestWithoutSourceUri() throws Exception {
+ assertThrows(UnsupportedOperationException.class, () -> {
+ TranscodingRequest request =
+ new TranscodingRequest.Builder()
+ .setDestinationUri(mDestinationUri)
+ .setType(MediaTranscodeManager.TRANSCODING_TYPE_VIDEO)
+ .setPriority(MediaTranscodeManager.PRIORITY_REALTIME)
+ .setVideoTrackFormat(createMediaFormat())
+ .build();
+ });
+ }
+
+ /**
+ * Verify that not setting destination uri will throw exception.
+ */
+ @Test
+ public void testCreateTranscodingRequestWithoutDestinationUri() throws Exception {
+ assertThrows(UnsupportedOperationException.class, () -> {
+ TranscodingRequest request =
+ new TranscodingRequest.Builder()
+ .setSourceUri(mSourceHEVCVideoUri)
+ .setType(MediaTranscodeManager.TRANSCODING_TYPE_VIDEO)
+ .setPriority(MediaTranscodeManager.PRIORITY_REALTIME)
+ .setVideoTrackFormat(createMediaFormat())
+ .build();
+ });
+ }
+
+ /**
+ * Verify that setting image transcoding mode will throw exception.
+ */
+ @Test
+ public void testCreateTranscodingRequestWithUnsupportedMode() throws Exception {
+ assertThrows(UnsupportedOperationException.class, () -> {
+ TranscodingRequest request =
+ new TranscodingRequest.Builder()
+ .setSourceUri(mSourceHEVCVideoUri)
+ .setDestinationUri(mDestinationUri)
+ .setType(MediaTranscodeManager.TRANSCODING_TYPE_IMAGE)
+ .setPriority(MediaTranscodeManager.PRIORITY_REALTIME)
+ .setVideoTrackFormat(createMediaFormat())
+ .build();
+ });
+ }
+
+ /**
+ * Verify that setting video transcoding without setting video format will throw exception.
+ */
+ @Test
+ public void testCreateTranscodingRequestWithoutVideoFormat() throws Exception {
+ assertThrows(UnsupportedOperationException.class, () -> {
+ TranscodingRequest request =
+ new TranscodingRequest.Builder()
+ .setSourceUri(mSourceHEVCVideoUri)
+ .setDestinationUri(mDestinationUri)
+ .setType(MediaTranscodeManager.TRANSCODING_TYPE_VIDEO)
+ .setPriority(MediaTranscodeManager.PRIORITY_REALTIME)
+ .build();
+ });
+ }
+
+ void testTranscodingWithExpectResult(Uri srcUri, Uri dstUri, int expectedResult)
+ throws Exception {
+ Semaphore transcodeCompleteSemaphore = new Semaphore(0);
+ TranscodingTestConfig testConfig = new TranscodingTestConfig();
+ testConfig.passThroughMode = true;
+ testConfig.processingTotalTimeMs = 300; // minimum time spent on transcoding.
+
+ TranscodingRequest request =
+ new TranscodingRequest.Builder()
+ .setSourceUri(srcUri)
+ .setDestinationUri(dstUri)
+ .setType(MediaTranscodeManager.TRANSCODING_TYPE_VIDEO)
+ .setPriority(MediaTranscodeManager.PRIORITY_REALTIME)
+ .setVideoTrackFormat(createMediaFormat())
+ .setTestConfig(testConfig)
+ .build();
+ Executor listenerExecutor = Executors.newSingleThreadExecutor();
+
+ TranscodingJob job = mMediaTranscodeManager.enqueueRequest(request, listenerExecutor,
+ transcodingJob -> {
+ Log.d(TAG, "Transcoding completed with result: " + transcodingJob.getResult());
+ assertTrue("Transcoding should failed.",
+ transcodingJob.getResult() == expectedResult);
+ transcodeCompleteSemaphore.release();
+ });
+ assertNotNull(job);
+
+ if (job != null) {
+ Log.d(TAG, "testMediaTranscodeManager - Waiting for transcode to complete.");
+ boolean finishedOnTime = transcodeCompleteSemaphore.tryAcquire(
+ TRANSCODE_TIMEOUT_SECONDS, TimeUnit.SECONDS);
+ assertTrue("Transcode failed to complete in time.", finishedOnTime);
+ }
+
+ if (expectedResult == TranscodingJob.RESULT_SUCCESS) {
+ // Checks the destination file get generated.
+ File file = new File(dstUri.getPath());
+ assertTrue("Failed to create destination file", file.exists());
+
+ // Removes the file.
+ file.delete();
+ }
+ }
+
+ // Tests transcoding from invalid a invalid and expects failure.
+ @Test
+ public void testTranscodingInvalidSrcUri() throws Exception {
Log.d(TAG, "Starting: testMediaTranscodeManager");
+ Uri invalidSrcUri = Uri.parse(ContentResolver.SCHEME_ANDROID_RESOURCE + "://"
+ + mContext.getPackageName() + "/source.mp4");
+ Log.d(TAG, "Transcoding from source: " + invalidSrcUri);
+
+ // Create a file Uri: file:///data/user/0/com.android.mediatranscodingtest/cache/temp.mp4
+ // The full path of this file is:
+ // /data/user/0/com.android.mediatranscodingtest/cache/temp.mp4
+ Uri destinationUri = Uri.parse(ContentResolver.SCHEME_ANDROID_RESOURCE + "://"
+ + mContext.getPackageName() + "/temp.mp4");
+ Log.d(TAG, "Transcoding to destination: " + destinationUri);
+
+ testTranscodingWithExpectResult(invalidSrcUri, destinationUri, TranscodingJob.RESULT_ERROR);
+ }
+
+ // Tests transcoding to a uri in res folder and expects failure as we could not write to res
+ // folder.
+ @Test
+ public void testTranscodingToResFolder() throws Exception {
+ Log.d(TAG, "Starting: testMediaTranscodeManager");
+
+ // Create a file Uri: file:///data/user/0/com.android.mediatranscodingtest/cache/temp.mp4
+ // The full path of this file is:
+ // /data/user/0/com.android.mediatranscodingtest/cache/temp.mp4
+ Uri destinationUri = Uri.parse(ContentResolver.SCHEME_ANDROID_RESOURCE + "://"
+ + mContext.getPackageName() + "/temp.mp4");
+ Log.d(TAG, "Transcoding to destination: " + destinationUri);
+
+ testTranscodingWithExpectResult(mSourceHEVCVideoUri, destinationUri,
+ TranscodingJob.RESULT_ERROR);
+ }
+
+ // Tests transcoding to a uri in internal storage folder and expects success.
+ @Test
+ public void testTranscodingToCacheDir() throws Exception {
+ Log.d(TAG, "Starting: testMediaTranscodeManager");
+
+ // Create a file Uri: file:///data/user/0/com.android.mediatranscodingtest/cache/temp.mp4
+ // The full path of this file is:
+ // /data/user/0/com.android.mediatranscodingtest/cache/temp.mp4
+ Uri destinationUri = Uri.parse(ContentResolver.SCHEME_FILE + "://"
+ + mContext.getCacheDir().getAbsolutePath() + "/temp.mp4");
+
+ testTranscodingWithExpectResult(mSourceHEVCVideoUri, destinationUri,
+ TranscodingJob.RESULT_SUCCESS);
+ }
+
+ // Tests transcoding to a uri in internal files directory and expects success.
+ @Test
+ public void testTranscodingToInternalFilesDir() throws Exception {
+ Log.d(TAG, "Starting: testMediaTranscodeManager");
+
+ // Create a file Uri:
+ // file:///storage/emulated/0/Android/data/com.android.mediatranscodingtest/files/temp.mp4
+ Uri destinationUri = Uri.fromFile(new File(mContext.getFilesDir(), "temp.mp4"));
+ Log.i(TAG, "Transcoding to files dir: " + destinationUri);
+
+ testTranscodingWithExpectResult(mSourceHEVCVideoUri, destinationUri,
+ TranscodingJob.RESULT_SUCCESS);
+ }
+
+ // Tests transcoding to a uri in external files directory and expects success.
+ @Test
+ public void testTranscodingToExternalFilesDir() throws Exception {
+ Log.d(TAG, "Starting: testMediaTranscodeManager");
+
+ // Create a file Uri: file:///data/user/0/com.android.mediatranscodingtest/files/temp.mp4
+ Uri destinationUri = Uri.fromFile(new File(mContext.getExternalFilesDir(null), "temp.mp4"));
+ Log.i(TAG, "Transcoding to files dir: " + destinationUri);
+
+ testTranscodingWithExpectResult(mSourceHEVCVideoUri, destinationUri,
+ TranscodingJob.RESULT_SUCCESS);
+ }
+
+ @Test
+ public void testTranscodingFromHevcToAvc() throws Exception {
Semaphore transcodeCompleteSemaphore = new Semaphore(0);
// Create a file Uri: file:///data/user/0/com.android.mediatranscodingtest/cache/temp.mp4
@@ -194,6 +450,7 @@ public class MediaTranscodeManagerTest
stats.mAveragePSNR >= PSNR_THRESHOLD);
}
+
@Test
public void testCancelTranscoding() throws Exception {
Log.d(TAG, "Starting: testMediaTranscodeManager");
@@ -300,5 +557,26 @@ public class MediaTranscodeManagerTest
assertTrue("Failed to receive at least 10 progress updates",
progressUpdateCount.get() > 10);
}
+
+ // [[ $(adb shell whoami) == "root" ]]
+ private boolean checkIfRoot() throws IOException {
+ try (ParcelFileDescriptor result = getInstrumentation().getUiAutomation()
+ .executeShellCommand("whoami");
+ BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(
+ new FileInputStream(result.getFileDescriptor())))) {
+ String line;
+ while ((line = bufferedReader.readLine()) != null) {
+ if (line.contains("root")) {
+ return true;
+ }
+ }
+ }
+ return false;
+ }
+
+ private String executeShellCommand(String cmd) throws Exception {
+ return UiDevice.getInstance(
+ InstrumentationRegistry.getInstrumentation()).executeShellCommand(cmd);
+ }
}
diff --git a/media/tests/MediaTranscodingTest/src/com/android/mediatranscodingtest/MediaTranscodeManagerWithMockServiceTest.java b/media/tests/MediaTranscodingTest/src/com/android/mediatranscodingtest/MediaTranscodeManagerWithMockServiceTest.java
deleted file mode 100644
index 748c21acebab..000000000000
--- a/media/tests/MediaTranscodingTest/src/com/android/mediatranscodingtest/MediaTranscodeManagerWithMockServiceTest.java
+++ /dev/null
@@ -1,503 +0,0 @@
-/*
- * 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.mediatranscodingtest;
-
-import static org.testng.Assert.assertThrows;
-
-import android.content.ContentResolver;
-import android.content.Context;
-import android.media.IMediaTranscodingService;
-import android.media.ITranscodingClient;
-import android.media.ITranscodingClientCallback;
-import android.media.MediaFormat;
-import android.media.MediaTranscodeManager;
-import android.media.MediaTranscodeManager.TranscodingJob;
-import android.media.MediaTranscodeManager.TranscodingRequest;
-import android.media.TranscodingJobParcel;
-import android.media.TranscodingRequestParcel;
-import android.media.TranscodingResultParcel;
-import android.media.TranscodingTestConfig;
-import android.net.Uri;
-import android.os.ParcelFileDescriptor;
-import android.os.RemoteException;
-import android.test.ActivityInstrumentationTestCase2;
-import android.util.Log;
-
-import org.junit.Test;
-
-import java.io.File;
-import java.util.concurrent.ConcurrentHashMap;
-import java.util.concurrent.ConcurrentMap;
-import java.util.concurrent.Executor;
-import java.util.concurrent.Executors;
-import java.util.concurrent.RejectedExecutionException;
-import java.util.concurrent.ScheduledExecutorService;
-import java.util.concurrent.ScheduledFuture;
-import java.util.concurrent.Semaphore;
-import java.util.concurrent.TimeUnit;
-import java.util.concurrent.atomic.AtomicInteger;
-
-/*
- * Functional tests for MediaTranscodeManager in the media framework.
- * The test uses a mock Transcoding service as backend to test the API functionality.
- *
- * To run this test suite:
- make frameworks/base/media/tests/MediaTranscodingTest
- make mediatranscodingtest
-
- adb install -r testcases/mediatranscodingtest/arm64/mediatranscodingtest.apk
-
- adb shell am instrument -e class \
- com.android.mediatranscodingtest.MediaTranscodeManagerWithMockServiceTest \
- -w com.android.mediatranscodingtest/.MediaTranscodingTestRunner
- *
- */
-public class MediaTranscodeManagerWithMockServiceTest
- extends ActivityInstrumentationTestCase2<MediaTranscodingTest> {
- private static final String TAG = "MediaTranscodeManagerWithMockServiceTest";
- /** The time to wait for the transcode operation to complete before failing the test. */
- private static final int TRANSCODE_TIMEOUT_SECONDS = 2;
- private Context mContext;
- private MediaTranscodeManager mMediaTranscodeManager = null;
- private Uri mSourceHEVCVideoUri = null;
- private Uri mDestinationUri = null;
- // Use mock transcoding service for testing the api.
- private MockTranscodingService mTranscodingService = null;
-
- // Setting for transcoding to H.264.
- private static final String MIME_TYPE = MediaFormat.MIMETYPE_VIDEO_AVC;
- private static final int BIT_RATE = 2000000; // 2Mbps
- private static final int WIDTH = 1920;
- private static final int HEIGHT = 1080;
-
- // A mock transcoding service that will take constant 300ms to process each transcoding job.
- // Instead of doing real transcoding, it will return the dst uri directly.
- class MockTranscodingService extends IMediaTranscodingService.Stub {
- private final ScheduledExecutorService mJobScheduler = Executors.newScheduledThreadPool(1);
- private int mNumOfClients = 0;
- private AtomicInteger mJobId = new AtomicInteger();
-
- // A runnable that will process the job.
- private class ProcessingJobRunnable implements Runnable {
- private TranscodingJobParcel mJob;
- private ITranscodingClientCallback mCallback;
- private ConcurrentMap<Integer, ScheduledFuture<?>> mJobMap;
-
- ProcessingJobRunnable(ITranscodingClientCallback callback,
- TranscodingJobParcel job,
- ConcurrentMap<Integer, ScheduledFuture<?>> jobMap) {
- mJob = job;
- mCallback = callback;
- mJobMap = jobMap;
- }
-
- @Override
- public void run() {
- Log.d(TAG, "Start to process job " + mJob.jobId);
- TranscodingResultParcel result = new TranscodingResultParcel();
- try {
- // Try to open the source fd.
- ParcelFileDescriptor sourceFd = mCallback.openFileDescriptor(
- mJob.request.sourceFilePath, "r");
- if (sourceFd == null) {
- Log.d(TAG, "Failed to open sourceFd");
- // TODO(hkuang): Pass the correct error code.
- mCallback.onTranscodingFailed(mJob.jobId, 1);
- return;
- } else {
- Log.d(TAG, "Successfully open sourceFd");
- }
-
- // Try to write to the destination fd.
- ParcelFileDescriptor destinationFd = mCallback.openFileDescriptor(
- mJob.request.destinationFilePath, "w");
- if (destinationFd == null) {
- Log.d(TAG, "Failed to open destinationFd");
- // TODO(hkuang): Pass the correct error code.
- mCallback.onTranscodingFailed(mJob.jobId, 1);
- return;
- } else {
- Log.d(TAG, "Successfully open destinationFd");
- }
-
- mCallback.onTranscodingFinished(mJob.jobId, result);
- // Removes the job from job map.
- mJobMap.remove(mJob.jobId);
- } catch (RemoteException re) {
- Log.e(TAG, "Failed to callback to client");
- }
- }
- }
-
- @Override
- public ITranscodingClient registerClient(ITranscodingClientCallback callback,
- String clientName, String opPackageName, int clientUid, int clientPid)
- throws RemoteException {
- Log.d(TAG, "MockTranscodingService creates one client");
-
- ITranscodingClient client = new ITranscodingClient.Stub() {
- private final ConcurrentMap<Integer, ScheduledFuture<?>> mPendingTranscodingJobs =
- new ConcurrentHashMap<Integer, ScheduledFuture<?>>();
-
- @Override
- public boolean submitRequest(TranscodingRequestParcel inRequest,
- TranscodingJobParcel outjob) {
- Log.d(TAG, "Mock client gets submitRequest");
- try {
- outjob.request = inRequest;
- outjob.jobId = mJobId.getAndIncrement();
- Log.i(TAG, "Generate new job " + outjob.jobId);
- Log.i(TAG, "Source Uri " + inRequest.sourceFilePath);
- Log.i(TAG, "Destination Uri " + inRequest.destinationFilePath);
-
- // Schedules the job to run after inRequest.processingDelayMs.
- ScheduledFuture<?> transcodingFuture = mJobScheduler.schedule(
- new ProcessingJobRunnable(callback, outjob,
- mPendingTranscodingJobs),
- inRequest.testConfig == null ? 0
- : inRequest.testConfig.processingTotalTimeMs,
- TimeUnit.MILLISECONDS);
- mPendingTranscodingJobs.put(outjob.jobId, transcodingFuture);
- } catch (RejectedExecutionException e) {
- Log.e(TAG, "Failed to schedule transcoding job: " + e);
- return false;
- }
-
- return true;
- }
-
- @Override
- public boolean cancelJob(int jobId) throws RemoteException {
- Log.d(TAG, "Mock client gets cancelJob " + jobId);
- // Cancels the job is still in the mPendingTranscodingJobs.
- if (mPendingTranscodingJobs.containsKey(jobId)) {
- // Cancel the future task for transcoding.
- mPendingTranscodingJobs.get(jobId).cancel(true);
-
- // Remove the job from the mPendingTranscodingJobs.
- mPendingTranscodingJobs.remove(jobId);
- return true;
- }
- return false;
- }
-
- @Override
- public boolean getJobWithId(int jobId, TranscodingJobParcel job)
- throws RemoteException {
- // This will be implemented this if needed in the test.
- return true;
- }
-
- @Override
- public void unregister() throws RemoteException {
- Log.d(TAG, "Mock client gets unregister");
- // This will be implemented this if needed in the test.
- mNumOfClients--;
- }
- };
- mNumOfClients++;
- return client;
- }
-
- @Override
- public int getNumOfClients() throws RemoteException {
- return mNumOfClients;
- }
- }
-
- public MediaTranscodeManagerWithMockServiceTest() {
- super("com.android.MediaTranscodeManagerWithMockServiceTest", MediaTranscodingTest.class);
- }
-
- private static Uri resourceToUri(Context context, int resId) {
- Uri uri = new Uri.Builder()
- .scheme(ContentResolver.SCHEME_ANDROID_RESOURCE)
- .authority(context.getResources().getResourcePackageName(resId))
- .appendPath(context.getResources().getResourceTypeName(resId))
- .appendPath(context.getResources().getResourceEntryName(resId))
- .build();
- return uri;
- }
-
- private static Uri generateNewUri(Context context, String filename) {
- File outFile = new File(context.getExternalCacheDir(), filename);
- return Uri.fromFile(outFile);
- }
-
- // Generates a invalid uri which will let the mock service return transcoding failure.
- private static Uri generateInvalidTranscodingUri(Context context) {
- File outFile = new File(context.getExternalCacheDir(), "InvalidUri.mp4");
- return Uri.fromFile(outFile);
- }
-
- /**
- * Creates a MediaFormat with the basic set of values.
- */
- private static MediaFormat createMediaFormat() {
- MediaFormat format = MediaFormat.createVideoFormat(MIME_TYPE, WIDTH, HEIGHT);
- format.setInteger(MediaFormat.KEY_BIT_RATE, BIT_RATE);
- return format;
- }
-
- @Override
- public void setUp() throws Exception {
- Log.d(TAG, "setUp");
- super.setUp();
- mTranscodingService = new MockTranscodingService();
- mContext = getInstrumentation().getContext();
- mMediaTranscodeManager = MediaTranscodeManager.getInstance(mContext, mTranscodingService);
- assertNotNull(mMediaTranscodeManager);
-
- // Setup source HEVC file uri.
- mSourceHEVCVideoUri = resourceToUri(mContext, R.raw.VideoOnlyHEVC);
-
- // Setup destination file.
- mDestinationUri = generateNewUri(mContext, "transcoded.mp4");
- }
-
- @Override
- public void tearDown() throws Exception {
- super.tearDown();
- }
-
- /**
- * Verify that setting null destination uri will throw exception.
- */
- @Test
- public void testCreateTranscodingRequestWithNullDestinationUri() throws Exception {
- assertThrows(IllegalArgumentException.class, () -> {
- TranscodingRequest request =
- new TranscodingRequest.Builder()
- .setSourceUri(mSourceHEVCVideoUri)
- .setDestinationUri(null)
- .setType(MediaTranscodeManager.TRANSCODING_TYPE_VIDEO)
- .setPriority(MediaTranscodeManager.PRIORITY_REALTIME)
- .setVideoTrackFormat(createMediaFormat())
- .build();
- });
- }
-
- /**
- * Verify that setting null source uri will throw exception.
- */
- @Test
- public void testCreateTranscodingRequestWithNullSourceUri() throws Exception {
- assertThrows(IllegalArgumentException.class, () -> {
- TranscodingRequest request =
- new TranscodingRequest.Builder()
- .setSourceUri(null)
- .setDestinationUri(mDestinationUri)
- .setPriority(MediaTranscodeManager.PRIORITY_REALTIME)
- .setType(MediaTranscodeManager.TRANSCODING_TYPE_VIDEO)
- .build();
- });
- }
-
- /**
- * Verify that not setting source uri will throw exception.
- */
- @Test
- public void testCreateTranscodingRequestWithoutSourceUri() throws Exception {
- assertThrows(UnsupportedOperationException.class, () -> {
- TranscodingRequest request =
- new TranscodingRequest.Builder()
- .setDestinationUri(mDestinationUri)
- .setType(MediaTranscodeManager.TRANSCODING_TYPE_VIDEO)
- .setPriority(MediaTranscodeManager.PRIORITY_REALTIME)
- .setVideoTrackFormat(createMediaFormat())
- .build();
- });
- }
-
- /**
- * Verify that not setting destination uri will throw exception.
- */
- @Test
- public void testCreateTranscodingRequestWithoutDestinationUri() throws Exception {
- assertThrows(UnsupportedOperationException.class, () -> {
- TranscodingRequest request =
- new TranscodingRequest.Builder()
- .setSourceUri(mSourceHEVCVideoUri)
- .setType(MediaTranscodeManager.TRANSCODING_TYPE_VIDEO)
- .setPriority(MediaTranscodeManager.PRIORITY_REALTIME)
- .setVideoTrackFormat(createMediaFormat())
- .build();
- });
- }
-
- /**
- * Verify that setting image transcoding mode will throw exception.
- */
- @Test
- public void testCreateTranscodingRequestWithUnsupportedMode() throws Exception {
- assertThrows(UnsupportedOperationException.class, () -> {
- TranscodingRequest request =
- new TranscodingRequest.Builder()
- .setSourceUri(mSourceHEVCVideoUri)
- .setDestinationUri(mDestinationUri)
- .setType(MediaTranscodeManager.TRANSCODING_TYPE_IMAGE)
- .setPriority(MediaTranscodeManager.PRIORITY_REALTIME)
- .setVideoTrackFormat(createMediaFormat())
- .build();
- });
- }
-
- /**
- * Verify that setting video transcoding without setting video format will throw exception.
- */
- @Test
- public void testCreateTranscodingRequestWithoutVideoFormat() throws Exception {
- assertThrows(UnsupportedOperationException.class, () -> {
- TranscodingRequest request =
- new TranscodingRequest.Builder()
- .setSourceUri(mSourceHEVCVideoUri)
- .setDestinationUri(mDestinationUri)
- .setType(MediaTranscodeManager.TRANSCODING_TYPE_VIDEO)
- .setPriority(MediaTranscodeManager.PRIORITY_REALTIME)
- .build();
- });
- }
-
- void testTranscodingWithExpectResult(Uri srcUri, Uri dstUri, int expectedResult)
- throws Exception {
- Semaphore transcodeCompleteSemaphore = new Semaphore(0);
- TranscodingTestConfig testConfig = new TranscodingTestConfig();
- testConfig.passThroughMode = true;
- testConfig.processingTotalTimeMs = 300; // minimum time spent on transcoding.
-
- TranscodingRequest request =
- new TranscodingRequest.Builder()
- .setSourceUri(srcUri)
- .setDestinationUri(dstUri)
- .setType(MediaTranscodeManager.TRANSCODING_TYPE_VIDEO)
- .setPriority(MediaTranscodeManager.PRIORITY_REALTIME)
- .setVideoTrackFormat(createMediaFormat())
- .setTestConfig(testConfig)
- .build();
- Executor listenerExecutor = Executors.newSingleThreadExecutor();
-
- TranscodingJob job = mMediaTranscodeManager.enqueueRequest(request, listenerExecutor,
- transcodingJob -> {
- Log.d(TAG, "Transcoding completed with result: " + transcodingJob.getResult());
- assertTrue("Transcoding should failed.",
- transcodingJob.getResult() == expectedResult);
- transcodeCompleteSemaphore.release();
- });
- assertNotNull(job);
-
- if (job != null) {
- Log.d(TAG, "testMediaTranscodeManager - Waiting for transcode to complete.");
- boolean finishedOnTime = transcodeCompleteSemaphore.tryAcquire(
- TRANSCODE_TIMEOUT_SECONDS, TimeUnit.SECONDS);
- assertTrue("Transcode failed to complete in time.", finishedOnTime);
- }
-
- if (expectedResult == TranscodingJob.RESULT_SUCCESS) {
- // Checks the destination file get generated.
- File file = new File(dstUri.getPath());
- assertTrue("Failed to create destination file", file.exists());
-
- // Removes the file.
- file.delete();
- }
- }
-
- // Tests transcoding from invalid a invalid and expects failure.
- @Test
- public void testTranscodingInvalidSrcUri() throws Exception {
- Log.d(TAG, "Starting: testMediaTranscodeManager");
-
- Uri invalidSrcUri = Uri.parse(ContentResolver.SCHEME_ANDROID_RESOURCE + "://"
- + mContext.getPackageName() + "/source.mp4");
- Log.d(TAG, "Transcoding from source: " + invalidSrcUri);
-
- // Create a file Uri: file:///data/user/0/com.android.mediatranscodingtest/cache/temp.mp4
- // The full path of this file is:
- // /data/user/0/com.android.mediatranscodingtest/cache/temp.mp4
- Uri destinationUri = Uri.parse(ContentResolver.SCHEME_ANDROID_RESOURCE + "://"
- + mContext.getPackageName() + "/temp.mp4");
- Log.d(TAG, "Transcoding to destination: " + destinationUri);
-
- testTranscodingWithExpectResult(invalidSrcUri, destinationUri, TranscodingJob.RESULT_ERROR);
- }
-
- // Tests transcoding to a uri in res folder and expects failure as we could not write to res
- // folder.
- @Test
- public void testTranscodingToResFolder() throws Exception {
- Log.d(TAG, "Starting: testMediaTranscodeManager");
-
- // Create a file Uri: file:///data/user/0/com.android.mediatranscodingtest/cache/temp.mp4
- // The full path of this file is:
- // /data/user/0/com.android.mediatranscodingtest/cache/temp.mp4
- Uri destinationUri = Uri.parse(ContentResolver.SCHEME_ANDROID_RESOURCE + "://"
- + mContext.getPackageName() + "/temp.mp4");
- Log.d(TAG, "Transcoding to destination: " + destinationUri);
-
- testTranscodingWithExpectResult(mSourceHEVCVideoUri, destinationUri,
- TranscodingJob.RESULT_ERROR);
- }
-
- // Tests transcoding to a uri in internal storage folder and expects success.
- @Test
- public void testTranscodingToCacheDir() throws Exception {
- Log.d(TAG, "Starting: testMediaTranscodeManager");
-
- // Create a file Uri: file:///data/user/0/com.android.mediatranscodingtest/cache/temp.mp4
- // The full path of this file is:
- // /data/user/0/com.android.mediatranscodingtest/cache/temp.mp4
- Uri destinationUri = Uri.parse(ContentResolver.SCHEME_FILE + "://"
- + mContext.getCacheDir().getAbsolutePath() + "/temp.mp4");
-
- testTranscodingWithExpectResult(mSourceHEVCVideoUri, destinationUri,
- TranscodingJob.RESULT_SUCCESS);
- }
-
- // Tests transcoding to a uri in internal files directory and expects success.
- @Test
- public void testTranscodingToInternalFilesDir() throws Exception {
- Log.d(TAG, "Starting: testMediaTranscodeManager");
-
- // Create a file Uri:
- // file:///storage/emulated/0/Android/data/com.android.mediatranscodingtest/files/temp.mp4
- Uri destinationUri = Uri.fromFile(new File(mContext.getFilesDir(), "temp.mp4"));
- Log.i(TAG, "Transcoding to files dir: " + destinationUri);
-
- testTranscodingWithExpectResult(mSourceHEVCVideoUri, destinationUri,
- TranscodingJob.RESULT_SUCCESS);
- }
-
- // Tests transcoding to a uri in external files directory and expects success.
- @Test
- public void testTranscodingToExternalFilesDir() throws Exception {
- Log.d(TAG, "Starting: testMediaTranscodeManager");
-
- // Create a file Uri: file:///data/user/0/com.android.mediatranscodingtest/files/temp.mp4
- Uri destinationUri = Uri.fromFile(new File(mContext.getExternalFilesDir(null), "temp.mp4"));
- Log.i(TAG, "Transcoding to files dir: " + destinationUri);
-
- testTranscodingWithExpectResult(mSourceHEVCVideoUri, destinationUri,
- TranscodingJob.RESULT_SUCCESS);
- }
-
- @Test
- public void testTranscodingOneVideo() throws Exception {
- Log.d(TAG, "Starting: testMediaTranscodeManager");
- testTranscodingWithExpectResult(mSourceHEVCVideoUri, mDestinationUri,
- TranscodingJob.RESULT_SUCCESS);
- }
-}
diff --git a/media/tests/MediaTranscodingTest/src/com/android/mediatranscodingtest/MediaTranscodingBenchmark.java b/media/tests/MediaTranscodingTest/src/com/android/mediatranscodingtest/MediaTranscodingBenchmark.java
index 5c87d30068b2..73e1d98cb2e2 100644
--- a/media/tests/MediaTranscodingTest/src/com/android/mediatranscodingtest/MediaTranscodingBenchmark.java
+++ b/media/tests/MediaTranscodingTest/src/com/android/mediatranscodingtest/MediaTranscodingBenchmark.java
@@ -89,7 +89,7 @@ public class MediaTranscodingBenchmark
Log.d(TAG, "setUp");
super.setUp();
mContext = getInstrumentation().getContext();
- mMediaTranscodeManager = MediaTranscodeManager.getInstance(mContext);
+ mMediaTranscodeManager = mContext.getSystemService(MediaTranscodeManager.class);
}
@Override
@@ -132,9 +132,9 @@ public class MediaTranscodingBenchmark
Log.d(TAG,
"Transcoding completed with result: " + transcodingJob.getResult());
assertEquals(transcodingJob.getResult(), TranscodingJob.RESULT_SUCCESS);
- transcodeCompleteSemaphore.release();
transcodingTime.set(System.currentTimeMillis() - startTimeMs);
totalTimeMs.addAndGet(transcodingTime.get());
+ transcodeCompleteSemaphore.release();
});
if (job != null) {
@@ -173,9 +173,6 @@ public class MediaTranscodingBenchmark
transcode(testVideoName, transcodedVideoName);
}
- // TODO(hkuang): Enable this after b/160268606 is fixed. Transcoding video with audio takes way
- // more long time that leads to timeout failure.
- /*
@Test
public void testBenchmarkingAVCToAVCWith66FramesWithAudio() throws Exception {
String videoNameWithoutExtension = "video_1920x1080_66frame_h264_22Mbps_30fps_aac";
@@ -183,7 +180,7 @@ public class MediaTranscodingBenchmark
String transcodedVideoName = videoNameWithoutExtension + "_transcode.mp4";
transcode(testVideoName, transcodedVideoName);
- }*/
+ }
@Test
public void testBenchmarkingAVCToAVCWith361FramesWithoutAudio() throws Exception {
@@ -194,16 +191,14 @@ public class MediaTranscodingBenchmark
transcode(testVideoName, transcodedVideoName);
}
- // TODO(hkuang): Enable this after b/160268606 is fixed. Transcoding video with audio takes way
- // more long time that leads to timeout failure.
- /*@Test
+ @Test
public void testBenchmarkingAVCToAVCWith361FramesWithAudio() throws Exception {
String videoNameWithoutExtension = "video_1920x1080_361frame_h264_22Mbps_30fps_aac";
String testVideoName = videoNameWithoutExtension + ".mp4";
String transcodedVideoName = videoNameWithoutExtension + "_transcode.mp4";
transcode(testVideoName, transcodedVideoName);
- }*/
+ }
@Test
public void testBenchmarkingAVCToAVCWith943FramesWithoutAudio() throws Exception {
@@ -214,16 +209,14 @@ public class MediaTranscodingBenchmark
transcode(testVideoName, transcodedVideoName);
}
- // TODO(hkuang): Enable this after b/160268606 is fixed. Transcoding video with audio takes way
- // more long time that leads to timeout failure.
- /* @Test
+ @Test
public void testBenchmarkingAVCToAVCWith943FramesWithAudio() throws Exception {
String videoNameWithoutExtension = "video_1920x1080_943frame_h264_22Mbps_30fps_aac";
String testVideoName = videoNameWithoutExtension + ".mp4";
String transcodedVideoName = videoNameWithoutExtension + "_transcode.mp4";
transcode(testVideoName, transcodedVideoName);
- }*/
+ }
@Test
public void testBenchmarkingAVCToAVCWith1822FramesWithoutAudio() throws Exception {
@@ -234,16 +227,14 @@ public class MediaTranscodingBenchmark
transcode(testVideoName, transcodedVideoName);
}
- // TODO(hkuang): Enable this after b/160268606 is fixed. Transcoding video with audio takes way
- // more long time that leads to timeout failure.
- /*@Test
+ @Test
public void testBenchmarkingAVCToAVCWith1822FramesWithAudio() throws Exception {
String videoNameWithoutExtension = "video_1920x1080_1822frame_h264_22Mbps_30fps_aac";
String testVideoName = videoNameWithoutExtension + ".mp4";
String transcodedVideoName = videoNameWithoutExtension + "_transcode.mp4";
transcode(testVideoName, transcodedVideoName);
- }*/
+ }
@Test
public void testBenchmarkingAVCToAVCWith3648FramesWithoutAudio() throws Exception {
@@ -254,16 +245,14 @@ public class MediaTranscodingBenchmark
transcode(testVideoName, transcodedVideoName);
}
- // TODO(hkuang): Enable this after b/160268606 is fixed. Transcoding video with audio takes way
- // more long time that leads to timeout failure.
- /*@Test
+ @Test
public void testBenchmarkingAVCToAVCWith3648FramesWithAudio() throws Exception {
String videoNameWithoutExtension = "video_1920x1080_3648frame_h264_22Mbps_30fps_aac";
String testVideoName = videoNameWithoutExtension + ".mp4";
String transcodedVideoName = videoNameWithoutExtension + "_transcode.mp4";
transcode(testVideoName, transcodedVideoName);
- }*/
+ }
@Test
public void testBenchmarkingAVCToAVCWith11042FramesWithoutAudio() throws Exception {
@@ -274,16 +263,14 @@ public class MediaTranscodingBenchmark
transcode(testVideoName, transcodedVideoName);
}
- // TODO(hkuang): Enable this after b/160268606 is fixed. Transcoding video with audio takes way
- // more long time that leads to timeout failure.
- /*@Test
+ @Test
public void testBenchmarkingAVCToAVCWith11042FramesWithAudio() throws Exception {
String videoNameWithoutExtension = "video_1920x1080_11042frame_h264_22Mbps_30fps_aac";
String testVideoName = videoNameWithoutExtension + ".mp4";
String transcodedVideoName = videoNameWithoutExtension + "_transcode.mp4";
transcode(testVideoName, transcodedVideoName);
- } */
+ }
@Test
public void testBenchmarkingHEVCToAVCWith107FramesWithoutAudio() throws Exception {
diff --git a/media/tests/MediaTranscodingTest/src/com/android/mediatranscodingtest/MediaTranscodingTestRunner.java b/media/tests/MediaTranscodingTest/src/com/android/mediatranscodingtest/MediaTranscodingTestRunner.java
index 53b23927fc64..bd1551f352f4 100644
--- a/media/tests/MediaTranscodingTest/src/com/android/mediatranscodingtest/MediaTranscodingTestRunner.java
+++ b/media/tests/MediaTranscodingTest/src/com/android/mediatranscodingtest/MediaTranscodingTestRunner.java
@@ -36,8 +36,8 @@ public class MediaTranscodingTestRunner extends InstrumentationTestRunner {
@Override
public TestSuite getAllTests() {
TestSuite suite = new InstrumentationTestSuite(this);
+ suite.addTestSuite(MediaTranscodeManagerDiedTest.class);
suite.addTestSuite(MediaTranscodeManagerTest.class);
- suite.addTestSuite(MediaTranscodeManagerWithMockServiceTest.class);
suite.addTestSuite(MediaTranscodingBenchmark.class);
return suite;
}
diff --git a/non-updatable-api/current.txt b/non-updatable-api/current.txt
index e0ebec6cbd01..e1b3151acd5b 100644
--- a/non-updatable-api/current.txt
+++ b/non-updatable-api/current.txt
@@ -11617,6 +11617,16 @@ package android.content.pm {
field public int version;
}
+ public final class FileChecksum implements android.os.Parcelable {
+ method public int describeContents();
+ method public int getKind();
+ method @Nullable public java.security.cert.Certificate getSourceCertificate() throws java.security.cert.CertificateException;
+ method @Nullable public String getSplitName();
+ method @NonNull public byte[] getValue();
+ method public void writeToParcel(@NonNull android.os.Parcel, int);
+ field @NonNull public static final android.os.Parcelable.Creator<android.content.pm.FileChecksum> CREATOR;
+ }
+
public final class InstallSourceInfo implements android.os.Parcelable {
method public int describeContents();
method @Nullable public String getInitiatingPackageName();
@@ -11992,6 +12002,7 @@ package android.content.pm {
method @Nullable public abstract android.graphics.drawable.Drawable getApplicationLogo(@NonNull String) throws android.content.pm.PackageManager.NameNotFoundException;
method @NonNull public CharSequence getBackgroundPermissionOptionLabel();
method @Nullable public abstract android.content.pm.ChangedPackages getChangedPackages(@IntRange(from=0) int);
+ method public void getChecksums(@NonNull String, boolean, int, @Nullable java.util.List<java.security.cert.Certificate>, @NonNull android.content.IntentSender) throws java.security.cert.CertificateEncodingException, java.io.IOException, android.content.pm.PackageManager.NameNotFoundException;
method public abstract int getComponentEnabledSetting(@NonNull android.content.ComponentName);
method @NonNull public abstract android.graphics.drawable.Drawable getDefaultActivityIcon();
method @Nullable public abstract android.graphics.drawable.Drawable getDrawable(@NonNull String, @DrawableRes int, @Nullable android.content.pm.ApplicationInfo);
@@ -12082,6 +12093,7 @@ package android.content.pm {
field public static final int COMPONENT_ENABLED_STATE_DISABLED_USER = 3; // 0x3
field public static final int COMPONENT_ENABLED_STATE_ENABLED = 1; // 0x1
field public static final int DONT_KILL_APP = 1; // 0x1
+ field public static final String EXTRA_CHECKSUMS = "android.content.pm.extra.CHECKSUMS";
field public static final String EXTRA_VERIFICATION_ID = "android.content.pm.extra.VERIFICATION_ID";
field public static final String EXTRA_VERIFICATION_RESULT = "android.content.pm.extra.VERIFICATION_RESULT";
field public static final String FEATURE_ACTIVITIES_ON_SECONDARY_DISPLAYS = "android.software.activities_on_secondary_displays";
@@ -12236,6 +12248,8 @@ package android.content.pm {
field public static final int MATCH_SYSTEM_ONLY = 1048576; // 0x100000
field public static final int MATCH_UNINSTALLED_PACKAGES = 8192; // 0x2000
field public static final long MAXIMUM_VERIFICATION_TIMEOUT = 3600000L; // 0x36ee80L
+ field public static final int PARTIAL_MERKLE_ROOT_1M_SHA256 = 32; // 0x20
+ field public static final int PARTIAL_MERKLE_ROOT_1M_SHA512 = 64; // 0x40
field public static final int PERMISSION_DENIED = -1; // 0xffffffff
field public static final int PERMISSION_GRANTED = 0; // 0x0
field public static final int SIGNATURE_FIRST_NOT_SIGNED = -1; // 0xffffffff
@@ -12245,9 +12259,16 @@ package android.content.pm {
field public static final int SIGNATURE_SECOND_NOT_SIGNED = -2; // 0xfffffffe
field public static final int SIGNATURE_UNKNOWN_PACKAGE = -4; // 0xfffffffc
field public static final int SYNCHRONOUS = 2; // 0x2
+ field @Nullable public static final java.util.List<java.security.cert.Certificate> TRUST_ALL;
+ field @NonNull public static final java.util.List<java.security.cert.Certificate> TRUST_NONE;
field public static final int VERIFICATION_ALLOW = 1; // 0x1
field public static final int VERIFICATION_REJECT = -1; // 0xffffffff
field public static final int VERSION_CODE_HIGHEST = -1; // 0xffffffff
+ field public static final int WHOLE_MD5 = 2; // 0x2
+ field public static final int WHOLE_MERKLE_ROOT_4K_SHA256 = 1; // 0x1
+ field public static final int WHOLE_SHA1 = 4; // 0x4
+ field public static final int WHOLE_SHA256 = 8; // 0x8
+ field public static final int WHOLE_SHA512 = 16; // 0x10
}
public static class PackageManager.NameNotFoundException extends android.util.AndroidException {
diff --git a/non-updatable-api/system-current.txt b/non-updatable-api/system-current.txt
index d1264dfdd36d..39ba60c23e7a 100644
--- a/non-updatable-api/system-current.txt
+++ b/non-updatable-api/system-current.txt
@@ -219,6 +219,7 @@ package android {
field public static final String SET_WALLPAPER_COMPONENT = "android.permission.SET_WALLPAPER_COMPONENT";
field public static final String SHOW_KEYGUARD_MESSAGE = "android.permission.SHOW_KEYGUARD_MESSAGE";
field public static final String SHUTDOWN = "android.permission.SHUTDOWN";
+ field public static final String STATUS_BAR_SERVICE = "android.permission.STATUS_BAR_SERVICE";
field public static final String STOP_APP_SWITCHES = "android.permission.STOP_APP_SWITCHES";
field public static final String SUBSTITUTE_NOTIFICATION_APP_NAME = "android.permission.SUBSTITUTE_NOTIFICATION_APP_NAME";
field public static final String SUBSTITUTE_SHARE_TARGET_APP_NAME_AND_ICON = "android.permission.SUBSTITUTE_SHARE_TARGET_APP_NAME_AND_ICON";
@@ -1680,6 +1681,7 @@ package android.content {
field public static final String ETHERNET_SERVICE = "ethernet";
field public static final String EUICC_CARD_SERVICE = "euicc_card";
field public static final String HDMI_CONTROL_SERVICE = "hdmi_control";
+ field public static final String MEDIA_TRANSCODING_SERVICE = "media_transcoding";
field public static final String NETD_SERVICE = "netd";
field public static final String NETWORK_SCORE_SERVICE = "network_score";
field public static final String OEM_LOCK_SERVICE = "oem_lock";
@@ -4137,8 +4139,10 @@ package android.media {
public class AudioManager {
method @Deprecated public int abandonAudioFocus(android.media.AudioManager.OnAudioFocusChangeListener, android.media.AudioAttributes);
method @Deprecated @RequiresPermission(android.Manifest.permission.MODIFY_AUDIO_ROUTING) public void addOnPreferredDeviceForStrategyChangedListener(@NonNull java.util.concurrent.Executor, @NonNull android.media.AudioManager.OnPreferredDeviceForStrategyChangedListener) throws java.lang.SecurityException;
+ method @RequiresPermission(android.Manifest.permission.MODIFY_AUDIO_ROUTING) public void addOnPreferredDevicesForCapturePresetChangedListener(@NonNull java.util.concurrent.Executor, @NonNull android.media.AudioManager.OnPreferredDevicesForCapturePresetChangedListener) throws java.lang.SecurityException;
method @RequiresPermission(android.Manifest.permission.MODIFY_AUDIO_ROUTING) public void addOnPreferredDevicesForStrategyChangedListener(@NonNull java.util.concurrent.Executor, @NonNull android.media.AudioManager.OnPreferredDevicesForStrategyChangedListener) throws java.lang.SecurityException;
method public void clearAudioServerStateCallback();
+ method @RequiresPermission(android.Manifest.permission.MODIFY_AUDIO_ROUTING) public boolean clearPreferredDevicesForCapturePreset(int);
method @RequiresPermission(android.Manifest.permission.MODIFY_AUDIO_ROUTING) public int dispatchAudioFocusChange(@NonNull android.media.AudioFocusInfo, int, @NonNull android.media.audiopolicy.AudioPolicy);
method @IntRange(from=0) public long getAdditionalOutputDeviceDelay(@NonNull android.media.AudioDeviceInfo);
method @NonNull @RequiresPermission(android.Manifest.permission.MODIFY_AUDIO_ROUTING) public static java.util.List<android.media.audiopolicy.AudioProductStrategy> getAudioProductStrategies();
@@ -4149,6 +4153,7 @@ package android.media {
method @IntRange(from=0) @RequiresPermission(android.Manifest.permission.MODIFY_AUDIO_ROUTING) public int getMaxVolumeIndexForAttributes(@NonNull android.media.AudioAttributes);
method @IntRange(from=0) @RequiresPermission(android.Manifest.permission.MODIFY_AUDIO_ROUTING) public int getMinVolumeIndexForAttributes(@NonNull android.media.AudioAttributes);
method @Nullable @RequiresPermission(android.Manifest.permission.MODIFY_AUDIO_ROUTING) public android.media.AudioDeviceAttributes getPreferredDeviceForStrategy(@NonNull android.media.audiopolicy.AudioProductStrategy);
+ method @NonNull @RequiresPermission(android.Manifest.permission.MODIFY_AUDIO_ROUTING) public java.util.List<android.media.AudioDeviceAttributes> getPreferredDevicesForCapturePreset(int);
method @NonNull @RequiresPermission(android.Manifest.permission.MODIFY_AUDIO_ROUTING) public java.util.List<android.media.AudioDeviceAttributes> getPreferredDevicesForStrategy(@NonNull android.media.audiopolicy.AudioProductStrategy);
method @NonNull @RequiresPermission(android.Manifest.permission.MODIFY_AUDIO_ROUTING) public int[] getSupportedSystemUsages();
method @IntRange(from=0) @RequiresPermission(android.Manifest.permission.MODIFY_AUDIO_ROUTING) public int getVolumeIndexForAttributes(@NonNull android.media.AudioAttributes);
@@ -4157,6 +4162,7 @@ package android.media {
method @RequiresPermission(android.Manifest.permission.MODIFY_AUDIO_ROUTING) public int registerAudioPolicy(@NonNull android.media.audiopolicy.AudioPolicy);
method public void registerVolumeGroupCallback(@NonNull java.util.concurrent.Executor, @NonNull android.media.AudioManager.VolumeGroupCallback);
method @Deprecated @RequiresPermission(android.Manifest.permission.MODIFY_AUDIO_ROUTING) public void removeOnPreferredDeviceForStrategyChangedListener(@NonNull android.media.AudioManager.OnPreferredDeviceForStrategyChangedListener);
+ method @RequiresPermission(android.Manifest.permission.MODIFY_AUDIO_ROUTING) public void removeOnPreferredDevicesForCapturePresetChangedListener(@NonNull android.media.AudioManager.OnPreferredDevicesForCapturePresetChangedListener);
method @RequiresPermission(android.Manifest.permission.MODIFY_AUDIO_ROUTING) public void removeOnPreferredDevicesForStrategyChangedListener(@NonNull android.media.AudioManager.OnPreferredDevicesForStrategyChangedListener);
method @RequiresPermission(android.Manifest.permission.MODIFY_AUDIO_ROUTING) public boolean removePreferredDeviceForStrategy(@NonNull android.media.audiopolicy.AudioProductStrategy);
method @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) public int requestAudioFocus(android.media.AudioManager.OnAudioFocusChangeListener, @NonNull android.media.AudioAttributes, int, int) throws java.lang.IllegalArgumentException;
@@ -4166,6 +4172,7 @@ package android.media {
method public void setAudioServerStateCallback(@NonNull java.util.concurrent.Executor, @NonNull android.media.AudioManager.AudioServerStateCallback);
method @RequiresPermission(android.Manifest.permission.MODIFY_AUDIO_ROUTING) public void setDeviceVolumeBehavior(@NonNull android.media.AudioDeviceAttributes, int);
method @RequiresPermission(android.Manifest.permission.MODIFY_AUDIO_ROUTING) public void setFocusRequestResult(@NonNull android.media.AudioFocusInfo, int, @NonNull android.media.audiopolicy.AudioPolicy);
+ method @RequiresPermission(android.Manifest.permission.MODIFY_AUDIO_ROUTING) public boolean setPreferredDeviceForCapturePreset(int, @NonNull android.media.AudioDeviceAttributes);
method @RequiresPermission(android.Manifest.permission.MODIFY_AUDIO_ROUTING) public boolean setPreferredDeviceForStrategy(@NonNull android.media.audiopolicy.AudioProductStrategy, @NonNull android.media.AudioDeviceAttributes);
method @RequiresPermission(android.Manifest.permission.MODIFY_AUDIO_ROUTING) public boolean setPreferredDevicesForStrategy(@NonNull android.media.audiopolicy.AudioProductStrategy, @NonNull java.util.List<android.media.AudioDeviceAttributes>);
method @RequiresPermission(android.Manifest.permission.MODIFY_AUDIO_ROUTING) public void setSupportedSystemUsages(@NonNull int[]);
@@ -4195,6 +4202,10 @@ package android.media {
method @Deprecated public void onPreferredDeviceForStrategyChanged(@NonNull android.media.audiopolicy.AudioProductStrategy, @Nullable android.media.AudioDeviceAttributes);
}
+ public static interface AudioManager.OnPreferredDevicesForCapturePresetChangedListener {
+ method public void onPreferredDevicesForCapturePresetChanged(int, @NonNull java.util.List<android.media.AudioDeviceAttributes>);
+ }
+
public static interface AudioManager.OnPreferredDevicesForStrategyChangedListener {
method public void onPreferredDevicesForStrategyChanged(@NonNull android.media.audiopolicy.AudioProductStrategy, @NonNull java.util.List<android.media.AudioDeviceAttributes>);
}
@@ -4272,6 +4283,60 @@ package android.media {
field @RequiresPermission(android.Manifest.permission.CAPTURE_AUDIO_OUTPUT) public static final int RADIO_TUNER = 1998; // 0x7ce
}
+ public final class MediaTranscodeManager implements java.lang.AutoCloseable {
+ method public void close();
+ method @NonNull public android.media.MediaTranscodeManager.TranscodingJob enqueueRequest(@NonNull android.media.MediaTranscodeManager.TranscodingRequest, @NonNull java.util.concurrent.Executor, @NonNull android.media.MediaTranscodeManager.OnTranscodingFinishedListener) throws java.io.FileNotFoundException;
+ method protected void finalize();
+ field public static final int PRIORITY_OFFLINE = 2; // 0x2
+ field public static final int PRIORITY_REALTIME = 1; // 0x1
+ field public static final int TRANSCODING_TYPE_VIDEO = 1; // 0x1
+ }
+
+ @java.lang.FunctionalInterface public static interface MediaTranscodeManager.OnTranscodingFinishedListener {
+ method public void onTranscodingFinished(@NonNull android.media.MediaTranscodeManager.TranscodingJob);
+ }
+
+ public static final class MediaTranscodeManager.TranscodingJob {
+ method public void cancel();
+ method public int getJobId();
+ method @IntRange(from=0, to=100) public int getProgress();
+ method public int getResult();
+ method public int getStatus();
+ method public boolean retry();
+ method public void setOnProgressUpdateListener(@NonNull java.util.concurrent.Executor, @Nullable android.media.MediaTranscodeManager.TranscodingJob.OnProgressUpdateListener);
+ method public void setOnProgressUpdateListener(int, @NonNull java.util.concurrent.Executor, @Nullable android.media.MediaTranscodeManager.TranscodingJob.OnProgressUpdateListener);
+ field public static final int RESULT_CANCELED = 4; // 0x4
+ field public static final int RESULT_ERROR = 3; // 0x3
+ field public static final int RESULT_NONE = 1; // 0x1
+ field public static final int RESULT_SUCCESS = 2; // 0x2
+ field public static final int STATUS_FINISHED = 3; // 0x3
+ field public static final int STATUS_PAUSED = 4; // 0x4
+ field public static final int STATUS_PENDING = 1; // 0x1
+ field public static final int STATUS_RUNNING = 2; // 0x2
+ }
+
+ @java.lang.FunctionalInterface public static interface MediaTranscodeManager.TranscodingJob.OnProgressUpdateListener {
+ method public void onProgressUpdate(@IntRange(from=0, to=100) int);
+ }
+
+ public static final class MediaTranscodeManager.TranscodingRequest {
+ method @NonNull public android.net.Uri getDestinationUri();
+ method public int getPriority();
+ method @NonNull public android.net.Uri getSourceUri();
+ method public int getType();
+ method @Nullable public android.media.MediaFormat getVideoTrackFormat();
+ }
+
+ public static final class MediaTranscodeManager.TranscodingRequest.Builder {
+ ctor public MediaTranscodeManager.TranscodingRequest.Builder();
+ method @NonNull public android.media.MediaTranscodeManager.TranscodingRequest build();
+ method @NonNull public android.media.MediaTranscodeManager.TranscodingRequest.Builder setDestinationUri(@NonNull android.net.Uri);
+ method @NonNull public android.media.MediaTranscodeManager.TranscodingRequest.Builder setPriority(int);
+ method @NonNull public android.media.MediaTranscodeManager.TranscodingRequest.Builder setSourceUri(@NonNull android.net.Uri);
+ method @NonNull public android.media.MediaTranscodeManager.TranscodingRequest.Builder setType(int);
+ method @NonNull public android.media.MediaTranscodeManager.TranscodingRequest.Builder setVideoTrackFormat(@NonNull android.media.MediaFormat);
+ }
+
public class PlayerProxy {
method public void pause();
method public void setPan(float);
diff --git a/packages/CarSystemUI/res/drawable/car_ic_apps.xml b/packages/CarSystemUI/res/drawable/car_ic_apps.xml
index a8d8a2f241f6..e028a0ed45c9 100644
--- a/packages/CarSystemUI/res/drawable/car_ic_apps.xml
+++ b/packages/CarSystemUI/res/drawable/car_ic_apps.xml
@@ -15,11 +15,11 @@
~ limitations under the License
-->
<vector xmlns:android="http://schemas.android.com/apk/res/android"
+ android:width="@dimen/system_bar_icon_drawing_size"
+ android:height="@dimen/system_bar_icon_drawing_size"
android:viewportWidth="44"
- android:viewportHeight="44"
- android:width="44dp"
- android:height="44dp">
-<path
- android:pathData="M7.33333333 14.6666667L14.6666667 14.6666667L14.6666667 7.33333333L7.33333333 7.33333333L7.33333333 14.6666667ZM18.3333333 36.6666667L25.6666667 36.6666667L25.6666667 29.3333333L18.3333333 29.3333333L18.3333333 36.6666667ZM7.33333333 36.6666667L14.6666667 36.6666667L14.6666667 29.3333333L7.33333333 29.3333333L7.33333333 36.6666667ZM7.33333333 25.6666667L14.6666667 25.6666667L14.6666667 18.3333333L7.33333333 18.3333333L7.33333333 25.6666667ZM18.3333333 25.6666667L25.6666667 25.6666667L25.6666667 18.3333333L18.3333333 18.3333333L18.3333333 25.6666667ZM29.3333333 7.33333333L29.3333333 14.6666667L36.6666667 14.6666667L36.6666667 7.33333333L29.3333333 7.33333333ZM18.3333333 14.6666667L25.6666667 14.6666667L25.6666667 7.33333333L18.3333333 7.33333333L18.3333333 14.6666667ZM29.3333333 25.6666667L36.6666667 25.6666667L36.6666667 18.3333333L29.3333333 18.3333333L29.3333333 25.6666667ZM29.3333333 36.6666667L36.6666667 36.6666667L36.6666667 29.3333333L29.3333333 29.3333333L29.3333333 36.6666667Z"
- android:fillColor="@color/car_nav_icon_fill_color" />
+ android:viewportHeight="44">
+ <path
+ android:pathData="M7.33333333 14.6666667L14.6666667 14.6666667L14.6666667 7.33333333L7.33333333 7.33333333L7.33333333 14.6666667ZM18.3333333 36.6666667L25.6666667 36.6666667L25.6666667 29.3333333L18.3333333 29.3333333L18.3333333 36.6666667ZM7.33333333 36.6666667L14.6666667 36.6666667L14.6666667 29.3333333L7.33333333 29.3333333L7.33333333 36.6666667ZM7.33333333 25.6666667L14.6666667 25.6666667L14.6666667 18.3333333L7.33333333 18.3333333L7.33333333 25.6666667ZM18.3333333 25.6666667L25.6666667 25.6666667L25.6666667 18.3333333L18.3333333 18.3333333L18.3333333 25.6666667ZM29.3333333 7.33333333L29.3333333 14.6666667L36.6666667 14.6666667L36.6666667 7.33333333L29.3333333 7.33333333ZM18.3333333 14.6666667L25.6666667 14.6666667L25.6666667 7.33333333L18.3333333 7.33333333L18.3333333 14.6666667ZM29.3333333 25.6666667L36.6666667 25.6666667L36.6666667 18.3333333L29.3333333 18.3333333L29.3333333 25.6666667ZM29.3333333 36.6666667L36.6666667 36.6666667L36.6666667 29.3333333L29.3333333 29.3333333L29.3333333 36.6666667Z"
+ android:fillColor="@color/car_nav_icon_fill_color" />
</vector> \ No newline at end of file
diff --git a/packages/CarSystemUI/res/drawable/car_ic_apps_selected.xml b/packages/CarSystemUI/res/drawable/car_ic_apps_selected.xml
index 2a4e91aa3cd9..9504e61e53e4 100644
--- a/packages/CarSystemUI/res/drawable/car_ic_apps_selected.xml
+++ b/packages/CarSystemUI/res/drawable/car_ic_apps_selected.xml
@@ -15,10 +15,10 @@
~ limitations under the License
-->
<vector xmlns:android="http://schemas.android.com/apk/res/android"
+ android:width="@dimen/system_bar_icon_drawing_size"
+ android:height="@dimen/system_bar_icon_drawing_size"
android:viewportWidth="44"
- android:viewportHeight="44"
- android:width="44dp"
- android:height="44dp">
+ android:viewportHeight="44">
<path
android:pathData="M7.33333333 14.6666667L14.6666667 14.6666667L14.6666667 7.33333333L7.33333333 7.33333333L7.33333333 14.6666667ZM18.3333333 36.6666667L25.6666667 36.6666667L25.6666667 29.3333333L18.3333333 29.3333333L18.3333333 36.6666667ZM7.33333333 36.6666667L14.6666667 36.6666667L14.6666667 29.3333333L7.33333333 29.3333333L7.33333333 36.6666667ZM7.33333333 25.6666667L14.6666667 25.6666667L14.6666667 18.3333333L7.33333333 18.3333333L7.33333333 25.6666667ZM18.3333333 25.6666667L25.6666667 25.6666667L25.6666667 18.3333333L18.3333333 18.3333333L18.3333333 25.6666667ZM29.3333333 7.33333333L29.3333333 14.6666667L36.6666667 14.6666667L36.6666667 7.33333333L29.3333333 7.33333333ZM18.3333333 14.6666667L25.6666667 14.6666667L25.6666667 7.33333333L18.3333333 7.33333333L18.3333333 14.6666667ZM29.3333333 25.6666667L36.6666667 25.6666667L36.6666667 18.3333333L29.3333333 18.3333333L29.3333333 25.6666667ZM29.3333333 36.6666667L36.6666667 36.6666667L36.6666667 29.3333333L29.3333333 29.3333333L29.3333333 36.6666667Z"
android:fillColor="@color/car_nav_icon_fill_color_selected" />
diff --git a/packages/CarSystemUI/res/drawable/car_ic_home.xml b/packages/CarSystemUI/res/drawable/car_ic_home.xml
new file mode 100644
index 000000000000..c78f0edd5594
--- /dev/null
+++ b/packages/CarSystemUI/res/drawable/car_ic_home.xml
@@ -0,0 +1,25 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ ~ 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.
+ -->
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+ android:width="@dimen/system_bar_icon_drawing_size"
+ android:height="@dimen/system_bar_icon_drawing_size"
+ android:viewportWidth="24"
+ android:viewportHeight="24">
+ <path
+ android:pathData="M10,20v-6h4v6h5v-8h3L12,3 2,12h3v8z"
+ android:fillColor="@color/car_nav_icon_fill_color" />
+</vector> \ No newline at end of file
diff --git a/packages/CarSystemUI/res/drawable/car_ic_home_selected.xml b/packages/CarSystemUI/res/drawable/car_ic_home_selected.xml
new file mode 100644
index 000000000000..16192df86676
--- /dev/null
+++ b/packages/CarSystemUI/res/drawable/car_ic_home_selected.xml
@@ -0,0 +1,25 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ ~ 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.
+ -->
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+ android:width="@dimen/system_bar_icon_drawing_size"
+ android:height="@dimen/system_bar_icon_drawing_size"
+ android:viewportWidth="24"
+ android:viewportHeight="24">
+ <path
+ android:pathData="M10,20v-6h4v6h5v-8h3L12,3 2,12h3v8z"
+ android:fillColor="@color/car_nav_icon_fill_color_selected" />
+</vector> \ No newline at end of file
diff --git a/packages/CarSystemUI/res/drawable/car_ic_hvac.xml b/packages/CarSystemUI/res/drawable/car_ic_hvac.xml
index bdc44b38a176..55c968eacc4d 100644
--- a/packages/CarSystemUI/res/drawable/car_ic_hvac.xml
+++ b/packages/CarSystemUI/res/drawable/car_ic_hvac.xml
@@ -1,3 +1,4 @@
+<?xml version="1.0" encoding="utf-8"?>
<!--
Copyright (C) 2018 The Android Open Source Project
@@ -14,38 +15,11 @@
limitations under the License.
-->
<vector xmlns:android="http://schemas.android.com/apk/res/android"
- android:width="37dp"
- android:height="31dp"
- android:viewportWidth="37"
- android:viewportHeight="31">
-
- <group
- android:translateX="-4.000000"
- android:translateY="-6.000000">
- <group
- android:translateX="5.000000"
- android:translateY="5.000000">
- <path
- android:fillType="evenOdd"
- android:strokeColor="#FAFAFA"
- android:strokeWidth="3.5"
- android:pathData="M0.320769938,6.07518051 C6.46754647,1.46509811 12.4222362,1.46509811
-18.1848392,6.07518051 C23.9474422,10.6852629 29.3258717,10.4931761
-34.3201276,5.49892021" />
- <path
- android:fillType="evenOdd"
- android:strokeColor="#FAFAFA"
- android:strokeWidth="3.5"
- android:pathData="M0.320769938,17.0751805 C6.46754647,12.4650981 12.4222362,12.4650981
-18.1848392,17.0751805 C23.9474422,21.6852629 29.3258717,21.4931761
-34.3201276,16.4989202" />
- <path
- android:fillType="evenOdd"
- android:strokeColor="#FAFAFA"
- android:strokeWidth="3.5"
- android:pathData="M0.320769938,28.0751805 C6.46754647,23.4650981 12.4222362,23.4650981
-18.1848392,28.0751805 C23.9474422,32.6852629 29.3258717,32.4931761
-34.3201276,27.4989202" />
- </group>
- </group>
-</vector> \ No newline at end of file
+ android:width="@dimen/system_bar_icon_drawing_size"
+ android:height="@dimen/system_bar_icon_drawing_size"
+ android:viewportWidth="24"
+ android:viewportHeight="24">
+ <path
+ android:pathData="M16.34,8.36l-2.29,0.82c-0.18,-0.13 -0.38,-0.25 -0.58,-0.34c0.17,-0.83 0.63,-1.58 1.36,-2.06C16.85,5.44 16.18,2 13.39,2C9,2 7.16,5.01 8.36,7.66l0.82,2.29c-0.13,0.18 -0.25,0.38 -0.34,0.58c-0.83,-0.17 -1.58,-0.63 -2.06,-1.36C5.44,7.15 2,7.82 2,10.61c0,4.4 3.01,6.24 5.66,5.03l2.29,-0.82c0.18,0.13 0.38,0.25 0.58,0.34c-0.17,0.83 -0.63,1.58 -1.36,2.06C7.15,18.56 7.82,22 10.61,22c4.4,0 6.24,-3.01 5.03,-5.66l-0.82,-2.29c0.13,-0.18 0.25,-0.38 0.34,-0.58c0.83,0.17 1.58,0.63 2.06,1.36c1.34,2.01 4.77,1.34 4.77,-1.45C22,9 18.99,7.16 16.34,8.36zM12,13.5c-0.83,0 -1.5,-0.67 -1.5,-1.5c0,-0.83 0.67,-1.5 1.5,-1.5c0.83,0 1.5,0.67 1.5,1.5C13.5,12.83 12.83,13.5 12,13.5zM10.24,5.22C10.74,4.44 11.89,4 13.39,4c0.79,0 0.71,0.86 0.34,1.11c-1.22,0.81 -2,2.06 -2.25,3.44c-0.21,0.03 -0.42,0.08 -0.62,0.15l-0.68,-1.88C10,6.42 9.86,5.81 10.24,5.22zM6.83,13.82c-0.4,0.18 -1.01,0.32 -1.61,-0.06C4.44,13.26 4,12.11 4,10.61c0,-0.79 0.86,-0.71 1.11,-0.34c0.81,1.22 2.06,2 3.44,2.25c0.03,0.21 0.08,0.42 0.15,0.62L6.83,13.82zM13.76,18.78c-0.5,0.77 -1.65,1.22 -3.15,1.22c-0.79,0 -0.71,-0.86 -0.34,-1.11c1.22,-0.81 2,-2.06 2.25,-3.44c0.21,-0.03 0.42,-0.08 0.62,-0.15l0.68,1.88C14,17.58 14.14,18.18 13.76,18.78zM18.89,13.73c-0.81,-1.22 -2.06,-2 -3.44,-2.25c-0.03,-0.21 -0.08,-0.42 -0.15,-0.62l1.88,-0.68c0.4,-0.18 1.01,-0.32 1.61,0.06c0.77,0.5 1.22,1.65 1.22,3.15C20,14.19 19.14,14.11 18.89,13.73z"
+ android:fillColor="@color/car_nav_icon_fill_color" />
+</vector>
diff --git a/packages/CarSystemUI/res/drawable/car_ic_hvac_selected.xml b/packages/CarSystemUI/res/drawable/car_ic_hvac_selected.xml
new file mode 100644
index 000000000000..817b7148ecdd
--- /dev/null
+++ b/packages/CarSystemUI/res/drawable/car_ic_hvac_selected.xml
@@ -0,0 +1,25 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ ~ 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.
+ -->
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+ android:width="@dimen/system_bar_icon_drawing_size"
+ android:height="@dimen/system_bar_icon_drawing_size"
+ android:viewportWidth="24"
+ android:viewportHeight="24">
+ <path
+ android:pathData="M16.34,8.36l-2.29,0.82c-0.18,-0.13 -0.38,-0.25 -0.58,-0.34c0.17,-0.83 0.63,-1.58 1.36,-2.06C16.85,5.44 16.18,2 13.39,2C9,2 7.16,5.01 8.36,7.66l0.82,2.29c-0.13,0.18 -0.25,0.38 -0.34,0.58c-0.83,-0.17 -1.58,-0.63 -2.06,-1.36C5.44,7.15 2,7.82 2,10.61c0,4.4 3.01,6.24 5.66,5.03l2.29,-0.82c0.18,0.13 0.38,0.25 0.58,0.34c-0.17,0.83 -0.63,1.58 -1.36,2.06C7.15,18.56 7.82,22 10.61,22c4.4,0 6.24,-3.01 5.03,-5.66l-0.82,-2.29c0.13,-0.18 0.25,-0.38 0.34,-0.58c0.83,0.17 1.58,0.63 2.06,1.36c1.34,2.01 4.77,1.34 4.77,-1.45C22,9 18.99,7.16 16.34,8.36zM12,13.5c-0.83,0 -1.5,-0.67 -1.5,-1.5c0,-0.83 0.67,-1.5 1.5,-1.5c0.83,0 1.5,0.67 1.5,1.5C13.5,12.83 12.83,13.5 12,13.5zM10.24,5.22C10.74,4.44 11.89,4 13.39,4c0.79,0 0.71,0.86 0.34,1.11c-1.22,0.81 -2,2.06 -2.25,3.44c-0.21,0.03 -0.42,0.08 -0.62,0.15l-0.68,-1.88C10,6.42 9.86,5.81 10.24,5.22zM6.83,13.82c-0.4,0.18 -1.01,0.32 -1.61,-0.06C4.44,13.26 4,12.11 4,10.61c0,-0.79 0.86,-0.71 1.11,-0.34c0.81,1.22 2.06,2 3.44,2.25c0.03,0.21 0.08,0.42 0.15,0.62L6.83,13.82zM13.76,18.78c-0.5,0.77 -1.65,1.22 -3.15,1.22c-0.79,0 -0.71,-0.86 -0.34,-1.11c1.22,-0.81 2,-2.06 2.25,-3.44c0.21,-0.03 0.42,-0.08 0.62,-0.15l0.68,1.88C14,17.58 14.14,18.18 13.76,18.78zM18.89,13.73c-0.81,-1.22 -2.06,-2 -3.44,-2.25c-0.03,-0.21 -0.08,-0.42 -0.15,-0.62l1.88,-0.68c0.4,-0.18 1.01,-0.32 1.61,0.06c0.77,0.5 1.22,1.65 1.22,3.15C20,14.19 19.14,14.11 18.89,13.73z"
+ android:fillColor="@color/car_nav_icon_fill_color_selected" />
+</vector> \ No newline at end of file
diff --git a/packages/CarSystemUI/res/drawable/car_ic_notification.xml b/packages/CarSystemUI/res/drawable/car_ic_notification.xml
index 9d9ad0fdf9c5..aabf9161c11f 100644
--- a/packages/CarSystemUI/res/drawable/car_ic_notification.xml
+++ b/packages/CarSystemUI/res/drawable/car_ic_notification.xml
@@ -15,10 +15,10 @@
~ limitations under the License
-->
<vector xmlns:android="http://schemas.android.com/apk/res/android"
- android:viewportWidth="44"
- android:viewportHeight="44"
- android:width="44dp"
- android:height="44dp">
+ android:width="@dimen/system_bar_icon_drawing_size"
+ android:height="@dimen/system_bar_icon_drawing_size"
+ android:viewportWidth="44"
+ android:viewportHeight="44">
<path
android:pathData="M22 39.125C23.925 39.125 25.5 37.55 25.5 35.625L18.5 35.625C18.5 37.55 20.0575 39.125 22 39.125ZM32.5 28.625L32.5 19.875C32.5 14.5025 29.63 10.005 24.625 8.815L24.625 7.625C24.625 6.1725 23.4525 5 22 5C20.5475 5 19.375 6.1725 19.375 7.625L19.375 8.815C14.3525 10.005 11.5 14.485 11.5 19.875L11.5 28.625L8 32.125L8 33.875L36 33.875L36 32.125L32.5 28.625Z"
android:fillColor="@color/car_nav_icon_fill_color" />
diff --git a/packages/CarSystemUI/res/drawable/car_ic_user_icon.xml b/packages/CarSystemUI/res/drawable/car_ic_user_icon.xml
new file mode 100644
index 000000000000..1195d05da228
--- /dev/null
+++ b/packages/CarSystemUI/res/drawable/car_ic_user_icon.xml
@@ -0,0 +1,25 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ ~ 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.
+ -->
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+ android:width="@dimen/system_bar_icon_drawing_size"
+ android:height="@dimen/system_bar_icon_drawing_size"
+ android:viewportWidth="24"
+ android:viewportHeight="24">
+ <path
+ android:pathData="M12,12c2.21,0 4,-1.79 4,-4s-1.79,-4 -4,-4 -4,1.79 -4,4 1.79,4 4,4zM12,14c-2.67,0 -8,1.34 -8,4v2h16v-2c0,-2.66 -5.33,-4 -8,-4z"
+ android:fillColor="@color/system_bar_user_icon_color"/>
+</vector> \ No newline at end of file
diff --git a/packages/CarSystemUI/res/drawable/hvac_decrease_button.xml b/packages/CarSystemUI/res/drawable/hvac_decrease_button.xml
new file mode 100644
index 000000000000..469ac91073f9
--- /dev/null
+++ b/packages/CarSystemUI/res/drawable/hvac_decrease_button.xml
@@ -0,0 +1,53 @@
+<?xml version="1.0" encoding="UTF-8" ?>
+<!--
+ ~ 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.
+ -->
+
+<layer-list
+ xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:aapt="http://schemas.android.com/aapt">
+ <item android:gravity="center"
+ android:width="@dimen/system_bar_icon_drawing_size"
+ android:height="@dimen/system_bar_icon_drawing_size">
+ <aapt:attr name="android:drawable">
+ <shape android:shape="oval">
+ <size
+ android:width="@dimen/system_bar_icon_drawing_size"
+ android:height="@dimen/system_bar_icon_drawing_size"/>
+ <solid
+ android:color="#3C4043"/>
+ </shape>
+ </aapt:attr>
+ </item>
+ <item android:gravity="center"
+ android:width="48dp"
+ android:height="48dp">
+ <aapt:attr name="android:drawable">
+ <vector android:width="48dp"
+ android:height="48dp"
+ android:viewportWidth="24.0"
+ android:viewportHeight="24.0">
+ <path
+ android:fillColor="#8AB4F8"
+ android:pathData="M14,7l-5,5 5,5V7z"/>
+ </vector>
+ </aapt:attr>
+ </item>
+ <item>
+ <aapt:attr name="android:drawable">
+ <ripple android:color="?android:attr/colorControlHighlight"/>
+ </aapt:attr>
+ </item>
+</layer-list> \ No newline at end of file
diff --git a/packages/CarSystemUI/res/drawable/hvac_increase_button.xml b/packages/CarSystemUI/res/drawable/hvac_increase_button.xml
new file mode 100644
index 000000000000..a3fca2233ddd
--- /dev/null
+++ b/packages/CarSystemUI/res/drawable/hvac_increase_button.xml
@@ -0,0 +1,53 @@
+<?xml version="1.0" encoding="UTF-8" ?>
+<!--
+ ~ 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.
+ -->
+
+<layer-list
+ xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:aapt="http://schemas.android.com/aapt">
+ <item android:gravity="center"
+ android:width="@dimen/system_bar_icon_drawing_size"
+ android:height="@dimen/system_bar_icon_drawing_size">
+ <aapt:attr name="android:drawable">
+ <shape android:shape="oval">
+ <size
+ android:width="@dimen/system_bar_icon_drawing_size"
+ android:height="@dimen/system_bar_icon_drawing_size"/>
+ <solid
+ android:color="#3C4043"/>
+ </shape>
+ </aapt:attr>
+ </item>
+ <item android:gravity="center"
+ android:width="48dp"
+ android:height="48dp">
+ <aapt:attr name="android:drawable">
+ <vector android:width="48dp"
+ android:height="48dp"
+ android:viewportWidth="24.0"
+ android:viewportHeight="24.0">
+ <path
+ android:fillColor="#F28B82"
+ android:pathData="M10,17l5,-5 -5,-5v10z"/>
+ </vector>
+ </aapt:attr>
+ </item>
+ <item>
+ <aapt:attr name="android:drawable">
+ <ripple android:color="?android:attr/colorControlHighlight"/>
+ </aapt:attr>
+ </item>
+</layer-list> \ No newline at end of file
diff --git a/packages/CarSystemUI/res/drawable/ic_mic_white.xml b/packages/CarSystemUI/res/drawable/ic_mic_white.xml
index 546b1a894e6a..71fcc5302d75 100644
--- a/packages/CarSystemUI/res/drawable/ic_mic_white.xml
+++ b/packages/CarSystemUI/res/drawable/ic_mic_white.xml
@@ -15,11 +15,11 @@
~ limitations under the License
-->
<vector xmlns:android="http://schemas.android.com/apk/res/android"
- android:viewportWidth="44"
- android:viewportHeight="44"
- android:width="44dp"
- android:height="44dp">
- <path
+ android:width="@dimen/system_bar_icon_drawing_size"
+ android:height="@dimen/system_bar_icon_drawing_size"
+ android:viewportWidth="44"
+ android:viewportHeight="44">
+<path
android:pathData="M22 25.6666667C25.0433333 25.6666667 27.4816667 23.21 27.4816667 20.1666667L27.5 9.16666667C27.5 6.12333333 25.0433333 3.66666667 22 3.66666667C18.9566667 3.66666667 16.5 6.12333333 16.5 9.16666667L16.5 20.1666667C16.5 23.21 18.9566667 25.6666667 22 25.6666667ZM31.7166667 20.1666667C31.7166667 25.6666667 27.06 29.5166667 22 29.5166667C16.94 29.5166667 12.2833333 25.6666667 12.2833333 20.1666667L9.16666667 20.1666667C9.16666667 26.4183333 14.1533333 31.5883333 20.1666667 32.4866667L20.1666667 38.5L23.8333333 38.5L23.8333333 32.4866667C29.8466667 31.6066667 34.8333333 26.4366667 34.8333333 20.1666667L31.7166667 20.1666667Z"
android:fillColor="@color/car_nav_icon_fill_color" />
</vector> \ No newline at end of file
diff --git a/packages/CarSystemUI/res/layout/adjustable_temperature_view.xml b/packages/CarSystemUI/res/layout/adjustable_temperature_view.xml
new file mode 100644
index 000000000000..d19740932aa4
--- /dev/null
+++ b/packages/CarSystemUI/res/layout/adjustable_temperature_view.xml
@@ -0,0 +1,50 @@
+<?xml version="1.0" encoding="UTF-8" ?>
+<!--
+ ~ 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.
+ -->
+
+<LinearLayout
+ xmlns:android="http://schemas.android.com/apk/res/android"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:orientation="horizontal"
+ android:gravity="center_vertical"
+ android:paddingEnd="@dimen/hvac_container_padding"
+ android:paddingStart="@dimen/hvac_container_padding">
+
+ <ImageView
+ android:id="@+id/hvac_decrease_button"
+ android:layout_width="@dimen/hvac_temperature_button_size"
+ android:layout_height="@dimen/hvac_temperature_button_size"
+ android:scaleType="center"
+ android:src="@drawable/hvac_decrease_button"/>
+
+ <TextView
+ android:id="@+id/hvac_temperature_text"
+ android:layout_width="wrap_content"
+ android:layout_height="match_parent"
+ android:textSize="@dimen/hvac_temperature_text_size"
+ android:textColor="@color/system_bar_text_color"
+ android:paddingStart="@dimen/hvac_temperature_text_padding"
+ android:paddingEnd="@dimen/hvac_temperature_text_padding"
+ android:gravity="center"/>
+
+ <ImageView
+ android:id="@+id/hvac_increase_button"
+ android:layout_width="@dimen/hvac_temperature_button_size"
+ android:layout_height="@dimen/hvac_temperature_button_size"
+ android:scaleType="center"
+ android:src="@drawable/hvac_increase_button" />
+</LinearLayout> \ No newline at end of file
diff --git a/packages/CarSystemUI/res/layout/car_navigation_bar.xml b/packages/CarSystemUI/res/layout/car_navigation_bar.xml
index a49a6373a252..b07dde582e5f 100644
--- a/packages/CarSystemUI/res/layout/car_navigation_bar.xml
+++ b/packages/CarSystemUI/res/layout/car_navigation_bar.xml
@@ -1,6 +1,6 @@
<?xml version="1.0" encoding="utf-8"?>
<!--
- ~ Copyright (C) 2018 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.
@@ -12,7 +12,7 @@
~ 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
+ ~ limitations under the License.
-->
<com.android.systemui.car.navigationbar.CarNavigationBarView
@@ -21,115 +21,115 @@
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="@drawable/system_bar_background"
- android:orientation="vertical">
- <!--The 20dp padding is the difference between the background selected icon size and the ripple
- that was chosen, thus it's a hack to make it look pretty and not an official margin value-->
- <LinearLayout
+ android:gravity="center"
+ android:orientation="horizontal">
+
+ <RelativeLayout
android:id="@+id/nav_buttons"
android:layout_width="match_parent"
android:layout_height="wrap_content"
- android:layout_weight="1"
- android:gravity="center"
- android:layoutDirection="ltr"
- android:paddingEnd="20dp"
- android:paddingStart="20dp">
+ android:layoutDirection="ltr">
<com.android.systemui.car.navigationbar.CarNavigationButton
- android:id="@+id/home"
- style="@style/NavigationBarButton"
- systemui:componentNames="com.android.car.carlauncher/.CarLauncher"
- systemui:icon="@drawable/car_ic_overview"
- systemui:intent="intent:#Intent;action=android.intent.action.MAIN;category=android.intent.category.HOME;launchFlags=0x14000000;end"
- systemui:selectedIcon="@drawable/car_ic_overview_selected"
- systemui:highlightWhenSelected="true"
- />
-
- <Space
- android:layout_width="0dp"
+ android:layout_width="wrap_content"
android:layout_height="match_parent"
- android:layout_weight="1"/>
-
- <com.android.systemui.car.navigationbar.CarNavigationButton
- android:id="@+id/maps_nav"
- style="@style/NavigationBarButton"
- systemui:categories="android.intent.category.APP_MAPS"
- systemui:icon="@drawable/car_ic_navigation"
- systemui:intent="intent:#Intent;action=android.intent.action.MAIN;category=android.intent.category.APP_MAPS;launchFlags=0x14000000;end"
- systemui:selectedIcon="@drawable/car_ic_navigation_selected"
- systemui:highlightWhenSelected="true"
- />
-
- <Space
- android:layout_width="0dp"
- android:layout_height="match_parent"
- android:layout_weight="1"/>
-
- <com.android.systemui.car.navigationbar.CarNavigationButton
- android:id="@+id/music_nav"
- style="@style/NavigationBarButton"
- systemui:categories="android.intent.category.APP_MUSIC"
- systemui:icon="@drawable/car_ic_music"
- systemui:intent="intent:#Intent;action=android.car.intent.action.MEDIA_TEMPLATE;launchFlags=0x10000000;end"
- systemui:packages="com.android.car.media"
- systemui:selectedIcon="@drawable/car_ic_music_selected"
- systemui:highlightWhenSelected="true"
- />
-
- <Space
- android:layout_width="0dp"
+ android:layout_alignParentStart="true"
+ android:background="@null"
+ systemui:broadcast="true"
+ systemui:intent="intent:#Intent;action=android.car.intent.action.TOGGLE_HVAC_CONTROLS;end">
+
+ <com.android.systemui.car.hvac.AdjustableTemperatureView
+ android:id="@+id/driver_hvac"
+ android:layout_width="wrap_content"
+ android:layout_height="match_parent"
+ android:gravity="center_vertical"
+ systemui:hvacAreaId="49"
+ systemui:hvacTempFormat="%.0f\u00B0" />
+ </com.android.systemui.car.navigationbar.CarNavigationButton>
+
+ <LinearLayout
+ android:layout_width="wrap_content"
android:layout_height="match_parent"
- android:layout_weight="1"/>
+ android:layout_centerInParent="true"
+ android:layout_weight="1"
+ android:gravity="center"
+ android:layoutDirection="ltr"
+ android:paddingEnd="@dimen/system_bar_button_group_padding"
+ android:paddingStart="@dimen/system_bar_button_group_padding">
+
+ <Space
+ android:layout_width="0dp"
+ android:layout_height="match_parent"
+ android:layout_weight="1"/>
+
+ <com.android.systemui.car.navigationbar.CarNavigationButton
+ android:id="@+id/home"
+ style="@style/NavigationBarButton"
+ systemui:componentNames="com.android.car.carlauncher/.CarLauncher"
+ systemui:icon="@drawable/car_ic_home"
+ systemui:intent="intent:#Intent;action=android.intent.action.MAIN;category=android.intent.category.HOME;launchFlags=0x14000000;end"
+ systemui:selectedIcon="@drawable/car_ic_home_selected"/>
+
+ <com.android.systemui.car.navigationbar.CarNavigationButton
+ android:id="@+id/phone_nav"
+ style="@style/NavigationBarButton"
+ systemui:icon="@drawable/car_ic_phone"
+ systemui:intent="intent:#Intent;action=android.intent.action.MAIN;category=android.intent.category.LAUNCHER;package=com.android.car.dialer;launchFlags=0x10000000;end"
+ systemui:packages="com.android.car.dialer"
+ systemui:selectedIcon="@drawable/car_ic_phone_selected"/>
+
+ <com.android.systemui.car.navigationbar.CarNavigationButton
+ android:id="@+id/grid_nav"
+ style="@style/NavigationBarButton"
+ systemui:componentNames="com.android.car.carlauncher/.AppGridActivity"
+ systemui:icon="@drawable/car_ic_apps"
+ systemui:intent="intent:#Intent;component=com.android.car.carlauncher/.AppGridActivity;launchFlags=0x24000000;end"
+ systemui:selectedIcon="@drawable/car_ic_apps_selected"/>
+
+ <com.android.systemui.car.navigationbar.CarNavigationButton
+ android:id="@+id/hvac"
+ style="@style/NavigationBarButton"
+ systemui:icon="@drawable/car_ic_hvac"
+ systemui:intent="intent:#Intent;action=android.car.intent.action.TOGGLE_HVAC_CONTROLS;end"
+ systemui:selectedIcon="@drawable/car_ic_hvac_selected"
+ systemui:broadcast="true"/>
+
+ <com.android.systemui.car.navigationbar.CarNavigationButton
+ android:id="@+id/notifications"
+ style="@style/NavigationBarButton"
+ systemui:icon="@drawable/car_ic_notification"
+ systemui:longIntent="intent:#Intent;component=com.android.car.bugreport/.BugReportActivity;end"/>
+
+ <com.android.systemui.car.navigationbar.AssitantButton
+ android:id="@+id/assist"
+ style="@style/NavigationBarButton"
+ systemui:icon="@drawable/ic_mic_white"
+ systemui:useDefaultAppIconForRole="true"/>
+
+ <Space
+ android:layout_width="0dp"
+ android:layout_height="match_parent"
+ android:layout_weight="1"/>
+ </LinearLayout>
<com.android.systemui.car.navigationbar.CarNavigationButton
- android:id="@+id/phone_nav"
- style="@style/NavigationBarButton"
- systemui:icon="@drawable/car_ic_phone"
- systemui:intent="intent:#Intent;action=android.intent.action.MAIN;category=android.intent.category.LAUNCHER;package=com.android.car.dialer;launchFlags=0x10000000;end"
- systemui:packages="com.android.car.dialer"
- systemui:selectedIcon="@drawable/car_ic_phone_selected"
- systemui:highlightWhenSelected="true"
- />
-
- <Space
- android:layout_width="0dp"
+ android:layout_width="wrap_content"
android:layout_height="match_parent"
- android:layout_weight="1"/>
-
- <com.android.systemui.car.navigationbar.CarNavigationButton
- android:id="@+id/grid_nav"
- style="@style/NavigationBarButton"
- systemui:componentNames="com.android.car.carlauncher/.AppGridActivity"
- systemui:icon="@drawable/car_ic_apps"
- systemui:intent="intent:#Intent;component=com.android.car.carlauncher/.AppGridActivity;launchFlags=0x24000000;end"
- systemui:selectedIcon="@drawable/car_ic_apps_selected"
- systemui:highlightWhenSelected="true"
- />
-
- <Space
- android:layout_width="0dp"
- android:layout_height="match_parent"
- android:layout_weight="1"/>
-
- <com.android.systemui.car.navigationbar.CarNavigationButton
- android:id="@+id/notifications"
- style="@style/NavigationBarButton"
- systemui:icon="@drawable/car_ic_notification"
- systemui:longIntent="intent:#Intent;component=com.android.car.bugreport/.BugReportActivity;end"
- />
-
- <Space
- android:layout_width="0dp"
- android:layout_height="match_parent"
- android:layout_weight="1"/>
-
- <com.android.systemui.car.navigationbar.AssitantButton
- android:id="@+id/assist"
- style="@style/NavigationBarButton"
- systemui:icon="@drawable/ic_mic_white"
- systemui:useDefaultAppIconForRole="true"
- />
-
- </LinearLayout>
+ android:layout_alignParentEnd="true"
+ android:background="@null"
+ systemui:broadcast="true"
+ systemui:intent="intent:#Intent;action=android.car.intent.action.TOGGLE_HVAC_CONTROLS;end">
+
+ <com.android.systemui.car.hvac.AdjustableTemperatureView
+ android:id="@+id/passenger_hvac"
+ android:layout_width="wrap_content"
+ android:layout_height="match_parent"
+ android:layout_alignParentEnd="true"
+ android:gravity="center_vertical"
+ systemui:hvacAreaId="68"
+ systemui:hvacTempFormat="%.0f\u00B0" />
+ </com.android.systemui.car.navigationbar.CarNavigationButton>
+ </RelativeLayout>
<LinearLayout
android:id="@+id/lock_screen_nav_buttons"
@@ -142,5 +142,4 @@
android:paddingStart="@dimen/car_keyline_1"
android:visibility="gone"
/>
-
</com.android.systemui.car.navigationbar.CarNavigationBarView> \ No newline at end of file
diff --git a/packages/CarSystemUI/res/layout/car_top_navigation_bar.xml b/packages/CarSystemUI/res/layout/car_top_navigation_bar.xml
index cdc29eec21cd..af8482a8c6a5 100644
--- a/packages/CarSystemUI/res/layout/car_top_navigation_bar.xml
+++ b/packages/CarSystemUI/res/layout/car_top_navigation_bar.xml
@@ -31,39 +31,44 @@
android:layoutDirection="ltr">
<FrameLayout
- android:id="@+id/left_hvac_container"
+ android:id="@+id/user_name_container"
android:layout_width="wrap_content"
android:layout_height="match_parent"
android:layout_alignParentStart="true"
+ android:layout_toStartOf="@+id/clock_container"
>
<com.android.systemui.car.navigationbar.CarNavigationButton
- android:id="@+id/hvacleft"
+ android:id="@+id/user_name"
android:layout_width="match_parent"
android:layout_height="match_parent"
- android:background="@null"
- systemui:broadcast="true"
- systemui:intent="intent:#Intent;action=android.car.intent.action.TOGGLE_HVAC_CONTROLS;end"
- />
-
- <com.android.systemui.car.hvac.AnimatedTemperatureView
- android:id="@+id/lefttext"
- android:layout_width="wrap_content"
- android:layout_height="match_parent"
- android:paddingStart="@*android:dimen/car_padding_4"
- android:paddingEnd="16dp"
- android:gravity="center_vertical|start"
- android:minEms="4"
- android:textAppearance="@style/TextAppearance.CarStatus"
- systemui:hvacAreaId="49"
- systemui:hvacMaxText="@string/hvac_max_text"
- systemui:hvacMaxValue="@dimen/hvac_max_value"
- systemui:hvacMinText="@string/hvac_min_text"
- systemui:hvacMinValue="@dimen/hvac_min_value"
- systemui:hvacPivotOffset="60dp"
- systemui:hvacPropertyId="358614275"
- systemui:hvacTempFormat="%.0f\u00B0"
- />
+ systemui:icon="@null"
+ systemui:intent="intent:#Intent;component=com.android.car.settings/.users.UserSwitcherActivity;launchFlags=0x24000000;end"
+ >
+ <LinearLayout
+ android:layout_width="match_parent"
+ android:layout_height="match_parent"
+ android:orientation="horizontal"
+ android:gravity="center_vertical"
+ >
+ <ImageView
+ android:id="@+id/user_avatar"
+ android:layout_width="wrap_content"
+ android:layout_height="match_parent"
+ android:src="@drawable/car_ic_user_icon"
+ android:paddingLeft="@dimen/system_bar_user_icon_padding"
+ android:paddingRight="@dimen/system_bar_user_icon_padding"
+ />
+ <TextView
+ android:id="@+id/user_name_text"
+ android:layout_width="wrap_content"
+ android:layout_height="match_parent"
+ android:gravity="center_vertical"
+ android:textAppearance="@style/TextAppearance.SystemBar.Username"
+ android:maxLines="1"
+ />
+ </LinearLayout>
+ </com.android.systemui.car.navigationbar.CarNavigationButton>
</FrameLayout>
<FrameLayout
@@ -86,7 +91,8 @@
android:layout_gravity="center"
android:elevation="5dp"
android:singleLine="true"
- android:textAppearance="@style/TextAppearance.StatusBar.Clock"
+ android:textAppearance="@style/TextAppearance.SystemBar.Clock"
+ systemui:amPmStyle="normal"
/>
</FrameLayout>
@@ -94,10 +100,9 @@
android:id="@+id/system_icon_area"
android:layout_width="wrap_content"
android:layout_height="match_parent"
- android:layout_centerHorizontal="true"
+ android:layout_alignParentEnd="true"
android:layout_centerVertical="true"
- android:layout_toEndOf="@+id/clock_container"
- android:paddingStart="@*android:dimen/car_padding_1"
+ android:paddingEnd="@*android:dimen/car_padding_1"
android:gravity="center_vertical"
android:orientation="horizontal"
>
@@ -107,46 +112,9 @@
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_weight="1"
- android:paddingStart="4dp"
android:gravity="center_vertical"
/>
</LinearLayout>
-
- <FrameLayout
- android:id="@+id/right_hvac_container"
- android:layout_width="wrap_content"
- android:layout_height="match_parent"
- android:layout_alignParentEnd="true"
- >
-
- <com.android.systemui.car.navigationbar.CarNavigationButton
- android:id="@+id/hvacright"
- android:layout_width="match_parent"
- android:layout_height="match_parent"
- android:background="@null"
- systemui:broadcast="true"
- systemui:intent="intent:#Intent;action=android.car.intent.action.TOGGLE_HVAC_CONTROLS;end"
- />
-
- <com.android.systemui.car.hvac.AnimatedTemperatureView
- android:id="@+id/righttext"
- android:layout_width="wrap_content"
- android:layout_height="match_parent"
- android:paddingStart="16dp"
- android:paddingEnd="@*android:dimen/car_padding_4"
- android:gravity="center_vertical|end"
- android:minEms="4"
- android:textAppearance="@style/TextAppearance.CarStatus"
- systemui:hvacAreaId="68"
- systemui:hvacMaxText="@string/hvac_max_text"
- systemui:hvacMaxValue="@dimen/hvac_max_value"
- systemui:hvacMinText="@string/hvac_min_text"
- systemui:hvacMinValue="@dimen/hvac_min_value"
- systemui:hvacPivotOffset="60dp"
- systemui:hvacPropertyId="358614275"
- systemui:hvacTempFormat="%.0f\u00B0"
- />
- </FrameLayout>
</RelativeLayout>
</com.android.systemui.car.navigationbar.CarNavigationBarView>
diff --git a/packages/CarSystemUI/res/layout/car_top_navigation_bar_unprovisioned.xml b/packages/CarSystemUI/res/layout/car_top_navigation_bar_unprovisioned.xml
index 9634950e4748..d9c149106451 100644
--- a/packages/CarSystemUI/res/layout/car_top_navigation_bar_unprovisioned.xml
+++ b/packages/CarSystemUI/res/layout/car_top_navigation_bar_unprovisioned.xml
@@ -55,10 +55,6 @@
android:minEms="4"
android:textAppearance="@style/TextAppearance.CarStatus"
systemui:hvacAreaId="49"
- systemui:hvacMaxText="@string/hvac_max_text"
- systemui:hvacMaxValue="@dimen/hvac_max_value"
- systemui:hvacMinText="@string/hvac_min_text"
- systemui:hvacMinValue="@dimen/hvac_min_value"
systemui:hvacPivotOffset="60dp"
systemui:hvacPropertyId="358614275"
systemui:hvacTempFormat="%.0f\u00B0"
@@ -133,10 +129,6 @@
android:minEms="4"
android:textAppearance="@style/TextAppearance.CarStatus"
systemui:hvacAreaId="68"
- systemui:hvacMaxText="@string/hvac_max_text"
- systemui:hvacMaxValue="@dimen/hvac_max_value"
- systemui:hvacMinText="@string/hvac_min_text"
- systemui:hvacMinValue="@dimen/hvac_min_value"
systemui:hvacPivotOffset="60dp"
systemui:hvacPropertyId="358614275"
systemui:hvacTempFormat="%.0f\u00B0"
diff --git a/packages/CarSystemUI/res/values/colors.xml b/packages/CarSystemUI/res/values/colors.xml
index ab9426593535..1e15affcbf48 100644
--- a/packages/CarSystemUI/res/values/colors.xml
+++ b/packages/CarSystemUI/res/values/colors.xml
@@ -31,6 +31,9 @@
<color name="docked_divider_background">@*android:color/car_grey_50</color>
<color name="system_bar_background_opaque">#ff172026</color>
+ <!-- colors for status bar -->
+ <color name="system_bar_user_icon_color">#ffffff</color>
+ <color name="system_bar_text_color">#ffffff</color>
<color name="status_bar_background_color">#33000000</color>
<drawable name="system_bar_background">@color/status_bar_background_color</drawable>
diff --git a/packages/CarSystemUI/res/values/config.xml b/packages/CarSystemUI/res/values/config.xml
index d3277ded6c5b..1fe2760e5b10 100644
--- a/packages/CarSystemUI/res/values/config.xml
+++ b/packages/CarSystemUI/res/values/config.xml
@@ -123,7 +123,6 @@
<item>com.android.systemui.volume.VolumeUI</item>
<item>com.android.systemui.statusbar.phone.StatusBar</item>
<item>com.android.systemui.keyboard.KeyboardUI</item>
- <item>com.android.systemui.pip.PipUI</item>
<item>com.android.systemui.shortcut.ShortcutKeyDispatcher</item>
<item>com.android.systemui.LatencyTester</item>
<item>com.android.systemui.globalactions.GlobalActionsComponent</item>
diff --git a/packages/CarSystemUI/res/values/dimens.xml b/packages/CarSystemUI/res/values/dimens.xml
index 8359dac6a30f..f02a8e7648c0 100644
--- a/packages/CarSystemUI/res/values/dimens.xml
+++ b/packages/CarSystemUI/res/values/dimens.xml
@@ -46,16 +46,23 @@
in frameworks/base/core package and thus will have no effect if
set here. See car_product overlay for car specific defaults-->
- <dimen name="status_bar_icon_drawing_size_dark">36dp</dimen>
- <dimen name="status_bar_icon_drawing_size">36dp</dimen>
+ <dimen name="system_bar_user_icon_padding">16dp</dimen>
+ <dimen name="system_bar_user_icon_drawing_size">36dp</dimen>
+ <dimen name="system_bar_button_group_padding">64dp</dimen>
+ <dimen name="system_bar_icon_drawing_size">44dp</dimen>
+
<!-- The amount by which to scale up the status bar icons. -->
<item name="status_bar_icon_scale_factor" format="float" type="dimen">1.75</item>
<dimen name="car_primary_icon_size">@*android:dimen/car_primary_icon_size</dimen>
+ <dimen name="hvac_container_padding">16dp</dimen>
+ <dimen name="hvac_temperature_text_size">56sp</dimen>
+ <dimen name="hvac_temperature_text_padding">8dp</dimen>
+ <dimen name="hvac_temperature_button_size">76dp</dimen>
<!--These values represent MIN and MAX for hvac-->
- <item name="hvac_min_value" format="float" type="dimen">0</item>
- <item name="hvac_max_value" format="float" type="dimen">126</item>
+ <item name="hvac_min_value_celsius" format="float" type="dimen">0</item>
+ <item name="hvac_max_value_celsius" format="float" type="dimen">126</item>
<!-- Largest size an avatar might need to be drawn in the user picker, status bar, or
quick settings header -->
diff --git a/packages/CarSystemUI/res/values/strings.xml b/packages/CarSystemUI/res/values/strings.xml
index 67fd5bb68521..fbdb5167fade 100644
--- a/packages/CarSystemUI/res/values/strings.xml
+++ b/packages/CarSystemUI/res/values/strings.xml
@@ -16,6 +16,8 @@
-->
<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <!-- Format for HVAC temperature (No decimal and the degree symbol) -->
+ <string name="hvac_temperature_format" translatable="false">%.0f\u00B0</string>
<!-- String to represent lowest setting of an HVAC system [CHAR LIMIT=10]-->
<string name="hvac_min_text">Min</string>
<!-- String to represent largest setting of an HVAC system [CHAR LIMIT=10]-->
diff --git a/packages/CarSystemUI/res/values/styles.xml b/packages/CarSystemUI/res/values/styles.xml
index e76373d4a4f7..0db17ac42a77 100644
--- a/packages/CarSystemUI/res/values/styles.xml
+++ b/packages/CarSystemUI/res/values/styles.xml
@@ -25,21 +25,29 @@
<item name="android:padding">22dp</item>
</style>
- <style name="TextAppearance.StatusBar.Clock"
- parent="@*android:style/TextAppearance.StatusBar.Icon">
- <item name="android:textSize">42sp</item>
- <item name="android:fontFamily">sans-serif-regular</item>
- <item name="android:textColor">@*android:color/car_grey_50</item>
+ <style name="TextAppearance.SystemBar.Clock"
+ parent="@*android:style/TextAppearance.StatusBar.Icon">
+ <item name="android:textSize">@dimen/car_body1_size</item>
+ <item name="android:textColor">@*android:color/car_headline3</item>
+ </style>
+
+ <style name="TextAppearance.SystemBar.Username"
+ parent="@android:style/TextAppearance.DeviceDefault">
+ <item name="android:textSize">@dimen/car_body3_size</item>
+ <item name="android:textColor">@color/system_bar_text_color</item>
</style>
<style name="TextAppearance.CarStatus" parent="@android:style/TextAppearance.DeviceDefault">
<item name="android:textSize">@*android:dimen/car_body2_size</item>
- <item name="android:textColor">@*android:color/car_grey_50</item>
+ <item name="android:textColor">@color/system_bar_text_color</item>
</style>
<style name="NavigationBarButton">
- <item name="android:layout_height">96dp</item>
- <item name="android:layout_width">96dp</item>
+ <item name="android:layout_height">76dp</item>
+ <item name="android:layout_width">76dp</item>
+ <item name="android:layout_marginEnd">32dp</item>
+ <item name="android:padding">16dp</item>
+ <item name="android:gravity">center</item>
<item name="android:background">?android:attr/selectableItemBackground</item>
</style>
</resources> \ No newline at end of file
diff --git a/packages/CarSystemUI/src/com/android/systemui/CarGlobalRootComponent.java b/packages/CarSystemUI/src/com/android/systemui/CarGlobalRootComponent.java
index 552cadfe967e..b17ad0febb90 100644
--- a/packages/CarSystemUI/src/com/android/systemui/CarGlobalRootComponent.java
+++ b/packages/CarSystemUI/src/com/android/systemui/CarGlobalRootComponent.java
@@ -16,7 +16,9 @@
package com.android.systemui;
+import com.android.systemui.dagger.GlobalModule;
import com.android.systemui.dagger.GlobalRootComponent;
+import com.android.systemui.dagger.WMModule;
import javax.inject.Singleton;
@@ -26,7 +28,9 @@ import dagger.Component;
@Singleton
@Component(
modules = {
- CarSysUIComponentModule.class
+ GlobalModule.class,
+ CarSysUIComponentModule.class,
+ WMModule.class
})
public interface CarGlobalRootComponent extends GlobalRootComponent {
/**
diff --git a/packages/CarSystemUI/src/com/android/systemui/CarSysUIComponent.java b/packages/CarSystemUI/src/com/android/systemui/CarSysUIComponent.java
index 24d9d09d2ca9..51855dc648e9 100644
--- a/packages/CarSystemUI/src/com/android/systemui/CarSysUIComponent.java
+++ b/packages/CarSystemUI/src/com/android/systemui/CarSysUIComponent.java
@@ -16,13 +16,10 @@
package com.android.systemui;
-import com.android.systemui.dagger.DependencyBinder;
import com.android.systemui.dagger.DependencyProvider;
import com.android.systemui.dagger.SysUIComponent;
import com.android.systemui.dagger.SysUISingleton;
-import com.android.systemui.dagger.SystemServicesModule;
import com.android.systemui.dagger.SystemUIModule;
-import com.android.systemui.pip.phone.dagger.PipModule;
import dagger.Subcomponent;
@@ -33,9 +30,6 @@ import dagger.Subcomponent;
@Subcomponent(modules = {
CarComponentBinder.class,
DependencyProvider.class,
- DependencyBinder.class,
- PipModule.class,
- SystemServicesModule.class,
SystemUIModule.class,
CarSystemUIModule.class,
CarSystemUIBinder.class})
diff --git a/packages/CarSystemUI/src/com/android/systemui/CarSystemUIBinder.java b/packages/CarSystemUI/src/com/android/systemui/CarSystemUIBinder.java
index 3971e18bb968..3def945dd03c 100644
--- a/packages/CarSystemUI/src/com/android/systemui/CarSystemUIBinder.java
+++ b/packages/CarSystemUI/src/com/android/systemui/CarSystemUIBinder.java
@@ -28,8 +28,6 @@ import com.android.systemui.car.window.SystemUIOverlayWindowManager;
import com.android.systemui.globalactions.GlobalActionsComponent;
import com.android.systemui.keyguard.KeyguardViewMediator;
import com.android.systemui.keyguard.dagger.KeyguardModule;
-import com.android.systemui.onehanded.OneHandedUI;
-import com.android.systemui.pip.PipUI;
import com.android.systemui.power.PowerUI;
import com.android.systemui.recents.Recents;
import com.android.systemui.recents.RecentsModule;
@@ -95,18 +93,6 @@ public abstract class CarSystemUIBinder {
@ClassKey(LatencyTester.class)
public abstract SystemUI bindLatencyTester(LatencyTester sysui);
- /** Inject into OneHandedUI. */
- @Binds
- @IntoMap
- @ClassKey(OneHandedUI.class)
- public abstract SystemUI bindOneHandedUI(OneHandedUI sysui);
-
- /** Inject into PipUI. */
- @Binds
- @IntoMap
- @ClassKey(PipUI.class)
- public abstract SystemUI bindPipUI(PipUI sysui);
-
/** Inject into PowerUI. */
@Binds
@IntoMap
diff --git a/packages/CarSystemUI/src/com/android/systemui/CarSystemUIModule.java b/packages/CarSystemUI/src/com/android/systemui/CarSystemUIModule.java
index 3eea5132da1d..51fda965dcd0 100644
--- a/packages/CarSystemUI/src/com/android/systemui/CarSystemUIModule.java
+++ b/packages/CarSystemUI/src/com/android/systemui/CarSystemUIModule.java
@@ -52,10 +52,10 @@ import com.android.systemui.statusbar.NotificationLockscreenUserManager;
import com.android.systemui.statusbar.NotificationLockscreenUserManagerImpl;
import com.android.systemui.statusbar.NotificationShadeWindowController;
import com.android.systemui.statusbar.notification.NotificationEntryManager;
+import com.android.systemui.statusbar.notification.collection.render.GroupMembershipManager;
import com.android.systemui.statusbar.phone.HeadsUpManagerPhone;
import com.android.systemui.statusbar.phone.KeyguardBypassController;
import com.android.systemui.statusbar.phone.KeyguardEnvironmentImpl;
-import com.android.systemui.statusbar.phone.NotificationGroupManager;
import com.android.systemui.statusbar.phone.ShadeController;
import com.android.systemui.statusbar.phone.ShadeControllerImpl;
import com.android.systemui.statusbar.policy.BatteryController;
@@ -92,7 +92,7 @@ abstract class CarSystemUIModule {
Context context,
StatusBarStateController statusBarStateController,
KeyguardBypassController bypassController,
- NotificationGroupManager groupManager,
+ GroupMembershipManager groupManager,
ConfigurationController configurationController) {
return new HeadsUpManagerPhone(context, statusBarStateController, bypassController,
groupManager, configurationController);
diff --git a/packages/CarSystemUI/src/com/android/systemui/car/CarDeviceProvisionedControllerImpl.java b/packages/CarSystemUI/src/com/android/systemui/car/CarDeviceProvisionedControllerImpl.java
index a2ba880facfe..fef032414bb9 100644
--- a/packages/CarSystemUI/src/com/android/systemui/car/CarDeviceProvisionedControllerImpl.java
+++ b/packages/CarSystemUI/src/com/android/systemui/car/CarDeviceProvisionedControllerImpl.java
@@ -16,20 +16,19 @@
package com.android.systemui.car;
+import android.annotation.NonNull;
import android.app.ActivityManager;
import android.car.settings.CarSettings;
-import android.content.ContentResolver;
-import android.content.Context;
import android.database.ContentObserver;
import android.net.Uri;
import android.os.Handler;
-import android.provider.Settings;
-import com.android.systemui.Dependency;
import com.android.systemui.broadcast.BroadcastDispatcher;
import com.android.systemui.dagger.SysUISingleton;
import com.android.systemui.dagger.qualifiers.Main;
import com.android.systemui.statusbar.policy.DeviceProvisionedControllerImpl;
+import com.android.systemui.util.settings.GlobalSettings;
+import com.android.systemui.util.settings.SecureSettings;
import javax.inject.Inject;
@@ -40,30 +39,33 @@ import javax.inject.Inject;
@SysUISingleton
public class CarDeviceProvisionedControllerImpl extends DeviceProvisionedControllerImpl implements
CarDeviceProvisionedController {
- private static final Uri USER_SETUP_IN_PROGRESS_URI = Settings.Secure.getUriFor(
- CarSettings.Secure.KEY_SETUP_WIZARD_IN_PROGRESS);
- private final ContentObserver mCarSettingsObserver = new ContentObserver(
- Dependency.get(Dependency.MAIN_HANDLER)) {
-
- @Override
- public void onChange(boolean selfChange, Uri uri, int flags) {
- if (USER_SETUP_IN_PROGRESS_URI.equals(uri)) {
- notifyUserSetupInProgressChanged();
- }
- }
- };
- private final ContentResolver mContentResolver;
+ private final Uri mUserSetupInProgressUri;
+ private final ContentObserver mCarSettingsObserver;
+ private final Handler mMainHandler;
+ private final SecureSettings mSecureSettings;
@Inject
- public CarDeviceProvisionedControllerImpl(Context context, @Main Handler mainHandler,
- BroadcastDispatcher broadcastDispatcher) {
- super(context, mainHandler, broadcastDispatcher);
- mContentResolver = context.getContentResolver();
+ public CarDeviceProvisionedControllerImpl(@Main Handler mainHandler,
+ BroadcastDispatcher broadcastDispatcher, GlobalSettings globalSetting,
+ SecureSettings secureSettings) {
+ super(mainHandler, broadcastDispatcher, globalSetting, secureSettings);
+ mMainHandler = mainHandler;
+ mSecureSettings = secureSettings;
+ mUserSetupInProgressUri = mSecureSettings.getUriFor(
+ CarSettings.Secure.KEY_SETUP_WIZARD_IN_PROGRESS);
+ mCarSettingsObserver = new ContentObserver(mMainHandler) {
+ @Override
+ public void onChange(boolean selfChange, Uri uri, int flags) {
+ if (mUserSetupInProgressUri.equals(uri)) {
+ notifyUserSetupInProgressChanged();
+ }
+ }
+ };
}
@Override
public boolean isUserSetupInProgress(int user) {
- return Settings.Secure.getIntForUser(mContentResolver,
+ return mSecureSettings.getIntForUser(
CarSettings.Secure.KEY_SETUP_WIZARD_IN_PROGRESS, /* def= */ 0, user) != 0;
}
@@ -73,7 +75,7 @@ public class CarDeviceProvisionedControllerImpl extends DeviceProvisionedControl
}
@Override
- public void addCallback(DeviceProvisionedListener listener) {
+ public void addCallback(@NonNull DeviceProvisionedListener listener) {
super.addCallback(listener);
if (listener instanceof CarDeviceProvisionedListener) {
((CarDeviceProvisionedListener) listener).onUserSetupInProgressChanged();
@@ -82,9 +84,9 @@ public class CarDeviceProvisionedControllerImpl extends DeviceProvisionedControl
@Override
protected void startListening(int user) {
- mContentResolver.registerContentObserver(
- USER_SETUP_IN_PROGRESS_URI, /* notifyForDescendants= */ true, mCarSettingsObserver,
- user);
+ mSecureSettings.registerContentObserverForUser(
+ mUserSetupInProgressUri, /* notifyForDescendants= */ true,
+ mCarSettingsObserver, user);
// The SUW Flag observer is registered before super.startListening() so that the observer is
// in place before DeviceProvisionedController starts to track user switches which avoids
// an edge case where our observer gets registered twice.
@@ -94,16 +96,16 @@ public class CarDeviceProvisionedControllerImpl extends DeviceProvisionedControl
@Override
protected void stopListening() {
super.stopListening();
- mContentResolver.unregisterContentObserver(mCarSettingsObserver);
+ mSecureSettings.unregisterContentObserver(mCarSettingsObserver);
}
@Override
public void onUserSwitched(int newUserId) {
super.onUserSwitched(newUserId);
- mContentResolver.unregisterContentObserver(mCarSettingsObserver);
- mContentResolver.registerContentObserver(
- USER_SETUP_IN_PROGRESS_URI, /* notifyForDescendants= */ true, mCarSettingsObserver,
- newUserId);
+ mSecureSettings.unregisterContentObserver(mCarSettingsObserver);
+ mSecureSettings.registerContentObserverForUser(
+ mUserSetupInProgressUri, /* notifyForDescendants= */ true,
+ mCarSettingsObserver, newUserId);
}
private void notifyUserSetupInProgressChanged() {
diff --git a/packages/CarSystemUI/src/com/android/systemui/car/hvac/AdjustableTemperatureView.java b/packages/CarSystemUI/src/com/android/systemui/car/hvac/AdjustableTemperatureView.java
new file mode 100644
index 000000000000..4cac4456789d
--- /dev/null
+++ b/packages/CarSystemUI/src/com/android/systemui/car/hvac/AdjustableTemperatureView.java
@@ -0,0 +1,108 @@
+/*
+ * 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.car.hvac;
+
+import static com.android.systemui.car.hvac.HvacController.convertToCelsius;
+import static com.android.systemui.car.hvac.HvacController.convertToFahrenheit;
+
+import android.content.Context;
+import android.content.res.TypedArray;
+import android.util.AttributeSet;
+import android.view.LayoutInflater;
+import android.widget.LinearLayout;
+import android.widget.TextView;
+
+import com.android.systemui.R;
+
+/**
+ * Displays temperature with a button to decrease and a button to increase on either side.
+ * Properties configured in the XML:
+ * hvacAreaId - Example: VehicleSeat.SEAT_ROW_1_LEFT (1)
+ */
+public class AdjustableTemperatureView extends LinearLayout implements TemperatureView {
+
+ private HvacController mHvacController;
+ private float mCurrentTempC;
+ private TextView mTempTextView;
+ private boolean mDisplayInFahrenheit = false;
+
+ private final float mMinTempC;
+ private final float mMaxTempC;
+ private final int mAreaId;
+ private final String mTempFormat;
+
+ public AdjustableTemperatureView(Context context, AttributeSet attrs) {
+ super(context, attrs);
+ TypedArray typedArray = context.obtainStyledAttributes(attrs, R.styleable.TemperatureView);
+ mAreaId = typedArray.getInt(R.styleable.TemperatureView_hvacAreaId, -1);
+
+ LayoutInflater.from(context).inflate(R.layout.adjustable_temperature_view, /* root= */this);
+ mTempFormat = getResources().getString(R.string.hvac_temperature_format);
+ mMinTempC = getResources().getFloat(R.dimen.hvac_min_value_celsius);
+ mMaxTempC = getResources().getFloat(R.dimen.hvac_max_value_celsius);
+ initializeButtons();
+ }
+
+ @Override
+ public void setHvacController(HvacController controller) {
+ mHvacController = controller;
+ }
+
+ @Override
+ public void setTemperatureView(float tempC) {
+ if (tempC > mMaxTempC || tempC < mMinTempC) {
+ return;
+ }
+ if (mTempTextView == null) {
+ mTempTextView = findViewById(R.id.hvac_temperature_text);
+ }
+ mTempTextView.setText(String.format(mTempFormat,
+ mDisplayInFahrenheit ? convertToFahrenheit(tempC) : tempC));
+ mCurrentTempC = tempC;
+ }
+
+ @Override
+ public void setDisplayInFahrenheit(boolean displayFahrenheit) {
+ mDisplayInFahrenheit = displayFahrenheit;
+ setTemperatureView(mCurrentTempC);
+ }
+
+ @Override
+ public int getAreaId() {
+ return mAreaId;
+ }
+
+ private void initializeButtons() {
+ findViewById(R.id.hvac_decrease_button).setOnClickListener(v -> {
+ float newTemp = mDisplayInFahrenheit ? convertToCelsius(
+ convertToFahrenheit(mCurrentTempC) - 1) : (mCurrentTempC - 1);
+ setTemperature(newTemp, mAreaId);
+ });
+
+ findViewById(R.id.hvac_increase_button).setOnClickListener(v -> {
+ float newTemp = mDisplayInFahrenheit ? convertToCelsius(
+ convertToFahrenheit(mCurrentTempC) + 1) : (mCurrentTempC + 1);
+ setTemperature(newTemp, mAreaId);
+ });
+ }
+
+ private void setTemperature(float tempC, int zone) {
+ if (tempC < mMaxTempC && tempC > mMinTempC && mHvacController != null) {
+ mHvacController.setTemperature(tempC, zone);
+ }
+ }
+}
diff --git a/packages/CarSystemUI/src/com/android/systemui/car/hvac/AnimatedTemperatureView.java b/packages/CarSystemUI/src/com/android/systemui/car/hvac/AnimatedTemperatureView.java
index a7294317f46c..567baa91cb59 100644
--- a/packages/CarSystemUI/src/com/android/systemui/car/hvac/AnimatedTemperatureView.java
+++ b/packages/CarSystemUI/src/com/android/systemui/car/hvac/AnimatedTemperatureView.java
@@ -16,6 +16,8 @@
package com.android.systemui.car.hvac;
+import static com.android.systemui.car.hvac.HvacController.convertToFahrenheit;
+
import android.animation.ObjectAnimator;
import android.annotation.SuppressLint;
import android.content.Context;
@@ -40,9 +42,7 @@ import com.android.systemui.R;
* Simple text display of HVAC properties, It is designed to show mTemperature and is configured in
* the XML.
* XML properties:
- * hvacPropertyId - Example: CarHvacManager.ID_ZONED_TEMP_SETPOINT (16385)
- * hvacAreaId - Example: VehicleSeat.SEAT_ROW_1_LEFT (1)
- * hvacTempFormat - Example: "%.1f\u00B0" (1 decimal and the degree symbol)
+ * hvacAreaId - Example: VehicleAreaSeat.SEAT_ROW_1_LEFT (1)
* hvacOrientaion = Example: left
*/
public class AnimatedTemperatureView extends FrameLayout implements TemperatureView {
@@ -84,7 +84,6 @@ public class AnimatedTemperatureView extends FrameLayout implements TemperatureV
}
private final int mAreaId;
- private final int mPropertyId;
private final int mPivotOffset;
private final int mGravity;
private final int mTextAppearanceRes;
@@ -100,12 +99,13 @@ public class AnimatedTemperatureView extends FrameLayout implements TemperatureV
private final TemperatureTextAnimator mTextAnimator;
boolean mDisplayInFahrenheit = false;
+ private HvacController mHvacController;
+
public AnimatedTemperatureView(Context context, AttributeSet attrs) {
super(context, attrs);
TypedArray typedArray = context.obtainStyledAttributes(attrs,
R.styleable.AnimatedTemperatureView);
mAreaId = typedArray.getInt(R.styleable.AnimatedTemperatureView_hvacAreaId, -1);
- mPropertyId = typedArray.getInt(R.styleable.AnimatedTemperatureView_hvacPropertyId, -1);
mPivotOffset =
typedArray.getDimensionPixelOffset(
R.styleable.AnimatedTemperatureView_hvacPivotOffset, 0);
@@ -115,11 +115,8 @@ public class AnimatedTemperatureView extends FrameLayout implements TemperatureV
typedArray.getResourceId(R.styleable.AnimatedTemperatureView_android_textAppearance,
0);
mMinEms = typedArray.getInteger(R.styleable.AnimatedTemperatureView_android_minEms, 0);
- mMinValue = typedArray.getFloat(R.styleable.AnimatedTemperatureView_hvacMinValue,
- Float.NaN);
- mMaxValue = typedArray.getFloat(R.styleable.AnimatedTemperatureView_hvacMaxValue,
- Float.NaN);
-
+ mMinValue = getResources().getFloat(R.dimen.hvac_min_value_celsius);
+ mMaxValue = getResources().getFloat(R.dimen.hvac_max_value_celsius);
mPaddingRect =
new Rect(getPaddingLeft(), getPaddingTop(), getPaddingRight(), getPaddingBottom());
@@ -138,15 +135,10 @@ public class AnimatedTemperatureView extends FrameLayout implements TemperatureV
mBackgroundAnimator = new TemperatureBackgroundAnimator(this, background);
-
- String format = typedArray.getString(R.styleable.AnimatedTemperatureView_hvacTempFormat);
- format = (format == null) ? "%.1f\u00B0" : format;
- CharSequence minText = typedArray.getString(
- R.styleable.AnimatedTemperatureView_hvacMinText);
- CharSequence maxText = typedArray.getString(
- R.styleable.AnimatedTemperatureView_hvacMaxText);
- mTextAnimator = new TemperatureTextAnimator(this, textSwitcher, format, mPivotOffset,
- minText, maxText);
+ mTextAnimator = new TemperatureTextAnimator(this, textSwitcher,
+ getResources().getString(R.string.hvac_temperature_format), mPivotOffset,
+ getResources().getString(R.string.hvac_min_text),
+ getResources().getString(R.string.hvac_max_text));
addView(background, ViewGroup.LayoutParams.MATCH_PARENT,
ViewGroup.LayoutParams.MATCH_PARENT);
@@ -186,13 +178,18 @@ public class AnimatedTemperatureView extends FrameLayout implements TemperatureV
return textView;
}
+ @Override
+ public void setHvacController(HvacController controller) {
+ mHvacController = controller;
+ }
+
/**
* Formats the float for display
*
* @param temp - The current temp or NaN
*/
@Override
- public void setTemp(float temp) {
+ public void setTemperatureView(float temp) {
if (mDisplayInFahrenheit) {
temp = convertToFahrenheit(temp);
}
@@ -252,15 +249,7 @@ public class AnimatedTemperatureView extends FrameLayout implements TemperatureV
}
/**
- * @return propertiyId Example: CarHvacManager.ID_ZONED_TEMP_SETPOINT (358614275)
- */
- @Override
- public int getPropertyId() {
- return mPropertyId;
- }
-
- /**
- * @return hvac AreaId - Example: VehicleSeat.SEAT_ROW_1_LEFT (1)
+ * @return hvac AreaId - Example: VehicleAreaSeat.SEAT_ROW_1_LEFT (1)
*/
@Override
public int getAreaId() {
@@ -272,6 +261,5 @@ public class AnimatedTemperatureView extends FrameLayout implements TemperatureV
super.onDetachedFromWindow();
mBackgroundAnimator.stopAnimations();
}
-
}
diff --git a/packages/CarSystemUI/src/com/android/systemui/car/hvac/HvacController.java b/packages/CarSystemUI/src/com/android/systemui/car/hvac/HvacController.java
index a4b6bfc58d3c..f7451dc6fdee 100644
--- a/packages/CarSystemUI/src/com/android/systemui/car/hvac/HvacController.java
+++ b/packages/CarSystemUI/src/com/android/systemui/car/hvac/HvacController.java
@@ -18,12 +18,12 @@ package com.android.systemui.car.hvac;
import static android.car.VehicleAreaType.VEHICLE_AREA_TYPE_GLOBAL;
import static android.car.VehiclePropertyIds.HVAC_TEMPERATURE_DISPLAY_UNITS;
+import static android.car.VehiclePropertyIds.HVAC_TEMPERATURE_SET;
import android.car.Car;
import android.car.VehicleUnit;
import android.car.hardware.CarPropertyValue;
-import android.car.hardware.hvac.CarHvacManager;
-import android.car.hardware.hvac.CarHvacManager.CarHvacEventCallback;
+import android.car.hardware.property.CarPropertyManager;
import android.util.Log;
import android.view.View;
import android.view.ViewGroup;
@@ -34,10 +34,8 @@ import com.android.systemui.dagger.SysUISingleton;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.HashSet;
-import java.util.Iterator;
import java.util.List;
import java.util.Map;
-import java.util.Objects;
import java.util.Set;
import javax.inject.Inject;
@@ -54,49 +52,64 @@ public class HvacController {
private final CarServiceProvider mCarServiceProvider;
private final Set<TemperatureView> mRegisteredViews = new HashSet<>();
- private CarHvacManager mHvacManager;
- private HashMap<HvacKey, List<TemperatureView>> mTempComponents = new HashMap<>();
-
- /**
- * Callback for getting changes from {@link CarHvacManager} and setting the UI elements to
- * match.
- */
- private final CarHvacEventCallback mHardwareCallback = new CarHvacEventCallback() {
- @Override
- public void onChangeEvent(final CarPropertyValue val) {
- try {
- int areaId = val.getAreaId();
- int propertyId = val.getPropertyId();
- List<TemperatureView> temperatureViews = mTempComponents.get(
- new HvacKey(propertyId, areaId));
- if (temperatureViews != null && !temperatureViews.isEmpty()) {
- float value = (float) val.getValue();
- if (DEBUG) {
- Log.d(TAG, "onChangeEvent: " + areaId + ":" + propertyId + ":" + value);
+ private CarPropertyManager mCarPropertyManager;
+ private HashMap<Integer, List<TemperatureView>> mTempComponents = new HashMap<>();
+
+ private final CarPropertyManager.CarPropertyEventCallback mHvacTemperatureSetCallback =
+ new CarPropertyManager.CarPropertyEventCallback() {
+ @Override
+ public void onChangeEvent(CarPropertyValue value) {
+ try {
+ int areaId = value.getAreaId();
+ List<TemperatureView> temperatureViews = mTempComponents.get(areaId);
+ if (temperatureViews != null && !temperatureViews.isEmpty()) {
+ float newTemp = (float) value.getValue();
+ if (DEBUG) {
+ Log.d(TAG, "onChangeEvent: " + areaId + ":" + value);
+ }
+ for (TemperatureView view : temperatureViews) {
+ view.setTemperatureView(newTemp);
+ }
+ }
+ } catch (Exception e) {
+ Log.e(TAG, "Failed handling hvac change event", e);
}
- for (TemperatureView tempView : temperatureViews) {
- tempView.setTemp(value);
+ }
+
+ @Override
+ public void onErrorEvent(int propId, int zone) {
+ Log.d(TAG, "HVAC error event, propertyId: " + propId + " zone: " + zone);
+ }
+ };
+
+ private final CarPropertyManager.CarPropertyEventCallback mTemperatureUnitChangeCallback =
+ new CarPropertyManager.CarPropertyEventCallback() {
+ @Override
+ public void onChangeEvent(CarPropertyValue value) {
+ if (!mRegisteredViews.isEmpty()) {
+ for (TemperatureView view : mRegisteredViews) {
+ view.setDisplayInFahrenheit(
+ value.getValue().equals(VehicleUnit.FAHRENHEIT));
+ }
}
- } // else the data is not of interest
- } catch (Exception e) {
- // catch all so we don't take down the sysui if a new data type is
- // introduced.
- Log.e(TAG, "Failed handling hvac change event", e);
- }
- }
+ }
- @Override
- public void onErrorEvent(final int propertyId, final int zone) {
- Log.d(TAG, "HVAC error event, propertyId: " + propertyId
- + " zone: " + zone);
- }
- };
+ @Override
+ public void onErrorEvent(int propId, int zone) {
+ Log.d(TAG, "HVAC error event, propertyId: " + propId + " zone: " + zone);
+ }
+ };
private final CarServiceProvider.CarServiceOnConnectedListener mCarServiceLifecycleListener =
car -> {
try {
- mHvacManager = (CarHvacManager) car.getCarManager(Car.HVAC_SERVICE);
- mHvacManager.registerCallback(mHardwareCallback);
+ mCarPropertyManager = (CarPropertyManager) car.getCarManager(
+ Car.PROPERTY_SERVICE);
+ mCarPropertyManager.registerCallback(mHvacTemperatureSetCallback,
+ HVAC_TEMPERATURE_SET, CarPropertyManager.SENSOR_RATE_ONCHANGE);
+ mCarPropertyManager.registerCallback(mTemperatureUnitChangeCallback,
+ HVAC_TEMPERATURE_DISPLAY_UNITS,
+ CarPropertyManager.SENSOR_RATE_ONCHANGE);
initComponents();
} catch (Exception e) {
Log.e(TAG, "Failed to correctly connect to HVAC", e);
@@ -109,8 +122,7 @@ public class HvacController {
}
/**
- * Create connection to the Car service. Note: call backs from the Car service
- * ({@link CarHvacManager}) will happen on the same thread this method was called from.
+ * Create connection to the Car service.
*/
public void connectToCarService() {
mCarServiceProvider.addListener(mCarServiceLifecycleListener);
@@ -124,21 +136,18 @@ public class HvacController {
return;
}
- HvacKey hvacKey = new HvacKey(temperatureView.getPropertyId(), temperatureView.getAreaId());
- if (!mTempComponents.containsKey(hvacKey)) {
- mTempComponents.put(hvacKey, new ArrayList<>());
+ int areaId = temperatureView.getAreaId();
+ if (!mTempComponents.containsKey(areaId)) {
+ mTempComponents.put(areaId, new ArrayList<>());
}
- mTempComponents.get(hvacKey).add(temperatureView);
+ mTempComponents.get(areaId).add(temperatureView);
initComponent(temperatureView);
mRegisteredViews.add(temperatureView);
}
private void initComponents() {
- Iterator<Map.Entry<HvacKey, List<TemperatureView>>> iterator =
- mTempComponents.entrySet().iterator();
- while (iterator.hasNext()) {
- Map.Entry<HvacKey, List<TemperatureView>> next = iterator.next();
+ for (Map.Entry<Integer, List<TemperatureView>> next : mTempComponents.entrySet()) {
List<TemperatureView> temperatureViews = next.getValue();
for (TemperatureView view : temperatureViews) {
initComponent(view);
@@ -147,29 +156,29 @@ public class HvacController {
}
private void initComponent(TemperatureView view) {
- int id = view.getPropertyId();
int zone = view.getAreaId();
if (DEBUG) {
- Log.d(TAG, "initComponent: " + zone + ":" + id);
+ Log.d(TAG, "initComponent: " + zone);
}
try {
- if (mHvacManager != null
- && mHvacManager.isPropertyAvailable(HVAC_TEMPERATURE_DISPLAY_UNITS,
- VEHICLE_AREA_TYPE_GLOBAL)) {
- if (mHvacManager.getIntProperty(HVAC_TEMPERATURE_DISPLAY_UNITS,
+ if (mCarPropertyManager != null && mCarPropertyManager.isPropertyAvailable(
+ HVAC_TEMPERATURE_DISPLAY_UNITS, VEHICLE_AREA_TYPE_GLOBAL)) {
+ if (mCarPropertyManager.getIntProperty(HVAC_TEMPERATURE_DISPLAY_UNITS,
VEHICLE_AREA_TYPE_GLOBAL) == VehicleUnit.FAHRENHEIT) {
view.setDisplayInFahrenheit(true);
}
-
}
- if (mHvacManager == null || !mHvacManager.isPropertyAvailable(id, zone)) {
- view.setTemp(Float.NaN);
+ if (mCarPropertyManager == null || !mCarPropertyManager.isPropertyAvailable(
+ HVAC_TEMPERATURE_SET, zone)) {
+ view.setTemperatureView(Float.NaN);
return;
}
- view.setTemp(mHvacManager.getFloatProperty(id, zone));
+ view.setTemperatureView(
+ mCarPropertyManager.getFloatProperty(HVAC_TEMPERATURE_SET, zone));
+ view.setHvacController(this);
} catch (Exception e) {
- view.setTemp(Float.NaN);
+ view.setTemperatureView(Float.NaN);
Log.e(TAG, "Failed to get value from hvac service", e);
}
}
@@ -199,30 +208,32 @@ public class HvacController {
}
/**
- * Key for storing {@link TemperatureView}s in a hash map
+ * Set the temperature in Celsius of the specified zone
*/
- private static class HvacKey {
-
- int mPropertyId;
- int mAreaId;
-
- private HvacKey(int propertyId, int areaId) {
- mPropertyId = propertyId;
- mAreaId = areaId;
+ public void setTemperature(float tempC, int zone) {
+ if (mCarPropertyManager != null) {
+ // Internally, all temperatures are represented in floating point Celsius
+ mCarPropertyManager.setFloatProperty(HVAC_TEMPERATURE_SET, zone, tempC);
}
+ }
- @Override
- public boolean equals(Object o) {
- if (this == o) return true;
- if (o == null || getClass() != o.getClass()) return false;
- HvacKey hvacKey = (HvacKey) o;
- return mPropertyId == hvacKey.mPropertyId
- && mAreaId == hvacKey.mAreaId;
- }
+ /**
+ * Convert the given temperature in Celsius into Fahrenheit
+ *
+ * @param tempC - The temperature in Celsius
+ * @return Temperature in Fahrenheit.
+ */
+ public static float convertToFahrenheit(float tempC) {
+ return (tempC * 9f / 5f) + 32;
+ }
- @Override
- public int hashCode() {
- return Objects.hash(mPropertyId, mAreaId);
- }
+ /**
+ * Convert the given temperature in Fahrenheit to Celsius
+ *
+ * @param tempF - The temperature in Fahrenheit.
+ * @return Temperature in Celsius.
+ */
+ public static float convertToCelsius(float tempF) {
+ return (float) ((tempF - 32) * 0.55555555556);
}
}
diff --git a/packages/CarSystemUI/src/com/android/systemui/car/hvac/TemperatureTextView.java b/packages/CarSystemUI/src/com/android/systemui/car/hvac/TemperatureTextView.java
index 521a665da5f6..252f7830b72c 100644
--- a/packages/CarSystemUI/src/com/android/systemui/car/hvac/TemperatureTextView.java
+++ b/packages/CarSystemUI/src/com/android/systemui/car/hvac/TemperatureTextView.java
@@ -16,6 +16,8 @@
package com.android.systemui.car.hvac;
+import static com.android.systemui.car.hvac.HvacController.convertToFahrenheit;
+
import android.content.Context;
import android.content.res.TypedArray;
import android.util.AttributeSet;
@@ -27,24 +29,25 @@ import com.android.systemui.R;
* Simple text display of HVAC properties, It is designed to show temperature and is configured in
* the XML.
* XML properties:
- * hvacPropertyId - Example: CarHvacManager.ID_ZONED_TEMP_SETPOINT (16385)
- * hvacAreaId - Example: VehicleSeat.SEAT_ROW_1_LEFT (1)
- * hvacTempFormat - Example: "%.1f\u00B0" (1 decimal and the degree symbol)
+ * hvacAreaId - Example: VehicleAreaSeat.SEAT_ROW_1_LEFT (1)
*/
public class TemperatureTextView extends TextView implements TemperatureView {
private final int mAreaId;
- private final int mPropertyId;
private final String mTempFormat;
+ private HvacController mHvacController;
private boolean mDisplayFahrenheit = false;
public TemperatureTextView(Context context, AttributeSet attrs) {
super(context, attrs);
TypedArray typedArray = context.obtainStyledAttributes(attrs, R.styleable.TemperatureView);
mAreaId = typedArray.getInt(R.styleable.TemperatureView_hvacAreaId, -1);
- mPropertyId = typedArray.getInt(R.styleable.TemperatureView_hvacPropertyId, -1);
- String format = typedArray.getString(R.styleable.TemperatureView_hvacTempFormat);
- mTempFormat = (format == null) ? "%.1f\u00B0" : format;
+ mTempFormat = getResources().getString(R.string.hvac_temperature_format);
+ }
+
+ @Override
+ public void setHvacController(HvacController controller) {
+ mHvacController = controller;
}
/**
@@ -53,7 +56,7 @@ public class TemperatureTextView extends TextView implements TemperatureView {
* @param temp - The current temp or NaN
*/
@Override
- public void setTemp(float temp) {
+ public void setTemperatureView(float temp) {
if (Float.isNaN(temp)) {
setText("--");
return;
@@ -70,15 +73,7 @@ public class TemperatureTextView extends TextView implements TemperatureView {
}
/**
- * @return propertiyId Example: CarHvacManager.ID_ZONED_TEMP_SETPOINT (16385)
- */
- @Override
- public int getPropertyId() {
- return mPropertyId;
- }
-
- /**
- * @return hvac AreaId - Example: VehicleSeat.SEAT_ROW_1_LEFT (1)
+ * @return hvac AreaId - Example: VehicleAreaSeat.SEAT_ROW_1_LEFT (1)
*/
@Override
public int getAreaId() {
diff --git a/packages/CarSystemUI/src/com/android/systemui/car/hvac/TemperatureView.java b/packages/CarSystemUI/src/com/android/systemui/car/hvac/TemperatureView.java
index 6b903fad505c..3c0e0acc446c 100644
--- a/packages/CarSystemUI/src/com/android/systemui/car/hvac/TemperatureView.java
+++ b/packages/CarSystemUI/src/com/android/systemui/car/hvac/TemperatureView.java
@@ -17,15 +17,23 @@
package com.android.systemui.car.hvac;
/**
- * Interface for Views that display temperature HVAC properties
+ * Interface for Views that display temperature HVAC properties.
*/
public interface TemperatureView {
+
+ /**
+ * Sets the {@link HvacController} to handle changes to HVAC properties. The View is only
+ * responsible for the UI to display temperature. It should not contain logic that makes direct
+ * changes to HVAC properties and instead use this {@link HvacController}.
+ */
+ void setHvacController(HvacController controller);
+
/**
* Formats the float for display
*
* @param temp - The current temp in Celsius or NaN
*/
- void setTemp(float temp);
+ void setTemperatureView(float temp);
/**
* Render the displayed temperature in Fahrenheit
@@ -35,22 +43,7 @@ public interface TemperatureView {
void setDisplayInFahrenheit(boolean displayFahrenheit);
/**
- * Convert the given temperature in Celsius into Fahrenheit
- *
- * @param realTemp - The temperature in Celsius
- * @return Temperature in Fahrenheit.
- */
- default float convertToFahrenheit(float realTemp) {
- return (realTemp * 9f / 5f) + 32;
- }
-
- /**
- * @return propertiyId Example: CarHvacManager.ID_ZONED_TEMP_SETPOINT (16385)
- */
- int getPropertyId();
-
- /**
- * @return hvac AreaId - Example: VehicleSeat.SEAT_ROW_1_LEFT (1)
+ * @return hvac AreaId - Example: VehicleAreaSeat.SEAT_ROW_1_LEFT (1)
*/
int getAreaId();
}
diff --git a/packages/CarSystemUI/src/com/android/systemui/car/keyguard/CarKeyguardViewController.java b/packages/CarSystemUI/src/com/android/systemui/car/keyguard/CarKeyguardViewController.java
index 276ddfbc2b4f..dadbc22760b9 100644
--- a/packages/CarSystemUI/src/com/android/systemui/car/keyguard/CarKeyguardViewController.java
+++ b/packages/CarSystemUI/src/com/android/systemui/car/keyguard/CarKeyguardViewController.java
@@ -18,7 +18,6 @@ package com.android.systemui.car.keyguard;
import android.car.Car;
import android.car.user.CarUserManager;
-import android.content.Context;
import android.os.Bundle;
import android.os.Handler;
import android.util.Log;
@@ -28,20 +27,17 @@ import android.view.ViewRootImpl;
import androidx.annotation.VisibleForTesting;
-import com.android.internal.widget.LockPatternUtils;
import com.android.keyguard.KeyguardUpdateMonitor;
import com.android.keyguard.KeyguardViewController;
import com.android.keyguard.ViewMediatorCallback;
+import com.android.keyguard.dagger.KeyguardBouncerComponent;
import com.android.systemui.R;
-import com.android.systemui.SystemUIFactory;
import com.android.systemui.car.CarServiceProvider;
import com.android.systemui.car.navigationbar.CarNavigationBarController;
import com.android.systemui.car.window.OverlayViewController;
import com.android.systemui.car.window.OverlayViewGlobalStateController;
import com.android.systemui.dagger.SysUISingleton;
import com.android.systemui.dagger.qualifiers.Main;
-import com.android.systemui.keyguard.DismissCallbackRegistry;
-import com.android.systemui.plugins.FalsingManager;
import com.android.systemui.statusbar.phone.BiometricUnlockController;
import com.android.systemui.statusbar.phone.KeyguardBouncer;
import com.android.systemui.statusbar.phone.KeyguardBypassController;
@@ -63,18 +59,14 @@ public class CarKeyguardViewController extends OverlayViewController implements
private static final String TAG = "CarKeyguardViewController";
private static final boolean DEBUG = true;
- private final Context mContext;
private final Handler mHandler;
private final CarServiceProvider mCarServiceProvider;
private final KeyguardStateController mKeyguardStateController;
private final KeyguardUpdateMonitor mKeyguardUpdateMonitor;
private final Lazy<BiometricUnlockController> mBiometricUnlockControllerLazy;
- private final LockPatternUtils mLockPatternUtils;
- private final FalsingManager mFalsingManager;
- private final Lazy<KeyguardBypassController> mKeyguardBypassControllerLazy;
- private final DismissCallbackRegistry mDismissCallbackRegistry;
private final ViewMediatorCallback mViewMediatorCallback;
private final CarNavigationBarController mCarNavigationBarController;
+ private final KeyguardBouncerComponent.Factory mKeyguardBouncerComponentFactory;
// Needed to instantiate mBouncer.
private final KeyguardBouncer.BouncerExpansionCallback
mExpansionCallback = new KeyguardBouncer.BouncerExpansionCallback() {
@@ -107,7 +99,6 @@ public class CarKeyguardViewController extends OverlayViewController implements
@Inject
public CarKeyguardViewController(
- Context context,
@Main Handler mainHandler,
CarServiceProvider carServiceProvider,
OverlayViewGlobalStateController overlayViewGlobalStateController,
@@ -116,26 +107,18 @@ public class CarKeyguardViewController extends OverlayViewController implements
Lazy<BiometricUnlockController> biometricUnlockControllerLazy,
ViewMediatorCallback viewMediatorCallback,
CarNavigationBarController carNavigationBarController,
- /* The params below are only used to reuse KeyguardBouncer */
- LockPatternUtils lockPatternUtils,
- DismissCallbackRegistry dismissCallbackRegistry,
- FalsingManager falsingManager,
- Lazy<KeyguardBypassController> keyguardBypassControllerLazy) {
+ KeyguardBouncerComponent.Factory keyguardBouncerComponentFactory) {
super(R.id.keyguard_stub, overlayViewGlobalStateController);
- mContext = context;
mHandler = mainHandler;
mCarServiceProvider = carServiceProvider;
mKeyguardStateController = keyguardStateController;
mKeyguardUpdateMonitor = keyguardUpdateMonitor;
mBiometricUnlockControllerLazy = biometricUnlockControllerLazy;
- mLockPatternUtils = lockPatternUtils;
- mFalsingManager = falsingManager;
- mKeyguardBypassControllerLazy = keyguardBypassControllerLazy;
- mDismissCallbackRegistry = dismissCallbackRegistry;
mViewMediatorCallback = viewMediatorCallback;
mCarNavigationBarController = carNavigationBarController;
+ mKeyguardBouncerComponentFactory = keyguardBouncerComponentFactory;
registerUserSwitchedListener();
}
@@ -147,11 +130,9 @@ public class CarKeyguardViewController extends OverlayViewController implements
@Override
public void onFinishInflate() {
- mBouncer = SystemUIFactory.getInstance().createKeyguardBouncer(mContext,
- mViewMediatorCallback, mLockPatternUtils,
- getLayout().findViewById(R.id.keyguard_container), mDismissCallbackRegistry,
- mExpansionCallback, mKeyguardStateController, mFalsingManager,
- mKeyguardBypassControllerLazy.get());
+ mBouncer = mKeyguardBouncerComponentFactory
+ .build(getLayout().findViewById(R.id.keyguard_container), mExpansionCallback)
+ .createKeyguardBouncer();
mBiometricUnlockControllerLazy.get().setKeyguardViewController(this);
}
@@ -359,9 +340,8 @@ public class CarKeyguardViewController extends OverlayViewController implements
public void registerStatusBar(StatusBar statusBar, ViewGroup container,
NotificationPanelViewController notificationPanelViewController,
BiometricUnlockController biometricUnlockController,
- DismissCallbackRegistry dismissCallbackRegistry, ViewGroup lockIconContainer,
- View notificationContainer, KeyguardBypassController bypassController,
- FalsingManager falsingManager) {
+ ViewGroup lockIconContainer,
+ View notificationContainer, KeyguardBypassController bypassController) {
// no-op
}
diff --git a/packages/CarSystemUI/src/com/android/systemui/car/navigationbar/CarNavigationBar.java b/packages/CarSystemUI/src/com/android/systemui/car/navigationbar/CarNavigationBar.java
index 9584850fde7c..bf8cda3b6dcb 100644
--- a/packages/CarSystemUI/src/com/android/systemui/car/navigationbar/CarNavigationBar.java
+++ b/packages/CarSystemUI/src/com/android/systemui/car/navigationbar/CarNavigationBar.java
@@ -340,24 +340,28 @@ public class CarNavigationBar extends SystemUI implements CommandQueue.Callbacks
mTopNavigationBarView = mCarNavigationBarController.getTopBar(isDeviceSetupForUser());
if (mTopNavigationBarView != null) {
mSystemBarConfigs.insetSystemBar(SystemBarConfigs.TOP, mTopNavigationBarView);
+ mSystemBarConfigs.setInsetUpdater(SystemBarConfigs.TOP, mTopNavigationBarView);
mTopNavigationBarWindow.addView(mTopNavigationBarView);
}
mBottomNavigationBarView = mCarNavigationBarController.getBottomBar(isDeviceSetupForUser());
if (mBottomNavigationBarView != null) {
mSystemBarConfigs.insetSystemBar(SystemBarConfigs.BOTTOM, mBottomNavigationBarView);
+ mSystemBarConfigs.setInsetUpdater(SystemBarConfigs.BOTTOM, mBottomNavigationBarView);
mBottomNavigationBarWindow.addView(mBottomNavigationBarView);
}
mLeftNavigationBarView = mCarNavigationBarController.getLeftBar(isDeviceSetupForUser());
if (mLeftNavigationBarView != null) {
mSystemBarConfigs.insetSystemBar(SystemBarConfigs.LEFT, mLeftNavigationBarView);
+ mSystemBarConfigs.setInsetUpdater(SystemBarConfigs.LEFT, mLeftNavigationBarView);
mLeftNavigationBarWindow.addView(mLeftNavigationBarView);
}
mRightNavigationBarView = mCarNavigationBarController.getRightBar(isDeviceSetupForUser());
if (mRightNavigationBarView != null) {
mSystemBarConfigs.insetSystemBar(SystemBarConfigs.RIGHT, mRightNavigationBarView);
+ mSystemBarConfigs.setInsetUpdater(SystemBarConfigs.RIGHT, mRightNavigationBarView);
mRightNavigationBarWindow.addView(mRightNavigationBarView);
}
}
@@ -367,7 +371,7 @@ public class CarNavigationBar extends SystemUI implements CommandQueue.Callbacks
}
private void attachNavBarBySide(int side) {
- switch(side) {
+ switch (side) {
case SystemBarConfigs.TOP:
if (mTopNavigationBarWindow != null) {
mWindowManager.addView(mTopNavigationBarWindow,
diff --git a/packages/CarSystemUI/src/com/android/systemui/car/navigationbar/CarNavigationBarController.java b/packages/CarSystemUI/src/com/android/systemui/car/navigationbar/CarNavigationBarController.java
index 51a883809aab..529083f4bab6 100644
--- a/packages/CarSystemUI/src/com/android/systemui/car/navigationbar/CarNavigationBarController.java
+++ b/packages/CarSystemUI/src/com/android/systemui/car/navigationbar/CarNavigationBarController.java
@@ -23,6 +23,7 @@ import android.view.ViewGroup;
import androidx.annotation.Nullable;
import com.android.systemui.car.hvac.HvacController;
+import com.android.systemui.car.statusbar.UserNameViewController;
import com.android.systemui.dagger.SysUISingleton;
import javax.inject.Inject;
@@ -38,6 +39,7 @@ public class CarNavigationBarController {
private final ButtonSelectionStateController mButtonSelectionStateController;
private final ButtonRoleHolderController mButtonRoleHolderController;
private final Lazy<HvacController> mHvacControllerLazy;
+ private final Lazy<UserNameViewController> mUserNameViewControllerLazy;
private boolean mShowTop;
private boolean mShowBottom;
@@ -60,12 +62,14 @@ public class CarNavigationBarController {
NavigationBarViewFactory navigationBarViewFactory,
ButtonSelectionStateController buttonSelectionStateController,
Lazy<HvacController> hvacControllerLazy,
+ Lazy<UserNameViewController> userNameViewControllerLazy,
ButtonRoleHolderController buttonRoleHolderController,
SystemBarConfigs systemBarConfigs) {
mContext = context;
mNavigationBarViewFactory = navigationBarViewFactory;
mButtonSelectionStateController = buttonSelectionStateController;
mHvacControllerLazy = hvacControllerLazy;
+ mUserNameViewControllerLazy = userNameViewControllerLazy;
mButtonRoleHolderController = buttonRoleHolderController;
// Read configuration.
@@ -109,6 +113,7 @@ public class CarNavigationBarController {
mHvacControllerLazy.get().removeAllComponents();
mButtonSelectionStateController.removeAll();
mButtonRoleHolderController.removeAll();
+ mUserNameViewControllerLazy.get().removeAll();
}
/** Gets the top window if configured to do so. */
@@ -218,6 +223,7 @@ public class CarNavigationBarController {
mButtonSelectionStateController.addAllButtonsWithSelectionState(view);
mButtonRoleHolderController.addAllButtonsWithRoleName(view);
mHvacControllerLazy.get().addTemperatureViewToController(view);
+ mUserNameViewControllerLazy.get().addUserNameView(view);
}
/** Sets a touch listener for the top navigation bar. */
diff --git a/packages/CarSystemUI/src/com/android/systemui/car/navigationbar/SystemBarConfigs.java b/packages/CarSystemUI/src/com/android/systemui/car/navigationbar/SystemBarConfigs.java
index 143c444fc4be..1418ace378d2 100644
--- a/packages/CarSystemUI/src/com/android/systemui/car/navigationbar/SystemBarConfigs.java
+++ b/packages/CarSystemUI/src/com/android/systemui/car/navigationbar/SystemBarConfigs.java
@@ -25,10 +25,13 @@ import android.util.Log;
import android.view.Gravity;
import android.view.InsetsState;
import android.view.ViewGroup;
+import android.view.WindowInsets;
import android.view.WindowManager;
import com.android.internal.annotations.VisibleForTesting;
import com.android.systemui.R;
+import com.android.systemui.car.notification.BottomNotificationPanelViewMediator;
+import com.android.systemui.car.notification.TopNotificationPanelViewMediator;
import com.android.systemui.dagger.SysUISingleton;
import com.android.systemui.dagger.qualifiers.Main;
@@ -95,6 +98,8 @@ public class SystemBarConfigs {
populateMaps();
readConfigs();
checkEnabledBarsHaveUniqueBarTypes();
+ checkAllOverlappingBarsHaveDifferentZOrders();
+ checkSystemBarEnabledForNotificationPanel();
setInsetPaddingsForOverlappingCorners();
sortSystemBarSidesByZOrder();
}
@@ -120,16 +125,60 @@ public class SystemBarConfigs {
}
protected void insetSystemBar(@SystemBarSide int side, CarNavigationBarView view) {
+ if (mSystemBarConfigMap.get(side) == null) return;
+
int[] paddings = mSystemBarConfigMap.get(side).getPaddings();
view.setPadding(paddings[2], paddings[0], paddings[3], paddings[1]);
}
+ protected void setInsetUpdater(@SystemBarSide int side, CarNavigationBarView view) {
+ view.setOnApplyWindowInsetsListener((v, insets) -> {
+ updateInsetPaddings(side, getSystemBarsVisibility(insets));
+ insetSystemBar(side, view);
+ return insets;
+ });
+ }
+
protected List<Integer> getSystemBarSidesByZOrder() {
return mSystemBarSidesByZOrder;
}
@VisibleForTesting
- protected static int getHunZOrder() {
+ void updateInsetPaddings(@SystemBarSide int side,
+ Map<@SystemBarSide Integer, Boolean> barVisibilities) {
+ SystemBarConfig currentConfig = mSystemBarConfigMap.get(side);
+
+ if (currentConfig == null) return;
+
+ if (isHorizontalBar(side)) {
+ if (mLeftNavBarEnabled && currentConfig.getZOrder() < mSystemBarConfigMap.get(
+ LEFT).getZOrder()) {
+ currentConfig.setPaddingBySide(LEFT,
+ barVisibilities.get(LEFT) ? mSystemBarConfigMap.get(LEFT).getGirth() : 0);
+ }
+ if (mRightNavBarEnabled && currentConfig.getZOrder() < mSystemBarConfigMap.get(
+ RIGHT).getZOrder()) {
+ currentConfig.setPaddingBySide(RIGHT,
+ barVisibilities.get(RIGHT) ? mSystemBarConfigMap.get(RIGHT).getGirth() : 0);
+ }
+ }
+ if (isVerticalBar(side)) {
+ if (mTopNavBarEnabled && currentConfig.getZOrder() < mSystemBarConfigMap.get(
+ TOP).getZOrder()) {
+ currentConfig.setPaddingBySide(TOP,
+ barVisibilities.get(TOP) ? mSystemBarConfigMap.get(TOP).getGirth() : 0);
+ }
+ if (mBottomNavBarEnabled && currentConfig.getZOrder() < mSystemBarConfigMap.get(
+ BOTTOM).getZOrder()) {
+ currentConfig.setPaddingBySide(BOTTOM,
+ barVisibilities.get(BOTTOM) ? mSystemBarConfigMap.get(BOTTOM).getGirth()
+ : 0);
+ }
+ }
+ }
+
+ @VisibleForTesting
+ static int getHunZOrder() {
return HUN_ZORDER;
}
@@ -221,14 +270,107 @@ public class SystemBarConfigs {
}
}
+ private void checkAllOverlappingBarsHaveDifferentZOrders() {
+ checkOverlappingBarsHaveDifferentZOrders(TOP, LEFT);
+ checkOverlappingBarsHaveDifferentZOrders(TOP, RIGHT);
+ checkOverlappingBarsHaveDifferentZOrders(BOTTOM, LEFT);
+ checkOverlappingBarsHaveDifferentZOrders(BOTTOM, RIGHT);
+ }
+
+ private void checkSystemBarEnabledForNotificationPanel() throws RuntimeException {
+ String notificationPanelMediatorName =
+ mResources.getString(R.string.config_notificationPanelViewMediator);
+ if (notificationPanelMediatorName == null) {
+ return;
+ }
+
+ Class<?> notificationPanelMediatorUsed = null;
+ try {
+ notificationPanelMediatorUsed = Class.forName(notificationPanelMediatorName);
+ } catch (ClassNotFoundException e) {
+ e.printStackTrace();
+ }
+
+ if (!mTopNavBarEnabled && notificationPanelMediatorUsed.isAssignableFrom(
+ TopNotificationPanelViewMediator.class)) {
+ throw new RuntimeException(
+ "Top System Bar must be enabled to use " + notificationPanelMediatorName);
+ }
+
+ if (!mBottomNavBarEnabled && notificationPanelMediatorUsed.isAssignableFrom(
+ BottomNotificationPanelViewMediator.class)) {
+ throw new RuntimeException("Bottom System Bar must be enabled to use "
+ + notificationPanelMediatorName);
+ }
+ }
+
private void setInsetPaddingsForOverlappingCorners() {
- setInsetPaddingForOverlappingCorner(TOP, LEFT);
- setInsetPaddingForOverlappingCorner(TOP, RIGHT);
- setInsetPaddingForOverlappingCorner(BOTTOM, LEFT);
- setInsetPaddingForOverlappingCorner(BOTTOM, RIGHT);
+ Map<@SystemBarSide Integer, Boolean> systemBarVisibilityOnInit =
+ getSystemBarsVisibilityOnInit();
+ updateInsetPaddings(TOP, systemBarVisibilityOnInit);
+ updateInsetPaddings(BOTTOM, systemBarVisibilityOnInit);
+ updateInsetPaddings(LEFT, systemBarVisibilityOnInit);
+ updateInsetPaddings(RIGHT, systemBarVisibilityOnInit);
+ }
+
+ private void sortSystemBarSidesByZOrder() {
+ List<SystemBarConfig> systemBarsByZOrder = new ArrayList<>(mSystemBarConfigMap.values());
+
+ systemBarsByZOrder.sort(new Comparator<SystemBarConfig>() {
+ @Override
+ public int compare(SystemBarConfig o1, SystemBarConfig o2) {
+ return o1.getZOrder() - o2.getZOrder();
+ }
+ });
+
+ systemBarsByZOrder.forEach(systemBarConfig -> {
+ mSystemBarSidesByZOrder.add(systemBarConfig.getSide());
+ });
+ }
+
+ @InsetsState.InternalInsetsType
+ private int getSystemBarTypeBySide(@SystemBarSide int side) {
+ return mSystemBarConfigMap.get(side) != null
+ ? mSystemBarConfigMap.get(side).getBarType() : null;
+ }
+
+ // On init, system bars are visible as long as they are enabled.
+ private Map<@SystemBarSide Integer, Boolean> getSystemBarsVisibilityOnInit() {
+ ArrayMap<@SystemBarSide Integer, Boolean> visibilityMap = new ArrayMap<>();
+ visibilityMap.put(TOP, mTopNavBarEnabled);
+ visibilityMap.put(BOTTOM, mBottomNavBarEnabled);
+ visibilityMap.put(LEFT, mLeftNavBarEnabled);
+ visibilityMap.put(RIGHT, mRightNavBarEnabled);
+ return visibilityMap;
+ }
+
+ private Map<@SystemBarSide Integer, Boolean> getSystemBarsVisibility(WindowInsets insets) {
+ ArrayMap<@SystemBarSide Integer, Boolean> visibilityMap = new ArrayMap<>();
+ if (mTopNavBarEnabled) {
+ visibilityMap.put(TOP, getSystemBarInsetVisibleBySide(TOP, insets));
+ }
+ if (mBottomNavBarEnabled) {
+ visibilityMap.put(BOTTOM, getSystemBarInsetVisibleBySide(BOTTOM, insets));
+ }
+ if (mLeftNavBarEnabled) {
+ visibilityMap.put(LEFT, getSystemBarInsetVisibleBySide(LEFT, insets));
+ }
+ if (mRightNavBarEnabled) {
+ visibilityMap.put(RIGHT, getSystemBarInsetVisibleBySide(RIGHT, insets));
+ }
+ return visibilityMap;
}
- private void setInsetPaddingForOverlappingCorner(@SystemBarSide int horizontalSide,
+ private boolean getSystemBarInsetVisibleBySide(@SystemBarSide int side, WindowInsets insets) {
+ if (mSystemBarConfigMap.get(side) == null) return false;
+
+ int internalInsetType = BAR_TYPE_MAP[getSystemBarTypeBySide(side)];
+ int publicInsetType = InsetsState.toPublicType(internalInsetType);
+
+ return insets.isVisible(publicInsetType);
+ }
+
+ private void checkOverlappingBarsHaveDifferentZOrders(@SystemBarSide int horizontalSide,
@SystemBarSide int verticalSide) {
if (isVerticalBar(horizontalSide) || isHorizontalBar(verticalSide)) {
@@ -242,15 +384,9 @@ public class SystemBarConfigs {
if (verticalBarConfig != null && horizontalBarConfig != null) {
int horizontalBarZOrder = horizontalBarConfig.getZOrder();
- int horizontalBarGirth = horizontalBarConfig.getGirth();
int verticalBarZOrder = verticalBarConfig.getZOrder();
- int verticalBarGirth = verticalBarConfig.getGirth();
- if (horizontalBarZOrder > verticalBarZOrder) {
- verticalBarConfig.setPaddingBySide(horizontalSide, horizontalBarGirth);
- } else if (horizontalBarZOrder < verticalBarZOrder) {
- horizontalBarConfig.setPaddingBySide(verticalSide, verticalBarGirth);
- } else {
+ if (horizontalBarZOrder == verticalBarZOrder) {
throw new RuntimeException(
BAR_TITLE_MAP.get(horizontalSide) + " " + BAR_TITLE_MAP.get(verticalSide)
+ " have the same Z-Order, and so their placing order cannot be "
@@ -261,23 +397,8 @@ public class SystemBarConfigs {
}
}
- private void sortSystemBarSidesByZOrder() {
- List<SystemBarConfig> systemBarsByZOrder = new ArrayList<>(mSystemBarConfigMap.values());
-
- systemBarsByZOrder.sort(new Comparator<SystemBarConfig>() {
- @Override
- public int compare(SystemBarConfig o1, SystemBarConfig o2) {
- return o1.getZOrder() - o2.getZOrder();
- }
- });
-
- systemBarsByZOrder.forEach(systemBarConfig -> {
- mSystemBarSidesByZOrder.add(systemBarConfig.getSide());
- });
- }
-
private static boolean isHorizontalBar(@SystemBarSide int side) {
- return side == TOP || side == BOTTOM;
+ return side == TOP || side == BOTTOM;
}
private static boolean isVerticalBar(@SystemBarSide int side) {
diff --git a/packages/CarSystemUI/src/com/android/systemui/car/notification/NotificationPanelViewController.java b/packages/CarSystemUI/src/com/android/systemui/car/notification/NotificationPanelViewController.java
index 3b22fdb50765..8d91e7eae91a 100644
--- a/packages/CarSystemUI/src/com/android/systemui/car/notification/NotificationPanelViewController.java
+++ b/packages/CarSystemUI/src/com/android/systemui/car/notification/NotificationPanelViewController.java
@@ -54,8 +54,8 @@ import com.android.systemui.dagger.qualifiers.Main;
import com.android.systemui.dagger.qualifiers.UiBackground;
import com.android.systemui.plugins.statusbar.StatusBarStateController;
import com.android.systemui.statusbar.CommandQueue;
-import com.android.systemui.statusbar.FlingAnimationUtils;
import com.android.systemui.statusbar.StatusBarState;
+import com.android.wm.shell.animation.FlingAnimationUtils;
import java.util.concurrent.Executor;
@@ -91,7 +91,6 @@ public class NotificationPanelViewController extends OverlayPanelViewController
private RecyclerView mNotificationList;
private NotificationViewController mNotificationViewController;
- private boolean mIsTracking;
private boolean mNotificationListAtEnd;
private float mFirstTouchDownOnGlassPane;
private boolean mNotificationListAtEndAtTimeOfTouch;
@@ -299,14 +298,14 @@ public class NotificationPanelViewController extends OverlayPanelViewController
// The glass pane is used to view touch events before passed to the notification list.
// This allows us to initialize gesture listeners and detect when to close the notifications
glassPane.setOnTouchListener((v, event) -> {
- if (event.getActionMasked() == MotionEvent.ACTION_UP) {
+ if (isClosingAction(event)) {
mNotificationListAtEndAtTimeOfTouch = false;
}
- if (event.getActionMasked() == MotionEvent.ACTION_DOWN) {
+ if (isOpeningAction(event)) {
mFirstTouchDownOnGlassPane = event.getRawX();
mNotificationListAtEndAtTimeOfTouch = mNotificationListAtEnd;
// Reset the tracker when there is a touch down on the glass pane.
- mIsTracking = false;
+ setIsTracking(false);
// Pass the down event to gesture detector so that it knows where the touch event
// started.
closeGestureDetector.onTouchEvent(event);
@@ -341,22 +340,21 @@ public class NotificationPanelViewController extends OverlayPanelViewController
// If the card is swiping we should not allow the notification shade to close.
// Hence setting mNotificationListAtEndAtTimeOfTouch to false will stop that
- // for us. We are also checking for mIsTracking because while swiping the
+ // for us. We are also checking for isTracking() because while swiping the
// notification shade to close if the user goes a bit horizontal while swiping
// upwards then also this should close.
- if (mIsNotificationCardSwiping && !mIsTracking) {
+ if (mIsNotificationCardSwiping && !isTracking()) {
mNotificationListAtEndAtTimeOfTouch = false;
}
boolean handled = closeGestureDetector.onTouchEvent(event);
- boolean isTracking = mIsTracking;
+ boolean isTracking = isTracking();
Rect rect = getLayout().getClipBounds();
float clippedHeight = 0;
if (rect != null) {
clippedHeight = rect.bottom;
}
- if (!handled && event.getActionMasked() == MotionEvent.ACTION_UP
- && mIsSwipingVerticallyToClose) {
+ if (!handled && isClosingAction(event) && mIsSwipingVerticallyToClose) {
if (getSettleClosePercentage() < getPercentageFromEndingEdge() && isTracking) {
animatePanel(DEFAULT_FLING_VELOCITY, false);
} else if (clippedHeight != getLayout().getHeight() && isTracking) {
@@ -369,7 +367,7 @@ public class NotificationPanelViewController extends OverlayPanelViewController
// Updating the mNotificationListAtEndAtTimeOfTouch state has to be done after
// the event has been passed to the closeGestureDetector above, such that the
// closeGestureDetector sees the up event before the state has changed.
- if (event.getActionMasked() == MotionEvent.ACTION_UP) {
+ if (isClosingAction(event)) {
mNotificationListAtEndAtTimeOfTouch = false;
}
return handled || isTracking;
diff --git a/packages/CarSystemUI/src/com/android/systemui/car/statusbar/UserNameViewController.java b/packages/CarSystemUI/src/com/android/systemui/car/statusbar/UserNameViewController.java
new file mode 100644
index 000000000000..5ef8aa19b182
--- /dev/null
+++ b/packages/CarSystemUI/src/com/android/systemui/car/statusbar/UserNameViewController.java
@@ -0,0 +1,132 @@
+/*
+ * 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.car.statusbar;
+
+import android.car.Car;
+import android.car.user.CarUserManager;
+import android.content.BroadcastReceiver;
+import android.content.Context;
+import android.content.Intent;
+import android.content.IntentFilter;
+import android.content.pm.UserInfo;
+import android.os.UserHandle;
+import android.os.UserManager;
+import android.util.Log;
+import android.view.View;
+import android.widget.TextView;
+
+import com.android.systemui.R;
+import com.android.systemui.broadcast.BroadcastDispatcher;
+import com.android.systemui.car.CarDeviceProvisionedController;
+import com.android.systemui.car.CarServiceProvider;
+import com.android.systemui.dagger.SysUISingleton;
+
+import javax.inject.Inject;
+
+/**
+ * Controls a TextView with the current driver's username
+ */
+@SysUISingleton
+public class UserNameViewController {
+ private static final String TAG = "UserNameViewController";
+
+ private Context mContext;
+ private UserManager mUserManager;
+ private CarUserManager mCarUserManager;
+ private CarServiceProvider mCarServiceProvider;
+ private CarDeviceProvisionedController mCarDeviceProvisionedController;
+ private BroadcastDispatcher mBroadcastDispatcher;
+ private TextView mUserNameView;
+
+ private final BroadcastReceiver mUserUpdateReceiver = new BroadcastReceiver() {
+ @Override
+ public void onReceive(Context context, Intent intent) {
+ updateUser(mCarDeviceProvisionedController.getCurrentUser());
+ }
+ };
+
+ private final CarUserManager.UserLifecycleListener mUserLifecycleListener =
+ new CarUserManager.UserLifecycleListener() {
+ @Override
+ public void onEvent(CarUserManager.UserLifecycleEvent event) {
+ if (event.getEventType()
+ == CarUserManager.USER_LIFECYCLE_EVENT_TYPE_SWITCHING) {
+ updateUser(event.getUserId());
+ }
+ }
+ };
+
+ @Inject
+ public UserNameViewController(Context context, CarServiceProvider carServiceProvider,
+ UserManager userManager, BroadcastDispatcher broadcastDispatcher,
+ CarDeviceProvisionedController carDeviceProvisionedController) {
+ mContext = context;
+ mCarServiceProvider = carServiceProvider;
+ mUserManager = userManager;
+ mBroadcastDispatcher = broadcastDispatcher;
+ mCarDeviceProvisionedController = carDeviceProvisionedController;
+ }
+
+ /**
+ * Find the {@link TextView} for the driver's user name from a view and if found set it with the
+ * current driver's user name.
+ */
+ public void addUserNameView(View v) {
+ TextView userNameView = v.findViewById(R.id.user_name_text);
+ if (userNameView != null) {
+ if (mUserNameView == null) {
+ registerForUserChangeEvents();
+ }
+ mUserNameView = userNameView;
+ updateUser(mCarDeviceProvisionedController.getCurrentUser());
+ }
+ }
+
+ /**
+ * Clean up the controller and unregister receiver.
+ */
+ public void removeAll() {
+ mBroadcastDispatcher.unregisterReceiver(mUserUpdateReceiver);
+ if (mCarUserManager != null) {
+ mCarUserManager.removeListener(mUserLifecycleListener);
+ }
+ }
+
+ private void registerForUserChangeEvents() {
+ // Register for user switching
+ mCarServiceProvider.addListener(car -> {
+ mCarUserManager = (CarUserManager) car.getCarManager(Car.CAR_USER_SERVICE);
+ if (mCarUserManager != null) {
+ mCarUserManager.addListener(Runnable::run, mUserLifecycleListener);
+ } else {
+ Log.e(TAG, "CarUserManager could not be obtained.");
+ }
+ });
+ // Also register for user info changing
+ IntentFilter filter = new IntentFilter();
+ filter.addAction(Intent.ACTION_USER_INFO_CHANGED);
+ mBroadcastDispatcher.registerReceiver(mUserUpdateReceiver, filter, /* executor= */ null,
+ UserHandle.ALL);
+ }
+
+ private void updateUser(int userId) {
+ if (mUserNameView != null) {
+ UserInfo currentUserInfo = mUserManager.getUserInfo(userId);
+ mUserNameView.setText(currentUserInfo.name);
+ }
+ }
+}
diff --git a/packages/CarSystemUI/src/com/android/systemui/car/userswitcher/UserGridRecyclerView.java b/packages/CarSystemUI/src/com/android/systemui/car/userswitcher/UserGridRecyclerView.java
index 5bd8797c5349..023b5b4f5f30 100644
--- a/packages/CarSystemUI/src/com/android/systemui/car/userswitcher/UserGridRecyclerView.java
+++ b/packages/CarSystemUI/src/com/android/systemui/car/userswitcher/UserGridRecyclerView.java
@@ -131,7 +131,7 @@ public class UserGridRecyclerView extends RecyclerView {
}
private List<UserInfo> getUsersForUserGrid() {
- return mUserManager.getUsers(/* excludeDying= */ true)
+ return mUserManager.getAliveUsers()
.stream()
.filter(UserInfo::supportsSwitchToByUser)
.collect(Collectors.toList());
@@ -338,7 +338,7 @@ public class UserGridRecyclerView extends RecyclerView {
maxSupportedUsers -= 1;
}
- List<UserInfo> users = mUserManager.getUsers(/* excludeDying= */ true);
+ List<UserInfo> users = mUserManager.getAliveUsers();
// Count all users that are managed profiles of another user.
int managedProfilesCount = 0;
diff --git a/packages/CarSystemUI/src/com/android/systemui/car/window/OverlayPanelViewController.java b/packages/CarSystemUI/src/com/android/systemui/car/window/OverlayPanelViewController.java
index 45808a8a0b3e..d928ad0f42c9 100644
--- a/packages/CarSystemUI/src/com/android/systemui/car/window/OverlayPanelViewController.java
+++ b/packages/CarSystemUI/src/com/android/systemui/car/window/OverlayPanelViewController.java
@@ -34,7 +34,7 @@ import androidx.annotation.CallSuper;
import com.android.systemui.R;
import com.android.systemui.car.CarDeviceProvisionedController;
import com.android.systemui.dagger.qualifiers.Main;
-import com.android.systemui.statusbar.FlingAnimationUtils;
+import com.android.wm.shell.animation.FlingAnimationUtils;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
@@ -191,6 +191,38 @@ public abstract class OverlayPanelViewController extends OverlayViewController {
}
}
+ /** Checks if a {@link MotionEvent} is an action to open the panel.
+ * @param e {@link MotionEvent} to check.
+ * @return true only if opening action.
+ */
+ protected boolean isOpeningAction(MotionEvent e) {
+ if (mAnimateDirection == POSITIVE_DIRECTION) {
+ return e.getActionMasked() == MotionEvent.ACTION_DOWN;
+ }
+
+ if (mAnimateDirection == NEGATIVE_DIRECTION) {
+ return e.getActionMasked() == MotionEvent.ACTION_UP;
+ }
+
+ return false;
+ }
+
+ /** Checks if a {@link MotionEvent} is an action to close the panel.
+ * @param e {@link MotionEvent} to check.
+ * @return true only if closing action.
+ */
+ protected boolean isClosingAction(MotionEvent e) {
+ if (mAnimateDirection == POSITIVE_DIRECTION) {
+ return e.getActionMasked() == MotionEvent.ACTION_UP;
+ }
+
+ if (mAnimateDirection == NEGATIVE_DIRECTION) {
+ return e.getActionMasked() == MotionEvent.ACTION_DOWN;
+ }
+
+ return false;
+ }
+
/* ***************************************************************************************** *
* Panel Animation
* ***************************************************************************************** */
@@ -243,8 +275,7 @@ public abstract class OverlayPanelViewController extends OverlayViewController {
* Depending on certain conditions, determines whether to fully expand or collapse the panel.
*/
protected void maybeCompleteAnimation(MotionEvent event) {
- if (event.getActionMasked() == MotionEvent.ACTION_UP
- && isPanelVisible()) {
+ if (isClosingAction(event) && isPanelVisible()) {
if (mSettleClosePercentage < mPercentageFromEndingEdge) {
animatePanel(DEFAULT_FLING_VELOCITY, false);
} else {
@@ -266,14 +297,17 @@ public abstract class OverlayPanelViewController extends OverlayViewController {
float from = getCurrentStartPosition(rect);
if (from != to) {
animate(from, to, velocity, isClosing);
- return;
}
+
+ // If we swipe down the notification panel all the way to the bottom of the screen
+ // (i.e. from == to), then we have finished animating the panel.
+ return;
}
// We will only be here if the shade is being opened programmatically or via button when
// height of the layout was not calculated.
- ViewTreeObserver notificationTreeObserver = getLayout().getViewTreeObserver();
- notificationTreeObserver.addOnGlobalLayoutListener(
+ ViewTreeObserver panelTreeObserver = getLayout().getViewTreeObserver();
+ panelTreeObserver.addOnGlobalLayoutListener(
new ViewTreeObserver.OnGlobalLayoutListener() {
@Override
public void onGlobalLayout() {
@@ -476,6 +510,11 @@ public abstract class OverlayPanelViewController extends OverlayViewController {
return mIsTracking;
}
+ /** Sets whether the panel is currently tracking or not. */
+ protected final void setIsTracking(boolean isTracking) {
+ mIsTracking = isTracking;
+ }
+
/** Returns {@code true} if the panel is currently animating. */
protected final boolean isAnimating() {
return mIsAnimating;
@@ -514,7 +553,7 @@ public abstract class OverlayPanelViewController extends OverlayViewController {
}
setPanelVisible(true);
- // clips the view for the notification shade when the user scrolls to open.
+ // clips the view for the panel when the user scrolls to open.
setViewClipBounds((int) event2.getRawY());
// Initially the scroll starts with height being zero. This checks protects from divide
@@ -569,11 +608,11 @@ public abstract class OverlayPanelViewController extends OverlayViewController {
boolean isInClosingDirection = mAnimateDirection * distanceY > 0;
// This check is to figure out if onScroll was called while swiping the card at
- // bottom of the list. At that time we should not allow notification shade to
+ // bottom of the panel. At that time we should not allow panel to
// close. We are also checking for the upwards swipe gesture here because it is
- // possible if a user is closing the notification shade and while swiping starts
+ // possible if a user is closing the panel and while swiping starts
// to open again but does not fling. At that time we should allow the
- // notification shade to close fully or else it would stuck in between.
+ // panel to close fully or else it would stuck in between.
if (Math.abs(getLayout().getHeight() - y)
> SWIPE_DOWN_MIN_DISTANCE && isInClosingDirection) {
setViewClipBounds((int) y);
diff --git a/packages/CarSystemUI/src/com/android/systemui/wmshell/CarWMShellModule.java b/packages/CarSystemUI/src/com/android/systemui/wmshell/CarWMShellModule.java
index fd6685ffdb8f..6d31a8d69ebe 100644
--- a/packages/CarSystemUI/src/com/android/systemui/wmshell/CarWMShellModule.java
+++ b/packages/CarSystemUI/src/com/android/systemui/wmshell/CarWMShellModule.java
@@ -22,8 +22,6 @@ import android.view.IWindowManager;
import com.android.systemui.dagger.SysUISingleton;
import com.android.systemui.dagger.qualifiers.Main;
-import com.android.systemui.pip.phone.PipMenuActivity;
-import com.android.systemui.pip.phone.dagger.PipMenuActivityClass;
import com.android.systemui.wm.DisplaySystemBarsController;
import com.android.wm.shell.common.DisplayController;
import com.android.wm.shell.common.DisplayImeController;
@@ -43,12 +41,4 @@ public class CarWMShellModule {
return new DisplaySystemBarsController(context, wmService, displayController,
mainHandler, transactionPool);
}
-
- /** TODO(b/150319024): PipMenuActivity will move to a Window */
- @SysUISingleton
- @PipMenuActivityClass
- @Provides
- Class<?> providePipMenuActivityClass() {
- return PipMenuActivity.class;
- }
}
diff --git a/packages/CarSystemUI/tests/src/com/android/systemui/car/hvac/AdjustableTemperatureViewTest.java b/packages/CarSystemUI/tests/src/com/android/systemui/car/hvac/AdjustableTemperatureViewTest.java
new file mode 100644
index 000000000000..e8850def6bcd
--- /dev/null
+++ b/packages/CarSystemUI/tests/src/com/android/systemui/car/hvac/AdjustableTemperatureViewTest.java
@@ -0,0 +1,174 @@
+/*
+ * 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.car.hvac;
+
+import static android.car.VehicleAreaType.VEHICLE_AREA_TYPE_GLOBAL;
+import static android.car.VehiclePropertyIds.HVAC_TEMPERATURE_DISPLAY_UNITS;
+import static android.car.VehiclePropertyIds.HVAC_TEMPERATURE_SET;
+
+import static com.android.systemui.car.hvac.HvacController.convertToCelsius;
+import static com.android.systemui.car.hvac.HvacController.convertToFahrenheit;
+
+import static org.junit.Assert.assertEquals;
+import static org.mockito.ArgumentMatchers.anyInt;
+import static org.mockito.ArgumentMatchers.eq;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.when;
+
+import android.car.Car;
+import android.car.VehicleUnit;
+import android.car.hardware.property.CarPropertyManager;
+import android.testing.AndroidTestingRunner;
+import android.testing.TestableLooper;
+import android.widget.TextView;
+
+import androidx.test.filters.SmallTest;
+
+import com.android.systemui.R;
+import com.android.systemui.SysuiTestCase;
+import com.android.systemui.car.CarServiceProvider;
+import com.android.systemui.car.CarSystemUiTest;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.Mock;
+import org.mockito.MockitoAnnotations;
+
+@CarSystemUiTest
+@RunWith(AndroidTestingRunner.class)
+@TestableLooper.RunWithLooper
+@SmallTest
+public class AdjustableTemperatureViewTest extends SysuiTestCase {
+
+ private static final float TEMP_CELSIUS = 22.0f;
+ private final String mFormat = getContext().getString(R.string.hvac_temperature_format);
+ private AdjustableTemperatureView mAdjustableTemperatureView;
+ private HvacController mHvacController;
+
+ @Mock
+ private Car mCar;
+ @Mock
+ private CarPropertyManager mCarPropertyManager;
+
+ @Before
+ public void setUp() {
+ MockitoAnnotations.initMocks(this);
+ when(mCar.isConnected()).thenReturn(true);
+ when(mCar.getCarManager(Car.PROPERTY_SERVICE)).thenReturn(mCarPropertyManager);
+
+ CarServiceProvider carServiceProvider = new CarServiceProvider(mContext, mCar);
+ mHvacController = new HvacController(carServiceProvider);
+ mHvacController.connectToCarService();
+ mAdjustableTemperatureView = new AdjustableTemperatureView(getContext(), /* attrs= */ null);
+ mAdjustableTemperatureView.setHvacController(mHvacController);
+ }
+
+ @Test
+ public void addTemperatureViewToController_setsTemperatureView() {
+ when(mCarPropertyManager.isPropertyAvailable(eq(HVAC_TEMPERATURE_SET),
+ anyInt())).thenReturn(true);
+ when(mCarPropertyManager.getFloatProperty(eq(HVAC_TEMPERATURE_SET), anyInt())).thenReturn(
+ TEMP_CELSIUS);
+
+ mHvacController.addTemperatureViewToController(mAdjustableTemperatureView);
+
+ TextView tempText = mAdjustableTemperatureView.findViewById(R.id.hvac_temperature_text);
+ assertEquals(tempText.getText(), String.format(mFormat, TEMP_CELSIUS));
+ }
+
+ @Test
+ public void setTemperatureToFahrenheit_callsViewSetDisplayInFahrenheit() {
+ when(mCarPropertyManager.isPropertyAvailable(eq(HVAC_TEMPERATURE_SET),
+ anyInt())).thenReturn(true);
+ when(mCarPropertyManager.getFloatProperty(eq(HVAC_TEMPERATURE_SET), anyInt())).thenReturn(
+ TEMP_CELSIUS);
+ when(mCarPropertyManager.isPropertyAvailable(HVAC_TEMPERATURE_DISPLAY_UNITS,
+ VEHICLE_AREA_TYPE_GLOBAL)).thenReturn(true);
+ when(mCarPropertyManager.getIntProperty(HVAC_TEMPERATURE_DISPLAY_UNITS,
+ VEHICLE_AREA_TYPE_GLOBAL)).thenReturn(VehicleUnit.FAHRENHEIT);
+
+ mHvacController.addTemperatureViewToController(mAdjustableTemperatureView);
+
+ TextView tempText = mAdjustableTemperatureView.findViewById(R.id.hvac_temperature_text);
+ assertEquals(tempText.getText(), String.format(mFormat, convertToFahrenheit(TEMP_CELSIUS)));
+ }
+
+ @Test
+ public void adjustableViewIncreaseButton_setsTempWithCarPropertyManager() {
+ when(mCarPropertyManager.isPropertyAvailable(eq(HVAC_TEMPERATURE_SET),
+ anyInt())).thenReturn(true);
+ when(mCarPropertyManager.getFloatProperty(eq(HVAC_TEMPERATURE_SET), anyInt())).thenReturn(
+ TEMP_CELSIUS);
+ mHvacController.addTemperatureViewToController(mAdjustableTemperatureView);
+
+ mAdjustableTemperatureView.findViewById(R.id.hvac_increase_button).callOnClick();
+
+ verify(mCarPropertyManager).setFloatProperty(eq(HVAC_TEMPERATURE_SET), anyInt(),
+ eq(TEMP_CELSIUS + 1));
+ }
+
+ @Test
+ public void adjustableViewDecreaseButton_setsTempWithCarPropertyManager() {
+ when(mCarPropertyManager.isPropertyAvailable(eq(HVAC_TEMPERATURE_SET),
+ anyInt())).thenReturn(true);
+ when(mCarPropertyManager.getFloatProperty(eq(HVAC_TEMPERATURE_SET), anyInt())).thenReturn(
+ TEMP_CELSIUS);
+ mHvacController.addTemperatureViewToController(mAdjustableTemperatureView);
+
+ mAdjustableTemperatureView.findViewById(R.id.hvac_decrease_button).callOnClick();
+
+ verify(mCarPropertyManager).setFloatProperty(eq(HVAC_TEMPERATURE_SET), anyInt(),
+ eq(TEMP_CELSIUS - 1));
+ }
+
+ @Test
+ public void adjustableViewIncreaseButton_inFahrenheit_setsTempWithCarPropertyManager() {
+ when(mCarPropertyManager.isPropertyAvailable(eq(HVAC_TEMPERATURE_SET),
+ anyInt())).thenReturn(true);
+ when(mCarPropertyManager.getFloatProperty(eq(HVAC_TEMPERATURE_SET), anyInt())).thenReturn(
+ TEMP_CELSIUS);
+ when(mCarPropertyManager.isPropertyAvailable(HVAC_TEMPERATURE_DISPLAY_UNITS,
+ VEHICLE_AREA_TYPE_GLOBAL)).thenReturn(true);
+ when(mCarPropertyManager.getIntProperty(HVAC_TEMPERATURE_DISPLAY_UNITS,
+ VEHICLE_AREA_TYPE_GLOBAL)).thenReturn(VehicleUnit.FAHRENHEIT);
+ mHvacController.addTemperatureViewToController(mAdjustableTemperatureView);
+
+ mAdjustableTemperatureView.findViewById(R.id.hvac_increase_button).callOnClick();
+
+ verify(mCarPropertyManager).setFloatProperty(eq(HVAC_TEMPERATURE_SET), anyInt(),
+ eq(convertToCelsius(convertToFahrenheit(TEMP_CELSIUS) + 1)));
+ }
+
+ @Test
+ public void adjustableViewDecreaseButton_inFahrenheit_setsTempWithCarPropertyManager() {
+ when(mCarPropertyManager.isPropertyAvailable(eq(HVAC_TEMPERATURE_SET),
+ anyInt())).thenReturn(true);
+ when(mCarPropertyManager.getFloatProperty(eq(HVAC_TEMPERATURE_SET), anyInt())).thenReturn(
+ TEMP_CELSIUS);
+ when(mCarPropertyManager.isPropertyAvailable(HVAC_TEMPERATURE_DISPLAY_UNITS,
+ VEHICLE_AREA_TYPE_GLOBAL)).thenReturn(true);
+ when(mCarPropertyManager.getIntProperty(HVAC_TEMPERATURE_DISPLAY_UNITS,
+ VEHICLE_AREA_TYPE_GLOBAL)).thenReturn(VehicleUnit.FAHRENHEIT);
+ mHvacController.addTemperatureViewToController(mAdjustableTemperatureView);
+
+ mAdjustableTemperatureView.findViewById(R.id.hvac_decrease_button).callOnClick();
+
+ verify(mCarPropertyManager).setFloatProperty(eq(HVAC_TEMPERATURE_SET), anyInt(),
+ eq(convertToCelsius(convertToFahrenheit(TEMP_CELSIUS) - 1)));
+ }
+}
diff --git a/packages/CarSystemUI/tests/src/com/android/systemui/car/hvac/HvacControllerTest.java b/packages/CarSystemUI/tests/src/com/android/systemui/car/hvac/HvacControllerTest.java
index e179ef1ce2a4..9912657d78e1 100644
--- a/packages/CarSystemUI/tests/src/com/android/systemui/car/hvac/HvacControllerTest.java
+++ b/packages/CarSystemUI/tests/src/com/android/systemui/car/hvac/HvacControllerTest.java
@@ -16,7 +16,13 @@
package com.android.systemui.car.hvac;
+import static android.car.VehicleAreaType.VEHICLE_AREA_TYPE_GLOBAL;
+import static android.car.VehiclePropertyIds.HVAC_TEMPERATURE_DISPLAY_UNITS;
+import static android.car.VehiclePropertyIds.HVAC_TEMPERATURE_SET;
+
import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.ArgumentMatchers.anyFloat;
+import static org.mockito.ArgumentMatchers.eq;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.never;
import static org.mockito.Mockito.reset;
@@ -24,7 +30,8 @@ import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
import android.car.Car;
-import android.car.hardware.hvac.CarHvacManager;
+import android.car.VehicleUnit;
+import android.car.hardware.property.CarPropertyManager;
import android.testing.AndroidTestingRunner;
import android.testing.TestableLooper;
@@ -46,92 +53,91 @@ import org.mockito.MockitoAnnotations;
@SmallTest
public class HvacControllerTest extends SysuiTestCase {
- private static final int PROPERTY_ID = 1;
private static final int AREA_ID = 1;
- private static final float VALUE = 72.0f;
+ private static final float TEMP = 72.0f;
private HvacController mHvacController;
- private CarServiceProvider mCarServiceProvider;
@Mock
private Car mCar;
@Mock
- private CarHvacManager mCarHvacManager;
+ private CarPropertyManager mCarPropertyManager;
@Before
public void setUp() {
MockitoAnnotations.initMocks(this);
when(mCar.isConnected()).thenReturn(true);
- when(mCar.getCarManager(Car.HVAC_SERVICE)).thenReturn(mCarHvacManager);
+ when(mCar.getCarManager(Car.PROPERTY_SERVICE)).thenReturn(mCarPropertyManager);
- mCarServiceProvider = new CarServiceProvider(mContext, mCar);
- mHvacController = new HvacController(mCarServiceProvider);
+ CarServiceProvider carServiceProvider = new CarServiceProvider(mContext, mCar);
+ mHvacController = new HvacController(carServiceProvider);
mHvacController.connectToCarService();
}
@Test
public void connectToCarService_registersCallback() {
- verify(mCarHvacManager).registerCallback(any());
+ verify(mCarPropertyManager).registerCallback(any(), eq(HVAC_TEMPERATURE_SET), anyFloat());
+ verify(mCarPropertyManager).registerCallback(any(), eq(HVAC_TEMPERATURE_DISPLAY_UNITS),
+ anyFloat());
}
@Test
public void addTemperatureViewToController_usingTemperatureView_registersView() {
- TemperatureTextView v = setupMockTemperatureTextView(PROPERTY_ID, AREA_ID, VALUE);
+ TemperatureTextView v = setupMockTemperatureTextView(AREA_ID, TEMP);
mHvacController.addTemperatureViewToController(v);
- verify(v).setTemp(VALUE);
+ verify(v).setTemperatureView(TEMP);
}
@Test
public void addTemperatureViewToController_usingSameTemperatureView_registersFirstView() {
- TemperatureTextView v = setupMockTemperatureTextView(PROPERTY_ID, AREA_ID, VALUE);
+ TemperatureTextView v = setupMockTemperatureTextView(AREA_ID, TEMP);
mHvacController.addTemperatureViewToController(v);
- verify(v).setTemp(VALUE);
- resetTemperatureView(v, PROPERTY_ID, AREA_ID);
+ verify(v).setTemperatureView(TEMP);
+ resetTemperatureView(v, AREA_ID);
mHvacController.addTemperatureViewToController(v);
- verify(v, never()).setTemp(VALUE);
+ verify(v, never()).setTemperatureView(TEMP);
}
@Test
public void addTemperatureViewToController_usingDifferentTemperatureView_registersBothViews() {
- TemperatureTextView v1 = setupMockTemperatureTextView(PROPERTY_ID, AREA_ID, VALUE);
+ TemperatureTextView v1 = setupMockTemperatureTextView(AREA_ID, TEMP);
mHvacController.addTemperatureViewToController(v1);
- verify(v1).setTemp(VALUE);
+ verify(v1).setTemperatureView(TEMP);
TemperatureTextView v2 = setupMockTemperatureTextView(
- PROPERTY_ID + 1,
AREA_ID + 1,
- VALUE + 1);
+ TEMP + 1);
mHvacController.addTemperatureViewToController(v2);
- verify(v2).setTemp(VALUE + 1);
+ verify(v2).setTemperatureView(TEMP + 1);
}
@Test
- public void removeAllComponents_ableToRegisterSameView() {
- TemperatureTextView v = setupMockTemperatureTextView(PROPERTY_ID, AREA_ID, VALUE);
- mHvacController.addTemperatureViewToController(v);
- verify(v).setTemp(VALUE);
-
- mHvacController.removeAllComponents();
- resetTemperatureView(v, PROPERTY_ID, AREA_ID);
+ public void setTemperatureToFahrenheit_callsViewSetDisplayInFahrenheit() {
+ when(mCarPropertyManager.isPropertyAvailable(HVAC_TEMPERATURE_DISPLAY_UNITS,
+ VEHICLE_AREA_TYPE_GLOBAL)).thenReturn(true);
+ when(mCarPropertyManager.getIntProperty(HVAC_TEMPERATURE_DISPLAY_UNITS,
+ VEHICLE_AREA_TYPE_GLOBAL)).thenReturn(VehicleUnit.FAHRENHEIT);
+ TemperatureTextView v = setupMockTemperatureTextView(AREA_ID, TEMP);
mHvacController.addTemperatureViewToController(v);
- verify(v).setTemp(VALUE);
+
+ verify(v).setDisplayInFahrenheit(true);
+ verify(v).setTemperatureView(TEMP);
}
- private TemperatureTextView setupMockTemperatureTextView(int propertyId, int areaId,
- float value) {
+ private TemperatureTextView setupMockTemperatureTextView(int areaId, float value) {
TemperatureTextView v = mock(TemperatureTextView.class);
- resetTemperatureView(v, propertyId, areaId);
- when(mCarHvacManager.isPropertyAvailable(propertyId, areaId)).thenReturn(true);
- when(mCarHvacManager.getFloatProperty(propertyId, areaId)).thenReturn(value);
+ resetTemperatureView(v, areaId);
+ when(mCarPropertyManager.isPropertyAvailable(HVAC_TEMPERATURE_SET, areaId)).thenReturn(
+ true);
+ when(mCarPropertyManager.getFloatProperty(HVAC_TEMPERATURE_SET, areaId)).thenReturn(value);
return v;
}
- private void resetTemperatureView(TemperatureTextView view, int propertyId, int areaId) {
+ private void resetTemperatureView(TemperatureTextView view, int areaId) {
reset(view);
- when(view.getPropertyId()).thenReturn(propertyId);
when(view.getAreaId()).thenReturn(areaId);
}
}
diff --git a/packages/CarSystemUI/tests/src/com/android/systemui/car/hvac/TemperatureTextViewTest.java b/packages/CarSystemUI/tests/src/com/android/systemui/car/hvac/TemperatureTextViewTest.java
new file mode 100644
index 000000000000..e97d9d9b3f6a
--- /dev/null
+++ b/packages/CarSystemUI/tests/src/com/android/systemui/car/hvac/TemperatureTextViewTest.java
@@ -0,0 +1,107 @@
+/*
+ * 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.car.hvac;
+
+import static android.car.VehicleAreaType.VEHICLE_AREA_TYPE_GLOBAL;
+import static android.car.VehiclePropertyIds.HVAC_TEMPERATURE_DISPLAY_UNITS;
+import static android.car.VehiclePropertyIds.HVAC_TEMPERATURE_SET;
+
+import static com.android.systemui.car.hvac.HvacController.convertToFahrenheit;
+
+import static org.junit.Assert.assertEquals;
+import static org.mockito.ArgumentMatchers.anyInt;
+import static org.mockito.ArgumentMatchers.eq;
+import static org.mockito.Mockito.when;
+
+import android.car.Car;
+import android.car.VehicleUnit;
+import android.car.hardware.property.CarPropertyManager;
+import android.content.Context;
+import android.testing.AndroidTestingRunner;
+import android.testing.TestableLooper;
+
+import androidx.test.filters.SmallTest;
+
+import com.android.systemui.R;
+import com.android.systemui.SysuiTestCase;
+import com.android.systemui.car.CarServiceProvider;
+import com.android.systemui.car.CarSystemUiTest;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.Mock;
+import org.mockito.MockitoAnnotations;
+
+@CarSystemUiTest
+@RunWith(AndroidTestingRunner.class)
+@TestableLooper.RunWithLooper
+@SmallTest
+public class TemperatureTextViewTest extends SysuiTestCase {
+ private static final float TEMP = 72.0f;
+ private final String mFormat = getContext().getString(R.string.hvac_temperature_format);
+ private HvacController mHvacController;
+ private TemperatureTextView mTextView;
+
+ @Mock
+ private Context mContext;
+
+ @Mock
+ private Car mCar;
+ @Mock
+ private CarPropertyManager mCarPropertyManager;
+
+ @Before
+ public void setUp() {
+ MockitoAnnotations.initMocks(this);
+ when(mCar.isConnected()).thenReturn(true);
+ when(mCar.getCarManager(Car.PROPERTY_SERVICE)).thenReturn(mCarPropertyManager);
+
+ CarServiceProvider carServiceProvider = new CarServiceProvider(mContext, mCar);
+ mHvacController = new HvacController(carServiceProvider);
+ mHvacController.connectToCarService();
+ mTextView = new TemperatureTextView(getContext(), /* attrs= */ null);
+ }
+
+ @Test
+ public void addTemperatureViewToController_usingTemperatureView_registersView() {
+ when(mCarPropertyManager.isPropertyAvailable(eq(HVAC_TEMPERATURE_SET),
+ anyInt())).thenReturn(true);
+ when(mCarPropertyManager.getFloatProperty(eq(HVAC_TEMPERATURE_SET), anyInt())).thenReturn(
+ TEMP);
+
+ mHvacController.addTemperatureViewToController(mTextView);
+
+ assertEquals(mTextView.getText(), String.format(mFormat, TEMP));
+ }
+
+ @Test
+ public void setTemperatureToFahrenheit_callsViewSetDisplayInFahrenheit() {
+ when(mCarPropertyManager.isPropertyAvailable(eq(HVAC_TEMPERATURE_SET),
+ anyInt())).thenReturn(true);
+ when(mCarPropertyManager.getFloatProperty(eq(HVAC_TEMPERATURE_SET), anyInt())).thenReturn(
+ TEMP);
+ when(mCarPropertyManager.isPropertyAvailable(HVAC_TEMPERATURE_DISPLAY_UNITS,
+ VEHICLE_AREA_TYPE_GLOBAL)).thenReturn(true);
+ when(mCarPropertyManager.getIntProperty(HVAC_TEMPERATURE_DISPLAY_UNITS,
+ VEHICLE_AREA_TYPE_GLOBAL)).thenReturn(VehicleUnit.FAHRENHEIT);
+
+ mHvacController.addTemperatureViewToController(mTextView);
+
+ assertEquals(mTextView.getText(), String.format(mFormat, convertToFahrenheit(TEMP)));
+ }
+}
diff --git a/packages/CarSystemUI/tests/src/com/android/systemui/car/keyguard/CarKeyguardViewControllerTest.java b/packages/CarSystemUI/tests/src/com/android/systemui/car/keyguard/CarKeyguardViewControllerTest.java
index 62dc23624520..63d4004fb640 100644
--- a/packages/CarSystemUI/tests/src/com/android/systemui/car/keyguard/CarKeyguardViewControllerTest.java
+++ b/packages/CarSystemUI/tests/src/com/android/systemui/car/keyguard/CarKeyguardViewControllerTest.java
@@ -26,7 +26,6 @@ import static org.mockito.Mockito.reset;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
-import android.content.Context;
import android.os.Handler;
import android.testing.AndroidTestingRunner;
import android.testing.TestableLooper;
@@ -35,20 +34,17 @@ import android.view.ViewGroup;
import androidx.test.filters.SmallTest;
-import com.android.internal.widget.LockPatternUtils;
import com.android.keyguard.KeyguardUpdateMonitor;
import com.android.keyguard.ViewMediatorCallback;
+import com.android.keyguard.dagger.KeyguardBouncerComponent;
import com.android.systemui.R;
import com.android.systemui.SysuiTestCase;
import com.android.systemui.car.CarServiceProvider;
import com.android.systemui.car.CarSystemUiTest;
import com.android.systemui.car.navigationbar.CarNavigationBarController;
import com.android.systemui.car.window.OverlayViewGlobalStateController;
-import com.android.systemui.keyguard.DismissCallbackRegistry;
-import com.android.systemui.plugins.FalsingManager;
import com.android.systemui.statusbar.phone.BiometricUnlockController;
import com.android.systemui.statusbar.phone.KeyguardBouncer;
-import com.android.systemui.statusbar.phone.KeyguardBypassController;
import com.android.systemui.statusbar.policy.KeyguardStateController;
import org.junit.Before;
@@ -58,31 +54,36 @@ import org.mockito.InOrder;
import org.mockito.Mock;
import org.mockito.MockitoAnnotations;
-import dagger.Lazy;
-
@CarSystemUiTest
@RunWith(AndroidTestingRunner.class)
@TestableLooper.RunWithLooper
@SmallTest
public class CarKeyguardViewControllerTest extends SysuiTestCase {
- private TestableCarKeyguardViewController mCarKeyguardViewController;
+ private CarKeyguardViewController mCarKeyguardViewController;
@Mock
private OverlayViewGlobalStateController mOverlayViewGlobalStateController;
@Mock
- private KeyguardBouncer mBouncer;
+ private CarKeyguardViewController.OnKeyguardCancelClickedListener mCancelClickedListener;
@Mock
- private CarNavigationBarController mCarNavigationBarController;
+ private KeyguardBouncerComponent.Factory mKeyguardBouncerComponentFactory;
@Mock
- private CarKeyguardViewController.OnKeyguardCancelClickedListener mCancelClickedListener;
+ private KeyguardBouncerComponent mKeyguardBouncerComponent;
+ @Mock
+ private KeyguardBouncer mBouncer;
@Before
public void setUp() {
MockitoAnnotations.initMocks(this);
- mCarKeyguardViewController = new TestableCarKeyguardViewController(
- mContext,
+ when(mKeyguardBouncerComponentFactory.build(
+ any(ViewGroup.class),
+ any(KeyguardBouncer.BouncerExpansionCallback.class)))
+ .thenReturn(mKeyguardBouncerComponent);
+ when(mKeyguardBouncerComponent.createKeyguardBouncer()).thenReturn(mBouncer);
+
+ mCarKeyguardViewController = new CarKeyguardViewController(
Handler.getMain(),
mock(CarServiceProvider.class),
mOverlayViewGlobalStateController,
@@ -91,10 +92,7 @@ public class CarKeyguardViewControllerTest extends SysuiTestCase {
() -> mock(BiometricUnlockController.class),
mock(ViewMediatorCallback.class),
mock(CarNavigationBarController.class),
- mock(LockPatternUtils.class),
- mock(DismissCallbackRegistry.class),
- mock(FalsingManager.class),
- () -> mock(KeyguardBypassController.class)
+ mKeyguardBouncerComponentFactory
);
mCarKeyguardViewController.inflate((ViewGroup) LayoutInflater.from(mContext).inflate(
R.layout.sysui_overlay_window, /* root= */ null));
@@ -202,33 +200,4 @@ public class CarKeyguardViewControllerTest extends SysuiTestCase {
verify(mBouncer).hide(/* destroyView= */ true);
}
-
- private class TestableCarKeyguardViewController extends CarKeyguardViewController {
-
- TestableCarKeyguardViewController(Context context,
- Handler mainHandler,
- CarServiceProvider carServiceProvider,
- OverlayViewGlobalStateController overlayViewGlobalStateController,
- KeyguardStateController keyguardStateController,
- KeyguardUpdateMonitor keyguardUpdateMonitor,
- Lazy<BiometricUnlockController> biometricUnlockControllerLazy,
- ViewMediatorCallback viewMediatorCallback,
- CarNavigationBarController carNavigationBarController,
- LockPatternUtils lockPatternUtils,
- DismissCallbackRegistry dismissCallbackRegistry,
- FalsingManager falsingManager,
- Lazy<KeyguardBypassController> keyguardBypassControllerLazy) {
- super(context, mainHandler, carServiceProvider, overlayViewGlobalStateController,
- keyguardStateController, keyguardUpdateMonitor, biometricUnlockControllerLazy,
- viewMediatorCallback, carNavigationBarController, lockPatternUtils,
- dismissCallbackRegistry, falsingManager, keyguardBypassControllerLazy);
- }
-
- @Override
- public void onFinishInflate() {
- super.onFinishInflate();
- setKeyguardBouncer(CarKeyguardViewControllerTest.this.mBouncer);
- }
- }
-
}
diff --git a/packages/CarSystemUI/tests/src/com/android/systemui/car/navigationbar/CarNavigationBarControllerTest.java b/packages/CarSystemUI/tests/src/com/android/systemui/car/navigationbar/CarNavigationBarControllerTest.java
index 0b164a2e1a51..0b3ac2a98e3a 100644
--- a/packages/CarSystemUI/tests/src/com/android/systemui/car/navigationbar/CarNavigationBarControllerTest.java
+++ b/packages/CarSystemUI/tests/src/com/android/systemui/car/navigationbar/CarNavigationBarControllerTest.java
@@ -33,6 +33,7 @@ import com.android.systemui.R;
import com.android.systemui.SysuiTestCase;
import com.android.systemui.car.CarSystemUiTest;
import com.android.systemui.car.hvac.HvacController;
+import com.android.systemui.car.statusbar.UserNameViewController;
import com.android.systemui.plugins.DarkIconDispatcher;
import com.android.systemui.statusbar.phone.StatusBarIconController;
@@ -48,6 +49,10 @@ import org.mockito.MockitoAnnotations;
@SmallTest
public class CarNavigationBarControllerTest extends SysuiTestCase {
+ private static final String TOP_NOTIFICATION_PANEL =
+ "com.android.systemui.car.notification.TopNotificationPanelViewMediator";
+ private static final String BOTTOM_NOTIFICATION_PANEL =
+ "com.android.systemui.car.notification.BottomNotificationPanelViewMediator";
private CarNavigationBarController mCarNavigationBar;
private NavigationBarViewFactory mNavigationBarViewFactory;
private TestableResources mTestableResources;
@@ -58,6 +63,8 @@ public class CarNavigationBarControllerTest extends SysuiTestCase {
private ButtonRoleHolderController mButtonRoleHolderController;
@Mock
private HvacController mHvacController;
+ @Mock
+ private UserNameViewController mUserNameViewController;
@Before
public void setUp() throws Exception {
@@ -73,7 +80,7 @@ public class CarNavigationBarControllerTest extends SysuiTestCase {
private CarNavigationBarController createNavigationBarController() {
return new CarNavigationBarController(mContext, mNavigationBarViewFactory,
mButtonSelectionStateController, () -> mHvacController,
- mButtonRoleHolderController,
+ () -> mUserNameViewController, mButtonRoleHolderController,
new SystemBarConfigs(mTestableResources.getResources()));
}
@@ -117,6 +124,11 @@ public class CarNavigationBarControllerTest extends SysuiTestCase {
@Test
public void testGetTopWindow_topDisabled_returnsNull() {
mTestableResources.addOverride(R.bool.config_enableTopNavigationBar, false);
+ mTestableResources.addOverride(R.bool.config_enableBottomNavigationBar, true);
+ // If Top Notification Panel is used but top navigation bar is not enabled, SystemUI is
+ // expected to crash.
+ mTestableResources.addOverride(R.string.config_notificationPanelViewMediator,
+ BOTTOM_NOTIFICATION_PANEL);
mCarNavigationBar = createNavigationBarController();
ViewGroup window = mCarNavigationBar.getTopWindow();
@@ -148,6 +160,11 @@ public class CarNavigationBarControllerTest extends SysuiTestCase {
@Test
public void testGetBottomWindow_bottomDisabled_returnsNull() {
mTestableResources.addOverride(R.bool.config_enableBottomNavigationBar, false);
+ mTestableResources.addOverride(R.bool.config_enableTopNavigationBar, true);
+ // If Bottom Notification Panel is used but bottom navigation bar is not enabled,
+ // SystemUI is expected to crash.
+ mTestableResources.addOverride(R.string.config_notificationPanelViewMediator,
+ TOP_NOTIFICATION_PANEL);
mCarNavigationBar = createNavigationBarController();
ViewGroup window = mCarNavigationBar.getBottomWindow();
diff --git a/packages/CarSystemUI/tests/src/com/android/systemui/car/navigationbar/SystemBarConfigsTest.java b/packages/CarSystemUI/tests/src/com/android/systemui/car/navigationbar/SystemBarConfigsTest.java
index 8b1589913d1d..072358b9f27c 100644
--- a/packages/CarSystemUI/tests/src/com/android/systemui/car/navigationbar/SystemBarConfigsTest.java
+++ b/packages/CarSystemUI/tests/src/com/android/systemui/car/navigationbar/SystemBarConfigsTest.java
@@ -25,6 +25,7 @@ import static org.mockito.Mockito.when;
import android.content.res.Resources;
import android.testing.AndroidTestingRunner;
import android.testing.TestableLooper;
+import android.util.ArrayMap;
import android.view.WindowManager;
import androidx.test.filters.SmallTest;
@@ -41,16 +42,20 @@ import org.mockito.MockitoAnnotations;
import java.util.ArrayList;
import java.util.List;
+import java.util.Map;
@CarSystemUiTest
@RunWith(AndroidTestingRunner.class)
@TestableLooper.RunWithLooper
@SmallTest
public class SystemBarConfigsTest extends SysuiTestCase {
+ private static final int SYSTEM_BAR_GIRTH = 100;
private SystemBarConfigs mSystemBarConfigs;
@Mock
private Resources mResources;
+ @Mock
+ private CarNavigationBarView mCarNavigationBarView;
@Before
public void setUp() {
@@ -133,6 +138,41 @@ public class SystemBarConfigsTest extends SysuiTestCase {
assertEquals(lp.type, WindowManager.LayoutParams.TYPE_STATUS_BAR_ADDITIONAL);
}
+ @Test
+ public void updateInsetPaddings_overlappingBarWithHigherZOrderDisappeared_removesInset() {
+ mSystemBarConfigs = new SystemBarConfigs(mResources);
+ CarNavigationBarView leftBar = new CarNavigationBarView(mContext, /* attrs= */ null);
+ Map<Integer, Boolean> visibilities = new ArrayMap<>();
+ visibilities.put(SystemBarConfigs.TOP, false);
+ visibilities.put(SystemBarConfigs.BOTTOM, true);
+ visibilities.put(SystemBarConfigs.LEFT, true);
+ visibilities.put(SystemBarConfigs.RIGHT, true);
+
+ mSystemBarConfigs.updateInsetPaddings(SystemBarConfigs.LEFT, visibilities);
+ mSystemBarConfigs.insetSystemBar(SystemBarConfigs.LEFT, leftBar);
+
+ assertEquals(0, leftBar.getPaddingTop());
+ }
+
+ @Test
+ public void updateInsetPaddings_overlappingBarWithHigherZOrderReappeared_addsInset() {
+ mSystemBarConfigs = new SystemBarConfigs(mResources);
+ CarNavigationBarView leftBar = new CarNavigationBarView(mContext, /* attrs= */ null);
+ Map<Integer, Boolean> visibilities = new ArrayMap<>();
+ visibilities.put(SystemBarConfigs.TOP, false);
+ visibilities.put(SystemBarConfigs.BOTTOM, true);
+ visibilities.put(SystemBarConfigs.LEFT, true);
+ visibilities.put(SystemBarConfigs.RIGHT, true);
+
+ mSystemBarConfigs.updateInsetPaddings(SystemBarConfigs.LEFT, visibilities);
+ mSystemBarConfigs.insetSystemBar(SystemBarConfigs.LEFT, leftBar);
+ visibilities.put(SystemBarConfigs.TOP, true);
+ mSystemBarConfigs.updateInsetPaddings(SystemBarConfigs.LEFT, visibilities);
+ mSystemBarConfigs.insetSystemBar(SystemBarConfigs.LEFT, leftBar);
+
+ assertEquals(SYSTEM_BAR_GIRTH, leftBar.getPaddingTop());
+ }
+
// Set valid config where all system bars are enabled.
private void setDefaultValidConfig() {
when(mResources.getBoolean(R.bool.config_enableTopNavigationBar)).thenReturn(true);
@@ -141,13 +181,13 @@ public class SystemBarConfigsTest extends SysuiTestCase {
when(mResources.getBoolean(R.bool.config_enableRightNavigationBar)).thenReturn(true);
when(mResources.getDimensionPixelSize(
- com.android.internal.R.dimen.status_bar_height)).thenReturn(100);
+ com.android.internal.R.dimen.status_bar_height)).thenReturn(SYSTEM_BAR_GIRTH);
when(mResources.getDimensionPixelSize(
- com.android.internal.R.dimen.navigation_bar_height)).thenReturn(100);
+ com.android.internal.R.dimen.navigation_bar_height)).thenReturn(SYSTEM_BAR_GIRTH);
when(mResources.getDimensionPixelSize(R.dimen.car_left_navigation_bar_width)).thenReturn(
- 100);
+ SYSTEM_BAR_GIRTH);
when(mResources.getDimensionPixelSize(R.dimen.car_right_navigation_bar_width)).thenReturn(
- 100);
+ SYSTEM_BAR_GIRTH);
when(mResources.getInteger(R.integer.config_topSystemBarType)).thenReturn(0);
when(mResources.getInteger(R.integer.config_bottomSystemBarType)).thenReturn(1);
diff --git a/packages/CarSystemUI/tests/src/com/android/systemui/car/statusbar/UserNameViewControllerTest.java b/packages/CarSystemUI/tests/src/com/android/systemui/car/statusbar/UserNameViewControllerTest.java
new file mode 100644
index 000000000000..8f9e56edf419
--- /dev/null
+++ b/packages/CarSystemUI/tests/src/com/android/systemui/car/statusbar/UserNameViewControllerTest.java
@@ -0,0 +1,155 @@
+/*
+ * 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.car.statusbar;
+
+import static org.junit.Assert.assertEquals;
+import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.Mockito.reset;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.verifyZeroInteractions;
+import static org.mockito.Mockito.when;
+
+import android.car.Car;
+import android.car.user.CarUserManager;
+import android.content.BroadcastReceiver;
+import android.content.Intent;
+import android.content.pm.UserInfo;
+import android.os.UserManager;
+import android.testing.AndroidTestingRunner;
+import android.testing.TestableLooper;
+import android.view.View;
+import android.widget.TextView;
+
+import androidx.test.filters.SmallTest;
+
+import com.android.systemui.R;
+import com.android.systemui.SysuiTestCase;
+import com.android.systemui.broadcast.BroadcastDispatcher;
+import com.android.systemui.car.CarDeviceProvisionedController;
+import com.android.systemui.car.CarServiceProvider;
+import com.android.systemui.car.CarSystemUiTest;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.ArgumentCaptor;
+import org.mockito.Mock;
+import org.mockito.MockitoAnnotations;
+
+@CarSystemUiTest
+@RunWith(AndroidTestingRunner.class)
+@TestableLooper.RunWithLooper
+@SmallTest
+public class UserNameViewControllerTest extends SysuiTestCase {
+
+ private final UserInfo mUserInfo1 = new UserInfo(/* id= */ 0, "Test User Name", /* flags= */ 0);
+ private final UserInfo mUserInfo2 = new UserInfo(/* id= */ 1, "Another User", /* flags= */ 0);
+ private TextView mTextView;
+ private UserNameViewController mUserNameViewController;
+
+ @Mock
+ private Car mCar;
+ @Mock
+ private CarUserManager mCarUserManager;
+ @Mock
+ private UserManager mUserManager;
+ @Mock
+ private CarDeviceProvisionedController mCarDeviceProvisionedController;
+ @Mock
+ private BroadcastDispatcher mBroadcastDispatcher;
+
+ @Before
+ public void setUp() {
+ MockitoAnnotations.initMocks(this);
+ when(mUserManager.getUserInfo(mUserInfo1.id)).thenReturn(mUserInfo1);
+ when(mUserManager.getUserInfo(mUserInfo2.id)).thenReturn(mUserInfo2);
+ when(mCar.isConnected()).thenReturn(true);
+ when(mCar.getCarManager(Car.CAR_USER_SERVICE)).thenReturn(mCarUserManager);
+
+ CarServiceProvider carServiceProvider = new CarServiceProvider(mContext, mCar);
+ mUserNameViewController = new UserNameViewController(getContext(), carServiceProvider,
+ mUserManager, mBroadcastDispatcher, mCarDeviceProvisionedController);
+
+ mTextView = new TextView(getContext());
+ mTextView.setId(R.id.user_name_text);
+ }
+
+ @Test
+ public void addUserNameViewToController_updatesUserNameView() {
+ when(mCarDeviceProvisionedController.getCurrentUser()).thenReturn(mUserInfo1.id);
+
+ mUserNameViewController.addUserNameView(mTextView);
+
+ assertEquals(mTextView.getText(), mUserInfo1.name);
+ }
+
+ @Test
+ public void addUserNameViewToController_withNoTextView_doesNotUpdate() {
+ View nullView = new View(getContext());
+ mUserNameViewController.addUserNameView(nullView);
+
+ assertEquals(mTextView.getText(), "");
+ verifyZeroInteractions(mCarDeviceProvisionedController);
+ verifyZeroInteractions(mCarUserManager);
+ verifyZeroInteractions(mUserManager);
+ }
+
+ @Test
+ public void userLifecycleListener_onUserSwitchLifecycleEvent_updatesUserNameView() {
+ ArgumentCaptor<CarUserManager.UserLifecycleListener> userLifecycleListenerArgumentCaptor =
+ ArgumentCaptor.forClass(CarUserManager.UserLifecycleListener.class);
+ when(mCarDeviceProvisionedController.getCurrentUser()).thenReturn(mUserInfo1.id);
+ // Add the initial TextView, which registers the UserLifecycleListener
+ mUserNameViewController.addUserNameView(mTextView);
+ assertEquals(mTextView.getText(), mUserInfo1.name);
+ verify(mCarUserManager).addListener(any(), userLifecycleListenerArgumentCaptor.capture());
+
+ CarUserManager.UserLifecycleEvent event = new CarUserManager.UserLifecycleEvent(
+ CarUserManager.USER_LIFECYCLE_EVENT_TYPE_SWITCHING, /* from= */ mUserInfo1.id,
+ /* to= */ mUserInfo2.id);
+ userLifecycleListenerArgumentCaptor.getValue().onEvent(event);
+
+ assertEquals(mTextView.getText(), mUserInfo2.name);
+ }
+
+ @Test
+ public void userInfoChangedBroadcast_withoutInitializingUserNameView_doesNothing() {
+ getContext().sendBroadcast(new Intent(Intent.ACTION_USER_INFO_CHANGED));
+
+ assertEquals(mTextView.getText(), "");
+ verifyZeroInteractions(mCarDeviceProvisionedController);
+ }
+
+ @Test
+ public void userInfoChangedBroadcast_withUserNameViewInitialized_updatesUserNameView() {
+ ArgumentCaptor<BroadcastReceiver> broadcastReceiverArgumentCaptor = ArgumentCaptor.forClass(
+ BroadcastReceiver.class);
+ when(mCarDeviceProvisionedController.getCurrentUser()).thenReturn(mUserInfo1.id);
+ mUserNameViewController.addUserNameView(mTextView);
+ assertEquals(mTextView.getText(), mUserInfo1.name);
+ verify(mBroadcastDispatcher).registerReceiver(broadcastReceiverArgumentCaptor.capture(),
+ any(), any(), any());
+
+ reset(mCarDeviceProvisionedController);
+ when(mCarDeviceProvisionedController.getCurrentUser()).thenReturn(mUserInfo2.id);
+ broadcastReceiverArgumentCaptor.getValue().onReceive(getContext(),
+ new Intent(Intent.ACTION_USER_INFO_CHANGED));
+
+ assertEquals(mTextView.getText(), mUserInfo2.name);
+ verify(mCarDeviceProvisionedController).getCurrentUser();
+ }
+}
diff --git a/packages/CarSystemUI/tests/src/com/android/systemui/car/window/OverlayPanelViewControllerTest.java b/packages/CarSystemUI/tests/src/com/android/systemui/car/window/OverlayPanelViewControllerTest.java
index 7311cdb68a3c..bed803eedc22 100644
--- a/packages/CarSystemUI/tests/src/com/android/systemui/car/window/OverlayPanelViewControllerTest.java
+++ b/packages/CarSystemUI/tests/src/com/android/systemui/car/window/OverlayPanelViewControllerTest.java
@@ -40,8 +40,8 @@ import androidx.test.filters.SmallTest;
import com.android.systemui.SysuiTestCase;
import com.android.systemui.car.CarDeviceProvisionedController;
import com.android.systemui.car.CarSystemUiTest;
-import com.android.systemui.statusbar.FlingAnimationUtils;
import com.android.systemui.tests.R;
+import com.android.wm.shell.animation.FlingAnimationUtils;
import org.junit.Before;
import org.junit.Test;
diff --git a/packages/CompanionDeviceManager/TEST_MAPPING b/packages/CompanionDeviceManager/TEST_MAPPING
new file mode 100644
index 000000000000..63f54fa35158
--- /dev/null
+++ b/packages/CompanionDeviceManager/TEST_MAPPING
@@ -0,0 +1,12 @@
+{
+ "presubmit": [
+ {
+ "name": "CtsOsTestCases",
+ "options": [
+ {
+ "include-filter": "android.os.cts.CompanionDeviceManagerTest"
+ }
+ ]
+ }
+ ]
+}
diff --git a/packages/DynamicSystemInstallationService/src/com/android/dynsystem/InstallationAsyncTask.java b/packages/DynamicSystemInstallationService/src/com/android/dynsystem/InstallationAsyncTask.java
index f8952ace3cb3..4d31ce97e8b7 100644
--- a/packages/DynamicSystemInstallationService/src/com/android/dynsystem/InstallationAsyncTask.java
+++ b/packages/DynamicSystemInstallationService/src/com/android/dynsystem/InstallationAsyncTask.java
@@ -334,6 +334,11 @@ class InstallationAsyncTask extends AsyncTask<String, InstallationAsyncTask.Prog
throw new IOException(
"Failed to start installation with requested size: " + mUserdataSize);
}
+ // Reset installation session and verify that installation completes successfully.
+ mInstallationSession = null;
+ if (!mDynSystem.closePartition()) {
+ throw new IOException("Failed to complete partition installation: userdata");
+ }
}
private void installImages()
@@ -503,6 +508,12 @@ class InstallationAsyncTask extends AsyncTask<String, InstallationAsyncTask.Prog
imageValidationThrowOrWarning(new KeyRevokedException(publicKey));
}
}
+
+ // Reset installation session and verify that installation completes successfully.
+ mInstallationSession = null;
+ if (!mDynSystem.closePartition()) {
+ throw new IOException("Failed to complete partition installation: " + partitionName);
+ }
}
private static String toHexString(byte[] bytes) {
diff --git a/packages/ExternalStorageProvider/src/com/android/externalstorage/ExternalStorageProvider.java b/packages/ExternalStorageProvider/src/com/android/externalstorage/ExternalStorageProvider.java
index f42bf1982b36..11d1b0a9ef2a 100644
--- a/packages/ExternalStorageProvider/src/com/android/externalstorage/ExternalStorageProvider.java
+++ b/packages/ExternalStorageProvider/src/com/android/externalstorage/ExternalStorageProvider.java
@@ -483,6 +483,13 @@ public class ExternalStorageProvider extends FileSystemProvider {
}
@Override
+ protected void onDocIdDeleted(String docId) {
+ Uri uri = DocumentsContract.buildDocumentUri(AUTHORITY, docId);
+ getContext().revokeUriPermission(uri, ~0);
+ }
+
+
+ @Override
public Cursor queryRoots(String[] projection) throws FileNotFoundException {
final MatrixCursor result = new MatrixCursor(resolveRootProjection(projection));
synchronized (mRootsLock) {
diff --git a/packages/PrintSpooler/res/values-fa/strings.xml b/packages/PrintSpooler/res/values-fa/strings.xml
index 596947dfb6dc..719fc9219450 100644
--- a/packages/PrintSpooler/res/values-fa/strings.xml
+++ b/packages/PrintSpooler/res/values-fa/strings.xml
@@ -31,7 +31,7 @@
<string name="template_all_pages" msgid="3322235982020148762">"همه <xliff:g id="PAGE_COUNT">%1$s</xliff:g> صفحه"</string>
<string name="template_page_range" msgid="428638530038286328">"محدوده <xliff:g id="PAGE_COUNT">%1$s</xliff:g> صفحه"</string>
<string name="pages_range_example" msgid="8558694453556945172">"‏‏‎مثلاً ۱—۵،‏۹،۷—۱۰"</string>
- <string name="print_preview" msgid="8010217796057763343">"پیش‌نمایش چاپ"</string>
+ <string name="print_preview" msgid="8010217796057763343">"پیش‌نمای چاپ"</string>
<string name="install_for_print_preview" msgid="6366303997385509332">"‏نصب نمایشگر PDF برای پیش‌نمایش"</string>
<string name="printing_app_crashed" msgid="854477616686566398">"برنامه چاپ خراب شد"</string>
<string name="generating_print_job" msgid="3119608742651698916">"در حال ایجاد کار چاپ"</string>
diff --git a/packages/PrintSpooler/res/values-uz/strings.xml b/packages/PrintSpooler/res/values-uz/strings.xml
index d17bce7ae54e..ea0a6ea2f7b8 100644
--- a/packages/PrintSpooler/res/values-uz/strings.xml
+++ b/packages/PrintSpooler/res/values-uz/strings.xml
@@ -100,7 +100,7 @@
</string-array>
<string-array name="orientation_labels">
<item msgid="4061931020926489228">"Tik holat"</item>
- <item msgid="3199660090246166812">"Eniga"</item>
+ <item msgid="3199660090246166812">"Yotiq"</item>
</string-array>
<string name="print_write_error_message" msgid="5787642615179572543">"Faylga yozib bo‘lmadi"</string>
<string name="print_error_default_message" msgid="8602678405502922346">"Xatolik yuz berdi. Qaytadan urining."</string>
diff --git a/packages/SettingsLib/res/drawable/ic_show_x_wifi_signal_0.xml b/packages/SettingsLib/res/drawable/ic_show_x_wifi_signal_0.xml
new file mode 100644
index 000000000000..16e91903084f
--- /dev/null
+++ b/packages/SettingsLib/res/drawable/ic_show_x_wifi_signal_0.xml
@@ -0,0 +1,31 @@
+<!--
+ 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.
+-->
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+ android:width="24dp"
+ android:height="24dp"
+ android:viewportWidth="25.50"
+ android:viewportHeight="25.50">
+ <group
+ android:translateX="0.77"
+ android:translateY="0.23" >
+ <path
+ android:pathData="M14,12h6.54l3.12,-3.89c0.39,-0.48 0.29,-1.19 -0.22,-1.54C21.67,5.36 17.55,3 12,3C6.44,3 2.33,5.36 0.56,6.57C0.05,6.92 -0.05,7.63 0.33,8.11L11.16,21.6c0.42,0.53 1.23,0.53 1.66,0L14,20.13V12z"
+ android:fillColor="#FFFFFF"/>
+ <path
+ android:pathData="M22.71,15.67l-1.83,1.83l1.83,1.83c0.38,0.38 0.38,1 0,1.38v0c-0.38,0.38 -1,0.39 -1.38,0l-1.83,-1.83l-1.83,1.83c-0.38,0.38 -1,0.38 -1.38,0l-0.01,-0.01c-0.38,-0.38 -0.38,-1 0,-1.38l1.83,-1.83l-1.82,-1.82c-0.38,-0.38 -0.38,-1 0,-1.38l0.01,-0.01c0.38,-0.38 1,-0.38 1.38,0l1.82,1.82l1.82,-1.82c0.38,-0.38 1,-0.38 1.38,0l0,0C23.09,14.67 23.09,15.29 22.71,15.67z"
+ android:fillColor="#FFFFFF"/>
+ </group>
+</vector>
diff --git a/packages/SettingsLib/res/drawable/ic_show_x_wifi_signal_1.xml b/packages/SettingsLib/res/drawable/ic_show_x_wifi_signal_1.xml
new file mode 100644
index 000000000000..4c338c968194
--- /dev/null
+++ b/packages/SettingsLib/res/drawable/ic_show_x_wifi_signal_1.xml
@@ -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.
+-->
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+ android:width="24dp"
+ android:height="24dp"
+ android:viewportWidth="24.0"
+ android:viewportHeight="24.0">
+ <path
+ android:fillColor="@android:color/white"
+ android:pathData="M22,16.41L20.59,15l-2.09,2.09L16.41,15L15,16.41l2.09,2.09L15,20.59L16.41,22l2.09,-2.08L20.59,22L22,20.59l-2.08,-2.09L22,16.41z"/>
+ <path
+ android:fillColor="@android:color/white"
+ android:pathData="M12,2.01C7.25,2.01 2.97,4.09 0,7.4L7.582,16.625C7.582,16.627 7.58,16.629 7.58,16.631L11.99,22L12,22L13,20.789L13,17.641L13,13.119C12.68,13.039 12.34,13 12,13C10.601,13 9.351,13.64 8.531,14.639L2.699,7.539C5.269,5.279 8.58,4.01 12,4.01C15.42,4.01 18.731,5.279 21.301,7.539L16.811,13L19.4,13L24,7.4C21.03,4.09 16.75,2.01 12,2.01z"/>
+</vector>
diff --git a/packages/SettingsLib/res/drawable/ic_show_x_wifi_signal_2.xml b/packages/SettingsLib/res/drawable/ic_show_x_wifi_signal_2.xml
new file mode 100644
index 000000000000..79037dbccf2d
--- /dev/null
+++ b/packages/SettingsLib/res/drawable/ic_show_x_wifi_signal_2.xml
@@ -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.
+-->
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+ android:width="24dp"
+ android:height="24dp"
+ android:viewportWidth="24.0"
+ android:viewportHeight="24.0">
+ <path
+ android:fillColor="@android:color/white"
+ android:pathData="M22,16.41L20.59,15l-2.09,2.09L16.41,15L15,16.41l2.09,2.09L15,20.59L16.41,22l2.09,-2.08L20.59,22L22,20.59l-2.08,-2.09L22,16.41z"/>
+ <path
+ android:fillColor="@android:color/white"
+ android:pathData="M12,2C7.25,2 2.97,4.081 0,7.391L12,22L13,20.779L13,17.631L13,13L16.801,13L18,13L19.391,13L24,7.391C21.03,4.081 16.75,2 12,2zM12,4C14.747,4 17.423,4.819 19.701,6.313C20.259,6.678 20.795,7.085 21.301,7.529L17.389,12.287C16.029,10.868 14.119,9.99 12,9.99C9.88,9.99 7.969,10.869 6.609,12.289L2.699,7.529C5.269,5.269 8.58,4 12,4z"/>
+</vector>
diff --git a/packages/SettingsLib/res/drawable/ic_show_x_wifi_signal_3.xml b/packages/SettingsLib/res/drawable/ic_show_x_wifi_signal_3.xml
new file mode 100644
index 000000000000..21ad128f81ff
--- /dev/null
+++ b/packages/SettingsLib/res/drawable/ic_show_x_wifi_signal_3.xml
@@ -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.
+-->
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+ android:width="24dp"
+ android:height="24dp"
+ android:viewportWidth="24.0"
+ android:viewportHeight="24.0">
+ <path
+ android:fillColor="@android:color/white"
+ android:pathData="M22,16.41L20.59,15l-2.09,2.09L16.41,15L15,16.41l2.09,2.09L15,20.59L16.41,22l2.09,-2.08L20.59,22L22,20.59l-2.08,-2.09L22,16.41z"/>
+ <path
+ android:fillColor="@android:color/white"
+ android:pathData="M12,2C7.25,2 2.97,4.081 0,7.391L3.301,11.41L12,22L13,20.779L13,17.631L13,13L16.801,13L19.391,13L20.699,11.41C20.699,11.409 20.698,11.409 20.697,11.408L24,7.391C21.03,4.081 16.75,2 12,2zM12,4C15.42,4 18.731,5.269 21.301,7.529L19.35,9.9C17.43,8.1 14.86,6.99 12,6.99C9.14,6.99 6.57,8.1 4.65,9.9C4.65,9.901 4.649,9.902 4.648,9.902L2.699,7.529C5.269,5.269 8.58,4 12,4z"/>
+</vector>
diff --git a/packages/SettingsLib/res/drawable/ic_show_x_wifi_signal_4.xml b/packages/SettingsLib/res/drawable/ic_show_x_wifi_signal_4.xml
new file mode 100644
index 000000000000..2ec5ba30cdc3
--- /dev/null
+++ b/packages/SettingsLib/res/drawable/ic_show_x_wifi_signal_4.xml
@@ -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.
+-->
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+ android:width="24dp"
+ android:height="24dp"
+ android:viewportWidth="24.0"
+ android:viewportHeight="24.0">
+ <path
+ android:fillColor="@android:color/white"
+ android:pathData="M12,2C7.25,2 2.97,4.08 0,7.39L12,22l1,-1.22V13h6.39L24,7.39C21.03,4.08 16.75,2 12,2z"/>
+ <path
+ android:fillColor="@android:color/white"
+ android:pathData="M22,16.41L20.59,15l-2.09,2.09L16.41,15L15,16.41l2.09,2.09L15,20.59L16.41,22l2.09,-2.08L20.59,22L22,20.59l-2.08,-2.09L22,16.41z"/>
+</vector>
diff --git a/packages/SettingsLib/res/values-fa/strings.xml b/packages/SettingsLib/res/values-fa/strings.xml
index f3b22d355b77..5fc311af26b2 100644
--- a/packages/SettingsLib/res/values-fa/strings.xml
+++ b/packages/SettingsLib/res/values-fa/strings.xml
@@ -139,7 +139,7 @@
<string name="accessibility_wifi_signal_full" msgid="7165262794551355617">"‏قدرت سیگنال Wi‑Fi کامل است."</string>
<string name="accessibility_wifi_security_type_none" msgid="162352241518066966">"شبکه باز"</string>
<string name="accessibility_wifi_security_type_secured" msgid="2399774097343238942">"شبکه ایمن"</string>
- <string name="process_kernel_label" msgid="950292573930336765">"‏سیستم عامل Android"</string>
+ <string name="process_kernel_label" msgid="950292573930336765">"‏سیستم‌عامل Android"</string>
<string name="data_usage_uninstalled_apps" msgid="1933665711856171491">"برنامه‌های حذف شده"</string>
<string name="data_usage_uninstalled_apps_users" msgid="5533981546921913295">"برنامه‌ها و کاربران حذف شده"</string>
<string name="data_usage_ota" msgid="7984667793701597001">"به‌روزرسانی‌های سیستم"</string>
diff --git a/packages/SettingsLib/src/com/android/settingslib/Utils.java b/packages/SettingsLib/src/com/android/settingslib/Utils.java
index a43412e116c8..2fd46d94d5cc 100644
--- a/packages/SettingsLib/src/com/android/settingslib/Utils.java
+++ b/packages/SettingsLib/src/com/android/settingslib/Utils.java
@@ -13,6 +13,7 @@ import android.content.res.ColorStateList;
import android.content.res.Resources;
import android.content.res.TypedArray;
import android.graphics.Bitmap;
+import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.drawable.BitmapDrawable;
import android.graphics.drawable.Drawable;
@@ -29,6 +30,10 @@ import android.telephony.AccessNetworkConstants;
import android.telephony.NetworkRegistrationInfo;
import android.telephony.ServiceState;
+import androidx.annotation.NonNull;
+import androidx.core.graphics.drawable.RoundedBitmapDrawable;
+import androidx.core.graphics.drawable.RoundedBitmapDrawableFactory;
+
import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.util.UserIcons;
import com.android.launcher3.icons.IconFactory;
@@ -49,11 +54,19 @@ public class Utils {
private static String sSharedSystemSharedLibPackageName;
static final int[] WIFI_PIE = {
- com.android.internal.R.drawable.ic_wifi_signal_0,
- com.android.internal.R.drawable.ic_wifi_signal_1,
- com.android.internal.R.drawable.ic_wifi_signal_2,
- com.android.internal.R.drawable.ic_wifi_signal_3,
- com.android.internal.R.drawable.ic_wifi_signal_4
+ com.android.internal.R.drawable.ic_wifi_signal_0,
+ com.android.internal.R.drawable.ic_wifi_signal_1,
+ com.android.internal.R.drawable.ic_wifi_signal_2,
+ com.android.internal.R.drawable.ic_wifi_signal_3,
+ com.android.internal.R.drawable.ic_wifi_signal_4
+ };
+
+ static final int[] SHOW_X_WIFI_PIE = {
+ R.drawable.ic_show_x_wifi_signal_0,
+ R.drawable.ic_show_x_wifi_signal_1,
+ R.drawable.ic_show_x_wifi_signal_2,
+ R.drawable.ic_show_x_wifi_signal_3,
+ R.drawable.ic_show_x_wifi_signal_4
};
public static void updateLocationEnabled(Context context, boolean enabled, int userId,
@@ -353,10 +366,22 @@ public class Utils {
* @throws IllegalArgumentException if an invalid RSSI level is given.
*/
public static int getWifiIconResource(int level) {
+ return getWifiIconResource(false /* showX */, level);
+ }
+
+ /**
+ * Returns the Wifi icon resource for a given RSSI level.
+ *
+ * @param showX True if a connected Wi-Fi network has the problem which should show Pie+x
+ * signal icon to users.
+ * @param level The number of bars to show (0-4)
+ * @throws IllegalArgumentException if an invalid RSSI level is given.
+ */
+ public static int getWifiIconResource(boolean showX, int level) {
if (level < 0 || level >= WIFI_PIE.length) {
throw new IllegalArgumentException("No Wifi icon found for level: " + level);
}
- return WIFI_PIE[level];
+ return showX ? SHOW_X_WIFI_PIE[level] : WIFI_PIE[level];
}
public static int getDefaultStorageManagerDaysToRetain(Resources resources) {
@@ -484,4 +509,25 @@ public class Utils {
== NetworkRegistrationInfo.REGISTRATION_STATE_ROAMING);
return !isInIwlan;
}
+
+ /**
+ * Returns a bitmap with rounded corner.
+ *
+ * @param context application context.
+ * @param source bitmap to apply round corner.
+ * @param cornerRadius corner radius value.
+ */
+ public static Bitmap convertCornerRadiusBitmap(@NonNull Context context,
+ @NonNull Bitmap source, @NonNull float cornerRadius) {
+ final Bitmap roundedBitmap = Bitmap.createBitmap(source.getWidth(), source.getHeight(),
+ Bitmap.Config.ARGB_8888);
+ final RoundedBitmapDrawable drawable =
+ RoundedBitmapDrawableFactory.create(context.getResources(), source);
+ drawable.setAntiAlias(true);
+ drawable.setCornerRadius(cornerRadius);
+ final Canvas canvas = new Canvas(roundedBitmap);
+ drawable.setBounds(0, 0, canvas.getWidth(), canvas.getHeight());
+ drawable.draw(canvas);
+ return roundedBitmap;
+ }
}
diff --git a/packages/SettingsLib/src/com/android/settingslib/bluetooth/BluetoothUtils.java b/packages/SettingsLib/src/com/android/settingslib/bluetooth/BluetoothUtils.java
index 68f72896c251..8f8f859d1ada 100644
--- a/packages/SettingsLib/src/com/android/settingslib/bluetooth/BluetoothUtils.java
+++ b/packages/SettingsLib/src/com/android/settingslib/bluetooth/BluetoothUtils.java
@@ -18,6 +18,7 @@ import android.util.Log;
import android.util.Pair;
import androidx.annotation.DrawableRes;
+import androidx.core.graphics.drawable.IconCompat;
import com.android.settingslib.R;
import com.android.settingslib.widget.AdaptiveIcon;
@@ -216,6 +217,23 @@ public class BluetoothUtils {
}
/**
+ * Create an Icon pointing to a drawable.
+ */
+ public static IconCompat createIconWithDrawable(Drawable drawable) {
+ Bitmap bitmap;
+ if (drawable instanceof BitmapDrawable) {
+ bitmap = ((BitmapDrawable) drawable).getBitmap();
+ } else {
+ final int width = drawable.getIntrinsicWidth();
+ final int height = drawable.getIntrinsicHeight();
+ bitmap = createBitmap(drawable,
+ width > 0 ? width : 1,
+ height > 0 ? height : 1);
+ }
+ return IconCompat.createWithBitmap(bitmap);
+ }
+
+ /**
* Build device icon with advanced outline
*/
public static Drawable buildAdvancedDrawable(Context context, Drawable drawable) {
diff --git a/packages/SettingsLib/src/com/android/settingslib/media/MediaOutputSliceConstants.java b/packages/SettingsLib/src/com/android/settingslib/media/MediaOutputSliceConstants.java
index 2821af97ed98..0d54d7ee9b5c 100644
--- a/packages/SettingsLib/src/com/android/settingslib/media/MediaOutputSliceConstants.java
+++ b/packages/SettingsLib/src/com/android/settingslib/media/MediaOutputSliceConstants.java
@@ -60,8 +60,30 @@ public class MediaOutputSliceConstants {
"com.android.settings.panel.action.MEDIA_OUTPUT_GROUP";
/**
- * An string extra specifying a media package name.
+ * A string extra specifying a media package name.
*/
public static final String EXTRA_PACKAGE_NAME =
"com.android.settings.panel.extra.PACKAGE_NAME";
+
+ /**
+ * An intent action to launch media output dialog.
+ */
+ public static final String ACTION_LAUNCH_MEDIA_OUTPUT_DIALOG =
+ "com.android.systemui.action.LAUNCH_MEDIA_OUTPUT_DIALOG";
+
+ /**
+ * Settings package name.
+ */
+ public static final String SETTINGS_PACKAGE_NAME = "com.android.settings";
+
+ /**
+ * An intent action to launch Bluetooth paring page.
+ */
+ public static final String ACTION_LAUNCH_BLUETOOTH_PAIRING =
+ "com.android.settings.action.LAUNCH_BLUETOOTH_PAIRING";
+
+ /**
+ * SystemUi package name.
+ */
+ public static final String SYSTEMUI_PACKAGE_NAME = "com.android.systemui";
}
diff --git a/packages/SettingsLib/src/com/android/settingslib/wifi/WifiEntryPreference.java b/packages/SettingsLib/src/com/android/settingslib/wifi/WifiEntryPreference.java
index a53bc9f966d2..bba69f29a290 100644
--- a/packages/SettingsLib/src/com/android/settingslib/wifi/WifiEntryPreference.java
+++ b/packages/SettingsLib/src/com/android/settingslib/wifi/WifiEntryPreference.java
@@ -35,6 +35,7 @@ import androidx.preference.PreferenceViewHolder;
import com.android.settingslib.R;
import com.android.settingslib.Utils;
import com.android.wifitrackerlib.WifiEntry;
+import com.android.wifitrackerlib.WifiEntry.ConnectedInfo;
/**
* Preference to display a WifiEntry in a wifi picker.
@@ -64,6 +65,7 @@ public class WifiEntryPreference extends Preference implements WifiEntry.WifiEnt
private final IconInjector mIconInjector;
private WifiEntry mWifiEntry;
private int mLevel = -1;
+ private boolean mShowX; // Shows the Wi-Fi signl icon of Pie+x when it's true.
private CharSequence mContentDescription;
private OnButtonClickListener mOnButtonClickListener;
@@ -136,9 +138,15 @@ public class WifiEntryPreference extends Preference implements WifiEntry.WifiEnt
public void refresh() {
setTitle(mWifiEntry.getTitle());
final int level = mWifiEntry.getLevel();
- if (level != mLevel) {
+ final ConnectedInfo connectedInfo = mWifiEntry.getConnectedInfo();
+ boolean showX = false;
+ if (connectedInfo != null) {
+ showX = !connectedInfo.isDefaultNetwork || !connectedInfo.isValidated;
+ }
+ if (level != mLevel || showX != mShowX) {
mLevel = level;
- updateIcon(mLevel);
+ mShowX = showX;
+ updateIcon(mShowX, mLevel);
notifyChanged();
}
@@ -184,13 +192,13 @@ public class WifiEntryPreference extends Preference implements WifiEntry.WifiEnt
}
- private void updateIcon(int level) {
+ private void updateIcon(boolean showX, int level) {
if (level == -1) {
setIcon(null);
return;
}
- final Drawable drawable = mIconInjector.getIcon(level);
+ final Drawable drawable = mIconInjector.getIcon(showX, level);
if (drawable != null) {
drawable.setTintList(Utils.getColorAttr(getContext(),
android.R.attr.colorControlNormal));
@@ -260,8 +268,8 @@ public class WifiEntryPreference extends Preference implements WifiEntry.WifiEnt
mContext = context;
}
- public Drawable getIcon(int level) {
- return mContext.getDrawable(Utils.getWifiIconResource(level));
+ public Drawable getIcon(boolean showX, int level) {
+ return mContext.getDrawable(Utils.getWifiIconResource(showX, level));
}
}
diff --git a/packages/SettingsLib/src/com/android/settingslib/wifi/WifiStatusTracker.java b/packages/SettingsLib/src/com/android/settingslib/wifi/WifiStatusTracker.java
index bc58bfc97718..c57d4ad962bd 100644
--- a/packages/SettingsLib/src/com/android/settingslib/wifi/WifiStatusTracker.java
+++ b/packages/SettingsLib/src/com/android/settingslib/wifi/WifiStatusTracker.java
@@ -13,6 +13,7 @@ package com.android.settingslib.wifi;
import static android.net.NetworkCapabilities.NET_CAPABILITY_CAPTIVE_PORTAL;
import static android.net.NetworkCapabilities.NET_CAPABILITY_PARTIAL_CONNECTIVITY;
import static android.net.NetworkCapabilities.NET_CAPABILITY_VALIDATED;
+import static android.net.NetworkCapabilities.TRANSPORT_CELLULAR;
import android.content.Context;
import android.content.Intent;
@@ -250,6 +251,10 @@ public class WifiStatusTracker {
statusLabel = mContext.getString(R.string.wifi_status_no_internet);
}
return;
+ } else if (!isDefaultNetwork && mDefaultNetworkCapabilities != null
+ && mDefaultNetworkCapabilities.hasTransport(TRANSPORT_CELLULAR)) {
+ statusLabel = mContext.getString(R.string.wifi_connected_low_quality);
+ return;
}
}
diff --git a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/wifi/WifiEntryPreferenceTest.java b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/wifi/WifiEntryPreferenceTest.java
index 46e699d3bed5..40af7dc797b3 100644
--- a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/wifi/WifiEntryPreferenceTest.java
+++ b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/wifi/WifiEntryPreferenceTest.java
@@ -17,6 +17,7 @@ package com.android.settingslib.wifi;
import static com.google.common.truth.Truth.assertThat;
+import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.when;
import android.content.Context;
@@ -29,6 +30,7 @@ import androidx.preference.PreferenceViewHolder;
import com.android.settingslib.R;
import com.android.wifitrackerlib.WifiEntry;
+import com.android.wifitrackerlib.WifiEntry.ConnectedInfo;
import org.junit.Before;
import org.junit.Test;
@@ -62,6 +64,17 @@ public class WifiEntryPreferenceTest {
@Mock
private Drawable mMockDrawable4;
+ @Mock
+ private Drawable mMockShowXDrawable0;
+ @Mock
+ private Drawable mMockShowXDrawable1;
+ @Mock
+ private Drawable mMockShowXDrawable2;
+ @Mock
+ private Drawable mMockShowXDrawable3;
+ @Mock
+ private Drawable mMockShowXDrawable4;
+
private static final String MOCK_TITLE = "title";
private static final String MOCK_SUMMARY = "summary";
private static final String FAKE_URI_STRING = "fakeuri";
@@ -75,11 +88,22 @@ public class WifiEntryPreferenceTest {
when(mMockWifiEntry.getTitle()).thenReturn(MOCK_TITLE);
when(mMockWifiEntry.getSummary(false /* concise */)).thenReturn(MOCK_SUMMARY);
- when(mMockIconInjector.getIcon(0)).thenReturn(mMockDrawable0);
- when(mMockIconInjector.getIcon(1)).thenReturn(mMockDrawable1);
- when(mMockIconInjector.getIcon(2)).thenReturn(mMockDrawable2);
- when(mMockIconInjector.getIcon(3)).thenReturn(mMockDrawable3);
- when(mMockIconInjector.getIcon(4)).thenReturn(mMockDrawable4);
+ when(mMockIconInjector.getIcon(false /* showX */, 0)).thenReturn(mMockDrawable0);
+ when(mMockIconInjector.getIcon(false /* showX */, 1)).thenReturn(mMockDrawable1);
+ when(mMockIconInjector.getIcon(false /* showX */, 2)).thenReturn(mMockDrawable2);
+ when(mMockIconInjector.getIcon(false /* showX */, 3)).thenReturn(mMockDrawable3);
+ when(mMockIconInjector.getIcon(false /* showX */, 4)).thenReturn(mMockDrawable4);
+
+ when(mMockIconInjector.getIcon(true /* showX */, 0))
+ .thenReturn(mMockShowXDrawable0);
+ when(mMockIconInjector.getIcon(true /* showX */, 1))
+ .thenReturn(mMockShowXDrawable1);
+ when(mMockIconInjector.getIcon(true /* showX */, 2))
+ .thenReturn(mMockShowXDrawable2);
+ when(mMockIconInjector.getIcon(true /* showX */, 3))
+ .thenReturn(mMockShowXDrawable3);
+ when(mMockIconInjector.getIcon(true /* showX */, 4))
+ .thenReturn(mMockShowXDrawable4);
}
@Test
@@ -155,6 +179,70 @@ public class WifiEntryPreferenceTest {
}
@Test
+ public void levelChanged_notDefaultWifiRefresh_shouldUpdateLevelIcon() {
+ final List<Drawable> iconList = new ArrayList<>();
+ final ConnectedInfo mockConnectedInfo = mock(ConnectedInfo.class);
+ mockConnectedInfo.isDefaultNetwork = false;
+ when(mMockWifiEntry.getConnectedInfo()).thenReturn(mockConnectedInfo);
+ final WifiEntryPreference pref =
+ new WifiEntryPreference(mContext, mMockWifiEntry, mMockIconInjector);
+
+ when(mMockWifiEntry.getLevel()).thenReturn(0);
+ pref.refresh();
+ iconList.add(pref.getIcon());
+ when(mMockWifiEntry.getLevel()).thenReturn(1);
+ pref.refresh();
+ iconList.add(pref.getIcon());
+ when(mMockWifiEntry.getLevel()).thenReturn(2);
+ pref.refresh();
+ iconList.add(pref.getIcon());
+ when(mMockWifiEntry.getLevel()).thenReturn(3);
+ pref.refresh();
+ iconList.add(pref.getIcon());
+ when(mMockWifiEntry.getLevel()).thenReturn(4);
+ pref.refresh();
+ iconList.add(pref.getIcon());
+ when(mMockWifiEntry.getLevel()).thenReturn(-1);
+ pref.refresh();
+ iconList.add(pref.getIcon());
+
+ assertThat(iconList).containsExactly(mMockShowXDrawable0, mMockShowXDrawable1,
+ mMockShowXDrawable2, mMockShowXDrawable3, mMockShowXDrawable4, null);
+ }
+
+ @Test
+ public void levelChanged_notValidatedWifiRefresh_shouldUpdateLevelIcon() {
+ final List<Drawable> iconList = new ArrayList<>();
+ final ConnectedInfo mockConnectedInfo = mock(ConnectedInfo.class);
+ mockConnectedInfo.isValidated = false;
+ when(mMockWifiEntry.getConnectedInfo()).thenReturn(mockConnectedInfo);
+ final WifiEntryPreference pref =
+ new WifiEntryPreference(mContext, mMockWifiEntry, mMockIconInjector);
+
+ when(mMockWifiEntry.getLevel()).thenReturn(0);
+ pref.refresh();
+ iconList.add(pref.getIcon());
+ when(mMockWifiEntry.getLevel()).thenReturn(1);
+ pref.refresh();
+ iconList.add(pref.getIcon());
+ when(mMockWifiEntry.getLevel()).thenReturn(2);
+ pref.refresh();
+ iconList.add(pref.getIcon());
+ when(mMockWifiEntry.getLevel()).thenReturn(3);
+ pref.refresh();
+ iconList.add(pref.getIcon());
+ when(mMockWifiEntry.getLevel()).thenReturn(4);
+ pref.refresh();
+ iconList.add(pref.getIcon());
+ when(mMockWifiEntry.getLevel()).thenReturn(-1);
+ pref.refresh();
+ iconList.add(pref.getIcon());
+
+ assertThat(iconList).containsExactly(mMockShowXDrawable0, mMockShowXDrawable1,
+ mMockShowXDrawable2, mMockShowXDrawable3, mMockShowXDrawable4, null);
+ }
+
+ @Test
public void notNull_whenGetHelpUriString_shouldSetImageButtonVisible() {
when(mMockWifiEntry.getHelpUriString()).thenReturn(FAKE_URI_STRING);
final WifiEntryPreference pref =
diff --git a/packages/SettingsProvider/src/com/android/providers/settings/SettingsProvider.java b/packages/SettingsProvider/src/com/android/providers/settings/SettingsProvider.java
index 807fbed7d8fd..9c92b464dfbb 100644
--- a/packages/SettingsProvider/src/com/android/providers/settings/SettingsProvider.java
+++ b/packages/SettingsProvider/src/com/android/providers/settings/SettingsProvider.java
@@ -2576,7 +2576,7 @@ public class SettingsProvider extends ContentProvider {
public void syncSsaidTableOnStart() {
synchronized (mLock) {
// Verify that each user's packages and ssaid's are in sync.
- for (UserInfo user : mUserManager.getUsers(true)) {
+ for (UserInfo user : mUserManager.getAliveUsers()) {
// Get all uids for the user's packages.
final List<PackageInfo> packages;
try {
@@ -3007,7 +3007,7 @@ public class SettingsProvider extends ContentProvider {
final long identity = Binder.clearCallingIdentity();
try {
- List<UserInfo> users = mUserManager.getUsers(true);
+ List<UserInfo> users = mUserManager.getAliveUsers();
final int userCount = users.size();
for (int i = 0; i < userCount; i++) {
@@ -3244,7 +3244,7 @@ public class SettingsProvider extends ContentProvider {
// is a singleton generation entry for the global settings which
// is already incremented be the caller.
final Uri uri = getNotificationUriFor(key, name);
- final List<UserInfo> users = mUserManager.getUsers(/*excludeDying*/ true);
+ final List<UserInfo> users = mUserManager.getAliveUsers();
for (int i = 0; i < users.size(); i++) {
final int userId = users.get(i).id;
if (mUserManager.isUserRunning(UserHandle.of(userId))) {
@@ -3255,7 +3255,7 @@ public class SettingsProvider extends ContentProvider {
}
private void notifyLocationChangeForRunningUsers() {
- final List<UserInfo> users = mUserManager.getUsers(/*excludeDying=*/ true);
+ final List<UserInfo> users = mUserManager.getAliveUsers();
for (int i = 0; i < users.size(); i++) {
final int userId = users.get(i).id;
diff --git a/packages/SoundPicker/res/values-cs/strings.xml b/packages/SoundPicker/res/values-cs/strings.xml
index e8fc97e44174..dc67c960cca9 100644
--- a/packages/SoundPicker/res/values-cs/strings.xml
+++ b/packages/SoundPicker/res/values-cs/strings.xml
@@ -16,14 +16,14 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="ringtone_default" msgid="798836092118824500">"Výchozí vyzváněcí tón"</string>
+ <string name="ringtone_default" msgid="798836092118824500">"Výchozí vyzvánění"</string>
<string name="notification_sound_default" msgid="8133121186242636840">"Výchozí zvuk oznámení"</string>
<string name="alarm_sound_default" msgid="4787646764557462649">"Výchozí zvuk budíku"</string>
- <string name="add_ringtone_text" msgid="6642389991738337529">"Přidat vyzváněcí tón"</string>
+ <string name="add_ringtone_text" msgid="6642389991738337529">"Přidat vyzvánění"</string>
<string name="add_alarm_text" msgid="3545497316166999225">"Přidat budík"</string>
<string name="add_notification_text" msgid="4431129543300614788">"Přidat oznámení"</string>
<string name="delete_ringtone_text" msgid="201443984070732499">"Smazat"</string>
- <string name="unable_to_add_ringtone" msgid="4583511263449467326">"Vlastní vyzváněcí tón se nepodařilo přidat"</string>
- <string name="unable_to_delete_ringtone" msgid="6792301380142859496">"Vlastní vyzváněcí tón se nepodařilo smazat"</string>
+ <string name="unable_to_add_ringtone" msgid="4583511263449467326">"Vlastní vyzvánění se nepodařilo přidat"</string>
+ <string name="unable_to_delete_ringtone" msgid="6792301380142859496">"Vlastní vyzvánění se nepodařilo smazat"</string>
<string name="app_label" msgid="3091611356093417332">"Zvuky"</string>
</resources>
diff --git a/packages/SystemUI/Android.bp b/packages/SystemUI/Android.bp
index 2fbd9ba05817..a9a5671d5b03 100644
--- a/packages/SystemUI/Android.bp
+++ b/packages/SystemUI/Android.bp
@@ -22,6 +22,10 @@ java_library {
proto: {
type: "nano",
},
+
+ libs: [
+ "WindowManager-Shell-proto",
+ ],
}
java_library {
@@ -174,6 +178,9 @@ android_app {
kotlincflags: ["-Xjvm-default=enable"],
dxflags: ["--multi-dex"],
- required: ["privapp_whitelist_com.android.systemui"],
+ required: [
+ "privapp_whitelist_com.android.systemui",
+ "checked-wm_shell_protolog.json",
+ ],
}
diff --git a/packages/SystemUI/AndroidManifest.xml b/packages/SystemUI/AndroidManifest.xml
index af008b996172..e3f75e3e0b34 100644
--- a/packages/SystemUI/AndroidManifest.xml
+++ b/packages/SystemUI/AndroidManifest.xml
@@ -390,7 +390,7 @@
</activity-alias>
<activity
- android:name=".stackdivider.ForcedResizableInfoActivity"
+ android:name="com.android.wm.shell.splitscreen.ForcedResizableInfoActivity"
android:theme="@style/ForcedResizableTheme"
android:excludeFromRecents="true"
android:stateNotNeeded="true"
@@ -516,7 +516,7 @@
android:excludeFromRecents="true"
android:visibleToInstantApps="true"/>
- <!-- started from PipUI -->
+ <!-- started from PipController -->
<activity
android:name=".pip.tv.PipMenuActivity"
android:permission="com.android.systemui.permission.SELF"
@@ -530,20 +530,6 @@
androidprv:alwaysFocusable="true"
android:excludeFromRecents="true" />
- <activity
- android:name=".pip.phone.PipMenuActivity"
- android:permission="com.android.systemui.permission.SELF"
- android:theme="@style/PipPhoneOverlayControlTheme"
- android:configChanges="orientation|screenSize|smallestScreenSize|screenLayout"
- android:excludeFromRecents="true"
- android:exported="false"
- android:resizeableActivity="true"
- android:supportsPictureInPicture="true"
- android:stateNotNeeded="true"
- android:taskAffinity=""
- android:launchMode="singleTop"
- androidprv:alwaysFocusable="true" />
-
<!-- started from SliceProvider -->
<activity android:name=".SlicePermissionActivity"
android:theme="@style/Theme.SystemUI.Dialog.Alert"
diff --git a/packages/SystemUI/README.md b/packages/SystemUI/README.md
index 148fabbbaf2c..ee8d02301d5d 100644
--- a/packages/SystemUI/README.md
+++ b/packages/SystemUI/README.md
@@ -111,14 +111,6 @@ Plays ringtones.
Shows UI for keyboard shortcuts (triggered by keyboard shortcut).
-### [com.android.systemui.onehanded.OneHandedUI](/packages/SystemUI/src/com/android/systemui/onehanded/OneHandedUI.java)
-
-Shows the overlay controls when One handed is triggered.
-
-### [com.android.systemui.pip.PipUI](/packages/SystemUI/src/com/android/systemui/pip/PipUI.java)
-
-Shows the overlay controls when Pip is showing.
-
### [com.android.systemui.shortcut.ShortcutKeyDispatcher](/packages/SystemUI/src/com/android/systemui/shortcut/ShortcutKeyDispatcher.java)
Dispatches shortcut to System UI components.
diff --git a/packages/SystemUI/plugin/src/com/android/systemui/plugins/FalsingManager.java b/packages/SystemUI/plugin/src/com/android/systemui/plugins/FalsingManager.java
index 9d52098f37d5..63f8b1f5dbb8 100644
--- a/packages/SystemUI/plugin/src/com/android/systemui/plugins/FalsingManager.java
+++ b/packages/SystemUI/plugin/src/com/android/systemui/plugins/FalsingManager.java
@@ -30,7 +30,7 @@ import java.io.PrintWriter;
*/
@ProvidesInterface(version = FalsingManager.VERSION)
public interface FalsingManager {
- int VERSION = 4;
+ int VERSION = 5;
void onSuccessfulUnlock();
@@ -42,7 +42,8 @@ public interface FalsingManager {
boolean isUnlockingDisabled();
- boolean isFalseTouch();
+ /** Returns true if the gesture should be rejected. */
+ boolean isFalseTouch(int interactionType);
void onNotificatonStopDraggingDown();
diff --git a/packages/SystemUI/plugin/src/com/android/systemui/plugins/statusbar/NotificationSwipeActionHelper.java b/packages/SystemUI/plugin/src/com/android/systemui/plugins/statusbar/NotificationSwipeActionHelper.java
index 02c4c5eff26e..4b6efa91a7c8 100644
--- a/packages/SystemUI/plugin/src/com/android/systemui/plugins/statusbar/NotificationSwipeActionHelper.java
+++ b/packages/SystemUI/plugin/src/com/android/systemui/plugins/statusbar/NotificationSwipeActionHelper.java
@@ -14,16 +14,16 @@
package com.android.systemui.plugins.statusbar;
-import com.android.systemui.plugins.annotations.DependsOn;
-import com.android.systemui.plugins.annotations.ProvidesInterface;
-import com.android.systemui.plugins.statusbar.NotificationSwipeActionHelper.SnoozeOption;
-
import android.service.notification.SnoozeCriterion;
import android.service.notification.StatusBarNotification;
import android.view.MotionEvent;
import android.view.View;
import android.view.accessibility.AccessibilityNodeInfo.AccessibilityAction;
+import com.android.systemui.plugins.annotations.DependsOn;
+import com.android.systemui.plugins.annotations.ProvidesInterface;
+import com.android.systemui.plugins.statusbar.NotificationSwipeActionHelper.SnoozeOption;
+
@ProvidesInterface(version = NotificationSwipeActionHelper.VERSION)
@DependsOn(target = SnoozeOption.class)
public interface NotificationSwipeActionHelper {
@@ -52,7 +52,8 @@ public interface NotificationSwipeActionHelper {
public boolean isDismissGesture(MotionEvent ev);
- public boolean isFalseGesture(MotionEvent ev);
+ /** Returns true if the gesture should be rejected. */
+ boolean isFalseGesture();
public boolean swipedFarEnough(float translation, float viewSize);
diff --git a/packages/SystemUI/proguard.flags b/packages/SystemUI/proguard.flags
index df66bf5a1051..6c06b0a19844 100644
--- a/packages/SystemUI/proguard.flags
+++ b/packages/SystemUI/proguard.flags
@@ -41,7 +41,12 @@
public <init>(android.content.Context);
}
+# Keep the wm shell lib
-keep class com.android.wm.shell.*
+# Keep the protolog group methods that are called by the generated code
+-keepclassmembers class com.android.wm.shell.protolog.ShellProtoLogGroup {
+ *;
+}
-keep class com.android.systemui.dagger.GlobalRootComponent { *; }
-keep class com.android.systemui.dagger.GlobalRootComponent$SysUIComponentImpl { *; }
diff --git a/packages/SystemUI/res/drawable-mcc310-mnc004/ic_5g_plus_mobiledata.xml b/packages/SystemUI/res/drawable-mcc310-mnc004/ic_5g_plus_mobiledata.xml
new file mode 100644
index 000000000000..998db3b44b19
--- /dev/null
+++ b/packages/SystemUI/res/drawable-mcc310-mnc004/ic_5g_plus_mobiledata.xml
@@ -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.
+-->
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+ android:viewportWidth="22"
+ android:viewportHeight="17"
+ android:width="22dp"
+ android:height="17dp">
+ <group>
+ <group>
+ <path android:fillColor="#FF000000"
+ android:pathData="M19.98,3.54v2.81c0,0.47 -0.15,0.84 -0.44,1.11s-0.69,0.41 -1.2,0.41c-0.5,0 -0.89,-0.13 -1.19,-0.4s-0.44,-0.63 -0.45,-1.09V3.54h0.88v2.82c0,0.28 0.07,0.48 0.2,0.61c0.13,0.13 0.32,0.19 0.56,0.19c0.49,0 0.75,-0.26 0.75,-0.78V3.54H19.98z"/>
+ <path android:fillColor="#FF000000"
+ android:pathData="M19.42,12.25l0.57,-3.04h0.88l-0.95,4.27h-0.88l-0.69,-2.85l-0.69,2.85h-0.88l-0.95,-4.27h0.88l0.58,3.03l0.7,-3.03h0.74L19.42,12.25z"/>
+ </group>
+ <group>
+ <path android:fillColor="#FF000000"
+ android:pathData="M0.94,8.49l0.43,-4.96H5.7v1.17H2.39L2.15,7.41c0.41,-0.29 0.85,-0.43 1.33,-0.43c0.77,0 1.38,0.3 1.83,0.9c0.44,0.6 0.66,1.41 0.66,2.43c0,1.03 -0.24,1.84 -0.72,2.43c-0.48,0.59 -1.14,0.88 -1.98,0.88c-0.75,0 -1.36,-0.24 -1.83,-0.73c-0.47,-0.49 -0.74,-1.16 -0.81,-2.02h1.13c0.07,0.57 0.23,1 0.49,1.29c0.26,0.29 0.59,0.43 1.01,0.43c0.47,0 0.84,-0.2 1.1,-0.61c0.26,-0.41 0.4,-0.96 0.4,-1.65c0,-0.65 -0.14,-1.18 -0.43,-1.59C4.05,8.32 3.67,8.11 3.19,8.11c-0.4,0 -0.72,0.1 -0.96,0.31L1.9,8.75L0.94,8.49z"/>
+ </group>
+ <path android:fillColor="#FF000000"
+ android:pathData="M13.86,12.24l-0.22,0.27c-0.63,0.73 -1.55,1.1 -2.76,1.1c-1.08,0 -1.92,-0.36 -2.53,-1.07c-0.61,-0.71 -0.93,-1.72 -0.94,-3.02V7.56c0,-1.39 0.28,-2.44 0.84,-3.13c0.56,-0.7 1.39,-1.04 2.51,-1.04c0.95,0 1.69,0.26 2.22,0.79c0.54,0.53 0.83,1.28 0.89,2.26h-1.25c-0.05,-0.62 -0.22,-1.1 -0.52,-1.45c-0.29,-0.35 -0.74,-0.52 -1.34,-0.52c-0.72,0 -1.24,0.23 -1.57,0.7C8.85,5.63 8.68,6.37 8.66,7.4v2.03c0,1 0.19,1.77 0.57,2.31c0.38,0.54 0.93,0.8 1.65,0.8c0.67,0 1.19,-0.16 1.54,-0.49l0.18,-0.17V9.59h-1.82V8.52h3.07V12.24z"/>
+ </group>
+</vector>
+
diff --git a/packages/SystemUI/res/drawable-mcc311-mnc480/ic_5g_plus_mobiledata.xml b/packages/SystemUI/res/drawable-mcc311-mnc480/ic_5g_plus_mobiledata.xml
new file mode 100644
index 000000000000..998db3b44b19
--- /dev/null
+++ b/packages/SystemUI/res/drawable-mcc311-mnc480/ic_5g_plus_mobiledata.xml
@@ -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.
+-->
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+ android:viewportWidth="22"
+ android:viewportHeight="17"
+ android:width="22dp"
+ android:height="17dp">
+ <group>
+ <group>
+ <path android:fillColor="#FF000000"
+ android:pathData="M19.98,3.54v2.81c0,0.47 -0.15,0.84 -0.44,1.11s-0.69,0.41 -1.2,0.41c-0.5,0 -0.89,-0.13 -1.19,-0.4s-0.44,-0.63 -0.45,-1.09V3.54h0.88v2.82c0,0.28 0.07,0.48 0.2,0.61c0.13,0.13 0.32,0.19 0.56,0.19c0.49,0 0.75,-0.26 0.75,-0.78V3.54H19.98z"/>
+ <path android:fillColor="#FF000000"
+ android:pathData="M19.42,12.25l0.57,-3.04h0.88l-0.95,4.27h-0.88l-0.69,-2.85l-0.69,2.85h-0.88l-0.95,-4.27h0.88l0.58,3.03l0.7,-3.03h0.74L19.42,12.25z"/>
+ </group>
+ <group>
+ <path android:fillColor="#FF000000"
+ android:pathData="M0.94,8.49l0.43,-4.96H5.7v1.17H2.39L2.15,7.41c0.41,-0.29 0.85,-0.43 1.33,-0.43c0.77,0 1.38,0.3 1.83,0.9c0.44,0.6 0.66,1.41 0.66,2.43c0,1.03 -0.24,1.84 -0.72,2.43c-0.48,0.59 -1.14,0.88 -1.98,0.88c-0.75,0 -1.36,-0.24 -1.83,-0.73c-0.47,-0.49 -0.74,-1.16 -0.81,-2.02h1.13c0.07,0.57 0.23,1 0.49,1.29c0.26,0.29 0.59,0.43 1.01,0.43c0.47,0 0.84,-0.2 1.1,-0.61c0.26,-0.41 0.4,-0.96 0.4,-1.65c0,-0.65 -0.14,-1.18 -0.43,-1.59C4.05,8.32 3.67,8.11 3.19,8.11c-0.4,0 -0.72,0.1 -0.96,0.31L1.9,8.75L0.94,8.49z"/>
+ </group>
+ <path android:fillColor="#FF000000"
+ android:pathData="M13.86,12.24l-0.22,0.27c-0.63,0.73 -1.55,1.1 -2.76,1.1c-1.08,0 -1.92,-0.36 -2.53,-1.07c-0.61,-0.71 -0.93,-1.72 -0.94,-3.02V7.56c0,-1.39 0.28,-2.44 0.84,-3.13c0.56,-0.7 1.39,-1.04 2.51,-1.04c0.95,0 1.69,0.26 2.22,0.79c0.54,0.53 0.83,1.28 0.89,2.26h-1.25c-0.05,-0.62 -0.22,-1.1 -0.52,-1.45c-0.29,-0.35 -0.74,-0.52 -1.34,-0.52c-0.72,0 -1.24,0.23 -1.57,0.7C8.85,5.63 8.68,6.37 8.66,7.4v2.03c0,1 0.19,1.77 0.57,2.31c0.38,0.54 0.93,0.8 1.65,0.8c0.67,0 1.19,-0.16 1.54,-0.49l0.18,-0.17V9.59h-1.82V8.52h3.07V12.24z"/>
+ </group>
+</vector>
+
diff --git a/packages/SystemUI/res/layout-land-television/volume_dialog.xml b/packages/SystemUI/res/layout-land-television/volume_dialog.xml
index 56d847c6aa2e..8179bf48e7ab 100644
--- a/packages/SystemUI/res/layout-land-television/volume_dialog.xml
+++ b/packages/SystemUI/res/layout-land-television/volume_dialog.xml
@@ -24,23 +24,17 @@
<FrameLayout
android:id="@+id/volume_dialog"
- android:minWidth="@dimen/volume_dialog_panel_width"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="right"
android:background="@android:color/transparent"
- android:paddingRight="@dimen/volume_dialog_panel_transparent_padding_right"
- android:paddingTop="@dimen/volume_dialog_panel_transparent_padding"
- android:paddingBottom="@dimen/volume_dialog_panel_transparent_padding"
- android:paddingLeft="@dimen/volume_dialog_panel_transparent_padding"
+ android:padding="@dimen/volume_dialog_panel_transparent_padding"
android:clipToPadding="false">
<LinearLayout
android:id="@+id/main"
android:layout_width="wrap_content"
- android:minWidth="@dimen/volume_dialog_panel_width"
android:layout_height="wrap_content"
- android:layout_marginTop="68dp"
android:layout_gravity="right"
android:orientation="vertical"
android:translationZ="@dimen/volume_dialog_elevation"
@@ -52,7 +46,6 @@
android:id="@+id/volume_dialog_rows"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
- android:minWidth="@dimen/volume_dialog_panel_width"
android:gravity="center"
android:orientation="horizontal">
<!-- volume rows added and removed here! :-) -->
diff --git a/packages/SystemUI/res/layout-land-television/volume_dialog_row.xml b/packages/SystemUI/res/layout-land-television/volume_dialog_row.xml
index c0f0aa8bbc8d..d28d5664d725 100644
--- a/packages/SystemUI/res/layout-land-television/volume_dialog_row.xml
+++ b/packages/SystemUI/res/layout-land-television/volume_dialog_row.xml
@@ -16,8 +16,8 @@
<FrameLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:tag="row"
- android:layout_width="@dimen/volume_dialog_row_width"
- android:layout_height="wrap_content"
+ android:layout_width="wrap_content"
+ android:layout_height="@dimen/volume_dialog_row_height"
android:background="@android:color/transparent"
android:clipChildren="false"
android:clipToPadding="false"
@@ -30,15 +30,17 @@
android:background="@android:color/transparent"
android:gravity="center"
android:layout_gravity="center"
- android:orientation="horizontal" >
- <com.android.keyguard.AlphaOptimizedImageButton
- android:id="@+id/volume_row_icon"
- style="@style/VolumeButtons"
+ android:orientation="vertical" >
+ <TextView
+ android:id="@+id/volume_number"
android:layout_width="@dimen/tv_volume_dialog_bubble_size"
android:layout_height="@dimen/tv_volume_dialog_bubble_size"
+ android:maxLength="2"
+ android:gravity="center"
+ android:fontFeatureSettings="tnum"
android:background="@drawable/tv_volume_dialog_circle"
- android:tint="@color/accent_tint_color_selector"
- android:soundEffectsEnabled="false" />
+ android:textSize="@dimen/tv_volume_number_text_size"
+ android:textColor="@color/accent_tint_color_selector"/>
<TextView
android:id="@+id/volume_row_header"
android:layout_width="wrap_content"
@@ -51,27 +53,24 @@
android:textAppearance="@style/TextAppearance.Volume.Header" />
<FrameLayout
android:id="@+id/volume_row_slider_frame"
- android:layout_height="match_parent"
- android:layoutDirection="ltr"
- android:layout_width="@dimen/volume_dialog_row_width">
+ android:layout_width="match_parent"
+ android:layout_height="@dimen/volume_dialog_row_height">
<SeekBar
android:id="@+id/volume_row_slider"
android:clickable="false"
- android:layout_width="@dimen/volume_dialog_row_width"
+ android:layout_width="@dimen/volume_dialog_row_height"
android:layout_height="match_parent"
- android:layoutDirection="ltr"
android:layout_gravity="center"
- android:rotation="0" />
+ android:rotation="270" />
</FrameLayout>
- <TextView
- android:id="@+id/volume_number"
+ <com.android.keyguard.AlphaOptimizedImageButton
+ android:id="@+id/volume_row_icon"
+ style="@style/VolumeButtons"
android:layout_width="@dimen/tv_volume_dialog_bubble_size"
android:layout_height="@dimen/tv_volume_dialog_bubble_size"
- android:maxLength="2"
- android:gravity="center"
android:background="@drawable/tv_volume_dialog_circle"
- android:textSize="@dimen/tv_volume_number_text_size"
- android:textColor="@color/accent_tint_color_selector"/>
+ android:tint="@color/accent_tint_color_selector"
+ android:soundEffectsEnabled="false" />
</LinearLayout>
<include layout="@layout/volume_dnd_icon"/>
diff --git a/packages/SystemUI/res/layout/controls_management.xml b/packages/SystemUI/res/layout/controls_management.xml
index ae7f44d19430..b9e711e54b3b 100644
--- a/packages/SystemUI/res/layout/controls_management.xml
+++ b/packages/SystemUI/res/layout/controls_management.xml
@@ -50,7 +50,7 @@
<FrameLayout
android:layout_width="match_parent"
- android:layout_height="72dp">
+ android:layout_height="@dimen/controls_management_footer_height">
<View
android:layout_width="match_parent"
@@ -61,7 +61,8 @@
<androidx.constraintlayout.widget.ConstraintLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
- android:padding="@dimen/controls_management_footer_side_margin">
+ android:paddingHorizontal="@dimen/controls_management_footer_side_margin"
+ android:paddingVertical="@dimen/controls_management_footer_top_margin" >
<Button
android:id="@+id/other_apps"
diff --git a/packages/SystemUI/res/layout/controls_management_favorites.xml b/packages/SystemUI/res/layout/controls_management_favorites.xml
index 4850e7534943..0ddd0e38acb9 100644
--- a/packages/SystemUI/res/layout/controls_management_favorites.xml
+++ b/packages/SystemUI/res/layout/controls_management_favorites.xml
@@ -36,7 +36,7 @@
android:layout_width="wrap_content"
android:layout_height="@dimen/controls_management_page_indicator_height"
android:layout_gravity="center"
- android:layout_marginTop="@dimen/controls_management_list_margin"
+ android:layout_marginTop="@dimen/controls_management_indicator_top_margin"
android:visibility="invisible" />
<androidx.viewpager2.widget.ViewPager2
diff --git a/packages/SystemUI/res/layout/controls_structure_page.xml b/packages/SystemUI/res/layout/controls_structure_page.xml
index f048d62d46d7..412ed566ff1b 100644
--- a/packages/SystemUI/res/layout/controls_structure_page.xml
+++ b/packages/SystemUI/res/layout/controls_structure_page.xml
@@ -21,4 +21,4 @@
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical"
- android:layout_marginTop="@dimen/controls_management_zone_top_margin"/> \ No newline at end of file
+ android:layout_marginTop="@dimen/controls_management_favorites_top_margin"/> \ No newline at end of file
diff --git a/packages/SystemUI/res/layout/media_view.xml b/packages/SystemUI/res/layout/media_view.xml
index ed870f8bb2ef..170f2c4e0bea 100644
--- a/packages/SystemUI/res/layout/media_view.xml
+++ b/packages/SystemUI/res/layout/media_view.xml
@@ -166,8 +166,7 @@
android:layout_height="wrap_content"
android:clickable="true"
android:maxHeight="@dimen/qs_media_enabled_seekbar_height"
- android:paddingTop="16dp"
- android:paddingBottom="16dp"
+ android:paddingVertical="@dimen/qs_media_enabled_seekbar_vertical_padding"
android:thumbTint="@color/media_primary_text"
android:progressTint="@color/media_seekbar_progress"
android:progressBackgroundTint="@color/media_disabled"
diff --git a/packages/SystemUI/res/values-af/strings.xml b/packages/SystemUI/res/values-af/strings.xml
index bac915d854d8..316fa8aac5e6 100644
--- a/packages/SystemUI/res/values-af/strings.xml
+++ b/packages/SystemUI/res/values-af/strings.xml
@@ -108,10 +108,8 @@
<string name="screenrecord_resume_label" msgid="4972223043729555575">"Hervat"</string>
<string name="screenrecord_cancel_label" msgid="7850926573274483294">"Kanselleer"</string>
<string name="screenrecord_share_label" msgid="5025590804030086930">"Deel"</string>
- <string name="screenrecord_delete_label" msgid="1376347010553987058">"Vee uit"</string>
<string name="screenrecord_cancel_success" msgid="1775448688137393901">"Skermopname is gekanselleer"</string>
<string name="screenrecord_save_message" msgid="490522052388998226">"Skermopname is gestoor, tik om te sien"</string>
- <string name="screenrecord_delete_description" msgid="1604522770162810570">"Skermopname is uitgevee"</string>
<string name="screenrecord_delete_error" msgid="2870506119743013588">"Kon nie skermopname uitvee nie"</string>
<string name="screenrecord_permission_error" msgid="7856841237023137686">"Kon nie toestemmings kry nie"</string>
<string name="screenrecord_start_error" msgid="2200660692479682368">"Kon nie skermopname begin nie"</string>
diff --git a/packages/SystemUI/res/values-am/strings.xml b/packages/SystemUI/res/values-am/strings.xml
index 43ab1d2d4fa1..e2a4dc6404d8 100644
--- a/packages/SystemUI/res/values-am/strings.xml
+++ b/packages/SystemUI/res/values-am/strings.xml
@@ -108,10 +108,8 @@
<string name="screenrecord_resume_label" msgid="4972223043729555575">"ከቆመበት ቀጥል"</string>
<string name="screenrecord_cancel_label" msgid="7850926573274483294">"ይቅር"</string>
<string name="screenrecord_share_label" msgid="5025590804030086930">"አጋራ"</string>
- <string name="screenrecord_delete_label" msgid="1376347010553987058">"ሰርዝ"</string>
<string name="screenrecord_cancel_success" msgid="1775448688137393901">"የማያ ገጽ ቀረጻ ተሰርዟል"</string>
<string name="screenrecord_save_message" msgid="490522052388998226">"የማያ ገጽ ቀረጻ ተቀምጧል፣ ለመመልከት መታ ያድርጉ"</string>
- <string name="screenrecord_delete_description" msgid="1604522770162810570">"የማያ ገጽ ቀረጻ ተሰርዟል"</string>
<string name="screenrecord_delete_error" msgid="2870506119743013588">"የማያ ገጽ ቀረጻን መሰረዝ ላይ ስህተት"</string>
<string name="screenrecord_permission_error" msgid="7856841237023137686">"ፈቃዶችን ማግኘት አልተቻለም"</string>
<string name="screenrecord_start_error" msgid="2200660692479682368">"የማያ ገጽ ቀረጻን መጀመር ላይ ስህተት"</string>
diff --git a/packages/SystemUI/res/values-ar/strings.xml b/packages/SystemUI/res/values-ar/strings.xml
index c68d0887e425..b33c6c57f905 100644
--- a/packages/SystemUI/res/values-ar/strings.xml
+++ b/packages/SystemUI/res/values-ar/strings.xml
@@ -108,10 +108,8 @@
<string name="screenrecord_resume_label" msgid="4972223043729555575">"استئناف"</string>
<string name="screenrecord_cancel_label" msgid="7850926573274483294">"إلغاء"</string>
<string name="screenrecord_share_label" msgid="5025590804030086930">"مشاركة"</string>
- <string name="screenrecord_delete_label" msgid="1376347010553987058">"حذف"</string>
<string name="screenrecord_cancel_success" msgid="1775448688137393901">"تمّ إلغاء تسجيل الشاشة."</string>
<string name="screenrecord_save_message" msgid="490522052388998226">"تمّ حفظ تسجيل الشاشة، انقر لعرضه."</string>
- <string name="screenrecord_delete_description" msgid="1604522770162810570">"تمّ حذف تسجيل الشاشة."</string>
<string name="screenrecord_delete_error" msgid="2870506119743013588">"حدث خطأ أثناء حذف تسجيل الشاشة."</string>
<string name="screenrecord_permission_error" msgid="7856841237023137686">"تعذّر الحصول على أذونات."</string>
<string name="screenrecord_start_error" msgid="2200660692479682368">"حدث خطأ في بدء تسجيل الشاشة"</string>
diff --git a/packages/SystemUI/res/values-as/strings.xml b/packages/SystemUI/res/values-as/strings.xml
index d604fd47c4fd..5a3c659727d3 100644
--- a/packages/SystemUI/res/values-as/strings.xml
+++ b/packages/SystemUI/res/values-as/strings.xml
@@ -108,10 +108,8 @@
<string name="screenrecord_resume_label" msgid="4972223043729555575">"ৰখোৱাৰ পৰা পুনৰ আৰম্ভ কৰক"</string>
<string name="screenrecord_cancel_label" msgid="7850926573274483294">"বাতিল কৰক"</string>
<string name="screenrecord_share_label" msgid="5025590804030086930">"শ্বেয়াৰ কৰক"</string>
- <string name="screenrecord_delete_label" msgid="1376347010553987058">"মচক"</string>
<string name="screenrecord_cancel_success" msgid="1775448688137393901">"স্ক্রীণ ৰেকৰ্ড কৰাটো বাতিল কৰা হ’ল"</string>
<string name="screenrecord_save_message" msgid="490522052388998226">"স্ক্রীণ ৰেকৰ্ডিং ছেভ কৰা হ’ল, চাবলৈ টিপক"</string>
- <string name="screenrecord_delete_description" msgid="1604522770162810570">"স্ক্রীণ ৰেকৰ্ডিং মচা হ’ল"</string>
<string name="screenrecord_delete_error" msgid="2870506119743013588">"স্ক্রীণ ৰেকৰ্ডিং মচি থাকোঁতে কিবা আসোঁৱাহ হ’ল"</string>
<string name="screenrecord_permission_error" msgid="7856841237023137686">"অনুমতি পাব পৰা নগ\'ল"</string>
<string name="screenrecord_start_error" msgid="2200660692479682368">"স্ক্রীন ৰেকৰ্ড কৰা আৰম্ভ কৰোঁতে আসোঁৱাহ হৈছে"</string>
diff --git a/packages/SystemUI/res/values-az/strings.xml b/packages/SystemUI/res/values-az/strings.xml
index b1df2522a513..40df8cd68bac 100644
--- a/packages/SystemUI/res/values-az/strings.xml
+++ b/packages/SystemUI/res/values-az/strings.xml
@@ -108,10 +108,8 @@
<string name="screenrecord_resume_label" msgid="4972223043729555575">"Davam edin"</string>
<string name="screenrecord_cancel_label" msgid="7850926573274483294">"Ləğv edin"</string>
<string name="screenrecord_share_label" msgid="5025590804030086930">"Paylaşın"</string>
- <string name="screenrecord_delete_label" msgid="1376347010553987058">"Silin"</string>
<string name="screenrecord_cancel_success" msgid="1775448688137393901">"Ekranın video çəkimi ləğv edildi"</string>
<string name="screenrecord_save_message" msgid="490522052388998226">"Ekranın video çəkimi yadda saxlanıldı. Baxmaq üçün klikləyin"</string>
- <string name="screenrecord_delete_description" msgid="1604522770162810570">"Ekranın video çəkimi silindi"</string>
<string name="screenrecord_delete_error" msgid="2870506119743013588">"Ekranın video çəkiminin silinməsi zamanı xəta baş verdi"</string>
<string name="screenrecord_permission_error" msgid="7856841237023137686">"İcazələr əldə edilmədi"</string>
<string name="screenrecord_start_error" msgid="2200660692479682368">"Ekranın yazılması ilə bağlı xəta"</string>
@@ -405,7 +403,7 @@
<item quantity="one">%d cihaz</item>
</plurals>
<string name="quick_settings_notifications_label" msgid="3379631363952582758">"Bildirişlər"</string>
- <string name="quick_settings_flashlight_label" msgid="4904634272006284185">"İşartı"</string>
+ <string name="quick_settings_flashlight_label" msgid="4904634272006284185">"Fənər"</string>
<string name="quick_settings_flashlight_camera_in_use" msgid="4820591564526512571">"Kamera istifadə olunur"</string>
<string name="quick_settings_cellular_detail_title" msgid="792977203299358893">"Mobil data"</string>
<string name="quick_settings_cellular_detail_data_usage" msgid="6105969068871138427">"Data istifadəsi"</string>
diff --git a/packages/SystemUI/res/values-b+sr+Latn/strings.xml b/packages/SystemUI/res/values-b+sr+Latn/strings.xml
index f3c4c6b8487d..a9725f331856 100644
--- a/packages/SystemUI/res/values-b+sr+Latn/strings.xml
+++ b/packages/SystemUI/res/values-b+sr+Latn/strings.xml
@@ -108,10 +108,8 @@
<string name="screenrecord_resume_label" msgid="4972223043729555575">"Nastavi"</string>
<string name="screenrecord_cancel_label" msgid="7850926573274483294">"Otkaži"</string>
<string name="screenrecord_share_label" msgid="5025590804030086930">"Deli"</string>
- <string name="screenrecord_delete_label" msgid="1376347010553987058">"Izbriši"</string>
<string name="screenrecord_cancel_success" msgid="1775448688137393901">"Snimanje ekrana je otkazano"</string>
<string name="screenrecord_save_message" msgid="490522052388998226">"Snimak ekrana je sačuvan, dodirnite da biste pregledali"</string>
- <string name="screenrecord_delete_description" msgid="1604522770162810570">"Snimak ekrana je izbrisan"</string>
<string name="screenrecord_delete_error" msgid="2870506119743013588">"Došlo je do problema pri brisanju snimka ekrana"</string>
<string name="screenrecord_permission_error" msgid="7856841237023137686">"Preuzimanje dozvola nije uspelo"</string>
<string name="screenrecord_start_error" msgid="2200660692479682368">"Greška pri pokretanju snimanja ekrana"</string>
diff --git a/packages/SystemUI/res/values-be/strings.xml b/packages/SystemUI/res/values-be/strings.xml
index 9c0eeb206e9e..b4c5eba9f77b 100644
--- a/packages/SystemUI/res/values-be/strings.xml
+++ b/packages/SystemUI/res/values-be/strings.xml
@@ -108,10 +108,8 @@
<string name="screenrecord_resume_label" msgid="4972223043729555575">"Узнавіць"</string>
<string name="screenrecord_cancel_label" msgid="7850926573274483294">"Скасаваць"</string>
<string name="screenrecord_share_label" msgid="5025590804030086930">"Абагуліць"</string>
- <string name="screenrecord_delete_label" msgid="1376347010553987058">"Выдаліць"</string>
<string name="screenrecord_cancel_success" msgid="1775448688137393901">"Запіс экрана скасаваны"</string>
<string name="screenrecord_save_message" msgid="490522052388998226">"Запіс экрана захаваны. Націсніце, каб прагледзець"</string>
- <string name="screenrecord_delete_description" msgid="1604522770162810570">"Запіс экрана выдалены"</string>
<string name="screenrecord_delete_error" msgid="2870506119743013588">"Памылка выдалення запісу экрана"</string>
<string name="screenrecord_permission_error" msgid="7856841237023137686">"Не ўдалося атрымаць дазволы"</string>
<string name="screenrecord_start_error" msgid="2200660692479682368">"Памылка пачатку запісу экрана"</string>
diff --git a/packages/SystemUI/res/values-bg/strings.xml b/packages/SystemUI/res/values-bg/strings.xml
index 3bf12ad06f1a..52e82869d575 100644
--- a/packages/SystemUI/res/values-bg/strings.xml
+++ b/packages/SystemUI/res/values-bg/strings.xml
@@ -108,10 +108,8 @@
<string name="screenrecord_resume_label" msgid="4972223043729555575">"Възобновяване"</string>
<string name="screenrecord_cancel_label" msgid="7850926573274483294">"Отказ"</string>
<string name="screenrecord_share_label" msgid="5025590804030086930">"Споделяне"</string>
- <string name="screenrecord_delete_label" msgid="1376347010553987058">"Изтриване"</string>
<string name="screenrecord_cancel_success" msgid="1775448688137393901">"Записването на екрана е анулирано"</string>
<string name="screenrecord_save_message" msgid="490522052388998226">"Записът на екрана е запазен. Докоснете, за да го видите"</string>
- <string name="screenrecord_delete_description" msgid="1604522770162810570">"Записът на екрана е изтрит"</string>
<string name="screenrecord_delete_error" msgid="2870506119743013588">"При изтриването на записа на екрана възникна грешка"</string>
<string name="screenrecord_permission_error" msgid="7856841237023137686">"Извличането на разрешенията не бе успешно."</string>
<string name="screenrecord_start_error" msgid="2200660692479682368">"При стартирането на записа на екрана възникна грешка"</string>
diff --git a/packages/SystemUI/res/values-bn/strings.xml b/packages/SystemUI/res/values-bn/strings.xml
index 5b7c953d5692..d0de9cf03b38 100644
--- a/packages/SystemUI/res/values-bn/strings.xml
+++ b/packages/SystemUI/res/values-bn/strings.xml
@@ -108,10 +108,8 @@
<string name="screenrecord_resume_label" msgid="4972223043729555575">"আবার চালু করুন"</string>
<string name="screenrecord_cancel_label" msgid="7850926573274483294">"বাতিল করুন"</string>
<string name="screenrecord_share_label" msgid="5025590804030086930">"শেয়ার করুন"</string>
- <string name="screenrecord_delete_label" msgid="1376347010553987058">"মুছুন"</string>
<string name="screenrecord_cancel_success" msgid="1775448688137393901">"স্ক্রিন রেকর্ডিং বাতিল করা হয়েছে"</string>
<string name="screenrecord_save_message" msgid="490522052388998226">"স্ক্রিন রেকর্ডিং সেভ করা হয়েছে, দেখতে ট্যাপ করুন"</string>
- <string name="screenrecord_delete_description" msgid="1604522770162810570">"স্ক্রিন রেকর্ডিং মুছে ফেলা হয়েছে"</string>
<string name="screenrecord_delete_error" msgid="2870506119743013588">"স্ক্রিন রেকডিং মুছে ফেলার সময় সমস্যা হয়েছে"</string>
<string name="screenrecord_permission_error" msgid="7856841237023137686">"অনুমতি পাওয়া যায়নি"</string>
<string name="screenrecord_start_error" msgid="2200660692479682368">"স্ক্রিন রেকর্ডিং শুরু করার সময় সমস্যা হয়েছে"</string>
diff --git a/packages/SystemUI/res/values-bs/strings.xml b/packages/SystemUI/res/values-bs/strings.xml
index 31f88c8fbd24..57b7945c7a8c 100644
--- a/packages/SystemUI/res/values-bs/strings.xml
+++ b/packages/SystemUI/res/values-bs/strings.xml
@@ -108,10 +108,8 @@
<string name="screenrecord_resume_label" msgid="4972223043729555575">"Nastavi"</string>
<string name="screenrecord_cancel_label" msgid="7850926573274483294">"Otkaži"</string>
<string name="screenrecord_share_label" msgid="5025590804030086930">"Dijeli"</string>
- <string name="screenrecord_delete_label" msgid="1376347010553987058">"Izbriši"</string>
<string name="screenrecord_cancel_success" msgid="1775448688137393901">"Snimanje ekrana je otkazano"</string>
<string name="screenrecord_save_message" msgid="490522052388998226">"Snimak ekrana je sačuvan. Dodirnite za prikaz."</string>
- <string name="screenrecord_delete_description" msgid="1604522770162810570">"Snimak ekrana je izbrisan"</string>
<string name="screenrecord_delete_error" msgid="2870506119743013588">"Greška prilikom brisanja snimka ekrana"</string>
<string name="screenrecord_permission_error" msgid="7856841237023137686">"Dobijanje odobrenja nije uspjelo"</string>
<string name="screenrecord_start_error" msgid="2200660692479682368">"Greška pri pokretanju snimanja ekrana"</string>
diff --git a/packages/SystemUI/res/values-ca/strings.xml b/packages/SystemUI/res/values-ca/strings.xml
index 753e25f13420..0489d18ff36b 100644
--- a/packages/SystemUI/res/values-ca/strings.xml
+++ b/packages/SystemUI/res/values-ca/strings.xml
@@ -108,10 +108,8 @@
<string name="screenrecord_resume_label" msgid="4972223043729555575">"Reprèn"</string>
<string name="screenrecord_cancel_label" msgid="7850926573274483294">"Cancel·la"</string>
<string name="screenrecord_share_label" msgid="5025590804030086930">"Comparteix"</string>
- <string name="screenrecord_delete_label" msgid="1376347010553987058">"Suprimeix"</string>
<string name="screenrecord_cancel_success" msgid="1775448688137393901">"S\'ha cancel·lat la gravació de la pantalla"</string>
<string name="screenrecord_save_message" msgid="490522052388998226">"S\'ha desat la gravació de la pantalla; toca per mostrar"</string>
- <string name="screenrecord_delete_description" msgid="1604522770162810570">"S\'ha suprimit la gravació de la pantalla"</string>
<string name="screenrecord_delete_error" msgid="2870506119743013588">"S\'ha produït un error en suprimir la gravació de la pantalla"</string>
<string name="screenrecord_permission_error" msgid="7856841237023137686">"No s\'han pogut obtenir els permisos"</string>
<string name="screenrecord_start_error" msgid="2200660692479682368">"S\'ha produït un error en iniciar la gravació de pantalla"</string>
diff --git a/packages/SystemUI/res/values-cs/strings.xml b/packages/SystemUI/res/values-cs/strings.xml
index 039500d2a4f4..acb6637b68dc 100644
--- a/packages/SystemUI/res/values-cs/strings.xml
+++ b/packages/SystemUI/res/values-cs/strings.xml
@@ -95,7 +95,7 @@
<string name="screenrecord_description" msgid="1123231719680353736">"Při nahrávání může systém Android zaznamenávat citlivé údaje, které jsou viditelné na obrazovce nebo které jsou přehrávány na zařízení. Týká se to hesel, údajů o platbě, fotek, zpráv a zvuků."</string>
<string name="screenrecord_audio_label" msgid="6183558856175159629">"Nahrát zvuk"</string>
<string name="screenrecord_device_audio_label" msgid="9016927171280567791">"Zvuk zařízení"</string>
- <string name="screenrecord_device_audio_description" msgid="4922694220572186193">"Zvuk ze zařízení, například hudba, hovory a vyzváněcí tóny"</string>
+ <string name="screenrecord_device_audio_description" msgid="4922694220572186193">"Zvuk ze zařízení, například hudba, hovory a vyzvánění"</string>
<string name="screenrecord_mic_label" msgid="2111264835791332350">"Mikrofon"</string>
<string name="screenrecord_device_audio_and_mic_label" msgid="1831323771978646841">"Zvuk a mikrofon zařízení"</string>
<string name="screenrecord_start" msgid="330991441575775004">"Spustit"</string>
@@ -108,10 +108,8 @@
<string name="screenrecord_resume_label" msgid="4972223043729555575">"Obnovit"</string>
<string name="screenrecord_cancel_label" msgid="7850926573274483294">"Zrušit"</string>
<string name="screenrecord_share_label" msgid="5025590804030086930">"Sdílet"</string>
- <string name="screenrecord_delete_label" msgid="1376347010553987058">"Smazat"</string>
<string name="screenrecord_cancel_success" msgid="1775448688137393901">"Nahrávání obrazovky bylo zrušeno"</string>
<string name="screenrecord_save_message" msgid="490522052388998226">"Záznam obrazovky byl uložen, zobrazíte jej klepnutím"</string>
- <string name="screenrecord_delete_description" msgid="1604522770162810570">"Záznam obrazovky byl smazán"</string>
<string name="screenrecord_delete_error" msgid="2870506119743013588">"Při mazání záznamu obrazovky došlo k chybě"</string>
<string name="screenrecord_permission_error" msgid="7856841237023137686">"Nepodařilo se načíst oprávnění"</string>
<string name="screenrecord_start_error" msgid="2200660692479682368">"Při spouštění nahrávání obrazovky došlo k chybě"</string>
diff --git a/packages/SystemUI/res/values-da/strings.xml b/packages/SystemUI/res/values-da/strings.xml
index 0c8a5b75c9e6..886369598f1c 100644
--- a/packages/SystemUI/res/values-da/strings.xml
+++ b/packages/SystemUI/res/values-da/strings.xml
@@ -108,10 +108,8 @@
<string name="screenrecord_resume_label" msgid="4972223043729555575">"Genoptag"</string>
<string name="screenrecord_cancel_label" msgid="7850926573274483294">"Annuller"</string>
<string name="screenrecord_share_label" msgid="5025590804030086930">"Del"</string>
- <string name="screenrecord_delete_label" msgid="1376347010553987058">"Slet"</string>
<string name="screenrecord_cancel_success" msgid="1775448688137393901">"Skærmoptagelsen er annulleret"</string>
<string name="screenrecord_save_message" msgid="490522052388998226">"Skærmoptagelsen er gemt. Tryk for at se den."</string>
- <string name="screenrecord_delete_description" msgid="1604522770162810570">"Skærmoptagelsen er slettet"</string>
<string name="screenrecord_delete_error" msgid="2870506119743013588">"Der opstod en fejl ved sletning af skærmoptagelsen"</string>
<string name="screenrecord_permission_error" msgid="7856841237023137686">"Det lykkedes ikke et hente tilladelserne"</string>
<string name="screenrecord_start_error" msgid="2200660692479682368">"Skærmoptagelsen kunne ikke startes"</string>
diff --git a/packages/SystemUI/res/values-de/strings.xml b/packages/SystemUI/res/values-de/strings.xml
index 1c4c7ab229f9..8d990c66ecdf 100644
--- a/packages/SystemUI/res/values-de/strings.xml
+++ b/packages/SystemUI/res/values-de/strings.xml
@@ -108,10 +108,8 @@
<string name="screenrecord_resume_label" msgid="4972223043729555575">"Fortsetzen"</string>
<string name="screenrecord_cancel_label" msgid="7850926573274483294">"Abbrechen"</string>
<string name="screenrecord_share_label" msgid="5025590804030086930">"Teilen"</string>
- <string name="screenrecord_delete_label" msgid="1376347010553987058">"Löschen"</string>
<string name="screenrecord_cancel_success" msgid="1775448688137393901">"Bildschirmaufzeichnung abgebrochen"</string>
<string name="screenrecord_save_message" msgid="490522052388998226">"Bildschirmaufzeichnung gespeichert, zum Ansehen tippen"</string>
- <string name="screenrecord_delete_description" msgid="1604522770162810570">"Bildschirmaufzeichnung gelöscht"</string>
<string name="screenrecord_delete_error" msgid="2870506119743013588">"Fehler beim Löschen der Bildschirmaufzeichnung"</string>
<string name="screenrecord_permission_error" msgid="7856841237023137686">"Berechtigungen nicht erhalten"</string>
<string name="screenrecord_start_error" msgid="2200660692479682368">"Fehler beim Start der Bildschirmaufzeichnung"</string>
diff --git a/packages/SystemUI/res/values-el/strings.xml b/packages/SystemUI/res/values-el/strings.xml
index 07ff80706b33..5ca236b2514a 100644
--- a/packages/SystemUI/res/values-el/strings.xml
+++ b/packages/SystemUI/res/values-el/strings.xml
@@ -108,10 +108,8 @@
<string name="screenrecord_resume_label" msgid="4972223043729555575">"Συνέχιση"</string>
<string name="screenrecord_cancel_label" msgid="7850926573274483294">"Ακύρωση"</string>
<string name="screenrecord_share_label" msgid="5025590804030086930">"Κοινοποίηση"</string>
- <string name="screenrecord_delete_label" msgid="1376347010553987058">"Διαγραφή"</string>
<string name="screenrecord_cancel_success" msgid="1775448688137393901">"Η εγγραφή οθόνης ακυρώθηκε"</string>
<string name="screenrecord_save_message" msgid="490522052388998226">"Η εγγραφή οθόνης αποθηκεύτηκε. Πατήστε για προβολή."</string>
- <string name="screenrecord_delete_description" msgid="1604522770162810570">"Η εγγραφή οθόνης διαγράφηκε"</string>
<string name="screenrecord_delete_error" msgid="2870506119743013588">"Παρουσιάστηκε σφάλμα κατά τη διαγραφή της εγγραφής οθόνης"</string>
<string name="screenrecord_permission_error" msgid="7856841237023137686">"Η λήψη αδειών απέτυχε"</string>
<string name="screenrecord_start_error" msgid="2200660692479682368">"Σφάλμα κατά την έναρξη της εγγραφής οθόνης"</string>
@@ -693,7 +691,7 @@
<string name="notification_channel_minimized" msgid="6892672757877552959">"Αυτές οι ειδοποιήσεις θα ελαχιστοποιηθούν"</string>
<string name="notification_channel_silenced" msgid="1995937493874511359">"Αυτές οι ειδοποιήσεις θα εμφανίζονται σιωπηλά"</string>
<string name="notification_channel_unsilenced" msgid="94878840742161152">"Αυτές οι ειδοποιήσεις θα σας ενημερώνουν"</string>
- <string name="inline_blocking_helper" msgid="2891486013649543452">"Συνήθως απορρίπτετε αυτές τις ειδοποιήσεις. \nΝα εξακολουθήσουν να εμφανίζονται;"</string>
+ <string name="inline_blocking_helper" msgid="2891486013649543452">"Συνήθως παραβλέπετε αυτές τις ειδοποιήσεις. \nΝα εξακολουθήσουν να εμφανίζονται;"</string>
<string name="inline_done_button" msgid="6043094985588909584">"Τέλος"</string>
<string name="inline_ok_button" msgid="603075490581280343">"Εφαρμογή"</string>
<string name="inline_keep_showing" msgid="8736001253507073497">"Να συνεχίσουν να εμφανίζονται αυτές οι ειδοποιήσεις;"</string>
diff --git a/packages/SystemUI/res/values-en-rAU/strings.xml b/packages/SystemUI/res/values-en-rAU/strings.xml
index 0e22b583352c..8a7963a1f845 100644
--- a/packages/SystemUI/res/values-en-rAU/strings.xml
+++ b/packages/SystemUI/res/values-en-rAU/strings.xml
@@ -108,10 +108,8 @@
<string name="screenrecord_resume_label" msgid="4972223043729555575">"Resume"</string>
<string name="screenrecord_cancel_label" msgid="7850926573274483294">"Cancel"</string>
<string name="screenrecord_share_label" msgid="5025590804030086930">"Share"</string>
- <string name="screenrecord_delete_label" msgid="1376347010553987058">"Delete"</string>
<string name="screenrecord_cancel_success" msgid="1775448688137393901">"Screen recording cancelled"</string>
<string name="screenrecord_save_message" msgid="490522052388998226">"Screen recording saved, tap to view"</string>
- <string name="screenrecord_delete_description" msgid="1604522770162810570">"Screen recording deleted"</string>
<string name="screenrecord_delete_error" msgid="2870506119743013588">"Error deleting screen recording"</string>
<string name="screenrecord_permission_error" msgid="7856841237023137686">"Failed to get permissions"</string>
<string name="screenrecord_start_error" msgid="2200660692479682368">"Error starting screen recording"</string>
diff --git a/packages/SystemUI/res/values-en-rCA/strings.xml b/packages/SystemUI/res/values-en-rCA/strings.xml
index acf087d51181..7b2b25a0e678 100644
--- a/packages/SystemUI/res/values-en-rCA/strings.xml
+++ b/packages/SystemUI/res/values-en-rCA/strings.xml
@@ -108,10 +108,8 @@
<string name="screenrecord_resume_label" msgid="4972223043729555575">"Resume"</string>
<string name="screenrecord_cancel_label" msgid="7850926573274483294">"Cancel"</string>
<string name="screenrecord_share_label" msgid="5025590804030086930">"Share"</string>
- <string name="screenrecord_delete_label" msgid="1376347010553987058">"Delete"</string>
<string name="screenrecord_cancel_success" msgid="1775448688137393901">"Screen recording cancelled"</string>
<string name="screenrecord_save_message" msgid="490522052388998226">"Screen recording saved, tap to view"</string>
- <string name="screenrecord_delete_description" msgid="1604522770162810570">"Screen recording deleted"</string>
<string name="screenrecord_delete_error" msgid="2870506119743013588">"Error deleting screen recording"</string>
<string name="screenrecord_permission_error" msgid="7856841237023137686">"Failed to get permissions"</string>
<string name="screenrecord_start_error" msgid="2200660692479682368">"Error starting screen recording"</string>
diff --git a/packages/SystemUI/res/values-en-rGB/strings.xml b/packages/SystemUI/res/values-en-rGB/strings.xml
index 0e22b583352c..8a7963a1f845 100644
--- a/packages/SystemUI/res/values-en-rGB/strings.xml
+++ b/packages/SystemUI/res/values-en-rGB/strings.xml
@@ -108,10 +108,8 @@
<string name="screenrecord_resume_label" msgid="4972223043729555575">"Resume"</string>
<string name="screenrecord_cancel_label" msgid="7850926573274483294">"Cancel"</string>
<string name="screenrecord_share_label" msgid="5025590804030086930">"Share"</string>
- <string name="screenrecord_delete_label" msgid="1376347010553987058">"Delete"</string>
<string name="screenrecord_cancel_success" msgid="1775448688137393901">"Screen recording cancelled"</string>
<string name="screenrecord_save_message" msgid="490522052388998226">"Screen recording saved, tap to view"</string>
- <string name="screenrecord_delete_description" msgid="1604522770162810570">"Screen recording deleted"</string>
<string name="screenrecord_delete_error" msgid="2870506119743013588">"Error deleting screen recording"</string>
<string name="screenrecord_permission_error" msgid="7856841237023137686">"Failed to get permissions"</string>
<string name="screenrecord_start_error" msgid="2200660692479682368">"Error starting screen recording"</string>
diff --git a/packages/SystemUI/res/values-en-rIN/strings.xml b/packages/SystemUI/res/values-en-rIN/strings.xml
index 0e22b583352c..8a7963a1f845 100644
--- a/packages/SystemUI/res/values-en-rIN/strings.xml
+++ b/packages/SystemUI/res/values-en-rIN/strings.xml
@@ -108,10 +108,8 @@
<string name="screenrecord_resume_label" msgid="4972223043729555575">"Resume"</string>
<string name="screenrecord_cancel_label" msgid="7850926573274483294">"Cancel"</string>
<string name="screenrecord_share_label" msgid="5025590804030086930">"Share"</string>
- <string name="screenrecord_delete_label" msgid="1376347010553987058">"Delete"</string>
<string name="screenrecord_cancel_success" msgid="1775448688137393901">"Screen recording cancelled"</string>
<string name="screenrecord_save_message" msgid="490522052388998226">"Screen recording saved, tap to view"</string>
- <string name="screenrecord_delete_description" msgid="1604522770162810570">"Screen recording deleted"</string>
<string name="screenrecord_delete_error" msgid="2870506119743013588">"Error deleting screen recording"</string>
<string name="screenrecord_permission_error" msgid="7856841237023137686">"Failed to get permissions"</string>
<string name="screenrecord_start_error" msgid="2200660692479682368">"Error starting screen recording"</string>
diff --git a/packages/SystemUI/res/values-en-rXC/strings.xml b/packages/SystemUI/res/values-en-rXC/strings.xml
index 4f4238a5eb45..15738f2512f4 100644
--- a/packages/SystemUI/res/values-en-rXC/strings.xml
+++ b/packages/SystemUI/res/values-en-rXC/strings.xml
@@ -108,10 +108,8 @@
<string name="screenrecord_resume_label" msgid="4972223043729555575">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‎‎‎‏‎‏‎‎‎‎‎‎‎‎‏‏‏‎‎‎‏‎‏‎‎‎‎‎‏‏‏‎‏‎‏‎‎‏‏‎‎‎‎‎‏‏‎‎‎‎‎‎‎‎‎‏‏‏‎‏‏‏‎Resume‎‏‎‎‏‎"</string>
<string name="screenrecord_cancel_label" msgid="7850926573274483294">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‏‎‏‏‎‎‏‏‏‏‎‏‎‎‎‎‎‏‏‎‎‎‎‎‎‏‏‏‏‏‎‏‎‏‎‏‎‏‏‎‏‏‎‎‏‏‎‏‎‎‏‎‏‎‎‏‎‏‏‏‏‎‎Cancel‎‏‎‎‏‎"</string>
<string name="screenrecord_share_label" msgid="5025590804030086930">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‎‎‎‏‎‏‏‎‏‏‏‏‏‎‎‏‏‏‏‏‎‎‎‎‏‏‎‏‎‏‏‎‏‎‎‏‎‎‏‎‏‎‏‏‏‎‏‏‎‏‏‏‏‏‎‎‎‏‎‎‏‎‎Share‎‏‎‎‏‎"</string>
- <string name="screenrecord_delete_label" msgid="1376347010553987058">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‎‏‏‎‎‏‏‎‎‎‏‏‎‎‏‏‏‎‎‎‏‎‎‎‏‎‏‎‎‎‎‎‏‎‏‏‎‏‏‏‎‏‏‏‏‎‏‏‎‏‏‏‏‏‏‏‏‏‏‎‎‏‎‎Delete‎‏‎‎‏‎"</string>
<string name="screenrecord_cancel_success" msgid="1775448688137393901">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‎‏‏‏‎‎‎‏‎‏‎‎‎‏‏‏‎‏‎‏‎‎‏‎‎‏‎‏‏‎‎‏‏‎‏‎‏‎‏‎‏‎‏‏‏‎‎‏‏‎‏‎‏‏‎‏‏‏‎‏‏‎‏‎Screen recording canceled‎‏‎‎‏‎"</string>
<string name="screenrecord_save_message" msgid="490522052388998226">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‎‏‏‏‏‎‏‏‎‎‏‏‏‎‏‎‏‎‏‏‏‏‎‎‏‏‎‏‎‏‎‎‏‎‏‏‏‏‎‎‏‎‎‏‎‎‎‏‎‎‏‏‎‎‎‏‎‏‎‎‏‎‎Screen recording saved, tap to view‎‏‎‎‏‎"</string>
- <string name="screenrecord_delete_description" msgid="1604522770162810570">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‎‏‏‎‏‏‎‎‏‎‎‎‏‎‎‎‏‏‎‏‎‎‎‏‏‏‏‎‏‎‏‎‏‎‏‎‏‎‏‏‎‎‏‎‏‎‎‎‏‏‏‏‏‏‎‏‏‎‎‏‎‏‎‎Screen recording deleted‎‏‎‎‏‎"</string>
<string name="screenrecord_delete_error" msgid="2870506119743013588">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‎‏‎‎‏‏‏‏‏‎‏‎‏‏‎‎‎‎‏‎‏‏‎‎‎‎‏‏‎‏‏‎‏‏‏‏‎‎‎‏‏‎‏‏‏‏‎‎‎‎‎‎‎‏‎‏‏‎‏‎‏‎‎‎Error deleting screen recording‎‏‎‎‏‎"</string>
<string name="screenrecord_permission_error" msgid="7856841237023137686">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‏‎‏‏‎‏‎‎‎‎‏‎‎‏‎‎‎‏‏‎‏‏‎‏‏‏‏‎‏‎‎‏‎‎‏‏‎‏‎‏‏‎‎‏‏‏‏‎‎‏‏‏‏‏‏‎‎‏‎‏‏‎‎Failed to get permissions‎‏‎‎‏‎"</string>
<string name="screenrecord_start_error" msgid="2200660692479682368">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‎‏‏‏‏‏‎‏‎‎‎‏‎‏‎‎‏‎‏‎‎‎‏‎‎‏‏‏‏‎‏‎‏‏‏‏‏‏‎‎‏‏‎‏‎‏‎‏‎‏‎‎‏‏‏‎‏‎‎‎‎‎‎‎Error starting screen recording‎‏‎‎‏‎"</string>
diff --git a/packages/SystemUI/res/values-es-rUS/strings.xml b/packages/SystemUI/res/values-es-rUS/strings.xml
index 38fa52874512..aa81ab8efadd 100644
--- a/packages/SystemUI/res/values-es-rUS/strings.xml
+++ b/packages/SystemUI/res/values-es-rUS/strings.xml
@@ -108,10 +108,8 @@
<string name="screenrecord_resume_label" msgid="4972223043729555575">"Reanudar"</string>
<string name="screenrecord_cancel_label" msgid="7850926573274483294">"Cancelar"</string>
<string name="screenrecord_share_label" msgid="5025590804030086930">"Compartir"</string>
- <string name="screenrecord_delete_label" msgid="1376347010553987058">"Borrar"</string>
<string name="screenrecord_cancel_success" msgid="1775448688137393901">"Se canceló la grabación de pantalla"</string>
<string name="screenrecord_save_message" msgid="490522052388998226">"Se guardó la grabación de pantalla; presiona para verla"</string>
- <string name="screenrecord_delete_description" msgid="1604522770162810570">"Se borró la grabación de pantalla"</string>
<string name="screenrecord_delete_error" msgid="2870506119743013588">"Error al borrar la grabación de pantalla"</string>
<string name="screenrecord_permission_error" msgid="7856841237023137686">"Error al obtener permisos"</string>
<string name="screenrecord_start_error" msgid="2200660692479682368">"Error al iniciar la grabación de pantalla"</string>
diff --git a/packages/SystemUI/res/values-es/strings.xml b/packages/SystemUI/res/values-es/strings.xml
index 10aa6cac7c2a..863857016388 100644
--- a/packages/SystemUI/res/values-es/strings.xml
+++ b/packages/SystemUI/res/values-es/strings.xml
@@ -108,10 +108,8 @@
<string name="screenrecord_resume_label" msgid="4972223043729555575">"Seguir"</string>
<string name="screenrecord_cancel_label" msgid="7850926573274483294">"Cancelar"</string>
<string name="screenrecord_share_label" msgid="5025590804030086930">"Compartir"</string>
- <string name="screenrecord_delete_label" msgid="1376347010553987058">"Eliminar"</string>
<string name="screenrecord_cancel_success" msgid="1775448688137393901">"Se ha cancelado la grabación de la pantalla"</string>
<string name="screenrecord_save_message" msgid="490522052388998226">"Se ha guardado la grabación de la pantalla; toca para verla"</string>
- <string name="screenrecord_delete_description" msgid="1604522770162810570">"Se ha eliminado la grabación de la pantalla"</string>
<string name="screenrecord_delete_error" msgid="2870506119743013588">"No se ha podido eliminar la grabación de la pantalla"</string>
<string name="screenrecord_permission_error" msgid="7856841237023137686">"No se han podido obtener los permisos"</string>
<string name="screenrecord_start_error" msgid="2200660692479682368">"No se ha podido empezar a grabar la pantalla"</string>
diff --git a/packages/SystemUI/res/values-et/strings.xml b/packages/SystemUI/res/values-et/strings.xml
index 9122ce5c4c0d..f5ffad255cf6 100644
--- a/packages/SystemUI/res/values-et/strings.xml
+++ b/packages/SystemUI/res/values-et/strings.xml
@@ -108,10 +108,8 @@
<string name="screenrecord_resume_label" msgid="4972223043729555575">"Jätka"</string>
<string name="screenrecord_cancel_label" msgid="7850926573274483294">"Tühista"</string>
<string name="screenrecord_share_label" msgid="5025590804030086930">"Jaga"</string>
- <string name="screenrecord_delete_label" msgid="1376347010553987058">"Kustuta"</string>
<string name="screenrecord_cancel_success" msgid="1775448688137393901">"Ekraanikuva salvestamine on tühistatud"</string>
<string name="screenrecord_save_message" msgid="490522052388998226">"Ekraanikuva salvestis on salvestatud, puudutage vaatamiseks"</string>
- <string name="screenrecord_delete_description" msgid="1604522770162810570">"Ekraanikuva salvestis on kustutatud"</string>
<string name="screenrecord_delete_error" msgid="2870506119743013588">"Viga ekraanikuva salvestise kustutamisel"</string>
<string name="screenrecord_permission_error" msgid="7856841237023137686">"Lubade hankimine ebaõnnestus"</string>
<string name="screenrecord_start_error" msgid="2200660692479682368">"Viga ekraanikuva salvestamise alustamisel"</string>
diff --git a/packages/SystemUI/res/values-eu/strings.xml b/packages/SystemUI/res/values-eu/strings.xml
index 38b2103d7973..23bcd2c32c76 100644
--- a/packages/SystemUI/res/values-eu/strings.xml
+++ b/packages/SystemUI/res/values-eu/strings.xml
@@ -108,10 +108,8 @@
<string name="screenrecord_resume_label" msgid="4972223043729555575">"Berrekin"</string>
<string name="screenrecord_cancel_label" msgid="7850926573274483294">"Utzi"</string>
<string name="screenrecord_share_label" msgid="5025590804030086930">"Partekatu"</string>
- <string name="screenrecord_delete_label" msgid="1376347010553987058">"Ezabatu"</string>
<string name="screenrecord_cancel_success" msgid="1775448688137393901">"Utzi zaio pantaila grabatzeari"</string>
<string name="screenrecord_save_message" msgid="490522052388998226">"Gorde da pantailaren grabaketa; sakatu ikusteko"</string>
- <string name="screenrecord_delete_description" msgid="1604522770162810570">"Ezabatu da pantailaren grabaketa"</string>
<string name="screenrecord_delete_error" msgid="2870506119743013588">"Errore bat gertatu da pantailaren grabaketa ezabatzean"</string>
<string name="screenrecord_permission_error" msgid="7856841237023137686">"Ezin izan dira lortu baimenak"</string>
<string name="screenrecord_start_error" msgid="2200660692479682368">"Errore bat gertatu da pantaila grabatzen hastean"</string>
@@ -554,7 +552,7 @@
<string name="monitoring_description_named_vpn" msgid="5749932930634037027">"<xliff:g id="VPN_APP">%1$s</xliff:g> aplikaziora konektatuta zaude eta hark sareko jarduerak gainbegira ditzake, mezu elektronikoak, aplikazioak eta webguneak barne."</string>
<string name="monitoring_description_two_named_vpns" msgid="3516830755681229463">"<xliff:g id="VPN_APP_0">%1$s</xliff:g> eta <xliff:g id="VPN_APP_1">%2$s</xliff:g> aplikazioetara konektatuta zaude, eta haiek sareko jarduerak gainbegira ditzakete, mezu elektronikoak, aplikazioak eta webguneak barne."</string>
<string name="monitoring_description_managed_profile_named_vpn" msgid="368812367182387320">"<xliff:g id="VPN_APP">%1$s</xliff:g> aplikaziora dago konektatuta laneko profila, eta aplikazio horrek sareko jarduerak gainbegira ditzake, mezu elektronikoak, aplikazioak eta webguneak barne."</string>
- <string name="monitoring_description_personal_profile_named_vpn" msgid="8179722332380953673">"<xliff:g id="VPN_APP">%1$s</xliff:g> aplikaziora konektatuta duzu profil pertsonala, eta aplikazio horrek sareko jarduerak gainbegira ditzake, mezu elektronikoak, aplikazioak eta webguneak barne."</string>
+ <string name="monitoring_description_personal_profile_named_vpn" msgid="8179722332380953673">"<xliff:g id="VPN_APP">%1$s</xliff:g> aplikaziora konektatuta daukazu profil pertsonala, eta aplikazio horrek sareko jarduerak gainbegira ditzake, mezu elektronikoak, aplikazioak eta webguneak barne."</string>
<string name="monitoring_description_do_header_generic" msgid="6130190408164834986">"<xliff:g id="DEVICE_OWNER_APP">%1$s</xliff:g> aplikazioak kudeatzen du gailu hau."</string>
<string name="monitoring_description_do_header_with_name" msgid="2696255132542779511">"<xliff:g id="ORGANIZATION_NAME">%1$s</xliff:g> erakundeak <xliff:g id="DEVICE_OWNER_APP">%2$s</xliff:g> erabiltzen du gailua kudeatzeko."</string>
<string name="monitoring_description_do_body" msgid="7700878065625769970">"Gailuko ezarpenak, enpresa-sarbidea, aplikazioak eta datuak gainbegira eta kudea ditzake administratzaileak, baita gailuaren kokapen-informazioa ere."</string>
diff --git a/packages/SystemUI/res/values-fa/strings.xml b/packages/SystemUI/res/values-fa/strings.xml
index d39d0c3d5027..55d8ab2566c6 100644
--- a/packages/SystemUI/res/values-fa/strings.xml
+++ b/packages/SystemUI/res/values-fa/strings.xml
@@ -108,10 +108,8 @@
<string name="screenrecord_resume_label" msgid="4972223043729555575">"ازسرگیری"</string>
<string name="screenrecord_cancel_label" msgid="7850926573274483294">"لغو"</string>
<string name="screenrecord_share_label" msgid="5025590804030086930">"هم‌رسانی"</string>
- <string name="screenrecord_delete_label" msgid="1376347010553987058">"حذف"</string>
<string name="screenrecord_cancel_success" msgid="1775448688137393901">"ضبط صفحه‌نمایش لغو شد"</string>
<string name="screenrecord_save_message" msgid="490522052388998226">"ضبط صفحه‌نمایش ذخیره شد، برای مشاهده ضربه بزنید"</string>
- <string name="screenrecord_delete_description" msgid="1604522770162810570">"فایل ضبط صفحه‌نمایش حذف شد"</string>
<string name="screenrecord_delete_error" msgid="2870506119743013588">"خطا در حذف فایل ضبط صفحه‌نمایش"</string>
<string name="screenrecord_permission_error" msgid="7856841237023137686">"مجوزها دریافت نشدند"</string>
<string name="screenrecord_start_error" msgid="2200660692479682368">"خطا هنگام شروع ضبط صفحه‌نمایش"</string>
diff --git a/packages/SystemUI/res/values-fi/strings.xml b/packages/SystemUI/res/values-fi/strings.xml
index 52e5e8cf29d6..f30c44b3ffba 100644
--- a/packages/SystemUI/res/values-fi/strings.xml
+++ b/packages/SystemUI/res/values-fi/strings.xml
@@ -108,10 +108,8 @@
<string name="screenrecord_resume_label" msgid="4972223043729555575">"Jatka"</string>
<string name="screenrecord_cancel_label" msgid="7850926573274483294">"Peruuta"</string>
<string name="screenrecord_share_label" msgid="5025590804030086930">"Jaa"</string>
- <string name="screenrecord_delete_label" msgid="1376347010553987058">"Poista"</string>
<string name="screenrecord_cancel_success" msgid="1775448688137393901">"Näytön tallennus peruutettu"</string>
<string name="screenrecord_save_message" msgid="490522052388998226">"Näyttötallenne tallennettu, katso napauttamalla"</string>
- <string name="screenrecord_delete_description" msgid="1604522770162810570">"Näyttötallenne poistettu"</string>
<string name="screenrecord_delete_error" msgid="2870506119743013588">"Virhe poistettaessa näyttötallennetta"</string>
<string name="screenrecord_permission_error" msgid="7856841237023137686">"Käyttöoikeuksien hakeminen epäonnistui."</string>
<string name="screenrecord_start_error" msgid="2200660692479682368">"Virhe näytön tallennuksen aloituksessa"</string>
diff --git a/packages/SystemUI/res/values-fr-rCA/strings.xml b/packages/SystemUI/res/values-fr-rCA/strings.xml
index 4797f323b5d5..f6196dd63695 100644
--- a/packages/SystemUI/res/values-fr-rCA/strings.xml
+++ b/packages/SystemUI/res/values-fr-rCA/strings.xml
@@ -108,10 +108,8 @@
<string name="screenrecord_resume_label" msgid="4972223043729555575">"Reprendre"</string>
<string name="screenrecord_cancel_label" msgid="7850926573274483294">"Annuler"</string>
<string name="screenrecord_share_label" msgid="5025590804030086930">"Partager"</string>
- <string name="screenrecord_delete_label" msgid="1376347010553987058">"Supprimer"</string>
<string name="screenrecord_cancel_success" msgid="1775448688137393901">"L\'enregistrement d\'écran a été annulé"</string>
<string name="screenrecord_save_message" msgid="490522052388998226">"L\'enregistrement d\'écran est terminé. Touchez ici pour l\'afficher."</string>
- <string name="screenrecord_delete_description" msgid="1604522770162810570">"L\'enregistrement d\'écran a été supprimé"</string>
<string name="screenrecord_delete_error" msgid="2870506119743013588">"Une erreur s\'est produite lors de la suppression de l\'enregistrement d\'écran"</string>
<string name="screenrecord_permission_error" msgid="7856841237023137686">"Impossible d\'obtenir les autorisations"</string>
<string name="screenrecord_start_error" msgid="2200660692479682368">"Une erreur s\'est produite lors du démarrage de l\'enregistrement d\'écran"</string>
diff --git a/packages/SystemUI/res/values-fr/strings.xml b/packages/SystemUI/res/values-fr/strings.xml
index e5df728c34c6..0146ce4d9a59 100644
--- a/packages/SystemUI/res/values-fr/strings.xml
+++ b/packages/SystemUI/res/values-fr/strings.xml
@@ -108,10 +108,8 @@
<string name="screenrecord_resume_label" msgid="4972223043729555575">"Reprendre"</string>
<string name="screenrecord_cancel_label" msgid="7850926573274483294">"Annuler"</string>
<string name="screenrecord_share_label" msgid="5025590804030086930">"Partager"</string>
- <string name="screenrecord_delete_label" msgid="1376347010553987058">"Supprimer"</string>
<string name="screenrecord_cancel_success" msgid="1775448688137393901">"Enregistrement de l\'écran annulé"</string>
<string name="screenrecord_save_message" msgid="490522052388998226">"Enregistrement de l\'écran enregistré. Appuyez pour afficher"</string>
- <string name="screenrecord_delete_description" msgid="1604522770162810570">"Enregistrement de l\'écran supprimé"</string>
<string name="screenrecord_delete_error" msgid="2870506119743013588">"Erreur lors de la suppression de l\'enregistrement de l\'écran"</string>
<string name="screenrecord_permission_error" msgid="7856841237023137686">"Échec d\'obtention des autorisations"</string>
<string name="screenrecord_start_error" msgid="2200660692479682368">"Erreur lors du démarrage de l\'enregistrement de l\'écran"</string>
diff --git a/packages/SystemUI/res/values-gl/strings.xml b/packages/SystemUI/res/values-gl/strings.xml
index 246fefd316db..fd4d3c6a4ad5 100644
--- a/packages/SystemUI/res/values-gl/strings.xml
+++ b/packages/SystemUI/res/values-gl/strings.xml
@@ -108,10 +108,8 @@
<string name="screenrecord_resume_label" msgid="4972223043729555575">"Retomar"</string>
<string name="screenrecord_cancel_label" msgid="7850926573274483294">"Cancelar"</string>
<string name="screenrecord_share_label" msgid="5025590804030086930">"Compartir"</string>
- <string name="screenrecord_delete_label" msgid="1376347010553987058">"Eliminar"</string>
<string name="screenrecord_cancel_success" msgid="1775448688137393901">"Cancelouse a gravación de pantalla"</string>
<string name="screenrecord_save_message" msgid="490522052388998226">"Gardouse a gravación de pantalla; toca esta notificación para visualizala"</string>
- <string name="screenrecord_delete_description" msgid="1604522770162810570">"Eliminouse a gravación de pantalla"</string>
<string name="screenrecord_delete_error" msgid="2870506119743013588">"Produciuse un erro ao eliminar a gravación de pantalla"</string>
<string name="screenrecord_permission_error" msgid="7856841237023137686">"Produciuse un erro ao obter os permisos"</string>
<string name="screenrecord_start_error" msgid="2200660692479682368">"Produciuse un erro ao iniciar a gravación da pantalla"</string>
diff --git a/packages/SystemUI/res/values-gu/strings.xml b/packages/SystemUI/res/values-gu/strings.xml
index beaacaa1c073..46f7a2bde43c 100644
--- a/packages/SystemUI/res/values-gu/strings.xml
+++ b/packages/SystemUI/res/values-gu/strings.xml
@@ -108,10 +108,8 @@
<string name="screenrecord_resume_label" msgid="4972223043729555575">"ફરી શરૂ કરો"</string>
<string name="screenrecord_cancel_label" msgid="7850926573274483294">"રદ કરો"</string>
<string name="screenrecord_share_label" msgid="5025590804030086930">"શેર કરો"</string>
- <string name="screenrecord_delete_label" msgid="1376347010553987058">"ડિલીટ કરો"</string>
<string name="screenrecord_cancel_success" msgid="1775448688137393901">"સ્ક્રીન રેકોર્ડિંગ રદ કર્યું"</string>
<string name="screenrecord_save_message" msgid="490522052388998226">"સ્ક્રીન રેકોર્ડિંગ સાચવ્યું, જોવા માટે ટૅપ કરો"</string>
- <string name="screenrecord_delete_description" msgid="1604522770162810570">"સ્ક્રીન રેકોર્ડિંગ ડિલીટ કર્યું"</string>
<string name="screenrecord_delete_error" msgid="2870506119743013588">"સ્ક્રીન રેકોર્ડિંગ ડિલીટ કરવામાં ભૂલ આવી"</string>
<string name="screenrecord_permission_error" msgid="7856841237023137686">"પરવાનગીઓ મેળવવામાં નિષ્ફળ રહ્યાં"</string>
<string name="screenrecord_start_error" msgid="2200660692479682368">"સ્ક્રીનને રેકૉર્ડ કરવાનું શરૂ કરવામાં ભૂલ"</string>
diff --git a/packages/SystemUI/res/values-hi/strings.xml b/packages/SystemUI/res/values-hi/strings.xml
index de4fc482a101..e4a6ed79848d 100644
--- a/packages/SystemUI/res/values-hi/strings.xml
+++ b/packages/SystemUI/res/values-hi/strings.xml
@@ -108,10 +108,8 @@
<string name="screenrecord_resume_label" msgid="4972223043729555575">"फिर से शुरू करें"</string>
<string name="screenrecord_cancel_label" msgid="7850926573274483294">"रद्द करें"</string>
<string name="screenrecord_share_label" msgid="5025590804030086930">"शेयर करें"</string>
- <string name="screenrecord_delete_label" msgid="1376347010553987058">"मिटाएं"</string>
<string name="screenrecord_cancel_success" msgid="1775448688137393901">"स्क्रीन रिकॉर्डिंग रद्द कर दी गई"</string>
<string name="screenrecord_save_message" msgid="490522052388998226">"स्क्रीन रिकॉर्डिंग सेव की गई, देखने के लिए टैप करें"</string>
- <string name="screenrecord_delete_description" msgid="1604522770162810570">"स्क्रीन रिकॉर्डिंग मिटा दी गई"</string>
<string name="screenrecord_delete_error" msgid="2870506119743013588">"स्क्रीन रिकॉर्डिंग मिटाने में गड़बड़ी हुई"</string>
<string name="screenrecord_permission_error" msgid="7856841237023137686">"मंज़ूरी नहीं मिल सकी"</string>
<string name="screenrecord_start_error" msgid="2200660692479682368">"स्क्रीन को रिकॉर्ड करने में गड़बड़ी आ रही है"</string>
diff --git a/packages/SystemUI/res/values-hr/strings.xml b/packages/SystemUI/res/values-hr/strings.xml
index 7bf0b93b9bcb..a27b06694588 100644
--- a/packages/SystemUI/res/values-hr/strings.xml
+++ b/packages/SystemUI/res/values-hr/strings.xml
@@ -108,10 +108,8 @@
<string name="screenrecord_resume_label" msgid="4972223043729555575">"Nastavi"</string>
<string name="screenrecord_cancel_label" msgid="7850926573274483294">"Odustani"</string>
<string name="screenrecord_share_label" msgid="5025590804030086930">"Dijeli"</string>
- <string name="screenrecord_delete_label" msgid="1376347010553987058">"Izbriši"</string>
<string name="screenrecord_cancel_success" msgid="1775448688137393901">"Snimanje zaslona otkazano"</string>
<string name="screenrecord_save_message" msgid="490522052388998226">"Snimanje zaslona spremljeno je, dodirnite da biste ga pregledali"</string>
- <string name="screenrecord_delete_description" msgid="1604522770162810570">"Snimanje zaslona izbrisano"</string>
<string name="screenrecord_delete_error" msgid="2870506119743013588">"Pogreška prilikom brisanja snimanja zaslona"</string>
<string name="screenrecord_permission_error" msgid="7856841237023137686">"Dohvaćanje dopuštenja nije uspjelo"</string>
<string name="screenrecord_start_error" msgid="2200660692479682368">"Pogreška prilikom pokretanja snimanja zaslona"</string>
diff --git a/packages/SystemUI/res/values-hu/strings.xml b/packages/SystemUI/res/values-hu/strings.xml
index 875a05f71453..0d1f50acc1c7 100644
--- a/packages/SystemUI/res/values-hu/strings.xml
+++ b/packages/SystemUI/res/values-hu/strings.xml
@@ -108,10 +108,8 @@
<string name="screenrecord_resume_label" msgid="4972223043729555575">"Folytatás"</string>
<string name="screenrecord_cancel_label" msgid="7850926573274483294">"Mégse"</string>
<string name="screenrecord_share_label" msgid="5025590804030086930">"Megosztás"</string>
- <string name="screenrecord_delete_label" msgid="1376347010553987058">"Törlés"</string>
<string name="screenrecord_cancel_success" msgid="1775448688137393901">"A képernyő rögzítése megszakítva"</string>
<string name="screenrecord_save_message" msgid="490522052388998226">"Képernyőfelvétel mentve, koppintson a megtekintéshez"</string>
- <string name="screenrecord_delete_description" msgid="1604522770162810570">"A képernyőről készült felvétel törölve"</string>
<string name="screenrecord_delete_error" msgid="2870506119743013588">"Hiba történt a képernyőről készült felvétel törlésekor"</string>
<string name="screenrecord_permission_error" msgid="7856841237023137686">"Nincs engedély"</string>
<string name="screenrecord_start_error" msgid="2200660692479682368">"Hiba a képernyőrögzítés indításakor"</string>
diff --git a/packages/SystemUI/res/values-hy/strings.xml b/packages/SystemUI/res/values-hy/strings.xml
index 4cc406bf9af7..f9a10fa1578e 100644
--- a/packages/SystemUI/res/values-hy/strings.xml
+++ b/packages/SystemUI/res/values-hy/strings.xml
@@ -108,10 +108,8 @@
<string name="screenrecord_resume_label" msgid="4972223043729555575">"Վերսկսել"</string>
<string name="screenrecord_cancel_label" msgid="7850926573274483294">"Չեղարկել"</string>
<string name="screenrecord_share_label" msgid="5025590804030086930">"Կիսվել"</string>
- <string name="screenrecord_delete_label" msgid="1376347010553987058">"Ջնջել"</string>
<string name="screenrecord_cancel_success" msgid="1775448688137393901">"Էկրանի տեսագրումը չեղարկվեց"</string>
<string name="screenrecord_save_message" msgid="490522052388998226">"Էկրանի տեսագրությունը պահվեց։ Հպեք՝ դիտելու համար:"</string>
- <string name="screenrecord_delete_description" msgid="1604522770162810570">"Էկրանի տեսագրությունը ջնջվեց"</string>
<string name="screenrecord_delete_error" msgid="2870506119743013588">"Չհաջողվեց ջնջել տեսագրությունը"</string>
<string name="screenrecord_permission_error" msgid="7856841237023137686">"Չհաջողվեց ստանալ անհրաժեշտ թույլտվությունները"</string>
<string name="screenrecord_start_error" msgid="2200660692479682368">"Չհաջողվեց սկսել տեսագրումը"</string>
@@ -337,7 +335,7 @@
<string name="accessibility_rotation_lock_on_portrait" msgid="2356633398683813837">"Էկրանը կողպված է ուղղաձիգ դիրքավորմամբ:"</string>
<string name="accessibility_rotation_lock_off_changed" msgid="5772498370935088261">"Էկրանն այժմ ավտոմատ կպտտվի:"</string>
<string name="accessibility_rotation_lock_on_landscape_changed" msgid="5785739044300729592">"Էկրանն այժմ կողպված է հորիզոնական դիրքում:"</string>
- <string name="accessibility_rotation_lock_on_portrait_changed" msgid="5580170829728987989">"Էկրանն այժմ կողպված է ուղղահայաց դիրքում:"</string>
+ <string name="accessibility_rotation_lock_on_portrait_changed" msgid="5580170829728987989">"Էկրանն այժմ կողպված է ուղղաձիգ դիրքում:"</string>
<string name="dessert_case" msgid="9104973640704357717">"Dessert Case"</string>
<string name="start_dreams" msgid="9131802557946276718">"Էկրանապահ"</string>
<string name="ethernet_label" msgid="2203544727007463351">"Ethernet"</string>
diff --git a/packages/SystemUI/res/values-in/strings.xml b/packages/SystemUI/res/values-in/strings.xml
index 5f7dce43925a..f65be90bb00e 100644
--- a/packages/SystemUI/res/values-in/strings.xml
+++ b/packages/SystemUI/res/values-in/strings.xml
@@ -108,10 +108,8 @@
<string name="screenrecord_resume_label" msgid="4972223043729555575">"Lanjutkan"</string>
<string name="screenrecord_cancel_label" msgid="7850926573274483294">"Batal"</string>
<string name="screenrecord_share_label" msgid="5025590804030086930">"Bagikan"</string>
- <string name="screenrecord_delete_label" msgid="1376347010553987058">"Hapus"</string>
<string name="screenrecord_cancel_success" msgid="1775448688137393901">"Rekaman layar dibatalkan"</string>
<string name="screenrecord_save_message" msgid="490522052388998226">"Rekaman layar disimpan, ketuk untuk melihat"</string>
- <string name="screenrecord_delete_description" msgid="1604522770162810570">"Rekaman layar dihapus"</string>
<string name="screenrecord_delete_error" msgid="2870506119743013588">"Error saat menghapus rekaman layar"</string>
<string name="screenrecord_permission_error" msgid="7856841237023137686">"Gagal mendapatkan izin"</string>
<string name="screenrecord_start_error" msgid="2200660692479682368">"Terjadi error saat memulai perekaman layar"</string>
diff --git a/packages/SystemUI/res/values-is/strings.xml b/packages/SystemUI/res/values-is/strings.xml
index b5f6e57002df..66c91477c1e8 100644
--- a/packages/SystemUI/res/values-is/strings.xml
+++ b/packages/SystemUI/res/values-is/strings.xml
@@ -108,10 +108,8 @@
<string name="screenrecord_resume_label" msgid="4972223043729555575">"Halda áfram"</string>
<string name="screenrecord_cancel_label" msgid="7850926573274483294">"Hætta við"</string>
<string name="screenrecord_share_label" msgid="5025590804030086930">"Deila"</string>
- <string name="screenrecord_delete_label" msgid="1376347010553987058">"Eyða"</string>
<string name="screenrecord_cancel_success" msgid="1775448688137393901">"Hætt við skjáupptöku"</string>
<string name="screenrecord_save_message" msgid="490522052388998226">"Skjáupptaka vistuð, ýttu til að skoða"</string>
- <string name="screenrecord_delete_description" msgid="1604522770162810570">"Skjáupptöku eytt"</string>
<string name="screenrecord_delete_error" msgid="2870506119743013588">"Villa við að eyða skjáupptöku"</string>
<string name="screenrecord_permission_error" msgid="7856841237023137686">"Ekki tókst að fá heimildir"</string>
<string name="screenrecord_start_error" msgid="2200660692479682368">"Villa við að hefja upptöku skjás"</string>
diff --git a/packages/SystemUI/res/values-it/strings.xml b/packages/SystemUI/res/values-it/strings.xml
index f4453b76bb61..b0e64a27f154 100644
--- a/packages/SystemUI/res/values-it/strings.xml
+++ b/packages/SystemUI/res/values-it/strings.xml
@@ -108,10 +108,8 @@
<string name="screenrecord_resume_label" msgid="4972223043729555575">"Riprendi"</string>
<string name="screenrecord_cancel_label" msgid="7850926573274483294">"Annulla"</string>
<string name="screenrecord_share_label" msgid="5025590804030086930">"Condividi"</string>
- <string name="screenrecord_delete_label" msgid="1376347010553987058">"CANC"</string>
<string name="screenrecord_cancel_success" msgid="1775448688137393901">"Registrazione dello schermo annullata"</string>
<string name="screenrecord_save_message" msgid="490522052388998226">"Registrazione dello schermo salvata. Tocca per visualizzarla."</string>
- <string name="screenrecord_delete_description" msgid="1604522770162810570">"Registrazione dello schermo eliminata"</string>
<string name="screenrecord_delete_error" msgid="2870506119743013588">"Errore durante l\'eliminazione della registrazione dello schermo"</string>
<string name="screenrecord_permission_error" msgid="7856841237023137686">"Impossibile ottenere le autorizzazioni"</string>
<string name="screenrecord_start_error" msgid="2200660692479682368">"Errore durante l\'avvio della registrazione dello schermo"</string>
diff --git a/packages/SystemUI/res/values-iw/strings.xml b/packages/SystemUI/res/values-iw/strings.xml
index 161fedc7a41e..92fa09b81e39 100644
--- a/packages/SystemUI/res/values-iw/strings.xml
+++ b/packages/SystemUI/res/values-iw/strings.xml
@@ -108,10 +108,8 @@
<string name="screenrecord_resume_label" msgid="4972223043729555575">"המשך"</string>
<string name="screenrecord_cancel_label" msgid="7850926573274483294">"ביטול"</string>
<string name="screenrecord_share_label" msgid="5025590804030086930">"שיתוף"</string>
- <string name="screenrecord_delete_label" msgid="1376347010553987058">"מחיקה"</string>
<string name="screenrecord_cancel_success" msgid="1775448688137393901">"הקלטת המסך בוטלה"</string>
<string name="screenrecord_save_message" msgid="490522052388998226">"הקלטת המסך נשמרה, יש להקיש כדי להציג"</string>
- <string name="screenrecord_delete_description" msgid="1604522770162810570">"הקלטת המסך נמחקה"</string>
<string name="screenrecord_delete_error" msgid="2870506119743013588">"שגיאה במחיקת הקלטת המסך"</string>
<string name="screenrecord_permission_error" msgid="7856841237023137686">"קבלת ההרשאות נכשלה"</string>
<string name="screenrecord_start_error" msgid="2200660692479682368">"שגיאה בהפעלה של הקלטת המסך"</string>
diff --git a/packages/SystemUI/res/values-ja/strings.xml b/packages/SystemUI/res/values-ja/strings.xml
index fa9c040b29a9..e427c8f950e5 100644
--- a/packages/SystemUI/res/values-ja/strings.xml
+++ b/packages/SystemUI/res/values-ja/strings.xml
@@ -108,10 +108,8 @@
<string name="screenrecord_resume_label" msgid="4972223043729555575">"再開"</string>
<string name="screenrecord_cancel_label" msgid="7850926573274483294">"キャンセル"</string>
<string name="screenrecord_share_label" msgid="5025590804030086930">"共有"</string>
- <string name="screenrecord_delete_label" msgid="1376347010553987058">"削除"</string>
<string name="screenrecord_cancel_success" msgid="1775448688137393901">"画面の録画をキャンセルしました"</string>
<string name="screenrecord_save_message" msgid="490522052388998226">"画面の録画を保存しました。タップで表示できます"</string>
- <string name="screenrecord_delete_description" msgid="1604522770162810570">"画面の録画を削除しました"</string>
<string name="screenrecord_delete_error" msgid="2870506119743013588">"画面の録画の削除中にエラーが発生しました"</string>
<string name="screenrecord_permission_error" msgid="7856841237023137686">"権限を取得できませんでした"</string>
<string name="screenrecord_start_error" msgid="2200660692479682368">"画面の録画中にエラーが発生しました"</string>
diff --git a/packages/SystemUI/res/values-ka/strings.xml b/packages/SystemUI/res/values-ka/strings.xml
index a3ddf70b5b25..b86bf8c32a75 100644
--- a/packages/SystemUI/res/values-ka/strings.xml
+++ b/packages/SystemUI/res/values-ka/strings.xml
@@ -108,10 +108,8 @@
<string name="screenrecord_resume_label" msgid="4972223043729555575">"გაგრძელება"</string>
<string name="screenrecord_cancel_label" msgid="7850926573274483294">"გაუქმება"</string>
<string name="screenrecord_share_label" msgid="5025590804030086930">"გაზიარება"</string>
- <string name="screenrecord_delete_label" msgid="1376347010553987058">"წაშლა"</string>
<string name="screenrecord_cancel_success" msgid="1775448688137393901">"ეკრანის ჩაწერა გაუქმდა"</string>
<string name="screenrecord_save_message" msgid="490522052388998226">"ეკრანის ჩანაწერი შენახულია, შეეხეთ სანახავად"</string>
- <string name="screenrecord_delete_description" msgid="1604522770162810570">"ეკრანის ჩანაწერი წაიშალა"</string>
<string name="screenrecord_delete_error" msgid="2870506119743013588">"ეკრანის ჩანაწერის წაშლისას წარმოიშვა შეცდომა"</string>
<string name="screenrecord_permission_error" msgid="7856841237023137686">"ნებართვების მიღება ვერ მოხერხდა"</string>
<string name="screenrecord_start_error" msgid="2200660692479682368">"ეკრანის ჩაწერის დაწყებისას წარმოიქმნა შეცდომა"</string>
diff --git a/packages/SystemUI/res/values-kk/strings.xml b/packages/SystemUI/res/values-kk/strings.xml
index 0d3f7f9f1973..1adaf2bc2755 100644
--- a/packages/SystemUI/res/values-kk/strings.xml
+++ b/packages/SystemUI/res/values-kk/strings.xml
@@ -108,10 +108,8 @@
<string name="screenrecord_resume_label" msgid="4972223043729555575">"Жалғастыру"</string>
<string name="screenrecord_cancel_label" msgid="7850926573274483294">"Бас тарту"</string>
<string name="screenrecord_share_label" msgid="5025590804030086930">"Бөлісу"</string>
- <string name="screenrecord_delete_label" msgid="1376347010553987058">"Жою"</string>
<string name="screenrecord_cancel_success" msgid="1775448688137393901">"Экранды бейнеге жазудан бас тартылды"</string>
<string name="screenrecord_save_message" msgid="490522052388998226">"Экран бейне жазбасы сақталды, көру үшін түртіңіз"</string>
- <string name="screenrecord_delete_description" msgid="1604522770162810570">"Экран бейне жазбасы жойылды"</string>
<string name="screenrecord_delete_error" msgid="2870506119743013588">"Экран бейне жазбасын жою кезінде қате кетті"</string>
<string name="screenrecord_permission_error" msgid="7856841237023137686">"Рұқсаттар алынбады"</string>
<string name="screenrecord_start_error" msgid="2200660692479682368">"Экрандағы бейнені жазу кезінде қате шықты."</string>
diff --git a/packages/SystemUI/res/values-km/strings.xml b/packages/SystemUI/res/values-km/strings.xml
index 5abd74000af5..961a37b3cd57 100644
--- a/packages/SystemUI/res/values-km/strings.xml
+++ b/packages/SystemUI/res/values-km/strings.xml
@@ -108,10 +108,8 @@
<string name="screenrecord_resume_label" msgid="4972223043729555575">"បន្ត"</string>
<string name="screenrecord_cancel_label" msgid="7850926573274483294">"បោះបង់"</string>
<string name="screenrecord_share_label" msgid="5025590804030086930">"ចែករំលែក"</string>
- <string name="screenrecord_delete_label" msgid="1376347010553987058">"លុប"</string>
<string name="screenrecord_cancel_success" msgid="1775448688137393901">"បាន​បោះបង់​ការថត​សកម្មភាព​អេក្រង់"</string>
<string name="screenrecord_save_message" msgid="490522052388998226">"បានរក្សាទុក​ការថត​សកម្មភាព​អេក្រង់។ សូមចុច​ដើម្បី​មើល"</string>
- <string name="screenrecord_delete_description" msgid="1604522770162810570">"បានលុប​ការថត​សកម្មភាព​អេក្រង់"</string>
<string name="screenrecord_delete_error" msgid="2870506119743013588">"មានបញ្ហា​ក្នុងការ​លុបការថត​សកម្មភាព​អេក្រង់"</string>
<string name="screenrecord_permission_error" msgid="7856841237023137686">"មិនអាច​ទទួលបាន​ការអនុញ្ញាត​ទេ"</string>
<string name="screenrecord_start_error" msgid="2200660692479682368">"មានបញ្ហា​ក្នុងការ​ចាប់ផ្ដើម​ថត​អេក្រង់"</string>
diff --git a/packages/SystemUI/res/values-kn/strings.xml b/packages/SystemUI/res/values-kn/strings.xml
index 47f23856c7b0..7ec6a9f54a74 100644
--- a/packages/SystemUI/res/values-kn/strings.xml
+++ b/packages/SystemUI/res/values-kn/strings.xml
@@ -108,10 +108,8 @@
<string name="screenrecord_resume_label" msgid="4972223043729555575">"ಮುಂದುವರಿಸಿ"</string>
<string name="screenrecord_cancel_label" msgid="7850926573274483294">"ರದ್ದುಮಾಡಿ"</string>
<string name="screenrecord_share_label" msgid="5025590804030086930">"ಹಂಚಿಕೊಳ್ಳಿ"</string>
- <string name="screenrecord_delete_label" msgid="1376347010553987058">"ಅಳಿಸಿ"</string>
<string name="screenrecord_cancel_success" msgid="1775448688137393901">"ಸ್ಕ್ರೀನ್ ರೆಕಾರ್ಡಿಂಗ್ ಅನ್ನು ರದ್ದುಮಾಡಲಾಗಿದೆ"</string>
<string name="screenrecord_save_message" msgid="490522052388998226">"ಸ್ಕ್ರೀನ್ ರೆಕಾರ್ಡಿಂಗ್ ಅನ್ನು ಉಳಿಸಲಾಗಿದೆ, ವೀಕ್ಷಿಸಲು ಟ್ಯಾಪ್ ಮಾಡಿ"</string>
- <string name="screenrecord_delete_description" msgid="1604522770162810570">"ಸ್ಕ್ರೀನ್ ರೆಕಾರ್ಡಿಂಗ್ ಅಳಿಸಲಾಗಿದೆ"</string>
<string name="screenrecord_delete_error" msgid="2870506119743013588">"ಸ್ಕ್ರೀನ್ ರೆಕಾರ್ಡಿಂಗ್ ಅಳಿಸುವಾಗ ದೋಷ ಕಂಡುಬಂದಿದೆ"</string>
<string name="screenrecord_permission_error" msgid="7856841237023137686">"ಅನುಮತಿಗಳನ್ನು ಪಡೆಯುವಲ್ಲಿ ವಿಫಲವಾಗಿದೆ"</string>
<string name="screenrecord_start_error" msgid="2200660692479682368">"ಸ್ಕ್ರೀನ್ ರೆಕಾರ್ಡಿಂಗ್ ಪ್ರಾರಂಭಿಸುವಾಗ ದೋಷ ಕಂಡುಬಂದಿದೆ"</string>
diff --git a/packages/SystemUI/res/values-ko/strings.xml b/packages/SystemUI/res/values-ko/strings.xml
index beb7edade8e6..840a98e32e23 100644
--- a/packages/SystemUI/res/values-ko/strings.xml
+++ b/packages/SystemUI/res/values-ko/strings.xml
@@ -108,10 +108,8 @@
<string name="screenrecord_resume_label" msgid="4972223043729555575">"재개"</string>
<string name="screenrecord_cancel_label" msgid="7850926573274483294">"취소"</string>
<string name="screenrecord_share_label" msgid="5025590804030086930">"공유"</string>
- <string name="screenrecord_delete_label" msgid="1376347010553987058">"삭제"</string>
<string name="screenrecord_cancel_success" msgid="1775448688137393901">"화면 녹화가 취소되었습니다."</string>
<string name="screenrecord_save_message" msgid="490522052388998226">"화면 녹화본이 저장되었습니다. 확인하려면 탭하세요."</string>
- <string name="screenrecord_delete_description" msgid="1604522770162810570">"화면 녹화가 삭제되었습니다."</string>
<string name="screenrecord_delete_error" msgid="2870506119743013588">"화면 녹화는 삭제하는 중에 오류가 발생했습니다."</string>
<string name="screenrecord_permission_error" msgid="7856841237023137686">"권한을 확보하지 못했습니다."</string>
<string name="screenrecord_start_error" msgid="2200660692479682368">"화면 녹화 시작 중 오류 발생"</string>
diff --git a/packages/SystemUI/res/values-ky/strings.xml b/packages/SystemUI/res/values-ky/strings.xml
index 4fbb09e56bbd..14ee566d305c 100644
--- a/packages/SystemUI/res/values-ky/strings.xml
+++ b/packages/SystemUI/res/values-ky/strings.xml
@@ -108,10 +108,8 @@
<string name="screenrecord_resume_label" msgid="4972223043729555575">"Улантуу"</string>
<string name="screenrecord_cancel_label" msgid="7850926573274483294">"Жокко чыгаруу"</string>
<string name="screenrecord_share_label" msgid="5025590804030086930">"Бөлүшүү"</string>
- <string name="screenrecord_delete_label" msgid="1376347010553987058">"Ооба"</string>
<string name="screenrecord_cancel_success" msgid="1775448688137393901">"Экранды жаздыруу жокко чыгарылды"</string>
<string name="screenrecord_save_message" msgid="490522052388998226">"Экранды жаздыруу сакталды, көрүү үчүн таптап коюңуз"</string>
- <string name="screenrecord_delete_description" msgid="1604522770162810570">"Экранды жаздыруу өчүрүлдү"</string>
<string name="screenrecord_delete_error" msgid="2870506119743013588">"Экранды жаздырууну өчүрүүдө ката кетти"</string>
<string name="screenrecord_permission_error" msgid="7856841237023137686">"Уруксаттар алынбай калды"</string>
<string name="screenrecord_start_error" msgid="2200660692479682368">"Экранды жаздырууну баштоодо ката кетти"</string>
diff --git a/packages/SystemUI/res/values-land-television/dimens.xml b/packages/SystemUI/res/values-land-television/dimens.xml
index 90fc652b05e9..8237919990de 100644
--- a/packages/SystemUI/res/values-land-television/dimens.xml
+++ b/packages/SystemUI/res/values-land-television/dimens.xml
@@ -15,8 +15,9 @@
-->
<resources>
- <!-- Width of volume bar -->
- <dimen name="volume_dialog_row_width">252dp</dimen>
+ <!-- Height of volume bar -->
+ <dimen name="volume_dialog_row_height">200dp</dimen>
+ <dimen name="volume_dialog_panel_transparent_padding">17dp</dimen>
<dimen name="tv_volume_dialog_bubble_size">36dp</dimen>
<dimen name="tv_volume_dialog_corner_radius">40dp</dimen>
<dimen name="tv_volume_dialog_row_padding">5dp</dimen>
diff --git a/packages/SystemUI/res/values-land/dimens.xml b/packages/SystemUI/res/values-land/dimens.xml
index 9e1b66f07758..b584dfee1e60 100644
--- a/packages/SystemUI/res/values-land/dimens.xml
+++ b/packages/SystemUI/res/values-land/dimens.xml
@@ -47,4 +47,15 @@
<dimen name="global_actions_power_dialog_item_height">130dp</dimen>
<dimen name="global_actions_power_dialog_item_bottom_margin">35dp</dimen>
+
+ <dimen name="controls_management_top_padding">12dp</dimen>
+ <dimen name="controls_management_titles_margin">8dp</dimen>
+ <dimen name="controls_management_indicator_top_margin">8dp</dimen>
+ <dimen name="controls_management_list_margin">4dp</dimen>
+ <dimen name="controls_management_footer_height">56dp</dimen>
+ <dimen name="controls_management_zone_top_margin">24dp</dimen>
+
+ <!-- (footer_height -48dp)/2 -->
+ <dimen name="controls_management_footer_top_margin">4dp</dimen>
+ <dimen name="controls_management_favorites_top_margin">8dp</dimen>
</resources>
diff --git a/packages/SystemUI/res/values-lo/strings.xml b/packages/SystemUI/res/values-lo/strings.xml
index 6d7feabfed1a..553d0da2e295 100644
--- a/packages/SystemUI/res/values-lo/strings.xml
+++ b/packages/SystemUI/res/values-lo/strings.xml
@@ -108,10 +108,8 @@
<string name="screenrecord_resume_label" msgid="4972223043729555575">"ສືບຕໍ່"</string>
<string name="screenrecord_cancel_label" msgid="7850926573274483294">"ຍົກເລີກ"</string>
<string name="screenrecord_share_label" msgid="5025590804030086930">"ແບ່ງປັນ"</string>
- <string name="screenrecord_delete_label" msgid="1376347010553987058">"ລຶບ"</string>
<string name="screenrecord_cancel_success" msgid="1775448688137393901">"ຍົກເລີກການບັນທຶກໜ້າຈໍແລ້ວ"</string>
<string name="screenrecord_save_message" msgid="490522052388998226">"ຈັດເກັບການບັນທຶກໜ້າຈໍ, ແຕະເພື່ອເບິ່ງ"</string>
- <string name="screenrecord_delete_description" msgid="1604522770162810570">"ລຶບການບັນທຶກໜ້າຈໍອອກແລ້ວ"</string>
<string name="screenrecord_delete_error" msgid="2870506119743013588">"ເກີດຄວາມຜິດພາດໃນການລຶບການບັນທຶກໜ້າຈໍ"</string>
<string name="screenrecord_permission_error" msgid="7856841237023137686">"ໂຫຼດສິດອະນຸຍາດບໍ່ສຳເລັດ"</string>
<string name="screenrecord_start_error" msgid="2200660692479682368">"ເກີດຄວາມຜິດພາດໃນການບັນທຶກໜ້າຈໍ"</string>
diff --git a/packages/SystemUI/res/values-lt/strings.xml b/packages/SystemUI/res/values-lt/strings.xml
index 21217a06179f..28d6e6b35431 100644
--- a/packages/SystemUI/res/values-lt/strings.xml
+++ b/packages/SystemUI/res/values-lt/strings.xml
@@ -108,10 +108,8 @@
<string name="screenrecord_resume_label" msgid="4972223043729555575">"Tęsti"</string>
<string name="screenrecord_cancel_label" msgid="7850926573274483294">"Atšaukti"</string>
<string name="screenrecord_share_label" msgid="5025590804030086930">"Bendrinti"</string>
- <string name="screenrecord_delete_label" msgid="1376347010553987058">"Ištrinti"</string>
<string name="screenrecord_cancel_success" msgid="1775448688137393901">"Ekrano įrašymas atšauktas"</string>
<string name="screenrecord_save_message" msgid="490522052388998226">"Ekrano įrašas išsaugotas, palieskite ir peržiūrėkite"</string>
- <string name="screenrecord_delete_description" msgid="1604522770162810570">"Ekrano įrašas ištrintas"</string>
<string name="screenrecord_delete_error" msgid="2870506119743013588">"Ištrinant ekrano įrašą įvyko klaida"</string>
<string name="screenrecord_permission_error" msgid="7856841237023137686">"Nepavyko gauti leidimų"</string>
<string name="screenrecord_start_error" msgid="2200660692479682368">"Pradedant ekrano vaizdo įrašymą iškilo problema"</string>
diff --git a/packages/SystemUI/res/values-lv/strings.xml b/packages/SystemUI/res/values-lv/strings.xml
index 4945dfa3f3db..223a57fdb640 100644
--- a/packages/SystemUI/res/values-lv/strings.xml
+++ b/packages/SystemUI/res/values-lv/strings.xml
@@ -108,10 +108,8 @@
<string name="screenrecord_resume_label" msgid="4972223043729555575">"Atsākt"</string>
<string name="screenrecord_cancel_label" msgid="7850926573274483294">"Atcelt"</string>
<string name="screenrecord_share_label" msgid="5025590804030086930">"Kopīgot"</string>
- <string name="screenrecord_delete_label" msgid="1376347010553987058">"Dzēst"</string>
<string name="screenrecord_cancel_success" msgid="1775448688137393901">"Ekrāna ierakstīšana ir atcelta."</string>
<string name="screenrecord_save_message" msgid="490522052388998226">"Ekrāna ieraksts ir saglabāts. Pieskarieties, lai to skatītu."</string>
- <string name="screenrecord_delete_description" msgid="1604522770162810570">"Ekrāna ieraksts ir izdzēsts."</string>
<string name="screenrecord_delete_error" msgid="2870506119743013588">"Dzēšot ekrāna ierakstu, radās kļūda."</string>
<string name="screenrecord_permission_error" msgid="7856841237023137686">"Neizdevās iegūt atļaujas."</string>
<string name="screenrecord_start_error" msgid="2200660692479682368">"Sākot ierakstīt ekrāna saturu, radās kļūda."</string>
diff --git a/packages/SystemUI/res/values-mcc310-mnc004/strings.xml b/packages/SystemUI/res/values-mcc310-mnc004/strings.xml
new file mode 100644
index 000000000000..f8ed0c01fa83
--- /dev/null
+++ b/packages/SystemUI/res/values-mcc310-mnc004/strings.xml
@@ -0,0 +1,22 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+/**
+ * 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.
+ */
+-->
+<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <!-- Content description of the data connection type 5G UW. [CHAR LIMIT=NONE] -->
+ <string name="data_connection_5g_plus" translatable="false">5G UW</string>
+</resources>
diff --git a/packages/SystemUI/res/values-mcc311-mnc480/strings.xml b/packages/SystemUI/res/values-mcc311-mnc480/strings.xml
new file mode 100644
index 000000000000..f8ed0c01fa83
--- /dev/null
+++ b/packages/SystemUI/res/values-mcc311-mnc480/strings.xml
@@ -0,0 +1,22 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+/**
+ * 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.
+ */
+-->
+<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <!-- Content description of the data connection type 5G UW. [CHAR LIMIT=NONE] -->
+ <string name="data_connection_5g_plus" translatable="false">5G UW</string>
+</resources>
diff --git a/packages/SystemUI/res/values-mk/strings.xml b/packages/SystemUI/res/values-mk/strings.xml
index 40d4698f7c21..a591031cabba 100644
--- a/packages/SystemUI/res/values-mk/strings.xml
+++ b/packages/SystemUI/res/values-mk/strings.xml
@@ -108,10 +108,8 @@
<string name="screenrecord_resume_label" msgid="4972223043729555575">"Продолжи"</string>
<string name="screenrecord_cancel_label" msgid="7850926573274483294">"Откажи"</string>
<string name="screenrecord_share_label" msgid="5025590804030086930">"Сподели"</string>
- <string name="screenrecord_delete_label" msgid="1376347010553987058">"Избриши"</string>
<string name="screenrecord_cancel_success" msgid="1775448688137393901">"Снимањето екран е откажано"</string>
<string name="screenrecord_save_message" msgid="490522052388998226">"Снимката од екранот е зачувана, допрете за да ја видите"</string>
- <string name="screenrecord_delete_description" msgid="1604522770162810570">"Снимката од екранот е избришана"</string>
<string name="screenrecord_delete_error" msgid="2870506119743013588">"Грешка при бришењето на снимката од екранот"</string>
<string name="screenrecord_permission_error" msgid="7856841237023137686">"Не успеаја да се добијат дозволи"</string>
<string name="screenrecord_start_error" msgid="2200660692479682368">"Грешка при почетокот на снимањето на екранот"</string>
@@ -667,7 +665,7 @@
<string name="tuner_warning_title" msgid="7721976098452135267">"Забава за некои, но не за сите"</string>
<string name="tuner_warning" msgid="1861736288458481650">"Адаптерот на УИ на системот ви дава дополнителни начини за дотерување и приспособување на корисничкиот интерфејс на Android. Овие експериментални функции можеби ќе се изменат, расипат или ќе исчезнат во следните изданија. Продолжете со претпазливост."</string>
<string name="tuner_persistent_warning" msgid="230466285569307806">"Овие експериментални функции можеби ќе се изменат, расипат или ќе исчезнат во следните изданија. Продолжете со претпазливост."</string>
- <string name="got_it" msgid="477119182261892069">"Разбрав"</string>
+ <string name="got_it" msgid="477119182261892069">"Сфатив"</string>
<string name="tuner_toast" msgid="3812684836514766951">"Честито! Го додадовте Адаптерот на УИ на системот на Поставки"</string>
<string name="remove_from_settings" msgid="633775561782209994">"Отстрани од поставки"</string>
<string name="remove_from_settings_prompt" msgid="551565437265615426">"Да се отстрани Адаптерот на УИ на системот од Поставки и да престанат да се користат сите негови функции?"</string>
diff --git a/packages/SystemUI/res/values-ml/strings.xml b/packages/SystemUI/res/values-ml/strings.xml
index c3bd65ef8e50..47d220df5bde 100644
--- a/packages/SystemUI/res/values-ml/strings.xml
+++ b/packages/SystemUI/res/values-ml/strings.xml
@@ -108,10 +108,8 @@
<string name="screenrecord_resume_label" msgid="4972223043729555575">"പുനരാരംഭിക്കുക"</string>
<string name="screenrecord_cancel_label" msgid="7850926573274483294">"റദ്ദാക്കുക"</string>
<string name="screenrecord_share_label" msgid="5025590804030086930">"പങ്കിടുക"</string>
- <string name="screenrecord_delete_label" msgid="1376347010553987058">"ഇല്ലാതാക്കുക"</string>
<string name="screenrecord_cancel_success" msgid="1775448688137393901">"സ്ക്രീൻ റെക്കോർഡിംഗ് റദ്ദാക്കി"</string>
<string name="screenrecord_save_message" msgid="490522052388998226">"സ്ക്രീൻ റെക്കോർഡിംഗ് സംരക്ഷിച്ചു, കാണാൻ ടാപ്പ് ചെയ്യുക"</string>
- <string name="screenrecord_delete_description" msgid="1604522770162810570">"സ്ക്രീൻ റെക്കോർഡിംഗ് ഇല്ലാതാക്കി"</string>
<string name="screenrecord_delete_error" msgid="2870506119743013588">"സ്ക്രീൻ റെക്കോർഡിംഗ് ഇല്ലാതാക്കുന്നതിൽ പിശക്"</string>
<string name="screenrecord_permission_error" msgid="7856841237023137686">"അനുമതികൾ ലഭിച്ചില്ല"</string>
<string name="screenrecord_start_error" msgid="2200660692479682368">"സ്ക്രീൻ റെക്കോർഡിംഗ് ആരംഭിക്കുന്നതിൽ പിശക്"</string>
diff --git a/packages/SystemUI/res/values-mn/strings.xml b/packages/SystemUI/res/values-mn/strings.xml
index 5f08f05ed9be..202f292503b0 100644
--- a/packages/SystemUI/res/values-mn/strings.xml
+++ b/packages/SystemUI/res/values-mn/strings.xml
@@ -108,10 +108,8 @@
<string name="screenrecord_resume_label" msgid="4972223043729555575">"Үргэлжлүүлэх"</string>
<string name="screenrecord_cancel_label" msgid="7850926573274483294">"Цуцлах"</string>
<string name="screenrecord_share_label" msgid="5025590804030086930">"Хуваалцах"</string>
- <string name="screenrecord_delete_label" msgid="1376347010553987058">"Устгах"</string>
<string name="screenrecord_cancel_success" msgid="1775448688137393901">"Дэлгэцийн бичлэгийг цуцалсан"</string>
<string name="screenrecord_save_message" msgid="490522052388998226">"Дэлгэцийн бичлэгийг хадгалсан. Харахын тулд товшино уу"</string>
- <string name="screenrecord_delete_description" msgid="1604522770162810570">"Дэлгэцийн бичлэгийг устгасан"</string>
<string name="screenrecord_delete_error" msgid="2870506119743013588">"Дэлгэцийн бичлэгийг устгахад алдаа гарлаа"</string>
<string name="screenrecord_permission_error" msgid="7856841237023137686">"Зөвшөөрөл авч чадсангүй"</string>
<string name="screenrecord_start_error" msgid="2200660692479682368">"Дэлгэцийн бичлэгийг эхлүүлэхэд алдаа гарлаа"</string>
diff --git a/packages/SystemUI/res/values-mr/strings.xml b/packages/SystemUI/res/values-mr/strings.xml
index 6d525df2d05b..e4120726c66c 100644
--- a/packages/SystemUI/res/values-mr/strings.xml
+++ b/packages/SystemUI/res/values-mr/strings.xml
@@ -108,10 +108,8 @@
<string name="screenrecord_resume_label" msgid="4972223043729555575">"पुन्हा सुरू करा"</string>
<string name="screenrecord_cancel_label" msgid="7850926573274483294">"रद्द करा"</string>
<string name="screenrecord_share_label" msgid="5025590804030086930">"शेअर करा"</string>
- <string name="screenrecord_delete_label" msgid="1376347010553987058">"हटवा"</string>
<string name="screenrecord_cancel_success" msgid="1775448688137393901">"स्क्रीन रेकॉर्डिंग रद्द केले"</string>
<string name="screenrecord_save_message" msgid="490522052388998226">"स्क्रीन रेकॉर्डिंग सेव्ह केली, पाहण्यासाठी टॅप करा"</string>
- <string name="screenrecord_delete_description" msgid="1604522770162810570">"स्क्रीन रेकॉर्डिंग हटवले"</string>
<string name="screenrecord_delete_error" msgid="2870506119743013588">"स्क्रीन रेकॉर्डिंग हटवताना एरर आली"</string>
<string name="screenrecord_permission_error" msgid="7856841237023137686">"परवानग्या मिळवता आल्या नाहीत"</string>
<string name="screenrecord_start_error" msgid="2200660692479682368">"स्क्रीन रेकॉर्डिंग सुरू करताना एरर आली"</string>
diff --git a/packages/SystemUI/res/values-ms/strings.xml b/packages/SystemUI/res/values-ms/strings.xml
index 4f832e4c450d..0331d26e4ec7 100644
--- a/packages/SystemUI/res/values-ms/strings.xml
+++ b/packages/SystemUI/res/values-ms/strings.xml
@@ -108,10 +108,8 @@
<string name="screenrecord_resume_label" msgid="4972223043729555575">"Sambung semula"</string>
<string name="screenrecord_cancel_label" msgid="7850926573274483294">"Batal"</string>
<string name="screenrecord_share_label" msgid="5025590804030086930">"Kongsi"</string>
- <string name="screenrecord_delete_label" msgid="1376347010553987058">"Padam"</string>
<string name="screenrecord_cancel_success" msgid="1775448688137393901">"Rakaman skrin dibatalkan"</string>
<string name="screenrecord_save_message" msgid="490522052388998226">"Rakaman skrin disimpan, ketik untuk melihat"</string>
- <string name="screenrecord_delete_description" msgid="1604522770162810570">"Rakaman skrin dipadamkan"</string>
<string name="screenrecord_delete_error" msgid="2870506119743013588">"Ralat semasa memadamkan rakaman skrin"</string>
<string name="screenrecord_permission_error" msgid="7856841237023137686">"Gagal mendapatkan kebenaran"</string>
<string name="screenrecord_start_error" msgid="2200660692479682368">"Ralat semasa memulakan rakaman skrin"</string>
@@ -405,7 +403,7 @@
<item quantity="one">%d peranti</item>
</plurals>
<string name="quick_settings_notifications_label" msgid="3379631363952582758">"Pemberitahuan"</string>
- <string name="quick_settings_flashlight_label" msgid="4904634272006284185">"Lampu suluh"</string>
+ <string name="quick_settings_flashlight_label" msgid="4904634272006284185">"Lampu Suluh"</string>
<string name="quick_settings_flashlight_camera_in_use" msgid="4820591564526512571">"Kamera sedang digunakan"</string>
<string name="quick_settings_cellular_detail_title" msgid="792977203299358893">"Data mudah alih"</string>
<string name="quick_settings_cellular_detail_data_usage" msgid="6105969068871138427">"Penggunaan data"</string>
diff --git a/packages/SystemUI/res/values-my/strings.xml b/packages/SystemUI/res/values-my/strings.xml
index 150ed94eec38..83272f2a43c4 100644
--- a/packages/SystemUI/res/values-my/strings.xml
+++ b/packages/SystemUI/res/values-my/strings.xml
@@ -108,10 +108,8 @@
<string name="screenrecord_resume_label" msgid="4972223043729555575">"ဆက်လုပ်ရန်"</string>
<string name="screenrecord_cancel_label" msgid="7850926573274483294">"မလုပ်တော့"</string>
<string name="screenrecord_share_label" msgid="5025590804030086930">"မျှဝေရန်"</string>
- <string name="screenrecord_delete_label" msgid="1376347010553987058">"ဖျက်ရန်"</string>
<string name="screenrecord_cancel_success" msgid="1775448688137393901">"ဖန်သားပြင် ရိုက်ကူးမှု ပယ်ဖျက်လိုက်ပါပြီ"</string>
<string name="screenrecord_save_message" msgid="490522052388998226">"ဖန်သားပြင် ရိုက်ကူးမှု သိမ်းထားသည်၊ ကြည့်ရန် တို့ပါ"</string>
- <string name="screenrecord_delete_description" msgid="1604522770162810570">"ဖန်သားပြင် ရိုက်ကူးမှု ဖျက်ပြီးပါပြီ"</string>
<string name="screenrecord_delete_error" msgid="2870506119743013588">"ဖန်သားပြင် ရိုက်ကူးမှု ဖျက်ရာတွင် အမှားအယွင်းရှိနေသည်"</string>
<string name="screenrecord_permission_error" msgid="7856841237023137686">"ခွင့်ပြုချက် မရယူနိုင်ပါ"</string>
<string name="screenrecord_start_error" msgid="2200660692479682368">"ဖန်သားပြင် ရိုက်ကူးမှု စတင်ရာတွင် အမှားအယွင်းရှိနေသည်"</string>
diff --git a/packages/SystemUI/res/values-nb/strings.xml b/packages/SystemUI/res/values-nb/strings.xml
index 849c2e9e7381..01859ef5a13e 100644
--- a/packages/SystemUI/res/values-nb/strings.xml
+++ b/packages/SystemUI/res/values-nb/strings.xml
@@ -108,10 +108,8 @@
<string name="screenrecord_resume_label" msgid="4972223043729555575">"Gjenoppta"</string>
<string name="screenrecord_cancel_label" msgid="7850926573274483294">"Avbryt"</string>
<string name="screenrecord_share_label" msgid="5025590804030086930">"Del"</string>
- <string name="screenrecord_delete_label" msgid="1376347010553987058">"Slett"</string>
<string name="screenrecord_cancel_success" msgid="1775448688137393901">"Skjermopptak er avbrutt"</string>
<string name="screenrecord_save_message" msgid="490522052388998226">"Skjermopptaket er lagret. Trykk for å se det"</string>
- <string name="screenrecord_delete_description" msgid="1604522770162810570">"Skjermopptaket er slettet"</string>
<string name="screenrecord_delete_error" msgid="2870506119743013588">"Feil ved sletting av skjermopptaket"</string>
<string name="screenrecord_permission_error" msgid="7856841237023137686">"Kunne ikke få tillatelser"</string>
<string name="screenrecord_start_error" msgid="2200660692479682368">"Feil ved start av skjermopptaket"</string>
diff --git a/packages/SystemUI/res/values-ne/strings.xml b/packages/SystemUI/res/values-ne/strings.xml
index 2ac442ec0225..196b4ad2f94e 100644
--- a/packages/SystemUI/res/values-ne/strings.xml
+++ b/packages/SystemUI/res/values-ne/strings.xml
@@ -108,10 +108,8 @@
<string name="screenrecord_resume_label" msgid="4972223043729555575">"जारी राख्नुहोस्"</string>
<string name="screenrecord_cancel_label" msgid="7850926573274483294">"रद्द गर्नुहोस्"</string>
<string name="screenrecord_share_label" msgid="5025590804030086930">"सेयर गर्नुहोस्"</string>
- <string name="screenrecord_delete_label" msgid="1376347010553987058">"मेट्नुहोस्"</string>
<string name="screenrecord_cancel_success" msgid="1775448688137393901">"स्क्रिन रेकर्ड गर्ने कार्य रद्द गरियो"</string>
<string name="screenrecord_save_message" msgid="490522052388998226">"स्क्रिन रेकर्डिङ सुरक्षित गरियो, हेर्न ट्याप गर्नुहोस्‌"</string>
- <string name="screenrecord_delete_description" msgid="1604522770162810570">"स्क्रिनको रेकर्डिङ मेटाइयो"</string>
<string name="screenrecord_delete_error" msgid="2870506119743013588">"स्क्रिनको रेकर्डिङ मेट्ने क्रममा त्रुटि"</string>
<string name="screenrecord_permission_error" msgid="7856841237023137686">"अनुमति प्राप्त गर्न सकिएन"</string>
<string name="screenrecord_start_error" msgid="2200660692479682368">"स्क्रिन रेकर्ड गर्न थाल्ने क्रममा त्रुटि भयो"</string>
@@ -502,8 +500,8 @@
<string name="battery_saver_notification_title" msgid="8419266546034372562">"ब्याट्री सेभर अन छ"</string>
<string name="battery_saver_notification_text" msgid="2617841636449016951">"प्रदर्शन र पृष्ठभूमि डेटा घटाउँनुहोस्"</string>
<string name="battery_saver_notification_action_text" msgid="6022091913807026887">"ब्याट्री सेभर अफ गर्नुहोस्"</string>
- <string name="media_projection_dialog_text" msgid="1755705274910034772">"<xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g> ले तपाईंको स्क्रिनमा देख्न सकिने सबै जानकारी अथवा रेकर्ड वा cast गर्दा तपाईंको यन्त्रबाट प्ले गरिएका कुरामाथि पहुँच राख्न सक्ने छ। यसअन्तर्गत पासवर्ड, भुक्तानीका विवरण, तस्बिर, सन्देश र तपाईंले प्ले गर्ने अडियो जस्ता जानकारी समावेश हुन्छन्।"</string>
- <string name="media_projection_dialog_service_text" msgid="958000992162214611">"यो कार्य प्रदान गर्ने सेवाले तपाईंको स्क्रिनमा देख्न सकिने सबै जानकारी अथवा रेकर्ड वा cast गर्दा तपाईंको यन्त्रबाट प्ले गरिएका कुरामाथि पहुँच राख्न सक्ने छ। यसअन्तर्गत पासवर्ड, भुक्तानीका विवरण, तस्बिर, सन्देश र तपाईंले प्ले गर्ने अडियो जस्ता जानकारी समावेश हुन्छन्।"</string>
+ <string name="media_projection_dialog_text" msgid="1755705274910034772">"<xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g> ले तपाईंको स्क्रिनमा देख्न सकिने सबै जानकारी अथवा रेकर्ड वा cast गर्दा तपाईंको यन्त्रबाट प्ले गरिएका कुरामाथि पहुँच राख्न सक्ने छ। यसअन्तर्गत पासवर्ड, भुक्तानीका विवरण, फोटो, सन्देश र तपाईंले प्ले गर्ने अडियो जस्ता जानकारी समावेश हुन्छन्।"</string>
+ <string name="media_projection_dialog_service_text" msgid="958000992162214611">"यो कार्य प्रदान गर्ने सेवाले तपाईंको स्क्रिनमा देख्न सकिने सबै जानकारी अथवा रेकर्ड वा cast गर्दा तपाईंको यन्त्रबाट प्ले गरिएका कुरामाथि पहुँच राख्न सक्ने छ। यसअन्तर्गत पासवर्ड, भुक्तानीका विवरण, फोटो, सन्देश र तपाईंले प्ले गर्ने अडियो जस्ता जानकारी समावेश हुन्छन्।"</string>
<string name="media_projection_dialog_service_title" msgid="2888507074107884040">"रेकर्ड गर्न वा cast गर्न थाल्ने हो?"</string>
<string name="media_projection_dialog_title" msgid="3316063622495360646">"<xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g> मार्फत रेकर्ड गर्न वा cast गर्न थाल्ने हो?"</string>
<string name="media_projection_remember_text" msgid="6896767327140422951">"फेरि नदेखाउनुहोस्"</string>
@@ -718,7 +716,7 @@
<string name="notification_channel_summary_default_with_bubbles" msgid="1782419896613644568">"फोनको सेटिङका आधारमा घन्टी बज्न वा कम्पन हुन सक्छ। <xliff:g id="APP_NAME">%1$s</xliff:g> का वार्तालापहरू पूर्वनिर्धारित रूपमा बबलमा देखाइन्छन्।"</string>
<string name="notification_channel_summary_bubble" msgid="7235935211580860537">"फ्लोटिङ सर्टकटमार्फत यो सामग्रीतर्फ तपाईंको ध्यान आकर्षित गर्दछ।"</string>
<string name="notification_channel_summary_automatic" msgid="5813109268050235275">"सिस्टमलाई यो सूचना आउँदा ध्वनि बज्नु पर्छ वा कम्पन हुनु पर्छ भन्ने कुराको निधो गर्न दिनुहोस्"</string>
- <string name="notification_channel_summary_priority" msgid="7952654515769021553">"वार्तालाप खण्डको सिरानमा देखा पर्छ, तैरने बबलका रूपमा देखा पर्छ, लक स्क्रिनमा प्रोफाइल तस्बिर देखाइन्छ"</string>
+ <string name="notification_channel_summary_priority" msgid="7952654515769021553">"वार्तालाप खण्डको सिरानमा देखा पर्छ, तैरने बबलका रूपमा देखा पर्छ, लक स्क्रिनमा प्रोफाइल फोटो देखाइन्छ"</string>
<string name="notification_conversation_channel_settings" msgid="2409977688430606835">"सेटिङ"</string>
<string name="notification_priority_title" msgid="2079708866333537093">"प्राथमिकता"</string>
<string name="no_shortcut" msgid="8257177117568230126">"<xliff:g id="APP_NAME">%1$s</xliff:g> मा वार्तालापसम्बन्धी सुविधा प्रयोग गर्न मिल्दैन"</string>
@@ -1021,7 +1019,7 @@
<string name="priority_onboarding_title" msgid="2893070698479227616">"वार्तालापको प्राथमिकता निर्धारण गरी \"महत्त्वपूर्ण\" बनाइयो"</string>
<string name="priority_onboarding_behavior" msgid="5342816047020432929">"महत्वपूर्ण वार्तालापहरू:"</string>
<string name="priority_onboarding_show_at_top_text" msgid="1678400241025513541">"वार्तालाप खण्डको सिरानमा देखिने छन्"</string>
- <string name="priority_onboarding_show_avatar_text" msgid="5756291381124091508">"लक स्क्रिनमा प्रोफाइल तस्बिर देखाउने छन्"</string>
+ <string name="priority_onboarding_show_avatar_text" msgid="5756291381124091508">"लक स्क्रिनमा प्रोफाइल फोटो देखाउने छन्"</string>
<string name="priority_onboarding_appear_as_bubble_text" msgid="4227039772250263122">"एपहरूमाथि तैरिने बबलका रूपमा देखाइयोस्"</string>
<string name="priority_onboarding_ignores_dnd_text" msgid="2918952762719600529">"बाधा नपुऱ्याउनुहोस् मोडलाई बेवास्ता गरियोस्"</string>
<string name="priority_onboarding_done_button_title" msgid="4569550984286506007">"बुझेँ"</string>
diff --git a/packages/SystemUI/res/values-nl/strings.xml b/packages/SystemUI/res/values-nl/strings.xml
index da0f42754acd..fa028c336594 100644
--- a/packages/SystemUI/res/values-nl/strings.xml
+++ b/packages/SystemUI/res/values-nl/strings.xml
@@ -108,10 +108,8 @@
<string name="screenrecord_resume_label" msgid="4972223043729555575">"Hervatten"</string>
<string name="screenrecord_cancel_label" msgid="7850926573274483294">"Annuleren"</string>
<string name="screenrecord_share_label" msgid="5025590804030086930">"Delen"</string>
- <string name="screenrecord_delete_label" msgid="1376347010553987058">"Verwijderen"</string>
<string name="screenrecord_cancel_success" msgid="1775448688137393901">"Schermopname geannuleerd"</string>
<string name="screenrecord_save_message" msgid="490522052388998226">"Schermopname opgeslagen, tik om te bekijken"</string>
- <string name="screenrecord_delete_description" msgid="1604522770162810570">"Schermopname verwijderd"</string>
<string name="screenrecord_delete_error" msgid="2870506119743013588">"Fout bij verwijderen van schermopname"</string>
<string name="screenrecord_permission_error" msgid="7856841237023137686">"Kan rechten niet ophalen"</string>
<string name="screenrecord_start_error" msgid="2200660692479682368">"Fout bij starten van schermopname"</string>
@@ -354,7 +352,7 @@
<string name="quick_settings_bluetooth_secondary_label_audio" msgid="780333390310051161">"Audio"</string>
<string name="quick_settings_bluetooth_secondary_label_headset" msgid="2332093067553000852">"Headset"</string>
<string name="quick_settings_bluetooth_secondary_label_input" msgid="3887552721233148132">"Invoer"</string>
- <string name="quick_settings_bluetooth_secondary_label_hearing_aids" msgid="3003338571871392293">"Gehoorapparaten"</string>
+ <string name="quick_settings_bluetooth_secondary_label_hearing_aids" msgid="3003338571871392293">"Hoortoestellen"</string>
<string name="quick_settings_bluetooth_secondary_label_transient" msgid="3882884317600669650">"Inschakelen..."</string>
<string name="quick_settings_brightness_label" msgid="680259653088849563">"Helderheid"</string>
<string name="quick_settings_rotation_unlocked_label" msgid="2359922767950346112">"Automatisch draaien"</string>
diff --git a/packages/SystemUI/res/values-or/strings.xml b/packages/SystemUI/res/values-or/strings.xml
index 029aa69b6fbf..4c6ef486436a 100644
--- a/packages/SystemUI/res/values-or/strings.xml
+++ b/packages/SystemUI/res/values-or/strings.xml
@@ -108,10 +108,8 @@
<string name="screenrecord_resume_label" msgid="4972223043729555575">"ପୁଣି ଚାଲୁ କରନ୍ତୁ"</string>
<string name="screenrecord_cancel_label" msgid="7850926573274483294">"ବାତିଲ୍‌ କରନ୍ତୁ"</string>
<string name="screenrecord_share_label" msgid="5025590804030086930">"ସେୟାର୍‍ କରନ୍ତୁ"</string>
- <string name="screenrecord_delete_label" msgid="1376347010553987058">"ଡିଲିଟ୍ କରନ୍ତୁ"</string>
<string name="screenrecord_cancel_success" msgid="1775448688137393901">"ସ୍କ୍ରିନ୍‍ ରେକର୍ଡିଂ ବାତିଲ୍‌ କରିଦିଆଯାଇଛି"</string>
<string name="screenrecord_save_message" msgid="490522052388998226">"ସ୍କ୍ରିନ୍‍ ରେକର୍ଡିଂ ସେଭ୍‍ ହୋଇଛି, ଦେଖିବାକୁ ଟାପ୍‍ କରନ୍ତୁ"</string>
- <string name="screenrecord_delete_description" msgid="1604522770162810570">"ସ୍କ୍ରିନ୍‍ ରେକର୍ଡିଂ ଡିଲିଟ୍‍ କରିଦିଆଯାଇଛି"</string>
<string name="screenrecord_delete_error" msgid="2870506119743013588">"ସ୍କ୍ରିନ୍‍ ରେକର୍ଡିଂ ଡିଲିଟ୍‍ କରିବାରେ ତ୍ରୁଟି"</string>
<string name="screenrecord_permission_error" msgid="7856841237023137686">"ଅନୁମତି ପାଇବାରେ ଅସଫଳ ହେଲା।"</string>
<string name="screenrecord_start_error" msgid="2200660692479682368">"ସ୍କ୍ରିନ୍ ରେକର୍ଡିଂ ଆରମ୍ଭ କରିବାରେ ତ୍ରୁଟି"</string>
diff --git a/packages/SystemUI/res/values-pa/strings.xml b/packages/SystemUI/res/values-pa/strings.xml
index ed5f40caf7d0..98583c0aedca 100644
--- a/packages/SystemUI/res/values-pa/strings.xml
+++ b/packages/SystemUI/res/values-pa/strings.xml
@@ -108,10 +108,8 @@
<string name="screenrecord_resume_label" msgid="4972223043729555575">"ਮੁੜ-ਚਾਲੂ ਕਰੋ"</string>
<string name="screenrecord_cancel_label" msgid="7850926573274483294">"ਰੱਦ ਕਰੋ"</string>
<string name="screenrecord_share_label" msgid="5025590804030086930">"ਸਾਂਝਾ ਕਰੋ"</string>
- <string name="screenrecord_delete_label" msgid="1376347010553987058">"ਮਿਟਾਓ"</string>
<string name="screenrecord_cancel_success" msgid="1775448688137393901">"ਸਕ੍ਰੀਨ ਦੀ ਰਿਕਾਰਡਿੰਗ ਰੱਦ ਕੀਤੀ ਗਈ"</string>
<string name="screenrecord_save_message" msgid="490522052388998226">"ਸਕ੍ਰੀਨ ਰਿਕਾਰਡਿੰਗ ਰੱਖਿਅਤ ਕੀਤੀ ਗਈ, ਦੇਖਣ ਲਈ ਟੈਪ ਕਰੋ"</string>
- <string name="screenrecord_delete_description" msgid="1604522770162810570">"ਸਕ੍ਰੀਨ ਰਿਕਾਰਡਿੰਗ ਨੂੰ ਮਿਟਾਇਆ ਗਿਆ"</string>
<string name="screenrecord_delete_error" msgid="2870506119743013588">"ਸਕ੍ਰੀਨ ਰਿਕਾਰਡਿੰਗ ਨੂੰ ਮਿਟਾਉਣ ਦੌਰਾਨ ਗੜਬੜ ਹੋਈ"</string>
<string name="screenrecord_permission_error" msgid="7856841237023137686">"ਇਜਾਜ਼ਤਾਂ ਪ੍ਰਾਪਤ ਕਰਨਾ ਅਸਫਲ ਰਿਹਾ"</string>
<string name="screenrecord_start_error" msgid="2200660692479682368">"ਸਕ੍ਰੀਨ ਰਿਕਾਰਡਿੰਗ ਨੂੰ ਸ਼ੁਰੂ ਕਰਨ ਵੇਲੇ ਗੜਬੜ ਹੋਈ"</string>
diff --git a/packages/SystemUI/res/values-pl/strings.xml b/packages/SystemUI/res/values-pl/strings.xml
index ba30cedd9e39..4d5a2ae88949 100644
--- a/packages/SystemUI/res/values-pl/strings.xml
+++ b/packages/SystemUI/res/values-pl/strings.xml
@@ -108,10 +108,8 @@
<string name="screenrecord_resume_label" msgid="4972223043729555575">"Wznów"</string>
<string name="screenrecord_cancel_label" msgid="7850926573274483294">"Anuluj"</string>
<string name="screenrecord_share_label" msgid="5025590804030086930">"Udostępnij"</string>
- <string name="screenrecord_delete_label" msgid="1376347010553987058">"Usuń"</string>
<string name="screenrecord_cancel_success" msgid="1775448688137393901">"Anulowano nagrywanie zawartości ekranu"</string>
<string name="screenrecord_save_message" msgid="490522052388998226">"Zapisano nagranie zawartości ekranu – kliknij, by je obejrzeć"</string>
- <string name="screenrecord_delete_description" msgid="1604522770162810570">"Usunięto nagranie zawartości ekranu"</string>
<string name="screenrecord_delete_error" msgid="2870506119743013588">"Błąd podczas usuwania nagrania zawartości ekranu"</string>
<string name="screenrecord_permission_error" msgid="7856841237023137686">"Nie udało się uzyskać uprawnień"</string>
<string name="screenrecord_start_error" msgid="2200660692479682368">"Błąd podczas rozpoczynania rejestracji zawartości ekranu"</string>
diff --git a/packages/SystemUI/res/values-pt-rBR/strings.xml b/packages/SystemUI/res/values-pt-rBR/strings.xml
index 715b0e45faeb..ef5c9cee6ee4 100644
--- a/packages/SystemUI/res/values-pt-rBR/strings.xml
+++ b/packages/SystemUI/res/values-pt-rBR/strings.xml
@@ -108,10 +108,8 @@
<string name="screenrecord_resume_label" msgid="4972223043729555575">"Retomar"</string>
<string name="screenrecord_cancel_label" msgid="7850926573274483294">"Cancelar"</string>
<string name="screenrecord_share_label" msgid="5025590804030086930">"Compartilhar"</string>
- <string name="screenrecord_delete_label" msgid="1376347010553987058">"Excluir"</string>
<string name="screenrecord_cancel_success" msgid="1775448688137393901">"Gravação de tela cancelada"</string>
<string name="screenrecord_save_message" msgid="490522052388998226">"Gravação de tela salva, toque para ver"</string>
- <string name="screenrecord_delete_description" msgid="1604522770162810570">"Gravação de tela excluída"</string>
<string name="screenrecord_delete_error" msgid="2870506119743013588">"Erro ao excluir a gravação de tela"</string>
<string name="screenrecord_permission_error" msgid="7856841237023137686">"Não foi possível acessar as permissões"</string>
<string name="screenrecord_start_error" msgid="2200660692479682368">"Erro ao iniciar a gravação de tela"</string>
diff --git a/packages/SystemUI/res/values-pt-rPT/strings.xml b/packages/SystemUI/res/values-pt-rPT/strings.xml
index 1a59de496c91..541f12c32e02 100644
--- a/packages/SystemUI/res/values-pt-rPT/strings.xml
+++ b/packages/SystemUI/res/values-pt-rPT/strings.xml
@@ -108,10 +108,8 @@
<string name="screenrecord_resume_label" msgid="4972223043729555575">"Retomar"</string>
<string name="screenrecord_cancel_label" msgid="7850926573274483294">"Cancelar"</string>
<string name="screenrecord_share_label" msgid="5025590804030086930">"Partilhar"</string>
- <string name="screenrecord_delete_label" msgid="1376347010553987058">"Eliminar"</string>
<string name="screenrecord_cancel_success" msgid="1775448688137393901">"Gravação de ecrã cancelada."</string>
<string name="screenrecord_save_message" msgid="490522052388998226">"Gravação de ecrã guardada. Toque para ver."</string>
- <string name="screenrecord_delete_description" msgid="1604522770162810570">"Gravação de ecrã eliminada."</string>
<string name="screenrecord_delete_error" msgid="2870506119743013588">"Erro ao eliminar a gravação de ecrã."</string>
<string name="screenrecord_permission_error" msgid="7856841237023137686">"Falha ao obter as autorizações."</string>
<string name="screenrecord_start_error" msgid="2200660692479682368">"Ocorreu um erro ao iniciar a gravação do ecrã."</string>
diff --git a/packages/SystemUI/res/values-pt/strings.xml b/packages/SystemUI/res/values-pt/strings.xml
index 715b0e45faeb..ef5c9cee6ee4 100644
--- a/packages/SystemUI/res/values-pt/strings.xml
+++ b/packages/SystemUI/res/values-pt/strings.xml
@@ -108,10 +108,8 @@
<string name="screenrecord_resume_label" msgid="4972223043729555575">"Retomar"</string>
<string name="screenrecord_cancel_label" msgid="7850926573274483294">"Cancelar"</string>
<string name="screenrecord_share_label" msgid="5025590804030086930">"Compartilhar"</string>
- <string name="screenrecord_delete_label" msgid="1376347010553987058">"Excluir"</string>
<string name="screenrecord_cancel_success" msgid="1775448688137393901">"Gravação de tela cancelada"</string>
<string name="screenrecord_save_message" msgid="490522052388998226">"Gravação de tela salva, toque para ver"</string>
- <string name="screenrecord_delete_description" msgid="1604522770162810570">"Gravação de tela excluída"</string>
<string name="screenrecord_delete_error" msgid="2870506119743013588">"Erro ao excluir a gravação de tela"</string>
<string name="screenrecord_permission_error" msgid="7856841237023137686">"Não foi possível acessar as permissões"</string>
<string name="screenrecord_start_error" msgid="2200660692479682368">"Erro ao iniciar a gravação de tela"</string>
diff --git a/packages/SystemUI/res/values-ro/strings.xml b/packages/SystemUI/res/values-ro/strings.xml
index cf428a39d4a7..3e2373deb67d 100644
--- a/packages/SystemUI/res/values-ro/strings.xml
+++ b/packages/SystemUI/res/values-ro/strings.xml
@@ -108,10 +108,8 @@
<string name="screenrecord_resume_label" msgid="4972223043729555575">"Reluați"</string>
<string name="screenrecord_cancel_label" msgid="7850926573274483294">"Anulați"</string>
<string name="screenrecord_share_label" msgid="5025590804030086930">"Trimiteți"</string>
- <string name="screenrecord_delete_label" msgid="1376347010553987058">"Ștergeți"</string>
<string name="screenrecord_cancel_success" msgid="1775448688137393901">"Înregistrarea ecranului a fost anulată"</string>
<string name="screenrecord_save_message" msgid="490522052388998226">"Înregistrarea ecranului a fost salvată. Atingeți pentru vizualizare"</string>
- <string name="screenrecord_delete_description" msgid="1604522770162810570">"Înregistrarea ecranului a fost ștearsă."</string>
<string name="screenrecord_delete_error" msgid="2870506119743013588">"Eroare la ștergerea înregistrării ecranului"</string>
<string name="screenrecord_permission_error" msgid="7856841237023137686">"Nu s-au obținut permisiunile"</string>
<string name="screenrecord_start_error" msgid="2200660692479682368">"Eroare la începerea înregistrării ecranului"</string>
diff --git a/packages/SystemUI/res/values-ru/strings.xml b/packages/SystemUI/res/values-ru/strings.xml
index ba86e9501006..7747724eab80 100644
--- a/packages/SystemUI/res/values-ru/strings.xml
+++ b/packages/SystemUI/res/values-ru/strings.xml
@@ -108,10 +108,8 @@
<string name="screenrecord_resume_label" msgid="4972223043729555575">"Возобновить"</string>
<string name="screenrecord_cancel_label" msgid="7850926573274483294">"Отмена"</string>
<string name="screenrecord_share_label" msgid="5025590804030086930">"Поделиться"</string>
- <string name="screenrecord_delete_label" msgid="1376347010553987058">"Удалить"</string>
<string name="screenrecord_cancel_success" msgid="1775448688137393901">"Запись видео с экрана отменена"</string>
<string name="screenrecord_save_message" msgid="490522052388998226">"Запись видео с экрана сохранена. Чтобы открыть ее, нажмите на уведомление."</string>
- <string name="screenrecord_delete_description" msgid="1604522770162810570">"Запись видео с экрана удалена"</string>
<string name="screenrecord_delete_error" msgid="2870506119743013588">"Не удалось удалить запись видео с экрана"</string>
<string name="screenrecord_permission_error" msgid="7856841237023137686">"Не удалось получить необходимые разрешения"</string>
<string name="screenrecord_start_error" msgid="2200660692479682368">"Не удалось начать запись видео с экрана."</string>
diff --git a/packages/SystemUI/res/values-si/strings.xml b/packages/SystemUI/res/values-si/strings.xml
index 1cd1ceb21c97..b8813f2ef53c 100644
--- a/packages/SystemUI/res/values-si/strings.xml
+++ b/packages/SystemUI/res/values-si/strings.xml
@@ -108,10 +108,8 @@
<string name="screenrecord_resume_label" msgid="4972223043729555575">"නැවත අරඹන්න"</string>
<string name="screenrecord_cancel_label" msgid="7850926573274483294">"අවලංගු කරන්න"</string>
<string name="screenrecord_share_label" msgid="5025590804030086930">"බෙදා ගන්න"</string>
- <string name="screenrecord_delete_label" msgid="1376347010553987058">"මකන්න"</string>
<string name="screenrecord_cancel_success" msgid="1775448688137393901">"තිර පටිගත කිරීම අවලංගු කරන ලදී"</string>
<string name="screenrecord_save_message" msgid="490522052388998226">"තිර පටිගත කිරීම සුරකින ලදී, බැලීමට තට්ටු කරන්න"</string>
- <string name="screenrecord_delete_description" msgid="1604522770162810570">"තිර පටිගත කිරීම මකන ලදී"</string>
<string name="screenrecord_delete_error" msgid="2870506119743013588">"තිර පටිගත කිරීම මැකීමේ දෝෂයකි"</string>
<string name="screenrecord_permission_error" msgid="7856841237023137686">"අවසර ලබා ගැනීමට අසමත් විය"</string>
<string name="screenrecord_start_error" msgid="2200660692479682368">"තිර පටිගත කිරීම ආරම්භ කිරීමේ දෝෂයකි"</string>
diff --git a/packages/SystemUI/res/values-sk/strings.xml b/packages/SystemUI/res/values-sk/strings.xml
index 75486073fd5e..0f9cb5f4616c 100644
--- a/packages/SystemUI/res/values-sk/strings.xml
+++ b/packages/SystemUI/res/values-sk/strings.xml
@@ -108,10 +108,8 @@
<string name="screenrecord_resume_label" msgid="4972223043729555575">"Obnoviť"</string>
<string name="screenrecord_cancel_label" msgid="7850926573274483294">"Zrušiť"</string>
<string name="screenrecord_share_label" msgid="5025590804030086930">"Zdieľať"</string>
- <string name="screenrecord_delete_label" msgid="1376347010553987058">"Odstrániť"</string>
<string name="screenrecord_cancel_success" msgid="1775448688137393901">"Záznam obrazovky bol zrušený"</string>
<string name="screenrecord_save_message" msgid="490522052388998226">"Záznam obrazovky bol uložený, zobrazíte ho klepnutím"</string>
- <string name="screenrecord_delete_description" msgid="1604522770162810570">"Záznam obrazovky bol odstránený"</string>
<string name="screenrecord_delete_error" msgid="2870506119743013588">"Pri odstraňovaní záznamu obrazovky sa vyskytla chyba"</string>
<string name="screenrecord_permission_error" msgid="7856841237023137686">"Nepodarilo sa získať povolenia"</string>
<string name="screenrecord_start_error" msgid="2200660692479682368">"Pri spustení nahrávania obrazovky sa vyskytla chyba"</string>
diff --git a/packages/SystemUI/res/values-sl/strings.xml b/packages/SystemUI/res/values-sl/strings.xml
index 07ad8c1ca99e..18db332b63ec 100644
--- a/packages/SystemUI/res/values-sl/strings.xml
+++ b/packages/SystemUI/res/values-sl/strings.xml
@@ -108,10 +108,8 @@
<string name="screenrecord_resume_label" msgid="4972223043729555575">"Nadaljuj"</string>
<string name="screenrecord_cancel_label" msgid="7850926573274483294">"Prekliči"</string>
<string name="screenrecord_share_label" msgid="5025590804030086930">"Deli"</string>
- <string name="screenrecord_delete_label" msgid="1376347010553987058">"Izbriši"</string>
<string name="screenrecord_cancel_success" msgid="1775448688137393901">"Snemanje zaslona je preklicano"</string>
<string name="screenrecord_save_message" msgid="490522052388998226">"Videoposnetek zaslona je shranjen, dotaknite se za ogled"</string>
- <string name="screenrecord_delete_description" msgid="1604522770162810570">"Videoposnetek zaslona je izbrisan"</string>
<string name="screenrecord_delete_error" msgid="2870506119743013588">"Napaka pri brisanju videoposnetka zaslona"</string>
<string name="screenrecord_permission_error" msgid="7856841237023137686">"Dovoljenj ni bilo mogoče pridobiti"</string>
<string name="screenrecord_start_error" msgid="2200660692479682368">"Napaka pri začenjanju snemanja zaslona"</string>
diff --git a/packages/SystemUI/res/values-sq/strings.xml b/packages/SystemUI/res/values-sq/strings.xml
index b92744d7f087..57ab1c384ca9 100644
--- a/packages/SystemUI/res/values-sq/strings.xml
+++ b/packages/SystemUI/res/values-sq/strings.xml
@@ -108,15 +108,13 @@
<string name="screenrecord_resume_label" msgid="4972223043729555575">"Vazhdo"</string>
<string name="screenrecord_cancel_label" msgid="7850926573274483294">"Anulo"</string>
<string name="screenrecord_share_label" msgid="5025590804030086930">"Ndaj"</string>
- <string name="screenrecord_delete_label" msgid="1376347010553987058">"Fshi"</string>
<string name="screenrecord_cancel_success" msgid="1775448688137393901">"Regjistrimi i ekranit u anulua"</string>
<string name="screenrecord_save_message" msgid="490522052388998226">"Regjistrimi i ekranit u ruajt, trokit për ta parë"</string>
- <string name="screenrecord_delete_description" msgid="1604522770162810570">"Regjistrimi i ekranit u fshi"</string>
<string name="screenrecord_delete_error" msgid="2870506119743013588">"Gabim gjatë fshirjes së regjistrimit të ekranit"</string>
<string name="screenrecord_permission_error" msgid="7856841237023137686">"Marrja e lejeve dështoi"</string>
<string name="screenrecord_start_error" msgid="2200660692479682368">"Gabim gjatë nisjes së regjistrimit të ekranit"</string>
<string name="usb_preference_title" msgid="1439924437558480718">"Opsionet e transferimit të dosjeve të USB-së"</string>
- <string name="use_mtp_button_title" msgid="5036082897886518086">"Lidh si një lexues \"media\" (MTP)"</string>
+ <string name="use_mtp_button_title" msgid="5036082897886518086">"Lidh si një luajtës të medias (MTP)"</string>
<string name="use_ptp_button_title" msgid="7676427598943446826">"Montoje si kamerë (PTP)"</string>
<string name="installer_cd_button_title" msgid="5499998592841984743">"Instalo \"Transferimi i skedarëve të Android\" për Mac"</string>
<string name="accessibility_back" msgid="6530104400086152611">"Prapa"</string>
diff --git a/packages/SystemUI/res/values-sr/strings.xml b/packages/SystemUI/res/values-sr/strings.xml
index f57d92bb911e..ec763f675d4c 100644
--- a/packages/SystemUI/res/values-sr/strings.xml
+++ b/packages/SystemUI/res/values-sr/strings.xml
@@ -108,10 +108,8 @@
<string name="screenrecord_resume_label" msgid="4972223043729555575">"Настави"</string>
<string name="screenrecord_cancel_label" msgid="7850926573274483294">"Откажи"</string>
<string name="screenrecord_share_label" msgid="5025590804030086930">"Дели"</string>
- <string name="screenrecord_delete_label" msgid="1376347010553987058">"Избриши"</string>
<string name="screenrecord_cancel_success" msgid="1775448688137393901">"Снимање екрана је отказано"</string>
<string name="screenrecord_save_message" msgid="490522052388998226">"Снимак екрана је сачуван, додирните да бисте прегледали"</string>
- <string name="screenrecord_delete_description" msgid="1604522770162810570">"Снимак екрана је избрисан"</string>
<string name="screenrecord_delete_error" msgid="2870506119743013588">"Дошло је до проблема при брисању снимка екрана"</string>
<string name="screenrecord_permission_error" msgid="7856841237023137686">"Преузимање дозвола није успело"</string>
<string name="screenrecord_start_error" msgid="2200660692479682368">"Грешка при покретању снимања екрана"</string>
diff --git a/packages/SystemUI/res/values-sv/strings.xml b/packages/SystemUI/res/values-sv/strings.xml
index 876e3377171c..a0a563d81d46 100644
--- a/packages/SystemUI/res/values-sv/strings.xml
+++ b/packages/SystemUI/res/values-sv/strings.xml
@@ -108,10 +108,8 @@
<string name="screenrecord_resume_label" msgid="4972223043729555575">"Återuppta"</string>
<string name="screenrecord_cancel_label" msgid="7850926573274483294">"Avbryt"</string>
<string name="screenrecord_share_label" msgid="5025590804030086930">"Dela"</string>
- <string name="screenrecord_delete_label" msgid="1376347010553987058">"Radera"</string>
<string name="screenrecord_cancel_success" msgid="1775448688137393901">"Skärminspelningen har avbrutits"</string>
<string name="screenrecord_save_message" msgid="490522052388998226">"Skärminspelningen har sparats, tryck här om du vill titta på den"</string>
- <string name="screenrecord_delete_description" msgid="1604522770162810570">"Skärminspelningen har raderats"</string>
<string name="screenrecord_delete_error" msgid="2870506119743013588">"Det gick inte att radera skärminspelningen"</string>
<string name="screenrecord_permission_error" msgid="7856841237023137686">"Behörighet saknas"</string>
<string name="screenrecord_start_error" msgid="2200660692479682368">"Det gick inte att starta skärminspelningen"</string>
diff --git a/packages/SystemUI/res/values-sw/strings.xml b/packages/SystemUI/res/values-sw/strings.xml
index 25e349367b52..7e264a4a312a 100644
--- a/packages/SystemUI/res/values-sw/strings.xml
+++ b/packages/SystemUI/res/values-sw/strings.xml
@@ -108,10 +108,8 @@
<string name="screenrecord_resume_label" msgid="4972223043729555575">"Endelea"</string>
<string name="screenrecord_cancel_label" msgid="7850926573274483294">"Ghairi"</string>
<string name="screenrecord_share_label" msgid="5025590804030086930">"Shiriki"</string>
- <string name="screenrecord_delete_label" msgid="1376347010553987058">"Futa"</string>
<string name="screenrecord_cancel_success" msgid="1775448688137393901">"Imeghairi mchakato wa kurekodi skrini"</string>
<string name="screenrecord_save_message" msgid="490522052388998226">"Imehifadhi rekodi ya skrini, gusa ili uangalie"</string>
- <string name="screenrecord_delete_description" msgid="1604522770162810570">"Imefuta rekodi ya skrini"</string>
<string name="screenrecord_delete_error" msgid="2870506119743013588">"Hitilafu imetokea wakati wa kufuta rekodi ya skrini"</string>
<string name="screenrecord_permission_error" msgid="7856841237023137686">"Imeshindwa kupata ruhusa"</string>
<string name="screenrecord_start_error" msgid="2200660692479682368">"Hitilafu imetokea wakati wa kuanza kurekodi skrini"</string>
diff --git a/packages/SystemUI/res/values-sw600dp/config.xml b/packages/SystemUI/res/values-sw600dp/config.xml
index 5d20564a3ab8..be66320975d9 100644
--- a/packages/SystemUI/res/values-sw600dp/config.xml
+++ b/packages/SystemUI/res/values-sw600dp/config.xml
@@ -29,9 +29,6 @@
<!-- Nav bar button default ordering/layout -->
<string name="config_navBarLayout" translatable="false">left;back,home,recent;right</string>
- <!-- Animation duration when using long press on recents to dock -->
- <integer name="long_press_dock_anim_duration">290</integer>
-
<!-- orientation of the dead zone when touches have recently occurred elsewhere on screen -->
<integer name="navigation_bar_deadzone_orientation">0</integer>
diff --git a/packages/SystemUI/res/values-ta/strings.xml b/packages/SystemUI/res/values-ta/strings.xml
index 19e67db62de8..e0f20ceea353 100644
--- a/packages/SystemUI/res/values-ta/strings.xml
+++ b/packages/SystemUI/res/values-ta/strings.xml
@@ -108,10 +108,8 @@
<string name="screenrecord_resume_label" msgid="4972223043729555575">"மீண்டும் தொடங்கு"</string>
<string name="screenrecord_cancel_label" msgid="7850926573274483294">"ரத்துசெய்"</string>
<string name="screenrecord_share_label" msgid="5025590804030086930">"பகிர்"</string>
- <string name="screenrecord_delete_label" msgid="1376347010553987058">"நீக்கு"</string>
<string name="screenrecord_cancel_success" msgid="1775448688137393901">"திரை ரெக்கார்டிங் ரத்துசெய்யப்பட்டது"</string>
<string name="screenrecord_save_message" msgid="490522052388998226">"திரை ரெக்கார்டிங் சேமிக்கப்பட்டது, பார்க்கத் தட்டவும்"</string>
- <string name="screenrecord_delete_description" msgid="1604522770162810570">"திரை ரெக்கார்டிங் நீக்கப்பட்டது"</string>
<string name="screenrecord_delete_error" msgid="2870506119743013588">"திரை ரெக்கார்டிங்கை நீக்குவதில் பிழை"</string>
<string name="screenrecord_permission_error" msgid="7856841237023137686">"அனுமதிகளைப் பெற இயலவில்லை"</string>
<string name="screenrecord_start_error" msgid="2200660692479682368">"ஸ்கிரீன் ரெக்கார்டிங்கைத் தொடங்குவதில் பிழை"</string>
diff --git a/packages/SystemUI/res/values-te/strings.xml b/packages/SystemUI/res/values-te/strings.xml
index 34ff9b102da0..3e94b72b02fe 100644
--- a/packages/SystemUI/res/values-te/strings.xml
+++ b/packages/SystemUI/res/values-te/strings.xml
@@ -108,10 +108,8 @@
<string name="screenrecord_resume_label" msgid="4972223043729555575">"కొనసాగించు"</string>
<string name="screenrecord_cancel_label" msgid="7850926573274483294">"రద్దు చేయి"</string>
<string name="screenrecord_share_label" msgid="5025590804030086930">"షేర్ చేయి"</string>
- <string name="screenrecord_delete_label" msgid="1376347010553987058">"తొలగించు"</string>
<string name="screenrecord_cancel_success" msgid="1775448688137393901">"స్క్రీన్ రికార్డ్ రద్దు చేయబడింది"</string>
<string name="screenrecord_save_message" msgid="490522052388998226">"స్క్రీన్ రికార్డింగ్ సేవ్ చేయబడింది, చూడటం కోసం నొక్కండి"</string>
- <string name="screenrecord_delete_description" msgid="1604522770162810570">"స్క్రీన్ రికార్డింగ్ తొలగించబడింది"</string>
<string name="screenrecord_delete_error" msgid="2870506119743013588">"స్క్రీన్ రికార్డింగ్‌ని తొలగిస్తున్నప్పుడు ఎర్రర్ ఏర్పడింది"</string>
<string name="screenrecord_permission_error" msgid="7856841237023137686">"అనుమతులను పొందడం విఫలమైంది"</string>
<string name="screenrecord_start_error" msgid="2200660692479682368">"స్క్రీన్ రికార్డింగ్ ప్రారంభించడంలో ఎర్రర్ ఏర్పడింది"</string>
diff --git a/packages/SystemUI/res/values-television/config.xml b/packages/SystemUI/res/values-television/config.xml
index b2d057b4bcd8..66304013da46 100644
--- a/packages/SystemUI/res/values-television/config.xml
+++ b/packages/SystemUI/res/values-television/config.xml
@@ -33,14 +33,12 @@
<item>com.android.systemui.power.PowerUI</item>
<item>com.android.systemui.media.RingtonePlayer</item>
<item>com.android.systemui.keyboard.KeyboardUI</item>
- <item>com.android.systemui.pip.PipUI</item>
<item>com.android.systemui.shortcut.ShortcutKeyDispatcher</item>
<item>@string/config_systemUIVendorServiceComponent</item>
<item>com.android.systemui.SliceBroadcastRelayHandler</item>
<item>com.android.systemui.SizeCompatModeActivityController</item>
<item>com.android.systemui.statusbar.notification.InstantAppNotifier</item>
<item>com.android.systemui.toast.ToastUI</item>
- <item>com.android.systemui.onehanded.OneHandedUI</item>
<item>com.android.systemui.wmshell.WMShell</item>
</string-array>
diff --git a/packages/SystemUI/res/values-television/integers.xml b/packages/SystemUI/res/values-television/integers.xml
index 91e83ccbbe79..587497edfdfb 100644
--- a/packages/SystemUI/res/values-television/integers.xml
+++ b/packages/SystemUI/res/values-television/integers.xml
@@ -17,6 +17,7 @@
<resources>
<!-- The position of the volume dialog on the screen.
See com.android.systemui.volume.VolumeDialogImpl.
- Value 81 corresponds to BOTTOM|CENTER_HORIZONTAL. -->
- <integer name="volume_dialog_gravity">81</integer>
-</resources> \ No newline at end of file
+ Value 81 corresponds to BOTTOM|CENTER_HORIZONTAL.
+ Value 21 corresponds to RIGHT|CENTER_VERTICAL. -->
+ <integer name="volume_dialog_gravity">21</integer>
+</resources>
diff --git a/packages/SystemUI/res/values-th/strings.xml b/packages/SystemUI/res/values-th/strings.xml
index d37be57e0136..088b62421b92 100644
--- a/packages/SystemUI/res/values-th/strings.xml
+++ b/packages/SystemUI/res/values-th/strings.xml
@@ -108,10 +108,8 @@
<string name="screenrecord_resume_label" msgid="4972223043729555575">"ทำต่อ"</string>
<string name="screenrecord_cancel_label" msgid="7850926573274483294">"ยกเลิก"</string>
<string name="screenrecord_share_label" msgid="5025590804030086930">"แชร์"</string>
- <string name="screenrecord_delete_label" msgid="1376347010553987058">"ลบ"</string>
<string name="screenrecord_cancel_success" msgid="1775448688137393901">"ยกเลิกการบันทึกหน้าจอแล้ว"</string>
<string name="screenrecord_save_message" msgid="490522052388998226">"บันทึกการบันทึกหน้าจอแล้ว แตะเพื่อดู"</string>
- <string name="screenrecord_delete_description" msgid="1604522770162810570">"ลบการบันทึกหน้าจอแล้ว"</string>
<string name="screenrecord_delete_error" msgid="2870506119743013588">"เกิดข้อผิดพลาดในการลบการบันทึกหน้าจอ"</string>
<string name="screenrecord_permission_error" msgid="7856841237023137686">"ขอสิทธิ์ไม่สำเร็จ"</string>
<string name="screenrecord_start_error" msgid="2200660692479682368">"เกิดข้อผิดพลาดขณะเริ่มบันทึกหน้าจอ"</string>
diff --git a/packages/SystemUI/res/values-tl/strings.xml b/packages/SystemUI/res/values-tl/strings.xml
index af474c761fc5..e787b17417bb 100644
--- a/packages/SystemUI/res/values-tl/strings.xml
+++ b/packages/SystemUI/res/values-tl/strings.xml
@@ -108,10 +108,8 @@
<string name="screenrecord_resume_label" msgid="4972223043729555575">"Ituloy"</string>
<string name="screenrecord_cancel_label" msgid="7850926573274483294">"Kanselahin"</string>
<string name="screenrecord_share_label" msgid="5025590804030086930">"Ibahagi"</string>
- <string name="screenrecord_delete_label" msgid="1376347010553987058">"I-delete"</string>
<string name="screenrecord_cancel_success" msgid="1775448688137393901">"Kinansela ang pag-record ng screen"</string>
<string name="screenrecord_save_message" msgid="490522052388998226">"Na-save ang pag-record ng screen, i-tap para tingnan"</string>
- <string name="screenrecord_delete_description" msgid="1604522770162810570">"Na-delete ang pag-record ng screen"</string>
<string name="screenrecord_delete_error" msgid="2870506119743013588">"Error sa pag-delete sa pag-record ng screen"</string>
<string name="screenrecord_permission_error" msgid="7856841237023137686">"Hindi nakuha ang mga pahintulot"</string>
<string name="screenrecord_start_error" msgid="2200660692479682368">"Nagkaroon ng error sa pagsisimula ng pag-record ng screen"</string>
diff --git a/packages/SystemUI/res/values-tr/strings.xml b/packages/SystemUI/res/values-tr/strings.xml
index ee494a25e366..e33944517393 100644
--- a/packages/SystemUI/res/values-tr/strings.xml
+++ b/packages/SystemUI/res/values-tr/strings.xml
@@ -108,10 +108,8 @@
<string name="screenrecord_resume_label" msgid="4972223043729555575">"Devam ettir"</string>
<string name="screenrecord_cancel_label" msgid="7850926573274483294">"İptal"</string>
<string name="screenrecord_share_label" msgid="5025590804030086930">"Paylaş"</string>
- <string name="screenrecord_delete_label" msgid="1376347010553987058">"Sil"</string>
<string name="screenrecord_cancel_success" msgid="1775448688137393901">"Ekran kaydı iptal edildi"</string>
<string name="screenrecord_save_message" msgid="490522052388998226">"Ekran kaydı tamamlandı, görüntülemek için dokunun"</string>
- <string name="screenrecord_delete_description" msgid="1604522770162810570">"Ekran kaydı silindi"</string>
<string name="screenrecord_delete_error" msgid="2870506119743013588">"Ekran kaydı silinirken hata oluştu"</string>
<string name="screenrecord_permission_error" msgid="7856841237023137686">"İzinler alınamadı"</string>
<string name="screenrecord_start_error" msgid="2200660692479682368">"Ekran kaydı başlatılırken hata oluştu"</string>
diff --git a/packages/SystemUI/res/values-uk/strings.xml b/packages/SystemUI/res/values-uk/strings.xml
index c444c47d1441..f5419f1d1290 100644
--- a/packages/SystemUI/res/values-uk/strings.xml
+++ b/packages/SystemUI/res/values-uk/strings.xml
@@ -108,10 +108,8 @@
<string name="screenrecord_resume_label" msgid="4972223043729555575">"Відновити"</string>
<string name="screenrecord_cancel_label" msgid="7850926573274483294">"Скасувати"</string>
<string name="screenrecord_share_label" msgid="5025590804030086930">"Поділитися"</string>
- <string name="screenrecord_delete_label" msgid="1376347010553987058">"Видалити"</string>
<string name="screenrecord_cancel_success" msgid="1775448688137393901">"Запис екрана скасовано"</string>
<string name="screenrecord_save_message" msgid="490522052388998226">"Запис екрана збережено. Натисніть, щоб переглянути"</string>
- <string name="screenrecord_delete_description" msgid="1604522770162810570">"Запис екрана видалено"</string>
<string name="screenrecord_delete_error" msgid="2870506119743013588">"Не вдалося видалити запис екрана"</string>
<string name="screenrecord_permission_error" msgid="7856841237023137686">"Не вдалось отримати дозволи"</string>
<string name="screenrecord_start_error" msgid="2200660692479682368">"Не вдалося почати запис екрана"</string>
diff --git a/packages/SystemUI/res/values-ur/strings.xml b/packages/SystemUI/res/values-ur/strings.xml
index 729ed5a3ac51..2abf3500ff4a 100644
--- a/packages/SystemUI/res/values-ur/strings.xml
+++ b/packages/SystemUI/res/values-ur/strings.xml
@@ -108,10 +108,8 @@
<string name="screenrecord_resume_label" msgid="4972223043729555575">"دوبارہ شروع کریں"</string>
<string name="screenrecord_cancel_label" msgid="7850926573274483294">"منسوخ کریں"</string>
<string name="screenrecord_share_label" msgid="5025590804030086930">"اشتراک کریں"</string>
- <string name="screenrecord_delete_label" msgid="1376347010553987058">"حذف کریں"</string>
<string name="screenrecord_cancel_success" msgid="1775448688137393901">"اسکرین ریکارڈنگ منسوخ ہو گئی"</string>
<string name="screenrecord_save_message" msgid="490522052388998226">"اسکرین ریکارڈنگ محفوظ ہو گئی، دیکھنے کیلئے تھپتھپائیں"</string>
- <string name="screenrecord_delete_description" msgid="1604522770162810570">"اسکرین ریکارڈنگ حذف ہو گئی"</string>
<string name="screenrecord_delete_error" msgid="2870506119743013588">"اسکرین ریکارڈنگ کو حذف کرنے میں خرابی"</string>
<string name="screenrecord_permission_error" msgid="7856841237023137686">"اجازتیں حاصل کرنے میں ناکامی"</string>
<string name="screenrecord_start_error" msgid="2200660692479682368">"اسکرین ریکارڈنگ شروع کرنے میں خرابی"</string>
diff --git a/packages/SystemUI/res/values-uz/strings.xml b/packages/SystemUI/res/values-uz/strings.xml
index cf1da7508052..61b10a4ed24c 100644
--- a/packages/SystemUI/res/values-uz/strings.xml
+++ b/packages/SystemUI/res/values-uz/strings.xml
@@ -108,10 +108,8 @@
<string name="screenrecord_resume_label" msgid="4972223043729555575">"Davom etish"</string>
<string name="screenrecord_cancel_label" msgid="7850926573274483294">"Bekor qilish"</string>
<string name="screenrecord_share_label" msgid="5025590804030086930">"Ulashish"</string>
- <string name="screenrecord_delete_label" msgid="1376347010553987058">"O‘chirish"</string>
<string name="screenrecord_cancel_success" msgid="1775448688137393901">"Ekrandan yozib olish bekor qilindi"</string>
<string name="screenrecord_save_message" msgid="490522052388998226">"Ekrandan yozib olingan video saqlandi. Uni ochish uchun bildirishnomani bosing."</string>
- <string name="screenrecord_delete_description" msgid="1604522770162810570">"Ekrandan yozib olingan video o‘chirib tashlandi"</string>
<string name="screenrecord_delete_error" msgid="2870506119743013588">"Ekrandan yozib olingan vi olib tashlanmadi"</string>
<string name="screenrecord_permission_error" msgid="7856841237023137686">"Zarur ruxsatlar olinmadi"</string>
<string name="screenrecord_start_error" msgid="2200660692479682368">"Ekranni yozib olish boshlanmadi"</string>
@@ -362,7 +360,7 @@
<string name="accessibility_quick_settings_rotation_value" msgid="2916484894750819251">"<xliff:g id="ID_1">%s</xliff:g> rejimi"</string>
<string name="quick_settings_rotation_locked_label" msgid="4420863550666310319">"Aylanmaydigan qilingan"</string>
<string name="quick_settings_rotation_locked_portrait_label" msgid="1194988975270484482">"Tik holat"</string>
- <string name="quick_settings_rotation_locked_landscape_label" msgid="2000295772687238645">"Eniga"</string>
+ <string name="quick_settings_rotation_locked_landscape_label" msgid="2000295772687238645">"Yotiq"</string>
<string name="quick_settings_ime_label" msgid="3351174938144332051">"Kiritish usuli"</string>
<string name="quick_settings_location_label" msgid="2621868789013389163">"Joylashuv"</string>
<string name="quick_settings_location_off_label" msgid="7923929131443915919">"Joylashuvni aniqlash xizmati yoqilmagan"</string>
diff --git a/packages/SystemUI/res/values-vi/strings.xml b/packages/SystemUI/res/values-vi/strings.xml
index 5794bdf3c8eb..6107270f10c5 100644
--- a/packages/SystemUI/res/values-vi/strings.xml
+++ b/packages/SystemUI/res/values-vi/strings.xml
@@ -108,10 +108,8 @@
<string name="screenrecord_resume_label" msgid="4972223043729555575">"Tiếp tục"</string>
<string name="screenrecord_cancel_label" msgid="7850926573274483294">"Hủy"</string>
<string name="screenrecord_share_label" msgid="5025590804030086930">"Chia sẻ"</string>
- <string name="screenrecord_delete_label" msgid="1376347010553987058">"Xóa"</string>
<string name="screenrecord_cancel_success" msgid="1775448688137393901">"Đã hủy bản ghi màn hình"</string>
<string name="screenrecord_save_message" msgid="490522052388998226">"Đã lưu bản ghi màn hình, nhấn để xem"</string>
- <string name="screenrecord_delete_description" msgid="1604522770162810570">"Đã xóa bản ghi màn hình"</string>
<string name="screenrecord_delete_error" msgid="2870506119743013588">"Lỗi khi xóa bản ghi màn hình"</string>
<string name="screenrecord_permission_error" msgid="7856841237023137686">"Không được cấp đủ quyền"</string>
<string name="screenrecord_start_error" msgid="2200660692479682368">"Lỗi khi bắt đầu ghi màn hình"</string>
diff --git a/packages/SystemUI/res/values-zh-rCN/strings.xml b/packages/SystemUI/res/values-zh-rCN/strings.xml
index 41c132c9faf6..ffd19956f471 100644
--- a/packages/SystemUI/res/values-zh-rCN/strings.xml
+++ b/packages/SystemUI/res/values-zh-rCN/strings.xml
@@ -108,10 +108,8 @@
<string name="screenrecord_resume_label" msgid="4972223043729555575">"继续"</string>
<string name="screenrecord_cancel_label" msgid="7850926573274483294">"取消"</string>
<string name="screenrecord_share_label" msgid="5025590804030086930">"分享"</string>
- <string name="screenrecord_delete_label" msgid="1376347010553987058">"删除"</string>
<string name="screenrecord_cancel_success" msgid="1775448688137393901">"已取消录制屏幕"</string>
<string name="screenrecord_save_message" msgid="490522052388998226">"屏幕录制内容已保存,点按即可查看"</string>
- <string name="screenrecord_delete_description" msgid="1604522770162810570">"已删除屏幕录制内容"</string>
<string name="screenrecord_delete_error" msgid="2870506119743013588">"删除屏幕录制内容时出错"</string>
<string name="screenrecord_permission_error" msgid="7856841237023137686">"无法获取权限"</string>
<string name="screenrecord_start_error" msgid="2200660692479682368">"启动屏幕录制时出错"</string>
diff --git a/packages/SystemUI/res/values-zh-rHK/strings.xml b/packages/SystemUI/res/values-zh-rHK/strings.xml
index b2e1b90de007..1575427f155b 100644
--- a/packages/SystemUI/res/values-zh-rHK/strings.xml
+++ b/packages/SystemUI/res/values-zh-rHK/strings.xml
@@ -108,10 +108,8 @@
<string name="screenrecord_resume_label" msgid="4972223043729555575">"繼續"</string>
<string name="screenrecord_cancel_label" msgid="7850926573274483294">"取消"</string>
<string name="screenrecord_share_label" msgid="5025590804030086930">"分享"</string>
- <string name="screenrecord_delete_label" msgid="1376347010553987058">"刪除"</string>
<string name="screenrecord_cancel_success" msgid="1775448688137393901">"已取消錄影畫面"</string>
<string name="screenrecord_save_message" msgid="490522052388998226">"已儲存錄影畫面,輕按即可查看"</string>
- <string name="screenrecord_delete_description" msgid="1604522770162810570">"已刪除錄影畫面"</string>
<string name="screenrecord_delete_error" msgid="2870506119743013588">"刪除錄影畫面時發生錯誤"</string>
<string name="screenrecord_permission_error" msgid="7856841237023137686">"無法獲得權限"</string>
<string name="screenrecord_start_error" msgid="2200660692479682368">"開始錄影畫面時發生錯誤"</string>
diff --git a/packages/SystemUI/res/values-zh-rTW/strings.xml b/packages/SystemUI/res/values-zh-rTW/strings.xml
index 346b1239cf0f..bbd83551c0f9 100644
--- a/packages/SystemUI/res/values-zh-rTW/strings.xml
+++ b/packages/SystemUI/res/values-zh-rTW/strings.xml
@@ -108,10 +108,8 @@
<string name="screenrecord_resume_label" msgid="4972223043729555575">"繼續"</string>
<string name="screenrecord_cancel_label" msgid="7850926573274483294">"取消"</string>
<string name="screenrecord_share_label" msgid="5025590804030086930">"分享"</string>
- <string name="screenrecord_delete_label" msgid="1376347010553987058">"刪除"</string>
<string name="screenrecord_cancel_success" msgid="1775448688137393901">"已取消錄製螢幕畫面"</string>
<string name="screenrecord_save_message" msgid="490522052388998226">"已儲存螢幕畫面錄製內容,輕觸即可查看"</string>
- <string name="screenrecord_delete_description" msgid="1604522770162810570">"已刪除螢幕畫面錄製內容"</string>
<string name="screenrecord_delete_error" msgid="2870506119743013588">"刪除螢幕畫面錄製內容時發生錯誤"</string>
<string name="screenrecord_permission_error" msgid="7856841237023137686">"無法取得權限"</string>
<string name="screenrecord_start_error" msgid="2200660692479682368">"開始錄製螢幕畫面時發生錯誤"</string>
diff --git a/packages/SystemUI/res/values-zu/strings.xml b/packages/SystemUI/res/values-zu/strings.xml
index 5abce7fb4415..63b4c613a06a 100644
--- a/packages/SystemUI/res/values-zu/strings.xml
+++ b/packages/SystemUI/res/values-zu/strings.xml
@@ -108,10 +108,8 @@
<string name="screenrecord_resume_label" msgid="4972223043729555575">"Qalisa kabusha"</string>
<string name="screenrecord_cancel_label" msgid="7850926573274483294">"Khansela"</string>
<string name="screenrecord_share_label" msgid="5025590804030086930">"Yabelana"</string>
- <string name="screenrecord_delete_label" msgid="1376347010553987058">"Susa"</string>
<string name="screenrecord_cancel_success" msgid="1775448688137393901">"Ukurekhoda isikrini kukhanseliwe"</string>
<string name="screenrecord_save_message" msgid="490522052388998226">"Ukurekhoda isikrini kulondoloziwe, thepha ukuze ubuke"</string>
- <string name="screenrecord_delete_description" msgid="1604522770162810570">"Ukurekhoda isikrini kususiwe"</string>
<string name="screenrecord_delete_error" msgid="2870506119743013588">"Iphutha lokususa ukurekhoda isikrini"</string>
<string name="screenrecord_permission_error" msgid="7856841237023137686">"Yehlulekile ukuthola izimvume"</string>
<string name="screenrecord_start_error" msgid="2200660692479682368">"Iphutha lokuqala ukurekhoda isikrini"</string>
diff --git a/packages/SystemUI/res/values/config.xml b/packages/SystemUI/res/values/config.xml
index 130bb4fc90b9..1c3fba2abacd 100644
--- a/packages/SystemUI/res/values/config.xml
+++ b/packages/SystemUI/res/values/config.xml
@@ -161,9 +161,6 @@
<!-- The number of milliseconds to extend ambient pulse by when prompted (e.g. on touch) -->
<integer name="ambient_notification_extension_time">10000</integer>
- <!-- Animation duration when using long press on recents to dock -->
- <integer name="long_press_dock_anim_duration">250</integer>
-
<!-- Whether to enable KeyguardService or not -->
<bool name="config_enableKeyguardService">true</bool>
@@ -306,7 +303,6 @@
<item>com.android.systemui.power.PowerUI</item>
<item>com.android.systemui.media.RingtonePlayer</item>
<item>com.android.systemui.keyboard.KeyboardUI</item>
- <item>com.android.systemui.pip.PipUI</item>
<item>com.android.systemui.shortcut.ShortcutKeyDispatcher</item>
<item>@string/config_systemUIVendorServiceComponent</item>
<item>com.android.systemui.util.leak.GarbageMonitor$Service</item>
@@ -321,7 +317,6 @@
<item>com.android.systemui.accessibility.WindowMagnification</item>
<item>com.android.systemui.accessibility.SystemActions</item>
<item>com.android.systemui.toast.ToastUI</item>
- <item>com.android.systemui.onehanded.OneHandedUI</item>
<item>com.android.systemui.wmshell.WMShell</item>
</string-array>
diff --git a/packages/SystemUI/res/values/dimens.xml b/packages/SystemUI/res/values/dimens.xml
index d12f0103238d..76c61fb6e1e5 100644
--- a/packages/SystemUI/res/values/dimens.xml
+++ b/packages/SystemUI/res/values/dimens.xml
@@ -954,12 +954,6 @@
<dimen name="fab_elevation">12dp</dimen>
<dimen name="fab_press_translation_z">9dp</dimen>
- <!-- How high we lift the divider when touching -->
- <dimen name="docked_stack_divider_lift_elevation">4dp</dimen>
-
- <dimen name="docked_divider_handle_width">16dp</dimen>
- <dimen name="docked_divider_handle_height">2dp</dimen>
-
<dimen name="battery_detail_graph_space_top">27dp</dimen>
<dimen name="battery_detail_graph_space_bottom">27dp</dimen>
@@ -1261,6 +1255,8 @@
<dimen name="qs_footer_horizontal_margin">22dp</dimen>
<dimen name="qs_media_disabled_seekbar_height">1dp</dimen>
<dimen name="qs_media_enabled_seekbar_height">3dp</dimen>
+ <dimen name="qs_media_enabled_seekbar_vertical_padding">15dp</dimen>
+ <dimen name="qs_media_disabled_seekbar_vertical_padding">16dp</dimen>
<!-- Window magnification -->
<dimen name="magnification_border_drag_size">35dp</dimen>
@@ -1321,15 +1317,19 @@
<dimen name="controls_management_side_padding">16dp</dimen>
<dimen name="controls_management_titles_margin">16dp</dimen>
<dimen name="controls_management_footer_side_margin">8dp</dimen>
+ <dimen name="controls_management_footer_top_margin">@dimen/controls_management_footer_side_margin</dimen>
<dimen name="controls_management_list_margin">16dp</dimen>
+ <dimen name="controls_management_indicator_top_margin">@dimen/controls_management_list_margin</dimen>
<dimen name="controls_management_apps_list_margin">64dp</dimen>
<dimen name="controls_management_editing_list_margin">48dp</dimen>
<dimen name="controls_management_editing_divider_margin">24dp</dimen>
<dimen name="controls_management_apps_extra_side_margin">8dp</dimen>
<dimen name="controls_management_zone_top_margin">32dp</dimen>
+ <dimen name="controls_management_favorites_top_margin">@dimen/controls_management_zone_top_margin</dimen>
<dimen name="controls_management_status_side_margin">16dp</dimen>
<dimen name="controls_management_page_indicator_height">24dp</dimen>
<dimen name="controls_management_checkbox_size">25dp</dimen>
+ <dimen name="controls_management_footer_height">72dp</dimen>
<dimen name="controls_title_size">24sp</dimen>
<dimen name="controls_subtitle_size">16sp</dimen>
diff --git a/packages/SystemUI/res/values/ids.xml b/packages/SystemUI/res/values/ids.xml
index a56f6f56836a..2f018b9239b5 100644
--- a/packages/SystemUI/res/values/ids.xml
+++ b/packages/SystemUI/res/values/ids.xml
@@ -103,13 +103,6 @@
<item type="id" name="contains_transformed_view" />
<item type="id" name="is_clicked_heads_up_tag" />
- <!-- Accessibility actions for the docked stack divider -->
- <item type="id" name="action_move_tl_full" />
- <item type="id" name="action_move_tl_70" />
- <item type="id" name="action_move_tl_50" />
- <item type="id" name="action_move_tl_30" />
- <item type="id" name="action_move_rb_full" />
-
<item type="id" name="bottom_roundess_animator_tag"/>
<item type="id" name="bottom_roundess_animator_start_tag"/>
<item type="id" name="bottom_roundess_animator_end_tag"/>
diff --git a/packages/SystemUI/res/values/strings.xml b/packages/SystemUI/res/values/strings.xml
index bfa7532349aa..e58bf3bad795 100644
--- a/packages/SystemUI/res/values/strings.xml
+++ b/packages/SystemUI/res/values/strings.xml
@@ -2260,31 +2260,6 @@
<!-- SysUI Tuner: Other section -->
<string name="other">Other</string>
- <!-- Accessibility label for the divider that separates the windows in split-screen mode [CHAR LIMIT=NONE] -->
- <string name="accessibility_divider">Split-screen divider</string>
-
- <!-- Accessibility action for moving docked stack divider to make the left screen full screen [CHAR LIMIT=NONE] -->
- <string name="accessibility_action_divider_left_full">Left full screen</string>
- <!-- Accessibility action for moving docked stack divider to make the left screen 70% [CHAR LIMIT=NONE] -->
- <string name="accessibility_action_divider_left_70">Left 70%</string>
- <!-- Accessibility action for moving docked stack divider to make the left screen 50% [CHAR LIMIT=NONE] -->
- <string name="accessibility_action_divider_left_50">Left 50%</string>
- <!-- Accessibility action for moving docked stack divider to make the left screen 30% [CHAR LIMIT=NONE] -->
- <string name="accessibility_action_divider_left_30">Left 30%</string>
- <!-- Accessibility action for moving docked stack divider to make the right screen full screen [CHAR LIMIT=NONE] -->
- <string name="accessibility_action_divider_right_full">Right full screen</string>
-
- <!-- Accessibility action for moving docked stack divider to make the top screen full screen [CHAR LIMIT=NONE] -->
- <string name="accessibility_action_divider_top_full">Top full screen</string>
- <!-- Accessibility action for moving docked stack divider to make the top screen 70% [CHAR LIMIT=NONE] -->
- <string name="accessibility_action_divider_top_70">Top 70%</string>
- <!-- Accessibility action for moving docked stack divider to make the top screen 50% [CHAR LIMIT=NONE] -->
- <string name="accessibility_action_divider_top_50">Top 50%</string>
- <!-- Accessibility action for moving docked stack divider to make the top screen 30% [CHAR LIMIT=NONE] -->
- <string name="accessibility_action_divider_top_30">Top 30%</string>
- <!-- Accessibility action for moving docked stack divider to make the bottom screen full screen [CHAR LIMIT=NONE] -->
- <string name="accessibility_action_divider_bottom_full">Bottom full screen</string>
-
<!-- Accessibility description of a QS tile while editing positions [CHAR LIMIT=NONE] -->
<string name="accessibility_qs_edit_tile_label">Position <xliff:g id="position" example="2">%1$d</xliff:g>, <xliff:g id="tile_name" example="Wi-Fi">%2$s</xliff:g>. Double tap to edit.</string>
@@ -2312,16 +2287,6 @@
<!-- Label for button that reports a touch that was wrongly rejected by the lockscreen. For debugging only. [CHAR LIMIT=NONE] -->
<string name="report_rejected_touch" translatable="false">Report rejected touch</string>
- <!-- Multi-Window strings -->
- <!-- Text that gets shown on top of current activity to inform the user that the system force-resized the current activity to be displayed in split-screen and that things might crash/not work properly [CHAR LIMIT=NONE] -->
- <string name="dock_forced_resizable">App may not work with split-screen.</string>
- <!-- Warning message when we try to dock a non-resizeable task and launch it in fullscreen instead. -->
- <string name="dock_non_resizeble_failed_to_dock_text">App does not support split-screen.</string>
- <!-- Text that gets shown on top of current activity to inform the user that the system force-resized the current activity to be displayed on a secondary display and that things might crash/not work properly [CHAR LIMIT=NONE] -->
- <string name="forced_resizable_secondary_display">App may not work on a secondary display.</string>
- <!-- Warning message when we try to launch a non-resizeable activity on a secondary display and launch it on the primary instead. -->
- <string name="activity_launch_on_secondary_display_failed_text">App does not support launch on secondary displays.</string>
-
<!-- accessibility label for button to open settings [CHAR LIMIT=NONE] -->
<string name="accessibility_quick_settings_settings">Open settings.</string>
diff --git a/packages/SystemUI/res/values/styles.xml b/packages/SystemUI/res/values/styles.xml
index ee07e613a0c5..58563f49dce4 100644
--- a/packages/SystemUI/res/values/styles.xml
+++ b/packages/SystemUI/res/values/styles.xml
@@ -24,21 +24,6 @@
<item name="android:layout_marginBottom">0dp</item>
</style>
- <!-- Theme used for the activity that shows when the system forced an app to be resizable -->
- <style name="ForcedResizableTheme" parent="@android:style/Theme.Translucent.NoTitleBar">
- <item name="android:windowBackground">@drawable/forced_resizable_background</item>
- <item name="android:statusBarColor">@*android:color/transparent</item>
- <item name="android:windowAnimationStyle">@style/Animation.ForcedResizable</item>
- </style>
-
- <style name="Animation.ForcedResizable" parent="@android:style/Animation">
- <item name="android:activityOpenEnterAnimation">@anim/forced_resizable_enter</item>
-
- <!-- If the target stack doesn't have focus, we do a task to front animation. -->
- <item name="android:taskToFrontEnterAnimation">@anim/forced_resizable_enter</item>
- <item name="android:activityCloseExitAnimation">@anim/forced_resizable_exit</item>
- </style>
-
<style name="PipPhoneOverlayControlTheme" parent="@android:style/Theme.Material">
<item name="android:windowIsTranslucent">true</item>
<item name="android:windowNoTitle">true</item>
@@ -483,23 +468,6 @@
<item name="android:background">@drawable/btn_borderless_rect</item>
</style>
- <style name="DockedDividerBackground">
- <item name="android:layout_width">match_parent</item>
- <item name="android:layout_height">10dp</item>
- <item name="android:layout_gravity">center_vertical</item>
- </style>
-
- <style name="DockedDividerMinimizedShadow">
- <item name="android:layout_width">match_parent</item>
- <item name="android:layout_height">8dp</item>
- </style>
-
- <style name="DockedDividerHandle">
- <item name="android:layout_gravity">center_horizontal</item>
- <item name="android:layout_width">96dp</item>
- <item name="android:layout_height">48dp</item>
- </style>
-
<style name="TunerSettings" parent="@android:style/Theme.DeviceDefault.Settings">
<item name="android:windowActionBar">false</item>
<item name="preferenceTheme">@style/TunerPreferenceTheme</item>
diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardClockSwitch.java b/packages/SystemUI/src/com/android/keyguard/KeyguardClockSwitch.java
index ecf1c2c91770..5ad8cad8195a 100644
--- a/packages/SystemUI/src/com/android/keyguard/KeyguardClockSwitch.java
+++ b/packages/SystemUI/src/com/android/keyguard/KeyguardClockSwitch.java
@@ -22,6 +22,7 @@ import android.widget.RelativeLayout;
import android.widget.TextClock;
import com.android.internal.colorextraction.ColorExtractor;
+import com.android.keyguard.dagger.KeyguardStatusViewScope;
import com.android.systemui.Interpolators;
import com.android.systemui.R;
import com.android.systemui.plugins.ClockPlugin;
@@ -36,6 +37,7 @@ import java.util.TimeZone;
/**
* Switch to show plugin clock when plugin is connected, otherwise it will show default clock.
*/
+@KeyguardStatusViewScope
public class KeyguardClockSwitch extends RelativeLayout {
private static final String TAG = "KeyguardClockSwitch";
diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardClockSwitchController.java b/packages/SystemUI/src/com/android/keyguard/KeyguardClockSwitchController.java
index f17f1ca797e0..fe5fcc6fd632 100644
--- a/packages/SystemUI/src/com/android/keyguard/KeyguardClockSwitchController.java
+++ b/packages/SystemUI/src/com/android/keyguard/KeyguardClockSwitchController.java
@@ -34,10 +34,11 @@ import javax.inject.Inject;
public class KeyguardClockSwitchController {
private static final boolean CUSTOM_CLOCKS_ENABLED = true;
+ private final KeyguardClockSwitch mView;
private final StatusBarStateController mStatusBarStateController;
private final SysuiColorExtractor mColorExtractor;
private final ClockManager mClockManager;
- private KeyguardClockSwitch mView;
+ private final KeyguardSliceViewController mKeyguardSliceViewController;
private final StatusBarStateController.StateListener mStateListener =
new StatusBarStateController.StateListener() {
@@ -52,9 +53,13 @@ public class KeyguardClockSwitchController {
*
* The color palette changes when the wallpaper is changed.
*/
- private final ColorExtractor.OnColorsChangedListener mColorsListener = (extractor, which) -> {
- if ((which & WallpaperManager.FLAG_LOCK) != 0) {
- mView.updateColors(getGradientColors());
+ private final ColorExtractor.OnColorsChangedListener mColorsListener =
+ new ColorExtractor.OnColorsChangedListener() {
+ @Override
+ public void onColorsChanged(ColorExtractor extractor, int which) {
+ if ((which & WallpaperManager.FLAG_LOCK) != 0) {
+ mView.updateColors(getGradientColors());
+ }
}
};
@@ -84,22 +89,27 @@ public class KeyguardClockSwitchController {
};
@Inject
- public KeyguardClockSwitchController(StatusBarStateController statusBarStateController,
- SysuiColorExtractor colorExtractor, ClockManager clockManager) {
+ public KeyguardClockSwitchController(KeyguardClockSwitch keyguardClockSwitch,
+ StatusBarStateController statusBarStateController,
+ SysuiColorExtractor colorExtractor, ClockManager clockManager,
+ KeyguardSliceViewController keyguardSliceViewController) {
+ mView = keyguardClockSwitch;
mStatusBarStateController = statusBarStateController;
mColorExtractor = colorExtractor;
mClockManager = clockManager;
+ mKeyguardSliceViewController = keyguardSliceViewController;
}
/**
* Attach the controller to the view it relates to.
*/
- public void attach(KeyguardClockSwitch view) {
- mView = view;
+ public void init() {
if (mView.isAttachedToWindow()) {
mOnAttachStateChangeListener.onViewAttachedToWindow(mView);
}
mView.addOnAttachStateChangeListener(mOnAttachStateChangeListener);
+
+ mKeyguardSliceViewController.init();
}
/**
diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardDisplayManager.java b/packages/SystemUI/src/com/android/keyguard/KeyguardDisplayManager.java
index 6f19613be28f..be21d203411e 100644
--- a/packages/SystemUI/src/com/android/keyguard/KeyguardDisplayManager.java
+++ b/packages/SystemUI/src/com/android/keyguard/KeyguardDisplayManager.java
@@ -34,12 +34,15 @@ import android.view.View;
import android.view.WindowManager;
import com.android.internal.annotations.VisibleForTesting;
+import com.android.keyguard.dagger.KeyguardStatusViewComponent;
import com.android.systemui.Dependency;
import com.android.systemui.R;
import com.android.systemui.navigationbar.NavigationBarController;
import com.android.systemui.navigationbar.NavigationBarView;
import com.android.systemui.util.InjectionInflationController;
+import javax.inject.Inject;
+
public class KeyguardDisplayManager {
protected static final String TAG = "KeyguardDisplayManager";
private static boolean DEBUG = KeyguardConstants.DEBUG;
@@ -47,6 +50,7 @@ public class KeyguardDisplayManager {
private final MediaRouter mMediaRouter;
private final DisplayManager mDisplayService;
private final InjectionInflationController mInjectableInflater;
+ private final KeyguardStatusViewComponent.Factory mKeyguardStatusViewComponentFactory;
private final Context mContext;
private boolean mShowing;
@@ -86,10 +90,13 @@ public class KeyguardDisplayManager {
}
};
+ @Inject
public KeyguardDisplayManager(Context context,
- InjectionInflationController injectableInflater) {
+ InjectionInflationController injectableInflater,
+ KeyguardStatusViewComponent.Factory keyguardStatusViewComponentFactory) {
mContext = context;
mInjectableInflater = injectableInflater;
+ mKeyguardStatusViewComponentFactory = keyguardStatusViewComponentFactory;
mMediaRouter = mContext.getSystemService(MediaRouter.class);
mDisplayService = mContext.getSystemService(DisplayManager.class);
mDisplayService.registerDisplayListener(mDisplayListener, null /* handler */);
@@ -124,6 +131,7 @@ public class KeyguardDisplayManager {
Presentation presentation = mPresentations.get(displayId);
if (presentation == null) {
final Presentation newPresentation = new KeyguardPresentation(mContext, display,
+ mKeyguardStatusViewComponentFactory,
mInjectableInflater.injectable(LayoutInflater.from(mContext)));
newPresentation.setOnDismissListener(dialog -> {
if (newPresentation.equals(mPresentations.get(displayId))) {
@@ -241,7 +249,9 @@ public class KeyguardDisplayManager {
static final class KeyguardPresentation extends Presentation {
private static final int VIDEO_SAFE_REGION = 80; // Percentage of display width & height
private static final int MOVE_CLOCK_TIMEOUT = 10000; // 10s
+ private final KeyguardStatusViewComponent.Factory mKeyguardStatusViewComponentFactory;
private final LayoutInflater mInjectableLayoutInflater;
+ private KeyguardClockSwitchController mKeyguardClockSwitchController;
private View mClock;
private int mUsableWidth;
private int mUsableHeight;
@@ -259,8 +269,10 @@ public class KeyguardDisplayManager {
};
KeyguardPresentation(Context context, Display display,
+ KeyguardStatusViewComponent.Factory keyguardStatusViewComponentFactory,
LayoutInflater injectionLayoutInflater) {
super(context, display, R.style.Theme_SystemUI_KeyguardPresentation);
+ mKeyguardStatusViewComponentFactory = keyguardStatusViewComponentFactory;
mInjectableLayoutInflater = injectionLayoutInflater;
getWindow().setType(WindowManager.LayoutParams.TYPE_KEYGUARD_DIALOG);
setCancelable(false);
@@ -302,6 +314,12 @@ public class KeyguardDisplayManager {
// Avoid screen burn in
mClock.post(mMoveTextRunnable);
+
+ mKeyguardClockSwitchController = mKeyguardStatusViewComponentFactory
+ .build(findViewById(R.id.clock))
+ .getKeyguardClockSwitchController();
+
+ mKeyguardClockSwitchController.init();
}
}
}
diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardSecurityContainer.java b/packages/SystemUI/src/com/android/keyguard/KeyguardSecurityContainer.java
index b0483339d14e..05172279c4ed 100644
--- a/packages/SystemUI/src/com/android/keyguard/KeyguardSecurityContainer.java
+++ b/packages/SystemUI/src/com/android/keyguard/KeyguardSecurityContainer.java
@@ -796,16 +796,6 @@ public class KeyguardSecurityContainer extends FrameLayout implements KeyguardSe
securityMode != SecurityMode.None && newView.needsInput());
}
- private KeyguardSecurityViewFlipper getFlipper() {
- for (int i = 0; i < getChildCount(); i++) {
- View child = getChildAt(i);
- if (child instanceof KeyguardSecurityViewFlipper) {
- return (KeyguardSecurityViewFlipper) child;
- }
- }
- return null;
- }
-
private KeyguardSecurityCallback mCallback = new KeyguardSecurityCallback() {
public void userActivity() {
if (mSecurityCallback != null) {
diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardSliceView.java b/packages/SystemUI/src/com/android/keyguard/KeyguardSliceView.java
index f639c880c97a..a479bca56c2a 100644
--- a/packages/SystemUI/src/com/android/keyguard/KeyguardSliceView.java
+++ b/packages/SystemUI/src/com/android/keyguard/KeyguardSliceView.java
@@ -16,12 +16,6 @@
package com.android.keyguard;
-import static android.app.slice.Slice.HINT_LIST_ITEM;
-import static android.view.Display.DEFAULT_DISPLAY;
-import static android.view.Display.INVALID_DISPLAY;
-
-import static com.android.systemui.util.InjectionInflationController.VIEW_CONTEXT;
-
import android.animation.LayoutTransition;
import android.animation.ObjectAnimator;
import android.animation.PropertyValuesHolder;
@@ -35,28 +29,19 @@ import android.graphics.drawable.Drawable;
import android.graphics.text.LineBreaker;
import android.net.Uri;
import android.os.Trace;
-import android.provider.Settings;
import android.text.TextUtils;
import android.text.TextUtils.TruncateAt;
import android.util.AttributeSet;
-import android.util.Log;
import android.util.TypedValue;
-import android.view.Display;
import android.view.View;
import android.view.animation.Animation;
import android.widget.LinearLayout;
import android.widget.TextView;
-import androidx.lifecycle.LiveData;
-import androidx.lifecycle.Observer;
-import androidx.slice.Slice;
import androidx.slice.SliceItem;
-import androidx.slice.SliceViewManager;
import androidx.slice.core.SliceQuery;
-import androidx.slice.widget.ListContent;
import androidx.slice.widget.RowContent;
import androidx.slice.widget.SliceContent;
-import androidx.slice.widget.SliceLiveData;
import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.graphics.ColorUtils;
@@ -64,70 +49,49 @@ import com.android.settingslib.Utils;
import com.android.systemui.Dependency;
import com.android.systemui.Interpolators;
import com.android.systemui.R;
-import com.android.systemui.dagger.qualifiers.Main;
-import com.android.systemui.keyguard.KeyguardSliceProvider;
-import com.android.systemui.plugins.ActivityStarter;
import com.android.systemui.statusbar.policy.ConfigurationController;
-import com.android.systemui.tuner.TunerService;
import com.android.systemui.util.wakelock.KeepAwakeAnimationListener;
import java.io.FileDescriptor;
import java.io.PrintWriter;
-import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
-
-import javax.inject.Inject;
-import javax.inject.Named;
+import java.util.Map;
/**
* View visible under the clock on the lock screen and AoD.
*/
-public class KeyguardSliceView extends LinearLayout implements View.OnClickListener,
- Observer<Slice>, TunerService.Tunable, ConfigurationController.ConfigurationListener {
+public class KeyguardSliceView extends LinearLayout {
private static final String TAG = "KeyguardSliceView";
public static final int DEFAULT_ANIM_DURATION = 550;
- private final HashMap<View, PendingIntent> mClickActions;
- private final ActivityStarter mActivityStarter;
- private final ConfigurationController mConfigurationController;
private final LayoutTransition mLayoutTransition;
- private final TunerService mTunerService;
- private Uri mKeyguardSliceUri;
@VisibleForTesting
TextView mTitle;
private Row mRow;
private int mTextColor;
private float mDarkAmount = 0;
- private LiveData<Slice> mLiveData;
- private int mDisplayId = INVALID_DISPLAY;
private int mIconSize;
private int mIconSizeWithHeader;
/**
* Runnable called whenever the view contents change.
*/
private Runnable mContentChangeListener;
- private Slice mSlice;
private boolean mHasHeader;
private final int mRowWithHeaderPadding;
private final int mRowPadding;
private float mRowTextSize;
private float mRowWithHeaderTextSize;
+ private View.OnClickListener mOnClickListener;
- @Inject
- public KeyguardSliceView(@Named(VIEW_CONTEXT) Context context, AttributeSet attrs,
- ActivityStarter activityStarter, ConfigurationController configurationController,
- TunerService tunerService, @Main Resources resources) {
+ public KeyguardSliceView(Context context, AttributeSet attrs) {
super(context, attrs);
- mTunerService = tunerService;
- mClickActions = new HashMap<>();
+ Resources resources = context.getResources();
mRowPadding = resources.getDimensionPixelSize(R.dimen.subtitle_clock_padding);
mRowWithHeaderPadding = resources.getDimensionPixelSize(R.dimen.header_subtitle_padding);
- mActivityStarter = activityStarter;
- mConfigurationController = configurationController;
mLayoutTransition = new LayoutTransition();
mLayoutTransition.setStagger(LayoutTransition.CHANGE_APPEARING, DEFAULT_ANIM_DURATION / 2);
@@ -153,39 +117,10 @@ public class KeyguardSliceView extends LinearLayout implements View.OnClickListe
R.dimen.widget_label_font_size);
mRowWithHeaderTextSize = mContext.getResources().getDimensionPixelSize(
R.dimen.header_row_font_size);
- mTitle.setOnClickListener(this);
mTitle.setBreakStrategy(LineBreaker.BREAK_STRATEGY_BALANCED);
}
@Override
- protected void onAttachedToWindow() {
- super.onAttachedToWindow();
-
- Display display = getDisplay();
- if (display != null) {
- mDisplayId = display.getDisplayId();
- }
- mTunerService.addTunable(this, Settings.Secure.KEYGUARD_SLICE_URI);
- // Make sure we always have the most current slice
- if (mDisplayId == DEFAULT_DISPLAY) {
- mLiveData.observeForever(this);
- }
- mConfigurationController.addCallback(this);
- }
-
- @Override
- protected void onDetachedFromWindow() {
- super.onDetachedFromWindow();
-
- // TODO(b/117344873) Remove below work around after this issue be fixed.
- if (mDisplayId == DEFAULT_DISPLAY) {
- mLiveData.removeObserver(this);
- }
- mTunerService.removeTunable(this);
- mConfigurationController.removeCallback(this);
- }
-
- @Override
public void onVisibilityAggregated(boolean isVisible) {
super.onVisibilityAggregated(isVisible);
setLayoutTransition(isVisible ? mLayoutTransition : null);
@@ -198,44 +133,31 @@ public class KeyguardSliceView extends LinearLayout implements View.OnClickListe
return mHasHeader;
}
- private void showSlice() {
- Trace.beginSection("KeyguardSliceView#showSlice");
- if (mSlice == null) {
- mTitle.setVisibility(GONE);
- mRow.setVisibility(GONE);
- mHasHeader = false;
- if (mContentChangeListener != null) {
- mContentChangeListener.run();
- }
- Trace.endSection();
- return;
- }
- mClickActions.clear();
-
- ListContent lc = new ListContent(getContext(), mSlice);
- SliceContent headerContent = lc.getHeader();
- mHasHeader = headerContent != null && !headerContent.getSliceItem().hasHint(HINT_LIST_ITEM);
- List<SliceContent> subItems = new ArrayList<>();
- for (int i = 0; i < lc.getRowItems().size(); i++) {
- SliceContent subItem = lc.getRowItems().get(i);
- String itemUri = subItem.getSliceItem().getSlice().getUri().toString();
- // Filter out the action row
- if (!KeyguardSliceProvider.KEYGUARD_ACTION_URI.equals(itemUri)) {
- subItems.add(subItem);
- }
+ void hideSlice() {
+ mTitle.setVisibility(GONE);
+ mRow.setVisibility(GONE);
+ mHasHeader = false;
+ if (mContentChangeListener != null) {
+ mContentChangeListener.run();
}
+ }
+
+ Map<View, PendingIntent> showSlice(RowContent header, List<SliceContent> subItems) {
+ Trace.beginSection("KeyguardSliceView#showSlice");
+ mHasHeader = header != null;
+ Map<View, PendingIntent> clickActions = new HashMap<>();
+
if (!mHasHeader) {
mTitle.setVisibility(GONE);
} else {
mTitle.setVisibility(VISIBLE);
- RowContent header = lc.getHeader();
SliceItem mainTitle = header.getTitleItem();
CharSequence title = mainTitle != null ? mainTitle.getText() : null;
mTitle.setText(title);
if (header.getPrimaryAction() != null
&& header.getPrimaryAction().getAction() != null) {
- mClickActions.put(mTitle, header.getPrimaryAction().getAction());
+ clickActions.put(mTitle, header.getPrimaryAction().getAction());
}
}
@@ -265,7 +187,7 @@ public class KeyguardSliceView extends LinearLayout implements View.OnClickListe
if (rc.getPrimaryAction() != null) {
pendingIntent = rc.getPrimaryAction().getAction();
}
- mClickActions.put(button, pendingIntent);
+ clickActions.put(button, pendingIntent);
final SliceItem titleItem = rc.getTitleItem();
button.setText(titleItem == null ? null : titleItem.getText());
@@ -286,14 +208,14 @@ public class KeyguardSliceView extends LinearLayout implements View.OnClickListe
}
}
button.setCompoundDrawables(iconDrawable, null, null, null);
- button.setOnClickListener(this);
+ button.setOnClickListener(mOnClickListener);
button.setClickable(pendingIntent != null);
}
// Removing old views
for (int i = 0; i < mRow.getChildCount(); i++) {
View child = mRow.getChildAt(i);
- if (!mClickActions.containsKey(child)) {
+ if (!clickActions.containsKey(child)) {
mRow.removeView(child);
i--;
}
@@ -303,6 +225,8 @@ public class KeyguardSliceView extends LinearLayout implements View.OnClickListe
mContentChangeListener.run();
}
Trace.endSection();
+
+ return clickActions;
}
public void setDarkAmount(float darkAmount) {
@@ -323,14 +247,6 @@ public class KeyguardSliceView extends LinearLayout implements View.OnClickListe
}
}
- @Override
- public void onClick(View v) {
- final PendingIntent action = mClickActions.get(v);
- if (action != null) {
- mActivityStarter.startPendingIntentDismissingKeyguard(action);
- }
- }
-
/**
* Runnable that gets invoked every time the title or the row visibility changes.
* @param contentChangeListener The listener.
@@ -339,43 +255,6 @@ public class KeyguardSliceView extends LinearLayout implements View.OnClickListe
mContentChangeListener = contentChangeListener;
}
- /**
- * LiveData observer lifecycle.
- * @param slice the new slice content.
- */
- @Override
- public void onChanged(Slice slice) {
- mSlice = slice;
- showSlice();
- }
-
- @Override
- public void onTuningChanged(String key, String newValue) {
- setupUri(newValue);
- }
-
- /**
- * Sets the slice provider Uri.
- */
- public void setupUri(String uriString) {
- if (uriString == null) {
- uriString = KeyguardSliceProvider.KEYGUARD_SLICE_URI;
- }
-
- boolean wasObserving = false;
- if (mLiveData != null && mLiveData.hasActiveObservers()) {
- wasObserving = true;
- mLiveData.removeObserver(this);
- }
-
- mKeyguardSliceUri = Uri.parse(uriString);
- mLiveData = SliceLiveData.fromUri(mContext, mKeyguardSliceUri);
-
- if (wasObserving) {
- mLiveData.observeForever(this);
- }
- }
-
@VisibleForTesting
int getTextColor() {
return ColorUtils.blendARGB(mTextColor, Color.WHITE, mDarkAmount);
@@ -387,8 +266,7 @@ public class KeyguardSliceView extends LinearLayout implements View.OnClickListe
updateTextColors();
}
- @Override
- public void onDensityOrFontScaleChanged() {
+ void onDensityOrFontScaleChanged() {
mIconSize = mContext.getResources().getDimensionPixelSize(R.dimen.widget_icon_size);
mIconSizeWithHeader = (int) mContext.getResources().getDimension(R.dimen.header_icon_size);
mRowTextSize = mContext.getResources().getDimensionPixelSize(
@@ -397,37 +275,21 @@ public class KeyguardSliceView extends LinearLayout implements View.OnClickListe
R.dimen.header_row_font_size);
}
- public void refresh() {
- Slice slice;
- Trace.beginSection("KeyguardSliceView#refresh");
- // We can optimize performance and avoid binder calls when we know that we're bound
- // to a Slice on the same process.
- if (KeyguardSliceProvider.KEYGUARD_SLICE_URI.equals(mKeyguardSliceUri.toString())) {
- KeyguardSliceProvider instance = KeyguardSliceProvider.getAttachedInstance();
- if (instance != null) {
- slice = instance.onBindSlice(mKeyguardSliceUri);
- } else {
- Log.w(TAG, "Keyguard slice not bound yet?");
- slice = null;
- }
- } else {
- slice = SliceViewManager.getInstance(getContext()).bindSlice(mKeyguardSliceUri);
- }
- onChanged(slice);
- Trace.endSection();
- }
-
public void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
pw.println("KeyguardSliceView:");
- pw.println(" mClickActions: " + mClickActions);
pw.println(" mTitle: " + (mTitle == null ? "null" : mTitle.getVisibility() == VISIBLE));
pw.println(" mRow: " + (mRow == null ? "null" : mRow.getVisibility() == VISIBLE));
pw.println(" mTextColor: " + Integer.toHexString(mTextColor));
pw.println(" mDarkAmount: " + mDarkAmount);
- pw.println(" mSlice: " + mSlice);
pw.println(" mHasHeader: " + mHasHeader);
}
+ @Override
+ public void setOnClickListener(View.OnClickListener onClickListener) {
+ mOnClickListener = onClickListener;
+ mTitle.setOnClickListener(onClickListener);
+ }
+
public static class Row extends LinearLayout {
/**
diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardSliceViewController.java b/packages/SystemUI/src/com/android/keyguard/KeyguardSliceViewController.java
new file mode 100644
index 000000000000..2470b958a85f
--- /dev/null
+++ b/packages/SystemUI/src/com/android/keyguard/KeyguardSliceViewController.java
@@ -0,0 +1,239 @@
+/*
+ * 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.keyguard;
+
+import static android.app.slice.Slice.HINT_LIST_ITEM;
+import static android.view.Display.DEFAULT_DISPLAY;
+
+import android.app.PendingIntent;
+import android.net.Uri;
+import android.os.Trace;
+import android.provider.Settings;
+import android.util.Log;
+import android.view.Display;
+import android.view.View;
+
+import androidx.annotation.NonNull;
+import androidx.lifecycle.LiveData;
+import androidx.lifecycle.Observer;
+import androidx.slice.Slice;
+import androidx.slice.SliceViewManager;
+import androidx.slice.widget.ListContent;
+import androidx.slice.widget.RowContent;
+import androidx.slice.widget.SliceContent;
+import androidx.slice.widget.SliceLiveData;
+
+import com.android.keyguard.dagger.KeyguardStatusViewScope;
+import com.android.systemui.Dumpable;
+import com.android.systemui.dump.DumpManager;
+import com.android.systemui.keyguard.KeyguardSliceProvider;
+import com.android.systemui.plugins.ActivityStarter;
+import com.android.systemui.statusbar.policy.ConfigurationController;
+import com.android.systemui.tuner.TunerService;
+
+import java.io.FileDescriptor;
+import java.io.PrintWriter;
+import java.util.List;
+import java.util.Map;
+import java.util.stream.Collectors;
+
+import javax.inject.Inject;
+
+/** Controller for a {@link KeyguardSliceView}. */
+@KeyguardStatusViewScope
+public class KeyguardSliceViewController implements Dumpable {
+ private static final String TAG = "KeyguardSliceViewCtrl";
+
+ private final KeyguardSliceView mView;
+ private final KeyguardStatusView mKeyguardStatusView;
+ private final ActivityStarter mActivityStarter;
+ private final ConfigurationController mConfigurationController;
+ private final TunerService mTunerService;
+ private final DumpManager mDumpManager;
+ private int mDisplayId;
+ private LiveData<Slice> mLiveData;
+ private Uri mKeyguardSliceUri;
+ private Slice mSlice;
+ private Map<View, PendingIntent> mClickActions;
+
+ private final View.OnAttachStateChangeListener mOnAttachStateChangeListener =
+ new View.OnAttachStateChangeListener() {
+
+ @Override
+ public void onViewAttachedToWindow(View v) {
+
+ Display display = mView.getDisplay();
+ if (display != null) {
+ mDisplayId = display.getDisplayId();
+ }
+ mTunerService.addTunable(mTunable, Settings.Secure.KEYGUARD_SLICE_URI);
+ // Make sure we always have the most current slice
+ if (mDisplayId == DEFAULT_DISPLAY && mLiveData != null) {
+ mLiveData.observeForever(mObserver);
+ }
+ mConfigurationController.addCallback(mConfigurationListener);
+ mDumpManager.registerDumpable(
+ TAG + "@" + Integer.toHexString(
+ KeyguardSliceViewController.this.hashCode()),
+ KeyguardSliceViewController.this);
+ }
+
+ @Override
+ public void onViewDetachedFromWindow(View v) {
+
+ // TODO(b/117344873) Remove below work around after this issue be fixed.
+ if (mDisplayId == DEFAULT_DISPLAY) {
+ mLiveData.removeObserver(mObserver);
+ }
+ mTunerService.removeTunable(mTunable);
+ mConfigurationController.removeCallback(mConfigurationListener);
+ mDumpManager.unregisterDumpable(TAG);
+ }
+ };
+
+ TunerService.Tunable mTunable = (key, newValue) -> setupUri(newValue);
+
+ ConfigurationController.ConfigurationListener mConfigurationListener =
+ new ConfigurationController.ConfigurationListener() {
+ @Override
+ public void onDensityOrFontScaleChanged() {
+ mView.onDensityOrFontScaleChanged();
+ }
+ };
+
+ Observer<Slice> mObserver = new Observer<Slice>() {
+ @Override
+ public void onChanged(Slice slice) {
+ mSlice = slice;
+ showSlice(slice);
+ }
+ };
+
+ private View.OnClickListener mOnClickListener = new View.OnClickListener() {
+ @Override
+ public void onClick(View v) {
+ final PendingIntent action = mClickActions.get(v);
+ if (action != null && mActivityStarter != null) {
+ mActivityStarter.startPendingIntentDismissingKeyguard(action);
+ }
+ }
+ };
+
+ @Inject
+ public KeyguardSliceViewController(KeyguardSliceView keyguardSliceView,
+ KeyguardStatusView keyguardStatusView, ActivityStarter activityStarter,
+ ConfigurationController configurationController, TunerService tunerService,
+ DumpManager dumpManager) {
+ mView = keyguardSliceView;
+ mKeyguardStatusView = keyguardStatusView;
+ mActivityStarter = activityStarter;
+ mConfigurationController = configurationController;
+ mTunerService = tunerService;
+ mDumpManager = dumpManager;
+ }
+
+ /** Initialize the controller. */
+ public void init() {
+ if (mView.isAttachedToWindow()) {
+ mOnAttachStateChangeListener.onViewAttachedToWindow(mView);
+ }
+ mView.addOnAttachStateChangeListener(mOnAttachStateChangeListener);
+ mView.setOnClickListener(mOnClickListener);
+ // TODO: remove the line below.
+ mKeyguardStatusView.setKeyguardSliceViewController(this);
+ }
+
+ /**
+ * Sets the slice provider Uri.
+ */
+ public void setupUri(String uriString) {
+ if (uriString == null) {
+ uriString = KeyguardSliceProvider.KEYGUARD_SLICE_URI;
+ }
+
+ boolean wasObserving = false;
+ if (mLiveData != null && mLiveData.hasActiveObservers()) {
+ wasObserving = true;
+ mLiveData.removeObserver(mObserver);
+ }
+
+ mKeyguardSliceUri = Uri.parse(uriString);
+ mLiveData = SliceLiveData.fromUri(mView.getContext(), mKeyguardSliceUri);
+
+ if (wasObserving) {
+ mLiveData.observeForever(mObserver);
+ }
+ }
+
+ /**
+ * Update contents of the view.
+ */
+ public void refresh() {
+ Slice slice;
+ Trace.beginSection("KeyguardSliceViewController#refresh");
+ // We can optimize performance and avoid binder calls when we know that we're bound
+ // to a Slice on the same process.
+ if (KeyguardSliceProvider.KEYGUARD_SLICE_URI.equals(mKeyguardSliceUri.toString())) {
+ KeyguardSliceProvider instance = KeyguardSliceProvider.getAttachedInstance();
+ if (instance != null) {
+ slice = instance.onBindSlice(mKeyguardSliceUri);
+ } else {
+ Log.w(TAG, "Keyguard slice not bound yet?");
+ slice = null;
+ }
+ } else {
+ // TODO: Make SliceViewManager injectable
+ slice = SliceViewManager.getInstance(mView.getContext()).bindSlice(mKeyguardSliceUri);
+ }
+ mObserver.onChanged(slice);
+ Trace.endSection();
+ }
+
+ void showSlice(Slice slice) {
+ Trace.beginSection("KeyguardSliceViewController#showSlice");
+ if (slice == null) {
+ mView.hideSlice();
+ Trace.endSection();
+ return;
+ }
+
+ ListContent lc = new ListContent(slice);
+ RowContent headerContent = lc.getHeader();
+ boolean hasHeader =
+ headerContent != null && !headerContent.getSliceItem().hasHint(HINT_LIST_ITEM);
+
+ List<SliceContent> subItems = lc.getRowItems().stream().filter(sliceContent -> {
+ String itemUri = sliceContent.getSliceItem().getSlice().getUri().toString();
+ // Filter out the action row
+ return !KeyguardSliceProvider.KEYGUARD_ACTION_URI.equals(itemUri);
+ }).collect(Collectors.toList());
+
+
+ mClickActions = mView.showSlice(hasHeader ? headerContent : null, subItems);
+
+ Trace.endSection();
+ }
+
+
+ @Override
+ public void dump(@NonNull FileDescriptor fd, @NonNull PrintWriter pw, @NonNull String[] args) {
+ pw.println(" mSlice: " + mSlice);
+ pw.println(" mClickActions: " + mClickActions);
+
+ mKeyguardStatusView.dump(fd, pw, args);
+ }
+}
diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardStatusView.java b/packages/SystemUI/src/com/android/keyguard/KeyguardStatusView.java
index 4c6aafb0058a..6e111745627f 100644
--- a/packages/SystemUI/src/com/android/keyguard/KeyguardStatusView.java
+++ b/packages/SystemUI/src/com/android/keyguard/KeyguardStatusView.java
@@ -32,7 +32,6 @@ import android.util.Slog;
import android.util.TypedValue;
import android.view.View;
import android.widget.GridLayout;
-import android.widget.LinearLayout;
import android.widget.TextView;
import androidx.core.graphics.ColorUtils;
@@ -56,7 +55,6 @@ public class KeyguardStatusView extends GridLayout implements
private final LockPatternUtils mLockPatternUtils;
private final IActivityManager mIActivityManager;
- private LinearLayout mStatusViewContainer;
private TextView mLogoutView;
private KeyguardClockSwitch mClockView;
private TextView mOwnerInfo;
@@ -64,6 +62,7 @@ public class KeyguardStatusView extends GridLayout implements
private View mNotificationIcons;
private Runnable mPendingMarqueeStart;
private Handler mHandler;
+ private KeyguardSliceViewController mKeyguardSliceViewController;
private boolean mPulsing;
private float mDarkAmount = 0;
@@ -179,7 +178,6 @@ public class KeyguardStatusView extends GridLayout implements
@Override
protected void onFinishInflate() {
super.onFinishInflate();
- mStatusViewContainer = findViewById(R.id.status_view_container);
mLogoutView = findViewById(R.id.logout);
mNotificationIcons = findViewById(R.id.clock_notification_icon_container);
if (mLogoutView != null) {
@@ -250,7 +248,7 @@ public class KeyguardStatusView extends GridLayout implements
public void dozeTimeTick() {
refreshTime();
- mKeyguardSlice.refresh();
+ mKeyguardSliceViewController.refresh();
}
private void refreshTime() {
@@ -456,4 +454,9 @@ public class KeyguardStatusView extends GridLayout implements
Log.e(TAG, "Failed to logout user", re);
}
}
+
+ // TODO: remove this method when a controller is available.
+ void setKeyguardSliceViewController(KeyguardSliceViewController keyguardSliceViewController) {
+ mKeyguardSliceViewController = keyguardSliceViewController;
+ }
}
diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardUpdateMonitor.java b/packages/SystemUI/src/com/android/keyguard/KeyguardUpdateMonitor.java
index c354241da7b4..1027329b8d3c 100644
--- a/packages/SystemUI/src/com/android/keyguard/KeyguardUpdateMonitor.java
+++ b/packages/SystemUI/src/com/android/keyguard/KeyguardUpdateMonitor.java
@@ -2519,13 +2519,11 @@ public class KeyguardUpdateMonitor implements TrustManager.TrustListener, Dumpab
if (isUserUnlocked(getCurrentUser())) {
return false;
}
- Intent homeIntent = new Intent(Intent.ACTION_MAIN)
- .addCategory(Intent.CATEGORY_HOME);
- ResolveInfo resolveInfo = mContext.getPackageManager().resolveActivity(homeIntent,
- 0 /* flags */);
+ Intent homeIntent = new Intent(Intent.ACTION_MAIN).addCategory(Intent.CATEGORY_HOME);
+ ResolveInfo resolveInfo = mContext.getPackageManager().resolveActivityAsUser(homeIntent,
+ 0 /* flags */, getCurrentUser());
- // TODO(b/160971249): Replace in the future by resolving activity as user.
- if (resolveInfo == null && mIsAutomotive) {
+ if (resolveInfo == null) {
Log.w(TAG, "resolveNeedsSlowUnlockTransition: returning false since activity "
+ "could not be resolved.");
return false;
diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardViewController.java b/packages/SystemUI/src/com/android/keyguard/KeyguardViewController.java
index 6a90d00c1e75..9766ee128f7c 100644
--- a/packages/SystemUI/src/com/android/keyguard/KeyguardViewController.java
+++ b/packages/SystemUI/src/com/android/keyguard/KeyguardViewController.java
@@ -21,9 +21,7 @@ import android.view.View;
import android.view.ViewGroup;
import android.view.ViewRootImpl;
-import com.android.systemui.keyguard.DismissCallbackRegistry;
import com.android.systemui.keyguard.KeyguardViewMediator;
-import com.android.systemui.plugins.FalsingManager;
import com.android.systemui.statusbar.phone.BiometricUnlockController;
import com.android.systemui.statusbar.phone.KeyguardBypassController;
import com.android.systemui.statusbar.phone.NotificationPanelViewController;
@@ -180,22 +178,18 @@ public interface KeyguardViewController {
/**
* Registers the StatusBar to which this Keyguard View is mounted.
- *
* @param statusBar
* @param container
* @param notificationPanelViewController
* @param biometricUnlockController
- * @param dismissCallbackRegistry
* @param lockIconContainer
* @param notificationContainer
* @param bypassController
- * @param falsingManager
*/
void registerStatusBar(StatusBar statusBar,
ViewGroup container,
NotificationPanelViewController notificationPanelViewController,
BiometricUnlockController biometricUnlockController,
- DismissCallbackRegistry dismissCallbackRegistry,
ViewGroup lockIconContainer, View notificationContainer,
- KeyguardBypassController bypassController, FalsingManager falsingManager);
+ KeyguardBypassController bypassController);
}
diff --git a/packages/SystemUI/src/com/android/systemui/pip/phone/dagger/PipMenuActivityClass.java b/packages/SystemUI/src/com/android/keyguard/dagger/ContainerView.java
index 114c30e625aa..e65f19db5ac2 100644
--- a/packages/SystemUI/src/com/android/systemui/pip/phone/dagger/PipMenuActivityClass.java
+++ b/packages/SystemUI/src/com/android/keyguard/dagger/ContainerView.java
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2020 The Android Open Source Project
+ * 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.
@@ -14,7 +14,7 @@
* limitations under the License.
*/
-package com.android.systemui.pip.phone.dagger;
+package com.android.keyguard.dagger;
import static java.lang.annotation.RetentionPolicy.RUNTIME;
@@ -26,5 +26,5 @@ import javax.inject.Qualifier;
@Qualifier
@Documented
@Retention(RUNTIME)
-public @interface PipMenuActivityClass {
+public @interface ContainerView {
}
diff --git a/packages/SystemUI/src/com/android/keyguard/dagger/KeyguardBouncerComponent.java b/packages/SystemUI/src/com/android/keyguard/dagger/KeyguardBouncerComponent.java
new file mode 100644
index 000000000000..84deaca096aa
--- /dev/null
+++ b/packages/SystemUI/src/com/android/keyguard/dagger/KeyguardBouncerComponent.java
@@ -0,0 +1,42 @@
+/*
+ * 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.keyguard.dagger;
+
+import android.view.ViewGroup;
+
+import com.android.systemui.statusbar.phone.KeyguardBouncer;
+
+import dagger.BindsInstance;
+import dagger.Subcomponent;
+
+/**
+ * Dagger Subcomponent for the {@link KeyguardBouncer}.
+ */
+@Subcomponent
+@KeyguardBouncerScope
+public interface KeyguardBouncerComponent {
+ /** Simple factory for {@link KeyguardBouncerComponent}. */
+ @Subcomponent.Factory
+ interface Factory {
+ KeyguardBouncerComponent build(
+ @BindsInstance @ContainerView ViewGroup container,
+ @BindsInstance KeyguardBouncer.BouncerExpansionCallback bouncerExpansionCallback);
+ }
+
+ /** */
+ KeyguardBouncer createKeyguardBouncer();
+}
diff --git a/packages/SystemUI/src/com/android/keyguard/dagger/KeyguardBouncerScope.java b/packages/SystemUI/src/com/android/keyguard/dagger/KeyguardBouncerScope.java
new file mode 100644
index 000000000000..207ac2852f2f
--- /dev/null
+++ b/packages/SystemUI/src/com/android/keyguard/dagger/KeyguardBouncerScope.java
@@ -0,0 +1,32 @@
+/*
+ * 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.keyguard.dagger;
+
+import static java.lang.annotation.RetentionPolicy.RUNTIME;
+
+import java.lang.annotation.Documented;
+import java.lang.annotation.Retention;
+
+import javax.inject.Scope;
+
+/**
+ * Scope annotation for singleton items within the StatusBarComponent.
+ */
+@Documented
+@Retention(RUNTIME)
+@Scope
+public @interface KeyguardBouncerScope {}
diff --git a/packages/SystemUI/src/com/android/keyguard/dagger/KeyguardStatusViewComponent.java b/packages/SystemUI/src/com/android/keyguard/dagger/KeyguardStatusViewComponent.java
new file mode 100644
index 000000000000..21ccff707d34
--- /dev/null
+++ b/packages/SystemUI/src/com/android/keyguard/dagger/KeyguardStatusViewComponent.java
@@ -0,0 +1,39 @@
+/*
+ * 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.keyguard.dagger;
+
+import com.android.keyguard.KeyguardClockSwitchController;
+import com.android.keyguard.KeyguardStatusView;
+
+import dagger.BindsInstance;
+import dagger.Subcomponent;
+
+/**
+ * Subcomponent for helping work with KeyguardStatusView and its children.
+ */
+@Subcomponent(modules = {KeyguardStatusViewModule.class})
+@KeyguardStatusViewScope
+public interface KeyguardStatusViewComponent {
+ /** Simple factory for {@link KeyguardStatusViewComponent}. */
+ @Subcomponent.Factory
+ interface Factory {
+ KeyguardStatusViewComponent build(@BindsInstance KeyguardStatusView presentation);
+ }
+
+ /** Builds a {@link com.android.keyguard.KeyguardClockSwitchController}. */
+ KeyguardClockSwitchController getKeyguardClockSwitchController();
+}
diff --git a/packages/SystemUI/src/com/android/keyguard/dagger/KeyguardStatusViewModule.java b/packages/SystemUI/src/com/android/keyguard/dagger/KeyguardStatusViewModule.java
new file mode 100644
index 000000000000..1d51e5925de8
--- /dev/null
+++ b/packages/SystemUI/src/com/android/keyguard/dagger/KeyguardStatusViewModule.java
@@ -0,0 +1,39 @@
+/*
+ * 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.keyguard.dagger;
+
+import com.android.keyguard.KeyguardClockSwitch;
+import com.android.keyguard.KeyguardSliceView;
+import com.android.keyguard.KeyguardStatusView;
+import com.android.systemui.R;
+
+import dagger.Module;
+import dagger.Provides;
+
+/** Dagger module for {@link KeyguardStatusViewComponent}. */
+@Module
+public abstract class KeyguardStatusViewModule {
+ @Provides
+ static KeyguardClockSwitch getKeyguardClockSwitch(KeyguardStatusView keyguardPresentation) {
+ return keyguardPresentation.findViewById(R.id.keyguard_clock_container);
+ }
+
+ @Provides
+ static KeyguardSliceView getKeyguardSliceView(KeyguardClockSwitch keyguardClockSwitch) {
+ return keyguardClockSwitch.findViewById(R.id.keyguard_status_area);
+ }
+}
diff --git a/packages/SystemUI/src/com/android/keyguard/dagger/KeyguardStatusViewScope.java b/packages/SystemUI/src/com/android/keyguard/dagger/KeyguardStatusViewScope.java
new file mode 100644
index 000000000000..880822aa7343
--- /dev/null
+++ b/packages/SystemUI/src/com/android/keyguard/dagger/KeyguardStatusViewScope.java
@@ -0,0 +1,32 @@
+/*
+ * 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.keyguard.dagger;
+
+import static java.lang.annotation.RetentionPolicy.RUNTIME;
+
+import java.lang.annotation.Documented;
+import java.lang.annotation.Retention;
+
+import javax.inject.Scope;
+
+/**
+ * Scope annotation for singleton items within the StatusBarComponent.
+ */
+@Documented
+@Retention(RUNTIME)
+@Scope
+public @interface KeyguardStatusViewScope {}
diff --git a/packages/SystemUI/src/com/android/systemui/Dependency.java b/packages/SystemUI/src/com/android/systemui/Dependency.java
index 27809b50d746..ed78c94d45f9 100644
--- a/packages/SystemUI/src/com/android/systemui/Dependency.java
+++ b/packages/SystemUI/src/com/android/systemui/Dependency.java
@@ -77,6 +77,7 @@ import com.android.systemui.statusbar.VibratorHelper;
import com.android.systemui.statusbar.notification.NotificationEntryManager;
import com.android.systemui.statusbar.notification.NotificationEntryManager.KeyguardEnvironment;
import com.android.systemui.statusbar.notification.NotificationFilter;
+import com.android.systemui.statusbar.notification.collection.legacy.NotificationGroupManagerLegacy;
import com.android.systemui.statusbar.notification.collection.legacy.VisualStabilityManager;
import com.android.systemui.statusbar.notification.logging.NotificationLogger;
import com.android.systemui.statusbar.notification.row.NotificationBlockingHelperManager;
@@ -88,7 +89,6 @@ import com.android.systemui.statusbar.phone.LightBarController;
import com.android.systemui.statusbar.phone.LockscreenGestureLogger;
import com.android.systemui.statusbar.phone.ManagedProfileController;
import com.android.systemui.statusbar.phone.NotificationGroupAlertTransferHelper;
-import com.android.systemui.statusbar.phone.NotificationGroupManager;
import com.android.systemui.statusbar.phone.ShadeController;
import com.android.systemui.statusbar.phone.StatusBar;
import com.android.systemui.statusbar.phone.StatusBarIconController;
@@ -276,7 +276,7 @@ public class Dependency {
@Inject Lazy<StatusBarStateController> mStatusBarStateController;
@Inject Lazy<NotificationLockscreenUserManager> mNotificationLockscreenUserManager;
@Inject Lazy<NotificationGroupAlertTransferHelper> mNotificationGroupAlertTransferHelper;
- @Inject Lazy<NotificationGroupManager> mNotificationGroupManager;
+ @Inject Lazy<NotificationGroupManagerLegacy> mNotificationGroupManager;
@Inject Lazy<VisualStabilityManager> mVisualStabilityManager;
@Inject Lazy<NotificationGutsManager> mNotificationGutsManager;
@Inject Lazy<NotificationMediaManager> mNotificationMediaManager;
@@ -468,7 +468,7 @@ public class Dependency {
mProviders.put(NotificationLockscreenUserManager.class,
mNotificationLockscreenUserManager::get);
mProviders.put(VisualStabilityManager.class, mVisualStabilityManager::get);
- mProviders.put(NotificationGroupManager.class, mNotificationGroupManager::get);
+ mProviders.put(NotificationGroupManagerLegacy.class, mNotificationGroupManager::get);
mProviders.put(NotificationGroupAlertTransferHelper.class,
mNotificationGroupAlertTransferHelper::get);
mProviders.put(NotificationMediaManager.class, mNotificationMediaManager::get);
diff --git a/packages/SystemUI/src/com/android/systemui/ExpandHelper.java b/packages/SystemUI/src/com/android/systemui/ExpandHelper.java
index 17b840cc7a20..744a77f5cff9 100644
--- a/packages/SystemUI/src/com/android/systemui/ExpandHelper.java
+++ b/packages/SystemUI/src/com/android/systemui/ExpandHelper.java
@@ -32,10 +32,10 @@ import android.view.View;
import android.view.ViewConfiguration;
import com.android.internal.annotations.VisibleForTesting;
-import com.android.systemui.statusbar.FlingAnimationUtils;
import com.android.systemui.statusbar.notification.row.ExpandableNotificationRow;
import com.android.systemui.statusbar.notification.row.ExpandableView;
import com.android.systemui.statusbar.policy.ScrollAdapter;
+import com.android.wm.shell.animation.FlingAnimationUtils;
public class ExpandHelper implements Gefingerpoken {
public interface Callback {
diff --git a/packages/SystemUI/src/com/android/systemui/Prefs.java b/packages/SystemUI/src/com/android/systemui/Prefs.java
index d1149d37d431..f4c865e1d131 100644
--- a/packages/SystemUI/src/com/android/systemui/Prefs.java
+++ b/packages/SystemUI/src/com/android/systemui/Prefs.java
@@ -21,7 +21,7 @@ import android.content.Context;
import android.content.SharedPreferences;
import android.content.SharedPreferences.OnSharedPreferenceChangeListener;
-import com.android.systemui.settings.CurrentUserContextTracker;
+import com.android.systemui.settings.UserContextProvider;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
@@ -38,7 +38,7 @@ import java.util.Set;
*
* NOTE: Clients of this class should take care to pass in the correct user context when querying
* settings, otherwise you will always read/write for user 0 which is almost never what you want.
- * See {@link CurrentUserContextTracker} for a simple way to get the current context
+ * See {@link UserContextProvider} for a simple way to get the current context
*/
public final class Prefs {
private Prefs() {} // no instantation
diff --git a/packages/SystemUI/src/com/android/systemui/SwipeHelper.java b/packages/SystemUI/src/com/android/systemui/SwipeHelper.java
index d17ca4041b31..8aa3493cc105 100644
--- a/packages/SystemUI/src/com/android/systemui/SwipeHelper.java
+++ b/packages/SystemUI/src/com/android/systemui/SwipeHelper.java
@@ -16,13 +16,14 @@
package com.android.systemui;
+import static com.android.systemui.classifier.Classifier.NOTIFICATION_DISMISS;
+
import android.animation.Animator;
import android.animation.AnimatorListenerAdapter;
import android.animation.ObjectAnimator;
import android.animation.ValueAnimator;
import android.animation.ValueAnimator.AnimatorUpdateListener;
import android.annotation.NonNull;
-import android.content.Context;
import android.content.res.Resources;
import android.graphics.RectF;
import android.os.Handler;
@@ -36,8 +37,8 @@ import android.view.accessibility.AccessibilityEvent;
import com.android.systemui.plugins.FalsingManager;
import com.android.systemui.plugins.statusbar.NotificationMenuRowPlugin;
-import com.android.systemui.statusbar.FlingAnimationUtils;
import com.android.systemui.statusbar.notification.row.ExpandableNotificationRow;
+import com.android.wm.shell.animation.FlingAnimationUtils;
public class SwipeHelper implements Gefingerpoken {
static final String TAG = "com.android.systemui.SwipeHelper";
@@ -115,24 +116,24 @@ public class SwipeHelper implements Gefingerpoken {
private final ArrayMap<View, Animator> mDismissPendingMap = new ArrayMap<>();
public SwipeHelper(
- int swipeDirection, Callback callback, Context context, FalsingManager falsingManager) {
+ int swipeDirection, Callback callback, Resources resources,
+ ViewConfiguration viewConfiguration, FalsingManager falsingManager) {
mCallback = callback;
mHandler = new Handler();
mSwipeDirection = swipeDirection;
mVelocityTracker = VelocityTracker.obtain();
- final ViewConfiguration configuration = ViewConfiguration.get(context);
- mPagingTouchSlop = configuration.getScaledPagingTouchSlop();
- mSlopMultiplier = configuration.getScaledAmbiguousGestureMultiplier();
+ mPagingTouchSlop = viewConfiguration.getScaledPagingTouchSlop();
+ mSlopMultiplier = viewConfiguration.getScaledAmbiguousGestureMultiplier();
// Extra long-press!
mLongPressTimeout = (long) (ViewConfiguration.getLongPressTimeout() * 1.5f);
- Resources res = context.getResources();
- mDensityScale = res.getDisplayMetrics().density;
- mFalsingThreshold = res.getDimensionPixelSize(R.dimen.swipe_helper_falsing_threshold);
- mFadeDependingOnAmountSwiped = res.getBoolean(R.bool.config_fadeDependingOnAmountSwiped);
+ mDensityScale = resources.getDisplayMetrics().density;
+ mFalsingThreshold = resources.getDimensionPixelSize(R.dimen.swipe_helper_falsing_threshold);
+ mFadeDependingOnAmountSwiped = resources.getBoolean(
+ R.bool.config_fadeDependingOnAmountSwiped);
mFalsingManager = falsingManager;
- mFlingAnimationUtils = new FlingAnimationUtils(res.getDisplayMetrics(),
+ mFlingAnimationUtils = new FlingAnimationUtils(resources.getDisplayMetrics(),
getMaxEscapeAnimDuration() / 1000f);
}
@@ -697,14 +698,15 @@ public class SwipeHelper implements Gefingerpoken {
float translation = getTranslation(mCurrView);
return ev.getActionMasked() == MotionEvent.ACTION_UP
&& !mFalsingManager.isUnlockingDisabled()
- && !isFalseGesture(ev) && (swipedFastEnough() || swipedFarEnough())
+ && !isFalseGesture() && (swipedFastEnough() || swipedFarEnough())
&& mCallback.canChildBeDismissedInDirection(mCurrView, translation > 0);
}
- public boolean isFalseGesture(MotionEvent ev) {
+ /** Returns true if the gesture should be rejected. */
+ public boolean isFalseGesture() {
boolean falsingDetected = mCallback.isAntiFalsingNeeded();
if (mFalsingManager.isClassifierEnabled()) {
- falsingDetected = falsingDetected && mFalsingManager.isFalseTouch();
+ falsingDetected = falsingDetected && mFalsingManager.isFalseTouch(NOTIFICATION_DISMISS);
} else {
falsingDetected = falsingDetected && !mTouchAboveFalsingThreshold;
}
diff --git a/packages/SystemUI/src/com/android/systemui/SystemUIFactory.java b/packages/SystemUI/src/com/android/systemui/SystemUIFactory.java
index f5c364947a2f..f15949977754 100644
--- a/packages/SystemUI/src/com/android/systemui/SystemUIFactory.java
+++ b/packages/SystemUI/src/com/android/systemui/SystemUIFactory.java
@@ -19,25 +19,16 @@ package com.android.systemui;
import android.content.Context;
import android.content.res.Resources;
import android.os.Handler;
-import android.os.Looper;
import android.util.Log;
-import android.view.ViewGroup;
import com.android.internal.annotations.VisibleForTesting;
-import com.android.internal.widget.LockPatternUtils;
-import com.android.keyguard.KeyguardUpdateMonitor;
-import com.android.keyguard.ViewMediatorCallback;
import com.android.systemui.dagger.DaggerGlobalRootComponent;
import com.android.systemui.dagger.GlobalRootComponent;
import com.android.systemui.dagger.SysUIComponent;
import com.android.systemui.dagger.WMComponent;
-import com.android.systemui.keyguard.DismissCallbackRegistry;
-import com.android.systemui.plugins.FalsingManager;
import com.android.systemui.screenshot.ScreenshotNotificationSmartActionsProvider;
-import com.android.systemui.statusbar.phone.KeyguardBouncer;
-import com.android.systemui.statusbar.phone.KeyguardBypassController;
-import com.android.systemui.statusbar.policy.KeyguardStateController;
+import java.util.concurrent.ExecutionException;
import java.util.concurrent.Executor;
/**
@@ -83,11 +74,16 @@ public class SystemUIFactory {
public SystemUIFactory() {}
- private void init(Context context) {
+ private void init(Context context) throws ExecutionException, InterruptedException {
mRootComponent = buildGlobalRootComponent(context);
+ // Stand up WMComponent
mWMComponent = mRootComponent.getWMComponentBuilder().build();
- // TODO: use WMComponent to pass APIs into the SysUIComponent.
- mSysUIComponent = mRootComponent.getSysUIComponent().build();
+
+ // And finally, retrieve whatever SysUI needs from WMShell and build SysUI.
+ // TODO: StubAPIClass is just a placeholder.
+ mSysUIComponent = mRootComponent.getSysUIComponent()
+ .setStubAPIClass(mWMComponent.createStubAPIClass())
+ .build();
// Every other part of our codebase currently relies on Dependency, so we
// really need to ensure the Dependency gets initialized early on.
@@ -101,10 +97,15 @@ public class SystemUIFactory {
.build();
}
+
public GlobalRootComponent getRootComponent() {
return mRootComponent;
}
+ public WMComponent getWMComponent() {
+ return mWMComponent;
+ }
+
public SysUIComponent getSysUIComponent() {
return mSysUIComponent;
}
@@ -129,17 +130,4 @@ public class SystemUIFactory {
Handler uiHandler) {
return new ScreenshotNotificationSmartActionsProvider();
}
-
- public KeyguardBouncer createKeyguardBouncer(Context context, ViewMediatorCallback callback,
- LockPatternUtils lockPatternUtils, ViewGroup container,
- DismissCallbackRegistry dismissCallbackRegistry,
- KeyguardBouncer.BouncerExpansionCallback expansionCallback,
- KeyguardStateController keyguardStateController, FalsingManager falsingManager,
- KeyguardBypassController bypassController) {
- return new KeyguardBouncer(context, callback, lockPatternUtils, container,
- dismissCallbackRegistry, falsingManager,
- expansionCallback, keyguardStateController,
- Dependency.get(KeyguardUpdateMonitor.class), bypassController,
- new Handler(Looper.getMainLooper()));
- }
}
diff --git a/packages/SystemUI/src/com/android/systemui/accessibility/MagnificationModeSwitch.java b/packages/SystemUI/src/com/android/systemui/accessibility/MagnificationModeSwitch.java
index 34f721c94ed2..128af3702c49 100644
--- a/packages/SystemUI/src/com/android/systemui/accessibility/MagnificationModeSwitch.java
+++ b/packages/SystemUI/src/com/android/systemui/accessibility/MagnificationModeSwitch.java
@@ -20,8 +20,13 @@ import android.annotation.NonNull;
import android.content.Context;
import android.content.pm.ActivityInfo;
import android.graphics.PixelFormat;
+import android.graphics.PointF;
import android.provider.Settings;
+import android.util.MathUtils;
import android.view.Gravity;
+import android.view.MotionEvent;
+import android.view.View;
+import android.view.ViewConfiguration;
import android.view.WindowManager;
import android.widget.ImageView;
@@ -31,7 +36,8 @@ import com.android.systemui.R;
/**
* Shows/hides a {@link android.widget.ImageView} on the screen and changes the values of
* {@link Settings.Secure.ACCESSIBILITY_MAGNIFICATION_MODE} when the UI is toggled.
- * The button UI would automatically be dismissed after displaying for a period of time.
+ * The button icon is movable by dragging. And the button UI would automatically be dismissed after
+ * displaying for a period of time.
*/
class MagnificationModeSwitch {
@@ -41,6 +47,10 @@ class MagnificationModeSwitch {
private final Context mContext;
private final WindowManager mWindowManager;
private final ImageView mImageView;
+ private final PointF mLastDown = new PointF();
+ private final PointF mLastDrag = new PointF();
+ private final int mTapTimeout = ViewConfiguration.getTapTimeout();
+ private final int mTouchSlop;
private int mMagnificationMode = Settings.Secure.ACCESSIBILITY_MAGNIFICATION_MODE_FULLSCREEN;
private final WindowManager.LayoutParams mParams;
private boolean mIsVisible = false;
@@ -56,13 +66,10 @@ class MagnificationModeSwitch {
Context.WINDOW_SERVICE);
mParams = createLayoutParams();
mImageView = imageView;
+ mTouchSlop = ViewConfiguration.get(mContext).getScaledTouchSlop();
applyResourcesValues();
- mImageView.setOnClickListener(
- view -> {
- removeButton();
- toggleMagnificationMode();
- });
mImageView.setImageResource(getIconResId(mMagnificationMode));
+ mImageView.setOnTouchListener(this::onTouch);
}
private void applyResourcesValues() {
@@ -71,13 +78,59 @@ class MagnificationModeSwitch {
mImageView.setPadding(padding, padding, padding, padding);
}
+ private boolean onTouch(View v, MotionEvent event) {
+ if (!mIsVisible || mImageView == null) {
+ return false;
+ }
+ switch (event.getAction()) {
+ case MotionEvent.ACTION_DOWN:
+ mImageView.setAlpha(1.0f);
+ mImageView.animate().cancel();
+ mLastDown.set(event.getRawX(), event.getRawY());
+ mLastDrag.set(event.getRawX(), event.getRawY());
+ return true;
+ case MotionEvent.ACTION_MOVE:
+ // Move the button position.
+ moveButton(event.getRawX() - mLastDrag.x,
+ event.getRawY() - mLastDrag.y);
+ mLastDrag.set(event.getRawX(), event.getRawY());
+ return true;
+ case MotionEvent.ACTION_UP:
+ // Single tap to toggle magnification mode and the button position will be reset
+ // after the action is performed.
+ final float distance = MathUtils.dist(mLastDown.x, mLastDown.y,
+ event.getRawX(), event.getRawY());
+ if ((event.getEventTime() - event.getDownTime()) <= mTapTimeout
+ && distance <= mTouchSlop) {
+ handleSingleTap();
+ } else {
+ showButton(mMagnificationMode);
+ }
+ return true;
+ case MotionEvent.ACTION_CANCEL:
+ showButton(mMagnificationMode);
+ return true;
+ default:
+ return false;
+ }
+ }
+
+ private void moveButton(float offsetX, float offsetY) {
+ mParams.x -= offsetX;
+ mParams.y -= offsetY;
+ mWindowManager.updateViewLayout(mImageView, mParams);
+ }
+
void removeButton() {
if (!mIsVisible) {
return;
}
mImageView.animate().cancel();
mWindowManager.removeView(mImageView);
+ // Reset button status.
mIsVisible = false;
+ mParams.x = 0;
+ mParams.y = 0;
}
void showButton(int mode) {
@@ -120,6 +173,11 @@ class MagnificationModeSwitch {
Settings.Secure.ACCESSIBILITY_MAGNIFICATION_MODE, newMode);
}
+ private void handleSingleTap() {
+ removeButton();
+ toggleMagnificationMode();
+ }
+
private static ImageView createView(Context context) {
ImageView imageView = new ImageView(context);
imageView.setClickable(true);
diff --git a/packages/SystemUI/src/com/android/systemui/accessibility/WindowMagnification.java b/packages/SystemUI/src/com/android/systemui/accessibility/WindowMagnification.java
index f601c52ba98e..e10d2be4cb5e 100644
--- a/packages/SystemUI/src/com/android/systemui/accessibility/WindowMagnification.java
+++ b/packages/SystemUI/src/com/android/systemui/accessibility/WindowMagnification.java
@@ -18,11 +18,13 @@ package com.android.systemui.accessibility;
import android.annotation.MainThread;
import android.annotation.NonNull;
+import android.annotation.Nullable;
import android.content.Context;
import android.content.pm.ActivityInfo;
import android.content.res.Configuration;
import android.graphics.Rect;
import android.os.Handler;
+import android.os.RemoteCallback;
import android.os.RemoteException;
import android.util.Log;
import android.view.SurfaceControl;
@@ -98,9 +100,11 @@ public class WindowMagnification extends SystemUI implements WindowMagnifierCall
}
@MainThread
- void enableWindowMagnification(int displayId, float scale, float centerX, float centerY) {
+ void enableWindowMagnification(int displayId, float scale, float centerX, float centerY,
+ @Nullable RemoteCallback endCallback) {
//TODO: b/144080869 support multi-display.
- mWindowMagnificationAnimationController.enableWindowMagnification(scale, centerX, centerY);
+ mWindowMagnificationAnimationController.enableWindowMagnification(scale, centerX, centerY,
+ endCallback != null ? () -> endCallback.sendResult(null) : null);
}
@MainThread
@@ -116,9 +120,10 @@ public class WindowMagnification extends SystemUI implements WindowMagnifierCall
}
@MainThread
- void disableWindowMagnification(int displayId) {
+ void disableWindowMagnification(int displayId, @Nullable RemoteCallback endCallback) {
//TODO: b/144080869 support multi-display.
- mWindowMagnificationAnimationController.deleteWindowMagnification();
+ mWindowMagnificationAnimationController.deleteWindowMagnification(
+ endCallback != null ? () -> endCallback.sendResult(null) : null);
}
@Override
@@ -177,10 +182,10 @@ public class WindowMagnification extends SystemUI implements WindowMagnifierCall
@Override
public void enableWindowMagnification(int displayId, float scale, float centerX,
- float centerY) {
+ float centerY, RemoteCallback remoteCallback) {
mHandler.post(
() -> mWindowMagnification.enableWindowMagnification(displayId, scale, centerX,
- centerY));
+ centerY, remoteCallback));
}
@Override
@@ -189,8 +194,9 @@ public class WindowMagnification extends SystemUI implements WindowMagnifierCall
}
@Override
- public void disableWindowMagnification(int displayId) {
- mHandler.post(() -> mWindowMagnification.disableWindowMagnification(displayId));
+ public void disableWindowMagnification(int displayId, RemoteCallback remoteCallback) {
+ mHandler.post(() -> mWindowMagnification.disableWindowMagnification(displayId,
+ remoteCallback));
}
@Override
diff --git a/packages/SystemUI/src/com/android/systemui/accessibility/WindowMagnificationAnimationController.java b/packages/SystemUI/src/com/android/systemui/accessibility/WindowMagnificationAnimationController.java
index ae51623f3dc2..2f2e3eaddd3b 100644
--- a/packages/SystemUI/src/com/android/systemui/accessibility/WindowMagnificationAnimationController.java
+++ b/packages/SystemUI/src/com/android/systemui/accessibility/WindowMagnificationAnimationController.java
@@ -19,6 +19,7 @@ package com.android.systemui.accessibility;
import android.animation.Animator;
import android.animation.ValueAnimator;
import android.annotation.IntDef;
+import android.annotation.Nullable;
import android.content.Context;
import android.content.res.Resources;
import android.util.Log;
@@ -44,13 +45,13 @@ class WindowMagnificationAnimationController implements ValueAnimator.AnimatorUp
@IntDef({STATE_DISABLED, STATE_ENABLED, STATE_DISABLING, STATE_ENABLING})
@interface MagnificationState {}
- //The window magnification is disabled.
+ // The window magnification is disabled.
private static final int STATE_DISABLED = 0;
- //The window magnification is enabled.
+ // The window magnification is enabled.
private static final int STATE_ENABLED = 1;
- //The window magnification is going to be disabled when the animation is end.
+ // The window magnification is going to be disabled when the animation is end.
private static final int STATE_DISABLING = 2;
- //The animation is running for enabling the window magnification.
+ // The animation is running for enabling the window magnification.
private static final int STATE_ENABLING = 3;
private final WindowMagnificationController mController;
@@ -58,7 +59,11 @@ class WindowMagnificationAnimationController implements ValueAnimator.AnimatorUp
private final AnimationSpec mStartSpec = new AnimationSpec();
private final AnimationSpec mEndSpec = new AnimationSpec();
private final Context mContext;
-
+ // Called when the animation is ended successfully without cancelling or mStartSpec and
+ // mEndSpec are equal.
+ private Runnable mAnimationEndCallback;
+ // The flag to ignore the animation end callback.
+ private boolean mEndAnimationCanceled = false;
@MagnificationState
private int mState = STATE_DISABLED;
@@ -83,26 +88,35 @@ class WindowMagnificationAnimationController implements ValueAnimator.AnimatorUp
* from 1.0 and the center won't be changed during the animation. If {@link #mState} is
* {@code STATE_DISABLING}, the animation runs in reverse.
*
- * @param scale the target scale, or {@link Float#NaN} to leave unchanged.
- * @param centerX the screen-relative X coordinate around which to center,
+ * @param scale The target scale, or {@link Float#NaN} to leave unchanged.
+ * @param centerX The screen-relative X coordinate around which to center,
* or {@link Float#NaN} to leave unchanged.
- * @param centerY the screen-relative Y coordinate around which to center,
+ * @param centerY The screen-relative Y coordinate around which to center,
* or {@link Float#NaN} to leave unchanged.
+ * @param animationEndCallback Called when the transition is complete or the given arguments
+ * are as same as current values.
*
* @see #onAnimationUpdate(ValueAnimator)
*/
- void enableWindowMagnification(float scale, float centerX, float centerY) {
- if (mState == STATE_ENABLING) {
- mValueAnimator.cancel();
- }
+ void enableWindowMagnification(float scale, float centerX, float centerY,
+ @Nullable Runnable animationEndCallback) {
+ mAnimationEndCallback = animationEndCallback;
setupEnableAnimationSpecs(scale, centerX, centerY);
-
if (mEndSpec.equals(mStartSpec)) {
+ if (mState == STATE_DISABLED) {
+ mController.enableWindowMagnification(scale, centerX, centerY);
+ } else if (mState == STATE_ENABLING || mState == STATE_DISABLING) {
+ mValueAnimator.cancel();
+ }
+ sendCallbackIfNeeded();
setState(STATE_ENABLED);
} else {
if (mState == STATE_DISABLING) {
mValueAnimator.reverse();
} else {
+ if (mState == STATE_ENABLING) {
+ mValueAnimator.cancel();
+ }
mValueAnimator.start();
}
setState(STATE_ENABLING);
@@ -115,7 +129,7 @@ class WindowMagnificationAnimationController implements ValueAnimator.AnimatorUp
final float currentCenterY = mController.getCenterY();
if (mState == STATE_DISABLED) {
- //We don't need to offset the center during the animation.
+ // We don't need to offset the center during the animation.
mStartSpec.set(/* scale*/ 1.0f, centerX, centerY);
mEndSpec.set(Float.isNaN(scale) ? mContext.getResources().getInteger(
R.integer.magnification_default_scale) : scale, centerX, centerY);
@@ -145,9 +159,16 @@ class WindowMagnificationAnimationController implements ValueAnimator.AnimatorUp
/**
* Wraps {@link WindowMagnificationController#deleteWindowMagnification()}} with transition
* animation. If the window magnification is enabling, it runs the animation in reverse.
+ *
+ * @param animationEndCallback Called when the transition is complete or the window
+ * magnification is disabled already.
*/
- void deleteWindowMagnification() {
+ void deleteWindowMagnification(@Nullable Runnable animationEndCallback) {
+ mAnimationEndCallback = animationEndCallback;
if (mState == STATE_DISABLED || mState == STATE_DISABLING) {
+ if (mState == STATE_DISABLED) {
+ sendCallbackIfNeeded();
+ }
return;
}
mStartSpec.set(/* scale*/ 1.0f, Float.NaN, Float.NaN);
@@ -160,9 +181,9 @@ class WindowMagnificationAnimationController implements ValueAnimator.AnimatorUp
/**
* Wraps {@link WindowMagnificationController#moveWindowMagnifier(float, float)}. If the
* animation is running, it has no effect.
- * @param offsetX the amount in pixels to offset the window magnifier in the X direction, in
+ * @param offsetX The amount in pixels to offset the window magnifier in the X direction, in
* current screen pixels.
- * @param offsetY the amount in pixels to offset the window magnifier in the Y direction, in
+ * @param offsetY The amount in pixels to offset the window magnifier in the Y direction, in
* current screen pixels.
*/
void moveWindowMagnifier(float offsetX, float offsetY) {
@@ -185,28 +206,43 @@ class WindowMagnificationAnimationController implements ValueAnimator.AnimatorUp
@Override
public void onAnimationStart(Animator animation) {
+ mEndAnimationCanceled = false;
}
@Override
- public void onAnimationEnd(Animator animation) {
- if (mState == STATE_DISABLING) {
+ public void onAnimationEnd(Animator animation, boolean isReverse) {
+ if (mEndAnimationCanceled) {
+ return;
+ }
+ if (isReverse) {
mController.deleteWindowMagnification();
setState(STATE_DISABLED);
- } else if (mState == STATE_ENABLING) {
- setState(STATE_ENABLED);
} else {
- Log.w(TAG, "onAnimationEnd unexpected state:" + mState);
+ setState(STATE_ENABLED);
}
+ sendCallbackIfNeeded();
+ }
+
+ @Override
+ public void onAnimationEnd(Animator animation) {
}
@Override
public void onAnimationCancel(Animator animation) {
+ mEndAnimationCanceled = true;
}
@Override
public void onAnimationRepeat(Animator animation) {
}
+ private void sendCallbackIfNeeded() {
+ if (mAnimationEndCallback != null) {
+ mAnimationEndCallback.run();
+ mAnimationEndCallback = null;
+ }
+ }
+
@Override
public void onAnimationUpdate(ValueAnimator animation) {
final float fract = animation.getAnimatedFraction();
diff --git a/packages/SystemUI/src/com/android/systemui/pip/phone/dagger/PipModule.java b/packages/SystemUI/src/com/android/systemui/appops/dagger/AppOpsModule.java
index c8b6982a2eba..d4cc3f37b8dd 100644
--- a/packages/SystemUI/src/com/android/systemui/pip/phone/dagger/PipModule.java
+++ b/packages/SystemUI/src/com/android/systemui/appops/dagger/AppOpsModule.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,21 +14,19 @@
* limitations under the License.
*/
-package com.android.systemui.pip.phone.dagger;
+package com.android.systemui.appops.dagger;
-import com.android.systemui.pip.BasePipManager;
-import com.android.systemui.pip.phone.PipManager;
+import com.android.systemui.appops.AppOpsController;
+import com.android.systemui.appops.AppOpsControllerImpl;
import dagger.Binds;
import dagger.Module;
-/**
- * Dagger Module for Phone PIP.
- */
+/** Dagger Module for code in the appops package. */
@Module
-public abstract class PipModule {
-
- /** Binds PipManager as the default BasePipManager. */
+public interface AppOpsModule {
+ /** */
@Binds
- public abstract BasePipManager providePipManager(PipManager pipManager);
+ AppOpsController provideAppOpsController(AppOpsControllerImpl controllerImpl);
+
}
diff --git a/packages/SystemUI/src/com/android/systemui/bubbles/BubbleController.java b/packages/SystemUI/src/com/android/systemui/bubbles/BubbleController.java
index 9e9d85a7cd1c..c81b7cefbbd7 100644
--- a/packages/SystemUI/src/com/android/systemui/bubbles/BubbleController.java
+++ b/packages/SystemUI/src/com/android/systemui/bubbles/BubbleController.java
@@ -104,11 +104,11 @@ import com.android.systemui.statusbar.notification.collection.NotifCollection;
import com.android.systemui.statusbar.notification.collection.NotifPipeline;
import com.android.systemui.statusbar.notification.collection.NotificationEntry;
import com.android.systemui.statusbar.notification.collection.coordinator.BubbleCoordinator;
+import com.android.systemui.statusbar.notification.collection.legacy.NotificationGroupManagerLegacy;
import com.android.systemui.statusbar.notification.collection.notifcollection.DismissedByUserStats;
import com.android.systemui.statusbar.notification.collection.notifcollection.NotifCollectionListener;
import com.android.systemui.statusbar.notification.interruption.NotificationInterruptStateProvider;
import com.android.systemui.statusbar.notification.logging.NotificationLogger;
-import com.android.systemui.statusbar.phone.NotificationGroupManager;
import com.android.systemui.statusbar.phone.ScrimController;
import com.android.systemui.statusbar.phone.ShadeController;
import com.android.systemui.statusbar.phone.StatusBar;
@@ -164,7 +164,7 @@ public class BubbleController implements ConfigurationController.ConfigurationLi
private final BubbleTaskStackListener mTaskStackListener;
private BubbleExpandListener mExpandListener;
@Nullable private BubbleStackView.SurfaceSynchronizer mSurfaceSynchronizer;
- private final NotificationGroupManager mNotificationGroupManager;
+ private final NotificationGroupManagerLegacy mNotificationGroupManager;
private final ShadeController mShadeController;
private final FloatingContentCoordinator mFloatingContentCoordinator;
private final BubbleDataRepository mDataRepository;
@@ -355,7 +355,7 @@ public class BubbleController implements ConfigurationController.ConfigurationLi
NotificationInterruptStateProvider interruptionStateProvider,
ZenModeController zenModeController,
NotificationLockscreenUserManager notifUserManager,
- NotificationGroupManager groupManager,
+ NotificationGroupManagerLegacy groupManager,
NotificationEntryManager entryManager,
NotifPipeline notifPipeline,
FeatureFlags featureFlags,
@@ -588,11 +588,11 @@ public class BubbleController implements ConfigurationController.ConfigurationLi
}
});
- mNotificationGroupManager.addOnGroupChangeListener(
- new NotificationGroupManager.OnGroupChangeListener() {
+ mNotificationGroupManager.registerGroupChangeListener(
+ new NotificationGroupManagerLegacy.OnGroupChangeListener() {
@Override
public void onGroupSuppressionChanged(
- NotificationGroupManager.NotificationGroup group,
+ NotificationGroupManagerLegacy.NotificationGroup group,
boolean suppressed) {
// More notifications could be added causing summary to no longer
// be suppressed -- in this case need to remove the key.
@@ -650,8 +650,7 @@ public class BubbleController implements ConfigurationController.ConfigurationLi
// 3. User removes all bubbles
// 4. We expect all the removed bubbles AND the summary (note: the summary was
// never added to the suppressedSummary list in BubbleData, so we add this check)
- NotificationEntry summary =
- mNotificationGroupManager.getLogicalGroupSummary(entry.getSbn());
+ NotificationEntry summary = mNotificationGroupManager.getLogicalGroupSummary(entry);
if (summary != null) {
ArrayList<NotificationEntry> summaryChildren =
mNotificationGroupManager.getLogicalChildren(summary.getSbn());
diff --git a/packages/SystemUI/src/com/android/systemui/bubbles/dagger/BubbleModule.java b/packages/SystemUI/src/com/android/systemui/bubbles/dagger/BubbleModule.java
index eecc41c697b3..9efc3c20f55a 100644
--- a/packages/SystemUI/src/com/android/systemui/bubbles/dagger/BubbleModule.java
+++ b/packages/SystemUI/src/com/android/systemui/bubbles/dagger/BubbleModule.java
@@ -34,8 +34,8 @@ import com.android.systemui.statusbar.NotificationLockscreenUserManager;
import com.android.systemui.statusbar.NotificationShadeWindowController;
import com.android.systemui.statusbar.notification.NotificationEntryManager;
import com.android.systemui.statusbar.notification.collection.NotifPipeline;
+import com.android.systemui.statusbar.notification.collection.legacy.NotificationGroupManagerLegacy;
import com.android.systemui.statusbar.notification.interruption.NotificationInterruptStateProvider;
-import com.android.systemui.statusbar.phone.NotificationGroupManager;
import com.android.systemui.statusbar.phone.ShadeController;
import com.android.systemui.statusbar.policy.ConfigurationController;
import com.android.systemui.statusbar.policy.ZenModeController;
@@ -62,7 +62,7 @@ public interface BubbleModule {
NotificationInterruptStateProvider interruptionStateProvider,
ZenModeController zenModeController,
NotificationLockscreenUserManager notifUserManager,
- NotificationGroupManager groupManager,
+ NotificationGroupManagerLegacy groupManager,
NotificationEntryManager entryManager,
NotifPipeline notifPipeline,
FeatureFlags featureFlags,
diff --git a/packages/SystemUI/src/com/android/systemui/classifier/FalsingManagerFake.java b/packages/SystemUI/src/com/android/systemui/classifier/FalsingManagerFake.java
index 646e62062dfb..6961b45c3c37 100644
--- a/packages/SystemUI/src/com/android/systemui/classifier/FalsingManagerFake.java
+++ b/packages/SystemUI/src/com/android/systemui/classifier/FalsingManagerFake.java
@@ -70,7 +70,7 @@ public class FalsingManagerFake implements FalsingManager {
}
@Override
- public boolean isFalseTouch() {
+ public boolean isFalseTouch(@Classifier.InteractionType int interactionType) {
return mIsFalseTouch;
}
diff --git a/packages/SystemUI/src/com/android/systemui/classifier/FalsingManagerImpl.java b/packages/SystemUI/src/com/android/systemui/classifier/FalsingManagerImpl.java
index cc64fb53f15f..decaec10e572 100644
--- a/packages/SystemUI/src/com/android/systemui/classifier/FalsingManagerImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/classifier/FalsingManagerImpl.java
@@ -262,7 +262,7 @@ public class FalsingManagerImpl implements FalsingManager {
/**
* @return true if the classifier determined that this is not a human interacting with the phone
*/
- public boolean isFalseTouch() {
+ public boolean isFalseTouch(@Classifier.InteractionType int interactionType) {
if (FalsingLog.ENABLED) {
// We're getting some false wtfs from touches that happen after the device went
// to sleep. Only report missing sessions that happen when the device is interactive.
diff --git a/packages/SystemUI/src/com/android/systemui/classifier/FalsingManagerProxy.java b/packages/SystemUI/src/com/android/systemui/classifier/FalsingManagerProxy.java
index 83b6df3e701b..2c31862e9b79 100644
--- a/packages/SystemUI/src/com/android/systemui/classifier/FalsingManagerProxy.java
+++ b/packages/SystemUI/src/com/android/systemui/classifier/FalsingManagerProxy.java
@@ -187,8 +187,8 @@ public class FalsingManagerProxy implements FalsingManager, Dumpable {
}
@Override
- public boolean isFalseTouch() {
- return mInternalFalsingManager.isFalseTouch();
+ public boolean isFalseTouch(@Classifier.InteractionType int interactionType) {
+ return mInternalFalsingManager.isFalseTouch(interactionType);
}
@Override
diff --git a/packages/SystemUI/src/com/android/systemui/classifier/brightline/BrightLineFalsingManager.java b/packages/SystemUI/src/com/android/systemui/classifier/brightline/BrightLineFalsingManager.java
index a50f9ce9713b..9d847ca62465 100644
--- a/packages/SystemUI/src/com/android/systemui/classifier/brightline/BrightLineFalsingManager.java
+++ b/packages/SystemUI/src/com/android/systemui/classifier/brightline/BrightLineFalsingManager.java
@@ -189,7 +189,8 @@ public class BrightLineFalsingManager implements FalsingManager {
}
@Override
- public boolean isFalseTouch() {
+ public boolean isFalseTouch(@Classifier.InteractionType int interactionType) {
+ mDataProvider.setInteractionType(interactionType);
if (!mDataProvider.isDirty()) {
return mPreviousResult;
}
diff --git a/packages/SystemUI/src/com/android/systemui/classifier/brightline/FalsingDataProvider.java b/packages/SystemUI/src/com/android/systemui/classifier/brightline/FalsingDataProvider.java
index ea46441c8fbe..8d067489a8cc 100644
--- a/packages/SystemUI/src/com/android/systemui/classifier/brightline/FalsingDataProvider.java
+++ b/packages/SystemUI/src/com/android/systemui/classifier/brightline/FalsingDataProvider.java
@@ -116,7 +116,10 @@ public class FalsingDataProvider {
* interactionType is defined by {@link com.android.systemui.classifier.Classifier}.
*/
final void setInteractionType(@Classifier.InteractionType int interactionType) {
- this.mInteractionType = interactionType;
+ if (mInteractionType != interactionType) {
+ mInteractionType = interactionType;
+ mDirty = true;
+ }
}
public boolean isDirty() {
diff --git a/packages/SystemUI/src/com/android/systemui/dagger/DependencyBinder.java b/packages/SystemUI/src/com/android/systemui/dagger/DependencyBinder.java
deleted file mode 100644
index e2a6d6c51d4d..000000000000
--- a/packages/SystemUI/src/com/android/systemui/dagger/DependencyBinder.java
+++ /dev/null
@@ -1,268 +0,0 @@
-/*
- * 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;
-
-import com.android.systemui.ActivityStarterDelegate;
-import com.android.systemui.appops.AppOpsController;
-import com.android.systemui.appops.AppOpsControllerImpl;
-import com.android.systemui.classifier.FalsingManagerProxy;
-import com.android.systemui.controls.dagger.ControlsModule;
-import com.android.systemui.globalactions.GlobalActionsComponent;
-import com.android.systemui.globalactions.GlobalActionsImpl;
-import com.android.systemui.plugins.ActivityStarter;
-import com.android.systemui.plugins.DarkIconDispatcher;
-import com.android.systemui.plugins.FalsingManager;
-import com.android.systemui.plugins.GlobalActions;
-import com.android.systemui.plugins.VolumeDialogController;
-import com.android.systemui.plugins.statusbar.StatusBarStateController;
-import com.android.systemui.power.PowerNotificationWarnings;
-import com.android.systemui.power.PowerUI;
-import com.android.systemui.qs.QSHost;
-import com.android.systemui.qs.QSTileHost;
-import com.android.systemui.statusbar.NotificationRemoteInputManager;
-import com.android.systemui.statusbar.StatusBarStateControllerImpl;
-import com.android.systemui.statusbar.SysuiStatusBarStateController;
-import com.android.systemui.statusbar.phone.DarkIconDispatcherImpl;
-import com.android.systemui.statusbar.phone.ManagedProfileController;
-import com.android.systemui.statusbar.phone.ManagedProfileControllerImpl;
-import com.android.systemui.statusbar.phone.StatusBarIconController;
-import com.android.systemui.statusbar.phone.StatusBarIconControllerImpl;
-import com.android.systemui.statusbar.phone.StatusBarRemoteInputCallback;
-import com.android.systemui.statusbar.policy.BluetoothController;
-import com.android.systemui.statusbar.policy.BluetoothControllerImpl;
-import com.android.systemui.statusbar.policy.CastController;
-import com.android.systemui.statusbar.policy.CastControllerImpl;
-import com.android.systemui.statusbar.policy.ExtensionController;
-import com.android.systemui.statusbar.policy.ExtensionControllerImpl;
-import com.android.systemui.statusbar.policy.FlashlightController;
-import com.android.systemui.statusbar.policy.FlashlightControllerImpl;
-import com.android.systemui.statusbar.policy.HotspotController;
-import com.android.systemui.statusbar.policy.HotspotControllerImpl;
-import com.android.systemui.statusbar.policy.KeyguardStateController;
-import com.android.systemui.statusbar.policy.KeyguardStateControllerImpl;
-import com.android.systemui.statusbar.policy.LocationController;
-import com.android.systemui.statusbar.policy.LocationControllerImpl;
-import com.android.systemui.statusbar.policy.NetworkController;
-import com.android.systemui.statusbar.policy.NetworkControllerImpl;
-import com.android.systemui.statusbar.policy.NextAlarmController;
-import com.android.systemui.statusbar.policy.NextAlarmControllerImpl;
-import com.android.systemui.statusbar.policy.RotationLockController;
-import com.android.systemui.statusbar.policy.RotationLockControllerImpl;
-import com.android.systemui.statusbar.policy.SecurityController;
-import com.android.systemui.statusbar.policy.SecurityControllerImpl;
-import com.android.systemui.statusbar.policy.SensorPrivacyController;
-import com.android.systemui.statusbar.policy.SensorPrivacyControllerImpl;
-import com.android.systemui.statusbar.policy.UserInfoController;
-import com.android.systemui.statusbar.policy.UserInfoControllerImpl;
-import com.android.systemui.statusbar.policy.ZenModeController;
-import com.android.systemui.statusbar.policy.ZenModeControllerImpl;
-import com.android.systemui.tuner.TunerService;
-import com.android.systemui.tuner.TunerServiceImpl;
-import com.android.systemui.util.RingerModeTracker;
-import com.android.systemui.util.RingerModeTrackerImpl;
-import com.android.systemui.volume.VolumeComponent;
-import com.android.systemui.volume.VolumeDialogComponent;
-import com.android.systemui.volume.VolumeDialogControllerImpl;
-
-import dagger.Binds;
-import dagger.Module;
-
-/**
- * Maps interfaces to implementations for use with Dagger.
- */
-@Module(includes = {ControlsModule.class})
-public abstract class DependencyBinder {
-
- /**
- */
- @Binds
- public abstract ActivityStarter provideActivityStarter(ActivityStarterDelegate delegate);
-
- /**
- */
- @Binds
- public abstract BluetoothController provideBluetoothController(
- BluetoothControllerImpl controllerImpl);
-
- /**
- */
- @Binds
- public abstract GlobalActions provideGlobalActions(GlobalActionsImpl controllerImpl);
-
- /**
- */
- @Binds
- public abstract GlobalActions.GlobalActionsManager provideGlobalActionsManager(
- GlobalActionsComponent controllerImpl);
-
- /**
- */
- @Binds
- public abstract LocationController provideLocationController(
- LocationControllerImpl controllerImpl);
-
- /**
- */
- @Binds
- public abstract RotationLockController provideRotationLockController(
- RotationLockControllerImpl controllerImpl);
-
- /**
- */
- @Binds
- public abstract NetworkController provideNetworkController(
- NetworkControllerImpl controllerImpl);
-
- /**
- */
- @Binds
- public abstract ZenModeController provideZenModeController(
- ZenModeControllerImpl controllerImpl);
-
- /**
- */
- @Binds
- public abstract HotspotController provideHotspotController(
- HotspotControllerImpl controllerImpl);
-
- /**
- */
- @Binds
- public abstract AppOpsController provideAppOpsController(
- AppOpsControllerImpl controllerImpl);
-
- /**
- */
- @Binds
- public abstract NotificationRemoteInputManager.Callback provideNotificationRemoteInputManager(
- StatusBarRemoteInputCallback callbackImpl);
-
- /**
- */
- @Binds
- public abstract CastController provideCastController(CastControllerImpl controllerImpl);
-
- /**
- */
- @Binds
- public abstract FlashlightController provideFlashlightController(
- FlashlightControllerImpl controllerImpl);
-
- /**
- */
- @Binds
- public abstract KeyguardStateController provideKeyguardMonitor(
- KeyguardStateControllerImpl controllerImpl);
-
- /**
- */
- @Binds
- public abstract UserInfoController provideUserInfoContrller(
- UserInfoControllerImpl controllerImpl);
-
- /**
- */
- @Binds
- public abstract ManagedProfileController provideManagedProfileController(
- ManagedProfileControllerImpl controllerImpl);
-
- /**
- */
- @Binds
- public abstract NextAlarmController provideNextAlarmController(
- NextAlarmControllerImpl controllerImpl);
-
- /**
- */
- @Binds
- public abstract SecurityController provideSecurityController(
- SecurityControllerImpl controllerImpl);
-
- /**
- */
- @Binds
- public abstract TunerService provideTunerService(TunerServiceImpl controllerImpl);
-
- /**
- */
- @Binds
- public abstract DarkIconDispatcher provideDarkIconDispatcher(
- DarkIconDispatcherImpl controllerImpl);
-
- /**
- */
- @Binds
- public abstract StatusBarStateController provideStatusBarStateController(
- StatusBarStateControllerImpl controllerImpl);
-
- /**
- */
- @Binds
- public abstract SysuiStatusBarStateController providesSysuiStatusBarStateController(
- StatusBarStateControllerImpl statusBarStateControllerImpl);
-
- /**
- */
- @Binds
- public abstract StatusBarIconController provideStatusBarIconController(
- StatusBarIconControllerImpl controllerImpl);
-
- /**
- */
- @Binds
- public abstract ExtensionController provideExtensionController(
- ExtensionControllerImpl controllerImpl);
-
- /**
- */
- @Binds
- public abstract VolumeDialogController provideVolumeDialogController(
- VolumeDialogControllerImpl controllerImpl);
-
- /**
- */
- @Binds
- public abstract PowerUI.WarningsUI provideWarningsUi(PowerNotificationWarnings controllerImpl);
-
- /**
- */
- @Binds
- public abstract SensorPrivacyController provideSensorPrivacyControllerImpl(
- SensorPrivacyControllerImpl controllerImpl);
-
- /**
- */
- @Binds
- public abstract QSHost provideQsHost(QSTileHost controllerImpl);
-
- /**
- */
- @Binds
- public abstract FalsingManager provideFalsingManager(FalsingManagerProxy falsingManagerImpl);
-
- /**
- */
- @Binds
- public abstract VolumeComponent provideVolumeComponent(
- VolumeDialogComponent volumeDialogComponent);
-
- /**
- */
- @Binds
- public abstract RingerModeTracker provideRingerModeTracker(
- RingerModeTrackerImpl ringerModeTrackerImpl);
-}
diff --git a/packages/SystemUI/src/com/android/systemui/dagger/DependencyProvider.java b/packages/SystemUI/src/com/android/systemui/dagger/DependencyProvider.java
index e5e3a1d16c01..ac01ba1539b3 100644
--- a/packages/SystemUI/src/com/android/systemui/dagger/DependencyProvider.java
+++ b/packages/SystemUI/src/com/android/systemui/dagger/DependencyProvider.java
@@ -18,6 +18,8 @@ package com.android.systemui.dagger;
import static com.android.systemui.Dependency.TIME_TICK_HANDLER_NAME;
+import android.annotation.Nullable;
+import android.annotation.SuppressLint;
import android.app.INotificationManager;
import android.content.Context;
import android.content.SharedPreferences;
@@ -26,6 +28,7 @@ import android.os.Handler;
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;
@@ -39,6 +42,7 @@ import com.android.internal.logging.UiEventLoggerImpl;
import com.android.internal.util.NotificationMessagingUtil;
import com.android.internal.widget.LockPatternUtils;
import com.android.keyguard.ViewMediatorCallback;
+import com.android.settingslib.bluetooth.LocalBluetoothManager;
import com.android.systemui.Prefs;
import com.android.systemui.accessibility.ModeSwitchesController;
import com.android.systemui.accessibility.SystemActions;
@@ -61,7 +65,6 @@ import com.android.systemui.shared.plugins.PluginManager;
import com.android.systemui.shared.plugins.PluginManagerImpl;
import com.android.systemui.shared.system.ActivityManagerWrapper;
import com.android.systemui.shared.system.DevicePolicyManagerWrapper;
-import com.android.systemui.stackdivider.SplitScreenController;
import com.android.systemui.statusbar.CommandQueue;
import com.android.systemui.statusbar.NotificationRemoteInputManager;
import com.android.systemui.statusbar.phone.AutoHideController;
@@ -74,6 +77,7 @@ import com.android.systemui.statusbar.policy.DataSaverController;
import com.android.systemui.statusbar.policy.DeviceProvisionedController;
import com.android.systemui.statusbar.policy.NetworkController;
import com.android.systemui.util.leak.LeakDetector;
+import com.android.wm.shell.splitscreen.SplitScreen;
import java.util.Optional;
import java.util.concurrent.Executor;
@@ -88,7 +92,7 @@ import dagger.Provides;
* Provides dependencies for the root component of sysui injection.
*
* Only SystemUI owned classes and instances should go in here. Other, framework-owned classes
- * should go in {@link SystemServicesModule}.
+ * should go in {@link FrameworkServicesModule}.
*
* See SystemUI/docs/dagger.md
*/
@@ -163,6 +167,15 @@ public class DependencyProvider {
}
+ @SuppressLint("MissingPermission")
+ @SysUISingleton
+ @Provides
+ @Nullable
+ static LocalBluetoothManager provideLocalBluetoothController(Context context,
+ @Background Handler bgHandler) {
+ return LocalBluetoothManager.create(context, bgHandler, UserHandle.ALL);
+ }
+
/** */
@Provides
@SysUISingleton
@@ -193,7 +206,7 @@ public class DependencyProvider {
SysUiState sysUiFlagsContainer,
BroadcastDispatcher broadcastDispatcher,
CommandQueue commandQueue,
- Optional<SplitScreenController> splitScreenControllerOptional,
+ Optional<SplitScreen> splitScreenOptional,
Optional<Recents> recentsOptional,
Lazy<StatusBar> statusBarLazy,
ShadeController shadeController,
@@ -215,7 +228,7 @@ public class DependencyProvider {
sysUiFlagsContainer,
broadcastDispatcher,
commandQueue,
- splitScreenControllerOptional,
+ splitScreenOptional,
recentsOptional,
statusBarLazy,
shadeController,
diff --git a/packages/SystemUI/src/com/android/systemui/dagger/SystemServicesModule.java b/packages/SystemUI/src/com/android/systemui/dagger/FrameworkServicesModule.java
index e7d2f125935a..66063a87a70d 100644
--- a/packages/SystemUI/src/com/android/systemui/dagger/SystemServicesModule.java
+++ b/packages/SystemUI/src/com/android/systemui/dagger/FrameworkServicesModule.java
@@ -17,7 +17,6 @@
package com.android.systemui.dagger;
import android.annotation.Nullable;
-import android.annotation.SuppressLint;
import android.app.ActivityManager;
import android.app.ActivityTaskManager;
import android.app.AlarmManager;
@@ -49,10 +48,8 @@ import android.net.ConnectivityManager;
import android.net.NetworkScoreManager;
import android.net.wifi.WifiManager;
import android.os.BatteryStats;
-import android.os.Handler;
import android.os.PowerManager;
import android.os.ServiceManager;
-import android.os.UserHandle;
import android.os.UserManager;
import android.os.Vibrator;
import android.service.dreams.DreamService;
@@ -60,6 +57,7 @@ import android.service.dreams.IDreamManager;
import android.telecom.TelecomManager;
import android.telephony.TelephonyManager;
import android.view.IWindowManager;
+import android.view.ViewConfiguration;
import android.view.WindowManager;
import android.view.WindowManagerGlobal;
import android.view.accessibility.AccessibilityManager;
@@ -67,12 +65,12 @@ import android.view.accessibility.AccessibilityManager;
import com.android.internal.app.IBatteryStats;
import com.android.internal.statusbar.IStatusBarService;
import com.android.internal.util.LatencyTracker;
-import com.android.settingslib.bluetooth.LocalBluetoothManager;
-import com.android.systemui.dagger.qualifiers.Background;
import com.android.systemui.dagger.qualifiers.DisplayId;
import com.android.systemui.dagger.qualifiers.Main;
import com.android.systemui.shared.system.PackageManagerWrapper;
+import javax.inject.Singleton;
+
import dagger.Module;
import dagger.Provides;
@@ -80,51 +78,51 @@ import dagger.Provides;
* Provides Non-SystemUI, Framework-Owned instances to the dependency graph.
*/
@Module
-public class SystemServicesModule {
+public class FrameworkServicesModule {
@Provides
- @SysUISingleton
+ @Singleton
static AccessibilityManager provideAccessibilityManager(Context context) {
return context.getSystemService(AccessibilityManager.class);
}
@Provides
- @SysUISingleton
+ @Singleton
static ActivityManager provideActivityManager(Context context) {
return context.getSystemService(ActivityManager.class);
}
- @SysUISingleton
@Provides
+ @Singleton
static AlarmManager provideAlarmManager(Context context) {
return context.getSystemService(AlarmManager.class);
}
@Provides
- @SysUISingleton
+ @Singleton
static AudioManager provideAudioManager(Context context) {
return context.getSystemService(AudioManager.class);
}
@Provides
- @SysUISingleton
+ @Singleton
static ColorDisplayManager provideColorDisplayManager(Context context) {
return context.getSystemService(ColorDisplayManager.class);
}
@Provides
- @SysUISingleton
+ @Singleton
static ConnectivityManager provideConnectivityManagager(Context context) {
return context.getSystemService(ConnectivityManager.class);
}
@Provides
- @SysUISingleton
+ @Singleton
static ContentResolver provideContentResolver(Context context) {
return context.getContentResolver();
}
@Provides
- @SysUISingleton
+ @Singleton
static DevicePolicyManager provideDevicePolicyManager(Context context) {
return context.getSystemService(DevicePolicyManager.class);
}
@@ -136,39 +134,39 @@ public class SystemServicesModule {
}
@Provides
- @SysUISingleton
+ @Singleton
static DisplayManager provideDisplayManager(Context context) {
return context.getSystemService(DisplayManager.class);
}
- @SysUISingleton
@Provides
+ @Singleton
static IActivityManager provideIActivityManager() {
return ActivityManager.getService();
}
- @SysUISingleton
@Provides
+ @Singleton
static IActivityTaskManager provideIActivityTaskManager() {
return ActivityTaskManager.getService();
}
@Provides
- @SysUISingleton
+ @Singleton
static IBatteryStats provideIBatteryStats() {
return IBatteryStats.Stub.asInterface(
ServiceManager.getService(BatteryStats.SERVICE_NAME));
}
@Provides
- @SysUISingleton
+ @Singleton
static IDreamManager provideIDreamManager() {
return IDreamManager.Stub.asInterface(
ServiceManager.checkService(DreamService.DREAM_SERVICE));
}
@Provides
- @SysUISingleton
+ @Singleton
@Nullable
static FaceManager provideFaceManager(Context context) {
return context.getSystemService(FaceManager.class);
@@ -176,13 +174,13 @@ public class SystemServicesModule {
}
@Provides
- @SysUISingleton
+ @Singleton
static IPackageManager provideIPackageManager() {
return IPackageManager.Stub.asInterface(ServiceManager.getService("package"));
}
- @SysUISingleton
@Provides
+ @Singleton
static IStatusBarService provideIStatusBarService() {
return IStatusBarService.Stub.asInterface(
ServiceManager.getService(Context.STATUS_BAR_SERVICE));
@@ -195,39 +193,30 @@ public class SystemServicesModule {
ServiceManager.getService(Context.WALLPAPER_SERVICE));
}
- @SysUISingleton
@Provides
+ @Singleton
static IWindowManager provideIWindowManager() {
return WindowManagerGlobal.getWindowManagerService();
}
- @SysUISingleton
@Provides
+ @Singleton
static KeyguardManager provideKeyguardManager(Context context) {
return context.getSystemService(KeyguardManager.class);
}
- @SysUISingleton
@Provides
+ @Singleton
static LatencyTracker provideLatencyTracker(Context context) {
return LatencyTracker.getInstance(context);
}
- @SysUISingleton
@Provides
+ @Singleton
static LauncherApps provideLauncherApps(Context context) {
return context.getSystemService(LauncherApps.class);
}
- @SuppressLint("MissingPermission")
- @SysUISingleton
- @Provides
- @Nullable
- static LocalBluetoothManager provideLocalBluetoothController(Context context,
- @Background Handler bgHandler) {
- return LocalBluetoothManager.create(context, bgHandler, UserHandle.ALL);
- }
-
@Provides
static MediaRouter2Manager provideMediaRouter2Manager(Context context) {
return MediaRouter2Manager.getInstance(context);
@@ -239,32 +228,32 @@ public class SystemServicesModule {
}
@Provides
- @SysUISingleton
+ @Singleton
static NetworkScoreManager provideNetworkScoreManager(Context context) {
return context.getSystemService(NetworkScoreManager.class);
}
- @SysUISingleton
@Provides
+ @Singleton
static NotificationManager provideNotificationManager(Context context) {
return context.getSystemService(NotificationManager.class);
}
- @SysUISingleton
@Provides
+ @Singleton
static PackageManager providePackageManager(Context context) {
return context.getPackageManager();
}
- @SysUISingleton
@Provides
+ @Singleton
static PackageManagerWrapper providePackageManagerWrapper() {
return PackageManagerWrapper.getInstance();
}
/** */
- @SysUISingleton
@Provides
+ @Singleton
static PowerManager providePowerManager(Context context) {
return context.getSystemService(PowerManager.class);
}
@@ -276,51 +265,63 @@ public class SystemServicesModule {
}
@Provides
- @SysUISingleton
+ @Singleton
+ static RoleManager provideRoleManager(Context context) {
+ return context.getSystemService(RoleManager.class);
+ }
+
+ @Provides
+ @Singleton
static SensorManager providesSensorManager(Context context) {
return context.getSystemService(SensorManager.class);
}
- @SysUISingleton
@Provides
+ @Singleton
static SensorPrivacyManager provideSensorPrivacyManager(Context context) {
return context.getSystemService(SensorPrivacyManager.class);
}
- @SysUISingleton
@Provides
+ @Singleton
static ShortcutManager provideShortcutManager(Context context) {
return context.getSystemService(ShortcutManager.class);
}
@Provides
- @SysUISingleton
+ @Singleton
@Nullable
static TelecomManager provideTelecomManager(Context context) {
return context.getSystemService(TelecomManager.class);
}
@Provides
- @SysUISingleton
+ @Singleton
static TelephonyManager provideTelephonyManager(Context context) {
return context.getSystemService(TelephonyManager.class);
}
@Provides
- @SysUISingleton
+ @Singleton
static TrustManager provideTrustManager(Context context) {
return context.getSystemService(TrustManager.class);
}
@Provides
- @SysUISingleton
+ @Singleton
@Nullable
static Vibrator provideVibrator(Context context) {
return context.getSystemService(Vibrator.class);
}
@Provides
- @SysUISingleton
+ @Singleton
+ static ViewConfiguration provideViewConfiguration(Context context) {
+ return ViewConfiguration.get(context);
+ }
+
+ @Provides
+ @Singleton
static UserManager provideUserManager(Context context) {
return context.getSystemService(UserManager.class);
}
@@ -331,21 +332,15 @@ public class SystemServicesModule {
}
@Provides
- @SysUISingleton
+ @Singleton
@Nullable
static WifiManager provideWifiManager(Context context) {
return context.getSystemService(WifiManager.class);
}
- @SysUISingleton
@Provides
+ @Singleton
static WindowManager provideWindowManager(Context context) {
return context.getSystemService(WindowManager.class);
}
-
- @Provides
- @SysUISingleton
- static RoleManager provideRoleManager(Context context) {
- return context.getSystemService(RoleManager.class);
- }
}
diff --git a/packages/SystemUI/src/com/android/systemui/dagger/GlobalModule.java b/packages/SystemUI/src/com/android/systemui/dagger/GlobalModule.java
index 553655bf672c..c5dc8cccfdf4 100644
--- a/packages/SystemUI/src/com/android/systemui/dagger/GlobalModule.java
+++ b/packages/SystemUI/src/com/android/systemui/dagger/GlobalModule.java
@@ -16,63 +16,27 @@
package com.android.systemui.dagger;
-import android.content.Context;
-import android.content.SharedPreferences;
-import android.hardware.display.AmbientDisplayConfiguration;
-import android.util.DisplayMetrics;
-import android.view.Choreographer;
-
-import com.android.systemui.Prefs;
-import com.android.systemui.dagger.qualifiers.Main;
-
-import javax.inject.Singleton;
+import com.android.systemui.util.concurrency.GlobalConcurrencyModule;
import dagger.Module;
-import dagger.Provides;
/**
- * Supplies globally scoped instances.
+ * Supplies globally scoped instances that should be available in all versions of SystemUI
*
* Providers in this module will be accessible to both WMComponent and SysUIComponent scoped
* classes. They are in here because they are either needed globally or are inherently universal
* to the application.
*
* Note that just because a class might be used by both WM and SysUI does not necessarily mean that
- * it should got into this module. If WM and SysUI might need the class for different purposes
+ * it should go into this module. If WM and SysUI might need the class for different purposes
* or different semantics, it may make sense to ask them to supply their own. Something like
* threading and concurrency provide a good example. Both components need
* Threads/Handlers/Executors, but they need separate instances of them in many cases.
*
* Please use discretion when adding things to the global scope.
*/
-@Module
+@Module(includes = {
+ FrameworkServicesModule.class,
+ GlobalConcurrencyModule.class})
public class GlobalModule {
- /** */
- @Provides
- @Main
- public SharedPreferences provideSharePreferences(Context context) {
- return Prefs.get(context);
- }
-
- /** */
- @Provides
- public AmbientDisplayConfiguration provideAmbientDisplayConfiguration(Context context) {
- return new AmbientDisplayConfiguration(context);
- }
-
- /** */
- @Provides
- @Singleton
- public Choreographer providesChoreographer() {
- return Choreographer.getInstance();
- }
-
- /** */
- @Provides
- @Singleton
- public DisplayMetrics provideDisplayMetrics(Context context) {
- DisplayMetrics displayMetrics = new DisplayMetrics();
- context.getDisplay().getMetrics(displayMetrics);
- return displayMetrics;
- }
}
diff --git a/packages/SystemUI/src/com/android/systemui/dagger/GlobalRootComponent.java b/packages/SystemUI/src/com/android/systemui/dagger/GlobalRootComponent.java
index 3d7c8ad4c43e..00fdf55b28e0 100644
--- a/packages/SystemUI/src/com/android/systemui/dagger/GlobalRootComponent.java
+++ b/packages/SystemUI/src/com/android/systemui/dagger/GlobalRootComponent.java
@@ -18,6 +18,8 @@ package com.android.systemui.dagger;
import android.content.Context;
+import com.android.systemui.util.concurrency.ThreadFactory;
+
import javax.inject.Singleton;
import dagger.BindsInstance;
@@ -28,6 +30,7 @@ import dagger.Component;
*/
@Singleton
@Component(modules = {
+ GlobalModule.class,
SysUISubcomponentModule.class,
WMModule.class})
public interface GlobalRootComponent {
@@ -52,4 +55,9 @@ public interface GlobalRootComponent {
* Builder for a SysuiComponent.
*/
SysUIComponent.Builder getSysUIComponent();
+
+ /**
+ * Build a {@link ThreadFactory}.
+ */
+ ThreadFactory createThreadFactory();
}
diff --git a/packages/SystemUI/src/com/android/systemui/dagger/PluginModule.java b/packages/SystemUI/src/com/android/systemui/dagger/PluginModule.java
new file mode 100644
index 000000000000..406981d0c4ad
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/dagger/PluginModule.java
@@ -0,0 +1,74 @@
+/*
+ * 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.dagger;
+
+import com.android.systemui.ActivityStarterDelegate;
+import com.android.systemui.classifier.FalsingManagerProxy;
+import com.android.systemui.globalactions.GlobalActionsComponent;
+import com.android.systemui.globalactions.GlobalActionsImpl;
+import com.android.systemui.plugins.ActivityStarter;
+import com.android.systemui.plugins.DarkIconDispatcher;
+import com.android.systemui.plugins.FalsingManager;
+import com.android.systemui.plugins.GlobalActions;
+import com.android.systemui.plugins.VolumeDialogController;
+import com.android.systemui.plugins.statusbar.StatusBarStateController;
+import com.android.systemui.statusbar.StatusBarStateControllerImpl;
+import com.android.systemui.statusbar.phone.DarkIconDispatcherImpl;
+import com.android.systemui.volume.VolumeDialogControllerImpl;
+
+import dagger.Binds;
+import dagger.Module;
+
+/**
+ * Module for binding Plugin implementations.
+ *
+ * TODO(b/166258224): Many of these should be moved closer to their implementations.
+ */
+@Module
+public interface PluginModule {
+
+ /** */
+ @Binds
+ ActivityStarter provideActivityStarter(ActivityStarterDelegate delegate);
+
+ /** */
+ @Binds
+ DarkIconDispatcher provideDarkIconDispatcher(DarkIconDispatcherImpl controllerImpl);
+
+ /** */
+ @Binds
+ FalsingManager provideFalsingManager(FalsingManagerProxy falsingManagerImpl);
+
+ /** */
+ @Binds
+ GlobalActions provideGlobalActions(GlobalActionsImpl controllerImpl);
+
+ /** */
+ @Binds
+ GlobalActions.GlobalActionsManager provideGlobalActionsManager(
+ GlobalActionsComponent controllerImpl);
+
+ /** */
+ @Binds
+ StatusBarStateController provideStatusBarStateController(
+ StatusBarStateControllerImpl controllerImpl);
+
+ /** */
+ @Binds
+ VolumeDialogController provideVolumeDialogController(VolumeDialogControllerImpl controllerImpl);
+
+}
diff --git a/packages/SystemUI/src/com/android/systemui/dagger/SysUIComponent.java b/packages/SystemUI/src/com/android/systemui/dagger/SysUIComponent.java
index b606201cc803..4bea0674e8bf 100644
--- a/packages/SystemUI/src/com/android/systemui/dagger/SysUIComponent.java
+++ b/packages/SystemUI/src/com/android/systemui/dagger/SysUIComponent.java
@@ -22,10 +22,10 @@ import com.android.systemui.InitController;
import com.android.systemui.SystemUIAppComponentFactory;
import com.android.systemui.dump.DumpManager;
import com.android.systemui.keyguard.KeyguardSliceProvider;
-import com.android.systemui.pip.phone.dagger.PipModule;
import com.android.systemui.statusbar.policy.ConfigurationController;
import com.android.systemui.util.InjectionInflationController;
+import dagger.BindsInstance;
import dagger.Subcomponent;
/**
@@ -35,9 +35,6 @@ import dagger.Subcomponent;
@Subcomponent(modules = {
DefaultComponentBinder.class,
DependencyProvider.class,
- DependencyBinder.class,
- PipModule.class,
- SystemServicesModule.class,
SystemUIBinder.class,
SystemUIModule.class,
SystemUIDefaultModule.class})
@@ -48,6 +45,9 @@ public interface SysUIComponent {
*/
@Subcomponent.Builder
interface Builder {
+ @BindsInstance
+ Builder setStubAPIClass(WMComponent.StubAPIClass stubAPIClass);
+
SysUIComponent build();
}
diff --git a/packages/SystemUI/src/com/android/systemui/dagger/SystemUIBinder.java b/packages/SystemUI/src/com/android/systemui/dagger/SystemUIBinder.java
index 9dfd9f8fd9bf..3a5ce4d82540 100644
--- a/packages/SystemUI/src/com/android/systemui/dagger/SystemUIBinder.java
+++ b/packages/SystemUI/src/com/android/systemui/dagger/SystemUIBinder.java
@@ -28,8 +28,6 @@ import com.android.systemui.bubbles.dagger.BubbleModule;
import com.android.systemui.globalactions.GlobalActionsComponent;
import com.android.systemui.keyguard.KeyguardViewMediator;
import com.android.systemui.keyguard.dagger.KeyguardModule;
-import com.android.systemui.onehanded.OneHandedUI;
-import com.android.systemui.pip.PipUI;
import com.android.systemui.power.PowerUI;
import com.android.systemui.recents.Recents;
import com.android.systemui.recents.RecentsModule;
@@ -91,18 +89,6 @@ public abstract class SystemUIBinder {
@ClassKey(LatencyTester.class)
public abstract SystemUI bindLatencyTester(LatencyTester sysui);
- /** Inject into OneHandedUI. */
- @Binds
- @IntoMap
- @ClassKey(OneHandedUI.class)
- public abstract SystemUI bindOneHandedUI(OneHandedUI sysui);
-
- /** Inject into PipUI. */
- @Binds
- @IntoMap
- @ClassKey(PipUI.class)
- public abstract SystemUI bindPipUI(PipUI sysui);
-
/** Inject into PowerUI. */
@Binds
@IntoMap
diff --git a/packages/SystemUI/src/com/android/systemui/dagger/SystemUIDefaultModule.java b/packages/SystemUI/src/com/android/systemui/dagger/SystemUIDefaultModule.java
index a021114c138b..2c0b04fed810 100644
--- a/packages/SystemUI/src/com/android/systemui/dagger/SystemUIDefaultModule.java
+++ b/packages/SystemUI/src/com/android/systemui/dagger/SystemUIDefaultModule.java
@@ -46,11 +46,11 @@ import com.android.systemui.statusbar.NotificationLockscreenUserManager;
import com.android.systemui.statusbar.NotificationLockscreenUserManagerImpl;
import com.android.systemui.statusbar.NotificationShadeWindowController;
import com.android.systemui.statusbar.notification.NotificationEntryManager;
+import com.android.systemui.statusbar.notification.collection.render.GroupMembershipManager;
import com.android.systemui.statusbar.phone.DozeServiceHost;
import com.android.systemui.statusbar.phone.HeadsUpManagerPhone;
import com.android.systemui.statusbar.phone.KeyguardBypassController;
import com.android.systemui.statusbar.phone.KeyguardEnvironmentImpl;
-import com.android.systemui.statusbar.phone.NotificationGroupManager;
import com.android.systemui.statusbar.phone.NotificationShadeWindowControllerImpl;
import com.android.systemui.statusbar.phone.ShadeController;
import com.android.systemui.statusbar.phone.ShadeControllerImpl;
@@ -143,7 +143,7 @@ public abstract class SystemUIDefaultModule {
Context context,
StatusBarStateController statusBarStateController,
KeyguardBypassController bypassController,
- NotificationGroupManager groupManager,
+ GroupMembershipManager groupManager,
ConfigurationController configurationController) {
return new HeadsUpManagerPhone(context, statusBarStateController, bypassController,
groupManager, configurationController);
diff --git a/packages/SystemUI/src/com/android/systemui/dagger/SystemUIModule.java b/packages/SystemUI/src/com/android/systemui/dagger/SystemUIModule.java
index e985e3d7ef90..8f4e738e5a5f 100644
--- a/packages/SystemUI/src/com/android/systemui/dagger/SystemUIModule.java
+++ b/packages/SystemUI/src/com/android/systemui/dagger/SystemUIModule.java
@@ -16,14 +16,18 @@
package com.android.systemui.dagger;
+import com.android.keyguard.dagger.KeyguardBouncerComponent;
import com.android.systemui.BootCompleteCache;
import com.android.systemui.BootCompleteCacheImpl;
+import com.android.systemui.appops.dagger.AppOpsModule;
import com.android.systemui.assist.AssistModule;
+import com.android.systemui.controls.dagger.ControlsModule;
import com.android.systemui.demomode.dagger.DemoModeModule;
import com.android.systemui.doze.dagger.DozeComponent;
import com.android.systemui.fragments.FragmentService;
import com.android.systemui.log.dagger.LogModule;
import com.android.systemui.model.SysUiState;
+import com.android.systemui.power.dagger.PowerModule;
import com.android.systemui.recents.Recents;
import com.android.systemui.screenshot.dagger.ScreenshotModule;
import com.android.systemui.settings.dagger.SettingsModule;
@@ -37,11 +41,15 @@ import com.android.systemui.statusbar.notification.row.dagger.NotificationShelfC
import com.android.systemui.statusbar.phone.StatusBar;
import com.android.systemui.statusbar.phone.dagger.StatusBarComponent;
import com.android.systemui.statusbar.policy.HeadsUpManager;
-import com.android.systemui.util.concurrency.ConcurrencyModule;
+import com.android.systemui.statusbar.policy.dagger.StatusBarPolicyModule;
+import com.android.systemui.tuner.dagger.TunerModule;
+import com.android.systemui.util.concurrency.SysUIConcurrencyModule;
+import com.android.systemui.util.dagger.UtilModule;
import com.android.systemui.util.sensors.SensorModule;
import com.android.systemui.util.settings.SettingsUtilModule;
import com.android.systemui.util.time.SystemClock;
import com.android.systemui.util.time.SystemClockImpl;
+import com.android.systemui.volume.dagger.VolumeModule;
import dagger.Binds;
import dagger.BindsOptionalOf;
@@ -53,20 +61,29 @@ import dagger.Provides;
* implementation.
*/
@Module(includes = {
+ AppOpsModule.class,
AssistModule.class,
- ConcurrencyModule.class,
+ ControlsModule.class,
DemoModeModule.class,
LogModule.class,
PeopleHubModule.class,
+ PowerModule.class,
+ PluginModule.class,
ScreenshotModule.class,
SensorModule.class,
SettingsModule.class,
- SettingsUtilModule.class
+ SettingsUtilModule.class,
+ StatusBarPolicyModule.class,
+ SysUIConcurrencyModule.class,
+ TunerModule.class,
+ UtilModule.class,
+ VolumeModule.class
},
subcomponents = {StatusBarComponent.class,
NotificationRowComponent.class,
DozeComponent.class,
ExpandableNotificationRowComponent.class,
+ KeyguardBouncerComponent.class,
NotificationShelfComponent.class,
FragmentService.FragmentCreator.class})
public abstract class SystemUIModule {
diff --git a/packages/SystemUI/src/com/android/systemui/dagger/WMComponent.java b/packages/SystemUI/src/com/android/systemui/dagger/WMComponent.java
index 929b61a3421c..ad90eff3c969 100644
--- a/packages/SystemUI/src/com/android/systemui/dagger/WMComponent.java
+++ b/packages/SystemUI/src/com/android/systemui/dagger/WMComponent.java
@@ -16,6 +16,8 @@
package com.android.systemui.dagger;
+import javax.inject.Inject;
+
import dagger.Subcomponent;
/**
@@ -32,4 +34,19 @@ public interface WMComponent {
interface Builder {
WMComponent build();
}
+
+
+ /**
+ * Example class used for passing an API to SysUI from WMShell.
+ *
+ * TODO: Remove this once real WM classes are ready to go.
+ **/
+ @WMSingleton
+ class StubAPIClass {
+ @Inject
+ StubAPIClass() {}
+ }
+
+ /** Create a StubAPIClass. */
+ StubAPIClass createStubAPIClass();
}
diff --git a/packages/SystemUI/src/com/android/systemui/doze/DozeScreenBrightness.java b/packages/SystemUI/src/com/android/systemui/doze/DozeScreenBrightness.java
index 342818de3d1e..d9f971731f29 100644
--- a/packages/SystemUI/src/com/android/systemui/doze/DozeScreenBrightness.java
+++ b/packages/SystemUI/src/com/android/systemui/doze/DozeScreenBrightness.java
@@ -30,6 +30,8 @@ import android.os.UserHandle;
import android.provider.Settings;
import android.view.Display;
+import androidx.annotation.Nullable;
+
import com.android.systemui.doze.dagger.BrightnessSensor;
import com.android.systemui.doze.dagger.DozeScope;
import com.android.systemui.doze.dagger.WrappedService;
@@ -75,7 +77,7 @@ public class DozeScreenBrightness extends BroadcastReceiver implements DozeMachi
@Inject
public DozeScreenBrightness(Context context, @WrappedService DozeMachine.Service service,
- AsyncSensorManager sensorManager, @BrightnessSensor Sensor lightSensor,
+ AsyncSensorManager sensorManager, @Nullable @BrightnessSensor Sensor lightSensor,
DozeHost host, Handler handler, AlwaysOnDisplayPolicy alwaysOnDisplayPolicy) {
mContext = context;
mDozeService = service;
diff --git a/packages/SystemUI/src/com/android/systemui/doze/DozeTriggers.java b/packages/SystemUI/src/com/android/systemui/doze/DozeTriggers.java
index e38dce05a32e..8364b486c8d7 100644
--- a/packages/SystemUI/src/com/android/systemui/doze/DozeTriggers.java
+++ b/packages/SystemUI/src/com/android/systemui/doze/DozeTriggers.java
@@ -262,11 +262,11 @@ public class DozeTriggers implements DozeMachine.Part {
onWakeScreen(wakeEvent, mMachine.isExecutingTransition() ? null : mMachine.getState());
} else if (isLongPress) {
requestPulse(pulseReason, true /* alreadyPerformedProxCheck */,
- null /* onPulseSupressedListener */);
+ null /* onPulseSuppressedListener */);
} else if (isWakeLockScreen) {
if (wakeEvent) {
requestPulse(pulseReason, true /* alreadyPerformedProxCheck */,
- null /* onPulseSupressedListener */);
+ null /* onPulseSuppressedListener */);
}
} else {
proximityCheckThenCall((result) -> {
@@ -536,7 +536,7 @@ public class DozeTriggers implements DozeMachine.Part {
if (PULSE_ACTION.equals(intent.getAction())) {
if (DozeMachine.DEBUG) Log.d(TAG, "Received pulse intent");
requestPulse(DozeLog.PULSE_REASON_INTENT, false, /* performedProxCheck */
- null /* onPulseSupressedListener */);
+ null /* onPulseSuppressedListener */);
}
if (UiModeManager.ACTION_ENTER_CAR_MODE.equals(intent.getAction())) {
mMachine.requestState(DozeMachine.State.FINISH);
diff --git a/packages/SystemUI/src/com/android/systemui/doze/dagger/DozeModule.java b/packages/SystemUI/src/com/android/systemui/doze/dagger/DozeModule.java
index 04f7c368fdc4..b89946028aeb 100644
--- a/packages/SystemUI/src/com/android/systemui/doze/dagger/DozeModule.java
+++ b/packages/SystemUI/src/com/android/systemui/doze/dagger/DozeModule.java
@@ -20,6 +20,8 @@ import android.content.Context;
import android.hardware.Sensor;
import android.os.Handler;
+import androidx.annotation.Nullable;
+
import com.android.systemui.R;
import com.android.systemui.dagger.qualifiers.Main;
import com.android.systemui.doze.DozeAuthRemover;
@@ -91,6 +93,7 @@ public abstract class DozeModule {
@Provides
@BrightnessSensor
+ @Nullable
static Sensor providesBrightnessSensor(AsyncSensorManager sensorManager, Context context) {
return DozeSensors.findSensorWithType(sensorManager,
context.getString(R.string.doze_brightness_sensor_type));
diff --git a/packages/SystemUI/src/com/android/systemui/globalactions/GlobalActionsDialog.java b/packages/SystemUI/src/com/android/systemui/globalactions/GlobalActionsDialog.java
index d213ac1132bb..3e64749c0dce 100644
--- a/packages/SystemUI/src/com/android/systemui/globalactions/GlobalActionsDialog.java
+++ b/packages/SystemUI/src/com/android/systemui/globalactions/GlobalActionsDialog.java
@@ -130,7 +130,7 @@ import com.android.systemui.model.SysUiState;
import com.android.systemui.plugins.ActivityStarter;
import com.android.systemui.plugins.GlobalActions.GlobalActionsManager;
import com.android.systemui.plugins.GlobalActionsPanelPlugin;
-import com.android.systemui.settings.CurrentUserContextTracker;
+import com.android.systemui.settings.UserContextProvider;
import com.android.systemui.statusbar.NotificationShadeDepthController;
import com.android.systemui.statusbar.NotificationShadeWindowController;
import com.android.systemui.statusbar.policy.ConfigurationController;
@@ -252,7 +252,7 @@ public class GlobalActionsDialog implements DialogInterface.OnDismissListener,
private final RingerModeTracker mRingerModeTracker;
private int mDialogPressDelay = DIALOG_PRESS_DELAY; // ms
private Handler mMainHandler;
- private CurrentUserContextTracker mCurrentUserContextTracker;
+ private UserContextProvider mUserContextProvider;
@VisibleForTesting
boolean mShowLockScreenCardsAndControls = false;
@@ -313,7 +313,7 @@ public class GlobalActionsDialog implements DialogInterface.OnDismissListener,
UiEventLogger uiEventLogger,
RingerModeTracker ringerModeTracker, SysUiState sysUiState, @Main Handler handler,
ControlsComponent controlsComponent,
- CurrentUserContextTracker currentUserContextTracker) {
+ UserContextProvider userContextProvider) {
mContext = context;
mWindowManagerFuncs = windowManagerFuncs;
mAudioManager = audioManager;
@@ -342,7 +342,7 @@ public class GlobalActionsDialog implements DialogInterface.OnDismissListener,
mControlsControllerOptional = controlsComponent.getControlsController();
mSysUiState = sysUiState;
mMainHandler = handler;
- mCurrentUserContextTracker = currentUserContextTracker;
+ mUserContextProvider = userContextProvider;
// receive broadcasts
IntentFilter filter = new IntentFilter();
@@ -436,7 +436,7 @@ public class GlobalActionsDialog implements DialogInterface.OnDismissListener,
String[] preferredControlsPackages = mContext.getResources()
.getStringArray(com.android.systemui.R.array.config_controlsPreferredPackages);
- SharedPreferences prefs = mCurrentUserContextTracker.getCurrentUserContext()
+ SharedPreferences prefs = mUserContextProvider.getUserContext()
.getSharedPreferences(PREFS_CONTROLS_FILE, Context.MODE_PRIVATE);
Set<String> seededPackages = prefs.getStringSet(PREFS_CONTROLS_SEEDING_COMPLETED,
Collections.emptySet());
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewMediator.java b/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewMediator.java
index 6214a6448287..2705f07069bf 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewMediator.java
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewMediator.java
@@ -89,15 +89,14 @@ import com.android.systemui.broadcast.BroadcastDispatcher;
import com.android.systemui.dagger.qualifiers.UiBackground;
import com.android.systemui.dump.DumpManager;
import com.android.systemui.keyguard.dagger.KeyguardModule;
+import com.android.systemui.navigationbar.NavigationModeController;
import com.android.systemui.plugins.FalsingManager;
import com.android.systemui.shared.system.QuickStepContract;
import com.android.systemui.statusbar.phone.BiometricUnlockController;
import com.android.systemui.statusbar.phone.KeyguardBypassController;
-import com.android.systemui.navigationbar.NavigationModeController;
import com.android.systemui.statusbar.phone.NotificationPanelViewController;
import com.android.systemui.statusbar.phone.StatusBar;
import com.android.systemui.util.DeviceConfigProxy;
-import com.android.systemui.util.InjectionInflationController;
import java.io.FileDescriptor;
import java.io.PrintWriter;
@@ -228,7 +227,6 @@ public class KeyguardViewMediator extends SystemUI implements Dumpable {
/** TrustManager for letting it know when we change visibility */
private final TrustManager mTrustManager;
- private final InjectionInflationController mInjectionInflationController;
/**
* Used to keep the device awake while to ensure the keyguard finishes opening before
@@ -345,7 +343,7 @@ public class KeyguardViewMediator extends SystemUI implements Dumpable {
/**
* For managing external displays
*/
- private KeyguardDisplayManager mKeyguardDisplayManager;
+ private final KeyguardDisplayManager mKeyguardDisplayManager;
private final ArrayList<IKeyguardStateCallback> mKeyguardStateCallbacks = new ArrayList<>();
@@ -724,7 +722,7 @@ public class KeyguardViewMediator extends SystemUI implements Dumpable {
TrustManager trustManager,
DeviceConfigProxy deviceConfig,
NavigationModeController navigationModeController,
- InjectionInflationController injectionInflationController) {
+ KeyguardDisplayManager keyguardDisplayManager) {
super(context);
mFalsingManager = falsingManager;
mLockPatternUtils = lockPatternUtils;
@@ -735,7 +733,7 @@ public class KeyguardViewMediator extends SystemUI implements Dumpable {
mUpdateMonitor = keyguardUpdateMonitor;
mPM = powerManager;
mTrustManager = trustManager;
- mInjectionInflationController = injectionInflationController;
+ mKeyguardDisplayManager = keyguardDisplayManager;
dumpManager.registerDumpable(getClass().getName(), this);
mDeviceConfig = deviceConfig;
mShowHomeOverLockscreen = mDeviceConfig.getBoolean(
@@ -775,9 +773,6 @@ public class KeyguardViewMediator extends SystemUI implements Dumpable {
mContext.registerReceiver(mDelayedLockBroadcastReceiver, delayedActionFilter,
SYSTEMUI_PERMISSION, null /* scheduler */);
- mKeyguardDisplayManager = new KeyguardDisplayManager(mContext,
- mInjectionInflationController);
-
mAlarmManager = (AlarmManager) mContext.getSystemService(Context.ALARM_SERVICE);
KeyguardUpdateMonitor.setCurrentUser(ActivityManager.getCurrentUser());
@@ -2189,8 +2184,8 @@ public class KeyguardViewMediator extends SystemUI implements Dumpable {
BiometricUnlockController biometricUnlockController, ViewGroup lockIconContainer,
View notificationContainer, KeyguardBypassController bypassController) {
mKeyguardViewControllerLazy.get().registerStatusBar(statusBar, container, panelView,
- biometricUnlockController, mDismissCallbackRegistry, lockIconContainer,
- notificationContainer, bypassController, mFalsingManager);
+ biometricUnlockController, lockIconContainer,
+ notificationContainer, bypassController);
return mKeyguardViewControllerLazy.get();
}
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/dagger/KeyguardModule.java b/packages/SystemUI/src/com/android/systemui/keyguard/dagger/KeyguardModule.java
index c9164f0c4459..9d8e73a0ff47 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/dagger/KeyguardModule.java
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/dagger/KeyguardModule.java
@@ -26,8 +26,10 @@ import android.os.Handler;
import android.os.PowerManager;
import com.android.internal.widget.LockPatternUtils;
+import com.android.keyguard.KeyguardDisplayManager;
import com.android.keyguard.KeyguardUpdateMonitor;
import com.android.keyguard.KeyguardViewController;
+import com.android.keyguard.dagger.KeyguardStatusViewComponent;
import com.android.systemui.broadcast.BroadcastDispatcher;
import com.android.systemui.dagger.SysUISingleton;
import com.android.systemui.dagger.qualifiers.Main;
@@ -43,7 +45,6 @@ import com.android.systemui.statusbar.NotificationShadeWindowController;
import com.android.systemui.statusbar.phone.KeyguardLiftController;
import com.android.systemui.statusbar.phone.StatusBar;
import com.android.systemui.util.DeviceConfigProxy;
-import com.android.systemui.util.InjectionInflationController;
import com.android.systemui.util.sensors.AsyncSensorManager;
import com.android.systemui.util.settings.GlobalSettings;
import com.android.systemui.util.settings.SystemSettings;
@@ -58,7 +59,7 @@ import dagger.Provides;
/**
* Dagger Module providing {@link StatusBar}.
*/
-@Module
+@Module(subcomponents = {KeyguardStatusViewComponent.class})
public class KeyguardModule {
/**
* Provides our instance of KeyguardViewMediator which is considered optional.
@@ -79,7 +80,7 @@ public class KeyguardModule {
@UiBackground Executor uiBgExecutor,
DeviceConfigProxy deviceConfig,
NavigationModeController navigationModeController,
- InjectionInflationController injectionInflationController) {
+ KeyguardDisplayManager keyguardDisplayManager) {
return new KeyguardViewMediator(
context,
falsingManager,
@@ -94,7 +95,8 @@ public class KeyguardModule {
trustManager,
deviceConfig,
navigationModeController,
- injectionInflationController);
+ keyguardDisplayManager
+ );
}
@SysUISingleton
diff --git a/packages/SystemUI/src/com/android/systemui/media/MediaCarouselController.kt b/packages/SystemUI/src/com/android/systemui/media/MediaCarouselController.kt
index a003d8365810..e5a9ac10389f 100644
--- a/packages/SystemUI/src/com/android/systemui/media/MediaCarouselController.kt
+++ b/packages/SystemUI/src/com/android/systemui/media/MediaCarouselController.kt
@@ -172,7 +172,6 @@ class MediaCarouselController @Inject constructor(
// This view is inactive, let's remove this! This happens e.g when dismissing /
// timing out a view. We still have the data around because resumption could
// be on, but we should save the resources and release this.
- oldKey?.let { MediaPlayerData.removeMediaPlayer(it) }
onMediaDataRemoved(key)
} else {
addOrUpdatePlayer(key, oldKey, data)
diff --git a/packages/SystemUI/src/com/android/systemui/media/MediaCarouselScrollHandler.kt b/packages/SystemUI/src/com/android/systemui/media/MediaCarouselScrollHandler.kt
index 77cac5023db3..486399979db7 100644
--- a/packages/SystemUI/src/com/android/systemui/media/MediaCarouselScrollHandler.kt
+++ b/packages/SystemUI/src/com/android/systemui/media/MediaCarouselScrollHandler.kt
@@ -30,6 +30,7 @@ import com.android.settingslib.Utils
import com.android.systemui.Gefingerpoken
import com.android.systemui.qs.PageIndicator
import com.android.systemui.R
+import com.android.systemui.classifier.Classifier.NOTIFICATION_DISMISS
import com.android.systemui.plugins.FalsingManager
import com.android.systemui.util.animation.PhysicsAnimator
import com.android.systemui.util.concurrency.DelayableExecutor
@@ -315,7 +316,8 @@ class MediaCarouselScrollHandler(
return false
}
- private fun isFalseTouch() = falsingProtectionNeeded && falsingManager.isFalseTouch
+ private fun isFalseTouch() = falsingProtectionNeeded &&
+ falsingManager.isFalseTouch(NOTIFICATION_DISMISS)
private fun getMaxTranslation() = if (showsSettingsButton) {
settingsButton.width
diff --git a/packages/SystemUI/src/com/android/systemui/media/MediaDataManager.kt b/packages/SystemUI/src/com/android/systemui/media/MediaDataManager.kt
index 686531acb6f9..b2ad19b5f42f 100644
--- a/packages/SystemUI/src/com/android/systemui/media/MediaDataManager.kt
+++ b/packages/SystemUI/src/com/android/systemui/media/MediaDataManager.kt
@@ -562,7 +562,10 @@ class MediaDataManager(
decoder, info, source -> decoder.isMutableRequired = true
}
} catch (e: IOException) {
- e.printStackTrace()
+ Log.e(TAG, "Unable to load bitmap", e)
+ null
+ } catch (e: RuntimeException) {
+ Log.e(TAG, "Unable to load bitmap", e)
null
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/media/SeekBarObserver.kt b/packages/SystemUI/src/com/android/systemui/media/SeekBarObserver.kt
index 1ae54d60d3fa..d789501ffdef 100644
--- a/packages/SystemUI/src/com/android/systemui/media/SeekBarObserver.kt
+++ b/packages/SystemUI/src/com/android/systemui/media/SeekBarObserver.kt
@@ -28,10 +28,14 @@ import com.android.systemui.R
*/
class SeekBarObserver(private val holder: PlayerViewHolder) : Observer<SeekBarViewModel.Progress> {
- val seekBarDefaultMaxHeight = holder.seekBar.context.resources
+ val seekBarEnabledMaxHeight = holder.seekBar.context.resources
.getDimensionPixelSize(R.dimen.qs_media_enabled_seekbar_height)
val seekBarDisabledHeight = holder.seekBar.context.resources
.getDimensionPixelSize(R.dimen.qs_media_disabled_seekbar_height)
+ val seekBarEnabledVerticalPadding = holder.seekBar.context.resources
+ .getDimensionPixelSize(R.dimen.qs_media_enabled_seekbar_vertical_padding)
+ val seekBarDisabledVerticalPadding = holder.seekBar.context.resources
+ .getDimensionPixelSize(R.dimen.qs_media_disabled_seekbar_vertical_padding)
/** Updates seek bar views when the data model changes. */
@UiThread
@@ -39,6 +43,7 @@ class SeekBarObserver(private val holder: PlayerViewHolder) : Observer<SeekBarVi
if (!data.enabled) {
if (holder.seekBar.maxHeight != seekBarDisabledHeight) {
holder.seekBar.maxHeight = seekBarDisabledHeight
+ setVerticalPadding(seekBarDisabledVerticalPadding)
}
holder.seekBar.setEnabled(false)
holder.seekBar.getThumb().setAlpha(0)
@@ -51,8 +56,9 @@ class SeekBarObserver(private val holder: PlayerViewHolder) : Observer<SeekBarVi
holder.seekBar.getThumb().setAlpha(if (data.seekAvailable) 255 else 0)
holder.seekBar.setEnabled(data.seekAvailable)
- if (holder.seekBar.maxHeight != seekBarDefaultMaxHeight) {
- holder.seekBar.maxHeight = seekBarDefaultMaxHeight
+ if (holder.seekBar.maxHeight != seekBarEnabledMaxHeight) {
+ holder.seekBar.maxHeight = seekBarEnabledMaxHeight
+ setVerticalPadding(seekBarEnabledVerticalPadding)
}
data.duration?.let {
@@ -67,4 +73,11 @@ class SeekBarObserver(private val holder: PlayerViewHolder) : Observer<SeekBarVi
it / DateUtils.SECOND_IN_MILLIS))
}
}
+
+ @UiThread
+ fun setVerticalPadding(padding: Int) {
+ val leftPadding = holder.seekBar.paddingLeft
+ val rightPadding = holder.seekBar.paddingRight
+ holder.seekBar.setPadding(leftPadding, padding, rightPadding, padding)
+ }
}
diff --git a/packages/SystemUI/src/com/android/systemui/navigationbar/NavigationBar.java b/packages/SystemUI/src/com/android/systemui/navigationbar/NavigationBar.java
index 94a2bd915016..4e0df214d884 100644
--- a/packages/SystemUI/src/com/android/systemui/navigationbar/NavigationBar.java
+++ b/packages/SystemUI/src/com/android/systemui/navigationbar/NavigationBar.java
@@ -122,7 +122,6 @@ import com.android.systemui.recents.OverviewProxyService;
import com.android.systemui.recents.Recents;
import com.android.systemui.shared.system.ActivityManagerWrapper;
import com.android.systemui.shared.system.QuickStepContract;
-import com.android.systemui.stackdivider.SplitScreenController;
import com.android.systemui.statusbar.AutoHideUiElement;
import com.android.systemui.statusbar.CommandQueue;
import com.android.systemui.statusbar.CommandQueue.Callbacks;
@@ -137,6 +136,7 @@ import com.android.systemui.statusbar.phone.StatusBar;
import com.android.systemui.statusbar.policy.AccessibilityManagerWrapper;
import com.android.systemui.statusbar.policy.BatteryController;
import com.android.systemui.statusbar.policy.DeviceProvisionedController;
+import com.android.wm.shell.splitscreen.SplitScreen;
import java.io.PrintWriter;
import java.util.List;
@@ -179,7 +179,7 @@ public class NavigationBar implements View.OnAttachStateChangeListener,
private final NavigationModeController mNavigationModeController;
private final BroadcastDispatcher mBroadcastDispatcher;
private final CommandQueue mCommandQueue;
- private final Optional<SplitScreenController> mSplitScreenControllerOptional;
+ private final Optional<SplitScreen> mSplitScreenOptional;
private final Optional<Recents> mRecentsOptional;
private final SystemActions mSystemActions;
private final Handler mHandler;
@@ -406,7 +406,7 @@ public class NavigationBar implements View.OnAttachStateChangeListener,
SysUiState sysUiFlagsContainer,
BroadcastDispatcher broadcastDispatcher,
CommandQueue commandQueue,
- Optional<SplitScreenController> splitScreenControllerOptional,
+ Optional<SplitScreen> splitScreenOptional,
Optional<Recents> recentsOptional, Lazy<StatusBar> statusBarLazy,
ShadeController shadeController,
NotificationRemoteInputManager notificationRemoteInputManager,
@@ -430,7 +430,7 @@ public class NavigationBar implements View.OnAttachStateChangeListener,
mNavBarMode = navigationModeController.addListener(this);
mBroadcastDispatcher = broadcastDispatcher;
mCommandQueue = commandQueue;
- mSplitScreenControllerOptional = splitScreenControllerOptional;
+ mSplitScreenOptional = splitScreenOptional;
mRecentsOptional = recentsOptional;
mSystemActions = systemActions;
mHandler = mainHandler;
@@ -458,10 +458,10 @@ public class NavigationBar implements View.OnAttachStateChangeListener,
lp.windowAnimations = 0;
lp.privateFlags |= WindowManager.LayoutParams.PRIVATE_FLAG_COLOR_SPACE_AGNOSTIC;
- LayoutInflater layoutInflater = LayoutInflater.from(mContext);
- NavigationBarFrame frame = (NavigationBarFrame) layoutInflater.inflate(
+ NavigationBarFrame frame = (NavigationBarFrame) LayoutInflater.from(mContext).inflate(
R.layout.navigation_bar_window, null);
- View barView = layoutInflater.inflate(R.layout.navigation_bar, frame);
+ View barView = LayoutInflater.from(frame.getContext()).inflate(
+ R.layout.navigation_bar, frame);
barView.addOnAttachStateChangeListener(this);
if (DEBUG) Log.v(TAG, "addNavigationBar: about to add " + barView);
@@ -528,7 +528,7 @@ public class NavigationBar implements View.OnAttachStateChangeListener,
}
mNavigationBarView.setNavigationIconHints(mNavigationIconHints);
mNavigationBarView.setWindowVisible(isNavBarWindowVisible());
- mSplitScreenControllerOptional.ifPresent(mNavigationBarView::registerDockedListener);
+ mSplitScreenOptional.ifPresent(mNavigationBarView::registerDockedListener);
prepareNavigationBarView();
checkNavBarModes();
@@ -662,7 +662,7 @@ public class NavigationBar implements View.OnAttachStateChangeListener,
WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE
| WindowManager.LayoutParams.FLAG_NOT_TOUCH_MODAL
| WindowManager.LayoutParams.FLAG_LAYOUT_IN_SCREEN
- | WindowManager.LayoutParams.FLAG_SPLIT_TOUCH
+ | WindowManager.LayoutParams.FLAG_NOT_TOUCHABLE
| WindowManager.LayoutParams.FLAG_SLIPPERY,
PixelFormat.TRANSLUCENT);
mOrientationParams.setTitle("SecondaryHomeHandle" + mContext.getDisplayId());
@@ -691,8 +691,8 @@ public class NavigationBar implements View.OnAttachStateChangeListener,
return;
}
- if (mStartingQuickSwitchRotation == -1 || mSplitScreenControllerOptional
- .map(SplitScreenController::isDividerVisible).orElse(false)) {
+ if (mStartingQuickSwitchRotation == -1 || mSplitScreenOptional
+ .map(SplitScreen::isDividerVisible).orElse(false)) {
// Hide the secondary home handle if we are in multiwindow since apps in multiwindow
// aren't allowed to set the display orientation
resetSecondaryHandle();
@@ -1251,7 +1251,7 @@ public class NavigationBar implements View.OnAttachStateChangeListener,
|| ActivityManager.isLowRamDeviceStatic()
// If we are connected to the overview service, then disable the recents button
|| mOverviewProxyService.getProxy() != null
- || !mSplitScreenControllerOptional.map(splitScreen ->
+ || !mSplitScreenOptional.map(splitScreen ->
splitScreen.getDividerView().getSnapAlgorithm().isSplitScreenFeasible())
.orElse(false)) {
return false;
diff --git a/packages/SystemUI/src/com/android/systemui/navigationbar/NavigationBarController.java b/packages/SystemUI/src/com/android/systemui/navigationbar/NavigationBarController.java
index 23ef71a6541e..339e504a3cf1 100644
--- a/packages/SystemUI/src/com/android/systemui/navigationbar/NavigationBarController.java
+++ b/packages/SystemUI/src/com/android/systemui/navigationbar/NavigationBarController.java
@@ -55,7 +55,6 @@ import com.android.systemui.plugins.statusbar.StatusBarStateController;
import com.android.systemui.recents.OverviewProxyService;
import com.android.systemui.recents.Recents;
import com.android.systemui.shared.system.ActivityManagerWrapper;
-import com.android.systemui.stackdivider.SplitScreenController;
import com.android.systemui.statusbar.CommandQueue;
import com.android.systemui.statusbar.CommandQueue.Callbacks;
import com.android.systemui.statusbar.NotificationRemoteInputManager;
@@ -65,6 +64,7 @@ import com.android.systemui.statusbar.phone.StatusBar;
import com.android.systemui.statusbar.policy.AccessibilityManagerWrapper;
import com.android.systemui.statusbar.policy.ConfigurationController;
import com.android.systemui.statusbar.policy.DeviceProvisionedController;
+import com.android.wm.shell.splitscreen.SplitScreen;
import java.io.FileDescriptor;
import java.io.PrintWriter;
@@ -96,7 +96,7 @@ public class NavigationBarController implements Callbacks,
private final SysUiState mSysUiFlagsContainer;
private final BroadcastDispatcher mBroadcastDispatcher;
private final CommandQueue mCommandQueue;
- private final Optional<SplitScreenController> mSplitScreenControllerOptional;
+ private final Optional<SplitScreen> mSplitScreenOptional;
private final Optional<Recents> mRecentsOptional;
private final Lazy<StatusBar> mStatusBarLazy;
private final ShadeController mShadeController;
@@ -130,7 +130,7 @@ public class NavigationBarController implements Callbacks,
SysUiState sysUiFlagsContainer,
BroadcastDispatcher broadcastDispatcher,
CommandQueue commandQueue,
- Optional<SplitScreenController> splitScreenControllerOptional,
+ Optional<SplitScreen> splitScreenOptional,
Optional<Recents> recentsOptional,
Lazy<StatusBar> statusBarLazy,
ShadeController shadeController,
@@ -152,7 +152,7 @@ public class NavigationBarController implements Callbacks,
mSysUiFlagsContainer = sysUiFlagsContainer;
mBroadcastDispatcher = broadcastDispatcher;
mCommandQueue = commandQueue;
- mSplitScreenControllerOptional = splitScreenControllerOptional;
+ mSplitScreenOptional = splitScreenOptional;
mRecentsOptional = recentsOptional;
mStatusBarLazy = statusBarLazy;
mShadeController = shadeController;
@@ -278,7 +278,7 @@ public class NavigationBarController implements Callbacks,
mSysUiFlagsContainer,
mBroadcastDispatcher,
mCommandQueue,
- mSplitScreenControllerOptional,
+ mSplitScreenOptional,
mRecentsOptional,
mStatusBarLazy,
mShadeController,
diff --git a/packages/SystemUI/src/com/android/systemui/navigationbar/NavigationBarView.java b/packages/SystemUI/src/com/android/systemui/navigationbar/NavigationBarView.java
index 7e3aa1050d10..13b9a552d75c 100644
--- a/packages/SystemUI/src/com/android/systemui/navigationbar/NavigationBarView.java
+++ b/packages/SystemUI/src/com/android/systemui/navigationbar/NavigationBarView.java
@@ -87,12 +87,12 @@ import com.android.systemui.shared.system.ActivityManagerWrapper;
import com.android.systemui.shared.system.QuickStepContract;
import com.android.systemui.shared.system.SysUiStatsLog;
import com.android.systemui.shared.system.WindowManagerWrapper;
-import com.android.systemui.stackdivider.SplitScreenController;
import com.android.systemui.statusbar.CommandQueue;
import com.android.systemui.statusbar.phone.AutoHideController;
import com.android.systemui.statusbar.phone.LightBarTransitionsController;
import com.android.systemui.statusbar.phone.NotificationPanelViewController;
import com.android.systemui.statusbar.phone.StatusBar;
+import com.android.wm.shell.splitscreen.SplitScreen;
import java.io.PrintWriter;
import java.util.function.Consumer;
@@ -329,8 +329,7 @@ public class NavigationBarView extends FrameLayout implements
mOverviewProxyService = Dependency.get(OverviewProxyService.class);
mFloatingRotationButton = new FloatingRotationButton(context);
- // TODO(165014649): Temporarily disable onboarding
- // mRecentsOnboarding = new RecentsOnboarding(context, mOverviewProxyService);
+ mRecentsOnboarding = new RecentsOnboarding(context, mOverviewProxyService);
mRotationButtonController = new RotationButtonController(mLightContext,
mLightIconColor, mDarkIconColor,
isGesturalMode ? mFloatingRotationButton : rotateSuggestionButton,
@@ -886,9 +885,7 @@ public class NavigationBarView extends FrameLayout implements
mNavBarMode = mode;
mBarTransitions.onNavigationModeChanged(mNavBarMode);
mEdgeBackGestureHandler.onNavigationModeChanged(mNavBarMode);
- if (mRecentsOnboarding != null) {
- mRecentsOnboarding.onNavigationModeChanged(mNavBarMode);
- }
+ mRecentsOnboarding.onNavigationModeChanged(mNavBarMode);
if (isGesturalMode(mNavBarMode)) {
mRegionSamplingHelper.start(mSamplingBounds);
@@ -904,9 +901,7 @@ public class NavigationBarView extends FrameLayout implements
}
void hideRecentsOnboarding() {
- if (mRecentsOnboarding != null) {
- mRecentsOnboarding.hide(true);
- }
+ mRecentsOnboarding.hide(true);
}
@Override
@@ -954,9 +949,7 @@ public class NavigationBarView extends FrameLayout implements
super.onLayout(changed, left, top, right, bottom);
notifyActiveTouchRegions();
- if (mRecentsOnboarding != null) {
- mRecentsOnboarding.setNavBarHeight(getMeasuredHeight());
- }
+ mRecentsOnboarding.setNavBarHeight(getMeasuredHeight());
}
/**
@@ -1118,9 +1111,7 @@ public class NavigationBarView extends FrameLayout implements
boolean uiCarModeChanged = updateCarMode();
updateIcons(mTmpLastConfiguration);
updateRecentsIcon();
- if (mRecentsOnboarding != null) {
- mRecentsOnboarding.onConfigurationChanged(mConfiguration);
- }
+ mRecentsOnboarding.onConfigurationChanged(mConfiguration);
if (uiCarModeChanged || mTmpLastConfiguration.densityDpi != mConfiguration.densityDpi
|| mTmpLastConfiguration.getLayoutDirection() != mConfiguration.getLayoutDirection()) {
// If car mode or density changes, we need to reset the icons.
@@ -1210,12 +1201,10 @@ public class NavigationBarView extends FrameLayout implements
}
private void setUpSwipeUpOnboarding(boolean connectedToOverviewProxy) {
- if (mRecentsOnboarding != null) {
- if (connectedToOverviewProxy) {
- mRecentsOnboarding.onConnectedToLauncher();
- } else {
- mRecentsOnboarding.onDisconnectedFromLauncher();
- }
+ if (connectedToOverviewProxy) {
+ mRecentsOnboarding.onConnectedToLauncher();
+ } else {
+ mRecentsOnboarding.onDisconnectedFromLauncher();
}
}
@@ -1261,9 +1250,7 @@ public class NavigationBarView extends FrameLayout implements
mNavigationInflaterView.dump(pw);
}
mContextualButtonGroup.dump(pw);
- if (mRecentsOnboarding != null) {
- mRecentsOnboarding.dump(pw);
- }
+ mRecentsOnboarding.dump(pw);
mRegionSamplingHelper.dump(pw);
mEdgeBackGestureHandler.dump(pw);
}
@@ -1296,8 +1283,8 @@ public class NavigationBarView extends FrameLayout implements
return super.onApplyWindowInsets(insets);
}
- void registerDockedListener(SplitScreenController splitScreenController) {
- splitScreenController.registerInSplitScreenListener(mDockedListener);
+ void registerDockedListener(SplitScreen splitScreen) {
+ splitScreen.registerInSplitScreenListener(mDockedListener);
}
private static void dumpButton(PrintWriter pw, String caption, ButtonDispatcher button) {
diff --git a/packages/SystemUI/src/com/android/systemui/navigationbar/gestural/EdgeBackGestureHandler.java b/packages/SystemUI/src/com/android/systemui/navigationbar/gestural/EdgeBackGestureHandler.java
index a1b55c428029..92d2f421d6ee 100644
--- a/packages/SystemUI/src/com/android/systemui/navigationbar/gestural/EdgeBackGestureHandler.java
+++ b/packages/SystemUI/src/com/android/systemui/navigationbar/gestural/EdgeBackGestureHandler.java
@@ -584,7 +584,7 @@ public class EdgeBackGestureHandler extends CurrentUserTracker implements Displa
}
}
- Dependency.get(ProtoTracer.class).update();
+ Dependency.get(ProtoTracer.class).scheduleFrameUpdate();
}
private void updateDisabledForQuickstep() {
diff --git a/packages/SystemUI/src/com/android/systemui/onehanded/OneHanded.java b/packages/SystemUI/src/com/android/systemui/onehanded/OneHanded.java
new file mode 100644
index 000000000000..b7c6262b07e0
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/onehanded/OneHanded.java
@@ -0,0 +1,80 @@
+/*
+ * 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.onehanded;
+
+import androidx.annotation.NonNull;
+
+import com.android.systemui.onehanded.OneHandedGestureHandler.OneHandedGestureEventCallback;
+
+import java.io.PrintWriter;
+
+/**
+ * Interface to engage one handed feature.
+ */
+public interface OneHanded {
+ /**
+ * Return whether the device has one handed feature or not.
+ */
+ boolean hasOneHandedFeature();
+
+ /**
+ * Return one handed settings enabled or not.
+ */
+ boolean isOneHandedEnabled();
+
+ /**
+ * Return swipe to notification settings enabled or not.
+ */
+ boolean isSwipeToNotificationEnabled();
+
+ /**
+ * Enters one handed mode.
+ */
+ void startOneHanded();
+
+ /**
+ * Exits one handed mode.
+ */
+ void stopOneHanded();
+
+ /**
+ * Exits one handed mode with {@link OneHandedEvents}.
+ */
+ void stopOneHanded(int event);
+
+ /**
+ * Set navigation 3 button mode enabled or disabled by users.
+ */
+ void setThreeButtonModeEnabled(boolean enabled);
+
+ /**
+ * Register callback to be notified after {@link OneHandedDisplayAreaOrganizer}
+ * transition start or finish
+ */
+ void registerTransitionCallback(OneHandedTransitionCallback callback);
+
+ /**
+ * Register callback for one handed gesture, this gesture callbcak will be activated on
+ * 3 button navigation mode only
+ */
+ void registerGestureCallback(OneHandedGestureEventCallback callback);
+
+ /**
+ * Dump one handed status.
+ */
+ void dump(@NonNull PrintWriter pw);
+}
diff --git a/packages/SystemUI/src/com/android/systemui/onehanded/OneHandedController.java b/packages/SystemUI/src/com/android/systemui/onehanded/OneHandedController.java
index bb59449d114d..90adf838440c 100644
--- a/packages/SystemUI/src/com/android/systemui/onehanded/OneHandedController.java
+++ b/packages/SystemUI/src/com/android/systemui/onehanded/OneHandedController.java
@@ -16,195 +16,262 @@
package com.android.systemui.onehanded;
+import static android.os.UserHandle.USER_CURRENT;
import static android.view.Display.DEFAULT_DISPLAY;
-import static com.android.systemui.shared.system.QuickStepContract.SYSUI_STATE_ONE_HANDED_ACTIVE;
-
-import android.content.ComponentName;
import android.content.Context;
+import android.content.om.IOverlayManager;
+import android.content.om.OverlayInfo;
+import android.database.ContentObserver;
import android.graphics.Point;
-import android.graphics.Rect;
+import android.os.Handler;
+import android.os.Looper;
+import android.os.RemoteException;
+import android.os.ServiceManager;
import android.os.SystemProperties;
-import android.view.KeyEvent;
+import android.provider.Settings;
+import android.util.Log;
import androidx.annotation.NonNull;
+import androidx.annotation.VisibleForTesting;
-import com.android.internal.annotations.VisibleForTesting;
-import com.android.systemui.Dumpable;
-import com.android.systemui.dagger.SysUISingleton;
-import com.android.systemui.model.SysUiState;
-import com.android.systemui.navigationbar.NavigationModeController;
-import com.android.systemui.shared.system.ActivityManagerWrapper;
-import com.android.systemui.shared.system.TaskStackChangeListener;
-import com.android.systemui.statusbar.CommandQueue;
+import com.android.systemui.onehanded.OneHandedGestureHandler.OneHandedGestureEventCallback;
import com.android.wm.shell.common.DisplayChangeController;
import com.android.wm.shell.common.DisplayController;
-import java.io.FileDescriptor;
import java.io.PrintWriter;
-import javax.inject.Inject;
-
/**
* Manages and manipulates the one handed states, transitions, and gesture for phones.
*/
-@SysUISingleton
-public class OneHandedController implements Dumpable {
- private static final String TAG = "OneHandedManager";
+public class OneHandedController implements OneHanded {
+ private static final String TAG = "OneHandedController";
+
private static final String ONE_HANDED_MODE_OFFSET_PERCENTAGE =
"persist.debug.one_handed_offset_percentage";
+ private static final String ONE_HANDED_MODE_GESTURAL_OVERLAY =
+ "com.android.internal.systemui.onehanded.gestural";
+
+ static final String SUPPORT_ONE_HANDED_MODE = "ro.support_one_handed_mode";
+ private final boolean mHasOneHandedFeature;
private boolean mIsOneHandedEnabled;
private boolean mIsSwipeToNotificationEnabled;
private boolean mTaskChangeToExit;
private float mOffSetFraction;
- private final CommandQueue mCommandQueue;
+ private final Context mContext;
private final DisplayController mDisplayController;
private final OneHandedGestureHandler mGestureHandler;
private final OneHandedTimeoutHandler mTimeoutHandler;
private final OneHandedTouchHandler mTouchHandler;
private final OneHandedTutorialHandler mTutorialHandler;
- private final SysUiState mSysUiFlagContainer;
+ private final IOverlayManager mOverlayManager;
+ private final Handler mMainHandler = new Handler(Looper.getMainLooper());
private OneHandedDisplayAreaOrganizer mDisplayAreaOrganizer;
/**
- * Handler for system task stack changes, exit when user lunch new task or bring task to front
+ * Handle rotation based on OnDisplayChangingListener callback
*/
- private final TaskStackChangeListener mTaskStackListener = new TaskStackChangeListener() {
+ private final DisplayChangeController.OnDisplayChangingListener mRotationController =
+ (display, fromRotation, toRotation, wct) -> {
+ if (mDisplayAreaOrganizer != null) {
+ mDisplayAreaOrganizer.onRotateDisplay(fromRotation, toRotation);
+ }
+ };
+
+ private final ContentObserver mEnabledObserver = new ContentObserver(mMainHandler) {
@Override
- public void onTaskCreated(int taskId, ComponentName componentName) {
- if (!mIsOneHandedEnabled || !mDisplayAreaOrganizer.isInOneHanded()) {
- return;
- }
- OneHandedEvents.writeEvent(OneHandedEvents.EVENT_ONE_HANDED_TRIGGER_APP_TAPS_OUT);
- stopOneHanded();
+ public void onChange(boolean selfChange) {
+ final boolean enabled = OneHandedSettingsUtil.getSettingsOneHandedModeEnabled(
+ mContext.getContentResolver());
+ OneHandedEvents.writeEvent(enabled
+ ? OneHandedEvents.EVENT_ONE_HANDED_SETTINGS_ENABLED_ON
+ : OneHandedEvents.EVENT_ONE_HANDED_SETTINGS_ENABLED_OFF);
+
+ setOneHandedEnabled(enabled);
+
+ // Also checks swipe to notification settings since they all need gesture overlay.
+ setEnabledGesturalOverlay(
+ enabled || OneHandedSettingsUtil.getSettingsSwipeToNotificationEnabled(
+ mContext.getContentResolver()));
}
+ };
+ private final ContentObserver mTimeoutObserver = new ContentObserver(mMainHandler) {
@Override
- public void onTaskMovedToFront(int taskId) {
- if (!mIsOneHandedEnabled || !mDisplayAreaOrganizer.isInOneHanded()) {
- return;
+ public void onChange(boolean selfChange) {
+ final int newTimeout = OneHandedSettingsUtil.getSettingsOneHandedModeTimeout(
+ mContext.getContentResolver());
+ int metricsId = OneHandedEvents.OneHandedSettingsTogglesEvent.INVALID.getId();
+ switch (newTimeout) {
+ case OneHandedSettingsUtil.ONE_HANDED_TIMEOUT_NEVER:
+ metricsId = OneHandedEvents.EVENT_ONE_HANDED_SETTINGS_TIMEOUT_SECONDS_NEVER;
+ break;
+ case OneHandedSettingsUtil.ONE_HANDED_TIMEOUT_SHORT_IN_SECONDS:
+ metricsId = OneHandedEvents.EVENT_ONE_HANDED_SETTINGS_TIMEOUT_SECONDS_4;
+ break;
+ case OneHandedSettingsUtil.ONE_HANDED_TIMEOUT_MEDIUM_IN_SECONDS:
+ metricsId = OneHandedEvents.EVENT_ONE_HANDED_SETTINGS_TIMEOUT_SECONDS_8;
+ break;
+ case OneHandedSettingsUtil.ONE_HANDED_TIMEOUT_LONG_IN_SECONDS:
+ metricsId = OneHandedEvents.EVENT_ONE_HANDED_SETTINGS_TIMEOUT_SECONDS_12;
+ break;
+ default:
+ // do nothing
+ break;
+ }
+ OneHandedEvents.writeEvent(metricsId);
+
+ if (mTimeoutHandler != null) {
+ mTimeoutHandler.setTimeout(newTimeout);
}
- OneHandedEvents.writeEvent(OneHandedEvents.EVENT_ONE_HANDED_TRIGGER_APP_TAPS_OUT);
- stopOneHanded();
}
};
- /**
- * Handle rotation based on OnDisplayChangingListener callback
- */
- private final DisplayChangeController.OnDisplayChangingListener mRotationController =
- (display, fromRotation, toRotation, wct) -> {
- if (mDisplayAreaOrganizer != null) {
- mDisplayAreaOrganizer.onRotateDisplay(fromRotation, toRotation);
+ private final ContentObserver mTaskChangeExitObserver = new ContentObserver(mMainHandler) {
+ @Override
+ public void onChange(boolean selfChange) {
+ final boolean enabled = OneHandedSettingsUtil.getSettingsTapsAppToExit(
+ mContext.getContentResolver());
+ OneHandedEvents.writeEvent(enabled
+ ? OneHandedEvents.EVENT_ONE_HANDED_SETTINGS_APP_TAPS_EXIT_ON
+ : OneHandedEvents.EVENT_ONE_HANDED_SETTINGS_APP_TAPS_EXIT_OFF);
+
+ setTaskChangeToExit(enabled);
+ }
+ };
+
+ private final ContentObserver mSwipeToNotificationEnabledObserver =
+ new ContentObserver(mMainHandler) {
+ @Override
+ public void onChange(boolean selfChange) {
+ final boolean enabled =
+ OneHandedSettingsUtil.getSettingsSwipeToNotificationEnabled(
+ mContext.getContentResolver());
+ setSwipeToNotificationEnabled(enabled);
+
+ // Also checks one handed mode settings since they all need gesture overlay.
+ setEnabledGesturalOverlay(
+ enabled || OneHandedSettingsUtil.getSettingsOneHandedModeEnabled(
+ mContext.getContentResolver()));
}
};
/**
- * Constructor of OneHandedManager
+ * The static constructor method to create OneHnadedController.
*/
- @Inject
- public OneHandedController(Context context,
- CommandQueue commandQueue,
- DisplayController displayController,
- NavigationModeController navigationModeController,
- SysUiState sysUiState) {
- mCommandQueue = commandQueue;
- mDisplayController = displayController;
- mDisplayController.addDisplayChangingController(mRotationController);
- mSysUiFlagContainer = sysUiState;
- mOffSetFraction = SystemProperties.getInt(ONE_HANDED_MODE_OFFSET_PERCENTAGE, 50) / 100.0f;
-
- mIsOneHandedEnabled = OneHandedSettingsUtil.getSettingsOneHandedModeEnabled(
- context.getContentResolver());
- mIsSwipeToNotificationEnabled = OneHandedSettingsUtil.getSettingsSwipeToNotificationEnabled(
- context.getContentResolver());
- mTimeoutHandler = OneHandedTimeoutHandler.get();
- mTouchHandler = new OneHandedTouchHandler();
- mTutorialHandler = new OneHandedTutorialHandler(context);
- mDisplayAreaOrganizer = new OneHandedDisplayAreaOrganizer(context, displayController,
- new OneHandedAnimationController(context), mTutorialHandler);
- mGestureHandler = new OneHandedGestureHandler(
- context, displayController, navigationModeController);
- updateOneHandedEnabled();
- setupGestures();
+ public static OneHandedController create(
+ Context context, DisplayController displayController) {
+ OneHandedTutorialHandler tutorialHandler = new OneHandedTutorialHandler(context);
+ OneHandedAnimationController animationController =
+ new OneHandedAnimationController(context);
+ OneHandedTouchHandler touchHandler = new OneHandedTouchHandler();
+ OneHandedGestureHandler gestureHandler = new OneHandedGestureHandler(
+ context, displayController);
+ OneHandedDisplayAreaOrganizer organizer = new OneHandedDisplayAreaOrganizer(
+ context, displayController, animationController, tutorialHandler);
+ return new OneHandedController(context, displayController, organizer, touchHandler,
+ tutorialHandler, gestureHandler);
}
- /**
- * Constructor of OneHandedManager for testing
- */
- // TODO(b/161980408): Should remove extra constructor.
@VisibleForTesting
OneHandedController(Context context,
- CommandQueue commandQueue,
DisplayController displayController,
OneHandedDisplayAreaOrganizer displayAreaOrganizer,
OneHandedTouchHandler touchHandler,
OneHandedTutorialHandler tutorialHandler,
- OneHandedGestureHandler gestureHandler,
- SysUiState sysUiState) {
- mCommandQueue = commandQueue;
+ OneHandedGestureHandler gestureHandler) {
+ mHasOneHandedFeature = SystemProperties.getBoolean(SUPPORT_ONE_HANDED_MODE, false);
+ if (!mHasOneHandedFeature) {
+ Log.i(TAG, "Device config SUPPORT_ONE_HANDED_MODE off");
+ mContext = null;
+ mDisplayAreaOrganizer = null;
+ mDisplayController = null;
+ mTouchHandler = null;
+ mTutorialHandler = null;
+ mGestureHandler = null;
+ mTimeoutHandler = null;
+ mOverlayManager = null;
+ return;
+ }
+
+ mContext = context;
mDisplayAreaOrganizer = displayAreaOrganizer;
mDisplayController = displayController;
- mDisplayController.addDisplayChangingController(mRotationController);
- mSysUiFlagContainer = sysUiState;
- mOffSetFraction = SystemProperties.getInt(ONE_HANDED_MODE_OFFSET_PERCENTAGE, 50) / 100.0f;
+ mTouchHandler = touchHandler;
+ mTutorialHandler = tutorialHandler;
+ mGestureHandler = gestureHandler;
+ mOverlayManager = IOverlayManager.Stub.asInterface(
+ ServiceManager.getService(Context.OVERLAY_SERVICE));
+ mOffSetFraction = SystemProperties.getInt(ONE_HANDED_MODE_OFFSET_PERCENTAGE, 50) / 100.0f;
mIsOneHandedEnabled = OneHandedSettingsUtil.getSettingsOneHandedModeEnabled(
context.getContentResolver());
mIsSwipeToNotificationEnabled = OneHandedSettingsUtil.getSettingsSwipeToNotificationEnabled(
context.getContentResolver());
mTimeoutHandler = OneHandedTimeoutHandler.get();
- mTouchHandler = touchHandler;
- mTutorialHandler = tutorialHandler;
- mGestureHandler = gestureHandler;
- updateOneHandedEnabled();
- setupGestures();
+
+ mDisplayController.addDisplayChangingController(mRotationController);
+
+ setupCallback();
+ setupSettingObservers();
+ setupTimeoutListener();
+ setupGesturalOverlay();
+ updateSettings();
}
/**
- * Set one handed enabled or disabled by OneHanded UI when user update settings
+ * Set one handed enabled or disabled when user update settings
*/
- public void setOneHandedEnabled(boolean enabled) {
+ void setOneHandedEnabled(boolean enabled) {
mIsOneHandedEnabled = enabled;
updateOneHandedEnabled();
}
/**
- * Set one handed enabled or disabled by OneHanded UI when user update settings
+ * Set one handed enabled or disabled by when user update settings
*/
- public void setTaskChangeToExit(boolean enabled) {
- if (mTaskChangeToExit == enabled) {
- return;
- }
+ void setTaskChangeToExit(boolean enabled) {
mTaskChangeToExit = enabled;
- updateOneHandedEnabled();
}
/**
* Sets whether to enable swipe bottom to notification gesture when user update settings.
*/
- public void setSwipeToNotificationEnabled(boolean enabled) {
+ void setSwipeToNotificationEnabled(boolean enabled) {
mIsSwipeToNotificationEnabled = enabled;
updateOneHandedEnabled();
}
- /**
- * Enters one handed mode.
- */
+ @Override
+ public boolean hasOneHandedFeature() {
+ return mHasOneHandedFeature;
+ }
+
+ @Override
+ public boolean isOneHandedEnabled() {
+ return mIsOneHandedEnabled;
+ }
+
+ @Override
+ public boolean isSwipeToNotificationEnabled() {
+ return mIsSwipeToNotificationEnabled;
+ }
+
+ @Override
public void startOneHanded() {
if (!mDisplayAreaOrganizer.isInOneHanded()) {
final int yOffSet = Math.round(getDisplaySize().y * mOffSetFraction);
mDisplayAreaOrganizer.scheduleOffset(0, yOffSet);
mTimeoutHandler.resetTimer();
+
+ OneHandedEvents.writeEvent(OneHandedEvents.EVENT_ONE_HANDED_TRIGGER_GESTURE_IN);
}
}
- /**
- * Exits one handed mode.
- */
+ @Override
public void stopOneHanded() {
if (mDisplayAreaOrganizer.isInOneHanded()) {
mDisplayAreaOrganizer.scheduleOffset(0, 0);
@@ -212,64 +279,72 @@ public class OneHandedController implements Dumpable {
}
}
- private void setupGestures() {
- mTouchHandler.registerTouchEventListener(
- new OneHandedTouchHandler.OneHandedTouchEventCallback() {
- @Override
- public void onStart() {
- if (mIsOneHandedEnabled) {
- startOneHanded();
- }
- }
-
- @Override
- public void onStop() {
- if (mIsOneHandedEnabled) {
- stopOneHanded();
- }
- }
- });
-
- mGestureHandler.setGestureEventListener(
- new OneHandedGestureHandler.OneHandedGestureEventCallback() {
- @Override
- public void onStart() {
- if (mIsOneHandedEnabled) {
- startOneHanded();
- } else if (mIsSwipeToNotificationEnabled) {
- mCommandQueue.handleSystemKey(KeyEvent.KEYCODE_SYSTEM_NAVIGATION_DOWN);
- }
- }
-
- @Override
- public void onStop() {
- if (mIsOneHandedEnabled) {
- stopOneHanded();
- } else if (mIsSwipeToNotificationEnabled) {
- mCommandQueue.handleSystemKey(KeyEvent.KEYCODE_SYSTEM_NAVIGATION_UP);
- }
- }
- });
-
- mDisplayAreaOrganizer.registerTransitionCallback(new OneHandedTransitionCallback() {
- @Override
- public void onStartFinished(Rect bounds) {
- mSysUiFlagContainer.setFlag(SYSUI_STATE_ONE_HANDED_ACTIVE,
- true).commitUpdate(DEFAULT_DISPLAY);
- }
+ @Override
+ public void stopOneHanded(int event) {
+ if (!mTaskChangeToExit && event == OneHandedEvents.EVENT_ONE_HANDED_TRIGGER_APP_TAPS_OUT) {
+ //Task change exit not enable, do nothing and return here.
+ return;
+ }
- @Override
- public void onStopFinished(Rect bounds) {
- mSysUiFlagContainer.setFlag(SYSUI_STATE_ONE_HANDED_ACTIVE,
- false).commitUpdate(DEFAULT_DISPLAY);
- }
- });
+ if (mDisplayAreaOrganizer.isInOneHanded()) {
+ OneHandedEvents.writeEvent(event);
+ }
+
+ stopOneHanded();
+ }
+
+ @Override
+ public void setThreeButtonModeEnabled(boolean enabled) {
+ mGestureHandler.onThreeButtonModeEnabled(enabled);
+ }
+
+ @Override
+ public void registerTransitionCallback(OneHandedTransitionCallback callback) {
+ mDisplayAreaOrganizer.registerTransitionCallback(callback);
+ }
+
+ @Override
+ public void registerGestureCallback(OneHandedGestureEventCallback callback) {
+ mGestureHandler.setGestureEventListener(callback);
+ }
+ private void setupCallback() {
+ mTouchHandler.registerTouchEventListener(() ->
+ stopOneHanded(OneHandedEvents.EVENT_ONE_HANDED_TRIGGER_OVERSPACE_OUT));
mDisplayAreaOrganizer.registerTransitionCallback(mTouchHandler);
mDisplayAreaOrganizer.registerTransitionCallback(mGestureHandler);
mDisplayAreaOrganizer.registerTransitionCallback(mTutorialHandler);
}
+ private void setupSettingObservers() {
+ OneHandedSettingsUtil.registerSettingsKeyObserver(Settings.Secure.ONE_HANDED_MODE_ENABLED,
+ mContext.getContentResolver(), mEnabledObserver);
+ OneHandedSettingsUtil.registerSettingsKeyObserver(Settings.Secure.ONE_HANDED_MODE_TIMEOUT,
+ mContext.getContentResolver(), mTimeoutObserver);
+ OneHandedSettingsUtil.registerSettingsKeyObserver(Settings.Secure.TAPS_APP_TO_EXIT,
+ mContext.getContentResolver(), mTaskChangeExitObserver);
+ OneHandedSettingsUtil.registerSettingsKeyObserver(
+ Settings.Secure.SWIPE_BOTTOM_TO_NOTIFICATION_ENABLED,
+ mContext.getContentResolver(), mSwipeToNotificationEnabledObserver);
+ }
+
+ private void updateSettings() {
+ setOneHandedEnabled(OneHandedSettingsUtil
+ .getSettingsOneHandedModeEnabled(mContext.getContentResolver()));
+ mTimeoutHandler.setTimeout(OneHandedSettingsUtil
+ .getSettingsOneHandedModeTimeout(mContext.getContentResolver()));
+ setTaskChangeToExit(OneHandedSettingsUtil
+ .getSettingsTapsAppToExit(mContext.getContentResolver()));
+ setSwipeToNotificationEnabled(OneHandedSettingsUtil
+ .getSettingsSwipeToNotificationEnabled(mContext.getContentResolver()));
+ }
+
+ private void setupTimeoutListener() {
+ mTimeoutHandler.registerTimeoutListener(timeoutTime -> {
+ stopOneHanded(OneHandedEvents.EVENT_ONE_HANDED_TRIGGER_TIMEOUT_OUT);
+ });
+ }
+
/**
* Query the current display real size from {@link DisplayController}
*
@@ -293,25 +368,73 @@ public class OneHandedController implements Dumpable {
mDisplayAreaOrganizer.registerOrganizer(
OneHandedDisplayAreaOrganizer.FEATURE_ONE_HANDED);
}
- ActivityManagerWrapper.getInstance().unregisterTaskStackListener(mTaskStackListener);
- if (mTaskChangeToExit) {
- ActivityManagerWrapper.getInstance().registerTaskStackListener(mTaskStackListener);
- }
mTouchHandler.onOneHandedEnabled(mIsOneHandedEnabled);
mGestureHandler.onOneHandedEnabled(mIsOneHandedEnabled || mIsSwipeToNotificationEnabled);
}
+ private void setupGesturalOverlay() {
+ if (!OneHandedSettingsUtil.getSettingsOneHandedModeEnabled(mContext.getContentResolver())) {
+ return;
+ }
+
+ OverlayInfo info = null;
+ try {
+ // TODO(b/157958539) migrate new RRO config file after S+
+ mOverlayManager.setHighestPriority(ONE_HANDED_MODE_GESTURAL_OVERLAY, USER_CURRENT);
+ info = mOverlayManager.getOverlayInfo(ONE_HANDED_MODE_GESTURAL_OVERLAY, USER_CURRENT);
+ } catch (RemoteException e) { /* Do nothing */ }
+
+ if (info != null && !info.isEnabled()) {
+ // Enable the default gestural one handed overlay.
+ setEnabledGesturalOverlay(true);
+ }
+ }
+
+ @androidx.annotation.VisibleForTesting
+ private void setEnabledGesturalOverlay(boolean enabled) {
+ try {
+ mOverlayManager.setEnabled(ONE_HANDED_MODE_GESTURAL_OVERLAY, enabled, USER_CURRENT);
+ } catch (RemoteException e) {
+ throw e.rethrowFromSystemServer();
+ }
+ }
+
@Override
- public void dump(@NonNull FileDescriptor fd, @NonNull PrintWriter pw, @NonNull String[] args) {
+ public void dump(@NonNull PrintWriter pw) {
final String innerPrefix = " ";
pw.println(TAG + "states: ");
- pw.print(innerPrefix + "mSysUiFlagContainer=");
- pw.println(mSysUiFlagContainer.getFlags());
pw.print(innerPrefix + "mOffSetFraction=");
pw.println(mOffSetFraction);
if (mDisplayAreaOrganizer != null) {
- mDisplayAreaOrganizer.dump(fd, pw, args);
+ mDisplayAreaOrganizer.dump(pw);
+ }
+
+ if (mTouchHandler != null) {
+ mTouchHandler.dump(pw);
+ }
+
+ if (mTimeoutHandler != null) {
+ mTimeoutHandler.dump(pw);
+ }
+
+ if (mTutorialHandler != null) {
+ mTutorialHandler.dump(pw);
+ }
+
+ OneHandedSettingsUtil.dump(pw, innerPrefix, mContext.getContentResolver());
+
+ if (mOverlayManager != null) {
+ OverlayInfo info = null;
+ try {
+ info = mOverlayManager.getOverlayInfo(ONE_HANDED_MODE_GESTURAL_OVERLAY,
+ USER_CURRENT);
+ } catch (RemoteException e) { /* Do nothing */ }
+
+ if (info != null && !info.isEnabled()) {
+ pw.print(innerPrefix + "OverlayInfo=");
+ pw.println(info);
+ }
}
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/onehanded/OneHandedDisplayAreaOrganizer.java b/packages/SystemUI/src/com/android/systemui/onehanded/OneHandedDisplayAreaOrganizer.java
index ad9f7ea4e945..ec40bad06b71 100644
--- a/packages/SystemUI/src/com/android/systemui/onehanded/OneHandedDisplayAreaOrganizer.java
+++ b/packages/SystemUI/src/com/android/systemui/onehanded/OneHandedDisplayAreaOrganizer.java
@@ -38,10 +38,8 @@ import androidx.annotation.Nullable;
import androidx.annotation.VisibleForTesting;
import com.android.internal.os.SomeArgs;
-import com.android.systemui.Dumpable;
import com.android.wm.shell.common.DisplayController;
-import java.io.FileDescriptor;
import java.io.PrintWriter;
import java.util.ArrayList;
import java.util.HashMap;
@@ -58,7 +56,7 @@ import java.util.Objects;
*
* This class is also responsible for translating one handed operations within SysUI component
*/
-public class OneHandedDisplayAreaOrganizer extends DisplayAreaOrganizer implements Dumpable {
+public class OneHandedDisplayAreaOrganizer extends DisplayAreaOrganizer {
private static final String TAG = "OneHandedDisplayAreaOrganizer";
private static final String ONE_HANDED_MODE_TRANSLATE_ANIMATION_DURATION =
"persist.debug.one_handed_translate_animation_duration";
@@ -353,8 +351,7 @@ public class OneHandedDisplayAreaOrganizer extends DisplayAreaOrganizer implemen
return args;
}
- @Override
- public void dump(@NonNull FileDescriptor fd, @NonNull PrintWriter pw, @NonNull String[] args) {
+ void dump(@NonNull PrintWriter pw) {
final String innerPrefix = " ";
pw.println(TAG + "states: ");
pw.print(innerPrefix + "mIsInOneHanded=");
diff --git a/packages/SystemUI/src/com/android/systemui/onehanded/OneHandedGestureHandler.java b/packages/SystemUI/src/com/android/systemui/onehanded/OneHandedGestureHandler.java
index f3be699ab821..4a493ba800ba 100644
--- a/packages/SystemUI/src/com/android/systemui/onehanded/OneHandedGestureHandler.java
+++ b/packages/SystemUI/src/com/android/systemui/onehanded/OneHandedGestureHandler.java
@@ -17,7 +17,6 @@
package com.android.systemui.onehanded;
import static android.view.Display.DEFAULT_DISPLAY;
-import static android.view.WindowManagerPolicyConstants.NAV_BAR_MODE_3BUTTON;
import android.annotation.Nullable;
import android.content.Context;
@@ -40,7 +39,6 @@ import android.window.WindowContainerTransaction;
import androidx.annotation.VisibleForTesting;
import com.android.systemui.R;
-import com.android.systemui.navigationbar.NavigationModeController;
import com.android.wm.shell.common.DisplayChangeController;
import com.android.wm.shell.common.DisplayController;
@@ -49,7 +47,6 @@ import com.android.wm.shell.common.DisplayController;
* others(e.g, 2-button, full gesture mode) are handled by Launcher quick steps.
*/
public class OneHandedGestureHandler implements OneHandedTransitionCallback,
- NavigationModeController.ModeChangedListener,
DisplayChangeController.OnDisplayChangingListener {
private static final String TAG = "OneHandedGestureHandler";
private static final boolean DEBUG_GESTURE = false;
@@ -66,7 +63,7 @@ public class OneHandedGestureHandler implements OneHandedTransitionCallback,
private boolean mAllowGesture;
private boolean mIsEnabled;
private int mNavGestureHeight;
- private boolean mIsThreeButtonModeEnable;
+ private boolean mIsThreeButtonModeEnabled;
private int mRotation = Surface.ROTATION_0;
@VisibleForTesting
@@ -85,14 +82,10 @@ public class OneHandedGestureHandler implements OneHandedTransitionCallback,
*
* @param context {@link Context}
* @param displayController {@link DisplayController}
- * @param navigationModeController {@link NavigationModeController}
*/
- public OneHandedGestureHandler(Context context, DisplayController displayController,
- NavigationModeController navigationModeController) {
+ public OneHandedGestureHandler(Context context, DisplayController displayController) {
mDisplayController = displayController;
displayController.addDisplayChangingController(this);
- final int NavBarMode = navigationModeController.addListener(this);
- mIsThreeButtonModeEnable = (NavBarMode == NAV_BAR_MODE_3BUTTON);
mNavGestureHeight = context.getResources().getDimensionPixelSize(
com.android.internal.R.dimen.navigation_bar_gesture_height);
mDragDistThreshold = context.getResources().getDimensionPixelSize(
@@ -115,6 +108,11 @@ public class OneHandedGestureHandler implements OneHandedTransitionCallback,
updateIsEnabled();
}
+ void onThreeButtonModeEnabled(boolean isEnabled) {
+ mIsThreeButtonModeEnabled = isEnabled;
+ updateIsEnabled();
+ }
+
/**
* Register {@link OneHandedGestureEventCallback} to receive onStart(), onStop() callback
*/
@@ -199,7 +197,7 @@ public class OneHandedGestureHandler implements OneHandedTransitionCallback,
private void updateIsEnabled() {
disposeInputChannel();
- if (mIsEnabled && mIsThreeButtonModeEnable) {
+ if (mIsEnabled && mIsThreeButtonModeEnabled) {
final Point displaySize = new Point();
if (mDisplayController != null) {
final Display display = mDisplayController.getDisplay(DEFAULT_DISPLAY);
@@ -224,15 +222,6 @@ public class OneHandedGestureHandler implements OneHandedTransitionCallback,
}
@Override
- public void onNavigationModeChanged(int mode) {
- if (DEBUG_GESTURE) {
- Log.d(TAG, "onNavigationModeChanged, mode =" + mode);
- }
- mIsThreeButtonModeEnable = (mode == NAV_BAR_MODE_3BUTTON);
- updateIsEnabled();
- }
-
- @Override
public void onRotateDisplay(int displayId, int fromRotation, int toRotation,
WindowContainerTransaction t) {
mRotation = toRotation;
diff --git a/packages/SystemUI/src/com/android/systemui/onehanded/OneHandedTimeoutHandler.java b/packages/SystemUI/src/com/android/systemui/onehanded/OneHandedTimeoutHandler.java
index 6bed30425c55..21329ea1b0e6 100644
--- a/packages/SystemUI/src/com/android/systemui/onehanded/OneHandedTimeoutHandler.java
+++ b/packages/SystemUI/src/com/android/systemui/onehanded/OneHandedTimeoutHandler.java
@@ -25,9 +25,6 @@ import android.os.Message;
import androidx.annotation.NonNull;
import androidx.annotation.VisibleForTesting;
-import com.android.systemui.Dumpable;
-
-import java.io.FileDescriptor;
import java.io.PrintWriter;
import java.util.ArrayList;
import java.util.List;
@@ -36,7 +33,7 @@ import java.util.concurrent.TimeUnit;
/**
* Timeout handler for stop one handed mode operations.
*/
-public class OneHandedTimeoutHandler implements Dumpable {
+public class OneHandedTimeoutHandler {
private static final String TAG = "OneHandedTimeoutHandler";
private static boolean sIsDragging = false;
// Default timeout is ONE_HANDED_TIMEOUT_MEDIUM
@@ -150,8 +147,7 @@ public class OneHandedTimeoutHandler implements Dumpable {
}
}
- @Override
- public void dump(@NonNull FileDescriptor fd, @NonNull PrintWriter pw, @NonNull String[] args) {
+ void dump(@NonNull PrintWriter pw) {
final String innerPrefix = " ";
pw.println(TAG + "states: ");
pw.print(innerPrefix + "sTimeout=");
diff --git a/packages/SystemUI/src/com/android/systemui/onehanded/OneHandedTouchHandler.java b/packages/SystemUI/src/com/android/systemui/onehanded/OneHandedTouchHandler.java
index 8265da6a5f14..3d28a426f4f8 100644
--- a/packages/SystemUI/src/com/android/systemui/onehanded/OneHandedTouchHandler.java
+++ b/packages/SystemUI/src/com/android/systemui/onehanded/OneHandedTouchHandler.java
@@ -30,9 +30,6 @@ import android.view.MotionEvent;
import androidx.annotation.NonNull;
import androidx.annotation.VisibleForTesting;
-import com.android.systemui.Dumpable;
-
-import java.io.FileDescriptor;
import java.io.PrintWriter;
/**
@@ -40,7 +37,7 @@ import java.io.PrintWriter;
* to exit, reset timer when user is in one-handed mode.
* Refer {@link OneHandedGestureHandler} to see start and stop one handed gesture
*/
-public class OneHandedTouchHandler implements OneHandedTransitionCallback, Dumpable {
+public class OneHandedTouchHandler implements OneHandedTransitionCallback {
private static final String TAG = "OneHandedTouchHandler";
private final Rect mLastUpdatedBounds = new Rect();
@@ -146,8 +143,7 @@ public class OneHandedTouchHandler implements OneHandedTransitionCallback, Dumpa
mIsOnStopTransitioning = false;
}
- @Override
- public void dump(@NonNull FileDescriptor fd, @NonNull PrintWriter pw, @NonNull String[] args) {
+ void dump(@NonNull PrintWriter pw) {
final String innerPrefix = " ";
pw.println(TAG + "states: ");
pw.print(innerPrefix + "mLastUpdatedBounds=");
@@ -170,11 +166,6 @@ public class OneHandedTouchHandler implements OneHandedTransitionCallback, Dumpa
*/
public interface OneHandedTouchEventCallback {
/**
- * Handle the start event.
- */
- void onStart();
-
- /**
* Handle the exit event.
*/
void onStop();
diff --git a/packages/SystemUI/src/com/android/systemui/onehanded/OneHandedTutorialHandler.java b/packages/SystemUI/src/com/android/systemui/onehanded/OneHandedTutorialHandler.java
index 0354c727c92c..beccf3dbc8de 100644
--- a/packages/SystemUI/src/com/android/systemui/onehanded/OneHandedTutorialHandler.java
+++ b/packages/SystemUI/src/com/android/systemui/onehanded/OneHandedTutorialHandler.java
@@ -33,10 +33,8 @@ import android.widget.FrameLayout;
import androidx.annotation.NonNull;
-import com.android.systemui.Dumpable;
import com.android.systemui.R;
-import java.io.FileDescriptor;
import java.io.PrintWriter;
/**
@@ -45,7 +43,7 @@ import java.io.PrintWriter;
* Refer {@link OneHandedGestureHandler} and {@link OneHandedTouchHandler} to see start and stop
* one handed gesture
*/
-public class OneHandedTutorialHandler implements OneHandedTransitionCallback, Dumpable {
+public class OneHandedTutorialHandler implements OneHandedTransitionCallback {
private static final String TAG = "OneHandedTutorialHandler";
private static final String ONE_HANDED_MODE_OFFSET_PERCENTAGE =
"persist.debug.one_handed_offset_percentage";
@@ -158,7 +156,9 @@ public class OneHandedTutorialHandler implements OneHandedTransitionCallback, Du
final WindowManager.LayoutParams lp = new WindowManager.LayoutParams(
mDisplaySize.x, mTutorialAreaHeight, 0, 0,
WindowManager.LayoutParams.TYPE_NAVIGATION_BAR_PANEL,
- WindowManager.LayoutParams.FLAG_LAYOUT_IN_SCREEN,
+ WindowManager.LayoutParams.FLAG_LAYOUT_IN_SCREEN
+ | WindowManager.LayoutParams.FLAG_NOT_TOUCHABLE
+ | WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE,
PixelFormat.TRANSLUCENT);
lp.gravity = Gravity.TOP | Gravity.LEFT;
lp.privateFlags |= WindowManager.LayoutParams.SYSTEM_FLAG_SHOW_FOR_ALL_USERS;
@@ -168,8 +168,7 @@ public class OneHandedTutorialHandler implements OneHandedTransitionCallback, Du
return lp;
}
- @Override
- public void dump(@NonNull FileDescriptor fd, @NonNull PrintWriter pw, @NonNull String[] args) {
+ void dump(@NonNull PrintWriter pw) {
final String innerPrefix = " ";
pw.println(TAG + "states: ");
pw.print(innerPrefix + "mLastUpdatedBounds=");
diff --git a/packages/SystemUI/src/com/android/systemui/onehanded/OneHandedUI.java b/packages/SystemUI/src/com/android/systemui/onehanded/OneHandedUI.java
deleted file mode 100644
index 3348a06d5cac..000000000000
--- a/packages/SystemUI/src/com/android/systemui/onehanded/OneHandedUI.java
+++ /dev/null
@@ -1,340 +0,0 @@
-/*
- * Copyright (C) 2020 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.systemui.onehanded;
-
-import static android.os.UserHandle.USER_CURRENT;
-import static android.view.Display.DEFAULT_DISPLAY;
-
-import android.content.Context;
-import android.content.om.IOverlayManager;
-import android.content.om.OverlayInfo;
-import android.database.ContentObserver;
-import android.inputmethodservice.InputMethodService;
-import android.os.Handler;
-import android.os.IBinder;
-import android.os.Looper;
-import android.os.RemoteException;
-import android.os.ServiceManager;
-import android.os.SystemProperties;
-import android.provider.Settings;
-import android.util.Log;
-
-import androidx.annotation.VisibleForTesting;
-
-import com.android.keyguard.KeyguardUpdateMonitor;
-import com.android.keyguard.KeyguardUpdateMonitorCallback;
-import com.android.systemui.Dependency;
-import com.android.systemui.Dumpable;
-import com.android.systemui.SystemUI;
-import com.android.systemui.dagger.SysUISingleton;
-import com.android.systemui.keyguard.ScreenLifecycle;
-import com.android.systemui.statusbar.CommandQueue;
-
-import java.io.FileDescriptor;
-import java.io.PrintWriter;
-
-import javax.inject.Inject;
-
-/**
- * A service that controls UI of the one handed mode function.
- */
-@SysUISingleton
-public class OneHandedUI extends SystemUI implements CommandQueue.Callbacks, Dumpable {
- private static final String TAG = "OneHandedUI";
- private static final String ONE_HANDED_MODE_GESTURAL_OVERLAY =
- "com.android.internal.systemui.onehanded.gestural";
- private static final String SUPPORT_ONE_HANDED_MODE = "ro.support_one_handed_mode";
-
- private final OneHandedController mOneHandedController;
- private final CommandQueue mCommandQueue;
- private final Handler mMainHandler = new Handler(Looper.getMainLooper());
- private final IOverlayManager mOverlayManager;
- private final OneHandedTimeoutHandler mTimeoutHandler;
- private final ScreenLifecycle mScreenLifecycle;
-
- private final ContentObserver mEnabledObserver = new ContentObserver(mMainHandler) {
- @Override
- public void onChange(boolean selfChange) {
- final boolean enabled = OneHandedSettingsUtil.getSettingsOneHandedModeEnabled(
- mContext.getContentResolver());
- OneHandedEvents.writeEvent(enabled
- ? OneHandedEvents.EVENT_ONE_HANDED_SETTINGS_ENABLED_ON
- : OneHandedEvents.EVENT_ONE_HANDED_SETTINGS_ENABLED_OFF);
- if (mOneHandedController != null) {
- mOneHandedController.setOneHandedEnabled(enabled);
- }
-
- // Also checks swipe to notification settings since they all need gesture overlay.
- setEnabledGesturalOverlay(
- enabled || OneHandedSettingsUtil.getSettingsSwipeToNotificationEnabled(
- mContext.getContentResolver()));
- }
- };
-
- private final ContentObserver mTimeoutObserver = new ContentObserver(mMainHandler) {
- @Override
- public void onChange(boolean selfChange) {
- final int newTimeout = OneHandedSettingsUtil.getSettingsOneHandedModeTimeout(
- mContext.getContentResolver());
- int metricsId = OneHandedEvents.OneHandedSettingsTogglesEvent.INVALID.getId();
- switch (newTimeout) {
- case OneHandedSettingsUtil.ONE_HANDED_TIMEOUT_NEVER:
- metricsId = OneHandedEvents.EVENT_ONE_HANDED_SETTINGS_TIMEOUT_SECONDS_NEVER;
- break;
- case OneHandedSettingsUtil.ONE_HANDED_TIMEOUT_SHORT_IN_SECONDS:
- metricsId = OneHandedEvents.EVENT_ONE_HANDED_SETTINGS_TIMEOUT_SECONDS_4;
- break;
- case OneHandedSettingsUtil.ONE_HANDED_TIMEOUT_MEDIUM_IN_SECONDS:
- metricsId = OneHandedEvents.EVENT_ONE_HANDED_SETTINGS_TIMEOUT_SECONDS_8;
- break;
- case OneHandedSettingsUtil.ONE_HANDED_TIMEOUT_LONG_IN_SECONDS:
- metricsId = OneHandedEvents.EVENT_ONE_HANDED_SETTINGS_TIMEOUT_SECONDS_12;
- break;
- default:
- // do nothing
- break;
- }
- OneHandedEvents.writeEvent(metricsId);
-
- if (mTimeoutHandler != null) {
- mTimeoutHandler.setTimeout(newTimeout);
- }
- }
- };
-
- private final ContentObserver mTaskChangeExitObserver = new ContentObserver(mMainHandler) {
- @Override
- public void onChange(boolean selfChange) {
- final boolean enabled = OneHandedSettingsUtil.getSettingsTapsAppToExit(
- mContext.getContentResolver());
- OneHandedEvents.writeEvent(enabled
- ? OneHandedEvents.EVENT_ONE_HANDED_SETTINGS_APP_TAPS_EXIT_ON
- : OneHandedEvents.EVENT_ONE_HANDED_SETTINGS_APP_TAPS_EXIT_OFF);
-
- if (mOneHandedController != null) {
- mOneHandedController.setTaskChangeToExit(enabled);
- }
- }
- };
-
- private final ContentObserver mSwipeToNotificationEnabledObserver =
- new ContentObserver(mMainHandler) {
- @Override
- public void onChange(boolean selfChange) {
- final boolean enabled =
- OneHandedSettingsUtil.getSettingsSwipeToNotificationEnabled(
- mContext.getContentResolver());
- if (mOneHandedController != null) {
- mOneHandedController.setSwipeToNotificationEnabled(enabled);
- }
-
- // Also checks one handed mode settings since they all need gesture overlay.
- setEnabledGesturalOverlay(
- enabled || OneHandedSettingsUtil.getSettingsOneHandedModeEnabled(
- mContext.getContentResolver()));
- }
- };
-
- @Inject
- public OneHandedUI(Context context,
- CommandQueue commandQueue,
- OneHandedController oneHandedController,
- ScreenLifecycle screenLifecycle) {
- super(context);
-
- if (!SystemProperties.getBoolean(SUPPORT_ONE_HANDED_MODE, false)) {
- Log.i(TAG, "Device config SUPPORT_ONE_HANDED_MODE off");
- mCommandQueue = null;
- mOneHandedController = null;
- mOverlayManager = null;
- mTimeoutHandler = null;
- mScreenLifecycle = null;
- return;
- }
-
- mCommandQueue = commandQueue;
- mOneHandedController = oneHandedController;
- mTimeoutHandler = OneHandedTimeoutHandler.get();
- mScreenLifecycle = screenLifecycle;
- mOverlayManager = IOverlayManager.Stub.asInterface(
- ServiceManager.getService(Context.OVERLAY_SERVICE));
- }
-
- @Override
- public void start() {
- if (!SystemProperties.getBoolean(SUPPORT_ONE_HANDED_MODE, false)) {
- return;
- }
- mCommandQueue.addCallback(this);
- setupKeyguardUpdateMonitor();
- setupScreenObserver();
- setupSettingObservers();
- setupTimeoutListener();
- setupGesturalOverlay();
- updateSettings();
- }
-
- private void setupGesturalOverlay() {
- if (!OneHandedSettingsUtil.getSettingsOneHandedModeEnabled(mContext.getContentResolver())) {
- return;
- }
-
- OverlayInfo info = null;
- try {
- // TODO(b/157958539) migrate new RRO config file after S+
- mOverlayManager.setHighestPriority(ONE_HANDED_MODE_GESTURAL_OVERLAY, USER_CURRENT);
- info = mOverlayManager.getOverlayInfo(ONE_HANDED_MODE_GESTURAL_OVERLAY, USER_CURRENT);
- } catch (RemoteException e) { /* Do nothing */ }
-
- if (info != null && !info.isEnabled()) {
- // Enable the default gestural one handed overlay.
- setEnabledGesturalOverlay(true);
- }
- }
-
- private void setupTimeoutListener() {
- mTimeoutHandler.registerTimeoutListener(timeoutTime -> {
- OneHandedEvents.writeEvent(OneHandedEvents.EVENT_ONE_HANDED_TRIGGER_TIMEOUT_OUT);
- stopOneHanded();
- });
- }
-
- private void setupKeyguardUpdateMonitor() {
- final KeyguardUpdateMonitorCallback keyguardCallback =
- new KeyguardUpdateMonitorCallback() {
- @Override
- public void onKeyguardBouncerChanged(boolean bouncer) {
- if (bouncer) {
- stopOneHanded();
- }
- }
-
- @Override
- public void onKeyguardVisibilityChanged(boolean showing) {
- stopOneHanded();
- }
- };
- Dependency.get(KeyguardUpdateMonitor.class).registerCallback(keyguardCallback);
- }
-
- @Override
- public void onCameraLaunchGestureDetected(int source) {
- stopOneHanded();
- }
-
- private void setupScreenObserver() {
- final ScreenLifecycle.Observer mScreenObserver = new ScreenLifecycle.Observer() {
- @Override
- public void onScreenTurningOff() {
- OneHandedEvents.writeEvent(OneHandedEvents.EVENT_ONE_HANDED_TRIGGER_SCREEN_OFF_OUT);
- stopOneHanded();
- }
- };
- mScreenLifecycle.addObserver(mScreenObserver);
- }
-
- private void setupSettingObservers() {
- OneHandedSettingsUtil.registerSettingsKeyObserver(Settings.Secure.ONE_HANDED_MODE_ENABLED,
- mContext.getContentResolver(), mEnabledObserver);
- OneHandedSettingsUtil.registerSettingsKeyObserver(Settings.Secure.ONE_HANDED_MODE_TIMEOUT,
- mContext.getContentResolver(), mTimeoutObserver);
- OneHandedSettingsUtil.registerSettingsKeyObserver(Settings.Secure.TAPS_APP_TO_EXIT,
- mContext.getContentResolver(), mTaskChangeExitObserver);
- OneHandedSettingsUtil.registerSettingsKeyObserver(
- Settings.Secure.SWIPE_BOTTOM_TO_NOTIFICATION_ENABLED,
- mContext.getContentResolver(), mSwipeToNotificationEnabledObserver);
- }
-
- private void updateSettings() {
- mOneHandedController.setOneHandedEnabled(OneHandedSettingsUtil
- .getSettingsOneHandedModeEnabled(mContext.getContentResolver()));
- mTimeoutHandler.setTimeout(OneHandedSettingsUtil
- .getSettingsOneHandedModeTimeout(mContext.getContentResolver()));
- mOneHandedController.setTaskChangeToExit(OneHandedSettingsUtil
- .getSettingsTapsAppToExit(mContext.getContentResolver()));
- mOneHandedController.setSwipeToNotificationEnabled(OneHandedSettingsUtil
- .getSettingsSwipeToNotificationEnabled(mContext.getContentResolver()));
- }
-
- @Override
- public void setImeWindowStatus(int displayId, IBinder token, int vis, int backDisposition,
- boolean showImeSwitcher) {
- if (displayId != DEFAULT_DISPLAY) {
- return;
- }
- if ((vis & InputMethodService.IME_VISIBLE) != 0) {
- OneHandedEvents.writeEvent(OneHandedEvents.EVENT_ONE_HANDED_TRIGGER_POP_IME_OUT);
- stopOneHanded();
- }
- }
-
- @VisibleForTesting
- private void setEnabledGesturalOverlay(boolean enabled) {
- try {
- mOverlayManager.setEnabled(ONE_HANDED_MODE_GESTURAL_OVERLAY, enabled, USER_CURRENT);
- } catch (RemoteException e) {
- throw e.rethrowFromSystemServer();
- }
- }
-
- /**
- * Trigger one handed more
- */
- public void startOneHanded() {
- mOneHandedController.startOneHanded();
- OneHandedEvents.writeEvent(OneHandedEvents.EVENT_ONE_HANDED_TRIGGER_GESTURE_IN);
- }
-
- /**
- * Dismiss one handed more
- */
- public void stopOneHanded() {
- mOneHandedController.stopOneHanded();
- OneHandedEvents.writeEvent(OneHandedEvents.EVENT_ONE_HANDED_TRIGGER_GESTURE_OUT);
- }
-
- /**
- * Dump all one handed data of states
- */
- public void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
- final String innerPrefix = " ";
- pw.println(TAG + "one handed states: ");
-
- if (mOneHandedController != null) {
- mOneHandedController.dump(fd, pw, args);
- }
-
- if (mTimeoutHandler != null) {
- mTimeoutHandler.dump(fd, pw, args);
- }
-
- OneHandedSettingsUtil.dump(pw, innerPrefix, mContext.getContentResolver());
-
- if (mOverlayManager != null) {
- OverlayInfo info = null;
- try {
- info = mOverlayManager.getOverlayInfo(ONE_HANDED_MODE_GESTURAL_OVERLAY,
- USER_CURRENT);
- } catch (RemoteException e) { /* Do nothing */ }
-
- if (info != null && !info.isEnabled()) {
- pw.print(innerPrefix + "OverlayInfo=");
- pw.println(info);
- }
- }
- }
-}
diff --git a/packages/SystemUI/src/com/android/systemui/pip/BasePipManager.java b/packages/SystemUI/src/com/android/systemui/pip/BasePipManager.java
deleted file mode 100644
index 38744fe1b670..000000000000
--- a/packages/SystemUI/src/com/android/systemui/pip/BasePipManager.java
+++ /dev/null
@@ -1,35 +0,0 @@
-/*
- * 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.
- */
-
-package com.android.systemui.pip;
-
-import android.content.res.Configuration;
-
-import com.android.systemui.shared.recents.IPinnedStackAnimationListener;
-
-import java.io.PrintWriter;
-
-
-public interface BasePipManager {
- void showPictureInPictureMenu();
- default void expandPip() {}
- default void hidePipMenu(Runnable onStartCallback, Runnable onEndCallback) {}
- void onConfigurationChanged(Configuration newConfig);
- default void setShelfHeight(boolean visible, int height) {}
- default void setPinnedStackAnimationType(int animationType) {}
- default void setPinnedStackAnimationListener(IPinnedStackAnimationListener listener) {}
- default void dump(PrintWriter pw) {}
-}
diff --git a/packages/SystemUI/src/com/android/systemui/pip/Pip.java b/packages/SystemUI/src/com/android/systemui/pip/Pip.java
new file mode 100644
index 000000000000..b068370da9e3
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/pip/Pip.java
@@ -0,0 +1,170 @@
+/*
+ * 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.
+ */
+
+package com.android.systemui.pip;
+
+import android.content.res.Configuration;
+import android.media.session.MediaController;
+
+import com.android.systemui.pip.tv.PipController;
+import com.android.systemui.shared.recents.IPinnedStackAnimationListener;
+
+import java.io.PrintWriter;
+
+/**
+ * Interface to engage picture in picture feature.
+ */
+public interface Pip {
+ /**
+ * Called when showing Pip menu.
+ */
+ void showPictureInPictureMenu();
+
+ /**
+ * Registers {@link com.android.systemui.pip.tv.PipController.Listener} that gets called.
+ * whenever receiving notification on changes in PIP.
+ */
+ default void addListener(PipController.Listener listener) {
+ }
+
+ /**
+ * Registers a {@link com.android.systemui.pip.tv.PipController.MediaListener} to PipController.
+ */
+ default void addMediaListener(PipController.MediaListener listener) {
+ }
+
+ /**
+ * Closes PIP (PIPed activity and PIP system UI).
+ */
+ default void closePip() {
+ }
+
+ /**
+ * Expand PIP, it's possible that specific request to activate the window via Alt-tab.
+ */
+ default void expandPip() {
+ }
+
+ /**
+ * Get current play back state. (e.g: Used in TV)
+ *
+ * @return The state of defined in PipController.
+ */
+ default int getPlaybackState() {
+ return 0;
+ }
+
+ /**
+ * Get MediaController.
+ *
+ * @return The MediaController instance.
+ */
+ default MediaController getMediaController() {
+ return null;
+ }
+
+ /**
+ * Hides the PIP menu.
+ */
+ void hidePipMenu(Runnable onStartCallback, Runnable onEndCallback);
+
+ /**
+ * Returns {@code true} if PIP is shown.
+ */
+ default boolean isPipShown() {
+ return false;
+ }
+
+ /**
+ * Moves the PIPed activity to the fullscreen and closes PIP system UI.
+ */
+ default void movePipToFullscreen() {
+ }
+
+ /**
+ * Called when configuration change invoked.
+ */
+ void onConfigurationChanged(Configuration newConfig);
+
+ /**
+ * Removes a {@link PipController.Listener} from PipController.
+ */
+ default void removeListener(PipController.Listener listener) {
+ }
+
+ /**
+ * Removes a {@link com.android.systemui.pip.tv.PipController.MediaListener} from PipController.
+ */
+ default void removeMediaListener(PipController.MediaListener listener) {
+ }
+
+ /**
+ * Resize the Pip to the appropriate size for the input state.
+ *
+ * @param state In Pip state also used to determine the new size for the Pip.
+ */
+ default void resizePinnedStack(int state) {
+ }
+
+ /**
+ * Resumes resizing operation on the Pip that was previously suspended.
+ *
+ * @param reason The reason resizing operations on the Pip was suspended.
+ */
+ default void resumePipResizing(int reason) {
+ }
+
+ /**
+ * Sets both shelf visibility and its height.
+ *
+ * @param visible visibility of shelf.
+ * @param height to specify the height for shelf.
+ */
+ default void setShelfHeight(boolean visible, int height) {
+ }
+
+ /**
+ * Set the pinned stack with {@link PipAnimationController.AnimationType}
+ *
+ * @param animationType The pre-defined {@link PipAnimationController.AnimationType}
+ */
+ default void setPinnedStackAnimationType(int animationType) {
+ }
+
+ /**
+ * Registers the pinned stack animation listener.
+ *
+ * @param listener The listener of pinned stack animation.
+ */
+ default void setPinnedStackAnimationListener(IPinnedStackAnimationListener listener) {
+ }
+
+ /**
+ * Suspends resizing operation on the Pip until {@link #resumePipResizing} is called.
+ *
+ * @param reason The reason for suspending resizing operations on the Pip.
+ */
+ default void suspendPipResizing(int reason) {
+ }
+
+ /**
+ * Dump the current state and information if need.
+ *
+ * @param pw The stream to dump information to.
+ */
+ default void dump(PrintWriter pw) {
+ }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/pip/PipTaskOrganizer.java b/packages/SystemUI/src/com/android/systemui/pip/PipTaskOrganizer.java
index e558be297a8b..862405609de8 100644
--- a/packages/SystemUI/src/com/android/systemui/pip/PipTaskOrganizer.java
+++ b/packages/SystemUI/src/com/android/systemui/pip/PipTaskOrganizer.java
@@ -47,8 +47,12 @@ import android.os.IBinder;
import android.os.Looper;
import android.os.RemoteException;
import android.util.Log;
+import android.util.Rational;
import android.util.Size;
import android.view.SurfaceControl;
+import android.view.SurfaceControlViewHost;
+import android.view.View;
+import android.view.WindowManager;
import android.window.TaskOrganizer;
import android.window.WindowContainerToken;
import android.window.WindowContainerTransaction;
@@ -57,11 +61,12 @@ import android.window.WindowOrganizer;
import com.android.internal.os.SomeArgs;
import com.android.systemui.dagger.SysUISingleton;
+import com.android.systemui.pip.phone.PipMenuActivityController;
import com.android.systemui.pip.phone.PipUpdateThread;
-import com.android.systemui.stackdivider.SplitScreenController;
import com.android.wm.shell.R;
import com.android.wm.shell.ShellTaskOrganizer;
import com.android.wm.shell.common.DisplayController;
+import com.android.wm.shell.splitscreen.SplitScreen;
import java.io.PrintWriter;
import java.util.ArrayList;
@@ -95,6 +100,7 @@ public class PipTaskOrganizer extends TaskOrganizer implements ShellTaskOrganize
private static final int MSG_FINISH_RESIZE = 4;
private static final int MSG_RESIZE_USER = 5;
+ private final Context mContext;
private final Handler mMainHandler;
private final Handler mUpdateHandler;
private final PipBoundsHandler mPipBoundsHandler;
@@ -105,8 +111,10 @@ public class PipTaskOrganizer extends TaskOrganizer implements ShellTaskOrganize
private final int mEnterExitAnimationDuration;
private final PipSurfaceTransactionHelper mSurfaceTransactionHelper;
private final Map<IBinder, Configuration> mInitialState = new HashMap<>();
- private final Optional<SplitScreenController> mSplitScreenControllerOptional;
+ private final Optional<SplitScreen> mSplitScreenOptional;
protected final ShellTaskOrganizer mTaskOrganizer;
+ private SurfaceControlViewHost mPipViewHost;
+ private SurfaceControl mPipMenuSurface;
// These callbacks are called on the update thread
private final PipAnimationController.PipAnimationCallback mPipAnimationCallback =
@@ -208,10 +216,11 @@ public class PipTaskOrganizer extends TaskOrganizer implements ShellTaskOrganize
public PipTaskOrganizer(Context context, @NonNull PipBoundsHandler boundsHandler,
@NonNull PipSurfaceTransactionHelper surfaceTransactionHelper,
- Optional<SplitScreenController> splitScreenControllerOptional,
+ Optional<SplitScreen> splitScreenOptional,
@NonNull DisplayController displayController,
@NonNull PipUiEventLogger pipUiEventLogger,
@NonNull ShellTaskOrganizer shellTaskOrganizer) {
+ mContext = context;
mMainHandler = new Handler(Looper.getMainLooper());
mUpdateHandler = new Handler(PipUpdateThread.get().getLooper(), mUpdateCallbacks);
mPipBoundsHandler = boundsHandler;
@@ -221,7 +230,7 @@ public class PipTaskOrganizer extends TaskOrganizer implements ShellTaskOrganize
mPipAnimationController = new PipAnimationController(mSurfaceTransactionHelper);
mPipUiEventLoggerLogger = pipUiEventLogger;
mSurfaceControlTransactionFactory = SurfaceControl.Transaction::new;
- mSplitScreenControllerOptional = splitScreenControllerOptional;
+ mSplitScreenOptional = splitScreenOptional;
mTaskOrganizer = shellTaskOrganizer;
mTaskOrganizer.addListener(this, WINDOWING_MODE_PINNED);
displayController.addDisplayWindowListener(this);
@@ -337,7 +346,7 @@ public class PipTaskOrganizer extends TaskOrganizer implements ShellTaskOrganize
wct.setWindowingMode(mToken, getOutPipWindowingMode());
// Simply reset the activity mode set prior to the animation running.
wct.setActivityWindowingMode(mToken, WINDOWING_MODE_UNDEFINED);
- mSplitScreenControllerOptional.ifPresent(splitScreen -> {
+ mSplitScreenOptional.ifPresent(splitScreen -> {
if (direction == TRANSITION_DIRECTION_LEAVE_PIP_TO_SPLIT_SCREEN) {
wct.reparent(mToken, splitScreen.getSecondaryRoot(), true /* onTop */);
}
@@ -504,6 +513,45 @@ public class PipTaskOrganizer extends TaskOrganizer implements ShellTaskOrganize
}
/**
+ * Setup the ViewHost and attach the provided menu view to the ViewHost.
+ */
+ public void attachPipMenuViewHost(View menuView, WindowManager.LayoutParams lp) {
+ if (mPipMenuSurface != null) {
+ Log.e(TAG, "PIP Menu View already created and attached.");
+ return;
+ }
+
+ if (Looper.getMainLooper() != Looper.myLooper()) {
+ throw new RuntimeException("PipMenuView needs to be attached on the main thread.");
+ }
+
+ mPipViewHost = new SurfaceControlViewHost(mContext, mContext.getDisplay(),
+ (android.os.Binder) null);
+ mPipMenuSurface = mPipViewHost.getSurfacePackage().getSurfaceControl();
+ SurfaceControl.Transaction transaction = new SurfaceControl.Transaction();
+ transaction.reparent(mPipMenuSurface, mLeash);
+ transaction.show(mPipMenuSurface);
+ transaction.setRelativeLayer(mPipMenuSurface, mLeash, 1);
+ transaction.apply();
+ mPipViewHost.setView(menuView, lp);
+ }
+
+
+ /**
+ * Releases the PIP Menu's View host, remove it from PIP task surface.
+ */
+ public void detachPipMenuViewHost() {
+ if (mPipMenuSurface != null) {
+ SurfaceControl.Transaction transaction = new SurfaceControl.Transaction();
+ transaction.remove(mPipMenuSurface);
+ transaction.apply();
+ mPipMenuSurface = null;
+ mPipViewHost = null;
+ }
+ }
+
+
+ /**
* Note that dismissing PiP is now originated from SystemUI, see {@link #exitPip(int)}.
* Meanwhile this callback is invoked whenever the task is removed. For instance:
* - as a result of removeStacksInWindowingModes from WM
@@ -637,13 +685,16 @@ public class PipTaskOrganizer extends TaskOrganizer implements ShellTaskOrganize
* {@link PictureInPictureParams} would affect the bounds.
*/
private boolean applyPictureInPictureParams(@NonNull PictureInPictureParams params) {
- final boolean changed = (mPictureInPictureParams == null) || !Objects.equals(
- mPictureInPictureParams.getAspectRatioRational(), params.getAspectRatioRational());
- if (changed) {
- mPictureInPictureParams = params;
+ final Rational currentAspectRatio =
+ mPictureInPictureParams != null ? mPictureInPictureParams.getAspectRatioRational()
+ : null;
+ final boolean aspectRatioChanged = !Objects.equals(currentAspectRatio,
+ params.getAspectRatioRational());
+ mPictureInPictureParams = params;
+ if (aspectRatioChanged) {
mPipBoundsHandler.onAspectRatioChanged(params.getAspectRatio());
}
- return changed;
+ return aspectRatioChanged;
}
/**
@@ -838,6 +889,12 @@ public class PipTaskOrganizer extends TaskOrganizer implements ShellTaskOrganize
WindowContainerTransaction wct = new WindowContainerTransaction();
prepareFinishResizeTransaction(destinationBounds, direction, tx, wct);
applyFinishBoundsResize(wct, direction);
+ runOnMainHandler(() -> {
+ if (mPipViewHost != null) {
+ mPipViewHost.relayout(PipMenuActivityController.getPipMenuLayoutParams(
+ destinationBounds.width(), destinationBounds.height()));
+ }
+ });
}
private void prepareFinishResizeTransaction(Rect destinationBounds,
@@ -937,21 +994,25 @@ public class PipTaskOrganizer extends TaskOrganizer implements ShellTaskOrganize
}
/**
- * Sync with {@link SplitScreenController} on destination bounds if PiP is going to split
- * screen.
+ * Sync with {@link SplitScreen} on destination bounds if PiP is going to split screen.
*
* @param destinationBoundsOut contain the updated destination bounds if applicable
* @return {@code true} if destinationBounds is altered for split screen
*/
private boolean syncWithSplitScreenBounds(Rect destinationBoundsOut) {
- if (!mSplitScreenControllerOptional.isPresent()) {
+ if (!mSplitScreenOptional.isPresent()) {
+ return false;
+ }
+
+ SplitScreen splitScreen = mSplitScreenOptional.get();
+ if (!splitScreen.isDividerVisible()) {
// fail early if system is not in split screen mode
return false;
}
// PiP window will go to split-secondary mode instead of fullscreen, populates the
// split screen bounds here.
- destinationBoundsOut.set(mSplitScreenControllerOptional.get().getDividerView()
+ destinationBoundsOut.set(splitScreen.getDividerView()
.getNonMinimizedSplitScreenSecondaryBounds());
return true;
}
diff --git a/packages/SystemUI/src/com/android/systemui/pip/PipUI.java b/packages/SystemUI/src/com/android/systemui/pip/PipUI.java
deleted file mode 100644
index 2cd1e202125d..000000000000
--- a/packages/SystemUI/src/com/android/systemui/pip/PipUI.java
+++ /dev/null
@@ -1,122 +0,0 @@
-/*
- * Copyright (C) 2016 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.systemui.pip;
-
-import static android.content.pm.PackageManager.FEATURE_PICTURE_IN_PICTURE;
-
-import android.content.Context;
-import android.content.pm.PackageManager;
-import android.content.res.Configuration;
-import android.os.UserHandle;
-import android.os.UserManager;
-
-import com.android.systemui.SystemUI;
-import com.android.systemui.dagger.SysUISingleton;
-import com.android.systemui.shared.recents.IPinnedStackAnimationListener;
-import com.android.systemui.statusbar.CommandQueue;
-
-import java.io.FileDescriptor;
-import java.io.PrintWriter;
-
-import javax.inject.Inject;
-
-/**
- * Controls the picture-in-picture window.
- */
-@SysUISingleton
-public class PipUI extends SystemUI implements CommandQueue.Callbacks {
-
- private final CommandQueue mCommandQueue;
- private BasePipManager mPipManager;
-
- @Inject
- public PipUI(Context context, CommandQueue commandQueue,
- BasePipManager pipManager) {
- super(context);
- mCommandQueue = commandQueue;
- mPipManager = pipManager;
- }
-
- @Override
- public void start() {
- PackageManager pm = mContext.getPackageManager();
- boolean supportsPip = pm.hasSystemFeature(FEATURE_PICTURE_IN_PICTURE);
- if (!supportsPip) {
- return;
- }
-
- // Ensure that we are the primary user's SystemUI.
- final int processUser = UserManager.get(mContext).getUserHandle();
- if (processUser != UserHandle.USER_SYSTEM) {
- throw new IllegalStateException("Non-primary Pip component not currently supported.");
- }
-
- mCommandQueue.addCallback(this);
- }
-
- @Override
- public void showPictureInPictureMenu() {
- mPipManager.showPictureInPictureMenu();
- }
-
- public void expandPip() {
- mPipManager.expandPip();
- }
-
- public void hidePipMenu(Runnable onStartCallback, Runnable onEndCallback) {
- mPipManager.hidePipMenu(onStartCallback, onEndCallback);
- }
-
- @Override
- protected void onConfigurationChanged(Configuration newConfig) {
- super.onConfigurationChanged(newConfig);
- if (mPipManager == null) {
- return;
- }
-
- mPipManager.onConfigurationChanged(newConfig);
- }
-
- public void setShelfHeight(boolean visible, int height) {
- if (mPipManager == null) {
- return;
- }
-
- mPipManager.setShelfHeight(visible, height);
- }
-
- public void setPinnedStackAnimationType(int animationType) {
- if (mPipManager != null) {
- mPipManager.setPinnedStackAnimationType(animationType);
- }
- }
-
- public void setPinnedStackAnimationListener(IPinnedStackAnimationListener listener) {
- if (mPipManager != null) {
- mPipManager.setPinnedStackAnimationListener(listener);
- }
- }
-
- @Override
- public void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
- if (mPipManager == null) {
- return;
- }
-
- mPipManager.dump(pw);
- }
-}
diff --git a/packages/SystemUI/src/com/android/systemui/pip/phone/PipManager.java b/packages/SystemUI/src/com/android/systemui/pip/phone/PipController.java
index 6aec14449d70..6998e90b3a7c 100644
--- a/packages/SystemUI/src/com/android/systemui/pip/phone/PipManager.java
+++ b/packages/SystemUI/src/com/android/systemui/pip/phone/PipController.java
@@ -18,6 +18,7 @@ package com.android.systemui.pip.phone;
import static android.app.WindowConfiguration.ACTIVITY_TYPE_UNDEFINED;
import static android.app.WindowConfiguration.WINDOWING_MODE_PINNED;
+import static android.content.pm.PackageManager.FEATURE_PICTURE_IN_PICTURE;
import static com.android.systemui.pip.PipAnimationController.isOutPipDirection;
@@ -28,11 +29,14 @@ import android.app.IActivityManager;
import android.app.RemoteAction;
import android.content.ComponentName;
import android.content.Context;
+import android.content.pm.PackageManager;
import android.content.pm.ParceledListSlice;
import android.content.res.Configuration;
import android.graphics.Rect;
import android.os.Handler;
import android.os.RemoteException;
+import android.os.UserHandle;
+import android.os.UserManager;
import android.util.Log;
import android.util.Pair;
import android.view.DisplayInfo;
@@ -44,37 +48,31 @@ import com.android.systemui.UiOffloadThread;
import com.android.systemui.broadcast.BroadcastDispatcher;
import com.android.systemui.dagger.SysUISingleton;
import com.android.systemui.model.SysUiState;
-import com.android.systemui.pip.BasePipManager;
+import com.android.systemui.pip.Pip;
import com.android.systemui.pip.PipBoundsHandler;
import com.android.systemui.pip.PipSurfaceTransactionHelper;
import com.android.systemui.pip.PipTaskOrganizer;
import com.android.systemui.pip.PipUiEventLogger;
-import com.android.systemui.pip.phone.dagger.PipMenuActivityClass;
import com.android.systemui.shared.recents.IPinnedStackAnimationListener;
import com.android.systemui.shared.system.ActivityManagerWrapper;
import com.android.systemui.shared.system.InputConsumerController;
import com.android.systemui.shared.system.PinnedStackListenerForwarder.PinnedStackListener;
import com.android.systemui.shared.system.TaskStackChangeListener;
import com.android.systemui.shared.system.WindowManagerWrapper;
-import com.android.systemui.stackdivider.SplitScreenController;
import com.android.systemui.statusbar.policy.ConfigurationController;
import com.android.systemui.util.DeviceConfigProxy;
import com.android.systemui.util.FloatingContentCoordinator;
-import com.android.wm.shell.ShellTaskOrganizer;
import com.android.wm.shell.common.DisplayChangeController;
import com.android.wm.shell.common.DisplayController;
import java.io.PrintWriter;
-import java.util.Optional;
-
-import javax.inject.Inject;
/**
* Manages the picture-in-picture (PIP) UI and states for Phones.
*/
@SysUISingleton
-public class PipManager implements BasePipManager, PipTaskOrganizer.PipTransitionCallback {
- private static final String TAG = "PipManager";
+public class PipController implements Pip, PipTaskOrganizer.PipTransitionCallback {
+ private static final String TAG = "PipController";
private Context mContext;
private IActivityManager mActivityManager;
@@ -88,15 +86,15 @@ public class PipManager implements BasePipManager, PipTaskOrganizer.PipTransitio
private DisplayController mDisplayController;
private InputConsumerController mInputConsumerController;
private PipAppOpsListener mAppOpsListener;
+ private PipBoundsHandler mPipBoundsHandler;
private PipMediaController mMediaController;
private PipTouchHandler mTouchHandler;
- private PipTaskOrganizer mPipTaskOrganizer;
private PipSurfaceTransactionHelper mPipSurfaceTransactionHelper;
private IPinnedStackAnimationListener mPinnedStackAnimationRecentsListener;
private boolean mIsInFixedRotation;
- protected PipBoundsHandler mPipBoundsHandler;
protected PipMenuActivityController mMenuController;
+ protected PipTaskOrganizer mPipTaskOrganizer;
/**
* Handler for display rotation changes.
@@ -128,7 +126,7 @@ public class PipManager implements BasePipManager, PipTaskOrganizer.PipTransitio
// not during the fixed rotation. In fixed rotation case, app is about to enter PiP
// and we need the offsets preserved to calculate the destination bounds.
if (!mIsInFixedRotation) {
- mPipBoundsHandler.setShelfHeight(false , 0);
+ mPipBoundsHandler.setShelfHeight(false, 0);
mPipBoundsHandler.onImeVisibilityChanged(false, 0);
mTouchHandler.onShelfVisibilityChanged(false, 0);
mTouchHandler.onImeVisibilityChanged(false, 0);
@@ -202,7 +200,7 @@ public class PipManager implements BasePipManager, PipTaskOrganizer.PipTransitio
/**
* Handler for messages from the PIP controller.
*/
- private class PipManagerPinnedStackListener extends PinnedStackListener {
+ private class PipControllerPinnedStackListener extends PinnedStackListener {
@Override
public void onListenerRegistered(IPinnedStackController controller) {
mHandler.post(() -> mTouchHandler.setPinnedStackController(controller));
@@ -254,50 +252,61 @@ public class PipManager implements BasePipManager, PipTaskOrganizer.PipTransitio
public ConfigurationController.ConfigurationListener mOverlayChangedListener =
new ConfigurationController.ConfigurationListener() {
- @Override
- public void onOverlayChanged() {
- mHandler.post(() -> {
- mPipBoundsHandler.onOverlayChanged(mContext, mContext.getDisplay());
- updateMovementBounds(null /* toBounds */,
- false /* fromRotation */, false /* fromImeAdjustment */,
- false /* fromShelfAdjustment */, null /* windowContainerTransaction */);
- });
- }
- };
+ @Override
+ public void onOverlayChanged() {
+ mHandler.post(() -> {
+ mPipBoundsHandler.onOverlayChanged(mContext, mContext.getDisplay());
+ updateMovementBounds(null /* toBounds */,
+ false /* fromRotation */, false /* fromImeAdjustment */,
+ false /* fromShelfAdjustment */,
+ null /* windowContainerTransaction */);
+ });
+ }
+ };
- @Inject
- public PipManager(Context context, BroadcastDispatcher broadcastDispatcher,
- @PipMenuActivityClass Class<?> pipMenuActivityClass,
+ public PipController(Context context, BroadcastDispatcher broadcastDispatcher,
ConfigurationController configController,
DeviceConfigProxy deviceConfig,
DisplayController displayController,
- Optional<SplitScreenController> splitScreenControllerOptional,
FloatingContentCoordinator floatingContentCoordinator,
SysUiState sysUiState,
- PipUiEventLogger pipUiEventLogger,
- ShellTaskOrganizer shellTaskOrganizer) {
+ PipBoundsHandler pipBoundsHandler,
+ PipSurfaceTransactionHelper pipSurfaceTransactionHelper,
+ PipTaskOrganizer pipTaskOrganizer,
+ PipUiEventLogger pipUiEventLogger) {
mContext = context;
mActivityManager = ActivityManager.getService();
+ PackageManager pm = context.getPackageManager();
+ boolean supportsPip = pm.hasSystemFeature(FEATURE_PICTURE_IN_PICTURE);
+ if (!supportsPip) {
+ Log.w(TAG, "Device not support PIP feature");
+ return;
+ }
+
+ // Ensure that we are the primary user's SystemUI.
+ final int processUser = UserManager.get(context).getUserHandle();
+ if (processUser != UserHandle.USER_SYSTEM) {
+ throw new IllegalStateException("Non-primary Pip component not currently supported.");
+ }
+
try {
WindowManagerWrapper.getInstance().addPinnedStackListener(
- new PipManagerPinnedStackListener());
+ new PipControllerPinnedStackListener());
} catch (RemoteException e) {
Log.e(TAG, "Failed to register pinned stack listener", e);
}
ActivityManagerWrapper.getInstance().registerTaskStackListener(mTaskStackListener);
mDisplayController = displayController;
- mPipBoundsHandler = new PipBoundsHandler(mContext);
- mPipSurfaceTransactionHelper = new PipSurfaceTransactionHelper(context, configController);
- mPipTaskOrganizer = new PipTaskOrganizer(mContext, mPipBoundsHandler,
- mPipSurfaceTransactionHelper, splitScreenControllerOptional, mDisplayController,
- pipUiEventLogger, shellTaskOrganizer);
+ mPipBoundsHandler = pipBoundsHandler;
+ mPipSurfaceTransactionHelper = pipSurfaceTransactionHelper;
+ mPipTaskOrganizer = pipTaskOrganizer;
mPipTaskOrganizer.registerPipTransitionCallback(this);
mInputConsumerController = InputConsumerController.getPipInputConsumer();
mMediaController = new PipMediaController(context, mActivityManager, broadcastDispatcher);
- mMenuController = new PipMenuActivityController(context, pipMenuActivityClass,
- mMediaController, mInputConsumerController);
+ mMenuController = new PipMenuActivityController(context,
+ mMediaController, mInputConsumerController, mPipTaskOrganizer);
mTouchHandler = new PipTouchHandler(context, mActivityManager,
mMenuController, mInputConsumerController, mPipBoundsHandler, mPipTaskOrganizer,
floatingContentCoordinator, deviceConfig, sysUiState, pipUiEventLogger);
@@ -452,6 +461,7 @@ public class PipManager implements BasePipManager, PipTaskOrganizer.PipTransitio
mTmpDisplayInfo.rotation);
}
+ @Override
public void dump(PrintWriter pw) {
final String innerPrefix = " ";
pw.println(TAG);
diff --git a/packages/SystemUI/src/com/android/systemui/pip/phone/PipMenuActivityController.java b/packages/SystemUI/src/com/android/systemui/pip/phone/PipMenuActivityController.java
index 383f6b3bf79d..873ba26b39ab 100644
--- a/packages/SystemUI/src/com/android/systemui/pip/phone/PipMenuActivityController.java
+++ b/packages/SystemUI/src/com/android/systemui/pip/phone/PipMenuActivityController.java
@@ -19,27 +19,20 @@ package com.android.systemui.pip.phone;
import static android.app.WindowConfiguration.ACTIVITY_TYPE_UNDEFINED;
import static android.app.WindowConfiguration.WINDOWING_MODE_PINNED;
-import android.annotation.Nullable;
import android.app.ActivityManager.StackInfo;
-import android.app.ActivityOptions;
import android.app.ActivityTaskManager;
import android.app.RemoteAction;
import android.content.Context;
-import android.content.Intent;
import android.content.pm.ParceledListSlice;
+import android.graphics.PixelFormat;
import android.graphics.Rect;
-import android.os.Bundle;
import android.os.Debug;
-import android.os.Handler;
-import android.os.Looper;
-import android.os.Message;
-import android.os.Messenger;
import android.os.RemoteException;
-import android.os.SystemClock;
-import android.os.UserHandle;
import android.util.Log;
import android.view.MotionEvent;
+import android.view.WindowManager;
+import com.android.systemui.pip.PipTaskOrganizer;
import com.android.systemui.pip.phone.PipMediaController.ActionListener;
import com.android.systemui.shared.system.InputConsumerController;
@@ -58,30 +51,10 @@ public class PipMenuActivityController {
private static final String TAG = "PipMenuActController";
private static final boolean DEBUG = false;
- public static final String EXTRA_CONTROLLER_MESSENGER = "messenger";
- public static final String EXTRA_ACTIONS = "actions";
- public static final String EXTRA_STACK_BOUNDS = "stack_bounds";
- public static final String EXTRA_ALLOW_TIMEOUT = "allow_timeout";
- public static final String EXTRA_WILL_RESIZE_MENU = "resize_menu_on_show";
- public static final String EXTRA_DISMISS_FRACTION = "dismiss_fraction";
- public static final String EXTRA_MENU_STATE = "menu_state";
- public static final String EXTRA_SHOW_MENU_WITH_DELAY = "show_menu_with_delay";
- public static final String EXTRA_SHOW_RESIZE_HANDLE = "show_resize_handle";
- public static final String EXTRA_MESSAGE_CALLBACK_WHAT = "message_callback_what";
-
- public static final int MESSAGE_MENU_STATE_CHANGED = 100;
- public static final int MESSAGE_EXPAND_PIP = 101;
- public static final int MESSAGE_DISMISS_PIP = 103;
- public static final int MESSAGE_UPDATE_ACTIVITY_CALLBACK = 104;
- public static final int MESSAGE_SHOW_MENU = 107;
-
public static final int MENU_STATE_NONE = 0;
public static final int MENU_STATE_CLOSE = 1;
public static final int MENU_STATE_FULL = 2;
- // The duration to wait before we consider the start activity as having timed out
- private static final long START_ACTIVITY_REQUEST_TIMEOUT_MS = 300;
-
/**
* A listener interface to receive notification on changes in PIP.
*/
@@ -110,9 +83,8 @@ public class PipMenuActivityController {
void onPipShowMenu();
}
- /** TODO(b/150319024): PipMenuActivity will move to a Window */
- private Class<?> mPipMenuActivityClass;
private Context mContext;
+ private PipTaskOrganizer mPipTaskOrganizer;
private PipMediaController mMediaController;
private InputConsumerController mInputConsumerController;
@@ -121,63 +93,7 @@ public class PipMenuActivityController {
private ParceledListSlice<RemoteAction> mMediaActions;
private int mMenuState;
- // The dismiss fraction update is sent frequently, so use a temporary bundle for the message
- private Bundle mTmpDismissFractionData = new Bundle();
-
- private Runnable mOnAnimationEndRunnable;
- private boolean mStartActivityRequested;
- private long mStartActivityRequestedTime;
- private Messenger mToActivityMessenger;
- private Handler mHandler = new Handler(Looper.getMainLooper()) {
- @Override
- public void handleMessage(Message msg) {
- switch (msg.what) {
- case MESSAGE_MENU_STATE_CHANGED: {
- final int menuState = msg.arg1;
- final boolean resize = msg.arg2 != 0;
- onMenuStateChanged(menuState, resize,
- getMenuStateChangeFinishedCallback(msg.replyTo, (Bundle) msg.obj));
- break;
- }
- case MESSAGE_EXPAND_PIP: {
- mListeners.forEach(Listener::onPipExpand);
- break;
- }
- case MESSAGE_DISMISS_PIP: {
- mListeners.forEach(Listener::onPipDismiss);
- break;
- }
- case MESSAGE_SHOW_MENU: {
- mListeners.forEach(Listener::onPipShowMenu);
- break;
- }
- case MESSAGE_UPDATE_ACTIVITY_CALLBACK: {
- mToActivityMessenger = msg.replyTo;
- setStartActivityRequested(false);
- if (mOnAnimationEndRunnable != null) {
- mOnAnimationEndRunnable.run();
- mOnAnimationEndRunnable = null;
- }
- // Mark the menu as invisible once the activity finishes as well
- if (mToActivityMessenger == null) {
- final boolean resize = msg.arg1 != 0;
- onMenuStateChanged(MENU_STATE_NONE, resize, null /* callback */);
- }
- break;
- }
- }
- }
- };
- private Messenger mMessenger = new Messenger(mHandler);
-
- private Runnable mStartActivityRequestedTimeoutRunnable = () -> {
- setStartActivityRequested(false);
- if (mOnAnimationEndRunnable != null) {
- mOnAnimationEndRunnable.run();
- mOnAnimationEndRunnable = null;
- }
- Log.e(TAG, "Expected start menu activity request timed out");
- };
+ private PipMenuView mPipMenuView;
private ActionListener mMediaActionListener = new ActionListener() {
@Override
@@ -187,39 +103,40 @@ public class PipMenuActivityController {
}
};
- public PipMenuActivityController(Context context, Class<?> pipMenuActivityClass,
- PipMediaController mediaController, InputConsumerController inputConsumerController
+ public PipMenuActivityController(Context context,
+ PipMediaController mediaController, InputConsumerController inputConsumerController,
+ PipTaskOrganizer pipTaskOrganizer
) {
mContext = context;
mMediaController = mediaController;
mInputConsumerController = inputConsumerController;
- mPipMenuActivityClass = pipMenuActivityClass;
+ mPipTaskOrganizer = pipTaskOrganizer;
}
- public boolean isMenuActivityVisible() {
- return mToActivityMessenger != null;
+ public boolean isMenuVisible() {
+ return mPipMenuView != null && mMenuState != MENU_STATE_NONE;
}
public void onActivityPinned() {
+ if (mPipMenuView == null) {
+ WindowManager.LayoutParams lp =
+ getPipMenuLayoutParams(0, 0);
+ mPipMenuView = new PipMenuView(mContext, this);
+ mPipTaskOrganizer.attachPipMenuViewHost(mPipMenuView, lp);
+ }
mInputConsumerController.registerInputConsumer(true /* withSfVsync */);
}
public void onActivityUnpinned() {
hideMenu();
mInputConsumerController.unregisterInputConsumer();
- setStartActivityRequested(false);
+ mPipTaskOrganizer.detachPipMenuViewHost();
+ mPipMenuView = null;
}
public void onPinnedStackAnimationEnded() {
- // Note: Only active menu activities care about this event
- if (mToActivityMessenger != null) {
- Message m = Message.obtain();
- m.what = PipMenuActivity.MESSAGE_ANIMATION_ENDED;
- try {
- mToActivityMessenger.send(m);
- } catch (RemoteException e) {
- Log.e(TAG, "Could not notify menu pinned animation ended", e);
- }
+ if (isMenuVisible()) {
+ mPipMenuView.onPipAnimationEnded();
}
}
@@ -236,27 +153,13 @@ public class PipMenuActivityController {
* Updates the appearance of the menu and scrim on top of the PiP while dismissing.
*/
public void setDismissFraction(float fraction) {
+ final boolean isMenuVisible = isMenuVisible();
if (DEBUG) {
- Log.d(TAG, "setDismissFraction() hasActivity=" + (mToActivityMessenger != null)
+ Log.d(TAG, "setDismissFraction() isMenuVisible=" + isMenuVisible
+ " fraction=" + fraction);
}
- if (mToActivityMessenger != null) {
- mTmpDismissFractionData.clear();
- mTmpDismissFractionData.putFloat(EXTRA_DISMISS_FRACTION, fraction);
- Message m = Message.obtain();
- m.what = PipMenuActivity.MESSAGE_UPDATE_DISMISS_FRACTION;
- m.obj = mTmpDismissFractionData;
- try {
- mToActivityMessenger.send(m);
- } catch (RemoteException e) {
- Log.e(TAG, "Could not notify menu to update dismiss fraction", e);
- }
- } else if (!mStartActivityRequested || isStartActivityRequestedElapsed()) {
- // If we haven't requested the start activity, or if it previously took too long to
- // start, then start it
- startMenuActivity(MENU_STATE_NONE, null /* stackBounds */,
- false /* allowMenuTimeout */, false /* resizeMenuOnShow */,
- false /* withDelay */, false /* showResizeHandle */);
+ if (isMenuVisible) {
+ mPipMenuView.updateDismissFraction(fraction);
}
}
@@ -282,27 +185,11 @@ public class PipMenuActivityController {
false /* withDelay */, showResizeHandle);
}
- private Runnable getMenuStateChangeFinishedCallback(@Nullable Messenger replyTo,
- @Nullable Bundle data) {
- if (replyTo == null || data == null) {
- return null;
- }
- return () -> {
- try {
- final Message m = Message.obtain();
- m.what = data.getInt(EXTRA_MESSAGE_CALLBACK_WHAT);
- replyTo.send(m);
- } catch (RemoteException e) {
- // ignored
- }
- };
- }
-
private void showMenuInternal(int menuState, Rect stackBounds, boolean allowMenuTimeout,
boolean willResizeMenu, boolean withDelay, boolean showResizeHandle) {
if (DEBUG) {
Log.d(TAG, "showMenu() state=" + menuState
- + " hasActivity=" + (mToActivityMessenger != null)
+ + " isMenuVisible=" + isMenuVisible()
+ " allowMenuTimeout=" + allowMenuTimeout
+ " willResizeMenu=" + willResizeMenu
+ " withDelay=" + withDelay
@@ -310,64 +197,34 @@ public class PipMenuActivityController {
+ " callers=\n" + Debug.getCallers(5, " "));
}
- if (mToActivityMessenger != null) {
- Bundle data = new Bundle();
- data.putInt(EXTRA_MENU_STATE, menuState);
- if (stackBounds != null) {
- data.putParcelable(EXTRA_STACK_BOUNDS, stackBounds);
- }
- data.putBoolean(EXTRA_ALLOW_TIMEOUT, allowMenuTimeout);
- data.putBoolean(EXTRA_WILL_RESIZE_MENU, willResizeMenu);
- data.putBoolean(EXTRA_SHOW_MENU_WITH_DELAY, withDelay);
- data.putBoolean(EXTRA_SHOW_RESIZE_HANDLE, showResizeHandle);
- Message m = Message.obtain();
- m.what = PipMenuActivity.MESSAGE_SHOW_MENU;
- m.obj = data;
- try {
- mToActivityMessenger.send(m);
- } catch (RemoteException e) {
- Log.e(TAG, "Could not notify menu to show", e);
- }
- } else if (!mStartActivityRequested || isStartActivityRequestedElapsed()) {
- // If we haven't requested the start activity, or if it previously took too long to
- // start, then start it
- startMenuActivity(menuState, stackBounds, allowMenuTimeout, willResizeMenu, withDelay,
- showResizeHandle);
+ if (mPipMenuView == null) {
+ Log.e(TAG, "PipMenu has not been attached yet.");
+ return;
}
+ mPipMenuView.showMenu(menuState, stackBounds, allowMenuTimeout, willResizeMenu, withDelay,
+ showResizeHandle);
}
/**
* Pokes the menu, indicating that the user is interacting with it.
*/
public void pokeMenu() {
+ final boolean isMenuVisible = isMenuVisible();
if (DEBUG) {
- Log.d(TAG, "pokeMenu() hasActivity=" + (mToActivityMessenger != null));
+ Log.d(TAG, "pokeMenu() isMenuVisible=" + isMenuVisible);
}
- if (mToActivityMessenger != null) {
- Message m = Message.obtain();
- m.what = PipMenuActivity.MESSAGE_POKE_MENU;
- try {
- mToActivityMessenger.send(m);
- } catch (RemoteException e) {
- Log.e(TAG, "Could not notify poke menu", e);
- }
+ if (isMenuVisible) {
+ mPipMenuView.pokeMenu();
}
}
private void fadeOutMenu() {
+ final boolean isMenuVisible = isMenuVisible();
if (DEBUG) {
- Log.d(TAG, "fadeOutMenu() state=" + mMenuState
- + " hasActivity=" + (mToActivityMessenger != null)
- + " callers=\n" + Debug.getCallers(5, " "));
+ Log.d(TAG, "fadeOutMenu() isMenuVisible=" + isMenuVisible);
}
- if (mToActivityMessenger != null) {
- Message m = Message.obtain();
- m.what = PipMenuActivity.MESSAGE_FADE_OUT_MENU;
- try {
- mToActivityMessenger.send(m);
- } catch (RemoteException e) {
- Log.e(TAG, "Could not notify menu to fade out", e);
- }
+ if (isMenuVisible) {
+ mPipMenuView.fadeOutMenu();
}
}
@@ -375,19 +232,14 @@ public class PipMenuActivityController {
* Hides the menu activity.
*/
public void hideMenu() {
+ final boolean isMenuVisible = isMenuVisible();
if (DEBUG) {
Log.d(TAG, "hideMenu() state=" + mMenuState
- + " hasActivity=" + (mToActivityMessenger != null)
+ + " isMenuVisible=" + isMenuVisible
+ " callers=\n" + Debug.getCallers(5, " "));
}
- if (mToActivityMessenger != null) {
- Message m = Message.obtain();
- m.what = PipMenuActivity.MESSAGE_HIDE_MENU;
- try {
- mToActivityMessenger.send(m);
- } catch (RemoteException e) {
- Log.e(TAG, "Could not notify menu to hide", e);
- }
+ if (isMenuVisible) {
+ mPipMenuView.hideMenu();
}
}
@@ -395,29 +247,11 @@ public class PipMenuActivityController {
* Hides the menu activity.
*/
public void hideMenu(Runnable onStartCallback, Runnable onEndCallback) {
- if (mStartActivityRequested) {
- // If the menu has been start-requested, but not actually started, then we defer the
- // trigger callback until the menu has started and called back to the controller.
- mOnAnimationEndRunnable = onEndCallback;
- onStartCallback.run();
-
- // Fallback for b/63752800, we have started the PipMenuActivity but it has not made any
- // callbacks. Don't continue to wait for the menu to show past some timeout.
- mHandler.removeCallbacks(mStartActivityRequestedTimeoutRunnable);
- mHandler.postDelayed(mStartActivityRequestedTimeoutRunnable,
- START_ACTIVITY_REQUEST_TIMEOUT_MS);
- } else if (mMenuState != MENU_STATE_NONE && mToActivityMessenger != null) {
+ if (isMenuVisible()) {
// If the menu is visible in either the closed or full state, then hide the menu and
// trigger the animation trigger afterwards
onStartCallback.run();
- Message m = Message.obtain();
- m.what = PipMenuActivity.MESSAGE_HIDE_MENU;
- m.obj = onEndCallback;
- try {
- mToActivityMessenger.send(m);
- } catch (RemoteException e) {
- Log.e(TAG, "Could not notify hide menu", e);
- }
+ mPipMenuView.hideMenu(onEndCallback);
}
}
@@ -438,6 +272,18 @@ public class PipMenuActivityController {
updateMenuActions();
}
+ void onPipExpand() {
+ mListeners.forEach(Listener::onPipExpand);
+ }
+
+ void onPipDismiss() {
+ mListeners.forEach(Listener::onPipDismiss);
+ }
+
+ void onPipShowMenu() {
+ mListeners.forEach(Listener::onPipShowMenu);
+ }
+
/**
* @return the best set of actions to show in the PiP menu.
*/
@@ -449,47 +295,20 @@ public class PipMenuActivityController {
}
/**
- * Starts the menu activity on the top task of the pinned stack.
+ * Returns a default LayoutParams for the PIP Menu.
+ * @param width the PIP stack width.
+ * @param height the PIP stack height.
*/
- private void startMenuActivity(int menuState, Rect stackBounds, boolean allowMenuTimeout,
- boolean willResizeMenu, boolean withDelay, boolean showResizeHandle) {
- try {
- StackInfo pinnedStackInfo = ActivityTaskManager.getService().getStackInfo(
- WINDOWING_MODE_PINNED, ACTIVITY_TYPE_UNDEFINED);
- if (pinnedStackInfo != null && pinnedStackInfo.taskIds != null &&
- pinnedStackInfo.taskIds.length > 0) {
- Intent intent = new Intent(mContext, mPipMenuActivityClass);
- intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
- intent.putExtra(EXTRA_CONTROLLER_MESSENGER, mMessenger);
- intent.putExtra(EXTRA_ACTIONS, resolveMenuActions());
- if (stackBounds != null) {
- intent.putExtra(EXTRA_STACK_BOUNDS, stackBounds);
- }
- intent.putExtra(EXTRA_MENU_STATE, menuState);
- intent.putExtra(EXTRA_ALLOW_TIMEOUT, allowMenuTimeout);
- intent.putExtra(EXTRA_WILL_RESIZE_MENU, willResizeMenu);
- intent.putExtra(EXTRA_SHOW_MENU_WITH_DELAY, withDelay);
- intent.putExtra(EXTRA_SHOW_RESIZE_HANDLE, showResizeHandle);
- ActivityOptions options = ActivityOptions.makeCustomAnimation(mContext, 0, 0);
- options.setLaunchTaskId(
- pinnedStackInfo.taskIds[pinnedStackInfo.taskIds.length - 1]);
- options.setTaskOverlay(true, true /* canResume */);
- mContext.startActivityAsUser(intent, options.toBundle(), UserHandle.CURRENT);
- setStartActivityRequested(true);
- } else {
- Log.e(TAG, "No PIP tasks found");
- }
- } catch (RemoteException e) {
- setStartActivityRequested(false);
- Log.e(TAG, "Error showing PIP menu activity", e);
- }
+ public static WindowManager.LayoutParams getPipMenuLayoutParams(int width, int height) {
+ return new WindowManager.LayoutParams(width, height,
+ WindowManager.LayoutParams.TYPE_APPLICATION, 0, PixelFormat.TRANSLUCENT);
}
/**
- * Updates the PiP menu activity with the best set of actions provided.
+ * Updates the PiP menu with the best set of actions provided.
*/
private void updateMenuActions() {
- if (mToActivityMessenger != null) {
+ if (isMenuVisible()) {
// Fetch the pinned stack bounds
Rect stackBounds = null;
try {
@@ -499,20 +318,10 @@ public class PipMenuActivityController {
stackBounds = pinnedStackInfo.bounds;
}
} catch (RemoteException e) {
- Log.e(TAG, "Error showing PIP menu activity", e);
+ Log.e(TAG, "Error showing PIP menu", e);
}
- Bundle data = new Bundle();
- data.putParcelable(EXTRA_STACK_BOUNDS, stackBounds);
- data.putParcelable(EXTRA_ACTIONS, resolveMenuActions());
- Message m = Message.obtain();
- m.what = PipMenuActivity.MESSAGE_UPDATE_ACTIONS;
- m.obj = data;
- try {
- mToActivityMessenger.send(m);
- } catch (RemoteException e) {
- Log.e(TAG, "Could not notify menu activity to update actions", e);
- }
+ mPipMenuView.setActions(stackBounds, resolveMenuActions().getList());
}
}
@@ -524,17 +333,9 @@ public class PipMenuActivityController {
}
/**
- * @return whether the time of the activity request has exceeded the timeout.
- */
- private boolean isStartActivityRequestedElapsed() {
- return (SystemClock.uptimeMillis() - mStartActivityRequestedTime)
- >= START_ACTIVITY_REQUEST_TIMEOUT_MS;
- }
-
- /**
* Handles changes in menu visibility.
*/
- private void onMenuStateChanged(int menuState, boolean resize, Runnable callback) {
+ void onMenuStateChanged(int menuState, boolean resize, Runnable callback) {
if (DEBUG) {
Log.d(TAG, "onMenuStateChanged() mMenuState=" + mMenuState
+ " menuState=" + menuState + " resize=" + resize
@@ -556,25 +357,14 @@ public class PipMenuActivityController {
mMenuState = menuState;
}
- private void setStartActivityRequested(boolean requested) {
- mHandler.removeCallbacks(mStartActivityRequestedTimeoutRunnable);
- mStartActivityRequested = requested;
- mStartActivityRequestedTime = requested ? SystemClock.uptimeMillis() : 0;
- }
-
/**
* Handles a pointer event sent from pip input consumer.
*/
void handlePointerEvent(MotionEvent ev) {
- if (mToActivityMessenger != null) {
- Message m = Message.obtain();
- m.what = PipMenuActivity.MESSAGE_POINTER_EVENT;
- m.obj = ev;
- try {
- mToActivityMessenger.send(m);
- } catch (RemoteException e) {
- Log.e(TAG, "Could not dispatch touch event", e);
- }
+ if (ev.isTouchEvent()) {
+ mPipMenuView.dispatchTouchEvent(ev);
+ } else {
+ mPipMenuView.dispatchGenericMotionEvent(ev);
}
}
@@ -582,15 +372,14 @@ public class PipMenuActivityController {
* Tell the PIP Menu to recalculate its layout given its current position on the display.
*/
public void updateMenuLayout(Rect bounds) {
- if (mToActivityMessenger != null) {
- Message m = Message.obtain();
- m.what = PipMenuActivity.MESSAGE_UPDATE_MENU_LAYOUT;
- m.obj = bounds;
- try {
- mToActivityMessenger.send(m);
- } catch (RemoteException e) {
- Log.e(TAG, "Could not dispatch touch event", e);
- }
+ final boolean isMenuVisible = isMenuVisible();
+ if (DEBUG) {
+ Log.d(TAG, "updateMenuLayout() state=" + mMenuState
+ + " isMenuVisible=" + isMenuVisible
+ + " callers=\n" + Debug.getCallers(5, " "));
+ }
+ if (isMenuVisible) {
+ mPipMenuView.updateMenuLayout(bounds);
}
}
@@ -598,9 +387,7 @@ public class PipMenuActivityController {
final String innerPrefix = prefix + " ";
pw.println(prefix + TAG);
pw.println(innerPrefix + "mMenuState=" + mMenuState);
- pw.println(innerPrefix + "mToActivityMessenger=" + mToActivityMessenger);
+ pw.println(innerPrefix + "mPipMenuView=" + mPipMenuView);
pw.println(innerPrefix + "mListeners=" + mListeners.size());
- pw.println(innerPrefix + "mStartActivityRequested=" + mStartActivityRequested);
- pw.println(innerPrefix + "mStartActivityRequestedTime=" + mStartActivityRequestedTime);
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/pip/phone/PipMenuActivity.java b/packages/SystemUI/src/com/android/systemui/pip/phone/PipMenuView.java
index 1b1b2de05883..993bfe04f9a3 100644
--- a/packages/SystemUI/src/com/android/systemui/pip/phone/PipMenuActivity.java
+++ b/packages/SystemUI/src/com/android/systemui/pip/phone/PipMenuView.java
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2016 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.
@@ -11,7 +11,7 @@
* 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
+ * limitations under the License.
*/
package com.android.systemui.pip.phone;
@@ -23,15 +23,6 @@ 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.systemui.pip.phone.PipMenuActivityController.EXTRA_ACTIONS;
-import static com.android.systemui.pip.phone.PipMenuActivityController.EXTRA_ALLOW_TIMEOUT;
-import static com.android.systemui.pip.phone.PipMenuActivityController.EXTRA_CONTROLLER_MESSENGER;
-import static com.android.systemui.pip.phone.PipMenuActivityController.EXTRA_DISMISS_FRACTION;
-import static com.android.systemui.pip.phone.PipMenuActivityController.EXTRA_MENU_STATE;
-import static com.android.systemui.pip.phone.PipMenuActivityController.EXTRA_SHOW_MENU_WITH_DELAY;
-import static com.android.systemui.pip.phone.PipMenuActivityController.EXTRA_SHOW_RESIZE_HANDLE;
-import static com.android.systemui.pip.phone.PipMenuActivityController.EXTRA_STACK_BOUNDS;
-import static com.android.systemui.pip.phone.PipMenuActivityController.EXTRA_WILL_RESIZE_MENU;
import static com.android.systemui.pip.phone.PipMenuActivityController.MENU_STATE_CLOSE;
import static com.android.systemui.pip.phone.PipMenuActivityController.MENU_STATE_FULL;
import static com.android.systemui.pip.phone.PipMenuActivityController.MENU_STATE_NONE;
@@ -41,14 +32,12 @@ import android.animation.AnimatorListenerAdapter;
import android.animation.AnimatorSet;
import android.animation.ObjectAnimator;
import android.animation.ValueAnimator;
-import android.annotation.Nullable;
-import android.app.Activity;
import android.app.ActivityManager;
import android.app.PendingIntent.CanceledException;
import android.app.RemoteAction;
import android.content.ComponentName;
+import android.content.Context;
import android.content.Intent;
-import android.content.pm.ParceledListSlice;
import android.graphics.Color;
import android.graphics.Rect;
import android.graphics.drawable.ColorDrawable;
@@ -56,10 +45,6 @@ import android.graphics.drawable.Drawable;
import android.net.Uri;
import android.os.Bundle;
import android.os.Handler;
-import android.os.Looper;
-import android.os.Message;
-import android.os.Messenger;
-import android.os.RemoteException;
import android.os.UserHandle;
import android.util.Log;
import android.util.Pair;
@@ -68,7 +53,6 @@ import android.view.LayoutInflater;
import android.view.MotionEvent;
import android.view.View;
import android.view.ViewGroup;
-import android.view.WindowManager.LayoutParams;
import android.view.accessibility.AccessibilityManager;
import android.view.accessibility.AccessibilityNodeInfo;
import android.widget.FrameLayout;
@@ -76,32 +60,20 @@ import android.widget.ImageButton;
import android.widget.LinearLayout;
import com.android.systemui.Interpolators;
-import com.android.wm.shell.R;
+import com.android.systemui.R;
import java.util.ArrayList;
-import java.util.Collections;
import java.util.List;
/**
- * Translucent activity that gets started on top of a task in PIP to allow the user to control it.
- * TODO(b/150319024): PipMenuActivity will move to a Window
+ * Translucent window that gets started on top of a task in PIP to allow the user to control it.
*/
-public class PipMenuActivity extends Activity {
+public class PipMenuView extends FrameLayout {
- private static final String TAG = "PipMenuActivity";
+ private static final String TAG = "PipMenuView";
private static final int MESSAGE_INVALID_TYPE = -1;
-
- public static final int MESSAGE_SHOW_MENU = 1;
- public static final int MESSAGE_POKE_MENU = 2;
- public static final int MESSAGE_HIDE_MENU = 3;
- public static final int MESSAGE_UPDATE_ACTIONS = 4;
- public static final int MESSAGE_UPDATE_DISMISS_FRACTION = 5;
- public static final int MESSAGE_ANIMATION_ENDED = 6;
- public static final int MESSAGE_POINTER_EVENT = 7;
public static final int MESSAGE_MENU_EXPANDED = 8;
- public static final int MESSAGE_FADE_OUT_MENU = 9;
- public static final int MESSAGE_UPDATE_MENU_LAYOUT = 10;
private static final int INITIAL_DISMISS_DELAY = 3500;
private static final int POST_INTERACTION_DISMISS_DELAY = 2000;
@@ -130,85 +102,20 @@ public class PipMenuActivity extends Activity {
private int mBetweenActionPaddingLand;
private AnimatorSet mMenuContainerAnimator;
+ private PipMenuActivityController mController;
private ValueAnimator.AnimatorUpdateListener mMenuBgUpdateListener =
new ValueAnimator.AnimatorUpdateListener() {
@Override
public void onAnimationUpdate(ValueAnimator animation) {
final float alpha = (float) animation.getAnimatedValue();
- mBackgroundDrawable.setAlpha((int) (MENU_BACKGROUND_ALPHA*alpha*255));
+ mBackgroundDrawable.setAlpha((int) (MENU_BACKGROUND_ALPHA * alpha * 255));
}
};
- private Handler mHandler = new Handler(Looper.getMainLooper()) {
- @Override
- public void handleMessage(Message msg) {
- switch (msg.what) {
- case MESSAGE_SHOW_MENU: {
- final Bundle data = (Bundle) msg.obj;
- showMenu(data.getInt(EXTRA_MENU_STATE),
- data.getParcelable(EXTRA_STACK_BOUNDS),
- data.getBoolean(EXTRA_ALLOW_TIMEOUT),
- data.getBoolean(EXTRA_WILL_RESIZE_MENU),
- data.getBoolean(EXTRA_SHOW_MENU_WITH_DELAY),
- data.getBoolean(EXTRA_SHOW_RESIZE_HANDLE));
- break;
- }
- case MESSAGE_POKE_MENU:
- cancelDelayedFinish();
- break;
- case MESSAGE_HIDE_MENU:
- hideMenu((Runnable) msg.obj);
- break;
- case MESSAGE_UPDATE_ACTIONS: {
- final Bundle data = (Bundle) msg.obj;
- final ParceledListSlice<RemoteAction> actions = data.getParcelable(
- EXTRA_ACTIONS);
- setActions(data.getParcelable(EXTRA_STACK_BOUNDS), actions != null
- ? actions.getList() : Collections.emptyList());
- break;
- }
- case MESSAGE_UPDATE_DISMISS_FRACTION: {
- final Bundle data = (Bundle) msg.obj;
- updateDismissFraction(data.getFloat(EXTRA_DISMISS_FRACTION));
- break;
- }
- case MESSAGE_ANIMATION_ENDED: {
- mAllowTouches = true;
- break;
- }
- case MESSAGE_POINTER_EVENT: {
- final MotionEvent ev = (MotionEvent) msg.obj;
- dispatchPointerEvent(ev);
- break;
- }
- case MESSAGE_MENU_EXPANDED : {
- if (mMenuContainerAnimator == null) {
- return;
- }
- mMenuContainerAnimator.setStartDelay(MENU_SHOW_ON_EXPAND_START_DELAY);
- mMenuContainerAnimator.start();
- break;
- }
- case MESSAGE_FADE_OUT_MENU: {
- fadeOutMenu();
- break;
- }
- case MESSAGE_UPDATE_MENU_LAYOUT: {
- if (mPipMenuIconsAlgorithm == null) {
- return;
- }
- final Rect bounds = (Rect) msg.obj;
- mPipMenuIconsAlgorithm.onBoundsChanged(bounds);
- break;
- }
- }
- }
- };
- private Messenger mToControllerMessenger;
- private Messenger mMessenger = new Messenger(mHandler);
+ private Handler mHandler = new Handler();
- private final Runnable mFinishRunnable = this::hideMenu;
+ private final Runnable mHideMenuRunnable = this::hideMenu;
protected View mViewRoot;
protected View mSettingsButton;
@@ -217,17 +124,14 @@ public class PipMenuActivity extends Activity {
protected View mTopEndContainer;
protected PipMenuIconsAlgorithm mPipMenuIconsAlgorithm;
- @Override
- protected void onCreate(@Nullable Bundle savedInstanceState) {
- // Set the flags to allow us to watch for outside touches and also hide the menu and start
- // manipulating the PIP in the same touch gesture
- getWindow().addFlags(LayoutParams.FLAG_WATCH_OUTSIDE_TOUCH);
-
- super.onCreate(savedInstanceState);
+ public PipMenuView(Context context, PipMenuActivityController controller) {
+ super(context, null, 0);
+ mContext = context;
+ mController = controller;
- setContentView(R.layout.pip_menu_activity);
+ mAccessibilityManager = context.getSystemService(AccessibilityManager.class);
+ inflate(context, R.layout.pip_menu, this);
- mAccessibilityManager = getSystemService(AccessibilityManager.class);
mBackgroundDrawable = new ColorDrawable(Color.BLACK);
mBackgroundDrawable.setAlpha(0);
mViewRoot = findViewById(R.id.background);
@@ -250,26 +154,25 @@ public class PipMenuActivity extends Activity {
expandPip();
}
});
+ // TODO (b/161710689): Remove this once focusability for Windowless window is working
+ findViewById(R.id.expand_button).setFocusable(false);
+ mDismissButton.setFocusable(false);
+ mSettingsButton.setFocusable(false);
+
mResizeHandle = findViewById(R.id.resize_handle);
mResizeHandle.setAlpha(0);
mActionsGroup = findViewById(R.id.actions_group);
mBetweenActionPaddingLand = getResources().getDimensionPixelSize(
R.dimen.pip_between_action_padding_land);
- mPipMenuIconsAlgorithm = new PipMenuIconsAlgorithm(this.getApplicationContext());
+ mPipMenuIconsAlgorithm = new PipMenuIconsAlgorithm(mContext);
mPipMenuIconsAlgorithm.bindViews((ViewGroup) mViewRoot, (ViewGroup) mTopEndContainer,
mResizeHandle, mSettingsButton, mDismissButton);
- updateFromIntent(getIntent());
- setTitle(R.string.pip_menu_title);
- setDisablePreviewScreenshots(true);
-
- // Hide without an animation.
- getWindow().setExitTransition(null);
initAccessibility();
}
private void initAccessibility() {
- getWindow().getDecorView().setAccessibilityDelegate(new View.AccessibilityDelegate() {
+ this.setAccessibilityDelegate(new View.AccessibilityDelegate() {
@Override
public void onInitializeAccessibilityNodeInfo(View host, AccessibilityNodeInfo info) {
super.onInitializeAccessibilityNodeInfo(host, info);
@@ -280,9 +183,7 @@ public class PipMenuActivity extends Activity {
@Override
public boolean performAccessibilityAction(View host, int action, Bundle args) {
if (action == ACTION_CLICK && mMenuState == MENU_STATE_CLOSE) {
- Message m = Message.obtain();
- m.what = PipMenuActivityController.MESSAGE_SHOW_MENU;
- sendMessage(m, "Could not notify controller to show PIP menu");
+ mController.onPipShowMenu();
}
return super.performAccessibilityAction(host, action, args);
}
@@ -299,108 +200,37 @@ public class PipMenuActivity extends Activity {
}
@Override
- protected void onNewIntent(Intent intent) {
- super.onNewIntent(intent);
- updateFromIntent(intent);
- }
-
- @Override
- public void onUserInteraction() {
- if (mAllowMenuTimeout) {
- repostDelayedFinish(POST_INTERACTION_DISMISS_DELAY);
- }
- }
-
- @Override
- protected void onUserLeaveHint() {
- super.onUserLeaveHint();
-
- // If another task is starting on top of the menu, then hide and finish it so that it can be
- // recreated on the top next time it starts
- hideMenu();
- }
-
- @Override
- public void onTopResumedActivityChanged(boolean isTopResumedActivity) {
- super.onTopResumedActivityChanged(isTopResumedActivity);
- if (!isTopResumedActivity && mMenuState != MENU_STATE_NONE) {
- hideMenu();
- }
- }
-
- @Override
- protected void onStop() {
- super.onStop();
-
- // In cases such as device lock, hide and finish it so that it can be recreated on the top
- // next time it starts, see also {@link #onUserLeaveHint}
- hideMenu();
- cancelDelayedFinish();
- }
-
- @Override
- protected void onDestroy() {
- super.onDestroy();
-
- // Fallback, if we are destroyed for any other reason (like when the task is being reset),
- // also reset the callback.
- notifyActivityCallback(null);
- }
-
- @Override
- public void onPictureInPictureModeChanged(boolean isInPictureInPictureMode) {
- if (!isInPictureInPictureMode) {
- finish();
- }
- }
-
- /**
- * Dispatch a pointer event from {@link PipTouchHandler}.
- */
- private void dispatchPointerEvent(MotionEvent event) {
- if (event.isTouchEvent()) {
- dispatchTouchEvent(event);
- } else {
- dispatchGenericMotionEvent(event);
- }
- }
-
- @Override
public boolean dispatchTouchEvent(MotionEvent ev) {
if (!mAllowTouches) {
return false;
}
- // On the first action outside the window, hide the menu
- switch (ev.getAction()) {
- case MotionEvent.ACTION_OUTSIDE:
- hideMenu();
- return true;
+ if (mAllowMenuTimeout) {
+ repostDelayedHide(POST_INTERACTION_DISMISS_DELAY);
}
+
return super.dispatchTouchEvent(ev);
}
@Override
- public void finish() {
- notifyActivityCallback(null);
- super.finish();
- }
+ public boolean dispatchGenericMotionEvent(MotionEvent event) {
+ if (mAllowMenuTimeout) {
+ repostDelayedHide(POST_INTERACTION_DISMISS_DELAY);
+ }
- @Override
- public void setTaskDescription(ActivityManager.TaskDescription taskDescription) {
- // Do nothing
+ return super.dispatchGenericMotionEvent(event);
}
- private void showMenu(int menuState, Rect stackBounds, boolean allowMenuTimeout,
+ void showMenu(int menuState, Rect stackBounds, boolean allowMenuTimeout,
boolean resizeMenuOnShow, boolean withDelay, boolean showResizeHandle) {
mAllowMenuTimeout = allowMenuTimeout;
if (mMenuState != menuState) {
// Disallow touches if the menu needs to resize while showing, and we are transitioning
// to/from a full menu state.
- boolean disallowTouchesUntilAnimationEnd = resizeMenuOnShow &&
- (mMenuState == MENU_STATE_FULL || menuState == MENU_STATE_FULL);
+ boolean disallowTouchesUntilAnimationEnd = resizeMenuOnShow
+ && (mMenuState == MENU_STATE_FULL || menuState == MENU_STATE_FULL);
mAllowTouches = !disallowTouchesUntilAnimationEnd;
- cancelDelayedFinish();
+ cancelDelayedHide();
updateActionViews(stackBounds);
if (mMenuContainerAnimator != null) {
mMenuContainerAnimator.cancel();
@@ -431,22 +261,28 @@ public class PipMenuActivity extends Activity {
mMenuContainerAnimator.addListener(new AnimatorListenerAdapter() {
@Override
public void onAnimationEnd(Animator animation) {
- repostDelayedFinish(INITIAL_DISMISS_DELAY);
+ repostDelayedHide(INITIAL_DISMISS_DELAY);
}
});
}
if (withDelay) {
// starts the menu container animation after window expansion is completed
- notifyMenuStateChange(menuState, resizeMenuOnShow, MESSAGE_MENU_EXPANDED);
+ notifyMenuStateChange(menuState, resizeMenuOnShow, () -> {
+ if (mMenuContainerAnimator == null) {
+ return;
+ }
+ mMenuContainerAnimator.setStartDelay(MENU_SHOW_ON_EXPAND_START_DELAY);
+ mMenuContainerAnimator.start();
+ });
} else {
- notifyMenuStateChange(menuState, resizeMenuOnShow, MESSAGE_INVALID_TYPE);
+ notifyMenuStateChange(menuState, resizeMenuOnShow, null);
mMenuContainerAnimator.start();
}
} else {
// If we are already visible, then just start the delayed dismiss and unregister any
// existing input consumers from the previous drag
if (allowMenuTimeout) {
- repostDelayedFinish(POST_INTERACTION_DISMISS_DELAY);
+ repostDelayedHide(POST_INTERACTION_DISMISS_DELAY);
}
}
}
@@ -456,28 +292,39 @@ public class PipMenuActivity extends Activity {
* and instead, it fades out the controls by setting the alpha to 0 directly without menu
* visibility callbacks invoked.
*/
- private void fadeOutMenu() {
+ void fadeOutMenu() {
mMenuContainer.setAlpha(0f);
mSettingsButton.setAlpha(0f);
mDismissButton.setAlpha(0f);
mResizeHandle.setAlpha(0f);
}
- private void hideMenu() {
+ void pokeMenu() {
+ cancelDelayedHide();
+ }
+
+ void onPipAnimationEnded() {
+ mAllowTouches = true;
+ }
+
+ void updateMenuLayout(Rect bounds) {
+ mPipMenuIconsAlgorithm.onBoundsChanged(bounds);
+ }
+
+ void hideMenu() {
hideMenu(null);
}
- private void hideMenu(Runnable animationEndCallback) {
- hideMenu(animationEndCallback, true /* notifyMenuVisibility */, false /* isDismissing */,
- true /* animate */);
+ void hideMenu(Runnable animationEndCallback) {
+ hideMenu(animationEndCallback, true /* notifyMenuVisibility */, false);
}
private void hideMenu(final Runnable animationFinishedRunnable, boolean notifyMenuVisibility,
- boolean isDismissing, boolean animate) {
+ boolean animate) {
if (mMenuState != MENU_STATE_NONE) {
- cancelDelayedFinish();
+ cancelDelayedHide();
if (notifyMenuVisibility) {
- notifyMenuStateChange(MENU_STATE_NONE, mResize, MESSAGE_INVALID_TYPE);
+ notifyMenuStateChange(MENU_STATE_NONE, mResize, null);
}
mMenuContainerAnimator = new AnimatorSet();
ObjectAnimator menuAnim = ObjectAnimator.ofFloat(mMenuContainer, View.ALPHA,
@@ -498,49 +345,13 @@ public class PipMenuActivity extends Activity {
if (animationFinishedRunnable != null) {
animationFinishedRunnable.run();
}
-
- if (!isDismissing) {
- // If we are dismissing the PiP, then don't try to pre-emptively finish the
- // menu activity
- finish();
- }
}
});
mMenuContainerAnimator.start();
- } else {
- // If the menu is not visible, just finish now
- finish();
}
}
- private void updateFromIntent(Intent intent) {
- mToControllerMessenger = intent.getParcelableExtra(EXTRA_CONTROLLER_MESSENGER);
- if (mToControllerMessenger == null) {
- Log.w(TAG, "Controller messenger is null. Stopping.");
- finish();
- return;
- }
- notifyActivityCallback(mMessenger);
-
- ParceledListSlice<RemoteAction> actions = intent.getParcelableExtra(EXTRA_ACTIONS);
- if (actions != null) {
- mActions.clear();
- mActions.addAll(actions.getList());
- }
-
- final int menuState = intent.getIntExtra(EXTRA_MENU_STATE, MENU_STATE_NONE);
- if (menuState != MENU_STATE_NONE) {
- Rect stackBounds = intent.getParcelableExtra(EXTRA_STACK_BOUNDS);
- boolean allowMenuTimeout = intent.getBooleanExtra(EXTRA_ALLOW_TIMEOUT, true);
- boolean willResizeMenu = intent.getBooleanExtra(EXTRA_WILL_RESIZE_MENU, false);
- boolean withDelay = intent.getBooleanExtra(EXTRA_SHOW_MENU_WITH_DELAY, false);
- boolean showResizeHandle = intent.getBooleanExtra(EXTRA_SHOW_RESIZE_HANDLE, false);
- showMenu(menuState, stackBounds, allowMenuTimeout, willResizeMenu, withDelay,
- showResizeHandle);
- }
- }
-
- private void setActions(Rect stackBounds, List<RemoteAction> actions) {
+ void setActions(Rect stackBounds, List<RemoteAction> actions) {
mActions.clear();
mActions.addAll(actions);
updateActionViews(stackBounds);
@@ -560,7 +371,7 @@ public class PipMenuActivity extends Activity {
actionsContainer.setVisibility(View.VISIBLE);
if (mActionsGroup != null) {
// Ensure we have as many buttons as actions
- final LayoutInflater inflater = LayoutInflater.from(this);
+ final LayoutInflater inflater = LayoutInflater.from(mContext);
while (mActionsGroup.getChildCount() < mActions.size()) {
final ImageButton actionView = (ImageButton) inflater.inflate(
R.layout.pip_menu_action, mActionsGroup, false);
@@ -575,14 +386,14 @@ public class PipMenuActivity extends Activity {
}
// Recreate the layout
- final boolean isLandscapePip = stackBounds != null &&
- (stackBounds.width() > stackBounds.height());
+ final boolean isLandscapePip = stackBounds != null
+ && (stackBounds.width() > stackBounds.height());
for (int i = 0; i < mActions.size(); i++) {
final RemoteAction action = mActions.get(i);
final ImageButton actionView = (ImageButton) mActionsGroup.getChildAt(i);
// TODO: Check if the action drawable has changed before we reload it
- action.getIcon().loadDrawableAsync(this, d -> {
+ action.getIcon().loadDrawableAsync(mContext, d -> {
d.setTint(Color.WHITE);
actionView.setImageDrawable(d);
}, mHandler);
@@ -620,7 +431,7 @@ public class PipMenuActivity extends Activity {
}
}
- private void updateDismissFraction(float fraction) {
+ void updateDismissFraction(float fraction) {
int alpha;
final float menuAlpha = 1 - fraction;
if (mMenuState == MENU_STATE_FULL) {
@@ -639,31 +450,15 @@ public class PipMenuActivity extends Activity {
mBackgroundDrawable.setAlpha(alpha);
}
- private void notifyMenuStateChange(int menuState, boolean resize, int callbackWhat) {
+ private void notifyMenuStateChange(int menuState, boolean resize, Runnable callback) {
mMenuState = menuState;
- mResize = resize;
- Message m = Message.obtain();
- m.what = PipMenuActivityController.MESSAGE_MENU_STATE_CHANGED;
- m.arg1 = menuState;
- m.arg2 = resize ? 1 : 0;
- if (callbackWhat != MESSAGE_INVALID_TYPE) {
- // This message could be sent across processes when in secondary user.
- // Make the receiver end sending back via our own Messenger
- m.replyTo = mMessenger;
- final Bundle data = new Bundle(1);
- data.putInt(PipMenuActivityController.EXTRA_MESSAGE_CALLBACK_WHAT, callbackWhat);
- m.obj = data;
- }
- sendMessage(m, "Could not notify controller of PIP menu visibility");
+ mController.onMenuStateChanged(menuState, resize, callback);
}
private void expandPip() {
// Do not notify menu visibility when hiding the menu, the controller will do this when it
// handles the message
- hideMenu(() -> {
- sendEmptyMessage(PipMenuActivityController.MESSAGE_EXPAND_PIP,
- "Could not notify controller to expand PIP");
- }, false /* notifyMenuVisibility */, false /* isDismissing */, true /* animate */);
+ hideMenu(mController::onPipExpand, false /* notifyMenuVisibility */, true /* animate */);
}
private void dismissPip() {
@@ -673,58 +468,30 @@ public class PipMenuActivity extends Activity {
final boolean animate = mMenuState != MENU_STATE_CLOSE;
// Do not notify menu visibility when hiding the menu, the controller will do this when it
// handles the message
- hideMenu(() -> {
- sendEmptyMessage(PipMenuActivityController.MESSAGE_DISMISS_PIP,
- "Could not notify controller to dismiss PIP");
- }, false /* notifyMenuVisibility */, true /* isDismissing */, animate);
+ hideMenu(mController::onPipDismiss, false /* notifyMenuVisibility */, animate);
}
private void showSettings() {
final Pair<ComponentName, Integer> topPipActivityInfo =
- PipUtils.getTopPipActivity(this, ActivityManager.getService());
+ PipUtils.getTopPipActivity(mContext, ActivityManager.getService());
if (topPipActivityInfo.first != null) {
final UserHandle user = UserHandle.of(topPipActivityInfo.second);
final Intent settingsIntent = new Intent(ACTION_PICTURE_IN_PICTURE_SETTINGS,
Uri.fromParts("package", topPipActivityInfo.first.getPackageName(), null));
settingsIntent.putExtra(Intent.EXTRA_USER_HANDLE, user);
settingsIntent.setFlags(FLAG_ACTIVITY_NEW_TASK | FLAG_ACTIVITY_CLEAR_TASK);
- startActivity(settingsIntent);
- }
- }
-
- private void notifyActivityCallback(Messenger callback) {
- Message m = Message.obtain();
- m.what = PipMenuActivityController.MESSAGE_UPDATE_ACTIVITY_CALLBACK;
- m.replyTo = callback;
- m.arg1 = mResize ? 1 : 0;
- sendMessage(m, "Could not notify controller of activity finished");
- }
-
- private void sendEmptyMessage(int what, String errorMsg) {
- Message m = Message.obtain();
- m.what = what;
- sendMessage(m, errorMsg);
- }
-
- private void sendMessage(Message m, String errorMsg) {
- if (mToControllerMessenger == null) {
- return;
- }
- try {
- mToControllerMessenger.send(m);
- } catch (RemoteException e) {
- Log.e(TAG, errorMsg, e);
+ mContext.startActivity(settingsIntent);
}
}
- private void cancelDelayedFinish() {
- mHandler.removeCallbacks(mFinishRunnable);
+ private void cancelDelayedHide() {
+ mHandler.removeCallbacks(mHideMenuRunnable);
}
- private void repostDelayedFinish(int delay) {
+ private void repostDelayedHide(int delay) {
int recommendedTimeout = mAccessibilityManager.getRecommendedTimeoutMillis(delay,
FLAG_CONTENT_ICONS | FLAG_CONTENT_CONTROLS);
- mHandler.removeCallbacks(mFinishRunnable);
- mHandler.postDelayed(mFinishRunnable, recommendedTimeout);
+ mHandler.removeCallbacks(mHideMenuRunnable);
+ mHandler.postDelayed(mHideMenuRunnable, recommendedTimeout);
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/pip/phone/PipMotionHelper.java b/packages/SystemUI/src/com/android/systemui/pip/phone/PipMotionHelper.java
index 19138fdba788..dcee2a5b4b20 100644
--- a/packages/SystemUI/src/com/android/systemui/pip/phone/PipMotionHelper.java
+++ b/packages/SystemUI/src/com/android/systemui/pip/phone/PipMotionHelper.java
@@ -23,6 +23,8 @@ import android.content.Context;
import android.graphics.PointF;
import android.graphics.Rect;
import android.os.Debug;
+import android.os.Handler;
+import android.os.Looper;
import android.util.Log;
import android.view.Choreographer;
@@ -66,6 +68,8 @@ public class PipMotionHelper implements PipAppOpsListener.Callback,
private PipMenuActivityController mMenuController;
private PipSnapAlgorithm mSnapAlgorithm;
+ private final Handler mMainHandler = new Handler(Looper.getMainLooper());
+
/** PIP's current bounds on the screen. */
private final Rect mBounds = new Rect();
@@ -128,8 +132,10 @@ public class PipMotionHelper implements PipAppOpsListener.Callback,
SpringForce.STIFFNESS_LOW, SpringForce.DAMPING_RATIO_LOW_BOUNCY);
private final Consumer<Rect> mUpdateBoundsCallback = (Rect newBounds) -> {
- mMenuController.updateMenuLayout(newBounds);
- mBounds.set(newBounds);
+ mMainHandler.post(() -> {
+ mMenuController.updateMenuLayout(newBounds);
+ mBounds.set(newBounds);
+ });
};
/**
@@ -253,7 +259,9 @@ public class PipMotionHelper implements PipAppOpsListener.Callback,
mTemporaryBounds.set(toBounds);
mPipTaskOrganizer.scheduleUserResizePip(mBounds, mTemporaryBounds,
(Rect newBounds) -> {
- mMenuController.updateMenuLayout(newBounds);
+ mMainHandler.post(() -> {
+ mMenuController.updateMenuLayout(newBounds);
+ });
});
}
} else {
diff --git a/packages/SystemUI/src/com/android/systemui/pip/phone/PipResizeGestureHandler.java b/packages/SystemUI/src/com/android/systemui/pip/phone/PipResizeGestureHandler.java
index 2800bb938149..50d20d3572d1 100644
--- a/packages/SystemUI/src/com/android/systemui/pip/phone/PipResizeGestureHandler.java
+++ b/packages/SystemUI/src/com/android/systemui/pip/phone/PipResizeGestureHandler.java
@@ -111,6 +111,7 @@ public class PipResizeGestureHandler {
private InputMonitor mInputMonitor;
private InputEventReceiver mInputEventReceiver;
private PipTaskOrganizer mPipTaskOrganizer;
+ private PipMenuActivityController mPipMenuActivityController;
private PipUiEventLogger mPipUiEventLogger;
private int mCtrlType;
@@ -119,7 +120,7 @@ public class PipResizeGestureHandler {
PipMotionHelper motionHelper, DeviceConfigProxy deviceConfig,
PipTaskOrganizer pipTaskOrganizer, Function<Rect, Rect> movementBoundsSupplier,
Runnable updateMovementBoundsRunnable, SysUiState sysUiState,
- PipUiEventLogger pipUiEventLogger) {
+ PipUiEventLogger pipUiEventLogger, PipMenuActivityController menuActivityController) {
mContext = context;
mDisplayId = context.getDisplayId();
mMainExecutor = context.getMainExecutor();
@@ -129,6 +130,7 @@ public class PipResizeGestureHandler {
mMovementBoundsSupplier = movementBoundsSupplier;
mUpdateMovementBoundsRunnable = updateMovementBoundsRunnable;
mSysUiState = sysUiState;
+ mPipMenuActivityController = menuActivityController;
mPipUiEventLogger = pipUiEventLogger;
context.getDisplay().getRealSize(mMaxSize);
@@ -298,6 +300,7 @@ public class PipResizeGestureHandler {
float x = ev.getX();
float y = ev.getY();
if (action == MotionEvent.ACTION_DOWN) {
+ final Rect currentPipBounds = mMotionHelper.getBounds();
mLastResizeBounds.setEmpty();
mAllowGesture = isInValidSysUiState() && isWithinTouchRegion((int) x, (int) y);
if (mAllowGesture) {
@@ -305,6 +308,10 @@ public class PipResizeGestureHandler {
mDownPoint.set(x, y);
mLastDownBounds.set(mMotionHelper.getBounds());
}
+ if (!currentPipBounds.contains((int) ev.getX(), (int) ev.getY())
+ && mPipMenuActivityController.isMenuVisible()) {
+ mPipMenuActivityController.hideMenu();
+ }
} else if (mAllowGesture) {
switch (action) {
@@ -322,6 +329,10 @@ public class PipResizeGestureHandler {
mInputMonitor.pilferPointers();
}
if (mThresholdCrossed) {
+ if (mPipMenuActivityController.isMenuVisible()) {
+ mPipMenuActivityController.hideMenuWithoutResize();
+ mPipMenuActivityController.hideMenu();
+ }
final Rect currentPipBounds = mMotionHelper.getBounds();
mLastResizeBounds.set(TaskResizingAlgorithm.resizeDrag(x, y,
mDownPoint.x, mDownPoint.y, currentPipBounds, mCtrlType, mMinSize.x,
diff --git a/packages/SystemUI/src/com/android/systemui/pip/phone/PipTouchHandler.java b/packages/SystemUI/src/com/android/systemui/pip/phone/PipTouchHandler.java
index 1b84c1417c51..9693f235a4ff 100644
--- a/packages/SystemUI/src/com/android/systemui/pip/phone/PipTouchHandler.java
+++ b/packages/SystemUI/src/com/android/systemui/pip/phone/PipTouchHandler.java
@@ -230,7 +230,7 @@ public class PipTouchHandler {
mPipResizeGestureHandler =
new PipResizeGestureHandler(context, pipBoundsHandler, mMotionHelper,
deviceConfig, pipTaskOrganizer, this::getMovementBounds,
- this::updateMovementBounds, sysUiState, pipUiEventLogger);
+ this::updateMovementBounds, sysUiState, pipUiEventLogger, menuController);
mTouchState = new PipTouchState(ViewConfiguration.get(context), mHandler,
() -> mMenuController.showMenuWithDelay(MENU_STATE_FULL, mMotionHelper.getBounds(),
true /* allowMenuTimeout */, willResizeMenu(), shouldShowResizeHandle()),
@@ -773,10 +773,7 @@ public class PipTouchHandler {
* Updates the appearance of the menu and scrim on top of the PiP while dismissing.
*/
private void updateDismissFraction() {
- // Skip updating the dismiss fraction when the IME is showing. This is to work around an
- // issue where starting the menu activity for the dismiss overlay will steal the window
- // focus, which closes the IME.
- if (mMenuController != null && !mIsImeShowing) {
+ if (mMenuController != null) {
Rect bounds = mMotionHelper.getBounds();
final float target = mInsetBounds.bottom;
float fraction = 0f;
@@ -784,7 +781,7 @@ public class PipTouchHandler {
final float distance = bounds.bottom - target;
fraction = Math.min(distance / bounds.height(), 1f);
}
- if (Float.compare(fraction, 0f) != 0 || mMenuController.isMenuActivityVisible()) {
+ if (Float.compare(fraction, 0f) != 0 || mMenuController.isMenuVisible()) {
// Update if the fraction > 0, or if fraction == 0 and the menu was already visible
mMenuController.setDismissFraction(fraction);
}
diff --git a/packages/SystemUI/src/com/android/systemui/pip/tv/PipManager.java b/packages/SystemUI/src/com/android/systemui/pip/tv/PipController.java
index 5d8e6306ba69..3b3235f1e63c 100644
--- a/packages/SystemUI/src/com/android/systemui/pip/tv/PipManager.java
+++ b/packages/SystemUI/src/com/android/systemui/pip/tv/PipController.java
@@ -20,7 +20,6 @@ import static android.app.ActivityTaskManager.INVALID_STACK_ID;
import static android.app.WindowConfiguration.ACTIVITY_TYPE_UNDEFINED;
import static android.app.WindowConfiguration.WINDOWING_MODE_PINNED;
-import android.annotation.NonNull;
import android.app.ActivityManager.RunningTaskInfo;
import android.app.ActivityManager.StackInfo;
import android.app.ActivityTaskManager;
@@ -51,35 +50,32 @@ import com.android.systemui.R;
import com.android.systemui.UiOffloadThread;
import com.android.systemui.broadcast.BroadcastDispatcher;
import com.android.systemui.dagger.SysUISingleton;
-import com.android.systemui.pip.BasePipManager;
+import com.android.systemui.pip.Pip;
import com.android.systemui.pip.PipBoundsHandler;
import com.android.systemui.pip.PipSurfaceTransactionHelper;
import com.android.systemui.pip.PipTaskOrganizer;
-import com.android.systemui.pip.PipUiEventLogger;
import com.android.systemui.shared.system.ActivityManagerWrapper;
import com.android.systemui.shared.system.PinnedStackListenerForwarder.PinnedStackListener;
import com.android.systemui.shared.system.TaskStackChangeListener;
import com.android.systemui.shared.system.WindowManagerWrapper;
-import com.android.systemui.stackdivider.SplitScreenController;
-import com.android.systemui.statusbar.policy.ConfigurationController;
-import com.android.wm.shell.ShellTaskOrganizer;
-import com.android.wm.shell.common.DisplayController;
import java.util.ArrayList;
import java.util.List;
import java.util.Optional;
-import javax.inject.Inject;
-
/**
* Manages the picture-in-picture (PIP) UI and states.
*/
@SysUISingleton
-public class PipManager implements BasePipManager, PipTaskOrganizer.PipTransitionCallback {
- private static final String TAG = "PipManager";
+public class PipController implements Pip, PipTaskOrganizer.PipTransitionCallback {
+ private static final String TAG = "PipController";
static final boolean DEBUG = Log.isLoggable(TAG, Log.DEBUG);
/**
+ * Unknown or invalid state
+ */
+ public static final int STATE_UNKNOWN = -1;
+ /**
* State when there's no PIP.
*/
public static final int STATE_NO_PIP = 0;
@@ -142,13 +138,12 @@ public class PipManager implements BasePipManager, PipTaskOrganizer.PipTransitio
// Used to calculate the movement bounds
private final DisplayInfo mTmpDisplayInfo = new DisplayInfo();
private final Rect mTmpInsetBounds = new Rect();
- private final Rect mTmpNormalBounds = new Rect();
// Keeps track of the IME visibility to adjust the PiP when the IME is visible
private boolean mImeVisible;
private int mImeHeightAdjustment;
- private final PinnedStackListener mPinnedStackListener = new PipManagerPinnedStackListener();
+ private final PinnedStackListener mPinnedStackListener = new PipControllerPinnedStackListener();
private final Runnable mResizePinnedStackRunnable = new Runnable() {
@Override
@@ -190,7 +185,7 @@ public class PipManager implements BasePipManager, PipTaskOrganizer.PipTransitio
/**
* Handler for messages from the PIP controller.
*/
- private class PipManagerPinnedStackListener extends PinnedStackListener {
+ private class PipControllerPinnedStackListener extends PinnedStackListener {
@Override
public void onImeVisibilityChanged(boolean imeVisible, int imeHeight) {
mHandler.post(() -> {
@@ -216,10 +211,8 @@ public class PipManager implements BasePipManager, PipTaskOrganizer.PipTransitio
public void onMovementBoundsChanged(boolean fromImeAdjustment) {
mHandler.post(() -> {
// Populate the inset / normal bounds and DisplayInfo from mPipBoundsHandler first.
- final Rect destinationBounds = new Rect();
- mPipBoundsHandler.onMovementBoundsChanged(mTmpInsetBounds, mTmpNormalBounds,
- destinationBounds, mTmpDisplayInfo);
- mDefaultPipBounds.set(destinationBounds);
+ mPipBoundsHandler.onMovementBoundsChanged(mTmpInsetBounds, mPipBounds,
+ mDefaultPipBounds, mTmpDisplayInfo);
});
}
@@ -234,20 +227,19 @@ public class PipManager implements BasePipManager, PipTaskOrganizer.PipTransitio
}
}
- @Inject
- public PipManager(Context context, BroadcastDispatcher broadcastDispatcher,
- ConfigurationController configController,
- DisplayController displayController,
- Optional<SplitScreenController> splitScreenControllerOptional,
- @NonNull PipUiEventLogger pipUiEventLogger,
- ShellTaskOrganizer shellTaskOrganizer) {
+ public PipController(Context context, BroadcastDispatcher broadcastDispatcher,
+ PipBoundsHandler pipBoundsHandler,
+ PipSurfaceTransactionHelper pipSurfaceTransactionHelper,
+ PipTaskOrganizer pipTaskOrganizer) {
if (mInitialized) {
return;
}
mInitialized = true;
mContext = context;
- mPipBoundsHandler = new PipBoundsHandler(mContext);
+ mPipNotification = new PipNotification(context, broadcastDispatcher,
+ Optional.of(this).get());
+ mPipBoundsHandler = pipBoundsHandler;
// 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();
@@ -256,10 +248,8 @@ public class PipManager implements BasePipManager, PipTaskOrganizer.PipTransitio
mResizeAnimationDuration = context.getResources()
.getInteger(R.integer.config_pipResizeAnimationDuration);
- mPipSurfaceTransactionHelper = new PipSurfaceTransactionHelper(context, configController);
- mPipTaskOrganizer = new PipTaskOrganizer(mContext, mPipBoundsHandler,
- mPipSurfaceTransactionHelper, splitScreenControllerOptional, displayController,
- pipUiEventLogger, shellTaskOrganizer);
+ mPipSurfaceTransactionHelper = pipSurfaceTransactionHelper;
+ mPipTaskOrganizer = pipTaskOrganizer;
mPipTaskOrganizer.registerPipTransitionCallback(this);
mActivityTaskManager = ActivityTaskManager.getService();
ActivityManagerWrapper.getInstance().registerTaskStackListener(mTaskStackListener);
@@ -281,8 +271,6 @@ public class PipManager implements BasePipManager, PipTaskOrganizer.PipTransitio
} catch (RemoteException | UnsupportedOperationException e) {
Log.e(TAG, "Failed to register pinned stack listener", e);
}
-
- mPipNotification = new PipNotification(context, broadcastDispatcher, this);
}
private void loadConfigurationsAndApply(Configuration newConfig) {
@@ -362,7 +350,7 @@ public class PipManager implements BasePipManager, PipTaskOrganizer.PipTransitio
/**
* Moves the PIPed activity to the fullscreen and closes PIP system UI.
*/
- void movePipToFullscreen() {
+ public void movePipToFullscreen() {
if (DEBUG) Log.d(TAG, "movePipToFullscreen(), current state=" + getStateDescription());
mPipTaskId = TASK_ID_NO_PIP;
@@ -375,34 +363,41 @@ public class PipManager implements BasePipManager, PipTaskOrganizer.PipTransitio
/**
* Suspends resizing operation on the Pip until {@link #resumePipResizing} is called
+ *
* @param reason The reason for suspending resizing operations on the Pip.
*/
public void suspendPipResizing(int reason) {
- if (DEBUG) Log.d(TAG,
- "suspendPipResizing() reason=" + reason + " callers=" + Debug.getCallers(2));
+ if (DEBUG) {
+ Log.d(TAG,
+ "suspendPipResizing() reason=" + reason + " callers=" + Debug.getCallers(2));
+ }
mSuspendPipResizingReason |= reason;
}
/**
* Resumes resizing operation on the Pip that was previously suspended.
+ *
* @param reason The reason resizing operations on the Pip was suspended.
*/
public void resumePipResizing(int reason) {
if ((mSuspendPipResizingReason & reason) == 0) {
return;
}
- if (DEBUG) Log.d(TAG,
- "resumePipResizing() reason=" + reason + " callers=" + Debug.getCallers(2));
+ if (DEBUG) {
+ Log.d(TAG,
+ "resumePipResizing() reason=" + reason + " callers=" + Debug.getCallers(2));
+ }
mSuspendPipResizingReason &= ~reason;
mHandler.post(mResizePinnedStackRunnable);
}
/**
* Resize the Pip to the appropriate size for the input state.
+ *
* @param state In Pip state also used to determine the new size for the Pip.
*/
- void resizePinnedStack(int state) {
+ public void resizePinnedStack(int state) {
if (DEBUG) {
Log.d(TAG, "resizePinnedStack() state=" + stateToName(state) + ", current state="
+ getStateDescription(), new Exception());
@@ -414,10 +409,12 @@ public class PipManager implements BasePipManager, PipTaskOrganizer.PipTransitio
}
if (mSuspendPipResizingReason != 0) {
mResumeResizePinnedStackRunnableState = state;
- if (DEBUG) Log.d(TAG, "resizePinnedStack() deferring"
- + " mSuspendPipResizingReason=" + mSuspendPipResizingReason
- + " mResumeResizePinnedStackRunnableState="
- + stateToName(mResumeResizePinnedStackRunnableState));
+ if (DEBUG) {
+ Log.d(TAG, "resizePinnedStack() deferring"
+ + " mSuspendPipResizingReason=" + mSuspendPipResizingReason
+ + " mResumeResizePinnedStackRunnableState="
+ + stateToName(mResumeResizePinnedStackRunnableState));
+ }
return;
}
mState = state;
@@ -474,28 +471,28 @@ public class PipManager implements BasePipManager, PipTaskOrganizer.PipTransitio
}
/**
- * Adds a {@link Listener} to PipManager.
+ * Adds a {@link Listener} to PipController.
*/
public void addListener(Listener listener) {
mListeners.add(listener);
}
/**
- * Removes a {@link Listener} from PipManager.
+ * Removes a {@link Listener} from PipController.
*/
public void removeListener(Listener listener) {
mListeners.remove(listener);
}
/**
- * Adds a {@link MediaListener} to PipManager.
+ * Adds a {@link MediaListener} to PipController.
*/
public void addMediaListener(MediaListener listener) {
mMediaListeners.add(listener);
}
/**
- * Removes a {@link MediaListener} from PipManager.
+ * Removes a {@link MediaListener} from PipController.
*/
public void removeMediaListener(MediaListener listener) {
mMediaListeners.remove(listener);
@@ -571,16 +568,21 @@ public class PipManager implements BasePipManager, PipTaskOrganizer.PipTransitio
/**
* Gets the {@link android.media.session.MediaController} for the PIPed activity.
*/
- MediaController getMediaController() {
+ public MediaController getMediaController() {
return mPipMediaController;
}
+ @Override
+ public void hidePipMenu(Runnable onStartCallback, Runnable onEndCallback) {
+
+ }
+
/**
* Returns the PIPed activity's playback state.
* This returns one of {@link #PLAYBACK_STATE_PLAYING}, {@link #PLAYBACK_STATE_PAUSED},
* or {@link #PLAYBACK_STATE_UNAVAILABLE}.
*/
- int getPlaybackState() {
+ public int getPlaybackState() {
if (mPipMediaController == null || mPipMediaController.getPlaybackState() == null) {
return PLAYBACK_STATE_UNAVAILABLE;
}
@@ -676,7 +678,8 @@ public class PipManager implements BasePipManager, PipTaskOrganizer.PipTransitio
};
@Override
- public void onPipTransitionStarted(ComponentName activity, int direction, Rect pipBounds) { }
+ public void onPipTransitionStarted(ComponentName activity, int direction, Rect pipBounds) {
+ }
@Override
public void onPipTransitionFinished(ComponentName activity, int direction) {
@@ -704,7 +707,7 @@ public class PipManager implements BasePipManager, PipTaskOrganizer.PipTransitio
* Invoked when an activity is pinned and PIP manager is set corresponding information.
* Classes must use this instead of {@link android.app.ITaskStackListener.onActivityPinned}
* because there's no guarantee for the PIP manager be return relavent information
- * correctly. (e.g. {@link isPipShown}).
+ * correctly. (e.g. {@link Pip.isPipShown}).
*/
void onPipEntered(String packageName);
/** Invoked when a PIPed activity is closed. */
diff --git a/packages/SystemUI/src/com/android/systemui/pip/tv/PipControlsViewController.java b/packages/SystemUI/src/com/android/systemui/pip/tv/PipControlsViewController.java
index 05bb882ea52e..4ecd52f8adf5 100644
--- a/packages/SystemUI/src/com/android/systemui/pip/tv/PipControlsViewController.java
+++ b/packages/SystemUI/src/com/android/systemui/pip/tv/PipControlsViewController.java
@@ -27,12 +27,14 @@ import android.view.LayoutInflater;
import android.view.View;
import com.android.systemui.dagger.qualifiers.Main;
+import com.android.systemui.pip.Pip;
import com.android.wm.shell.R;
import java.util.ArrayList;
import java.util.List;
-
-import javax.inject.Inject;
+import java.util.Optional;
+import java.util.concurrent.atomic.AtomicInteger;
+import java.util.concurrent.atomic.AtomicReference;
/**
* Controller for {@link PipControlsView}.
@@ -43,9 +45,9 @@ public class PipControlsViewController {
private static final float DISABLED_ACTION_ALPHA = 0.54f;
private final PipControlsView mView;
- private final PipManager mPipManager;
private final LayoutInflater mLayoutInflater;
private final Handler mHandler;
+ private final Optional<Pip> mPipOptional;
private final PipControlButtonView mPlayPauseButtonView;
private MediaController mMediaController;
private PipControlButtonView mFocusedChild;
@@ -73,12 +75,14 @@ public class PipControlsViewController {
@Override
public void onViewAttachedToWindow(View v) {
updateMediaController();
- mPipManager.addMediaListener(mPipMediaListener);
+ mPipOptional.ifPresent(
+ pip -> pip.addMediaListener(mPipMediaListener));
}
@Override
public void onViewDetachedFromWindow(View v) {
- mPipManager.removeMediaListener(mPipMediaListener);
+ mPipOptional.ifPresent(
+ pip -> pip.removeMediaListener(mPipMediaListener));
}
};
@@ -89,7 +93,7 @@ public class PipControlsViewController {
}
};
- private final PipManager.MediaListener mPipMediaListener = this::updateMediaController;
+ private final PipController.MediaListener mPipMediaListener = this::updateMediaController;
private final View.OnFocusChangeListener
mFocusChangeListener =
@@ -105,12 +109,11 @@ public class PipControlsViewController {
};
- @Inject
- public PipControlsViewController(PipControlsView view, PipManager pipManager,
+ public PipControlsViewController(PipControlsView view, Optional<Pip> pipOptional,
LayoutInflater layoutInflater, @Main Handler handler) {
super();
mView = view;
- mPipManager = pipManager;
+ mPipOptional = pipOptional;
mLayoutInflater = layoutInflater;
mHandler = handler;
@@ -121,12 +124,14 @@ public class PipControlsViewController {
View fullButtonView = mView.getFullButtonView();
fullButtonView.setOnFocusChangeListener(mFocusChangeListener);
- fullButtonView.setOnClickListener(v -> mPipManager.movePipToFullscreen());
+ fullButtonView.setOnClickListener(
+ v -> mPipOptional.ifPresent(pip -> pip.movePipToFullscreen())
+ );
View closeButtonView = mView.getCloseButtonView();
closeButtonView.setOnFocusChangeListener(mFocusChangeListener);
closeButtonView.setOnClickListener(v -> {
- mPipManager.closePip();
+ mPipOptional.ifPresent(pip -> pip.closePip());
if (mListener != null) {
mListener.onClosed();
}
@@ -139,24 +144,29 @@ public class PipControlsViewController {
if (mMediaController == null || mMediaController.getPlaybackState() == null) {
return;
}
- if (mPipManager.getPlaybackState() == PipManager.PLAYBACK_STATE_PAUSED) {
- mMediaController.getTransportControls().play();
- } else if (mPipManager.getPlaybackState() == PipManager.PLAYBACK_STATE_PLAYING) {
- mMediaController.getTransportControls().pause();
- }
+ mPipOptional.ifPresent(pip -> {
+ if (pip.getPlaybackState() == PipController.PLAYBACK_STATE_PAUSED) {
+ mMediaController.getTransportControls().play();
+ } else if (pip.getPlaybackState() == PipController.PLAYBACK_STATE_PLAYING) {
+ mMediaController.getTransportControls().pause();
+ }
+ });
+
// View will be updated later in {@link mMediaControllerCallback}
});
}
private void updateMediaController() {
- MediaController newController = mPipManager.getMediaController();
- if (mMediaController == newController) {
+ AtomicReference<MediaController> newController = new AtomicReference<>();
+ mPipOptional.ifPresent(pip -> newController.set(pip.getMediaController()));
+
+ if (newController.get() == null || mMediaController == newController.get()) {
return;
}
if (mMediaController != null) {
mMediaController.unregisterCallback(mMediaControllerCallback);
}
- mMediaController = newController;
+ mMediaController = newController.get();
if (mMediaController != null) {
mMediaController.registerCallback(mMediaControllerCallback);
}
@@ -210,12 +220,14 @@ public class PipControlsViewController {
// Hide the media session buttons
mPlayPauseButtonView.setVisibility(View.GONE);
} else {
- int state = mPipManager.getPlaybackState();
- if (state == PipManager.PLAYBACK_STATE_UNAVAILABLE) {
+ AtomicInteger state = new AtomicInteger(PipController.STATE_UNKNOWN);
+ mPipOptional.ifPresent(pip -> state.set(pip.getPlaybackState()));
+ if (state.get() == PipController.STATE_UNKNOWN
+ || state.get() == PipController.PLAYBACK_STATE_UNAVAILABLE) {
mPlayPauseButtonView.setVisibility(View.GONE);
} else {
mPlayPauseButtonView.setVisibility(View.VISIBLE);
- if (state == PipManager.PLAYBACK_STATE_PLAYING) {
+ if (state.get() == PipController.PLAYBACK_STATE_PLAYING) {
mPlayPauseButtonView.setImageResource(R.drawable.pip_ic_pause_white);
mPlayPauseButtonView.setText(R.string.pip_pause);
} else {
diff --git a/packages/SystemUI/src/com/android/systemui/pip/tv/PipMenuActivity.java b/packages/SystemUI/src/com/android/systemui/pip/tv/PipMenuActivity.java
index 214088c99eeb..7e812d9ca8a1 100644
--- a/packages/SystemUI/src/com/android/systemui/pip/tv/PipMenuActivity.java
+++ b/packages/SystemUI/src/com/android/systemui/pip/tv/PipMenuActivity.java
@@ -25,25 +25,28 @@ import android.content.pm.ParceledListSlice;
import android.os.Bundle;
import android.util.Log;
+import com.android.systemui.pip.Pip;
import com.android.systemui.pip.tv.dagger.TvPipComponent;
import com.android.wm.shell.R;
import java.util.Collections;
+import java.util.Optional;
import javax.inject.Inject;
/**
* Activity to show the PIP menu to control PIP.
*/
-public class PipMenuActivity extends Activity implements PipManager.Listener {
- private static final boolean DEBUG = false;
+
+public class PipMenuActivity extends Activity implements PipController.Listener {
private static final String TAG = "PipMenuActivity";
+ private static final boolean DEBUG = Log.isLoggable(TAG, Log.DEBUG);
static final String EXTRA_CUSTOM_ACTIONS = "custom_actions";
private final TvPipComponent.Builder mPipComponentBuilder;
private TvPipComponent mTvPipComponent;
- private final PipManager mPipManager;
+ private final Optional<Pip> mPipOptional;
private Animator mFadeInAnimation;
private Animator mFadeOutAnimation;
@@ -51,10 +54,11 @@ public class PipMenuActivity extends Activity implements PipManager.Listener {
private PipControlsViewController mPipControlsViewController;
@Inject
- public PipMenuActivity(TvPipComponent.Builder pipComponentBuilder, PipManager pipManager) {
+ public PipMenuActivity(TvPipComponent.Builder pipComponentBuilder,
+ Optional<Pip> pipOptional) {
super();
mPipComponentBuilder = pipComponentBuilder;
- mPipManager = pipManager;
+ mPipOptional = pipOptional;
}
@Override
@@ -62,15 +66,17 @@ public class PipMenuActivity extends Activity implements PipManager.Listener {
if (DEBUG) Log.d(TAG, "onCreate()");
super.onCreate(bundle);
- if (!mPipManager.isPipShown()) {
- finish();
- }
+ mPipOptional.ifPresent(pip -> {
+ if (!pip.isPipShown()) {
+ finish();
+ }
+ });
setContentView(R.layout.tv_pip_menu);
mTvPipComponent = mPipComponentBuilder.pipControlsView(
findViewById(R.id.pip_controls)).build();
mPipControlsViewController = mTvPipComponent.getPipControlsViewController();
- mPipManager.addListener(this);
+ mPipOptional.ifPresent(pip -> pip.addListener(this));
mRestorePipSizeWhenClose = true;
mFadeInAnimation = AnimatorInflater.loadAnimator(
@@ -98,7 +104,7 @@ public class PipMenuActivity extends Activity implements PipManager.Listener {
if (DEBUG) Log.d(TAG, " > restoring to the default position");
// When PIP menu activity is closed, restore to the default position.
- mPipManager.resizePinnedStack(PipManager.STATE_PIP);
+ mPipOptional.ifPresent(pip -> pip.resizePinnedStack(PipController.STATE_PIP));
}
finish();
}
@@ -125,9 +131,9 @@ public class PipMenuActivity extends Activity implements PipManager.Listener {
if (DEBUG) Log.d(TAG, "onDestroy()");
super.onDestroy();
- mPipManager.removeListener(this);
- mPipManager.resumePipResizing(
- PipManager.SUSPEND_PIP_RESIZE_REASON_WAITING_FOR_MENU_ACTIVITY_FINISH);
+ mPipOptional.ifPresent(pip -> pip.removeListener(this));
+ mPipOptional.ifPresent(pip -> pip.resumePipResizing(
+ PipController.SUSPEND_PIP_RESIZE_REASON_WAITING_FOR_MENU_ACTIVITY_FINISH));
}
@Override
@@ -178,8 +184,8 @@ public class PipMenuActivity extends Activity implements PipManager.Listener {
if (DEBUG) Log.d(TAG, "onPipResizeAboutToStart()");
finish();
- mPipManager.suspendPipResizing(
- PipManager.SUSPEND_PIP_RESIZE_REASON_WAITING_FOR_MENU_ACTIVITY_FINISH);
+ mPipOptional.ifPresent(pip -> pip.suspendPipResizing(
+ PipController.SUSPEND_PIP_RESIZE_REASON_WAITING_FOR_MENU_ACTIVITY_FINISH));
}
@Override
diff --git a/packages/SystemUI/src/com/android/systemui/pip/tv/PipNotification.java b/packages/SystemUI/src/com/android/systemui/pip/tv/PipNotification.java
index 651a4f367f21..78569edf009d 100644
--- a/packages/SystemUI/src/com/android/systemui/pip/tv/PipNotification.java
+++ b/packages/SystemUI/src/com/android/systemui/pip/tv/PipNotification.java
@@ -48,14 +48,14 @@ import com.android.wm.shell.R;
public class PipNotification {
private static final String TAG = "PipNotification";
private static final String NOTIFICATION_TAG = PipNotification.class.getSimpleName();
- private static final boolean DEBUG = PipManager.DEBUG;
+ private static final boolean DEBUG = PipController.DEBUG;
private static final String ACTION_MENU = "PipNotification.menu";
private static final String ACTION_CLOSE = "PipNotification.close";
private final PackageManager mPackageManager;
- private final PipManager mPipManager;
+ private final PipController mPipController;
private final NotificationManager mNotificationManager;
private final Notification.Builder mNotificationBuilder;
@@ -70,7 +70,7 @@ public class PipNotification {
private String mMediaTitle;
private Bitmap mArt;
- private PipManager.Listener mPipListener = new PipManager.Listener() {
+ private PipController.Listener mPipListener = new PipController.Listener() {
@Override
public void onPipEntered(String packageName) {
mPackageName = packageName;
@@ -114,22 +114,9 @@ public class PipNotification {
notifyPipNotification();
}
}
- };
- private final PipManager.MediaListener mPipMediaListener = new PipManager.MediaListener() {
@Override
- public void onMediaControllerChanged() {
- MediaController newController = mPipManager.getMediaController();
- if (mMediaController == newController) {
- return;
- }
- if (mMediaController != null) {
- mMediaController.unregisterCallback(mMediaControllerCallback);
- }
- mMediaController = newController;
- if (mMediaController != null) {
- mMediaController.registerCallback(mMediaControllerCallback);
- }
+ public void onMetadataChanged(MediaMetadata metadata) {
if (updateMediaControllerMetadata() && mNotified) {
// update notification
notifyPipNotification();
@@ -137,6 +124,28 @@ public class PipNotification {
}
};
+ private final PipController.MediaListener mPipMediaListener =
+ new PipController.MediaListener() {
+ @Override
+ public void onMediaControllerChanged() {
+ MediaController newController = mPipController.getMediaController();
+ if (newController == null || mMediaController == newController) {
+ return;
+ }
+ if (mMediaController != null) {
+ mMediaController.unregisterCallback(mMediaControllerCallback);
+ }
+ mMediaController = newController;
+ if (mMediaController != null) {
+ mMediaController.registerCallback(mMediaControllerCallback);
+ }
+ if (updateMediaControllerMetadata() && mNotified) {
+ // update notification
+ notifyPipNotification();
+ }
+ }
+ };
+
private final BroadcastReceiver mEventReceiver = new BroadcastReceiver() {
@Override
public void onReceive(Context context, Intent intent) {
@@ -145,17 +154,17 @@ public class PipNotification {
}
switch (intent.getAction()) {
case ACTION_MENU:
- mPipManager.showPictureInPictureMenu();
+ mPipController.showPictureInPictureMenu();
break;
case ACTION_CLOSE:
- mPipManager.closePip();
+ mPipController.closePip();
break;
}
}
};
public PipNotification(Context context, BroadcastDispatcher broadcastDispatcher,
- PipManager pipManager) {
+ PipController pipController) {
mPackageManager = context.getPackageManager();
mNotificationManager = (NotificationManager) context.getSystemService(
@@ -169,9 +178,9 @@ public class PipNotification {
.setContentIntent(createPendingIntent(context, ACTION_MENU))
.setDeleteIntent(createPendingIntent(context, ACTION_CLOSE)));
- mPipManager = pipManager;
- mPipManager.addListener(mPipListener);
- mPipManager.addMediaListener(mPipMediaListener);
+ mPipController = pipController;
+ pipController.addListener(mPipListener);
+ pipController.addMediaListener(mPipMediaListener);
IntentFilter intentFilter = new IntentFilter();
intentFilter.addAction(ACTION_MENU);
@@ -182,7 +191,7 @@ public class PipNotification {
}
/**
- * Called by {@link PipManager} when the configuration is changed.
+ * Called by {@link PipController} when the configuration is changed.
*/
void onConfigurationChanged(Context context) {
Resources res = context.getResources();
@@ -219,8 +228,8 @@ public class PipNotification {
private boolean updateMediaControllerMetadata() {
String title = null;
Bitmap art = null;
- if (mPipManager.getMediaController() != null) {
- MediaMetadata metadata = mPipManager.getMediaController().getMetadata();
+ if (mPipController.getMediaController() != null) {
+ MediaMetadata metadata = mPipController.getMediaController().getMetadata();
if (metadata != null) {
title = metadata.getString(MediaMetadata.METADATA_KEY_DISPLAY_TITLE);
if (TextUtils.isEmpty(title)) {
@@ -240,6 +249,7 @@ public class PipNotification {
return false;
}
+
private String getNotificationTitle() {
if (!TextUtils.isEmpty(mMediaTitle)) {
return mMediaTitle;
diff --git a/packages/SystemUI/src/com/android/systemui/pip/tv/dagger/PipModule.java b/packages/SystemUI/src/com/android/systemui/pip/tv/dagger/PipModule.java
deleted file mode 100644
index 52b38a91a58f..000000000000
--- a/packages/SystemUI/src/com/android/systemui/pip/tv/dagger/PipModule.java
+++ /dev/null
@@ -1,46 +0,0 @@
-/*
- * 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.pip.tv.dagger;
-
-import android.app.Activity;
-
-import com.android.systemui.pip.BasePipManager;
-import com.android.systemui.pip.tv.PipManager;
-import com.android.systemui.pip.tv.PipMenuActivity;
-
-import dagger.Binds;
-import dagger.Module;
-import dagger.multibindings.ClassKey;
-import dagger.multibindings.IntoMap;
-
-/**
- * Dagger module for TV Pip.
- */
-@Module(subcomponents = {TvPipComponent.class})
-public abstract class PipModule {
-
- /** Binds PipManager as the default BasePipManager. */
- @Binds
- public abstract BasePipManager providePipManager(PipManager pipManager);
-
-
- /** Inject into PipMenuActivity. */
- @Binds
- @IntoMap
- @ClassKey(PipMenuActivity.class)
- public abstract Activity providePipMenuActivity(PipMenuActivity activity);
-}
diff --git a/packages/SystemUI/src/com/android/systemui/power/dagger/PowerModule.java b/packages/SystemUI/src/com/android/systemui/power/dagger/PowerModule.java
new file mode 100644
index 000000000000..8b8941a9112d
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/power/dagger/PowerModule.java
@@ -0,0 +1,32 @@
+/*
+ * 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.power.dagger;
+
+import com.android.systemui.power.PowerNotificationWarnings;
+import com.android.systemui.power.PowerUI;
+
+import dagger.Binds;
+import dagger.Module;
+
+
+/** Dagger Module for code in the power package. */
+@Module
+public interface PowerModule {
+ /** */
+ @Binds
+ PowerUI.WarningsUI provideWarningsUi(PowerNotificationWarnings controllerImpl);
+}
diff --git a/packages/SystemUI/src/com/android/systemui/qs/dagger/QSModule.java b/packages/SystemUI/src/com/android/systemui/qs/dagger/QSModule.java
index 8740581240b5..8ff96c8a4a37 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/dagger/QSModule.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/dagger/QSModule.java
@@ -22,6 +22,7 @@ import android.os.Handler;
import com.android.systemui.dagger.qualifiers.Background;
import com.android.systemui.qs.AutoAddTracker;
+import com.android.systemui.qs.QSHost;
import com.android.systemui.qs.QSTileHost;
import com.android.systemui.statusbar.phone.AutoTileManager;
import com.android.systemui.statusbar.phone.ManagedProfileController;
@@ -29,6 +30,7 @@ import com.android.systemui.statusbar.policy.CastController;
import com.android.systemui.statusbar.policy.DataSaverController;
import com.android.systemui.statusbar.policy.HotspotController;
+import dagger.Binds;
import dagger.Module;
import dagger.Provides;
@@ -56,4 +58,9 @@ public interface QSModule {
manager.init();
return manager;
}
+
+
+ /** */
+ @Binds
+ QSHost provideQsHost(QSTileHost controllerImpl);
}
diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/CellularTile.java b/packages/SystemUI/src/com/android/systemui/qs/tiles/CellularTile.java
index b4f1fe72f944..5e6a6ce45b46 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/tiles/CellularTile.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/CellularTile.java
@@ -130,7 +130,8 @@ public class CellularTile extends QSTileImpl<SignalState> {
return;
}
String carrierName = mController.getMobileDataNetworkName();
- if (TextUtils.isEmpty(carrierName)) {
+ boolean isInService = mController.isMobileDataNetworkInService();
+ if (TextUtils.isEmpty(carrierName) || !isInService) {
carrierName = mContext.getString(R.string.mobile_data_disable_message_default_carrier);
}
AlertDialog dialog = new Builder(mContext)
diff --git a/packages/SystemUI/src/com/android/systemui/recents/OverviewProxyRecentsImpl.java b/packages/SystemUI/src/com/android/systemui/recents/OverviewProxyRecentsImpl.java
index 3decb9688828..47002683c6b9 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/OverviewProxyRecentsImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/OverviewProxyRecentsImpl.java
@@ -38,8 +38,8 @@ import com.android.systemui.R;
import com.android.systemui.dagger.SysUISingleton;
import com.android.systemui.shared.recents.IOverviewProxy;
import com.android.systemui.shared.system.ActivityManagerWrapper;
-import com.android.systemui.stackdivider.SplitScreenController;
import com.android.systemui.statusbar.phone.StatusBar;
+import com.android.wm.shell.splitscreen.SplitScreen;
import java.util.Optional;
@@ -56,7 +56,7 @@ public class OverviewProxyRecentsImpl implements RecentsImplementation {
private final static String TAG = "OverviewProxyRecentsImpl";
@Nullable
private final Lazy<StatusBar> mStatusBarLazy;
- private final Optional<SplitScreenController> mSplitScreenControllerOptional;
+ private final Optional<SplitScreen> mSplitScreenOptional;
private Context mContext;
private Handler mHandler;
@@ -66,9 +66,9 @@ public class OverviewProxyRecentsImpl implements RecentsImplementation {
@SuppressWarnings("OptionalUsedAsFieldOrParameterType")
@Inject
public OverviewProxyRecentsImpl(Optional<Lazy<StatusBar>> statusBarLazy,
- Optional<SplitScreenController> splitScreenControllerOptional) {
+ Optional<SplitScreen> splitScreenOptional) {
mStatusBarLazy = statusBarLazy.orElse(null);
- mSplitScreenControllerOptional = splitScreenControllerOptional;
+ mSplitScreenOptional = splitScreenOptional;
}
@Override
@@ -163,7 +163,7 @@ public class OverviewProxyRecentsImpl implements RecentsImplementation {
if (runningTask.supportsSplitScreenMultiWindow) {
if (ActivityManagerWrapper.getInstance().setTaskWindowingModeSplitScreenPrimary(
runningTask.id, stackCreateMode, initialBounds)) {
- mSplitScreenControllerOptional.ifPresent(splitScreen -> {
+ mSplitScreenOptional.ifPresent(splitScreen -> {
splitScreen.onDockedTopTask();
// The overview service is handling split screen, so just skip the wait
// for the first draw and notify the divider to start animating now
diff --git a/packages/SystemUI/src/com/android/systemui/recents/OverviewProxyService.java b/packages/SystemUI/src/com/android/systemui/recents/OverviewProxyService.java
index 304dc93c5dee..cba938f5e1a6 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/OverviewProxyService.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/OverviewProxyService.java
@@ -16,6 +16,7 @@
package com.android.systemui.recents;
+import static android.content.pm.PackageManager.FEATURE_PICTURE_IN_PICTURE;
import static android.content.pm.PackageManager.MATCH_SYSTEM_ONLY;
import static android.view.MotionEvent.ACTION_CANCEL;
import static android.view.MotionEvent.ACTION_DOWN;
@@ -74,9 +75,10 @@ import com.android.systemui.navigationbar.NavigationBar;
import com.android.systemui.navigationbar.NavigationBarController;
import com.android.systemui.navigationbar.NavigationBarView;
import com.android.systemui.navigationbar.NavigationModeController;
-import com.android.systemui.onehanded.OneHandedUI;
+import com.android.systemui.onehanded.OneHanded;
+import com.android.systemui.onehanded.OneHandedEvents;
+import com.android.systemui.pip.Pip;
import com.android.systemui.pip.PipAnimationController;
-import com.android.systemui.pip.PipUI;
import com.android.systemui.recents.OverviewProxyService.OverviewProxyListener;
import com.android.systemui.settings.CurrentUserTracker;
import com.android.systemui.shared.recents.IOverviewProxy;
@@ -86,18 +88,19 @@ import com.android.systemui.shared.recents.model.Task;
import com.android.systemui.shared.system.ActivityManagerWrapper;
import com.android.systemui.shared.system.InputMonitorCompat;
import com.android.systemui.shared.system.QuickStepContract;
-import com.android.systemui.stackdivider.SplitScreenController;
import com.android.systemui.statusbar.CommandQueue;
import com.android.systemui.statusbar.NotificationShadeWindowController;
import com.android.systemui.statusbar.phone.StatusBar;
import com.android.systemui.statusbar.phone.StatusBarWindowCallback;
import com.android.systemui.statusbar.policy.CallbackController;
+import com.android.wm.shell.splitscreen.SplitScreen;
import java.io.FileDescriptor;
import java.io.PrintWriter;
import java.util.ArrayList;
import java.util.List;
import java.util.Optional;
+import java.util.function.BiConsumer;
import javax.inject.Inject;
@@ -121,9 +124,9 @@ public class OverviewProxyService extends CurrentUserTracker implements
private static final long MAX_BACKOFF_MILLIS = 10 * 60 * 1000;
private final Context mContext;
- private final PipUI mPipUI;
+ private final Optional<Pip> mPipOptional;
private final Optional<Lazy<StatusBar>> mStatusBarOptionalLazy;
- private final Optional<SplitScreenController> mSplitScreenControllerOptional;
+ private final Optional<SplitScreen> mSplitScreenOptional;
private SysUiState mSysUiState;
private final Handler mHandler;
private final Lazy<NavigationBarController> mNavBarControllerLazy;
@@ -133,7 +136,7 @@ public class OverviewProxyService extends CurrentUserTracker implements
private final List<OverviewProxyListener> mConnectionCallbacks = new ArrayList<>();
private final Intent mQuickStepIntent;
private final ScreenshotHelper mScreenshotHelper;
- private final OneHandedUI mOneHandedUI;
+ private final Optional<OneHanded> mOneHandedOptional;
private final CommandQueue mCommandQueue;
private Region mActiveNavBarRegion;
@@ -142,6 +145,7 @@ public class OverviewProxyService extends CurrentUserTracker implements
private int mConnectionBackoffAttempts;
private boolean mBound;
private boolean mIsEnabled;
+ private boolean mHasPipFeature;
private int mCurrentBoundedUserId = -1;
private float mNavBarButtonAlpha;
private boolean mInputFocusTransferStarted;
@@ -232,7 +236,7 @@ public class OverviewProxyService extends CurrentUserTracker implements
}
long token = Binder.clearCallingIdentity();
try {
- mSplitScreenControllerOptional.ifPresent(splitScreen -> {
+ mSplitScreenOptional.ifPresent(splitScreen -> {
splitScreen.onDockedFirstAnimationFrame();
});
} finally {
@@ -264,7 +268,7 @@ public class OverviewProxyService extends CurrentUserTracker implements
}
long token = Binder.clearCallingIdentity();
try {
- return mSplitScreenControllerOptional.map(splitScreen ->
+ return mSplitScreenOptional.map(splitScreen ->
splitScreen.getDividerView().getNonMinimizedSplitScreenSecondaryBounds())
.orElse(null);
} finally {
@@ -382,12 +386,15 @@ public class OverviewProxyService extends CurrentUserTracker implements
@Override
public void setShelfHeight(boolean visible, int shelfHeight) {
- if (!verifyCaller("setShelfHeight")) {
+ if (!verifyCaller("setShelfHeight") || !mHasPipFeature) {
+ Log.w(TAG_OPS,
+ "ByPass setShelfHeight, FEATURE_PICTURE_IN_PICTURE:" + mHasPipFeature);
return;
}
long token = Binder.clearCallingIdentity();
try {
- mPipUI.setShelfHeight(visible, shelfHeight);
+ mPipOptional.ifPresent(
+ pip -> pip.setShelfHeight(visible, shelfHeight));
} finally {
Binder.restoreCallingIdentity(token);
}
@@ -401,18 +408,22 @@ public class OverviewProxyService extends CurrentUserTracker implements
@Override
public void setSplitScreenMinimized(boolean minimized) {
- mSplitScreenControllerOptional.ifPresent(
+ mSplitScreenOptional.ifPresent(
splitScreen -> splitScreen.setMinimized(minimized));
}
@Override
public void notifySwipeToHomeFinished() {
- if (!verifyCaller("notifySwipeToHomeFinished")) {
+ if (!verifyCaller("notifySwipeToHomeFinished") || !mHasPipFeature) {
+ Log.w(TAG_OPS, "ByPass notifySwipeToHomeFinished, FEATURE_PICTURE_IN_PICTURE:"
+ + mHasPipFeature);
return;
}
long token = Binder.clearCallingIdentity();
try {
- mPipUI.setPinnedStackAnimationType(PipAnimationController.ANIM_TYPE_ALPHA);
+ mPipOptional.ifPresent(
+ pip -> pip.setPinnedStackAnimationType(
+ PipAnimationController.ANIM_TYPE_ALPHA));
} finally {
Binder.restoreCallingIdentity(token);
}
@@ -420,12 +431,15 @@ public class OverviewProxyService extends CurrentUserTracker implements
@Override
public void setPinnedStackAnimationListener(IPinnedStackAnimationListener listener) {
- if (!verifyCaller("setPinnedStackAnimationListener")) {
+ if (!verifyCaller("setPinnedStackAnimationListener") || !mHasPipFeature) {
+ Log.w(TAG_OPS, "ByPass setPinnedStackAnimationListener, FEATURE_PICTURE_IN_PICTURE:"
+ + mHasPipFeature);
return;
}
long token = Binder.clearCallingIdentity();
try {
- mPipUI.setPinnedStackAnimationListener(listener);
+ mPipOptional.ifPresent(
+ pip -> pip.setPinnedStackAnimationListener(listener));
} finally {
Binder.restoreCallingIdentity(token);
}
@@ -451,9 +465,7 @@ public class OverviewProxyService extends CurrentUserTracker implements
}
long token = Binder.clearCallingIdentity();
try {
- if (mOneHandedUI != null) {
- mOneHandedUI.startOneHanded();
- }
+ mOneHandedOptional.ifPresent(oneHanded -> oneHanded.startOneHanded());
} finally {
Binder.restoreCallingIdentity(token);
}
@@ -466,9 +478,8 @@ public class OverviewProxyService extends CurrentUserTracker implements
}
long token = Binder.clearCallingIdentity();
try {
- if (mOneHandedUI != null) {
- mOneHandedUI.stopOneHanded();
- }
+ mOneHandedOptional.ifPresent(oneHanded -> oneHanded.stopOneHanded(
+ OneHandedEvents.EVENT_ONE_HANDED_TRIGGER_GESTURE_OUT));
} finally {
Binder.restoreCallingIdentity(token);
}
@@ -592,6 +603,8 @@ public class OverviewProxyService extends CurrentUserTracker implements
};
private final StatusBarWindowCallback mStatusBarWindowCallback = this::onStatusBarStateChanged;
+ private final BiConsumer<Rect, Rect> mSplitScreenBoundsChangeListener =
+ this::notifySplitScreenBoundsChanged;
// This is the death handler for the binder from the launcher service
private final IBinder.DeathRecipient mOverviewServiceDeathRcpt
@@ -600,20 +613,23 @@ public class OverviewProxyService extends CurrentUserTracker implements
@SuppressWarnings("OptionalUsedAsFieldOrParameterType")
@Inject
public OverviewProxyService(Context context, CommandQueue commandQueue,
- Lazy<NavigationBarController> navBarControllerLazy, NavigationModeController navModeController,
+ Lazy<NavigationBarController> navBarControllerLazy,
+ NavigationModeController navModeController,
NotificationShadeWindowController statusBarWinController, SysUiState sysUiState,
- PipUI pipUI, Optional<SplitScreenController> splitScreenControllerOptional,
- Optional<Lazy<StatusBar>> statusBarOptionalLazy, OneHandedUI oneHandedUI,
+ Optional<Pip> pipOptional,
+ Optional<SplitScreen> splitScreenOptional,
+ Optional<Lazy<StatusBar>> statusBarOptionalLazy,
+ Optional<OneHanded> oneHandedOptional,
BroadcastDispatcher broadcastDispatcher) {
super(broadcastDispatcher);
mContext = context;
- mPipUI = pipUI;
+ mPipOptional = pipOptional;
+ mHasPipFeature = mContext.getPackageManager().hasSystemFeature(FEATURE_PICTURE_IN_PICTURE);
mStatusBarOptionalLazy = statusBarOptionalLazy;
mHandler = new Handler();
mNavBarControllerLazy = navBarControllerLazy;
mStatusBarWinController = statusBarWinController;
mConnectionBackoffAttempts = 0;
- mSplitScreenControllerOptional = splitScreenControllerOptional;
mRecentsComponentName = ComponentName.unflattenFromString(context.getString(
com.android.internal.R.string.config_recentsComponentName));
mQuickStepIntent = new Intent(ACTION_QUICKSTEP)
@@ -623,7 +639,7 @@ public class OverviewProxyService extends CurrentUserTracker implements
.supportsRoundedCornersOnWindows(mContext.getResources());
mSysUiState = sysUiState;
mSysUiState.addCallback(this::notifySystemUiStateFlags);
- mOneHandedUI = oneHandedUI;
+ mOneHandedOptional = oneHandedOptional;
// Assumes device always starts with back button until launcher tells it that it does not
mNavBarButtonAlpha = 1.0f;
@@ -653,6 +669,10 @@ public class OverviewProxyService extends CurrentUserTracker implements
});
mCommandQueue = commandQueue;
+ splitScreenOptional.ifPresent(splitScreen ->
+ splitScreen.registerBoundsChangeListener(mSplitScreenBoundsChangeListener));
+ mSplitScreenOptional = splitScreenOptional;
+
// Listen for user setup
startTracking();
@@ -755,7 +775,7 @@ public class OverviewProxyService extends CurrentUserTracker implements
startConnectionToCurrentUser();
// Clean up the minimized state if launcher dies
- mSplitScreenControllerOptional.ifPresent(
+ mSplitScreenOptional.ifPresent(
splitScreen -> splitScreen.setMinimized(false));
}
@@ -910,6 +930,7 @@ public class OverviewProxyService extends CurrentUserTracker implements
/**
* Notifies the Launcher of split screen size changes
+ *
* @param secondaryWindowBounds Bounds of the secondary window including the insets
* @param secondaryWindowInsets stable insets received by the secondary window
*/
diff --git a/packages/SystemUI/src/com/android/systemui/screenrecord/RecordingService.java b/packages/SystemUI/src/com/android/systemui/screenrecord/RecordingService.java
index 8ec3db59117d..3bf118d1f39f 100644
--- a/packages/SystemUI/src/com/android/systemui/screenrecord/RecordingService.java
+++ b/packages/SystemUI/src/com/android/systemui/screenrecord/RecordingService.java
@@ -40,7 +40,7 @@ import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.logging.UiEventLogger;
import com.android.systemui.R;
import com.android.systemui.dagger.qualifiers.LongRunning;
-import com.android.systemui.settings.CurrentUserContextTracker;
+import com.android.systemui.settings.UserContextProvider;
import com.android.systemui.statusbar.phone.KeyguardDismissUtil;
import java.io.IOException;
@@ -79,12 +79,12 @@ public class RecordingService extends Service implements MediaRecorder.OnInfoLis
private final Executor mLongExecutor;
private final UiEventLogger mUiEventLogger;
private final NotificationManager mNotificationManager;
- private final CurrentUserContextTracker mUserContextTracker;
+ private final UserContextProvider mUserContextTracker;
@Inject
public RecordingService(RecordingController controller, @LongRunning Executor executor,
UiEventLogger uiEventLogger, NotificationManager notificationManager,
- CurrentUserContextTracker userContextTracker, KeyguardDismissUtil keyguardDismissUtil) {
+ UserContextProvider userContextTracker, KeyguardDismissUtil keyguardDismissUtil) {
mController = controller;
mLongExecutor = executor;
mUiEventLogger = uiEventLogger;
@@ -120,7 +120,7 @@ public class RecordingService extends Service implements MediaRecorder.OnInfoLis
String action = intent.getAction();
Log.d(TAG, "onStartCommand " + action);
- int mCurrentUserId = mUserContextTracker.getCurrentUserContext().getUserId();
+ int mCurrentUserId = mUserContextTracker.getUserContext().getUserId();
UserHandle currentUser = new UserHandle(mCurrentUserId);
switch (action) {
case ACTION_START:
@@ -136,7 +136,7 @@ public class RecordingService extends Service implements MediaRecorder.OnInfoLis
setTapsVisible(mShowTaps);
mRecorder = new ScreenMediaRecorder(
- mUserContextTracker.getCurrentUserContext(),
+ mUserContextTracker.getUserContext(),
mCurrentUserId,
mAudioSource,
this
@@ -156,7 +156,7 @@ public class RecordingService extends Service implements MediaRecorder.OnInfoLis
// we want to post the notifications for that user, which is NOT current user
int userId = intent.getIntExtra(Intent.EXTRA_USER_HANDLE, -1);
if (userId == -1) {
- userId = mUserContextTracker.getCurrentUserContext().getUserId();
+ userId = mUserContextTracker.getUserContext().getUserId();
}
Log.d(TAG, "notifying for user " + userId);
stopRecording(userId);
diff --git a/packages/SystemUI/src/com/android/systemui/screenrecord/ScreenRecordDialog.java b/packages/SystemUI/src/com/android/systemui/screenrecord/ScreenRecordDialog.java
index dc47ab4dff63..2b62a29587e6 100644
--- a/packages/SystemUI/src/com/android/systemui/screenrecord/ScreenRecordDialog.java
+++ b/packages/SystemUI/src/com/android/systemui/screenrecord/ScreenRecordDialog.java
@@ -35,7 +35,7 @@ import android.widget.Spinner;
import android.widget.Switch;
import com.android.systemui.R;
-import com.android.systemui.settings.CurrentUserContextTracker;
+import com.android.systemui.settings.UserContextProvider;
import java.util.ArrayList;
import java.util.List;
@@ -51,7 +51,7 @@ public class ScreenRecordDialog extends Activity {
private static final String TAG = "ScreenRecordDialog";
private final RecordingController mController;
- private final CurrentUserContextTracker mCurrentUserContextTracker;
+ private final UserContextProvider mUserContextProvider;
private Switch mTapsSwitch;
private Switch mAudioSwitch;
private Spinner mOptions;
@@ -59,9 +59,9 @@ public class ScreenRecordDialog extends Activity {
@Inject
public ScreenRecordDialog(RecordingController controller,
- CurrentUserContextTracker currentUserContextTracker) {
+ UserContextProvider userContextProvider) {
mController = controller;
- mCurrentUserContextTracker = currentUserContextTracker;
+ mUserContextProvider = userContextProvider;
}
@Override
@@ -108,7 +108,7 @@ public class ScreenRecordDialog extends Activity {
}
private void requestScreenCapture() {
- Context userContext = mCurrentUserContextTracker.getCurrentUserContext();
+ Context userContext = mUserContextProvider.getUserContext();
boolean showTaps = mTapsSwitch.isChecked();
ScreenRecordingAudioSource audioMode = mAudioSwitch.isChecked()
? (ScreenRecordingAudioSource) mOptions.getSelectedItem()
diff --git a/packages/SystemUI/src/com/android/systemui/screenshot/GlobalScreenshot.java b/packages/SystemUI/src/com/android/systemui/screenshot/GlobalScreenshot.java
index e24fbc6cca9d..7dd4edd233bd 100644
--- a/packages/SystemUI/src/com/android/systemui/screenshot/GlobalScreenshot.java
+++ b/packages/SystemUI/src/com/android/systemui/screenshot/GlobalScreenshot.java
@@ -573,7 +573,12 @@ public class GlobalScreenshot implements ViewTreeObserver.OnComputeInternalInset
private void saveScreenshot(Bitmap screenshot, Consumer<Uri> finisher, Rect screenRect,
Insets screenInsets, boolean showFlash) {
- dismissScreenshot("new screenshot requested", true);
+ if (mScreenshotLayout.isAttachedToWindow()) {
+ if (!mDismissAnimation.isRunning()) { // if we didn't already dismiss for another reason
+ mUiEventLogger.log(ScreenshotEvent.SCREENSHOT_REENTERED);
+ }
+ dismissScreenshot("new screenshot requested", true);
+ }
mScreenBitmap = screenshot;
diff --git a/packages/SystemUI/src/com/android/systemui/screenshot/ScreenshotEvent.java b/packages/SystemUI/src/com/android/systemui/screenshot/ScreenshotEvent.java
index 6b42f2e07bc3..74e0229c4992 100644
--- a/packages/SystemUI/src/com/android/systemui/screenshot/ScreenshotEvent.java
+++ b/packages/SystemUI/src/com/android/systemui/screenshot/ScreenshotEvent.java
@@ -59,7 +59,9 @@ public enum ScreenshotEvent implements UiEventLogger.UiEventEnum {
@UiEvent(doc = "screenshot interaction timed out")
SCREENSHOT_INTERACTION_TIMEOUT(310),
@UiEvent(doc = "screenshot explicitly dismissed")
- SCREENSHOT_EXPLICIT_DISMISSAL(311);
+ SCREENSHOT_EXPLICIT_DISMISSAL(311),
+ @UiEvent(doc = "screenshot reentered for new screenshot")
+ SCREENSHOT_REENTERED(640);
private final int mId;
diff --git a/packages/SystemUI/src/com/android/systemui/settings/CurrentUserContextTracker.kt b/packages/SystemUI/src/com/android/systemui/settings/CurrentUserContextTracker.kt
deleted file mode 100644
index d7c4caaa4f9d..000000000000
--- a/packages/SystemUI/src/com/android/systemui/settings/CurrentUserContextTracker.kt
+++ /dev/null
@@ -1,74 +0,0 @@
-/*
- * Copyright (C) 2020 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.systemui.settings
-
-import android.content.ContentResolver
-import android.content.Context
-import android.os.UserHandle
-import androidx.annotation.VisibleForTesting
-import com.android.systemui.broadcast.BroadcastDispatcher
-import com.android.systemui.util.Assert
-import java.lang.IllegalStateException
-
-/**
- * Tracks a reference to the context for the current user
- *
- * Constructor is injected at SettingsModule
- */
-class CurrentUserContextTracker internal constructor(
- private val sysuiContext: Context,
- broadcastDispatcher: BroadcastDispatcher
-) : CurrentUserContentResolverProvider {
- private val userTracker: CurrentUserTracker
- private var initialized = false
-
- private var _curUserContext: Context? = null
- val currentUserContext: Context
- get() {
- if (!initialized) {
- throw IllegalStateException("Must initialize before getting context")
- }
- return _curUserContext!!
- }
-
- override val currentUserContentResolver: ContentResolver
- get() = currentUserContext.contentResolver
-
- init {
- userTracker = object : CurrentUserTracker(broadcastDispatcher) {
- override fun onUserSwitched(newUserId: Int) {
- handleUserSwitched(newUserId)
- }
- }
- }
-
- fun initialize() {
- initialized = true
- userTracker.startTracking()
- _curUserContext = makeUserContext(userTracker.currentUserId)
- }
-
- @VisibleForTesting
- fun handleUserSwitched(newUserId: Int) {
- _curUserContext = makeUserContext(newUserId)
- }
-
- private fun makeUserContext(uid: Int): Context {
- Assert.isMainThread()
- return sysuiContext.createContextAsUser(UserHandle.of(uid), 0)
- }
-} \ No newline at end of file
diff --git a/packages/SystemUI/src/com/android/systemui/settings/CurrentUserContentResolverProvider.kt b/packages/SystemUI/src/com/android/systemui/settings/UserContentResolverProvider.kt
index 9d05843b42bf..e0c0c15cba31 100644
--- a/packages/SystemUI/src/com/android/systemui/settings/CurrentUserContentResolverProvider.kt
+++ b/packages/SystemUI/src/com/android/systemui/settings/UserContentResolverProvider.kt
@@ -18,7 +18,10 @@ package com.android.systemui.settings
import android.content.ContentResolver
-interface CurrentUserContentResolverProvider {
+/**
+ * Implemented by [UserTrackerImpl].
+ */
+interface UserContentResolverProvider {
- val currentUserContentResolver: ContentResolver
+ val userContentResolver: ContentResolver
} \ No newline at end of file
diff --git a/packages/SystemUI/src/com/android/systemui/settings/UserContextProvider.kt b/packages/SystemUI/src/com/android/systemui/settings/UserContextProvider.kt
new file mode 100644
index 000000000000..27af15222327
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/settings/UserContextProvider.kt
@@ -0,0 +1,26 @@
+/*
+ * 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.settings
+
+import android.content.Context
+
+/**
+ * Implemented by [UserTrackerImpl].
+ */
+interface UserContextProvider {
+ val userContext: Context
+} \ No newline at end of file
diff --git a/packages/SystemUI/src/com/android/systemui/settings/UserTracker.kt b/packages/SystemUI/src/com/android/systemui/settings/UserTracker.kt
new file mode 100644
index 000000000000..26d408fe4ab7
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/settings/UserTracker.kt
@@ -0,0 +1,74 @@
+/*
+ * 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.settings
+
+import android.content.Context
+import android.content.pm.UserInfo
+import android.os.UserHandle
+import java.util.concurrent.Executor
+
+/**
+ * User tracker for SystemUI.
+ *
+ * This tracker provides async access to current user information, as well as callbacks for
+ * user/profile change.
+ */
+interface UserTracker : UserContentResolverProvider, UserContextProvider {
+
+ /**
+ * Current user's id.
+ */
+ val userId: Int
+
+ /**
+ * [UserHandle] for current user
+ */
+ val userHandle: UserHandle
+
+ /**
+ * List of profiles associated with the current user.
+ */
+ val userProfiles: List<UserInfo>
+
+ /**
+ * Add a [Callback] to be notified of chances, on a particular [Executor]
+ */
+ fun addCallback(callback: Callback, executor: Executor)
+
+ /**
+ * Remove a [Callback] previously added.
+ */
+ fun removeCallback(callback: Callback)
+
+ /**
+ * Ćallback for notifying of changes.
+ */
+ interface Callback {
+
+ /**
+ * Notifies that the current user has changed.
+ */
+ @JvmDefault
+ fun onUserChanged(newUser: Int, userContext: Context) {}
+
+ /**
+ * Notifies that the current user's profiles have changed.
+ */
+ @JvmDefault
+ fun onProfilesChanged(profiles: List<UserInfo>) {}
+ }
+} \ No newline at end of file
diff --git a/packages/SystemUI/src/com/android/systemui/settings/UserTrackerImpl.kt b/packages/SystemUI/src/com/android/systemui/settings/UserTrackerImpl.kt
new file mode 100644
index 000000000000..4cc0eeee712c
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/settings/UserTrackerImpl.kt
@@ -0,0 +1,240 @@
+/*
+ * 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.settings
+
+import android.content.BroadcastReceiver
+import android.content.ContentResolver
+import android.content.Context
+import android.content.Intent
+import android.content.IntentFilter
+import android.content.pm.UserInfo
+import android.os.Handler
+import android.os.UserHandle
+import android.os.UserManager
+import android.util.Log
+import androidx.annotation.GuardedBy
+import androidx.annotation.WorkerThread
+import com.android.systemui.Dumpable
+import com.android.systemui.dump.DumpManager
+import com.android.systemui.util.Assert
+import java.io.FileDescriptor
+import java.io.PrintWriter
+import java.lang.IllegalStateException
+import java.lang.ref.WeakReference
+import java.util.concurrent.Executor
+import kotlin.properties.ReadWriteProperty
+import kotlin.reflect.KProperty
+
+/**
+ * SystemUI cache for keeping track of the current user and associated values.
+ *
+ * The values provided asynchronously are NOT copies, but shared among all requesters. Do not
+ * modify them.
+ *
+ * This class purposefully doesn't use [BroadcastDispatcher] in order to receive the broadcast as
+ * soon as possible (and reduce its dependency graph).
+ * Other classes that want to listen to the broadcasts listened here SHOULD
+ * subscribe to this class instead.
+ *
+ * @see UserTracker
+ *
+ * Class constructed and initialized in [SettingsModule].
+ */
+class UserTrackerImpl internal constructor(
+ private val context: Context,
+ private val userManager: UserManager,
+ private val dumpManager: DumpManager,
+ private val backgroundHandler: Handler
+) : UserTracker, Dumpable, BroadcastReceiver() {
+
+ companion object {
+ private const val TAG = "UserTrackerImpl"
+ }
+
+ var initialized = false
+ private set
+
+ private val mutex = Any()
+
+ override var userId: Int by SynchronizedDelegate(context.userId)
+ private set
+
+ override var userHandle: UserHandle by SynchronizedDelegate(context.user)
+ private set
+
+ override var userContext: Context by SynchronizedDelegate(context)
+ private set
+
+ override val userContentResolver: ContentResolver
+ get() = userContext.contentResolver
+
+ /**
+ * Returns a [List<UserInfo>] of all profiles associated with the current user.
+ *
+ * The list returned is not a copy, so a copy should be made if its elements need to be
+ * modified.
+ */
+ override var userProfiles: List<UserInfo> by SynchronizedDelegate(emptyList())
+ private set
+
+ @GuardedBy("callbacks")
+ private val callbacks: MutableList<DataItem> = ArrayList()
+
+ fun initialize(startingUser: Int) {
+ if (initialized) {
+ return
+ }
+ initialized = true
+ setUserIdInternal(startingUser)
+
+ val filter = IntentFilter().apply {
+ addAction(Intent.ACTION_USER_SWITCHED)
+ addAction(Intent.ACTION_MANAGED_PROFILE_AVAILABLE)
+ addAction(Intent.ACTION_MANAGED_PROFILE_REMOVED)
+ }
+ context.registerReceiverForAllUsers(this, filter, null /* permission */, backgroundHandler)
+
+ dumpManager.registerDumpable(TAG, this)
+ }
+
+ override fun onReceive(context: Context, intent: Intent) {
+ when (intent.action) {
+ Intent.ACTION_USER_SWITCHED -> {
+ handleSwitchUser(intent.getIntExtra(Intent.EXTRA_USER_HANDLE, UserHandle.USER_NULL))
+ }
+ Intent.ACTION_MANAGED_PROFILE_AVAILABLE, Intent.ACTION_MANAGED_PROFILE_UNAVAILABLE -> {
+ handleProfilesChanged()
+ }
+ }
+ }
+
+ private fun setUserIdInternal(user: Int): Pair<Context, List<UserInfo>> {
+ val profiles = userManager.getProfiles(user)
+ val handle = UserHandle(user)
+ val ctx = context.createContextAsUser(handle, 0)
+
+ synchronized(mutex) {
+ userId = user
+ userHandle = handle
+ userContext = ctx
+ userProfiles = profiles.map { UserInfo(it) }
+ }
+ return ctx to profiles
+ }
+
+ @WorkerThread
+ private fun handleSwitchUser(newUser: Int) {
+ Assert.isNotMainThread()
+ if (newUser == UserHandle.USER_NULL) {
+ Log.w(TAG, "handleSwitchUser - Couldn't get new id from intent")
+ return
+ }
+
+ if (newUser == userId) return
+ Log.i(TAG, "Switching to user $newUser")
+
+ val (ctx, profiles) = setUserIdInternal(newUser)
+
+ notifySubscribers {
+ onUserChanged(newUser, ctx)
+ onProfilesChanged(profiles)
+ }
+ }
+
+ @WorkerThread
+ private fun handleProfilesChanged() {
+ Assert.isNotMainThread()
+
+ val profiles = userManager.getProfiles(userId)
+ synchronized(mutex) {
+ userProfiles = profiles.map { UserInfo(it) } // save a "deep" copy
+ }
+ notifySubscribers {
+ onProfilesChanged(profiles)
+ }
+ }
+
+ override fun addCallback(callback: UserTracker.Callback, executor: Executor) {
+ synchronized(callbacks) {
+ callbacks.add(DataItem(WeakReference(callback), executor))
+ }
+ }
+
+ override fun removeCallback(callback: UserTracker.Callback) {
+ synchronized(callbacks) {
+ callbacks.removeIf { it.sameOrEmpty(callback) }
+ }
+ }
+
+ private inline fun notifySubscribers(crossinline action: UserTracker.Callback.() -> Unit) {
+ val list = synchronized(callbacks) {
+ callbacks.toList()
+ }
+ list.forEach {
+ if (it.callback.get() != null) {
+ it.executor.execute {
+ it.callback.get()?.action()
+ }
+ }
+ }
+ }
+
+ override fun dump(fd: FileDescriptor, pw: PrintWriter, args: Array<out String>) {
+ pw.println("Initialized: $initialized")
+ if (initialized) {
+ pw.println("userId: $userId")
+ val ids = userProfiles.map { it.id }
+ pw.println("userProfiles: $ids")
+ }
+ val list = synchronized(callbacks) {
+ callbacks.toList()
+ }
+ pw.println("Callbacks:")
+ list.forEach {
+ it.callback.get()?.let {
+ pw.println(" $it")
+ }
+ }
+ }
+
+ private class SynchronizedDelegate<T : Any>(
+ private var value: T
+ ) : ReadWriteProperty<UserTrackerImpl, T> {
+
+ @GuardedBy("mutex")
+ override fun getValue(thisRef: UserTrackerImpl, property: KProperty<*>): T {
+ if (!thisRef.initialized) {
+ throw IllegalStateException("Must initialize before getting ${property.name}")
+ }
+ return synchronized(thisRef.mutex) { value }
+ }
+
+ @GuardedBy("mutex")
+ override fun setValue(thisRef: UserTrackerImpl, property: KProperty<*>, value: T) {
+ synchronized(thisRef.mutex) { this.value = value }
+ }
+ }
+}
+
+private data class DataItem(
+ val callback: WeakReference<UserTracker.Callback>,
+ val executor: Executor
+) {
+ fun sameOrEmpty(other: UserTracker.Callback): Boolean {
+ return callback.get()?.equals(other) ?: true
+ }
+} \ No newline at end of file
diff --git a/packages/SystemUI/src/com/android/systemui/settings/dagger/SettingsModule.java b/packages/SystemUI/src/com/android/systemui/settings/dagger/SettingsModule.java
index b1ed77275187..7084d3ffc9ff 100644
--- a/packages/SystemUI/src/com/android/systemui/settings/dagger/SettingsModule.java
+++ b/packages/SystemUI/src/com/android/systemui/settings/dagger/SettingsModule.java
@@ -16,12 +16,18 @@
package com.android.systemui.settings.dagger;
+import android.app.ActivityManager;
import android.content.Context;
+import android.os.Handler;
+import android.os.UserManager;
-import com.android.systemui.broadcast.BroadcastDispatcher;
import com.android.systemui.dagger.SysUISingleton;
-import com.android.systemui.settings.CurrentUserContentResolverProvider;
-import com.android.systemui.settings.CurrentUserContextTracker;
+import com.android.systemui.dagger.qualifiers.Background;
+import com.android.systemui.dump.DumpManager;
+import com.android.systemui.settings.UserContentResolverProvider;
+import com.android.systemui.settings.UserContextProvider;
+import com.android.systemui.settings.UserTracker;
+import com.android.systemui.settings.UserTrackerImpl;
import dagger.Binds;
import dagger.Module;
@@ -33,22 +39,27 @@ import dagger.Provides;
@Module
public abstract class SettingsModule {
- /**
- * Provides and initializes a CurrentUserContextTracker
- */
+
+ @Binds
+ @SysUISingleton
+ abstract UserContextProvider bindUserContextProvider(UserTracker tracker);
+
+ @Binds
+ @SysUISingleton
+ abstract UserContentResolverProvider bindUserContentResolverProvider(
+ UserTracker tracker);
+
@SysUISingleton
@Provides
- static CurrentUserContextTracker provideCurrentUserContextTracker(
+ static UserTracker provideUserTracker(
Context context,
- BroadcastDispatcher broadcastDispatcher) {
- CurrentUserContextTracker tracker =
- new CurrentUserContextTracker(context, broadcastDispatcher);
- tracker.initialize();
+ UserManager userManager,
+ DumpManager dumpManager,
+ @Background Handler handler
+ ) {
+ int startingUser = ActivityManager.getCurrentUser();
+ UserTrackerImpl tracker = new UserTrackerImpl(context, userManager, dumpManager, handler);
+ tracker.initialize(startingUser);
return tracker;
}
-
- @Binds
- @SysUISingleton
- abstract CurrentUserContentResolverProvider bindCurrentUserContentResolverTracker(
- CurrentUserContextTracker tracker);
}
diff --git a/packages/SystemUI/src/com/android/systemui/shortcut/ShortcutKeyDispatcher.java b/packages/SystemUI/src/com/android/systemui/shortcut/ShortcutKeyDispatcher.java
index e2118a798a43..b9b4f42a66e1 100644
--- a/packages/SystemUI/src/com/android/systemui/shortcut/ShortcutKeyDispatcher.java
+++ b/packages/SystemUI/src/com/android/systemui/shortcut/ShortcutKeyDispatcher.java
@@ -30,8 +30,8 @@ import com.android.internal.policy.DividerSnapAlgorithm;
import com.android.systemui.SystemUI;
import com.android.systemui.dagger.SysUISingleton;
import com.android.systemui.recents.Recents;
-import com.android.systemui.stackdivider.DividerView;
-import com.android.systemui.stackdivider.SplitScreenController;
+import com.android.wm.shell.splitscreen.DividerView;
+import com.android.wm.shell.splitscreen.SplitScreen;
import java.util.Optional;
@@ -45,7 +45,7 @@ public class ShortcutKeyDispatcher extends SystemUI
implements ShortcutKeyServiceProxy.Callbacks {
private static final String TAG = "ShortcutKeyDispatcher";
- private final Optional<SplitScreenController> mSplitScreenControllerOptional;
+ private final Optional<SplitScreen> mSplitScreenOptional;
private final Recents mRecents;
private ShortcutKeyServiceProxy mShortcutKeyServiceProxy = new ShortcutKeyServiceProxy(this);
@@ -61,9 +61,9 @@ public class ShortcutKeyDispatcher extends SystemUI
@Inject
public ShortcutKeyDispatcher(Context context,
- Optional<SplitScreenController> splitScreenControllerOptional, Recents recents) {
+ Optional<SplitScreen> splitScreenOptional, Recents recents) {
super(context);
- mSplitScreenControllerOptional = splitScreenControllerOptional;
+ mSplitScreenOptional = splitScreenOptional;
mRecents = recents;
}
@@ -96,11 +96,11 @@ public class ShortcutKeyDispatcher extends SystemUI
}
private void handleDockKey(long shortcutCode) {
- if (mSplitScreenControllerOptional.isPresent()) {
- SplitScreenController splitScreenController = mSplitScreenControllerOptional.get();
- if (splitScreenController.isDividerVisible()) {
+ if (mSplitScreenOptional.isPresent()) {
+ SplitScreen splitScreen = mSplitScreenOptional.get();
+ if (splitScreen.isDividerVisible()) {
// If there is already a docked window, we respond by resizing the docking pane.
- DividerView dividerView = splitScreenController.getDividerView();
+ DividerView dividerView = splitScreen.getDividerView();
DividerSnapAlgorithm snapAlgorithm = dividerView.getSnapAlgorithm();
int dividerPosition = dividerView.getCurrentPosition();
DividerSnapAlgorithm.SnapTarget currentTarget =
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/AlertingNotificationManager.java b/packages/SystemUI/src/com/android/systemui/statusbar/AlertingNotificationManager.java
index eca4c8082dfe..0df69a0a1f43 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/AlertingNotificationManager.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/AlertingNotificationManager.java
@@ -185,6 +185,7 @@ public abstract class AlertingNotificationManager implements NotificationLifetim
mAlertEntries.put(entry.getKey(), alertEntry);
onAlertEntryAdded(alertEntry);
entry.sendAccessibilityEvent(AccessibilityEvent.TYPE_WINDOW_CONTENT_CHANGED);
+ entry.setIsAlerting(true);
}
/**
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/DragDownHelper.java b/packages/SystemUI/src/com/android/systemui/statusbar/DragDownHelper.java
index 4fa782269c2d..e61e05a7dc2f 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/DragDownHelper.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/DragDownHelper.java
@@ -16,6 +16,8 @@
package com.android.systemui.statusbar;
+import static com.android.systemui.classifier.Classifier.NOTIFICATION_DRAG_DOWN;
+
import android.animation.Animator;
import android.animation.AnimatorListenerAdapter;
import android.animation.ObjectAnimator;
@@ -163,7 +165,7 @@ public class DragDownHelper implements Gefingerpoken {
if (!mDragDownCallback.isFalsingCheckNeeded()) {
return false;
}
- return mFalsingManager.isFalseTouch() || !mDraggedFarEnough;
+ return mFalsingManager.isFalseTouch(NOTIFICATION_DRAG_DOWN) || !mDraggedFarEnough;
}
private void captureStartingChild(float x, float y) {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/KeyguardAffordanceView.java b/packages/SystemUI/src/com/android/systemui/statusbar/KeyguardAffordanceView.java
index 2c296353bd14..4b9d5924a8d2 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/KeyguardAffordanceView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/KeyguardAffordanceView.java
@@ -40,6 +40,7 @@ import android.widget.ImageView;
import com.android.systemui.Interpolators;
import com.android.systemui.R;
+import com.android.wm.shell.animation.FlingAnimationUtils;
/**
* An ImageView which does not have overlapping renderings commands and therefore does not need a
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationMediaManager.java b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationMediaManager.java
index c01bdc4c2f28..8bf134d9c5b9 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationMediaManager.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationMediaManager.java
@@ -21,6 +21,7 @@ import static com.android.systemui.statusbar.phone.StatusBar.ENABLE_LOCKSCREEN_W
import static com.android.systemui.statusbar.phone.StatusBar.SHOW_LOCKSCREEN_MEDIA_ARTWORK;
import android.annotation.MainThread;
+import android.annotation.NonNull;
import android.annotation.Nullable;
import android.app.Notification;
import android.content.Context;
@@ -57,6 +58,7 @@ import com.android.systemui.statusbar.dagger.StatusBarModule;
import com.android.systemui.statusbar.notification.NotificationEntryListener;
import com.android.systemui.statusbar.notification.NotificationEntryManager;
import com.android.systemui.statusbar.notification.collection.NotificationEntry;
+import com.android.systemui.statusbar.notification.collection.notifcollection.NotifCollectionListener;
import com.android.systemui.statusbar.phone.BiometricUnlockController;
import com.android.systemui.statusbar.phone.KeyguardBypassController;
import com.android.systemui.statusbar.phone.LockscreenWallpaper;
@@ -233,8 +235,17 @@ public class NotificationMediaManager implements Dumpable {
NotificationVisibility visibility,
boolean removedByUser,
int reason) {
- onNotificationRemoved(entry.getKey());
- mediaDataManager.onNotificationRemoved(entry.getKey());
+ removeEntry(entry);
+ }
+ });
+
+ // Pending entries are never inflated, and will never generate a call to onEntryRemoved().
+ // This can happen when notifications are added and canceled before inflation. Add this
+ // separate listener for cleanup, since media inflation occurs onPendingEntryAdded().
+ notificationEntryManager.addCollectionListener(new NotifCollectionListener() {
+ @Override
+ public void onEntryCleanUp(@NonNull NotificationEntry entry) {
+ removeEntry(entry);
}
});
@@ -247,6 +258,11 @@ public class NotificationMediaManager implements Dumpable {
mPropertiesChangedListener);
}
+ private void removeEntry(NotificationEntry entry) {
+ onNotificationRemoved(entry.getKey());
+ mMediaDataManager.onNotificationRemoved(entry.getKey());
+ }
+
/**
* Check if a state should be considered actively playing
* @param state a PlaybackState
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationPresenter.java b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationPresenter.java
index 1079f10497a9..17bf346fa22b 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationPresenter.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationPresenter.java
@@ -55,14 +55,6 @@ public interface NotificationPresenter extends ExpandableNotificationRow.OnExpan
void updateNotificationViews(String reason);
/**
- * Returns the maximum number of notifications to show while locked.
- *
- * @param recompute whether something has changed that means we should recompute this value
- * @return the maximum number of notifications to show while locked
- */
- int getMaxNotificationsWhileLocked(boolean recompute);
-
- /**
* Called when the row states are updated by {@link NotificationViewHierarchyManager}.
*/
void onUpdateRowStates();
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationShelfController.java b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationShelfController.java
index 77abcfa848ee..1e935c19b710 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationShelfController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationShelfController.java
@@ -85,6 +85,10 @@ public class NotificationShelfController {
return mView.getShelfIcons();
}
+ public @View.Visibility int getVisibility() {
+ return mView.getVisibility();
+ };
+
public void setCollapsedIcons(NotificationIconContainer notificationIcons) {
mView.setCollapsedIcons(notificationIcons);
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationViewHierarchyManager.java b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationViewHierarchyManager.java
index 1cd1b60ac1ac..38c7e5c50f63 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationViewHierarchyManager.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationViewHierarchyManager.java
@@ -36,12 +36,12 @@ import com.android.systemui.statusbar.notification.DynamicPrivacyController;
import com.android.systemui.statusbar.notification.NotificationEntryManager;
import com.android.systemui.statusbar.notification.collection.NotificationEntry;
import com.android.systemui.statusbar.notification.collection.inflation.LowPriorityInflationHelper;
+import com.android.systemui.statusbar.notification.collection.legacy.NotificationGroupManagerLegacy;
import com.android.systemui.statusbar.notification.collection.legacy.VisualStabilityManager;
import com.android.systemui.statusbar.notification.row.ExpandableNotificationRow;
import com.android.systemui.statusbar.notification.stack.ForegroundServiceSectionController;
import com.android.systemui.statusbar.notification.stack.NotificationListContainer;
import com.android.systemui.statusbar.phone.KeyguardBypassController;
-import com.android.systemui.statusbar.phone.NotificationGroupManager;
import com.android.systemui.util.Assert;
import java.util.ArrayList;
@@ -72,7 +72,7 @@ public class NotificationViewHierarchyManager implements DynamicPrivacyControlle
// Dependencies:
private final DynamicChildBindController mDynamicChildBindController;
protected final NotificationLockscreenUserManager mLockscreenUserManager;
- protected final NotificationGroupManager mGroupManager;
+ protected final NotificationGroupManagerLegacy mGroupManager;
protected final VisualStabilityManager mVisualStabilityManager;
private final SysuiStatusBarStateController mStatusBarStateController;
private final NotificationEntryManager mEntryManager;
@@ -107,7 +107,7 @@ public class NotificationViewHierarchyManager implements DynamicPrivacyControlle
Context context,
@Main Handler mainHandler,
NotificationLockscreenUserManager notificationLockscreenUserManager,
- NotificationGroupManager groupManager,
+ NotificationGroupManagerLegacy groupManager,
VisualStabilityManager visualStabilityManager,
StatusBarStateController statusBarStateController,
NotificationEntryManager notificationEntryManager,
@@ -187,13 +187,13 @@ public class NotificationViewHierarchyManager implements DynamicPrivacyControlle
ent.setSensitive(sensitive, deviceSensitive);
ent.getRow().setNeedsRedaction(needsRedaction);
mLowPriorityInflationHelper.recheckLowPriorityViewAndInflate(ent, ent.getRow());
- boolean isChildInGroup = mGroupManager.isChildInGroupWithSummary(ent.getSbn());
+ boolean isChildInGroup = mGroupManager.isChildInGroup(ent);
boolean groupChangesAllowed =
mVisualStabilityManager.areGroupChangesAllowed() // user isn't looking at notifs
|| !ent.hasFinishedInitialization(); // notif recently added
- NotificationEntry parent = mGroupManager.getGroupSummary(ent.getSbn());
+ NotificationEntry parent = mGroupManager.getGroupSummary(ent);
if (!groupChangesAllowed) {
// We don't to change groups while the user is looking at them
boolean wasChildInGroup = ent.isChildInGroup();
@@ -420,11 +420,6 @@ public class NotificationViewHierarchyManager implements DynamicPrivacyControlle
int visibleNotifications = 0;
boolean onKeyguard = mStatusBarStateController.getState() == StatusBarState.KEYGUARD;
- int maxNotifications = -1;
- if (onKeyguard && !mBypassController.getBypassEnabled()) {
- maxNotifications = mPresenter.getMaxNotificationsWhileLocked(true /* recompute */);
- }
- mListContainer.setMaxDisplayedNotifications(maxNotifications);
Stack<ExpandableNotificationRow> stack = new Stack<>();
for (int i = N - 1; i >= 0; i--) {
View child = mListContainer.getContainerChildAt(i);
@@ -436,10 +431,7 @@ public class NotificationViewHierarchyManager implements DynamicPrivacyControlle
while(!stack.isEmpty()) {
ExpandableNotificationRow row = stack.pop();
NotificationEntry entry = row.getEntry();
- boolean isChildNotification =
- mGroupManager.isChildInGroupWithSummary(entry.getSbn());
-
- row.setOnKeyguard(onKeyguard);
+ boolean isChildNotification = mGroupManager.isChildInGroup(entry);
if (!onKeyguard) {
// If mAlwaysExpandNonGroupedNotification is false, then only expand the
@@ -455,9 +447,8 @@ public class NotificationViewHierarchyManager implements DynamicPrivacyControlle
boolean showOnKeyguard = mLockscreenUserManager.shouldShowOnKeyguard(entry);
if (!showOnKeyguard) {
// min priority notifications should show if their summary is showing
- if (mGroupManager.isChildInGroupWithSummary(entry.getSbn())) {
- NotificationEntry summary = mGroupManager.getLogicalGroupSummary(
- entry.getSbn());
+ if (mGroupManager.isChildInGroup(entry)) {
+ NotificationEntry summary = mGroupManager.getLogicalGroupSummary(entry);
if (summary != null && mLockscreenUserManager.shouldShowOnKeyguard(summary)) {
showOnKeyguard = true;
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/PulseExpansionHandler.kt b/packages/SystemUI/src/com/android/systemui/statusbar/PulseExpansionHandler.kt
index ba54d1bff6e8..6fa3633acc43 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/PulseExpansionHandler.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/PulseExpansionHandler.kt
@@ -30,6 +30,7 @@ import android.view.ViewConfiguration
import com.android.systemui.Gefingerpoken
import com.android.systemui.Interpolators
import com.android.systemui.R
+import com.android.systemui.classifier.Classifier.NOTIFICATION_DRAG_DOWN
import com.android.systemui.dagger.SysUISingleton
import com.android.systemui.plugins.FalsingManager
import com.android.systemui.plugins.statusbar.StatusBarStateController
@@ -106,7 +107,7 @@ constructor(
private var velocityTracker: VelocityTracker? = null
private val isFalseTouch: Boolean
- get() = falsingManager.isFalseTouch
+ get() = falsingManager.isFalseTouch(NOTIFICATION_DRAG_DOWN)
var qsExpanded: Boolean = false
var pulseExpandAbortListener: Runnable? = null
var bouncerShowing: Boolean = false
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/dagger/StatusBarDependenciesModule.java b/packages/SystemUI/src/com/android/systemui/statusbar/dagger/StatusBarDependenciesModule.java
index 44550b72e521..d15b8476b3c5 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/dagger/StatusBarDependenciesModule.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/dagger/StatusBarDependenciesModule.java
@@ -37,21 +37,29 @@ import com.android.systemui.statusbar.NotificationRemoteInputManager;
import com.android.systemui.statusbar.NotificationShadeWindowController;
import com.android.systemui.statusbar.NotificationViewHierarchyManager;
import com.android.systemui.statusbar.SmartReplyController;
+import com.android.systemui.statusbar.StatusBarStateControllerImpl;
+import com.android.systemui.statusbar.SysuiStatusBarStateController;
import com.android.systemui.statusbar.notification.AssistantFeedbackController;
import com.android.systemui.statusbar.notification.DynamicChildBindController;
import com.android.systemui.statusbar.notification.DynamicPrivacyController;
import com.android.systemui.statusbar.notification.NotificationEntryManager;
import com.android.systemui.statusbar.notification.collection.inflation.LowPriorityInflationHelper;
+import com.android.systemui.statusbar.notification.collection.legacy.NotificationGroupManagerLegacy;
import com.android.systemui.statusbar.notification.collection.legacy.VisualStabilityManager;
import com.android.systemui.statusbar.notification.stack.ForegroundServiceSectionController;
import com.android.systemui.statusbar.phone.KeyguardBypassController;
-import com.android.systemui.statusbar.phone.NotificationGroupManager;
+import com.android.systemui.statusbar.phone.ManagedProfileController;
+import com.android.systemui.statusbar.phone.ManagedProfileControllerImpl;
import com.android.systemui.statusbar.phone.StatusBar;
+import com.android.systemui.statusbar.phone.StatusBarIconController;
+import com.android.systemui.statusbar.phone.StatusBarIconControllerImpl;
+import com.android.systemui.statusbar.phone.StatusBarRemoteInputCallback;
import com.android.systemui.statusbar.policy.RemoteInputUriController;
import com.android.systemui.tracing.ProtoTracer;
import com.android.systemui.util.DeviceConfigProxy;
import com.android.systemui.util.concurrency.DelayableExecutor;
+import dagger.Binds;
import dagger.Lazy;
import dagger.Module;
import dagger.Provides;
@@ -136,6 +144,12 @@ public interface StatusBarDependenciesModule {
return new SmartReplyController(entryManager, statusBarService, clickNotifier);
}
+
+ /** */
+ @Binds
+ NotificationRemoteInputManager.Callback provideNotificationRemoteInputManagerCallback(
+ StatusBarRemoteInputCallback callbackImpl);
+
/** */
@SysUISingleton
@Provides
@@ -143,7 +157,7 @@ public interface StatusBarDependenciesModule {
Context context,
@Main Handler mainHandler,
NotificationLockscreenUserManager notificationLockscreenUserManager,
- NotificationGroupManager groupManager,
+ NotificationGroupManagerLegacy groupManager,
VisualStabilityManager visualStabilityManager,
StatusBarStateController statusBarStateController,
NotificationEntryManager notificationEntryManager,
@@ -179,4 +193,22 @@ public interface StatusBarDependenciesModule {
static CommandQueue provideCommandQueue(Context context, ProtoTracer protoTracer) {
return new CommandQueue(context, protoTracer);
}
+
+ /**
+ */
+ @Binds
+ ManagedProfileController provideManagedProfileController(
+ ManagedProfileControllerImpl controllerImpl);
+
+ /**
+ */
+ @Binds
+ SysuiStatusBarStateController providesSysuiStatusBarStateController(
+ StatusBarStateControllerImpl statusBarStateControllerImpl);
+
+ /**
+ */
+ @Binds
+ StatusBarIconController provideStatusBarIconController(
+ StatusBarIconControllerImpl controllerImpl);
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/ConversationNotifications.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/ConversationNotifications.kt
index c68625c9d9ee..433c8b0d361d 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/ConversationNotifications.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/ConversationNotifications.kt
@@ -30,7 +30,7 @@ import com.android.systemui.statusbar.notification.collection.NotificationEntry
import com.android.systemui.statusbar.notification.row.ExpandableNotificationRow
import com.android.systemui.statusbar.notification.row.NotificationContentView
import com.android.systemui.statusbar.notification.stack.StackStateAnimator
-import com.android.systemui.statusbar.phone.NotificationGroupManager
+import com.android.systemui.statusbar.notification.collection.legacy.NotificationGroupManagerLegacy
import java.util.concurrent.ConcurrentHashMap
import javax.inject.Inject
@@ -64,7 +64,7 @@ class ConversationNotificationProcessor @Inject constructor(
@SysUISingleton
class ConversationNotificationManager @Inject constructor(
private val notificationEntryManager: NotificationEntryManager,
- private val notificationGroupManager: NotificationGroupManager,
+ private val notificationGroupManager: NotificationGroupManagerLegacy,
private val context: Context,
@Main private val mainHandler: Handler
) {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/InstantAppNotifier.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/InstantAppNotifier.java
index c27f66356ff3..6f7b32b3ac74 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/InstantAppNotifier.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/InstantAppNotifier.java
@@ -55,10 +55,10 @@ import com.android.systemui.R;
import com.android.systemui.SystemUI;
import com.android.systemui.dagger.SysUISingleton;
import com.android.systemui.dagger.qualifiers.UiBackground;
-import com.android.systemui.stackdivider.SplitScreenController;
import com.android.systemui.statusbar.CommandQueue;
import com.android.systemui.statusbar.policy.KeyguardStateController;
import com.android.systemui.util.NotificationChannels;
+import com.android.wm.shell.splitscreen.SplitScreen;
import java.util.List;
import java.util.Optional;
@@ -81,14 +81,13 @@ public class InstantAppNotifier extends SystemUI
private final CommandQueue mCommandQueue;
private boolean mDockedStackExists;
private KeyguardStateController mKeyguardStateController;
- private final Optional<SplitScreenController> mSplitScreenControllerOptional;
+ private final Optional<SplitScreen> mSplitScreenOptional;
@Inject
public InstantAppNotifier(Context context, CommandQueue commandQueue,
- @UiBackground Executor uiBgExecutor,
- Optional<SplitScreenController> splitScreenControllerOptional) {
+ @UiBackground Executor uiBgExecutor, Optional<SplitScreen> splitScreenOptional) {
super(context);
- mSplitScreenControllerOptional = splitScreenControllerOptional;
+ mSplitScreenOptional = splitScreenOptional;
mCommandQueue = commandQueue;
mUiBgExecutor = uiBgExecutor;
}
@@ -107,7 +106,7 @@ public class InstantAppNotifier extends SystemUI
mCommandQueue.addCallback(this);
mKeyguardStateController.addCallback(this);
- mSplitScreenControllerOptional.ifPresent(splitScreen ->
+ mSplitScreenOptional.ifPresent(splitScreen ->
splitScreen.registerInSplitScreenListener(exists -> {
mDockedStackExists = exists;
updateForegroundInstantApps();
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationEntryManager.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationEntryManager.java
index b5f1c7ff9b62..e1e77b0723a4 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationEntryManager.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationEntryManager.java
@@ -48,13 +48,13 @@ import com.android.systemui.statusbar.NotificationUiAdjustment;
import com.android.systemui.statusbar.notification.collection.NotificationEntry;
import com.android.systemui.statusbar.notification.collection.NotificationRankingManager;
import com.android.systemui.statusbar.notification.collection.inflation.NotificationRowBinder;
+import com.android.systemui.statusbar.notification.collection.legacy.NotificationGroupManagerLegacy;
import com.android.systemui.statusbar.notification.collection.legacy.VisualStabilityManager;
import com.android.systemui.statusbar.notification.collection.notifcollection.CommonNotifCollection;
import com.android.systemui.statusbar.notification.collection.notifcollection.DismissedByUserStats;
import com.android.systemui.statusbar.notification.collection.notifcollection.NotifCollectionListener;
import com.android.systemui.statusbar.notification.dagger.NotificationsModule;
import com.android.systemui.statusbar.notification.logging.NotificationLogger;
-import com.android.systemui.statusbar.phone.NotificationGroupManager;
import com.android.systemui.util.Assert;
import com.android.systemui.util.leak.LeakDetector;
@@ -139,7 +139,7 @@ public class NotificationEntryManager implements
private final List<NotifCollectionListener> mNotifCollectionListeners = new ArrayList<>();
private final KeyguardEnvironment mKeyguardEnvironment;
- private final NotificationGroupManager mGroupManager;
+ private final NotificationGroupManagerLegacy mGroupManager;
private final NotificationRankingManager mRankingManager;
private final FeatureFlags mFeatureFlags;
private final ForegroundServiceDismissalFeatureController mFgsFeatureController;
@@ -199,7 +199,7 @@ public class NotificationEntryManager implements
*/
public NotificationEntryManager(
NotificationEntryManagerLogger logger,
- NotificationGroupManager groupManager,
+ NotificationGroupManagerLegacy groupManager,
NotificationRankingManager rankingManager,
KeyguardEnvironment keyguardEnvironment,
FeatureFlags featureFlags,
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationFilter.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationFilter.java
index 590ccf830a78..73c7fd1b64a3 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationFilter.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationFilter.java
@@ -34,7 +34,6 @@ import com.android.systemui.media.MediaFeatureFlag;
import com.android.systemui.plugins.statusbar.StatusBarStateController;
import com.android.systemui.statusbar.NotificationLockscreenUserManager;
import com.android.systemui.statusbar.notification.collection.NotificationEntry;
-import com.android.systemui.statusbar.phone.NotificationGroupManager;
import com.android.systemui.statusbar.phone.ShadeController;
import javax.inject.Inject;
@@ -46,8 +45,6 @@ import javax.inject.Inject;
@SysUISingleton
public class NotificationFilter {
- private final NotificationGroupManager mGroupManager = Dependency.get(
- NotificationGroupManager.class);
private final StatusBarStateController mStatusBarStateController;
private final Boolean mIsMediaFlagEnabled;
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/NotificationEntry.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/NotificationEntry.java
index 387247eb6c5b..789e78e33671 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/NotificationEntry.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/NotificationEntry.java
@@ -60,6 +60,7 @@ import com.android.internal.util.ArrayUtils;
import com.android.internal.util.ContrastColorUtil;
import com.android.systemui.statusbar.InflationTask;
import com.android.systemui.statusbar.notification.collection.NotifCollection.CancellationReason;
+import com.android.systemui.statusbar.notification.collection.legacy.NotificationGroupManagerLegacy;
import com.android.systemui.statusbar.notification.collection.listbuilder.pluggable.NotifFilter;
import com.android.systemui.statusbar.notification.collection.listbuilder.pluggable.NotifPromoter;
import com.android.systemui.statusbar.notification.collection.notifcollection.NotifDismissInterceptor;
@@ -69,7 +70,6 @@ import com.android.systemui.statusbar.notification.row.ExpandableNotificationRow
import com.android.systemui.statusbar.notification.row.ExpandableNotificationRowController;
import com.android.systemui.statusbar.notification.row.NotificationGuts;
import com.android.systemui.statusbar.notification.stack.PriorityBucket;
-import com.android.systemui.statusbar.phone.NotificationGroupManager;
import java.util.ArrayList;
import java.util.List;
@@ -177,6 +177,7 @@ public final class NotificationEntry extends ListEntry {
@Nullable private Long mPendingAnimationDuration;
private boolean mIsMarkedForUserTriggeredMovement;
private boolean mShelfIconVisible;
+ private boolean mIsAlerting;
/**
* @param sbn the StatusBarNotification from system server
@@ -429,7 +430,7 @@ public final class NotificationEntry extends ListEntry {
* Get the children that are actually attached to this notification's row.
*
* TODO: Seems like most callers here should probably be using
- * {@link NotificationGroupManager#getChildren}
+ * {@link NotificationGroupManagerLegacy#getChildren}
*/
public @Nullable List<NotificationEntry> getAttachedNotifChildren() {
if (row == null) {
@@ -955,6 +956,14 @@ public final class NotificationEntry extends ListEntry {
mIsMarkedForUserTriggeredMovement = marked;
}
+ public void setIsAlerting(boolean isAlerting) {
+ mIsAlerting = isAlerting;
+ }
+
+ public boolean isAlerting() {
+ return mIsAlerting;
+ }
+
/** Information about a suggestion that is being edited. */
public static class EditedSuggestionInfo {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/NotificationRankingManager.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/NotificationRankingManager.kt
index bab2686c5c9c..fb42c424f603 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/NotificationRankingManager.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/NotificationRankingManager.kt
@@ -33,7 +33,7 @@ import com.android.systemui.statusbar.notification.stack.BUCKET_FOREGROUND_SERVI
import com.android.systemui.statusbar.notification.stack.BUCKET_PEOPLE
import com.android.systemui.statusbar.notification.stack.BUCKET_SILENT
import com.android.systemui.statusbar.notification.stack.PriorityBucket
-import com.android.systemui.statusbar.phone.NotificationGroupManager
+import com.android.systemui.statusbar.notification.collection.legacy.NotificationGroupManagerLegacy
import com.android.systemui.statusbar.policy.HeadsUpManager
import dagger.Lazy
import java.util.Objects
@@ -52,7 +52,7 @@ private const val TAG = "NotifRankingManager"
*/
open class NotificationRankingManager @Inject constructor(
private val mediaManagerLazy: Lazy<NotificationMediaManager>,
- private val groupManager: NotificationGroupManager,
+ private val groupManager: NotificationGroupManagerLegacy,
private val headsUpManager: HeadsUpManager,
private val notifFilter: NotificationFilter,
private val logger: NotificationEntryManagerLogger,
@@ -191,7 +191,7 @@ open class NotificationRankingManager @Inject constructor(
private fun NotificationEntry.isConversation() = getPeopleNotificationType() != TYPE_NON_PERSON
private fun NotificationEntry.getPeopleNotificationType() =
- peopleNotificationIdentifier.getPeopleNotificationType(sbn, ranking)
+ peopleNotificationIdentifier.getPeopleNotificationType(this)
private fun NotificationEntry.isHighPriority() =
highPriorityProvider.isHighPriority(this)
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/ConversationCoordinator.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/ConversationCoordinator.kt
index dea11626a3f8..3aaa9acdb897 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/ConversationCoordinator.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/ConversationCoordinator.kt
@@ -53,8 +53,7 @@ class ConversationCoordinator @Inject constructor(
}
private fun isConversation(entry: NotificationEntry): Boolean =
- peopleNotificationIdentifier.getPeopleNotificationType(entry.sbn, entry.ranking) !=
- TYPE_NON_PERSON
+ peopleNotificationIdentifier.getPeopleNotificationType(entry) != TYPE_NON_PERSON
companion object {
private const val TAG = "ConversationCoordinator"
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/HeadsUpCoordinator.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/HeadsUpCoordinator.java
index c023400ca9ca..24e912ed0cc3 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/HeadsUpCoordinator.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/HeadsUpCoordinator.java
@@ -204,10 +204,8 @@ public class HeadsUpCoordinator implements Coordinator {
public void onHeadsUpStateChanged(NotificationEntry entry, boolean isHeadsUp) {
NotificationEntry newHUN = mHeadsUpManager.getTopEntry();
if (!Objects.equals(mCurrentHun, newHUN)) {
- endNotifLifetimeExtension();
mCurrentHun = newHUN;
- mNotifPromoter.invalidateList();
- mNotifSectioner.invalidateList();
+ endNotifLifetimeExtension();
}
if (!isHeadsUp) {
mHeadsUpViewBinder.unbindHeadsUpView(entry);
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/inflation/LowPriorityInflationHelper.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/inflation/LowPriorityInflationHelper.java
index 6089aa26fe71..aec26474cf7d 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/inflation/LowPriorityInflationHelper.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/inflation/LowPriorityInflationHelper.java
@@ -20,10 +20,10 @@ import com.android.systemui.dagger.SysUISingleton;
import com.android.systemui.statusbar.FeatureFlags;
import com.android.systemui.statusbar.notification.collection.GroupEntry;
import com.android.systemui.statusbar.notification.collection.NotificationEntry;
+import com.android.systemui.statusbar.notification.collection.legacy.NotificationGroupManagerLegacy;
import com.android.systemui.statusbar.notification.row.ExpandableNotificationRow;
import com.android.systemui.statusbar.notification.row.RowContentBindParams;
import com.android.systemui.statusbar.notification.row.RowContentBindStage;
-import com.android.systemui.statusbar.phone.NotificationGroupManager;
import javax.inject.Inject;
@@ -34,13 +34,13 @@ import javax.inject.Inject;
@SysUISingleton
public class LowPriorityInflationHelper {
private final FeatureFlags mFeatureFlags;
- private final NotificationGroupManager mGroupManager;
+ private final NotificationGroupManagerLegacy mGroupManager;
private final RowContentBindStage mRowContentBindStage;
@Inject
LowPriorityInflationHelper(
FeatureFlags featureFlags,
- NotificationGroupManager groupManager,
+ NotificationGroupManagerLegacy groupManager,
RowContentBindStage rowContentBindStage) {
mFeatureFlags = featureFlags;
mGroupManager = groupManager;
@@ -78,7 +78,7 @@ public class LowPriorityInflationHelper {
if (mFeatureFlags.isNewNotifPipelineRenderingEnabled()) {
isGroupChild = (entry.getParent() != GroupEntry.ROOT_ENTRY);
} else {
- isGroupChild = mGroupManager.isChildInGroupWithSummary(entry.getSbn());
+ isGroupChild = mGroupManager.isChildInGroup(entry);
}
return entry.isAmbient() && !isGroupChild;
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/inflation/NotificationRowBinderImpl.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/inflation/NotificationRowBinderImpl.java
index 7c061aad7b4a..e5425cfc8c93 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/inflation/NotificationRowBinderImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/inflation/NotificationRowBinderImpl.java
@@ -140,7 +140,7 @@ public class NotificationRowBinderImpl implements NotificationRowBinder {
.build();
ExpandableNotificationRowController rowController =
component.getExpandableNotificationRowController();
- rowController.init();
+ rowController.init(entry);
entry.setRowController(rowController);
bindRow(entry, row);
updateRow(entry, row);
@@ -160,7 +160,6 @@ public class NotificationRowBinderImpl implements NotificationRowBinder {
mNotificationRemoteInputManager.bindRow(row);
row.setOnActivatedListener(mPresenter);
entry.setRow(row);
- row.setEntry(entry);
mNotifBindPipeline.manageRow(entry, row);
mBindRowCallback.onBindRow(row);
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationGroupManager.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/legacy/NotificationGroupManagerLegacy.java
index c44c59c02810..21d54c85160b 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationGroupManager.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/legacy/NotificationGroupManagerLegacy.java
@@ -11,10 +11,10 @@
* 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
+ * limitations under the License.
*/
-package com.android.systemui.statusbar.phone;
+package com.android.systemui.statusbar.notification.collection.legacy;
import android.annotation.Nullable;
import android.service.notification.StatusBarNotification;
@@ -22,14 +22,17 @@ import android.util.ArraySet;
import android.util.Log;
import com.android.systemui.Dependency;
+import com.android.systemui.Dumpable;
import com.android.systemui.bubbles.BubbleController;
import com.android.systemui.dagger.SysUISingleton;
import com.android.systemui.plugins.statusbar.StatusBarStateController;
import com.android.systemui.plugins.statusbar.StatusBarStateController.StateListener;
import com.android.systemui.statusbar.StatusBarState;
+import com.android.systemui.statusbar.notification.collection.ListEntry;
import com.android.systemui.statusbar.notification.collection.NotificationEntry;
+import com.android.systemui.statusbar.notification.collection.render.GroupExpansionManager;
+import com.android.systemui.statusbar.notification.collection.render.GroupMembershipManager;
import com.android.systemui.statusbar.notification.people.PeopleNotificationIdentifier;
-import com.android.systemui.statusbar.notification.row.ExpandableNotificationRow;
import com.android.systemui.statusbar.policy.HeadsUpManager;
import com.android.systemui.statusbar.policy.OnHeadsUpChangedListener;
@@ -37,6 +40,7 @@ import java.io.FileDescriptor;
import java.io.PrintWriter;
import java.util.ArrayList;
import java.util.HashMap;
+import java.util.List;
import java.util.Map;
import java.util.Objects;
@@ -46,13 +50,19 @@ import dagger.Lazy;
/**
* A class to handle notifications and their corresponding groups.
+ * This includes:
+ * 1. Determining whether an entry is a member of a group and whether it is a summary or a child
+ * 2. Tracking group expansion states
*/
@SysUISingleton
-public class NotificationGroupManager implements OnHeadsUpChangedListener, StateListener {
+public class NotificationGroupManagerLegacy implements OnHeadsUpChangedListener, StateListener,
+ GroupMembershipManager, GroupExpansionManager, Dumpable {
private static final String TAG = "NotificationGroupManager";
private final HashMap<String, NotificationGroup> mGroupMap = new HashMap<>();
- private final ArraySet<OnGroupChangeListener> mListeners = new ArraySet<>();
+ private final ArraySet<OnGroupExpansionChangeListener> mExpansionChangeListeners =
+ new ArraySet<>();
+ private final ArraySet<OnGroupChangeListener> mGroupChangeListeners = new ArraySet<>();
private final Lazy<PeopleNotificationIdentifier> mPeopleNotificationIdentifier;
private int mBarState = -1;
private HashMap<String, StatusBarNotification> mIsolatedEntries = new HashMap<>();
@@ -61,7 +71,7 @@ public class NotificationGroupManager implements OnHeadsUpChangedListener, State
@Nullable private BubbleController mBubbleController = null;
@Inject
- public NotificationGroupManager(
+ public NotificationGroupManagerLegacy(
StatusBarStateController statusBarStateController,
Lazy<PeopleNotificationIdentifier> peopleNotificationIdentifier) {
statusBarStateController.addCallback(this);
@@ -77,15 +87,19 @@ public class NotificationGroupManager implements OnHeadsUpChangedListener, State
/**
* Add a listener for changes to groups.
- *
- * @param listener listener to add
*/
- public void addOnGroupChangeListener(OnGroupChangeListener listener) {
- mListeners.add(listener);
+ public void registerGroupChangeListener(OnGroupChangeListener listener) {
+ mGroupChangeListeners.add(listener);
}
- public boolean isGroupExpanded(StatusBarNotification sbn) {
- NotificationGroup group = mGroupMap.get(getGroupKey(sbn));
+ @Override
+ public void registerGroupExpansionChangeListener(OnGroupExpansionChangeListener listener) {
+ mExpansionChangeListeners.add(listener);
+ }
+
+ @Override
+ public boolean isGroupExpanded(NotificationEntry entry) {
+ NotificationGroup group = mGroupMap.get(getGroupKey(entry.getSbn()));
if (group == null) {
return false;
}
@@ -103,8 +117,9 @@ public class NotificationGroupManager implements OnHeadsUpChangedListener, State
return group.expanded;
}
- public void setGroupExpanded(StatusBarNotification sbn, boolean expanded) {
- NotificationGroup group = mGroupMap.get(getGroupKey(sbn));
+ @Override
+ public void setGroupExpanded(NotificationEntry entry, boolean expanded) {
+ NotificationGroup group = mGroupMap.get(getGroupKey(entry.getSbn()));
if (group == null) {
return;
}
@@ -114,12 +129,15 @@ public class NotificationGroupManager implements OnHeadsUpChangedListener, State
private void setGroupExpanded(NotificationGroup group, boolean expanded) {
group.expanded = expanded;
if (group.summary != null) {
- for (OnGroupChangeListener listener : mListeners) {
- listener.onGroupExpansionChanged(group.summary.getRow(), expanded);
+ for (OnGroupExpansionChangeListener listener : mExpansionChangeListeners) {
+ listener.onGroupExpansionChange(group.summary.getRow(), expanded);
}
}
}
+ /**
+ * When we want to remove an entry from being tracked for grouping
+ */
public void onEntryRemoved(NotificationEntry removed) {
onEntryRemovedInternal(removed, removed.getSbn());
mIsolatedEntries.remove(removed.getKey());
@@ -158,7 +176,7 @@ public class NotificationGroupManager implements OnHeadsUpChangedListener, State
if (group.children.isEmpty()) {
if (group.summary == null) {
mGroupMap.remove(groupKey);
- for (OnGroupChangeListener listener : mListeners) {
+ for (OnGroupChangeListener listener : mGroupChangeListeners) {
listener.onGroupRemoved(group, groupKey);
}
}
@@ -184,7 +202,8 @@ public class NotificationGroupManager implements OnHeadsUpChangedListener, State
if (group == null) {
group = new NotificationGroup();
mGroupMap.put(groupKey, group);
- for (OnGroupChangeListener listener : mListeners) {
+
+ for (OnGroupChangeListener listener : mGroupChangeListeners) {
listener.onGroupCreated(group, groupKey);
}
}
@@ -195,9 +214,8 @@ public class NotificationGroupManager implements OnHeadsUpChangedListener, State
Log.wtf(TAG, "Inconsistent entries found with the same key " + added.getKey()
+ "existing removed: " + existing.isRowRemoved()
+ (existingThrowable != null
- ? Log.getStackTraceString(existingThrowable) + "\n": "")
- + " added removed" + added.isRowRemoved()
- , new Throwable());
+ ? Log.getStackTraceString(existingThrowable) + "\n" : "")
+ + " added removed" + added.isRowRemoved(), new Throwable());
}
group.children.put(added.getKey(), added);
updateSuppression(group);
@@ -206,12 +224,12 @@ public class NotificationGroupManager implements OnHeadsUpChangedListener, State
group.expanded = added.areChildrenExpanded();
updateSuppression(group);
if (!group.children.isEmpty()) {
- ArrayList<NotificationEntry> childrenCopy
- = new ArrayList<>(group.children.values());
+ ArrayList<NotificationEntry> childrenCopy =
+ new ArrayList<>(group.children.values());
for (NotificationEntry child : childrenCopy) {
onEntryBecomingChild(child);
}
- for (OnGroupChangeListener listener : mListeners) {
+ for (OnGroupChangeListener listener : mGroupChangeListeners) {
listener.onGroupCreatedFromChildren(group);
}
}
@@ -243,7 +261,7 @@ public class NotificationGroupManager implements OnHeadsUpChangedListener, State
&& group.summary.getSbn().getNotification().isGroupSummary()
&& (hasIsolatedChildren(group) || hasBubbles)));
if (prevSuppressed != group.suppressed) {
- for (OnGroupChangeListener listener : mListeners) {
+ for (OnGroupChangeListener listener : mGroupChangeListeners) {
if (!mIsUpdatingUnchangedGroup) {
listener.onGroupSuppressionChanged(group, group.suppressed);
listener.onGroupsChanged();
@@ -306,6 +324,9 @@ public class NotificationGroupManager implements OnHeadsUpChangedListener, State
}
}
+ /**
+ * Whether the given notification is the summary of a group that is being suppressed
+ */
public boolean isSummaryOfSuppressedGroup(StatusBarNotification sbn) {
return isGroupSuppressed(getGroupKey(sbn)) && sbn.getNotification().isGroupSummary();
}
@@ -315,13 +336,14 @@ public class NotificationGroupManager implements OnHeadsUpChangedListener, State
&& getTotalNumberOfChildren(sbn) == 1;
}
- public boolean isOnlyChildInGroup(StatusBarNotification sbn) {
+ @Override
+ public boolean isOnlyChildInGroup(NotificationEntry entry) {
+ final StatusBarNotification sbn = entry.getSbn();
if (!isOnlyChild(sbn)) {
return false;
}
- NotificationEntry logicalGroupSummary = getLogicalGroupSummary(sbn);
- return logicalGroupSummary != null
- && !logicalGroupSummary.getSbn().equals(sbn);
+ NotificationEntry logicalGroupSummary = getLogicalGroupSummary(entry);
+ return logicalGroupSummary != null && !logicalGroupSummary.getSbn().equals(sbn);
}
private int getTotalNumberOfChildren(StatusBarNotification sbn) {
@@ -339,11 +361,12 @@ public class NotificationGroupManager implements OnHeadsUpChangedListener, State
private void setStatusBarState(int newState) {
mBarState = newState;
if (mBarState == StatusBarState.KEYGUARD) {
- collapseAllGroups();
+ collapseGroups();
}
}
- public void collapseAllGroups() {
+ @Override
+ public void collapseGroups() {
// Because notifications can become isolated when the group becomes suppressed it can
// lead to concurrent modifications while looping. We need to make a copy.
ArrayList<NotificationGroup> groupCopy = new ArrayList<>(mGroupMap.values());
@@ -357,10 +380,9 @@ public class NotificationGroupManager implements OnHeadsUpChangedListener, State
}
}
- /**
- * @return whether a given notification is a child in a group which has a summary
- */
- public boolean isChildInGroupWithSummary(StatusBarNotification sbn) {
+ @Override
+ public boolean isChildInGroup(NotificationEntry entry) {
+ final StatusBarNotification sbn = entry.getSbn();
if (!isGroupChild(sbn)) {
return false;
}
@@ -377,10 +399,9 @@ public class NotificationGroupManager implements OnHeadsUpChangedListener, State
return true;
}
- /**
- * @return whether a given notification is a summary in a group which has children
- */
- public boolean isSummaryOfGroup(StatusBarNotification sbn) {
+ @Override
+ public boolean isGroupSummary(NotificationEntry entry) {
+ final StatusBarNotification sbn = entry.getSbn();
if (!isGroupSummary(sbn)) {
return false;
}
@@ -391,21 +412,14 @@ public class NotificationGroupManager implements OnHeadsUpChangedListener, State
return !group.children.isEmpty() && Objects.equals(group.summary.getSbn(), sbn);
}
- /**
- * Get the summary of a specified status bar notification. For isolated notification this return
- * itself.
- */
- public NotificationEntry getGroupSummary(StatusBarNotification sbn) {
- return getGroupSummary(getGroupKey(sbn));
+ @Override
+ public NotificationEntry getGroupSummary(NotificationEntry entry) {
+ return getGroupSummary(getGroupKey(entry.getSbn()));
}
- /**
- * Similar to {@link #getGroupSummary(StatusBarNotification)} but doesn't get the visual summary
- * but the logical summary, i.e when a child is isolated, it still returns the summary as if
- * it wasn't isolated.
- */
- public NotificationEntry getLogicalGroupSummary(StatusBarNotification sbn) {
- return getGroupSummary(sbn.getGroupKey());
+ @Override
+ public NotificationEntry getLogicalGroupSummary(NotificationEntry entry) {
+ return getGroupSummary(entry.getSbn().getGroupKey());
}
@Nullable
@@ -436,14 +450,10 @@ public class NotificationGroupManager implements OnHeadsUpChangedListener, State
return children;
}
- /**
- * Get the children that are in the summary's group, not including those isolated.
- *
- * @param summary summary of a group
- * @return list of the children
- */
- public @Nullable ArrayList<NotificationEntry> getChildren(StatusBarNotification summary) {
- NotificationGroup group = mGroupMap.get(summary.getGroupKey());
+ @Override
+ public @Nullable List<NotificationEntry> getChildren(ListEntry listEntrySummary) {
+ NotificationEntry summary = listEntrySummary.getRepresentativeEntry();
+ NotificationGroup group = mGroupMap.get(summary.getSbn().getGroupKey());
if (group == null) {
return null;
}
@@ -479,9 +489,9 @@ public class NotificationGroupManager implements OnHeadsUpChangedListener, State
return groupKey;
}
- /** @return group expansion state after toggling. */
- public boolean toggleGroupExpansion(StatusBarNotification sbn) {
- NotificationGroup group = mGroupMap.get(getGroupKey(sbn));
+ @Override
+ public boolean toggleGroupExpansion(NotificationEntry entry) {
+ NotificationGroup group = mGroupMap.get(getGroupKey(entry.getSbn()));
if (group == null) {
return false;
}
@@ -494,10 +504,7 @@ public class NotificationGroupManager implements OnHeadsUpChangedListener, State
}
/**
- * Whether a notification is visually a group summary.
- *
- * @param sbn notification to check
- * @return true if it is visually a group summary
+ * Is this notification the summary of a group?
*/
public boolean isGroupSummary(StatusBarNotification sbn) {
if (isIsolated(sbn.getKey())) {
@@ -536,14 +543,13 @@ public class NotificationGroupManager implements OnHeadsUpChangedListener, State
* @param entry the notification to check
* @return true if the entry should be isolated
*/
-
private boolean shouldIsolate(NotificationEntry entry) {
StatusBarNotification sbn = entry.getSbn();
if (!sbn.isGroup() || sbn.getNotification().isGroupSummary()) {
return false;
}
- int peopleNotificationType = mPeopleNotificationIdentifier.get().getPeopleNotificationType(
- entry.getSbn(), entry.getRanking());
+ int peopleNotificationType =
+ mPeopleNotificationIdentifier.get().getPeopleNotificationType(entry);
if (peopleNotificationType == PeopleNotificationIdentifier.TYPE_IMPORTANT_PERSON) {
return true;
}
@@ -576,7 +582,7 @@ public class NotificationGroupManager implements OnHeadsUpChangedListener, State
// When the notification gets added afterwards it is already isolated and therefore
// it doesn't lead to an update.
updateSuppression(mGroupMap.get(entry.getSbn().getGroupKey()));
- for (OnGroupChangeListener listener : mListeners) {
+ for (OnGroupChangeListener listener : mGroupChangeListeners) {
listener.onGroupsChanged();
}
}
@@ -607,7 +613,7 @@ public class NotificationGroupManager implements OnHeadsUpChangedListener, State
onEntryRemovedInternal(entry, entry.getSbn());
mIsolatedEntries.remove(sbn.getKey());
onEntryAddedInternal(entry);
- for (OnGroupChangeListener listener : mListeners) {
+ for (OnGroupChangeListener listener : mGroupChangeListeners) {
listener.onGroupsChanged();
}
}
@@ -618,12 +624,16 @@ public class NotificationGroupManager implements OnHeadsUpChangedListener, State
|| notificationGroup.summary.isGroupNotFullyVisible();
}
+ /**
+ * Directly set the heads up manager to avoid circular dependencies
+ */
public void setHeadsUpManager(HeadsUpManager headsUpManager) {
mHeadsUpManager = headsUpManager;
}
+ @Override
public void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
- pw.println("GroupManager state:");
+ pw.println("GroupManagerLegacy state:");
pw.println(" number of groups: " + mGroupMap.size());
for (Map.Entry<String, NotificationGroup> entry : mGroupMap.entrySet()) {
pw.println("\n key: " + entry.getKey()); pw.println(entry.getValue());
@@ -640,6 +650,9 @@ public class NotificationGroupManager implements OnHeadsUpChangedListener, State
setStatusBarState(newState);
}
+ /**
+ * Represents a notification group in the notification shade.
+ */
public static class NotificationGroup {
public final HashMap<String, NotificationEntry> children = new HashMap<>();
public NotificationEntry summary;
@@ -659,24 +672,29 @@ public class NotificationGroupManager implements OnHeadsUpChangedListener, State
result += "\n children size: " + children.size();
for (NotificationEntry child : children.values()) {
result += "\n " + child.getSbn()
- + (child.getDebugThrowable() != null
- ? Log.getStackTraceString(child.getDebugThrowable())
- : "");
+ + (child.getDebugThrowable() != null
+ ? Log.getStackTraceString(child.getDebugThrowable())
+ : "");
}
result += "\n summary suppressed: " + suppressed;
return result;
}
}
+ /**
+ * Listener for group changes not including group expansion changes which are handled by
+ * {@link OnGroupExpansionChangeListener}.
+ */
public interface OnGroupChangeListener {
-
/**
* A new group has been created.
*
* @param group the group that was created
* @param groupKey the group's key
*/
- default void onGroupCreated(NotificationGroup group, String groupKey) {}
+ default void onGroupCreated(
+ NotificationGroup group,
+ String groupKey) {}
/**
* A group has been removed.
@@ -684,7 +702,9 @@ public class NotificationGroupManager implements OnHeadsUpChangedListener, State
* @param group the group that was removed
* @param groupKey the group's key
*/
- default void onGroupRemoved(NotificationGroup group, String groupKey) {}
+ default void onGroupRemoved(
+ NotificationGroup group,
+ String groupKey) {}
/**
* The suppression of a group has changed.
@@ -692,16 +712,9 @@ public class NotificationGroupManager implements OnHeadsUpChangedListener, State
* @param group the group that has changed
* @param suppressed true if the group is now suppressed, false o/w
*/
- default void onGroupSuppressionChanged(NotificationGroup group, boolean suppressed) {}
-
- /**
- * The expansion of a group has changed.
- *
- * @param changedRow the row for which the expansion has changed, which is also the summary
- * @param expanded a boolean indicating the new expanded state
- */
- default void onGroupExpansionChanged(ExpandableNotificationRow changedRow,
- boolean expanded) {}
+ default void onGroupSuppressionChanged(
+ NotificationGroup group,
+ boolean suppressed) {}
/**
* A group of children just received a summary notification and should therefore become
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/notifcollection/NotifLifetimeExtender.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/notifcollection/NotifLifetimeExtender.java
index 05f5ea85bd4d..f8fe0676e003 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/notifcollection/NotifLifetimeExtender.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/notifcollection/NotifLifetimeExtender.java
@@ -53,8 +53,12 @@ public interface NotifLifetimeExtender {
*/
void cancelLifetimeExtension(NotificationEntry entry);
- /** Callback for notifying the NotifCollection that a lifetime extension has expired. */
+ /** Callback for notifying the NotifCollection that a lifetime extension has expired.*/
interface OnEndLifetimeExtensionCallback {
+ /**
+ * Stop extending the lifetime of `entry` with `extender` and then immediately re-evaluates
+ * whether to continue lifetime extending this notification or to remove it.
+ */
void onEndLifetimeExtension(NotifLifetimeExtender extender, NotificationEntry entry);
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/provider/HighPriorityProvider.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/provider/HighPriorityProvider.java
index 8b803b517f14..18806effc545 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/provider/HighPriorityProvider.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/provider/HighPriorityProvider.java
@@ -20,11 +20,10 @@ import android.app.Notification;
import android.app.NotificationManager;
import com.android.systemui.dagger.SysUISingleton;
-import com.android.systemui.statusbar.notification.collection.GroupEntry;
import com.android.systemui.statusbar.notification.collection.ListEntry;
import com.android.systemui.statusbar.notification.collection.NotificationEntry;
+import com.android.systemui.statusbar.notification.collection.render.GroupMembershipManager;
import com.android.systemui.statusbar.notification.people.PeopleNotificationIdentifier;
-import com.android.systemui.statusbar.phone.NotificationGroupManager;
import java.util.List;
@@ -39,14 +38,14 @@ import javax.inject.Inject;
@SysUISingleton
public class HighPriorityProvider {
private final PeopleNotificationIdentifier mPeopleNotificationIdentifier;
- private final NotificationGroupManager mGroupManager;
+ private final GroupMembershipManager mGroupMembershipManager;
@Inject
public HighPriorityProvider(
PeopleNotificationIdentifier peopleNotificationIdentifier,
- NotificationGroupManager groupManager) {
+ GroupMembershipManager groupManager) {
mPeopleNotificationIdentifier = peopleNotificationIdentifier;
- mGroupManager = groupManager;
+ mGroupMembershipManager = groupManager;
}
/**
@@ -81,20 +80,15 @@ public class HighPriorityProvider {
private boolean hasHighPriorityChild(ListEntry entry) {
- List<NotificationEntry> children = null;
-
- if (entry instanceof GroupEntry) {
- // New notification pipeline
- children = ((GroupEntry) entry).getChildren();
- } else if (entry.getRepresentativeEntry() != null
- && mGroupManager.isGroupSummary(entry.getRepresentativeEntry().getSbn())) {
- // Old notification pipeline
- children = mGroupManager.getChildren(entry.getRepresentativeEntry().getSbn());
+ if (entry instanceof NotificationEntry
+ && !mGroupMembershipManager.isGroupSummary((NotificationEntry) entry)) {
+ return false;
}
+ List<NotificationEntry> children = mGroupMembershipManager.getChildren(entry);
if (children != null) {
for (NotificationEntry child : children) {
- if (isHighPriority(child)) {
+ if (child != entry && isHighPriority(child)) {
return true;
}
}
@@ -122,8 +116,8 @@ public class HighPriorityProvider {
}
private boolean isPeopleNotification(NotificationEntry entry) {
- return mPeopleNotificationIdentifier.getPeopleNotificationType(
- entry.getSbn(), entry.getRanking()) != PeopleNotificationIdentifier.TYPE_NON_PERSON;
+ return mPeopleNotificationIdentifier.getPeopleNotificationType(entry)
+ != PeopleNotificationIdentifier.TYPE_NON_PERSON;
}
private boolean hasUserSetImportance(NotificationEntry entry) {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/render/GroupExpansionManager.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/render/GroupExpansionManager.java
new file mode 100644
index 000000000000..d2df07ed7864
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/render/GroupExpansionManager.java
@@ -0,0 +1,66 @@
+/*
+ * 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.statusbar.notification.collection.render;
+
+import com.android.systemui.Dumpable;
+import com.android.systemui.statusbar.notification.collection.NotificationEntry;
+import com.android.systemui.statusbar.notification.row.ExpandableNotificationRow;
+
+/**
+ * Tracks expanded notification states for groups. This expanded state should not be confused by the
+ * expanded/collapsed state of a single notification which is tracked within each
+ * ExpandableNotificationRow.
+ */
+public interface GroupExpansionManager extends Dumpable {
+
+ /**
+ * Register a listener for group expansion changes
+ */
+ void registerGroupExpansionChangeListener(OnGroupExpansionChangeListener listener);
+
+ /**
+ * Whether the group associated with this notification is expanded.
+ * If this notification is not part of a group, it will always return false.
+ */
+ boolean isGroupExpanded(NotificationEntry entry);
+
+ /**
+ * Set whether the group associated with this notification is expanded or not.
+ */
+ void setGroupExpanded(NotificationEntry entry, boolean expanded);
+
+ /** @return group expansion state after toggling. */
+ boolean toggleGroupExpansion(NotificationEntry entry);
+
+ /**
+ * Set expanded=false for all groups
+ */
+ void collapseGroups();
+
+ /**
+ * Listener for group expansion changes.
+ */
+ interface OnGroupExpansionChangeListener {
+ /**
+ * The expansion of a group has changed.
+ *
+ * @param changedRow the row for which the expansion has changed, which is also the summary
+ * @param expanded a boolean indicating the new expanded state
+ */
+ void onGroupExpansionChange(ExpandableNotificationRow changedRow, boolean expanded);
+ }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/render/GroupExpansionManagerImpl.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/render/GroupExpansionManagerImpl.java
new file mode 100644
index 000000000000..b9aa26f75c9b
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/render/GroupExpansionManagerImpl.java
@@ -0,0 +1,113 @@
+/*
+ * 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.statusbar.notification.collection.render;
+
+import com.android.systemui.statusbar.notification.collection.GroupEntry;
+import com.android.systemui.statusbar.notification.collection.ListEntry;
+import com.android.systemui.statusbar.notification.collection.NotifPipeline;
+import com.android.systemui.statusbar.notification.collection.NotificationEntry;
+import com.android.systemui.statusbar.notification.collection.coordinator.Coordinator;
+import com.android.systemui.statusbar.notification.collection.listbuilder.OnBeforeRenderListListener;
+
+import java.io.FileDescriptor;
+import java.io.PrintWriter;
+import java.util.HashSet;
+import java.util.Set;
+
+/**
+ * Provides grouping information for notification entries including information about a group's
+ * expanded state.
+ */
+public class GroupExpansionManagerImpl implements GroupExpansionManager, Coordinator {
+ private final GroupMembershipManager mGroupMembershipManager;
+ private final Set<OnGroupExpansionChangeListener> mOnGroupChangeListeners = new HashSet<>();
+
+ // Set of summary keys whose groups are expanded
+ private final Set<NotificationEntry> mExpandedGroups = new HashSet<>();
+
+ public GroupExpansionManagerImpl(GroupMembershipManager groupMembershipManager) {
+ mGroupMembershipManager = groupMembershipManager;
+ }
+
+ /**
+ * Cleanup entries from mExpandedGroups that no longer exist in the pipeline.
+ */
+ private final OnBeforeRenderListListener mNotifTracker = (entries) -> {
+ final Set<NotificationEntry> renderingSummaries = new HashSet<>();
+ for (ListEntry entry : entries) {
+ if (entry instanceof GroupEntry) {
+ renderingSummaries.add(entry.getRepresentativeEntry());
+ }
+ }
+ mExpandedGroups.removeIf(expandedGroup -> !renderingSummaries.contains(expandedGroup));
+ };
+
+ @Override
+ public void attach(NotifPipeline pipeline) {
+ pipeline.addOnBeforeRenderListListener(mNotifTracker);
+ }
+
+ @Override
+ public void registerGroupExpansionChangeListener(OnGroupExpansionChangeListener listener) {
+ mOnGroupChangeListeners.add(listener);
+ }
+
+ @Override
+ public boolean isGroupExpanded(NotificationEntry entry) {
+ return mExpandedGroups.contains(mGroupMembershipManager.getGroupSummary(entry));
+ }
+
+ @Override
+ public void setGroupExpanded(NotificationEntry entry, boolean expanded) {
+ final NotificationEntry groupSummary = mGroupMembershipManager.getGroupSummary(entry);
+ if (expanded) {
+ mExpandedGroups.add(groupSummary);
+ } else {
+ mExpandedGroups.remove(groupSummary);
+ }
+
+ sendOnGroupExpandedChange(entry, expanded);
+ }
+
+ @Override
+ public boolean toggleGroupExpansion(NotificationEntry entry) {
+ setGroupExpanded(entry, !isGroupExpanded(entry));
+ return isGroupExpanded(entry);
+ }
+
+ @Override
+ public void collapseGroups() {
+ for (NotificationEntry entry : mExpandedGroups) {
+ setGroupExpanded(entry, false);
+ }
+ }
+
+ @Override
+ public void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
+ pw.println("NotificationEntryExpansion state:");
+ pw.println(" # expanded groups: " + mExpandedGroups.size());
+ for (NotificationEntry entry : mExpandedGroups) {
+ pw.println(" summary key of expanded group: " + entry.getKey());
+ }
+ }
+
+ private void sendOnGroupExpandedChange(NotificationEntry entry, boolean expanded) {
+ for (OnGroupExpansionChangeListener listener : mOnGroupChangeListeners) {
+ listener.onGroupExpansionChange(entry.getRow(), expanded);
+ }
+ }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/render/GroupMembershipManager.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/render/GroupMembershipManager.java
new file mode 100644
index 000000000000..196cb8f26b22
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/render/GroupMembershipManager.java
@@ -0,0 +1,73 @@
+/*
+ * 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.statusbar.notification.collection.render;
+
+import android.annotation.Nullable;
+
+import com.android.systemui.statusbar.notification.collection.ListEntry;
+import com.android.systemui.statusbar.notification.collection.NotificationEntry;
+
+import java.util.List;
+
+/**
+ * Helper that determines the group states (parent, summary, children) of a notification.
+ */
+public interface GroupMembershipManager {
+ /**
+ * @return whether a given notification is a top level entry or is the summary in a group which
+ * has children
+ */
+ boolean isGroupSummary(NotificationEntry entry);
+
+ /**
+ * Get the summary of a specified status bar notification. For an isolated notification this
+ * returns itself.
+ */
+ NotificationEntry getGroupSummary(NotificationEntry entry);
+
+ /**
+ * Similar to {@link #getGroupSummary(NotificationEntry)} but doesn't get the visual summary
+ * but the logical summary, i.e when a child is isolated, it still returns the summary as if
+ * it wasn't isolated.
+ * TODO: remove this when migrating to the new pipeline, this is taken care of in the
+ * dismissal logic built into NotifCollection
+ */
+ default NotificationEntry getLogicalGroupSummary(NotificationEntry entry) {
+ return getGroupSummary(entry);
+ }
+
+ /**
+ * @return whether a given notification is a child in a group
+ */
+ boolean isChildInGroup(NotificationEntry entry);
+
+ /**
+ * Whether this is the only child in a group
+ * TODO: remove this when migrating to the new pipeline, this is taken care of in the
+ * dismissal logic built into NotifCollection
+ */
+ boolean isOnlyChildInGroup(NotificationEntry entry);
+
+ /**
+ * Get the children that are in the summary's group, not including those isolated.
+ *
+ * @param summary summary of a group
+ * @return list of the children
+ */
+ @Nullable
+ List<NotificationEntry> getChildren(ListEntry summary);
+}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/render/GroupMembershipManagerImpl.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/render/GroupMembershipManagerImpl.java
new file mode 100644
index 000000000000..c1f468a3072f
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/render/GroupMembershipManagerImpl.java
@@ -0,0 +1,80 @@
+/*
+ * 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.statusbar.notification.collection.render;
+
+import static com.android.systemui.statusbar.notification.collection.GroupEntry.ROOT_ENTRY;
+
+import androidx.annotation.Nullable;
+
+import com.android.systemui.statusbar.notification.collection.GroupEntry;
+import com.android.systemui.statusbar.notification.collection.ListEntry;
+import com.android.systemui.statusbar.notification.collection.NotificationEntry;
+
+import java.util.List;
+
+/**
+ * ShadeListBuilder groups notifications from system server. This manager translates
+ * ShadeListBuilder's method of grouping to be used within SystemUI.
+ */
+public class GroupMembershipManagerImpl implements GroupMembershipManager {
+ @Override
+ public boolean isGroupSummary(NotificationEntry entry) {
+ return getGroupSummary(entry) == entry;
+ }
+
+ @Override
+ public NotificationEntry getGroupSummary(NotificationEntry entry) {
+ if (isEntryTopLevel(entry) || entry.getParent() == null) {
+ return null;
+ }
+
+ return entry.getParent().getRepresentativeEntry();
+ }
+
+ @Override
+ public boolean isChildInGroup(NotificationEntry entry) {
+ return !isEntryTopLevel(entry);
+ }
+
+ @Override
+ public boolean isOnlyChildInGroup(NotificationEntry entry) {
+ if (entry.getParent() == null) {
+ return false;
+ }
+
+ return entry.getParent().getChildren().size() == 1;
+ }
+
+ @Nullable
+ @Override
+ public List<NotificationEntry> getChildren(ListEntry entry) {
+ if (entry instanceof GroupEntry) {
+ return ((GroupEntry) entry).getChildren();
+ }
+
+ if (isGroupSummary(entry.getRepresentativeEntry())) {
+ // maybe we were actually passed the summary
+ return entry.getRepresentativeEntry().getParent().getChildren();
+ }
+
+ return null;
+ }
+
+ private boolean isEntryTopLevel(NotificationEntry entry) {
+ return entry.getParent() == ROOT_ENTRY;
+ }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/render/ShadeViewManager.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/render/ShadeViewManager.kt
index 3c35b7bd8472..5243854ea412 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/render/ShadeViewManager.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/render/ShadeViewManager.kt
@@ -24,7 +24,6 @@ import com.android.systemui.statusbar.notification.collection.NotificationEntry
import com.android.systemui.statusbar.notification.collection.ShadeListBuilder
import com.android.systemui.statusbar.notification.stack.NotificationListContainer
import com.android.systemui.statusbar.phone.NotificationIconAreaController
-import java.lang.RuntimeException
import javax.inject.Inject
/**
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/dagger/NotificationsModule.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/dagger/NotificationsModule.java
index 6d01324f1b7b..e2aae64ce220 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/dagger/NotificationsModule.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/dagger/NotificationsModule.java
@@ -34,7 +34,7 @@ import com.android.systemui.dagger.qualifiers.Main;
import com.android.systemui.dagger.qualifiers.UiBackground;
import com.android.systemui.keyguard.WakefulnessLifecycle;
import com.android.systemui.plugins.statusbar.StatusBarStateController;
-import com.android.systemui.settings.CurrentUserContextTracker;
+import com.android.systemui.settings.UserContextProvider;
import com.android.systemui.statusbar.FeatureFlags;
import com.android.systemui.statusbar.NotificationListener;
import com.android.systemui.statusbar.NotificationRemoteInputManager;
@@ -50,10 +50,15 @@ import com.android.systemui.statusbar.notification.collection.coordinator.Visual
import com.android.systemui.statusbar.notification.collection.inflation.NotifInflater;
import com.android.systemui.statusbar.notification.collection.inflation.NotificationRowBinder;
import com.android.systemui.statusbar.notification.collection.inflation.OnUserInteractionCallbackImpl;
+import com.android.systemui.statusbar.notification.collection.legacy.NotificationGroupManagerLegacy;
import com.android.systemui.statusbar.notification.collection.legacy.OnUserInteractionCallbackImplLegacy;
import com.android.systemui.statusbar.notification.collection.legacy.VisualStabilityManager;
import com.android.systemui.statusbar.notification.collection.notifcollection.CommonNotifCollection;
import com.android.systemui.statusbar.notification.collection.provider.HighPriorityProvider;
+import com.android.systemui.statusbar.notification.collection.render.GroupExpansionManager;
+import com.android.systemui.statusbar.notification.collection.render.GroupExpansionManagerImpl;
+import com.android.systemui.statusbar.notification.collection.render.GroupMembershipManager;
+import com.android.systemui.statusbar.notification.collection.render.GroupMembershipManagerImpl;
import com.android.systemui.statusbar.notification.init.NotificationsController;
import com.android.systemui.statusbar.notification.init.NotificationsControllerImpl;
import com.android.systemui.statusbar.notification.init.NotificationsControllerStub;
@@ -67,7 +72,6 @@ import com.android.systemui.statusbar.notification.row.NotificationBlockingHelpe
import com.android.systemui.statusbar.notification.row.NotificationGutsManager;
import com.android.systemui.statusbar.notification.row.OnUserInteractionCallback;
import com.android.systemui.statusbar.notification.row.PriorityOnboardingDialogController;
-import com.android.systemui.statusbar.phone.NotificationGroupManager;
import com.android.systemui.statusbar.phone.StatusBar;
import com.android.systemui.statusbar.policy.HeadsUpManager;
import com.android.systemui.util.leak.LeakDetector;
@@ -91,7 +95,7 @@ public interface NotificationsModule {
@Provides
static NotificationEntryManager provideNotificationEntryManager(
NotificationEntryManagerLogger logger,
- NotificationGroupManager groupManager,
+ NotificationGroupManagerLegacy groupManager,
NotificationRankingManager rankingManager,
NotificationEntryManager.KeyguardEnvironment keyguardEnvironment,
FeatureFlags featureFlags,
@@ -127,7 +131,7 @@ public interface NotificationsModule {
LauncherApps launcherApps,
ShortcutManager shortcutManager,
ChannelEditorDialogController channelEditorDialogController,
- CurrentUserContextTracker contextTracker,
+ UserContextProvider contextTracker,
Provider<PriorityOnboardingDialogController.Builder> builderProvider,
AssistantFeedbackController assistantFeedbackController,
BubbleController bubbleController,
@@ -206,6 +210,29 @@ public interface NotificationsModule {
context, notificationGutsManager, notificationEntryManager, metricsLogger);
}
+ /** Provides an instance of {@link GroupMembershipManager} */
+ @SysUISingleton
+ @Provides
+ static GroupMembershipManager provideGroupMembershipManager(
+ FeatureFlags featureFlags,
+ Lazy<NotificationGroupManagerLegacy> groupManagerLegacy) {
+ return featureFlags.isNewNotifPipelineRenderingEnabled()
+ ? new GroupMembershipManagerImpl()
+ : groupManagerLegacy.get();
+ }
+
+ /** Provides an instance of {@link GroupExpansionManager} */
+ @SysUISingleton
+ @Provides
+ static GroupExpansionManager provideGroupExpansionManager(
+ FeatureFlags featureFlags,
+ Lazy<GroupMembershipManager> groupMembershipManager,
+ Lazy<NotificationGroupManagerLegacy> groupManagerLegacy) {
+ return featureFlags.isNewNotifPipelineRenderingEnabled()
+ ? new GroupExpansionManagerImpl(groupMembershipManager.get())
+ : groupManagerLegacy.get();
+ }
+
/** Initializes the notification data pipeline (can be disabled via config). */
@SysUISingleton
@Provides
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/init/NotificationsControllerImpl.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/init/NotificationsControllerImpl.kt
index 6460892952e7..9fb292878553 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/init/NotificationsControllerImpl.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/init/NotificationsControllerImpl.kt
@@ -30,12 +30,12 @@ import com.android.systemui.statusbar.notification.collection.NotifPipeline
import com.android.systemui.statusbar.notification.collection.TargetSdkResolver
import com.android.systemui.statusbar.notification.collection.inflation.NotificationRowBinderImpl
import com.android.systemui.statusbar.notification.collection.init.NotifPipelineInitializer
+import com.android.systemui.statusbar.notification.collection.legacy.NotificationGroupManagerLegacy
import com.android.systemui.statusbar.notification.interruption.HeadsUpController
import com.android.systemui.statusbar.notification.interruption.HeadsUpViewBinder
import com.android.systemui.statusbar.notification.row.NotifBindPipelineInitializer
import com.android.systemui.statusbar.notification.stack.NotificationListContainer
import com.android.systemui.statusbar.phone.NotificationGroupAlertTransferHelper
-import com.android.systemui.statusbar.phone.NotificationGroupManager
import com.android.systemui.statusbar.phone.StatusBar
import com.android.systemui.statusbar.policy.DeviceProvisionedController
import com.android.systemui.statusbar.policy.HeadsUpManager
@@ -65,7 +65,7 @@ class NotificationsControllerImpl @Inject constructor(
private val deviceProvisionedController: DeviceProvisionedController,
private val notificationRowBinder: NotificationRowBinderImpl,
private val remoteInputUriController: RemoteInputUriController,
- private val groupManager: NotificationGroupManager,
+ private val groupManagerLegacy: Lazy<NotificationGroupManagerLegacy>,
private val groupAlertTransferHelper: NotificationGroupAlertTransferHelper,
private val headsUpManager: HeadsUpManager,
private val headsUpController: HeadsUpController,
@@ -111,11 +111,11 @@ class NotificationsControllerImpl @Inject constructor(
} else {
targetSdkResolver.initialize(entryManager)
remoteInputUriController.attach(entryManager)
- groupAlertTransferHelper.bind(entryManager, groupManager)
- headsUpManager.addListener(groupManager)
+ groupAlertTransferHelper.bind(entryManager, groupManagerLegacy.get())
+ headsUpManager.addListener(groupManagerLegacy.get())
headsUpManager.addListener(groupAlertTransferHelper)
headsUpController.attach(entryManager, headsUpManager)
- groupManager.setHeadsUpManager(headsUpManager)
+ groupManagerLegacy.get().setHeadsUpManager(headsUpManager)
groupAlertTransferHelper.setHeadsUpManager(headsUpManager)
entryManager.attach(notificationListener)
@@ -131,7 +131,6 @@ class NotificationsControllerImpl @Inject constructor(
if (dumpTruck) {
entryManager.dump(pw, " ")
}
- groupManager.dump(fd, pw, args)
}
// TODO: Convert all functions below this line into listeners instead of public methods
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/people/PeopleHubNotificationListener.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/people/PeopleHubNotificationListener.kt
index 743bf332fc9d..99b2fcc9d610 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/people/PeopleHubNotificationListener.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/people/PeopleHubNotificationListener.kt
@@ -214,7 +214,7 @@ class PeopleHubDataSourceImpl @Inject constructor(
}
private fun NotificationEntry.extractPerson(): PersonModel? {
- val type = peopleNotificationIdentifier.getPeopleNotificationType(sbn, ranking)
+ val type = peopleNotificationIdentifier.getPeopleNotificationType(this)
if (type == TYPE_NON_PERSON) {
return null
}
@@ -249,7 +249,7 @@ class PeopleHubDataSourceImpl @Inject constructor(
private fun NotificationEntry.extractPersonKey(): PersonKey? {
// TODO migrate to shortcut id when snoozing is conversation wide
- val type = peopleNotificationIdentifier.getPeopleNotificationType(sbn, ranking)
+ val type = peopleNotificationIdentifier.getPeopleNotificationType(this)
return if (type != TYPE_NON_PERSON) key else null
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/people/PeopleNotificationIdentifier.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/people/PeopleNotificationIdentifier.kt
index 1ac2cb5a36d5..0d92616767f3 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/people/PeopleNotificationIdentifier.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/people/PeopleNotificationIdentifier.kt
@@ -20,12 +20,13 @@ import android.annotation.IntDef
import android.service.notification.NotificationListenerService.Ranking
import android.service.notification.StatusBarNotification
import com.android.systemui.dagger.SysUISingleton
+import com.android.systemui.statusbar.notification.collection.NotificationEntry
+import com.android.systemui.statusbar.notification.collection.render.GroupMembershipManager
import com.android.systemui.statusbar.notification.people.PeopleNotificationIdentifier.Companion.PeopleNotificationType
import com.android.systemui.statusbar.notification.people.PeopleNotificationIdentifier.Companion.TYPE_FULL_PERSON
import com.android.systemui.statusbar.notification.people.PeopleNotificationIdentifier.Companion.TYPE_IMPORTANT_PERSON
import com.android.systemui.statusbar.notification.people.PeopleNotificationIdentifier.Companion.TYPE_NON_PERSON
import com.android.systemui.statusbar.notification.people.PeopleNotificationIdentifier.Companion.TYPE_PERSON
-import com.android.systemui.statusbar.phone.NotificationGroupManager
import javax.inject.Inject
import kotlin.math.max
@@ -40,10 +41,12 @@ interface PeopleNotificationIdentifier {
* that users shortcuts.
*/
@PeopleNotificationType
- fun getPeopleNotificationType(sbn: StatusBarNotification, ranking: Ranking): Int
+ fun getPeopleNotificationType(entry: NotificationEntry): Int
- fun compareTo(@PeopleNotificationType a: Int,
- @PeopleNotificationType b: Int): Int
+ fun compareTo(
+ @PeopleNotificationType a: Int,
+ @PeopleNotificationType b: Int
+ ): Int
companion object {
@@ -62,24 +65,27 @@ interface PeopleNotificationIdentifier {
@SysUISingleton
class PeopleNotificationIdentifierImpl @Inject constructor(
private val personExtractor: NotificationPersonExtractor,
- private val groupManager: NotificationGroupManager
+ private val groupManager: GroupMembershipManager
) : PeopleNotificationIdentifier {
@PeopleNotificationType
- override fun getPeopleNotificationType(sbn: StatusBarNotification, ranking: Ranking): Int =
- when (val type = ranking.personTypeInfo) {
+ override fun getPeopleNotificationType(entry: NotificationEntry): Int =
+ when (val type = entry.ranking.personTypeInfo) {
TYPE_IMPORTANT_PERSON -> TYPE_IMPORTANT_PERSON
else -> {
- when (val type = upperBound(type, extractPersonTypeInfo(sbn))) {
+ when (val type = upperBound(type, extractPersonTypeInfo(entry.sbn))) {
TYPE_IMPORTANT_PERSON -> TYPE_IMPORTANT_PERSON
- else -> upperBound(type, getPeopleTypeOfSummary(sbn))
+ else -> upperBound(type, getPeopleTypeOfSummary(entry))
}
}
}
- override fun compareTo(@PeopleNotificationType a: Int,
- @PeopleNotificationType b: Int): Int {
- return b.compareTo(a);
+ override fun compareTo(
+ @PeopleNotificationType a: Int,
+ @PeopleNotificationType b: Int
+ ): Int
+ {
+ return b.compareTo(a)
}
/**
@@ -105,14 +111,14 @@ class PeopleNotificationIdentifierImpl @Inject constructor(
private fun extractPersonTypeInfo(sbn: StatusBarNotification) =
if (personExtractor.isPersonNotification(sbn)) TYPE_PERSON else TYPE_NON_PERSON
- private fun getPeopleTypeOfSummary(statusBarNotification: StatusBarNotification): Int {
- if (!groupManager.isSummaryOfGroup(statusBarNotification)) {
+ private fun getPeopleTypeOfSummary(entry: NotificationEntry): Int {
+ if (!groupManager.isGroupSummary(entry)) {
return TYPE_NON_PERSON
}
- val childTypes = groupManager.getChildren(statusBarNotification)
+ val childTypes = groupManager.getChildren(entry)
?.asSequence()
- ?.map { getPeopleNotificationType(it.sbn, it.ranking) }
+ ?.map { getPeopleNotificationType(it) }
?: return TYPE_NON_PERSON
var groupType = TYPE_NON_PERSON
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ExpandableNotificationRow.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ExpandableNotificationRow.java
index 9c09cba5e137..89f720535402 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ExpandableNotificationRow.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ExpandableNotificationRow.java
@@ -86,6 +86,8 @@ import com.android.systemui.statusbar.notification.ActivityLaunchAnimator;
import com.android.systemui.statusbar.notification.NotificationUtils;
import com.android.systemui.statusbar.notification.collection.NotificationEntry;
import com.android.systemui.statusbar.notification.collection.legacy.VisualStabilityManager;
+import com.android.systemui.statusbar.notification.collection.render.GroupExpansionManager;
+import com.android.systemui.statusbar.notification.collection.render.GroupMembershipManager;
import com.android.systemui.statusbar.notification.logging.NotificationCounters;
import com.android.systemui.statusbar.notification.people.PeopleNotificationIdentifier;
import com.android.systemui.statusbar.notification.row.NotificationRowContentBinder.InflationFlag;
@@ -97,7 +99,6 @@ import com.android.systemui.statusbar.notification.stack.NotificationChildrenCon
import com.android.systemui.statusbar.notification.stack.NotificationStackScrollLayout;
import com.android.systemui.statusbar.notification.stack.SwipeableView;
import com.android.systemui.statusbar.phone.KeyguardBypassController;
-import com.android.systemui.statusbar.phone.NotificationGroupManager;
import com.android.systemui.statusbar.phone.StatusBar;
import com.android.systemui.statusbar.policy.HeadsUpManager;
import com.android.systemui.statusbar.policy.InflatedSmartReplies.SmartRepliesAndActions;
@@ -141,7 +142,7 @@ public class ExpandableNotificationRow extends ActivatableNotificationView
void onExpansionChanged(boolean isExpanded);
}
- private StatusBarStateController mStatusbarStateController;
+ private StatusBarStateController mStatusBarStateController;
private KeyguardBypassController mBypassController;
private LayoutListener mLayoutListener;
private RowContentBindStage mRowContentBindStage;
@@ -220,7 +221,8 @@ public class ExpandableNotificationRow extends ActivatableNotificationView
private boolean mNeedsRedaction;
private boolean mLastChronometerRunning = true;
private ViewStub mChildrenContainerStub;
- private NotificationGroupManager mGroupManager;
+ private GroupMembershipManager mGroupMembershipManager;
+ private GroupExpansionManager mGroupExpansionManager;
private boolean mChildrenExpanded;
private boolean mIsSummaryWithChildren;
private NotificationChildrenContainer mChildrenContainer;
@@ -269,10 +271,10 @@ public class ExpandableNotificationRow extends ActivatableNotificationView
@Override
public void onClick(View v) {
if (!shouldShowPublic() && (!mIsLowPriority || isExpanded())
- && mGroupManager.isSummaryOfGroup(mEntry.getSbn())) {
+ && mGroupMembershipManager.isGroupSummary(mEntry)) {
mGroupExpansionChanging = true;
- final boolean wasExpanded = mGroupManager.isGroupExpanded(mEntry.getSbn());
- boolean nowExpanded = mGroupManager.toggleGroupExpansion(mEntry.getSbn());
+ final boolean wasExpanded = mGroupExpansionManager.isGroupExpanded(mEntry);
+ boolean nowExpanded = mGroupExpansionManager.toggleGroupExpansion(mEntry);
mOnExpandClickListener.onExpandClicked(mEntry, nowExpanded);
MetricsLogger.action(mContext, MetricsEvent.ACTION_NOTIFICATION_GROUP_EXPANDER,
nowExpanded);
@@ -463,16 +465,6 @@ public class ExpandableNotificationRow extends ActivatableNotificationView
}
/**
- * Set the entry for the row.
- *
- * @param entry the entry this row is tied to
- */
- public void setEntry(@NonNull NotificationEntry entry) {
- mEntry = entry;
- cacheIsSystemNotification();
- }
-
- /**
* Marks a content view as freeable, setting it so that future inflations do not reinflate
* and ensuring that the view is freed when it is safe to remove.
*
@@ -537,8 +529,7 @@ public class ExpandableNotificationRow extends ActivatableNotificationView
}
private boolean isConversation() {
- return mPeopleNotificationIdentifier
- .getPeopleNotificationType(mEntry.getSbn(), mEntry.getRanking())
+ return mPeopleNotificationIdentifier.getPeopleNotificationType(mEntry)
!= PeopleNotificationIdentifier.TYPE_NON_PERSON;
}
@@ -830,7 +821,7 @@ public class ExpandableNotificationRow extends ActivatableNotificationView
* @return whether this notification is the only child in the group summary
*/
public boolean isOnlyChildInGroup() {
- return mGroupManager.isOnlyChildInGroup(mEntry.getSbn());
+ return mGroupMembershipManager.isOnlyChildInGroup(mEntry);
}
public ExpandableNotificationRow getNotificationParent() {
@@ -1435,8 +1426,7 @@ public class ExpandableNotificationRow extends ActivatableNotificationView
public void performDismiss(boolean fromAccessibility) {
if (isOnlyChildInGroup()) {
- NotificationEntry groupSummary =
- mGroupManager.getLogicalGroupSummary(mEntry.getSbn());
+ NotificationEntry groupSummary = mGroupMembershipManager.getLogicalGroupSummary(mEntry);
if (groupSummary.isClearable()) {
// If this is the only child in the group, dismiss the group, but don't try to show
// the blocking helper affordance!
@@ -1584,11 +1574,13 @@ public class ExpandableNotificationRow extends ActivatableNotificationView
* Initialize row.
*/
public void initialize(
+ NotificationEntry entry,
String appName,
String notificationKey,
ExpansionLogger logger,
KeyguardBypassController bypassController,
- NotificationGroupManager groupManager,
+ GroupMembershipManager groupMembershipManager,
+ GroupExpansionManager groupExpansionManager,
HeadsUpManager headsUpManager,
RowContentBindStage rowContentBindStage,
OnExpandClickListener onExpandClickListener,
@@ -1598,6 +1590,7 @@ public class ExpandableNotificationRow extends ActivatableNotificationView
StatusBarStateController statusBarStateController,
PeopleNotificationIdentifier peopleNotificationIdentifier,
OnUserInteractionCallback onUserInteractionCallback) {
+ mEntry = entry;
mAppName = appName;
if (mMenuRow == null) {
mMenuRow = new NotificationMenuRow(mContext, peopleNotificationIdentifier);
@@ -1608,20 +1601,24 @@ public class ExpandableNotificationRow extends ActivatableNotificationView
mLogger = logger;
mLoggingKey = notificationKey;
mBypassController = bypassController;
- mGroupManager = groupManager;
- mPrivateLayout.setGroupManager(groupManager);
+ mGroupMembershipManager = groupMembershipManager;
+ mGroupExpansionManager = groupExpansionManager;
+ mPrivateLayout.setGroupMembershipManager(groupMembershipManager);
mHeadsUpManager = headsUpManager;
mRowContentBindStage = rowContentBindStage;
mOnExpandClickListener = onExpandClickListener;
mMediaManager = notificationMediaManager;
setOnFeedbackClickListener(onFeedbackClickListener);
mFalsingManager = falsingManager;
- mStatusbarStateController = statusBarStateController;
+ mStatusBarStateController = statusBarStateController;
+
mPeopleNotificationIdentifier = peopleNotificationIdentifier;
for (NotificationContentView l : mLayouts) {
l.setPeopleNotificationIdentifier(mPeopleNotificationIdentifier);
}
mOnUserInteractionCallback = onUserInteractionCallback;
+
+ cacheIsSystemNotification();
}
private void initDimens() {
@@ -2134,8 +2131,8 @@ public class ExpandableNotificationRow extends ActivatableNotificationView
*/
@Override
public boolean isSoundEffectsEnabled() {
- final boolean mute = mStatusbarStateController != null
- && mStatusbarStateController.isDozing()
+ final boolean mute = mStatusBarStateController != null
+ && mStatusBarStateController.isDozing()
&& mSecureStateProvider != null &&
!mSecureStateProvider.getAsBoolean();
return !mute && super.isSoundEffectsEnabled();
@@ -2189,8 +2186,8 @@ public class ExpandableNotificationRow extends ActivatableNotificationView
mFalsingManager.setNotificationExpanded();
if (mIsSummaryWithChildren && !shouldShowPublic() && allowChildExpansion
&& !mChildrenContainer.showingAsLowPriority()) {
- final boolean wasExpanded = mGroupManager.isGroupExpanded(mEntry.getSbn());
- mGroupManager.setGroupExpanded(mEntry.getSbn(), userExpanded);
+ final boolean wasExpanded = mGroupExpansionManager.isGroupExpanded(mEntry);
+ mGroupExpansionManager.setGroupExpanded(mEntry, userExpanded);
onExpansionChanged(true /* userAction */, wasExpanded);
return;
}
@@ -2259,10 +2256,7 @@ public class ExpandableNotificationRow extends ActivatableNotificationView
}
}
- /**
- * @param onKeyguard whether to prevent notification expansion
- */
- public void setOnKeyguard(boolean onKeyguard) {
+ void setOnKeyguard(boolean onKeyguard) {
if (onKeyguard != mOnKeyguard) {
boolean wasAboveShelf = isAboveShelf();
final boolean wasExpanded = isExpanded();
@@ -2331,12 +2325,12 @@ public class ExpandableNotificationRow extends ActivatableNotificationView
}
private boolean isDozing() {
- return mStatusbarStateController != null && mStatusbarStateController.isDozing();
+ return mStatusBarStateController != null && mStatusBarStateController.isDozing();
}
@Override
public boolean isGroupExpanded() {
- return mGroupManager.isGroupExpanded(mEntry.getSbn());
+ return mGroupExpansionManager.isGroupExpanded(mEntry);
}
private void onAttachedChildrenCountChanged() {
@@ -2582,7 +2576,7 @@ public class ExpandableNotificationRow extends ActivatableNotificationView
public void makeActionsVisibile() {
setUserExpanded(true, true);
if (isChildInGroup()) {
- mGroupManager.setGroupExpanded(mEntry.getSbn(), true);
+ mGroupExpansionManager.setGroupExpanded(mEntry, true);
}
notifyHeightChanged(false /* needsAnimation */);
}
@@ -2875,7 +2869,7 @@ public class ExpandableNotificationRow extends ActivatableNotificationView
public void onExpandedByGesture(boolean userExpanded) {
int event = MetricsEvent.ACTION_NOTIFICATION_GESTURE_EXPANDER;
- if (mGroupManager.isSummaryOfGroup(mEntry.getSbn())) {
+ if (mGroupMembershipManager.isGroupSummary(mEntry)) {
event = MetricsEvent.ACTION_NOTIFICATION_GROUP_GESTURE_EXPANDER;
}
MetricsLogger.action(mContext, event, userExpanded);
@@ -2920,7 +2914,7 @@ public class ExpandableNotificationRow extends ActivatableNotificationView
private void onExpansionChanged(boolean userAction, boolean wasExpanded) {
boolean nowExpanded = isExpanded();
if (mIsSummaryWithChildren && (!mIsLowPriority || wasExpanded)) {
- nowExpanded = mGroupManager.isGroupExpanded(mEntry.getSbn());
+ nowExpanded = mGroupExpansionManager.isGroupExpanded(mEntry);
}
if (nowExpanded != wasExpanded) {
updateShelfIconColor();
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ExpandableNotificationRowController.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ExpandableNotificationRowController.java
index f8bc2bebf93b..1d72557c6a89 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ExpandableNotificationRowController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ExpandableNotificationRowController.java
@@ -18,6 +18,7 @@ package com.android.systemui.statusbar.notification.row;
import static com.android.systemui.Dependency.ALLOW_NOTIFICATION_LONG_PRESS_NAME;
import static com.android.systemui.statusbar.NotificationRemoteInputManager.ENABLE_REMOTE_INPUT;
+import static com.android.systemui.statusbar.StatusBarState.KEYGUARD;
import android.view.View;
import android.view.ViewGroup;
@@ -29,6 +30,9 @@ import com.android.systemui.plugins.statusbar.NotificationMenuRowPlugin;
import com.android.systemui.plugins.statusbar.StatusBarStateController;
import com.android.systemui.shared.plugins.PluginManager;
import com.android.systemui.statusbar.NotificationMediaManager;
+import com.android.systemui.statusbar.notification.collection.NotificationEntry;
+import com.android.systemui.statusbar.notification.collection.render.GroupExpansionManager;
+import com.android.systemui.statusbar.notification.collection.render.GroupMembershipManager;
import com.android.systemui.statusbar.notification.collection.render.NodeController;
import com.android.systemui.statusbar.notification.logging.NotificationLogger;
import com.android.systemui.statusbar.notification.people.PeopleNotificationIdentifier;
@@ -37,7 +41,6 @@ import com.android.systemui.statusbar.notification.row.dagger.NotificationKey;
import com.android.systemui.statusbar.notification.row.dagger.NotificationRowScope;
import com.android.systemui.statusbar.notification.stack.NotificationListContainer;
import com.android.systemui.statusbar.phone.KeyguardBypassController;
-import com.android.systemui.statusbar.phone.NotificationGroupManager;
import com.android.systemui.statusbar.policy.HeadsUpManager;
import com.android.systemui.util.time.SystemClock;
@@ -60,7 +63,8 @@ public class ExpandableNotificationRowController implements NodeController {
private final String mAppName;
private final String mNotificationKey;
private final KeyguardBypassController mKeyguardBypassController;
- private final NotificationGroupManager mNotificationGroupManager;
+ private final GroupMembershipManager mGroupMembershipManager;
+ private final GroupExpansionManager mGroupExpansionManager;
private final RowContentBindStage mRowContentBindStage;
private final NotificationLogger mNotificationLogger;
private final HeadsUpManager mHeadsUpManager;
@@ -83,7 +87,8 @@ public class ExpandableNotificationRowController implements NodeController {
NotificationMediaManager mediaManager, PluginManager pluginManager,
SystemClock clock, @AppName String appName, @NotificationKey String notificationKey,
KeyguardBypassController keyguardBypassController,
- NotificationGroupManager notificationGroupManager,
+ GroupMembershipManager groupMembershipManager,
+ GroupExpansionManager groupExpansionManager,
RowContentBindStage rowContentBindStage,
NotificationLogger notificationLogger, HeadsUpManager headsUpManager,
ExpandableNotificationRow.OnExpandClickListener onExpandClickListener,
@@ -101,7 +106,8 @@ public class ExpandableNotificationRowController implements NodeController {
mAppName = appName;
mNotificationKey = notificationKey;
mKeyguardBypassController = keyguardBypassController;
- mNotificationGroupManager = notificationGroupManager;
+ mGroupMembershipManager = groupMembershipManager;
+ mGroupExpansionManager = groupExpansionManager;
mRowContentBindStage = rowContentBindStage;
mNotificationLogger = notificationLogger;
mHeadsUpManager = headsUpManager;
@@ -118,14 +124,16 @@ public class ExpandableNotificationRowController implements NodeController {
/**
* Initialize the controller.
*/
- public void init() {
+ public void init(NotificationEntry entry) {
mActivatableNotificationViewController.init();
mView.initialize(
+ entry,
mAppName,
mNotificationKey,
mExpansionLogger,
mKeyguardBypassController,
- mNotificationGroupManager,
+ mGroupMembershipManager,
+ mGroupExpansionManager,
mHeadsUpManager,
mRowContentBindStage,
mOnExpandClickListener,
@@ -135,6 +143,7 @@ public class ExpandableNotificationRowController implements NodeController {
mStatusBarStateController,
mPeopleNotificationIdentifier,
mOnUserInteractionCallback
+
);
mView.setDescendantFocusability(ViewGroup.FOCUS_BLOCK_DESCENDANTS);
if (mAllowLongPress) {
@@ -156,15 +165,26 @@ public class ExpandableNotificationRowController implements NodeController {
mView.getEntry().setInitializationTime(mClock.elapsedRealtime());
mPluginManager.addPluginListener(mView,
NotificationMenuRowPlugin.class, false /* Allow multiple */);
+ mView.setOnKeyguard(mStatusBarStateController.getState() == KEYGUARD);
+ mStatusBarStateController.addCallback(mStatusBarStateListener);
}
@Override
public void onViewDetachedFromWindow(View v) {
mPluginManager.removePluginListener(mView);
+ mStatusBarStateController.removeCallback(mStatusBarStateListener);
}
});
}
+ private final StatusBarStateController.StateListener mStatusBarStateListener =
+ new StatusBarStateController.StateListener() {
+ @Override
+ public void onStateChanged(int newState) {
+ mView.setOnKeyguard(newState == KEYGUARD);
+ }
+ };
+
private void logNotificationExpansion(String key, boolean userAction, boolean expanded) {
mNotificationLogger.onExpansionChanged(key, userAction, expanded);
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationContentView.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationContentView.java
index c7e44c5e8e0a..1de9308a40b1 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationContentView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationContentView.java
@@ -28,9 +28,7 @@ import android.graphics.Rect;
import android.graphics.drawable.Drawable;
import android.os.Build;
import android.provider.Settings;
-import android.service.notification.StatusBarNotification;
import android.util.ArrayMap;
-import android.util.ArraySet;
import android.util.AttributeSet;
import android.util.Log;
import android.view.MotionEvent;
@@ -52,11 +50,10 @@ import com.android.systemui.statusbar.SmartReplyController;
import com.android.systemui.statusbar.TransformableView;
import com.android.systemui.statusbar.notification.NotificationUtils;
import com.android.systemui.statusbar.notification.collection.NotificationEntry;
+import com.android.systemui.statusbar.notification.collection.render.GroupMembershipManager;
import com.android.systemui.statusbar.notification.people.PeopleNotificationIdentifier;
import com.android.systemui.statusbar.notification.row.wrapper.NotificationCustomViewWrapper;
-import com.android.systemui.statusbar.notification.row.wrapper.NotificationTemplateViewWrapper;
import com.android.systemui.statusbar.notification.row.wrapper.NotificationViewWrapper;
-import com.android.systemui.statusbar.phone.NotificationGroupManager;
import com.android.systemui.statusbar.policy.InflatedSmartReplies;
import com.android.systemui.statusbar.policy.InflatedSmartReplies.SmartRepliesAndActions;
import com.android.systemui.statusbar.policy.RemoteInputView;
@@ -122,8 +119,8 @@ public class NotificationContentView extends FrameLayout {
private int mSmallHeight;
private int mHeadsUpHeight;
private int mNotificationMaxHeight;
- private StatusBarNotification mStatusBarNotification;
- private NotificationGroupManager mGroupManager;
+ private NotificationEntry mNotificationEntry;
+ private GroupMembershipManager mGroupMembershipManager;
private RemoteInputController mRemoteInputController;
private Runnable mExpandedVisibleListener;
private PeopleNotificationIdentifier mPeopleIdentifier;
@@ -778,7 +775,7 @@ public class NotificationContentView extends FrameLayout {
}
private boolean isGroupExpanded() {
- return mGroupManager.isGroupExpanded(mStatusBarNotification);
+ return mContainingNotification.isGroupExpanded();
}
public void setClipTopAmount(int clipTopAmount) {
@@ -908,10 +905,10 @@ public class NotificationContentView extends FrameLayout {
public int getBackgroundColorForExpansionState() {
// When expanding or user locked we want the new type, when collapsing we want
// the original type
- final int visibleType = (mContainingNotification.isGroupExpanded()
- || mContainingNotification.isUserLocked())
- ? calculateVisibleType()
- : getVisibleType();
+ final int visibleType = (
+ isGroupExpanded() || mContainingNotification.isUserLocked())
+ ? calculateVisibleType()
+ : getVisibleType();
return getBackgroundColor(visibleType);
}
@@ -1145,7 +1142,7 @@ public class NotificationContentView extends FrameLayout {
}
public void onNotificationUpdated(NotificationEntry entry) {
- mStatusBarNotification = entry.getSbn();
+ mNotificationEntry = entry;
mBeforeN = entry.targetSdk < Build.VERSION_CODES.N;
updateAllSingleLineViews();
ExpandableNotificationRow row = entry.getRow();
@@ -1176,7 +1173,7 @@ public class NotificationContentView extends FrameLayout {
if (mIsChildInGroup) {
boolean isNewView = mSingleLineView == null;
mSingleLineView = mHybridGroupManager.bindFromNotification(
- mSingleLineView, mContractedChild, mStatusBarNotification, this);
+ mSingleLineView, mContractedChild, mNotificationEntry.getSbn(), this);
if (isNewView) {
updateViewVisibility(mVisibleType, VISIBLE_TYPE_SINGLELINE,
mSingleLineView, mSingleLineView);
@@ -1363,7 +1360,7 @@ public class NotificationContentView extends FrameLayout {
return;
}
boolean isPersonWithShortcut =
- mPeopleIdentifier.getPeopleNotificationType(entry.getSbn(), entry.getRanking())
+ mPeopleIdentifier.getPeopleNotificationType(entry)
>= PeopleNotificationIdentifier.TYPE_FULL_PERSON;
boolean showButton = isBubblesEnabled()
&& isPersonWithShortcut
@@ -1516,8 +1513,8 @@ public class NotificationContentView extends FrameLayout {
}
}
- public void setGroupManager(NotificationGroupManager groupManager) {
- mGroupManager = groupManager;
+ public void setGroupMembershipManager(GroupMembershipManager groupMembershipManager) {
+ mGroupMembershipManager = groupMembershipManager;
}
public void setRemoteInputController(RemoteInputController r) {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationGutsManager.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationGutsManager.java
index 60074f608969..7d418f30e4c5 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationGutsManager.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationGutsManager.java
@@ -52,7 +52,7 @@ import com.android.systemui.dagger.qualifiers.Background;
import com.android.systemui.dagger.qualifiers.Main;
import com.android.systemui.plugins.statusbar.NotificationMenuRowPlugin;
import com.android.systemui.plugins.statusbar.StatusBarStateController;
-import com.android.systemui.settings.CurrentUserContextTracker;
+import com.android.systemui.settings.UserContextProvider;
import com.android.systemui.statusbar.NotificationLifetimeExtender;
import com.android.systemui.statusbar.NotificationLockscreenUserManager;
import com.android.systemui.statusbar.NotificationPresenter;
@@ -121,7 +121,7 @@ public class NotificationGutsManager implements Dumpable, NotificationLifetimeEx
private final INotificationManager mNotificationManager;
private final LauncherApps mLauncherApps;
private final ShortcutManager mShortcutManager;
- private final CurrentUserContextTracker mContextTracker;
+ private final UserContextProvider mContextTracker;
private final Provider<PriorityOnboardingDialogController.Builder> mBuilderProvider;
private final UiEventLogger mUiEventLogger;
@@ -138,7 +138,7 @@ public class NotificationGutsManager implements Dumpable, NotificationLifetimeEx
LauncherApps launcherApps,
ShortcutManager shortcutManager,
ChannelEditorDialogController channelEditorDialogController,
- CurrentUserContextTracker contextTracker,
+ UserContextProvider contextTracker,
Provider<PriorityOnboardingDialogController.Builder> builderProvider,
AssistantFeedbackController assistantFeedbackController,
BubbleController bubbleController,
@@ -484,7 +484,7 @@ public class NotificationGutsManager implements Dumpable, NotificationLifetimeEx
onSettingsClick,
onSnoozeClickListener,
iconFactoryLoader,
- mContextTracker.getCurrentUserContext(),
+ mContextTracker.getUserContext(),
mBuilderProvider,
mDeviceProvisionedController.isDeviceProvisioned(),
mMainHandler,
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationMenuRow.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationMenuRow.java
index 205cecc92e55..65a72cc0b76b 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationMenuRow.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationMenuRow.java
@@ -24,7 +24,6 @@ import android.animation.Animator;
import android.animation.AnimatorListenerAdapter;
import android.animation.ValueAnimator;
import android.annotation.Nullable;
-import android.app.Notification;
import android.content.Context;
import android.content.res.Resources;
import android.graphics.Point;
@@ -260,8 +259,7 @@ public class NotificationMenuRow implements NotificationMenuRowPlugin, View.OnCl
}
mFeedbackItem = createFeedbackItem(mContext);
NotificationEntry entry = mParent.getEntry();
- int personNotifType = mPeopleNotificationIdentifier
- .getPeopleNotificationType(entry.getSbn(), entry.getRanking());
+ int personNotifType = mPeopleNotificationIdentifier.getPeopleNotificationType(entry);
if (personNotifType == PeopleNotificationIdentifier.TYPE_PERSON) {
mInfoItem = createPartialConversationItem(mContext);
} else if (personNotifType >= PeopleNotificationIdentifier.TYPE_FULL_PERSON) {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/AmbientState.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/AmbientState.java
index 11e698b03823..0302b2b450e2 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/AmbientState.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/AmbientState.java
@@ -42,7 +42,7 @@ public class AmbientState {
private static final float MAX_PULSE_HEIGHT = 100000f;
private final SectionProvider mSectionProvider;
- private ArrayList<ExpandableView> mDraggedViews = new ArrayList<>();
+ private ArrayList<View> mDraggedViews = new ArrayList<>();
private int mScrollY;
private int mAnchorViewIndex;
private int mAnchorViewY;
@@ -81,17 +81,17 @@ public class AmbientState {
private boolean mAppearing;
private float mPulseHeight = MAX_PULSE_HEIGHT;
private float mDozeAmount = 0.0f;
- private HeadsUpManager mHeadUpManager;
private Runnable mOnPulseHeightChangedListener;
private ExpandableNotificationRow mTrackedHeadsUpRow;
private float mAppearFraction;
+ /** Tracks the state from AlertingNotificationManager#hasNotifications() */
+ private boolean mHasAlertEntries;
+
public AmbientState(
Context context,
- @NonNull SectionProvider sectionProvider,
- HeadsUpManager headsUpManager) {
+ @NonNull SectionProvider sectionProvider) {
mSectionProvider = sectionProvider;
- mHeadUpManager = headsUpManager;
reload(context);
}
@@ -164,7 +164,7 @@ public class AmbientState {
}
/** Call when dragging begins. */
- public void onBeginDrag(ExpandableView view) {
+ public void onBeginDrag(View view) {
mDraggedViews.add(view);
}
@@ -172,7 +172,7 @@ public class AmbientState {
mDraggedViews.remove(view);
}
- public ArrayList<ExpandableView> getDraggedViews() {
+ public ArrayList<View> getDraggedViews() {
return mDraggedViews;
}
@@ -393,7 +393,7 @@ public class AmbientState {
}
public boolean hasPulsingNotifications() {
- return mPulsing && mHeadUpManager != null && mHeadUpManager.hasNotifications();
+ return mPulsing && mHasAlertEntries;
}
public void setPulsing(boolean hasPulsing) {
@@ -408,10 +408,7 @@ public class AmbientState {
}
public boolean isPulsing(NotificationEntry entry) {
- if (!mPulsing || mHeadUpManager == null) {
- return false;
- }
- return mHeadUpManager.isAlerting(entry.getKey());
+ return mPulsing && entry.isAlerting();
}
public boolean isPanelTracking() {
@@ -568,4 +565,8 @@ public class AmbientState {
public float getAppearFraction() {
return mAppearFraction;
}
+
+ public void setHasAlertEntries(boolean hasAlertEntries) {
+ mHasAlertEntries = hasAlertEntries;
+ }
}
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 e061472b3939..c24d3fcadbf9 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
@@ -44,7 +44,6 @@ import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Outline;
import android.graphics.Paint;
-import android.graphics.Point;
import android.graphics.PointF;
import android.graphics.PorterDuff;
import android.graphics.PorterDuffXfermode;
@@ -54,7 +53,6 @@ import android.os.ServiceManager;
import android.os.UserHandle;
import android.provider.Settings;
import android.service.notification.NotificationListenerService;
-import android.service.notification.StatusBarNotification;
import android.util.AttributeSet;
import android.util.DisplayMetrics;
import android.util.Log;
@@ -94,11 +92,6 @@ import com.android.systemui.Dumpable;
import com.android.systemui.ExpandHelper;
import com.android.systemui.Interpolators;
import com.android.systemui.R;
-import com.android.systemui.SwipeHelper;
-import com.android.systemui.plugins.FalsingManager;
-import com.android.systemui.plugins.statusbar.NotificationMenuRowPlugin;
-import com.android.systemui.plugins.statusbar.NotificationMenuRowPlugin.MenuItem;
-import com.android.systemui.plugins.statusbar.NotificationMenuRowPlugin.OnMenuEventListener;
import com.android.systemui.plugins.statusbar.NotificationSwipeActionHelper;
import com.android.systemui.statusbar.CommandQueue;
import com.android.systemui.statusbar.DragDownHelper.DragDownCallback;
@@ -107,7 +100,6 @@ import com.android.systemui.statusbar.FeatureFlags;
import com.android.systemui.statusbar.NotificationRemoteInputManager;
import com.android.systemui.statusbar.NotificationShelf;
import com.android.systemui.statusbar.NotificationShelfController;
-import com.android.systemui.statusbar.RemoteInputController;
import com.android.systemui.statusbar.StatusBarState;
import com.android.systemui.statusbar.SysuiStatusBarStateController;
import com.android.systemui.statusbar.notification.DynamicPrivacyController;
@@ -125,6 +117,8 @@ import com.android.systemui.statusbar.notification.collection.NotificationEntry;
import com.android.systemui.statusbar.notification.collection.legacy.VisualStabilityManager;
import com.android.systemui.statusbar.notification.collection.notifcollection.DismissedByUserStats;
import com.android.systemui.statusbar.notification.collection.notifcollection.NotifCollectionListener;
+import com.android.systemui.statusbar.notification.collection.render.GroupExpansionManager;
+import com.android.systemui.statusbar.notification.collection.render.GroupMembershipManager;
import com.android.systemui.statusbar.notification.logging.NotificationLogger;
import com.android.systemui.statusbar.notification.row.ActivatableNotificationView;
import com.android.systemui.statusbar.notification.row.ExpandableNotificationRow;
@@ -132,19 +126,12 @@ import com.android.systemui.statusbar.notification.row.ExpandableView;
import com.android.systemui.statusbar.notification.row.FooterView;
import com.android.systemui.statusbar.notification.row.ForegroundServiceDungeonView;
import com.android.systemui.statusbar.notification.row.NotificationBlockingHelperManager;
-import com.android.systemui.statusbar.notification.row.NotificationGuts;
-import com.android.systemui.statusbar.notification.row.NotificationGutsManager;
-import com.android.systemui.statusbar.notification.row.NotificationSnooze;
import com.android.systemui.statusbar.notification.row.StackScrollerDecorView;
import com.android.systemui.statusbar.phone.HeadsUpAppearanceController;
-import com.android.systemui.statusbar.phone.HeadsUpManagerPhone;
import com.android.systemui.statusbar.phone.HeadsUpTouchHelper;
import com.android.systemui.statusbar.phone.LockscreenGestureLogger;
import com.android.systemui.statusbar.phone.LockscreenGestureLogger.LockscreenUiEvent;
-import com.android.systemui.statusbar.phone.NotificationGroupManager;
-import com.android.systemui.statusbar.phone.NotificationGroupManager.OnGroupChangeListener;
import com.android.systemui.statusbar.phone.NotificationPanelViewController;
-import com.android.systemui.statusbar.phone.ScrimController;
import com.android.systemui.statusbar.phone.ShadeController;
import com.android.systemui.statusbar.phone.StatusBar;
import com.android.systemui.statusbar.policy.HeadsUpUtil;
@@ -185,13 +172,12 @@ public class NotificationStackScrollLayout extends ViewGroup implements Dumpable
* gap is drawn between them). In this case we don't want to round their corners.
*/
private static final int DISTANCE_BETWEEN_ADJACENT_SECTIONS_PX = 1;
- private OnMenuEventListener mMenuEventListener;
private KeyguardBypassEnabledProvider mKeyguardBypassEnabledProvider;
private final DynamicPrivacyController mDynamicPrivacyController;
private final SysuiStatusBarStateController mStatusbarStateController;
private ExpandHelper mExpandHelper;
- private final NotificationSwipeHelper mSwipeHelper;
+ private NotificationSwipeHelper mSwipeHelper;
private int mCurrentStackHeight = Integer.MAX_VALUE;
private final Paint mBackgroundPaint = new Paint();
private final boolean mShouldDrawNotificationBackground;
@@ -244,10 +230,11 @@ public class NotificationStackScrollLayout extends ViewGroup implements Dumpable
/**
* The algorithm which calculates the properties for our children
*/
- protected final StackScrollAlgorithm mStackScrollAlgorithm;
-
+ private final StackScrollAlgorithm mStackScrollAlgorithm;
private final AmbientState mAmbientState;
- private NotificationGroupManager mGroupManager;
+
+ private GroupMembershipManager mGroupMembershipManager;
+ private GroupExpansionManager mGroupExpansionManager;
private NotificationActivityStarter mNotificationActivityStarter;
private HashSet<ExpandableView> mChildrenToAddAnimated = new HashSet<>();
private ArrayList<View> mAddedHeadsUpChildren = new ArrayList<>();
@@ -346,13 +333,10 @@ public class NotificationStackScrollLayout extends ViewGroup implements Dumpable
private HashSet<ExpandableView> mClearTransientViewsWhenFinished = new HashSet<>();
private HashSet<Pair<ExpandableNotificationRow, Boolean>> mHeadsUpChangeAnimations
= new HashSet<>();
- private HeadsUpManagerPhone mHeadsUpManager;
private final NotificationRoundnessManager mRoundnessManager;
private boolean mTrackingHeadsUp;
- private ScrimController mScrimController;
private boolean mForceNoOverlappingRendering;
private final ArrayList<Pair<ExpandableNotificationRow, Boolean>> mTmpList = new ArrayList<>();
- private FalsingManager mFalsingManager;
private boolean mAnimationRunning;
private ViewTreeObserver.OnPreDrawListener mRunningAnimationUpdater
= new ViewTreeObserver.OnPreDrawListener() {
@@ -432,7 +416,6 @@ public class NotificationStackScrollLayout extends ViewGroup implements Dumpable
};
private PorterDuffXfermode mSrcMode = new PorterDuffXfermode(PorterDuff.Mode.SRC);
private boolean mPulsing;
- private boolean mGroupExpandedForMeasure;
private boolean mScrollable;
private View mForcedScroll;
@@ -505,7 +488,6 @@ public class NotificationStackScrollLayout extends ViewGroup implements Dumpable
private Interpolator mHideXInterpolator = Interpolators.FAST_OUT_SLOW_IN;
private NotificationPanelViewController mNotificationPanelController;
- private final NotificationGutsManager mNotificationGutsManager;
private final NotificationSectionsManager mSectionsManager;
private final ForegroundServiceSectionController mFgsSectionController;
private ForegroundServiceDungeonView mFgsSectionView;
@@ -519,6 +501,9 @@ public class NotificationStackScrollLayout extends ViewGroup implements Dumpable
private NotificationStackScrollLayoutController mController;
private boolean mKeyguardMediaControllorVisible;
+ private NotificationEntry mTopHeadsUpEntry;
+ private long mNumHeadsUp;
+ private NotificationStackScrollLayoutController.TouchHandler mTouchHandler;
private final ExpandableView.OnHeightChangedListener mOnChildHeightChangedListener =
new ExpandableView.OnHeightChangedListener() {
@@ -568,9 +553,6 @@ public class NotificationStackScrollLayout extends ViewGroup implements Dumpable
NotificationRoundnessManager notificationRoundnessManager,
DynamicPrivacyController dynamicPrivacyController,
SysuiStatusBarStateController statusbarStateController,
- HeadsUpManagerPhone headsUpManager,
- FalsingManager falsingManager,
- NotificationGutsManager notificationGutsManager,
NotificationSectionsManager notificationSectionsManager,
ForegroundServiceSectionController fgsSectionController,
ForegroundServiceDismissalFeatureController fgsFeatureController,
@@ -578,17 +560,14 @@ public class NotificationStackScrollLayout extends ViewGroup implements Dumpable
NotifPipeline notifPipeline,
NotificationEntryManager entryManager,
NotifCollection notifCollection,
- UiEventLogger uiEventLogger
+ UiEventLogger uiEventLogger,
+ GroupMembershipManager groupMembershipManager,
+ GroupExpansionManager groupExpansionManager
) {
super(context, attrs, 0, 0);
Resources res = getResources();
mRoundnessManager = notificationRoundnessManager;
-
- mNotificationGutsManager = notificationGutsManager;
- mHeadsUpManager = headsUpManager;
- mHeadsUpManager.setAnimationStateHandler(this::setHeadsUpGoingAwayAnimationsAllowed);
- mFalsingManager = falsingManager;
mFgsSectionController = fgsSectionController;
mSectionsManager = notificationSectionsManager;
@@ -600,7 +579,7 @@ public class NotificationStackScrollLayout extends ViewGroup implements Dumpable
});
mSections = mSectionsManager.createSectionsForBuckets();
- mAmbientState = new AmbientState(context, mSectionsManager, mHeadsUpManager);
+ mAmbientState = new AmbientState(context, mSectionsManager);
mBgColor = context.getColor(R.color.notification_shade_background_color);
int minHeight = res.getDimensionPixelSize(R.dimen.notification_min_height);
int maxHeight = res.getDimensionPixelSize(R.dimen.notification_max_height);
@@ -609,31 +588,9 @@ public class NotificationStackScrollLayout extends ViewGroup implements Dumpable
mExpandHelper.setEventSource(this);
mExpandHelper.setScrollAdapter(mScrollAdapter);
- // TODO: move swipe helper into controller.
- // The anonymous proxy through to mMenuEventListener is temporary until more can be moved
- // into the controller.
- mSwipeHelper = new NotificationSwipeHelper(SwipeHelper.X, mNotificationCallback,
- getContext(), new OnMenuEventListener() {
- @Override
- public void onMenuClicked(View row, int x, int y, MenuItem menu) {
- mMenuEventListener.onMenuClicked(row, x, y, menu);
- }
-
- @Override
- public void onMenuReset(View row) {
- mMenuEventListener.onMenuReset(row);
- }
-
- @Override
- public void onMenuShown(View row) {
- mMenuEventListener.onMenuShown(row);
- }
- }, mFalsingManager);
mStackScrollAlgorithm = createStackScrollAlgorithm(context);
mShouldDrawNotificationBackground =
res.getBoolean(R.bool.config_drawNotificationBackground);
- mFadeNotificationsOnDismiss =
- res.getBoolean(R.bool.config_fadeNotificationsOnDismiss);
setOutlineProvider(mOutlineProvider);
// Blocking helper manager wants to know the expanded state, update as well.
@@ -681,6 +638,8 @@ public class NotificationStackScrollLayout extends ViewGroup implements Dumpable
}
});
}
+ mGroupMembershipManager = groupMembershipManager;
+ mGroupExpansionManager = groupExpansionManager;
mDynamicPrivacyController = dynamicPrivacyController;
mStatusbarStateController = statusbarStateController;
@@ -778,27 +737,6 @@ public class NotificationStackScrollLayout extends ViewGroup implements Dumpable
return false;
}
- @ShadeViewRefactor(RefactorComponent.SHADE_VIEW)
- public RemoteInputController.Delegate createDelegate() {
- return new RemoteInputController.Delegate() {
- public void setRemoteInputActive(NotificationEntry entry,
- boolean remoteInputActive) {
- mHeadsUpManager.setRemoteInputActive(entry, remoteInputActive);
- entry.notifyHeightChanged(true /* needsAnimation */);
- updateFooter();
- }
-
- public void lockScrollTo(NotificationEntry entry) {
- NotificationStackScrollLayout.this.lockScrollTo(entry.getRow());
- }
-
- public void requestDisallowLongPressAndDismiss() {
- requestDisallowLongPress();
- requestDisallowDismiss();
- }
- };
- }
-
@ShadeViewRefactor(RefactorComponent.SHADE_VIEW)
public NotificationSwipeActionHelper getSwipeActionHelper() {
return mSwipeHelper;
@@ -984,7 +922,7 @@ public class NotificationStackScrollLayout extends ViewGroup implements Dumpable
}
@ShadeViewRefactor(RefactorComponent.SHADE_VIEW)
- private void updateBackgroundDimming() {
+ void updateBackgroundDimming() {
// No need to update the background color if it's not being drawn.
if (!mShouldDrawNotificationBackground) {
return;
@@ -1004,14 +942,16 @@ public class NotificationStackScrollLayout extends ViewGroup implements Dumpable
}
private void reinitView() {
- initView(getContext(), mKeyguardBypassEnabledProvider);
+ initView(getContext(), mKeyguardBypassEnabledProvider, mSwipeHelper);
}
@ShadeViewRefactor(RefactorComponent.SHADE_VIEW)
void initView(Context context,
- KeyguardBypassEnabledProvider keyguardBypassEnabledProvider) {
+ KeyguardBypassEnabledProvider keyguardBypassEnabledProvider,
+ NotificationSwipeHelper swipeHelper) {
mScroller = new OverScroller(getContext());
mKeyguardBypassEnabledProvider = keyguardBypassEnabledProvider;
+ mSwipeHelper = swipeHelper;
setDescendantFocusability(FOCUS_AFTER_DESCENDANTS);
setClipChildren(false);
@@ -1069,6 +1009,10 @@ public class NotificationStackScrollLayout extends ViewGroup implements Dumpable
return mAmbientState.isPulseExpanding();
}
+ public int getSpeedBumpIndex() {
+ return mAmbientState.getSpeedBumpIndex();
+ }
+
@Override
@ShadeViewRefactor(RefactorComponent.SHADE_VIEW)
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
@@ -1123,7 +1067,7 @@ public class NotificationStackScrollLayout extends ViewGroup implements Dumpable
}
@ShadeViewRefactor(RefactorComponent.ADAPTER)
- public void updateSpeedBumpIndex(int newIndex, boolean noAmbient) {
+ private void setSpeedBumpIndex(int newIndex, boolean noAmbient) {
mAmbientState.setSpeedBumpIndex(newIndex);
mNoAmbient = noAmbient;
}
@@ -1498,14 +1442,13 @@ public class NotificationStackScrollLayout extends ViewGroup implements Dumpable
*/
@ShadeViewRefactor(RefactorComponent.COORDINATOR)
private int getTopHeadsUpPinnedHeight() {
- NotificationEntry topEntry = mHeadsUpManager.getTopEntry();
- if (topEntry == null) {
+ if (mTopHeadsUpEntry == null) {
return 0;
}
- ExpandableNotificationRow row = topEntry.getRow();
+ ExpandableNotificationRow row = mTopHeadsUpEntry.getRow();
if (row.isChildInGroup()) {
final NotificationEntry groupSummary =
- mGroupManager.getGroupSummary(row.getEntry().getSbn());
+ mGroupMembershipManager.getGroupSummary(row.getEntry());
if (groupSummary != null) {
row = groupSummary.getRow();
}
@@ -1523,7 +1466,7 @@ public class NotificationStackScrollLayout extends ViewGroup implements Dumpable
int visibleNotifCount = getVisibleNotificationCount();
if (mEmptyShadeView.getVisibility() == GONE && visibleNotifCount > 0) {
if (isHeadsUpTransition()
- || (mHeadsUpManager.hasPinnedHeadsUp() && !mAmbientState.isDozing())) {
+ || (mInHeadsUpPinnedMode && !mAmbientState.isDozing())) {
if (mShelf.getVisibility() != GONE && visibleNotifCount > 1) {
appearPosition += mShelf.getIntrinsicHeight() + mPaddingBetweenElements;
}
@@ -1655,7 +1598,7 @@ public class NotificationStackScrollLayout extends ViewGroup implements Dumpable
* @return the child at the given location.
*/
@ShadeViewRefactor(RefactorComponent.COORDINATOR)
- private ExpandableView getChildAtPosition(float touchX, float touchY,
+ ExpandableView getChildAtPosition(float touchX, float touchY,
boolean requireMinHeight, boolean ignoreDecors) {
// find the view under the pointer, accounting for GONE views
final int count = getChildCount();
@@ -1681,10 +1624,8 @@ public class NotificationStackScrollLayout extends ViewGroup implements Dumpable
ExpandableNotificationRow row = (ExpandableNotificationRow) slidingChild;
NotificationEntry entry = row.getEntry();
if (!mIsExpanded && row.isHeadsUp() && row.isPinned()
- && mHeadsUpManager.getTopEntry().getRow() != row
- && mGroupManager.getGroupSummary(
- mHeadsUpManager.getTopEntry().getSbn())
- != entry) {
+ && mTopHeadsUpEntry.getRow() != row
+ && mGroupMembershipManager.getGroupSummary(mTopHeadsUpEntry) != entry) {
continue;
}
return row.getViewAtPosition(touchY - childTop);
@@ -1803,7 +1744,7 @@ public class NotificationStackScrollLayout extends ViewGroup implements Dumpable
}
@ShadeViewRefactor(RefactorComponent.SHADE_VIEW)
- private boolean onKeyguard() {
+ boolean onKeyguard() {
return mStatusBarState == StatusBarState.KEYGUARD;
}
@@ -2311,7 +2252,7 @@ public class NotificationStackScrollLayout extends ViewGroup implements Dumpable
// In current design, it only use the top HUN to treat all of HUNs
// although there are more than one HUNs
int contentHeight = mContentHeight;
- if (!isExpanded() && mHeadsUpManager.hasPinnedHeadsUp()) {
+ if (!isExpanded() && mInHeadsUpPinnedMode) {
contentHeight = mHeadsUpInset + getTopHeadsUpPinnedHeight();
}
int scrollRange = Math.max(0, contentHeight - mMaxLayoutHeight);
@@ -2662,7 +2603,7 @@ public class NotificationStackScrollLayout extends ViewGroup implements Dumpable
false /* shiftPulsingWithFirst */);
minTopPosition = firstVisibleSection.getBounds().top;
}
- boolean shiftPulsingWithFirst = mHeadsUpManager.getAllEntries().count() <= 1
+ boolean shiftPulsingWithFirst = mNumHeadsUp <= 1
&& (mAmbientState.isDozing()
|| (mKeyguardBypassEnabledProvider.getBypassEnabled() && onKeyguard));
for (NotificationSection section : mSections) {
@@ -3082,8 +3023,8 @@ public class NotificationStackScrollLayout extends ViewGroup implements Dumpable
@ShadeViewRefactor(RefactorComponent.ADAPTER)
private boolean isChildInGroup(View child) {
return child instanceof ExpandableNotificationRow
- && mGroupManager.isChildInGroupWithSummary(
- ((ExpandableNotificationRow) child).getEntry().getSbn());
+ && mGroupMembershipManager.isChildInGroup(
+ ((ExpandableNotificationRow) child).getEntry());
}
/**
@@ -3148,6 +3089,8 @@ public class NotificationStackScrollLayout extends ViewGroup implements Dumpable
return hasAddEvent;
}
+ // TODO (b/162832756): remove since this won't happen in new pipeline (we prune groups in
+ // ShadeListBuilder)
/**
* @param child the child to query
* @return whether a view is not a top level child but a child notification and that group is
@@ -3158,7 +3101,7 @@ public class NotificationStackScrollLayout extends ViewGroup implements Dumpable
if (child instanceof ExpandableNotificationRow) {
ExpandableNotificationRow row = (ExpandableNotificationRow) child;
NotificationEntry groupSummary =
- mGroupManager.getGroupSummary(row.getEntry().getSbn());
+ mGroupMembershipManager.getGroupSummary(row.getEntry());
if (groupSummary != null && groupSummary.getRow() != row) {
return row.getVisibility() == View.INVISIBLE;
}
@@ -3537,7 +3480,7 @@ public class NotificationStackScrollLayout extends ViewGroup implements Dumpable
// Only animate if we still have pinned heads up, otherwise we just have the
// regular collapse animation of the lock screen
|| (mKeyguardBypassEnabledProvider.getBypassEnabled() && onKeyguard()
- && mHeadsUpManager.hasPinnedHeadsUp());
+ && mInHeadsUpPinnedMode);
if (performDisappearAnimation && !isHeadsUp) {
type = row.wasJustClicked()
? AnimationEvent.ANIMATION_TYPE_HEADS_UP_DISAPPEAR_CLICK
@@ -3780,58 +3723,16 @@ public class NotificationStackScrollLayout extends ViewGroup implements Dumpable
}
@Override
- @ShadeViewRefactor(RefactorComponent.INPUT)
public boolean onTouchEvent(MotionEvent ev) {
- NotificationGuts guts = mNotificationGutsManager.getExposedGuts();
- boolean isCancelOrUp = ev.getActionMasked() == MotionEvent.ACTION_CANCEL
- || ev.getActionMasked() == MotionEvent.ACTION_UP;
- handleEmptySpaceClick(ev);
- boolean expandWantsIt = false;
- boolean swipingInProgress = mSwipingInProgress;
- if (mIsExpanded && !swipingInProgress && !mOnlyScrollingInThisMotion && guts == null) {
- if (isCancelOrUp) {
- mExpandHelper.onlyObserveMovements(false);
- }
- boolean wasExpandingBefore = mExpandingNotification;
- expandWantsIt = mExpandHelper.onTouchEvent(ev);
- if (mExpandedInThisMotion && !mExpandingNotification && wasExpandingBefore
- && !mDisallowScrollingInThisMotion) {
- dispatchDownEventToScroller(ev);
- }
- }
- boolean scrollerWantsIt = false;
- if (mIsExpanded && !swipingInProgress && !mExpandingNotification
- && !mDisallowScrollingInThisMotion) {
- scrollerWantsIt = onScrollTouch(ev);
- }
- boolean horizontalSwipeWantsIt = false;
- if (!mIsBeingDragged
- && !mExpandingNotification
- && !mExpandedInThisMotion
- && !mOnlyScrollingInThisMotion
- && !mDisallowDismissInThisMotion) {
- horizontalSwipeWantsIt = mSwipeHelper.onTouchEvent(ev);
+ if (mTouchHandler != null && mTouchHandler.onTouchEvent(ev)) {
+ return true;
}
- // Check if we need to clear any snooze leavebehinds
- if (guts != null && !NotificationSwipeHelper.isTouchInView(ev, guts)
- && guts.getGutsContent() instanceof NotificationSnooze) {
- NotificationSnooze ns = (NotificationSnooze) guts.getGutsContent();
- if ((ns.isExpanded() && isCancelOrUp)
- || (!horizontalSwipeWantsIt && scrollerWantsIt)) {
- // If the leavebehind is expanded we clear it on the next up event, otherwise we
- // clear it on the next non-horizontal swipe or expand event.
- checkSnoozeLeavebehind();
- }
- }
- if (ev.getActionMasked() == MotionEvent.ACTION_UP) {
- mCheckForLeavebehind = true;
- }
- return horizontalSwipeWantsIt || scrollerWantsIt || expandWantsIt || super.onTouchEvent(ev);
+ return super.onTouchEvent(ev);
}
@ShadeViewRefactor(RefactorComponent.INPUT)
- private void dispatchDownEventToScroller(MotionEvent ev) {
+ void dispatchDownEventToScroller(MotionEvent ev) {
MotionEvent downEvent = MotionEvent.obtain(ev);
downEvent.setAction(MotionEvent.ACTION_DOWN);
onScrollTouch(downEvent);
@@ -3880,7 +3781,7 @@ public class NotificationStackScrollLayout extends ViewGroup implements Dumpable
}
@ShadeViewRefactor(RefactorComponent.INPUT)
- private boolean onScrollTouch(MotionEvent ev) {
+ boolean onScrollTouch(MotionEvent ev) {
if (!isScrollingEnabled()) {
return false;
}
@@ -3969,7 +3870,7 @@ public class NotificationStackScrollLayout extends ViewGroup implements Dumpable
customOverScrollBy((int) scrollAmount, mOwnScrollY,
range, getHeight() / 2);
// If we're scrolling, leavebehinds should be dismissed
- checkSnoozeLeavebehind();
+ mController.checkSnoozeLeavebehind();
}
}
break;
@@ -4087,44 +3988,14 @@ public class NotificationStackScrollLayout extends ViewGroup implements Dumpable
@Override
@ShadeViewRefactor(RefactorComponent.INPUT)
public boolean onInterceptTouchEvent(MotionEvent ev) {
- initDownStates(ev);
- handleEmptySpaceClick(ev);
-
- NotificationGuts guts = mNotificationGutsManager.getExposedGuts();
- boolean expandWantsIt = false;
- boolean swipingInProgress = mSwipingInProgress;
- if (!swipingInProgress && !mOnlyScrollingInThisMotion && guts == null) {
- expandWantsIt = mExpandHelper.onInterceptTouchEvent(ev);
- }
- boolean scrollWantsIt = false;
- if (!swipingInProgress && !mExpandingNotification) {
- scrollWantsIt = onInterceptTouchEventScroll(ev);
- }
- boolean swipeWantsIt = false;
- if (!mIsBeingDragged
- && !mExpandingNotification
- && !mExpandedInThisMotion
- && !mOnlyScrollingInThisMotion
- && !mDisallowDismissInThisMotion) {
- swipeWantsIt = mSwipeHelper.onInterceptTouchEvent(ev);
- }
- // Check if we need to clear any snooze leavebehinds
- boolean isUp = ev.getActionMasked() == MotionEvent.ACTION_UP;
- if (!NotificationSwipeHelper.isTouchInView(ev, guts) && isUp && !swipeWantsIt &&
- !expandWantsIt && !scrollWantsIt) {
- mCheckForLeavebehind = false;
- mNotificationGutsManager.closeAndSaveGuts(true /* removeLeavebehind */,
- false /* force */, false /* removeControls */, -1 /* x */, -1 /* y */,
- false /* resetMenu */);
- }
- if (ev.getActionMasked() == MotionEvent.ACTION_UP) {
- mCheckForLeavebehind = true;
+ if (mTouchHandler != null && mTouchHandler.onInterceptTouchEvent(ev)) {
+ return true;
}
- return swipeWantsIt || scrollWantsIt || expandWantsIt || super.onInterceptTouchEvent(ev);
+ return super.onInterceptTouchEvent(ev);
}
@ShadeViewRefactor(RefactorComponent.INPUT)
- private void handleEmptySpaceClick(MotionEvent ev) {
+ void handleEmptySpaceClick(MotionEvent ev) {
switch (ev.getActionMasked()) {
case MotionEvent.ACTION_MOVE:
final float touchSlop = getTouchSlop(ev);
@@ -4143,7 +4014,7 @@ public class NotificationStackScrollLayout extends ViewGroup implements Dumpable
}
@ShadeViewRefactor(RefactorComponent.INPUT)
- private void initDownStates(MotionEvent ev) {
+ void initDownStates(MotionEvent ev) {
if (ev.getAction() == MotionEvent.ACTION_DOWN) {
mExpandedInThisMotion = false;
mOnlyScrollingInThisMotion = !mScroller.isFinished();
@@ -4165,7 +4036,7 @@ public class NotificationStackScrollLayout extends ViewGroup implements Dumpable
}
@ShadeViewRefactor(RefactorComponent.INPUT)
- private boolean onInterceptTouchEventScroll(MotionEvent ev) {
+ boolean onInterceptTouchEventScroll(MotionEvent ev) {
if (!isScrollingEnabled()) {
return false;
}
@@ -4361,30 +4232,7 @@ public class NotificationStackScrollLayout extends ViewGroup implements Dumpable
}
@ShadeViewRefactor(RefactorComponent.INPUT)
- public void closeControlsIfOutsideTouch(MotionEvent ev) {
- NotificationGuts guts = mNotificationGutsManager.getExposedGuts();
- NotificationMenuRowPlugin menuRow = mSwipeHelper.getCurrentMenuRow();
- View translatingParentView = mSwipeHelper.getTranslatingParentView();
- View view = null;
- if (guts != null && !guts.getGutsContent().isLeavebehind()) {
- // Only close visible guts if they're not a leavebehind.
- view = guts;
- } else if (menuRow != null && menuRow.isMenuVisible()
- && translatingParentView != null) {
- // Checking menu
- view = translatingParentView;
- }
- if (view != null && !NotificationSwipeHelper.isTouchInView(ev, view)) {
- // Touch was outside visible guts / menu notification, close what's visible
- mNotificationGutsManager.closeAndSaveGuts(false /* removeLeavebehind */,
- false /* force */, true /* removeControls */, -1 /* x */, -1 /* y */,
- false /* resetMenu */);
- resetExposedMenuView(true /* animate */, true /* force */);
- }
- }
-
- @ShadeViewRefactor(RefactorComponent.INPUT)
- private void setSwipingInProgress(boolean swiping) {
+ void setSwipingInProgress(boolean swiping) {
mSwipingInProgress = swiping;
if (swiping) {
requestDisallowInterceptTouchEvent(true);
@@ -4418,39 +4266,22 @@ public class NotificationStackScrollLayout extends ViewGroup implements Dumpable
return Math.max(mMaxLayoutHeight - mContentHeight, 0);
}
- @ShadeViewRefactor(RefactorComponent.SHADE_VIEW)
- void checkSnoozeLeavebehind() {
- if (mCheckForLeavebehind) {
- mNotificationGutsManager.closeAndSaveGuts(true /* removeLeavebehind */,
- false /* force */, false /* removeControls */, -1 /* x */, -1 /* y */,
- false /* resetMenu */);
- mCheckForLeavebehind = false;
- }
- }
-
- @ShadeViewRefactor(RefactorComponent.SHADE_VIEW)
- void resetCheckSnoozeLeavebehind() {
- mCheckForLeavebehind = true;
- }
-
@ShadeViewRefactor(RefactorComponent.STATE_RESOLVER)
void onExpansionStarted() {
mIsExpansionChanging = true;
mAmbientState.setExpansionChanging(true);
- checkSnoozeLeavebehind();
}
@ShadeViewRefactor(RefactorComponent.STATE_RESOLVER)
void onExpansionStopped() {
mIsExpansionChanging = false;
- resetCheckSnoozeLeavebehind();
mAmbientState.setExpansionChanging(false);
if (!mIsExpanded) {
resetScrollPosition();
mStatusBar.resetUserExpandedStates();
clearTemporaryViews();
clearUserLockedViews();
- ArrayList<ExpandableView> draggedViews = mAmbientState.getDraggedViews();
+ ArrayList<View> draggedViews = mAmbientState.getDraggedViews();
if (draggedViews.size() > 0) {
draggedViews.clear();
updateContinuousShadowDrawing();
@@ -4526,7 +4357,7 @@ public class NotificationStackScrollLayout extends ViewGroup implements Dumpable
if (changed) {
mWillExpand = false;
if (!mIsExpanded) {
- mGroupManager.collapseAllGroups();
+ mGroupExpansionManager.collapseGroups();
mExpandHelper.cancelImmediately();
}
updateNotificationAnimationStates();
@@ -4994,6 +4825,10 @@ public class NotificationStackScrollLayout extends ViewGroup implements Dumpable
handleDismissAllClipping();
}
+ boolean getDismissAllInProgress() {
+ return mDismissAllInProgress;
+ }
+
@ShadeViewRefactor(RefactorComponent.ADAPTER)
private void handleDismissAllClipping() {
final int count = getChildCount();
@@ -5059,12 +4894,6 @@ public class NotificationStackScrollLayout extends ViewGroup implements Dumpable
this.mStatusBar = statusBar;
}
- @ShadeViewRefactor(RefactorComponent.SHADE_VIEW)
- public void setGroupManager(NotificationGroupManager groupManager) {
- this.mGroupManager = groupManager;
- mGroupManager.addOnGroupChangeListener(mOnGroupChangeListener);
- }
-
@ShadeViewRefactor(RefactorComponent.STATE_RESOLVER)
void requestAnimateEverything() {
if (mIsExpanded && mAnimationsEnabled) {
@@ -5163,17 +4992,35 @@ public class NotificationStackScrollLayout extends ViewGroup implements Dumpable
public void removeContainerView(View v) {
Assert.isMainThread();
removeView(v);
+ if (v instanceof ExpandableNotificationRow && !mController.isShowingEmptyShadeView()) {
+ mController.updateShowEmptyShadeView();
+ updateFooter();
+ }
+
+ updateSpeedBumpIndex();
}
@ShadeViewRefactor(RefactorComponent.SHADE_VIEW)
public void addContainerView(View v) {
Assert.isMainThread();
addView(v);
+ if (v instanceof ExpandableNotificationRow && mController.isShowingEmptyShadeView()) {
+ mController.updateShowEmptyShadeView();
+ updateFooter();
+ }
+
+ updateSpeedBumpIndex();
}
public void addContainerViewAt(View v, int index) {
Assert.isMainThread();
addView(v, index);
+ if (v instanceof ExpandableNotificationRow && mController.isShowingEmptyShadeView()) {
+ mController.updateShowEmptyShadeView();
+ updateFooter();
+ }
+
+ updateSpeedBumpIndex();
}
@ShadeViewRefactor(RefactorComponent.SHADE_VIEW)
@@ -5224,12 +5071,6 @@ public class NotificationStackScrollLayout extends ViewGroup implements Dumpable
}
@ShadeViewRefactor(RefactorComponent.SHADE_VIEW)
- public void setScrimController(ScrimController scrimController) {
- mScrimController = scrimController;
- mScrimController.setScrimBehindChangeRunnable(this::updateBackgroundDimming);
- }
-
- @ShadeViewRefactor(RefactorComponent.SHADE_VIEW)
public void forceNoOverlappingRendering(boolean force) {
mForceNoOverlappingRendering = force;
}
@@ -5280,6 +5121,10 @@ public class NotificationStackScrollLayout extends ViewGroup implements Dumpable
updateScrollability();
}
+ boolean isQsExpanded() {
+ return mQsExpanded;
+ }
+
@ShadeViewRefactor(RefactorComponent.SHADE_VIEW)
public void setQsExpansionFraction(float qsExpansionFraction) {
mQsExpansionFraction = qsExpansionFraction;
@@ -5402,6 +5247,7 @@ public class NotificationStackScrollLayout extends ViewGroup implements Dumpable
protected void setStatusBarState(int statusBarState) {
mStatusBarState = statusBarState;
mAmbientState.setStatusBarState(statusBarState);
+ updateSpeedBumpIndex();
}
void onStatePostChange(boolean fromShadeLocked) {
@@ -5507,12 +5353,15 @@ public class NotificationStackScrollLayout extends ViewGroup implements Dumpable
ExpandableView child = (ExpandableView) getTransientView(i);
child.dump(fd, pw, args);
}
- ArrayList<ExpandableView> draggedViews = mAmbientState.getDraggedViews();
+ ArrayList<View> draggedViews = mAmbientState.getDraggedViews();
int draggedCount = draggedViews.size();
pw.println(" Dragged Views: " + draggedCount);
for (int i = 0; i < draggedCount; i++) {
- ExpandableView child = (ExpandableView) draggedViews.get(i);
- child.dump(fd, pw, args);
+ View view = draggedViews.get(i);
+ if (view instanceof ExpandableView) {
+ ExpandableView expandableView = (ExpandableView) view;
+ expandableView.dump(fd, pw, args);
+ }
}
}
@@ -5765,6 +5614,10 @@ public class NotificationStackScrollLayout extends ViewGroup implements Dumpable
requestChildrenUpdate();
}
+ public boolean isFullyAwake() {
+ return mAmbientState.isFullyAwake();
+ }
+
public void wakeUpFromPulse() {
setPulseHeight(getWakeUpHeight());
// Let's place the hidden views at the end of the pulsing notification to make sure we have
@@ -5826,25 +5679,77 @@ public class NotificationStackScrollLayout extends ViewGroup implements Dumpable
mCurrentUserId = userId;
}
- void onMenuShown(View row) {
- mSwipeHelper.onMenuShown(row);
+ void addSwipedOutView(View v) {
+ mSwipedOutViews.add(v);
}
- void onMenuReset(View row) {
- View translatingParentView = mSwipeHelper.getTranslatingParentView();
- if (translatingParentView != null && row == translatingParentView) {
- mSwipeHelper.clearExposedMenuView();
- mSwipeHelper.clearTranslatingParentView();
- if (row instanceof ExpandableNotificationRow) {
- mHeadsUpManager.setMenuShown(
- ((ExpandableNotificationRow) row).getEntry(), false);
+ void addDraggedView(View view) {
+ mAmbientState.onBeginDrag(view);
+ }
- }
- }
+ void removeDraggedView(View view) {
+ mAmbientState.onDragFinished(view);
+ }
+
+ void setTopHeadsUpEntry(NotificationEntry topEntry) {
+ mTopHeadsUpEntry = topEntry;
+ }
+
+ void setNumHeadsUp(long numHeadsUp) {
+ mNumHeadsUp = numHeadsUp;
+ mAmbientState.setHasAlertEntries(numHeadsUp > 0);
}
- void setMenuEventListener(OnMenuEventListener menuEventListener) {
- mMenuEventListener = menuEventListener;
+ boolean getSwipingInProgress() {
+ return mSwipingInProgress;
+ }
+
+ public boolean getIsExpanded() {
+ return mIsExpanded;
+ }
+
+ boolean getOnlyScrollingInThisMotion() {
+ return mOnlyScrollingInThisMotion;
+ }
+
+ ExpandHelper getExpandHelper() {
+ return mExpandHelper;
+ }
+
+ boolean isExpandingNotification() {
+ return mExpandingNotification;
+ }
+
+ boolean getDisallowScrollingInThisMotion() {
+ return mDisallowScrollingInThisMotion;
+ }
+
+ boolean isBeingDragged() {
+ return mIsBeingDragged;
+ }
+
+ boolean getExpandedInThisMotion() {
+ return mExpandedInThisMotion;
+ }
+
+ boolean getDisallowDismissInThisMotion() {
+ return mDisallowDismissInThisMotion;
+ }
+
+ void setCheckForLeaveBehind(boolean checkForLeaveBehind) {
+ mCheckForLeavebehind = checkForLeaveBehind;
+ }
+
+ void setTouchHandler(NotificationStackScrollLayoutController.TouchHandler touchHandler) {
+ mTouchHandler = touchHandler;
+ }
+
+ boolean isSwipingInProgress() {
+ return mSwipingInProgress;
+ }
+
+ boolean getCheckSnoozeLeaveBehind() {
+ return mCheckForLeavebehind;
}
/**
@@ -5883,7 +5788,7 @@ public class NotificationStackScrollLayout extends ViewGroup implements Dumpable
}
@ShadeViewRefactor(RefactorComponent.SHADE_VIEW)
- public void updateSpeedBumpIndex() {
+ private void updateSpeedBumpIndex() {
int speedBumpIndex = 0;
int currentIndex = 0;
final int N = getChildCount();
@@ -5905,7 +5810,7 @@ public class NotificationStackScrollLayout extends ViewGroup implements Dumpable
}
}
boolean noAmbient = speedBumpIndex == N;
- updateSpeedBumpIndex(speedBumpIndex, noAmbient);
+ setSpeedBumpIndex(speedBumpIndex, noAmbient);
}
/** Updates the indices of the boundaries between sections. */
@@ -5914,7 +5819,7 @@ public class NotificationStackScrollLayout extends ViewGroup implements Dumpable
mSectionsManager.updateSectionBoundaries(reason);
}
- private void updateContinuousBackgroundDrawing() {
+ void updateContinuousBackgroundDrawing() {
boolean continuousBackground = !mAmbientState.isFullyAwake()
&& !mAmbientState.getDraggedViews().isEmpty();
if (continuousBackground != mContinuousBackgroundUpdate) {
@@ -5928,7 +5833,7 @@ public class NotificationStackScrollLayout extends ViewGroup implements Dumpable
}
@ShadeViewRefactor(RefactorComponent.STATE_RESOLVER)
- private void updateContinuousShadowDrawing() {
+ void updateContinuousShadowDrawing() {
boolean continuousShadowUpdate = mAnimationRunning
|| !mAmbientState.getDraggedViews().isEmpty();
if (continuousShadowUpdate != mContinuousShadowUpdate) {
@@ -5942,7 +5847,7 @@ public class NotificationStackScrollLayout extends ViewGroup implements Dumpable
}
@ShadeViewRefactor(RefactorComponent.SHADE_VIEW)
- public void resetExposedMenuView(boolean animate, boolean force) {
+ private void resetExposedMenuView(boolean animate, boolean force) {
mSwipeHelper.resetExposedMenuView(animate, force);
}
@@ -6202,195 +6107,7 @@ public class NotificationStackScrollLayout extends ViewGroup implements Dumpable
}
}
-
-
- @ShadeViewRefactor(RefactorComponent.INPUT)
- private final NotificationSwipeHelper.NotificationCallback mNotificationCallback =
- new NotificationSwipeHelper.NotificationCallback() {
- @Override
- public void onDismiss() {
- mNotificationGutsManager.closeAndSaveGuts(true /* removeLeavebehind */,
- false /* force */, false /* removeControls */, -1 /* x */, -1 /* y */,
- false /* resetMenu */);
- }
-
- @Override
- public void onSnooze(StatusBarNotification sbn,
- NotificationSwipeActionHelper.SnoozeOption snoozeOption) {
- mStatusBar.setNotificationSnoozed(sbn, snoozeOption);
- }
-
- @Override
- public void onSnooze(StatusBarNotification sbn, int hours) {
- mStatusBar.setNotificationSnoozed(sbn, hours);
- }
-
- @Override
- public boolean shouldDismissQuickly() {
- return NotificationStackScrollLayout.this.isExpanded() && mAmbientState.isFullyAwake();
- }
-
- @Override
- public void onDragCancelled(View v) {
- setSwipingInProgress(false);
- mFalsingManager.onNotificationStopDismissing();
- }
-
- /**
- * Handles cleanup after the given {@code view} has been fully swiped out (including
- * re-invoking dismiss logic in case the notification has not made its way out yet).
- */
- @Override
- public void onChildDismissed(View view) {
- if (!(view instanceof ActivatableNotificationView)) {
- return;
- }
- ActivatableNotificationView row = (ActivatableNotificationView) view;
- if (!row.isDismissed()) {
- handleChildViewDismissed(view);
- }
- ViewGroup transientContainer = row.getTransientContainer();
- if (transientContainer != null) {
- transientContainer.removeTransientView(view);
- }
- }
-
- /**
- * Starts up notification dismiss and tells the notification, if any, to remove itself from
- * layout.
- *
- * @param view view (e.g. notification) to dismiss from the layout
- */
-
- public void handleChildViewDismissed(View view) {
- setSwipingInProgress(false);
- if (mDismissAllInProgress) {
- return;
- }
-
- boolean isBlockingHelperShown = false;
-
- mAmbientState.onDragFinished(view);
- updateContinuousShadowDrawing();
-
- if (view instanceof ExpandableNotificationRow) {
- ExpandableNotificationRow row = (ExpandableNotificationRow) view;
- if (row.isHeadsUp()) {
- mHeadsUpManager.addSwipedOutNotification(
- row.getEntry().getSbn().getKey());
- }
- isBlockingHelperShown =
- row.performDismissWithBlockingHelper(false /* fromAccessibility */);
- }
-
- if (view instanceof PeopleHubView) {
- mSectionsManager.hidePeopleRow();
- }
-
- if (!isBlockingHelperShown) {
- mSwipedOutViews.add(view);
- }
- mFalsingManager.onNotificationDismissed();
- if (mFalsingManager.shouldEnforceBouncer()) {
- mStatusBar.executeRunnableDismissingKeyguard(
- null,
- null /* cancelAction */,
- false /* dismissShade */,
- true /* afterKeyguardGone */,
- false /* deferred */);
- }
- }
-
- @Override
- public boolean isAntiFalsingNeeded() {
- return onKeyguard();
- }
-
- @Override
- public View getChildAtPosition(MotionEvent ev) {
- View child = NotificationStackScrollLayout.this.getChildAtPosition(
- ev.getX(),
- ev.getY(),
- true /* requireMinHeight */,
- false /* ignoreDecors */);
- if (child instanceof ExpandableNotificationRow) {
- ExpandableNotificationRow row = (ExpandableNotificationRow) child;
- ExpandableNotificationRow parent = row.getNotificationParent();
- if (parent != null && parent.areChildrenExpanded()
- && (parent.areGutsExposed()
- || mSwipeHelper.getExposedMenuView() == parent
- || (parent.getAttachedChildren().size() == 1
- && parent.getEntry().isClearable()))) {
- // In this case the group is expanded and showing the menu for the
- // group, further interaction should apply to the group, not any
- // child notifications so we use the parent of the child. We also do the same
- // if we only have a single child.
- child = parent;
- }
- }
- return child;
- }
-
- @Override
- public void onBeginDrag(View v) {
- mFalsingManager.onNotificationStartDismissing();
- setSwipingInProgress(true);
- mAmbientState.onBeginDrag((ExpandableView) v);
- updateContinuousShadowDrawing();
- updateContinuousBackgroundDrawing();
- requestChildrenUpdate();
- }
-
- @Override
- public void onChildSnappedBack(View animView, float targetLeft) {
- mAmbientState.onDragFinished(animView);
- updateContinuousShadowDrawing();
- updateContinuousBackgroundDrawing();
- if (animView instanceof ExpandableNotificationRow) {
- ExpandableNotificationRow row = (ExpandableNotificationRow) animView;
- if (row.isPinned() && !canChildBeDismissed(row)
- && row.getEntry().getSbn().getNotification().fullScreenIntent
- == null) {
- mHeadsUpManager.removeNotification(row.getEntry().getSbn().getKey(),
- true /* removeImmediately */);
- }
- }
- }
-
- @Override
- public boolean updateSwipeProgress(View animView, boolean dismissable,
- float swipeProgress) {
- // Returning true prevents alpha fading.
- return !mFadeNotificationsOnDismiss;
- }
-
- @Override
- public float getFalsingThresholdFactor() {
- return mStatusBar.isWakeUpComingFromTouch() ? 1.5f : 1.0f;
- }
-
- @Override
- public int getConstrainSwipeStartPosition() {
- NotificationMenuRowPlugin menuRow = mSwipeHelper.getCurrentMenuRow();
- if (menuRow != null) {
- return Math.abs(menuRow.getMenuSnapTarget());
- }
- return 0;
- }
-
- @Override
- public boolean canChildBeDismissed(View v) {
- return NotificationStackScrollLayout.canChildBeDismissed(v);
- }
-
- @Override
- public boolean canChildBeDismissedInDirection(View v, boolean isRightOrDown) {
- //TODO: b/131242807 for why this doesn't do anything with direction
- return canChildBeDismissed(v);
- }
- };
-
- private static boolean canChildBeDismissed(View v) {
+ static boolean canChildBeDismissed(View v) {
if (v instanceof ExpandableNotificationRow) {
ExpandableNotificationRow row = (ExpandableNotificationRow) v;
if (row.isBlockingHelperShowingAndTranslationFinished()) {
@@ -6488,6 +6205,10 @@ public class NotificationStackScrollLayout extends ViewGroup implements Dumpable
mKeyguardMediaControllorVisible = keyguardMediaControllorVisible;
}
+ void resetCheckSnoozeLeavebehind() {
+ setCheckForLeaveBehind(true);
+ }
+
// ---------------------- DragDownHelper.OnDragDownListener ------------------------------------
@ShadeViewRefactor(RefactorComponent.INPUT)
@@ -6540,7 +6261,7 @@ public class NotificationStackScrollLayout extends ViewGroup implements Dumpable
@Override
public void onTouchSlopExceeded() {
cancelLongPress();
- checkSnoozeLeavebehind();
+ mController.checkSnoozeLeavebehind();
}
@Override
@@ -6600,39 +6321,22 @@ public class NotificationStackScrollLayout extends ViewGroup implements Dumpable
public HeadsUpTouchHelper.Callback getHeadsUpCallback() { return mHeadsUpCallback; }
-
- @ShadeViewRefactor(RefactorComponent.SHADE_VIEW)
- private final OnGroupChangeListener mOnGroupChangeListener = new OnGroupChangeListener() {
- @Override
- public void onGroupExpansionChanged(ExpandableNotificationRow changedRow, boolean expanded) {
- boolean animated = !mGroupExpandedForMeasure && mAnimationsEnabled
- && (mIsExpanded || changedRow.isPinned());
- if (animated) {
- mExpandedGroupView = changedRow;
- mNeedsAnimation = true;
- }
- changedRow.setChildrenExpanded(expanded, animated);
- if (!mGroupExpandedForMeasure) {
- onChildHeightChanged(changedRow, false /* needsAnimation */);
- }
- runAfterAnimationFinished(new Runnable() {
- @Override
- public void run() {
- changedRow.onFinishedExpansionChange();
- }
- });
- }
-
- @Override
- public void onGroupCreatedFromChildren(NotificationGroupManager.NotificationGroup group) {
- mStatusBar.requestNotificationUpdate("onGroupCreatedFromChildren");
+ void onGroupExpandChanged(ExpandableNotificationRow changedRow, boolean expanded) {
+ boolean animated = mAnimationsEnabled && (mIsExpanded || changedRow.isPinned());
+ if (animated) {
+ mExpandedGroupView = changedRow;
+ mNeedsAnimation = true;
}
+ changedRow.setChildrenExpanded(expanded, animated);
+ onChildHeightChanged(changedRow, false /* needsAnimation */);
- @Override
- public void onGroupsChanged() {
- mStatusBar.requestNotificationUpdate("onGroupsChanged");
- }
- };
+ runAfterAnimationFinished(new Runnable() {
+ @Override
+ public void run() {
+ changedRow.onFinishedExpansionChange();
+ }
+ });
+ }
@ShadeViewRefactor(RefactorComponent.SHADE_VIEW)
private ExpandHelper.Callback mExpandHelperCallback = new ExpandHelper.Callback() {
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 ca78b2a1fc68..8d792ab6aa58 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
@@ -17,12 +17,16 @@
package com.android.systemui.statusbar.notification.stack;
import static com.android.systemui.Dependency.ALLOW_NOTIFICATION_LONG_PRESS_NAME;
+import static com.android.systemui.statusbar.StatusBarState.KEYGUARD;
+import android.content.res.Resources;
import android.graphics.Point;
import android.graphics.PointF;
import android.provider.Settings;
+import android.service.notification.StatusBarNotification;
import android.util.Log;
import android.view.Display;
+import android.view.MotionEvent;
import android.view.View;
import android.view.ViewGroup;
import android.view.WindowInsets;
@@ -31,8 +35,14 @@ import android.widget.FrameLayout;
import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.logging.MetricsLogger;
import com.android.internal.logging.nano.MetricsProto.MetricsEvent;
+import com.android.systemui.ExpandHelper;
+import com.android.systemui.Gefingerpoken;
+import com.android.systemui.R;
+import com.android.systemui.SwipeHelper;
import com.android.systemui.colorextraction.SysuiColorExtractor;
+import com.android.systemui.dagger.qualifiers.Main;
import com.android.systemui.media.KeyguardMediaController;
+import com.android.systemui.plugins.FalsingManager;
import com.android.systemui.plugins.statusbar.NotificationMenuRowPlugin;
import com.android.systemui.plugins.statusbar.NotificationMenuRowPlugin.OnMenuEventListener;
import com.android.systemui.plugins.statusbar.NotificationSwipeActionHelper;
@@ -47,22 +57,28 @@ import com.android.systemui.statusbar.notification.ActivityLaunchAnimator;
import com.android.systemui.statusbar.notification.DynamicPrivacyController;
import com.android.systemui.statusbar.notification.NotificationActivityStarter;
import com.android.systemui.statusbar.notification.collection.NotificationEntry;
+import com.android.systemui.statusbar.notification.collection.legacy.NotificationGroupManagerLegacy;
+import com.android.systemui.statusbar.notification.collection.legacy.NotificationGroupManagerLegacy.NotificationGroup;
+import com.android.systemui.statusbar.notification.collection.legacy.NotificationGroupManagerLegacy.OnGroupChangeListener;
+import com.android.systemui.statusbar.notification.collection.render.GroupExpansionManager;
import com.android.systemui.statusbar.notification.logging.NotificationLogger;
import com.android.systemui.statusbar.notification.row.ActivatableNotificationView;
import com.android.systemui.statusbar.notification.row.ExpandableNotificationRow;
import com.android.systemui.statusbar.notification.row.ExpandableView;
+import com.android.systemui.statusbar.notification.row.NotificationGuts;
import com.android.systemui.statusbar.notification.row.NotificationGutsManager;
+import com.android.systemui.statusbar.notification.row.NotificationSnooze;
import com.android.systemui.statusbar.phone.HeadsUpAppearanceController;
import com.android.systemui.statusbar.phone.HeadsUpManagerPhone;
import com.android.systemui.statusbar.phone.HeadsUpTouchHelper;
import com.android.systemui.statusbar.phone.KeyguardBypassController;
-import com.android.systemui.statusbar.phone.NotificationGroupManager;
import com.android.systemui.statusbar.phone.NotificationPanelViewController;
import com.android.systemui.statusbar.phone.ScrimController;
import com.android.systemui.statusbar.phone.StatusBar;
import com.android.systemui.statusbar.phone.dagger.StatusBarComponent;
import com.android.systemui.statusbar.policy.ConfigurationController;
import com.android.systemui.statusbar.policy.ConfigurationController.ConfigurationListener;
+import com.android.systemui.statusbar.policy.OnHeadsUpChangedListener;
import com.android.systemui.statusbar.policy.ZenModeController;
import com.android.systemui.tuner.TunerService;
@@ -89,13 +105,24 @@ public class NotificationStackScrollLayoutController {
private final ConfigurationController mConfigurationController;
private final ZenModeController mZenModeController;
private final MetricsLogger mMetricsLogger;
+ private final FalsingManager mFalsingManager;
+ private final NotificationSectionsManager mNotificationSectionsManager;
+ private final Resources mResources;
+ private final NotificationSwipeHelper.Builder mNotificationSwipeHelperBuilder;
+ private final ScrimController mScrimController;
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;
private NotificationStackScrollLayout mView;
+ private boolean mFadeNotificationsOnDismiss;
+ private NotificationSwipeHelper mSwipeHelper;
+ private boolean mShowEmptyShadeView;
+ private int mBarState;
private final NotificationListContainerImpl mNotificationListContainer =
new NotificationListContainerImpl();
@@ -106,6 +133,8 @@ public class NotificationStackScrollLayoutController {
@Override
public void onViewAttachedToWindow(View v) {
mConfigurationController.addCallback(mConfigurationListener);
+ mZenModeController.addCallback(mZenModeControllerCallback);
+ mBarState = mStatusBarStateController.getState();
mStatusBarStateController.addCallback(
mStateListener, SysuiStatusBarStateController.RANK_STACK_SCROLLER);
}
@@ -113,6 +142,7 @@ public class NotificationStackScrollLayoutController {
@Override
public void onViewDetachedFromWindow(View v) {
mConfigurationController.removeCallback(mConfigurationListener);
+ mZenModeController.removeCallback(mZenModeControllerCallback);
mStatusBarStateController.removeCallback(mStateListener);
}
};
@@ -133,11 +163,13 @@ public class NotificationStackScrollLayoutController {
final ConfigurationListener mConfigurationListener = new ConfigurationListener() {
@Override
public void onDensityOrFontScaleChanged() {
+ updateShowEmptyShadeView();
mView.reinflateViews();
}
@Override
public void onOverlayChanged() {
+ updateShowEmptyShadeView();
mView.updateCornerRadius();
mView.reinflateViews();
}
@@ -158,14 +190,15 @@ public class NotificationStackScrollLayoutController {
@Override
public void onStatePreChange(int oldState, int newState) {
if (oldState == StatusBarState.SHADE_LOCKED
- && newState == StatusBarState.KEYGUARD) {
+ && newState == KEYGUARD) {
mView.requestAnimateEverything();
}
}
@Override
public void onStateChanged(int newState) {
- mView.setStatusBarState(newState);
+ mBarState = newState;
+ mView.setStatusBarState(mBarState);
}
@Override
@@ -203,7 +236,16 @@ public class NotificationStackScrollLayoutController {
@Override
public void onMenuReset(View row) {
- mView.onMenuReset(row);
+ View translatingParentView = mSwipeHelper.getTranslatingParentView();
+ if (translatingParentView != null && row == translatingParentView) {
+ mSwipeHelper.clearExposedMenuView();
+ mSwipeHelper.clearTranslatingParentView();
+ if (row instanceof ExpandableNotificationRow) {
+ mHeadsUpManager.setMenuShown(
+ ((ExpandableNotificationRow) row).getEntry(), false);
+
+ }
+ }
}
@Override
@@ -214,7 +256,7 @@ public class NotificationStackScrollLayoutController {
.setCategory(MetricsEvent.ACTION_REVEAL_GEAR)
.setType(MetricsEvent.TYPE_ACTION));
mHeadsUpManager.setMenuShown(notificationRow.getEntry(), true);
- mView.onMenuShown(row);
+ mSwipeHelper.onMenuShown(row);
mNotificationGutsManager.closeAndSaveGuts(true /* removeLeavebehind */,
false /* force */, false /* removeControls */, -1 /* x */, -1 /* y */,
false /* resetMenu */);
@@ -232,12 +274,232 @@ public class NotificationStackScrollLayoutController {
}
// Close the menu row since we went directly to the guts
- mView.resetExposedMenuView(false, true);
+ mSwipeHelper.resetExposedMenuView(false, true);
}
}
}
};
+ private final NotificationSwipeHelper.NotificationCallback mNotificationCallback =
+ new NotificationSwipeHelper.NotificationCallback() {
+
+ @Override
+ public void onDismiss() {
+ mNotificationGutsManager.closeAndSaveGuts(true /* removeLeavebehind */,
+ false /* force */, false /* removeControls */, -1 /* x */, -1 /* y */,
+ false /* resetMenu */);
+ }
+
+ @Override
+ public void onSnooze(StatusBarNotification sbn,
+ NotificationSwipeActionHelper.SnoozeOption snoozeOption) {
+ mStatusBar.setNotificationSnoozed(sbn, snoozeOption);
+ }
+
+ @Override
+ public void onSnooze(StatusBarNotification sbn, int hours) {
+ mStatusBar.setNotificationSnoozed(sbn, hours);
+ }
+
+ @Override
+ public boolean shouldDismissQuickly() {
+ return mView.isExpanded() && mView.isFullyAwake();
+ }
+
+ @Override
+ public void onDragCancelled(View v) {
+ mView.setSwipingInProgress(false);
+ mFalsingManager.onNotificationStopDismissing();
+ }
+
+ /**
+ * Handles cleanup after the given {@code view} has been fully swiped out (including
+ * re-invoking dismiss logic in case the notification has not made its way out yet).
+ */
+ @Override
+ public void onChildDismissed(View view) {
+ if (!(view instanceof ActivatableNotificationView)) {
+ return;
+ }
+ ActivatableNotificationView row = (ActivatableNotificationView) view;
+ if (!row.isDismissed()) {
+ handleChildViewDismissed(view);
+ }
+ ViewGroup transientContainer = row.getTransientContainer();
+ if (transientContainer != null) {
+ transientContainer.removeTransientView(view);
+ }
+ }
+
+ /**
+ * Starts up notification dismiss and tells the notification, if any, to remove
+ * itself from the layout.
+ *
+ * @param view view (e.g. notification) to dismiss from the layout
+ */
+
+ public void handleChildViewDismissed(View view) {
+ mView.setSwipingInProgress(false);
+ if (mView.getDismissAllInProgress()) {
+ return;
+ }
+
+ boolean isBlockingHelperShown = false;
+
+ mView.removeDraggedView(view);
+ mView.updateContinuousShadowDrawing();
+
+ if (view instanceof ExpandableNotificationRow) {
+ ExpandableNotificationRow row = (ExpandableNotificationRow) view;
+ if (row.isHeadsUp()) {
+ mHeadsUpManager.addSwipedOutNotification(
+ row.getEntry().getSbn().getKey());
+ }
+ isBlockingHelperShown =
+ row.performDismissWithBlockingHelper(false /* fromAccessibility */);
+ }
+
+ if (view instanceof PeopleHubView) {
+ mNotificationSectionsManager.hidePeopleRow();
+ }
+
+ if (!isBlockingHelperShown) {
+ mView.addSwipedOutView(view);
+ }
+ mFalsingManager.onNotificationDismissed();
+ if (mFalsingManager.shouldEnforceBouncer()) {
+ mStatusBar.executeRunnableDismissingKeyguard(
+ null,
+ null /* cancelAction */,
+ false /* dismissShade */,
+ true /* afterKeyguardGone */,
+ false /* deferred */);
+ }
+ }
+
+ @Override
+ public boolean isAntiFalsingNeeded() {
+ return mView.onKeyguard();
+ }
+
+ @Override
+ public View getChildAtPosition(MotionEvent ev) {
+ View child = mView.getChildAtPosition(
+ ev.getX(),
+ ev.getY(),
+ true /* requireMinHeight */,
+ false /* ignoreDecors */);
+ if (child instanceof ExpandableNotificationRow) {
+ ExpandableNotificationRow row = (ExpandableNotificationRow) child;
+ ExpandableNotificationRow parent = row.getNotificationParent();
+ if (parent != null && parent.areChildrenExpanded()
+ && (parent.areGutsExposed()
+ || mSwipeHelper.getExposedMenuView() == parent
+ || (parent.getAttachedChildren().size() == 1
+ && parent.getEntry().isClearable()))) {
+ // In this case the group is expanded and showing the menu for the
+ // group, further interaction should apply to the group, not any
+ // child notifications so we use the parent of the child. We also do the
+ // same if we only have a single child.
+ child = parent;
+ }
+ }
+ return child;
+ }
+
+ @Override
+ public void onBeginDrag(View v) {
+ mFalsingManager.onNotificationStartDismissing();
+ mView.setSwipingInProgress(true);
+ mView.addDraggedView(v);
+ mView.updateContinuousShadowDrawing();
+ mView.updateContinuousBackgroundDrawing();
+ mView.requestChildrenUpdate();
+ }
+
+ @Override
+ public void onChildSnappedBack(View animView, float targetLeft) {
+ mView.addDraggedView(animView);
+ mView.updateContinuousShadowDrawing();
+ mView.updateContinuousBackgroundDrawing();
+ if (animView instanceof ExpandableNotificationRow) {
+ ExpandableNotificationRow row = (ExpandableNotificationRow) animView;
+ if (row.isPinned() && !canChildBeDismissed(row)
+ && row.getEntry().getSbn().getNotification().fullScreenIntent
+ == null) {
+ mHeadsUpManager.removeNotification(row.getEntry().getSbn().getKey(),
+ true /* removeImmediately */);
+ }
+ }
+ }
+
+ @Override
+ public boolean updateSwipeProgress(View animView, boolean dismissable,
+ float swipeProgress) {
+ // Returning true prevents alpha fading.
+ return !mFadeNotificationsOnDismiss;
+ }
+
+ @Override
+ public float getFalsingThresholdFactor() {
+ return mStatusBar.isWakeUpComingFromTouch() ? 1.5f : 1.0f;
+ }
+
+ @Override
+ public int getConstrainSwipeStartPosition() {
+ NotificationMenuRowPlugin menuRow = mSwipeHelper.getCurrentMenuRow();
+ if (menuRow != null) {
+ return Math.abs(menuRow.getMenuSnapTarget());
+ }
+ return 0;
+ }
+
+ @Override
+ public boolean canChildBeDismissed(View v) {
+ return NotificationStackScrollLayout.canChildBeDismissed(v);
+ }
+
+ @Override
+ public boolean canChildBeDismissedInDirection(View v, boolean isRightOrDown) {
+ //TODO: b/131242807 for why this doesn't do anything with direction
+ return canChildBeDismissed(v);
+ }
+ };
+
+ private final OnHeadsUpChangedListener mOnHeadsUpChangedListener =
+ new OnHeadsUpChangedListener() {
+ @Override
+ public void onHeadsUpPinnedModeChanged(boolean inPinnedMode) {
+ mView.setInHeadsUpPinnedMode(inPinnedMode);
+ }
+
+ @Override
+ public void onHeadsUpPinned(NotificationEntry entry) {
+
+ }
+
+ @Override
+ public void onHeadsUpUnPinned(NotificationEntry entry) {
+
+ }
+
+ @Override
+ public void onHeadsUpStateChanged(NotificationEntry entry, boolean isHeadsUp) {
+ long numEntries = mHeadsUpManager.getAllEntries().count();
+ NotificationEntry topEntry = mHeadsUpManager.getTopEntry();
+ mView.setNumHeadsUp(numEntries);
+ mView.setTopHeadsUpEntry(topEntry);
+ }
+ };
+
+ private final ZenModeController.Callback mZenModeControllerCallback =
+ new ZenModeController.Callback() {
+ @Override
+ public void onZenChanged(int zen) {
+ updateShowEmptyShadeView();
+ }
+ };
+
@Inject
public NotificationStackScrollLayoutController(
@Named(ALLOW_NOTIFICATION_LONG_PRESS_NAME) boolean allowLongPress,
@@ -253,7 +515,15 @@ public class NotificationStackScrollLayoutController {
ZenModeController zenModeController,
SysuiColorExtractor colorExtractor,
NotificationLockscreenUserManager lockscreenUserManager,
- MetricsLogger metricsLogger) {
+ MetricsLogger metricsLogger,
+ FalsingManager falsingManager,
+ NotificationSectionsManager notificationSectionsManager,
+ @Main Resources resources,
+ NotificationSwipeHelper.Builder notificationSwipeHelperBuilder,
+ StatusBar statusBar,
+ ScrimController scrimController,
+ NotificationGroupManagerLegacy legacyGroupManager,
+ GroupExpansionManager groupManager) {
mAllowLongPress = allowLongPress;
mNotificationGutsManager = notificationGutsManager;
mHeadsUpManager = headsUpManager;
@@ -268,20 +538,56 @@ public class NotificationStackScrollLayoutController {
mColorExtractor = colorExtractor;
mLockscreenUserManager = lockscreenUserManager;
mMetricsLogger = metricsLogger;
+ mFalsingManager = falsingManager;
+ mNotificationSectionsManager = notificationSectionsManager;
+ mResources = resources;
+ mNotificationSwipeHelperBuilder = notificationSwipeHelperBuilder;
+ mStatusBar = statusBar;
+ mScrimController = scrimController;
+ groupManager.registerGroupExpansionChangeListener((changedRow, expanded) -> {
+ mView.onGroupExpandChanged(changedRow, expanded);
+ });
+
+ legacyGroupManager.registerGroupChangeListener(new OnGroupChangeListener() {
+ @Override
+ public void onGroupCreatedFromChildren(NotificationGroup group) {
+ mStatusBar.requestNotificationUpdate("onGroupCreatedFromChildren");
+ }
+
+ @Override
+ public void onGroupsChanged() {
+ mStatusBar.requestNotificationUpdate("onGroupsChanged");
+ }
+ });
}
public void attach(NotificationStackScrollLayout view) {
mView = view;
mView.setController(this);
- mView.initView(mView.getContext(), mKeyguardBypassController::getBypassEnabled);
+ mView.setTouchHandler(new TouchHandler());
+ mView.setStatusBar(mStatusBar);
+
+ mSwipeHelper = mNotificationSwipeHelperBuilder
+ .setSwipeDirection(SwipeHelper.X)
+ .setNotificationCallback(mNotificationCallback)
+ .setOnMenuEventListener(mMenuEventListener)
+ .build();
+
+ mView.initView(mView.getContext(), mKeyguardBypassController::getBypassEnabled,
+ mSwipeHelper);
mHeadsUpManager.addListener(mNotificationRoundnessManager); // TODO: why is this here?
+ mHeadsUpManager.addListener(mOnHeadsUpChangedListener);
+ mHeadsUpManager.setAnimationStateHandler(mView::setHeadsUpGoingAwayAnimationsAllowed);
mDynamicPrivacyController.addListener(mDynamicPrivacyControllerListener);
+ mScrimController.setScrimBehindChangeRunnable(mView::updateBackgroundDimming);
+
mLockscreenUserManager.addUserChangedListener(mLockscreenUserChangeListener);
mView.setCurrentUserid(mLockscreenUserManager.getCurrentUserId());
- mView.setMenuEventListener(mMenuEventListener);
+ mFadeNotificationsOnDismiss = // TODO: this should probably be injected directly
+ mResources.getBoolean(R.bool.config_fadeNotificationsOnDismiss);
mNotificationRoundnessManager.setOnRoundingChangedCallback(mView::invalidate);
mView.addOnExpandedHeightChangedListener(mNotificationRoundnessManager::setExpanded);
@@ -517,11 +823,17 @@ public class NotificationStackScrollLayoutController {
}
public void checkSnoozeLeavebehind() {
- mView.checkSnoozeLeavebehind();
+ if (mView.getCheckSnoozeLeaveBehind()) {
+ mNotificationGutsManager.closeAndSaveGuts(true /* removeLeavebehind */,
+ false /* force */, false /* removeControls */, -1 /* x */, -1 /* y */,
+ false /* resetMenu */);
+ mView.setCheckForLeaveBehind(false);
+ }
}
public void setQsExpanded(boolean expanded) {
mView.setQsExpanded(expanded);
+ updateShowEmptyShadeView();
}
public void setScrollingEnabled(boolean enabled) {
@@ -540,10 +852,6 @@ public class NotificationStackScrollLayoutController {
mView.updateTopPadding(qsHeight, animate);
}
- public void resetCheckSnoozeLeavebehind() {
- mView.resetCheckSnoozeLeavebehind();
- }
-
public boolean isScrolledToBottom() {
return mView.isScrolledToBottom();
}
@@ -594,9 +902,11 @@ public class NotificationStackScrollLayoutController {
public void onExpansionStarted() {
mView.onExpansionStarted();
+ checkSnoozeLeavebehind();
}
public void onExpansionStopped() {
+ mView.setCheckForLeaveBehind(false);
mView.onExpansionStopped();
}
@@ -632,8 +942,21 @@ public class NotificationStackScrollLayoutController {
return mView.getFooterViewHeightWithPadding();
}
- public void updateEmptyShadeView(boolean visible) {
- mView.updateEmptyShadeView(visible, mZenModeController.areNotificationsHiddenInShade());
+ /**
+ * Update whether we should show the empty shade view (no notifications in the shade).
+ * If so, send the update to our view.
+ */
+ public void updateShowEmptyShadeView() {
+ mShowEmptyShadeView = mBarState != KEYGUARD
+ && !mView.isQsExpanded()
+ && mView.getVisibleNotificationCount() == 0;
+ mView.updateEmptyShadeView(
+ mShowEmptyShadeView,
+ mZenModeController.areNotificationsHiddenInShade());
+ }
+
+ public boolean isShowingEmptyShadeView() {
+ return mShowEmptyShadeView;
}
public void setHeadsUpAnimatingAway(boolean headsUpAnimatingAway) {
@@ -681,18 +1004,37 @@ public class NotificationStackScrollLayoutController {
return mView.hasActiveClearableNotifications(selection);
}
+ /**
+ * Set the maximum number of notifications that can currently be displayed
+ */
+ public void setMaxDisplayedNotifications(int maxNotifications) {
+ mNotificationListContainer.setMaxDisplayedNotifications(maxNotifications);
+ }
+
public RemoteInputController.Delegate createDelegate() {
- return mView.createDelegate();
+ return new RemoteInputController.Delegate() {
+ public void setRemoteInputActive(NotificationEntry entry,
+ boolean remoteInputActive) {
+ mHeadsUpManager.setRemoteInputActive(entry, remoteInputActive);
+ entry.notifyHeightChanged(true /* needsAnimation */);
+ updateFooter();
+ }
+
+ public void lockScrollTo(NotificationEntry entry) {
+ mView.lockScrollTo(entry.getRow());
+ }
+
+ public void requestDisallowLongPressAndDismiss() {
+ mView.requestDisallowLongPress();
+ mView.requestDisallowDismiss();
+ }
+ };
}
public void updateSectionBoundaries(String reason) {
mView.updateSectionBoundaries(reason);
}
- public void updateSpeedBumpIndex() {
- mView.updateSpeedBumpIndex();
- }
-
public void updateFooter() {
mView.updateFooter();
}
@@ -718,30 +1060,14 @@ public class NotificationStackScrollLayoutController {
mView.setNotificationPanelController(notificationPanelViewController);
}
- public void setStatusBar(StatusBar statusBar) {
- mView.setStatusBar(statusBar);
- }
-
- public void setGroupManager(NotificationGroupManager groupManager) {
- mView.setGroupManager(groupManager);
- }
-
public void setShelfController(NotificationShelfController notificationShelfController) {
mView.setShelfController(notificationShelfController);
}
- public void setScrimController(ScrimController scrimController) {
- mView.setScrimController(scrimController);
- }
-
public ExpandableView getFirstChildNotGone() {
return mView.getFirstChildNotGone();
}
- public void setInHeadsUpPinnedMode(boolean inPinnedMode) {
- mView.setInHeadsUpPinnedMode(inPinnedMode);
- }
-
public void generateHeadsUpAnimation(NotificationEntry entry, boolean isHeadsUp) {
mView.generateHeadsUpAnimation(entry, isHeadsUp);
}
@@ -774,7 +1100,7 @@ public class NotificationStackScrollLayoutController {
return mView.calculateGapHeight(previousView, child, count);
}
- public NotificationRoundnessManager getNoticationRoundessManager() {
+ NotificationRoundnessManager getNoticationRoundessManager() {
return mNotificationRoundnessManager;
}
@@ -782,7 +1108,34 @@ public class NotificationStackScrollLayoutController {
return mNotificationListContainer;
}
+ public void resetCheckSnoozeLeavebehind() {
+ mView.resetCheckSnoozeLeavebehind();
+ }
+
+ public void closeControlsIfOutsideTouch(MotionEvent ev) {
+ NotificationGuts guts = mNotificationGutsManager.getExposedGuts();
+ NotificationMenuRowPlugin menuRow = mSwipeHelper.getCurrentMenuRow();
+ View translatingParentView = mSwipeHelper.getTranslatingParentView();
+ View view = null;
+ if (guts != null && !guts.getGutsContent().isLeavebehind()) {
+ // Only close visible guts if they're not a leavebehind.
+ view = guts;
+ } else if (menuRow != null && menuRow.isMenuVisible()
+ && translatingParentView != null) {
+ // Checking menu
+ view = translatingParentView;
+ }
+ if (view != null && !NotificationSwipeHelper.isTouchInView(ev, view)) {
+ // Touch was outside visible guts / menu notification, close what's visible
+ mNotificationGutsManager.closeAndSaveGuts(false /* removeLeavebehind */,
+ false /* force */, true /* removeControls */, -1 /* x */, -1 /* y */,
+ false /* resetMenu */);
+ mSwipeHelper.resetExposedMenuView(true /* animate */, true /* force */);
+ }
+ }
+
private class NotificationListContainerImpl implements NotificationListContainer {
+
@Override
public void setChildTransferInProgress(boolean childTransferInProgress) {
mView.setChildTransferInProgress(childTransferInProgress);
@@ -856,12 +1209,12 @@ public class NotificationStackScrollLayoutController {
@Override
public void resetExposedMenuView(boolean animate, boolean force) {
- mView.resetExposedMenuView(animate, force);
+ mSwipeHelper.resetExposedMenuView(animate, force);
}
@Override
public NotificationSwipeActionHelper getSwipeActionHelper() {
- return mView.getSwipeActionHelper();
+ return mSwipeHelper;
}
@Override
@@ -920,4 +1273,99 @@ public class NotificationStackScrollLayoutController {
mView.setWillExpand(willExpand);
}
}
+
+ class TouchHandler implements Gefingerpoken {
+ @Override
+ public boolean onInterceptTouchEvent(MotionEvent ev) {
+ mView.initDownStates(ev);
+ mView.handleEmptySpaceClick(ev);
+
+ NotificationGuts guts = mNotificationGutsManager.getExposedGuts();
+ boolean expandWantsIt = false;
+ boolean swipingInProgress = mView.isSwipingInProgress();
+ if (!swipingInProgress && !mView.getOnlyScrollingInThisMotion() && guts == null) {
+ expandWantsIt = mView.getExpandHelper().onInterceptTouchEvent(ev);
+ }
+ boolean scrollWantsIt = false;
+ if (!swipingInProgress && !mView.isExpandingNotification()) {
+ scrollWantsIt = mView.onInterceptTouchEventScroll(ev);
+ }
+ boolean swipeWantsIt = false;
+ if (!mView.isBeingDragged()
+ && !mView.isExpandingNotification()
+ && !mView.getExpandedInThisMotion()
+ && !mView.getOnlyScrollingInThisMotion()
+ && !mView.getDisallowDismissInThisMotion()) {
+ swipeWantsIt = mSwipeHelper.onInterceptTouchEvent(ev);
+ }
+ // Check if we need to clear any snooze leavebehinds
+ boolean isUp = ev.getActionMasked() == MotionEvent.ACTION_UP;
+ if (!NotificationSwipeHelper.isTouchInView(ev, guts) && isUp && !swipeWantsIt &&
+ !expandWantsIt && !scrollWantsIt) {
+ mView.setCheckForLeaveBehind(false);
+ mNotificationGutsManager.closeAndSaveGuts(true /* removeLeavebehind */,
+ false /* force */, false /* removeControls */, -1 /* x */, -1 /* y */,
+ false /* resetMenu */);
+ }
+ if (ev.getActionMasked() == MotionEvent.ACTION_UP) {
+ mView.setCheckForLeaveBehind(true);
+ }
+ return swipeWantsIt || scrollWantsIt || expandWantsIt;
+ }
+
+ @Override
+ public boolean onTouchEvent(MotionEvent ev) {
+ NotificationGuts guts = mNotificationGutsManager.getExposedGuts();
+ boolean isCancelOrUp = ev.getActionMasked() == MotionEvent.ACTION_CANCEL
+ || ev.getActionMasked() == MotionEvent.ACTION_UP;
+ mView.handleEmptySpaceClick(ev);
+ boolean expandWantsIt = false;
+ boolean swipingInProgress = mView.getSwipingInProgress();
+ boolean onlyScrollingInThisMotion = mView.getOnlyScrollingInThisMotion();
+ boolean expandingNotification = mView.isExpandingNotification();
+ if (mView.getIsExpanded() && !swipingInProgress && !onlyScrollingInThisMotion
+ && guts == null) {
+ ExpandHelper expandHelper = mView.getExpandHelper();
+ if (isCancelOrUp) {
+ expandHelper.onlyObserveMovements(false);
+ }
+ boolean wasExpandingBefore = expandingNotification;
+ expandWantsIt = expandHelper.onTouchEvent(ev);
+ expandingNotification = mView.isExpandingNotification();
+ if (mView.getExpandedInThisMotion() && !expandingNotification && wasExpandingBefore
+ && !mView.getDisallowScrollingInThisMotion()) {
+ mView.dispatchDownEventToScroller(ev);
+ }
+ }
+ boolean scrollerWantsIt = false;
+ if (mView.isExpanded() && !swipingInProgress && !expandingNotification
+ && !mView.getDisallowScrollingInThisMotion()) {
+ scrollerWantsIt = mView.onScrollTouch(ev);
+ }
+ boolean horizontalSwipeWantsIt = false;
+ if (!mView.isBeingDragged()
+ && !expandingNotification
+ && !mView.getExpandedInThisMotion()
+ && !onlyScrollingInThisMotion
+ && !mView.getDisallowDismissInThisMotion()) {
+ horizontalSwipeWantsIt = mSwipeHelper.onTouchEvent(ev);
+ }
+
+ // Check if we need to clear any snooze leavebehinds
+ if (guts != null && !NotificationSwipeHelper.isTouchInView(ev, guts)
+ && guts.getGutsContent() instanceof NotificationSnooze) {
+ NotificationSnooze ns = (NotificationSnooze) guts.getGutsContent();
+ if ((ns.isExpanded() && isCancelOrUp)
+ || (!horizontalSwipeWantsIt && scrollerWantsIt)) {
+ // If the leavebehind is expanded we clear it on the next up event, otherwise we
+ // clear it on the next non-horizontal swipe or expand event.
+ checkSnoozeLeavebehind();
+ }
+ }
+ if (ev.getActionMasked() == MotionEvent.ACTION_UP) {
+ mView.setCheckForLeaveBehind(true);
+ }
+ return horizontalSwipeWantsIt || scrollerWantsIt || expandWantsIt;
+ }
+ }
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationSwipeHelper.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationSwipeHelper.java
index d3b8a8cd2093..ba01c8420ef2 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationSwipeHelper.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationSwipeHelper.java
@@ -19,15 +19,17 @@ package com.android.systemui.statusbar.notification.stack;
import android.animation.Animator;
import android.animation.ValueAnimator;
-import android.content.Context;
+import android.content.res.Resources;
import android.graphics.Rect;
import android.os.Handler;
import android.service.notification.StatusBarNotification;
import android.view.MotionEvent;
import android.view.View;
+import android.view.ViewConfiguration;
import com.android.internal.annotations.VisibleForTesting;
import com.android.systemui.SwipeHelper;
+import com.android.systemui.dagger.qualifiers.Main;
import com.android.systemui.plugins.FalsingManager;
import com.android.systemui.plugins.statusbar.NotificationMenuRowPlugin;
import com.android.systemui.plugins.statusbar.NotificationSwipeActionHelper;
@@ -36,6 +38,8 @@ import com.android.systemui.statusbar.notification.row.ExpandableView;
import java.lang.ref.WeakReference;
+import javax.inject.Inject;
+
class NotificationSwipeHelper extends SwipeHelper implements NotificationSwipeActionHelper {
@VisibleForTesting
@@ -58,10 +62,10 @@ class NotificationSwipeHelper extends SwipeHelper implements NotificationSwipeAc
private boolean mPulsing;
NotificationSwipeHelper(
- int swipeDirection, NotificationCallback callback, Context context,
- NotificationMenuRowPlugin.OnMenuEventListener menuListener,
- FalsingManager falsingManager) {
- super(swipeDirection, callback, context, falsingManager);
+ Resources resources, ViewConfiguration viewConfiguration,
+ FalsingManager falsingManager, int swipeDirection, NotificationCallback callback,
+ NotificationMenuRowPlugin.OnMenuEventListener menuListener) {
+ super(swipeDirection, callback, resources, viewConfiguration, falsingManager);
mMenuListener = menuListener;
mCallback = callback;
mFalsingCheck = () -> resetExposedMenuView(true /* animate */, true /* force */);
@@ -74,7 +78,7 @@ class NotificationSwipeHelper extends SwipeHelper implements NotificationSwipeAc
public void clearTranslatingParentView() { setTranslatingParentView(null); }
@VisibleForTesting
- protected void setTranslatingParentView(View view) { mTranslatingParentView = view; };
+ protected void setTranslatingParentView(View view) { mTranslatingParentView = view; }
public void setExposedMenuView(View view) {
mMenuExposedView = view;
@@ -90,7 +94,7 @@ class NotificationSwipeHelper extends SwipeHelper implements NotificationSwipeAc
@VisibleForTesting
void setCurrentMenuRow(NotificationMenuRowPlugin menuRow) {
- mCurrMenuRowRef = menuRow != null ? new WeakReference(menuRow) : null;
+ mCurrMenuRowRef = menuRow != null ? new WeakReference<>(menuRow) : null;
}
public NotificationMenuRowPlugin getCurrentMenuRow() {
@@ -223,7 +227,7 @@ class NotificationSwipeHelper extends SwipeHelper implements NotificationSwipeAc
|| (isFastNonDismissGesture && isAbleToShowMenu);
int menuSnapTarget = menuRow.getMenuSnapTarget();
boolean isNonFalseMenuRevealingGesture =
- !isFalseGesture(ev) && isMenuRevealingGestureAwayFromMenu;
+ !isFalseGesture() && isMenuRevealingGestureAwayFromMenu;
if ((isNonDismissGestureTowardsMenu || isNonFalseMenuRevealingGesture)
&& menuSnapTarget != 0) {
// Menu has not been snapped to previously and this is menu revealing gesture
@@ -470,4 +474,42 @@ class NotificationSwipeHelper extends SwipeHelper implements NotificationSwipeAc
void onDismiss();
}
+
+ static class Builder {
+ private final Resources mResources;
+ private final ViewConfiguration mViewConfiguration;
+ private final FalsingManager mFalsingManager;
+ private int mSwipeDirection;
+ private NotificationCallback mNotificationCallback;
+ private NotificationMenuRowPlugin.OnMenuEventListener mOnMenuEventListener;
+
+ @Inject
+ Builder(@Main Resources resources, ViewConfiguration viewConfiguration,
+ FalsingManager falsingManager) {
+ mResources = resources;
+ mViewConfiguration = viewConfiguration;
+ mFalsingManager = falsingManager;
+ }
+
+ Builder setSwipeDirection(int swipeDirection) {
+ mSwipeDirection = swipeDirection;
+ return this;
+ }
+
+ Builder setNotificationCallback(NotificationCallback notificationCallback) {
+ mNotificationCallback = notificationCallback;
+ return this;
+ }
+
+ Builder setOnMenuEventListener(
+ NotificationMenuRowPlugin.OnMenuEventListener onMenuEventListener) {
+ mOnMenuEventListener = onMenuEventListener;
+ return this;
+ }
+
+ NotificationSwipeHelper build() {
+ return new NotificationSwipeHelper(mResources, mViewConfiguration, mFalsingManager,
+ mSwipeDirection, mNotificationCallback, mOnMenuEventListener);
+ }
+ }
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/HeadsUpManagerPhone.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/HeadsUpManagerPhone.java
index 8092cb910b07..3827123f0160 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/HeadsUpManagerPhone.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/HeadsUpManagerPhone.java
@@ -33,6 +33,7 @@ import com.android.systemui.plugins.statusbar.StatusBarStateController.StateList
import com.android.systemui.statusbar.StatusBarState;
import com.android.systemui.statusbar.notification.collection.NotificationEntry;
import com.android.systemui.statusbar.notification.collection.legacy.VisualStabilityManager;
+import com.android.systemui.statusbar.notification.collection.render.GroupMembershipManager;
import com.android.systemui.statusbar.notification.row.ExpandableNotificationRow;
import com.android.systemui.statusbar.policy.ConfigurationController;
import com.android.systemui.statusbar.policy.HeadsUpManager;
@@ -55,7 +56,7 @@ public class HeadsUpManagerPhone extends HeadsUpManager implements Dumpable,
@VisibleForTesting
final int mExtensionTime;
private final KeyguardBypassController mBypassController;
- private final NotificationGroupManager mGroupManager;
+ private final GroupMembershipManager mGroupMembershipManager;
private final List<OnHeadsUpPhoneListenerChange> mHeadsUpPhoneListeners = new ArrayList<>();
private final int mAutoHeadsUpNotificationDecay;
// TODO (b/162832756): remove visual stability manager when migrating to new pipeline
@@ -101,7 +102,7 @@ public class HeadsUpManagerPhone extends HeadsUpManager implements Dumpable,
public HeadsUpManagerPhone(@NonNull final Context context,
StatusBarStateController statusBarStateController,
KeyguardBypassController bypassController,
- NotificationGroupManager groupManager,
+ GroupMembershipManager groupMembershipManager,
ConfigurationController configurationController) {
super(context);
Resources resources = mContext.getResources();
@@ -110,7 +111,7 @@ public class HeadsUpManagerPhone extends HeadsUpManager implements Dumpable,
R.integer.auto_heads_up_notification_decay);
statusBarStateController.addCallback(mStatusBarStateListener);
mBypassController = bypassController;
- mGroupManager = groupManager;
+ mGroupMembershipManager = groupMembershipManager;
updateResources();
configurationController.addCallback(new ConfigurationController.ConfigurationListener() {
@@ -166,7 +167,7 @@ public class HeadsUpManagerPhone extends HeadsUpManager implements Dumpable,
} else {
if (topEntry.isChildInGroup()) {
final NotificationEntry groupSummary =
- mGroupManager.getGroupSummary(topEntry.getSbn());
+ mGroupMembershipManager.getGroupSummary(topEntry);
if (groupSummary != null) {
topEntry = groupSummary;
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardAffordanceHelper.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardAffordanceHelper.java
index 858023dc6c62..5dfb22faee7a 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardAffordanceHelper.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardAffordanceHelper.java
@@ -27,9 +27,10 @@ import android.view.ViewConfiguration;
import com.android.systemui.Interpolators;
import com.android.systemui.R;
+import com.android.systemui.classifier.Classifier;
import com.android.systemui.plugins.FalsingManager;
-import com.android.systemui.statusbar.FlingAnimationUtils;
import com.android.systemui.statusbar.KeyguardAffordanceView;
+import com.android.wm.shell.animation.FlingAnimationUtils;
/**
* A touch handler of the keyguard which is responsible for launching phone and camera affordances.
@@ -317,7 +318,9 @@ public class KeyguardAffordanceHelper {
// We snap back if the current translation is not far enough
boolean snapBack = false;
if (mCallback.needsAntiFalsing()) {
- snapBack = snapBack || mFalsingManager.isFalseTouch();
+ snapBack = snapBack || mFalsingManager.isFalseTouch(
+ mTargetedView == mRightIcon
+ ? Classifier.RIGHT_AFFORDANCE : Classifier.LEFT_AFFORDANCE);
}
snapBack = snapBack || isBelowFalsingThreshold();
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardBouncer.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardBouncer.java
index b6a284c5e3c4..09034c0899f5 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardBouncer.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardBouncer.java
@@ -40,6 +40,8 @@ import com.android.keyguard.KeyguardSecurityView;
import com.android.keyguard.KeyguardUpdateMonitor;
import com.android.keyguard.KeyguardUpdateMonitorCallback;
import com.android.keyguard.ViewMediatorCallback;
+import com.android.keyguard.dagger.ContainerView;
+import com.android.keyguard.dagger.KeyguardBouncerScope;
import com.android.systemui.DejankUtils;
import com.android.systemui.Dependency;
import com.android.systemui.R;
@@ -50,9 +52,12 @@ import com.android.systemui.statusbar.policy.KeyguardStateController;
import java.io.PrintWriter;
+import javax.inject.Inject;
+
/**
* A class which manages the bouncer on the lockscreen.
*/
+@KeyguardBouncerScope
public class KeyguardBouncer {
private static final String TAG = "KeyguardBouncer";
@@ -95,8 +100,9 @@ public class KeyguardBouncer {
private boolean mIsAnimatingAway;
private boolean mIsScrimmed;
+ @Inject
public KeyguardBouncer(Context context, ViewMediatorCallback callback,
- LockPatternUtils lockPatternUtils, ViewGroup container,
+ LockPatternUtils lockPatternUtils, @ContainerView ViewGroup container,
DismissCallbackRegistry dismissCallbackRegistry, FalsingManager falsingManager,
BouncerExpansionCallback expansionCallback,
KeyguardStateController keyguardStateController,
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationGroupAlertTransferHelper.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationGroupAlertTransferHelper.java
index dd9c8207af06..3181f520dca2 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationGroupAlertTransferHelper.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationGroupAlertTransferHelper.java
@@ -31,11 +31,11 @@ import com.android.systemui.statusbar.AlertingNotificationManager;
import com.android.systemui.statusbar.notification.NotificationEntryListener;
import com.android.systemui.statusbar.notification.NotificationEntryManager;
import com.android.systemui.statusbar.notification.collection.NotificationEntry;
+import com.android.systemui.statusbar.notification.collection.legacy.NotificationGroupManagerLegacy;
+import com.android.systemui.statusbar.notification.collection.legacy.NotificationGroupManagerLegacy.NotificationGroup;
import com.android.systemui.statusbar.notification.row.NotificationRowContentBinder.InflationFlag;
import com.android.systemui.statusbar.notification.row.RowContentBindParams;
import com.android.systemui.statusbar.notification.row.RowContentBindStage;
-import com.android.systemui.statusbar.phone.NotificationGroupManager.NotificationGroup;
-import com.android.systemui.statusbar.phone.NotificationGroupManager.OnGroupChangeListener;
import com.android.systemui.statusbar.phone.dagger.StatusBarPhoneModule;
import com.android.systemui.statusbar.policy.HeadsUpManager;
import com.android.systemui.statusbar.policy.OnHeadsUpChangedListener;
@@ -44,8 +44,8 @@ import java.util.ArrayList;
import java.util.Objects;
/**
- * A helper class dealing with the alert interactions between {@link NotificationGroupManager} and
- * {@link HeadsUpManager}. In particular, this class deals with keeping
+ * A helper class dealing with the alert interactions between {@link NotificationGroupManagerLegacy}
+ * and {@link HeadsUpManager}. In particular, this class deals with keeping
* the correct notification in a group alerting based off the group suppression.
*/
public class NotificationGroupAlertTransferHelper implements OnHeadsUpChangedListener,
@@ -66,8 +66,8 @@ public class NotificationGroupAlertTransferHelper implements OnHeadsUpChangedLis
private HeadsUpManager mHeadsUpManager;
private final RowContentBindStage mRowContentBindStage;
- private final NotificationGroupManager mGroupManager =
- Dependency.get(NotificationGroupManager.class);
+ private final NotificationGroupManagerLegacy mGroupManager =
+ Dependency.get(NotificationGroupManagerLegacy.class);
private NotificationEntryManager mEntryManager;
@@ -83,7 +83,7 @@ public class NotificationGroupAlertTransferHelper implements OnHeadsUpChangedLis
/** Causes the TransferHelper to register itself as a listener to the appropriate classes. */
public void bind(NotificationEntryManager entryManager,
- NotificationGroupManager groupManager) {
+ NotificationGroupManagerLegacy groupManager) {
if (mEntryManager != null) {
throw new IllegalStateException("Already bound.");
}
@@ -95,7 +95,7 @@ public class NotificationGroupAlertTransferHelper implements OnHeadsUpChangedLis
mEntryManager = entryManager;
mEntryManager.addNotificationEntryListener(mNotificationEntryListener);
- groupManager.addOnGroupChangeListener(mOnGroupChangeListener);
+ groupManager.registerGroupChangeListener(mOnGroupChangeListener);
}
/**
@@ -128,7 +128,8 @@ public class NotificationGroupAlertTransferHelper implements OnHeadsUpChangedLis
mIsDozing = isDozing;
}
- private final OnGroupChangeListener mOnGroupChangeListener = new OnGroupChangeListener() {
+ private final NotificationGroupManagerLegacy.OnGroupChangeListener mOnGroupChangeListener =
+ new NotificationGroupManagerLegacy.OnGroupChangeListener() {
@Override
public void onGroupCreated(NotificationGroup group, String groupKey) {
mGroupAlertEntries.put(groupKey, new GroupAlertEntry(group));
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 5974a53fc86d..cd9cc0775c66 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelViewController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelViewController.java
@@ -18,6 +18,8 @@ package com.android.systemui.statusbar.phone;
import static android.view.View.GONE;
+import static com.android.systemui.classifier.Classifier.QUICK_SETTINGS;
+import static com.android.systemui.statusbar.StatusBarState.KEYGUARD;
import static com.android.systemui.statusbar.notification.ActivityLaunchAnimator.ExpandAnimationParameters;
import static com.android.systemui.statusbar.notification.stack.NotificationStackScrollLayout.ROWS_ALL;
@@ -31,6 +33,7 @@ import android.app.Fragment;
import android.app.StatusBarManager;
import android.content.pm.ResolveInfo;
import android.content.res.Configuration;
+import android.content.res.Resources;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.ColorFilter;
@@ -66,10 +69,13 @@ import com.android.keyguard.KeyguardClockSwitchController;
import com.android.keyguard.KeyguardStatusView;
import com.android.keyguard.KeyguardUpdateMonitor;
import com.android.keyguard.KeyguardUpdateMonitorCallback;
+import com.android.keyguard.dagger.KeyguardStatusViewComponent;
import com.android.systemui.DejankUtils;
import com.android.systemui.Interpolators;
import com.android.systemui.R;
+import com.android.systemui.classifier.Classifier;
import com.android.systemui.dagger.qualifiers.DisplayId;
+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;
@@ -80,12 +86,10 @@ import com.android.systemui.plugins.statusbar.StatusBarStateController;
import com.android.systemui.plugins.statusbar.StatusBarStateController.StateListener;
import com.android.systemui.qs.QSFragment;
import com.android.systemui.statusbar.CommandQueue;
-import com.android.systemui.statusbar.FlingAnimationUtils;
import com.android.systemui.statusbar.GestureRecorder;
import com.android.systemui.statusbar.KeyguardAffordanceView;
import com.android.systemui.statusbar.KeyguardIndicationController;
import com.android.systemui.statusbar.NotificationLockscreenUserManager;
-import com.android.systemui.statusbar.NotificationShelf;
import com.android.systemui.statusbar.NotificationShelfController;
import com.android.systemui.statusbar.PulseExpansionHandler;
import com.android.systemui.statusbar.RemoteInputController;
@@ -102,6 +106,8 @@ import com.android.systemui.statusbar.notification.PropertyAnimator;
import com.android.systemui.statusbar.notification.ViewGroupFadeHelper;
import com.android.systemui.statusbar.notification.collection.ListEntry;
import com.android.systemui.statusbar.notification.collection.NotificationEntry;
+import com.android.systemui.statusbar.notification.collection.legacy.NotificationGroupManagerLegacy;
+import com.android.systemui.statusbar.notification.collection.render.ShadeViewManager;
import com.android.systemui.statusbar.notification.row.ActivatableNotificationView;
import com.android.systemui.statusbar.notification.row.ExpandableNotificationRow;
import com.android.systemui.statusbar.notification.row.ExpandableView;
@@ -115,8 +121,8 @@ import com.android.systemui.statusbar.policy.ConfigurationController;
import com.android.systemui.statusbar.policy.KeyguardStateController;
import com.android.systemui.statusbar.policy.KeyguardUserSwitcher;
import com.android.systemui.statusbar.policy.OnHeadsUpChangedListener;
-import com.android.systemui.statusbar.policy.ZenModeController;
import com.android.systemui.util.InjectionInflationController;
+import com.android.wm.shell.animation.FlingAnimationUtils;
import java.io.FileDescriptor;
import java.io.PrintWriter;
@@ -127,7 +133,6 @@ 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 {
@@ -164,9 +169,6 @@ public class NotificationPanelViewController extends PanelViewController {
mOnHeadsUpChangedListener =
new MyOnHeadsUpChangedListener();
private final HeightListener mHeightListener = new HeightListener();
- private final ZenModeControllerCallback
- mZenModeControllerCallback =
- new ZenModeControllerCallback();
private final ConfigurationListener mConfigurationListener = new ConfigurationListener();
private final StatusBarStateListener mStatusBarStateListener = new StatusBarStateListener();
private final ExpansionCallback mExpansionCallback = new ExpansionCallback();
@@ -174,7 +176,6 @@ public class NotificationPanelViewController extends PanelViewController {
private final NotificationPanelView mView;
private final MetricsLogger mMetricsLogger;
private final ActivityManager mActivityManager;
- private final ZenModeController mZenModeController;
private final ConfigurationController mConfigurationController;
private final FlingAnimationUtils.Builder mFlingAnimationUtilsBuilder;
private final NotificationStackScrollLayoutController mNotificationStackScrollLayoutController;
@@ -231,7 +232,7 @@ public class NotificationPanelViewController extends PanelViewController {
BiometricSourceType biometricSourceType) {
boolean
keyguardOrShadeLocked =
- mBarState == StatusBarState.KEYGUARD
+ mBarState == KEYGUARD
|| mBarState == StatusBarState.SHADE_LOCKED;
if (!running && mFirstBypassAttempt && keyguardOrShadeLocked && !mDozing
&& !mDelayShowingKeyguardStatusBar
@@ -258,7 +259,12 @@ public class NotificationPanelViewController extends PanelViewController {
private final ConversationNotificationManager mConversationNotificationManager;
private final MediaHierarchyManager mMediaHierarchyManager;
private final StatusBarKeyguardViewManager mStatusBarKeyguardViewManager;
- private final Provider<KeyguardClockSwitchController> mKeyguardClockSwitchControllerProvider;
+ private final KeyguardStatusViewComponent.Factory mKeyguardStatusViewComponentFactory;
+ // Maximum # notifications to show on Keyguard; extras will be collapsed in an overflow card.
+ // If there are exactly 1 + mMaxKeyguardNotifications, then still shows all notifications
+ private final int mMaxKeyguardNotifications;
+ // Current max allowed keyguard notifications determined by measuring the panel
+ private int mMaxAllowedKeyguardNotifications;
private KeyguardAffordanceHelper mAffordanceHelper;
private KeyguardUserSwitcher mKeyguardUserSwitcher;
@@ -333,8 +339,6 @@ public class NotificationPanelViewController extends PanelViewController {
private boolean mKeyguardStatusViewAnimating;
private ValueAnimator mQsSizeChangeAnimator;
- private boolean mShowEmptyShadeView;
-
private boolean mQsScrimEnabled = true;
private boolean mQsTouchAboveFalsingThreshold;
private int mQsFalsingThreshold;
@@ -358,7 +362,8 @@ public class NotificationPanelViewController extends PanelViewController {
setHeadsUpAnimatingAway(false);
notifyBarPanelExpansionChanged();
};
- private NotificationGroupManager mGroupManager;
+ // TODO (b/162832756): once migrated to the new pipeline, delete legacy group manager
+ private NotificationGroupManagerLegacy mGroupManager;
private boolean mShowIconsWhenExpanded;
private int mIndicationBottomPadding;
private int mAmbientIndicationBottomPadding;
@@ -482,6 +487,7 @@ public class NotificationPanelViewController extends PanelViewController {
@Inject
public NotificationPanelViewController(NotificationPanelView view,
+ @Main Resources resources,
InjectionInflationController injectionInflationController,
NotificationWakeUpCoordinator coordinator, PulseExpansionHandler pulseExpansionHandler,
DynamicPrivacyController dynamicPrivacyController,
@@ -495,7 +501,7 @@ public class NotificationPanelViewController extends PanelViewController {
LatencyTracker latencyTracker, PowerManager powerManager,
AccessibilityManager accessibilityManager, @DisplayId int displayId,
KeyguardUpdateMonitor keyguardUpdateMonitor, MetricsLogger metricsLogger,
- ActivityManager activityManager, ZenModeController zenModeController,
+ ActivityManager activityManager,
ConfigurationController configurationController,
FlingAnimationUtils.Builder flingAnimationUtilsBuilder,
StatusBarTouchableRegionManager statusBarTouchableRegionManager,
@@ -503,8 +509,9 @@ public class NotificationPanelViewController extends PanelViewController {
MediaHierarchyManager mediaHierarchyManager,
BiometricUnlockController biometricUnlockController,
StatusBarKeyguardViewManager statusBarKeyguardViewManager,
- Provider<KeyguardClockSwitchController> keyguardClockSwitchControllerProvider,
NotificationStackScrollLayoutController notificationStackScrollLayoutController,
+ KeyguardStatusViewComponent.Factory keyguardStatusViewComponentFactory,
+ NotificationGroupManagerLegacy groupManager,
NotificationIconAreaController notificationIconAreaController) {
super(view, falsingManager, dozeLog, keyguardStateController,
(SysuiStatusBarStateController) statusBarStateController, vibratorHelper,
@@ -512,14 +519,14 @@ public class NotificationPanelViewController extends PanelViewController {
mView = view;
mMetricsLogger = metricsLogger;
mActivityManager = activityManager;
- mZenModeController = zenModeController;
mConfigurationController = configurationController;
mFlingAnimationUtilsBuilder = flingAnimationUtilsBuilder;
mMediaHierarchyManager = mediaHierarchyManager;
mStatusBarKeyguardViewManager = statusBarKeyguardViewManager;
- mKeyguardClockSwitchControllerProvider = keyguardClockSwitchControllerProvider;
mNotificationStackScrollLayoutController = notificationStackScrollLayoutController;
+ mGroupManager = groupManager;
mNotificationIconAreaController = notificationIconAreaController;
+ mKeyguardStatusViewComponentFactory = keyguardStatusViewComponentFactory;
mView.setWillNotDraw(!DEBUG);
mInjectionInflationController = injectionInflationController;
mFalsingManager = falsingManager;
@@ -584,6 +591,7 @@ public class NotificationPanelViewController extends PanelViewController {
mView.getOverlay().add(new DebugDrawable());
}
+ mMaxKeyguardNotifications = resources.getInteger(R.integer.keyguard_max_notification_count);
onFinishInflate();
}
@@ -593,8 +601,10 @@ public class NotificationPanelViewController extends PanelViewController {
mKeyguardStatusView = mView.findViewById(R.id.keyguard_status_view);
KeyguardClockSwitchController keyguardClockSwitchController =
- mKeyguardClockSwitchControllerProvider.get();
- keyguardClockSwitchController.attach(mView.findViewById(R.id.keyguard_clock_container));
+ mKeyguardStatusViewComponentFactory
+ .build(mKeyguardStatusView)
+ .getKeyguardClockSwitchController();
+ keyguardClockSwitchController.init();
mBigClockContainer = mView.findViewById(R.id.big_clock_container);
keyguardClockSwitchController.setBigClockContainer(mBigClockContainer);
@@ -711,8 +721,6 @@ public class NotificationPanelViewController extends PanelViewController {
}
private void reInflateViews() {
- updateShowEmptyShadeView();
-
// Re-inflate the status view group.
int index = mView.indexOfChild(mKeyguardStatusView);
mView.removeView(mKeyguardStatusView);
@@ -724,8 +732,10 @@ public class NotificationPanelViewController extends PanelViewController {
// Re-associate the clock container with the keyguard clock switch.
mBigClockContainer.removeAllViews();
KeyguardClockSwitchController keyguardClockSwitchController =
- mKeyguardClockSwitchControllerProvider.get();
- keyguardClockSwitchController.attach(mView.findViewById(R.id.keyguard_clock_container));
+ mKeyguardStatusViewComponentFactory
+ .build(mKeyguardStatusView)
+ .getKeyguardClockSwitchController();
+ keyguardClockSwitchController.init();
keyguardClockSwitchController.setBigClockContainer(mBigClockContainer);
// Update keyguard bottom area
@@ -761,6 +771,20 @@ public class NotificationPanelViewController extends PanelViewController {
mKeyguardBottomArea.setUserSetupComplete(mUserSetupComplete);
}
+ private void updateMaxDisplayedNotifications(boolean recompute) {
+ if (recompute) {
+ mMaxAllowedKeyguardNotifications = Math.max(computeMaxKeyguardNotifications(), 1);
+ }
+
+ if (mKeyguardShowing && !mKeyguardBypassController.getBypassEnabled()) {
+ mNotificationStackScrollLayoutController.setMaxDisplayedNotifications(
+ mMaxAllowedKeyguardNotifications);
+ } else {
+ // no max when not on the keyguard
+ mNotificationStackScrollLayoutController.setMaxDisplayedNotifications(-1);
+ }
+ }
+
public void setKeyguardIndicationController(KeyguardIndicationController indicationController) {
mKeyguardIndicationController = indicationController;
mKeyguardIndicationController.setIndicationArea(mKeyguardBottomArea);
@@ -821,7 +845,7 @@ public class NotificationPanelViewController extends PanelViewController {
boolean animate = mNotificationStackScrollLayoutController.isAddOrRemoveAnimationPending();
boolean animateClock = animate || mAnimateNextPositionUpdate;
int stackScrollerPadding;
- if (mBarState != StatusBarState.KEYGUARD) {
+ if (mBarState != KEYGUARD) {
stackScrollerPadding = getUnlockedStackScrollerPadding();
} else {
int totalHeight = mView.getHeight();
@@ -865,20 +889,17 @@ public class NotificationPanelViewController extends PanelViewController {
}
/**
- * @param maximum the maximum to return at most
* @return the maximum keyguard notifications that can fit on the screen
*/
- public int computeMaxKeyguardNotifications(int maximum) {
+ private int computeMaxKeyguardNotifications() {
float minPadding = mClockPositionAlgorithm.getMinStackScrollerPadding();
int notificationPadding = Math.max(
1, mResources.getDimensionPixelSize(R.dimen.notification_divider_height));
- NotificationShelf shelf = mNotificationShelfController.getView();
- float
- shelfSize =
- shelf.getVisibility() == View.GONE ? 0
- : shelf.getIntrinsicHeight() + notificationPadding;
- float
- availableSpace =
+ float shelfSize =
+ mNotificationShelfController.getVisibility() == View.GONE
+ ? 0
+ : mNotificationShelfController.getIntrinsicHeight() + notificationPadding;
+ float availableSpace =
mNotificationStackScrollLayoutController.getHeight() - minPadding - shelfSize
- Math.max(mIndicationBottomPadding, mAmbientIndicationBottomPadding)
- mKeyguardStatusView.getLogoutButtonHeight();
@@ -908,7 +929,8 @@ public class NotificationPanelViewController extends PanelViewController {
availableSpace -= mNotificationStackScrollLayoutController
.calculateGapHeight(previousView, child, count);
previousView = child;
- if (availableSpace >= 0 && count < maximum) {
+ if (availableSpace >= 0
+ && (mMaxKeyguardNotifications == -1 || count < mMaxKeyguardNotifications)) {
count++;
} else if (availableSpace > -shelfSize) {
// if we are exactly the last view, then we can show us still!
@@ -1235,7 +1257,7 @@ public class NotificationPanelViewController extends PanelViewController {
float vel = getCurrentQSVelocity();
final int
gesture =
- mBarState == StatusBarState.KEYGUARD ? MetricsEvent.ACTION_LS_QS
+ mBarState == KEYGUARD ? MetricsEvent.ACTION_LS_QS
: MetricsEvent.ACTION_SHADE_QS_PULL;
mLockscreenGestureLogger.write(gesture,
(int) ((y - mInitialTouchY) / mStatusBar.getDisplayDensity()),
@@ -1243,7 +1265,7 @@ public class NotificationPanelViewController extends PanelViewController {
}
private boolean flingExpandsQs(float vel) {
- if (mFalsingManager.isUnlockingDisabled() || isFalseTouch()) {
+ if (mFalsingManager.isUnlockingDisabled() || isFalseTouch(QUICK_SETTINGS)) {
return false;
}
if (Math.abs(vel) < mFlingAnimationUtils.getMinVelocityPxPerSecond()) {
@@ -1253,12 +1275,12 @@ public class NotificationPanelViewController extends PanelViewController {
}
}
- private boolean isFalseTouch() {
+ private boolean isFalseTouch(@Classifier.InteractionType int interactionType) {
if (!mKeyguardAffordanceHelperCallback.needsAntiFalsing()) {
return false;
}
if (mFalsingManager.isClassifierEnabled()) {
- return mFalsingManager.isFalseTouch();
+ return mFalsingManager.isFalseTouch(interactionType);
}
return !mQsTouchAboveFalsingThreshold;
}
@@ -1292,7 +1314,7 @@ public class NotificationPanelViewController extends PanelViewController {
private boolean handleQsTouch(MotionEvent event) {
final int action = event.getActionMasked();
if (action == MotionEvent.ACTION_DOWN && getExpandedFraction() == 1f
- && mBarState != StatusBarState.KEYGUARD && !mQsExpanded && mQsExpansionEnabled) {
+ && mBarState != KEYGUARD && !mQsExpanded && mQsExpansionEnabled) {
// Down in the empty area while fully expanded - go to QS.
mQsTracking = true;
@@ -1646,7 +1668,7 @@ public class NotificationPanelViewController extends PanelViewController {
mKeyguardStateController.getShortenedFadingAwayDuration()).setInterpolator(
Interpolators.ALPHA_OUT).withEndAction(
mAnimateKeyguardBottomAreaInvisibleEndRunnable).start();
- } else if (statusBarState == StatusBarState.KEYGUARD
+ } else if (statusBarState == KEYGUARD
|| statusBarState == StatusBarState.SHADE_LOCKED) {
mKeyguardBottomArea.setVisibility(View.VISIBLE);
mKeyguardBottomArea.setAlpha(1f);
@@ -1659,8 +1681,8 @@ public class NotificationPanelViewController extends PanelViewController {
boolean goingToFullShade) {
mKeyguardStatusView.animate().cancel();
mKeyguardStatusViewAnimating = false;
- if ((!keyguardFadingAway && mBarState == StatusBarState.KEYGUARD
- && statusBarState != StatusBarState.KEYGUARD) || goingToFullShade) {
+ if ((!keyguardFadingAway && mBarState == KEYGUARD
+ && statusBarState != KEYGUARD) || goingToFullShade) {
mKeyguardStatusViewAnimating = true;
mKeyguardStatusView.animate().alpha(0f).setStartDelay(0).setDuration(
160).setInterpolator(Interpolators.ALPHA_OUT).withEndAction(
@@ -1671,14 +1693,14 @@ public class NotificationPanelViewController extends PanelViewController {
mKeyguardStateController.getShortenedFadingAwayDuration()).start();
}
} else if (mBarState == StatusBarState.SHADE_LOCKED
- && statusBarState == StatusBarState.KEYGUARD) {
+ && statusBarState == KEYGUARD) {
mKeyguardStatusView.setVisibility(View.VISIBLE);
mKeyguardStatusViewAnimating = true;
mKeyguardStatusView.setAlpha(0f);
mKeyguardStatusView.animate().alpha(1f).setStartDelay(0).setDuration(
320).setInterpolator(Interpolators.ALPHA_IN).withEndAction(
mAnimateKeyguardStatusViewVisibleEndRunnable);
- } else if (statusBarState == StatusBarState.KEYGUARD) {
+ } else if (statusBarState == KEYGUARD) {
if (keyguardFadingAway) {
mKeyguardStatusViewAnimating = true;
mKeyguardStatusView.animate().alpha(0).translationYBy(
@@ -1698,9 +1720,8 @@ public class NotificationPanelViewController extends PanelViewController {
private void updateQsState() {
mNotificationStackScrollLayoutController.setQsExpanded(mQsExpanded);
mNotificationStackScrollLayoutController.setScrollingEnabled(
- mBarState != StatusBarState.KEYGUARD && (!mQsExpanded
+ mBarState != KEYGUARD && (!mQsExpanded
|| mQsExpansionFromOverscroll));
- updateEmptyShadeView();
mQsNavbarScrim.setVisibility(
mBarState == StatusBarState.SHADE && mQsExpanded && !mStackScrollerOverscrolling
@@ -1725,7 +1746,7 @@ public class NotificationPanelViewController extends PanelViewController {
updateQsExpansion();
requestScrollerTopPaddingUpdate(false /* animate */);
updateHeaderKeyguardAlpha();
- if (mBarState == StatusBarState.SHADE_LOCKED || mBarState == StatusBarState.KEYGUARD) {
+ if (mBarState == StatusBarState.SHADE_LOCKED || mBarState == KEYGUARD) {
updateKeyguardBottomAreaAlpha();
updateBigClockAlpha();
}
@@ -1767,7 +1788,7 @@ public class NotificationPanelViewController extends PanelViewController {
// Upon initialisation when we are not layouted yet we don't want to announce that we
// are fully expanded, hence the != 0.0f check.
return mResources.getString(R.string.accessibility_desc_quick_settings);
- } else if (mBarState == StatusBarState.KEYGUARD) {
+ } else if (mBarState == KEYGUARD) {
return mResources.getString(R.string.accessibility_desc_lock_screen);
} else {
return mResources.getString(R.string.accessibility_desc_notification_shade);
@@ -1785,7 +1806,7 @@ public class NotificationPanelViewController extends PanelViewController {
// for a nice motion.
int maxNotificationPadding = getKeyguardNotificationStaticPadding();
int maxQsPadding = mQsMaxExpansionHeight + mQsNotificationTopPadding;
- int max = mBarState == StatusBarState.KEYGUARD ? Math.max(
+ int max = mBarState == KEYGUARD ? Math.max(
maxNotificationPadding, maxQsPadding) : maxQsPadding;
return (int) MathUtils.lerp((float) mQsMinExpansionHeight, (float) max,
getExpandedFraction());
@@ -1973,7 +1994,7 @@ public class NotificationPanelViewController extends PanelViewController {
@Override
protected boolean canCollapsePanelOnTouch() {
if (!isInSettings()) {
- return mBarState == StatusBarState.KEYGUARD
+ return mBarState == KEYGUARD
|| mIsPanelCollapseOnQQS
|| mNotificationStackScrollLayoutController.isScrolledToBottom();
} else {
@@ -1983,7 +2004,7 @@ public class NotificationPanelViewController extends PanelViewController {
@Override
protected int getMaxPanelHeight() {
- if (mKeyguardBypassController.getBypassEnabled() && mBarState == StatusBarState.KEYGUARD) {
+ if (mKeyguardBypassController.getBypassEnabled() && mBarState == KEYGUARD) {
return getMaxPanelHeightBypass();
} else {
return getMaxPanelHeightNonBypass();
@@ -1992,7 +2013,7 @@ public class NotificationPanelViewController extends PanelViewController {
private int getMaxPanelHeightNonBypass() {
int min = mStatusBarMinHeight;
- if (!(mBarState == StatusBarState.KEYGUARD)
+ if (!(mBarState == KEYGUARD)
&& mNotificationStackScrollLayoutController.getNotGoneChildCount() == 0) {
int minHeight = (int) (mQsMinExpansionHeight + getOverExpansionAmount());
min = Math.max(min, minHeight);
@@ -2095,7 +2116,7 @@ public class NotificationPanelViewController extends PanelViewController {
int maxHeight = mNotificationStackScrollLayoutController.getHeight() - emptyBottomMargin;
maxHeight += mNotificationStackScrollLayoutController.getTopPaddingOverflow();
- if (mBarState == StatusBarState.KEYGUARD) {
+ if (mBarState == KEYGUARD) {
int
minKeyguardPanelBottom =
mClockPositionAlgorithm.getExpandedClockPosition()
@@ -2118,7 +2139,7 @@ public class NotificationPanelViewController extends PanelViewController {
// it in expanded QS state as well so we don't run into troubles when fading the view in/out
// and expanding/collapsing the whole panel from/to quick settings.
if (mNotificationStackScrollLayoutController.getNotGoneChildCount() == 0
- && mShowEmptyShadeView) {
+ && mNotificationStackScrollLayoutController.isShowingEmptyShadeView()) {
notificationHeight = mNotificationStackScrollLayoutController.getEmptyShadeViewHeight();
}
int maxQsHeight = mQsMaxExpansionHeight;
@@ -2132,7 +2153,7 @@ public class NotificationPanelViewController extends PanelViewController {
maxQsHeight = (int) mQsSizeChangeAnimator.getAnimatedValue();
}
float totalHeight = Math.max(maxQsHeight,
- mBarState == StatusBarState.KEYGUARD ? mClockPositionResult.stackScrollerPadding
+ mBarState == KEYGUARD ? mClockPositionResult.stackScrollerPadding
: 0) + notificationHeight
+ mNotificationStackScrollLayoutController.getTopPaddingOverflow();
if (totalHeight > mNotificationStackScrollLayoutController.getHeight()) {
@@ -2151,7 +2172,7 @@ public class NotificationPanelViewController extends PanelViewController {
&& !mHeadsUpManager.hasPinnedHeadsUp()) {
alpha = getFadeoutAlpha();
}
- if (mBarState == StatusBarState.KEYGUARD && !mHintAnimationRunning
+ if (mBarState == KEYGUARD && !mHintAnimationRunning
&& !mKeyguardBypassController.getBypassEnabled()) {
alpha *= mClockPositionResult.clockAlpha;
}
@@ -2190,14 +2211,14 @@ public class NotificationPanelViewController extends PanelViewController {
* Hides the header when notifications are colliding with it.
*/
private void updateHeader() {
- if (mBarState == StatusBarState.KEYGUARD) {
+ if (mBarState == KEYGUARD) {
updateHeaderKeyguardAlpha();
}
updateQsExpansion();
}
protected float getHeaderTranslation() {
- if (mBarState == StatusBarState.KEYGUARD && !mKeyguardBypassController.getBypassEnabled()) {
+ if (mBarState == KEYGUARD && !mKeyguardBypassController.getBypassEnabled()) {
return -mQs.getQsMinExpansionHeight();
}
float appearAmount = mNotificationStackScrollLayoutController
@@ -2227,7 +2248,7 @@ public class NotificationPanelViewController extends PanelViewController {
*/
private float getKeyguardContentsAlpha() {
float alpha;
- if (mBarState == StatusBarState.KEYGUARD) {
+ if (mBarState == KEYGUARD) {
// When on Keyguard, we hide the header as soon as we expanded close enough to the
// header
@@ -2376,7 +2397,7 @@ public class NotificationPanelViewController extends PanelViewController {
if (mConflictingQsExpansionGesture || mQsExpandImmediate) {
return;
}
- if (mBarState != StatusBarState.KEYGUARD) {
+ if (mBarState != KEYGUARD) {
mNotificationStackScrollLayoutController.setOnHeightChangedListener(null);
if (isPixels) {
mNotificationStackScrollLayoutController.setOverScrolledPixels(
@@ -2398,7 +2419,7 @@ public class NotificationPanelViewController extends PanelViewController {
mQsExpandImmediate = true;
mNotificationStackScrollLayoutController.setShouldShowShelfOnly(true);
}
- if (mBarState == StatusBarState.KEYGUARD || mBarState == StatusBarState.SHADE_LOCKED) {
+ if (mBarState == KEYGUARD || mBarState == StatusBarState.SHADE_LOCKED) {
mAffordanceHelper.animateHideLeftRightIcon();
}
mNotificationStackScrollLayoutController.onPanelTrackingStarted();
@@ -2413,7 +2434,7 @@ public class NotificationPanelViewController extends PanelViewController {
true /* animate */);
}
mNotificationStackScrollLayoutController.onPanelTrackingStopped();
- if (expand && (mBarState == StatusBarState.KEYGUARD
+ if (expand && (mBarState == KEYGUARD
|| mBarState == StatusBarState.SHADE_LOCKED)) {
if (!mHintAnimationRunning) {
mAffordanceHelper.reset(true);
@@ -2534,17 +2555,6 @@ public class NotificationPanelViewController extends PanelViewController {
return mDozing;
}
- public void showEmptyShadeView(boolean emptyShadeViewVisible) {
- mShowEmptyShadeView = emptyShadeViewVisible;
- updateEmptyShadeView();
- }
-
- private void updateEmptyShadeView() {
- // Hide "No notifications" in QS.
- mNotificationStackScrollLayoutController.updateEmptyShadeView(
- mShowEmptyShadeView && !mQsExpanded);
- }
-
public void setQsScrimEnabled(boolean qsScrimEnabled) {
boolean changed = mQsScrimEnabled != qsScrimEnabled;
mQsScrimEnabled = qsScrimEnabled;
@@ -2564,7 +2574,7 @@ public class NotificationPanelViewController extends PanelViewController {
@Override
protected boolean onMiddleClicked() {
switch (mBarState) {
- case StatusBarState.KEYGUARD:
+ case KEYGUARD:
if (!mDozingOnDown) {
if (mKeyguardBypassController.getBypassEnabled()) {
mUpdateMonitor.requestFaceAuth();
@@ -2579,7 +2589,7 @@ public class NotificationPanelViewController extends PanelViewController {
return true;
case StatusBarState.SHADE_LOCKED:
if (!mQsExpanded) {
- mStatusBarStateController.setState(StatusBarState.KEYGUARD);
+ mStatusBarStateController.setState(KEYGUARD);
}
return true;
case StatusBarState.SHADE:
@@ -2750,7 +2760,7 @@ public class NotificationPanelViewController extends PanelViewController {
}
private boolean isOnKeyguard() {
- return mBarState == StatusBarState.KEYGUARD;
+ return mBarState == KEYGUARD;
}
public void setPanelScrimMinFraction(float minFraction) {
@@ -2846,10 +2856,6 @@ public class NotificationPanelViewController extends PanelViewController {
return !tasks.isEmpty() && pkgName.equals(tasks.get(0).topActivity.getPackageName());
}
- private void setGroupManager(NotificationGroupManager groupManager) {
- mGroupManager = groupManager;
- }
-
public boolean hideStatusBarIconsWhenExpanded() {
if (mLaunchingNotification) {
return mHideIconsDuringNotificationLaunch;
@@ -2925,7 +2931,7 @@ public class NotificationPanelViewController extends PanelViewController {
mBottomAreaShadeAlphaAnimator.cancel();
}
- if (mBarState == StatusBarState.KEYGUARD || mBarState == StatusBarState.SHADE_LOCKED) {
+ if (mBarState == KEYGUARD || mBarState == StatusBarState.SHADE_LOCKED) {
updateDozingVisibilities(animate);
}
@@ -2953,7 +2959,7 @@ public class NotificationPanelViewController extends PanelViewController {
public void setAmbientIndicationBottomPadding(int ambientIndicationBottomPadding) {
if (mAmbientIndicationBottomPadding != ambientIndicationBottomPadding) {
mAmbientIndicationBottomPadding = ambientIndicationBottomPadding;
- mStatusBar.updateKeyguardMaxNotifications();
+ updateMaxDisplayedNotifications(true);
}
}
@@ -3045,31 +3051,26 @@ public class NotificationPanelViewController extends PanelViewController {
if (mKeyguardStatusBar != null) {
mKeyguardStatusBar.dump(fd, pw, args);
}
- if (mKeyguardStatusView != null) {
- mKeyguardStatusView.dump(fd, pw, args);
- }
}
public boolean hasActiveClearableNotifications() {
return mNotificationStackScrollLayoutController.hasActiveClearableNotifications(ROWS_ALL);
}
- private void updateShowEmptyShadeView() {
- boolean
- showEmptyShadeView =
- mBarState != StatusBarState.KEYGUARD && !mEntryManager.hasActiveNotifications();
- showEmptyShadeView(showEmptyShadeView);
- }
-
public RemoteInputController.Delegate createRemoteInputDelegate() {
return mNotificationStackScrollLayoutController.createDelegate();
}
- void updateNotificationViews(String reason) {
+ /**
+ * Updates the notification views' sections and status bar icons. This is
+ * triggered by the NotificationPresenter whenever there are changes to the underlying
+ * notification data being displayed. In the new notification pipeline, this is handled in
+ * {@link ShadeViewManager}.
+ */
+ public void updateNotificationViews(String reason) {
mNotificationStackScrollLayoutController.updateSectionBoundaries(reason);
- mNotificationStackScrollLayoutController.updateSpeedBumpIndex();
mNotificationStackScrollLayoutController.updateFooter();
- updateShowEmptyShadeView();
+
mNotificationIconAreaController.updateNotificationIcons(createVisibleEntriesList());
}
@@ -3115,18 +3116,12 @@ public class NotificationPanelViewController extends PanelViewController {
*/
public void initDependencies(
StatusBar statusBar,
- NotificationGroupManager groupManager,
- NotificationShelfController notificationShelfController,
- ScrimController scrimController) {
+ NotificationShelfController notificationShelfController) {
setStatusBar(statusBar);
- setGroupManager(mGroupManager);
mNotificationStackScrollLayoutController.setNotificationPanelController(this);
- mNotificationStackScrollLayoutController.setStatusBar(statusBar);
- mNotificationStackScrollLayoutController.setGroupManager(groupManager);
mNotificationStackScrollLayoutController.setShelfController(notificationShelfController);
- mNotificationStackScrollLayoutController.setScrimController(scrimController);
- updateShowEmptyShadeView();
mNotificationShelfController = notificationShelfController;
+ updateMaxDisplayedNotifications(true);
}
public void showTransientIndication(int id) {
@@ -3506,7 +3501,7 @@ public class NotificationPanelViewController extends PanelViewController {
@Override
public boolean needsAntiFalsing() {
- return mBarState == StatusBarState.KEYGUARD;
+ return mBarState == KEYGUARD;
}
}
@@ -3521,7 +3516,6 @@ public class NotificationPanelViewController extends PanelViewController {
private class MyOnHeadsUpChangedListener implements OnHeadsUpChangedListener {
@Override
public void onHeadsUpPinnedModeChanged(final boolean inPinnedMode) {
- mNotificationStackScrollLayoutController.setInHeadsUpPinnedMode(inPinnedMode);
if (inPinnedMode) {
mHeadsUpExistenceChangedRunnable.run();
updateNotificationTranslucency();
@@ -3580,20 +3574,8 @@ public class NotificationPanelViewController extends PanelViewController {
}
}
- private class ZenModeControllerCallback implements ZenModeController.Callback {
- @Override
- public void onZenChanged(int zen) {
- updateShowEmptyShadeView();
- }
- }
-
private class ConfigurationListener implements ConfigurationController.ConfigurationListener {
@Override
- public void onDensityOrFontScaleChanged() {
- updateShowEmptyShadeView();
- }
-
- @Override
public void onThemeChanged() {
final int themeResId = mView.getContext().getThemeResId();
if (mThemeResId == themeResId) {
@@ -3619,14 +3601,15 @@ public class NotificationPanelViewController extends PanelViewController {
boolean goingToFullShade = mStatusBarStateController.goingToFullShade();
boolean keyguardFadingAway = mKeyguardStateController.isKeyguardFadingAway();
int oldState = mBarState;
- boolean keyguardShowing = statusBarState == StatusBarState.KEYGUARD;
+ boolean keyguardShowing = statusBarState == KEYGUARD;
+
setKeyguardStatusViewVisibility(statusBarState, keyguardFadingAway, goingToFullShade);
setKeyguardBottomAreaVisibility(statusBarState, goingToFullShade);
mBarState = statusBarState;
mKeyguardShowing = keyguardShowing;
- if (oldState == StatusBarState.KEYGUARD && (goingToFullShade
+ if (oldState == KEYGUARD && (goingToFullShade
|| statusBarState == StatusBarState.SHADE_LOCKED)) {
animateKeyguardStatusBarOut();
long
@@ -3635,7 +3618,7 @@ public class NotificationPanelViewController extends PanelViewController {
: mKeyguardStateController.calculateGoingToFullShadeDelay();
mQs.animateHeaderSlidingIn(delay);
} else if (oldState == StatusBarState.SHADE_LOCKED
- && statusBarState == StatusBarState.KEYGUARD) {
+ && statusBarState == KEYGUARD) {
animateKeyguardStatusBarIn(StackStateAnimator.ANIMATION_DURATION_STANDARD);
mNotificationStackScrollLayoutController.resetScrollPosition();
// Only animate header if the header is visible. If not, it will partially
@@ -3657,7 +3640,9 @@ public class NotificationPanelViewController extends PanelViewController {
if (keyguardShowing) {
updateDozingVisibilities(false /* animate */);
}
- // THe update needs to happen after the headerSlide in above, otherwise the translation
+
+ updateMaxDisplayedNotifications(false);
+ // The update needs to happen after the headerSlide in above, otherwise the translation
// would reset
updateQSPulseExpansion();
maybeAnimateBottomAreaAlpha();
@@ -3687,7 +3672,6 @@ public class NotificationPanelViewController extends PanelViewController {
public void onViewAttachedToWindow(View v) {
FragmentHostManager.get(mView).addTagListener(QS.TAG, mFragmentListener);
mStatusBarStateController.addCallback(mStatusBarStateListener);
- mZenModeController.addCallback(mZenModeControllerCallback);
mConfigurationController.addCallback(mConfigurationListener);
mUpdateMonitor.registerCallback(mKeyguardUpdateCallback);
// Theme might have changed between inflating this view and attaching it to the
@@ -3700,7 +3684,6 @@ public class NotificationPanelViewController extends PanelViewController {
public void onViewDetachedFromWindow(View v) {
FragmentHostManager.get(mView).removeTagListener(QS.TAG, mFragmentListener);
mStatusBarStateController.removeCallback(mStatusBarStateListener);
- mZenModeController.removeCallback(mZenModeControllerCallback);
mConfigurationController.removeCallback(mConfigurationListener);
mUpdateMonitor.removeCallback(mKeyguardUpdateCallback);
}
@@ -3713,6 +3696,7 @@ public class NotificationPanelViewController extends PanelViewController {
int oldTop, int oldRight, int oldBottom) {
DejankUtils.startDetectingBlockingIpcs("NVP#onLayout");
super.onLayoutChange(v, left, top, right, bottom, oldLeft, oldTop, oldRight, oldBottom);
+ updateMaxDisplayedNotifications(true);
setIsFullWidth(mNotificationStackScrollLayoutController.getWidth() == mView.getWidth());
// Update Clock Pivot
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationShadeWindowControllerImpl.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationShadeWindowControllerImpl.java
index 5abc42613fd1..9ea402d4e6df 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationShadeWindowControllerImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationShadeWindowControllerImpl.java
@@ -652,6 +652,7 @@ public class NotificationShadeWindowControllerImpl implements NotificationShadeW
pw.println(TAG + ":");
pw.println(" mKeyguardDisplayMode=" + mKeyguardDisplayMode);
pw.println(mCurrentState);
+ mNotificationShadeView.getViewRootImpl().dump(" ", fd, pw, args);
}
@Override
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationShadeWindowViewController.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationShadeWindowViewController.java
index 53cc2676723c..a3d3c2bb0af5 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationShadeWindowViewController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationShadeWindowViewController.java
@@ -52,6 +52,7 @@ import com.android.systemui.statusbar.notification.DynamicPrivacyController;
import com.android.systemui.statusbar.notification.NotificationEntryManager;
import com.android.systemui.statusbar.notification.NotificationWakeUpCoordinator;
import com.android.systemui.statusbar.notification.stack.NotificationStackScrollLayout;
+import com.android.systemui.statusbar.notification.stack.NotificationStackScrollLayoutController;
import com.android.systemui.statusbar.policy.KeyguardStateController;
import com.android.systemui.tuner.TunerService;
import com.android.systemui.util.InjectionInflationController;
@@ -83,6 +84,7 @@ public class NotificationShadeWindowViewController {
private final NotificationShadeWindowView mView;
private final ShadeController mShadeController;
private final NotificationShadeDepthController mDepthController;
+ private final NotificationStackScrollLayoutController mNotificationStackScrollLayoutController;
private GestureDetector mGestureDetector;
private View mBrightnessMirror;
@@ -130,7 +132,8 @@ public class NotificationShadeWindowViewController {
NotificationShadeDepthController depthController,
NotificationShadeWindowView notificationShadeWindowView,
NotificationPanelViewController notificationPanelViewController,
- SuperStatusBarViewFactory statusBarViewFactory) {
+ SuperStatusBarViewFactory statusBarViewFactory,
+ NotificationStackScrollLayoutController notificationStackScrollLayoutController) {
mInjectionInflationController = injectionInflationController;
mCoordinator = coordinator;
mPulseExpansionHandler = pulseExpansionHandler;
@@ -152,6 +155,7 @@ public class NotificationShadeWindowViewController {
mNotificationPanelViewController = notificationPanelViewController;
mDepthController = depthController;
mStatusBarViewFactory = statusBarViewFactory;
+ mNotificationStackScrollLayoutController = notificationStackScrollLayoutController;
// This view is not part of the newly inflated expanded status bar.
mBrightnessMirror = mView.findViewById(R.id.brightness_mirror);
@@ -245,7 +249,7 @@ public class NotificationShadeWindowViewController {
}
}
if (isDown) {
- mStackScrollLayout.closeControlsIfOutsideTouch(ev);
+ mNotificationStackScrollLayoutController.closeControlsIfOutsideTouch(ev);
}
if (mStatusBarStateController.isDozing()) {
mService.mDozeScrimController.extendPulse();
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PanelViewController.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PanelViewController.java
index ac329e2598a9..6fa99ba41006 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PanelViewController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PanelViewController.java
@@ -16,6 +16,10 @@
package com.android.systemui.statusbar.phone;
+import static com.android.systemui.classifier.Classifier.BOUNCER_UNLOCK;
+import static com.android.systemui.classifier.Classifier.QUICK_SETTINGS;
+import static com.android.systemui.classifier.Classifier.UNLOCK;
+
import static java.lang.Float.isNaN;
import android.animation.Animator;
@@ -41,14 +45,15 @@ import com.android.internal.util.LatencyTracker;
import com.android.systemui.DejankUtils;
import com.android.systemui.Interpolators;
import com.android.systemui.R;
+import com.android.systemui.classifier.Classifier;
import com.android.systemui.doze.DozeLog;
import com.android.systemui.plugins.FalsingManager;
-import com.android.systemui.statusbar.FlingAnimationUtils;
import com.android.systemui.statusbar.StatusBarState;
import com.android.systemui.statusbar.SysuiStatusBarStateController;
import com.android.systemui.statusbar.VibratorHelper;
import com.android.systemui.statusbar.phone.LockscreenGestureLogger.LockscreenUiEvent;
import com.android.systemui.statusbar.policy.KeyguardStateController;
+import com.android.wm.shell.animation.FlingAnimationUtils;
import java.io.FileDescriptor;
import java.io.PrintWriter;
@@ -397,7 +402,12 @@ public abstract class PanelViewController {
mLockscreenGestureLogger.write(MetricsEvent.ACTION_LS_UNLOCK, heightDp, velocityDp);
mLockscreenGestureLogger.log(LockscreenUiEvent.LOCKSCREEN_UNLOCK);
}
- fling(vel, expand, isFalseTouch(x, y));
+ @Classifier.InteractionType int interactionType = vel > 0
+ ? QUICK_SETTINGS : (
+ mKeyguardStateController.canDismissLockScreen()
+ ? UNLOCK : BOUNCER_UNLOCK);
+
+ fling(vel, expand, isFalseTouch(x, y, interactionType));
onTrackingStopped(expand);
mUpdateFlingOnLayout = expand && mPanelClosedOnDown && !mHasLayoutedSinceDown;
if (mUpdateFlingOnLayout) {
@@ -492,7 +502,11 @@ public abstract class PanelViewController {
return true;
}
- if (isFalseTouch(x, y)) {
+ @Classifier.InteractionType int interactionType = vel > 0
+ ? QUICK_SETTINGS : (
+ mKeyguardStateController.canDismissLockScreen() ? UNLOCK : BOUNCER_UNLOCK);
+
+ if (isFalseTouch(x, y, interactionType)) {
return true;
}
if (Math.abs(vectorVel) < mFlingAnimationUtils.getMinVelocityPxPerSecond()) {
@@ -511,12 +525,13 @@ public abstract class PanelViewController {
* @param y the final y-coordinate when the finger was lifted
* @return whether this motion should be regarded as a false touch
*/
- private boolean isFalseTouch(float x, float y) {
+ private boolean isFalseTouch(float x, float y,
+ @Classifier.InteractionType int interactionType) {
if (!mStatusBar.isFalsingThresholdNeeded()) {
return false;
}
if (mFalsingManager.isClassifierEnabled()) {
- return mFalsingManager.isFalseTouch();
+ return mFalsingManager.isFalseTouch(interactionType);
}
if (!mTouchAboveFalsingThreshold) {
return true;
@@ -1325,7 +1340,6 @@ public abstract class PanelViewController {
@Override
public void onLayoutChange(View v, int left, int top, int right, int bottom, int oldLeft,
int oldTop, int oldRight, int oldBottom) {
- mStatusBar.onPanelLaidOut();
requestPanelHeightUpdate();
mHasLayoutedSinceDown = true;
if (mUpdateFlingOnLayout) {
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 11d05830d065..e95cf2806691 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/ScrimController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/ScrimController.java
@@ -141,6 +141,8 @@ public class ScrimController implements ViewTreeObserver.OnPreDrawListener, OnCo
private ScrimView mScrimBehind;
private ScrimView mScrimForBubble;
+ private Runnable mScrimBehindChangeRunnable;
+
private final KeyguardStateController mKeyguardStateController;
private final KeyguardUpdateMonitor mKeyguardUpdateMonitor;
private final DozeParameters mDozeParameters;
@@ -241,6 +243,11 @@ public class ScrimController implements ViewTreeObserver.OnPreDrawListener, OnCo
mScrimInFront = scrimInFront;
mScrimForBubble = scrimForBubble;
+ if (mScrimBehindChangeRunnable != null) {
+ mScrimBehind.setChangeRunnable(mScrimBehindChangeRunnable);
+ mScrimBehindChangeRunnable = null;
+ }
+
final ScrimState[] states = ScrimState.values();
for (int i = 0; i < states.length; i++) {
states[i].init(mScrimInFront, mScrimBehind, mScrimForBubble, mDozeParameters,
@@ -934,7 +941,13 @@ public class ScrimController implements ViewTreeObserver.OnPreDrawListener, OnCo
}
public void setScrimBehindChangeRunnable(Runnable changeRunnable) {
- mScrimBehind.setChangeRunnable(changeRunnable);
+ // TODO: remove this. This is necessary because of an order-of-operations limitation.
+ // The fix is to move more of these class into @StatusBarScope
+ if (mScrimBehind == null) {
+ mScrimBehindChangeRunnable = changeRunnable;
+ } else {
+ mScrimBehind.setChangeRunnable(changeRunnable);
+ }
}
public void setCurrentUser(int currentUser) {
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 9391104fc2b4..31c1a5e5a9aa 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBar.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBar.java
@@ -177,7 +177,6 @@ import com.android.systemui.recents.Recents;
import com.android.systemui.recents.ScreenPinningRequest;
import com.android.systemui.shared.plugins.PluginManager;
import com.android.systemui.shared.system.WindowManagerWrapper;
-import com.android.systemui.stackdivider.SplitScreenController;
import com.android.systemui.statusbar.AutoHideUiElement;
import com.android.systemui.statusbar.BackDropView;
import com.android.systemui.statusbar.CommandQueue;
@@ -231,6 +230,7 @@ import com.android.systemui.statusbar.policy.RemoteInputQuickSettingsDisabler;
import com.android.systemui.statusbar.policy.UserInfoControllerImpl;
import com.android.systemui.statusbar.policy.UserSwitcherController;
import com.android.systemui.volume.VolumeComponent;
+import com.android.wm.shell.splitscreen.SplitScreen;
import java.io.FileDescriptor;
import java.io.PrintWriter;
@@ -388,7 +388,7 @@ public class StatusBar extends SystemUI implements DemoMode,
private final Lazy<BiometricUnlockController> mBiometricUnlockControllerLazy;
private final Provider<StatusBarComponent.Builder> mStatusBarComponentBuilder;
private final PluginManager mPluginManager;
- private final Optional<SplitScreenController> mSplitScreenControllerOptional;
+ private final Optional<SplitScreen> mSplitScreenOptional;
private final StatusBarNotificationActivityStarter.Builder
mStatusBarNotificationActivityStarterBuilder;
private final ShadeController mShadeController;
@@ -699,7 +699,6 @@ public class StatusBar extends SystemUI implements DemoMode,
SysuiStatusBarStateController statusBarStateController,
VibratorHelper vibratorHelper,
BubbleController bubbleController,
- NotificationGroupManager groupManager,
VisualStabilityManager visualStabilityManager,
DeviceProvisionedController deviceProvisionedController,
NavigationBarController navigationBarController,
@@ -721,7 +720,7 @@ public class StatusBar extends SystemUI implements DemoMode,
Optional<Recents> recentsOptional,
Provider<StatusBarComponent.Builder> statusBarComponentBuilder,
PluginManager pluginManager,
- Optional<SplitScreenController> splitScreenControllerOptional,
+ Optional<SplitScreen> splitScreenOptional,
LightsOutNotifController lightsOutNotifController,
StatusBarNotificationActivityStarter.Builder
statusBarNotificationActivityStarterBuilder,
@@ -780,7 +779,6 @@ public class StatusBar extends SystemUI implements DemoMode,
mStatusBarStateController = statusBarStateController;
mVibratorHelper = vibratorHelper;
mBubbleController = bubbleController;
- mGroupManager = groupManager;
mVisualStabilityManager = visualStabilityManager;
mDeviceProvisionedController = deviceProvisionedController;
mNavigationBarController = navigationBarController;
@@ -803,7 +801,7 @@ public class StatusBar extends SystemUI implements DemoMode,
mRecentsOptional = recentsOptional;
mStatusBarComponentBuilder = statusBarComponentBuilder;
mPluginManager = pluginManager;
- mSplitScreenControllerOptional = splitScreenControllerOptional;
+ mSplitScreenOptional = splitScreenOptional;
mStatusBarNotificationActivityStarterBuilder = statusBarNotificationActivityStarterBuilder;
mShadeController = shadeController;
mSuperStatusBarViewFactory = superStatusBarViewFactory;
@@ -1159,9 +1157,7 @@ public class StatusBar extends SystemUI implements DemoMode,
mNotificationPanelViewController.initDependencies(
this,
- mGroupManager,
- mNotificationShelfController,
- mScrimController);
+ mNotificationShelfController);
BackDropView backdrop = mNotificationShadeWindowView.findViewById(R.id.backdrop);
mMediaManager.setup(backdrop, backdrop.findViewById(R.id.backdrop_front),
@@ -1507,9 +1503,8 @@ public class StatusBar extends SystemUI implements DemoMode,
mStatusBarKeyguardViewManager.registerStatusBar(
/* statusBar= */ this, getBouncerContainer(),
mNotificationPanelViewController, mBiometricUnlockController,
- mDismissCallbackRegistry,
mNotificationShadeWindowView.findViewById(R.id.lock_icon_container),
- mStackScroller, mKeyguardBypassController, mFalsingManager);
+ mStackScroller, mKeyguardBypassController);
mKeyguardIndicationController
.setStatusBarKeyguardViewManager(mStatusBarKeyguardViewManager);
mBiometricUnlockController.setKeyguardViewController(mStatusBarKeyguardViewManager);
@@ -1551,15 +1546,15 @@ public class StatusBar extends SystemUI implements DemoMode,
return false;
}
- if (mSplitScreenControllerOptional.isPresent()) {
- SplitScreenController splitScreenController = mSplitScreenControllerOptional.get();
- if (splitScreenController.isDividerVisible()) {
- if (splitScreenController.isMinimized()
- && !splitScreenController.isHomeStackResizable()) {
+ if (mSplitScreenOptional.isPresent()) {
+ SplitScreen splitScreen = mSplitScreenOptional.get();
+ if (splitScreen.isDividerVisible()) {
+ if (splitScreen.isMinimized()
+ && !splitScreen.isHomeStackResizable()) {
// Undocking from the minimized state is not supported
return false;
} else {
- splitScreenController.onUndockingTask();
+ splitScreen.onUndockingTask();
if (metricsUndockAction != -1) {
mMetricsLogger.action(metricsUndockAction);
}
@@ -3917,16 +3912,14 @@ public class StatusBar extends SystemUI implements DemoMode,
@Override
public void appTransitionCancelled(int displayId) {
if (displayId == mDisplayId) {
- mSplitScreenControllerOptional.ifPresent(
- splitScreen -> splitScreen.onAppTransitionFinished());
+ mSplitScreenOptional.ifPresent(splitScreen -> splitScreen.onAppTransitionFinished());
}
}
@Override
public void appTransitionFinished(int displayId) {
if (displayId == mDisplayId) {
- mSplitScreenControllerOptional.ifPresent(
- splitScreen -> splitScreen.onAppTransitionFinished());
+ mSplitScreenOptional.ifPresent(splitScreen -> splitScreen.onAppTransitionFinished());
}
}
@@ -4087,8 +4080,6 @@ public class StatusBar extends SystemUI implements DemoMode,
// all notifications
protected NotificationStackScrollLayout mStackScroller;
- private final NotificationGroupManager mGroupManager;
-
// handling reordering
private final VisualStabilityManager mVisualStabilityManager;
@@ -4224,25 +4215,6 @@ public class StatusBar extends SystemUI implements DemoMode,
KeyboardShortcuts.dismiss();
}
- /**
- * Called when the notification panel layouts
- */
- public void onPanelLaidOut() {
- updateKeyguardMaxNotifications();
- }
-
- public void updateKeyguardMaxNotifications() {
- if (mState == StatusBarState.KEYGUARD) {
- // Since the number of notifications is determined based on the height of the view, we
- // need to update them.
- int maxBefore = mPresenter.getMaxNotificationsWhileLocked(false /* recompute */);
- int maxNotifications = mPresenter.getMaxNotificationsWhileLocked(true /* recompute */);
- if (maxBefore != maxNotifications) {
- mViewHierarchyManager.updateRowStates();
- }
- }
- }
-
public void executeActionDismissingKeyguard(Runnable action, boolean afterKeyguardGone) {
if (!mDeviceProvisionedController.isDeviceProvisioned()) return;
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarKeyguardViewManager.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarKeyguardViewManager.java
index 777bf3f73480..b56993b5f439 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarKeyguardViewManager.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarKeyguardViewManager.java
@@ -44,15 +44,13 @@ import com.android.keyguard.KeyguardUpdateMonitor;
import com.android.keyguard.KeyguardUpdateMonitorCallback;
import com.android.keyguard.KeyguardViewController;
import com.android.keyguard.ViewMediatorCallback;
+import com.android.keyguard.dagger.KeyguardBouncerComponent;
import com.android.settingslib.animation.AppearAnimationUtils;
import com.android.systemui.DejankUtils;
-import com.android.systemui.SystemUIFactory;
import com.android.systemui.dagger.SysUISingleton;
import com.android.systemui.dock.DockManager;
-import com.android.systemui.keyguard.DismissCallbackRegistry;
import com.android.systemui.keyguard.FaceAuthScreenBrightnessController;
import com.android.systemui.navigationbar.NavigationModeController;
-import com.android.systemui.plugins.FalsingManager;
import com.android.systemui.plugins.statusbar.StatusBarStateController;
import com.android.systemui.shared.system.QuickStepContract;
import com.android.systemui.shared.system.SysUiStatsLog;
@@ -106,6 +104,7 @@ public class StatusBarKeyguardViewManager implements RemoteInputController.Callb
private final NavigationModeController mNavigationModeController;
private final NotificationShadeWindowController mNotificationShadeWindowController;
private final Optional<FaceAuthScreenBrightnessController> mFaceAuthScreenBrightnessController;
+ private final KeyguardBouncerComponent.Factory mKeyguardBouncerComponentFactory;
private final BouncerExpansionCallback mExpansionCallback = new BouncerExpansionCallback() {
@Override
public void onFullyShown() {
@@ -216,7 +215,8 @@ public class StatusBarKeyguardViewManager implements RemoteInputController.Callb
NotificationShadeWindowController notificationShadeWindowController,
KeyguardStateController keyguardStateController,
Optional<FaceAuthScreenBrightnessController> faceAuthScreenBrightnessController,
- NotificationMediaManager notificationMediaManager) {
+ NotificationMediaManager notificationMediaManager,
+ KeyguardBouncerComponent.Factory keyguardBouncerComponentFactory) {
mContext = context;
mViewMediatorCallback = callback;
mLockPatternUtils = lockPatternUtils;
@@ -229,6 +229,7 @@ public class StatusBarKeyguardViewManager implements RemoteInputController.Callb
mStatusBarStateController = sysuiStatusBarStateController;
mDockManager = dockManager;
mFaceAuthScreenBrightnessController = faceAuthScreenBrightnessController;
+ mKeyguardBouncerComponentFactory = keyguardBouncerComponentFactory;
}
@Override
@@ -236,9 +237,8 @@ public class StatusBarKeyguardViewManager implements RemoteInputController.Callb
ViewGroup container,
NotificationPanelViewController notificationPanelViewController,
BiometricUnlockController biometricUnlockController,
- DismissCallbackRegistry dismissCallbackRegistry,
ViewGroup lockIconContainer, View notificationContainer,
- KeyguardBypassController bypassController, FalsingManager falsingManager) {
+ KeyguardBypassController bypassController) {
mStatusBar = statusBar;
mContainer = container;
mLockIconContainer = lockIconContainer;
@@ -246,9 +246,9 @@ public class StatusBarKeyguardViewManager implements RemoteInputController.Callb
mLastLockVisible = mLockIconContainer.getVisibility() == View.VISIBLE;
}
mBiometricUnlockController = biometricUnlockController;
- mBouncer = SystemUIFactory.getInstance().createKeyguardBouncer(mContext,
- mViewMediatorCallback, mLockPatternUtils, container, dismissCallbackRegistry,
- mExpansionCallback, mKeyguardStateController, falsingManager, bypassController);
+ mBouncer = mKeyguardBouncerComponentFactory
+ .build(container, mExpansionCallback)
+ .createKeyguardBouncer();
mNotificationPanelViewController = notificationPanelViewController;
notificationPanelViewController.addExpansionListener(this);
mBypassController = bypassController;
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarNotificationActivityStarter.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarNotificationActivityStarter.java
index de11c9023200..f80656706f37 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarNotificationActivityStarter.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarNotificationActivityStarter.java
@@ -66,10 +66,10 @@ import com.android.systemui.statusbar.notification.ActivityLaunchAnimator;
import com.android.systemui.statusbar.notification.NotificationActivityStarter;
import com.android.systemui.statusbar.notification.NotificationEntryListener;
import com.android.systemui.statusbar.notification.NotificationEntryManager;
-import com.android.systemui.statusbar.notification.collection.NotifCollection;
import com.android.systemui.statusbar.notification.collection.NotifPipeline;
import com.android.systemui.statusbar.notification.collection.NotificationEntry;
import com.android.systemui.statusbar.notification.collection.notifcollection.NotifCollectionListener;
+import com.android.systemui.statusbar.notification.collection.render.GroupMembershipManager;
import com.android.systemui.statusbar.notification.interruption.NotificationInterruptStateProvider;
import com.android.systemui.statusbar.notification.logging.NotificationLogger;
import com.android.systemui.statusbar.notification.row.ExpandableNotificationRow;
@@ -96,7 +96,6 @@ public class StatusBarNotificationActivityStarter implements NotificationActivit
private final NotificationEntryManager mEntryManager;
private final NotifPipeline mNotifPipeline;
- private final NotifCollection mNotifCollection;
private final HeadsUpManagerPhone mHeadsUpManager;
private final ActivityStarter mActivityStarter;
private final NotificationClickNotifier mClickNotifier;
@@ -107,7 +106,7 @@ public class StatusBarNotificationActivityStarter implements NotificationActivit
private final BubbleController mBubbleController;
private final Lazy<AssistManager> mAssistManagerLazy;
private final NotificationRemoteInputManager mRemoteInputManager;
- private final NotificationGroupManager mGroupManager;
+ private final GroupMembershipManager mGroupMembershipManager;
private final NotificationLockscreenUserManager mLockscreenUserManager;
private final ShadeController mShadeController;
private final KeyguardStateController mKeyguardStateController;
@@ -135,7 +134,6 @@ public class StatusBarNotificationActivityStarter implements NotificationActivit
Executor uiBgExecutor,
NotificationEntryManager entryManager,
NotifPipeline notifPipeline,
- NotifCollection notifCollection,
HeadsUpManagerPhone headsUpManager,
ActivityStarter activityStarter,
NotificationClickNotifier clickNotifier,
@@ -146,7 +144,7 @@ public class StatusBarNotificationActivityStarter implements NotificationActivit
BubbleController bubbleController,
Lazy<AssistManager> assistManagerLazy,
NotificationRemoteInputManager remoteInputManager,
- NotificationGroupManager groupManager,
+ GroupMembershipManager groupMembershipManager,
NotificationLockscreenUserManager lockscreenUserManager,
ShadeController shadeController,
KeyguardStateController keyguardStateController,
@@ -170,7 +168,6 @@ public class StatusBarNotificationActivityStarter implements NotificationActivit
mUiBgExecutor = uiBgExecutor;
mEntryManager = entryManager;
mNotifPipeline = notifPipeline;
- mNotifCollection = notifCollection;
mHeadsUpManager = headsUpManager;
mActivityStarter = activityStarter;
mClickNotifier = clickNotifier;
@@ -181,7 +178,7 @@ public class StatusBarNotificationActivityStarter implements NotificationActivit
mBubbleController = bubbleController;
mAssistManagerLazy = assistManagerLazy;
mRemoteInputManager = remoteInputManager;
- mGroupManager = groupManager;
+ mGroupMembershipManager = groupMembershipManager;
mLockscreenUserManager = lockscreenUserManager;
mShadeController = shadeController;
mKeyguardStateController = keyguardStateController;
@@ -228,8 +225,9 @@ public class StatusBarNotificationActivityStarter implements NotificationActivit
public void onNotificationClicked(StatusBarNotification sbn, ExpandableNotificationRow row) {
mLogger.logStartingActivityFromClick(sbn.getKey());
+ final NotificationEntry entry = row.getEntry();
RemoteInputController controller = mRemoteInputManager.getController();
- if (controller.isRemoteInputActive(row.getEntry())
+ if (controller.isRemoteInputActive(entry)
&& !TextUtils.isEmpty(row.getActiveRemoteInputText())) {
// We have an active remote input typed and the user clicked on the notification.
// this was probably unintentional, so we're closing the edit text instead.
@@ -240,7 +238,7 @@ public class StatusBarNotificationActivityStarter implements NotificationActivit
final PendingIntent intent = notification.contentIntent != null
? notification.contentIntent
: notification.fullScreenIntent;
- final boolean isBubble = row.getEntry().isBubble();
+ final boolean isBubble = entry.isBubble();
// This code path is now executed for notification without a contentIntent.
// The only valid case is Bubble notifications. Guard against other cases
@@ -260,7 +258,7 @@ public class StatusBarNotificationActivityStarter implements NotificationActivit
mLockscreenUserManager.getCurrentUserId());
ActivityStarter.OnDismissAction postKeyguardAction =
() -> handleNotificationClickAfterKeyguardDismissed(
- sbn, row, controller, intent,
+ entry, row, controller, intent,
isActivityIntent, wasOccluded, showOverLockscreen);
if (showOverLockscreen) {
mIsCollapsingToShowActivityOverLockscreen = true;
@@ -272,27 +270,27 @@ public class StatusBarNotificationActivityStarter implements NotificationActivit
}
private boolean handleNotificationClickAfterKeyguardDismissed(
- StatusBarNotification sbn,
+ NotificationEntry entry,
ExpandableNotificationRow row,
RemoteInputController controller,
PendingIntent intent,
boolean isActivityIntent,
boolean wasOccluded,
boolean showOverLockscreen) {
- mLogger.logHandleClickAfterKeyguardDismissed(sbn.getKey());
+ mLogger.logHandleClickAfterKeyguardDismissed(entry.getKey());
// TODO: Some of this code may be able to move to NotificationEntryManager.
removeHUN(row);
NotificationEntry parentToCancel = null;
- if (shouldAutoCancel(sbn) && mGroupManager.isOnlyChildInGroup(sbn)) {
- NotificationEntry summarySbn = mGroupManager.getLogicalGroupSummary(sbn);
+ if (shouldAutoCancel(entry.getSbn()) && mGroupMembershipManager.isOnlyChildInGroup(entry)) {
+ NotificationEntry summarySbn = mGroupMembershipManager.getLogicalGroupSummary(entry);
if (shouldAutoCancel(summarySbn.getSbn())) {
parentToCancel = summarySbn;
}
}
final NotificationEntry parentToCancelFinal = parentToCancel;
final Runnable runnable = () -> handleNotificationClickAfterPanelCollapsed(
- sbn, row, controller, intent,
+ entry, row, controller, intent,
isActivityIntent, wasOccluded, parentToCancelFinal);
if (showOverLockscreen) {
@@ -309,16 +307,16 @@ public class StatusBarNotificationActivityStarter implements NotificationActivit
}
private void handleNotificationClickAfterPanelCollapsed(
- StatusBarNotification sbn,
+ NotificationEntry entry,
ExpandableNotificationRow row,
RemoteInputController controller,
PendingIntent intent,
boolean isActivityIntent,
boolean wasOccluded,
NotificationEntry parentToCancelFinal) {
- mLogger.logHandleClickAfterPanelCollapsed(sbn.getKey());
+ String notificationKey = entry.getKey();
+ mLogger.logHandleClickAfterPanelCollapsed(notificationKey);
- String notificationKey = sbn.getKey();
try {
// The intent we are sending is for the application, which
// won't have permission to immediately start an activity after
@@ -346,7 +344,6 @@ public class StatusBarNotificationActivityStarter implements NotificationActivit
}
}
Intent fillInIntent = null;
- NotificationEntry entry = row.getEntry();
CharSequence remoteInputText = null;
if (!TextUtils.isEmpty(entry.remoteInputText)) {
remoteInputText = entry.remoteInputText;
@@ -385,7 +382,7 @@ public class StatusBarNotificationActivityStarter implements NotificationActivit
// necessary in the new pipeline due to group pruning in ShadeListBuilder.
removeNotification(parentToCancelFinal);
}
- if (shouldAutoCancel(sbn)
+ if (shouldAutoCancel(entry.getSbn())
|| mRemoteInputManager.isNotificationKeptForRemoteInputHistory(
notificationKey)) {
// Automatically remove all notifications that we may have kept around longer
@@ -605,7 +602,6 @@ public class StatusBarNotificationActivityStarter implements NotificationActivit
private final Executor mUiBgExecutor;
private final NotificationEntryManager mEntryManager;
private final NotifPipeline mNotifPipeline;
- private final NotifCollection mNotifCollection;
private final HeadsUpManagerPhone mHeadsUpManager;
private final ActivityStarter mActivityStarter;
private final NotificationClickNotifier mClickNotifier;
@@ -616,7 +612,7 @@ public class StatusBarNotificationActivityStarter implements NotificationActivit
private final BubbleController mBubbleController;
private final Lazy<AssistManager> mAssistManagerLazy;
private final NotificationRemoteInputManager mRemoteInputManager;
- private final NotificationGroupManager mGroupManager;
+ private final GroupMembershipManager mGroupMembershipManager;
private final NotificationLockscreenUserManager mLockscreenUserManager;
private final ShadeController mShadeController;
private final KeyguardStateController mKeyguardStateController;
@@ -643,7 +639,6 @@ public class StatusBarNotificationActivityStarter implements NotificationActivit
@UiBackground Executor uiBgExecutor,
NotificationEntryManager entryManager,
NotifPipeline notifPipeline,
- NotifCollection notifCollection,
HeadsUpManagerPhone headsUpManager,
ActivityStarter activityStarter,
NotificationClickNotifier clickNotifier,
@@ -654,7 +649,7 @@ public class StatusBarNotificationActivityStarter implements NotificationActivit
BubbleController bubbleController,
Lazy<AssistManager> assistManagerLazy,
NotificationRemoteInputManager remoteInputManager,
- NotificationGroupManager groupManager,
+ GroupMembershipManager groupMembershipManager,
NotificationLockscreenUserManager lockscreenUserManager,
ShadeController shadeController,
KeyguardStateController keyguardStateController,
@@ -674,7 +669,6 @@ public class StatusBarNotificationActivityStarter implements NotificationActivit
mUiBgExecutor = uiBgExecutor;
mEntryManager = entryManager;
mNotifPipeline = notifPipeline;
- mNotifCollection = notifCollection;
mHeadsUpManager = headsUpManager;
mActivityStarter = activityStarter;
mClickNotifier = clickNotifier;
@@ -685,7 +679,7 @@ public class StatusBarNotificationActivityStarter implements NotificationActivit
mBubbleController = bubbleController;
mAssistManagerLazy = assistManagerLazy;
mRemoteInputManager = remoteInputManager;
- mGroupManager = groupManager;
+ mGroupMembershipManager = groupMembershipManager;
mLockscreenUserManager = lockscreenUserManager;
mShadeController = shadeController;
mKeyguardStateController = keyguardStateController;
@@ -731,7 +725,6 @@ public class StatusBarNotificationActivityStarter implements NotificationActivit
mUiBgExecutor,
mEntryManager,
mNotifPipeline,
- mNotifCollection,
mHeadsUpManager,
mActivityStarter,
mClickNotifier,
@@ -742,7 +735,7 @@ public class StatusBarNotificationActivityStarter implements NotificationActivit
mBubbleController,
mAssistManagerLazy,
mRemoteInputManager,
- mGroupManager,
+ mGroupMembershipManager,
mLockscreenUserManager,
mShadeController,
mKeyguardStateController,
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarNotificationPresenter.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarNotificationPresenter.java
index 67adaaae402e..024a0b17b5cc 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarNotificationPresenter.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarNotificationPresenter.java
@@ -110,7 +110,6 @@ public class StatusBarNotificationPresenter implements NotificationPresenter,
private final AboveShelfObserver mAboveShelfObserver;
private final DozeScrimController mDozeScrimController;
private final ScrimController mScrimController;
- private final Context mContext;
private final KeyguardIndicationController mKeyguardIndicationController;
private final StatusBar mStatusBar;
private final ShadeController mShadeController;
@@ -119,7 +118,6 @@ public class StatusBarNotificationPresenter implements NotificationPresenter,
private final AccessibilityManager mAccessibilityManager;
private final KeyguardManager mKeyguardManager;
private final ActivityLaunchAnimator mActivityLaunchAnimator;
- private final int mMaxAllowedKeyguardNotifications;
private final IStatusBarService mBarService;
private final DynamicPrivacyController mDynamicPrivacyController;
private boolean mReinflateNotificationsOnUserSwitched;
@@ -127,7 +125,6 @@ public class StatusBarNotificationPresenter implements NotificationPresenter,
private TextView mNotificationPanelDebugText;
protected boolean mVrMode;
- private int mMaxKeyguardNotifications;
public StatusBarNotificationPresenter(Context context,
NotificationPanelViewController panel,
@@ -145,7 +142,6 @@ public class StatusBarNotificationPresenter implements NotificationPresenter,
CommandQueue commandQueue,
InitController initController,
NotificationInterruptStateProvider notificationInterruptStateProvider) {
- mContext = context;
mKeyguardStateController = keyguardStateController;
mNotificationPanel = panel;
mHeadsUpManager = headsUp;
@@ -163,8 +159,6 @@ public class StatusBarNotificationPresenter implements NotificationPresenter,
mDozeScrimController = dozeScrimController;
mScrimController = scrimController;
mKeyguardManager = context.getSystemService(KeyguardManager.class);
- mMaxAllowedKeyguardNotifications = context.getResources().getInteger(
- R.integer.keyguard_max_notification_count);
mBarService = IStatusBarService.Stub.asInterface(
ServiceManager.getService(Context.STATUS_BAR_SERVICE));
@@ -397,17 +391,6 @@ public class StatusBarNotificationPresenter implements NotificationPresenter,
}
@Override
- public int getMaxNotificationsWhileLocked(boolean recompute) {
- if (recompute) {
- mMaxKeyguardNotifications = Math.max(1,
- mNotificationPanel.computeMaxKeyguardNotifications(
- mMaxAllowedKeyguardNotifications));
- return mMaxKeyguardNotifications;
- }
- return mMaxKeyguardNotifications;
- }
-
- @Override
public void onUpdateRowStates() {
mNotificationPanel.onUpdateRowStates();
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarRemoteInputCallback.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarRemoteInputCallback.java
index 8a8942975d2e..36519ac0d808 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarRemoteInputCallback.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarRemoteInputCallback.java
@@ -45,6 +45,7 @@ import com.android.systemui.statusbar.NotificationRemoteInputManager;
import com.android.systemui.statusbar.NotificationRemoteInputManager.Callback;
import com.android.systemui.statusbar.StatusBarState;
import com.android.systemui.statusbar.SysuiStatusBarStateController;
+import com.android.systemui.statusbar.notification.collection.render.GroupExpansionManager;
import com.android.systemui.statusbar.notification.row.ExpandableNotificationRow;
import com.android.systemui.statusbar.notification.stack.NotificationStackScrollLayout;
import com.android.systemui.statusbar.policy.KeyguardStateController;
@@ -65,7 +66,7 @@ public class StatusBarRemoteInputCallback implements Callback, Callbacks,
private final StatusBarKeyguardViewManager mStatusBarKeyguardViewManager;
private final ShadeController mShadeController;
private final ActivityIntentHelper mActivityIntentHelper;
- private final NotificationGroupManager mGroupManager;
+ private final GroupExpansionManager mGroupExpansionManager;
private View mPendingWorkRemoteInputView;
private View mPendingRemoteInputView;
private KeyguardManager mKeyguardManager;
@@ -78,12 +79,15 @@ public class StatusBarRemoteInputCallback implements Callback, Callbacks,
/**
*/
@Inject
- public StatusBarRemoteInputCallback(Context context, NotificationGroupManager groupManager,
+ public StatusBarRemoteInputCallback(
+ Context context,
+ GroupExpansionManager groupExpansionManager,
NotificationLockscreenUserManager notificationLockscreenUserManager,
KeyguardStateController keyguardStateController,
StatusBarStateController statusBarStateController,
StatusBarKeyguardViewManager statusBarKeyguardViewManager,
- ActivityStarter activityStarter, ShadeController shadeController,
+ ActivityStarter activityStarter,
+ ShadeController shadeController,
CommandQueue commandQueue,
ActionClickLogger clickLogger) {
mContext = context;
@@ -101,7 +105,7 @@ public class StatusBarRemoteInputCallback implements Callback, Callbacks,
mCommandQueue.addCallback(this);
mActionClickLogger = clickLogger;
mActivityIntentHelper = new ActivityIntentHelper(mContext);
- mGroupManager = groupManager;
+ mGroupExpansionManager = groupExpansionManager;
}
@Override
@@ -182,7 +186,7 @@ public class StatusBarRemoteInputCallback implements Callback, Callbacks,
} else {
if (row.isChildInGroup() && !row.areChildrenExpanded()) {
// The group isn't expanded, let's make sure it's visible!
- mGroupManager.toggleGroupExpansion(row.getEntry().getSbn());
+ mGroupExpansionManager.toggleGroupExpansion(row.getEntry());
}
row.setUserExpanded(true);
row.getPrivateLayout().setOnExpandedVisibleListener(clickedView::performClick);
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/dagger/StatusBarPhoneModule.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/dagger/StatusBarPhoneModule.java
index 024a77664781..b7f83145f477 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/dagger/StatusBarPhoneModule.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/dagger/StatusBarPhoneModule.java
@@ -46,7 +46,6 @@ import com.android.systemui.plugins.PluginDependencyProvider;
import com.android.systemui.recents.Recents;
import com.android.systemui.recents.ScreenPinningRequest;
import com.android.systemui.shared.plugins.PluginManager;
-import com.android.systemui.stackdivider.SplitScreenController;
import com.android.systemui.statusbar.CommandQueue;
import com.android.systemui.statusbar.KeyguardIndicationController;
import com.android.systemui.statusbar.NotificationLockscreenUserManager;
@@ -80,7 +79,6 @@ import com.android.systemui.statusbar.phone.LightBarController;
import com.android.systemui.statusbar.phone.LightsOutNotifController;
import com.android.systemui.statusbar.phone.LockscreenLockIconController;
import com.android.systemui.statusbar.phone.LockscreenWallpaper;
-import com.android.systemui.statusbar.phone.NotificationGroupManager;
import com.android.systemui.statusbar.phone.NotificationIconAreaController;
import com.android.systemui.statusbar.phone.PhoneStatusBarPolicy;
import com.android.systemui.statusbar.phone.ScrimController;
@@ -100,6 +98,7 @@ import com.android.systemui.statusbar.policy.RemoteInputQuickSettingsDisabler;
import com.android.systemui.statusbar.policy.UserInfoControllerImpl;
import com.android.systemui.statusbar.policy.UserSwitcherController;
import com.android.systemui.volume.VolumeComponent;
+import com.android.wm.shell.splitscreen.SplitScreen;
import java.util.Optional;
import java.util.concurrent.Executor;
@@ -158,7 +157,6 @@ public interface StatusBarPhoneModule {
SysuiStatusBarStateController statusBarStateController,
VibratorHelper vibratorHelper,
BubbleController bubbleController,
- NotificationGroupManager groupManager,
VisualStabilityManager visualStabilityManager,
DeviceProvisionedController deviceProvisionedController,
NavigationBarController navigationBarController,
@@ -180,7 +178,7 @@ public interface StatusBarPhoneModule {
Optional<Recents> recentsOptional,
Provider<StatusBarComponent.Builder> statusBarComponentBuilder,
PluginManager pluginManager,
- Optional<SplitScreenController> splitScreenControllerOptional,
+ Optional<SplitScreen> splitScreenOptional,
LightsOutNotifController lightsOutNotifController,
StatusBarNotificationActivityStarter.Builder
statusBarNotificationActivityStarterBuilder,
@@ -238,7 +236,6 @@ public interface StatusBarPhoneModule {
statusBarStateController,
vibratorHelper,
bubbleController,
- groupManager,
visualStabilityManager,
deviceProvisionedController,
navigationBarController,
@@ -260,7 +257,7 @@ public interface StatusBarPhoneModule {
recentsOptional,
statusBarComponentBuilder,
pluginManager,
- splitScreenControllerOptional,
+ splitScreenOptional,
lightsOutNotifController,
statusBarNotificationActivityStarterBuilder,
shadeController,
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/BluetoothControllerImpl.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/BluetoothControllerImpl.java
index 33b1a4a880ae..f39acf9a40ed 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/BluetoothControllerImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/BluetoothControllerImpl.java
@@ -39,6 +39,7 @@ import com.android.settingslib.bluetooth.LocalBluetoothProfileManager;
import com.android.systemui.dagger.SysUISingleton;
import com.android.systemui.dagger.qualifiers.Background;
import com.android.systemui.dagger.qualifiers.Main;
+import com.android.systemui.dump.DumpManager;
import java.io.FileDescriptor;
import java.io.PrintWriter;
@@ -58,6 +59,7 @@ public class BluetoothControllerImpl implements BluetoothController, BluetoothCa
private static final String TAG = "BluetoothController";
private static final boolean DEBUG = Log.isLoggable(TAG, Log.DEBUG);
+ private final DumpManager mDumpManager;
private final LocalBluetoothManager mLocalBluetoothManager;
private final UserManager mUserManager;
private final int mCurrentUser;
@@ -77,8 +79,13 @@ public class BluetoothControllerImpl implements BluetoothController, BluetoothCa
/**
*/
@Inject
- public BluetoothControllerImpl(Context context, @Background Looper bgLooper,
- @Main Looper mainLooper, @Nullable LocalBluetoothManager localBluetoothManager) {
+ public BluetoothControllerImpl(
+ Context context,
+ DumpManager dumpManager,
+ @Background Looper bgLooper,
+ @Main Looper mainLooper,
+ @Nullable LocalBluetoothManager localBluetoothManager) {
+ mDumpManager = dumpManager;
mLocalBluetoothManager = localBluetoothManager;
mBgHandler = new Handler(bgLooper);
mHandler = new H(mainLooper);
@@ -90,6 +97,7 @@ public class BluetoothControllerImpl implements BluetoothController, BluetoothCa
}
mUserManager = (UserManager) context.getSystemService(Context.USER_SERVICE);
mCurrentUser = ActivityManager.getCurrentUser();
+ mDumpManager.registerDumpable(TAG, this);
}
@Override
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/DeviceProvisionedControllerImpl.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/DeviceProvisionedControllerImpl.java
index 9b4e16525df2..485b1b109eb4 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/DeviceProvisionedControllerImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/DeviceProvisionedControllerImpl.java
@@ -15,8 +15,6 @@
package com.android.systemui.statusbar.policy;
import android.app.ActivityManager;
-import android.content.ContentResolver;
-import android.content.Context;
import android.database.ContentObserver;
import android.net.Uri;
import android.os.Handler;
@@ -30,6 +28,8 @@ import com.android.systemui.broadcast.BroadcastDispatcher;
import com.android.systemui.dagger.SysUISingleton;
import com.android.systemui.dagger.qualifiers.Main;
import com.android.systemui.settings.CurrentUserTracker;
+import com.android.systemui.util.settings.GlobalSettings;
+import com.android.systemui.util.settings.SecureSettings;
import java.util.ArrayList;
@@ -43,8 +43,8 @@ public class DeviceProvisionedControllerImpl extends CurrentUserTracker implemen
protected static final String TAG = DeviceProvisionedControllerImpl.class.getSimpleName();
protected final ArrayList<DeviceProvisionedListener> mListeners = new ArrayList<>();
- private final ContentResolver mContentResolver;
- private final Context mContext;
+ private final GlobalSettings mGlobalSettings;
+ private final SecureSettings mSecureSettings;
private final Uri mDeviceProvisionedUri;
private final Uri mUserSetupUri;
protected final ContentObserver mSettingsObserver;
@@ -52,13 +52,14 @@ public class DeviceProvisionedControllerImpl extends CurrentUserTracker implemen
/**
*/
@Inject
- public DeviceProvisionedControllerImpl(Context context, @Main Handler mainHandler,
- BroadcastDispatcher broadcastDispatcher) {
+ public DeviceProvisionedControllerImpl(@Main Handler mainHandler,
+ BroadcastDispatcher broadcastDispatcher, GlobalSettings globalSettings,
+ SecureSettings secureSettings) {
super(broadcastDispatcher);
- mContext = context;
- mContentResolver = context.getContentResolver();
- mDeviceProvisionedUri = Global.getUriFor(Global.DEVICE_PROVISIONED);
- mUserSetupUri = Secure.getUriFor(Secure.USER_SETUP_COMPLETE);
+ mGlobalSettings = globalSettings;
+ mSecureSettings = secureSettings;
+ mDeviceProvisionedUri = mGlobalSettings.getUriFor(Global.DEVICE_PROVISIONED);
+ mUserSetupUri = mSecureSettings.getUriFor(Secure.USER_SETUP_COMPLETE);
mSettingsObserver = new ContentObserver(mainHandler) {
@Override
public void onChange(boolean selfChange, Uri uri, int flags) {
@@ -74,13 +75,12 @@ public class DeviceProvisionedControllerImpl extends CurrentUserTracker implemen
@Override
public boolean isDeviceProvisioned() {
- return Global.getInt(mContentResolver, Global.DEVICE_PROVISIONED, 0) != 0;
+ return mGlobalSettings.getInt(Global.DEVICE_PROVISIONED, 0) != 0;
}
@Override
public boolean isUserSetup(int currentUser) {
- return Secure.getIntForUser(mContentResolver, Secure.USER_SETUP_COMPLETE, 0, currentUser)
- != 0;
+ return mSecureSettings.getIntForUser(Secure.USER_SETUP_COMPLETE, 0, currentUser) != 0;
}
@Override
@@ -107,24 +107,24 @@ public class DeviceProvisionedControllerImpl extends CurrentUserTracker implemen
}
protected void startListening(int user) {
- mContentResolver.registerContentObserver(mDeviceProvisionedUri, true,
+ mGlobalSettings.registerContentObserverForUser(mDeviceProvisionedUri, true,
mSettingsObserver, 0);
- mContentResolver.registerContentObserver(mUserSetupUri, true,
+ mSecureSettings.registerContentObserverForUser(mUserSetupUri, true,
mSettingsObserver, user);
startTracking();
}
protected void stopListening() {
stopTracking();
- mContentResolver.unregisterContentObserver(mSettingsObserver);
+ mGlobalSettings.unregisterContentObserver(mSettingsObserver);
}
@Override
public void onUserSwitched(int newUserId) {
- mContentResolver.unregisterContentObserver(mSettingsObserver);
- mContentResolver.registerContentObserver(mDeviceProvisionedUri, true,
+ mGlobalSettings.unregisterContentObserver(mSettingsObserver);
+ mGlobalSettings.registerContentObserverForUser(mDeviceProvisionedUri, true,
mSettingsObserver, 0);
- mContentResolver.registerContentObserver(mUserSetupUri, true,
+ mSecureSettings.registerContentObserverForUser(mUserSetupUri, true,
mSettingsObserver, newUserId);
notifyUserChanged();
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/MobileSignalController.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/MobileSignalController.java
index cf83603997c0..eb2d9bce6c4e 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/MobileSignalController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/MobileSignalController.java
@@ -418,6 +418,10 @@ public class MobileSignalController extends SignalController<
return (mServiceState != null && mServiceState.isEmergencyOnly());
}
+ public boolean isInService() {
+ return Utils.isInService(mServiceState);
+ }
+
private boolean isRoaming() {
// During a carrier change, roaming indications need to be supressed.
if (isCarrierNetworkChangeActive()) {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/NetworkController.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/NetworkController.java
index b790c92b293c..8722fecdad96 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/NetworkController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/NetworkController.java
@@ -35,6 +35,7 @@ public interface NetworkController extends CallbackController<SignalCallback>, D
DataUsageController getMobileDataController();
DataSaverController getDataSaverController();
String getMobileDataNetworkName();
+ boolean isMobileDataNetworkInService();
int getNumberSubscriptions();
boolean hasVoiceCallingFeature();
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/NetworkControllerImpl.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/NetworkControllerImpl.java
index 2253ce7a62a3..62b922e23532 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/NetworkControllerImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/NetworkControllerImpl.java
@@ -460,6 +460,12 @@ public class NetworkControllerImpl extends BroadcastReceiver
}
@Override
+ public boolean isMobileDataNetworkInService() {
+ MobileSignalController controller = getDataController();
+ return controller != null && controller.isInService();
+ }
+
+ @Override
public int getNumberSubscriptions() {
return mMobileSignalControllers.size();
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/UserSwitcherController.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/UserSwitcherController.java
index f9ac760a3367..17fcb1dd6f1a 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/UserSwitcherController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/UserSwitcherController.java
@@ -206,7 +206,7 @@ public class UserSwitcherController implements Dumpable {
@Override
protected ArrayList<UserRecord> doInBackground(SparseArray<Bitmap>... params) {
final SparseArray<Bitmap> bitmaps = params[0];
- List<UserInfo> infos = mUserManager.getUsers(true);
+ List<UserInfo> infos = mUserManager.getAliveUsers();
if (infos == null) {
return null;
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/dagger/StatusBarPolicyModule.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/dagger/StatusBarPolicyModule.java
new file mode 100644
index 000000000000..914105fdc4c4
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/dagger/StatusBarPolicyModule.java
@@ -0,0 +1,112 @@
+/*
+ * 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.statusbar.policy.dagger;
+
+import com.android.systemui.statusbar.policy.BluetoothController;
+import com.android.systemui.statusbar.policy.BluetoothControllerImpl;
+import com.android.systemui.statusbar.policy.CastController;
+import com.android.systemui.statusbar.policy.CastControllerImpl;
+import com.android.systemui.statusbar.policy.ExtensionController;
+import com.android.systemui.statusbar.policy.ExtensionControllerImpl;
+import com.android.systemui.statusbar.policy.FlashlightController;
+import com.android.systemui.statusbar.policy.FlashlightControllerImpl;
+import com.android.systemui.statusbar.policy.HotspotController;
+import com.android.systemui.statusbar.policy.HotspotControllerImpl;
+import com.android.systemui.statusbar.policy.KeyguardStateController;
+import com.android.systemui.statusbar.policy.KeyguardStateControllerImpl;
+import com.android.systemui.statusbar.policy.LocationController;
+import com.android.systemui.statusbar.policy.LocationControllerImpl;
+import com.android.systemui.statusbar.policy.NetworkController;
+import com.android.systemui.statusbar.policy.NetworkControllerImpl;
+import com.android.systemui.statusbar.policy.NextAlarmController;
+import com.android.systemui.statusbar.policy.NextAlarmControllerImpl;
+import com.android.systemui.statusbar.policy.RotationLockController;
+import com.android.systemui.statusbar.policy.RotationLockControllerImpl;
+import com.android.systemui.statusbar.policy.SecurityController;
+import com.android.systemui.statusbar.policy.SecurityControllerImpl;
+import com.android.systemui.statusbar.policy.SensorPrivacyController;
+import com.android.systemui.statusbar.policy.SensorPrivacyControllerImpl;
+import com.android.systemui.statusbar.policy.UserInfoController;
+import com.android.systemui.statusbar.policy.UserInfoControllerImpl;
+import com.android.systemui.statusbar.policy.ZenModeController;
+import com.android.systemui.statusbar.policy.ZenModeControllerImpl;
+
+import dagger.Binds;
+import dagger.Module;
+
+
+/** Dagger Module for code in the statusbar.policy package. */
+@Module
+public interface StatusBarPolicyModule {
+ /** */
+ @Binds
+ BluetoothController provideBluetoothController(BluetoothControllerImpl controllerImpl);
+
+ /** */
+ @Binds
+ CastController provideCastController(CastControllerImpl controllerImpl);
+
+ /** */
+ @Binds
+ ExtensionController provideExtensionController(ExtensionControllerImpl controllerImpl);
+
+ /** */
+ @Binds
+ FlashlightController provideFlashlightController(FlashlightControllerImpl controllerImpl);
+
+ /** */
+ @Binds
+ KeyguardStateController provideKeyguardMonitor(KeyguardStateControllerImpl controllerImpl);
+
+ /** */
+ @Binds
+ HotspotController provideHotspotController(HotspotControllerImpl controllerImpl);
+
+ /** */
+ @Binds
+ LocationController provideLocationController(LocationControllerImpl controllerImpl);
+
+ /** */
+ @Binds
+ NetworkController provideNetworkController(NetworkControllerImpl controllerImpl);
+
+ /** */
+ @Binds
+ NextAlarmController provideNextAlarmController(NextAlarmControllerImpl controllerImpl);
+
+ /** */
+ @Binds
+ RotationLockController provideRotationLockController(RotationLockControllerImpl controllerImpl);
+
+ /** */
+ @Binds
+ SecurityController provideSecurityController(SecurityControllerImpl controllerImpl);
+
+ /** */
+ @Binds
+ SensorPrivacyController provideSensorPrivacyControllerImpl(
+ SensorPrivacyControllerImpl controllerImpl);
+
+ /** */
+ @Binds
+ UserInfoController provideUserInfoContrller(UserInfoControllerImpl controllerImpl);
+
+ /** */
+ @Binds
+ ZenModeController provideZenModeController(ZenModeControllerImpl controllerImpl);
+
+}
diff --git a/packages/SystemUI/src/com/android/systemui/tracing/sysui_trace.proto b/packages/SystemUI/src/com/android/systemui/tracing/sysui_trace.proto
index d940a6b5c460..eb23b9d7a994 100644
--- a/packages/SystemUI/src/com/android/systemui/tracing/sysui_trace.proto
+++ b/packages/SystemUI/src/com/android/systemui/tracing/sysui_trace.proto
@@ -16,6 +16,8 @@
syntax = "proto2";
+import "frameworks/base/libs/WindowManager/Shell/proto/wm_shell_trace.proto";
+
package com.android.systemui.tracing;
option java_multiple_files = true;
@@ -23,6 +25,7 @@ option java_multiple_files = true;
message SystemUiTraceProto {
optional EdgeBackGestureHandlerProto edge_back_gesture_handler = 1;
+ optional com.android.wm.shell.WmShellTraceProto wm_shell = 2;
}
message EdgeBackGestureHandlerProto {
diff --git a/packages/SystemUI/src/com/android/systemui/tuner/dagger/TunerModule.java b/packages/SystemUI/src/com/android/systemui/tuner/dagger/TunerModule.java
new file mode 100644
index 000000000000..faf7b842f3b2
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/tuner/dagger/TunerModule.java
@@ -0,0 +1,31 @@
+/*
+ * 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.tuner.dagger;
+
+import com.android.systemui.tuner.TunerService;
+import com.android.systemui.tuner.TunerServiceImpl;
+
+import dagger.Binds;
+import dagger.Module;
+
+/** Dagger Module for code in the tuner package. */
+@Module
+public interface TunerModule {
+ /** */
+ @Binds
+ TunerService provideTunerService(TunerServiceImpl controllerImpl);
+}
diff --git a/packages/SystemUI/src/com/android/systemui/tv/TvGlobalRootComponent.java b/packages/SystemUI/src/com/android/systemui/tv/TvGlobalRootComponent.java
index 37aac1124048..df741a0e98ff 100644
--- a/packages/SystemUI/src/com/android/systemui/tv/TvGlobalRootComponent.java
+++ b/packages/SystemUI/src/com/android/systemui/tv/TvGlobalRootComponent.java
@@ -16,7 +16,9 @@
package com.android.systemui.tv;
+import com.android.systemui.dagger.GlobalModule;
import com.android.systemui.dagger.GlobalRootComponent;
+import com.android.systemui.dagger.WMModule;
import javax.inject.Singleton;
@@ -26,7 +28,11 @@ import dagger.Component;
* Root component for Dagger injection.
*/
@Singleton
-@Component(modules = {TvSysUIComponentModule.class})
+@Component(modules = {
+ GlobalModule.class,
+ TvSysUIComponentModule.class,
+ WMModule.class
+})
public interface TvGlobalRootComponent extends GlobalRootComponent {
/**
* Component Builder interface. This allows to bind Context instance in the component
diff --git a/packages/SystemUI/src/com/android/systemui/tv/TvSysUIComponent.java b/packages/SystemUI/src/com/android/systemui/tv/TvSysUIComponent.java
index 302301d79c3a..bef05ebb724e 100644
--- a/packages/SystemUI/src/com/android/systemui/tv/TvSysUIComponent.java
+++ b/packages/SystemUI/src/com/android/systemui/tv/TvSysUIComponent.java
@@ -17,11 +17,9 @@
package com.android.systemui.tv;
import com.android.systemui.dagger.DefaultComponentBinder;
-import com.android.systemui.dagger.DependencyBinder;
import com.android.systemui.dagger.DependencyProvider;
import com.android.systemui.dagger.SysUIComponent;
import com.android.systemui.dagger.SysUISingleton;
-import com.android.systemui.dagger.SystemServicesModule;
import com.android.systemui.dagger.SystemUIBinder;
import com.android.systemui.dagger.SystemUIModule;
@@ -34,8 +32,6 @@ import dagger.Subcomponent;
@Subcomponent(modules = {
DefaultComponentBinder.class,
DependencyProvider.class,
- DependencyBinder.class,
- SystemServicesModule.class,
SystemUIBinder.class,
SystemUIModule.class,
TvSystemUIModule.class,
diff --git a/packages/SystemUI/src/com/android/systemui/tv/TvSystemUIBinder.java b/packages/SystemUI/src/com/android/systemui/tv/TvSystemUIBinder.java
index 9a44bf12a3ef..22fa0106795a 100644
--- a/packages/SystemUI/src/com/android/systemui/tv/TvSystemUIBinder.java
+++ b/packages/SystemUI/src/com/android/systemui/tv/TvSystemUIBinder.java
@@ -17,12 +17,11 @@
package com.android.systemui.tv;
import com.android.systemui.dagger.GlobalRootComponent;
-import com.android.systemui.pip.tv.dagger.PipModule;
import dagger.Binds;
import dagger.Module;
-@Module(includes = {PipModule.class})
+@Module()
interface TvSystemUIBinder {
@Binds
GlobalRootComponent bindGlobalRootComponent(TvGlobalRootComponent globalRootComponent);
diff --git a/packages/SystemUI/src/com/android/systemui/tv/TvSystemUIModule.java b/packages/SystemUI/src/com/android/systemui/tv/TvSystemUIModule.java
index e7c10f1697f5..c5bb9c1b6f48 100644
--- a/packages/SystemUI/src/com/android/systemui/tv/TvSystemUIModule.java
+++ b/packages/SystemUI/src/com/android/systemui/tv/TvSystemUIModule.java
@@ -47,11 +47,11 @@ import com.android.systemui.statusbar.NotificationLockscreenUserManager;
import com.android.systemui.statusbar.NotificationLockscreenUserManagerImpl;
import com.android.systemui.statusbar.NotificationShadeWindowController;
import com.android.systemui.statusbar.notification.NotificationEntryManager;
+import com.android.systemui.statusbar.notification.collection.legacy.NotificationGroupManagerLegacy;
import com.android.systemui.statusbar.phone.DozeServiceHost;
import com.android.systemui.statusbar.phone.HeadsUpManagerPhone;
import com.android.systemui.statusbar.phone.KeyguardBypassController;
import com.android.systemui.statusbar.phone.KeyguardEnvironmentImpl;
-import com.android.systemui.statusbar.phone.NotificationGroupManager;
import com.android.systemui.statusbar.phone.NotificationShadeWindowControllerImpl;
import com.android.systemui.statusbar.phone.ShadeController;
import com.android.systemui.statusbar.phone.ShadeControllerImpl;
@@ -62,7 +62,7 @@ import com.android.systemui.statusbar.policy.ConfigurationController;
import com.android.systemui.statusbar.policy.DeviceProvisionedController;
import com.android.systemui.statusbar.policy.DeviceProvisionedControllerImpl;
import com.android.systemui.statusbar.policy.HeadsUpManager;
-import com.android.systemui.wmshell.WMShellModule;
+import com.android.systemui.wmshell.TvWMShellModule;
import javax.inject.Named;
@@ -76,7 +76,7 @@ import dagger.Provides;
*/
@Module(includes = {
QSModule.class,
- WMShellModule.class
+ TvWMShellModule.class,
},
subcomponents = {
})
@@ -136,7 +136,7 @@ public abstract class TvSystemUIModule {
Context context,
StatusBarStateController statusBarStateController,
KeyguardBypassController bypassController,
- NotificationGroupManager groupManager,
+ NotificationGroupManagerLegacy groupManager,
ConfigurationController configurationController) {
return new HeadsUpManagerPhone(context, statusBarStateController, bypassController,
groupManager, configurationController);
diff --git a/packages/SystemUI/src/com/android/systemui/util/InjectionInflationController.java b/packages/SystemUI/src/com/android/systemui/util/InjectionInflationController.java
index d278905abacb..eb8f065149c8 100644
--- a/packages/SystemUI/src/com/android/systemui/util/InjectionInflationController.java
+++ b/packages/SystemUI/src/com/android/systemui/util/InjectionInflationController.java
@@ -24,7 +24,6 @@ import android.view.LayoutInflater;
import android.view.View;
import com.android.keyguard.KeyguardMessageArea;
-import com.android.keyguard.KeyguardSliceView;
import com.android.systemui.dagger.SysUISingleton;
import com.android.systemui.qs.QSFooterImpl;
import com.android.systemui.qs.QSPanel;
@@ -109,11 +108,6 @@ public class InjectionInflationController {
NotificationStackScrollLayout createNotificationStackScrollLayout();
/**
- * Creates the KeyguardSliceView.
- */
- KeyguardSliceView createKeyguardSliceView();
-
- /**
* Creates the KeyguardMessageArea.
*/
KeyguardMessageArea createKeyguardMessageArea();
diff --git a/packages/SystemUI/src/com/android/systemui/util/concurrency/GlobalConcurrencyModule.java b/packages/SystemUI/src/com/android/systemui/util/concurrency/GlobalConcurrencyModule.java
new file mode 100644
index 000000000000..5946af383b0f
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/util/concurrency/GlobalConcurrencyModule.java
@@ -0,0 +1,70 @@
+/*
+ * 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.util.concurrency;
+
+import android.content.Context;
+import android.os.Handler;
+import android.os.Looper;
+
+import com.android.systemui.dagger.qualifiers.Main;
+
+import java.util.concurrent.Executor;
+
+import dagger.Binds;
+import dagger.Module;
+import dagger.Provides;
+
+/**
+ * Dagger Module for classes found within the concurrent package.
+ */
+@Module
+public abstract class GlobalConcurrencyModule {
+
+ /**
+ * Binds {@link ThreadFactoryImpl} to {@link ThreadFactory}.
+ */
+ @Binds
+ public abstract ThreadFactory bindExecutorFactory(ThreadFactoryImpl impl);
+
+ /** Main Looper */
+ @Provides
+ @Main
+ public static Looper provideMainLooper() {
+ return Looper.getMainLooper();
+ }
+
+ /**
+ * Main Handler.
+ *
+ * Prefer the Main Executor when possible.
+ */
+ @Provides
+ @Main
+ public static Handler provideMainHandler(@Main Looper mainLooper) {
+ return new Handler(mainLooper);
+ }
+
+ /**
+ * Provide a Main-Thread Executor.
+ */
+ @Provides
+ @Main
+ public static Executor provideMainExecutor(Context context) {
+ return context.getMainExecutor();
+ }
+
+}
diff --git a/packages/SystemUI/src/com/android/systemui/util/concurrency/ConcurrencyModule.java b/packages/SystemUI/src/com/android/systemui/util/concurrency/SysUIConcurrencyModule.java
index 628c808aa12b..b9b20c73c5d5 100644
--- a/packages/SystemUI/src/com/android/systemui/util/concurrency/ConcurrencyModule.java
+++ b/packages/SystemUI/src/com/android/systemui/util/concurrency/SysUIConcurrencyModule.java
@@ -16,7 +16,6 @@
package com.android.systemui.util.concurrency;
-import android.content.Context;
import android.os.Handler;
import android.os.HandlerThread;
import android.os.Looper;
@@ -31,7 +30,6 @@ import com.android.systemui.dagger.qualifiers.UiBackground;
import java.util.concurrent.Executor;
import java.util.concurrent.Executors;
-import dagger.Binds;
import dagger.Module;
import dagger.Provides;
@@ -39,7 +37,7 @@ import dagger.Provides;
* Dagger Module for classes found within the concurrent package.
*/
@Module
-public abstract class ConcurrencyModule {
+public abstract class SysUIConcurrencyModule {
/** Background Looper */
@Provides
@SysUISingleton
@@ -62,13 +60,6 @@ public abstract class ConcurrencyModule {
return thread.getLooper();
}
- /** Main Looper */
- @Provides
- @Main
- public static Looper provideMainLooper() {
- return Looper.getMainLooper();
- }
-
/**
* Background Handler.
*
@@ -81,17 +72,6 @@ public abstract class ConcurrencyModule {
}
/**
- * Main Handler.
- *
- * Prefer the Main Executor when possible.
- */
- @Provides
- @Main
- public static Handler provideMainHandler(@Main Looper mainLooper) {
- return new Handler(mainLooper);
- }
-
- /**
* Provide a Background-Thread Executor by default.
*/
@Provides
@@ -121,15 +101,6 @@ public abstract class ConcurrencyModule {
}
/**
- * Provide a Main-Thread Executor.
- */
- @Provides
- @Main
- public static Executor provideMainExecutor(Context context) {
- return context.getMainExecutor();
- }
-
- /**
* Provide a Background-Thread Executor by default.
*/
@Provides
@@ -199,10 +170,4 @@ public abstract class ConcurrencyModule {
public static Executor provideUiBackgroundExecutor() {
return Executors.newSingleThreadExecutor();
}
-
- /**
- * Binds {@link ThreadFactoryImpl} to {@link ThreadFactory}.
- */
- @Binds
- public abstract ThreadFactory bindExecutorFactory(ThreadFactoryImpl impl);
}
diff --git a/packages/SystemUI/src/com/android/systemui/util/dagger/UtilModule.java b/packages/SystemUI/src/com/android/systemui/util/dagger/UtilModule.java
new file mode 100644
index 000000000000..cdfa1457f4a5
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/util/dagger/UtilModule.java
@@ -0,0 +1,31 @@
+/*
+ * 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.util.dagger;
+
+import com.android.systemui.util.RingerModeTracker;
+import com.android.systemui.util.RingerModeTrackerImpl;
+
+import dagger.Binds;
+import dagger.Module;
+
+/** Dagger Module for code in the util package. */
+@Module
+public interface UtilModule {
+ /** */
+ @Binds
+ RingerModeTracker provideRingerModeTracker(RingerModeTrackerImpl ringerModeTrackerImpl);
+}
diff --git a/packages/SystemUI/src/com/android/systemui/util/settings/SettingsProxy.java b/packages/SystemUI/src/com/android/systemui/util/settings/SettingsProxy.java
index 5c37f797b678..5aaf7f680d5c 100644
--- a/packages/SystemUI/src/com/android/systemui/util/settings/SettingsProxy.java
+++ b/packages/SystemUI/src/com/android/systemui/util/settings/SettingsProxy.java
@@ -67,7 +67,35 @@ public interface SettingsProxy {
* Implicitly calls {@link #getUriFor(String)} on the passed in name.
*/
default void registerContentObserver(String name, ContentObserver settingsObserver) {
- registerContentObserverForUser(name, settingsObserver, getUserId());
+ registerContentObserver(getUriFor(name), settingsObserver);
+ }
+
+ /**
+ * Convenience wrapper around
+ * {@link ContentResolver#registerContentObserver(Uri, boolean, ContentObserver)}.'
+ */
+ default void registerContentObserver(Uri uri, ContentObserver settingsObserver) {
+ registerContentObserverForUser(uri, settingsObserver, getUserId());
+ }
+
+ /**
+ * Convenience wrapper around
+ * {@link ContentResolver#registerContentObserver(Uri, boolean, ContentObserver)}.'
+ *
+ * Implicitly calls {@link #getUriFor(String)} on the passed in name.
+ */
+ default void registerContentObserver(String name, boolean notifyForDescendents,
+ ContentObserver settingsObserver) {
+ registerContentObserver(getUriFor(name), notifyForDescendents, settingsObserver);
+ }
+
+ /**
+ * Convenience wrapper around
+ * {@link ContentResolver#registerContentObserver(Uri, boolean, ContentObserver)}.'
+ */
+ default void registerContentObserver(Uri uri, boolean notifyForDescendents,
+ ContentObserver settingsObserver) {
+ registerContentObserverForUser(uri, notifyForDescendents, settingsObserver, getUserId());
}
/**
@@ -78,8 +106,42 @@ public interface SettingsProxy {
*/
default void registerContentObserverForUser(
String name, ContentObserver settingsObserver, int userHandle) {
+ registerContentObserverForUser(
+ getUriFor(name), settingsObserver, userHandle);
+ }
+
+ /**
+ * Convenience wrapper around
+ * {@link ContentResolver#registerContentObserver(Uri, boolean, ContentObserver, int)}
+ */
+ default void registerContentObserverForUser(
+ Uri uri, ContentObserver settingsObserver, int userHandle) {
+ registerContentObserverForUser(
+ uri, false, settingsObserver, userHandle);
+ }
+
+ /**
+ * Convenience wrapper around
+ * {@link ContentResolver#registerContentObserver(Uri, boolean, ContentObserver, int)}
+ *
+ * Implicitly calls {@link #getUriFor(String)} on the passed in name.
+ */
+ default void registerContentObserverForUser(
+ String name, boolean notifyForDescendents, ContentObserver settingsObserver,
+ int userHandle) {
+ registerContentObserverForUser(
+ getUriFor(name), notifyForDescendents, settingsObserver, userHandle);
+ }
+
+ /**
+ * Convenience wrapper around
+ * {@link ContentResolver#registerContentObserver(Uri, boolean, ContentObserver, int)}
+ */
+ default void registerContentObserverForUser(
+ Uri uri, boolean notifyForDescendents, ContentObserver settingsObserver,
+ int userHandle) {
getContentResolver().registerContentObserver(
- getUriFor(name), false, settingsObserver, userHandle);
+ uri, notifyForDescendents, settingsObserver, userHandle);
}
/** See {@link ContentResolver#unregisterContentObserver(ContentObserver)}. */
diff --git a/packages/SystemUI/src/com/android/systemui/volume/VolumeDialogImpl.java b/packages/SystemUI/src/com/android/systemui/volume/VolumeDialogImpl.java
index 51ad30ebcac6..78f83d3c09b4 100644
--- a/packages/SystemUI/src/com/android/systemui/volume/VolumeDialogImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/volume/VolumeDialogImpl.java
@@ -49,6 +49,7 @@ import android.content.res.Resources;
import android.content.res.TypedArray;
import android.graphics.Color;
import android.graphics.PixelFormat;
+import android.graphics.Region;
import android.graphics.drawable.ColorDrawable;
import android.media.AudioManager;
import android.media.AudioSystem;
@@ -71,6 +72,7 @@ import android.view.View.AccessibilityDelegate;
import android.view.ViewGroup;
import android.view.ViewPropertyAnimator;
import android.view.ViewStub;
+import android.view.ViewTreeObserver;
import android.view.Window;
import android.view.WindowManager;
import android.view.accessibility.AccessibilityEvent;
@@ -109,7 +111,8 @@ import java.util.List;
* Methods ending in "H" must be called on the (ui) handler.
*/
public class VolumeDialogImpl implements VolumeDialog,
- ConfigurationController.ConfigurationListener {
+ ConfigurationController.ConfigurationListener,
+ ViewTreeObserver.OnComputeInternalInsetsListener {
private static final String TAG = Util.logTag(VolumeDialogImpl.class);
private static final long USER_ATTEMPT_GRACE_PERIOD = 1000;
@@ -126,6 +129,7 @@ public class VolumeDialogImpl implements VolumeDialog,
private final H mHandler = new H();
private final VolumeDialogController mController;
private final DeviceProvisionedController mDeviceProvisionedController;
+ private final Region mTouchableRegion = new Region();
private Window mWindow;
private CustomDialog mDialog;
@@ -204,6 +208,33 @@ public class VolumeDialogImpl implements VolumeDialog,
Dependency.get(ConfigurationController.class).removeCallback(this);
}
+ @Override
+ public void onComputeInternalInsets(ViewTreeObserver.InternalInsetsInfo internalInsetsInfo) {
+ // Set touchable region insets on the root dialog view. This tells WindowManager that
+ // touches outside of this region should not be delivered to the volume window, and instead
+ // go to the window below. This is the only way to do this - returning false in
+ // onDispatchTouchEvent results in the event being ignored entirely, rather than passed to
+ // the next window.
+ internalInsetsInfo.setTouchableInsets(
+ ViewTreeObserver.InternalInsetsInfo.TOUCHABLE_INSETS_REGION);
+
+ mTouchableRegion.setEmpty();
+
+ // Set the touchable region to the union of all child view bounds. We don't use touches on
+ // the volume dialog container itself, so this is fine.
+ for (int i = 0; i < mDialogView.getChildCount(); i++) {
+ final View view = mDialogView.getChildAt(i);
+ mTouchableRegion.op(
+ view.getLeft(),
+ view.getTop(),
+ view.getRight(),
+ view.getBottom(),
+ Region.Op.UNION);
+ }
+
+ internalInsetsInfo.touchableRegion.set(mTouchableRegion);
+ }
+
private void initDialog() {
mDialog = new CustomDialog(mContext);
@@ -235,6 +266,7 @@ public class VolumeDialogImpl implements VolumeDialog,
mDialogView.setAlpha(0);
mDialog.setCanceledOnTouchOutside(true);
mDialog.setOnShowListener(dialog -> {
+ mDialogView.getViewTreeObserver().addOnComputeInternalInsetsListener(this);
if (!isLandscape()) mDialogView.setTranslationX(mDialogView.getWidth() / 2.0f);
mDialogView.setAlpha(0);
mDialogView.animate()
@@ -253,6 +285,11 @@ public class VolumeDialogImpl implements VolumeDialog,
.start();
});
+ mDialog.setOnDismissListener(dialogInterface ->
+ mDialogView
+ .getViewTreeObserver()
+ .removeOnComputeInternalInsetsListener(VolumeDialogImpl.this));
+
mDialogView.setOnHoverListener((v, event) -> {
int action = event.getActionMasked();
mHovering = (action == MotionEvent.ACTION_HOVER_ENTER)
@@ -1369,6 +1406,11 @@ public class VolumeDialogImpl implements VolumeDialog,
super(context, R.style.volume_dialog_theme);
}
+ /**
+ * NOTE: This will only be called for touches within the touchable region of the volume
+ * dialog, as returned by {@link #onComputeInternalInsets}. Other touches, even if they are
+ * within the bounds of the volume dialog, will fall through to the window below.
+ */
@Override
public boolean dispatchTouchEvent(MotionEvent ev) {
rescheduleTimeoutH();
@@ -1387,6 +1429,12 @@ public class VolumeDialogImpl implements VolumeDialog,
mHandler.sendEmptyMessage(H.RECHECK_ALL);
}
+ /**
+ * NOTE: This will be called with ACTION_OUTSIDE MotionEvents for touches that occur outside
+ * of the touchable region of the volume dialog (as returned by
+ * {@link #onComputeInternalInsets}) even if those touches occurred within the bounds of the
+ * volume dialog.
+ */
@Override
public boolean onTouchEvent(MotionEvent event) {
if (mShowing) {
diff --git a/packages/SystemUI/src/com/android/systemui/volume/dagger/VolumeModule.java b/packages/SystemUI/src/com/android/systemui/volume/dagger/VolumeModule.java
new file mode 100644
index 000000000000..1ef4c169b786
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/volume/dagger/VolumeModule.java
@@ -0,0 +1,32 @@
+/*
+ * 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.volume.dagger;
+
+import com.android.systemui.volume.VolumeComponent;
+import com.android.systemui.volume.VolumeDialogComponent;
+
+import dagger.Binds;
+import dagger.Module;
+
+
+/** Dagger Module for code in the volume package. */
+@Module
+public interface VolumeModule {
+ /** */
+ @Binds
+ VolumeComponent provideVolumeComponent(VolumeDialogComponent volumeDialogComponent);
+}
diff --git a/packages/SystemUI/src/com/android/systemui/wmshell/TvWMShellModule.java b/packages/SystemUI/src/com/android/systemui/wmshell/TvWMShellModule.java
new file mode 100644
index 000000000000..0869cf739d02
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/wmshell/TvWMShellModule.java
@@ -0,0 +1,108 @@
+/*
+ * 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.wmshell;
+
+import android.content.Context;
+import android.os.Handler;
+import android.view.IWindowManager;
+
+import com.android.systemui.broadcast.BroadcastDispatcher;
+import com.android.systemui.dagger.SysUISingleton;
+import com.android.systemui.dagger.qualifiers.Main;
+import com.android.systemui.pip.Pip;
+import com.android.systemui.pip.PipBoundsHandler;
+import com.android.systemui.pip.PipSurfaceTransactionHelper;
+import com.android.systemui.pip.PipTaskOrganizer;
+import com.android.systemui.pip.PipUiEventLogger;
+import com.android.systemui.pip.tv.PipController;
+import com.android.systemui.pip.tv.PipNotification;
+import com.android.systemui.pip.tv.dagger.TvPipComponent;
+import com.android.wm.shell.ShellTaskOrganizer;
+import com.android.wm.shell.common.DisplayController;
+import com.android.wm.shell.common.DisplayImeController;
+import com.android.wm.shell.common.SystemWindows;
+import com.android.wm.shell.common.TransactionPool;
+import com.android.wm.shell.splitscreen.SplitScreen;
+import com.android.wm.shell.splitscreen.SplitScreenController;
+
+import java.util.Optional;
+
+import dagger.Module;
+import dagger.Provides;
+
+/**
+ * Provides dependencies from {@link com.android.wm.shell} which could be customized among different
+ * branches of SystemUI.
+ */
+// TODO(b/162923491): Move most of these dependencies into WMSingleton scope.
+@Module(includes = WMShellBaseModule.class, subcomponents = {TvPipComponent.class})
+public class TvWMShellModule {
+ @SysUISingleton
+ @Provides
+ static DisplayImeController provideDisplayImeController(IWindowManager wmService,
+ DisplayController displayController, @Main Handler mainHandler,
+ TransactionPool transactionPool) {
+ return new DisplayImeController(wmService, displayController, mainHandler, transactionPool);
+ }
+
+ @SysUISingleton
+ @Provides
+ static Pip providePipController(Context context,
+ BroadcastDispatcher broadcastDispatcher,
+ PipBoundsHandler pipBoundsHandler,
+ PipSurfaceTransactionHelper pipSurfaceTransactionHelper,
+ PipTaskOrganizer pipTaskOrganizer) {
+ return new PipController(context, broadcastDispatcher, pipBoundsHandler,
+ pipSurfaceTransactionHelper, pipTaskOrganizer);
+ }
+
+ @SysUISingleton
+ @Provides
+ static SplitScreen provideSplitScreen(Context context,
+ DisplayController displayController, SystemWindows systemWindows,
+ DisplayImeController displayImeController, @Main Handler handler,
+ TransactionPool transactionPool, ShellTaskOrganizer shellTaskOrganizer) {
+ return new SplitScreenController(context, displayController, systemWindows,
+ displayImeController, handler, transactionPool, shellTaskOrganizer);
+ }
+
+ @SysUISingleton
+ @Provides
+ static PipNotification providePipNotification(Context context,
+ BroadcastDispatcher broadcastDispatcher,
+ PipController pipController) {
+ return new PipNotification(context, broadcastDispatcher, pipController);
+ }
+
+ @SysUISingleton
+ @Provides
+ static PipBoundsHandler providesPipBoundsHandler(Context context) {
+ return new PipBoundsHandler(context);
+ }
+
+ @SysUISingleton
+ @Provides
+ static PipTaskOrganizer providesPipTaskOrganizer(Context context,
+ PipBoundsHandler pipBoundsHandler,
+ PipSurfaceTransactionHelper pipSurfaceTransactionHelper,
+ Optional<SplitScreen> splitScreenOptional, DisplayController displayController,
+ PipUiEventLogger pipUiEventLogger, ShellTaskOrganizer shellTaskOrganizer) {
+ return new PipTaskOrganizer(context, pipBoundsHandler,
+ pipSurfaceTransactionHelper, splitScreenOptional, displayController,
+ pipUiEventLogger, shellTaskOrganizer);
+ }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/wmshell/WMShell.java b/packages/SystemUI/src/com/android/systemui/wmshell/WMShell.java
index b7d6903be23a..c7a9af3642e5 100644
--- a/packages/SystemUI/src/com/android/systemui/wmshell/WMShell.java
+++ b/packages/SystemUI/src/com/android/systemui/wmshell/WMShell.java
@@ -16,20 +16,47 @@
package com.android.systemui.wmshell;
+import static android.view.Display.DEFAULT_DISPLAY;
+import static android.view.WindowManagerPolicyConstants.NAV_BAR_MODE_3BUTTON;
+
+import static com.android.systemui.shared.system.QuickStepContract.SYSUI_STATE_ONE_HANDED_ACTIVE;
import static com.android.systemui.shared.system.WindowManagerWrapper.WINDOWING_MODE_SPLIT_SCREEN_PRIMARY;
import android.app.ActivityManager;
+import android.content.ComponentName;
import android.content.Context;
+import android.graphics.Rect;
+import android.inputmethodservice.InputMethodService;
+import android.os.IBinder;
+import android.view.KeyEvent;
+import com.android.internal.annotations.VisibleForTesting;
import com.android.keyguard.KeyguardUpdateMonitor;
import com.android.keyguard.KeyguardUpdateMonitorCallback;
import com.android.systemui.SystemUI;
import com.android.systemui.dagger.SysUISingleton;
+import com.android.systemui.keyguard.ScreenLifecycle;
+import com.android.systemui.model.SysUiState;
+import com.android.systemui.navigationbar.NavigationModeController;
+import com.android.systemui.onehanded.OneHanded;
+import com.android.systemui.onehanded.OneHandedEvents;
+import com.android.systemui.onehanded.OneHandedGestureHandler.OneHandedGestureEventCallback;
+import com.android.systemui.onehanded.OneHandedTransitionCallback;
+import com.android.systemui.pip.Pip;
import com.android.systemui.shared.system.ActivityManagerWrapper;
import com.android.systemui.shared.system.TaskStackChangeListener;
-import com.android.systemui.stackdivider.SplitScreenController;
+import com.android.systemui.shared.tracing.ProtoTraceable;
+import com.android.systemui.statusbar.CommandQueue;
+import com.android.systemui.tracing.ProtoTracer;
+import com.android.systemui.tracing.nano.SystemUiTraceProto;
import com.android.wm.shell.common.DisplayImeController;
+import com.android.wm.shell.nano.WmShellTraceProto;
+import com.android.wm.shell.protolog.ShellProtoLogImpl;
+import com.android.wm.shell.splitscreen.SplitScreen;
+import java.io.FileDescriptor;
+import java.io.PrintWriter;
+import java.util.Arrays;
import java.util.Optional;
import javax.inject.Inject;
@@ -38,19 +65,44 @@ import javax.inject.Inject;
* Proxy in SysUiScope to delegate events to controllers in WM Shell library.
*/
@SysUISingleton
-public final class WMShell extends SystemUI {
- private final KeyguardUpdateMonitor mKeyguardUpdateMonitor;
+public final class WMShell extends SystemUI implements ProtoTraceable<SystemUiTraceProto> {
+ private final CommandQueue mCommandQueue;
private final DisplayImeController mDisplayImeController;
- private final Optional<SplitScreenController> mSplitScreenControllerOptional;
+ private final KeyguardUpdateMonitor mKeyguardUpdateMonitor;
+ private final ActivityManagerWrapper mActivityManagerWrapper;
+ private final NavigationModeController mNavigationModeController;
+ private final ScreenLifecycle mScreenLifecycle;
+ private final SysUiState mSysUiState;
+ private final Optional<Pip> mPipOptional;
+ private final Optional<SplitScreen> mSplitScreenOptional;
+ private final Optional<OneHanded> mOneHandedOptional;
+ private final ProtoTracer mProtoTracer;
@Inject
- WMShell(Context context, KeyguardUpdateMonitor keyguardUpdateMonitor,
+ public WMShell(Context context, CommandQueue commandQueue,
+ KeyguardUpdateMonitor keyguardUpdateMonitor,
+ ActivityManagerWrapper activityManagerWrapper,
DisplayImeController displayImeController,
- Optional<SplitScreenController> splitScreenControllerOptional) {
+ NavigationModeController navigationModeController,
+ ScreenLifecycle screenLifecycle,
+ SysUiState sysUiState,
+ Optional<Pip> pipOptional,
+ Optional<SplitScreen> splitScreenOptional,
+ Optional<OneHanded> oneHandedOptional,
+ ProtoTracer protoTracer) {
super(context);
+ mCommandQueue = commandQueue;
mKeyguardUpdateMonitor = keyguardUpdateMonitor;
+ mActivityManagerWrapper = activityManagerWrapper;
mDisplayImeController = displayImeController;
- mSplitScreenControllerOptional = splitScreenControllerOptional;
+ mNavigationModeController = navigationModeController;
+ mScreenLifecycle = screenLifecycle;
+ mSysUiState = sysUiState;
+ mPipOptional = pipOptional;
+ mSplitScreenOptional = splitScreenOptional;
+ mOneHandedOptional = oneHandedOptional;
+ mProtoTracer = protoTracer;
+ mProtoTracer.add(this);
}
@Override
@@ -59,11 +111,23 @@ public final class WMShell extends SystemUI {
// constructor. And make sure the initialization of DisplayImeController won't depend on
// specific feature anymore.
mDisplayImeController.startMonitorDisplays();
+ mPipOptional.ifPresent(this::initPip);
+ mSplitScreenOptional.ifPresent(this::initSplitScreen);
+ mOneHandedOptional.ifPresent(this::initOneHanded);
+ }
- mSplitScreenControllerOptional.ifPresent(this::initSplitScreenController);
+ @VisibleForTesting
+ void initPip(Pip pip) {
+ mCommandQueue.addCallback(new CommandQueue.Callbacks() {
+ @Override
+ public void showPictureInPictureMenu() {
+ pip.showPictureInPictureMenu();
+ }
+ });
}
- private void initSplitScreenController(SplitScreenController splitScreenController) {
+ @VisibleForTesting
+ void initSplitScreen(SplitScreen splitScreen) {
mKeyguardUpdateMonitor.registerCallback(new KeyguardUpdateMonitorCallback() {
@Override
public void onKeyguardVisibilityChanged(boolean showing) {
@@ -71,42 +135,179 @@ public final class WMShell extends SystemUI {
// above everything, it is actually transparent except for notifications, so
// we still need to hide any surfaces that are below it.
// TODO(b/148906453): Figure out keyguard dismiss animation for divider view.
- splitScreenController.onKeyguardVisibilityChanged(showing);
+ splitScreen.onKeyguardVisibilityChanged(showing);
}
});
- ActivityManagerWrapper.getInstance().registerTaskStackListener(
+ mActivityManagerWrapper.registerTaskStackListener(
new TaskStackChangeListener() {
@Override
public void onActivityRestartAttempt(ActivityManager.RunningTaskInfo task,
boolean homeTaskVisible, boolean clearedTask, boolean wasVisible) {
if (!wasVisible || task.configuration.windowConfiguration.getWindowingMode()
!= WINDOWING_MODE_SPLIT_SCREEN_PRIMARY
- || !splitScreenController.isSplitScreenSupported()) {
+ || !splitScreen.isSplitScreenSupported()) {
return;
}
- if (splitScreenController.isMinimized()) {
- splitScreenController.onUndockingTask();
+ if (splitScreen.isMinimized()) {
+ splitScreen.onUndockingTask();
}
}
@Override
public void onActivityForcedResizable(String packageName, int taskId,
int reason) {
- splitScreenController
- .onActivityForcedResizable(packageName, taskId, reason);
+ splitScreen.onActivityForcedResizable(packageName, taskId, reason);
}
@Override
public void onActivityDismissingDockedStack() {
- splitScreenController.onActivityDismissingSplitScreen();
+ splitScreen.onActivityDismissingSplitScreen();
}
@Override
public void onActivityLaunchOnSecondaryDisplayFailed() {
- splitScreenController.onActivityLaunchOnSecondaryDisplayFailed();
+ splitScreen.onActivityLaunchOnSecondaryDisplayFailed();
+ }
+ });
+ }
+
+ @VisibleForTesting
+ void initOneHanded(OneHanded oneHanded) {
+ if (!oneHanded.hasOneHandedFeature()) {
+ return;
+ }
+
+ int currentMode = mNavigationModeController.addListener(mode ->
+ oneHanded.setThreeButtonModeEnabled(mode == NAV_BAR_MODE_3BUTTON));
+ oneHanded.setThreeButtonModeEnabled(currentMode == NAV_BAR_MODE_3BUTTON);
+
+ oneHanded.registerTransitionCallback(new OneHandedTransitionCallback() {
+ @Override
+ public void onStartFinished(Rect bounds) {
+ mSysUiState.setFlag(SYSUI_STATE_ONE_HANDED_ACTIVE,
+ true).commitUpdate(DEFAULT_DISPLAY);
+ }
+
+ @Override
+ public void onStopFinished(Rect bounds) {
+ mSysUiState.setFlag(SYSUI_STATE_ONE_HANDED_ACTIVE,
+ false).commitUpdate(DEFAULT_DISPLAY);
+ }
+ });
+
+ oneHanded.registerGestureCallback(new OneHandedGestureEventCallback() {
+ @Override
+ public void onStart() {
+ if (oneHanded.isOneHandedEnabled()) {
+ oneHanded.startOneHanded();
+ } else if (oneHanded.isSwipeToNotificationEnabled()) {
+ mCommandQueue.handleSystemKey(KeyEvent.KEYCODE_SYSTEM_NAVIGATION_DOWN);
+ }
+ }
+
+ @Override
+ public void onStop() {
+ if (oneHanded.isOneHandedEnabled()) {
+ oneHanded.stopOneHanded(OneHandedEvents.EVENT_ONE_HANDED_TRIGGER_GESTURE_OUT);
+ } else if (oneHanded.isSwipeToNotificationEnabled()) {
+ mCommandQueue.handleSystemKey(KeyEvent.KEYCODE_SYSTEM_NAVIGATION_UP);
+ }
+ }
+ });
+
+ mKeyguardUpdateMonitor.registerCallback(new KeyguardUpdateMonitorCallback() {
+ @Override
+ public void onKeyguardBouncerChanged(boolean bouncer) {
+ if (bouncer) {
+ oneHanded.stopOneHanded();
+ }
+ }
+
+ @Override
+ public void onKeyguardVisibilityChanged(boolean showing) {
+ oneHanded.stopOneHanded();
+ }
+ });
+
+ mScreenLifecycle.addObserver(new ScreenLifecycle.Observer() {
+ @Override
+ public void onScreenTurningOff() {
+ oneHanded.stopOneHanded(
+ OneHandedEvents.EVENT_ONE_HANDED_TRIGGER_SCREEN_OFF_OUT);
+ }
+ });
+
+ mCommandQueue.addCallback(new CommandQueue.Callbacks() {
+ @Override
+ public void onCameraLaunchGestureDetected(int source) {
+ oneHanded.stopOneHanded();
+ }
+
+ @Override
+ public void setImeWindowStatus(int displayId, IBinder token, int vis,
+ int backDisposition, boolean showImeSwitcher) {
+ if (displayId != DEFAULT_DISPLAY && (vis & InputMethodService.IME_VISIBLE) == 0) {
+ return;
+ }
+ oneHanded.stopOneHanded(OneHandedEvents.EVENT_ONE_HANDED_TRIGGER_POP_IME_OUT);
+ }
+ });
+
+ mActivityManagerWrapper.registerTaskStackListener(
+ new TaskStackChangeListener() {
+ @Override
+ public void onTaskCreated(int taskId, ComponentName componentName) {
+ oneHanded.stopOneHanded(
+ OneHandedEvents.EVENT_ONE_HANDED_TRIGGER_APP_TAPS_OUT);
+ }
+
+ @Override
+ public void onTaskMovedToFront(int taskId) {
+ oneHanded.stopOneHanded(
+ OneHandedEvents.EVENT_ONE_HANDED_TRIGGER_APP_TAPS_OUT);
}
});
}
+
+ @Override
+ public void writeToProto(SystemUiTraceProto proto) {
+ if (proto.wmShell == null) {
+ proto.wmShell = new WmShellTraceProto();
+ }
+ // Dump to WMShell proto here
+ // TODO: Figure out how we want to synchronize while dumping to proto
+ }
+
+ @Override
+ public void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
+ // Handle commands if provided
+ for (int i = 0; i < args.length; i++) {
+ switch (args[i]) {
+ case "enable-text-logging": {
+ String[] groups = Arrays.copyOfRange(args, i + 1, args.length);
+ startTextLogging(groups);
+ pw.println("Starting logging on groups: " + Arrays.toString(groups));
+ return;
+ }
+ case "disable-text-logging": {
+ String[] groups = Arrays.copyOfRange(args, i + 1, args.length);
+ stopTextLogging(groups);
+ pw.println("Stopping logging on groups: " + Arrays.toString(groups));
+ return;
+ }
+ }
+ }
+
+ // Dump WMShell stuff here if no commands were handled
+ }
+
+ private void startTextLogging(String... groups) {
+ ShellProtoLogImpl.getSingleInstance().startTextLogging(mContext, groups);
+ }
+
+ private void stopTextLogging(String... groups) {
+ ShellProtoLogImpl.getSingleInstance().stopTextLogging(groups);
+ }
}
diff --git a/packages/SystemUI/src/com/android/systemui/wmshell/WMShellBaseModule.java b/packages/SystemUI/src/com/android/systemui/wmshell/WMShellBaseModule.java
index 3111b13bc7f4..adb9186d6705 100644
--- a/packages/SystemUI/src/com/android/systemui/wmshell/WMShellBaseModule.java
+++ b/packages/SystemUI/src/com/android/systemui/wmshell/WMShellBaseModule.java
@@ -18,19 +18,25 @@ package com.android.systemui.wmshell;
import android.content.Context;
import android.os.Handler;
+import android.util.DisplayMetrics;
import android.view.IWindowManager;
import com.android.internal.logging.UiEventLogger;
import com.android.systemui.dagger.SysUISingleton;
import com.android.systemui.dagger.qualifiers.Main;
+import com.android.systemui.onehanded.OneHanded;
+import com.android.systemui.pip.Pip;
+import com.android.systemui.pip.PipSurfaceTransactionHelper;
import com.android.systemui.pip.PipUiEventLogger;
-import com.android.systemui.stackdivider.SplitScreenController;
+import com.android.systemui.statusbar.policy.ConfigurationController;
import com.android.systemui.util.DeviceConfigProxy;
import com.android.systemui.util.FloatingContentCoordinator;
import com.android.wm.shell.ShellTaskOrganizer;
+import com.android.wm.shell.animation.FlingAnimationUtils;
import com.android.wm.shell.common.DisplayController;
import com.android.wm.shell.common.SystemWindows;
import com.android.wm.shell.common.TransactionPool;
+import com.android.wm.shell.splitscreen.SplitScreen;
import dagger.BindsOptionalOf;
import dagger.Module;
@@ -76,6 +82,13 @@ public abstract class WMShellBaseModule {
@SysUISingleton
@Provides
+ static PipSurfaceTransactionHelper providesPipSurfaceTransactionHelper(Context context,
+ ConfigurationController configController) {
+ return new PipSurfaceTransactionHelper(context, configController);
+ }
+
+ @SysUISingleton
+ @Provides
static SystemWindows provideSystemWindows(DisplayController displayController,
IWindowManager wmService) {
return new SystemWindows(displayController, wmService);
@@ -89,6 +102,19 @@ public abstract class WMShellBaseModule {
return organizer;
}
+ @SysUISingleton
+ @Provides
+ static FlingAnimationUtils.Builder provideFlingAnimationUtilsBuilder(
+ DisplayMetrics displayMetrics) {
+ return new FlingAnimationUtils.Builder(displayMetrics);
+ }
+
+ @BindsOptionalOf
+ abstract Pip optionalPip();
+
+ @BindsOptionalOf
+ abstract SplitScreen optionalSplitScreen();
+
@BindsOptionalOf
- abstract SplitScreenController optionalSplitScreenController();
+ abstract OneHanded optionalOneHanded();
}
diff --git a/packages/SystemUI/src/com/android/systemui/wmshell/WMShellModule.java b/packages/SystemUI/src/com/android/systemui/wmshell/WMShellModule.java
index ceb6d5970007..3a249d68d969 100644
--- a/packages/SystemUI/src/com/android/systemui/wmshell/WMShellModule.java
+++ b/packages/SystemUI/src/com/android/systemui/wmshell/WMShellModule.java
@@ -20,16 +20,30 @@ import android.content.Context;
import android.os.Handler;
import android.view.IWindowManager;
+import com.android.systemui.broadcast.BroadcastDispatcher;
import com.android.systemui.dagger.SysUISingleton;
import com.android.systemui.dagger.qualifiers.Main;
-import com.android.systemui.pip.phone.PipMenuActivity;
-import com.android.systemui.pip.phone.dagger.PipMenuActivityClass;
-import com.android.systemui.stackdivider.SplitScreenController;
+import com.android.systemui.model.SysUiState;
+import com.android.systemui.onehanded.OneHanded;
+import com.android.systemui.onehanded.OneHandedController;
+import com.android.systemui.pip.Pip;
+import com.android.systemui.pip.PipBoundsHandler;
+import com.android.systemui.pip.PipSurfaceTransactionHelper;
+import com.android.systemui.pip.PipTaskOrganizer;
+import com.android.systemui.pip.PipUiEventLogger;
+import com.android.systemui.pip.phone.PipController;
+import com.android.systemui.statusbar.policy.ConfigurationController;
+import com.android.systemui.util.DeviceConfigProxy;
+import com.android.systemui.util.FloatingContentCoordinator;
import com.android.wm.shell.ShellTaskOrganizer;
import com.android.wm.shell.common.DisplayController;
import com.android.wm.shell.common.DisplayImeController;
import com.android.wm.shell.common.SystemWindows;
import com.android.wm.shell.common.TransactionPool;
+import com.android.wm.shell.splitscreen.SplitScreen;
+import com.android.wm.shell.splitscreen.SplitScreenController;
+
+import java.util.Optional;
import dagger.Module;
import dagger.Provides;
@@ -49,21 +63,58 @@ public class WMShellModule {
return new DisplayImeController(wmService, displayController, mainHandler, transactionPool);
}
- /** TODO(b/150319024): PipMenuActivity will move to a Window */
@SysUISingleton
- @PipMenuActivityClass
@Provides
- static Class<?> providePipMenuActivityClass() {
- return PipMenuActivity.class;
+ static Pip providePipController(Context context,
+ BroadcastDispatcher broadcastDispatcher,
+ ConfigurationController configController,
+ DeviceConfigProxy deviceConfig,
+ DisplayController displayController,
+ FloatingContentCoordinator floatingContentCoordinator,
+ SysUiState sysUiState,
+ PipBoundsHandler pipBoundsHandler,
+ PipSurfaceTransactionHelper surfaceTransactionHelper,
+ PipTaskOrganizer pipTaskOrganizer,
+ PipUiEventLogger pipUiEventLogger) {
+ return new PipController(context, broadcastDispatcher, configController, deviceConfig,
+ displayController, floatingContentCoordinator, sysUiState, pipBoundsHandler,
+ surfaceTransactionHelper,
+ pipTaskOrganizer,
+ pipUiEventLogger);
}
@SysUISingleton
@Provides
- static SplitScreenController provideSplitScreenController(Context context,
+ static SplitScreen provideSplitScreen(Context context,
DisplayController displayController, SystemWindows systemWindows,
DisplayImeController displayImeController, @Main Handler handler,
TransactionPool transactionPool, ShellTaskOrganizer shellTaskOrganizer) {
return new SplitScreenController(context, displayController, systemWindows,
displayImeController, handler, transactionPool, shellTaskOrganizer);
}
+
+ @SysUISingleton
+ @Provides
+ static PipBoundsHandler providesPipBoundsHandler(Context context) {
+ return new PipBoundsHandler(context);
+ }
+
+ @SysUISingleton
+ @Provides
+ static PipTaskOrganizer providesPipTaskOrganizer(Context context,
+ PipBoundsHandler pipBoundsHandler,
+ PipSurfaceTransactionHelper pipSurfaceTransactionHelper,
+ Optional<SplitScreen> splitScreenOptional, DisplayController displayController,
+ PipUiEventLogger pipUiEventLogger, ShellTaskOrganizer shellTaskOrganizer) {
+ return new PipTaskOrganizer(context, pipBoundsHandler,
+ pipSurfaceTransactionHelper, splitScreenOptional, displayController,
+ pipUiEventLogger, shellTaskOrganizer);
+ }
+
+ @SysUISingleton
+ @Provides
+ static OneHanded provideOneHandedController(Context context,
+ DisplayController displayController) {
+ return OneHandedController.create(context, displayController);
+ }
}
diff --git a/packages/SystemUI/tests/src/com/android/keyguard/KeyguardClockSwitchControllerTest.java b/packages/SystemUI/tests/src/com/android/keyguard/KeyguardClockSwitchControllerTest.java
index 657e4fbb4633..3aa6ec08683f 100644
--- a/packages/SystemUI/tests/src/com/android/keyguard/KeyguardClockSwitchControllerTest.java
+++ b/packages/SystemUI/tests/src/com/android/keyguard/KeyguardClockSwitchControllerTest.java
@@ -62,6 +62,8 @@ public class KeyguardClockSwitchControllerTest extends SysuiTestCase {
private ClockPlugin mClockPlugin;
@Mock
ColorExtractor.GradientColors mGradientColors;
+ @Mock
+ KeyguardSliceViewController mKeyguardSliceViewController;
private KeyguardClockSwitchController mController;
@@ -69,28 +71,30 @@ public class KeyguardClockSwitchControllerTest extends SysuiTestCase {
public void setup() {
MockitoAnnotations.initMocks(this);
+ when(mView.isAttachedToWindow()).thenReturn(true);
+
mController = new KeyguardClockSwitchController(
- mStatusBarStateController, mColorExtractor, mClockManager);
+ mView, mStatusBarStateController, mColorExtractor, mClockManager,
+ mKeyguardSliceViewController);
- when(mView.isAttachedToWindow()).thenReturn(true);
when(mStatusBarStateController.getState()).thenReturn(StatusBarState.SHADE);
when(mColorExtractor.getColors(anyInt())).thenReturn(mGradientColors);
}
@Test
- public void testAttach_viewAlreadyAttached() {
- mController.attach(mView);
+ public void testInit_viewAlreadyAttached() {
+ mController.init();
verifyAttachment(times(1));
}
@Test
- public void testAttach_viewNotYetAttached() {
+ public void testInit_viewNotYetAttached() {
ArgumentCaptor<View.OnAttachStateChangeListener> listenerArgumentCaptor =
ArgumentCaptor.forClass(View.OnAttachStateChangeListener.class);
when(mView.isAttachedToWindow()).thenReturn(false);
- mController.attach(mView);
+ mController.init();
verify(mView).addOnAttachStateChangeListener(listenerArgumentCaptor.capture());
verifyAttachment(never());
@@ -100,12 +104,17 @@ public class KeyguardClockSwitchControllerTest extends SysuiTestCase {
verifyAttachment(times(1));
}
+ @Test
+ public void testInitSubControllers() {
+ mController.init();
+ verify(mKeyguardSliceViewController).init();
+ }
@Test
- public void testAttach_viewDetached() {
+ public void testInit_viewDetached() {
ArgumentCaptor<View.OnAttachStateChangeListener> listenerArgumentCaptor =
ArgumentCaptor.forClass(View.OnAttachStateChangeListener.class);
- mController.attach(mView);
+ mController.init();
verify(mView).addOnAttachStateChangeListener(listenerArgumentCaptor.capture());
verifyAttachment(times(1));
@@ -122,7 +131,7 @@ public class KeyguardClockSwitchControllerTest extends SysuiTestCase {
public void testBigClockPassesStatusBarState() {
ViewGroup testView = new FrameLayout(mContext);
- mController.attach(mView);
+ mController.init();
when(mStatusBarStateController.getState()).thenReturn(StatusBarState.SHADE);
mController.setBigClockContainer(testView);
verify(mView).setBigClockContainer(testView, StatusBarState.SHADE);
@@ -143,7 +152,7 @@ public class KeyguardClockSwitchControllerTest extends SysuiTestCase {
ArgumentCaptor<ClockManager.ClockChangedListener> listenerArgumentCaptor =
ArgumentCaptor.forClass(ClockManager.ClockChangedListener.class);
- mController.attach(mView);
+ mController.init();
verify(mClockManager).addOnClockChangedListener(listenerArgumentCaptor.capture());
listenerArgumentCaptor.getValue().onClockChanged(mClockPlugin);
diff --git a/packages/SystemUI/tests/src/com/android/keyguard/KeyguardPresentationTest.java b/packages/SystemUI/tests/src/com/android/keyguard/KeyguardPresentationTest.java
index 446b1228f1bb..559284ac0672 100644
--- a/packages/SystemUI/tests/src/com/android/keyguard/KeyguardPresentationTest.java
+++ b/packages/SystemUI/tests/src/com/android/keyguard/KeyguardPresentationTest.java
@@ -16,6 +16,7 @@
package com.android.keyguard;
+import static org.mockito.ArgumentMatchers.any;
import static org.mockito.Mockito.when;
import android.content.Context;
@@ -28,6 +29,7 @@ import android.view.View;
import androidx.test.filters.SmallTest;
import com.android.keyguard.KeyguardDisplayManager.KeyguardPresentation;
+import com.android.keyguard.dagger.KeyguardStatusViewComponent;
import com.android.systemui.R;
import com.android.systemui.SystemUIFactory;
import com.android.systemui.SysuiTestCase;
@@ -51,6 +53,12 @@ public class KeyguardPresentationTest extends SysuiTestCase {
KeyguardSliceView mMockKeyguardSliceView;
@Mock
KeyguardStatusView mMockKeyguardStatusView;
+ @Mock
+ private KeyguardStatusViewComponent.Factory mKeyguardStatusViewComponentFactory;
+ @Mock
+ private KeyguardStatusViewComponent mKeyguardStatusViewComponent;
+ @Mock
+ private KeyguardClockSwitchController mKeyguardClockSwitchController;
LayoutInflater mLayoutInflater;
@@ -62,6 +70,11 @@ public class KeyguardPresentationTest extends SysuiTestCase {
when(mMockKeyguardSliceView.getContext()).thenReturn(mContext);
when(mMockKeyguardStatusView.getContext()).thenReturn(mContext);
when(mMockKeyguardStatusView.findViewById(R.id.clock)).thenReturn(mMockKeyguardStatusView);
+ when(mKeyguardStatusViewComponentFactory.build(any(KeyguardStatusView.class)))
+ .thenReturn(mKeyguardStatusViewComponent);
+ when(mKeyguardStatusViewComponent.getKeyguardClockSwitchController())
+ .thenReturn(mKeyguardClockSwitchController);
+
allowTestableLooperAsMainThread();
InjectionInflationController inflationController = new InjectionInflationController(
@@ -99,7 +112,8 @@ public class KeyguardPresentationTest extends SysuiTestCase {
@Test
public void testInflation_doesntCrash() {
KeyguardPresentation keyguardPresentation = new KeyguardPresentation(mContext,
- mContext.getDisplayNoVerify(), mLayoutInflater);
+ mContext.getDisplayNoVerify(), mKeyguardStatusViewComponentFactory,
+ mLayoutInflater);
keyguardPresentation.onCreate(null /*savedInstanceState */);
}
}
diff --git a/packages/SystemUI/tests/src/com/android/keyguard/KeyguardSliceViewControllerTest.java b/packages/SystemUI/tests/src/com/android/keyguard/KeyguardSliceViewControllerTest.java
new file mode 100644
index 000000000000..b7bcaa3c3566
--- /dev/null
+++ b/packages/SystemUI/tests/src/com/android/keyguard/KeyguardSliceViewControllerTest.java
@@ -0,0 +1,99 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.android.keyguard;
+
+import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.ArgumentMatchers.anyString;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.when;
+
+import android.test.suitebuilder.annotation.SmallTest;
+import android.testing.AndroidTestingRunner;
+import android.testing.TestableLooper.RunWithLooper;
+import android.view.View;
+
+import com.android.systemui.SysuiTestCase;
+import com.android.systemui.dump.DumpManager;
+import com.android.systemui.keyguard.KeyguardSliceProvider;
+import com.android.systemui.plugins.ActivityStarter;
+import com.android.systemui.statusbar.policy.ConfigurationController;
+import com.android.systemui.tuner.TunerService;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.ArgumentCaptor;
+import org.mockito.Mock;
+import org.mockito.MockitoAnnotations;
+
+@SmallTest
+@RunWith(AndroidTestingRunner.class)
+@RunWithLooper(setAsMainLooper = true)
+public class KeyguardSliceViewControllerTest extends SysuiTestCase {
+ @Mock
+ private KeyguardSliceView mView;;
+ @Mock
+ private KeyguardStatusView mKeyguardStatusView;
+ @Mock
+ private TunerService mTunerService;
+ @Mock
+ private ConfigurationController mConfigurationController;
+ @Mock
+ private ActivityStarter mActivityStarter;
+ private DumpManager mDumpManager = new DumpManager();
+
+ private KeyguardSliceViewController mController;
+
+ @Before
+ public void setUp() throws Exception {
+ MockitoAnnotations.initMocks(this);
+ when(mView.isAttachedToWindow()).thenReturn(true);
+ when(mView.getContext()).thenReturn(mContext);
+ mController = new KeyguardSliceViewController(
+ mView, mKeyguardStatusView, mActivityStarter, mConfigurationController,
+ mTunerService, mDumpManager);
+ mController.setupUri(KeyguardSliceProvider.KEYGUARD_SLICE_URI);
+ }
+
+ @Test
+ public void refresh_replacesSliceContentAndNotifiesListener() {
+ mController.refresh();
+ verify(mView).hideSlice();
+ }
+
+ @Test
+ public void onAttachedToWindow_registersListeners() {
+ mController.init();
+ verify(mTunerService).addTunable(any(TunerService.Tunable.class), anyString());
+ verify(mConfigurationController).addCallback(
+ any(ConfigurationController.ConfigurationListener.class));
+ }
+
+ @Test
+ public void onDetachedFromWindow_unregistersListeners() {
+ ArgumentCaptor<View.OnAttachStateChangeListener> attachListenerArgumentCaptor =
+ ArgumentCaptor.forClass(View.OnAttachStateChangeListener.class);
+
+ mController.init();
+ verify(mView).addOnAttachStateChangeListener(attachListenerArgumentCaptor.capture());
+
+ attachListenerArgumentCaptor.getValue().onViewDetachedFromWindow(mView);
+
+ verify(mTunerService).removeTunable(any(TunerService.Tunable.class));
+ verify(mConfigurationController).removeCallback(
+ any(ConfigurationController.ConfigurationListener.class));
+ }
+}
diff --git a/packages/SystemUI/tests/src/com/android/keyguard/KeyguardSliceViewTest.java b/packages/SystemUI/tests/src/com/android/keyguard/KeyguardSliceViewTest.java
index 06552b9bdbb4..1ab08c27088a 100644
--- a/packages/SystemUI/tests/src/com/android/keyguard/KeyguardSliceViewTest.java
+++ b/packages/SystemUI/tests/src/com/android/keyguard/KeyguardSliceViewTest.java
@@ -15,37 +15,27 @@
*/
package com.android.keyguard;
-import static org.mockito.ArgumentMatchers.anyString;
-import static org.mockito.ArgumentMatchers.eq;
-import static org.mockito.Mockito.verify;
-
-import android.content.Context;
-import android.content.res.Resources;
import android.graphics.Color;
import android.net.Uri;
import android.test.suitebuilder.annotation.SmallTest;
import android.testing.AndroidTestingRunner;
import android.testing.TestableLooper.RunWithLooper;
-import android.util.AttributeSet;
import android.view.LayoutInflater;
-import android.view.View;
+import androidx.slice.Slice;
import androidx.slice.SliceProvider;
import androidx.slice.SliceSpecs;
import androidx.slice.builders.ListBuilder;
+import androidx.slice.widget.RowContent;
import com.android.systemui.R;
import com.android.systemui.SysuiTestCase;
import com.android.systemui.keyguard.KeyguardSliceProvider;
-import com.android.systemui.plugins.ActivityStarter;
-import com.android.systemui.statusbar.policy.ConfigurationController;
-import com.android.systemui.tuner.TunerService;
import org.junit.Assert;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
-import org.mockito.Mock;
import org.mockito.MockitoAnnotations;
import java.util.Collections;
@@ -53,46 +43,18 @@ import java.util.HashSet;
import java.util.concurrent.atomic.AtomicBoolean;
@SmallTest
-@RunWithLooper
+@RunWithLooper(setAsMainLooper = true)
@RunWith(AndroidTestingRunner.class)
public class KeyguardSliceViewTest extends SysuiTestCase {
private KeyguardSliceView mKeyguardSliceView;
private Uri mSliceUri;
- @Mock
- private TunerService mTunerService;
- @Mock
- private ConfigurationController mConfigurationController;
- @Mock
- private ActivityStarter mActivityStarter;
- @Mock
- private Resources mResources;
-
@Before
public void setUp() throws Exception {
MockitoAnnotations.initMocks(this);
- allowTestableLooperAsMainThread();
LayoutInflater layoutInflater = LayoutInflater.from(getContext());
- layoutInflater.setPrivateFactory(new LayoutInflater.Factory2() {
-
- @Override
- public View onCreateView(View parent, String name, Context context,
- AttributeSet attrs) {
- return onCreateView(name, context, attrs);
- }
-
- @Override
- public View onCreateView(String name, Context context, AttributeSet attrs) {
- if ("com.android.keyguard.KeyguardSliceView".equals(name)) {
- return new KeyguardSliceView(getContext(), attrs, mActivityStarter,
- mConfigurationController, mTunerService, mResources);
- }
- return null;
- }
- });
mKeyguardSliceView = (KeyguardSliceView) layoutInflater
.inflate(R.layout.keyguard_status_area, null);
- mKeyguardSliceView.setupUri(KeyguardSliceProvider.KEYGUARD_SLICE_URI);
mSliceUri = Uri.parse(KeyguardSliceProvider.KEYGUARD_SLICE_URI);
SliceProvider.setSpecs(new HashSet<>(Collections.singletonList(SliceSpecs.LIST)));
}
@@ -100,9 +62,13 @@ public class KeyguardSliceViewTest extends SysuiTestCase {
@Test
public void showSlice_notifiesListener() {
ListBuilder builder = new ListBuilder(getContext(), mSliceUri, ListBuilder.INFINITY);
+ builder.setHeader(new ListBuilder.HeaderBuilder().setTitle("header title!"));
+ Slice slice = builder.build();
+ RowContent rowContent = new RowContent(slice.getItemArray()[0], 0);
+
AtomicBoolean notified = new AtomicBoolean();
mKeyguardSliceView.setContentChangeListener(()-> notified.set(true));
- mKeyguardSliceView.onChanged(builder.build());
+ mKeyguardSliceView.showSlice(rowContent, Collections.EMPTY_LIST);
Assert.assertTrue("Listener should be notified about slice changes.",
notified.get());
}
@@ -111,7 +77,7 @@ public class KeyguardSliceViewTest extends SysuiTestCase {
public void showSlice_emptySliceNotifiesListener() {
AtomicBoolean notified = new AtomicBoolean();
mKeyguardSliceView.setContentChangeListener(()-> notified.set(true));
- mKeyguardSliceView.onChanged(null);
+ mKeyguardSliceView.showSlice(null, Collections.EMPTY_LIST);
Assert.assertTrue("Listener should be notified about slice changes.",
notified.get());
}
@@ -119,24 +85,17 @@ public class KeyguardSliceViewTest extends SysuiTestCase {
@Test
public void hasHeader_readsSliceData() {
ListBuilder builder = new ListBuilder(getContext(), mSliceUri, ListBuilder.INFINITY);
- mKeyguardSliceView.onChanged(builder.build());
+ mKeyguardSliceView.showSlice(null, Collections.EMPTY_LIST);
Assert.assertFalse("View should not have a header", mKeyguardSliceView.hasHeader());
builder.setHeader(new ListBuilder.HeaderBuilder().setTitle("header title!"));
- mKeyguardSliceView.onChanged(builder.build());
+ Slice slice = builder.build();
+ RowContent rowContent = new RowContent(slice.getItemArray()[0], 0);
+ mKeyguardSliceView.showSlice(rowContent, Collections.EMPTY_LIST);
Assert.assertTrue("View should have a header", mKeyguardSliceView.hasHeader());
}
@Test
- public void refresh_replacesSliceContentAndNotifiesListener() {
- AtomicBoolean notified = new AtomicBoolean();
- mKeyguardSliceView.setContentChangeListener(()-> notified.set(true));
- mKeyguardSliceView.refresh();
- Assert.assertTrue("Listener should be notified about slice changes.",
- notified.get());
- }
-
- @Test
public void getTextColor_whiteTextWhenAOD() {
// Set text color to red since the default is white and test would always pass
mKeyguardSliceView.setTextColor(Color.RED);
@@ -147,18 +106,4 @@ public class KeyguardSliceViewTest extends SysuiTestCase {
Assert.assertEquals("Should be using AOD text color", Color.WHITE,
mKeyguardSliceView.getTextColor());
}
-
- @Test
- public void onAttachedToWindow_registersListeners() {
- mKeyguardSliceView.onAttachedToWindow();
- verify(mTunerService).addTunable(eq(mKeyguardSliceView), anyString());
- verify(mConfigurationController).addCallback(eq(mKeyguardSliceView));
- }
-
- @Test
- public void onDetachedFromWindow_unregistersListeners() {
- mKeyguardSliceView.onDetachedFromWindow();
- verify(mTunerService).removeTunable(eq(mKeyguardSliceView));
- verify(mConfigurationController).removeCallback(eq(mKeyguardSliceView));
- }
}
diff --git a/packages/SystemUI/tests/src/com/android/keyguard/KeyguardStatusViewTest.java b/packages/SystemUI/tests/src/com/android/keyguard/KeyguardStatusViewTest.java
index 0bf137689aa1..0431704778c3 100644
--- a/packages/SystemUI/tests/src/com/android/keyguard/KeyguardStatusViewTest.java
+++ b/packages/SystemUI/tests/src/com/android/keyguard/KeyguardStatusViewTest.java
@@ -40,7 +40,8 @@ import org.mockito.Mock;
public class KeyguardStatusViewTest extends SysuiTestCase {
@Mock
- KeyguardSliceView mKeyguardSlice;
+ KeyguardSliceViewController mKeyguardSliceViewController;
+
@Mock
KeyguardClockSwitch mClockView;
@InjectMocks
@@ -64,7 +65,7 @@ public class KeyguardStatusViewTest extends SysuiTestCase {
@Test
public void dozeTimeTick_updatesSlice() {
mKeyguardStatusView.dozeTimeTick();
- verify(mKeyguardSlice).refresh();
+ verify(mKeyguardSliceViewController).refresh();
}
@Test
diff --git a/packages/SystemUI/tests/src/com/android/systemui/accessibility/IWindowMagnificationConnectionTest.java b/packages/SystemUI/tests/src/com/android/systemui/accessibility/IWindowMagnificationConnectionTest.java
index ac567e0ae67d..9079338cd502 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/accessibility/IWindowMagnificationConnectionTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/accessibility/IWindowMagnificationConnectionTest.java
@@ -18,10 +18,12 @@ package com.android.systemui.accessibility;
import static org.junit.Assert.assertNotNull;
import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.ArgumentMatchers.eq;
import static org.mockito.Mockito.doAnswer;
import static org.mockito.Mockito.verify;
import android.content.Context;
+import android.os.RemoteCallback;
import android.os.RemoteException;
import android.provider.Settings;
import android.testing.AndroidTestingRunner;
@@ -39,6 +41,7 @@ import com.android.systemui.statusbar.CommandQueue;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
+import org.mockito.ArgumentCaptor;
import org.mockito.Mock;
import org.mockito.MockitoAnnotations;
@@ -62,6 +65,9 @@ public class IWindowMagnificationConnectionTest extends SysuiTestCase {
private WindowMagnificationAnimationController mWindowMagnificationAnimationController;
@Mock
private ModeSwitchesController mModeSwitchesController;
+ @Mock
+ private RemoteCallback mRemoteCallback;
+ private ArgumentCaptor<Runnable> mRunnableCaptor = ArgumentCaptor.forClass(Runnable.class);
private IWindowMagnificationConnection mIWindowMagnificationConnection;
private WindowMagnification mWindowMagnification;
@@ -84,25 +90,24 @@ public class IWindowMagnificationConnectionTest extends SysuiTestCase {
}
@Test
- public void enableWindowMagnification() throws RemoteException {
+ public void enableWindowMagnification_passThrough() throws RemoteException {
mIWindowMagnificationConnection.enableWindowMagnification(TEST_DISPLAY, 3.0f, Float.NaN,
- Float.NaN);
+ Float.NaN, mRemoteCallback);
waitForIdleSync();
- verify(mWindowMagnificationAnimationController).enableWindowMagnification(3.0f, Float.NaN,
- Float.NaN);
+ verify(mWindowMagnificationAnimationController).enableWindowMagnification(eq(3.0f),
+ eq(Float.NaN), eq(Float.NaN), mRunnableCaptor.capture());
+ verifyRunnableWrapsRemoteCallback(mRunnableCaptor.getValue());
}
@Test
public void disableWindowMagnification_deleteWindowMagnification() throws RemoteException {
- mIWindowMagnificationConnection.enableWindowMagnification(TEST_DISPLAY, 3.0f, Float.NaN,
- Float.NaN);
- waitForIdleSync();
-
- mIWindowMagnificationConnection.disableWindowMagnification(TEST_DISPLAY);
+ mIWindowMagnificationConnection.disableWindowMagnification(TEST_DISPLAY, mRemoteCallback);
waitForIdleSync();
- verify(mWindowMagnificationAnimationController).deleteWindowMagnification();
+ verify(mWindowMagnificationAnimationController).deleteWindowMagnification(
+ mRunnableCaptor.capture());
+ verifyRunnableWrapsRemoteCallback(mRunnableCaptor.getValue());
}
@Test
@@ -138,5 +143,10 @@ public class IWindowMagnificationConnectionTest extends SysuiTestCase {
verify(mModeSwitchesController).removeButton(TEST_DISPLAY);
}
+
+ private void verifyRunnableWrapsRemoteCallback(Runnable runnable) {
+ runnable.run();
+ verify(mRemoteCallback).sendResult(null);
+ }
}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/accessibility/MagnificationModeSwitchTest.java b/packages/SystemUI/tests/src/com/android/systemui/accessibility/MagnificationModeSwitchTest.java
index ee151c441b68..cdbc647f152b 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/accessibility/MagnificationModeSwitchTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/accessibility/MagnificationModeSwitchTest.java
@@ -18,6 +18,10 @@ package com.android.systemui.accessibility;
import static android.provider.Settings.Secure.ACCESSIBILITY_MAGNIFICATION_MODE_FULLSCREEN;
import static android.provider.Settings.Secure.ACCESSIBILITY_MAGNIFICATION_MODE_WINDOW;
+import static android.view.MotionEvent.ACTION_CANCEL;
+import static android.view.MotionEvent.ACTION_DOWN;
+import static android.view.MotionEvent.ACTION_MOVE;
+import static android.view.MotionEvent.ACTION_UP;
import static com.android.systemui.accessibility.MagnificationModeSwitch.getIconResId;
@@ -27,6 +31,7 @@ import static org.mockito.ArgumentMatchers.any;
import static org.mockito.ArgumentMatchers.anyFloat;
import static org.mockito.ArgumentMatchers.anyLong;
import static org.mockito.ArgumentMatchers.eq;
+import static org.mockito.Mockito.doAnswer;
import static org.mockito.Mockito.times;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
@@ -35,7 +40,9 @@ import android.content.Context;
import android.content.pm.ActivityInfo;
import android.provider.Settings;
import android.testing.AndroidTestingRunner;
+import android.view.MotionEvent;
import android.view.View;
+import android.view.ViewConfiguration;
import android.view.ViewPropertyAnimator;
import android.view.WindowManager;
import android.widget.ImageView;
@@ -48,35 +55,38 @@ import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.ArgumentCaptor;
+import org.mockito.Captor;
import org.mockito.Mock;
+import org.mockito.Mockito;
import org.mockito.MockitoAnnotations;
@SmallTest
@RunWith(AndroidTestingRunner.class)
public class MagnificationModeSwitchTest extends SysuiTestCase {
- @Mock
- private ImageView mMockImageView;
+ private ImageView mSpyImageView;
@Mock
private WindowManager mWindowManager;
@Mock
private ViewPropertyAnimator mViewPropertyAnimator;
private MagnificationModeSwitch mMagnificationModeSwitch;
+ @Captor
+ private ArgumentCaptor<View.OnTouchListener> mTouchListenerCaptor;
@Before
public void setUp() throws Exception {
MockitoAnnotations.initMocks(this);
+ WindowManager wm = mContext.getSystemService(WindowManager.class);
+ doAnswer(invocation ->
+ wm.getMaximumWindowMetrics()
+ ).when(mWindowManager).getMaximumWindowMetrics();
mContext.addMockSystemService(Context.WINDOW_SERVICE, mWindowManager);
+ mSpyImageView = Mockito.spy(new ImageView(mContext));
+ doAnswer(invocation -> null).when(mSpyImageView).setOnTouchListener(
+ mTouchListenerCaptor.capture());
+ initMockImageViewAndAnimator();
- when(mViewPropertyAnimator.setDuration(anyLong())).thenReturn(mViewPropertyAnimator);
- when(mViewPropertyAnimator.alpha(anyFloat())).thenReturn(mViewPropertyAnimator);
- when(mViewPropertyAnimator.setStartDelay(anyLong())).thenReturn(mViewPropertyAnimator);
- when(mViewPropertyAnimator.withEndAction(any(Runnable.class))).thenReturn(
- mViewPropertyAnimator);
-
- when(mMockImageView.animate()).thenReturn(mViewPropertyAnimator);
-
- mMagnificationModeSwitch = new MagnificationModeSwitch(mContext, mMockImageView);
+ mMagnificationModeSwitch = new MagnificationModeSwitch(mContext, mSpyImageView);
}
@Test
@@ -85,7 +95,7 @@ public class MagnificationModeSwitchTest extends SysuiTestCase {
mMagnificationModeSwitch.removeButton();
- verify(mWindowManager).removeView(mMockImageView);
+ verify(mWindowManager).removeView(mSpyImageView);
// First invocation is in showButton.
verify(mViewPropertyAnimator, times(2)).cancel();
}
@@ -94,22 +104,19 @@ public class MagnificationModeSwitchTest extends SysuiTestCase {
public void showWindowModeButton_fullscreenMode_addViewAndSetImageResource() {
mMagnificationModeSwitch.showButton(ACCESSIBILITY_MAGNIFICATION_MODE_WINDOW);
- verify(mMockImageView).setAlpha(1.0f);
- verify(mMockImageView).setImageResource(
+ verify(mSpyImageView).setAlpha(1.0f);
+ verify(mSpyImageView).setImageResource(
getIconResId(ACCESSIBILITY_MAGNIFICATION_MODE_WINDOW));
- verify(mViewPropertyAnimator).cancel();
- verify(mViewPropertyAnimator).setDuration(anyLong());
- verify(mViewPropertyAnimator).setStartDelay(anyLong());
- verify(mViewPropertyAnimator).alpha(anyFloat());
+ assertShowButtonAnimation();
ArgumentCaptor<Runnable> captor = ArgumentCaptor.forClass(Runnable.class);
verify(mViewPropertyAnimator).withEndAction(captor.capture());
- verify(mWindowManager).addView(eq(mMockImageView), any(WindowManager.LayoutParams.class));
+ verify(mWindowManager).addView(eq(mSpyImageView), any(WindowManager.LayoutParams.class));
captor.getValue().run();
// First invocation is in showButton.
verify(mViewPropertyAnimator, times(2)).cancel();
- verify(mWindowManager).removeView(mMockImageView);
+ verify(mWindowManager).removeView(mSpyImageView);
}
@Test
@@ -117,26 +124,131 @@ public class MagnificationModeSwitchTest extends SysuiTestCase {
mMagnificationModeSwitch.showButton(ACCESSIBILITY_MAGNIFICATION_MODE_FULLSCREEN);
mMagnificationModeSwitch.onConfigurationChanged(ActivityInfo.CONFIG_DENSITY);
- verify(mMockImageView, times(2)).setImageResource(
+ verify(mSpyImageView, times(2)).setImageResource(
getIconResId(ACCESSIBILITY_MAGNIFICATION_MODE_FULLSCREEN));
}
@Test
- public void performClick_fullscreenMode_removeViewAndChangeSettingsValue() {
- ArgumentCaptor<View.OnClickListener> captor = ArgumentCaptor.forClass(
- View.OnClickListener.class);
- verify(mMockImageView).setOnClickListener(captor.capture());
+ public void performSingleTap_fullscreenMode_removeViewAndChangeSettingsValue() {
mMagnificationModeSwitch.showButton(ACCESSIBILITY_MAGNIFICATION_MODE_FULLSCREEN);
+ resetMockImageViewAndAnimator();
- captor.getValue().onClick(mMockImageView);
+ // Perform a single-tap
+ final View.OnTouchListener listener = mTouchListenerCaptor.getValue();
+ listener.onTouch(mSpyImageView, MotionEvent.obtain(
+ 0, 0, ACTION_DOWN, 100, 100, 0));
+ verify(mViewPropertyAnimator).cancel();
- // First invocation is in showButton.
- verify(mViewPropertyAnimator, times(2)).cancel();
- verify(mMockImageView).setImageResource(
+ resetMockImageViewAndAnimator();
+ listener.onTouch(mSpyImageView, MotionEvent.obtain(
+ 0, ViewConfiguration.getTapTimeout(), ACTION_UP, 100, 100, 0));
+ verify(mViewPropertyAnimator).cancel();
+ verify(mSpyImageView).setImageResource(
getIconResId(ACCESSIBILITY_MAGNIFICATION_MODE_WINDOW));
- verify(mWindowManager).removeView(mMockImageView);
+ verify(mWindowManager).removeView(mSpyImageView);
final int actualMode = Settings.Secure.getInt(mContext.getContentResolver(),
Settings.Secure.ACCESSIBILITY_MAGNIFICATION_MODE, 0);
assertEquals(ACCESSIBILITY_MAGNIFICATION_MODE_WINDOW, actualMode);
}
+
+ @Test
+ public void showMagnificationButton_performDragging_updateViewLayout() {
+ mMagnificationModeSwitch.showButton(ACCESSIBILITY_MAGNIFICATION_MODE_FULLSCREEN);
+ resetMockImageViewAndAnimator();
+
+ // Perform dragging
+ final View.OnTouchListener listener = mTouchListenerCaptor.getValue();
+ final int offset = ViewConfiguration.get(mContext).getScaledTouchSlop();
+ final int previousMode = Settings.Secure.getInt(mContext.getContentResolver(),
+ Settings.Secure.ACCESSIBILITY_MAGNIFICATION_MODE, 0);
+ listener.onTouch(mSpyImageView, MotionEvent.obtain(
+ 0, 0, ACTION_DOWN, 100, 100, 0));
+ verify(mSpyImageView).setAlpha(1.0f);
+ verify(mViewPropertyAnimator).cancel();
+
+ listener.onTouch(mSpyImageView, MotionEvent.obtain(
+ 0, ViewConfiguration.getTapTimeout(), ACTION_MOVE, 100 + offset, 100, 0));
+ verify(mWindowManager).updateViewLayout(eq(mSpyImageView),
+ any(WindowManager.LayoutParams.class));
+
+ resetMockImageViewAndAnimator();
+ listener.onTouch(mSpyImageView, MotionEvent.obtain(
+ 0, ViewConfiguration.getTapTimeout() + 10, ACTION_UP, 100 + offset, 100, 0));
+ verify(mSpyImageView).setAlpha(1.0f);
+ assertModeUnchanged(previousMode);
+ assertShowButtonAnimation();
+ }
+
+ @Test
+ public void performSingleTapActionCanceled_showButtonAnimation() {
+ mMagnificationModeSwitch.showButton(ACCESSIBILITY_MAGNIFICATION_MODE_FULLSCREEN);
+ resetMockImageViewAndAnimator();
+
+ // Perform single tap
+ final View.OnTouchListener listener = mTouchListenerCaptor.getValue();
+ final int previousMode = Settings.Secure.getInt(mContext.getContentResolver(),
+ Settings.Secure.ACCESSIBILITY_MAGNIFICATION_MODE, 0);
+ listener.onTouch(mSpyImageView, MotionEvent.obtain(
+ 0, 0, ACTION_DOWN, 100, 100, 0));
+
+ resetMockImageViewAndAnimator();
+ listener.onTouch(mSpyImageView, MotionEvent.obtain(
+ 0, ViewConfiguration.getTapTimeout(), ACTION_CANCEL, 100, 100, 0));
+ verify(mSpyImageView).setAlpha(1.0f);
+ assertModeUnchanged(previousMode);
+ assertShowButtonAnimation();
+ }
+
+ @Test
+ public void performDraggingActionCanceled_showButtonAnimation() {
+ mMagnificationModeSwitch.showButton(ACCESSIBILITY_MAGNIFICATION_MODE_FULLSCREEN);
+ resetMockImageViewAndAnimator();
+
+ // Perform dragging
+ final View.OnTouchListener listener = mTouchListenerCaptor.getValue();
+ final int offset = ViewConfiguration.get(mContext).getScaledTouchSlop();
+ final int previousMode = Settings.Secure.getInt(mContext.getContentResolver(),
+ Settings.Secure.ACCESSIBILITY_MAGNIFICATION_MODE, 0);
+ listener.onTouch(mSpyImageView, MotionEvent.obtain(
+ 0, 0, ACTION_DOWN, 100, 100, 0));
+ listener.onTouch(mSpyImageView, MotionEvent.obtain(
+ 0, ViewConfiguration.getTapTimeout(), ACTION_MOVE, 100 + offset, 100, 0));
+
+ resetMockImageViewAndAnimator();
+ listener.onTouch(mSpyImageView, MotionEvent.obtain(
+ 0, ViewConfiguration.getTapTimeout(), ACTION_CANCEL, 100 + offset, 100, 0));
+ verify(mSpyImageView).setAlpha(1.0f);
+ assertModeUnchanged(previousMode);
+ assertShowButtonAnimation();
+ }
+
+ private void assertModeUnchanged(int expectedMode) {
+ final int actualMode = Settings.Secure.getInt(mContext.getContentResolver(),
+ Settings.Secure.ACCESSIBILITY_MAGNIFICATION_MODE, 0);
+ assertEquals(expectedMode, actualMode);
+ }
+
+ private void assertShowButtonAnimation() {
+ verify(mViewPropertyAnimator).cancel();
+ verify(mViewPropertyAnimator).setDuration(anyLong());
+ verify(mViewPropertyAnimator).setStartDelay(anyLong());
+ verify(mViewPropertyAnimator).alpha(anyFloat());
+ verify(mViewPropertyAnimator).start();
+ }
+
+ private void initMockImageViewAndAnimator() {
+ when(mViewPropertyAnimator.setDuration(anyLong())).thenReturn(mViewPropertyAnimator);
+ when(mViewPropertyAnimator.alpha(anyFloat())).thenReturn(mViewPropertyAnimator);
+ when(mViewPropertyAnimator.setStartDelay(anyLong())).thenReturn(mViewPropertyAnimator);
+ when(mViewPropertyAnimator.withEndAction(any(Runnable.class))).thenReturn(
+ mViewPropertyAnimator);
+
+ when(mSpyImageView.animate()).thenReturn(mViewPropertyAnimator);
+ }
+
+ private void resetMockImageViewAndAnimator() {
+ Mockito.reset(mViewPropertyAnimator);
+ Mockito.reset(mSpyImageView);
+ initMockImageViewAndAnimator();
+ }
}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/accessibility/WindowMagnificationAnimationControllerTest.java b/packages/SystemUI/tests/src/com/android/systemui/accessibility/WindowMagnificationAnimationControllerTest.java
index a6dfbbd93178..d74c62b90fda 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/accessibility/WindowMagnificationAnimationControllerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/accessibility/WindowMagnificationAnimationControllerTest.java
@@ -24,6 +24,7 @@ import static org.mockito.Mockito.never;
import static org.mockito.Mockito.verify;
import android.animation.ValueAnimator;
+import android.annotation.Nullable;
import android.app.Instrumentation;
import android.content.Context;
import android.os.Handler;
@@ -73,7 +74,10 @@ public class WindowMagnificationAnimationControllerTest extends SysuiTestCase {
SfVsyncFrameCallbackProvider mSfVsyncFrameProvider;
@Mock
WindowMagnifierCallback mWindowMagnifierCallback;
-
+ @Mock
+ Runnable mAnimationEndCallback;
+ @Mock
+ Runnable mAnimationEndCallback2;
private SpyWindowMagnificationController mController;
private WindowMagnificationController mSpyController;
private WindowMagnificationAnimationController mWindowMagnificationAnimationController;
@@ -101,8 +105,8 @@ public class WindowMagnificationAnimationControllerTest extends SysuiTestCase {
}
@Test
- public void enableWindowMagnification_disabled_expectedStartAndEndValues() {
- enableWindowMagnificationAndWaitAnimating(mWaitingAnimationPeriod);
+ public void enableWindowMagnification_disabled_expectedValuesAndInvokeCallback() {
+ enableWindowMagnificationAndWaitAnimating(mWaitingAnimationPeriod, mAnimationEndCallback);
verify(mSpyController, atLeast(2)).enableWindowMagnification(
mScaleCaptor.capture(),
@@ -111,11 +115,28 @@ public class WindowMagnificationAnimationControllerTest extends SysuiTestCase {
verifyStartValue(mCenterXCaptor, DEFAULT_CENTER_X);
verifyStartValue(mCenterYCaptor, DEFAULT_CENTER_Y);
verifyFinalSpec(DEFAULT_SCALE, DEFAULT_CENTER_X, DEFAULT_CENTER_Y);
+ verify(mAnimationEndCallback).run();
}
+
@Test
- public void enableWindowMagnification_enabling_expectedStartAndEndValues() {
- enableWindowMagnificationAndWaitAnimating(mWaitIntermediateAnimationPeriod);
+ public void enableWindowMagnificationWithScaleOne_disabled_NoAnimationAndInvokeCallback() {
+ mInstrumentation.runOnMainSync(
+ () -> {
+ mWindowMagnificationAnimationController.enableWindowMagnification(1,
+ DEFAULT_CENTER_X, DEFAULT_CENTER_Y, mAnimationEndCallback);
+ });
+ SystemClock.sleep(mWaitingAnimationPeriod);
+
+ verify(mSpyController).enableWindowMagnification(1, DEFAULT_CENTER_X,
+ DEFAULT_CENTER_Y);
+ verify(mAnimationEndCallback).run();
+ }
+
+ @Test
+ public void enableWindowMagnification_enabling_expectedValuesAndInvokeCallback() {
+ enableWindowMagnificationAndWaitAnimating(mWaitIntermediateAnimationPeriod,
+ mAnimationEndCallback);
final float targetScale = DEFAULT_SCALE + 1.0f;
final float targetCenterX = DEFAULT_CENTER_X + 100;
final float targetCenterY = DEFAULT_CENTER_Y + 100;
@@ -123,7 +144,7 @@ public class WindowMagnificationAnimationControllerTest extends SysuiTestCase {
mInstrumentation.runOnMainSync(() -> {
Mockito.reset(mSpyController);
mWindowMagnificationAnimationController.enableWindowMagnification(targetScale,
- targetCenterX, targetCenterY);
+ targetCenterX, targetCenterY, mAnimationEndCallback2);
mCurrentScale.set(mController.getScale());
mCurrentCenterX.set(mController.getCenterX());
mCurrentCenterY.set(mController.getCenterY());
@@ -137,12 +158,33 @@ public class WindowMagnificationAnimationControllerTest extends SysuiTestCase {
verifyStartValue(mCenterXCaptor, mCurrentCenterX.get());
verifyStartValue(mCenterYCaptor, mCurrentCenterY.get());
verifyFinalSpec(targetScale, targetCenterX, targetCenterY);
+ verify(mAnimationEndCallback, never()).run();
+ verify(mAnimationEndCallback2).run();
}
@Test
- public void enableWindowMagnification_disabling_expectedStartAndEndValues() {
- enableWindowMagnificationAndWaitAnimating(mWaitingAnimationPeriod);
- deleteWindowMagnificationAndWaitAnimating(mWaitIntermediateAnimationPeriod);
+ public void enableWindowMagnificationWithSameSpec_enabling_NoAnimationAndInvokeCallback() {
+ enableWindowMagnificationAndWaitAnimating(mWaitIntermediateAnimationPeriod,
+ mAnimationEndCallback);
+
+ mInstrumentation.runOnMainSync(() -> {
+ Mockito.reset(mSpyController);
+ mWindowMagnificationAnimationController.enableWindowMagnification(Float.NaN,
+ Float.NaN, Float.NaN, mAnimationEndCallback2);
+ });
+ SystemClock.sleep(mWaitingAnimationPeriod);
+
+ verify(mSpyController, never()).enableWindowMagnification(anyFloat(), anyFloat(),
+ anyFloat());
+ verify(mAnimationEndCallback, never()).run();
+ verify(mAnimationEndCallback2).run();
+ }
+
+ @Test
+ public void enableWindowMagnification_disabling_expectedValuesAndInvokeCallback() {
+ enableWindowMagnificationAndWaitAnimating(mWaitingAnimationPeriod, null);
+ deleteWindowMagnificationAndWaitAnimating(mWaitIntermediateAnimationPeriod,
+ mAnimationEndCallback);
final float targetScale = DEFAULT_SCALE + 1.0f;
final float targetCenterX = DEFAULT_CENTER_X + 100;
final float targetCenterY = DEFAULT_CENTER_Y + 100;
@@ -151,11 +193,13 @@ public class WindowMagnificationAnimationControllerTest extends SysuiTestCase {
() -> {
Mockito.reset(mSpyController);
mWindowMagnificationAnimationController.enableWindowMagnification(targetScale,
- targetCenterX, targetCenterY);
+ targetCenterX, targetCenterY, mAnimationEndCallback2);
mCurrentScale.set(mController.getScale());
mCurrentCenterX.set(mController.getCenterX());
mCurrentCenterY.set(mController.getCenterY());
});
+ // Current spec shouldn't match given spec.
+ verify(mAnimationEndCallback2, never()).run();
SystemClock.sleep(mWaitingAnimationPeriod);
verify(mSpyController, atLeast(2)).enableWindowMagnification(
@@ -169,21 +213,73 @@ public class WindowMagnificationAnimationControllerTest extends SysuiTestCase {
assertTrue(mCenterYCaptor.getAllValues().get(0) > mCurrentCenterY.get());
assertEquals(targetCenterY, mCenterYCaptor.getValue(), 0f);
verifyFinalSpec(targetScale, targetCenterX, targetCenterY);
+ verify(mAnimationEndCallback, never()).run();
+ verify(mAnimationEndCallback2).run();
+ }
+
+ @Test
+ public void enableWindowMagnificationWithSameSpec_disabling_NoAnimationAndInvokeCallback() {
+ enableWindowMagnificationAndWaitAnimating(mWaitingAnimationPeriod, null);
+ deleteWindowMagnificationAndWaitAnimating(mWaitIntermediateAnimationPeriod,
+ mAnimationEndCallback);
+
+ mInstrumentation.runOnMainSync(() -> {
+ Mockito.reset(mSpyController);
+ mWindowMagnificationAnimationController.enableWindowMagnification(Float.NaN,
+ Float.NaN, Float.NaN, mAnimationEndCallback2);
+ });
+ SystemClock.sleep(mWaitingAnimationPeriod);
+
+ verify(mSpyController, never()).enableWindowMagnification(anyFloat(), anyFloat(),
+ anyFloat());
+ verify(mSpyController, never()).deleteWindowMagnification();
+ verify(mAnimationEndCallback, never()).run();
+ verify(mAnimationEndCallback2).run();
+ }
+
+ @Test
+ public void enableWindowMagnification_enabled_expectedValuesAndInvokeCallback() {
+ enableWindowMagnificationAndWaitAnimating(mWaitIntermediateAnimationPeriod,
+ mAnimationEndCallback);
+ final float targetScale = DEFAULT_SCALE + 1.0f;
+ final float targetCenterX = DEFAULT_CENTER_X + 100;
+ final float targetCenterY = DEFAULT_CENTER_Y + 100;
+
+ mInstrumentation.runOnMainSync(() -> {
+ Mockito.reset(mSpyController);
+ mWindowMagnificationAnimationController.enableWindowMagnification(targetScale,
+ targetCenterX, targetCenterY, mAnimationEndCallback2);
+ mCurrentScale.set(mController.getScale());
+ mCurrentCenterX.set(mController.getCenterX());
+ mCurrentCenterY.set(mController.getCenterY());
+ });
+
+ SystemClock.sleep(mWaitingAnimationPeriod);
+
+ verify(mSpyController, atLeast(2)).enableWindowMagnification(mScaleCaptor.capture(),
+ mCenterXCaptor.capture(), mCenterYCaptor.capture());
+ verifyStartValue(mScaleCaptor, mCurrentScale.get());
+ verifyStartValue(mCenterXCaptor, mCurrentCenterX.get());
+ verifyStartValue(mCenterYCaptor, mCurrentCenterY.get());
+ verifyFinalSpec(targetScale, targetCenterX, targetCenterY);
+ verify(mAnimationEndCallback, never()).run();
+ verify(mAnimationEndCallback2).run();
}
@Test
- public void enableWindowMagnificationWithSameScale_doNothing() {
- enableWindowMagnificationAndWaitAnimating(mWaitingAnimationPeriod);
+ public void enableWindowMagnificationWithSameScale_enabled_doNothingButInvokeCallback() {
+ enableWindowMagnificationAndWaitAnimating(mWaitingAnimationPeriod, null);
- enableWindowMagnificationAndWaitAnimating(mWaitingAnimationPeriod);
+ enableWindowMagnificationAndWaitAnimating(mWaitingAnimationPeriod, mAnimationEndCallback);
verify(mSpyController, never()).enableWindowMagnification(anyFloat(), anyFloat(),
anyFloat());
+ verify(mAnimationEndCallback).run();
}
@Test
public void setScale_enabled_expectedScale() {
- enableWindowMagnificationAndWaitAnimating(mWaitingAnimationPeriod);
+ enableWindowMagnificationAndWaitAnimating(mWaitingAnimationPeriod, null);
mInstrumentation.runOnMainSync(
() -> mWindowMagnificationAnimationController.setScale(DEFAULT_SCALE + 1));
@@ -193,10 +289,10 @@ public class WindowMagnificationAnimationControllerTest extends SysuiTestCase {
}
@Test
- public void deleteWindowMagnification_enabled_expectedStartAndEndValues() {
- enableWindowMagnificationAndWaitAnimating(mWaitingAnimationPeriod);
+ public void deleteWindowMagnification_enabled_expectedValuesAndInvokeCallback() {
+ enableWindowMagnificationAndWaitAnimating(mWaitingAnimationPeriod, null);
- deleteWindowMagnificationAndWaitAnimating(mWaitingAnimationPeriod);
+ deleteWindowMagnificationAndWaitAnimating(mWaitingAnimationPeriod, mAnimationEndCallback);
verify(mSpyController, atLeast(2)).enableWindowMagnification(mScaleCaptor.capture(),
mCenterXCaptor.capture(), mCenterYCaptor.capture());
@@ -205,24 +301,27 @@ public class WindowMagnificationAnimationControllerTest extends SysuiTestCase {
verifyStartValue(mCenterXCaptor, Float.NaN);
verifyStartValue(mCenterYCaptor, Float.NaN);
verifyFinalSpec(Float.NaN, Float.NaN, Float.NaN);
+ verify(mAnimationEndCallback).run();
}
@Test
- public void deleteWindowMagnification_disabled_doNothing() {
- deleteWindowMagnificationAndWaitAnimating(mWaitingAnimationPeriod);
+ public void deleteWindowMagnification_disabled_doNothingAndInvokeCallback() {
+ deleteWindowMagnificationAndWaitAnimating(mWaitingAnimationPeriod, mAnimationEndCallback);
Mockito.verifyNoMoreInteractions(mSpyController);
+ verify(mAnimationEndCallback).run();
}
@Test
- public void deleteWindowMagnification_enabling_checkStartAndEndValues() {
- enableWindowMagnificationAndWaitAnimating(mWaitIntermediateAnimationPeriod);
+ public void deleteWindowMagnification_enabling_expectedValuesAndInvokeCallback() {
+ enableWindowMagnificationAndWaitAnimating(mWaitIntermediateAnimationPeriod,
+ mAnimationEndCallback);
- //It just reverse the animation, so we don't need to wait the whole duration.
mInstrumentation.runOnMainSync(
() -> {
Mockito.reset(mSpyController);
- mWindowMagnificationAnimationController.deleteWindowMagnification();
+ mWindowMagnificationAnimationController.deleteWindowMagnification(
+ mAnimationEndCallback2);
mCurrentScale.set(mController.getScale());
mCurrentCenterX.set(mController.getCenterX());
mCurrentCenterY.set(mController.getCenterY());
@@ -240,25 +339,30 @@ public class WindowMagnificationAnimationControllerTest extends SysuiTestCase {
verifyStartValue(mCenterXCaptor, Float.NaN);
verifyStartValue(mCenterYCaptor, Float.NaN);
verifyFinalSpec(Float.NaN, Float.NaN, Float.NaN);
+ verify(mAnimationEndCallback, never()).run();
+ verify(mAnimationEndCallback2).run();
}
@Test
public void deleteWindowMagnification_disabling_checkStartAndValues() {
- enableWindowMagnificationAndWaitAnimating(mWaitingAnimationPeriod);
- deleteWindowMagnificationAndWaitAnimating(mWaitIntermediateAnimationPeriod);
+ enableWindowMagnificationAndWaitAnimating(mWaitingAnimationPeriod, null);
+ deleteWindowMagnificationAndWaitAnimating(mWaitIntermediateAnimationPeriod,
+ mAnimationEndCallback);
- deleteWindowMagnificationAndWaitAnimating(mWaitingAnimationPeriod);
+ deleteWindowMagnificationAndWaitAnimating(mWaitingAnimationPeriod, mAnimationEndCallback2);
verify(mSpyController, atLeast(2)).enableWindowMagnification(mScaleCaptor.capture(),
mCenterXCaptor.capture(), mCenterYCaptor.capture());
verify(mSpyController).deleteWindowMagnification();
assertEquals(1.0f, mScaleCaptor.getValue(), 0f);
verifyFinalSpec(Float.NaN, Float.NaN, Float.NaN);
+ verify(mAnimationEndCallback, never()).run();
+ verify(mAnimationEndCallback2).run();
}
@Test
public void moveWindowMagnifier_enabled() {
- enableWindowMagnificationAndWaitAnimating(mWaitingAnimationPeriod);
+ enableWindowMagnificationAndWaitAnimating(mWaitingAnimationPeriod, null);
mInstrumentation.runOnMainSync(
() -> mWindowMagnificationAnimationController.moveWindowMagnifier(100f, 200f));
@@ -273,6 +377,7 @@ public class WindowMagnificationAnimationControllerTest extends SysuiTestCase {
verify(mSpyController).onConfigurationChanged(100);
}
+
private void verifyFinalSpec(float expectedScale, float expectedCenterX,
float expectedCenterY) {
assertEquals(expectedScale, mController.getScale(), 0f);
@@ -280,21 +385,23 @@ public class WindowMagnificationAnimationControllerTest extends SysuiTestCase {
assertEquals(expectedCenterY, mController.getCenterY(), 0f);
}
- private void enableWindowMagnificationAndWaitAnimating(long duration) {
+ private void enableWindowMagnificationAndWaitAnimating(long duration,
+ @Nullable Runnable endCallback) {
mInstrumentation.runOnMainSync(
() -> {
Mockito.reset(mSpyController);
mWindowMagnificationAnimationController.enableWindowMagnification(DEFAULT_SCALE,
- DEFAULT_CENTER_X, DEFAULT_CENTER_Y);
+ DEFAULT_CENTER_X, DEFAULT_CENTER_Y, endCallback);
});
SystemClock.sleep(duration);
}
- private void deleteWindowMagnificationAndWaitAnimating(long duration) {
+ private void deleteWindowMagnificationAndWaitAnimating(long duration,
+ @Nullable Runnable endCallback) {
mInstrumentation.runOnMainSync(
() -> {
resetMockObjects();
- mWindowMagnificationAnimationController.deleteWindowMagnification();
+ mWindowMagnificationAnimationController.deleteWindowMagnification(endCallback);
});
SystemClock.sleep(duration);
}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/bubbles/BubbleControllerTest.java b/packages/SystemUI/tests/src/com/android/systemui/bubbles/BubbleControllerTest.java
index a7808ad54d63..f65c2c91c50a 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/bubbles/BubbleControllerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/bubbles/BubbleControllerTest.java
@@ -77,13 +77,13 @@ import com.android.systemui.statusbar.notification.NotificationEntryManager;
import com.android.systemui.statusbar.notification.NotificationFilter;
import com.android.systemui.statusbar.notification.collection.NotifPipeline;
import com.android.systemui.statusbar.notification.collection.NotificationEntry;
+import com.android.systemui.statusbar.notification.collection.legacy.NotificationGroupManagerLegacy;
import com.android.systemui.statusbar.notification.row.ExpandableNotificationRow;
import com.android.systemui.statusbar.notification.row.NotificationTestHelper;
import com.android.systemui.statusbar.notification.row.dagger.NotificationShelfComponent;
import com.android.systemui.statusbar.phone.DozeParameters;
import com.android.systemui.statusbar.phone.KeyguardBypassController;
import com.android.systemui.statusbar.phone.LockscreenLockIconController;
-import com.android.systemui.statusbar.phone.NotificationGroupManager;
import com.android.systemui.statusbar.phone.NotificationShadeWindowControllerImpl;
import com.android.systemui.statusbar.phone.NotificationShadeWindowView;
import com.android.systemui.statusbar.phone.ShadeController;
@@ -118,7 +118,7 @@ public class BubbleControllerTest extends SysuiTestCase {
@Mock
private NotificationEntryManager mNotificationEntryManager;
@Mock
- private NotificationGroupManager mNotificationGroupManager;
+ private NotificationGroupManagerLegacy mNotificationGroupManager;
@Mock
private WindowManager mWindowManager;
@Mock
diff --git a/packages/SystemUI/tests/src/com/android/systemui/bubbles/NewNotifPipelineBubbleControllerTest.java b/packages/SystemUI/tests/src/com/android/systemui/bubbles/NewNotifPipelineBubbleControllerTest.java
index 4936360756fd..dd191e9cd328 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/bubbles/NewNotifPipelineBubbleControllerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/bubbles/NewNotifPipelineBubbleControllerTest.java
@@ -75,6 +75,7 @@ import com.android.systemui.statusbar.notification.NotificationEntryManager;
import com.android.systemui.statusbar.notification.NotificationFilter;
import com.android.systemui.statusbar.notification.collection.NotifPipeline;
import com.android.systemui.statusbar.notification.collection.NotificationEntry;
+import com.android.systemui.statusbar.notification.collection.legacy.NotificationGroupManagerLegacy;
import com.android.systemui.statusbar.notification.collection.notifcollection.NotifCollectionListener;
import com.android.systemui.statusbar.notification.row.ExpandableNotificationRow;
import com.android.systemui.statusbar.notification.row.NotificationTestHelper;
@@ -82,7 +83,6 @@ import com.android.systemui.statusbar.notification.row.dagger.NotificationShelfC
import com.android.systemui.statusbar.phone.DozeParameters;
import com.android.systemui.statusbar.phone.KeyguardBypassController;
import com.android.systemui.statusbar.phone.LockscreenLockIconController;
-import com.android.systemui.statusbar.phone.NotificationGroupManager;
import com.android.systemui.statusbar.phone.NotificationShadeWindowControllerImpl;
import com.android.systemui.statusbar.phone.NotificationShadeWindowView;
import com.android.systemui.statusbar.phone.ShadeController;
@@ -116,7 +116,7 @@ public class NewNotifPipelineBubbleControllerTest extends SysuiTestCase {
@Mock
private NotificationEntryManager mNotificationEntryManager;
@Mock
- private NotificationGroupManager mNotificationGroupManager;
+ private NotificationGroupManagerLegacy mNotificationGroupManager;
@Mock
private BubbleController.NotifCallback mNotifCallback;
@Mock
diff --git a/packages/SystemUI/tests/src/com/android/systemui/bubbles/TestableBubbleController.java b/packages/SystemUI/tests/src/com/android/systemui/bubbles/TestableBubbleController.java
index 51ca2a4e5966..58b27f24a1d4 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/bubbles/TestableBubbleController.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/bubbles/TestableBubbleController.java
@@ -30,8 +30,8 @@ import com.android.systemui.statusbar.NotificationLockscreenUserManager;
import com.android.systemui.statusbar.NotificationShadeWindowController;
import com.android.systemui.statusbar.notification.NotificationEntryManager;
import com.android.systemui.statusbar.notification.collection.NotifPipeline;
+import com.android.systemui.statusbar.notification.collection.legacy.NotificationGroupManagerLegacy;
import com.android.systemui.statusbar.notification.interruption.NotificationInterruptStateProvider;
-import com.android.systemui.statusbar.phone.NotificationGroupManager;
import com.android.systemui.statusbar.phone.ShadeController;
import com.android.systemui.statusbar.policy.ConfigurationController;
import com.android.systemui.statusbar.policy.ZenModeController;
@@ -52,7 +52,7 @@ public class TestableBubbleController extends BubbleController {
NotificationInterruptStateProvider interruptionStateProvider,
ZenModeController zenModeController,
NotificationLockscreenUserManager lockscreenUserManager,
- NotificationGroupManager groupManager,
+ NotificationGroupManagerLegacy groupManager,
NotificationEntryManager entryManager,
NotifPipeline notifPipeline,
FeatureFlags featureFlags,
diff --git a/packages/SystemUI/tests/src/com/android/systemui/globalactions/GlobalActionsDialogTest.java b/packages/SystemUI/tests/src/com/android/systemui/globalactions/GlobalActionsDialogTest.java
index c8e0f490a783..909acead9553 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/globalactions/GlobalActionsDialogTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/globalactions/GlobalActionsDialogTest.java
@@ -69,7 +69,7 @@ import com.android.systemui.model.SysUiState;
import com.android.systemui.plugins.ActivityStarter;
import com.android.systemui.plugins.GlobalActions;
import com.android.systemui.plugins.GlobalActionsPanelPlugin;
-import com.android.systemui.settings.CurrentUserContextTracker;
+import com.android.systemui.settings.UserContextProvider;
import com.android.systemui.statusbar.NotificationShadeDepthController;
import com.android.systemui.statusbar.NotificationShadeWindowController;
import com.android.systemui.statusbar.policy.ConfigurationController;
@@ -125,7 +125,7 @@ public class GlobalActionsDialogTest extends SysuiTestCase {
@Mock GlobalActionsPanelPlugin mWalletPlugin;
@Mock GlobalActionsPanelPlugin.PanelViewController mWalletController;
@Mock private Handler mHandler;
- @Mock private CurrentUserContextTracker mCurrentUserContextTracker;
+ @Mock private UserContextProvider mUserContextProvider;
private ControlsComponent mControlsComponent;
private TestableLooper mTestableLooper;
@@ -137,7 +137,7 @@ public class GlobalActionsDialogTest extends SysuiTestCase {
allowTestableLooperAsMainThread();
when(mRingerModeTracker.getRingerMode()).thenReturn(mRingerModeLiveData);
- when(mCurrentUserContextTracker.getCurrentUserContext()).thenReturn(mContext);
+ when(mUserContextProvider.getUserContext()).thenReturn(mContext);
mControlsComponent = new ControlsComponent(
true,
() -> mControlsController,
@@ -176,7 +176,7 @@ public class GlobalActionsDialogTest extends SysuiTestCase {
mSysUiState,
mHandler,
mControlsComponent,
- mCurrentUserContextTracker
+ mUserContextProvider
);
mGlobalActionsDialog.setZeroDialogPressDelayForTesting();
diff --git a/packages/SystemUI/tests/src/com/android/systemui/keyguard/KeyguardViewMediatorTest.java b/packages/SystemUI/tests/src/com/android/systemui/keyguard/KeyguardViewMediatorTest.java
index c874b1fb72ad..f6d6f562e3fa 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/keyguard/KeyguardViewMediatorTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/keyguard/KeyguardViewMediatorTest.java
@@ -37,6 +37,7 @@ import android.testing.TestableLooper.RunWithLooper;
import androidx.test.filters.SmallTest;
import com.android.internal.widget.LockPatternUtils;
+import com.android.keyguard.KeyguardDisplayManager;
import com.android.keyguard.KeyguardUpdateMonitor;
import com.android.systemui.SysuiTestCase;
import com.android.systemui.broadcast.BroadcastDispatcher;
@@ -46,7 +47,6 @@ import com.android.systemui.navigationbar.NavigationModeController;
import com.android.systemui.statusbar.phone.StatusBarKeyguardViewManager;
import com.android.systemui.util.DeviceConfigProxy;
import com.android.systemui.util.DeviceConfigProxyFake;
-import com.android.systemui.util.InjectionInflationController;
import com.android.systemui.util.concurrency.FakeExecutor;
import com.android.systemui.util.time.FakeSystemClock;
@@ -72,7 +72,7 @@ public class KeyguardViewMediatorTest extends SysuiTestCase {
private @Mock PowerManager mPowerManager;
private @Mock TrustManager mTrustManager;
private @Mock NavigationModeController mNavigationModeController;
- private @Mock InjectionInflationController mInjectionInflationController;
+ private @Mock KeyguardDisplayManager mKeyguardDisplayManager;
private DeviceConfigProxy mDeviceConfig = new DeviceConfigProxyFake();
private FakeExecutor mUiBgExecutor = new FakeExecutor(new FakeSystemClock());
@@ -91,7 +91,7 @@ public class KeyguardViewMediatorTest extends SysuiTestCase {
() -> mStatusBarKeyguardViewManager,
mDismissCallbackRegistry, mUpdateMonitor, mDumpManager, mUiBgExecutor,
mPowerManager, mTrustManager, mDeviceConfig, mNavigationModeController,
- mInjectionInflationController);
+ mKeyguardDisplayManager);
mViewMediator.start();
}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/navigationbar/NavigationBarControllerTest.java b/packages/SystemUI/tests/src/com/android/systemui/navigationbar/NavigationBarControllerTest.java
index 4bc9b464334d..ad5f987b59e7 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/navigationbar/NavigationBarControllerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/navigationbar/NavigationBarControllerTest.java
@@ -52,7 +52,6 @@ import com.android.systemui.model.SysUiState;
import com.android.systemui.plugins.statusbar.StatusBarStateController;
import com.android.systemui.recents.OverviewProxyService;
import com.android.systemui.recents.Recents;
-import com.android.systemui.stackdivider.SplitScreenController;
import com.android.systemui.statusbar.CommandQueue;
import com.android.systemui.statusbar.NotificationRemoteInputManager;
import com.android.systemui.statusbar.phone.ShadeController;
@@ -60,6 +59,7 @@ import com.android.systemui.statusbar.phone.StatusBar;
import com.android.systemui.statusbar.policy.AccessibilityManagerWrapper;
import com.android.systemui.statusbar.policy.ConfigurationController;
import com.android.systemui.statusbar.policy.DeviceProvisionedController;
+import com.android.wm.shell.splitscreen.SplitScreen;
import org.junit.After;
import org.junit.Before;
@@ -96,7 +96,7 @@ public class NavigationBarControllerTest extends SysuiTestCase {
mock(SysUiState.class),
mock(BroadcastDispatcher.class),
mock(CommandQueue.class),
- Optional.of(mock(SplitScreenController.class)),
+ Optional.of(mock(SplitScreen.class)),
Optional.of(mock(Recents.class)),
() -> mock(StatusBar.class),
mock(ShadeController.class),
diff --git a/packages/SystemUI/tests/src/com/android/systemui/navigationbar/NavigationBarTest.java b/packages/SystemUI/tests/src/com/android/systemui/navigationbar/NavigationBarTest.java
index 63821c400e23..f308e9e479e1 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/navigationbar/NavigationBarTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/navigationbar/NavigationBarTest.java
@@ -68,7 +68,6 @@ import com.android.systemui.model.SysUiState;
import com.android.systemui.plugins.statusbar.StatusBarStateController;
import com.android.systemui.recents.OverviewProxyService;
import com.android.systemui.recents.Recents;
-import com.android.systemui.stackdivider.SplitScreenController;
import com.android.systemui.statusbar.CommandQueue;
import com.android.systemui.statusbar.NotificationRemoteInputManager;
import com.android.systemui.statusbar.phone.ShadeController;
@@ -77,6 +76,7 @@ import com.android.systemui.statusbar.policy.AccessibilityManagerWrapper;
import com.android.systemui.statusbar.policy.DeviceProvisionedController;
import com.android.systemui.statusbar.policy.KeyguardStateController;
import com.android.systemui.utils.leaks.LeakCheckedTest;
+import com.android.wm.shell.splitscreen.SplitScreen;
import org.junit.Before;
import org.junit.Rule;
@@ -223,7 +223,7 @@ public class NavigationBarTest extends SysuiTestCase {
mMockSysUiState,
mBroadcastDispatcher,
mCommandQueue,
- Optional.of(mock(SplitScreenController.class)),
+ Optional.of(mock(SplitScreen.class)),
Optional.of(mock(Recents.class)),
() -> mock(StatusBar.class),
mock(ShadeController.class),
diff --git a/packages/SystemUI/tests/src/com/android/systemui/onehanded/OneHandedControllerTest.java b/packages/SystemUI/tests/src/com/android/systemui/onehanded/OneHandedControllerTest.java
index 02d587d90655..e42cf529373e 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/onehanded/OneHandedControllerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/onehanded/OneHandedControllerTest.java
@@ -22,21 +22,20 @@ import static org.mockito.ArgumentMatchers.any;
import static org.mockito.ArgumentMatchers.anyInt;
import static org.mockito.Mockito.atLeastOnce;
import static org.mockito.Mockito.never;
-import static org.mockito.Mockito.times;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
+import android.provider.Settings;
import android.testing.AndroidTestingRunner;
import android.testing.TestableLooper;
import android.view.Display;
import androidx.test.filters.SmallTest;
-import com.android.systemui.model.SysUiState;
-import com.android.systemui.statusbar.CommandQueue;
import com.android.wm.shell.common.DisplayController;
import org.junit.Before;
+import org.junit.Ignore;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.Mock;
@@ -52,8 +51,6 @@ public class OneHandedControllerTest extends OneHandedTestCase {
OneHandedTimeoutHandler mTimeoutHandler;
@Mock
- CommandQueue mCommandQueue;
- @Mock
DisplayController mMockDisplayController;
@Mock
OneHandedDisplayAreaOrganizer mMockDisplayAreaOrganizer;
@@ -64,21 +61,20 @@ public class OneHandedControllerTest extends OneHandedTestCase {
@Mock
OneHandedGestureHandler mMockGestureHandler;
@Mock
- SysUiState mMockSysUiState;
+ OneHandedTimeoutHandler mMockTimeoutHandler;
@Before
public void setUp() throws Exception {
MockitoAnnotations.initMocks(this);
mDisplay = mContext.getDisplay();
- mOneHandedController = new OneHandedController(
- getContext(),
- mCommandQueue,
+ OneHandedController oneHandedController = new OneHandedController(
+ mContext,
mMockDisplayController,
mMockDisplayAreaOrganizer,
mMockTouchHandler,
mMockTutorialHandler,
- mMockGestureHandler,
- mMockSysUiState);
+ mMockGestureHandler);
+ mOneHandedController = Mockito.spy(oneHandedController);
mTimeoutHandler = Mockito.spy(OneHandedTimeoutHandler.get());
when(mMockDisplayController.getDisplay(anyInt())).thenReturn(mDisplay);
@@ -97,7 +93,7 @@ public class OneHandedControllerTest extends OneHandedTestCase {
@Test
public void testRegisterOrganizer() {
- verify(mMockDisplayAreaOrganizer).registerOrganizer(anyInt());
+ verify(mMockDisplayAreaOrganizer, atLeastOnce()).registerOrganizer(anyInt());
}
@Test
@@ -132,7 +128,7 @@ public class OneHandedControllerTest extends OneHandedTestCase {
final boolean enabled = true;
mOneHandedController.setOneHandedEnabled(enabled);
- verify(mMockTouchHandler, times(2)).onOneHandedEnabled(enabled);
+ verify(mMockTouchHandler, atLeastOnce()).onOneHandedEnabled(enabled);
}
@Test
@@ -140,6 +136,44 @@ public class OneHandedControllerTest extends OneHandedTestCase {
final boolean enabled = true;
mOneHandedController.setSwipeToNotificationEnabled(enabled);
- verify(mMockTouchHandler, times(2)).onOneHandedEnabled(enabled);
+ verify(mMockTouchHandler, atLeastOnce()).onOneHandedEnabled(enabled);
+ }
+
+ @Ignore("b/161980408, fix it after migration finished")
+ @Test
+ public void tesSettingsObserver_updateTapAppToExit() {
+ Settings.Secure.putInt(mContext.getContentResolver(),
+ Settings.Secure.TAPS_APP_TO_EXIT, 1);
+
+ verify(mOneHandedController).setTaskChangeToExit(true);
+ }
+
+ @Ignore("b/161980408, fix it after migration finished")
+ @Test
+ public void tesSettingsObserver_updateEnabled() {
+ Settings.Secure.putInt(mContext.getContentResolver(),
+ Settings.Secure.ONE_HANDED_MODE_ENABLED, 1);
+
+ verify(mOneHandedController).setOneHandedEnabled(true);
+ }
+
+ @Ignore("b/161980408, fix it after migration finished")
+ @Test
+ public void tesSettingsObserver_updateTimeout() {
+ Settings.Secure.putInt(mContext.getContentResolver(),
+ Settings.Secure.ONE_HANDED_MODE_TIMEOUT,
+ OneHandedSettingsUtil.ONE_HANDED_TIMEOUT_MEDIUM_IN_SECONDS);
+
+ verify(mMockTimeoutHandler).setTimeout(
+ OneHandedSettingsUtil.ONE_HANDED_TIMEOUT_MEDIUM_IN_SECONDS);
+ }
+
+ @Ignore("b/161980408, fix it after migration finished")
+ @Test
+ public void tesSettingsObserver_updateSwipeToNotification() {
+ Settings.Secure.putInt(mContext.getContentResolver(),
+ Settings.Secure.SWIPE_BOTTOM_TO_NOTIFICATION_ENABLED, 1);
+
+ verify(mOneHandedController).setSwipeToNotificationEnabled(true);
}
}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/onehanded/OneHandedGestureHandlerTest.java b/packages/SystemUI/tests/src/com/android/systemui/onehanded/OneHandedGestureHandlerTest.java
index 756382a6c630..41af53b1c522 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/onehanded/OneHandedGestureHandlerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/onehanded/OneHandedGestureHandlerTest.java
@@ -16,12 +16,10 @@
package com.android.systemui.onehanded;
-import static android.view.WindowManagerPolicyConstants.NAV_BAR_MODE_2BUTTON;
-
import static com.google.common.truth.Truth.assertThat;
-import static org.mockito.ArgumentMatchers.any;
-import static org.mockito.Mockito.times;
+import static org.mockito.Mockito.atLeast;
+import static org.mockito.Mockito.atLeastOnce;
import static org.mockito.Mockito.verify;
import android.testing.AndroidTestingRunner;
@@ -29,9 +27,6 @@ import android.testing.TestableLooper;
import androidx.test.filters.SmallTest;
-import com.android.systemui.model.SysUiState;
-import com.android.systemui.navigationbar.NavigationModeController;
-import com.android.systemui.statusbar.CommandQueue;
import com.android.wm.shell.common.DisplayController;
import org.junit.Before;
@@ -50,52 +45,55 @@ public class OneHandedGestureHandlerTest extends OneHandedTestCase {
OneHandedGestureHandler mGestureHandler;
OneHandedController mOneHandedController;
@Mock
- CommandQueue mCommandQueue;
- @Mock
DisplayController mMockDisplayController;
@Mock
OneHandedDisplayAreaOrganizer mMockDisplayAreaOrganizer;
- @Mock
- SysUiState mMockSysUiState;
- @Mock
- NavigationModeController mMockNavigationModeController;
@Before
public void setUp() throws Exception {
MockitoAnnotations.initMocks(this);
mTouchHandler = new OneHandedTouchHandler();
mTutorialHandler = new OneHandedTutorialHandler(mContext);
- mGestureHandler = Mockito.spy(new OneHandedGestureHandler(
- mContext, mMockDisplayController, mMockNavigationModeController));
+ mGestureHandler = Mockito.spy(
+ new OneHandedGestureHandler(mContext, mMockDisplayController));
mOneHandedController = new OneHandedController(
getContext(),
- mCommandQueue,
mMockDisplayController,
mMockDisplayAreaOrganizer,
mTouchHandler,
mTutorialHandler,
- mGestureHandler,
- mMockSysUiState);
+ mGestureHandler);
+ mOneHandedController.setThreeButtonModeEnabled(true);
}
@Test
public void testOneHandedManager_registerForDisplayAreaOrganizer() {
- verify(mMockDisplayAreaOrganizer).registerTransitionCallback(mGestureHandler);
+ verify(mMockDisplayAreaOrganizer, atLeastOnce())
+ .registerTransitionCallback(mGestureHandler);
}
@Test
public void testOneHandedManager_setGestureEventListener() {
- verify(mGestureHandler).setGestureEventListener(any());
-
- assertThat(mGestureHandler.mGestureEventCallback).isNotNull();
+ OneHandedGestureHandler.OneHandedGestureEventCallback callback =
+ new OneHandedGestureHandler.OneHandedGestureEventCallback() {
+ @Override
+ public void onStart() {}
+
+ @Override
+ public void onStop() {}
+ };
+ mOneHandedController.registerGestureCallback(callback);
+
+ verify(mGestureHandler).setGestureEventListener(callback);
+ assertThat(mGestureHandler.mGestureEventCallback).isEqualTo(callback);
}
@Test
public void testReceiveNewConfig_whenSetOneHandedEnabled() {
// 1st called at init
- verify(mGestureHandler).onOneHandedEnabled(true);
+ verify(mGestureHandler, atLeastOnce()).onOneHandedEnabled(true);
mOneHandedController.setOneHandedEnabled(true);
// 2nd called by setOneHandedEnabled()
- verify(mGestureHandler, times(2)).onOneHandedEnabled(true);
+ verify(mGestureHandler, atLeast(2)).onOneHandedEnabled(true);
}
@Test
@@ -108,14 +106,14 @@ public class OneHandedGestureHandlerTest extends OneHandedTestCase {
}
@Test
- public void testChangeNavBarTo2Button_shouldDisposeInputChannel() {
+ public void testChangeNavBarToNon3Button_shouldDisposeInputChannel() {
// 1st called at init
- verify(mGestureHandler).onOneHandedEnabled(true);
+ verify(mGestureHandler, atLeastOnce()).onOneHandedEnabled(true);
mOneHandedController.setOneHandedEnabled(true);
// 2nd called by setOneHandedEnabled()
- verify(mGestureHandler, times(2)).onOneHandedEnabled(true);
+ verify(mGestureHandler, atLeast(2)).onOneHandedEnabled(true);
- mGestureHandler.onNavigationModeChanged(NAV_BAR_MODE_2BUTTON);
+ mGestureHandler.onThreeButtonModeEnabled(false);
assertThat(mGestureHandler.mInputMonitor).isNull();
assertThat(mGestureHandler.mInputEventReceiver).isNull();
diff --git a/packages/SystemUI/tests/src/com/android/systemui/onehanded/OneHandedTestCase.java b/packages/SystemUI/tests/src/com/android/systemui/onehanded/OneHandedTestCase.java
index 04ebf25e1b49..f111c4896458 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/onehanded/OneHandedTestCase.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/onehanded/OneHandedTestCase.java
@@ -16,8 +16,12 @@
package com.android.systemui.onehanded;
+import static com.android.systemui.onehanded.OneHandedController.SUPPORT_ONE_HANDED_MODE;
import static com.android.systemui.onehanded.OneHandedSettingsUtil.ONE_HANDED_TIMEOUT_MEDIUM_IN_SECONDS;
+import static org.junit.Assume.assumeTrue;
+
+import android.os.SystemProperties;
import android.provider.Settings;
import com.android.systemui.SysuiTestCase;
@@ -54,6 +58,11 @@ public abstract class OneHandedTestCase extends SysuiTestCase {
Settings.Secure.SWIPE_BOTTOM_TO_NOTIFICATION_ENABLED, 1);
}
+ @Before
+ public void assumeOneHandedModeSupported() {
+ assumeTrue(SystemProperties.getBoolean(SUPPORT_ONE_HANDED_MODE, false));
+ }
+
@After
public void restoreSettings() {
Settings.Secure.putInt(getContext().getContentResolver(),
diff --git a/packages/SystemUI/tests/src/com/android/systemui/onehanded/OneHandedTouchHandlerTest.java b/packages/SystemUI/tests/src/com/android/systemui/onehanded/OneHandedTouchHandlerTest.java
index 3c3ace052e47..1e408313a36e 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/onehanded/OneHandedTouchHandlerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/onehanded/OneHandedTouchHandlerTest.java
@@ -19,7 +19,8 @@ package com.android.systemui.onehanded;
import static com.google.common.truth.Truth.assertThat;
import static org.mockito.ArgumentMatchers.any;
-import static org.mockito.Mockito.times;
+import static org.mockito.Mockito.atLeast;
+import static org.mockito.Mockito.atLeastOnce;
import static org.mockito.Mockito.verify;
import android.testing.AndroidTestingRunner;
@@ -27,9 +28,6 @@ import android.testing.TestableLooper;
import androidx.test.filters.SmallTest;
-import com.android.systemui.model.SysUiState;
-import com.android.systemui.navigationbar.NavigationModeController;
-import com.android.systemui.statusbar.CommandQueue;
import com.android.wm.shell.common.DisplayController;
import org.junit.Before;
@@ -48,31 +46,22 @@ public class OneHandedTouchHandlerTest extends OneHandedTestCase {
OneHandedGestureHandler mGestureHandler;
OneHandedController mOneHandedController;
@Mock
- CommandQueue mCommandQueue;
- @Mock
DisplayController mMockDisplayController;
@Mock
- NavigationModeController mMockNavigationModeController;
- @Mock
OneHandedDisplayAreaOrganizer mMockDisplayAreaOrganizer;
- @Mock
- SysUiState mMockSysUiState;
@Before
public void setUp() {
MockitoAnnotations.initMocks(this);
mTouchHandler = Mockito.spy(new OneHandedTouchHandler());
- mGestureHandler = new OneHandedGestureHandler(mContext, mMockDisplayController,
- mMockNavigationModeController);
+ mGestureHandler = new OneHandedGestureHandler(mContext, mMockDisplayController);
mOneHandedController = new OneHandedController(
getContext(),
- mCommandQueue,
mMockDisplayController,
mMockDisplayAreaOrganizer,
mTouchHandler,
mTutorialHandler,
- mGestureHandler,
- mMockSysUiState);
+ mGestureHandler);
}
@Test
@@ -102,10 +91,10 @@ public class OneHandedTouchHandlerTest extends OneHandedTestCase {
@Test
public void testReceiveNewConfig_whenSetOneHandedEnabled() {
- // 1st called at init
- verify(mTouchHandler).onOneHandedEnabled(true);
+ // Called at init
+ verify(mTouchHandler, atLeastOnce()).onOneHandedEnabled(true);
mOneHandedController.setOneHandedEnabled(true);
- // 2nd called by setOneHandedEnabled()
- verify(mTouchHandler, times(2)).onOneHandedEnabled(true);
+ // Called by setOneHandedEnabled()
+ verify(mTouchHandler, atLeast(2)).onOneHandedEnabled(true);
}
}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/onehanded/OneHandedTutorialHandlerTest.java b/packages/SystemUI/tests/src/com/android/systemui/onehanded/OneHandedTutorialHandlerTest.java
index 1bffbf7eb8dd..8ea5524eb7e6 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/onehanded/OneHandedTutorialHandlerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/onehanded/OneHandedTutorialHandlerTest.java
@@ -23,9 +23,6 @@ import android.testing.TestableLooper;
import androidx.test.filters.SmallTest;
-import com.android.systemui.model.SysUiState;
-import com.android.systemui.navigationbar.NavigationModeController;
-import com.android.systemui.statusbar.CommandQueue;
import com.android.wm.shell.common.DisplayController;
import org.junit.Before;
@@ -44,32 +41,23 @@ public class OneHandedTutorialHandlerTest extends OneHandedTestCase {
OneHandedGestureHandler mGestureHandler;
OneHandedController mOneHandedController;
@Mock
- CommandQueue mCommandQueue;
- @Mock
DisplayController mMockDisplayController;
@Mock
- NavigationModeController mMockNavigationModeController;
- @Mock
OneHandedDisplayAreaOrganizer mMockDisplayAreaOrganizer;
- @Mock
- SysUiState mMockSysUiState;
@Before
public void setUp() {
MockitoAnnotations.initMocks(this);
mTouchHandler = new OneHandedTouchHandler();
mTutorialHandler = Mockito.spy(new OneHandedTutorialHandler(mContext));
- mGestureHandler = new OneHandedGestureHandler(mContext, mMockDisplayController,
- mMockNavigationModeController);
+ mGestureHandler = new OneHandedGestureHandler(mContext, mMockDisplayController);
mOneHandedController = new OneHandedController(
getContext(),
- mCommandQueue,
mMockDisplayController,
mMockDisplayAreaOrganizer,
mTouchHandler,
mTutorialHandler,
- mGestureHandler,
- mMockSysUiState);
+ mGestureHandler);
}
@Test
diff --git a/packages/SystemUI/tests/src/com/android/systemui/onehanded/OneHandedUITest.java b/packages/SystemUI/tests/src/com/android/systemui/onehanded/OneHandedUITest.java
deleted file mode 100644
index ae3df5db30bc..000000000000
--- a/packages/SystemUI/tests/src/com/android/systemui/onehanded/OneHandedUITest.java
+++ /dev/null
@@ -1,136 +0,0 @@
-/*
- * Copyright (C) 2020 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.systemui.onehanded;
-
-import static org.junit.Assume.assumeTrue;
-import static org.mockito.Mockito.verify;
-
-import android.os.SystemProperties;
-import android.provider.Settings;
-import android.testing.AndroidTestingRunner;
-import android.testing.TestableLooper;
-
-import androidx.test.filters.SmallTest;
-
-import com.android.keyguard.KeyguardUpdateMonitor;
-import com.android.systemui.keyguard.ScreenLifecycle;
-import com.android.systemui.statusbar.CommandQueue;
-
-import org.junit.Before;
-import org.junit.Ignore;
-import org.junit.Test;
-import org.junit.runner.RunWith;
-import org.mockito.Mock;
-import org.mockito.MockitoAnnotations;
-
-@SmallTest
-@RunWith(AndroidTestingRunner.class)
-@TestableLooper.RunWithLooper
-public class OneHandedUITest extends OneHandedTestCase {
- private static final String SUPPORT_ONE_HANDED_MODE = "ro.support_one_handed_mode";
-
- CommandQueue mCommandQueue;
- KeyguardUpdateMonitor mKeyguardUpdateMonitor;
- OneHandedUI mOneHandedUI;
- ScreenLifecycle mScreenLifecycle;
- @Mock
- OneHandedController mOneHandedController;
- @Mock
- OneHandedTimeoutHandler mMockTimeoutHandler;
-
- @Before
- public void setUp() throws Exception {
- MockitoAnnotations.initMocks(this);
- mCommandQueue = new CommandQueue(mContext);
- mScreenLifecycle = new ScreenLifecycle();
- mOneHandedUI = new OneHandedUI(mContext,
- mCommandQueue,
- mOneHandedController,
- mScreenLifecycle);
- mOneHandedUI.start();
- mKeyguardUpdateMonitor = mDependency.injectMockDependency(KeyguardUpdateMonitor.class);
- }
-
- @Before
- public void assumeOneHandedModeSupported() {
- assumeTrue(SystemProperties.getBoolean(SUPPORT_ONE_HANDED_MODE, false));
- }
-
- @Test
- public void testStartOneHanded() {
- mOneHandedUI.startOneHanded();
-
- verify(mOneHandedController).startOneHanded();
- }
-
- @Test
- public void testStopOneHanded() {
- mOneHandedUI.stopOneHanded();
-
- verify(mOneHandedController).stopOneHanded();
- }
-
- @Test
- public void tesSettingsObserver_updateTapAppToExit() {
- Settings.Secure.putInt(mContext.getContentResolver(),
- Settings.Secure.TAPS_APP_TO_EXIT, 1);
-
- verify(mOneHandedController).setTaskChangeToExit(true);
- }
-
- @Test
- public void tesSettingsObserver_updateEnabled() {
- Settings.Secure.putInt(mContext.getContentResolver(),
- Settings.Secure.ONE_HANDED_MODE_ENABLED, 1);
-
- verify(mOneHandedController).setOneHandedEnabled(true);
- }
-
- @Test
- public void tesSettingsObserver_updateTimeout() {
- Settings.Secure.putInt(mContext.getContentResolver(),
- Settings.Secure.ONE_HANDED_MODE_TIMEOUT,
- OneHandedSettingsUtil.ONE_HANDED_TIMEOUT_MEDIUM_IN_SECONDS);
-
- verify(mMockTimeoutHandler).setTimeout(
- OneHandedSettingsUtil.ONE_HANDED_TIMEOUT_MEDIUM_IN_SECONDS);
- }
-
- @Test
- public void tesSettingsObserver_updateSwipeToNotification() {
- Settings.Secure.putInt(mContext.getContentResolver(),
- Settings.Secure.SWIPE_BOTTOM_TO_NOTIFICATION_ENABLED, 1);
-
- verify(mOneHandedController).setSwipeToNotificationEnabled(true);
- }
-
- @Ignore("Clarifying do not receive callback")
- @Test
- public void testKeyguardBouncerShowing_shouldStopOneHanded() {
- mKeyguardUpdateMonitor.sendKeyguardBouncerChanged(true);
-
- verify(mOneHandedController).stopOneHanded();
- }
-
- @Test
- public void testScreenTurningOff_shouldStopOneHanded() {
- mScreenLifecycle.dispatchScreenTurningOff();
-
- verify(mOneHandedController).stopOneHanded();
- }
-
-}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/screenrecord/RecordingServiceTest.java b/packages/SystemUI/tests/src/com/android/systemui/screenrecord/RecordingServiceTest.java
index 4c9e141c45cc..3e37fde84544 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/screenrecord/RecordingServiceTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/screenrecord/RecordingServiceTest.java
@@ -33,7 +33,7 @@ import androidx.test.filters.SmallTest;
import com.android.internal.logging.UiEventLogger;
import com.android.systemui.SysuiTestCase;
import com.android.systemui.plugins.ActivityStarter;
-import com.android.systemui.settings.CurrentUserContextTracker;
+import com.android.systemui.settings.UserContextProvider;
import com.android.systemui.statusbar.phone.KeyguardDismissUtil;
import org.junit.Before;
@@ -62,7 +62,7 @@ public class RecordingServiceTest extends SysuiTestCase {
@Mock
private Executor mExecutor;
@Mock
- private CurrentUserContextTracker mUserContextTracker;
+ private UserContextProvider mUserContextTracker;
private KeyguardDismissUtil mKeyguardDismissUtil = new KeyguardDismissUtil() {
public void executeWhenUnlocked(ActivityStarter.OnDismissAction action,
boolean requiresShadeOpen) {
@@ -92,7 +92,7 @@ public class RecordingServiceTest extends SysuiTestCase {
doNothing().when(mRecordingService).startForeground(anyInt(), any());
doReturn(mScreenMediaRecorder).when(mRecordingService).getRecorder();
- doReturn(mContext).when(mUserContextTracker).getCurrentUserContext();
+ doReturn(mContext).when(mUserContextTracker).getUserContext();
}
@Test
diff --git a/packages/SystemUI/tests/src/com/android/systemui/settings/CurrentUserContextTrackerTest.kt b/packages/SystemUI/tests/src/com/android/systemui/settings/CurrentUserContextTrackerTest.kt
deleted file mode 100644
index 628c06a56abd..000000000000
--- a/packages/SystemUI/tests/src/com/android/systemui/settings/CurrentUserContextTrackerTest.kt
+++ /dev/null
@@ -1,92 +0,0 @@
-/*
- * Copyright (C) 2020 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License
- */
-
-package com.android.systemui.settings
-
-import android.content.Context
-import android.content.ContextWrapper
-import android.os.UserHandle
-import android.testing.AndroidTestingRunner
-import android.testing.TestableLooper
-import androidx.test.filters.SmallTest
-import com.android.systemui.SysuiTestCase
-import com.android.systemui.broadcast.BroadcastDispatcher
-import junit.framework.Assert.assertTrue
-import org.junit.Before
-import org.junit.Test
-import org.junit.runner.RunWith
-import org.mockito.Mock
-import org.mockito.Mockito.`when`
-import org.mockito.Mockito.mock
-import org.mockito.MockitoAnnotations
-
-@SmallTest
-@RunWith(AndroidTestingRunner::class)
-@TestableLooper.RunWithLooper
-class CurrentUserContextTrackerTest : SysuiTestCase() {
-
- private lateinit var tracker: CurrentUserContextTracker
- @Mock private lateinit var broadcastDispatcher: BroadcastDispatcher
-
- @Before
- fun setUp() {
- MockitoAnnotations.initMocks(this)
- allowTestableLooperAsMainThread()
-
- // wrap Context so that tests don't throw for missing package errors
- val wrapped = object : ContextWrapper(context) {
- override fun createContextAsUser(user: UserHandle, flags: Int): Context {
- val mockContext = mock(Context::class.java)
- `when`(mockContext.user).thenReturn(user)
- `when`(mockContext.userId).thenReturn(user.identifier)
- return mockContext
- }
- }
-
- tracker = CurrentUserContextTracker(wrapped, broadcastDispatcher)
- tracker.initialize()
- }
-
- @Test
- fun testContextExistsAfterInit_noCrash() {
- tracker.currentUserContext
- }
-
- @Test
- fun testUserContextIsCorrectAfterUserSwitch() {
- // We always start out with system ui test
- assertTrue("Starting userId should be 0", tracker.currentUserContext.userId == 0)
-
- // WHEN user changes
- tracker.handleUserSwitched(1)
-
- // THEN user context should have the correct userId
- assertTrue("User has changed to userId 1, the context should reflect that",
- tracker.currentUserContext.userId == 1)
- }
-
- @Suppress("UNUSED_PARAMETER")
- @Test(expected = IllegalStateException::class)
- fun testContextTrackerThrowsExceptionWhenNotInitialized() {
- // GIVEN an uninitialized CurrentUserContextTracker
- val userTracker = CurrentUserContextTracker(context, broadcastDispatcher)
-
- // WHEN client asks for a context
- val userContext = userTracker.currentUserContext
-
- // THEN an exception is thrown
- }
-} \ No newline at end of file
diff --git a/packages/SystemUI/tests/src/com/android/systemui/settings/UserTrackerImplTest.kt b/packages/SystemUI/tests/src/com/android/systemui/settings/UserTrackerImplTest.kt
new file mode 100644
index 000000000000..f76b50a173c3
--- /dev/null
+++ b/packages/SystemUI/tests/src/com/android/systemui/settings/UserTrackerImplTest.kt
@@ -0,0 +1,292 @@
+/*
+ * 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.settings
+
+import android.content.Context
+import android.content.Intent
+import android.content.IntentFilter
+import android.content.pm.UserInfo
+import android.os.Handler
+import android.os.UserHandle
+import android.os.UserManager
+import android.testing.AndroidTestingRunner
+import androidx.test.filters.SmallTest
+import com.android.systemui.SysuiTestCase
+import com.android.systemui.dump.DumpManager
+import com.android.systemui.util.mockito.capture
+import com.google.common.truth.Truth.assertThat
+import org.junit.Before
+import org.junit.Test
+import org.junit.runner.RunWith
+import org.mockito.ArgumentCaptor
+import org.mockito.ArgumentMatchers.any
+import org.mockito.ArgumentMatchers.anyInt
+import org.mockito.ArgumentMatchers.eq
+import org.mockito.ArgumentMatchers.isNull
+import org.mockito.Mock
+import org.mockito.Mockito.`when`
+import org.mockito.Mockito.verify
+import org.mockito.MockitoAnnotations
+import java.util.concurrent.Executor
+
+@SmallTest
+@RunWith(AndroidTestingRunner::class)
+class UserTrackerImplTest : SysuiTestCase() {
+
+ @Mock
+ private lateinit var context: Context
+ @Mock
+ private lateinit var userManager: UserManager
+ @Mock(stubOnly = true)
+ private lateinit var dumpManager: DumpManager
+ @Mock(stubOnly = true)
+ private lateinit var handler: Handler
+
+ private val executor = Executor(Runnable::run)
+ private lateinit var tracker: UserTrackerImpl
+
+ @Before
+ fun setUp() {
+ MockitoAnnotations.initMocks(this)
+
+ `when`(context.userId).thenReturn(UserHandle.USER_SYSTEM)
+ `when`(context.user).thenReturn(UserHandle.SYSTEM)
+ `when`(context.createContextAsUser(any(), anyInt())).thenAnswer { invocation ->
+ val user = invocation.getArgument<UserHandle>(0)
+ `when`(context.user).thenReturn(user)
+ `when`(context.userId).thenReturn(user.identifier)
+ context
+ }
+ `when`(userManager.getProfiles(anyInt())).thenAnswer { invocation ->
+ val info = UserInfo(invocation.getArgument<Int>(0), "", UserInfo.FLAG_FULL)
+ listOf(info)
+ }
+
+ tracker = UserTrackerImpl(context, userManager, dumpManager, handler)
+ }
+
+ @Test
+ fun testNotInitialized() {
+ assertThat(tracker.initialized).isFalse()
+ }
+
+ @Test(expected = IllegalStateException::class)
+ fun testGetUserIdBeforeInitThrowsException() {
+ tracker.userId
+ }
+
+ @Test(expected = IllegalStateException::class)
+ fun testGetUserHandleBeforeInitThrowsException() {
+ tracker.userHandle
+ }
+
+ @Test(expected = IllegalStateException::class)
+ fun testGetUserContextBeforeInitThrowsException() {
+ tracker.userContext
+ }
+
+ @Test(expected = IllegalStateException::class)
+ fun testGetUserContentResolverBeforeInitThrowsException() {
+ tracker.userContentResolver
+ }
+
+ @Test(expected = IllegalStateException::class)
+ fun testGetUserProfilesBeforeInitThrowsException() {
+ tracker.userProfiles
+ }
+
+ @Test
+ fun testInitialize() {
+ tracker.initialize(0)
+
+ assertThat(tracker.initialized).isTrue()
+ }
+
+ @Test
+ fun testReceiverRegisteredOnInitialize() {
+ tracker.initialize(0)
+
+ val captor = ArgumentCaptor.forClass(IntentFilter::class.java)
+
+ verify(context).registerReceiverForAllUsers(
+ eq(tracker), capture(captor), isNull(), eq(handler))
+ }
+
+ @Test
+ fun testInitialValuesSet() {
+ val testID = 4
+ tracker.initialize(testID)
+
+ verify(userManager).getProfiles(testID)
+
+ assertThat(tracker.userId).isEqualTo(testID)
+ assertThat(tracker.userHandle).isEqualTo(UserHandle.of(testID))
+ assertThat(tracker.userContext.userId).isEqualTo(testID)
+ assertThat(tracker.userContext.user).isEqualTo(UserHandle.of(testID))
+ assertThat(tracker.userProfiles).hasSize(1)
+
+ val info = tracker.userProfiles[0]
+ assertThat(info.id).isEqualTo(testID)
+ }
+
+ @Test
+ fun testUserSwitch() {
+ tracker.initialize(0)
+ val newID = 5
+
+ val intent = Intent(Intent.ACTION_USER_SWITCHED).putExtra(Intent.EXTRA_USER_HANDLE, newID)
+ tracker.onReceive(context, intent)
+
+ verify(userManager).getProfiles(newID)
+
+ assertThat(tracker.userId).isEqualTo(newID)
+ assertThat(tracker.userHandle).isEqualTo(UserHandle.of(newID))
+ assertThat(tracker.userContext.userId).isEqualTo(newID)
+ assertThat(tracker.userContext.user).isEqualTo(UserHandle.of(newID))
+ assertThat(tracker.userProfiles).hasSize(1)
+
+ val info = tracker.userProfiles[0]
+ assertThat(info.id).isEqualTo(newID)
+ }
+
+ @Test
+ fun testManagedProfileAvailable() {
+ tracker.initialize(0)
+ val profileID = tracker.userId + 10
+
+ `when`(userManager.getProfiles(anyInt())).thenAnswer { invocation ->
+ val id = invocation.getArgument<Int>(0)
+ val info = UserInfo(id, "", UserInfo.FLAG_FULL)
+ val infoProfile = UserInfo(
+ id + 10,
+ "",
+ "",
+ UserInfo.FLAG_MANAGED_PROFILE,
+ UserManager.USER_TYPE_PROFILE_MANAGED
+ )
+ infoProfile.profileGroupId = id
+ listOf(info, infoProfile)
+ }
+
+ val intent = Intent(Intent.ACTION_MANAGED_PROFILE_AVAILABLE)
+ .putExtra(Intent.EXTRA_USER, UserHandle.of(profileID))
+ tracker.onReceive(context, intent)
+
+ assertThat(tracker.userProfiles.map { it.id }).containsExactly(tracker.userId, profileID)
+ }
+
+ @Test
+ fun testCallbackNotCalledOnAdd() {
+ tracker.initialize(0)
+ val callback = TestCallback()
+
+ tracker.addCallback(callback, executor)
+
+ assertThat(callback.calledOnProfilesChanged).isEqualTo(0)
+ assertThat(callback.calledOnUserChanged).isEqualTo(0)
+ }
+
+ @Test
+ fun testCallbackCalledOnUserChanged() {
+ tracker.initialize(0)
+ val callback = TestCallback()
+ tracker.addCallback(callback, executor)
+
+ val newID = 5
+
+ val intent = Intent(Intent.ACTION_USER_SWITCHED).putExtra(Intent.EXTRA_USER_HANDLE, newID)
+ tracker.onReceive(context, intent)
+
+ assertThat(callback.calledOnUserChanged).isEqualTo(1)
+ assertThat(callback.lastUser).isEqualTo(newID)
+ assertThat(callback.lastUserContext?.userId).isEqualTo(newID)
+ assertThat(callback.calledOnProfilesChanged).isEqualTo(1)
+ assertThat(callback.lastUserProfiles.map { it.id }).containsExactly(newID)
+ }
+
+ @Test
+ fun testCallbackCalledOnProfileChanged() {
+ tracker.initialize(0)
+ val callback = TestCallback()
+ tracker.addCallback(callback, executor)
+ val profileID = tracker.userId + 10
+
+ `when`(userManager.getProfiles(anyInt())).thenAnswer { invocation ->
+ val id = invocation.getArgument<Int>(0)
+ val info = UserInfo(id, "", UserInfo.FLAG_FULL)
+ val infoProfile = UserInfo(
+ id + 10,
+ "",
+ "",
+ UserInfo.FLAG_MANAGED_PROFILE,
+ UserManager.USER_TYPE_PROFILE_MANAGED
+ )
+ infoProfile.profileGroupId = id
+ listOf(info, infoProfile)
+ }
+
+ val intent = Intent(Intent.ACTION_MANAGED_PROFILE_AVAILABLE)
+ .putExtra(Intent.EXTRA_USER, UserHandle.of(profileID))
+
+ tracker.onReceive(context, intent)
+
+ assertThat(callback.calledOnUserChanged).isEqualTo(0)
+ assertThat(callback.calledOnProfilesChanged).isEqualTo(1)
+ assertThat(callback.lastUserProfiles.map { it.id }).containsExactly(0, profileID)
+ }
+
+ @Test
+ fun testCallbackRemoved() {
+ tracker.initialize(0)
+ val newID = 5
+ val profileID = newID + 10
+
+ val callback = TestCallback()
+ tracker.addCallback(callback, executor)
+ tracker.removeCallback(callback)
+
+ val intent = Intent(Intent.ACTION_USER_SWITCHED).putExtra(Intent.EXTRA_USER_HANDLE, 5)
+ tracker.onReceive(context, intent)
+
+ val intentProfiles = Intent(Intent.ACTION_MANAGED_PROFILE_AVAILABLE)
+ .putExtra(Intent.EXTRA_USER, UserHandle.of(profileID))
+
+ tracker.onReceive(context, intentProfiles)
+
+ assertThat(callback.calledOnUserChanged).isEqualTo(0)
+ assertThat(callback.calledOnProfilesChanged).isEqualTo(0)
+ }
+
+ private class TestCallback : UserTracker.Callback {
+ var calledOnUserChanged = 0
+ var calledOnProfilesChanged = 0
+ var lastUser: Int? = null
+ var lastUserContext: Context? = null
+ var lastUserProfiles = emptyList<UserInfo>()
+
+ override fun onUserChanged(newUser: Int, userContext: Context) {
+ calledOnUserChanged++
+ lastUser = newUser
+ lastUserContext = userContext
+ }
+
+ override fun onProfilesChanged(profiles: List<UserInfo>) {
+ calledOnProfilesChanged++
+ lastUserProfiles = profiles
+ }
+ }
+} \ No newline at end of file
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/NonPhoneDependencyTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/NonPhoneDependencyTest.java
index 8089561f44a0..b0f2a8902870 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/NonPhoneDependencyTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/NonPhoneDependencyTest.java
@@ -38,6 +38,7 @@ import com.android.systemui.statusbar.phone.ShadeController;
import com.android.systemui.statusbar.policy.HeadsUpManager;
import org.junit.Before;
+import org.junit.Ignore;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.Mock;
@@ -70,6 +71,7 @@ public class NonPhoneDependencyTest extends SysuiTestCase {
new Handler(TestableLooper.get(this).getLooper()));
}
+ @Ignore("Causes binder calls which fail")
@Test
public void testNotificationManagementCodeHasNoDependencyOnStatusBarWindowManager() {
mDependency.injectMockDependency(ShadeController.class);
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/NotificationViewHierarchyManagerTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/NotificationViewHierarchyManagerTest.java
index 1259d28c3400..d041ee047ae0 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/NotificationViewHierarchyManagerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/NotificationViewHierarchyManagerTest.java
@@ -19,7 +19,6 @@ package com.android.systemui.statusbar;
import static junit.framework.Assert.assertTrue;
import static org.junit.Assert.assertEquals;
-import static org.mockito.ArgumentMatchers.anyInt;
import static org.mockito.Mockito.clearInvocations;
import static org.mockito.Mockito.doAnswer;
import static org.mockito.Mockito.mock;
@@ -46,6 +45,7 @@ import com.android.systemui.statusbar.notification.NotificationActivityStarter;
import com.android.systemui.statusbar.notification.NotificationEntryManager;
import com.android.systemui.statusbar.notification.collection.NotificationEntry;
import com.android.systemui.statusbar.notification.collection.inflation.LowPriorityInflationHelper;
+import com.android.systemui.statusbar.notification.collection.legacy.NotificationGroupManagerLegacy;
import com.android.systemui.statusbar.notification.collection.legacy.VisualStabilityManager;
import com.android.systemui.statusbar.notification.logging.NotificationLogger;
import com.android.systemui.statusbar.notification.row.ExpandableNotificationRow;
@@ -54,7 +54,6 @@ import com.android.systemui.statusbar.notification.row.NotificationTestHelper;
import com.android.systemui.statusbar.notification.stack.ForegroundServiceSectionController;
import com.android.systemui.statusbar.notification.stack.NotificationListContainer;
import com.android.systemui.statusbar.phone.KeyguardBypassController;
-import com.android.systemui.statusbar.phone.NotificationGroupManager;
import com.google.android.collect.Lists;
@@ -77,7 +76,7 @@ public class NotificationViewHierarchyManagerTest extends SysuiTestCase {
// Dependency mocks:
@Mock private NotificationEntryManager mEntryManager;
@Mock private NotificationLockscreenUserManager mLockscreenUserManager;
- @Mock private NotificationGroupManager mGroupManager;
+ @Mock private NotificationGroupManagerLegacy mGroupManager;
@Mock private VisualStabilityManager mVisualStabilityManager;
private TestableLooper mTestableLooper;
@@ -96,7 +95,7 @@ public class NotificationViewHierarchyManagerTest extends SysuiTestCase {
mDependency.injectTestDependency(NotificationEntryManager.class, mEntryManager);
mDependency.injectTestDependency(NotificationLockscreenUserManager.class,
mLockscreenUserManager);
- mDependency.injectTestDependency(NotificationGroupManager.class, mGroupManager);
+ mDependency.injectTestDependency(NotificationGroupManagerLegacy.class, mGroupManager);
mDependency.injectTestDependency(VisualStabilityManager.class, mVisualStabilityManager);
when(mVisualStabilityManager.areGroupChangesAllowed()).thenReturn(true);
when(mVisualStabilityManager.isReorderingAllowed()).thenReturn(true);
@@ -137,11 +136,11 @@ public class NotificationViewHierarchyManagerTest extends SysuiTestCase {
Lists.newArrayList(entry0, entry1, entry2));
// Set up group manager to report that they should be bundled now.
- when(mGroupManager.isChildInGroupWithSummary(entry0.getSbn())).thenReturn(false);
- when(mGroupManager.isChildInGroupWithSummary(entry1.getSbn())).thenReturn(true);
- when(mGroupManager.isChildInGroupWithSummary(entry2.getSbn())).thenReturn(true);
- when(mGroupManager.getGroupSummary(entry1.getSbn())).thenReturn(entry0);
- when(mGroupManager.getGroupSummary(entry2.getSbn())).thenReturn(entry0);
+ when(mGroupManager.isChildInGroup(entry0)).thenReturn(false);
+ when(mGroupManager.isChildInGroup(entry1)).thenReturn(true);
+ when(mGroupManager.isChildInGroup(entry2)).thenReturn(true);
+ when(mGroupManager.getGroupSummary(entry1)).thenReturn(entry0);
+ when(mGroupManager.getGroupSummary(entry2)).thenReturn(entry0);
// Run updateNotifications - the view hierarchy should be reorganized.
mViewHierarchyManager.updateNotificationViews();
@@ -166,9 +165,9 @@ public class NotificationViewHierarchyManagerTest extends SysuiTestCase {
Lists.newArrayList(entry0, entry1, entry2));
// Set up group manager to report that they should not be bundled now.
- when(mGroupManager.isChildInGroupWithSummary(entry0.getSbn())).thenReturn(false);
- when(mGroupManager.isChildInGroupWithSummary(entry1.getSbn())).thenReturn(false);
- when(mGroupManager.isChildInGroupWithSummary(entry2.getSbn())).thenReturn(false);
+ when(mGroupManager.isChildInGroup(entry0)).thenReturn(false);
+ when(mGroupManager.isChildInGroup(entry1)).thenReturn(false);
+ when(mGroupManager.isChildInGroup(entry2)).thenReturn(false);
// Run updateNotifications - the view hierarchy should be reorganized.
mViewHierarchyManager.updateNotificationViews();
@@ -195,8 +194,8 @@ public class NotificationViewHierarchyManagerTest extends SysuiTestCase {
Lists.newArrayList(entry0, entry1));
// Set up group manager to report a suppressed summary now.
- when(mGroupManager.isChildInGroupWithSummary(entry0.getSbn())).thenReturn(false);
- when(mGroupManager.isChildInGroupWithSummary(entry1.getSbn())).thenReturn(false);
+ when(mGroupManager.isChildInGroup(entry0)).thenReturn(false);
+ when(mGroupManager.isChildInGroup(entry1)).thenReturn(false);
when(mGroupManager.isSummaryOfSuppressedGroup(entry0.getSbn())).thenReturn(true);
// Run updateNotifications - the view hierarchy should be reorganized.
@@ -219,7 +218,7 @@ public class NotificationViewHierarchyManagerTest extends SysuiTestCase {
mViewHierarchyManager.onDynamicPrivacyChanged();
}
return null;
- }).when(mListContainer).setMaxDisplayedNotifications(anyInt());
+ }).when(mListContainer).onNotificationViewUpdateFinished();
// WHEN we call updateNotificationViews()
mViewHierarchyManager.updateNotificationViews();
@@ -247,7 +246,7 @@ public class NotificationViewHierarchyManagerTest extends SysuiTestCase {
mViewHierarchyManager.onDynamicPrivacyChanged();
}
return null;
- }).when(mListContainer).setMaxDisplayedNotifications(anyInt());
+ }).when(mListContainer).onNotificationViewUpdateFinished();
// WHEN we call updateNotificationViews() and drain the looper
mViewHierarchyManager.updateNotificationViews();
@@ -262,7 +261,6 @@ public class NotificationViewHierarchyManagerTest extends SysuiTestCase {
private class FakeListContainer implements NotificationListContainer {
final LinearLayout mLayout = new LinearLayout(mContext);
final List<View> mRows = Lists.newArrayList();
- private boolean mMakeReentrantCallDuringSetMaxDisplayedNotifications;
@Override
public void setChildTransferInProgress(boolean childTransferInProgress) {}
@@ -322,9 +320,6 @@ public class NotificationViewHierarchyManagerTest extends SysuiTestCase {
@Override
public void setMaxDisplayedNotifications(int maxNotifications) {
- if (mMakeReentrantCallDuringSetMaxDisplayedNotifications) {
- mViewHierarchyManager.onDynamicPrivacyChanged();
- }
}
@Override
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/NotificationEntryManagerTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/NotificationEntryManagerTest.java
index d4718e7e55fa..3e1616c9fa7b 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/NotificationEntryManagerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/NotificationEntryManagerTest.java
@@ -75,13 +75,13 @@ import com.android.systemui.statusbar.notification.collection.NotificationEntry;
import com.android.systemui.statusbar.notification.collection.NotificationEntryBuilder;
import com.android.systemui.statusbar.notification.collection.NotificationRankingManager;
import com.android.systemui.statusbar.notification.collection.inflation.NotificationRowBinder;
+import com.android.systemui.statusbar.notification.collection.legacy.NotificationGroupManagerLegacy;
import com.android.systemui.statusbar.notification.collection.notifcollection.DismissedByUserStats;
import com.android.systemui.statusbar.notification.collection.provider.HighPriorityProvider;
import com.android.systemui.statusbar.notification.people.PeopleNotificationIdentifier;
import com.android.systemui.statusbar.notification.row.ExpandableNotificationRow;
import com.android.systemui.statusbar.notification.row.NotificationEntryManagerInflationTest;
import com.android.systemui.statusbar.notification.row.RowInflaterTask;
-import com.android.systemui.statusbar.phone.NotificationGroupManager;
import com.android.systemui.statusbar.policy.DeviceProvisionedController;
import com.android.systemui.statusbar.policy.HeadsUpManager;
import com.android.systemui.util.leak.LeakDetector;
@@ -119,7 +119,7 @@ public class NotificationEntryManagerTest extends SysuiTestCase {
@Mock private NotificationRemoveInterceptor mRemoveInterceptor;
@Mock private HeadsUpManager mHeadsUpManager;
@Mock private RankingMap mRankingMap;
- @Mock private NotificationGroupManager mGroupManager;
+ @Mock private NotificationGroupManagerLegacy mGroupManager;
@Mock private NotificationRemoteInputManager mRemoteInputManager;
@Mock private DeviceProvisionedController mDeviceProvisionedController;
@Mock private RowInflaterTask mAsyncInflationTask;
@@ -346,7 +346,6 @@ public class NotificationEntryManagerTest extends SysuiTestCase {
setSmartActions(mEntry.getKey(), null);
mEntryManager.updateNotificationRanking(mRankingMap);
- verify(mRow, never()).setEntry(eq(mEntry));
assertNull(mEntry.getSmartActions());
}
@@ -360,7 +359,6 @@ public class NotificationEntryManagerTest extends SysuiTestCase {
setSmartActions(mEntry.getKey(), new ArrayList<>(Arrays.asList(createAction())));
mEntryManager.updateNotificationRanking(mRankingMap);
- verify(mRow, never()).setEntry(eq(mEntry));
assertEquals(1, mEntry.getSmartActions().size());
assertEquals("action", mEntry.getSmartActions().get(0).title);
}
@@ -375,7 +373,6 @@ public class NotificationEntryManagerTest extends SysuiTestCase {
setSmartActions(mEntry.getKey(), new ArrayList<>(Arrays.asList(createAction())));
mEntryManager.updateNotificationRanking(mRankingMap);
- verify(mRow, never()).setEntry(eq(mEntry));
assertEquals(1, mEntry.getSmartActions().size());
assertEquals("action", mEntry.getSmartActions().get(0).title);
}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/NotificationFilterTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/NotificationFilterTest.java
index 5a81d36ea744..dfe006dfd4fe 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/NotificationFilterTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/NotificationFilterTest.java
@@ -48,10 +48,10 @@ import com.android.systemui.statusbar.NotificationLockscreenUserManager;
import com.android.systemui.statusbar.notification.NotificationEntryManager.KeyguardEnvironment;
import com.android.systemui.statusbar.notification.collection.NotificationEntry;
import com.android.systemui.statusbar.notification.collection.NotificationEntryBuilder;
+import com.android.systemui.statusbar.notification.collection.legacy.NotificationGroupManagerLegacy;
import com.android.systemui.statusbar.notification.people.PeopleNotificationIdentifier;
import com.android.systemui.statusbar.notification.row.ExpandableNotificationRow;
import com.android.systemui.statusbar.notification.row.NotificationTestHelper;
-import com.android.systemui.statusbar.phone.NotificationGroupManager;
import com.android.systemui.statusbar.phone.ShadeController;
import org.junit.After;
@@ -109,8 +109,8 @@ public class NotificationFilterTest extends SysuiTestCase {
eq(UID_ALLOW_DURING_SETUP)))
.thenReturn(PackageManager.PERMISSION_GRANTED);
mDependency.injectTestDependency(ForegroundServiceController.class, mFsc);
- mDependency.injectTestDependency(NotificationGroupManager.class,
- new NotificationGroupManager(
+ mDependency.injectTestDependency(NotificationGroupManagerLegacy.class,
+ new NotificationGroupManagerLegacy(
mock(StatusBarStateController.class),
() -> mock(PeopleNotificationIdentifier.class)));
mDependency.injectMockDependency(ShadeController.class);
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/HighPriorityProviderTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/HighPriorityProviderTest.java
index 386c866cdd03..14877eec9a83 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/HighPriorityProviderTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/HighPriorityProviderTest.java
@@ -37,8 +37,8 @@ import androidx.test.filters.SmallTest;
import com.android.systemui.SysuiTestCase;
import com.android.systemui.statusbar.RankingBuilder;
import com.android.systemui.statusbar.notification.collection.provider.HighPriorityProvider;
+import com.android.systemui.statusbar.notification.collection.render.GroupMembershipManager;
import com.android.systemui.statusbar.notification.people.PeopleNotificationIdentifier;
-import com.android.systemui.statusbar.phone.NotificationGroupManager;
import org.junit.Before;
import org.junit.Test;
@@ -48,12 +48,13 @@ import org.mockito.MockitoAnnotations;
import java.util.ArrayList;
import java.util.Arrays;
+import java.util.List;
@SmallTest
@RunWith(AndroidTestingRunner.class)
public class HighPriorityProviderTest extends SysuiTestCase {
@Mock private PeopleNotificationIdentifier mPeopleNotificationIdentifier;
- @Mock private NotificationGroupManager mGroupManager;
+ @Mock private GroupMembershipManager mGroupMembershipManager;
private HighPriorityProvider mHighPriorityProvider;
@Before
@@ -61,7 +62,7 @@ public class HighPriorityProviderTest extends SysuiTestCase {
MockitoAnnotations.initMocks(this);
mHighPriorityProvider = new HighPriorityProvider(
mPeopleNotificationIdentifier,
- mGroupManager);
+ mGroupMembershipManager);
}
@Test
@@ -71,7 +72,7 @@ public class HighPriorityProviderTest extends SysuiTestCase {
.setImportance(IMPORTANCE_HIGH)
.build();
when(mPeopleNotificationIdentifier
- .getPeopleNotificationType(entry.getSbn(), entry.getRanking()))
+ .getPeopleNotificationType(entry))
.thenReturn(TYPE_NON_PERSON);
// THEN it has high priority
@@ -88,7 +89,7 @@ public class HighPriorityProviderTest extends SysuiTestCase {
.setImportance(IMPORTANCE_LOW)
.build();
when(mPeopleNotificationIdentifier
- .getPeopleNotificationType(entry.getSbn(), entry.getRanking()))
+ .getPeopleNotificationType(entry))
.thenReturn(TYPE_PERSON);
// THEN it has high priority
@@ -105,7 +106,7 @@ public class HighPriorityProviderTest extends SysuiTestCase {
.setNotification(notification)
.build();
when(mPeopleNotificationIdentifier
- .getPeopleNotificationType(entry.getSbn(), entry.getRanking()))
+ .getPeopleNotificationType(entry))
.thenReturn(TYPE_NON_PERSON);
// THEN it has high priority
@@ -123,7 +124,7 @@ public class HighPriorityProviderTest extends SysuiTestCase {
.setImportance(IMPORTANCE_LOW)
.build();
when(mPeopleNotificationIdentifier
- .getPeopleNotificationType(entry.getSbn(), entry.getRanking()))
+ .getPeopleNotificationType(entry))
.thenReturn(TYPE_NON_PERSON);
// THEN it has high priority
@@ -141,7 +142,7 @@ public class HighPriorityProviderTest extends SysuiTestCase {
.setImportance(IMPORTANCE_MIN)
.build();
when(mPeopleNotificationIdentifier
- .getPeopleNotificationType(entry.getSbn(), entry.getRanking()))
+ .getPeopleNotificationType(entry))
.thenReturn(TYPE_NON_PERSON);
// THEN it does NOT have high priority
@@ -165,7 +166,7 @@ public class HighPriorityProviderTest extends SysuiTestCase {
.setChannel(channel)
.build();
when(mPeopleNotificationIdentifier
- .getPeopleNotificationType(entry.getSbn(), entry.getRanking()))
+ .getPeopleNotificationType(entry))
.thenReturn(TYPE_PERSON);
// THEN it does NOT have high priority
@@ -173,13 +174,13 @@ public class HighPriorityProviderTest extends SysuiTestCase {
}
@Test
- public void testIsHighPriority_checkChildrenToCalculatePriority() {
+ public void testIsHighPriority_checkChildrenToCalculatePriority_legacy() {
// GIVEN: a summary with low priority has a highPriorityChild and a lowPriorityChild
final NotificationEntry summary = createNotifEntry(false);
final NotificationEntry lowPriorityChild = createNotifEntry(false);
final NotificationEntry highPriorityChild = createNotifEntry(true);
- when(mGroupManager.isGroupSummary(summary.getSbn())).thenReturn(true);
- when(mGroupManager.getChildren(summary.getSbn())).thenReturn(
+ when(mGroupMembershipManager.isGroupSummary(summary)).thenReturn(true);
+ when(mGroupMembershipManager.getChildren(summary)).thenReturn(
new ArrayList<>(Arrays.asList(lowPriorityChild, highPriorityChild)));
// THEN the summary is high priority since it has a high priority child
@@ -210,16 +211,20 @@ public class HighPriorityProviderTest extends SysuiTestCase {
}
@Test
- public void testIsHighPriority_checkChildrenToCalculatePriorityOf() {
+ public void testIsHighPriority_checkChildrenToCalculatePriority() {
// GIVEN:
- // GroupEntry = parentEntry, summary = lowPrioritySummary
+ // parent with summary = lowPrioritySummary
// NotificationEntry = lowPriorityChild
// NotificationEntry = highPriorityChild
+ final NotificationEntry lowPrioritySummary = createNotifEntry(false);
final GroupEntry parentEntry = new GroupEntryBuilder()
- .setSummary(createNotifEntry(false))
- .addChild(createNotifEntry(false))
- .addChild(createNotifEntry(true))
+ .setSummary(lowPrioritySummary)
.build();
+ when(mGroupMembershipManager.getChildren(parentEntry)).thenReturn(
+ new ArrayList<>(
+ List.of(
+ createNotifEntry(false),
+ createNotifEntry(true))));
// THEN the GroupEntry parentEntry is high priority since it has a high priority child
assertTrue(mHighPriorityProvider.isHighPriority(parentEntry));
@@ -228,13 +233,15 @@ public class HighPriorityProviderTest extends SysuiTestCase {
@Test
public void testIsHighPriority_childEntryRankingUpdated() {
// GIVEN:
- // GroupEntry = parentEntry, summary = lowPrioritySummary
+ // parent with summary = lowPrioritySummary
// NotificationEntry = lowPriorityChild
- final NotificationEntry lowPriorityChild = createNotifEntry(false);
+ final NotificationEntry lowPrioritySummary = createNotifEntry(false);
final GroupEntry parentEntry = new GroupEntryBuilder()
- .setSummary(createNotifEntry(false))
- .addChild(lowPriorityChild)
+ .setSummary(lowPrioritySummary)
.build();
+ final NotificationEntry lowPriorityChild = createNotifEntry(false);
+ when(mGroupMembershipManager.getChildren(parentEntry)).thenReturn(
+ new ArrayList<>(List.of(lowPriorityChild)));
// WHEN the child entry ranking changes to high priority
lowPriorityChild.setRanking(
@@ -243,9 +250,8 @@ public class HighPriorityProviderTest extends SysuiTestCase {
.setImportance(IMPORTANCE_HIGH)
.build());
- // THEN the parent entry's high priority value is updated - but not the parent's summary
+ // THEN the parent entry's high priority value is updated
assertTrue(mHighPriorityProvider.isHighPriority(parentEntry));
- assertFalse(mHighPriorityProvider.isHighPriority(parentEntry.getSummary()));
}
private NotificationEntry createNotifEntry(boolean highPriority) {
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/NotificationRankingManagerTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/NotificationRankingManagerTest.kt
index 82a7774b4d82..c832fe481f74 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/NotificationRankingManagerTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/NotificationRankingManagerTest.kt
@@ -40,7 +40,7 @@ import com.android.systemui.statusbar.notification.row.ExpandableNotificationRow
import com.android.systemui.statusbar.notification.stack.BUCKET_ALERTING
import com.android.systemui.statusbar.notification.stack.BUCKET_FOREGROUND_SERVICE
import com.android.systemui.statusbar.notification.stack.BUCKET_SILENT
-import com.android.systemui.statusbar.phone.NotificationGroupManager
+import com.android.systemui.statusbar.notification.collection.legacy.NotificationGroupManagerLegacy
import com.android.systemui.statusbar.policy.HeadsUpManager
import com.google.common.truth.Truth.assertThat
import dagger.Lazy
@@ -71,14 +71,14 @@ class NotificationRankingManagerTest : SysuiTestCase() {
notificationFilter = mock(NotificationFilter::class.java)
rankingManager = TestableNotificationRankingManager(
lazyMedia,
- mock(NotificationGroupManager::class.java),
+ mock(NotificationGroupManagerLegacy::class.java),
mock(HeadsUpManager::class.java),
notificationFilter,
mock(NotificationEntryManagerLogger::class.java),
sectionsManager,
personNotificationIdentifier,
HighPriorityProvider(personNotificationIdentifier,
- mock(NotificationGroupManager::class.java))
+ mock(NotificationGroupManagerLegacy::class.java))
)
}
@@ -174,7 +174,7 @@ class NotificationRankingManagerTest : SysuiTestCase() {
.setOverrideGroupKey("")
.build()
- whenever(personNotificationIdentifier.getPeopleNotificationType(a.sbn, a.ranking))
+ whenever(personNotificationIdentifier.getPeopleNotificationType(a))
.thenReturn(TYPE_IMPORTANT_PERSON)
val bN = Notification.Builder(mContext, "test")
@@ -194,7 +194,7 @@ class NotificationRankingManagerTest : SysuiTestCase() {
whenever(it.isHeadsUp).thenReturn(true)
}
- whenever(personNotificationIdentifier.getPeopleNotificationType(a.sbn, a.ranking))
+ whenever(personNotificationIdentifier.getPeopleNotificationType(a))
.thenReturn(TYPE_PERSON)
assertEquals(listOf(b, a), rankingManager.updateRanking(null, listOf(a, b), "test"))
@@ -216,7 +216,7 @@ class NotificationRankingManagerTest : SysuiTestCase() {
.setUser(mContext.user)
.setOverrideGroupKey("")
.build()
- whenever(personNotificationIdentifier.getPeopleNotificationType(a.sbn, a.ranking))
+ whenever(personNotificationIdentifier.getPeopleNotificationType(a))
.thenReturn(TYPE_PERSON)
val bN = Notification.Builder(mContext, "test")
@@ -232,7 +232,7 @@ class NotificationRankingManagerTest : SysuiTestCase() {
.setUser(mContext.user)
.setOverrideGroupKey("")
.build()
- whenever(personNotificationIdentifier.getPeopleNotificationType(b.sbn, b.ranking))
+ whenever(personNotificationIdentifier.getPeopleNotificationType(b))
.thenReturn(TYPE_IMPORTANT_PERSON)
whenever(personNotificationIdentifier.compareTo(TYPE_PERSON, TYPE_IMPORTANT_PERSON))
@@ -261,7 +261,7 @@ class NotificationRankingManagerTest : SysuiTestCase() {
.setUser(mContext.user)
.setOverrideGroupKey("")
.build()
- whenever(personNotificationIdentifier.getPeopleNotificationType(a.sbn, a.ranking))
+ whenever(personNotificationIdentifier.getPeopleNotificationType(a))
.thenReturn(TYPE_PERSON)
val bN = Notification.Builder(mContext, "test")
@@ -277,7 +277,7 @@ class NotificationRankingManagerTest : SysuiTestCase() {
.setUser(mContext.user)
.setOverrideGroupKey("")
.build()
- whenever(personNotificationIdentifier.getPeopleNotificationType(b.sbn, b.ranking))
+ whenever(personNotificationIdentifier.getPeopleNotificationType(b))
.thenReturn(TYPE_FULL_PERSON)
whenever(personNotificationIdentifier.compareTo(TYPE_PERSON, TYPE_FULL_PERSON))
@@ -400,7 +400,7 @@ class NotificationRankingManagerTest : SysuiTestCase() {
.setUser(mContext.user)
.setOverrideGroupKey("")
.build()
- whenever(personNotificationIdentifier.getPeopleNotificationType(a.sbn, a.ranking))
+ whenever(personNotificationIdentifier.getPeopleNotificationType(a))
.thenReturn(TYPE_IMPORTANT_PERSON)
assertThat(rankingManager.updateRanking(null, listOf(a, b, c), "test"))
@@ -410,7 +410,7 @@ class NotificationRankingManagerTest : SysuiTestCase() {
internal class TestableNotificationRankingManager(
mediaManager: Lazy<NotificationMediaManager>,
- groupManager: NotificationGroupManager,
+ groupManager: NotificationGroupManagerLegacy,
headsUpManager: HeadsUpManager,
filter: NotificationFilter,
logger: NotificationEntryManagerLogger,
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/coordinator/ConversationCoordinatorTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/coordinator/ConversationCoordinatorTest.kt
index c49393d2ed34..09c9bcd967bd 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/coordinator/ConversationCoordinatorTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/coordinator/ConversationCoordinatorTest.kt
@@ -84,8 +84,8 @@ class ConversationCoordinatorTest : SysuiTestCase() {
@Test
fun testInPeopleSection() {
- whenever(peopleNotificationIdentifier.getPeopleNotificationType(
- entry.sbn, entry.ranking)).thenReturn(TYPE_PERSON)
+ whenever(peopleNotificationIdentifier.getPeopleNotificationType(entry))
+ .thenReturn(TYPE_PERSON)
// only put people notifications in this section
assertTrue(peopleSectioner.isInSection(entry))
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/NotificationEntryManagerInflationTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/NotificationEntryManagerInflationTest.java
index 7a0a19bd5424..aff8ade6f1ae 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/NotificationEntryManagerInflationTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/NotificationEntryManagerInflationTest.java
@@ -67,6 +67,7 @@ import com.android.systemui.statusbar.notification.collection.NotificationEntry;
import com.android.systemui.statusbar.notification.collection.NotificationRankingManager;
import com.android.systemui.statusbar.notification.collection.inflation.LowPriorityInflationHelper;
import com.android.systemui.statusbar.notification.collection.inflation.NotificationRowBinderImpl;
+import com.android.systemui.statusbar.notification.collection.legacy.NotificationGroupManagerLegacy;
import com.android.systemui.statusbar.notification.collection.provider.HighPriorityProvider;
import com.android.systemui.statusbar.notification.icon.IconBuilder;
import com.android.systemui.statusbar.notification.icon.IconManager;
@@ -77,7 +78,6 @@ import com.android.systemui.statusbar.notification.row.dagger.ExpandableNotifica
import com.android.systemui.statusbar.notification.row.dagger.NotificationRowComponent;
import com.android.systemui.statusbar.notification.stack.NotificationListContainer;
import com.android.systemui.statusbar.phone.KeyguardBypassController;
-import com.android.systemui.statusbar.phone.NotificationGroupManager;
import com.android.systemui.statusbar.policy.HeadsUpManager;
import com.android.systemui.statusbar.policy.SmartReplyConstants;
import com.android.systemui.util.concurrency.FakeExecutor;
@@ -130,7 +130,8 @@ public class NotificationEntryManagerInflationTest extends SysuiTestCase {
@Mock private KeyguardBypassController mKeyguardBypassController;
@Mock private StatusBarStateController mStatusBarStateController;
- @Mock private NotificationGroupManager mGroupManager;
+ @Mock private NotificationGroupManagerLegacy mGroupMembershipManager;
+ @Mock private NotificationGroupManagerLegacy mGroupExpansionManager;
@Mock private FeatureFlags mFeatureFlags;
@Mock private LeakDetector mLeakDetector;
@@ -170,10 +171,10 @@ public class NotificationEntryManagerInflationTest extends SysuiTestCase {
mEntryManager = new NotificationEntryManager(
mock(NotificationEntryManagerLogger.class),
- mGroupManager,
+ mGroupMembershipManager,
new NotificationRankingManager(
() -> mock(NotificationMediaManager.class),
- mGroupManager,
+ mGroupMembershipManager,
mHeadsUpManager,
mock(NotificationFilter.class),
mock(NotificationEntryManagerLogger.class),
@@ -228,7 +229,8 @@ public class NotificationEntryManagerInflationTest extends SysuiTestCase {
new FakeSystemClock(),
"FOOBAR", "FOOBAR",
mKeyguardBypassController,
- mGroupManager,
+ mGroupMembershipManager,
+ mGroupExpansionManager,
mRowContentBindStage,
mock(NotificationLogger.class),
mHeadsUpManager,
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/NotificationGutsManagerTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/NotificationGutsManagerTest.java
index c2c40cac3d0f..e1668cab3333 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/NotificationGutsManagerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/NotificationGutsManagerTest.java
@@ -69,7 +69,7 @@ import com.android.internal.logging.testing.UiEventLoggerFake;
import com.android.systemui.SysuiTestCase;
import com.android.systemui.bubbles.BubbleController;
import com.android.systemui.plugins.statusbar.NotificationMenuRowPlugin;
-import com.android.systemui.settings.CurrentUserContextTracker;
+import com.android.systemui.settings.UserContextProvider;
import com.android.systemui.statusbar.NotificationLockscreenUserManager;
import com.android.systemui.statusbar.NotificationPresenter;
import com.android.systemui.statusbar.notification.AssistantFeedbackController;
@@ -128,7 +128,7 @@ public class NotificationGutsManagerTest extends SysuiTestCase {
@Mock private ShortcutManager mShortcutManager;
@Mock private ChannelEditorDialogController mChannelEditorDialogController;
@Mock private PeopleNotificationIdentifier mPeopleNotificationIdentifier;
- @Mock private CurrentUserContextTracker mContextTracker;
+ @Mock private UserContextProvider mContextTracker;
@Mock private BubbleController mBubbleController;
@Mock(answer = Answers.RETURNS_SELF)
private PriorityOnboardingDialogController.Builder mBuilder;
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/NotificationTestHelper.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/NotificationTestHelper.java
index 9a8678f01870..b952c056c33d 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/NotificationTestHelper.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/NotificationTestHelper.java
@@ -57,6 +57,7 @@ import com.android.systemui.statusbar.SmartReplyController;
import com.android.systemui.statusbar.notification.ConversationNotificationProcessor;
import com.android.systemui.statusbar.notification.collection.NotificationEntry;
import com.android.systemui.statusbar.notification.collection.NotificationEntryBuilder;
+import com.android.systemui.statusbar.notification.collection.legacy.NotificationGroupManagerLegacy;
import com.android.systemui.statusbar.notification.collection.notifcollection.CommonNotifCollection;
import com.android.systemui.statusbar.notification.collection.notifcollection.NotifCollectionListener;
import com.android.systemui.statusbar.notification.icon.IconBuilder;
@@ -68,7 +69,6 @@ import com.android.systemui.statusbar.notification.row.NotificationRowContentBin
import com.android.systemui.statusbar.phone.ConfigurationControllerImpl;
import com.android.systemui.statusbar.phone.HeadsUpManagerPhone;
import com.android.systemui.statusbar.phone.KeyguardBypassController;
-import com.android.systemui.statusbar.phone.NotificationGroupManager;
import com.android.systemui.statusbar.policy.SmartReplyConstants;
import org.mockito.ArgumentCaptor;
@@ -96,7 +96,8 @@ public class NotificationTestHelper {
private final Context mContext;
private final TestableLooper mTestLooper;
private int mId;
- private final NotificationGroupManager mGroupManager;
+ private final NotificationGroupManagerLegacy mGroupMembershipManager;
+ private final NotificationGroupManagerLegacy mGroupExpansionManager;
private ExpandableNotificationRow mRow;
private HeadsUpManagerPhone mHeadsUpManager;
private final NotifBindPipeline mBindPipeline;
@@ -116,13 +117,14 @@ public class NotificationTestHelper {
dependency.injectMockDependency(BubbleController.class);
dependency.injectMockDependency(NotificationShadeWindowController.class);
mStatusBarStateController = mock(StatusBarStateController.class);
- mGroupManager = new NotificationGroupManager(
+ mGroupMembershipManager = new NotificationGroupManagerLegacy(
mStatusBarStateController,
() -> mock(PeopleNotificationIdentifier.class));
+ mGroupExpansionManager = mGroupMembershipManager;
mHeadsUpManager = new HeadsUpManagerPhone(mContext, mStatusBarStateController,
- mock(KeyguardBypassController.class), mock(NotificationGroupManager.class),
+ mock(KeyguardBypassController.class), mock(NotificationGroupManagerLegacy.class),
mock(ConfigurationControllerImpl.class));
- mGroupManager.setHeadsUpManager(mHeadsUpManager);
+ mGroupMembershipManager.setHeadsUpManager(mHeadsUpManager);
mIconManager = new IconManager(
mock(CommonNotifCollection.class),
mock(LauncherApps.class),
@@ -406,17 +408,18 @@ public class NotificationTestHelper {
entry.setRow(row);
mIconManager.createIcons(entry);
- row.setEntry(entry);
mBindPipelineEntryListener.onEntryInit(entry);
mBindPipeline.manageRow(entry, row);
row.initialize(
+ entry,
APP_NAME,
entry.getKey(),
mock(ExpansionLogger.class),
mock(KeyguardBypassController.class),
- mGroupManager,
+ mGroupMembershipManager,
+ mGroupExpansionManager,
mHeadsUpManager,
mBindStage,
mock(OnExpandClickListener.class),
@@ -426,6 +429,7 @@ public class NotificationTestHelper {
mStatusBarStateController,
mPeopleNotificationIdentifier,
mock(OnUserInteractionCallback.class));
+
row.setAboveShelfChangedListener(aboveShelf -> { });
mBindStage.getStageParams(entry).requireContentViews(extraInflationFlags);
inflateAndWait(entry);
@@ -433,7 +437,7 @@ public class NotificationTestHelper {
// This would be done as part of onAsyncInflationFinished, but we skip large amounts of
// the callback chain, so we need to make up for not adding it to the group manager
// here.
- mGroupManager.onEntryAdded(entry);
+ mGroupMembershipManager.onEntryAdded(entry);
return row;
}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayoutTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayoutTest.java
index bca7b312ff15..f48e6ea7941e 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayoutTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayoutTest.java
@@ -18,7 +18,6 @@ import static android.provider.Settings.Secure.NOTIFICATION_NEW_INTERRUPTION_MOD
import static junit.framework.Assert.assertEquals;
import static junit.framework.Assert.assertNotNull;
-import static junit.framework.Assert.assertNull;
import static org.junit.Assert.assertFalse;
import static org.mockito.ArgumentMatchers.any;
@@ -34,12 +33,10 @@ import static org.mockito.Mockito.spy;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
-import android.metrics.LogMaker;
import android.os.UserHandle;
import android.provider.Settings;
import android.testing.AndroidTestingRunner;
import android.testing.TestableLooper;
-import android.view.View;
import androidx.test.annotation.UiThreadTest;
import androidx.test.filters.SmallTest;
@@ -50,8 +47,6 @@ import com.android.internal.statusbar.IStatusBarService;
import com.android.systemui.ExpandHelper;
import com.android.systemui.R;
import com.android.systemui.SysuiTestCase;
-import com.android.systemui.classifier.FalsingManagerFake;
-import com.android.systemui.plugins.statusbar.NotificationMenuRowPlugin;
import com.android.systemui.statusbar.EmptyShadeView;
import com.android.systemui.statusbar.FeatureFlags;
import com.android.systemui.statusbar.NotificationMediaManager;
@@ -74,18 +69,15 @@ import com.android.systemui.statusbar.notification.collection.NotificationEntry;
import com.android.systemui.statusbar.notification.collection.NotificationEntryBuilder;
import com.android.systemui.statusbar.notification.collection.NotificationRankingManager;
import com.android.systemui.statusbar.notification.collection.inflation.NotificationRowBinder;
+import com.android.systemui.statusbar.notification.collection.legacy.NotificationGroupManagerLegacy;
import com.android.systemui.statusbar.notification.collection.legacy.VisualStabilityManager;
import com.android.systemui.statusbar.notification.collection.provider.HighPriorityProvider;
import com.android.systemui.statusbar.notification.people.PeopleNotificationIdentifier;
import com.android.systemui.statusbar.notification.row.ExpandableNotificationRow;
import com.android.systemui.statusbar.notification.row.FooterView;
import com.android.systemui.statusbar.notification.row.NotificationBlockingHelperManager;
-import com.android.systemui.statusbar.notification.row.NotificationGutsManager;
import com.android.systemui.statusbar.notification.stack.NotificationStackScrollLayout.KeyguardBypassEnabledProvider;
import com.android.systemui.statusbar.phone.HeadsUpManagerPhone;
-import com.android.systemui.statusbar.phone.NotificationGroupManager;
-import com.android.systemui.statusbar.phone.NotificationIconAreaController;
-import com.android.systemui.statusbar.phone.ScrimController;
import com.android.systemui.statusbar.phone.ShadeController;
import com.android.systemui.statusbar.phone.StatusBar;
import com.android.systemui.util.leak.LeakDetector;
@@ -119,12 +111,12 @@ public class NotificationStackScrollLayoutTest extends SysuiTestCase {
@Mock private SysuiStatusBarStateController mBarState;
@Mock private HeadsUpManagerPhone mHeadsUpManager;
@Mock private NotificationBlockingHelperManager mBlockingHelperManager;
- @Mock private NotificationGroupManager mGroupManager;
+ @Mock private NotificationGroupManagerLegacy mGroupMembershipManger;
+ @Mock private NotificationGroupManagerLegacy mGroupExpansionManager;
@Mock private ExpandHelper mExpandHelper;
@Mock private EmptyShadeView mEmptyShadeView;
@Mock private NotificationRemoteInputManager mRemoteInputManager;
@Mock private RemoteInputController mRemoteInputController;
- @Mock private NotificationIconAreaController mNotificationIconAreaController;
@Mock private MetricsLogger mMetricsLogger;
@Mock private NotificationRoundnessManager mNotificationRoundnessManager;
@Mock private KeyguardBypassEnabledProvider mKeyguardBypassEnabledProvider;
@@ -132,6 +124,8 @@ public class NotificationStackScrollLayoutTest extends SysuiTestCase {
@Mock private NotificationSection mNotificationSection;
@Mock private FeatureFlags mFeatureFlags;
@Mock private SysuiStatusBarStateController mStatusBarStateController;
+ @Mock private NotificationSwipeHelper mNotificationSwipeHelper;
+ @Mock NotificationStackScrollLayoutController mStackScrollLayoutController;
private NotificationEntryManager mEntryManager;
private int mOriginalInterruptionModelSetting;
private UiEventLoggerFake mUiEventLoggerFake = new UiEventLoggerFake();
@@ -163,10 +157,10 @@ public class NotificationStackScrollLayoutTest extends SysuiTestCase {
mEntryManager = new NotificationEntryManager(
mock(NotificationEntryManagerLogger.class),
- mock(NotificationGroupManager.class),
+ mock(NotificationGroupManagerLegacy.class),
new NotificationRankingManager(
() -> mock(NotificationMediaManager.class),
- mGroupManager,
+ mGroupMembershipManger,
mHeadsUpManager,
mock(NotificationFilter.class),
mock(NotificationEntryManagerLogger.class),
@@ -204,9 +198,6 @@ public class NotificationStackScrollLayoutTest extends SysuiTestCase {
mNotificationRoundnessManager,
mock(DynamicPrivacyController.class),
mStatusBarStateController,
- mHeadsUpManager,
- new FalsingManagerFake(),
- mock(NotificationGutsManager.class),
mNotificationSectionsManager,
mock(ForegroundServiceSectionController.class),
mock(ForegroundServiceDismissalFeatureController.class),
@@ -214,15 +205,19 @@ public class NotificationStackScrollLayoutTest extends SysuiTestCase {
mock(NotifPipeline.class),
mEntryManager,
mock(NotifCollection.class),
- mUiEventLoggerFake
+ mUiEventLoggerFake,
+ mGroupMembershipManger,
+ mGroupExpansionManager
);
- mStackScrollerInternal.initView(getContext(), mKeyguardBypassEnabledProvider);
+ mStackScrollerInternal.initView(getContext(), mKeyguardBypassEnabledProvider,
+ mNotificationSwipeHelper);
mStackScroller = spy(mStackScrollerInternal);
mStackScroller.setShelfController(notificationShelfController);
mStackScroller.setStatusBar(mBar);
- mStackScroller.setScrimController(mock(ScrimController.class));
- mStackScroller.setGroupManager(mGroupManager);
mStackScroller.setEmptyShadeView(mEmptyShadeView);
+ when(mStackScrollLayoutController.getNoticationRoundessManager())
+ .thenReturn(mock(NotificationRoundnessManager.class));
+ mStackScroller.setController(mStackScrollLayoutController);
// Stub out functionality that isn't necessary to test.
doNothing().when(mBar)
@@ -231,7 +226,7 @@ public class NotificationStackScrollLayoutTest extends SysuiTestCase {
anyBoolean(),
anyBoolean(),
anyBoolean());
- doNothing().when(mGroupManager).collapseAllGroups();
+ doNothing().when(mGroupExpansionManager).collapseGroups();
doNothing().when(mExpandHelper).cancelImmediately();
doNothing().when(notificationShelf).setAnimationsEnabled(anyBoolean());
}
@@ -420,31 +415,22 @@ public class NotificationStackScrollLayoutTest extends SysuiTestCase {
@Test
@UiThreadTest
public void testSetIsBeingDraggedResetsExposedMenu() {
- NotificationSwipeHelper swipeActionHelper =
- (NotificationSwipeHelper) mStackScroller.getSwipeActionHelper();
- swipeActionHelper.setExposedMenuView(new View(mContext));
mStackScroller.setIsBeingDragged(true);
- assertNull(swipeActionHelper.getExposedMenuView());
+ verify(mNotificationSwipeHelper).resetExposedMenuView(true, true);
}
@Test
@UiThreadTest
public void testPanelTrackingStartResetsExposedMenu() {
- NotificationSwipeHelper swipeActionHelper =
- (NotificationSwipeHelper) mStackScroller.getSwipeActionHelper();
- swipeActionHelper.setExposedMenuView(new View(mContext));
mStackScroller.onPanelTrackingStarted();
- assertNull(swipeActionHelper.getExposedMenuView());
+ verify(mNotificationSwipeHelper).resetExposedMenuView(true, true);
}
@Test
@UiThreadTest
public void testDarkModeResetsExposedMenu() {
- NotificationSwipeHelper swipeActionHelper =
- (NotificationSwipeHelper) mStackScroller.getSwipeActionHelper();
- swipeActionHelper.setExposedMenuView(new View(mContext));
mStackScroller.setHideAmount(0.1f, 0.1f);
- assertNull(swipeActionHelper.getExposedMenuView());
+ verify(mNotificationSwipeHelper).resetExposedMenuView(true, true);
}
@Test
@@ -463,6 +449,60 @@ public class NotificationStackScrollLayoutTest extends SysuiTestCase {
.DISMISS_SILENT_NOTIFICATIONS_PANEL.getId(), mUiEventLoggerFake.eventId(0));
}
+ @Test
+ public void testAddNotificationUpdatesSpeedBumpIndex() {
+ // initial state == -1
+ assertEquals(-1, mStackScroller.getSpeedBumpIndex());
+
+ // add notification that's before the speed bump
+ ExpandableNotificationRow row = mock(ExpandableNotificationRow.class);
+ NotificationEntry entry = mock(NotificationEntry.class);
+ when(row.getEntry()).thenReturn(entry);
+ when(entry.isAmbient()).thenReturn(false);
+ mStackScroller.addContainerView(row);
+
+ // speed bump = 1
+ assertEquals(1, mStackScroller.getSpeedBumpIndex());
+ }
+
+ @Test
+ public void testAddAmbientNotificationNoSpeedBumpUpdate() {
+ // initial state == -1
+ assertEquals(-1, mStackScroller.getSpeedBumpIndex());
+
+ // add notification that's after the speed bump
+ ExpandableNotificationRow row = mock(ExpandableNotificationRow.class);
+ NotificationEntry entry = mock(NotificationEntry.class);
+ when(row.getEntry()).thenReturn(entry);
+ when(entry.isAmbient()).thenReturn(true);
+ mStackScroller.addContainerView(row);
+
+ // speed bump is set to 0
+ assertEquals(0, mStackScroller.getSpeedBumpIndex());
+ }
+
+ @Test
+ public void testRemoveNotificationUpdatesSpeedBump() {
+ // initial state == -1
+ assertEquals(-1, mStackScroller.getSpeedBumpIndex());
+
+ // add 3 notification that are after the speed bump
+ ExpandableNotificationRow row = mock(ExpandableNotificationRow.class);
+ NotificationEntry entry = mock(NotificationEntry.class);
+ when(row.getEntry()).thenReturn(entry);
+ when(entry.isAmbient()).thenReturn(false);
+ mStackScroller.addContainerView(row);
+
+ // speed bump is 1
+ assertEquals(1, mStackScroller.getSpeedBumpIndex());
+
+ // remove the notification that was before the speed bump
+ mStackScroller.removeContainerView(row);
+
+ // speed bump is now 0
+ assertEquals(0, mStackScroller.getSpeedBumpIndex());
+ }
+
private void setBarStateForTest(int state) {
// Can't inject this through the listener or we end up on the actual implementation
// rather than the mock because the spy just coppied the anonymous inner /shruggie.
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollerControllerTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollerControllerTest.java
index 83d6ac904bfe..32c682878c28 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollerControllerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollerControllerTest.java
@@ -16,6 +16,9 @@
package com.android.systemui.statusbar.notification.stack;
+import static com.android.systemui.statusbar.StatusBarState.KEYGUARD;
+import static com.android.systemui.statusbar.StatusBarState.SHADE;
+
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.ArgumentMatchers.anyInt;
import static org.mockito.ArgumentMatchers.argThat;
@@ -26,6 +29,7 @@ import static org.mockito.Mockito.reset;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
+import android.content.res.Resources;
import android.metrics.LogMaker;
import android.testing.AndroidTestingRunner;
@@ -36,6 +40,7 @@ import com.android.internal.logging.nano.MetricsProto;
import com.android.systemui.SysuiTestCase;
import com.android.systemui.colorextraction.SysuiColorExtractor;
import com.android.systemui.media.KeyguardMediaController;
+import com.android.systemui.plugins.FalsingManager;
import com.android.systemui.plugins.statusbar.NotificationMenuRowPlugin;
import com.android.systemui.plugins.statusbar.NotificationMenuRowPlugin.OnMenuEventListener;
import com.android.systemui.plugins.statusbar.StatusBarStateController;
@@ -43,10 +48,13 @@ import com.android.systemui.statusbar.NotificationLockscreenUserManager;
import com.android.systemui.statusbar.NotificationLockscreenUserManager.UserChangedListener;
import com.android.systemui.statusbar.SysuiStatusBarStateController;
import com.android.systemui.statusbar.notification.DynamicPrivacyController;
+import com.android.systemui.statusbar.notification.collection.legacy.NotificationGroupManagerLegacy;
import com.android.systemui.statusbar.notification.row.ExpandableNotificationRow;
import com.android.systemui.statusbar.notification.row.NotificationGutsManager;
import com.android.systemui.statusbar.phone.HeadsUpManagerPhone;
import com.android.systemui.statusbar.phone.KeyguardBypassController;
+import com.android.systemui.statusbar.phone.ScrimController;
+import com.android.systemui.statusbar.phone.StatusBar;
import com.android.systemui.statusbar.policy.ConfigurationController;
import com.android.systemui.statusbar.policy.ZenModeController;
import com.android.systemui.tuner.TunerService;
@@ -54,8 +62,10 @@ import com.android.systemui.tuner.TunerService;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
+import org.mockito.Answers;
import org.mockito.ArgumentCaptor;
import org.mockito.ArgumentMatcher;
+import org.mockito.Captor;
import org.mockito.Mock;
import org.mockito.MockitoAnnotations;
@@ -94,6 +104,25 @@ public class NotificationStackScrollerControllerTest extends SysuiTestCase {
private NotificationLockscreenUserManager mNotificationLockscreenUserManager;
@Mock
private MetricsLogger mMetricsLogger;
+ @Mock
+ private FalsingManager mFalsingManager;
+ @Mock
+ private NotificationSectionsManager mNotificationSectionsManager;
+ @Mock
+ private Resources mResources;
+ @Mock(answer = Answers.RETURNS_SELF)
+ private NotificationSwipeHelper.Builder mNotificationSwipeHelperBuilder;
+ @Mock
+ private NotificationSwipeHelper mNotificationSwipeHelper;
+ @Mock
+ private StatusBar mStatusBar;
+ @Mock
+ private ScrimController mScrimController;
+ @Mock
+ private NotificationGroupManagerLegacy mLegacyGroupManager;
+
+ @Captor
+ ArgumentCaptor<StatusBarStateController.StateListener> mStateListenerArgumentCaptor;
private NotificationStackScrollLayoutController mController;
@@ -101,6 +130,8 @@ public class NotificationStackScrollerControllerTest extends SysuiTestCase {
public void setUp() {
MockitoAnnotations.initMocks(this);
+ when(mNotificationSwipeHelperBuilder.build()).thenReturn(mNotificationSwipeHelper);
+
mController = new NotificationStackScrollLayoutController(
true,
mNotificationGutsManager,
@@ -115,7 +146,15 @@ public class NotificationStackScrollerControllerTest extends SysuiTestCase {
mZenModeController,
mColorExtractor,
mNotificationLockscreenUserManager,
- mMetricsLogger
+ mMetricsLogger,
+ mFalsingManager,
+ mNotificationSectionsManager,
+ mResources,
+ mNotificationSwipeHelperBuilder,
+ mStatusBar,
+ mScrimController,
+ mLegacyGroupManager,
+ mLegacyGroupManager
);
when(mNotificationStackScrollLayout.isAttachedToWindow()).thenReturn(true);
@@ -153,32 +192,49 @@ public class NotificationStackScrollerControllerTest extends SysuiTestCase {
}
@Test
- public void testUpdateEmptyShadeView_notificationsVisible() {
+ public void testUpdateEmptyShadeView_notificationsVisible_zenHiding() {
when(mZenModeController.areNotificationsHiddenInShade()).thenReturn(true);
mController.attach(mNotificationStackScrollLayout);
+ verify(mSysuiStatusBarStateController).addCallback(
+ mStateListenerArgumentCaptor.capture(), anyInt());
+ StatusBarStateController.StateListener stateListener =
+ mStateListenerArgumentCaptor.getValue();
- mController.updateEmptyShadeView(true /* visible */);
+ setupShowEmptyShadeViewState(stateListener, true);
+ reset(mNotificationStackScrollLayout);
+ mController.updateShowEmptyShadeView();
verify(mNotificationStackScrollLayout).updateEmptyShadeView(
true /* visible */,
+
true /* notifVisibleInShade */);
+
+ setupShowEmptyShadeViewState(stateListener, false);
reset(mNotificationStackScrollLayout);
- mController.updateEmptyShadeView(false /* visible */);
+ mController.updateShowEmptyShadeView();
verify(mNotificationStackScrollLayout).updateEmptyShadeView(
false /* visible */,
true /* notifVisibleInShade */);
}
@Test
- public void testUpdateEmptyShadeView_notificationsHidden() {
+ public void testUpdateEmptyShadeView_notificationsHidden_zenNotHiding() {
when(mZenModeController.areNotificationsHiddenInShade()).thenReturn(false);
mController.attach(mNotificationStackScrollLayout);
+ verify(mSysuiStatusBarStateController).addCallback(
+ mStateListenerArgumentCaptor.capture(), anyInt());
+ StatusBarStateController.StateListener stateListener =
+ mStateListenerArgumentCaptor.getValue();
- mController.updateEmptyShadeView(true /* visible */);
+ setupShowEmptyShadeViewState(stateListener, true);
+ reset(mNotificationStackScrollLayout);
+ mController.updateShowEmptyShadeView();
verify(mNotificationStackScrollLayout).updateEmptyShadeView(
true /* visible */,
false /* notifVisibleInShade */);
+
+ setupShowEmptyShadeViewState(stateListener, false);
reset(mNotificationStackScrollLayout);
- mController.updateEmptyShadeView(false /* visible */);
+ mController.updateShowEmptyShadeView();
verify(mNotificationStackScrollLayout).updateEmptyShadeView(
false /* visible */,
false /* notifVisibleInShade */);
@@ -206,15 +262,12 @@ public class NotificationStackScrollerControllerTest extends SysuiTestCase {
public void testOnStatePostChange_verifyIfProfileIsPublic() {
when(mNotificationLockscreenUserManager.isAnyProfilePublicMode()).thenReturn(true);
- ArgumentCaptor<StatusBarStateController.StateListener> stateListenerArgumentCaptor =
- ArgumentCaptor.forClass(StatusBarStateController.StateListener.class);
-
mController.attach(mNotificationStackScrollLayout);
verify(mSysuiStatusBarStateController).addCallback(
- stateListenerArgumentCaptor.capture(), anyInt());
+ mStateListenerArgumentCaptor.capture(), anyInt());
StatusBarStateController.StateListener stateListener =
- stateListenerArgumentCaptor.getValue();
+ mStateListenerArgumentCaptor.getValue();
stateListener.onStatePostChange();
verify(mNotificationStackScrollLayout).updateSensitiveness(false, true);
@@ -233,7 +286,7 @@ public class NotificationStackScrollerControllerTest extends SysuiTestCase {
ArgumentCaptor.forClass(OnMenuEventListener.class);
mController.attach(mNotificationStackScrollLayout);
- verify(mNotificationStackScrollLayout).setMenuEventListener(
+ verify(mNotificationSwipeHelperBuilder).setOnMenuEventListener(
onMenuEventListenerArgumentCaptor.capture());
OnMenuEventListener onMenuEventListener = onMenuEventListenerArgumentCaptor.getValue();
@@ -255,7 +308,7 @@ public class NotificationStackScrollerControllerTest extends SysuiTestCase {
ArgumentCaptor.forClass(OnMenuEventListener.class);
mController.attach(mNotificationStackScrollLayout);
- verify(mNotificationStackScrollLayout).setMenuEventListener(
+ verify(mNotificationSwipeHelperBuilder).setOnMenuEventListener(
onMenuEventListenerArgumentCaptor.capture());
OnMenuEventListener onMenuEventListener = onMenuEventListenerArgumentCaptor.getValue();
@@ -271,6 +324,20 @@ public class NotificationStackScrollerControllerTest extends SysuiTestCase {
return argThat(new LogMatcher(category, type));
}
+ private void setupShowEmptyShadeViewState(
+ StatusBarStateController.StateListener statusBarStateListener,
+ boolean toShow) {
+ if (toShow) {
+ statusBarStateListener.onStateChanged(SHADE);
+ mController.setQsExpanded(false);
+ mController.getView().removeAllViews();
+ } else {
+ statusBarStateListener.onStateChanged(KEYGUARD);
+ mController.setQsExpanded(true);
+ mController.getView().addContainerView(mock(ExpandableNotificationRow.class));
+ }
+ }
+
static class LogMatcher implements ArgumentMatcher<LogMaker> {
private int mCategory, mType;
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/stack/NotificationSwipeHelperTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/stack/NotificationSwipeHelperTest.java
index 323d8bd9d2e6..0faf5d478116 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/stack/NotificationSwipeHelperTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/stack/NotificationSwipeHelperTest.java
@@ -35,6 +35,7 @@ import android.testing.AndroidTestingRunner;
import android.testing.TestableLooper;
import android.view.MotionEvent;
import android.view.View;
+import android.view.ViewConfiguration;
import androidx.test.filters.SmallTest;
@@ -78,7 +79,8 @@ public class NotificationSwipeHelperTest extends SysuiTestCase {
mCallback = mock(NotificationSwipeHelper.NotificationCallback.class);
mListener = mock(NotificationMenuRowPlugin.OnMenuEventListener.class);
mSwipeHelper = spy(new NotificationSwipeHelper(
- SwipeHelper.X, mCallback, mContext, mListener, new FalsingManagerFake()));
+ mContext.getResources(), ViewConfiguration.get(mContext),
+ new FalsingManagerFake(), SwipeHelper.X, mCallback, mListener));
mView = mock(View.class);
mEvent = mock(MotionEvent.class);
mMenuRow = mock(NotificationMenuRowPlugin.class);
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/HeadsUpManagerPhoneTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/HeadsUpManagerPhoneTest.java
index 2239b1b96ac8..57020eb08a7f 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/HeadsUpManagerPhoneTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/HeadsUpManagerPhoneTest.java
@@ -36,6 +36,7 @@ import com.android.systemui.statusbar.AlertingNotificationManagerTest;
import com.android.systemui.statusbar.NotificationShadeWindowController;
import com.android.systemui.statusbar.notification.collection.NotificationEntry;
import com.android.systemui.statusbar.notification.collection.NotificationEntryBuilder;
+import com.android.systemui.statusbar.notification.collection.legacy.NotificationGroupManagerLegacy;
import com.android.systemui.statusbar.notification.collection.legacy.VisualStabilityManager;
import com.android.systemui.statusbar.policy.AccessibilityManagerWrapper;
import com.android.systemui.statusbar.policy.ConfigurationController;
@@ -57,7 +58,7 @@ public class HeadsUpManagerPhoneTest extends AlertingNotificationManagerTest {
private HeadsUpManagerPhone mHeadsUpManager;
- @Mock private NotificationGroupManager mGroupManager;
+ @Mock private NotificationGroupManagerLegacy mGroupManager;
@Mock private View mNotificationShadeWindowView;
@Mock private VisualStabilityManager mVSManager;
@Mock private StatusBar mBar;
@@ -69,7 +70,7 @@ public class HeadsUpManagerPhoneTest extends AlertingNotificationManagerTest {
private final class TestableHeadsUpManagerPhone extends HeadsUpManagerPhone {
TestableHeadsUpManagerPhone(
Context context,
- NotificationGroupManager groupManager,
+ NotificationGroupManagerLegacy groupManager,
VisualStabilityManager vsManager,
StatusBarStateController statusBarStateController,
KeyguardBypassController keyguardBypassController,
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/NotificationGroupAlertTransferHelperTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/NotificationGroupAlertTransferHelperTest.java
index 885dff39f7b3..2ece8be8d332 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/NotificationGroupAlertTransferHelperTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/NotificationGroupAlertTransferHelperTest.java
@@ -42,6 +42,7 @@ import com.android.systemui.plugins.statusbar.StatusBarStateController;
import com.android.systemui.statusbar.notification.NotificationEntryListener;
import com.android.systemui.statusbar.notification.NotificationEntryManager;
import com.android.systemui.statusbar.notification.collection.NotificationEntry;
+import com.android.systemui.statusbar.notification.collection.legacy.NotificationGroupManagerLegacy;
import com.android.systemui.statusbar.notification.people.PeopleNotificationIdentifier;
import com.android.systemui.statusbar.notification.row.NotifBindPipeline.BindCallback;
import com.android.systemui.statusbar.notification.row.RowContentBindParams;
@@ -68,7 +69,7 @@ public class NotificationGroupAlertTransferHelperTest extends SysuiTestCase {
@Rule public MockitoRule rule = MockitoJUnit.rule();
private NotificationGroupAlertTransferHelper mGroupAlertTransferHelper;
- private NotificationGroupManager mGroupManager;
+ private NotificationGroupManagerLegacy mGroupManager;
private HeadsUpManager mHeadsUpManager;
@Mock private NotificationEntryManager mNotificationEntryManager;
@Mock private RowContentBindStage mBindStage;
@@ -88,10 +89,10 @@ public class NotificationGroupAlertTransferHelperTest extends SysuiTestCase {
when(mNotificationEntryManager.getPendingNotificationsIterator())
.thenReturn(mPendingEntries.values());
- mGroupManager = new NotificationGroupManager(
+ mGroupManager = new NotificationGroupManagerLegacy(
mock(StatusBarStateController.class),
() -> mock(PeopleNotificationIdentifier.class));
- mDependency.injectTestDependency(NotificationGroupManager.class, mGroupManager);
+ mDependency.injectTestDependency(NotificationGroupManagerLegacy.class, mGroupManager);
mGroupManager.setHeadsUpManager(mHeadsUpManager);
when(mBindStage.getStageParams(any())).thenReturn(new RowContentBindParams());
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/NotificationGroupManagerTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/NotificationGroupManagerLegacyTest.java
index 5a6f74a4c6aa..0aa009134440 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/NotificationGroupManagerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/NotificationGroupManagerLegacyTest.java
@@ -33,6 +33,7 @@ import com.android.systemui.SysuiTestCase;
import com.android.systemui.bubbles.BubbleController;
import com.android.systemui.plugins.statusbar.StatusBarStateController;
import com.android.systemui.statusbar.notification.collection.NotificationEntry;
+import com.android.systemui.statusbar.notification.collection.legacy.NotificationGroupManagerLegacy;
import com.android.systemui.statusbar.notification.people.PeopleNotificationIdentifier;
import com.android.systemui.statusbar.policy.HeadsUpManager;
@@ -47,11 +48,11 @@ import org.mockito.junit.MockitoRule;
@SmallTest
@RunWith(AndroidTestingRunner.class)
@TestableLooper.RunWithLooper
-public class NotificationGroupManagerTest extends SysuiTestCase {
+public class NotificationGroupManagerLegacyTest extends SysuiTestCase {
@Rule
public MockitoRule rule = MockitoJUnit.rule();
- private NotificationGroupManager mGroupManager;
+ private NotificationGroupManagerLegacy mGroupManager;
private final NotificationGroupTestHelper mGroupTestHelper =
new NotificationGroupTestHelper(mContext);
@@ -64,7 +65,7 @@ public class NotificationGroupManagerTest extends SysuiTestCase {
}
private void initializeGroupManager() {
- mGroupManager = new NotificationGroupManager(
+ mGroupManager = new NotificationGroupManagerLegacy(
mock(StatusBarStateController.class),
() -> mock(PeopleNotificationIdentifier.class));
mGroupManager.setHeadsUpManager(mHeadsUpManager);
@@ -78,7 +79,7 @@ public class NotificationGroupManagerTest extends SysuiTestCase {
mGroupManager.onEntryAdded(summaryEntry);
mGroupManager.onEntryAdded(childEntry);
- assertTrue(mGroupManager.isOnlyChildInGroup(childEntry.getSbn()));
+ assertTrue(mGroupManager.isOnlyChildInGroup(childEntry));
}
@Test
@@ -90,7 +91,7 @@ public class NotificationGroupManagerTest extends SysuiTestCase {
mGroupManager.onEntryAdded(childEntry);
mGroupManager.onEntryAdded(mGroupTestHelper.createChildNotification());
- assertTrue(mGroupManager.isChildInGroupWithSummary(childEntry.getSbn()));
+ assertTrue(mGroupManager.isChildInGroup(childEntry));
}
@Test
@@ -102,8 +103,8 @@ public class NotificationGroupManagerTest extends SysuiTestCase {
mGroupManager.onEntryAdded(childEntry);
mGroupManager.onEntryAdded(mGroupTestHelper.createChildNotification());
- assertTrue(mGroupManager.isSummaryOfGroup(summaryEntry.getSbn()));
- assertEquals(summaryEntry, mGroupManager.getGroupSummary(childEntry.getSbn()));
+ assertTrue(mGroupManager.isGroupSummary(summaryEntry));
+ assertEquals(summaryEntry, mGroupManager.getGroupSummary(childEntry));
}
@Test
@@ -116,7 +117,7 @@ public class NotificationGroupManagerTest extends SysuiTestCase {
mGroupManager.onEntryRemoved(childEntry);
- assertFalse(mGroupManager.isChildInGroupWithSummary(childEntry.getSbn()));
+ assertFalse(mGroupManager.isChildInGroup(childEntry));
}
@Test
@@ -129,8 +130,8 @@ public class NotificationGroupManagerTest extends SysuiTestCase {
mGroupManager.onEntryRemoved(summaryEntry);
- assertNull(mGroupManager.getGroupSummary(childEntry.getSbn()));
- assertFalse(mGroupManager.isSummaryOfGroup(summaryEntry.getSbn()));
+ assertNull(mGroupManager.getGroupSummary(childEntry));
+ assertFalse(mGroupManager.isGroupSummary(summaryEntry));
}
@Test
@@ -146,7 +147,7 @@ public class NotificationGroupManagerTest extends SysuiTestCase {
// Child entries that are heads upped should be considered separate groups visually even if
// they are the same group logically
- assertEquals(childEntry, mGroupManager.getGroupSummary(childEntry.getSbn()));
- assertEquals(summaryEntry, mGroupManager.getLogicalGroupSummary(childEntry.getSbn()));
+ assertEquals(childEntry, mGroupManager.getGroupSummary(childEntry));
+ assertEquals(summaryEntry, mGroupManager.getLogicalGroupSummary(childEntry));
}
}
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 c9e9d94d8a79..7ee27c9a8aab 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
@@ -52,7 +52,9 @@ import com.android.internal.logging.testing.UiEventLoggerFake;
import com.android.internal.util.LatencyTracker;
import com.android.keyguard.KeyguardClockSwitch;
import com.android.keyguard.KeyguardClockSwitchController;
+import com.android.keyguard.KeyguardStatusView;
import com.android.keyguard.KeyguardUpdateMonitor;
+import com.android.keyguard.dagger.KeyguardStatusViewComponent;
import com.android.systemui.R;
import com.android.systemui.SysuiTestCase;
import com.android.systemui.classifier.FalsingManagerFake;
@@ -60,7 +62,6 @@ import com.android.systemui.doze.DozeLog;
import com.android.systemui.media.MediaHierarchyManager;
import com.android.systemui.plugins.FalsingManager;
import com.android.systemui.statusbar.CommandQueue;
-import com.android.systemui.statusbar.FlingAnimationUtils;
import com.android.systemui.statusbar.KeyguardAffordanceView;
import com.android.systemui.statusbar.NotificationLockscreenUserManager;
import com.android.systemui.statusbar.NotificationShelfController;
@@ -72,13 +73,14 @@ import com.android.systemui.statusbar.notification.ConversationNotificationManag
import com.android.systemui.statusbar.notification.DynamicPrivacyController;
import com.android.systemui.statusbar.notification.NotificationEntryManager;
import com.android.systemui.statusbar.notification.NotificationWakeUpCoordinator;
+import com.android.systemui.statusbar.notification.collection.legacy.NotificationGroupManagerLegacy;
import com.android.systemui.statusbar.notification.stack.NotificationRoundnessManager;
import com.android.systemui.statusbar.notification.stack.NotificationStackScrollLayout;
import com.android.systemui.statusbar.notification.stack.NotificationStackScrollLayoutController;
import com.android.systemui.statusbar.policy.ConfigurationController;
import com.android.systemui.statusbar.policy.KeyguardStateController;
-import com.android.systemui.statusbar.policy.ZenModeController;
import com.android.systemui.util.InjectionInflationController;
+import com.android.wm.shell.animation.FlingAnimationUtils;
import org.junit.Before;
import org.junit.Test;
@@ -110,15 +112,13 @@ public class NotificationPanelViewTest extends SysuiTestCase {
@Mock
private ViewGroup mBigClockContainer;
@Mock
- private ScrimController mScrimController;
- @Mock
private NotificationIconAreaController mNotificationAreaController;
@Mock
private HeadsUpManagerPhone mHeadsUpManager;
@Mock
private NotificationShelfController mNotificationShelfController;
@Mock
- private NotificationGroupManager mGroupManager;
+ private NotificationGroupManagerLegacy mGroupManager;
@Mock
private KeyguardStatusBarView mKeyguardStatusBar;
@Mock
@@ -174,8 +174,6 @@ public class NotificationPanelViewTest extends SysuiTestCase {
private KeyguardClockSwitch mKeyguardClockSwitch;
private PanelViewController.TouchHandler mTouchHandler;
@Mock
- private ZenModeController mZenModeController;
- @Mock
private ConfigurationController mConfigurationController;
@Mock
private MediaHierarchyManager mMediaHiearchyManager;
@@ -186,6 +184,10 @@ public class NotificationPanelViewTest extends SysuiTestCase {
@Mock
private StatusBarKeyguardViewManager mStatusBarKeyguardViewManager;
@Mock
+ private KeyguardStatusViewComponent.Factory mKeyguardStatusViewComponentFactory;
+ @Mock
+ private KeyguardStatusViewComponent mKeyguardStatusViewComponent;
+ @Mock
private KeyguardClockSwitchController mKeyguardClockSwitchController;
@Mock
private NotificationStackScrollLayoutController mNotificationStackScrollLayoutController;
@@ -217,6 +219,8 @@ public class NotificationPanelViewTest extends SysuiTestCase {
when(mKeyguardBottomArea.getRightView()).thenReturn(mock(KeyguardAffordanceView.class));
when(mView.findViewById(R.id.big_clock_container)).thenReturn(mBigClockContainer);
when(mView.findViewById(R.id.qs_frame)).thenReturn(mQsFrame);
+ when(mView.findViewById(R.id.keyguard_status_view))
+ .thenReturn(mock(KeyguardStatusView.class));
FlingAnimationUtils.Builder flingAnimationUtilsBuilder = new FlingAnimationUtils.Builder(
mDisplayMetrics);
@@ -238,7 +242,12 @@ public class NotificationPanelViewTest extends SysuiTestCase {
mock(NotificationRoundnessManager.class),
mStatusBarStateController,
new FalsingManagerFake());
+ when(mKeyguardStatusViewComponentFactory.build(any()))
+ .thenReturn(mKeyguardStatusViewComponent);
+ when(mKeyguardStatusViewComponent.getKeyguardClockSwitchController())
+ .thenReturn(mKeyguardClockSwitchController);
mNotificationPanelViewController = new NotificationPanelViewController(mView,
+ mResources,
mInjectionInflationController,
coordinator, expansionHandler, mDynamicPrivacyController, mKeyguardBypassController,
mFalsingManager, mShadeController,
@@ -246,18 +255,17 @@ public class NotificationPanelViewTest extends SysuiTestCase {
mKeyguardStateController, mStatusBarStateController, mDozeLog,
mDozeParameters, mCommandQueue, mVibratorHelper,
mLatencyTracker, mPowerManager, mAccessibilityManager, 0, mUpdateMonitor,
- mMetricsLogger, mActivityManager, mZenModeController, mConfigurationController,
+ mMetricsLogger, mActivityManager, mConfigurationController,
flingAnimationUtilsBuilder, mStatusBarTouchableRegionManager,
mConversationNotificationManager, mMediaHiearchyManager,
mBiometricUnlockController, mStatusBarKeyguardViewManager,
- () -> mKeyguardClockSwitchController,
mNotificationStackScrollLayoutController,
+ mKeyguardStatusViewComponentFactory,
+ mGroupManager,
mNotificationAreaController);
mNotificationPanelViewController.initDependencies(
mStatusBar,
- mGroupManager,
- mNotificationShelfController,
- mScrimController);
+ mNotificationShelfController);
mNotificationPanelViewController.setHeadsUpManager(mHeadsUpManager);
mNotificationPanelViewController.setBar(mPanelBar);
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/NotificationShadeWindowViewTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/NotificationShadeWindowViewTest.java
index c1d51f3beb7d..25af584ed3f8 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/NotificationShadeWindowViewTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/NotificationShadeWindowViewTest.java
@@ -46,6 +46,7 @@ import com.android.systemui.statusbar.notification.DynamicPrivacyController;
import com.android.systemui.statusbar.notification.NotificationEntryManager;
import com.android.systemui.statusbar.notification.NotificationWakeUpCoordinator;
import com.android.systemui.statusbar.notification.stack.NotificationStackScrollLayout;
+import com.android.systemui.statusbar.notification.stack.NotificationStackScrollLayoutController;
import com.android.systemui.statusbar.policy.KeyguardStateController;
import com.android.systemui.tuner.TunerService;
import com.android.systemui.util.InjectionInflationController;
@@ -85,6 +86,7 @@ public class NotificationShadeWindowViewTest extends SysuiTestCase {
@Mock private NotificationShadeDepthController mNotificationShadeDepthController;
@Mock private SuperStatusBarViewFactory mStatusBarViewFactory;
@Mock private NotificationShadeWindowController mNotificationShadeWindowController;
+ @Mock private NotificationStackScrollLayoutController mNotificationStackScrollLayoutController;
@Before
public void setUp() {
@@ -123,11 +125,11 @@ public class NotificationShadeWindowViewTest extends SysuiTestCase {
mNotificationShadeDepthController,
mView,
mNotificationPanelViewController,
- mStatusBarViewFactory);
+ mStatusBarViewFactory,
+ mNotificationStackScrollLayoutController);
mController.setupExpandedStatusBar();
mController.setService(mStatusBar, mNotificationShadeWindowController);
mController.setDragDownHelper(mDragDownHelper);
-
}
@Test
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarKeyguardViewManagerTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarKeyguardViewManagerTest.java
index 2f4511329041..108327341f94 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarKeyguardViewManagerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarKeyguardViewManagerTest.java
@@ -16,6 +16,7 @@
package com.android.systemui.statusbar.phone;
+import static org.mockito.ArgumentMatchers.any;
import static org.mockito.ArgumentMatchers.anyBoolean;
import static org.mockito.ArgumentMatchers.anyFloat;
import static org.mockito.ArgumentMatchers.eq;
@@ -27,7 +28,6 @@ import static org.mockito.Mockito.reset;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
-import android.content.Context;
import android.testing.AndroidTestingRunner;
import android.testing.TestableLooper;
import android.view.View;
@@ -39,14 +39,13 @@ import androidx.test.filters.SmallTest;
import com.android.internal.widget.LockPatternUtils;
import com.android.keyguard.KeyguardUpdateMonitor;
import com.android.keyguard.ViewMediatorCallback;
+import com.android.keyguard.dagger.KeyguardBouncerComponent;
import com.android.systemui.SysuiTestCase;
-import com.android.systemui.classifier.FalsingManagerFake;
import com.android.systemui.dock.DockManager;
import com.android.systemui.keyguard.DismissCallbackRegistry;
import com.android.systemui.keyguard.FaceAuthScreenBrightnessController;
import com.android.systemui.navigationbar.NavigationModeController;
import com.android.systemui.plugins.ActivityStarter.OnDismissAction;
-import com.android.systemui.plugins.FalsingManager;
import com.android.systemui.statusbar.NotificationMediaManager;
import com.android.systemui.statusbar.NotificationShadeWindowController;
import com.android.systemui.statusbar.SysuiStatusBarStateController;
@@ -71,8 +70,6 @@ public class StatusBarKeyguardViewManagerTest extends SysuiTestCase {
@Mock
private LockPatternUtils mLockPatternUtils;
@Mock
- private KeyguardBouncer mBouncer;
- @Mock
private KeyguardStateController mKeyguardStateController;
@Mock
private StatusBar mStatusBar;
@@ -94,6 +91,13 @@ public class StatusBarKeyguardViewManagerTest extends SysuiTestCase {
private KeyguardBypassController mBypassController;
@Mock
private FaceAuthScreenBrightnessController mFaceAuthScreenBrightnessController;
+ @Mock
+ private KeyguardBouncerComponent.Factory mKeyguardBouncerComponentFactory;
+ @Mock
+ private KeyguardBouncerComponent mKeyguardBouncerComponent;
+ @Mock
+ private KeyguardBouncer mBouncer;
+
private StatusBarKeyguardViewManager mStatusBarKeyguardViewManager;
@Before
@@ -102,7 +106,14 @@ public class StatusBarKeyguardViewManagerTest extends SysuiTestCase {
when(mLockIconContainer.getParent()).thenReturn(mock(ViewGroup.class));
when(mLockIconContainer.animate()).thenReturn(mock(ViewPropertyAnimator.class,
RETURNS_DEEP_STUBS));
- mStatusBarKeyguardViewManager = new TestableStatusBarKeyguardViewManager(
+
+ when(mKeyguardBouncerComponentFactory.build(
+ any(ViewGroup.class),
+ any(KeyguardBouncer.BouncerExpansionCallback.class)))
+ .thenReturn(mKeyguardBouncerComponent);
+ when(mKeyguardBouncerComponent.createKeyguardBouncer()).thenReturn(mBouncer);
+
+ mStatusBarKeyguardViewManager = new StatusBarKeyguardViewManager(
getContext(),
mViewMediatorCallback,
mLockPatternUtils,
@@ -113,12 +124,12 @@ public class StatusBarKeyguardViewManagerTest extends SysuiTestCase {
mock(DockManager.class),
mock(NotificationShadeWindowController.class),
mKeyguardStateController,
- mFaceAuthScreenBrightnessController,
- mock(NotificationMediaManager.class));
+ Optional.of(mFaceAuthScreenBrightnessController),
+ mock(NotificationMediaManager.class),
+ mKeyguardBouncerComponentFactory);
mStatusBarKeyguardViewManager.registerStatusBar(mStatusBar, mContainer,
- mNotificationPanelView, mBiometrucUnlockController, mDismissCallbackRegistry,
- mLockIconContainer, mNotificationContainer, mBypassController,
- new FalsingManagerFake());
+ mNotificationPanelView, mBiometrucUnlockController,
+ mLockIconContainer, mNotificationContainer, mBypassController);
mStatusBarKeyguardViewManager.show(null);
}
@@ -267,38 +278,4 @@ public class StatusBarKeyguardViewManagerTest extends SysuiTestCase {
verify(action).onDismiss();
verify(cancelAction, never()).run();
}
-
- private class TestableStatusBarKeyguardViewManager extends StatusBarKeyguardViewManager {
-
- public TestableStatusBarKeyguardViewManager(Context context,
- ViewMediatorCallback callback,
- LockPatternUtils lockPatternUtils,
- SysuiStatusBarStateController sysuiStatusBarStateController,
- ConfigurationController configurationController,
- KeyguardUpdateMonitor keyguardUpdateMonitor,
- NavigationModeController navigationModeController,
- DockManager dockManager,
- NotificationShadeWindowController notificationShadeWindowController,
- KeyguardStateController keyguardStateController,
- FaceAuthScreenBrightnessController faceAuthScreenBrightnessController,
- NotificationMediaManager notificationMediaManager) {
- super(context, callback, lockPatternUtils, sysuiStatusBarStateController,
- configurationController, keyguardUpdateMonitor, navigationModeController,
- dockManager, notificationShadeWindowController, keyguardStateController,
- Optional.of(faceAuthScreenBrightnessController), notificationMediaManager);
- }
-
- @Override
- public void registerStatusBar(StatusBar statusBar, ViewGroup container,
- NotificationPanelViewController notificationPanelViewController,
- BiometricUnlockController fingerprintUnlockController,
- DismissCallbackRegistry dismissCallbackRegistry,
- ViewGroup lockIconContainer, View notificationContainer,
- KeyguardBypassController bypassController, FalsingManager falsingManager) {
- super.registerStatusBar(statusBar, container, notificationPanelViewController,
- fingerprintUnlockController, dismissCallbackRegistry, lockIconContainer,
- notificationContainer, bypassController, falsingManager);
- mBouncer = StatusBarKeyguardViewManagerTest.this.mBouncer;
- }
- }
}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarNotificationActivityStarterTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarNotificationActivityStarterTest.java
index 3f631b1f6282..792637d8479b 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarNotificationActivityStarterTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarNotificationActivityStarterTest.java
@@ -67,9 +67,9 @@ import com.android.systemui.statusbar.StatusBarState;
import com.android.systemui.statusbar.notification.ActivityLaunchAnimator;
import com.android.systemui.statusbar.notification.NotificationActivityStarter;
import com.android.systemui.statusbar.notification.NotificationEntryManager;
-import com.android.systemui.statusbar.notification.collection.NotifCollection;
import com.android.systemui.statusbar.notification.collection.NotifPipeline;
import com.android.systemui.statusbar.notification.collection.NotificationEntry;
+import com.android.systemui.statusbar.notification.collection.legacy.NotificationGroupManagerLegacy;
import com.android.systemui.statusbar.notification.interruption.NotificationInterruptStateProvider;
import com.android.systemui.statusbar.notification.row.ExpandableNotificationRow;
import com.android.systemui.statusbar.notification.row.NotificationTestHelper;
@@ -122,8 +122,6 @@ public class StatusBarNotificationActivityStarterTest extends SysuiTestCase {
private FeatureFlags mFeatureFlags;
@Mock
private NotifPipeline mNotifPipeline;
- @Mock
- private NotifCollection mNotifCollection;
@Mock
private ActivityIntentHelper mActivityIntentHelper;
@@ -187,7 +185,6 @@ public class StatusBarNotificationActivityStarterTest extends SysuiTestCase {
mUiBgExecutor,
mEntryManager,
mNotifPipeline,
- mNotifCollection,
mock(HeadsUpManagerPhone.class),
mActivityStarter,
mClickNotifier,
@@ -198,7 +195,7 @@ public class StatusBarNotificationActivityStarterTest extends SysuiTestCase {
mBubbleController,
() -> mAssistManager,
mRemoteInputManager,
- mock(NotificationGroupManager.class),
+ mock(NotificationGroupManagerLegacy.class),
mock(NotificationLockscreenUserManager.class),
mShadeController,
mKeyguardStateController,
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarRemoteInputCallbackTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarRemoteInputCallbackTest.java
index bf2bd38638ff..6fbbee22a73c 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarRemoteInputCallbackTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarRemoteInputCallbackTest.java
@@ -36,6 +36,7 @@ import com.android.systemui.statusbar.CommandQueue;
import com.android.systemui.statusbar.NotificationLockscreenUserManager;
import com.android.systemui.statusbar.SysuiStatusBarStateController;
import com.android.systemui.statusbar.notification.NotificationEntryManager;
+import com.android.systemui.statusbar.notification.collection.legacy.NotificationGroupManagerLegacy;
import com.android.systemui.statusbar.policy.DeviceProvisionedController;
import com.android.systemui.statusbar.policy.KeyguardStateController;
@@ -72,7 +73,7 @@ public class StatusBarRemoteInputCallbackTest extends SysuiTestCase {
mNotificationLockscreenUserManager);
mRemoteInputCallback = spy(new StatusBarRemoteInputCallback(mContext,
- mock(NotificationGroupManager.class), mNotificationLockscreenUserManager,
+ mock(NotificationGroupManagerLegacy.class), mNotificationLockscreenUserManager,
mKeyguardStateController, mStatusBarStateController, mStatusBarKeyguardViewManager,
mActivityStarter, mShadeController, new CommandQueue(mContext),
mock(ActionClickLogger.class)));
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarTest.java
index 869fbd813e9e..7d8a62607395 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarTest.java
@@ -96,7 +96,6 @@ import com.android.systemui.plugins.statusbar.StatusBarStateController;
import com.android.systemui.recents.Recents;
import com.android.systemui.recents.ScreenPinningRequest;
import com.android.systemui.shared.plugins.PluginManager;
-import com.android.systemui.stackdivider.SplitScreenController;
import com.android.systemui.statusbar.CommandQueue;
import com.android.systemui.statusbar.KeyguardIndicationController;
import com.android.systemui.statusbar.NotificationListener;
@@ -143,6 +142,7 @@ import com.android.systemui.statusbar.policy.UserSwitcherController;
import com.android.systemui.util.concurrency.FakeExecutor;
import com.android.systemui.util.time.FakeSystemClock;
import com.android.systemui.volume.VolumeComponent;
+import com.android.wm.shell.splitscreen.SplitScreen;
import org.junit.Before;
import org.junit.Test;
@@ -220,7 +220,6 @@ public class StatusBarTest extends SysuiTestCase {
@Mock private NetworkController mNetworkController;
@Mock private VibratorHelper mVibratorHelper;
@Mock private BubbleController mBubbleController;
- @Mock private NotificationGroupManager mGroupManager;
@Mock private NotificationShadeWindowController mNotificationShadeWindowController;
@Mock private NotificationIconAreaController mNotificationIconAreaController;
@Mock private NotificationShadeWindowViewController mNotificationShadeWindowViewController;
@@ -238,7 +237,7 @@ public class StatusBarTest extends SysuiTestCase {
@Mock private StatusBarComponent.Builder mStatusBarComponentBuilder;
@Mock private StatusBarComponent mStatusBarComponent;
@Mock private PluginManager mPluginManager;
- @Mock private SplitScreenController mSplitScreenController;
+ @Mock private SplitScreen mSplitScreen;
@Mock private SuperStatusBarViewFactory mSuperStatusBarViewFactory;
@Mock private LightsOutNotifController mLightsOutNotifController;
@Mock private ViewMediatorCallback mViewMediatorCallback;
@@ -376,7 +375,6 @@ public class StatusBarTest extends SysuiTestCase {
mStatusBarStateController,
mVibratorHelper,
mBubbleController,
- mGroupManager,
mVisualStabilityManager,
mDeviceProvisionedController,
mNavigationBarController,
@@ -397,7 +395,7 @@ public class StatusBarTest extends SysuiTestCase {
Optional.of(mRecents),
mStatusBarComponentBuilderProvider,
mPluginManager,
- Optional.of(mSplitScreenController),
+ Optional.of(mSplitScreen),
mLightsOutNotifController,
mStatusBarNotificationActivityStarterBuilder,
mShadeController,
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/BluetoothControllerImplTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/BluetoothControllerImplTest.java
index fbbfa9611217..3dd36d134cf7 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/BluetoothControllerImplTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/BluetoothControllerImplTest.java
@@ -41,6 +41,7 @@ import com.android.settingslib.bluetooth.LocalBluetoothManager;
import com.android.settingslib.bluetooth.LocalBluetoothProfile;
import com.android.settingslib.bluetooth.LocalBluetoothProfileManager;
import com.android.systemui.SysuiTestCase;
+import com.android.systemui.dump.DumpManager;
import org.junit.Before;
import org.junit.Test;
@@ -58,6 +59,7 @@ public class BluetoothControllerImplTest extends SysuiTestCase {
private CachedBluetoothDeviceManager mMockDeviceManager;
private LocalBluetoothAdapter mMockAdapter;
private TestableLooper mTestableLooper;
+ private DumpManager mMockDumpManager;
private BluetoothControllerImpl mBluetoothControllerImpl;
private List<CachedBluetoothDevice> mDevices;
@@ -75,8 +77,10 @@ public class BluetoothControllerImplTest extends SysuiTestCase {
when(mMockBluetoothManager.getEventManager()).thenReturn(mock(BluetoothEventManager.class));
when(mMockBluetoothManager.getProfileManager())
.thenReturn(mock(LocalBluetoothProfileManager.class));
+ mMockDumpManager = mock(DumpManager.class);
mBluetoothControllerImpl = new BluetoothControllerImpl(mContext,
+ mMockDumpManager,
mTestableLooper.getLooper(),
mTestableLooper.getLooper(),
mMockBluetoothManager);
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/NetworkControllerDataTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/NetworkControllerDataTest.java
index d8aa29e9f766..68992179de59 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/NetworkControllerDataTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/NetworkControllerDataTest.java
@@ -3,6 +3,8 @@ package com.android.systemui.statusbar.policy;
import static android.telephony.AccessNetworkConstants.TRANSPORT_TYPE_WWAN;
import static android.telephony.NetworkRegistrationInfo.DOMAIN_PS;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertTrue;
import static org.mockito.Matchers.anyInt;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.when;
@@ -10,6 +12,7 @@ import static org.mockito.Mockito.when;
import android.net.NetworkCapabilities;
import android.os.Looper;
import android.telephony.NetworkRegistrationInfo;
+import android.telephony.ServiceState;
import android.telephony.TelephonyManager;
import android.test.suitebuilder.annotation.SmallTest;
import android.testing.AndroidTestingRunner;
@@ -259,6 +262,25 @@ public class NetworkControllerDataTest extends NetworkControllerBaseTest {
assertDataNetworkNameEquals(newDataName);
}
+ @Test
+ public void testIsDataInService_true() {
+ setupDefaultSignal();
+ assertTrue(mNetworkController.isMobileDataNetworkInService());
+ }
+
+ @Test
+ public void testIsDataInService_noSignal_false() {
+ assertFalse(mNetworkController.isMobileDataNetworkInService());
+ }
+
+ @Test
+ public void testIsDataInService_notInService_false() {
+ setupDefaultSignal();
+ setVoiceRegState(ServiceState.STATE_OUT_OF_SERVICE);
+ setDataRegState(ServiceState.STATE_OUT_OF_SERVICE);
+ assertFalse(mNetworkController.isMobileDataNetworkInService());
+ }
+
private void testDataActivity(int direction, boolean in, boolean out) {
updateDataActivity(direction);
diff --git a/packages/SystemUI/tests/src/com/android/systemui/util/settings/FakeSettings.java b/packages/SystemUI/tests/src/com/android/systemui/util/settings/FakeSettings.java
index 8cb5f3e65a5e..69764227040b 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/util/settings/FakeSettings.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/util/settings/FakeSettings.java
@@ -53,9 +53,9 @@ public class FakeSettings implements SecureSettings, GlobalSettings, SystemSetti
}
@Override
- public void registerContentObserverForUser(String name, ContentObserver settingsObserver,
- int userHandle) {
- SettingsKey key = new SettingsKey(userHandle, name);
+ public void registerContentObserverForUser(Uri uri, boolean notifyDescendents,
+ ContentObserver settingsObserver, int userHandle) {
+ SettingsKey key = new SettingsKey(userHandle, uri.toString());
mContentObservers.putIfAbsent(key, new ArrayList<>());
List<ContentObserver> observers = mContentObservers.get(key);
observers.add(settingsObserver);
@@ -86,7 +86,7 @@ public class FakeSettings implements SecureSettings, GlobalSettings, SystemSetti
@Override
public String getStringForUser(String name, int userHandle) {
- return mValues.get(new SettingsKey(userHandle, name));
+ return mValues.get(new SettingsKey(userHandle, getUriFor(name).toString()));
}
@Override
@@ -107,7 +107,7 @@ public class FakeSettings implements SecureSettings, GlobalSettings, SystemSetti
@Override
public boolean putStringForUser(String name, String value, String tag, boolean makeDefault,
int userHandle, boolean overrideableByRestore) {
- SettingsKey key = new SettingsKey(userHandle, name);
+ SettingsKey key = new SettingsKey(userHandle, getUriFor(name).toString());
mValues.put(key, value);
Uri uri = getUriFor(name);
diff --git a/packages/SystemUI/tests/src/com/android/systemui/utils/leaks/FakeNetworkController.java b/packages/SystemUI/tests/src/com/android/systemui/utils/leaks/FakeNetworkController.java
index d5ba381bfcac..e7acfae24f30 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/utils/leaks/FakeNetworkController.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/utils/leaks/FakeNetworkController.java
@@ -95,6 +95,11 @@ public class FakeNetworkController extends BaseLeakChecker<SignalCallback>
}
@Override
+ public boolean isMobileDataNetworkInService() {
+ return false;
+ }
+
+ @Override
public int getNumberSubscriptions() {
return 0;
}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/wmshell/WMShellTest.java b/packages/SystemUI/tests/src/com/android/systemui/wmshell/WMShellTest.java
new file mode 100644
index 000000000000..51cc5f175444
--- /dev/null
+++ b/packages/SystemUI/tests/src/com/android/systemui/wmshell/WMShellTest.java
@@ -0,0 +1,118 @@
+/*
+ * 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.wmshell;
+
+import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.when;
+
+import android.test.suitebuilder.annotation.SmallTest;
+
+import androidx.test.runner.AndroidJUnit4;
+
+import com.android.keyguard.KeyguardUpdateMonitor;
+import com.android.keyguard.KeyguardUpdateMonitorCallback;
+import com.android.systemui.SysuiTestCase;
+import com.android.systemui.keyguard.ScreenLifecycle;
+import com.android.systemui.model.SysUiState;
+import com.android.systemui.navigationbar.NavigationModeController;
+import com.android.systemui.onehanded.OneHanded;
+import com.android.systemui.onehanded.OneHandedGestureHandler;
+import com.android.systemui.onehanded.OneHandedTransitionCallback;
+import com.android.systemui.pip.Pip;
+import com.android.systemui.shared.system.ActivityManagerWrapper;
+import com.android.systemui.shared.system.TaskStackChangeListener;
+import com.android.systemui.statusbar.CommandQueue;
+import com.android.systemui.tracing.ProtoTracer;
+import com.android.wm.shell.common.DisplayImeController;
+import com.android.wm.shell.splitscreen.SplitScreen;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.Mock;
+import org.mockito.MockitoAnnotations;
+
+import java.util.Optional;
+
+@SmallTest
+@RunWith(AndroidJUnit4.class)
+public class WMShellTest extends SysuiTestCase {
+
+ WMShell mWMShell;
+ @Mock CommandQueue mCommandQueue;
+ @Mock KeyguardUpdateMonitor mKeyguardUpdateMonitor;
+ @Mock ActivityManagerWrapper mActivityManagerWrapper;
+ @Mock DisplayImeController mDisplayImeController;
+ @Mock NavigationModeController mNavigationModeController;
+ @Mock ScreenLifecycle mScreenLifecycle;
+ @Mock SysUiState mSysUiState;
+ @Mock Pip mPip;
+ @Mock SplitScreen mSplitScreen;
+ @Mock OneHanded mOneHanded;
+ @Mock ProtoTracer mProtoTracer;
+
+ @Before
+ public void setUp() {
+ MockitoAnnotations.initMocks(this);
+ mWMShell = new WMShell(mContext, mCommandQueue, mKeyguardUpdateMonitor,
+ mActivityManagerWrapper, mDisplayImeController, mNavigationModeController,
+ mScreenLifecycle, mSysUiState, Optional.of(mPip), Optional.of(mSplitScreen),
+ Optional.of(mOneHanded), mProtoTracer);
+ }
+
+ @Test
+ public void start_startsMonitorDisplays() {
+ mWMShell.start();
+
+ verify(mDisplayImeController).startMonitorDisplays();
+ }
+
+ @Test
+ public void initPip_registersCommandQueueCallback() {
+ mWMShell.initPip(mPip);
+
+ verify(mCommandQueue).addCallback(any(CommandQueue.Callbacks.class));
+ }
+
+ @Test
+ public void initSplitScreen_registersCallbacks() {
+ mWMShell.initSplitScreen(mSplitScreen);
+
+ verify(mKeyguardUpdateMonitor).registerCallback(any(KeyguardUpdateMonitorCallback.class));
+ verify(mActivityManagerWrapper).registerTaskStackListener(
+ any(TaskStackChangeListener.class));
+ }
+
+ @Test
+ public void initOneHanded_registersCallbacks() {
+ when(mOneHanded.hasOneHandedFeature()).thenReturn(true);
+ mWMShell.initOneHanded(mOneHanded);
+
+ verify(mKeyguardUpdateMonitor).registerCallback(any(KeyguardUpdateMonitorCallback.class));
+ verify(mCommandQueue).addCallback(any(CommandQueue.Callbacks.class));
+ verify(mScreenLifecycle).addObserver(any(ScreenLifecycle.Observer.class));
+ verify(mNavigationModeController).addListener(
+ any(NavigationModeController.ModeChangedListener.class));
+ verify(mActivityManagerWrapper).registerTaskStackListener(
+ any(TaskStackChangeListener.class));
+
+ verify(mOneHanded).registerGestureCallback(any(
+ OneHandedGestureHandler.OneHandedGestureEventCallback.class));
+ verify(mOneHanded).registerTransitionCallback(any(OneHandedTransitionCallback.class));
+ }
+}
diff --git a/services/accessibility/java/com/android/server/accessibility/gestures/EventDispatcher.java b/services/accessibility/java/com/android/server/accessibility/gestures/EventDispatcher.java
index 070626be9f80..df4a52e308b6 100644
--- a/services/accessibility/java/com/android/server/accessibility/gestures/EventDispatcher.java
+++ b/services/accessibility/java/com/android/server/accessibility/gestures/EventDispatcher.java
@@ -256,6 +256,7 @@ class EventDispatcher {
return actionMasked;
}
}
+
/**
* Sends down events to the view hierarchy for all pointers which are not already being
* delivered i.e. pointers that are not yet injected.
@@ -285,6 +286,79 @@ class EventDispatcher {
}
/**
+ * Sends down events to the view hierarchy for all pointers which are not already being
+ * delivered with original down location. i.e. pointers that are not yet injected. The down time
+ * is also replaced by the original one.
+ *
+ *
+ * @param prototype The prototype from which to create the injected events.
+ * @param policyFlags The policy flags associated with the event.
+ */
+ void sendDownForAllNotInjectedPointersWithOriginalDown(MotionEvent prototype, int policyFlags) {
+ // Inject the injected pointers.
+ int pointerIdBits = 0;
+ final int pointerCount = prototype.getPointerCount();
+ final MotionEvent event = computeInjectionDownEvent(prototype);
+ for (int i = 0; i < pointerCount; i++) {
+ final int pointerId = prototype.getPointerId(i);
+ // Do not send event for already delivered pointers.
+ if (!mState.isInjectedPointerDown(pointerId)) {
+ pointerIdBits |= (1 << pointerId);
+ final int action = computeInjectionAction(MotionEvent.ACTION_DOWN, i);
+ sendMotionEvent(
+ event,
+ action,
+ mState.getLastReceivedEvent(),
+ pointerIdBits,
+ policyFlags);
+ }
+ }
+ }
+
+ private MotionEvent computeInjectionDownEvent(MotionEvent prototype) {
+ final int pointerCount = prototype.getPointerCount();
+ if (pointerCount != mState.getReceivedPointerTracker().getReceivedPointerDownCount()) {
+ Slog.w(LOG_TAG, "The pointer count doesn't match the received count.");
+ return MotionEvent.obtain(prototype);
+ }
+ MotionEvent.PointerCoords[] coords = new MotionEvent.PointerCoords[pointerCount];
+ MotionEvent.PointerProperties[] properties =
+ new MotionEvent.PointerProperties[pointerCount];
+ for (int i = 0; i < pointerCount; ++i) {
+ final int pointerId = prototype.getPointerId(i);
+ final float x = mState.getReceivedPointerTracker().getReceivedPointerDownX(pointerId);
+ final float y = mState.getReceivedPointerTracker().getReceivedPointerDownY(pointerId);
+ coords[i] = new MotionEvent.PointerCoords();
+ coords[i].x = x;
+ coords[i].y = y;
+ properties[i] = new MotionEvent.PointerProperties();
+ properties[i].id = pointerId;
+ properties[i].toolType = MotionEvent.TOOL_TYPE_FINGER;
+ }
+ MotionEvent event =
+ MotionEvent.obtain(
+ prototype.getDownTime(),
+ // The event time is used for downTime while sending ACTION_DOWN. We adjust
+ // it to avoid the motion velocity is too fast in the beginning after
+ // Delegating.
+ prototype.getDownTime(),
+ prototype.getAction(),
+ pointerCount,
+ properties,
+ coords,
+ prototype.getMetaState(),
+ prototype.getButtonState(),
+ prototype.getXPrecision(),
+ prototype.getYPrecision(),
+ prototype.getDeviceId(),
+ prototype.getEdgeFlags(),
+ prototype.getSource(),
+ prototype.getFlags());
+ return event;
+ }
+
+ /**
+ *
* Sends up events to the view hierarchy for all pointers which are already being delivered i.e.
* pointers that are injected.
*
diff --git a/services/accessibility/java/com/android/server/accessibility/gestures/MultiFingerSwipe.java b/services/accessibility/java/com/android/server/accessibility/gestures/MultiFingerSwipe.java
index 07e82111d4e5..5b46cb4ab378 100644
--- a/services/accessibility/java/com/android/server/accessibility/gestures/MultiFingerSwipe.java
+++ b/services/accessibility/java/com/android/server/accessibility/gestures/MultiFingerSwipe.java
@@ -294,7 +294,7 @@ class MultiFingerSwipe extends GestureMatcher {
+ Float.toString(mGestureDetectionThresholdPixels));
}
if (getState() == STATE_CLEAR) {
- if (moveDelta < mTouchSlop) {
+ if (moveDelta < (mTargetFingerCount * mTouchSlop)) {
// This still counts as a touch not a swipe.
continue;
} else if (mStrokeBuffers[pointerIndex].size() == 0) {
diff --git a/services/accessibility/java/com/android/server/accessibility/gestures/TouchExplorer.java b/services/accessibility/java/com/android/server/accessibility/gestures/TouchExplorer.java
index b587dd33c4e5..8305be393ab1 100644
--- a/services/accessibility/java/com/android/server/accessibility/gestures/TouchExplorer.java
+++ b/services/accessibility/java/com/android/server/accessibility/gestures/TouchExplorer.java
@@ -594,15 +594,23 @@ public class TouchExplorer extends BaseEventStreamTransformation
if (pointerIndex < 0) {
return;
}
- final float deltaX =
- mReceivedPointerTracker.getReceivedPointerDownX(pointerId)
- - rawEvent.getX(pointerIndex);
- final float deltaY =
- mReceivedPointerTracker.getReceivedPointerDownY(pointerId)
- - rawEvent.getY(pointerIndex);
- final double moveDelta = Math.hypot(deltaX, deltaY);
- if (moveDelta < mTouchSlop) {
- return;
+ // Require both fingers to have moved a certain amount before starting a drag.
+ for (int index = 0; index < event.getPointerCount(); ++index) {
+ int id = event.getPointerId(index);
+ if (!mReceivedPointerTracker.isReceivedPointerDown(id)) {
+ // Something is wrong with the event stream.
+ Slog.e(LOG_TAG, "Invalid pointer id: " + id);
+ }
+ final float deltaX =
+ mReceivedPointerTracker.getReceivedPointerDownX(id)
+ - rawEvent.getX(index);
+ final float deltaY =
+ mReceivedPointerTracker.getReceivedPointerDownY(id)
+ - rawEvent.getY(index);
+ final double moveDelta = Math.hypot(deltaX, deltaY);
+ if (moveDelta < (2 * mTouchSlop)) {
+ return;
+ }
}
}
// More than one pointer so the user is not touch exploring
@@ -612,12 +620,20 @@ public class TouchExplorer extends BaseEventStreamTransformation
if (isDraggingGesture(event)) {
// Two pointers moving in the same direction within
// a given distance perform a drag.
- mState.startDragging();
computeDraggingPointerIdIfNeeded(event);
pointerIdBits = 1 << mDraggingPointerId;
event.setEdgeFlags(mReceivedPointerTracker.getLastReceivedDownEdgeFlags());
- mDispatcher.sendMotionEvent(
- event, ACTION_DOWN, rawEvent, pointerIdBits, policyFlags);
+ MotionEvent downEvent = computeDownEventForDrag(event);
+ if (downEvent != null) {
+ mDispatcher.sendMotionEvent(
+ downEvent, ACTION_DOWN, rawEvent, pointerIdBits, policyFlags);
+ mDispatcher.sendMotionEvent(
+ event, ACTION_MOVE, rawEvent, pointerIdBits, policyFlags);
+ } else {
+ mDispatcher.sendMotionEvent(
+ event, ACTION_DOWN, rawEvent, pointerIdBits, policyFlags);
+ }
+ mState.startDragging();
} else {
// Two pointers moving arbitrary are delegated to the view hierarchy.
mState.startDelegating();
@@ -628,23 +644,20 @@ public class TouchExplorer extends BaseEventStreamTransformation
if (mGestureDetector.isMultiFingerGesturesEnabled()) {
if (mGestureDetector.isTwoFingerPassthroughEnabled()) {
if (event.getPointerCount() == 3) {
- boolean isOnBottomEdge = true;
// If three fingers went down on the bottom edge of the screen, delegate
// immediately.
- final long screenHeight =
- mContext.getResources().getDisplayMetrics().heightPixels;
- for (int i = 0; i < TouchState.MAX_POINTER_COUNT; ++i) {
- if (mReceivedPointerTracker.getReceivedPointerDownY(i)
- < (screenHeight - mEdgeSwipeHeightPixels)) {
- isOnBottomEdge = false;
- }
- }
- if (isOnBottomEdge) {
+ if (allPointersDownOnBottomEdge(event)) {
if (DEBUG) {
Slog.d(LOG_TAG, "Three-finger edge swipe detected.");
}
mState.startDelegating();
- mDispatcher.sendDownForAllNotInjectedPointers(event, policyFlags);
+ if (mState.isTouchExploring()) {
+ mDispatcher.sendDownForAllNotInjectedPointers(event,
+ policyFlags);
+ } else {
+ mDispatcher.sendDownForAllNotInjectedPointersWithOriginalDown(
+ event, policyFlags);
+ }
}
}
}
@@ -1004,6 +1017,65 @@ public class TouchExplorer extends BaseEventStreamTransformation
return distance;
}
+ /**
+ * Creates a down event using the down coordinates of the dragging pointer and other information
+ * from the supplied event. The supplied event's down time is adjusted to reflect the time when
+ * the dragging pointer initially went down.
+ */
+ private MotionEvent computeDownEventForDrag(MotionEvent event) {
+ // Creating a down event only makes sense if we haven't started touch exploring yet.
+ if (mState.isTouchExploring()
+ || mDraggingPointerId == INVALID_POINTER_ID
+ || event == null) {
+ return null;
+ }
+ final float x = mReceivedPointerTracker.getReceivedPointerDownX(mDraggingPointerId);
+ final float y = mReceivedPointerTracker.getReceivedPointerDownY(mDraggingPointerId);
+ final long time = mReceivedPointerTracker.getReceivedPointerDownTime(mDraggingPointerId);
+ MotionEvent.PointerCoords[] coords = new MotionEvent.PointerCoords[1];
+ coords[0] = new MotionEvent.PointerCoords();
+ coords[0].x = x;
+ coords[0].y = y;
+ MotionEvent.PointerProperties[] properties = new MotionEvent.PointerProperties[1];
+ properties[0] = new MotionEvent.PointerProperties();
+ properties[0].id = mDraggingPointerId;
+ properties[0].toolType = MotionEvent.TOOL_TYPE_FINGER;
+ MotionEvent downEvent =
+ MotionEvent.obtain(
+ time,
+ time,
+ ACTION_DOWN,
+ 1,
+ properties,
+ coords,
+ event.getMetaState(),
+ event.getButtonState(),
+ event.getXPrecision(),
+ event.getYPrecision(),
+ event.getDeviceId(),
+ event.getEdgeFlags(),
+ event.getSource(),
+ event.getFlags());
+ event.setDownTime(time);
+ return downEvent;
+ }
+
+ private boolean allPointersDownOnBottomEdge(MotionEvent event) {
+ final long screenHeight =
+ mContext.getResources().getDisplayMetrics().heightPixels;
+ for (int i = 0; i < event.getPointerCount(); ++i) {
+ final int pointerId = event.getPointerId(i);
+ final float pointerDownY = mReceivedPointerTracker.getReceivedPointerDownY(pointerId);
+ if (pointerDownY < (screenHeight - mEdgeSwipeHeightPixels)) {
+ if (DEBUG) {
+ Slog.d(LOG_TAG, "The pointer is not on the bottom edge" + pointerDownY);
+ }
+ return false;
+ }
+ }
+ return true;
+ }
+
public TouchState getState() {
return mState;
}
diff --git a/services/accessibility/java/com/android/server/accessibility/magnification/WindowMagnificationConnectionWrapper.java b/services/accessibility/java/com/android/server/accessibility/magnification/WindowMagnificationConnectionWrapper.java
index 49a85864407b..a401bcd3eabd 100644
--- a/services/accessibility/java/com/android/server/accessibility/magnification/WindowMagnificationConnectionWrapper.java
+++ b/services/accessibility/java/com/android/server/accessibility/magnification/WindowMagnificationConnectionWrapper.java
@@ -19,6 +19,8 @@ package com.android.server.accessibility.magnification;
import static android.os.IBinder.DeathRecipient;
import android.annotation.NonNull;
+import android.annotation.Nullable;
+import android.os.RemoteCallback;
import android.os.RemoteException;
import android.util.Slog;
import android.view.accessibility.IWindowMagnificationConnection;
@@ -47,9 +49,10 @@ class WindowMagnificationConnectionWrapper {
mConnection.asBinder().linkToDeath(deathRecipient, 0);
}
- boolean enableWindowMagnification(int displayId, float scale, float centerX, float centerY) {
+ boolean enableWindowMagnification(int displayId, float scale, float centerX, float centerY,
+ @Nullable RemoteCallback endCallback) {
try {
- mConnection.enableWindowMagnification(displayId, scale, centerX, centerY);
+ mConnection.enableWindowMagnification(displayId, scale, centerX, centerY, endCallback);
} catch (RemoteException e) {
if (DBG) {
Slog.e(TAG, "Error calling enableWindowMagnification()", e);
@@ -71,9 +74,9 @@ class WindowMagnificationConnectionWrapper {
return true;
}
- boolean disableWindowMagnification(int displayId) {
+ boolean disableWindowMagnification(int displayId, @Nullable RemoteCallback endCallback) {
try {
- mConnection.disableWindowMagnification(displayId);
+ mConnection.disableWindowMagnification(displayId, endCallback);
} catch (RemoteException e) {
if (DBG) {
Slog.e(TAG, "Error calling disableWindowMagnification()", e);
diff --git a/services/accessibility/java/com/android/server/accessibility/magnification/WindowMagnificationGestureHandler.java b/services/accessibility/java/com/android/server/accessibility/magnification/WindowMagnificationGestureHandler.java
index 3ee5b28ee338..7d6067c8e1da 100644
--- a/services/accessibility/java/com/android/server/accessibility/magnification/WindowMagnificationGestureHandler.java
+++ b/services/accessibility/java/com/android/server/accessibility/magnification/WindowMagnificationGestureHandler.java
@@ -176,7 +176,7 @@ public class WindowMagnificationGestureHandler extends MagnificationGestureHandl
Slog.i(LOG_TAG, "onDestroy(); delayed = "
+ mDetectingState.toString());
}
- mWindowMagnificationMgr.disableWindowMagnifier(mDisplayId, true);
+ mWindowMagnificationMgr.disableWindowMagnification(mDisplayId, true);
resetToDetectState();
}
@@ -211,14 +211,14 @@ public class WindowMagnificationGestureHandler extends MagnificationGestureHandl
final float scale = MathUtils.constrain(
mWindowMagnificationMgr.getPersistedScale(),
MIN_SCALE, MAX_SCALE);
- mWindowMagnificationMgr.enableWindowMagnifier(mDisplayId, scale, centerX, centerY);
+ mWindowMagnificationMgr.enableWindowMagnification(mDisplayId, scale, centerX, centerY);
}
private void disableWindowMagnifier() {
if (DEBUG_ALL) {
Slog.i(LOG_TAG, "disableWindowMagnifier()");
}
- mWindowMagnificationMgr.disableWindowMagnifier(mDisplayId, false);
+ mWindowMagnificationMgr.disableWindowMagnification(mDisplayId, false);
}
private void toggleMagnification(float centerX, float centerY) {
diff --git a/services/accessibility/java/com/android/server/accessibility/magnification/WindowMagnificationManager.java b/services/accessibility/java/com/android/server/accessibility/magnification/WindowMagnificationManager.java
index ed2b26f24478..d3d56d7f857d 100644
--- a/services/accessibility/java/com/android/server/accessibility/magnification/WindowMagnificationManager.java
+++ b/services/accessibility/java/com/android/server/accessibility/magnification/WindowMagnificationManager.java
@@ -24,6 +24,7 @@ import android.content.IntentFilter;
import android.graphics.Rect;
import android.os.Binder;
import android.os.IBinder;
+import android.os.RemoteCallback;
import android.os.RemoteException;
import android.provider.Settings;
import android.util.MathUtils;
@@ -73,7 +74,7 @@ public class WindowMagnificationManager implements
public void onReceive(Context context, Intent intent) {
final int displayId = context.getDisplayId();
removeMagnificationButton(displayId);
- disableWindowMagnification(displayId);
+ disableWindowMagnification(displayId, false);
}
};
@@ -84,6 +85,7 @@ public class WindowMagnificationManager implements
/**
* Sets {@link IWindowMagnificationConnection}.
+ *
* @param connection {@link IWindowMagnificationConnection}
*/
public void setConnection(@Nullable IWindowMagnificationConnection connection) {
@@ -124,7 +126,6 @@ public class WindowMagnificationManager implements
}
/**
- *
* @return {@code true} if {@link IWindowMagnificationConnection} is available
*/
public boolean isConnected() {
@@ -136,10 +137,10 @@ public class WindowMagnificationManager implements
/**
* Requests {@link IWindowMagnificationConnection} through
* {@link StatusBarManagerInternal#requestWindowMagnificationConnection(boolean)} and
- * destroys all window magnifiers if necessary.
+ * destroys all window magnifications if necessary.
*
* @param connect {@code true} if needs connection, otherwise set the connection to null and
- * destroy all window magnifiers.
+ * destroy all window magnifications.
* @return {@code true} if {@link IWindowMagnificationConnection} state is going to change.
*/
public boolean requestConnection(boolean connect) {
@@ -171,7 +172,7 @@ public class WindowMagnificationManager implements
private void disableAllWindowMagnifiers() {
for (int i = 0; i < mWindowMagnifiers.size(); i++) {
final WindowMagnifier magnifier = mWindowMagnifiers.valueAt(i);
- magnifier.disable();
+ magnifier.disableWindowMagnificationInternal(null);
}
mWindowMagnifiers.clear();
}
@@ -187,12 +188,12 @@ public class WindowMagnificationManager implements
@Override
public boolean processScroll(int displayId, float distanceX, float distanceY) {
- moveWindowMagnifier(displayId, -distanceX, -distanceY);
+ moveWindowMagnification(displayId, -distanceX, -distanceY);
return /* event consumed: */ true;
}
/**
- * Scales the magnified region on the specified display if the window magnifier is enabled.
+ * Scales the magnified region on the specified display if window magnification is initiated.
*
* @param displayId The logical display id.
* @param scale The target scale, must be >= 1
@@ -209,37 +210,69 @@ public class WindowMagnificationManager implements
}
/**
- * Enables the window magnifier with specified center and scale on the specified display.
- * @param displayId The logical display id.
+ * Enables window magnification with specified center and scale on the given display and
+ * animating the transition.
+ *
+ * @param displayId The logical display id.
+ * @param scale The target scale, must be >= 1.
+ * @param centerX The screen-relative X coordinate around which to center,
+ * or {@link Float#NaN} to leave unchanged.
+ * @param centerY The screen-relative Y coordinate around which to center,
+ * or {@link Float#NaN} to leave unchanged.
+ */
+ void enableWindowMagnification(int displayId, float scale, float centerX, float centerY) {
+ enableWindowMagnification(displayId, scale, centerX, centerY, null);
+ }
+
+ /**
+ * Enables window magnification with specified center and scale on the specified display and
+ * animating the transition.
+ *
+ * @param displayId The logical display id.
* @param scale The target scale, must be >= 1.
* @param centerX The screen-relative X coordinate around which to center,
* or {@link Float#NaN} to leave unchanged.
* @param centerY The screen-relative Y coordinate around which to center,
* or {@link Float#NaN} to leave unchanged.
+ * @param endCallback Called when the animation is ended without any interruption or the
+ * window magnifier is disabled already.
*/
- void enableWindowMagnifier(int displayId, float scale, float centerX, float centerY) {
+ void enableWindowMagnification(int displayId, float scale, float centerX, float centerY,
+ @Nullable Runnable endCallback) {
synchronized (mLock) {
WindowMagnifier magnifier = mWindowMagnifiers.get(displayId);
if (magnifier == null) {
magnifier = createWindowMagnifier(displayId);
}
- magnifier.enable(scale, centerX, centerY);
+ magnifier.enableWindowMagnificationInternal(scale, centerX, centerY, endCallback);
}
}
/**
- * Disables the window magnifier on the specified display.
+ * Disables window magnification on the given display.
+ *
+ * @param displayId The logical display id.
+ * @param clear {@true} Clears the state of window magnification.
+ */
+ void disableWindowMagnification(int displayId, boolean clear) {
+ disableWindowMagnification(displayId, clear, null);
+ }
+
+ /**
+ * Disables window magnification on the specified display and animating the transition.
*
* @param displayId The logical display id.
- * @param clear {@true} Clears the state of the window magnifier
+ * @param clear {@true} Clears the state of window magnification.
+ * @param endCallback Called when the animation is ended without any interruption or the
+ * window magnifier is disabled already.
*/
- void disableWindowMagnifier(int displayId, boolean clear) {
+ void disableWindowMagnification(int displayId, boolean clear, Runnable endCallback) {
synchronized (mLock) {
WindowMagnifier magnifier = mWindowMagnifiers.get(displayId);
if (magnifier == null) {
return;
}
- magnifier.disable();
+ magnifier.disableWindowMagnificationInternal(endCallback);
if (clear) {
mWindowMagnifiers.delete(displayId);
}
@@ -264,10 +297,10 @@ public class WindowMagnificationManager implements
}
/**
- * Indicates whether this window magnifier is enabled on specified display.
+ * Indicates whether window magnification is enabled on specified display.
*
* @param displayId The logical display id.
- * @return {@code true} if the window magnifier is enabled.
+ * @return {@code true} if the window magnification is enabled.
*/
boolean isWindowMagnifierEnabled(int displayId) {
synchronized (mLock) {
@@ -323,7 +356,7 @@ public class WindowMagnificationManager implements
}
/**
- * Moves the window magnifier with specified offset.
+ * Moves window magnification on the specified display with the specified offset.
*
* @param displayId The logical display id.
* @param offsetX the amount in pixels to offset the region in the X direction, in current
@@ -331,7 +364,7 @@ public class WindowMagnificationManager implements
* @param offsetY the amount in pixels to offset the region in the Y direction, in current
* screen pixels.
*/
- void moveWindowMagnifier(int displayId, float offsetX, float offsetY) {
+ void moveWindowMagnification(int displayId, float offsetX, float offsetY) {
synchronized (mLock) {
WindowMagnifier magnifier = mWindowMagnifiers.get(displayId);
if (magnifier == null) {
@@ -366,6 +399,7 @@ public class WindowMagnificationManager implements
/**
* Creates the windowMagnifier based on the specified display and stores it.
+ *
* @param displayId logical display id.
*/
@GuardedBy("mLock")
@@ -425,7 +459,8 @@ public class WindowMagnificationManager implements
}
/**
- * A class to manipulate the window magnifier and contains the relevant information.
+ * A class manipulates window magnification per display and contains the magnification
+ * information.
*/
private static class WindowMagnifier {
@@ -434,31 +469,34 @@ public class WindowMagnificationManager implements
private boolean mEnabled;
private final WindowMagnificationManager mWindowMagnificationManager;
- //Records the bounds of window magnifier.
+ //Records the bounds of window magnification.
private final Rect mBounds = new Rect();
//The magnified bounds on the screen.
private final Rect mSourceBounds = new Rect();
+
WindowMagnifier(int displayId, WindowMagnificationManager windowMagnificationManager) {
mDisplayId = displayId;
mWindowMagnificationManager = windowMagnificationManager;
}
@GuardedBy("mLock")
- void enable(float scale, float centerX, float centerY) {
+ void enableWindowMagnificationInternal(float scale, float centerX, float centerY,
+ @Nullable Runnable endCallback) {
if (mEnabled) {
return;
}
final float normScale = MathUtils.constrain(scale, MIN_SCALE, MAX_SCALE);
- if (mWindowMagnificationManager.enableWindowMagnification(mDisplayId, normScale,
- centerX, centerY)) {
+ if (mWindowMagnificationManager.enableWindowMagnificationInternal(mDisplayId, normScale,
+ centerX, centerY, endCallback)) {
mScale = normScale;
mEnabled = true;
}
}
@GuardedBy("mLock")
- void disable() {
- if (mEnabled && mWindowMagnificationManager.disableWindowMagnification(mDisplayId)) {
+ void disableWindowMagnificationInternal(@Nullable Runnable endCallback) {
+ if (mEnabled && mWindowMagnificationManager.disableWindowMagnificationInternal(
+ mDisplayId, endCallback)) {
mEnabled = false;
}
}
@@ -519,19 +557,21 @@ public class WindowMagnificationManager implements
}
}
- private boolean enableWindowMagnification(int displayId, float scale, float centerX,
- float centerY) {
+ private boolean enableWindowMagnificationInternal(int displayId, float scale, float centerX,
+ float centerY, Runnable endCallback) {
return mConnectionWrapper != null && mConnectionWrapper.enableWindowMagnification(
- displayId, scale, centerX, centerY);
+ displayId, scale, centerX, centerY,
+ endCallback != null ? new RemoteCallback(bundle -> endCallback.run()) : null);
}
private boolean setScaleInternal(int displayId, float scale) {
return mConnectionWrapper != null && mConnectionWrapper.setScale(displayId, scale);
}
- private boolean disableWindowMagnification(int displayId) {
+ private boolean disableWindowMagnificationInternal(int displayId, Runnable endCallback) {
return mConnectionWrapper != null && mConnectionWrapper.disableWindowMagnification(
- displayId);
+ displayId,
+ endCallback != null ? new RemoteCallback(bundle -> endCallback.run()) : null);
}
private boolean moveWindowMagnifierInternal(int displayId, float offsetX, float offsetY) {
diff --git a/services/appprediction/java/com/android/server/appprediction/AppPredictionManagerService.java b/services/appprediction/java/com/android/server/appprediction/AppPredictionManagerService.java
index 1c4db1214d3b..59ba82e4616a 100644
--- a/services/appprediction/java/com/android/server/appprediction/AppPredictionManagerService.java
+++ b/services/appprediction/java/com/android/server/appprediction/AppPredictionManagerService.java
@@ -34,6 +34,7 @@ import android.app.prediction.IPredictionManager;
import android.content.Context;
import android.content.pm.ParceledListSlice;
import android.os.Binder;
+import android.os.IBinder;
import android.os.ResultReceiver;
import android.os.ShellCallback;
import android.util.Slog;
@@ -108,9 +109,9 @@ public class AppPredictionManagerService extends
@Override
public void createPredictionSession(@NonNull AppPredictionContext context,
- @NonNull AppPredictionSessionId sessionId) {
- runForUserLocked("createPredictionSession", sessionId,
- (service) -> service.onCreatePredictionSessionLocked(context, sessionId));
+ @NonNull AppPredictionSessionId sessionId, @NonNull IBinder token) {
+ runForUserLocked("createPredictionSession", sessionId, (service) ->
+ service.onCreatePredictionSessionLocked(context, sessionId, token));
}
@Override
diff --git a/services/appprediction/java/com/android/server/appprediction/AppPredictionPerUserService.java b/services/appprediction/java/com/android/server/appprediction/AppPredictionPerUserService.java
index 7ee607c3eab4..735f420ca03e 100644
--- a/services/appprediction/java/com/android/server/appprediction/AppPredictionPerUserService.java
+++ b/services/appprediction/java/com/android/server/appprediction/AppPredictionPerUserService.java
@@ -30,6 +30,7 @@ import android.content.pm.PackageManager;
import android.content.pm.PackageManager.NameNotFoundException;
import android.content.pm.ParceledListSlice;
import android.content.pm.ServiceInfo;
+import android.os.IBinder;
import android.os.RemoteCallbackList;
import android.os.RemoteException;
import android.provider.DeviceConfig;
@@ -44,8 +45,6 @@ import com.android.server.LocalServices;
import com.android.server.infra.AbstractPerUserSystemService;
import com.android.server.people.PeopleServiceInternal;
-import java.util.function.Consumer;
-
/**
* Per-user instance of {@link AppPredictionManagerService}.
*/
@@ -112,17 +111,24 @@ public class AppPredictionPerUserService extends
*/
@GuardedBy("mLock")
public void onCreatePredictionSessionLocked(@NonNull AppPredictionContext context,
- @NonNull AppPredictionSessionId sessionId) {
- if (!mSessionInfos.containsKey(sessionId)) {
- mSessionInfos.put(sessionId, new AppPredictionSessionInfo(sessionId, context,
- DeviceConfig.getBoolean(NAMESPACE_SYSTEMUI,
- PREDICT_USING_PEOPLE_SERVICE_PREFIX + context.getUiSurface(), false),
- this::removeAppPredictionSessionInfo));
- }
- final boolean serviceExists = resolveService(sessionId, s ->
- s.onCreatePredictionSession(context, sessionId), true);
- if (!serviceExists) {
- mSessionInfos.remove(sessionId);
+ @NonNull AppPredictionSessionId sessionId, @NonNull IBinder token) {
+ final boolean usesPeopleService = DeviceConfig.getBoolean(NAMESPACE_SYSTEMUI,
+ PREDICT_USING_PEOPLE_SERVICE_PREFIX + context.getUiSurface(), false);
+ final boolean serviceExists = resolveService(sessionId, false,
+ usesPeopleService, s -> s.onCreatePredictionSession(context, sessionId));
+ if (serviceExists && !mSessionInfos.containsKey(sessionId)) {
+ final AppPredictionSessionInfo sessionInfo = new AppPredictionSessionInfo(
+ sessionId, context, usesPeopleService, token, () -> {
+ synchronized (mLock) {
+ onDestroyPredictionSessionLocked(sessionId);
+ }
+ });
+ if (sessionInfo.linkToDeath()) {
+ mSessionInfos.put(sessionId, sessionInfo);
+ } else {
+ // destroy the session if calling process is already dead
+ onDestroyPredictionSessionLocked(sessionId);
+ }
}
}
@@ -132,7 +138,10 @@ public class AppPredictionPerUserService extends
@GuardedBy("mLock")
public void notifyAppTargetEventLocked(@NonNull AppPredictionSessionId sessionId,
@NonNull AppTargetEvent event) {
- resolveService(sessionId, s -> s.notifyAppTargetEvent(sessionId, event), false);
+ final AppPredictionSessionInfo sessionInfo = mSessionInfos.get(sessionId);
+ if (sessionInfo == null) return;
+ resolveService(sessionId, false, sessionInfo.mUsesPeopleService,
+ s -> s.notifyAppTargetEvent(sessionId, event));
}
/**
@@ -141,8 +150,10 @@ public class AppPredictionPerUserService extends
@GuardedBy("mLock")
public void notifyLaunchLocationShownLocked(@NonNull AppPredictionSessionId sessionId,
@NonNull String launchLocation, @NonNull ParceledListSlice targetIds) {
- resolveService(sessionId, s ->
- s.notifyLaunchLocationShown(sessionId, launchLocation, targetIds), false);
+ final AppPredictionSessionInfo sessionInfo = mSessionInfos.get(sessionId);
+ if (sessionInfo == null) return;
+ resolveService(sessionId, false, sessionInfo.mUsesPeopleService,
+ s -> s.notifyLaunchLocationShown(sessionId, launchLocation, targetIds));
}
/**
@@ -151,7 +162,10 @@ public class AppPredictionPerUserService extends
@GuardedBy("mLock")
public void sortAppTargetsLocked(@NonNull AppPredictionSessionId sessionId,
@NonNull ParceledListSlice targets, @NonNull IPredictionCallback callback) {
- resolveService(sessionId, s -> s.sortAppTargets(sessionId, targets, callback), true);
+ final AppPredictionSessionInfo sessionInfo = mSessionInfos.get(sessionId);
+ if (sessionInfo == null) return;
+ resolveService(sessionId, true, sessionInfo.mUsesPeopleService,
+ s -> s.sortAppTargets(sessionId, targets, callback));
}
/**
@@ -160,10 +174,12 @@ public class AppPredictionPerUserService extends
@GuardedBy("mLock")
public void registerPredictionUpdatesLocked(@NonNull AppPredictionSessionId sessionId,
@NonNull IPredictionCallback callback) {
- final boolean serviceExists = resolveService(sessionId, s ->
- s.registerPredictionUpdates(sessionId, callback), false);
final AppPredictionSessionInfo sessionInfo = mSessionInfos.get(sessionId);
- if (serviceExists && sessionInfo != null) {
+ if (sessionInfo == null) return;
+ final boolean serviceExists = resolveService(sessionId, false,
+ sessionInfo.mUsesPeopleService,
+ s -> s.registerPredictionUpdates(sessionId, callback));
+ if (serviceExists) {
sessionInfo.addCallbackLocked(callback);
}
}
@@ -174,10 +190,12 @@ public class AppPredictionPerUserService extends
@GuardedBy("mLock")
public void unregisterPredictionUpdatesLocked(@NonNull AppPredictionSessionId sessionId,
@NonNull IPredictionCallback callback) {
- final boolean serviceExists = resolveService(sessionId, s ->
- s.unregisterPredictionUpdates(sessionId, callback), false);
final AppPredictionSessionInfo sessionInfo = mSessionInfos.get(sessionId);
- if (serviceExists && sessionInfo != null) {
+ if (sessionInfo == null) return;
+ final boolean serviceExists = resolveService(sessionId, false,
+ sessionInfo.mUsesPeopleService,
+ s -> s.unregisterPredictionUpdates(sessionId, callback));
+ if (serviceExists) {
sessionInfo.removeCallbackLocked(callback);
}
}
@@ -187,7 +205,10 @@ public class AppPredictionPerUserService extends
*/
@GuardedBy("mLock")
public void requestPredictionUpdateLocked(@NonNull AppPredictionSessionId sessionId) {
- resolveService(sessionId, s -> s.requestPredictionUpdate(sessionId), true);
+ final AppPredictionSessionInfo sessionInfo = mSessionInfos.get(sessionId);
+ if (sessionInfo == null) return;
+ resolveService(sessionId, true, sessionInfo.mUsesPeopleService,
+ s -> s.requestPredictionUpdate(sessionId));
}
/**
@@ -195,12 +216,14 @@ public class AppPredictionPerUserService extends
*/
@GuardedBy("mLock")
public void onDestroyPredictionSessionLocked(@NonNull AppPredictionSessionId sessionId) {
- final boolean serviceExists = resolveService(sessionId, s ->
- s.onDestroyPredictionSession(sessionId), false);
- final AppPredictionSessionInfo sessionInfo = mSessionInfos.get(sessionId);
- if (serviceExists && sessionInfo != null) {
- sessionInfo.destroy();
+ if (isDebug()) {
+ Slog.d(TAG, "onDestroyPredictionSessionLocked(): sessionId=" + sessionId);
}
+ final AppPredictionSessionInfo sessionInfo = mSessionInfos.remove(sessionId);
+ if (sessionInfo == null) return;
+ resolveService(sessionId, false, sessionInfo.mUsesPeopleService,
+ s -> s.onDestroyPredictionSession(sessionId));
+ sessionInfo.destroy();
}
@Override
@@ -291,27 +314,18 @@ public class AppPredictionPerUserService extends
}
for (AppPredictionSessionInfo sessionInfo : mSessionInfos.values()) {
- sessionInfo.resurrectSessionLocked(this);
- }
- }
-
- private void removeAppPredictionSessionInfo(AppPredictionSessionId sessionId) {
- if (isDebug()) {
- Slog.d(TAG, "removeAppPredictionSessionInfo(): sessionId=" + sessionId);
- }
- synchronized (mLock) {
- mSessionInfos.remove(sessionId);
+ sessionInfo.resurrectSessionLocked(this, sessionInfo.mToken);
}
}
@GuardedBy("mLock")
@Nullable
- protected boolean resolveService(@NonNull final AppPredictionSessionId sessionId,
- @NonNull final AbstractRemoteService.AsyncRequest<IPredictionService> cb,
- boolean sendImmediately) {
- final AppPredictionSessionInfo sessionInfo = mSessionInfos.get(sessionId);
- if (sessionInfo == null) return false;
- if (sessionInfo.mUsesPeopleService) {
+ protected boolean resolveService(
+ @NonNull final AppPredictionSessionId sessionId,
+ boolean sendImmediately,
+ boolean usesPeopleService,
+ @NonNull final AbstractRemoteService.AsyncRequest<IPredictionService> cb) {
+ if (usesPeopleService) {
final IPredictionService service =
LocalServices.getService(PeopleServiceInternal.class);
if (service != null) {
@@ -368,7 +382,9 @@ public class AppPredictionPerUserService extends
private final AppPredictionContext mPredictionContext;
private final boolean mUsesPeopleService;
@NonNull
- private final Consumer<AppPredictionSessionId> mRemoveSessionInfoAction;
+ final IBinder mToken;
+ @NonNull
+ final IBinder.DeathRecipient mDeathRecipient;
private final RemoteCallbackList<IPredictionCallback> mCallbacks =
new RemoteCallbackList<IPredictionCallback>() {
@@ -388,14 +404,16 @@ public class AppPredictionPerUserService extends
@NonNull final AppPredictionSessionId id,
@NonNull final AppPredictionContext predictionContext,
final boolean usesPeopleService,
- @NonNull final Consumer<AppPredictionSessionId> removeSessionInfoAction) {
+ @NonNull final IBinder token,
+ @NonNull final IBinder.DeathRecipient deathRecipient) {
if (DEBUG) {
Slog.d(TAG, "Creating AppPredictionSessionInfo for session Id=" + id);
}
mSessionId = id;
mPredictionContext = predictionContext;
mUsesPeopleService = usesPeopleService;
- mRemoveSessionInfoAction = removeSessionInfoAction;
+ mToken = token;
+ mDeathRecipient = deathRecipient;
}
void addCallbackLocked(IPredictionCallback callback) {
@@ -414,23 +432,38 @@ public class AppPredictionPerUserService extends
mCallbacks.unregister(callback);
}
+ boolean linkToDeath() {
+ try {
+ mToken.linkToDeath(mDeathRecipient, 0);
+ } catch (RemoteException e) {
+ if (DEBUG) {
+ Slog.w(TAG, "Caller is dead before session can be started, sessionId: "
+ + mSessionId);
+ }
+ return false;
+ }
+ return true;
+ }
+
void destroy() {
if (DEBUG) {
Slog.d(TAG, "Removing all callbacks for session Id=" + mSessionId
+ " and " + mCallbacks.getRegisteredCallbackCount() + " callbacks.");
}
+ if (mToken != null) {
+ mToken.unlinkToDeath(mDeathRecipient, 0);
+ }
mCallbacks.kill();
- mRemoveSessionInfoAction.accept(mSessionId);
}
- void resurrectSessionLocked(AppPredictionPerUserService service) {
+ void resurrectSessionLocked(AppPredictionPerUserService service, IBinder token) {
int callbackCount = mCallbacks.getRegisteredCallbackCount();
if (DEBUG) {
Slog.d(TAG, "Resurrecting remote service (" + service.getRemoteServiceLocked()
+ ") for session Id=" + mSessionId + " and "
+ callbackCount + " callbacks.");
}
- service.onCreatePredictionSessionLocked(mPredictionContext, mSessionId);
+ service.onCreatePredictionSessionLocked(mPredictionContext, mSessionId, token);
mCallbacks.broadcast(
callback -> service.registerPredictionUpdatesLocked(mSessionId, callback));
}
diff --git a/services/companion/TEST_MAPPING b/services/companion/TEST_MAPPING
new file mode 100644
index 000000000000..63f54fa35158
--- /dev/null
+++ b/services/companion/TEST_MAPPING
@@ -0,0 +1,12 @@
+{
+ "presubmit": [
+ {
+ "name": "CtsOsTestCases",
+ "options": [
+ {
+ "include-filter": "android.os.cts.CompanionDeviceManagerTest"
+ }
+ ]
+ }
+ ]
+}
diff --git a/services/companion/java/com/android/server/companion/CompanionDeviceManagerService.java b/services/companion/java/com/android/server/companion/CompanionDeviceManagerService.java
index eb38f5199ce5..7b9728cb4f08 100644
--- a/services/companion/java/com/android/server/companion/CompanionDeviceManagerService.java
+++ b/services/companion/java/com/android/server/companion/CompanionDeviceManagerService.java
@@ -393,12 +393,14 @@ public class CompanionDeviceManagerService extends SystemService implements Bind
.toString());
long identity = Binder.clearCallingIdentity();
try {
- return PendingIntent.getActivity(getContext(),
+ return PendingIntent.getActivityAsUser(getContext(),
0 /* request code */,
NotificationAccessConfirmationActivityContract.launcherIntent(
userId, component, packageTitle),
PendingIntent.FLAG_IMMUTABLE | PendingIntent.FLAG_ONE_SHOT
- | PendingIntent.FLAG_CANCEL_CURRENT);
+ | PendingIntent.FLAG_CANCEL_CURRENT,
+ null /* options */,
+ new UserHandle(userId));
} finally {
Binder.restoreCallingIdentity(identity);
}
@@ -612,8 +614,8 @@ public class CompanionDeviceManagerService extends SystemService implements Bind
}
}
- private AtomicFile getStorageFileForUser(int uid) {
- return mUidToStorage.computeIfAbsent(uid, (u) ->
+ private AtomicFile getStorageFileForUser(int userId) {
+ return mUidToStorage.computeIfAbsent(userId, (u) ->
new AtomicFile(new File(
//TODO deprecated method - what's the right replacement?
Environment.getUserSystemDirectory(u),
diff --git a/services/core/java/android/content/pm/PackageManagerInternal.java b/services/core/java/android/content/pm/PackageManagerInternal.java
index ad1986a6669f..cf9324c13ae8 100644
--- a/services/core/java/android/content/pm/PackageManagerInternal.java
+++ b/services/core/java/android/content/pm/PackageManagerInternal.java
@@ -302,24 +302,11 @@ public abstract class PackageManagerInternal {
String packageName, int userId);
/**
- * Do a straight uid lookup for the given package/application in the given user. This enforces
- * app visibility rules and permissions. Call {@link #getPackageUidInternal} for the internal
- * implementation.
- * @deprecated Use {@link PackageManager#getPackageUid(String, int)}
- * @return The app's uid, or < 0 if the package was not found in that user
- */
- @Deprecated
- public abstract int getPackageUid(String packageName,
- @PackageInfoFlags int flags, int userId);
-
- /**
* Do a straight uid lookup for the given package/application in the given user.
* @see PackageManager#getPackageUidAsUser(String, int, int)
* @return The app's uid, or < 0 if the package was not found in that user
- * TODO(b/148235092): rename this to getPackageUid
*/
- public abstract int getPackageUidInternal(String packageName,
- @PackageInfoFlags int flags, int userId);
+ public abstract int getPackageUid(String packageName, @PackageInfoFlags int flags, int userId);
/**
* Retrieve all of the information we know about a particular package/application.
diff --git a/services/core/java/com/android/server/DynamicSystemService.java b/services/core/java/com/android/server/DynamicSystemService.java
index b09b2605a791..500e768372f5 100644
--- a/services/core/java/com/android/server/DynamicSystemService.java
+++ b/services/core/java/com/android/server/DynamicSystemService.java
@@ -126,6 +126,16 @@ public class DynamicSystemService extends IDynamicSystemService.Stub {
}
@Override
+ public boolean closePartition() throws RemoteException {
+ IGsiService service = getGsiService();
+ if (service.closePartition() != 0) {
+ Slog.i(TAG, "Partition installation completes with error");
+ return false;
+ }
+ return true;
+ }
+
+ @Override
public boolean finishInstallation() throws RemoteException {
IGsiService service = getGsiService();
if (service.closeInstall() != 0) {
diff --git a/services/core/java/com/android/server/StorageManagerService.java b/services/core/java/com/android/server/StorageManagerService.java
index b72985cc8f2c..27c5d4a53956 100644
--- a/services/core/java/com/android/server/StorageManagerService.java
+++ b/services/core/java/com/android/server/StorageManagerService.java
@@ -2160,7 +2160,7 @@ class StorageManagerService extends IStorageManager.Stub
Slog.i(TAG, "Remounting storage for pid: " + pid);
final String[] sharedPackages =
mPmInternal.getSharedUserPackagesForPackage(packageName, userId);
- final int uid = mPmInternal.getPackageUidInternal(packageName, 0, userId);
+ final int uid = mPmInternal.getPackageUid(packageName, 0 /* flags */, userId);
final String[] packages =
sharedPackages.length != 0 ? sharedPackages : new String[]{packageName};
try {
diff --git a/services/core/java/com/android/server/UiModeManagerService.java b/services/core/java/com/android/server/UiModeManagerService.java
index 6dbb1e922f60..bcb7bfacfaf3 100644
--- a/services/core/java/com/android/server/UiModeManagerService.java
+++ b/services/core/java/com/android/server/UiModeManagerService.java
@@ -489,6 +489,9 @@ final class UiModeManagerService extends SystemService {
* @return True if the new value is different from the old value. False otherwise.
*/
private boolean updateNightModeFromSettingsLocked(Context context, Resources res, int userId) {
+ if (mCarModeEnabled || mCar) {
+ return false;
+ }
int oldNightMode = mNightMode;
if (mSetupWizardComplete) {
mNightMode = Secure.getIntForUser(context.getContentResolver(),
@@ -1033,7 +1036,7 @@ final class UiModeManagerService extends SystemService {
private void persistNightMode(int user) {
// Only persist setting if not in car mode
- if (mCarModeEnabled) return;
+ if (mCarModeEnabled || mCar) return;
Secure.putIntForUser(getContext().getContentResolver(),
Secure.UI_NIGHT_MODE, mNightMode, user);
Secure.putLongForUser(getContext().getContentResolver(),
@@ -1046,7 +1049,7 @@ final class UiModeManagerService extends SystemService {
private void persistNightModeOverrides(int user) {
// Only persist setting if not in car mode
- if (mCarModeEnabled) return;
+ if (mCarModeEnabled || mCar) return;
Secure.putIntForUser(getContext().getContentResolver(),
Secure.UI_NIGHT_MODE_OVERRIDE_ON, mOverrideNightModeOn ? 1 : 0, user);
Secure.putIntForUser(getContext().getContentResolver(),
@@ -1097,7 +1100,7 @@ final class UiModeManagerService extends SystemService {
}
// Override night mode in power save mode if not in car mode
- if (mPowerSave && !mCarModeEnabled) {
+ if (mPowerSave && !mCarModeEnabled && !mCar) {
uiMode &= ~Configuration.UI_MODE_NIGHT_NO;
uiMode |= Configuration.UI_MODE_NIGHT_YES;
} else {
diff --git a/services/core/java/com/android/server/VibratorService.java b/services/core/java/com/android/server/VibratorService.java
index 96d973ec5272..687af107590a 100644
--- a/services/core/java/com/android/server/VibratorService.java
+++ b/services/core/java/com/android/server/VibratorService.java
@@ -85,6 +85,7 @@ import java.util.Arrays;
import java.util.Date;
import java.util.LinkedList;
import java.util.List;
+import java.util.concurrent.atomic.AtomicInteger;
public class VibratorService extends IVibratorService.Stub
implements InputManager.InputDeviceListener {
@@ -114,6 +115,9 @@ public class VibratorService extends IVibratorService.Stub
private static final VibrationAttributes DEFAULT_ATTRIBUTES =
new VibrationAttributes.Builder().build();
+ // Used to generate globally unique vibration ids.
+ private final AtomicInteger mNextVibrationId = new AtomicInteger(1); // 0 = no callback
+
// A mapping from the intensity adjustment to the scaling to apply, where the intensity
// adjustment is defined as the delta between the default intensity level and the user selected
// intensity level. It's important that we apply the scaling on the delta between the two so
@@ -171,34 +175,34 @@ public class VibratorService extends IVibratorService.Stub
private int mRingIntensity;
private SparseArray<Vibration> mAlwaysOnEffects = new SparseArray<>();
- static native long vibratorInit();
+ static native long vibratorInit(OnCompleteListener listener);
static native long vibratorGetFinalizer();
- static native boolean vibratorExists(long controllerPtr);
+ static native boolean vibratorExists(long nativeServicePtr);
- static native void vibratorOn(long controllerPtr, long milliseconds, Vibration vibration);
+ static native void vibratorOn(long nativeServicePtr, long milliseconds, long vibrationId);
- static native void vibratorOff(long controllerPtr);
+ static native void vibratorOff(long nativeServicePtr);
- static native void vibratorSetAmplitude(long controllerPtr, int amplitude);
+ static native void vibratorSetAmplitude(long nativeServicePtr, int amplitude);
- static native int[] vibratorGetSupportedEffects(long controllerPtr);
+ static native int[] vibratorGetSupportedEffects(long nativeServicePtr);
- static native int[] vibratorGetSupportedPrimitives(long controllerPtr);
+ static native int[] vibratorGetSupportedPrimitives(long nativeServicePtr);
static native long vibratorPerformEffect(
- long controllerPtr, long effect, long strength, Vibration vibration);
+ long nativeServicePtr, long effect, long strength, long vibrationId);
- static native void vibratorPerformComposedEffect(long controllerPtr,
- VibrationEffect.Composition.PrimitiveEffect[] effect, Vibration vibration);
+ static native void vibratorPerformComposedEffect(long nativeServicePtr,
+ VibrationEffect.Composition.PrimitiveEffect[] effect, long vibrationId);
- static native void vibratorSetExternalControl(long controllerPtr, boolean enabled);
+ static native void vibratorSetExternalControl(long nativeServicePtr, boolean enabled);
- static native long vibratorGetCapabilities(long controllerPtr);
- static native void vibratorAlwaysOnEnable(long controllerPtr, long id, long effect,
+ static native long vibratorGetCapabilities(long nativeServicePtr);
+ static native void vibratorAlwaysOnEnable(long nativeServicePtr, long id, long effect,
long strength);
- static native void vibratorAlwaysOnDisable(long controllerPtr, long id);
+ static native void vibratorAlwaysOnDisable(long nativeServicePtr, long id);
private final IUidObserver mUidObserver = new IUidObserver.Stub() {
@Override public void onUidStateChanged(int uid, int procState, long procStateSeq,
@@ -220,12 +224,19 @@ public class VibratorService extends IVibratorService.Stub
}
};
+ /** Listener for vibration completion callbacks from native. */
+ public interface OnCompleteListener {
+
+ /** Callback triggered when vibration is complete, identified by {@link Vibration#id}. */
+ void onComplete(long vibrationId);
+ }
+
/**
* Holder for a vibration to be played. This class can be shared with native methods for
* hardware callback support.
*/
- @VisibleForTesting
- public final class Vibration implements IBinder.DeathRecipient {
+ private final class Vibration implements IBinder.DeathRecipient {
+
public final IBinder token;
// Start time in CLOCK_BOOTTIME base.
public final long startTime;
@@ -234,6 +245,7 @@ public class VibratorService extends IVibratorService.Stub
// not to be affected by discontinuities created by RTC adjustments.
public final long startTimeDebug;
public final VibrationAttributes attrs;
+ public final long id;
public final int uid;
public final String opPkg;
public final String reason;
@@ -248,6 +260,7 @@ public class VibratorService extends IVibratorService.Stub
VibrationAttributes attrs, int uid, String opPkg, String reason) {
this.token = token;
this.effect = effect;
+ this.id = mNextVibrationId.getAndIncrement();
this.startTime = SystemClock.elapsedRealtime();
this.startTimeDebug = System.currentTimeMillis();
this.attrs = attrs;
@@ -268,19 +281,6 @@ public class VibratorService extends IVibratorService.Stub
}
}
- /** Callback for when vibration is complete, to be called by native. */
- @VisibleForTesting
- public void onComplete() {
- synchronized (mLock) {
- if (this == mCurrentVibration) {
- if (DEBUG) {
- Slog.d(TAG, "Vibration finished by callback, cleaning up");
- }
- doCancelVibrateLocked();
- }
- }
- }
-
public boolean hasTimeoutLongerThan(long millis) {
final long duration = effect.getDuration();
return duration >= 0 && duration > millis;
@@ -385,14 +385,14 @@ public class VibratorService extends IVibratorService.Stub
mNativeWrapper = injector.getNativeWrapper();
mH = injector.createHandler(Looper.myLooper());
- long controllerPtr = mNativeWrapper.vibratorInit();
+ long nativeServicePtr = mNativeWrapper.vibratorInit(this::onVibrationComplete);
long finalizerPtr = mNativeWrapper.vibratorGetFinalizer();
if (finalizerPtr != 0) {
NativeAllocationRegistry registry =
NativeAllocationRegistry.createMalloced(
VibratorService.class.getClassLoader(), finalizerPtr);
- registry.registerNativeAllocation(this, controllerPtr);
+ registry.registerNativeAllocation(this, nativeServicePtr);
}
// Reset the hardware to a default state, in case this is a runtime
@@ -549,6 +549,19 @@ public class VibratorService extends IVibratorService.Stub
}
}
+ /** Callback for when vibration is complete, to be called by native. */
+ @VisibleForTesting
+ public void onVibrationComplete(long vibrationId) {
+ synchronized (mLock) {
+ if (mCurrentVibration != null && mCurrentVibration.id == vibrationId) {
+ if (DEBUG) {
+ Slog.d(TAG, "Vibration finished by callback, cleaning up");
+ }
+ doCancelVibrateLocked();
+ }
+ }
+ }
+
@Override // Binder call
public boolean hasVibrator() {
return doVibratorExists();
@@ -1266,18 +1279,18 @@ public class VibratorService extends IVibratorService.Stub
return mNativeWrapper.vibratorExists();
}
- /** Vibrates with native callback trigger for {@link Vibration#onComplete()}. */
+ /** Vibrates with native callback trigger for {@link #onVibrationComplete(long)}. */
private void doVibratorOn(long millis, int amplitude, Vibration vib) {
- doVibratorOn(millis, amplitude, vib.uid, vib.attrs, vib);
+ doVibratorOn(millis, amplitude, vib.uid, vib.attrs, vib.id);
}
/** Vibrates without native callback. */
private void doVibratorOn(long millis, int amplitude, int uid, VibrationAttributes attrs) {
- doVibratorOn(millis, amplitude, uid, attrs, /* vib= */ null);
+ doVibratorOn(millis, amplitude, uid, attrs, /* vibrationId= */ 0);
}
private void doVibratorOn(long millis, int amplitude, int uid, VibrationAttributes attrs,
- @Nullable Vibration vib) {
+ long vibrationId) {
Trace.traceBegin(Trace.TRACE_TAG_VIBRATOR, "doVibratorOn");
try {
synchronized (mInputDeviceVibrators) {
@@ -1299,7 +1312,7 @@ public class VibratorService extends IVibratorService.Stub
// Note: ordering is important here! Many haptic drivers will reset their
// amplitude when enabled, so we always have to enable first, then set the
// amplitude.
- mNativeWrapper.vibratorOn(millis, vib);
+ mNativeWrapper.vibratorOn(millis, vibrationId);
doVibratorSetAmplitude(amplitude);
}
}
@@ -1348,7 +1361,7 @@ public class VibratorService extends IVibratorService.Stub
// Input devices don't support prebaked effect, so skip trying it with them.
if (!usingInputDeviceVibrators) {
long duration = mNativeWrapper.vibratorPerformEffect(
- prebaked.getId(), prebaked.getEffectStrength(), vib);
+ prebaked.getId(), prebaked.getEffectStrength(), vib.id);
if (duration > 0) {
noteVibratorOnLocked(vib.uid, duration);
return;
@@ -1395,7 +1408,7 @@ public class VibratorService extends IVibratorService.Stub
PrimitiveEffect[] primitiveEffects =
composed.getPrimitiveEffects().toArray(new PrimitiveEffect[0]);
- mNativeWrapper.vibratorPerformComposedEffect(primitiveEffects, vib);
+ mNativeWrapper.vibratorPerformComposedEffect(primitiveEffects, vib.id);
// Composed effects don't actually give us an estimated duration, so we just guess here.
noteVibratorOnLocked(vib.uid, 10 * primitiveEffects.length);
@@ -1726,20 +1739,20 @@ public class VibratorService extends IVibratorService.Stub
@VisibleForTesting
public static class NativeWrapper {
- private long mNativeControllerPtr = 0;
+ private long mNativeServicePtr = 0;
/** Checks if vibrator exists on device. */
public boolean vibratorExists() {
- return VibratorService.vibratorExists(mNativeControllerPtr);
+ return VibratorService.vibratorExists(mNativeServicePtr);
}
/**
* Returns native pointer to newly created controller and initializes connection to vibrator
* HAL service.
*/
- public long vibratorInit() {
- mNativeControllerPtr = VibratorService.vibratorInit();
- return mNativeControllerPtr;
+ public long vibratorInit(OnCompleteListener listener) {
+ mNativeServicePtr = VibratorService.vibratorInit(listener);
+ return mNativeServicePtr;
}
/** Returns pointer to native finalizer function to be called by GC. */
@@ -1748,60 +1761,61 @@ public class VibratorService extends IVibratorService.Stub
}
/** Turns vibrator on for given time. */
- public void vibratorOn(long milliseconds, @Nullable Vibration vibration) {
- VibratorService.vibratorOn(mNativeControllerPtr, milliseconds, vibration);
+ public void vibratorOn(long milliseconds, long vibrationId) {
+ VibratorService.vibratorOn(mNativeServicePtr, milliseconds, vibrationId);
}
/** Turns vibrator off. */
public void vibratorOff() {
- VibratorService.vibratorOff(mNativeControllerPtr);
+ VibratorService.vibratorOff(mNativeServicePtr);
}
/** Sets the amplitude for the vibrator to run. */
public void vibratorSetAmplitude(int amplitude) {
- VibratorService.vibratorSetAmplitude(mNativeControllerPtr, amplitude);
+ VibratorService.vibratorSetAmplitude(mNativeServicePtr, amplitude);
}
/** Returns all predefined effects supported by the device vibrator. */
public int[] vibratorGetSupportedEffects() {
- return VibratorService.vibratorGetSupportedEffects(mNativeControllerPtr);
+ return VibratorService.vibratorGetSupportedEffects(mNativeServicePtr);
}
/** Returns all compose primitives supported by the device vibrator. */
public int[] vibratorGetSupportedPrimitives() {
- return VibratorService.vibratorGetSupportedPrimitives(mNativeControllerPtr);
+ return VibratorService.vibratorGetSupportedPrimitives(mNativeServicePtr);
}
/** Turns vibrator on to perform one of the supported effects. */
- public long vibratorPerformEffect(long effect, long strength, Vibration vibration) {
+ public long vibratorPerformEffect(long effect, long strength, long vibrationId) {
return VibratorService.vibratorPerformEffect(
- mNativeControllerPtr, effect, strength, vibration);
+ mNativeServicePtr, effect, strength, vibrationId);
}
/** Turns vibrator on to perform one of the supported composed effects. */
public void vibratorPerformComposedEffect(
- VibrationEffect.Composition.PrimitiveEffect[] effect, Vibration vibration) {
- VibratorService.vibratorPerformComposedEffect(mNativeControllerPtr, effect, vibration);
+ VibrationEffect.Composition.PrimitiveEffect[] effect, long vibrationId) {
+ VibratorService.vibratorPerformComposedEffect(mNativeServicePtr, effect,
+ vibrationId);
}
/** Enabled the device vibrator to be controlled by another service. */
public void vibratorSetExternalControl(boolean enabled) {
- VibratorService.vibratorSetExternalControl(mNativeControllerPtr, enabled);
+ VibratorService.vibratorSetExternalControl(mNativeServicePtr, enabled);
}
/** Returns all capabilities of the device vibrator. */
public long vibratorGetCapabilities() {
- return VibratorService.vibratorGetCapabilities(mNativeControllerPtr);
+ return VibratorService.vibratorGetCapabilities(mNativeServicePtr);
}
/** Enable always-on vibration with given id and effect. */
public void vibratorAlwaysOnEnable(long id, long effect, long strength) {
- VibratorService.vibratorAlwaysOnEnable(mNativeControllerPtr, id, effect, strength);
+ VibratorService.vibratorAlwaysOnEnable(mNativeServicePtr, id, effect, strength);
}
/** Disable always-on vibration for given id. */
public void vibratorAlwaysOnDisable(long id) {
- VibratorService.vibratorAlwaysOnDisable(mNativeControllerPtr, id);
+ VibratorService.vibratorAlwaysOnDisable(mNativeServicePtr, id);
}
}
diff --git a/services/core/java/com/android/server/accounts/AccountManagerService.java b/services/core/java/com/android/server/accounts/AccountManagerService.java
index 35e88eb804cb..7d81d412e369 100644
--- a/services/core/java/com/android/server/accounts/AccountManagerService.java
+++ b/services/core/java/com/android/server/accounts/AccountManagerService.java
@@ -2114,7 +2114,7 @@ public class AccountManagerService
* Owner or system user account was renamed, rename the account for
* those users with which the account was shared.
*/
- List<UserInfo> users = getUserManager().getUsers(true);
+ List<UserInfo> users = getUserManager().getAliveUsers();
for (UserInfo user : users) {
if (user.isRestricted()
&& (user.restrictedProfileParentId == parentUserId)) {
@@ -2373,7 +2373,7 @@ public class AccountManagerService
int parentUserId = accounts.userId;
if (canHaveProfile(parentUserId)) {
// Remove from any restricted profiles that are sharing this account.
- List<UserInfo> users = getUserManager().getUsers(true);
+ List<UserInfo> users = getUserManager().getAliveUsers();
for (UserInfo user : users) {
if (user.isRestricted() && parentUserId == (user.restrictedProfileParentId)) {
removeSharedAccountAsUser(account, user.id, callingUid);
@@ -4267,7 +4267,7 @@ public class AccountManagerService
*/
@NonNull
public AccountAndUser[] getAllAccounts() {
- final List<UserInfo> users = getUserManager().getUsers(true);
+ final List<UserInfo> users = getUserManager().getAliveUsers();
final int[] userIds = new int[users.size()];
for (int i = 0; i < userIds.length; i++) {
userIds[i] = users.get(i).id;
diff --git a/services/core/java/com/android/server/am/ActiveServices.java b/services/core/java/com/android/server/am/ActiveServices.java
index c31d73246ff6..343e05d982fd 100644
--- a/services/core/java/com/android/server/am/ActiveServices.java
+++ b/services/core/java/com/android/server/am/ActiveServices.java
@@ -2268,21 +2268,23 @@ public final class ActiveServices {
clist.remove(0);
}
- if (r.binding.service.app != null) {
- if (r.binding.service.app.whitelistManager) {
- updateWhitelistManagerLocked(r.binding.service.app);
+ final ProcessRecord app = r.binding.service.app;
+ if (app != null) {
+ if (app.whitelistManager) {
+ updateWhitelistManagerLocked(app);
}
// This could have made the service less important.
if ((r.flags&Context.BIND_TREAT_LIKE_ACTIVITY) != 0) {
- r.binding.service.app.treatLikeActivity = true;
- mAm.updateLruProcessLocked(r.binding.service.app,
- r.binding.service.app.hasClientActivities()
- || r.binding.service.app.treatLikeActivity, null);
+ app.treatLikeActivity = true;
+ mAm.updateLruProcessLocked(app,
+ app.hasClientActivities()
+ || app.treatLikeActivity, null);
}
+ mAm.enqueueOomAdjTargetLocked(app);
}
}
- mAm.updateOomAdjLocked(OomAdjuster.OOM_ADJ_REASON_UNBIND_SERVICE);
+ mAm.updateOomAdjPendingTargetsLocked(OomAdjuster.OOM_ADJ_REASON_UNBIND_SERVICE);
} finally {
Binder.restoreCallingIdentity(origId);
diff --git a/services/core/java/com/android/server/am/ActivityManagerService.java b/services/core/java/com/android/server/am/ActivityManagerService.java
index 6e1e3d0a9a9a..a5d2011483bc 100644
--- a/services/core/java/com/android/server/am/ActivityManagerService.java
+++ b/services/core/java/com/android/server/am/ActivityManagerService.java
@@ -83,6 +83,7 @@ import static android.provider.Settings.Global.NETWORK_ACCESS_TIMEOUT_MS;
import static android.provider.Settings.Global.WAIT_FOR_DEBUGGER;
import static android.text.format.DateUtils.DAY_IN_MILLIS;
+import static com.android.internal.protolog.ProtoLogGroup.WM_DEBUG_CONFIGURATION;
import static com.android.server.am.ActivityManagerDebugConfig.DEBUG_ALL;
import static com.android.server.am.ActivityManagerDebugConfig.DEBUG_ANR;
import static com.android.server.am.ActivityManagerDebugConfig.DEBUG_BACKGROUND_CHECK;
@@ -117,7 +118,6 @@ import static com.android.server.am.ActivityManagerDebugConfig.TAG_WITH_CLASS_NA
import static com.android.server.am.MemoryStatUtil.hasMemcg;
import static com.android.server.pm.PackageManagerService.PLATFORM_PACKAGE_NAME;
import static com.android.server.wm.ActivityTaskManagerDebugConfig.DEBUG_CLEANUP;
-import static com.android.server.wm.ActivityTaskManagerDebugConfig.DEBUG_CONFIGURATION;
import static com.android.server.wm.ActivityTaskManagerDebugConfig.DEBUG_SWITCH;
import static com.android.server.wm.ActivityTaskManagerDebugConfig.POSTFIX_CONFIGURATION;
import static com.android.server.wm.ActivityTaskManagerDebugConfig.POSTFIX_LOCKTASK;
@@ -319,6 +319,7 @@ import com.android.internal.os.IResultReceiver;
import com.android.internal.os.ProcessCpuTracker;
import com.android.internal.os.TransferPipe;
import com.android.internal.os.Zygote;
+import com.android.internal.protolog.common.ProtoLog;
import com.android.internal.util.ArrayUtils;
import com.android.internal.util.DumpUtils;
import com.android.internal.util.FastPrintWriter;
@@ -2102,17 +2103,13 @@ public class ActivityManagerService extends IActivityManager.Stub
@Override
protected void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
try {
- if (mActivityManagerService.mOomAdjuster.mCachedAppOptimizer.useFreezer()) {
- Process.enableFreezer(false);
- }
+ mActivityManagerService.mOomAdjuster.mCachedAppOptimizer.enableFreezer(false);
if (!DumpUtils.checkDumpAndUsageStatsPermission(mActivityManagerService.mContext,
"meminfo", pw)) return;
PriorityDump.dump(mPriorityDumper, fd, pw, args);
} finally {
- if (mActivityManagerService.mOomAdjuster.mCachedAppOptimizer.useFreezer()) {
- Process.enableFreezer(true);
- }
+ mActivityManagerService.mOomAdjuster.mCachedAppOptimizer.enableFreezer(true);
}
}
}
@@ -2126,17 +2123,13 @@ public class ActivityManagerService extends IActivityManager.Stub
@Override
protected void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
try {
- if (mActivityManagerService.mOomAdjuster.mCachedAppOptimizer.useFreezer()) {
- Process.enableFreezer(false);
- }
+ mActivityManagerService.mOomAdjuster.mCachedAppOptimizer.enableFreezer(false);
if (!DumpUtils.checkDumpAndUsageStatsPermission(mActivityManagerService.mContext,
"gfxinfo", pw)) return;
mActivityManagerService.dumpGraphicsHardwareUsage(fd, pw, args);
} finally {
- if (mActivityManagerService.mOomAdjuster.mCachedAppOptimizer.useFreezer()) {
- Process.enableFreezer(true);
- }
+ mActivityManagerService.mOomAdjuster.mCachedAppOptimizer.enableFreezer(true);
}
}
}
@@ -2150,17 +2143,13 @@ public class ActivityManagerService extends IActivityManager.Stub
@Override
protected void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
try {
- if (mActivityManagerService.mOomAdjuster.mCachedAppOptimizer.useFreezer()) {
- Process.enableFreezer(false);
- }
+ mActivityManagerService.mOomAdjuster.mCachedAppOptimizer.enableFreezer(false);
if (!DumpUtils.checkDumpAndUsageStatsPermission(mActivityManagerService.mContext,
"dbinfo", pw)) return;
mActivityManagerService.dumpDbInfo(fd, pw, args);
} finally {
- if (mActivityManagerService.mOomAdjuster.mCachedAppOptimizer.useFreezer()) {
- Process.enableFreezer(true);
- }
+ mActivityManagerService.mOomAdjuster.mCachedAppOptimizer.enableFreezer(true);
}
}
}
@@ -2206,9 +2195,7 @@ public class ActivityManagerService extends IActivityManager.Stub
@Override
protected void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
try {
- if (mActivityManagerService.mOomAdjuster.mCachedAppOptimizer.useFreezer()) {
- Process.enableFreezer(false);
- }
+ mActivityManagerService.mOomAdjuster.mCachedAppOptimizer.enableFreezer(false);
if (!DumpUtils.checkDumpAndUsageStatsPermission(mActivityManagerService.mContext,
"cacheinfo", pw)) {
@@ -2217,9 +2204,7 @@ public class ActivityManagerService extends IActivityManager.Stub
mActivityManagerService.dumpBinderCacheContents(fd, pw, args);
} finally {
- if (mActivityManagerService.mOomAdjuster.mCachedAppOptimizer.useFreezer()) {
- Process.enableFreezer(true);
- }
+ mActivityManagerService.mOomAdjuster.mCachedAppOptimizer.enableFreezer(true);
}
}
}
@@ -4946,9 +4931,8 @@ public class ActivityManagerService extends IActivityManager.Stub
notifyPackageUse(instr.mClass.getPackageName(),
PackageManager.NOTIFY_PACKAGE_USE_INSTRUMENTATION);
}
- if (DEBUG_CONFIGURATION) Slog.v(TAG_CONFIGURATION, "Binding proc "
- + processName + " with config "
- + app.getWindowProcessController().getConfiguration());
+ ProtoLog.v(WM_DEBUG_CONFIGURATION, "Binding proc %s with config %s",
+ processName, app.getWindowProcessController().getConfiguration());
ApplicationInfo appInfo = instr != null ? instr.mTargetInfo : app.info;
app.compat = compatibilityInfoForPackage(appInfo);
@@ -5686,8 +5670,8 @@ public class ActivityManagerService extends IActivityManager.Stub
"setProcessLimit()");
synchronized (this) {
mConstants.setOverrideMaxCachedProcesses(max);
+ trimApplicationsLocked(true, OomAdjuster.OOM_ADJ_REASON_PROCESS_END);
}
- trimApplications(OomAdjuster.OOM_ADJ_REASON_PROCESS_END);
}
@Override
@@ -5778,9 +5762,7 @@ public class ActivityManagerService extends IActivityManager.Stub
}
private boolean isAppBad(final String processName, final int uid) {
- synchronized (this) {
- return mAppErrors.isBadProcessLocked(processName, uid);
- }
+ return mAppErrors.isBadProcess(processName, uid);
}
// NOTE: this is an internal method used by the OnShellCommand implementation only and should
@@ -13995,7 +13977,8 @@ public class ActivityManagerService extends IActivityManager.Stub
r.resultAbort, false);
if (doNext) {
doTrim = true;
- r.queue.processNextBroadcast(false);
+ r.queue.processNextBroadcastLocked(/* frommsg */ false,
+ /* skipOomAdj */ true);
}
}
@@ -14008,13 +13991,13 @@ public class ActivityManagerService extends IActivityManager.Stub
rl.receiver.asBinder().unlinkToDeath(rl, 0);
}
}
- }
- // If we actually concluded any broadcasts, we might now be able
- // to trim the recipients' apps from our working set
- if (doTrim) {
- trimApplications(OomAdjuster.OOM_ADJ_REASON_FINISH_RECEIVER);
- return;
+ // If we actually concluded any broadcasts, we might now be able
+ // to trim the recipients' apps from our working set
+ if (doTrim) {
+ trimApplicationsLocked(false, OomAdjuster.OOM_ADJ_REASON_FINISH_RECEIVER);
+ return;
+ }
}
} finally {
@@ -15145,7 +15128,7 @@ public class ActivityManagerService extends IActivityManager.Stub
r.queue.processNextBroadcastLocked(/*fromMsg=*/ false, /*skipOomAdj=*/ true);
}
// updateOomAdjLocked() will be done here
- trimApplicationsLocked(OomAdjuster.OOM_ADJ_REASON_FINISH_RECEIVER);
+ trimApplicationsLocked(false, OomAdjuster.OOM_ADJ_REASON_FINISH_RECEIVER);
}
} finally {
@@ -16155,6 +16138,32 @@ public class ActivityManagerService extends IActivityManager.Stub
return mOomAdjuster.updateOomAdjLocked(app, oomAdjAll, oomAdjReason);
}
+ /**
+ * Enqueue the given process into a todo list, and the caller should
+ * call {@link #updateOomAdjPendingTargetsLocked} to kick off a pass of the oom adj update.
+ */
+ @GuardedBy("this")
+ void enqueueOomAdjTargetLocked(ProcessRecord app) {
+ mOomAdjuster.enqueueOomAdjTargetLocked(app);
+ }
+
+ /**
+ * Remove the given process into a todo list.
+ */
+ @GuardedBy("this")
+ void removeOomAdjTargetLocked(ProcessRecord app, boolean procDied) {
+ mOomAdjuster.removeOomAdjTargetLocked(app, procDied);
+ }
+
+ /**
+ * Kick off an oom adj update pass for the pending targets which are enqueued via
+ * {@link #enqueueOomAdjTargetLocked}.
+ */
+ @GuardedBy("this")
+ void updateOomAdjPendingTargetsLocked(String oomAdjReason) {
+ mOomAdjuster.updateOomAdjPendingTargetsLocked(oomAdjReason);
+ }
+
static final class ProcStatsRunnable implements Runnable {
private final ActivityManagerService mService;
private final ProcessStatsService mProcessStats;
@@ -16563,16 +16572,17 @@ public class ActivityManagerService extends IActivityManager.Stub
mOomAdjuster.setUidTempWhitelistStateLocked(uid, onWhitelist);
}
- final void trimApplications(String oomAdjReason) {
+ private void trimApplications(boolean forceFullOomAdj, String oomAdjReason) {
synchronized (this) {
- trimApplicationsLocked(oomAdjReason);
+ trimApplicationsLocked(forceFullOomAdj, oomAdjReason);
}
}
@GuardedBy("this")
- final void trimApplicationsLocked(String oomAdjReason) {
+ private void trimApplicationsLocked(boolean forceFullOomAdj, String oomAdjReason) {
// First remove any unused application processes whose package
// has been removed.
+ boolean didSomething = false;
for (int i = mProcessList.mRemovedProcesses.size() - 1; i >= 0; i--) {
final ProcessRecord app = mProcessList.mRemovedProcesses.get(i);
if (!app.hasActivitiesOrRecentTasks()
@@ -16594,6 +16604,7 @@ public class ActivityManagerService extends IActivityManager.Stub
// Ignore exceptions.
}
}
+ didSomething = true;
cleanUpApplicationRecordLocked(app, false, true, -1, false /*replacingPid*/);
mProcessList.mRemovedProcesses.remove(i);
@@ -16606,7 +16617,12 @@ public class ActivityManagerService extends IActivityManager.Stub
// Now update the oom adj for all processes. Don't skip this, since other callers
// might be depending on it.
- updateOomAdjLocked(oomAdjReason);
+ if (didSomething || forceFullOomAdj) {
+ updateOomAdjLocked(oomAdjReason);
+ } else {
+ // Process any pending oomAdj targets, it'll be a no-op if nothing is pending.
+ updateOomAdjPendingTargetsLocked(oomAdjReason);
+ }
}
/** This method sends the specified signal to each of the persistent apps */
@@ -16800,14 +16816,14 @@ public class ActivityManagerService extends IActivityManager.Stub
}
}
- Process.enableFreezer(false);
+ mOomAdjuster.mCachedAppOptimizer.enableFreezer(false);
final RemoteCallback intermediateCallback = new RemoteCallback(
new RemoteCallback.OnResultListener() {
@Override
public void onResult(Bundle result) {
finishCallback.sendResult(result);
- Process.enableFreezer(true);
+ mOomAdjuster.mCachedAppOptimizer.enableFreezer(true);
}
}, null);
@@ -17144,8 +17160,7 @@ public class ActivityManagerService extends IActivityManager.Stub
@Override
public int checkContentProviderUriPermission(Uri uri, int userId,
int callingUid, int modeFlags) {
- return mCpHelper.checkContentProviderUriPermission(uri,
- userId, callingUid, modeFlags);
+ return mCpHelper.checkContentProviderUriPermission(uri, userId, callingUid, modeFlags);
}
@Override
@@ -17412,7 +17427,7 @@ public class ActivityManagerService extends IActivityManager.Stub
@Override
public void trimApplications() {
- ActivityManagerService.this.trimApplications(OomAdjuster.OOM_ADJ_REASON_ACTIVITY);
+ ActivityManagerService.this.trimApplications(true, OomAdjuster.OOM_ADJ_REASON_ACTIVITY);
}
public void killProcessesForRemovedTask(ArrayList<Object> procsToKill) {
@@ -18738,4 +18753,16 @@ public class ActivityManagerService extends IActivityManager.Stub
mAppErrors.resetStateLocked();
}
}
+
+ @Override
+ public boolean enableAppFreezer(boolean enable) {
+ int callerUid = Binder.getCallingUid();
+
+ // Only system can toggle the freezer state
+ if (callerUid == SYSTEM_UID) {
+ return mOomAdjuster.mCachedAppOptimizer.enableFreezer(enable);
+ } else {
+ throw new SecurityException("Caller uid " + callerUid + " cannot set freezer state ");
+ }
+ }
}
diff --git a/services/core/java/com/android/server/am/AppErrors.java b/services/core/java/com/android/server/am/AppErrors.java
index 5268359df327..5d429d3065f3 100644
--- a/services/core/java/com/android/server/am/AppErrors.java
+++ b/services/core/java/com/android/server/am/AppErrors.java
@@ -50,6 +50,7 @@ import android.util.SparseArray;
import android.util.TimeUtils;
import android.util.proto.ProtoOutputStream;
+import com.android.internal.annotations.GuardedBy;
import com.android.internal.app.ProcessMap;
import com.android.internal.logging.MetricsLogger;
import com.android.internal.logging.nano.MetricsProto;
@@ -96,7 +97,11 @@ class AppErrors {
* a minimum amount of time; they are removed from it when they are
* later restarted (hopefully due to some user action). The value is the
* time it was added to the list.
+ *
+ * Access is synchronized on the container object itself, and no other
+ * locks may be acquired while holding that one.
*/
+ @GuardedBy("mBadProcesses")
private final ProcessMap<BadProcessInfo> mBadProcesses = new ProcessMap<>();
@@ -114,76 +119,81 @@ class AppErrors {
mProcessCrashTimes.clear();
mProcessCrashTimesPersistent.clear();
mProcessCrashShowDialogTimes.clear();
- mBadProcesses.clear();
+ synchronized (mBadProcesses) {
+ mBadProcesses.clear();
+ }
}
void dumpDebug(ProtoOutputStream proto, long fieldId, String dumpPackage) {
- if (mProcessCrashTimes.getMap().isEmpty() && mBadProcesses.getMap().isEmpty()) {
- return;
- }
-
- final long token = proto.start(fieldId);
- final long now = SystemClock.uptimeMillis();
- proto.write(AppErrorsProto.NOW_UPTIME_MS, now);
-
- if (!mProcessCrashTimes.getMap().isEmpty()) {
- final ArrayMap<String, SparseArray<Long>> pmap = mProcessCrashTimes.getMap();
- final int procCount = pmap.size();
- for (int ip = 0; ip < procCount; ip++) {
- final long ctoken = proto.start(AppErrorsProto.PROCESS_CRASH_TIMES);
- final String pname = pmap.keyAt(ip);
- final SparseArray<Long> uids = pmap.valueAt(ip);
- final int uidCount = uids.size();
+ synchronized (mBadProcesses) {
+ if (mProcessCrashTimes.getMap().isEmpty() && mBadProcesses.getMap().isEmpty()) {
+ return;
+ }
- proto.write(AppErrorsProto.ProcessCrashTime.PROCESS_NAME, pname);
- for (int i = 0; i < uidCount; i++) {
- final int puid = uids.keyAt(i);
- final ProcessRecord r = mService.getProcessNames().get(pname, puid);
- if (dumpPackage != null && (r == null || !r.pkgList.containsKey(dumpPackage))) {
- continue;
+ final long token = proto.start(fieldId);
+ final long now = SystemClock.uptimeMillis();
+ proto.write(AppErrorsProto.NOW_UPTIME_MS, now);
+
+ if (!mProcessCrashTimes.getMap().isEmpty()) {
+ final ArrayMap<String, SparseArray<Long>> pmap = mProcessCrashTimes.getMap();
+ final int procCount = pmap.size();
+ for (int ip = 0; ip < procCount; ip++) {
+ final long ctoken = proto.start(AppErrorsProto.PROCESS_CRASH_TIMES);
+ final String pname = pmap.keyAt(ip);
+ final SparseArray<Long> uids = pmap.valueAt(ip);
+ final int uidCount = uids.size();
+
+ proto.write(AppErrorsProto.ProcessCrashTime.PROCESS_NAME, pname);
+ for (int i = 0; i < uidCount; i++) {
+ final int puid = uids.keyAt(i);
+ final ProcessRecord r = mService.getProcessNames().get(pname, puid);
+ if (dumpPackage != null
+ && (r == null || !r.pkgList.containsKey(dumpPackage))) {
+ continue;
+ }
+ final long etoken = proto.start(AppErrorsProto.ProcessCrashTime.ENTRIES);
+ proto.write(AppErrorsProto.ProcessCrashTime.Entry.UID, puid);
+ proto.write(AppErrorsProto.ProcessCrashTime.Entry.LAST_CRASHED_AT_MS,
+ uids.valueAt(i));
+ proto.end(etoken);
}
- final long etoken = proto.start(AppErrorsProto.ProcessCrashTime.ENTRIES);
- proto.write(AppErrorsProto.ProcessCrashTime.Entry.UID, puid);
- proto.write(AppErrorsProto.ProcessCrashTime.Entry.LAST_CRASHED_AT_MS,
- uids.valueAt(i));
- proto.end(etoken);
+ proto.end(ctoken);
}
- proto.end(ctoken);
- }
- }
+ }
- if (!mBadProcesses.getMap().isEmpty()) {
- final ArrayMap<String, SparseArray<BadProcessInfo>> pmap = mBadProcesses.getMap();
- final int processCount = pmap.size();
- for (int ip = 0; ip < processCount; ip++) {
- final long btoken = proto.start(AppErrorsProto.BAD_PROCESSES);
- final String pname = pmap.keyAt(ip);
- final SparseArray<BadProcessInfo> uids = pmap.valueAt(ip);
- final int uidCount = uids.size();
+ if (!mBadProcesses.getMap().isEmpty()) {
+ final ArrayMap<String, SparseArray<BadProcessInfo>> pmap = mBadProcesses.getMap();
+ final int processCount = pmap.size();
+ for (int ip = 0; ip < processCount; ip++) {
+ final long btoken = proto.start(AppErrorsProto.BAD_PROCESSES);
+ final String pname = pmap.keyAt(ip);
+ final SparseArray<BadProcessInfo> uids = pmap.valueAt(ip);
+ final int uidCount = uids.size();
- proto.write(AppErrorsProto.BadProcess.PROCESS_NAME, pname);
- for (int i = 0; i < uidCount; i++) {
- final int puid = uids.keyAt(i);
- final ProcessRecord r = mService.getProcessNames().get(pname, puid);
- if (dumpPackage != null && (r == null
- || !r.pkgList.containsKey(dumpPackage))) {
- continue;
+ proto.write(AppErrorsProto.BadProcess.PROCESS_NAME, pname);
+ for (int i = 0; i < uidCount; i++) {
+ final int puid = uids.keyAt(i);
+ final ProcessRecord r = mService.getProcessNames().get(pname, puid);
+ if (dumpPackage != null && (r == null
+ || !r.pkgList.containsKey(dumpPackage))) {
+ continue;
+ }
+ final BadProcessInfo info = uids.valueAt(i);
+ final long etoken = proto.start(AppErrorsProto.BadProcess.ENTRIES);
+ proto.write(AppErrorsProto.BadProcess.Entry.UID, puid);
+ proto.write(AppErrorsProto.BadProcess.Entry.CRASHED_AT_MS, info.time);
+ proto.write(AppErrorsProto.BadProcess.Entry.SHORT_MSG, info.shortMsg);
+ proto.write(AppErrorsProto.BadProcess.Entry.LONG_MSG, info.longMsg);
+ proto.write(AppErrorsProto.BadProcess.Entry.STACK, info.stack);
+ proto.end(etoken);
}
- final BadProcessInfo info = uids.valueAt(i);
- final long etoken = proto.start(AppErrorsProto.BadProcess.ENTRIES);
- proto.write(AppErrorsProto.BadProcess.Entry.UID, puid);
- proto.write(AppErrorsProto.BadProcess.Entry.CRASHED_AT_MS, info.time);
- proto.write(AppErrorsProto.BadProcess.Entry.SHORT_MSG, info.shortMsg);
- proto.write(AppErrorsProto.BadProcess.Entry.LONG_MSG, info.longMsg);
- proto.write(AppErrorsProto.BadProcess.Entry.STACK, info.stack);
- proto.end(etoken);
+ proto.end(btoken);
}
- proto.end(btoken);
}
- }
- proto.end(token);
+ proto.end(token);
+ }
}
boolean dumpLocked(FileDescriptor fd, PrintWriter pw, boolean needSep, String dumpPackage) {
@@ -272,12 +282,16 @@ class AppErrors {
return needSep;
}
- boolean isBadProcessLocked(final String processName, final int uid) {
- return mBadProcesses.get(processName, uid) != null;
+ boolean isBadProcess(final String processName, final int uid) {
+ synchronized (mBadProcesses) {
+ return mBadProcesses.get(processName, uid) != null;
+ }
}
- void clearBadProcessLocked(final String processName, final int uid) {
- mBadProcesses.remove(processName, uid);
+ void clearBadProcess(final String processName, final int uid) {
+ synchronized (mBadProcesses) {
+ mBadProcesses.remove(processName, uid);
+ }
}
void resetProcessCrashTimeLocked(final String processName, final int uid) {
@@ -747,8 +761,10 @@ class AppErrors {
if (!app.isolated) {
// XXX We don't have a way to mark isolated processes
// as bad, since they don't have a peristent identity.
- mBadProcesses.put(app.processName, app.uid,
- new BadProcessInfo(now, shortMsg, longMsg, stackTrace));
+ synchronized (mBadProcesses) {
+ mBadProcesses.put(app.processName, app.uid,
+ new BadProcessInfo(now, shortMsg, longMsg, stackTrace));
+ }
mProcessCrashTimes.remove(app.processName, app.uid);
}
app.bad = true;
diff --git a/services/core/java/com/android/server/am/BroadcastQueue.java b/services/core/java/com/android/server/am/BroadcastQueue.java
index 960d26b5da34..6948f9061038 100644
--- a/services/core/java/com/android/server/am/BroadcastQueue.java
+++ b/services/core/java/com/android/server/am/BroadcastQueue.java
@@ -281,7 +281,7 @@ public final class BroadcastQueue {
}
private final void processCurBroadcastLocked(BroadcastRecord r,
- ProcessRecord app, boolean skipOomAdj) throws RemoteException {
+ ProcessRecord app) throws RemoteException {
if (DEBUG_BROADCAST) Slog.v(TAG_BROADCAST,
"Process cur broadcast " + r + " for app " + app);
if (app.thread == null) {
@@ -297,9 +297,11 @@ public final class BroadcastQueue {
app.curReceivers.add(r);
app.forceProcessStateUpTo(ActivityManager.PROCESS_STATE_RECEIVER);
mService.mProcessList.updateLruProcessLocked(app, false, null);
- if (!skipOomAdj) {
- mService.updateOomAdjLocked(app, OomAdjuster.OOM_ADJ_REASON_NONE);
- }
+ // Make sure the oom adj score is updated before delivering the broadcast.
+ // Force an update, even if there are other pending requests, overall it still saves time,
+ // because time(updateOomAdj(N apps)) <= N * time(updateOomAdj(1 app)).
+ mService.enqueueOomAdjTargetLocked(app);
+ mService.updateOomAdjPendingTargetsLocked(OomAdjuster.OOM_ADJ_REASON_START_RECEIVER);
// Tell the application to launch this receiver.
r.intent.setComponent(r.curComponent);
@@ -340,7 +342,7 @@ public final class BroadcastQueue {
}
try {
mPendingBroadcast = null;
- processCurBroadcastLocked(br, app, false);
+ processCurBroadcastLocked(br, app);
didSomething = true;
} catch (Exception e) {
Slog.w(TAG, "Exception in new application when starting receiver "
@@ -501,6 +503,7 @@ public final class BroadcastQueue {
r.intent.setComponent(null);
if (r.curApp != null && r.curApp.curReceivers.contains(r)) {
r.curApp.curReceivers.remove(r);
+ mService.enqueueOomAdjTargetLocked(r.curApp);
}
if (r.curFilter != null) {
r.curFilter.receiverList.curBroadcast = null;
@@ -562,7 +565,7 @@ public final class BroadcastQueue {
Slog.i(TAG, "Resuming delayed broadcast");
br.curComponent = null;
br.state = BroadcastRecord.IDLE;
- processNextBroadcast(false);
+ processNextBroadcastLocked(false, false);
}
}
}
@@ -604,7 +607,7 @@ public final class BroadcastQueue {
}
private void deliverToRegisteredReceiverLocked(BroadcastRecord r,
- BroadcastFilter filter, boolean ordered, int index, boolean skipOomAdj) {
+ BroadcastFilter filter, boolean ordered, int index) {
boolean skip = false;
if (!mService.validateAssociationAllowedLocked(r.callerPackage, r.callingUid,
filter.packageName, filter.owningUid)) {
@@ -790,10 +793,9 @@ public final class BroadcastQueue {
// are already core system stuff so don't matter for this.
r.curApp = filter.receiverList.app;
filter.receiverList.app.curReceivers.add(r);
- if (!skipOomAdj) {
- mService.updateOomAdjLocked(r.curApp, true,
- OomAdjuster.OOM_ADJ_REASON_START_RECEIVER);
- }
+ mService.enqueueOomAdjTargetLocked(r.curApp);
+ mService.updateOomAdjPendingTargetsLocked(
+ OomAdjuster.OOM_ADJ_REASON_START_RECEIVER);
}
}
try {
@@ -827,6 +829,8 @@ public final class BroadcastQueue {
filter.receiverList.app.removeAllowBackgroundActivityStartsToken(r);
if (ordered) {
filter.receiverList.app.curReceivers.remove(r);
+ // Something wrong, its oom adj could be downgraded, but not in a hurry.
+ mService.enqueueOomAdjTargetLocked(r.curApp);
}
}
// And BroadcastRecord state related to ordered delivery, if appropriate
@@ -946,7 +950,7 @@ public final class BroadcastQueue {
return true;
}
- final void processNextBroadcast(boolean fromMsg) {
+ private void processNextBroadcast(boolean fromMsg) {
synchronized (mService) {
processNextBroadcastLocked(fromMsg, false);
}
@@ -990,7 +994,7 @@ public final class BroadcastQueue {
"Delivering non-ordered on [" + mQueueName + "] to registered "
+ target + ": " + r);
deliverToRegisteredReceiverLocked(r,
- (BroadcastFilter) target, false, i, skipOomAdj);
+ (BroadcastFilter) target, false, i);
}
addBroadcastToHistoryLocked(r);
if (DEBUG_BROADCAST_LIGHT) Slog.v(TAG_BROADCAST, "Done with parallel broadcast ["
@@ -1046,7 +1050,8 @@ public final class BroadcastQueue {
// If we had finished the last ordered broadcast, then
// make sure all processes have correct oom and sched
// adjustments.
- mService.updateOomAdjLocked(OomAdjuster.OOM_ADJ_REASON_START_RECEIVER);
+ mService.updateOomAdjPendingTargetsLocked(
+ OomAdjuster.OOM_ADJ_REASON_START_RECEIVER);
}
// when we have no more ordered broadcast on this queue, stop logging
@@ -1288,7 +1293,7 @@ public final class BroadcastQueue {
"Delivering ordered ["
+ mQueueName + "] to registered "
+ filter + ": " + r);
- deliverToRegisteredReceiverLocked(r, filter, r.ordered, recIdx, skipOomAdj);
+ deliverToRegisteredReceiverLocked(r, filter, r.ordered, recIdx);
if (r.receiver == null || !r.ordered) {
// The receiver has already finished, so schedule to
// process the next one.
@@ -1616,7 +1621,7 @@ public final class BroadcastQueue {
app.addPackage(info.activityInfo.packageName,
info.activityInfo.applicationInfo.longVersionCode, mService.mProcessStats);
maybeAddAllowBackgroundActivityStartsToken(app, r);
- processCurBroadcastLocked(r, app, skipOomAdj);
+ processCurBroadcastLocked(r, app);
return;
} catch (RemoteException e) {
Slog.w(TAG, "Exception when sending broadcast to "
@@ -1750,7 +1755,7 @@ public final class BroadcastQueue {
? r.curComponent.flattenToShortString() : "(null)"));
r.curComponent = null;
r.state = BroadcastRecord.IDLE;
- processNextBroadcast(false);
+ processNextBroadcastLocked(false, false);
return;
}
diff --git a/services/core/java/com/android/server/am/CachedAppOptimizer.java b/services/core/java/com/android/server/am/CachedAppOptimizer.java
index d9fde0f6728a..c5047e5eed03 100644
--- a/services/core/java/com/android/server/am/CachedAppOptimizer.java
+++ b/services/core/java/com/android/server/am/CachedAppOptimizer.java
@@ -208,6 +208,8 @@ public final class CachedAppOptimizer {
@GuardedBy("mPhenotypeFlagLock")
private volatile boolean mUseCompaction = DEFAULT_USE_COMPACTION;
private volatile boolean mUseFreezer = DEFAULT_USE_FREEZER;
+ @GuardedBy("this")
+ private int mFreezerDisableCount = 1; // Freezer is initially disabled, until enabled
private final Random mRandom = new Random();
@GuardedBy("mPhenotypeFlagLock")
@VisibleForTesting volatile float mCompactStatsdSampleRate = DEFAULT_STATSD_SAMPLE_RATE;
@@ -420,25 +422,82 @@ public final class CachedAppOptimizer {
}
/**
- * Determines whether the freezer is correctly supported by this system
+ * Enables or disabled the app freezer.
+ * @param enable Enables the freezer if true, disables it if false.
+ * @return true if the operation completed successfully, false otherwise.
+ */
+ public synchronized boolean enableFreezer(boolean enable) {
+ if (!mUseFreezer) {
+ return false;
+ }
+
+ if (enable) {
+ mFreezerDisableCount--;
+
+ if (mFreezerDisableCount > 0) {
+ return true;
+ } else if (mFreezerDisableCount < 0) {
+ Slog.e(TAG_AM, "unbalanced call to enableFreezer, ignoring");
+ mFreezerDisableCount = 0;
+ return false;
+ }
+ } else {
+ mFreezerDisableCount++;
+
+ if (mFreezerDisableCount > 1) {
+ return true;
+ }
+ }
+
+ try {
+ enableFreezerInternal(enable);
+ return true;
+ } catch (java.lang.RuntimeException e) {
+ if (enable) {
+ mFreezerDisableCount = 0;
+ } else {
+ mFreezerDisableCount = 1;
+ }
+
+ Slog.e(TAG_AM, "Exception handling freezer state (enable: " + enable + "): "
+ + e.toString());
+ }
+
+ return false;
+ }
+
+ /**
+ * Enable or disable the freezer. When enable == false all frozen processes are unfrozen,
+ * but aren't removed from the freezer. While in this state, processes can be added or removed
+ * by using Process.setProcessFrozen(), but they wouldn't be actually frozen until the freezer
+ * is enabled. If enable == true all processes in the freezer are frozen.
+ *
+ * @param enable Specify whether to enable (true) or disable (false) the freezer.
+ *
+ * @hide
+ */
+ private static native void enableFreezerInternal(boolean enable);
+
+ /**
+ * Determines whether the freezer is supported by this system
*/
public static boolean isFreezerSupported() {
boolean supported = false;
FileReader fr = null;
try {
- fr = new FileReader("/dev/freezer/frozen/freezer.killable");
- int i = fr.read();
+ fr = new FileReader("/sys/fs/cgroup/freezer/cgroup.freeze");
+ char state = (char) fr.read();
- if ((char) i == '1') {
+ if (state == '1' || state == '0') {
supported = true;
} else {
- Slog.w(TAG_AM, "Freezer killability is turned off, disabling freezer");
+ Slog.e(TAG_AM, "unexpected value in cgroup.freeze");
}
} catch (java.io.FileNotFoundException e) {
- Slog.d(TAG_AM, "Freezer.killable not present, disabling freezer");
+ Slog.d(TAG_AM, "cgroup.freeze not present");
} catch (Exception e) {
- Slog.d(TAG_AM, "Unable to read freezer.killable, disabling freezer: " + e.toString());
+ Slog.d(TAG_AM, "unable to read cgroup.freeze: " + e.toString());
}
if (fr != null) {
@@ -471,6 +530,8 @@ public final class CachedAppOptimizer {
if (mUseFreezer && mFreezeHandler == null) {
Slog.d(TAG_AM, "Freezer enabled");
+ enableFreezer(true);
+
if (!mCachedAppOptimizerThread.isAlive()) {
mCachedAppOptimizerThread.start();
}
@@ -479,6 +540,8 @@ public final class CachedAppOptimizer {
Process.setThreadGroupAndCpuset(mCachedAppOptimizerThread.getThreadId(),
Process.THREAD_GROUP_SYSTEM);
+ } else {
+ enableFreezer(false);
}
}
diff --git a/services/core/java/com/android/server/am/ContentProviderHelper.java b/services/core/java/com/android/server/am/ContentProviderHelper.java
index bfba4afcd4e4..1155569c6b36 100644
--- a/services/core/java/com/android/server/am/ContentProviderHelper.java
+++ b/services/core/java/com/android/server/am/ContentProviderHelper.java
@@ -198,22 +198,10 @@ public class ContentProviderHelper {
if (providerRunning) {
cpi = cpr.info;
- String msg;
if (r != null && cpr.canRunHere(r)) {
- if ((msg = checkContentProviderAssociation(r, callingUid, cpi)) != null) {
- throw new SecurityException("Content provider lookup "
- + cpr.name.flattenToShortString()
- + " failed: association not allowed with package " + msg);
- }
- checkTime(startTime,
- "getContentProviderImpl: before checkContentProviderPermission");
- if ((msg = checkContentProviderPermissionLocked(cpi, r, userId, checkCrossUser))
- != null) {
- throw new SecurityException(msg);
- }
- checkTime(startTime,
- "getContentProviderImpl: after checkContentProviderPermission");
+ checkAssociationAndPermissionLocked(r, cpi, callingUid, userId, checkCrossUser,
+ cpr.name.flattenToShortString(), startTime);
// This provider has been published or is in the process
// of being published... but it is also allowed to run
@@ -234,26 +222,14 @@ public class ContentProviderHelper {
} catch (RemoteException e) {
}
- if ((msg = checkContentProviderAssociation(r, callingUid, cpi)) != null) {
- throw new SecurityException(
- "Content provider lookup " + cpr.name.flattenToShortString()
- + " failed: association not allowed with package " + msg);
- }
- checkTime(startTime,
- "getContentProviderImpl: before checkContentProviderPermission");
- if ((msg = checkContentProviderPermissionLocked(cpi, r, userId, checkCrossUser))
- != null) {
- throw new SecurityException(msg);
- }
- checkTime(startTime,
- "getContentProviderImpl: after checkContentProviderPermission");
+ checkAssociationAndPermissionLocked(r, cpi, callingUid, userId, checkCrossUser,
+ cpr.name.flattenToShortString(), startTime);
final long origId = Binder.clearCallingIdentity();
checkTime(startTime, "getContentProviderImpl: incProviderCountLocked");
- // In this case the provider instance already exists, so we can
- // return it right away.
+ // In this case the provider instance already exists so we can return it right away.
conn = incProviderCountLocked(r, cpr, token, callingUid, callingPackage, callingTag,
stable, true, startTime, mService.mProcessList);
@@ -328,19 +304,8 @@ public class ContentProviderHelper {
cpi.applicationInfo = mService.getAppInfoForUser(cpi.applicationInfo, userId);
checkTime(startTime, "getContentProviderImpl: got app info for user");
- String msg;
- if ((msg = checkContentProviderAssociation(r, callingUid, cpi)) != null) {
- throw new SecurityException("Content provider lookup " + name
- + " failed: association not allowed with package " + msg);
- }
- checkTime(startTime,
- "getContentProviderImpl: before checkContentProviderPermission");
- if ((msg = checkContentProviderPermissionLocked(cpi, r, userId, !singleton))
- != null) {
- throw new SecurityException(msg);
- }
- checkTime(startTime,
- "getContentProviderImpl: after checkContentProviderPermission");
+ checkAssociationAndPermissionLocked(r, cpi, callingUid, userId, !singleton,
+ name, startTime);
if (!mService.mProcessesReady && !cpi.processName.equals("system")) {
// If this content provider does not run in the system
@@ -352,10 +317,12 @@ public class ContentProviderHelper {
// If system providers are not installed yet we aggressively crash to avoid
// creating multiple instance of these providers and then bad things happen!
- if (!mSystemProvidersInstalled && cpi.applicationInfo.isSystemApp()
- && "system".equals(cpi.processName)) {
- throw new IllegalStateException("Cannot access system provider: '"
- + cpi.authority + "' before system providers are installed!");
+ synchronized (this) {
+ if (!mSystemProvidersInstalled && cpi.applicationInfo.isSystemApp()
+ && "system".equals(cpi.processName)) {
+ throw new IllegalStateException("Cannot access system provider: '"
+ + cpi.authority + "' before system providers are installed!");
+ }
}
// Make sure that the user who owns this provider is running. If not,
@@ -605,6 +572,23 @@ public class ContentProviderHelper {
return cpr.newHolder(conn, false);
}
+ private void checkAssociationAndPermissionLocked(ProcessRecord callingApp, ProviderInfo cpi,
+ int callingUid, int userId, boolean checkUser, String cprName, long startTime) {
+ String msg;
+ if ((msg = checkContentProviderAssociation(callingApp, callingUid, cpi)) != null) {
+ throw new SecurityException("Content provider lookup " + cprName
+ + " failed: association not allowed with package " + msg);
+ }
+ checkTime(startTime, "getContentProviderImpl: before checkContentProviderPermission");
+ if ((msg = checkContentProviderPermission(
+ cpi, Binder.getCallingPid(), Binder.getCallingUid(), userId, checkUser,
+ callingApp != null ? callingApp.toString() : null))
+ != null) {
+ throw new SecurityException(msg);
+ }
+ checkTime(startTime, "getContentProviderImpl: after checkContentProviderPermission");
+ }
+
void publishContentProviders(IApplicationThread caller, List<ContentProviderHolder> providers) {
if (providers == null) {
return;
@@ -623,7 +607,7 @@ public class ContentProviderHelper {
}
final long origId = Binder.clearCallingIdentity();
-
+ boolean providersPublished = false;
for (int i = 0, size = providers.size(); i < size; i++) {
ContentProviderHolder src = providers.get(i);
if (src == null || src.info == null || src.provider == null) {
@@ -636,6 +620,7 @@ public class ContentProviderHelper {
if (DEBUG_MU) {
Slog.v(TAG_MU, "ContentProviderRecord uid = " + dst.uid);
}
+ providersPublished = true;
ComponentName comp = new ComponentName(dst.info.packageName, dst.info.name);
mProviderMap.putProviderByClass(comp, dst);
@@ -673,8 +658,19 @@ public class ContentProviderHelper {
dst.onProviderPublishStatusLocked(true);
}
dst.mRestartCount = 0;
+ }
+
+ // update the app's oom adj value and each provider's usage stats
+ if (providersPublished) {
mService.updateOomAdjLocked(r, true, OomAdjuster.OOM_ADJ_REASON_GET_PROVIDER);
- maybeUpdateProviderUsageStatsLocked(r, src.info.packageName, src.info.authority);
+ for (int i = 0, size = providers.size(); i < size; i++) {
+ ContentProviderHolder src = providers.get(i);
+ if (src == null || src.info == null || src.provider == null) {
+ continue;
+ }
+ maybeUpdateProviderUsageStatsLocked(r,
+ src.info.packageName, src.info.authority);
+ }
}
Binder.restoreCallingIdentity(origId);
@@ -702,7 +698,8 @@ public class ContentProviderHelper {
throw new NullPointerException("connection is null");
}
if (decProviderCountLocked(conn, null, null, stable)) {
- mService.updateOomAdjLocked(OomAdjuster.OOM_ADJ_REASON_REMOVE_PROVIDER);
+ mService.updateOomAdjLocked(conn.provider.proc,
+ OomAdjuster.OOM_ADJ_REASON_REMOVE_PROVIDER);
}
}
} finally {
@@ -738,7 +735,8 @@ public class ContentProviderHelper {
ContentProviderRecord localCpr = mProviderMap.getProviderByClass(comp, userId);
if (localCpr.hasExternalProcessHandles()) {
if (localCpr.removeExternalProcessHandleLocked(token)) {
- mService.updateOomAdjLocked(OomAdjuster.OOM_ADJ_REASON_REMOVE_PROVIDER);
+ mService.updateOomAdjLocked(localCpr.proc,
+ OomAdjuster.OOM_ADJ_REASON_REMOVE_PROVIDER);
} else {
Slog.e(TAG, "Attempt to remove content provider " + localCpr
+ " with no external reference for token: " + token + ".");
@@ -997,17 +995,19 @@ public class ContentProviderHelper {
+ "; expected to find a valid ContentProvider for this authority";
}
+ final int callingPid = Binder.getCallingPid();
ProcessRecord r;
+ final String appName;
synchronized (mService.mPidsSelfLocked) {
- r = mService.mPidsSelfLocked.get(Binder.getCallingPid());
- }
- if (r == null) {
- return "Failed to find PID " + Binder.getCallingPid();
+ r = mService.mPidsSelfLocked.get(callingPid);
+ if (r == null) {
+ return "Failed to find PID " + callingPid;
+ }
+ appName = r.toString();
}
- synchronized (mService) {
- return checkContentProviderPermissionLocked(cpi, r, userId, true);
- }
+ return checkContentProviderPermission(cpi, callingPid, Binder.getCallingUid(),
+ userId, true, appName);
}
int checkContentProviderUriPermission(Uri uri, int userId, int callingUid, int modeFlags) {
@@ -1163,13 +1163,14 @@ public class ContentProviderHelper {
}
}
}
- if (providers != null) {
- mService.mSystemThread.installSystemProviders(providers);
- }
- synchronized (mService) {
+ synchronized (this) {
+ if (providers != null) {
+ mService.mSystemThread.installSystemProviders(providers);
+ }
mSystemProvidersInstalled = true;
}
+
mService.mConstants.start(mService.mContext.getContentResolver());
mService.mCoreSettingsObserver = new CoreSettingsObserver(mService);
mService.mActivityTaskManager.installSystemProviders();
@@ -1305,10 +1306,8 @@ public class ContentProviderHelper {
* given {@link ProviderInfo}. Final permission checking is always done
* in {@link ContentProvider}.
*/
- private String checkContentProviderPermissionLocked(ProviderInfo cpi, ProcessRecord r,
- int userId, boolean checkUser) {
- final int callingPid = (r != null) ? r.pid : Binder.getCallingPid();
- final int callingUid = (r != null) ? r.uid : Binder.getCallingUid();
+ private String checkContentProviderPermission(ProviderInfo cpi, int callingPid, int callingUid,
+ int userId, boolean checkUser, String appName) {
boolean checkedGrants = false;
if (checkUser) {
// Looking for cross-user grants before enforcing the typical cross-users permissions
@@ -1376,8 +1375,8 @@ public class ContentProviderHelper {
suffix = " requires " + cpi.readPermission + " or " + cpi.writePermission;
}
final String msg = "Permission Denial: opening provider " + cpi.name
- + " from " + (r != null ? r : "(null)") + " (pid=" + callingPid
- + ", uid=" + callingUid + ")" + suffix;
+ + " from " + (appName != null ? appName : "(null)")
+ + " (pid=" + callingPid + ", uid=" + callingUid + ")" + suffix;
Slog.w(TAG, msg);
return msg;
}
@@ -1398,18 +1397,17 @@ public class ContentProviderHelper {
}
ProviderInfo getProviderInfoLocked(String authority, @UserIdInt int userId, int pmFlags) {
- ProviderInfo pi = null;
ContentProviderRecord cpr = mProviderMap.getProviderByName(authority, userId);
if (cpr != null) {
- pi = cpr.info;
+ return cpr.info;
} else {
try {
- pi = AppGlobals.getPackageManager().resolveContentProvider(
+ return AppGlobals.getPackageManager().resolveContentProvider(
authority, PackageManager.GET_URI_PERMISSION_PATTERNS | pmFlags, userId);
} catch (RemoteException ex) {
+ return null;
}
}
- return pi;
}
private void maybeUpdateProviderUsageStatsLocked(ProcessRecord app, String providerPkgName,
@@ -1419,7 +1417,6 @@ public class ContentProviderHelper {
return;
}
-
UserState userState = mService.mUserController.getStartedUserState(app.userId);
if (userState == null) return;
final long now = SystemClock.elapsedRealtime();
diff --git a/services/core/java/com/android/server/am/OomAdjuster.java b/services/core/java/com/android/server/am/OomAdjuster.java
index bad042cd3a68..fc330313373e 100644
--- a/services/core/java/com/android/server/am/OomAdjuster.java
+++ b/services/core/java/com/android/server/am/OomAdjuster.java
@@ -81,6 +81,7 @@ import android.content.ComponentName;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
+import android.content.pm.ApplicationInfo;
import android.content.pm.ServiceInfo;
import android.os.Debug;
import android.os.Handler;
@@ -94,6 +95,8 @@ import android.os.Trace;
import android.os.UserHandle;
import android.util.ArrayMap;
import android.util.ArraySet;
+import android.util.LongSparseArray;
+import android.util.Pair;
import android.util.Slog;
import android.util.proto.ProtoOutputStream;
@@ -103,10 +106,13 @@ import com.android.internal.app.procstats.ProcessStats;
import com.android.internal.compat.IPlatformCompat;
import com.android.server.LocalServices;
import com.android.server.ServiceThread;
+import com.android.server.compat.CompatChange;
+import com.android.server.compat.PlatformCompat;
import com.android.server.wm.ActivityServiceConnectionsHolder;
import com.android.server.wm.WindowProcessController;
import java.io.PrintWriter;
+import java.lang.ref.WeakReference;
import java.util.ArrayDeque;
import java.util.ArrayList;
import java.util.Arrays;
@@ -209,12 +215,99 @@ public final class OomAdjuster {
private final ProcessList mProcessList;
private final int mNumSlots;
- private ArrayList<ProcessRecord> mTmpProcessList = new ArrayList<ProcessRecord>();
- private ArrayList<UidRecord> mTmpBecameIdle = new ArrayList<UidRecord>();
- private ActiveUids mTmpUidRecords;
- private ArrayDeque<ProcessRecord> mTmpQueue;
+ private final ArrayList<ProcessRecord> mTmpProcessList = new ArrayList<ProcessRecord>();
+ private final ArrayList<UidRecord> mTmpBecameIdle = new ArrayList<UidRecord>();
+ private final ActiveUids mTmpUidRecords;
+ private final ArrayDeque<ProcessRecord> mTmpQueue;
+ private final ArraySet<ProcessRecord> mPendingProcessSet = new ArraySet<>();
+
+ private final PlatformCompatCache mPlatformCompatCache;
+
+ private static class PlatformCompatCache {
+ private final PlatformCompat mPlatformCompat;
+ private final IPlatformCompat mIPlatformCompatProxy;
+ private final LongSparseArray<CacheItem> mCaches = new LongSparseArray<>();
+ private final boolean mCacheEnabled;
+
+ PlatformCompatCache(long[] compatChanges) {
+ IBinder b = ServiceManager.getService(Context.PLATFORM_COMPAT_SERVICE);
+ if (b instanceof PlatformCompat) {
+ mPlatformCompat = (PlatformCompat) ServiceManager.getService(
+ Context.PLATFORM_COMPAT_SERVICE);
+ for (long changeId: compatChanges) {
+ mCaches.put(changeId, new CacheItem(mPlatformCompat, changeId));
+ }
+ mIPlatformCompatProxy = null;
+ mCacheEnabled = true;
+ } else {
+ // we are in UT where the platform_compat is not running within the same process
+ mIPlatformCompatProxy = IPlatformCompat.Stub.asInterface(b);
+ mPlatformCompat = null;
+ mCacheEnabled = false;
+ }
+ }
+
+ boolean isChangeEnabled(long changeId, ApplicationInfo app) throws RemoteException {
+ return mCacheEnabled ? mCaches.get(changeId).isChangeEnabled(app)
+ : mIPlatformCompatProxy.isChangeEnabled(changeId, app);
+ }
+
+ void invalidate(ApplicationInfo app) {
+ for (int i = mCaches.size() - 1; i >= 0; i--) {
+ mCaches.valueAt(i).invalidate(app);
+ }
+ }
+
+ static class CacheItem implements CompatChange.ChangeListener {
+ private final PlatformCompat mPlatformCompat;
+ private final long mChangeId;
+ private final Object mLock = new Object();
+
+ private final ArrayMap<String, Pair<Boolean, WeakReference<ApplicationInfo>>> mCache =
+ new ArrayMap<>();
+
+ CacheItem(PlatformCompat platformCompat, long changeId) {
+ mPlatformCompat = platformCompat;
+ mChangeId = changeId;
+ mPlatformCompat.registerListener(changeId, this);
+ }
+
+ boolean isChangeEnabled(ApplicationInfo app) {
+ synchronized (mLock) {
+ final int index = mCache.indexOfKey(app.packageName);
+ Pair<Boolean, WeakReference<ApplicationInfo>> p;
+ if (index < 0) {
+ p = new Pair<>(mPlatformCompat.isChangeEnabled(mChangeId, app),
+ new WeakReference<>(app));
+ mCache.put(app.packageName, p);
+ return p.first;
+ }
+ p = mCache.valueAt(index);
+ if (p.second.get() == app) {
+ return p.first;
+ }
+ // Cache is invalid, regenerate it
+ p = new Pair<>(mPlatformCompat.isChangeEnabled(mChangeId, app),
+ new WeakReference<>(app));
+ mCache.setValueAt(index, p);
+ return p.first;
+ }
+ }
- private final IPlatformCompat mPlatformCompat;
+ void invalidate(ApplicationInfo app) {
+ synchronized (mLock) {
+ mCache.remove(app.packageName);
+ }
+ }
+
+ @Override
+ public void onCompatChange(String packageName) {
+ synchronized (mLock) {
+ mCache.remove(packageName);
+ }
+ }
+ }
+ }
OomAdjuster(ActivityManagerService service, ProcessList processList, ActiveUids activeUids) {
this(service, processList, activeUids, createAdjusterThread());
@@ -263,8 +356,9 @@ public final class OomAdjuster {
mTmpQueue = new ArrayDeque<ProcessRecord>(mConstants.CUR_MAX_CACHED_PROCESSES << 1);
mNumSlots = ((ProcessList.CACHED_APP_MAX_ADJ - ProcessList.CACHED_APP_MIN_ADJ + 1) >> 1)
/ ProcessList.CACHED_APP_IMPORTANCE_LEVELS;
- IBinder b = ServiceManager.getService(Context.PLATFORM_COMPAT_SERVICE);
- mPlatformCompat = IPlatformCompat.Stub.asInterface(b);
+ mPlatformCompatCache = new PlatformCompatCache(new long[] {
+ PROCESS_CAPABILITY_CHANGE_ID, CAMERA_MICROPHONE_CAPABILITY_CHANGE_ID
+ });
}
void initSettings() {
@@ -333,6 +427,8 @@ public final class OomAdjuster {
// need to do a complete oom adj.
final int cachedAdj = app.getCurRawAdj() >= ProcessList.CACHED_APP_MIN_ADJ
? app.getCurRawAdj() : ProcessList.UNKNOWN_ADJ;
+ // Check if this process is in the pending list too, remove from pending list if so.
+ mPendingProcessSet.remove(app);
boolean success = updateOomAdjLocked(app, cachedAdj, TOP_APP, false,
SystemClock.uptimeMillis());
if (oomAdjAll
@@ -360,6 +456,9 @@ public final class OomAdjuster {
uidRec.reset();
}
+ // Check if this process is in the pending list too, remove from pending list if so.
+ mPendingProcessSet.remove(app);
+
computeOomAdjLocked(app, cachedAdj, TOP_APP, doingAll, now, false, true);
boolean success = applyOomAdjLocked(app, doingAll, now, SystemClock.elapsedRealtime());
@@ -401,6 +500,8 @@ public final class OomAdjuster {
@GuardedBy("mService")
void updateOomAdjLocked(String oomAdjReason) {
final ProcessRecord topApp = mService.getTopAppLocked();
+ // Clear any pending ones because we are doing a full update now.
+ mPendingProcessSet.clear();
updateOomAdjLockedInner(oomAdjReason, topApp , null, null, true, true);
}
@@ -434,6 +535,8 @@ public final class OomAdjuster {
app.containsCycle = false;
app.procStateChanged = false;
app.resetCachedInfo();
+ // Check if this process is in the pending list too, remove from pending list if so.
+ mPendingProcessSet.remove(app);
boolean success = updateOomAdjLocked(app, cachedAdj, topApp, false,
SystemClock.uptimeMillis());
if (!success || (wasCached == app.isCached() && oldAdj != ProcessList.INVALID_ADJ
@@ -486,6 +589,10 @@ public final class OomAdjuster {
}
queue.offer(service);
service.mReachable = true;
+ // During scanning the reachable dependants, remove them from the pending oomadj
+ // targets list if it's possible, as they've been added into the immediate
+ // oomadj targets list 'processes' above.
+ mPendingProcessSet.remove(service);
}
for (int i = pr.conProviders.size() - 1; i >= 0; i--) {
ContentProviderConnection cpc = pr.conProviders.get(i);
@@ -499,6 +606,10 @@ public final class OomAdjuster {
}
queue.offer(provider);
provider.mReachable = true;
+ // During scanning the reachable dependants, remove them from the pending oomadj
+ // targets list if it's possible, as they've been added into the immediate
+ // oomadj targets list 'processes' above.
+ mPendingProcessSet.remove(provider);
}
}
@@ -523,12 +634,67 @@ public final class OomAdjuster {
applyOomAdjLocked(app, false, SystemClock.uptimeMillis(),
SystemClock.elapsedRealtime());
}
+ mTmpProcessList.clear();
mService.mOomAdjProfiler.oomAdjEnded();
Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER);
return true;
}
/**
+ * Enqueue the given process for a later oom adj update
+ */
+ @GuardedBy("mService")
+ void enqueueOomAdjTargetLocked(ProcessRecord app) {
+ if (app != null) {
+ mPendingProcessSet.add(app);
+ }
+ }
+
+ @GuardedBy("mService")
+ void removeOomAdjTargetLocked(ProcessRecord app, boolean procDied) {
+ if (app != null) {
+ mPendingProcessSet.remove(app);
+ if (procDied) {
+ mPlatformCompatCache.invalidate(app.info);
+ }
+ }
+ }
+
+ /**
+ * Kick off an oom adj update pass for the pending targets which are enqueued via
+ * {@link #enqueueOomAdjTargetLocked}.
+ */
+ @GuardedBy("mService")
+ void updateOomAdjPendingTargetsLocked(String oomAdjReason) {
+ if (mPendingProcessSet.isEmpty()) {
+ return;
+ }
+ final ProcessRecord topApp = mService.getTopAppLocked();
+
+ Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER, oomAdjReason);
+ mService.mOomAdjProfiler.oomAdjStarted();
+
+ final ArrayList<ProcessRecord> processes = mTmpProcessList;
+ final ActiveUids uids = mTmpUidRecords;
+ uids.clear();
+ processes.clear();
+ for (int i = mPendingProcessSet.size() - 1; i >= 0; i--) {
+ final ProcessRecord app = mPendingProcessSet.valueAt(i);
+ if (app.uidRecord != null) {
+ uids.put(app.uidRecord.uid, app.uidRecord);
+ }
+ processes.add(app);
+ }
+
+ updateOomAdjLockedInner(oomAdjReason, topApp, processes, uids, true, false);
+ processes.clear();
+ mPendingProcessSet.clear();
+
+ mService.mOomAdjProfiler.oomAdjEnded();
+ Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER);
+ }
+
+ /**
* Update OomAdj for all processes within the given list (could be partial), or the whole LRU
* list if the given list is null; when it's partial update, each process's client proc won't
* get evaluated recursively here.
@@ -1555,7 +1721,7 @@ public final class OomAdjuster {
boolean enabled = false;
try {
- enabled = mPlatformCompat.isChangeEnabled(
+ enabled = mPlatformCompatCache.isChangeEnabled(
CAMERA_MICROPHONE_CAPABILITY_CHANGE_ID, s.appInfo);
} catch (RemoteException e) {
}
@@ -1742,7 +1908,7 @@ public final class OomAdjuster {
clientProcState = PROCESS_STATE_BOUND_TOP;
boolean enabled = false;
try {
- enabled = mPlatformCompat.isChangeEnabled(
+ enabled = mPlatformCompatCache.isChangeEnabled(
PROCESS_CAPABILITY_CHANGE_ID, client.info);
} catch (RemoteException e) {
}
diff --git a/services/core/java/com/android/server/am/ProcessList.java b/services/core/java/com/android/server/am/ProcessList.java
index 76089f8fba01..87898d80bd46 100644
--- a/services/core/java/com/android/server/am/ProcessList.java
+++ b/services/core/java/com/android/server/am/ProcessList.java
@@ -1528,15 +1528,18 @@ public final class ProcessList {
&& proc.setProcState >= ActivityManager.PROCESS_STATE_CACHED_EMPTY
&& proc.lastCachedPss >= 4000) {
// Turn this condition on to cause killing to happen regularly, for testing.
- if (proc.baseProcessTracker != null) {
- proc.baseProcessTracker.reportCachedKill(proc.pkgList.mPkgList, proc.lastCachedPss);
- for (int ipkg = proc.pkgList.size() - 1; ipkg >= 0; ipkg--) {
- ProcessStats.ProcessStateHolder holder = proc.pkgList.valueAt(ipkg);
- FrameworkStatsLog.write(FrameworkStatsLog.CACHED_KILL_REPORTED,
- proc.info.uid,
- holder.state.getName(),
- holder.state.getPackage(),
- proc.lastCachedPss, holder.appVersion);
+ synchronized (mService.mProcessStats.mLock) {
+ if (proc.baseProcessTracker != null) {
+ proc.baseProcessTracker.reportCachedKill(
+ proc.pkgList.mPkgList, proc.lastCachedPss);
+ for (int ipkg = proc.pkgList.size() - 1; ipkg >= 0; ipkg--) {
+ ProcessStats.ProcessStateHolder holder = proc.pkgList.valueAt(ipkg);
+ FrameworkStatsLog.write(FrameworkStatsLog.CACHED_KILL_REPORTED,
+ proc.info.uid,
+ holder.state.getName(),
+ holder.state.getPackage(),
+ proc.lastCachedPss, holder.appVersion);
+ }
}
}
proc.kill(Long.toString(proc.lastCachedPss) + "k from cached",
@@ -1549,16 +1552,18 @@ public final class ProcessList {
if (DEBUG_PSS) Slog.d(TAG_PSS, "May not keep " + proc + ": pss=" + proc
.lastCachedPss);
if (proc.lastCachedPss >= getCachedRestoreThresholdKb()) {
- if (proc.baseProcessTracker != null) {
- proc.baseProcessTracker.reportCachedKill(proc.pkgList.mPkgList,
- proc.lastCachedPss);
- for (int ipkg = proc.pkgList.size() - 1; ipkg >= 0; ipkg--) {
- ProcessStats.ProcessStateHolder holder = proc.pkgList.valueAt(ipkg);
- FrameworkStatsLog.write(FrameworkStatsLog.CACHED_KILL_REPORTED,
- proc.info.uid,
- holder.state.getName(),
- holder.state.getPackage(),
- proc.lastCachedPss, holder.appVersion);
+ synchronized (mService.mProcessStats.mLock) {
+ if (proc.baseProcessTracker != null) {
+ proc.baseProcessTracker.reportCachedKill(proc.pkgList.mPkgList,
+ proc.lastCachedPss);
+ for (int ipkg = proc.pkgList.size() - 1; ipkg >= 0; ipkg--) {
+ ProcessStats.ProcessStateHolder holder = proc.pkgList.valueAt(ipkg);
+ FrameworkStatsLog.write(FrameworkStatsLog.CACHED_KILL_REPORTED,
+ proc.info.uid,
+ holder.state.getName(),
+ holder.state.getPackage(),
+ proc.lastCachedPss, holder.appVersion);
+ }
}
}
proc.kill(Long.toString(proc.lastCachedPss) + "k from cached",
@@ -2360,7 +2365,7 @@ public final class ProcessList {
if ((intentFlags & Intent.FLAG_FROM_BACKGROUND) != 0) {
// If we are in the background, then check to see if this process
// is bad. If so, we will just silently fail.
- if (mService.mAppErrors.isBadProcessLocked(processName, info.uid)) {
+ if (mService.mAppErrors.isBadProcess(processName, info.uid)) {
if (DEBUG_PROCESSES) Slog.v(TAG, "Bad process: " + info.uid
+ "/" + processName);
return null;
@@ -2373,11 +2378,11 @@ public final class ProcessList {
if (DEBUG_PROCESSES) Slog.v(TAG, "Clearing bad process: " + info.uid
+ "/" + processName);
mService.mAppErrors.resetProcessCrashTimeLocked(processName, info.uid);
- if (mService.mAppErrors.isBadProcessLocked(processName, info.uid)) {
+ if (mService.mAppErrors.isBadProcess(processName, info.uid)) {
EventLog.writeEvent(EventLogTags.AM_PROC_GOOD,
UserHandle.getUserId(info.uid), info.uid,
info.processName);
- mService.mAppErrors.clearBadProcessLocked(processName, info.uid);
+ mService.mAppErrors.clearBadProcess(processName, info.uid);
if (app != null) {
app.bad = false;
}
@@ -2636,6 +2641,7 @@ public final class ProcessList {
mLruProcessServiceStart--;
}
mLruProcesses.remove(lrui);
+ mService.removeOomAdjTargetLocked(app, true);
}
}
diff --git a/services/core/java/com/android/server/audio/AudioDeviceBroker.java b/services/core/java/com/android/server/audio/AudioDeviceBroker.java
index 06ef58f8cc61..1615998f7787 100644
--- a/services/core/java/com/android/server/audio/AudioDeviceBroker.java
+++ b/services/core/java/com/android/server/audio/AudioDeviceBroker.java
@@ -28,6 +28,7 @@ import android.media.AudioDeviceAttributes;
import android.media.AudioRoutesInfo;
import android.media.AudioSystem;
import android.media.IAudioRoutesObserver;
+import android.media.ICapturePresetDevicesRoleDispatcher;
import android.media.IStrategyPreferredDevicesDispatcher;
import android.media.MediaMetrics;
import android.os.Binder;
@@ -500,8 +501,8 @@ import java.util.concurrent.atomic.AtomicBoolean;
sendIIMsgNoDelay(MSG_II_SET_HEARING_AID_VOLUME, SENDMSG_REPLACE, index, streamType);
}
- /*package*/ void postSetModeOwnerPid(int pid) {
- sendIMsgNoDelay(MSG_I_SET_MODE_OWNER_PID, SENDMSG_REPLACE, pid);
+ /*package*/ void postSetModeOwnerPid(int pid, int mode) {
+ sendIIMsgNoDelay(MSG_I_SET_MODE_OWNER_PID, SENDMSG_REPLACE, pid, mode);
}
/*package*/ void postBluetoothA2dpDeviceConfigChange(@NonNull BluetoothDevice device) {
@@ -546,6 +547,25 @@ import java.util.concurrent.atomic.AtomicBoolean;
mDeviceInventory.unregisterStrategyPreferredDevicesDispatcher(dispatcher);
}
+ /*package*/ int setPreferredDevicesForCapturePresetSync(int capturePreset,
+ @NonNull List<AudioDeviceAttributes> devices) {
+ return mDeviceInventory.setPreferredDevicesForCapturePresetSync(capturePreset, devices);
+ }
+
+ /*package*/ int clearPreferredDevicesForCapturePresetSync(int capturePreset) {
+ return mDeviceInventory.clearPreferredDevicesForCapturePresetSync(capturePreset);
+ }
+
+ /*package*/ void registerCapturePresetDevicesRoleDispatcher(
+ @NonNull ICapturePresetDevicesRoleDispatcher dispatcher) {
+ mDeviceInventory.registerCapturePresetDevicesRoleDispatcher(dispatcher);
+ }
+
+ /*package*/ void unregisterCapturePresetDevicesRoleDispatcher(
+ @NonNull ICapturePresetDevicesRoleDispatcher dispatcher) {
+ mDeviceInventory.unregisterCapturePresetDevicesRoleDispatcher(dispatcher);
+ }
+
//---------------------------------------------------------------------
// Communication with (to) AudioService
//TODO check whether the AudioService methods are candidates to move here
@@ -694,6 +714,17 @@ import java.util.concurrent.atomic.AtomicBoolean;
sendIMsgNoDelay(MSG_I_SAVE_REMOVE_PREF_DEVICES_FOR_STRATEGY, SENDMSG_QUEUE, strategy);
}
+ /*package*/ void postSaveSetPreferredDevicesForCapturePreset(
+ int capturePreset, List<AudioDeviceAttributes> devices) {
+ sendILMsgNoDelay(
+ MSG_IL_SAVE_PREF_DEVICES_FOR_CAPTURE_PRESET, SENDMSG_QUEUE, capturePreset, devices);
+ }
+
+ /*package*/ void postSaveClearPreferredDevicesForCapturePreset(int capturePreset) {
+ sendIMsgNoDelay(
+ MSG_I_SAVE_CLEAR_PREF_DEVICES_FOR_CAPTURE_PRESET, SENDMSG_QUEUE, capturePreset);
+ }
+
//---------------------------------------------------------------------
// Method forwarding between the helper classes (BtHelper, AudioDeviceInventory)
// only call from a "handle"* method or "on"* method
@@ -977,7 +1008,9 @@ import java.util.concurrent.atomic.AtomicBoolean;
synchronized (mDeviceStateLock) {
if (mModeOwnerPid != msg.arg1) {
mModeOwnerPid = msg.arg1;
- updateSpeakerphoneOn("setNewModeOwner");
+ if (msg.arg2 != AudioSystem.MODE_RINGTONE) {
+ updateSpeakerphoneOn("setNewModeOwner");
+ }
if (mModeOwnerPid != 0) {
mBtHelper.disconnectBluetoothSco(mModeOwnerPid);
}
@@ -1096,6 +1129,17 @@ import java.util.concurrent.atomic.AtomicBoolean;
case MSG_CHECK_MUTE_MUSIC:
checkMessagesMuteMusic(0);
break;
+ case MSG_IL_SAVE_PREF_DEVICES_FOR_CAPTURE_PRESET: {
+ final int capturePreset = msg.arg1;
+ final List<AudioDeviceAttributes> devices =
+ (List<AudioDeviceAttributes>) msg.obj;
+ mDeviceInventory.onSaveSetPreferredDevicesForCapturePreset(
+ capturePreset, devices);
+ } break;
+ case MSG_I_SAVE_CLEAR_PREF_DEVICES_FOR_CAPTURE_PRESET: {
+ final int capturePreset = msg.arg1;
+ mDeviceInventory.onSaveClearPreferredDevicesForCapturePreset(capturePreset);
+ } break;
default:
Log.wtf(TAG, "Invalid message " + msg.what);
}
@@ -1172,6 +1216,9 @@ import java.util.concurrent.atomic.AtomicBoolean;
private static final int MSG_CHECK_MUTE_MUSIC = 36;
private static final int MSG_REPORT_NEW_ROUTES_A2DP = 37;
+ private static final int MSG_IL_SAVE_PREF_DEVICES_FOR_CAPTURE_PRESET = 38;
+ private static final int MSG_I_SAVE_CLEAR_PREF_DEVICES_FOR_CAPTURE_PRESET = 39;
+
private static boolean isMessageHandledUnderWakelock(int msgId) {
switch(msgId) {
diff --git a/services/core/java/com/android/server/audio/AudioDeviceInventory.java b/services/core/java/com/android/server/audio/AudioDeviceInventory.java
index fbf07cc591ff..33a8a30243de 100644
--- a/services/core/java/com/android/server/audio/AudioDeviceInventory.java
+++ b/services/core/java/com/android/server/audio/AudioDeviceInventory.java
@@ -31,6 +31,7 @@ import android.media.AudioPort;
import android.media.AudioRoutesInfo;
import android.media.AudioSystem;
import android.media.IAudioRoutesObserver;
+import android.media.ICapturePresetDevicesRoleDispatcher;
import android.media.IStrategyPreferredDevicesDispatcher;
import android.media.MediaMetrics;
import android.os.Binder;
@@ -140,6 +141,10 @@ public class AudioDeviceInventory {
private final ArrayMap<Integer, List<AudioDeviceAttributes>> mPreferredDevices =
new ArrayMap<>();
+ // List of preferred devices of capture preset
+ private final ArrayMap<Integer, List<AudioDeviceAttributes>> mPreferredDevicesForCapturePreset =
+ new ArrayMap<>();
+
// the wrapper for AudioSystem static methods, allows us to spy AudioSystem
private final @NonNull AudioSystemAdapter mAudioSystem;
@@ -154,6 +159,10 @@ public class AudioDeviceInventory {
final RemoteCallbackList<IStrategyPreferredDevicesDispatcher> mPrefDevDispatchers =
new RemoteCallbackList<IStrategyPreferredDevicesDispatcher>();
+ // Monitoring of devices for role and capture preset
+ final RemoteCallbackList<ICapturePresetDevicesRoleDispatcher> mDevRoleCapturePresetDispatchers =
+ new RemoteCallbackList<ICapturePresetDevicesRoleDispatcher>();
+
/*package*/ AudioDeviceInventory(@NonNull AudioDeviceBroker broker) {
mDeviceBroker = broker;
mAudioSystem = AudioSystemAdapter.getDefaultAdapter();
@@ -243,6 +252,9 @@ public class AudioDeviceInventory {
pw.println(" " + prefix + " type:0x" + Integer.toHexString(keyType)
+ " (" + AudioSystem.getDeviceName(keyType)
+ ") addr:" + valueAddress); });
+ mPreferredDevicesForCapturePreset.forEach((capturePreset, devices) -> {
+ pw.println(" " + prefix + "capturePreset:" + capturePreset
+ + " devices:" + devices); });
}
//------------------------------------------------------------
@@ -270,6 +282,9 @@ public class AudioDeviceInventory {
mAudioSystem.setDevicesRoleForStrategy(
strategy, AudioSystem.DEVICE_ROLE_PREFERRED, devices); });
}
+ synchronized (mPreferredDevicesForCapturePreset) {
+ // TODO: call audiosystem to restore
+ }
}
// only public for mocking/spying
@@ -613,6 +628,20 @@ public class AudioDeviceInventory {
dispatchPreferredDevice(strategy, new ArrayList<AudioDeviceAttributes>());
}
+ /*package*/ void onSaveSetPreferredDevicesForCapturePreset(
+ int capturePreset, @NonNull List<AudioDeviceAttributes> devices) {
+ mPreferredDevicesForCapturePreset.put(capturePreset, devices);
+ dispatchDevicesRoleForCapturePreset(
+ capturePreset, AudioSystem.DEVICE_ROLE_PREFERRED, devices);
+ }
+
+ /*package*/ void onSaveClearPreferredDevicesForCapturePreset(int capturePreset) {
+ mPreferredDevicesForCapturePreset.remove(capturePreset);
+ dispatchDevicesRoleForCapturePreset(
+ capturePreset, AudioSystem.DEVICE_ROLE_PREFERRED,
+ new ArrayList<AudioDeviceAttributes>());
+ }
+
//------------------------------------------------------------
//
@@ -651,6 +680,41 @@ public class AudioDeviceInventory {
mPrefDevDispatchers.unregister(dispatcher);
}
+ /*package*/ int setPreferredDevicesForCapturePresetSync(
+ int capturePreset, @NonNull List<AudioDeviceAttributes> devices) {
+ final long identity = Binder.clearCallingIdentity();
+ final int status = mAudioSystem.setDevicesRoleForCapturePreset(
+ capturePreset, AudioSystem.DEVICE_ROLE_PREFERRED, devices);
+ Binder.restoreCallingIdentity(identity);
+
+ if (status == AudioSystem.SUCCESS) {
+ mDeviceBroker.postSaveSetPreferredDevicesForCapturePreset(capturePreset, devices);
+ }
+ return status;
+ }
+
+ /*package*/ int clearPreferredDevicesForCapturePresetSync(int capturePreset) {
+ final long identity = Binder.clearCallingIdentity();
+ final int status = mAudioSystem.clearDevicesRoleForCapturePreset(
+ capturePreset, AudioSystem.DEVICE_ROLE_PREFERRED);
+ Binder.restoreCallingIdentity(identity);
+
+ if (status == AudioSystem.SUCCESS) {
+ mDeviceBroker.postSaveClearPreferredDevicesForCapturePreset(capturePreset);
+ }
+ return status;
+ }
+
+ /*package*/ void registerCapturePresetDevicesRoleDispatcher(
+ @NonNull ICapturePresetDevicesRoleDispatcher dispatcher) {
+ mDevRoleCapturePresetDispatchers.register(dispatcher);
+ }
+
+ /*package*/ void unregisterCapturePresetDevicesRoleDispatcher(
+ @NonNull ICapturePresetDevicesRoleDispatcher dispatcher) {
+ mDevRoleCapturePresetDispatchers.unregister(dispatcher);
+ }
+
/**
* Implements the communication with AudioSystem to (dis)connect a device in the native layers
* @param connect true if connection
@@ -1306,6 +1370,19 @@ public class AudioDeviceInventory {
mPrefDevDispatchers.finishBroadcast();
}
+ private void dispatchDevicesRoleForCapturePreset(
+ int capturePreset, int role, @NonNull List<AudioDeviceAttributes> devices) {
+ final int nbDispatchers = mDevRoleCapturePresetDispatchers.beginBroadcast();
+ for (int i = 0; i < nbDispatchers; ++i) {
+ try {
+ mDevRoleCapturePresetDispatchers.getBroadcastItem(i).dispatchDevicesRoleChanged(
+ capturePreset, role, devices);
+ } catch (RemoteException e) {
+ }
+ }
+ mDevRoleCapturePresetDispatchers.finishBroadcast();
+ }
+
//----------------------------------------------------------
// For tests only
diff --git a/services/core/java/com/android/server/audio/AudioEventLogger.java b/services/core/java/com/android/server/audio/AudioEventLogger.java
index 9ebd75bd0f64..af0e978726e3 100644
--- a/services/core/java/com/android/server/audio/AudioEventLogger.java
+++ b/services/core/java/com/android/server/audio/AudioEventLogger.java
@@ -60,7 +60,36 @@ public class AudioEventLogger {
* @return the same instance of the event
*/
public Event printLog(String tag) {
- Log.i(tag, eventToString());
+ return printLog(ALOGI, tag);
+ }
+
+ public static final int ALOGI = 0;
+ public static final int ALOGE = 1;
+ public static final int ALOGW = 2;
+ public static final int ALOGV = 3;
+
+ /**
+ * Same as {@link #printLog(String)} with a log type
+ * @param type one of {@link #ALOGI}, {@link #ALOGE}, {@link #ALOGV}
+ * @param tag
+ * @return
+ */
+ public Event printLog(int type, String tag) {
+ switch (type) {
+ case ALOGI:
+ Log.i(tag, eventToString());
+ break;
+ case ALOGE:
+ Log.e(tag, eventToString());
+ break;
+ case ALOGW:
+ Log.w(tag, eventToString());
+ break;
+ case ALOGV:
+ default:
+ Log.v(tag, eventToString());
+ break;
+ }
return this;
}
diff --git a/services/core/java/com/android/server/audio/AudioService.java b/services/core/java/com/android/server/audio/AudioService.java
index 673ca1f3da86..5f6491093453 100755
--- a/services/core/java/com/android/server/audio/AudioService.java
+++ b/services/core/java/com/android/server/audio/AudioService.java
@@ -26,6 +26,10 @@ import static android.provider.Settings.Secure.VOLUME_HUSH_MUTE;
import static android.provider.Settings.Secure.VOLUME_HUSH_OFF;
import static android.provider.Settings.Secure.VOLUME_HUSH_VIBRATE;
+import static com.android.server.audio.AudioEventLogger.Event.ALOGE;
+import static com.android.server.audio.AudioEventLogger.Event.ALOGI;
+import static com.android.server.audio.AudioEventLogger.Event.ALOGW;
+
import android.Manifest;
import android.annotation.IntDef;
import android.annotation.NonNull;
@@ -80,6 +84,7 @@ import android.media.IAudioFocusDispatcher;
import android.media.IAudioRoutesObserver;
import android.media.IAudioServerStateDispatcher;
import android.media.IAudioService;
+import android.media.ICapturePresetDevicesRoleDispatcher;
import android.media.IPlaybackConfigDispatcher;
import android.media.IRecordingConfigDispatcher;
import android.media.IRingtonePlayer;
@@ -287,6 +292,7 @@ public class AudioService extends IAudioService.Stub
private static final int MSG_CHECK_MODE_FOR_UID = 31;
private static final int MSG_STREAM_DEVICES_CHANGED = 32;
private static final int MSG_UPDATE_VOLUME_STATES_FOR_DEVICE = 33;
+ private static final int MSG_REINIT_VOLUMES = 34;
// start of messages handled under wakelock
// these messages can only be queued, i.e. sent with queueMsgUnderWakeLock(),
// and not with sendMsg(..., ..., SENDMSG_QUEUE, ...)
@@ -669,6 +675,7 @@ public class AudioService extends IAudioService.Stub
public AudioService(Context context, AudioSystemAdapter audioSystem,
SystemServerAdapter systemServer) {
+ sLifecycleLogger.log(new AudioEventLogger.StringEvent("AudioService()"));
mContext = context;
mContentResolver = context.getContentResolver();
mAppOps = (AppOpsManager)context.getSystemService(Context.APP_OPS_SERVICE);
@@ -888,6 +895,9 @@ public class AudioService extends IAudioService.Stub
mPrescaleAbsoluteVolume[i] = preScale[i];
}
}
+
+ // check on volume initialization
+ checkVolumeRangeInitialization("AudioService()");
}
public void systemReady() {
@@ -1015,11 +1025,15 @@ public class AudioService extends IAudioService.Stub
if (!mSystemReady ||
(AudioSystem.checkAudioFlinger() != AudioSystem.AUDIO_STATUS_OK)) {
Log.e(TAG, "Audioserver died.");
+ sLifecycleLogger.log(new AudioEventLogger.StringEvent(
+ "onAudioServerDied() audioserver died"));
sendMsg(mAudioHandler, MSG_AUDIO_SERVER_DIED, SENDMSG_NOOP, 0, 0,
null, 500);
return;
}
- Log.e(TAG, "Audioserver started.");
+ Log.i(TAG, "Audioserver started.");
+ sLifecycleLogger.log(new AudioEventLogger.StringEvent(
+ "onAudioServerDied() audioserver started"));
updateAudioHalPids();
@@ -1054,14 +1068,7 @@ public class AudioService extends IAudioService.Stub
mDeviceBroker.setForceUse_Async(AudioSystem.FOR_SYSTEM, forSys, "onAudioServerDied");
// Restore stream volumes
- int numStreamTypes = AudioSystem.getNumStreamTypes();
- for (int streamType = numStreamTypes - 1; streamType >= 0; streamType--) {
- VolumeStreamState streamState = mStreamStates[streamType];
- AudioSystem.initStreamVolume(
- streamType, streamState.mIndexMin / 10, streamState.mIndexMax / 10);
-
- streamState.applyAllVolumes();
- }
+ onReinitVolumes("after audioserver restart");
// Restore audio volume groups
restoreVolumeGroups();
@@ -1159,6 +1166,72 @@ public class AudioService extends IAudioService.Stub
setMicMuteFromSwitchInput();
}
+ private void onReinitVolumes(@NonNull String caller) {
+ final int numStreamTypes = AudioSystem.getNumStreamTypes();
+ // keep track of any error during stream volume initialization
+ int status = AudioSystem.AUDIO_STATUS_OK;
+ for (int streamType = numStreamTypes - 1; streamType >= 0; streamType--) {
+ VolumeStreamState streamState = mStreamStates[streamType];
+ final int res = AudioSystem.initStreamVolume(
+ streamType, streamState.mIndexMin / 10, streamState.mIndexMax / 10);
+ if (res != AudioSystem.AUDIO_STATUS_OK) {
+ status = res;
+ Log.e(TAG, "Failed to initStreamVolume (" + res + ") for stream " + streamType);
+ // stream volume initialization failed, no need to try the others, it will be
+ // attempted again when MSG_REINIT_VOLUMES is handled
+ break;
+ }
+ streamState.applyAllVolumes();
+ }
+
+ // did it work? check based on status
+ if (status != AudioSystem.AUDIO_STATUS_OK) {
+ sLifecycleLogger.log(new AudioEventLogger.StringEvent(
+ caller + ": initStreamVolume failed with " + status + " will retry")
+ .printLog(ALOGE, TAG));
+ sendMsg(mAudioHandler, MSG_REINIT_VOLUMES, SENDMSG_NOOP, 0, 0,
+ caller /*obj*/, 2 * INDICATE_SYSTEM_READY_RETRY_DELAY_MS);
+ return;
+ }
+
+ // did it work? check based on min/max values of some basic streams
+ if (!checkVolumeRangeInitialization(caller)) {
+ return;
+ }
+
+ // success
+ sLifecycleLogger.log(new AudioEventLogger.StringEvent(
+ caller + ": initStreamVolume succeeded").printLog(ALOGI, TAG));
+ }
+
+ /**
+ * Check volume ranges were properly initialized
+ * @return true if volume ranges were successfully initialized
+ */
+ private boolean checkVolumeRangeInitialization(String caller) {
+ boolean success = true;
+ final int[] basicStreams = { AudioSystem.STREAM_ALARM, AudioSystem.STREAM_RING,
+ AudioSystem.STREAM_MUSIC, AudioSystem.STREAM_VOICE_CALL,
+ AudioSystem.STREAM_ACCESSIBILITY };
+ for (int streamType : basicStreams) {
+ final AudioAttributes aa = new AudioAttributes.Builder()
+ .setInternalLegacyStreamType(streamType).build();
+ if (AudioSystem.getMaxVolumeIndexForAttributes(aa) < 0
+ || AudioSystem.getMinVolumeIndexForAttributes(aa) < 0) {
+ success = false;
+ break;
+ }
+ }
+ if (!success) {
+ sLifecycleLogger.log(new AudioEventLogger.StringEvent(
+ caller + ": initStreamVolume succeeded but invalid mix/max levels, will retry")
+ .printLog(ALOGW, TAG));
+ sendMsg(mAudioHandler, MSG_REINIT_VOLUMES, SENDMSG_NOOP, 0, 0,
+ caller /*obj*/, 2 * INDICATE_SYSTEM_READY_RETRY_DELAY_MS);
+ }
+ return success;
+ }
+
private void onDispatchAudioServerStateChange(boolean state) {
synchronized (mAudioServerStateListeners) {
for (AsdProxy asdp : mAudioServerStateListeners.values()) {
@@ -1915,6 +1988,94 @@ public class AudioService extends IAudioService.Stub
mDeviceBroker.unregisterStrategyPreferredDevicesDispatcher(dispatcher);
}
+ /**
+ * @see AudioManager#setPreferredDeviceForCapturePreset(int, AudioDeviceAttributes)
+ */
+ public int setPreferredDevicesForCapturePreset(
+ int capturePreset, List<AudioDeviceAttributes> devices) {
+ if (devices == null) {
+ return AudioSystem.ERROR;
+ }
+ enforceModifyAudioRoutingPermission();
+ final String logString = String.format(
+ "setPreferredDevicesForCapturePreset u/pid:%d/%d source:%d dev:%s",
+ Binder.getCallingUid(), Binder.getCallingPid(), capturePreset,
+ devices.stream().map(e -> e.toString()).collect(Collectors.joining(",")));
+ sDeviceLogger.log(new AudioEventLogger.StringEvent(logString).printLog(TAG));
+ if (devices.stream().anyMatch(device ->
+ device.getRole() == AudioDeviceAttributes.ROLE_OUTPUT)) {
+ Log.e(TAG, "Unsupported output routing in " + logString);
+ return AudioSystem.ERROR;
+ }
+
+ final int status = mDeviceBroker.setPreferredDevicesForCapturePresetSync(
+ capturePreset, devices);
+ if (status != AudioSystem.SUCCESS) {
+ Log.e(TAG, String.format("Error %d in %s)", status, logString));
+ }
+
+ return status;
+ }
+
+ /** @see AudioManager#clearPreferredDevicesForCapturePreset(int) */
+ public int clearPreferredDevicesForCapturePreset(int capturePreset) {
+ enforceModifyAudioRoutingPermission();
+ final String logString = String.format(
+ "removePreferredDeviceForCapturePreset source:%d", capturePreset);
+ sDeviceLogger.log(new AudioEventLogger.StringEvent(logString).printLog(TAG));
+
+ final int status = mDeviceBroker.clearPreferredDevicesForCapturePresetSync(capturePreset);
+ if (status != AudioSystem.SUCCESS) {
+ Log.e(TAG, String.format("Error %d in %s", status, logString));
+ }
+ return status;
+ }
+
+ /**
+ * @see AudioManager#getPreferredDevicesForCapturePreset(int)
+ */
+ public List<AudioDeviceAttributes> getPreferredDevicesForCapturePreset(int capturePreset) {
+ enforceModifyAudioRoutingPermission();
+ List<AudioDeviceAttributes> devices = new ArrayList<>();
+ final long identity = Binder.clearCallingIdentity();
+ final int status = AudioSystem.getDevicesForRoleAndCapturePreset(
+ capturePreset, AudioSystem.DEVICE_ROLE_PREFERRED, devices);
+ Binder.restoreCallingIdentity(identity);
+ if (status != AudioSystem.SUCCESS) {
+ Log.e(TAG, String.format("Error %d in getPreferredDeviceForCapturePreset(%d)",
+ status, capturePreset));
+ return new ArrayList<AudioDeviceAttributes>();
+ } else {
+ return devices;
+ }
+ }
+
+ /**
+ * @see AudioManager#addOnPreferredDevicesForCapturePresetChangedListener(
+ * Executor, OnPreferredDevicesForCapturePresetChangedListener)
+ */
+ public void registerCapturePresetDevicesRoleDispatcher(
+ @Nullable ICapturePresetDevicesRoleDispatcher dispatcher) {
+ if (dispatcher == null) {
+ return;
+ }
+ enforceModifyAudioRoutingPermission();
+ mDeviceBroker.registerCapturePresetDevicesRoleDispatcher(dispatcher);
+ }
+
+ /**
+ * @see AudioManager#removeOnPreferredDevicesForCapturePresetChangedListener(
+ * AudioManager.OnPreferredDevicesForCapturePresetChangedListener)
+ */
+ public void unregisterCapturePresetDevicesRoleDispatcher(
+ @Nullable ICapturePresetDevicesRoleDispatcher dispatcher) {
+ if (dispatcher == null) {
+ return;
+ }
+ enforceModifyAudioRoutingPermission();
+ mDeviceBroker.unregisterCapturePresetDevicesRoleDispatcher(dispatcher);
+ }
+
/** @see AudioManager#getDevicesForAttributes(AudioAttributes) */
public @NonNull ArrayList<AudioDeviceAttributes> getDevicesForAttributes(
@NonNull AudioAttributes attributes) {
@@ -3747,13 +3908,15 @@ public class AudioService extends IAudioService.Stub
private final IBinder mCb; // To be notified of client's death
private final int mPid;
private final int mUid;
- private String mPackage;
+ private final boolean mIsPrivileged;
+ private final String mPackage;
private int mMode = AudioSystem.MODE_NORMAL; // Current mode set by this client
- SetModeDeathHandler(IBinder cb, int pid, int uid, String caller) {
+ SetModeDeathHandler(IBinder cb, int pid, int uid, boolean isPrivileged, String caller) {
mCb = cb;
mPid = pid;
mUid = uid;
+ mIsPrivileged = isPrivileged;
mPackage = caller;
}
@@ -3765,12 +3928,13 @@ public class AudioService extends IAudioService.Stub
if (index < 0) {
Log.w(TAG, "unregistered setMode() client died");
} else {
- newModeOwnerPid = setModeInt(AudioSystem.MODE_NORMAL, mCb, mPid, mUid, TAG);
+ newModeOwnerPid = setModeInt(
+ AudioSystem.MODE_NORMAL, mCb, mPid, mUid, mIsPrivileged, TAG);
}
}
// when entering RINGTONE, IN_CALL or IN_COMMUNICATION mode, clear all
// SCO connections not started by the application changing the mode when pid changes
- mDeviceBroker.postSetModeOwnerPid(newModeOwnerPid);
+ mDeviceBroker.postSetModeOwnerPid(newModeOwnerPid, AudioService.this.getMode());
}
public int getPid() {
@@ -3796,6 +3960,10 @@ public class AudioService extends IAudioService.Stub
public String getPackage() {
return mPackage;
}
+
+ public boolean isPrivileged() {
+ return mIsPrivileged;
+ }
}
/** @see AudioManager#setMode(int) */
@@ -3847,18 +4015,19 @@ public class AudioService extends IAudioService.Stub
+ " without permission or being mode owner");
return;
}
- newModeOwnerPid = setModeInt(
- mode, cb, callingPid, Binder.getCallingUid(), callingPackage);
+ newModeOwnerPid = setModeInt(mode, cb, callingPid, Binder.getCallingUid(),
+ hasModifyPhoneStatePermission, callingPackage);
}
// when entering RINGTONE, IN_CALL or IN_COMMUNICATION mode, clear all
// SCO connections not started by the application changing the mode when pid changes
- mDeviceBroker.postSetModeOwnerPid(newModeOwnerPid);
+ mDeviceBroker.postSetModeOwnerPid(newModeOwnerPid, getMode());
}
// setModeInt() returns a valid PID if the audio mode was successfully set to
// any mode other than NORMAL.
@GuardedBy("mDeviceBroker.mSetModeLock")
- private int setModeInt(int mode, IBinder cb, int pid, int uid, String caller) {
+ private int setModeInt(
+ int mode, IBinder cb, int pid, int uid, boolean isPrivileged, String caller) {
if (DEBUG_MODE) {
Log.v(TAG, "setModeInt(mode=" + mode + ", pid=" + pid
+ ", uid=" + uid + ", caller=" + caller + ")");
@@ -3910,7 +4079,7 @@ public class AudioService extends IAudioService.Stub
}
} else {
if (hdlr == null) {
- hdlr = new SetModeDeathHandler(cb, pid, uid, caller);
+ hdlr = new SetModeDeathHandler(cb, pid, uid, isPrivileged, caller);
}
// Register for client death notification
try {
@@ -3969,7 +4138,8 @@ public class AudioService extends IAudioService.Stub
// change of mode may require volume to be re-applied on some devices
updateAbsVolumeMultiModeDevices(oldMode, actualMode);
- if (actualMode == AudioSystem.MODE_IN_COMMUNICATION) {
+ if (actualMode == AudioSystem.MODE_IN_COMMUNICATION
+ && !hdlr.isPrivileged()) {
sendMsg(mAudioHandler,
MSG_CHECK_MODE_FOR_UID,
SENDMSG_QUEUE,
@@ -5663,7 +5833,15 @@ public class AudioService extends IAudioService.Stub
mIndexMin = MIN_STREAM_VOLUME[streamType] * 10;
mIndexMinNoPerm = mIndexMin; // may be overwritten later in updateNoPermMinIndex()
mIndexMax = MAX_STREAM_VOLUME[streamType] * 10;
- AudioSystem.initStreamVolume(streamType, mIndexMin / 10, mIndexMax / 10);
+ final int status = AudioSystem.initStreamVolume(
+ streamType, mIndexMin / 10, mIndexMax / 10);
+ if (status != AudioSystem.AUDIO_STATUS_OK) {
+ sLifecycleLogger.log(new AudioEventLogger.StringEvent(
+ "VSS() stream:" + streamType + " initStreamVolume=" + status)
+ .printLog(ALOGE, TAG));
+ sendMsg(mAudioHandler, MSG_REINIT_VOLUMES, SENDMSG_NOOP, 0, 0,
+ "VSS()" /*obj*/, 2 * INDICATE_SYSTEM_READY_RETRY_DELAY_MS);
+ }
readSettings();
mVolumeChanged = new Intent(AudioManager.VOLUME_CHANGED_ACTION);
@@ -6519,8 +6697,8 @@ public class AudioService extends IAudioService.Stub
CHECK_MODE_FOR_UID_PERIOD_MS);
break;
}
- // For now just log the fact that an app is hogging the audio mode.
- // TODO(b/160260850): remove abusive app from audio mode stack.
+ setModeInt(AudioSystem.MODE_NORMAL, h.getBinder(), h.getPid(), h.getUid(),
+ h.isPrivileged(), "MSG_CHECK_MODE_FOR_UID");
mModeLogger.log(new PhoneStateEvent(h.getPackage(), h.getPid()));
}
break;
@@ -6534,6 +6712,10 @@ public class AudioService extends IAudioService.Stub
case MSG_UPDATE_VOLUME_STATES_FOR_DEVICE:
onUpdateVolumeStatesForAudioDevice(msg.arg1, (String) msg.obj);
break;
+
+ case MSG_REINIT_VOLUMES:
+ onReinitVolumes((String) msg.obj);
+ break;
}
}
}
@@ -7463,12 +7645,16 @@ public class AudioService extends IAudioService.Stub
//==========================================================================================
// AudioService logging and dumpsys
//==========================================================================================
+ static final int LOG_NB_EVENTS_LIFECYCLE = 20;
static final int LOG_NB_EVENTS_PHONE_STATE = 20;
static final int LOG_NB_EVENTS_DEVICE_CONNECTION = 30;
static final int LOG_NB_EVENTS_FORCE_USE = 20;
static final int LOG_NB_EVENTS_VOLUME = 40;
static final int LOG_NB_EVENTS_DYN_POLICY = 10;
+ static final AudioEventLogger sLifecycleLogger = new AudioEventLogger(LOG_NB_EVENTS_LIFECYCLE,
+ "audio services lifecycle");
+
final private AudioEventLogger mModeLogger = new AudioEventLogger(LOG_NB_EVENTS_PHONE_STATE,
"phone state (logged after successful call to AudioSystem.setPhoneState(int, int))");
@@ -7545,6 +7731,7 @@ public class AudioService extends IAudioService.Stub
protected void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
if (!DumpUtils.checkDumpPermission(mContext, TAG, pw)) return;
+ sLifecycleLogger.dump(pw);
if (mAudioHandler != null) {
pw.println("\nMessage handler (watch for unhandled messages):");
mAudioHandler.dump(new PrintWriterPrinter(pw), " ");
diff --git a/services/core/java/com/android/server/audio/AudioSystemAdapter.java b/services/core/java/com/android/server/audio/AudioSystemAdapter.java
index a0e1ca78a5e7..ae64990fd8d0 100644
--- a/services/core/java/com/android/server/audio/AudioSystemAdapter.java
+++ b/services/core/java/com/android/server/audio/AudioSystemAdapter.java
@@ -101,6 +101,40 @@ public class AudioSystemAdapter {
}
/**
+ * Same as (@link AudioSystem#setDevicesRoleForCapturePreset(int, List))
+ * @param capturePreset
+ * @param role
+ * @param devices
+ * @return
+ */
+ public int setDevicesRoleForCapturePreset(int capturePreset, int role,
+ @NonNull List<AudioDeviceAttributes> devices) {
+ return AudioSystem.setDevicesRoleForCapturePreset(capturePreset, role, devices);
+ }
+
+ /**
+ * Same as {@link AudioSystem#removeDevicesRoleForCapturePreset(int, int)}
+ * @param capturePreset
+ * @param role
+ * @param devicesToRemove
+ * @return
+ */
+ public int removeDevicesRoleForCapturePreset(
+ int capturePreset, int role, @NonNull List<AudioDeviceAttributes> devicesToRemove) {
+ return AudioSystem.removeDevicesRoleForCapturePreset(capturePreset, role, devicesToRemove);
+ }
+
+ /**
+ * Same as {@link AudioSystem#}
+ * @param capturePreset
+ * @param role
+ * @return
+ */
+ public int clearDevicesRoleForCapturePreset(int capturePreset, int role) {
+ return AudioSystem.clearDevicesRoleForCapturePreset(capturePreset, role);
+ }
+
+ /**
* Same as {@link AudioSystem#setParameters(String)}
* @param keyValuePairs
* @return
diff --git a/services/core/java/com/android/server/biometrics/sensors/AuthenticationClient.java b/services/core/java/com/android/server/biometrics/sensors/AuthenticationClient.java
index 9128359250df..4be596de3af1 100644
--- a/services/core/java/com/android/server/biometrics/sensors/AuthenticationClient.java
+++ b/services/core/java/com/android/server/biometrics/sensors/AuthenticationClient.java
@@ -195,6 +195,8 @@ public abstract class AuthenticationClient<T> extends AcquisitionClient<T>
if (listener != null) {
listener.onAuthenticationFailed(getSensorId());
}
+ } else {
+ mAlreadyDone = true;
}
}
} catch (RemoteException e) {
diff --git a/services/core/java/com/android/server/biometrics/sensors/ClientMonitor.java b/services/core/java/com/android/server/biometrics/sensors/ClientMonitor.java
index dec40e39fb29..e585b48d49b6 100644
--- a/services/core/java/com/android/server/biometrics/sensors/ClientMonitor.java
+++ b/services/core/java/com/android/server/biometrics/sensors/ClientMonitor.java
@@ -176,6 +176,11 @@ public abstract class ClientMonitor<T> extends LoggableMonitor implements IBinde
// TODO(b/157790417): Move this to the scheduler
void binderDiedInternal(boolean clearListener) {
+ if (isAlreadyDone()) {
+ Slog.w(TAG, "Binder died but client is finished, ignoring");
+ return;
+ }
+
// If the current client dies we should cancel the current operation.
if (this instanceof Interruptable) {
Slog.e(TAG, "Binder died, cancelling client");
diff --git a/services/core/java/com/android/server/biometrics/sensors/face/Face10.java b/services/core/java/com/android/server/biometrics/sensors/face/Face10.java
index 32bb2db77ddc..d9c62df3f3ea 100644
--- a/services/core/java/com/android/server/biometrics/sensors/face/Face10.java
+++ b/services/core/java/com/android/server/biometrics/sensors/face/Face10.java
@@ -29,7 +29,6 @@ import android.hardware.biometrics.BiometricsProtoEnums;
import android.hardware.biometrics.face.V1_0.IBiometricsFace;
import android.hardware.biometrics.face.V1_0.IBiometricsFaceClientCallback;
import android.hardware.face.Face;
-import android.hardware.face.FaceManager;
import android.hardware.face.FaceSensorProperties;
import android.hardware.face.IFaceServiceReceiver;
import android.os.Build;
@@ -383,7 +382,7 @@ class Face10 implements IHwBinder.DeathRecipient {
// is safe because authenticatorIds only change when A) new template has been enrolled,
// or B) all templates are removed.
mHandler.post(() -> {
- for (UserInfo user : UserManager.get(mContext).getUsers(true /* excludeDying */)) {
+ for (UserInfo user : UserManager.get(mContext).getAliveUsers()) {
final int targetUserId = user.id;
if (!mAuthenticatorIds.containsKey(targetUserId)) {
scheduleUpdateActiveUserWithoutHandler(targetUserId);
@@ -480,7 +479,8 @@ class Face10 implements IHwBinder.DeathRecipient {
* notifying the previous caller that the interrupting operation is complete (e.g. the
* interrupting client's challenge has been revoked, so that the interrupted client can
* start retry logic if necessary). See
- * {@link FaceManager.GenerateChallengeCallback#onChallengeInterruptFinished(int)}
+ * {@link
+ *android.hardware.face.FaceManager.GenerateChallengeCallback#onChallengeInterruptFinished(int)}
* The only case of conflicting challenges is currently resetLockout --> enroll. So, the second
* option seems better as it prioritizes the new operation, which is user-facing.
*/
diff --git a/services/core/java/com/android/server/biometrics/sensors/fingerprint/Fingerprint21.java b/services/core/java/com/android/server/biometrics/sensors/fingerprint/Fingerprint21.java
index c5c28227fd24..3754bd748781 100644
--- a/services/core/java/com/android/server/biometrics/sensors/fingerprint/Fingerprint21.java
+++ b/services/core/java/com/android/server/biometrics/sensors/fingerprint/Fingerprint21.java
@@ -440,7 +440,7 @@ class Fingerprint21 implements IHwBinder.DeathRecipient {
// is safe because authenticatorIds only change when A) new template has been enrolled,
// or B) all templates are removed.
mHandler.post(() -> {
- for (UserInfo user : UserManager.get(mContext).getUsers(true /* excludeDying */)) {
+ for (UserInfo user : UserManager.get(mContext).getAliveUsers()) {
final int targetUserId = user.id;
if (!mAuthenticatorIds.containsKey(targetUserId)) {
scheduleUpdateActiveUserWithoutHandler(targetUserId);
diff --git a/services/core/java/com/android/server/connectivity/KeepaliveTracker.java b/services/core/java/com/android/server/connectivity/KeepaliveTracker.java
index 7c8fb5aefd1e..1f0066a43538 100644
--- a/services/core/java/com/android/server/connectivity/KeepaliveTracker.java
+++ b/services/core/java/com/android/server/connectivity/KeepaliveTracker.java
@@ -29,6 +29,7 @@ import static android.net.SocketKeepalive.ERROR_INVALID_INTERVAL;
import static android.net.SocketKeepalive.ERROR_INVALID_IP_ADDRESS;
import static android.net.SocketKeepalive.ERROR_INVALID_NETWORK;
import static android.net.SocketKeepalive.ERROR_INVALID_SOCKET;
+import static android.net.SocketKeepalive.ERROR_STOP_REASON_UNINITIALIZED;
import static android.net.SocketKeepalive.ERROR_UNSUPPORTED;
import static android.net.SocketKeepalive.MAX_INTERVAL_SEC;
import static android.net.SocketKeepalive.MIN_INTERVAL_SEC;
@@ -152,6 +153,7 @@ public class KeepaliveTracker {
private static final int STARTED = 3;
private static final int STOPPING = 4;
private int mStartedState = NOT_STARTED;
+ private int mStopReason = ERROR_STOP_REASON_UNINITIALIZED;
KeepaliveInfo(@NonNull ISocketKeepaliveCallback callback,
@NonNull NetworkAgentInfo nai,
@@ -365,6 +367,11 @@ public class KeepaliveTracker {
Log.e(TAG, "Cannot stop unowned keepalive " + mSlot + " on " + mNai.network);
}
}
+ // Store the reason of stopping, and report it after the keepalive is fully stopped.
+ if (mStopReason != ERROR_STOP_REASON_UNINITIALIZED) {
+ throw new IllegalStateException("Unexpected stop reason: " + mStopReason);
+ }
+ mStopReason = reason;
Log.d(TAG, "Stopping keepalive " + mSlot + " on " + mNai.toShortString()
+ ": " + reason);
switch (mStartedState) {
@@ -403,24 +410,6 @@ public class KeepaliveTracker {
Log.wtf(TAG, "Error closing fd for keepalive " + mSlot + ": " + e);
}
}
-
- if (reason == SUCCESS) {
- try {
- mCallback.onStopped();
- } catch (RemoteException e) {
- Log.w(TAG, "Discarded onStop callback: " + reason);
- }
- } else if (reason == DATA_RECEIVED) {
- try {
- mCallback.onDataReceived();
- } catch (RemoteException e) {
- Log.w(TAG, "Discarded onDataReceived callback: " + reason);
- }
- } else {
- notifyErrorCallback(mCallback, reason);
- }
-
- unlinkDeathRecipient();
}
void onFileDescriptorInitiatedStop(final int socketKeepaliveReason) {
@@ -505,12 +494,37 @@ public class KeepaliveTracker {
Log.e(TAG, "Attempt to remove nonexistent keepalive " + slot + " on " + networkName);
return;
}
+
+ // Remove the keepalive from hash table so the slot can be considered available when reusing
+ // it.
networkKeepalives.remove(slot);
Log.d(TAG, "Remove keepalive " + slot + " on " + networkName + ", "
+ networkKeepalives.size() + " remains.");
if (networkKeepalives.isEmpty()) {
mKeepalives.remove(nai);
}
+
+ // Notify app that the keepalive is stopped.
+ final int reason = ki.mStopReason;
+ if (reason == SUCCESS) {
+ try {
+ ki.mCallback.onStopped();
+ } catch (RemoteException e) {
+ Log.w(TAG, "Discarded onStop callback: " + reason);
+ }
+ } else if (reason == DATA_RECEIVED) {
+ try {
+ ki.mCallback.onDataReceived();
+ } catch (RemoteException e) {
+ Log.w(TAG, "Discarded onDataReceived callback: " + reason);
+ }
+ } else if (reason == ERROR_STOP_REASON_UNINITIALIZED) {
+ throw new IllegalStateException("Unexpected stop reason: " + reason);
+ } else {
+ notifyErrorCallback(ki.mCallback, reason);
+ }
+
+ ki.unlinkDeathRecipient();
}
public void handleCheckKeepalivesStillValid(NetworkAgentInfo nai) {
diff --git a/services/core/java/com/android/server/connectivity/PermissionMonitor.java b/services/core/java/com/android/server/connectivity/PermissionMonitor.java
index a75a80a606eb..4c63eb488118 100644
--- a/services/core/java/com/android/server/connectivity/PermissionMonitor.java
+++ b/services/core/java/com/android/server/connectivity/PermissionMonitor.java
@@ -174,7 +174,7 @@ public class PermissionMonitor implements PackageManagerInternal.PackageListObse
netdPermsUids.put(uid, netdPermsUids.get(uid) | otherNetdPerms);
}
- List<UserInfo> users = mUserManager.getUsers(true); // exclude dying users
+ List<UserInfo> users = mUserManager.getAliveUsers();
if (users != null) {
for (UserInfo user : users) {
mUsers.add(user.id);
diff --git a/services/core/java/com/android/server/connectivity/Vpn.java b/services/core/java/com/android/server/connectivity/Vpn.java
index 5484bfca5851..7175489614ea 100644
--- a/services/core/java/com/android/server/connectivity/Vpn.java
+++ b/services/core/java/com/android/server/connectivity/Vpn.java
@@ -1463,7 +1463,7 @@ public class Vpn {
final long token = Binder.clearCallingIdentity();
List<UserInfo> users;
try {
- users = UserManager.get(mContext).getUsers(true);
+ users = UserManager.get(mContext).getAliveUsers();
} finally {
Binder.restoreCallingIdentity(token);
}
diff --git a/services/core/java/com/android/server/content/SyncManager.java b/services/core/java/com/android/server/content/SyncManager.java
index ec12a971e445..b33aa0a6fad3 100644
--- a/services/core/java/com/android/server/content/SyncManager.java
+++ b/services/core/java/com/android/server/content/SyncManager.java
@@ -367,7 +367,7 @@ public class SyncManager {
}
private void removeStaleAccounts() {
- for (UserInfo user : mUserManager.getUsers(true)) {
+ for (UserInfo user : mUserManager.getAliveUsers()) {
// Skip any partially created/removed users
if (user.partial) continue;
Account[] accountsForUser = AccountManagerService.getSingleton().getAccounts(
@@ -777,7 +777,7 @@ public class SyncManager {
if (!mSyncStorageEngine.shouldGrantSyncAdaptersAccountAccess()) {
return;
}
- List<UserInfo> users = mUserManager.getUsers(true);
+ List<UserInfo> users = mUserManager.getAliveUsers();
final int userCount = users.size();
for (int i = 0; i < userCount; i++) {
UserHandle userHandle = users.get(i).getUserHandle();
diff --git a/services/core/java/com/android/server/display/DisplayManagerService.java b/services/core/java/com/android/server/display/DisplayManagerService.java
index 2c632d96e738..4a12ee71adbe 100644
--- a/services/core/java/com/android/server/display/DisplayManagerService.java
+++ b/services/core/java/com/android/server/display/DisplayManagerService.java
@@ -83,6 +83,7 @@ import android.os.UserHandle;
import android.os.UserManager;
import android.provider.Settings;
import android.text.TextUtils;
+import android.util.EventLog;
import android.util.IntArray;
import android.util.Pair;
import android.util.Slog;
@@ -283,6 +284,7 @@ public final class DisplayManagerService extends SystemService {
// Temporary display info, used for comparing display configurations.
private final DisplayInfo mTempDisplayInfo = new DisplayInfo();
+ private final DisplayInfo mTempNonOverrideDisplayInfo = new DisplayInfo();
// Temporary viewports, used when sending new viewport information to the
// input system. May be used outside of the lock but only on the handler thread.
@@ -507,7 +509,8 @@ public final class DisplayManagerService extends SystemService {
mDisplayTransactionListeners.remove(listener);
}
- private void setDisplayInfoOverrideFromWindowManagerInternal(
+ @VisibleForTesting
+ void setDisplayInfoOverrideFromWindowManagerInternal(
int displayId, DisplayInfo info) {
synchronized (mSyncRoot) {
LogicalDisplay display = mLogicalDisplays.get(displayId);
@@ -935,7 +938,8 @@ public final class DisplayManagerService extends SystemService {
adapter.registerLocked();
}
- private void handleDisplayDeviceAdded(DisplayDevice device) {
+ @VisibleForTesting
+ void handleDisplayDeviceAdded(DisplayDevice device) {
synchronized (mSyncRoot) {
handleDisplayDeviceAddedLocked(device);
}
@@ -947,7 +951,6 @@ public final class DisplayManagerService extends SystemService {
Slog.w(TAG, "Attempted to add already added display device: " + info);
return;
}
-
Slog.i(TAG, "Display device added: " + info);
device.mDebugLastLoggedDeviceInfo = info;
@@ -960,7 +963,8 @@ public final class DisplayManagerService extends SystemService {
scheduleTraversalLocked(false);
}
- private void handleDisplayDeviceChanged(DisplayDevice device) {
+ @VisibleForTesting
+ void handleDisplayDeviceChanged(DisplayDevice device) {
synchronized (mSyncRoot) {
DisplayDeviceInfo info = device.getDisplayDeviceInfoLocked();
if (!mDisplayDevices.contains(device)) {
@@ -1234,6 +1238,7 @@ public final class DisplayManagerService extends SystemService {
LogicalDisplay display = mLogicalDisplays.valueAt(i);
mTempDisplayInfo.copyFrom(display.getDisplayInfoLocked());
+ display.getNonOverrideDisplayInfoLocked(mTempNonOverrideDisplayInfo);
display.updateLocked(mDisplayDevices);
if (!display.isValidLocked()) {
mLogicalDisplays.removeAt(i);
@@ -1242,6 +1247,15 @@ public final class DisplayManagerService extends SystemService {
} else if (!mTempDisplayInfo.equals(display.getDisplayInfoLocked())) {
handleLogicalDisplayChanged(displayId, display);
changed = true;
+ } else {
+ // While applications shouldn't know nor care about the non-overridden info, we
+ // still need to let WindowManager know so it can update its own internal state for
+ // things like display cutouts.
+ display.getNonOverrideDisplayInfoLocked(mTempDisplayInfo);
+ if (!mTempNonOverrideDisplayInfo.equals(mTempDisplayInfo)) {
+ handleLogicalDisplayChanged(displayId, display);
+ changed = true;
+ }
}
}
return changed;
@@ -2176,6 +2190,8 @@ public final class DisplayManagerService extends SystemService {
if (callingUid != Process.SYSTEM_UID && (flags & VIRTUAL_DISPLAY_FLAG_TRUSTED) != 0) {
if (!checkCallingPermission(ADD_TRUSTED_DISPLAY, "createVirtualDisplay()")) {
+ EventLog.writeEvent(0x534e4554, "162627132", callingUid,
+ "Attempt to create a trusted display without holding permission!");
throw new SecurityException("Requires ADD_TRUSTED_DISPLAY permission to "
+ "create a trusted virtual display.");
}
diff --git a/services/core/java/com/android/server/hdmi/ActiveSourceAction.java b/services/core/java/com/android/server/hdmi/ActiveSourceAction.java
index c90f297e1485..179602737985 100644
--- a/services/core/java/com/android/server/hdmi/ActiveSourceAction.java
+++ b/services/core/java/com/android/server/hdmi/ActiveSourceAction.java
@@ -51,7 +51,7 @@ public class ActiveSourceAction extends HdmiCecFeatureAction {
Constants.MENU_STATE_ACTIVATED));
}
- source().setActiveSource(logicalAddress, physicalAddress);
+ source().setActiveSource(logicalAddress, physicalAddress, "ActiveSourceAction");
mState = STATE_FINISHED;
finish();
return true;
diff --git a/services/core/java/com/android/server/hdmi/ActiveSourceHandler.java b/services/core/java/com/android/server/hdmi/ActiveSourceHandler.java
index 01547c16e9b5..8405bbe38b12 100644
--- a/services/core/java/com/android/server/hdmi/ActiveSourceHandler.java
+++ b/services/core/java/com/android/server/hdmi/ActiveSourceHandler.java
@@ -17,9 +17,9 @@
package com.android.server.hdmi;
import android.annotation.Nullable;
-import android.hardware.hdmi.IHdmiControlCallback;
-import android.hardware.hdmi.HdmiDeviceInfo;
import android.hardware.hdmi.HdmiControlManager;
+import android.hardware.hdmi.HdmiDeviceInfo;
+import android.hardware.hdmi.IHdmiControlCallback;
import android.os.RemoteException;
import android.util.Slog;
@@ -69,7 +69,7 @@ final class ActiveSourceHandler {
if (!tv.isProhibitMode()) {
ActiveSource old = ActiveSource.of(tv.getActiveSource());
- tv.updateActiveSource(newActive);
+ tv.updateActiveSource(newActive, "ActiveSourceHandler");
boolean notifyInputChange = (mCallback == null);
if (!old.equals(newActive)) {
tv.setPrevPortId(tv.getActivePortId());
@@ -85,7 +85,7 @@ final class ActiveSourceHandler {
HdmiCecMessage activeSourceCommand = HdmiCecMessageBuilder.buildActiveSource(
current.logicalAddress, current.physicalAddress);
mService.sendCecCommand(activeSourceCommand);
- tv.updateActiveSource(current);
+ tv.updateActiveSource(current, "ActiveSourceHandler");
invokeCallback(HdmiControlManager.RESULT_SUCCESS);
} else {
tv.startRoutingControl(newActive.physicalAddress, current.physicalAddress, true,
diff --git a/services/core/java/com/android/server/hdmi/HdmiCecController.java b/services/core/java/com/android/server/hdmi/HdmiCecController.java
index 66652ca26e54..7b52ddef29bc 100644
--- a/services/core/java/com/android/server/hdmi/HdmiCecController.java
+++ b/services/core/java/com/android/server/hdmi/HdmiCecController.java
@@ -688,16 +688,24 @@ final class HdmiCecController {
}
void dump(final IndentingPrintWriter pw) {
+ final SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
+
for (int i = 0; i < mLocalDevices.size(); ++i) {
pw.println("HdmiCecLocalDevice #" + mLocalDevices.keyAt(i) + ":");
pw.increaseIndent();
mLocalDevices.valueAt(i).dump(pw);
+
+ pw.println("Active Source history:");
+ pw.increaseIndent();
+ for (Dumpable activeSourceEvent : mLocalDevices.valueAt(i).getActiveSourceHistory()) {
+ activeSourceEvent.dump(pw, sdf);
+ }
+ pw.decreaseIndent();
pw.decreaseIndent();
}
pw.println("CEC message history:");
pw.increaseIndent();
- final SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
for (Dumpable record : mMessageHistory) {
record.dump(pw, sdf);
}
@@ -917,7 +925,7 @@ final class HdmiCecController {
}
}
- private abstract static class Dumpable {
+ public abstract static class Dumpable {
protected final long mTime;
Dumpable() {
diff --git a/services/core/java/com/android/server/hdmi/HdmiCecLocalDevice.java b/services/core/java/com/android/server/hdmi/HdmiCecLocalDevice.java
index 86e6a3220507..b88a37e7b8b4 100755
--- a/services/core/java/com/android/server/hdmi/HdmiCecLocalDevice.java
+++ b/services/core/java/com/android/server/hdmi/HdmiCecLocalDevice.java
@@ -38,10 +38,13 @@ import com.android.server.hdmi.Constants.LocalActivePort;
import com.android.server.hdmi.HdmiAnnotations.ServiceThreadOnly;
import com.android.server.hdmi.HdmiControlService.SendMessageCallback;
+import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Collections;
+import java.util.Date;
import java.util.Iterator;
import java.util.List;
+import java.util.concurrent.ArrayBlockingQueue;
/**
* Class that models a logical CEC device hosted in this system. Handles initialization, CEC
@@ -50,6 +53,7 @@ import java.util.List;
abstract class HdmiCecLocalDevice {
private static final String TAG = "HdmiCecLocalDevice";
+ private static final int MAX_HDMI_ACTIVE_SOURCE_HISTORY = 10;
private static final int MSG_DISABLE_DEVICE_TIMEOUT = 1;
private static final int MSG_USER_CONTROL_RELEASE_TIMEOUT = 2;
// Timeout in millisecond for device clean up (5s).
@@ -68,6 +72,10 @@ abstract class HdmiCecLocalDevice {
protected int mLastKeycode = HdmiCecKeycode.UNSUPPORTED_KEYCODE;
protected int mLastKeyRepeatCount = 0;
+ // Stores recent changes to the active source in the CEC network.
+ private final ArrayBlockingQueue<HdmiCecController.Dumpable> mActiveSourceHistory =
+ new ArrayBlockingQueue<>(MAX_HDMI_ACTIVE_SOURCE_HISTORY);
+
static class ActiveSource {
int logicalAddress;
int physicalAddress;
@@ -893,16 +901,16 @@ abstract class HdmiCecLocalDevice {
return mService.getLocalActiveSource();
}
- void setActiveSource(ActiveSource newActive) {
- setActiveSource(newActive.logicalAddress, newActive.physicalAddress);
+ void setActiveSource(ActiveSource newActive, String caller) {
+ setActiveSource(newActive.logicalAddress, newActive.physicalAddress, caller);
}
- void setActiveSource(HdmiDeviceInfo info) {
- setActiveSource(info.getLogicalAddress(), info.getPhysicalAddress());
+ void setActiveSource(HdmiDeviceInfo info, String caller) {
+ setActiveSource(info.getLogicalAddress(), info.getPhysicalAddress(), caller);
}
- void setActiveSource(int logicalAddress, int physicalAddress) {
- mService.setActiveSource(logicalAddress, physicalAddress);
+ void setActiveSource(int logicalAddress, int physicalAddress, String caller) {
+ mService.setActiveSource(logicalAddress, physicalAddress, caller);
mService.setLastInputForMhl(Constants.INVALID_PORT_ID);
}
@@ -1120,6 +1128,20 @@ abstract class HdmiCecLocalDevice {
HdmiCecMessageBuilder.buildUserControlReleased(mAddress, targetAddress));
}
+ void addActiveSourceHistoryItem(ActiveSource activeSource, boolean isActiveSource,
+ String caller) {
+ ActiveSourceHistoryRecord record = new ActiveSourceHistoryRecord(activeSource,
+ isActiveSource, caller);
+ if (!mActiveSourceHistory.offer(record)) {
+ mActiveSourceHistory.poll();
+ mActiveSourceHistory.offer(record);
+ }
+ }
+
+ public ArrayBlockingQueue<HdmiCecController.Dumpable> getActiveSourceHistory() {
+ return this.mActiveSourceHistory;
+ }
+
/** Dump internal status of HdmiCecLocalDevice object. */
protected void dump(final IndentingPrintWriter pw) {
pw.println("mDeviceType: " + mDeviceType);
@@ -1152,4 +1174,29 @@ abstract class HdmiCecLocalDevice {
}
return finalMask | myPhysicalAddress;
}
+
+ private static final class ActiveSourceHistoryRecord extends HdmiCecController.Dumpable {
+ private final ActiveSource mActiveSource;
+ private final boolean mIsActiveSource;
+ private final String mCaller;
+
+ private ActiveSourceHistoryRecord(ActiveSource mActiveSource, boolean mIsActiveSource,
+ String caller) {
+ this.mActiveSource = mActiveSource;
+ this.mIsActiveSource = mIsActiveSource;
+ this.mCaller = caller;
+ }
+
+ @Override
+ void dump(final IndentingPrintWriter pw, SimpleDateFormat sdf) {
+ pw.print("time=");
+ pw.print(sdf.format(new Date(mTime)));
+ pw.print(" active source=");
+ pw.print(mActiveSource);
+ pw.print(" isActiveSource=");
+ pw.print(mIsActiveSource);
+ pw.print(" from=");
+ pw.println(mCaller);
+ }
+ }
}
diff --git a/services/core/java/com/android/server/hdmi/HdmiCecLocalDeviceAudioSystem.java b/services/core/java/com/android/server/hdmi/HdmiCecLocalDeviceAudioSystem.java
index af815973d3c3..68473c1830ae 100644
--- a/services/core/java/com/android/server/hdmi/HdmiCecLocalDeviceAudioSystem.java
+++ b/services/core/java/com/android/server/hdmi/HdmiCecLocalDeviceAudioSystem.java
@@ -361,7 +361,8 @@ public class HdmiCecLocalDeviceAudioSystem extends HdmiCecLocalDeviceSource {
assertRunOnServiceThread();
// Invalidate the internal active source record when goes to standby
// This set will also update mIsActiveSource
- mService.setActiveSource(Constants.ADDR_INVALID, Constants.INVALID_PHYSICAL_ADDRESS);
+ mService.setActiveSource(Constants.ADDR_INVALID, Constants.INVALID_PHYSICAL_ADDRESS,
+ "HdmiCecLocalDeviceAudioSystem#onStandby()");
mTvSystemAudioModeSupport = null;
// Record the last state of System Audio Control before going to standby
synchronized (mLock) {
diff --git a/services/core/java/com/android/server/hdmi/HdmiCecLocalDevicePlayback.java b/services/core/java/com/android/server/hdmi/HdmiCecLocalDevicePlayback.java
index d675b81629a4..f2f6dbe9bde5 100644
--- a/services/core/java/com/android/server/hdmi/HdmiCecLocalDevicePlayback.java
+++ b/services/core/java/com/android/server/hdmi/HdmiCecLocalDevicePlayback.java
@@ -190,7 +190,8 @@ public class HdmiCecLocalDevicePlayback extends HdmiCecLocalDeviceSource {
boolean wasActiveSource = mIsActiveSource;
// Invalidate the internal active source record when goes to standby
// This set will also update mIsActiveSource
- mService.setActiveSource(Constants.ADDR_INVALID, Constants.INVALID_PHYSICAL_ADDRESS);
+ mService.setActiveSource(Constants.ADDR_INVALID, Constants.INVALID_PHYSICAL_ADDRESS,
+ "HdmiCecLocalDevicePlayback#onStandby()");
if (initiatedByCec || !mAutoTvOff || !wasActiveSource) {
return;
}
@@ -399,7 +400,8 @@ public class HdmiCecLocalDevicePlayback extends HdmiCecLocalDeviceSource {
protected void handleRoutingChangeAndInformation(int physicalAddress, HdmiCecMessage message) {
assertRunOnServiceThread();
if (physicalAddress != mService.getPhysicalAddress()) {
- setActiveSource(physicalAddress);
+ setActiveSource(physicalAddress,
+ "HdmiCecLocalDevicePlayback#handleRoutingChangeAndInformation()");
return;
}
switch (mPlaybackDeviceActionOnRoutingControl) {
diff --git a/services/core/java/com/android/server/hdmi/HdmiCecLocalDeviceSource.java b/services/core/java/com/android/server/hdmi/HdmiCecLocalDeviceSource.java
index 44ad8eea65ca..4ff36c4b65db 100644
--- a/services/core/java/com/android/server/hdmi/HdmiCecLocalDeviceSource.java
+++ b/services/core/java/com/android/server/hdmi/HdmiCecLocalDeviceSource.java
@@ -119,11 +119,11 @@ abstract class HdmiCecLocalDeviceSource extends HdmiCecLocalDevice {
}
@ServiceThreadOnly
- protected void setActiveSource(int physicalAddress) {
+ protected void setActiveSource(int physicalAddress, String caller) {
assertRunOnServiceThread();
// Invalidate the internal active source record. This will also update mIsActiveSource.
ActiveSource activeSource = ActiveSource.of(Constants.ADDR_INVALID, physicalAddress);
- setActiveSource(activeSource);
+ setActiveSource(activeSource, caller);
}
@ServiceThreadOnly
@@ -133,7 +133,7 @@ abstract class HdmiCecLocalDeviceSource extends HdmiCecLocalDevice {
int physicalAddress = HdmiUtils.twoBytesToInt(message.getParams());
ActiveSource activeSource = ActiveSource.of(logicalAddress, physicalAddress);
if (!getActiveSource().equals(activeSource)) {
- setActiveSource(activeSource);
+ setActiveSource(activeSource, "HdmiCecLocalDeviceSource#handleActiveSource()");
}
setIsActiveSource(physicalAddress == mService.getPhysicalAddress());
updateDevicePowerStatus(logicalAddress, HdmiControlManager.POWER_STATUS_ON);
@@ -162,7 +162,7 @@ abstract class HdmiCecLocalDeviceSource extends HdmiCecLocalDevice {
setAndBroadcastActiveSource(message, physicalAddress);
}
if (physicalAddress != mService.getPhysicalAddress()) {
- setActiveSource(physicalAddress);
+ setActiveSource(physicalAddress, "HdmiCecLocalDeviceSource#handleSetStreamPath()");
}
switchInputOnReceivingNewActivePath(physicalAddress);
return true;
@@ -174,7 +174,7 @@ abstract class HdmiCecLocalDeviceSource extends HdmiCecLocalDevice {
assertRunOnServiceThread();
int physicalAddress = HdmiUtils.twoBytesToInt(message.getParams(), 2);
if (physicalAddress != mService.getPhysicalAddress()) {
- setActiveSource(physicalAddress);
+ setActiveSource(physicalAddress, "HdmiCecLocalDeviceSource#handleRoutingChange()");
}
if (!isRoutingControlFeatureEnabled()) {
mService.maySendFeatureAbortCommand(message, Constants.ABORT_REFUSED);
@@ -196,7 +196,7 @@ abstract class HdmiCecLocalDeviceSource extends HdmiCecLocalDevice {
assertRunOnServiceThread();
int physicalAddress = HdmiUtils.twoBytesToInt(message.getParams());
if (physicalAddress != mService.getPhysicalAddress()) {
- setActiveSource(physicalAddress);
+ setActiveSource(physicalAddress, "HdmiCecLocalDeviceSource#handleRoutingInformation()");
}
if (!isRoutingControlFeatureEnabled()) {
mService.maySendFeatureAbortCommand(message, Constants.ABORT_REFUSED);
diff --git a/services/core/java/com/android/server/hdmi/HdmiCecLocalDeviceTv.java b/services/core/java/com/android/server/hdmi/HdmiCecLocalDeviceTv.java
index 804cc92cca08..0325ad929849 100644
--- a/services/core/java/com/android/server/hdmi/HdmiCecLocalDeviceTv.java
+++ b/services/core/java/com/android/server/hdmi/HdmiCecLocalDeviceTv.java
@@ -288,13 +288,14 @@ final class HdmiCecLocalDeviceTv extends HdmiCecLocalDevice {
if (targetAddress == Constants.ADDR_INTERNAL) {
handleSelectInternalSource();
// Switching to internal source is always successful even when CEC control is disabled.
- setActiveSource(targetAddress, mService.getPhysicalAddress());
+ setActiveSource(targetAddress, mService.getPhysicalAddress(),
+ "HdmiCecLocalDeviceTv#deviceSelect()");
setActivePath(mService.getPhysicalAddress());
invokeCallback(callback, HdmiControlManager.RESULT_SUCCESS);
return;
}
if (!mService.isControlEnabled()) {
- setActiveSource(targetDevice);
+ setActiveSource(targetDevice, "HdmiCecLocalDeviceTv#deviceSelect()");
invokeCallback(callback, HdmiControlManager.RESULT_INCORRECT_MODE);
return;
}
@@ -307,7 +308,8 @@ final class HdmiCecLocalDeviceTv extends HdmiCecLocalDevice {
assertRunOnServiceThread();
// Seq #18
if (mService.isControlEnabled() && getActiveSource().logicalAddress != mAddress) {
- updateActiveSource(mAddress, mService.getPhysicalAddress());
+ updateActiveSource(mAddress, mService.getPhysicalAddress(),
+ "HdmiCecLocalDeviceTv#handleSelectInternalSource()");
if (mSkipRoutingControl) {
mSkipRoutingControl = false;
return;
@@ -319,19 +321,19 @@ final class HdmiCecLocalDeviceTv extends HdmiCecLocalDevice {
}
@ServiceThreadOnly
- void updateActiveSource(int logicalAddress, int physicalAddress) {
+ void updateActiveSource(int logicalAddress, int physicalAddress, String caller) {
assertRunOnServiceThread();
- updateActiveSource(ActiveSource.of(logicalAddress, physicalAddress));
+ updateActiveSource(ActiveSource.of(logicalAddress, physicalAddress), caller);
}
@ServiceThreadOnly
- void updateActiveSource(ActiveSource newActive) {
+ void updateActiveSource(ActiveSource newActive, String caller) {
assertRunOnServiceThread();
// Seq #14
if (getActiveSource().equals(newActive)) {
return;
}
- setActiveSource(newActive);
+ setActiveSource(newActive, caller);
int logicalAddress = newActive.logicalAddress;
if (getCecDeviceInfo(logicalAddress) != null && logicalAddress != mAddress) {
if (mService.pathToPortId(newActive.physicalAddress) == getActivePortId()) {
diff --git a/services/core/java/com/android/server/hdmi/HdmiCecMessageBuilder.java b/services/core/java/com/android/server/hdmi/HdmiCecMessageBuilder.java
index 3f949bab8a2e..653323de8d60 100644
--- a/services/core/java/com/android/server/hdmi/HdmiCecMessageBuilder.java
+++ b/services/core/java/com/android/server/hdmi/HdmiCecMessageBuilder.java
@@ -25,7 +25,7 @@ import java.util.Arrays;
* A helper class to build {@link HdmiCecMessage} from various cec commands.
*/
public class HdmiCecMessageBuilder {
- private static final int OSD_NAME_MAX_LENGTH = 13;
+ private static final int OSD_NAME_MAX_LENGTH = 14;
private HdmiCecMessageBuilder() {}
diff --git a/services/core/java/com/android/server/hdmi/HdmiCecMessageValidator.java b/services/core/java/com/android/server/hdmi/HdmiCecMessageValidator.java
index 4ad51de2e25b..0b4f31d365d3 100644
--- a/services/core/java/com/android/server/hdmi/HdmiCecMessageValidator.java
+++ b/services/core/java/com/android/server/hdmi/HdmiCecMessageValidator.java
@@ -293,6 +293,11 @@ public class HdmiCecMessageValidator {
return success ? OK : ERROR_PARAMETER;
}
+ private boolean isWithinRange(int value, int min, int max) {
+ value = value & 0xFF;
+ return (value >= min && value <= max);
+ }
+
private class PhysicalAddressValidator implements ParameterValidator {
@Override
public int isValid(byte[] params) {
diff --git a/services/core/java/com/android/server/hdmi/HdmiControlService.java b/services/core/java/com/android/server/hdmi/HdmiControlService.java
index 0576e91b79eb..44b6a63faea1 100644
--- a/services/core/java/com/android/server/hdmi/HdmiControlService.java
+++ b/services/core/java/com/android/server/hdmi/HdmiControlService.java
@@ -1970,7 +1970,21 @@ public class HdmiControlService extends SystemService {
@Override
public void powerOnRemoteDevice(int logicalAddress, int powerStatus) {
- // TODO(amyjojo): implement the method
+ enforceAccessPermission();
+ runOnServiceThread(new Runnable() {
+ @Override
+ public void run() {
+ Slog.i(TAG, "Device "
+ + logicalAddress + " power status is " + powerStatus
+ + " before power on command sent out");
+ if (getSwitchDevice() != null) {
+ getSwitchDevice().sendUserControlPressedAndReleased(
+ logicalAddress, HdmiCecKeycode.CEC_KEYCODE_POWER_ON_FUNCTION);
+ } else {
+ Slog.e(TAG, "Can't get the correct local device to handle routing.");
+ }
+ }
+ });
}
@Override
@@ -3214,7 +3228,7 @@ public class HdmiControlService extends SystemService {
}
}
- void setActiveSource(int logicalAddress, int physicalAddress) {
+ void setActiveSource(int logicalAddress, int physicalAddress, String caller) {
synchronized (mLock) {
mActiveSource.logicalAddress = logicalAddress;
mActiveSource.physicalAddress = physicalAddress;
@@ -3225,14 +3239,17 @@ public class HdmiControlService extends SystemService {
// mIsActiveSource only exists in source device, ignore this setting if the current
// device is not an HdmiCecLocalDeviceSource.
if (!(device instanceof HdmiCecLocalDeviceSource)) {
+ device.addActiveSourceHistoryItem(new ActiveSource(logicalAddress, physicalAddress),
+ false, caller);
continue;
}
- if (logicalAddress == device.getDeviceInfo().getLogicalAddress()
- && physicalAddress == getPhysicalAddress()) {
- ((HdmiCecLocalDeviceSource) device).setIsActiveSource(true);
- } else {
- ((HdmiCecLocalDeviceSource) device).setIsActiveSource(false);
- }
+ boolean deviceIsActiveSource =
+ logicalAddress == device.getDeviceInfo().getLogicalAddress()
+ && physicalAddress == getPhysicalAddress();
+
+ ((HdmiCecLocalDeviceSource) device).setIsActiveSource(deviceIsActiveSource);
+ device.addActiveSourceHistoryItem(new ActiveSource(logicalAddress, physicalAddress),
+ deviceIsActiveSource, caller);
}
}
diff --git a/services/core/java/com/android/server/inputmethod/InputMethodManagerService.java b/services/core/java/com/android/server/inputmethod/InputMethodManagerService.java
index 9ab410d258cc..3235b20fb75e 100644
--- a/services/core/java/com/android/server/inputmethod/InputMethodManagerService.java
+++ b/services/core/java/com/android/server/inputmethod/InputMethodManagerService.java
@@ -2591,7 +2591,7 @@ public class InputMethodManagerService extends IInputMethodManager.Stub
if (mCurIntent != null && name.equals(mCurIntent.getComponent())) {
mCurMethod = IInputMethod.Stub.asInterface(service);
final String curMethodPackage = mCurIntent.getComponent().getPackageName();
- final int curMethodUid = mPackageManagerInternal.getPackageUidInternal(
+ final int curMethodUid = mPackageManagerInternal.getPackageUid(
curMethodPackage, 0 /* flags */, mSettings.getCurrentUserId());
if (curMethodUid < 0) {
Slog.e(TAG, "Failed to get UID for package=" + curMethodPackage);
@@ -3274,6 +3274,9 @@ public class InputMethodManagerService extends IInputMethodManager.Stub
boolean hideCurrentInputLocked(IBinder windowToken, int flags, ResultReceiver resultReceiver,
@SoftInputShowHideReason int reason) {
+ if (mCurClient == null || mCurClient.curSession == null) {
+ return false;
+ }
if ((flags&InputMethodManager.HIDE_IMPLICIT_ONLY) != 0
&& (mShowExplicitlyRequested || mShowForced)) {
if (DEBUG) Slog.v(TAG, "Not hiding: explicit show not cancelled by non-explicit hide");
@@ -3458,7 +3461,9 @@ public class InputMethodManagerService extends IInputMethodManager.Stub
// pre-rendering not supported on low-ram devices.
cs.shouldPreRenderIme = DebugFlags.FLAG_PRE_RENDER_IME_VIEWS.value() && !mIsLowRam;
- if (mCurFocusedWindow == windowToken) {
+ final boolean sameWindowFocused = mCurFocusedWindow == windowToken;
+ final boolean isTextEditor = (startInputFlags & StartInputFlags.IS_TEXT_EDITOR) != 0;
+ if (sameWindowFocused && isTextEditor) {
if (DEBUG) {
Slog.w(TAG, "Window already focused, ignoring focus gain of: " + client
+ " attribute=" + attribute + ", token = " + windowToken
@@ -3473,6 +3478,7 @@ public class InputMethodManagerService extends IInputMethodManager.Stub
InputBindResult.ResultCode.SUCCESS_REPORT_WINDOW_FOCUS_ONLY,
null, null, null, -1, null);
}
+
mCurFocusedWindow = windowToken;
mCurFocusedWindowSoftInputMode = softInputMode;
mCurFocusedWindowClient = cs;
@@ -3490,7 +3496,6 @@ public class InputMethodManagerService extends IInputMethodManager.Stub
== LayoutParams.SOFT_INPUT_ADJUST_RESIZE
|| mRes.getConfiguration().isLayoutSizeAtLeast(
Configuration.SCREENLAYOUT_SIZE_LARGE);
- final boolean isTextEditor = (startInputFlags & StartInputFlags.IS_TEXT_EDITOR) != 0;
// We want to start input before showing the IME, but after closing
// it. We want to do this after closing it to help the IME disappear
@@ -3550,9 +3555,11 @@ public class InputMethodManagerService extends IInputMethodManager.Stub
}
break;
case LayoutParams.SOFT_INPUT_STATE_ALWAYS_HIDDEN:
- if (DEBUG) Slog.v(TAG, "Window asks to hide input");
- hideCurrentInputLocked(mCurFocusedWindow, 0, null,
- SoftInputShowHideReason.HIDE_ALWAYS_HIDDEN_STATE);
+ if (isImeVisible()) {
+ if (DEBUG) Slog.v(TAG, "Window asks to hide input");
+ hideCurrentInputLocked(mCurFocusedWindow, 0, null,
+ SoftInputShowHideReason.HIDE_ALWAYS_HIDDEN_STATE);
+ }
break;
case LayoutParams.SOFT_INPUT_STATE_VISIBLE:
if ((softInputMode & LayoutParams.SOFT_INPUT_IS_FORWARD_NAVIGATION) != 0) {
@@ -3577,13 +3584,15 @@ public class InputMethodManagerService extends IInputMethodManager.Stub
if (DEBUG) Slog.v(TAG, "Window asks to always show input");
if (InputMethodUtils.isSoftInputModeStateVisibleAllowed(
unverifiedTargetSdkVersion, startInputFlags)) {
- if (attribute != null) {
- res = startInputUncheckedLocked(cs, inputContext, missingMethods,
- attribute, startInputFlags, startInputReason);
- didStart = true;
+ if (!isImeVisible()) {
+ if (attribute != null) {
+ res = startInputUncheckedLocked(cs, inputContext, missingMethods,
+ attribute, startInputFlags, startInputReason);
+ didStart = true;
+ }
+ showCurrentInputLocked(windowToken, InputMethodManager.SHOW_IMPLICIT, null,
+ SoftInputShowHideReason.SHOW_STATE_ALWAYS_VISIBLE);
}
- showCurrentInputLocked(windowToken, InputMethodManager.SHOW_IMPLICIT, null,
- SoftInputShowHideReason.SHOW_STATE_ALWAYS_VISIBLE);
} else {
Slog.e(TAG, "SOFT_INPUT_STATE_ALWAYS_VISIBLE is ignored because"
+ " there is no focused view that also returns true from"
@@ -3601,6 +3610,10 @@ public class InputMethodManagerService extends IInputMethodManager.Stub
} else {
res = InputBindResult.NO_EDITOR;
}
+ } else if (sameWindowFocused) {
+ return new InputBindResult(
+ InputBindResult.ResultCode.SUCCESS_REPORT_WINDOW_FOCUS_ONLY,
+ null, null, null, -1, null);
} else {
res = InputBindResult.NULL_EDITOR_INFO;
}
@@ -3608,6 +3621,10 @@ public class InputMethodManagerService extends IInputMethodManager.Stub
return res;
}
+ private boolean isImeVisible() {
+ return (mImeWindowVis & InputMethodService.IME_VISIBLE) != 0;
+ }
+
private boolean canShowInputMethodPickerLocked(IInputMethodClient client) {
// TODO(yukawa): multi-display support.
final int uid = Binder.getCallingUid();
diff --git a/services/core/java/com/android/server/inputmethod/TEST_MAPPING b/services/core/java/com/android/server/inputmethod/TEST_MAPPING
new file mode 100644
index 000000000000..0ccd75dcbdce
--- /dev/null
+++ b/services/core/java/com/android/server/inputmethod/TEST_MAPPING
@@ -0,0 +1,7 @@
+{
+ "imports": [
+ {
+ "path": "frameworks/base/core/java/android/view/inputmethod"
+ }
+ ]
+}
diff --git a/services/core/java/com/android/server/integrity/AppIntegrityManagerServiceImpl.java b/services/core/java/com/android/server/integrity/AppIntegrityManagerServiceImpl.java
index 817902d9d566..b61c6a7ca569 100644
--- a/services/core/java/com/android/server/integrity/AppIntegrityManagerServiceImpl.java
+++ b/services/core/java/com/android/server/integrity/AppIntegrityManagerServiceImpl.java
@@ -205,8 +205,13 @@ public class AppIntegrityManagerServiceImpl extends IAppIntegrityManager.Stub {
}
if (DEBUG_INTEGRITY_COMPONENT) {
- Slog.i(TAG, String.format("Successfully pushed rule set: %s", version));
+ Slog.i(
+ TAG,
+ String.format(
+ "Successfully pushed rule set to version '%s' from '%s'",
+ version, ruleProvider));
}
+
FrameworkStatsLog.write(
FrameworkStatsLog.INTEGRITY_RULES_PUSHED,
success,
@@ -324,13 +329,12 @@ public class AppIntegrityManagerServiceImpl extends IAppIntegrityManager.Stub {
+ getAllowedInstallers(packageInfo));
}
IntegrityCheckResult result = mEvaluationEngine.evaluate(appInstallMetadata);
- if (DEBUG_INTEGRITY_COMPONENT) {
+ if (!result.getMatchedRules().isEmpty() || DEBUG_INTEGRITY_COMPONENT) {
Slog.i(
TAG,
- "Integrity check result: "
- + result.getEffect()
- + " due to "
- + result.getMatchedRules());
+ String.format(
+ "Integrity check of %s result: %s due to %s",
+ packageName, result.getEffect(), result.getMatchedRules()));
}
FrameworkStatsLog.write(
@@ -673,8 +677,10 @@ public class AppIntegrityManagerServiceImpl extends IAppIntegrityManager.Stub {
// Obtain the system apps that are whitelisted in config_integrityRuleProviderPackages.
List<String> allowedRuleProviders = getAllowedRuleProviderSystemApps();
if (DEBUG_INTEGRITY_COMPONENT) {
- Slog.i(TAG, String.format(
- "Rule provider system app list contains: %s", allowedRuleProviders));
+ Slog.i(
+ TAG,
+ String.format(
+ "Rule provider system app list contains: %s", allowedRuleProviders));
}
// Identify the package names in the caller list.
@@ -730,9 +736,9 @@ public class AppIntegrityManagerServiceImpl extends IAppIntegrityManager.Stub {
private boolean integrityCheckIncludesRuleProvider() {
return Settings.Global.getInt(
- mContext.getContentResolver(),
- Settings.Global.INTEGRITY_CHECK_INCLUDES_RULE_PROVIDER,
- 0)
+ mContext.getContentResolver(),
+ Settings.Global.INTEGRITY_CHECK_INCLUDES_RULE_PROVIDER,
+ 0)
== 1;
}
diff --git a/services/core/java/com/android/server/location/LocationManagerService.java b/services/core/java/com/android/server/location/LocationManagerService.java
index 71f1833854ce..f4d0a6254318 100644
--- a/services/core/java/com/android/server/location/LocationManagerService.java
+++ b/services/core/java/com/android/server/location/LocationManagerService.java
@@ -697,7 +697,8 @@ public class LocationManagerService extends ILocationManager.Stub {
return null;
}
- Location location = manager.getLastLocation(request, identity, permissionLevel);
+ Location location = manager.getLastLocation(identity, permissionLevel,
+ request.isLocationSettingsIgnored());
// lastly - note app ops
if (!mInjector.getAppOpsHelper().noteOpNoThrow(LocationPermissions.asAppOp(permissionLevel),
@@ -740,13 +741,9 @@ public class LocationManagerService extends ILocationManager.Stub {
return null;
}
- // create a location request that works in almost all circumstances
- LocationRequest request = LocationRequest.createFromDeprecatedProvider(GPS_PROVIDER, 0,
- 0, true);
-
- // use our own identity rather than the caller
- CallerIdentity identity = CallerIdentity.fromContext(mContext);
- Location location = gpsManager.getLastLocation(request, identity, PERMISSION_FINE);
+ // use fine permission level to avoid creating unnecessary coarse locations
+ Location location = gpsManager.getLastLocationUnsafe(UserHandle.USER_ALL,
+ PERMISSION_FINE, false);
if (location == null) {
return null;
}
@@ -1133,9 +1130,7 @@ public class LocationManagerService extends ILocationManager.Stub {
return;
}
- String dumpFilter = args.length == 0 ? null : args[0];
-
- ipw.println("Location Manager State:");
+ ipw.print("Location Manager State:");
ipw.increaseIndent();
ipw.println("Elapsed Realtime: " + TimeUtils.formatDuration(SystemClock.elapsedRealtime()));
@@ -1166,34 +1161,28 @@ public class LocationManagerService extends ILocationManager.Stub {
ipw.println(
"Location Controller Extra Package: " + mExtraLocationControllerPackage
+ (mExtraLocationControllerPackageEnabled ? " [enabled]"
- : "[disabled]"));
+ : " [disabled]"));
}
}
ipw.println("Location Providers:");
ipw.increaseIndent();
for (LocationProviderManager manager : mProviderManagers) {
- if (dumpFilter == null || manager.getName().equals(dumpFilter)) {
- manager.dump(fd, ipw, args);
- }
+ manager.dump(fd, ipw, args);
}
ipw.decreaseIndent();
- if (dumpFilter == null || GPS_PROVIDER.equals(dumpFilter)) {
- if (mGnssManagerService != null) {
- ipw.println("GNSS Manager:");
- ipw.increaseIndent();
- mGnssManagerService.dump(fd, ipw, args);
- ipw.decreaseIndent();
- }
- }
-
- if (dumpFilter == null || "geofence".equals(dumpFilter)) {
- ipw.println("Geofence Manager:");
+ if (mGnssManagerService != null) {
+ ipw.println("GNSS Manager:");
ipw.increaseIndent();
- mGeofenceManager.dump(fd, ipw, args);
+ mGnssManagerService.dump(fd, ipw, args);
ipw.decreaseIndent();
}
+
+ ipw.println("Geofence Manager:");
+ ipw.increaseIndent();
+ mGeofenceManager.dump(fd, ipw, args);
+ ipw.decreaseIndent();
}
private class LocalService extends LocationManagerInternal {
diff --git a/services/core/java/com/android/server/location/LocationProviderManager.java b/services/core/java/com/android/server/location/LocationProviderManager.java
index 05aa3150cfef..1815a8554705 100644
--- a/services/core/java/com/android/server/location/LocationProviderManager.java
+++ b/services/core/java/com/android/server/location/LocationProviderManager.java
@@ -84,7 +84,7 @@ import com.android.server.LocalServices;
import com.android.server.PendingIntentUtils;
import com.android.server.location.LocationPermissions.PermissionLevel;
import com.android.server.location.listeners.ListenerMultiplexer;
-import com.android.server.location.listeners.RemovableListenerRegistration;
+import com.android.server.location.listeners.RemoteListenerRegistration;
import com.android.server.location.util.AppForegroundHelper;
import com.android.server.location.util.AppForegroundHelper.AppForegroundListener;
import com.android.server.location.util.AppOpsHelper;
@@ -154,15 +154,8 @@ class LocationProviderManager extends
@Override
public void deliverOnLocationChanged(Location location,
- @Nullable Runnable onCompleteCallback)
- throws RemoteException {
- mListener.onLocationChanged(location,
- onCompleteCallback == null ? null : new IRemoteCallback.Stub() {
- @Override
- public void sendResult(Bundle data) {
- onCompleteCallback.run();
- }
- });
+ @Nullable Runnable onCompleteCallback) throws RemoteException {
+ mListener.onLocationChanged(location, SingleUseCallback.wrap(onCompleteCallback));
}
@Override
@@ -221,7 +214,7 @@ class LocationProviderManager extends
}
protected abstract class Registration extends
- RemovableListenerRegistration<LocationRequest, LocationTransport> {
+ RemoteListenerRegistration<LocationRequest, LocationTransport> {
@PermissionLevel protected final int mPermissionLevel;
private final WorkSource mWorkSource;
@@ -306,11 +299,20 @@ class LocationProviderManager extends
}
@Override
- protected final void onInactive() {
+ protected final ListenerOperation<LocationTransport> onInactive() {
onHighPowerUsageChanged();
if (!getRequest().getHideFromAppOps()) {
mLocationAttributionHelper.reportLocationStop(getIdentity(), getName(), getKey());
}
+ return null;
+ }
+
+ @Override
+ public final <Listener> void onOperationFailure(ListenerOperation<Listener> operation,
+ Exception e) {
+ synchronized (mLock) {
+ super.onOperationFailure(operation, e);
+ }
}
@Override
@@ -432,18 +434,17 @@ class LocationProviderManager extends
}
LocationRequest newRequest = calculateProviderLocationRequest();
- if (!mProviderLocationRequest.equals(newRequest)) {
- LocationRequest oldRequest = mProviderLocationRequest;
- mProviderLocationRequest = newRequest;
- onHighPowerUsageChanged();
- updateService();
-
- // if location settings ignored has changed then the active state may have changed
- return oldRequest.isLocationSettingsIgnored()
- != newRequest.isLocationSettingsIgnored();
+ if (mProviderLocationRequest.equals(newRequest)) {
+ return false;
}
- return false;
+ LocationRequest oldRequest = mProviderLocationRequest;
+ mProviderLocationRequest = newRequest;
+ onHighPowerUsageChanged();
+ updateService();
+
+ // if location settings ignored has changed then the active state may have changed
+ return oldRequest.isLocationSettingsIgnored() != newRequest.isLocationSettingsIgnored();
}
private LocationRequest calculateProviderLocationRequest() {
@@ -818,6 +819,12 @@ class LocationProviderManager extends
@GuardedBy("mLock")
@Override
protected void onProviderListenerRegister() {
+ try {
+ ((IBinder) getKey()).linkToDeath(this, 0);
+ } catch (RemoteException e) {
+ remove();
+ }
+
mExpirationRealtimeMs = getRequest().getExpirationRealtimeMs(
SystemClock.elapsedRealtime());
@@ -829,12 +836,6 @@ class LocationProviderManager extends
0, this, FgThread.getHandler(), getWorkSource());
}
- try {
- ((IBinder) getKey()).linkToDeath(this, 0);
- } catch (RemoteException e) {
- remove();
- }
-
// start listening for provider enabled/disabled events
addEnabledListener(this);
@@ -1058,8 +1059,13 @@ class LocationProviderManager extends
mUserInfoHelper.addListener(mUserChangedListener);
mSettingsHelper.addOnLocationEnabledChangedListener(mLocationEnabledChangedListener);
- // initialize enabled state
- onUserStarted(UserHandle.USER_ALL);
+ long identity = Binder.clearCallingIdentity();
+ try {
+ // initialize enabled state
+ onUserStarted(UserHandle.USER_ALL);
+ } finally {
+ Binder.restoreCallingIdentity(identity);
+ }
}
}
@@ -1069,10 +1075,15 @@ class LocationProviderManager extends
mSettingsHelper.removeOnLocationEnabledChangedListener(mLocationEnabledChangedListener);
// notify and remove all listeners
- onUserStopped(UserHandle.USER_ALL);
- removeRegistrationIf(key -> true);
- mEnabledListeners.clear();
+ long identity = Binder.clearCallingIdentity();
+ try {
+ onUserStopped(UserHandle.USER_ALL);
+ removeRegistrationIf(key -> true);
+ } finally {
+ Binder.restoreCallingIdentity(identity);
+ }
+ mEnabledListeners.clear();
mStarted = false;
}
}
@@ -1133,14 +1144,26 @@ class LocationProviderManager extends
public void setRealProvider(AbstractLocationProvider provider) {
synchronized (mLock) {
Preconditions.checkState(mStarted);
- mProvider.setRealProvider(provider);
+
+ long identity = Binder.clearCallingIdentity();
+ try {
+ mProvider.setRealProvider(provider);
+ } finally {
+ Binder.restoreCallingIdentity(identity);
+ }
}
}
public void setMockProvider(@Nullable MockProvider provider) {
synchronized (mLock) {
Preconditions.checkState(mStarted);
- mProvider.setMockProvider(provider);
+
+ long identity = Binder.clearCallingIdentity();
+ try {
+ mProvider.setMockProvider(provider);
+ } finally {
+ Binder.restoreCallingIdentity(identity);
+ }
// when removing a mock provider, also clear any mock last locations and reset the
// location fudger. the mock provider could have been used to infer the current
@@ -1162,7 +1185,12 @@ class LocationProviderManager extends
throw new IllegalArgumentException(mName + " provider is not a test provider");
}
- mProvider.setMockProviderAllowed(enabled);
+ long identity = Binder.clearCallingIdentity();
+ try {
+ mProvider.setMockProviderAllowed(enabled);
+ } finally {
+ Binder.restoreCallingIdentity(identity);
+ }
}
}
@@ -1172,15 +1200,20 @@ class LocationProviderManager extends
throw new IllegalArgumentException(mName + " provider is not a test provider");
}
- String locationProvider = location.getProvider();
- if (!TextUtils.isEmpty(locationProvider) && !mName.equals(locationProvider)) {
- // The location has an explicit provider that is different from the mock
- // provider name. The caller may be trying to fool us via b/33091107.
- EventLog.writeEvent(0x534e4554, "33091107", Binder.getCallingUid(),
- mName + "!=" + locationProvider);
- }
+ long identity = Binder.clearCallingIdentity();
+ try {
+ String locationProvider = location.getProvider();
+ if (!TextUtils.isEmpty(locationProvider) && !mName.equals(locationProvider)) {
+ // The location has an explicit provider that is different from the mock
+ // provider name. The caller may be trying to fool us via b/33091107.
+ EventLog.writeEvent(0x534e4554, "33091107", Binder.getCallingUid(),
+ mName + "!=" + locationProvider);
+ }
- mProvider.setMockProviderLocation(location);
+ mProvider.setMockProviderLocation(location);
+ } finally {
+ Binder.restoreCallingIdentity(identity);
+ }
}
}
@@ -1195,10 +1228,8 @@ class LocationProviderManager extends
}
@Nullable
- public Location getLastLocation(LocationRequest request, CallerIdentity identity,
- @PermissionLevel int permissionLevel) {
- Preconditions.checkArgument(mName.equals(request.getProvider()));
-
+ public Location getLastLocation(CallerIdentity identity, @PermissionLevel int permissionLevel,
+ boolean ignoreLocationSettings) {
if (mSettingsHelper.isLocationPackageBlacklisted(identity.getUserId(),
identity.getPackageName())) {
return null;
@@ -1206,12 +1237,12 @@ class LocationProviderManager extends
if (!mUserInfoHelper.isCurrentUserId(identity.getUserId())) {
return null;
}
- if (!request.isLocationSettingsIgnored() && !isEnabled(identity.getUserId())) {
+ if (!ignoreLocationSettings && !isEnabled(identity.getUserId())) {
return null;
}
- Location location = getLastLocation(identity.getUserId(), permissionLevel,
- request.isLocationSettingsIgnored());
+ Location location = getLastLocationUnsafe(identity.getUserId(), permissionLevel,
+ ignoreLocationSettings);
// we don't note op here because we don't know what the client intends to do with the
// location, the client is responsible for noting if necessary
@@ -1225,9 +1256,30 @@ class LocationProviderManager extends
}
}
+ /**
+ * This function does not perform any permissions or safety checks, by calling it you are
+ * committing to performing all applicable checks yourself. Prefer
+ * {@link #getLastLocation(CallerIdentity, int, boolean)} where possible.
+ */
@Nullable
- private Location getLastLocation(int userId, @PermissionLevel int permissionLevel,
+ public Location getLastLocationUnsafe(int userId, @PermissionLevel int permissionLevel,
boolean ignoreLocationSettings) {
+ if (userId == UserHandle.USER_ALL) {
+ Location lastLocation = null;
+ final int[] runningUserIds = mUserInfoHelper.getRunningUserIds();
+ for (int i = 0; i < runningUserIds.length; i++) {
+ Location next = getLastLocationUnsafe(runningUserIds[i], permissionLevel,
+ ignoreLocationSettings);
+ if (lastLocation == null || (next != null && next.getElapsedRealtimeNanos()
+ > lastLocation.getElapsedRealtimeNanos())) {
+ lastLocation = next;
+ }
+ }
+ return lastLocation;
+ }
+
+ Preconditions.checkArgument(userId >= 0);
+
synchronized (mLock) {
LastLocation lastLocation = mLastLocations.get(userId);
if (lastLocation == null) {
@@ -1239,7 +1291,7 @@ class LocationProviderManager extends
public void injectLastLocation(Location location, int userId) {
synchronized (mLock) {
- if (getLastLocation(userId, PERMISSION_FINE, false) == null) {
+ if (getLastLocationUnsafe(userId, PERMISSION_FINE, false) == null) {
setLastLocation(location, userId);
}
}
@@ -1271,7 +1323,7 @@ class LocationProviderManager extends
}
}
- public void getCurrentLocation(LocationRequest request, CallerIdentity identity,
+ public void getCurrentLocation(LocationRequest request, CallerIdentity callerIdentity,
int permissionLevel, ICancellationSignal cancellationTransport,
ILocationCallback callback) {
Preconditions.checkArgument(mName.equals(request.getProvider()));
@@ -1283,12 +1335,27 @@ class LocationProviderManager extends
GetCurrentLocationListenerRegistration registration =
new GetCurrentLocationListenerRegistration(
request,
- identity,
+ callerIdentity,
new GetCurrentLocationTransport(callback),
permissionLevel);
synchronized (mLock) {
- Location lastLocation = getLastLocation(request, identity, permissionLevel);
+ if (mSettingsHelper.isLocationPackageBlacklisted(callerIdentity.getUserId(),
+ callerIdentity.getPackageName())) {
+ registration.deliverLocation(null);
+ return;
+ }
+ if (!mUserInfoHelper.isCurrentUserId(callerIdentity.getUserId())) {
+ registration.deliverLocation(null);
+ return;
+ }
+ if (!request.isLocationSettingsIgnored() && !isEnabled(callerIdentity.getUserId())) {
+ registration.deliverLocation(null);
+ return;
+ }
+
+ Location lastLocation = getLastLocationUnsafe(callerIdentity.getUserId(),
+ permissionLevel, request.isLocationSettingsIgnored());
if (lastLocation != null) {
long locationAgeMs = NANOSECONDS.toMillis(
SystemClock.elapsedRealtimeNanos()
@@ -1306,63 +1373,94 @@ class LocationProviderManager extends
}
// if last location isn't good enough then we add a location request
- addRegistration(callback.asBinder(), registration);
- CancellationSignal cancellationSignal = CancellationSignal.fromTransport(
- cancellationTransport);
- if (cancellationSignal != null) {
- cancellationSignal.setOnCancelListener(
- () -> {
- synchronized (mLock) {
- removeRegistration(callback.asBinder(), registration);
- }
- });
+ long identity = Binder.clearCallingIdentity();
+ try {
+ addRegistration(callback.asBinder(), registration);
+ } finally {
+ Binder.restoreCallingIdentity(identity);
}
}
+
+ CancellationSignal cancellationSignal = CancellationSignal.fromTransport(
+ cancellationTransport);
+ if (cancellationSignal != null) {
+ cancellationSignal.setOnCancelListener(SingleUseCallback.wrap(
+ () -> {
+ synchronized (mLock) {
+ removeRegistration(callback.asBinder(), registration);
+ }
+ }));
+ }
}
public void sendExtraCommand(int uid, int pid, String command, Bundle extras) {
- mProvider.sendExtraCommand(uid, pid, command, extras);
+ long identity = Binder.clearCallingIdentity();
+ try {
+ mProvider.sendExtraCommand(uid, pid, command, extras);
+ } finally {
+ Binder.restoreCallingIdentity(identity);
+ }
}
- public void registerLocationRequest(LocationRequest request, CallerIdentity identity,
+ public void registerLocationRequest(LocationRequest request, CallerIdentity callerIdentity,
@PermissionLevel int permissionLevel, ILocationListener listener) {
Preconditions.checkArgument(mName.equals(request.getProvider()));
synchronized (mLock) {
- addRegistration(
- listener.asBinder(),
- new LocationListenerRegistration(
- request,
- identity,
- new LocationListenerTransport(listener),
- permissionLevel));
+ long identity = Binder.clearCallingIdentity();
+ try {
+ addRegistration(
+ listener.asBinder(),
+ new LocationListenerRegistration(
+ request,
+ callerIdentity,
+ new LocationListenerTransport(listener),
+ permissionLevel));
+ } finally {
+ Binder.restoreCallingIdentity(identity);
+ }
}
}
- public void registerLocationRequest(LocationRequest request, CallerIdentity identity,
+ public void registerLocationRequest(LocationRequest request, CallerIdentity callerIdentity,
@PermissionLevel int permissionLevel, PendingIntent pendingIntent) {
Preconditions.checkArgument(mName.equals(request.getProvider()));
synchronized (mLock) {
- addRegistration(
- pendingIntent,
- new LocationPendingIntentRegistration(
- request,
- identity,
- new LocationPendingIntentTransport(mContext, pendingIntent),
- permissionLevel));
+ long identity = Binder.clearCallingIdentity();
+ try {
+ addRegistration(
+ pendingIntent,
+ new LocationPendingIntentRegistration(
+ request,
+ callerIdentity,
+ new LocationPendingIntentTransport(mContext, pendingIntent),
+ permissionLevel));
+ } finally {
+ Binder.restoreCallingIdentity(identity);
+ }
}
}
public void unregisterLocationRequest(ILocationListener listener) {
synchronized (mLock) {
- removeRegistration(listener.asBinder());
+ long identity = Binder.clearCallingIdentity();
+ try {
+ removeRegistration(listener.asBinder());
+ } finally {
+ Binder.restoreCallingIdentity(identity);
+ }
}
}
public void unregisterLocationRequest(PendingIntent pendingIntent) {
synchronized (mLock) {
- removeRegistration(pendingIntent);
+ long identity = Binder.clearCallingIdentity();
+ try {
+ removeRegistration(pendingIntent);
+ } finally {
+ Binder.restoreCallingIdentity(identity);
+ }
}
}
@@ -1869,7 +1967,8 @@ class LocationProviderManager extends
ipw.println("user " + userId + ":");
ipw.increaseIndent();
}
- ipw.println("last location=" + getLastLocation(userId, PERMISSION_FINE, false));
+ ipw.println(
+ "last location=" + getLastLocationUnsafe(userId, PERMISSION_FINE, false));
ipw.println("enabled=" + isEnabled(userId));
if (userIds.length != 1) {
ipw.decreaseIndent();
@@ -1942,7 +2041,7 @@ class LocationProviderManager extends
}
// update last coarse interval only if enough time has passed
long timeDeltaMs = NANOSECONDS.toMillis(newCoarse.getElapsedRealtimeNanos())
- - NANOSECONDS.toMillis(oldCoarse.getElapsedRealtimeNanos());
+ - NANOSECONDS.toMillis(oldCoarse.getElapsedRealtimeNanos());
if (timeDeltaMs > FASTEST_COARSE_INTERVAL_MS) {
return newCoarse;
} else {
@@ -1950,4 +2049,61 @@ class LocationProviderManager extends
}
}
}
+
+ private static class SingleUseCallback extends IRemoteCallback.Stub implements Runnable,
+ CancellationSignal.OnCancelListener {
+
+ @Nullable
+ public static SingleUseCallback wrap(@Nullable Runnable callback) {
+ return callback == null ? null : new SingleUseCallback(callback);
+ }
+
+ @GuardedBy("this")
+ @Nullable private Runnable mCallback;
+
+ private SingleUseCallback(Runnable callback) {
+ mCallback = Objects.requireNonNull(callback);
+ }
+
+ @Override
+ public void sendResult(Bundle data) {
+ run();
+ }
+
+ @Override
+ public void onCancel() {
+ run();
+ }
+
+ @Override
+ public void run() {
+ Runnable callback;
+ synchronized (this) {
+ callback = mCallback;
+ mCallback = null;
+ }
+
+ // prevent this callback from being run more than once - otherwise this could provide an
+ // attack vector for a malicious app to break assumptions on how many times a callback
+ // may be invoked, and thus crash system server.
+ if (callback == null) {
+ return;
+ }
+
+ long identity = Binder.clearCallingIdentity();
+ try {
+ callback.run();
+ } catch (RuntimeException e) {
+ // since this is within a oneway binder transaction there is nowhere
+ // for exceptions to go - move onto another thread to crash system
+ // server so we find out about it
+ FgThread.getExecutor().execute(() -> {
+ throw new AssertionError(e);
+ });
+ throw e;
+ } finally {
+ Binder.restoreCallingIdentity(identity);
+ }
+ }
+ }
}
diff --git a/services/core/java/com/android/server/location/geofence/GeofenceManager.java b/services/core/java/com/android/server/location/geofence/GeofenceManager.java
index 2d9734ef0553..2d7f02873b8f 100644
--- a/services/core/java/com/android/server/location/geofence/GeofenceManager.java
+++ b/services/core/java/com/android/server/location/geofence/GeofenceManager.java
@@ -32,6 +32,7 @@ import android.location.LocationListener;
import android.location.LocationManager;
import android.location.LocationRequest;
import android.location.util.identity.CallerIdentity;
+import android.os.Binder;
import android.os.PowerManager;
import android.os.SystemClock;
import android.os.WorkSource;
@@ -291,17 +292,28 @@ public class GeofenceManager extends
@Nullable String attributionTag) {
LocationPermissions.enforceCallingOrSelfLocationPermission(mContext, PERMISSION_FINE);
- CallerIdentity identity = CallerIdentity.fromBinder(mContext, packageName, attributionTag,
- AppOpsManager.toReceiverId(pendingIntent));
- addRegistration(new GeofenceKey(pendingIntent, geofence),
- new GeofenceRegistration(geofence, identity, pendingIntent));
+ CallerIdentity callerIdentity = CallerIdentity.fromBinder(mContext, packageName,
+ attributionTag, AppOpsManager.toReceiverId(pendingIntent));
+
+ long identity = Binder.clearCallingIdentity();
+ try {
+ addRegistration(new GeofenceKey(pendingIntent, geofence),
+ new GeofenceRegistration(geofence, callerIdentity, pendingIntent));
+ } finally {
+ Binder.restoreCallingIdentity(identity);
+ }
}
/**
* Removes the geofence associated with the PendingIntent.
*/
public void removeGeofence(PendingIntent pendingIntent) {
- removeRegistrationIf(key -> key.getPendingIntent().equals(pendingIntent));
+ long identity = Binder.clearCallingIdentity();
+ try {
+ removeRegistrationIf(key -> key.getPendingIntent().equals(pendingIntent));
+ } finally {
+ Binder.restoreCallingIdentity(identity);
+ }
}
@Override
diff --git a/services/core/java/com/android/server/location/gnss/GnssListenerMultiplexer.java b/services/core/java/com/android/server/location/gnss/GnssListenerMultiplexer.java
index 1b599b026c38..a9fdacca9a06 100644
--- a/services/core/java/com/android/server/location/gnss/GnssListenerMultiplexer.java
+++ b/services/core/java/com/android/server/location/gnss/GnssListenerMultiplexer.java
@@ -25,6 +25,7 @@ import android.annotation.Nullable;
import android.location.LocationManagerInternal;
import android.location.LocationManagerInternal.ProviderEnabledListener;
import android.location.util.identity.CallerIdentity;
+import android.os.Binder;
import android.os.IBinder;
import android.os.IInterface;
import android.os.Process;
@@ -218,16 +219,27 @@ public abstract class GnssListenerMultiplexer<TRequest, TListener extends IInter
/**
* Adds a listener with the given identity and request.
*/
- protected void addListener(TRequest request, CallerIdentity identity, TListener listener) {
- addRegistration(listener.asBinder(),
- new GnssListenerRegistration(request, identity, listener));
+ protected void addListener(TRequest request, CallerIdentity callerIdentity,
+ TListener listener) {
+ long identity = Binder.clearCallingIdentity();
+ try {
+ addRegistration(listener.asBinder(),
+ new GnssListenerRegistration(request, callerIdentity, listener));
+ } finally {
+ Binder.restoreCallingIdentity(identity);
+ }
}
/**
* Removes the given listener.
*/
public void removeListener(TListener listener) {
- removeRegistration(listener.asBinder());
+ long identity = Binder.clearCallingIdentity();
+ try {
+ removeRegistration(listener.asBinder());
+ } finally {
+ Binder.restoreCallingIdentity(identity);
+ }
}
@Override
diff --git a/services/core/java/com/android/server/location/gnss/GnssLocationProvider.java b/services/core/java/com/android/server/location/gnss/GnssLocationProvider.java
index 850cf7f4b7ce..3e5b6e3f462f 100644
--- a/services/core/java/com/android/server/location/gnss/GnssLocationProvider.java
+++ b/services/core/java/com/android/server/location/gnss/GnssLocationProvider.java
@@ -821,7 +821,7 @@ public class GnssLocationProvider extends AbstractLocationProvider implements
byte[] data = psdsDownloader.downloadPsdsData(psdsType);
if (data != null) {
if (DEBUG) Log.d(TAG, "calling native_inject_psds_data");
- native_inject_psds_data(data, data.length);
+ native_inject_psds_data(data, data.length, psdsType);
mPsdsBackOff.reset();
}
@@ -2022,6 +2022,21 @@ public class GnssLocationProvider extends AbstractLocationProvider implements
@Override
public void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
+ boolean dumpAll = false;
+
+ int opti = 0;
+ while (opti < args.length) {
+ String opt = args[opti];
+ if (opt == null || opt.length() <= 0 || opt.charAt(0) != '-') {
+ break;
+ }
+ opti++;
+ if ("-a".equals(opt)) {
+ dumpAll = true;
+ break;
+ }
+ }
+
StringBuilder s = new StringBuilder();
s.append("mStarted=").append(mStarted).append(" (changed ");
TimeUtils.formatDuration(SystemClock.elapsedRealtime()
@@ -2053,9 +2068,11 @@ public class GnssLocationProvider extends AbstractLocationProvider implements
s.append("]\n");
}
s.append(mGnssMetrics.dumpGnssMetricsAsText());
- s.append("native internal state: \n");
- s.append(" ").append(native_get_internal_state());
- s.append("\n");
+ if (dumpAll) {
+ s.append("native internal state: \n");
+ s.append(" ").append(native_get_internal_state());
+ s.append("\n");
+ }
pw.append(s);
}
@@ -2094,7 +2111,7 @@ public class GnssLocationProvider extends AbstractLocationProvider implements
private native boolean native_supports_psds();
- private native void native_inject_psds_data(byte[] data, int length);
+ private native void native_inject_psds_data(byte[] data, int length, int psdsType);
// DEBUG Support
private native String native_get_internal_state();
diff --git a/services/core/java/com/android/server/location/listeners/BinderListenerRegistration.java b/services/core/java/com/android/server/location/listeners/BinderListenerRegistration.java
index bd8bce8f6d52..58aabdad056f 100644
--- a/services/core/java/com/android/server/location/listeners/BinderListenerRegistration.java
+++ b/services/core/java/com/android/server/location/listeners/BinderListenerRegistration.java
@@ -32,10 +32,10 @@ import android.util.Log;
* @param <TListener> listener type
*/
public abstract class BinderListenerRegistration<TRequest, TListener> extends
- RemovableListenerRegistration<TRequest, TListener> implements Binder.DeathRecipient {
+ RemoteListenerRegistration<TRequest, TListener> implements Binder.DeathRecipient {
/**
- * Interface to allowed binder retrieval when keys are not themselves IBinder.
+ * Interface to allow binder retrieval when keys are not themselves IBinders.
*/
public interface BinderKey {
/**
diff --git a/services/core/java/com/android/server/location/listeners/ListenerMultiplexer.java b/services/core/java/com/android/server/location/listeners/ListenerMultiplexer.java
index f94de9be0cfe..8a6b8aa1e463 100644
--- a/services/core/java/com/android/server/location/listeners/ListenerMultiplexer.java
+++ b/services/core/java/com/android/server/location/listeners/ListenerMultiplexer.java
@@ -18,12 +18,9 @@ package com.android.server.location.listeners;
import android.annotation.NonNull;
import android.annotation.Nullable;
-import android.os.Binder;
import android.os.Build;
import android.util.ArrayMap;
import android.util.ArraySet;
-import android.util.IndentingPrintWriter;
-import android.util.Pair;
import com.android.internal.annotations.GuardedBy;
import com.android.internal.listeners.ListenerExecutor.ListenerOperation;
@@ -31,8 +28,10 @@ import com.android.internal.util.Preconditions;
import java.io.FileDescriptor;
import java.io.PrintWriter;
+import java.util.AbstractMap;
import java.util.ArrayList;
import java.util.Collection;
+import java.util.Map.Entry;
import java.util.Objects;
import java.util.function.Function;
import java.util.function.Predicate;
@@ -42,7 +41,7 @@ import java.util.function.Predicate;
* divided into two categories, active registrations and inactive registrations, as defined by
* {@link #isActive(ListenerRegistration)}. If a registration's active state changes,
* {@link #updateRegistrations(Predicate)} must be invoked and return true for any registration
- * whose active state may have changed.
+ * whose active state may have changed. Listeners will only be invoked for active registrations.
*
* Callbacks invoked for various changes will always be ordered according to this lifecycle list:
*
@@ -64,14 +63,6 @@ import java.util.function.Predicate;
* {@link #removeRegistration(Object, ListenerRegistration)}, not via any other removal method. This
* ensures re-entrant removal does not accidentally remove the incorrect registration.
*
- * All callbacks will be invoked with a cleared binder identity.
- *
- * Listeners owned by other processes will be run on a direct executor (and thus while holding a
- * lock). Listeners owned by the same process this multiplexer is in will be run asynchronously (and
- * thus without holding a lock). The underlying assumption is that listeners owned by other
- * processes will simply be forwarding the call to those other processes and perhaps performing
- * simple bookkeeping, with no potential for deadlock.
- *
* @param <TKey> key type
* @param <TRequest> request type
* @param <TListener> listener type
@@ -149,46 +140,51 @@ public abstract class ListenerMultiplexer<TKey, TRequest, TListener,
}
/**
- * Invoked before the first registration occurs. This is a convenient entry point for
- * registering listeners, etc, which only need to be present while there are any registrations.
+ * Invoked when the multiplexer goes from having no registrations to having some registrations.
+ * This is a convenient entry point for registering listeners, etc, which only need to be
+ * present while there are any registrations. Invoked while holding the multiplexer's internal
+ * lock.
*/
protected void onRegister() {}
/**
- * Invoked after the last unregistration occurs. This is a convenient entry point for
- * unregistering listeners, etc, which only need to be present while there are any
- * registrations.
+ * Invoked when the multiplexer goes from having some registrations to having no registrations.
+ * This is a convenient entry point for unregistering listeners, etc, which only need to be
+ * present while there are any registrations. Invoked while holding the multiplexer's internal
+ * lock.
*/
protected void onUnregister() {}
/**
- * Invoked when a registration is added.
+ * Invoked when a registration is added. Invoked while holding the multiplexer's internal lock.
*/
protected void onRegistrationAdded(@NonNull TKey key, @NonNull TRegistration registration) {}
/**
- * Invoked when a registration is removed.
+ * Invoked when a registration is removed. Invoked while holding the multiplexer's internal
+ * lock.
*/
protected void onRegistrationRemoved(@NonNull TKey key, @NonNull TRegistration registration) {}
/**
- * Invoked when the manager goes from having no active registrations to having some active
+ * Invoked when the multiplexer goes from having no active registrations to having some active
* registrations. This is a convenient entry point for registering listeners, etc, which only
- * need to be present while there are active registrations.
+ * need to be present while there are active registrations. Invoked while holding the
+ * multiplexer's internal lock.
*/
protected void onActive() {}
/**
- * Invoked when the manager goes from having some active registrations to having no active
+ * Invoked when the multiplexer goes from having some active registrations to having no active
* registrations. This is a convenient entry point for unregistering listeners, etc, which only
- * need to be present while there are active registrations.
+ * need to be present while there are active registrations. Invoked while holding the
+ * multiplexer's internal lock.
*/
protected void onInactive() {}
/**
- * Adds a new registration with the given key. Registration may fail if
- * {@link ListenerRegistration#onRegister(Object)} returns false, in which case the registration
- * will not be added. This method cannot be called to add a registration re-entrantly.
+ * Adds a new registration with the given key. This method cannot be called to add a
+ * registration re-entrantly.
*/
protected final void addRegistration(@NonNull TKey key, @NonNull TRegistration registration) {
Objects.requireNonNull(key);
@@ -204,7 +200,6 @@ public abstract class ListenerMultiplexer<TKey, TRequest, TListener,
// involve removing a prior registration. note that try-with-resources ordering is
// meaningful here as well. we want to close the reentrancy guard first, as this may
// generate additional service updates, then close the update service buffer.
- long identity = Binder.clearCallingIdentity();
try (UpdateServiceBuffer ignored1 = mUpdateServiceBuffer.acquire();
ReentrancyGuard ignored2 = mReentrancyGuard.acquire()) {
@@ -224,16 +219,13 @@ public abstract class ListenerMultiplexer<TKey, TRequest, TListener,
registration.onRegister(key);
onRegistrationAdded(key, registration);
onRegistrationActiveChanged(registration);
- } finally {
- Binder.restoreCallingIdentity(identity);
}
}
}
/**
- * Removes the registration with the given key. If unregistration occurs,
- * {@link #onRegistrationRemoved(Object, ListenerRegistration)} will be called. This method
- * cannot be called to remove a registration re-entrantly.
+ * Removes the registration with the given key. This method cannot be called to remove a
+ * registration re-entrantly.
*/
protected final void removeRegistration(@NonNull Object key) {
synchronized (mRegistrations) {
@@ -250,9 +242,8 @@ public abstract class ListenerMultiplexer<TKey, TRequest, TListener,
}
/**
- * Removes all registrations with keys that satisfy the given predicate. If unregistration
- * occurs, {@link #onRegistrationRemoved(Object, ListenerRegistration)} will be called. This
- * method cannot be called to remove a registration re-entrantly.
+ * Removes all registrations with keys that satisfy the given predicate. This method cannot be
+ * called to remove a registration re-entrantly.
*/
protected final void removeRegistrationIf(@NonNull Predicate<TKey> predicate) {
synchronized (mRegistrations) {
@@ -281,11 +272,8 @@ public abstract class ListenerMultiplexer<TKey, TRequest, TListener,
/**
* Removes the given registration with the given key. If the given key has a different
- * registration at the time this method is called, nothing happens. If unregistration occurs,
- * {@link #onRegistrationRemoved(Object, ListenerRegistration)} will be called. This method
- * allows for re-entrancy, and may be called to remove a registration re-entrantly. In this case
- * the registration will immediately be marked inactive and unregistered, and will be removed
- * completely at some later time.
+ * registration at the time this method is called, nothing happens. This method allows for
+ * re-entrancy, and may be called to remove a registration re-entrantly.
*/
protected final void removeRegistration(@NonNull Object key,
@NonNull ListenerRegistration<?, ?> registration) {
@@ -324,7 +312,6 @@ public abstract class ListenerMultiplexer<TKey, TRequest, TListener,
// in multiple service updates. note that try-with-resources ordering is meaningful here as
// well. we want to close the reentrancy guard first, as this may generate additional
// service updates, then close the update service buffer.
- long identity = Binder.clearCallingIdentity();
try (UpdateServiceBuffer ignored1 = mUpdateServiceBuffer.acquire();
ReentrancyGuard ignored2 = mReentrancyGuard.acquire()) {
@@ -337,8 +324,6 @@ public abstract class ListenerMultiplexer<TKey, TRequest, TListener,
onUnregister();
}
}
- } finally {
- Binder.restoreCallingIdentity(identity);
}
}
@@ -362,38 +347,46 @@ public abstract class ListenerMultiplexer<TKey, TRequest, TListener,
}
}
- long identity = Binder.clearCallingIdentity();
- try {
- if (actives.isEmpty()) {
+ if (actives.isEmpty()) {
+ mCurrentRequest = null;
+ if (mServiceRegistered) {
+ mServiceRegistered = false;
mCurrentRequest = null;
- if (mServiceRegistered) {
- mServiceRegistered = false;
- mCurrentRequest = null;
- unregisterWithService();
- }
- return;
+ unregisterWithService();
}
+ return;
+ }
- TMergedRequest merged = mergeRequests(actives);
- if (!mServiceRegistered || !Objects.equals(merged, mCurrentRequest)) {
- if (mServiceRegistered) {
- mServiceRegistered = reregisterWithService(mCurrentRequest, merged);
- } else {
- mServiceRegistered = registerWithService(merged);
- }
- if (mServiceRegistered) {
- mCurrentRequest = merged;
- } else {
- mCurrentRequest = null;
- }
+ TMergedRequest merged = mergeRequests(actives);
+ if (!mServiceRegistered || !Objects.equals(merged, mCurrentRequest)) {
+ if (mServiceRegistered) {
+ mServiceRegistered = reregisterWithService(mCurrentRequest, merged);
+ } else {
+ mServiceRegistered = registerWithService(merged);
+ }
+ if (mServiceRegistered) {
+ mCurrentRequest = merged;
+ } else {
+ mCurrentRequest = null;
}
- } finally {
- Binder.restoreCallingIdentity(identity);
}
}
}
/**
+ * Clears currently stored service state, and invokes {@link #updateService()} to force a new
+ * call to {@link #registerWithService(Object)} if necessary. This is useful, for instance, if
+ * the backing service has crashed or otherwise lost state, and needs to be re-initialized.
+ */
+ protected final void resetService() {
+ synchronized (mRegistrations) {
+ mServiceRegistered = false;
+ mCurrentRequest = null;
+ updateService();
+ }
+ }
+
+ /**
* Begins buffering calls to {@link #updateService()} until {@link UpdateServiceLock#close()}
* is called. This is useful to prevent extra work when combining multiple calls (for example,
* buffering {@code updateService()} until after multiple adds/removes/updates occur.
@@ -404,9 +397,9 @@ public abstract class ListenerMultiplexer<TKey, TRequest, TListener,
/**
* Evaluates the predicate on all registrations. The predicate should return true if the active
- * state of the registration may have changed as a result. Any {@link #updateService()}
- * invocations made while this method is executing will be deferred until after the method is
- * complete so as to avoid redundant work.
+ * state of the registration may have changed as a result. If the active state of any
+ * registration has changed, {@link #updateService()} will automatically be invoked to handle
+ * the resulting changes.
*/
protected final void updateRegistrations(@NonNull Predicate<TRegistration> predicate) {
synchronized (mRegistrations) {
@@ -415,7 +408,6 @@ public abstract class ListenerMultiplexer<TKey, TRequest, TListener,
// callbacks. note that try-with-resources ordering is meaningful here as well. we want
// to close the reentrancy guard first, as this may generate additional service updates,
// then close the update service buffer.
- long identity = Binder.clearCallingIdentity();
try (UpdateServiceBuffer ignored1 = mUpdateServiceBuffer.acquire();
ReentrancyGuard ignored2 = mReentrancyGuard.acquire()) {
@@ -426,8 +418,6 @@ public abstract class ListenerMultiplexer<TKey, TRequest, TListener,
onRegistrationActiveChanged(registration);
}
}
- } finally {
- Binder.restoreCallingIdentity(identity);
}
}
}
@@ -450,7 +440,10 @@ public abstract class ListenerMultiplexer<TKey, TRequest, TListener,
execute(registration, operation);
}
} else {
- registration.onInactive();
+ ListenerOperation<TListener> operation = registration.onInactive();
+ if (operation != null) {
+ execute(registration, operation);
+ }
if (--mActiveRegistrationsCount == 0) {
onInactive();
}
@@ -468,7 +461,6 @@ public abstract class ListenerMultiplexer<TKey, TRequest, TListener,
protected final void deliverToListeners(
@NonNull Function<TRegistration, ListenerOperation<TListener>> function) {
synchronized (mRegistrations) {
- long identity = Binder.clearCallingIdentity();
try (ReentrancyGuard ignored = mReentrancyGuard.acquire()) {
final int size = mRegistrations.size();
for (int i = 0; i < size; i++) {
@@ -480,8 +472,6 @@ public abstract class ListenerMultiplexer<TKey, TRequest, TListener,
}
}
}
- } finally {
- Binder.restoreCallingIdentity(identity);
}
}
}
@@ -495,7 +485,6 @@ public abstract class ListenerMultiplexer<TKey, TRequest, TListener,
*/
protected final void deliverToListeners(@NonNull ListenerOperation<TListener> operation) {
synchronized (mRegistrations) {
- long identity = Binder.clearCallingIdentity();
try (ReentrancyGuard ignored = mReentrancyGuard.acquire()) {
final int size = mRegistrations.size();
for (int i = 0; i < size; i++) {
@@ -504,8 +493,6 @@ public abstract class ListenerMultiplexer<TKey, TRequest, TListener,
execute(registration, operation);
}
}
- } finally {
- Binder.restoreCallingIdentity(identity);
}
}
}
@@ -522,27 +509,26 @@ public abstract class ListenerMultiplexer<TKey, TRequest, TListener,
/**
* Dumps debug information.
*/
- public void dump(FileDescriptor fd, IndentingPrintWriter ipw, String[] args) {
+ public void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
synchronized (mRegistrations) {
- ipw.print("service: ");
- dumpServiceState(ipw);
- ipw.println();
+ pw.print("service: ");
+ dumpServiceState(pw);
+ pw.println();
if (!mRegistrations.isEmpty()) {
- ipw.println("listeners:");
+ pw.println("listeners:");
- ipw.increaseIndent();
final int size = mRegistrations.size();
for (int i = 0; i < size; i++) {
TRegistration registration = mRegistrations.valueAt(i);
- ipw.print(registration);
+ pw.print(" ");
+ pw.print(registration);
if (!registration.isActive()) {
- ipw.println(" (inactive)");
+ pw.println(" (inactive)");
} else {
- ipw.println();
+ pw.println();
}
}
- ipw.decreaseIndent();
}
}
}
@@ -577,7 +563,7 @@ public abstract class ListenerMultiplexer<TKey, TRequest, TListener,
@GuardedBy("mRegistrations")
private int mGuardCount;
@GuardedBy("mRegistrations")
- private @Nullable ArraySet<Pair<Object, ListenerRegistration<?, ?>>> mScheduledRemovals;
+ private @Nullable ArraySet<Entry<Object, ListenerRegistration<?, ?>>> mScheduledRemovals;
ReentrancyGuard() {
mGuardCount = 0;
@@ -602,7 +588,7 @@ public abstract class ListenerMultiplexer<TKey, TRequest, TListener,
if (mScheduledRemovals == null) {
mScheduledRemovals = new ArraySet<>(mRegistrations.size());
}
- mScheduledRemovals.add(new Pair<>(key, registration));
+ mScheduledRemovals.add(new AbstractMap.SimpleImmutableEntry<>(key, registration));
}
ReentrancyGuard acquire() {
@@ -612,7 +598,7 @@ public abstract class ListenerMultiplexer<TKey, TRequest, TListener,
@Override
public void close() {
- ArraySet<Pair<Object, ListenerRegistration<?, ?>>> scheduledRemovals = null;
+ ArraySet<Entry<Object, ListenerRegistration<?, ?>>> scheduledRemovals = null;
Preconditions.checkState(mGuardCount > 0);
if (--mGuardCount == 0) {
@@ -620,14 +606,15 @@ public abstract class ListenerMultiplexer<TKey, TRequest, TListener,
mScheduledRemovals = null;
}
- if (scheduledRemovals != null) {
- try (UpdateServiceBuffer ignored = mUpdateServiceBuffer.acquire()) {
- final int size = scheduledRemovals.size();
- for (int i = 0; i < size; i++) {
- Pair<Object, ListenerRegistration<?, ?>> pair = scheduledRemovals.valueAt(
- i);
- removeRegistration(pair.first, pair.second);
- }
+ if (scheduledRemovals == null) {
+ return;
+ }
+
+ try (UpdateServiceBuffer ignored = mUpdateServiceBuffer.acquire()) {
+ final int size = scheduledRemovals.size();
+ for (int i = 0; i < size; i++) {
+ Entry<Object, ListenerRegistration<?, ?>> entry = scheduledRemovals.valueAt(i);
+ removeRegistration(entry.getKey(), entry.getValue());
}
}
}
diff --git a/services/core/java/com/android/server/location/listeners/ListenerRegistration.java b/services/core/java/com/android/server/location/listeners/ListenerRegistration.java
index ac56c51568be..deb9660a1c82 100644
--- a/services/core/java/com/android/server/location/listeners/ListenerRegistration.java
+++ b/services/core/java/com/android/server/location/listeners/ListenerRegistration.java
@@ -17,55 +17,34 @@
package com.android.server.location.listeners;
-import static com.android.internal.util.ConcurrentUtils.DIRECT_EXECUTOR;
-
import android.annotation.NonNull;
import android.annotation.Nullable;
-import android.location.util.identity.CallerIdentity;
-import android.os.Process;
-import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.listeners.ListenerExecutor;
-import com.android.server.FgThread;
import java.util.Objects;
import java.util.concurrent.Executor;
/**
* A listener registration object which holds data associated with the listener, such as an optional
- * request, and the identity of the listener owner.
+ * request, and an executor responsible for listener invocations.
*
* @param <TRequest> request type
* @param <TListener> listener type
*/
public class ListenerRegistration<TRequest, TListener> implements ListenerExecutor {
- @VisibleForTesting
- public static final Executor IN_PROCESS_EXECUTOR = FgThread.getExecutor();
-
private final Executor mExecutor;
private final @Nullable TRequest mRequest;
- private final CallerIdentity mIdentity;
private boolean mActive;
private volatile @Nullable TListener mListener;
- protected ListenerRegistration(@Nullable TRequest request, CallerIdentity identity,
+ protected ListenerRegistration(Executor executor, @Nullable TRequest request,
TListener listener) {
- // if a client is in the same process as us, binder calls will execute synchronously and
- // we shouldn't run callbacks directly since they might be run under lock and deadlock
- if (identity.getPid() == Process.myPid()) {
- // there's a slight loophole here for pending intents - pending intent callbacks can
- // always be run on the direct executor since they're always asynchronous, but honestly
- // you shouldn't be using pending intent callbacks within the same process anyways
- mExecutor = IN_PROCESS_EXECUTOR;
- } else {
- mExecutor = DIRECT_EXECUTOR;
- }
-
+ mExecutor = Objects.requireNonNull(executor);
mRequest = request;
- mIdentity = Objects.requireNonNull(identity);
mActive = false;
mListener = Objects.requireNonNull(listener);
}
@@ -82,34 +61,34 @@ public class ListenerRegistration<TRequest, TListener> implements ListenerExecut
}
/**
- * Returns the listener identity.
- */
- public final CallerIdentity getIdentity() {
- return mIdentity;
- }
-
- /**
- * May be overridden by subclasses. Invoked when registration occurs.
+ * May be overridden by subclasses. Invoked when registration occurs. Invoked while holding the
+ * owning multiplexer's internal lock.
*/
protected void onRegister(Object key) {}
/**
- * May be overridden by subclasses. Invoked when unregistration occurs.
+ * May be overridden by subclasses. Invoked when unregistration occurs. Invoked while holding
+ * the owning multiplexer's internal lock.
*/
protected void onUnregister() {}
/**
* May be overridden by subclasses. Invoked when this registration becomes active. If this
- * returns a non-null operation, that operation will be invoked for the listener.
+ * returns a non-null operation, that operation will be invoked for the listener. Invoked
+ * while holding the owning multiplexer's internal lock.
*/
protected @Nullable ListenerOperation<TListener> onActive() {
return null;
}
/**
- * May be overridden by subclasses. Invoked when registration becomes inactive.
+ * May be overridden by subclasses. Invoked when registration becomes inactive. If this returns
+ * a non-null operation, that operation will be invoked for the listener. Invoked while holding
+ * the owning multiplexer's internal lock.
*/
- protected void onInactive() {}
+ protected @Nullable ListenerOperation<TListener> onInactive() {
+ return null;
+ }
public final boolean isActive() {
return mActive;
@@ -136,8 +115,7 @@ public class ListenerRegistration<TRequest, TListener> implements ListenerExecut
/**
* May be overridden by subclasses, however should rarely be needed. Invoked when the listener
* associated with this registration is unregistered, which may occur before the registration
- * itself is unregistered. This immediately prevents the listener from being further invoked
- * even if the various bookkeeping associated with unregistration has not occurred yet.
+ * itself is unregistered. This immediately prevents the listener from being further invoked.
*/
protected void onListenerUnregister() {};
diff --git a/services/core/java/com/android/server/location/listeners/PendingIntentListenerRegistration.java b/services/core/java/com/android/server/location/listeners/PendingIntentListenerRegistration.java
index b5d2ef6a72ec..7b6154eb0d00 100644
--- a/services/core/java/com/android/server/location/listeners/PendingIntentListenerRegistration.java
+++ b/services/core/java/com/android/server/location/listeners/PendingIntentListenerRegistration.java
@@ -30,7 +30,7 @@ import android.util.Log;
* @param <TListener> listener type
*/
public abstract class PendingIntentListenerRegistration<TRequest, TListener> extends
- RemovableListenerRegistration<TRequest, TListener> implements PendingIntent.CancelListener {
+ RemoteListenerRegistration<TRequest, TListener> implements PendingIntent.CancelListener {
/**
* Interface to allowed pending intent retrieval when keys are not themselves PendingIntents.
diff --git a/services/core/java/com/android/server/location/listeners/RemoteListenerRegistration.java b/services/core/java/com/android/server/location/listeners/RemoteListenerRegistration.java
new file mode 100644
index 000000000000..e4b0b190d34c
--- /dev/null
+++ b/services/core/java/com/android/server/location/listeners/RemoteListenerRegistration.java
@@ -0,0 +1,75 @@
+/*
+ * 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.location.listeners;
+
+
+import static com.android.internal.util.ConcurrentUtils.DIRECT_EXECUTOR;
+
+import android.annotation.Nullable;
+import android.location.util.identity.CallerIdentity;
+import android.os.Process;
+
+import com.android.internal.annotations.VisibleForTesting;
+import com.android.server.FgThread;
+
+import java.util.Objects;
+import java.util.concurrent.Executor;
+
+/**
+ * A listener registration representing a remote (possibly from a different process) listener.
+ * Listeners from a different process will be run on a direct executor, since the x-process listener
+ * invocation should already be asynchronous. Listeners from the same process will be run on a
+ * normal executor, since in-process listener invocation may be synchronous.
+ *
+ * @param <TRequest> request type
+ * @param <TListener> listener type
+ */
+public abstract class RemoteListenerRegistration<TRequest, TListener> extends
+ RemovableListenerRegistration<TRequest, TListener> {
+
+ @VisibleForTesting
+ public static final Executor IN_PROCESS_EXECUTOR = FgThread.getExecutor();
+
+ private static Executor chooseExecutor(CallerIdentity identity) {
+ // if a client is in the same process as us, binder calls will execute synchronously and
+ // we shouldn't run callbacks directly since they might be run under lock and deadlock
+ if (identity.getPid() == Process.myPid()) {
+ // there's a slight loophole here for pending intents - pending intent callbacks can
+ // always be run on the direct executor since they're always asynchronous, but honestly
+ // you shouldn't be using pending intent callbacks within the same process anyways
+ return IN_PROCESS_EXECUTOR;
+ } else {
+ return DIRECT_EXECUTOR;
+ }
+ }
+
+ private final CallerIdentity mIdentity;
+
+ protected RemoteListenerRegistration(String tag, @Nullable TRequest request,
+ CallerIdentity identity, TListener listener) {
+ super(tag, chooseExecutor(identity), request, listener);
+ mIdentity = Objects.requireNonNull(identity);
+ }
+
+ /**
+ * Returns the listener identity.
+ */
+ public final CallerIdentity getIdentity() {
+ return mIdentity;
+ }
+}
+
diff --git a/services/core/java/com/android/server/location/listeners/RemovableListenerRegistration.java b/services/core/java/com/android/server/location/listeners/RemovableListenerRegistration.java
index 0698cca903f0..2383bece4e0a 100644
--- a/services/core/java/com/android/server/location/listeners/RemovableListenerRegistration.java
+++ b/services/core/java/com/android/server/location/listeners/RemovableListenerRegistration.java
@@ -17,10 +17,10 @@
package com.android.server.location.listeners;
import android.annotation.Nullable;
-import android.location.util.identity.CallerIdentity;
import android.util.Log;
import java.util.Objects;
+import java.util.concurrent.Executor;
/**
* A listener registration that stores its own key, and thus can remove itself. By default it will
@@ -36,9 +36,9 @@ public abstract class RemovableListenerRegistration<TRequest, TListener> extends
private volatile @Nullable Object mKey;
- protected RemovableListenerRegistration(String tag, @Nullable TRequest request,
- CallerIdentity callerIdentity, TListener listener) {
- super(request, callerIdentity, listener);
+ protected RemovableListenerRegistration(String tag, Executor executor,
+ @Nullable TRequest request, TListener listener) {
+ super(executor, request, listener);
mTag = Objects.requireNonNull(tag);
}
@@ -70,7 +70,7 @@ public abstract class RemovableListenerRegistration<TRequest, TListener> extends
@Override
public <Listener> void onOperationFailure(ListenerOperation<Listener> operation, Exception e) {
- Log.w(mTag, "registration " + getIdentity() + " removed due to unexpected exception", e);
+ Log.w(mTag, "registration " + this + " removed due to unexpected exception", e);
remove();
}
diff --git a/services/core/java/com/android/server/locksettings/LockSettingsService.java b/services/core/java/com/android/server/locksettings/LockSettingsService.java
index 93352dca7ce9..26c3132167d3 100644
--- a/services/core/java/com/android/server/locksettings/LockSettingsService.java
+++ b/services/core/java/com/android/server/locksettings/LockSettingsService.java
@@ -1090,7 +1090,9 @@ public class LockSettingsService extends ILockSettings.Stub {
public void setSeparateProfileChallengeEnabled(int userId, boolean enabled,
LockscreenCredential managedUserPassword) {
checkWritePermission(userId);
- if (!mHasSecureLockScreen) {
+ if (!mHasSecureLockScreen
+ && managedUserPassword != null
+ && managedUserPassword.getType() != CREDENTIAL_TYPE_NONE) {
throw new UnsupportedOperationException(
"This operation requires secure lock screen feature.");
}
@@ -1560,7 +1562,8 @@ public class LockSettingsService extends ILockSettings.Stub {
public boolean setLockCredential(LockscreenCredential credential,
LockscreenCredential savedCredential, int userId) {
- if (!mHasSecureLockScreen) {
+ if (!mHasSecureLockScreen
+ && credential != null && credential.getType() != CREDENTIAL_TYPE_NONE) {
throw new UnsupportedOperationException(
"This operation requires secure lock screen feature");
}
@@ -3423,7 +3426,8 @@ public class LockSettingsService extends ILockSettings.Stub {
@Override
public boolean setLockCredentialWithToken(LockscreenCredential credential, long tokenHandle,
byte[] token, int userId) {
- if (!mHasSecureLockScreen) {
+ if (!mHasSecureLockScreen
+ && credential != null && credential.getType() != CREDENTIAL_TYPE_NONE) {
throw new UnsupportedOperationException(
"This operation requires secure lock screen feature.");
}
diff --git a/services/core/java/com/android/server/locksettings/LockSettingsStorage.java b/services/core/java/com/android/server/locksettings/LockSettingsStorage.java
index e9a05a8aa16c..715e41c62a05 100644
--- a/services/core/java/com/android/server/locksettings/LockSettingsStorage.java
+++ b/services/core/java/com/android/server/locksettings/LockSettingsStorage.java
@@ -746,7 +746,7 @@ class LockSettingsStorage {
public void dump(IndentingPrintWriter pw) {
final UserManager um = UserManager.get(mContext);
- for (UserInfo user : um.getUsers(false)) {
+ for (UserInfo user : um.getUsers()) {
File userPath = getSyntheticPasswordDirectoryForUser(user.id);
pw.println(String.format("User %d [%s]:", user.id, userPath.getAbsolutePath()));
pw.increaseIndent();
diff --git a/services/core/java/com/android/server/net/NetworkPolicyManagerService.java b/services/core/java/com/android/server/net/NetworkPolicyManagerService.java
index 29ee8eb13564..ded77b394066 100644
--- a/services/core/java/com/android/server/net/NetworkPolicyManagerService.java
+++ b/services/core/java/com/android/server/net/NetworkPolicyManagerService.java
@@ -518,8 +518,9 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub {
private final SparseBooleanArray mRestrictBackgroundAllowlistRevokedUids =
new SparseBooleanArray();
+ final Object mMeteredIfacesLock = new Object();
/** Set of ifaces that are metered. */
- @GuardedBy("mNetworkPoliciesSecondLock")
+ @GuardedBy("mMeteredIfacesLock")
private ArraySet<String> mMeteredIfaces = new ArraySet<>();
/** Set of over-limit templates that have been notified. */
@GuardedBy("mNetworkPoliciesSecondLock")
@@ -1972,13 +1973,15 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub {
}
// Remove quota from any interfaces that are no longer metered.
- for (int i = mMeteredIfaces.size() - 1; i >= 0; i--) {
- final String iface = mMeteredIfaces.valueAt(i);
- if (!newMeteredIfaces.contains(iface)) {
- removeInterfaceQuotaAsync(iface);
+ synchronized (mMeteredIfacesLock) {
+ for (int i = mMeteredIfaces.size() - 1; i >= 0; i--) {
+ final String iface = mMeteredIfaces.valueAt(i);
+ if (!newMeteredIfaces.contains(iface)) {
+ removeInterfaceQuotaAsync(iface);
+ }
}
+ mMeteredIfaces = newMeteredIfaces;
}
- mMeteredIfaces = newMeteredIfaces;
final ContentResolver cr = mContext.getContentResolver();
final boolean quotaEnabled = Settings.Global.getInt(cr,
@@ -2030,7 +2033,10 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub {
mSubscriptionOpportunisticQuota.put(subId, quotaBytes);
}
- final String[] meteredIfaces = mMeteredIfaces.toArray(new String[mMeteredIfaces.size()]);
+ final String[] meteredIfaces;
+ synchronized (mMeteredIfacesLock) {
+ meteredIfaces = mMeteredIfaces.toArray(new String[mMeteredIfaces.size()]);
+ }
mHandler.obtainMessage(MSG_METERED_IFACES_CHANGED, meteredIfaces).sendToTarget();
mHandler.obtainMessage(MSG_ADVISE_PERSIST_THRESHOLD, lowestRule).sendToTarget();
@@ -3436,7 +3442,10 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub {
fout.print("Restrict background: "); fout.println(mRestrictBackground);
fout.print("Restrict power: "); fout.println(mRestrictPower);
fout.print("Device idle: "); fout.println(mDeviceIdleMode);
- fout.print("Metered ifaces: "); fout.println(mMeteredIfaces);
+ synchronized (mMeteredIfacesLock) {
+ fout.print("Metered ifaces: ");
+ fout.println(mMeteredIfaces);
+ }
fout.println();
fout.print("mRestrictBackgroundLowPowerMode: " + mRestrictBackgroundLowPowerMode);
@@ -4632,7 +4641,7 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub {
}
case MSG_LIMIT_REACHED: {
final String iface = (String) msg.obj;
- synchronized (mNetworkPoliciesSecondLock) {
+ synchronized (mMeteredIfacesLock) {
// fast return if not needed.
if (!mMeteredIfaces.contains(iface)) {
return true;
@@ -5274,7 +5283,7 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub {
isBackgroundRestricted = mRestrictBackground;
}
final boolean isNetworkMetered;
- synchronized (mNetworkPoliciesSecondLock) {
+ synchronized (mMeteredIfacesLock) {
isNetworkMetered = mMeteredIfaces.contains(ifname);
}
final boolean ret = isUidNetworkingBlockedInternal(uid, uidRules, isNetworkMetered,
diff --git a/services/core/java/com/android/server/notification/ManagedServices.java b/services/core/java/com/android/server/notification/ManagedServices.java
index a604625460a7..74b7bd76b047 100644
--- a/services/core/java/com/android/server/notification/ManagedServices.java
+++ b/services/core/java/com/android/server/notification/ManagedServices.java
@@ -1554,7 +1554,7 @@ abstract public class ManagedServices {
if (!isEnabledForCurrentProfiles()) {
return false;
}
- return this.userid == userId;
+ return userId == USER_ALL || userId == this.userid;
}
public boolean enabledAndUserMatches(int nid) {
diff --git a/services/core/java/com/android/server/notification/NotificationManagerService.java b/services/core/java/com/android/server/notification/NotificationManagerService.java
index 04658555f22b..12419a9fcafa 100755
--- a/services/core/java/com/android/server/notification/NotificationManagerService.java
+++ b/services/core/java/com/android/server/notification/NotificationManagerService.java
@@ -262,7 +262,6 @@ import com.android.server.EventLogTags;
import com.android.server.IoThread;
import com.android.server.LocalServices;
import com.android.server.SystemService;
-import com.android.server.SystemService.TargetUser;
import com.android.server.UiThread;
import com.android.server.lights.LightsManager;
import com.android.server.lights.LogicalLight;
@@ -966,8 +965,7 @@ public class NotificationManagerService extends SystemService {
nv.recycle();
}
reportUserInteraction(r);
- mAssistants.notifyAssistantActionClicked(
- r.getSbn(), actionIndex, action, generatedByAssistant);
+ mAssistants.notifyAssistantActionClicked(r.getSbn(), action, generatedByAssistant);
}
}
@@ -8629,12 +8627,25 @@ public class NotificationManagerService extends SystemService {
ServiceManager.getService(Context.COMPANION_DEVICE_SERVICE));
}
- private boolean isVisibleToListener(StatusBarNotification sbn, ManagedServiceInfo listener) {
+ @VisibleForTesting
+ boolean isVisibleToListener(StatusBarNotification sbn, ManagedServiceInfo listener) {
if (!listener.enabledAndUserMatches(sbn.getUserId())) {
return false;
}
- // TODO: remove this for older listeners.
- return true;
+ return isInteractionVisibleToListener(listener, sbn.getUserId());
+ }
+
+ /**
+ * Returns whether the given assistant should be informed about interactions on the given user.
+ *
+ * Normally an assistant would be able to see all interactions on the current user and any
+ * associated profiles because they are notification listeners, but since NASes have one
+ * instance per user, we want to filter out interactions that are not for the user that the
+ * given NAS is bound in.
+ */
+ private boolean isInteractionVisibleToListener(ManagedServiceInfo info, int userId) {
+ boolean isAssistantService = mAssistants.isServiceTokenValidLocked(info.service);
+ return !isAssistantService || info.isSameUser(userId);
}
private boolean isPackageSuspendedForUser(String pkg, int uid) {
@@ -8856,8 +8867,6 @@ public class NotificationManagerService extends SystemService {
}
protected void onNotificationsSeenLocked(ArrayList<NotificationRecord> records) {
- // There should be only one, but it's a list, so while we enforce
- // singularity elsewhere, we keep it general here, to avoid surprises.
for (final ManagedServiceInfo info : NotificationAssistants.this.getServices()) {
ArrayList<String> keys = new ArrayList<>(records.size());
for (NotificationRecord r : records) {
@@ -8875,6 +8884,8 @@ public class NotificationManagerService extends SystemService {
}
protected void onPanelRevealed(int items) {
+ // send to all currently bounds NASes since notifications from both users will appear in
+ // the panel
for (final ManagedServiceInfo info : NotificationAssistants.this.getServices()) {
mHandler.post(() -> {
final INotificationListener assistant = (INotificationListener) info.service;
@@ -8888,6 +8899,8 @@ public class NotificationManagerService extends SystemService {
}
protected void onPanelHidden() {
+ // send to all currently bounds NASes since notifications from both users will appear in
+ // the panel
for (final ManagedServiceInfo info : NotificationAssistants.this.getServices()) {
mHandler.post(() -> {
final INotificationListener assistant = (INotificationListener) info.service;
@@ -8976,7 +8989,7 @@ public class NotificationManagerService extends SystemService {
}
notifyAssistantLocked(
sbn,
- false /* sameUserOnly */,
+ true /* sameUserOnly */,
(assistant, sbnHolder) -> {
try {
assistant.onNotificationVisibilityChanged(key, isVisible);
@@ -8994,7 +9007,7 @@ public class NotificationManagerService extends SystemService {
final String key = sbn.getKey();
notifyAssistantLocked(
sbn,
- false /* sameUserOnly */,
+ true /* sameUserOnly */,
(assistant, sbnHolder) -> {
try {
assistant.onNotificationExpansionChanged(key, isUserAction, isExpanded);
@@ -9010,7 +9023,7 @@ public class NotificationManagerService extends SystemService {
final String key = sbn.getKey();
notifyAssistantLocked(
sbn,
- false /* sameUserOnly */,
+ true /* sameUserOnly */,
(assistant, sbnHolder) -> {
try {
assistant.onNotificationDirectReply(key);
@@ -9026,7 +9039,7 @@ public class NotificationManagerService extends SystemService {
final String key = sbn.getKey();
notifyAssistantLocked(
sbn,
- false /* sameUserOnly */,
+ true /* sameUserOnly */,
(assistant, sbnHolder) -> {
try {
assistant.onSuggestedReplySent(
@@ -9043,12 +9056,12 @@ public class NotificationManagerService extends SystemService {
@GuardedBy("mNotificationLock")
void notifyAssistantActionClicked(
- final StatusBarNotification sbn, int actionIndex, Notification.Action action,
+ final StatusBarNotification sbn, Notification.Action action,
boolean generatedByAssistant) {
final String key = sbn.getKey();
notifyAssistantLocked(
sbn,
- false /* sameUserOnly */,
+ true /* sameUserOnly */,
(assistant, sbnHolder) -> {
try {
assistant.onActionClicked(
@@ -9072,7 +9085,7 @@ public class NotificationManagerService extends SystemService {
final StatusBarNotification sbn, final String snoozeCriterionId) {
notifyAssistantLocked(
sbn,
- false /* sameUserOnly */,
+ true /* sameUserOnly */,
(assistant, sbnHolder) -> {
try {
assistant.onNotificationSnoozedUntilContext(
@@ -9129,7 +9142,7 @@ public class NotificationManagerService extends SystemService {
}
protected void resetDefaultAssistantsIfNecessary() {
- final List<UserInfo> activeUsers = mUm.getUsers(true);
+ final List<UserInfo> activeUsers = mUm.getAliveUsers();
for (UserInfo userInfo : activeUsers) {
int userId = userInfo.getUserHandle().getIdentifier();
if (!hasUserSet(userId)) {
@@ -9293,10 +9306,12 @@ public class NotificationManagerService extends SystemService {
}
public void onStatusBarIconsBehaviorChanged(boolean hideSilentStatusIcons) {
+ // send to all currently bounds NASes since notifications from both users will appear in
+ // the status bar
for (final ManagedServiceInfo info : getServices()) {
mHandler.post(() -> {
final INotificationListener listener = (INotificationListener) info.service;
- try {
+ try {
listener.onStatusBarIconsBehaviorChanged(hideSilentStatusIcons);
} catch (RemoteException ex) {
Slog.e(TAG, "unable to notify listener "
@@ -9470,7 +9485,8 @@ public class NotificationManagerService extends SystemService {
&& changedHiddenNotifications.size() > 0;
for (final ManagedServiceInfo serviceInfo : getServices()) {
- if (!serviceInfo.isEnabledForCurrentProfiles()) {
+ if (!serviceInfo.isEnabledForCurrentProfiles() || !isInteractionVisibleToListener(
+ serviceInfo, ActivityManager.getCurrentUser())) {
continue;
}
@@ -9489,12 +9505,7 @@ public class NotificationManagerService extends SystemService {
final NotificationRankingUpdate update = makeRankingUpdateLocked(
serviceInfo);
- mHandler.post(new Runnable() {
- @Override
- public void run() {
- notifyRankingUpdate(serviceInfo, update);
- }
- });
+ mHandler.post(() -> notifyRankingUpdate(serviceInfo, update));
}
}
}
@@ -9502,15 +9513,11 @@ public class NotificationManagerService extends SystemService {
@GuardedBy("mNotificationLock")
public void notifyListenerHintsChangedLocked(final int hints) {
for (final ManagedServiceInfo serviceInfo : getServices()) {
- if (!serviceInfo.isEnabledForCurrentProfiles()) {
+ if (!serviceInfo.isEnabledForCurrentProfiles() || !isInteractionVisibleToListener(
+ serviceInfo, ActivityManager.getCurrentUser())) {
continue;
}
- mHandler.post(new Runnable() {
- @Override
- public void run() {
- notifyListenerHintsChanged(serviceInfo, hints);
- }
- });
+ mHandler.post(() -> notifyListenerHintsChanged(serviceInfo, hints));
}
}
@@ -9562,15 +9569,12 @@ public class NotificationManagerService extends SystemService {
public void notifyInterruptionFilterChanged(final int interruptionFilter) {
for (final ManagedServiceInfo serviceInfo : getServices()) {
- if (!serviceInfo.isEnabledForCurrentProfiles()) {
+ if (!serviceInfo.isEnabledForCurrentProfiles() || !isInteractionVisibleToListener(
+ serviceInfo, ActivityManager.getCurrentUser())) {
continue;
}
- mHandler.post(new Runnable() {
- @Override
- public void run() {
- notifyInterruptionFilterChanged(serviceInfo, interruptionFilter);
- }
- });
+ mHandler.post(
+ () -> notifyInterruptionFilterChanged(serviceInfo, interruptionFilter));
}
}
@@ -9579,15 +9583,16 @@ public class NotificationManagerService extends SystemService {
if (channel == null) {
return;
}
- for (final ManagedServiceInfo serviceInfo : getServices()) {
- if (!serviceInfo.enabledAndUserMatches(UserHandle.getCallingUserId())) {
+ for (final ManagedServiceInfo info : getServices()) {
+ if (!info.enabledAndUserMatches(UserHandle.getCallingUserId())
+ || !isInteractionVisibleToListener(info, UserHandle.getCallingUserId())) {
continue;
}
BackgroundThread.getHandler().post(() -> {
- if (serviceInfo.isSystem || hasCompanionDevice(serviceInfo)) {
+ if (info.isSystem || hasCompanionDevice(info)) {
notifyNotificationChannelChanged(
- serviceInfo, pkg, user, channel, modificationType);
+ info, pkg, user, channel, modificationType);
}
});
}
@@ -9599,15 +9604,16 @@ public class NotificationManagerService extends SystemService {
if (group == null) {
return;
}
- for (final ManagedServiceInfo serviceInfo : getServices()) {
- if (!serviceInfo.enabledAndUserMatches(UserHandle.getCallingUserId())) {
+ for (final ManagedServiceInfo info : getServices()) {
+ if (!info.enabledAndUserMatches(UserHandle.getCallingUserId())
+ || !isInteractionVisibleToListener(info, UserHandle.getCallingUserId())) {
continue;
}
BackgroundThread.getHandler().post(() -> {
- if (serviceInfo.isSystem || hasCompanionDevice(serviceInfo)) {
+ if (info.isSystem || hasCompanionDevice(info)) {
notifyNotificationChannelGroupChanged(
- serviceInfo, pkg, user, group, modificationType);
+ info, pkg, user, group, modificationType);
}
});
}
@@ -9626,9 +9632,6 @@ public class NotificationManagerService extends SystemService {
private void notifyRemoved(ManagedServiceInfo info, StatusBarNotification sbn,
NotificationRankingUpdate rankingUpdate, NotificationStats stats, int reason) {
- if (!info.enabledAndUserMatches(sbn.getUserId())) {
- return;
- }
final INotificationListener listener = (INotificationListener) info.service;
StatusBarNotificationHolder sbnHolder = new StatusBarNotificationHolder(sbn);
try {
diff --git a/services/core/java/com/android/server/om/OverlayManagerService.java b/services/core/java/com/android/server/om/OverlayManagerService.java
index a4debc16493a..d7a1ba2a93d4 100644
--- a/services/core/java/com/android/server/om/OverlayManagerService.java
+++ b/services/core/java/com/android/server/om/OverlayManagerService.java
@@ -288,7 +288,7 @@ public final class OverlayManagerService extends SystemService {
private void initIfNeeded() {
final UserManager um = getContext().getSystemService(UserManager.class);
- final List<UserInfo> users = um.getUsers(true /*excludeDying*/);
+ final List<UserInfo> users = um.getAliveUsers();
synchronized (mLock) {
final int userCount = users.size();
for (int i = 0; i < userCount; i++) {
diff --git a/services/core/java/com/android/server/pm/ApkChecksums.java b/services/core/java/com/android/server/pm/ApkChecksums.java
new file mode 100644
index 000000000000..0338ed802436
--- /dev/null
+++ b/services/core/java/com/android/server/pm/ApkChecksums.java
@@ -0,0 +1,510 @@
+/*
+ * 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.pm;
+
+import static android.content.pm.PackageManager.EXTRA_CHECKSUMS;
+import static android.content.pm.PackageManager.PARTIAL_MERKLE_ROOT_1M_SHA256;
+import static android.content.pm.PackageManager.PARTIAL_MERKLE_ROOT_1M_SHA512;
+import static android.content.pm.PackageManager.WHOLE_MD5;
+import static android.content.pm.PackageManager.WHOLE_MERKLE_ROOT_4K_SHA256;
+import static android.content.pm.PackageManager.WHOLE_SHA1;
+import static android.content.pm.PackageManager.WHOLE_SHA256;
+import static android.content.pm.PackageManager.WHOLE_SHA512;
+import static android.util.apk.ApkSigningBlockUtils.CONTENT_DIGEST_CHUNKED_SHA256;
+import static android.util.apk.ApkSigningBlockUtils.CONTENT_DIGEST_CHUNKED_SHA512;
+import static android.util.apk.ApkSigningBlockUtils.CONTENT_DIGEST_VERITY_CHUNKED_SHA256;
+
+import android.annotation.NonNull;
+import android.annotation.Nullable;
+import android.content.Context;
+import android.content.Intent;
+import android.content.IntentSender;
+import android.content.pm.FileChecksum;
+import android.content.pm.PackageManager;
+import android.content.pm.PackageParser;
+import android.os.Handler;
+import android.os.SystemClock;
+import android.os.incremental.IncrementalManager;
+import android.os.incremental.IncrementalStorage;
+import android.util.ArrayMap;
+import android.util.Pair;
+import android.util.Slog;
+import android.util.apk.ApkSignatureSchemeV2Verifier;
+import android.util.apk.ApkSignatureSchemeV3Verifier;
+import android.util.apk.ApkSignatureSchemeV4Verifier;
+import android.util.apk.ApkSignatureVerifier;
+import android.util.apk.ApkSigningBlockUtils;
+import android.util.apk.ByteBufferFactory;
+import android.util.apk.SignatureInfo;
+import android.util.apk.SignatureNotFoundException;
+import android.util.apk.VerityBuilder;
+
+import com.android.internal.annotations.VisibleForTesting;
+import com.android.server.security.VerityUtils;
+
+import java.io.BufferedInputStream;
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.IOException;
+import java.io.RandomAccessFile;
+import java.nio.ByteBuffer;
+import java.security.DigestException;
+import java.security.MessageDigest;
+import java.security.NoSuchAlgorithmException;
+import java.security.cert.Certificate;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Map;
+
+/**
+ * Provides checksums for APK.
+ */
+public class ApkChecksums {
+ static final String TAG = "ApkChecksums";
+
+ // MessageDigest algorithms.
+ static final String ALGO_MD5 = "MD5";
+ static final String ALGO_SHA1 = "SHA1";
+ static final String ALGO_SHA256 = "SHA256";
+ static final String ALGO_SHA512 = "SHA512";
+
+ /**
+ * Check back in 1 second after we detected we needed to wait for the APK to be fully available.
+ */
+ private static final long PROCESS_REQUIRED_CHECKSUMS_DELAY_MILLIS = 1000;
+
+ /**
+ * 24 hours timeout to wait till all files are loaded.
+ */
+ private static final long PROCESS_REQUIRED_CHECKSUMS_TIMEOUT_MILLIS = 1000 * 3600 * 24;
+
+ /**
+ * Unit tests will instantiate, extend and/or mock to mock dependencies / behaviors.
+ *
+ * NOTE: All getters should return the same instance for every call.
+ */
+ @VisibleForTesting(visibility = VisibleForTesting.Visibility.PRIVATE)
+ static class Injector {
+
+ @VisibleForTesting(visibility = VisibleForTesting.Visibility.PRIVATE)
+ interface Producer<T> {
+ /** Produce an instance of type {@link T} */
+ T produce();
+ }
+
+ private final Producer<Context> mContext;
+ private final Producer<Handler> mHandlerProducer;
+ private final Producer<IncrementalManager> mIncrementalManagerProducer;
+
+ Injector(Producer<Context> context, Producer<Handler> handlerProducer,
+ Producer<IncrementalManager> incrementalManagerProducer) {
+ mContext = context;
+ mHandlerProducer = handlerProducer;
+ mIncrementalManagerProducer = incrementalManagerProducer;
+ }
+
+ public Context getContext() {
+ return mContext.produce();
+ }
+
+ public Handler getHandler() {
+ return mHandlerProducer.produce();
+ }
+
+ public IncrementalManager getIncrementalManager() {
+ return mIncrementalManagerProducer.produce();
+ }
+ }
+
+ /**
+ * Fetch or calculate checksums for the collection of files.
+ *
+ * @param filesToChecksum split name, null for base and File to fetch checksums for
+ * @param optional mask to fetch readily available checksums
+ * @param required mask to forcefully calculate if not available
+ * @param trustedInstallers array of certificate to trust, two specific cases:
+ * null - trust anybody,
+ * [] - trust nobody.
+ * @param statusReceiver to receive the resulting checksums
+ */
+ public static void getChecksums(List<Pair<String, File>> filesToChecksum,
+ @PackageManager.FileChecksumKind int optional,
+ @PackageManager.FileChecksumKind int required,
+ @Nullable Certificate[] trustedInstallers,
+ @NonNull IntentSender statusReceiver,
+ @NonNull Injector injector) {
+ List<Map<Integer, FileChecksum>> result = new ArrayList<>(filesToChecksum.size());
+ for (int i = 0, size = filesToChecksum.size(); i < size; ++i) {
+ final String split = filesToChecksum.get(i).first;
+ final File file = filesToChecksum.get(i).second;
+ Map<Integer, FileChecksum> checksums = new ArrayMap<>();
+ result.add(checksums);
+
+ try {
+ getAvailableFileChecksums(split, file, optional | required, trustedInstallers,
+ checksums);
+ } catch (Throwable e) {
+ Slog.e(TAG, "Preferred checksum calculation error", e);
+ }
+ }
+
+ long startTime = SystemClock.uptimeMillis();
+ processRequiredChecksums(filesToChecksum, result, required, statusReceiver, injector,
+ startTime);
+ }
+
+ private static void processRequiredChecksums(List<Pair<String, File>> filesToChecksum,
+ List<Map<Integer, FileChecksum>> result,
+ @PackageManager.FileChecksumKind int required,
+ @NonNull IntentSender statusReceiver,
+ @NonNull Injector injector,
+ long startTime) {
+ final boolean timeout =
+ SystemClock.uptimeMillis() - startTime >= PROCESS_REQUIRED_CHECKSUMS_TIMEOUT_MILLIS;
+ List<FileChecksum> allChecksums = new ArrayList<>();
+ for (int i = 0, size = filesToChecksum.size(); i < size; ++i) {
+ final String split = filesToChecksum.get(i).first;
+ final File file = filesToChecksum.get(i).second;
+ Map<Integer, FileChecksum> checksums = result.get(i);
+
+ try {
+ if (!timeout || required != 0) {
+ if (needToWait(file, required, checksums, injector)) {
+ // Not ready, come back later.
+ injector.getHandler().postDelayed(() -> {
+ processRequiredChecksums(filesToChecksum, result, required,
+ statusReceiver, injector, startTime);
+ }, PROCESS_REQUIRED_CHECKSUMS_DELAY_MILLIS);
+ return;
+ }
+
+ getRequiredFileChecksums(split, file, required, checksums);
+ }
+ allChecksums.addAll(checksums.values());
+ } catch (Throwable e) {
+ Slog.e(TAG, "Required checksum calculation error", e);
+ }
+ }
+
+ final Intent intent = new Intent();
+ intent.putExtra(EXTRA_CHECKSUMS,
+ allChecksums.toArray(new FileChecksum[allChecksums.size()]));
+
+ try {
+ statusReceiver.sendIntent(injector.getContext(), 1, intent, null, null);
+ } catch (IntentSender.SendIntentException e) {
+ Slog.w(TAG, e);
+ }
+ }
+
+ /**
+ * Fetch readily available checksums - enforced by kernel or provided by Installer.
+ *
+ * @param split split name, null for base
+ * @param file to fetch checksums for
+ * @param kinds mask to fetch checksums
+ * @param trustedInstallers array of certificate to trust, two specific cases:
+ * null - trust anybody,
+ * [] - trust nobody.
+ * @param checksums resulting checksums
+ */
+ private static void getAvailableFileChecksums(String split, File file,
+ @PackageManager.FileChecksumKind int kinds,
+ @Nullable Certificate[] trustedInstallers,
+ Map<Integer, FileChecksum> checksums) {
+ final String filePath = file.getAbsolutePath();
+
+ // Always available: FSI or IncFs.
+ if (isRequired(WHOLE_MERKLE_ROOT_4K_SHA256, kinds, checksums)) {
+ // Hashes in fs-verity and IncFS are always verified.
+ FileChecksum checksum = extractHashFromFS(split, filePath);
+ if (checksum != null) {
+ checksums.put(checksum.getKind(), checksum);
+ }
+ }
+
+ // System enforced: v2/v3.
+ if (isRequired(PARTIAL_MERKLE_ROOT_1M_SHA256, kinds, checksums) || isRequired(
+ PARTIAL_MERKLE_ROOT_1M_SHA512, kinds, checksums)) {
+ Map<Integer, FileChecksum> v2v3checksums = extractHashFromV2V3Signature(
+ split, filePath, kinds);
+ if (v2v3checksums != null) {
+ checksums.putAll(v2v3checksums);
+ }
+ }
+
+ // TODO(b/160605420): Installer provided.
+ }
+
+ /**
+ * Whether the file is available for checksumming or we need to wait.
+ */
+ private static boolean needToWait(File file,
+ @PackageManager.FileChecksumKind int kinds,
+ Map<Integer, FileChecksum> checksums,
+ @NonNull Injector injector) throws IOException {
+ if (!isRequired(WHOLE_MERKLE_ROOT_4K_SHA256, kinds, checksums)
+ && !isRequired(WHOLE_MD5, kinds, checksums)
+ && !isRequired(WHOLE_SHA1, kinds, checksums)
+ && !isRequired(WHOLE_SHA256, kinds, checksums)
+ && !isRequired(WHOLE_SHA512, kinds, checksums)
+ && !isRequired(PARTIAL_MERKLE_ROOT_1M_SHA256, kinds, checksums)
+ && !isRequired(PARTIAL_MERKLE_ROOT_1M_SHA512, kinds, checksums)) {
+ return false;
+ }
+
+ final String filePath = file.getAbsolutePath();
+ if (!IncrementalManager.isIncrementalPath(filePath)) {
+ return false;
+ }
+
+ IncrementalManager manager = injector.getIncrementalManager();
+ if (manager == null) {
+ throw new IllegalStateException("IncrementalManager is missing.");
+ }
+ IncrementalStorage storage = manager.openStorage(filePath);
+ if (storage == null) {
+ throw new IllegalStateException(
+ "IncrementalStorage is missing for a path on IncFs: " + filePath);
+ }
+
+ return !storage.isFileFullyLoaded(filePath);
+ }
+
+ /**
+ * Fetch or calculate checksums for the specific file.
+ *
+ * @param split split name, null for base
+ * @param file to fetch checksums for
+ * @param kinds mask to forcefully calculate if not available
+ * @param checksums resulting checksums
+ */
+ private static void getRequiredFileChecksums(String split, File file,
+ @PackageManager.FileChecksumKind int kinds,
+ Map<Integer, FileChecksum> checksums) {
+ final String filePath = file.getAbsolutePath();
+
+ // Manually calculating required checksums if not readily available.
+ if (isRequired(WHOLE_MERKLE_ROOT_4K_SHA256, kinds, checksums)) {
+ try {
+ byte[] generatedRootHash = VerityBuilder.generateFsVerityRootHash(
+ filePath, /*salt=*/null,
+ new ByteBufferFactory() {
+ @Override
+ public ByteBuffer create(int capacity) {
+ return ByteBuffer.allocate(capacity);
+ }
+ });
+ checksums.put(WHOLE_MERKLE_ROOT_4K_SHA256,
+ new FileChecksum(split, WHOLE_MERKLE_ROOT_4K_SHA256, generatedRootHash));
+ } catch (IOException | NoSuchAlgorithmException | DigestException e) {
+ Slog.e(TAG, "Error calculating WHOLE_MERKLE_ROOT_4K_SHA256", e);
+ }
+ }
+
+ calculateChecksumIfRequested(checksums, split, file, kinds, WHOLE_MD5);
+ calculateChecksumIfRequested(checksums, split, file, kinds, WHOLE_SHA1);
+ calculateChecksumIfRequested(checksums, split, file, kinds, WHOLE_SHA256);
+ calculateChecksumIfRequested(checksums, split, file, kinds, WHOLE_SHA512);
+
+ calculatePartialChecksumsIfRequested(checksums, split, file, kinds);
+ }
+
+ private static boolean isRequired(@PackageManager.FileChecksumKind int kind,
+ @PackageManager.FileChecksumKind int kinds, Map<Integer, FileChecksum> checksums) {
+ if ((kinds & kind) == 0) {
+ return false;
+ }
+ if (checksums.containsKey(kind)) {
+ return false;
+ }
+ return true;
+ }
+
+ private static FileChecksum extractHashFromFS(String split, String filePath) {
+ // verity first
+ {
+ byte[] hash = VerityUtils.getFsverityRootHash(filePath);
+ if (hash != null) {
+ return new FileChecksum(split, WHOLE_MERKLE_ROOT_4K_SHA256, hash);
+ }
+ }
+ // v4 next
+ try {
+ ApkSignatureSchemeV4Verifier.VerifiedSigner signer =
+ ApkSignatureSchemeV4Verifier.extractCertificates(filePath);
+ byte[] hash = signer.contentDigests.getOrDefault(CONTENT_DIGEST_VERITY_CHUNKED_SHA256,
+ null);
+ if (hash != null) {
+ return new FileChecksum(split, WHOLE_MERKLE_ROOT_4K_SHA256, hash);
+ }
+ } catch (SignatureNotFoundException e) {
+ // Nothing
+ } catch (SecurityException e) {
+ Slog.e(TAG, "V4 signature error", e);
+ }
+ return null;
+ }
+
+ private static Map<Integer, FileChecksum> extractHashFromV2V3Signature(
+ String split, String filePath, int kinds) {
+ Map<Integer, byte[]> contentDigests = null;
+ try {
+ contentDigests = ApkSignatureVerifier.verifySignaturesInternal(filePath,
+ PackageParser.SigningDetails.SignatureSchemeVersion.SIGNING_BLOCK_V2,
+ false).contentDigests;
+ } catch (PackageParser.PackageParserException e) {
+ if (!(e.getCause() instanceof SignatureNotFoundException)) {
+ Slog.e(TAG, "Signature verification error", e);
+ }
+ }
+
+ if (contentDigests == null) {
+ return null;
+ }
+
+ Map<Integer, FileChecksum> checksums = new ArrayMap<>();
+ if ((kinds & PARTIAL_MERKLE_ROOT_1M_SHA256) != 0) {
+ byte[] hash = contentDigests.getOrDefault(CONTENT_DIGEST_CHUNKED_SHA256, null);
+ if (hash != null) {
+ checksums.put(PARTIAL_MERKLE_ROOT_1M_SHA256,
+ new FileChecksum(split, PARTIAL_MERKLE_ROOT_1M_SHA256, hash));
+ }
+ }
+ if ((kinds & PARTIAL_MERKLE_ROOT_1M_SHA512) != 0) {
+ byte[] hash = contentDigests.getOrDefault(CONTENT_DIGEST_CHUNKED_SHA512, null);
+ if (hash != null) {
+ checksums.put(PARTIAL_MERKLE_ROOT_1M_SHA512,
+ new FileChecksum(split, PARTIAL_MERKLE_ROOT_1M_SHA512, hash));
+ }
+ }
+ return checksums;
+ }
+
+ private static String getMessageDigestAlgoForChecksumKind(int kind)
+ throws NoSuchAlgorithmException {
+ switch (kind) {
+ case WHOLE_MD5:
+ return ALGO_MD5;
+ case WHOLE_SHA1:
+ return ALGO_SHA1;
+ case WHOLE_SHA256:
+ return ALGO_SHA256;
+ case WHOLE_SHA512:
+ return ALGO_SHA512;
+ default:
+ throw new NoSuchAlgorithmException("Invalid checksum kind: " + kind);
+ }
+ }
+
+ private static void calculateChecksumIfRequested(Map<Integer, FileChecksum> checksums,
+ String split, File file, int required, int kind) {
+ if ((required & kind) != 0 && !checksums.containsKey(kind)) {
+ final byte[] checksum = getFileChecksum(file, kind);
+ if (checksum != null) {
+ checksums.put(kind, new FileChecksum(split, kind, checksum));
+ }
+ }
+ }
+
+ private static byte[] getFileChecksum(File file, int kind) {
+ try (FileInputStream fis = new FileInputStream(file);
+ BufferedInputStream bis = new BufferedInputStream(fis)) {
+ byte[] dataBytes = new byte[512 * 1024];
+ int nread = 0;
+
+ final String algo = getMessageDigestAlgoForChecksumKind(kind);
+ MessageDigest md = MessageDigest.getInstance(algo);
+ while ((nread = bis.read(dataBytes)) != -1) {
+ md.update(dataBytes, 0, nread);
+ }
+
+ return md.digest();
+ } catch (IOException e) {
+ Slog.e(TAG, "Error reading " + file.getAbsolutePath() + " to compute hash.", e);
+ return null;
+ } catch (NoSuchAlgorithmException e) {
+ Slog.e(TAG, "Device does not support MessageDigest algorithm", e);
+ return null;
+ }
+ }
+
+ private static int[] getContentDigestAlgos(boolean needSignatureSha256,
+ boolean needSignatureSha512) {
+ if (needSignatureSha256 && needSignatureSha512) {
+ // Signature block present, but no digests???
+ return new int[]{CONTENT_DIGEST_CHUNKED_SHA256, CONTENT_DIGEST_CHUNKED_SHA512};
+ } else if (needSignatureSha256) {
+ return new int[]{CONTENT_DIGEST_CHUNKED_SHA256};
+ } else {
+ return new int[]{CONTENT_DIGEST_CHUNKED_SHA512};
+ }
+ }
+
+ private static int getChecksumKindForContentDigestAlgo(int contentDigestAlgo) {
+ switch (contentDigestAlgo) {
+ case CONTENT_DIGEST_CHUNKED_SHA256:
+ return PARTIAL_MERKLE_ROOT_1M_SHA256;
+ case CONTENT_DIGEST_CHUNKED_SHA512:
+ return PARTIAL_MERKLE_ROOT_1M_SHA512;
+ default:
+ return -1;
+ }
+ }
+
+ private static void calculatePartialChecksumsIfRequested(Map<Integer, FileChecksum> checksums,
+ String split, File file, int required) {
+ boolean needSignatureSha256 =
+ (required & PARTIAL_MERKLE_ROOT_1M_SHA256) != 0 && !checksums.containsKey(
+ PARTIAL_MERKLE_ROOT_1M_SHA256);
+ boolean needSignatureSha512 =
+ (required & PARTIAL_MERKLE_ROOT_1M_SHA512) != 0 && !checksums.containsKey(
+ PARTIAL_MERKLE_ROOT_1M_SHA512);
+ if (!needSignatureSha256 && !needSignatureSha512) {
+ return;
+ }
+
+ try (RandomAccessFile raf = new RandomAccessFile(file, "r")) {
+ SignatureInfo signatureInfo = null;
+ try {
+ signatureInfo = ApkSignatureSchemeV3Verifier.findSignature(raf);
+ } catch (SignatureNotFoundException e) {
+ try {
+ signatureInfo = ApkSignatureSchemeV2Verifier.findSignature(raf);
+ } catch (SignatureNotFoundException ee) {
+ }
+ }
+ if (signatureInfo == null) {
+ Slog.e(TAG, "V2/V3 signatures not found in " + file.getAbsolutePath());
+ return;
+ }
+
+ final int[] digestAlgos = getContentDigestAlgos(needSignatureSha256,
+ needSignatureSha512);
+ byte[][] digests = ApkSigningBlockUtils.computeContentDigestsPer1MbChunk(digestAlgos,
+ raf.getFD(), signatureInfo);
+ for (int i = 0, size = digestAlgos.length; i < size; ++i) {
+ int checksumKind = getChecksumKindForContentDigestAlgo(digestAlgos[i]);
+ if (checksumKind != -1) {
+ checksums.put(checksumKind, new FileChecksum(split, checksumKind, digests[i]));
+ }
+ }
+ } catch (IOException | DigestException e) {
+ Slog.e(TAG, "Error computing hash.", e);
+ }
+ }
+}
diff --git a/services/core/java/com/android/server/pm/AppsFilter.java b/services/core/java/com/android/server/pm/AppsFilter.java
index 3d7c978ca625..f168ac70dda8 100644
--- a/services/core/java/com/android/server/pm/AppsFilter.java
+++ b/services/core/java/com/android/server/pm/AppsFilter.java
@@ -560,9 +560,9 @@ public class AppsFilter {
final boolean newIsForceQueryable =
mForceQueryable.contains(newPkgSetting.appId)
/* shared user that is already force queryable */
- || newPkg.isForceQueryable()
- || newPkgSetting.forceQueryableOverride
+ || newPkgSetting.forceQueryableOverride /* adb override */
|| (newPkgSetting.isSystem() && (mSystemAppsQueryable
+ || newPkg.isForceQueryable()
|| ArrayUtils.contains(mForceQueryableByDevicePackageNames,
newPkg.getPackageName())));
if (newIsForceQueryable
diff --git a/services/core/java/com/android/server/pm/ComponentResolver.java b/services/core/java/com/android/server/pm/ComponentResolver.java
index 3f6b8e92ef74..d25ddad174f9 100644
--- a/services/core/java/com/android/server/pm/ComponentResolver.java
+++ b/services/core/java/com/android/server/pm/ComponentResolver.java
@@ -890,54 +890,55 @@ public class ComponentResolver {
return;
}
- if (systemActivities == null) {
- // the system package is not disabled; we're parsing the system partition
- if (isProtectedAction(intent)) {
- if (mDeferProtectedFilters) {
- // We can't deal with these just yet. No component should ever obtain a
- // >0 priority for a protected actions, with ONE exception -- the setup
- // wizard. The setup wizard, however, cannot be known until we're able to
- // query it for the category CATEGORY_SETUP_WIZARD. Which we can't do
- // until all intent filters have been processed. Chicken, meet egg.
- // Let the filter temporarily have a high priority and rectify the
- // priorities after all system packages have been scanned.
- if (mProtectedFilters == null) {
- mProtectedFilters = new ArrayList<>();
- }
- mProtectedFilters.add(Pair.create(activity, intent));
- if (DEBUG_FILTERS) {
- Slog.i(TAG, "Protected action; save for later;"
- + " package: " + packageName
- + " activity: " + className
- + " origPrio: " + intent.getPriority());
- }
- return;
- } else {
- if (DEBUG_FILTERS && setupWizardPackage == null) {
- Slog.i(TAG, "No setup wizard;"
- + " All protected intents capped to priority 0");
- }
- if (packageName.equals(setupWizardPackage)) {
- if (DEBUG_FILTERS) {
- Slog.i(TAG, "Found setup wizard;"
- + " allow priority " + intent.getPriority() + ";"
- + " package: " + packageName
- + " activity: " + className
- + " priority: " + intent.getPriority());
- }
- // setup wizard gets whatever it wants
- return;
- }
+ if (isProtectedAction(intent)) {
+ if (mDeferProtectedFilters) {
+ // We can't deal with these just yet. No component should ever obtain a
+ // >0 priority for a protected actions, with ONE exception -- the setup
+ // wizard. The setup wizard, however, cannot be known until we're able to
+ // query it for the category CATEGORY_SETUP_WIZARD. Which we can't do
+ // until all intent filters have been processed. Chicken, meet egg.
+ // Let the filter temporarily have a high priority and rectify the
+ // priorities after all system packages have been scanned.
+ if (mProtectedFilters == null) {
+ mProtectedFilters = new ArrayList<>();
+ }
+ mProtectedFilters.add(Pair.create(activity, intent));
+ if (DEBUG_FILTERS) {
+ Slog.i(TAG, "Protected action; save for later;"
+ + " package: " + packageName
+ + " activity: " + className
+ + " origPrio: " + intent.getPriority());
+ }
+ } else {
+ if (DEBUG_FILTERS && setupWizardPackage == null) {
+ Slog.i(TAG, "No setup wizard;"
+ + " All protected intents capped to priority 0");
+ }
+ if (packageName.equals(setupWizardPackage)) {
if (DEBUG_FILTERS) {
- Slog.i(TAG, "Protected action; cap priority to 0;"
+ Slog.i(TAG, "Found setup wizard;"
+ + " allow priority " + intent.getPriority() + ";"
+ " package: " + packageName
+ " activity: " + className
- + " origPrio: " + intent.getPriority());
+ + " priority: " + intent.getPriority());
}
- intent.setPriority(0);
+ // setup wizard gets whatever it wants
return;
}
+ if (DEBUG_FILTERS) {
+ Slog.i(TAG, "Protected action; cap priority to 0;"
+ + " package: " + packageName
+ + " activity: " + className
+ + " origPrio: " + intent.getPriority());
+ }
+ intent.setPriority(0);
}
+ return;
+ }
+
+ if (systemActivities == null) {
+ // the system package is not disabled; we're parsing the system partition
+
// privileged apps on the system image get whatever priority they request
return;
}
diff --git a/services/core/java/com/android/server/pm/CrossProfileAppsServiceImpl.java b/services/core/java/com/android/server/pm/CrossProfileAppsServiceImpl.java
index 617f6879e65e..a234f5ac3f3e 100644
--- a/services/core/java/com/android/server/pm/CrossProfileAppsServiceImpl.java
+++ b/services/core/java/com/android/server/pm/CrossProfileAppsServiceImpl.java
@@ -605,7 +605,7 @@ public class CrossProfileAppsServiceImpl extends ICrossProfileApps.Stub {
private boolean isPlatformSignedAppWithAutomaticProfilesPermission(
String packageName, int[] profileIds) {
for (int userId : profileIds) {
- final int uid = mInjector.getPackageManagerInternal().getPackageUidInternal(
+ final int uid = mInjector.getPackageManagerInternal().getPackageUid(
packageName, /* flags= */ 0, userId);
if (uid == -1) {
continue;
diff --git a/services/core/java/com/android/server/pm/PackageInstallerService.java b/services/core/java/com/android/server/pm/PackageInstallerService.java
index 4b246c3b330c..162bfee8848d 100644
--- a/services/core/java/com/android/server/pm/PackageInstallerService.java
+++ b/services/core/java/com/android/server/pm/PackageInstallerService.java
@@ -743,9 +743,8 @@ public class PackageInstallerService extends IPackageInstaller.Stub implements
mStagingManager.createSession(session);
}
- if ((session.params.installFlags & PackageManager.INSTALL_DRY_RUN) == 0) {
- mCallbacks.notifySessionCreated(session.sessionId, session.userId);
- }
+ mCallbacks.notifySessionCreated(session.sessionId, session.userId);
+
writeSessionsAsync();
return sessionId;
}
@@ -1355,25 +1354,18 @@ public class PackageInstallerService extends IPackageInstaller.Stub implements
class InternalCallback {
public void onSessionBadgingChanged(PackageInstallerSession session) {
- if ((session.params.installFlags & PackageManager.INSTALL_DRY_RUN) == 0) {
- mCallbacks.notifySessionBadgingChanged(session.sessionId, session.userId);
- }
-
+ mCallbacks.notifySessionBadgingChanged(session.sessionId, session.userId);
writeSessionsAsync();
}
public void onSessionActiveChanged(PackageInstallerSession session, boolean active) {
- if ((session.params.installFlags & PackageManager.INSTALL_DRY_RUN) == 0) {
- mCallbacks.notifySessionActiveChanged(session.sessionId, session.userId,
- active);
- }
+ mCallbacks.notifySessionActiveChanged(session.sessionId, session.userId,
+ active);
}
public void onSessionProgressChanged(PackageInstallerSession session, float progress) {
- if ((session.params.installFlags & PackageManager.INSTALL_DRY_RUN) == 0) {
- mCallbacks.notifySessionProgressChanged(session.sessionId, session.userId,
- progress);
- }
+ mCallbacks.notifySessionProgressChanged(session.sessionId, session.userId,
+ progress);
}
public void onStagedSessionChanged(PackageInstallerSession session) {
@@ -1389,17 +1381,13 @@ public class PackageInstallerService extends IPackageInstaller.Stub implements
}
public void onSessionFinished(final PackageInstallerSession session, boolean success) {
- if ((session.params.installFlags & PackageManager.INSTALL_DRY_RUN) == 0) {
- mCallbacks.notifySessionFinished(session.sessionId, session.userId, success);
- }
+ mCallbacks.notifySessionFinished(session.sessionId, session.userId, success);
mInstallHandler.post(new Runnable() {
@Override
public void run() {
- if (session.isStaged()) {
- if (!success) {
- mStagingManager.abortSession(session);
- }
+ if (session.isStaged() && !success) {
+ mStagingManager.abortSession(session);
}
synchronized (mSessions) {
if (!session.isStaged() || !success) {
diff --git a/services/core/java/com/android/server/pm/PackageInstallerSession.java b/services/core/java/com/android/server/pm/PackageInstallerSession.java
index 28c5e964fe27..51164ba412b3 100644
--- a/services/core/java/com/android/server/pm/PackageInstallerSession.java
+++ b/services/core/java/com/android/server/pm/PackageInstallerSession.java
@@ -134,6 +134,7 @@ import com.android.internal.os.SomeArgs;
import com.android.internal.util.ArrayUtils;
import com.android.internal.util.FrameworkStatsLog;
import com.android.internal.util.IndentingPrintWriter;
+import com.android.internal.util.Preconditions;
import com.android.server.LocalServices;
import com.android.server.pm.Installer.InstallerException;
import com.android.server.pm.dex.DexManager;
@@ -1325,6 +1326,7 @@ public class PackageInstallerSession extends IPackageInstallerSession.Stub {
final int status = intent.getIntExtra(PackageInstaller.EXTRA_STATUS,
PackageInstaller.STATUS_FAILURE);
final int sessionIndex = mChildSessionsRemaining.indexOfKey(sessionId);
+ final String message = intent.getStringExtra(PackageInstaller.EXTRA_STATUS_MESSAGE);
if (PackageInstaller.STATUS_SUCCESS == status) {
mChildSessionsRemaining.removeAt(sessionIndex);
if (mChildSessionsRemaining.size() == 0) {
@@ -1341,10 +1343,9 @@ public class PackageInstallerSession extends IPackageInstallerSession.Stub {
intent.putExtra(PackageInstaller.EXTRA_SESSION_ID,
PackageInstallerSession.this.sessionId);
mChildSessionsRemaining.clear(); // we're done. Don't send any more.
- try {
- mStatusReceiver.sendIntent(mContext, 0, intent, null, null);
- } catch (IntentSender.SendIntentException ignore) {
- }
+ destroyInternal();
+ dispatchSessionFinished(INSTALL_FAILED_INTERNAL_ERROR,
+ "Child session " + sessionId + " failed: " + message, null);
}
});
}
@@ -1554,12 +1555,29 @@ public class PackageInstallerSession extends IPackageInstallerSession.Stub {
}
private void onSessionValidationFailure(int error, String detailMessage) {
- // Session is sealed but could not be verified, we need to destroy it.
+ // Session is sealed but could not be validated, we need to destroy it.
destroyInternal();
// Dispatch message to remove session from PackageInstallerService.
dispatchSessionFinished(error, detailMessage, null);
}
+ private void onSessionVerificationFailure(int error, String msg) {
+ final String msgWithErrorCode = PackageManager.installStatusToString(error, msg);
+ Slog.e(TAG, "Failed to verify session " + sessionId + " [" + msgWithErrorCode + "]");
+ // Session is sealed and committed but could not be verified, we need to destroy it.
+ destroyInternal();
+ if (isStaged()) {
+ setStagedSessionFailed(
+ SessionInfo.STAGED_SESSION_VERIFICATION_FAILED, msgWithErrorCode);
+ // TODO(b/136257624): Remove this once all verification logic has been transferred out
+ // of StagingManager.
+ mStagingManager.notifyVerificationComplete(sessionId);
+ } else {
+ // Dispatch message to remove session from PackageInstallerService.
+ dispatchSessionFinished(error, msg, null);
+ }
+ }
+
private void onStorageUnhealthy() {
final String packageName = getPackageName();
if (TextUtils.isEmpty(packageName)) {
@@ -1680,7 +1698,8 @@ public class PackageInstallerSession extends IPackageInstallerSession.Stub {
}
if (params.isStaged) {
mStagingManager.commitSession(this);
- destroyInternal();
+ // TODO(b/136257624): CTS test fails if we don't send session finished broadcast, even
+ // though ideally, we just need to send session committed broadcast.
dispatchSessionFinished(PackageManager.INSTALL_SUCCEEDED, "Session staged", null);
return;
}
@@ -1691,14 +1710,30 @@ public class PackageInstallerSession extends IPackageInstallerSession.Stub {
"APEX packages can only be installed using staged sessions.", null);
return;
}
+ verify();
+ }
+ /**
+ * Resumes verification process for non-final committed staged session.
+ *
+ * Useful if a device gets rebooted before verification is complete and we need to restart the
+ * verification.
+ */
+ void verifyStagedSession() {
+ assertCallerIsOwnerOrRootOrSystemLocked();
+ Preconditions.checkArgument(isCommitted());
+ Preconditions.checkArgument(isStaged());
+ Preconditions.checkArgument(!mStagedSessionApplied && !mStagedSessionFailed);
+
+ verify();
+ }
+
+ private void verify() {
try {
verifyNonStaged();
} catch (PackageManagerException e) {
final String completeMsg = ExceptionUtils.getCompleteMessage(e);
- Slog.e(TAG, "Commit of session " + sessionId + " failed: " + completeMsg);
- destroyInternal();
- dispatchSessionFinished(e.error, completeMsg, null);
+ onSessionVerificationFailure(e.error, completeMsg);
}
}
@@ -1846,7 +1881,9 @@ public class PackageInstallerSession extends IPackageInstallerSession.Stub {
@GuardedBy("mLock")
private PackageManagerService.VerificationParams makeVerificationParamsLocked()
throws PackageManagerException {
- if (!params.isMultiPackage) {
+ // TODO(b/136257624): Some logic in this if block probably belongs in
+ // makeInstallParams().
+ if (!params.isMultiPackage && !isApexInstallation()) {
Objects.requireNonNull(mPackageName);
Objects.requireNonNull(mSigningDetails);
Objects.requireNonNull(mResolvedBaseFile);
@@ -1923,8 +1960,7 @@ public class PackageInstallerSession extends IPackageInstallerSession.Stub {
if (returnCode == PackageManager.INSTALL_SUCCEEDED) {
onVerificationComplete();
} else {
- destroyInternal();
- dispatchSessionFinished(returnCode, msg, extras);
+ onSessionVerificationFailure(returnCode, msg);
}
}
};
@@ -1946,9 +1982,13 @@ public class PackageInstallerSession extends IPackageInstallerSession.Stub {
}
private void onVerificationComplete() {
- if ((params.installFlags & PackageManager.INSTALL_DRY_RUN) != 0) {
- destroyInternal();
- dispatchSessionFinished(PackageManager.INSTALL_SUCCEEDED, "Dry run", new Bundle());
+ // Staged sessions will be installed later during boot
+ if (isStaged()) {
+ // TODO(b/136257624): Remove this once all verification logic has been transferred out
+ // of StagingManager.
+ mStagingManager.notifyPreRebootVerification_Apk_Complete(sessionId);
+ // TODO(b/136257624): We also need to destroy internals for verified staged session,
+ // otherwise file descriptors are never closed for verified staged session until reboot
return;
}
@@ -3267,8 +3307,7 @@ public class PackageInstallerSession extends IPackageInstallerSession.Stub {
// Send broadcast to default launcher only if it's a new install
// TODO(b/144270665): Secure the usage of this broadcast.
final boolean isNewInstall = extras == null || !extras.getBoolean(Intent.EXTRA_REPLACING);
- if (success && isNewInstall && mPm.mInstallerService.okToSendBroadcasts()
- && (params.installFlags & PackageManager.INSTALL_DRY_RUN) == 0) {
+ if (success && isNewInstall && mPm.mInstallerService.okToSendBroadcasts()) {
mPm.sendSessionCommitBroadcast(generateInfoScrubbed(true /*icon*/), userId);
}
diff --git a/services/core/java/com/android/server/pm/PackageManagerService.java b/services/core/java/com/android/server/pm/PackageManagerService.java
index 3b98d24dc709..c6269eba8120 100644
--- a/services/core/java/com/android/server/pm/PackageManagerService.java
+++ b/services/core/java/com/android/server/pm/PackageManagerService.java
@@ -254,6 +254,7 @@ import android.os.IBinder;
import android.os.Looper;
import android.os.Message;
import android.os.Parcel;
+import android.os.ParcelableException;
import android.os.PatternMatcher;
import android.os.PersistableBundle;
import android.os.Process;
@@ -394,6 +395,7 @@ import java.io.FileDescriptor;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
+import java.io.InputStream;
import java.io.PrintWriter;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
@@ -404,7 +406,10 @@ import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.security.PublicKey;
import java.security.SecureRandom;
+import java.security.cert.Certificate;
import java.security.cert.CertificateException;
+import java.security.cert.CertificateFactory;
+import java.security.cert.X509Certificate;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
@@ -926,6 +931,7 @@ public class PackageManagerService extends IPackageManager.Stub
private final Object mLock;
private final Installer mInstaller;
private final Object mInstallLock;
+ private final Handler mBackgroundHandler;
private final Executor mBackgroundExecutor;
// ----- producers -----
@@ -948,7 +954,7 @@ public class PackageManagerService extends IPackageManager.Stub
Injector(Context context, Object lock, Installer installer,
Object installLock, PackageAbiHelper abiHelper,
- Executor backgroundExecutor,
+ Handler backgroundHandler,
Producer<ComponentResolver> componentResolverProducer,
Producer<PermissionManagerServiceInternal> permissionManagerProducer,
Producer<UserManagerService> userManagerProducer,
@@ -970,7 +976,8 @@ public class PackageManagerService extends IPackageManager.Stub
mInstaller = installer;
mAbiHelper = abiHelper;
mInstallLock = installLock;
- mBackgroundExecutor = backgroundExecutor;
+ mBackgroundHandler = backgroundHandler;
+ mBackgroundExecutor = new HandlerExecutor(backgroundHandler);
mComponentResolverProducer = new Singleton<>(componentResolverProducer);
mPermissionManagerProducer = new Singleton<>(permissionManagerProducer);
mUserManagerProducer = new Singleton<>(userManagerProducer);
@@ -1085,6 +1092,10 @@ public class PackageManagerService extends IPackageManager.Stub
return mPlatformCompatProducer.get(this, mPackageManager);
}
+ public Handler getBackgroundHandler() {
+ return mBackgroundHandler;
+ }
+
public Executor getBackgroundExecutor() {
return mBackgroundExecutor;
}
@@ -2400,9 +2411,12 @@ public class PackageManagerService extends IPackageManager.Stub
final int callingUserId = UserHandle.getUserId(callingUid);
for (String packageName : packages) {
- PackageSetting setting = mSettings.mPackages.get(packageName);
- if (setting != null
- && !shouldFilterApplicationLocked(setting, callingUid, callingUserId)) {
+ final boolean filterApp;
+ synchronized (mLock) {
+ final PackageSetting ps = mSettings.getPackageLPr(packageName);
+ filterApp = shouldFilterApplicationLocked(ps, callingUid, callingUserId);
+ }
+ if (!filterApp) {
notifyInstallObserver(packageName);
}
}
@@ -2443,6 +2457,68 @@ public class PackageManagerService extends IPackageManager.Stub
mHandler.sendMessageDelayed(message, DEFERRED_NO_KILL_INSTALL_OBSERVER_DELAY_MS);
}
+ @Override
+ public void getChecksums(@NonNull String packageName, boolean includeSplits,
+ @PackageManager.FileChecksumKind int optional,
+ @PackageManager.FileChecksumKind int required, @Nullable List trustedInstallers,
+ @NonNull IntentSender statusReceiver, int userId) {
+ Objects.requireNonNull(packageName);
+ Objects.requireNonNull(statusReceiver);
+
+ final ApplicationInfo applicationInfo = getApplicationInfoInternal(packageName, 0,
+ Binder.getCallingUid(), userId);
+ if (applicationInfo == null) {
+ throw new ParcelableException(new PackageManager.NameNotFoundException(packageName));
+ }
+
+ List<Pair<String, File>> filesToChecksum = new ArrayList<>();
+
+ // Adding base split.
+ filesToChecksum.add(Pair.create(null, new File(applicationInfo.sourceDir)));
+
+ // Adding other splits.
+ if (includeSplits && applicationInfo.splitNames != null) {
+ for (int i = 0, size = applicationInfo.splitNames.length; i < size; ++i) {
+ filesToChecksum.add(Pair.create(applicationInfo.splitNames[i],
+ new File(applicationInfo.splitSourceDirs[i])));
+ }
+ }
+
+ for (int i = 0, size = filesToChecksum.size(); i < size; ++i) {
+ final File file = filesToChecksum.get(i).second;
+ if (!file.exists()) {
+ throw new IllegalStateException("File not found: " + file.getPath());
+ }
+ }
+
+ final Certificate[] trustedCerts = (trustedInstallers != null) ? decodeCertificates(
+ trustedInstallers) : null;
+
+ mInjector.getBackgroundExecutor().execute(() -> {
+ ApkChecksums.Injector injector = new ApkChecksums.Injector(
+ () -> mContext,
+ () -> mInjector.getBackgroundHandler(),
+ () -> mContext.getSystemService(IncrementalManager.class));
+ ApkChecksums.getChecksums(filesToChecksum, optional, required, trustedCerts,
+ statusReceiver, injector);
+ });
+ }
+
+ private static @NonNull Certificate[] decodeCertificates(@NonNull List certs) {
+ try {
+ final CertificateFactory cf = CertificateFactory.getInstance("X.509");
+ final Certificate[] result = new Certificate[certs.size()];
+ for (int i = 0, size = certs.size(); i < size; ++i) {
+ final InputStream is = new ByteArrayInputStream((byte[]) certs.get(i));
+ final X509Certificate cert = (X509Certificate) cf.generateCertificate(is);
+ result[i] = cert;
+ }
+ return result;
+ } catch (CertificateException e) {
+ throw ExceptionUtils.propagate(e);
+ }
+ }
+
/**
* Gets the type of the external storage a package is installed on.
* @param packageVolume The storage volume of the package.
@@ -2597,7 +2673,7 @@ public class PackageManagerService extends IPackageManager.Stub
Injector injector = new Injector(
context, lock, installer, installLock, new PackageAbiHelperImpl(),
- new HandlerExecutor(backgroundHandler),
+ backgroundHandler,
(i, pm) ->
new ComponentResolver(i.getUserManagerService(), pm.mPmInternal, lock),
(i, pm) ->
@@ -5806,10 +5882,6 @@ public class PackageManagerService extends IPackageManager.Stub
private void updateSequenceNumberLP(PackageSetting pkgSetting, int[] userList) {
for (int i = userList.length - 1; i >= 0; --i) {
final int userId = userList[i];
- // don't add instant app to the list of updates
- if (pkgSetting.getInstantApp(userId)) {
- continue;
- }
SparseArray<String> changedPackages = mChangedPackages.get(userId);
if (changedPackages == null) {
changedPackages = new SparseArray<>();
@@ -5854,6 +5926,11 @@ public class PackageManagerService extends IPackageManager.Stub
for (int i = sequenceNumber; i < mChangedPackagesSequenceNumber; i++) {
final String packageName = changedPackages.get(i);
if (packageName != null) {
+ // Filter out the changes if the calling package should not be able to see it.
+ final PackageSetting ps = mSettings.mPackages.get(packageName);
+ if (shouldFilterApplicationLocked(ps, callingUid, userId)) {
+ continue;
+ }
packageNames.add(packageName);
}
}
@@ -8963,10 +9040,10 @@ public class PackageManagerService extends IPackageManager.Stub
if (providerInfo == null) {
return null;
}
- if (!mSettings.isEnabledAndMatchLPr(providerInfo, flags, userId)) {
- return null;
- }
synchronized (mLock) {
+ if (!mSettings.isEnabledAndMatchLPr(providerInfo, flags, userId)) {
+ return null;
+ }
final PackageSetting ps = mSettings.mPackages.get(providerInfo.packageName);
final ComponentName component =
new ComponentName(providerInfo.packageName, providerInfo.name);
@@ -9053,9 +9130,11 @@ public class PackageManagerService extends IPackageManager.Stub
String targetPackage, int flags) {
final int callingUid = Binder.getCallingUid();
final int callingUserId = UserHandle.getUserId(callingUid);
- final PackageSetting ps = mSettings.mPackages.get(targetPackage);
- if (shouldFilterApplicationLocked(ps, callingUid, callingUserId)) {
- return ParceledListSlice.emptyList();
+ synchronized (mLock) {
+ final PackageSetting ps = mSettings.getPackageLPr(targetPackage);
+ if (shouldFilterApplicationLocked(ps, callingUid, callingUserId)) {
+ return ParceledListSlice.emptyList();
+ }
}
return new ParceledListSlice<>(queryInstrumentationInternal(targetPackage, flags,
callingUserId));
@@ -11586,7 +11665,7 @@ public class PackageManagerService extends IPackageManager.Stub
configurePackageComponents(parsedPackage);
}
- final String cpuAbiOverride = deriveAbiOverride(request.cpuAbiOverride, pkgSetting);
+ final String cpuAbiOverride = deriveAbiOverride(request.cpuAbiOverride);
final boolean isUpdatedSystemApp = pkgSetting.getPkgState().isUpdatedSystemApp();
if ((scanFlags & SCAN_NEW_INSTALL) == 0) {
@@ -13792,7 +13871,7 @@ public class PackageManagerService extends IPackageManager.Stub
final boolean isCallerOwner = isCallerDeviceOrProfileOwner(userId);
final long callingId = Binder.clearCallingIdentity();
try {
- final String activeLauncherPackageName = getActiveLauncherPackageName(userId);
+ final String activeLauncherPackageName = mPermissionManager.getDefaultHome(userId);
final String dialerPackageName = mPermissionManager.getDefaultDialer(userId);
for (int i = 0; i < packageNames.length; i++) {
canSuspend[i] = false;
@@ -13868,18 +13947,6 @@ public class PackageManagerService extends IPackageManager.Stub
return canSuspend;
}
- private String getActiveLauncherPackageName(int userId) {
- Intent intent = new Intent(Intent.ACTION_MAIN);
- intent.addCategory(Intent.CATEGORY_HOME);
- ResolveInfo resolveInfo = resolveIntent(
- intent,
- intent.resolveTypeIfNeeded(mContext.getContentResolver()),
- PackageManager.MATCH_DEFAULT_ONLY,
- userId);
-
- return resolveInfo == null ? null : resolveInfo.activityInfo.packageName;
- }
-
@Override
public void verifyPendingInstall(int id, int verificationCode) throws RemoteException {
mContext.enforceCallingOrSelfPermission(
@@ -14571,7 +14638,7 @@ public class PackageManagerService extends IPackageManager.Stub
final PackageSetting ps;
int appId = -1;
long ceDataInode = -1;
- synchronized (mSettings) {
+ synchronized (mLock) {
ps = mSettings.getPackageLPr(packageName);
if (ps != null) {
appId = ps.appId;
@@ -15200,6 +15267,13 @@ public class PackageManagerService extends IPackageManager.Stub
}
public void handleStartCopy() {
+ if ((installFlags & PackageManager.INSTALL_APEX) != 0) {
+ // Apex packages get verified in StagingManager currently.
+ // TODO(b/136257624): Move apex verification logic out of StagingManager
+ mRet = INSTALL_SUCCEEDED;
+ return;
+ }
+
PackageInfoLite pkgLite = PackageManagerServiceUtils.getMinimalPackageInfo(mContext,
origin.resolvedPath, installFlags, packageAbiOverride);
@@ -17612,7 +17686,7 @@ public class PackageManagerService extends IPackageManager.Stub
}
boolean isUpdatedSystemAppFromExistingSetting = pkgSetting != null
&& pkgSetting.getPkgState().isUpdatedSystemApp();
- final String abiOverride = deriveAbiOverride(args.abiOverride, pkgSetting);
+ final String abiOverride = deriveAbiOverride(args.abiOverride);
AndroidPackage oldPackage = mPackages.get(pkgName);
boolean isUpdatedSystemAppInferred = oldPackage != null && oldPackage.isSystem();
final Pair<PackageAbiHelper.Abis, PackageAbiHelper.NativeLibraryPaths>
@@ -19445,6 +19519,9 @@ public class PackageManagerService extends IPackageManager.Stub
}
if (outInfo != null) {
+ if ((flags & PackageManager.DELETE_KEEP_DATA) == 0) {
+ outInfo.dataRemoved = true;
+ }
outInfo.removedPackage = ps.name;
outInfo.installerPackageName = ps.installSource.installerPackageName;
outInfo.isStaticSharedLib = pkg != null && pkg.getStaticSharedLibName() != null;
@@ -19480,9 +19557,11 @@ public class PackageManagerService extends IPackageManager.Stub
mPermissionManager.enforceCrossUserPermission(callingUid, userId,
true /* requireFullPermission */, false /* checkShell */, "clear application data");
- final PackageSetting ps = mSettings.getPackageLPr(packageName);
- final boolean filterApp =
- (ps != null && shouldFilterApplicationLocked(ps, callingUid, userId));
+ final boolean filterApp;
+ synchronized (mLock) {
+ final PackageSetting ps = mSettings.getPackageLPr(packageName);
+ filterApp = shouldFilterApplicationLocked(ps, callingUid, userId);
+ }
if (!filterApp && mProtectedPackages.isPackageDataProtected(userId, packageName)) {
throw new SecurityException("Cannot clear data for a protected package: "
+ packageName);
@@ -19762,11 +19841,13 @@ public class PackageManagerService extends IPackageManager.Stub
if (mContext.checkCallingOrSelfPermission(
android.Manifest.permission.SET_PREFERRED_APPLICATIONS)
!= PackageManager.PERMISSION_GRANTED) {
- if (getUidTargetSdkVersionLockedLPr(callingUid)
- < Build.VERSION_CODES.FROYO) {
- Slog.w(TAG, "Ignoring addPreferredActivity() from uid "
- + callingUid);
- return;
+ synchronized (mLock) {
+ if (getUidTargetSdkVersionLockedLPr(callingUid)
+ < Build.VERSION_CODES.FROYO) {
+ Slog.w(TAG, "Ignoring addPreferredActivity() from uid "
+ + callingUid);
+ return;
+ }
}
mContext.enforceCallingOrSelfPermission(
android.Manifest.permission.SET_PREFERRED_APPLICATIONS, null);
@@ -19946,8 +20027,9 @@ public class PackageManagerService extends IPackageManager.Stub
/** This method takes a specific user id as well as UserHandle.USER_ALL. */
private void clearPackagePreferredActivities(String packageName, int userId) {
final SparseBooleanArray changedUsers = new SparseBooleanArray();
-
- clearPackagePreferredActivitiesLPw(packageName, changedUsers, userId);
+ synchronized (mLock) {
+ clearPackagePreferredActivitiesLPw(packageName, changedUsers, userId);
+ }
if (changedUsers.size() > 0) {
updateDefaultHomeNotLocked(changedUsers);
postPreferredActivityChangedBroadcast(userId);
@@ -20069,7 +20151,9 @@ public class PackageManagerService extends IPackageManager.Stub
// writer
try {
final SparseBooleanArray changedUsers = new SparseBooleanArray();
- clearPackagePreferredActivitiesLPw(null, changedUsers, userId);
+ synchronized (mLock) {
+ clearPackagePreferredActivitiesLPw(null, changedUsers, userId);
+ }
if (changedUsers.size() > 0) {
postPreferredActivityChangedBroadcast(userId);
}
@@ -20537,6 +20621,9 @@ public class PackageManagerService extends IPackageManager.Stub
if (cn != null) {
return cn;
}
+ // TODO: This should not happen since there should always be a default package set for
+ // ROLE_HOME in RoleManager. Continue with a warning log for now.
+ Slog.w(TAG, "Default package for ROLE_HOME is not set in RoleManager");
// Find the launcher with the highest priority and return that component if there are no
// other home activity with the same priority.
@@ -20585,6 +20672,7 @@ public class PackageManagerService extends IPackageManager.Stub
if (packageName == null) {
return null;
}
+
int resolveInfosSize = resolveInfos.size();
for (int i = 0; i < resolveInfosSize; i++) {
ResolveInfo resolveInfo = resolveInfos.get(i);
@@ -20644,6 +20732,11 @@ public class PackageManagerService extends IPackageManager.Stub
// PermissionController manages default home directly.
return false;
}
+
+ if (packageName == null) {
+ // Keep the default home package in RoleManager.
+ return false;
+ }
mPermissionManager.setDefaultHome(packageName, userId, (successful) -> {
if (successful) {
postPreferredActivityChangedBroadcast(userId);
@@ -21079,15 +21172,19 @@ public class PackageManagerService extends IPackageManager.Stub
// Limit who can change which apps
if (!UserHandle.isSameApp(callingUid, pkgSetting.appId)) {
// Don't allow apps that don't have permission to modify other apps
- if (!allowedByPermission
- || shouldFilterApplicationLocked(pkgSetting, callingUid, userId)) {
+ final boolean filterApp;
+ synchronized (mLock) {
+ filterApp = (!allowedByPermission
+ || shouldFilterApplicationLocked(pkgSetting, callingUid, userId));
+ }
+ if (filterApp) {
throw new SecurityException(
"Attempt to change component state; "
- + "pid=" + Binder.getCallingPid()
- + ", uid=" + callingUid
- + (className == null
+ + "pid=" + Binder.getCallingPid()
+ + ", uid=" + callingUid
+ + (className == null
? ", package=" + packageName
- : ", component=" + packageName + "/" + className));
+ : ", component=" + packageName + "/" + className));
}
// Don't allow changing protected packages.
if (mProtectedPackages.isPackageStateProtected(userId, packageName)) {
@@ -21550,8 +21647,6 @@ public class PackageManagerService extends IPackageManager.Stub
.getUriFor(Secure.INSTANT_APPS_ENABLED), false, co, UserHandle.USER_ALL);
co.onChange(true);
- mAppsFilter.onSystemReady();
-
// Disable any carrier apps. We do this very early in boot to prevent the apps from being
// disabled after already being started.
CarrierAppUtils.disableCarrierAppsUntilPrivileged(
@@ -21700,6 +21795,9 @@ public class PackageManagerService extends IPackageManager.Stub
mInstallerService.restoreAndApplyStagedSessionIfNeeded();
mExistingPackages = null;
+
+ // We'll do this last as it builds its cache while holding mLock via callback.
+ mAppsFilter.onSystemReady();
}
public void waitForAppDataPrepared() {
@@ -24603,12 +24701,6 @@ public class PackageManagerService extends IPackageManager.Stub
@Override
public int getPackageUid(String packageName, int flags, int userId) {
return PackageManagerService.this
- .getPackageUid(packageName, flags, userId);
- }
-
- @Override
- public int getPackageUidInternal(String packageName, int flags, int userId) {
- return PackageManagerService.this
.getPackageUidInternal(packageName, flags, userId, Process.SYSTEM_UID);
}
diff --git a/services/core/java/com/android/server/pm/PackageManagerServiceUtils.java b/services/core/java/com/android/server/pm/PackageManagerServiceUtils.java
index 491b4fc515ce..5553cd0e2fb8 100644
--- a/services/core/java/com/android/server/pm/PackageManagerServiceUtils.java
+++ b/services/core/java/com/android/server/pm/PackageManagerServiceUtils.java
@@ -421,18 +421,13 @@ public class PackageManagerServiceUtils {
/**
* Derive the value of the {@code cpuAbiOverride} based on the provided
- * value and an optional stored value from the package settings.
+ * value.
*/
- public static String deriveAbiOverride(String abiOverride, PackageSetting settings) {
- String cpuAbiOverride = null;
+ public static String deriveAbiOverride(String abiOverride) {
if (NativeLibraryHelper.CLEAR_ABI_OVERRIDE.equals(abiOverride)) {
- cpuAbiOverride = null;
- } else if (abiOverride != null) {
- cpuAbiOverride = abiOverride;
- } else if (settings != null) {
- cpuAbiOverride = settings.cpuAbiOverrideString;
+ return null;
}
- return cpuAbiOverride;
+ return abiOverride;
}
/**
diff --git a/services/core/java/com/android/server/pm/PackageManagerShellCommand.java b/services/core/java/com/android/server/pm/PackageManagerShellCommand.java
index 7e2ef41943d6..4d2e22a2640e 100644
--- a/services/core/java/com/android/server/pm/PackageManagerShellCommand.java
+++ b/services/core/java/com/android/server/pm/PackageManagerShellCommand.java
@@ -103,6 +103,7 @@ import android.util.SparseArray;
import com.android.internal.content.PackageHelper;
import com.android.internal.util.ArrayUtils;
import com.android.internal.util.IndentingPrintWriter;
+import com.android.internal.util.Preconditions;
import com.android.server.LocalServices;
import com.android.server.SystemConfig;
import com.android.server.pm.PackageManagerShellCommandDataLoader.Metadata;
@@ -138,7 +139,7 @@ class PackageManagerShellCommand extends ShellCommand {
private static final String STDIN_PATH = "-";
/** Path where ART profiles snapshots are dumped for the shell user */
private final static String ART_PROFILE_SNAPSHOT_DEBUG_LOCATION = "/data/misc/profman/";
- private static final int DEFAULT_WAIT_MS = 60 * 1000;
+ private static final int DEFAULT_STAGED_READY_TIMEOUT_MS = 60 * 1000;
private static final String TAG = "PackageManagerShellCommand";
final IPackageManager mInterface;
@@ -463,9 +464,20 @@ class PackageManagerShellCommand extends ShellCommand {
return 1;
}
- private int runRollbackApp() {
+ private int runRollbackApp() throws RemoteException {
final PrintWriter pw = getOutPrintWriter();
+ String opt;
+ long stagedReadyTimeoutMs = DEFAULT_STAGED_READY_TIMEOUT_MS;
+ while ((opt = getNextOption()) != null) {
+ switch (opt) {
+ case "--staged-ready-timeout":
+ stagedReadyTimeoutMs = Long.parseLong(getNextArgRequired());
+ break;
+ default:
+ throw new IllegalArgumentException("Unknown option: " + opt);
+ }
+ }
final String packageName = getNextArgRequired();
if (packageName == null) {
pw.println("Error: package name not specified");
@@ -495,14 +507,21 @@ class PackageManagerShellCommand extends ShellCommand {
final Intent result = receiver.getResult();
final int status = result.getIntExtra(RollbackManager.EXTRA_STATUS,
RollbackManager.STATUS_FAILURE);
- if (status == RollbackManager.STATUS_SUCCESS) {
- pw.println("Success");
- return 0;
- } else {
+
+ if (status != RollbackManager.STATUS_SUCCESS) {
pw.println("Failure ["
+ result.getStringExtra(RollbackManager.EXTRA_STATUS_MESSAGE) + "]");
return 1;
}
+
+ if (rollback.isStaged() && stagedReadyTimeoutMs > 0) {
+ final int committedSessionId = rollback.getCommittedSessionId();
+ return doWaitForStagedSessionReady(committedSessionId, stagedReadyTimeoutMs, pw);
+ }
+
+ pw.println("Success");
+ return 0;
+
}
private void setParamsSize(InstallParams params, List<String> inPaths) {
@@ -1307,11 +1326,12 @@ class PackageManagerShellCommand extends ShellCommand {
}
abandonSession = false;
- if (!params.sessionParams.isStaged || !params.mWaitForStagedSessionReady) {
- pw.println("Success");
- return 0;
+ if (params.sessionParams.isStaged && params.stagedReadyTimeoutMs > 0) {
+ return doWaitForStagedSessionReady(sessionId, params.stagedReadyTimeoutMs, pw);
}
- return doWaitForStagedSessionRead(sessionId, params.timeoutMs, pw);
+
+ pw.println("Success");
+ return 0;
} finally {
if (abandonSession) {
try {
@@ -1322,11 +1342,9 @@ class PackageManagerShellCommand extends ShellCommand {
}
}
- private int doWaitForStagedSessionRead(int sessionId, long timeoutMs, PrintWriter pw)
+ private int doWaitForStagedSessionReady(int sessionId, long timeoutMs, PrintWriter pw)
throws RemoteException {
- if (timeoutMs <= 0) {
- timeoutMs = DEFAULT_WAIT_MS;
- }
+ Preconditions.checkArgument(timeoutMs > 0);
PackageInstaller.SessionInfo si = mInterface.getPackageInstaller()
.getSessionInfo(sessionId);
if (si == null) {
@@ -1376,25 +1394,14 @@ class PackageManagerShellCommand extends ShellCommand {
private int runInstallCommit() throws RemoteException {
final PrintWriter pw = getOutPrintWriter();
String opt;
- boolean waitForStagedSessionReady = true;
- long timeoutMs = -1;
+ long stagedReadyTimeoutMs = DEFAULT_STAGED_READY_TIMEOUT_MS;
while ((opt = getNextOption()) != null) {
switch (opt) {
- case "--wait-for-staged-ready":
- waitForStagedSessionReady = true;
- // If there is only one remaining argument, then it represents the sessionId, we
- // shouldn't try to parse it as timeoutMs.
- if (getRemainingArgsCount() > 1) {
- try {
- timeoutMs = Long.parseLong(peekNextArg());
- getNextArg();
- } catch (NumberFormatException ignore) {
- }
- }
- break;
- case "--no-wait":
- waitForStagedSessionReady = false;
+ case "--staged-ready-timeout":
+ stagedReadyTimeoutMs = Long.parseLong(getNextArgRequired());
break;
+ default:
+ throw new IllegalArgumentException("Unknown option: " + opt);
}
}
final int sessionId = Integer.parseInt(getNextArg());
@@ -1403,11 +1410,11 @@ class PackageManagerShellCommand extends ShellCommand {
}
final PackageInstaller.SessionInfo si = mInterface.getPackageInstaller()
.getSessionInfo(sessionId);
- if (si == null || !si.isStaged() || !waitForStagedSessionReady) {
- pw.println("Success");
- return 0;
+ if (si != null && si.isStaged() && stagedReadyTimeoutMs > 0) {
+ return doWaitForStagedSessionReady(sessionId, stagedReadyTimeoutMs, pw);
}
- return doWaitForStagedSessionRead(sessionId, timeoutMs, pw);
+ pw.println("Success");
+ return 0;
}
private int runInstallCreate() throws RemoteException {
@@ -2738,8 +2745,7 @@ class PackageManagerShellCommand extends ShellCommand {
SessionParams sessionParams;
String installerPackageName;
int userId = UserHandle.USER_ALL;
- boolean mWaitForStagedSessionReady = true;
- long timeoutMs = DEFAULT_WAIT_MS;
+ long stagedReadyTimeoutMs = DEFAULT_STAGED_READY_TIMEOUT_MS;
}
private InstallParams makeInstallParams() {
@@ -2868,16 +2874,8 @@ class PackageManagerShellCommand extends ShellCommand {
}
sessionParams.installFlags |= PackageManager.INSTALL_ENABLE_ROLLBACK;
break;
- case "--wait-for-staged-ready":
- params.mWaitForStagedSessionReady = true;
- try {
- params.timeoutMs = Long.parseLong(peekNextArg());
- getNextArg();
- } catch (NumberFormatException ignore) {
- }
- break;
- case "--no-wait":
- params.mWaitForStagedSessionReady = false;
+ case "--staged-ready-timeout":
+ params.stagedReadyTimeoutMs = Long.parseLong(getNextArgRequired());
break;
case "--skip-verification":
sessionParams.installFlags |= PackageManager.INSTALL_DISABLE_VERIFICATION;
@@ -3613,7 +3611,7 @@ class PackageManagerShellCommand extends ShellCommand {
pw.println(" [--preload] [--instant] [--full] [--dont-kill]");
pw.println(" [--enable-rollback]");
pw.println(" [--force-uuid internal|UUID] [--pkg PACKAGE] [-S BYTES]");
- pw.println(" [--apex] [--wait-for-staged-ready TIMEOUT]");
+ pw.println(" [--apex] [--staged-ready-timeout TIMEOUT]");
pw.println(" [PATH [SPLIT...]|-]");
pw.println(" Install an application. Must provide the apk data to install, either as");
pw.println(" file path(s) or '-' to read from stdin. Options are:");
@@ -3641,9 +3639,11 @@ class PackageManagerShellCommand extends ShellCommand {
pw.println(" 3=device setup, 4=user request");
pw.println(" --force-uuid: force install on to disk volume with given UUID");
pw.println(" --apex: install an .apex file, not an .apk");
- pw.println(" --wait-for-staged-ready: when performing staged install, wait TIMEOUT");
- pw.println(" ms for pre-reboot verification to complete. If TIMEOUT is not");
- pw.println(" specified it will wait for " + DEFAULT_WAIT_MS + " milliseconds.");
+ pw.println(" --staged-ready-timeout: By default, staged sessions wait "
+ + DEFAULT_STAGED_READY_TIMEOUT_MS);
+ pw.println(" milliseconds for pre-reboot verification to complete when");
+ pw.println(" performing staged install. This flag is used to alter the waiting");
+ pw.println(" time. You can skip the waiting time by specifying a TIMEOUT of '0'");
pw.println("");
pw.println(" install-existing [--user USER_ID|all|current]");
pw.println(" [--instant] [--full] [--wait] [--restrict-permissions] PACKAGE");
diff --git a/services/core/java/com/android/server/pm/ShortcutService.java b/services/core/java/com/android/server/pm/ShortcutService.java
index 700f7be83e15..8412077d9a11 100644
--- a/services/core/java/com/android/server/pm/ShortcutService.java
+++ b/services/core/java/com/android/server/pm/ShortcutService.java
@@ -3301,7 +3301,7 @@ public class ShortcutService extends IShortcutService.Stub {
final long token = Binder.clearCallingIdentity();
try {
- int packageUid = mPackageManagerInternal.getPackageUidInternal(packageName,
+ int packageUid = mPackageManagerInternal.getPackageUid(packageName,
PackageManager.MATCH_DIRECT_BOOT_AUTO, userId);
// Grant read uri permission to the caller on behalf of the shortcut owner. All
// granted permissions are revoked when the default launcher changes, or when
diff --git a/services/core/java/com/android/server/pm/StagingManager.java b/services/core/java/com/android/server/pm/StagingManager.java
index 105a9b06cf42..0c4eaec32ba5 100644
--- a/services/core/java/com/android/server/pm/StagingManager.java
+++ b/services/core/java/com/android/server/pm/StagingManager.java
@@ -88,7 +88,6 @@ import java.util.List;
import java.util.Set;
import java.util.concurrent.LinkedBlockingQueue;
import java.util.concurrent.TimeUnit;
-import java.util.function.Consumer;
import java.util.function.Predicate;
import java.util.function.Supplier;
@@ -189,7 +188,6 @@ public class StagingManager {
* Validates the signature used to sign the container of the new apex package
*
* @param newApexPkg The new apex package that is being installed
- * @throws PackageManagerException
*/
private void validateApexSignature(PackageInfo newApexPkg)
throws PackageManagerException {
@@ -725,12 +723,9 @@ public class StagingManager {
return ret;
}
- @NonNull
private PackageInstallerSession createAndWriteApkSession(
- @NonNull PackageInstallerSession originalSession, boolean preReboot)
- throws PackageManagerException {
- final int errorCode = preReboot ? SessionInfo.STAGED_SESSION_VERIFICATION_FAILED
- : SessionInfo.STAGED_SESSION_ACTIVATION_FAILED;
+ PackageInstallerSession originalSession) throws PackageManagerException {
+ final int errorCode = SessionInfo.STAGED_SESSION_ACTIVATION_FAILED;
if (originalSession.stageDir == null) {
Slog.wtf(TAG, "Attempting to install a staged APK session with no staging dir");
throw new PackageManagerException(errorCode,
@@ -746,12 +741,7 @@ public class StagingManager {
PackageInstaller.SessionParams params = originalSession.params.copy();
params.isStaged = false;
params.installFlags |= PackageManager.INSTALL_STAGED;
- if (preReboot) {
- params.installFlags &= ~PackageManager.INSTALL_ENABLE_ROLLBACK;
- params.installFlags |= PackageManager.INSTALL_DRY_RUN;
- } else {
- params.installFlags |= PackageManager.INSTALL_DISABLE_VERIFICATION;
- }
+ params.installFlags |= PackageManager.INSTALL_DISABLE_VERIFICATION;
try {
int apkSessionId = mPi.createSession(
params, originalSession.getInstallerPackageName(),
@@ -783,12 +773,10 @@ public class StagingManager {
* apks in the given session. Only parent session is returned for multi-package session.
*/
@Nullable
- private PackageInstallerSession extractApksInSession(PackageInstallerSession session,
- boolean preReboot) throws PackageManagerException {
- final int errorCode = preReboot ? SessionInfo.STAGED_SESSION_VERIFICATION_FAILED
- : SessionInfo.STAGED_SESSION_ACTIVATION_FAILED;
+ private PackageInstallerSession extractApksInSession(PackageInstallerSession session)
+ throws PackageManagerException {
if (!session.isMultiPackage() && !isApexSession(session)) {
- return createAndWriteApkSession(session, preReboot);
+ return createAndWriteApkSession(session);
} else if (session.isMultiPackage()) {
// For multi-package staged sessions containing APKs, we identify which child sessions
// contain an APK, and with those then create a new multi-package group of sessions,
@@ -810,10 +798,6 @@ public class StagingManager {
}
final PackageInstaller.SessionParams params = session.params.copy();
params.isStaged = false;
- if (preReboot) {
- params.installFlags &= ~PackageManager.INSTALL_ENABLE_ROLLBACK;
- params.installFlags |= PackageManager.INSTALL_DRY_RUN;
- }
final int apkParentSessionId = mPi.createSession(
params, session.getInstallerPackageName(), session.getInstallerAttributionTag(),
session.userId);
@@ -823,18 +807,18 @@ public class StagingManager {
} catch (IOException e) {
Slog.e(TAG, "Unable to prepare multi-package session for staged session "
+ session.sessionId);
- throw new PackageManagerException(errorCode,
+ throw new PackageManagerException(SessionInfo.STAGED_SESSION_ACTIVATION_FAILED,
"Unable to prepare multi-package session for staged session");
}
for (int i = 0, size = childSessions.size(); i < size; i++) {
final PackageInstallerSession apkChildSession = createAndWriteApkSession(
- childSessions.get(i), preReboot);
+ childSessions.get(i));
try {
apkParentSession.addChildSessionId(apkChildSession.sessionId);
} catch (IllegalStateException e) {
Slog.e(TAG, "Failed to add a child session for installing the APK files", e);
- throw new PackageManagerException(errorCode,
+ throw new PackageManagerException(SessionInfo.STAGED_SESSION_ACTIVATION_FAILED,
"Failed to add a child session " + apkChildSession.sessionId);
}
}
@@ -877,11 +861,9 @@ public class StagingManager {
}
}
- private void installApksInSession(@NonNull PackageInstallerSession session)
+ private void installApksInSession(PackageInstallerSession session)
throws PackageManagerException {
-
- final PackageInstallerSession apksToInstall = extractApksInSession(
- session, /* preReboot */ false);
+ final PackageInstallerSession apksToInstall = extractApksInSession(session);
if (apksToInstall == null) {
return;
}
@@ -1047,7 +1029,7 @@ public class StagingManager {
/**
* <p>Abort committed staged session
*
- * <p>This method must be called while holding {@link PackageInstallerSession.mLock}.
+ * <p>This method must be called while holding {@link PackageInstallerSession#mLock}.
*
* <p>The method returns {@code false} to indicate it is not safe to clean up the session from
* system yet. When it is safe, the method returns {@code true}.
@@ -1218,7 +1200,7 @@ public class StagingManager {
}
}
- void markStagedSessionsAsSuccessful() {
+ private void markStagedSessionsAsSuccessful() {
synchronized (mSuccessfulStagedSessionIds) {
for (int i = 0; i < mSuccessfulStagedSessionIds.size(); i++) {
mApexManager.markStagedSessionSuccessful(mSuccessfulStagedSessionIds.get(i));
@@ -1242,30 +1224,10 @@ public class StagingManager {
mFailureReasonFile.delete();
}
- private static class LocalIntentReceiverAsync {
- final Consumer<Intent> mConsumer;
-
- LocalIntentReceiverAsync(Consumer<Intent> consumer) {
- mConsumer = consumer;
- }
-
- private IIntentSender.Stub mLocalSender = new IIntentSender.Stub() {
- @Override
- public void send(int code, Intent intent, String resolvedType, IBinder whitelistToken,
- IIntentReceiver finishedReceiver, String requiredPermission, Bundle options) {
- mConsumer.accept(intent);
- }
- };
-
- public IntentSender getIntentSender() {
- return new IntentSender((IIntentSender) mLocalSender);
- }
- }
-
private static class LocalIntentReceiverSync {
private final LinkedBlockingQueue<Intent> mResult = new LinkedBlockingQueue<>();
- private IIntentSender.Stub mLocalSender = new IIntentSender.Stub() {
+ private final IIntentSender.Stub mLocalSender = new IIntentSender.Stub() {
@Override
public void send(int code, Intent intent, String resolvedType, IBinder whitelistToken,
IIntentReceiver finishedReceiver, String requiredPermission,
@@ -1299,6 +1261,20 @@ public class StagingManager {
return session;
}
+ // TODO(b/136257624): Temporary API to let PMS communicate with StagingManager. When all
+ // verification logic is extracted out of StagingManager into PMS, we can remove
+ // this.
+ void notifyVerificationComplete(int sessionId) {
+ mPreRebootVerificationHandler.onPreRebootVerificationComplete(sessionId);
+ }
+
+ // TODO(b/136257624): Temporary API to let PMS communicate with StagingManager. When all
+ // verification logic is extracted out of StagingManager into PMS, we can remove
+ // this.
+ void notifyPreRebootVerification_Apk_Complete(int sessionId) {
+ mPreRebootVerificationHandler.notifyPreRebootVerification_Apk_Complete(sessionId);
+ }
+
private final class PreRebootVerificationHandler extends Handler {
// Hold session ids before handler gets ready to do the verification.
private IntArray mPendingSessionIds;
@@ -1500,54 +1476,16 @@ public class StagingManager {
}
/**
- * Pre-reboot verification state for apk files:
- * <p><ul>
- * <li>performs a dry-run install of apk</li>
- * </ul></p>
+ * Pre-reboot verification state for apk files. Session is sent to
+ * {@link PackageManagerService} for verification and it notifies back the result via
+ * {@link #notifyPreRebootVerification_Apk_Complete(int)}
*/
private void handlePreRebootVerification_Apk(@NonNull PackageInstallerSession session) {
if (!sessionContainsApk(session)) {
notifyPreRebootVerification_Apk_Complete(session.sessionId);
return;
}
-
- try {
- Slog.d(TAG, "Running a pre-reboot verification for APKs in session "
- + session.sessionId + " by performing a dry-run install");
- // verifyApksInSession will notify the handler when APK verification is complete
- verifyApksInSession(session);
- } catch (PackageManagerException e) {
- onPreRebootVerificationFailure(session, e.error, e.getMessage());
- }
- }
-
- private void verifyApksInSession(PackageInstallerSession session)
- throws PackageManagerException {
-
- final PackageInstallerSession apksToVerify = extractApksInSession(
- session, /* preReboot */ true);
- if (apksToVerify == null) {
- return;
- }
-
- final LocalIntentReceiverAsync receiver = new LocalIntentReceiverAsync(
- (Intent result) -> {
- final int status = result.getIntExtra(PackageInstaller.EXTRA_STATUS,
- PackageInstaller.STATUS_FAILURE);
- if (status != PackageInstaller.STATUS_SUCCESS) {
- final String errorMessage = result.getStringExtra(
- PackageInstaller.EXTRA_STATUS_MESSAGE);
- Slog.e(TAG, "Failure to verify APK staged session "
- + session.sessionId + " [" + errorMessage + "]");
- onPreRebootVerificationFailure(session,
- SessionInfo.STAGED_SESSION_ACTIVATION_FAILED, errorMessage);
- return;
- }
- mPreRebootVerificationHandler.notifyPreRebootVerification_Apk_Complete(
- session.sessionId);
- });
-
- apksToVerify.commit(receiver.getIntentSender(), false);
+ session.verifyStagedSession();
}
/**
diff --git a/services/core/java/com/android/server/pm/TEST_MAPPING b/services/core/java/com/android/server/pm/TEST_MAPPING
index dbe96e63d978..485868237895 100644
--- a/services/core/java/com/android/server/pm/TEST_MAPPING
+++ b/services/core/java/com/android/server/pm/TEST_MAPPING
@@ -33,6 +33,9 @@
"name": "CtsContentTestCases",
"options": [
{
+ "include-filter": "android.content.pm.cts.ChecksumsTest"
+ },
+ {
"include-filter": "android.content.pm.cts.PackageManagerShellCommandTest"
},
{
diff --git a/services/core/java/com/android/server/pm/UserManagerService.java b/services/core/java/com/android/server/pm/UserManagerService.java
index c1aebd33889c..6ecaab6692a2 100644
--- a/services/core/java/com/android/server/pm/UserManagerService.java
+++ b/services/core/java/com/android/server/pm/UserManagerService.java
@@ -84,7 +84,6 @@ import android.os.storage.StorageManager;
import android.security.GateKeeper;
import android.service.gatekeeper.IGateKeeperService;
import android.stats.devicepolicy.DevicePolicyEnums;
-import android.text.TextUtils;
import android.util.ArrayMap;
import android.util.ArraySet;
import android.util.AtomicFile;
@@ -142,6 +141,7 @@ import java.util.List;
import java.util.Objects;
import java.util.Set;
import java.util.concurrent.ThreadLocalRandom;
+import java.util.concurrent.atomic.AtomicInteger;
/**
* Service for {@link UserManager}.
@@ -159,10 +159,6 @@ public class UserManagerService extends IUserManager.Stub {
private static final String LOG_TAG = "UserManagerService";
static final boolean DBG = false; // DO NOT SUBMIT WITH TRUE
private static final boolean DBG_WITH_STACKTRACE = false; // DO NOT SUBMIT WITH TRUE
-
- // TODO(b/164159026): remove once owner_name issue on automotive is fixed
- // Can be used to track getUsers() / userWithNameLU() behavior
- public static final boolean DBG_CACHED_USERINFOS = false; // DO NOT SUBMIT WITH TRUE
// Can be used for manual testing of id recycling
private static final boolean RELEASE_DELETED_USER_ID = false; // DO NOT SUBMIT WITH TRUE
@@ -276,25 +272,6 @@ public class UserManagerService extends IUserManager.Stub {
private DevicePolicyManagerInternal mDevicePolicyManagerInternal;
/**
- * Reference to the {@link UserHandle#SYSTEM} user's UserInfo; it's {@code name} was either
- * manually set, or it's {@code null}.
- *
- * <p>The reference is set just once, but it's {@code name} is updated when it's manually set.
- */
- @GuardedBy("mUsersLock")
- private UserInfo mSystemUserInfo;
-
- /**
- * Reference to the {@link UserHandle#SYSTEM} user's UserInfo, with its {@code name} set to
- * the localized value of {@code owner_name}.
- *
- * <p>The reference is set just once, but it's {@code name} is updated everytime the reference
- * is used and the locale changed.
- */
- @GuardedBy("mUsersLock")
- private UserInfo mSystemUserInfoWithName;
-
- /**
* Internal non-parcelable wrapper for UserInfo that is not exposed to other system apps.
*/
@VisibleForTesting
@@ -430,6 +407,10 @@ public class UserManagerService extends IUserManager.Stub {
@GuardedBy("mUsersLock")
private int[] mUserIds;
+
+ @GuardedBy("mUsersLock")
+ private int[] mUserIdsIncludingPreCreated;
+
@GuardedBy("mPackagesLock")
private int mNextSerialNumber;
private int mUserVersion = 0;
@@ -467,6 +448,11 @@ public class UserManagerService extends IUserManager.Stub {
}
};
+ // TODO(b/161915546): remove once userWithName() is fixed / removed
+ // Use to debug / dump when user 0 is allocated at userWithName()
+ public static final boolean DBG_ALLOCATION = false; // DO NOT SUBMIT WITH TRUE
+ public final AtomicInteger mUser0Allocations;
+
/**
* Start an {@link IntentSender} when user is unlocked after disabling quiet mode.
*
@@ -656,6 +642,7 @@ public class UserManagerService extends IUserManager.Stub {
LocalServices.addService(UserManagerInternal.class, mLocalService);
mLockPatternUtils = new LockPatternUtils(mContext);
mUserStates.put(UserHandle.USER_SYSTEM, UserState.STATE_BOOTING);
+ mUser0Allocations = DBG_ALLOCATION ? new AtomicInteger() : null;
}
void systemReady() {
@@ -777,6 +764,8 @@ public class UserManagerService extends IUserManager.Stub {
return null;
}
+ // TODO(b/157921703): replace by getAliveUsers() or remove (so callers
+ // explicitly call the 3-booleans version)
public @NonNull List<UserInfo> getUsers(boolean excludeDying) {
return getUsers(/*excludePartial= */ true, excludeDying, /* excludePreCreated= */
true);
@@ -801,7 +790,7 @@ public class UserManagerService extends IUserManager.Stub {
|| (excludePreCreated && ui.preCreated)) {
continue;
}
- users.add(userWithNameLU(ui));
+ users.add(userWithName(ui));
}
return users;
}
@@ -870,7 +859,7 @@ public class UserManagerService extends IUserManager.Stub {
userInfo.name = null;
userInfo.iconPath = null;
} else {
- userInfo = userWithNameLU(userInfo);
+ userInfo = userWithName(userInfo);
}
users.add(userInfo);
}
@@ -1327,57 +1316,26 @@ public class UserManagerService extends IUserManager.Stub {
public UserInfo getUserInfo(@UserIdInt int userId) {
checkManageOrCreateUsersPermission("query user");
synchronized (mUsersLock) {
- return userWithNameLU(getUserInfoLU(userId));
+ return userWithName(getUserInfoLU(userId));
}
}
/**
* Returns a UserInfo object with the name filled in, for Owner, or the original
* if the name is already set.
- *
- * <p>Note:</p> the Owner name is localized, so the current value must be checked every time
- * this method is called.
*/
- private UserInfo userWithNameLU(UserInfo orig) {
- // Only the system user uses the owner_name string.
- if (orig == null || orig.id != UserHandle.USER_SYSTEM) return orig;
-
- if (mSystemUserInfo == null) {
- mSystemUserInfo = orig;
- if (DBG_CACHED_USERINFOS) {
- Slog.d(LOG_TAG, "Set mSystemUserInfo:" + mSystemUserInfo.toFullString());
- }
- }
-
- if (mSystemUserInfo.name != null) {
- if (DBG_CACHED_USERINFOS) {
- Slog.v(LOG_TAG, "Returning mSystemUserInfo: " + mSystemUserInfo.toFullString());
- }
- return mSystemUserInfo;
- }
-
- final String ownerName = getOwnerName();
-
- if (mSystemUserInfoWithName == null) {
- mSystemUserInfoWithName = new UserInfo(orig);
- mSystemUserInfoWithName.name = ownerName;
- if (DBG_CACHED_USERINFOS) {
- Slog.d(LOG_TAG, "Set mSystemUserInfoWithName: "
- + mSystemUserInfoWithName.toFullString());
- }
- } else if (!TextUtils.equals(ownerName, mSystemUserInfoWithName.name)) {
- if (DBG_CACHED_USERINFOS) {
- Slog.d(LOG_TAG, "Updating mSystemUserInfoWithName.name from "
- + mSystemUserInfoWithName.name + " to " + ownerName);
- }
- mSystemUserInfoWithName.name = ownerName;
- }
-
- if (DBG_CACHED_USERINFOS) {
- Slog.v(LOG_TAG, "Returning mSystemUserInfoWithName:"
- + mSystemUserInfoWithName.toFullString());
+ private UserInfo userWithName(UserInfo orig) {
+ if (orig != null && orig.name == null && orig.id == UserHandle.USER_SYSTEM) {
+ if (DBG_ALLOCATION) {
+ final int number = mUser0Allocations.incrementAndGet();
+ Slog.w(LOG_TAG, "System user instantiated at least " + number + " times");
+ }
+ UserInfo withName = new UserInfo(orig);
+ withName.name = getOwnerName();
+ return withName;
+ } else {
+ return orig;
}
- return mSystemUserInfoWithName;
}
/** Returns whether the given user type is one of the FULL user types. */
@@ -1530,7 +1488,7 @@ public class UserManagerService extends IUserManager.Stub {
}
final int userId = UserHandle.getUserId(Binder.getCallingUid());
synchronized (mUsersLock) {
- UserInfo userInfo = userWithNameLU(getUserInfoLU(userId));
+ UserInfo userInfo = userWithName(getUserInfoLU(userId));
return userInfo == null ? "" : userInfo.name;
}
}
@@ -1645,13 +1603,6 @@ public class UserManagerService extends IUserManager.Stub {
Slog.w(LOG_TAG, "getUserInfo: unknown user #" + userId);
return null;
}
-
- if (DBG_CACHED_USERINFOS && userId == UserHandle.USER_SYSTEM && userData != null
- && userData.info != mSystemUserInfo) {
- Slog.wtf(LOG_TAG, "getUserInfoLU(): system user on userData (" + userData.info
- + ") is not the same as mSystemUserInfo (" + mSystemUserInfo + ")");
- }
-
return userData != null ? userData.info : null;
}
@@ -2549,16 +2500,35 @@ public class UserManagerService extends IUserManager.Stub {
}
/**
- * Returns an array of user ids. This array is cached here for quick access, so do not modify or
- * cache it elsewhere.
+ * Returns an array of user ids.
+ *
+ * <p>This array is cached here for quick access, so do not modify or cache it elsewhere.
+ *
* @return the array of user ids.
*/
- public int[] getUserIds() {
+ public @NonNull int[] getUserIds() {
synchronized (mUsersLock) {
return mUserIds;
}
}
+ /**
+ * Returns an array of user ids, including pre-created users.
+ *
+ * <p>This method should only used for the specific cases that need to handle pre-created users;
+ * most callers should call {@link #getUserIds()} instead.
+ *
+ * <p>This array is cached here for quick access, so do not modify or
+ * cache it elsewhere.
+ *
+ * @return the array of user ids.
+ */
+ public @NonNull int[] getUserIdsIncludingPreCreated() {
+ synchronized (mUsersLock) {
+ return mUserIdsIncludingPreCreated;
+ }
+ }
+
@GuardedBy({"mRestrictionsLock", "mPackagesLock"})
private void readUserListLP() {
if (!mUserListFile.exists()) {
@@ -4414,23 +4384,43 @@ public class UserManagerService extends IUserManager.Stub {
*/
private void updateUserIds() {
int num = 0;
+ int numIncludingPreCreated = 0;
synchronized (mUsersLock) {
final int userSize = mUsers.size();
for (int i = 0; i < userSize; i++) {
- UserInfo userInfo = mUsers.valueAt(i).info;
- if (!userInfo.partial && !userInfo.preCreated) {
- num++;
+ final UserInfo userInfo = mUsers.valueAt(i).info;
+ if (!userInfo.partial) {
+ numIncludingPreCreated++;
+ if (!userInfo.preCreated) {
+ num++;
+ }
}
}
+ if (DBG) {
+ Slog.d(LOG_TAG, "updateUserIds(): numberUsers= " + num
+ + " includingPreCreated=" + numIncludingPreCreated);
+ }
final int[] newUsers = new int[num];
+ final int[] newUsersIncludingPreCreated = new int[numIncludingPreCreated];
+
int n = 0;
+ int nIncludingPreCreated = 0;
for (int i = 0; i < userSize; i++) {
- UserInfo userInfo = mUsers.valueAt(i).info;
- if (!userInfo.partial && !userInfo.preCreated) {
- newUsers[n++] = mUsers.keyAt(i);
+ final UserInfo userInfo = mUsers.valueAt(i).info;
+ if (!userInfo.partial) {
+ final int userId = mUsers.keyAt(i);
+ newUsersIncludingPreCreated[nIncludingPreCreated++] = userId;
+ if (!userInfo.preCreated) {
+ newUsers[n++] = userId;
+ }
}
}
mUserIds = newUsers;
+ mUserIdsIncludingPreCreated = newUsersIncludingPreCreated;
+ if (DBG) {
+ Slog.d(LOG_TAG, "updateUserIds(): userIds= " + Arrays.toString(mUserIds)
+ + " includingPreCreated=" + Arrays.toString(mUserIdsIncludingPreCreated));
+ }
}
}
@@ -4894,6 +4884,8 @@ public class UserManagerService extends IUserManager.Stub {
synchronized (mUsersLock) {
pw.print(" Cached user IDs: ");
pw.println(Arrays.toString(mUserIds));
+ pw.print(" Cached user IDs (including pre-created): ");
+ pw.println(Arrays.toString(mUserIdsIncludingPreCreated));
}
} // synchronized (mPackagesLock)
@@ -4910,15 +4902,8 @@ public class UserManagerService extends IUserManager.Stub {
pw.println(" Is headless-system mode: " + UserManager.isHeadlessSystemUserMode());
pw.println(" User version: " + mUserVersion);
pw.println(" Owner name: " + getOwnerName());
- if (mSystemUserInfo == null) {
- pw.println(" (mSystemUserInfo not set)");
- } else {
- pw.println(" System user: " + mSystemUserInfo.toFullString());
- }
- if (mSystemUserInfoWithName == null) {
- pw.println(" (mSystemUserInfoWithName not set)");
- } else {
- pw.println(" System user (with name): " + mSystemUserInfoWithName.toFullString());
+ if (DBG_ALLOCATION) {
+ pw.println(" System user allocations: " + mUser0Allocations.get());
}
// Dump UserTypes
diff --git a/services/core/java/com/android/server/pm/permission/DefaultPermissionGrantPolicy.java b/services/core/java/com/android/server/pm/permission/DefaultPermissionGrantPolicy.java
index 75a88e2e04b6..f7721a4d6f22 100644
--- a/services/core/java/com/android/server/pm/permission/DefaultPermissionGrantPolicy.java
+++ b/services/core/java/com/android/server/pm/permission/DefaultPermissionGrantPolicy.java
@@ -414,17 +414,14 @@ public final class DefaultPermissionGrantPolicy {
if (pkg == null
|| !doesPackageSupportRuntimePermissions(pkg)
|| ArrayUtils.isEmpty(pkg.requestedPermissions)
- || !pkg.applicationInfo.isPrivilegedApp()) {
+ || !pm.isGranted(Manifest.permission.READ_PRIVILEGED_PHONE_STATE,
+ pkg, UserHandle.of(userId))) {
continue;
}
- for (String permission : pkg.requestedPermissions) {
- if (Manifest.permission.READ_PRIVILEGED_PHONE_STATE.equals(permission)) {
- grantRuntimePermissions(pm, pkg,
- Collections.singleton(Manifest.permission.READ_PHONE_STATE),
- true, // systemFixed
- userId);
- }
- }
+ grantRuntimePermissions(pm, pkg,
+ Collections.singleton(Manifest.permission.READ_PHONE_STATE),
+ true, // systemFixed
+ userId);
}
}
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 f5dd918a18f3..ffdcc227b7f1 100644
--- a/services/core/java/com/android/server/pm/permission/PermissionManagerService.java
+++ b/services/core/java/com/android/server/pm/permission/PermissionManagerService.java
@@ -83,7 +83,6 @@ import android.content.pm.PackageParser;
import android.content.pm.ParceledListSlice;
import android.content.pm.PermissionGroupInfo;
import android.content.pm.PermissionInfo;
-import android.content.pm.UserInfo;
import android.content.pm.parsing.component.ParsedPermission;
import android.content.pm.parsing.component.ParsedPermissionGroup;
import android.content.pm.permission.SplitPermissionInfoParcelable;
@@ -121,7 +120,6 @@ import android.util.Log;
import android.util.Slog;
import android.util.SparseArray;
import android.util.SparseBooleanArray;
-import android.util.TimingsTraceLog;
import com.android.internal.annotations.GuardedBy;
import com.android.internal.annotations.VisibleForTesting;
@@ -3146,17 +3144,7 @@ public class PermissionManagerService extends IPermissionManager.Stub {
* @return user ids for created users and pre-created users
*/
private int[] getAllUserIds() {
- final TimingsTraceLog t = new TimingsTraceLog(TAG, Trace.TRACE_TAG_SYSTEM_SERVER);
- t.traceBegin("getAllUserIds");
- List<UserInfo> users = UserManagerService.getInstance().getUsers(
- /*excludePartial=*/ true, /*excludeDying=*/ true, /*excludePreCreated=*/ false);
- int size = users.size();
- final int[] userIds = new int[size];
- for (int i = 0; i < size; i++) {
- userIds[i] = users.get(i).id;
- }
- t.traceEnd();
- return userIds;
+ return UserManagerService.getInstance().getUserIdsIncludingPreCreated();
}
/**
diff --git a/services/core/java/com/android/server/policy/PhoneWindowManager.java b/services/core/java/com/android/server/policy/PhoneWindowManager.java
index 548cd70de4d1..d01a30fbd818 100644
--- a/services/core/java/com/android/server/policy/PhoneWindowManager.java
+++ b/services/core/java/com/android/server/policy/PhoneWindowManager.java
@@ -69,6 +69,7 @@ import static android.view.WindowManager.TAKE_SCREENSHOT_SELECTED_REGION;
import static android.view.WindowManagerGlobal.ADD_OKAY;
import static android.view.WindowManagerGlobal.ADD_PERMISSION_DENIED;
+import static com.android.internal.config.sysui.SystemUiDeviceConfigFlags.SCREENSHOT_KEYCHORD_DELAY;
import static com.android.server.policy.WindowManagerPolicy.WindowManagerFuncs.CAMERA_LENS_COVERED;
import static com.android.server.policy.WindowManagerPolicy.WindowManagerFuncs.CAMERA_LENS_COVER_ABSENT;
import static com.android.server.policy.WindowManagerPolicy.WindowManagerFuncs.CAMERA_LENS_UNCOVERED;
@@ -148,6 +149,7 @@ import android.os.UEventObserver;
import android.os.UserHandle;
import android.os.VibrationEffect;
import android.os.Vibrator;
+import android.provider.DeviceConfig;
import android.provider.MediaStore;
import android.provider.Settings;
import android.service.dreams.DreamManagerInternal;
@@ -1378,12 +1380,14 @@ public class PhoneWindowManager implements WindowManagerPolicy {
}
private long getScreenshotChordLongPressDelay() {
+ long delayMs = DeviceConfig.getLong(
+ DeviceConfig.NAMESPACE_SYSTEMUI, SCREENSHOT_KEYCHORD_DELAY,
+ ViewConfiguration.get(mContext).getScreenshotChordKeyTimeout());
if (mKeyguardDelegate.isShowing()) {
// Double the time it takes to take a screenshot from the keyguard
- return (long) (KEYGUARD_SCREENSHOT_CHORD_DELAY_MULTIPLIER *
- ViewConfiguration.get(mContext).getScreenshotChordKeyTimeout());
+ return (long) (KEYGUARD_SCREENSHOT_CHORD_DELAY_MULTIPLIER * delayMs);
}
- return ViewConfiguration.get(mContext).getScreenshotChordKeyTimeout();
+ return delayMs;
}
private long getRingerToggleChordDelay() {
@@ -2219,11 +2223,6 @@ public class PhoneWindowManager implements WindowManagerPolicy {
}
@Override
- public int getMaxWallpaperLayer() {
- return getWindowLayerFromTypeLw(TYPE_NOTIFICATION_SHADE);
- }
-
- @Override
public boolean isKeyguardHostWindow(WindowManager.LayoutParams attrs) {
return attrs.type == TYPE_NOTIFICATION_SHADE;
}
@@ -5324,15 +5323,6 @@ public class PhoneWindowManager implements WindowManagerPolicy {
}
@Override
- public boolean isTopLevelWindow(int windowType) {
- if (windowType >= WindowManager.LayoutParams.FIRST_SUB_WINDOW
- && windowType <= WindowManager.LayoutParams.LAST_SUB_WINDOW) {
- return (windowType == WindowManager.LayoutParams.TYPE_APPLICATION_ATTACHED_DIALOG);
- }
- return true;
- }
-
- @Override
public void dumpDebug(ProtoOutputStream proto, long fieldId) {
final long token = proto.start(fieldId);
proto.write(ROTATION_MODE, mDefaultDisplayRotation.getUserRotationMode());
diff --git a/services/core/java/com/android/server/policy/WindowManagerPolicy.java b/services/core/java/com/android/server/policy/WindowManagerPolicy.java
index 651eafd77fe7..b96d65cb7433 100644
--- a/services/core/java/com/android/server/policy/WindowManagerPolicy.java
+++ b/services/core/java/com/android/server/policy/WindowManagerPolicy.java
@@ -67,7 +67,6 @@ import static java.lang.annotation.RetentionPolicy.SOURCE;
import android.annotation.IntDef;
import android.annotation.NonNull;
import android.annotation.Nullable;
-import android.app.WindowConfiguration;
import android.content.Context;
import android.content.res.CompatibilityInfo;
import android.content.res.Configuration;
@@ -90,7 +89,6 @@ import android.view.animation.Animation;
import com.android.internal.policy.IKeyguardDismissCallback;
import com.android.internal.policy.IShortcutService;
import com.android.server.wm.DisplayRotation;
-import com.android.server.wm.WindowFrames;
import java.io.PrintWriter;
import java.lang.annotation.Retention;
@@ -181,92 +179,11 @@ public interface WindowManagerPolicy extends WindowManagerPolicyConstants {
*/
public interface WindowState {
/**
- * Return the uid of the app that owns this window.
- */
- int getOwningUid();
-
- /**
* Return the package name of the app that owns this window.
*/
String getOwningPackage();
/**
- * Perform standard frame computation. The result can be obtained with
- * getFrame() if so desired. Must be called with the window manager
- * lock held.
- *
- */
- public void computeFrameLw();
-
- /**
- * Retrieve the current frame of the window that has been assigned by
- * the window manager. Must be called with the window manager lock held.
- *
- * @return Rect The rectangle holding the window frame.
- */
- public Rect getFrameLw();
-
- /**
- * Retrieve the frame of the display that this window was last
- * laid out in. Must be called with the
- * window manager lock held.
- *
- * @return Rect The rectangle holding the display frame.
- */
- public Rect getDisplayFrameLw();
-
- /**
- * Retrieve the frame of the content area that this window was last
- * laid out in. This is the area in which the content of the window
- * should be placed. It will be smaller than the display frame to
- * account for screen decorations such as a status bar or soft
- * keyboard. Must be called with the
- * window manager lock held.
- *
- * @return Rect The rectangle holding the content frame.
- */
- public Rect getContentFrameLw();
-
- /**
- * Retrieve the frame of the visible area that this window was last
- * laid out in. This is the area of the screen in which the window
- * will actually be fully visible. It will be smaller than the
- * content frame to account for transient UI elements blocking it
- * such as an input method's candidates UI. Must be called with the
- * window manager lock held.
- *
- * @return Rect The rectangle holding the visible frame.
- */
- public Rect getVisibleFrameLw();
-
- /**
- * Returns true if this window is waiting to receive its given
- * internal insets from the client app, and so should not impact the
- * layout of other windows.
- */
- public boolean getGivenInsetsPendingLw();
-
- /**
- * Retrieve the insets given by this window's client for the content
- * area of windows behind it. Must be called with the
- * window manager lock held.
- *
- * @return Rect The left, top, right, and bottom insets, relative
- * to the window's frame, of the actual contents.
- */
- public Rect getGivenContentInsetsLw();
-
- /**
- * Retrieve the insets given by this window's client for the visible
- * area of windows behind it. Must be called with the
- * window manager lock held.
- *
- * @return Rect The left, top, right, and bottom insets, relative
- * to the window's frame, of the actual visible area.
- */
- public Rect getGivenVisibleInsetsLw();
-
- /**
* Retrieve the current LayoutParams of the window.
*
* @return WindowManager.LayoutParams The window's internal LayoutParams
@@ -275,17 +192,6 @@ public interface WindowManagerPolicy extends WindowManagerPolicyConstants {
public WindowManager.LayoutParams getAttrs();
/**
- * Retrieve the current system UI visibility flags associated with
- * this window.
- */
- public int getSystemUiVisibility();
-
- /**
- * Get the layer at which this window's surface will be Z-ordered.
- */
- public int getSurfaceLayer();
-
- /**
* Retrieve the type of the top-level window.
*
* @return the base type of the parent window if attached or its own type otherwise
@@ -301,22 +207,6 @@ public interface WindowManagerPolicy extends WindowManagerPolicyConstants {
public IApplicationToken getAppToken();
/**
- * Return true if this window is participating in voice interaction.
- */
- public boolean isVoiceInteraction();
-
- /**
- * Return true if, at any point, the application token associated with
- * this window has actually displayed any windows. This is most useful
- * with the "starting up" window to determine if any windows were
- * displayed when it is closed.
- *
- * @return Returns true if one or more windows have been displayed,
- * else false.
- */
- public boolean hasAppShownWindows();
-
- /**
* Is this window visible? It is not visible if there is no
* surface, or we are in the process of running an exit animation
* that will remove the surface.
@@ -324,42 +214,12 @@ public interface WindowManagerPolicy extends WindowManagerPolicyConstants {
boolean isVisibleLw();
/**
- * Is this window currently visible to the user on-screen? It is
- * displayed either if it is visible or it is currently running an
- * animation before no longer being visible. Must be called with the
- * window manager lock held.
- */
- boolean isDisplayedLw();
-
- /**
* Return true if this window (or a window it is attached to, but not
* considering its app token) is currently animating.
*/
boolean isAnimatingLw();
/**
- * Is this window considered to be gone for purposes of layout?
- */
- boolean isGoneForLayoutLw();
-
- /**
- * Returns true if the window has a surface that it has drawn a
- * complete UI in to. Note that this is different from {@link #hasDrawnLw()}
- * in that it also returns true if the window is READY_TO_SHOW, but was not yet
- * promoted to HAS_DRAWN.
- */
- boolean isDrawnLw();
-
- /**
- * Returns true if this window has been shown on screen at some time in
- * the past. Must be called with the window manager lock held.
- *
- * @deprecated Use {@link #isDrawnLw} or any of the other drawn/visibility methods.
- */
- @Deprecated
- public boolean hasDrawnLw();
-
- /**
* Can be called by the policy to force a window to be hidden,
* regardless of whether the client or window manager would like
* it shown. Must be called with the window manager lock held.
@@ -377,51 +237,12 @@ public interface WindowManagerPolicy extends WindowManagerPolicyConstants {
public boolean showLw(boolean doAnimation);
/**
- * Check whether the process hosting this window is currently alive.
- */
- public boolean isAlive();
-
- /**
- * Check if window is on {@link Display#DEFAULT_DISPLAY}.
- * @return true if window is on default display.
- */
- public boolean isDefaultDisplay();
-
- /**
* Check whether the window is currently dimming.
*/
public boolean isDimming();
- /**
- * Returns true if the window is letterboxed for the display cutout.
- */
- default boolean isLetterboxedForDisplayCutoutLw() {
- return false;
- }
-
- /** @return the current windowing mode of this window. */
- int getWindowingMode();
-
- /**
- * Returns the {@link WindowConfiguration.ActivityType} associated with the configuration
- * of this window.
- */
- default int getActivityType() {
- return WindowConfiguration.WINDOWING_MODE_UNDEFINED;
- }
-
- /**
- * Returns true if the window is current in multi-windowing mode. i.e. it shares the
- * screen with other application windows.
- */
- boolean inMultiWindowMode();
-
- public int getRotationAnimationHint();
-
public boolean isInputMethodWindow();
- public boolean isInputMethodTarget();
-
public int getDisplayId();
/**
@@ -432,42 +253,8 @@ public interface WindowManagerPolicy extends WindowManagerPolicyConstants {
return false;
}
- /**
- * Returns true if the window owner has the permission to acquire a sleep token when it's
- * visible. That is, they have the permission {@link Manifest.permission#DEVICE_POWER}.
- */
- boolean canAcquireSleepToken();
-
- /** @return true if this window desires key events. */
- boolean canReceiveKeys();
-
/** @return true if the window can show over keyguard. */
boolean canShowWhenLocked();
-
- /**
- * Writes {@link com.android.server.wm.IdentifierProto} to stream.
- */
- void writeIdentifierToProto(ProtoOutputStream proto, long fieldId);
-
- /**
- * @return The {@link WindowFrames} associated with this {@link WindowState}
- */
- WindowFrames getWindowFrames();
- }
-
- /**
- * Representation of a input consumer that the policy has added to the
- * window manager to consume input events going to windows below it.
- */
- public interface InputConsumer {
- /**
- * Remove the input consumer from the window manager.
- */
- void dismiss();
- /**
- * Dispose the input consumer and input receiver from UI thread.
- */
- void dispose();
}
/**
@@ -538,11 +325,6 @@ public interface WindowManagerPolicy extends WindowManagerPolicyConstants {
void unregisterPointerEventListener(PointerEventListener listener, int displayId);
/**
- * @return The currently active input method window.
- */
- WindowState getInputMethodWindowLw();
-
- /**
* Notifies window manager that {@link #isKeyguardTrustedLw} has changed.
*/
void notifyKeyguardTrustedChanged();
@@ -615,17 +397,6 @@ public interface WindowManagerPolicy extends WindowManagerPolicyConstants {
}
/**
- * Provides the rotation of a device.
- *
- * @see com.android.server.policy.WindowOrientationListener
- */
- public interface RotationSource {
- int getProposedRotation();
-
- void setCurrentRotation(int rotation);
- }
-
- /**
* Interface to get public information of a display content.
*/
public interface DisplayContentInfo {
@@ -889,12 +660,6 @@ public interface WindowManagerPolicy extends WindowManagerPolicyConstants {
}
/**
- * Get the highest layer (actually one more than) that the wallpaper is
- * allowed to be in.
- */
- public int getMaxWallpaperLayer();
-
- /**
* Return whether the given window can become the Keyguard window. Typically returns true for
* the StatusBar.
*/
@@ -1384,17 +1149,6 @@ public interface WindowManagerPolicy extends WindowManagerPolicyConstants {
void dumpDebug(ProtoOutputStream proto, long fieldId);
/**
- * Returns whether a given window type is considered a top level one.
- * A top level window does not have a container, i.e. attached window,
- * or if it has a container it is laid out as a top-level window, not
- * as a child of its container.
- *
- * @param windowType The window type.
- * @return True if the window is a top level one.
- */
- public boolean isTopLevelWindow(int windowType);
-
- /**
* Notifies the keyguard to start fading out.
*
* @param startTime the start time of the animation in uptime milliseconds
diff --git a/services/core/java/com/android/server/security/VerityUtils.java b/services/core/java/com/android/server/security/VerityUtils.java
index 2b793c894eb0..f204aa2cc1ca 100644
--- a/services/core/java/com/android/server/security/VerityUtils.java
+++ b/services/core/java/com/android/server/security/VerityUtils.java
@@ -52,6 +52,9 @@ abstract public class VerityUtils {
/** The maximum size of signature file. This is just to avoid potential abuse. */
private static final int MAX_SIGNATURE_FILE_SIZE_BYTES = 8192;
+ /** SHA256 hash size. */
+ private static final int HASH_SIZE_BYTES = 32;
+
private static final boolean DEBUG = false;
/** Returns true if the given file looks like containing an fs-verity signature. */
@@ -90,8 +93,23 @@ abstract public class VerityUtils {
return (retval == 1);
}
+ /** Returns hash of a root node for the fs-verity enabled file. */
+ public static byte[] getFsverityRootHash(@NonNull String filePath) {
+ byte[] result = new byte[HASH_SIZE_BYTES];
+ int retval = measureFsverityNative(filePath, result);
+ if (retval < 0) {
+ if (retval != -OsConstants.ENODATA) {
+ Slog.e(TAG, "Failed to measure fs-verity, errno " + -retval + ": " + filePath);
+ }
+ return null;
+ }
+ return result;
+ }
+
private static native int enableFsverityNative(@NonNull String filePath,
@NonNull byte[] pkcs7Signature);
+ private static native int measureFsverityNative(@NonNull String filePath,
+ @NonNull byte[] digest);
private static native int statxForFsverityNative(@NonNull String filePath);
/**
diff --git a/services/core/java/com/android/server/slice/SliceFullAccessList.java b/services/core/java/com/android/server/slice/SliceFullAccessList.java
index 6f5afa207d31..d25ddf877951 100644
--- a/services/core/java/com/android/server/slice/SliceFullAccessList.java
+++ b/services/core/java/com/android/server/slice/SliceFullAccessList.java
@@ -101,7 +101,7 @@ public class SliceFullAccessList {
public void readXml(XmlPullParser parser) throws XmlPullParserException, IOException {
// upgrade xml
int xmlVersion = XmlUtils.readIntAttribute(parser, ATT_VERSION, 0);
- final List<UserInfo> activeUsers = UserManager.get(mContext).getUsers(true);
+ final List<UserInfo> activeUsers = UserManager.get(mContext).getAliveUsers();
for (UserInfo userInfo : activeUsers) {
upgradeXml(xmlVersion, userInfo.getUserHandle().getIdentifier());
}
diff --git a/services/core/java/com/android/server/soundtrigger_middleware/SoundTriggerHw2Watchdog.java b/services/core/java/com/android/server/soundtrigger_middleware/SoundTriggerHw2Watchdog.java
index 8e5ecee8262b..ebe9733e5d55 100644
--- a/services/core/java/com/android/server/soundtrigger_middleware/SoundTriggerHw2Watchdog.java
+++ b/services/core/java/com/android/server/soundtrigger_middleware/SoundTriggerHw2Watchdog.java
@@ -35,7 +35,8 @@ import java.util.TimerTask;
* HAL whenever they expire.
*/
public class SoundTriggerHw2Watchdog implements ISoundTriggerHw2 {
- private static final long TIMEOUT_MS = 1000;
+ // TODO(b/166328980): Reduce this to 1000 as soon as HAL is fixed.
+ private static final long TIMEOUT_MS = 10000;
private static final String TAG = "SoundTriggerHw2Watchdog";
private final @NonNull
diff --git a/services/core/java/com/android/server/soundtrigger_middleware/SoundTriggerModule.java b/services/core/java/com/android/server/soundtrigger_middleware/SoundTriggerModule.java
index c382e1152e4b..5a587cc9764c 100644
--- a/services/core/java/com/android/server/soundtrigger_middleware/SoundTriggerModule.java
+++ b/services/core/java/com/android/server/soundtrigger_middleware/SoundTriggerModule.java
@@ -36,7 +36,6 @@ import android.media.soundtrigger_middleware.Status;
import android.os.IBinder;
import android.os.IHwBinder;
import android.os.RemoteException;
-import android.os.ServiceSpecificException;
import android.util.Log;
import java.util.ArrayList;
@@ -293,7 +292,11 @@ class SoundTriggerModule implements IHwBinder.DeathRecipient {
} catch (Exception e) {
// We must do this outside the lock, to avoid possible deadlocks with the remote
// process that provides the audio sessions, which may also be calling into us.
- mAudioSessionProvider.releaseSession(audioSession.mSessionHandle);
+ try {
+ mAudioSessionProvider.releaseSession(audioSession.mSessionHandle);
+ } catch (Exception ee) {
+ Log.e(TAG, "Failed to release session.", ee);
+ }
throw e;
}
}
@@ -321,7 +324,11 @@ class SoundTriggerModule implements IHwBinder.DeathRecipient {
} catch (Exception e) {
// We must do this outside the lock, to avoid possible deadlocks with the remote
// process that provides the audio sessions, which may also be calling into us.
- mAudioSessionProvider.releaseSession(audioSession.mSessionHandle);
+ try {
+ mAudioSessionProvider.releaseSession(audioSession.mSessionHandle);
+ } catch (Exception ee) {
+ Log.e(TAG, "Failed to release session.", ee);
+ }
throw e;
}
}
diff --git a/services/core/java/com/android/server/timezonedetector/CallerIdentityInjector.java b/services/core/java/com/android/server/timezonedetector/CallerIdentityInjector.java
new file mode 100644
index 000000000000..1500cfaeb3a2
--- /dev/null
+++ b/services/core/java/com/android/server/timezonedetector/CallerIdentityInjector.java
@@ -0,0 +1,62 @@
+/*
+ * 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 com.android.server.timezonedetector;
+
+import android.annotation.UserIdInt;
+import android.os.Binder;
+import android.os.UserHandle;
+
+/**
+ * An interface to wrap various difficult-to-intercept calls that services make to access / manage
+ * caller identity, e.g. {@link Binder#clearCallingIdentity()}.
+ */
+public interface CallerIdentityInjector {
+
+ /** A singleton for the real implementation of {@link CallerIdentityInjector}. */
+ CallerIdentityInjector REAL = new Real();
+
+ /** A {@link UserHandle#getCallingUserId()} call. */
+ @UserIdInt int getCallingUserId();
+
+ /** A {@link Binder#clearCallingIdentity()} call. */
+ long clearCallingIdentity();
+
+ /** A {@link Binder#restoreCallingIdentity(long)} ()} call. */
+ void restoreCallingIdentity(long token);
+
+ /** The real implementation of {@link CallerIdentityInjector}. */
+ class Real implements CallerIdentityInjector {
+
+ protected Real() {
+ }
+
+ @Override
+ public int getCallingUserId() {
+ return UserHandle.getCallingUserId();
+ }
+
+ @Override
+ public long clearCallingIdentity() {
+ return Binder.clearCallingIdentity();
+ }
+
+ @Override
+ public void restoreCallingIdentity(long token) {
+ Binder.restoreCallingIdentity(token);
+ }
+ }
+}
diff --git a/services/core/java/com/android/server/timezonedetector/ConfigurationChangeListener.java b/services/core/java/com/android/server/timezonedetector/ConfigurationChangeListener.java
new file mode 100644
index 000000000000..4c7b1f38dd5a
--- /dev/null
+++ b/services/core/java/com/android/server/timezonedetector/ConfigurationChangeListener.java
@@ -0,0 +1,26 @@
+/*
+ * Copyright 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.server.timezonedetector;
+
+/**
+ * A listener used to receive notification that time zone configuration has changed.
+ */
+@FunctionalInterface
+public interface ConfigurationChangeListener {
+ /** Called when the current user or a configuration value has changed. */
+ void onChange();
+}
diff --git a/services/core/java/com/android/server/timezonedetector/ConfigurationInternal.java b/services/core/java/com/android/server/timezonedetector/ConfigurationInternal.java
new file mode 100644
index 000000000000..aee3d8d3499b
--- /dev/null
+++ b/services/core/java/com/android/server/timezonedetector/ConfigurationInternal.java
@@ -0,0 +1,288 @@
+/*
+ * 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.timezonedetector;
+
+import static android.app.timezonedetector.TimeZoneCapabilities.CAPABILITY_NOT_ALLOWED;
+import static android.app.timezonedetector.TimeZoneCapabilities.CAPABILITY_NOT_APPLICABLE;
+import static android.app.timezonedetector.TimeZoneCapabilities.CAPABILITY_NOT_SUPPORTED;
+import static android.app.timezonedetector.TimeZoneCapabilities.CAPABILITY_POSSESSED;
+
+import android.annotation.NonNull;
+import android.annotation.UserIdInt;
+import android.app.timezonedetector.TimeZoneCapabilities;
+import android.app.timezonedetector.TimeZoneConfiguration;
+
+import java.util.Objects;
+
+/**
+ * Holds all configuration values that affect time zone behavior and some associated logic, e.g.
+ * {@link #getAutoDetectionEnabledBehavior()}, {@link #getGeoDetectionEnabledBehavior()} and {@link
+ * #createCapabilities()}.
+ */
+public final class ConfigurationInternal {
+
+ private final @UserIdInt int mUserId;
+ private final boolean mUserConfigAllowed;
+ private final boolean mAutoDetectionSupported;
+ private final boolean mAutoDetectionEnabled;
+ private final boolean mLocationEnabled;
+ private final boolean mGeoDetectionEnabled;
+
+ private ConfigurationInternal(Builder builder) {
+ mUserId = builder.mUserId;
+ mUserConfigAllowed = builder.mUserConfigAllowed;
+ mAutoDetectionSupported = builder.mAutoDetectionSupported;
+ mAutoDetectionEnabled = builder.mAutoDetectionEnabled;
+ mLocationEnabled = builder.mLocationEnabled;
+ mGeoDetectionEnabled = builder.mGeoDetectionEnabled;
+ }
+
+ /** Returns the ID of the user this configuration is associated with. */
+ public @UserIdInt int getUserId() {
+ return mUserId;
+ }
+
+ /** Returns true if the user allowed to modify time zone configuration. */
+ public boolean isUserConfigAllowed() {
+ return mUserConfigAllowed;
+ }
+
+ /** Returns true if the device supports some form of auto time zone detection. */
+ public boolean isAutoDetectionSupported() {
+ return mAutoDetectionSupported;
+ }
+
+ /** Returns the value of the auto time zone detection enabled setting. */
+ public boolean getAutoDetectionEnabledSetting() {
+ return mAutoDetectionEnabled;
+ }
+
+ /**
+ * Returns true if auto time zone detection behavior is actually enabled, which can be distinct
+ * from the raw setting value. */
+ public boolean getAutoDetectionEnabledBehavior() {
+ return mAutoDetectionSupported && mAutoDetectionEnabled;
+ }
+
+ /** Returns true if user's location can be used generally. */
+ public boolean isLocationEnabled() {
+ return mLocationEnabled;
+ }
+
+ /** Returns the value of the geolocation time zone detection enabled setting. */
+ public boolean getGeoDetectionEnabledSetting() {
+ return mGeoDetectionEnabled;
+ }
+
+ /**
+ * Returns true if geolocation time zone detection behavior is actually enabled, which can be
+ * distinct from the raw setting value.
+ */
+ public boolean getGeoDetectionEnabledBehavior() {
+ if (getAutoDetectionEnabledBehavior()) {
+ return mLocationEnabled && mGeoDetectionEnabled;
+ }
+ return false;
+ }
+
+ /** Creates a {@link TimeZoneCapabilities} object using the configuration values. */
+ public TimeZoneCapabilities createCapabilities() {
+ TimeZoneCapabilities.Builder builder = new TimeZoneCapabilities.Builder()
+ .setConfiguration(asConfiguration());
+
+ boolean allowConfigDateTime = isUserConfigAllowed();
+
+ // Automatic time zone detection is only supported on devices if there is a telephony
+ // network available or geolocation time zone detection is possible.
+ boolean deviceHasTimeZoneDetection = isAutoDetectionSupported();
+
+ final int configureAutoDetectionEnabledCapability;
+ if (!deviceHasTimeZoneDetection) {
+ configureAutoDetectionEnabledCapability = CAPABILITY_NOT_SUPPORTED;
+ } else if (!allowConfigDateTime) {
+ configureAutoDetectionEnabledCapability = CAPABILITY_NOT_ALLOWED;
+ } else {
+ configureAutoDetectionEnabledCapability = CAPABILITY_POSSESSED;
+ }
+ builder.setConfigureAutoDetectionEnabled(configureAutoDetectionEnabledCapability);
+
+ final int configureGeolocationDetectionEnabledCapability;
+ if (!deviceHasTimeZoneDetection) {
+ configureGeolocationDetectionEnabledCapability = CAPABILITY_NOT_SUPPORTED;
+ } else if (!allowConfigDateTime) {
+ configureGeolocationDetectionEnabledCapability = CAPABILITY_NOT_ALLOWED;
+ } else if (!isLocationEnabled()) {
+ configureGeolocationDetectionEnabledCapability = CAPABILITY_NOT_APPLICABLE;
+ } else {
+ configureGeolocationDetectionEnabledCapability = CAPABILITY_POSSESSED;
+ }
+ builder.setConfigureGeoDetectionEnabled(configureGeolocationDetectionEnabledCapability);
+
+ // The ability to make manual time zone suggestions can also be restricted by policy. With
+ // the current logic above, this could lead to a situation where a device hardware does not
+ // support auto detection, the device has been forced into "auto" mode by an admin and the
+ // user is unable to disable auto detection.
+ final int suggestManualTimeZoneCapability;
+ if (!allowConfigDateTime) {
+ suggestManualTimeZoneCapability = CAPABILITY_NOT_ALLOWED;
+ } else if (getAutoDetectionEnabledBehavior()) {
+ suggestManualTimeZoneCapability = CAPABILITY_NOT_APPLICABLE;
+ } else {
+ suggestManualTimeZoneCapability = CAPABILITY_POSSESSED;
+ }
+ builder.setSuggestManualTimeZone(suggestManualTimeZoneCapability);
+
+ return builder.build();
+ }
+
+ /** Returns a {@link TimeZoneConfiguration} from the configuration values. */
+ public TimeZoneConfiguration asConfiguration() {
+ return new TimeZoneConfiguration.Builder(mUserId)
+ .setAutoDetectionEnabled(getAutoDetectionEnabledSetting())
+ .setGeoDetectionEnabled(getGeoDetectionEnabledSetting())
+ .build();
+ }
+
+ /**
+ * Merges the configuration values from this with any properties set in {@code
+ * newConfiguration}. The new configuration has precedence. Used to apply user updates to
+ * internal configuration.
+ */
+ public ConfigurationInternal merge(TimeZoneConfiguration newConfiguration) {
+ Builder builder = new Builder(this);
+ if (newConfiguration.hasSetting(TimeZoneConfiguration.SETTING_AUTO_DETECTION_ENABLED)) {
+ builder.setAutoDetectionEnabled(newConfiguration.isAutoDetectionEnabled());
+ }
+ if (newConfiguration.hasSetting(TimeZoneConfiguration.SETTING_GEO_DETECTION_ENABLED)) {
+ builder.setGeoDetectionEnabled(newConfiguration.isGeoDetectionEnabled());
+ }
+ return builder.build();
+ }
+
+ @Override
+ public boolean equals(Object o) {
+ if (this == o) {
+ return true;
+ }
+ if (o == null || getClass() != o.getClass()) {
+ return false;
+ }
+ ConfigurationInternal that = (ConfigurationInternal) o;
+ return mUserId == that.mUserId
+ && mUserConfigAllowed == that.mUserConfigAllowed
+ && mAutoDetectionSupported == that.mAutoDetectionSupported
+ && mAutoDetectionEnabled == that.mAutoDetectionEnabled
+ && mLocationEnabled == that.mLocationEnabled
+ && mGeoDetectionEnabled == that.mGeoDetectionEnabled;
+ }
+
+ @Override
+ public int hashCode() {
+ return Objects.hash(mUserId, mUserConfigAllowed, mAutoDetectionSupported,
+ mAutoDetectionEnabled, mLocationEnabled, mGeoDetectionEnabled);
+ }
+
+ @Override
+ public String toString() {
+ return "TimeZoneDetectorConfiguration{"
+ + "mUserId=" + mUserId
+ + "mUserConfigAllowed=" + mUserConfigAllowed
+ + "mAutoDetectionSupported=" + mAutoDetectionSupported
+ + "mAutoDetectionEnabled=" + mAutoDetectionEnabled
+ + "mLocationEnabled=" + mLocationEnabled
+ + "mGeoDetectionEnabled=" + mGeoDetectionEnabled
+ + '}';
+ }
+
+ /**
+ * A Builder for {@link ConfigurationInternal}.
+ */
+ public static class Builder {
+
+ private final @UserIdInt int mUserId;
+ private boolean mUserConfigAllowed;
+ private boolean mAutoDetectionSupported;
+ private boolean mAutoDetectionEnabled;
+ private boolean mLocationEnabled;
+ private boolean mGeoDetectionEnabled;
+
+ /**
+ * Creates a new Builder with only the userId set.
+ */
+ public Builder(@UserIdInt int userId) {
+ mUserId = userId;
+ }
+
+ /**
+ * Creates a new Builder by copying values from an existing instance.
+ */
+ public Builder(ConfigurationInternal toCopy) {
+ this.mUserId = toCopy.mUserId;
+ this.mUserConfigAllowed = toCopy.mUserConfigAllowed;
+ this.mAutoDetectionSupported = toCopy.mAutoDetectionSupported;
+ this.mAutoDetectionEnabled = toCopy.mAutoDetectionEnabled;
+ this.mLocationEnabled = toCopy.mLocationEnabled;
+ this.mGeoDetectionEnabled = toCopy.mGeoDetectionEnabled;
+ }
+
+ /**
+ * Sets whether the user is allowed to configure time zone settings on this device.
+ */
+ public Builder setUserConfigAllowed(boolean configAllowed) {
+ mUserConfigAllowed = configAllowed;
+ return this;
+ }
+
+ /**
+ * Sets whether automatic time zone detection is supported on this device.
+ */
+ public Builder setAutoDetectionSupported(boolean supported) {
+ mAutoDetectionSupported = supported;
+ return this;
+ }
+
+ /**
+ * Sets the value of the automatic time zone detection enabled setting for this device.
+ */
+ public Builder setAutoDetectionEnabled(boolean enabled) {
+ mAutoDetectionEnabled = enabled;
+ return this;
+ }
+
+ /**
+ * Sets the value of the location mode setting for this user.
+ */
+ public Builder setLocationEnabled(boolean enabled) {
+ mLocationEnabled = enabled;
+ return this;
+ }
+
+ /**
+ * Sets the value of the geolocation time zone detection setting for this user.
+ */
+ public Builder setGeoDetectionEnabled(boolean enabled) {
+ mGeoDetectionEnabled = enabled;
+ return this;
+ }
+
+ /** Returns a new {@link ConfigurationInternal}. */
+ @NonNull
+ public ConfigurationInternal build() {
+ return new ConfigurationInternal(this);
+ }
+ }
+}
diff --git a/services/core/java/com/android/server/timezonedetector/TEST_MAPPING b/services/core/java/com/android/server/timezonedetector/TEST_MAPPING
new file mode 100644
index 000000000000..91e172c9d153
--- /dev/null
+++ b/services/core/java/com/android/server/timezonedetector/TEST_MAPPING
@@ -0,0 +1,12 @@
+{
+ "presubmit": [
+ {
+ "name": "FrameworksServicesTests",
+ "options": [
+ {
+ "include-filter": "com.android.server.timezonedetector."
+ }
+ ]
+ }
+ ]
+}
diff --git a/services/core/java/com/android/server/timezonedetector/TimeZoneDetectorCallbackImpl.java b/services/core/java/com/android/server/timezonedetector/TimeZoneDetectorCallbackImpl.java
index 0ca36e0fc258..d64032325539 100644
--- a/services/core/java/com/android/server/timezonedetector/TimeZoneDetectorCallbackImpl.java
+++ b/services/core/java/com/android/server/timezonedetector/TimeZoneDetectorCallbackImpl.java
@@ -16,24 +16,30 @@
package com.android.server.timezonedetector;
-import static android.app.timezonedetector.TimeZoneCapabilities.CAPABILITY_NOT_ALLOWED;
-import static android.app.timezonedetector.TimeZoneCapabilities.CAPABILITY_NOT_APPLICABLE;
-import static android.app.timezonedetector.TimeZoneCapabilities.CAPABILITY_NOT_SUPPORTED;
-import static android.app.timezonedetector.TimeZoneCapabilities.CAPABILITY_POSSESSED;
+import static android.content.Intent.ACTION_USER_SWITCHED;
import android.annotation.NonNull;
import android.annotation.Nullable;
import android.annotation.UserIdInt;
+import android.app.ActivityManagerInternal;
import android.app.AlarmManager;
-import android.app.timezonedetector.TimeZoneCapabilities;
import android.app.timezonedetector.TimeZoneConfiguration;
+import android.content.BroadcastReceiver;
import android.content.ContentResolver;
import android.content.Context;
+import android.content.Intent;
+import android.content.IntentFilter;
+import android.database.ContentObserver;
+import android.location.LocationManager;
import android.net.ConnectivityManager;
+import android.os.Handler;
import android.os.SystemProperties;
import android.os.UserHandle;
import android.os.UserManager;
import android.provider.Settings;
+import android.util.Slog;
+
+import com.android.server.LocalServices;
import java.util.Objects;
@@ -42,103 +48,87 @@ import java.util.Objects;
*/
public final class TimeZoneDetectorCallbackImpl implements TimeZoneDetectorStrategyImpl.Callback {
+ private static final String LOG_TAG = "TimeZoneDetectorCallbackImpl";
private static final String TIMEZONE_PROPERTY = "persist.sys.timezone";
- private final Context mContext;
- private final ContentResolver mCr;
- private final UserManager mUserManager;
-
- TimeZoneDetectorCallbackImpl(Context context) {
- mContext = context;
+ @NonNull private final Context mContext;
+ @NonNull private final Handler mHandler;
+ @NonNull private final ContentResolver mCr;
+ @NonNull private final UserManager mUserManager;
+ @NonNull private final boolean mGeoDetectionFeatureEnabled;
+ @NonNull private final LocationManager mLocationManager;
+ // @NonNull after setConfigChangeListener() is called.
+ private ConfigurationChangeListener mConfigChangeListener;
+
+ TimeZoneDetectorCallbackImpl(@NonNull Context context, @NonNull Handler handler,
+ boolean geoDetectionFeatureEnabled) {
+ mContext = Objects.requireNonNull(context);
+ mHandler = Objects.requireNonNull(handler);
mCr = context.getContentResolver();
mUserManager = context.getSystemService(UserManager.class);
+ mLocationManager = context.getSystemService(LocationManager.class);
+ mGeoDetectionFeatureEnabled = geoDetectionFeatureEnabled;
+
+ // Wire up the change listener. All invocations are performed on the mHandler thread.
+
+ // Listen for the user changing / the user's location mode changing.
+ IntentFilter filter = new IntentFilter();
+ filter.addAction(ACTION_USER_SWITCHED);
+ filter.addAction(LocationManager.MODE_CHANGED_ACTION);
+ mContext.registerReceiverForAllUsers(new BroadcastReceiver() {
+ @Override
+ public void onReceive(Context context, Intent intent) {
+ handleConfigChangeOnHandlerThread();
+ }
+ }, filter, null, mHandler);
+
+ // Add async callbacks for global settings being changed.
+ ContentResolver contentResolver = mContext.getContentResolver();
+ contentResolver.registerContentObserver(
+ Settings.Global.getUriFor(Settings.Global.AUTO_TIME_ZONE), true,
+ new ContentObserver(mHandler) {
+ public void onChange(boolean selfChange) {
+ handleConfigChangeOnHandlerThread();
+ }
+ });
+
+ // Add async callbacks for user scoped location settings being changed.
+ contentResolver.registerContentObserver(
+ Settings.Secure.getUriFor(Settings.Secure.LOCATION_TIME_ZONE_DETECTION_ENABLED),
+ true,
+ new ContentObserver(mHandler) {
+ public void onChange(boolean selfChange) {
+ handleConfigChangeOnHandlerThread();
+ }
+ }, UserHandle.USER_ALL);
}
- @Override
- public TimeZoneCapabilities getCapabilities(@UserIdInt int userId) {
- UserHandle userHandle = UserHandle.of(userId);
- boolean disallowConfigDateTime =
- mUserManager.hasUserRestriction(UserManager.DISALLOW_CONFIG_DATE_TIME, userHandle);
-
- TimeZoneCapabilities.Builder builder = new TimeZoneCapabilities.Builder(userId);
-
- // Automatic time zone detection is only supported (currently) on devices if there is a
- // telephony network available.
- if (!deviceHasTelephonyNetwork()) {
- builder.setConfigureAutoDetectionEnabled(CAPABILITY_NOT_SUPPORTED);
- } else if (disallowConfigDateTime) {
- builder.setConfigureAutoDetectionEnabled(CAPABILITY_NOT_ALLOWED);
- } else {
- builder.setConfigureAutoDetectionEnabled(CAPABILITY_POSSESSED);
- }
-
- // TODO(b/149014708) Replace this with real logic when the settings storage is fully
- // implemented.
- builder.setConfigureGeoDetectionEnabled(CAPABILITY_NOT_SUPPORTED);
-
- // The ability to make manual time zone suggestions can also be restricted by policy. With
- // the current logic above, this could lead to a situation where a device hardware does not
- // support auto detection, the device has been forced into "auto" mode by an admin and the
- // user is unable to disable auto detection.
- if (disallowConfigDateTime) {
- builder.setSuggestManualTimeZone(CAPABILITY_NOT_ALLOWED);
- } else if (isAutoDetectionEnabled()) {
- builder.setSuggestManualTimeZone(CAPABILITY_NOT_APPLICABLE);
- } else {
- builder.setSuggestManualTimeZone(CAPABILITY_POSSESSED);
+ private void handleConfigChangeOnHandlerThread() {
+ if (mConfigChangeListener == null) {
+ Slog.wtf(LOG_TAG, "mConfigChangeListener is unexpectedly null");
}
- return builder.build();
+ mConfigChangeListener.onChange();
}
@Override
- public TimeZoneConfiguration getConfiguration(@UserIdInt int userId) {
- return new TimeZoneConfiguration.Builder()
- .setAutoDetectionEnabled(isAutoDetectionEnabled())
- .setGeoDetectionEnabled(isGeoDetectionEnabled())
- .build();
+ public void setConfigChangeListener(@NonNull ConfigurationChangeListener listener) {
+ mConfigChangeListener = Objects.requireNonNull(listener);
}
@Override
- public void setConfiguration(
- @UserIdInt int userId, @NonNull TimeZoneConfiguration configuration) {
- Objects.requireNonNull(configuration);
- if (!configuration.isComplete()) {
- throw new IllegalArgumentException("configuration=" + configuration + " not complete");
- }
-
- // Avoid writing auto detection config for devices that do not support auto time zone
- // detection: if we wrote it down then we'd set the default explicitly. That might influence
- // what happens on later releases that do support auto detection on the same hardware.
- if (isAutoDetectionSupported()) {
- final int autoEnabledValue = configuration.isAutoDetectionEnabled() ? 1 : 0;
- Settings.Global.putInt(mCr, Settings.Global.AUTO_TIME_ZONE, autoEnabledValue);
-
- final boolean geoTzDetectionEnabledValue = configuration.isGeoDetectionEnabled();
- // TODO(b/149014708) Write this down to user-scoped settings once implemented.
- }
- }
-
- @Override
- public boolean isAutoDetectionEnabled() {
- // To ensure that TimeZoneConfiguration is "complete" for simplicity, devices that do not
- // support auto detection have safe, hard coded configuration values that make it look like
- // auto detection is turned off. It is therefore important that false is returned from this
- // method for devices that do not support auto time zone detection. Such devices will not
- // have a UI to turn the auto detection on/off. Returning true could prevent the user
- // entering information manually. On devices that do support auto time detection the default
- // is to turn auto detection on.
- if (isAutoDetectionSupported()) {
- return Settings.Global.getInt(mCr, Settings.Global.AUTO_TIME_ZONE, 1 /* default */) > 0;
- }
- return false;
+ public ConfigurationInternal getConfigurationInternal(@UserIdInt int userId) {
+ return new ConfigurationInternal.Builder(userId)
+ .setUserConfigAllowed(isUserConfigAllowed(userId))
+ .setAutoDetectionSupported(isAutoDetectionSupported())
+ .setAutoDetectionEnabled(isAutoDetectionEnabled())
+ .setLocationEnabled(isLocationEnabled(userId))
+ .setGeoDetectionEnabled(isGeoDetectionEnabled(userId))
+ .build();
}
@Override
- public boolean isGeoDetectionEnabled() {
- // TODO(b/149014708) Read this from user-scoped settings once implemented. The user's
- // location toggle will act as an override for this setting, i.e. so that the setting will
- // return false if the location toggle is disabled.
- return false;
+ public @UserIdInt int getCurrentUserId() {
+ return LocalServices.getService(ActivityManagerInternal.class).getCurrentUserId();
}
@Override
@@ -165,8 +155,55 @@ public final class TimeZoneDetectorCallbackImpl implements TimeZoneDetectorStrat
alarmManager.setTimeZone(zoneId);
}
+ @Override
+ public void storeConfiguration(TimeZoneConfiguration configuration) {
+ Objects.requireNonNull(configuration);
+
+ // Avoid writing the auto detection enabled setting for devices that do not support auto
+ // time zone detection: if we wrote it down then we'd set the value explicitly, which would
+ // prevent detecting "default" later. That might influence what happens on later releases
+ // that support new types of auto detection on the same hardware.
+ if (isAutoDetectionSupported()) {
+ final boolean autoDetectionEnabled = configuration.isAutoDetectionEnabled();
+ setAutoDetectionEnabled(autoDetectionEnabled);
+
+ final int userId = configuration.getUserId();
+ final boolean geoTzDetectionEnabled = configuration.isGeoDetectionEnabled();
+ setGeoDetectionEnabled(userId, geoTzDetectionEnabled);
+ }
+ }
+
+ private boolean isUserConfigAllowed(@UserIdInt int userId) {
+ UserHandle userHandle = UserHandle.of(userId);
+ return !mUserManager.hasUserRestriction(UserManager.DISALLOW_CONFIG_DATE_TIME, userHandle);
+ }
+
private boolean isAutoDetectionSupported() {
- return deviceHasTelephonyNetwork();
+ return deviceHasTelephonyNetwork() || mGeoDetectionFeatureEnabled;
+ }
+
+ private boolean isAutoDetectionEnabled() {
+ return Settings.Global.getInt(mCr, Settings.Global.AUTO_TIME_ZONE, 1 /* default */) > 0;
+ }
+
+ private void setAutoDetectionEnabled(boolean enabled) {
+ Settings.Global.putInt(mCr, Settings.Global.AUTO_TIME_ZONE, enabled ? 1 : 0);
+ }
+
+ private boolean isLocationEnabled(@UserIdInt int userId) {
+ return mLocationManager.isLocationEnabledForUser(UserHandle.of(userId));
+ }
+
+ private boolean isGeoDetectionEnabled(@UserIdInt int userId) {
+ final boolean locationEnabled = isLocationEnabled(userId);
+ return Settings.Secure.getIntForUser(mCr,
+ Settings.Secure.LOCATION_TIME_ZONE_DETECTION_ENABLED,
+ locationEnabled ? 1 : 0 /* defaultValue */, userId) != 0;
+ }
+
+ private void setGeoDetectionEnabled(@UserIdInt int userId, boolean enabled) {
+ Settings.Secure.putIntForUser(mCr, Settings.Secure.LOCATION_TIME_ZONE_DETECTION_ENABLED,
+ enabled ? 1 : 0, userId);
}
private boolean deviceHasTelephonyNetwork() {
@@ -174,4 +211,4 @@ public final class TimeZoneDetectorCallbackImpl implements TimeZoneDetectorStrat
return mContext.getSystemService(ConnectivityManager.class)
.isNetworkSupported(ConnectivityManager.TYPE_MOBILE);
}
-}
+} \ No newline at end of file
diff --git a/services/core/java/com/android/server/timezonedetector/TimeZoneDetectorInternal.java b/services/core/java/com/android/server/timezonedetector/TimeZoneDetectorInternal.java
index fb7a73d12632..2d50390c27a9 100644
--- a/services/core/java/com/android/server/timezonedetector/TimeZoneDetectorInternal.java
+++ b/services/core/java/com/android/server/timezonedetector/TimeZoneDetectorInternal.java
@@ -27,6 +27,12 @@ import android.annotation.NonNull;
*/
public interface TimeZoneDetectorInternal extends Dumpable.Container {
+ /** Adds a listener that will be invoked when time zone detection configuration is changed. */
+ void addConfigurationListener(ConfigurationChangeListener listener);
+
+ /** Returns the {@link ConfigurationInternal} for the current user. */
+ ConfigurationInternal getCurrentUserConfigurationInternal();
+
/**
* Suggests the current time zone, determined using geolocation, to the detector. The
* detector may ignore the signal based on system settings, whether better information is
diff --git a/services/core/java/com/android/server/timezonedetector/TimeZoneDetectorInternalImpl.java b/services/core/java/com/android/server/timezonedetector/TimeZoneDetectorInternalImpl.java
index 15412a0d14a1..f0ce827cec5e 100644
--- a/services/core/java/com/android/server/timezonedetector/TimeZoneDetectorInternalImpl.java
+++ b/services/core/java/com/android/server/timezonedetector/TimeZoneDetectorInternalImpl.java
@@ -20,8 +20,8 @@ import android.annotation.NonNull;
import android.content.Context;
import android.os.Handler;
-import com.android.internal.annotations.VisibleForTesting;
-
+import java.util.ArrayList;
+import java.util.List;
import java.util.Objects;
/**
@@ -34,18 +34,26 @@ public final class TimeZoneDetectorInternalImpl implements TimeZoneDetectorInter
@NonNull private final Context mContext;
@NonNull private final Handler mHandler;
@NonNull private final TimeZoneDetectorStrategy mTimeZoneDetectorStrategy;
+ @NonNull private final List<ConfigurationChangeListener> mConfigurationListeners =
+ new ArrayList<>();
- static TimeZoneDetectorInternalImpl create(@NonNull Context context, @NonNull Handler handler,
- @NonNull TimeZoneDetectorStrategy timeZoneDetectorStrategy) {
- return new TimeZoneDetectorInternalImpl(context, handler, timeZoneDetectorStrategy);
- }
-
- @VisibleForTesting
public TimeZoneDetectorInternalImpl(@NonNull Context context, @NonNull Handler handler,
@NonNull TimeZoneDetectorStrategy timeZoneDetectorStrategy) {
mContext = Objects.requireNonNull(context);
mHandler = Objects.requireNonNull(handler);
mTimeZoneDetectorStrategy = Objects.requireNonNull(timeZoneDetectorStrategy);
+
+ // Wire up a change listener so that any downstream listeners can be notified when
+ // the configuration changes for any reason.
+ mTimeZoneDetectorStrategy.addConfigChangeListener(this::handleConfigurationChanged);
+ }
+
+ private void handleConfigurationChanged() {
+ synchronized (mConfigurationListeners) {
+ for (ConfigurationChangeListener listener : mConfigurationListeners) {
+ listener.onChange();
+ }
+ }
}
@Override
@@ -54,6 +62,19 @@ public final class TimeZoneDetectorInternalImpl implements TimeZoneDetectorInter
}
@Override
+ public void addConfigurationListener(ConfigurationChangeListener listener) {
+ synchronized (mConfigurationListeners) {
+ mConfigurationListeners.add(Objects.requireNonNull(listener));
+ }
+ }
+
+ @Override
+ @NonNull
+ public ConfigurationInternal getCurrentUserConfigurationInternal() {
+ return mTimeZoneDetectorStrategy.getCurrentUserConfigurationInternal();
+ }
+
+ @Override
public void suggestGeolocationTimeZone(
@NonNull GeolocationTimeZoneSuggestion timeZoneSuggestion) {
Objects.requireNonNull(timeZoneSuggestion);
diff --git a/services/core/java/com/android/server/timezonedetector/TimeZoneDetectorService.java b/services/core/java/com/android/server/timezonedetector/TimeZoneDetectorService.java
index d81f949742bd..7501d9fe6a7c 100644
--- a/services/core/java/com/android/server/timezonedetector/TimeZoneDetectorService.java
+++ b/services/core/java/com/android/server/timezonedetector/TimeZoneDetectorService.java
@@ -24,32 +24,24 @@ import android.app.timezonedetector.ManualTimeZoneSuggestion;
import android.app.timezonedetector.TelephonyTimeZoneSuggestion;
import android.app.timezonedetector.TimeZoneCapabilities;
import android.app.timezonedetector.TimeZoneConfiguration;
-import android.content.ContentResolver;
import android.content.Context;
-import android.database.ContentObserver;
-import android.os.Binder;
import android.os.Handler;
import android.os.IBinder;
import android.os.RemoteException;
import android.os.ResultReceiver;
import android.os.ShellCallback;
-import android.os.UserHandle;
-import android.provider.Settings;
import android.util.IndentingPrintWriter;
import android.util.Slog;
-import android.util.SparseArray;
import com.android.internal.annotations.GuardedBy;
import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.util.DumpUtils;
import com.android.server.FgThread;
import com.android.server.SystemService;
-import com.android.server.timezonedetector.TimeZoneDetectorStrategy.StrategyListener;
import java.io.FileDescriptor;
import java.io.PrintWriter;
import java.util.ArrayList;
-import java.util.Iterator;
import java.util.Objects;
/**
@@ -65,6 +57,9 @@ public final class TimeZoneDetectorService extends ITimeZoneDetectorService.Stub
private static final String TAG = "TimeZoneDetectorService";
+ /** A compile time switch for enabling / disabling geolocation-based time zone detection. */
+ private static final boolean GEOLOCATION_TIME_ZONE_DETECTION_ENABLED = false;
+
/**
* Handles the service lifecycle for {@link TimeZoneDetectorService} and
* {@link TimeZoneDetectorInternalImpl}.
@@ -80,18 +75,20 @@ public final class TimeZoneDetectorService extends ITimeZoneDetectorService.Stub
// Obtain / create the shared dependencies.
Context context = getContext();
Handler handler = FgThread.getHandler();
+
TimeZoneDetectorStrategy timeZoneDetectorStrategy =
- TimeZoneDetectorStrategyImpl.create(context);
+ TimeZoneDetectorStrategyImpl.create(
+ context, handler, GEOLOCATION_TIME_ZONE_DETECTION_ENABLED);
// Create and publish the local service for use by internal callers.
TimeZoneDetectorInternal internal =
- TimeZoneDetectorInternalImpl.create(context, handler, timeZoneDetectorStrategy);
+ new TimeZoneDetectorInternalImpl(context, handler, timeZoneDetectorStrategy);
publishLocalService(TimeZoneDetectorInternal.class, internal);
// Publish the binder service so it can be accessed from other (appropriately
// permissioned) processes.
- TimeZoneDetectorService service =
- TimeZoneDetectorService.create(context, handler, timeZoneDetectorStrategy);
+ TimeZoneDetectorService service = TimeZoneDetectorService.create(
+ context, handler, timeZoneDetectorStrategy);
publishBinderService(Context.TIME_ZONE_DETECTOR_SERVICE, service);
}
}
@@ -103,79 +100,51 @@ public final class TimeZoneDetectorService extends ITimeZoneDetectorService.Stub
private final Handler mHandler;
@NonNull
+ private final CallerIdentityInjector mCallerIdentityInjector;
+
+ @NonNull
private final TimeZoneDetectorStrategy mTimeZoneDetectorStrategy;
- /**
- * This sparse array acts as a map from userId to listeners running as that userId. User scoped
- * as time zone detection configuration is partially user-specific, so different users can
- * get different configuration.
- */
@GuardedBy("mConfigurationListeners")
@NonNull
- private final SparseArray<ArrayList<ITimeZoneConfigurationListener>> mConfigurationListeners =
- new SparseArray<>();
+ private final ArrayList<ITimeZoneConfigurationListener> mConfigurationListeners =
+ new ArrayList<>();
private static TimeZoneDetectorService create(
@NonNull Context context, @NonNull Handler handler,
@NonNull TimeZoneDetectorStrategy timeZoneDetectorStrategy) {
- TimeZoneDetectorService service =
- new TimeZoneDetectorService(context, handler, timeZoneDetectorStrategy);
-
- ContentResolver contentResolver = context.getContentResolver();
- contentResolver.registerContentObserver(
- Settings.Global.getUriFor(Settings.Global.AUTO_TIME_ZONE), true,
- new ContentObserver(handler) {
- public void onChange(boolean selfChange) {
- service.handleAutoTimeZoneConfigChanged();
- }
- });
- // TODO(b/149014708) Listen for changes to geolocation time zone detection enabled config.
- // This should also include listening to the current user and the current user's location
- // toggle since the config is user-scoped and the location toggle overrides the geolocation
- // time zone enabled setting.
+ CallerIdentityInjector callerIdentityInjector = CallerIdentityInjector.REAL;
+ TimeZoneDetectorService service = new TimeZoneDetectorService(
+ context, handler, callerIdentityInjector, timeZoneDetectorStrategy);
return service;
}
@VisibleForTesting
public TimeZoneDetectorService(@NonNull Context context, @NonNull Handler handler,
+ @NonNull CallerIdentityInjector callerIdentityInjector,
@NonNull TimeZoneDetectorStrategy timeZoneDetectorStrategy) {
mContext = Objects.requireNonNull(context);
mHandler = Objects.requireNonNull(handler);
+ mCallerIdentityInjector = Objects.requireNonNull(callerIdentityInjector);
mTimeZoneDetectorStrategy = Objects.requireNonNull(timeZoneDetectorStrategy);
- mTimeZoneDetectorStrategy.setStrategyListener(new StrategyListener() {
- @Override
- public void onConfigurationChanged() {
- handleConfigurationChanged();
- }
- });
- }
-
- @Override
- @NonNull
- public TimeZoneCapabilities getCapabilities() {
- enforceManageTimeZoneDetectorConfigurationPermission();
- int userId = UserHandle.getCallingUserId();
- long token = Binder.clearCallingIdentity();
- try {
- return mTimeZoneDetectorStrategy.getCapabilities(userId);
- } finally {
- Binder.restoreCallingIdentity(token);
- }
+ // Wire up a change listener so that ITimeZoneConfigurationListeners can be notified when
+ // the configuration changes for any reason.
+ mTimeZoneDetectorStrategy.addConfigChangeListener(this::handleConfigurationChanged);
}
@Override
@NonNull
- public TimeZoneConfiguration getConfiguration() {
+ public TimeZoneCapabilities getCapabilities() {
enforceManageTimeZoneDetectorConfigurationPermission();
- int userId = UserHandle.getCallingUserId();
- long token = Binder.clearCallingIdentity();
+ int userId = mCallerIdentityInjector.getCallingUserId();
+ long token = mCallerIdentityInjector.clearCallingIdentity();
try {
- return mTimeZoneDetectorStrategy.getConfiguration(userId);
+ return mTimeZoneDetectorStrategy.getConfigurationInternal(userId).createCapabilities();
} finally {
- Binder.restoreCallingIdentity(token);
+ mCallerIdentityInjector.restoreCallingIdentity(token);
}
}
@@ -184,12 +153,16 @@ public final class TimeZoneDetectorService extends ITimeZoneDetectorService.Stub
enforceManageTimeZoneDetectorConfigurationPermission();
Objects.requireNonNull(configuration);
- int userId = UserHandle.getCallingUserId();
- long token = Binder.clearCallingIdentity();
+ int callingUserId = mCallerIdentityInjector.getCallingUserId();
+ if (callingUserId != configuration.getUserId()) {
+ return false;
+ }
+
+ long token = mCallerIdentityInjector.clearCallingIdentity();
try {
- return mTimeZoneDetectorStrategy.updateConfiguration(userId, configuration);
+ return mTimeZoneDetectorStrategy.updateConfiguration(configuration);
} finally {
- Binder.restoreCallingIdentity(token);
+ mCallerIdentityInjector.restoreCallingIdentity(token);
}
}
@@ -197,25 +170,17 @@ public final class TimeZoneDetectorService extends ITimeZoneDetectorService.Stub
public void addConfigurationListener(@NonNull ITimeZoneConfigurationListener listener) {
enforceManageTimeZoneDetectorConfigurationPermission();
Objects.requireNonNull(listener);
- int userId = UserHandle.getCallingUserId();
synchronized (mConfigurationListeners) {
- ArrayList<ITimeZoneConfigurationListener> listeners =
- mConfigurationListeners.get(userId);
- if (listeners != null && listeners.contains(listener)) {
+ if (mConfigurationListeners.contains(listener)) {
return;
}
try {
- if (listeners == null) {
- listeners = new ArrayList<>(1);
- mConfigurationListeners.put(userId, listeners);
- }
-
// Ensure the reference to the listener will be removed if the client process dies.
listener.asBinder().linkToDeath(this, 0 /* flags */);
// Only add the listener if we can linkToDeath().
- listeners.add(listener);
+ mConfigurationListeners.add(listener);
} catch (RemoteException e) {
Slog.e(TAG, "Unable to linkToDeath() for listener=" + listener, e);
}
@@ -226,19 +191,16 @@ public final class TimeZoneDetectorService extends ITimeZoneDetectorService.Stub
public void removeConfigurationListener(@NonNull ITimeZoneConfigurationListener listener) {
enforceManageTimeZoneDetectorConfigurationPermission();
Objects.requireNonNull(listener);
- int userId = UserHandle.getCallingUserId();
synchronized (mConfigurationListeners) {
boolean removedListener = false;
- ArrayList<ITimeZoneConfigurationListener> userListeners =
- mConfigurationListeners.get(userId);
- if (userListeners.remove(listener)) {
+ if (mConfigurationListeners.remove(listener)) {
// Stop listening for the client process to die.
listener.asBinder().unlinkToDeath(this, 0 /* flags */);
removedListener = true;
}
if (!removedListener) {
- Slog.w(TAG, "Client asked to remove listenener=" + listener
+ Slog.w(TAG, "Client asked to remove listener=" + listener
+ ", but no listeners were removed."
+ " mConfigurationListeners=" + mConfigurationListeners);
}
@@ -259,19 +221,14 @@ public final class TimeZoneDetectorService extends ITimeZoneDetectorService.Stub
public void binderDied(IBinder who) {
synchronized (mConfigurationListeners) {
boolean removedListener = false;
- final int userCount = mConfigurationListeners.size();
- for (int i = 0; i < userCount; i++) {
- ArrayList<ITimeZoneConfigurationListener> userListeners =
- mConfigurationListeners.valueAt(i);
- Iterator<ITimeZoneConfigurationListener> userListenerIterator =
- userListeners.iterator();
- while (userListenerIterator.hasNext()) {
- ITimeZoneConfigurationListener userListener = userListenerIterator.next();
- if (userListener.asBinder().equals(who)) {
- userListenerIterator.remove();
- removedListener = true;
- break;
- }
+ final int listenerCount = mConfigurationListeners.size();
+ for (int listenerIndex = listenerCount - 1; listenerIndex >= 0; listenerIndex--) {
+ ITimeZoneConfigurationListener listener =
+ mConfigurationListeners.get(listenerIndex);
+ if (listener.asBinder().equals(who)) {
+ mConfigurationListeners.remove(listenerIndex);
+ removedListener = true;
+ break;
}
}
if (!removedListener) {
@@ -283,42 +240,25 @@ public final class TimeZoneDetectorService extends ITimeZoneDetectorService.Stub
}
void handleConfigurationChanged() {
- // Note: we could trigger an async time zone detection operation here via a call to
- // handleAutoTimeZoneConfigChanged(), but that is triggered in response to the underlying
- // setting value changing so it is currently unnecessary. If we get to a point where all
- // configuration changes are guaranteed to happen in response to an updateConfiguration()
- // call, then we can remove that path and call it here instead.
-
// Configuration has changed, but each user may have a different view of the configuration.
// It's possible that this will cause unnecessary notifications but that shouldn't be a
// problem.
synchronized (mConfigurationListeners) {
- final int userCount = mConfigurationListeners.size();
- for (int userIndex = 0; userIndex < userCount; userIndex++) {
- int userId = mConfigurationListeners.keyAt(userIndex);
- TimeZoneConfiguration configuration =
- mTimeZoneDetectorStrategy.getConfiguration(userId);
-
- ArrayList<ITimeZoneConfigurationListener> listeners =
- mConfigurationListeners.valueAt(userIndex);
- final int listenerCount = listeners.size();
- for (int listenerIndex = 0; listenerIndex < listenerCount; listenerIndex++) {
- ITimeZoneConfigurationListener listener = listeners.get(listenerIndex);
- try {
- listener.onChange(configuration);
- } catch (RemoteException e) {
- Slog.w(TAG, "Unable to notify listener=" + listener
- + " for userId=" + userId
- + " of updated configuration=" + configuration, e);
- }
+ final int listenerCount = mConfigurationListeners.size();
+ for (int listenerIndex = 0; listenerIndex < listenerCount; listenerIndex++) {
+ ITimeZoneConfigurationListener listener =
+ mConfigurationListeners.get(listenerIndex);
+ try {
+ listener.onChange();
+ } catch (RemoteException e) {
+ Slog.w(TAG, "Unable to notify listener=" + listener, e);
}
}
}
}
/** Provided for command-line access. This is not exposed as a binder API. */
- void suggestGeolocationTimeZone(
- @NonNull GeolocationTimeZoneSuggestion timeZoneSuggestion) {
+ void suggestGeolocationTimeZone(@NonNull GeolocationTimeZoneSuggestion timeZoneSuggestion) {
enforceSuggestGeolocationTimeZonePermission();
Objects.requireNonNull(timeZoneSuggestion);
@@ -331,12 +271,12 @@ public final class TimeZoneDetectorService extends ITimeZoneDetectorService.Stub
enforceSuggestManualTimeZonePermission();
Objects.requireNonNull(timeZoneSuggestion);
- int userId = UserHandle.getCallingUserId();
- long token = Binder.clearCallingIdentity();
+ int userId = mCallerIdentityInjector.getCallingUserId();
+ long token = mCallerIdentityInjector.clearCallingIdentity();
try {
return mTimeZoneDetectorStrategy.suggestManualTimeZone(userId, timeZoneSuggestion);
} finally {
- Binder.restoreCallingIdentity(token);
+ mCallerIdentityInjector.restoreCallingIdentity(token);
}
}
@@ -358,12 +298,6 @@ public final class TimeZoneDetectorService extends ITimeZoneDetectorService.Stub
ipw.flush();
}
- /** Internal method for handling the auto time zone configuration being changed. */
- @VisibleForTesting
- public void handleAutoTimeZoneConfigChanged() {
- mHandler.post(mTimeZoneDetectorStrategy::handleAutoTimeZoneConfigChanged);
- }
-
private void enforceManageTimeZoneDetectorConfigurationPermission() {
// TODO Switch to a dedicated MANAGE_TIME_AND_ZONE_CONFIGURATION permission.
mContext.enforceCallingPermission(
diff --git a/services/core/java/com/android/server/timezonedetector/TimeZoneDetectorStrategy.java b/services/core/java/com/android/server/timezonedetector/TimeZoneDetectorStrategy.java
index c5b7e39f4fef..f944c5638fa9 100644
--- a/services/core/java/com/android/server/timezonedetector/TimeZoneDetectorStrategy.java
+++ b/services/core/java/com/android/server/timezonedetector/TimeZoneDetectorStrategy.java
@@ -19,51 +19,84 @@ import android.annotation.NonNull;
import android.annotation.UserIdInt;
import android.app.timezonedetector.ManualTimeZoneSuggestion;
import android.app.timezonedetector.TelephonyTimeZoneSuggestion;
-import android.app.timezonedetector.TimeZoneCapabilities;
import android.app.timezonedetector.TimeZoneConfiguration;
import android.util.IndentingPrintWriter;
/**
- * The interface for the class that implements the time detection algorithm used by the
- * {@link TimeZoneDetectorService}.
+ * The interface for the class that is responsible for setting the time zone on a device, used by
+ * {@link TimeZoneDetectorService} and {@link TimeZoneDetectorInternal}.
*
- * <p>The strategy uses suggestions to decide whether to modify the device's time zone setting
- * and what to set it to.
+ * <p>The strategy receives suggestions, which it may use to modify the device's time zone setting.
+ * Suggestions are acted on or ignored as needed, depending on previously received suggestions and
+ * the current user's configuration (see {@link ConfigurationInternal}).
*
- * <p>Most calls will be handled by a single thread, but that is not true for all calls. For example
- * {@link #dump(IndentingPrintWriter, String[])}) may be called on a different thread concurrently
- * with other operations so implementations must still handle thread safety.
+ * <p>Devices can have zero, one or two automatic time zone detection algorithm available at any
+ * point in time.
+ *
+ * <p>The two automatic detection algorithms supported are "telephony" and "geolocation". Algorithm
+ * availability and use depends on several factors:
+ * <ul>
+ * <li>Telephony is only available on devices with a telephony stack.
+ * <li>Geolocation is also optional and configured at image creation time. When enabled on a
+ * device, its availability depends on the current user's settings, so switching between users can
+ * change the automatic algorithm used by the device.</li>
+ * </ul>
+ *
+ * <p>If there are no automatic time zone detections algorithms available then the user can usually
+ * change the device time zone manually. Under most circumstances the current user can turn
+ * automatic time zone detection on or off, or choose the algorithm via settings.
+ *
+ * <p>Telephony detection is independent of the current user. The device keeps track of the most
+ * recent telephony suggestion from each slotIndex. When telephony detection is in use, the highest
+ * scoring suggestion is used to set the device time zone based on a scoring algorithm. If several
+ * slotIndexes provide the same score then the slotIndex with the lowest numeric value "wins". If
+ * the situation changes and it is no longer possible to be confident about the time zone,
+ * slotIndexes must have an empty suggestion submitted in order to "withdraw" their previous
+ * suggestion otherwise it will remain in use.
+ *
+ * <p>Geolocation detection is dependent on the current user and their settings. The device retains
+ * at most one geolocation suggestion. Generally, use of a device's location is dependent on the
+ * user's "location toggle", but even when that is enabled the user may choose to enable / disable
+ * the use of geolocation for device time zone detection. If the current user changes to one that
+ * does not have geolocation detection enabled, or the user turns off geolocation detection, then
+ * the strategy discards the latest geolocation suggestion. Devices that lose a location fix must
+ * have an empty suggestion submitted in order to "withdraw" their previous suggestion otherwise it
+ * will remain in use.
+ *
+ * <p>Threading:
+ *
+ * <p>Suggestion calls with a void return type may be handed off to a separate thread and handled
+ * asynchronously. Synchronous calls like {@link #getCurrentUserConfigurationInternal()}, and debug
+ * calls like {@link #dump(IndentingPrintWriter, String[])}, may be called on a different thread
+ * concurrently with other operations.
*
* @hide
*/
public interface TimeZoneDetectorStrategy extends Dumpable, Dumpable.Container {
- /** A listener for strategy events. */
- interface StrategyListener {
- /**
- * Invoked when configuration has been changed.
- */
- void onConfigurationChanged();
- }
-
- /** Sets the listener that enables the strategy to communicate with the surrounding service. */
- void setStrategyListener(@NonNull StrategyListener listener);
+ /**
+ * Sets a listener that will be triggered whenever time zone detection configuration is
+ * changed.
+ */
+ void addConfigChangeListener(@NonNull ConfigurationChangeListener listener);
- /** Returns the user's time zone capabilities. */
+ /** Returns the user's time zone configuration. */
@NonNull
- TimeZoneCapabilities getCapabilities(@UserIdInt int userId);
+ ConfigurationInternal getConfigurationInternal(@UserIdInt int userId);
/**
- * Returns the configuration that controls time zone detector behavior.
+ * Returns the configuration that controls time zone detector behavior for the current user.
*/
@NonNull
- TimeZoneConfiguration getConfiguration(@UserIdInt int userId);
+ ConfigurationInternal getCurrentUserConfigurationInternal();
/**
- * Updates the configuration settings that control time zone detector behavior.
+ * Updates the configuration properties that control a device's time zone behavior.
+ *
+ * <p>This method returns {@code true} if the configuration was changed,
+ * {@code false} otherwise.
*/
- boolean updateConfiguration(
- @UserIdInt int userId, @NonNull TimeZoneConfiguration configuration);
+ boolean updateConfiguration(@NonNull TimeZoneConfiguration configuration);
/**
* Suggests zero, one or more time zones for the device, or withdraws a previous suggestion if
@@ -85,9 +118,4 @@ public interface TimeZoneDetectorStrategy extends Dumpable, Dumpable.Container {
* suggestion.
*/
void suggestTelephonyTimeZone(@NonNull TelephonyTimeZoneSuggestion suggestion);
-
- /**
- * Called when there has been a change to the automatic time zone detection configuration.
- */
- void handleAutoTimeZoneConfigChanged();
}
diff --git a/services/core/java/com/android/server/timezonedetector/TimeZoneDetectorStrategyImpl.java b/services/core/java/com/android/server/timezonedetector/TimeZoneDetectorStrategyImpl.java
index d1369a289428..8a42b18b514f 100644
--- a/services/core/java/com/android/server/timezonedetector/TimeZoneDetectorStrategyImpl.java
+++ b/services/core/java/com/android/server/timezonedetector/TimeZoneDetectorStrategyImpl.java
@@ -20,10 +20,7 @@ import static android.app.timezonedetector.TelephonyTimeZoneSuggestion.MATCH_TYP
import static android.app.timezonedetector.TelephonyTimeZoneSuggestion.QUALITY_MULTIPLE_ZONES_WITH_DIFFERENT_OFFSETS;
import static android.app.timezonedetector.TelephonyTimeZoneSuggestion.QUALITY_MULTIPLE_ZONES_WITH_SAME_OFFSET;
import static android.app.timezonedetector.TelephonyTimeZoneSuggestion.QUALITY_SINGLE_ZONE;
-import static android.app.timezonedetector.TimeZoneCapabilities.CAPABILITY_NOT_APPLICABLE;
import static android.app.timezonedetector.TimeZoneCapabilities.CAPABILITY_POSSESSED;
-import static android.app.timezonedetector.TimeZoneConfiguration.PROPERTY_AUTO_DETECTION_ENABLED;
-import static android.app.timezonedetector.TimeZoneConfiguration.PROPERTY_GEO_DETECTION_ENABLED;
import android.annotation.NonNull;
import android.annotation.Nullable;
@@ -33,6 +30,7 @@ import android.app.timezonedetector.TelephonyTimeZoneSuggestion;
import android.app.timezonedetector.TimeZoneCapabilities;
import android.app.timezonedetector.TimeZoneConfiguration;
import android.content.Context;
+import android.os.Handler;
import android.util.IndentingPrintWriter;
import android.util.LocalLog;
import android.util.Slog;
@@ -45,15 +43,7 @@ import java.util.List;
import java.util.Objects;
/**
- * An implementation of {@link TimeZoneDetectorStrategy} that handle telephony and manual
- * suggestions. Suggestions are acted on or ignored as needed, dependent on the current "auto time
- * zone detection" setting.
- *
- * <p>For automatic detection, it keeps track of the most recent telephony suggestion from each
- * slotIndex and it uses the best suggestion based on a scoring algorithm. If several slotIndexes
- * provide the same score then the slotIndex with the lowest numeric value "wins". If the situation
- * changes and it is no longer possible to be confident about the time zone, slotIndexes must have
- * an empty suggestion submitted in order to "withdraw" their previous suggestion.
+ * The real implementation of {@link TimeZoneDetectorStrategy}.
*
* <p>Most public methods are marked synchronized to ensure thread safety around internal state.
*/
@@ -61,48 +51,27 @@ public final class TimeZoneDetectorStrategyImpl implements TimeZoneDetectorStrat
/**
* Used by {@link TimeZoneDetectorStrategyImpl} to interact with device configuration / settings
- * / system properties. It can be faked for testing different scenarios.
+ * / system properties. It can be faked for testing.
*
* <p>Note: Because the settings / system properties-derived values can currently be modified
- * independently and from different threads (and processes!), their use are prone to race
- * conditions. That will be true until the responsibility for setting their values is moved to
- * {@link TimeZoneDetectorStrategyImpl} (which is thread safe).
+ * independently and from different threads (and processes!), their use is prone to race
+ * conditions.
*/
@VisibleForTesting
public interface Callback {
/**
- * Returns the capabilities for the user.
- */
- @NonNull
- TimeZoneCapabilities getCapabilities(@UserIdInt int userId);
-
- /**
- * Returns the configuration for the user.
- * @param userId
+ * Sets a {@link ConfigurationChangeListener} that will be invoked when there are any
+ * changes that could affect time zone detection. This is invoked during system server
+ * setup.
*/
- @NonNull
- TimeZoneConfiguration getConfiguration(int userId);
+ void setConfigChangeListener(@NonNull ConfigurationChangeListener listener);
- /**
- * Sets the configuration for the user. This method handles storage only, the configuration
- * must have been validated by the caller and be complete.
- *
- * @throws IllegalArgumentException if {@link TimeZoneConfiguration#isComplete()}
- * returns {@code false}
- */
- void setConfiguration(@UserIdInt int userId, @NonNull TimeZoneConfiguration configuration);
-
- /**
- * Returns true if automatic time zone detection is currently enabled.
- */
- boolean isAutoDetectionEnabled();
+ /** Returns the current user at the instant it is called. */
+ @UserIdInt int getCurrentUserId();
- /**
- * Returns whether geolocation can be used for time zone detection when {@link
- * #isAutoDetectionEnabled()} returns {@code true}.
- */
- boolean isGeoDetectionEnabled();
+ /** Returns the {@link ConfigurationInternal} for the specified user. */
+ ConfigurationInternal getConfigurationInternal(@UserIdInt int userId);
/**
* Returns true if the device has had an explicit time zone set.
@@ -118,6 +87,13 @@ public final class TimeZoneDetectorStrategyImpl implements TimeZoneDetectorStrat
* Sets the device's time zone.
*/
void setDeviceTimeZone(@NonNull String zoneId);
+
+ /**
+ * Stores the configuration properties contained in {@code newConfiguration}.
+ * All checks about user capabilities must be done by the caller and
+ * {@link TimeZoneConfiguration#isComplete()} must be {@code true}.
+ */
+ void storeConfiguration(TimeZoneConfiguration newConfiguration);
}
private static final String LOG_TAG = "TimeZoneDetectorStrategy";
@@ -189,9 +165,9 @@ public final class TimeZoneDetectorStrategyImpl implements TimeZoneDetectorStrat
@NonNull
private final Callback mCallback;
- /** Non-null after {@link #setStrategyListener(StrategyListener)} is called. */
- @Nullable
- private StrategyListener mListener;
+ @GuardedBy("this")
+ @NonNull
+ private List<ConfigurationChangeListener> mConfigChangeListeners = new ArrayList<>();
/**
* A log that records the decisions / decision metadata that affected the device's time zone.
@@ -211,7 +187,8 @@ public final class TimeZoneDetectorStrategyImpl implements TimeZoneDetectorStrat
new ArrayMapWithHistory<>(KEEP_SUGGESTION_HISTORY_SIZE);
/**
- * The latest geolocation suggestion received.
+ * The latest geolocation suggestion received. If the user disabled geolocation time zone
+ * detection then the latest suggestion is cleared.
*/
@GuardedBy("this")
private ReferenceWithHistory<GeolocationTimeZoneSuggestion> mLatestGeoLocationSuggestion =
@@ -223,113 +200,120 @@ public final class TimeZoneDetectorStrategyImpl implements TimeZoneDetectorStrat
/**
* Creates a new instance of {@link TimeZoneDetectorStrategyImpl}.
*/
- public static TimeZoneDetectorStrategyImpl create(Context context) {
- Callback timeZoneDetectionServiceHelper = new TimeZoneDetectorCallbackImpl(context);
- return new TimeZoneDetectorStrategyImpl(timeZoneDetectionServiceHelper);
+ public static TimeZoneDetectorStrategyImpl create(
+ @NonNull Context context, @NonNull Handler handler,
+ boolean geolocationTimeZoneDetectionEnabled) {
+
+ TimeZoneDetectorCallbackImpl callback = new TimeZoneDetectorCallbackImpl(
+ context, handler, geolocationTimeZoneDetectionEnabled);
+ return new TimeZoneDetectorStrategyImpl(callback);
}
@VisibleForTesting
- public TimeZoneDetectorStrategyImpl(Callback callback) {
+ public TimeZoneDetectorStrategyImpl(@NonNull Callback callback) {
mCallback = Objects.requireNonNull(callback);
+ mCallback.setConfigChangeListener(this::handleConfigChanged);
}
/**
- * Sets a listener that allows the strategy to communicate with the surrounding service. This
- * must be called before the instance is used and must only be called once.
+ * Adds a listener that allows the strategy to communicate with the surrounding service /
+ * internal. This must be called before the instance is used.
*/
@Override
- public synchronized void setStrategyListener(@NonNull StrategyListener listener) {
- if (mListener != null) {
- throw new IllegalStateException("Strategy already has a listener");
- }
- mListener = Objects.requireNonNull(listener);
+ public synchronized void addConfigChangeListener(
+ @NonNull ConfigurationChangeListener listener) {
+ Objects.requireNonNull(listener);
+ mConfigChangeListeners.add(listener);
}
@Override
@NonNull
- public synchronized TimeZoneCapabilities getCapabilities(@UserIdInt int userId) {
- return mCallback.getCapabilities(userId);
+ public ConfigurationInternal getConfigurationInternal(@UserIdInt int userId) {
+ return mCallback.getConfigurationInternal(userId);
}
@Override
@NonNull
- public synchronized TimeZoneConfiguration getConfiguration(@UserIdInt int userId) {
- return mCallback.getConfiguration(userId);
+ public synchronized ConfigurationInternal getCurrentUserConfigurationInternal() {
+ int currentUserId = mCallback.getCurrentUserId();
+ return getConfigurationInternal(currentUserId);
}
@Override
public synchronized boolean updateConfiguration(
- @UserIdInt int userId, @NonNull TimeZoneConfiguration configurationChanges) {
- Objects.requireNonNull(configurationChanges);
-
- // Validate the requested configuration changes before applying any of them.
- TimeZoneCapabilities capabilities = mCallback.getCapabilities(userId);
- boolean canManageTimeZoneDetection =
- capabilities.getConfigureAutoDetectionEnabled() >= CAPABILITY_NOT_APPLICABLE;
- if (!canManageTimeZoneDetection
- && containsAutoTimeDetectionProperties(configurationChanges)) {
+ @NonNull TimeZoneConfiguration requestedConfiguration) {
+ Objects.requireNonNull(requestedConfiguration);
+
+ int userId = requestedConfiguration.getUserId();
+ TimeZoneCapabilities capabilities = getConfigurationInternal(userId).createCapabilities();
+
+ // Create a new configuration builder, and copy across the mutable properties users are
+ // able to modify. Other properties are therefore ignored.
+ final TimeZoneConfiguration newConfiguration =
+ capabilities.applyUpdate(requestedConfiguration);
+ if (newConfiguration == null) {
+ // The changes could not be made due to
return false;
}
- // Create a complete configuration by merging the existing and new (possibly partial)
- // configuration.
- final TimeZoneConfiguration oldConfiguration = mCallback.getConfiguration(userId);
- final TimeZoneConfiguration newConfiguration =
- new TimeZoneConfiguration.Builder(oldConfiguration)
- .mergeProperties(configurationChanges)
- .build();
-
- // Set the configuration / notify as needed.
- boolean configurationChanged = !oldConfiguration.equals(newConfiguration);
- if (configurationChanged) {
- mCallback.setConfiguration(userId, newConfiguration);
-
- String logMsg = "Configuration changed:"
- + "oldConfiguration=" + oldConfiguration
- + ", configuration=" + configurationChanges
- + ", newConfiguration=" + newConfiguration;
- mTimeZoneChangesLog.log(logMsg);
- if (DBG) {
- Slog.d(LOG_TAG, logMsg);
- }
- mListener.onConfigurationChanged();
+ // Store the configuration / notify as needed. This will cause the mCallback to invoke
+ // handleConfigChanged() asynchronously.
+ mCallback.storeConfiguration(newConfiguration);
+
+ TimeZoneConfiguration oldConfiguration = capabilities.getConfiguration();
+ String logMsg = "Configuration changed:"
+ + " oldConfiguration=" + oldConfiguration
+ + ", newConfiguration=" + newConfiguration;
+ mTimeZoneChangesLog.log(logMsg);
+ if (DBG) {
+ Slog.d(LOG_TAG, logMsg);
}
return true;
}
- private static boolean containsAutoTimeDetectionProperties(
- @NonNull TimeZoneConfiguration configuration) {
- return configuration.hasProperty(PROPERTY_AUTO_DETECTION_ENABLED)
- || configuration.hasProperty(PROPERTY_GEO_DETECTION_ENABLED);
- }
-
@Override
public synchronized void suggestGeolocationTimeZone(
@NonNull GeolocationTimeZoneSuggestion suggestion) {
+
+ int currentUserId = mCallback.getCurrentUserId();
+ ConfigurationInternal currentUserConfig = mCallback.getConfigurationInternal(currentUserId);
if (DBG) {
- Slog.d(LOG_TAG, "Geolocation suggestion received. newSuggestion=" + suggestion);
+ Slog.d(LOG_TAG, "Geolocation suggestion received."
+ + " currentUserConfig=" + currentUserConfig
+ + " newSuggestion=" + suggestion);
}
-
Objects.requireNonNull(suggestion);
- mLatestGeoLocationSuggestion.set(suggestion);
- // Now perform auto time zone detection. The new suggestion may be used to modify the time
- // zone setting.
- if (mCallback.isGeoDetectionEnabled()) {
+ if (currentUserConfig.getGeoDetectionEnabledBehavior()) {
+ // Only store a geolocation suggestion if geolocation detection is currently enabled.
+ mLatestGeoLocationSuggestion.set(suggestion);
+
+ // Now perform auto time zone detection. The new suggestion may be used to modify the
+ // time zone setting.
String reason = "New geolocation time zone suggested. suggestion=" + suggestion;
- doAutoTimeZoneDetection(reason);
+ doAutoTimeZoneDetection(currentUserConfig, reason);
}
}
@Override
public synchronized boolean suggestManualTimeZone(
@UserIdInt int userId, @NonNull ManualTimeZoneSuggestion suggestion) {
+
+ int currentUserId = mCallback.getCurrentUserId();
+ if (userId != currentUserId) {
+ Slog.w(LOG_TAG, "Manual suggestion received but user != current user, userId=" + userId
+ + " suggestion=" + suggestion);
+
+ // Only listen to changes from the current user.
+ return false;
+ }
+
Objects.requireNonNull(suggestion);
String timeZoneId = suggestion.getZoneId();
String cause = "Manual time suggestion received: suggestion=" + suggestion;
- TimeZoneCapabilities capabilities = mCallback.getCapabilities(userId);
+ TimeZoneCapabilities capabilities = getConfigurationInternal(userId).createCapabilities();
if (capabilities.getSuggestManualTimeZone() != CAPABILITY_POSSESSED) {
Slog.i(LOG_TAG, "User does not have the capability needed to set the time zone manually"
+ ", capabilities=" + capabilities
@@ -345,8 +329,12 @@ public final class TimeZoneDetectorStrategyImpl implements TimeZoneDetectorStrat
@Override
public synchronized void suggestTelephonyTimeZone(
@NonNull TelephonyTimeZoneSuggestion suggestion) {
+
+ int currentUserId = mCallback.getCurrentUserId();
+ ConfigurationInternal currentUserConfig = mCallback.getConfigurationInternal(currentUserId);
if (DBG) {
- Slog.d(LOG_TAG, "Telephony suggestion received. newSuggestion=" + suggestion);
+ Slog.d(LOG_TAG, "Telephony suggestion received. currentUserConfig=" + currentUserConfig
+ + " newSuggestion=" + suggestion);
}
Objects.requireNonNull(suggestion);
@@ -360,9 +348,9 @@ public final class TimeZoneDetectorStrategyImpl implements TimeZoneDetectorStrat
// Now perform auto time zone detection. The new suggestion may be used to modify the time
// zone setting.
- if (!mCallback.isGeoDetectionEnabled()) {
+ if (!currentUserConfig.getGeoDetectionEnabledBehavior()) {
String reason = "New telephony time zone suggested. suggestion=" + suggestion;
- doAutoTimeZoneDetection(reason);
+ doAutoTimeZoneDetection(currentUserConfig, reason);
}
}
@@ -392,15 +380,15 @@ public final class TimeZoneDetectorStrategyImpl implements TimeZoneDetectorStrat
* Performs automatic time zone detection.
*/
@GuardedBy("this")
- private void doAutoTimeZoneDetection(@NonNull String detectionReason) {
- if (!mCallback.isAutoDetectionEnabled()) {
- // Avoid doing unnecessary work with this (race-prone) check.
+ private void doAutoTimeZoneDetection(
+ @NonNull ConfigurationInternal currentUserConfig, @NonNull String detectionReason) {
+ if (!currentUserConfig.getAutoDetectionEnabledBehavior()) {
+ // Avoid doing unnecessary work.
return;
}
- // Use the right suggestions based on the current configuration. This check is potentially
- // race-prone until this value is set via a call to TimeZoneDetectorStrategy.
- if (mCallback.isGeoDetectionEnabled()) {
+ // Use the right suggestions based on the current configuration.
+ if (currentUserConfig.getGeoDetectionEnabledBehavior()) {
doGeolocationTimeZoneDetection(detectionReason);
} else {
doTelephonyTimeZoneDetection(detectionReason);
@@ -480,35 +468,18 @@ public final class TimeZoneDetectorStrategyImpl implements TimeZoneDetectorStrat
// Paranoia: Every suggestion above the SCORE_USAGE_THRESHOLD should have a non-null time
// zone ID.
- String newZoneId = bestTelephonySuggestion.suggestion.getZoneId();
- if (newZoneId == null) {
+ String zoneId = bestTelephonySuggestion.suggestion.getZoneId();
+ if (zoneId == null) {
Slog.w(LOG_TAG, "Empty zone suggestion scored higher than expected. This is an error:"
+ " bestTelephonySuggestion=" + bestTelephonySuggestion
+ " detectionReason=" + detectionReason);
return;
}
- String zoneId = bestTelephonySuggestion.suggestion.getZoneId();
String cause = "Found good suggestion."
+ ", bestTelephonySuggestion=" + bestTelephonySuggestion
+ ", detectionReason=" + detectionReason;
- setAutoDeviceTimeZoneIfRequired(zoneId, cause);
- }
-
- @GuardedBy("this")
- private void setAutoDeviceTimeZoneIfRequired(@NonNull String newZoneId, @NonNull String cause) {
- Objects.requireNonNull(newZoneId);
- Objects.requireNonNull(cause);
-
- if (!mCallback.isAutoDetectionEnabled()) {
- if (DBG) {
- Slog.d(LOG_TAG, "Auto time zone detection is not enabled."
- + ", newZoneId=" + newZoneId
- + ", cause=" + cause);
- }
- return;
- }
- setDeviceTimeZoneIfRequired(newZoneId, cause);
+ setDeviceTimeZoneIfRequired(zoneId, cause);
}
@GuardedBy("this")
@@ -582,13 +553,39 @@ public final class TimeZoneDetectorStrategyImpl implements TimeZoneDetectorStrat
return findBestTelephonySuggestion();
}
- @Override
- public synchronized void handleAutoTimeZoneConfigChanged() {
+ private synchronized void handleConfigChanged() {
if (DBG) {
- Slog.d(LOG_TAG, "handleAutoTimeZoneConfigChanged()");
+ Slog.d(LOG_TAG, "handleConfigChanged()");
+ }
+
+ clearGeolocationSuggestionIfNeeded();
+
+ for (ConfigurationChangeListener listener : mConfigChangeListeners) {
+ listener.onChange();
+ }
+ }
+
+ @GuardedBy("this")
+ private void clearGeolocationSuggestionIfNeeded() {
+ // This method is called whenever the user changes or the config for any user changes. We
+ // don't know what happened, so we capture the current user's config, check to see if we
+ // need to clear state associated with a previous user, and rerun detection.
+ int currentUserId = mCallback.getCurrentUserId();
+ ConfigurationInternal currentUserConfig = mCallback.getConfigurationInternal(currentUserId);
+
+ GeolocationTimeZoneSuggestion latestGeoLocationSuggestion =
+ mLatestGeoLocationSuggestion.get();
+ if (latestGeoLocationSuggestion != null
+ && !currentUserConfig.getGeoDetectionEnabledBehavior()) {
+ // The current user's config has geodetection disabled, so clear the latest suggestion.
+ // This is done to ensure we only ever keep a geolocation suggestion if the user has
+ // said it is ok to do so.
+ mLatestGeoLocationSuggestion.set(null);
+ mTimeZoneChangesLog.log(
+ "clearGeolocationSuggestionIfNeeded: Cleared latest Geolocation suggestion.");
}
- doAutoTimeZoneDetection("handleAutoTimeZoneConfigChanged()");
+ doAutoTimeZoneDetection(currentUserConfig, "clearGeolocationSuggestionIfNeeded()");
}
@Override
@@ -604,11 +601,14 @@ public final class TimeZoneDetectorStrategyImpl implements TimeZoneDetectorStrat
ipw.println("TimeZoneDetectorStrategy:");
ipw.increaseIndent(); // level 1
- ipw.println("mCallback.isAutoDetectionEnabled()=" + mCallback.isAutoDetectionEnabled());
+ int currentUserId = mCallback.getCurrentUserId();
+ ipw.println("mCallback.getCurrentUserId()=" + currentUserId);
+ ConfigurationInternal configuration = mCallback.getConfigurationInternal(currentUserId);
+ ipw.println("mCallback.getConfiguration(currentUserId)=" + configuration);
+ ipw.println("[Capabilities=" + configuration.createCapabilities() + "]");
ipw.println("mCallback.isDeviceTimeZoneInitialized()="
+ mCallback.isDeviceTimeZoneInitialized());
ipw.println("mCallback.getDeviceTimeZone()=" + mCallback.getDeviceTimeZone());
- ipw.println("mCallback.isGeoDetectionEnabled()=" + mCallback.isGeoDetectionEnabled());
ipw.println("Time zone change log:");
ipw.increaseIndent(); // level 2
diff --git a/services/core/java/com/android/server/trust/TrustManagerService.java b/services/core/java/com/android/server/trust/TrustManagerService.java
index 0c85387be695..386f390c6cb9 100644
--- a/services/core/java/com/android/server/trust/TrustManagerService.java
+++ b/services/core/java/com/android/server/trust/TrustManagerService.java
@@ -379,7 +379,7 @@ public class TrustManagerService extends SystemService {
}
private void updateTrustAll() {
- List<UserInfo> userInfos = mUserManager.getUsers(true /* excludeDying */);
+ List<UserInfo> userInfos = mUserManager.getAliveUsers();
for (UserInfo userInfo : userInfos) {
updateTrust(userInfo.id, 0);
}
@@ -485,7 +485,7 @@ public class TrustManagerService extends SystemService {
List<UserInfo> userInfos;
if (userIdOrAll == UserHandle.USER_ALL) {
- userInfos = mUserManager.getUsers(true /* excludeDying */);
+ userInfos = mUserManager.getAliveUsers();
} else {
userInfos = new ArrayList<>();
userInfos.add(mUserManager.getUserInfo(userIdOrAll));
@@ -644,7 +644,7 @@ public class TrustManagerService extends SystemService {
}
List<UserInfo> userInfos;
if (userId == UserHandle.USER_ALL) {
- userInfos = mUserManager.getUsers(true /* excludeDying */);
+ userInfos = mUserManager.getAliveUsers();
} else {
userInfos = new ArrayList<>();
userInfos.add(mUserManager.getUserInfo(userId));
@@ -1171,7 +1171,7 @@ public class TrustManagerService extends SystemService {
fout.println("disabled because the third-party apps can't run yet.");
return;
}
- final List<UserInfo> userInfos = mUserManager.getUsers(true /* excludeDying */);
+ final List<UserInfo> userInfos = mUserManager.getAliveUsers();
mHandler.runWithScissors(new Runnable() {
@Override
public void run() {
diff --git a/services/core/java/com/android/server/uri/UriGrantsManagerService.java b/services/core/java/com/android/server/uri/UriGrantsManagerService.java
index a106dc682208..0b0bb7059f3b 100644
--- a/services/core/java/com/android/server/uri/UriGrantsManagerService.java
+++ b/services/core/java/com/android/server/uri/UriGrantsManagerService.java
@@ -258,7 +258,7 @@ public class UriGrantsManagerService extends IUriGrantsManager.Stub {
final int callingUid = Binder.getCallingUid();
final int callingUserId = UserHandle.getUserId(callingUid);
final PackageManagerInternal pm = LocalServices.getService(PackageManagerInternal.class);
- final int packageUid = pm.getPackageUidInternal(packageName,
+ final int packageUid = pm.getPackageUid(packageName,
MATCH_DIRECT_BOOT_AWARE | MATCH_DIRECT_BOOT_UNAWARE, callingUserId);
if (packageUid != callingUid) {
throw new SecurityException(
@@ -336,7 +336,7 @@ public class UriGrantsManagerService extends IUriGrantsManager.Stub {
if (toPackage != null) {
mAmInternal.enforceCallingPermission(FORCE_PERSISTABLE_URI_PERMISSIONS,
"takePersistableUriPermission");
- uid = mPmInternal.getPackageUidInternal(toPackage, 0, userId);
+ uid = mPmInternal.getPackageUid(toPackage, 0 /* flags */, userId);
} else {
enforceNotIsolatedCaller("takePersistableUriPermission");
uid = Binder.getCallingUid();
@@ -401,7 +401,7 @@ public class UriGrantsManagerService extends IUriGrantsManager.Stub {
if (toPackage != null) {
mAmInternal.enforceCallingPermission(FORCE_PERSISTABLE_URI_PERMISSIONS,
"releasePersistableUriPermission");
- uid = mPmInternal.getPackageUidInternal(toPackage, 0, userId);
+ uid = mPmInternal.getPackageUid(toPackage, 0 /* flags */ , userId);
} else {
enforceNotIsolatedCaller("releasePersistableUriPermission");
uid = Binder.getCallingUid();
@@ -600,7 +600,7 @@ public class UriGrantsManagerService extends IUriGrantsManager.Stub {
if (needed != null) {
targetUid = needed.targetUid;
} else {
- targetUid = mPmInternal.getPackageUidInternal(targetPkg, MATCH_DEBUG_TRIAGED_MISSING,
+ targetUid = mPmInternal.getPackageUid(targetPkg, MATCH_DEBUG_TRIAGED_MISSING,
targetUserId);
if (targetUid < 0) {
if (DEBUG) Slog.v(TAG, "Can't grant URI permission no uid for: " + targetPkg
@@ -690,7 +690,7 @@ public class UriGrantsManagerService extends IUriGrantsManager.Stub {
final ProviderInfo pi = getProviderInfo(uri.getAuthority(), sourceUserId,
MATCH_DIRECT_BOOT_AWARE | MATCH_DIRECT_BOOT_UNAWARE);
if (pi != null && sourcePkg.equals(pi.packageName)) {
- int targetUid = mPmInternal.getPackageUidInternal(
+ int targetUid = mPmInternal.getPackageUid(
targetPkg, MATCH_UNINSTALLED_PACKAGES, targetUserId);
if (targetUid != -1) {
final GrantUri grantUri = new GrantUri(sourceUserId, uri,
@@ -787,7 +787,7 @@ public class UriGrantsManagerService extends IUriGrantsManager.Stub {
if (targetPkg == null) {
throw new NullPointerException("targetPkg");
}
- int targetUid = mPmInternal.getPackageUidInternal(targetPkg, MATCH_DEBUG_TRIAGED_MISSING,
+ int targetUid = mPmInternal.getPackageUid(targetPkg, MATCH_DEBUG_TRIAGED_MISSING,
targetUserId);
targetUid = checkGrantUriPermissionUnlocked(callingUid, targetPkg, grantUri, modeFlags,
@@ -1108,7 +1108,7 @@ public class UriGrantsManagerService extends IUriGrantsManager.Stub {
int targetUid = lastTargetUid;
if (targetUid < 0 && targetPkg != null) {
- targetUid = mPmInternal.getPackageUidInternal(targetPkg, MATCH_DEBUG_TRIAGED_MISSING,
+ targetUid = mPmInternal.getPackageUid(targetPkg, MATCH_DEBUG_TRIAGED_MISSING,
UserHandle.getUserId(callingUid));
if (targetUid < 0) {
if (DEBUG) Slog.v(TAG, "Can't grant URI permission no uid for: " + targetPkg);
@@ -1462,7 +1462,8 @@ public class UriGrantsManagerService extends IUriGrantsManager.Stub {
boolean printed = false;
int dumpUid = -2;
if (dumpPackage != null) {
- dumpUid = mPmInternal.getPackageUidInternal(dumpPackage, MATCH_ANY_USER, 0);
+ dumpUid = mPmInternal.getPackageUid(dumpPackage,
+ MATCH_ANY_USER, 0 /* userId */);
}
for (int i = 0; i < mGrantedUriPermissions.size(); i++) {
int uid = mGrantedUriPermissions.keyAt(i);
diff --git a/services/core/java/com/android/server/webkit/WebViewUpdateService.java b/services/core/java/com/android/server/webkit/WebViewUpdateService.java
index 9bbeb728ae33..90a153be8800 100644
--- a/services/core/java/com/android/server/webkit/WebViewUpdateService.java
+++ b/services/core/java/com/android/server/webkit/WebViewUpdateService.java
@@ -209,8 +209,8 @@ public class WebViewUpdateService extends SystemService {
private void grantVisibilityToCaller(String webViewPackageName, int callingUid) {
final PackageManagerInternal pmInternal = LocalServices.getService(
PackageManagerInternal.class);
- final int webviewUid = pmInternal.getPackageUidInternal(
- webViewPackageName, 0, UserHandle.getUserId(callingUid));
+ final int webviewUid = pmInternal.getPackageUid(
+ webViewPackageName, 0 /* flags */, UserHandle.getUserId(callingUid));
pmInternal.grantImplicitAccess(UserHandle.getUserId(callingUid), null,
UserHandle.getAppId(callingUid), webviewUid,
true /*direct*/);
diff --git a/services/core/java/com/android/server/wm/AccessibilityController.java b/services/core/java/com/android/server/wm/AccessibilityController.java
index 1536473ff0a1..4c2d0d08cd4e 100644
--- a/services/core/java/com/android/server/wm/AccessibilityController.java
+++ b/services/core/java/com/android/server/wm/AccessibilityController.java
@@ -700,8 +700,8 @@ final class AccessibilityController {
touchableRegion.getBounds(touchableFrame);
RectF windowFrame = mTempRectF;
windowFrame.set(touchableFrame);
- windowFrame.offset(-windowState.getFrameLw().left,
- -windowState.getFrameLw().top);
+ windowFrame.offset(-windowState.getFrame().left,
+ -windowState.getFrame().top);
matrix.mapRect(windowFrame);
Region windowBounds = mTempRegion2;
windowBounds.set((int) windowFrame.left, (int) windowFrame.top,
@@ -730,7 +730,7 @@ final class AccessibilityController {
}
// Count letterbox into nonMagnifiedBounds
- if (windowState.isLetterboxedForDisplayCutoutLw()) {
+ if (windowState.isLetterboxedForDisplayCutout()) {
Region letterboxBounds = getLetterboxBounds(windowState);
nonMagnifiedBounds.op(letterboxBounds, Region.Op.UNION);
availableBounds.op(letterboxBounds, Region.Op.DIFFERENCE);
@@ -1429,11 +1429,11 @@ final class AccessibilityController {
// Account for all space in the task, whether the windows in it are
// touchable or not. The modal window blocks all touches from the task's
// area.
- unaccountedSpace.op(windowState.getDisplayFrameLw(), unaccountedSpace,
+ unaccountedSpace.op(windowState.getDisplayFrame(), unaccountedSpace,
Region.Op.REVERSE_DIFFERENCE);
} else {
// If a window has tap exclude region, we need to account it.
- final Region displayRegion = new Region(windowState.getDisplayFrameLw());
+ final Region displayRegion = new Region(windowState.getDisplayFrame());
final Region tapExcludeRegion = new Region();
windowState.getTapExcludeRegion(tapExcludeRegion);
displayRegion.op(tapExcludeRegion, displayRegion,
@@ -1470,7 +1470,7 @@ final class AccessibilityController {
// Move to origin as all transforms are captured by the matrix.
RectF windowFrame = mTempRectF;
windowFrame.set(rect);
- windowFrame.offset(-windowState.getFrameLw().left, -windowState.getFrameLw().top);
+ windowFrame.offset(-windowState.getFrame().left, -windowState.getFrame().top);
matrix.mapRect(windowFrame);
diff --git a/services/core/java/com/android/server/wm/ActivityRecord.java b/services/core/java/com/android/server/wm/ActivityRecord.java
index 9316c4657826..56e404c8f409 100644
--- a/services/core/java/com/android/server/wm/ActivityRecord.java
+++ b/services/core/java/com/android/server/wm/ActivityRecord.java
@@ -110,9 +110,13 @@ import static android.view.WindowManager.TRANSIT_UNSET;
import static com.android.internal.protolog.ProtoLogGroup.WM_DEBUG_ADD_REMOVE;
import static com.android.internal.protolog.ProtoLogGroup.WM_DEBUG_APP_TRANSITIONS;
import static com.android.internal.protolog.ProtoLogGroup.WM_DEBUG_APP_TRANSITIONS_ANIM;
+import static com.android.internal.protolog.ProtoLogGroup.WM_DEBUG_CONFIGURATION;
+import static com.android.internal.protolog.ProtoLogGroup.WM_DEBUG_CONTAINERS;
+import static com.android.internal.protolog.ProtoLogGroup.WM_DEBUG_FOCUS;
import static com.android.internal.protolog.ProtoLogGroup.WM_DEBUG_FOCUS_LIGHT;
import static com.android.internal.protolog.ProtoLogGroup.WM_DEBUG_ORIENTATION;
import static com.android.internal.protolog.ProtoLogGroup.WM_DEBUG_STARTING_WINDOW;
+import static com.android.internal.protolog.ProtoLogGroup.WM_DEBUG_SWITCH;
import static com.android.server.policy.WindowManagerPolicy.FINISH_LAYOUT_REDO_ANIM;
import static com.android.server.policy.WindowManagerPolicy.FINISH_LAYOUT_REDO_WALLPAPER;
import static com.android.server.wm.ActivityRecordProto.ALL_DRAWN;
@@ -145,9 +149,6 @@ import static com.android.server.wm.ActivityRecordProto.WINDOW_TOKEN;
import static com.android.server.wm.ActivityStackSupervisor.PRESERVE_WINDOWS;
import static com.android.server.wm.ActivityTaskManagerDebugConfig.DEBUG_APP;
import static com.android.server.wm.ActivityTaskManagerDebugConfig.DEBUG_CLEANUP;
-import static com.android.server.wm.ActivityTaskManagerDebugConfig.DEBUG_CONFIGURATION;
-import static com.android.server.wm.ActivityTaskManagerDebugConfig.DEBUG_CONTAINERS;
-import static com.android.server.wm.ActivityTaskManagerDebugConfig.DEBUG_FOCUS;
import static com.android.server.wm.ActivityTaskManagerDebugConfig.DEBUG_PAUSE;
import static com.android.server.wm.ActivityTaskManagerDebugConfig.DEBUG_RESULTS;
import static com.android.server.wm.ActivityTaskManagerDebugConfig.DEBUG_SAVED_STATE;
@@ -400,7 +401,6 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A
final ActivityTaskManagerService mAtmService;
final ActivityInfo info; // activity info provided by developer in AndroidManifest
- // Non-null only for application tokens.
// TODO: rename to mActivityToken
final ActivityRecord.Token appToken;
// Which user is this running for?
@@ -1096,15 +1096,15 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A
private void scheduleActivityMovedToDisplay(int displayId, Configuration config) {
if (!attachedToProcess()) {
- if (DEBUG_SWITCH || DEBUG_CONFIGURATION) Slog.w(TAG,
- "Can't report activity moved to display - client not running, activityRecord="
- + this + ", displayId=" + displayId);
+ ProtoLog.w(WM_DEBUG_SWITCH, "Can't report activity moved "
+ + "to display - client not running, activityRecord=%s, displayId=%d",
+ this, displayId);
return;
}
try {
- if (DEBUG_SWITCH || DEBUG_CONFIGURATION) Slog.v(TAG,
- "Reporting activity moved to display" + ", activityRecord=" + this
- + ", displayId=" + displayId + ", config=" + config);
+ ProtoLog.v(WM_DEBUG_SWITCH, "Reporting activity moved to "
+ + "display, activityRecord=%s, displayId=%d, config=%s", this, displayId,
+ config);
mAtmService.getLifecycleManager().scheduleTransaction(app.getThread(), appToken,
MoveToDisplayItem.obtain(displayId, config));
@@ -1115,14 +1115,13 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A
private void scheduleConfigurationChanged(Configuration config) {
if (!attachedToProcess()) {
- if (DEBUG_CONFIGURATION) Slog.w(TAG,
- "Can't report activity configuration update - client not running"
- + ", activityRecord=" + this);
+ ProtoLog.w(WM_DEBUG_CONFIGURATION, "Can't report activity configuration "
+ + "update - client not running, activityRecord=%s", this);
return;
}
try {
- if (DEBUG_CONFIGURATION) Slog.v(TAG, "Sending new config to " + this + ", config: "
- + config);
+ ProtoLog.v(WM_DEBUG_CONFIGURATION, "Sending new config to %s, "
+ + "config: %s", this, config);
mAtmService.getLifecycleManager().scheduleTransaction(app.getThread(), appToken,
ActivityConfigurationChangeItem.obtain(config));
@@ -1334,7 +1333,7 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A
if (w == null || winHint != null && w != winHint) {
return;
}
- final boolean surfaceReady = w.isDrawnLw() // Regular case
+ final boolean surfaceReady = w.isDrawn() // Regular case
|| w.mWinAnimator.mSurfaceDestroyDeferred // The preserved surface is still ready.
|| w.isDragResizeChanged(); // Waiting for relayoutWindow to call preserveSurface.
final boolean needsLetterbox = surfaceReady && w.isLetterboxedAppWindow() && fillsParent();
@@ -1355,7 +1354,7 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A
: inMultiWindowMode()
? task.getBounds()
: getRootTask().getParent().getBounds();
- mLetterbox.layout(spaceToFill, w.getFrameLw(), mTmpPoint);
+ mLetterbox.layout(spaceToFill, w.getFrame(), mTmpPoint);
} else if (mLetterbox != null) {
mLetterbox.hide();
}
@@ -1587,7 +1586,8 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A
hasBeenLaunched = false;
mStackSupervisor = supervisor;
- info.taskAffinity = getTaskAffinityWithUid(info.taskAffinity, info.applicationInfo.uid);
+ info.taskAffinity = computeTaskAffinity(info.taskAffinity, info.applicationInfo.uid,
+ launchMode);
taskAffinity = info.taskAffinity;
final String uid = Integer.toString(info.applicationInfo.uid);
if (info.windowLayout != null && info.windowLayout.windowLayoutAffinity != null
@@ -1648,17 +1648,18 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A
}
/**
- * Generate the task affinity with uid. For b/35954083, Limit task affinity to uid to avoid
- * issues associated with sharing affinity across uids.
+ * Generate the task affinity with uid and activity launch mode. For b/35954083, Limit task
+ * affinity to uid to avoid issues associated with sharing affinity across uids.
*
* @param affinity The affinity of the activity.
* @param uid The user-ID that has been assigned to this application.
- * @return The task affinity with uid.
+ * @param launchMode The activity launch mode
+ * @return The task affinity
*/
- static String getTaskAffinityWithUid(String affinity, int uid) {
+ static String computeTaskAffinity(String affinity, int uid, int launchMode) {
final String uidStr = Integer.toString(uid);
if (affinity != null && !affinity.startsWith(uidStr)) {
- affinity = uidStr + ":" + affinity;
+ affinity = uidStr + (launchMode == LAUNCH_SINGLE_INSTANCE ? "-si:" : ":") + affinity;
}
return affinity;
}
@@ -1949,10 +1950,8 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A
startingWindow = null;
startingDisplayed = false;
if (surface == null) {
- ProtoLog.v(WM_DEBUG_STARTING_WINDOW,
- "startingWindow was set but startingSurface==null, couldn't "
- + "remove");
-
+ ProtoLog.v(WM_DEBUG_STARTING_WINDOW, "startingWindow was set but "
+ + "startingSurface==null, couldn't remove");
return;
}
} else {
@@ -1962,9 +1961,10 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A
return;
}
+
ProtoLog.v(WM_DEBUG_STARTING_WINDOW, "Schedule remove starting %s startingWindow=%s"
- + " startingView=%s Callers=%s",
- this, startingWindow, startingSurface, Debug.getCallers(5));
+ + " startingView=%s Callers=%s", this, startingWindow, startingSurface,
+ Debug.getCallers(5));
// Use the same thread to remove the window as we used to add it, as otherwise we end up
@@ -2124,11 +2124,6 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A
return task != null ? task.getRootTaskId() : INVALID_TASK_ID;
}
- DisplayContent getDisplay() {
- final Task stack = getRootTask();
- return stack != null ? stack.getDisplay() : null;
- }
-
@Override
@Nullable
TaskDisplayArea getDisplayArea() {
@@ -2388,7 +2383,10 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A
}
}
- return (canReceiveKeys() || isAlwaysFocusable()) && getDisplay() != null;
+ // Check isAttached() because the method may be called when removing this activity from
+ // display, and WindowContainer#compareTo will throw exception if it doesn't have a parent
+ // when updating focused window from DisplayContent#findFocusedWindow.
+ return (canReceiveKeys() || isAlwaysFocusable()) && isAttached();
}
/**
@@ -2399,9 +2397,8 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A
*/
boolean moveFocusableActivityToTop(String reason) {
if (!isFocusable()) {
- if (DEBUG_FOCUS) {
- Slog.d(TAG_FOCUS, "moveActivityStackToFront: unfocusable activity=" + this);
- }
+ ProtoLog.d(WM_DEBUG_FOCUS, "moveActivityStackToFront: unfocusable "
+ + "activity=%s", this);
return false;
}
@@ -2414,15 +2411,11 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A
if (mRootWindowContainer.getTopResumedActivity() == this
&& getDisplayContent().mFocusedApp == this) {
- if (DEBUG_FOCUS) {
- Slog.d(TAG_FOCUS, "moveActivityStackToFront: already on top, activity=" + this);
- }
+ ProtoLog.d(WM_DEBUG_FOCUS, "moveActivityStackToFront: already on top, "
+ + "activity=%s", this);
return !isState(RESUMED);
}
-
- if (DEBUG_FOCUS) {
- Slog.d(TAG_FOCUS, "moveActivityStackToFront: activity=" + this);
- }
+ ProtoLog.d(WM_DEBUG_FOCUS, "moveActivityStackToFront: activity=%s", this);
stack.moveToFront(reason, task);
// Report top activity change to tracking services and WM
@@ -2670,7 +2663,7 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A
}
private void prepareActivityHideTransitionAnimation(int transit) {
- final DisplayContent dc = getDisplay().mDisplayContent;
+ final DisplayContent dc = mDisplayContent;
dc.prepareAppTransition(transit, false);
setVisibility(false);
dc.executeAppTransition();
@@ -2715,7 +2708,7 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A
}
if (ensureVisibility) {
- getDisplay().ensureActivitiesVisible(null /* starting */, 0 /* configChanges */,
+ mDisplayContent.ensureActivitiesVisible(null /* starting */, 0 /* configChanges */,
false /* preserveWindows */, true /* notifyClients */);
}
}
@@ -2786,8 +2779,7 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A
}
makeFinishingLocked();
- final boolean activityRemoved = destroyImmediately(true /* removeFromApp */,
- "finish-imm:" + reason);
+ final boolean activityRemoved = destroyImmediately("finish-imm:" + reason);
// If the display does not have running activity, the configuration may need to be
// updated for restoring original orientation of the display.
@@ -2799,10 +2791,8 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A
mRootWindowContainer.resumeFocusedStacksTopActivities();
}
- if (DEBUG_CONTAINERS) {
- Slog.d(TAG_CONTAINERS, "destroyIfPossible: r=" + this + " destroy returned removed="
- + activityRemoved);
- }
+ ProtoLog.d(WM_DEBUG_CONTAINERS, "destroyIfPossible: r=%s destroy returned "
+ + "removed=%s", this, activityRemoved);
return activityRemoved;
}
@@ -2835,7 +2825,7 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A
* @return {@code true} if activity was immediately removed from history, {@code false}
* otherwise.
*/
- boolean destroyImmediately(boolean removeFromApp, String reason) {
+ boolean destroyImmediately(String reason) {
if (DEBUG_SWITCH || DEBUG_CLEANUP) {
Slog.v(TAG_SWITCH, "Removing activity from " + reason + ": token=" + this
+ ", app=" + (hasProcess() ? app.mName : "(null)"));
@@ -2857,17 +2847,9 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A
cleanUp(false /* cleanServices */, false /* setState */);
if (hasProcess()) {
- if (removeFromApp) {
- app.removeActivity(this, true /* keepAssociation */);
- if (!app.hasActivities()) {
- mAtmService.clearHeavyWeightProcessIfEquals(app);
- // Update any services we are bound to that might care about whether
- // their client may have activities.
- // No longer have activities, so update LRU list and oom adj.
- app.updateProcessInfo(true /* updateServiceConnectionActivities */,
- false /* activityChange */, true /* updateOomAdj */,
- false /* addPendingTopUid */);
- }
+ app.removeActivity(this, true /* keepAssociation */);
+ if (!app.hasActivities()) {
+ mAtmService.clearHeavyWeightProcessIfEquals(app);
}
boolean skipDestroy = false;
@@ -2934,7 +2916,7 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A
+ " pausing=" + stack.mPausingActivity
+ " for reason " + reason);
}
- return destroyImmediately(true /* removeFromApp */, reason);
+ return destroyImmediately(reason);
}
return false;
}
@@ -2944,10 +2926,9 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A
finishActivityResults(Activity.RESULT_CANCELED,
null /* resultData */, null /* resultGrants */);
makeFinishingLocked();
- if (ActivityTaskManagerDebugConfig.DEBUG_ADD_REMOVE) {
- Slog.i(TAG_ADD_REMOVE, "Removing activity " + this + " from stack, reason="
- + reason + ", callers=" + Debug.getCallers(5));
- }
+
+ ProtoLog.i(WM_DEBUG_ADD_REMOVE, "Removing activity %s from stack, reason= %s "
+ + "callers=%s", this, reason, Debug.getCallers(5));
takeFromHistory();
removeTimeouts();
@@ -2987,7 +2968,7 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A
void destroyed(String reason) {
removeDestroyTimeout();
- if (DEBUG_CONTAINERS) Slog.d(TAG_CONTAINERS, "activityDestroyedLocked: r=" + this);
+ ProtoLog.d(WM_DEBUG_CONTAINERS, "activityDestroyedLocked: r=%s", this);
if (!isState(DESTROYING, DESTROYED)) {
throw new IllegalStateException(
@@ -3188,12 +3169,9 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A
remove = false;
}
if (remove) {
- if (ActivityTaskManagerDebugConfig.DEBUG_ADD_REMOVE || DEBUG_CLEANUP) {
- Slog.i(TAG_ADD_REMOVE, "Removing activity " + this
- + " hasSavedState=" + mHaveState + " stateNotNeeded=" + stateNotNeeded
- + " finishing=" + finishing + " state=" + mState
- + " callers=" + Debug.getCallers(5));
- }
+ ProtoLog.i(WM_DEBUG_ADD_REMOVE, "Removing activity %s hasSavedState=%b "
+ + "stateNotNeeded=%s finishing=%b state=%s callers=%s", this,
+ mHaveState, stateNotNeeded, finishing, mState, Debug.getCallers(5));
if (!finishing || (app != null && app.isRemoved())) {
Slog.w(TAG, "Force removing " + this + ": app died, no saved state");
EventLogTags.writeWmFinishActivity(mUserId, System.identityHashCode(this),
@@ -4305,7 +4283,7 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A
} else {
// If we are being set visible, and the starting window is not yet displayed,
// then make sure it doesn't get displayed.
- if (startingWindow != null && !startingWindow.isDrawnLw()) {
+ if (startingWindow != null && !startingWindow.isDrawn()) {
startingWindow.clearPolicyVisibilityFlag(LEGACY_POLICY_VISIBILITY);
startingWindow.mLegacyPolicyVisibilityAfterAnim = false;
}
@@ -4487,16 +4465,40 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A
detachChildren();
}
- if (state == RESUMED) {
- mAtmService.updateBatteryStats(this, true);
- mAtmService.updateActivityUsageStats(this, Event.ACTIVITY_RESUMED);
- } else if (state == PAUSED) {
- mAtmService.updateBatteryStats(this, false);
- mAtmService.updateActivityUsageStats(this, Event.ACTIVITY_PAUSED);
- } else if (state == STOPPED) {
- mAtmService.updateActivityUsageStats(this, Event.ACTIVITY_STOPPED);
- } else if (state == DESTROYED) {
- mAtmService.updateActivityUsageStats(this, Event.ACTIVITY_DESTROYED);
+ switch (state) {
+ case RESUMED:
+ mAtmService.updateBatteryStats(this, true);
+ mAtmService.updateActivityUsageStats(this, Event.ACTIVITY_RESUMED);
+ // Fall through.
+ case STARTED:
+ // Update process info while making an activity from invisible to visible, to make
+ // sure the process state is updated to foreground.
+ if (app != null) {
+ app.updateProcessInfo(false /* updateServiceConnectionActivities */,
+ true /* activityChange */, true /* updateOomAdj */,
+ true /* addPendingTopUid */);
+ }
+ break;
+ case PAUSED:
+ mAtmService.updateBatteryStats(this, false);
+ mAtmService.updateActivityUsageStats(this, Event.ACTIVITY_PAUSED);
+ break;
+ case STOPPED:
+ mAtmService.updateActivityUsageStats(this, Event.ACTIVITY_STOPPED);
+ break;
+ case DESTROYED:
+ mAtmService.updateActivityUsageStats(this, Event.ACTIVITY_DESTROYED);
+ // Fall through.
+ case DESTROYING:
+ if (app != null && !app.hasActivities()) {
+ // Update any services we are bound to that might care about whether
+ // their client may have activities.
+ // No longer have activities, so update LRU list and oom adj.
+ app.updateProcessInfo(true /* updateServiceConnectionActivities */,
+ false /* activityChange */, true /* updateOomAdj */,
+ false /* addPendingTopUid */);
+ }
+ break;
}
}
@@ -4650,7 +4652,7 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A
}
// Check if the activity is on a sleeping display, and if it can turn it ON.
- if (getDisplay().isSleeping()) {
+ if (mDisplayContent.isSleeping()) {
final boolean canTurnScreenOn = !mSetToSleep || canTurnScreenOn()
|| canShowWhenLocked() || containsDismissKeyguardWindow();
if (!canTurnScreenOn) {
@@ -4807,14 +4809,6 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A
}
setState(STARTED, "makeActiveIfNeeded");
- // Update process info while making an activity from invisible to visible, to make
- // sure the process state is updated to foreground.
- if (app != null) {
- app.updateProcessInfo(false /* updateServiceConnectionActivities */,
- true /* activityChange */, true /* updateOomAdj */,
- true /* addPendingTopUid */);
- }
-
try {
mAtmService.getLifecycleManager().scheduleTransaction(app.getThread(), appToken,
StartActivityItem.obtain());
@@ -4937,12 +4931,8 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A
}
r.setSavedState(null /* savedState */);
- final DisplayContent display = r.getDisplay();
- if (display != null) {
- display.handleActivitySizeCompatModeIfNeeded(r);
- }
-
- r.getDisplayContent().mUnknownAppVisibilityController.notifyAppResumedFinished(r);
+ r.mDisplayContent.handleActivitySizeCompatModeIfNeeded(r);
+ r.mDisplayContent.mUnknownAppVisibilityController.notifyAppResumedFinished(r);
}
/**
@@ -5122,7 +5112,7 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A
if (DEBUG_STATES) Slog.v(TAG_STATES, "Stop failed; moving to STOPPED: " + this);
setState(STOPPED, "stopIfPossible");
if (deferRelaunchUntilPaused) {
- destroyImmediately(true /* removeFromApp */, "stop-except");
+ destroyImmediately("stop-except");
}
}
}
@@ -5163,7 +5153,7 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A
clearOptionsLocked();
} else {
if (deferRelaunchUntilPaused) {
- destroyImmediately(true /* removeFromApp */, "stop-config");
+ destroyImmediately("stop-config");
mRootWindowContainer.resumeFocusedStacksTopActivities();
} else {
mRootWindowContainer.updatePreviousProcess(this);
@@ -5485,10 +5475,6 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A
}
void updateReportedVisibilityLocked() {
- if (appToken == null) {
- return;
- }
-
if (DEBUG_VISIBILITY) Slog.v(TAG, "Update reported visibility: " + this);
final int count = mChildren.size();
@@ -5589,9 +5575,9 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A
if (DEBUG_VISIBILITY || WM_DEBUG_ORIENTATION.isLogToLogcat()) {
final boolean isAnimationSet = isAnimating(TRANSITION | PARENTS,
ANIMATION_TYPE_APP_TRANSITION);
- Slog.v(TAG, "Eval win " + w + ": isDrawn=" + w.isDrawnLw()
+ Slog.v(TAG, "Eval win " + w + ": isDrawn=" + w.isDrawn()
+ ", isAnimationSet=" + isAnimationSet);
- if (!w.isDrawnLw()) {
+ if (!w.isDrawn()) {
Slog.v(TAG, "Not displayed: s=" + winAnimator.mSurfaceController
+ " pv=" + w.isVisibleByPolicy()
+ " mDrawState=" + winAnimator.drawStateToString()
@@ -5606,7 +5592,7 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A
if (findMainWindow(false /* includeStartingApp */) != w) {
mNumInterestingWindows++;
}
- if (w.isDrawnLw()) {
+ if (w.isDrawn()) {
mNumDrawnWindows++;
if (DEBUG_VISIBILITY || WM_DEBUG_ORIENTATION.isLogToLogcat()) {
@@ -5619,7 +5605,7 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A
isInterestingAndDrawn = true;
}
}
- } else if (w.isDrawnLw()) {
+ } else if (w.isDrawn()) {
// The starting window for this container is drawn.
mStackSupervisor.getActivityMetricsLogger().notifyStartingWindowDrawn(this);
startingDisplayed = true;
@@ -6148,7 +6134,7 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A
if (win == null) {
return;
}
- final Rect frame = win.getRelativeFrameLw();
+ final Rect frame = win.getRelativeFrame();
final int thumbnailDrawableRes = task.mUserId == mWmService.mCurrentUserId
? R.drawable.ic_account_circle
: R.drawable.ic_corp_badge;
@@ -6174,7 +6160,7 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A
// destination of the thumbnail header animation. If this is a full screen
// window scenario, we use the whole display as the target.
WindowState win = findMainWindow();
- Rect appRect = win != null ? win.getContentFrameLw() :
+ final Rect appRect = win != null ? win.getContentFrame() :
new Rect(0, 0, displayInfo.appWidth, displayInfo.appHeight);
final Rect insets = win != null ? win.getContentInsets() : null;
final Configuration displayConfig = mDisplayContent.getConfiguration();
@@ -6335,8 +6321,7 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A
}
private void setOrientation(int requestedOrientation, boolean freezeScreenIfNeeded) {
- final IBinder binder =
- (freezeScreenIfNeeded && appToken != null) ? appToken.asBinder() : null;
+ final IBinder binder = freezeScreenIfNeeded ? appToken.asBinder() : null;
setOrientation(requestedOrientation, binder, this);
// Push the new configuration to the requested app in case where it's not pushed, e.g. when
@@ -6845,7 +6830,7 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A
onMergedOverrideConfigurationChanged();
}
- final DisplayContent display = getDisplay();
+ final DisplayContent display = mDisplayContent;
if (display == null) {
return;
}
@@ -7000,27 +6985,27 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A
boolean ignoreVisibility) {
final Task stack = getRootTask();
if (stack.mConfigWillChange) {
- if (DEBUG_SWITCH || DEBUG_CONFIGURATION) Slog.v(TAG_CONFIGURATION,
- "Skipping config check (will change): " + this);
+ ProtoLog.v(WM_DEBUG_CONFIGURATION, "Skipping config check "
+ + "(will change): %s", this);
return true;
}
// We don't worry about activities that are finishing.
if (finishing) {
- if (DEBUG_SWITCH || DEBUG_CONFIGURATION) Slog.v(TAG_CONFIGURATION,
- "Configuration doesn't matter in finishing " + this);
+ ProtoLog.v(WM_DEBUG_CONFIGURATION, "Configuration doesn't matter "
+ + "in finishing %s", this);
stopFreezingScreenLocked(false);
return true;
}
if (!ignoreVisibility && (mState == STOPPING || mState == STOPPED || !shouldBeVisible())) {
- if (DEBUG_SWITCH || DEBUG_CONFIGURATION) Slog.v(TAG_CONFIGURATION,
- "Skipping config check invisible: " + this);
+ ProtoLog.v(WM_DEBUG_CONFIGURATION, "Skipping config check "
+ + "invisible: %s", this);
return true;
}
- if (DEBUG_SWITCH || DEBUG_CONFIGURATION) Slog.v(TAG_CONFIGURATION,
- "Ensuring correct configuration: " + this);
+ ProtoLog.v(WM_DEBUG_CONFIGURATION, "Ensuring correct "
+ + "configuration: %s", this);
final int newDisplayId = getDisplayId();
final boolean displayChanged = mLastReportedDisplayId != newDisplayId;
@@ -7036,8 +7021,8 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A
// the combine configurations are equal, but would otherwise differ in the override config
mTmpConfig.setTo(mLastReportedConfiguration.getMergedConfiguration());
if (getConfiguration().equals(mTmpConfig) && !forceNewConfig && !displayChanged) {
- if (DEBUG_SWITCH || DEBUG_CONFIGURATION) Slog.v(TAG_CONFIGURATION,
- "Configuration & display unchanged in " + this);
+ ProtoLog.v(WM_DEBUG_CONFIGURATION, "Configuration & display "
+ + "unchanged in %s", this);
return true;
}
@@ -7057,14 +7042,14 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A
// No need to relaunch or schedule new config for activity that hasn't been launched
// yet. We do, however, return after applying the config to activity record, so that
// it will use it for launch transaction.
- if (DEBUG_SWITCH || DEBUG_CONFIGURATION) Slog.v(TAG_CONFIGURATION,
- "Skipping config check for initializing activity: " + this);
+ ProtoLog.v(WM_DEBUG_CONFIGURATION, "Skipping config check for "
+ + "initializing activity: %s", this);
return true;
}
if (changes == 0 && !forceNewConfig) {
- if (DEBUG_SWITCH || DEBUG_CONFIGURATION) Slog.v(TAG_CONFIGURATION,
- "Configuration no differences in " + this);
+ ProtoLog.v(WM_DEBUG_CONFIGURATION, "Configuration no differences in %s",
+ this);
// There are no significant differences, so we won't relaunch but should still deliver
// the new configuration to the client process.
if (displayChanged) {
@@ -7075,26 +7060,23 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A
return true;
}
- if (DEBUG_SWITCH || DEBUG_CONFIGURATION) Slog.v(TAG_CONFIGURATION,
- "Configuration changes for " + this + ", allChanges="
- + Configuration.configurationDiffToString(changes));
+ ProtoLog.v(WM_DEBUG_CONFIGURATION, "Configuration changes for %s, "
+ + "allChanges=%s", this, Configuration.configurationDiffToString(changes));
// If the activity isn't currently running, just leave the new configuration and it will
// pick that up next time it starts.
if (!attachedToProcess()) {
- if (DEBUG_SWITCH || DEBUG_CONFIGURATION) Slog.v(TAG_CONFIGURATION,
- "Configuration doesn't matter not running " + this);
+ ProtoLog.v(WM_DEBUG_CONFIGURATION, "Configuration doesn't matter not running %s", this);
stopFreezingScreenLocked(false);
forceNewConfig = false;
return true;
}
// Figure out how to handle the changes between the configurations.
- if (DEBUG_SWITCH || DEBUG_CONFIGURATION) Slog.v(TAG_CONFIGURATION,
- "Checking to restart " + info.name + ": changed=0x"
- + Integer.toHexString(changes) + ", handles=0x"
- + Integer.toHexString(info.getRealConfigChanged())
- + ", mLastReportedConfiguration=" + mLastReportedConfiguration);
+ ProtoLog.v(WM_DEBUG_CONFIGURATION, "Checking to restart %s: changed=0x%s, "
+ + "handles=0x%s, mLastReportedConfiguration=%s", info.name,
+ Integer.toHexString(changes), Integer.toHexString(info.getRealConfigChanged()),
+ mLastReportedConfiguration);
if (shouldRelaunchLocked(changes, mTmpConfig) || forceNewConfig) {
// Aha, the activity isn't handling the change, so DIE DIE DIE.
@@ -7111,20 +7093,20 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A
mRelaunchReason = RELAUNCH_REASON_NONE;
}
if (!attachedToProcess()) {
- if (DEBUG_SWITCH || DEBUG_CONFIGURATION) Slog.v(TAG_CONFIGURATION,
- "Config is destroying non-running " + this);
- destroyImmediately(true /* removeFromApp */, "config");
+ ProtoLog.v(WM_DEBUG_CONFIGURATION,
+ "Config is destroying non-running %s", this);
+ destroyImmediately("config");
} else if (mState == PAUSING) {
// A little annoying: we are waiting for this activity to finish pausing. Let's not
// do anything now, but just flag that it needs to be restarted when done pausing.
- if (DEBUG_SWITCH || DEBUG_CONFIGURATION) Slog.v(TAG_CONFIGURATION,
- "Config is skipping already pausing " + this);
+ ProtoLog.v(WM_DEBUG_CONFIGURATION,
+ "Config is skipping already pausing %s", this);
deferRelaunchUntilPaused = true;
preserveWindowOnDeferredRelaunch = preserveWindow;
return true;
} else {
- if (DEBUG_SWITCH || DEBUG_CONFIGURATION) Slog.v(TAG_CONFIGURATION,
- "Config is relaunching " + this);
+ ProtoLog.v(WM_DEBUG_CONFIGURATION, "Config is relaunching %s",
+ this);
if (DEBUG_STATES && !mVisibleRequested) {
Slog.v(TAG_STATES, "Config is relaunching invisible activity " + this
+ " called by " + Debug.getCallers(4));
@@ -7273,7 +7255,7 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A
final ActivityLifecycleItem lifecycleItem;
if (andResume) {
lifecycleItem = ResumeActivityItem.obtain(
- getDisplay().mDisplayContent.isNextTransitionForward());
+ mDisplayContent.isNextTransitionForward());
} else {
lifecycleItem = PauseActivityItem.obtain();
}
@@ -7598,11 +7580,7 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A
* otherwise.
*/
boolean isFocusedActivityOnDisplay() {
- final DisplayContent display = getDisplay();
- if (display == null) {
- return false;
- }
- return display.forAllTaskDisplayAreas(taskDisplayArea ->
+ return mDisplayContent.forAllTaskDisplayAreas(taskDisplayArea ->
taskDisplayArea.getFocusedActivity() == this);
}
@@ -7721,9 +7699,7 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A
}
void writeNameToProto(ProtoOutputStream proto, long fieldId) {
- if (appToken != null) {
- proto.write(fieldId, appToken.getName());
- }
+ proto.write(fieldId, appToken.getName());
}
@Override
@@ -7810,42 +7786,40 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A
/** Gets the horizontal centered container bounds for size compatibility mode. */
void getContainerBounds(Rect outAppBounds, Rect outBounds, int rotation, int orientation,
boolean orientationRequested, boolean canChangeOrientation) {
+ getFrameByOrientation(outBounds, orientation);
if (mIsFloating) {
- getFrameByOrientation(outBounds, orientation);
outAppBounds.set(outBounds);
return;
}
- if (canChangeOrientation) {
- getBoundsByRotation(outBounds, rotation);
- if (orientationRequested) {
- getFrameByOrientation(outAppBounds, orientation);
- } else {
- outAppBounds.set(outBounds);
- }
- } else {
- if (orientationRequested) {
- getFrameByOrientation(outBounds, orientation);
- if ((outBounds.width() > outBounds.height()) != (mWidth > mHeight)) {
- // The orientation is mismatched but the display cannot rotate. The bounds
- // will fit to the short side of display.
- if (orientation == ORIENTATION_LANDSCAPE) {
- outBounds.bottom = (int) ((float) mWidth * mWidth / mHeight);
- outBounds.right = mWidth;
- } else {
- outBounds.bottom = mHeight;
- outBounds.right = (int) ((float) mHeight * mHeight / mWidth);
- }
- outBounds.offset(
- getHorizontalCenterOffset(mWidth, outBounds.width()), 0 /* dy */);
- }
+ getBoundsByRotation(outAppBounds, rotation);
+ final int dW = outAppBounds.width();
+ final int dH = outAppBounds.height();
+ final boolean isOrientationMismatched =
+ ((outBounds.width() > outBounds.height()) != (dW > dH));
+
+ if (isOrientationMismatched && !canChangeOrientation && orientationRequested) {
+ // The orientation is mismatched but the display cannot rotate. The bounds will fit
+ // to the short side of container.
+ if (orientation == ORIENTATION_LANDSCAPE) {
+ outBounds.bottom = (int) ((float) dW * dW / dH);
+ outBounds.right = dW;
} else {
- outBounds.set(0, 0, mWidth, mHeight);
+ outBounds.bottom = dH;
+ outBounds.right = (int) ((float) dH * dH / dW);
}
- outAppBounds.set(outBounds);
- }
-
- if (rotation != ROTATION_UNDEFINED) {
+ outBounds.offset(getHorizontalCenterOffset(mWidth, outBounds.width()), 0 /* dy */);
+ }
+ outAppBounds.set(outBounds);
+
+ if (isOrientationMismatched) {
+ // One side of container is smaller than the requested size, then it will be scaled
+ // and the final position will be calculated according to the parent container and
+ // scale, so the original size shouldn't be shrunk by insets.
+ final Rect insets = mNonDecorInsets[rotation];
+ outBounds.offset(insets.left, insets.top);
+ outAppBounds.offset(insets.left, insets.top);
+ } else if (rotation != ROTATION_UNDEFINED) {
// Ensure the app bounds won't overlap with insets.
Task.intersectWithInsetsIfFits(outAppBounds, outBounds, mNonDecorInsets[rotation]);
}
diff --git a/services/core/java/com/android/server/wm/ActivityStackSupervisor.java b/services/core/java/com/android/server/wm/ActivityStackSupervisor.java
index 2c475e0b9bcb..9df192b76f9a 100644
--- a/services/core/java/com/android/server/wm/ActivityStackSupervisor.java
+++ b/services/core/java/com/android/server/wm/ActivityStackSupervisor.java
@@ -41,10 +41,8 @@ import static android.content.pm.PackageManager.PERMISSION_DENIED;
import static android.content.pm.PackageManager.PERMISSION_GRANTED;
import static android.os.PowerManager.PARTIAL_WAKE_LOCK;
import static android.os.Process.INVALID_UID;
-import static android.os.Process.SYSTEM_UID;
import static android.os.Trace.TRACE_TAG_WINDOW_MANAGER;
import static android.view.Display.DEFAULT_DISPLAY;
-import static android.view.Display.TYPE_VIRTUAL;
import static com.android.server.wm.ActivityTaskManagerDebugConfig.DEBUG_ALL;
import static com.android.server.wm.ActivityTaskManagerDebugConfig.DEBUG_CLEANUP;
@@ -839,7 +837,7 @@ public class ActivityStackSupervisor implements RecentTasks.Callbacks {
final ClientTransaction clientTransaction = ClientTransaction.obtain(
proc.getThread(), r.appToken);
- final DisplayContent dc = r.getDisplay().mDisplayContent;
+ final DisplayContent dc = r.mDisplayContent;
clientTransaction.addCallback(LaunchActivityItem.obtain(new Intent(r.intent),
System.identityHashCode(r), r.info,
// TODO: Have this take the merged configuration instead of separate global
@@ -1869,7 +1867,7 @@ public class ActivityStackSupervisor implements RecentTasks.Callbacks {
for (int i = 0; i < numFinishingActivities; i++) {
final ActivityRecord r = finishingActivities.get(i);
if (r.isInHistory()) {
- r.destroyImmediately(true /* removeFromApp */, "finish-" + reason);
+ r.destroyImmediately("finish-" + reason);
}
}
}
diff --git a/services/core/java/com/android/server/wm/ActivityStarter.java b/services/core/java/com/android/server/wm/ActivityStarter.java
index f6158383d28a..19755f29043e 100644
--- a/services/core/java/com/android/server/wm/ActivityStarter.java
+++ b/services/core/java/com/android/server/wm/ActivityStarter.java
@@ -56,12 +56,12 @@ import static android.content.pm.PackageManager.PERMISSION_GRANTED;
import static android.os.Process.INVALID_UID;
import static android.view.Display.DEFAULT_DISPLAY;
+import static com.android.internal.protolog.ProtoLogGroup.WM_DEBUG_CONFIGURATION;
import static com.android.server.wm.ActivityStackSupervisor.DEFER_RESUME;
import static com.android.server.wm.ActivityStackSupervisor.ON_TOP;
import static com.android.server.wm.ActivityStackSupervisor.PRESERVE_WINDOWS;
import static com.android.server.wm.ActivityStackSupervisor.TAG_TASKS;
import static com.android.server.wm.ActivityTaskManagerDebugConfig.DEBUG_ACTIVITY_STARTS;
-import static com.android.server.wm.ActivityTaskManagerDebugConfig.DEBUG_CONFIGURATION;
import static com.android.server.wm.ActivityTaskManagerDebugConfig.DEBUG_PERMISSIONS_REVIEW;
import static com.android.server.wm.ActivityTaskManagerDebugConfig.DEBUG_RESULTS;
import static com.android.server.wm.ActivityTaskManagerDebugConfig.DEBUG_TASKS;
@@ -116,6 +116,7 @@ import android.util.Slog;
import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.app.HeavyWeightSwitcherActivity;
import com.android.internal.app.IVoiceInteractor;
+import com.android.internal.protolog.common.ProtoLog;
import com.android.server.am.PendingIntentRecord;
import com.android.server.pm.InstantAppResolver;
import com.android.server.power.ShutdownCheckPoints;
@@ -669,10 +670,8 @@ class ActivityStarter {
if (stack != null) {
stack.mConfigWillChange = globalConfigWillChange;
}
- if (DEBUG_CONFIGURATION) {
- Slog.v(TAG_CONFIGURATION, "Starting activity when config will change = "
- + globalConfigWillChange);
- }
+ ProtoLog.v(WM_DEBUG_CONFIGURATION, "Starting activity when config "
+ + "will change = %b", globalConfigWillChange);
final long origId = Binder.clearCallingIdentity();
@@ -695,10 +694,9 @@ class ActivityStarter {
if (stack != null) {
stack.mConfigWillChange = false;
}
- if (DEBUG_CONFIGURATION) {
- Slog.v(TAG_CONFIGURATION,
+ ProtoLog.v(WM_DEBUG_CONFIGURATION,
"Updating to new configuration after starting activity.");
- }
+
mService.updateConfigurationLocked(mRequest.globalConfig, null, false);
}
@@ -1693,8 +1691,9 @@ class ActivityStarter {
// we need to resolve resultTo to a uid as grantImplicitAccess deals explicitly in UIDs
final PackageManagerInternal pmInternal =
mService.getPackageManagerInternalLocked();
- final int resultToUid = pmInternal.getPackageUidInternal(
- mStartActivity.resultTo.info.packageName, 0, mStartActivity.mUserId);
+ final int resultToUid = pmInternal.getPackageUid(
+ mStartActivity.resultTo.info.packageName, 0 /* flags */,
+ mStartActivity.mUserId);
pmInternal.grantImplicitAccess(mStartActivity.mUserId, mIntent,
UserHandle.getAppId(mStartActivity.info.applicationInfo.uid) /*recipient*/,
resultToUid /*visible*/, true /*direct*/);
@@ -1711,8 +1710,9 @@ class ActivityStarter {
mRootWindowContainer.startPowerModeLaunchIfNeeded(
false /* forceSend */, mStartActivity);
- mTargetStack.startActivityLocked(mStartActivity, topStack.getTopNonFinishingActivity(),
- newTask, mKeepCurTransition, mOptions);
+ mTargetStack.startActivityLocked(mStartActivity,
+ topStack != null ? topStack.getTopNonFinishingActivity() : null, newTask,
+ mKeepCurTransition, mOptions);
if (mDoResume) {
final ActivityRecord topTaskActivity =
mStartActivity.getTask().topRunningActivityLocked();
@@ -1731,7 +1731,7 @@ class ActivityStarter {
0 /* configChanges */, !PRESERVE_WINDOWS);
// Go ahead and tell window manager to execute app transition for this activity
// since the app transition will not be triggered through the resume channel.
- mTargetStack.getDisplay().mDisplayContent.executeAppTransition();
+ mTargetStack.mDisplayContent.executeAppTransition();
} else {
// If the target stack was not previously focusable (previous top running activity
// on that stack was not visible) then any prior calls to move the stack to the
@@ -2481,7 +2481,7 @@ class ActivityStarter {
// to the front if the caller is not itself in the front.
final boolean differentTopTask;
if (mTargetStack.getDisplayArea() == mPreferredTaskDisplayArea) {
- final Task focusStack = mTargetStack.getDisplay().getFocusedStack();
+ final Task focusStack = mTargetStack.mDisplayContent.getFocusedStack();
final ActivityRecord curTop = (focusStack == null)
? null : focusStack.topRunningNonDelayedActivityLocked(mNotTop);
final Task topTask = curTop != null ? curTop.getTask() : null;
diff --git a/services/core/java/com/android/server/wm/ActivityTaskManagerDebugConfig.java b/services/core/java/com/android/server/wm/ActivityTaskManagerDebugConfig.java
index da0bfd67e353..3c562a6472b2 100644
--- a/services/core/java/com/android/server/wm/ActivityTaskManagerDebugConfig.java
+++ b/services/core/java/com/android/server/wm/ActivityTaskManagerDebugConfig.java
@@ -43,12 +43,6 @@ public class ActivityTaskManagerDebugConfig {
// Enable all debug log categories for activities.
private static final boolean DEBUG_ALL_ACTIVITIES = DEBUG_ALL || false;
- static final boolean DEBUG_ADD_REMOVE = DEBUG_ALL_ACTIVITIES || false;
- public static final boolean DEBUG_CONFIGURATION = DEBUG_ALL || false;
- static final boolean DEBUG_CONTAINERS = DEBUG_ALL_ACTIVITIES || false;
- static final boolean DEBUG_FOCUS = false;
- static final boolean DEBUG_IMMERSIVE = DEBUG_ALL || false;
- static final boolean DEBUG_LOCKTASK = DEBUG_ALL || false;
static final boolean DEBUG_PAUSE = DEBUG_ALL || false;
static final boolean DEBUG_RECENTS = DEBUG_ALL || false;
static final boolean DEBUG_RECENTS_TRIM_TASKS = DEBUG_RECENTS || false;
diff --git a/services/core/java/com/android/server/wm/ActivityTaskManagerService.java b/services/core/java/com/android/server/wm/ActivityTaskManagerService.java
index 403f225032e9..505233cd8a4a 100644
--- a/services/core/java/com/android/server/wm/ActivityTaskManagerService.java
+++ b/services/core/java/com/android/server/wm/ActivityTaskManagerService.java
@@ -66,6 +66,10 @@ import static android.view.Display.DEFAULT_DISPLAY;
import static android.view.Display.INVALID_DISPLAY;
import static android.view.WindowManager.TRANSIT_NONE;
+import static com.android.internal.protolog.ProtoLogGroup.WM_DEBUG_CONFIGURATION;
+import static com.android.internal.protolog.ProtoLogGroup.WM_DEBUG_FOCUS;
+import static com.android.internal.protolog.ProtoLogGroup.WM_DEBUG_IMMERSIVE;
+import static com.android.internal.protolog.ProtoLogGroup.WM_DEBUG_LOCKTASK;
import static com.android.server.am.ActivityManagerService.ANR_TRACE_DIR;
import static com.android.server.am.ActivityManagerService.MY_PID;
import static com.android.server.am.ActivityManagerService.STOCK_PM_FLAGS;
@@ -92,10 +96,6 @@ import static com.android.server.wm.ActivityStackSupervisor.ON_TOP;
import static com.android.server.wm.ActivityStackSupervisor.PRESERVE_WINDOWS;
import static com.android.server.wm.ActivityStackSupervisor.REMOVE_FROM_RECENTS;
import static com.android.server.wm.ActivityTaskManagerDebugConfig.DEBUG_ALL;
-import static com.android.server.wm.ActivityTaskManagerDebugConfig.DEBUG_CONFIGURATION;
-import static com.android.server.wm.ActivityTaskManagerDebugConfig.DEBUG_FOCUS;
-import static com.android.server.wm.ActivityTaskManagerDebugConfig.DEBUG_IMMERSIVE;
-import static com.android.server.wm.ActivityTaskManagerDebugConfig.DEBUG_LOCKTASK;
import static com.android.server.wm.ActivityTaskManagerDebugConfig.DEBUG_STACK;
import static com.android.server.wm.ActivityTaskManagerDebugConfig.DEBUG_SWITCH;
import static com.android.server.wm.ActivityTaskManagerDebugConfig.DEBUG_TASKS;
@@ -125,6 +125,7 @@ import static com.android.server.wm.Task.LOCK_TASK_AUTH_DONT_LOCK;
import static com.android.server.wm.Task.REPARENT_KEEP_STACK_AT_FRONT;
import static com.android.server.wm.Task.REPARENT_LEAVE_STACK_IN_PLACE;
import static com.android.server.wm.WindowContainer.POSITION_TOP;
+import static com.android.server.wm.WindowManagerService.UPDATE_FOCUS_NORMAL;
import android.Manifest;
import android.annotation.IntDef;
@@ -242,6 +243,7 @@ import com.android.internal.notification.SystemNotificationChannels;
import com.android.internal.os.TransferPipe;
import com.android.internal.policy.IKeyguardDismissCallback;
import com.android.internal.policy.KeyguardDismissCallback;
+import com.android.internal.protolog.common.ProtoLog;
import com.android.internal.util.ArrayUtils;
import com.android.internal.util.FastPrintWriter;
import com.android.internal.util.FrameworkStatsLog;
@@ -813,7 +815,7 @@ public class ActivityTaskManagerService extends IActivityTaskManager.Stub {
// in-place.
updateConfigurationLocked(configuration, null, true);
final Configuration globalConfig = getGlobalConfiguration();
- if (DEBUG_CONFIGURATION) Slog.v(TAG_CONFIGURATION, "Initial config: " + globalConfig);
+ ProtoLog.v(WM_DEBUG_CONFIGURATION, "Initial config: %s", globalConfig);
// Load resources only after the current configuration has been set.
final Resources res = mContext.getResources();
@@ -1960,7 +1962,7 @@ public class ActivityTaskManagerService extends IActivityTaskManager.Stub {
// update associated state if we're frontmost
if (r.isFocusedActivityOnDisplay()) {
- if (DEBUG_IMMERSIVE) Slog.d(TAG_IMMERSIVE, "Frontmost changed immersion: "+ r);
+ ProtoLog.d(WM_DEBUG_IMMERSIVE, "Frontmost changed immersion: %s", r);
applyUpdateLockStateLocked(r);
}
}
@@ -1974,8 +1976,8 @@ public class ActivityTaskManagerService extends IActivityTaskManager.Stub {
final boolean nextState = r != null && r.immersive;
mH.post(() -> {
if (mUpdateLock.isHeld() != nextState) {
- if (DEBUG_IMMERSIVE) Slog.d(TAG_IMMERSIVE,
- "Applying new update lock state '" + nextState + "' for " + r);
+ ProtoLog.d(WM_DEBUG_IMMERSIVE, "Applying new update lock state '%s' for %s",
+ nextState, r);
if (nextState) {
mUpdateLock.acquire();
} else {
@@ -2023,7 +2025,7 @@ public class ActivityTaskManagerService extends IActivityTaskManager.Stub {
if (self.isState(
Task.ActivityState.RESUMED, Task.ActivityState.PAUSING)) {
- self.getDisplay().mDisplayContent.mAppTransition.overridePendingAppTransition(
+ self.mDisplayContent.mAppTransition.overridePendingAppTransition(
packageName, enterAnim, exitAnim, null, null);
}
@@ -2176,7 +2178,7 @@ public class ActivityTaskManagerService extends IActivityTaskManager.Stub {
@Override
public void setFocusedStack(int stackId) {
mAmInternal.enforceCallingPermission(MANAGE_ACTIVITY_STACKS, "setFocusedStack()");
- if (DEBUG_FOCUS) Slog.d(TAG_FOCUS, "setFocusedStack: stackId=" + stackId);
+ ProtoLog.d(WM_DEBUG_FOCUS, "setFocusedStack: stackId=%d", stackId);
final long callingId = Binder.clearCallingIdentity();
try {
synchronized (mGlobalLock) {
@@ -2198,7 +2200,7 @@ public class ActivityTaskManagerService extends IActivityTaskManager.Stub {
@Override
public void setFocusedTask(int taskId) {
mAmInternal.enforceCallingPermission(MANAGE_ACTIVITY_STACKS, "setFocusedTask()");
- if (DEBUG_FOCUS) Slog.d(TAG_FOCUS, "setFocusedTask: taskId=" + taskId);
+ ProtoLog.d(WM_DEBUG_FOCUS, "setFocusedTask: taskId=%d", taskId);
final long callingId = Binder.clearCallingIdentity();
try {
synchronized (mGlobalLock) {
@@ -2407,7 +2409,7 @@ public class ActivityTaskManagerService extends IActivityTaskManager.Stub {
} else {
stack.setWindowingMode(windowingMode);
- stack.getDisplay().ensureActivitiesVisible(null, 0, PRESERVE_WINDOWS,
+ stack.mDisplayContent.ensureActivitiesVisible(null, 0, PRESERVE_WINDOWS,
true /* notifyClients */);
}
return true;
@@ -3013,7 +3015,7 @@ public class ActivityTaskManagerService extends IActivityTaskManager.Stub {
}
private void startLockTaskModeLocked(@Nullable Task task, boolean isSystemCaller) {
- if (DEBUG_LOCKTASK) Slog.w(TAG_LOCKTASK, "startLockTaskModeLocked: " + task);
+ ProtoLog.w(WM_DEBUG_LOCKTASK, "startLockTaskModeLocked: %s", task);
if (task == null || task.mLockTaskAuth == LOCK_TASK_AUTH_DONT_LOCK) {
return;
}
@@ -3075,8 +3077,7 @@ public class ActivityTaskManagerService extends IActivityTaskManager.Stub {
"updateLockTaskPackages()");
}
synchronized (mGlobalLock) {
- if (DEBUG_LOCKTASK) Slog.w(TAG_LOCKTASK, "Allowlisting " + userId + ":"
- + Arrays.toString(packages));
+ ProtoLog.w(WM_DEBUG_LOCKTASK, "Allowlisting %d:%s", userId, Arrays.toString(packages));
getLockTaskController().updateLockTaskPackages(userId, packages);
}
}
@@ -3379,7 +3380,7 @@ public class ActivityTaskManagerService extends IActivityTaskManager.Stub {
if (r == null || !r.isDestroyable()) {
return false;
}
- r.destroyImmediately(true /* removeFromApp */, "app-req");
+ r.destroyImmediately("app-req");
return r.isState(DESTROYING, DESTROYED);
} finally {
Binder.restoreCallingIdentity(origId);
@@ -4001,9 +4002,9 @@ public class ActivityTaskManagerService extends IActivityTaskManager.Stub {
@Override
public void reportSizeConfigurations(IBinder token, int[] horizontalSizeConfiguration,
int[] verticalSizeConfigurations, int[] smallestSizeConfigurations) {
- if (DEBUG_CONFIGURATION) Slog.v(TAG, "Report configuration: " + token + " "
- + Arrays.toString(horizontalSizeConfiguration) + " "
- + Arrays.toString(verticalSizeConfigurations));
+ ProtoLog.v(WM_DEBUG_CONFIGURATION, "Report configuration: %s %s %s",
+ token, Arrays.toString(horizontalSizeConfiguration),
+ Arrays.toString(verticalSizeConfigurations));
synchronized (mGlobalLock) {
ActivityRecord record = ActivityRecord.isInStackLocked(token);
if (record == null) {
@@ -4175,7 +4176,7 @@ public class ActivityTaskManagerService extends IActivityTaskManager.Stub {
if (params.hasSetAspectRatio()
&& !mWindowManager.isValidPictureInPictureAspectRatio(
- r.getDisplay(), params.getAspectRatio())) {
+ r.mDisplayContent, params.getAspectRatio())) {
final float minAspectRatio = mContext.getResources().getFloat(
com.android.internal.R.dimen.config_pictureInPictureMinAspectRatio);
final float maxAspectRatio = mContext.getResources().getFloat(
@@ -4497,8 +4498,8 @@ public class ActivityTaskManagerService extends IActivityTaskManager.Stub {
"updateLockTaskFeatures()");
}
synchronized (mGlobalLock) {
- if (DEBUG_LOCKTASK) Slog.w(TAG_LOCKTASK, "Allowing features " + userId + ":0x" +
- Integer.toHexString(flags));
+ ProtoLog.w(WM_DEBUG_LOCKTASK, "Allowing features %d:0x%s",
+ userId, Integer.toHexString(flags));
getLockTaskController().updateLockTaskFeatures(userId, flags);
}
}
@@ -4619,7 +4620,7 @@ public class ActivityTaskManagerService extends IActivityTaskManager.Stub {
}
final long origId = Binder.clearCallingIdentity();
try {
- display.mDisplayContent.registerRemoteAnimations(definition);
+ display.registerRemoteAnimations(definition);
} finally {
Binder.restoreCallingIdentity(origId);
}
@@ -5183,8 +5184,8 @@ public class ActivityTaskManagerService extends IActivityTaskManager.Stub {
return 0;
}
- if (DEBUG_SWITCH || DEBUG_CONFIGURATION) Slog.i(TAG_CONFIGURATION,
- "Updating global configuration to: " + values);
+ ProtoLog.i(WM_DEBUG_CONFIGURATION, "Updating global configuration "
+ + "to: %s", values);
writeConfigurationChanged(changes);
FrameworkStatsLog.write(FrameworkStatsLog.RESOURCE_CONFIGURATION_CHANGED,
values.colorMode,
@@ -5262,10 +5263,8 @@ public class ActivityTaskManagerService extends IActivityTaskManager.Stub {
for (int i = pidMap.size() - 1; i >= 0; i--) {
final int pid = pidMap.keyAt(i);
final WindowProcessController app = pidMap.get(pid);
- if (DEBUG_CONFIGURATION) {
- Slog.v(TAG_CONFIGURATION, "Update process config of "
- + app.mName + " to new config " + configCopy);
- }
+ ProtoLog.v(WM_DEBUG_CONFIGURATION, "Update process config of %s to new "
+ + "config %s", app.mName, configCopy);
app.onConfigurationChanged(configCopy);
}
@@ -5467,8 +5466,11 @@ public class ActivityTaskManagerService extends IActivityTaskManager.Stub {
updateResumedAppTrace(r);
mLastResumedActivity = r;
- r.getDisplay().setFocusedApp(r, true);
-
+ final boolean changed = r.mDisplayContent.setFocusedApp(r);
+ if (changed) {
+ mWindowManager.updateFocusedWindowLocked(UPDATE_FOCUS_NORMAL,
+ true /*updateInputWindows*/);
+ }
if (prevTask == null || task != prevTask) {
if (prevTask != null) {
mTaskChangeNotificationController.notifyTaskFocusChanged(prevTask.mTaskId, false);
@@ -6204,12 +6206,10 @@ public class ActivityTaskManagerService extends IActivityTaskManager.Stub {
// We might change the visibilities here, so prepare an empty app transition which
// might be overridden later if we actually change visibilities.
- final DisplayContent displayContent =
- mRootWindowContainer.getDisplayContent(displayId);
- if (displayContent == null) {
+ final DisplayContent dc = mRootWindowContainer.getDisplayContent(displayId);
+ if (dc == null) {
return;
}
- final DisplayContent dc = displayContent.mDisplayContent;
final boolean wasTransitionSet =
dc.mAppTransition.getAppTransition() != TRANSIT_NONE;
if (!wasTransitionSet) {
@@ -6563,10 +6563,8 @@ public class ActivityTaskManagerService extends IActivityTaskManager.Stub {
if (InputMethodSystemProperty.MULTI_CLIENT_IME_ENABLED) return;
if (pid == MY_PID || pid < 0) {
- if (DEBUG_CONFIGURATION) {
- Slog.w(TAG,
+ ProtoLog.w(WM_DEBUG_CONFIGURATION,
"Trying to update display configuration for system/invalid process.");
- }
return;
}
synchronized (mGlobalLock) {
@@ -6574,18 +6572,14 @@ public class ActivityTaskManagerService extends IActivityTaskManager.Stub {
mRootWindowContainer.getDisplayContent(displayId);
if (displayContent == null) {
// Call might come when display is not yet added or has been removed.
- if (DEBUG_CONFIGURATION) {
- Slog.w(TAG, "Trying to update display configuration for non-existing "
- + "displayId=" + displayId);
- }
+ ProtoLog.w(WM_DEBUG_CONFIGURATION, "Trying to update display "
+ + "configuration for non-existing displayId=%d", displayId);
return;
}
final WindowProcessController process = mProcessMap.getProcess(pid);
if (process == null) {
- if (DEBUG_CONFIGURATION) {
- Slog.w(TAG, "Trying to update display configuration for invalid "
- + "process, pid=" + pid);
- }
+ ProtoLog.w(WM_DEBUG_CONFIGURATION, "Trying to update display "
+ + "configuration for invalid process, pid=%d", pid);
return;
}
process.registerDisplayConfigurationListener(displayContent);
diff --git a/services/core/java/com/android/server/wm/BarController.java b/services/core/java/com/android/server/wm/BarController.java
index c1447553ba31..8568d5fc1d64 100644
--- a/services/core/java/com/android/server/wm/BarController.java
+++ b/services/core/java/com/android/server/wm/BarController.java
@@ -222,12 +222,12 @@ public class BarController {
}
protected boolean skipAnimation() {
- return !mWin.isDrawnLw();
+ return !mWin.isDrawn();
}
private @StatusBarManager.WindowVisibleState int computeStateLw(
boolean wasVis, boolean wasAnim, WindowState win, boolean change) {
- if (win.isDrawnLw()) {
+ if (win.isDrawn()) {
final boolean vis = win.isVisibleLw();
final boolean anim = win.isAnimatingLw();
if (mState == StatusBarManager.WINDOW_STATE_HIDING && !change && !vis) {
@@ -264,7 +264,7 @@ public class BarController {
}
boolean checkHiddenLw() {
- if (mWin != null && mWin.isDrawnLw()) {
+ if (mWin != null && mWin.isDrawn()) {
if (!mWin.isVisibleLw() && !mWin.isAnimatingLw()) {
updateStateLw(StatusBarManager.WINDOW_STATE_HIDDEN);
}
@@ -291,7 +291,7 @@ public class BarController {
} else if (mWin == null) {
if (DEBUG) Slog.d(mTag, "Not showing transient bar, bar doesn't exist");
return false;
- } else if (mWin.isDisplayedLw()) {
+ } else if (mWin.isDisplayed()) {
if (DEBUG) Slog.d(mTag, "Not showing transient bar, bar already visible");
return false;
} else {
diff --git a/services/core/java/com/android/server/wm/CompatModePackages.java b/services/core/java/com/android/server/wm/CompatModePackages.java
index 167afab9db0e..7e55f0aa2aa6 100644
--- a/services/core/java/com/android/server/wm/CompatModePackages.java
+++ b/services/core/java/com/android/server/wm/CompatModePackages.java
@@ -16,8 +16,8 @@
package com.android.server.wm;
+import static com.android.internal.protolog.ProtoLogGroup.WM_DEBUG_CONFIGURATION;
import static com.android.server.wm.ActivityStackSupervisor.PRESERVE_WINDOWS;
-import static com.android.server.wm.ActivityTaskManagerDebugConfig.DEBUG_CONFIGURATION;
import static com.android.server.wm.ActivityTaskManagerDebugConfig.POSTFIX_CONFIGURATION;
import static com.android.server.wm.ActivityTaskManagerDebugConfig.TAG_ATM;
import static com.android.server.wm.ActivityTaskManagerDebugConfig.TAG_WITH_CLASS_NAME;
@@ -37,6 +37,7 @@ import android.util.Slog;
import android.util.SparseArray;
import android.util.Xml;
+import com.android.internal.protolog.common.ProtoLog;
import com.android.internal.util.FastXmlSerializer;
import org.xmlpull.v1.XmlPullParser;
@@ -333,8 +334,8 @@ public final class CompatModePackages {
}
try {
if (app.hasThread()) {
- if (DEBUG_CONFIGURATION) Slog.v(TAG_CONFIGURATION, "Sending to proc "
- + app.mName + " new compat " + ci);
+ ProtoLog.v(WM_DEBUG_CONFIGURATION, "Sending to proc %s "
+ + "new compat %s", app.mName, ci);
app.getThread().updatePackageCompatibilityInfo(packageName, ci);
}
} catch (Exception e) {
diff --git a/services/core/java/com/android/server/wm/DisplayAreaOrganizerController.java b/services/core/java/com/android/server/wm/DisplayAreaOrganizerController.java
index 9a397fe07f4e..01c007e381b1 100644
--- a/services/core/java/com/android/server/wm/DisplayAreaOrganizerController.java
+++ b/services/core/java/com/android/server/wm/DisplayAreaOrganizerController.java
@@ -18,6 +18,9 @@ package com.android.server.wm;
import static android.Manifest.permission.MANAGE_ACTIVITY_STACKS;
+
+import static com.android.internal.protolog.ProtoLogGroup.WM_DEBUG_WINDOW_ORGANIZER;
+
import android.os.Binder;
import android.os.IBinder;
import android.os.RemoteException;
@@ -25,6 +28,8 @@ import android.view.SurfaceControl;
import android.window.IDisplayAreaOrganizer;
import android.window.IDisplayAreaOrganizerController;
+import com.android.internal.protolog.common.ProtoLog;
+
import java.util.HashMap;
public class DisplayAreaOrganizerController extends IDisplayAreaOrganizerController.Stub {
@@ -67,9 +72,12 @@ public class DisplayAreaOrganizerController extends IDisplayAreaOrganizerControl
@Override
public void registerOrganizer(IDisplayAreaOrganizer organizer, int feature) {
enforceStackPermission("registerOrganizer()");
+ final long uid = Binder.getCallingUid();
final long origId = Binder.clearCallingIdentity();
try {
synchronized (mGlobalLock) {
+ ProtoLog.v(WM_DEBUG_WINDOW_ORGANIZER, "Register display organizer=%s uid=%d",
+ organizer.asBinder(), uid);
if (mOrganizersByFeatureIds.get(feature) != null) {
throw new IllegalStateException(
"Replacing existing organizer currently unsupported");
@@ -96,9 +104,12 @@ public class DisplayAreaOrganizerController extends IDisplayAreaOrganizerControl
@Override
public void unregisterOrganizer(IDisplayAreaOrganizer organizer) {
enforceStackPermission("unregisterTaskOrganizer()");
+ final long uid = Binder.getCallingUid();
final long origId = Binder.clearCallingIdentity();
try {
synchronized (mGlobalLock) {
+ ProtoLog.v(WM_DEBUG_WINDOW_ORGANIZER, "Unregister display organizer=%s uid=%d",
+ organizer.asBinder(), uid);
mOrganizersByFeatureIds.entrySet().removeIf(
entry -> entry.getValue().asBinder() == organizer.asBinder());
@@ -113,6 +124,7 @@ public class DisplayAreaOrganizerController extends IDisplayAreaOrganizerControl
}
void onDisplayAreaAppeared(IDisplayAreaOrganizer organizer, DisplayArea da) {
+ ProtoLog.v(WM_DEBUG_WINDOW_ORGANIZER, "DisplayArea appeared name=%s", da.getName());
try {
SurfaceControl outSurfaceControl = new SurfaceControl(da.getSurfaceControl(),
"DisplayAreaOrganizerController.onDisplayAreaAppeared");
@@ -123,6 +135,7 @@ public class DisplayAreaOrganizerController extends IDisplayAreaOrganizerControl
}
void onDisplayAreaVanished(IDisplayAreaOrganizer organizer, DisplayArea da) {
+ ProtoLog.v(WM_DEBUG_WINDOW_ORGANIZER, "DisplayArea vanished name=%s", da.getName());
try {
organizer.onDisplayAreaVanished(da.getDisplayAreaInfo());
} catch (RemoteException e) {
@@ -131,6 +144,7 @@ public class DisplayAreaOrganizerController extends IDisplayAreaOrganizerControl
}
void onDisplayAreaInfoChanged(IDisplayAreaOrganizer organizer, DisplayArea da) {
+ ProtoLog.v(WM_DEBUG_WINDOW_ORGANIZER, "DisplayArea info changed name=%s", da.getName());
try {
organizer.onDisplayAreaInfoChanged(da.getDisplayAreaInfo());
} catch (RemoteException e) {
diff --git a/services/core/java/com/android/server/wm/DisplayContent.java b/services/core/java/com/android/server/wm/DisplayContent.java
index 0215ead7e5de..aa8069a76330 100644
--- a/services/core/java/com/android/server/wm/DisplayContent.java
+++ b/services/core/java/com/android/server/wm/DisplayContent.java
@@ -115,13 +115,11 @@ import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_WALLPAPER_LIG
import static com.android.server.wm.WindowManagerDebugConfig.SHOW_STACK_CRAWLS;
import static com.android.server.wm.WindowManagerDebugConfig.TAG_WITH_CLASS_NAME;
import static com.android.server.wm.WindowManagerDebugConfig.TAG_WM;
-import static com.android.server.wm.WindowManagerService.H.REPORT_FOCUS_CHANGE;
import static com.android.server.wm.WindowManagerService.H.REPORT_HARD_KEYBOARD_STATUS_CHANGE;
import static com.android.server.wm.WindowManagerService.H.UPDATE_MULTI_WINDOW_STACKS;
import static com.android.server.wm.WindowManagerService.H.WINDOW_HIDE_TIMEOUT;
import static com.android.server.wm.WindowManagerService.LAYOUT_REPEAT_THRESHOLD;
import static com.android.server.wm.WindowManagerService.SEAMLESS_ROTATION_TIMEOUT_DURATION;
-import static com.android.server.wm.WindowManagerService.UPDATE_FOCUS_NORMAL;
import static com.android.server.wm.WindowManagerService.UPDATE_FOCUS_PLACING_SURFACES;
import static com.android.server.wm.WindowManagerService.UPDATE_FOCUS_REMOVING_FOCUS;
import static com.android.server.wm.WindowManagerService.UPDATE_FOCUS_WILL_ASSIGN_LAYERS;
@@ -649,8 +647,9 @@ class DisplayContent extends RootDisplayArea implements WindowManagerPolicy.Disp
private final ToBooleanFunction<WindowState> mFindFocusedWindow = w -> {
final ActivityRecord focusedApp = mFocusedApp;
- ProtoLog.v(WM_DEBUG_FOCUS, "Looking for focus: %s, flags=%d, canReceive=%b",
- w, w.mAttrs.flags, w.canReceiveKeys());
+ ProtoLog.v(WM_DEBUG_FOCUS, "Looking for focus: %s, flags=%d, canReceive=%b, reason=%s",
+ w, w.mAttrs.flags, w.canReceiveKeys(),
+ w.canReceiveKeysReason(false /* fromUserTouch */));
if (!w.canReceiveKeys()) {
return false;
@@ -694,7 +693,7 @@ class DisplayContent extends RootDisplayArea implements WindowManagerPolicy.Disp
// Don't do layout of a window if it is not visible, or soon won't be visible, to avoid
// wasting time and funky changes while a window is animating away.
final boolean gone = (mTmpWindow != null && mWmService.mPolicy.canBeHiddenByKeyguardLw(w))
- || w.isGoneForLayoutLw();
+ || w.isGoneForLayout();
if (DEBUG_LAYOUT && !w.mLayoutAttached) {
Slog.v(TAG, "1ST PASS " + w + ": gone=" + gone + " mHaveFrame=" + w.mHaveFrame
@@ -742,7 +741,7 @@ class DisplayContent extends RootDisplayArea implements WindowManagerPolicy.Disp
if (firstLayout) {
// The client may compute its actual requested size according to the first layout,
// so we still request the window to resize if the current frame is empty.
- if (!w.getFrameLw().isEmpty()) {
+ if (!w.getFrame().isEmpty()) {
w.updateLastFrames();
}
w.updateLastInsetValues();
@@ -753,9 +752,9 @@ class DisplayContent extends RootDisplayArea implements WindowManagerPolicy.Disp
w.mActivityRecord.layoutLetterbox(w);
}
- if (DEBUG_LAYOUT) Slog.v(TAG, " LAYOUT: mFrame=" + w.getFrameLw()
+ if (DEBUG_LAYOUT) Slog.v(TAG, " LAYOUT: mFrame=" + w.getFrame()
+ " mContainingFrame=" + w.getContainingFrame()
- + " mDisplayFrame=" + w.getDisplayFrameLw());
+ + " mDisplayFrame=" + w.getDisplayFrame());
}
};
@@ -780,9 +779,9 @@ class DisplayContent extends RootDisplayArea implements WindowManagerPolicy.Disp
w.prelayout();
getDisplayPolicy().layoutWindowLw(w, w.getParentWindow(), mDisplayFrames);
w.mLayoutSeq = mLayoutSeq;
- if (DEBUG_LAYOUT) Slog.v(TAG, " LAYOUT: mFrame=" + w.getFrameLw()
+ if (DEBUG_LAYOUT) Slog.v(TAG, " LAYOUT: mFrame=" + w.getFrame()
+ " mContainingFrame=" + w.getContainingFrame()
- + " mDisplayFrame=" + w.getDisplayFrameLw());
+ + " mDisplayFrame=" + w.getDisplayFrame());
}
}
};
@@ -807,7 +806,7 @@ class DisplayContent extends RootDisplayArea implements WindowManagerPolicy.Disp
w.mObscured = mTmpApplySurfaceChangesTransactionState.obscured;
if (!mTmpApplySurfaceChangesTransactionState.obscured) {
- final boolean isDisplayed = w.isDisplayedLw();
+ final boolean isDisplayed = w.isDisplayed();
if (isDisplayed && w.isObscuringDisplay()) {
// This window completely covers everything behind it, so we want to leave all
@@ -2549,7 +2548,7 @@ class DisplayContent extends RootDisplayArea implements WindowManagerPolicy.Disp
return;
}
- if (w.isOnScreen() && w.isVisibleLw() && w.getFrameLw().contains(x, y)) {
+ if (w.isOnScreen() && w.isVisibleLw() && w.getFrame().contains(x, y)) {
targetWindowType[0] = w.mAttrs.type;
return;
}
@@ -2747,7 +2746,7 @@ class DisplayContent extends RootDisplayArea implements WindowManagerPolicy.Disp
void adjustForImeIfNeeded() {
final WindowState imeWin = mInputMethodWindow;
final boolean imeVisible = imeWin != null && imeWin.isVisibleLw()
- && imeWin.isDisplayedLw();
+ && imeWin.isDisplayed();
final int imeHeight = mDisplayFrames.getInputMethodWindowVisibleHeight();
mPinnedStackControllerLocked.setAdjustedForIme(imeVisible, imeHeight);
}
@@ -3072,7 +3071,7 @@ class DisplayContent extends RootDisplayArea implements WindowManagerPolicy.Disp
*/
WindowState findFocusedWindowIfNeeded(int topFocusedDisplayId) {
return (mWmService.mPerDisplayFocusEnabled || topFocusedDisplayId == INVALID_DISPLAY)
- ? findFocusedWindow() : null;
+ ? findFocusedWindow() : null;
}
WindowState findFocusedWindow() {
@@ -3081,7 +3080,8 @@ class DisplayContent extends RootDisplayArea implements WindowManagerPolicy.Disp
forAllWindows(mFindFocusedWindow, true /* traverseTopToBottom */);
if (mTmpWindow == null) {
- ProtoLog.v(WM_DEBUG_FOCUS_LIGHT, "findFocusedWindow: No focusable windows.");
+ ProtoLog.v(WM_DEBUG_FOCUS_LIGHT, "findFocusedWindow: No focusable windows, display=%d",
+ getDisplayId());
return null;
}
return mTmpWindow;
@@ -3116,18 +3116,15 @@ class DisplayContent extends RootDisplayArea implements WindowManagerPolicy.Disp
&& mode != UPDATE_FOCUS_WILL_PLACE_SURFACES) {
assignWindowLayers(false /* setLayoutNeeded */);
}
- }
- if (imWindowChanged) {
- mWmService.mWindowsChanged = true;
- setLayoutNeeded();
- newFocus = findFocusedWindowIfNeeded(topFocusedDisplayId);
- }
- if (mCurrentFocus != newFocus) {
- mWmService.mH.obtainMessage(REPORT_FOCUS_CHANGE, this).sendToTarget();
+ if (imWindowChanged) {
+ mWmService.mWindowsChanged = true;
+ setLayoutNeeded();
+ newFocus = findFocusedWindowIfNeeded(topFocusedDisplayId);
+ }
}
- ProtoLog.v(WM_DEBUG_FOCUS_LIGHT, "Changing focus from %s to %s displayId=%d Callers=%s",
+ ProtoLog.d(WM_DEBUG_FOCUS_LIGHT, "Changing focus from %s to %s displayId=%d Callers=%s",
mCurrentFocus, newFocus, getDisplayId(), Debug.getCallers(4));
final WindowState oldFocus = mCurrentFocus;
mCurrentFocus = newFocus;
@@ -3185,9 +3182,25 @@ class DisplayContent extends RootDisplayArea implements WindowManagerPolicy.Disp
if (mode == UPDATE_FOCUS_PLACING_SURFACES) {
pendingLayoutChanges |= FINISH_LAYOUT_REDO_ANIM;
}
+
+ // Notify the accessibility manager for the change so it has the windows before the newly
+ // focused one starts firing events.
+ // TODO(b/151179149) investigate what info accessibility service needs before input can
+ // dispatch focus to clients.
+ if (mWmService.mAccessibilityController != null) {
+ mWmService.mH.sendMessage(PooledLambda.obtainMessage(
+ this::updateAccessibilityOnWindowFocusChanged,
+ mWmService.mAccessibilityController));
+ }
+
+ mLastFocus = mCurrentFocus;
return true;
}
+ void updateAccessibilityOnWindowFocusChanged(AccessibilityController accessibilityController) {
+ accessibilityController.onWindowFocusChangedNotLocked(getDisplayId());
+ }
+
private static void onWindowFocusChanged(WindowState oldFocus, WindowState newFocus) {
final Task focusedTask = newFocus != null ? newFocus.getTask() : null;
final Task unfocusedTask = oldFocus != null ? oldFocus.getTask() : null;
@@ -3219,6 +3232,8 @@ class DisplayContent extends RootDisplayArea implements WindowManagerPolicy.Disp
if (mFocusedApp == newFocus) {
return false;
}
+ ProtoLog.i(WM_DEBUG_FOCUS_LIGHT, "setFocusedApp %s displayId=%d Callers=%s",
+ newFocus, getDisplayId(), Debug.getCallers(4));
mFocusedApp = newFocus;
getInputMonitor().setFocusedAppLw(newFocus);
updateTouchExcludeRegion();
@@ -3364,7 +3379,7 @@ class DisplayContent extends RootDisplayArea implements WindowManagerPolicy.Disp
// Now, a special case -- if the last target's window is in the process of exiting, but
// not removed, keep on the last target to avoid IME flicker. The exception is if the
// current target is home since we want opening apps to become the IME target right away.
- if (curTarget != null && !curTarget.mRemoved && curTarget.isDisplayedLw()
+ if (curTarget != null && !curTarget.mRemoved && curTarget.isDisplayed()
&& curTarget.isClosing() && !curTarget.isActivityTypeHome()) {
if (DEBUG_INPUT_METHOD) Slog.v(TAG_WM, "Not changing target till current window is"
+ " closing and not removed");
@@ -3647,7 +3662,7 @@ class DisplayContent extends RootDisplayArea implements WindowManagerPolicy.Disp
final WindowState visibleNotDrawnWindow = getWindow(w -> {
final boolean isVisible = w.isVisible() && !w.mObscured;
- final boolean isDrawn = w.isDrawnLw();
+ final boolean isDrawn = w.isDrawn();
if (isVisible && !isDrawn) {
ProtoLog.d(WM_DEBUG_BOOT,
"DisplayContent: boot is waiting for window of type %d to be drawn",
@@ -4599,9 +4614,9 @@ class DisplayContent extends RootDisplayArea implements WindowManagerPolicy.Disp
DisplayContent dc = this;
do {
final WindowState displayParent = dc.getParentWindow();
- location.x += displayParent.getFrameLw().left
+ location.x += displayParent.getFrame().left
+ (dc.getLocationInParentWindow().x * displayParent.mGlobalScale + 0.5f);
- location.y += displayParent.getFrameLw().top
+ location.y += displayParent.getFrame().top
+ (dc.getLocationInParentWindow().y * displayParent.mGlobalScale + 0.5f);
dc = displayParent.getDisplayContent();
} while (dc != null && dc.getParentWindow() != null);
@@ -4708,7 +4723,7 @@ class DisplayContent extends RootDisplayArea implements WindowManagerPolicy.Disp
// Traverse all windows top down to assemble the gesture exclusion rects.
// For each window, we only take the rects that fall within its touchable region.
forAllWindows(w -> {
- if (w.cantReceiveTouchInput() || !w.isVisible()
+ if (!w.canReceiveTouchInput() || !w.isVisible()
|| (w.getAttrs().flags & FLAG_NOT_TOUCHABLE) != 0
|| unhandled.isEmpty()) {
return;
@@ -5225,30 +5240,6 @@ class DisplayContent extends RootDisplayArea implements WindowManagerPolicy.Disp
&& (mAtmService.mRunningVoice == null);
}
- void setFocusedApp(ActivityRecord r, boolean moveFocusNow) {
- final ActivityRecord newFocus;
- final IBinder token = r.appToken;
- if (token == null) {
- ProtoLog.v(WM_DEBUG_FOCUS_LIGHT, "Clearing focused app, displayId=%d",
- mDisplayId);
- newFocus = null;
- } else {
- newFocus = mWmService.mRoot.getActivityRecord(token);
- if (newFocus == null) {
- Slog.w(TAG_WM, "Attempted to set focus to non-existing app token: " + token
- + ", displayId=" + mDisplayId);
- }
- ProtoLog.v(WM_DEBUG_FOCUS_LIGHT,
- "Set focused app to: %s moveFocusNow=%b displayId=%d", newFocus,
- moveFocusNow, mDisplayId);
- }
-
- final boolean changed = setFocusedApp(newFocus);
- if (moveFocusNow && changed) {
- mWmService.updateFocusedWindowLocked(UPDATE_FOCUS_NORMAL,
- true /*updateInputWindows*/);
- }
- }
void ensureActivitiesVisible(ActivityRecord starting, int configChanges,
boolean preserveWindows, boolean notifyClients) {
diff --git a/services/core/java/com/android/server/wm/DisplayPolicy.java b/services/core/java/com/android/server/wm/DisplayPolicy.java
index 40fc25b41d9f..4998624b9097 100644
--- a/services/core/java/com/android/server/wm/DisplayPolicy.java
+++ b/services/core/java/com/android/server/wm/DisplayPolicy.java
@@ -29,6 +29,7 @@ import static android.view.InsetsState.ITYPE_BOTTOM_DISPLAY_CUTOUT;
import static android.view.InsetsState.ITYPE_BOTTOM_GESTURES;
import static android.view.InsetsState.ITYPE_BOTTOM_TAPPABLE_ELEMENT;
import static android.view.InsetsState.ITYPE_CAPTION_BAR;
+import static android.view.InsetsState.ITYPE_IME;
import static android.view.InsetsState.ITYPE_LEFT_DISPLAY_CUTOUT;
import static android.view.InsetsState.ITYPE_LEFT_GESTURES;
import static android.view.InsetsState.ITYPE_NAVIGATION_BAR;
@@ -38,11 +39,6 @@ import static android.view.InsetsState.ITYPE_STATUS_BAR;
import static android.view.InsetsState.ITYPE_TOP_DISPLAY_CUTOUT;
import static android.view.InsetsState.ITYPE_TOP_GESTURES;
import static android.view.InsetsState.ITYPE_TOP_TAPPABLE_ELEMENT;
-import static android.view.View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN;
-import static android.view.View.SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION;
-import static android.view.ViewGroup.LayoutParams.MATCH_PARENT;
-import static android.view.ViewRootImpl.NEW_INSETS_MODE_FULL;
-import static android.view.ViewRootImpl.NEW_INSETS_MODE_NONE;
import static android.view.WindowInsetsController.APPEARANCE_LIGHT_NAVIGATION_BARS;
import static android.view.WindowInsetsController.APPEARANCE_LIGHT_STATUS_BARS;
import static android.view.WindowInsetsController.APPEARANCE_OPAQUE_NAVIGATION_BARS;
@@ -57,20 +53,18 @@ import static android.view.WindowManager.LayoutParams.FLAG_ALLOW_LOCK_WHILE_SCRE
import static android.view.WindowManager.LayoutParams.FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS;
import static android.view.WindowManager.LayoutParams.FLAG_FORCE_NOT_FULLSCREEN;
import static android.view.WindowManager.LayoutParams.FLAG_FULLSCREEN;
-import static android.view.WindowManager.LayoutParams.FLAG_LAYOUT_ATTACHED_IN_DECOR;
import static android.view.WindowManager.LayoutParams.FLAG_LAYOUT_INSET_DECOR;
import static android.view.WindowManager.LayoutParams.FLAG_LAYOUT_IN_SCREEN;
import static android.view.WindowManager.LayoutParams.FLAG_LAYOUT_NO_LIMITS;
import static android.view.WindowManager.LayoutParams.FLAG_NOT_TOUCHABLE;
import static android.view.WindowManager.LayoutParams.FLAG_TRANSLUCENT_NAVIGATION;
import static android.view.WindowManager.LayoutParams.FLAG_TRANSLUCENT_STATUS;
-import static android.view.WindowManager.LayoutParams.LAST_APPLICATION_WINDOW;
-import static android.view.WindowManager.LayoutParams.LAST_SUB_WINDOW;
import static android.view.WindowManager.LayoutParams.LAYOUT_IN_DISPLAY_CUTOUT_MODE_ALWAYS;
import static android.view.WindowManager.LayoutParams.LAYOUT_IN_DISPLAY_CUTOUT_MODE_DEFAULT;
import static android.view.WindowManager.LayoutParams.LAYOUT_IN_DISPLAY_CUTOUT_MODE_SHORT_EDGES;
import static android.view.WindowManager.LayoutParams.PRIVATE_FLAG_FORCE_DRAW_BAR_BACKGROUNDS;
import static android.view.WindowManager.LayoutParams.PRIVATE_FLAG_FORCE_SHOW_STATUS_BAR;
+import static android.view.WindowManager.LayoutParams.PRIVATE_FLAG_INSET_PARENT_FRAME_BY_IME;
import static android.view.WindowManager.LayoutParams.PRIVATE_FLAG_IS_SCREEN_DECOR;
import static android.view.WindowManager.LayoutParams.PRIVATE_FLAG_STATUS_FORCE_SHOW_NAVIGATION;
import static android.view.WindowManager.LayoutParams.PRIVATE_FLAG_TRUSTED_OVERLAY;
@@ -78,27 +72,21 @@ import static android.view.WindowManager.LayoutParams.SOFT_INPUT_ADJUST_NOTHING;
import static android.view.WindowManager.LayoutParams.SOFT_INPUT_ADJUST_RESIZE;
import static android.view.WindowManager.LayoutParams.SOFT_INPUT_MASK_ADJUST;
import static android.view.WindowManager.LayoutParams.TYPE_BASE_APPLICATION;
-import static android.view.WindowManager.LayoutParams.TYPE_BOOT_PROGRESS;
-import static android.view.WindowManager.LayoutParams.TYPE_DOCK_DIVIDER;
import static android.view.WindowManager.LayoutParams.TYPE_INPUT_CONSUMER;
import static android.view.WindowManager.LayoutParams.TYPE_INPUT_METHOD;
-import static android.view.WindowManager.LayoutParams.TYPE_KEYGUARD_DIALOG;
import static android.view.WindowManager.LayoutParams.TYPE_NAVIGATION_BAR;
import static android.view.WindowManager.LayoutParams.TYPE_NAVIGATION_BAR_PANEL;
import static android.view.WindowManager.LayoutParams.TYPE_NOTIFICATION_SHADE;
-import static android.view.WindowManager.LayoutParams.TYPE_SCREENSHOT;
import static android.view.WindowManager.LayoutParams.TYPE_SECURE_SYSTEM_OVERLAY;
import static android.view.WindowManager.LayoutParams.TYPE_STATUS_BAR;
import static android.view.WindowManager.LayoutParams.TYPE_STATUS_BAR_ADDITIONAL;
import static android.view.WindowManager.LayoutParams.TYPE_STATUS_BAR_PANEL;
import static android.view.WindowManager.LayoutParams.TYPE_STATUS_BAR_SUB_PANEL;
-import static android.view.WindowManager.LayoutParams.TYPE_SYSTEM_ALERT;
import static android.view.WindowManager.LayoutParams.TYPE_SYSTEM_ERROR;
import static android.view.WindowManager.LayoutParams.TYPE_SYSTEM_OVERLAY;
import static android.view.WindowManager.LayoutParams.TYPE_TOAST;
import static android.view.WindowManager.LayoutParams.TYPE_VOICE_INTERACTION;
import static android.view.WindowManager.LayoutParams.TYPE_VOICE_INTERACTION_STARTING;
-import static android.view.WindowManager.LayoutParams.TYPE_VOLUME_OVERLAY;
import static android.view.WindowManager.LayoutParams.TYPE_WALLPAPER;
import static android.view.WindowManagerGlobal.ADD_OKAY;
import static android.view.WindowManagerPolicyConstants.ACTION_HDMI_PLUGGED;
@@ -171,7 +159,6 @@ import android.view.MotionEvent;
import android.view.PointerIcon;
import android.view.Surface;
import android.view.View;
-import android.view.ViewRootImpl;
import android.view.WindowInsets.Side;
import android.view.WindowInsets.Side.InsetsSide;
import android.view.WindowInsets.Type;
@@ -195,13 +182,13 @@ import com.android.internal.widget.PointerLocationView;
import com.android.server.LocalServices;
import com.android.server.UiThread;
import com.android.server.policy.WindowManagerPolicy;
-import com.android.server.policy.WindowManagerPolicy.InputConsumer;
import com.android.server.policy.WindowManagerPolicy.NavigationBarPosition;
import com.android.server.policy.WindowManagerPolicy.ScreenOnListener;
import com.android.server.policy.WindowManagerPolicy.WindowManagerFuncs;
import com.android.server.policy.WindowOrientationListener;
import com.android.server.statusbar.StatusBarManagerInternal;
import com.android.server.wallpaper.WallpaperManagerInternal;
+import com.android.server.wm.InputMonitor.EventReceiverInputConsumer;
import com.android.server.wm.utils.InsetUtils;
import java.io.PrintWriter;
@@ -416,7 +403,7 @@ public class DisplayPolicy {
private boolean mAllowLockscreenWhenOn;
@VisibleForTesting
- InputConsumer mInputConsumer = null;
+ EventReceiverInputConsumer mInputConsumer;
private PointerLocationView mPointerLocationView;
@@ -462,7 +449,7 @@ public class DisplayPolicy {
}
break;
case MSG_DISPOSE_INPUT_CONSUMER:
- disposeInputConsumer((InputConsumer) msg.obj);
+ disposeInputConsumer((EventReceiverInputConsumer) msg.obj);
break;
case MSG_ENABLE_POINTER_LOCATION:
enablePointerLocation();
@@ -1126,7 +1113,7 @@ public class DisplayPolicy {
// For IME we use regular frame.
(displayFrames, windowState, inOutFrame) ->
- inOutFrame.set(windowState.getFrameLw()));
+ inOutFrame.set(windowState.getFrame()));
mDisplayContent.setInsetProvider(ITYPE_BOTTOM_GESTURES, win,
(displayFrames, windowState, inOutFrame) -> {
@@ -1203,11 +1190,11 @@ public class DisplayPolicy {
// IME should not provide frame which is smaller than the nav bar frame. Otherwise,
// nav bar might be overlapped with the content of the client when IME is shown.
sTmpRect.set(inOutFrame);
- sTmpRect.intersectUnchecked(mNavigationBar.getFrameLw());
- inOutFrame.inset(windowState.getGivenContentInsetsLw());
+ sTmpRect.intersectUnchecked(mNavigationBar.getFrame());
+ inOutFrame.inset(windowState.mGivenContentInsets);
inOutFrame.union(sTmpRect);
} else {
- inOutFrame.inset(windowState.getGivenContentInsetsLw());
+ inOutFrame.inset(windowState.mGivenContentInsets);
}
};
}
@@ -1440,8 +1427,7 @@ public class DisplayPolicy {
DisplayCutout.ParcelableWrapper outDisplayCutout) {
final int fl = PolicyControl.getWindowFlags(null, attrs);
final int pfl = attrs.privateFlags;
- final int requestedSysUiVis = PolicyControl.getSystemUiVisibility(null, attrs);
- final int sysUiVis = requestedSysUiVis | getImpliedSysUiFlagsForLayout(attrs);
+ final int sysUiVis = PolicyControl.getSystemUiVisibility(null, attrs);
final boolean layoutInScreen = (fl & FLAG_LAYOUT_IN_SCREEN) != 0;
final boolean layoutInScreenAndInsetDecor = layoutInScreen
@@ -1461,7 +1447,7 @@ public class DisplayPolicy {
: mDisplayContent.mDisplayFrames;
if (layoutInScreenAndInsetDecor && !screenDecor) {
- if ((sysUiVis & SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION) != 0
+ if ((attrs.flags & FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS) != 0
|| (attrs.getFitInsetsTypes() & Type.navigationBars()) == 0) {
outFrame.set(displayFrames.mUnrestricted);
} else {
@@ -1492,7 +1478,6 @@ public class DisplayPolicy {
InsetUtils.insetsBetweenFrames(outFrame, sf, outStableInsets);
outDisplayCutout.set(displayFrames.mDisplayCutout.calculateRelativeTo(outFrame)
.getDisplayCutout());
- return mForceShowSystemBars;
} else {
if (layoutInScreen) {
outFrame.set(displayFrames.mUnrestricted);
@@ -1506,22 +1491,8 @@ public class DisplayPolicy {
outContentInsets.setEmpty();
outStableInsets.setEmpty();
outDisplayCutout.set(DisplayCutout.NO_CUTOUT);
- return mForceShowSystemBars;
}
- }
-
- // TODO(b/118118435): remove after migration
- private static int getImpliedSysUiFlagsForLayout(LayoutParams attrs) {
- int impliedFlags = 0;
- final boolean forceWindowDrawsBarBackgrounds =
- (attrs.privateFlags & PRIVATE_FLAG_FORCE_DRAW_BAR_BACKGROUNDS) != 0
- && attrs.height == MATCH_PARENT && attrs.width == MATCH_PARENT;
- if ((attrs.flags & FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS) != 0
- || forceWindowDrawsBarBackgrounds) {
- impliedFlags |= SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION;
- impliedFlags |= View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN;
- }
- return impliedFlags;
+ return mForceShowSystemBars;
}
private final Runnable mClearHideNavigationFlag = new Runnable() {
@@ -1668,11 +1639,8 @@ public class DisplayPolicy {
final int behavior = mLastBehavior;
final InsetsSourceProvider provider =
mDisplayContent.getInsetsStateController().peekSourceProvider(ITYPE_NAVIGATION_BAR);
- boolean navVisible = ViewRootImpl.sNewInsetsMode != ViewRootImpl.NEW_INSETS_MODE_FULL
- ? (sysui & View.SYSTEM_UI_FLAG_HIDE_NAVIGATION) == 0
- : provider != null
- ? provider.isClientVisible()
- : InsetsState.getDefaultVisibility(ITYPE_NAVIGATION_BAR);
+ boolean navVisible = provider != null ? provider.isClientVisible()
+ : InsetsState.getDefaultVisibility(ITYPE_NAVIGATION_BAR);
boolean navTranslucent = (sysui
& (View.NAVIGATION_BAR_TRANSLUCENT | View.NAVIGATION_BAR_TRANSPARENT)) != 0;
boolean immersive = (sysui & View.SYSTEM_UI_FLAG_IMMERSIVE) != 0
@@ -2057,80 +2025,6 @@ public class DisplayPolicy {
return mNavigationBarController.checkHiddenLw();
}
- private void setAttachedWindowFrames(WindowState win, int fl, int adjust, WindowState attached,
- boolean insetDecors, Rect pf, Rect df, Rect cf, Rect vf,
- DisplayFrames displayFrames) {
- if (!win.isInputMethodTarget() && attached.isInputMethodTarget()) {
- // Here's a special case: if the child window is not the 'dock window'
- // or input method target, and the window it is attached to is below
- // the dock window, then the frames we computed for the window it is
- // attached to can not be used because the dock is effectively part
- // of the underlying window and the attached window is floating on top
- // of the whole thing. So, we ignore the attached window and explicitly
- // compute the frames that would be appropriate without the dock.
- vf.set(displayFrames.mDock);
- cf.set(displayFrames.mDock);
- df.set(displayFrames.mDock);
- } else {
-
- // In case we forced the window to draw behind the navigation bar, restrict df to
- // DF.Restricted to simulate old compat behavior.
- Rect parentDisplayFrame = attached.getDisplayFrameLw();
- final WindowManager.LayoutParams attachedAttrs = attached.mAttrs;
- if ((attachedAttrs.privateFlags & PRIVATE_FLAG_FORCE_DRAW_BAR_BACKGROUNDS) != 0
- && (attachedAttrs.flags & FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS) == 0
- && (attachedAttrs.systemUiVisibility
- & SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION) == 0) {
- parentDisplayFrame = new Rect(parentDisplayFrame);
- parentDisplayFrame.intersect(displayFrames.mRestricted);
- }
-
- // The effective display frame of the attached window depends on whether it is taking
- // care of insetting its content. If not, we need to use the parent's content frame so
- // that the entire window is positioned within that content. Otherwise we can use the
- // parent display frame and let the attached window take care of positioning its content
- // appropriately.
- if (adjust != SOFT_INPUT_ADJUST_RESIZE) {
- // Set the content frame of the attached window to the parent's decor frame
- // (same as content frame when IME isn't present) if specifically requested by
- // setting {@link WindowManager.LayoutParams#FLAG_LAYOUT_ATTACHED_IN_DECOR} flag.
- // Otherwise, use the overscan frame.
- cf.set((fl & FLAG_LAYOUT_ATTACHED_IN_DECOR) != 0
- ? attached.getContentFrameLw() : parentDisplayFrame);
- } else {
- // If the window is resizing, then we want to base the content frame on our attached
- // content frame to resize...however, things can be tricky if the attached window is
- // NOT in resize mode, in which case its content frame will be larger.
- // Ungh. So to deal with that, make sure the content frame we end up using is not
- // covering the IM dock.
- cf.set(attached.getContentFrameLw());
- if (attached.isVoiceInteraction()) {
- cf.intersectUnchecked(displayFrames.mVoiceContent);
- } else if (win.isInputMethodTarget() || attached.isInputMethodTarget()) {
- cf.intersectUnchecked(displayFrames.mContent);
- }
- }
- df.set(insetDecors ? parentDisplayFrame : cf);
- vf.set(attached.getVisibleFrameLw());
- }
- // The LAYOUT_IN_SCREEN flag is used to determine whether the attached window should be
- // positioned relative to its parent or the entire screen.
- pf.set((fl & FLAG_LAYOUT_IN_SCREEN) == 0 ? attached.getFrameLw() : df);
- }
-
- private void applyStableConstraints(int sysui, int fl, Rect r, DisplayFrames displayFrames) {
- if ((sysui & View.SYSTEM_UI_FLAG_LAYOUT_STABLE) == 0) {
- return;
- }
- // If app is requesting a stable layout, don't let the content insets go below the stable
- // values.
- if ((fl & FLAG_FULLSCREEN) != 0) {
- r.intersectUnchecked(displayFrames.mStableFullscreen);
- } else {
- r.intersectUnchecked(displayFrames.mStable);
- }
- }
-
private boolean canReceiveInput(WindowState win) {
boolean notFocusable =
(win.getAttrs().flags & WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE) != 0;
@@ -2165,8 +2059,6 @@ public class DisplayPolicy {
final int fl = PolicyControl.getWindowFlags(win, attrs);
final int pfl = attrs.privateFlags;
final int sim = attrs.softInputMode;
- final int requestedSysUiFl = PolicyControl.getSystemUiVisibility(null, attrs);
- final int sysUiFl = requestedSysUiFl | getImpliedSysUiFlagsForLayout(attrs);
displayFrames = win.getDisplayFrames(displayFrames);
final WindowFrames windowFrames = win.getWindowFrames();
@@ -2191,351 +2083,60 @@ public class DisplayPolicy {
sf.set(displayFrames.mStable);
- if (ViewRootImpl.sNewInsetsMode == NEW_INSETS_MODE_FULL) {
- final @InsetsType int typesToFit = attrs.getFitInsetsTypes();
- final @InsetsSide int sidesToFit = attrs.getFitInsetsSides();
- final ArraySet<Integer> types = InsetsState.toInternalType(typesToFit);
- getRotatedWindowBounds(displayFrames, win, sTmpRect);
- final Rect dfu = sTmpRect;
- Insets insets = Insets.of(0, 0, 0, 0);
- for (int i = types.size() - 1; i >= 0; i--) {
- final InsetsSource source = mDisplayContent.getInsetsPolicy()
- .getInsetsForDispatch(win).peekSource(types.valueAt(i));
- if (source == null) {
- continue;
- }
- insets = Insets.max(insets, source.calculateInsets(
- dfu, attrs.isFitInsetsIgnoringVisibility()));
- }
- final int left = (sidesToFit & Side.LEFT) != 0 ? insets.left : 0;
- final int top = (sidesToFit & Side.TOP) != 0 ? insets.top : 0;
- final int right = (sidesToFit & Side.RIGHT) != 0 ? insets.right : 0;
- final int bottom = (sidesToFit & Side.BOTTOM) != 0 ? insets.bottom : 0;
- df.set(dfu.left + left, dfu.top + top, dfu.right - right, dfu.bottom - bottom);
- if (attached == null) {
- pf.set(df);
- vf.set(adjust != SOFT_INPUT_ADJUST_NOTHING
- ? displayFrames.mCurrent : displayFrames.mDock);
- } else {
- pf.set((fl & FLAG_LAYOUT_IN_SCREEN) == 0 ? attached.getFrameLw() : df);
- vf.set(attached.getVisibleFrameLw());
- }
- cf.set(adjust != SOFT_INPUT_ADJUST_RESIZE
- ? displayFrames.mDock : displayFrames.mContent);
- dcf.set(displayFrames.mSystem);
- } else if (type == TYPE_INPUT_METHOD) {
- vf.set(displayFrames.mDock);
- cf.set(displayFrames.mDock);
- df.set(displayFrames.mDock);
- pf.set(displayFrames.mDock);
- // IM dock windows layout below the nav bar...
- pf.bottom = df.bottom = displayFrames.mUnrestricted.bottom;
- // ...with content insets above the nav bar
- cf.bottom = vf.bottom = displayFrames.mStable.bottom;
- if (mStatusBar != null && mFocusedWindow == mStatusBar && canReceiveInput(mStatusBar)) {
- // The status bar forces the navigation bar while it's visible. Make sure the IME
- // avoids the navigation bar in that case.
- if (mNavigationBarPosition == NAV_BAR_RIGHT) {
- pf.right = df.right = cf.right = vf.right =
- displayFrames.mStable.right;
- } else if (mNavigationBarPosition == NAV_BAR_LEFT) {
- pf.left = df.left = cf.left = vf.left = displayFrames.mStable.left;
- }
- }
-
- // In case the navigation bar is on the bottom, we use the frame height instead of the
- // regular height for the insets we send to the IME as we need some space to show
- // additional buttons in SystemUI when the IME is up.
- if (mNavigationBarPosition == NAV_BAR_BOTTOM) {
- final int rotation = displayFrames.mRotation;
- final int uimode = mService.mPolicy.getUiMode();
- final int navHeightOffset = getNavigationBarFrameHeight(rotation, uimode)
- - getNavigationBarHeight(rotation, uimode);
- if (navHeightOffset > 0) {
- cf.bottom -= navHeightOffset;
- sf.bottom -= navHeightOffset;
- vf.bottom -= navHeightOffset;
- dcf.bottom -= navHeightOffset;
- }
- }
-
- // IM dock windows always go to the bottom of the screen.
- attrs.gravity = Gravity.BOTTOM;
- } else if (type == TYPE_VOICE_INTERACTION) {
- df.set(displayFrames.mUnrestricted);
- pf.set(displayFrames.mUnrestricted);
- if (adjust != SOFT_INPUT_ADJUST_RESIZE) {
- cf.set(displayFrames.mDock);
- } else {
- cf.set(displayFrames.mContent);
- }
- if (adjust != SOFT_INPUT_ADJUST_NOTHING) {
- vf.set(displayFrames.mCurrent);
- } else {
- vf.set(cf);
+ final @InsetsType int typesToFit = attrs.getFitInsetsTypes();
+ final @InsetsSide int sidesToFit = attrs.getFitInsetsSides();
+ final ArraySet<Integer> types = InsetsState.toInternalType(typesToFit);
+ getRotatedWindowBounds(displayFrames, win, sTmpRect);
+ final Rect dfu = sTmpRect;
+ Insets insets = Insets.of(0, 0, 0, 0);
+ for (int i = types.size() - 1; i >= 0; i--) {
+ final InsetsSource source = mDisplayContent.getInsetsPolicy()
+ .getInsetsForDispatch(win).peekSource(types.valueAt(i));
+ if (source == null) {
+ continue;
}
- } else if (type == TYPE_WALLPAPER) {
- layoutWallpaper(displayFrames, pf, df, cf);
- } else if (win == mStatusBar || type == TYPE_NOTIFICATION_SHADE) {
- df.set(displayFrames.mUnrestricted);
- pf.set(displayFrames.mUnrestricted);
- cf.set(displayFrames.mStable);
- vf.set(displayFrames.mStable);
-
- if (adjust == SOFT_INPUT_ADJUST_RESIZE) {
- // cf.bottom should not be below the stable bottom, or the content might be obscured
- // by the navigation bar.
- if (cf.bottom > displayFrames.mContent.bottom) {
- cf.bottom = displayFrames.mContent.bottom;
- }
- } else {
- if (cf.bottom > displayFrames.mDock.bottom) {
- cf.bottom = displayFrames.mDock.bottom;
- }
- if (vf.bottom > displayFrames.mContent.bottom) {
- vf.bottom = displayFrames.mContent.bottom;
+ insets = Insets.max(insets, source.calculateInsets(
+ dfu, attrs.isFitInsetsIgnoringVisibility()));
+ }
+ final int left = (sidesToFit & Side.LEFT) != 0 ? insets.left : 0;
+ final int top = (sidesToFit & Side.TOP) != 0 ? insets.top : 0;
+ final int right = (sidesToFit & Side.RIGHT) != 0 ? insets.right : 0;
+ final int bottom = (sidesToFit & Side.BOTTOM) != 0 ? insets.bottom : 0;
+ df.set(dfu.left + left, dfu.top + top, dfu.right - right, dfu.bottom - bottom);
+ if (attached == null) {
+ pf.set(df);
+ if ((pfl & PRIVATE_FLAG_INSET_PARENT_FRAME_BY_IME) != 0) {
+ final InsetsSource source = mDisplayContent.getInsetsPolicy()
+ .getInsetsForDispatch(win).peekSource(ITYPE_IME);
+ if (source != null) {
+ pf.inset(source.calculateInsets(pf, false /* ignoreVisibility */));
}
}
+ vf.set(adjust != SOFT_INPUT_ADJUST_NOTHING
+ ? displayFrames.mCurrent : displayFrames.mDock);
} else {
- dcf.set(displayFrames.mSystem);
- final boolean isAppWindow =
- type >= FIRST_APPLICATION_WINDOW && type <= LAST_APPLICATION_WINDOW;
- final boolean topAtRest =
- win == mTopFullscreenOpaqueWindowState && !win.isAnimatingLw();
- if (isAppWindow && !topAtRest) {
- if ((sysUiFl & View.SYSTEM_UI_FLAG_FULLSCREEN) == 0
- && (fl & FLAG_FULLSCREEN) == 0
- && (fl & FLAG_TRANSLUCENT_STATUS) == 0
- && (fl & FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS) == 0
- && (pfl & PRIVATE_FLAG_FORCE_DRAW_BAR_BACKGROUNDS) == 0) {
- // Ensure policy decor includes status bar
- dcf.top = displayFrames.mStable.top;
- }
- if ((fl & FLAG_TRANSLUCENT_NAVIGATION) == 0
- && (sysUiFl & View.SYSTEM_UI_FLAG_HIDE_NAVIGATION) == 0
- && (fl & FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS) == 0
- && (pfl & PRIVATE_FLAG_FORCE_DRAW_BAR_BACKGROUNDS) == 0) {
- // Ensure policy decor includes navigation bar
- dcf.bottom = displayFrames.mStable.bottom;
- dcf.right = displayFrames.mStable.right;
- }
- }
-
- if (layoutInScreen && layoutInsetDecor) {
- if (DEBUG_LAYOUT) Slog.v(TAG, "layoutWindowLw(" + attrs.getTitle()
- + "): IN_SCREEN, INSET_DECOR");
- // This is the case for a normal activity window: we want it to cover all of the
- // screen space, and it can take care of moving its contents to account for screen
- // decorations that intrude into that space.
- if (attached != null) {
- // If this window is attached to another, our display
- // frame is the same as the one we are attached to.
- setAttachedWindowFrames(win, fl, adjust, attached, true, pf, df, cf, vf,
- displayFrames);
- } else {
- if (type == TYPE_STATUS_BAR_ADDITIONAL || type == TYPE_STATUS_BAR_SUB_PANEL) {
- // Status bar panels are the only windows who can go on top of the status
- // bar. They are protected by the STATUS_BAR_SERVICE permission, so they
- // have the same privileges as the status bar itself.
- //
- // However, they should still dodge the navigation bar if it exists.
-
- pf.left = df.left = hasNavBar
- ? displayFrames.mDock.left : displayFrames.mUnrestricted.left;
- pf.top = df.top = displayFrames.mUnrestricted.top;
- pf.right = df.right = hasNavBar
- ? displayFrames.mRestricted.right
- : displayFrames.mUnrestricted.right;
- pf.bottom = df.bottom = hasNavBar
- ? displayFrames.mRestricted.bottom
- : displayFrames.mUnrestricted.bottom;
-
- if (DEBUG_LAYOUT) Slog.v(TAG, "Laying out status bar window: " + pf);
- } else if ((sysUiFl & SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION) != 0
- && (type >= FIRST_APPLICATION_WINDOW && type <= LAST_SUB_WINDOW
- || type == TYPE_VOLUME_OVERLAY
- || type == TYPE_KEYGUARD_DIALOG)) {
- // Asking for layout as if the nav bar is hidden, lets the application
- // extend into the unrestricted overscan screen area. We only do this for
- // application windows and certain system windows to ensure no window that
- // can be above the nav bar can do this.
- df.set(displayFrames.mUnrestricted);
- pf.set(displayFrames.mUnrestricted);
- } else {
- df.set(displayFrames.mRestricted);
- pf.set(displayFrames.mRestricted);
- }
-
- if ((fl & FLAG_FULLSCREEN) == 0) {
- if (win.isVoiceInteraction()) {
- cf.set(displayFrames.mVoiceContent);
- } else {
- // IME Insets are handled on the client for ADJUST_RESIZE in the new
- // insets world
- if (ViewRootImpl.sNewInsetsMode != NEW_INSETS_MODE_NONE
- || adjust != SOFT_INPUT_ADJUST_RESIZE) {
- cf.set(displayFrames.mDock);
- } else {
- cf.set(displayFrames.mContent);
- }
- }
- } else {
- // Full screen windows are always given a layout that is as if the status
- // bar and other transient decors are gone. This is to avoid bad states when
- // moving from a window that is not hiding the status bar to one that is.
- cf.set(displayFrames.mRestricted);
- }
- applyStableConstraints(sysUiFl, fl, cf, displayFrames);
- if (ViewRootImpl.sNewInsetsMode == NEW_INSETS_MODE_NONE
- && adjust != SOFT_INPUT_ADJUST_NOTHING) {
- vf.set(displayFrames.mCurrent);
- } else {
- vf.set(cf);
- }
- }
- } else if (layoutInScreen || (sysUiFl
- & (SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN
- | SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION)) != 0) {
- if (DEBUG_LAYOUT) Slog.v(TAG, "layoutWindowLw(" + attrs.getTitle()
- + "): IN_SCREEN");
- // A window that has requested to fill the entire screen just
- // gets everything, period.
- if (type == TYPE_STATUS_BAR_ADDITIONAL || type == TYPE_STATUS_BAR_SUB_PANEL) {
- cf.set(displayFrames.mUnrestricted);
- df.set(displayFrames.mUnrestricted);
- pf.set(displayFrames.mUnrestricted);
- if (hasNavBar) {
- pf.left = df.left = cf.left = displayFrames.mDock.left;
- pf.right = df.right = cf.right = displayFrames.mRestricted.right;
- pf.bottom = df.bottom = cf.bottom =
- displayFrames.mRestricted.bottom;
- }
- if (DEBUG_LAYOUT) Slog.v(TAG, "Laying out IN_SCREEN status bar window: " + pf);
- } else if (type == TYPE_NAVIGATION_BAR || type == TYPE_NAVIGATION_BAR_PANEL) {
- // The navigation bar has Real Ultimate Power.
- df.set(displayFrames.mUnrestricted);
- pf.set(displayFrames.mUnrestricted);
- if (DEBUG_LAYOUT) Slog.v(TAG, "Laying out navigation bar window: " + pf);
- } else if ((type == TYPE_SECURE_SYSTEM_OVERLAY || type == TYPE_SCREENSHOT)
- && ((fl & FLAG_FULLSCREEN) != 0)) {
- // Fullscreen secure system overlays get what they ask for. Screenshot region
- // selection overlay should also expand to full screen.
- cf.set(displayFrames.mUnrestricted);
- df.set(displayFrames.mUnrestricted);
- pf.set(displayFrames.mUnrestricted);
- } else if (type == TYPE_BOOT_PROGRESS) {
- // Boot progress screen always covers entire display.
- cf.set(displayFrames.mUnrestricted);
- df.set(displayFrames.mUnrestricted);
- pf.set(displayFrames.mUnrestricted);
- } else if ((sysUiFl & SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION) != 0
- && (type == TYPE_NOTIFICATION_SHADE
- || type == TYPE_TOAST
- || type == TYPE_DOCK_DIVIDER
- || type == TYPE_VOICE_INTERACTION_STARTING
- || (type >= FIRST_APPLICATION_WINDOW && type <= LAST_SUB_WINDOW))) {
- // Asking for layout as if the nav bar is hidden, lets the
- // application extend into the unrestricted screen area. We
- // only do this for application windows (or toasts) to ensure no window that
- // can be above the nav bar can do this.
- // XXX This assumes that an app asking for this will also
- // ask for layout in only content. We can't currently figure out
- // what the screen would be if only laying out to hide the nav bar.
- cf.set(displayFrames.mUnrestricted);
- df.set(displayFrames.mUnrestricted);
- pf.set(displayFrames.mUnrestricted);
- } else if ((sysUiFl & SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN) != 0) {
- df.set(displayFrames.mRestricted);
- pf.set(displayFrames.mRestricted);
-
- // IME Insets are handled on the client for ADJUST_RESIZE in the new insets
- // world
- if (ViewRootImpl.sNewInsetsMode != NEW_INSETS_MODE_NONE
- || adjust != SOFT_INPUT_ADJUST_RESIZE) {
- cf.set(displayFrames.mDock);
- } else {
- cf.set(displayFrames.mContent);
- }
- } else {
- cf.set(displayFrames.mRestricted);
- df.set(displayFrames.mRestricted);
- pf.set(displayFrames.mRestricted);
- }
-
- applyStableConstraints(sysUiFl, fl, cf, displayFrames);
-
- if (ViewRootImpl.sNewInsetsMode == NEW_INSETS_MODE_NONE
- && adjust != SOFT_INPUT_ADJUST_NOTHING) {
- vf.set(displayFrames.mCurrent);
- } else {
- vf.set(cf);
- }
- } else if (attached != null) {
- if (DEBUG_LAYOUT) Slog.v(TAG, "layoutWindowLw(" + attrs.getTitle()
- + "): attached to " + attached);
- // A child window should be placed inside of the same visible
- // frame that its parent had.
- setAttachedWindowFrames(win, fl, adjust, attached, false, pf, df, cf, vf,
- displayFrames);
- } else {
- if (DEBUG_LAYOUT) Slog.v(TAG, "layoutWindowLw(" + attrs.getTitle()
- + "): normal window");
- // Otherwise, a normal window must be placed inside the content
- // of all screen decorations.
- if (type == TYPE_STATUS_BAR_ADDITIONAL) {
- // Status bar panels can go on
- // top of the status bar. They are protected by the STATUS_BAR_SERVICE
- // permission, so they have the same privileges as the status bar itself.
- cf.set(displayFrames.mRestricted);
- df.set(displayFrames.mRestricted);
- pf.set(displayFrames.mRestricted);
- } else if (type == TYPE_TOAST || type == TYPE_SYSTEM_ALERT) {
- // These dialogs are stable to interim decor changes.
- cf.set(displayFrames.mStable);
- df.set(displayFrames.mStable);
- pf.set(displayFrames.mStable);
- } else {
- pf.set(displayFrames.mContent);
- if (win.isVoiceInteraction()) {
- cf.set(displayFrames.mVoiceContent);
- df.set(displayFrames.mVoiceContent);
- } else if (adjust != SOFT_INPUT_ADJUST_RESIZE) {
- cf.set(displayFrames.mDock);
- df.set(displayFrames.mDock);
- } else {
- cf.set(displayFrames.mContent);
- df.set(displayFrames.mContent);
- }
- if (ViewRootImpl.sNewInsetsMode == NEW_INSETS_MODE_NONE
- && adjust != SOFT_INPUT_ADJUST_NOTHING) {
- vf.set(displayFrames.mCurrent);
- } else {
- vf.set(cf);
- }
- }
- }
+ pf.set((fl & FLAG_LAYOUT_IN_SCREEN) == 0 ? attached.getFrame() : df);
+ vf.set(attached.getVisibleFrame());
}
+ cf.set(adjust != SOFT_INPUT_ADJUST_RESIZE
+ ? displayFrames.mDock : displayFrames.mContent);
+ dcf.set(displayFrames.mSystem);
final int cutoutMode = attrs.layoutInDisplayCutoutMode;
- final boolean attachedInParent = attached != null && !layoutInScreen;
- final boolean requestedFullscreen = (fl & FLAG_FULLSCREEN) != 0
- || (requestedSysUiFl & View.SYSTEM_UI_FLAG_FULLSCREEN) != 0
- || (ViewRootImpl.sNewInsetsMode == NEW_INSETS_MODE_FULL
- && !win.getRequestedInsetsState().getSourceOrDefaultVisibility(
- ITYPE_STATUS_BAR));
- final boolean requestedHideNavigation =
- (requestedSysUiFl & View.SYSTEM_UI_FLAG_HIDE_NAVIGATION) != 0
- || (ViewRootImpl.sNewInsetsMode == NEW_INSETS_MODE_FULL
- && !win.getRequestedInsetsState().getSourceOrDefaultVisibility(
- ITYPE_NAVIGATION_BAR));
-
- // TYPE_BASE_APPLICATION windows are never considered floating here because they don't get
- // cropped / shifted to the displayFrame in WindowState.
- final boolean floatingInScreenWindow = !attrs.isFullscreen() && layoutInScreen
- && type != TYPE_BASE_APPLICATION;
// Ensure that windows with a DEFAULT or NEVER display cutout mode are laid out in
// the cutout safe zone.
if (cutoutMode != LAYOUT_IN_DISPLAY_CUTOUT_MODE_ALWAYS) {
+ final boolean attachedInParent = attached != null && !layoutInScreen;
+ final InsetsState requestedInsetsState = win.getRequestedInsetsState();
+ final boolean requestedFullscreen = (fl & FLAG_FULLSCREEN) != 0
+ || !requestedInsetsState.getSourceOrDefaultVisibility(ITYPE_STATUS_BAR);
+ final boolean requestedHideNavigation =
+ !requestedInsetsState.getSourceOrDefaultVisibility(ITYPE_NAVIGATION_BAR);
+
+ // TYPE_BASE_APPLICATION windows are never considered floating here because they don't
+ // get cropped / shifted to the displayFrame in WindowState.
+ final boolean floatingInScreenWindow = !attrs.isFullscreen() && layoutInScreen
+ && type != TYPE_BASE_APPLICATION;
final Rect displayCutoutSafeExceptMaybeBars = sTmpDisplayCutoutSafeExceptMaybeBarsRect;
displayCutoutSafeExceptMaybeBars.set(displayFrames.mDisplayCutoutSafe);
if (cutoutMode == LAYOUT_IN_DISPLAY_CUTOUT_MODE_SHORT_EDGES) {
@@ -2623,30 +2224,21 @@ public class DisplayPolicy {
win.computeFrame(displayFrames);
// Dock windows carve out the bottom of the screen, so normal windows
// can't appear underneath them.
- if (type == TYPE_INPUT_METHOD && win.isVisibleLw()
- && !win.getGivenInsetsPendingLw()) {
+ if (type == TYPE_INPUT_METHOD && win.isVisibleLw() && !win.mGivenInsetsPending) {
offsetInputMethodWindowLw(win, displayFrames);
}
- if (type == TYPE_VOICE_INTERACTION && win.isVisibleLw()
- && !win.getGivenInsetsPendingLw()) {
+ if (type == TYPE_VOICE_INTERACTION && win.isVisibleLw() && !win.mGivenInsetsPending) {
offsetVoiceInputWindowLw(win, displayFrames);
}
}
- private void layoutWallpaper(DisplayFrames displayFrames, Rect pf, Rect df, Rect cf) {
- // The wallpaper has Real Ultimate Power
- df.set(displayFrames.mUnrestricted);
- pf.set(displayFrames.mUnrestricted);
- cf.set(displayFrames.mUnrestricted);
- }
-
private void offsetInputMethodWindowLw(WindowState win, DisplayFrames displayFrames) {
final int rotation = displayFrames.mRotation;
final int navBarPosition = navigationBarPosition(displayFrames.mDisplayWidth,
displayFrames.mDisplayHeight, rotation);
- int top = Math.max(win.getDisplayFrameLw().top, win.getContentFrameLw().top);
- top += win.getGivenContentInsetsLw().top;
+ int top = Math.max(win.getDisplayFrame().top, win.getContentFrame().top);
+ top += win.mGivenContentInsets.top;
displayFrames.mContent.bottom = Math.min(displayFrames.mContent.bottom, top);
if (navBarPosition == NAV_BAR_BOTTOM) {
// Always account for the nav bar frame height on the bottom since in all navigation
@@ -2658,8 +2250,8 @@ public class DisplayPolicy {
displayFrames.mUnrestricted.bottom - navFrameHeight);
}
displayFrames.mVoiceContent.bottom = Math.min(displayFrames.mVoiceContent.bottom, top);
- top = win.getVisibleFrameLw().top;
- top += win.getGivenVisibleInsetsLw().top;
+ top = win.getVisibleFrame().top;
+ top += win.mGivenVisibleInsets.top;
displayFrames.mCurrent.bottom = Math.min(displayFrames.mCurrent.bottom, top);
if (DEBUG_LAYOUT) Slog.v(TAG, "Input method: mDockBottom="
+ displayFrames.mDock.bottom + " mContentBottom="
@@ -2667,8 +2259,8 @@ public class DisplayPolicy {
}
private void offsetVoiceInputWindowLw(WindowState win, DisplayFrames displayFrames) {
- int top = Math.max(win.getDisplayFrameLw().top, win.getContentFrameLw().top);
- top += win.getGivenContentInsetsLw().top;
+ int top = Math.max(win.getDisplayFrame().top, win.getContentFrame().top);
+ top += win.mGivenContentInsets.top;
displayFrames.mVoiceContent.bottom = Math.min(displayFrames.mVoiceContent.bottom, top);
}
@@ -2729,8 +2321,7 @@ public class DisplayPolicy {
if (win.isDreamWindow()) {
// If the lockscreen was showing when the dream started then wait
// for the dream to draw before hiding the lockscreen.
- if (!mDreamingLockscreen
- || (win.isVisibleLw() && win.hasDrawnLw())) {
+ if (!mDreamingLockscreen || (win.isVisibleLw() && win.hasDrawn())) {
mShowingDream = true;
appWindow = true;
}
@@ -2916,7 +2507,7 @@ public class DisplayPolicy {
final InsetsSource request = mTopFullscreenOpaqueWindowState.getRequestedInsetsState()
.peekSource(ITYPE_STATUS_BAR);
if (WindowManagerDebugConfig.DEBUG) {
- Slog.d(TAG, "frame: " + mTopFullscreenOpaqueWindowState.getFrameLw());
+ Slog.d(TAG, "frame: " + mTopFullscreenOpaqueWindowState.getFrame());
Slog.d(TAG, "attr: " + attrs + " request: " + request);
}
return (fl & LayoutParams.FLAG_FULLSCREEN) != 0
@@ -3346,59 +2937,42 @@ public class DisplayPolicy {
// Swipe-up for navigation bar is disabled during setup
return;
}
- if (ViewRootImpl.sNewInsetsMode == NEW_INSETS_MODE_FULL) {
- final InsetsSourceProvider provider = swipeTarget.getControllableInsetProvider();
- final InsetsControlTarget controlTarget = provider != null
- ? provider.getControlTarget() : null;
+ final InsetsSourceProvider provider = swipeTarget.getControllableInsetProvider();
+ final InsetsControlTarget controlTarget = provider != null
+ ? provider.getControlTarget() : null;
- if (controlTarget == null || controlTarget == getNotificationShade()) {
- // No transient mode on lockscreen (in notification shade window).
- return;
- }
+ if (controlTarget == null || controlTarget == getNotificationShade()) {
+ // No transient mode on lockscreen (in notification shade window).
+ return;
+ }
- final InsetsState requestedState = controlTarget.getRequestedInsetsState();
- final @InsetsType int restorePositionTypes =
- (requestedState.getSourceOrDefaultVisibility(ITYPE_NAVIGATION_BAR)
- ? Type.navigationBars() : 0)
- | (requestedState.getSourceOrDefaultVisibility(ITYPE_STATUS_BAR)
- ? Type.statusBars() : 0);
-
- if (swipeTarget == mNavigationBar
- && (restorePositionTypes & Type.navigationBars()) != 0) {
- // Don't show status bar when swiping on already visible navigation bar.
- // But restore the position of navigation bar if it has been moved by the control
- // target.
- controlTarget.showInsets(Type.navigationBars(), false);
- return;
- }
+ final InsetsState requestedState = controlTarget.getRequestedInsetsState();
+ final @InsetsType int restorePositionTypes = (requestedState.getSourceOrDefaultVisibility(
+ ITYPE_NAVIGATION_BAR) ? Type.navigationBars() : 0) | (
+ requestedState.getSourceOrDefaultVisibility(ITYPE_STATUS_BAR) ? Type.statusBars()
+ : 0);
- if (controlTarget.canShowTransient()) {
- // Show transient bars if they are hidden; restore position if they are visible.
- mDisplayContent.getInsetsPolicy().showTransient(SHOW_TYPES_FOR_SWIPE);
- controlTarget.showInsets(restorePositionTypes, false);
- } else {
- // Restore visibilities and positions of system bars.
- controlTarget.showInsets(Type.statusBars() | Type.navigationBars(), false);
- }
+ if (swipeTarget == mNavigationBar
+ && (restorePositionTypes & Type.navigationBars()) != 0) {
+ // Don't show status bar when swiping on already visible navigation bar.
+ // But restore the position of navigation bar if it has been moved by the control
+ // target.
+ controlTarget.showInsets(Type.navigationBars(), false);
+ return;
+ }
+
+ if (controlTarget.canShowTransient()) {
+ // Show transient bars if they are hidden; restore position if they are visible.
+ mDisplayContent.getInsetsPolicy().showTransient(SHOW_TYPES_FOR_SWIPE);
+ controlTarget.showInsets(restorePositionTypes, false);
} else {
- boolean sb = mStatusBarController.checkShowTransientBarLw();
- boolean nb = mNavigationBarController.checkShowTransientBarLw()
- && !isNavBarEmpty(mLastSystemUiFlags);
- if (sb || nb) {
- // Don't show status bar when swiping on already visible navigation bar
- if (!nb && swipeTarget == mNavigationBar) {
- if (DEBUG) Slog.d(TAG, "Not showing transient bar, wrong swipe target");
- return;
- }
- if (sb) mStatusBarController.showTransient();
- if (nb) mNavigationBarController.showTransient();
- updateSystemUiVisibilityLw();
- }
+ // Restore visibilities and positions of system bars.
+ controlTarget.showInsets(Type.statusBars() | Type.navigationBars(), false);
}
mImmersiveModeConfirmation.confirmCurrentPrompt();
}
- private void disposeInputConsumer(InputConsumer inputConsumer) {
+ private void disposeInputConsumer(EventReceiverInputConsumer inputConsumer) {
if (inputConsumer != null) {
inputConsumer.dispose();
}
@@ -3482,11 +3056,10 @@ public class DisplayPolicy {
navColorWin != null && navColorWin == mDisplayContent.mInputMethodWindow;
final int opaqueAppearance = InsetsFlags.getAppearance(visibility)
& (APPEARANCE_OPAQUE_STATUS_BARS | APPEARANCE_OPAQUE_NAVIGATION_BARS);
- final int appearance = ViewRootImpl.sNewInsetsMode == NEW_INSETS_MODE_FULL
- ? updateLightNavigationBarAppearanceLw(win.mAttrs.insetsFlags.appearance,
- mTopFullscreenOpaqueWindowState, mTopFullscreenOpaqueOrDimmingWindowState,
- mDisplayContent.mInputMethodWindow, navColorWin) | opaqueAppearance
- : InsetsFlags.getAppearance(visibility);
+ final int appearance = updateLightNavigationBarAppearanceLw(
+ win.mAttrs.insetsFlags.appearance, mTopFullscreenOpaqueWindowState,
+ mTopFullscreenOpaqueOrDimmingWindowState,
+ mDisplayContent.mInputMethodWindow, navColorWin) | opaqueAppearance;
final int diff = visibility ^ mLastSystemUiFlags;
final InsetsPolicy insetsPolicy = getInsetsPolicy();
final boolean isFullscreen = (visibility & (View.SYSTEM_UI_FLAG_FULLSCREEN
@@ -3808,9 +3381,8 @@ public class DisplayPolicy {
vis = mStatusBarController.updateVisibilityLw(transientStatusBarAllowed, oldVis, vis);
// update navigation bar
- boolean newInsetsMode = ViewRootImpl.sNewInsetsMode == NEW_INSETS_MODE_FULL;
- boolean oldImmersiveMode = newInsetsMode ? mLastImmersiveMode : isImmersiveMode(oldVis);
- boolean newImmersiveMode = newInsetsMode ? isImmersiveMode(win) : isImmersiveMode(vis);
+ boolean oldImmersiveMode = mLastImmersiveMode;
+ boolean newImmersiveMode = isImmersiveMode(win);
if (oldImmersiveMode != newImmersiveMode) {
mLastImmersiveMode = newImmersiveMode;
final String pkg = win.getOwningPackage();
@@ -3914,15 +3486,6 @@ public class DisplayPolicy {
}
}
- // TODO(b/118118435): Remove this after migration
- private boolean isImmersiveMode(int vis) {
- final int flags = View.SYSTEM_UI_FLAG_IMMERSIVE | View.SYSTEM_UI_FLAG_IMMERSIVE_STICKY;
- return getNavigationBar() != null
- && (vis & View.SYSTEM_UI_FLAG_HIDE_NAVIGATION) != 0
- && (vis & flags) != 0
- && canHideNavigationBar();
- }
-
private boolean isImmersiveMode(WindowState win) {
if (win == null) {
return false;
@@ -4113,9 +3676,7 @@ public class DisplayPolicy {
mPointerLocationView = new PointerLocationView(mContext);
mPointerLocationView.setPrintCoords(false);
- final WindowManager.LayoutParams lp = new WindowManager.LayoutParams(
- WindowManager.LayoutParams.MATCH_PARENT,
- WindowManager.LayoutParams.MATCH_PARENT);
+ final WindowManager.LayoutParams lp = new WindowManager.LayoutParams();
lp.type = WindowManager.LayoutParams.TYPE_SECURE_SYSTEM_OVERLAY;
lp.flags = WindowManager.LayoutParams.FLAG_NOT_TOUCHABLE
| WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE
@@ -4171,6 +3732,6 @@ public class DisplayPolicy {
return false;
}
- return Rect.intersects(targetWindow.getFrameLw(), navBarWindow.getFrameLw());
+ return Rect.intersects(targetWindow.getFrame(), navBarWindow.getFrame());
}
}
diff --git a/services/core/java/com/android/server/wm/DragDropController.java b/services/core/java/com/android/server/wm/DragDropController.java
index 999aab982816..ec62ed44c640 100644
--- a/services/core/java/com/android/server/wm/DragDropController.java
+++ b/services/core/java/com/android/server/wm/DragDropController.java
@@ -114,7 +114,7 @@ class DragDropController {
final WindowState callingWin = mService.windowForClientLocked(
null, window, false);
- if (callingWin == null || callingWin.cantReceiveTouchInput()) {
+ if (callingWin == null || !callingWin.canReceiveTouchInput()) {
Slog.w(TAG_WM, "Bad requesting window " + window);
return null; // !!! TODO: throw here?
}
diff --git a/services/core/java/com/android/server/wm/ImeInsetsSourceProvider.java b/services/core/java/com/android/server/wm/ImeInsetsSourceProvider.java
index 86e2698302aa..f0f338534ed2 100644
--- a/services/core/java/com/android/server/wm/ImeInsetsSourceProvider.java
+++ b/services/core/java/com/android/server/wm/ImeInsetsSourceProvider.java
@@ -93,7 +93,7 @@ class ImeInsetsSourceProvider extends InsetsSourceProvider {
|| (mImeTargetFromIme != null
&& isImeTargetFromDisplayContentAndImeSame()
&& mWin != null
- && mWin.isDrawnLw()
+ && mWin.isDrawn()
&& !mWin.mGivenInsetsPending)) {
mIsImeLayoutDrawn = true;
// show IME if InputMethodService requested it to be shown.
diff --git a/services/core/java/com/android/server/wm/InputManagerCallback.java b/services/core/java/com/android/server/wm/InputManagerCallback.java
index e166bfc08ad4..0978636ea502 100644
--- a/services/core/java/com/android/server/wm/InputManagerCallback.java
+++ b/services/core/java/com/android/server/wm/InputManagerCallback.java
@@ -24,6 +24,7 @@ import android.view.InputApplicationHandle;
import android.view.KeyEvent;
import android.view.WindowManager;
+import com.android.internal.util.function.pooled.PooledLambda;
import com.android.server.am.ActivityManagerService;
import com.android.server.input.InputManagerService;
import com.android.server.wm.EmbeddedWindowController.EmbeddedWindow;
@@ -252,7 +253,7 @@ final class InputManagerCallback implements InputManagerService.WindowManagerCal
// All the calls below need to happen without the WM lock held since they call into AM.
mService.mAtmInternal.saveANRState(reason);
- if (activity != null && activity.appToken != null) {
+ if (activity != null) {
// Notify the activity manager about the timeout and let it decide whether
// to abort dispatching or keep waiting.
final boolean abort = activity.keyDispatchingTimedOut(reason, windowPid);
@@ -410,6 +411,8 @@ final class InputManagerCallback implements InputManagerService.WindowManagerCal
requestRefreshConfiguration = dispatchPointerCaptureChanged(focusedWindow, false);
}
mFocusedWindow.set(newFocusedWindow);
+ mService.mH.sendMessage(PooledLambda.obtainMessage(mService::reportFocusChanged,
+ oldToken, newToken));
return requestRefreshConfiguration;
}
diff --git a/services/core/java/com/android/server/wm/InputMonitor.java b/services/core/java/com/android/server/wm/InputMonitor.java
index 16c4942ee972..4efd687b7bb4 100644
--- a/services/core/java/com/android/server/wm/InputMonitor.java
+++ b/services/core/java/com/android/server/wm/InputMonitor.java
@@ -61,7 +61,6 @@ import android.view.InputWindowHandle;
import android.view.SurfaceControl;
import com.android.internal.protolog.common.ProtoLog;
-import com.android.server.policy.WindowManagerPolicy;
import java.io.PrintWriter;
import java.util.Set;
@@ -95,8 +94,11 @@ final class InputMonitor {
*/
private final ArrayMap<String, InputConsumerImpl> mInputConsumers = new ArrayMap();
- private static final class EventReceiverInputConsumer extends InputConsumerImpl
- implements WindowManagerPolicy.InputConsumer {
+ /**
+ * Representation of a input consumer that the policy has added to the window manager to consume
+ * input events going to windows below it.
+ */
+ static final class EventReceiverInputConsumer extends InputConsumerImpl {
private InputMonitor mInputMonitor;
private final InputEventReceiver mInputEventReceiver;
@@ -111,8 +113,8 @@ final class InputMonitor {
mClientChannel, looper);
}
- @Override
- public void dismiss() {
+ /** Removes the input consumer from the window manager. */
+ void dismiss() {
synchronized (mService.mGlobalLock) {
mInputMonitor.mInputConsumers.remove(mName);
hide(mInputMonitor.mInputTransaction);
@@ -120,8 +122,8 @@ final class InputMonitor {
}
}
- @Override
- public void dispose() {
+ /** Disposes the input consumer and input receiver from the associated thread. */
+ void dispose() {
synchronized (mService.mGlobalLock) {
disposeChannelsLw(mInputMonitor.mInputTransaction);
mInputEventReceiver.dispose();
@@ -225,7 +227,7 @@ final class InputMonitor {
}
}
- WindowManagerPolicy.InputConsumer createInputConsumer(Looper looper, String name,
+ EventReceiverInputConsumer createInputConsumer(Looper looper, String name,
InputEventReceiver.Factory inputEventReceiverFactory) {
if (!name.contentEquals(INPUT_CONSUMER_NAVIGATION)) {
throw new IllegalArgumentException("Illegal input consumer : " + name
@@ -289,7 +291,7 @@ final class InputMonitor {
inputWindowHandle.inputFeatures = child.mAttrs.inputFeatures;
inputWindowHandle.displayId = child.getDisplayId();
- final Rect frame = child.getFrameLw();
+ final Rect frame = child.getFrame();
inputWindowHandle.frameLeft = frame.left;
inputWindowHandle.frameTop = frame.top;
inputWindowHandle.frameRight = frame.right;
@@ -368,7 +370,8 @@ final class InputMonitor {
* Layer assignment is assumed to be complete by the time this is called.
*/
public void setInputFocusLw(WindowState newWindow, boolean updateInputWindows) {
- ProtoLog.d(WM_DEBUG_FOCUS_LIGHT, "Input focus has changed to %s", newWindow);
+ ProtoLog.v(WM_DEBUG_FOCUS_LIGHT, "Input focus has changed to %s display=%d",
+ newWindow, mDisplayId);
if (newWindow != mInputFocus) {
if (newWindow != null && newWindow.canReceiveKeys()) {
@@ -491,7 +494,7 @@ final class InputMonitor {
final int type = w.mAttrs.type;
final boolean isVisible = w.isVisibleLw();
if (inputChannel == null || inputWindowHandle == null || w.mRemoved
- || (w.cantReceiveTouchInput() && !shouldApplyRecentsInputConsumer)) {
+ || (!w.canReceiveTouchInput() && !shouldApplyRecentsInputConsumer)) {
if (w.mWinAnimator.hasSurface()) {
// Assign an InputInfo with type to the overlay window which can't receive input
// event. This is used to omit Surfaces from occlusion detection.
diff --git a/services/core/java/com/android/server/wm/InsetsSourceProvider.java b/services/core/java/com/android/server/wm/InsetsSourceProvider.java
index d1eb79556d1d..e00c9e7ac38b 100644
--- a/services/core/java/com/android/server/wm/InsetsSourceProvider.java
+++ b/services/core/java/com/android/server/wm/InsetsSourceProvider.java
@@ -173,7 +173,7 @@ class InsetsSourceProvider {
// frame may not yet determined that server side doesn't think the window is ready to
// visible. (i.e. No surface, pending insets that were given during layout, etc..)
if (mServerVisible) {
- mTmpRect.set(mWin.getFrameLw());
+ mTmpRect.set(mWin.getFrame());
if (mFrameProvider != null) {
mFrameProvider.accept(mWin.getDisplayContent().mDisplayFrames, mWin, mTmpRect);
} else {
@@ -185,14 +185,14 @@ class InsetsSourceProvider {
mSource.setFrame(mTmpRect);
if (mImeFrameProvider != null) {
- mImeOverrideFrame.set(mWin.getFrameLw());
+ mImeOverrideFrame.set(mWin.getFrame());
mImeFrameProvider.accept(mWin.getDisplayContent().mDisplayFrames, mWin,
mImeOverrideFrame);
}
if (mWin.mGivenVisibleInsets.left != 0 || mWin.mGivenVisibleInsets.top != 0
|| mWin.mGivenVisibleInsets.right != 0 || mWin.mGivenVisibleInsets.bottom != 0) {
- mTmpRect.set(mWin.getFrameLw());
+ mTmpRect.set(mWin.getFrame());
mTmpRect.inset(mWin.mGivenVisibleInsets);
mSource.setVisibleFrame(mTmpRect);
} else {
diff --git a/services/core/java/com/android/server/wm/KeyguardController.java b/services/core/java/com/android/server/wm/KeyguardController.java
index c36a75b01293..69e8c57a489c 100644
--- a/services/core/java/com/android/server/wm/KeyguardController.java
+++ b/services/core/java/com/android/server/wm/KeyguardController.java
@@ -190,7 +190,7 @@ class KeyguardController {
mAodShowing ? 1 : 0,
1 /* keyguardGoingAway */,
"keyguardGoingAway");
- mRootWindowContainer.getDefaultDisplay().mDisplayContent
+ mRootWindowContainer.getDefaultDisplay()
.prepareAppTransition(TRANSIT_KEYGUARD_GOING_AWAY,
false /* alwaysKeepCurrent */, convertTransitFlags(flags),
false /* forceOverride */);
@@ -314,7 +314,7 @@ class KeyguardController {
if (isKeyguardLocked()) {
mService.deferWindowLayout();
try {
- mRootWindowContainer.getDefaultDisplay().mDisplayContent
+ mRootWindowContainer.getDefaultDisplay()
.prepareAppTransition(resolveOccludeTransit(),
false /* alwaysKeepCurrent */, 0 /* flags */,
true /* forceOverride */);
@@ -344,8 +344,7 @@ class KeyguardController {
// If we are about to unocclude the Keyguard, but we can dismiss it without security,
// we immediately dismiss the Keyguard so the activity gets shown without a flicker.
- final DisplayContent dc =
- mRootWindowContainer.getDefaultDisplay().mDisplayContent;
+ final DisplayContent dc = mRootWindowContainer.getDefaultDisplay();
if (mKeyguardShowing && canDismissKeyguard()
&& dc.mAppTransition.getAppTransition() == TRANSIT_KEYGUARD_UNOCCLUDE) {
dc.prepareAppTransition(mBeforeUnoccludeTransit, false /* alwaysKeepCurrent */,
@@ -368,7 +367,7 @@ class KeyguardController {
}
private int resolveOccludeTransit() {
- final DisplayContent dc = mRootWindowContainer.getDefaultDisplay().mDisplayContent;
+ final DisplayContent dc = mRootWindowContainer.getDefaultDisplay();
if (mBeforeUnoccludeTransit != TRANSIT_UNSET
&& dc.mAppTransition.getAppTransition() == TRANSIT_KEYGUARD_UNOCCLUDE
// TODO(b/113840485): Handle app transition for individual display.
@@ -485,7 +484,7 @@ class KeyguardController {
}
// TODO(b/123372519): isShowingDream can only works on default display.
if (mDisplayId == DEFAULT_DISPLAY) {
- mOccluded |= mService.mRootWindowContainer.getDefaultDisplay().mDisplayContent
+ mOccluded |= mService.mRootWindowContainer.getDefaultDisplay()
.getDisplayPolicy().isShowingDreamLw();
}
diff --git a/services/core/java/com/android/server/wm/LockTaskController.java b/services/core/java/com/android/server/wm/LockTaskController.java
index 8ef57f726658..c49690157c08 100644
--- a/services/core/java/com/android/server/wm/LockTaskController.java
+++ b/services/core/java/com/android/server/wm/LockTaskController.java
@@ -29,7 +29,7 @@ import static android.os.UserHandle.USER_ALL;
import static android.os.UserHandle.USER_CURRENT;
import static android.telecom.TelecomManager.EMERGENCY_DIALER_COMPONENT;
-import static com.android.server.wm.ActivityTaskManagerDebugConfig.DEBUG_LOCKTASK;
+import static com.android.internal.protolog.ProtoLogGroup.WM_DEBUG_LOCKTASK;
import static com.android.server.wm.ActivityTaskManagerDebugConfig.POSTFIX_LOCKTASK;
import static com.android.server.wm.ActivityTaskManagerDebugConfig.TAG_ATM;
import static com.android.server.wm.ActivityTaskManagerDebugConfig.TAG_WITH_CLASS_NAME;
@@ -65,6 +65,7 @@ import android.util.SparseIntArray;
import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.policy.IKeyguardDismissCallback;
+import com.android.internal.protolog.common.ProtoLog;
import com.android.internal.statusbar.IStatusBarService;
import com.android.internal.widget.LockPatternUtils;
import com.android.server.LocalServices;
@@ -448,7 +449,7 @@ public class LockTaskController {
* unlike {@link #stopLockTaskMode(Task, boolean, int)}, it doesn't perform the checks.
*/
void clearLockedTasks(String reason) {
- if (DEBUG_LOCKTASK) Slog.i(TAG_LOCKTASK, "clearLockedTasks: " + reason);
+ ProtoLog.i(WM_DEBUG_LOCKTASK, "clearLockedTasks: %s", reason);
if (!mLockTaskModeTasks.isEmpty()) {
clearLockedTask(mLockTaskModeTasks.get(0));
}
@@ -490,10 +491,10 @@ public class LockTaskController {
if (!mLockTaskModeTasks.remove(task)) {
return;
}
- if (DEBUG_LOCKTASK) Slog.d(TAG_LOCKTASK, "removeLockedTask: removed " + task);
+ ProtoLog.d(WM_DEBUG_LOCKTASK, "removeLockedTask: removed %s", task);
if (mLockTaskModeTasks.isEmpty()) {
- if (DEBUG_LOCKTASK) Slog.d(TAG_LOCKTASK, "removeLockedTask: task=" + task +
- " last task, reverting locktask mode. Callers=" + Debug.getCallers(3));
+ ProtoLog.d(WM_DEBUG_LOCKTASK, "removeLockedTask: task=%s last task, "
+ + "reverting locktask mode. Callers=%s", task, Debug.getCallers(3));
mHandler.post(() -> performStopLockTask(task.mUserId));
}
}
@@ -558,7 +559,7 @@ public class LockTaskController {
if (task.mLockTaskAuth == LOCK_TASK_AUTH_PINNABLE) {
// startLockTask() called by app, but app is not part of lock task allowlist. Show
// app pinning request. We will come back here with isSystemCaller true.
- if (DEBUG_LOCKTASK) Slog.w(TAG_LOCKTASK, "Mode default, asking user");
+ ProtoLog.w(WM_DEBUG_LOCKTASK, "Mode default, asking user");
StatusBarManagerInternal statusBarManager = LocalServices.getService(
StatusBarManagerInternal.class);
if (statusBarManager != null) {
@@ -569,8 +570,7 @@ public class LockTaskController {
}
// System can only initiate screen pinning, not full lock task mode
- if (DEBUG_LOCKTASK) Slog.w(TAG_LOCKTASK,
- isSystemCaller ? "Locking pinned" : "Locking fully");
+ ProtoLog.w(WM_DEBUG_LOCKTASK, "%s", isSystemCaller ? "Locking pinned" : "Locking fully");
setLockTaskMode(task, isSystemCaller ? LOCK_TASK_MODE_PINNED : LOCK_TASK_MODE_LOCKED,
"startLockTask", true);
}
@@ -584,7 +584,7 @@ public class LockTaskController {
String reason, boolean andResume) {
// Should have already been checked, but do it again.
if (task.mLockTaskAuth == LOCK_TASK_AUTH_DONT_LOCK) {
- if (DEBUG_LOCKTASK) Slog.w(TAG_LOCKTASK,
+ ProtoLog.w(WM_DEBUG_LOCKTASK,
"setLockTaskMode: Can't lock due to auth");
return;
}
@@ -602,8 +602,8 @@ public class LockTaskController {
task.mUserId,
lockTaskModeState));
}
- if (DEBUG_LOCKTASK) Slog.w(TAG_LOCKTASK, "setLockTaskMode: Locking to " + task +
- " Callers=" + Debug.getCallers(4));
+ ProtoLog.w(WM_DEBUG_LOCKTASK, "setLockTaskMode: Locking to %s Callers=%s",
+ task, Debug.getCallers(4));
if (!mLockTaskModeTasks.contains(task)) {
mLockTaskModeTasks.add(task);
@@ -619,7 +619,7 @@ public class LockTaskController {
mSupervisor.mRootWindowContainer.resumeFocusedStacksTopActivities();
final Task rootTask = task.getRootTask();
if (rootTask != null) {
- rootTask.getDisplay().mDisplayContent.executeAppTransition();
+ rootTask.mDisplayContent.executeAppTransition();
}
} else if (lockTaskModeState != LOCK_TASK_MODE_NONE) {
mSupervisor.handleNonResizableTaskIfNeeded(task, WINDOWING_MODE_UNDEFINED,
@@ -672,8 +672,8 @@ public class LockTaskController {
}
// Terminate locked tasks that have recently lost allowlist authorization.
- if (DEBUG_LOCKTASK) Slog.d(TAG_LOCKTASK, "onLockTaskPackagesUpdated: removing " +
- lockedTask + " mLockTaskAuth()=" + lockedTask.lockTaskAuthToString());
+ ProtoLog.d(WM_DEBUG_LOCKTASK, "onLockTaskPackagesUpdated: removing %s"
+ + " mLockTaskAuth()=%s", lockedTask, lockedTask.lockTaskAuthToString());
removeLockedTask(lockedTask);
lockedTask.performClearTaskLocked();
taskChanged = true;
@@ -686,8 +686,8 @@ public class LockTaskController {
if (mLockTaskModeTasks.isEmpty() && task!= null
&& task.mLockTaskAuth == LOCK_TASK_AUTH_LAUNCHABLE) {
// This task must have just been authorized.
- if (DEBUG_LOCKTASK) Slog.d(TAG_LOCKTASK,
- "onLockTaskPackagesUpdated: starting new locktask task=" + task);
+ ProtoLog.d(WM_DEBUG_LOCKTASK, "onLockTaskPackagesUpdated: starting new "
+ + "locktask task=%s", task);
setLockTaskMode(task, LOCK_TASK_MODE_LOCKED, "package updated", false);
taskChanged = true;
}
diff --git a/services/core/java/com/android/server/wm/RecentTasks.java b/services/core/java/com/android/server/wm/RecentTasks.java
index 3c64ffb237d6..255b3f147d30 100644
--- a/services/core/java/com/android/server/wm/RecentTasks.java
+++ b/services/core/java/com/android/server/wm/RecentTasks.java
@@ -1346,11 +1346,8 @@ class RecentTasks {
// singleTaskInstance is set on the VirtualDisplay managed by ActivityView
// TODO(b/126185105): Find a different signal to use besides isSingleTaskInstance
final Task rootTask = task.getRootTask();
- if (rootTask != null) {
- DisplayContent display = rootTask.getDisplay();
- if (display != null && display.isSingleTaskInstance()) {
- return false;
- }
+ if (rootTask != null && rootTask.isSingleTaskInstance()) {
+ return false;
}
// If we're in lock task mode, ignore the root task
diff --git a/services/core/java/com/android/server/wm/ResetTargetTaskHelper.java b/services/core/java/com/android/server/wm/ResetTargetTaskHelper.java
index cc5ed36e0f47..c3953b4efa16 100644
--- a/services/core/java/com/android/server/wm/ResetTargetTaskHelper.java
+++ b/services/core/java/com/android/server/wm/ResetTargetTaskHelper.java
@@ -16,9 +16,8 @@
package com.android.server.wm;
-import static com.android.server.wm.ActivityTaskManagerDebugConfig.DEBUG_ADD_REMOVE;
+import static com.android.internal.protolog.ProtoLogGroup.WM_DEBUG_ADD_REMOVE;
import static com.android.server.wm.ActivityTaskManagerDebugConfig.DEBUG_TASKS;
-import static com.android.server.wm.Task.TAG_ADD_REMOVE;
import static com.android.server.wm.Task.TAG_TASKS;
import android.app.ActivityOptions;
@@ -27,6 +26,7 @@ import android.content.pm.ActivityInfo;
import android.os.Debug;
import android.util.Slog;
+import com.android.internal.protolog.common.ProtoLog;
import com.android.internal.util.function.pooled.PooledConsumer;
import com.android.internal.util.function.pooled.PooledFunction;
import com.android.internal.util.function.pooled.PooledLambda;
@@ -218,8 +218,8 @@ class ResetTargetTaskHelper {
if (takeOptions) {
noOptions = takeOption(p, noOptions);
}
- if (DEBUG_ADD_REMOVE) Slog.i(TAG_ADD_REMOVE, "Removing activity " + p + " from task="
- + mTask + " adding to task=" + targetTask + " Callers=" + Debug.getCallers(4));
+ ProtoLog.i(WM_DEBUG_ADD_REMOVE, "Removing activity %s from task=%s "
+ + "adding to task=%s Callers=%s", p, mTask, targetTask, Debug.getCallers(4));
if (DEBUG_TASKS) Slog.v(TAG_TASKS,
"Pushing next activity " + p + " out to target's task " + target);
p.reparent(targetTask, position, "resetTargetTaskIfNeeded");
diff --git a/services/core/java/com/android/server/wm/RootWindowContainer.java b/services/core/java/com/android/server/wm/RootWindowContainer.java
index aeaffd98f820..6539e1325ec1 100644
--- a/services/core/java/com/android/server/wm/RootWindowContainer.java
+++ b/services/core/java/com/android/server/wm/RootWindowContainer.java
@@ -129,6 +129,7 @@ import android.os.UserHandle;
import android.os.storage.StorageManager;
import android.provider.Settings;
import android.service.voice.IVoiceInteractionSession;
+import android.util.ArrayMap;
import android.util.ArraySet;
import android.util.DisplayMetrics;
import android.util.IntArray;
@@ -162,7 +163,6 @@ import java.io.PrintWriter;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.util.ArrayList;
-import java.util.HashMap;
import java.util.List;
import java.util.Objects;
import java.util.Set;
@@ -214,7 +214,7 @@ class RootWindowContainer extends WindowContainer<DisplayContent>
private int mTopFocusedDisplayId = INVALID_DISPLAY;
// Map from the PID to the top most app which has a focused window of the process.
- final HashMap<Integer, ActivityRecord> mTopFocusedAppByProcess = new HashMap<>();
+ final ArrayMap<Integer, ActivityRecord> mTopFocusedAppByProcess = new ArrayMap<>();
// Only a separate transaction until we separate the apply surface changes
// transaction from the global transaction.
@@ -480,8 +480,7 @@ class RootWindowContainer extends WindowContainer<DisplayContent>
mTopFocusedDisplayId = topFocusedDisplayId;
mWmService.mInputManager.setFocusedDisplay(topFocusedDisplayId);
mWmService.mPolicy.setTopFocusedDisplay(topFocusedDisplayId);
- ProtoLog.v(WM_DEBUG_FOCUS_LIGHT, "New topFocusedDisplayId=%d",
- topFocusedDisplayId);
+ ProtoLog.d(WM_DEBUG_FOCUS_LIGHT, "New topFocusedDisplayId=%d", topFocusedDisplayId);
}
return changed;
}
@@ -1106,14 +1105,14 @@ class RootWindowContainer extends WindowContainer<DisplayContent>
final WindowManager.LayoutParams attrs = w.mAttrs;
final int attrFlags = attrs.flags;
final boolean onScreen = w.isOnScreen();
- final boolean canBeSeen = w.isDisplayedLw();
+ final boolean canBeSeen = w.isDisplayed();
final int privateflags = attrs.privateFlags;
boolean displayHasContent = false;
ProtoLog.d(WM_DEBUG_KEEP_SCREEN_ON,
"handleNotObscuredLocked w: %s, w.mHasSurface: %b, w.isOnScreen(): %b, w"
+ ".isDisplayedLw(): %b, w.mAttrs.userActivityTimeout: %d",
- w, w.mHasSurface, onScreen, w.isDisplayedLw(), w.mAttrs.userActivityTimeout);
+ w, w.mHasSurface, onScreen, w.isDisplayed(), w.mAttrs.userActivityTimeout);
if (w.mHasSurface && onScreen) {
if (!syswin && w.mAttrs.userActivityTimeout >= 0 && mUserActivityTimeout < 0) {
mUserActivityTimeout = w.mAttrs.userActivityTimeout;
@@ -2289,10 +2288,6 @@ class RootWindowContainer extends WindowContainer<DisplayContent>
for (int displayNdx = getChildCount() - 1; displayNdx >= 0; --displayNdx) {
final DisplayContent display = getChildAt(displayNdx);
- if (display.shouldSleep()) {
- continue;
- }
-
final boolean curResult = result;
boolean resumedOnDisplay = display.reduceOnAllTaskDisplayAreas(
(taskDisplayArea, resumed) -> {
@@ -2716,7 +2711,7 @@ class RootWindowContainer extends WindowContainer<DisplayContent>
+ " resumed=" + r.getStack().mResumedActivity + " pausing="
+ r.getStack().mPausingActivity + " for reason " + mDestroyAllActivitiesReason);
- r.destroyImmediately(true /* removeFromTask */, mDestroyAllActivitiesReason);
+ r.destroyImmediately(mDestroyAllActivitiesReason);
}
// Tries to put all activity stacks to sleep. Returns true if all stacks were
@@ -2753,7 +2748,7 @@ class RootWindowContainer extends WindowContainer<DisplayContent>
Slog.w(TAG, " Force finishing activity "
+ r.intent.getComponent().flattenToShortString());
r.detachFromProcess();
- r.getDisplay().mDisplayContent.prepareAppTransition(
+ r.mDisplayContent.prepareAppTransition(
TRANSIT_CRASHING_ACTIVITY_CLOSE, false /* alwaysKeepCurrent */);
r.destroyIfPossible("handleAppCrashed");
}
@@ -3124,7 +3119,6 @@ class RootWindowContainer extends WindowContainer<DisplayContent>
FinishDisabledPackageActivitiesHelper mFinishDisabledPackageActivitiesHelper =
new FinishDisabledPackageActivitiesHelper();
class FinishDisabledPackageActivitiesHelper {
- private boolean mDidSomething;
private String mPackageName;
private Set<String> mFilterByClasses;
private boolean mDoit;
@@ -3132,11 +3126,10 @@ class RootWindowContainer extends WindowContainer<DisplayContent>
private int mUserId;
private boolean mOnlyRemoveNoProcess;
private Task mLastTask;
- private ComponentName mHomeActivity;
+ private final ArrayList<ActivityRecord> mCollectedActivities = new ArrayList<>();
private void reset(String packageName, Set<String> filterByClasses,
boolean doit, boolean evenPersistent, int userId, boolean onlyRemoveNoProcess) {
- mDidSomething = false;
mPackageName = packageName;
mFilterByClasses = filterByClasses;
mDoit = doit;
@@ -3144,7 +3137,6 @@ class RootWindowContainer extends WindowContainer<DisplayContent>
mUserId = userId;
mOnlyRemoveNoProcess = onlyRemoveNoProcess;
mLastTask = null;
- mHomeActivity = null;
}
boolean process(String packageName, Set<String> filterByClasses,
@@ -3152,14 +3144,35 @@ class RootWindowContainer extends WindowContainer<DisplayContent>
reset(packageName, filterByClasses, doit, evenPersistent, userId, onlyRemoveNoProcess);
final PooledFunction f = PooledLambda.obtainFunction(
- FinishDisabledPackageActivitiesHelper::processActivity, this,
+ FinishDisabledPackageActivitiesHelper::collectActivity, this,
PooledLambda.__(ActivityRecord.class));
forAllActivities(f);
f.recycle();
- return mDidSomething;
+
+ boolean didSomething = false;
+ final int size = mCollectedActivities.size();
+ // Keep the finishing order from top to bottom.
+ for (int i = 0; i < size; i++) {
+ final ActivityRecord r = mCollectedActivities.get(i);
+ if (mOnlyRemoveNoProcess) {
+ if (!r.hasProcess()) {
+ didSomething = true;
+ Slog.i(TAG, " Force removing " + r);
+ r.cleanUp(false /* cleanServices */, false /* setState */);
+ r.removeFromHistory("force-stop");
+ }
+ } else {
+ didSomething = true;
+ Slog.i(TAG, " Force finishing " + r);
+ r.finishIfPossible("force-stop", true /* oomAdj */);
+ }
+ }
+ mCollectedActivities.clear();
+
+ return didSomething;
}
- private boolean processActivity(ActivityRecord r) {
+ private boolean collectActivity(ActivityRecord r) {
final boolean sameComponent =
(r.packageName.equals(mPackageName) && (mFilterByClasses == null
|| mFilterByClasses.contains(r.mActivityComponent.getClassName())))
@@ -3176,26 +3189,7 @@ class RootWindowContainer extends WindowContainer<DisplayContent>
}
return true;
}
- if (r.isActivityTypeHome()) {
- if (mHomeActivity != null && mHomeActivity.equals(r.mActivityComponent)) {
- Slog.i(TAG, "Skip force-stop again " + r);
- return false;
- } else {
- mHomeActivity = r.mActivityComponent;
- }
- }
- if (mOnlyRemoveNoProcess) {
- if (noProcess) {
- mDidSomething = true;
- Slog.i(TAG, " Force removing " + r);
- r.cleanUp(false /* cleanServices */, false /* setState */);
- r.removeFromHistory("force-stop");
- }
- } else {
- mDidSomething = true;
- Slog.i(TAG, " Force finishing " + r);
- r.finishIfPossible("force-stop", true /* oomAdj */);
- }
+ mCollectedActivities.add(r);
mLastTask = r.getTask();
}
diff --git a/services/core/java/com/android/server/wm/RunningTasks.java b/services/core/java/com/android/server/wm/RunningTasks.java
index 6cf9432089b4..7b5b0ad870dd 100644
--- a/services/core/java/com/android/server/wm/RunningTasks.java
+++ b/services/core/java/com/android/server/wm/RunningTasks.java
@@ -99,9 +99,8 @@ class RunningTasks {
// the task's profile
return;
}
- if (!mAllowed && !task.isActivityTypeHome()) {
- // Skip if the caller isn't allowed to fetch this task, except for the home
- // task which we always return.
+ if (!mAllowed) {
+ // Skip if the caller isn't allowed to fetch this task
return;
}
}
diff --git a/services/core/java/com/android/server/wm/SurfaceAnimator.java b/services/core/java/com/android/server/wm/SurfaceAnimator.java
index 33935d61ead2..7df2b407557d 100644
--- a/services/core/java/com/android/server/wm/SurfaceAnimator.java
+++ b/services/core/java/com/android/server/wm/SurfaceAnimator.java
@@ -26,6 +26,7 @@ import static com.android.server.wm.WindowManagerDebugConfig.TAG_WM;
import android.annotation.IntDef;
import android.annotation.NonNull;
import android.annotation.Nullable;
+import android.util.DebugUtils;
import android.util.Slog;
import android.util.proto.ProtoOutputStream;
import android.view.SurfaceControl;
@@ -429,7 +430,8 @@ class SurfaceAnimator {
void dump(PrintWriter pw, String prefix) {
pw.print(prefix); pw.print("mLeash="); pw.print(mLeash);
- pw.print(" mAnimationType=" + mAnimationType);
+ pw.print(" mAnimationType=" + DebugUtils.valueToString(SurfaceAnimator.class,
+ "ANIMATION_TYPE_", mAnimationType));
pw.println(mAnimationStartDelayed ? " mAnimationStartDelayed=true" : "");
pw.print(prefix); pw.print("Animation: "); pw.println(mAnimation);
if (mAnimation != null) {
@@ -442,56 +444,56 @@ class SurfaceAnimator {
* No animation is specified.
* @hide
*/
- static final int ANIMATION_TYPE_NONE = 0;
+ public static final int ANIMATION_TYPE_NONE = 0;
/**
* Animation for an app transition.
* @hide
*/
- static final int ANIMATION_TYPE_APP_TRANSITION = 1;
+ public static final int ANIMATION_TYPE_APP_TRANSITION = 1;
/**
* Animation for screen rotation.
* @hide
*/
- static final int ANIMATION_TYPE_SCREEN_ROTATION = 1 << 1;
+ public static final int ANIMATION_TYPE_SCREEN_ROTATION = 1 << 1;
/**
* Animation for dimming.
* @hide
*/
- static final int ANIMATION_TYPE_DIMMER = 1 << 2;
+ public static final int ANIMATION_TYPE_DIMMER = 1 << 2;
/**
* Animation for recent apps.
* @hide
*/
- static final int ANIMATION_TYPE_RECENTS = 1 << 3;
+ public static final int ANIMATION_TYPE_RECENTS = 1 << 3;
/**
* Animation for a {@link WindowState} without animating the activity.
* @hide
*/
- static final int ANIMATION_TYPE_WINDOW_ANIMATION = 1 << 4;
+ public static final int ANIMATION_TYPE_WINDOW_ANIMATION = 1 << 4;
/**
* Animation to control insets. This is actually not an animation, but is used to give the
* client a leash over the system window causing insets.
* @hide
*/
- static final int ANIMATION_TYPE_INSETS_CONTROL = 1 << 5;
+ public static final int ANIMATION_TYPE_INSETS_CONTROL = 1 << 5;
/**
* Animation when a fixed rotation transform is applied to a window token.
* @hide
*/
- static final int ANIMATION_TYPE_FIXED_TRANSFORM = 1 << 6;
+ public static final int ANIMATION_TYPE_FIXED_TRANSFORM = 1 << 6;
/**
* Bitmask to include all animation types. This is NOT an {@link AnimationType}
* @hide
*/
- static final int ANIMATION_TYPE_ALL = -1;
+ public static final int ANIMATION_TYPE_ALL = -1;
/**
* The type of the animation.
diff --git a/services/core/java/com/android/server/wm/Task.java b/services/core/java/com/android/server/wm/Task.java
index 4dbbbc6de32c..70fd860f21f2 100644
--- a/services/core/java/com/android/server/wm/Task.java
+++ b/services/core/java/com/android/server/wm/Task.java
@@ -79,6 +79,7 @@ import static android.view.WindowManager.TRANSIT_TASK_TO_FRONT;
import static com.android.internal.policy.DecorView.DECOR_SHADOW_FOCUSED_HEIGHT_IN_DIP;
import static com.android.internal.policy.DecorView.DECOR_SHADOW_UNFOCUSED_HEIGHT_IN_DIP;
import static com.android.internal.protolog.ProtoLogGroup.WM_DEBUG_ADD_REMOVE;
+import static com.android.internal.protolog.ProtoLogGroup.WM_DEBUG_LOCKTASK;
import static com.android.internal.protolog.ProtoLogGroup.WM_DEBUG_RECENTS_ANIMATIONS;
import static com.android.server.wm.ActivityRecord.STARTING_WINDOW_SHOWN;
import static com.android.server.wm.ActivityStackSupervisor.DEFER_RESUME;
@@ -87,9 +88,7 @@ import static com.android.server.wm.ActivityStackSupervisor.PRESERVE_WINDOWS;
import static com.android.server.wm.ActivityStackSupervisor.REMOVE_FROM_RECENTS;
import static com.android.server.wm.ActivityStackSupervisor.dumpHistoryList;
import static com.android.server.wm.ActivityStackSupervisor.printThisActivity;
-import static com.android.server.wm.ActivityTaskManagerDebugConfig.DEBUG_ADD_REMOVE;
import static com.android.server.wm.ActivityTaskManagerDebugConfig.DEBUG_CLEANUP;
-import static com.android.server.wm.ActivityTaskManagerDebugConfig.DEBUG_LOCKTASK;
import static com.android.server.wm.ActivityTaskManagerDebugConfig.DEBUG_PAUSE;
import static com.android.server.wm.ActivityTaskManagerDebugConfig.DEBUG_RECENTS;
import static com.android.server.wm.ActivityTaskManagerDebugConfig.DEBUG_RESULTS;
@@ -1651,8 +1650,8 @@ class Task extends WindowContainer<WindowContainer> {
* Reorder the history stack so that the passed activity is brought to the front.
*/
final void moveActivityToFrontLocked(ActivityRecord newTop) {
- if (DEBUG_ADD_REMOVE) Slog.i(TAG_ADD_REMOVE, "Removing and adding activity "
- + newTop + " to stack at top callers=" + Debug.getCallers(4));
+ ProtoLog.i(WM_DEBUG_ADD_REMOVE, "Removing and adding activity %s to stack at top "
+ + "callers=%s", newTop, Debug.getCallers(4));
positionChildAtTop(newTop);
updateEffectiveIntent();
@@ -1951,8 +1950,8 @@ class Task extends WindowContainer<WindowContainer> {
? LOCK_TASK_AUTH_LAUNCHABLE : LOCK_TASK_AUTH_PINNABLE;
break;
}
- if (DEBUG_LOCKTASK) Slog.d(TAG_LOCKTASK, "setLockTaskAuth: task=" + this
- + " mLockTaskAuth=" + lockTaskAuthToString());
+ ProtoLog.d(WM_DEBUG_LOCKTASK, "setLockTaskAuth: task=%s mLockTaskAuth=%s", this,
+ lockTaskAuthToString());
}
@Override
@@ -2320,8 +2319,7 @@ class Task extends WindowContainer<WindowContainer> {
taskDisplayArea.onStackWindowingModeChanged(this);
}
- final DisplayContent display = getDisplay();
- if (display == null ) {
+ if (mDisplayContent == null) {
return;
}
@@ -2337,7 +2335,7 @@ class Task extends WindowContainer<WindowContainer> {
final int newRotation = getWindowConfiguration().getRotation();
final boolean rotationChanged = prevRotation != newRotation;
if (rotationChanged) {
- display.mDisplayContent.rotateBounds(
+ mDisplayContent.rotateBounds(
newParentConfig.windowConfiguration.getBounds(), prevRotation, newRotation,
newBounds);
hasNewOverrideBounds = true;
@@ -2595,15 +2593,12 @@ class Task extends WindowContainer<WindowContainer> {
outNonDecorBounds.set(bounds);
outStableBounds.set(bounds);
final Task rootTask = getRootTask();
- if (rootTask == null || rootTask.getDisplay() == null) {
- return;
- }
- DisplayPolicy policy = rootTask.getDisplay().mDisplayContent.getDisplayPolicy();
- if (policy == null) {
+ if (rootTask == null || rootTask.mDisplayContent == null) {
return;
}
mTmpBounds.set(0, 0, displayInfo.logicalWidth, displayInfo.logicalHeight);
+ final DisplayPolicy policy = rootTask.mDisplayContent.getDisplayPolicy();
policy.getNonDecorInsetsLw(displayInfo.rotation, displayInfo.logicalWidth,
displayInfo.logicalHeight, displayInfo.displayCutout, mTmpInsets);
intersectWithInsetsIfFits(outNonDecorBounds, mTmpBounds, mTmpInsets);
@@ -2991,14 +2986,6 @@ class Task extends WindowContainer<WindowContainer> {
}
}
- @Override
- DisplayContent getDisplayContent() {
- // TODO: Why aren't we just using our own display content vs. parent's???
- final Task stack = getRootTask();
- return stack != null && stack != this
- ? stack.getDisplayContent() : super.getDisplayContent();
- }
-
int getDisplayId() {
final DisplayContent dc = getDisplayContent();
return dc != null ? dc.mDisplayId : INVALID_DISPLAY;
@@ -5174,14 +5161,9 @@ class Task extends WindowContainer<WindowContainer> {
!PRESERVE_WINDOWS);
}
- DisplayContent getDisplay() {
- return getDisplayContent();
- }
-
/** @return true if the stack can only contain one task */
boolean isSingleTaskInstance() {
- final DisplayContent display = getDisplay();
- return display != null && display.isSingleTaskInstance();
+ return mDisplayContent != null && mDisplayContent.isSingleTaskInstance();
}
final boolean isHomeOrRecentsStack() {
@@ -5621,8 +5603,7 @@ class Task extends WindowContainer<WindowContainer> {
* otherwise.
*/
boolean isFocusedStackOnDisplay() {
- final DisplayContent display = getDisplay();
- return display != null && this == display.getFocusedStack();
+ return mDisplayContent != null && this == mDisplayContent.getFocusedStack();
}
/**
@@ -5761,7 +5742,7 @@ class Task extends WindowContainer<WindowContainer> {
* {@link Display#FLAG_CAN_SHOW_WITH_INSECURE_KEYGUARD} applied.
*/
boolean canShowWithInsecureKeyguard() {
- final DisplayContent displayContent = getDisplay();
+ final DisplayContent displayContent = mDisplayContent;
if (displayContent == null) {
throw new IllegalStateException("Stack is not attached to any display, stackId="
+ getRootTaskId());
@@ -6190,10 +6171,6 @@ class Task extends WindowContainer<WindowContainer> {
next.setState(RESUMED, "resumeTopActivityInnerLocked");
- next.app.updateProcessInfo(false /* updateServiceConnectionActivities */,
- true /* activityChange */, true /* updateOomAdj */,
- true /* addPendingTopUid */);
-
// Have the window manager re-evaluate the orientation of
// the screen based on the new activity order.
boolean notUpdated = true;
@@ -6353,7 +6330,7 @@ class Task extends WindowContainer<WindowContainer> {
return mRootWindowContainer.resumeHomeActivity(prev, reason, getDisplayArea());
}
- void startActivityLocked(ActivityRecord r, ActivityRecord focusedTopActivity,
+ void startActivityLocked(ActivityRecord r, @Nullable ActivityRecord focusedTopActivity,
boolean newTask, boolean keepCurTransition, ActivityOptions options) {
Task rTask = r.getTask();
final boolean allowMoveToFront = options == null || !options.getAvoidMoveToFront();
@@ -6374,7 +6351,8 @@ class Task extends WindowContainer<WindowContainer> {
// Here it is! Now, if this is not yet visible (occluded by another task) to the
// user, then just add it without starting; it will get started when the user
// navigates back to it.
- if (DEBUG_ADD_REMOVE) Slog.i(TAG, "Adding activity " + r + " to task " + task,
+ ProtoLog.i(WM_DEBUG_ADD_REMOVE, "Adding activity %s to task %s "
+ + "callers: %s", r, task,
new RuntimeException("here").fillInStackTrace());
rTask.positionChildAtTop(r);
ActivityOptions.abort(options);
@@ -6396,14 +6374,14 @@ class Task extends WindowContainer<WindowContainer> {
task = activityTask;
// Slot the activity into the history stack and proceed
- if (DEBUG_ADD_REMOVE) Slog.i(TAG, "Adding activity " + r + " to stack to task " + task,
- new RuntimeException("here").fillInStackTrace());
+ ProtoLog.i(WM_DEBUG_ADD_REMOVE, "Adding activity %s to stack to task %s "
+ + "callers: %s", r, task, new RuntimeException("here").fillInStackTrace());
task.positionChildAtTop(r);
// The transition animation and starting window are not needed if {@code allowMoveToFront}
// is false, because the activity won't be visible.
if ((!isHomeOrRecentsStack() || hasActivity()) && allowMoveToFront) {
- final DisplayContent dc = getDisplay().mDisplayContent;
+ final DisplayContent dc = mDisplayContent;
if (DEBUG_TRANSITION) Slog.v(TAG_TRANSITION,
"Prepare open transition: starting " + r);
if ((r.intent.getFlags() & Intent.FLAG_ACTIVITY_NO_ANIMATION) != 0) {
@@ -6414,7 +6392,7 @@ class Task extends WindowContainer<WindowContainer> {
if (newTask) {
if (r.mLaunchTaskBehind) {
transit = TRANSIT_TASK_OPEN_BEHIND;
- } else if (getDisplay().isSingleTaskInstance()) {
+ } else if (dc.isSingleTaskInstance()) {
// If a new task is being launched in a single task display, we don't need
// to play normal animation, but need to trigger a callback when an app
// transition is actually handled. So ignore already prepared activity, and
@@ -6458,7 +6436,7 @@ class Task extends WindowContainer<WindowContainer> {
ensureActivitiesVisible(null, 0, !PRESERVE_WINDOWS);
// Go ahead to execute app transition for this activity since the app transition
// will not be triggered through the resume channel.
- getDisplay().mDisplayContent.executeAppTransition();
+ mDisplayContent.executeAppTransition();
} else if (SHOW_APP_STARTING_PREVIEW && doShow) {
// Figure out if we are transitioning from another activity that is
// "has the same starting icon" as the next one. This allows the
@@ -6571,7 +6549,7 @@ class Task extends WindowContainer<WindowContainer> {
Slog.w(TAG, " Force finishing activity "
+ r.intent.getComponent().flattenToShortString());
Task finishedTask = r.getTask();
- getDisplay().mDisplayContent.prepareAppTransition(
+ mDisplayContent.prepareAppTransition(
TRANSIT_CRASHING_ACTIVITY_CLOSE, false /* alwaysKeepCurrent */);
r.finishIfPossible(reason, false /* oomAdj */);
@@ -6659,7 +6637,8 @@ class Task extends WindowContainer<WindowContainer> {
// Basic case: for simple app-centric recents, we need to recreate
// the task if the affinity has changed.
- final String affinity = ActivityRecord.getTaskAffinityWithUid(destAffinity, srec.getUid());
+ final String affinity = ActivityRecord.computeTaskAffinity(destAffinity, srec.getUid(),
+ srec.launchMode);
if (srec == null || srec.getTask().affinity == null
|| !srec.getTask().affinity.equals(affinity)) {
return true;
@@ -6811,7 +6790,7 @@ class Task extends WindowContainer<WindowContainer> {
ActivityOptions.abort(options);
}
}
- getDisplay().mDisplayContent.prepareAppTransition(transit, false,
+ mDisplayContent.prepareAppTransition(transit, false,
0 /* flags */, forceOverride);
}
@@ -6859,7 +6838,7 @@ class Task extends WindowContainer<WindowContainer> {
// Defer updating the IME target since the new IME target will try to get computed
// before updating all closing and opening apps, which can cause the ime target to
// get calculated incorrectly.
- getDisplay().deferUpdateImeTarget();
+ mDisplayContent.deferUpdateImeTarget();
// Shift all activities with this task up to the top
// of the stack, keeping them in the same internal order.
@@ -6883,7 +6862,7 @@ class Task extends WindowContainer<WindowContainer> {
if (DEBUG_TRANSITION) Slog.v(TAG_TRANSITION, "Prepare to front transition: task=" + tr);
if (noAnimation) {
- getDisplay().mDisplayContent.prepareAppTransition(TRANSIT_NONE, false);
+ mDisplayContent.prepareAppTransition(TRANSIT_NONE, false /* alwaysKeepCurrent */);
if (r != null) {
mStackSupervisor.mNoAnimActivities.add(r);
}
@@ -6913,7 +6892,7 @@ class Task extends WindowContainer<WindowContainer> {
mAtmService.getTaskChangeNotificationController()
.notifyTaskMovedToFront(tr.getTaskInfo());
} finally {
- getDisplay().continueUpdateImeTarget();
+ mDisplayContent.continueUpdateImeTarget();
}
}
@@ -6963,7 +6942,7 @@ class Task extends WindowContainer<WindowContainer> {
if (DEBUG_TRANSITION) Slog.v(TAG_TRANSITION, "Prepare to back transition: task="
+ tr.mTaskId);
- getDisplay().mDisplayContent.prepareAppTransition(TRANSIT_TASK_TO_BACK, false);
+ mDisplayContent.prepareAppTransition(TRANSIT_TASK_TO_BACK, false /* alwaysKeepCurrent */);
moveToBack("moveTaskToBackLocked", tr);
if (inPinnedWindowingMode()) {
@@ -6972,7 +6951,7 @@ class Task extends WindowContainer<WindowContainer> {
}
mRootWindowContainer.ensureVisibilityAndConfig(null /* starting */,
- getDisplay().mDisplayId, false /* markFrozenIfConfigChanged */,
+ mDisplayContent.mDisplayId, false /* markFrozenIfConfigChanged */,
false /* deferResume */);
ActivityRecord topActivity = getDisplayArea().topRunningActivity();
@@ -6980,7 +6959,7 @@ class Task extends WindowContainer<WindowContainer> {
if (topStack != null && topStack != this && topActivity.isState(RESUMED)) {
// Usually resuming a top activity triggers the next app transition, but nothing's got
// resumed in this case, so we need to execute it explicitly.
- getDisplay().mDisplayContent.executeAppTransition();
+ mDisplayContent.executeAppTransition();
} else {
mRootWindowContainer.resumeFocusedStacksTopActivities();
}
@@ -7579,17 +7558,21 @@ class Task extends WindowContainer<WindowContainer> {
}
void executeAppTransition(ActivityOptions options) {
- getDisplay().mDisplayContent.executeAppTransition();
+ mDisplayContent.executeAppTransition();
ActivityOptions.abort(options);
}
boolean shouldSleepActivities() {
- final DisplayContent display = getDisplay();
+ final DisplayContent display = mDisplayContent;
// Do not sleep activities in this stack if we're marked as focused and the keyguard
// is in the process of going away.
if (isFocusedStackOnDisplay()
- && mStackSupervisor.getKeyguardController().isKeyguardGoingAway()) {
+ && mStackSupervisor.getKeyguardController().isKeyguardGoingAway()
+ // Avoid resuming activities on secondary displays since we don't want bubble
+ // activities to be resumed while bubble is still collapsed.
+ // TODO(b/113840485): Having keyguard going away state for secondary displays.
+ && display.isDefaultDisplay) {
return false;
}
diff --git a/services/core/java/com/android/server/wm/TaskOrganizerController.java b/services/core/java/com/android/server/wm/TaskOrganizerController.java
index f8465ddc02a2..63a595e3bc17 100644
--- a/services/core/java/com/android/server/wm/TaskOrganizerController.java
+++ b/services/core/java/com/android/server/wm/TaskOrganizerController.java
@@ -23,6 +23,7 @@ import static android.app.WindowConfiguration.WINDOWING_MODE_PINNED;
import static android.app.WindowConfiguration.WINDOWING_MODE_SPLIT_SCREEN_PRIMARY;
import static android.app.WindowConfiguration.WINDOWING_MODE_SPLIT_SCREEN_SECONDARY;
+import static com.android.internal.protolog.ProtoLogGroup.WM_DEBUG_WINDOW_ORGANIZER;
import static com.android.server.wm.WindowOrganizerController.CONTROLLABLE_CONFIGS;
import static com.android.server.wm.WindowOrganizerController.CONTROLLABLE_WINDOW_CONFIGS;
@@ -37,19 +38,20 @@ import android.os.Binder;
import android.os.IBinder;
import android.os.RemoteException;
import android.util.Slog;
+import android.util.SparseBooleanArray;
import android.view.SurfaceControl;
import android.window.ITaskOrganizer;
import android.window.ITaskOrganizerController;
import android.window.WindowContainerToken;
import com.android.internal.annotations.VisibleForTesting;
+import com.android.internal.protolog.common.ProtoLog;
import com.android.internal.util.ArrayUtils;
import java.io.PrintWriter;
import java.util.ArrayList;
-import java.util.Arrays;
import java.util.HashMap;
-import java.util.LinkedHashMap;
+import java.util.HashSet;
import java.util.LinkedList;
import java.util.List;
import java.util.Set;
@@ -126,6 +128,7 @@ class TaskOrganizerController extends ITaskOrganizerController.Stub {
}
void onTaskAppeared(Task task) {
+ ProtoLog.v(WM_DEBUG_WINDOW_ORGANIZER, "Task appeared taskId=%d", task.mTaskId);
final boolean visible = task.isVisible();
final RunningTaskInfo taskInfo = task.getTaskInfo();
mDeferTaskOrgCallbacksConsumer.accept(() -> {
@@ -147,6 +150,7 @@ class TaskOrganizerController extends ITaskOrganizerController.Stub {
void onTaskVanished(Task task) {
+ ProtoLog.v(WM_DEBUG_WINDOW_ORGANIZER, "Task vanished taskId=%d", task.mTaskId);
final RunningTaskInfo taskInfo = task.getTaskInfo();
mDeferTaskOrgCallbacksConsumer.accept(() -> {
try {
@@ -163,6 +167,7 @@ class TaskOrganizerController extends ITaskOrganizerController.Stub {
// by the organizer that don't receive that signal
return;
}
+ ProtoLog.v(WM_DEBUG_WINDOW_ORGANIZER, "Task info changed taskId=%d", task.mTaskId);
mDeferTaskOrgCallbacksConsumer.accept(() -> {
if (!task.isOrganized()) {
// This is safe to ignore if the task is no longer organized
@@ -177,6 +182,8 @@ class TaskOrganizerController extends ITaskOrganizerController.Stub {
}
void onBackPressedOnTaskRoot(Task task) {
+ ProtoLog.v(WM_DEBUG_WINDOW_ORGANIZER, "Task back pressed on root taskId=%d",
+ task.mTaskId);
if (!task.mCreatedByOrganizer && !task.mTaskAppearedSent) {
// Skip if the task has not yet received taskAppeared(), except for tasks created
// by the organizer that don't receive that signal
@@ -201,7 +208,6 @@ class TaskOrganizerController extends ITaskOrganizerController.Stub {
private final DeathRecipient mDeathRecipient;
private final ArrayList<Task> mOrganizedTasks = new ArrayList<>();
private final int mUid;
- private boolean mInterceptBackPressedOnTaskRoot;
TaskOrganizerState(ITaskOrganizer organizer, int uid) {
final Consumer<Runnable> deferTaskOrgCallbacksConsumer =
@@ -219,10 +225,6 @@ class TaskOrganizerController extends ITaskOrganizerController.Stub {
mUid = uid;
}
- void setInterceptBackPressedOnTaskRoot(boolean interceptBackPressed) {
- mInterceptBackPressedOnTaskRoot = interceptBackPressed;
- }
-
void addTask(Task t) {
if (t.mTaskAppearedSent) return;
@@ -242,6 +244,7 @@ class TaskOrganizerController extends ITaskOrganizerController.Stub {
mOrganizer.onTaskVanished(t);
}
mOrganizedTasks.remove(t);
+ mInterceptBackPressedOnRootTasks.remove(t.mTaskId);
}
void dispose() {
@@ -273,6 +276,8 @@ class TaskOrganizerController extends ITaskOrganizerController.Stub {
private final HashMap<IBinder, TaskOrganizerState> mTaskOrganizerStates = new HashMap<>();
private final WeakHashMap<Task, RunningTaskInfo> mLastSentTaskInfos = new WeakHashMap<>();
private final ArrayList<Task> mPendingTaskInfoChanges = new ArrayList<>();
+ // Set of organized tasks (by taskId) that dispatch back pressed to their organizers
+ private final HashSet<Integer> mInterceptBackPressedOnRootTasks = new HashSet();
private final ActivityTaskManagerService mService;
@@ -306,6 +311,8 @@ class TaskOrganizerController extends ITaskOrganizerController.Stub {
final long origId = Binder.clearCallingIdentity();
try {
synchronized (mGlobalLock) {
+ ProtoLog.v(WM_DEBUG_WINDOW_ORGANIZER, "Register task organizer=%s uid=%d",
+ organizer.asBinder(), uid);
for (int winMode : SUPPORTED_WINDOWING_MODES) {
if (!mTaskOrganizerStates.containsKey(organizer.asBinder())) {
mTaskOrganizers.add(organizer);
@@ -327,6 +334,7 @@ class TaskOrganizerController extends ITaskOrganizerController.Stub {
@Override
public void unregisterTaskOrganizer(ITaskOrganizer organizer) {
enforceStackPermission("unregisterTaskOrganizer()");
+ final int uid = Binder.getCallingUid();
final long origId = Binder.clearCallingIdentity();
try {
synchronized (mGlobalLock) {
@@ -334,6 +342,8 @@ class TaskOrganizerController extends ITaskOrganizerController.Stub {
if (state == null) {
return;
}
+ ProtoLog.v(WM_DEBUG_WINDOW_ORGANIZER, "Unregister task organizer=%s uid=%d",
+ organizer.asBinder(), uid);
state.unlinkDeath();
state.dispose();
}
@@ -383,6 +393,8 @@ class TaskOrganizerController extends ITaskOrganizerController.Stub {
return null;
}
+ ProtoLog.v(WM_DEBUG_WINDOW_ORGANIZER, "Create root task displayId=%d winMode=%d",
+ displayId, windowingMode);
final Task task = display.getDefaultTaskDisplayArea().createStack(windowingMode,
ACTIVITY_TYPE_UNDEFINED, false /* onTop */, null /* info */, new Intent(),
true /* createdByOrganizer */);
@@ -407,6 +419,9 @@ class TaskOrganizerController extends ITaskOrganizerController.Stub {
throw new IllegalArgumentException(
"Attempt to delete task not created by organizer task=" + task);
}
+
+ ProtoLog.v(WM_DEBUG_WINDOW_ORGANIZER, "Delete root task display=%d winMode=%d",
+ task.getDisplayId(), task.getWindowingMode());
task.removeImmediately();
return true;
}
@@ -608,15 +623,23 @@ class TaskOrganizerController extends ITaskOrganizerController.Stub {
}
@Override
- public void setInterceptBackPressedOnTaskRoot(ITaskOrganizer organizer,
+ public void setInterceptBackPressedOnTaskRoot(WindowContainerToken token,
boolean interceptBackPressed) {
enforceStackPermission("setInterceptBackPressedOnTaskRoot()");
final long origId = Binder.clearCallingIdentity();
try {
synchronized (mGlobalLock) {
- final TaskOrganizerState state = mTaskOrganizerStates.get(organizer.asBinder());
- if (state != null) {
- state.setInterceptBackPressedOnTaskRoot(interceptBackPressed);
+ ProtoLog.v(WM_DEBUG_WINDOW_ORGANIZER, "Set intercept back pressed on root=%b",
+ interceptBackPressed);
+ final Task task = WindowContainer.fromBinder(token.asBinder()).asTask();
+ if (task == null) {
+ Slog.w(TAG, "Could not resolve task from token");
+ return;
+ }
+ if (interceptBackPressed) {
+ mInterceptBackPressedOnRootTasks.add(task.mTaskId);
+ } else {
+ mInterceptBackPressedOnRootTasks.remove(task.mTaskId);
}
}
} finally {
@@ -625,15 +648,12 @@ class TaskOrganizerController extends ITaskOrganizerController.Stub {
}
public boolean handleInterceptBackPressedOnTaskRoot(Task task) {
- if (task == null || !task.isOrganized()) {
+ if (task == null || !task.isOrganized()
+ || !mInterceptBackPressedOnRootTasks.contains(task.mTaskId)) {
return false;
}
final TaskOrganizerState state = mTaskOrganizerStates.get(task.mTaskOrganizer.asBinder());
- if (!state.mInterceptBackPressedOnTaskRoot) {
- return false;
- }
-
state.mOrganizer.onBackPressedOnTaskRoot(task);
return true;
}
diff --git a/services/core/java/com/android/server/wm/TaskSnapshotController.java b/services/core/java/com/android/server/wm/TaskSnapshotController.java
index dbbb7ff69b3b..e3112efdead2 100644
--- a/services/core/java/com/android/server/wm/TaskSnapshotController.java
+++ b/services/core/java/com/android/server/wm/TaskSnapshotController.java
@@ -483,7 +483,7 @@ class TaskSnapshotController {
final InsetsState insetsState =
new InsetsState(insetsPolicy.getInsetsForDispatch(mainWindow));
mergeInsetsSources(insetsState, mainWindow.getRequestedInsetsState());
- final Rect systemBarInsets = getSystemBarInsets(mainWindow.getFrameLw(), insetsState);
+ final Rect systemBarInsets = getSystemBarInsets(mainWindow.getFrame(), insetsState);
final SystemBarBackgroundPainter decorPainter = new SystemBarBackgroundPainter(attrs.flags,
attrs.privateFlags, attrs.systemUiVisibility, task.getTaskDescription(),
mHighResTaskSnapshotScale, insetsState);
diff --git a/services/core/java/com/android/server/wm/WallpaperController.java b/services/core/java/com/android/server/wm/WallpaperController.java
index 6e00ab4939fa..ce138674cb93 100644
--- a/services/core/java/com/android/server/wm/WallpaperController.java
+++ b/services/core/java/com/android/server/wm/WallpaperController.java
@@ -308,7 +308,7 @@ class WallpaperController {
float defaultWallpaperX = wallpaperWin.isRtl() ? 1f : 0f;
float wpx = mLastWallpaperX >= 0 ? mLastWallpaperX : defaultWallpaperX;
float wpxs = mLastWallpaperXStep >= 0 ? mLastWallpaperXStep : -1.0f;
- int availw = wallpaperWin.getFrameLw().right - wallpaperWin.getFrameLw().left - dw;
+ int availw = wallpaperWin.getFrame().right - wallpaperWin.getFrame().left - dw;
int offset = availw > 0 ? -(int)(availw * wpx + .5f) : 0;
if (mLastWallpaperDisplayOffsetX != Integer.MIN_VALUE) {
offset += mLastWallpaperDisplayOffsetX;
@@ -323,7 +323,7 @@ class WallpaperController {
float wpy = mLastWallpaperY >= 0 ? mLastWallpaperY : 0.5f;
float wpys = mLastWallpaperYStep >= 0 ? mLastWallpaperYStep : -1.0f;
- int availh = wallpaperWin.getFrameLw().bottom - wallpaperWin.getFrameLw().top - dh;
+ int availh = wallpaperWin.getFrame().bottom - wallpaperWin.getFrame().top - dh;
offset = availh > 0 ? -(int)(availh * wpy + .5f) : 0;
if (mLastWallpaperDisplayOffsetY != Integer.MIN_VALUE) {
offset += mLastWallpaperDisplayOffsetY;
diff --git a/services/core/java/com/android/server/wm/WindowManagerService.java b/services/core/java/com/android/server/wm/WindowManagerService.java
index 2ce16b2fdd79..017747f03ca0 100644
--- a/services/core/java/com/android/server/wm/WindowManagerService.java
+++ b/services/core/java/com/android/server/wm/WindowManagerService.java
@@ -376,8 +376,11 @@ public class WindowManagerService extends IWindowManager.Stub
private static final String BOOT_ANIMATION_SERVICE = "bootanim";
static final int UPDATE_FOCUS_NORMAL = 0;
+ /** Caller will assign layers */
static final int UPDATE_FOCUS_WILL_ASSIGN_LAYERS = 1;
+ /** Caller is performing surface placement */
static final int UPDATE_FOCUS_PLACING_SURFACES = 2;
+ /** Caller will performSurfacePlacement */
static final int UPDATE_FOCUS_WILL_PLACE_SURFACES = 3;
/** Indicates we are removing the focused window when updating the focus. */
static final int UPDATE_FOCUS_REMOVING_FOCUS = 4;
@@ -1407,7 +1410,8 @@ public class WindowManagerService extends IWindowManager.Stub
if (!displayContent.hasAccess(session.mUid)) {
ProtoLog.w(WM_ERROR,
"Attempted to add window to a display for which the application "
- + "does not have access: %d. Aborting.", displayId);
+ + "does not have access: %d. Aborting.",
+ displayContent.getDisplayId());
return WindowManagerGlobal.ADD_INVALID_DISPLAY;
}
@@ -1848,7 +1852,7 @@ public class WindowManagerService extends IWindowManager.Stub
}
// We use the visible frame, because we want the animation to morph the window from what
// was visible to the user to the final destination of the new window.
- Rect frame = replacedWindow.getVisibleFrameLw();
+ Rect frame = replacedWindow.getVisibleFrame();
// We treat this as if this activity was opening, so we can trigger the app transition
// animation and piggy-back on existing transition animation infrastructure.
final DisplayContent dc = activity.getDisplayContent();
@@ -2069,7 +2073,7 @@ public class WindowManagerService extends IWindowManager.Stub
outDisplayFrame.setEmpty();
return;
}
- outDisplayFrame.set(win.getDisplayFrameLw());
+ outDisplayFrame.set(win.getDisplayFrame());
if (win.inSizeCompatMode()) {
outDisplayFrame.scale(win.mInvGlobalScale);
}
@@ -2389,7 +2393,7 @@ public class WindowManagerService extends IWindowManager.Stub
if (displayPolicy.areSystemBarsForcedShownLw(win)) {
result |= WindowManagerGlobal.RELAYOUT_RES_CONSUME_ALWAYS_SYSTEM_BARS;
}
- if (!win.isGoneForLayoutLw()) {
+ if (!win.isGoneForLayout()) {
win.mResizedWhileGone = false;
}
@@ -2419,7 +2423,7 @@ public class WindowManagerService extends IWindowManager.Stub
win.getInsetsForRelayout(outContentInsets, outVisibleInsets,
outStableInsets);
outCutout.set(win.getWmDisplayCutout().getDisplayCutout());
- outBackdropFrame.set(win.getBackdropFrame(win.getFrameLw()));
+ outBackdropFrame.set(win.getBackdropFrame(win.getFrame()));
outInsetsState.set(win.getInsetsState(), win.isClientLocal());
if (DEBUG) {
Slog.v(TAG_WM, "Relayout given client " + client.asBinder()
@@ -2883,11 +2887,6 @@ public class WindowManagerService extends IWindowManager.Stub
}
@Override
- public WindowManagerPolicy.WindowState getInputMethodWindowLw() {
- return mRoot.getCurrentInputMethodWindow();
- }
-
- @Override
public void notifyKeyguardTrustedChanged() {
mAtmInternal.notifyKeyguardTrustedChanged();
}
@@ -4735,12 +4734,30 @@ public class WindowManagerService extends IWindowManager.Stub
return false;
}
+ void reportFocusChanged(IBinder oldToken, IBinder newToken) {
+ WindowState lastFocus;
+ WindowState newFocus;
+ synchronized (mGlobalLock) {
+ lastFocus = mInputToWindowMap.get(oldToken);
+ newFocus = mInputToWindowMap.get(newToken);
+ ProtoLog.i(WM_DEBUG_FOCUS_LIGHT, "Focus changing: %s -> %s", lastFocus, newFocus);
+ }
+
+ if (newFocus != null) {
+ newFocus.reportFocusChangedSerialized(true);
+ notifyFocusChanged();
+ }
+
+ if (lastFocus != null) {
+ lastFocus.reportFocusChangedSerialized(false);
+ }
+ }
+
// -------------------------------------------------------------
// Async Handler
// -------------------------------------------------------------
final class H extends android.os.Handler {
- public static final int REPORT_FOCUS_CHANGE = 2;
public static final int WINDOW_FREEZE_TIMEOUT = 11;
public static final int PERSIST_ANIMATION_SCALE = 14;
@@ -4793,50 +4810,6 @@ public class WindowManagerService extends IWindowManager.Stub
Slog.v(TAG_WM, "handleMessage: entry what=" + msg.what);
}
switch (msg.what) {
- case REPORT_FOCUS_CHANGE: {
- final DisplayContent displayContent = (DisplayContent) msg.obj;
- WindowState lastFocus;
- WindowState newFocus;
-
- AccessibilityController accessibilityController = null;
-
- synchronized (mGlobalLock) {
- if (mAccessibilityController != null) {
- accessibilityController = mAccessibilityController;
- }
-
- lastFocus = displayContent.mLastFocus;
- newFocus = displayContent.mCurrentFocus;
- if (lastFocus == newFocus) {
- // Focus is not changing, so nothing to do.
- return;
- }
- displayContent.mLastFocus = newFocus;
- ProtoLog.i(WM_DEBUG_FOCUS_LIGHT, "Focus moving from %s"
- + " to %s displayId=%d", lastFocus, newFocus,
- displayContent.getDisplayId());
- }
-
- // First notify the accessibility manager for the change so it has
- // the windows before the newly focused one starts firing events.
- if (accessibilityController != null) {
- accessibilityController.onWindowFocusChangedNotLocked(
- displayContent.getDisplayId());
- }
-
- if (newFocus != null) {
- ProtoLog.i(WM_DEBUG_FOCUS_LIGHT, "Gaining focus: %s", newFocus);
- newFocus.reportFocusChangedSerialized(true);
- notifyFocusChanged();
- }
-
- if (lastFocus != null) {
- ProtoLog.i(WM_DEBUG_FOCUS_LIGHT, "Losing focus: %s", lastFocus);
- lastFocus.reportFocusChangedSerialized(false);
- }
- break;
- }
-
case WINDOW_FREEZE_TIMEOUT: {
final DisplayContent displayContent = (DisplayContent) msg.obj;
synchronized (mGlobalLock) {
@@ -5481,7 +5454,7 @@ public class WindowManagerService extends IWindowManager.Stub
// Window has been removed or hidden; no draw will now happen, so stop waiting.
ProtoLog.w(WM_DEBUG_SCREEN_ON, "Aborted waiting for drawn: %s", win);
container.mWaitingForDrawn.remove(win);
- } else if (win.hasDrawnLw()) {
+ } else if (win.hasDrawn()) {
// Window is now drawn (and shown).
ProtoLog.d(WM_DEBUG_SCREEN_ON, "Window drawn win=%s", win);
container.mWaitingForDrawn.remove(win);
@@ -7356,7 +7329,7 @@ public class WindowManagerService extends IWindowManager.Stub
synchronized (mGlobalLock) {
WindowState windowState = mWindowMap.get(token);
if (windowState != null) {
- outBounds.set(windowState.getFrameLw());
+ outBounds.set(windowState.getFrame());
} else {
outBounds.setEmpty();
}
@@ -7999,6 +7972,8 @@ public class WindowManagerService extends IWindowManager.Stub
return;
}
+ ProtoLog.i(WM_DEBUG_FOCUS_LIGHT, "onPointerDownOutsideFocusLocked called on %s",
+ touchedWindow);
final DisplayContent displayContent = touchedWindow.getDisplayContent();
if (!displayContent.isOnTop()) {
displayContent.getParent().positionChildAt(WindowContainer.POSITION_TOP, displayContent,
@@ -8027,10 +8002,7 @@ public class WindowManagerService extends IWindowManager.Stub
}
}
- try {
- mActivityTaskManager.setFocusedTask(task.mTaskId);
- } catch (RemoteException e) {
- }
+ mAtmService.setFocusedTask(task.mTaskId);
}
/**
diff --git a/services/core/java/com/android/server/wm/WindowOrganizerController.java b/services/core/java/com/android/server/wm/WindowOrganizerController.java
index d25a64890337..c7cad2f76486 100644
--- a/services/core/java/com/android/server/wm/WindowOrganizerController.java
+++ b/services/core/java/com/android/server/wm/WindowOrganizerController.java
@@ -19,6 +19,7 @@ package com.android.server.wm;
import static android.Manifest.permission.MANAGE_ACTIVITY_STACKS;
import static android.Manifest.permission.READ_FRAME_BUFFER;
+import static com.android.internal.protolog.ProtoLogGroup.WM_DEBUG_WINDOW_ORGANIZER;
import static com.android.server.wm.ActivityStackSupervisor.PRESERVE_WINDOWS;
import static com.android.server.wm.ActivityTaskManagerService.LAYOUT_REASON_CONFIG_CHANGED;
import static com.android.server.wm.Task.FLAG_FORCE_HIDDEN_FOR_TASK_ORG;
@@ -45,6 +46,7 @@ import android.window.WindowContainerToken;
import android.window.WindowContainerTransaction;
import com.android.internal.annotations.VisibleForTesting;
+import com.android.internal.protolog.common.ProtoLog;
import com.android.internal.util.function.pooled.PooledConsumer;
import com.android.internal.util.function.pooled.PooledLambda;
@@ -127,6 +129,8 @@ class WindowOrganizerController extends IWindowOrganizerController.Stub
if (callback != null) {
syncId = startSyncWithOrganizer(callback);
}
+ ProtoLog.v(WM_DEBUG_WINDOW_ORGANIZER, "Apply window transaction, syncId=%d",
+ syncId);
mService.deferWindowLayout();
try {
ArraySet<WindowContainer> haveConfigChanges = new ArraySet<>();
@@ -427,6 +431,7 @@ class WindowOrganizerController extends IWindowOrganizerController.Stub
@VisibleForTesting
void setSyncReady(int id) {
+ ProtoLog.v(WM_DEBUG_WINDOW_ORGANIZER, "Set sync ready, syncId=%d", id);
mBLASTSyncEngine.setReady(id);
}
@@ -436,9 +441,10 @@ class WindowOrganizerController extends IWindowOrganizerController.Stub
}
@Override
- public void onTransactionReady(int mSyncId, Set<WindowContainer> windowContainersReady) {
+ public void onTransactionReady(int syncId, Set<WindowContainer> windowContainersReady) {
+ ProtoLog.v(WM_DEBUG_WINDOW_ORGANIZER, "Transaction ready, syncId=%d", syncId);
final IWindowContainerTransactionCallback callback =
- mTransactionCallbacksByPendingSyncId.get(mSyncId);
+ mTransactionCallbacksByPendingSyncId.get(syncId);
SurfaceControl.Transaction mergedTransaction = new SurfaceControl.Transaction();
for (WindowContainer container : windowContainersReady) {
@@ -446,14 +452,14 @@ class WindowOrganizerController extends IWindowOrganizerController.Stub
}
try {
- callback.onTransactionReady(mSyncId, mergedTransaction);
+ callback.onTransactionReady(syncId, mergedTransaction);
} catch (RemoteException e) {
// If there's an exception when trying to send the mergedTransaction to the client, we
// should immediately apply it here so the transactions aren't lost.
mergedTransaction.apply();
}
- mTransactionCallbacksByPendingSyncId.remove(mSyncId);
+ mTransactionCallbacksByPendingSyncId.remove(syncId);
}
@Override
diff --git a/services/core/java/com/android/server/wm/WindowProcessController.java b/services/core/java/com/android/server/wm/WindowProcessController.java
index c714eeb92e68..8bf0820c7dad 100644
--- a/services/core/java/com/android/server/wm/WindowProcessController.java
+++ b/services/core/java/com/android/server/wm/WindowProcessController.java
@@ -22,9 +22,9 @@ import static android.os.Build.VERSION_CODES.Q;
import static android.os.IInputConstants.DEFAULT_DISPATCHING_TIMEOUT_MILLIS;
import static android.view.Display.INVALID_DISPLAY;
+import static com.android.internal.protolog.ProtoLogGroup.WM_DEBUG_CONFIGURATION;
import static com.android.server.am.ActivityManagerService.MY_PID;
import static com.android.server.wm.ActivityTaskManagerDebugConfig.DEBUG_ACTIVITY_STARTS;
-import static com.android.server.wm.ActivityTaskManagerDebugConfig.DEBUG_CONFIGURATION;
import static com.android.server.wm.ActivityTaskManagerDebugConfig.DEBUG_RELEASE;
import static com.android.server.wm.ActivityTaskManagerDebugConfig.POSTFIX_CONFIGURATION;
import static com.android.server.wm.ActivityTaskManagerDebugConfig.POSTFIX_RELEASE;
@@ -72,6 +72,7 @@ import android.view.IRemoteAnimationRunner;
import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.app.HeavyWeightSwitcherActivity;
+import com.android.internal.protolog.common.ProtoLog;
import com.android.internal.util.function.pooled.PooledLambda;
import com.android.server.Watchdog;
import com.android.server.wm.ActivityTaskManagerService.HotPath;
@@ -728,15 +729,16 @@ public class WindowProcessController extends ConfigurationContainer<Configuratio
return true;
}
- final DisplayContent display = activity.getDisplay();
- if (display == null) {
+ if (!activity.isAttached()) {
// No need to update if the activity hasn't attach to any display.
return false;
}
boolean canUpdate = false;
final DisplayContent topDisplay =
- mPreQTopResumedActivity != null ? mPreQTopResumedActivity.getDisplay() : null;
+ (mPreQTopResumedActivity != null && mPreQTopResumedActivity.isAttached())
+ ? mPreQTopResumedActivity.mDisplayContent
+ : null;
// Update the topmost activity if current top activity is
// - not on any display OR
// - no longer visible OR
@@ -747,8 +749,9 @@ public class WindowProcessController extends ConfigurationContainer<Configuratio
canUpdate = true;
}
+ final DisplayContent display = activity.mDisplayContent;
// Update the topmost activity if the current top activity wasn't on top of the other one.
- if (!canUpdate && topDisplay.mDisplayContent.compareTo(display.mDisplayContent) < 0) {
+ if (!canUpdate && topDisplay.compareTo(display) < 0) {
canUpdate = true;
}
@@ -941,7 +944,7 @@ public class WindowProcessController extends ConfigurationContainer<Configuratio
final ActivityRecord r = candidates.remove(0);
if (DEBUG_RELEASE) Slog.v(TAG_RELEASE, "Destroying " + r
+ " in state " + r.getState() + " for reason " + reason);
- r.destroyImmediately(true /*removeFromApp*/, reason);
+ r.destroyImmediately(reason);
--maxRelease;
} while (maxRelease > 0);
}
@@ -1348,9 +1351,8 @@ public class WindowProcessController extends ConfigurationContainer<Configuratio
}
return;
}
- if (DEBUG_CONFIGURATION) {
- Slog.v(TAG_CONFIGURATION, "Sending to proc " + mName + " new config " + config);
- }
+ ProtoLog.v(WM_DEBUG_CONFIGURATION, "Sending to proc %s new config %s", mName,
+ config);
if (Build.IS_DEBUGGABLE && mHasImeService) {
// TODO (b/135719017): Temporary log for debugging IME service.
Slog.v(TAG_CONFIGURATION, "Sending to IME proc " + mName + " new config " + config);
diff --git a/services/core/java/com/android/server/wm/WindowState.java b/services/core/java/com/android/server/wm/WindowState.java
index 0e455d2a5aa6..84a9c750d2d3 100644
--- a/services/core/java/com/android/server/wm/WindowState.java
+++ b/services/core/java/com/android/server/wm/WindowState.java
@@ -1009,8 +1009,8 @@ class WindowState extends WindowContainer<WindowState> implements WindowManagerP
getDisplayContent().reapplyMagnificationSpec();
}
- @Override
- public int getOwningUid() {
+ /** Returns the uid of the app that owns this window. */
+ int getOwningUid() {
return mOwnerUid;
}
@@ -1024,8 +1024,12 @@ class WindowState extends WindowContainer<WindowState> implements WindowManagerP
return mOwnerCanAddInternalSystemWindow;
}
- @Override
- public boolean canAcquireSleepToken() {
+ /**
+ * Returns {@code true} if the window owner has the permission to acquire a sleep token when
+ * it's visible. That is, they have the permission
+ * {@link androidManifest.permission#DEVICE_POWER}.
+ */
+ boolean canAcquireSleepToken() {
return mSession.mCanAcquireSleepToken;
}
@@ -1046,7 +1050,7 @@ class WindowState extends WindowContainer<WindowState> implements WindowManagerP
void computeFrame(DisplayFrames displayFrames) {
getLayoutingWindowFrames().setDisplayCutout(displayFrames.mDisplayCutout);
- computeFrameLw();
+ computeFrame();
// Update the source frame to provide insets to other windows during layout. If the
// simulated frames exist, then this is not computing a stable result so just skip.
if (mControllableInsetProvider != null && mSimulatedWindowFrames == null) {
@@ -1054,8 +1058,10 @@ class WindowState extends WindowContainer<WindowState> implements WindowManagerP
}
}
- @Override
- public void computeFrameLw() {
+ /**
+ * Perform standard frame computation. The result can be obtained with getFrame() if so desired.
+ */
+ void computeFrame() {
if (mWillReplaceWindow && (mAnimatingExit || !mReplacingRemoveRequested)) {
// This window is being replaced and either already got information that it's being
// removed or we are still waiting for some information. Because of this we don't
@@ -1283,32 +1289,41 @@ class WindowState extends WindowContainer<WindowState> implements WindowManagerP
}
}
- @Override
- public Rect getFrameLw() {
+ /** Retrieves the current frame of the window that the application sees. */
+ Rect getFrame() {
return mWindowFrames.mFrame;
}
/** Accessor for testing */
- Rect getRelativeFrameLw() {
+ Rect getRelativeFrame() {
return mWindowFrames.mRelFrame;
}
- @Override
- public Rect getDisplayFrameLw() {
+ /** Retrieves the frame of the display that this window was last laid out in. */
+ Rect getDisplayFrame() {
return mWindowFrames.mDisplayFrame;
}
- @Override
- public Rect getContentFrameLw() {
+ /**
+ * Retrieves the frame of the content area that this window was last laid out in. This is the
+ * area in which the content of the window should be placed. It will be smaller than the display
+ * frame to account for screen decorations such as a status bar or soft keyboard.
+ */
+ Rect getContentFrame() {
return mWindowFrames.mContentFrame;
}
- @Override
- public Rect getVisibleFrameLw() {
+ /**
+ * Retrieves the frame of the visible area that this window was last laid out in. This is the
+ * area of the screen in which the window will actually be fully visible. It will be smaller
+ * than the content frame to account for transient UI elements blocking it such as an input
+ * method's candidates UI.
+ */
+ Rect getVisibleFrame() {
return mWindowFrames.mVisibleFrame;
}
- Rect getStableFrameLw() {
+ Rect getStableFrame() {
return mWindowFrames.mStableFrame;
}
@@ -1337,32 +1352,17 @@ class WindowState extends WindowContainer<WindowState> implements WindowManagerP
}
@Override
- public boolean getGivenInsetsPendingLw() {
- return mGivenInsetsPending;
- }
-
- @Override
- public Rect getGivenContentInsetsLw() {
- return mGivenContentInsets;
- }
-
- @Override
- public Rect getGivenVisibleInsetsLw() {
- return mGivenVisibleInsets;
- }
-
- @Override
public WindowManager.LayoutParams getAttrs() {
return mAttrs;
}
- @Override
- public int getSystemUiVisibility() {
+ /** Retrieves the current system UI visibility flags associated with this window. */
+ int getSystemUiVisibility() {
return mSystemUiVisibility;
}
- @Override
- public int getSurfaceLayer() {
+ /** Gets the layer at which this window's surface will be Z-ordered. */
+ int getSurfaceLayer() {
return mLayer;
}
@@ -1376,8 +1376,8 @@ class WindowState extends WindowContainer<WindowState> implements WindowManagerP
return mActivityRecord != null ? mActivityRecord.appToken : null;
}
- @Override
- public boolean isVoiceInteraction() {
+ /** Returns true if this window is participating in voice interaction. */
+ boolean isVoiceInteraction() {
return mActivityRecord != null && mActivityRecord.mVoiceInteraction;
}
@@ -1391,7 +1391,7 @@ class WindowState extends WindowContainer<WindowState> implements WindowManagerP
*/
void updateResizingWindowIfNeeded() {
final WindowStateAnimator winAnimator = mWinAnimator;
- if (!mHasSurface || getDisplayContent().mLayoutSeq != mLayoutSeq || isGoneForLayoutLw()) {
+ if (!mHasSurface || getDisplayContent().mLayoutSeq != mLayoutSeq || isGoneForLayout()) {
return;
}
@@ -1464,7 +1464,7 @@ class WindowState extends WindowContainer<WindowState> implements WindowManagerP
mWmService.mResizingWindows.add(this);
}
} else if (getOrientationChanging()) {
- if (isDrawnLw()) {
+ if (isDrawn()) {
ProtoLog.v(WM_DEBUG_ORIENTATION,
"Orientation not waiting for draw in %s, surfaceController %s", this,
winAnimator.mSurfaceController);
@@ -1639,9 +1639,16 @@ class WindowState extends WindowContainer<WindowState> implements WindowManagerP
: DEFAULT_DISPATCHING_TIMEOUT_MILLIS;
}
- @Override
- public boolean hasAppShownWindows() {
- return mActivityRecord != null && (mActivityRecord.firstWindowDrawn || mActivityRecord.startingDisplayed);
+ /**
+ * Returns true if, at any point, the application token associated with this window has actually
+ * displayed any windows. This is most useful with the "starting up" window to determine if any
+ * windows were displayed when it is closed.
+ *
+ * @return {@code true} if one or more windows have been displayed, else false.
+ */
+ boolean hasAppShownWindows() {
+ return mActivityRecord != null
+ && (mActivityRecord.firstWindowDrawn || mActivityRecord.startingDisplayed);
}
boolean isIdentityMatrix(float dsdx, float dtdx, float dsdy, float dtdy) {
@@ -1663,7 +1670,7 @@ class WindowState extends WindowContainer<WindowState> implements WindowManagerP
@Override
boolean hasContentToDisplay() {
- if (!mAppFreezing && isDrawnLw() && (mViewVisibility == View.VISIBLE
+ if (!mAppFreezing && isDrawn() && (mViewVisibility == View.VISIBLE
|| (isAnimating(TRANSITION | PARENTS)
&& !getDisplayContent().mAppTransition.isTransitionSet()))) {
return true;
@@ -1851,10 +1858,9 @@ class WindowState extends WindowContainer<WindowState> implements WindowManagerP
* Like isOnScreen, but returns false if the surface hasn't yet
* been drawn.
*/
- @Override
- public boolean isDisplayedLw() {
+ boolean isDisplayed() {
final ActivityRecord atoken = mActivityRecord;
- return isDrawnLw() && isVisibleByPolicy()
+ return isDrawn() && isVisibleByPolicy()
&& ((!isParentWindowHidden() && (atoken == null || atoken.mVisibleRequested))
|| isAnimating(TRANSITION | PARENTS));
}
@@ -1867,8 +1873,8 @@ class WindowState extends WindowContainer<WindowState> implements WindowManagerP
return isAnimating(TRANSITION | PARENTS);
}
- @Override
- public boolean isGoneForLayoutLw() {
+ /** Returns {@code true} if this window considered to be gone for purposes of layout. */
+ boolean isGoneForLayout() {
final ActivityRecord atoken = mActivityRecord;
return mViewVisibility == View.GONE
|| !mRelayoutCalled
@@ -1895,11 +1901,11 @@ class WindowState extends WindowContainer<WindowState> implements WindowManagerP
}
/**
- * Returns true if the window has a surface that it has drawn a
- * complete UI in to.
+ * Returns true if the window has a surface that it has drawn a complete UI in to. Note that
+ * this is different from {@link #hasDrawn()} in that it also returns true if the window is
+ * READY_TO_SHOW, but was not yet promoted to HAS_DRAWN.
*/
- @Override
- public boolean isDrawnLw() {
+ boolean isDrawn() {
return mHasSurface && !mDestroying &&
(mWinAnimator.mDrawState == READY_TO_SHOW || mWinAnimator.mDrawState == HAS_DRAWN);
}
@@ -1914,7 +1920,7 @@ class WindowState extends WindowContainer<WindowState> implements WindowManagerP
// to determine if it's occluding apps.
return ((!mIsWallpaper && mAttrs.format == PixelFormat.OPAQUE)
|| (mIsWallpaper && mWallpaperVisible))
- && isDrawnLw() && !isAnimating(TRANSITION | PARENTS);
+ && isDrawn() && !isAnimating(TRANSITION | PARENTS);
}
/** @see WindowManagerInternal#waitForAllWindowsDrawn */
@@ -1929,7 +1935,7 @@ class WindowState extends WindowContainer<WindowState> implements WindowManagerP
return;
}
if (mAttrs.type == TYPE_APPLICATION_STARTING) {
- if (isDrawnLw()) {
+ if (isDrawn()) {
// Unnecessary to redraw a drawn starting window.
return;
}
@@ -2016,11 +2022,11 @@ class WindowState extends WindowContainer<WindowState> implements WindowManagerP
@Override
void onResize() {
final ArrayList<WindowState> resizingWindows = mWmService.mResizingWindows;
- if (mHasSurface && !isGoneForLayoutLw() && !resizingWindows.contains(this)) {
+ if (mHasSurface && !isGoneForLayout() && !resizingWindows.contains(this)) {
ProtoLog.d(WM_DEBUG_RESIZE, "onResize: Resizing %s", this);
resizingWindows.add(this);
}
- if (isGoneForLayoutLw()) {
+ if (isGoneForLayout()) {
mResizedWhileGone = true;
}
@@ -2058,10 +2064,17 @@ class WindowState extends WindowContainer<WindowState> implements WindowManagerP
// animating... let's do something.
final int left = mWindowFrames.mFrame.left;
final int top = mWindowFrames.mFrame.top;
+
+ // During the transition from pip to fullscreen, the activity windowing mode is set to
+ // fullscreen at the beginning while the task is kept in pinned mode. Skip the move
+ // animation in such case since the transition is handled in SysUI.
+ final boolean hasMovementAnimation = getTask() == null
+ ? getWindowConfiguration().hasMovementAnimations()
+ : getTask().getWindowConfiguration().hasMovementAnimations();
if (mToken.okToAnimate()
&& (mAttrs.privateFlags & PRIVATE_FLAG_NO_MOVE_ANIMATION) == 0
&& !isDragResizing()
- && getWindowConfiguration().hasMovementAnimations()
+ && hasMovementAnimation
&& !mWinAnimator.mLastHidden
&& !mSeamlesslyRotated) {
startMoveAnimation(left, top);
@@ -2507,7 +2520,7 @@ class WindowState extends WindowContainer<WindowState> implements WindowManagerP
/** Returns true if the replacement window was removed. */
boolean removeReplacedWindowIfNeeded(WindowState replacement) {
- if (mWillReplaceWindow && mReplacementWindow == replacement && replacement.hasDrawnLw()) {
+ if (mWillReplaceWindow && mReplacementWindow == replacement && replacement.hasDrawn()) {
replacement.mSkipEnterAnimationForSeamlessReplacement = false;
removeReplacedWindow();
return true;
@@ -2741,7 +2754,7 @@ class WindowState extends WindowContainer<WindowState> implements WindowManagerP
mLayoutNeeded = true;
}
- if (isDrawnLw() && mToken.okToAnimate()) {
+ if (isDrawn() && mToken.okToAnimate()) {
mWinAnimator.applyEnterAnimationLocked();
}
}
@@ -2866,17 +2879,30 @@ class WindowState extends WindowContainer<WindowState> implements WindowManagerP
return getWindowConfiguration().keepVisibleDeadAppWindowOnScreen();
}
- @Override
- public boolean canReceiveKeys() {
+ /** Returns {@code true} if this window desires key events. */
+ boolean canReceiveKeys() {
return canReceiveKeys(false /* fromUserTouch */);
}
+ public String canReceiveKeysReason(boolean fromUserTouch) {
+ return "fromTouch= " + fromUserTouch
+ + " isVisibleOrAdding=" + isVisibleOrAdding()
+ + " mViewVisibility=" + mViewVisibility
+ + " mRemoveOnExit=" + mRemoveOnExit
+ + " flags=" + mAttrs.flags
+ + " appWindowsAreFocusable="
+ + (mActivityRecord == null || mActivityRecord.windowsAreFocusable(fromUserTouch))
+ + " canReceiveTouchInput=" + canReceiveTouchInput()
+ + " displayIsOnTop=" + getDisplayContent().isOnTop()
+ + " displayIsTrusted=" + getDisplayContent().isTrusted();
+ }
+
public boolean canReceiveKeys(boolean fromUserTouch) {
final boolean canReceiveKeys = isVisibleOrAdding()
&& (mViewVisibility == View.VISIBLE) && !mRemoveOnExit
&& ((mAttrs.flags & WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE) == 0)
&& (mActivityRecord == null || mActivityRecord.windowsAreFocusable(fromUserTouch))
- && !cantReceiveTouchInput();
+ && canReceiveTouchInput();
if (!canReceiveKeys) {
return false;
}
@@ -2894,15 +2920,18 @@ class WindowState extends WindowContainer<WindowState> implements WindowManagerP
return showBecauseOfActivity || showBecauseOfWindow;
}
- /** @return {@code false} if this window desires touch events. */
- boolean cantReceiveTouchInput() {
- if (mActivityRecord == null || mActivityRecord.getTask() == null) {
- return false;
+ /**
+ * @return {@code true} if this window can receive touches based on among other things,
+ * windowing state and recents animation state.
+ **/
+ boolean canReceiveTouchInput() {
+ if (mActivityRecord == null || mActivityRecord.getTask() == null) {
+ return true;
}
- return mActivityRecord.getTask().getRootTask().shouldIgnoreInput()
- || !mActivityRecord.mVisibleRequested
- || isRecentsAnimationConsumingAppInput();
+ return !mActivityRecord.getTask().getRootTask().shouldIgnoreInput()
+ && mActivityRecord.mVisibleRequested
+ && !isRecentsAnimationConsumingAppInput();
}
/**
@@ -2916,8 +2945,13 @@ class WindowState extends WindowContainer<WindowState> implements WindowManagerP
&& recentsAnimationController.shouldApplyInputConsumer(mActivityRecord);
}
- @Override
- public boolean hasDrawnLw() {
+ /**
+ * Returns {@code true} if this window has been shown on screen at some time in the past.
+ *
+ * @deprecated Use {@link #isDrawnLw} or any of the other drawn/visibility methods.
+ */
+ @Deprecated
+ boolean hasDrawn() {
return mWinAnimator.mDrawState == WindowStateAnimator.HAS_DRAWN;
}
@@ -3151,8 +3185,8 @@ class WindowState extends WindowContainer<WindowState> implements WindowManagerP
}
}
- @Override
- public boolean isAlive() {
+ /** Checks whether the process hosting this window is currently alive. */
+ boolean isAlive() {
return mClient.asBinder().isBinderAlive();
}
@@ -3332,16 +3366,6 @@ class WindowState extends WindowContainer<WindowState> implements WindowManagerP
mLastExclusionLogUptimeMillis[EXCLUSION_RIGHT] = now;
}
- @Override
- public boolean isDefaultDisplay() {
- final DisplayContent displayContent = getDisplayContent();
- if (displayContent == null) {
- // Only a window that was on a non-default display can be detached from it.
- return false;
- }
- return displayContent.isDefaultDisplay;
- }
-
/** @return {@code true} if this window can be shown to all users. */
boolean showForAllUsers() {
@@ -3401,10 +3425,10 @@ class WindowState extends WindowContainer<WindowState> implements WindowManagerP
// All window frames that are fullscreen extend above status bar, but some don't extend
// below navigation bar. Thus, check for display frame for top/left and stable frame for
// bottom right.
- if (win.getFrameLw().left <= win.getDisplayFrameLw().left
- && win.getFrameLw().top <= win.getDisplayFrameLw().top
- && win.getFrameLw().right >= win.getStableFrameLw().right
- && win.getFrameLw().bottom >= win.getStableFrameLw().bottom) {
+ if (win.getFrame().left <= win.getDisplayFrame().left
+ && win.getFrame().top <= win.getDisplayFrame().top
+ && win.getFrame().right >= win.getStableFrame().right
+ && win.getFrame().bottom >= win.getStableFrame().bottom) {
// Is a fullscreen window, like the clock alarm. Show to everyone.
return true;
}
@@ -3562,6 +3586,13 @@ class WindowState extends WindowContainer<WindowState> implements WindowManagerP
}
void reportResized() {
+ // If the activity is scheduled to relaunch, skip sending the resized to ViewRootImpl now
+ // since it will be destroyed anyway. This also prevents the client from receiving
+ // windowing mode change before it is destroyed.
+ if (mActivityRecord != null && mActivityRecord.isRelaunching()) {
+ return;
+ }
+
if (Trace.isTagEnabled(TRACE_TAG_WINDOW_MANAGER)) {
Trace.traceBegin(TRACE_TAG_WINDOW_MANAGER, "wm.reportResized_" + getWindowTag());
}
@@ -3767,11 +3798,11 @@ class WindowState extends WindowContainer<WindowState> implements WindowManagerP
* is transitioning into/out-of fullscreen. */
boolean isLetterboxedAppWindow() {
return !inMultiWindowMode() && !matchesDisplayBounds()
- || isLetterboxedForDisplayCutoutLw();
+ || isLetterboxedForDisplayCutout();
}
- @Override
- public boolean isLetterboxedForDisplayCutoutLw() {
+ /** Returns {@code true} if the window is letterboxed for the display cutout. */
+ boolean isLetterboxedForDisplayCutout() {
if (mActivityRecord == null) {
// Only windows with an ActivityRecord are letterboxed.
return false;
@@ -3875,7 +3906,7 @@ class WindowState extends WindowContainer<WindowState> implements WindowManagerP
// background.
return (getDisplayContent().mDividerControllerLocked.isResizing()
|| mActivityRecord != null && !mActivityRecord.mFrozenBounds.isEmpty()) &&
- !task.inFreeformWindowingMode() && !isGoneForLayoutLw();
+ !task.inFreeformWindowingMode() && !isGoneForLayout();
}
@@ -4291,7 +4322,7 @@ class WindowState extends WindowContainer<WindowState> implements WindowManagerP
private boolean isParentWindowGoneForLayout() {
final WindowState parent = getParentWindow();
- return parent != null && parent.isGoneForLayoutLw();
+ return parent != null && parent.isGoneForLayout();
}
void setWillReplaceWindow(boolean animate) {
@@ -4404,8 +4435,7 @@ class WindowState extends WindowContainer<WindowState> implements WindowManagerP
return null;
}
- @Override
- public int getRotationAnimationHint() {
+ int getRotationAnimationHint() {
if (mActivityRecord != null) {
return mActivityRecord.mRotationAnimationHint;
} else {
@@ -4861,7 +4891,7 @@ class WindowState extends WindowContainer<WindowState> implements WindowManagerP
}
boolean hasVisibleNotDrawnWallpaper() {
- if (mWallpaperVisible && !isDrawnLw()) {
+ if (mWallpaperVisible && !isDrawn()) {
return true;
}
for (int j = mChildren.size() - 1; j >= 0; --j) {
@@ -4885,9 +4915,9 @@ class WindowState extends WindowContainer<WindowState> implements WindowManagerP
return;
}
if (DEBUG_VISIBILITY) {
- Slog.v(TAG, "Win " + this + ": isDrawn=" + isDrawnLw()
+ Slog.v(TAG, "Win " + this + ": isDrawn=" + isDrawn()
+ ", animating=" + isAnimating(TRANSITION | PARENTS));
- if (!isDrawnLw()) {
+ if (!isDrawn()) {
Slog.v(TAG, "Not displayed: s=" + mWinAnimator.mSurfaceController
+ " pv=" + isVisibleByPolicy()
+ " mDrawState=" + mWinAnimator.mDrawState
@@ -4898,7 +4928,7 @@ class WindowState extends WindowContainer<WindowState> implements WindowManagerP
}
results.numInteresting++;
- if (isDrawnLw()) {
+ if (isDrawn()) {
results.numDrawn++;
if (!isAnimating(TRANSITION | PARENTS)) {
results.numVisible++;
@@ -5034,7 +5064,7 @@ class WindowState extends WindowContainer<WindowState> implements WindowManagerP
int relayoutVisibleWindow(int result, int attrChanges) {
final boolean wasVisible = isVisibleLw();
- result |= (!wasVisible || !isDrawnLw()) ? RELAYOUT_RES_FIRST_TIME : 0;
+ result |= (!wasVisible || !isDrawn()) ? RELAYOUT_RES_FIRST_TIME : 0;
if (mAnimatingExit) {
Slog.d(TAG, "relayoutVisibleWindow: " + this + " mAnimatingExit=true, mRemoveOnExit="
@@ -5606,15 +5636,14 @@ class WindowState extends WindowContainer<WindowState> implements WindowManagerP
return !mTapExcludeRegion.isEmpty();
}
- @Override
- public boolean isInputMethodTarget() {
+ boolean isInputMethodTarget() {
return getDisplayContent().mInputMethodTarget == this;
}
long getFrameNumber() {
// Return the frame number in which changes requested in this layout will be rendered or
// -1 if we do not expect the frame to be rendered.
- return getFrameLw().isEmpty() ? -1 : mFrameNumber;
+ return getFrame().isEmpty() ? -1 : mFrameNumber;
}
void setFrameNumber(long frameNumber) {
@@ -5677,8 +5706,8 @@ class WindowState extends WindowContainer<WindowState> implements WindowManagerP
return mWindowFrames.mVisibleInsets;
}
- @Override
- public WindowFrames getWindowFrames() {
+ /** Returns the {@link WindowFrames} associated with this {@link WindowState}. */
+ WindowFrames getWindowFrames() {
return mWindowFrames;
}
@@ -5786,7 +5815,7 @@ class WindowState extends WindowContainer<WindowState> implements WindowManagerP
// won't exactly match the final freeform window frame (e.g. when overlapping with
// the status bar). In that case we need to use the final frame.
if (inFreeformWindowingMode()) {
- outFrame.set(getFrameLw());
+ outFrame.set(getFrame());
} else if (isLetterboxedAppWindow() || mToken.isFixedRotationTransforming()) {
// 1. The letterbox surfaces should be animated with the owner activity, so use task
// bounds to include them.
diff --git a/services/core/java/com/android/server/wm/WindowStateAnimator.java b/services/core/java/com/android/server/wm/WindowStateAnimator.java
index 6f483428eaec..1bd712c3638b 100644
--- a/services/core/java/com/android/server/wm/WindowStateAnimator.java
+++ b/services/core/java/com/android/server/wm/WindowStateAnimator.java
@@ -526,13 +526,13 @@ class WindowStateAnimator {
if (DEBUG) {
Slog.v(TAG, "Got surface: " + mSurfaceController
- + ", set left=" + w.getFrameLw().left + " top=" + w.getFrameLw().top);
+ + ", set left=" + w.getFrame().left + " top=" + w.getFrame().top);
}
if (SHOW_LIGHT_TRANSACTIONS) {
Slog.i(TAG, ">>> OPEN TRANSACTION createSurfaceLocked");
WindowManagerService.logSurface(w, "CREATE pos=("
- + w.getFrameLw().left + "," + w.getFrameLw().top + ") ("
+ + w.getFrame().left + "," + w.getFrame().top + ") ("
+ width + "x" + height + ")" + " HIDE", false);
}
@@ -896,7 +896,7 @@ class WindowStateAnimator {
// There is no need to wait for an animation change if our window is gone for layout
// already as we'll never be visible.
- if (w.getOrientationChanging() && w.isGoneForLayoutLw()) {
+ if (w.getOrientationChanging() && w.isGoneForLayout()) {
ProtoLog.v(WM_DEBUG_ORIENTATION, "Orientation change skips hidden %s", w);
w.setOrientationChanging(false);
}
@@ -920,7 +920,7 @@ class WindowStateAnimator {
// really hidden (gone for layout), there is no point in still waiting for it.
// Note that this does introduce a potential glitch if the window becomes unhidden
// before it has drawn for the new orientation.
- if (w.getOrientationChanging() && w.isGoneForLayoutLw()) {
+ if (w.getOrientationChanging() && w.isGoneForLayout()) {
w.setOrientationChanging(false);
ProtoLog.v(WM_DEBUG_ORIENTATION,
"Orientation change skips hidden %s", w);
@@ -998,7 +998,7 @@ class WindowStateAnimator {
}
if (w.getOrientationChanging()) {
- if (!w.isDrawnLw()) {
+ if (!w.isDrawn()) {
mAnimator.mBulkUpdateParams &= ~SET_ORIENTATION_CHANGE_COMPLETE;
mAnimator.mLastWindowFreezeSource = w;
ProtoLog.v(WM_DEBUG_ORIENTATION,
diff --git a/services/core/jni/Android.bp b/services/core/jni/Android.bp
index 4b5f38c40e4f..d84f9d1a7dad 100644
--- a/services/core/jni/Android.bp
+++ b/services/core/jni/Android.bp
@@ -97,6 +97,7 @@ cc_defaults {
"libnativehelper",
"libnativewindow",
"libpowermanager",
+ "libprocessgroup",
"libutils",
"libui",
"libvibratorservice",
diff --git a/services/core/jni/com_android_server_VibratorService.cpp b/services/core/jni/com_android_server_VibratorService.cpp
index b3f3a5e1ff72..9aca84849fc6 100644
--- a/services/core/jni/com_android_server_VibratorService.cpp
+++ b/services/core/jni/com_android_server_VibratorService.cpp
@@ -40,14 +40,12 @@ namespace aidl = android::hardware::vibrator;
namespace android {
static JavaVM* sJvm = nullptr;
-
static jmethodID sMethodIdOnComplete;
-
static struct {
jfieldID id;
jfieldID scale;
jfieldID delay;
-} gPrimitiveClassInfo;
+} sPrimitiveClassInfo;
static_assert(static_cast<uint8_t>(V1_0::EffectStrength::LIGHT) ==
static_cast<uint8_t>(aidl::EffectStrength::LIGHT));
@@ -77,100 +75,117 @@ static_assert(static_cast<uint8_t>(V1_3::Effect::RINGTONE_15) ==
static_assert(static_cast<uint8_t>(V1_3::Effect::TEXTURE_TICK) ==
static_cast<uint8_t>(aidl::Effect::TEXTURE_TICK));
-static inline void callVibrationOnComplete(jobject vibration) {
- if (vibration == nullptr) {
- return;
+class NativeVibratorService {
+public:
+ NativeVibratorService(JNIEnv* env, jobject callbackListener)
+ : mController(std::make_unique<vibrator::HalController>()),
+ mCallbackListener(env->NewGlobalRef(callbackListener)) {
+ LOG_ALWAYS_FATAL_IF(mCallbackListener == nullptr,
+ "Unable to create global reference to vibration callback handler");
}
- auto jniEnv = GetOrAttachJNIEnvironment(sJvm);
- jniEnv->CallVoidMethod(vibration, sMethodIdOnComplete);
- jniEnv->DeleteGlobalRef(vibration);
-}
+
+ ~NativeVibratorService() {
+ auto jniEnv = GetOrAttachJNIEnvironment(sJvm);
+ jniEnv->DeleteGlobalRef(mCallbackListener);
+ }
+
+ vibrator::HalController* controller() const { return mController.get(); }
+
+ std::function<void()> createCallback(jlong vibrationId) {
+ return [vibrationId, this]() {
+ auto jniEnv = GetOrAttachJNIEnvironment(sJvm);
+ jniEnv->CallVoidMethod(mCallbackListener, sMethodIdOnComplete, vibrationId);
+ };
+ }
+
+private:
+ const std::unique_ptr<vibrator::HalController> mController;
+ const jobject mCallbackListener;
+};
static aidl::CompositeEffect effectFromJavaPrimitive(JNIEnv* env, jobject primitive) {
aidl::CompositeEffect effect;
effect.primitive = static_cast<aidl::CompositePrimitive>(
- env->GetIntField(primitive, gPrimitiveClassInfo.id));
- effect.scale = static_cast<float>(env->GetFloatField(primitive, gPrimitiveClassInfo.scale));
- effect.delayMs = static_cast<int32_t>(env->GetIntField(primitive, gPrimitiveClassInfo.delay));
+ env->GetIntField(primitive, sPrimitiveClassInfo.id));
+ effect.scale = static_cast<float>(env->GetFloatField(primitive, sPrimitiveClassInfo.scale));
+ effect.delayMs = static_cast<int32_t>(env->GetIntField(primitive, sPrimitiveClassInfo.delay));
return effect;
}
-static void destroyVibratorController(void* rawVibratorController) {
- vibrator::HalController* vibratorController =
- reinterpret_cast<vibrator::HalController*>(rawVibratorController);
- if (vibratorController) {
- delete vibratorController;
+static void destroyNativeService(void* servicePtr) {
+ NativeVibratorService* service = reinterpret_cast<NativeVibratorService*>(servicePtr);
+ if (service) {
+ delete service;
}
}
-static jlong vibratorInit(JNIEnv* /* env */, jclass /* clazz */) {
- std::unique_ptr<vibrator::HalController> controller =
- std::make_unique<vibrator::HalController>();
- controller->init();
- return reinterpret_cast<jlong>(controller.release());
+static jlong vibratorInit(JNIEnv* env, jclass /* clazz */, jobject callbackListener) {
+ std::unique_ptr<NativeVibratorService> service =
+ std::make_unique<NativeVibratorService>(env, callbackListener);
+ service->controller()->init();
+ return reinterpret_cast<jlong>(service.release());
}
static jlong vibratorGetFinalizer(JNIEnv* /* env */, jclass /* clazz */) {
- return static_cast<jlong>(reinterpret_cast<uintptr_t>(&destroyVibratorController));
+ return static_cast<jlong>(reinterpret_cast<uintptr_t>(&destroyNativeService));
}
-static jboolean vibratorExists(JNIEnv* env, jclass /* clazz */, jlong controllerPtr) {
- vibrator::HalController* controller = reinterpret_cast<vibrator::HalController*>(controllerPtr);
- if (controller == nullptr) {
- ALOGE("vibratorExists failed because controller was not initialized");
+static jboolean vibratorExists(JNIEnv* env, jclass /* clazz */, jlong servicePtr) {
+ NativeVibratorService* service = reinterpret_cast<NativeVibratorService*>(servicePtr);
+ if (service == nullptr) {
+ ALOGE("vibratorExists failed because native service was not initialized");
return JNI_FALSE;
}
- return controller->ping().isOk() ? JNI_TRUE : JNI_FALSE;
+ return service->controller()->ping().isOk() ? JNI_TRUE : JNI_FALSE;
}
-static void vibratorOn(JNIEnv* env, jclass /* clazz */, jlong controllerPtr, jlong timeoutMs,
- jobject vibration) {
- vibrator::HalController* controller = reinterpret_cast<vibrator::HalController*>(controllerPtr);
- if (controller == nullptr) {
- ALOGE("vibratorOn failed because controller was not initialized");
+static void vibratorOn(JNIEnv* env, jclass /* clazz */, jlong servicePtr, jlong timeoutMs,
+ jlong vibrationId) {
+ NativeVibratorService* service = reinterpret_cast<NativeVibratorService*>(servicePtr);
+ if (service == nullptr) {
+ ALOGE("vibratorOn failed because native service was not initialized");
return;
}
- jobject vibrationRef = vibration == nullptr ? vibration : MakeGlobalRefOrDie(env, vibration);
- auto callback = [vibrationRef]() { callVibrationOnComplete(vibrationRef); };
- controller->on(std::chrono::milliseconds(timeoutMs), callback);
+ auto callback = service->createCallback(vibrationId);
+ service->controller()->on(std::chrono::milliseconds(timeoutMs), callback);
}
-static void vibratorOff(JNIEnv* env, jclass /* clazz */, jlong controllerPtr) {
- vibrator::HalController* controller = reinterpret_cast<vibrator::HalController*>(controllerPtr);
- if (controller == nullptr) {
- ALOGE("vibratorOff failed because controller was not initialized");
+static void vibratorOff(JNIEnv* env, jclass /* clazz */, jlong servicePtr) {
+ NativeVibratorService* service = reinterpret_cast<NativeVibratorService*>(servicePtr);
+ if (service == nullptr) {
+ ALOGE("vibratorOff failed because native service was not initialized");
return;
}
- controller->off();
+ service->controller()->off();
}
-static void vibratorSetAmplitude(JNIEnv* env, jclass /* clazz */, jlong controllerPtr,
+static void vibratorSetAmplitude(JNIEnv* env, jclass /* clazz */, jlong servicePtr,
jint amplitude) {
- vibrator::HalController* controller = reinterpret_cast<vibrator::HalController*>(controllerPtr);
- if (controller == nullptr) {
- ALOGE("vibratorSetAmplitude failed because controller was not initialized");
+ NativeVibratorService* service = reinterpret_cast<NativeVibratorService*>(servicePtr);
+ if (service == nullptr) {
+ ALOGE("vibratorSetAmplitude failed because native service was not initialized");
return;
}
- controller->setAmplitude(static_cast<int32_t>(amplitude));
+ service->controller()->setAmplitude(static_cast<int32_t>(amplitude));
}
-static void vibratorSetExternalControl(JNIEnv* env, jclass /* clazz */, jlong controllerPtr,
+static void vibratorSetExternalControl(JNIEnv* env, jclass /* clazz */, jlong servicePtr,
jboolean enabled) {
- vibrator::HalController* controller = reinterpret_cast<vibrator::HalController*>(controllerPtr);
- if (controller == nullptr) {
- ALOGE("vibratorSetExternalControl failed because controller was not initialized");
+ NativeVibratorService* service = reinterpret_cast<NativeVibratorService*>(servicePtr);
+ if (service == nullptr) {
+ ALOGE("vibratorSetExternalControl failed because native service was not initialized");
return;
}
- controller->setExternalControl(enabled);
+ service->controller()->setExternalControl(enabled);
}
-static jintArray vibratorGetSupportedEffects(JNIEnv* env, jclass /* clazz */, jlong controllerPtr) {
- vibrator::HalController* controller = reinterpret_cast<vibrator::HalController*>(controllerPtr);
- if (controller == nullptr) {
- ALOGE("vibratorGetSupportedEffects failed because controller was not initialized");
+static jintArray vibratorGetSupportedEffects(JNIEnv* env, jclass /* clazz */, jlong servicePtr) {
+ NativeVibratorService* service = reinterpret_cast<NativeVibratorService*>(servicePtr);
+ if (service == nullptr) {
+ ALOGE("vibratorGetSupportedEffects failed because native service was not initialized");
return nullptr;
}
- auto result = controller->getSupportedEffects();
+ auto result = service->controller()->getSupportedEffects();
if (!result.isOk()) {
return nullptr;
}
@@ -181,14 +196,13 @@ static jintArray vibratorGetSupportedEffects(JNIEnv* env, jclass /* clazz */, jl
return effects;
}
-static jintArray vibratorGetSupportedPrimitives(JNIEnv* env, jclass /* clazz */,
- jlong controllerPtr) {
- vibrator::HalController* controller = reinterpret_cast<vibrator::HalController*>(controllerPtr);
- if (controller == nullptr) {
- ALOGE("vibratorGetSupportedPrimitives failed because controller was not initialized");
+static jintArray vibratorGetSupportedPrimitives(JNIEnv* env, jclass /* clazz */, jlong servicePtr) {
+ NativeVibratorService* service = reinterpret_cast<NativeVibratorService*>(servicePtr);
+ if (service == nullptr) {
+ ALOGE("vibratorGetSupportedPrimitives failed because native service was not initialized");
return nullptr;
}
- auto result = controller->getSupportedPrimitives();
+ auto result = service->controller()->getSupportedPrimitives();
if (!result.isOk()) {
return nullptr;
}
@@ -199,26 +213,25 @@ static jintArray vibratorGetSupportedPrimitives(JNIEnv* env, jclass /* clazz */,
return primitives;
}
-static jlong vibratorPerformEffect(JNIEnv* env, jclass /* clazz */, jlong controllerPtr,
- jlong effect, jlong strength, jobject vibration) {
- vibrator::HalController* controller = reinterpret_cast<vibrator::HalController*>(controllerPtr);
- if (controller == nullptr) {
- ALOGE("vibratorPerformEffect failed because controller was not initialized");
+static jlong vibratorPerformEffect(JNIEnv* env, jclass /* clazz */, jlong servicePtr, jlong effect,
+ jlong strength, jlong vibrationId) {
+ NativeVibratorService* service = reinterpret_cast<NativeVibratorService*>(servicePtr);
+ if (service == nullptr) {
+ ALOGE("vibratorPerformEffect failed because native service was not initialized");
return -1;
}
aidl::Effect effectType = static_cast<aidl::Effect>(effect);
aidl::EffectStrength effectStrength = static_cast<aidl::EffectStrength>(strength);
- jobject vibrationRef = vibration == nullptr ? vibration : MakeGlobalRefOrDie(env, vibration);
- auto callback = [vibrationRef]() { callVibrationOnComplete(vibrationRef); };
- auto result = controller->performEffect(effectType, effectStrength, callback);
+ auto callback = service->createCallback(vibrationId);
+ auto result = service->controller()->performEffect(effectType, effectStrength, callback);
return result.isOk() ? result.value().count() : -1;
}
-static void vibratorPerformComposedEffect(JNIEnv* env, jclass /* clazz */, jlong controllerPtr,
- jobjectArray composition, jobject vibration) {
- vibrator::HalController* controller = reinterpret_cast<vibrator::HalController*>(controllerPtr);
- if (controller == nullptr) {
- ALOGE("vibratorPerformComposedEffect failed because controller was not initialized");
+static void vibratorPerformComposedEffect(JNIEnv* env, jclass /* clazz */, jlong servicePtr,
+ jobjectArray composition, jlong vibrationId) {
+ NativeVibratorService* service = reinterpret_cast<NativeVibratorService*>(servicePtr);
+ if (service == nullptr) {
+ ALOGE("vibratorPerformComposedEffect failed because native service was not initialized");
return;
}
size_t size = env->GetArrayLength(composition);
@@ -227,54 +240,52 @@ static void vibratorPerformComposedEffect(JNIEnv* env, jclass /* clazz */, jlong
jobject element = env->GetObjectArrayElement(composition, i);
effects.push_back(effectFromJavaPrimitive(env, element));
}
- jobject vibrationRef = vibration == nullptr ? vibration : MakeGlobalRefOrDie(env, vibration);
- auto callback = [vibrationRef]() { callVibrationOnComplete(vibrationRef); };
- controller->performComposedEffect(effects, callback);
+ auto callback = service->createCallback(vibrationId);
+ service->controller()->performComposedEffect(effects, callback);
}
-static jlong vibratorGetCapabilities(JNIEnv* env, jclass /* clazz */, jlong controllerPtr) {
- vibrator::HalController* controller = reinterpret_cast<vibrator::HalController*>(controllerPtr);
- if (controller == nullptr) {
- ALOGE("vibratorGetCapabilities failed because controller was not initialized");
+static jlong vibratorGetCapabilities(JNIEnv* env, jclass /* clazz */, jlong servicePtr) {
+ NativeVibratorService* service = reinterpret_cast<NativeVibratorService*>(servicePtr);
+ if (service == nullptr) {
+ ALOGE("vibratorGetCapabilities failed because native service was not initialized");
return 0;
}
- auto result = controller->getCapabilities();
+ auto result = service->controller()->getCapabilities();
return result.isOk() ? static_cast<jlong>(result.value()) : 0;
}
-static void vibratorAlwaysOnEnable(JNIEnv* env, jclass /* clazz */, jlong controllerPtr, jlong id,
+static void vibratorAlwaysOnEnable(JNIEnv* env, jclass /* clazz */, jlong servicePtr, jlong id,
jlong effect, jlong strength) {
- vibrator::HalController* controller = reinterpret_cast<vibrator::HalController*>(controllerPtr);
- if (controller == nullptr) {
- ALOGE("vibratorAlwaysOnEnable failed because controller was not initialized");
+ NativeVibratorService* service = reinterpret_cast<NativeVibratorService*>(servicePtr);
+ if (service == nullptr) {
+ ALOGE("vibratorAlwaysOnEnable failed because native service was not initialized");
return;
}
- controller->alwaysOnEnable(static_cast<int32_t>(id), static_cast<aidl::Effect>(effect),
- static_cast<aidl::EffectStrength>(strength));
+ service->controller()->alwaysOnEnable(static_cast<int32_t>(id),
+ static_cast<aidl::Effect>(effect),
+ static_cast<aidl::EffectStrength>(strength));
}
-static void vibratorAlwaysOnDisable(JNIEnv* env, jclass /* clazz */, jlong controllerPtr,
- jlong id) {
- vibrator::HalController* controller = reinterpret_cast<vibrator::HalController*>(controllerPtr);
- if (controller == nullptr) {
- ALOGE("vibratorAlwaysOnDisable failed because controller was not initialized");
+static void vibratorAlwaysOnDisable(JNIEnv* env, jclass /* clazz */, jlong servicePtr, jlong id) {
+ NativeVibratorService* service = reinterpret_cast<NativeVibratorService*>(servicePtr);
+ if (service == nullptr) {
+ ALOGE("vibratorAlwaysOnDisable failed because native service was not initialized");
return;
}
- controller->alwaysOnDisable(static_cast<int32_t>(id));
+ service->controller()->alwaysOnDisable(static_cast<int32_t>(id));
}
static const JNINativeMethod method_table[] = {
- {"vibratorInit", "()J", (void*)vibratorInit},
+ {"vibratorInit", "(Lcom/android/server/VibratorService$OnCompleteListener;)J",
+ (void*)vibratorInit},
{"vibratorGetFinalizer", "()J", (void*)vibratorGetFinalizer},
{"vibratorExists", "(J)Z", (void*)vibratorExists},
- {"vibratorOn", "(JJLcom/android/server/VibratorService$Vibration;)V", (void*)vibratorOn},
+ {"vibratorOn", "(JJJ)V", (void*)vibratorOn},
{"vibratorOff", "(J)V", (void*)vibratorOff},
{"vibratorSetAmplitude", "(JI)V", (void*)vibratorSetAmplitude},
- {"vibratorPerformEffect", "(JJJLcom/android/server/VibratorService$Vibration;)J",
- (void*)vibratorPerformEffect},
+ {"vibratorPerformEffect", "(JJJJ)J", (void*)vibratorPerformEffect},
{"vibratorPerformComposedEffect",
- "(J[Landroid/os/VibrationEffect$Composition$PrimitiveEffect;Lcom/android/server/"
- "VibratorService$Vibration;)V",
+ "(J[Landroid/os/VibrationEffect$Composition$PrimitiveEffect;J)V",
(void*)vibratorPerformComposedEffect},
{"vibratorGetSupportedEffects", "(J)[I", (void*)vibratorGetSupportedEffects},
{"vibratorGetSupportedPrimitives", "(J)[I", (void*)vibratorGetSupportedPrimitives},
@@ -284,18 +295,17 @@ static const JNINativeMethod method_table[] = {
{"vibratorAlwaysOnDisable", "(JJ)V", (void*)vibratorAlwaysOnDisable},
};
-int register_android_server_VibratorService(JavaVM* vm, JNIEnv* env) {
- sJvm = vm;
- sMethodIdOnComplete =
- GetMethodIDOrDie(env,
- FindClassOrDie(env, "com/android/server/VibratorService$Vibration"),
- "onComplete", "()V");
+int register_android_server_VibratorService(JavaVM* jvm, JNIEnv* env) {
+ sJvm = jvm;
+ jclass listenerClass =
+ FindClassOrDie(env, "com/android/server/VibratorService$OnCompleteListener");
+ sMethodIdOnComplete = GetMethodIDOrDie(env, listenerClass, "onComplete", "(J)V");
jclass primitiveClass =
FindClassOrDie(env, "android/os/VibrationEffect$Composition$PrimitiveEffect");
- gPrimitiveClassInfo.id = GetFieldIDOrDie(env, primitiveClass, "id", "I");
- gPrimitiveClassInfo.scale = GetFieldIDOrDie(env, primitiveClass, "scale", "F");
- gPrimitiveClassInfo.delay = GetFieldIDOrDie(env, primitiveClass, "delay", "I");
+ sPrimitiveClassInfo.id = GetFieldIDOrDie(env, primitiveClass, "id", "I");
+ sPrimitiveClassInfo.scale = GetFieldIDOrDie(env, primitiveClass, "scale", "F");
+ sPrimitiveClassInfo.delay = GetFieldIDOrDie(env, primitiveClass, "delay", "I");
return jniRegisterNativeMethods(env, "com/android/server/VibratorService", method_table,
NELEM(method_table));
diff --git a/services/core/jni/com_android_server_am_CachedAppOptimizer.cpp b/services/core/jni/com_android_server_am_CachedAppOptimizer.cpp
index 6a6da0e2b395..7e9e11d209a6 100644
--- a/services/core/jni/com_android_server_am_CachedAppOptimizer.cpp
+++ b/services/core/jni/com_android_server_am_CachedAppOptimizer.cpp
@@ -30,6 +30,7 @@
#include <nativehelper/JNIHelp.h>
#include <android_runtime/AndroidRuntime.h>
#include <jni.h>
+#include <processgroup/processgroup.h>
using android::base::StringPrintf;
using android::base::WriteStringToFile;
@@ -74,9 +75,26 @@ static void com_android_server_am_CachedAppOptimizer_compactSystem(JNIEnv *, job
}
}
+static void com_android_server_am_CachedAppOptimizer_enableFreezerInternal(
+ JNIEnv *env, jobject clazz, jboolean enable) {
+ bool success = true;
+
+ if (enable) {
+ success = SetTaskProfiles(0, {"FreezerEnabled"}, true);
+ } else {
+ success = SetTaskProfiles(0, {"FreezerDisabled"}, true);
+ }
+
+ if (!success) {
+ jniThrowException(env, "java/lang/RuntimeException", "Unknown error");
+ }
+}
+
static const JNINativeMethod sMethods[] = {
/* name, signature, funcPtr */
{"compactSystem", "()V", (void*)com_android_server_am_CachedAppOptimizer_compactSystem},
+ {"enableFreezerInternal", "(Z)V",
+ (void*)com_android_server_am_CachedAppOptimizer_enableFreezerInternal},
};
int register_android_server_am_CachedAppOptimizer(JNIEnv* env)
diff --git a/services/core/jni/com_android_server_input_InputManagerService.cpp b/services/core/jni/com_android_server_input_InputManagerService.cpp
index 9751c46f93c9..5dd6cd7b42e9 100644
--- a/services/core/jni/com_android_server_input_InputManagerService.cpp
+++ b/services/core/jni/com_android_server_input_InputManagerService.cpp
@@ -233,7 +233,8 @@ public:
virtual void getReaderConfiguration(InputReaderConfiguration* outConfig);
virtual std::shared_ptr<PointerControllerInterface> obtainPointerController(int32_t deviceId);
virtual void notifyInputDevicesChanged(const std::vector<InputDeviceInfo>& inputDevices);
- virtual sp<KeyCharacterMap> getKeyboardLayoutOverlay(const InputDeviceIdentifier& identifier);
+ virtual std::shared_ptr<KeyCharacterMap> getKeyboardLayoutOverlay(
+ const InputDeviceIdentifier& identifier);
virtual std::string getDeviceAlias(const InputDeviceIdentifier& identifier);
virtual TouchAffineTransformation getTouchAffineTransformation(JNIEnv *env,
jfloatArray matrixArr);
@@ -622,12 +623,12 @@ void NativeInputManager::notifyInputDevicesChanged(const std::vector<InputDevice
checkAndClearExceptionFromCallback(env, "notifyInputDevicesChanged");
}
-sp<KeyCharacterMap> NativeInputManager::getKeyboardLayoutOverlay(
+std::shared_ptr<KeyCharacterMap> NativeInputManager::getKeyboardLayoutOverlay(
const InputDeviceIdentifier& identifier) {
ATRACE_CALL();
JNIEnv* env = jniEnv();
- sp<KeyCharacterMap> result;
+ std::shared_ptr<KeyCharacterMap> result;
ScopedLocalRef<jstring> descriptor(env, env->NewStringUTF(identifier.descriptor.c_str()));
ScopedLocalRef<jobject> identifierObj(env, env->NewObject(gInputDeviceIdentifierInfo.clazz,
gInputDeviceIdentifierInfo.constructor, descriptor.get(),
@@ -642,8 +643,12 @@ sp<KeyCharacterMap> NativeInputManager::getKeyboardLayoutOverlay(
ScopedUtfChars filenameChars(env, filenameObj.get());
ScopedUtfChars contentsChars(env, contentsObj.get());
- KeyCharacterMap::loadContents(filenameChars.c_str(),
- contentsChars.c_str(), KeyCharacterMap::FORMAT_OVERLAY, &result);
+ base::Result<std::shared_ptr<KeyCharacterMap>> ret =
+ KeyCharacterMap::loadContents(filenameChars.c_str(), contentsChars.c_str(),
+ KeyCharacterMap::FORMAT_OVERLAY);
+ if (ret) {
+ result = *ret;
+ }
}
checkAndClearExceptionFromCallback(env, "getKeyboardLayoutOverlay");
return result;
diff --git a/services/core/jni/com_android_server_location_GnssLocationProvider.cpp b/services/core/jni/com_android_server_location_GnssLocationProvider.cpp
index 777cbf410b9b..4e53aa218b71 100644
--- a/services/core/jni/com_android_server_location_GnssLocationProvider.cpp
+++ b/services/core/jni/com_android_server_location_GnssLocationProvider.cpp
@@ -928,7 +928,7 @@ Return<void> GnssCallback::gnssSetSystemInfoCb(const IGnssCallback_V2_0::GnssSys
* GnssPsdsCallback class implements the callback methods for the IGnssPsds
* interface.
*/
-class GnssPsdsCallback : public IGnssPsdsCallback {
+struct GnssPsdsCallback : public IGnssPsdsCallback {
Return<void> downloadRequestCb() override;
Return<void> downloadRequestCb_3_0(int32_t psdsType) override;
};
@@ -2743,19 +2743,26 @@ static void android_location_GnssLocationProvider_inject_location(JNIEnv* /* env
static jboolean android_location_GnssLocationProvider_supports_psds(
JNIEnv* /* env */, jobject /* obj */) {
- return (gnssXtraIface != nullptr) ? JNI_TRUE : JNI_FALSE;
+ return (gnssPsdsIface != nullptr || gnssXtraIface != nullptr) ? JNI_TRUE : JNI_FALSE;
}
static void android_location_GnssLocationProvider_inject_psds_data(JNIEnv* env, jobject /* obj */,
- jbyteArray data, jint length) {
- if (gnssXtraIface == nullptr) {
- ALOGE("%s: IGnssXtra interface not available.", __func__);
+ jbyteArray data, jint length,
+ jint psdsType) {
+ if (gnssPsdsIface == nullptr && gnssXtraIface == nullptr) {
+ ALOGE("%s: IGnssPsds or IGnssXtra interface not available.", __func__);
return;
}
jbyte* bytes = reinterpret_cast<jbyte *>(env->GetPrimitiveArrayCritical(data, 0));
- auto result = gnssXtraIface->injectXtraData(std::string((const char*)bytes, length));
- checkHidlReturn(result, "IGnssXtra injectXtraData() failed.");
+ if (gnssPsdsIface != nullptr) {
+ auto result = gnssPsdsIface->injectPsdsData_3_0(psdsType,
+ std::string((const char*)bytes, length));
+ checkHidlReturn(result, "IGnssPsds injectPsdsData() failed.");
+ } else if (gnssXtraIface != nullptr) {
+ auto result = gnssXtraIface->injectXtraData(std::string((const char*)bytes, length));
+ checkHidlReturn(result, "IGnssXtra injectXtraData() failed.");
+ }
env->ReleasePrimitiveArrayCritical(data, bytes, JNI_ABORT);
}
@@ -3685,7 +3692,7 @@ static const JNINativeMethod sLocationProviderMethods[] = {
reinterpret_cast<void*>(android_location_GnssLocationProvider_inject_location)},
{"native_supports_psds", "()Z",
reinterpret_cast<void*>(android_location_GnssLocationProvider_supports_psds)},
- {"native_inject_psds_data", "([BI)V",
+ {"native_inject_psds_data", "([BII)V",
reinterpret_cast<void*>(android_location_GnssLocationProvider_inject_psds_data)},
{"native_agps_set_id", "(ILjava/lang/String;)V",
reinterpret_cast<void*>(android_location_GnssLocationProvider_agps_set_id)},
diff --git a/services/core/jni/com_android_server_security_VerityUtils.cpp b/services/core/jni/com_android_server_security_VerityUtils.cpp
index 0277f16d5e54..46e6f912edb0 100644
--- a/services/core/jni/com_android_server_security_VerityUtils.cpp
+++ b/services/core/jni/com_android_server_security_VerityUtils.cpp
@@ -33,6 +33,8 @@
#include <android-base/unique_fd.h>
+#include <type_traits>
+
namespace android {
namespace {
@@ -53,7 +55,7 @@ int enableFsverity(JNIEnv* env, jobject /* clazz */, jstring filePath, jbyteArra
fsverity_enable_arg arg = {};
arg.version = 1;
- arg.hash_algorithm = FS_VERITY_HASH_ALG_SHA256;
+ arg.hash_algorithm = FS_VERITY_HASH_ALG_SHA256; // hardcoded in measureFsverity below
arg.block_size = 4096;
arg.salt_size = 0;
arg.salt_ptr = reinterpret_cast<uintptr_t>(nullptr);
@@ -85,9 +87,41 @@ int statxForFsverity(JNIEnv *env, jobject /* clazz */, jstring filePath) {
return (out.stx_attributes & STATX_ATTR_VERITY) != 0;
}
+int measureFsverity(JNIEnv *env, jobject /* clazz */, jstring filePath, jbyteArray digest) {
+ static constexpr auto kDigestSha256 = 32;
+ using Storage = std::aligned_storage_t<sizeof(fsverity_digest) + kDigestSha256>;
+
+ Storage bytes;
+ fsverity_digest *data = reinterpret_cast<fsverity_digest *>(&bytes);
+ data->digest_size = kDigestSha256; // the only input/output parameter
+
+ ScopedUtfChars path(env, filePath);
+ ::android::base::unique_fd rfd(open(path.c_str(), O_RDONLY | O_CLOEXEC));
+ if (rfd.get() < 0) {
+ return rfd.get();
+ }
+ if (auto err = ioctl(rfd.get(), FS_IOC_MEASURE_VERITY, data); err < 0) {
+ return err;
+ }
+
+ if (data->digest_algorithm != FS_VERITY_HASH_ALG_SHA256) {
+ return -EINVAL;
+ }
+
+ if (digest != nullptr && data->digest_size > 0) {
+ auto digestSize = env->GetArrayLength(digest);
+ if (data->digest_size > digestSize) {
+ return -E2BIG;
+ }
+ env->SetByteArrayRegion(digest, 0, data->digest_size, (const jbyte *)data->digest);
+ }
+
+ return 0;
+}
const JNINativeMethod sMethods[] = {
{"enableFsverityNative", "(Ljava/lang/String;[B)I", (void *)enableFsverity},
{"statxForFsverityNative", "(Ljava/lang/String;)I", (void *)statxForFsverity},
+ {"measureFsverityNative", "(Ljava/lang/String;[B)I", (void *)measureFsverity},
};
} // namespace
diff --git a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
index 22e309cdc2b4..80455833a3eb 100644
--- a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
+++ b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
@@ -5782,9 +5782,6 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager {
if (!mHasFeature) {
return;
}
- final CallerIdentity identity = getCallerIdentity();
- Preconditions.checkCallAuthorization(isSystemUid(identity) || isRootUid(identity)
- || hasCallingOrSelfPermission(permission.INTERACT_ACROSS_USERS_FULL));
final ActiveAdmin admin;
synchronized (getLockObject()) {
@@ -9438,8 +9435,7 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager {
Preconditions.checkCallAuthorization(isDeviceOwner(identity));
return mInjector.binderWithCleanCallingIdentity(() -> {
- final List<UserInfo> userInfos = mInjector.getUserManager().getUsers(true
- /*excludeDying*/);
+ final List<UserInfo> userInfos = mInjector.getUserManager().getAliveUsers();
final List<UserHandle> userHandles = new ArrayList<>();
for (UserInfo userInfo : userInfos) {
UserHandle userHandle = userInfo.getUserHandle();
@@ -10362,7 +10358,7 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager {
private void maybeClearLockTaskPolicyLocked() {
mInjector.binderWithCleanCallingIdentity(() -> {
- final List<UserInfo> userInfos = mUserManager.getUsers(/*excludeDying=*/ true);
+ final List<UserInfo> userInfos = mUserManager.getAliveUsers();
for (int i = userInfos.size() - 1; i >= 0; i--) {
int userId = userInfos.get(i).id;
if (canUserUseLockTaskLocked(userId)) {
@@ -10849,7 +10845,7 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager {
* them.
*/
void updateUserSetupCompleteAndPaired() {
- List<UserInfo> users = mUserManager.getUsers(true);
+ List<UserInfo> users = mUserManager.getAliveUsers();
final int N = users.size();
for (int i = 0; i < N; i++) {
int userHandle = users.get(i).id;
@@ -12052,14 +12048,6 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager {
}
@Override
- public boolean isSystemOnlyUser(ComponentName admin) {
- Objects.requireNonNull(admin, "ComponentName is null");
- final CallerIdentity identity = getCallerIdentity(admin);
- Preconditions.checkCallAuthorization(isDeviceOwner(identity));
- return UserManager.isSplitSystemUser() && identity.getUserId() == UserHandle.USER_SYSTEM;
- }
-
- @Override
public void reboot(ComponentName admin) {
Objects.requireNonNull(admin, "ComponentName is null");
final CallerIdentity identity = getCallerIdentity(admin);
@@ -12579,7 +12567,7 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager {
private boolean areAllUsersAffiliatedWithDeviceLocked() {
return mInjector.binderWithCleanCallingIdentity(() -> {
- final List<UserInfo> userInfos = mUserManager.getUsers(/*excludeDying=*/ true);
+ final List<UserInfo> userInfos = mUserManager.getAliveUsers();
for (int i = 0; i < userInfos.size(); i++) {
int userId = userInfos.get(i).id;
if (!isUserAffiliatedWithDeviceLocked(userId)) {
@@ -13048,7 +13036,7 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager {
}
} else {
// Caller is the device owner: Look for profile owners that it can bind to.
- final List<UserInfo> userInfos = mUserManager.getUsers(/*excludeDying=*/ true);
+ final List<UserInfo> userInfos = mUserManager.getAliveUsers();
for (int i = 0; i < userInfos.size(); i++) {
final int userId = userInfos.get(i).id;
if (userId != callingUserId && canUserBindToDeviceOwnerLocked(userId)) {
diff --git a/services/devicepolicy/java/com/android/server/devicepolicy/Owners.java b/services/devicepolicy/java/com/android/server/devicepolicy/Owners.java
index 3cdd482ffa37..7649af4ee911 100644
--- a/services/devicepolicy/java/com/android/server/devicepolicy/Owners.java
+++ b/services/devicepolicy/java/com/android/server/devicepolicy/Owners.java
@@ -169,7 +169,7 @@ class Owners {
// First, try to read from the legacy file.
final File legacy = getLegacyConfigFile();
- final List<UserInfo> users = mUserManager.getUsers(true);
+ final List<UserInfo> users = mUserManager.getAliveUsers();
if (readLegacyOwnerFileLocked(legacy)) {
if (DEBUG) {
diff --git a/services/incremental/Android.bp b/services/incremental/Android.bp
index 7534c7c40a3d..e978ed4000e0 100644
--- a/services/incremental/Android.bp
+++ b/services/incremental/Android.bp
@@ -51,9 +51,9 @@ cc_defaults {
static_libs: [
"libbase",
"libext2_uuid",
- "libdataloader_aidl-cpp",
- "libincremental_aidl-cpp",
- "libincremental_manager_aidl-cpp",
+ "libdataloader_aidl-unstable-cpp",
+ "libincremental_aidl-unstable-cpp",
+ "libincremental_manager_aidl-unstable-cpp",
"libprotobuf-cpp-lite",
"service.incremental.proto",
"libutils",
diff --git a/services/incremental/BinderIncrementalService.cpp b/services/incremental/BinderIncrementalService.cpp
index 0ae10b6dc3b5..87ae4d719d11 100644
--- a/services/incremental/BinderIncrementalService.cpp
+++ b/services/incremental/BinderIncrementalService.cpp
@@ -237,11 +237,16 @@ binder::Status BinderIncrementalService::unlink(int32_t storageId, const std::st
return ok();
}
-binder::Status BinderIncrementalService::isFileRangeLoaded(int32_t storageId,
- const std::string& path, int64_t start,
- int64_t end, bool* _aidl_return) {
- // TODO: implement
- *_aidl_return = false;
+binder::Status BinderIncrementalService::isFileFullyLoaded(int32_t storageId,
+ const std::string& path,
+ int32_t* _aidl_return) {
+ *_aidl_return = mImpl.isFileFullyLoaded(storageId, path);
+ return ok();
+}
+
+binder::Status BinderIncrementalService::getLoadingProgress(int32_t storageId,
+ float* _aidl_return) {
+ *_aidl_return = mImpl.getLoadingProgress(storageId);
return ok();
}
diff --git a/services/incremental/BinderIncrementalService.h b/services/incremental/BinderIncrementalService.h
index 10154946d3ee..8478142b2d95 100644
--- a/services/incremental/BinderIncrementalService.h
+++ b/services/incremental/BinderIncrementalService.h
@@ -66,8 +66,9 @@ public:
int32_t destStorageId, const std::string& destPath,
int32_t* _aidl_return) final;
binder::Status unlink(int32_t storageId, const std::string& path, int32_t* _aidl_return) final;
- binder::Status isFileRangeLoaded(int32_t storageId, const std::string& path, int64_t start,
- int64_t end, bool* _aidl_return) final;
+ binder::Status isFileFullyLoaded(int32_t storageId, const std::string& path,
+ int32_t* _aidl_return) final;
+ binder::Status getLoadingProgress(int32_t storageId, float* _aidl_return) final;
binder::Status getMetadataByPath(int32_t storageId, const std::string& path,
std::vector<uint8_t>* _aidl_return) final;
binder::Status getMetadataById(int32_t storageId, const std::vector<uint8_t>& id,
diff --git a/services/incremental/IncrementalService.cpp b/services/incremental/IncrementalService.cpp
index f7082a9a1a0c..447ee552a335 100644
--- a/services/incremental/IncrementalService.cpp
+++ b/services/incremental/IncrementalService.cpp
@@ -37,7 +37,6 @@
#include "Metadata.pb.h"
using namespace std::literals;
-namespace fs = std::filesystem;
constexpr const char* kDataUsageStats = "android.permission.LOADER_USAGE_STATS";
constexpr const char* kOpUsage = "android:loader_usage_stats";
@@ -276,6 +275,7 @@ IncrementalService::IncrementalService(ServiceManagerWrapper&& sm, std::string_v
mJni(sm.getJni()),
mLooper(sm.getLooper()),
mTimedQueue(sm.getTimedQueue()),
+ mFs(sm.getFs()),
mIncrementalDir(rootDir) {
CHECK(mVold) << "Vold service is unavailable";
CHECK(mDataLoaderManager) << "DataLoaderManagerService is unavailable";
@@ -283,6 +283,7 @@ IncrementalService::IncrementalService(ServiceManagerWrapper&& sm, std::string_v
CHECK(mJni) << "JNI is unavailable";
CHECK(mLooper) << "Looper is unavailable";
CHECK(mTimedQueue) << "TimedQueue is unavailable";
+ CHECK(mFs) << "Fs is unavailable";
mJobQueue.reserve(16);
mJobProcessor = std::thread([this]() {
@@ -344,7 +345,8 @@ void IncrementalService::onDump(int fd) {
}
dprintf(fd, " storages (%d): {\n", int(mnt.storages.size()));
for (auto&& [storageId, storage] : mnt.storages) {
- dprintf(fd, " [%d] -> [%s]\n", storageId, storage.name.c_str());
+ dprintf(fd, " [%d] -> [%s] (%d %% loaded) \n", storageId, storage.name.c_str(),
+ (int)(getLoadingProgressFromPath(mnt, storage.name.c_str()) * 100));
}
dprintf(fd, " }\n");
@@ -1601,7 +1603,8 @@ void IncrementalService::extractZipFile(const IfsMountPtr& ifs, ZipArchiveHandle
const auto writeFd = mIncFs->openForSpecialOps(ifs->control, libFileId);
if (!writeFd.ok()) {
- LOG(ERROR) << "Failed to open write fd for: " << targetLibPath << " errno: " << writeFd;
+ LOG(ERROR) << "Failed to open write fd for: " << targetLibPath
+ << " errno: " << writeFd.get();
return;
}
@@ -1671,6 +1674,76 @@ bool IncrementalService::waitForNativeBinariesExtraction(StorageId storage) {
return mRunning;
}
+int IncrementalService::isFileFullyLoaded(StorageId storage, const std::string& path) const {
+ std::unique_lock l(mLock);
+ const auto ifs = getIfsLocked(storage);
+ if (!ifs) {
+ LOG(ERROR) << "isFileFullyLoaded failed, invalid storageId: " << storage;
+ return -EINVAL;
+ }
+ const auto storageInfo = ifs->storages.find(storage);
+ if (storageInfo == ifs->storages.end()) {
+ LOG(ERROR) << "isFileFullyLoaded failed, no storage: " << storage;
+ return -EINVAL;
+ }
+ l.unlock();
+ return isFileFullyLoadedFromPath(*ifs, path);
+}
+
+int IncrementalService::isFileFullyLoadedFromPath(const IncFsMount& ifs,
+ std::string_view filePath) const {
+ const auto [filledBlocks, totalBlocks] = mIncFs->countFilledBlocks(ifs.control, filePath);
+ if (filledBlocks < 0) {
+ LOG(ERROR) << "isFileFullyLoadedFromPath failed to get filled blocks count for: "
+ << filePath << " errno: " << filledBlocks;
+ return filledBlocks;
+ }
+ if (totalBlocks < filledBlocks) {
+ LOG(ERROR) << "isFileFullyLoadedFromPath failed to get total num of blocks";
+ return -EINVAL;
+ }
+ return totalBlocks - filledBlocks;
+}
+
+float IncrementalService::getLoadingProgress(StorageId storage) const {
+ std::unique_lock l(mLock);
+ const auto ifs = getIfsLocked(storage);
+ if (!ifs) {
+ LOG(ERROR) << "getLoadingProgress failed, invalid storageId: " << storage;
+ return -EINVAL;
+ }
+ const auto storageInfo = ifs->storages.find(storage);
+ if (storageInfo == ifs->storages.end()) {
+ LOG(ERROR) << "getLoadingProgress failed, no storage: " << storage;
+ return -EINVAL;
+ }
+ l.unlock();
+ return getLoadingProgressFromPath(*ifs, storageInfo->second.name);
+}
+
+float IncrementalService::getLoadingProgressFromPath(const IncFsMount& ifs,
+ std::string_view storagePath) const {
+ size_t totalBlocks = 0, filledBlocks = 0;
+ const auto filePaths = mFs->listFilesRecursive(storagePath);
+ for (const auto& filePath : filePaths) {
+ const auto [filledBlocksCount, totalBlocksCount] =
+ mIncFs->countFilledBlocks(ifs.control, filePath);
+ if (filledBlocksCount < 0) {
+ LOG(ERROR) << "getLoadingProgress failed to get filled blocks count for: " << filePath
+ << " errno: " << filledBlocksCount;
+ return filledBlocksCount;
+ }
+ totalBlocks += totalBlocksCount;
+ filledBlocks += filledBlocksCount;
+ }
+
+ if (totalBlocks == 0) {
+ // No file in the storage or files are empty; regarded as fully loaded
+ return 1;
+ }
+ return (float)filledBlocks / (float)totalBlocks;
+}
+
bool IncrementalService::perfLoggingEnabled() {
static const bool enabled = base::GetBoolProperty("incremental.perflogging", false);
return enabled;
@@ -2029,11 +2102,13 @@ void IncrementalService::DataLoaderStub::updateHealthStatus(bool baseline) {
// Healthcheck depends on timestamp of the oldest pending read.
// To get it, we need to re-open a pendingReads FD to get a full list of reads.
- // Additionally we need to re-register for epoll with fresh FDs in case there are no reads.
+ // Additionally we need to re-register for epoll with fresh FDs in case there are no
+ // reads.
const auto now = Clock::now();
const auto kernelTsUs = getOldestPendingReadTs();
if (baseline) {
- // Updating baseline only on looper/epoll callback, i.e. on new set of pending reads.
+ // Updating baseline only on looper/epoll callback, i.e. on new set of pending
+ // reads.
mHealthBase = {now, kernelTsUs};
}
diff --git a/services/incremental/IncrementalService.h b/services/incremental/IncrementalService.h
index a6cc94639c8a..267458d8769c 100644
--- a/services/incremental/IncrementalService.h
+++ b/services/incremental/IncrementalService.h
@@ -132,9 +132,8 @@ public:
std::string_view newPath);
int unlink(StorageId storage, std::string_view path);
- bool isRangeLoaded(StorageId storage, FileId file, std::pair<BlockIndex, BlockIndex> range) {
- return false;
- }
+ int isFileFullyLoaded(StorageId storage, const std::string& path) const;
+ float getLoadingProgress(StorageId storage) const;
RawMetadata getMetadata(StorageId storage, std::string_view path) const;
RawMetadata getMetadata(StorageId storage, FileId node) const;
@@ -341,6 +340,9 @@ private:
int makeDirs(const IncFsMount& ifs, StorageId storageId, std::string_view path, int mode);
binder::Status applyStorageParams(IncFsMount& ifs, bool enableReadLogs);
+ int isFileFullyLoadedFromPath(const IncFsMount& ifs, std::string_view filePath) const;
+ float getLoadingProgressFromPath(const IncFsMount& ifs, std::string_view path) const;
+
void registerAppOpsCallback(const std::string& packageName);
bool unregisterAppOpsCallback(const std::string& packageName);
void onAppOpChanged(const std::string& packageName);
@@ -363,6 +365,7 @@ private:
const std::unique_ptr<JniWrapper> mJni;
const std::unique_ptr<LooperWrapper> mLooper;
const std::unique_ptr<TimedQueueWrapper> mTimedQueue;
+ const std::unique_ptr<FsWrapper> mFs;
const std::string mIncrementalDir;
mutable std::mutex mLock;
diff --git a/services/incremental/ServiceWrappers.cpp b/services/incremental/ServiceWrappers.cpp
index 99a35adb5074..f6d89c53be32 100644
--- a/services/incremental/ServiceWrappers.cpp
+++ b/services/incremental/ServiceWrappers.cpp
@@ -25,6 +25,7 @@
#include <binder/AppOpsManager.h>
#include <utils/String16.h>
+#include <filesystem>
#include <thread>
#include "IncrementalServiceValidation.h"
@@ -165,14 +166,37 @@ public:
FileId getFileId(const Control& control, std::string_view path) const final {
return incfs::getFileId(control, path);
}
+ std::pair<IncFsBlockIndex, IncFsBlockIndex> countFilledBlocks(
+ const Control& control, std::string_view path) const final {
+ const auto fileId = incfs::getFileId(control, path);
+ const auto fd = incfs::openForSpecialOps(control, fileId);
+ int res = fd.get();
+ if (!fd.ok()) {
+ return {res, res};
+ }
+ const auto ranges = incfs::getFilledRanges(res);
+ res = ranges.first;
+ if (res) {
+ return {res, res};
+ }
+ const auto totalBlocksCount = ranges.second.internalRawRanges().endIndex;
+ int filledBlockCount = 0;
+ for (const auto& dataRange : ranges.second.dataRanges()) {
+ filledBlockCount += dataRange.size();
+ }
+ for (const auto& hashRange : ranges.second.hashRanges()) {
+ filledBlockCount += hashRange.size();
+ }
+ return {filledBlockCount, totalBlocksCount};
+ }
ErrorCode link(const Control& control, std::string_view from, std::string_view to) const final {
return incfs::link(control, from, to);
}
ErrorCode unlink(const Control& control, std::string_view path) const final {
return incfs::unlink(control, path);
}
- base::unique_fd openForSpecialOps(const Control& control, FileId id) const final {
- return base::unique_fd{incfs::openForSpecialOps(control, id).release()};
+ incfs::UniqueFd openForSpecialOps(const Control& control, FileId id) const final {
+ return incfs::openForSpecialOps(control, id);
}
ErrorCode writeBlocks(std::span<const incfs::DataBlock> blocks) const final {
return incfs::writeBlocks({blocks.data(), size_t(blocks.size())});
@@ -265,6 +289,23 @@ private:
std::thread mThread;
};
+class RealFsWrapper : public FsWrapper {
+public:
+ RealFsWrapper() = default;
+ ~RealFsWrapper() = default;
+
+ std::vector<std::string> listFilesRecursive(std::string_view directoryPath) const final {
+ std::vector<std::string> files;
+ for (const auto& entry : std::filesystem::recursive_directory_iterator(directoryPath)) {
+ if (!entry.is_regular_file()) {
+ continue;
+ }
+ files.push_back(entry.path().c_str());
+ }
+ return files;
+ }
+};
+
RealServiceManager::RealServiceManager(sp<IServiceManager> serviceManager, JNIEnv* env)
: mServiceManager(std::move(serviceManager)), mJvm(RealJniWrapper::getJvm(env)) {}
@@ -316,6 +357,10 @@ std::unique_ptr<TimedQueueWrapper> RealServiceManager::getTimedQueue() {
return std::make_unique<RealTimedQueueWrapper>(mJvm);
}
+std::unique_ptr<FsWrapper> RealServiceManager::getFs() {
+ return std::make_unique<RealFsWrapper>();
+}
+
static JavaVM* getJavaVm(JNIEnv* env) {
CHECK(env);
JavaVM* jvm = nullptr;
diff --git a/services/incremental/ServiceWrappers.h b/services/incremental/ServiceWrappers.h
index 8cd726fdc0f1..6376d86543f8 100644
--- a/services/incremental/ServiceWrappers.h
+++ b/services/incremental/ServiceWrappers.h
@@ -74,6 +74,7 @@ public:
using Control = incfs::Control;
using FileId = incfs::FileId;
using ErrorCode = incfs::ErrorCode;
+ using UniqueFd = incfs::UniqueFd;
using WaitResult = incfs::WaitResult;
using ExistingMountCallback =
@@ -91,10 +92,12 @@ public:
virtual incfs::RawMetadata getMetadata(const Control& control, FileId fileid) const = 0;
virtual incfs::RawMetadata getMetadata(const Control& control, std::string_view path) const = 0;
virtual FileId getFileId(const Control& control, std::string_view path) const = 0;
+ virtual std::pair<IncFsBlockIndex, IncFsBlockIndex> countFilledBlocks(
+ const Control& control, std::string_view path) const = 0;
virtual ErrorCode link(const Control& control, std::string_view from,
std::string_view to) const = 0;
virtual ErrorCode unlink(const Control& control, std::string_view path) const = 0;
- virtual base::unique_fd openForSpecialOps(const Control& control, FileId id) const = 0;
+ virtual UniqueFd openForSpecialOps(const Control& control, FileId id) const = 0;
virtual ErrorCode writeBlocks(std::span<const incfs::DataBlock> blocks) const = 0;
virtual WaitResult waitForPendingReads(
const Control& control, std::chrono::milliseconds timeout,
@@ -106,7 +109,8 @@ public:
virtual ~AppOpsManagerWrapper() = default;
virtual binder::Status checkPermission(const char* permission, const char* operation,
const char* package) const = 0;
- virtual void startWatchingMode(int32_t op, const String16& packageName, const sp<IAppOpsCallback>& callback) = 0;
+ virtual void startWatchingMode(int32_t op, const String16& packageName,
+ const sp<IAppOpsCallback>& callback) = 0;
virtual void stopWatchingMode(const sp<IAppOpsCallback>& callback) = 0;
};
@@ -134,6 +138,12 @@ public:
virtual void stop() = 0;
};
+class FsWrapper {
+public:
+ virtual ~FsWrapper() = default;
+ virtual std::vector<std::string> listFilesRecursive(std::string_view directoryPath) const = 0;
+};
+
class ServiceManagerWrapper {
public:
virtual ~ServiceManagerWrapper() = default;
@@ -144,6 +154,7 @@ public:
virtual std::unique_ptr<JniWrapper> getJni() = 0;
virtual std::unique_ptr<LooperWrapper> getLooper() = 0;
virtual std::unique_ptr<TimedQueueWrapper> getTimedQueue() = 0;
+ virtual std::unique_ptr<FsWrapper> getFs() = 0;
};
// --- Real stuff ---
@@ -159,6 +170,7 @@ public:
std::unique_ptr<JniWrapper> getJni() final;
std::unique_ptr<LooperWrapper> getLooper() final;
std::unique_ptr<TimedQueueWrapper> getTimedQueue() final;
+ std::unique_ptr<FsWrapper> getFs() final;
private:
template <class INTERFACE>
diff --git a/services/incremental/test/IncrementalServiceTest.cpp b/services/incremental/test/IncrementalServiceTest.cpp
index 1ae9e256c9f4..a290a1791481 100644
--- a/services/incremental/test/IncrementalServiceTest.cpp
+++ b/services/incremental/test/IncrementalServiceTest.cpp
@@ -54,8 +54,10 @@ public:
MOCK_CONST_METHOD1(unmountIncFs, binder::Status(const std::string& dir));
MOCK_CONST_METHOD2(bindMount,
binder::Status(const std::string& sourceDir, const std::string& argetDir));
- MOCK_CONST_METHOD2(setIncFsMountOptions,
- binder::Status(const ::android::os::incremental::IncrementalFileSystemControlParcel&, bool));
+ MOCK_CONST_METHOD2(
+ setIncFsMountOptions,
+ binder::Status(const ::android::os::incremental::IncrementalFileSystemControlParcel&,
+ bool));
void mountIncFsFails() {
ON_CALL(*this, mountIncFs(_, _, _, _))
@@ -80,8 +82,8 @@ public:
}
void setIncFsMountOptionsFails() const {
ON_CALL(*this, setIncFsMountOptions(_, _))
- .WillByDefault(
- Return(binder::Status::fromExceptionCode(1, String8("failed to set options"))));
+ .WillByDefault(Return(
+ binder::Status::fromExceptionCode(1, String8("failed to set options"))));
}
void setIncFsMountOptionsSuccess() {
ON_CALL(*this, setIncFsMountOptions(_, _)).WillByDefault(Return(binder::Status::ok()));
@@ -280,10 +282,14 @@ public:
MOCK_CONST_METHOD2(getMetadata, RawMetadata(const Control& control, FileId fileid));
MOCK_CONST_METHOD2(getMetadata, RawMetadata(const Control& control, std::string_view path));
MOCK_CONST_METHOD2(getFileId, FileId(const Control& control, std::string_view path));
+ MOCK_CONST_METHOD2(countFilledBlocks,
+ std::pair<IncFsBlockIndex, IncFsBlockIndex>(const Control& control,
+ std::string_view path));
MOCK_CONST_METHOD3(link,
- ErrorCode(const Control& control, std::string_view from, std::string_view to));
+ ErrorCode(const Control& control, std::string_view from,
+ std::string_view to));
MOCK_CONST_METHOD2(unlink, ErrorCode(const Control& control, std::string_view path));
- MOCK_CONST_METHOD2(openForSpecialOps, base::unique_fd(const Control& control, FileId id));
+ MOCK_CONST_METHOD2(openForSpecialOps, UniqueFd(const Control& control, FileId id));
MOCK_CONST_METHOD1(writeBlocks, ErrorCode(std::span<const DataBlock> blocks));
MOCK_CONST_METHOD3(waitForPendingReads,
WaitResult(const Control& control, std::chrono::milliseconds timeout,
@@ -293,6 +299,23 @@ public:
void makeFileFails() { ON_CALL(*this, makeFile(_, _, _, _, _)).WillByDefault(Return(-1)); }
void makeFileSuccess() { ON_CALL(*this, makeFile(_, _, _, _, _)).WillByDefault(Return(0)); }
+
+ void countFilledBlocksSuccess() {
+ ON_CALL(*this, countFilledBlocks(_, _)).WillByDefault(Return(std::make_pair(1, 2)));
+ }
+
+ void countFilledBlocksFullyLoaded() {
+ ON_CALL(*this, countFilledBlocks(_, _)).WillByDefault(Return(std::make_pair(10000, 10000)));
+ }
+
+ void countFilledBlocksFails() {
+ ON_CALL(*this, countFilledBlocks(_, _)).WillByDefault(Return(std::make_pair(-1, -1)));
+ }
+
+ void countFilledBlocksEmpty() {
+ ON_CALL(*this, countFilledBlocks(_, _)).WillByDefault(Return(std::make_pair(0, 0)));
+ }
+
void openMountSuccess() {
ON_CALL(*this, openMount(_)).WillByDefault(Invoke(this, &MockIncFs::openMountForHealth));
}
@@ -447,6 +470,21 @@ public:
Job mWhat;
};
+class MockFsWrapper : public FsWrapper {
+public:
+ MOCK_CONST_METHOD1(listFilesRecursive, std::vector<std::string>(std::string_view));
+ void hasNoFile() {
+ ON_CALL(*this, listFilesRecursive(_)).WillByDefault(Return(std::vector<std::string>()));
+ }
+ void hasFiles() {
+ ON_CALL(*this, listFilesRecursive(_))
+ .WillByDefault(Invoke(this, &MockFsWrapper::fakeFiles));
+ }
+ std::vector<std::string> fakeFiles(std::string_view directoryPath) {
+ return {"base.apk", "split.apk", "lib/a.so"};
+ }
+};
+
class MockStorageHealthListener : public os::incremental::BnStorageHealthListener {
public:
MOCK_METHOD2(onHealthStatus, binder::Status(int32_t storageId, int32_t status));
@@ -474,23 +512,28 @@ public:
std::unique_ptr<MockAppOpsManager> appOpsManager,
std::unique_ptr<MockJniWrapper> jni,
std::unique_ptr<MockLooperWrapper> looper,
- std::unique_ptr<MockTimedQueueWrapper> timedQueue)
+ std::unique_ptr<MockTimedQueueWrapper> timedQueue,
+ std::unique_ptr<MockFsWrapper> fs)
: mVold(std::move(vold)),
mDataLoaderManager(std::move(dataLoaderManager)),
mIncFs(std::move(incfs)),
mAppOpsManager(std::move(appOpsManager)),
mJni(std::move(jni)),
mLooper(std::move(looper)),
- mTimedQueue(std::move(timedQueue)) {}
+ mTimedQueue(std::move(timedQueue)),
+ mFs(std::move(fs)) {}
std::unique_ptr<VoldServiceWrapper> getVoldService() final { return std::move(mVold); }
std::unique_ptr<DataLoaderManagerWrapper> getDataLoaderManager() final {
return std::move(mDataLoaderManager);
}
std::unique_ptr<IncFsWrapper> getIncFs() final { return std::move(mIncFs); }
- std::unique_ptr<AppOpsManagerWrapper> getAppOpsManager() final { return std::move(mAppOpsManager); }
+ std::unique_ptr<AppOpsManagerWrapper> getAppOpsManager() final {
+ return std::move(mAppOpsManager);
+ }
std::unique_ptr<JniWrapper> getJni() final { return std::move(mJni); }
std::unique_ptr<LooperWrapper> getLooper() final { return std::move(mLooper); }
std::unique_ptr<TimedQueueWrapper> getTimedQueue() final { return std::move(mTimedQueue); }
+ std::unique_ptr<FsWrapper> getFs() final { return std::move(mFs); }
private:
std::unique_ptr<MockVoldService> mVold;
@@ -500,6 +543,7 @@ private:
std::unique_ptr<MockJniWrapper> mJni;
std::unique_ptr<MockLooperWrapper> mLooper;
std::unique_ptr<MockTimedQueueWrapper> mTimedQueue;
+ std::unique_ptr<MockFsWrapper> mFs;
};
// --- IncrementalServiceTest ---
@@ -523,6 +567,8 @@ public:
mLooper = looper.get();
auto timedQueue = std::make_unique<NiceMock<MockTimedQueueWrapper>>();
mTimedQueue = timedQueue.get();
+ auto fs = std::make_unique<NiceMock<MockFsWrapper>>();
+ mFs = fs.get();
mIncrementalService =
std::make_unique<IncrementalService>(MockServiceManager(std::move(vold),
std::move(
@@ -531,12 +577,14 @@ public:
std::move(appOps),
std::move(jni),
std::move(looper),
- std::move(timedQueue)),
+ std::move(timedQueue),
+ std::move(fs)),
mRootDir.path);
mDataLoaderParcel.packageName = "com.test";
mDataLoaderParcel.arguments = "uri";
mDataLoaderManager->unbindFromDataLoaderSuccess();
mIncrementalService->onSystemReady();
+ setupSuccess();
}
void setUpExistingMountDir(const std::string& rootDir) {
@@ -560,6 +608,14 @@ public:
.WillByDefault(Invoke(mIncFs, &MockIncFs::getStorageMetadata));
}
+ void setupSuccess() {
+ mVold->mountIncFsSuccess();
+ mIncFs->makeFileSuccess();
+ mVold->bindMountSuccess();
+ mDataLoaderManager->bindToDataLoaderSuccess();
+ mDataLoaderManager->getDataLoaderSuccess();
+ }
+
protected:
NiceMock<MockVoldService>* mVold = nullptr;
NiceMock<MockIncFs>* mIncFs = nullptr;
@@ -568,6 +624,7 @@ protected:
NiceMock<MockJniWrapper>* mJni = nullptr;
NiceMock<MockLooperWrapper>* mLooper = nullptr;
NiceMock<MockTimedQueueWrapper>* mTimedQueue = nullptr;
+ NiceMock<MockFsWrapper>* mFs = nullptr;
NiceMock<MockDataLoader>* mDataLoader = nullptr;
std::unique_ptr<IncrementalService> mIncrementalService;
TemporaryDir mRootDir;
@@ -641,11 +698,6 @@ TEST_F(IncrementalServiceTest, testCreateStoragePrepareDataLoaderFails) {
}
TEST_F(IncrementalServiceTest, testDeleteStorageSuccess) {
- mVold->mountIncFsSuccess();
- mIncFs->makeFileSuccess();
- mVold->bindMountSuccess();
- mDataLoaderManager->bindToDataLoaderSuccess();
- mDataLoaderManager->getDataLoaderSuccess();
EXPECT_CALL(*mDataLoaderManager, bindToDataLoader(_, _, _, _)).Times(1);
EXPECT_CALL(*mDataLoaderManager, unbindFromDataLoader(_)).Times(1);
EXPECT_CALL(*mDataLoader, create(_, _, _, _)).Times(1);
@@ -661,11 +713,6 @@ TEST_F(IncrementalServiceTest, testDeleteStorageSuccess) {
}
TEST_F(IncrementalServiceTest, testDataLoaderDestroyed) {
- mVold->mountIncFsSuccess();
- mIncFs->makeFileSuccess();
- mVold->bindMountSuccess();
- mDataLoaderManager->bindToDataLoaderSuccess();
- mDataLoaderManager->getDataLoaderSuccess();
EXPECT_CALL(*mDataLoaderManager, bindToDataLoader(_, _, _, _)).Times(2);
EXPECT_CALL(*mDataLoaderManager, unbindFromDataLoader(_)).Times(1);
EXPECT_CALL(*mDataLoader, create(_, _, _, _)).Times(2);
@@ -682,12 +729,7 @@ TEST_F(IncrementalServiceTest, testDataLoaderDestroyed) {
}
TEST_F(IncrementalServiceTest, testStartDataLoaderCreate) {
- mVold->mountIncFsSuccess();
- mIncFs->makeFileSuccess();
- mVold->bindMountSuccess();
mDataLoader->initializeCreateOkNoStatus();
- mDataLoaderManager->bindToDataLoaderSuccess();
- mDataLoaderManager->getDataLoaderSuccess();
EXPECT_CALL(*mDataLoaderManager, bindToDataLoader(_, _, _, _)).Times(1);
EXPECT_CALL(*mDataLoaderManager, unbindFromDataLoader(_)).Times(1);
EXPECT_CALL(*mDataLoader, create(_, _, _, _)).Times(1);
@@ -705,12 +747,7 @@ TEST_F(IncrementalServiceTest, testStartDataLoaderCreate) {
}
TEST_F(IncrementalServiceTest, testStartDataLoaderPendingStart) {
- mVold->mountIncFsSuccess();
- mIncFs->makeFileSuccess();
- mVold->bindMountSuccess();
mDataLoader->initializeCreateOkNoStatus();
- mDataLoaderManager->bindToDataLoaderSuccess();
- mDataLoaderManager->getDataLoaderSuccess();
EXPECT_CALL(*mDataLoaderManager, bindToDataLoader(_, _, _, _)).Times(1);
EXPECT_CALL(*mDataLoaderManager, unbindFromDataLoader(_)).Times(1);
EXPECT_CALL(*mDataLoader, create(_, _, _, _)).Times(2);
@@ -727,12 +764,7 @@ TEST_F(IncrementalServiceTest, testStartDataLoaderPendingStart) {
}
TEST_F(IncrementalServiceTest, testStartDataLoaderCreateUnavailable) {
- mVold->mountIncFsSuccess();
- mIncFs->makeFileSuccess();
- mVold->bindMountSuccess();
mDataLoader->initializeCreateOkNoStatus();
- mDataLoaderManager->bindToDataLoaderSuccess();
- mDataLoaderManager->getDataLoaderSuccess();
EXPECT_CALL(*mDataLoaderManager, bindToDataLoader(_, _, _, _)).Times(1);
EXPECT_CALL(*mDataLoaderManager, unbindFromDataLoader(_)).Times(1);
EXPECT_CALL(*mDataLoader, create(_, _, _, _)).Times(1);
@@ -748,14 +780,10 @@ TEST_F(IncrementalServiceTest, testStartDataLoaderCreateUnavailable) {
}
TEST_F(IncrementalServiceTest, testStartDataLoaderRecreateOnPendingReads) {
- mVold->mountIncFsSuccess();
- mIncFs->makeFileSuccess();
- mIncFs->openMountSuccess();
mIncFs->waitForPendingReadsSuccess();
- mVold->bindMountSuccess();
+ mIncFs->openMountSuccess();
mDataLoader->initializeCreateOkNoStatus();
- mDataLoaderManager->bindToDataLoaderSuccess();
- mDataLoaderManager->getDataLoaderSuccess();
+
EXPECT_CALL(*mDataLoaderManager, bindToDataLoader(_, _, _, _)).Times(2);
EXPECT_CALL(*mDataLoaderManager, unbindFromDataLoader(_)).Times(2);
EXPECT_CALL(*mDataLoader, create(_, _, _, _)).Times(2);
@@ -776,12 +804,8 @@ TEST_F(IncrementalServiceTest, testStartDataLoaderRecreateOnPendingReads) {
}
TEST_F(IncrementalServiceTest, testStartDataLoaderUnhealthyStorage) {
- mVold->mountIncFsSuccess();
- mIncFs->makeFileSuccess();
mIncFs->openMountSuccess();
- mVold->bindMountSuccess();
- mDataLoaderManager->bindToDataLoaderSuccess();
- mDataLoaderManager->getDataLoaderSuccess();
+
EXPECT_CALL(*mDataLoaderManager, bindToDataLoader(_, _, _, _)).Times(1);
EXPECT_CALL(*mDataLoaderManager, unbindFromDataLoader(_)).Times(1);
EXPECT_CALL(*mDataLoader, create(_, _, _, _)).Times(1);
@@ -906,13 +930,9 @@ TEST_F(IncrementalServiceTest, testStartDataLoaderUnhealthyStorage) {
}
TEST_F(IncrementalServiceTest, testSetIncFsMountOptionsSuccess) {
- mVold->mountIncFsSuccess();
- mIncFs->makeFileSuccess();
- mVold->bindMountSuccess();
mVold->setIncFsMountOptionsSuccess();
- mDataLoaderManager->bindToDataLoaderSuccess();
- mDataLoaderManager->getDataLoaderSuccess();
mAppOpsManager->checkPermissionSuccess();
+
EXPECT_CALL(*mDataLoaderManager, unbindFromDataLoader(_));
EXPECT_CALL(*mVold, unmountIncFs(_)).Times(2);
// We are calling setIncFsMountOptions(true).
@@ -930,13 +950,9 @@ TEST_F(IncrementalServiceTest, testSetIncFsMountOptionsSuccess) {
}
TEST_F(IncrementalServiceTest, testSetIncFsMountOptionsSuccessAndDisabled) {
- mVold->mountIncFsSuccess();
- mIncFs->makeFileSuccess();
- mVold->bindMountSuccess();
mVold->setIncFsMountOptionsSuccess();
- mDataLoaderManager->bindToDataLoaderSuccess();
- mDataLoaderManager->getDataLoaderSuccess();
mAppOpsManager->checkPermissionSuccess();
+
EXPECT_CALL(*mDataLoaderManager, unbindFromDataLoader(_));
EXPECT_CALL(*mVold, unmountIncFs(_)).Times(2);
// Enabling and then disabling readlogs.
@@ -958,14 +974,10 @@ TEST_F(IncrementalServiceTest, testSetIncFsMountOptionsSuccessAndDisabled) {
}
TEST_F(IncrementalServiceTest, testSetIncFsMountOptionsSuccessAndPermissionChanged) {
- mVold->mountIncFsSuccess();
- mIncFs->makeFileSuccess();
- mVold->bindMountSuccess();
mVold->setIncFsMountOptionsSuccess();
- mDataLoaderManager->bindToDataLoaderSuccess();
- mDataLoaderManager->getDataLoaderSuccess();
mAppOpsManager->checkPermissionSuccess();
mAppOpsManager->initializeStartWatchingMode();
+
EXPECT_CALL(*mDataLoaderManager, unbindFromDataLoader(_));
EXPECT_CALL(*mVold, unmountIncFs(_)).Times(2);
// We are calling setIncFsMountOptions(true).
@@ -987,12 +999,8 @@ TEST_F(IncrementalServiceTest, testSetIncFsMountOptionsSuccessAndPermissionChang
}
TEST_F(IncrementalServiceTest, testSetIncFsMountOptionsCheckPermissionFails) {
- mVold->mountIncFsSuccess();
- mIncFs->makeFileSuccess();
- mVold->bindMountSuccess();
- mDataLoaderManager->bindToDataLoaderSuccess();
- mDataLoaderManager->getDataLoaderSuccess();
mAppOpsManager->checkPermissionFails();
+
EXPECT_CALL(*mDataLoaderManager, unbindFromDataLoader(_));
EXPECT_CALL(*mVold, unmountIncFs(_)).Times(2);
// checkPermission fails, no calls to set opitions, start or stop WatchingMode.
@@ -1008,13 +1016,9 @@ TEST_F(IncrementalServiceTest, testSetIncFsMountOptionsCheckPermissionFails) {
}
TEST_F(IncrementalServiceTest, testSetIncFsMountOptionsFails) {
- mVold->mountIncFsSuccess();
- mIncFs->makeFileSuccess();
- mVold->bindMountSuccess();
mVold->setIncFsMountOptionsFails();
- mDataLoaderManager->bindToDataLoaderSuccess();
- mDataLoaderManager->getDataLoaderSuccess();
mAppOpsManager->checkPermissionSuccess();
+
EXPECT_CALL(*mDataLoaderManager, unbindFromDataLoader(_));
EXPECT_CALL(*mVold, unmountIncFs(_)).Times(2);
// We are calling setIncFsMountOptions.
@@ -1031,11 +1035,6 @@ TEST_F(IncrementalServiceTest, testSetIncFsMountOptionsFails) {
}
TEST_F(IncrementalServiceTest, testMakeDirectory) {
- mVold->mountIncFsSuccess();
- mIncFs->makeFileSuccess();
- mVold->bindMountSuccess();
- mDataLoaderManager->bindToDataLoaderSuccess();
- mDataLoaderManager->getDataLoaderSuccess();
TemporaryDir tempDir;
int storageId = mIncrementalService->createStorage(tempDir.path, std::move(mDataLoaderParcel),
IncrementalService::CreateOptions::CreateNew,
@@ -1055,11 +1054,6 @@ TEST_F(IncrementalServiceTest, testMakeDirectory) {
}
TEST_F(IncrementalServiceTest, testMakeDirectories) {
- mVold->mountIncFsSuccess();
- mIncFs->makeFileSuccess();
- mVold->bindMountSuccess();
- mDataLoaderManager->bindToDataLoaderSuccess();
- mDataLoaderManager->getDataLoaderSuccess();
TemporaryDir tempDir;
int storageId = mIncrementalService->createStorage(tempDir.path, std::move(mDataLoaderParcel),
IncrementalService::CreateOptions::CreateNew,
@@ -1078,4 +1072,98 @@ TEST_F(IncrementalServiceTest, testMakeDirectories) {
auto res = mIncrementalService->makeDirs(storageId, dir_path, 0555);
ASSERT_EQ(res, 0);
}
+
+TEST_F(IncrementalServiceTest, testIsFileFullyLoadedFailsWithNoFile) {
+ mIncFs->countFilledBlocksFails();
+ mFs->hasNoFile();
+
+ TemporaryDir tempDir;
+ int storageId = mIncrementalService->createStorage(tempDir.path, std::move(mDataLoaderParcel),
+ IncrementalService::CreateOptions::CreateNew,
+ {}, {}, {});
+ ASSERT_EQ(-1, mIncrementalService->isFileFullyLoaded(storageId, "base.apk"));
+}
+
+TEST_F(IncrementalServiceTest, testIsFileFullyLoadedFailsWithFailedRanges) {
+ mIncFs->countFilledBlocksFails();
+ mFs->hasFiles();
+
+ TemporaryDir tempDir;
+ int storageId = mIncrementalService->createStorage(tempDir.path, std::move(mDataLoaderParcel),
+ IncrementalService::CreateOptions::CreateNew,
+ {}, {}, {});
+ EXPECT_CALL(*mIncFs, countFilledBlocks(_, _)).Times(1);
+ ASSERT_EQ(-1, mIncrementalService->isFileFullyLoaded(storageId, "base.apk"));
+}
+
+TEST_F(IncrementalServiceTest, testIsFileFullyLoadedSuccessWithEmptyRanges) {
+ mIncFs->countFilledBlocksEmpty();
+ mFs->hasFiles();
+
+ TemporaryDir tempDir;
+ int storageId = mIncrementalService->createStorage(tempDir.path, std::move(mDataLoaderParcel),
+ IncrementalService::CreateOptions::CreateNew,
+ {}, {}, {});
+ EXPECT_CALL(*mIncFs, countFilledBlocks(_, _)).Times(1);
+ ASSERT_EQ(0, mIncrementalService->isFileFullyLoaded(storageId, "base.apk"));
+}
+
+TEST_F(IncrementalServiceTest, testIsFileFullyLoadedSuccess) {
+ mIncFs->countFilledBlocksFullyLoaded();
+ mFs->hasFiles();
+
+ TemporaryDir tempDir;
+ int storageId = mIncrementalService->createStorage(tempDir.path, std::move(mDataLoaderParcel),
+ IncrementalService::CreateOptions::CreateNew,
+ {}, {}, {});
+ EXPECT_CALL(*mIncFs, countFilledBlocks(_, _)).Times(1);
+ ASSERT_EQ(0, mIncrementalService->isFileFullyLoaded(storageId, "base.apk"));
+}
+
+TEST_F(IncrementalServiceTest, testGetLoadingProgressSuccessWithNoFile) {
+ mIncFs->countFilledBlocksSuccess();
+ mFs->hasNoFile();
+
+ TemporaryDir tempDir;
+ int storageId = mIncrementalService->createStorage(tempDir.path, std::move(mDataLoaderParcel),
+ IncrementalService::CreateOptions::CreateNew,
+ {}, {}, {});
+ ASSERT_EQ(1, mIncrementalService->getLoadingProgress(storageId));
+}
+
+TEST_F(IncrementalServiceTest, testGetLoadingProgressFailsWithFailedRanges) {
+ mIncFs->countFilledBlocksFails();
+ mFs->hasFiles();
+
+ TemporaryDir tempDir;
+ int storageId = mIncrementalService->createStorage(tempDir.path, std::move(mDataLoaderParcel),
+ IncrementalService::CreateOptions::CreateNew,
+ {}, {}, {});
+ EXPECT_CALL(*mIncFs, countFilledBlocks(_, _)).Times(1);
+ ASSERT_EQ(-1, mIncrementalService->getLoadingProgress(storageId));
+}
+
+TEST_F(IncrementalServiceTest, testGetLoadingProgressSuccessWithEmptyRanges) {
+ mIncFs->countFilledBlocksEmpty();
+ mFs->hasFiles();
+
+ TemporaryDir tempDir;
+ int storageId = mIncrementalService->createStorage(tempDir.path, std::move(mDataLoaderParcel),
+ IncrementalService::CreateOptions::CreateNew,
+ {}, {}, {});
+ EXPECT_CALL(*mIncFs, countFilledBlocks(_, _)).Times(3);
+ ASSERT_EQ(1, mIncrementalService->getLoadingProgress(storageId));
+}
+
+TEST_F(IncrementalServiceTest, testGetLoadingProgressSuccess) {
+ mIncFs->countFilledBlocksSuccess();
+ mFs->hasFiles();
+
+ TemporaryDir tempDir;
+ int storageId = mIncrementalService->createStorage(tempDir.path, std::move(mDataLoaderParcel),
+ IncrementalService::CreateOptions::CreateNew,
+ {}, {}, {});
+ EXPECT_CALL(*mIncFs, countFilledBlocks(_, _)).Times(3);
+ ASSERT_EQ(0.5, mIncrementalService->getLoadingProgress(storageId));
+}
} // namespace android::os::incremental
diff --git a/services/robotests/src/com/android/server/pm/CrossProfileAppsServiceImplRoboTest.java b/services/robotests/src/com/android/server/pm/CrossProfileAppsServiceImplRoboTest.java
index 4b25890e5fdb..5fa809fc89af 100644
--- a/services/robotests/src/com/android/server/pm/CrossProfileAppsServiceImplRoboTest.java
+++ b/services/robotests/src/com/android/server/pm/CrossProfileAppsServiceImplRoboTest.java
@@ -204,10 +204,10 @@ public class CrossProfileAppsServiceImplRoboTest {
CROSS_PROFILE_APP_PACKAGE_NAME, PERSONAL_PROFILE_UID, PERSONAL_PROFILE_USER_ID);
ShadowApplicationPackageManager.setPackageUidAsUser(
CROSS_PROFILE_APP_PACKAGE_NAME, WORK_PROFILE_UID, WORK_PROFILE_USER_ID);
- when(mPackageManagerInternal.getPackageUidInternal(
+ when(mPackageManagerInternal.getPackageUid(
CROSS_PROFILE_APP_PACKAGE_NAME, /* flags= */ 0, PERSONAL_PROFILE_USER_ID))
.thenReturn(PERSONAL_PROFILE_UID);
- when(mPackageManagerInternal.getPackageUidInternal(
+ when(mPackageManagerInternal.getPackageUid(
CROSS_PROFILE_APP_PACKAGE_NAME, /* flags= */ 0, WORK_PROFILE_USER_ID))
.thenReturn(WORK_PROFILE_UID);
}
diff --git a/services/tests/mockingservicestests/src/com/android/server/alarm/AlarmManagerServiceTest.java b/services/tests/mockingservicestests/src/com/android/server/alarm/AlarmManagerServiceTest.java
index 77232dc4644c..0789d680a80c 100644
--- a/services/tests/mockingservicestests/src/com/android/server/alarm/AlarmManagerServiceTest.java
+++ b/services/tests/mockingservicestests/src/com/android/server/alarm/AlarmManagerServiceTest.java
@@ -780,7 +780,7 @@ public class AlarmManagerServiceTest {
setTestAlarm(ELAPSED_REALTIME_WAKEUP, mNowElapsedTest + 2, alarmPi);
assertEquals(mNowElapsedTest + 2, mTestTimer.getElapsed());
- final SparseArray<ArrayList<AlarmManagerService.Alarm>> restrictedAlarms =
+ final SparseArray<ArrayList<Alarm>> restrictedAlarms =
mService.mPendingBackgroundAlarms;
assertNull(restrictedAlarms.get(TEST_CALLING_UID));
@@ -993,7 +993,7 @@ public class AlarmManagerServiceTest {
@Test
public void alarmCountOnRemoveFromPendingWhileIdle() {
- mService.mPendingIdleUntil = mock(AlarmManagerService.Alarm.class);
+ mService.mPendingIdleUntil = mock(Alarm.class);
final int numAlarms = 15;
final PendingIntent[] pis = new PendingIntent[numAlarms];
for (int i = 0; i < numAlarms; i++) {
diff --git a/services/tests/mockingservicestests/src/com/android/server/alarm/AlarmStoreTest.java b/services/tests/mockingservicestests/src/com/android/server/alarm/AlarmStoreTest.java
new file mode 100644
index 000000000000..9e43b4ab9b5a
--- /dev/null
+++ b/services/tests/mockingservicestests/src/com/android/server/alarm/AlarmStoreTest.java
@@ -0,0 +1,193 @@
+/*
+ * 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.alarm;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertTrue;
+import static org.mockito.Mockito.mock;
+
+import android.app.AlarmManager;
+import android.app.PendingIntent;
+import android.platform.test.annotations.Presubmit;
+
+import androidx.test.runner.AndroidJUnit4;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+import java.util.ArrayList;
+
+@Presubmit
+@RunWith(AndroidJUnit4.class)
+public class AlarmStoreTest {
+ private static final int TEST_CALLING_UID = 12345;
+ private static final String TEST_CALLING_PACKAGE = "android.alarm.unit.test";
+
+ private AlarmStore mAlarmStore;
+
+ @Before
+ public void setUp() {
+ mAlarmStore = new BatchingAlarmStore(null);
+ }
+
+ private static Alarm createAlarm(long whenElapsed, long windowLength, PendingIntent mockPi,
+ AlarmManager.AlarmClockInfo alarmClock) {
+ return createAlarm(AlarmManager.ELAPSED_REALTIME, whenElapsed, windowLength, mockPi,
+ alarmClock);
+ }
+
+ private static Alarm createWakeupAlarm(long whenElapsed, long windowLength,
+ PendingIntent mockPi, AlarmManager.AlarmClockInfo alarmClock) {
+ return createAlarm(AlarmManager.ELAPSED_REALTIME_WAKEUP, whenElapsed, windowLength, mockPi,
+ alarmClock);
+ }
+
+ private static Alarm createAlarm(int type, long whenElapsed, long windowLength,
+ PendingIntent mockPi, AlarmManager.AlarmClockInfo alarmClock) {
+ return new Alarm(type, whenElapsed, whenElapsed, windowLength, whenElapsed + windowLength,
+ 0, mockPi, null, null, null, 0, alarmClock, TEST_CALLING_UID, TEST_CALLING_PACKAGE);
+ }
+
+ private void addAlarmsToStore(Alarm... alarms) {
+ for (Alarm a : alarms) {
+ mAlarmStore.add(a);
+ }
+ }
+
+ @Test
+ public void add() {
+ final Alarm a1 = createAlarm(1, 0, mock(PendingIntent.class), null);
+ mAlarmStore.add(a1);
+ assertEquals(1, mAlarmStore.size());
+
+ final Alarm a2 = createAlarm(2, 0, mock(PendingIntent.class), null);
+ mAlarmStore.add(a2);
+ assertEquals(2, mAlarmStore.size());
+
+ ArrayList<Alarm> alarmsAdded = mAlarmStore.asList();
+ assertEquals(2, alarmsAdded.size());
+ assertTrue(alarmsAdded.contains(a1) && alarmsAdded.contains(a2));
+ }
+
+ @Test
+ public void remove() {
+ final Alarm a1 = createAlarm(1, 0, mock(PendingIntent.class), null);
+ final Alarm a2 = createAlarm(2, 0, mock(PendingIntent.class), null);
+ final Alarm a5 = createAlarm(5, 0, mock(PendingIntent.class), null);
+ addAlarmsToStore(a1, a2, a5);
+
+ ArrayList<Alarm> removed = mAlarmStore.remove(a -> (a.whenElapsed < 4));
+ assertEquals(2, removed.size());
+ assertEquals(1, mAlarmStore.size());
+ assertTrue(removed.contains(a1) && removed.contains(a2));
+
+ final Alarm a8 = createAlarm(8, 0, mock(PendingIntent.class), null);
+ addAlarmsToStore(a8, a2, a1);
+
+ removed = mAlarmStore.remove(unused -> false);
+ assertEquals(0, removed.size());
+ assertEquals(4, mAlarmStore.size());
+
+ removed = mAlarmStore.remove(unused -> true);
+ assertEquals(4, removed.size());
+ assertEquals(0, mAlarmStore.size());
+ }
+
+ @Test
+ public void removePendingAlarms() {
+ final Alarm a1_11 = createAlarm(1, 10, mock(PendingIntent.class), null);
+ final Alarm a2_5 = createAlarm(2, 3, mock(PendingIntent.class), null);
+ final Alarm a6_9 = createAlarm(6, 3, mock(PendingIntent.class), null);
+ addAlarmsToStore(a2_5, a6_9, a1_11);
+
+ final ArrayList<Alarm> pendingAt0 = mAlarmStore.removePendingAlarms(0);
+ assertEquals(0, pendingAt0.size());
+ assertEquals(3, mAlarmStore.size());
+
+ final ArrayList<Alarm> pendingAt3 = mAlarmStore.removePendingAlarms(3);
+ assertEquals(2, pendingAt3.size());
+ assertTrue(pendingAt3.contains(a1_11) && pendingAt3.contains(a2_5));
+ assertEquals(1, mAlarmStore.size());
+
+ addAlarmsToStore(a2_5, a1_11);
+ final ArrayList<Alarm> pendingAt7 = mAlarmStore.removePendingAlarms(7);
+ assertEquals(3, pendingAt7.size());
+ assertTrue(pendingAt7.contains(a1_11) && pendingAt7.contains(a2_5) && pendingAt7.contains(
+ a6_9));
+ assertEquals(0, mAlarmStore.size());
+ }
+
+ @Test
+ public void getNextWakeupDeliveryTime() {
+ final Alarm a1_10 = createAlarm(1, 9, mock(PendingIntent.class), null);
+ final Alarm a3_8_wakeup = createWakeupAlarm(3, 5, mock(PendingIntent.class), null);
+ final Alarm a6_wakeup = createWakeupAlarm(6, 0, mock(PendingIntent.class), null);
+ final Alarm a5 = createAlarm(5, 0, mock(PendingIntent.class), null);
+ addAlarmsToStore(a5, a6_wakeup, a3_8_wakeup, a1_10);
+
+ // The wakeup alarms are [6] and [3, 8], hence 6 is the latest time till when we can
+ // defer delivering any wakeup alarm.
+ assertTrue(mAlarmStore.getNextWakeupDeliveryTime() <= 6);
+
+ mAlarmStore.remove(a -> a.wakeup);
+ assertEquals(2, mAlarmStore.size());
+ // No wakeup alarms left.
+ assertEquals(0, mAlarmStore.getNextWakeupDeliveryTime());
+
+ mAlarmStore.remove(unused -> true);
+ assertEquals(0, mAlarmStore.getNextWakeupDeliveryTime());
+ }
+
+ @Test
+ public void getNextDeliveryTime() {
+ final Alarm a1_10 = createAlarm(1, 9, mock(PendingIntent.class), null);
+ final Alarm a3_8_wakeup = createWakeupAlarm(3, 5, mock(PendingIntent.class), null);
+ final Alarm a6_wakeup = createWakeupAlarm(6, 0, mock(PendingIntent.class), null);
+ final Alarm a5 = createAlarm(5, 0, mock(PendingIntent.class), null);
+ addAlarmsToStore(a5, a6_wakeup, a3_8_wakeup, a1_10);
+
+ assertTrue(mAlarmStore.getNextDeliveryTime() <= 5);
+
+ mAlarmStore.remove(unused -> true);
+ assertEquals(0, mAlarmStore.getNextWakeupDeliveryTime());
+ }
+
+ @Test
+ public void recalculateAlarmDeliveries() {
+ final Alarm a5 = createAlarm(5, 0, mock(PendingIntent.class), null);
+ final Alarm a8 = createAlarm(8, 0, mock(PendingIntent.class), null);
+ final Alarm a10 = createAlarm(10, 0, mock(PendingIntent.class), null);
+ addAlarmsToStore(a8, a10, a5);
+
+ assertEquals(5, mAlarmStore.getNextDeliveryTime());
+
+ mAlarmStore.recalculateAlarmDeliveries(a -> {
+ a.whenElapsed += 3;
+ a.maxWhenElapsed = a.whenElapsed;
+ return true;
+ });
+ assertEquals(8, mAlarmStore.getNextDeliveryTime());
+
+ mAlarmStore.recalculateAlarmDeliveries(a -> {
+ a.whenElapsed = 20 - a.whenElapsed;
+ a.maxWhenElapsed = a.whenElapsed;
+ return true;
+ });
+ assertEquals(7, mAlarmStore.getNextDeliveryTime());
+ }
+}
diff --git a/services/tests/mockingservicestests/src/com/android/server/alarm/BackgroundRestrictedAlarmsTest.java b/services/tests/mockingservicestests/src/com/android/server/alarm/BackgroundRestrictedAlarmsTest.java
index 12e953a4d4e8..6465739f6822 100644
--- a/services/tests/mockingservicestests/src/com/android/server/alarm/BackgroundRestrictedAlarmsTest.java
+++ b/services/tests/mockingservicestests/src/com/android/server/alarm/BackgroundRestrictedAlarmsTest.java
@@ -27,7 +27,6 @@ import androidx.test.filters.SmallTest;
import androidx.test.runner.AndroidJUnit4;
import com.android.internal.util.ObjectUtils;
-import com.android.server.alarm.AlarmManagerService.Alarm;
import org.junit.Test;
import org.junit.runner.RunWith;
diff --git a/services/tests/mockingservicestests/src/com/android/server/location/LocationProviderManagerTest.java b/services/tests/mockingservicestests/src/com/android/server/location/LocationProviderManagerTest.java
index fdcadf3e3088..80ad0a838bbb 100644
--- a/services/tests/mockingservicestests/src/com/android/server/location/LocationProviderManagerTest.java
+++ b/services/tests/mockingservicestests/src/com/android/server/location/LocationProviderManagerTest.java
@@ -33,6 +33,7 @@ import static com.android.internal.util.ConcurrentUtils.DIRECT_EXECUTOR;
import static com.android.server.location.LocationPermissions.PERMISSION_COARSE;
import static com.android.server.location.LocationPermissions.PERMISSION_FINE;
import static com.android.server.location.LocationUtils.createLocation;
+import static com.android.server.location.listeners.RemoteListenerRegistration.IN_PROCESS_EXECUTOR;
import static com.google.common.truth.Truth.assertThat;
@@ -85,7 +86,6 @@ import com.android.internal.location.ProviderProperties;
import com.android.internal.location.ProviderRequest;
import com.android.server.FgThread;
import com.android.server.LocalServices;
-import com.android.server.location.listeners.ListenerRegistration;
import com.android.server.location.util.FakeUserInfoHelper;
import com.android.server.location.util.TestInjector;
@@ -274,60 +274,55 @@ public class LocationProviderManagerTest {
@Test
public void testGetLastLocation_Fine() {
- LocationRequest request = LocationRequest.createFromDeprecatedProvider(NAME, 0, 0, false);
- assertThat(mManager.getLastLocation(request, IDENTITY, PERMISSION_FINE)).isNull();
+ assertThat(mManager.getLastLocation(IDENTITY, PERMISSION_FINE, false)).isNull();
Location loc = createLocation(NAME, mRandom);
mProvider.setProviderLocation(loc);
- assertThat(mManager.getLastLocation(request, IDENTITY, PERMISSION_FINE)).isEqualTo(loc);
+ assertThat(mManager.getLastLocation(IDENTITY, PERMISSION_FINE, false)).isEqualTo(loc);
}
@Test
public void testGetLastLocation_Coarse() {
- LocationRequest request = LocationRequest.createFromDeprecatedProvider(NAME, 0, 0, false);
- assertThat(mManager.getLastLocation(request, IDENTITY, PERMISSION_FINE)).isNull();
+ assertThat(mManager.getLastLocation(IDENTITY, PERMISSION_FINE, false)).isNull();
Location loc = createLocation(NAME, mRandom);
mProvider.setProviderLocation(loc);
- Location coarse = mManager.getLastLocation(request, IDENTITY, PERMISSION_COARSE);
+ Location coarse = mManager.getLastLocation(IDENTITY, PERMISSION_COARSE, false);
assertThat(coarse).isNotEqualTo(loc);
assertThat(coarse).isNearby(loc, 5000);
}
@Test
public void testGetLastLocation_Bypass() {
- LocationRequest request = LocationRequest.createFromDeprecatedProvider(NAME, 0, 0, false);
- LocationRequest bypassRequest = LocationRequest.createFromDeprecatedProvider(NAME, 0, 0,
- false).setLocationSettingsIgnored(true);
- assertThat(mManager.getLastLocation(request, IDENTITY, PERMISSION_FINE)).isNull();
- assertThat(mManager.getLastLocation(bypassRequest, IDENTITY, PERMISSION_FINE)).isNull();
+ assertThat(mManager.getLastLocation(IDENTITY, PERMISSION_FINE, false)).isNull();
+ assertThat(mManager.getLastLocation(IDENTITY, PERMISSION_FINE, true)).isNull();
Location loc = createLocation(NAME, mRandom);
mProvider.setProviderLocation(loc);
- assertThat(mManager.getLastLocation(request, IDENTITY, PERMISSION_FINE)).isEqualTo(loc);
- assertThat(mManager.getLastLocation(bypassRequest, IDENTITY, PERMISSION_FINE)).isEqualTo(
+ assertThat(mManager.getLastLocation(IDENTITY, PERMISSION_FINE, false)).isEqualTo(loc);
+ assertThat(mManager.getLastLocation(IDENTITY, PERMISSION_FINE, true)).isEqualTo(
loc);
mProvider.setProviderAllowed(false);
- assertThat(mManager.getLastLocation(request, IDENTITY, PERMISSION_FINE)).isNull();
- assertThat(mManager.getLastLocation(bypassRequest, IDENTITY, PERMISSION_FINE)).isEqualTo(
+ assertThat(mManager.getLastLocation(IDENTITY, PERMISSION_FINE, false)).isNull();
+ assertThat(mManager.getLastLocation(IDENTITY, PERMISSION_FINE, true)).isEqualTo(
loc);
loc = createLocation(NAME, mRandom);
mProvider.setProviderLocation(loc);
- assertThat(mManager.getLastLocation(request, IDENTITY, PERMISSION_FINE)).isNull();
- assertThat(mManager.getLastLocation(bypassRequest, IDENTITY, PERMISSION_FINE)).isEqualTo(
+ assertThat(mManager.getLastLocation(IDENTITY, PERMISSION_FINE, false)).isNull();
+ assertThat(mManager.getLastLocation(IDENTITY, PERMISSION_FINE, true)).isEqualTo(
loc);
mProvider.setProviderAllowed(true);
- assertThat(mManager.getLastLocation(request, IDENTITY, PERMISSION_FINE)).isNull();
- assertThat(mManager.getLastLocation(bypassRequest, IDENTITY, PERMISSION_FINE)).isEqualTo(
+ assertThat(mManager.getLastLocation(IDENTITY, PERMISSION_FINE, false)).isNull();
+ assertThat(mManager.getLastLocation(IDENTITY, PERMISSION_FINE, true)).isEqualTo(
loc);
loc = createLocation(NAME, mRandom);
mProvider.setProviderLocation(loc);
- assertThat(mManager.getLastLocation(request, IDENTITY, PERMISSION_FINE)).isEqualTo(loc);
- assertThat(mManager.getLastLocation(bypassRequest, IDENTITY, PERMISSION_FINE)).isEqualTo(
+ assertThat(mManager.getLastLocation(IDENTITY, PERMISSION_FINE, false)).isEqualTo(loc);
+ assertThat(mManager.getLastLocation(IDENTITY, PERMISSION_FINE, true)).isEqualTo(
loc);
}
@@ -337,13 +332,12 @@ public class LocationProviderManagerTest {
mockProvider.setAllowed(true);
mManager.setMockProvider(mockProvider);
- LocationRequest request = LocationRequest.createFromDeprecatedProvider(NAME, 0, 0, false);
Location loc = createLocation(NAME, mRandom);
mockProvider.setProviderLocation(loc);
- assertThat(mManager.getLastLocation(request, IDENTITY, PERMISSION_FINE)).isEqualTo(loc);
+ assertThat(mManager.getLastLocation(IDENTITY, PERMISSION_FINE, false)).isEqualTo(loc);
mManager.setMockProvider(null);
- assertThat(mManager.getLastLocation(request, IDENTITY, PERMISSION_FINE)).isNull();
+ assertThat(mManager.getLastLocation(IDENTITY, PERMISSION_FINE, false)).isNull();
}
@Test
@@ -351,13 +345,12 @@ public class LocationProviderManagerTest {
Location loc1 = createLocation(NAME, mRandom);
mManager.injectLastLocation(loc1, CURRENT_USER);
- LocationRequest request = LocationRequest.createFromDeprecatedProvider(NAME, 0, 0, false);
- assertThat(mManager.getLastLocation(request, IDENTITY, PERMISSION_FINE)).isEqualTo(loc1);
+ assertThat(mManager.getLastLocation(IDENTITY, PERMISSION_FINE, false)).isEqualTo(loc1);
Location loc2 = createLocation(NAME, mRandom);
mManager.injectLastLocation(loc2, CURRENT_USER);
- assertThat(mManager.getLastLocation(request, IDENTITY, PERMISSION_FINE)).isEqualTo(loc1);
+ assertThat(mManager.getLastLocation(IDENTITY, PERMISSION_FINE, false)).isEqualTo(loc1);
}
@Test
@@ -381,9 +374,7 @@ public class LocationProviderManagerTest {
Location loc = createLocation(NAME, mRandom);
mProvider.setProviderLocation(loc);
- LocationRequest request = LocationRequest.createFromDeprecatedProvider(PASSIVE_PROVIDER, 0,
- 0, false);
- assertThat(mPassive.getLastLocation(request, IDENTITY, PERMISSION_FINE)).isEqualTo(loc);
+ assertThat(mPassive.getLastLocation(IDENTITY, PERMISSION_FINE, false)).isEqualTo(loc);
}
@Test
@@ -484,7 +475,7 @@ public class LocationProviderManagerTest {
PERMISSION_FINE, listener);
CountDownLatch blocker = new CountDownLatch(1);
- ListenerRegistration.IN_PROCESS_EXECUTOR.execute(() -> {
+ IN_PROCESS_EXECUTOR.execute(() -> {
try {
blocker.await();
} catch (InterruptedException e) {
@@ -622,7 +613,7 @@ public class LocationProviderManagerTest {
PERMISSION_FINE, listener);
CountDownLatch blocker = new CountDownLatch(1);
- ListenerRegistration.IN_PROCESS_EXECUTOR.execute(() -> {
+ IN_PROCESS_EXECUTOR.execute(() -> {
try {
blocker.await();
} catch (InterruptedException e) {
diff --git a/services/tests/mockingservicestests/src/com/android/server/location/listeners/ListenerMultiplexerTest.java b/services/tests/mockingservicestests/src/com/android/server/location/listeners/ListenerMultiplexerTest.java
index 1ef12555a83a..69a9f4415fe7 100644
--- a/services/tests/mockingservicestests/src/com/android/server/location/listeners/ListenerMultiplexerTest.java
+++ b/services/tests/mockingservicestests/src/com/android/server/location/listeners/ListenerMultiplexerTest.java
@@ -16,6 +16,8 @@
package com.android.server.location.listeners;
+import static com.android.internal.util.ConcurrentUtils.DIRECT_EXECUTOR;
+
import static com.google.common.truth.Truth.assertThat;
import static org.mockito.ArgumentMatchers.any;
@@ -27,8 +29,6 @@ import static org.mockito.Mockito.times;
import static org.mockito.Mockito.verify;
import static org.testng.Assert.assertThrows;
-import android.location.util.identity.CallerIdentity;
-import android.os.Process;
import android.platform.test.annotations.Presubmit;
import androidx.test.filters.SmallTest;
@@ -324,10 +324,8 @@ public class ListenerMultiplexerTest {
boolean mActive = true;
protected TestListenerRegistration(Integer integer,
- Consumer<TestListenerRegistration> consumer,
- boolean outOfProcess) {
- super(integer, CallerIdentity.forTest(Process.myUid(),
- Process.myPid() + (outOfProcess ? 1 : 0), "test", "test"), consumer);
+ Consumer<TestListenerRegistration> consumer) {
+ super(DIRECT_EXECUTOR, integer, consumer);
}
}
@@ -345,7 +343,7 @@ public class ListenerMultiplexerTest {
}
public void addListener(Integer request, Consumer<TestListenerRegistration> consumer) {
- addRegistration(consumer, new TestListenerRegistration(request, consumer, true));
+ addRegistration(consumer, new TestListenerRegistration(request, consumer));
}
public void removeListener(Consumer<TestListenerRegistration> consumer) {
diff --git a/services/tests/servicestests/src/com/android/server/VibratorServiceTest.java b/services/tests/servicestests/src/com/android/server/VibratorServiceTest.java
index b7a36f2eaed2..8d4f2aa69d68 100644
--- a/services/tests/servicestests/src/com/android/server/VibratorServiceTest.java
+++ b/services/tests/servicestests/src/com/android/server/VibratorServiceTest.java
@@ -20,12 +20,13 @@ import static org.junit.Assert.assertArrayEquals;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertTrue;
+import static org.mockito.AdditionalMatchers.gt;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.ArgumentMatchers.anyInt;
import static org.mockito.ArgumentMatchers.anyLong;
import static org.mockito.ArgumentMatchers.eq;
import static org.mockito.ArgumentMatchers.intThat;
-import static org.mockito.ArgumentMatchers.isNull;
+import static org.mockito.ArgumentMatchers.notNull;
import static org.mockito.Mockito.doAnswer;
import static org.mockito.Mockito.inOrder;
import static org.mockito.Mockito.never;
@@ -167,7 +168,7 @@ public class VibratorServiceTest {
@Test
public void createService_initializesNativeService() {
createService();
- verify(mNativeWrapperMock).vibratorInit();
+ verify(mNativeWrapperMock).vibratorInit(notNull());
verify(mNativeWrapperMock).vibratorOff();
}
@@ -294,7 +295,7 @@ public class VibratorServiceTest {
assertTrue(service.isVibrating());
verify(mNativeWrapperMock).vibratorOff();
- verify(mNativeWrapperMock).vibratorOn(eq(100L), any(VibratorService.Vibration.class));
+ verify(mNativeWrapperMock).vibratorOn(eq(100L), gt(0L));
verify(mNativeWrapperMock).vibratorSetAmplitude(eq(128));
}
@@ -307,7 +308,7 @@ public class VibratorServiceTest {
assertTrue(service.isVibrating());
verify(mNativeWrapperMock).vibratorOff();
- verify(mNativeWrapperMock).vibratorOn(eq(100L), any(VibratorService.Vibration.class));
+ verify(mNativeWrapperMock).vibratorOn(eq(100L), gt(0L));
verify(mNativeWrapperMock, never()).vibratorSetAmplitude(anyInt());
}
@@ -321,10 +322,8 @@ public class VibratorServiceTest {
vibrate(service, VibrationEffect.createPredefined(VibrationEffect.EFFECT_CLICK));
verify(mNativeWrapperMock).vibratorOff();
- verify(mNativeWrapperMock).vibratorPerformEffect(
- eq((long) VibrationEffect.EFFECT_CLICK),
- eq((long) VibrationEffect.EFFECT_STRENGTH_STRONG),
- any(VibratorService.Vibration.class));
+ verify(mNativeWrapperMock).vibratorPerformEffect(eq((long) VibrationEffect.EFFECT_CLICK),
+ eq((long) VibrationEffect.EFFECT_STRENGTH_STRONG), gt(0L));
}
@Test
@@ -343,7 +342,7 @@ public class VibratorServiceTest {
verify(mNativeWrapperMock).vibratorOff();
verify(mNativeWrapperMock).vibratorPerformComposedEffect(
- primitivesCaptor.capture(), any(VibratorService.Vibration.class));
+ primitivesCaptor.capture(), gt(0L));
// Check all primitive effect fields are passed down to the HAL.
assertEquals(1, primitivesCaptor.getValue().length);
@@ -368,7 +367,7 @@ public class VibratorServiceTest {
// Wait for VibrateThread to turn vibrator ON with total timing and no callback.
Thread.sleep(5);
- verify(mNativeWrapperMock).vibratorOn(eq(30L), isNull());
+ verify(mNativeWrapperMock).vibratorOn(eq(30L), eq(0L));
// First amplitude set right away.
verify(mNativeWrapperMock).vibratorSetAmplitude(eq(100));
@@ -384,11 +383,11 @@ public class VibratorServiceTest {
@Test
public void vibrate_withOneShotAndNativeCallbackTriggered_finishesVibration() {
+ VibratorService service = createService();
doAnswer(invocation -> {
- ((VibratorService.Vibration) invocation.getArgument(1)).onComplete();
+ service.onVibrationComplete(invocation.getArgument(1));
return null;
- }).when(mNativeWrapperMock).vibratorOn(anyLong(), any(VibratorService.Vibration.class));
- VibratorService service = createService();
+ }).when(mNativeWrapperMock).vibratorOn(anyLong(), anyLong());
Mockito.clearInvocations(mNativeWrapperMock);
vibrate(service, VibrationEffect.createOneShot(100, VibrationEffect.DEFAULT_AMPLITUDE));
@@ -396,7 +395,7 @@ public class VibratorServiceTest {
InOrder inOrderVerifier = inOrder(mNativeWrapperMock);
inOrderVerifier.verify(mNativeWrapperMock).vibratorOff();
inOrderVerifier.verify(mNativeWrapperMock).vibratorOn(eq(100L),
- any(VibratorService.Vibration.class));
+ gt(0L));
inOrderVerifier.verify(mNativeWrapperMock).vibratorOff();
}
@@ -404,12 +403,11 @@ public class VibratorServiceTest {
public void vibrate_withPrebakedAndNativeCallbackTriggered_finishesVibration() {
when(mNativeWrapperMock.vibratorGetSupportedEffects())
.thenReturn(new int[]{VibrationEffect.EFFECT_CLICK});
+ VibratorService service = createService();
doAnswer(invocation -> {
- ((VibratorService.Vibration) invocation.getArgument(2)).onComplete();
+ service.onVibrationComplete(invocation.getArgument(2));
return 10_000L; // 10s
- }).when(mNativeWrapperMock).vibratorPerformEffect(
- anyLong(), anyLong(), any(VibratorService.Vibration.class));
- VibratorService service = createService();
+ }).when(mNativeWrapperMock).vibratorPerformEffect(anyLong(), anyLong(), anyLong());
Mockito.clearInvocations(mNativeWrapperMock);
vibrate(service, VibrationEffect.createPredefined(VibrationEffect.EFFECT_CLICK));
@@ -419,7 +417,7 @@ public class VibratorServiceTest {
inOrderVerifier.verify(mNativeWrapperMock).vibratorPerformEffect(
eq((long) VibrationEffect.EFFECT_CLICK),
eq((long) VibrationEffect.EFFECT_STRENGTH_STRONG),
- any(VibratorService.Vibration.class));
+ gt(0L));
inOrderVerifier.verify(mNativeWrapperMock).vibratorOff();
}
@@ -436,44 +434,19 @@ public class VibratorServiceTest {
Thread.sleep(15);
InOrder inOrderVerifier = inOrder(mNativeWrapperMock);
inOrderVerifier.verify(mNativeWrapperMock).vibratorOff();
- inOrderVerifier.verify(mNativeWrapperMock).vibratorOn(eq(3L), isNull());
- inOrderVerifier.verify(mNativeWrapperMock).vibratorOn(eq(2L), isNull());
+ inOrderVerifier.verify(mNativeWrapperMock).vibratorOn(eq(3L), eq(0L));
+ inOrderVerifier.verify(mNativeWrapperMock).vibratorOn(eq(2L), eq(0L));
inOrderVerifier.verify(mNativeWrapperMock).vibratorOff();
}
@Test
public void vibrate_withComposedAndNativeCallbackTriggered_finishesVibration() {
mockVibratorCapabilities(IVibrator.CAP_COMPOSE_EFFECTS);
- doAnswer(invocation -> {
- ((VibratorService.Vibration) invocation.getArgument(1)).onComplete();
- return null;
- }).when(mNativeWrapperMock).vibratorPerformComposedEffect(
- any(), any(VibratorService.Vibration.class));
VibratorService service = createService();
- Mockito.clearInvocations(mNativeWrapperMock);
-
- VibrationEffect effect = VibrationEffect.startComposition()
- .addPrimitive(VibrationEffect.Composition.PRIMITIVE_CLICK, 1f, 10)
- .compose();
- vibrate(service, effect);
-
- InOrder inOrderVerifier = inOrder(mNativeWrapperMock);
- inOrderVerifier.verify(mNativeWrapperMock).vibratorOff();
- inOrderVerifier.verify(mNativeWrapperMock).vibratorPerformComposedEffect(
- any(VibrationEffect.Composition.PrimitiveEffect[].class),
- any(VibratorService.Vibration.class));
- inOrderVerifier.verify(mNativeWrapperMock).vibratorOff();
- }
-
- @Test
- public void vibrate_whenBinderDies_cancelsVibration() {
- mockVibratorCapabilities(IVibrator.CAP_COMPOSE_EFFECTS);
doAnswer(invocation -> {
- ((VibratorService.Vibration) invocation.getArgument(1)).binderDied();
+ service.onVibrationComplete(invocation.getArgument(1));
return null;
- }).when(mNativeWrapperMock).vibratorPerformComposedEffect(
- any(), any(VibratorService.Vibration.class));
- VibratorService service = createService();
+ }).when(mNativeWrapperMock).vibratorPerformComposedEffect(any(), anyLong());
Mockito.clearInvocations(mNativeWrapperMock);
VibrationEffect effect = VibrationEffect.startComposition()
@@ -484,8 +457,7 @@ public class VibratorServiceTest {
InOrder inOrderVerifier = inOrder(mNativeWrapperMock);
inOrderVerifier.verify(mNativeWrapperMock).vibratorOff();
inOrderVerifier.verify(mNativeWrapperMock).vibratorPerformComposedEffect(
- any(VibrationEffect.Composition.PrimitiveEffect[].class),
- any(VibratorService.Vibration.class));
+ any(VibrationEffect.Composition.PrimitiveEffect[].class), gt(0L));
inOrderVerifier.verify(mNativeWrapperMock).vibratorOff();
}
@@ -513,12 +485,11 @@ public class VibratorServiceTest {
@Test
public void registerVibratorStateListener_callbacksAreTriggered() throws Exception {
+ VibratorService service = createService();
doAnswer(invocation -> {
- ((VibratorService.Vibration) invocation.getArgument(1)).onComplete();
+ service.onVibrationComplete(invocation.getArgument(1));
return null;
- }).when(mNativeWrapperMock).vibratorOn(anyLong(), any(VibratorService.Vibration.class));
- VibratorService service = createService();
-
+ }).when(mNativeWrapperMock).vibratorOn(anyLong(), anyLong());
service.registerVibratorStateListener(mVibratorStateListenerMock);
verify(mVibratorStateListenerMock).onVibrating(false);
Mockito.clearInvocations(mVibratorStateListenerMock);
@@ -569,15 +540,15 @@ public class VibratorServiceTest {
verify(mNativeWrapperMock).vibratorPerformEffect(
eq((long) VibrationEffect.EFFECT_CLICK),
- eq((long) VibrationEffect.EFFECT_STRENGTH_STRONG), any());
+ eq((long) VibrationEffect.EFFECT_STRENGTH_STRONG), anyLong());
verify(mNativeWrapperMock).vibratorPerformEffect(
eq((long) VibrationEffect.EFFECT_TICK),
- eq((long) VibrationEffect.EFFECT_STRENGTH_MEDIUM), any());
+ eq((long) VibrationEffect.EFFECT_STRENGTH_MEDIUM), anyLong());
verify(mNativeWrapperMock).vibratorPerformEffect(
eq((long) VibrationEffect.EFFECT_DOUBLE_CLICK),
- eq((long) VibrationEffect.EFFECT_STRENGTH_LIGHT), any());
+ eq((long) VibrationEffect.EFFECT_STRENGTH_LIGHT), anyLong());
verify(mNativeWrapperMock, never()).vibratorPerformEffect(
- eq((long) VibrationEffect.EFFECT_HEAVY_CLICK), anyLong(), any());
+ eq((long) VibrationEffect.EFFECT_HEAVY_CLICK), anyLong(), anyLong());
}
@Test
@@ -644,7 +615,7 @@ public class VibratorServiceTest {
// Ringtone vibration is off, so only the other 3 are propagated to native.
verify(mNativeWrapperMock, times(3)).vibratorPerformComposedEffect(
- primitivesCaptor.capture(), any());
+ primitivesCaptor.capture(), anyLong());
List<VibrationEffect.Composition.PrimitiveEffect[]> values =
primitivesCaptor.getAllValues();
diff --git a/services/tests/servicestests/src/com/android/server/accessibility/gestures/TouchExplorerTest.java b/services/tests/servicestests/src/com/android/server/accessibility/gestures/TouchExplorerTest.java
index 763654d24047..dda81ffded4f 100644
--- a/services/tests/servicestests/src/com/android/server/accessibility/gestures/TouchExplorerTest.java
+++ b/services/tests/servicestests/src/com/android/server/accessibility/gestures/TouchExplorerTest.java
@@ -187,7 +187,7 @@ public class TouchExplorerTest {
moveEachPointers(mLastEvent, p(10, 10), p(10, 10));
send(mLastEvent);
goToStateClearFrom(STATE_DRAGGING_2FINGERS);
- assertCapturedEvents(ACTION_DOWN, ACTION_MOVE, ACTION_MOVE, ACTION_UP);
+ assertCapturedEvents(ACTION_DOWN, ACTION_MOVE, ACTION_MOVE, ACTION_MOVE, ACTION_UP);
}
@Test
@@ -288,7 +288,7 @@ public class TouchExplorerTest {
assertState(STATE_DRAGGING);
goToStateClearFrom(STATE_DRAGGING_2FINGERS);
assertState(STATE_CLEAR);
- assertCapturedEvents(ACTION_DOWN, ACTION_UP);
+ assertCapturedEvents(ACTION_DOWN, ACTION_MOVE, ACTION_UP);
assertCapturedEventsNoHistory();
}
@@ -301,6 +301,7 @@ public class TouchExplorerTest {
assertState(STATE_CLEAR);
assertCapturedEvents(
/* goto dragging state */ ACTION_DOWN,
+ ACTION_MOVE,
/* leave dragging state */ ACTION_UP,
ACTION_DOWN,
ACTION_POINTER_DOWN,
diff --git a/services/tests/servicestests/src/com/android/server/accessibility/magnification/MockWindowMagnificationConnection.java b/services/tests/servicestests/src/com/android/server/accessibility/magnification/MockWindowMagnificationConnection.java
index 42ba842f8434..f896d75ecb3b 100644
--- a/services/tests/servicestests/src/com/android/server/accessibility/magnification/MockWindowMagnificationConnection.java
+++ b/services/tests/servicestests/src/com/android/server/accessibility/magnification/MockWindowMagnificationConnection.java
@@ -20,6 +20,7 @@ import static org.mockito.ArgumentMatchers.any;
import static org.mockito.ArgumentMatchers.anyFloat;
import static org.mockito.ArgumentMatchers.anyInt;
import static org.mockito.ArgumentMatchers.eq;
+import static org.mockito.ArgumentMatchers.nullable;
import static org.mockito.Mockito.doAnswer;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.when;
@@ -27,6 +28,7 @@ import static org.mockito.Mockito.when;
import android.graphics.Rect;
import android.os.Binder;
import android.os.IBinder;
+import android.os.RemoteCallback;
import android.os.RemoteException;
import android.view.Display;
import android.view.accessibility.IWindowMagnificationConnection;
@@ -69,13 +71,28 @@ class MockWindowMagnificationConnection {
if (displayId != TEST_DISPLAY) {
throw new IllegalArgumentException("only support default display :" + displayId);
}
- computeMirrorWindowFrame(invocation.getArgument(1), invocation.getArgument(2));
-
+ computeMirrorWindowFrame(invocation.getArgument(2), invocation.getArgument(3));
+ final RemoteCallback callback = invocation.getArgument(4);
+ if (callback != null) {
+ callback.sendResult(null);
+ }
mIMirrorWindowCallback.onWindowMagnifierBoundsChanged(TEST_DISPLAY,
mMirrorWindowFrame);
return null;
}).when(mConnection).enableWindowMagnification(anyInt(),
- anyFloat(), anyFloat(), anyFloat());
+ anyFloat(), anyFloat(), anyFloat(), nullable(RemoteCallback.class));
+
+ doAnswer((invocation) -> {
+ final int displayId = invocation.getArgument(0);
+ if (displayId != TEST_DISPLAY) {
+ throw new IllegalArgumentException("only support default display :" + displayId);
+ }
+ final RemoteCallback callback = invocation.getArgument(1);
+ if (callback != null) {
+ callback.sendResult(null);
+ }
+ return null;
+ }).when(mConnection).disableWindowMagnification(anyInt(), nullable(RemoteCallback.class));
}
private void computeMirrorWindowFrame(float centerX, float centerY) {
diff --git a/services/tests/servicestests/src/com/android/server/accessibility/magnification/WindowMagnificationConnectionWrapperTest.java b/services/tests/servicestests/src/com/android/server/accessibility/magnification/WindowMagnificationConnectionWrapperTest.java
index 36b304b4884c..9ef65d9cce09 100644
--- a/services/tests/servicestests/src/com/android/server/accessibility/magnification/WindowMagnificationConnectionWrapperTest.java
+++ b/services/tests/servicestests/src/com/android/server/accessibility/magnification/WindowMagnificationConnectionWrapperTest.java
@@ -19,6 +19,7 @@ package com.android.server.accessibility.magnification;
import static org.mockito.Mockito.verify;
+import android.os.RemoteCallback;
import android.os.RemoteException;
import android.provider.Settings;
import android.view.Display;
@@ -43,18 +44,22 @@ public class WindowMagnificationConnectionWrapperTest {
private IWindowMagnificationConnection mConnection;
@Mock
private IWindowMagnificationConnectionCallback mCallback;
+ @Mock
+ private RemoteCallback.OnResultListener mOnResultListener;
+ private RemoteCallback mRemoteCallback;
private WindowMagnificationConnectionWrapper mConnectionWrapper;
@Before
public void setUp() {
MockitoAnnotations.initMocks(this);
mConnectionWrapper = new WindowMagnificationConnectionWrapper(mConnection);
+ mRemoteCallback = new RemoteCallback(mOnResultListener);
}
@Test
public void enableWindowMagnification() throws RemoteException {
- mConnectionWrapper.enableWindowMagnification(TEST_DISPLAY, 2, 100f, 200f);
- verify(mConnection).enableWindowMagnification(TEST_DISPLAY, 2, 100f, 200f);
+ mConnectionWrapper.enableWindowMagnification(TEST_DISPLAY, 2, 100f, 200f, mRemoteCallback);
+ verify(mConnection).enableWindowMagnification(TEST_DISPLAY, 2, 100f, 200f, mRemoteCallback);
}
@Test
@@ -65,8 +70,8 @@ public class WindowMagnificationConnectionWrapperTest {
@Test
public void disableWindowMagnification() throws RemoteException {
- mConnectionWrapper.disableWindowMagnification(TEST_DISPLAY);
- verify(mConnection).disableWindowMagnification(TEST_DISPLAY);
+ mConnectionWrapper.disableWindowMagnification(TEST_DISPLAY, mRemoteCallback);
+ verify(mConnection).disableWindowMagnification(TEST_DISPLAY, mRemoteCallback);
}
@Test
diff --git a/services/tests/servicestests/src/com/android/server/accessibility/magnification/WindowMagnificationGestureHandlerTest.java b/services/tests/servicestests/src/com/android/server/accessibility/magnification/WindowMagnificationGestureHandlerTest.java
index bec9f26672f4..a10e0ba5020c 100644
--- a/services/tests/servicestests/src/com/android/server/accessibility/magnification/WindowMagnificationGestureHandlerTest.java
+++ b/services/tests/servicestests/src/com/android/server/accessibility/magnification/WindowMagnificationGestureHandlerTest.java
@@ -81,7 +81,7 @@ public class WindowMagnificationGestureHandlerTest {
@After
public void tearDown() {
- mWindowMagnificationManager.disableWindowMagnifier(DISPLAY_0, true);
+ mWindowMagnificationManager.disableWindowMagnification(DISPLAY_0, true);
}
@Test
@@ -225,7 +225,7 @@ public class WindowMagnificationGestureHandlerTest {
}
break;
case STATE_SHOW_MAGNIFIER: {
- mWindowMagnificationManager.disableWindowMagnifier(DISPLAY_0, false);
+ mWindowMagnificationManager.disableWindowMagnification(DISPLAY_0, false);
}
break;
case STATE_TWO_FINGERS_DOWN: {
diff --git a/services/tests/servicestests/src/com/android/server/accessibility/magnification/WindowMagnificationManagerTest.java b/services/tests/servicestests/src/com/android/server/accessibility/magnification/WindowMagnificationManagerTest.java
index 70e6a340816a..dcb1262ad2de 100644
--- a/services/tests/servicestests/src/com/android/server/accessibility/magnification/WindowMagnificationManagerTest.java
+++ b/services/tests/servicestests/src/com/android/server/accessibility/magnification/WindowMagnificationManagerTest.java
@@ -68,8 +68,12 @@ public class WindowMagnificationManagerTest {
private static final int CURRENT_USER_ID = UserHandle.USER_CURRENT;
private MockWindowMagnificationConnection mMockConnection;
- @Mock private Context mContext;
- @Mock private StatusBarManagerInternal mMockStatusBarManagerInternal;
+ @Mock
+ private Context mContext;
+ @Mock
+ private StatusBarManagerInternal mMockStatusBarManagerInternal;
+ @Mock
+ private Runnable mEndCallback;
private MockContentResolver mResolver;
private WindowMagnificationManager mWindowMagnificationManager;
@@ -84,7 +88,7 @@ public class WindowMagnificationManagerTest {
when(mContext.getContentResolver()).thenReturn(mResolver);
doAnswer((InvocationOnMock invocation) -> {
- final boolean connect = (Boolean) invocation.getArguments()[0];
+ final boolean connect = (Boolean) invocation.getArguments()[0];
mWindowMagnificationManager.setConnection(
connect ? mMockConnection.getConnection() : null);
return null;
@@ -158,32 +162,53 @@ public class WindowMagnificationManagerTest {
}
@Test
- public void enable_TestDisplay_enableWindowMagnification() throws RemoteException {
+ public void enable_hasConnection_enableWindowMagnification() throws RemoteException {
mWindowMagnificationManager.setConnection(mMockConnection.getConnection());
- mWindowMagnificationManager.enableWindowMagnifier(TEST_DISPLAY, 2f, 200f, 300f);
+ mWindowMagnificationManager.enableWindowMagnification(TEST_DISPLAY, 2f, 200f, 300f);
verify(mMockConnection.getConnection()).enableWindowMagnification(TEST_DISPLAY, 2f,
- 200f, 300f);
+ 200f, 300f, null);
}
@Test
- public void disable_testDisplay_disableWindowMagnification() throws RemoteException {
+ public void enableWithCallback_hasConnection_enableWindowMagnification()
+ throws RemoteException {
+ mWindowMagnificationManager.setConnection(mMockConnection.getConnection());
+
+ mWindowMagnificationManager.enableWindowMagnification(TEST_DISPLAY, 2f, 200f, 300f,
+ mEndCallback);
+
+ verify(mEndCallback).run();
+ }
+
+ @Test
+ public void disable_hasConnectionAndEnabled_disableWindowMagnification()
+ throws RemoteException {
mWindowMagnificationManager.setConnection(mMockConnection.getConnection());
- mWindowMagnificationManager.enableWindowMagnifier(TEST_DISPLAY, 3f, NaN, NaN);
+ mWindowMagnificationManager.enableWindowMagnification(TEST_DISPLAY, 3f, NaN, NaN);
- mWindowMagnificationManager.disableWindowMagnifier(TEST_DISPLAY, false);
+ mWindowMagnificationManager.disableWindowMagnification(TEST_DISPLAY, false);
- verify(mMockConnection.getConnection()).disableWindowMagnification(TEST_DISPLAY);
+ verify(mMockConnection.getConnection()).disableWindowMagnification(TEST_DISPLAY, null);
}
@Test
- public void isWindowMagnifierEnabled_returnExpectedValue() {
+ public void disableWithCallback_hasConnectionAndEnabled_disableWindowMagnification() {
mWindowMagnificationManager.setConnection(mMockConnection.getConnection());
+ mWindowMagnificationManager.enableWindowMagnification(TEST_DISPLAY, 3f, NaN, NaN);
+ mWindowMagnificationManager.disableWindowMagnification(TEST_DISPLAY, false, mEndCallback);
+
+ verify(mEndCallback).run();
+ }
+
+ @Test
+ public void isWindowMagnifierEnabled_hasConnectionAndEnabled_returnExpectedValue() {
+ mWindowMagnificationManager.setConnection(mMockConnection.getConnection());
assertFalse(mWindowMagnificationManager.isWindowMagnifierEnabled(TEST_DISPLAY));
- mWindowMagnificationManager.enableWindowMagnifier(TEST_DISPLAY, 2f, NaN, NaN);
+ mWindowMagnificationManager.enableWindowMagnification(TEST_DISPLAY, 2f, NaN, NaN);
assertTrue(mWindowMagnificationManager.isWindowMagnifierEnabled(TEST_DISPLAY));
}
@@ -198,7 +223,7 @@ public class WindowMagnificationManagerTest {
@Test
public void persistScale_setValue_expectedValueInProvider() {
mWindowMagnificationManager.setConnection(mMockConnection.getConnection());
- mWindowMagnificationManager.enableWindowMagnifier(TEST_DISPLAY, 2.0f, NaN, NaN);
+ mWindowMagnificationManager.enableWindowMagnification(TEST_DISPLAY, 2.0f, NaN, NaN);
mWindowMagnificationManager.setScale(TEST_DISPLAY, 2.5f);
mWindowMagnificationManager.persistScale(TEST_DISPLAY);
@@ -211,7 +236,7 @@ public class WindowMagnificationManagerTest {
@Test
public void scaleSetterGetter_enabledOnTestDisplay_expectedValue() {
mWindowMagnificationManager.setConnection(mMockConnection.getConnection());
- mWindowMagnificationManager.enableWindowMagnifier(TEST_DISPLAY, 2.0f, NaN, NaN);
+ mWindowMagnificationManager.enableWindowMagnification(TEST_DISPLAY, 2.0f, NaN, NaN);
mWindowMagnificationManager.setScale(TEST_DISPLAY, 2.5f);
@@ -221,7 +246,7 @@ public class WindowMagnificationManagerTest {
@Test
public void scaleSetterGetter_scaleIsOutOfRang_getNormalizeValue() {
mWindowMagnificationManager.setConnection(mMockConnection.getConnection());
- mWindowMagnificationManager.enableWindowMagnifier(TEST_DISPLAY, 2.5f, NaN, NaN);
+ mWindowMagnificationManager.enableWindowMagnification(TEST_DISPLAY, 2.5f, NaN, NaN);
mWindowMagnificationManager.setScale(TEST_DISPLAY, 10.0f);
@@ -230,16 +255,17 @@ public class WindowMagnificationManagerTest {
}
@Test
- public void moveWindowMagnifier() throws RemoteException {
+ public void moveWindowMagnifier_enabled_invokeConnectionMethod() throws RemoteException {
mWindowMagnificationManager.setConnection(mMockConnection.getConnection());
- mWindowMagnificationManager.enableWindowMagnifier(TEST_DISPLAY, 2f, NaN, NaN);
+ mWindowMagnificationManager.enableWindowMagnification(TEST_DISPLAY, 2f, NaN, NaN);
- mWindowMagnificationManager.moveWindowMagnifier(TEST_DISPLAY, 200, 300);
+ mWindowMagnificationManager.moveWindowMagnification(TEST_DISPLAY, 200, 300);
verify(mMockConnection.getConnection()).moveWindowMagnifier(TEST_DISPLAY, 200, 300);
}
@Test
- public void showMagnificationButton() throws RemoteException {
+ public void showMagnificationButton_hasConnection_invokeConnectionMethod()
+ throws RemoteException {
mWindowMagnificationManager.setConnection(mMockConnection.getConnection());
mWindowMagnificationManager.showMagnificationButton(TEST_DISPLAY,
@@ -252,9 +278,9 @@ public class WindowMagnificationManagerTest {
}
@Test
- public void pointersInWindow_returnCorrectValue() throws RemoteException {
+ public void pointersInWindow_magnifierEnabled_returnCorrectValue() throws RemoteException {
mWindowMagnificationManager.setConnection(mMockConnection.getConnection());
- mWindowMagnificationManager.enableWindowMagnifier(TEST_DISPLAY, 3.0f, NaN, NaN);
+ mWindowMagnificationManager.enableWindowMagnification(TEST_DISPLAY, 3.0f, NaN, NaN);
mMockConnection.getConnectionCallback().onWindowMagnifierBoundsChanged(TEST_DISPLAY,
new Rect(0, 0, 500, 500));
PointF[] pointersLocation = new PointF[2];
@@ -268,7 +294,7 @@ public class WindowMagnificationManagerTest {
@Test
public void binderDied_windowMagnifierIsEnabled_resetState() throws RemoteException {
mWindowMagnificationManager.setConnection(mMockConnection.getConnection());
- mWindowMagnificationManager.enableWindowMagnifier(TEST_DISPLAY, 3f, NaN, NaN);
+ mWindowMagnificationManager.enableWindowMagnification(TEST_DISPLAY, 3f, NaN, NaN);
mMockConnection.getDeathRecipient().binderDied();
@@ -280,11 +306,11 @@ public class WindowMagnificationManagerTest {
requestConnectionToNull_disableAllMagnifiersAndRequestWindowMagnificationConnection()
throws RemoteException {
mWindowMagnificationManager.setConnection(mMockConnection.getConnection());
- mWindowMagnificationManager.enableWindowMagnifier(TEST_DISPLAY, 3f, NaN, NaN);
+ mWindowMagnificationManager.enableWindowMagnification(TEST_DISPLAY, 3f, NaN, NaN);
assertTrue(mWindowMagnificationManager.requestConnection(false));
- verify(mMockConnection.getConnection()).disableWindowMagnification(TEST_DISPLAY);
+ verify(mMockConnection.getConnection()).disableWindowMagnification(TEST_DISPLAY, null);
verify(mMockStatusBarManagerInternal).requestWindowMagnificationConnection(false);
}
@@ -306,21 +332,24 @@ public class WindowMagnificationManagerTest {
@Test
public void requestConnection_registerAndUnregisterBroadcastReceiver() {
assertTrue(mWindowMagnificationManager.requestConnection(true));
- verify(mContext).registerReceiver(any(BroadcastReceiver.class), any(IntentFilter.class));
+ verify(mContext).registerReceiver(any(BroadcastReceiver.class), any(IntentFilter.class));
assertTrue(mWindowMagnificationManager.requestConnection(false));
verify(mContext).unregisterReceiver(any(BroadcastReceiver.class));
}
@Test
- public void onReceiveScreenOff_removeMagnificationButtonAndDisableWindowMagnification()
+ public void onScreenOff_windowMagnifierIsEnabled_removeButtonAndDisableWindowMagnification()
throws RemoteException {
mWindowMagnificationManager.requestConnection(true);
+ mWindowMagnificationManager.enableWindowMagnification(TEST_DISPLAY, 2.5f, NaN, NaN);
+
mWindowMagnificationManager.mScreenStateReceiver.onReceive(mContext,
new Intent(Intent.ACTION_SCREEN_OFF));
verify(mMockConnection.getConnection()).removeMagnificationButton(TEST_DISPLAY);
- verify(mMockConnection.getConnection()).disableWindowMagnification(TEST_DISPLAY);
+ verify(mMockConnection.getConnection()).disableWindowMagnification(TEST_DISPLAY, null);
+ assertFalse(mWindowMagnificationManager.isWindowMagnifierEnabled(TEST_DISPLAY));
}
private MotionEvent generatePointersDownEvent(PointF[] pointersLocation) {
diff --git a/services/tests/servicestests/src/com/android/server/audio/NoOpAudioSystemAdapter.java b/services/tests/servicestests/src/com/android/server/audio/NoOpAudioSystemAdapter.java
index 609af8d5bf4d..8d706cb960e9 100644
--- a/services/tests/servicestests/src/com/android/server/audio/NoOpAudioSystemAdapter.java
+++ b/services/tests/servicestests/src/com/android/server/audio/NoOpAudioSystemAdapter.java
@@ -79,6 +79,23 @@ public class NoOpAudioSystemAdapter extends AudioSystemAdapter {
}
@Override
+ public int setDevicesRoleForCapturePreset(int capturePreset, int role,
+ @NonNull List<AudioDeviceAttributes> devices) {
+ return AudioSystem.AUDIO_STATUS_OK;
+ }
+
+ @Override
+ public int removeDevicesRoleForCapturePreset(
+ int capturePreset, int role, @NonNull List<AudioDeviceAttributes> devicesToRemove) {
+ return AudioSystem.AUDIO_STATUS_OK;
+ }
+
+ @Override
+ public int clearDevicesRoleForCapturePreset(int capturePreset, int role) {
+ return AudioSystem.AUDIO_STATUS_OK;
+ }
+
+ @Override
public int setParameters(String keyValuePairs) {
return AudioSystem.AUDIO_STATUS_OK;
}
diff --git a/services/tests/servicestests/src/com/android/server/devicepolicy/MockSystemServices.java b/services/tests/servicestests/src/com/android/server/devicepolicy/MockSystemServices.java
index b306ff091267..431cc27a6635 100644
--- a/services/tests/servicestests/src/com/android/server/devicepolicy/MockSystemServices.java
+++ b/services/tests/servicestests/src/com/android/server/devicepolicy/MockSystemServices.java
@@ -16,7 +16,6 @@
package com.android.server.devicepolicy;
import static org.mockito.ArgumentMatchers.any;
-import static org.mockito.ArgumentMatchers.anyBoolean;
import static org.mockito.ArgumentMatchers.anyInt;
import static org.mockito.ArgumentMatchers.eq;
import static org.mockito.Mockito.RETURNS_DEEP_STUBS;
@@ -236,7 +235,7 @@ public class MockSystemServices {
}
mUserInfos.add(uh);
when(userManager.getUsers()).thenReturn(mUserInfos);
- when(userManager.getUsers(anyBoolean())).thenReturn(mUserInfos);
+ when(userManager.getAliveUsers()).thenReturn(mUserInfos);
when(userManager.isUserRunning(eq(new UserHandle(userId)))).thenReturn(true);
when(userManager.getProfileParent(anyInt())).thenAnswer(
invocation -> {
diff --git a/services/tests/servicestests/src/com/android/server/display/DisplayManagerServiceTest.java b/services/tests/servicestests/src/com/android/server/display/DisplayManagerServiceTest.java
index b1f3871274ac..73dda0736d2f 100644
--- a/services/tests/servicestests/src/com/android/server/display/DisplayManagerServiceTest.java
+++ b/services/tests/servicestests/src/com/android/server/display/DisplayManagerServiceTest.java
@@ -19,6 +19,7 @@ package com.android.server.display;
import static com.android.server.display.VirtualDisplayAdapter.UNIQUE_ID_PREFIX;
import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertTrue;
import static org.junit.Assert.fail;
@@ -28,18 +29,23 @@ import static org.mockito.Mockito.when;
import android.app.PropertyInvalidatedCache;
import android.content.Context;
+import android.graphics.Insets;
+import android.graphics.Rect;
import android.hardware.display.BrightnessConfiguration;
import android.hardware.display.Curve;
import android.hardware.display.DisplayManager;
+import android.hardware.display.DisplayManagerGlobal;
import android.hardware.display.DisplayViewport;
import android.hardware.display.DisplayedContentSample;
import android.hardware.display.DisplayedContentSamplingAttributes;
+import android.hardware.display.IDisplayManagerCallback;
import android.hardware.display.IVirtualDisplayCallback;
import android.hardware.display.VirtualDisplayConfig;
import android.hardware.input.InputManagerInternal;
import android.os.Handler;
import android.os.IBinder;
import android.view.Display;
+import android.view.DisplayCutout;
import android.view.DisplayInfo;
import android.view.Surface;
import android.view.SurfaceControl;
@@ -282,6 +288,68 @@ public class DisplayManagerServiceTest {
}
/**
+ * Tests that there should be a display change notification to WindowManager to update its own
+ * internal state for things like display cutout when nonOverrideDisplayInfo is changed.
+ */
+ @Test
+ public void testShouldNotifyChangeWhenNonOverrideDisplayInfoChanged() throws Exception {
+ DisplayManagerService displayManager =
+ new DisplayManagerService(mContext, mShortMockedInjector);
+ registerDefaultDisplays(displayManager);
+ displayManager.onBootPhase(SystemService.PHASE_WAIT_FOR_DEFAULT_DISPLAY);
+
+ // Add the FakeDisplayDevice
+ FakeDisplayDevice displayDevice = new FakeDisplayDevice();
+ DisplayDeviceInfo displayDeviceInfo = new DisplayDeviceInfo();
+ displayDeviceInfo.width = 100;
+ displayDeviceInfo.height = 200;
+ final Rect zeroRect = new Rect();
+ displayDeviceInfo.displayCutout = new DisplayCutout(
+ Insets.of(0, 10, 0, 0),
+ zeroRect, new Rect(0, 0, 10, 10), zeroRect, zeroRect);
+ displayDeviceInfo.flags = DisplayDeviceInfo.FLAG_DEFAULT_DISPLAY;
+ displayDevice.setDisplayDeviceInfo(displayDeviceInfo);
+ displayManager.handleDisplayDeviceAdded(displayDevice);
+
+ // Find the display id of the added FakeDisplayDevice
+ DisplayManagerService.BinderService bs = displayManager.new BinderService();
+ final int[] displayIds = bs.getDisplayIds();
+ assertTrue(displayIds.length > 0);
+ int displayId = Display.INVALID_DISPLAY;
+ for (int i = 0; i < displayIds.length; i++) {
+ DisplayDeviceInfo ddi = displayManager.getDisplayDeviceInfoInternal(displayIds[i]);
+ if (displayDeviceInfo.equals(ddi)) {
+ displayId = displayIds[i];
+ break;
+ }
+ }
+ assertFalse(displayId == Display.INVALID_DISPLAY);
+
+ // Setup override DisplayInfo
+ DisplayInfo overrideInfo = bs.getDisplayInfo(displayId);
+ displayManager.setDisplayInfoOverrideFromWindowManagerInternal(displayId, overrideInfo);
+
+ Handler handler = displayManager.getDisplayHandler();
+ handler.runWithScissors(() -> {
+ }, 0 /* now */);
+
+ // register display listener callback
+ FakeDisplayManagerCallback callback = new FakeDisplayManagerCallback(displayId);
+ bs.registerCallback(callback);
+
+ // Simulate DisplayDevice change
+ DisplayDeviceInfo displayDeviceInfo2 = new DisplayDeviceInfo();
+ displayDeviceInfo2.copyFrom(displayDeviceInfo);
+ displayDeviceInfo2.displayCutout = null;
+ displayDevice.setDisplayDeviceInfo(displayDeviceInfo2);
+ displayManager.handleDisplayDeviceChanged(displayDevice);
+
+ handler.runWithScissors(() -> {
+ }, 0 /* now */);
+ assertTrue(callback.mCalled);
+ }
+
+ /**
* Tests that we get a Runtime exception when we cannot initialize the default display.
*/
@Test
@@ -512,4 +580,42 @@ public class DisplayManagerServiceTest {
// flush the handler
handler.runWithScissors(() -> {}, 0 /* now */);
}
+
+ private class FakeDisplayManagerCallback extends IDisplayManagerCallback.Stub {
+ int mDisplayId;
+ boolean mCalled = false;
+
+ FakeDisplayManagerCallback(int displayId) {
+ mDisplayId = displayId;
+ }
+
+ @Override
+ public void onDisplayEvent(int displayId, int event) {
+ if (displayId == mDisplayId && event == DisplayManagerGlobal.EVENT_DISPLAY_CHANGED) {
+ mCalled = true;
+ }
+ }
+ }
+
+ private class FakeDisplayDevice extends DisplayDevice {
+ private DisplayDeviceInfo mDisplayDeviceInfo;
+
+ FakeDisplayDevice() {
+ super(null, null, "");
+ }
+
+ public void setDisplayDeviceInfo(DisplayDeviceInfo displayDeviceInfo) {
+ mDisplayDeviceInfo = displayDeviceInfo;
+ }
+
+ @Override
+ public boolean hasStableUniqueId() {
+ return false;
+ }
+
+ @Override
+ public DisplayDeviceInfo getDisplayDeviceInfoLocked() {
+ return mDisplayDeviceInfo;
+ }
+ }
}
diff --git a/services/tests/servicestests/src/com/android/server/hdmi/HdmiCecLocalDevicePlaybackTest.java b/services/tests/servicestests/src/com/android/server/hdmi/HdmiCecLocalDevicePlaybackTest.java
index ef2365e6da3e..0c35797b38ea 100644
--- a/services/tests/servicestests/src/com/android/server/hdmi/HdmiCecLocalDevicePlaybackTest.java
+++ b/services/tests/servicestests/src/com/android/server/hdmi/HdmiCecLocalDevicePlaybackTest.java
@@ -15,6 +15,7 @@
*/
package com.android.server.hdmi;
+import static com.android.server.hdmi.Constants.ADDR_AUDIO_SYSTEM;
import static com.android.server.hdmi.Constants.ADDR_BROADCAST;
import static com.android.server.hdmi.Constants.ADDR_TV;
import static com.android.server.hdmi.HdmiControlService.INITIATED_BY_ENABLE_CEC;
@@ -693,6 +694,84 @@ public class HdmiCecLocalDevicePlaybackTest {
}
@Test
+ public void sendVolumeKeyEvent_toTv_activeSource() {
+ mHdmiControlService.setHdmiCecVolumeControlEnabled(true);
+ mHdmiControlService.setSystemAudioActivated(false);
+ mHdmiControlService.setActiveSource(mPlaybackLogicalAddress, mPlaybackPhysicalAddress,
+ "HdmiCecLocalDevicePlaybackTest");
+
+ mHdmiCecLocalDevicePlayback.sendVolumeKeyEvent(KeyEvent.KEYCODE_VOLUME_UP, true);
+ mHdmiCecLocalDevicePlayback.sendVolumeKeyEvent(KeyEvent.KEYCODE_VOLUME_UP, false);
+
+ HdmiCecMessage pressed = HdmiCecMessageBuilder.buildUserControlPressed(
+ mPlaybackLogicalAddress, ADDR_TV, HdmiCecKeycode.CEC_KEYCODE_VOLUME_UP);
+ HdmiCecMessage released = HdmiCecMessageBuilder.buildUserControlReleased(
+ mPlaybackLogicalAddress, ADDR_TV);
+ mTestLooper.dispatchAll();
+
+ assertThat(mHdmiCecLocalDevicePlayback.mIsActiveSource).isTrue();
+ assertThat(mNativeWrapper.getResultMessages()).containsAllOf(pressed, released);
+ }
+
+ @Test
+ public void sendVolumeKeyEvent_toAudio_activeSource() {
+ mHdmiControlService.setHdmiCecVolumeControlEnabled(true);
+ mHdmiControlService.setSystemAudioActivated(true);
+ mHdmiControlService.setActiveSource(mPlaybackLogicalAddress, mPlaybackPhysicalAddress,
+ "HdmiCecLocalDevicePlaybackTest");
+
+ mHdmiCecLocalDevicePlayback.sendVolumeKeyEvent(KeyEvent.KEYCODE_VOLUME_UP, true);
+ mHdmiCecLocalDevicePlayback.sendVolumeKeyEvent(KeyEvent.KEYCODE_VOLUME_UP, false);
+
+ HdmiCecMessage pressed = HdmiCecMessageBuilder.buildUserControlPressed(
+ mPlaybackLogicalAddress, ADDR_AUDIO_SYSTEM, HdmiCecKeycode.CEC_KEYCODE_VOLUME_UP);
+ HdmiCecMessage released = HdmiCecMessageBuilder.buildUserControlReleased(
+ mPlaybackLogicalAddress, ADDR_AUDIO_SYSTEM);
+ mTestLooper.dispatchAll();
+
+ assertThat(mHdmiCecLocalDevicePlayback.mIsActiveSource).isTrue();
+ assertThat(mNativeWrapper.getResultMessages()).containsAllOf(pressed, released);
+ }
+
+ @Test
+ public void sendVolumeKeyEvent_toTv_inactiveSource() {
+ mHdmiControlService.setHdmiCecVolumeControlEnabled(true);
+ mHdmiControlService.setSystemAudioActivated(false);
+ mHdmiControlService.setActiveSource(ADDR_TV, 0x0000, "HdmiCecLocalDevicePlaybackTest");
+
+ mHdmiCecLocalDevicePlayback.sendVolumeKeyEvent(KeyEvent.KEYCODE_VOLUME_UP, true);
+ mHdmiCecLocalDevicePlayback.sendVolumeKeyEvent(KeyEvent.KEYCODE_VOLUME_UP, false);
+
+ HdmiCecMessage pressed = HdmiCecMessageBuilder.buildUserControlPressed(
+ mPlaybackLogicalAddress, ADDR_TV, HdmiCecKeycode.CEC_KEYCODE_VOLUME_UP);
+ HdmiCecMessage released = HdmiCecMessageBuilder.buildUserControlReleased(
+ mPlaybackLogicalAddress, ADDR_TV);
+ mTestLooper.dispatchAll();
+
+ assertThat(mHdmiCecLocalDevicePlayback.mIsActiveSource).isFalse();
+ assertThat(mNativeWrapper.getResultMessages()).containsAllOf(pressed, released);
+ }
+
+ @Test
+ public void sendVolumeKeyEvent_toAudio_inactiveSource() {
+ mHdmiControlService.setHdmiCecVolumeControlEnabled(true);
+ mHdmiControlService.setSystemAudioActivated(true);
+ mHdmiControlService.setActiveSource(ADDR_TV, 0x0000, "HdmiCecLocalDevicePlaybackTest");
+
+ mHdmiCecLocalDevicePlayback.sendVolumeKeyEvent(KeyEvent.KEYCODE_VOLUME_UP, true);
+ mHdmiCecLocalDevicePlayback.sendVolumeKeyEvent(KeyEvent.KEYCODE_VOLUME_UP, false);
+
+ HdmiCecMessage pressed = HdmiCecMessageBuilder.buildUserControlPressed(
+ mPlaybackLogicalAddress, ADDR_AUDIO_SYSTEM, HdmiCecKeycode.CEC_KEYCODE_VOLUME_UP);
+ HdmiCecMessage released = HdmiCecMessageBuilder.buildUserControlReleased(
+ mPlaybackLogicalAddress, ADDR_AUDIO_SYSTEM);
+ mTestLooper.dispatchAll();
+
+ assertThat(mHdmiCecLocalDevicePlayback.mIsActiveSource).isFalse();
+ assertThat(mNativeWrapper.getResultMessages()).containsAllOf(pressed, released);
+ }
+
+ @Test
public void handleSetStreamPath_broadcastsActiveSource() {
HdmiCecMessage setStreamPath = HdmiCecMessageBuilder.buildSetStreamPath(ADDR_TV,
mPlaybackPhysicalAddress);
diff --git a/services/tests/servicestests/src/com/android/server/hdmi/HdmiCecMessageBuilderTest.java b/services/tests/servicestests/src/com/android/server/hdmi/HdmiCecMessageBuilderTest.java
index 53c4d6faf0b9..f17173f61b69 100644
--- a/services/tests/servicestests/src/com/android/server/hdmi/HdmiCecMessageBuilderTest.java
+++ b/services/tests/servicestests/src/com/android/server/hdmi/HdmiCecMessageBuilderTest.java
@@ -62,6 +62,32 @@ public class HdmiCecMessageBuilderTest {
assertThat(message).isEqualTo(buildMessage("5F:81:21:00"));
}
+ @Test
+ public void buildSetOsdName_short() {
+ String deviceName = "abc";
+ HdmiCecMessage message = HdmiCecMessageBuilder.buildSetOsdNameCommand(ADDR_PLAYBACK_1,
+ ADDR_TV, deviceName);
+ assertThat(message).isEqualTo(buildMessage("40:47:61:62:63"));
+ }
+
+ @Test
+ public void buildSetOsdName_maximumLength() {
+ String deviceName = "abcdefghijklmn";
+ HdmiCecMessage message = HdmiCecMessageBuilder.buildSetOsdNameCommand(ADDR_PLAYBACK_1,
+ ADDR_TV, deviceName);
+ assertThat(message).isEqualTo(
+ buildMessage("40:47:61:62:63:64:65:66:67:68:69:6A:6B:6C:6D:6E"));
+ }
+
+ @Test
+ public void buildSetOsdName_tooLong() {
+ String deviceName = "abcdefghijklmnop";
+ HdmiCecMessage message = HdmiCecMessageBuilder.buildSetOsdNameCommand(ADDR_PLAYBACK_1,
+ ADDR_TV, deviceName);
+ assertThat(message).isEqualTo(
+ buildMessage("40:47:61:62:63:64:65:66:67:68:69:6A:6B:6C:6D:6E"));
+ }
+
/**
* Build a CEC message from a hex byte string with bytes separated by {@code :}.
*
diff --git a/services/tests/servicestests/src/com/android/server/hdmi/HdmiControlServiceTest.java b/services/tests/servicestests/src/com/android/server/hdmi/HdmiControlServiceTest.java
index 775e88750cef..31cf59ee7bde 100644
--- a/services/tests/servicestests/src/com/android/server/hdmi/HdmiControlServiceTest.java
+++ b/services/tests/servicestests/src/com/android/server/hdmi/HdmiControlServiceTest.java
@@ -63,7 +63,7 @@ import java.util.ArrayList;
@RunWith(JUnit4.class)
public class HdmiControlServiceTest {
- private class HdmiCecLocalDeviceMyDevice extends HdmiCecLocalDevice {
+ private class HdmiCecLocalDeviceMyDevice extends HdmiCecLocalDeviceSource {
private boolean mCanGoToStandby;
private boolean mIsStandby;
@@ -405,6 +405,83 @@ public class HdmiControlServiceTest {
assertThat(callback2.mVolumeControlEnabled).isTrue();
}
+ @Test
+ public void setActiveSource_localDevice_playback() {
+ int physicalAddress = 0x1000;
+ mNativeWrapper.setPhysicalAddress(physicalAddress);
+
+ mHdmiControlService.setActiveSource(mMyPlaybackDevice.mAddress, physicalAddress,
+ "HdmiControlServiceTest");
+
+ assertThat(mHdmiControlService.getLocalActiveSource().logicalAddress).isEqualTo(
+ mMyPlaybackDevice.mAddress);
+ assertThat(mHdmiControlService.getLocalActiveSource().physicalAddress).isEqualTo(
+ physicalAddress);
+ assertThat(mMyPlaybackDevice.mIsActiveSource).isTrue();
+ assertThat(mMyAudioSystemDevice.mIsActiveSource).isFalse();
+ }
+
+ @Test
+ public void setActiveSource_localDevice_audio() {
+ int physicalAddress = 0x1000;
+ mNativeWrapper.setPhysicalAddress(physicalAddress);
+
+ mHdmiControlService.setActiveSource(mMyAudioSystemDevice.mAddress, physicalAddress,
+ "HdmiControlServiceTest");
+
+ assertThat(mHdmiControlService.getLocalActiveSource().logicalAddress).isEqualTo(
+ mMyAudioSystemDevice.mAddress);
+ assertThat(mHdmiControlService.getLocalActiveSource().physicalAddress).isEqualTo(
+ physicalAddress);
+ assertThat(mMyPlaybackDevice.mIsActiveSource).isFalse();
+ assertThat(mMyAudioSystemDevice.mIsActiveSource).isTrue();
+ }
+
+ @Test
+ public void setActiveSource_remoteDevice() {
+ int physicalAddress = 0x1000;
+ mNativeWrapper.setPhysicalAddress(physicalAddress);
+
+ mHdmiControlService.setActiveSource(Constants.ADDR_TV, 0x0000, "HdmiControlServiceTest");
+
+ assertThat(mHdmiControlService.getLocalActiveSource().logicalAddress).isEqualTo(
+ Constants.ADDR_TV);
+ assertThat(mHdmiControlService.getLocalActiveSource().physicalAddress).isEqualTo(0x000);
+ assertThat(mMyPlaybackDevice.mIsActiveSource).isFalse();
+ assertThat(mMyAudioSystemDevice.mIsActiveSource).isFalse();
+ }
+
+ @Test
+ public void setActiveSource_nonCecDevice() {
+ int physicalAddress = 0x1000;
+ mNativeWrapper.setPhysicalAddress(physicalAddress);
+
+ mHdmiControlService.setActiveSource(Constants.ADDR_INVALID, 0x1234,
+ "HdmiControlServiceTest");
+
+ assertThat(mHdmiControlService.getLocalActiveSource().logicalAddress).isEqualTo(
+ Constants.ADDR_INVALID);
+ assertThat(mHdmiControlService.getLocalActiveSource().physicalAddress).isEqualTo(0x1234);
+ assertThat(mMyPlaybackDevice.mIsActiveSource).isFalse();
+ assertThat(mMyAudioSystemDevice.mIsActiveSource).isFalse();
+ }
+
+ @Test
+ public void setActiveSource_unknown() {
+ int physicalAddress = 0x1000;
+ mNativeWrapper.setPhysicalAddress(physicalAddress);
+
+ mHdmiControlService.setActiveSource(Constants.ADDR_INVALID,
+ Constants.INVALID_PHYSICAL_ADDRESS, "HdmiControlServiceTest");
+
+ assertThat(mHdmiControlService.getLocalActiveSource().logicalAddress).isEqualTo(
+ Constants.ADDR_INVALID);
+ assertThat(mHdmiControlService.getLocalActiveSource().physicalAddress).isEqualTo(
+ Constants.INVALID_PHYSICAL_ADDRESS);
+ assertThat(mMyPlaybackDevice.mIsActiveSource).isFalse();
+ assertThat(mMyAudioSystemDevice.mIsActiveSource).isFalse();
+ }
+
private static class VolumeControlFeatureCallback extends
IHdmiCecVolumeControlFeatureListener.Stub {
boolean mCallbackReceived = false;
diff --git a/services/tests/servicestests/src/com/android/server/pm/AppsFilterTest.java b/services/tests/servicestests/src/com/android/server/pm/AppsFilterTest.java
index b2512d3ed8ca..eec7d125d219 100644
--- a/services/tests/servicestests/src/com/android/server/pm/AppsFilterTest.java
+++ b/services/tests/servicestests/src/com/android/server/pm/AppsFilterTest.java
@@ -379,7 +379,7 @@ public class AppsFilterTest {
}
@Test
- public void testForceQueryable_DoesntFilter() throws Exception {
+ public void testForceQueryable_SystemDoesntFilter() throws Exception {
final AppsFilter appsFilter =
new AppsFilter(mStateProvider, mFeatureConfigMock, new String[]{}, false, null,
mMockExecutor);
@@ -387,7 +387,8 @@ public class AppsFilterTest {
appsFilter.onSystemReady();
PackageSetting target = simulateAddPackage(appsFilter,
- pkg("com.some.package").setForceQueryable(true), DUMMY_TARGET_APPID);
+ pkg("com.some.package").setForceQueryable(true), DUMMY_TARGET_APPID,
+ setting -> setting.setPkgFlags(ApplicationInfo.FLAG_SYSTEM));
PackageSetting calling = simulateAddPackage(appsFilter,
pkg("com.some.other.package"), DUMMY_CALLING_APPID);
@@ -395,6 +396,24 @@ public class AppsFilterTest {
SYSTEM_USER));
}
+
+ @Test
+ public void testForceQueryable_NonSystemFilters() throws Exception {
+ final AppsFilter appsFilter =
+ new AppsFilter(mStateProvider, mFeatureConfigMock, new String[]{}, false, null,
+ mMockExecutor);
+ simulateAddBasicAndroid(appsFilter);
+ appsFilter.onSystemReady();
+
+ PackageSetting target = simulateAddPackage(appsFilter,
+ pkg("com.some.package").setForceQueryable(true), DUMMY_TARGET_APPID);
+ PackageSetting calling = simulateAddPackage(appsFilter,
+ pkg("com.some.other.package"), DUMMY_CALLING_APPID);
+
+ assertTrue(appsFilter.shouldFilterApplication(DUMMY_CALLING_APPID, calling, target,
+ SYSTEM_USER));
+ }
+
@Test
public void testForceQueryableByDevice_SystemCaller_DoesntFilter() throws Exception {
final AppsFilter appsFilter =
diff --git a/services/tests/servicestests/src/com/android/server/timezonedetector/ConfigurationInternalTest.java b/services/tests/servicestests/src/com/android/server/timezonedetector/ConfigurationInternalTest.java
new file mode 100644
index 000000000000..d7ed96fd5833
--- /dev/null
+++ b/services/tests/servicestests/src/com/android/server/timezonedetector/ConfigurationInternalTest.java
@@ -0,0 +1,182 @@
+/*
+ * 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.timezonedetector;
+
+import static android.app.timezonedetector.TimeZoneCapabilities.CAPABILITY_NOT_ALLOWED;
+import static android.app.timezonedetector.TimeZoneCapabilities.CAPABILITY_NOT_APPLICABLE;
+import static android.app.timezonedetector.TimeZoneCapabilities.CAPABILITY_NOT_SUPPORTED;
+import static android.app.timezonedetector.TimeZoneCapabilities.CAPABILITY_POSSESSED;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertTrue;
+
+import android.app.timezonedetector.TimeZoneCapabilities;
+
+import org.junit.Test;
+
+/**
+ * Tests for {@link ConfigurationInternal} and the {@link TimeZoneCapabilities} and
+ * {@link android.app.timezonedetector.TimeZoneConfiguration} that can be generated from it.
+ */
+public class ConfigurationInternalTest {
+
+ private static final int ARBITRARY_USER_ID = 99999;
+
+ /**
+ * Tests when {@link ConfigurationInternal#isUserConfigAllowed()} and
+ * {@link ConfigurationInternal#isAutoDetectionSupported()} are both true.
+ */
+ @Test
+ public void test_unrestricted() {
+ ConfigurationInternal baseConfig = new ConfigurationInternal.Builder(ARBITRARY_USER_ID)
+ .setUserConfigAllowed(true)
+ .setAutoDetectionSupported(true)
+ .setAutoDetectionEnabled(true)
+ .setLocationEnabled(true)
+ .setGeoDetectionEnabled(true)
+ .build();
+ {
+ ConfigurationInternal autoOnConfig = new ConfigurationInternal.Builder(baseConfig)
+ .setAutoDetectionEnabled(true)
+ .build();
+ assertTrue(autoOnConfig.getAutoDetectionEnabledSetting());
+ assertTrue(autoOnConfig.getGeoDetectionEnabledSetting());
+ assertTrue(autoOnConfig.getAutoDetectionEnabledBehavior());
+ assertTrue(autoOnConfig.getGeoDetectionEnabledBehavior());
+
+ TimeZoneCapabilities capabilities = autoOnConfig.createCapabilities();
+ assertEquals(CAPABILITY_POSSESSED, capabilities.getConfigureAutoDetectionEnabled());
+ assertEquals(CAPABILITY_POSSESSED, capabilities.getConfigureGeoDetectionEnabled());
+ assertEquals(CAPABILITY_NOT_APPLICABLE, capabilities.getSuggestManualTimeZone());
+ assertEquals(autoOnConfig.asConfiguration(), capabilities.getConfiguration());
+ assertTrue(capabilities.getConfiguration().isAutoDetectionEnabled());
+ assertTrue(capabilities.getConfiguration().isGeoDetectionEnabled());
+ }
+
+ {
+ ConfigurationInternal autoOffConfig = new ConfigurationInternal.Builder(baseConfig)
+ .setAutoDetectionEnabled(false)
+ .build();
+ assertFalse(autoOffConfig.getAutoDetectionEnabledSetting());
+ assertTrue(autoOffConfig.getGeoDetectionEnabledSetting());
+ assertFalse(autoOffConfig.getAutoDetectionEnabledBehavior());
+ assertFalse(autoOffConfig.getGeoDetectionEnabledBehavior());
+
+ TimeZoneCapabilities capabilities = autoOffConfig.createCapabilities();
+ assertEquals(CAPABILITY_POSSESSED, capabilities.getConfigureAutoDetectionEnabled());
+ assertEquals(CAPABILITY_POSSESSED, capabilities.getConfigureGeoDetectionEnabled());
+ assertEquals(CAPABILITY_POSSESSED, capabilities.getSuggestManualTimeZone());
+ assertEquals(autoOffConfig.asConfiguration(), capabilities.getConfiguration());
+ assertFalse(capabilities.getConfiguration().isAutoDetectionEnabled());
+ assertTrue(capabilities.getConfiguration().isGeoDetectionEnabled());
+ }
+ }
+
+ /** Tests when {@link ConfigurationInternal#isUserConfigAllowed()} is false */
+ @Test
+ public void test_restricted() {
+ ConfigurationInternal baseConfig = new ConfigurationInternal.Builder(ARBITRARY_USER_ID)
+ .setUserConfigAllowed(false)
+ .setAutoDetectionSupported(true)
+ .setAutoDetectionEnabled(true)
+ .setLocationEnabled(true)
+ .setGeoDetectionEnabled(true)
+ .build();
+ {
+ ConfigurationInternal autoOnConfig = new ConfigurationInternal.Builder(baseConfig)
+ .setAutoDetectionEnabled(true)
+ .build();
+ assertTrue(autoOnConfig.getAutoDetectionEnabledSetting());
+ assertTrue(autoOnConfig.getGeoDetectionEnabledSetting());
+ assertTrue(autoOnConfig.getAutoDetectionEnabledBehavior());
+ assertTrue(autoOnConfig.getGeoDetectionEnabledBehavior());
+
+ TimeZoneCapabilities capabilities = autoOnConfig.createCapabilities();
+ assertEquals(CAPABILITY_NOT_ALLOWED, capabilities.getConfigureAutoDetectionEnabled());
+ assertEquals(CAPABILITY_NOT_ALLOWED, capabilities.getConfigureGeoDetectionEnabled());
+ assertEquals(CAPABILITY_NOT_ALLOWED, capabilities.getSuggestManualTimeZone());
+ assertEquals(autoOnConfig.asConfiguration(), capabilities.getConfiguration());
+ assertTrue(capabilities.getConfiguration().isAutoDetectionEnabled());
+ assertTrue(capabilities.getConfiguration().isGeoDetectionEnabled());
+ }
+
+ {
+ ConfigurationInternal autoOffConfig = new ConfigurationInternal.Builder(baseConfig)
+ .setAutoDetectionEnabled(false)
+ .build();
+ assertFalse(autoOffConfig.getAutoDetectionEnabledSetting());
+ assertTrue(autoOffConfig.getGeoDetectionEnabledSetting());
+ assertFalse(autoOffConfig.getAutoDetectionEnabledBehavior());
+ assertFalse(autoOffConfig.getGeoDetectionEnabledBehavior());
+
+ TimeZoneCapabilities capabilities = autoOffConfig.createCapabilities();
+ assertEquals(CAPABILITY_NOT_ALLOWED, capabilities.getConfigureAutoDetectionEnabled());
+ assertEquals(CAPABILITY_NOT_ALLOWED, capabilities.getConfigureGeoDetectionEnabled());
+ assertEquals(CAPABILITY_NOT_ALLOWED, capabilities.getSuggestManualTimeZone());
+ assertEquals(autoOffConfig.asConfiguration(), capabilities.getConfiguration());
+ assertFalse(capabilities.getConfiguration().isAutoDetectionEnabled());
+ assertTrue(capabilities.getConfiguration().isGeoDetectionEnabled());
+ }
+ }
+
+ /** Tests when {@link ConfigurationInternal#isAutoDetectionSupported()} is false. */
+ @Test
+ public void test_autoDetectNotSupported() {
+ ConfigurationInternal baseConfig = new ConfigurationInternal.Builder(ARBITRARY_USER_ID)
+ .setUserConfigAllowed(true)
+ .setAutoDetectionSupported(false)
+ .setAutoDetectionEnabled(true)
+ .setLocationEnabled(true)
+ .setGeoDetectionEnabled(true)
+ .build();
+ {
+ ConfigurationInternal autoOnConfig = new ConfigurationInternal.Builder(baseConfig)
+ .setAutoDetectionEnabled(true)
+ .build();
+ assertTrue(autoOnConfig.getAutoDetectionEnabledSetting());
+ assertTrue(autoOnConfig.getGeoDetectionEnabledSetting());
+ assertFalse(autoOnConfig.getAutoDetectionEnabledBehavior());
+ assertFalse(autoOnConfig.getGeoDetectionEnabledBehavior());
+
+ TimeZoneCapabilities capabilities = autoOnConfig.createCapabilities();
+ assertEquals(CAPABILITY_NOT_SUPPORTED, capabilities.getConfigureAutoDetectionEnabled());
+ assertEquals(CAPABILITY_NOT_SUPPORTED, capabilities.getConfigureGeoDetectionEnabled());
+ assertEquals(CAPABILITY_POSSESSED, capabilities.getSuggestManualTimeZone());
+ assertEquals(autoOnConfig.asConfiguration(), capabilities.getConfiguration());
+ assertTrue(capabilities.getConfiguration().isAutoDetectionEnabled());
+ assertTrue(capabilities.getConfiguration().isGeoDetectionEnabled());
+ }
+ {
+ ConfigurationInternal autoOffConfig = new ConfigurationInternal.Builder(baseConfig)
+ .setAutoDetectionEnabled(false)
+ .build();
+ assertFalse(autoOffConfig.getAutoDetectionEnabledSetting());
+ assertTrue(autoOffConfig.getGeoDetectionEnabledSetting());
+ assertFalse(autoOffConfig.getAutoDetectionEnabledBehavior());
+ assertFalse(autoOffConfig.getGeoDetectionEnabledBehavior());
+
+ TimeZoneCapabilities capabilities = autoOffConfig.createCapabilities();
+ assertEquals(CAPABILITY_NOT_SUPPORTED, capabilities.getConfigureAutoDetectionEnabled());
+ assertEquals(CAPABILITY_NOT_SUPPORTED, capabilities.getConfigureGeoDetectionEnabled());
+ assertEquals(CAPABILITY_POSSESSED, capabilities.getSuggestManualTimeZone());
+ assertEquals(autoOffConfig.asConfiguration(), capabilities.getConfiguration());
+ assertFalse(capabilities.getConfiguration().isAutoDetectionEnabled());
+ assertTrue(capabilities.getConfiguration().isGeoDetectionEnabled());
+ }
+ }
+}
diff --git a/services/tests/servicestests/src/com/android/server/timezonedetector/FakeTimeZoneDetectorStrategy.java b/services/tests/servicestests/src/com/android/server/timezonedetector/FakeTimeZoneDetectorStrategy.java
index e5e931115c05..4ef20829f2dc 100644
--- a/services/tests/servicestests/src/com/android/server/timezonedetector/FakeTimeZoneDetectorStrategy.java
+++ b/services/tests/servicestests/src/com/android/server/timezonedetector/FakeTimeZoneDetectorStrategy.java
@@ -18,6 +18,7 @@ package com.android.server.timezonedetector;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertTrue;
+import static org.junit.Assert.fail;
import android.annotation.NonNull;
import android.annotation.UserIdInt;
@@ -32,56 +33,64 @@ import java.util.List;
class FakeTimeZoneDetectorStrategy implements TimeZoneDetectorStrategy {
- private StrategyListener mListener;
+ private ConfigurationChangeListener mConfigurationChangeListener;
// Fake state
- private TimeZoneCapabilities mCapabilities;
- private TimeZoneConfiguration mConfiguration;
+ private ConfigurationInternal mConfigurationInternal;
// Call tracking.
private GeolocationTimeZoneSuggestion mLastGeolocationSuggestion;
private ManualTimeZoneSuggestion mLastManualSuggestion;
private TelephonyTimeZoneSuggestion mLastTelephonySuggestion;
- private boolean mHandleAutoTimeZoneConfigChangedCalled;
private boolean mDumpCalled;
private final List<Dumpable> mDumpables = new ArrayList<>();
@Override
- public void setStrategyListener(@NonNull StrategyListener listener) {
- mListener = listener;
+ public void addConfigChangeListener(@NonNull ConfigurationChangeListener listener) {
+ if (mConfigurationChangeListener != null) {
+ fail("Fake only supports one listener");
+ }
+ mConfigurationChangeListener = listener;
+ }
+
+ @Override
+ public ConfigurationInternal getConfigurationInternal(int userId) {
+ if (mConfigurationInternal.getUserId() != userId) {
+ fail("Fake only supports one user");
+ }
+ return mConfigurationInternal;
}
@Override
- public TimeZoneCapabilities getCapabilities(@UserIdInt int userId) {
- return mCapabilities;
+ public ConfigurationInternal getCurrentUserConfigurationInternal() {
+ return mConfigurationInternal;
}
@Override
- public boolean updateConfiguration(
- @UserIdInt int userId, @NonNull TimeZoneConfiguration configuration) {
- assertNotNull(mConfiguration);
- assertNotNull(configuration);
-
- // Simulate the strategy's behavior: the new configuration will be the old configuration
- // merged with the new.
- TimeZoneConfiguration oldConfiguration = mConfiguration;
- TimeZoneConfiguration newConfiguration =
- new TimeZoneConfiguration.Builder(mConfiguration)
- .mergeProperties(configuration)
- .build();
-
- if (newConfiguration.equals(oldConfiguration)) {
+ public boolean updateConfiguration(@NonNull TimeZoneConfiguration requestedChanges) {
+ assertNotNull(mConfigurationInternal);
+ assertNotNull(requestedChanges);
+
+ // Simulate the real strategy's behavior: the new configuration will be updated to be the
+ // old configuration merged with the new if the user has the capability to up the settings.
+ // Then, if the configuration changed, the change listener is invoked.
+ TimeZoneCapabilities capabilities = mConfigurationInternal.createCapabilities();
+ TimeZoneConfiguration newConfiguration = capabilities.applyUpdate(requestedChanges);
+ if (newConfiguration == null) {
return false;
}
- mConfiguration = newConfiguration;
- mListener.onConfigurationChanged();
+
+ if (!newConfiguration.equals(capabilities.getConfiguration())) {
+ mConfigurationInternal = mConfigurationInternal.merge(newConfiguration);
+
+ // Note: Unlike the real strategy, the listeners is invoked synchronously.
+ mConfigurationChangeListener.onChange();
+ }
return true;
}
- @Override
- @NonNull
- public TimeZoneConfiguration getConfiguration(@UserIdInt int userId) {
- return mConfiguration;
+ public void simulateConfigurationChangeForTests() {
+ mConfigurationChangeListener.onChange();
}
@Override
@@ -103,11 +112,6 @@ class FakeTimeZoneDetectorStrategy implements TimeZoneDetectorStrategy {
}
@Override
- public void handleAutoTimeZoneConfigChanged() {
- mHandleAutoTimeZoneConfigChangedCalled = true;
- }
-
- @Override
public void addDumpable(Dumpable dumpable) {
mDumpables.add(dumpable);
}
@@ -117,19 +121,14 @@ class FakeTimeZoneDetectorStrategy implements TimeZoneDetectorStrategy {
mDumpCalled = true;
}
- void initializeConfiguration(TimeZoneConfiguration configuration) {
- mConfiguration = configuration;
- }
-
- void initializeCapabilities(TimeZoneCapabilities capabilities) {
- mCapabilities = capabilities;
+ void initializeConfiguration(ConfigurationInternal configurationInternal) {
+ mConfigurationInternal = configurationInternal;
}
void resetCallTracking() {
mLastGeolocationSuggestion = null;
mLastManualSuggestion = null;
mLastTelephonySuggestion = null;
- mHandleAutoTimeZoneConfigChangedCalled = false;
mDumpCalled = false;
}
@@ -146,10 +145,6 @@ class FakeTimeZoneDetectorStrategy implements TimeZoneDetectorStrategy {
assertEquals(expectedSuggestion, mLastTelephonySuggestion);
}
- void verifyHandleAutoTimeZoneConfigChangedCalled() {
- assertTrue(mHandleAutoTimeZoneConfigChangedCalled);
- }
-
void verifyDumpCalled() {
assertTrue(mDumpCalled);
}
diff --git a/services/tests/servicestests/src/com/android/server/timezonedetector/TestCallerIdentityInjector.java b/services/tests/servicestests/src/com/android/server/timezonedetector/TestCallerIdentityInjector.java
new file mode 100644
index 000000000000..f45b3a822f1a
--- /dev/null
+++ b/services/tests/servicestests/src/com/android/server/timezonedetector/TestCallerIdentityInjector.java
@@ -0,0 +1,53 @@
+/*
+ * 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 com.android.server.timezonedetector;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNotNull;
+
+import android.annotation.UserIdInt;
+
+/** A fake {@link CallerIdentityInjector} used in tests. */
+public class TestCallerIdentityInjector implements CallerIdentityInjector {
+
+ private long mToken = 9999L;
+ private int mCallingUserId;
+ private Integer mCurrentCallingUserId;
+
+ public void initializeCallingUserId(@UserIdInt int userId) {
+ mCallingUserId = userId;
+ mCurrentCallingUserId = userId;
+ }
+
+ @Override
+ public int getCallingUserId() {
+ assertNotNull("callingUserId has been cleared", mCurrentCallingUserId);
+ return mCurrentCallingUserId;
+ }
+
+ @Override
+ public long clearCallingIdentity() {
+ mCurrentCallingUserId = null;
+ return mToken;
+ }
+
+ @Override
+ public void restoreCallingIdentity(long token) {
+ assertEquals(token, mToken);
+ mCurrentCallingUserId = mCallingUserId;
+ }
+}
diff --git a/services/tests/servicestests/src/com/android/server/timezonedetector/TimeZoneDetectorInternalImplTest.java b/services/tests/servicestests/src/com/android/server/timezonedetector/TimeZoneDetectorInternalImplTest.java
index e9d57e52ce69..918babca677e 100644
--- a/services/tests/servicestests/src/com/android/server/timezonedetector/TimeZoneDetectorInternalImplTest.java
+++ b/services/tests/servicestests/src/com/android/server/timezonedetector/TimeZoneDetectorInternalImplTest.java
@@ -16,6 +16,7 @@
package com.android.server.timezonedetector;
+import static org.junit.Assert.assertTrue;
import static org.mockito.Mockito.mock;
import android.content.Context;
@@ -85,6 +86,18 @@ public class TimeZoneDetectorInternalImplTest {
mFakeTimeZoneDetectorStrategy.verifyHasDumpable(stubbedDumpable);
}
+ @Test
+ public void testAddConfigurationListener() throws Exception {
+ boolean[] changeCalled = new boolean[2];
+ mTimeZoneDetectorInternal.addConfigurationListener(() -> changeCalled[0] = true);
+ mTimeZoneDetectorInternal.addConfigurationListener(() -> changeCalled[1] = true);
+
+ mFakeTimeZoneDetectorStrategy.simulateConfigurationChangeForTests();
+
+ assertTrue(changeCalled[0]);
+ assertTrue(changeCalled[1]);
+ }
+
private static GeolocationTimeZoneSuggestion createGeolocationTimeZoneSuggestion() {
return new GeolocationTimeZoneSuggestion(ARBITRARY_ZONE_IDS);
}
diff --git a/services/tests/servicestests/src/com/android/server/timezonedetector/TimeZoneDetectorServiceTest.java b/services/tests/servicestests/src/com/android/server/timezonedetector/TimeZoneDetectorServiceTest.java
index 3a1ec4f90d7a..27b04b6ab17d 100644
--- a/services/tests/servicestests/src/com/android/server/timezonedetector/TimeZoneDetectorServiceTest.java
+++ b/services/tests/servicestests/src/com/android/server/timezonedetector/TimeZoneDetectorServiceTest.java
@@ -16,8 +16,6 @@
package com.android.server.timezonedetector;
-import static android.app.timezonedetector.TimeZoneCapabilities.CAPABILITY_POSSESSED;
-
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.fail;
import static org.mockito.ArgumentMatchers.any;
@@ -36,7 +34,6 @@ import static org.mockito.Mockito.when;
import android.app.timezonedetector.ITimeZoneConfigurationListener;
import android.app.timezonedetector.ManualTimeZoneSuggestion;
import android.app.timezonedetector.TelephonyTimeZoneSuggestion;
-import android.app.timezonedetector.TimeZoneCapabilities;
import android.app.timezonedetector.TimeZoneConfiguration;
import android.content.Context;
import android.content.pm.PackageManager;
@@ -65,6 +62,7 @@ public class TimeZoneDetectorServiceTest {
private TimeZoneDetectorService mTimeZoneDetectorService;
private HandlerThread mHandlerThread;
private TestHandler mTestHandler;
+ private TestCallerIdentityInjector mTestCallerIdentityInjector;
@Before
@@ -76,10 +74,14 @@ public class TimeZoneDetectorServiceTest {
mHandlerThread.start();
mTestHandler = new TestHandler(mHandlerThread.getLooper());
+ mTestCallerIdentityInjector = new TestCallerIdentityInjector();
+ mTestCallerIdentityInjector.initializeCallingUserId(ARBITRARY_USER_ID);
+
mFakeTimeZoneDetectorStrategy = new FakeTimeZoneDetectorStrategy();
mTimeZoneDetectorService = new TimeZoneDetectorService(
- mMockContext, mTestHandler, mFakeTimeZoneDetectorStrategy);
+ mMockContext, mTestHandler, mTestCallerIdentityInjector,
+ mFakeTimeZoneDetectorStrategy);
}
@After
@@ -107,40 +109,12 @@ public class TimeZoneDetectorServiceTest {
public void testGetCapabilities() {
doNothing().when(mMockContext).enforceCallingPermission(anyString(), any());
- TimeZoneCapabilities capabilities = createTimeZoneCapabilities();
- mFakeTimeZoneDetectorStrategy.initializeCapabilities(capabilities);
-
- assertEquals(capabilities, mTimeZoneDetectorService.getCapabilities());
-
- verify(mMockContext).enforceCallingPermission(
- eq(android.Manifest.permission.WRITE_SECURE_SETTINGS),
- anyString());
- }
-
- @Test(expected = SecurityException.class)
- public void testGetConfiguration_withoutPermission() {
- doThrow(new SecurityException("Mock"))
- .when(mMockContext).enforceCallingPermission(anyString(), any());
-
- try {
- mTimeZoneDetectorService.getConfiguration();
- fail();
- } finally {
- verify(mMockContext).enforceCallingPermission(
- eq(android.Manifest.permission.WRITE_SECURE_SETTINGS),
- anyString());
- }
- }
-
- @Test
- public void testGetConfiguration() {
- doNothing().when(mMockContext).enforceCallingPermission(anyString(), any());
-
- TimeZoneConfiguration configuration =
- createTimeZoneConfiguration(false /* autoDetectionEnabled */);
+ ConfigurationInternal configuration =
+ createConfigurationInternal(true /* autoDetectionEnabled*/);
mFakeTimeZoneDetectorStrategy.initializeConfiguration(configuration);
- assertEquals(configuration, mTimeZoneDetectorService.getConfiguration());
+ assertEquals(configuration.createCapabilities(),
+ mTimeZoneDetectorService.getCapabilities());
verify(mMockContext).enforceCallingPermission(
eq(android.Manifest.permission.WRITE_SECURE_SETTINGS),
@@ -181,10 +155,9 @@ public class TimeZoneDetectorServiceTest {
@Test
public void testConfigurationChangeListenerRegistrationAndCallbacks() throws Exception {
- TimeZoneConfiguration autoDetectDisabledConfiguration =
- createTimeZoneConfiguration(false /* autoDetectionEnabled */);
-
- mFakeTimeZoneDetectorStrategy.initializeConfiguration(autoDetectDisabledConfiguration);
+ ConfigurationInternal initialConfiguration =
+ createConfigurationInternal(false /* autoDetectionEnabled */);
+ mFakeTimeZoneDetectorStrategy.initializeConfiguration(initialConfiguration);
IBinder mockListenerBinder = mock(IBinder.class);
ITimeZoneConfigurationListener mockListener = mock(ITimeZoneConfigurationListener.class);
@@ -210,13 +183,12 @@ public class TimeZoneDetectorServiceTest {
// Simulate the configuration being changed and verify the mockListener was notified.
TimeZoneConfiguration autoDetectEnabledConfiguration =
createTimeZoneConfiguration(true /* autoDetectionEnabled */);
-
mTimeZoneDetectorService.updateConfiguration(autoDetectEnabledConfiguration);
verify(mMockContext).enforceCallingPermission(
eq(android.Manifest.permission.WRITE_SECURE_SETTINGS),
anyString());
- verify(mockListener).onChange(autoDetectEnabledConfiguration);
+ verify(mockListener).onChange();
verifyNoMoreInteractions(mockListenerBinder, mockListener, mMockContext);
reset(mockListenerBinder, mockListener, mMockContext);
}
@@ -242,12 +214,14 @@ public class TimeZoneDetectorServiceTest {
{
doNothing().when(mMockContext).enforceCallingPermission(anyString(), any());
+ TimeZoneConfiguration autoDetectDisabledConfiguration =
+ createTimeZoneConfiguration(false /* autoDetectionEnabled */);
mTimeZoneDetectorService.updateConfiguration(autoDetectDisabledConfiguration);
verify(mMockContext).enforceCallingPermission(
eq(android.Manifest.permission.WRITE_SECURE_SETTINGS),
anyString());
- verify(mockListener, never()).onChange(any());
+ verify(mockListener, never()).onChange();
verifyNoMoreInteractions(mockListenerBinder, mockListener, mMockContext);
reset(mockListenerBinder, mockListener, mMockContext);
}
@@ -379,33 +353,22 @@ public class TimeZoneDetectorServiceTest {
mFakeTimeZoneDetectorStrategy.verifyDumpCalled();
}
- @Test
- public void testHandleAutoTimeZoneConfigChanged() throws Exception {
- mTimeZoneDetectorService.handleAutoTimeZoneConfigChanged();
- mTestHandler.assertTotalMessagesEnqueued(1);
- mTestHandler.waitForMessagesToBeProcessed();
- mFakeTimeZoneDetectorStrategy.verifyHandleAutoTimeZoneConfigChangedCalled();
-
- mFakeTimeZoneDetectorStrategy.resetCallTracking();
-
- mTimeZoneDetectorService.handleAutoTimeZoneConfigChanged();
- mTestHandler.assertTotalMessagesEnqueued(2);
- mTestHandler.waitForMessagesToBeProcessed();
- mFakeTimeZoneDetectorStrategy.verifyHandleAutoTimeZoneConfigChangedCalled();
- }
-
- private static TimeZoneConfiguration createTimeZoneConfiguration(
- boolean autoDetectionEnabled) {
- return new TimeZoneConfiguration.Builder()
+ private static TimeZoneConfiguration createTimeZoneConfiguration(boolean autoDetectionEnabled) {
+ return new TimeZoneConfiguration.Builder(ARBITRARY_USER_ID)
.setAutoDetectionEnabled(autoDetectionEnabled)
.build();
}
- private static TimeZoneCapabilities createTimeZoneCapabilities() {
- return new TimeZoneCapabilities.Builder(ARBITRARY_USER_ID)
- .setConfigureAutoDetectionEnabled(CAPABILITY_POSSESSED)
- .setConfigureGeoDetectionEnabled(CAPABILITY_POSSESSED)
- .setSuggestManualTimeZone(CAPABILITY_POSSESSED)
+ private static ConfigurationInternal createConfigurationInternal(boolean autoDetectionEnabled) {
+ // Default geo detection settings from auto detection settings - they are not important to
+ // the tests.
+ final boolean geoDetectionEnabled = autoDetectionEnabled;
+ return new ConfigurationInternal.Builder(ARBITRARY_USER_ID)
+ .setAutoDetectionSupported(true)
+ .setUserConfigAllowed(true)
+ .setAutoDetectionEnabled(autoDetectionEnabled)
+ .setLocationEnabled(geoDetectionEnabled)
+ .setGeoDetectionEnabled(geoDetectionEnabled)
.build();
}
diff --git a/services/tests/servicestests/src/com/android/server/timezonedetector/TimeZoneDetectorStrategyImplTest.java b/services/tests/servicestests/src/com/android/server/timezonedetector/TimeZoneDetectorStrategyImplTest.java
index a6caa4299ef6..2bee5e5e7295 100644
--- a/services/tests/servicestests/src/com/android/server/timezonedetector/TimeZoneDetectorStrategyImplTest.java
+++ b/services/tests/servicestests/src/com/android/server/timezonedetector/TimeZoneDetectorStrategyImplTest.java
@@ -23,10 +23,6 @@ import static android.app.timezonedetector.TelephonyTimeZoneSuggestion.MATCH_TYP
import static android.app.timezonedetector.TelephonyTimeZoneSuggestion.QUALITY_MULTIPLE_ZONES_WITH_DIFFERENT_OFFSETS;
import static android.app.timezonedetector.TelephonyTimeZoneSuggestion.QUALITY_MULTIPLE_ZONES_WITH_SAME_OFFSET;
import static android.app.timezonedetector.TelephonyTimeZoneSuggestion.QUALITY_SINGLE_ZONE;
-import static android.app.timezonedetector.TimeZoneCapabilities.CAPABILITY_NOT_ALLOWED;
-import static android.app.timezonedetector.TimeZoneCapabilities.CAPABILITY_NOT_APPLICABLE;
-import static android.app.timezonedetector.TimeZoneCapabilities.CAPABILITY_NOT_SUPPORTED;
-import static android.app.timezonedetector.TimeZoneCapabilities.CAPABILITY_POSSESSED;
import static com.android.server.timezonedetector.TimeZoneDetectorStrategyImpl.TELEPHONY_SCORE_HIGH;
import static com.android.server.timezonedetector.TimeZoneDetectorStrategyImpl.TELEPHONY_SCORE_HIGHEST;
@@ -37,9 +33,9 @@ import static com.android.server.timezonedetector.TimeZoneDetectorStrategyImpl.T
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
-import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertNull;
import static org.junit.Assert.assertTrue;
+import static org.junit.Assert.fail;
import android.annotation.Nullable;
import android.annotation.UserIdInt;
@@ -47,7 +43,6 @@ import android.app.timezonedetector.ManualTimeZoneSuggestion;
import android.app.timezonedetector.TelephonyTimeZoneSuggestion;
import android.app.timezonedetector.TelephonyTimeZoneSuggestion.MatchType;
import android.app.timezonedetector.TelephonyTimeZoneSuggestion.Quality;
-import android.app.timezonedetector.TimeZoneCapabilities;
import android.app.timezonedetector.TimeZoneConfiguration;
import android.util.IndentingPrintWriter;
@@ -61,7 +56,6 @@ import java.util.Arrays;
import java.util.Collections;
import java.util.LinkedList;
import java.util.List;
-import java.util.Objects;
import java.util.concurrent.atomic.AtomicBoolean;
/**
@@ -94,192 +88,149 @@ public class TimeZoneDetectorStrategyImplTest {
TELEPHONY_SCORE_HIGHEST),
};
- private static final TimeZoneConfiguration CONFIG_AUTO_ENABLED =
- new TimeZoneConfiguration.Builder()
+ private static final ConfigurationInternal CONFIG_INT_USER_RESTRICTED_AUTO_DISABLED =
+ new ConfigurationInternal.Builder(USER_ID)
+ .setUserConfigAllowed(false)
+ .setAutoDetectionSupported(true)
+ .setAutoDetectionEnabled(false)
+ .setLocationEnabled(true)
+ .setGeoDetectionEnabled(false)
+ .build();
+
+ private static final ConfigurationInternal CONFIG_INT_USER_RESTRICTED_AUTO_ENABLED =
+ new ConfigurationInternal.Builder(USER_ID)
+ .setUserConfigAllowed(false)
+ .setAutoDetectionSupported(true)
.setAutoDetectionEnabled(true)
+ .setLocationEnabled(true)
+ .setGeoDetectionEnabled(true)
.build();
- private static final TimeZoneConfiguration CONFIG_AUTO_DISABLED =
- new TimeZoneConfiguration.Builder()
+ private static final ConfigurationInternal CONFIG_INT_AUTO_DETECT_NOT_SUPPORTED =
+ new ConfigurationInternal.Builder(USER_ID)
+ .setUserConfigAllowed(true)
+ .setAutoDetectionSupported(false)
.setAutoDetectionEnabled(false)
+ .setLocationEnabled(true)
+ .setGeoDetectionEnabled(false)
.build();
- private static final TimeZoneConfiguration CONFIG_GEO_DETECTION_DISABLED =
- new TimeZoneConfiguration.Builder()
+ private static final ConfigurationInternal CONFIG_INT_AUTO_DISABLED_GEO_DISABLED =
+ new ConfigurationInternal.Builder(USER_ID)
+ .setUserConfigAllowed(true)
+ .setAutoDetectionSupported(true)
+ .setAutoDetectionEnabled(false)
+ .setLocationEnabled(true)
.setGeoDetectionEnabled(false)
.build();
- private static final TimeZoneConfiguration CONFIG_GEO_DETECTION_ENABLED =
- new TimeZoneConfiguration.Builder()
+ private static final ConfigurationInternal CONFIG_INT_AUTO_DISABLED_GEO_ENABLED =
+ new ConfigurationInternal.Builder(USER_ID)
+ .setUserConfigAllowed(true)
+ .setAutoDetectionSupported(true)
+ .setAutoDetectionEnabled(false)
+ .setLocationEnabled(true)
.setGeoDetectionEnabled(true)
.build();
+ private static final ConfigurationInternal CONFIG_INT_AUTO_ENABLED_GEO_DISABLED =
+ new ConfigurationInternal.Builder(USER_ID)
+ .setAutoDetectionSupported(true)
+ .setUserConfigAllowed(true)
+ .setAutoDetectionEnabled(true)
+ .setLocationEnabled(true)
+ .setGeoDetectionEnabled(false)
+ .build();
+
+ private static final ConfigurationInternal CONFIG_INT_AUTO_ENABLED_GEO_ENABLED =
+ new ConfigurationInternal.Builder(USER_ID)
+ .setAutoDetectionSupported(true)
+ .setUserConfigAllowed(true)
+ .setAutoDetectionEnabled(true)
+ .setLocationEnabled(true)
+ .setGeoDetectionEnabled(true)
+ .build();
+
+ private static final TimeZoneConfiguration CONFIG_AUTO_DISABLED =
+ createConfig(false /* autoDetection */, null);
+ private static final TimeZoneConfiguration CONFIG_AUTO_ENABLED =
+ createConfig(true /* autoDetection */, null);
+ private static final TimeZoneConfiguration CONFIG_GEO_DETECTION_ENABLED =
+ createConfig(null, true /* geoDetection */);
+ private static final TimeZoneConfiguration CONFIG_GEO_DETECTION_DISABLED =
+ createConfig(null, false /* geoDetection */);
+
private TimeZoneDetectorStrategyImpl mTimeZoneDetectorStrategy;
private FakeCallback mFakeCallback;
- private MockStrategyListener mMockStrategyListener;
+ private MockConfigChangeListener mMockConfigChangeListener;
+
@Before
public void setUp() {
mFakeCallback = new FakeCallback();
- mMockStrategyListener = new MockStrategyListener();
+ mMockConfigChangeListener = new MockConfigChangeListener();
mTimeZoneDetectorStrategy = new TimeZoneDetectorStrategyImpl(mFakeCallback);
- mFakeCallback.setStrategyForSettingsCallbacks(mTimeZoneDetectorStrategy);
- mTimeZoneDetectorStrategy.setStrategyListener(mMockStrategyListener);
- }
-
- @Test
- public void testGetCapabilities() {
- new Script()
- .initializeUser(USER_ID, UserCase.UNRESTRICTED,
- CONFIG_AUTO_ENABLED.with(CONFIG_GEO_DETECTION_DISABLED));
- TimeZoneCapabilities expectedCapabilities = mFakeCallback.getCapabilities(USER_ID);
- assertEquals(expectedCapabilities, mTimeZoneDetectorStrategy.getCapabilities(USER_ID));
+ mTimeZoneDetectorStrategy.addConfigChangeListener(mMockConfigChangeListener);
}
@Test
- public void testGetConfiguration() {
- new Script()
- .initializeUser(USER_ID, UserCase.UNRESTRICTED,
- CONFIG_AUTO_ENABLED.with(CONFIG_GEO_DETECTION_DISABLED));
- TimeZoneConfiguration expectedConfiguration = mFakeCallback.getConfiguration(USER_ID);
- assertTrue(expectedConfiguration.isComplete());
- assertEquals(expectedConfiguration, mTimeZoneDetectorStrategy.getConfiguration(USER_ID));
- }
-
- @Test
- public void testCapabilitiesTestInfra_unrestricted() {
- Script script = new Script();
-
- script.initializeUser(USER_ID, UserCase.UNRESTRICTED,
- CONFIG_AUTO_ENABLED.with(CONFIG_GEO_DETECTION_DISABLED));
- {
- // Check the fake test infra is doing what is expected.
- TimeZoneCapabilities capabilities = mFakeCallback.getCapabilities(USER_ID);
- assertEquals(CAPABILITY_POSSESSED, capabilities.getConfigureAutoDetectionEnabled());
- assertEquals(CAPABILITY_POSSESSED, capabilities.getConfigureGeoDetectionEnabled());
- assertEquals(CAPABILITY_NOT_APPLICABLE, capabilities.getSuggestManualTimeZone());
- }
-
- script.initializeUser(USER_ID, UserCase.UNRESTRICTED,
- CONFIG_AUTO_DISABLED.with(CONFIG_GEO_DETECTION_DISABLED));
- {
- // Check the fake test infra is doing what is expected.
- TimeZoneCapabilities capabilities = mFakeCallback.getCapabilities(USER_ID);
- assertEquals(CAPABILITY_POSSESSED, capabilities.getConfigureAutoDetectionEnabled());
- assertEquals(CAPABILITY_POSSESSED, capabilities.getConfigureGeoDetectionEnabled());
- assertEquals(CAPABILITY_POSSESSED, capabilities.getSuggestManualTimeZone());
- }
- }
-
- @Test
- public void testCapabilitiesTestInfra_restricted() {
- Script script = new Script();
-
- script.initializeUser(USER_ID, UserCase.RESTRICTED,
- CONFIG_AUTO_ENABLED.with(CONFIG_GEO_DETECTION_DISABLED));
- {
- // Check the fake test infra is doing what is expected.
- TimeZoneCapabilities capabilities = mFakeCallback.getCapabilities(USER_ID);
- assertEquals(CAPABILITY_NOT_ALLOWED, capabilities.getConfigureAutoDetectionEnabled());
- assertEquals(CAPABILITY_NOT_ALLOWED, capabilities.getConfigureGeoDetectionEnabled());
- assertEquals(CAPABILITY_NOT_ALLOWED, capabilities.getSuggestManualTimeZone());
- }
-
- script.initializeUser(USER_ID, UserCase.RESTRICTED,
- CONFIG_AUTO_DISABLED.with(CONFIG_GEO_DETECTION_DISABLED));
- {
- // Check the fake test infra is doing what is expected.
- TimeZoneCapabilities capabilities = mFakeCallback.getCapabilities(USER_ID);
- assertEquals(CAPABILITY_NOT_ALLOWED, capabilities.getConfigureAutoDetectionEnabled());
- assertEquals(CAPABILITY_NOT_ALLOWED, capabilities.getConfigureGeoDetectionEnabled());
- assertEquals(CAPABILITY_NOT_ALLOWED, capabilities.getSuggestManualTimeZone());
- }
- }
-
- @Test
- public void testCapabilitiesTestInfra_autoDetectNotSupported() {
- Script script = new Script();
-
- script.initializeUser(USER_ID, UserCase.AUTO_DETECT_NOT_SUPPORTED,
- CONFIG_AUTO_ENABLED.with(CONFIG_GEO_DETECTION_DISABLED));
- {
- // Check the fake test infra is doing what is expected.
- TimeZoneCapabilities capabilities = mFakeCallback.getCapabilities(USER_ID);
- assertEquals(CAPABILITY_NOT_SUPPORTED, capabilities.getConfigureAutoDetectionEnabled());
- assertEquals(CAPABILITY_NOT_SUPPORTED, capabilities.getConfigureGeoDetectionEnabled());
- assertEquals(CAPABILITY_POSSESSED, capabilities.getSuggestManualTimeZone());
- }
-
- script.initializeUser(USER_ID, UserCase.AUTO_DETECT_NOT_SUPPORTED,
- CONFIG_AUTO_DISABLED.with(CONFIG_GEO_DETECTION_DISABLED));
- {
- // Check the fake test infra is doing what is expected.
- TimeZoneCapabilities capabilities = mFakeCallback.getCapabilities(USER_ID);
- assertEquals(CAPABILITY_NOT_SUPPORTED, capabilities.getConfigureAutoDetectionEnabled());
- assertEquals(CAPABILITY_NOT_SUPPORTED, capabilities.getConfigureGeoDetectionEnabled());
- assertEquals(CAPABILITY_POSSESSED, capabilities.getSuggestManualTimeZone());
- }
+ public void testGetCurrentUserConfiguration() {
+ new Script().initializeConfig(CONFIG_INT_AUTO_ENABLED_GEO_DISABLED);
+ ConfigurationInternal expectedConfiguration =
+ mFakeCallback.getConfigurationInternal(USER_ID);
+ assertEquals(expectedConfiguration,
+ mTimeZoneDetectorStrategy.getCurrentUserConfigurationInternal());
}
@Test
public void testUpdateConfiguration_unrestricted() {
- Script script = new Script()
- .initializeUser(USER_ID, UserCase.UNRESTRICTED,
- CONFIG_AUTO_ENABLED.with(CONFIG_GEO_DETECTION_DISABLED));
+ Script script = new Script().initializeConfig(CONFIG_INT_AUTO_ENABLED_GEO_DISABLED);
// Set the configuration with auto detection enabled.
- script.simulateUpdateConfiguration(USER_ID, CONFIG_AUTO_ENABLED, true /* expectedResult */);
+ script.simulateUpdateConfiguration(CONFIG_AUTO_ENABLED, true /* expectedResult */);
// Nothing should have happened: it was initialized in this state.
script.verifyConfigurationNotChanged();
// Update the configuration with auto detection disabled.
- script.simulateUpdateConfiguration(
- USER_ID, CONFIG_AUTO_DISABLED, true /* expectedResult */);
+ script.simulateUpdateConfiguration(CONFIG_AUTO_DISABLED, true /* expectedResult */);
// The settings should have been changed and the StrategyListener onChange() called.
- script.verifyConfigurationChangedAndReset(USER_ID,
- CONFIG_AUTO_DISABLED.with(CONFIG_GEO_DETECTION_DISABLED));
+ script.verifyConfigurationChangedAndReset(CONFIG_INT_AUTO_DISABLED_GEO_DISABLED);
// Update the configuration with auto detection enabled.
- script.simulateUpdateConfiguration(USER_ID, CONFIG_AUTO_ENABLED, true /* expectedResult */);
+ script.simulateUpdateConfiguration(CONFIG_AUTO_ENABLED, true /* expectedResult */);
// The settings should have been changed and the StrategyListener onChange() called.
- script.verifyConfigurationChangedAndReset(USER_ID,
- CONFIG_AUTO_ENABLED.with(CONFIG_GEO_DETECTION_DISABLED));
+ script.verifyConfigurationChangedAndReset(CONFIG_INT_AUTO_ENABLED_GEO_DISABLED);
// Update the configuration to enable geolocation time zone detection.
script.simulateUpdateConfiguration(
- USER_ID, CONFIG_GEO_DETECTION_ENABLED, true /* expectedResult */);
+ CONFIG_GEO_DETECTION_ENABLED, true /* expectedResult */);
// The settings should have been changed and the StrategyListener onChange() called.
- script.verifyConfigurationChangedAndReset(USER_ID,
- CONFIG_AUTO_ENABLED.with(CONFIG_GEO_DETECTION_ENABLED));
+ script.verifyConfigurationChangedAndReset(CONFIG_INT_AUTO_ENABLED_GEO_ENABLED);
}
@Test
public void testUpdateConfiguration_restricted() {
- Script script = new Script()
- .initializeUser(USER_ID, UserCase.RESTRICTED,
- CONFIG_AUTO_ENABLED.with(CONFIG_GEO_DETECTION_DISABLED));
+ Script script = new Script().initializeConfig(CONFIG_INT_USER_RESTRICTED_AUTO_ENABLED);
// Try to update the configuration with auto detection disabled.
- script.simulateUpdateConfiguration(
- USER_ID, CONFIG_AUTO_DISABLED, false /* expectedResult */);
+ script.simulateUpdateConfiguration(CONFIG_AUTO_DISABLED, false /* expectedResult */);
// The settings should not have been changed: user shouldn't have the capabilities.
script.verifyConfigurationNotChanged();
// Update the configuration with auto detection enabled.
- script.simulateUpdateConfiguration(
- USER_ID, CONFIG_AUTO_ENABLED, false /* expectedResult */);
+ script.simulateUpdateConfiguration(CONFIG_AUTO_ENABLED, false /* expectedResult */);
// The settings should not have been changed: user shouldn't have the capabilities.
script.verifyConfigurationNotChanged();
- // Update the configuration to enable geolocation time zone detection.
+ // Try to update the configuration to enable geolocation time zone detection.
script.simulateUpdateConfiguration(
- USER_ID, CONFIG_GEO_DETECTION_ENABLED, false /* expectedResult */);
+ CONFIG_GEO_DETECTION_ENABLED, false /* expectedResult */);
// The settings should not have been changed: user shouldn't have the capabilities.
script.verifyConfigurationNotChanged();
@@ -287,20 +238,16 @@ public class TimeZoneDetectorStrategyImplTest {
@Test
public void testUpdateConfiguration_autoDetectNotSupported() {
- Script script = new Script()
- .initializeUser(USER_ID, UserCase.AUTO_DETECT_NOT_SUPPORTED,
- CONFIG_AUTO_ENABLED.with(CONFIG_GEO_DETECTION_DISABLED));
+ Script script = new Script().initializeConfig(CONFIG_INT_AUTO_DETECT_NOT_SUPPORTED);
// Try to update the configuration with auto detection disabled.
- script.simulateUpdateConfiguration(
- USER_ID, CONFIG_AUTO_DISABLED, false /* expectedResult */);
+ script.simulateUpdateConfiguration(CONFIG_AUTO_DISABLED, false /* expectedResult */);
// The settings should not have been changed: user shouldn't have the capabilities.
script.verifyConfigurationNotChanged();
// Update the configuration with auto detection enabled.
- script.simulateUpdateConfiguration(
- USER_ID, CONFIG_AUTO_ENABLED, false /* expectedResult */);
+ script.simulateUpdateConfiguration(CONFIG_AUTO_ENABLED, false /* expectedResult */);
// The settings should not have been changed: user shouldn't have the capabilities.
script.verifyConfigurationNotChanged();
@@ -313,8 +260,7 @@ public class TimeZoneDetectorStrategyImplTest {
TelephonyTimeZoneSuggestion slotIndex2TimeZoneSuggestion =
createEmptySlotIndex2Suggestion();
Script script = new Script()
- .initializeUser(USER_ID, UserCase.UNRESTRICTED,
- CONFIG_AUTO_ENABLED.with(CONFIG_GEO_DETECTION_DISABLED))
+ .initializeConfig(CONFIG_INT_AUTO_ENABLED_GEO_DISABLED)
.initializeTimeZoneSetting(ARBITRARY_TIME_ZONE_ID);
script.simulateTelephonyTimeZoneSuggestion(slotIndex1TimeZoneSuggestion)
@@ -359,9 +305,7 @@ public class TimeZoneDetectorStrategyImplTest {
TelephonyTestCase testCase2 = newTelephonyTestCase(MATCH_TYPE_NETWORK_COUNTRY_ONLY,
QUALITY_SINGLE_ZONE, TELEPHONY_SCORE_HIGH);
- Script script = new Script()
- .initializeUser(USER_ID, UserCase.UNRESTRICTED,
- CONFIG_AUTO_ENABLED.with(CONFIG_GEO_DETECTION_DISABLED));
+ Script script = new Script().initializeConfig(CONFIG_INT_AUTO_ENABLED_GEO_DISABLED);
// A low quality suggestions will not be taken: The device time zone setting is left
// uninitialized.
@@ -426,8 +370,7 @@ public class TimeZoneDetectorStrategyImplTest {
for (TelephonyTestCase testCase : TELEPHONY_TEST_CASES) {
// Start with the device in a known state.
- script.initializeUser(USER_ID, UserCase.UNRESTRICTED,
- CONFIG_AUTO_DISABLED.with(CONFIG_GEO_DETECTION_DISABLED))
+ script.initializeConfig(CONFIG_INT_AUTO_DISABLED_GEO_DISABLED)
.initializeTimeZoneSetting(ARBITRARY_TIME_ZONE_ID);
TelephonyTimeZoneSuggestion suggestion =
@@ -447,8 +390,7 @@ public class TimeZoneDetectorStrategyImplTest {
mTimeZoneDetectorStrategy.findBestTelephonySuggestionForTests());
// Toggling the time zone setting on should cause the device setting to be set.
- script.simulateUpdateConfiguration(USER_ID, CONFIG_AUTO_ENABLED,
- true /* expectedResult */);
+ script.simulateUpdateConfiguration(CONFIG_AUTO_ENABLED, true /* expectedResult */);
// When time zone detection is already enabled the suggestion (if it scores highly
// enough) should be set immediately.
@@ -465,8 +407,7 @@ public class TimeZoneDetectorStrategyImplTest {
mTimeZoneDetectorStrategy.findBestTelephonySuggestionForTests());
// Toggling the time zone setting should off should do nothing.
- script.simulateUpdateConfiguration(
- USER_ID, CONFIG_AUTO_DISABLED, true /* expectedResult */)
+ script.simulateUpdateConfiguration(CONFIG_AUTO_DISABLED, true /* expectedResult */)
.verifyTimeZoneNotChanged();
// Assert internal service state.
@@ -480,8 +421,7 @@ public class TimeZoneDetectorStrategyImplTest {
@Test
public void testTelephonySuggestionsSingleSlotId() {
Script script = new Script()
- .initializeUser(USER_ID, UserCase.UNRESTRICTED,
- CONFIG_AUTO_ENABLED.with(CONFIG_GEO_DETECTION_DISABLED))
+ .initializeConfig(CONFIG_INT_AUTO_ENABLED_GEO_DISABLED)
.initializeTimeZoneSetting(ARBITRARY_TIME_ZONE_ID);
for (TelephonyTestCase testCase : TELEPHONY_TEST_CASES) {
@@ -546,8 +486,7 @@ public class TimeZoneDetectorStrategyImplTest {
TELEPHONY_SCORE_NONE);
Script script = new Script()
- .initializeUser(USER_ID, UserCase.UNRESTRICTED,
- CONFIG_AUTO_ENABLED.with(CONFIG_GEO_DETECTION_DISABLED))
+ .initializeConfig(CONFIG_INT_AUTO_ENABLED_GEO_DISABLED)
.initializeTimeZoneSetting(ARBITRARY_TIME_ZONE_ID)
// Initialize the latest suggestions as empty so we don't need to worry about nulls
// below for the first loop.
@@ -632,9 +571,7 @@ public class TimeZoneDetectorStrategyImplTest {
*/
@Test
public void testTelephonySuggestionStrategyDoesNotAssumeCurrentSetting_autoTelephony() {
- Script script = new Script()
- .initializeUser(USER_ID, UserCase.UNRESTRICTED,
- CONFIG_AUTO_ENABLED.with(CONFIG_GEO_DETECTION_DISABLED));
+ Script script = new Script().initializeConfig(CONFIG_INT_AUTO_ENABLED_GEO_DISABLED);
TelephonyTestCase testCase = newTelephonyTestCase(
MATCH_TYPE_NETWORK_COUNTRY_AND_OFFSET, QUALITY_SINGLE_ZONE, TELEPHONY_SCORE_HIGH);
@@ -652,40 +589,39 @@ public class TimeZoneDetectorStrategyImplTest {
// Toggling time zone detection should set the device time zone only if the current setting
// value is different from the most recent telephony suggestion.
- script.simulateUpdateConfiguration(USER_ID, CONFIG_AUTO_DISABLED, true /* expectedResult */)
+ script.simulateUpdateConfiguration(CONFIG_AUTO_DISABLED, true /* expectedResult */)
.verifyTimeZoneNotChanged()
- .simulateUpdateConfiguration(
- USER_ID, CONFIG_AUTO_ENABLED, true /* expectedResult */)
+ .simulateUpdateConfiguration(CONFIG_AUTO_ENABLED, true /* expectedResult */)
.verifyTimeZoneNotChanged();
// Simulate a user turning auto detection off, a new suggestion being made while auto
// detection is off, and the user turning it on again.
- script.simulateUpdateConfiguration(USER_ID, CONFIG_AUTO_DISABLED, true /* expectedResult */)
+ script.simulateUpdateConfiguration(CONFIG_AUTO_DISABLED, true /* expectedResult */)
.simulateTelephonyTimeZoneSuggestion(newYorkSuggestion)
.verifyTimeZoneNotChanged();
// Latest suggestion should be used.
- script.simulateUpdateConfiguration(USER_ID, CONFIG_AUTO_ENABLED, true /* expectedResult */)
+ script.simulateUpdateConfiguration(CONFIG_AUTO_ENABLED, true /* expectedResult */)
.verifyTimeZoneChangedAndReset(newYorkSuggestion);
}
@Test
- public void testManualSuggestion_autoDetectionEnabled_autoTelephony() {
- checkManualSuggestion_autoDetectionEnabled(false /* geoDetectionEnabled */);
+ public void testManualSuggestion_unrestricted_autoDetectionEnabled_autoTelephony() {
+ checkManualSuggestion_unrestricted_autoDetectionEnabled(false /* geoDetectionEnabled */);
}
@Test
- public void testManualSuggestion_autoDetectionEnabled_autoGeo() {
- checkManualSuggestion_autoDetectionEnabled(true /* geoDetectionEnabled */);
+ public void testManualSuggestion_unrestricted_autoDetectionEnabled_autoGeo() {
+ checkManualSuggestion_unrestricted_autoDetectionEnabled(true /* geoDetectionEnabled */);
}
- private void checkManualSuggestion_autoDetectionEnabled(boolean geoDetectionEnabled) {
- TimeZoneConfiguration geoTzEnabledConfig =
- new TimeZoneConfiguration.Builder()
+ private void checkManualSuggestion_unrestricted_autoDetectionEnabled(
+ boolean geoDetectionEnabled) {
+ ConfigurationInternal geoTzEnabledConfig =
+ new ConfigurationInternal.Builder(CONFIG_INT_AUTO_ENABLED_GEO_DISABLED)
.setGeoDetectionEnabled(geoDetectionEnabled)
.build();
Script script = new Script()
- .initializeUser(USER_ID, UserCase.UNRESTRICTED,
- CONFIG_AUTO_ENABLED.with(geoTzEnabledConfig))
+ .initializeConfig(geoTzEnabledConfig)
.initializeTimeZoneSetting(ARBITRARY_TIME_ZONE_ID);
// Auto time zone detection is enabled so the manual suggestion should be ignored.
@@ -697,35 +633,19 @@ public class TimeZoneDetectorStrategyImplTest {
@Test
public void testManualSuggestion_restricted_simulateAutoTimeZoneEnabled() {
Script script = new Script()
- .initializeUser(USER_ID, UserCase.RESTRICTED,
- CONFIG_AUTO_ENABLED.with(CONFIG_GEO_DETECTION_DISABLED))
+ .initializeConfig(CONFIG_INT_USER_RESTRICTED_AUTO_ENABLED)
.initializeTimeZoneSetting(ARBITRARY_TIME_ZONE_ID);
- // Auto time zone detection is enabled so the manual suggestion should be ignored.
+ // User is restricted so the manual suggestion should be ignored.
script.simulateManualTimeZoneSuggestion(
USER_ID, createManualSuggestion("Europe/Paris"), false /* expectedResult */)
- .verifyTimeZoneNotChanged();
- }
-
- @Test
- public void testManualSuggestion_autoDetectNotSupported_simulateAutoTimeZoneEnabled() {
- Script script = new Script()
- .initializeUser(USER_ID, UserCase.AUTO_DETECT_NOT_SUPPORTED,
- CONFIG_AUTO_ENABLED.with(CONFIG_GEO_DETECTION_DISABLED))
- .initializeTimeZoneSetting(ARBITRARY_TIME_ZONE_ID);
-
- // Auto time zone detection is enabled so the manual suggestion should be ignored.
- ManualTimeZoneSuggestion manualSuggestion = createManualSuggestion("Europe/Paris");
- script.simulateManualTimeZoneSuggestion(
- USER_ID, manualSuggestion, true /* expectedResult */)
- .verifyTimeZoneChangedAndReset(manualSuggestion);
+ .verifyTimeZoneNotChanged();
}
@Test
public void testManualSuggestion_unrestricted_autoTimeZoneDetectionDisabled() {
Script script = new Script()
- .initializeUser(USER_ID, UserCase.UNRESTRICTED,
- CONFIG_AUTO_DISABLED.with(CONFIG_GEO_DETECTION_DISABLED))
+ .initializeConfig(CONFIG_INT_AUTO_DISABLED_GEO_DISABLED)
.initializeTimeZoneSetting(ARBITRARY_TIME_ZONE_ID);
// Auto time zone detection is disabled so the manual suggestion should be used.
@@ -738,8 +658,7 @@ public class TimeZoneDetectorStrategyImplTest {
@Test
public void testManualSuggestion_restricted_autoTimeZoneDetectionDisabled() {
Script script = new Script()
- .initializeUser(USER_ID, UserCase.RESTRICTED,
- CONFIG_AUTO_DISABLED.with(CONFIG_GEO_DETECTION_DISABLED))
+ .initializeConfig(CONFIG_INT_USER_RESTRICTED_AUTO_DISABLED)
.initializeTimeZoneSetting(ARBITRARY_TIME_ZONE_ID);
// Restricted users do not have the capability.
@@ -750,10 +669,9 @@ public class TimeZoneDetectorStrategyImplTest {
}
@Test
- public void testManualSuggestion_autoDetectNotSupported_autoTimeZoneDetectionDisabled() {
+ public void testManualSuggestion_autoDetectNotSupported() {
Script script = new Script()
- .initializeUser(USER_ID, UserCase.AUTO_DETECT_NOT_SUPPORTED,
- CONFIG_AUTO_DISABLED.with(CONFIG_GEO_DETECTION_DISABLED))
+ .initializeConfig(CONFIG_INT_AUTO_DETECT_NOT_SUPPORTED)
.initializeTimeZoneSetting(ARBITRARY_TIME_ZONE_ID);
// Unrestricted users have the capability.
@@ -765,9 +683,7 @@ public class TimeZoneDetectorStrategyImplTest {
@Test
public void testGeoSuggestion_uncertain() {
- Script script = new Script()
- .initializeUser(USER_ID, UserCase.UNRESTRICTED,
- CONFIG_AUTO_ENABLED.with(CONFIG_GEO_DETECTION_ENABLED))
+ Script script = new Script().initializeConfig(CONFIG_INT_AUTO_ENABLED_GEO_ENABLED)
.initializeTimeZoneSetting(ARBITRARY_TIME_ZONE_ID);
GeolocationTimeZoneSuggestion uncertainSuggestion = createUncertainGeoLocationSuggestion();
@@ -783,8 +699,7 @@ public class TimeZoneDetectorStrategyImplTest {
@Test
public void testGeoSuggestion_noZones() {
Script script = new Script()
- .initializeUser(USER_ID, UserCase.UNRESTRICTED,
- CONFIG_AUTO_ENABLED.with(CONFIG_GEO_DETECTION_ENABLED))
+ .initializeConfig(CONFIG_INT_AUTO_ENABLED_GEO_ENABLED)
.initializeTimeZoneSetting(ARBITRARY_TIME_ZONE_ID);
GeolocationTimeZoneSuggestion noZonesSuggestion = createGeoLocationSuggestion(list());
@@ -802,8 +717,7 @@ public class TimeZoneDetectorStrategyImplTest {
createGeoLocationSuggestion(list("Europe/London"));
Script script = new Script()
- .initializeUser(USER_ID, UserCase.UNRESTRICTED,
- CONFIG_AUTO_ENABLED.with(CONFIG_GEO_DETECTION_ENABLED))
+ .initializeConfig(CONFIG_INT_AUTO_ENABLED_GEO_ENABLED)
.initializeTimeZoneSetting(ARBITRARY_TIME_ZONE_ID);
script.simulateGeolocationTimeZoneSuggestion(suggestion)
@@ -828,8 +742,7 @@ public class TimeZoneDetectorStrategyImplTest {
createGeoLocationSuggestion(list("Europe/Paris"));
Script script = new Script()
- .initializeUser(USER_ID, UserCase.UNRESTRICTED,
- CONFIG_AUTO_ENABLED.with(CONFIG_GEO_DETECTION_ENABLED))
+ .initializeConfig(CONFIG_INT_AUTO_ENABLED_GEO_ENABLED)
.initializeTimeZoneSetting(ARBITRARY_TIME_ZONE_ID);
script.simulateGeolocationTimeZoneSuggestion(londonOnlySuggestion)
@@ -856,72 +769,27 @@ public class TimeZoneDetectorStrategyImplTest {
mTimeZoneDetectorStrategy.getLatestGeolocationSuggestion());
}
- /**
- * Confirms that toggling the auto time zone detection enabled setting has the expected behavior
- * when the strategy is "opinionated" and "un-opinionated" when in geolocation detection is
- * enabled.
- */
@Test
- public void testTogglingAutoDetectionEnabled_autoGeo() {
- GeolocationTimeZoneSuggestion geolocationSuggestion =
+ public void testGeoSuggestion_togglingGeoDetectionClearsLastSuggestion() {
+ GeolocationTimeZoneSuggestion suggestion =
createGeoLocationSuggestion(list("Europe/London"));
- GeolocationTimeZoneSuggestion uncertainGeolocationSuggestion =
- createUncertainGeoLocationSuggestion();
- ManualTimeZoneSuggestion manualSuggestion = createManualSuggestion("Europe/Paris");
Script script = new Script()
- .initializeUser(USER_ID, UserCase.UNRESTRICTED,
- CONFIG_AUTO_DISABLED.with(CONFIG_GEO_DETECTION_ENABLED))
+ .initializeConfig(CONFIG_INT_AUTO_ENABLED_GEO_ENABLED)
.initializeTimeZoneSetting(ARBITRARY_TIME_ZONE_ID);
- script.simulateGeolocationTimeZoneSuggestion(geolocationSuggestion);
-
- // When time zone detection is not enabled, the time zone suggestion will not be set.
- script.verifyTimeZoneNotChanged();
-
- // Assert internal service state.
- assertEquals(geolocationSuggestion,
- mTimeZoneDetectorStrategy.getLatestGeolocationSuggestion());
-
- // Toggling the time zone setting on should cause the device setting to be set.
- script.simulateUpdateConfiguration(USER_ID, CONFIG_AUTO_ENABLED, true /* expectedResult */)
+ script.simulateGeolocationTimeZoneSuggestion(suggestion)
.verifyTimeZoneChangedAndReset("Europe/London");
- // Toggling the time zone setting should off should do nothing because the device is now
- // set to that time zone.
- script.simulateUpdateConfiguration(USER_ID, CONFIG_AUTO_DISABLED, true /* expectedResult */)
- .verifyTimeZoneNotChanged()
- .simulateUpdateConfiguration(
- USER_ID, CONFIG_AUTO_ENABLED, true /* expectedResult */)
- .verifyTimeZoneNotChanged();
-
- // Now toggle auto time zone setting, and confirm it is opinionated.
- script.simulateUpdateConfiguration(USER_ID, CONFIG_AUTO_DISABLED, true /* expectedResult */)
- .simulateManualTimeZoneSuggestion(
- USER_ID, manualSuggestion, true /* expectedResult */)
- .verifyTimeZoneChangedAndReset(manualSuggestion)
- .simulateUpdateConfiguration(
- USER_ID, CONFIG_AUTO_ENABLED, true /* expectedResult */)
- .verifyTimeZoneChangedAndReset("Europe/London");
+ // Assert internal service state.
+ assertEquals(suggestion, mTimeZoneDetectorStrategy.getLatestGeolocationSuggestion());
- // Now withdraw the geolocation suggestion, and assert the strategy is no longer
- // opinionated.
- /* expectedResult */
- script.simulateGeolocationTimeZoneSuggestion(uncertainGeolocationSuggestion)
- .verifyTimeZoneNotChanged()
- .simulateUpdateConfiguration(
- USER_ID, CONFIG_AUTO_DISABLED, true /* expectedResult */)
- .verifyTimeZoneNotChanged()
- .simulateManualTimeZoneSuggestion(
- USER_ID, manualSuggestion, true /* expectedResult */)
- .verifyTimeZoneChangedAndReset(manualSuggestion)
- .simulateUpdateConfiguration(
- USER_ID, CONFIG_AUTO_ENABLED, true /* expectedResult */)
- .verifyTimeZoneNotChanged();
+ // Turn off geo detection and verify the latest suggestion is cleared.
+ script.simulateUpdateConfiguration(CONFIG_GEO_DETECTION_DISABLED, true)
+ .verifyConfigurationChangedAndReset(CONFIG_INT_AUTO_ENABLED_GEO_DISABLED);
// Assert internal service state.
- assertEquals(uncertainGeolocationSuggestion,
- mTimeZoneDetectorStrategy.getLatestGeolocationSuggestion());
+ assertNull(mTimeZoneDetectorStrategy.getLatestGeolocationSuggestion());
}
/**
@@ -937,88 +805,48 @@ public class TimeZoneDetectorStrategyImplTest {
"Europe/Paris");
Script script = new Script()
- .initializeUser(USER_ID, UserCase.UNRESTRICTED,
- CONFIG_AUTO_DISABLED.with(CONFIG_GEO_DETECTION_DISABLED))
+ .initializeConfig(CONFIG_INT_AUTO_DISABLED_GEO_DISABLED)
.initializeTimeZoneSetting(ARBITRARY_TIME_ZONE_ID);
// Add suggestions. Nothing should happen as time zone detection is disabled.
script.simulateGeolocationTimeZoneSuggestion(geolocationSuggestion)
.verifyTimeZoneNotChanged();
+
+ // Geolocation suggestions are only stored when geolocation detection is enabled.
+ assertNull(mTimeZoneDetectorStrategy.getLatestGeolocationSuggestion());
+
script.simulateTelephonyTimeZoneSuggestion(telephonySuggestion)
.verifyTimeZoneNotChanged();
- // Assert internal service state.
- assertEquals(geolocationSuggestion,
- mTimeZoneDetectorStrategy.getLatestGeolocationSuggestion());
+ // Telephony suggestions are always stored.
assertEquals(telephonySuggestion,
mTimeZoneDetectorStrategy.getLatestTelephonySuggestion(SLOT_INDEX1).suggestion);
// Toggling the time zone detection enabled setting on should cause the device setting to be
// set from the telephony signal, as we've started with geolocation time zone detection
// disabled.
- script.simulateUpdateConfiguration(USER_ID, CONFIG_AUTO_ENABLED, true /* expectedResult */)
+ script.simulateUpdateConfiguration(CONFIG_AUTO_ENABLED, true /* expectedResult */)
.verifyTimeZoneChangedAndReset(telephonySuggestion);
- // Changing the detection to enable geo detection should cause the device tz setting to
- // change to the geo suggestion.
- script.simulateUpdateConfiguration(
- USER_ID, CONFIG_GEO_DETECTION_ENABLED, true /* expectedResult */)
+ // Changing the detection to enable geo detection won't cause the device tz setting to
+ // change because the geo suggestion is empty.
+ script.simulateUpdateConfiguration(CONFIG_GEO_DETECTION_ENABLED, true /* expectedResult */)
+ .verifyTimeZoneNotChanged()
+ .simulateGeolocationTimeZoneSuggestion(geolocationSuggestion)
.verifyTimeZoneChangedAndReset(geolocationSuggestion.getZoneIds().get(0));
// Changing the detection to disable geo detection should cause the device tz setting to
// change to the telephony suggestion.
- script.simulateUpdateConfiguration(
- USER_ID, CONFIG_GEO_DETECTION_DISABLED, true /* expectedResult */)
+ script.simulateUpdateConfiguration(CONFIG_GEO_DETECTION_DISABLED, true /* expectedResult */)
.verifyTimeZoneChangedAndReset(telephonySuggestion);
- }
- /**
- * The {@link TimeZoneDetectorStrategyImpl.Callback} is left to detect whether changing the time
- * zone is actually necessary. This test proves that the strategy doesn't assume it knows the
- * current setting.
- */
- @Test
- public void testTimeZoneDetectorStrategyDoesNotAssumeCurrentSetting_autoGeo() {
- GeolocationTimeZoneSuggestion losAngelesSuggestion =
- createGeoLocationSuggestion(list("America/Los_Angeles"));
- GeolocationTimeZoneSuggestion newYorkSuggestion =
- createGeoLocationSuggestion(list("America/New_York"));
-
- Script script = new Script()
- .initializeUser(USER_ID, UserCase.UNRESTRICTED,
- CONFIG_AUTO_ENABLED.with(CONFIG_GEO_DETECTION_ENABLED));
-
- // Initialization.
- script.simulateGeolocationTimeZoneSuggestion(losAngelesSuggestion)
- .verifyTimeZoneChangedAndReset("America/Los_Angeles");
- // Suggest it again - it should not be set because it is already set.
- script.simulateGeolocationTimeZoneSuggestion(losAngelesSuggestion)
- .verifyTimeZoneNotChanged();
-
- // Toggling time zone detection should set the device time zone only if the current setting
- // value is different from the most recent telephony suggestion.
- /* expectedResult */
- script.simulateUpdateConfiguration(USER_ID, CONFIG_AUTO_DISABLED, true /* expectedResult */)
- .verifyTimeZoneNotChanged()
- .simulateUpdateConfiguration(
- USER_ID, CONFIG_AUTO_ENABLED, true /* expectedResult */)
- .verifyTimeZoneNotChanged();
-
- // Simulate a user turning auto detection off, a new suggestion being made while auto
- // detection is off, and the user turning it on again.
- script.simulateUpdateConfiguration(USER_ID, CONFIG_AUTO_DISABLED, true /* expectedResult */)
- .simulateGeolocationTimeZoneSuggestion(newYorkSuggestion)
- .verifyTimeZoneNotChanged();
- // Latest suggestion should be used.
- script.simulateUpdateConfiguration(USER_ID, CONFIG_AUTO_ENABLED, true /* expectedResult */)
- .verifyTimeZoneChangedAndReset("America/New_York");
+ assertNull(mTimeZoneDetectorStrategy.getLatestGeolocationSuggestion());
}
@Test
public void testAddDumpable() {
new Script()
- .initializeUser(USER_ID, UserCase.UNRESTRICTED,
- CONFIG_AUTO_DISABLED.with(CONFIG_GEO_DETECTION_DISABLED))
+ .initializeConfig(CONFIG_INT_AUTO_DISABLED_GEO_DISABLED)
.initializeTimeZoneSetting(ARBITRARY_TIME_ZONE_ID);
AtomicBoolean dumpCalled = new AtomicBoolean(false);
@@ -1069,25 +897,26 @@ public class TimeZoneDetectorStrategyImplTest {
return suggestion;
}
+ private static TimeZoneConfiguration createConfig(
+ @Nullable Boolean autoDetection, @Nullable Boolean geoDetection) {
+ TimeZoneConfiguration.Builder builder = new TimeZoneConfiguration.Builder(USER_ID);
+ if (autoDetection != null) {
+ builder.setAutoDetectionEnabled(autoDetection);
+ }
+ if (geoDetection != null) {
+ builder.setGeoDetectionEnabled(geoDetection);
+ }
+ return builder.build();
+ }
+
static class FakeCallback implements TimeZoneDetectorStrategyImpl.Callback {
- private TimeZoneCapabilities mCapabilities;
- private final TestState<UserConfiguration> mConfiguration = new TestState<>();
+ private final TestState<ConfigurationInternal> mConfigurationInternal = new TestState<>();
private final TestState<String> mTimeZoneId = new TestState<>();
- private TimeZoneDetectorStrategyImpl mStrategy;
-
- void setStrategyForSettingsCallbacks(TimeZoneDetectorStrategyImpl strategy) {
- assertNotNull(strategy);
- mStrategy = strategy;
- }
+ private ConfigurationChangeListener mConfigChangeListener;
- void initializeUser(@UserIdInt int userId, TimeZoneCapabilities capabilities,
- TimeZoneConfiguration configuration) {
- assertEquals(userId, capabilities.getUserId());
- mCapabilities = capabilities;
- assertTrue("Configuration must be complete when initializing, config=" + configuration,
- configuration.isComplete());
- mConfiguration.init(new UserConfiguration(userId, configuration));
+ void initializeConfig(ConfigurationInternal configurationInternal) {
+ mConfigurationInternal.init(configurationInternal);
}
void initializeTimeZoneSetting(String zoneId) {
@@ -1095,43 +924,22 @@ public class TimeZoneDetectorStrategyImplTest {
}
@Override
- public TimeZoneCapabilities getCapabilities(@UserIdInt int userId) {
- assertEquals(userId, mCapabilities.getUserId());
- return mCapabilities;
+ public void setConfigChangeListener(ConfigurationChangeListener listener) {
+ mConfigChangeListener = listener;
}
@Override
- public TimeZoneConfiguration getConfiguration(@UserIdInt int userId) {
- UserConfiguration latest = mConfiguration.getLatest();
- assertEquals(userId, latest.userId);
- return latest.configuration;
- }
-
- @Override
- public void setConfiguration(@UserIdInt int userId, TimeZoneConfiguration newConfig) {
- assertNotNull(newConfig);
- assertTrue(newConfig.isComplete());
-
- UserConfiguration latestUserConfig = mConfiguration.getLatest();
- assertEquals(userId, latestUserConfig.userId);
- TimeZoneConfiguration oldConfig = latestUserConfig.configuration;
-
- mConfiguration.set(new UserConfiguration(userId, newConfig));
-
- if (!newConfig.equals(oldConfig)) {
- // Simulate what happens when the auto detection configuration is changed.
- mStrategy.handleAutoTimeZoneConfigChanged();
+ public ConfigurationInternal getConfigurationInternal(int userId) {
+ ConfigurationInternal configuration = mConfigurationInternal.getLatest();
+ if (userId != configuration.getUserId()) {
+ fail("FakeCallback does not support multiple users.");
}
+ return configuration;
}
@Override
- public boolean isAutoDetectionEnabled() {
- return mConfiguration.getLatest().configuration.isAutoDetectionEnabled();
- }
-
- @Override
- public boolean isGeoDetectionEnabled() {
- return mConfiguration.getLatest().configuration.isGeoDetectionEnabled();
+ public int getCurrentUserId() {
+ return mConfigurationInternal.getLatest().getUserId();
}
@Override
@@ -1149,9 +957,25 @@ public class TimeZoneDetectorStrategyImplTest {
mTimeZoneId.set(zoneId);
}
+ @Override
+ public void storeConfiguration(TimeZoneConfiguration newConfiguration) {
+ ConfigurationInternal oldConfiguration = mConfigurationInternal.getLatest();
+ if (newConfiguration.getUserId() != oldConfiguration.getUserId()) {
+ fail("FakeCallback does not support multiple users");
+ }
+
+ ConfigurationInternal mergedConfiguration = oldConfiguration.merge(newConfiguration);
+ if (!mergedConfiguration.equals(oldConfiguration)) {
+ mConfigurationInternal.set(mergedConfiguration);
+
+ // Note: Unlike the real callback impl, the listener is invoked synchronously.
+ mConfigChangeListener.onChange();
+ }
+ }
+
void assertKnownUser(int userId) {
- assertEquals(userId, mCapabilities.getUserId());
- assertEquals(userId, mConfiguration.getLatest().userId);
+ assertEquals("FakeCallback does not support multiple users",
+ mConfigurationInternal.getLatest().getUserId(), userId);
}
void assertTimeZoneNotChanged() {
@@ -1166,43 +990,7 @@ public class TimeZoneDetectorStrategyImplTest {
void commitAllChanges() {
mTimeZoneId.commitLatest();
- mConfiguration.commitLatest();
- }
- }
-
- private static final class UserConfiguration {
- public final @UserIdInt int userId;
- public final TimeZoneConfiguration configuration;
-
- UserConfiguration(int userId, TimeZoneConfiguration configuration) {
- this.userId = userId;
- this.configuration = configuration;
- }
-
- @Override
- public boolean equals(Object o) {
- if (this == o) {
- return true;
- }
- if (o == null || getClass() != o.getClass()) {
- return false;
- }
- UserConfiguration that = (UserConfiguration) o;
- return userId == that.userId
- && Objects.equals(configuration, that.configuration);
- }
-
- @Override
- public int hashCode() {
- return Objects.hash(userId, configuration);
- }
-
- @Override
- public String toString() {
- return "UserConfiguration{"
- + "userId=" + userId
- + ", configuration=" + configuration
- + '}';
+ mConfigurationInternal.commitLatest();
}
}
@@ -1255,64 +1043,14 @@ public class TimeZoneDetectorStrategyImplTest {
}
}
- /** Simulated user test cases. */
- enum UserCase {
- /** A catch-all for users that can set auto time zone config. */
- UNRESTRICTED,
- /** A catch-all for users that can't set auto time zone config. */
- RESTRICTED,
- /**
- * Like {@link #UNRESTRICTED}, but auto tz detection is not
- * supported on the device.
- */
- AUTO_DETECT_NOT_SUPPORTED,
- }
-
- /**
- * Creates a {@link TimeZoneCapabilities} object for a user in the specific role with the
- * supplied configuration.
- */
- private static TimeZoneCapabilities createCapabilities(
- int userId, UserCase userCase, TimeZoneConfiguration configuration) {
- switch (userCase) {
- case UNRESTRICTED: {
- int suggestManualTimeZoneCapability = configuration.isAutoDetectionEnabled()
- ? CAPABILITY_NOT_APPLICABLE : CAPABILITY_POSSESSED;
- return new TimeZoneCapabilities.Builder(userId)
- .setConfigureAutoDetectionEnabled(CAPABILITY_POSSESSED)
- .setConfigureGeoDetectionEnabled(CAPABILITY_POSSESSED)
- .setSuggestManualTimeZone(suggestManualTimeZoneCapability)
- .build();
- }
- case RESTRICTED: {
- return new TimeZoneCapabilities.Builder(userId)
- .setConfigureAutoDetectionEnabled(CAPABILITY_NOT_ALLOWED)
- .setConfigureGeoDetectionEnabled(CAPABILITY_NOT_ALLOWED)
- .setSuggestManualTimeZone(CAPABILITY_NOT_ALLOWED)
- .build();
- }
- case AUTO_DETECT_NOT_SUPPORTED: {
- return new TimeZoneCapabilities.Builder(userId)
- .setConfigureAutoDetectionEnabled(CAPABILITY_NOT_SUPPORTED)
- .setConfigureGeoDetectionEnabled(CAPABILITY_NOT_SUPPORTED)
- .setSuggestManualTimeZone(CAPABILITY_POSSESSED)
- .build();
- }
- default:
- throw new AssertionError(userCase + " not recognized");
- }
- }
-
/**
* A "fluent" class allows reuse of code in tests: initialization, simulation and verification
* logic.
*/
private class Script {
- Script initializeUser(
- @UserIdInt int userId, UserCase userCase, TimeZoneConfiguration configuration) {
- TimeZoneCapabilities capabilities = createCapabilities(userId, userCase, configuration);
- mFakeCallback.initializeUser(userId, capabilities, configuration);
+ Script initializeConfig(ConfigurationInternal configuration) {
+ mFakeCallback.initializeConfig(configuration);
return this;
}
@@ -1326,10 +1064,9 @@ public class TimeZoneDetectorStrategyImplTest {
* the return value.
*/
Script simulateUpdateConfiguration(
- @UserIdInt int userId, TimeZoneConfiguration configuration,
- boolean expectedResult) {
+ TimeZoneConfiguration configuration, boolean expectedResult) {
assertEquals(expectedResult,
- mTimeZoneDetectorStrategy.updateConfiguration(userId, configuration));
+ mTimeZoneDetectorStrategy.updateConfiguration(configuration));
return this;
}
@@ -1392,16 +1129,14 @@ public class TimeZoneDetectorStrategyImplTest {
/**
* Verifies that the configuration has been changed to the expected value.
*/
- Script verifyConfigurationChangedAndReset(
- @UserIdInt int userId, TimeZoneConfiguration expected) {
- mFakeCallback.mConfiguration.assertHasBeenSet();
- UserConfiguration expectedUserConfig = new UserConfiguration(userId, expected);
- assertEquals(expectedUserConfig, mFakeCallback.mConfiguration.getLatest());
+ Script verifyConfigurationChangedAndReset(ConfigurationInternal expected) {
+ mFakeCallback.mConfigurationInternal.assertHasBeenSet();
+ assertEquals(expected, mFakeCallback.mConfigurationInternal.getLatest());
mFakeCallback.commitAllChanges();
// Also confirm the listener triggered.
- mMockStrategyListener.verifyOnConfigurationChangedCalled();
- mMockStrategyListener.reset();
+ mMockConfigChangeListener.verifyOnChangeCalled();
+ mMockConfigChangeListener.reset();
return this;
}
@@ -1410,10 +1145,10 @@ public class TimeZoneDetectorStrategyImplTest {
* {@link TimeZoneConfiguration} have been changed.
*/
Script verifyConfigurationNotChanged() {
- mFakeCallback.mConfiguration.assertHasNotBeenSet();
+ mFakeCallback.mConfigurationInternal.assertHasNotBeenSet();
// Also confirm the listener did not trigger.
- mMockStrategyListener.verifyOnConfigurationChangedNotCalled();
+ mMockConfigChangeListener.verifyOnChangeNotCalled();
return this;
}
@@ -1448,24 +1183,24 @@ public class TimeZoneDetectorStrategyImplTest {
return new TelephonyTestCase(matchType, quality, expectedScore);
}
- private static class MockStrategyListener implements TimeZoneDetectorStrategy.StrategyListener {
- private boolean mOnConfigurationChangedCalled;
+ private static class MockConfigChangeListener implements ConfigurationChangeListener {
+ private boolean mOnChangeCalled;
@Override
- public void onConfigurationChanged() {
- mOnConfigurationChangedCalled = true;
+ public void onChange() {
+ mOnChangeCalled = true;
}
- void verifyOnConfigurationChangedCalled() {
- assertTrue(mOnConfigurationChangedCalled);
+ void verifyOnChangeCalled() {
+ assertTrue(mOnChangeCalled);
}
- void verifyOnConfigurationChangedNotCalled() {
- assertFalse(mOnConfigurationChangedCalled);
+ void verifyOnChangeNotCalled() {
+ assertFalse(mOnChangeCalled);
}
void reset() {
- mOnConfigurationChangedCalled = false;
+ mOnChangeCalled = false;
}
}
diff --git a/services/tests/servicestests/src/com/android/server/uri/UriGrantsMockContext.java b/services/tests/servicestests/src/com/android/server/uri/UriGrantsMockContext.java
index d5aee5d208f5..2c719ff9e8b3 100644
--- a/services/tests/servicestests/src/com/android/server/uri/UriGrantsMockContext.java
+++ b/services/tests/servicestests/src/com/android/server/uri/UriGrantsMockContext.java
@@ -120,17 +120,17 @@ public class UriGrantsMockContext extends ContextWrapper {
LocalServices.addService(PackageManagerInternal.class, mPmInternal);
for (int userId : new int[] { USER_PRIMARY, USER_SECONDARY }) {
- when(mPmInternal.getPackageUidInternal(eq(PKG_SOCIAL), anyInt(), eq(userId)))
+ when(mPmInternal.getPackageUid(eq(PKG_SOCIAL), anyInt(), eq(userId)))
.thenReturn(UserHandle.getUid(userId, UID_SOCIAL));
- when(mPmInternal.getPackageUidInternal(eq(PKG_CAMERA), anyInt(), eq(userId)))
+ when(mPmInternal.getPackageUid(eq(PKG_CAMERA), anyInt(), eq(userId)))
.thenReturn(UserHandle.getUid(userId, UID_CAMERA));
- when(mPmInternal.getPackageUidInternal(eq(PKG_PRIVATE), anyInt(), eq(userId)))
+ when(mPmInternal.getPackageUid(eq(PKG_PRIVATE), anyInt(), eq(userId)))
.thenReturn(UserHandle.getUid(userId, UID_PRIVATE));
- when(mPmInternal.getPackageUidInternal(eq(PKG_PUBLIC), anyInt(), eq(userId)))
+ when(mPmInternal.getPackageUid(eq(PKG_PUBLIC), anyInt(), eq(userId)))
.thenReturn(UserHandle.getUid(userId, UID_PUBLIC));
- when(mPmInternal.getPackageUidInternal(eq(PKG_FORCE), anyInt(), eq(userId)))
+ when(mPmInternal.getPackageUid(eq(PKG_FORCE), anyInt(), eq(userId)))
.thenReturn(UserHandle.getUid(userId, UID_FORCE));
- when(mPmInternal.getPackageUidInternal(eq(PKG_COMPLEX), anyInt(), eq(userId)))
+ when(mPmInternal.getPackageUid(eq(PKG_COMPLEX), anyInt(), eq(userId)))
.thenReturn(UserHandle.getUid(userId, UID_COMPLEX));
when(mPmInternal.resolveContentProvider(eq(PKG_CAMERA), anyInt(), eq(userId)))
diff --git a/services/tests/uiservicestests/src/com/android/server/notification/ManagedServicesTest.java b/services/tests/uiservicestests/src/com/android/server/notification/ManagedServicesTest.java
index 99433a6603c9..d7e431f3bb51 100644
--- a/services/tests/uiservicestests/src/com/android/server/notification/ManagedServicesTest.java
+++ b/services/tests/uiservicestests/src/com/android/server/notification/ManagedServicesTest.java
@@ -978,6 +978,7 @@ public class ManagedServicesTest extends UiServiceTestCase {
assertFalse(services.isSameUser(service, 0));
assertTrue(services.isSameUser(service, 10));
+ assertTrue(services.isSameUser(service, UserHandle.USER_ALL));
}
@Test
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 ab4dc476ff20..5796e848ff6e 100644
--- a/services/tests/uiservicestests/src/com/android/server/notification/NotificationAssistantsTest.java
+++ b/services/tests/uiservicestests/src/com/android/server/notification/NotificationAssistantsTest.java
@@ -103,7 +103,7 @@ public class NotificationAssistantsTest extends UiServiceTestCase {
when(mUm.getUserInfo(eq(user.id))).thenReturn(user);
}
when(mUm.getUsers()).thenReturn(users);
- when(mUm.getUsers(anyBoolean())).thenReturn(users);
+ when(mUm.getAliveUsers()).thenReturn(users);
IntArray profileIds = new IntArray();
profileIds.add(0);
profileIds.add(11);
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 9319bea497fb..86447192a441 100755
--- a/services/tests/uiservicestests/src/com/android/server/notification/NotificationManagerServiceTest.java
+++ b/services/tests/uiservicestests/src/com/android/server/notification/NotificationManagerServiceTest.java
@@ -5058,7 +5058,7 @@ public class NotificationManagerServiceTest extends UiServiceTestCase {
10, 10, r.getKey(), actionIndex, action, notificationVisibility,
generatedByAssistant);
verify(mAssistants).notifyAssistantActionClicked(
- eq(r.getSbn()), eq(actionIndex), eq(action), eq(generatedByAssistant));
+ eq(r.getSbn()), eq(action), eq(generatedByAssistant));
assertEquals(1, mNotificationRecordLogger.numCalls());
assertEquals(
@@ -5082,7 +5082,7 @@ public class NotificationManagerServiceTest extends UiServiceTestCase {
10, 10, r.getKey(), actionIndex, action, notificationVisibility,
generatedByAssistant);
verify(mAssistants).notifyAssistantActionClicked(
- eq(r.getSbn()), eq(actionIndex), eq(action), eq(generatedByAssistant));
+ eq(r.getSbn()), eq(action), eq(generatedByAssistant));
assertEquals(1, mNotificationRecordLogger.numCalls());
assertEquals(
@@ -6948,4 +6948,63 @@ public class NotificationManagerServiceTest extends UiServiceTestCase {
assertEquals(NotificationManagerService.MAX_PACKAGE_NOTIFICATIONS + 1,
mService.getNotificationRecordCount());
}
+
+ @Test
+ public void testIsVisibleToListener_notEnabled() {
+ StatusBarNotification sbn = mock(StatusBarNotification.class);
+ when(sbn.getUserId()).thenReturn(10);
+ ManagedServices.ManagedServiceInfo info = mock(ManagedServices.ManagedServiceInfo.class);
+ ManagedServices.ManagedServiceInfo assistant = mock(ManagedServices.ManagedServiceInfo.class);
+ info.userid = 10;
+ when(info.isSameUser(anyInt())).thenReturn(true);
+ when(assistant.isSameUser(anyInt())).thenReturn(true);
+ when(info.enabledAndUserMatches(info.userid)).thenReturn(false);
+ when(mAssistants.checkServiceTokenLocked(any())).thenReturn(assistant);
+
+ assertFalse(mService.isVisibleToListener(sbn, info));
+ }
+
+ @Test
+ public void testIsVisibleToListener_noAssistant() {
+ StatusBarNotification sbn = mock(StatusBarNotification.class);
+ when(sbn.getUserId()).thenReturn(10);
+ ManagedServices.ManagedServiceInfo info = mock(ManagedServices.ManagedServiceInfo.class);
+ info.userid = 10;
+ when(info.isSameUser(anyInt())).thenReturn(true);
+ when(info.enabledAndUserMatches(info.userid)).thenReturn(true);
+ when(mAssistants.checkServiceTokenLocked(any())).thenReturn(null);
+
+ assertTrue(mService.isVisibleToListener(sbn, info));
+ }
+
+ @Test
+ public void testIsVisibleToListener_assistant_differentUser() {
+ StatusBarNotification sbn = mock(StatusBarNotification.class);
+ when(sbn.getUserId()).thenReturn(10);
+ ManagedServices.ManagedServiceInfo info = mock(ManagedServices.ManagedServiceInfo.class);
+ ManagedServices.ManagedServiceInfo assistant = mock(ManagedServices.ManagedServiceInfo.class);
+ info.userid = 0;
+ when(info.isSameUser(anyInt())).thenReturn(true);
+ when(assistant.isSameUser(anyInt())).thenReturn(true);
+ when(info.enabledAndUserMatches(info.userid)).thenReturn(true);
+ when(mAssistants.checkServiceTokenLocked(any())).thenReturn(assistant);
+
+ assertFalse(mService.isVisibleToListener(sbn, info));
+ }
+
+ @Test
+ public void testIsVisibleToListener_assistant_sameUser() {
+ StatusBarNotification sbn = mock(StatusBarNotification.class);
+ when(sbn.getUserId()).thenReturn(10);
+ ManagedServices.ManagedServiceInfo info = mock(ManagedServices.ManagedServiceInfo.class);
+ ManagedServices.ManagedServiceInfo assistant = mock(ManagedServices.ManagedServiceInfo.class);
+ info.userid = 10;
+ when(info.isSameUser(anyInt())).thenReturn(true);
+ when(assistant.isSameUser(anyInt())).thenReturn(true);
+ when(info.enabledAndUserMatches(info.userid)).thenReturn(true);
+ when(mAssistants.checkServiceTokenLocked(any())).thenReturn(assistant);
+
+ assertTrue(mService.isVisibleToListener(sbn, info));
+ }
+
}
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 708d802a7533..bca990c659ae 100644
--- a/services/tests/wmtests/src/com/android/server/wm/ActivityRecordTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/ActivityRecordTests.java
@@ -415,12 +415,12 @@ public class ActivityRecordTests extends WindowTestsBase {
public void ignoreRequestedOrientationInFreeformWindows() {
mStack.setWindowingMode(WINDOWING_MODE_FREEFORM);
final Rect stableRect = new Rect();
- mStack.getDisplay().mDisplayContent.getStableRect(stableRect);
+ mStack.mDisplayContent.getStableRect(stableRect);
// Carve out non-decor insets from stableRect
final Rect insets = new Rect();
- final DisplayInfo displayInfo = mStack.getDisplay().getDisplayInfo();
- final DisplayPolicy policy = mStack.getDisplay().getDisplayPolicy();
+ final DisplayInfo displayInfo = mStack.mDisplayContent.getDisplayInfo();
+ final DisplayPolicy policy = mStack.mDisplayContent.getDisplayPolicy();
policy.getNonDecorInsetsLw(displayInfo.rotation, displayInfo.logicalWidth,
displayInfo.logicalHeight, displayInfo.displayCutout, insets);
policy.convertNonDecorInsetsToStableInsets(insets, displayInfo.rotation);
@@ -454,12 +454,12 @@ public class ActivityRecordTests extends WindowTestsBase {
public void ignoreRequestedOrientationInSplitWindows() {
mStack.setWindowingMode(WindowConfiguration.WINDOWING_MODE_SPLIT_SCREEN_PRIMARY);
final Rect stableRect = new Rect();
- mStack.getDisplay().getStableRect(stableRect);
+ mStack.mDisplayContent.getStableRect(stableRect);
// Carve out non-decor insets from stableRect
final Rect insets = new Rect();
- final DisplayInfo displayInfo = mStack.getDisplay().getDisplayInfo();
- final DisplayPolicy policy = mStack.getDisplay().getDisplayPolicy();
+ final DisplayInfo displayInfo = mStack.mDisplayContent.getDisplayInfo();
+ final DisplayPolicy policy = mStack.mDisplayContent.getDisplayPolicy();
policy.getNonDecorInsetsLw(displayInfo.rotation, displayInfo.logicalWidth,
displayInfo.logicalHeight, displayInfo.displayCutout, insets);
policy.convertNonDecorInsetsToStableInsets(insets, displayInfo.rotation);
@@ -844,7 +844,7 @@ public class ActivityRecordTests extends WindowTestsBase {
FINISH_RESULT_REQUESTED, mActivity.finishIfPossible("test", false /* oomAdj */));
assertEquals(PAUSING, mActivity.getState());
verify(mActivity).setVisibility(eq(false));
- verify(mActivity.getDisplay().mDisplayContent)
+ verify(mActivity.mDisplayContent)
.prepareAppTransition(eq(TRANSIT_TASK_CLOSE), eq(false) /* alwaysKeepCurrent */);
}
@@ -888,9 +888,9 @@ public class ActivityRecordTests extends WindowTestsBase {
mActivity.finishIfPossible("test", false /* oomAdj */);
verify(mActivity).setVisibility(eq(false));
- verify(mActivity.getDisplay().mDisplayContent)
+ verify(mActivity.mDisplayContent)
.prepareAppTransition(eq(TRANSIT_TASK_CLOSE), eq(false) /* alwaysKeepCurrent */);
- verify(mActivity.getDisplay().mDisplayContent, never()).executeAppTransition();
+ verify(mActivity.mDisplayContent, never()).executeAppTransition();
}
/**
@@ -904,9 +904,9 @@ public class ActivityRecordTests extends WindowTestsBase {
mActivity.finishIfPossible("test", false /* oomAdj */);
verify(mActivity, atLeast(1)).setVisibility(eq(false));
- verify(mActivity.getDisplay().mDisplayContent)
+ verify(mActivity.mDisplayContent)
.prepareAppTransition(eq(TRANSIT_TASK_CLOSE), eq(false) /* alwaysKeepCurrent */);
- verify(mActivity.getDisplay().mDisplayContent).executeAppTransition();
+ verify(mActivity.mDisplayContent).executeAppTransition();
}
/**
@@ -922,7 +922,7 @@ public class ActivityRecordTests extends WindowTestsBase {
mActivity.finishIfPossible("test", false /* oomAdj */);
- verify(mActivity.getDisplay().mDisplayContent, never())
+ verify(mActivity.mDisplayContent, never())
.prepareAppTransition(eq(TRANSIT_TASK_CLOSE), eq(false) /* alwaysKeepCurrent */);
}
@@ -1166,7 +1166,7 @@ public class ActivityRecordTests extends WindowTestsBase {
// Finish the second activity
secondActivity.finishing = true;
secondActivity.completeFinishing("test");
- verify(secondActivity.getDisplay()).ensureActivitiesVisible(null /* starting */,
+ verify(secondActivity.mDisplayContent).ensureActivitiesVisible(null /* starting */,
0 /* configChanges */ , false /* preserveWindows */,
true /* notifyClients */);
@@ -1174,7 +1174,7 @@ public class ActivityRecordTests extends WindowTestsBase {
firstActivity.finishing = true;
firstActivity.mVisibleRequested = true;
firstActivity.completeFinishing("test");
- verify(firstActivity.getDisplay(), times(2)).ensureActivitiesVisible(null /* starting */,
+ verify(firstActivity.mDisplayContent, times(2)).ensureActivitiesVisible(null /* starting */,
0 /* configChanges */ , false /* preserveWindows */,
true /* notifyClients */);
}
@@ -1190,7 +1190,7 @@ public class ActivityRecordTests extends WindowTestsBase {
assertEquals(DESTROYING, mActivity.getState());
assertTrue(mActivity.finishing);
- verify(mActivity).destroyImmediately(eq(true) /* removeFromApp */, anyString());
+ verify(mActivity).destroyImmediately(anyString());
}
/**
@@ -1214,7 +1214,7 @@ public class ActivityRecordTests extends WindowTestsBase {
// Verify that the activity was not actually destroyed, but waits for next one to come up
// instead.
- verify(mActivity, never()).destroyImmediately(eq(true) /* removeFromApp */, anyString());
+ verify(mActivity, never()).destroyImmediately(anyString());
assertEquals(FINISHING, mActivity.getState());
assertTrue(mActivity.mStackSupervisor.mFinishingActivities.contains(mActivity));
}
@@ -1238,7 +1238,7 @@ public class ActivityRecordTests extends WindowTestsBase {
mActivity.completeFinishing("test");
// Verify that the activity is not destroyed immediately, but waits for next one to come up.
- verify(mActivity, never()).destroyImmediately(eq(true) /* removeFromApp */, anyString());
+ verify(mActivity, never()).destroyImmediately(anyString());
assertEquals(FINISHING, mActivity.getState());
assertTrue(mActivity.mStackSupervisor.mFinishingActivities.contains(mActivity));
}
@@ -1250,26 +1250,26 @@ public class ActivityRecordTests extends WindowTestsBase {
@Test
public void testDestroyImmediately_hadApp_finishing() {
mActivity.finishing = true;
- mActivity.destroyImmediately(false /* removeFromApp */, "test");
+ mActivity.destroyImmediately("test");
assertEquals(DESTROYING, mActivity.getState());
}
/**
* Test that the activity will be moved to destroyed state immediately if it was not marked as
- * finishing before {@link ActivityRecord#destroyImmediately(boolean, String)}.
+ * finishing before {@link ActivityRecord#destroyImmediately(String)}.
*/
@Test
public void testDestroyImmediately_hadApp_notFinishing() {
mActivity.finishing = false;
- mActivity.destroyImmediately(false /* removeFromApp */, "test");
+ mActivity.destroyImmediately("test");
assertEquals(DESTROYED, mActivity.getState());
}
/**
* Test that an activity with no process attached and that is marked as finishing will be
- * removed from task when {@link ActivityRecord#destroyImmediately(boolean, String)} is called.
+ * removed from task when {@link ActivityRecord#destroyImmediately(String)} is called.
*/
@Test
public void testDestroyImmediately_noApp_finishing() {
@@ -1277,7 +1277,7 @@ public class ActivityRecordTests extends WindowTestsBase {
mActivity.finishing = true;
final Task task = mActivity.getTask();
- mActivity.destroyImmediately(false /* removeFromApp */, "test");
+ mActivity.destroyImmediately("test");
assertEquals(DESTROYED, mActivity.getState());
assertNull(mActivity.getTask());
@@ -1294,7 +1294,7 @@ public class ActivityRecordTests extends WindowTestsBase {
mActivity.finishing = false;
final Task task = mActivity.getTask();
- mActivity.destroyImmediately(false /* removeFromApp */, "test");
+ mActivity.destroyImmediately("test");
assertEquals(DESTROYED, mActivity.getState());
assertEquals(task, mActivity.getTask());
@@ -1310,7 +1310,7 @@ public class ActivityRecordTests extends WindowTestsBase {
mActivity.safelyDestroy("test");
- verify(mActivity, never()).destroyImmediately(eq(true) /* removeFromApp */, anyString());
+ verify(mActivity, never()).destroyImmediately(anyString());
}
/**
@@ -1322,7 +1322,7 @@ public class ActivityRecordTests extends WindowTestsBase {
mActivity.safelyDestroy("test");
- verify(mActivity).destroyImmediately(eq(true) /* removeFromApp */, anyString());
+ verify(mActivity).destroyImmediately(anyString());
}
@Test
@@ -1655,13 +1655,13 @@ public class ActivityRecordTests extends WindowTestsBase {
assertEquals(0, thirdActivity.getMergedOverrideConfiguration()
.diff(wpc.getRequestedOverrideConfiguration()));
- secondActivity.destroyImmediately(true, "");
+ secondActivity.destroyImmediately("");
assertTrue(wpc.registeredForActivityConfigChanges());
assertEquals(0, thirdActivity.getMergedOverrideConfiguration()
.diff(wpc.getRequestedOverrideConfiguration()));
- firstActivity.destroyImmediately(true, "");
+ firstActivity.destroyImmediately("");
assertTrue(wpc.registeredForActivityConfigChanges());
assertEquals(0, thirdActivity.getMergedOverrideConfiguration()
@@ -1714,6 +1714,27 @@ public class ActivityRecordTests extends WindowTestsBase {
}
+ @Test
+ public void testProcessInfoUpdateWhenSetState() {
+ spyOn(mActivity.app);
+ verifyProcessInfoUpdate(RESUMED, true /* shouldUpdate */, true /* activityChange */);
+ verifyProcessInfoUpdate(PAUSED, false /* shouldUpdate */, false /* activityChange */);
+ verifyProcessInfoUpdate(STOPPED, false /* shouldUpdate */, false /* activityChange */);
+ verifyProcessInfoUpdate(STARTED, true /* shouldUpdate */, true /* activityChange */);
+
+ mActivity.app.removeActivity(mActivity, true /* keepAssociation */);
+ verifyProcessInfoUpdate(DESTROYING, true /* shouldUpdate */, false /* activityChange */);
+ verifyProcessInfoUpdate(DESTROYED, true /* shouldUpdate */, false /* activityChange */);
+ }
+
+ private void verifyProcessInfoUpdate(ActivityState state, boolean shouldUpdate,
+ boolean activityChange) {
+ reset(mActivity.app);
+ mActivity.setState(state, "test");
+ verify(mActivity.app, times(shouldUpdate ? 1 : 0)).updateProcessInfo(anyBoolean(),
+ eq(activityChange), anyBoolean(), anyBoolean());
+ }
+
/**
* Creates an activity on display. For non-default display request it will also create a new
* display with custom DisplayInfo.
diff --git a/services/tests/wmtests/src/com/android/server/wm/ActivityStackTests.java b/services/tests/wmtests/src/com/android/server/wm/ActivityStackTests.java
index e2948a724acd..524f32deb864 100644
--- a/services/tests/wmtests/src/com/android/server/wm/ActivityStackTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/ActivityStackTests.java
@@ -1202,19 +1202,22 @@ public class ActivityStackTests extends WindowTestsBase {
@Test
public void testShouldSleepActivities() {
// When focused activity and keyguard is going away, we should not sleep regardless
- // of the display state
+ // of the display state, but keyguard-going-away should only take effects on default
+ // display since there is no keyguard on secondary displays (yet).
verifyShouldSleepActivities(true /* focusedStack */, true /*keyguardGoingAway*/,
- true /* displaySleeping */, false /* expected*/);
+ true /* displaySleeping */, true /* isDefaultDisplay */, false /* expected */);
+ verifyShouldSleepActivities(true /* focusedStack */, true /*keyguardGoingAway*/,
+ true /* displaySleeping */, false /* isDefaultDisplay */, true /* expected */);
// When not the focused stack, defer to display sleeping state.
verifyShouldSleepActivities(false /* focusedStack */, true /*keyguardGoingAway*/,
- true /* displaySleeping */, true /* expected*/);
+ true /* displaySleeping */, true /* isDefaultDisplay */, true /* expected */);
// If keyguard is going away, defer to the display sleeping state.
verifyShouldSleepActivities(true /* focusedStack */, false /*keyguardGoingAway*/,
- true /* displaySleeping */, true /* expected*/);
+ true /* displaySleeping */, true /* isDefaultDisplay */, true /* expected */);
verifyShouldSleepActivities(true /* focusedStack */, false /*keyguardGoingAway*/,
- false /* displaySleeping */, false /* expected*/);
+ false /* displaySleeping */, true /* isDefaultDisplay */, false /* expected */);
}
@Test
@@ -1423,11 +1426,13 @@ public class ActivityStackTests extends WindowTestsBase {
}
private void verifyShouldSleepActivities(boolean focusedStack,
- boolean keyguardGoingAway, boolean displaySleeping, boolean expected) {
+ boolean keyguardGoingAway, boolean displaySleeping, boolean isDefaultDisplay,
+ boolean expected) {
final DisplayContent display = mock(DisplayContent.class);
final KeyguardController keyguardController = mSupervisor.getKeyguardController();
+ display.isDefaultDisplay = isDefaultDisplay;
- doReturn(display).when(mStack).getDisplay();
+ mStack.mDisplayContent = display;
doReturn(keyguardGoingAway).when(keyguardController).isKeyguardGoingAway();
doReturn(displaySleeping).when(display).isSleeping();
doReturn(focusedStack).when(mStack).isFocusedStackOnDisplay();
diff --git a/services/tests/wmtests/src/com/android/server/wm/ActivityStarterTests.java b/services/tests/wmtests/src/com/android/server/wm/ActivityStarterTests.java
index e5c9ecc7676d..e537b7c204cc 100644
--- a/services/tests/wmtests/src/com/android/server/wm/ActivityStarterTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/ActivityStarterTests.java
@@ -890,7 +890,7 @@ public class ActivityStarterTests extends WindowTestsBase {
.execute();
// Ensure the activity is moved to secondary display.
- assertEquals(secondaryDisplay, topActivity.getDisplay());
+ assertEquals(secondaryDisplay, topActivity.mDisplayContent);
}
/**
diff --git a/services/tests/wmtests/src/com/android/server/wm/DisplayContentTests.java b/services/tests/wmtests/src/com/android/server/wm/DisplayContentTests.java
index d54b4a0a72f6..f8baf8497069 100644
--- a/services/tests/wmtests/src/com/android/server/wm/DisplayContentTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/DisplayContentTests.java
@@ -1110,7 +1110,7 @@ public class DisplayContentTests extends WindowTestsBase {
performLayout(mDisplayContent);
// The frame is empty because the requested height is zero.
- assertTrue(win.getFrameLw().isEmpty());
+ assertTrue(win.getFrame().isEmpty());
// The window should be scheduled to resize then the client may report a new non-empty size.
win.updateResizingWindowIfNeeded();
assertThat(mWm.mResizingWindows).contains(win);
diff --git a/services/tests/wmtests/src/com/android/server/wm/DisplayPolicyLayoutTests.java b/services/tests/wmtests/src/com/android/server/wm/DisplayPolicyLayoutTests.java
index 0675c6d04422..94e40413f9f8 100644
--- a/services/tests/wmtests/src/com/android/server/wm/DisplayPolicyLayoutTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/DisplayPolicyLayoutTests.java
@@ -26,8 +26,6 @@ import static android.view.InsetsState.ITYPE_TOP_GESTURES;
import static android.view.Surface.ROTATION_0;
import static android.view.Surface.ROTATION_270;
import static android.view.Surface.ROTATION_90;
-import static android.view.View.SYSTEM_UI_FLAG_FULLSCREEN;
-import static android.view.View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN;
import static android.view.ViewGroup.LayoutParams.MATCH_PARENT;
import static android.view.WindowManager.LayoutParams.FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS;
import static android.view.WindowManager.LayoutParams.FLAG_LAYOUT_INSET_DECOR;
@@ -36,6 +34,7 @@ import static android.view.WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE;
import static android.view.WindowManager.LayoutParams.LAYOUT_IN_DISPLAY_CUTOUT_MODE_ALWAYS;
import static android.view.WindowManager.LayoutParams.LAYOUT_IN_DISPLAY_CUTOUT_MODE_NEVER;
import static android.view.WindowManager.LayoutParams.LAYOUT_IN_DISPLAY_CUTOUT_MODE_SHORT_EDGES;
+import static android.view.WindowManager.LayoutParams.PRIVATE_FLAG_INSET_PARENT_FRAME_BY_IME;
import static android.view.WindowManager.LayoutParams.PRIVATE_FLAG_IS_SCREEN_DECOR;
import static android.view.WindowManager.LayoutParams.SOFT_INPUT_ADJUST_NOTHING;
import static android.view.WindowManager.LayoutParams.TYPE_APPLICATION;
@@ -114,7 +113,7 @@ public class DisplayPolicyLayoutTests extends DisplayPolicyTestsBase {
mWindow = spy(createWindow(null, TYPE_APPLICATION, "window"));
// We only test window frames set by DisplayPolicy, so here prevents computeFrameLw from
// changing those frames.
- doNothing().when(mWindow).computeFrameLw();
+ doNothing().when(mWindow).computeFrame();
final WindowManager.LayoutParams attrs = mWindow.mAttrs;
attrs.width = MATCH_PARENT;
@@ -179,7 +178,7 @@ public class DisplayPolicyLayoutTests extends DisplayPolicyTestsBase {
WindowState win = createWindow(null, TYPE_STATUS_BAR_SUB_PANEL, "StatusBarSubPanel");
win.mAttrs.providesInsetsTypes = new int[]{ITYPE_STATUS_BAR, ITYPE_TOP_GESTURES};
- win.getFrameLw().set(0, 0, 500, 100);
+ win.getFrame().set(0, 0, 500, 100);
addWindow(win);
InsetsStateController controller = mDisplayContent.getInsetsStateController();
@@ -207,7 +206,7 @@ public class DisplayPolicyLayoutTests extends DisplayPolicyTestsBase {
mDisplayPolicy.removeWindowLw(mStatusBarWindow); // Removes the existing one.
WindowState win = createWindow(null, TYPE_STATUS_BAR, "StatusBar");
win.mAttrs.providesInsetsTypes = new int[]{ITYPE_STATUS_BAR};
- win.getFrameLw().set(0, 0, 500, 100);
+ win.getFrame().set(0, 0, 500, 100);
addWindow(win);
mDisplayContent.getInsetsStateController().onPostLayout();
@@ -232,7 +231,7 @@ public class DisplayPolicyLayoutTests extends DisplayPolicyTestsBase {
WindowState win1 = createWindow(null, TYPE_NAVIGATION_BAR_PANEL, "NavBarPanel1");
win1.mAttrs.providesInsetsTypes = new int[]{ITYPE_NAVIGATION_BAR};
win1.mAttrs.gravity = Gravity.TOP;
- win1.getFrameLw().set(0, 0, 200, 500);
+ win1.getFrame().set(0, 0, 200, 500);
addWindow(win1);
assertEquals(mDisplayPolicy.getAlternateNavBarPosition(), ALT_BAR_TOP);
@@ -241,7 +240,7 @@ public class DisplayPolicyLayoutTests extends DisplayPolicyTestsBase {
WindowState win2 = createWindow(null, TYPE_NAVIGATION_BAR_PANEL, "NavBarPanel2");
win2.mAttrs.providesInsetsTypes = new int[]{ITYPE_NAVIGATION_BAR};
win2.mAttrs.gravity = Gravity.BOTTOM;
- win2.getFrameLw().set(0, 0, 200, 500);
+ win2.getFrame().set(0, 0, 200, 500);
addWindow(win2);
assertEquals(mDisplayPolicy.getAlternateNavBarPosition(), ALT_BAR_BOTTOM);
@@ -250,7 +249,7 @@ public class DisplayPolicyLayoutTests extends DisplayPolicyTestsBase {
WindowState win3 = createWindow(null, TYPE_NAVIGATION_BAR_PANEL, "NavBarPanel3");
win3.mAttrs.providesInsetsTypes = new int[]{ITYPE_NAVIGATION_BAR};
win3.mAttrs.gravity = Gravity.LEFT;
- win3.getFrameLw().set(0, 0, 200, 500);
+ win3.getFrame().set(0, 0, 200, 500);
addWindow(win3);
assertEquals(mDisplayPolicy.getAlternateNavBarPosition(), ALT_BAR_LEFT);
@@ -259,7 +258,7 @@ public class DisplayPolicyLayoutTests extends DisplayPolicyTestsBase {
WindowState win4 = createWindow(null, TYPE_NAVIGATION_BAR_PANEL, "NavBarPanel4");
win4.mAttrs.providesInsetsTypes = new int[]{ITYPE_NAVIGATION_BAR};
win4.mAttrs.gravity = Gravity.RIGHT;
- win4.getFrameLw().set(0, 0, 200, 500);
+ win4.getFrame().set(0, 0, 200, 500);
addWindow(win4);
assertEquals(mDisplayPolicy.getAlternateNavBarPosition(), ALT_BAR_RIGHT);
@@ -274,11 +273,11 @@ public class DisplayPolicyLayoutTests extends DisplayPolicyTestsBase {
mDisplayPolicy.beginLayoutLw(mFrames, 0 /* UI mode */);
mDisplayPolicy.layoutWindowLw(mWindow, null, mFrames);
- assertInsetByTopBottom(mWindow.getStableFrameLw(), STATUS_BAR_HEIGHT, NAV_BAR_HEIGHT);
- assertInsetByTopBottom(mWindow.getDisplayFrameLw(), STATUS_BAR_HEIGHT, 0);
+ assertInsetByTopBottom(mWindow.getStableFrame(), STATUS_BAR_HEIGHT, NAV_BAR_HEIGHT);
+ assertInsetByTopBottom(mWindow.getDisplayFrame(), STATUS_BAR_HEIGHT, 0);
assertInsetByTopBottom(mWindow.getParentFrame(), STATUS_BAR_HEIGHT, 0);
- assertInsetByTopBottom(mWindow.getVisibleFrameLw(), STATUS_BAR_HEIGHT, NAV_BAR_HEIGHT);
- assertInsetByTopBottom(mWindow.getContentFrameLw(), STATUS_BAR_HEIGHT, NAV_BAR_HEIGHT);
+ assertInsetByTopBottom(mWindow.getVisibleFrame(), STATUS_BAR_HEIGHT, NAV_BAR_HEIGHT);
+ assertInsetByTopBottom(mWindow.getContentFrame(), STATUS_BAR_HEIGHT, NAV_BAR_HEIGHT);
assertInsetByTopBottom(mWindow.getDecorFrame(), 0, 0);
}
@@ -290,11 +289,11 @@ public class DisplayPolicyLayoutTests extends DisplayPolicyTestsBase {
mDisplayPolicy.beginLayoutLw(mFrames, 0 /* UI mode */);
mDisplayPolicy.layoutWindowLw(mWindow, null, mFrames);
- assertInsetByTopBottom(mWindow.getStableFrameLw(), STATUS_BAR_HEIGHT, NAV_BAR_HEIGHT);
- assertInsetByTopBottom(mWindow.getDisplayFrameLw(), 0, NAV_BAR_HEIGHT);
+ assertInsetByTopBottom(mWindow.getStableFrame(), STATUS_BAR_HEIGHT, NAV_BAR_HEIGHT);
+ assertInsetByTopBottom(mWindow.getDisplayFrame(), 0, NAV_BAR_HEIGHT);
assertInsetByTopBottom(mWindow.getParentFrame(), 0, NAV_BAR_HEIGHT);
- assertInsetByTopBottom(mWindow.getVisibleFrameLw(), STATUS_BAR_HEIGHT, NAV_BAR_HEIGHT);
- assertInsetByTopBottom(mWindow.getContentFrameLw(), STATUS_BAR_HEIGHT, NAV_BAR_HEIGHT);
+ assertInsetByTopBottom(mWindow.getVisibleFrame(), STATUS_BAR_HEIGHT, NAV_BAR_HEIGHT);
+ assertInsetByTopBottom(mWindow.getContentFrame(), STATUS_BAR_HEIGHT, NAV_BAR_HEIGHT);
assertInsetByTopBottom(mWindow.getDecorFrame(), 0, 0);
}
@@ -306,11 +305,11 @@ public class DisplayPolicyLayoutTests extends DisplayPolicyTestsBase {
mDisplayPolicy.beginLayoutLw(mFrames, 0 /* UI mode */);
mDisplayPolicy.layoutWindowLw(mWindow, null, mFrames);
- assertInsetByTopBottom(mWindow.getStableFrameLw(), STATUS_BAR_HEIGHT, NAV_BAR_HEIGHT);
- assertInsetByTopBottom(mWindow.getDisplayFrameLw(), STATUS_BAR_HEIGHT, NAV_BAR_HEIGHT);
+ assertInsetByTopBottom(mWindow.getStableFrame(), STATUS_BAR_HEIGHT, NAV_BAR_HEIGHT);
+ assertInsetByTopBottom(mWindow.getDisplayFrame(), STATUS_BAR_HEIGHT, NAV_BAR_HEIGHT);
assertInsetByTopBottom(mWindow.getParentFrame(), STATUS_BAR_HEIGHT, NAV_BAR_HEIGHT);
- assertInsetByTopBottom(mWindow.getVisibleFrameLw(), STATUS_BAR_HEIGHT, NAV_BAR_HEIGHT);
- assertInsetByTopBottom(mWindow.getContentFrameLw(), STATUS_BAR_HEIGHT, NAV_BAR_HEIGHT);
+ assertInsetByTopBottom(mWindow.getVisibleFrame(), STATUS_BAR_HEIGHT, NAV_BAR_HEIGHT);
+ assertInsetByTopBottom(mWindow.getContentFrame(), STATUS_BAR_HEIGHT, NAV_BAR_HEIGHT);
assertInsetByTopBottom(mWindow.getDecorFrame(), 0, 0);
}
@@ -322,11 +321,11 @@ public class DisplayPolicyLayoutTests extends DisplayPolicyTestsBase {
mDisplayPolicy.beginLayoutLw(mFrames, 0 /* UI mode */);
mDisplayPolicy.layoutWindowLw(mWindow, null, mFrames);
- assertInsetByTopBottom(mWindow.getStableFrameLw(), STATUS_BAR_HEIGHT, NAV_BAR_HEIGHT);
- assertInsetByTopBottom(mWindow.getDisplayFrameLw(), STATUS_BAR_HEIGHT, 0);
+ assertInsetByTopBottom(mWindow.getStableFrame(), STATUS_BAR_HEIGHT, NAV_BAR_HEIGHT);
+ assertInsetByTopBottom(mWindow.getDisplayFrame(), STATUS_BAR_HEIGHT, 0);
assertInsetByTopBottom(mWindow.getParentFrame(), STATUS_BAR_HEIGHT, 0);
- assertInsetByTopBottom(mWindow.getVisibleFrameLw(), STATUS_BAR_HEIGHT, NAV_BAR_HEIGHT);
- assertInsetByTopBottom(mWindow.getContentFrameLw(), STATUS_BAR_HEIGHT, NAV_BAR_HEIGHT);
+ assertInsetByTopBottom(mWindow.getVisibleFrame(), STATUS_BAR_HEIGHT, NAV_BAR_HEIGHT);
+ assertInsetByTopBottom(mWindow.getContentFrame(), STATUS_BAR_HEIGHT, NAV_BAR_HEIGHT);
assertInsetByTopBottom(mWindow.getDecorFrame(), 0, 0);
}
@@ -342,11 +341,11 @@ public class DisplayPolicyLayoutTests extends DisplayPolicyTestsBase {
mDisplayPolicy.beginLayoutLw(mFrames, 0 /* UI mode */);
mDisplayPolicy.layoutWindowLw(mWindow, null, mFrames);
- assertInsetByTopBottom(mWindow.getStableFrameLw(), STATUS_BAR_HEIGHT, NAV_BAR_HEIGHT);
- assertInsetByTopBottom(mWindow.getDisplayFrameLw(), STATUS_BAR_HEIGHT, NAV_BAR_HEIGHT);
+ assertInsetByTopBottom(mWindow.getStableFrame(), STATUS_BAR_HEIGHT, NAV_BAR_HEIGHT);
+ assertInsetByTopBottom(mWindow.getDisplayFrame(), STATUS_BAR_HEIGHT, NAV_BAR_HEIGHT);
assertInsetByTopBottom(mWindow.getParentFrame(), STATUS_BAR_HEIGHT, NAV_BAR_HEIGHT);
- assertInsetByTopBottom(mWindow.getVisibleFrameLw(), STATUS_BAR_HEIGHT, NAV_BAR_HEIGHT);
- assertInsetByTopBottom(mWindow.getContentFrameLw(), STATUS_BAR_HEIGHT, NAV_BAR_HEIGHT);
+ assertInsetByTopBottom(mWindow.getVisibleFrame(), STATUS_BAR_HEIGHT, NAV_BAR_HEIGHT);
+ assertInsetByTopBottom(mWindow.getContentFrame(), STATUS_BAR_HEIGHT, NAV_BAR_HEIGHT);
assertInsetByTopBottom(mWindow.getDecorFrame(), 0, 0);
}
@@ -362,15 +361,33 @@ public class DisplayPolicyLayoutTests extends DisplayPolicyTestsBase {
mDisplayPolicy.beginLayoutLw(mFrames, 0 /* UI mode */);
mDisplayPolicy.layoutWindowLw(mWindow, null, mFrames);
- assertInsetByTopBottom(mWindow.getStableFrameLw(), STATUS_BAR_HEIGHT, NAV_BAR_HEIGHT);
- assertInsetByTopBottom(mWindow.getDisplayFrameLw(), 0, 0);
+ assertInsetByTopBottom(mWindow.getStableFrame(), STATUS_BAR_HEIGHT, NAV_BAR_HEIGHT);
+ assertInsetByTopBottom(mWindow.getDisplayFrame(), 0, 0);
assertInsetByTopBottom(mWindow.getParentFrame(), 0, 0);
- assertInsetByTopBottom(mWindow.getVisibleFrameLw(), STATUS_BAR_HEIGHT, NAV_BAR_HEIGHT);
- assertInsetByTopBottom(mWindow.getContentFrameLw(), STATUS_BAR_HEIGHT, NAV_BAR_HEIGHT);
+ assertInsetByTopBottom(mWindow.getVisibleFrame(), STATUS_BAR_HEIGHT, NAV_BAR_HEIGHT);
+ assertInsetByTopBottom(mWindow.getContentFrame(), STATUS_BAR_HEIGHT, NAV_BAR_HEIGHT);
assertInsetByTopBottom(mWindow.getDecorFrame(), 0, 0);
}
@Test
+ public void layoutWindowLw_insetParentFrameByIme() {
+ final InsetsState state =
+ mDisplayContent.getInsetsStateController().getRawInsetsState();
+ state.getSource(InsetsState.ITYPE_IME).setVisible(true);
+ state.getSource(InsetsState.ITYPE_IME).setFrame(
+ 0, DISPLAY_HEIGHT - IME_HEIGHT, DISPLAY_WIDTH, DISPLAY_HEIGHT);
+ mWindow.mAttrs.privateFlags |= PRIVATE_FLAG_INSET_PARENT_FRAME_BY_IME;
+ mWindow.mBehindIme = true;
+ addWindow(mWindow);
+
+ mDisplayPolicy.beginLayoutLw(mFrames, 0 /* UI mode */);
+ mDisplayPolicy.layoutWindowLw(mWindow, null, mFrames);
+
+ assertInsetByTopBottom(mWindow.getDisplayFrame(), STATUS_BAR_HEIGHT, NAV_BAR_HEIGHT);
+ assertInsetByTopBottom(mWindow.getParentFrame(), STATUS_BAR_HEIGHT, IME_HEIGHT);
+ }
+
+ @Test
public void layoutWindowLw_fitDisplayCutout() {
addDisplayCutout();
@@ -381,11 +398,11 @@ public class DisplayPolicyLayoutTests extends DisplayPolicyTestsBase {
mDisplayPolicy.beginLayoutLw(mFrames, 0 /* UI mode */);
mDisplayPolicy.layoutWindowLw(mWindow, null, mFrames);
- assertInsetByTopBottom(mWindow.getStableFrameLw(), STATUS_BAR_HEIGHT, NAV_BAR_HEIGHT);
- assertInsetByTopBottom(mWindow.getDisplayFrameLw(), DISPLAY_CUTOUT_HEIGHT, 0);
+ assertInsetByTopBottom(mWindow.getStableFrame(), STATUS_BAR_HEIGHT, NAV_BAR_HEIGHT);
+ assertInsetByTopBottom(mWindow.getDisplayFrame(), DISPLAY_CUTOUT_HEIGHT, 0);
assertInsetByTopBottom(mWindow.getParentFrame(), DISPLAY_CUTOUT_HEIGHT, 0);
- assertInsetByTopBottom(mWindow.getVisibleFrameLw(), STATUS_BAR_HEIGHT, NAV_BAR_HEIGHT);
- assertInsetByTopBottom(mWindow.getContentFrameLw(), STATUS_BAR_HEIGHT, NAV_BAR_HEIGHT);
+ assertInsetByTopBottom(mWindow.getVisibleFrame(), STATUS_BAR_HEIGHT, NAV_BAR_HEIGHT);
+ assertInsetByTopBottom(mWindow.getContentFrame(), STATUS_BAR_HEIGHT, NAV_BAR_HEIGHT);
assertInsetByTopBottom(mWindow.getDecorFrame(), 0, 0);
}
@@ -402,10 +419,10 @@ public class DisplayPolicyLayoutTests extends DisplayPolicyTestsBase {
mDisplayPolicy.layoutWindowLw(mWindow, null, mFrames);
assertInsetByTopBottom(mWindow.getParentFrame(), 0, 0);
- assertInsetByTopBottom(mWindow.getStableFrameLw(), STATUS_BAR_HEIGHT, NAV_BAR_HEIGHT);
- assertInsetByTopBottom(mWindow.getContentFrameLw(), STATUS_BAR_HEIGHT, NAV_BAR_HEIGHT);
+ assertInsetByTopBottom(mWindow.getStableFrame(), STATUS_BAR_HEIGHT, NAV_BAR_HEIGHT);
+ assertInsetByTopBottom(mWindow.getContentFrame(), STATUS_BAR_HEIGHT, NAV_BAR_HEIGHT);
assertInsetByTopBottom(mWindow.getDecorFrame(), 0, 0);
- assertInsetByTopBottom(mWindow.getDisplayFrameLw(), 0, 0);
+ assertInsetByTopBottom(mWindow.getDisplayFrame(), 0, 0);
}
@Test
@@ -422,10 +439,10 @@ public class DisplayPolicyLayoutTests extends DisplayPolicyTestsBase {
mDisplayPolicy.layoutWindowLw(mWindow, null, mFrames);
assertInsetByTopBottom(mWindow.getParentFrame(), STATUS_BAR_HEIGHT, 0);
- assertInsetByTopBottom(mWindow.getStableFrameLw(), STATUS_BAR_HEIGHT, NAV_BAR_HEIGHT);
- assertInsetByTopBottom(mWindow.getContentFrameLw(), STATUS_BAR_HEIGHT, NAV_BAR_HEIGHT);
+ assertInsetByTopBottom(mWindow.getStableFrame(), STATUS_BAR_HEIGHT, NAV_BAR_HEIGHT);
+ assertInsetByTopBottom(mWindow.getContentFrame(), STATUS_BAR_HEIGHT, NAV_BAR_HEIGHT);
assertInsetByTopBottom(mWindow.getDecorFrame(), 0, 0);
- assertInsetByTopBottom(mWindow.getDisplayFrameLw(), STATUS_BAR_HEIGHT, 0);
+ assertInsetByTopBottom(mWindow.getDisplayFrame(), STATUS_BAR_HEIGHT, 0);
}
@Test
@@ -442,10 +459,10 @@ public class DisplayPolicyLayoutTests extends DisplayPolicyTestsBase {
mDisplayPolicy.layoutWindowLw(mWindow, null, mFrames);
assertInsetBy(mWindow.getParentFrame(), 0, 0, 0, 0);
- assertInsetBy(mWindow.getStableFrameLw(), 0, STATUS_BAR_HEIGHT, 0, NAV_BAR_HEIGHT);
- assertInsetBy(mWindow.getContentFrameLw(), 0, STATUS_BAR_HEIGHT, 0, NAV_BAR_HEIGHT);
+ assertInsetBy(mWindow.getStableFrame(), 0, STATUS_BAR_HEIGHT, 0, NAV_BAR_HEIGHT);
+ assertInsetBy(mWindow.getContentFrame(), 0, STATUS_BAR_HEIGHT, 0, NAV_BAR_HEIGHT);
assertInsetBy(mWindow.getDecorFrame(), 0, 0, 0, 0);
- assertInsetBy(mWindow.getDisplayFrameLw(), 0, 0, 0, 0);
+ assertInsetBy(mWindow.getDisplayFrame(), 0, 0, 0, 0);
}
@Test
@@ -462,10 +479,10 @@ public class DisplayPolicyLayoutTests extends DisplayPolicyTestsBase {
mDisplayPolicy.layoutWindowLw(mWindow, null, mFrames);
assertInsetBy(mWindow.getParentFrame(), 0, 0, 0, 0);
- assertInsetBy(mWindow.getStableFrameLw(), 0, STATUS_BAR_HEIGHT, 0, NAV_BAR_HEIGHT);
- assertInsetBy(mWindow.getContentFrameLw(), 0, STATUS_BAR_HEIGHT, 0, NAV_BAR_HEIGHT);
+ assertInsetBy(mWindow.getStableFrame(), 0, STATUS_BAR_HEIGHT, 0, NAV_BAR_HEIGHT);
+ assertInsetBy(mWindow.getContentFrame(), 0, STATUS_BAR_HEIGHT, 0, NAV_BAR_HEIGHT);
assertInsetBy(mWindow.getDecorFrame(), 0, 0, 0, 0);
- assertInsetBy(mWindow.getDisplayFrameLw(), 0, 0, 0, 0);
+ assertInsetBy(mWindow.getDisplayFrame(), 0, 0, 0, 0);
}
@Test
@@ -475,7 +492,6 @@ public class DisplayPolicyLayoutTests extends DisplayPolicyTestsBase {
mWindow.mAttrs.flags =
FLAG_LAYOUT_IN_SCREEN | FLAG_LAYOUT_INSET_DECOR | FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS;
mWindow.mAttrs.setFitInsetsTypes(0 /* types */);
- mWindow.mAttrs.subtreeSystemUiVisibility |= SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN;
mWindow.mAttrs.setFitInsetsTypes(
mWindow.mAttrs.getFitInsetsTypes() & ~Type.statusBars());
addWindow(mWindow);
@@ -484,10 +500,10 @@ public class DisplayPolicyLayoutTests extends DisplayPolicyTestsBase {
mDisplayPolicy.layoutWindowLw(mWindow, null, mFrames);
assertInsetByTopBottom(mWindow.getParentFrame(), 0, 0);
- assertInsetByTopBottom(mWindow.getStableFrameLw(), STATUS_BAR_HEIGHT, NAV_BAR_HEIGHT);
- assertInsetByTopBottom(mWindow.getContentFrameLw(), STATUS_BAR_HEIGHT, NAV_BAR_HEIGHT);
+ assertInsetByTopBottom(mWindow.getStableFrame(), STATUS_BAR_HEIGHT, NAV_BAR_HEIGHT);
+ assertInsetByTopBottom(mWindow.getContentFrame(), STATUS_BAR_HEIGHT, NAV_BAR_HEIGHT);
assertInsetByTopBottom(mWindow.getDecorFrame(), 0, 0);
- assertInsetByTopBottom(mWindow.getDisplayFrameLw(), 0, 0);
+ assertInsetByTopBottom(mWindow.getDisplayFrame(), 0, 0);
}
@Test
@@ -497,19 +513,19 @@ public class DisplayPolicyLayoutTests extends DisplayPolicyTestsBase {
mWindow.mAttrs.flags =
FLAG_LAYOUT_IN_SCREEN | FLAG_LAYOUT_INSET_DECOR | FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS;
mWindow.mAttrs.setFitInsetsTypes(0 /* types */);
- mWindow.mAttrs.subtreeSystemUiVisibility |= SYSTEM_UI_FLAG_FULLSCREEN;
mDisplayContent.getInsetsPolicy().getInsetsForDispatch(mWindow)
.getSource(InsetsState.ITYPE_STATUS_BAR).setVisible(false);
+ mWindow.getRequestedInsetsState().getSource(ITYPE_STATUS_BAR).setVisible(false);
addWindow(mWindow);
mDisplayPolicy.beginLayoutLw(mFrames, 0 /* UI mode */);
mDisplayPolicy.layoutWindowLw(mWindow, null, mFrames);
assertInsetByTopBottom(mWindow.getParentFrame(), STATUS_BAR_HEIGHT, 0);
- assertInsetByTopBottom(mWindow.getStableFrameLw(), STATUS_BAR_HEIGHT, NAV_BAR_HEIGHT);
- assertInsetByTopBottom(mWindow.getContentFrameLw(), STATUS_BAR_HEIGHT, NAV_BAR_HEIGHT);
+ assertInsetByTopBottom(mWindow.getStableFrame(), STATUS_BAR_HEIGHT, NAV_BAR_HEIGHT);
+ assertInsetByTopBottom(mWindow.getContentFrame(), STATUS_BAR_HEIGHT, NAV_BAR_HEIGHT);
assertInsetByTopBottom(mWindow.getDecorFrame(), 0, 0);
- assertInsetByTopBottom(mWindow.getDisplayFrameLw(), STATUS_BAR_HEIGHT, 0);
+ assertInsetByTopBottom(mWindow.getDisplayFrame(), STATUS_BAR_HEIGHT, 0);
}
@Test
@@ -519,9 +535,9 @@ public class DisplayPolicyLayoutTests extends DisplayPolicyTestsBase {
mWindow.mAttrs.flags =
FLAG_LAYOUT_IN_SCREEN | FLAG_LAYOUT_INSET_DECOR | FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS;
mWindow.mAttrs.setFitInsetsTypes(0 /* types */);
- mWindow.mAttrs.subtreeSystemUiVisibility |= SYSTEM_UI_FLAG_FULLSCREEN;
mDisplayContent.getInsetsPolicy().getInsetsForDispatch(mWindow)
.getSource(InsetsState.ITYPE_STATUS_BAR).setVisible(false);
+ mWindow.getRequestedInsetsState().getSource(ITYPE_STATUS_BAR).setVisible(false);
mWindow.mAttrs.layoutInDisplayCutoutMode = LAYOUT_IN_DISPLAY_CUTOUT_MODE_ALWAYS;
addWindow(mWindow);
@@ -529,10 +545,10 @@ public class DisplayPolicyLayoutTests extends DisplayPolicyTestsBase {
mDisplayPolicy.layoutWindowLw(mWindow, null, mFrames);
assertInsetByTopBottom(mWindow.getParentFrame(), 0, 0);
- assertInsetByTopBottom(mWindow.getStableFrameLw(), STATUS_BAR_HEIGHT, NAV_BAR_HEIGHT);
- assertInsetByTopBottom(mWindow.getContentFrameLw(), STATUS_BAR_HEIGHT, NAV_BAR_HEIGHT);
+ assertInsetByTopBottom(mWindow.getStableFrame(), STATUS_BAR_HEIGHT, NAV_BAR_HEIGHT);
+ assertInsetByTopBottom(mWindow.getContentFrame(), STATUS_BAR_HEIGHT, NAV_BAR_HEIGHT);
assertInsetByTopBottom(mWindow.getDecorFrame(), 0, 0);
- assertInsetByTopBottom(mWindow.getDisplayFrameLw(), 0, 0);
+ assertInsetByTopBottom(mWindow.getDisplayFrame(), 0, 0);
}
@@ -549,11 +565,11 @@ public class DisplayPolicyLayoutTests extends DisplayPolicyTestsBase {
mDisplayPolicy.layoutWindowLw(mWindow, null, mFrames);
assertInsetBy(mWindow.getParentFrame(), DISPLAY_CUTOUT_HEIGHT, 0, 0, 0);
- assertInsetBy(mWindow.getStableFrameLw(), 0, STATUS_BAR_HEIGHT, NAV_BAR_HEIGHT, 0);
- assertInsetBy(mWindow.getContentFrameLw(),
+ assertInsetBy(mWindow.getStableFrame(), 0, STATUS_BAR_HEIGHT, NAV_BAR_HEIGHT, 0);
+ assertInsetBy(mWindow.getContentFrame(),
DISPLAY_CUTOUT_HEIGHT, STATUS_BAR_HEIGHT, NAV_BAR_HEIGHT, 0);
assertInsetBy(mWindow.getDecorFrame(), 0, 0, 0, 0);
- assertInsetBy(mWindow.getDisplayFrameLw(), DISPLAY_CUTOUT_HEIGHT, 0, 0, 0);
+ assertInsetBy(mWindow.getDisplayFrame(), DISPLAY_CUTOUT_HEIGHT, 0, 0, 0);
}
@Test
@@ -570,11 +586,11 @@ public class DisplayPolicyLayoutTests extends DisplayPolicyTestsBase {
mDisplayPolicy.layoutWindowLw(mWindow, null, mFrames);
assertInsetBy(mWindow.getParentFrame(), 0, 0, DISPLAY_CUTOUT_HEIGHT, 0);
- assertInsetBy(mWindow.getStableFrameLw(), NAV_BAR_HEIGHT, STATUS_BAR_HEIGHT, 0, 0);
- assertInsetBy(mWindow.getContentFrameLw(),
+ assertInsetBy(mWindow.getStableFrame(), NAV_BAR_HEIGHT, STATUS_BAR_HEIGHT, 0, 0);
+ assertInsetBy(mWindow.getContentFrame(),
NAV_BAR_HEIGHT, STATUS_BAR_HEIGHT, DISPLAY_CUTOUT_HEIGHT, 0);
assertInsetBy(mWindow.getDecorFrame(), 0, 0, 0, 0);
- assertInsetBy(mWindow.getDisplayFrameLw(), 0, 0, DISPLAY_CUTOUT_HEIGHT, 0);
+ assertInsetBy(mWindow.getDisplayFrame(), 0, 0, DISPLAY_CUTOUT_HEIGHT, 0);
}
@Test
@@ -585,7 +601,6 @@ public class DisplayPolicyLayoutTests extends DisplayPolicyTestsBase {
mWindow.mAttrs.flags =
FLAG_LAYOUT_IN_SCREEN | FLAG_LAYOUT_INSET_DECOR | FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS;
mWindow.mAttrs.setFitInsetsTypes(0 /* types */);
- mWindow.mAttrs.subtreeSystemUiVisibility |= SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN;
mWindow.mAttrs.setFitInsetsTypes(
mWindow.mAttrs.getFitInsetsTypes() & ~Type.statusBars());
addWindow(mWindow);
@@ -594,8 +609,8 @@ public class DisplayPolicyLayoutTests extends DisplayPolicyTestsBase {
mDisplayPolicy.layoutWindowLw(mWindow, null, mFrames);
assertInsetBy(mWindow.getParentFrame(), DISPLAY_CUTOUT_HEIGHT, 0, 0, 0);
- assertInsetBy(mWindow.getStableFrameLw(), 0, STATUS_BAR_HEIGHT, NAV_BAR_HEIGHT, 0);
- assertInsetBy(mWindow.getContentFrameLw(),
+ assertInsetBy(mWindow.getStableFrame(), 0, STATUS_BAR_HEIGHT, NAV_BAR_HEIGHT, 0);
+ assertInsetBy(mWindow.getContentFrame(),
DISPLAY_CUTOUT_HEIGHT, STATUS_BAR_HEIGHT, NAV_BAR_HEIGHT, 0);
assertInsetBy(mWindow.getDecorFrame(), 0, 0, 0, 0);
}
@@ -615,7 +630,7 @@ public class DisplayPolicyLayoutTests extends DisplayPolicyTestsBase {
mDisplayPolicy.layoutWindowLw(mWindow, null, mFrames);
assertInsetByTopBottom(mWindow.getParentFrame(), 0, NAV_BAR_HEIGHT);
- assertInsetByTopBottom(mWindow.getDisplayFrameLw(), STATUS_BAR_HEIGHT, NAV_BAR_HEIGHT);
+ assertInsetByTopBottom(mWindow.getDisplayFrame(), STATUS_BAR_HEIGHT, NAV_BAR_HEIGHT);
}
@Test
@@ -626,7 +641,6 @@ public class DisplayPolicyLayoutTests extends DisplayPolicyTestsBase {
mWindow.mAttrs.flags =
FLAG_LAYOUT_IN_SCREEN | FLAG_LAYOUT_INSET_DECOR | FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS;
mWindow.mAttrs.setFitInsetsTypes(0 /* types */);
- mWindow.mAttrs.subtreeSystemUiVisibility |= SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN;
mWindow.mAttrs.setFitInsetsTypes(
mWindow.mAttrs.getFitInsetsTypes() & ~Type.statusBars());
mWindow.mAttrs.layoutInDisplayCutoutMode = LAYOUT_IN_DISPLAY_CUTOUT_MODE_ALWAYS;
@@ -636,8 +650,8 @@ public class DisplayPolicyLayoutTests extends DisplayPolicyTestsBase {
mDisplayPolicy.layoutWindowLw(mWindow, null, mFrames);
assertInsetBy(mWindow.getParentFrame(), 0, 0, 0, 0);
- assertInsetBy(mWindow.getStableFrameLw(), 0, STATUS_BAR_HEIGHT, NAV_BAR_HEIGHT, 0);
- assertInsetBy(mWindow.getContentFrameLw(),
+ assertInsetBy(mWindow.getStableFrame(), 0, STATUS_BAR_HEIGHT, NAV_BAR_HEIGHT, 0);
+ assertInsetBy(mWindow.getContentFrame(),
DISPLAY_CUTOUT_HEIGHT, STATUS_BAR_HEIGHT, NAV_BAR_HEIGHT, 0);
assertInsetBy(mWindow.getDecorFrame(), 0, 0, 0, 0);
}
@@ -655,11 +669,11 @@ public class DisplayPolicyLayoutTests extends DisplayPolicyTestsBase {
mDisplayPolicy.layoutWindowLw(mWindow, null, mFrames);
assertInsetBy(mWindow.getParentFrame(), DISPLAY_CUTOUT_HEIGHT, 0, 0, 0);
- assertInsetBy(mWindow.getStableFrameLw(), 0, STATUS_BAR_HEIGHT, 0, NAV_BAR_HEIGHT);
- assertInsetBy(mWindow.getContentFrameLw(), DISPLAY_CUTOUT_HEIGHT, STATUS_BAR_HEIGHT, 0,
+ assertInsetBy(mWindow.getStableFrame(), 0, STATUS_BAR_HEIGHT, 0, NAV_BAR_HEIGHT);
+ assertInsetBy(mWindow.getContentFrame(), DISPLAY_CUTOUT_HEIGHT, STATUS_BAR_HEIGHT, 0,
NAV_BAR_HEIGHT);
assertInsetBy(mWindow.getDecorFrame(), 0, 0, 0, 0);
- assertInsetBy(mWindow.getDisplayFrameLw(), DISPLAY_CUTOUT_HEIGHT, 0, 0, 0);
+ assertInsetBy(mWindow.getDisplayFrame(), DISPLAY_CUTOUT_HEIGHT, 0, 0, 0);
}
@Test
@@ -676,12 +690,12 @@ public class DisplayPolicyLayoutTests extends DisplayPolicyTestsBase {
mDisplayPolicy.layoutWindowLw(mWindow, null, mFrames);
assertInsetBy(mWindow.getParentFrame(), DISPLAY_CUTOUT_HEIGHT, 0, 0, 0);
- assertInsetBy(mWindow.getStableFrameLw(), 0, STATUS_BAR_HEIGHT, 0,
+ assertInsetBy(mWindow.getStableFrame(), 0, STATUS_BAR_HEIGHT, 0,
NAV_BAR_HEIGHT);
- assertInsetBy(mWindow.getContentFrameLw(), DISPLAY_CUTOUT_HEIGHT, STATUS_BAR_HEIGHT, 0,
+ assertInsetBy(mWindow.getContentFrame(), DISPLAY_CUTOUT_HEIGHT, STATUS_BAR_HEIGHT, 0,
NAV_BAR_HEIGHT);
assertInsetBy(mWindow.getDecorFrame(), 0, 0, 0, 0);
- assertInsetBy(mWindow.getDisplayFrameLw(), DISPLAY_CUTOUT_HEIGHT, 0, 0, 0);
+ assertInsetBy(mWindow.getDisplayFrame(), DISPLAY_CUTOUT_HEIGHT, 0, 0, 0);
}
@Test
@@ -698,11 +712,11 @@ public class DisplayPolicyLayoutTests extends DisplayPolicyTestsBase {
mDisplayPolicy.layoutWindowLw(mWindow, null, mFrames);
assertInsetBy(mWindow.getParentFrame(), DISPLAY_CUTOUT_HEIGHT, 0, 0, 0);
- assertInsetBy(mWindow.getStableFrameLw(), 0, STATUS_BAR_HEIGHT, 0, NAV_BAR_HEIGHT);
- assertInsetBy(mWindow.getContentFrameLw(), DISPLAY_CUTOUT_HEIGHT, STATUS_BAR_HEIGHT, 0,
+ assertInsetBy(mWindow.getStableFrame(), 0, STATUS_BAR_HEIGHT, 0, NAV_BAR_HEIGHT);
+ assertInsetBy(mWindow.getContentFrame(), DISPLAY_CUTOUT_HEIGHT, STATUS_BAR_HEIGHT, 0,
NAV_BAR_HEIGHT);
assertInsetBy(mWindow.getDecorFrame(), 0, 0, 0, 0);
- assertInsetBy(mWindow.getDisplayFrameLw(), DISPLAY_CUTOUT_HEIGHT, 0, 0, 0);
+ assertInsetBy(mWindow.getDisplayFrame(), DISPLAY_CUTOUT_HEIGHT, 0, 0, 0);
}
@Test
@@ -719,11 +733,11 @@ public class DisplayPolicyLayoutTests extends DisplayPolicyTestsBase {
mDisplayPolicy.layoutWindowLw(mWindow, null, mFrames);
assertInsetBy(mWindow.getParentFrame(), 0, 0, 0, 0);
- assertInsetBy(mWindow.getStableFrameLw(), 0, STATUS_BAR_HEIGHT, 0, NAV_BAR_HEIGHT);
- assertInsetBy(mWindow.getContentFrameLw(), DISPLAY_CUTOUT_HEIGHT, STATUS_BAR_HEIGHT, 0,
+ assertInsetBy(mWindow.getStableFrame(), 0, STATUS_BAR_HEIGHT, 0, NAV_BAR_HEIGHT);
+ assertInsetBy(mWindow.getContentFrame(), DISPLAY_CUTOUT_HEIGHT, STATUS_BAR_HEIGHT, 0,
NAV_BAR_HEIGHT);
assertInsetBy(mWindow.getDecorFrame(), 0, 0, 0, 0);
- assertInsetBy(mWindow.getDisplayFrameLw(), 0, 0, 0, 0);
+ assertInsetBy(mWindow.getDisplayFrame(), 0, 0, 0, 0);
}
@Test
@@ -740,11 +754,11 @@ public class DisplayPolicyLayoutTests extends DisplayPolicyTestsBase {
mDisplayPolicy.layoutWindowLw(mWindow, null, mFrames);
assertInsetBy(mWindow.getParentFrame(), 0, 0, 0, 0);
- assertInsetByTopBottom(mWindow.getStableFrameLw(), STATUS_BAR_HEIGHT, NAV_BAR_HEIGHT);
- assertInsetByTopBottom(mWindow.getContentFrameLw(), STATUS_BAR_HEIGHT, NAV_BAR_HEIGHT);
- assertInsetByTopBottom(mWindow.getVisibleFrameLw(), STATUS_BAR_HEIGHT, NAV_BAR_HEIGHT);
+ assertInsetByTopBottom(mWindow.getStableFrame(), STATUS_BAR_HEIGHT, NAV_BAR_HEIGHT);
+ assertInsetByTopBottom(mWindow.getContentFrame(), STATUS_BAR_HEIGHT, NAV_BAR_HEIGHT);
+ assertInsetByTopBottom(mWindow.getVisibleFrame(), STATUS_BAR_HEIGHT, NAV_BAR_HEIGHT);
assertInsetBy(mWindow.getDecorFrame(), 0, 0, 0, 0);
- assertInsetBy(mWindow.getDisplayFrameLw(), 0, 0, 0, 0);
+ assertInsetBy(mWindow.getDisplayFrame(), 0, 0, 0, 0);
}
@Test
@@ -904,34 +918,34 @@ public class DisplayPolicyLayoutTests extends DisplayPolicyTestsBase {
updateDecorWindow(decorWindow, MATCH_PARENT, DECOR_WINDOW_INSET, TOP);
mDisplayPolicy.beginLayoutLw(mFrames, 0 /* UI mode */);
mDisplayPolicy.layoutWindowLw(mWindow, null, mFrames);
- assertInsetByTopBottom(mWindow.getContentFrameLw(), DECOR_WINDOW_INSET, NAV_BAR_HEIGHT);
+ assertInsetByTopBottom(mWindow.getContentFrame(), DECOR_WINDOW_INSET, NAV_BAR_HEIGHT);
// Decor on bottom
updateDecorWindow(decorWindow, MATCH_PARENT, DECOR_WINDOW_INSET, BOTTOM);
mDisplayPolicy.beginLayoutLw(mFrames, 0 /* UI mode */);
mDisplayPolicy.layoutWindowLw(mWindow, null, mFrames);
- assertInsetByTopBottom(mWindow.getContentFrameLw(), STATUS_BAR_HEIGHT,
+ assertInsetByTopBottom(mWindow.getContentFrame(), STATUS_BAR_HEIGHT,
DECOR_WINDOW_INSET);
// Decor on the left
updateDecorWindow(decorWindow, DECOR_WINDOW_INSET, MATCH_PARENT, LEFT);
mDisplayPolicy.beginLayoutLw(mFrames, 0 /* UI mode */);
mDisplayPolicy.layoutWindowLw(mWindow, null, mFrames);
- assertInsetBy(mWindow.getContentFrameLw(), DECOR_WINDOW_INSET, STATUS_BAR_HEIGHT, 0,
+ assertInsetBy(mWindow.getContentFrame(), DECOR_WINDOW_INSET, STATUS_BAR_HEIGHT, 0,
NAV_BAR_HEIGHT);
// Decor on the right
updateDecorWindow(decorWindow, DECOR_WINDOW_INSET, MATCH_PARENT, RIGHT);
mDisplayPolicy.beginLayoutLw(mFrames, 0 /* UI mode */);
mDisplayPolicy.layoutWindowLw(mWindow, null, mFrames);
- assertInsetBy(mWindow.getContentFrameLw(), 0, STATUS_BAR_HEIGHT, DECOR_WINDOW_INSET,
+ assertInsetBy(mWindow.getContentFrame(), 0, STATUS_BAR_HEIGHT, DECOR_WINDOW_INSET,
NAV_BAR_HEIGHT);
// Decor not allowed as inset
updateDecorWindow(decorWindow, DECOR_WINDOW_INSET, DECOR_WINDOW_INSET, TOP);
mDisplayPolicy.beginLayoutLw(mFrames, 0 /* UI mode */);
mDisplayPolicy.layoutWindowLw(mWindow, null, mFrames);
- assertInsetByTopBottom(mWindow.getContentFrameLw(), STATUS_BAR_HEIGHT, NAV_BAR_HEIGHT);
+ assertInsetByTopBottom(mWindow.getContentFrame(), STATUS_BAR_HEIGHT, NAV_BAR_HEIGHT);
}
private void updateDecorWindow(WindowState decorWindow, int width, int height, int gravity) {
diff --git a/services/tests/wmtests/src/com/android/server/wm/DisplayPolicyTests.java b/services/tests/wmtests/src/com/android/server/wm/DisplayPolicyTests.java
index 4483f8c341cf..b50530ed3059 100644
--- a/services/tests/wmtests/src/com/android/server/wm/DisplayPolicyTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/DisplayPolicyTests.java
@@ -297,7 +297,7 @@ public class DisplayPolicyTests extends WindowTestsBase {
final WindowState navigationBar = createNavigationBarWindow();
- navigationBar.getFrameLw().set(new Rect(100, 200, 200, 300));
+ navigationBar.getFrame().set(new Rect(100, 200, 200, 300));
assertFalse("Freeform is overlapping with navigation bar",
DisplayPolicy.isOverlappingWithNavBar(targetWin, navigationBar));
@@ -377,7 +377,7 @@ public class DisplayPolicyTests extends WindowTestsBase {
mDisplayContent.setInputMethodWindowLocked(mImeWindow);
mImeWindow.mAttrs.setFitInsetsSides(Side.all() & ~Side.BOTTOM);
- mImeWindow.getGivenContentInsetsLw().set(0, displayInfo.logicalHeight, 0, 0);
+ mImeWindow.mGivenContentInsets.set(0, displayInfo.logicalHeight, 0, 0);
mImeWindow.getControllableInsetProvider().setServerVisible(true);
displayPolicy.beginLayoutLw(mDisplayContent.mDisplayFrames, 0 /* UI mode */);
diff --git a/services/tests/wmtests/src/com/android/server/wm/DisplayPolicyTestsBase.java b/services/tests/wmtests/src/com/android/server/wm/DisplayPolicyTestsBase.java
index b4e1c375993d..af8cb02a86fe 100644
--- a/services/tests/wmtests/src/com/android/server/wm/DisplayPolicyTestsBase.java
+++ b/services/tests/wmtests/src/com/android/server/wm/DisplayPolicyTestsBase.java
@@ -62,7 +62,7 @@ public class DisplayPolicyTestsBase extends WindowTestsBase {
static final int STATUS_BAR_HEIGHT = 10;
static final int NAV_BAR_HEIGHT = 15;
static final int DISPLAY_CUTOUT_HEIGHT = 8;
- static final int INPUT_METHOD_WINDOW_TOP = 585;
+ static final int IME_HEIGHT = 415;
DisplayPolicy mDisplayPolicy;
diff --git a/services/tests/wmtests/src/com/android/server/wm/InsetsSourceProviderTest.java b/services/tests/wmtests/src/com/android/server/wm/InsetsSourceProviderTest.java
index 1d6dd0b566a1..a0fa9369e7a8 100644
--- a/services/tests/wmtests/src/com/android/server/wm/InsetsSourceProviderTest.java
+++ b/services/tests/wmtests/src/com/android/server/wm/InsetsSourceProviderTest.java
@@ -61,7 +61,7 @@ public class InsetsSourceProviderTest extends WindowTestsBase {
@Test
public void testPostLayout() {
final WindowState statusBar = createWindow(null, TYPE_APPLICATION, "statusBar");
- statusBar.getFrameLw().set(0, 0, 500, 100);
+ statusBar.getFrame().set(0, 0, 500, 100);
statusBar.mHasSurface = true;
mProvider.setWindow(statusBar, null, null);
mProvider.onPostLayout();
@@ -76,9 +76,9 @@ public class InsetsSourceProviderTest extends WindowTestsBase {
@Test
public void testPostLayout_givenInsets() {
final WindowState ime = createWindow(null, TYPE_APPLICATION, "ime");
- ime.getFrameLw().set(0, 0, 500, 100);
- ime.getGivenContentInsetsLw().set(0, 0, 0, 60);
- ime.getGivenVisibleInsetsLw().set(0, 0, 0, 75);
+ ime.getFrame().set(0, 0, 500, 100);
+ ime.mGivenContentInsets.set(0, 0, 0, 60);
+ ime.mGivenVisibleInsets.set(0, 0, 0, 75);
ime.mHasSurface = true;
mProvider.setWindow(ime, null, null);
mProvider.onPostLayout();
@@ -94,7 +94,7 @@ public class InsetsSourceProviderTest extends WindowTestsBase {
@Test
public void testPostLayout_invisible() {
final WindowState statusBar = createWindow(null, TYPE_APPLICATION, "statusBar");
- statusBar.getFrameLw().set(0, 0, 500, 100);
+ statusBar.getFrame().set(0, 0, 500, 100);
mProvider.setWindow(statusBar, null, null);
mProvider.onPostLayout();
assertEquals(Insets.NONE, mProvider.getSource().calculateInsets(new Rect(0, 0, 500, 500),
@@ -104,7 +104,7 @@ public class InsetsSourceProviderTest extends WindowTestsBase {
@Test
public void testPostLayout_frameProvider() {
final WindowState statusBar = createWindow(null, TYPE_APPLICATION, "statusBar");
- statusBar.getFrameLw().set(0, 0, 500, 100);
+ statusBar.getFrame().set(0, 0, 500, 100);
statusBar.mHasSurface = true;
mProvider.setWindow(statusBar,
(displayFrames, windowState, rect) -> {
@@ -118,7 +118,7 @@ public class InsetsSourceProviderTest extends WindowTestsBase {
public void testUpdateControlForTarget() {
final WindowState statusBar = createWindow(null, TYPE_APPLICATION, "statusBar");
final WindowState target = createWindow(null, TYPE_APPLICATION, "target");
- statusBar.getFrameLw().set(0, 0, 500, 100);
+ statusBar.getFrame().set(0, 0, 500, 100);
// We must not have control or control target before we have the insets source window.
mProvider.updateControlForTarget(target, true /* force */);
@@ -163,7 +163,7 @@ public class InsetsSourceProviderTest extends WindowTestsBase {
public void testUpdateControlForFakeTarget() {
final WindowState statusBar = createWindow(null, TYPE_APPLICATION, "statusBar");
final WindowState target = createWindow(null, TYPE_APPLICATION, "target");
- statusBar.getFrameLw().set(0, 0, 500, 100);
+ statusBar.getFrame().set(0, 0, 500, 100);
mProvider.setWindow(statusBar, null, null);
mProvider.updateControlForFakeTarget(target);
assertNotNull(mProvider.getControl(target));
@@ -176,7 +176,7 @@ public class InsetsSourceProviderTest extends WindowTestsBase {
public void testUpdateSourceFrameForIme() {
final WindowState inputMethod = createWindow(null, TYPE_INPUT_METHOD, "inputMethod");
- inputMethod.getFrameLw().set(new Rect(0, 400, 500, 500));
+ inputMethod.getFrame().set(new Rect(0, 400, 500, 500));
mImeProvider.setWindow(inputMethod, null, null);
mImeProvider.setServerVisible(false);
@@ -190,7 +190,7 @@ public class InsetsSourceProviderTest extends WindowTestsBase {
mImeProvider.setServerVisible(true);
mImeSource.setVisible(true);
mImeProvider.updateSourceFrame();
- assertEquals(inputMethod.getFrameLw(), mImeSource.getFrame());
+ assertEquals(inputMethod.getFrame(), mImeSource.getFrame());
insets = mImeSource.calculateInsets(new Rect(0, 0, 500, 500),
false /* ignoreVisibility */);
assertEquals(Insets.of(0, 0, 0, 100), insets);
@@ -200,7 +200,7 @@ public class InsetsSourceProviderTest extends WindowTestsBase {
public void testInsetsModified() {
final WindowState statusBar = createWindow(null, TYPE_APPLICATION, "statusBar");
final WindowState target = createWindow(null, TYPE_APPLICATION, "target");
- statusBar.getFrameLw().set(0, 0, 500, 100);
+ statusBar.getFrame().set(0, 0, 500, 100);
mProvider.setWindow(statusBar, null, null);
mProvider.updateControlForTarget(target, false /* force */);
InsetsState state = new InsetsState();
@@ -213,7 +213,7 @@ public class InsetsSourceProviderTest extends WindowTestsBase {
public void testInsetsModified_noControl() {
final WindowState statusBar = createWindow(null, TYPE_APPLICATION, "statusBar");
final WindowState target = createWindow(null, TYPE_APPLICATION, "target");
- statusBar.getFrameLw().set(0, 0, 500, 100);
+ statusBar.getFrame().set(0, 0, 500, 100);
mProvider.setWindow(statusBar, null, null);
InsetsState state = new InsetsState();
state.getSource(ITYPE_STATUS_BAR).setVisible(false);
@@ -224,7 +224,7 @@ public class InsetsSourceProviderTest extends WindowTestsBase {
@Test
public void testInsetGeometries() {
final WindowState statusBar = createWindow(null, TYPE_APPLICATION, "statusBar");
- statusBar.getFrameLw().set(0, 0, 500, 100);
+ statusBar.getFrame().set(0, 0, 500, 100);
statusBar.mHasSurface = true;
mProvider.setWindow(statusBar, null, null);
mProvider.onPostLayout();
@@ -236,7 +236,7 @@ public class InsetsSourceProviderTest extends WindowTestsBase {
false /* ignoreVisibility */));
// Don't apply left insets if window is left-of inset-window but still overlaps
- statusBar.getFrameLw().set(100, 0, 0, 0);
+ statusBar.getFrame().set(100, 0, 0, 0);
assertEquals(Insets.of(0, 0, 0, 0),
mProvider.getSource().calculateInsets(new Rect(-100, 0, 400, 500),
false /* ignoreVisibility */));
diff --git a/services/tests/wmtests/src/com/android/server/wm/RecentTasksTest.java b/services/tests/wmtests/src/com/android/server/wm/RecentTasksTest.java
index 54c7f271e81b..9954f484f0a6 100644
--- a/services/tests/wmtests/src/com/android/server/wm/RecentTasksTest.java
+++ b/services/tests/wmtests/src/com/android/server/wm/RecentTasksTest.java
@@ -28,6 +28,8 @@ import static android.content.Intent.FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS;
import static android.content.Intent.FLAG_ACTIVITY_MULTIPLE_TASK;
import static android.content.Intent.FLAG_ACTIVITY_NEW_DOCUMENT;
import static android.content.Intent.FLAG_ACTIVITY_NEW_TASK;
+import static android.content.pm.ActivityInfo.LAUNCH_MULTIPLE;
+import static android.content.pm.ActivityInfo.LAUNCH_SINGLE_INSTANCE;
import static com.android.dx.mockito.inline.extended.ExtendedMockito.doNothing;
import static com.android.dx.mockito.inline.extended.ExtendedMockito.doReturn;
@@ -447,6 +449,31 @@ public class RecentTasksTest extends WindowTestsBase {
}
@Test
+ public void testRemoveAffinityTask() {
+ // Add task to recents
+ final String taskAffinity = "affinity";
+ final int uid = 10123;
+ final Task task1 = createTaskBuilder(".Task1").setStack(mStack).build();
+ task1.affinity = ActivityRecord.computeTaskAffinity(taskAffinity, uid, LAUNCH_MULTIPLE);
+ mRecentTasks.add(task1);
+
+ // Add another task to recents, and make sure the previous task was removed.
+ final Task task2 = createTaskBuilder(".Task2").setStack(mStack).build();
+ task2.affinity = ActivityRecord.computeTaskAffinity(taskAffinity, uid, LAUNCH_MULTIPLE);
+ mRecentTasks.add(task2);
+ assertEquals(1, mRecentTasks.getRecentTasks(MAX_VALUE, 0 /* flags */,
+ true /* getTasksAllowed */, TEST_USER_0_ID, 0).getList().size());
+
+ // Add another single-instance task to recents, and make sure no task is removed.
+ final Task task3 = createTaskBuilder(".Task3").setStack(mStack).build();
+ task3.affinity = ActivityRecord.computeTaskAffinity(taskAffinity, uid,
+ LAUNCH_SINGLE_INSTANCE);
+ mRecentTasks.add(task3);
+ assertEquals(2, mRecentTasks.getRecentTasks(MAX_VALUE, 0 /* flags */,
+ true /* getTasksAllowed */, TEST_USER_0_ID, 0).getList().size());
+ }
+
+ @Test
public void testAddTasksHomeClearUntrackedTasks_expectFinish() {
// There may be multiple tasks with the same base intent by flags (FLAG_ACTIVITY_NEW_TASK |
// FLAG_ACTIVITY_MULTIPLE_TASK). If the previous task is still active, it should be removed
diff --git a/services/tests/wmtests/src/com/android/server/wm/RootActivityContainerTests.java b/services/tests/wmtests/src/com/android/server/wm/RootActivityContainerTests.java
index b89d16807a6e..26b0bfb1dd7c 100644
--- a/services/tests/wmtests/src/com/android/server/wm/RootActivityContainerTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/RootActivityContainerTests.java
@@ -915,24 +915,6 @@ public class RootActivityContainerTests extends WindowTestsBase {
assertEquals(taskDisplayArea.getTopStack(), taskDisplayArea.getRootHomeTask());
}
- @Test
- public void testResumeFocusedStackOnSleepingDisplay() {
- // Create an activity on secondary display.
- final TestDisplayContent secondDisplay = addNewDisplayContentAt(
- DisplayContent.POSITION_TOP);
- final Task stack = secondDisplay.getDefaultTaskDisplayArea()
- .createStack(WINDOWING_MODE_FULLSCREEN, ACTIVITY_TYPE_STANDARD, true /* onTop */);
- final ActivityRecord activity = new ActivityBuilder(mAtm).setStack(stack).build();
- spyOn(activity);
- spyOn(stack);
-
- // Cannot resumed activities on secondary display if the display should sleep.
- doReturn(true).when(secondDisplay).shouldSleep();
- mRootWindowContainer.resumeFocusedStacksTopActivities();
- verify(stack, never()).resumeTopActivityUncheckedLocked(any(), any());
- verify(activity, never()).makeActiveIfNeeded(any());
- }
-
/**
* Mock {@link RootWindowContainer#resolveHomeActivity} for returning consistent activity
* info for test cases.
diff --git a/services/tests/wmtests/src/com/android/server/wm/RootWindowContainerTests.java b/services/tests/wmtests/src/com/android/server/wm/RootWindowContainerTests.java
index 72899e726b6e..191c33c61aca 100644
--- a/services/tests/wmtests/src/com/android/server/wm/RootWindowContainerTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/RootWindowContainerTests.java
@@ -184,7 +184,7 @@ public class RootWindowContainerTests extends WindowTestsBase {
};
activities[0].detachFromProcess();
activities[1].finishing = true;
- activities[1].destroyImmediately(true /* removeFromApp */, "test");
+ activities[1].destroyImmediately("test");
spyOn(wpc);
doReturn(true).when(wpc).isRemoved();
diff --git a/services/tests/wmtests/src/com/android/server/wm/SizeCompatTests.java b/services/tests/wmtests/src/com/android/server/wm/SizeCompatTests.java
index 982e469cba92..468b2c35ffc2 100644
--- a/services/tests/wmtests/src/com/android/server/wm/SizeCompatTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/SizeCompatTests.java
@@ -35,7 +35,9 @@ import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertNotEquals;
import static org.junit.Assert.assertTrue;
+import static org.mockito.ArgumentMatchers.anyBoolean;
import static org.mockito.ArgumentMatchers.anyString;
+import static org.mockito.Mockito.doCallRealMethod;
import android.app.ActivityManager;
import android.app.ActivityManagerInternal;
@@ -90,7 +92,7 @@ public class SizeCompatTests extends WindowTestsBase {
prepareUnresizable(1.5f /* maxAspect */, SCREEN_ORIENTATION_UNSPECIFIED);
final Rect originalOverrideBounds = new Rect(mActivity.getBounds());
- resizeDisplay(mStack.getDisplay(), 600, 1200);
+ resizeDisplay(mStack.mDisplayContent, 600, 1200);
// The visible activity should recompute configuration according to the last parent bounds.
mAtm.restartActivityProcessIfVisible(mActivity.appToken);
@@ -216,22 +218,50 @@ public class SizeCompatTests extends WindowTestsBase {
final Rect origBounds = new Rect(mActivity.getBounds());
final Rect currentBounds = mActivity.getWindowConfiguration().getBounds();
+ final DisplayContent display = mActivity.mDisplayContent;
// Change the size of current display.
- resizeDisplay(mStack.getDisplay(), 1000, 2000);
-
+ resizeDisplay(display, 1000, 2000);
+ // The bounds should be [100, 0 - 1100, 2500].
assertEquals(origBounds.width(), currentBounds.width());
assertEquals(origBounds.height(), currentBounds.height());
assertScaled();
+ // The scale is 2000/2500=0.8. The horizontal centered offset is (1000-(1000*0.8))/2=100.
+ final float scale = (float) display.mBaseDisplayHeight / currentBounds.height();
+ final int offsetX = (int) (display.mBaseDisplayWidth - (origBounds.width() * scale)) / 2;
+ assertEquals(offsetX, currentBounds.left);
+
// The position of configuration bounds should be the same as compat bounds.
assertEquals(mActivity.getBounds().left, currentBounds.left);
assertEquals(mActivity.getBounds().top, currentBounds.top);
// Change display size to a different orientation
- resizeDisplay(mStack.getDisplay(), 2000, 1000);
+ resizeDisplay(display, 2000, 1000);
+ // The bounds should be [800, 0 - 1800, 2500].
assertEquals(origBounds.width(), currentBounds.width());
assertEquals(origBounds.height(), currentBounds.height());
+ assertEquals(Configuration.ORIENTATION_LANDSCAPE, display.getConfiguration().orientation);
+ assertEquals(Configuration.ORIENTATION_PORTRAIT, mActivity.getConfiguration().orientation);
+
+ // The previous resize operation doesn't consider the rotation change after size changed.
+ // These setups apply the requested orientation to rotation as real case that the top fixed
+ // portrait activity will determine the display rotation.
+ final DisplayRotation displayRotation = display.getDisplayRotation();
+ doCallRealMethod().when(displayRotation).updateRotationUnchecked(anyBoolean());
+ // Skip unrelated layout procedures.
+ mAtm.deferWindowLayout();
+ display.reconfigureDisplayLocked();
+ displayRotation.updateOrientation(display.getOrientation(), true /* forceUpdate */);
+ display.sendNewConfiguration();
+
+ assertEquals(Configuration.ORIENTATION_PORTRAIT, display.getConfiguration().orientation);
+ assertEquals(Configuration.ORIENTATION_PORTRAIT, mActivity.getConfiguration().orientation);
+ // The size should still be in portrait [100, 0 - 1100, 2500] = 1000x2500.
+ assertEquals(origBounds.width(), currentBounds.width());
+ assertEquals(origBounds.height(), currentBounds.height());
+ assertEquals(offsetX, currentBounds.left);
+ assertScaled();
}
@Test
@@ -412,7 +442,7 @@ public class SizeCompatTests extends WindowTestsBase {
public void testResetNonVisibleActivity() {
setUpDisplaySizeWithApp(1000, 2500);
prepareUnresizable(1.5f, SCREEN_ORIENTATION_UNSPECIFIED);
- final DisplayContent display = mStack.getDisplay();
+ final DisplayContent display = mStack.mDisplayContent;
// Resize the display so the activity is in size compatibility mode.
resizeDisplay(display, 900, 1800);
@@ -464,7 +494,7 @@ public class SizeCompatTests extends WindowTestsBase {
});
// Resize the display so that the activity exercises size-compat mode.
- resizeDisplay(mStack.getDisplay(), 1000, 2500);
+ resizeDisplay(mStack.mDisplayContent, 1000, 2500);
// Expect the exact token when the activity is in size compatibility mode.
assertEquals(1, compatTokens.size());
@@ -477,7 +507,7 @@ public class SizeCompatTests extends WindowTestsBase {
activity.restartProcessIfVisible();
// The full lifecycle isn't hooked up so manually set state to resumed
activity.setState(Task.ActivityState.RESUMED, "testHandleActivitySizeCompatMode");
- mStack.getDisplay().handleActivitySizeCompatModeIfNeeded(activity);
+ mStack.mDisplayContent.handleActivitySizeCompatModeIfNeeded(activity);
// Expect null token when switching to non-size-compat mode activity.
assertEquals(1, compatTokens.size());
diff --git a/services/tests/wmtests/src/com/android/server/wm/TaskStackChangedListenerTest.java b/services/tests/wmtests/src/com/android/server/wm/TaskStackChangedListenerTest.java
index bce1142c99be..ca3f815698e8 100644
--- a/services/tests/wmtests/src/com/android/server/wm/TaskStackChangedListenerTest.java
+++ b/services/tests/wmtests/src/com/android/server/wm/TaskStackChangedListenerTest.java
@@ -53,7 +53,6 @@ import androidx.test.filters.FlakyTest;
import androidx.test.filters.MediumTest;
import com.android.compatibility.common.util.SystemUtil;
-import com.android.internal.annotations.GuardedBy;
import org.junit.After;
import org.junit.Before;
@@ -76,14 +75,10 @@ public class TaskStackChangedListenerTest {
private static final int WAIT_TIMEOUT_MS = 5000;
private static final Object sLock = new Object();
- @GuardedBy("sLock")
- private static boolean sTaskStackChangedCalled;
- private static boolean sActivityBResumed;
@Before
public void setUp() throws Exception {
mService = ActivityManager.getService();
- sTaskStackChangedCalled = false;
}
@After
@@ -94,47 +89,33 @@ public class TaskStackChangedListenerTest {
@Test
@Presubmit
- @FlakyTest(bugId = 130388819)
public void testTaskStackChanged_afterFinish() throws Exception {
+ final TestActivity activity = startTestActivity(ActivityA.class);
+ final CountDownLatch latch = new CountDownLatch(1);
registerTaskStackChangedListener(new TaskStackListener() {
@Override
public void onTaskStackChanged() throws RemoteException {
- synchronized (sLock) {
- sTaskStackChangedCalled = true;
- }
+ latch.countDown();
}
});
- Context context = getInstrumentation().getContext();
- context.startActivity(
- new Intent(context, ActivityA.class).addFlags(Intent.FLAG_ACTIVITY_NEW_TASK));
- UiDevice.getInstance(getInstrumentation()).waitForIdle();
- synchronized (sLock) {
- assertTrue(sTaskStackChangedCalled);
- }
- assertTrue(sActivityBResumed);
+ activity.finish();
+ waitForCallback(latch);
}
@Test
@Presubmit
public void testTaskStackChanged_resumeWhilePausing() throws Exception {
+ final CountDownLatch latch = new CountDownLatch(1);
registerTaskStackChangedListener(new TaskStackListener() {
@Override
public void onTaskStackChanged() throws RemoteException {
- synchronized (sLock) {
- sTaskStackChangedCalled = true;
- }
+ latch.countDown();
}
});
- final Context context = getInstrumentation().getContext();
- context.startActivity(new Intent(context, ResumeWhilePausingActivity.class).addFlags(
- Intent.FLAG_ACTIVITY_NEW_TASK));
- UiDevice.getInstance(getInstrumentation()).waitForIdle();
-
- synchronized (sLock) {
- assertTrue(sTaskStackChangedCalled);
- }
+ startTestActivity(ResumeWhilePausingActivity.class);
+ waitForCallback(latch);
}
@Test
@@ -512,7 +493,7 @@ public class TaskStackChangedListenerTest {
try {
final boolean result = latch.await(WAIT_TIMEOUT_MS, TimeUnit.MILLISECONDS);
if (!result) {
- throw new RuntimeException("Timed out waiting for task stack change notification");
+ throw new AssertionError("Timed out waiting for task stack change notification");
}
} catch (InterruptedException e) {
}
@@ -569,19 +550,6 @@ public class TaskStackChangedListenerTest {
}
public static class ActivityA extends TestActivity {
-
- private boolean mActivityBLaunched = false;
-
- @Override
- protected void onPostResume() {
- super.onPostResume();
- if (mActivityBLaunched) {
- return;
- }
- mActivityBLaunched = true;
- finish();
- startActivity(new Intent(this, ActivityB.class));
- }
}
public static class ActivityB extends TestActivity {
@@ -589,10 +557,6 @@ public class TaskStackChangedListenerTest {
@Override
protected void onPostResume() {
super.onPostResume();
- synchronized (sLock) {
- sTaskStackChangedCalled = false;
- }
- sActivityBResumed = true;
finish();
}
}
diff --git a/services/tests/wmtests/src/com/android/server/wm/TestWindowManagerPolicy.java b/services/tests/wmtests/src/com/android/server/wm/TestWindowManagerPolicy.java
index 4a8e8dafb57d..dc859046db42 100644
--- a/services/tests/wmtests/src/com/android/server/wm/TestWindowManagerPolicy.java
+++ b/services/tests/wmtests/src/com/android/server/wm/TestWindowManagerPolicy.java
@@ -86,11 +86,6 @@ class TestWindowManagerPolicy implements WindowManagerPolicy {
}
@Override
- public int getMaxWallpaperLayer() {
- return 0;
- }
-
- @Override
public boolean isKeyguardHostWindow(WindowManager.LayoutParams attrs) {
return attrs.type == TYPE_NOTIFICATION_SHADE;
}
@@ -377,11 +372,6 @@ class TestWindowManagerPolicy implements WindowManagerPolicy {
}
@Override
- public boolean isTopLevelWindow(int windowType) {
- return false;
- }
-
- @Override
public void startKeyguardExitAnimation(long startTime, long fadeoutDuration) {
}
diff --git a/services/tests/wmtests/src/com/android/server/wm/WallpaperControllerTests.java b/services/tests/wmtests/src/com/android/server/wm/WallpaperControllerTests.java
index ed9e2707ae39..63367ac2badf 100644
--- a/services/tests/wmtests/src/com/android/server/wm/WallpaperControllerTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/WallpaperControllerTests.java
@@ -133,8 +133,8 @@ public class WallpaperControllerTests extends WindowTestsBase {
int expectedWidth = (int) (wallpaperWidth * (displayHeight / (double) wallpaperHeight));
// Check that the wallpaper is correctly scaled
- assertEquals(new Rect(0, 0, expectedWidth, displayHeight), wallpaperWindow.getFrameLw());
- Rect portraitFrame = wallpaperWindow.getFrameLw();
+ assertEquals(new Rect(0, 0, expectedWidth, displayHeight), wallpaperWindow.getFrame());
+ Rect portraitFrame = wallpaperWindow.getFrame();
// Rotate the display
dc.getDisplayRotation().updateOrientation(ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE, true);
@@ -149,7 +149,7 @@ public class WallpaperControllerTests extends WindowTestsBase {
// Check that the wallpaper has the same frame in landscape than in portrait
assertEquals(Configuration.ORIENTATION_LANDSCAPE, dc.getConfiguration().orientation);
- assertEquals(portraitFrame, wallpaperWindow.getFrameLw());
+ assertEquals(portraitFrame, wallpaperWindow.getFrame());
}
@Test
diff --git a/services/tests/wmtests/src/com/android/server/wm/WindowFrameTests.java b/services/tests/wmtests/src/com/android/server/wm/WindowFrameTests.java
index eb2aa41192c2..ca3626d09062 100644
--- a/services/tests/wmtests/src/com/android/server/wm/WindowFrameTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/WindowFrameTests.java
@@ -89,29 +89,29 @@ public class WindowFrameTests extends WindowTestsBase {
}
private void assertFrame(WindowState w, Rect frame) {
- assertEquals(w.getFrameLw(), frame);
+ assertEquals(w.getFrame(), frame);
}
private void assertFrame(WindowState w, int left, int top, int right, int bottom) {
- assertRect(w.getFrameLw(), left, top, right, bottom);
+ assertRect(w.getFrame(), left, top, right, bottom);
}
private void assertRelFrame(WindowState w, int left, int top, int right, int bottom) {
- assertRect(w.getRelativeFrameLw(), left, top, right, bottom);
+ assertRect(w.getRelativeFrame(), left, top, right, bottom);
}
private void assertContentFrame(WindowState w, Rect expectedRect) {
- assertRect(w.getContentFrameLw(), expectedRect.left, expectedRect.top, expectedRect.right,
+ assertRect(w.getContentFrame(), expectedRect.left, expectedRect.top, expectedRect.right,
expectedRect.bottom);
}
private void assertVisibleFrame(WindowState w, Rect expectedRect) {
- assertRect(w.getVisibleFrameLw(), expectedRect.left, expectedRect.top, expectedRect.right,
+ assertRect(w.getVisibleFrame(), expectedRect.left, expectedRect.top, expectedRect.right,
expectedRect.bottom);
}
private void assertStableFrame(WindowState w, Rect expectedRect) {
- assertRect(w.getStableFrameLw(), expectedRect.left, expectedRect.top, expectedRect.right,
+ assertRect(w.getStableFrame(), expectedRect.left, expectedRect.top, expectedRect.right,
expectedRect.bottom);
}
@@ -155,7 +155,7 @@ public class WindowFrameTests extends WindowTestsBase {
// the difference between mFrame and ContentFrame. Visible
// and stable frames work the same way.
w.getWindowFrames().setFrames(pf, df, cf, vf, dcf, sf);
- w.computeFrameLw();
+ w.computeFrame();
assertFrame(w, 0, 0, 1000, 1000);
assertRelFrame(w, 0, 0, 1000, 1000);
assertContentInset(w, 0, topContentInset, 0, bottomContentInset);
@@ -170,14 +170,14 @@ public class WindowFrameTests extends WindowTestsBase {
w.mAttrs.width = 100; w.mAttrs.height = 100; //have to clear MATCH_PARENT
w.mRequestedWidth = 100;
w.mRequestedHeight = 100;
- w.computeFrameLw();
+ w.computeFrame();
assertFrame(w, 100, 100, 200, 200);
assertRelFrame(w, 100, 100, 200, 200);
assertContentInset(w, 0, 0, 0, 0);
// In this case the frames are shrunk to the window frame.
- assertContentFrame(w, w.getFrameLw());
- assertVisibleFrame(w, w.getFrameLw());
- assertStableFrame(w, w.getFrameLw());
+ assertContentFrame(w, w.getFrame());
+ assertVisibleFrame(w, w.getFrame());
+ assertStableFrame(w, w.getFrame());
}
@Test
@@ -193,7 +193,7 @@ public class WindowFrameTests extends WindowTestsBase {
// Here the window has FILL_PARENT, FILL_PARENT
// so we expect it to fill the entire available frame.
w.getWindowFrames().setFrames(pf, pf, pf, pf, pf, pf);
- w.computeFrameLw();
+ w.computeFrame();
assertFrame(w, 0, 0, 1000, 1000);
assertRelFrame(w, 0, 0, 1000, 1000);
@@ -202,14 +202,14 @@ public class WindowFrameTests extends WindowTestsBase {
// and we use mRequestedWidth/mRequestedHeight
w.mAttrs.width = 300;
w.mAttrs.height = 300;
- w.computeFrameLw();
+ w.computeFrame();
// Explicit width and height without requested width/height
// gets us nothing.
assertFrame(w, 0, 0, 0, 0);
w.mRequestedWidth = 300;
w.mRequestedHeight = 300;
- w.computeFrameLw();
+ w.computeFrame();
// With requestedWidth/Height we can freely choose our size within the
// parent bounds.
assertFrame(w, 0, 0, 300, 300);
@@ -222,14 +222,14 @@ public class WindowFrameTests extends WindowTestsBase {
w.mRequestedWidth = -1;
w.mAttrs.width = 100;
w.mAttrs.height = 100;
- w.computeFrameLw();
+ w.computeFrame();
assertFrame(w, 0, 0, 100, 100);
w.mAttrs.flags = 0;
// But sizes too large will be clipped to the containing frame
w.mRequestedWidth = 1200;
w.mRequestedHeight = 1200;
- w.computeFrameLw();
+ w.computeFrame();
assertFrame(w, 0, 0, 1000, 1000);
// Before they are clipped though windows will be shifted
@@ -237,7 +237,7 @@ public class WindowFrameTests extends WindowTestsBase {
w.mAttrs.y = 300;
w.mRequestedWidth = 1000;
w.mRequestedHeight = 1000;
- w.computeFrameLw();
+ w.computeFrame();
assertFrame(w, 0, 0, 1000, 1000);
// If there is room to move around in the parent frame the window will be shifted according
@@ -247,18 +247,18 @@ public class WindowFrameTests extends WindowTestsBase {
w.mRequestedWidth = 300;
w.mRequestedHeight = 300;
w.mAttrs.gravity = Gravity.RIGHT | Gravity.TOP;
- w.computeFrameLw();
+ w.computeFrame();
assertFrame(w, 700, 0, 1000, 300);
assertRelFrame(w, 700, 0, 1000, 300);
w.mAttrs.gravity = Gravity.RIGHT | Gravity.BOTTOM;
- w.computeFrameLw();
+ w.computeFrame();
assertFrame(w, 700, 700, 1000, 1000);
assertRelFrame(w, 700, 700, 1000, 1000);
// Window specified x and y are interpreted as offsets in the opposite
// direction of gravity
w.mAttrs.x = 100;
w.mAttrs.y = 100;
- w.computeFrameLw();
+ w.computeFrame();
assertFrame(w, 600, 600, 900, 900);
assertRelFrame(w, 600, 600, 900, 900);
}
@@ -285,12 +285,12 @@ public class WindowFrameTests extends WindowTestsBase {
final Rect pf = new Rect(0, 0, logicalWidth, logicalHeight);
final WindowFrames windowFrames = w.getWindowFrames();
windowFrames.setFrames(pf, pf, pf, pf, pf, pf);
- w.computeFrameLw();
+ w.computeFrame();
// For non fullscreen tasks the containing frame is based off the
// task bounds not the parent frame.
- assertEquals(resolvedTaskBounds, w.getFrameLw());
- assertEquals(0, w.getRelativeFrameLw().left);
- assertEquals(0, w.getRelativeFrameLw().top);
+ assertEquals(resolvedTaskBounds, w.getFrame());
+ assertEquals(0, w.getRelativeFrame().left);
+ assertEquals(0, w.getRelativeFrame().top);
assertContentFrame(w, resolvedTaskBounds);
assertContentInset(w, 0, 0, 0, 0);
@@ -300,10 +300,10 @@ public class WindowFrameTests extends WindowTestsBase {
final int cfBottom = logicalHeight / 2;
final Rect cf = new Rect(0, 0, cfRight, cfBottom);
windowFrames.setFrames(pf, pf, cf, cf, pf, cf);
- w.computeFrameLw();
- assertEquals(resolvedTaskBounds, w.getFrameLw());
- assertEquals(0, w.getRelativeFrameLw().left);
- assertEquals(0, w.getRelativeFrameLw().top);
+ w.computeFrame();
+ assertEquals(resolvedTaskBounds, w.getFrame());
+ assertEquals(0, w.getRelativeFrame().left);
+ assertEquals(0, w.getRelativeFrame().top);
int contentInsetRight = resolvedTaskBounds.right - cfRight;
int contentInsetBottom = resolvedTaskBounds.bottom - cfBottom;
assertContentInset(w, 0, 0, contentInsetRight, contentInsetBottom);
@@ -334,12 +334,12 @@ public class WindowFrameTests extends WindowTestsBase {
final WindowFrames windowFrames = w.getWindowFrames();
windowFrames.setFrames(pf, df, cf, vf, dcf, sf);
- w.computeFrameLw();
+ w.computeFrame();
assertPolicyCrop(w, 0, cf.top, logicalWidth, cf.bottom);
windowFrames.mDecorFrame.setEmpty();
// Likewise with no decor frame we would get no crop
- w.computeFrameLw();
+ w.computeFrame();
assertPolicyCrop(w, 0, 0, logicalWidth, logicalHeight);
// Now we set up a window which doesn't fill the entire decor frame.
@@ -353,7 +353,7 @@ public class WindowFrameTests extends WindowTestsBase {
w.mAttrs.height = logicalHeight / 2;
w.mRequestedWidth = logicalWidth / 2;
w.mRequestedHeight = logicalHeight / 2;
- w.computeFrameLw();
+ w.computeFrame();
// Normally the crop is shrunk from the decor frame
// to the computed window frame.
@@ -390,7 +390,7 @@ public class WindowFrameTests extends WindowTestsBase {
final Rect pf = new Rect(0, 0, logicalWidth, logicalHeight);
final WindowFrames windowFrames = w.getWindowFrames();
windowFrames.setFrames(pf, pf, pf, pf, pf, pf);
- w.computeFrameLw();
+ w.computeFrame();
// For non fullscreen tasks the containing frame is based off the
// task bounds not the parent frame.
assertFrame(w, taskLeft, taskTop, taskRight, taskBottom);
@@ -408,7 +408,7 @@ public class WindowFrameTests extends WindowTestsBase {
task.setWindowingMode(WINDOWING_MODE_FULLSCREEN);
task.setBounds(null);
windowFrames.setFrames(pf, pf, cf, cf, pf, cf);
- w.computeFrameLw();
+ w.computeFrame();
assertFrame(w, cf);
assertContentFrame(w, cf);
assertContentInset(w, 0, 0, 0, 0);
@@ -430,7 +430,7 @@ public class WindowFrameTests extends WindowTestsBase {
final WindowFrames windowFrames = w.getWindowFrames();
windowFrames.setFrames(pf, pf, pf, pf, pf, pf);
windowFrames.setDisplayCutout(cutout);
- w.computeFrameLw();
+ w.computeFrame();
assertEquals(w.getWmDisplayCutout().getDisplayCutout().getSafeInsetTop(), 50);
assertEquals(w.getWmDisplayCutout().getDisplayCutout().getSafeInsetBottom(), 0);
@@ -469,20 +469,20 @@ public class WindowFrameTests extends WindowTestsBase {
task.setBounds(winRect);
w.getWindowFrames().setFrames(pf, df, cf, vf, dcf, sf);
- w.computeFrameLw();
+ w.computeFrame();
final Rect expected = new Rect(winRect.left, cf.bottom - winRect.height(),
winRect.right, cf.bottom);
- assertEquals(expected, w.getFrameLw());
- assertEquals(expected, w.getContentFrameLw());
- assertEquals(expected, w.getVisibleFrameLw());
+ assertEquals(expected, w.getFrame());
+ assertEquals(expected, w.getContentFrame());
+ assertEquals(expected, w.getVisibleFrame());
// Now check that it won't get moved beyond the top and then has appropriate insets
winRect.bottom = 600;
task.setBounds(winRect);
w.setBounds(winRect);
w.getWindowFrames().setFrames(pf, df, cf, vf, dcf, sf);
- w.computeFrameLw();
+ w.computeFrame();
assertFrame(w, winRect.left, 0, winRect.right, winRect.height());
expected.top = 0;
@@ -492,8 +492,8 @@ public class WindowFrameTests extends WindowTestsBase {
// Check that it's moved back without ime insets
w.getWindowFrames().setFrames(pf, df, pf, pf, dcf, sf);
- w.computeFrameLw();
- assertEquals(winRect, w.getFrameLw());
+ w.computeFrame();
+ assertEquals(winRect, w.getFrame());
}
private WindowState createWindow() {
diff --git a/services/tests/wmtests/src/com/android/server/wm/WindowManagerServiceTests.java b/services/tests/wmtests/src/com/android/server/wm/WindowManagerServiceTests.java
index f97dff3162c4..2510385f4580 100644
--- a/services/tests/wmtests/src/com/android/server/wm/WindowManagerServiceTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/WindowManagerServiceTests.java
@@ -114,11 +114,11 @@ public class WindowManagerServiceTests extends WindowTestsBase {
Task tappedStack = createTaskStackOnDisplay(
WINDOWING_MODE_FULLSCREEN, ACTIVITY_TYPE_STANDARD, display);
Task tappedTask = createTaskInStack(tappedStack, 0 /* userId */);
- spyOn(mWm.mActivityTaskManager);
+ spyOn(mWm.mAtmService);
mWm.handleTaskFocusChange(tappedTask);
- verify(mWm.mActivityTaskManager).setFocusedTask(tappedTask.mTaskId);
+ verify(mWm.mAtmService).setFocusedTask(tappedTask.mTaskId);
}
@Test
@@ -135,11 +135,11 @@ public class WindowManagerServiceTests extends WindowTestsBase {
Task tappedStack = createTaskStackOnDisplay(
WINDOWING_MODE_FULLSCREEN, ACTIVITY_TYPE_HOME, display);
Task tappedTask = createTaskInStack(tappedStack, 0 /* userId */);
- spyOn(mWm.mActivityTaskManager);
+ spyOn(mWm.mAtmService);
mWm.handleTaskFocusChange(tappedTask);
- verify(mWm.mActivityTaskManager, never()).setFocusedTask(tappedTask.mTaskId);
+ verify(mWm.mAtmService, never()).setFocusedTask(tappedTask.mTaskId);
}
@Test
@@ -158,10 +158,10 @@ public class WindowManagerServiceTests extends WindowTestsBase {
Task tappedStack = createTaskStackOnTaskDisplayArea(
WINDOWING_MODE_FULLSCREEN, ACTIVITY_TYPE_HOME, secondTda);
Task tappedTask = createTaskInStack(tappedStack, 0 /* userId */);
- spyOn(mWm.mActivityTaskManager);
+ spyOn(mWm.mAtmService);
mWm.handleTaskFocusChange(tappedTask);
- verify(mWm.mActivityTaskManager).setFocusedTask(tappedTask.mTaskId);
+ verify(mWm.mAtmService).setFocusedTask(tappedTask.mTaskId);
}
}
diff --git a/services/tests/wmtests/src/com/android/server/wm/WindowOrganizerTests.java b/services/tests/wmtests/src/com/android/server/wm/WindowOrganizerTests.java
index 289d54e967f5..46a6a82faba5 100644
--- a/services/tests/wmtests/src/com/android/server/wm/WindowOrganizerTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/WindowOrganizerTests.java
@@ -930,23 +930,36 @@ public class WindowOrganizerTests extends WindowTestsBase {
final Task stack = createStack();
final Task task = createTask(stack);
final ActivityRecord activity = createActivityRecordInTask(stack.mDisplayContent, task);
+ final Task stack2 = createStack();
+ final Task task2 = createTask(stack2);
+ final ActivityRecord activity2 = createActivityRecordInTask(stack.mDisplayContent, task2);
final ITaskOrganizer organizer = registerMockOrganizer();
// Setup the task to be controlled by the MW mode organizer
stack.setWindowingMode(WINDOWING_MODE_MULTI_WINDOW);
+ stack2.setWindowingMode(WINDOWING_MODE_MULTI_WINDOW);
assertTrue(stack.isOrganized());
+ assertTrue(stack2.isOrganized());
// Verify a back pressed does not call the organizer
mWm.mAtmService.onBackPressedOnTaskRoot(activity.token);
verify(organizer, never()).onBackPressedOnTaskRoot(any());
// Enable intercepting back
- mWm.mAtmService.mTaskOrganizerController.setInterceptBackPressedOnTaskRoot(organizer,
- true);
+ mWm.mAtmService.mTaskOrganizerController.setInterceptBackPressedOnTaskRoot(
+ stack.mRemoteToken.toWindowContainerToken(), true);
// Verify now that the back press does call the organizer
mWm.mAtmService.onBackPressedOnTaskRoot(activity.token);
verify(organizer, times(1)).onBackPressedOnTaskRoot(any());
+
+ // Disable intercepting back
+ mWm.mAtmService.mTaskOrganizerController.setInterceptBackPressedOnTaskRoot(
+ stack.mRemoteToken.toWindowContainerToken(), false);
+
+ // Verify now that the back press no longer calls the organizer
+ mWm.mAtmService.onBackPressedOnTaskRoot(activity.token);
+ verify(organizer, times(1)).onBackPressedOnTaskRoot(any());
}
@Test
diff --git a/services/tests/wmtests/src/com/android/server/wm/WindowStateTests.java b/services/tests/wmtests/src/com/android/server/wm/WindowStateTests.java
index f095fd42900b..3106ca26c8a1 100644
--- a/services/tests/wmtests/src/com/android/server/wm/WindowStateTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/WindowStateTests.java
@@ -479,7 +479,7 @@ public class WindowStateTests extends WindowTestsBase {
app.mHasSurface = true;
app.mSurfaceControl = mock(SurfaceControl.class);
try {
- app.getFrameLw().set(10, 20, 60, 80);
+ app.getFrame().set(10, 20, 60, 80);
app.updateSurfacePosition(t);
app.seamlesslyRotateIfAllowed(t, ROTATION_0, ROTATION_90, true);
@@ -519,7 +519,7 @@ public class WindowStateTests extends WindowTestsBase {
new Rect(95, 378, 105, 400));
wf.setDisplayCutout(new WmDisplayCutout(cutout, new Size(200, 400)));
- app.computeFrameLw();
+ app.computeFrame();
assertThat(app.getWmDisplayCutout().getDisplayCutout(), is(cutout.inset(7, 10, 5, 20)));
}
@@ -633,7 +633,7 @@ public class WindowStateTests extends WindowTestsBase {
final WindowState win0 = createWindow(null, TYPE_APPLICATION, "win0");
final DisplayContent dc = createNewDisplay();
- win0.getFrameLw().offsetTo(PARENT_WINDOW_OFFSET, 0);
+ win0.getFrame().offsetTo(PARENT_WINDOW_OFFSET, 0);
dc.reparentDisplayContent(win0, win0.getSurfaceControl());
dc.updateLocation(win0, DISPLAY_IN_PARENT_WINDOW_OFFSET, 0);
@@ -644,7 +644,7 @@ public class WindowStateTests extends WindowTestsBase {
win1.mHasSurface = true;
win1.mSurfaceControl = mock(SurfaceControl.class);
win1.mAttrs.surfaceInsets.set(1, 2, 3, 4);
- win1.getFrameLw().offsetTo(WINDOW_OFFSET, 0);
+ win1.getFrame().offsetTo(WINDOW_OFFSET, 0);
win1.updateSurfacePosition(t);
win1.getTransformationMatrix(values, matrix);
@@ -661,14 +661,14 @@ public class WindowStateTests extends WindowTestsBase {
RecentsAnimationController recentsController = mock(RecentsAnimationController.class);
when(recentsController.shouldApplyInputConsumer(win0.mActivityRecord)).thenReturn(true);
mWm.setRecentsAnimationController(recentsController);
- assertTrue(win0.cantReceiveTouchInput());
+ assertFalse(win0.canReceiveTouchInput());
}
@Test
public void testCantReceiveTouchWhenAppTokenHiddenRequested() {
final WindowState win0 = createWindow(null, TYPE_APPLICATION, "win0");
win0.mActivityRecord.mVisibleRequested = false;
- assertTrue(win0.cantReceiveTouchInput());
+ assertFalse(win0.canReceiveTouchInput());
}
@Test
@@ -676,7 +676,7 @@ public class WindowStateTests extends WindowTestsBase {
final WindowState win0 = createWindow(null, TYPE_APPLICATION, "win0");
win0.mActivityRecord.getStack().setWindowingMode(WINDOWING_MODE_SPLIT_SCREEN_PRIMARY);
win0.mActivityRecord.getStack().setFocusable(false);
- assertTrue(win0.cantReceiveTouchInput());
+ assertFalse(win0.canReceiveTouchInput());
}
@UseTestDisplay(addWindows = W_ACTIVITY)
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 f86d8f15353e..38c4e0a7de02 100644
--- a/services/tests/wmtests/src/com/android/server/wm/WindowTestsBase.java
+++ b/services/tests/wmtests/src/com/android/server/wm/WindowTestsBase.java
@@ -1131,7 +1131,7 @@ class WindowTestsBase extends SystemServiceTestsBase {
}
@Override
- public boolean isGoneForLayoutLw() {
+ public boolean isGoneForLayout() {
return false;
}
diff --git a/services/usage/java/com/android/server/usage/UsageStatsService.java b/services/usage/java/com/android/server/usage/UsageStatsService.java
index 1e5d92b270d2..f151d9ca2420 100644
--- a/services/usage/java/com/android/server/usage/UsageStatsService.java
+++ b/services/usage/java/com/android/server/usage/UsageStatsService.java
@@ -183,6 +183,7 @@ public class UsageStatsService extends SystemService implements
private static class ActivityData {
private final String mTaskRootPackage;
private final String mTaskRootClass;
+ public int lastEvent = Event.NONE;
private ActivityData(String taskRootPackage, String taskRootClass) {
mTaskRootPackage = taskRootPackage;
mTaskRootClass = taskRootClass;
@@ -785,6 +786,7 @@ public class UsageStatsService extends SystemService implements
switch (event.mEventType) {
case Event.ACTIVITY_RESUMED:
case Event.ACTIVITY_PAUSED:
+ case Event.ACTIVITY_STOPPED:
uid = mPackageManagerInternal.getPackageUid(event.mPackage, 0, userId);
break;
default:
@@ -817,8 +819,10 @@ public class UsageStatsService extends SystemService implements
.APP_USAGE_EVENT_OCCURRED__EVENT_TYPE__MOVE_TO_FOREGROUND);
// check if this activity has already been resumed
if (mVisibleActivities.get(event.mInstanceId) != null) break;
- mVisibleActivities.put(event.mInstanceId,
- new ActivityData(event.mTaskRootPackage, event.mTaskRootClass));
+ final ActivityData resumedData = new ActivityData(event.mTaskRootPackage,
+ event.mTaskRootClass);
+ resumedData.lastEvent = Event.ACTIVITY_RESUMED;
+ mVisibleActivities.put(event.mInstanceId, resumedData);
try {
switch(mUsageSource) {
case USAGE_SOURCE_CURRENT_ACTIVITY:
@@ -834,16 +838,17 @@ public class UsageStatsService extends SystemService implements
}
break;
case Event.ACTIVITY_PAUSED:
- if (event.mTaskRootPackage == null) {
- // Task Root info is missing. Repair the event based on previous data
- final ActivityData prevData = mVisibleActivities.get(event.mInstanceId);
- if (prevData == null) {
- Slog.w(TAG, "Unexpected activity event reported! (" + event.mPackage
- + "/" + event.mClass + " event : " + event.mEventType
- + " instanceId : " + event.mInstanceId + ")");
- } else {
- event.mTaskRootPackage = prevData.mTaskRootPackage;
- event.mTaskRootClass = prevData.mTaskRootClass;
+ final ActivityData pausedData = mVisibleActivities.get(event.mInstanceId);
+ if (pausedData == null) {
+ Slog.w(TAG, "Unexpected activity event reported! (" + event.mPackage
+ + "/" + event.mClass + " event : " + event.mEventType
+ + " instanceId : " + event.mInstanceId + ")");
+ } else {
+ pausedData.lastEvent = Event.ACTIVITY_PAUSED;
+ if (event.mTaskRootPackage == null) {
+ // Task Root info is missing. Repair the event based on previous data
+ event.mTaskRootPackage = pausedData.mTaskRootPackage;
+ event.mTaskRootClass = pausedData.mTaskRootClass;
}
}
FrameworkStatsLog.write(
@@ -866,6 +871,16 @@ public class UsageStatsService extends SystemService implements
return;
}
+ if (prevData.lastEvent != Event.ACTIVITY_PAUSED) {
+ FrameworkStatsLog.write(
+ FrameworkStatsLog.APP_USAGE_EVENT_OCCURRED,
+ uid,
+ event.mPackage,
+ event.mClass,
+ FrameworkStatsLog
+ .APP_USAGE_EVENT_OCCURRED__EVENT_TYPE__MOVE_TO_BACKGROUND);
+ }
+
ArraySet<String> tokens;
synchronized (mUsageReporters) {
tokens = mUsageReporters.removeReturnOld(event.mInstanceId);
@@ -1653,8 +1668,8 @@ public class UsageStatsService extends SystemService implements
// If the calling app is asking about itself, continue, else check for permission.
if (packageName.equals(callingPackage)) {
- final int actualCallingUid = mPackageManagerInternal.getPackageUidInternal(
- callingPackage, 0, userId);
+ final int actualCallingUid = mPackageManagerInternal.getPackageUid(
+ callingPackage, /* flags= */ 0, userId);
if (actualCallingUid != callingUid) {
return false;
}
diff --git a/telephony/java/android/telephony/CarrierConfigManager.java b/telephony/java/android/telephony/CarrierConfigManager.java
index a229efbe9970..470d4bec4c38 100755
--- a/telephony/java/android/telephony/CarrierConfigManager.java
+++ b/telephony/java/android/telephony/CarrierConfigManager.java
@@ -1678,6 +1678,15 @@ public class CarrierConfigManager {
"hide_lte_plus_data_icon_bool";
/**
+ * The combined channel bandwidth threshold (non-inclusive) in KHz required to display the
+ * LTE+ data icon. It is 20000 by default, meaning the LTE+ icon will be shown if the device is
+ * using carrier aggregation and the combined channel bandwidth is strictly greater than 20 MHz.
+ * @hide
+ */
+ public static final String KEY_LTE_PLUS_THRESHOLD_BANDWIDTH_KHZ_INT =
+ "lte_plus_threshold_bandwidth_khz_int";
+
+ /**
* The string is used to filter redundant string from PLMN Network Name that's supplied by
* specific carrier.
*
@@ -4259,6 +4268,7 @@ public class CarrierConfigManager {
sDefaults.putString(KEY_OPERATOR_NAME_FILTER_PATTERN_STRING, "");
sDefaults.putString(KEY_SHOW_CARRIER_DATA_ICON_PATTERN_STRING, "");
sDefaults.putBoolean(KEY_HIDE_LTE_PLUS_DATA_ICON_BOOL, true);
+ sDefaults.putInt(KEY_LTE_PLUS_THRESHOLD_BANDWIDTH_KHZ_INT, 20000);
sDefaults.putBoolean(KEY_NR_ENABLED_BOOL, true);
sDefaults.putBoolean(KEY_LTE_ENABLED_BOOL, true);
sDefaults.putBoolean(KEY_SUPPORT_TDSCDMA_BOOL, false);
diff --git a/tests/FlickerTests/Android.bp b/tests/FlickerTests/Android.bp
index 952997efa0d4..943d78398879 100644
--- a/tests/FlickerTests/Android.bp
+++ b/tests/FlickerTests/Android.bp
@@ -18,7 +18,7 @@ android_test {
name: "FlickerTests",
srcs: ["src/**/*.java", "src/**/*.kt"],
manifest: "AndroidManifest.xml",
- test_config: "AndroidTest.xml",
+ test_config: "AndroidTestPhysicalDevices.xml",
platform_apis: true,
certificate: "platform",
test_suites: ["device-tests"],
@@ -33,3 +33,24 @@ android_test {
"launcher-aosp-tapl"
],
}
+
+
+android_test {
+ name: "FlickerTestsVirtual",
+ srcs: ["src/**/*.java", "src/**/*.kt"],
+ manifest: "AndroidManifest.xml",
+ test_config: "AndroidTestVirtualDevices.xml",
+ platform_apis: true,
+ certificate: "platform",
+ test_suites: ["device-tests"],
+ libs: ["android.test.runner"],
+ static_libs: [
+ "androidx.test.ext.junit",
+ "flickertestapplib",
+ "flickerlib",
+ "truth-prebuilt",
+ "app-helpers-core",
+ "launcher-helper-lib",
+ "launcher-aosp-tapl"
+ ],
+} \ No newline at end of file
diff --git a/tests/FlickerTests/AndroidTest.xml b/tests/FlickerTests/AndroidTestPhysicalDevices.xml
index 68c99a35e5d0..16504389098c 100644
--- a/tests/FlickerTests/AndroidTest.xml
+++ b/tests/FlickerTests/AndroidTestPhysicalDevices.xml
@@ -27,6 +27,7 @@
</target_preparer>
<test class="com.android.tradefed.testtype.AndroidJUnitTest">
<option name="package" value="com.android.server.wm.flicker"/>
+ <option name="include-annotation" value="androidx.test.filters.RequiresDevice" />
<option name="exclude-annotation" value="androidx.test.filters.FlakyTest" />
<option name="shell-timeout" value="6600s" />
<option name="test-timeout" value="6000s" />
diff --git a/tests/FlickerTests/AndroidTestVirtualDevices.xml b/tests/FlickerTests/AndroidTestVirtualDevices.xml
new file mode 100644
index 000000000000..222212a74cd0
--- /dev/null
+++ b/tests/FlickerTests/AndroidTestVirtualDevices.xml
@@ -0,0 +1,41 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ * Copyright 2018 Google Inc. All Rights Reserved.
+ -->
+<configuration description="Runs WindowManager Flicker Tests">
+ <option name="test-tag" value="FlickerTests" />
+ <target_preparer class="com.android.tradefed.targetprep.DeviceSetup">
+ <!-- keeps the screen on during tests -->
+ <option name="screen-always-on" value="on" />
+ <!-- prevents the phone from restarting -->
+ <option name="force-skip-system-props" value="true" />
+ <!-- set WM tracing verbose level to all -->
+ <option name="run-command" value="cmd window tracing level all" />
+ <!-- inform WM to log all transactions -->
+ <option name="run-command" value="cmd window tracing transaction" />
+ <!-- restart launcher to activate TAPL -->
+ <option name="run-command" value="setprop ro.test_harness 1 ; am force-stop com.google.android.apps.nexuslauncher" />
+ </target_preparer>
+ <target_preparer class="com.android.tradefed.targetprep.DeviceCleaner">
+ <!-- reboot the device to teardown any crashed tests -->
+ <option name="cleanup-action" value="REBOOT" />
+ </target_preparer>
+ <target_preparer class="com.android.tradefed.targetprep.suite.SuiteApkInstaller">
+ <option name="cleanup-apks" value="true"/>
+ <option name="test-file-name" value="FlickerTests.apk"/>
+ <option name="test-file-name" value="FlickerTestApp.apk" />
+ </target_preparer>
+ <test class="com.android.tradefed.testtype.AndroidJUnitTest">
+ <option name="package" value="com.android.server.wm.flicker"/>
+ <option name="exclude-annotation" value="androidx.test.filters.RequiresDevice" />
+ <option name="exclude-annotation" value="androidx.test.filters.FlakyTest" />
+ <option name="shell-timeout" value="6600s" />
+ <option name="test-timeout" value="6000s" />
+ <option name="hidden-api-checks" value="false" />
+ </test>
+ <metrics_collector class="com.android.tradefed.device.metric.FilePullerLogCollector">
+ <option name="directory-keys" value="/storage/emulated/0/Android/data/com.android.server.wm.flicker/files" />
+ <option name="collect-on-run-ended-only" value="true" />
+ <option name="clean-up" value="true" />
+ </metrics_collector>
+</configuration>
diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/ime/CloseImeAutoOpenWindowToAppTest.kt b/tests/FlickerTests/src/com/android/server/wm/flicker/ime/CloseImeAutoOpenWindowToAppTest.kt
index 80d039475fab..404c7891bcad 100644
--- a/tests/FlickerTests/src/com/android/server/wm/flicker/ime/CloseImeAutoOpenWindowToAppTest.kt
+++ b/tests/FlickerTests/src/com/android/server/wm/flicker/ime/CloseImeAutoOpenWindowToAppTest.kt
@@ -17,7 +17,7 @@
package com.android.server.wm.flicker.ime
import android.view.Surface
-import androidx.test.filters.LargeTest
+import androidx.test.filters.RequiresDevice
import com.android.server.wm.flicker.dsl.flicker
import com.android.server.wm.flicker.helpers.ImeAppAutoFocusHelper
import com.android.server.wm.flicker.helpers.ImeAppHelper
@@ -39,7 +39,7 @@ import org.junit.runners.Parameterized
* Test IME window closing back to app window transitions.
* To run this test: `atest FlickerTests:CloseImeWindowToAppTest`
*/
-@LargeTest
+@RequiresDevice
@RunWith(Parameterized::class)
@FixMethodOrder(MethodSorters.NAME_ASCENDING)
class CloseImeAutoOpenWindowToAppTest(
diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/ime/CloseImeAutoOpenWindowToHomeTest.kt b/tests/FlickerTests/src/com/android/server/wm/flicker/ime/CloseImeAutoOpenWindowToHomeTest.kt
index c0658fe4422e..b64811b2767d 100644
--- a/tests/FlickerTests/src/com/android/server/wm/flicker/ime/CloseImeAutoOpenWindowToHomeTest.kt
+++ b/tests/FlickerTests/src/com/android/server/wm/flicker/ime/CloseImeAutoOpenWindowToHomeTest.kt
@@ -17,7 +17,7 @@
package com.android.server.wm.flicker.ime
import android.view.Surface
-import androidx.test.filters.LargeTest
+import androidx.test.filters.RequiresDevice
import com.android.server.wm.flicker.dsl.flicker
import com.android.server.wm.flicker.helpers.ImeAppAutoFocusHelper
import com.android.server.wm.flicker.helpers.ImeAppHelper
@@ -39,7 +39,7 @@ import org.junit.runners.Parameterized
* Test IME window closing back to app window transitions.
* To run this test: `atest FlickerTests:CloseImeWindowToAppTest`
*/
-@LargeTest
+@RequiresDevice
@RunWith(Parameterized::class)
@FixMethodOrder(MethodSorters.NAME_ASCENDING)
class CloseImeAutoOpenWindowToHomeTest(
diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/ime/CloseImeWindowToAppTest.kt b/tests/FlickerTests/src/com/android/server/wm/flicker/ime/CloseImeWindowToAppTest.kt
index 67c46d3f4722..0940c192517e 100644
--- a/tests/FlickerTests/src/com/android/server/wm/flicker/ime/CloseImeWindowToAppTest.kt
+++ b/tests/FlickerTests/src/com/android/server/wm/flicker/ime/CloseImeWindowToAppTest.kt
@@ -17,7 +17,7 @@
package com.android.server.wm.flicker.ime
import android.view.Surface
-import androidx.test.filters.LargeTest
+import androidx.test.filters.RequiresDevice
import com.android.server.wm.flicker.NonRotationTestBase
import com.android.server.wm.flicker.dsl.flicker
import com.android.server.wm.flicker.helpers.ImeAppHelper
@@ -39,7 +39,7 @@ import org.junit.runners.Parameterized
* Test IME window closing back to app window transitions.
* To run this test: `atest FlickerTests:CloseImeWindowToAppTest`
*/
-@LargeTest
+@RequiresDevice
@RunWith(Parameterized::class)
@FixMethodOrder(MethodSorters.NAME_ASCENDING)
open class CloseImeWindowToAppTest(
diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/ime/CloseImeWindowToHomeTest.kt b/tests/FlickerTests/src/com/android/server/wm/flicker/ime/CloseImeWindowToHomeTest.kt
index dcf308533ee6..c2e87dbbf24b 100644
--- a/tests/FlickerTests/src/com/android/server/wm/flicker/ime/CloseImeWindowToHomeTest.kt
+++ b/tests/FlickerTests/src/com/android/server/wm/flicker/ime/CloseImeWindowToHomeTest.kt
@@ -17,7 +17,7 @@
package com.android.server.wm.flicker.ime
import android.view.Surface
-import androidx.test.filters.LargeTest
+import androidx.test.filters.RequiresDevice
import com.android.server.wm.flicker.NonRotationTestBase
import com.android.server.wm.flicker.dsl.flicker
import com.android.server.wm.flicker.helpers.ImeAppHelper
@@ -40,7 +40,7 @@ import org.junit.runners.Parameterized
* Test IME window closing to home transitions.
* To run this test: `atest FlickerTests:CloseImeWindowToHomeTest`
*/
-@LargeTest
+@RequiresDevice
@RunWith(Parameterized::class)
@FixMethodOrder(MethodSorters.NAME_ASCENDING)
open class CloseImeWindowToHomeTest(
diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/ime/OpenImeWindowTest.kt b/tests/FlickerTests/src/com/android/server/wm/flicker/ime/OpenImeWindowTest.kt
index 5874a0736d85..11ccb69c46cf 100644
--- a/tests/FlickerTests/src/com/android/server/wm/flicker/ime/OpenImeWindowTest.kt
+++ b/tests/FlickerTests/src/com/android/server/wm/flicker/ime/OpenImeWindowTest.kt
@@ -17,7 +17,7 @@
package com.android.server.wm.flicker.ime
import android.view.Surface
-import androidx.test.filters.LargeTest
+import androidx.test.filters.RequiresDevice
import com.android.server.wm.flicker.NonRotationTestBase
import com.android.server.wm.flicker.dsl.flicker
import com.android.server.wm.flicker.helpers.ImeAppHelper
@@ -39,7 +39,7 @@ import org.junit.runners.Parameterized
* Test IME window opening transitions.
* To run this test: `atest FlickerTests:OpenImeWindowTest`
*/
-@LargeTest
+@RequiresDevice
@RunWith(Parameterized::class)
@FixMethodOrder(MethodSorters.NAME_ASCENDING)
class OpenImeWindowTest(
diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/launch/OpenAppColdTest.kt b/tests/FlickerTests/src/com/android/server/wm/flicker/launch/OpenAppColdTest.kt
index 62337e9bff34..254209aee450 100644
--- a/tests/FlickerTests/src/com/android/server/wm/flicker/launch/OpenAppColdTest.kt
+++ b/tests/FlickerTests/src/com/android/server/wm/flicker/launch/OpenAppColdTest.kt
@@ -17,7 +17,7 @@
package com.android.server.wm.flicker.launch
import android.view.Surface
-import androidx.test.filters.LargeTest
+import androidx.test.filters.RequiresDevice
import com.android.server.wm.flicker.dsl.flicker
import com.android.server.wm.flicker.focusChanges
import com.android.server.wm.flicker.helpers.wakeUpAndGoToHomeScreen
@@ -38,7 +38,7 @@ import org.junit.runners.Parameterized
* Test cold launch app from launcher.
* To run this test: `atest FlickerTests:OpenAppColdTest`
*/
-@LargeTest
+@RequiresDevice
@RunWith(Parameterized::class)
@FixMethodOrder(MethodSorters.NAME_ASCENDING)
class OpenAppColdTest(
diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/launch/OpenAppWarmTest.kt b/tests/FlickerTests/src/com/android/server/wm/flicker/launch/OpenAppWarmTest.kt
index 57d6127b1cd1..dda41a3021a0 100644
--- a/tests/FlickerTests/src/com/android/server/wm/flicker/launch/OpenAppWarmTest.kt
+++ b/tests/FlickerTests/src/com/android/server/wm/flicker/launch/OpenAppWarmTest.kt
@@ -17,7 +17,7 @@
package com.android.server.wm.flicker.launch
import android.view.Surface
-import androidx.test.filters.LargeTest
+import androidx.test.filters.RequiresDevice
import com.android.server.wm.flicker.StandardAppHelper
import com.android.server.wm.flicker.dsl.flicker
import com.android.server.wm.flicker.focusChanges
@@ -39,7 +39,7 @@ import org.junit.runners.Parameterized
* Test warm launch app.
* To run this test: `atest FlickerTests:OpenAppWarmTest`
*/
-@LargeTest
+@RequiresDevice
@RunWith(Parameterized::class)
@FixMethodOrder(MethodSorters.NAME_ASCENDING)
class OpenAppWarmTest(
diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/pip/EnterPipTest.kt b/tests/FlickerTests/src/com/android/server/wm/flicker/pip/EnterPipTest.kt
index 4acd97553bc0..9cfc03304fe7 100644
--- a/tests/FlickerTests/src/com/android/server/wm/flicker/pip/EnterPipTest.kt
+++ b/tests/FlickerTests/src/com/android/server/wm/flicker/pip/EnterPipTest.kt
@@ -18,7 +18,7 @@ package com.android.server.wm.flicker.pip
import android.view.Surface
import androidx.test.filters.FlakyTest
-import androidx.test.filters.LargeTest
+import androidx.test.filters.RequiresDevice
import com.android.server.wm.flicker.dsl.flicker
import com.android.server.wm.flicker.helpers.closePipWindow
import com.android.server.wm.flicker.helpers.expandPipWindow
@@ -41,7 +41,7 @@ import org.junit.runners.Parameterized
* Test Pip launch.
* To run this test: `atest FlickerTests:PipToAppTest`
*/
-@LargeTest
+@RequiresDevice
@RunWith(Parameterized::class)
@FixMethodOrder(MethodSorters.NAME_ASCENDING)
@FlakyTest(bugId = 152738416)
diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/pip/PipToAppTest.kt b/tests/FlickerTests/src/com/android/server/wm/flicker/pip/PipToAppTest.kt
index 04c2f59118bd..deccc908961d 100644
--- a/tests/FlickerTests/src/com/android/server/wm/flicker/pip/PipToAppTest.kt
+++ b/tests/FlickerTests/src/com/android/server/wm/flicker/pip/PipToAppTest.kt
@@ -18,7 +18,7 @@ package com.android.server.wm.flicker.pip
import android.view.Surface
import androidx.test.filters.FlakyTest
-import androidx.test.filters.LargeTest
+import androidx.test.filters.RequiresDevice
import com.android.server.wm.flicker.dsl.flicker
import com.android.server.wm.flicker.focusChanges
import com.android.server.wm.flicker.helpers.closePipWindow
@@ -42,7 +42,7 @@ import org.junit.runners.Parameterized
* Test Pip launch.
* To run this test: `atest FlickerTests:PipToAppTest`
*/
-@LargeTest
+@RequiresDevice
@RunWith(Parameterized::class)
@FixMethodOrder(MethodSorters.NAME_ASCENDING)
@FlakyTest(bugId = 152738416)
diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/pip/PipToHomeTest.kt b/tests/FlickerTests/src/com/android/server/wm/flicker/pip/PipToHomeTest.kt
index b6074cd7033b..f40869c88d63 100644
--- a/tests/FlickerTests/src/com/android/server/wm/flicker/pip/PipToHomeTest.kt
+++ b/tests/FlickerTests/src/com/android/server/wm/flicker/pip/PipToHomeTest.kt
@@ -18,7 +18,7 @@ package com.android.server.wm.flicker.pip
import android.view.Surface
import androidx.test.filters.FlakyTest
-import androidx.test.filters.LargeTest
+import androidx.test.filters.RequiresDevice
import com.android.server.wm.flicker.dsl.flicker
import com.android.server.wm.flicker.focusChanges
import com.android.server.wm.flicker.helpers.closePipWindow
@@ -41,7 +41,7 @@ import org.junit.runners.Parameterized
* Test Pip launch.
* To run this test: `atest FlickerTests:PipToHomeTest`
*/
-@LargeTest
+@RequiresDevice
@RunWith(Parameterized::class)
@FixMethodOrder(MethodSorters.NAME_ASCENDING)
@FlakyTest(bugId = 152738416)
diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/rotation/ChangeAppRotationTest.kt b/tests/FlickerTests/src/com/android/server/wm/flicker/rotation/ChangeAppRotationTest.kt
index 5e75e4a144bf..0ca150892f36 100644
--- a/tests/FlickerTests/src/com/android/server/wm/flicker/rotation/ChangeAppRotationTest.kt
+++ b/tests/FlickerTests/src/com/android/server/wm/flicker/rotation/ChangeAppRotationTest.kt
@@ -16,8 +16,8 @@
package com.android.server.wm.flicker.rotation
+import androidx.test.filters.RequiresDevice
import android.view.Surface
-import androidx.test.filters.LargeTest
import com.android.server.wm.flicker.NonRotationTestBase.Companion.SCREENSHOT_LAYER
import com.android.server.wm.flicker.RotationTestBase
import com.android.server.wm.flicker.StandardAppHelper
@@ -42,7 +42,7 @@ import org.junit.runners.Parameterized
* Cycle through supported app rotations.
* To run this test: `atest FlickerTest:ChangeAppRotationTest`
*/
-@LargeTest
+@RequiresDevice
@RunWith(Parameterized::class)
@FixMethodOrder(MethodSorters.NAME_ASCENDING)
class ChangeAppRotationTest(
diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/rotation/SeamlessAppRotationTest.kt b/tests/FlickerTests/src/com/android/server/wm/flicker/rotation/SeamlessAppRotationTest.kt
index de87b412fc90..33a823d6cfc9 100644
--- a/tests/FlickerTests/src/com/android/server/wm/flicker/rotation/SeamlessAppRotationTest.kt
+++ b/tests/FlickerTests/src/com/android/server/wm/flicker/rotation/SeamlessAppRotationTest.kt
@@ -20,14 +20,13 @@ import android.content.Intent
import android.content.Intent.FLAG_ACTIVITY_NEW_TASK
import android.view.Surface
import androidx.test.filters.FlakyTest
-import androidx.test.filters.LargeTest
+import androidx.test.filters.RequiresDevice
import androidx.test.uiautomator.By
import androidx.test.uiautomator.Until
import com.android.server.wm.flicker.RotationTestBase
import com.android.server.wm.flicker.dsl.flicker
import com.android.server.wm.flicker.focusDoesNotChange
import com.android.server.wm.flicker.helpers.WindowUtils
-import com.android.server.wm.flicker.dsl.flicker
import com.android.server.wm.flicker.helpers.stopPackage
import com.android.server.wm.flicker.helpers.wakeUpAndGoToHomeScreen
import com.android.server.wm.flicker.navBarLayerIsAlwaysVisible
@@ -48,7 +47,7 @@ import org.junit.runners.Parameterized
* Cycle through supported app rotations using seamless rotations.
* To run this test: `atest FlickerTests:SeamlessAppRotationTest`
*/
-@LargeTest
+@RequiresDevice
@RunWith(Parameterized::class)
@FixMethodOrder(MethodSorters.NAME_ASCENDING)
@FlakyTest(bugId = 147659548)
diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/splitscreen/OpenAppToSplitScreenTest.kt b/tests/FlickerTests/src/com/android/server/wm/flicker/splitscreen/OpenAppToSplitScreenTest.kt
index 279092d716e2..c5e48d966155 100644
--- a/tests/FlickerTests/src/com/android/server/wm/flicker/splitscreen/OpenAppToSplitScreenTest.kt
+++ b/tests/FlickerTests/src/com/android/server/wm/flicker/splitscreen/OpenAppToSplitScreenTest.kt
@@ -17,7 +17,7 @@
package com.android.server.wm.flicker.splitscreen
import android.view.Surface
-import androidx.test.filters.LargeTest
+import androidx.test.filters.RequiresDevice
import com.android.server.wm.flicker.NonRotationTestBase
import com.android.server.wm.flicker.StandardAppHelper
import com.android.server.wm.flicker.dsl.flicker
@@ -43,7 +43,7 @@ import org.junit.runners.Parameterized
* Test open app to split screen.
* To run this test: `atest FlickerTests:OpenAppToSplitScreenTest`
*/
-@LargeTest
+@RequiresDevice
@RunWith(Parameterized::class)
@FixMethodOrder(MethodSorters.NAME_ASCENDING)
class OpenAppToSplitScreenTest(
diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/splitscreen/ResizeSplitScreenTest.kt b/tests/FlickerTests/src/com/android/server/wm/flicker/splitscreen/ResizeSplitScreenTest.kt
index a08b2bfdf1fe..91211cabf45c 100644
--- a/tests/FlickerTests/src/com/android/server/wm/flicker/splitscreen/ResizeSplitScreenTest.kt
+++ b/tests/FlickerTests/src/com/android/server/wm/flicker/splitscreen/ResizeSplitScreenTest.kt
@@ -21,7 +21,7 @@ import android.util.Rational
import android.view.Surface
import androidx.test.ext.junit.runners.AndroidJUnit4
import androidx.test.filters.FlakyTest
-import androidx.test.filters.LargeTest
+import androidx.test.filters.RequiresDevice
import androidx.test.uiautomator.By
import com.android.server.wm.flicker.FlickerTestBase
import com.android.server.wm.flicker.StandardAppHelper
@@ -52,7 +52,7 @@ import org.junit.runners.MethodSorters
*
* Currently it runs only in 0 degrees because of b/156100803
*/
-@LargeTest
+@RequiresDevice
@RunWith(AndroidJUnit4::class)
@FixMethodOrder(MethodSorters.NAME_ASCENDING)
@FlakyTest(bugId = 159096424)
diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/splitscreen/SplitScreenToLauncherTest.kt b/tests/FlickerTests/src/com/android/server/wm/flicker/splitscreen/SplitScreenToLauncherTest.kt
index e2d78399b35b..5c7dcd901a41 100644
--- a/tests/FlickerTests/src/com/android/server/wm/flicker/splitscreen/SplitScreenToLauncherTest.kt
+++ b/tests/FlickerTests/src/com/android/server/wm/flicker/splitscreen/SplitScreenToLauncherTest.kt
@@ -17,7 +17,7 @@
package com.android.server.wm.flicker.splitscreen
import android.view.Surface
-import androidx.test.filters.LargeTest
+import androidx.test.filters.RequiresDevice
import com.android.server.wm.flicker.NonRotationTestBase
import com.android.server.wm.flicker.StandardAppHelper
import com.android.server.wm.flicker.dsl.flicker
@@ -43,7 +43,7 @@ import org.junit.runners.Parameterized
* Test open app to split screen.
* To run this test: `atest FlickerTests:SplitScreenToLauncherTest`
*/
-@LargeTest
+@RequiresDevice
@RunWith(Parameterized::class)
@FixMethodOrder(MethodSorters.NAME_ASCENDING)
class SplitScreenToLauncherTest(
diff --git a/tests/RollbackTest/Android.bp b/tests/RollbackTest/Android.bp
index 4f5a30502c91..7dd003eb9755 100644
--- a/tests/RollbackTest/Android.bp
+++ b/tests/RollbackTest/Android.bp
@@ -15,6 +15,7 @@
android_test {
name: "RollbackTest",
manifest: "RollbackTest/AndroidManifest.xml",
+ platform_apis: true,
srcs: ["RollbackTest/src/**/*.java"],
static_libs: ["androidx.test.rules", "cts-rollback-lib", "cts-install-lib"],
test_suites: ["general-tests"],
diff --git a/tests/RollbackTest/RollbackTest/src/com/android/tests/rollback/RollbackTest.java b/tests/RollbackTest/RollbackTest/src/com/android/tests/rollback/RollbackTest.java
index de51c5ca19ed..0db2b2af7260 100644
--- a/tests/RollbackTest/RollbackTest/src/com/android/tests/rollback/RollbackTest.java
+++ b/tests/RollbackTest/RollbackTest/src/com/android/tests/rollback/RollbackTest.java
@@ -175,7 +175,7 @@ public class RollbackTest {
assertThat(InstallUtils.getInstalledVersion(TestApp.A)).isEqualTo(1);
UserManager um = (UserManager) context.getSystemService(context.USER_SERVICE);
- List<Integer> userIds = um.getUsers(true)
+ List<Integer> userIds = um.getAliveUsers()
.stream().map(user -> user.id).collect(Collectors.toList());
assertThat(InstallUtils.isOnlyInstalledForUser(TestApp.A,
context.getUserId(), userIds)).isTrue();
diff --git a/tests/SilkFX/Android.bp b/tests/SilkFX/Android.bp
index ca0a091e65bb..92e3efa7fd55 100644
--- a/tests/SilkFX/Android.bp
+++ b/tests/SilkFX/Android.bp
@@ -19,4 +19,10 @@ android_test {
srcs: ["**/*.java", "**/*.kt"],
platform_apis: true,
certificate: "platform",
+ static_libs: [
+ "androidx.core_core",
+ "androidx.appcompat_appcompat",
+ "com.google.android.material_material",
+ "androidx-constraintlayout_constraintlayout",
+ ],
}
diff --git a/tests/SilkFX/AndroidManifest.xml b/tests/SilkFX/AndroidManifest.xml
index ca9550a9eeab..050e9c33aeac 100644
--- a/tests/SilkFX/AndroidManifest.xml
+++ b/tests/SilkFX/AndroidManifest.xml
@@ -39,5 +39,8 @@
<activity android:name=".hdr.GlowActivity"
android:label="Glow Examples"/>
+ <activity android:name=".materials.GlassActivity"
+ android:label="Glass Examples"/>
+
</application>
</manifest>
diff --git a/tests/SilkFX/res/drawable-hdpi/background1.jpeg b/tests/SilkFX/res/drawable-hdpi/background1.jpeg
new file mode 100644
index 000000000000..dcdfa7b850bc
--- /dev/null
+++ b/tests/SilkFX/res/drawable-hdpi/background1.jpeg
Binary files differ
diff --git a/tests/SilkFX/res/drawable-hdpi/background2.jpeg b/tests/SilkFX/res/drawable-hdpi/background2.jpeg
new file mode 100644
index 000000000000..dc7ce84e6784
--- /dev/null
+++ b/tests/SilkFX/res/drawable-hdpi/background2.jpeg
Binary files differ
diff --git a/tests/SilkFX/res/drawable-hdpi/background3.jpeg b/tests/SilkFX/res/drawable-hdpi/background3.jpeg
new file mode 100644
index 000000000000..12b3429e3920
--- /dev/null
+++ b/tests/SilkFX/res/drawable-hdpi/background3.jpeg
Binary files differ
diff --git a/tests/SilkFX/res/drawable-hdpi/noise.png b/tests/SilkFX/res/drawable-hdpi/noise.png
new file mode 100644
index 000000000000..053995dad760
--- /dev/null
+++ b/tests/SilkFX/res/drawable-hdpi/noise.png
Binary files differ
diff --git a/tests/SilkFX/res/layout/activity_glass.xml b/tests/SilkFX/res/layout/activity_glass.xml
new file mode 100644
index 000000000000..85dab9315197
--- /dev/null
+++ b/tests/SilkFX/res/layout/activity_glass.xml
@@ -0,0 +1,246 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+** Copyright 2012, 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.
+-->
+<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:app="http://schemas.android.com/apk/res-auto"
+ xmlns:tools="http://schemas.android.com/tools"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent"
+ tools:context=".MainActivity">
+
+ <ImageView
+ android:id="@+id/background"
+ android:layout_width="0dp"
+ android:layout_height="0dp"
+ android:scaleType="matrix"
+ app:layout_constraintBottom_toBottomOf="parent"
+ app:layout_constraintEnd_toEndOf="parent"
+ app:layout_constraintStart_toStartOf="parent"
+ app:layout_constraintTop_toTopOf="parent"
+ tools:srcCompat="@drawable/background1" />
+
+ <com.android.test.silkfx.materials.GlassView
+ android:id="@+id/materialView"
+ android:layout_width="0dp"
+ android:layout_height="180dp"
+ android:layout_marginEnd="64dp"
+ android:layout_marginStart="64dp"
+ app:layout_constraintBottom_toTopOf="@+id/bottomPanel"
+ app:layout_constraintEnd_toEndOf="parent"
+ app:layout_constraintStart_toStartOf="parent"
+ app:layout_constraintTop_toTopOf="parent" />
+
+ <androidx.constraintlayout.widget.ConstraintLayout
+ android:id="@+id/bottomPanel"
+ android:layout_width="0dp"
+ android:layout_height="wrap_content"
+ android:background="?android:attr/colorBackground"
+ android:paddingTop="24dp"
+ app:layout_constraintEnd_toEndOf="parent"
+ app:layout_constraintStart_toStartOf="parent"
+ app:layout_constraintBottom_toBottomOf="parent">
+
+ <SeekBar
+ android:id="@+id/materialOpacity"
+ android:layout_width="0dp"
+ android:layout_height="wrap_content"
+ android:layout_marginStart="12dp"
+ android:layout_marginEnd="12dp"
+ android:layout_marginBottom="16dp"
+ android:max="100"
+ android:progress="12"
+ app:layout_constraintBottom_toTopOf="@+id/scrimOpacityTitle"
+ app:layout_constraintEnd_toEndOf="parent"
+ app:layout_constraintHorizontal_bias="1.0"
+ app:layout_constraintStart_toStartOf="parent" />
+
+ <SeekBar
+ android:id="@+id/blurRadius"
+ android:layout_width="0dp"
+ android:layout_height="wrap_content"
+ android:layout_marginBottom="16dp"
+ android:layout_marginEnd="12dp"
+ android:layout_marginStart="12dp"
+ android:max="150"
+ android:progress="50"
+ app:layout_constraintBottom_toTopOf="@+id/materialOpacityTitle"
+ app:layout_constraintEnd_toEndOf="parent"
+ app:layout_constraintHorizontal_bias="1.0"
+ app:layout_constraintStart_toStartOf="parent" />
+
+ <SeekBar
+ android:id="@+id/scrimOpacity"
+ android:layout_width="0dp"
+ android:layout_height="wrap_content"
+ android:layout_marginStart="12dp"
+ android:layout_marginEnd="12dp"
+ android:layout_marginBottom="16dp"
+ android:max="100"
+ android:progress="50"
+ app:layout_constraintBottom_toTopOf="@+id/noiseOpacityTitle"
+ app:layout_constraintEnd_toEndOf="parent"
+ app:layout_constraintHorizontal_bias="1.0"
+ app:layout_constraintStart_toStartOf="parent" />
+
+ <SeekBar
+ android:id="@+id/noiseOpacity"
+ android:layout_width="0dp"
+ android:layout_height="wrap_content"
+ android:layout_marginStart="12dp"
+ android:layout_marginEnd="12dp"
+ android:layout_marginBottom="24dp"
+ android:max="100"
+ android:progress="5"
+ app:layout_constraintBottom_toBottomOf="parent"
+ app:layout_constraintEnd_toEndOf="parent"
+ app:layout_constraintHorizontal_bias="0.0"
+ app:layout_constraintStart_toStartOf="parent" />
+
+ <TextView
+ android:id="@+id/scrimOpacityTitle"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_marginStart="24dp"
+ android:layout_marginBottom="8dp"
+ android:text="Scrim Opacity"
+ android:textColor="@android:color/white"
+ app:layout_constraintBottom_toTopOf="@+id/scrimOpacity"
+ app:layout_constraintStart_toStartOf="parent" />
+
+ <TextView
+ android:id="@+id/materialOpacityTitle"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_marginStart="24dp"
+ android:layout_marginBottom="8dp"
+ android:text="Material Opacity"
+ android:textColor="@android:color/white"
+ app:layout_constraintBottom_toTopOf="@+id/materialOpacity"
+ app:layout_constraintStart_toStartOf="parent" />
+
+ <TextView
+ android:id="@+id/blurRadiusTitle"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_marginStart="24dp"
+ android:layout_marginBottom="8dp"
+ android:text="Blur Radius"
+ android:textColor="@android:color/white"
+ app:layout_constraintBottom_toTopOf="@+id/blurRadius"
+ app:layout_constraintStart_toStartOf="parent" />
+
+ <TextView
+ android:id="@+id/noiseOpacityTitle"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_marginStart="24dp"
+ android:layout_marginBottom="8dp"
+ android:textColor="@android:color/white"
+ android:text="Noise Opacity"
+ app:layout_constraintBottom_toTopOf="@+id/noiseOpacity"
+ app:layout_constraintStart_toStartOf="parent" />
+
+ <ImageView
+ android:id="@+id/background1"
+ android:layout_width="64dp"
+ android:layout_height="64dp"
+ android:layout_marginStart="24dp"
+ android:layout_marginBottom="16dp"
+ android:foreground="?android:attr/selectableItemBackgroundBorderless"
+ android:clickable="true"
+ android:onClick="onBackgroundClick"
+ android:scaleType="centerCrop"
+ app:layout_constraintBottom_toTopOf="@+id/lightMaterialSwitch"
+ app:layout_constraintStart_toStartOf="parent"
+ android:src="@drawable/background1" />
+
+ <ImageView
+ android:id="@+id/background2"
+ android:layout_width="64dp"
+ android:layout_height="64dp"
+ android:layout_marginStart="8dp"
+ android:foreground="?android:attr/selectableItemBackgroundBorderless"
+ android:clickable="true"
+ android:onClick="onBackgroundClick"
+ android:scaleType="centerCrop"
+ app:layout_constraintBottom_toBottomOf="@+id/background1"
+ app:layout_constraintStart_toEndOf="@+id/background1"
+ android:src="@drawable/background2" />
+
+ <ImageView
+ android:id="@+id/background3"
+ android:layout_width="64dp"
+ android:layout_height="64dp"
+ android:layout_marginStart="8dp"
+ android:scaleType="centerCrop"
+ android:foreground="?android:attr/selectableItemBackgroundBorderless"
+ android:clickable="true"
+ android:onClick="onBackgroundClick"
+ app:layout_constraintBottom_toBottomOf="@+id/background1"
+ app:layout_constraintStart_toEndOf="@+id/background2"
+ android:src="@drawable/background3" />
+
+ <Switch
+ android:id="@+id/lightMaterialSwitch"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_marginStart="24dp"
+ android:layout_marginBottom="8dp"
+ android:text="Light Material"
+ app:layout_constraintBottom_toTopOf="@+id/blurRadiusTitle"
+ app:layout_constraintStart_toStartOf="parent" />
+
+ <TextView
+ android:id="@+id/blurRadiusValue"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:text="TextView"
+ android:layout_marginLeft="8dp"
+ app:layout_constraintBottom_toBottomOf="@+id/blurRadiusTitle"
+ app:layout_constraintStart_toEndOf="@+id/blurRadiusTitle" />
+
+ <TextView
+ android:id="@+id/materialOpacityValue"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:text="TextView"
+ android:layout_marginLeft="8dp"
+ app:layout_constraintBottom_toBottomOf="@+id/materialOpacityTitle"
+ app:layout_constraintStart_toEndOf="@+id/materialOpacityTitle" />
+
+ <TextView
+ android:id="@+id/noiseOpacityValue"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:text="TextView"
+ android:layout_marginLeft="8dp"
+ app:layout_constraintBottom_toBottomOf="@+id/noiseOpacityTitle"
+ app:layout_constraintStart_toEndOf="@+id/noiseOpacityTitle" />
+
+
+ <TextView
+ android:id="@+id/scrimOpacityValue"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:text="TextView"
+ android:layout_marginLeft="8dp"
+ app:layout_constraintBottom_toBottomOf="@+id/scrimOpacityTitle"
+ app:layout_constraintStart_toEndOf="@+id/scrimOpacityTitle" />
+
+ </androidx.constraintlayout.widget.ConstraintLayout>
+
+
+</androidx.constraintlayout.widget.ConstraintLayout> \ No newline at end of file
diff --git a/tests/SilkFX/src/com/android/test/silkfx/Main.kt b/tests/SilkFX/src/com/android/test/silkfx/Main.kt
index 76e62a6c8cff..9ed8d2f5edf7 100644
--- a/tests/SilkFX/src/com/android/test/silkfx/Main.kt
+++ b/tests/SilkFX/src/com/android/test/silkfx/Main.kt
@@ -29,6 +29,7 @@ import com.android.test.silkfx.app.CommonDemoActivity
import com.android.test.silkfx.app.EXTRA_LAYOUT
import com.android.test.silkfx.app.EXTRA_TITLE
import com.android.test.silkfx.hdr.GlowActivity
+import com.android.test.silkfx.materials.GlassActivity
import kotlin.reflect.KClass
class Demo(val name: String, val makeIntent: (Context) -> Intent) {
@@ -48,6 +49,9 @@ private val AllDemos = listOf(
DemoGroup("HDR", listOf(
Demo("Glow", GlowActivity::class),
Demo("Blingy Notifications", R.layout.bling_notifications)
+ )),
+ DemoGroup("Materials", listOf(
+ Demo("Glass", GlassActivity::class)
))
)
diff --git a/tests/SilkFX/src/com/android/test/silkfx/materials/GlassActivity.kt b/tests/SilkFX/src/com/android/test/silkfx/materials/GlassActivity.kt
new file mode 100644
index 000000000000..6f5ddacb2733
--- /dev/null
+++ b/tests/SilkFX/src/com/android/test/silkfx/materials/GlassActivity.kt
@@ -0,0 +1,126 @@
+/*
+ * 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.silkfx.materials
+
+import android.app.Activity
+import android.graphics.Bitmap
+import android.graphics.BitmapFactory
+import android.graphics.Color
+import android.os.Bundle
+import android.util.TypedValue
+import android.view.View
+import android.widget.ImageView
+import android.widget.SeekBar
+import android.widget.Switch
+import android.widget.TextView
+import com.android.test.silkfx.R
+
+class GlassActivity : Activity(), SeekBar.OnSeekBarChangeListener {
+
+ lateinit var backgroundButton1: ImageView
+ lateinit var backgroundButton2: ImageView
+ lateinit var backgroundButton3: ImageView
+ lateinit var backgroundView: ImageView
+ lateinit var materialView: GlassView
+ lateinit var lightMaterialSwitch: Switch
+ lateinit var noiseOpacitySeekBar: SeekBar
+ lateinit var materialOpacitySeekBar: SeekBar
+ lateinit var scrimOpacitySeekBar: SeekBar
+ lateinit var blurRadiusSeekBar: SeekBar
+ lateinit var noiseOpacityValue: TextView
+ lateinit var materialOpacityValue: TextView
+ lateinit var scrimOpacityValue: TextView
+ lateinit var blurRadiusValue: TextView
+
+ lateinit var background: Bitmap
+
+ override fun onCreate(savedInstanceState: Bundle?) {
+ super.onCreate(savedInstanceState)
+ setContentView(R.layout.activity_glass)
+ backgroundButton1 = requireViewById(R.id.background1)
+ backgroundButton2 = requireViewById(R.id.background2)
+ backgroundButton3 = requireViewById(R.id.background3)
+ backgroundView = requireViewById(R.id.background)
+ lightMaterialSwitch = requireViewById(R.id.lightMaterialSwitch)
+ materialView = requireViewById(R.id.materialView)
+ materialOpacitySeekBar = requireViewById(R.id.materialOpacity)
+ blurRadiusSeekBar = requireViewById(R.id.blurRadius)
+ noiseOpacitySeekBar = requireViewById(R.id.noiseOpacity)
+ scrimOpacitySeekBar = requireViewById(R.id.scrimOpacity)
+ noiseOpacityValue = requireViewById(R.id.noiseOpacityValue)
+ materialOpacityValue = requireViewById(R.id.materialOpacityValue)
+ scrimOpacityValue = requireViewById(R.id.scrimOpacityValue)
+ blurRadiusValue = requireViewById(R.id.blurRadiusValue)
+
+ background = BitmapFactory.decodeResource(resources, R.drawable.background1)
+ backgroundView.setImageBitmap(background)
+ materialView.backgroundBitmap = background
+
+ blurRadiusSeekBar.setOnSeekBarChangeListener(this)
+ materialOpacitySeekBar.setOnSeekBarChangeListener(this)
+ noiseOpacitySeekBar.setOnSeekBarChangeListener(this)
+ scrimOpacitySeekBar.setOnSeekBarChangeListener(this)
+
+ arrayOf(blurRadiusSeekBar, materialOpacitySeekBar, noiseOpacitySeekBar,
+ scrimOpacitySeekBar).forEach {
+ it.setOnSeekBarChangeListener(this)
+ onProgressChanged(it, it.progress, fromUser = false)
+ }
+
+ lightMaterialSwitch.setOnCheckedChangeListener { _, isChecked ->
+ materialView.color = if (isChecked) Color.WHITE else Color.BLACK
+ }
+ }
+
+ override fun onProgressChanged(seekBar: SeekBar?, progress: Int, fromUser: Boolean) {
+ when (seekBar) {
+ blurRadiusSeekBar -> {
+ materialView.blurRadius = TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP,
+ progress.toFloat(), resources.displayMetrics)
+ blurRadiusValue.text = progress.toString()
+ }
+ materialOpacitySeekBar -> {
+ materialView.materialOpacity = progress / seekBar.max.toFloat()
+ materialOpacityValue.text = progress.toString()
+ }
+ noiseOpacitySeekBar -> {
+ materialView.noiseOpacity = progress / seekBar.max.toFloat()
+ noiseOpacityValue.text = progress.toString()
+ }
+ scrimOpacitySeekBar -> {
+ materialView.scrimOpacity = progress / seekBar.max.toFloat()
+ scrimOpacityValue.text = progress.toString()
+ }
+ else -> throw IllegalArgumentException("Unknown seek bar")
+ }
+ }
+
+ override fun onStartTrackingTouch(seekBar: SeekBar?) {}
+ override fun onStopTrackingTouch(seekBar: SeekBar?) {}
+
+ fun onBackgroundClick(view: View) {
+ val resource = when (view) {
+ backgroundButton1 -> R.drawable.background1
+ backgroundButton2 -> R.drawable.background2
+ backgroundButton3 -> R.drawable.background3
+ else -> throw IllegalArgumentException("Invalid button")
+ }
+
+ background = BitmapFactory.decodeResource(resources, resource)
+ backgroundView.setImageBitmap(background)
+ materialView.backgroundBitmap = background
+ }
+} \ No newline at end of file
diff --git a/tests/SilkFX/src/com/android/test/silkfx/materials/GlassView.kt b/tests/SilkFX/src/com/android/test/silkfx/materials/GlassView.kt
new file mode 100644
index 000000000000..e100959908c3
--- /dev/null
+++ b/tests/SilkFX/src/com/android/test/silkfx/materials/GlassView.kt
@@ -0,0 +1,117 @@
+/*
+ * 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.silkfx.materials
+
+import android.content.Context
+import android.graphics.Bitmap
+import android.graphics.BitmapFactory
+import android.graphics.BitmapShader
+import android.graphics.BlendMode
+import android.graphics.BlurShader
+import android.graphics.Canvas
+import android.graphics.Color
+import android.graphics.Outline
+import android.graphics.Paint
+import android.graphics.Rect
+import android.graphics.Shader
+import android.util.AttributeSet
+import android.view.View
+import android.view.ViewOutlineProvider
+import com.android.test.silkfx.R
+
+class GlassView(context: Context, attributeSet: AttributeSet) : View(context, attributeSet) {
+
+ var noise = BitmapFactory.decodeResource(resources, R.drawable.noise)
+ var materialPaint = Paint()
+ var scrimPaint = Paint()
+ var noisePaint = Paint()
+ var blurPaint = Paint()
+
+ val src = Rect()
+ val dst = Rect()
+
+ var backgroundBitmap: Bitmap = Bitmap.createBitmap(1, 1, Bitmap.Config.ARGB_8888)
+ set(value) {
+ field = value
+ invalidate()
+ }
+
+ var noiseOpacity = 0.0f
+ set(value) {
+ field = value
+ noisePaint.alpha = (value * 255).toInt()
+ invalidate()
+ }
+
+ var materialOpacity = 0.0f
+ set(value) {
+ field = value
+ materialPaint.alpha = (value * 255).toInt()
+ invalidate()
+ }
+
+ var scrimOpacity = 0.5f
+ set(value) {
+ field = value
+ scrimPaint.alpha = (value * 255).toInt()
+ invalidate()
+ }
+
+ var color = Color.BLACK
+ set(value) {
+ field = value
+ var alpha = materialPaint.alpha
+ materialPaint.color = color
+ materialPaint.alpha = alpha
+
+ alpha = scrimPaint.alpha
+ scrimPaint.color = color
+ scrimPaint.alpha = alpha
+ invalidate()
+ }
+
+ var blurRadius = 150f
+ set(value) {
+ field = value
+ blurPaint.shader = BlurShader(value, value, null)
+ invalidate()
+ }
+
+ init {
+ materialPaint.blendMode = BlendMode.SOFT_LIGHT
+ noisePaint.blendMode = BlendMode.SOFT_LIGHT
+ noisePaint.shader = BitmapShader(noise, Shader.TileMode.REPEAT, Shader.TileMode.REPEAT)
+ scrimPaint.alpha = (scrimOpacity * 255).toInt()
+ noisePaint.alpha = (noiseOpacity * 255).toInt()
+ materialPaint.alpha = (materialOpacity * 255).toInt()
+ blurPaint.shader = BlurShader(blurRadius, blurRadius, null)
+ outlineProvider = object : ViewOutlineProvider() {
+ override fun getOutline(view: View?, outline: Outline?) {
+ outline?.setRoundRect(Rect(0, 0, width, height), 100f)
+ }
+ }
+ clipToOutline = true
+ }
+
+ override fun onDraw(canvas: Canvas?) {
+ src.set(left, top, right, bottom)
+ dst.set(0, 0, width, height)
+ canvas?.drawBitmap(backgroundBitmap, src, dst, blurPaint)
+ canvas?.drawRect(dst, materialPaint)
+ canvas?.drawRect(dst, noisePaint)
+ canvas?.drawRect(dst, scrimPaint)
+ }
+} \ No newline at end of file
diff --git a/tests/StagedInstallTest/Android.bp b/tests/StagedInstallTest/Android.bp
index 76f8df02465b..f55d4d474bfb 100644
--- a/tests/StagedInstallTest/Android.bp
+++ b/tests/StagedInstallTest/Android.bp
@@ -26,7 +26,7 @@ android_test_helper_app {
java_test_host {
name: "StagedInstallInternalTest",
srcs: ["src/**/*.java"],
- libs: ["tradefed"],
+ libs: ["tradefed", "cts-shim-host-lib"],
static_libs: [
"testng",
"compatibility-tradefed",
@@ -35,6 +35,7 @@ java_test_host {
"cts-install-lib-host",
],
data: [
+ ":com.android.apex.apkrollback.test_v1",
":com.android.apex.cts.shim.v2_prebuilt",
":TestAppAv1",
],
diff --git a/tests/StagedInstallTest/app/src/com/android/tests/stagedinstallinternal/StagedInstallInternalTest.java b/tests/StagedInstallTest/app/src/com/android/tests/stagedinstallinternal/StagedInstallInternalTest.java
index 781723985ec5..e5411dee7805 100644
--- a/tests/StagedInstallTest/app/src/com/android/tests/stagedinstallinternal/StagedInstallInternalTest.java
+++ b/tests/StagedInstallTest/app/src/com/android/tests/stagedinstallinternal/StagedInstallInternalTest.java
@@ -47,11 +47,7 @@ import java.util.function.Consumer;
@RunWith(JUnit4.class)
public class StagedInstallInternalTest {
-
- private static final String TAG = StagedInstallInternalTest.class.getSimpleName();
private static final String APK_IN_APEX_TESTAPEX_NAME = "com.android.apex.apkrollback.test";
- private static final TestApp TEST_APEX_WITH_APK_V1 = new TestApp("TestApexWithApkV1",
- APK_IN_APEX_TESTAPEX_NAME, 1, /*isApex*/true, APK_IN_APEX_TESTAPEX_NAME + "_v1.apex");
private static final TestApp TEST_APEX_WITH_APK_V2 = new TestApp("TestApexWithApkV2",
APK_IN_APEX_TESTAPEX_NAME, 2, /*isApex*/true, APK_IN_APEX_TESTAPEX_NAME + "_v2.apex");
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 d7b07967f979..702f8719ff24 100644
--- a/tests/StagedInstallTest/src/com/android/tests/stagedinstallinternal/host/StagedInstallInternalTest.java
+++ b/tests/StagedInstallTest/src/com/android/tests/stagedinstallinternal/host/StagedInstallInternalTest.java
@@ -16,6 +16,8 @@
package com.android.tests.stagedinstallinternal.host;
+import static com.android.cts.shim.lib.ShimPackage.SHIM_APEX_PACKAGE_NAME;
+
import static com.google.common.truth.Truth.assertThat;
import static org.junit.Assert.assertTrue;
@@ -82,7 +84,8 @@ public class StagedInstallInternalTest extends BaseHostJUnit4Test {
Log.e(TAG, e);
}
deleteFiles("/system/apex/" + APK_IN_APEX_TESTAPEX_NAME + "*.apex",
- "/data/apex/active/" + APK_IN_APEX_TESTAPEX_NAME + "*.apex");
+ "/data/apex/active/" + APK_IN_APEX_TESTAPEX_NAME + "*.apex",
+ "/data/apex/active/" + SHIM_APEX_PACKAGE_NAME + "*.apex");
}
@Before
@@ -151,43 +154,78 @@ public class StagedInstallInternalTest extends BaseHostJUnit4Test {
runPhase("testSystemServerRestartDoesNotAffectStagedSessions_Verify");
}
+ // Test waiting time for staged session to be ready using adb staged install can be altered
@Test
- public void testAdbStagedInstallWaitForReadyFlagWorks() throws Exception {
+ public void testAdbStagdReadyTimeoutFlagWorks() throws Exception {
assumeTrue("Device does not support updating APEX",
mHostUtils.isApexUpdateSupported());
- File apexFile = mTestUtils.getTestFile(SHIM_V2);
- String output = getDevice().executeAdbCommand("install", "--staged",
- "--wait-for-staged-ready", "60000", apexFile.getAbsolutePath());
+ final File apexFile = mTestUtils.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");
- String sessionId = getDevice().executeShellCommand(
+ final String sessionId = getDevice().executeShellCommand(
"pm get-stagedsessions --only-ready --only-parent --only-sessionid").trim();
assertThat(sessionId).isNotEmpty();
}
+ // Test adb staged installation wait for session to be ready by default
@Test
- public void testAdbStagedInstallNoWaitFlagWorks() throws Exception {
+ public void testAdbStagedInstallWaitsTillReadyByDefault() throws Exception {
assumeTrue("Device does not support updating APEX",
mHostUtils.isApexUpdateSupported());
- File apexFile = mTestUtils.getTestFile(SHIM_V2);
- String output = getDevice().executeAdbCommand("install", "--staged",
- "--no-wait", apexFile.getAbsolutePath());
+ final File apexFile = mTestUtils.getTestFile(SHIM_V2);
+ final String output = getDevice().executeAdbCommand("install", "--staged",
+ apexFile.getAbsolutePath());
+ assertThat(output).contains("Reboot device to apply staged session");
+ final String sessionId = getDevice().executeShellCommand(
+ "pm get-stagedsessions --only-ready --only-parent --only-sessionid").trim();
+ assertThat(sessionId).isNotEmpty();
+ }
+
+ // Test we can skip waiting for staged session to be ready
+ @Test
+ public void testAdbStagedReadyWaitCanBeSkipped() throws Exception {
+ assumeTrue("Device does not support updating APEX",
+ mHostUtils.isApexUpdateSupported());
+
+ final File apexFile = mTestUtils.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");
assertThat(output).contains("Success");
- String sessionId = getDevice().executeShellCommand(
+ final String sessionId = getDevice().executeShellCommand(
"pm get-stagedsessions --only-ready --only-parent --only-sessionid").trim();
assertThat(sessionId).isEmpty();
}
+ // Test rollback-app command waits for staged sessions to be ready
+ @Test
+ public void testAdbRollbackAppWaitsForStagedReady() throws Exception {
+ assumeTrue("Device does not support updating APEX",
+ mHostUtils.isApexUpdateSupported());
+
+ final File apexFile = mTestUtils.getTestFile(SHIM_V2);
+ String output = getDevice().executeAdbCommand("install", "--staged",
+ "--enable-rollback", apexFile.getAbsolutePath());
+ assertThat(output).contains("Reboot device to apply staged session");
+ getDevice().reboot();
+ output = getDevice().executeShellCommand("pm rollback-app " + SHIM_APEX_PACKAGE_NAME);
+ assertThat(output).contains("Reboot device to apply staged session");
+ final String sessionId = getDevice().executeShellCommand(
+ "pm get-stagedsessions --only-ready --only-parent --only-sessionid").trim();
+ assertThat(sessionId).isNotEmpty();
+ }
+
@Test
public void testAdbInstallMultiPackageCommandWorks() throws Exception {
assumeTrue("Device does not support updating APEX",
mHostUtils.isApexUpdateSupported());
- File apexFile = mTestUtils.getTestFile(SHIM_V2);
- File apkFile = mTestUtils.getTestFile(APK_A);
- String output = getDevice().executeAdbCommand("install-multi-package",
+ final File apexFile = mTestUtils.getTestFile(SHIM_V2);
+ final File apkFile = mTestUtils.getTestFile(APK_A);
+ final String output = getDevice().executeAdbCommand("install-multi-package",
apexFile.getAbsolutePath(), apkFile.getAbsolutePath());
assertThat(output).contains("Created parent session");
assertThat(output).contains("Created child session");
@@ -227,16 +265,16 @@ public class StagedInstallInternalTest extends BaseHostJUnit4Test {
private void restartSystemServer() throws Exception {
// Restart the system server
- ProcessInfo oldPs = getDevice().getProcessByName("system_server");
+ final ProcessInfo oldPs = getDevice().getProcessByName("system_server");
getDevice().enableAdbRoot(); // Need root to restart system server
assertThat(getDevice().executeShellCommand("am restart")).contains("Restart the system");
getDevice().disableAdbRoot();
// Wait for new system server process to start
- long start = System.currentTimeMillis();
+ final long start = System.currentTimeMillis();
while (System.currentTimeMillis() < start + SYSTEM_SERVER_TIMEOUT_MS) {
- ProcessInfo newPs = getDevice().getProcessByName("system_server");
+ final ProcessInfo newPs = getDevice().getProcessByName("system_server");
if (newPs != null) {
if (newPs.getPid() != oldPs.getPid()) {
getDevice().waitForDeviceAvailable();
diff --git a/tests/net/java/com/android/server/ConnectivityServiceTest.java b/tests/net/java/com/android/server/ConnectivityServiceTest.java
index a3673df1c713..1f23bf38c2f2 100644
--- a/tests/net/java/com/android/server/ConnectivityServiceTest.java
+++ b/tests/net/java/com/android/server/ConnectivityServiceTest.java
@@ -218,7 +218,6 @@ import android.util.Log;
import android.util.SparseArray;
import androidx.test.InstrumentationRegistry;
-import androidx.test.filters.FlakyTest;
import androidx.test.filters.SmallTest;
import androidx.test.runner.AndroidJUnit4;
@@ -1199,7 +1198,7 @@ public class ConnectivityServiceTest {
MockitoAnnotations.initMocks(this);
when(mMetricsService.defaultNetworkMetrics()).thenReturn(mDefaultNetworkMetrics);
- when(mUserManager.getUsers(eq(true))).thenReturn(
+ when(mUserManager.getAliveUsers()).thenReturn(
Arrays.asList(new UserInfo[] {
new UserInfo(VPN_USER, "", 0),
}));
@@ -4028,7 +4027,6 @@ public class ConnectivityServiceTest {
}
@Test
- @FlakyTest(bugId = 140305589)
public void testPacketKeepalives() throws Exception {
InetAddress myIPv4 = InetAddress.getByName("192.0.2.129");
InetAddress notMyIPv4 = InetAddress.getByName("192.0.2.35");
diff --git a/tests/net/java/com/android/server/connectivity/PermissionMonitorTest.java b/tests/net/java/com/android/server/connectivity/PermissionMonitorTest.java
index 5a29c2c96ba7..de35f910d53a 100644
--- a/tests/net/java/com/android/server/connectivity/PermissionMonitorTest.java
+++ b/tests/net/java/com/android/server/connectivity/PermissionMonitorTest.java
@@ -123,7 +123,7 @@ public class PermissionMonitorTest {
MockitoAnnotations.initMocks(this);
when(mContext.getPackageManager()).thenReturn(mPackageManager);
when(mContext.getSystemService(eq(Context.USER_SERVICE))).thenReturn(mUserManager);
- when(mUserManager.getUsers(eq(true))).thenReturn(
+ when(mUserManager.getAliveUsers()).thenReturn(
Arrays.asList(new UserInfo[] {
new UserInfo(MOCK_USER1, "", 0),
new UserInfo(MOCK_USER2, "", 0),
diff --git a/tests/net/java/com/android/server/connectivity/VpnTest.java b/tests/net/java/com/android/server/connectivity/VpnTest.java
index e8c4ee9c628d..c76b4cd501e7 100644
--- a/tests/net/java/com/android/server/connectivity/VpnTest.java
+++ b/tests/net/java/com/android/server/connectivity/VpnTest.java
@@ -1238,15 +1238,14 @@ public class VpnTest {
* @see UserManagerService#getUsers(boolean)
*/
doAnswer(invocation -> {
- final boolean excludeDying = (boolean) invocation.getArguments()[0];
final ArrayList<UserInfo> result = new ArrayList<>(users.length);
for (UserInfo ui : users) {
- if (!excludeDying || (ui.isEnabled() && !ui.partial)) {
+ if (ui.isEnabled() && !ui.partial) {
result.add(ui);
}
}
return result;
- }).when(mUserManager).getUsers(anyBoolean());
+ }).when(mUserManager).getAliveUsers();
doAnswer(invocation -> {
final int id = (int) invocation.getArguments()[0];
diff --git a/tools/preload-check/Android.bp b/tools/preload-check/Android.bp
index 87b31d22af32..aaa6d76b39e3 100644
--- a/tools/preload-check/Android.bp
+++ b/tools/preload-check/Android.bp
@@ -15,7 +15,7 @@
java_test_host {
name: "PreloadCheck",
srcs: ["src/**/*.java"],
- java_resources: [":preloaded-classes-blacklist"],
+ java_resources: [":preloaded-classes-denylist"],
libs: ["tradefed"],
test_suites: ["general-tests"],
required: ["preload-check-device"],
diff --git a/tools/preload-check/src/com/android/preload/check/PreloadCheck.java b/tools/preload-check/src/com/android/preload/check/PreloadCheck.java
index 00fd414e3ee2..3d851531d7e7 100644
--- a/tools/preload-check/src/com/android/preload/check/PreloadCheck.java
+++ b/tools/preload-check/src/com/android/preload/check/PreloadCheck.java
@@ -69,13 +69,13 @@ public class PreloadCheck implements IDeviceTest {
}
/**
- * Test the classes mentioned in the embedded preloaded-classes blacklist.
+ * Test the classes mentioned in the embedded preloaded-classes denylist.
*/
@Test
- public void testBlackList() throws Exception {
+ public void testDenyList() throws Exception {
StringBuilder sb = new StringBuilder();
try (BufferedReader br = new BufferedReader(new InputStreamReader(getClass()
- .getResourceAsStream("/preloaded-classes-blacklist")))) {
+ .getResourceAsStream("/preloaded-classes-denylist")))) {
String s;
while ((s = br.readLine()) != null) {
s = s.trim();
diff --git a/tools/validatekeymaps/Main.cpp b/tools/validatekeymaps/Main.cpp
index 5ac9dfd2a557..0aca13e95a52 100644
--- a/tools/validatekeymaps/Main.cpp
+++ b/tools/validatekeymaps/Main.cpp
@@ -96,21 +96,19 @@ static bool validateFile(const char* filename) {
return false;
case FILETYPE_KEYLAYOUT: {
- sp<KeyLayoutMap> map;
- status_t status = KeyLayoutMap::load(filename, &map);
- if (status) {
- error("Error %d parsing key layout file.\n\n", status);
+ base::Result<std::shared_ptr<KeyLayoutMap>> ret = KeyLayoutMap::load(filename);
+ if (!ret) {
+ error("Error %s parsing key layout file.\n\n", ret.error().message().c_str());
return false;
}
break;
}
case FILETYPE_KEYCHARACTERMAP: {
- sp<KeyCharacterMap> map;
- status_t status = KeyCharacterMap::load(filename,
- KeyCharacterMap::FORMAT_ANY, &map);
- if (status) {
- error("Error %d parsing key character map file.\n\n", status);
+ base::Result<std::shared_ptr<KeyCharacterMap>> ret = KeyCharacterMap::load(filename,
+ KeyCharacterMap::FORMAT_ANY);
+ if (!ret) {
+ error("Error %s parsing key character map file.\n\n", ret.error().message().c_str());
return false;
}
break;
diff --git a/wifi/api/current.txt b/wifi/api/current.txt
index 53c3b33d9845..b104decab73c 100644
--- a/wifi/api/current.txt
+++ b/wifi/api/current.txt
@@ -487,6 +487,7 @@ package android.net.wifi {
method @Nullable public String getPassphrase();
method @Nullable public android.net.wifi.hotspot2.PasspointConfiguration getPasspointConfig();
method @IntRange(from=0) public int getPriority();
+ method public int getPriorityGroup();
method @Nullable public String getSsid();
method public boolean isAppInteractionRequired();
method public boolean isCredentialSharedWithUser();
@@ -506,6 +507,7 @@ package android.net.wifi {
method @NonNull public android.net.wifi.WifiNetworkSuggestion.Builder setBssid(@NonNull android.net.MacAddress);
method @NonNull public android.net.wifi.WifiNetworkSuggestion.Builder setCredentialSharedWithUser(boolean);
method @NonNull public android.net.wifi.WifiNetworkSuggestion.Builder setIsAppInteractionRequired(boolean);
+ method @NonNull public android.net.wifi.WifiNetworkSuggestion.Builder setIsEnhancedMacRandomizationEnabled(boolean);
method @NonNull public android.net.wifi.WifiNetworkSuggestion.Builder setIsEnhancedOpen(boolean);
method @NonNull public android.net.wifi.WifiNetworkSuggestion.Builder setIsHiddenSsid(boolean);
method @NonNull public android.net.wifi.WifiNetworkSuggestion.Builder setIsInitialAutojoinEnabled(boolean);
@@ -513,6 +515,7 @@ package android.net.wifi {
method @NonNull public android.net.wifi.WifiNetworkSuggestion.Builder setIsUserInteractionRequired(boolean);
method @NonNull public android.net.wifi.WifiNetworkSuggestion.Builder setPasspointConfig(@NonNull android.net.wifi.hotspot2.PasspointConfiguration);
method @NonNull public android.net.wifi.WifiNetworkSuggestion.Builder setPriority(@IntRange(from=0) int);
+ method @NonNull public android.net.wifi.WifiNetworkSuggestion.Builder setPriorityGroup(int);
method @NonNull public android.net.wifi.WifiNetworkSuggestion.Builder setSsid(@NonNull String);
method @NonNull public android.net.wifi.WifiNetworkSuggestion.Builder setUntrusted(boolean);
method @NonNull public android.net.wifi.WifiNetworkSuggestion.Builder setWapiEnterpriseConfig(@NonNull android.net.wifi.WifiEnterpriseConfig);
diff --git a/wifi/java/android/net/wifi/ScanResult.java b/wifi/java/android/net/wifi/ScanResult.java
index aa3a13925894..9302f78b7fca 100644
--- a/wifi/java/android/net/wifi/ScanResult.java
+++ b/wifi/java/android/net/wifi/ScanResult.java
@@ -81,6 +81,12 @@ public final class ScanResult implements Parcelable {
public String capabilities;
/**
+ * The interface name on which the scan result was received.
+ * @hide
+ */
+ public String ifaceName;
+
+ /**
* @hide
* No security protocol.
*/
@@ -939,6 +945,7 @@ public final class ScanResult implements Parcelable {
flags = source.flags;
radioChainInfos = source.radioChainInfos;
this.mWifiStandard = source.mWifiStandard;
+ this.ifaceName = source.ifaceName;
}
}
@@ -977,6 +984,7 @@ public final class ScanResult implements Parcelable {
sb.append(", 80211mcResponder: ");
sb.append(((flags & FLAG_80211mc_RESPONDER) != 0) ? "is supported" : "is not supported");
sb.append(", Radio Chain Infos: ").append(Arrays.toString(radioChainInfos));
+ sb.append(", interface name: ").append(ifaceName);
return sb.toString();
}
@@ -1056,6 +1064,7 @@ public final class ScanResult implements Parcelable {
} else {
dest.writeInt(0);
}
+ dest.writeString((ifaceName != null) ? ifaceName.toString() : "");
}
/** Implement the Parcelable interface */
@@ -1134,6 +1143,7 @@ public final class ScanResult implements Parcelable {
sr.radioChainInfos[i].level = in.readInt();
}
}
+ sr.ifaceName = in.readString();
return sr;
}
diff --git a/wifi/java/android/net/wifi/WifiNetworkSuggestion.java b/wifi/java/android/net/wifi/WifiNetworkSuggestion.java
index 68eb1bbd8a79..e4e900ffe12a 100644
--- a/wifi/java/android/net/wifi/WifiNetworkSuggestion.java
+++ b/wifi/java/android/net/wifi/WifiNetworkSuggestion.java
@@ -102,10 +102,15 @@ public final class WifiNetworkSuggestion implements Parcelable {
*/
private int mMeteredOverride;
/**
- * Priority of this network among other network suggestions provided by the app.
+ * Priority of this network among other network suggestions from same priority group
+ * provided by the app.
* The lower the number, the higher the priority (i.e value of 0 = highest priority).
*/
private int mPriority;
+ /**
+ * Priority group ID, while suggestion priority will only effect inside the priority group.
+ */
+ private int mPriorityGroup;
/**
* The carrier ID identifies the operator who provides this network configuration.
@@ -144,6 +149,11 @@ public final class WifiNetworkSuggestion implements Parcelable {
*/
private boolean mIsNetworkUntrusted;
+ /**
+ * Whether this network will use enhanced MAC randomization.
+ */
+ private boolean mIsEnhancedMacRandomizationEnabled;
+
public Builder() {
mSsid = null;
mBssid = null;
@@ -165,6 +175,8 @@ public final class WifiNetworkSuggestion implements Parcelable {
mWapiPskPassphrase = null;
mWapiEnterpriseConfig = null;
mIsNetworkUntrusted = false;
+ mPriorityGroup = 0;
+ mIsEnhancedMacRandomizationEnabled = true;
}
/**
@@ -329,6 +341,18 @@ public final class WifiNetworkSuggestion implements Parcelable {
}
/**
+ * Set the priority group ID, {@link #setPriority(int)} will only impact the network
+ * suggestions from the same priority group within the same app.
+ *
+ * @param priorityGroup priority group id, if not set default is 0.
+ * @return Instance of {@link Builder} to enable chaining of the builder method.
+ */
+ public @NonNull Builder setPriorityGroup(int priorityGroup) {
+ mPriorityGroup = priorityGroup;
+ return this;
+ }
+
+ /**
* Set the ASCII WAPI passphrase for this network. Needed for authenticating to
* WAPI-PSK networks.
*
@@ -376,6 +400,29 @@ public final class WifiNetworkSuggestion implements Parcelable {
}
/**
+ * Specifies the MAC randomization method.
+ * <p>
+ * Suggested networks will never use the device (factory) MAC address to associate to the
+ * network - instead they use a locally generated random MAC address. This method controls
+ * the strategy for generating the random MAC address:
+ * <li> Persisted MAC randomization (false): generates the MAC address from a secret seed
+ * and information from the Wi-Fi configuration (SSID or Passpoint profile). That means that
+ * the same generated MAC address will be used for each subsequent association. </li>
+ * <li> Enhanced MAC randomization (true - the default): periodically generates a new MAC
+ * address new connections. Under this option, the randomized MAC address should change
+ * if the suggestion is removed and then added back. </li>
+ *
+ * @param enabled {@code true} to periodically change the randomized MAC address.
+ * {@code false} to use the same randomized MAC for all connections to this
+ * network.
+ * @return Instance of {@link Builder} to enable chaining of the builder method.
+ */
+ public @NonNull Builder setIsEnhancedMacRandomizationEnabled(boolean enabled) {
+ mIsEnhancedMacRandomizationEnabled = enabled;
+ return this;
+ }
+
+ /**
* Specifies whether the app needs to log in to a captive portal to obtain Internet access.
* <p>
* This will dictate if the directed broadcast
@@ -411,8 +458,9 @@ public final class WifiNetworkSuggestion implements Parcelable {
/**
* Specify the priority of this network among other network suggestions provided by the same
- * app (priorities have no impact on suggestions by different apps). The higher the number,
- * the higher the priority (i.e value of 0 = lowest priority).
+ * app (priorities have no impact on suggestions by different apps) and within the same
+ * priority group, see {@link #setPriorityGroup(int)}.
+ * The higher the number, the higher the priority (i.e value of 0 = lowest priority).
* <p>
* <li>If not set, defaults a lower priority than any assigned priority.</li>
*
@@ -558,6 +606,9 @@ public final class WifiNetworkSuggestion implements Parcelable {
wifiConfiguration.meteredOverride = mMeteredOverride;
wifiConfiguration.carrierId = mCarrierId;
wifiConfiguration.trusted = !mIsNetworkUntrusted;
+ wifiConfiguration.macRandomizationSetting = mIsEnhancedMacRandomizationEnabled
+ ? WifiConfiguration.RANDOMIZATION_ENHANCED
+ : WifiConfiguration.RANDOMIZATION_PERSISTENT;
return wifiConfiguration;
}
@@ -588,6 +639,9 @@ public final class WifiNetworkSuggestion implements Parcelable {
wifiConfiguration.trusted = !mIsNetworkUntrusted;
mPasspointConfiguration.setCarrierId(mCarrierId);
mPasspointConfiguration.setMeteredOverride(wifiConfiguration.meteredOverride);
+ wifiConfiguration.macRandomizationSetting = mIsEnhancedMacRandomizationEnabled
+ ? WifiConfiguration.RANDOMIZATION_ENHANCED
+ : WifiConfiguration.RANDOMIZATION_PERSISTENT;
return wifiConfiguration;
}
@@ -696,7 +750,8 @@ public final class WifiNetworkSuggestion implements Parcelable {
mIsAppInteractionRequired,
mIsUserInteractionRequired,
mIsSharedWithUser,
- mIsInitialAutojoinEnabled);
+ mIsInitialAutojoinEnabled,
+ mPriorityGroup);
}
}
@@ -739,6 +794,12 @@ public final class WifiNetworkSuggestion implements Parcelable {
*/
public final boolean isInitialAutoJoinEnabled;
+ /**
+ * Priority group ID.
+ * @hide
+ */
+ public final int priorityGroup;
+
/** @hide */
public WifiNetworkSuggestion() {
this.wifiConfiguration = new WifiConfiguration();
@@ -747,6 +808,7 @@ public final class WifiNetworkSuggestion implements Parcelable {
this.isUserInteractionRequired = false;
this.isUserAllowedToManuallyConnect = true;
this.isInitialAutoJoinEnabled = true;
+ this.priorityGroup = 0;
}
/** @hide */
@@ -755,7 +817,7 @@ public final class WifiNetworkSuggestion implements Parcelable {
boolean isAppInteractionRequired,
boolean isUserInteractionRequired,
boolean isUserAllowedToManuallyConnect,
- boolean isInitialAutoJoinEnabled) {
+ boolean isInitialAutoJoinEnabled, int priorityGroup) {
checkNotNull(networkConfiguration);
this.wifiConfiguration = networkConfiguration;
this.passpointConfiguration = passpointConfiguration;
@@ -764,6 +826,7 @@ public final class WifiNetworkSuggestion implements Parcelable {
this.isUserInteractionRequired = isUserInteractionRequired;
this.isUserAllowedToManuallyConnect = isUserAllowedToManuallyConnect;
this.isInitialAutoJoinEnabled = isInitialAutoJoinEnabled;
+ this.priorityGroup = priorityGroup;
}
public static final @NonNull Creator<WifiNetworkSuggestion> CREATOR =
@@ -776,7 +839,8 @@ public final class WifiNetworkSuggestion implements Parcelable {
in.readBoolean(), // isAppInteractionRequired
in.readBoolean(), // isUserInteractionRequired
in.readBoolean(), // isSharedCredentialWithUser
- in.readBoolean() // isAutojoinEnabled
+ in.readBoolean(), // isAutojoinEnabled
+ in.readInt() // priorityGroup
);
}
@@ -799,6 +863,7 @@ public final class WifiNetworkSuggestion implements Parcelable {
dest.writeBoolean(isUserInteractionRequired);
dest.writeBoolean(isUserAllowedToManuallyConnect);
dest.writeBoolean(isInitialAutoJoinEnabled);
+ dest.writeInt(priorityGroup);
}
@Override
@@ -842,6 +907,7 @@ public final class WifiNetworkSuggestion implements Parcelable {
.append(", isCredentialSharedWithUser=").append(isUserAllowedToManuallyConnect)
.append(", isInitialAutoJoinEnabled=").append(isInitialAutoJoinEnabled)
.append(", isUnTrusted=").append(!wifiConfiguration.trusted)
+ .append(", priorityGroup=").append(priorityGroup)
.append(" ]");
return sb.toString();
}
@@ -962,4 +1028,11 @@ public final class WifiNetworkSuggestion implements Parcelable {
}
return WifiInfo.removeDoubleQuotes(wifiConfiguration.preSharedKey);
}
+
+ /**
+ * @see Builder#setPriorityGroup(int)
+ */
+ public int getPriorityGroup() {
+ return priorityGroup;
+ }
}
diff --git a/wifi/tests/src/android/net/wifi/ScanResultTest.java b/wifi/tests/src/android/net/wifi/ScanResultTest.java
index 5516f433070f..4a3586826de9 100644
--- a/wifi/tests/src/android/net/wifi/ScanResultTest.java
+++ b/wifi/tests/src/android/net/wifi/ScanResultTest.java
@@ -44,6 +44,7 @@ public class ScanResultTest {
public static final long TEST_TSF = 04660l;
public static final @WifiAnnotations.WifiStandard int TEST_WIFI_STANDARD =
ScanResult.WIFI_STANDARD_11AC;
+ public static final String TEST_IFACE_NAME = "test_ifname";
/**
* Frequency to channel map. This include some frequencies used outside the US.
@@ -219,7 +220,7 @@ public class ScanResultTest {
+ "passpoint: no, ChannelBandwidth: 0, centerFreq0: 0, centerFreq1: 0, "
+ "standard: 11ac, "
+ "80211mcResponder: is not supported, "
- + "Radio Chain Infos: null", scanResult.toString());
+ + "Radio Chain Infos: null, interface name: test_ifname", scanResult.toString());
}
/**
@@ -242,7 +243,8 @@ public class ScanResultTest {
+ "standard: 11ac, "
+ "80211mcResponder: is not supported, "
+ "Radio Chain Infos: [RadioChainInfo: id=0, level=-45, "
- + "RadioChainInfo: id=1, level=-54]", scanResult.toString());
+ + "RadioChainInfo: id=1, level=-54], interface name: test_ifname",
+ scanResult.toString());
}
/**
@@ -283,6 +285,8 @@ public class ScanResultTest {
result.frequency = TEST_FREQUENCY;
result.timestamp = TEST_TSF;
result.setWifiStandard(TEST_WIFI_STANDARD);
+ result.ifaceName = TEST_IFACE_NAME;
+
return result;
}
diff --git a/wifi/tests/src/android/net/wifi/WifiNetworkSuggestionTest.java b/wifi/tests/src/android/net/wifi/WifiNetworkSuggestionTest.java
index f0839e9b3122..7d5a45216fc4 100644
--- a/wifi/tests/src/android/net/wifi/WifiNetworkSuggestionTest.java
+++ b/wifi/tests/src/android/net/wifi/WifiNetworkSuggestionTest.java
@@ -16,7 +16,12 @@
package android.net.wifi;
-import static org.junit.Assert.*;
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertNotEquals;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertNull;
+import static org.junit.Assert.assertTrue;
import android.net.MacAddress;
import android.net.wifi.hotspot2.PasspointConfiguration;
@@ -39,6 +44,8 @@ public class WifiNetworkSuggestionTest {
private static final String TEST_FQDN = "fqdn";
private static final String TEST_WAPI_CERT_SUITE = "suite";
private static final String TEST_DOMAIN_SUFFIX_MATCH = "domainSuffixMatch";
+ private static final int DEFAULT_PRIORITY_GROUP = 0;
+ private static final int TEST_PRIORITY_GROUP = 1;
/**
* Validate correctness of WifiNetworkSuggestion object created by
@@ -603,6 +610,33 @@ public class WifiNetworkSuggestionTest {
}
/**
+ * Verify that the macRandomizationSetting defaults to RANDOMIZATION_ENHANCED and could be set
+ * to RANDOMIZATION_PERSISTENT.
+ */
+ @Test
+ public void testWifiNetworkSuggestionBuilderSetMacRandomization() {
+ WifiNetworkSuggestion suggestion = new WifiNetworkSuggestion.Builder()
+ .setSsid(TEST_SSID)
+ .build();
+ assertEquals(WifiConfiguration.RANDOMIZATION_ENHANCED,
+ suggestion.wifiConfiguration.macRandomizationSetting);
+
+ suggestion = new WifiNetworkSuggestion.Builder()
+ .setSsid(TEST_SSID)
+ .setIsEnhancedMacRandomizationEnabled(false)
+ .build();
+ assertEquals(WifiConfiguration.RANDOMIZATION_PERSISTENT,
+ suggestion.wifiConfiguration.macRandomizationSetting);
+
+ suggestion = new WifiNetworkSuggestion.Builder()
+ .setSsid(TEST_SSID)
+ .setIsEnhancedMacRandomizationEnabled(true)
+ .build();
+ assertEquals(WifiConfiguration.RANDOMIZATION_ENHANCED,
+ suggestion.wifiConfiguration.macRandomizationSetting);
+ }
+
+ /**
* Check that parcel marshalling/unmarshalling works
*/
@Test
@@ -612,7 +646,7 @@ public class WifiNetworkSuggestionTest {
configuration.BSSID = TEST_BSSID;
configuration.allowedKeyManagement.set(WifiConfiguration.KeyMgmt.NONE);
WifiNetworkSuggestion suggestion = new WifiNetworkSuggestion(
- configuration, null, false, true, true, true);
+ configuration, null, false, true, true, true, TEST_PRIORITY_GROUP);
Parcel parcelW = Parcel.obtain();
suggestion.writeToParcel(parcelW, 0);
@@ -683,14 +717,16 @@ public class WifiNetworkSuggestionTest {
configuration.BSSID = TEST_BSSID;
configuration.allowedKeyManagement.set(WifiConfiguration.KeyMgmt.WPA_PSK);
WifiNetworkSuggestion suggestion =
- new WifiNetworkSuggestion(configuration, null, true, false, true, true);
+ new WifiNetworkSuggestion(configuration, null, true, false, true, true,
+ TEST_PRIORITY_GROUP);
WifiConfiguration configuration1 = new WifiConfiguration();
configuration1.SSID = TEST_SSID;
configuration1.BSSID = TEST_BSSID;
configuration1.allowedKeyManagement.set(WifiConfiguration.KeyMgmt.WPA_PSK);
WifiNetworkSuggestion suggestion1 =
- new WifiNetworkSuggestion(configuration1, null, false, true, true, true);
+ new WifiNetworkSuggestion(configuration1, null, false, true, true, true,
+ DEFAULT_PRIORITY_GROUP);
assertEquals(suggestion, suggestion1);
assertEquals(suggestion.hashCode(), suggestion1.hashCode());
@@ -706,13 +742,15 @@ public class WifiNetworkSuggestionTest {
configuration.SSID = TEST_SSID;
configuration.allowedKeyManagement.set(WifiConfiguration.KeyMgmt.NONE);
WifiNetworkSuggestion suggestion =
- new WifiNetworkSuggestion(configuration, null, false, false, true, true);
+ new WifiNetworkSuggestion(configuration, null, false, false, true, true,
+ DEFAULT_PRIORITY_GROUP);
WifiConfiguration configuration1 = new WifiConfiguration();
configuration1.SSID = TEST_SSID_1;
configuration.allowedKeyManagement.set(WifiConfiguration.KeyMgmt.NONE);
WifiNetworkSuggestion suggestion1 =
- new WifiNetworkSuggestion(configuration1, null, false, false, true, true);
+ new WifiNetworkSuggestion(configuration1, null, false, false, true, true,
+ DEFAULT_PRIORITY_GROUP);
assertNotEquals(suggestion, suggestion1);
}
@@ -728,13 +766,15 @@ public class WifiNetworkSuggestionTest {
configuration.BSSID = TEST_BSSID;
configuration.allowedKeyManagement.set(WifiConfiguration.KeyMgmt.NONE);
WifiNetworkSuggestion suggestion =
- new WifiNetworkSuggestion(configuration, null, false, false, true, true);
+ new WifiNetworkSuggestion(configuration, null, false, false, true, true,
+ DEFAULT_PRIORITY_GROUP);
WifiConfiguration configuration1 = new WifiConfiguration();
configuration1.SSID = TEST_SSID;
configuration1.allowedKeyManagement.set(WifiConfiguration.KeyMgmt.NONE);
WifiNetworkSuggestion suggestion1 =
- new WifiNetworkSuggestion(configuration1, null, false, false, true, true);
+ new WifiNetworkSuggestion(configuration1, null, false, false, true, true,
+ DEFAULT_PRIORITY_GROUP);
assertNotEquals(suggestion, suggestion1);
}
@@ -749,13 +789,15 @@ public class WifiNetworkSuggestionTest {
configuration.SSID = TEST_SSID;
configuration.allowedKeyManagement.set(WifiConfiguration.KeyMgmt.NONE);
WifiNetworkSuggestion suggestion =
- new WifiNetworkSuggestion(configuration, null, false, false, true, true);
+ new WifiNetworkSuggestion(configuration, null, false, false, true, true,
+ DEFAULT_PRIORITY_GROUP);
WifiConfiguration configuration1 = new WifiConfiguration();
configuration1.SSID = TEST_SSID;
configuration1.allowedKeyManagement.set(WifiConfiguration.KeyMgmt.WPA_PSK);
WifiNetworkSuggestion suggestion1 =
- new WifiNetworkSuggestion(configuration1, null, false, false, true, true);
+ new WifiNetworkSuggestion(configuration1, null, false, false, true, true,
+ DEFAULT_PRIORITY_GROUP);
assertNotEquals(suggestion, suggestion1);
}