summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--apct-tests/perftests/core/src/android/app/ResourcesManagerPerfTest.java19
-rw-r--r--api/current.txt21
-rwxr-xr-xapi/system-current.txt1
-rw-r--r--api/test-current.txt2
-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/MetricsManager.cpp13
-rw-r--r--cmds/statsd/src/metrics/MetricsManager.h5
-rw-r--r--cmds/statsd/src/metrics/ValueMetricProducer.cpp42
-rw-r--r--cmds/statsd/src/metrics/ValueMetricProducer.h34
-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.cpp55
-rw-r--r--cmds/statsd/src/metrics/parsing_utils/metrics_manager_util.h14
-rw-r--r--cmds/statsd/tests/condition/SimpleConditionTracker_test.cpp18
-rw-r--r--cmds/statsd/tests/metrics/ValueMetricProducer_test.cpp678
-rw-r--r--cmds/statsd/tests/metrics/parsing_utils/config_update_utils_test.cpp486
-rw-r--r--cmds/statsd/tests/metrics/parsing_utils/metrics_manager_util_test.cpp132
-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/AppOpsManager.java25
-rw-r--r--core/java/android/app/ApplicationPackageManager.java44
-rw-r--r--core/java/android/app/ResourcesManager.java36
-rw-r--r--core/java/android/app/admin/DevicePolicyManager.java15
-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/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/PackageManager.java118
-rw-r--r--core/java/android/os/UserManager.java44
-rw-r--r--core/java/android/preference/OWNERS1
-rw-r--r--core/java/android/provider/DocumentsProvider.java17
-rw-r--r--core/java/android/provider/Settings.java11
-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/NotificationHeaderView.java4
-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/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/jni/android_hardware_camera2_CameraMetadata.cpp21
-rw-r--r--core/jni/android_util_Process.cpp2
-rw-r--r--core/proto/android/app/settings_enums.proto10
-rw-r--r--core/res/AndroidManifest.xml3
-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/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.json481
-rw-r--r--keystore/TEST_MAPPING74
-rw-r--r--libs/WindowManager/Shell/Android.bp78
-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/src/com/android/wm/shell/ShellTaskOrganizer.java22
-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/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--non-updatable-api/current.txt21
-rw-r--r--non-updatable-api/system-current.txt1
-rw-r--r--packages/CarSystemUI/src/com/android/systemui/CarGlobalRootComponent.java6
-rw-r--r--packages/CarSystemUI/src/com/android/systemui/CarSysUIComponent.java4
-rw-r--r--packages/CarSystemUI/src/com/android/systemui/car/notification/NotificationPanelViewController.java9
-rw-r--r--packages/CarSystemUI/src/com/android/systemui/car/window/OverlayPanelViewController.java35
-rw-r--r--packages/CarSystemUI/src/com/android/systemui/wmshell/CarWMShellModule.java10
-rw-r--r--packages/ExternalStorageProvider/src/com/android/externalstorage/ExternalStorageProvider.java7
-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/src/com/android/settingslib/Utils.java32
-rw-r--r--packages/SettingsLib/src/com/android/settingslib/wifi/WifiEntryPreference.java20
-rw-r--r--packages/SettingsLib/tests/robotests/src/com/android/settingslib/wifi/WifiEntryPreferenceTest.java98
-rw-r--r--packages/SystemUI/Android.bp5
-rw-r--r--packages/SystemUI/AndroidManifest.xml14
-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/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/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/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.java (renamed from packages/SystemUI/src/com/android/systemui/pip/phone/dagger/PipMenuActivityClass.java)12
-rw-r--r--packages/SystemUI/src/com/android/systemui/Prefs.java4
-rw-r--r--packages/SystemUI/src/com/android/systemui/SwipeHelper.java9
-rw-r--r--packages/SystemUI/src/com/android/systemui/SystemUIFactory.java17
-rw-r--r--packages/SystemUI/src/com/android/systemui/appops/dagger/AppOpsModule.java32
-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.java15
-rw-r--r--packages/SystemUI/src/com/android/systemui/dagger/FrameworkServicesModule.java (renamed from packages/SystemUI/src/com/android/systemui/dagger/SystemServicesModule.java)102
-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.java6
-rw-r--r--packages/SystemUI/src/com/android/systemui/dagger/SystemUIModule.java21
-rw-r--r--packages/SystemUI/src/com/android/systemui/dagger/WMComponent.java17
-rw-r--r--packages/SystemUI/src/com/android/systemui/doze/DozeTriggers.java6
-rw-r--r--packages/SystemUI/src/com/android/systemui/globalactions/GlobalActionsDialog.java10
-rw-r--r--packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewMediator.java13
-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/navigationbar/NavigationBar.java2
-rw-r--r--packages/SystemUI/src/com/android/systemui/onehanded/OneHandedTutorialHandler.java4
-rw-r--r--packages/SystemUI/src/com/android/systemui/pip/PipTaskOrganizer.java53
-rw-r--r--packages/SystemUI/src/com/android/systemui/pip/phone/PipManager.java6
-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.java9
-rw-r--r--packages/SystemUI/src/com/android/systemui/pip/phone/PipTouchHandler.java9
-rw-r--r--packages/SystemUI/src/com/android/systemui/pip/tv/PipManager.java7
-rw-r--r--packages/SystemUI/src/com/android/systemui/pip/tv/PipMenuActivity.java2
-rw-r--r--packages/SystemUI/src/com/android/systemui/pip/tv/PipNotification.java8
-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/recents/OverviewProxyService.java8
-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/stackdivider/DividerView.java10
-rw-r--r--packages/SystemUI/src/com/android/systemui/stackdivider/SplitScreen.java5
-rw-r--r--packages/SystemUI/src/com/android/systemui/stackdivider/SplitScreenController.java25
-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/PulseExpansionHandler.kt3
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/dagger/StatusBarDependenciesModule.java32
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/NotificationEntry.java9
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/notification/dagger/NotificationsModule.java4
-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/stack/AmbientState.java19
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayout.java293
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayoutController.java221
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationSwipeHelper.java2
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardAffordanceHelper.java5
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelViewController.java38
-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.java23
-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.java3
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/policy/dagger/StatusBarPolicyModule.java112
-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/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/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/WMShell.java35
-rw-r--r--packages/SystemUI/src/com/android/systemui/wmshell/WMShellModule.java10
-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/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/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/notification/row/NotificationGutsManagerTest.java4
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayoutTest.java7
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollerControllerTest.java7
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/NotificationPanelViewTest.java20
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/NotificationShadeWindowViewTest.java6
-rw-r--r--services/accessibility/java/com/android/server/accessibility/gestures/EventDispatcher.java69
-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/WindowMagnificationGestureHandler.java6
-rw-r--r--services/accessibility/java/com/android/server/accessibility/magnification/WindowMagnificationManager.java50
-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/core/java/com/android/server/VibratorService.java128
-rw-r--r--services/core/java/com/android/server/am/ActivityManagerService.java8
-rw-r--r--services/core/java/com/android/server/audio/AudioDeviceBroker.java8
-rwxr-xr-xservices/core/java/com/android/server/audio/AudioService.java33
-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/hdmi/HdmiCecMessageBuilder.java2
-rw-r--r--services/core/java/com/android/server/location/LocationManagerService.java30
-rw-r--r--services/core/java/com/android/server/location/LocationProviderManager.java225
-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.java23
-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/pm/ApkChecksums.java310
-rw-r--r--services/core/java/com/android/server/pm/PackageInstallerSession.java61
-rw-r--r--services/core/java/com/android/server/pm/PackageManagerService.java191
-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/StagingManager.java126
-rw-r--r--services/core/java/com/android/server/pm/UserManagerService.java110
-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/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/wm/AccessibilityController.java12
-rw-r--r--services/core/java/com/android/server/wm/ActivityRecord.java211
-rw-r--r--services/core/java/com/android/server/wm/ActivityStarter.java14
-rw-r--r--services/core/java/com/android/server/wm/ActivityTaskManagerDebugConfig.java6
-rw-r--r--services/core/java/com/android/server/wm/ActivityTaskManagerService.java62
-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.java26
-rw-r--r--services/core/java/com/android/server/wm/DisplayPolicy.java55
-rw-r--r--services/core/java/com/android/server/wm/ImeInsetsSourceProvider.java2
-rw-r--r--services/core/java/com/android/server/wm/InputMonitor.java20
-rw-r--r--services/core/java/com/android/server/wm/InsetsSourceProvider.java6
-rw-r--r--services/core/java/com/android/server/wm/LockTaskController.java30
-rw-r--r--services/core/java/com/android/server/wm/ResetTargetTaskHelper.java8
-rw-r--r--services/core/java/com/android/server/wm/RootWindowContainer.java57
-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.java22
-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.java17
-rw-r--r--services/core/java/com/android/server/wm/WindowOrganizerController.java14
-rw-r--r--services/core/java/com/android/server/wm/WindowProcessController.java8
-rw-r--r--services/core/java/com/android/server/wm/WindowState.java193
-rw-r--r--services/core/java/com/android/server/wm/WindowStateAnimator.java10
-rw-r--r--services/core/jni/com_android_server_VibratorService.cpp232
-rw-r--r--services/core/jni/com_android_server_security_VerityUtils.cpp36
-rw-r--r--services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java8
-rw-r--r--services/incremental/IncrementalService.cpp4
-rw-r--r--services/incremental/test/IncrementalServiceTest.cpp8
-rw-r--r--services/tests/mockingservicestests/src/com/android/server/location/LocationProviderManagerTest.java6
-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/WindowMagnificationGestureHandlerTest.java4
-rw-r--r--services/tests/servicestests/src/com/android/server/accessibility/magnification/WindowMagnificationManagerTest.java39
-rw-r--r--services/tests/servicestests/src/com/android/server/hdmi/HdmiCecLocalDevicePlaybackTest.java77
-rw-r--r--services/tests/servicestests/src/com/android/server/hdmi/HdmiCecMessageBuilderTest.java26
-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/wmtests/src/com/android/server/wm/ActivityRecordTests.java21
-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.java176
-rw-r--r--services/tests/wmtests/src/com/android/server/wm/DisplayPolicyTests.java4
-rw-r--r--services/tests/wmtests/src/com/android/server/wm/InsetsSourceProviderTest.java28
-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/WindowOrganizerTests.java17
-rw-r--r--services/tests/wmtests/src/com/android/server/wm/WindowStateTests.java8
-rw-r--r--services/tests/wmtests/src/com/android/server/wm/WindowTestsBase.java2
-rw-r--r--tests/StagedInstallTest/Android.bp2
-rw-r--r--tests/StagedInstallTest/src/com/android/tests/stagedinstallinternal/host/StagedInstallInternalTest.java72
-rw-r--r--tests/net/java/com/android/server/ConnectivityServiceTest.java2
-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
329 files changed, 11089 insertions, 6098 deletions
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/api/current.txt b/api/current.txt
index c6af6beca60b..e5baa7c07cd5 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 {
diff --git a/api/system-current.txt b/api/system-current.txt
index 41e859363581..00a59bf4f1e3 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";
diff --git a/api/test-current.txt b/api/test-current.txt
index 529dcf71ef6e..5741fe7e90a4 100644
--- a/api/test-current.txt
+++ b/api/test-current.txt
@@ -5579,7 +5579,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/MetricsManager.cpp b/cmds/statsd/src/metrics/MetricsManager.cpp
index 5a520326116a..a0c701ea4229 100644
--- a/cmds/statsd/src/metrics/MetricsManager.cpp
+++ b/cmds/statsd/src/metrics/MetricsManager.cpp
@@ -80,7 +80,7 @@ MetricsManager::MetricsManager(const ConfigKey& key, const StatsdConfig& config,
mConfigValid = initStatsdConfig(
key, config, uidMap, pullerManager, anomalyAlarmMonitor, periodicAlarmMonitor,
timeBaseNs, currentTimeNs, mTagIds, mAllAtomMatchingTrackers, mAtomMatchingTrackerMap,
- mAllConditionTrackers, mAllMetricProducers, mAllAnomalyTrackers,
+ mAllConditionTrackers, mConditionTrackerMap, mAllMetricProducers, mAllAnomalyTrackers,
mAllPeriodicAlarmTrackers, mConditionToMetricMap, mTrackerToMetricMap,
mTrackerToConditionMap, mActivationAtomTrackerToMetricMap,
mDeactivationAtomTrackerToMetricMap, mAlertTrackerMap, mMetricIndexesWithActivation,
@@ -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..bd0c8161a884 100644
--- a/cmds/statsd/src/metrics/MetricsManager.h
+++ b/cmds/statsd/src/metrics/MetricsManager.h
@@ -242,9 +242,12 @@ 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;
+
// 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.
diff --git a/cmds/statsd/src/metrics/ValueMetricProducer.cpp b/cmds/statsd/src/metrics/ValueMetricProducer.cpp
index 9b684f1248c5..dcfbd5ea239b 100644
--- a/cmds/statsd/src/metrics/ValueMetricProducer.cpp
+++ b/cmds/statsd/src/metrics/ValueMetricProducer.cpp
@@ -411,7 +411,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 +623,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 +652,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 +788,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 +818,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 +990,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 +1030,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 +1059,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 +1107,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 +1126,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 +1139,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..472cc33b97fa 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
@@ -173,7 +172,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 +187,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 +238,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 +248,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..2e3e43413d54 100644
--- a/cmds/statsd/src/metrics/parsing_utils/metrics_manager_util.cpp
+++ b/cmds/statsd/src/metrics/parsing_utils/metrics_manager_util.cpp
@@ -74,16 +74,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,
@@ -266,8 +287,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 +296,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 +327,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);
}
@@ -934,6 +943,7 @@ 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,
vector<sp<AnomalyTracker>>& allAnomalyTrackers,
vector<sp<AlarmTracker>>& allPeriodicAlarmTrackers,
@@ -944,7 +954,6 @@ bool initStatsdConfig(const ConfigKey& key, const StatsdConfig& config, const sp
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<ConditionState> initialConditionCache;
unordered_map<int64_t, int> metricProducerMap;
unordered_map<int64_t, int> stateAtomIdMap;
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..6eabcf4971d3 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
@@ -111,7 +121,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,6 +144,7 @@ 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,
vector<sp<AnomalyTracker>>& allAnomalyTrackers,
vector<sp<AlarmTracker>>& allPeriodicAlarmTrackers,
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/ValueMetricProducer_test.cpp b/cmds/statsd/tests/metrics/ValueMetricProducer_test.cpp
index 1000aea14868..8790fe428d19 100644
--- a/cmds/statsd/tests/metrics/ValueMetricProducer_test.cpp
+++ b/cmds/statsd/tests/metrics/ValueMetricProducer_test.cpp
@@ -57,7 +57,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 +79,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;
@@ -288,8 +288,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 +305,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 +323,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);
@@ -426,8 +427,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 +457,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 +491,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 +505,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 +519,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 +552,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 +566,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 +577,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 +628,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 +646,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 +659,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);
@@ -879,8 +884,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 +894,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);
@@ -925,8 +931,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 +941,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 +952,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);
@@ -1089,8 +1095,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 +1111,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 +1128,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 +1187,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 +1197,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 +1211,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 +1260,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 +1274,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 +1283,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 +1295,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);
@@ -1327,7 +1336,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 +1344,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);
@@ -1364,7 +1373,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 +1383,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);
@@ -1405,7 +1414,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 +1423,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);
@@ -1449,7 +1458,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 +1466,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);
@@ -1487,8 +1496,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 +1509,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 +1519,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 +1530,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);
@@ -1558,12 +1568,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 +1583,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 +1598,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 +1615,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 +1667,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 +1703,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 +1743,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 +1773,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 +1805,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 +1852,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 +1890,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 +1904,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 +1918,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 +1958,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 +1996,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 +2047,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);
@@ -2103,8 +2121,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 +2175,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 +2314,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 +2394,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 +2482,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 +2492,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 +2536,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 +2548,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 +2594,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 +2700,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 +2835,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);
@@ -3045,8 +3069,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 +3083,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 +3116,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 +4010,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 +4031,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 +4053,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 +4082,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 +4221,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 +4242,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 +4265,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 +4288,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 +4310,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 +4473,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 +4511,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 +4550,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 +4596,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 +4634,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 +4643,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 +4656,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 +4692,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 +4701,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 +4713,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 +4751,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 +4761,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 +4883,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 +4908,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 +4921,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 +4935,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 +4959,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..890884bc5d83 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,6 +56,7 @@ 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;
std::vector<sp<AnomalyTracker>> oldAnomalyTrackers;
std::vector<sp<AlarmTracker>> oldAlarmTrackers;
@@ -75,6 +79,7 @@ public:
oldAtomMatchingTrackers.clear();
oldAtomMatchingTrackerMap.clear();
oldConditionTrackers.clear();
+ oldConditionTrackerMap.clear();
oldMetricProducers.clear();
oldAnomalyTrackers.clear();
oldAlarmTrackers.clear();
@@ -93,8 +98,8 @@ 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,
+ oldConditionTrackers, oldConditionTrackerMap, oldMetricProducers, oldAnomalyTrackers,
+ oldAlarmTrackers, conditionToMetricMap, trackerToMetricMap, trackerToConditionMap,
activationAtomTrackerToMetricMap, deactivationAtomTrackerToMetricMap, alertTrackerMap,
metricsWithActivation, noReportMetricIds);
}
@@ -144,6 +149,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 +367,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 +435,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..e6583c9686ec 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
@@ -384,8 +384,9 @@ 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;
std::vector<sp<AnomalyTracker>> allAnomalyTrackers;
std::vector<sp<AlarmTracker>> allAlarmTrackers;
@@ -400,9 +401,9 @@ TEST(MetricsManagerTest, TestInitialConditions) {
EXPECT_TRUE(initStatsdConfig(
kConfigKey, config, uidMap, pullerManager, anomalyAlarmMonitor, periodicAlarmMonitor,
- timeBaseSec, timeBaseSec, allTagIds, allAtomMatchingTrackers, logTrackerMap,
- allConditionTrackers, allMetricProducers, allAnomalyTrackers, allAlarmTrackers,
- conditionToMetricMap, trackerToMetricMap, trackerToConditionMap,
+ timeBaseSec, timeBaseSec, allTagIds, allAtomMatchingTrackers, atomMatchingTrackerMap,
+ allConditionTrackers, conditionTrackerMap, allMetricProducers, allAnomalyTrackers,
+ allAlarmTrackers, conditionToMetricMap, trackerToMetricMap, trackerToConditionMap,
activationAtomTrackerToMetricMap, deactivationAtomTrackerToMetricMap, alertTrackerMap,
metricsWithActivation, noReportMetricIds));
ASSERT_EQ(4u, allMetricProducers.size());
@@ -433,8 +434,9 @@ 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;
std::vector<sp<AnomalyTracker>> allAnomalyTrackers;
std::vector<sp<AlarmTracker>> allAlarmTrackers;
@@ -449,9 +451,9 @@ TEST(MetricsManagerTest, TestGoodConfig) {
EXPECT_TRUE(initStatsdConfig(
kConfigKey, config, uidMap, pullerManager, anomalyAlarmMonitor, periodicAlarmMonitor,
- timeBaseSec, timeBaseSec, allTagIds, allAtomMatchingTrackers, logTrackerMap,
- allConditionTrackers, allMetricProducers, allAnomalyTrackers, allAlarmTrackers,
- conditionToMetricMap, trackerToMetricMap, trackerToConditionMap,
+ timeBaseSec, timeBaseSec, allTagIds, allAtomMatchingTrackers, atomMatchingTrackerMap,
+ allConditionTrackers, conditionTrackerMap, allMetricProducers, allAnomalyTrackers,
+ allAlarmTrackers, conditionToMetricMap, trackerToMetricMap, trackerToConditionMap,
activationAtomTrackerToMetricMap, deactivationAtomTrackerToMetricMap, alertTrackerMap,
metricsWithActivation, noReportMetricIds));
ASSERT_EQ(1u, allMetricProducers.size());
@@ -470,8 +472,9 @@ 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;
std::vector<sp<AnomalyTracker>> allAnomalyTrackers;
std::vector<sp<AlarmTracker>> allAlarmTrackers;
@@ -486,9 +489,9 @@ TEST(MetricsManagerTest, TestDimensionMetricsWithMultiTags) {
EXPECT_FALSE(initStatsdConfig(
kConfigKey, config, uidMap, pullerManager, anomalyAlarmMonitor, periodicAlarmMonitor,
- timeBaseSec, timeBaseSec, allTagIds, allAtomMatchingTrackers, logTrackerMap,
- allConditionTrackers, allMetricProducers, allAnomalyTrackers, allAlarmTrackers,
- conditionToMetricMap, trackerToMetricMap, trackerToConditionMap,
+ timeBaseSec, timeBaseSec, allTagIds, allAtomMatchingTrackers, atomMatchingTrackerMap,
+ allConditionTrackers, conditionTrackerMap, allMetricProducers, allAnomalyTrackers,
+ allAlarmTrackers, conditionToMetricMap, trackerToMetricMap, trackerToConditionMap,
activationAtomTrackerToMetricMap, deactivationAtomTrackerToMetricMap, alertTrackerMap,
metricsWithActivation, noReportMetricIds));
}
@@ -501,8 +504,9 @@ 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;
std::vector<sp<AnomalyTracker>> allAnomalyTrackers;
std::vector<sp<AlarmTracker>> allAlarmTrackers;
@@ -517,9 +521,9 @@ TEST(MetricsManagerTest, TestCircleLogMatcherDependency) {
EXPECT_FALSE(initStatsdConfig(
kConfigKey, config, uidMap, pullerManager, anomalyAlarmMonitor, periodicAlarmMonitor,
- timeBaseSec, timeBaseSec, allTagIds, allAtomMatchingTrackers, logTrackerMap,
- allConditionTrackers, allMetricProducers, allAnomalyTrackers, allAlarmTrackers,
- conditionToMetricMap, trackerToMetricMap, trackerToConditionMap,
+ timeBaseSec, timeBaseSec, allTagIds, allAtomMatchingTrackers, atomMatchingTrackerMap,
+ allConditionTrackers, conditionTrackerMap, allMetricProducers, allAnomalyTrackers,
+ allAlarmTrackers, conditionToMetricMap, trackerToMetricMap, trackerToConditionMap,
activationAtomTrackerToMetricMap, deactivationAtomTrackerToMetricMap, alertTrackerMap,
metricsWithActivation, noReportMetricIds));
}
@@ -532,8 +536,9 @@ 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;
std::vector<sp<AnomalyTracker>> allAnomalyTrackers;
std::vector<sp<AlarmTracker>> allAlarmTrackers;
@@ -547,9 +552,9 @@ TEST(MetricsManagerTest, TestMissingMatchers) {
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,
+ timeBaseSec, timeBaseSec, allTagIds, allAtomMatchingTrackers, atomMatchingTrackerMap,
+ allConditionTrackers, conditionTrackerMap, allMetricProducers, allAnomalyTrackers,
+ allAlarmTrackers, conditionToMetricMap, trackerToMetricMap, trackerToConditionMap,
activationAtomTrackerToMetricMap, deactivationAtomTrackerToMetricMap, alertTrackerMap,
metricsWithActivation, noReportMetricIds));
}
@@ -562,8 +567,9 @@ 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;
std::vector<sp<AnomalyTracker>> allAnomalyTrackers;
std::vector<sp<AlarmTracker>> allAlarmTrackers;
@@ -577,9 +583,9 @@ TEST(MetricsManagerTest, TestMissingPredicate) {
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,
+ timeBaseSec, timeBaseSec, allTagIds, allAtomMatchingTrackers, atomMatchingTrackerMap,
+ allConditionTrackers, conditionTrackerMap, allMetricProducers, allAnomalyTrackers,
+ allAlarmTrackers, conditionToMetricMap, trackerToMetricMap, trackerToConditionMap,
activationAtomTrackerToMetricMap, deactivationAtomTrackerToMetricMap, alertTrackerMap,
metricsWithActivation, noReportMetricIds));
}
@@ -592,8 +598,9 @@ 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;
std::vector<sp<AnomalyTracker>> allAnomalyTrackers;
std::vector<sp<AlarmTracker>> allAlarmTrackers;
@@ -608,9 +615,9 @@ TEST(MetricsManagerTest, TestCirclePredicateDependency) {
EXPECT_FALSE(initStatsdConfig(
kConfigKey, config, uidMap, pullerManager, anomalyAlarmMonitor, periodicAlarmMonitor,
- timeBaseSec, timeBaseSec, allTagIds, allAtomMatchingTrackers, logTrackerMap,
- allConditionTrackers, allMetricProducers, allAnomalyTrackers, allAlarmTrackers,
- conditionToMetricMap, trackerToMetricMap, trackerToConditionMap,
+ timeBaseSec, timeBaseSec, allTagIds, allAtomMatchingTrackers, atomMatchingTrackerMap,
+ allConditionTrackers, conditionTrackerMap, allMetricProducers, allAnomalyTrackers,
+ allAlarmTrackers, conditionToMetricMap, trackerToMetricMap, trackerToConditionMap,
activationAtomTrackerToMetricMap, deactivationAtomTrackerToMetricMap, alertTrackerMap,
metricsWithActivation, noReportMetricIds));
}
@@ -623,8 +630,9 @@ 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;
std::vector<sp<AnomalyTracker>> allAnomalyTrackers;
std::vector<sp<AlarmTracker>> allAlarmTrackers;
@@ -639,9 +647,9 @@ TEST(MetricsManagerTest, testAlertWithUnknownMetric) {
EXPECT_FALSE(initStatsdConfig(
kConfigKey, config, uidMap, pullerManager, anomalyAlarmMonitor, periodicAlarmMonitor,
- timeBaseSec, timeBaseSec, allTagIds, allAtomMatchingTrackers, logTrackerMap,
- allConditionTrackers, allMetricProducers, allAnomalyTrackers, allAlarmTrackers,
- conditionToMetricMap, trackerToMetricMap, trackerToConditionMap,
+ timeBaseSec, timeBaseSec, allTagIds, allAtomMatchingTrackers, atomMatchingTrackerMap,
+ allConditionTrackers, conditionTrackerMap, allMetricProducers, allAnomalyTrackers,
+ allAlarmTrackers, conditionToMetricMap, trackerToMetricMap, trackerToConditionMap,
activationAtomTrackerToMetricMap, deactivationAtomTrackerToMetricMap, alertTrackerMap,
metricsWithActivation, noReportMetricIds));
}
@@ -649,6 +657,7 @@ TEST(MetricsManagerTest, testAlertWithUnknownMetric) {
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 +708,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/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/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/admin/DevicePolicyManager.java b/core/java/android/app/admin/DevicePolicyManager.java
index c61426d5c172..98de85d9735d 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.
*
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/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/PackageManager.java b/core/java/android/content/pm/PackageManager.java
index 7b2955db3318..da8d15af92b8 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;
@@ -3305,6 +3308,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 +7852,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/os/UserManager.java b/core/java/android/os/UserManager.java
index 2465b0e41876..81a147c68e2e 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;
@@ -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);
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/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/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/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/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/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/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_util_Process.cpp b/core/jni/android_util_Process.cpp
index 23af70a7cc18..cbcbe7f11390 100644
--- a/core/jni/android_util_Process.cpp
+++ b/core/jni/android_util_Process.cpp
@@ -613,7 +613,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);
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/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/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..75eb7b64a444 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,12 +295,30 @@
"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",
@@ -307,6 +391,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",
@@ -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,6 +553,12 @@
"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",
@@ -475,6 +589,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 +679,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 +763,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",
@@ -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",
@@ -739,6 +901,12 @@
"group": "WM_DEBUG_FOCUS_LIGHT",
"at": "com\/android\/server\/wm\/DisplayContent.java"
},
+ "-593535526": {
+ "message": "Binding proc %s with config %s",
+ "level": "VERBOSE",
+ "group": "WM_DEBUG_CONFIGURATION",
+ "at": "com\/android\/server\/am\/ActivityManagerService.java"
+ },
"-583031528": {
"message": "%s",
"level": "INFO",
@@ -757,6 +925,12 @@
"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",
@@ -979,6 +1207,12 @@
"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",
"level": "VERBOSE",
@@ -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",
@@ -1267,6 +1519,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",
@@ -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",
@@ -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,12 @@
"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"
+ },
"873914452": {
"message": "goodToGo()",
"level": "DEBUG",
@@ -1633,6 +1921,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 +1939,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 +1975,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 +2005,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 +2035,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,6 +2125,12 @@
"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",
@@ -1801,6 +2143,12 @@
"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",
"level": "VERBOSE",
@@ -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",
@@ -1927,6 +2281,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 +2311,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 +2347,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 +2395,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 +2455,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 +2527,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 +2563,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 +2581,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 +2605,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",
@@ -2269,6 +2689,12 @@
"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 +2703,6 @@
}
},
"groups": {
- "TEST_GROUP": {
- "tag": "WindowManagetProtoLogTest"
- },
"WM_DEBUG_ADD_REMOVE": {
"tag": "WindowManager"
},
@@ -2292,6 +2715,12 @@
"WM_DEBUG_BOOT": {
"tag": "WindowManager"
},
+ "WM_DEBUG_CONFIGURATION": {
+ "tag": "WindowManager"
+ },
+ "WM_DEBUG_CONTAINERS": {
+ "tag": "WindowManager"
+ },
"WM_DEBUG_DRAW": {
"tag": "WindowManager"
},
@@ -2304,9 +2733,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 +2760,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/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..307b82e69506 100644
--- a/libs/WindowManager/Shell/Android.bp
+++ b/libs/WindowManager/Shell/Android.bp
@@ -12,14 +12,88 @@
// 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
+
android_library {
name: "WindowManager-Shell",
srcs: [
- "src/**/*.java",
+ ":wm_shell_protolog_src",
"src/**/I*.aidl",
],
resource_dirs: [
"res",
],
+ static_libs: [
+ "protolog-lib",
+ ],
manifest: "AndroidManifest.xml",
-}
+} \ No newline at end of file
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/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/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/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/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..7cce0f2f4b3e 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";
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..1a6fdfa9c996 100644
--- a/packages/CarSystemUI/src/com/android/systemui/CarSysUIComponent.java
+++ b/packages/CarSystemUI/src/com/android/systemui/CarSysUIComponent.java
@@ -16,11 +16,9 @@
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;
@@ -33,9 +31,7 @@ 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/car/notification/NotificationPanelViewController.java b/packages/CarSystemUI/src/com/android/systemui/car/notification/NotificationPanelViewController.java
index 3b22fdb50765..38e1a48ab3a7 100644
--- a/packages/CarSystemUI/src/com/android/systemui/car/notification/NotificationPanelViewController.java
+++ b/packages/CarSystemUI/src/com/android/systemui/car/notification/NotificationPanelViewController.java
@@ -299,10 +299,10 @@ 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.
@@ -355,8 +355,7 @@ public class NotificationPanelViewController extends OverlayPanelViewController
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 +368,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/window/OverlayPanelViewController.java b/packages/CarSystemUI/src/com/android/systemui/car/window/OverlayPanelViewController.java
index 45808a8a0b3e..bde31f18d8fd 100644
--- a/packages/CarSystemUI/src/com/android/systemui/car/window/OverlayPanelViewController.java
+++ b/packages/CarSystemUI/src/com/android/systemui/car/window/OverlayPanelViewController.java
@@ -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 {
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/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/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/src/com/android/settingslib/Utils.java b/packages/SettingsLib/src/com/android/settingslib/Utils.java
index a43412e116c8..b2808061586b 100644
--- a/packages/SettingsLib/src/com/android/settingslib/Utils.java
+++ b/packages/SettingsLib/src/com/android/settingslib/Utils.java
@@ -49,11 +49,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 +361,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) {
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/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/SystemUI/Android.bp b/packages/SystemUI/Android.bp
index 2fbd9ba05817..0f2e25c7025b 100644
--- a/packages/SystemUI/Android.bp
+++ b/packages/SystemUI/Android.bp
@@ -174,6 +174,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..7f4f580abf94 100644
--- a/packages/SystemUI/AndroidManifest.xml
+++ b/packages/SystemUI/AndroidManifest.xml
@@ -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/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/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/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/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/systemui/pip/phone/dagger/PipMenuActivityClass.java b/packages/SystemUI/src/com/android/keyguard/dagger/KeyguardStatusViewScope.java
index 114c30e625aa..880822aa7343 100644
--- a/packages/SystemUI/src/com/android/systemui/pip/phone/dagger/PipMenuActivityClass.java
+++ b/packages/SystemUI/src/com/android/keyguard/dagger/KeyguardStatusViewScope.java
@@ -14,17 +14,19 @@
* limitations under the License.
*/
-package com.android.systemui.pip.phone.dagger;
+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.Qualifier;
+import javax.inject.Scope;
-@Qualifier
+/**
+ * Scope annotation for singleton items within the StatusBarComponent.
+ */
@Documented
@Retention(RUNTIME)
-public @interface PipMenuActivityClass {
-}
+@Scope
+public @interface KeyguardStatusViewScope {}
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 47066a05b9b8..e91284b546db 100644
--- a/packages/SystemUI/src/com/android/systemui/SwipeHelper.java
+++ b/packages/SystemUI/src/com/android/systemui/SwipeHelper.java
@@ -16,6 +16,8 @@
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;
@@ -696,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..941fd6f320e2 100644
--- a/packages/SystemUI/src/com/android/systemui/SystemUIFactory.java
+++ b/packages/SystemUI/src/com/android/systemui/SystemUIFactory.java
@@ -38,6 +38,7 @@ 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 +84,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 +107,15 @@ public class SystemUIFactory {
.build();
}
+
public GlobalRootComponent getRootComponent() {
return mRootComponent;
}
+ public WMComponent getWMComponent() {
+ return mWMComponent;
+ }
+
public SysUIComponent getSysUIComponent() {
return mSysUIComponent;
}
diff --git a/packages/SystemUI/src/com/android/systemui/appops/dagger/AppOpsModule.java b/packages/SystemUI/src/com/android/systemui/appops/dagger/AppOpsModule.java
new file mode 100644
index 000000000000..d4cc3f37b8dd
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/appops/dagger/AppOpsModule.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.appops.dagger;
+
+import com.android.systemui.appops.AppOpsController;
+import com.android.systemui.appops.AppOpsControllerImpl;
+
+import dagger.Binds;
+import dagger.Module;
+
+/** Dagger Module for code in the appops package. */
+@Module
+public interface AppOpsModule {
+ /** */
+ @Binds
+ AppOpsController provideAppOpsController(AppOpsControllerImpl controllerImpl);
+
+}
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 8a67e968ae13..0dd9488f1d3e 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;
@@ -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
diff --git a/packages/SystemUI/src/com/android/systemui/dagger/SystemServicesModule.java b/packages/SystemUI/src/com/android/systemui/dagger/FrameworkServicesModule.java
index ceb9aeee1d3b..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;
@@ -68,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;
@@ -81,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);
}
@@ -137,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);
@@ -177,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));
@@ -196,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);
@@ -240,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);
}
@@ -277,57 +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
- @SysUISingleton
+ @Singleton
static UserManager provideUserManager(Context context) {
return context.getSystemService(UserManager.class);
}
@@ -338,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..2622593880ba 100644
--- a/packages/SystemUI/src/com/android/systemui/dagger/SysUIComponent.java
+++ b/packages/SystemUI/src/com/android/systemui/dagger/SysUIComponent.java
@@ -26,6 +26,7 @@ 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 +36,7 @@ import dagger.Subcomponent;
@Subcomponent(modules = {
DefaultComponentBinder.class,
DependencyProvider.class,
- DependencyBinder.class,
PipModule.class,
- SystemServicesModule.class,
SystemUIBinder.class,
SystemUIModule.class,
SystemUIDefaultModule.class})
@@ -48,6 +47,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/SystemUIModule.java b/packages/SystemUI/src/com/android/systemui/dagger/SystemUIModule.java
index e985e3d7ef90..99a3a9119f89 100644
--- a/packages/SystemUI/src/com/android/systemui/dagger/SystemUIModule.java
+++ b/packages/SystemUI/src/com/android/systemui/dagger/SystemUIModule.java
@@ -18,12 +18,15 @@ package com.android.systemui.dagger;
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 +40,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,15 +60,23 @@ 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,
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/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/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..33407918f938 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());
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/navigationbar/NavigationBar.java b/packages/SystemUI/src/com/android/systemui/navigationbar/NavigationBar.java
index aec3543de4eb..c7e78174f474 100644
--- a/packages/SystemUI/src/com/android/systemui/navigationbar/NavigationBar.java
+++ b/packages/SystemUI/src/com/android/systemui/navigationbar/NavigationBar.java
@@ -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());
diff --git a/packages/SystemUI/src/com/android/systemui/onehanded/OneHandedTutorialHandler.java b/packages/SystemUI/src/com/android/systemui/onehanded/OneHandedTutorialHandler.java
index 0354c727c92c..8ef9b092bc00 100644
--- a/packages/SystemUI/src/com/android/systemui/onehanded/OneHandedTutorialHandler.java
+++ b/packages/SystemUI/src/com/android/systemui/onehanded/OneHandedTutorialHandler.java
@@ -158,7 +158,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;
diff --git a/packages/SystemUI/src/com/android/systemui/pip/PipTaskOrganizer.java b/packages/SystemUI/src/com/android/systemui/pip/PipTaskOrganizer.java
index 7421ec14398b..c956702c9216 100644
--- a/packages/SystemUI/src/com/android/systemui/pip/PipTaskOrganizer.java
+++ b/packages/SystemUI/src/com/android/systemui/pip/PipTaskOrganizer.java
@@ -49,6 +49,9 @@ import android.os.RemoteException;
import android.util.Log;
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,6 +60,7 @@ 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.SplitScreen;
import com.android.wm.shell.R;
@@ -95,6 +99,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;
@@ -107,6 +112,8 @@ public class PipTaskOrganizer extends TaskOrganizer implements ShellTaskOrganize
private final Map<IBinder, Configuration> mInitialState = new HashMap<>();
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 =
@@ -212,6 +219,7 @@ public class PipTaskOrganizer extends TaskOrganizer implements ShellTaskOrganize
@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;
@@ -504,6 +512,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
@@ -838,6 +885,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,
diff --git a/packages/SystemUI/src/com/android/systemui/pip/phone/PipManager.java b/packages/SystemUI/src/com/android/systemui/pip/phone/PipManager.java
index d8864ec72dc3..5ef5b902327e 100644
--- a/packages/SystemUI/src/com/android/systemui/pip/phone/PipManager.java
+++ b/packages/SystemUI/src/com/android/systemui/pip/phone/PipManager.java
@@ -49,7 +49,6 @@ 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;
@@ -267,7 +266,6 @@ public class PipManager implements BasePipManager, PipTaskOrganizer.PipTransitio
@Inject
public PipManager(Context context, BroadcastDispatcher broadcastDispatcher,
- @PipMenuActivityClass Class<?> pipMenuActivityClass,
ConfigurationController configController,
DeviceConfigProxy deviceConfig,
DisplayController displayController,
@@ -296,8 +294,8 @@ public class PipManager implements BasePipManager, PipTaskOrganizer.PipTransitio
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);
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..f6853ecf8ee7 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) {
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/PipManager.java
index 8d0948b16d20..a388fa324a2e 100644
--- a/packages/SystemUI/src/com/android/systemui/pip/tv/PipManager.java
+++ b/packages/SystemUI/src/com/android/systemui/pip/tv/PipManager.java
@@ -142,7 +142,6 @@ 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;
@@ -216,10 +215,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);
});
}
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..70374036ef14 100644
--- a/packages/SystemUI/src/com/android/systemui/pip/tv/PipMenuActivity.java
+++ b/packages/SystemUI/src/com/android/systemui/pip/tv/PipMenuActivity.java
@@ -36,8 +36,8 @@ 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;
private static final String TAG = "PipMenuActivity";
+ private static final boolean DEBUG = Log.isLoggable(TAG, Log.DEBUG);
static final String EXTRA_CUSTOM_ACTIONS = "custom_actions";
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..5e5de58da2f6 100644
--- a/packages/SystemUI/src/com/android/systemui/pip/tv/PipNotification.java
+++ b/packages/SystemUI/src/com/android/systemui/pip/tv/PipNotification.java
@@ -114,6 +114,14 @@ public class PipNotification {
notifyPipNotification();
}
}
+
+ @Override
+ public void onMetadataChanged(MediaMetadata metadata) {
+ if (updateMediaControllerMetadata() && mNotified) {
+ // update notification
+ notifyPipNotification();
+ }
+ }
};
private final PipManager.MediaListener mPipMediaListener = new PipManager.MediaListener() {
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/recents/OverviewProxyService.java b/packages/SystemUI/src/com/android/systemui/recents/OverviewProxyService.java
index c0cc58638e3f..263bbdbf7c35 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/OverviewProxyService.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/OverviewProxyService.java
@@ -98,6 +98,7 @@ 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;
@@ -592,6 +593,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
@@ -613,7 +616,6 @@ public class OverviewProxyService extends CurrentUserTracker implements
mNavBarControllerLazy = navBarControllerLazy;
mStatusBarWinController = statusBarWinController;
mConnectionBackoffAttempts = 0;
- mSplitScreenOptional = splitScreenOptional;
mRecentsComponentName = ComponentName.unflattenFromString(context.getString(
com.android.internal.R.string.config_recentsComponentName));
mQuickStepIntent = new Intent(ACTION_QUICKSTEP)
@@ -653,6 +655,10 @@ public class OverviewProxyService extends CurrentUserTracker implements
});
mCommandQueue = commandQueue;
+ splitScreenOptional.ifPresent(splitScreen ->
+ splitScreen.registerBoundsChangeListener(mSplitScreenBoundsChangeListener));
+ mSplitScreenOptional = splitScreenOptional;
+
// Listen for user setup
startTracking();
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/stackdivider/DividerView.java b/packages/SystemUI/src/com/android/systemui/stackdivider/DividerView.java
index 95f048b0b06d..fdf24b1e1a7e 100644
--- a/packages/SystemUI/src/com/android/systemui/stackdivider/DividerView.java
+++ b/packages/SystemUI/src/com/android/systemui/stackdivider/DividerView.java
@@ -62,10 +62,8 @@ 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 java.util.function.Consumer;
@@ -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;
@@ -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;
@@ -697,8 +698,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() {
diff --git a/packages/SystemUI/src/com/android/systemui/stackdivider/SplitScreen.java b/packages/SystemUI/src/com/android/systemui/stackdivider/SplitScreen.java
index 91850cc46ab6..93b1f86a5dc2 100644
--- a/packages/SystemUI/src/com/android/systemui/stackdivider/SplitScreen.java
+++ b/packages/SystemUI/src/com/android/systemui/stackdivider/SplitScreen.java
@@ -16,9 +16,11 @@
package com.android.systemui.stackdivider;
+import android.graphics.Rect;
import android.window.WindowContainerToken;
import java.io.PrintWriter;
+import java.util.function.BiConsumer;
import java.util.function.Consumer;
/**
@@ -81,6 +83,9 @@ public interface SplitScreen {
/** 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/packages/SystemUI/src/com/android/systemui/stackdivider/SplitScreenController.java
index 11773f6d358c..360b49555612 100644
--- a/packages/SystemUI/src/com/android/systemui/stackdivider/SplitScreenController.java
+++ b/packages/SystemUI/src/com/android/systemui/stackdivider/SplitScreenController.java
@@ -46,6 +46,7 @@ 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;
/**
@@ -73,6 +74,8 @@ public class SplitScreenController implements SplitScreen,
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 SplitScreen,
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 SplitScreen,
}
}
+ @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/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/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..db2875a3d9aa 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/dagger/StatusBarDependenciesModule.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/dagger/StatusBarDependenciesModule.java
@@ -37,6 +37,8 @@ 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;
@@ -45,13 +47,19 @@ import com.android.systemui.statusbar.notification.collection.inflation.LowPrior
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.ManagedProfileController;
+import com.android.systemui.statusbar.phone.ManagedProfileControllerImpl;
import com.android.systemui.statusbar.phone.NotificationGroupManager;
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
@@ -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/collection/NotificationEntry.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/NotificationEntry.java
index 387247eb6c5b..8ce9d944b865 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
@@ -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
@@ -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/dagger/NotificationsModule.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/dagger/NotificationsModule.java
index 6d01324f1b7b..f3ed95bd2d76 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;
@@ -127,7 +127,7 @@ public interface NotificationsModule {
LauncherApps launcherApps,
ShortcutManager shortcutManager,
ChannelEditorDialogController channelEditorDialogController,
- CurrentUserContextTracker contextTracker,
+ UserContextProvider contextTracker,
Provider<PriorityOnboardingDialogController.Builder> builderProvider,
AssistantFeedbackController assistantFeedbackController,
BubbleController bubbleController,
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/stack/AmbientState.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/AmbientState.java
index d5e55315ff0a..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
@@ -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);
}
@@ -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 b1a9efe40fdb..3370773df807 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
@@ -92,8 +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.plugins.FalsingManager;
-import com.android.systemui.plugins.statusbar.NotificationMenuRowPlugin;
import com.android.systemui.plugins.statusbar.NotificationSwipeActionHelper;
import com.android.systemui.statusbar.CommandQueue;
import com.android.systemui.statusbar.DragDownHelper.DragDownCallback;
@@ -102,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;
@@ -127,19 +124,14 @@ 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;
@@ -340,13 +332,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() {
@@ -499,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;
@@ -513,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() {
@@ -562,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,11 +566,6 @@ public class NotificationStackScrollLayout extends ViewGroup implements Dumpable
Resources res = getResources();
mRoundnessManager = notificationRoundnessManager;
-
- mNotificationGutsManager = notificationGutsManager;
- mHeadsUpManager = headsUpManager;
- mHeadsUpManager.setAnimationStateHandler(this::setHeadsUpGoingAwayAnimationsAllowed);
- mFalsingManager = falsingManager;
mFgsSectionController = fgsSectionController;
mSectionsManager = notificationSectionsManager;
@@ -594,7 +577,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);
@@ -750,27 +733,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;
@@ -956,7 +918,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;
@@ -1472,11 +1434,10 @@ 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());
@@ -1497,7 +1458,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,9 +1616,9 @@ 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
+ && mTopHeadsUpEntry.getRow() != row
&& mGroupManager.getGroupSummary(
- mHeadsUpManager.getTopEntry().getSbn())
+ mTopHeadsUpEntry.getSbn())
!= entry) {
continue;
}
@@ -2285,7 +2246,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);
@@ -2636,7 +2597,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) {
@@ -3511,7 +3472,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
@@ -3754,58 +3715,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);
@@ -3854,7 +3773,7 @@ public class NotificationStackScrollLayout extends ViewGroup implements Dumpable
}
@ShadeViewRefactor(RefactorComponent.INPUT)
- private boolean onScrollTouch(MotionEvent ev) {
+ boolean onScrollTouch(MotionEvent ev) {
if (!isScrollingEnabled()) {
return false;
}
@@ -3943,7 +3862,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;
@@ -4061,44 +3980,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);
@@ -4117,7 +4006,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();
@@ -4139,7 +4028,7 @@ public class NotificationStackScrollLayout extends ViewGroup implements Dumpable
}
@ShadeViewRefactor(RefactorComponent.INPUT)
- private boolean onInterceptTouchEventScroll(MotionEvent ev) {
+ boolean onInterceptTouchEventScroll(MotionEvent ev) {
if (!isScrollingEnabled()) {
return false;
}
@@ -4335,29 +4224,6 @@ 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)
void setSwipingInProgress(boolean swiping) {
mSwipingInProgress = swiping;
if (swiping) {
@@ -4392,32 +4258,15 @@ 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();
@@ -5202,12 +5051,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;
}
@@ -5811,23 +5654,6 @@ public class NotificationStackScrollLayout extends ViewGroup implements Dumpable
mCurrentUserId = userId;
}
- void onMenuShown(View row) {
- mSwipeHelper.onMenuShown(row);
- }
-
- 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 addSwipedOutView(View v) {
mSwipedOutViews.add(v);
}
@@ -5840,6 +5666,67 @@ public class NotificationStackScrollLayout extends ViewGroup implements Dumpable
mAmbientState.onDragFinished(view);
}
+ void setTopHeadsUpEntry(NotificationEntry topEntry) {
+ mTopHeadsUpEntry = topEntry;
+ }
+
+ void setNumHeadsUp(long numHeadsUp) {
+ mNumHeadsUp = numHeadsUp;
+ mAmbientState.setHasAlertEntries(numHeadsUp > 0);
+ }
+
+ 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;
+ }
+
/**
* A listener that is notified when the empty space below the notifications is clicked on
*/
@@ -5935,7 +5822,7 @@ public class NotificationStackScrollLayout extends ViewGroup implements Dumpable
}
@ShadeViewRefactor(RefactorComponent.SHADE_VIEW)
- void resetExposedMenuView(boolean animate, boolean force) {
+ private void resetExposedMenuView(boolean animate, boolean force) {
mSwipeHelper.resetExposedMenuView(animate, force);
}
@@ -6293,6 +6180,10 @@ public class NotificationStackScrollLayout extends ViewGroup implements Dumpable
mKeyguardMediaControllorVisible = keyguardMediaControllorVisible;
}
+ void resetCheckSnoozeLeavebehind() {
+ setCheckForLeaveBehind(true);
+ }
+
// ---------------------- DragDownHelper.OnDragDownListener ------------------------------------
@ShadeViewRefactor(RefactorComponent.INPUT)
@@ -6345,7 +6236,7 @@ public class NotificationStackScrollLayout extends ViewGroup implements Dumpable
@Override
public void onTouchSlopExceeded() {
cancelLongPress();
- checkSnoozeLeavebehind();
+ mController.checkSnoozeLeavebehind();
}
@Override
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 73b4cad4ced5..70892e0f9b38 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
@@ -34,6 +34,8 @@ 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;
@@ -58,7 +60,9 @@ 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;
@@ -70,6 +74,7 @@ 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;
@@ -100,6 +105,7 @@ public class NotificationStackScrollLayoutController {
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;
@@ -110,6 +116,7 @@ public class NotificationStackScrollLayoutController {
private NotificationStackScrollLayout mView;
private boolean mFadeNotificationsOnDismiss;
+ private NotificationSwipeHelper mSwipeHelper;
private final NotificationListContainerImpl mNotificationListContainer =
new NotificationListContainerImpl();
@@ -217,7 +224,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
@@ -228,7 +244,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 */);
@@ -246,7 +262,7 @@ public class NotificationStackScrollLayoutController {
}
// Close the menu row since we went directly to the guts
- mView.resetExposedMenuView(false, true);
+ mSwipeHelper.resetExposedMenuView(false, true);
}
}
}
@@ -438,7 +454,31 @@ public class NotificationStackScrollLayoutController {
}
};
- private NotificationSwipeHelper mSwipeHelper;
+ 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);
+ }
+ };
@Inject
public NotificationStackScrollLayoutController(
@@ -460,7 +500,8 @@ public class NotificationStackScrollLayoutController {
NotificationSectionsManager notificationSectionsManager,
@Main Resources resources,
NotificationSwipeHelper.Builder notificationSwipeHelperBuilder,
- StatusBar statusBar) {
+ StatusBar statusBar,
+ ScrimController scrimController) {
mAllowLongPress = allowLongPress;
mNotificationGutsManager = notificationGutsManager;
mHeadsUpManager = headsUpManager;
@@ -480,11 +521,13 @@ public class NotificationStackScrollLayoutController {
mResources = resources;
mNotificationSwipeHelperBuilder = notificationSwipeHelperBuilder;
mStatusBar = statusBar;
+ mScrimController = scrimController;
}
public void attach(NotificationStackScrollLayout view) {
mView = view;
mView.setController(this);
+ mView.setTouchHandler(new TouchHandler());
mSwipeHelper = mNotificationSwipeHelperBuilder
.setSwipeDirection(SwipeHelper.X)
@@ -496,8 +539,12 @@ public class NotificationStackScrollLayoutController {
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());
@@ -738,7 +785,12 @@ 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) {
@@ -761,10 +813,6 @@ public class NotificationStackScrollLayoutController {
mView.updateTopPadding(qsHeight, animate);
}
- public void resetCheckSnoozeLeavebehind() {
- mView.resetCheckSnoozeLeavebehind();
- }
-
public boolean isScrolledToBottom() {
return mView.isScrolledToBottom();
}
@@ -815,9 +863,11 @@ public class NotificationStackScrollLayoutController {
public void onExpansionStarted() {
mView.onExpansionStarted();
+ checkSnoozeLeavebehind();
}
public void onExpansionStopped() {
+ mView.setCheckForLeaveBehind(false);
mView.onExpansionStopped();
}
@@ -910,7 +960,23 @@ public class NotificationStackScrollLayoutController {
}
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) {
@@ -958,18 +1024,10 @@ public class NotificationStackScrollLayoutController {
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);
}
@@ -1002,7 +1060,7 @@ public class NotificationStackScrollLayoutController {
return mView.calculateGapHeight(previousView, child, count);
}
- public NotificationRoundnessManager getNoticationRoundessManager() {
+ NotificationRoundnessManager getNoticationRoundessManager() {
return mNotificationRoundnessManager;
}
@@ -1010,6 +1068,32 @@ 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) {
@@ -1084,7 +1168,7 @@ public class NotificationStackScrollLayoutController {
@Override
public void resetExposedMenuView(boolean animate, boolean force) {
- mView.resetExposedMenuView(animate, force);
+ mSwipeHelper.resetExposedMenuView(animate, force);
}
@Override
@@ -1148,4 +1232,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 1e80e88df1a1..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
@@ -227,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
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..ba9420265849 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardAffordanceHelper.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardAffordanceHelper.java
@@ -27,6 +27,7 @@ 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;
@@ -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/NotificationPanelViewController.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelViewController.java
index d83758a57401..1cd85e3b3cc1 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,7 @@ 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;
@@ -68,9 +69,11 @@ 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;
@@ -129,7 +132,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 {
@@ -260,7 +262,7 @@ 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;
@@ -511,9 +513,9 @@ public class NotificationPanelViewController extends PanelViewController {
MediaHierarchyManager mediaHierarchyManager,
BiometricUnlockController biometricUnlockController,
StatusBarKeyguardViewManager statusBarKeyguardViewManager,
- Provider<KeyguardClockSwitchController> keyguardClockSwitchControllerProvider,
NotificationStackScrollLayoutController notificationStackScrollLayoutController,
- NotificationIconAreaController notificationIconAreaController) {
+ NotificationIconAreaController notificationIconAreaController,
+ KeyguardStatusViewComponent.Factory keyguardStatusViewComponentFactory) {
super(view, falsingManager, dozeLog, keyguardStateController,
(SysuiStatusBarStateController) statusBarStateController, vibratorHelper,
latencyTracker, flingAnimationUtilsBuilder, statusBarTouchableRegionManager);
@@ -525,9 +527,9 @@ public class NotificationPanelViewController extends PanelViewController {
mFlingAnimationUtilsBuilder = flingAnimationUtilsBuilder;
mMediaHierarchyManager = mediaHierarchyManager;
mStatusBarKeyguardViewManager = statusBarKeyguardViewManager;
- mKeyguardClockSwitchControllerProvider = keyguardClockSwitchControllerProvider;
mNotificationStackScrollLayoutController = notificationStackScrollLayoutController;
mNotificationIconAreaController = notificationIconAreaController;
+ mKeyguardStatusViewComponentFactory = keyguardStatusViewComponentFactory;
mView.setWillNotDraw(!DEBUG);
mInjectionInflationController = injectionInflationController;
mFalsingManager = falsingManager;
@@ -602,8 +604,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);
@@ -733,8 +737,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
@@ -1264,7 +1270,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()) {
@@ -1274,12 +1280,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;
}
@@ -3066,9 +3072,6 @@ public class NotificationPanelViewController extends PanelViewController {
if (mKeyguardStatusBar != null) {
mKeyguardStatusBar.dump(fd, pw, args);
}
- if (mKeyguardStatusView != null) {
- mKeyguardStatusView.dump(fd, pw, args);
- }
}
public boolean hasActiveClearableNotifications() {
@@ -3137,15 +3140,13 @@ 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);
@@ -3543,7 +3544,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();
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 965368e78e69..0e72506c6d94 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,6 +45,7 @@ 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;
@@ -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;
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 115d164bd761..58828797cfde 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBar.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBar.java
@@ -1160,8 +1160,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),
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/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/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/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/WMShell.java b/packages/SystemUI/src/com/android/systemui/wmshell/WMShell.java
index 49226000e97d..e4ff1b5dcf4f 100644
--- a/packages/SystemUI/src/com/android/systemui/wmshell/WMShell.java
+++ b/packages/SystemUI/src/com/android/systemui/wmshell/WMShell.java
@@ -29,7 +29,11 @@ import com.android.systemui.shared.system.ActivityManagerWrapper;
import com.android.systemui.shared.system.TaskStackChangeListener;
import com.android.systemui.stackdivider.SplitScreen;
import com.android.wm.shell.common.DisplayImeController;
+import com.android.wm.shell.protolog.ShellProtoLogImpl;
+import java.io.FileDescriptor;
+import java.io.PrintWriter;
+import java.util.Arrays;
import java.util.Optional;
import javax.inject.Inject;
@@ -108,4 +112,35 @@ public final class WMShell extends SystemUI {
}
});
}
+
+ @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/WMShellModule.java b/packages/SystemUI/src/com/android/systemui/wmshell/WMShellModule.java
index 7b4547689c8b..6a2ca44bfc17 100644
--- a/packages/SystemUI/src/com/android/systemui/wmshell/WMShellModule.java
+++ b/packages/SystemUI/src/com/android/systemui/wmshell/WMShellModule.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.stackdivider.SplitScreen;
import com.android.systemui.stackdivider.SplitScreenController;
import com.android.wm.shell.ShellTaskOrganizer;
@@ -50,14 +48,6 @@ 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;
- }
-
@SysUISingleton
@Provides
static SplitScreen provideSplitScreen(Context context,
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/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/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/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/stack/NotificationStackScrollLayoutTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayoutTest.java
index fa9ea6b1ea10..62b741c1938a 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
@@ -78,12 +78,10 @@ import com.android.systemui.statusbar.notification.people.PeopleNotificationIden
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;
@@ -122,7 +120,6 @@ public class NotificationStackScrollLayoutTest extends SysuiTestCase {
@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;
@@ -203,9 +200,6 @@ public class NotificationStackScrollLayoutTest extends SysuiTestCase {
mNotificationRoundnessManager,
mock(DynamicPrivacyController.class),
mStatusBarStateController,
- mHeadsUpManager,
- new FalsingManagerFake(),
- mock(NotificationGutsManager.class),
mNotificationSectionsManager,
mock(ForegroundServiceSectionController.class),
mock(ForegroundServiceDismissalFeatureController.class),
@@ -220,7 +214,6 @@ public class NotificationStackScrollLayoutTest extends SysuiTestCase {
mStackScroller = spy(mStackScrollerInternal);
mStackScroller.setShelfController(notificationShelfController);
mStackScroller.setStatusBar(mBar);
- mStackScroller.setScrimController(mock(ScrimController.class));
mStackScroller.setGroupManager(mGroupManager);
mStackScroller.setEmptyShadeView(mEmptyShadeView);
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 4fffd3e0124a..f5d9fa07fa1c 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
@@ -49,6 +49,8 @@ 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.LockscreenGestureLogger;
+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;
@@ -110,6 +112,8 @@ public class NotificationStackScrollerControllerTest extends SysuiTestCase {
private NotificationSwipeHelper mNotificationSwipeHelper;
@Mock
private StatusBar mStatusBar;
+ @Mock
+ private ScrimController mScrimController;
private NotificationStackScrollLayoutController mController;
@@ -138,7 +142,8 @@ public class NotificationStackScrollerControllerTest extends SysuiTestCase {
mNotificationSectionsManager,
mResources,
mNotificationSwipeHelperBuilder,
- mStatusBar
+ mStatusBar,
+ mScrimController
);
when(mNotificationStackScrollLayout.isAttachedToWindow()).thenReturn(true);
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 04e870d4b35c..453baa5e16fd 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
@@ -54,6 +54,7 @@ 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;
@@ -111,8 +112,6 @@ public class NotificationPanelViewTest extends SysuiTestCase {
@Mock
private ViewGroup mBigClockContainer;
@Mock
- private ScrimController mScrimController;
- @Mock
private NotificationIconAreaController mNotificationAreaController;
@Mock
private HeadsUpManagerPhone mHeadsUpManager;
@@ -187,10 +186,16 @@ 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;
+ private FlingAnimationUtils.Builder mFlingAnimationUtilsBuilder;
+
private NotificationPanelViewController mNotificationPanelViewController;
private View.AccessibilityDelegate mAccessibiltyDelegate;
@@ -241,6 +246,10 @@ 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,
@@ -254,14 +263,13 @@ public class NotificationPanelViewTest extends SysuiTestCase {
flingAnimationUtilsBuilder, mStatusBarTouchableRegionManager,
mConversationNotificationManager, mMediaHiearchyManager,
mBiometricUnlockController, mStatusBarKeyguardViewManager,
- () -> mKeyguardClockSwitchController,
mNotificationStackScrollLayoutController,
- mNotificationAreaController);
+ mNotificationAreaController,
+ mKeyguardStatusViewComponentFactory);
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/services/accessibility/java/com/android/server/accessibility/gestures/EventDispatcher.java b/services/accessibility/java/com/android/server/accessibility/gestures/EventDispatcher.java
index 070626be9f80..c70dfcc93e49 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,74 @@ 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.
+ *
+ * @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 = computeEventWithOriginalDown(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 computeEventWithOriginalDown(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(),
+ prototype.getEventTime(),
+ 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/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..ecbece6f1f27 100644
--- a/services/accessibility/java/com/android/server/accessibility/magnification/WindowMagnificationManager.java
+++ b/services/accessibility/java/com/android/server/accessibility/magnification/WindowMagnificationManager.java
@@ -73,7 +73,7 @@ public class WindowMagnificationManager implements
public void onReceive(Context context, Intent intent) {
final int displayId = context.getDisplayId();
removeMagnificationButton(displayId);
- disableWindowMagnification(displayId);
+ disableWindowMagnification(displayId, false);
}
};
@@ -136,10 +136,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 +171,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();
}
mWindowMagnifiers.clear();
}
@@ -187,12 +187,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 the window magnifier is initiated.
*
* @param displayId The logical display id.
* @param scale The target scale, must be >= 1
@@ -209,7 +209,7 @@ public class WindowMagnificationManager implements
}
/**
- * Enables the window magnifier with specified center and scale on the specified display.
+ * Enables window magnification with specified center and scale on the specified display.
* @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,
@@ -217,29 +217,29 @@ public class WindowMagnificationManager implements
* @param centerY The screen-relative Y coordinate around which to center,
* or {@link Float#NaN} to leave unchanged.
*/
- void enableWindowMagnifier(int displayId, float scale, float centerX, float centerY) {
+ void enableWindowMagnification(int displayId, float scale, float centerX, float centerY) {
synchronized (mLock) {
WindowMagnifier magnifier = mWindowMagnifiers.get(displayId);
if (magnifier == null) {
magnifier = createWindowMagnifier(displayId);
}
- magnifier.enable(scale, centerX, centerY);
+ magnifier.enableWindowMagnificationInternal(scale, centerX, centerY);
}
}
/**
- * Disables the window magnifier on the specified display.
+ * Disables window magnification on the specified display.
*
* @param displayId The logical display id.
* @param clear {@true} Clears the state of the window magnifier
*/
- void disableWindowMagnifier(int displayId, boolean clear) {
+ void disableWindowMagnification(int displayId, boolean clear) {
synchronized (mLock) {
WindowMagnifier magnifier = mWindowMagnifiers.get(displayId);
if (magnifier == null) {
return;
}
- magnifier.disable();
+ magnifier.disableWindowMagnificationInternal();
if (clear) {
mWindowMagnifiers.delete(displayId);
}
@@ -264,10 +264,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 +323,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 +331,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) {
@@ -425,7 +425,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,7 +435,7 @@ 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();
@@ -444,12 +445,12 @@ public class WindowMagnificationManager implements
}
@GuardedBy("mLock")
- void enable(float scale, float centerX, float centerY) {
+ void enableWindowMagnificationInternal(float scale, float centerX, float centerY) {
if (mEnabled) {
return;
}
final float normScale = MathUtils.constrain(scale, MIN_SCALE, MAX_SCALE);
- if (mWindowMagnificationManager.enableWindowMagnification(mDisplayId, normScale,
+ if (mWindowMagnificationManager.enableWindowMagnificationInternal(mDisplayId, normScale,
centerX, centerY)) {
mScale = normScale;
mEnabled = true;
@@ -457,8 +458,9 @@ public class WindowMagnificationManager implements
}
@GuardedBy("mLock")
- void disable() {
- if (mEnabled && mWindowMagnificationManager.disableWindowMagnification(mDisplayId)) {
+ void disableWindowMagnificationInternal() {
+ if (mEnabled && mWindowMagnificationManager.disableWindowMagnificationInternal(
+ mDisplayId)) {
mEnabled = false;
}
}
@@ -519,7 +521,7 @@ public class WindowMagnificationManager implements
}
}
- private boolean enableWindowMagnification(int displayId, float scale, float centerX,
+ private boolean enableWindowMagnificationInternal(int displayId, float scale, float centerX,
float centerY) {
return mConnectionWrapper != null && mConnectionWrapper.enableWindowMagnification(
displayId, scale, centerX, centerY);
@@ -529,7 +531,7 @@ public class WindowMagnificationManager implements
return mConnectionWrapper != null && mConnectionWrapper.setScale(displayId, scale);
}
- private boolean disableWindowMagnification(int displayId) {
+ private boolean disableWindowMagnificationInternal(int displayId) {
return mConnectionWrapper != null && mConnectionWrapper.disableWindowMagnification(
displayId);
}
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/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/am/ActivityManagerService.java b/services/core/java/com/android/server/am/ActivityManagerService.java
index 6e1e3d0a9a9a..2d803437beb9 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;
@@ -4946,9 +4947,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);
diff --git a/services/core/java/com/android/server/audio/AudioDeviceBroker.java b/services/core/java/com/android/server/audio/AudioDeviceBroker.java
index 06ef58f8cc61..5447605a36d1 100644
--- a/services/core/java/com/android/server/audio/AudioDeviceBroker.java
+++ b/services/core/java/com/android/server/audio/AudioDeviceBroker.java
@@ -500,8 +500,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) {
@@ -977,7 +977,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);
}
diff --git a/services/core/java/com/android/server/audio/AudioService.java b/services/core/java/com/android/server/audio/AudioService.java
index 673ca1f3da86..3f29eb5636ea 100755
--- a/services/core/java/com/android/server/audio/AudioService.java
+++ b/services/core/java/com/android/server/audio/AudioService.java
@@ -3747,13 +3747,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 +3767,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 +3799,10 @@ public class AudioService extends IAudioService.Stub
public String getPackage() {
return mPackage;
}
+
+ public boolean isPrivileged() {
+ return mIsPrivileged;
+ }
}
/** @see AudioManager#setMode(int) */
@@ -3847,18 +3854,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 +3918,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 +3977,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,
@@ -6519,8 +6528,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;
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/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/location/LocationManagerService.java b/services/core/java/com/android/server/location/LocationManagerService.java
index 71f1833854ce..534533f2fc97 100644
--- a/services/core/java/com/android/server/location/LocationManagerService.java
+++ b/services/core/java/com/android/server/location/LocationManagerService.java
@@ -1133,9 +1133,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 +1164,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..66245a279666 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
@@ -818,6 +820,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 +837,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 +1060,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 +1076,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 +1145,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 +1186,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 +1201,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);
+ }
}
}
@@ -1271,7 +1305,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 +1317,12 @@ class LocationProviderManager extends
GetCurrentLocationListenerRegistration registration =
new GetCurrentLocationListenerRegistration(
request,
- identity,
+ callerIdentity,
new GetCurrentLocationTransport(callback),
permissionLevel);
synchronized (mLock) {
- Location lastLocation = getLastLocation(request, identity, permissionLevel);
+ Location lastLocation = getLastLocation(request, callerIdentity, permissionLevel);
if (lastLocation != null) {
long locationAgeMs = NANOSECONDS.toMillis(
SystemClock.elapsedRealtimeNanos()
@@ -1306,7 +1340,13 @@ class LocationProviderManager extends
}
// if last location isn't good enough then we add a location request
- addRegistration(callback.asBinder(), registration);
+ long identity = Binder.clearCallingIdentity();
+ try {
+ addRegistration(callback.asBinder(), registration);
+ } finally {
+ Binder.restoreCallingIdentity(identity);
+ }
+
CancellationSignal cancellationSignal = CancellationSignal.fromTransport(
cancellationTransport);
if (cancellationSignal != null) {
@@ -1321,48 +1361,73 @@ class LocationProviderManager extends
}
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);
+ }
}
}
@@ -1950,4 +2015,50 @@ class LocationProviderManager extends
}
}
}
+
+ private static class SingleUseCallback extends IRemoteCallback.Stub {
+
+ @Nullable
+ public static IRemoteCallback 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) {
+ 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..5c30fe840073 100644
--- a/services/core/java/com/android/server/location/gnss/GnssLocationProvider.java
+++ b/services/core/java/com/android/server/location/gnss/GnssLocationProvider.java
@@ -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);
}
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/pm/ApkChecksums.java b/services/core/java/com/android/server/pm/ApkChecksums.java
new file mode 100644
index 000000000000..d8745abb4a07
--- /dev/null
+++ b/services/core/java/com/android/server/pm/ApkChecksums.java
@@ -0,0 +1,310 @@
+/*
+ * 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.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.Nullable;
+import android.content.pm.FileChecksum;
+import android.content.pm.PackageManager;
+import android.content.pm.PackageParser;
+import android.util.ArrayMap;
+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.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";
+
+ /**
+ * Fetch or calculate checksums for the specific file.
+ *
+ * @param split split name, null for base
+ * @param 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.
+ */
+ public static List<FileChecksum> getFileChecksums(String split, File file,
+ @PackageManager.FileChecksumKind int optional,
+ @PackageManager.FileChecksumKind int required,
+ @Nullable Certificate[] trustedInstallers) {
+ final String filePath = file.getAbsolutePath();
+ Map<Integer, FileChecksum> checksums = new ArrayMap<>();
+ final int kinds = (optional | required);
+ // System enforced: FSI or v2/v3/v4 signatures.
+ if ((kinds & WHOLE_MERKLE_ROOT_4K_SHA256) != 0) {
+ // Hashes in fs-verity and IncFS are always verified.
+ FileChecksum checksum = extractHashFromFS(split, filePath);
+ if (checksum != null) {
+ checksums.put(checksum.getKind(), checksum);
+ }
+ }
+ if ((kinds & (PARTIAL_MERKLE_ROOT_1M_SHA256 | PARTIAL_MERKLE_ROOT_1M_SHA512)) != 0) {
+ Map<Integer, FileChecksum> v2v3checksums = extractHashFromV2V3Signature(
+ split, filePath, kinds);
+ if (v2v3checksums != null) {
+ checksums.putAll(v2v3checksums);
+ }
+ }
+
+ // TODO(b/160605420): Installer provided.
+ // TODO(b/160605420): Wait for Incremental to be fully loaded.
+
+ // Manually calculating required checksums if not readily available.
+ if ((required & WHOLE_MERKLE_ROOT_4K_SHA256) != 0 && !checksums.containsKey(
+ WHOLE_MERKLE_ROOT_4K_SHA256)) {
+ 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, required, WHOLE_MD5);
+ calculateChecksumIfRequested(checksums, split, file, required, WHOLE_SHA1);
+ calculateChecksumIfRequested(checksums, split, file, required, WHOLE_SHA256);
+ calculateChecksumIfRequested(checksums, split, file, required, WHOLE_SHA512);
+
+ calculatePartialChecksumsIfRequested(checksums, split, file, required);
+
+ return new ArrayList<>(checksums.values());
+ }
+
+ 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) {
+ 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/PackageInstallerSession.java b/services/core/java/com/android/server/pm/PackageInstallerSession.java
index 4f3d3600ae37..ed62362b04fb 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;
@@ -1554,12 +1555,28 @@ 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 detailMessage) {
+ Slog.e(TAG, "Failed to verify session " + sessionId + " [" + detailMessage + "]");
+ // Session is sealed and committed but could not be verified, we need to destroy it.
+ destroyInternal();
+ if (isStaged()) {
+ setStagedSessionFailed(
+ SessionInfo.STAGED_SESSION_VERIFICATION_FAILED, detailMessage);
+ // 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, detailMessage, null);
+ }
+ }
+
private void onStorageUnhealthy() {
final String packageName = getPackageName();
if (TextUtils.isEmpty(packageName)) {
@@ -1680,7 +1697,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 +1709,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 +1880,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 +1959,7 @@ public class PackageInstallerSession extends IPackageInstallerSession.Stub {
if (returnCode == PackageManager.INSTALL_SUCCEEDED) {
onVerificationComplete();
} else {
- destroyInternal();
- dispatchSessionFinished(returnCode, msg, extras);
+ onSessionVerificationFailure(returnCode, msg);
}
}
};
@@ -1946,9 +1981,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;
}
diff --git a/services/core/java/com/android/server/pm/PackageManagerService.java b/services/core/java/com/android/server/pm/PackageManagerService.java
index 5fd73743c3ac..344f9cfdbc96 100644
--- a/services/core/java/com/android/server/pm/PackageManagerService.java
+++ b/services/core/java/com/android/server/pm/PackageManagerService.java
@@ -40,6 +40,7 @@ import static android.content.pm.PackageManager.COMPONENT_ENABLED_STATE_DISABLED
import static android.content.pm.PackageManager.COMPONENT_ENABLED_STATE_DISABLED_UNTIL_USED;
import static android.content.pm.PackageManager.COMPONENT_ENABLED_STATE_DISABLED_USER;
import static android.content.pm.PackageManager.COMPONENT_ENABLED_STATE_ENABLED;
+import static android.content.pm.PackageManager.EXTRA_CHECKSUMS;
import static android.content.pm.PackageManager.EXTRA_VERIFICATION_ID;
import static android.content.pm.PackageManager.FLAG_PERMISSION_GRANTED_BY_DEFAULT;
import static android.content.pm.PackageManager.FLAG_PERMISSION_POLICY_FIXED;
@@ -168,6 +169,7 @@ import android.content.pm.ComponentInfo;
import android.content.pm.DataLoaderType;
import android.content.pm.FallbackCategoryProvider;
import android.content.pm.FeatureInfo;
+import android.content.pm.FileChecksum;
import android.content.pm.IDexModuleRegisterCallback;
import android.content.pm.IPackageChangeObserver;
import android.content.pm.IPackageDataObserver;
@@ -254,6 +256,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 +397,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 +408,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;
@@ -2400,9 +2407,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 +2453,83 @@ 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;
+ final Context context = mContext;
+
+ mInjector.getBackgroundExecutor().execute(() -> {
+ final Intent intent = new Intent();
+ List<FileChecksum> result = 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;
+ try {
+ result.addAll(ApkChecksums.getFileChecksums(split, file, optional, required,
+ trustedCerts));
+ } catch (Throwable e) {
+ Slog.e(TAG, "Checksum calculation error", e);
+ }
+ }
+ intent.putExtra(EXTRA_CHECKSUMS,
+ result.toArray(new FileChecksum[result.size()]));
+
+ try {
+ statusReceiver.sendIntent(context, 1, intent, null, null);
+ } catch (SendIntentException e) {
+ Slog.w(TAG, e);
+ }
+ });
+ }
+
+ 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.
@@ -8964,10 +9051,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);
@@ -9054,9 +9141,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));
@@ -11587,7 +11676,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) {
@@ -13793,7 +13882,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;
@@ -13869,18 +13958,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(
@@ -14572,7 +14649,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;
@@ -15201,6 +15278,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);
@@ -17613,7 +17697,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>
@@ -19446,6 +19530,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;
@@ -19481,9 +19568,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);
@@ -19763,11 +19852,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);
@@ -19947,8 +20038,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);
@@ -20070,7 +20162,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);
}
@@ -20538,6 +20632,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.
@@ -20586,6 +20683,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);
@@ -20645,6 +20743,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);
@@ -21080,15 +21183,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)) {
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/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/UserManagerService.java b/services/core/java/com/android/server/pm/UserManagerService.java
index c1aebd33889c..d137fd05f793 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
@@ -467,6 +444,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 +638,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() {
@@ -801,7 +784,7 @@ public class UserManagerService extends IUserManager.Stub {
|| (excludePreCreated && ui.preCreated)) {
continue;
}
- users.add(userWithNameLU(ui));
+ users.add(userWithName(ui));
}
return users;
}
@@ -870,7 +853,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 +1310,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 +1482,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 +1597,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;
}
@@ -4910,15 +4855,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/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/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/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 b8b20a3e80af..56261c4fce97 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;
@@ -1096,15 +1097,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 +1116,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 +1334,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 +1355,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();
}
@@ -1949,10 +1949,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 +1960,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
@@ -2399,9 +2398,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 +2412,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
@@ -2798,10 +2792,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;
}
@@ -2859,12 +2851,6 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A
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 */);
}
boolean skipDestroy = false;
@@ -2941,10 +2927,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();
@@ -2984,7 +2969,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(
@@ -3185,12 +3170,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),
@@ -4302,7 +4284,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;
}
@@ -4484,16 +4466,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;
}
}
@@ -4804,14 +4810,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());
@@ -5586,9 +5584,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()
@@ -5603,7 +5601,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()) {
@@ -5616,7 +5614,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;
@@ -6145,7 +6143,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;
@@ -6171,7 +6169,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();
@@ -6997,27 +6995,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;
@@ -7033,8 +7031,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;
}
@@ -7054,14 +7052,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) {
@@ -7072,26 +7070,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.
@@ -7108,20 +7103,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);
+ 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));
diff --git a/services/core/java/com/android/server/wm/ActivityStarter.java b/services/core/java/com/android/server/wm/ActivityStarter.java
index 4c93b9ef64de..be7a6aed7489 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);
}
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 2adaa52dfb30..6a8cbfbb5840 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;
@@ -242,6 +242,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 +814,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 +1961,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 +1975,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 {
@@ -2176,7 +2177,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 +2199,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) {
@@ -3013,7 +3014,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 +3076,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);
}
}
@@ -4001,9 +4001,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) {
@@ -4497,8 +4497,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);
}
}
@@ -5183,8 +5183,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 +5262,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);
}
@@ -6563,10 +6561,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 +6570,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..2f7cc69b01a7 100644
--- a/services/core/java/com/android/server/wm/DisplayContent.java
+++ b/services/core/java/com/android/server/wm/DisplayContent.java
@@ -694,7 +694,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 +742,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 +753,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 +780,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 +807,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 +2549,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 +2747,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);
}
@@ -3364,7 +3364,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 +3647,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 +4599,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);
diff --git a/services/core/java/com/android/server/wm/DisplayPolicy.java b/services/core/java/com/android/server/wm/DisplayPolicy.java
index 40fc25b41d9f..1c147c259f07 100644
--- a/services/core/java/com/android/server/wm/DisplayPolicy.java
+++ b/services/core/java/com/android/server/wm/DisplayPolicy.java
@@ -195,13 +195,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 +416,7 @@ public class DisplayPolicy {
private boolean mAllowLockscreenWhenOn;
@VisibleForTesting
- InputConsumer mInputConsumer = null;
+ EventReceiverInputConsumer mInputConsumer;
private PointerLocationView mPointerLocationView;
@@ -462,7 +462,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 +1126,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 +1203,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);
}
};
}
@@ -2075,7 +2075,7 @@ public class DisplayPolicy {
// 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();
+ Rect parentDisplayFrame = attached.getDisplayFrame();
final WindowManager.LayoutParams attachedAttrs = attached.mAttrs;
if ((attachedAttrs.privateFlags & PRIVATE_FLAG_FORCE_DRAW_BAR_BACKGROUNDS) != 0
&& (attachedAttrs.flags & FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS) == 0
@@ -2096,14 +2096,14 @@ public class DisplayPolicy {
// 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);
+ ? attached.getContentFrame() : 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());
+ cf.set(attached.getContentFrame());
if (attached.isVoiceInteraction()) {
cf.intersectUnchecked(displayFrames.mVoiceContent);
} else if (win.isInputMethodTarget() || attached.isInputMethodTarget()) {
@@ -2111,11 +2111,11 @@ public class DisplayPolicy {
}
}
df.set(insetDecors ? parentDisplayFrame : cf);
- vf.set(attached.getVisibleFrameLw());
+ vf.set(attached.getVisibleFrame());
}
// 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);
+ pf.set((fl & FLAG_LAYOUT_IN_SCREEN) == 0 ? attached.getFrame() : df);
}
private void applyStableConstraints(int sysui, int fl, Rect r, DisplayFrames displayFrames) {
@@ -2217,8 +2217,8 @@ public class DisplayPolicy {
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());
+ 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);
@@ -2623,12 +2623,10 @@ 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);
}
}
@@ -2645,8 +2643,8 @@ public class DisplayPolicy {
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 +2656,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 +2665,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 +2727,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 +2913,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
@@ -3398,7 +3395,7 @@ public class DisplayPolicy {
mImmersiveModeConfirmation.confirmCurrentPrompt();
}
- private void disposeInputConsumer(InputConsumer inputConsumer) {
+ private void disposeInputConsumer(EventReceiverInputConsumer inputConsumer) {
if (inputConsumer != null) {
inputConsumer.dispose();
}
@@ -4171,6 +4168,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/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/InputMonitor.java b/services/core/java/com/android/server/wm/InputMonitor.java
index 16c4942ee972..fb511e032c98 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;
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/LockTaskController.java b/services/core/java/com/android/server/wm/LockTaskController.java
index 8ef57f726658..c8d7693c9229 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);
@@ -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/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 0bf3dd9ca4a0..21e30ce0a495 100644
--- a/services/core/java/com/android/server/wm/RootWindowContainer.java
+++ b/services/core/java/com/android/server/wm/RootWindowContainer.java
@@ -1106,14 +1106,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;
@@ -3124,7 +3124,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 +3131,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 +3142,6 @@ class RootWindowContainer extends WindowContainer<DisplayContent>
mUserId = userId;
mOnlyRemoveNoProcess = onlyRemoveNoProcess;
mLastTask = null;
- mHomeActivity = null;
}
boolean process(String packageName, Set<String> filterByClasses,
@@ -3152,14 +3149,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 +3194,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..19bf451cec05 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
@@ -6190,10 +6189,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;
@@ -6374,7 +6369,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,8 +6392,8 @@ 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}
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..c45ccb6e17e3 100644
--- a/services/core/java/com/android/server/wm/WindowManagerService.java
+++ b/services/core/java/com/android/server/wm/WindowManagerService.java
@@ -1848,7 +1848,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 +2069,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 +2389,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 +2419,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 +2883,6 @@ public class WindowManagerService extends IWindowManager.Stub
}
@Override
- public WindowManagerPolicy.WindowState getInputMethodWindowLw() {
- return mRoot.getCurrentInputMethodWindow();
- }
-
- @Override
public void notifyKeyguardTrustedChanged() {
mAtmInternal.notifyKeyguardTrustedChanged();
}
@@ -5481,7 +5476,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 +7351,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();
}
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 bb9cf2e2ac05..c5ebace78261 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;
@@ -1348,9 +1349,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 69d38219284f..9ff33b18cb89 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;
}
@@ -2514,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;
@@ -2748,7 +2754,7 @@ class WindowState extends WindowContainer<WindowState> implements WindowManagerP
mLayoutNeeded = true;
}
- if (isDrawnLw() && mToken.okToAnimate()) {
+ if (isDrawn() && mToken.okToAnimate()) {
mWinAnimator.applyEnterAnimationLocked();
}
}
@@ -2873,8 +2879,8 @@ 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 */);
}
@@ -2923,8 +2929,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;
}
@@ -3158,8 +3169,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();
}
@@ -3339,16 +3350,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() {
@@ -3408,10 +3409,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;
}
@@ -3781,11 +3782,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;
@@ -3889,7 +3890,7 @@ class WindowState extends WindowContainer<WindowState> implements WindowManagerP
// background.
return (getDisplayContent().mDividerControllerLocked.isResizing()
|| mActivityRecord != null && !mActivityRecord.mFrozenBounds.isEmpty()) &&
- !task.inFreeformWindowingMode() && !isGoneForLayoutLw();
+ !task.inFreeformWindowingMode() && !isGoneForLayout();
}
@@ -4305,7 +4306,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) {
@@ -4418,8 +4419,7 @@ class WindowState extends WindowContainer<WindowState> implements WindowManagerP
return null;
}
- @Override
- public int getRotationAnimationHint() {
+ int getRotationAnimationHint() {
if (mActivityRecord != null) {
return mActivityRecord.mRotationAnimationHint;
} else {
@@ -4875,7 +4875,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) {
@@ -4899,9 +4899,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
@@ -4912,7 +4912,7 @@ class WindowState extends WindowContainer<WindowState> implements WindowManagerP
}
results.numInteresting++;
- if (isDrawnLw()) {
+ if (isDrawn()) {
results.numDrawn++;
if (!isAnimating(TRANSITION | PARENTS)) {
results.numVisible++;
@@ -5048,7 +5048,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="
@@ -5620,15 +5620,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) {
@@ -5691,8 +5690,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;
}
@@ -5800,7 +5799,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/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_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..277218d4e543 100644
--- a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
+++ b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
@@ -12052,14 +12052,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);
diff --git a/services/incremental/IncrementalService.cpp b/services/incremental/IncrementalService.cpp
index ba6ae9262aea..9836262ec2b0 100644
--- a/services/incremental/IncrementalService.cpp
+++ b/services/incremental/IncrementalService.cpp
@@ -1706,8 +1706,8 @@ float IncrementalService::getLoadingProgressFromPath(const IncFsMount& ifs,
}
if (totalBlocks == 0) {
- LOG(ERROR) << "getLoadingProgress failed to get total num of blocks";
- return -EINVAL;
+ // No file in the storage or files are empty; regarded as fully loaded
+ return 1;
}
return (float)filledBlocks / (float)totalBlocks;
}
diff --git a/services/incremental/test/IncrementalServiceTest.cpp b/services/incremental/test/IncrementalServiceTest.cpp
index 44cef49a716c..d1000e56e5ee 100644
--- a/services/incremental/test/IncrementalServiceTest.cpp
+++ b/services/incremental/test/IncrementalServiceTest.cpp
@@ -1069,7 +1069,7 @@ TEST_F(IncrementalServiceTest, testMakeDirectories) {
ASSERT_EQ(res, 0);
}
-TEST_F(IncrementalServiceTest, testGetLoadingProgressFailsWithNoFile) {
+TEST_F(IncrementalServiceTest, testGetLoadingProgressSuccessWithNoFile) {
mIncFs->countFilledBlocksSuccess();
mFs->hasNoFile();
@@ -1077,7 +1077,7 @@ TEST_F(IncrementalServiceTest, testGetLoadingProgressFailsWithNoFile) {
int storageId = mIncrementalService->createStorage(tempDir.path, std::move(mDataLoaderParcel),
IncrementalService::CreateOptions::CreateNew,
{}, {}, {});
- ASSERT_EQ(-EINVAL, mIncrementalService->getLoadingProgress(storageId));
+ ASSERT_EQ(1, mIncrementalService->getLoadingProgress(storageId));
}
TEST_F(IncrementalServiceTest, testGetLoadingProgressFailsWithFailedRanges) {
@@ -1092,7 +1092,7 @@ TEST_F(IncrementalServiceTest, testGetLoadingProgressFailsWithFailedRanges) {
ASSERT_EQ(-1, mIncrementalService->getLoadingProgress(storageId));
}
-TEST_F(IncrementalServiceTest, testGetLoadingProgressFailsWithEmptyRanges) {
+TEST_F(IncrementalServiceTest, testGetLoadingProgressSuccessWithEmptyRanges) {
mIncFs->countFilledBlocksEmpty();
mFs->hasFiles();
@@ -1101,7 +1101,7 @@ TEST_F(IncrementalServiceTest, testGetLoadingProgressFailsWithEmptyRanges) {
IncrementalService::CreateOptions::CreateNew,
{}, {}, {});
EXPECT_CALL(*mIncFs, countFilledBlocks(_, _)).Times(3);
- ASSERT_EQ(-EINVAL, mIncrementalService->getLoadingProgress(storageId));
+ ASSERT_EQ(1, mIncrementalService->getLoadingProgress(storageId));
}
TEST_F(IncrementalServiceTest, testGetLoadingProgressSuccess) {
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..d6894cf2a4e8 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;
@@ -484,7 +484,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 +622,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/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..e067b7eca755 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,10 @@ 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;
private MockContentResolver mResolver;
private WindowMagnificationManager mWindowMagnificationManager;
@@ -84,7 +86,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;
@@ -161,7 +163,7 @@ public class WindowMagnificationManagerTest {
public void enable_TestDisplay_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);
@@ -170,9 +172,9 @@ public class WindowMagnificationManagerTest {
@Test
public void disable_testDisplay_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);
}
@@ -183,7 +185,7 @@ public class WindowMagnificationManagerTest {
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 +200,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 +213,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 +223,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);
@@ -232,9 +234,9 @@ public class WindowMagnificationManagerTest {
@Test
public void moveWindowMagnifier() 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);
}
@@ -254,7 +256,7 @@ public class WindowMagnificationManagerTest {
@Test
public void pointersInWindow_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 +270,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,7 +282,7 @@ 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));
@@ -306,21 +308,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);
+ assertFalse(mWindowMagnificationManager.isWindowMagnifierEnabled(TEST_DISPLAY));
}
private MotionEvent generatePointersDownEvent(PointF[] pointersLocation) {
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..3f324a279270 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,82 @@ public class HdmiCecLocalDevicePlaybackTest {
}
@Test
+ public void sendVolumeKeyEvent_toTv_activeSource() {
+ mHdmiControlService.setHdmiCecVolumeControlEnabled(true);
+ mHdmiControlService.setSystemAudioActivated(false);
+ mHdmiControlService.setActiveSource(mPlaybackLogicalAddress, mPlaybackPhysicalAddress);
+
+ 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);
+
+ 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);
+
+ 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);
+
+ 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/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/wmtests/src/com/android/server/wm/ActivityRecordTests.java b/services/tests/wmtests/src/com/android/server/wm/ActivityRecordTests.java
index 6358c0dba471..59f0a7987bda 100644
--- a/services/tests/wmtests/src/com/android/server/wm/ActivityRecordTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/ActivityRecordTests.java
@@ -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/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..2d834ac57f51 100644
--- a/services/tests/wmtests/src/com/android/server/wm/DisplayPolicyLayoutTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/DisplayPolicyLayoutTests.java
@@ -114,7 +114,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 +179,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 +207,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 +232,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 +241,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 +250,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 +259,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 +274,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 +290,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 +306,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 +322,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 +342,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,11 +362,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, 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);
}
@@ -381,11 +381,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 +402,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 +422,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 +442,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 +462,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
@@ -484,10 +484,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
@@ -506,10 +506,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
@@ -529,10 +529,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 +549,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 +570,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
@@ -594,8 +594,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 +615,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
@@ -636,8 +636,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 +655,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 +676,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 +698,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 +719,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 +740,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 +904,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/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/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/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..9603d28c286b 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);
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/tests/StagedInstallTest/Android.bp b/tests/StagedInstallTest/Android.bp
index 229a9aa65166..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",
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..bcb5c992f162 100644
--- a/tests/net/java/com/android/server/ConnectivityServiceTest.java
+++ b/tests/net/java/com/android/server/ConnectivityServiceTest.java
@@ -1199,7 +1199,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),
}));
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();