summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--Android.bp1
-rw-r--r--api/current.txt11
-rw-r--r--api/system-current.txt18
-rw-r--r--api/test-current.txt15
-rw-r--r--cmds/input/src/com/android/commands/input/Input.java433
-rw-r--r--cmds/media/src/com/android/commands/media/Media.java4
-rw-r--r--config/hiddenapi-greylist.txt86
-rw-r--r--core/java/android/app/ActivityView.java3
-rw-r--r--core/java/android/app/IWallpaperManager.aidl11
-rw-r--r--core/java/android/app/WallpaperManager.java20
-rw-r--r--core/java/android/app/usage/IUsageStatsManager.aidl4
-rw-r--r--core/java/android/app/usage/UsageStatsManager.java118
-rw-r--r--core/java/android/content/Intent.java22
-rw-r--r--core/java/android/net/ConnectivityManager.java82
-rw-r--r--core/java/android/net/dhcp/DhcpServingParamsParcel.aidl30
-rw-r--r--core/java/android/os/GraphicsEnvironment.java26
-rw-r--r--core/java/android/os/Trace.java2
-rw-r--r--core/java/android/os/UpdateEngine.java1
-rw-r--r--core/java/android/permission/IPermissionController.aidl3
-rw-r--r--core/java/android/permission/PermissionControllerManager.java179
-rw-r--r--core/java/android/permission/PermissionControllerService.java78
-rw-r--r--core/java/android/permission/TEST_MAPPING12
-rw-r--r--core/java/android/provider/Settings.java22
-rw-r--r--core/java/android/service/autofill/augmented/AugmentedAutofillService.java11
-rw-r--r--core/java/android/service/contentcapture/ContentCaptureEventsRequest.java2
-rw-r--r--core/java/android/service/contentcapture/ContentCaptureService.java27
-rw-r--r--core/java/android/service/wallpaper/IWallpaperConnection.aidl2
-rw-r--r--core/java/android/service/wallpaper/WallpaperService.java13
-rw-r--r--core/java/android/view/IWindowSession.aidl2
-rw-r--r--core/java/android/view/SurfaceControl.java46
-rw-r--r--core/java/android/view/SurfaceSession.java10
-rw-r--r--core/java/android/view/SurfaceView.java3
-rw-r--r--core/java/android/view/View.java14
-rw-r--r--core/java/android/view/ViewRootImpl.java17
-rw-r--r--core/java/android/view/autofill/AutofillManager.java147
-rw-r--r--core/java/android/view/contentcapture/ChildContentCaptureSession.java29
-rw-r--r--core/java/android/view/contentcapture/ContentCaptureEvent.java4
-rw-r--r--core/java/android/view/contentcapture/ContentCaptureManager.java3
-rw-r--r--core/java/android/view/contentcapture/ContentCaptureSession.java99
-rw-r--r--core/java/android/view/contentcapture/MainContentCaptureSession.java30
-rw-r--r--core/java/android/widget/Magnifier.java23
-rw-r--r--core/java/com/android/internal/util/SyncResultReceiver.java145
-rw-r--r--core/jni/android_view_SurfaceControl.cpp20
-rw-r--r--core/jni/android_view_SurfaceSession.cpp9
-rw-r--r--core/proto/android/providers/settings/global.proto4
-rw-r--r--core/res/res/drawable/ic_account_circle.xml24
-rw-r--r--core/res/res/drawable/ic_battery.xml25
-rw-r--r--core/res/res/drawable/ic_corp_badge.xml23
-rw-r--r--core/res/res/values/attrs.xml7
-rw-r--r--core/res/res/values/config.xml2
-rw-r--r--core/res/res/values/strings.xml9
-rw-r--r--core/res/res/values/symbols.xml5
-rw-r--r--core/res/res/values/themes_device_defaults.xml12
-rw-r--r--core/tests/coretests/src/android/provider/SettingsBackupTest.java2
-rw-r--r--core/tests/coretests/src/android/view/textclassifier/TextClassifierTest.java3
-rw-r--r--core/tests/hdmitests/Android.mk2
-rw-r--r--core/tests/hdmitests/AndroidManifest.xml2
-rw-r--r--core/tests/hdmitests/AndroidTest.xml2
-rw-r--r--core/tests/hdmitests/src/android/hardware/hdmi/HdmiAudioSystemClientTest.java7
-rw-r--r--graphics/java/android/graphics/ColorSpace.java4
-rw-r--r--libs/hwui/WebViewFunctorManager.cpp5
-rw-r--r--libs/hwui/renderthread/CacheManager.cpp29
-rw-r--r--libs/hwui/renderthread/RenderThread.h1
-rw-r--r--libs/hwui/service/GraphicsStatsService.cpp2
-rw-r--r--libs/hwui/tests/common/scenes/BitmapFillrate.cpp4
-rw-r--r--libs/hwui/tests/common/scenes/BitmapShaders.cpp2
-rw-r--r--libs/hwui/tests/common/scenes/TvApp.cpp8
-rw-r--r--libs/hwui/tests/unit/SkiaRenderPropertiesTests.cpp2
-rw-r--r--libs/hwui/tests/unit/ThreadBaseTests.cpp4
-rw-r--r--media/java/android/media/MediaRecorder.java3
-rw-r--r--media/java/android/media/session/ISessionController.aidl4
-rw-r--r--media/java/android/media/session/ISessionControllerCallback.aidl4
-rw-r--r--media/java/android/media/session/MediaController.aidl (renamed from media/java/android/media/session/ParcelableVolumeInfo.aidl)2
-rw-r--r--media/java/android/media/session/MediaController.java94
-rw-r--r--media/java/android/media/session/MediaSession.java3
-rw-r--r--media/java/android/media/session/ParcelableVolumeInfo.java80
-rw-r--r--media/jni/Android.bp3
-rw-r--r--packages/CarSystemUI/src/com/android/systemui/car/CarNotificationInterruptionStateProvider.java4
-rw-r--r--packages/SettingsLib/BarChartPreference/src/com/android/settingslib/widget/BarChartPreference.java2
-rw-r--r--packages/SystemUI/src/com/android/keyguard/KeyguardClockSwitch.java27
-rw-r--r--packages/SystemUI/src/com/android/systemui/Dependency.java2
-rw-r--r--packages/SystemUI/src/com/android/systemui/ForegroundServiceNotificationListener.java8
-rw-r--r--packages/SystemUI/src/com/android/systemui/SystemUIFactory.java2
-rw-r--r--packages/SystemUI/src/com/android/systemui/bubbles/BubbleController.java12
-rw-r--r--packages/SystemUI/src/com/android/systemui/bubbles/BubbleStackView.java4
-rw-r--r--packages/SystemUI/src/com/android/systemui/bubbles/BubbleView.java10
-rw-r--r--packages/SystemUI/src/com/android/systemui/keyguard/KeyguardSliceProvider.java53
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/AlertingNotificationManager.java25
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/AmbientPulseManager.java8
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/HeadsUpStatusBarView.java8
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/NotificationLifetimeExtender.java6
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/NotificationLockscreenUserManager.java4
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/NotificationLockscreenUserManagerImpl.java4
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/NotificationMediaManager.java14
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/NotificationRemoteInputManager.java34
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/NotificationUiAdjustment.java4
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/NotificationViewHierarchyManager.java16
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/RemoteInputController.java52
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/SmartReplyController.java12
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationAlertingManager.java13
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationData.java1072
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationEntryListener.java13
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationEntryManager.java42
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationFilter.java4
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationInterruptionStateProvider.java13
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationRowBinder.java11
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/notification/VisibilityLocationProvider.java4
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/notification/VisualStabilityManager.java7
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/NotificationData.java424
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/NotificationEntry.java701
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/notification/logging/NotificationLogger.java8
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ExpandableNotificationRow.java14
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationContentView.java16
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationGutsManager.java8
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationInflater.java10
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/notification/row/RowInflaterTask.java6
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/AmbientState.java4
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationListContainer.java6
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationRoundnessManager.java6
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayout.java28
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/phone/HeadsUpAppearanceController.java12
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/phone/HeadsUpManagerPhone.java22
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/phone/HeadsUpTouchHelper.java4
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardEnvironmentImpl.java2
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationGroupAlertTransferHelper.java46
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationGroupManager.java56
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationIconAreaController.java8
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelView.java8
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBar.java21
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarNotificationActivityStarter.java10
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarNotificationPresenter.java18
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/policy/HeadsUpManager.java18
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/policy/OnHeadsUpChangedListener.java9
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/policy/RemoteInputView.java6
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/policy/SmartReplyView.java10
-rw-r--r--packages/SystemUI/tests/src/com/android/keyguard/KeyguardClockSwitchTest.java30
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/ForegroundServiceControllerTest.java8
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/bubbles/BubbleControllerTest.java2
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/keyguard/KeyguardSliceProviderTest.java36
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/statusbar/AlertingNotificationManagerTest.java8
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/statusbar/NotificationListenerTest.java5
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/statusbar/NotificationLockscreenUserManagerTest.java3
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/statusbar/NotificationRemoteInputManagerTest.java8
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/statusbar/NotificationTestHelper.java4
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/statusbar/NotificationViewHierarchyManagerTest.java32
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/statusbar/SmartReplyControllerTest.java6
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/NotificationEntryManagerTest.java15
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/NotificationFilterTest.java6
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/VisualStabilityManagerTest.java5
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/NotificationDataTest.java (renamed from packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/NotificationDataTest.java)22
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/logging/NotificationLoggerTest.java7
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/NotificationContentViewTest.java6
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/NotificationGutsManagerTest.java12
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/NotificationInflaterTest.java8
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/NotificationMenuRowTest.java4
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayoutTest.java18
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/HeadsUpManagerPhoneTest.java16
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/NotificationGroupAlertTransferHelperTest.java47
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/NotificationGroupManagerTest.java30
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/NotificationGroupTestHelper.java14
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarNotificationPresenterTest.java6
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarTest.java14
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/SmartReplyViewTest.java6
-rw-r--r--packages/services/PacProcessor/jni/com_android_pacprocessor_PacNative.cpp22
-rw-r--r--proto/src/metrics_constants/metrics_constants.proto2
-rw-r--r--services/Android.bp1
-rw-r--r--services/autofill/java/com/android/server/autofill/AutofillManagerService.java7
-rw-r--r--services/autofill/java/com/android/server/autofill/AutofillManagerServiceImpl.java7
-rw-r--r--services/backup/java/com/android/server/backup/BackupManagerService.java9
-rw-r--r--services/backup/java/com/android/server/backup/UserBackupManagerService.java5
-rw-r--r--services/backup/java/com/android/server/backup/internal/SetupObserver.java2
-rw-r--r--services/contentcapture/java/com/android/server/contentcapture/ContentCapturePerUserService.java13
-rw-r--r--services/core/java/com/android/server/LocationManagerService.java1659
-rw-r--r--services/core/java/com/android/server/am/ActivityManagerService.java17
-rw-r--r--services/core/java/com/android/server/connectivity/NetworkMonitor.java79
-rw-r--r--services/core/java/com/android/server/connectivity/tethering/TetheringDependencies.java21
-rw-r--r--services/core/java/com/android/server/hdmi/Constants.java13
-rw-r--r--services/core/java/com/android/server/hdmi/HdmiCecLocalDeviceAudioSystem.java38
-rw-r--r--services/core/java/com/android/server/hdmi/HdmiControlService.java5
-rw-r--r--services/core/java/com/android/server/inputmethod/InputMethodManagerService.java19
-rw-r--r--services/core/java/com/android/server/media/MediaSessionRecord.java13
-rw-r--r--services/core/java/com/android/server/notification/ManagedServices.java17
-rw-r--r--services/core/java/com/android/server/notification/NotificationManagerService.java15
-rw-r--r--services/core/java/com/android/server/notification/SnoozeHelper.java26
-rw-r--r--services/core/java/com/android/server/notification/ZenModeHelper.java3
-rw-r--r--services/core/java/com/android/server/pm/PackageInstallerSession.java3
-rw-r--r--services/core/java/com/android/server/pm/PackageManagerService.java7
-rw-r--r--services/core/java/com/android/server/pm/PackageManagerServiceUtils.java10
-rw-r--r--services/core/java/com/android/server/power/Notifier.java12
-rw-r--r--services/core/java/com/android/server/power/batterysaver/BatterySaverStateMachine.java54
-rw-r--r--services/core/java/com/android/server/wallpaper/WallpaperManagerService.java178
-rw-r--r--services/core/java/com/android/server/wm/AccessibilityController.java155
-rw-r--r--services/core/java/com/android/server/wm/ActivityRecord.java17
-rw-r--r--services/core/java/com/android/server/wm/AppWindowToken.java3
-rw-r--r--services/core/java/com/android/server/wm/ConfigurationContainer.java9
-rw-r--r--services/core/java/com/android/server/wm/DisplayContent.java6
-rw-r--r--services/core/java/com/android/server/wm/Letterbox.java17
-rw-r--r--services/core/java/com/android/server/wm/Session.java4
-rw-r--r--services/core/java/com/android/server/wm/TaskRecord.java133
-rw-r--r--services/core/java/com/android/server/wm/TaskSnapshotSurface.java17
-rw-r--r--services/core/java/com/android/server/wm/WindowManagerService.java20
-rw-r--r--services/core/java/com/android/server/wm/WindowSurfaceController.java4
-rw-r--r--services/devicepolicy/java/com/android/server/devicepolicy/AbUpdateInstaller.java3
-rw-r--r--services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java26
-rw-r--r--services/java/com/android/server/SystemServer.java6
-rw-r--r--services/net/java/android/net/dhcp/DhcpLease.java12
-rw-r--r--services/net/java/android/net/dhcp/DhcpLeaseRepository.java8
-rw-r--r--services/net/java/android/net/dhcp/DhcpPacketListener.java24
-rw-r--r--services/net/java/android/net/dhcp/DhcpServer.java51
-rw-r--r--services/net/java/android/net/dhcp/DhcpServingParams.java108
-rw-r--r--services/net/java/android/net/dhcp/DhcpServingParamsParcelExt.java172
-rw-r--r--services/net/java/android/net/util/SharedLog.java51
-rw-r--r--services/robotests/backup/src/com/android/server/backup/BackupManagerServiceTest.java5
-rw-r--r--services/robotests/backup/src/com/android/server/backup/internal/SetupObserverTest.java2
-rw-r--r--services/startop/Android.bp24
-rw-r--r--services/tests/servicestests/src/com/android/server/display/DisplayManagerServiceTest.java2
-rw-r--r--services/tests/servicestests/src/com/android/server/hdmi/FakeNativeWrapper.java16
-rw-r--r--services/tests/servicestests/src/com/android/server/hdmi/HdmiCecLocalDeviceAudioSystemTest.java192
-rw-r--r--services/tests/servicestests/src/com/android/server/usage/AppTimeLimitControllerTests.java42
-rw-r--r--services/tests/uiservicestests/src/com/android/server/notification/ManagedServicesTest.java26
-rw-r--r--services/tests/uiservicestests/src/com/android/server/notification/SnoozeHelperTest.java53
-rw-r--r--services/tests/wmtests/src/com/android/server/wm/ActivityTestsBase.java32
-rw-r--r--services/tests/wmtests/src/com/android/server/wm/DisplayRotationTests.java17
-rw-r--r--services/tests/wmtests/src/com/android/server/wm/LockTaskControllerTest.java45
-rw-r--r--services/tests/wmtests/src/com/android/server/wm/RemoteAnimationControllerTest.java2
-rw-r--r--services/tests/wmtests/src/com/android/server/wm/ScreenDecorWindowTests.java7
-rw-r--r--services/tests/wmtests/src/com/android/server/wm/TaskRecordTests.java116
-rw-r--r--services/tests/wmtests/src/com/android/server/wm/TaskSnapshotSurfaceTest.java3
-rw-r--r--services/tests/wmtests/src/com/android/server/wm/WindowManagerServiceRule.java223
-rw-r--r--services/tests/wmtests/src/com/android/server/wm/WindowManagerServiceRuleTest.java44
-rw-r--r--services/tests/wmtests/src/com/android/server/wm/WindowTestsBase.java18
-rw-r--r--services/tests/wmtests/src/com/android/server/wm/WmServiceUtils.java204
-rw-r--r--services/usage/java/com/android/server/usage/AppTimeLimitController.java111
-rw-r--r--services/usage/java/com/android/server/usage/UsageStatsService.java148
-rw-r--r--startop/iorap/Android.bp4
-rw-r--r--startop/iorap/src/com/google/android/startop/iorap/AppLaunchEvent.java368
-rw-r--r--startop/iorap/src/com/google/android/startop/iorap/IorapForwardingService.java216
-rw-r--r--startop/iorap/src/com/google/android/startop/iorap/RequestId.java2
-rw-r--r--startop/iorap/tests/Android.bp11
-rw-r--r--startop/view_compiler/Android.bp18
-rw-r--r--startop/view_compiler/apk_layout_compiler.cc159
-rw-r--r--startop/view_compiler/apk_layout_compiler.h31
-rw-r--r--startop/view_compiler/main.cc24
-rw-r--r--telecomm/java/android/telecom/CallRedirectionService.java76
-rw-r--r--telecomm/java/com/android/internal/telecom/ICallRedirectionAdapter.aidl3
-rw-r--r--telecomm/java/com/android/internal/telecom/ICallRedirectionService.aidl2
-rw-r--r--telephony/java/android/telephony/ims/RcsParticipant.java102
-rw-r--r--telephony/java/android/telephony/ims/aidl/IRcs.aidl9
-rw-r--r--tests/RcsTests/src/com/android/tests/ims/RcsParticipantTest.java46
-rw-r--r--tests/UsageReportingTest/Android.mk17
-rw-r--r--tests/UsageReportingTest/AndroidManifest.xml22
-rw-r--r--tests/UsageReportingTest/res/layout/row_item.xml36
-rw-r--r--tests/UsageReportingTest/res/menu/main.xml28
-rw-r--r--tests/UsageReportingTest/res/values/colors.xml19
-rw-r--r--tests/UsageReportingTest/res/values/strings.xml47
-rw-r--r--tests/UsageReportingTest/res/values/styles.xml31
-rw-r--r--tests/UsageReportingTest/src/com/android/tests/usagereporter/UsageReporterActivity.java320
-rw-r--r--tests/UsageStatsTest/src/com/android/tests/usagestats/UsageStatsActivity.java2
-rw-r--r--tests/WindowManagerStressTest/src/test/windowmanagerstresstest/MainActivity.java3
-rw-r--r--tests/net/java/android/net/dhcp/DhcpLeaseRepositoryTest.java4
-rw-r--r--tests/net/java/android/net/dhcp/DhcpServingParamsParcelExtTest.java113
-rw-r--r--tests/net/java/android/net/dhcp/DhcpServingParamsTest.java42
-rw-r--r--tests/net/java/android/net/ip/IpServerTest.java24
-rw-r--r--wifi/java/android/net/wifi/IWifiManager.aidl2
-rw-r--r--wifi/java/android/net/wifi/WifiInfo.java18
-rw-r--r--wifi/java/android/net/wifi/WifiManager.java5
-rw-r--r--wifi/java/com/android/server/wifi/AbstractWifiService.java27
-rw-r--r--wifi/tests/src/android/net/wifi/WifiInfoTest.java2
268 files changed, 7598 insertions, 4239 deletions
diff --git a/Android.bp b/Android.bp
index eb9cbbb136f9..93c94e36ed36 100644
--- a/Android.bp
+++ b/Android.bp
@@ -872,6 +872,7 @@ aidl_interface {
local_include_dir: "core/java",
srcs: [
"core/java/android/net/INetworkStackConnector.aidl",
+ "core/java/android/net/dhcp/DhcpServingParamsParcel.aidl",
],
api_dir: "aidl/networkstack",
}
diff --git a/api/current.txt b/api/current.txt
index b11e6cdaa635..16652bfe97f5 100644
--- a/api/current.txt
+++ b/api/current.txt
@@ -10200,6 +10200,7 @@ package android.content {
field public static final java.lang.String ACTION_PACKAGE_RESTARTED = "android.intent.action.PACKAGE_RESTARTED";
field public static final java.lang.String ACTION_PACKAGE_VERIFIED = "android.intent.action.PACKAGE_VERIFIED";
field public static final java.lang.String ACTION_PASTE = "android.intent.action.PASTE";
+ field public static final java.lang.String ACTION_PERMISSION_USAGE_DETAILS = "android.intent.action.PERMISSION_USAGE_DETAILS";
field public static final java.lang.String ACTION_PICK = "android.intent.action.PICK";
field public static final java.lang.String ACTION_PICK_ACTIVITY = "android.intent.action.PICK_ACTIVITY";
field public static final java.lang.String ACTION_POWER_CONNECTED = "android.intent.action.ACTION_POWER_CONNECTED";
@@ -10324,6 +10325,7 @@ package android.content {
field public static final java.lang.String EXTRA_NOT_UNKNOWN_SOURCE = "android.intent.extra.NOT_UNKNOWN_SOURCE";
field public static final java.lang.String EXTRA_ORIGINATING_URI = "android.intent.extra.ORIGINATING_URI";
field public static final java.lang.String EXTRA_PACKAGE_NAME = "android.intent.extra.PACKAGE_NAME";
+ field public static final java.lang.String EXTRA_PERMISSION_USAGE_PERMISSIONS = "android.intent.extra.PERMISSION_USAGE_PERMISSIONS";
field public static final java.lang.String EXTRA_PHONE_NUMBER = "android.intent.extra.PHONE_NUMBER";
field public static final java.lang.String EXTRA_PROCESS_TEXT = "android.intent.extra.PROCESS_TEXT";
field public static final java.lang.String EXTRA_PROCESS_TEXT_READONLY = "android.intent.extra.PROCESS_TEXT_READONLY";
@@ -27146,12 +27148,15 @@ package android.media.session {
method public void onSessionEvent(java.lang.String, android.os.Bundle);
}
- public static final class MediaController.PlaybackInfo {
+ public static final class MediaController.PlaybackInfo implements android.os.Parcelable {
+ method public int describeContents();
method public android.media.AudioAttributes getAudioAttributes();
method public int getCurrentVolume();
method public int getMaxVolume();
method public int getPlaybackType();
method public int getVolumeControl();
+ method public void writeToParcel(android.os.Parcel, int);
+ field public static final android.os.Parcelable.Creator<android.media.session.MediaController.PlaybackInfo> CREATOR;
field public static final int PLAYBACK_TYPE_LOCAL = 1; // 0x1
field public static final int PLAYBACK_TYPE_REMOTE = 2; // 0x2
}
@@ -42759,10 +42764,10 @@ package android.telecom {
ctor public CallRedirectionService();
method public final void cancelCall();
method public final android.os.IBinder onBind(android.content.Intent);
- method public abstract void onPlaceCall(android.net.Uri, android.telecom.PhoneAccountHandle);
+ method public abstract void onPlaceCall(android.net.Uri, android.telecom.PhoneAccountHandle, boolean);
method public final boolean onUnbind(android.content.Intent);
method public final void placeCallUnmodified();
- method public final void redirectCall(android.net.Uri, android.telecom.PhoneAccountHandle);
+ method public final void redirectCall(android.net.Uri, android.telecom.PhoneAccountHandle, boolean);
field public static final java.lang.String SERVICE_INTERFACE = "android.telecom.CallRedirectionService";
}
diff --git a/api/system-current.txt b/api/system-current.txt
index e99ac06c258e..9ce25f52957d 100644
--- a/api/system-current.txt
+++ b/api/system-current.txt
@@ -927,6 +927,9 @@ package android.app.usage {
method public java.util.Map<java.lang.String, java.lang.Integer> getAppStandbyBuckets();
method public void registerAppUsageObserver(int, java.lang.String[], long, java.util.concurrent.TimeUnit, android.app.PendingIntent);
method public void registerUsageSessionObserver(int, java.lang.String[], long, java.util.concurrent.TimeUnit, long, java.util.concurrent.TimeUnit, android.app.PendingIntent, android.app.PendingIntent);
+ method public void reportUsageStart(android.app.Activity, java.lang.String);
+ method public void reportUsageStart(android.app.Activity, java.lang.String, long);
+ method public void reportUsageStop(android.app.Activity, java.lang.String);
method public void setAppStandbyBucket(java.lang.String, int);
method public void setAppStandbyBuckets(java.util.Map<java.lang.String, java.lang.Integer>);
method public void unregisterAppUsageObserver(int);
@@ -4491,6 +4494,7 @@ package android.os {
field public static final int PAYLOAD_HASH_MISMATCH_ERROR = 10; // 0xa
field public static final int PAYLOAD_MISMATCHED_TYPE_ERROR = 6; // 0x6
field public static final int PAYLOAD_SIZE_MISMATCH_ERROR = 11; // 0xb
+ field public static final int PAYLOAD_TIMESTAMP_ERROR = 51; // 0x33
field public static final int POST_INSTALL_RUNNER_ERROR = 5; // 0x5
field public static final int SUCCESS = 0; // 0x0
field public static final int UPDATED_BUT_NOT_ACTIVE = 52; // 0x34
@@ -4595,6 +4599,17 @@ package android.os.storage {
package android.permission {
+ public final class PermissionControllerManager {
+ method public void revokeRuntimePermissions(java.util.Map<java.lang.String, java.util.List<java.lang.String>>, boolean, int, java.util.concurrent.Executor, android.permission.PermissionControllerManager.OnRevokeRuntimePermissionsCallback);
+ field public static final int REASON_INSTALLER_POLICY_VIOLATION = 2; // 0x2
+ field public static final int REASON_MALWARE = 1; // 0x1
+ }
+
+ public static abstract class PermissionControllerManager.OnRevokeRuntimePermissionsCallback {
+ ctor public PermissionControllerManager.OnRevokeRuntimePermissionsCallback();
+ method public abstract void onRevokeRuntimePermissions(java.util.Map<java.lang.String, java.util.List<java.lang.String>>);
+ }
+
public abstract class PermissionControllerService extends android.app.Service {
ctor public PermissionControllerService();
method public final void attachBaseContext(android.content.Context);
@@ -4602,6 +4617,7 @@ package android.permission {
method public abstract int onCountPermissionApps(java.util.List<java.lang.String>, boolean, boolean);
method public abstract java.util.List<android.permission.RuntimePermissionPresentationInfo> onGetAppPermissions(java.lang.String);
method public abstract void onRevokeRuntimePermission(java.lang.String, java.lang.String);
+ method public abstract java.util.Map<java.lang.String, java.util.List<java.lang.String>> onRevokeRuntimePermissions(java.util.Map<java.lang.String, java.util.List<java.lang.String>>, boolean, int, java.lang.String);
field public static final java.lang.String SERVICE_INTERFACE = "android.permission.PermissionControllerService";
}
@@ -5127,6 +5143,8 @@ package android.service.autofill.augmented {
public abstract class AugmentedAutofillService extends android.app.Service {
ctor public AugmentedAutofillService();
+ method protected final void dump(java.io.FileDescriptor, java.io.PrintWriter, java.lang.String[]);
+ method protected void dump(java.io.PrintWriter, java.lang.String[]);
method public void onFillRequest(android.service.autofill.augmented.FillRequest, android.os.CancellationSignal, android.service.autofill.augmented.FillController, android.service.autofill.augmented.FillCallback);
field public static final java.lang.String SERVICE_INTERFACE = "android.service.autofill.augmented.AugmentedAutofillService";
}
diff --git a/api/test-current.txt b/api/test-current.txt
index 1401cbb4211e..de643501d16c 100644
--- a/api/test-current.txt
+++ b/api/test-current.txt
@@ -985,6 +985,21 @@ package android.os.strictmode {
}
+package android.permission {
+
+ public final class PermissionControllerManager {
+ method public void revokeRuntimePermissions(java.util.Map<java.lang.String, java.util.List<java.lang.String>>, boolean, int, java.util.concurrent.Executor, android.permission.PermissionControllerManager.OnRevokeRuntimePermissionsCallback);
+ field public static final int REASON_INSTALLER_POLICY_VIOLATION = 2; // 0x2
+ field public static final int REASON_MALWARE = 1; // 0x1
+ }
+
+ public static abstract class PermissionControllerManager.OnRevokeRuntimePermissionsCallback {
+ ctor public PermissionControllerManager.OnRevokeRuntimePermissionsCallback();
+ method public abstract void onRevokeRuntimePermissions(java.util.Map<java.lang.String, java.util.List<java.lang.String>>);
+ }
+
+}
+
package android.print {
public final class PrintJobInfo implements android.os.Parcelable {
diff --git a/cmds/input/src/com/android/commands/input/Input.java b/cmds/input/src/com/android/commands/input/Input.java
index 74edffb4738d..b905e94cd96f 100644
--- a/cmds/input/src/com/android/commands/input/Input.java
+++ b/cmds/input/src/com/android/commands/input/Input.java
@@ -16,15 +16,20 @@
package com.android.commands.input;
+import static android.view.Display.DEFAULT_DISPLAY;
+import static android.view.Display.INVALID_DISPLAY;
+
import android.hardware.input.InputManager;
import android.os.SystemClock;
-import android.util.Log;
import android.view.InputDevice;
import android.view.KeyCharacterMap;
import android.view.KeyEvent;
import android.view.MotionEvent;
import android.view.ViewConfiguration;
+import com.android.internal.os.BaseCommand;
+
+import java.io.PrintStream;
import java.util.HashMap;
import java.util.Map;
@@ -33,9 +38,11 @@ import java.util.Map;
* desired character output.
*/
-public class Input {
+public class Input extends BaseCommand {
private static final String TAG = "Input";
private static final String INVALID_ARGUMENTS = "Error: Invalid arguments for command: ";
+ private static final String INVALID_DISPLAY_ARGUMENTS =
+ "Error: Invalid arguments for display ID.";
private static final Map<String, Integer> SOURCES = new HashMap<String, Integer>() {{
put("keyboard", InputDevice.SOURCE_KEYBOARD);
@@ -50,6 +57,7 @@ public class Input {
put("joystick", InputDevice.SOURCE_JOYSTICK);
}};
+ private static final Map<String, InputCmd> COMMANDS = new HashMap<String, InputCmd>();
/**
* Command-line entry point.
@@ -60,217 +68,256 @@ public class Input {
(new Input()).run(args);
}
- private void run(String[] args) {
- if (args.length < 1) {
- showUsage();
- return;
- }
+ Input() {
+ COMMANDS.put("text", new InputText());
+ COMMANDS.put("keyevent", new InputKeyEvent());
+ COMMANDS.put("tap", new InputTap());
+ COMMANDS.put("swipe", new InputSwipe());
+ COMMANDS.put("draganddrop", new InputDragAndDrop());
+ COMMANDS.put("press", new InputPress());
+ COMMANDS.put("roll", new InputRoll());
+ }
- int index = 0;
- String command = args[index];
+ @Override
+ public void onRun() throws Exception {
+ String arg = nextArgRequired();
int inputSource = InputDevice.SOURCE_UNKNOWN;
- if (SOURCES.containsKey(command)) {
- inputSource = SOURCES.get(command);
- index++;
- command = args[index];
+
+ // Get source (optional).
+ if (SOURCES.containsKey(arg)) {
+ inputSource = SOURCES.get(arg);
+ arg = nextArgRequired();
}
- final int length = args.length - index;
-
- try {
- if (command.equals("text")) {
- if (length == 2) {
- inputSource = getSource(inputSource, InputDevice.SOURCE_KEYBOARD);
- sendText(inputSource, args[index+1]);
- return;
- }
- } else if (command.equals("keyevent")) {
- if (length >= 2) {
- final boolean longpress = "--longpress".equals(args[index + 1]);
- final int start = longpress ? index + 2 : index + 1;
- inputSource = getSource(inputSource, InputDevice.SOURCE_KEYBOARD);
- if (args.length > start) {
- for (int i = start; i < args.length; i++) {
- int keyCode = KeyEvent.keyCodeFromString(args[i]);
- sendKeyEvent(inputSource, keyCode, longpress);
- }
- return;
- }
- }
- } else if (command.equals("tap")) {
- if (length == 3) {
- inputSource = getSource(inputSource, InputDevice.SOURCE_TOUCHSCREEN);
- sendTap(inputSource, Float.parseFloat(args[index+1]),
- Float.parseFloat(args[index+2]));
- return;
- }
- } else if (command.equals("swipe")) {
- int duration = -1;
- inputSource = getSource(inputSource, InputDevice.SOURCE_TOUCHSCREEN);
- switch (length) {
- case 6:
- duration = Integer.parseInt(args[index+5]);
- case 5:
- sendSwipe(inputSource,
- Float.parseFloat(args[index+1]), Float.parseFloat(args[index+2]),
- Float.parseFloat(args[index+3]), Float.parseFloat(args[index+4]),
- duration);
- return;
- }
- } else if (command.equals("draganddrop")) {
- int duration = -1;
- inputSource = getSource(inputSource, InputDevice.SOURCE_TOUCHSCREEN);
- switch (length) {
- case 6:
- duration = Integer.parseInt(args[index+5]);
- case 5:
- sendDragAndDrop(inputSource,
- Float.parseFloat(args[index+1]), Float.parseFloat(args[index+2]),
- Float.parseFloat(args[index+3]), Float.parseFloat(args[index+4]),
- duration);
- return;
- }
- } else if (command.equals("press")) {
- inputSource = getSource(inputSource, InputDevice.SOURCE_TRACKBALL);
- if (length == 1) {
- sendTap(inputSource, 0.0f, 0.0f);
- return;
- }
- } else if (command.equals("roll")) {
- inputSource = getSource(inputSource, InputDevice.SOURCE_TRACKBALL);
- if (length == 3) {
- sendMove(inputSource, Float.parseFloat(args[index+1]),
- Float.parseFloat(args[index+2]));
- return;
- }
- } else {
- System.err.println("Error: Unknown command: " + command);
- showUsage();
+
+ // Get displayId (optional).
+ int displayId = INVALID_DISPLAY;
+ if ("-d".equals(arg)) {
+ displayId = getDisplayId();
+ arg = nextArgRequired();
+ }
+
+ // Get command and run.
+ InputCmd cmd = COMMANDS.get(arg);
+ if (cmd != null) {
+ try {
+ cmd.run(inputSource, displayId);
return;
+ } catch (NumberFormatException ex) {
+ throw new IllegalArgumentException(INVALID_ARGUMENTS + arg);
}
- } catch (NumberFormatException ex) {
}
- System.err.println(INVALID_ARGUMENTS + command);
- showUsage();
+
+ throw new IllegalArgumentException("Error: Unknown command: " + arg);
}
- /**
- * Convert the characters of string text into key event's and send to
- * device.
- *
- * @param text is a string of characters you want to input to the device.
- */
- private void sendText(int source, String text) {
+ private int getDisplayId() {
+ String displayArg = nextArgRequired();
+ if ("INVALID_DISPLAY".equalsIgnoreCase(displayArg)) {
+ return INVALID_DISPLAY;
+ } else if ("DEFAULT_DISPLAY".equalsIgnoreCase(displayArg)) {
+ return DEFAULT_DISPLAY;
+ } else {
+ try {
+ final int displayId = Integer.parseInt(displayArg);
+ if (displayId == INVALID_DISPLAY) {
+ return INVALID_DISPLAY;
+ }
+ return Math.max(displayId, 0);
+ } catch (NumberFormatException e) {
+ throw new IllegalArgumentException(INVALID_DISPLAY_ARGUMENTS);
+ }
+ }
+ }
+
+ class InputText implements InputCmd {
+ @Override
+ public void run(int inputSource, int displayId) {
+ inputSource = getSource(inputSource, InputDevice.SOURCE_KEYBOARD);
+ sendText(inputSource, nextArgRequired(), displayId);
+ }
- StringBuffer buff = new StringBuffer(text);
+ /**
+ * Convert the characters of string text into key event's and send to
+ * device.
+ *
+ * @param text is a string of characters you want to input to the device.
+ */
+ private void sendText(int source, final String text, int displayId) {
+ final StringBuffer buff = new StringBuffer(text);
+ boolean escapeFlag = false;
+ for (int i = 0; i < buff.length(); i++) {
+ if (escapeFlag) {
+ escapeFlag = false;
+ if (buff.charAt(i) == 's') {
+ buff.setCharAt(i, ' ');
+ buff.deleteCharAt(--i);
+ }
+ }
+ if (buff.charAt(i) == '%') {
+ escapeFlag = true;
+ }
+ }
- boolean escapeFlag = false;
- for (int i=0; i<buff.length(); i++) {
- if (escapeFlag) {
- escapeFlag = false;
- if (buff.charAt(i) == 's') {
- buff.setCharAt(i, ' ');
- buff.deleteCharAt(--i);
+ final char[] chars = buff.toString().toCharArray();
+ final KeyCharacterMap kcm = KeyCharacterMap.load(KeyCharacterMap.VIRTUAL_KEYBOARD);
+ final KeyEvent[] events = kcm.getEvents(chars);
+ for (int i = 0; i < events.length; i++) {
+ KeyEvent e = events[i];
+ if (source != e.getSource()) {
+ e.setSource(source);
}
+ e.setDisplayId(displayId);
+ injectKeyEvent(e);
}
- if (buff.charAt(i) == '%') {
- escapeFlag = true;
+ }
+ }
+
+ class InputKeyEvent implements InputCmd {
+ @Override
+ public void run(int inputSource, int displayId) {
+ String arg = nextArgRequired();
+ final boolean longpress = "--longpress".equals(arg);
+ if (longpress) {
+ arg = nextArgRequired();
}
+
+ do {
+ final int keycode = KeyEvent.keyCodeFromString(arg);
+ sendKeyEvent(inputSource, keycode, longpress, displayId);
+ } while ((arg = nextArg()) != null);
}
- char[] chars = buff.toString().toCharArray();
+ private void sendKeyEvent(int inputSource, int keyCode, boolean longpress, int displayId) {
+ final long now = SystemClock.uptimeMillis();
+ int repeatCount = 0;
+
+ KeyEvent event = new KeyEvent(now, now, KeyEvent.ACTION_DOWN, keyCode, repeatCount,
+ 0 /*metaState*/, KeyCharacterMap.VIRTUAL_KEYBOARD, 0 /*scancode*/, 0/*flags*/,
+ inputSource);
+ event.setDisplayId(displayId);
- KeyCharacterMap kcm = KeyCharacterMap.load(KeyCharacterMap.VIRTUAL_KEYBOARD);
- KeyEvent[] events = kcm.getEvents(chars);
- for(int i = 0; i < events.length; i++) {
- KeyEvent e = events[i];
- if (source != e.getSource()) {
- e.setSource(source);
+ injectKeyEvent(event);
+ if (longpress) {
+ repeatCount++;
+ injectKeyEvent(KeyEvent.changeTimeRepeat(event, now, repeatCount,
+ KeyEvent.FLAG_LONG_PRESS));
}
- injectKeyEvent(e);
+ injectKeyEvent(KeyEvent.changeAction(event, KeyEvent.ACTION_UP));
}
}
- private void sendKeyEvent(int inputSource, int keyCode, boolean longpress) {
- long now = SystemClock.uptimeMillis();
- injectKeyEvent(new KeyEvent(now, now, KeyEvent.ACTION_DOWN, keyCode, 0, 0,
- KeyCharacterMap.VIRTUAL_KEYBOARD, 0, 0, inputSource));
- if (longpress) {
- injectKeyEvent(new KeyEvent(now, now, KeyEvent.ACTION_DOWN, keyCode, 1, 0,
- KeyCharacterMap.VIRTUAL_KEYBOARD, 0, KeyEvent.FLAG_LONG_PRESS,
- inputSource));
+ class InputTap implements InputCmd {
+ @Override
+ public void run(int inputSource, int displayId) {
+ inputSource = getSource(inputSource, InputDevice.SOURCE_TOUCHSCREEN);
+ sendTap(inputSource, Float.parseFloat(nextArgRequired()),
+ Float.parseFloat(nextArgRequired()), displayId);
+ }
+
+ void sendTap(int inputSource, float x, float y, int displayId) {
+ final long now = SystemClock.uptimeMillis();
+ injectMotionEvent(inputSource, MotionEvent.ACTION_DOWN, now, now, x, y, 1.0f,
+ displayId);
+ injectMotionEvent(inputSource, MotionEvent.ACTION_UP, now, now, x, y, 0.0f, displayId);
}
- injectKeyEvent(new KeyEvent(now, now, KeyEvent.ACTION_UP, keyCode, 0, 0,
- KeyCharacterMap.VIRTUAL_KEYBOARD, 0, 0, inputSource));
}
- private void sendTap(int inputSource, float x, float y) {
- long now = SystemClock.uptimeMillis();
- injectMotionEvent(inputSource, MotionEvent.ACTION_DOWN, now, x, y, 1.0f);
- injectMotionEvent(inputSource, MotionEvent.ACTION_UP, now, x, y, 0.0f);
+ class InputPress extends InputTap {
+ @Override
+ public void run(int inputSource, int displayId) {
+ inputSource = getSource(inputSource, InputDevice.SOURCE_TRACKBALL);
+ sendTap(inputSource, 0.0f, 0.0f, displayId);
+ }
}
- private void sendSwipe(int inputSource, float x1, float y1, float x2, float y2, int duration) {
- if (duration < 0) {
- duration = 300;
+ class InputSwipe implements InputCmd {
+ @Override
+ public void run(int inputSource, int displayId) {
+ inputSource = getSource(inputSource, InputDevice.SOURCE_TOUCHSCREEN);
+ sendSwipe(inputSource, displayId, false);
}
- long now = SystemClock.uptimeMillis();
- injectMotionEvent(inputSource, MotionEvent.ACTION_DOWN, now, x1, y1, 1.0f);
- long startTime = now;
- long endTime = startTime + duration;
- while (now < endTime) {
- long elapsedTime = now - startTime;
- float alpha = (float) elapsedTime / duration;
- injectMotionEvent(inputSource, MotionEvent.ACTION_MOVE, now, lerp(x1, x2, alpha),
- lerp(y1, y2, alpha), 1.0f);
- now = SystemClock.uptimeMillis();
+
+ void sendSwipe(int inputSource, int displayId, boolean isDragDrop) {
+ // Parse two points and duration.
+ final float x1 = Float.parseFloat(nextArgRequired());
+ final float y1 = Float.parseFloat(nextArgRequired());
+ final float x2 = Float.parseFloat(nextArgRequired());
+ final float y2 = Float.parseFloat(nextArgRequired());
+ String durationArg = nextArg();
+ int duration = durationArg != null ? Integer.parseInt(durationArg) : -1;
+ if (duration < 0) {
+ duration = 300;
+ }
+
+ final long down = SystemClock.uptimeMillis();
+ injectMotionEvent(inputSource, MotionEvent.ACTION_DOWN, down, down, x1, y1, 1.0f,
+ displayId);
+ if (isDragDrop) {
+ // long press until drag start.
+ try {
+ Thread.sleep(ViewConfiguration.getLongPressTimeout());
+ } catch (InterruptedException e) {
+ throw new RuntimeException(e);
+ }
+ }
+ long now = SystemClock.uptimeMillis();
+ final long endTime = down + duration;
+ while (now < endTime) {
+ final long elapsedTime = now - down;
+ final float alpha = (float) elapsedTime / duration;
+ injectMotionEvent(inputSource, MotionEvent.ACTION_MOVE, down, now,
+ lerp(x1, x2, alpha), lerp(y1, y2, alpha), 1.0f, displayId);
+ now = SystemClock.uptimeMillis();
+ }
+ injectMotionEvent(inputSource, MotionEvent.ACTION_UP, down, now, x2, y2, 0.0f,
+ displayId);
}
- injectMotionEvent(inputSource, MotionEvent.ACTION_UP, now, x2, y2, 0.0f);
}
- private void sendDragAndDrop(int inputSource, float x1, float y1, float x2, float y2,
- int dragDuration) {
- if (dragDuration < 0) {
- dragDuration = 300;
+ class InputDragAndDrop extends InputSwipe {
+ @Override
+ public void run(int inputSource, int displayId) {
+ inputSource = getSource(inputSource, InputDevice.SOURCE_TOUCHSCREEN);
+ sendSwipe(inputSource, displayId, true);
}
- long now = SystemClock.uptimeMillis();
- injectMotionEvent(inputSource, MotionEvent.ACTION_DOWN, now, x1, y1, 1.0f);
- try {
- Thread.sleep(ViewConfiguration.getLongPressTimeout());
- } catch (InterruptedException e) {
- throw new RuntimeException(e);
+ }
+
+ class InputRoll implements InputCmd {
+ @Override
+ public void run(int inputSource, int displayId) {
+ inputSource = getSource(inputSource, InputDevice.SOURCE_TRACKBALL);
+ sendMove(inputSource, Float.parseFloat(nextArgRequired()),
+ Float.parseFloat(nextArgRequired()), displayId);
}
- now = SystemClock.uptimeMillis();
- long startTime = now;
- long endTime = startTime + dragDuration;
- while (now < endTime) {
- long elapsedTime = now - startTime;
- float alpha = (float) elapsedTime / dragDuration;
- injectMotionEvent(inputSource, MotionEvent.ACTION_MOVE, now, lerp(x1, x2, alpha),
- lerp(y1, y2, alpha), 1.0f);
- now = SystemClock.uptimeMillis();
+
+ /**
+ * Sends a simple zero-pressure move event.
+ *
+ * @param inputSource the InputDevice.SOURCE_* sending the input event
+ * @param dx change in x coordinate due to move
+ * @param dy change in y coordinate due to move
+ */
+ private void sendMove(int inputSource, float dx, float dy, int displayId) {
+ final long now = SystemClock.uptimeMillis();
+ injectMotionEvent(inputSource, MotionEvent.ACTION_MOVE, now, now, dx, dy, 0.0f,
+ displayId);
}
- injectMotionEvent(inputSource, MotionEvent.ACTION_UP, now, x2, y2, 0.0f);
}
/**
- * Sends a simple zero-pressure move event.
- *
- * @param inputSource the InputDevice.SOURCE_* sending the input event
- * @param dx change in x coordinate due to move
- * @param dy change in y coordinate due to move
+ * Abstract class for command
+ * use nextArgRequired or nextArg to check next argument if necessary.
*/
- private void sendMove(int inputSource, float dx, float dy) {
- long now = SystemClock.uptimeMillis();
- injectMotionEvent(inputSource, MotionEvent.ACTION_MOVE, now, dx, dy, 0.0f);
+ private interface InputCmd {
+ void run(int inputSource, int displayId);
}
- private void injectKeyEvent(KeyEvent event) {
- Log.i(TAG, "injectKeyEvent: " + event);
+ private static void injectKeyEvent(KeyEvent event) {
InputManager.getInstance().injectInputEvent(event,
InputManager.INJECT_INPUT_EVENT_MODE_WAIT_FOR_FINISH);
}
- private int getInputDeviceId(int inputSource) {
+ private static int getInputDeviceId(int inputSource) {
final int DEFAULT_DEVICE_ID = 0;
int[] devIds = InputDevice.getDeviceIds();
for (int devId : devIds) {
@@ -287,22 +334,27 @@ public class Input {
*
* @param inputSource the InputDevice.SOURCE_* sending the input event
* @param action the MotionEvent.ACTION_* for the event
+ * @param downTime the value of the ACTION_DOWN event happened
* @param when the value of SystemClock.uptimeMillis() at which the event happened
* @param x x coordinate of event
* @param y y coordinate of event
* @param pressure pressure of event
*/
- private void injectMotionEvent(int inputSource, int action, long when, float x, float y, float pressure) {
+ private static void injectMotionEvent(int inputSource, int action, long downTime, long when,
+ float x, float y, float pressure, int displayId) {
final float DEFAULT_SIZE = 1.0f;
final int DEFAULT_META_STATE = 0;
final float DEFAULT_PRECISION_X = 1.0f;
final float DEFAULT_PRECISION_Y = 1.0f;
final int DEFAULT_EDGE_FLAGS = 0;
- MotionEvent event = MotionEvent.obtain(when, when, action, x, y, pressure, DEFAULT_SIZE,
+ MotionEvent event = MotionEvent.obtain(downTime, when, action, x, y, pressure, DEFAULT_SIZE,
DEFAULT_META_STATE, DEFAULT_PRECISION_X, DEFAULT_PRECISION_Y,
getInputDeviceId(inputSource), DEFAULT_EDGE_FLAGS);
event.setSource(inputSource);
- Log.i(TAG, "injectMotionEvent: " + event);
+ if (displayId == INVALID_DISPLAY && (inputSource & InputDevice.SOURCE_CLASS_POINTER) != 0) {
+ displayId = DEFAULT_DISPLAY;
+ }
+ event.setDisplayId(displayId);
InputManager.getInstance().injectInputEvent(event,
InputManager.INJECT_INPUT_EVENT_MODE_WAIT_FOR_FINISH);
}
@@ -315,24 +367,29 @@ public class Input {
return inputSource == InputDevice.SOURCE_UNKNOWN ? defaultSource : inputSource;
}
- private void showUsage() {
- System.err.println("Usage: input [<source>] <command> [<arg>...]");
- System.err.println();
- System.err.println("The sources are: ");
+ @Override
+ public void onShowUsage(PrintStream out) {
+ out.println("Usage: input [<source>] [-d DISPLAY_ID] <command> [<arg>...]");
+ out.println();
+ out.println("The sources are: ");
for (String src : SOURCES.keySet()) {
- System.err.println(" " + src);
+ out.println(" " + src);
}
- System.err.println();
- System.err.println("The commands and default sources are:");
- System.err.println(" text <string> (Default: touchscreen)");
- System.err.println(" keyevent [--longpress] <key code number or name> ..."
+ out.println();
+ out.printf("-d: specify the display ID.\n"
+ + " (Default: %d for key event, %d for motion event if not specified.)",
+ INVALID_DISPLAY, DEFAULT_DISPLAY);
+ out.println();
+ out.println("The commands and default sources are:");
+ out.println(" text <string> (Default: touchscreen)");
+ out.println(" keyevent [--longpress] <key code number or name> ..."
+ " (Default: keyboard)");
- System.err.println(" tap <x> <y> (Default: touchscreen)");
- System.err.println(" swipe <x1> <y1> <x2> <y2> [duration(ms)]"
+ out.println(" tap <x> <y> (Default: touchscreen)");
+ out.println(" swipe <x1> <y1> <x2> <y2> [duration(ms)]"
+ " (Default: touchscreen)");
- System.err.println(" draganddrop <x1> <y1> <x2> <y2> [duration(ms)]"
+ out.println(" draganddrop <x1> <y1> <x2> <y2> [duration(ms)]"
+ " (Default: touchscreen)");
- System.err.println(" press (Default: trackball)");
- System.err.println(" roll <dx> <dy> (Default: trackball)");
+ out.println(" press (Default: trackball)");
+ out.println(" roll <dx> <dy> (Default: trackball)");
}
}
diff --git a/cmds/media/src/com/android/commands/media/Media.java b/cmds/media/src/com/android/commands/media/Media.java
index c6d2bc891b18..6788f7d45071 100644
--- a/cmds/media/src/com/android/commands/media/Media.java
+++ b/cmds/media/src/com/android/commands/media/Media.java
@@ -24,7 +24,7 @@ import android.media.MediaMetadata;
import android.media.session.ISessionController;
import android.media.session.ISessionControllerCallback;
import android.media.session.ISessionManager;
-import android.media.session.ParcelableVolumeInfo;
+import android.media.session.MediaController.PlaybackInfo;
import android.media.session.PlaybackState;
import android.os.Bundle;
import android.os.HandlerThread;
@@ -224,7 +224,7 @@ public class Media extends BaseCommand {
}
@Override
- public void onVolumeInfoChanged(ParcelableVolumeInfo info) throws RemoteException {
+ public void onVolumeInfoChanged(PlaybackInfo info) throws RemoteException {
System.out.println("onVolumeInfoChanged " + info);
}
diff --git a/config/hiddenapi-greylist.txt b/config/hiddenapi-greylist.txt
index d0ed28294288..e0e1b7202347 100644
--- a/config/hiddenapi-greylist.txt
+++ b/config/hiddenapi-greylist.txt
@@ -2767,92 +2767,6 @@ Lcom/android/internal/telephony/Connection;->mDuration:J
Lcom/android/internal/telephony/Connection;->mIsIncoming:Z
Lcom/android/internal/telephony/Connection;->mNumberPresentation:I
Lcom/android/internal/telephony/Connection;->setVideoState(I)V
-Lcom/android/internal/telephony/dataconnection/ApnContext;->getApnType()Ljava/lang/String;
-Lcom/android/internal/telephony/dataconnection/ApnContext;->getReason()Ljava/lang/String;
-Lcom/android/internal/telephony/dataconnection/ApnContext;->getState()Lcom/android/internal/telephony/DctConstants$State;
-Lcom/android/internal/telephony/dataconnection/ApnContext;->isConnectable()Z
-Lcom/android/internal/telephony/dataconnection/ApnContext;->isDisconnected()Z
-Lcom/android/internal/telephony/dataconnection/ApnContext;->isEnabled()Z
-Lcom/android/internal/telephony/dataconnection/ApnContext;->isReady()Z
-Lcom/android/internal/telephony/dataconnection/ApnContext;->log(Ljava/lang/String;)V
-Lcom/android/internal/telephony/dataconnection/ApnContext;->mApnType:Ljava/lang/String;
-Lcom/android/internal/telephony/dataconnection/ApnContext;->mRefCount:I
-Lcom/android/internal/telephony/dataconnection/ApnContext;->mRefCountLock:Ljava/lang/Object;
-Lcom/android/internal/telephony/dataconnection/ApnContext;->setState(Lcom/android/internal/telephony/DctConstants$State;)V
-Lcom/android/internal/telephony/dataconnection/DataConnection$ConnectionParams;->mApnContext:Lcom/android/internal/telephony/dataconnection/ApnContext;
-Lcom/android/internal/telephony/dataconnection/DataConnection;->clearSettings()V
-Lcom/android/internal/telephony/dataconnection/DataConnection;->dumpToLog()V
-Lcom/android/internal/telephony/dataconnection/DataConnection;->initConnection(Lcom/android/internal/telephony/dataconnection/DataConnection$ConnectionParams;)Z
-Lcom/android/internal/telephony/dataconnection/DataConnection;->log(Ljava/lang/String;)V
-Lcom/android/internal/telephony/dataconnection/DataConnection;->mActivatingState:Lcom/android/internal/telephony/dataconnection/DataConnection$DcActivatingState;
-Lcom/android/internal/telephony/dataconnection/DataConnection;->mActiveState:Lcom/android/internal/telephony/dataconnection/DataConnection$DcActiveState;
-Lcom/android/internal/telephony/dataconnection/DataConnection;->mConnectionParams:Lcom/android/internal/telephony/dataconnection/DataConnection$ConnectionParams;
-Lcom/android/internal/telephony/dataconnection/DataConnection;->mDataRegState:I
-Lcom/android/internal/telephony/dataconnection/DataConnection;->mDct:Lcom/android/internal/telephony/dataconnection/DcTracker;
-Lcom/android/internal/telephony/dataconnection/DataConnection;->mDisconnectingErrorCreatingConnection:Lcom/android/internal/telephony/dataconnection/DataConnection$DcDisconnectionErrorCreatingConnection;
-Lcom/android/internal/telephony/dataconnection/DataConnection;->mDisconnectingState:Lcom/android/internal/telephony/dataconnection/DataConnection$DcDisconnectingState;
-Lcom/android/internal/telephony/dataconnection/DataConnection;->mDisconnectParams:Lcom/android/internal/telephony/dataconnection/DataConnection$DisconnectParams;
-Lcom/android/internal/telephony/dataconnection/DataConnection;->mId:I
-Lcom/android/internal/telephony/dataconnection/DataConnection;->mInactiveState:Lcom/android/internal/telephony/dataconnection/DataConnection$DcInactiveState;
-Lcom/android/internal/telephony/dataconnection/DataConnection;->mLinkProperties:Landroid/net/LinkProperties;
-Lcom/android/internal/telephony/dataconnection/DataConnection;->mNetworkInfo:Landroid/net/NetworkInfo;
-Lcom/android/internal/telephony/dataconnection/DataConnection;->mPhone:Lcom/android/internal/telephony/Phone;
-Lcom/android/internal/telephony/dataconnection/DataConnection;->mRilRat:I
-Lcom/android/internal/telephony/dataconnection/DataConnection;->notifyAllOfConnected(Ljava/lang/String;)V
-Lcom/android/internal/telephony/dataconnection/DataConnection;->notifyDisconnectCompleted(Lcom/android/internal/telephony/dataconnection/DataConnection$DisconnectParams;Z)V
-Lcom/android/internal/telephony/dataconnection/DataConnection;->onConnect(Lcom/android/internal/telephony/dataconnection/DataConnection$ConnectionParams;)V
-Lcom/android/internal/telephony/dataconnection/DataConnection;->tearDownData(Ljava/lang/Object;)V
-Lcom/android/internal/telephony/dataconnection/DataConnection;->updateTcpBufferSizes(I)V
-Lcom/android/internal/telephony/dataconnection/DcController;->lr(Ljava/lang/String;)V
-Lcom/android/internal/telephony/dataconnection/DcController;->mDcListActiveByCid:Ljava/util/HashMap;
-Lcom/android/internal/telephony/dataconnection/DcController;->mDct:Lcom/android/internal/telephony/dataconnection/DcTracker;
-Lcom/android/internal/telephony/dataconnection/DcController;->mDcTesterDeactivateAll:Lcom/android/internal/telephony/dataconnection/DcTesterDeactivateAll;
-Lcom/android/internal/telephony/dataconnection/DcTracker$RecoveryAction;->isAggressiveRecovery(I)Z
-Lcom/android/internal/telephony/dataconnection/DcTracker;->cancelReconnectAlarm(Lcom/android/internal/telephony/dataconnection/ApnContext;)V
-Lcom/android/internal/telephony/dataconnection/DcTracker;->cleanUpAllConnections(Ljava/lang/String;)V
-Lcom/android/internal/telephony/dataconnection/DcTracker;->createAllApnList()V
-Lcom/android/internal/telephony/dataconnection/DcTracker;->getActiveApnTypes()[Ljava/lang/String;
-Lcom/android/internal/telephony/dataconnection/DcTracker;->getOverallState()Lcom/android/internal/telephony/DctConstants$State;
-Lcom/android/internal/telephony/dataconnection/DcTracker;->getUiccRecords(I)Lcom/android/internal/telephony/uicc/IccRecords;
-Lcom/android/internal/telephony/dataconnection/DcTracker;->isConnected()Z
-Lcom/android/internal/telephony/dataconnection/DcTracker;->isDisconnected()Z
-Lcom/android/internal/telephony/dataconnection/DcTracker;->isOnlySingleDcAllowed(I)Z
-Lcom/android/internal/telephony/dataconnection/DcTracker;->log(Ljava/lang/String;)V
-Lcom/android/internal/telephony/dataconnection/DcTracker;->loge(Ljava/lang/String;)V
-Lcom/android/internal/telephony/dataconnection/DcTracker;->mAllApnSettings:Ljava/util/ArrayList;
-Lcom/android/internal/telephony/dataconnection/DcTracker;->mApnContexts:Ljava/util/concurrent/ConcurrentHashMap;
-Lcom/android/internal/telephony/dataconnection/DcTracker;->mAttached:Ljava/util/concurrent/atomic/AtomicBoolean;
-Lcom/android/internal/telephony/dataconnection/DcTracker;->mAutoAttachOnCreation:Ljava/util/concurrent/atomic/AtomicBoolean;
-Lcom/android/internal/telephony/dataconnection/DcTracker;->mDataConnectionTracker:Landroid/os/Handler;
-Lcom/android/internal/telephony/dataconnection/DcTracker;->mDisconnectPendingCount:I
-Lcom/android/internal/telephony/dataconnection/DcTracker;->mIccRecords:Ljava/util/concurrent/atomic/AtomicReference;
-Lcom/android/internal/telephony/dataconnection/DcTracker;->mIsPsRestricted:Z
-Lcom/android/internal/telephony/dataconnection/DcTracker;->mIsScreenOn:Z
-Lcom/android/internal/telephony/dataconnection/DcTracker;->mNetStatPollEnabled:Z
-Lcom/android/internal/telephony/dataconnection/DcTracker;->mNetStatPollPeriod:I
-Lcom/android/internal/telephony/dataconnection/DcTracker;->mPhone:Lcom/android/internal/telephony/Phone;
-Lcom/android/internal/telephony/dataconnection/DcTracker;->mPrioritySortedApnContexts:Ljava/util/PriorityQueue;
-Lcom/android/internal/telephony/dataconnection/DcTracker;->mProvisioningSpinner:Landroid/app/ProgressDialog;
-Lcom/android/internal/telephony/dataconnection/DcTracker;->mResolver:Landroid/content/ContentResolver;
-Lcom/android/internal/telephony/dataconnection/DcTracker;->mState:Lcom/android/internal/telephony/DctConstants$State;
-Lcom/android/internal/telephony/dataconnection/DcTracker;->mSubscriptionManager:Landroid/telephony/SubscriptionManager;
-Lcom/android/internal/telephony/dataconnection/DcTracker;->onActionIntentDataStallAlarm(Landroid/content/Intent;)V
-Lcom/android/internal/telephony/dataconnection/DcTracker;->onActionIntentProvisioningApnAlarm(Landroid/content/Intent;)V
-Lcom/android/internal/telephony/dataconnection/DcTracker;->onRecordsLoadedOrSubIdChanged()V
-Lcom/android/internal/telephony/dataconnection/DcTracker;->onTrySetupData(Lcom/android/internal/telephony/dataconnection/ApnContext;)Z
-Lcom/android/internal/telephony/dataconnection/DcTracker;->onTrySetupData(Ljava/lang/String;)Z
-Lcom/android/internal/telephony/dataconnection/DcTracker;->registerSettingsObserver()V
-Lcom/android/internal/telephony/dataconnection/DcTracker;->resetPollStats()V
-Lcom/android/internal/telephony/dataconnection/DcTracker;->restartDataStallAlarm()V
-Lcom/android/internal/telephony/dataconnection/DcTracker;->setInitialAttachApn()V
-Lcom/android/internal/telephony/dataconnection/DcTracker;->setPreferredApn(I)V
-Lcom/android/internal/telephony/dataconnection/DcTracker;->setRadio(Z)V
-Lcom/android/internal/telephony/dataconnection/DcTracker;->setupDataOnConnectableApns(Ljava/lang/String;)V
-Lcom/android/internal/telephony/dataconnection/DcTracker;->startDataStallAlarm(Z)V
-Lcom/android/internal/telephony/dataconnection/DcTracker;->startNetStatPoll()V
-Lcom/android/internal/telephony/dataconnection/DcTracker;->stopDataStallAlarm()V
-Lcom/android/internal/telephony/dataconnection/DcTracker;->stopNetStatPoll()V
-Lcom/android/internal/telephony/dataconnection/DcTracker;->unregisterForAllDataDisconnected(Landroid/os/Handler;)V
Lcom/android/internal/telephony/DctConstants$Activity;->DATAIN:Lcom/android/internal/telephony/DctConstants$Activity;
Lcom/android/internal/telephony/DctConstants$Activity;->DATAINANDOUT:Lcom/android/internal/telephony/DctConstants$Activity;
Lcom/android/internal/telephony/DctConstants$Activity;->DATAOUT:Lcom/android/internal/telephony/DctConstants$Activity;
diff --git a/core/java/android/app/ActivityView.java b/core/java/android/app/ActivityView.java
index 7cda8403f1f9..57132a72700d 100644
--- a/core/java/android/app/ActivityView.java
+++ b/core/java/android/app/ActivityView.java
@@ -321,7 +321,7 @@ public class ActivityView extends ViewGroup {
public void surfaceCreated(SurfaceHolder surfaceHolder) {
mTmpSurface = new Surface();
if (mVirtualDisplay == null) {
- initVirtualDisplay(new SurfaceSession(surfaceHolder.getSurface()));
+ initVirtualDisplay(new SurfaceSession());
if (mVirtualDisplay != null && mActivityViewCallback != null) {
mActivityViewCallback.onActivityViewReady(ActivityView.this);
}
@@ -389,6 +389,7 @@ public class ActivityView extends ViewGroup {
mRootSurfaceControl = new SurfaceControl.Builder(surfaceSession)
.setContainerLayer(true)
+ .setParent(mSurfaceView.getSurfaceControl())
.setName(DISPLAY_NAME)
.build();
diff --git a/core/java/android/app/IWallpaperManager.aidl b/core/java/android/app/IWallpaperManager.aidl
index 3a2038d40952..666f7218a4f2 100644
--- a/core/java/android/app/IWallpaperManager.aidl
+++ b/core/java/android/app/IWallpaperManager.aidl
@@ -142,19 +142,20 @@ interface IWallpaperManager {
*
* @param which either {@link WallpaperManager#FLAG_LOCK}
* or {@link WallpaperManager#FLAG_SYSTEM}
+ * @param displayId Which display is interested
* @return colors of chosen wallpaper
*/
- WallpaperColors getWallpaperColors(int which, int userId);
+ WallpaperColors getWallpaperColors(int which, int userId, int displayId);
/**
- * Register a callback to receive color updates
+ * Register a callback to receive color updates from a display
*/
- void registerWallpaperColorsCallback(IWallpaperManagerCallback cb, int userId);
+ void registerWallpaperColorsCallback(IWallpaperManagerCallback cb, int userId, int displayId);
/**
- * Unregister a callback that was receiving color updates
+ * Unregister a callback that was receiving color updates from a display
*/
- void unregisterWallpaperColorsCallback(IWallpaperManagerCallback cb, int userId);
+ void unregisterWallpaperColorsCallback(IWallpaperManagerCallback cb, int userId, int displayId);
/**
* Called from SystemUI when it shows the AoD UI.
diff --git a/core/java/android/app/WallpaperManager.java b/core/java/android/app/WallpaperManager.java
index 27ae0b0314d0..a929fe0f688e 100644
--- a/core/java/android/app/WallpaperManager.java
+++ b/core/java/android/app/WallpaperManager.java
@@ -307,13 +307,14 @@ public class WallpaperManager {
* @param callback Listener
* @param handler Thread to call it from. Main thread if null.
* @param userId Owner of the wallpaper or UserHandle.USER_ALL
+ * @param displayId Caller comes from which display
*/
public void addOnColorsChangedListener(@NonNull OnColorsChangedListener callback,
- @Nullable Handler handler, int userId) {
+ @Nullable Handler handler, int userId, int displayId) {
synchronized (this) {
if (!mColorCallbackRegistered) {
try {
- mService.registerWallpaperColorsCallback(this, userId);
+ mService.registerWallpaperColorsCallback(this, userId, displayId);
mColorCallbackRegistered = true;
} catch (RemoteException e) {
// Failed, service is gone
@@ -329,16 +330,17 @@ public class WallpaperManager {
*
* @param callback listener
* @param userId Owner of the wallpaper or UserHandle.USER_ALL
+ * @param displayId Which display is interested
*/
public void removeOnColorsChangedListener(@NonNull OnColorsChangedListener callback,
- int userId) {
+ int userId, int displayId) {
synchronized (this) {
mColorListeners.removeIf(pair -> pair.first == callback);
if (mColorListeners.size() == 0 && mColorCallbackRegistered) {
mColorCallbackRegistered = false;
try {
- mService.unregisterWallpaperColorsCallback(this, userId);
+ mService.unregisterWallpaperColorsCallback(this, userId, displayId);
} catch (RemoteException e) {
// Failed, service is gone
Log.w(TAG, "Can't unregister color updates", e);
@@ -370,14 +372,14 @@ public class WallpaperManager {
}
}
- WallpaperColors getWallpaperColors(int which, int userId) {
+ WallpaperColors getWallpaperColors(int which, int userId, int displayId) {
if (which != FLAG_LOCK && which != FLAG_SYSTEM) {
throw new IllegalArgumentException(
"Must request colors for exactly one kind of wallpaper");
}
try {
- return mService.getWallpaperColors(which, userId);
+ return mService.getWallpaperColors(which, userId, displayId);
} catch (RemoteException e) {
// Can't get colors, connection lost.
}
@@ -894,7 +896,7 @@ public class WallpaperManager {
@UnsupportedAppUsage
public void addOnColorsChangedListener(@NonNull OnColorsChangedListener listener,
@NonNull Handler handler, int userId) {
- sGlobals.addOnColorsChangedListener(listener, handler, userId);
+ sGlobals.addOnColorsChangedListener(listener, handler, userId, mContext.getDisplayId());
}
/**
@@ -913,7 +915,7 @@ public class WallpaperManager {
*/
public void removeOnColorsChangedListener(@NonNull OnColorsChangedListener callback,
int userId) {
- sGlobals.removeOnColorsChangedListener(callback, userId);
+ sGlobals.removeOnColorsChangedListener(callback, userId, mContext.getDisplayId());
}
/**
@@ -947,7 +949,7 @@ public class WallpaperManager {
*/
@UnsupportedAppUsage
public @Nullable WallpaperColors getWallpaperColors(int which, int userId) {
- return sGlobals.getWallpaperColors(which, userId);
+ return sGlobals.getWallpaperColors(which, userId, mContext.getDisplayId());
}
/**
diff --git a/core/java/android/app/usage/IUsageStatsManager.aidl b/core/java/android/app/usage/IUsageStatsManager.aidl
index 4d52263c1d78..bbae7d3463ae 100644
--- a/core/java/android/app/usage/IUsageStatsManager.aidl
+++ b/core/java/android/app/usage/IUsageStatsManager.aidl
@@ -55,4 +55,8 @@ interface IUsageStatsManager {
long sessionThresholdTimeMs, in PendingIntent limitReachedCallbackIntent,
in PendingIntent sessionEndCallbackIntent, String callingPackage);
void unregisterUsageSessionObserver(int sessionObserverId, String callingPackage);
+ void reportUsageStart(in IBinder activity, String token, String callingPackage);
+ void reportPastUsageStart(in IBinder activity, String token, long timeAgoMs,
+ String callingPackage);
+ void reportUsageStop(in IBinder activity, String token, String callingPackage);
}
diff --git a/core/java/android/app/usage/UsageStatsManager.java b/core/java/android/app/usage/UsageStatsManager.java
index 26beb45be13f..605deac80994 100644
--- a/core/java/android/app/usage/UsageStatsManager.java
+++ b/core/java/android/app/usage/UsageStatsManager.java
@@ -23,6 +23,7 @@ import android.annotation.RequiresPermission;
import android.annotation.SystemApi;
import android.annotation.SystemService;
import android.annotation.UnsupportedAppUsage;
+import android.app.Activity;
import android.app.PendingIntent;
import android.content.Context;
import android.content.pm.ParceledListSlice;
@@ -579,15 +580,18 @@ public final class UsageStatsManager {
/**
* @hide
* Register an app usage limit observer that receives a callback on the provided intent when
- * the sum of usages of apps in the packages array exceeds the {@code timeLimit} specified. The
- * observer will automatically be unregistered when the time limit is reached and the intent
- * is delivered. Registering an {@code observerId} that was already registered will override
- * the previous one. No more than 1000 unique {@code observerId} may be registered by a single
- * uid at any one time.
+ * the sum of usages of apps and tokens in the {@code observed} array exceeds the
+ * {@code timeLimit} specified. The structure of a token is a String with the reporting
+ * package's name and a token the reporting app will use, separated by the forward slash
+ * character. Example: com.reporting.package/5OM3*0P4QU3-7OK3N
+ * The observer will automatically be unregistered when the time limit is reached and the
+ * intent is delivered. Registering an {@code observerId} that was already registered will
+ * override the previous one. No more than 1000 unique {@code observerId} may be registered by
+ * a single uid at any one time.
* @param observerId A unique id associated with the group of apps to be monitored. There can
* be multiple groups with common packages and different time limits.
- * @param packages The list of packages to observe for foreground activity time. Cannot be null
- * and must include at least one package.
+ * @param observedEntities The list of packages and token to observe for usage time. Cannot be
+ * null and must include at least one package or token.
* @param timeLimit The total time the set of apps can be in the foreground before the
* callbackIntent is delivered. Must be at least one minute.
* @param timeUnit The unit for time specified in {@code timeLimit}. Cannot be null.
@@ -600,11 +604,11 @@ public final class UsageStatsManager {
*/
@SystemApi
@RequiresPermission(android.Manifest.permission.OBSERVE_APP_USAGE)
- public void registerAppUsageObserver(int observerId, @NonNull String[] packages, long timeLimit,
- @NonNull TimeUnit timeUnit, @NonNull PendingIntent callbackIntent) {
+ public void registerAppUsageObserver(int observerId, @NonNull String[] observedEntities,
+ long timeLimit, @NonNull TimeUnit timeUnit, @NonNull PendingIntent callbackIntent) {
try {
- mService.registerAppUsageObserver(observerId, packages, timeUnit.toMillis(timeLimit),
- callbackIntent, mContext.getOpPackageName());
+ mService.registerAppUsageObserver(observerId, observedEntities,
+ timeUnit.toMillis(timeLimit), callbackIntent, mContext.getOpPackageName());
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
}
@@ -631,18 +635,21 @@ public final class UsageStatsManager {
/**
* Register a usage session observer that receives a callback on the provided {@code
- * limitReachedCallbackIntent} when the sum of usages of apps in the packages array exceeds
- * the {@code timeLimit} specified within a usage session. After the {@code timeLimit} has
- * been reached, the usage session observer will receive a callback on the provided {@code
- * sessionEndCallbackIntent} when the usage session ends. Registering another session
- * observer against a {@code sessionObserverId} that has already been registered will
- * override the previous session observer.
+ * limitReachedCallbackIntent} when the sum of usages of apps and tokens in the {@code
+ * observed} array exceeds the {@code timeLimit} specified within a usage session. The
+ * structure of a token is a String with the reporting packages' name and a token the
+ * reporting app will use, separated by the forward slash character.
+ * Example: com.reporting.package/5OM3*0P4QU3-7OK3N
+ * After the {@code timeLimit} has been reached, the usage session observer will receive a
+ * callback on the provided {@code sessionEndCallbackIntent} when the usage session ends.
+ * Registering another session observer against a {@code sessionObserverId} that has already
+ * been registered will override the previous session observer.
*
* @param sessionObserverId A unique id associated with the group of apps to be
* monitored. There can be multiple groups with common
* packages and different time limits.
- * @param packages The list of packages to observe for foreground activity time. Cannot be null
- * and must include at least one package.
+ * @param observedEntities The list of packages and token to observe for usage time. Cannot be
+ * null and must include at least one package or token.
* @param timeLimit The total time the set of apps can be used continuously before the {@code
* limitReachedCallbackIntent} is delivered. Must be at least one minute.
* @param timeUnit The unit for time specified in {@code timeLimit}. Cannot be null.
@@ -668,13 +675,13 @@ public final class UsageStatsManager {
*/
@SystemApi
@RequiresPermission(android.Manifest.permission.OBSERVE_APP_USAGE)
- public void registerUsageSessionObserver(int sessionObserverId, @NonNull String[] packages,
- long timeLimit, @NonNull TimeUnit timeUnit, long sessionThresholdTime,
- @NonNull TimeUnit sessionThresholdTimeUnit,
+ public void registerUsageSessionObserver(int sessionObserverId,
+ @NonNull String[] observedEntities, long timeLimit, @NonNull TimeUnit timeUnit,
+ long sessionThresholdTime, @NonNull TimeUnit sessionThresholdTimeUnit,
@NonNull PendingIntent limitReachedCallbackIntent,
@Nullable PendingIntent sessionEndCallbackIntent) {
try {
- mService.registerUsageSessionObserver(sessionObserverId, packages,
+ mService.registerUsageSessionObserver(sessionObserverId, observedEntities,
timeUnit.toMillis(timeLimit),
sessionThresholdTimeUnit.toMillis(sessionThresholdTime),
limitReachedCallbackIntent, sessionEndCallbackIntent,
@@ -704,6 +711,71 @@ public final class UsageStatsManager {
}
}
+ /**
+ * Report usage associated with a particular {@code token} has started. Tokens are app defined
+ * strings used to represent usage of in-app features. Apps with the {@link
+ * android.Manifest.permission#OBSERVE_APP_USAGE} permission can register time limit observers
+ * to monitor the usage of a token. In app usage can only associated with an {@code activity}
+ * and usage will be considered stopped if the activity stops or crashes.
+ * @see #registerAppUsageObserver
+ * @see #registerUsageSessionObserver
+ *
+ * @param activity The activity {@code token} is associated with.
+ * @param token The token to report usage against.
+ * @hide
+ */
+ @SystemApi
+ public void reportUsageStart(@NonNull Activity activity, @NonNull String token) {
+ try {
+ mService.reportUsageStart(activity.getActivityToken(), token,
+ mContext.getOpPackageName());
+ } catch (RemoteException e) {
+ throw e.rethrowFromSystemServer();
+ }
+ }
+
+ /**
+ * Report usage associated with a particular {@code token} had started some amount of time in
+ * the past. Tokens are app defined strings used to represent usage of in-app features. Apps
+ * with the {@link android.Manifest.permission#OBSERVE_APP_USAGE} permission can register time
+ * limit observers to monitor the usage of a token. In app usage can only associated with an
+ * {@code activity} and usage will be considered stopped if the activity stops or crashes.
+ * @see #registerAppUsageObserver
+ * @see #registerUsageSessionObserver
+ *
+ * @param activity The activity {@code token} is associated with.
+ * @param token The token to report usage against.
+ * @param timeAgoMs How long ago the start of usage took place
+ * @hide
+ */
+ @SystemApi
+ public void reportUsageStart(@NonNull Activity activity, @NonNull String token,
+ long timeAgoMs) {
+ try {
+ mService.reportPastUsageStart(activity.getActivityToken(), token, timeAgoMs,
+ mContext.getOpPackageName());
+ } catch (RemoteException e) {
+ throw e.rethrowFromSystemServer();
+ }
+ }
+
+ /**
+ * Report the usage associated with a particular {@code token} has stopped.
+ *
+ * @param activity The activity {@code token} is associated with.
+ * @param token The token to report usage against.
+ * @hide
+ */
+ @SystemApi
+ public void reportUsageStop(@NonNull Activity activity, @NonNull String token) {
+ try {
+ mService.reportUsageStop(activity.getActivityToken(), token,
+ mContext.getOpPackageName());
+ } catch (RemoteException e) {
+ throw e.rethrowFromSystemServer();
+ }
+ }
+
/** @hide */
public static String reasonToString(int standbyReason) {
StringBuilder sb = new StringBuilder();
diff --git a/core/java/android/content/Intent.java b/core/java/android/content/Intent.java
index 7b3497b8b483..ab60b845e6fe 100644
--- a/core/java/android/content/Intent.java
+++ b/core/java/android/content/Intent.java
@@ -816,6 +816,28 @@ public class Intent implements Parcelable, Cloneable {
= "android.intent.action.SHOW_APP_INFO";
/**
+ * Activity Action: Start an activity to show the app's detailed usage information for
+ * permission protected data.
+ *
+ * The Intent contains an extra {@link #EXTRA_PERMISSION_USAGE_PERMISSIONS} that is of
+ * type {@code String[]} and contains the specific permissions to show information for.
+ *
+ * Apps should handle this intent if they want to provide more information about permission
+ * usage to users beyond the information provided in the manifest.
+ */
+ @SdkConstant(SdkConstantType.ACTIVITY_INTENT_ACTION)
+ public static final String ACTION_PERMISSION_USAGE_DETAILS =
+ "android.intent.action.PERMISSION_USAGE_DETAILS";
+
+ /**
+ * The name of the extra used to contain the permissions in
+ * {@link #ACTION_PERMISSION_USAGE_DETAILS}.
+ * @see #ACTION_PERMISSION_USAGE_DETAILS
+ */
+ public static final String EXTRA_PERMISSION_USAGE_PERMISSIONS =
+ "android.intent.extra.PERMISSION_USAGE_PERMISSIONS";
+
+ /**
* Represents a shortcut/live folder icon resource.
*
* @see Intent#ACTION_CREATE_SHORTCUT
diff --git a/core/java/android/net/ConnectivityManager.java b/core/java/android/net/ConnectivityManager.java
index 61d5a9127743..23e4ec0567f2 100644
--- a/core/java/android/net/ConnectivityManager.java
+++ b/core/java/android/net/ConnectivityManager.java
@@ -16,6 +16,7 @@
package android.net;
import android.annotation.IntDef;
+import android.annotation.NonNull;
import android.annotation.Nullable;
import android.annotation.RequiresPermission;
import android.annotation.SdkConstant;
@@ -909,6 +910,7 @@ public class ConnectivityManager {
*/
@Deprecated
@RequiresPermission(android.Manifest.permission.ACCESS_NETWORK_STATE)
+ @Nullable
public NetworkInfo getActiveNetworkInfo() {
try {
return mService.getActiveNetworkInfo();
@@ -928,6 +930,7 @@ public class ConnectivityManager {
* {@code null} if no default network is currently active
*/
@RequiresPermission(android.Manifest.permission.ACCESS_NETWORK_STATE)
+ @Nullable
public Network getActiveNetwork() {
try {
return mService.getActiveNetwork();
@@ -949,6 +952,7 @@ public class ConnectivityManager {
* @hide
*/
@RequiresPermission(android.Manifest.permission.CONNECTIVITY_INTERNAL)
+ @Nullable
public Network getActiveNetworkForUid(int uid) {
return getActiveNetworkForUid(uid, false);
}
@@ -1074,6 +1078,7 @@ public class ConnectivityManager {
*/
@Deprecated
@RequiresPermission(android.Manifest.permission.ACCESS_NETWORK_STATE)
+ @Nullable
public NetworkInfo getNetworkInfo(int networkType) {
try {
return mService.getNetworkInfo(networkType);
@@ -1095,7 +1100,8 @@ public class ConnectivityManager {
*/
@Deprecated
@RequiresPermission(android.Manifest.permission.ACCESS_NETWORK_STATE)
- public NetworkInfo getNetworkInfo(Network network) {
+ @Nullable
+ public NetworkInfo getNetworkInfo(@Nullable Network network) {
return getNetworkInfoForUid(network, Process.myUid(), false);
}
@@ -1121,6 +1127,7 @@ public class ConnectivityManager {
*/
@Deprecated
@RequiresPermission(android.Manifest.permission.ACCESS_NETWORK_STATE)
+ @NonNull
public NetworkInfo[] getAllNetworkInfo() {
try {
return mService.getAllNetworkInfo();
@@ -1156,6 +1163,7 @@ public class ConnectivityManager {
* @return an array of {@link Network} objects.
*/
@RequiresPermission(android.Manifest.permission.ACCESS_NETWORK_STATE)
+ @NonNull
public Network[] getAllNetworks() {
try {
return mService.getAllNetworks();
@@ -1230,7 +1238,8 @@ public class ConnectivityManager {
* @return The {@link LinkProperties} for the network, or {@code null}.
*/
@RequiresPermission(android.Manifest.permission.ACCESS_NETWORK_STATE)
- public LinkProperties getLinkProperties(Network network) {
+ @Nullable
+ public LinkProperties getLinkProperties(@Nullable Network network) {
try {
return mService.getLinkProperties(network);
} catch (RemoteException e) {
@@ -1246,7 +1255,8 @@ public class ConnectivityManager {
* @return The {@link android.net.NetworkCapabilities} for the network, or {@code null}.
*/
@RequiresPermission(android.Manifest.permission.ACCESS_NETWORK_STATE)
- public NetworkCapabilities getNetworkCapabilities(Network network) {
+ @Nullable
+ public NetworkCapabilities getNetworkCapabilities(@Nullable Network network) {
try {
return mService.getNetworkCapabilities(network);
} catch (RemoteException e) {
@@ -2000,7 +2010,7 @@ public class ConnectivityManager {
*
* @param l Previously registered listener.
*/
- public void removeDefaultNetworkActiveListener(OnNetworkActiveListener l) {
+ public void removeDefaultNetworkActiveListener(@NonNull OnNetworkActiveListener l) {
INetworkActivityListener rl = mNetworkActivityListeners.get(l);
Preconditions.checkArgument(rl != null, "Listener was not registered.");
try {
@@ -2528,7 +2538,7 @@ public class ConnectivityManager {
* working and non-working connectivity.
*/
@Deprecated
- public void reportBadNetwork(Network network) {
+ public void reportBadNetwork(@Nullable Network network) {
printStackTrace();
try {
// One of these will be ignored because it matches system's current state.
@@ -2551,7 +2561,7 @@ public class ConnectivityManager {
* @param hasConnectivity {@code true} if the application was able to successfully access the
* Internet using {@code network} or {@code false} if not.
*/
- public void reportNetworkConnectivity(Network network, boolean hasConnectivity) {
+ public void reportNetworkConnectivity(@Nullable Network network, boolean hasConnectivity) {
printStackTrace();
try {
mService.reportNetworkConnectivity(network, hasConnectivity);
@@ -2625,6 +2635,7 @@ public class ConnectivityManager {
* @return the {@link ProxyInfo} for the current HTTP proxy, or {@code null} if no
* HTTP proxy is active.
*/
+ @Nullable
public ProxyInfo getDefaultProxy() {
return getProxyForNetwork(getBoundNetworkForProcess());
}
@@ -3156,8 +3167,9 @@ public class ConnectivityManager {
*
* @hide
*/
- public void requestNetwork(NetworkRequest request, NetworkCallback networkCallback,
- int timeoutMs, int legacyType, Handler handler) {
+ public void requestNetwork(@NonNull NetworkRequest request,
+ @NonNull NetworkCallback networkCallback, int timeoutMs, int legacyType,
+ @NonNull Handler handler) {
CallbackHandler cbHandler = new CallbackHandler(handler);
NetworkCapabilities nc = request.networkCapabilities;
sendRequestForNetwork(nc, networkCallback, timeoutMs, REQUEST, legacyType, cbHandler);
@@ -3194,7 +3206,8 @@ public class ConnectivityManager {
* @throws IllegalArgumentException if {@code request} specifies any mutable
* {@code NetworkCapabilities}.
*/
- public void requestNetwork(NetworkRequest request, NetworkCallback networkCallback) {
+ public void requestNetwork(@NonNull NetworkRequest request,
+ @NonNull NetworkCallback networkCallback) {
requestNetwork(request, networkCallback, getDefaultHandler());
}
@@ -3229,8 +3242,8 @@ public class ConnectivityManager {
* @throws IllegalArgumentException if {@code request} specifies any mutable
* {@code NetworkCapabilities}.
*/
- public void requestNetwork(
- NetworkRequest request, NetworkCallback networkCallback, Handler handler) {
+ public void requestNetwork(@NonNull NetworkRequest request,
+ @NonNull NetworkCallback networkCallback, @NonNull Handler handler) {
int legacyType = inferLegacyTypeForNetworkCapabilities(request.networkCapabilities);
CallbackHandler cbHandler = new CallbackHandler(handler);
requestNetwork(request, networkCallback, 0, legacyType, cbHandler);
@@ -3264,8 +3277,8 @@ public class ConnectivityManager {
* before {@link NetworkCallback#onUnavailable()} is called. The timeout must
* be a positive value (i.e. >0).
*/
- public void requestNetwork(NetworkRequest request, NetworkCallback networkCallback,
- int timeoutMs) {
+ public void requestNetwork(@NonNull NetworkRequest request,
+ @NonNull NetworkCallback networkCallback, int timeoutMs) {
checkTimeout(timeoutMs);
int legacyType = inferLegacyTypeForNetworkCapabilities(request.networkCapabilities);
requestNetwork(request, networkCallback, timeoutMs, legacyType, getDefaultHandler());
@@ -3298,8 +3311,8 @@ public class ConnectivityManager {
* @param timeoutMs The time in milliseconds to attempt looking for a suitable network
* before {@link NetworkCallback#onUnavailable} is called.
*/
- public void requestNetwork(NetworkRequest request, NetworkCallback networkCallback,
- Handler handler, int timeoutMs) {
+ public void requestNetwork(@NonNull NetworkRequest request,
+ @NonNull NetworkCallback networkCallback, @NonNull Handler handler, int timeoutMs) {
checkTimeout(timeoutMs);
int legacyType = inferLegacyTypeForNetworkCapabilities(request.networkCapabilities);
CallbackHandler cbHandler = new CallbackHandler(handler);
@@ -3371,7 +3384,8 @@ public class ConnectivityManager {
* {@link NetworkCapabilities#NET_CAPABILITY_VALIDATED} or
* {@link NetworkCapabilities#NET_CAPABILITY_CAPTIVE_PORTAL}.
*/
- public void requestNetwork(NetworkRequest request, PendingIntent operation) {
+ public void requestNetwork(@NonNull NetworkRequest request,
+ @NonNull PendingIntent operation) {
printStackTrace();
checkPendingIntentNotNull(operation);
try {
@@ -3395,7 +3409,7 @@ public class ConnectivityManager {
* {@link #requestNetwork(NetworkRequest, android.app.PendingIntent)} with the
* corresponding NetworkRequest you'd like to remove. Cannot be null.
*/
- public void releaseNetworkRequest(PendingIntent operation) {
+ public void releaseNetworkRequest(@NonNull PendingIntent operation) {
printStackTrace();
checkPendingIntentNotNull(operation);
try {
@@ -3428,7 +3442,8 @@ public class ConnectivityManager {
* The callback is invoked on the default internal Handler.
*/
@RequiresPermission(android.Manifest.permission.ACCESS_NETWORK_STATE)
- public void registerNetworkCallback(NetworkRequest request, NetworkCallback networkCallback) {
+ public void registerNetworkCallback(@NonNull NetworkRequest request,
+ @NonNull NetworkCallback networkCallback) {
registerNetworkCallback(request, networkCallback, getDefaultHandler());
}
@@ -3443,8 +3458,8 @@ public class ConnectivityManager {
* @param handler {@link Handler} to specify the thread upon which the callback will be invoked.
*/
@RequiresPermission(android.Manifest.permission.ACCESS_NETWORK_STATE)
- public void registerNetworkCallback(
- NetworkRequest request, NetworkCallback networkCallback, Handler handler) {
+ public void registerNetworkCallback(@NonNull NetworkRequest request,
+ @NonNull NetworkCallback networkCallback, @NonNull Handler handler) {
CallbackHandler cbHandler = new CallbackHandler(handler);
NetworkCapabilities nc = request.networkCapabilities;
sendRequestForNetwork(nc, networkCallback, 0, LISTEN, TYPE_NONE, cbHandler);
@@ -3480,7 +3495,8 @@ public class ConnectivityManager {
* comes from {@link PendingIntent#getBroadcast}. Cannot be null.
*/
@RequiresPermission(android.Manifest.permission.ACCESS_NETWORK_STATE)
- public void registerNetworkCallback(NetworkRequest request, PendingIntent operation) {
+ public void registerNetworkCallback(@NonNull NetworkRequest request,
+ @NonNull PendingIntent operation) {
printStackTrace();
checkPendingIntentNotNull(operation);
try {
@@ -3502,7 +3518,7 @@ public class ConnectivityManager {
* The callback is invoked on the default internal Handler.
*/
@RequiresPermission(android.Manifest.permission.ACCESS_NETWORK_STATE)
- public void registerDefaultNetworkCallback(NetworkCallback networkCallback) {
+ public void registerDefaultNetworkCallback(@NonNull NetworkCallback networkCallback) {
registerDefaultNetworkCallback(networkCallback, getDefaultHandler());
}
@@ -3516,7 +3532,8 @@ public class ConnectivityManager {
* @param handler {@link Handler} to specify the thread upon which the callback will be invoked.
*/
@RequiresPermission(android.Manifest.permission.ACCESS_NETWORK_STATE)
- public void registerDefaultNetworkCallback(NetworkCallback networkCallback, Handler handler) {
+ public void registerDefaultNetworkCallback(@NonNull NetworkCallback networkCallback,
+ @NonNull Handler handler) {
// This works because if the NetworkCapabilities are null,
// ConnectivityService takes them from the default request.
//
@@ -3541,7 +3558,7 @@ public class ConnectivityManager {
* @param network {@link Network} specifying which network you're interested.
* @return {@code true} on success, {@code false} if the {@link Network} is no longer valid.
*/
- public boolean requestBandwidthUpdate(Network network) {
+ public boolean requestBandwidthUpdate(@NonNull Network network) {
try {
return mService.requestBandwidthUpdate(network);
} catch (RemoteException e) {
@@ -3562,7 +3579,7 @@ public class ConnectivityManager {
*
* @param networkCallback The {@link NetworkCallback} used when making the request.
*/
- public void unregisterNetworkCallback(NetworkCallback networkCallback) {
+ public void unregisterNetworkCallback(@NonNull NetworkCallback networkCallback) {
printStackTrace();
checkCallbackNotNull(networkCallback);
final List<NetworkRequest> reqs = new ArrayList<>();
@@ -3601,7 +3618,7 @@ public class ConnectivityManager {
* {@link #registerNetworkCallback(NetworkRequest, android.app.PendingIntent)}.
* Cannot be null.
*/
- public void unregisterNetworkCallback(PendingIntent operation) {
+ public void unregisterNetworkCallback(@NonNull PendingIntent operation) {
checkPendingIntentNotNull(operation);
releaseNetworkRequest(operation);
}
@@ -3723,7 +3740,7 @@ public class ConnectivityManager {
* @return a bitwise OR of zero or more of the {@code MULTIPATH_PREFERENCE_*} constants.
*/
@RequiresPermission(android.Manifest.permission.ACCESS_NETWORK_STATE)
- public @MultipathPreference int getMultipathPreference(Network network) {
+ public @MultipathPreference int getMultipathPreference(@Nullable Network network) {
try {
return mService.getMultipathPreference(network);
} catch (RemoteException e) {
@@ -3761,7 +3778,7 @@ public class ConnectivityManager {
* the current binding.
* @return {@code true} on success, {@code false} if the {@link Network} is no longer valid.
*/
- public boolean bindProcessToNetwork(Network network) {
+ public boolean bindProcessToNetwork(@Nullable Network network) {
// Forcing callers to call through non-static function ensures ConnectivityManager
// instantiated.
return setProcessDefaultNetwork(network);
@@ -3789,7 +3806,7 @@ public class ConnectivityManager {
* is a direct replacement.
*/
@Deprecated
- public static boolean setProcessDefaultNetwork(Network network) {
+ public static boolean setProcessDefaultNetwork(@Nullable Network network) {
int netId = (network == null) ? NETID_UNSET : network.netId;
if (netId == NetworkUtils.getBoundNetworkForProcess()) {
return true;
@@ -3820,6 +3837,7 @@ public class ConnectivityManager {
*
* @return {@code Network} to which this process is bound, or {@code null}.
*/
+ @Nullable
public Network getBoundNetworkForProcess() {
// Forcing callers to call thru non-static function ensures ConnectivityManager
// instantiated.
@@ -3836,6 +3854,7 @@ public class ConnectivityManager {
* {@code getBoundNetworkForProcess} is a direct replacement.
*/
@Deprecated
+ @Nullable
public static Network getProcessDefaultNetwork() {
int netId = NetworkUtils.getBoundNetworkForProcess();
if (netId == NETID_UNSET) return null;
@@ -3962,6 +3981,7 @@ public class ConnectivityManager {
*
* @return Hash of network watchlist config file. Null if config does not exist.
*/
+ @Nullable
public byte[] getNetworkWatchlistConfigHash() {
try {
return mService.getNetworkWatchlistConfigHash();
@@ -3983,8 +4003,8 @@ public class ConnectivityManager {
* (e.g., if it is associated with the calling VPN app's tunnel) or
* {@link android.os.Process#INVALID_UID} if the connection is not found.
*/
- public int getConnectionOwnerUid(int protocol, InetSocketAddress local,
- InetSocketAddress remote) {
+ public int getConnectionOwnerUid(int protocol, @NonNull InetSocketAddress local,
+ @NonNull InetSocketAddress remote) {
ConnectionInfo connectionInfo = new ConnectionInfo(protocol, local, remote);
try {
return mService.getConnectionOwnerUid(connectionInfo);
diff --git a/core/java/android/net/dhcp/DhcpServingParamsParcel.aidl b/core/java/android/net/dhcp/DhcpServingParamsParcel.aidl
new file mode 100644
index 000000000000..7b8b9ee324bc
--- /dev/null
+++ b/core/java/android/net/dhcp/DhcpServingParamsParcel.aidl
@@ -0,0 +1,30 @@
+/**
+ *
+ * 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 android.net.dhcp;
+
+parcelable DhcpServingParamsParcel {
+ int serverAddr;
+ int serverAddrPrefixLength;
+ int[] defaultRouters;
+ int[] dnsServers;
+ int[] excludedAddrs;
+ long dhcpLeaseTimeSecs;
+ int linkMtu;
+ boolean metered;
+}
+
diff --git a/core/java/android/os/GraphicsEnvironment.java b/core/java/android/os/GraphicsEnvironment.java
index d9793097fc3a..4c0ee6fcaa43 100644
--- a/core/java/android/os/GraphicsEnvironment.java
+++ b/core/java/android/os/GraphicsEnvironment.java
@@ -353,26 +353,6 @@ public class GraphicsEnvironment {
}
/**
- * Attempt to setup ANGLE with a (temporary) default rules file: b/121153494
- * True: Rules file was loaded.
- * False: Rules file was *not* loaded.
- */
- private boolean setupAngleRulesDebug(String packageName, String paths, String devOptIn) {
- // b/121153494
- // Skip APK rules file checking.
- if (!DEBUG) {
- Log.v(TAG, "Skipping loading the rules file.");
- // Fill in some default values for now, so the loader can get an answer when it asks.
- // Most importantly, we need to indicate which app we are init'ing and what the
- // developer options for it are so we can turn on ANGLE if needed.
- setAngleInfo(paths, packageName, devOptIn, null, 0, 0);
- return true;
- }
-
- return false;
- }
-
- /**
* Attempt to setup ANGLE with a rules file loaded from the ANGLE APK.
* True: APK rules file was loaded.
* False: APK rules file was *not* loaded.
@@ -450,12 +430,6 @@ public class GraphicsEnvironment {
return;
}
- // b/121153494
- if (setupAngleRulesDebug(packageName, paths, devOptIn)) {
- // We setup ANGLE with defaults, so we're done here.
- return;
- }
-
if (setupAngleRulesApk(anglePkgName, angleInfo, context, packageName, paths, devOptIn)) {
// We setup ANGLE with rules from the APK, so we're done here.
return;
diff --git a/core/java/android/os/Trace.java b/core/java/android/os/Trace.java
index 6ea155fe70f8..980140675959 100644
--- a/core/java/android/os/Trace.java
+++ b/core/java/android/os/Trace.java
@@ -95,6 +95,8 @@ public final class Trace {
public static final long TRACE_TAG_AIDL = 1L << 24;
/** @hide */
public static final long TRACE_TAG_NNAPI = 1L << 25;
+ /** @hide */
+ public static final long TRACE_TAG_RRO = 1L << 26;
private static final long TRACE_TAG_NOT_READY = 1L << 63;
private static final int MAX_SECTION_NAME_LEN = 127;
diff --git a/core/java/android/os/UpdateEngine.java b/core/java/android/os/UpdateEngine.java
index 8f2826c16b63..1df3dad9530b 100644
--- a/core/java/android/os/UpdateEngine.java
+++ b/core/java/android/os/UpdateEngine.java
@@ -66,6 +66,7 @@ public class UpdateEngine {
public static final int PAYLOAD_HASH_MISMATCH_ERROR = 10;
public static final int PAYLOAD_SIZE_MISMATCH_ERROR = 11;
public static final int DOWNLOAD_PAYLOAD_VERIFICATION_ERROR = 12;
+ public static final int PAYLOAD_TIMESTAMP_ERROR = 51;
public static final int UPDATED_BUT_NOT_ACTIVE = 52;
}
diff --git a/core/java/android/permission/IPermissionController.aidl b/core/java/android/permission/IPermissionController.aidl
index 38951d5466c7..0e18b445fd01 100644
--- a/core/java/android/permission/IPermissionController.aidl
+++ b/core/java/android/permission/IPermissionController.aidl
@@ -17,6 +17,7 @@
package android.permission;
import android.os.RemoteCallback;
+import android.os.Bundle;
/**
* Interface for system apps to communication with the permission controller.
@@ -24,6 +25,8 @@ import android.os.RemoteCallback;
* @hide
*/
oneway interface IPermissionController {
+ void revokeRuntimePermissions(in Bundle request, boolean doDryRun, int reason,
+ String callerPackageName, in RemoteCallback callback);
void getAppPermissions(String packageName, in RemoteCallback callback);
void revokeRuntimePermission(String packageName, String permissionName);
void countPermissionApps(in List<String> permissionNames, boolean countOnlyGranted,
diff --git a/core/java/android/permission/PermissionControllerManager.java b/core/java/android/permission/PermissionControllerManager.java
index 66e8666a8a70..e21a6608bee0 100644
--- a/core/java/android/permission/PermissionControllerManager.java
+++ b/core/java/android/permission/PermissionControllerManager.java
@@ -22,46 +22,97 @@ import static com.android.internal.util.Preconditions.checkCollectionElementsNot
import static com.android.internal.util.Preconditions.checkNotNull;
import android.Manifest;
+import android.annotation.CallbackExecutor;
+import android.annotation.IntDef;
import android.annotation.NonNull;
import android.annotation.Nullable;
import android.annotation.RequiresPermission;
+import android.annotation.SystemApi;
import android.annotation.SystemService;
+import android.annotation.TestApi;
import android.content.ComponentName;
import android.content.Context;
import android.content.Intent;
+import android.content.pm.PackageManager;
import android.content.pm.ResolveInfo;
+import android.os.Binder;
+import android.os.Bundle;
import android.os.Handler;
import android.os.IBinder;
import android.os.RemoteCallback;
import android.os.RemoteException;
import android.os.UserHandle;
+import android.util.ArrayMap;
import android.util.Log;
import com.android.internal.infra.AbstractMultiplePendingRequestsRemoteService;
import com.android.internal.infra.AbstractRemoteService;
+import com.android.internal.util.Preconditions;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
+import java.util.Map;
+import java.util.concurrent.Executor;
/**
- * Interface for communicating with the permission controller from system apps. All UI operations
- * regarding permissions and any changes to the permission state should flow through this
- * interface.
+ * Interface for communicating with the permission controller.
*
* @hide
*/
+@TestApi
+@SystemApi
@SystemService(Context.PERMISSION_CONTROLLER_SERVICE)
public final class PermissionControllerManager {
private static final String TAG = PermissionControllerManager.class.getSimpleName();
/**
* The key for retrieving the result from the returned bundle.
+ *
+ * @hide
*/
public static final String KEY_RESULT =
"android.permission.PermissionControllerManager.key.result";
+ /** @hide */
+ @IntDef(prefix = { "REASON_" }, value = {
+ REASON_MALWARE,
+ REASON_INSTALLER_POLICY_VIOLATION,
+ })
+ @Retention(RetentionPolicy.SOURCE)
+ public @interface Reason {}
+
+ /** The permissions are revoked because the apps holding the permissions are malware */
+ public static final int REASON_MALWARE = 1;
+
+ /**
+ * The permissions are revoked because the apps holding the permissions violate a policy of the
+ * app that installed it.
+ *
+ * <p>If this reason is used only permissions of apps that are installed by the caller of the
+ * API can be revoked.
+ */
+ public static final int REASON_INSTALLER_POLICY_VIOLATION = 2;
+
+ /**
+ * Callback for delivering the result of {@link #revokeRuntimePermissions}.
+ */
+ public abstract static class OnRevokeRuntimePermissionsCallback {
+ /**
+ * The result for {@link #revokeRuntimePermissions}.
+ *
+ * @param revoked The actually revoked permissions as
+ * {@code Map<packageName, List<permission>>}
+ */
+ public abstract void onRevokeRuntimePermissions(@NonNull Map<String, List<String>> revoked);
+ }
+
/**
* Callback for delivering the result of {@link #getAppPermissions}.
+ *
+ * @hide
*/
public interface OnGetAppPermissionResultCallback {
/**
@@ -75,6 +126,8 @@ public final class PermissionControllerManager {
/**
* Callback for delivering the result of {@link #countPermissionApps}.
+ *
+ * @hide
*/
public interface OnCountPermissionAppsResultCallback {
/**
@@ -86,23 +139,61 @@ public final class PermissionControllerManager {
void onCountPermissionApps(int numApps);
}
+ private final @NonNull Context mContext;
private final RemoteService mRemoteService;
+ /** @hide */
public PermissionControllerManager(@NonNull Context context) {
Intent intent = new Intent(SERVICE_INTERFACE);
intent.setPackage(context.getPackageManager().getPermissionControllerPackageName());
ResolveInfo serviceInfo = context.getPackageManager().resolveService(intent, 0);
+ mContext = context;
mRemoteService = new RemoteService(context,
serviceInfo.getComponentInfo().getComponentName());
}
/**
+ * Revoke a set of runtime permissions for various apps.
+ *
+ * @param request The permissions to revoke as {@code Map<packageName, List<permission>>}
+ * @param doDryRun Compute the permissions that would be revoked, but not actually revoke them
+ * @param reason Why the permission should be revoked
+ * @param executor Executor on which to invoke the callback
+ * @param callback Callback to receive the result
+ */
+ @RequiresPermission(Manifest.permission.REVOKE_RUNTIME_PERMISSIONS)
+ public void revokeRuntimePermissions(@NonNull Map<String, List<String>> request,
+ boolean doDryRun, @Reason int reason, @NonNull @CallbackExecutor Executor executor,
+ @NonNull OnRevokeRuntimePermissionsCallback callback) {
+ // Check input to fail immediately instead of inside the async request
+ checkNotNull(executor);
+ checkNotNull(callback);
+ checkNotNull(request);
+ for (Map.Entry<String, List<String>> appRequest : request.entrySet()) {
+ checkNotNull(appRequest.getKey());
+ checkCollectionElementsNotNull(appRequest.getValue(), "permissions");
+ }
+
+ // Check required permission to fail immediately instead of inside the oneway binder call
+ if (mContext.checkSelfPermission(Manifest.permission.REVOKE_RUNTIME_PERMISSIONS)
+ != PackageManager.PERMISSION_GRANTED) {
+ throw new SecurityException(Manifest.permission.REVOKE_RUNTIME_PERMISSIONS
+ + " required");
+ }
+
+ mRemoteService.scheduleRequest(new PendingRevokeRuntimePermissionRequest(mRemoteService,
+ request, doDryRun, reason, mContext.getPackageName(), executor, callback));
+ }
+
+ /**
* Gets the runtime permissions for an app.
*
* @param packageName The package for which to query.
* @param callback Callback to receive the result.
* @param handler Handler on which to invoke the callback.
+ *
+ * @hide
*/
@RequiresPermission(Manifest.permission.GET_RUNTIME_PERMISSIONS)
public void getAppPermissions(@NonNull String packageName,
@@ -119,6 +210,8 @@ public final class PermissionControllerManager {
*
* @param packageName The package for which to revoke
* @param permissionName The permission to revoke
+ *
+ * @hide
*/
@RequiresPermission(Manifest.permission.REVOKE_RUNTIME_PERMISSIONS)
public void revokeRuntimePermission(@NonNull String packageName,
@@ -138,6 +231,8 @@ public final class PermissionControllerManager {
* @param countSystem Also count system apps
* @param callback Callback to receive the result
* @param handler Handler on which to invoke the callback
+ *
+ * @hide
*/
@RequiresPermission(Manifest.permission.GET_RUNTIME_PERMISSIONS)
public void countPermissionApps(@NonNull List<String> permissionNames,
@@ -206,6 +301,84 @@ public final class PermissionControllerManager {
}
/**
+ * Request for {@link #revokeRuntimePermissions}
+ */
+ private static final class PendingRevokeRuntimePermissionRequest extends
+ AbstractRemoteService.PendingRequest<RemoteService, IPermissionController> {
+ private final @NonNull Map<String, List<String>> mRequest;
+ private final boolean mDoDryRun;
+ private final int mReason;
+ private final @NonNull String mCallingPackage;
+ private final @NonNull OnRevokeRuntimePermissionsCallback mCallback;
+
+ private final @NonNull RemoteCallback mRemoteCallback;
+
+ private PendingRevokeRuntimePermissionRequest(@NonNull RemoteService service,
+ @NonNull Map<String, List<String>> request, boolean doDryRun,
+ @Reason int reason, @NonNull String callingPackage,
+ @NonNull @CallbackExecutor Executor executor,
+ @NonNull OnRevokeRuntimePermissionsCallback callback) {
+ super(service);
+
+ mRequest = request;
+ mDoDryRun = doDryRun;
+ mReason = reason;
+ mCallingPackage = callingPackage;
+ mCallback = callback;
+
+ mRemoteCallback = new RemoteCallback(result -> executor.execute(() -> {
+ long token = Binder.clearCallingIdentity();
+ try {
+ Map<String, List<String>> revoked = new ArrayMap<>();
+ try {
+ Bundle bundleizedRevoked = result.getBundle(KEY_RESULT);
+
+ for (String packageName : bundleizedRevoked.keySet()) {
+ Preconditions.checkNotNull(packageName);
+
+ ArrayList<String> permissions =
+ bundleizedRevoked.getStringArrayList(packageName);
+ Preconditions.checkCollectionElementsNotNull(permissions,
+ "permissions");
+
+ revoked.put(packageName, permissions);
+ }
+ } catch (Exception e) {
+ Log.e(TAG, "Could not read result when revoking runtime permissions", e);
+ }
+
+ callback.onRevokeRuntimePermissions(revoked);
+ } finally {
+ Binder.restoreCallingIdentity(token);
+
+ finish();
+ }
+ }), null);
+ }
+
+ @Override
+ protected void onTimeout(RemoteService remoteService) {
+ mCallback.onRevokeRuntimePermissions(Collections.emptyMap());
+ }
+
+ @Override
+ public void run() {
+ Bundle bundledizedRequest = new Bundle();
+ for (Map.Entry<String, List<String>> appRequest : mRequest.entrySet()) {
+ bundledizedRequest.putStringArrayList(appRequest.getKey(),
+ new ArrayList<>(appRequest.getValue()));
+ }
+
+ try {
+ getService().getServiceInterface().revokeRuntimePermissions(bundledizedRequest,
+ mDoDryRun, mReason, mCallingPackage, mRemoteCallback);
+ } catch (RemoteException e) {
+ Log.e(TAG, "Error revoking runtime permission", e);
+ }
+ }
+ }
+
+ /**
* Request for {@link #getAppPermissions}
*/
private static final class PendingGetAppPermissionRequest extends
diff --git a/core/java/android/permission/PermissionControllerService.java b/core/java/android/permission/PermissionControllerService.java
index 5dad07178e53..f621737e5ed4 100644
--- a/core/java/android/permission/PermissionControllerService.java
+++ b/core/java/android/permission/PermissionControllerService.java
@@ -16,6 +16,7 @@
package android.permission;
+import static com.android.internal.util.Preconditions.checkArgument;
import static com.android.internal.util.Preconditions.checkCollectionElementsNotNull;
import static com.android.internal.util.Preconditions.checkNotNull;
import static com.android.internal.util.function.pooled.PooledLambda.obtainMessage;
@@ -26,12 +27,19 @@ import android.annotation.SystemApi;
import android.app.Service;
import android.content.Context;
import android.content.Intent;
+import android.content.pm.PackageInfo;
+import android.content.pm.PackageManager;
import android.os.Bundle;
import android.os.Handler;
import android.os.IBinder;
import android.os.RemoteCallback;
+import android.util.ArrayMap;
+import com.android.internal.util.Preconditions;
+
+import java.util.ArrayList;
import java.util.List;
+import java.util.Map;
/**
* This service is meant to be implemented by the app controlling permissions.
@@ -60,6 +68,20 @@ public abstract class PermissionControllerService extends Service {
}
/**
+ * Revoke a set of runtime permissions for various apps.
+ *
+ * @param requests The permissions to revoke as {@code Map<packageName, List<permission>>}
+ * @param doDryRun Compute the permissions that would be revoked, but not actually revoke them
+ * @param reason Why the permission should be revoked
+ * @param callerPackageName The package name of the calling app
+ *
+ * @return the actually removed permissions as {@code Map<packageName, List<permission>>}
+ */
+ public abstract @NonNull Map<String, List<String>> onRevokeRuntimePermissions(
+ @NonNull Map<String, List<String>> requests, boolean doDryRun,
+ @PermissionControllerManager.Reason int reason, @NonNull String callerPackageName);
+
+ /**
* Gets the runtime permissions for an app.
*
* @param packageName The package for which to query.
@@ -94,6 +116,41 @@ public abstract class PermissionControllerService extends Service {
public final IBinder onBind(Intent intent) {
return new IPermissionController.Stub() {
@Override
+ public void revokeRuntimePermissions(
+ Bundle bundleizedRequest, boolean doDryRun, int reason,
+ String callerPackageName, RemoteCallback callback) {
+ checkNotNull(bundleizedRequest, "bundleizedRequest");
+ checkNotNull(callerPackageName);
+ checkNotNull(callback);
+
+ Map<String, List<String>> request = new ArrayMap<>();
+ for (String packageName : bundleizedRequest.keySet()) {
+ Preconditions.checkNotNull(packageName);
+
+ ArrayList<String> permissions =
+ bundleizedRequest.getStringArrayList(packageName);
+ Preconditions.checkCollectionElementsNotNull(permissions, "permissions");
+
+ request.put(packageName, permissions);
+ }
+
+ enforceCallingPermission(Manifest.permission.REVOKE_RUNTIME_PERMISSIONS, null);
+
+ // Verify callerPackageName
+ try {
+ PackageInfo pkgInfo = getPackageManager().getPackageInfo(callerPackageName, 0);
+ checkArgument(getCallingUid() == pkgInfo.applicationInfo.uid);
+ } catch (PackageManager.NameNotFoundException e) {
+ throw new RuntimeException(e);
+ }
+
+ mHandler.sendMessage(obtainMessage(
+ PermissionControllerService::revokeRuntimePermissions,
+ PermissionControllerService.this, request, doDryRun, reason,
+ callerPackageName, callback));
+ }
+
+ @Override
public void getAppPermissions(String packageName, RemoteCallback callback) {
checkNotNull(packageName, "packageName");
checkNotNull(callback, "callback");
@@ -133,6 +190,27 @@ public abstract class PermissionControllerService extends Service {
};
}
+ private void revokeRuntimePermissions(@NonNull Map<String, List<String>> requests,
+ boolean doDryRun, @PermissionControllerManager.Reason int reason,
+ @NonNull String callerPackageName, @NonNull RemoteCallback callback) {
+ Map<String, List<String>> revoked = onRevokeRuntimePermissions(requests,
+ doDryRun, reason, callerPackageName);
+
+ checkNotNull(revoked);
+ Bundle bundledizedRevoked = new Bundle();
+ for (Map.Entry<String, List<String>> appRevocation : revoked.entrySet()) {
+ checkNotNull(appRevocation.getKey());
+ checkCollectionElementsNotNull(appRevocation.getValue(), "permissions");
+
+ bundledizedRevoked.putStringArrayList(appRevocation.getKey(),
+ new ArrayList<>(appRevocation.getValue()));
+ }
+
+ Bundle result = new Bundle();
+ result.putBundle(PermissionControllerManager.KEY_RESULT, bundledizedRevoked);
+ callback.sendResult(result);
+ }
+
private void getAppPermissions(@NonNull String packageName, @NonNull RemoteCallback callback) {
List<RuntimePermissionPresentationInfo> permissions = onGetAppPermissions(packageName);
if (permissions != null && !permissions.isEmpty()) {
diff --git a/core/java/android/permission/TEST_MAPPING b/core/java/android/permission/TEST_MAPPING
new file mode 100644
index 000000000000..ba9f36a31f2e
--- /dev/null
+++ b/core/java/android/permission/TEST_MAPPING
@@ -0,0 +1,12 @@
+{
+ "presubmit": [
+ {
+ "name": "CtsPermissionTestCases",
+ "options": [
+ {
+ "include-filter": "android.permission.cts.PermissionControllerTest"
+ }
+ ]
+ }
+ ]
+} \ No newline at end of file
diff --git a/core/java/android/provider/Settings.java b/core/java/android/provider/Settings.java
index bb1784af6c85..5bb5ee880398 100644
--- a/core/java/android/provider/Settings.java
+++ b/core/java/android/provider/Settings.java
@@ -6207,7 +6207,7 @@ public final class Settings {
public static final String CHARGING_SOUNDS_ENABLED = "charging_sounds_enabled";
/**
- * Whether to vibrate for wireless charging events.
+ * Whether to vibrate for charging events.
* @hide
*/
public static final String CHARGING_VIBRATION_ENABLED = "charging_vibration_enabled";
@@ -8882,6 +8882,14 @@ public final class Settings {
public static final String ADD_USERS_WHEN_LOCKED = "add_users_when_locked";
/**
+ * Whether applying ramping ringer on incoming phone call ringtone.
+ * <p>1 = apply ramping ringer
+ * <p>0 = do not apply ramping ringer
+ * @hide
+ */
+ public static final String APPLY_RAMPING_RINGER = "apply_ramping_ringer";
+
+ /**
* Setting whether the global gesture for enabling accessibility is enabled.
* If this gesture is enabled the user will be able to perfrom it to enable
* the accessibility state without visiting the settings app.
@@ -9415,7 +9423,8 @@ public final class Settings {
"hdmi_control_auto_wakeup_enabled";
/**
- * Whether TV will also turn off other CEC devices when it goes to standby mode.
+ * Whether TV or Audio System will also turn off other CEC devices when it goes to standby
+ * mode.
* (0 = false, 1 = true)
*
* @hide
@@ -9424,6 +9433,15 @@ public final class Settings {
"hdmi_control_auto_device_off_enabled";
/**
+ * Whether Audio System will also turn off TV when it goes to standby mode.
+ * (0 = false, 1 = true)
+ *
+ * @hide
+ */
+ public static final String HDMI_CONTROL_AUTO_TV_OFF_ENABLED =
+ "hdmi_control_auto_tv_off_enabled";
+
+ /**
* If <b>true</b>, enables out-of-the-box execution for priv apps.
* Default: false
* Values: 0 = false, 1 = true
diff --git a/core/java/android/service/autofill/augmented/AugmentedAutofillService.java b/core/java/android/service/autofill/augmented/AugmentedAutofillService.java
index 7683b8ae08b2..a9f4034c37af 100644
--- a/core/java/android/service/autofill/augmented/AugmentedAutofillService.java
+++ b/core/java/android/service/autofill/augmented/AugmentedAutofillService.java
@@ -214,7 +214,7 @@ public abstract class AugmentedAutofillService extends Service {
}
@Override
- protected void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
+ protected final void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
if (mAutofillProxies != null) {
final int size = mAutofillProxies.size();
pw.print("Number proxies: "); pw.println(size);
@@ -225,6 +225,15 @@ public abstract class AugmentedAutofillService extends Service {
proxy.dump(" ", pw);
}
}
+ dump(pw, args);
+ }
+
+ /**
+ * Implementation specific {@code dump}.
+ */
+ protected void dump(@NonNull PrintWriter pw,
+ @SuppressWarnings("unused") @NonNull String[] args) {
+ pw.print(getClass().getName()); pw.println(": nothing to dump");
}
/** @hide */
diff --git a/core/java/android/service/contentcapture/ContentCaptureEventsRequest.java b/core/java/android/service/contentcapture/ContentCaptureEventsRequest.java
index 784e71993815..db242a2e265e 100644
--- a/core/java/android/service/contentcapture/ContentCaptureEventsRequest.java
+++ b/core/java/android/service/contentcapture/ContentCaptureEventsRequest.java
@@ -34,7 +34,7 @@ import java.util.List;
@SystemApi
@Deprecated
public final class ContentCaptureEventsRequest implements Parcelable {
-// TODO(b/121033016): remove .java and .aidl once service implementation doesn't use it anymore
+// TODO(b/121051220): remove .java and .aidl once service implementation doesn't use it anymore
private final ContentCaptureEvent mEvent;
diff --git a/core/java/android/service/contentcapture/ContentCaptureService.java b/core/java/android/service/contentcapture/ContentCaptureService.java
index c9d46dd701b5..26bf361a8acc 100644
--- a/core/java/android/service/contentcapture/ContentCaptureService.java
+++ b/core/java/android/service/contentcapture/ContentCaptureService.java
@@ -123,12 +123,12 @@ public abstract class ContentCaptureService extends Service {
};
/**
- * List of sessions per UID.
+ * UIDs associated with each session.
*
* <p>This map is populated when an session is started, which is called by the system server
* and can be trusted. Then subsequent calls made by the app are verified against this map.
*/
- private final ArrayMap<String, Integer> mSessionsByUid = new ArrayMap<>();
+ private final ArrayMap<String, Integer> mSessionUids = new ArrayMap<>();
@CallSuper
@Override
@@ -285,13 +285,13 @@ public abstract class ContentCaptureService extends Service {
@Override
@CallSuper
protected void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
- final int size = mSessionsByUid.size();
+ final int size = mSessionUids.size();
pw.print("Number sessions: "); pw.println(size);
if (size > 0) {
final String prefix = " ";
for (int i = 0; i < size; i++) {
- pw.print(prefix); pw.print(mSessionsByUid.keyAt(i));
- pw.print(": uid="); pw.println(mSessionsByUid.valueAt(i));
+ pw.print(prefix); pw.print(mSessionUids.keyAt(i));
+ pw.print(": uid="); pw.println(mSessionUids.valueAt(i));
}
}
}
@@ -309,7 +309,7 @@ public abstract class ContentCaptureService extends Service {
private void handleOnCreateSession(@NonNull ContentCaptureContext context,
@NonNull String sessionId, int uid, IResultReceiver clientReceiver) {
- mSessionsByUid.put(sessionId, uid);
+ mSessionUids.put(sessionId, uid);
onCreateContentCaptureSession(context, new ContentCaptureSessionId(sessionId));
setClientState(clientReceiver, ContentCaptureSession.STATE_ACTIVE,
mClientInterface.asBinder());
@@ -336,11 +336,11 @@ public abstract class ContentCaptureService extends Service {
case ContentCaptureEvent.TYPE_SESSION_STARTED:
final ContentCaptureContext clientContext = event.getClientContext();
clientContext.setParentSessionId(event.getParentSessionId());
- mSessionsByUid.put(sessionIdString, uid);
+ mSessionUids.put(sessionIdString, uid);
onCreateContentCaptureSession(clientContext, sessionId);
break;
case ContentCaptureEvent.TYPE_SESSION_FINISHED:
- mSessionsByUid.remove(sessionIdString);
+ mSessionUids.remove(sessionIdString);
onDestroyContentCaptureSession(sessionId);
break;
default:
@@ -355,7 +355,7 @@ public abstract class ContentCaptureService extends Service {
}
private void handleFinishSession(@NonNull String sessionId) {
- mSessionsByUid.remove(sessionId);
+ mSessionUids.remove(sessionId);
onDestroyContentCaptureSession(new ContentCaptureSessionId(sessionId));
}
@@ -372,10 +372,13 @@ public abstract class ContentCaptureService extends Service {
default:
sessionId = event.getSessionId();
}
- final Integer rightUid = mSessionsByUid.get(sessionId);
+ final Integer rightUid = mSessionUids.get(sessionId);
if (rightUid == null) {
- if (VERBOSE) Log.v(TAG, "No session for " + sessionId);
- // Just ignore, as the session could have finished
+ if (DEBUG) {
+ Log.d(TAG, "handleIsRightCallerFor(" + event + "): no session for " + sessionId
+ + ": " + mSessionUids);
+ }
+ // Just ignore, as the session could have been finished already
return false;
}
if (rightUid != uid) {
diff --git a/core/java/android/service/wallpaper/IWallpaperConnection.aidl b/core/java/android/service/wallpaper/IWallpaperConnection.aidl
index a976d0e40423..f334d9d3e874 100644
--- a/core/java/android/service/wallpaper/IWallpaperConnection.aidl
+++ b/core/java/android/service/wallpaper/IWallpaperConnection.aidl
@@ -27,5 +27,5 @@ interface IWallpaperConnection {
void attachEngine(IWallpaperEngine engine, int displayId);
void engineShown(IWallpaperEngine engine);
ParcelFileDescriptor setWallpaper(String name);
- void onWallpaperColorsChanged(in WallpaperColors colors);
+ void onWallpaperColorsChanged(in WallpaperColors colors, int displayId);
}
diff --git a/core/java/android/service/wallpaper/WallpaperService.java b/core/java/android/service/wallpaper/WallpaperService.java
index a011d677fc6a..984846e33b1d 100644
--- a/core/java/android/service/wallpaper/WallpaperService.java
+++ b/core/java/android/service/wallpaper/WallpaperService.java
@@ -56,6 +56,7 @@ import android.view.InputEvent;
import android.view.InputEventReceiver;
import android.view.InsetsState;
import android.view.MotionEvent;
+import android.view.SurfaceControl;
import android.view.SurfaceHolder;
import android.view.View;
import android.view.ViewGroup;
@@ -217,6 +218,8 @@ public abstract class WallpaperService extends Service {
private Context mDisplayContext;
private int mDisplayState;
+ SurfaceControl mSurfaceControl = new SurfaceControl();
+
final BaseSurfaceHolder mSurfaceHolder = new BaseSurfaceHolder() {
{
mRequestedFormat = PixelFormat.RGBX_8888;
@@ -642,7 +645,7 @@ public abstract class WallpaperService extends Service {
try {
final WallpaperColors newColors = onComputeColors();
if (mConnection != null) {
- mConnection.onWallpaperColorsChanged(newColors);
+ mConnection.onWallpaperColorsChanged(newColors, mDisplay.getDisplayId());
} else {
Log.w(TAG, "Can't notify system because wallpaper connection "
+ "was not established.");
@@ -843,8 +846,12 @@ public abstract class WallpaperService extends Service {
mWindow, mWindow.mSeq, mLayout, mWidth, mHeight,
View.VISIBLE, 0, -1, mWinFrame, mOverscanInsets, mContentInsets,
mVisibleInsets, mStableInsets, mOutsets, mBackdropFrame,
- mDisplayCutout, mMergedConfiguration, mSurfaceHolder.mSurface,
+ mDisplayCutout, mMergedConfiguration, mSurfaceControl,
mInsetsState);
+ if (mSurfaceControl.isValid()) {
+ mSurfaceHolder.mSurface.copyFrom(mSurfaceControl);
+ mSurfaceControl.release();
+ }
if (DEBUG) Log.v(TAG, "New surface: " + mSurfaceHolder.mSurface
+ ", frame=" + mWinFrame);
@@ -1466,7 +1473,7 @@ public abstract class WallpaperService extends Service {
break;
}
try {
- mConnection.onWallpaperColorsChanged(mEngine.onComputeColors());
+ mConnection.onWallpaperColorsChanged(mEngine.onComputeColors(), mDisplayId);
} catch (RemoteException e) {
// Connection went away, nothing to do in here.
}
diff --git a/core/java/android/view/IWindowSession.aidl b/core/java/android/view/IWindowSession.aidl
index d1115c7b4d1d..658f06ad21f9 100644
--- a/core/java/android/view/IWindowSession.aidl
+++ b/core/java/android/view/IWindowSession.aidl
@@ -99,7 +99,7 @@ interface IWindowSession {
out Rect outContentInsets, out Rect outVisibleInsets, out Rect outStableInsets,
out Rect outOutsets, out Rect outBackdropFrame,
out DisplayCutout.ParcelableWrapper displayCutout,
- out MergedConfiguration outMergedConfiguration, out Surface outSurface,
+ out MergedConfiguration outMergedConfiguration, out SurfaceControl outSurfaceControl,
out InsetsState insetsState);
/*
diff --git a/core/java/android/view/SurfaceControl.java b/core/java/android/view/SurfaceControl.java
index 1a708e8e30ec..0b6beba06555 100644
--- a/core/java/android/view/SurfaceControl.java
+++ b/core/java/android/view/SurfaceControl.java
@@ -67,6 +67,7 @@ public class SurfaceControl implements Parcelable {
int w, int h, int format, int flags, long parentObject, int windowType, int ownerUid)
throws OutOfResourcesException;
private static native long nativeReadFromParcel(Parcel in);
+ private static native long nativeCopyFromSurfaceControl(long nativeObject);
private static native void nativeWriteToParcel(long nativeObject, Parcel out);
private static native void nativeRelease(long nativeObject);
private static native void nativeDestroy(long nativeObject);
@@ -169,7 +170,7 @@ public class SurfaceControl implements Parcelable {
IBinder toToken);
private final CloseGuard mCloseGuard = CloseGuard.get();
- private final String mName;
+ private String mName;
long mNativeObject; // package visibility only for Surface.java access
// TODO: Move this to native.
@@ -359,6 +360,13 @@ public class SurfaceControl implements Parcelable {
*/
public static final int WINDOW_TYPE_DONT_SCREENSHOT = 441731;
+ public void copyFrom(SurfaceControl other) {
+ mName = other.mName;
+ mWidth = other.mWidth;
+ mHeight = other.mHeight;
+ mNativeObject = nativeCopyFromSurfaceControl(other.mNativeObject);
+ }
+
/**
* Builder class for {@link SurfaceControl} objects.
*/
@@ -660,14 +668,29 @@ public class SurfaceControl implements Parcelable {
}
private SurfaceControl(Parcel in) {
+ readFromParcel(in);
+ mCloseGuard.open("release");
+ }
+
+ public SurfaceControl() {
+ mCloseGuard.open("release");
+ }
+
+ public void readFromParcel(Parcel in) {
+ if (in == null) {
+ throw new IllegalArgumentException("source must not be null");
+ }
+
mName = in.readString();
mWidth = in.readInt();
mHeight = in.readInt();
- mNativeObject = nativeReadFromParcel(in);
- if (mNativeObject == 0) {
- throw new IllegalArgumentException("Couldn't read SurfaceControl from parcel=" + in);
+
+ release();
+ if (in.readInt() != 0) {
+ mNativeObject = nativeReadFromParcel(in);
+ } else {
+ mNativeObject = 0;
}
- mCloseGuard.open("release");
}
@Override
@@ -680,7 +703,16 @@ public class SurfaceControl implements Parcelable {
dest.writeString(mName);
dest.writeInt(mWidth);
dest.writeInt(mHeight);
+ if (mNativeObject == 0) {
+ dest.writeInt(0);
+ } else {
+ dest.writeInt(1);
+ }
nativeWriteToParcel(mNativeObject, dest);
+
+ if ((flags & Parcelable.PARCELABLE_WRITE_RETURN_VALUE) != 0) {
+ release();
+ }
}
/**
@@ -763,6 +795,10 @@ public class SurfaceControl implements Parcelable {
"mNativeObject is null. Have you called release() already?");
}
+ public boolean isValid() {
+ return mNativeObject != 0;
+ }
+
/*
* set surface parameters.
* needs to be inside open/closeTransaction block
diff --git a/core/java/android/view/SurfaceSession.java b/core/java/android/view/SurfaceSession.java
index a4fa12a57e93..361ac932758e 100644
--- a/core/java/android/view/SurfaceSession.java
+++ b/core/java/android/view/SurfaceSession.java
@@ -30,7 +30,6 @@ public final class SurfaceSession {
private long mNativeClient; // SurfaceComposerClient*
private static native long nativeCreate();
- private static native long nativeCreateScoped(long surfacePtr);
private static native void nativeDestroy(long ptr);
private static native void nativeKill(long ptr);
@@ -40,15 +39,6 @@ public final class SurfaceSession {
mNativeClient = nativeCreate();
}
- public SurfaceSession(Surface root) {
- synchronized (root.mLock) {
- if (root.mNativeObject == 0) {
- throw new IllegalStateException("Surface is not initialized or has been released");
- }
- mNativeClient = nativeCreateScoped(root.mNativeObject);
- }
- }
-
/* no user serviceable parts here ... */
@Override
protected void finalize() throws Throwable {
diff --git a/core/java/android/view/SurfaceView.java b/core/java/android/view/SurfaceView.java
index a0af83d17abd..61fb00d3fe59 100644
--- a/core/java/android/view/SurfaceView.java
+++ b/core/java/android/view/SurfaceView.java
@@ -547,7 +547,7 @@ public class SurfaceView extends View implements ViewRootImpl.WindowStoppedCallb
if (creating) {
viewRoot.createBoundsSurface(mSubLayer);
- mSurfaceSession = new SurfaceSession(viewRoot.mBoundsSurface);
+ mSurfaceSession = new SurfaceSession();
mDeferredDestroySurfaceControl = mSurfaceControl;
updateOpaqueFlag();
@@ -559,6 +559,7 @@ public class SurfaceView extends View implements ViewRootImpl.WindowStoppedCallb
new SurfaceControl.Builder(mSurfaceSession)
.setBufferSize(mSurfaceWidth, mSurfaceHeight)
.setFormat(mFormat)
+ .setParent(viewRoot.getSurfaceControl())
.setFlags(mSurfaceFlags));
} else if (mSurfaceControl == null) {
return;
diff --git a/core/java/android/view/View.java b/core/java/android/view/View.java
index 6b07efc0b448..9dfbf28f925a 100644
--- a/core/java/android/view/View.java
+++ b/core/java/android/view/View.java
@@ -7660,10 +7660,13 @@ public class View implements Drawable.Callback, KeyEvent.Callback,
/**
* Convenience method for sending a {@link AccessibilityEvent#TYPE_ANNOUNCEMENT}
- * {@link AccessibilityEvent} to make an announcement which is related to some
- * sort of a context change for which none of the events representing UI transitions
- * is a good fit. For example, announcing a new page in a book. If accessibility
- * is not enabled this method does nothing.
+ * {@link AccessibilityEvent} to suggest that an accessibility service announce the
+ * specified text to its users.
+ * <p>
+ * Note: The event generated with this API carries no semantic meaning, and is appropriate only
+ * in exceptional situations. Apps can generally achieve correct behavior for accessibility by
+ * accurately supplying the semantics of their UI.
+ * They should not need to specify what exactly is announced to users.
*
* @param text The announcement text.
*/
@@ -25053,9 +25056,10 @@ public class View implements Drawable.Callback, KeyEvent.Callback,
}
final ViewRootImpl root = mAttachInfo.mViewRootImpl;
- final SurfaceSession session = new SurfaceSession(root.mSurface);
+ final SurfaceSession session = new SurfaceSession();
final SurfaceControl surfaceControl = new SurfaceControl.Builder(session)
.setName("drag surface")
+ .setParent(root.getSurfaceControl())
.setBufferSize(shadowSize.x, shadowSize.y)
.setFormat(PixelFormat.TRANSLUCENT)
.build();
diff --git a/core/java/android/view/ViewRootImpl.java b/core/java/android/view/ViewRootImpl.java
index 3f7a5127339d..c0b428359efc 100644
--- a/core/java/android/view/ViewRootImpl.java
+++ b/core/java/android/view/ViewRootImpl.java
@@ -432,6 +432,7 @@ public final class ViewRootImpl implements ViewParent,
// Surface can never be reassigned or cleared (use Surface.clear()).
@UnsupportedAppUsage
public final Surface mSurface = new Surface();
+ private final SurfaceControl mSurfaceControl = new SurfaceControl();
/**
* Child surface of {@code mSurface} with the same bounds as its parent, and crop bounds
@@ -1526,7 +1527,7 @@ public final class ViewRootImpl implements ViewParent,
*/
public void createBoundsSurface(int zOrderLayer) {
if (mSurfaceSession == null) {
- mSurfaceSession = new SurfaceSession(mSurface);
+ mSurfaceSession = new SurfaceSession();
}
if (mBoundsSurfaceControl != null && mBoundsSurface.isValid()) {
return; // surface control for bounds surface already exists.
@@ -1534,6 +1535,7 @@ public final class ViewRootImpl implements ViewParent,
mBoundsSurfaceControl = new SurfaceControl.Builder(mSurfaceSession)
.setName("Bounds for - " + getTitle().toString())
+ .setParent(mSurfaceControl)
.build();
setBoundsSurfaceCrop();
@@ -1567,6 +1569,8 @@ public final class ViewRootImpl implements ViewParent,
private void destroySurface() {
mSurface.release();
+ mSurfaceControl.release();
+
mSurfaceSession = null;
if (mBoundsSurfaceControl != null) {
@@ -6801,7 +6805,12 @@ public final class ViewRootImpl implements ViewParent,
insetsPending ? WindowManagerGlobal.RELAYOUT_INSETS_PENDING : 0, frameNumber,
mTmpFrame, mPendingOverscanInsets, mPendingContentInsets, mPendingVisibleInsets,
mPendingStableInsets, mPendingOutsets, mPendingBackDropFrame, mPendingDisplayCutout,
- mPendingMergedConfiguration, mSurface, mTempInsets);
+ mPendingMergedConfiguration, mSurfaceControl, mTempInsets);
+ if (mSurfaceControl.isValid()) {
+ mSurface.copyFrom(mSurfaceControl);
+ } else {
+ destroySurface();
+ }
mPendingAlwaysConsumeNavBar =
(relayoutResult & WindowManagerGlobal.RELAYOUT_RES_CONSUME_ALWAYS_NAV_BAR) != 0;
@@ -8483,6 +8492,10 @@ public final class ViewRootImpl implements ViewParent,
mActivityRelaunched = true;
}
+ public SurfaceControl getSurfaceControl() {
+ return mSurfaceControl;
+ }
+
/**
* Class for managing the accessibility interaction connection
* based on the global accessibility state.
diff --git a/core/java/android/view/autofill/AutofillManager.java b/core/java/android/view/autofill/AutofillManager.java
index 56f973eb9e46..90ccc257b134 100644
--- a/core/java/android/view/autofill/AutofillManager.java
+++ b/core/java/android/view/autofill/AutofillManager.java
@@ -62,6 +62,7 @@ import com.android.internal.logging.nano.MetricsProto.MetricsEvent;
import com.android.internal.os.IResultReceiver;
import com.android.internal.util.ArrayUtils;
import com.android.internal.util.Preconditions;
+import com.android.internal.util.SyncResultReceiver;
import org.xmlpull.v1.XmlPullParserException;
@@ -75,8 +76,7 @@ import java.util.Arrays;
import java.util.Collections;
import java.util.List;
import java.util.Objects;
-import java.util.concurrent.CountDownLatch;
-import java.util.concurrent.TimeUnit;
+
//TODO: use java.lang.ref.Cleaner once Android supports Java 9
import sun.misc.Cleaner;
@@ -324,6 +324,11 @@ public final class AutofillManager {
public static final int FC_SERVICE_TIMEOUT = 5000;
/**
+ * Timeout for calls to system_server.
+ */
+ private static final int SYNC_CALLS_TIMEOUT_MS = 5000;
+
+ /**
* Makes an authentication id from a request id and a dataset id.
*
* @param requestId The request id.
@@ -612,7 +617,8 @@ public final class AutofillManager {
final AutofillClient client = getClient();
if (client != null) {
- final SyncResultReceiver receiver = new SyncResultReceiver();
+ final SyncResultReceiver receiver = new SyncResultReceiver(
+ SYNC_CALLS_TIMEOUT_MS);
try {
mService.restoreSession(mSessionId, client.autofillClientGetActivityToken(),
mServiceClient.asBinder(), receiver);
@@ -732,9 +738,9 @@ public final class AutofillManager {
*/
@Nullable public FillEventHistory getFillEventHistory() {
try {
- final SyncResultReceiver receiver = new SyncResultReceiver();
+ final SyncResultReceiver receiver = new SyncResultReceiver(SYNC_CALLS_TIMEOUT_MS);
mService.getFillEventHistory(receiver);
- return receiver.getObjectResult(SyncResultReceiver.TYPE_PARCELABLE);
+ return receiver.getParcelableResult();
} catch (RemoteException e) {
e.rethrowFromSystemServer();
return null;
@@ -1287,7 +1293,7 @@ public final class AutofillManager {
public boolean hasEnabledAutofillServices() {
if (mService == null) return false;
- final SyncResultReceiver receiver = new SyncResultReceiver();
+ final SyncResultReceiver receiver = new SyncResultReceiver(SYNC_CALLS_TIMEOUT_MS);
try {
mService.isServiceEnabled(mContext.getUserId(), mContext.getPackageName(), receiver);
return receiver.getIntResult() == 1;
@@ -1304,10 +1310,10 @@ public final class AutofillManager {
public ComponentName getAutofillServiceComponentName() {
if (mService == null) return null;
- final SyncResultReceiver receiver = new SyncResultReceiver();
+ final SyncResultReceiver receiver = new SyncResultReceiver(SYNC_CALLS_TIMEOUT_MS);
try {
mService.getAutofillServiceComponentName(receiver);
- return receiver.getObjectResult(SyncResultReceiver.TYPE_PARCELABLE);
+ return receiver.getParcelableResult();
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
}
@@ -1330,9 +1336,9 @@ public final class AutofillManager {
*/
@Nullable public String getUserDataId() {
try {
- final SyncResultReceiver receiver = new SyncResultReceiver();
+ final SyncResultReceiver receiver = new SyncResultReceiver(SYNC_CALLS_TIMEOUT_MS);
mService.getUserDataId(receiver);
- return receiver.getObjectResult(SyncResultReceiver.TYPE_STRING);
+ return receiver.getStringResult();
} catch (RemoteException e) {
e.rethrowFromSystemServer();
return null;
@@ -1352,9 +1358,9 @@ public final class AutofillManager {
*/
@Nullable public UserData getUserData() {
try {
- final SyncResultReceiver receiver = new SyncResultReceiver();
+ final SyncResultReceiver receiver = new SyncResultReceiver(SYNC_CALLS_TIMEOUT_MS);
mService.getUserData(receiver);
- return receiver.getObjectResult(SyncResultReceiver.TYPE_PARCELABLE);
+ return receiver.getParcelableResult();
} catch (RemoteException e) {
e.rethrowFromSystemServer();
return null;
@@ -1390,7 +1396,7 @@ public final class AutofillManager {
* the user.
*/
public boolean isFieldClassificationEnabled() {
- final SyncResultReceiver receiver = new SyncResultReceiver();
+ final SyncResultReceiver receiver = new SyncResultReceiver(SYNC_CALLS_TIMEOUT_MS);
try {
mService.isFieldClassificationEnabled(receiver);
return receiver.getIntResult() == 1;
@@ -1413,10 +1419,10 @@ public final class AutofillManager {
*/
@Nullable
public String getDefaultFieldClassificationAlgorithm() {
- final SyncResultReceiver receiver = new SyncResultReceiver();
+ final SyncResultReceiver receiver = new SyncResultReceiver(SYNC_CALLS_TIMEOUT_MS);
try {
mService.getDefaultFieldClassificationAlgorithm(receiver);
- return receiver.getObjectResult(SyncResultReceiver.TYPE_STRING);
+ return receiver.getStringResult();
} catch (RemoteException e) {
e.rethrowFromSystemServer();
return null;
@@ -1433,11 +1439,10 @@ public final class AutofillManager {
*/
@NonNull
public List<String> getAvailableFieldClassificationAlgorithms() {
- final SyncResultReceiver receiver = new SyncResultReceiver();
+ final SyncResultReceiver receiver = new SyncResultReceiver(SYNC_CALLS_TIMEOUT_MS);
try {
mService.getAvailableFieldClassificationAlgorithms(receiver);
- final String[] algorithms = receiver
- .getObjectResult(SyncResultReceiver.TYPE_STRING_ARRAY);
+ final String[] algorithms = receiver.getStringArrayResult();
return algorithms != null ? Arrays.asList(algorithms) : Collections.emptyList();
} catch (RemoteException e) {
e.rethrowFromSystemServer();
@@ -1458,7 +1463,7 @@ public final class AutofillManager {
public boolean isAutofillSupported() {
if (mService == null) return false;
- final SyncResultReceiver receiver = new SyncResultReceiver();
+ final SyncResultReceiver receiver = new SyncResultReceiver(SYNC_CALLS_TIMEOUT_MS);
try {
mService.isServiceSupported(mContext.getUserId(), receiver);
return receiver.getIntResult() == 1;
@@ -1582,7 +1587,7 @@ public final class AutofillManager {
final AutofillClient client = getClient();
if (client == null) return; // NOTE: getClient() already logged it..
- final SyncResultReceiver receiver = new SyncResultReceiver();
+ final SyncResultReceiver receiver = new SyncResultReceiver(SYNC_CALLS_TIMEOUT_MS);
mService.startSession(client.autofillClientGetActivityToken(),
mServiceClient.asBinder(), id, bounds, value, mContext.getUserId(),
mCallback != null, flags, client.autofillClientGetComponentName(),
@@ -1665,7 +1670,7 @@ public final class AutofillManager {
mServiceClient = new AutofillManagerClient(this);
try {
final int userId = mContext.getUserId();
- final SyncResultReceiver receiver = new SyncResultReceiver();
+ final SyncResultReceiver receiver = new SyncResultReceiver(SYNC_CALLS_TIMEOUT_MS);
mService.addClient(mServiceClient, userId, receiver);
final int flags = receiver.getIntResult();
mEnabled = (flags & FLAG_ADD_CLIENT_ENABLED) != 0;
@@ -2986,104 +2991,4 @@ public final class AutofillManager {
}
}
}
-
- /**
- * @hide
- */
- public static final class SyncResultReceiver extends IResultReceiver.Stub {
-
- private static final String EXTRA = "EXTRA";
-
- /**
- * How long to block waiting for {@link IResultReceiver} callbacks when calling server.
- */
- private static final long BINDER_TIMEOUT_MS = 5000;
-
- private static final int TYPE_STRING = 0;
- private static final int TYPE_STRING_ARRAY = 1;
- private static final int TYPE_PARCELABLE = 2;
-
- private final CountDownLatch mLatch = new CountDownLatch(1);
- private int mResult;
- private Bundle mBundle;
-
- private void waitResult() {
- try {
- if (!mLatch.await(BINDER_TIMEOUT_MS, TimeUnit.MILLISECONDS)) {
- throw new IllegalStateException("Not called in " + BINDER_TIMEOUT_MS + "ms");
- }
- } catch (InterruptedException e) {
- Thread.currentThread().interrupt();
- }
- }
-
- /**
- * Gets the result from an operation that returns an {@code int}.
- */
- int getIntResult() {
- waitResult();
- return mResult;
- }
-
- /**
- * Gets the result from an operation that returns an {@code Object}.
- *
- * @param type type of expected object.
- */
- @Nullable
- @SuppressWarnings("unchecked")
- <T> T getObjectResult(int type) {
- waitResult();
- if (mBundle == null) {
- return null;
- }
- switch (type) {
- case TYPE_STRING:
- return (T) mBundle.getString(EXTRA);
- case TYPE_STRING_ARRAY:
- return (T) mBundle.getStringArray(EXTRA);
- case TYPE_PARCELABLE:
- return (T) mBundle.getParcelable(EXTRA);
- default:
- throw new IllegalArgumentException("unsupported type: " + type);
- }
- }
-
- @Override
- public void send(int resultCode, Bundle resultData) {
- mResult = resultCode;
- mBundle = resultData;
- mLatch.countDown();
- }
-
- /**
- * Creates a bundle for a {@code String} value.
- */
- @NonNull
- public static Bundle bundleFor(@Nullable String value) {
- final Bundle bundle = new Bundle();
- bundle.putString(EXTRA, value);
- return bundle;
- }
-
- /**
- * Creates a bundle for a {@code String[]} value.
- */
- @NonNull
- public static Bundle bundleFor(@Nullable String[] value) {
- final Bundle bundle = new Bundle();
- bundle.putStringArray(EXTRA, value);
- return bundle;
- }
-
- /**
- * Creates a bundle for a {@code Parcelable} value.
- */
- @NonNull
- public static Bundle bundleFor(@Nullable Parcelable value) {
- final Bundle bundle = new Bundle();
- bundle.putParcelable(EXTRA, value);
- return bundle;
- }
- }
}
diff --git a/core/java/android/view/contentcapture/ChildContentCaptureSession.java b/core/java/android/view/contentcapture/ChildContentCaptureSession.java
index 51668319cde2..04e725e64e9c 100644
--- a/core/java/android/view/contentcapture/ChildContentCaptureSession.java
+++ b/core/java/android/view/contentcapture/ChildContentCaptureSession.java
@@ -33,7 +33,7 @@ import java.io.PrintWriter;
final class ChildContentCaptureSession extends ContentCaptureSession {
@NonNull
- private final MainContentCaptureSession mParent;
+ private final ContentCaptureSession mParent;
/**
* {@link ContentCaptureContext} set by client, or {@code null} when it's the
@@ -46,16 +46,25 @@ final class ChildContentCaptureSession extends ContentCaptureSession {
private final ContentCaptureContext mClientContext;
/** @hide */
- protected ChildContentCaptureSession(@NonNull MainContentCaptureSession parent,
+ protected ChildContentCaptureSession(@NonNull ContentCaptureSession parent,
@NonNull ContentCaptureContext clientContext) {
mParent = parent;
mClientContext = Preconditions.checkNotNull(clientContext);
}
@Override
- ContentCaptureSession newChild(@NonNull ContentCaptureContext context) {
- // TODO(b/121033016): implement it
- throw new UnsupportedOperationException("grand-children not implemented yet");
+ MainContentCaptureSession getMainCaptureSession() {
+ if (mParent instanceof MainContentCaptureSession) {
+ return (MainContentCaptureSession) mParent;
+ }
+ return mParent.getMainCaptureSession();
+ }
+
+ @Override
+ ContentCaptureSession newChild(@NonNull ContentCaptureContext clientContext) {
+ final ContentCaptureSession child = new ChildContentCaptureSession(this, clientContext);
+ getMainCaptureSession().notifyChildSessionStarted(mId, child.mId, clientContext);
+ return child;
}
@Override
@@ -65,27 +74,27 @@ final class ChildContentCaptureSession extends ContentCaptureSession {
@Override
void onDestroy() {
- mParent.notifyChildSessionFinished(mParent.mId, mId);
+ getMainCaptureSession().notifyChildSessionFinished(mParent.mId, mId);
}
@Override
void internalNotifyViewAppeared(@NonNull ViewStructureImpl node) {
- mParent.notifyViewAppeared(mId, node);
+ getMainCaptureSession().notifyViewAppeared(mId, node);
}
@Override
void internalNotifyViewDisappeared(@NonNull AutofillId id) {
- mParent.notifyViewDisappeared(mId, id);
+ getMainCaptureSession().notifyViewDisappeared(mId, id);
}
@Override
void internalNotifyViewTextChanged(@NonNull AutofillId id, @Nullable CharSequence text,
int flags) {
- mParent.notifyViewTextChanged(mId, id, text, flags);
+ getMainCaptureSession().notifyViewTextChanged(mId, id, text, flags);
}
@Override
boolean isContentCaptureEnabled() {
- return mParent.isContentCaptureEnabled();
+ return getMainCaptureSession().isContentCaptureEnabled();
}
@Override
diff --git a/core/java/android/view/contentcapture/ContentCaptureEvent.java b/core/java/android/view/contentcapture/ContentCaptureEvent.java
index 9e3da9234b58..0d064307ce54 100644
--- a/core/java/android/view/contentcapture/ContentCaptureEvent.java
+++ b/core/java/android/view/contentcapture/ContentCaptureEvent.java
@@ -251,6 +251,10 @@ public final class ContentCaptureEvent implements Parcelable {
public String toString() {
final StringBuilder string = new StringBuilder("ContentCaptureEvent[type=")
.append(getTypeAsString(mType));
+ string.append(", session=").append(mSessionId);
+ if (mType == TYPE_SESSION_STARTED && mParentSessionId != null) {
+ string.append(", parent=").append(mParentSessionId);
+ }
if (mFlags > 0) {
string.append(", flags=").append(mFlags);
}
diff --git a/core/java/android/view/contentcapture/ContentCaptureManager.java b/core/java/android/view/contentcapture/ContentCaptureManager.java
index 983079073d02..e962e7c8fe41 100644
--- a/core/java/android/view/contentcapture/ContentCaptureManager.java
+++ b/core/java/android/view/contentcapture/ContentCaptureManager.java
@@ -117,13 +117,11 @@ public final class ContentCaptureManager {
/** @hide */
public void onActivityStarted(@NonNull IBinder applicationToken,
@NonNull ComponentName activityComponent) {
- // TODO(b/121033016): must start all sessions
getMainContentCaptureSession().start(applicationToken, activityComponent);
}
/** @hide */
public void onActivityStopped() {
- // TODO(b/121033016): must finish all sessions
getMainContentCaptureSession().destroy();
}
@@ -135,7 +133,6 @@ public final class ContentCaptureManager {
* @hide
*/
public void flush() {
- // TODO(b/121033016): must flush all sessions
getMainContentCaptureSession().flush();
}
diff --git a/core/java/android/view/contentcapture/ContentCaptureSession.java b/core/java/android/view/contentcapture/ContentCaptureSession.java
index 46e6882b8643..344b9973fdb1 100644
--- a/core/java/android/view/contentcapture/ContentCaptureSession.java
+++ b/core/java/android/view/contentcapture/ContentCaptureSession.java
@@ -27,6 +27,7 @@ import android.view.ViewStructure;
import android.view.autofill.AutofillId;
import android.view.contentcapture.ViewNode.ViewStructureImpl;
+import com.android.internal.annotations.GuardedBy;
import com.android.internal.util.Preconditions;
import dalvik.system.CloseGuard;
@@ -34,7 +35,6 @@ import dalvik.system.CloseGuard;
import java.io.PrintWriter;
import java.util.ArrayList;
import java.util.UUID;
-import java.util.concurrent.atomic.AtomicBoolean;
/**
* Session used to notify a system-provided Content Capture service about events associated with
@@ -73,11 +73,11 @@ public abstract class ContentCaptureSession implements AutoCloseable {
public static final int STATE_ACTIVE = 2;
/**
- * Session is disabled.
+ * Session is disabled because there is no service for this user.
*
* @hide
*/
- public static final int STATE_DISABLED = 3;
+ public static final int STATE_DISABLED_NO_SERVICE = 3;
/**
* Session is disabled because its id already existed on server.
@@ -90,11 +90,14 @@ public abstract class ContentCaptureSession implements AutoCloseable {
private final CloseGuard mCloseGuard = CloseGuard.get();
+ private final Object mLock = new Object();
+
/**
* Guard use to ignore events after it's destroyed.
*/
@NonNull
- private final AtomicBoolean mDestroyed = new AtomicBoolean();
+ @GuardedBy("mLock")
+ private boolean mDestroyed;
/** @hide */
@Nullable
@@ -108,11 +111,8 @@ public abstract class ContentCaptureSession implements AutoCloseable {
/**
* List of children session.
*/
- // TODO(b/121033016): need to synchonize access, either by changing on handler or UI thread
- // (for now there's no handler on this class, so we need to wait for the next refactoring),
- // most likely the former (as we have no guarantee that createContentCaptureSession()
- // it will be called in the UiThread; for example, WebView most likely won't call on it)
@Nullable
+ @GuardedBy("mLock")
private ArrayList<ContentCaptureSession> mChildren;
/** @hide */
@@ -120,6 +120,10 @@ public abstract class ContentCaptureSession implements AutoCloseable {
mCloseGuard.open("destroy");
}
+ /** @hide */
+ @NonNull
+ abstract MainContentCaptureSession getMainCaptureSession();
+
/**
* Gets the id used to identify this session.
*/
@@ -143,10 +147,12 @@ public abstract class ContentCaptureSession implements AutoCloseable {
Log.d(TAG, "createContentCaptureSession(" + context + ": parent=" + mId + ", child="
+ child.mId);
}
- if (mChildren == null) {
- mChildren = new ArrayList<>(INITIAL_CHILDREN_CAPACITY);
+ synchronized (mLock) {
+ if (mChildren == null) {
+ mChildren = new ArrayList<>(INITIAL_CHILDREN_CAPACITY);
+ }
+ mChildren.add(child);
}
- mChildren.add(child);
return child;
}
@@ -163,29 +169,31 @@ public abstract class ContentCaptureSession implements AutoCloseable {
* <p>Once destroyed, any new notification will be dropped.
*/
public final void destroy() {
- if (!mDestroyed.compareAndSet(false, true)) {
- Log.e(TAG, "destroy(): already destroyed");
- return;
- }
-
- mCloseGuard.close();
+ synchronized (mLock) {
+ if (mDestroyed) {
+ Log.e(TAG, "destroy(" + mId + "): already destroyed");
+ return;
+ }
+ mDestroyed = true;
- //TODO(b/111276913): check state (for example, how to handle if it's waiting for remote
- // id) and send it to the cache of batched commands
- if (VERBOSE) {
- Log.v(TAG, "destroy(): state=" + getStateAsString(mState) + ", mId=" + mId);
- }
+ mCloseGuard.close();
- // Finish children first
- if (mChildren != null) {
- final int numberChildren = mChildren.size();
- if (VERBOSE) Log.v(TAG, "Destroying " + numberChildren + " children first");
- for (int i = 0; i < numberChildren; i++) {
- final ContentCaptureSession child = mChildren.get(i);
- try {
- child.destroy();
- } catch (Exception e) {
- Log.w(TAG, "exception destroying child session #" + i + ": " + e);
+ //TODO(b/111276913): check state (for example, how to handle if it's waiting for remote
+ // id) and send it to the cache of batched commands
+ if (VERBOSE) {
+ Log.v(TAG, "destroy(): state=" + getStateAsString(mState) + ", mId=" + mId);
+ }
+ // Finish children first
+ if (mChildren != null) {
+ final int numberChildren = mChildren.size();
+ if (VERBOSE) Log.v(TAG, "Destroying " + numberChildren + " children first");
+ for (int i = 0; i < numberChildren; i++) {
+ final ContentCaptureSession child = mChildren.get(i);
+ try {
+ child.destroy();
+ } catch (Exception e) {
+ Log.w(TAG, "exception destroying child session #" + i + ": " + e);
+ }
}
}
}
@@ -305,23 +313,26 @@ public abstract class ContentCaptureSession implements AutoCloseable {
}
boolean isContentCaptureEnabled() {
- return !mDestroyed.get();
+ synchronized (mLock) {
+ return !mDestroyed;
+ }
}
@CallSuper
void dump(@NonNull String prefix, @NonNull PrintWriter pw) {
pw.print(prefix); pw.print("id: "); pw.println(mId);
- pw.print(prefix); pw.print("destroyed: "); pw.println(mDestroyed.get());
- if (mChildren != null && !mChildren.isEmpty()) {
- final String prefix2 = prefix + " ";
- final int numberChildren = mChildren.size();
- pw.print(prefix); pw.print("number children: "); pw.println(numberChildren);
- for (int i = 0; i < numberChildren; i++) {
- final ContentCaptureSession child = mChildren.get(i);
- pw.print(prefix); pw.print(i); pw.println(": "); child.dump(prefix2, pw);
+ synchronized (mLock) {
+ pw.print(prefix); pw.print("destroyed: "); pw.println(mDestroyed);
+ if (mChildren != null && !mChildren.isEmpty()) {
+ final String prefix2 = prefix + " ";
+ final int numberChildren = mChildren.size();
+ pw.print(prefix); pw.print("number children: "); pw.println(numberChildren);
+ for (int i = 0; i < numberChildren; i++) {
+ final ContentCaptureSession child = mChildren.get(i);
+ pw.print(prefix); pw.print(i); pw.println(": "); child.dump(prefix2, pw);
+ }
}
}
-
}
@Override
@@ -341,8 +352,8 @@ public abstract class ContentCaptureSession implements AutoCloseable {
return "WAITING_FOR_SERVER";
case STATE_ACTIVE:
return "ACTIVE";
- case STATE_DISABLED:
- return "DISABLED";
+ case STATE_DISABLED_NO_SERVICE:
+ return "DISABLED_NO_SERVICE";
case STATE_DISABLED_DUPLICATED_ID:
return "DISABLED_DUPLICATED_ID";
default:
diff --git a/core/java/android/view/contentcapture/MainContentCaptureSession.java b/core/java/android/view/contentcapture/MainContentCaptureSession.java
index baf4a35f179e..44a381e5533d 100644
--- a/core/java/android/view/contentcapture/MainContentCaptureSession.java
+++ b/core/java/android/view/contentcapture/MainContentCaptureSession.java
@@ -141,6 +141,11 @@ public final class MainContentCaptureSession extends ContentCaptureSession {
}
@Override
+ MainContentCaptureSession getMainCaptureSession() {
+ return this;
+ }
+
+ @Override
ContentCaptureSession newChild(@NonNull ContentCaptureContext clientContext) {
final ContentCaptureSession child = new ChildContentCaptureSession(this, clientContext);
notifyChildSessionStarted(mId, child.mId, clientContext);
@@ -171,6 +176,7 @@ public final class MainContentCaptureSession extends ContentCaptureSession {
@Override
void onDestroy() {
+ mHandler.removeMessages(MSG_FLUSH);
mHandler.sendMessage(
obtainMessage(MainContentCaptureSession::handleDestroySession, this));
}
@@ -237,7 +243,7 @@ public final class MainContentCaptureSession extends ContentCaptureSession {
Log.w(TAG, "Failed to link to death on " + binder + ": " + e);
}
}
- if (resultCode == STATE_DISABLED || resultCode == STATE_DISABLED_DUPLICATED_ID) {
+ if (resultCode == STATE_DISABLED_NO_SERVICE || resultCode == STATE_DISABLED_DUPLICATED_ID) {
mDisabled.set(true);
handleResetSession(/* resetState= */ false);
} else {
@@ -246,7 +252,7 @@ public final class MainContentCaptureSession extends ContentCaptureSession {
if (VERBOSE) {
Log.v(TAG, "handleSessionStarted() result: code=" + resultCode + ", id=" + mId
+ ", state=" + getStateAsString(mState) + ", disabled=" + mDisabled.get()
- + ", binder=" + binder);
+ + ", binder=" + binder + ", events=" + (mEvents == null ? 0 : mEvents.size()));
}
}
@@ -285,14 +291,14 @@ public final class MainContentCaptureSession extends ContentCaptureSession {
return;
}
- if (mState != STATE_ACTIVE) {
+ if (mState != STATE_ACTIVE && numberEvents >= MAX_BUFFER_SIZE) {
// Callback from startSession hasn't been called yet - typically happens on system
// apps that are started before the system service
// TODO(b/111276913): try to ignore session while system is not ready / boot
// not complete instead. Similarly, the manager service should return right away
// when the user does not have a service set
- if (VERBOSE) {
- Log.v(TAG, "Closing session for " + getActivityDebugName()
+ if (DEBUG) {
+ Log.d(TAG, "Closing session for " + getActivityDebugName()
+ " after " + numberEvents + " delayed events and state "
+ getStateAsString(mState));
}
@@ -331,7 +337,9 @@ public final class MainContentCaptureSession extends ContentCaptureSession {
if (mEvents == null) return;
if (mDirectServiceInterface == null) {
- if (DEBUG) Log.d(TAG, "handleForceFlush(): hold your horses, client not ready yet!");
+ if (VERBOSE) {
+ Log.v(TAG, "handleForceFlush(): hold your horses, client not ready: " + mEvents);
+ }
if (!mHandler.hasMessages(MSG_FLUSH)) {
handleScheduleFlush(/* checkExisting= */ false);
}
@@ -386,14 +394,14 @@ public final class MainContentCaptureSession extends ContentCaptureSession {
handleResetSession(/* resetState= */ true);
}
- // TODO(b/121033016): once we support multiple sessions, we might need to move some of these
+ // TODO(b/122454205): once we support multiple sessions, we might need to move some of these
// clearings out.
private void handleResetSession(boolean resetState) {
if (resetState) {
mState = STATE_UNKNOWN;
}
- // TODO(b/121033016): must reset children (which currently is owned by superclass)
+ // TODO(b/122454205): must reset children (which currently is owned by superclass)
mApplicationToken = null;
mComponentName = null;
mEvents = null;
@@ -426,7 +434,7 @@ public final class MainContentCaptureSession extends ContentCaptureSession {
&& !mDisabled.get();
}
- // TODO(b/121033016): refactor "notifyXXXX" methods below to a common "Buffer" object that is
+ // TODO(b/122454205): refactor "notifyXXXX" methods below to a common "Buffer" object that is
// shared between ActivityContentCaptureSession and ChildContentCaptureSession objects. Such
// change should also get get rid of the "internalNotifyXXXX" methods above
void notifyChildSessionStarted(@NonNull String parentSessionId,
@@ -435,14 +443,14 @@ public final class MainContentCaptureSession extends ContentCaptureSession {
new ContentCaptureEvent(childSessionId, TYPE_SESSION_STARTED)
.setParentSessionId(parentSessionId)
.setClientContext(clientContext),
- /* forceFlush= */ false));
+ /* forceFlush= */ true));
}
void notifyChildSessionFinished(@NonNull String parentSessionId,
@NonNull String childSessionId) {
mHandler.sendMessage(obtainMessage(MainContentCaptureSession::handleSendEvent, this,
new ContentCaptureEvent(childSessionId, TYPE_SESSION_FINISHED)
- .setParentSessionId(parentSessionId), /* forceFlush= */ false));
+ .setParentSessionId(parentSessionId), /* forceFlush= */ true));
}
void notifyViewAppeared(@NonNull String sessionId, @NonNull ViewStructureImpl node) {
diff --git a/core/java/android/widget/Magnifier.java b/core/java/android/widget/Magnifier.java
index 7d027574198d..886718d192e0 100644
--- a/core/java/android/widget/Magnifier.java
+++ b/core/java/android/widget/Magnifier.java
@@ -271,7 +271,7 @@ public final class Magnifier {
if (mWindow == null) {
synchronized (mLock) {
mWindow = new InternalPopupWindow(mView.getContext(), mView.getDisplay(),
- mParentSurface.mSurface, mWindowWidth, mWindowHeight,
+ mParentSurface.mSurfaceControl, mWindowWidth, mWindowHeight,
mWindowElevation, mWindowCornerRadius,
mOverlay != null ? mOverlay : new ColorDrawable(Color.TRANSPARENT),
Handler.getMain() /* draw the magnifier on the UI thread */, mLock,
@@ -528,17 +528,20 @@ public final class Magnifier {
final int surfaceHeight =
viewRootImpl.getHeight() + surfaceInsets.top + surfaceInsets.bottom;
validMainWindowSurface =
- new SurfaceInfo(mainWindowSurface, surfaceWidth, surfaceHeight, true);
+ new SurfaceInfo(viewRootImpl.getSurfaceControl(), mainWindowSurface,
+ surfaceWidth, surfaceHeight, true);
}
}
// Get the surface backing the magnified view, if it is a SurfaceView.
SurfaceInfo validSurfaceViewSurface = SurfaceInfo.NULL;
if (mView instanceof SurfaceView) {
+ final SurfaceControl sc = ((SurfaceView) mView).getSurfaceControl();
final SurfaceHolder surfaceHolder = ((SurfaceView) mView).getHolder();
final Surface surfaceViewSurface = surfaceHolder.getSurface();
- if (surfaceViewSurface != null && surfaceViewSurface.isValid()) {
+
+ if (sc != null && sc.isValid()) {
final Rect surfaceFrame = surfaceHolder.getSurfaceFrame();
- validSurfaceViewSurface = new SurfaceInfo(surfaceViewSurface,
+ validSurfaceViewSurface = new SurfaceInfo(sc, surfaceViewSurface,
surfaceFrame.right, surfaceFrame.bottom, false);
}
}
@@ -733,15 +736,18 @@ public final class Magnifier {
* Contains a surface and metadata corresponding to it.
*/
private static class SurfaceInfo {
- public static final SurfaceInfo NULL = new SurfaceInfo(null, 0, 0, false);
+ public static final SurfaceInfo NULL = new SurfaceInfo(null, null, 0, 0, false);
private Surface mSurface;
+ private SurfaceControl mSurfaceControl;
private int mWidth;
private int mHeight;
private boolean mIsMainWindowSurface;
- SurfaceInfo(final Surface surface, final int width, final int height,
+ SurfaceInfo(final SurfaceControl surfaceControl, final Surface surface,
+ final int width, final int height,
final boolean isMainWindowSurface) {
+ mSurfaceControl = surfaceControl;
mSurface = surface;
mWidth = width;
mHeight = height;
@@ -819,7 +825,7 @@ public final class Magnifier {
private Bitmap mCurrentContent;
InternalPopupWindow(final Context context, final Display display,
- final Surface parentSurface, final int width, final int height,
+ final SurfaceControl parentSurfaceControl, final int width, final int height,
final float elevation, final float cornerRadius, final Drawable overlay,
final Handler handler, final Object lock, final Callback callback) {
mDisplay = display;
@@ -834,12 +840,13 @@ public final class Magnifier {
// Setup the surface we will use for drawing the content and shadow.
mSurfaceWidth = mContentWidth + 2 * mOffsetX;
mSurfaceHeight = mContentHeight + 2 * mOffsetY;
- mSurfaceSession = new SurfaceSession(parentSurface);
+ mSurfaceSession = new SurfaceSession();
mSurfaceControl = new SurfaceControl.Builder(mSurfaceSession)
.setFormat(PixelFormat.TRANSLUCENT)
.setBufferSize(mSurfaceWidth, mSurfaceHeight)
.setName("magnifier surface")
.setFlags(SurfaceControl.HIDDEN)
+ .setParent(parentSurfaceControl)
.build();
mSurface = new Surface();
mSurface.copyFrom(mSurfaceControl);
diff --git a/core/java/com/android/internal/util/SyncResultReceiver.java b/core/java/com/android/internal/util/SyncResultReceiver.java
new file mode 100644
index 000000000000..9a346ac93a8d
--- /dev/null
+++ b/core/java/com/android/internal/util/SyncResultReceiver.java
@@ -0,0 +1,145 @@
+/*
+ * 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.internal.util;
+
+import android.annotation.NonNull;
+import android.annotation.Nullable;
+import android.os.Bundle;
+import android.os.Parcelable;
+import android.os.RemoteException;
+
+import com.android.internal.os.IResultReceiver;
+
+import java.util.concurrent.CountDownLatch;
+import java.util.concurrent.TimeUnit;
+
+/**
+ * A {@code IResultReceiver} implementation that can be used to make "sync" Binder calls by blocking
+ * until it receives a result
+ *
+ * @hide
+ */
+public final class SyncResultReceiver extends IResultReceiver.Stub {
+
+ private static final String EXTRA = "EXTRA";
+
+ private final CountDownLatch mLatch = new CountDownLatch(1);
+ private final int mTimeoutMs;
+ private int mResult;
+ private Bundle mBundle;
+
+ /**
+ * Default constructor.
+ *
+ * @param timeoutMs how long to block waiting for {@link IResultReceiver} callbacks.
+ */
+ public SyncResultReceiver(int timeoutMs) {
+ mTimeoutMs = timeoutMs;
+ }
+
+ private void waitResult() throws TimeoutException {
+ try {
+ if (!mLatch.await(mTimeoutMs, TimeUnit.MILLISECONDS)) {
+ throw new TimeoutException("Not called in " + mTimeoutMs + "ms");
+ }
+ } catch (InterruptedException e) {
+ Thread.currentThread().interrupt();
+ throw new TimeoutException("Interrupted");
+ }
+ }
+
+ /**
+ * Gets the result from an operation that returns an {@code int}.
+ */
+ public int getIntResult() throws TimeoutException {
+ waitResult();
+ return mResult;
+ }
+
+ /**
+ * Gets the result from an operation that returns an {@code String}.
+ */
+ @Nullable
+ public String getStringResult() throws TimeoutException {
+ waitResult();
+ return mBundle == null ? null : mBundle.getString(EXTRA);
+ }
+
+ /**
+ * Gets the result from an operation that returns a {@code String[]}.
+ */
+ @Nullable
+ public String[] getStringArrayResult() throws TimeoutException {
+ waitResult();
+ return mBundle == null ? null : mBundle.getStringArray(EXTRA);
+ }
+
+ /**
+ * Gets the result from an operation that returns a {@code Parcelable}.
+ */
+ @Nullable
+ public <P extends Parcelable> P getParcelableResult() throws TimeoutException {
+ waitResult();
+ return mBundle == null ? null : mBundle.getParcelable(EXTRA);
+ }
+
+ @Override
+ public void send(int resultCode, Bundle resultData) {
+ mResult = resultCode;
+ mBundle = resultData;
+ mLatch.countDown();
+ }
+
+ /**
+ * Creates a bundle for a {@code String} value so it can be retrieved by
+ * {@link #getStringResult()}.
+ */
+ @NonNull
+ public static Bundle bundleFor(@Nullable String value) {
+ final Bundle bundle = new Bundle();
+ bundle.putString(EXTRA, value);
+ return bundle;
+ }
+
+ /**
+ * Creates a bundle for a {@code String[]} value so it can be retrieved by
+ * {@link #getStringArrayResult()}.
+ */
+ @NonNull
+ public static Bundle bundleFor(@Nullable String[] value) {
+ final Bundle bundle = new Bundle();
+ bundle.putStringArray(EXTRA, value);
+ return bundle;
+ }
+
+ /**
+ * Creates a bundle for a {@code Parcelable} value so it can be retrieved by
+ * {@link #getParcelableResult()}.
+ */
+ @NonNull
+ public static Bundle bundleFor(@Nullable Parcelable value) {
+ final Bundle bundle = new Bundle();
+ bundle.putParcelable(EXTRA, value);
+ return bundle;
+ }
+
+ /** @hide */
+ public static final class TimeoutException extends RemoteException {
+ private TimeoutException(String msg) {
+ super(msg);
+ }
+ }
+}
diff --git a/core/jni/android_view_SurfaceControl.cpp b/core/jni/android_view_SurfaceControl.cpp
index 6576587899be..f292d25c15fe 100644
--- a/core/jni/android_view_SurfaceControl.cpp
+++ b/core/jni/android_view_SurfaceControl.cpp
@@ -438,8 +438,9 @@ static jobject nativeGetDisplayedContentSamplingAttributes(JNIEnv* env, jclass c
static jboolean nativeSetDisplayedContentSamplingEnabled(JNIEnv* env, jclass clazz,
jobject tokenObj, jboolean enable, jint componentMask, jint maxFrames) {
sp<IBinder> token(ibinderForJavaObject(env, tokenObj));
- return SurfaceComposerClient::setDisplayContentSamplingEnabled(
+ status_t rc = SurfaceComposerClient::setDisplayContentSamplingEnabled(
token, enable, componentMask, maxFrames);
+ return rc == OK;
}
static jobject nativeGetDisplayedContentSample(JNIEnv* env, jclass clazz, jobject tokenObj,
@@ -916,6 +917,17 @@ static jlong nativeReadFromParcel(JNIEnv* env, jclass clazz, jobject parcelObj)
return reinterpret_cast<jlong>(surface.get());
}
+static jlong nativeCopyFromSurfaceControl(JNIEnv* env, jclass clazz, jlong surfaceControlNativeObj) {
+ sp<SurfaceControl> surface(reinterpret_cast<SurfaceControl *>(surfaceControlNativeObj));
+ if (surface == nullptr) {
+ return 0;
+ }
+
+ sp<SurfaceControl> newSurface = new SurfaceControl(surface);
+ newSurface->incStrong((void *)nativeCreate);
+ return reinterpret_cast<jlong>(newSurface.get());
+}
+
static void nativeWriteToParcel(JNIEnv* env, jclass clazz,
jlong nativeObject, jobject parcelObj) {
Parcel* parcel = parcelForJavaObject(env, parcelObj);
@@ -924,7 +936,9 @@ static void nativeWriteToParcel(JNIEnv* env, jclass clazz,
return;
}
SurfaceControl* const self = reinterpret_cast<SurfaceControl *>(nativeObject);
- self->writeToParcel(parcel);
+ if (self != nullptr) {
+ self->writeToParcel(parcel);
+ }
}
// ----------------------------------------------------------------------------
@@ -934,6 +948,8 @@ static const JNINativeMethod sSurfaceControlMethods[] = {
(void*)nativeCreate },
{"nativeReadFromParcel", "(Landroid/os/Parcel;)J",
(void*)nativeReadFromParcel },
+ {"nativeCopyFromSurfaceControl", "(J)J" ,
+ (void*)nativeCopyFromSurfaceControl },
{"nativeWriteToParcel", "(JLandroid/os/Parcel;)V",
(void*)nativeWriteToParcel },
{"nativeRelease", "(J)V",
diff --git a/core/jni/android_view_SurfaceSession.cpp b/core/jni/android_view_SurfaceSession.cpp
index 30c00302eefd..191f748d80bf 100644
--- a/core/jni/android_view_SurfaceSession.cpp
+++ b/core/jni/android_view_SurfaceSession.cpp
@@ -46,13 +46,6 @@ static jlong nativeCreate(JNIEnv* env, jclass clazz) {
return reinterpret_cast<jlong>(client);
}
-static jlong nativeCreateScoped(JNIEnv* env, jclass clazz, jlong surfaceObject) {
- Surface *parent = reinterpret_cast<Surface*>(surfaceObject);
- SurfaceComposerClient* client = new SurfaceComposerClient(parent->getIGraphicBufferProducer());
- client->incStrong((void*)nativeCreate);
- return reinterpret_cast<jlong>(client);
-}
-
static void nativeDestroy(JNIEnv* env, jclass clazz, jlong ptr) {
SurfaceComposerClient* client = reinterpret_cast<SurfaceComposerClient*>(ptr);
client->decStrong((void*)nativeCreate);
@@ -67,8 +60,6 @@ static const JNINativeMethod gMethods[] = {
/* name, signature, funcPtr */
{ "nativeCreate", "()J",
(void*)nativeCreate },
- { "nativeCreateScoped", "(J)J",
- (void*)nativeCreateScoped },
{ "nativeDestroy", "(J)V",
(void*)nativeDestroy },
{ "nativeKill", "(J)V",
diff --git a/core/proto/android/providers/settings/global.proto b/core/proto/android/providers/settings/global.proto
index a914369a036c..d817aa33302d 100644
--- a/core/proto/android/providers/settings/global.proto
+++ b/core/proto/android/providers/settings/global.proto
@@ -558,6 +558,8 @@ message GlobalSettingsProto {
// ringer mode.
optional SettingProto mode_ringer = 75 [ (android.privacy).dest = DEST_AUTOMATIC ];
+ optional SettingProto apply_ramping_ringer = 147 [ (android.privacy).dest = DEST_AUTOMATIC ];
+
message MultiSim {
option (android.msg_privacy).dest = DEST_EXPLICIT;
@@ -1017,5 +1019,5 @@ message GlobalSettingsProto {
// Please insert fields in alphabetical order and group them into messages
// if possible (to avoid reaching the method limit).
- // Next tag = 147;
+ // Next tag = 148;
}
diff --git a/core/res/res/drawable/ic_account_circle.xml b/core/res/res/drawable/ic_account_circle.xml
index f7317dbc5245..71691add7322 100644
--- a/core/res/res/drawable/ic_account_circle.xml
+++ b/core/res/res/drawable/ic_account_circle.xml
@@ -14,18 +14,14 @@ Copyright (C) 2014 The Android Open Source Project
limitations under the License.
-->
<vector xmlns:android="http://schemas.android.com/apk/res/android"
- android:width="48.0dp"
- android:height="48.0dp"
- android:viewportWidth="20.0"
- android:viewportHeight="20.0">
- <group
- android:translateX="-2"
- android:translateY="-2" >
- <path
- android:pathData="M12,2C6.48,2 2,6.48 2,12c0,5.52 4.48,10 10,10c5.52,0 10,-4.48 10,-10C22,6.48 17.52,2 12,2zM18.36,16.83c-1.43,-1.74 -4.9,-2.33 -6.36,-2.33s-4.93,0.59 -6.36,2.33C4.62,15.49 4,13.82 4,12c0,-4.41 3.59,-8 8,-8c4.41,0 8,3.59 8,8C20,13.82 19.38,15.49 18.36,16.83z"
- android:fillColor="#FFFFFFFF" />
- <path
- android:pathData="M12,6c-1.94,0 -3.5,1.56 -3.5,3.5S10.06,13 12,13c1.94,0 3.5,-1.56 3.5,-3.5S13.94,6 12,6z"
- android:fillColor="#FFFFFFFF" />
- </group>
+ android:width="48dp"
+ android:height="48dp"
+ android:viewportWidth="24"
+ android:viewportHeight="24">
+ <path
+ android:fillColor="#FFFFFFFF"
+ android:pathData="M12,2C6.48,2 2,6.48 2,12c0,5.52 4.48,10 10,10c5.52,0 10,-4.48 10,-10C22,6.48 17.52,2 12,2zM18.36,16.83c-1.43,-1.74 -4.9,-2.33 -6.36,-2.33s-4.93,0.59 -6.36,2.33C4.62,15.49 4,13.82 4,12c0,-4.41 3.59,-8 8,-8c4.41,0 8,3.59 8,8C20,13.82 19.38,15.49 18.36,16.83z"/>
+ <path
+ android:fillColor="#FFFFFFFF"
+ android:pathData="M12,6c-1.94,0 -3.5,1.56 -3.5,3.5S10.06,13 12,13c1.94,0 3.5,-1.56 3.5,-3.5S13.94,6 12,6z"/>
</vector>
diff --git a/core/res/res/drawable/ic_battery.xml b/core/res/res/drawable/ic_battery.xml
new file mode 100644
index 000000000000..bd40f4df505e
--- /dev/null
+++ b/core/res/res/drawable/ic_battery.xml
@@ -0,0 +1,25 @@
+<!--
+ 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.
+-->
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+ android:width="24dp"
+ android:height="24dp"
+ android:viewportWidth="24.0"
+ android:viewportHeight="24.0"
+ android:tint="?android:attr/colorControlNormal">
+ <path
+ android:fillColor="#FF000000"
+ android:pathData="M15.67,4H14V2h-4v2H8.33C7.6,4 7,4.6 7,5.33v15.33C7,21.4 7.6,22 8.33,22h7.33c0.74,0 1.34,-0.6 1.34,-1.33V5.33C17,4.6 16.4,4 15.67,4z"/>
+</vector>
diff --git a/core/res/res/drawable/ic_corp_badge.xml b/core/res/res/drawable/ic_corp_badge.xml
index 1dad9776851e..5ab504528366 100644
--- a/core/res/res/drawable/ic_corp_badge.xml
+++ b/core/res/res/drawable/ic_corp_badge.xml
@@ -15,22 +15,11 @@ Copyright (C) 2018 The Android Open Source Project
limitations under the License.
-->
<vector xmlns:android="http://schemas.android.com/apk/res/android"
- android:width="20dp"
- android:height="20dp"
- android:viewportWidth="48"
- android:viewportHeight="48">
-
+ android:width="48dp"
+ android:height="48dp"
+ android:viewportWidth="24"
+ android:viewportHeight="24">
<path
- android:fillType="evenOdd"
- android:strokeColor="#1A73E8"
- android:strokeWidth="4"
- android:pathData="M 24 2 C 36.1502644963 2 46 11.8497355037 46 24 C 46 36.1502644963 36.1502644963 46 24 46 C 11.8497355037 46 2 36.1502644963 2 24 C 2 11.8497355037 11.8497355037 2 24 2 Z" />
- <group
- android:translateX="10.400000"
- android:translateY="10.400000">
- <path
- android:fillColor="#1A73E8"
- android:strokeWidth="1"
- android:pathData="M24.2971429,5.38947368 L18.9485714,5.38947368 L18.9485714,2.80902256 C18.9485714,1.37687218 17.7585143,0.228571429 16.2742857,0.228571429 L10.9257143,0.228571429 C9.44148571,0.228571429 8.25142857,1.37687218 8.25142857,2.80902256 L8.25142857,5.38947368 L2.90285714,5.38947368 C1.41862857,5.38947368 0.241942857,6.53777444 0.241942857,7.96992481 L0.228571429,22.162406 C0.228571429,23.5945564 1.41862857,24.7428571 2.90285714,24.7428571 L24.2971429,24.7428571 C25.7813714,24.7428571 26.9714286,23.5945564 26.9714286,22.162406 L26.9714286,7.96992481 C26.9714286,6.53777444 25.7813714,5.38947368 24.2971429,5.38947368 Z M13.6,17.0015038 C12.1291429,17.0015038 10.9257143,15.8403008 10.9257143,14.4210526 C10.9257143,13.0018045 12.1291429,11.8406015 13.6,11.8406015 C15.0708571,11.8406015 16.2742857,13.0018045 16.2742857,14.4210526 C16.2742857,15.8403008 15.0708571,17.0015038 13.6,17.0015038 Z M16.2742857,5.38947368 L10.9257143,5.38947368 L10.9257143,2.80902256 L16.2742857,2.80902256 L16.2742857,5.38947368 Z" />
- </group>
+ android:fillColor="@*android:color/accent_device_default_light"
+ android:pathData="M20,6h-4V4c0,-1.11 -0.89,-2 -2,-2h-4C8.89,2 8,2.89 8,4v2H4C2.89,6 2.01,6.89 2.01,8L2,19c0,1.11 0.89,2 2,2h16c1.11,0 2,-0.89 2,-2V8C22,6.89 21.11,6 20,6zM10,4h4v2h-4V4zM20,19H4V8h16V19z"/>
</vector> \ No newline at end of file
diff --git a/core/res/res/values/attrs.xml b/core/res/res/values/attrs.xml
index 183c2e8cf486..fa3a549463f5 100644
--- a/core/res/res/values/attrs.xml
+++ b/core/res/res/values/attrs.xml
@@ -3660,7 +3660,12 @@
the settings for this service. This setting cannot be changed at runtime. -->
<attr name="settingsActivity" />
<!-- Attribute whether the accessibility service wants to be able to retrieve the
- active window content. This setting cannot be changed at runtime. -->
+ active window content. This setting cannot be changed at runtime.
+ <p>
+ Required to allow setting the {@link android.accessibilityservice
+ #AccessibilityServiceInfo#FLAG_RETRIEVE_INTERACTIVE_WINDOWS} flag.
+ </p>
+ -->
<attr name="canRetrieveWindowContent" format="boolean" />
<!-- Attribute whether the accessibility service wants to be able to request touch
exploration mode in which touched items are spoken aloud and the UI can be
diff --git a/core/res/res/values/config.xml b/core/res/res/values/config.xml
index e4abf8f4cf49..8735557e3f4c 100644
--- a/core/res/res/values/config.xml
+++ b/core/res/res/values/config.xml
@@ -1169,7 +1169,7 @@
<integer name="config_lowBatteryAutoTriggerDefaultLevel">15</integer>
<!-- The app which will handle routine based automatic battery saver, if empty the UI for
- routine based battery saver will be hidden -->
+ routine based battery saver will be hidden -->
<string name="config_batterySaverScheduleProvider"></string>
<!-- Close low battery warning when battery level reaches the lowBatteryWarningLevel
diff --git a/core/res/res/values/strings.xml b/core/res/res/values/strings.xml
index a7bc57afa749..0878562e00fb 100644
--- a/core/res/res/values/strings.xml
+++ b/core/res/res/values/strings.xml
@@ -5238,6 +5238,15 @@
<!-- Content description of the overlay icon in the notification. [CHAR LIMIT=NONE] -->
<string name="notification_appops_overlay_active">displaying over other apps on your screen</string>
+ <!-- Dynamic mode battery saver strings -->
+ <!-- The user visible name of the notification channel for the routine mode battery saver fyi notification [CHAR_LIMIT=80]-->
+ <string name="dynamic_mode_notification_channel_name">Routine Mode info notification</string>
+ <!-- Title of notification letting users know why battery saver was turned on automatically [CHAR_LIMIT=NONE]-->
+ <string name="dynamic_mode_notification_title">Battery may run out before usual charge</string>
+ <!-- Summary of notification letting users know why battery saver was turned on automatically [CHAR_LIMIT=NONE]-->
+ <string name="dynamic_mode_notification_summary">Battery Saver activated to extend battery life</string>
+
+
<!-- Strings for car -->
<!-- String displayed when loading a user in the car [CHAR LIMIT=30] -->
<string name="car_loading_profile">Loading</string>
diff --git a/core/res/res/values/symbols.xml b/core/res/res/values/symbols.xml
index e8cbf666c03c..c2d97bc261e4 100644
--- a/core/res/res/values/symbols.xml
+++ b/core/res/res/values/symbols.xml
@@ -3519,4 +3519,9 @@
<!-- For Secondary Launcher -->
<java-symbol type="string" name="config_secondaryHomeComponent" />
+
+ <java-symbol type="string" name="dynamic_mode_notification_channel_name" />
+ <java-symbol type="string" name="dynamic_mode_notification_title" />
+ <java-symbol type="string" name="dynamic_mode_notification_summary" />
+ <java-symbol type="drawable" name="ic_battery" />
</resources>
diff --git a/core/res/res/values/themes_device_defaults.xml b/core/res/res/values/themes_device_defaults.xml
index 0f4ca66dcd68..d60313a4402c 100644
--- a/core/res/res/values/themes_device_defaults.xml
+++ b/core/res/res/values/themes_device_defaults.xml
@@ -1454,12 +1454,17 @@ easier.
<item name="panelMenuListTheme">@style/Theme.Material.Settings.CompactMenu</item>
<!-- action bar -->
+ <item name="actionBarStyle">@style/Widget.DeviceDefault.Light.ActionBar.Solid</item>
<item name="actionBarTheme">@style/ThemeOverlay.DeviceDefault.ActionBar</item>
<item name="popupTheme">@style/ThemeOverlay.DeviceDefault.Popup.Light</item>
<!-- Color palette -->
+ <item name="colorBackground">@color/background_device_default_light</item>
+ <item name="colorPrimary">@color/primary_device_default_settings_light</item>
<item name="colorPrimaryDark">@color/primary_dark_device_default_settings_light</item>
<item name="colorSecondary">@color/secondary_device_default_settings_light</item>
+ <item name="colorAccent">@color/accent_device_default_light</item>
+ <item name="colorError">@color/error_color_device_default_light</item>
<item name="colorEdgeEffect">@android:color/black</item>
<!-- Add white nav bar with divider that matches material -->
@@ -1467,9 +1472,16 @@ easier.
<item name="navigationBarColor">@android:color/white</item>
<item name="windowLightNavigationBar">true</item>
+ <!-- Dialog attributes -->
+ <item name="dialogCornerRadius">@dimen/config_dialogCornerRadius</item>
+
<!-- Button styles -->
+ <item name="buttonCornerRadius">@dimen/config_buttonCornerRadius</item>
<item name="buttonBarButtonStyle">@style/Widget.DeviceDefault.Button.ButtonBar.AlertDialog</item>
+ <!-- Progress bar attributes -->
+ <item name="progressBarCornerRadius">@dimen/config_progressBarCornerRadius</item>
+
<item name="listDivider">@color/list_divider_color_light</item>
</style>
diff --git a/core/tests/coretests/src/android/provider/SettingsBackupTest.java b/core/tests/coretests/src/android/provider/SettingsBackupTest.java
index ac57d20a438a..70267c7c2dfa 100644
--- a/core/tests/coretests/src/android/provider/SettingsBackupTest.java
+++ b/core/tests/coretests/src/android/provider/SettingsBackupTest.java
@@ -114,6 +114,7 @@ public class SettingsBackupTest {
Settings.Global.ANOMALY_CONFIG_VERSION,
Settings.Global.APN_DB_UPDATE_CONTENT_URL,
Settings.Global.APN_DB_UPDATE_METADATA_URL,
+ Settings.Global.APPLY_RAMPING_RINGER,
Settings.Global.APP_BINDING_CONSTANTS,
Settings.Global.APP_IDLE_CONSTANTS,
Settings.Global.APP_OPS_CONSTANTS,
@@ -269,6 +270,7 @@ public class SettingsBackupTest {
Settings.Global.GNSS_SATELLITE_BLACKLIST,
Settings.Global.GPRS_REGISTER_CHECK_PERIOD_MS,
Settings.Global.HDMI_CONTROL_AUTO_DEVICE_OFF_ENABLED,
+ Settings.Global.HDMI_CONTROL_AUTO_TV_OFF_ENABLED,
Settings.Global.HDMI_CONTROL_AUTO_WAKEUP_ENABLED,
Settings.Global.HDMI_CONTROL_ENABLED,
Settings.Global.HDMI_SYSTEM_AUDIO_CONTROL_ENABLED,
diff --git a/core/tests/coretests/src/android/view/textclassifier/TextClassifierTest.java b/core/tests/coretests/src/android/view/textclassifier/TextClassifierTest.java
index 81ec85eb2ea5..82eaf88fb07a 100644
--- a/core/tests/coretests/src/android/view/textclassifier/TextClassifierTest.java
+++ b/core/tests/coretests/src/android/view/textclassifier/TextClassifierTest.java
@@ -368,6 +368,7 @@ public class TextClassifierTest {
assertThat(textLanguage, isTextLanguage("ja"));
}
+ /* DISABLED: b/122467291
@Test
public void testSuggestConversationActions_textReplyOnly_maxThree() {
if (isTextClassifierDisabled()) return;
@@ -395,7 +396,7 @@ public class TextClassifierTest {
assertThat(conversationAction,
isConversationAction(ConversationActions.TYPE_TEXT_REPLY));
}
- }
+ }*/
@Test
public void testSuggestConversationActions_textReplyOnly_noMax() {
diff --git a/core/tests/hdmitests/Android.mk b/core/tests/hdmitests/Android.mk
index e0d2c09a6f0f..2ca31a6a240a 100644
--- a/core/tests/hdmitests/Android.mk
+++ b/core/tests/hdmitests/Android.mk
@@ -20,7 +20,7 @@ LOCAL_MODULE_TAGS := tests
# Include all test java files
LOCAL_SRC_FILES := $(call all-java-files-under, src)
-LOCAL_STATIC_JAVA_LIBRARIES := android-support-test frameworks-base-testutils
+LOCAL_STATIC_JAVA_LIBRARIES := androidx.test.rules frameworks-base-testutils
LOCAL_JAVA_LIBRARIES := android.test.runner
LOCAL_PACKAGE_NAME := HdmiCecTests
diff --git a/core/tests/hdmitests/AndroidManifest.xml b/core/tests/hdmitests/AndroidManifest.xml
index 1460b4168581..f8ed118d2338 100644
--- a/core/tests/hdmitests/AndroidManifest.xml
+++ b/core/tests/hdmitests/AndroidManifest.xml
@@ -22,7 +22,7 @@
<uses-library android:name="android.test.runner" />
</application>
- <instrumentation android:name="android.support.test.runner.AndroidJUnitRunner"
+ <instrumentation android:name="androidx.test.runner.AndroidJUnitRunner"
android:targetPackage="android.hardware.hdmi"
android:label="HDMI CEC Tests"/>
diff --git a/core/tests/hdmitests/AndroidTest.xml b/core/tests/hdmitests/AndroidTest.xml
index 7ef672d344c5..0c8da28cab7c 100644
--- a/core/tests/hdmitests/AndroidTest.xml
+++ b/core/tests/hdmitests/AndroidTest.xml
@@ -29,6 +29,6 @@
<test class="com.android.tradefed.testtype.AndroidJUnitTest" >
<option name="package" value="android.hardware.hdmi" />
<option name="hidden-api-checks" value="false"/>
- <option name="runner" value="android.support.test.runner.AndroidJUnitRunner"/>
+ <option name="runner" value="androidx.test.runner.AndroidJUnitRunner"/>
</test>
</configuration> \ No newline at end of file
diff --git a/core/tests/hdmitests/src/android/hardware/hdmi/HdmiAudioSystemClientTest.java b/core/tests/hdmitests/src/android/hardware/hdmi/HdmiAudioSystemClientTest.java
index 7b76a0819e22..0dd9d0904746 100644
--- a/core/tests/hdmitests/src/android/hardware/hdmi/HdmiAudioSystemClientTest.java
+++ b/core/tests/hdmitests/src/android/hardware/hdmi/HdmiAudioSystemClientTest.java
@@ -18,15 +18,18 @@ package android.hardware.hdmi;
import android.os.Handler;
import android.os.test.TestLooper;
-import android.support.test.filters.SmallTest;
import android.util.Log;
-import java.util.List;
+
+import androidx.test.filters.SmallTest;
+
import org.junit.Assert;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.junit.runners.JUnit4;
+import java.util.List;
+
/**
* Tests for {@link HdmiAudioSystemClient}
*/
diff --git a/graphics/java/android/graphics/ColorSpace.java b/graphics/java/android/graphics/ColorSpace.java
index 2227cf5ef2e0..f0efb581dab6 100644
--- a/graphics/java/android/graphics/ColorSpace.java
+++ b/graphics/java/android/graphics/ColorSpace.java
@@ -1354,9 +1354,9 @@ public abstract class ColorSpace {
*/
@NonNull
static ColorSpace get(@IntRange(from = MIN_ID, to = MAX_ID) int index) {
- if (index < 0 || index > Named.values().length) {
+ if (index < 0 || index >= Named.values().length) {
throw new IllegalArgumentException("Invalid ID, must be in the range [0.." +
- Named.values().length + "]");
+ Named.values().length + ")");
}
return sNamedColorSpaces[index];
}
diff --git a/libs/hwui/WebViewFunctorManager.cpp b/libs/hwui/WebViewFunctorManager.cpp
index 5b7ae70e821c..9170d6d1dc50 100644
--- a/libs/hwui/WebViewFunctorManager.cpp
+++ b/libs/hwui/WebViewFunctorManager.cpp
@@ -18,6 +18,7 @@
#include <private/hwui/WebViewFunctor.h>
#include "Properties.h"
+#include "renderthread/RenderThread.h"
#include <log/log.h>
#include <utils/Trace.h>
@@ -90,6 +91,10 @@ void WebViewFunctor::destroyContext() {
mHasContext = false;
ATRACE_NAME("WebViewFunctor::onContextDestroyed");
mCallbacks.onContextDestroyed(mFunctor, mData);
+
+ // grContext may be null in unit tests.
+ auto* grContext = renderthread::RenderThread::getInstance().getGrContext();
+ if (grContext) grContext->resetContext();
}
}
diff --git a/libs/hwui/renderthread/CacheManager.cpp b/libs/hwui/renderthread/CacheManager.cpp
index 7acc44ca65b7..6c04232ab7f5 100644
--- a/libs/hwui/renderthread/CacheManager.cpp
+++ b/libs/hwui/renderthread/CacheManager.cpp
@@ -30,6 +30,7 @@
#include <gui/Surface.h>
#include <math.h>
#include <set>
+#include <SkMathPriv.h>
namespace android {
namespace uirenderer {
@@ -42,11 +43,6 @@ namespace renderthread {
#define SURFACE_SIZE_MULTIPLIER (12.0f * 4.0f)
#define BACKGROUND_RETENTION_PERCENTAGE (0.5f)
-// for super large fonts we will draw them as paths so no need to keep linearly
-// increasing the font cache size.
-#define FONT_CACHE_MIN_MB (0.5f)
-#define FONT_CACHE_MAX_MB (4.0f)
-
CacheManager::CacheManager(const DisplayInfo& display) : mMaxSurfaceArea(display.w * display.h) {
mVectorDrawableAtlas = new skiapipeline::VectorDrawableAtlas(
mMaxSurfaceArea / 2,
@@ -106,25 +102,10 @@ public:
void CacheManager::configureContext(GrContextOptions* contextOptions, const void* identity, ssize_t size) {
contextOptions->fAllowPathMaskCaching = true;
- float screenMP = mMaxSurfaceArea / 1024.0f / 1024.0f;
- float fontCacheMB = 0;
- float decimalVal = std::modf(screenMP, &fontCacheMB);
-
- // This is a basic heuristic to size the cache to a multiple of 512 KB
- if (decimalVal > 0.8f) {
- fontCacheMB += 1.0f;
- } else if (decimalVal > 0.5f) {
- fontCacheMB += 0.5f;
- }
-
- // set limits on min/max size of the cache
- fontCacheMB = std::max(FONT_CACHE_MIN_MB, std::min(FONT_CACHE_MAX_MB, fontCacheMB));
-
- // We must currently set the size of the text cache based on the size of the
- // display even though we like to be dynamicallysizing it to the size of the window.
- // Skia's implementation doesn't provide a mechanism to resize the font cache due to
- // the potential cost of recreating the glyphs.
- contextOptions->fGlyphCacheTextureMaximumBytes = fontCacheMB * 1024 * 1024;
+ // This sets the maximum size for a single texture atlas in the GPU font cache. If necessary,
+ // the cache can allocate additional textures that are counted against the total cache limits
+ // provided to Skia.
+ contextOptions->fGlyphCacheTextureMaximumBytes = GrNextSizePow2(mMaxSurfaceArea);
if (mTaskManager.canRunTasks()) {
if (!mTaskProcessor.get()) {
diff --git a/libs/hwui/renderthread/RenderThread.h b/libs/hwui/renderthread/RenderThread.h
index 12666b323d11..5272227509c8 100644
--- a/libs/hwui/renderthread/RenderThread.h
+++ b/libs/hwui/renderthread/RenderThread.h
@@ -123,6 +123,7 @@ private:
friend class RenderProxy;
friend class DummyVsyncSource;
friend class android::uirenderer::TestUtils;
+ friend class android::uirenderer::WebViewFunctor;
RenderThread();
virtual ~RenderThread();
diff --git a/libs/hwui/service/GraphicsStatsService.cpp b/libs/hwui/service/GraphicsStatsService.cpp
index 3d50d2d7e59c..29e4256e2ab7 100644
--- a/libs/hwui/service/GraphicsStatsService.cpp
+++ b/libs/hwui/service/GraphicsStatsService.cpp
@@ -139,6 +139,7 @@ bool GraphicsStatsService::parseFromFile(const std::string& path,
uint32_t file_version = *reinterpret_cast<uint32_t*>(addr);
if (file_version != sCurrentFileVersion) {
ALOGW("file_version mismatch! expected %d got %d", sCurrentFileVersion, file_version);
+ munmap(addr, sb.st_size);
return false;
}
@@ -150,6 +151,7 @@ bool GraphicsStatsService::parseFromFile(const std::string& path,
ALOGW("Parse failed on '%s' error='%s'", path.c_str(),
output->InitializationErrorString().c_str());
}
+ munmap(addr, sb.st_size);
return success;
}
diff --git a/libs/hwui/tests/common/scenes/BitmapFillrate.cpp b/libs/hwui/tests/common/scenes/BitmapFillrate.cpp
index 1d3d60716d68..5af7d43d7f66 100644
--- a/libs/hwui/tests/common/scenes/BitmapFillrate.cpp
+++ b/libs/hwui/tests/common/scenes/BitmapFillrate.cpp
@@ -31,7 +31,7 @@ static bool _BitmapFillrate(
class BitmapFillrate : public TestScene {
public:
- BitmapFillrate(BitmapAllocationTestUtils::BitmapAllocator allocator)
+ explicit BitmapFillrate(BitmapAllocationTestUtils::BitmapAllocator allocator)
: TestScene(), mAllocator(allocator) {}
void createContent(int width, int height, Canvas& canvas) override {
@@ -70,4 +70,4 @@ private:
BitmapAllocationTestUtils::BitmapAllocator mAllocator;
std::vector<sp<RenderNode> > mNodes;
-}; \ No newline at end of file
+};
diff --git a/libs/hwui/tests/common/scenes/BitmapShaders.cpp b/libs/hwui/tests/common/scenes/BitmapShaders.cpp
index ad11a1d32310..510766073b08 100644
--- a/libs/hwui/tests/common/scenes/BitmapShaders.cpp
+++ b/libs/hwui/tests/common/scenes/BitmapShaders.cpp
@@ -26,7 +26,7 @@ static bool _BitmapShaders(BitmapAllocationTestUtils::registerBitmapAllocationSc
class BitmapShaders : public TestScene {
public:
- BitmapShaders(BitmapAllocationTestUtils::BitmapAllocator allocator)
+ explicit BitmapShaders(BitmapAllocationTestUtils::BitmapAllocator allocator)
: TestScene(), mAllocator(allocator) {}
sp<RenderNode> card;
diff --git a/libs/hwui/tests/common/scenes/TvApp.cpp b/libs/hwui/tests/common/scenes/TvApp.cpp
index a64e8444a9b1..286f5f194aed 100644
--- a/libs/hwui/tests/common/scenes/TvApp.cpp
+++ b/libs/hwui/tests/common/scenes/TvApp.cpp
@@ -48,7 +48,7 @@ static bool _TvAppNoRoundedCornerColorFilter(
class TvApp : public TestScene {
public:
- TvApp(BitmapAllocationTestUtils::BitmapAllocator allocator)
+ explicit TvApp(BitmapAllocationTestUtils::BitmapAllocator allocator)
: TestScene(), mAllocator(allocator) {}
sp<RenderNode> mBg;
@@ -232,7 +232,7 @@ private:
class TvAppNoRoundedCorner : public TvApp {
public:
- TvAppNoRoundedCorner(BitmapAllocationTestUtils::BitmapAllocator allocator) : TvApp(allocator) {}
+ explicit TvAppNoRoundedCorner(BitmapAllocationTestUtils::BitmapAllocator allocator) : TvApp(allocator) {}
private:
virtual float roundedCornerRadius() override { return dp(0); }
@@ -240,7 +240,7 @@ private:
class TvAppColorFilter : public TvApp {
public:
- TvAppColorFilter(BitmapAllocationTestUtils::BitmapAllocator allocator) : TvApp(allocator) {}
+ explicit TvAppColorFilter(BitmapAllocationTestUtils::BitmapAllocator allocator) : TvApp(allocator) {}
private:
virtual bool useOverlay() override { return false; }
@@ -248,7 +248,7 @@ private:
class TvAppNoRoundedCornerColorFilter : public TvApp {
public:
- TvAppNoRoundedCornerColorFilter(BitmapAllocationTestUtils::BitmapAllocator allocator)
+ explicit TvAppNoRoundedCornerColorFilter(BitmapAllocationTestUtils::BitmapAllocator allocator)
: TvApp(allocator) {}
private:
diff --git a/libs/hwui/tests/unit/SkiaRenderPropertiesTests.cpp b/libs/hwui/tests/unit/SkiaRenderPropertiesTests.cpp
index 479c462bd1a6..635429dea359 100644
--- a/libs/hwui/tests/unit/SkiaRenderPropertiesTests.cpp
+++ b/libs/hwui/tests/unit/SkiaRenderPropertiesTests.cpp
@@ -44,7 +44,7 @@ static void testProperty(std::function<void(RenderProperties&)> propSetupCallbac
static const int CANVAS_HEIGHT = 100;
class PropertyTestCanvas : public TestCanvasBase {
public:
- PropertyTestCanvas(std::function<void(const SkCanvas&)> callback)
+ explicit PropertyTestCanvas(std::function<void(const SkCanvas&)> callback)
: TestCanvasBase(CANVAS_WIDTH, CANVAS_HEIGHT), mCallback(callback) {}
void onDrawRect(const SkRect& rect, const SkPaint& paint) override {
EXPECT_EQ(mDrawCounter++, 0);
diff --git a/libs/hwui/tests/unit/ThreadBaseTests.cpp b/libs/hwui/tests/unit/ThreadBaseTests.cpp
index 1168ff211202..817c1f3d3e43 100644
--- a/libs/hwui/tests/unit/ThreadBaseTests.cpp
+++ b/libs/hwui/tests/unit/ThreadBaseTests.cpp
@@ -95,7 +95,7 @@ TEST(ThreadBase, lifecyclePerf) {
};
struct Counter {
- Counter(EventCount* count) : mCount(count) { mCount->construct++; }
+ explicit Counter(EventCount* count) : mCount(count) { mCount->construct++; }
Counter(const Counter& other) : mCount(other.mCount) {
if (mCount) mCount->copy++;
@@ -148,4 +148,4 @@ TEST(ThreadBase, lifecycle) {
ASSERT_EQ(1, dummyObject->getStrongCount());
ASSERT_EQ(2, lifecycleTestHelper(dummyObject));
ASSERT_EQ(1, dummyObject->getStrongCount());
-} \ No newline at end of file
+}
diff --git a/media/java/android/media/MediaRecorder.java b/media/java/android/media/MediaRecorder.java
index b16002900799..eeb146151ff1 100644
--- a/media/java/android/media/MediaRecorder.java
+++ b/media/java/android/media/MediaRecorder.java
@@ -456,6 +456,9 @@ public class MediaRecorder implements AudioRouting,
/** VP8/VORBIS data in a WEBM container */
public static final int WEBM = 9;
+ /** @hide HEIC data in a HEIF container */
+ public static final int HEIF = 10;
+
/** Opus data in a Ogg container */
public static final int OGG = 11;
};
diff --git a/media/java/android/media/session/ISessionController.aidl b/media/java/android/media/session/ISessionController.aidl
index e61bf5b48223..a843881e95ae 100644
--- a/media/java/android/media/session/ISessionController.aidl
+++ b/media/java/android/media/session/ISessionController.aidl
@@ -21,8 +21,8 @@ import android.content.pm.ParceledListSlice;
import android.media.MediaMetadata;
import android.media.Rating;
import android.media.session.ISessionControllerCallback;
+import android.media.session.MediaController;
import android.media.session.MediaSession;
-import android.media.session.ParcelableVolumeInfo;
import android.media.session.PlaybackState;
import android.net.Uri;
import android.os.Bundle;
@@ -47,7 +47,7 @@ interface ISessionController {
String getTag();
PendingIntent getLaunchPendingIntent();
long getFlags();
- ParcelableVolumeInfo getVolumeAttributes();
+ MediaController.PlaybackInfo getVolumeAttributes();
void adjustVolume(String packageName, String opPackageName,
in ISessionControllerCallback caller, boolean asSystemService, int direction,
int flags);
diff --git a/media/java/android/media/session/ISessionControllerCallback.aidl b/media/java/android/media/session/ISessionControllerCallback.aidl
index cf3176706d7e..fac8897d1b89 100644
--- a/media/java/android/media/session/ISessionControllerCallback.aidl
+++ b/media/java/android/media/session/ISessionControllerCallback.aidl
@@ -17,8 +17,8 @@ package android.media.session;
import android.content.pm.ParceledListSlice;
import android.media.MediaMetadata;
-import android.media.session.ParcelableVolumeInfo;
import android.media.session.PlaybackState;
+import android.media.session.MediaController;
import android.media.session.MediaSession;
import android.os.Bundle;
@@ -35,5 +35,5 @@ oneway interface ISessionControllerCallback {
void onQueueChanged(in ParceledListSlice queue);
void onQueueTitleChanged(CharSequence title);
void onExtrasChanged(in Bundle extras);
- void onVolumeInfoChanged(in ParcelableVolumeInfo info);
+ void onVolumeInfoChanged(in MediaController.PlaybackInfo info);
}
diff --git a/media/java/android/media/session/ParcelableVolumeInfo.aidl b/media/java/android/media/session/MediaController.aidl
index c4250f097fb4..17167f45d0e3 100644
--- a/media/java/android/media/session/ParcelableVolumeInfo.aidl
+++ b/media/java/android/media/session/MediaController.aidl
@@ -15,4 +15,4 @@
package android.media.session;
-parcelable ParcelableVolumeInfo;
+parcelable MediaController.PlaybackInfo;
diff --git a/media/java/android/media/session/MediaController.java b/media/java/android/media/session/MediaController.java
index 181ee5327547..ef2df15da8f4 100644
--- a/media/java/android/media/session/MediaController.java
+++ b/media/java/android/media/session/MediaController.java
@@ -32,6 +32,8 @@ import android.os.Bundle;
import android.os.Handler;
import android.os.Looper;
import android.os.Message;
+import android.os.Parcel;
+import android.os.Parcelable;
import android.os.RemoteException;
import android.os.ResultReceiver;
import android.text.TextUtils;
@@ -327,10 +329,7 @@ public final class MediaController {
*/
public @Nullable PlaybackInfo getPlaybackInfo() {
try {
- ParcelableVolumeInfo result = mSessionBinder.getVolumeAttributes();
- return new PlaybackInfo(result.volumeType, result.audioAttrs, result.controlType,
- result.maxVolume, result.currentVolume);
-
+ return mSessionBinder.getVolumeAttributes();
} catch (RemoteException e) {
Log.wtf(TAG, "Error calling getAudioInfo.", e);
}
@@ -986,15 +985,15 @@ public final class MediaController {
* Holds information about the current playback and how audio is handled for
* this session.
*/
- public static final class PlaybackInfo {
- /**
- * The session uses remote playback.
- */
- public static final int PLAYBACK_TYPE_REMOTE = 2;
+ public static final class PlaybackInfo implements Parcelable {
/**
* The session uses local playback.
*/
public static final int PLAYBACK_TYPE_LOCAL = 1;
+ /**
+ * The session uses remote playback.
+ */
+ public static final int PLAYBACK_TYPE_REMOTE = 2;
private final int mVolumeType;
private final int mVolumeControl;
@@ -1005,12 +1004,20 @@ public final class MediaController {
/**
* @hide
*/
- public PlaybackInfo(int type, AudioAttributes attrs, int control, int max, int current) {
+ public PlaybackInfo(int type, int control, int max, int current, AudioAttributes attrs) {
mVolumeType = type;
- mAudioAttrs = attrs;
mVolumeControl = control;
mMaxVolume = max;
mCurrentVolume = current;
+ mAudioAttrs = attrs;
+ }
+
+ PlaybackInfo(Parcel in) {
+ mVolumeType = in.readInt();
+ mVolumeControl = in.readInt();
+ mMaxVolume = in.readInt();
+ mCurrentVolume = in.readInt();
+ mAudioAttrs = in.readParcelable(null);
}
/**
@@ -1027,18 +1034,6 @@ public final class MediaController {
}
/**
- * Get the audio attributes for this session. The attributes will affect
- * volume handling for the session. When the volume type is
- * {@link PlaybackInfo#PLAYBACK_TYPE_REMOTE} these may be ignored by the
- * remote volume handler.
- *
- * @return The attributes for this session.
- */
- public AudioAttributes getAudioAttributes() {
- return mAudioAttrs;
- }
-
- /**
* Get the type of volume control that can be used. One of:
* <ul>
* <li>{@link VolumeProvider#VOLUME_CONTROL_ABSOLUTE}</li>
@@ -1070,6 +1065,52 @@ public final class MediaController {
public int getCurrentVolume() {
return mCurrentVolume;
}
+
+ /**
+ * Get the audio attributes for this session. The attributes will affect
+ * volume handling for the session. When the volume type is
+ * {@link PlaybackInfo#PLAYBACK_TYPE_REMOTE} these may be ignored by the
+ * remote volume handler.
+ *
+ * @return The attributes for this session.
+ */
+ public AudioAttributes getAudioAttributes() {
+ return mAudioAttrs;
+ }
+
+ @Override
+ public String toString() {
+ return "volumeType=" + mVolumeType + ", volumeControl=" + mVolumeControl
+ + ", maxVolume=" + mMaxVolume + ", currentVolume=" + mCurrentVolume
+ + ", audioAttrs=" + mAudioAttrs;
+ }
+
+ @Override
+ public int describeContents() {
+ return 0;
+ }
+
+ @Override
+ public void writeToParcel(Parcel dest, int flags) {
+ dest.writeInt(mVolumeType);
+ dest.writeInt(mVolumeControl);
+ dest.writeInt(mMaxVolume);
+ dest.writeInt(mCurrentVolume);
+ dest.writeParcelable(mAudioAttrs, flags);
+ }
+
+ public static final Parcelable.Creator<PlaybackInfo> CREATOR =
+ new Parcelable.Creator<PlaybackInfo>() {
+ @Override
+ public PlaybackInfo createFromParcel(Parcel in) {
+ return new PlaybackInfo(in);
+ }
+
+ @Override
+ public PlaybackInfo[] newArray(int size) {
+ return new PlaybackInfo[size];
+ }
+ };
}
private final static class CallbackStub extends ISessionControllerCallback.Stub {
@@ -1138,11 +1179,9 @@ public final class MediaController {
}
@Override
- public void onVolumeInfoChanged(ParcelableVolumeInfo pvi) {
+ public void onVolumeInfoChanged(PlaybackInfo info) {
MediaController controller = mController.get();
if (controller != null) {
- PlaybackInfo info = new PlaybackInfo(pvi.volumeType, pvi.audioAttrs,
- pvi.controlType, pvi.maxVolume, pvi.currentVolume);
controller.postMessage(MSG_UPDATE_VOLUME, info, null);
}
}
@@ -1154,7 +1193,7 @@ public final class MediaController {
private boolean mRegistered = false;
public MessageHandler(Looper looper, MediaController.Callback cb) {
- super(looper, null, true);
+ super(looper);
mCallback = cb;
}
@@ -1193,6 +1232,7 @@ public final class MediaController {
public void post(int what, Object obj, Bundle data) {
Message msg = obtainMessage(what, obj);
+ msg.setAsynchronous(true);
msg.setData(data);
msg.sendToTarget();
}
diff --git a/media/java/android/media/session/MediaSession.java b/media/java/android/media/session/MediaSession.java
index 8962bb7fb4c4..df8cc35945d3 100644
--- a/media/java/android/media/session/MediaSession.java
+++ b/media/java/android/media/session/MediaSession.java
@@ -1453,7 +1453,7 @@ public final class MediaSession {
private RemoteUserInfo mCurrentControllerInfo;
public CallbackMessageHandler(Looper looper, MediaSession.Callback callback) {
- super(looper, null, true);
+ super(looper);
mCallback = callback;
mCallback.mHandler = this;
}
@@ -1461,6 +1461,7 @@ public final class MediaSession {
public void post(RemoteUserInfo caller, int what, Object obj, Bundle data, long delayMs) {
Pair<RemoteUserInfo, Object> objWithCaller = Pair.create(caller, obj);
Message msg = obtainMessage(what, objWithCaller);
+ msg.setAsynchronous(true);
msg.setData(data);
if (delayMs > 0) {
sendMessageDelayed(msg, delayMs);
diff --git a/media/java/android/media/session/ParcelableVolumeInfo.java b/media/java/android/media/session/ParcelableVolumeInfo.java
deleted file mode 100644
index f59c9756d466..000000000000
--- a/media/java/android/media/session/ParcelableVolumeInfo.java
+++ /dev/null
@@ -1,80 +0,0 @@
-/* Copyright 2014, The Android Open Source Project
- **
- ** Licensed under the Apache License, Version 2.0 (the "License");
- ** you may not use this file except in compliance with the License.
- ** You may obtain a copy of the License at
- **
- ** http://www.apache.org/licenses/LICENSE-2.0
- **
- ** Unless required by applicable law or agreed to in writing, software
- ** distributed under the License is distributed on an "AS IS" BASIS,
- ** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- ** See the License for the specific language governing permissions and
- ** limitations under the License.
- */
-
-package android.media.session;
-
-import android.media.AudioAttributes;
-import android.os.Parcel;
-import android.os.Parcelable;
-
-/**
- * Convenience class for passing information about the audio configuration of a
- * session. The public implementation is {@link MediaController.PlaybackInfo}.
- *
- * @hide
- */
-public class ParcelableVolumeInfo implements Parcelable {
- public int volumeType;
- public AudioAttributes audioAttrs;
- public int controlType;
- public int maxVolume;
- public int currentVolume;
-
- public ParcelableVolumeInfo(int volumeType, AudioAttributes audioAttrs, int controlType,
- int maxVolume,
- int currentVolume) {
- this.volumeType = volumeType;
- this.audioAttrs = audioAttrs;
- this.controlType = controlType;
- this.maxVolume = maxVolume;
- this.currentVolume = currentVolume;
- }
-
- public ParcelableVolumeInfo(Parcel from) {
- volumeType = from.readInt();
- controlType = from.readInt();
- maxVolume = from.readInt();
- currentVolume = from.readInt();
- audioAttrs = AudioAttributes.CREATOR.createFromParcel(from);
- }
-
- @Override
- public int describeContents() {
- return 0;
- }
-
- @Override
- public void writeToParcel(Parcel dest, int flags) {
- dest.writeInt(volumeType);
- dest.writeInt(controlType);
- dest.writeInt(maxVolume);
- dest.writeInt(currentVolume);
- audioAttrs.writeToParcel(dest, flags);
- }
-
-
- public static final Parcelable.Creator<ParcelableVolumeInfo> CREATOR
- = new Parcelable.Creator<ParcelableVolumeInfo>() {
- @Override
- public ParcelableVolumeInfo createFromParcel(Parcel in) {
- return new ParcelableVolumeInfo(in);
- }
-
- @Override
- public ParcelableVolumeInfo[] newArray(int size) {
- return new ParcelableVolumeInfo[size];
- }
- };
-}
diff --git a/media/jni/Android.bp b/media/jni/Android.bp
index f75f69b4f2ee..fda0fc4c8546 100644
--- a/media/jni/Android.bp
+++ b/media/jni/Android.bp
@@ -102,7 +102,7 @@ cc_library_shared {
"libhidlbase",
"libhidlmemory",
- "libpowermanager", // Used by JWakeLock. Will be replace with public SDJ API.
+ "libpowermanager", // Used by JWakeLock. Will be replace with public SDK API.
"libmediametrics", // Used by MediaMetrics. Will be replaced with stable C API.
"libbinder", // Used by JWakeLock and MediaMetrics.
@@ -111,6 +111,7 @@ cc_library_shared {
// NDK or NDK-compliant
"libandroid",
+ "libbinder_ndk",
"libmediandk",
"libnativehelper_compat_libc++",
"liblog",
diff --git a/packages/CarSystemUI/src/com/android/systemui/car/CarNotificationInterruptionStateProvider.java b/packages/CarSystemUI/src/com/android/systemui/car/CarNotificationInterruptionStateProvider.java
index 62502ef60e96..6d960d7b9e21 100644
--- a/packages/CarSystemUI/src/com/android/systemui/car/CarNotificationInterruptionStateProvider.java
+++ b/packages/CarSystemUI/src/com/android/systemui/car/CarNotificationInterruptionStateProvider.java
@@ -18,8 +18,8 @@ package com.android.systemui.car;
import android.content.Context;
-import com.android.systemui.statusbar.notification.NotificationData;
import com.android.systemui.statusbar.notification.NotificationInterruptionStateProvider;
+import com.android.systemui.statusbar.notification.collection.NotificationEntry;
/** Auto-specific implementation of {@link NotificationInterruptionStateProvider}. */
public class CarNotificationInterruptionStateProvider extends
@@ -29,7 +29,7 @@ public class CarNotificationInterruptionStateProvider extends
}
@Override
- public boolean shouldHeadsUp(NotificationData.Entry entry) {
+ public boolean shouldHeadsUp(NotificationEntry entry) {
// Because space is usually constrained in the auto use-case, there should not be a
// pinned notification when the shade has been expanded. Ensure this by not pinning any
// notification if the shade is already opened.
diff --git a/packages/SettingsLib/BarChartPreference/src/com/android/settingslib/widget/BarChartPreference.java b/packages/SettingsLib/BarChartPreference/src/com/android/settingslib/widget/BarChartPreference.java
index eed66e94a9ef..d332bac3bb6d 100644
--- a/packages/SettingsLib/BarChartPreference/src/com/android/settingslib/widget/BarChartPreference.java
+++ b/packages/SettingsLib/BarChartPreference/src/com/android/settingslib/widget/BarChartPreference.java
@@ -77,7 +77,7 @@ import java.util.Arrays;
*/
public class BarChartPreference extends Preference {
- static final int MAXIMUM_BAR_VIEWS = 4;
+ public static final int MAXIMUM_BAR_VIEWS = 4;
private static final String TAG = "BarChartPreference";
private static final int[] BAR_VIEWS = {
R.id.bar_view1,
diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardClockSwitch.java b/packages/SystemUI/src/com/android/keyguard/KeyguardClockSwitch.java
index 570d351a8b71..27d624ab0b58 100644
--- a/packages/SystemUI/src/com/android/keyguard/KeyguardClockSwitch.java
+++ b/packages/SystemUI/src/com/android/keyguard/KeyguardClockSwitch.java
@@ -16,6 +16,8 @@ import com.android.systemui.Dependency;
import com.android.systemui.plugins.ClockPlugin;
import com.android.systemui.plugins.PluginListener;
import com.android.systemui.shared.plugins.PluginManager;
+import com.android.systemui.statusbar.StatusBarState;
+import com.android.systemui.statusbar.StatusBarStateController;
import java.util.Objects;
import java.util.TimeZone;
@@ -82,6 +84,24 @@ public class KeyguardClockSwitch extends RelativeLayout {
}
}
};
+ private final StatusBarStateController.StateListener mStateListener =
+ new StatusBarStateController.StateListener() {
+ @Override
+ public void onStateChanged(int newState) {
+ if (mBigClockContainer == null) {
+ return;
+ }
+ if (newState == StatusBarState.SHADE) {
+ if (mBigClockContainer.getVisibility() == View.VISIBLE) {
+ mBigClockContainer.setVisibility(View.INVISIBLE);
+ }
+ } else {
+ if (mBigClockContainer.getVisibility() == View.INVISIBLE) {
+ mBigClockContainer.setVisibility(View.VISIBLE);
+ }
+ }
+ }
+ };
public KeyguardClockSwitch(Context context) {
this(context, null);
@@ -104,12 +124,14 @@ public class KeyguardClockSwitch extends RelativeLayout {
super.onAttachedToWindow();
Dependency.get(PluginManager.class).addPluginListener(mClockPluginListener,
ClockPlugin.class);
+ Dependency.get(StatusBarStateController.class).addCallback(mStateListener);
}
@Override
protected void onDetachedFromWindow() {
super.onDetachedFromWindow();
Dependency.get(PluginManager.class).removePluginListener(mClockPluginListener);
+ Dependency.get(StatusBarStateController.class).removeCallback(mStateListener);
}
/**
@@ -238,4 +260,9 @@ public class KeyguardClockSwitch extends RelativeLayout {
PluginListener getClockPluginListener() {
return mClockPluginListener;
}
+
+ @VisibleForTesting (otherwise = VisibleForTesting.NONE)
+ StatusBarStateController.StateListener getStateListener() {
+ return mStateListener;
+ }
}
diff --git a/packages/SystemUI/src/com/android/systemui/Dependency.java b/packages/SystemUI/src/com/android/systemui/Dependency.java
index 3cc9bb6f668f..9d810645f6a2 100644
--- a/packages/SystemUI/src/com/android/systemui/Dependency.java
+++ b/packages/SystemUI/src/com/android/systemui/Dependency.java
@@ -56,12 +56,12 @@ import com.android.systemui.statusbar.SmartReplyController;
import com.android.systemui.statusbar.StatusBarStateController;
import com.android.systemui.statusbar.VibratorHelper;
import com.android.systemui.statusbar.notification.NotificationAlertingManager;
-import com.android.systemui.statusbar.notification.NotificationData.KeyguardEnvironment;
import com.android.systemui.statusbar.notification.NotificationEntryManager;
import com.android.systemui.statusbar.notification.NotificationFilter;
import com.android.systemui.statusbar.notification.NotificationInterruptionStateProvider;
import com.android.systemui.statusbar.notification.NotificationRowBinder;
import com.android.systemui.statusbar.notification.VisualStabilityManager;
+import com.android.systemui.statusbar.notification.collection.NotificationData.KeyguardEnvironment;
import com.android.systemui.statusbar.notification.logging.NotificationLogger;
import com.android.systemui.statusbar.notification.row.NotificationBlockingHelperManager;
import com.android.systemui.statusbar.notification.row.NotificationGutsManager;
diff --git a/packages/SystemUI/src/com/android/systemui/ForegroundServiceNotificationListener.java b/packages/SystemUI/src/com/android/systemui/ForegroundServiceNotificationListener.java
index b0b7e6c88984..96f216e357af 100644
--- a/packages/SystemUI/src/com/android/systemui/ForegroundServiceNotificationListener.java
+++ b/packages/SystemUI/src/com/android/systemui/ForegroundServiceNotificationListener.java
@@ -24,9 +24,9 @@ import android.service.notification.StatusBarNotification;
import android.util.Log;
import com.android.internal.statusbar.NotificationVisibility;
-import com.android.systemui.statusbar.notification.NotificationData;
import com.android.systemui.statusbar.notification.NotificationEntryListener;
import com.android.systemui.statusbar.notification.NotificationEntryManager;
+import com.android.systemui.statusbar.notification.collection.NotificationEntry;
import javax.inject.Inject;
import javax.inject.Singleton;
@@ -49,18 +49,18 @@ public class ForegroundServiceNotificationListener {
mForegroundServiceController = foregroundServiceController;
notificationEntryManager.addNotificationEntryListener(new NotificationEntryListener() {
@Override
- public void onPendingEntryAdded(NotificationData.Entry entry) {
+ public void onPendingEntryAdded(NotificationEntry entry) {
addNotification(entry.notification, entry.importance);
}
@Override
- public void onEntryUpdated(NotificationData.Entry entry) {
+ public void onEntryUpdated(NotificationEntry entry) {
updateNotification(entry.notification, entry.importance);
}
@Override
public void onEntryRemoved(
- NotificationData.Entry entry,
+ NotificationEntry entry,
NotificationVisibility visibility,
boolean removedByUser) {
removeNotification(entry.notification);
diff --git a/packages/SystemUI/src/com/android/systemui/SystemUIFactory.java b/packages/SystemUI/src/com/android/systemui/SystemUIFactory.java
index 5347a5cb16b6..d0111cb1a5b3 100644
--- a/packages/SystemUI/src/com/android/systemui/SystemUIFactory.java
+++ b/packages/SystemUI/src/com/android/systemui/SystemUIFactory.java
@@ -40,9 +40,9 @@ import com.android.systemui.statusbar.NotificationListener;
import com.android.systemui.statusbar.NotificationLockscreenUserManager;
import com.android.systemui.statusbar.NotificationLockscreenUserManagerImpl;
import com.android.systemui.statusbar.ScrimView;
-import com.android.systemui.statusbar.notification.NotificationData;
import com.android.systemui.statusbar.notification.NotificationEntryManager;
import com.android.systemui.statusbar.notification.NotificationInterruptionStateProvider;
+import com.android.systemui.statusbar.notification.collection.NotificationData;
import com.android.systemui.statusbar.phone.DozeParameters;
import com.android.systemui.statusbar.phone.KeyguardBouncer;
import com.android.systemui.statusbar.phone.KeyguardEnvironmentImpl;
diff --git a/packages/SystemUI/src/com/android/systemui/bubbles/BubbleController.java b/packages/SystemUI/src/com/android/systemui/bubbles/BubbleController.java
index 644723321103..75776098decf 100644
--- a/packages/SystemUI/src/com/android/systemui/bubbles/BubbleController.java
+++ b/packages/SystemUI/src/com/android/systemui/bubbles/BubbleController.java
@@ -35,9 +35,9 @@ import android.widget.FrameLayout;
import com.android.internal.annotations.VisibleForTesting;
import com.android.systemui.Dependency;
import com.android.systemui.R;
-import com.android.systemui.statusbar.notification.NotificationData;
import com.android.systemui.statusbar.notification.NotificationEntryListener;
import com.android.systemui.statusbar.notification.NotificationEntryManager;
+import com.android.systemui.statusbar.notification.collection.NotificationEntry;
import com.android.systemui.statusbar.phone.StatusBarWindowController;
import java.util.ArrayList;
@@ -180,7 +180,7 @@ public class BubbleController {
/**
* Adds a bubble associated with the provided notification entry or updates it if it exists.
*/
- public void addBubble(NotificationData.Entry notif) {
+ public void addBubble(NotificationEntry notif) {
if (mBubbles.containsKey(notif.key)) {
// It's an update
BubbleView bubble = mBubbles.get(notif.key);
@@ -226,7 +226,7 @@ public class BubbleController {
bv.getEntry().setBubbleDismissed(true);
}
- NotificationData.Entry entry = mNotificationEntryManager.getNotificationData().get(key);
+ NotificationEntry entry = mNotificationEntryManager.getNotificationData().get(key);
if (entry != null) {
entry.setBubbleDismissed(true);
if (!DEBUG_DEMOTE_TO_NOTIF) {
@@ -241,7 +241,7 @@ public class BubbleController {
@SuppressWarnings("FieldCanBeLocal")
private final NotificationEntryListener mEntryListener = new NotificationEntryListener() {
@Override
- public void onPendingEntryAdded(NotificationData.Entry entry) {
+ public void onPendingEntryAdded(NotificationEntry entry) {
if (shouldAutoBubble(mContext, entry)) {
entry.setIsBubble(true);
}
@@ -275,7 +275,7 @@ public class BubbleController {
}
ArrayList<BubbleView> viewsToRemove = new ArrayList<>();
for (BubbleView bv : mBubbles.values()) {
- NotificationData.Entry entry = bv.getEntry();
+ NotificationEntry entry = bv.getEntry();
if (entry != null) {
if (entry.isRowRemoved() || entry.isBubbleDismissed() || entry.isRowDismissed()) {
viewsToRemove.add(bv);
@@ -332,7 +332,7 @@ public class BubbleController {
/**
* Whether the notification should bubble or not.
*/
- private static boolean shouldAutoBubble(Context context, NotificationData.Entry entry) {
+ private static boolean shouldAutoBubble(Context context, NotificationEntry entry) {
if (entry.isBubbleDismissed()) {
return false;
}
diff --git a/packages/SystemUI/src/com/android/systemui/bubbles/BubbleStackView.java b/packages/SystemUI/src/com/android/systemui/bubbles/BubbleStackView.java
index dfd18b23a5e3..d69e7b3ae924 100644
--- a/packages/SystemUI/src/com/android/systemui/bubbles/BubbleStackView.java
+++ b/packages/SystemUI/src/com/android/systemui/bubbles/BubbleStackView.java
@@ -40,7 +40,7 @@ import androidx.annotation.Nullable;
import com.android.internal.widget.ViewClippingUtil;
import com.android.systemui.R;
-import com.android.systemui.statusbar.notification.NotificationData;
+import com.android.systemui.statusbar.notification.collection.NotificationEntry;
import com.android.systemui.statusbar.notification.row.ExpandableNotificationRow;
import com.android.systemui.statusbar.notification.stack.ExpandableViewState;
import com.android.systemui.statusbar.notification.stack.ViewState;
@@ -247,7 +247,7 @@ public class BubbleStackView extends FrameLayout implements BubbleTouchHandler.F
* @param bubbleView the view to update in the stack.
* @param entry the entry to update it with.
*/
- public void updateBubble(BubbleView bubbleView, NotificationData.Entry entry) {
+ public void updateBubble(BubbleView bubbleView, NotificationEntry entry) {
// TODO - move to top of bubble stack, make it show its update if it makes sense
bubbleView.update(entry);
if (bubbleView.equals(mExpandedBubble)) {
diff --git a/packages/SystemUI/src/com/android/systemui/bubbles/BubbleView.java b/packages/SystemUI/src/com/android/systemui/bubbles/BubbleView.java
index 6c47aac712f6..3307992e779a 100644
--- a/packages/SystemUI/src/com/android/systemui/bubbles/BubbleView.java
+++ b/packages/SystemUI/src/com/android/systemui/bubbles/BubbleView.java
@@ -31,7 +31,7 @@ import android.widget.LinearLayout;
import com.android.internal.util.ContrastColorUtil;
import com.android.systemui.R;
-import com.android.systemui.statusbar.notification.NotificationData;
+import com.android.systemui.statusbar.notification.collection.NotificationEntry;
import com.android.systemui.statusbar.notification.row.ExpandableNotificationRow;
/**
@@ -43,7 +43,7 @@ public class BubbleView extends LinearLayout implements BubbleTouchHandler.Float
private Context mContext;
private View mIconView;
- private NotificationData.Entry mEntry;
+ private NotificationEntry mEntry;
private int mBubbleSize;
private int mIconSize;
@@ -72,7 +72,7 @@ public class BubbleView extends LinearLayout implements BubbleTouchHandler.Float
*
* @param entry the notification to display as a bubble.
*/
- public void setNotif(NotificationData.Entry entry) {
+ public void setNotif(NotificationEntry entry) {
removeAllViews();
// TODO: migrate to inflater
mIconView = new ImageView(mContext);
@@ -89,7 +89,7 @@ public class BubbleView extends LinearLayout implements BubbleTouchHandler.Float
/**
* Updates the UI based on the entry.
*/
- public void update(NotificationData.Entry entry) {
+ public void update(NotificationEntry entry) {
mEntry = entry;
Notification n = entry.notification.getNotification();
Icon ic = n.getLargeIcon() != null ? n.getLargeIcon() : n.getSmallIcon();
@@ -112,7 +112,7 @@ public class BubbleView extends LinearLayout implements BubbleTouchHandler.Float
/**
* @return the notification entry associated with this bubble.
*/
- public NotificationData.Entry getEntry() {
+ public NotificationEntry getEntry() {
return mEntry;
}
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardSliceProvider.java b/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardSliceProvider.java
index 6a0e8ad35736..c4c8bc703802 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardSliceProvider.java
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardSliceProvider.java
@@ -50,9 +50,9 @@ import androidx.slice.builders.SliceAction;
import com.android.internal.annotations.VisibleForTesting;
import com.android.keyguard.KeyguardUpdateMonitor;
import com.android.keyguard.KeyguardUpdateMonitorCallback;
-import com.android.systemui.Dependency;
import com.android.systemui.R;
import com.android.systemui.statusbar.NotificationMediaManager;
+import com.android.systemui.statusbar.StatusBarStateController;
import com.android.systemui.statusbar.policy.NextAlarmController;
import com.android.systemui.statusbar.policy.NextAlarmControllerImpl;
import com.android.systemui.statusbar.policy.ZenModeController;
@@ -68,7 +68,7 @@ import java.util.concurrent.TimeUnit;
*/
public class KeyguardSliceProvider extends SliceProvider implements
NextAlarmController.NextAlarmChangeCallback, ZenModeController.Callback,
- NotificationMediaManager.MediaListener {
+ NotificationMediaManager.MediaListener, StatusBarStateController.StateListener {
private static final StyleSpan BOLD_STYLE = new StyleSpan(Typeface.BOLD);
public static final String KEYGUARD_SLICE_URI = "content://com.android.systemui.keyguard/main";
@@ -109,7 +109,9 @@ public class KeyguardSliceProvider extends SliceProvider implements
private AlarmManager.AlarmClockInfo mNextAlarmInfo;
private PendingIntent mPendingIntent;
protected NotificationMediaManager mMediaManager;
+ private StatusBarStateController mStatusBarStateController;
protected MediaMetadata mMediaMetaData;
+ protected boolean mDozing;
/**
* Receiver responsible for time ticking and updating the date format.
@@ -167,9 +169,20 @@ public class KeyguardSliceProvider extends SliceProvider implements
mMediaUri = Uri.parse(KEYGUARD_MEDIA_URI);
}
- public void initDependencies() {
- mMediaManager = Dependency.get(NotificationMediaManager.class);
+ /**
+ * Initialize dependencies that don't exist during {@link android.content.ContentProvider}
+ * instantiation.
+ *
+ * @param mediaManager {@link NotificationMediaManager} singleton.
+ * @param statusBarStateController {@link StatusBarStateController} singleton.
+ */
+ public void initDependencies(
+ NotificationMediaManager mediaManager,
+ StatusBarStateController statusBarStateController) {
+ mMediaManager = mediaManager;
mMediaManager.addCallback(this);
+ mStatusBarStateController = statusBarStateController;
+ mStatusBarStateController.addCallback(this);
}
@AnyThread
@@ -179,7 +192,7 @@ public class KeyguardSliceProvider extends SliceProvider implements
Slice slice;
synchronized (this) {
ListBuilder builder = new ListBuilder(getContext(), mSliceUri, ListBuilder.INFINITY);
- if (mMediaMetaData != null) {
+ if (needsMediaLocked()) {
addMediaLocked(builder);
} else {
builder.addRow(new RowBuilder(mDateUri).setTitle(mLastText));
@@ -193,6 +206,10 @@ public class KeyguardSliceProvider extends SliceProvider implements
return slice;
}
+ protected boolean needsMediaLocked() {
+ return mMediaMetaData != null && mDozing;
+ }
+
protected void addMediaLocked(ListBuilder listBuilder) {
if (mMediaMetaData != null) {
SpannableStringBuilder builder = new SpannableStringBuilder();
@@ -209,7 +226,7 @@ public class KeyguardSliceProvider extends SliceProvider implements
}
RowBuilder mediaBuilder = new RowBuilder(mMediaUri).setTitle(builder);
- Icon notificationIcon = mMediaManager.getMediaIcon();
+ Icon notificationIcon = mMediaManager == null ? null : mMediaManager.getMediaIcon();
if (notificationIcon != null) {
IconCompat icon = IconCompat.createFromIcon(notificationIcon);
mediaBuilder.addEndItem(icon, ListBuilder.ICON_IMAGE);
@@ -389,13 +406,35 @@ public class KeyguardSliceProvider extends SliceProvider implements
@Override
public void onMetadataChanged(MediaMetadata metadata) {
+ final boolean notify;
synchronized (this) {
+ boolean neededMedia = needsMediaLocked();
mMediaMetaData = metadata;
+ notify = neededMedia != needsMediaLocked();
+ }
+ if (notify) {
+ notifyChange();
}
- notifyChange();
}
protected void notifyChange() {
mContentResolver.notifyChange(mSliceUri, null /* observer */);
}
+
+ @Override
+ public void onDozingChanged(boolean isDozing) {
+ final boolean notify;
+ synchronized (this) {
+ boolean neededMedia = needsMediaLocked();
+ mDozing = isDozing;
+ notify = neededMedia != needsMediaLocked();
+ }
+ if (notify) {
+ notifyChange();
+ }
+ }
+
+ @Override
+ public void onStateChanged(int newState) {
+ }
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/AlertingNotificationManager.java b/packages/SystemUI/src/com/android/systemui/statusbar/AlertingNotificationManager.java
index bc381699494a..a776d0fbb45e 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/AlertingNotificationManager.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/AlertingNotificationManager.java
@@ -16,8 +16,6 @@
package com.android.systemui.statusbar;
-import static com.android.systemui.statusbar.notification.NotificationData.Entry;
-
import android.annotation.NonNull;
import android.annotation.Nullable;
import android.os.Handler;
@@ -29,6 +27,7 @@ import android.util.Log;
import android.view.accessibility.AccessibilityEvent;
import com.android.internal.annotations.VisibleForTesting;
+import com.android.systemui.statusbar.notification.collection.NotificationEntry;
import com.android.systemui.statusbar.notification.row.NotificationInflater.InflationFlag;
import java.util.stream.Stream;
@@ -48,7 +47,7 @@ public abstract class AlertingNotificationManager implements NotificationLifetim
* NotificationManagerService side, but we keep it to prevent the UI from looking weird and
* will remove when possible. See {@link NotificationLifetimeExtender}
*/
- protected final ArraySet<Entry> mExtendedLifetimeAlertEntries = new ArraySet<>();
+ protected final ArraySet<NotificationEntry> mExtendedLifetimeAlertEntries = new ArraySet<>();
protected NotificationSafeToRemoveCallback mNotificationLifetimeFinishedCallback;
protected int mMinimumDisplayTime;
@@ -61,7 +60,7 @@ public abstract class AlertingNotificationManager implements NotificationLifetim
* Adds the notification to be managed.
* @param entry entry to show
*/
- public void showNotification(@NonNull Entry entry) {
+ public void showNotification(@NonNull NotificationEntry entry) {
if (Log.isLoggable(TAG, Log.VERBOSE)) {
Log.v(TAG, "showNotification");
}
@@ -139,7 +138,7 @@ public abstract class AlertingNotificationManager implements NotificationLifetim
* @return the entry
*/
@Nullable
- public Entry getEntry(@NonNull String key) {
+ public NotificationEntry getEntry(@NonNull String key) {
AlertEntry entry = mAlertEntries.get(key);
return entry != null ? entry.mEntry : null;
}
@@ -149,7 +148,7 @@ public abstract class AlertingNotificationManager implements NotificationLifetim
* @return all entries
*/
@NonNull
- public Stream<Entry> getAllEntries() {
+ public Stream<NotificationEntry> getAllEntries() {
return mAlertEntries.values().stream().map(headsUpEntry -> headsUpEntry.mEntry);
}
@@ -180,7 +179,7 @@ public abstract class AlertingNotificationManager implements NotificationLifetim
* Add a new entry and begin managing it.
* @param entry the entry to add
*/
- protected final void addAlertEntry(@NonNull Entry entry) {
+ protected final void addAlertEntry(@NonNull NotificationEntry entry) {
AlertEntry alertEntry = createAlertEntry();
alertEntry.setEntry(entry);
mAlertEntries.put(entry.key, alertEntry);
@@ -203,7 +202,7 @@ public abstract class AlertingNotificationManager implements NotificationLifetim
if (alertEntry == null) {
return;
}
- Entry entry = alertEntry.mEntry;
+ NotificationEntry entry = alertEntry.mEntry;
mAlertEntries.remove(key);
onAlertEntryRemoved(alertEntry);
entry.sendAccessibilityEvent(AccessibilityEvent.TYPE_WINDOW_CONTENT_CHANGED);
@@ -250,12 +249,12 @@ public abstract class AlertingNotificationManager implements NotificationLifetim
}
@Override
- public boolean shouldExtendLifetime(Entry entry) {
+ public boolean shouldExtendLifetime(NotificationEntry entry) {
return !canRemoveImmediately(entry.key);
}
@Override
- public void setShouldManageLifetime(Entry entry, boolean shouldExtend) {
+ public void setShouldManageLifetime(NotificationEntry entry, boolean shouldExtend) {
if (shouldExtend) {
mExtendedLifetimeAlertEntries.add(entry);
} else {
@@ -265,17 +264,17 @@ public abstract class AlertingNotificationManager implements NotificationLifetim
///////////////////////////////////////////////////////////////////////////////////////////////
protected class AlertEntry implements Comparable<AlertEntry> {
- @Nullable public Entry mEntry;
+ @Nullable public NotificationEntry mEntry;
public long mPostTime;
public long mEarliestRemovaltime;
@Nullable protected Runnable mRemoveAlertRunnable;
- public void setEntry(@NonNull final Entry entry) {
+ public void setEntry(@NonNull final NotificationEntry entry) {
setEntry(entry, () -> removeAlertEntry(entry.key));
}
- public void setEntry(@NonNull final Entry entry,
+ public void setEntry(@NonNull final NotificationEntry entry,
@Nullable Runnable removeAlertRunnable) {
mEntry = entry;
mRemoveAlertRunnable = removeAlertRunnable;
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/AmbientPulseManager.java b/packages/SystemUI/src/com/android/systemui/statusbar/AmbientPulseManager.java
index 9bfd4ee24ff0..a3beb96780d3 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/AmbientPulseManager.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/AmbientPulseManager.java
@@ -25,7 +25,7 @@ import android.util.ArraySet;
import com.android.internal.annotations.VisibleForTesting;
import com.android.systemui.R;
-import com.android.systemui.statusbar.notification.NotificationData;
+import com.android.systemui.statusbar.notification.collection.NotificationEntry;
import com.android.systemui.statusbar.notification.row.NotificationInflater.InflationFlag;
import javax.inject.Inject;
@@ -83,7 +83,7 @@ public class AmbientPulseManager extends AlertingNotificationManager {
@Override
protected void onAlertEntryAdded(AlertEntry alertEntry) {
- NotificationData.Entry entry = alertEntry.mEntry;
+ NotificationEntry entry = alertEntry.mEntry;
entry.setAmbientPulsing(true);
for (OnAmbientChangedListener listener : mListeners) {
listener.onAmbientStateChanged(entry, true);
@@ -92,7 +92,7 @@ public class AmbientPulseManager extends AlertingNotificationManager {
@Override
protected void onAlertEntryRemoved(AlertEntry alertEntry) {
- NotificationData.Entry entry = alertEntry.mEntry;
+ NotificationEntry entry = alertEntry.mEntry;
entry.setAmbientPulsing(false);
for (OnAmbientChangedListener listener : mListeners) {
listener.onAmbientStateChanged(entry, false);
@@ -131,7 +131,7 @@ public class AmbientPulseManager extends AlertingNotificationManager {
* @param entry the entry that changed
* @param isPulsing true if the entry is now pulsing, false otherwise
*/
- void onAmbientStateChanged(NotificationData.Entry entry, boolean isPulsing);
+ void onAmbientStateChanged(NotificationEntry entry, boolean isPulsing);
}
private final class AmbientEntry extends AlertEntry {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/HeadsUpStatusBarView.java b/packages/SystemUI/src/com/android/systemui/statusbar/HeadsUpStatusBarView.java
index e2177774a75d..3f1ff33437b9 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/HeadsUpStatusBarView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/HeadsUpStatusBarView.java
@@ -32,7 +32,7 @@ import com.android.internal.annotations.VisibleForTesting;
import com.android.keyguard.AlphaOptimizedLinearLayout;
import com.android.systemui.R;
import com.android.systemui.plugins.DarkIconDispatcher;
-import com.android.systemui.statusbar.notification.NotificationData;
+import com.android.systemui.statusbar.notification.collection.NotificationEntry;
import java.util.List;
@@ -50,7 +50,7 @@ public class HeadsUpStatusBarView extends AlphaOptimizedLinearLayout {
private int mEndMargin;
private View mIconPlaceholder;
private TextView mTextView;
- private NotificationData.Entry mShowingEntry;
+ private NotificationEntry mShowingEntry;
private Rect mLayoutedIconRect = new Rect();
private int[] mTmpPosition = new int[2];
private boolean mFirstLayout = true;
@@ -162,7 +162,7 @@ public class HeadsUpStatusBarView extends AlphaOptimizedLinearLayout {
mTextView = findViewById(R.id.text);
}
- public void setEntry(NotificationData.Entry entry) {
+ public void setEntry(NotificationEntry entry) {
if (entry != null) {
mShowingEntry = entry;
CharSequence text = entry.headsUpStatusBarText;
@@ -261,7 +261,7 @@ public class HeadsUpStatusBarView extends AlphaOptimizedLinearLayout {
return super.fitSystemWindows(insets);
}
- public NotificationData.Entry getShowingEntry() {
+ public NotificationEntry getShowingEntry() {
return mShowingEntry;
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationLifetimeExtender.java b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationLifetimeExtender.java
index ecd9814c3073..0f295ba75fe4 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationLifetimeExtender.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationLifetimeExtender.java
@@ -2,7 +2,7 @@ package com.android.systemui.statusbar;
import androidx.annotation.NonNull;
-import com.android.systemui.statusbar.notification.NotificationData;
+import com.android.systemui.statusbar.notification.collection.NotificationEntry;
/**
* Interface for anything that may need to keep notifications managed even after
@@ -24,7 +24,7 @@ public interface NotificationLifetimeExtender {
* @param entry the entry containing the notification to check
* @return true if the notification lifetime should be extended
*/
- boolean shouldExtendLifetime(@NonNull NotificationData.Entry entry);
+ boolean shouldExtendLifetime(@NonNull NotificationEntry entry);
/**
* Sets whether or not the lifetime should be managed by the extender. In practice, if
@@ -37,7 +37,7 @@ public interface NotificationLifetimeExtender {
* @param entry the entry that needs an extended lifetime
* @param shouldManage true if the extender should manage the entry now, false otherwise
*/
- void setShouldManageLifetime(@NonNull NotificationData.Entry entry, boolean shouldManage);
+ void setShouldManageLifetime(@NonNull NotificationEntry entry, boolean shouldManage);
/**
* The callback for when the notification is now safe to remove (i.e. its lifetime has ended).
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationLockscreenUserManager.java b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationLockscreenUserManager.java
index bc662e3d8855..f46ded4d61d8 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationLockscreenUserManager.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationLockscreenUserManager.java
@@ -18,7 +18,7 @@ import android.content.pm.UserInfo;
import android.service.notification.StatusBarNotification;
import android.util.SparseArray;
-import com.android.systemui.statusbar.notification.NotificationData.Entry;
+import com.android.systemui.statusbar.notification.collection.NotificationEntry;
public interface NotificationLockscreenUserManager {
String PERMISSION_SELF = "com.android.systemui.permission.SELF";
@@ -55,7 +55,7 @@ public interface NotificationLockscreenUserManager {
void updatePublicMode();
- boolean needsRedaction(Entry entry);
+ boolean needsRedaction(NotificationEntry entry);
boolean userAllowsPrivateNotificationsInPublic(int currentUserId);
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationLockscreenUserManagerImpl.java b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationLockscreenUserManagerImpl.java
index bba4369b5e01..d5f4d0461ba4 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationLockscreenUserManagerImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationLockscreenUserManagerImpl.java
@@ -46,9 +46,9 @@ import com.android.systemui.Dependency;
import com.android.systemui.Dumpable;
import com.android.systemui.recents.OverviewProxyService;
import com.android.systemui.statusbar.StatusBarStateController.StateListener;
-import com.android.systemui.statusbar.notification.NotificationData;
import com.android.systemui.statusbar.notification.NotificationEntryManager;
import com.android.systemui.statusbar.notification.NotificationUtils;
+import com.android.systemui.statusbar.notification.collection.NotificationEntry;
import com.android.systemui.statusbar.policy.DeviceProvisionedController;
import com.android.systemui.statusbar.policy.KeyguardMonitor;
@@ -407,7 +407,7 @@ public class NotificationLockscreenUserManagerImpl implements
}
/** @return true if the entry needs redaction when on the lockscreen. */
- public boolean needsRedaction(NotificationData.Entry ent) {
+ public boolean needsRedaction(NotificationEntry ent) {
int userId = ent.notification.getUserId();
boolean currentUserWantsRedaction = !userAllowsPrivateNotificationsInPublic(mCurrentUserId);
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationMediaManager.java b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationMediaManager.java
index e59bc2a82c4c..7412702abfea 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationMediaManager.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationMediaManager.java
@@ -46,9 +46,9 @@ import com.android.systemui.Dependency;
import com.android.systemui.Dumpable;
import com.android.systemui.Interpolators;
import com.android.systemui.colorextraction.SysuiColorExtractor;
-import com.android.systemui.statusbar.notification.NotificationData.Entry;
import com.android.systemui.statusbar.notification.NotificationEntryListener;
import com.android.systemui.statusbar.notification.NotificationEntryManager;
+import com.android.systemui.statusbar.notification.collection.NotificationEntry;
import com.android.systemui.statusbar.phone.BiometricUnlockController;
import com.android.systemui.statusbar.phone.LockscreenWallpaper;
import com.android.systemui.statusbar.phone.ScrimController;
@@ -156,7 +156,7 @@ public class NotificationMediaManager implements Dumpable {
notificationEntryManager.addNotificationEntryListener(new NotificationEntryListener() {
@Override
public void onEntryRemoved(
- Entry entry,
+ NotificationEntry entry,
NotificationVisibility visibility,
boolean removedByUser) {
onNotificationRemoved(entry.key);
@@ -188,7 +188,7 @@ public class NotificationMediaManager implements Dumpable {
return null;
}
synchronized (mEntryManager.getNotificationData()) {
- Entry entry = mEntryManager.getNotificationData().get(mMediaNotificationKey);
+ NotificationEntry entry = mEntryManager.getNotificationData().get(mMediaNotificationKey);
if (entry == null || entry.expandedIcon == null) {
return null;
}
@@ -210,15 +210,15 @@ public class NotificationMediaManager implements Dumpable {
boolean metaDataChanged = false;
synchronized (mEntryManager.getNotificationData()) {
- ArrayList<Entry> activeNotifications =
+ ArrayList<NotificationEntry> activeNotifications =
mEntryManager.getNotificationData().getActiveNotifications();
final int N = activeNotifications.size();
// Promote the media notification with a controller in 'playing' state, if any.
- Entry mediaNotification = null;
+ NotificationEntry mediaNotification = null;
MediaController controller = null;
for (int i = 0; i < N; i++) {
- final Entry entry = activeNotifications.get(i);
+ final NotificationEntry entry = activeNotifications.get(i);
if (entry.isMediaNotification()) {
final MediaSession.Token token =
@@ -258,7 +258,7 @@ public class NotificationMediaManager implements Dumpable {
final String pkg = aController.getPackageName();
for (int i = 0; i < N; i++) {
- final Entry entry = activeNotifications.get(i);
+ final NotificationEntry entry = activeNotifications.get(i);
if (entry.notification.getPackageName().equals(pkg)) {
if (DEBUG_MEDIA) {
Log.v(TAG, "DEBUG_MEDIA: found controller matching "
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationRemoteInputManager.java b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationRemoteInputManager.java
index 1ab9c5c2b4a2..7d6231f27885 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationRemoteInputManager.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationRemoteInputManager.java
@@ -51,9 +51,9 @@ import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.statusbar.IStatusBarService;
import com.android.internal.statusbar.NotificationVisibility;
import com.android.systemui.Dumpable;
-import com.android.systemui.statusbar.notification.NotificationData;
import com.android.systemui.statusbar.notification.NotificationEntryListener;
import com.android.systemui.statusbar.notification.NotificationEntryManager;
+import com.android.systemui.statusbar.notification.collection.NotificationEntry;
import com.android.systemui.statusbar.notification.row.ExpandableNotificationRow;
import com.android.systemui.statusbar.phone.ShadeController;
import com.android.systemui.statusbar.policy.RemoteInputView;
@@ -103,7 +103,7 @@ public class NotificationRemoteInputManager implements Dumpable {
* Notifications that are already removed but are kept around because the remote input is
* actively being used (i.e. user is typing in it). See {@link RemoteInputActiveExtender}.
*/
- protected final ArraySet<NotificationData.Entry> mEntriesKeptForRemoteInputActive =
+ protected final ArraySet<NotificationEntry> mEntriesKeptForRemoteInputActive =
new ArraySet<>();
// Dependencies:
@@ -253,7 +253,7 @@ public class NotificationRemoteInputManager implements Dumpable {
notificationEntryManager.addNotificationEntryListener(new NotificationEntryListener() {
@Override
public void onEntryRemoved(
- @Nullable NotificationData.Entry entry,
+ @Nullable NotificationEntry entry,
NotificationVisibility visibility,
boolean removedByUser) {
if (removedByUser && entry != null) {
@@ -269,7 +269,7 @@ public class NotificationRemoteInputManager implements Dumpable {
mRemoteInputController = new RemoteInputController(delegate);
mRemoteInputController.addCallback(new RemoteInputController.Callback() {
@Override
- public void onRemoteInputSent(NotificationData.Entry entry) {
+ public void onRemoteInputSent(NotificationEntry entry) {
if (FORCE_REMOTE_INPUT_HISTORY
&& isNotificationKeptForRemoteInputHistory(entry.key)) {
mNotificationLifetimeFinishedCallback.onSafeToRemove(entry.key);
@@ -413,7 +413,7 @@ public class NotificationRemoteInputManager implements Dumpable {
}
@VisibleForTesting
- void onPerformRemoveNotification(NotificationData.Entry entry, final String key) {
+ void onPerformRemoveNotification(NotificationEntry entry, final String key) {
if (mKeysKeptForRemoteInputHistory.contains(key)) {
mKeysKeptForRemoteInputHistory.remove(key);
}
@@ -424,7 +424,7 @@ public class NotificationRemoteInputManager implements Dumpable {
public void onPanelCollapsed() {
for (int i = 0; i < mEntriesKeptForRemoteInputActive.size(); i++) {
- NotificationData.Entry entry = mEntriesKeptForRemoteInputActive.valueAt(i);
+ NotificationEntry entry = mEntriesKeptForRemoteInputActive.valueAt(i);
mRemoteInputController.removeRemoteInput(entry, null);
if (mNotificationLifetimeFinishedCallback != null) {
mNotificationLifetimeFinishedCallback.onSafeToRemove(entry.key);
@@ -437,7 +437,7 @@ public class NotificationRemoteInputManager implements Dumpable {
return mKeysKeptForRemoteInputHistory.contains(key);
}
- public boolean shouldKeepForRemoteInputHistory(NotificationData.Entry entry) {
+ public boolean shouldKeepForRemoteInputHistory(NotificationEntry entry) {
if (entry.isDismissed()) {
return false;
}
@@ -447,7 +447,7 @@ public class NotificationRemoteInputManager implements Dumpable {
return (mRemoteInputController.isSpinning(entry.key) || entry.hasJustSentRemoteInput());
}
- public boolean shouldKeepForSmartReplyHistory(NotificationData.Entry entry) {
+ public boolean shouldKeepForSmartReplyHistory(NotificationEntry entry) {
if (entry.isDismissed()) {
return false;
}
@@ -467,13 +467,13 @@ public class NotificationRemoteInputManager implements Dumpable {
@VisibleForTesting
StatusBarNotification rebuildNotificationForCanceledSmartReplies(
- NotificationData.Entry entry) {
+ NotificationEntry entry) {
return rebuildNotificationWithRemoteInput(entry, null /* remoteInputTest */,
false /* showSpinner */);
}
@VisibleForTesting
- StatusBarNotification rebuildNotificationWithRemoteInput(NotificationData.Entry entry,
+ StatusBarNotification rebuildNotificationWithRemoteInput(NotificationEntry entry,
CharSequence remoteInputText, boolean showSpinner) {
StatusBarNotification sbn = entry.notification;
@@ -530,7 +530,7 @@ public class NotificationRemoteInputManager implements Dumpable {
}
@VisibleForTesting
- public Set<NotificationData.Entry> getEntriesKeptForRemoteInputActive() {
+ public Set<NotificationEntry> getEntriesKeptForRemoteInputActive() {
return mEntriesKeptForRemoteInputActive;
}
@@ -553,12 +553,12 @@ public class NotificationRemoteInputManager implements Dumpable {
*/
protected class RemoteInputHistoryExtender extends RemoteInputExtender {
@Override
- public boolean shouldExtendLifetime(@NonNull NotificationData.Entry entry) {
+ public boolean shouldExtendLifetime(@NonNull NotificationEntry entry) {
return shouldKeepForRemoteInputHistory(entry);
}
@Override
- public void setShouldManageLifetime(NotificationData.Entry entry,
+ public void setShouldManageLifetime(NotificationEntry entry,
boolean shouldExtend) {
if (shouldExtend) {
CharSequence remoteInputText = entry.remoteInputText;
@@ -599,12 +599,12 @@ public class NotificationRemoteInputManager implements Dumpable {
*/
protected class SmartReplyHistoryExtender extends RemoteInputExtender {
@Override
- public boolean shouldExtendLifetime(@NonNull NotificationData.Entry entry) {
+ public boolean shouldExtendLifetime(@NonNull NotificationEntry entry) {
return shouldKeepForSmartReplyHistory(entry);
}
@Override
- public void setShouldManageLifetime(NotificationData.Entry entry,
+ public void setShouldManageLifetime(NotificationEntry entry,
boolean shouldExtend) {
if (shouldExtend) {
StatusBarNotification newSbn = rebuildNotificationForCanceledSmartReplies(entry);
@@ -637,7 +637,7 @@ public class NotificationRemoteInputManager implements Dumpable {
*/
protected class RemoteInputActiveExtender extends RemoteInputExtender {
@Override
- public boolean shouldExtendLifetime(@NonNull NotificationData.Entry entry) {
+ public boolean shouldExtendLifetime(@NonNull NotificationEntry entry) {
if (entry.isDismissed()) {
return false;
}
@@ -645,7 +645,7 @@ public class NotificationRemoteInputManager implements Dumpable {
}
@Override
- public void setShouldManageLifetime(NotificationData.Entry entry,
+ public void setShouldManageLifetime(NotificationEntry entry,
boolean shouldExtend) {
if (shouldExtend) {
if (Log.isLoggable(TAG, Log.DEBUG)) {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationUiAdjustment.java b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationUiAdjustment.java
index f23ae3f6bfb7..f0d804dbc7a3 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationUiAdjustment.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationUiAdjustment.java
@@ -24,7 +24,7 @@ import android.text.TextUtils;
import androidx.annotation.VisibleForTesting;
-import com.android.systemui.statusbar.notification.NotificationData;
+import com.android.systemui.statusbar.notification.collection.NotificationEntry;
import java.util.ArrayList;
import java.util.Arrays;
@@ -52,7 +52,7 @@ public class NotificationUiAdjustment {
}
public static NotificationUiAdjustment extractFromNotificationEntry(
- NotificationData.Entry entry) {
+ NotificationEntry entry) {
return new NotificationUiAdjustment(
entry.key, entry.systemGeneratedSmartActions, entry.smartReplies);
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationViewHierarchyManager.java b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationViewHierarchyManager.java
index 017a9c368fdf..bf6caa010e9b 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationViewHierarchyManager.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationViewHierarchyManager.java
@@ -27,9 +27,9 @@ import android.view.ViewGroup;
import com.android.systemui.R;
import com.android.systemui.bubbles.BubbleController;
-import com.android.systemui.statusbar.notification.NotificationData;
import com.android.systemui.statusbar.notification.NotificationEntryManager;
import com.android.systemui.statusbar.notification.VisualStabilityManager;
+import com.android.systemui.statusbar.notification.collection.NotificationEntry;
import com.android.systemui.statusbar.notification.row.ExpandableNotificationRow;
import com.android.systemui.statusbar.notification.stack.NotificationListContainer;
import com.android.systemui.statusbar.phone.NotificationGroupManager;
@@ -150,13 +150,13 @@ public class NotificationViewHierarchyManager {
*/
//TODO: Rewrite this to focus on Entries, or some other data object instead of views
public void updateNotificationViews() {
- ArrayList<NotificationData.Entry> activeNotifications = mEntryManager.getNotificationData()
+ ArrayList<NotificationEntry> activeNotifications = mEntryManager.getNotificationData()
.getActiveNotifications();
ArrayList<ExpandableNotificationRow> toShow = new ArrayList<>(activeNotifications.size());
- ArrayList<NotificationData.Entry> toBubble = new ArrayList<>();
+ ArrayList<NotificationEntry> toBubble = new ArrayList<>();
final int N = activeNotifications.size();
for (int i = 0; i < N; i++) {
- NotificationData.Entry ent = activeNotifications.get(i);
+ NotificationEntry ent = activeNotifications.get(i);
if (ent.isRowDismissed() || ent.isRowRemoved()) {
// we don't want to update removed notifications because they could
// temporarily become children if they were isolated before.
@@ -187,7 +187,7 @@ public class NotificationViewHierarchyManager {
ent.getRow().setSensitive(sensitive, deviceSensitive);
ent.getRow().setNeedsRedaction(needsRedaction);
if (mGroupManager.isChildInGroupWithSummary(ent.notification)) {
- NotificationData.Entry summary = mGroupManager.getGroupSummary(ent.notification);
+ NotificationEntry summary = mGroupManager.getGroupSummary(ent.notification);
List<ExpandableNotificationRow> orderedChildren =
mTmpChildOrderMap.get(summary.getRow());
if (orderedChildren == null) {
@@ -271,7 +271,7 @@ public class NotificationViewHierarchyManager {
for (int i = 0; i < toBubble.size(); i++) {
// TODO: might make sense to leave them in the shade and just reposition them
- NotificationData.Entry ent = toBubble.get(i);
+ NotificationEntry ent = toBubble.get(i);
mBubbleController.addBubble(ent);
}
@@ -385,7 +385,7 @@ public class NotificationViewHierarchyManager {
}
while(!stack.isEmpty()) {
ExpandableNotificationRow row = stack.pop();
- NotificationData.Entry entry = row.getEntry();
+ NotificationEntry entry = row.getEntry();
boolean isChildNotification =
mGroupManager.isChildInGroupWithSummary(entry.notification);
@@ -408,7 +408,7 @@ public class NotificationViewHierarchyManager {
if (!showOnKeyguard) {
// min priority notifications should show if their summary is showing
if (mGroupManager.isChildInGroupWithSummary(entry.notification)) {
- NotificationData.Entry summary = mGroupManager.getLogicalGroupSummary(
+ NotificationEntry summary = mGroupManager.getLogicalGroupSummary(
entry.notification);
if (summary != null && mLockscreenUserManager.shouldShowOnKeyguard(
summary.notification)) {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/RemoteInputController.java b/packages/SystemUI/src/com/android/systemui/statusbar/RemoteInputController.java
index e8abcc2bd80e..998cf523d3df 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/RemoteInputController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/RemoteInputController.java
@@ -24,7 +24,7 @@ import android.util.ArrayMap;
import android.util.Pair;
import com.android.internal.util.Preconditions;
-import com.android.systemui.statusbar.notification.NotificationData;
+import com.android.systemui.statusbar.notification.collection.NotificationEntry;
import com.android.systemui.statusbar.policy.RemoteInputView;
import java.lang.ref.WeakReference;
@@ -38,7 +38,7 @@ public class RemoteInputController {
private static final boolean ENABLE_REMOTE_INPUT =
SystemProperties.getBoolean("debug.enable_remote_input", true);
- private final ArrayList<Pair<WeakReference<NotificationData.Entry>, Object>> mOpen
+ private final ArrayList<Pair<WeakReference<NotificationEntry>, Object>> mOpen
= new ArrayList<>();
private final ArrayMap<String, Object> mSpinning = new ArrayMap<>();
private final ArrayList<Callback> mCallbacks = new ArrayList<>(3);
@@ -101,7 +101,7 @@ public class RemoteInputController {
* @param entry the entry for which a remote input is now active.
* @param token a token identifying the view that is managing the remote input
*/
- public void addRemoteInput(NotificationData.Entry entry, Object token) {
+ public void addRemoteInput(NotificationEntry entry, Object token) {
Preconditions.checkNotNull(entry);
Preconditions.checkNotNull(token);
@@ -122,7 +122,7 @@ public class RemoteInputController {
* the entry is only removed if the token matches the last added token for this
* entry. If null, the entry is removed regardless.
*/
- public void removeRemoteInput(NotificationData.Entry entry, Object token) {
+ public void removeRemoteInput(NotificationEntry entry, Object token) {
Preconditions.checkNotNull(entry);
pruneWeakThenRemoveAndContains(null /* contains */, entry /* remove */, token);
@@ -173,7 +173,7 @@ public class RemoteInputController {
return mSpinning.get(key) == token;
}
- private void apply(NotificationData.Entry entry) {
+ private void apply(NotificationEntry entry) {
mDelegate.setRemoteInputActive(entry, isRemoteInputActive(entry));
boolean remoteInputActive = isRemoteInputActive();
int N = mCallbacks.size();
@@ -185,7 +185,7 @@ public class RemoteInputController {
/**
* @return true if {@param entry} has an active RemoteInput
*/
- public boolean isRemoteInputActive(NotificationData.Entry entry) {
+ public boolean isRemoteInputActive(NotificationEntry entry) {
return pruneWeakThenRemoveAndContains(entry /* contains */, null /* remove */,
null /* removeToken */);
}
@@ -208,10 +208,10 @@ public class RemoteInputController {
* @return true if {@param contains} is in the set of active remote inputs
*/
private boolean pruneWeakThenRemoveAndContains(
- NotificationData.Entry contains, NotificationData.Entry remove, Object removeToken) {
+ NotificationEntry contains, NotificationEntry remove, Object removeToken) {
boolean found = false;
for (int i = mOpen.size() - 1; i >= 0; i--) {
- NotificationData.Entry item = mOpen.get(i).first.get();
+ NotificationEntry item = mOpen.get(i).first.get();
Object itemToken = mOpen.get(i).second;
boolean removeTokenMatches = (removeToken == null || itemToken == removeToken);
@@ -235,7 +235,7 @@ public class RemoteInputController {
mCallbacks.add(callback);
}
- public void remoteInputSent(NotificationData.Entry entry) {
+ public void remoteInputSent(NotificationEntry entry) {
int N = mCallbacks.size();
for (int i = 0; i < N; i++) {
mCallbacks.get(i).onRemoteInputSent(entry);
@@ -248,16 +248,16 @@ public class RemoteInputController {
}
// Make a copy because closing the remote inputs will modify mOpen.
- ArrayList<NotificationData.Entry> list = new ArrayList<>(mOpen.size());
+ ArrayList<NotificationEntry> list = new ArrayList<>(mOpen.size());
for (int i = mOpen.size() - 1; i >= 0; i--) {
- NotificationData.Entry entry = mOpen.get(i).first.get();
+ NotificationEntry entry = mOpen.get(i).first.get();
if (entry != null && entry.rowExists()) {
list.add(entry);
}
}
for (int i = list.size() - 1; i >= 0; i--) {
- NotificationData.Entry entry = list.get(i);
+ NotificationEntry entry = list.get(i);
if (entry.rowExists()) {
entry.closeRemoteInput();
}
@@ -268,31 +268,31 @@ public class RemoteInputController {
mDelegate.requestDisallowLongPressAndDismiss();
}
- public void lockScrollTo(NotificationData.Entry entry) {
+ public void lockScrollTo(NotificationEntry entry) {
mDelegate.lockScrollTo(entry);
}
public interface Callback {
default void onRemoteInputActive(boolean active) {}
- default void onRemoteInputSent(NotificationData.Entry entry) {}
+ default void onRemoteInputSent(NotificationEntry entry) {}
}
public interface Delegate {
/**
* Activate remote input if necessary.
*/
- void setRemoteInputActive(NotificationData.Entry entry, boolean remoteInputActive);
-
- /**
- * Request that the view does not dismiss nor perform long press for the current touch.
- */
- void requestDisallowLongPressAndDismiss();
-
- /**
- * Request that the view is made visible by scrolling to it, and keep the scroll locked until
- * the user scrolls, or {@param v} loses focus or is detached.
- */
- void lockScrollTo(NotificationData.Entry entry);
+ void setRemoteInputActive(NotificationEntry entry, boolean remoteInputActive);
+
+ /**
+ * Request that the view does not dismiss nor perform long press for the current touch.
+ */
+ void requestDisallowLongPressAndDismiss();
+
+ /**
+ * Request that the view is made visible by scrolling to it, and keep the scroll locked until
+ * the user scrolls, or {@param entry} loses focus or is detached.
+ */
+ void lockScrollTo(NotificationEntry entry);
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/SmartReplyController.java b/packages/SystemUI/src/com/android/systemui/statusbar/SmartReplyController.java
index 9e91133aff09..573c1f8ee509 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/SmartReplyController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/SmartReplyController.java
@@ -21,8 +21,8 @@ import android.util.ArraySet;
import com.android.internal.statusbar.IStatusBarService;
import com.android.internal.statusbar.NotificationVisibility;
-import com.android.systemui.statusbar.notification.NotificationData;
import com.android.systemui.statusbar.notification.NotificationEntryManager;
+import com.android.systemui.statusbar.notification.collection.NotificationEntry;
import java.util.Set;
@@ -54,7 +54,7 @@ public class SmartReplyController {
/**
* Notifies StatusBarService a smart reply is sent.
*/
- public void smartReplySent(NotificationData.Entry entry, int replyIndex, CharSequence reply,
+ public void smartReplySent(NotificationEntry entry, int replyIndex, CharSequence reply,
boolean generatedByAssistant) {
mCallback.onSmartReplySent(entry, reply);
mSendingKeys.add(entry.key);
@@ -70,7 +70,7 @@ public class SmartReplyController {
* Notifies StatusBarService a smart action is clicked.
*/
public void smartActionClicked(
- NotificationData.Entry entry, int actionIndex, Notification.Action action,
+ NotificationEntry entry, int actionIndex, Notification.Action action,
boolean generatedByAssistant) {
final int count = mEntryManager.getNotificationData().getActiveNotifications().size();
final int rank = mEntryManager.getNotificationData().getRank(entry.key);
@@ -95,7 +95,7 @@ public class SmartReplyController {
/**
* Smart Replies and Actions have been added to the UI.
*/
- public void smartSuggestionsAdded(final NotificationData.Entry entry, int replyCount,
+ public void smartSuggestionsAdded(final NotificationEntry entry, int replyCount,
int actionCount, boolean generatedByAssistant) {
try {
mBarService.onNotificationSmartSuggestionsAdded(
@@ -105,7 +105,7 @@ public class SmartReplyController {
}
}
- public void stopSending(final NotificationData.Entry entry) {
+ public void stopSending(final NotificationEntry entry) {
if (entry != null) {
mSendingKeys.remove(entry.notification.getKey());
}
@@ -121,6 +121,6 @@ public class SmartReplyController {
* @param entry the entry for the notification
* @param reply the reply that was sent
*/
- void onSmartReplySent(NotificationData.Entry entry, CharSequence reply);
+ void onSmartReplySent(NotificationEntry entry, CharSequence reply);
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationAlertingManager.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationAlertingManager.java
index 2bb0d5ce9161..c24698deabde 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationAlertingManager.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationAlertingManager.java
@@ -29,6 +29,7 @@ import com.android.systemui.statusbar.AlertingNotificationManager;
import com.android.systemui.statusbar.AmbientPulseManager;
import com.android.systemui.statusbar.NotificationListener;
import com.android.systemui.statusbar.NotificationRemoteInputManager;
+import com.android.systemui.statusbar.notification.collection.NotificationEntry;
import com.android.systemui.statusbar.notification.row.NotificationInflater;
import com.android.systemui.statusbar.phone.ShadeController;
import com.android.systemui.statusbar.policy.HeadsUpManager;
@@ -71,18 +72,18 @@ public class NotificationAlertingManager {
notificationEntryManager.addNotificationEntryListener(new NotificationEntryListener() {
@Override
- public void onEntryInflated(NotificationData.Entry entry, int inflatedFlags) {
+ public void onEntryInflated(NotificationEntry entry, int inflatedFlags) {
showAlertingView(entry, inflatedFlags);
}
@Override
- public void onEntryUpdated(NotificationData.Entry entry) {
+ public void onEntryUpdated(NotificationEntry entry) {
updateAlertState(entry);
}
@Override
public void onEntryRemoved(
- NotificationData.Entry entry,
+ NotificationEntry entry,
NotificationVisibility visibility,
boolean removedByUser) {
stopAlerting(entry.key);
@@ -101,7 +102,7 @@ public class NotificationAlertingManager {
* @param entry entry to add
* @param inflatedFlags flags representing content views that were inflated
*/
- private void showAlertingView(NotificationData.Entry entry,
+ private void showAlertingView(NotificationEntry entry,
@NotificationInflater.InflationFlag int inflatedFlags) {
if ((inflatedFlags & FLAG_CONTENT_VIEW_HEADS_UP) != 0) {
// Possible for shouldHeadsUp to change between the inflation starting and ending.
@@ -123,7 +124,7 @@ public class NotificationAlertingManager {
}
}
- private void updateAlertState(NotificationData.Entry entry) {
+ private void updateAlertState(NotificationEntry entry) {
boolean alertAgain = alertAgain(entry, entry.notification.getNotification());
AlertingNotificationManager alertManager;
boolean shouldAlert;
@@ -150,7 +151,7 @@ public class NotificationAlertingManager {
}
private static boolean alertAgain(
- NotificationData.Entry oldEntry, Notification newNotification) {
+ NotificationEntry oldEntry, Notification newNotification) {
return oldEntry == null || !oldEntry.hasInterrupted()
|| (newNotification.flags & Notification.FLAG_ONLY_ALERT_ONCE) == 0;
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationData.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationData.java
deleted file mode 100644
index a51896ee69fc..000000000000
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationData.java
+++ /dev/null
@@ -1,1072 +0,0 @@
-/*
- * Copyright (C) 2008 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License
- */
-
-package com.android.systemui.statusbar.notification;
-
-import static android.app.Notification.CATEGORY_ALARM;
-import static android.app.Notification.CATEGORY_CALL;
-import static android.app.Notification.CATEGORY_EVENT;
-import static android.app.Notification.CATEGORY_MESSAGE;
-import static android.app.Notification.CATEGORY_REMINDER;
-import static android.app.NotificationManager.Policy.SUPPRESSED_EFFECT_AMBIENT;
-import static android.app.NotificationManager.Policy.SUPPRESSED_EFFECT_FULL_SCREEN_INTENT;
-import static android.app.NotificationManager.Policy.SUPPRESSED_EFFECT_NOTIFICATION_LIST;
-import static android.app.NotificationManager.Policy.SUPPRESSED_EFFECT_PEEK;
-import static android.app.NotificationManager.Policy.SUPPRESSED_EFFECT_STATUS_BAR;
-
-import android.annotation.NonNull;
-import android.app.Notification;
-import android.app.NotificationChannel;
-import android.app.NotificationManager;
-import android.app.Person;
-import android.content.Context;
-import android.graphics.drawable.Icon;
-import android.os.Bundle;
-import android.os.Parcelable;
-import android.os.SystemClock;
-import android.service.notification.NotificationListenerService.Ranking;
-import android.service.notification.NotificationListenerService.RankingMap;
-import android.service.notification.SnoozeCriterion;
-import android.service.notification.StatusBarNotification;
-import android.util.ArrayMap;
-import android.util.ArraySet;
-import android.view.View;
-import android.widget.ImageView;
-
-import androidx.annotation.Nullable;
-
-import com.android.internal.annotations.VisibleForTesting;
-import com.android.internal.statusbar.StatusBarIcon;
-import com.android.internal.util.ArrayUtils;
-import com.android.internal.util.ContrastColorUtil;
-import com.android.systemui.Dependency;
-import com.android.systemui.statusbar.InflationTask;
-import com.android.systemui.statusbar.NotificationMediaManager;
-import com.android.systemui.statusbar.StatusBarIconView;
-import com.android.systemui.statusbar.notification.row.ExpandableNotificationRow;
-import com.android.systemui.statusbar.notification.row.NotificationGuts;
-import com.android.systemui.statusbar.notification.row.NotificationInflater.InflationFlag;
-import com.android.systemui.statusbar.phone.NotificationGroupManager;
-import com.android.systemui.statusbar.policy.HeadsUpManager;
-
-import java.io.PrintWriter;
-import java.util.ArrayList;
-import java.util.Collections;
-import java.util.Comparator;
-import java.util.List;
-import java.util.Objects;
-
-/**
- * The list of currently displaying notifications.
- */
-public class NotificationData {
-
- private final NotificationFilter mNotificationFilter = Dependency.get(NotificationFilter.class);
-
- /**
- * These dependencies are late init-ed
- */
- private KeyguardEnvironment mEnvironment;
- private NotificationMediaManager mMediaManager;
-
- private HeadsUpManager mHeadsUpManager;
-
- public static final class Entry {
- private static final long LAUNCH_COOLDOWN = 2000;
- private static final long REMOTE_INPUT_COOLDOWN = 500;
- private static final long INITIALIZATION_DELAY = 400;
- private static final long NOT_LAUNCHED_YET = -LAUNCH_COOLDOWN;
- private static final int COLOR_INVALID = 1;
- public final String key;
- public StatusBarNotification notification;
- public NotificationChannel channel;
- public long lastAudiblyAlertedMs;
- public boolean noisy;
- public boolean ambient;
- public int importance;
- public StatusBarIconView icon;
- public StatusBarIconView expandedIcon;
- private boolean interruption;
- public boolean autoRedacted; // whether the redacted notification was generated by us
- public int targetSdk;
- private long lastFullScreenIntentLaunchTime = NOT_LAUNCHED_YET;
- public CharSequence remoteInputText;
- public List<SnoozeCriterion> snoozeCriteria;
- public int userSentiment = Ranking.USER_SENTIMENT_NEUTRAL;
- /** Smart Actions provided by the NotificationAssistantService. */
- @NonNull
- public List<Notification.Action> systemGeneratedSmartActions = Collections.emptyList();
- public CharSequence[] smartReplies = new CharSequence[0];
- @VisibleForTesting
- public int suppressedVisualEffects;
- public boolean suspended;
-
- private Entry parent; // our parent (if we're in a group)
- private ArrayList<Entry> children = new ArrayList<Entry>();
- private ExpandableNotificationRow row; // the outer expanded view
-
- private int mCachedContrastColor = COLOR_INVALID;
- private int mCachedContrastColorIsFor = COLOR_INVALID;
- private InflationTask mRunningTask = null;
- private Throwable mDebugThrowable;
- public CharSequence remoteInputTextWhenReset;
- public long lastRemoteInputSent = NOT_LAUNCHED_YET;
- public ArraySet<Integer> mActiveAppOps = new ArraySet<>(3);
- public CharSequence headsUpStatusBarText;
- public CharSequence headsUpStatusBarTextPublic;
-
- private long initializationTime = -1;
-
- /**
- * Whether or not this row represents a system notification. Note that if this is
- * {@code null}, that means we were either unable to retrieve the info or have yet to
- * retrieve the info.
- */
- public Boolean mIsSystemNotification;
-
- /**
- * Has the user sent a reply through this Notification.
- */
- private boolean hasSentReply;
-
- /**
- * Whether this notification should be displayed as a bubble.
- */
- private boolean mIsBubble;
-
- /**
- * Whether the user has dismissed this notification when it was in bubble form.
- */
- private boolean mUserDismissedBubble;
-
- public Entry(StatusBarNotification n) {
- this(n, null);
- }
-
- public Entry(StatusBarNotification n, @Nullable Ranking ranking) {
- this.key = n.getKey();
- this.notification = n;
- if (ranking != null) {
- populateFromRanking(ranking);
- }
- }
-
- public void populateFromRanking(@NonNull Ranking ranking) {
- channel = ranking.getChannel();
- lastAudiblyAlertedMs = ranking.getLastAudiblyAlertedMillis();
- importance = ranking.getImportance();
- ambient = ranking.isAmbient();
- snoozeCriteria = ranking.getSnoozeCriteria();
- userSentiment = ranking.getUserSentiment();
- systemGeneratedSmartActions = ranking.getSmartActions() == null
- ? Collections.emptyList() : ranking.getSmartActions();
- smartReplies = ranking.getSmartReplies() == null
- ? new CharSequence[0]
- : ranking.getSmartReplies().toArray(new CharSequence[0]);
- suppressedVisualEffects = ranking.getSuppressedVisualEffects();
- suspended = ranking.isSuspended();
- }
-
- public void setInterruption() {
- interruption = true;
- }
-
- public boolean hasInterrupted() {
- return interruption;
- }
-
- public void setIsBubble(boolean bubbleable) {
- mIsBubble = bubbleable;
- }
-
- public boolean isBubble() {
- return mIsBubble;
- }
-
- public void setBubbleDismissed(boolean userDismissed) {
- mUserDismissedBubble = userDismissed;
- }
-
- public boolean isBubbleDismissed() {
- return mUserDismissedBubble;
- }
-
- /**
- * Resets the notification entry to be re-used.
- */
- public void reset() {
- if (row != null) {
- row.reset();
- }
- }
-
- public ExpandableNotificationRow getRow() {
- return row;
- }
-
- //TODO: This will go away when we have a way to bind an entry to a row
- public void setRow(ExpandableNotificationRow row) {
- this.row = row;
- }
-
- @Nullable
- public List<Entry> getChildren() {
- if (children.size() <= 0) {
- return null;
- }
-
- return children;
- }
-
- public void notifyFullScreenIntentLaunched() {
- setInterruption();
- lastFullScreenIntentLaunchTime = SystemClock.elapsedRealtime();
- }
-
- public boolean hasJustLaunchedFullScreenIntent() {
- return SystemClock.elapsedRealtime() < lastFullScreenIntentLaunchTime + LAUNCH_COOLDOWN;
- }
-
- public boolean hasJustSentRemoteInput() {
- return SystemClock.elapsedRealtime() < lastRemoteInputSent + REMOTE_INPUT_COOLDOWN;
- }
-
- public boolean hasFinishedInitialization() {
- return initializationTime == -1 ||
- SystemClock.elapsedRealtime() > initializationTime + INITIALIZATION_DELAY;
- }
-
- /**
- * Create the icons for a notification
- * @param context the context to create the icons with
- * @param sbn the notification
- * @throws InflationException
- */
- public void createIcons(Context context, StatusBarNotification sbn)
- throws InflationException {
- Notification n = sbn.getNotification();
- final Icon smallIcon = n.getSmallIcon();
- if (smallIcon == null) {
- throw new InflationException("No small icon in notification from "
- + sbn.getPackageName());
- }
-
- // Construct the icon.
- icon = new StatusBarIconView(context,
- sbn.getPackageName() + "/0x" + Integer.toHexString(sbn.getId()), sbn);
- icon.setScaleType(ImageView.ScaleType.CENTER_INSIDE);
-
- // Construct the expanded icon.
- expandedIcon = new StatusBarIconView(context,
- sbn.getPackageName() + "/0x" + Integer.toHexString(sbn.getId()), sbn);
- expandedIcon.setScaleType(ImageView.ScaleType.CENTER_INSIDE);
- final StatusBarIcon ic = new StatusBarIcon(
- sbn.getUser(),
- sbn.getPackageName(),
- smallIcon,
- n.iconLevel,
- n.number,
- StatusBarIconView.contentDescForNotification(context, n));
- if (!icon.set(ic) || !expandedIcon.set(ic)) {
- icon = null;
- expandedIcon = null;
- throw new InflationException("Couldn't create icon: " + ic);
- }
- expandedIcon.setVisibility(View.INVISIBLE);
- expandedIcon.setOnVisibilityChangedListener(
- newVisibility -> {
- if (row != null) {
- row.setIconsVisible(newVisibility != View.VISIBLE);
- }
- });
- }
-
- public void setIconTag(int key, Object tag) {
- if (icon != null) {
- icon.setTag(key, tag);
- expandedIcon.setTag(key, tag);
- }
- }
-
- /**
- * Update the notification icons.
- *
- * @param context the context to create the icons with.
- * @param sbn the notification to read the icon from.
- * @throws InflationException
- */
- public void updateIcons(Context context, StatusBarNotification sbn)
- throws InflationException {
- if (icon != null) {
- // Update the icon
- Notification n = sbn.getNotification();
- final StatusBarIcon ic = new StatusBarIcon(
- notification.getUser(),
- notification.getPackageName(),
- n.getSmallIcon(),
- n.iconLevel,
- n.number,
- StatusBarIconView.contentDescForNotification(context, n));
- icon.setNotification(sbn);
- expandedIcon.setNotification(sbn);
- if (!icon.set(ic) || !expandedIcon.set(ic)) {
- throw new InflationException("Couldn't update icon: " + ic);
- }
- }
- }
-
- public int getContrastedColor(Context context, boolean isLowPriority,
- int backgroundColor) {
- int rawColor = isLowPriority ? Notification.COLOR_DEFAULT :
- notification.getNotification().color;
- if (mCachedContrastColorIsFor == rawColor && mCachedContrastColor != COLOR_INVALID) {
- return mCachedContrastColor;
- }
- final int contrasted = ContrastColorUtil.resolveContrastColor(context, rawColor,
- backgroundColor);
- mCachedContrastColorIsFor = rawColor;
- mCachedContrastColor = contrasted;
- return mCachedContrastColor;
- }
-
- /**
- * Abort all existing inflation tasks
- */
- public void abortTask() {
- if (mRunningTask != null) {
- mRunningTask.abort();
- mRunningTask = null;
- }
- }
-
- public void setInflationTask(InflationTask abortableTask) {
- // abort any existing inflation
- InflationTask existing = mRunningTask;
- abortTask();
- mRunningTask = abortableTask;
- if (existing != null && mRunningTask != null) {
- mRunningTask.supersedeTask(existing);
- }
- }
-
- public void onInflationTaskFinished() {
- mRunningTask = null;
- }
-
- @VisibleForTesting
- public InflationTask getRunningTask() {
- return mRunningTask;
- }
-
- /**
- * Set a throwable that is used for debugging
- *
- * @param debugThrowable the throwable to save
- */
- public void setDebugThrowable(Throwable debugThrowable) {
- mDebugThrowable = debugThrowable;
- }
-
- public Throwable getDebugThrowable() {
- return mDebugThrowable;
- }
-
- public void onRemoteInputInserted() {
- lastRemoteInputSent = NOT_LAUNCHED_YET;
- remoteInputTextWhenReset = null;
- }
-
- public void setHasSentReply() {
- hasSentReply = true;
- }
-
- public boolean isLastMessageFromReply() {
- if (!hasSentReply) {
- return false;
- }
- Bundle extras = notification.getNotification().extras;
- CharSequence[] replyTexts = extras.getCharSequenceArray(
- Notification.EXTRA_REMOTE_INPUT_HISTORY);
- if (!ArrayUtils.isEmpty(replyTexts)) {
- return true;
- }
- Parcelable[] messages = extras.getParcelableArray(Notification.EXTRA_MESSAGES);
- if (messages != null && messages.length > 0) {
- Parcelable message = messages[messages.length - 1];
- if (message instanceof Bundle) {
- Notification.MessagingStyle.Message lastMessage =
- Notification.MessagingStyle.Message.getMessageFromBundle(
- (Bundle) message);
- if (lastMessage != null) {
- Person senderPerson = lastMessage.getSenderPerson();
- if (senderPerson == null) {
- return true;
- }
- Person user = extras.getParcelable(Notification.EXTRA_MESSAGING_PERSON);
- return Objects.equals(user, senderPerson);
- }
- }
- }
- return false;
- }
-
- public void setInitializationTime(long time) {
- if (initializationTime == -1) {
- initializationTime = time;
- }
- }
-
- public void sendAccessibilityEvent(int eventType) {
- if (row != null) {
- row.sendAccessibilityEvent(eventType);
- }
- }
-
- /**
- * Used by NotificationMediaManager to determine... things
- * @return {@code true} if we are a media notification
- */
- public boolean isMediaNotification() {
- if (row == null) return false;
-
- return row.isMediaRow();
- }
-
- /**
- * We are a top level child if our parent is the list of notifications duh
- * @return {@code true} if we're a top level notification
- */
- public boolean isTopLevelChild() {
- return row != null && row.isTopLevelChild();
- }
-
- public void resetUserExpansion() {
- if (row != null) row.resetUserExpansion();
- }
-
- public void freeContentViewWhenSafe(@InflationFlag int inflationFlag) {
- if (row != null) row.freeContentViewWhenSafe(inflationFlag);
- }
-
- public void setAmbientPulsing(boolean pulsing) {
- if (row != null) row.setAmbientPulsing(pulsing);
- }
-
- public boolean rowExists() {
- return row != null;
- }
-
- public boolean isRowDismissed() {
- return row != null && row.isDismissed();
- }
-
- public boolean isRowRemoved() {
- return row != null && row.isRemoved();
- }
-
- /**
- * @return {@code true} if the row is null or removed
- */
- public boolean isRemoved() {
- //TODO: recycling invalidates this
- return row == null || row.isRemoved();
- }
-
- /**
- * @return {@code true} if the row is null or dismissed
- */
- public boolean isDismissed() {
- //TODO: recycling
- return row == null || row.isDismissed();
- }
-
- public boolean isRowPinned() {
- return row != null && row.isPinned();
- }
-
- public void setRowPinned(boolean pinned) {
- if (row != null) row.setPinned(pinned);
- }
-
- public boolean isRowAnimatingAway() {
- return row != null && row.isHeadsUpAnimatingAway();
- }
-
- public boolean isRowHeadsUp() {
- return row != null && row.isHeadsUp();
- }
-
- public void setHeadsUp(boolean shouldHeadsUp) {
- if (row != null) row.setHeadsUp(shouldHeadsUp);
- }
-
- public boolean mustStayOnScreen() {
- return row != null && row.mustStayOnScreen();
- }
-
- public void setHeadsUpIsVisible() {
- if (row != null) row.setHeadsUpIsVisible();
- }
-
- //TODO: i'm imagining a world where this isn't just the row, but I could be rwong
- public ExpandableNotificationRow getHeadsUpAnimationView() {
- return row;
- }
-
- public void setUserLocked(boolean userLocked) {
- if (row != null) row.setUserLocked(userLocked);
- }
-
- public void setUserExpanded(boolean userExpanded, boolean allowChildExpansion) {
- if (row != null) row.setUserExpanded(userExpanded, allowChildExpansion);
- }
-
- public void setGroupExpansionChanging(boolean changing) {
- if (row != null) row.setGroupExpansionChanging(changing);
- }
-
- public void notifyHeightChanged(boolean needsAnimation) {
- if (row != null) row.notifyHeightChanged(needsAnimation);
- }
-
- public void closeRemoteInput() {
- if (row != null) row.closeRemoteInput();
- }
-
- public boolean areChildrenExpanded() {
- return row != null && row.areChildrenExpanded();
- }
-
- public boolean keepInParent() {
- return row != null && row.keepInParent();
- }
-
- //TODO: probably less confusing to say "is group fully visible"
- public boolean isGroupNotFullyVisible() {
- return row == null || row.isGroupNotFullyVisible();
- }
-
- public NotificationGuts getGuts() {
- if (row != null) return row.getGuts();
- return null;
- }
-
- public boolean hasLowPriorityStateUpdated() {
- return row != null && row.hasLowPriorityStateUpdated();
- }
-
- public void removeRow() {
- if (row != null) row.setRemoved();
- }
-
- public boolean isSummaryWithChildren() {
- return row != null && row.isSummaryWithChildren();
- }
-
- public void setKeepInParent(boolean keep) {
- if (row != null) row.setKeepInParent(keep);
- }
-
- public void onDensityOrFontScaleChanged() {
- if (row != null) row.onDensityOrFontScaleChanged();
- }
-
- public boolean areGutsExposed() {
- return row != null && row.getGuts() != null && row.getGuts().isExposed();
- }
-
- public boolean isChildInGroup() {
- return parent == null;
- }
-
- public void setLowPriorityStateUpdated(boolean updated) {
- if (row != null) row.setLowPriorityStateUpdated(updated);
- }
-
- /**
- * @return Can the underlying notification be cleared? This can be different from whether the
- * notification can be dismissed in case notifications are sensitive on the lockscreen.
- * @see #canViewBeDismissed()
- */
- public boolean isClearable() {
- if (notification == null || !notification.isClearable()) {
- return false;
- }
- if (children.size() > 0) {
- for (int i = 0; i < children.size(); i++) {
- Entry child = children.get(i);
- if (!child.isClearable()) {
- return false;
- }
- }
- }
- return true;
- }
-
- public boolean canViewBeDismissed() {
- if (row == null) return true;
- return row.canViewBeDismissed();
- }
-
- boolean isExemptFromDndVisualSuppression() {
- if (isNotificationBlockedByPolicy(notification.getNotification())) {
- return false;
- }
-
- if ((notification.getNotification().flags
- & Notification.FLAG_FOREGROUND_SERVICE) != 0) {
- return true;
- }
- if (notification.getNotification().isMediaNotification()) {
- return true;
- }
- if (mIsSystemNotification != null && mIsSystemNotification) {
- return true;
- }
- return false;
- }
-
- private boolean shouldSuppressVisualEffect(int effect) {
- if (isExemptFromDndVisualSuppression()) {
- return false;
- }
- return (suppressedVisualEffects & effect) != 0;
- }
-
- /**
- * Returns whether {@link NotificationManager.Policy#SUPPRESSED_EFFECT_FULL_SCREEN_INTENT}
- * is set for this entry.
- */
- public boolean shouldSuppressFullScreenIntent() {
- return shouldSuppressVisualEffect(SUPPRESSED_EFFECT_FULL_SCREEN_INTENT);
- }
-
- /**
- * Returns whether {@link NotificationManager.Policy#SUPPRESSED_EFFECT_PEEK}
- * is set for this entry.
- */
- public boolean shouldSuppressPeek() {
- return shouldSuppressVisualEffect(SUPPRESSED_EFFECT_PEEK);
- }
-
- /**
- * Returns whether {@link NotificationManager.Policy#SUPPRESSED_EFFECT_STATUS_BAR}
- * is set for this entry.
- */
- public boolean shouldSuppressStatusBar() {
- return shouldSuppressVisualEffect(SUPPRESSED_EFFECT_STATUS_BAR);
- }
-
- /**
- * Returns whether {@link NotificationManager.Policy#SUPPRESSED_EFFECT_AMBIENT}
- * is set for this entry.
- */
- public boolean shouldSuppressAmbient() {
- return shouldSuppressVisualEffect(SUPPRESSED_EFFECT_AMBIENT);
- }
-
- /**
- * Returns whether {@link NotificationManager.Policy#SUPPRESSED_EFFECT_NOTIFICATION_LIST}
- * is set for this entry.
- */
- public boolean shouldSuppressNotificationList() {
- return shouldSuppressVisualEffect(SUPPRESSED_EFFECT_NOTIFICATION_LIST);
- }
- }
-
- private final ArrayMap<String, Entry> mEntries = new ArrayMap<>();
- private final ArrayList<Entry> mSortedAndFiltered = new ArrayList<>();
- private final ArrayList<Entry> mFilteredForUser = new ArrayList<>();
-
- private final NotificationGroupManager mGroupManager
- = Dependency.get(NotificationGroupManager.class);
-
- private RankingMap mRankingMap;
- private final Ranking mTmpRanking = new Ranking();
-
- public void setHeadsUpManager(HeadsUpManager headsUpManager) {
- mHeadsUpManager = headsUpManager;
- }
-
- private final Comparator<Entry> mRankingComparator = new Comparator<Entry>() {
- private final Ranking mRankingA = new Ranking();
- private final Ranking mRankingB = new Ranking();
-
- @Override
- public int compare(Entry a, Entry b) {
- final StatusBarNotification na = a.notification;
- final StatusBarNotification nb = b.notification;
- int aImportance = NotificationManager.IMPORTANCE_DEFAULT;
- int bImportance = NotificationManager.IMPORTANCE_DEFAULT;
- int aRank = 0;
- int bRank = 0;
-
- if (mRankingMap != null) {
- // RankingMap as received from NoMan
- getRanking(a.key, mRankingA);
- getRanking(b.key, mRankingB);
- aImportance = mRankingA.getImportance();
- bImportance = mRankingB.getImportance();
- aRank = mRankingA.getRank();
- bRank = mRankingB.getRank();
- }
-
- String mediaNotification = getMediaManager().getMediaNotificationKey();
-
- // IMPORTANCE_MIN media streams are allowed to drift to the bottom
- final boolean aMedia = a.key.equals(mediaNotification)
- && aImportance > NotificationManager.IMPORTANCE_MIN;
- final boolean bMedia = b.key.equals(mediaNotification)
- && bImportance > NotificationManager.IMPORTANCE_MIN;
-
- boolean aSystemMax = aImportance >= NotificationManager.IMPORTANCE_HIGH &&
- isSystemNotification(na);
- boolean bSystemMax = bImportance >= NotificationManager.IMPORTANCE_HIGH &&
- isSystemNotification(nb);
-
- boolean isHeadsUp = a.row.isHeadsUp();
- if (isHeadsUp != b.row.isHeadsUp()) {
- return isHeadsUp ? -1 : 1;
- } else if (isHeadsUp) {
- // Provide consistent ranking with headsUpManager
- return mHeadsUpManager.compare(a, b);
- } else if (a.row.isAmbientPulsing() != b.row.isAmbientPulsing()) {
- return a.row.isAmbientPulsing() ? -1 : 1;
- } else if (aMedia != bMedia) {
- // Upsort current media notification.
- return aMedia ? -1 : 1;
- } else if (aSystemMax != bSystemMax) {
- // Upsort PRIORITY_MAX system notifications
- return aSystemMax ? -1 : 1;
- } else if (aRank != bRank) {
- return aRank - bRank;
- } else {
- return Long.compare(nb.getNotification().when, na.getNotification().when);
- }
- }
- };
-
- private KeyguardEnvironment getEnvironment() {
- if (mEnvironment == null) {
- mEnvironment = Dependency.get(KeyguardEnvironment.class);
- }
- return mEnvironment;
- }
-
- private NotificationMediaManager getMediaManager() {
- if (mMediaManager == null) {
- mMediaManager = Dependency.get(NotificationMediaManager.class);
- }
- return mMediaManager;
- }
-
- /**
- * Returns the sorted list of active notifications (depending on {@link KeyguardEnvironment}
- *
- * <p>
- * This call doesn't update the list of active notifications. Call {@link #filterAndSort()}
- * when the environment changes.
- * <p>
- * Don't hold on to or modify the returned list.
- */
- public ArrayList<Entry> getActiveNotifications() {
- return mSortedAndFiltered;
- }
-
- public ArrayList<Entry> getNotificationsForCurrentUser() {
- mFilteredForUser.clear();
-
- synchronized (mEntries) {
- final int N = mEntries.size();
- for (int i = 0; i < N; i++) {
- Entry entry = mEntries.valueAt(i);
- final StatusBarNotification sbn = entry.notification;
- if (!getEnvironment().isNotificationForCurrentProfiles(sbn)) {
- continue;
- }
- mFilteredForUser.add(entry);
- }
- }
- return mFilteredForUser;
- }
-
- public Entry get(String key) {
- return mEntries.get(key);
- }
-
- public void add(Entry entry) {
- synchronized (mEntries) {
- mEntries.put(entry.notification.getKey(), entry);
- }
- mGroupManager.onEntryAdded(entry);
-
- updateRankingAndSort(mRankingMap);
- }
-
- public Entry remove(String key, RankingMap ranking) {
- Entry removed;
- synchronized (mEntries) {
- removed = mEntries.remove(key);
- }
- if (removed == null) return null;
- mGroupManager.onEntryRemoved(removed);
- updateRankingAndSort(ranking);
- return removed;
- }
-
- /** Updates the given notification entry with the provided ranking. */
- public void update(Entry entry, RankingMap ranking, StatusBarNotification notification) {
- updateRanking(ranking);
- final StatusBarNotification oldNotification = entry.notification;
- entry.notification = notification;
- mGroupManager.onEntryUpdated(entry, oldNotification);
- }
-
- public void updateRanking(RankingMap ranking) {
- updateRankingAndSort(ranking);
- }
-
- public void updateAppOp(int appOp, int uid, String pkg, String key, boolean showIcon) {
- synchronized (mEntries) {
- final int N = mEntries.size();
- for (int i = 0; i < N; i++) {
- Entry entry = mEntries.valueAt(i);
- if (uid == entry.notification.getUid()
- && pkg.equals(entry.notification.getPackageName())
- && key.equals(entry.key)) {
- if (showIcon) {
- entry.mActiveAppOps.add(appOp);
- } else {
- entry.mActiveAppOps.remove(appOp);
- }
- }
- }
- }
- }
-
- /**
- * Returns true if this notification should be displayed in the high-priority notifications
- * section (and on the lockscreen and status bar).
- */
- public boolean isHighPriority(StatusBarNotification statusBarNotification) {
- if (mRankingMap != null) {
- getRanking(statusBarNotification.getKey(), mTmpRanking);
- if (mTmpRanking.getImportance() >= NotificationManager.IMPORTANCE_DEFAULT
- || statusBarNotification.getNotification().isForegroundService()
- || statusBarNotification.getNotification().hasMediaSession()) {
- return true;
- }
- if (mGroupManager.isSummaryOfGroup(statusBarNotification)) {
- for (Entry child : mGroupManager.getLogicalChildren(statusBarNotification)) {
- if (isHighPriority(child.notification)) {
- return true;
- }
- }
- }
- }
- return false;
- }
-
- public boolean isAmbient(String key) {
- if (mRankingMap != null) {
- getRanking(key, mTmpRanking);
- return mTmpRanking.isAmbient();
- }
- return false;
- }
-
- public int getVisibilityOverride(String key) {
- if (mRankingMap != null) {
- getRanking(key, mTmpRanking);
- return mTmpRanking.getVisibilityOverride();
- }
- return Ranking.VISIBILITY_NO_OVERRIDE;
- }
-
- /**
- * Categories that are explicitly called out on DND settings screens are always blocked, if
- * DND has flagged them, even if they are foreground or system notifications that might
- * otherwise visually bypass DND.
- */
- private static boolean isNotificationBlockedByPolicy(Notification n) {
- if (isCategory(CATEGORY_CALL, n)
- || isCategory(CATEGORY_MESSAGE, n)
- || isCategory(CATEGORY_ALARM, n)
- || isCategory(CATEGORY_EVENT, n)
- || isCategory(CATEGORY_REMINDER, n)) {
- return true;
- }
- return false;
- }
-
- private static boolean isCategory(String category, Notification n) {
- return Objects.equals(n.category, category);
- }
-
- public int getImportance(String key) {
- if (mRankingMap != null) {
- getRanking(key, mTmpRanking);
- return mTmpRanking.getImportance();
- }
- return NotificationManager.IMPORTANCE_UNSPECIFIED;
- }
-
- public String getOverrideGroupKey(String key) {
- if (mRankingMap != null) {
- getRanking(key, mTmpRanking);
- return mTmpRanking.getOverrideGroupKey();
- }
- return null;
- }
-
- public List<SnoozeCriterion> getSnoozeCriteria(String key) {
- if (mRankingMap != null) {
- getRanking(key, mTmpRanking);
- return mTmpRanking.getSnoozeCriteria();
- }
- return null;
- }
-
- public NotificationChannel getChannel(String key) {
- if (mRankingMap != null) {
- getRanking(key, mTmpRanking);
- return mTmpRanking.getChannel();
- }
- return null;
- }
-
- public int getRank(String key) {
- if (mRankingMap != null) {
- getRanking(key, mTmpRanking);
- return mTmpRanking.getRank();
- }
- return 0;
- }
-
- public boolean shouldHide(String key) {
- if (mRankingMap != null) {
- getRanking(key, mTmpRanking);
- return mTmpRanking.isSuspended();
- }
- return false;
- }
-
- private void updateRankingAndSort(RankingMap ranking) {
- if (ranking != null) {
- mRankingMap = ranking;
- synchronized (mEntries) {
- final int N = mEntries.size();
- for (int i = 0; i < N; i++) {
- Entry entry = mEntries.valueAt(i);
- if (!getRanking(entry.key, mTmpRanking)) {
- continue;
- }
- final StatusBarNotification oldSbn = entry.notification.cloneLight();
- final String overrideGroupKey = getOverrideGroupKey(entry.key);
- if (!Objects.equals(oldSbn.getOverrideGroupKey(), overrideGroupKey)) {
- entry.notification.setOverrideGroupKey(overrideGroupKey);
- mGroupManager.onEntryUpdated(entry, oldSbn);
- }
- entry.populateFromRanking(mTmpRanking);
- }
- }
- }
- filterAndSort();
- }
-
- /**
- * Get the ranking from the current ranking map.
- *
- * @param key the key to look up
- * @param outRanking the ranking to populate
- *
- * @return {@code true} if the ranking was properly obtained.
- */
- @VisibleForTesting
- protected boolean getRanking(String key, Ranking outRanking) {
- return mRankingMap.getRanking(key, outRanking);
- }
-
- // TODO: This should not be public. Instead the Environment should notify this class when
- // anything changed, and this class should call back the UI so it updates itself.
- public void filterAndSort() {
- mSortedAndFiltered.clear();
-
- synchronized (mEntries) {
- final int N = mEntries.size();
- for (int i = 0; i < N; i++) {
- Entry entry = mEntries.valueAt(i);
-
- if (mNotificationFilter.shouldFilterOut(entry)) {
- continue;
- }
-
- mSortedAndFiltered.add(entry);
- }
- }
-
- Collections.sort(mSortedAndFiltered, mRankingComparator);
- }
-
- public void dump(PrintWriter pw, String indent) {
- int N = mSortedAndFiltered.size();
- pw.print(indent);
- pw.println("active notifications: " + N);
- int active;
- for (active = 0; active < N; active++) {
- NotificationData.Entry e = mSortedAndFiltered.get(active);
- dumpEntry(pw, indent, active, e);
- }
- synchronized (mEntries) {
- int M = mEntries.size();
- pw.print(indent);
- pw.println("inactive notifications: " + (M - active));
- int inactiveCount = 0;
- for (int i = 0; i < M; i++) {
- Entry entry = mEntries.valueAt(i);
- if (!mSortedAndFiltered.contains(entry)) {
- dumpEntry(pw, indent, inactiveCount, entry);
- inactiveCount++;
- }
- }
- }
- }
-
- private void dumpEntry(PrintWriter pw, String indent, int i, Entry e) {
- getRanking(e.key, mTmpRanking);
- pw.print(indent);
- pw.println(" [" + i + "] key=" + e.key + " icon=" + e.icon);
- StatusBarNotification n = e.notification;
- pw.print(indent);
- pw.println(" pkg=" + n.getPackageName() + " id=" + n.getId() + " importance=" +
- mTmpRanking.getImportance());
- pw.print(indent);
- pw.println(" notification=" + n.getNotification());
- }
-
- private static boolean isSystemNotification(StatusBarNotification sbn) {
- String sbnPackage = sbn.getPackageName();
- return "android".equals(sbnPackage) || "com.android.systemui".equals(sbnPackage);
- }
-
- /**
- * Provides access to keyguard state and user settings dependent data.
- */
- public interface KeyguardEnvironment {
- boolean isDeviceProvisioned();
- boolean isNotificationForCurrentProfiles(StatusBarNotification sbn);
- }
-}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationEntryListener.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationEntryListener.java
index 2f60f115ed53..c6407604290f 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationEntryListener.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationEntryListener.java
@@ -19,6 +19,7 @@ import android.annotation.Nullable;
import android.service.notification.StatusBarNotification;
import com.android.internal.statusbar.NotificationVisibility;
+import com.android.systemui.statusbar.notification.collection.NotificationEntry;
import com.android.systemui.statusbar.notification.row.NotificationInflater;
/**
@@ -29,25 +30,25 @@ public interface NotificationEntryListener {
* Called when a new notification is posted. At this point, the notification is "pending": its
* views haven't been inflated yet and most of the system pretends like it doesn't exist yet.
*/
- default void onPendingEntryAdded(NotificationData.Entry entry) {
+ default void onPendingEntryAdded(NotificationEntry entry) {
}
/**
* Called when a new entry is created.
*/
- default void onNotificationAdded(NotificationData.Entry entry) {
+ default void onNotificationAdded(NotificationEntry entry) {
}
/**
* Called when a notification was updated.
*/
- default void onEntryUpdated(NotificationData.Entry entry) {
+ default void onEntryUpdated(NotificationEntry entry) {
}
/**
* Called when a notification's views are inflated for the first time.
*/
- default void onEntryInflated(NotificationData.Entry entry,
+ default void onEntryInflated(NotificationEntry entry,
@NotificationInflater.InflationFlag int inflatedFlags) {
}
@@ -57,7 +58,7 @@ public interface NotificationEntryListener {
*
* @param entry notification data entry that was reinflated.
*/
- default void onEntryReinflated(NotificationData.Entry entry) {
+ default void onEntryReinflated(NotificationEntry entry) {
}
/**
@@ -77,7 +78,7 @@ public interface NotificationEntryListener {
* @param removedByUser true if the notification was removed by a user action
*/
default void onEntryRemoved(
- NotificationData.Entry entry,
+ NotificationEntry entry,
@Nullable NotificationVisibility visibility,
boolean removedByUser) {
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationEntryManager.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationEntryManager.java
index 6b5e70825d1d..a4e3f339b58f 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationEntryManager.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationEntryManager.java
@@ -36,7 +36,9 @@ import com.android.systemui.statusbar.NotificationPresenter;
import com.android.systemui.statusbar.NotificationRemoteInputManager;
import com.android.systemui.statusbar.NotificationUiAdjustment;
import com.android.systemui.statusbar.NotificationUpdateHandler;
-import com.android.systemui.statusbar.notification.NotificationData.KeyguardEnvironment;
+import com.android.systemui.statusbar.notification.collection.NotificationData;
+import com.android.systemui.statusbar.notification.collection.NotificationData.KeyguardEnvironment;
+import com.android.systemui.statusbar.notification.collection.NotificationEntry;
import com.android.systemui.statusbar.notification.row.NotificationGutsManager;
import com.android.systemui.statusbar.notification.row.NotificationInflater;
import com.android.systemui.statusbar.notification.row.NotificationInflater.InflationFlag;
@@ -68,7 +70,7 @@ public class NotificationEntryManager implements
public static final long RECENTLY_ALERTED_THRESHOLD_MS = TimeUnit.SECONDS.toMillis(30);
protected final Context mContext;
- protected final HashMap<String, NotificationData.Entry> mPendingNotifications = new HashMap<>();
+ protected final HashMap<String, NotificationEntry> mPendingNotifications = new HashMap<>();
private final NotificationGutsManager mGutsManager =
Dependency.get(NotificationGutsManager.class);
@@ -113,7 +115,7 @@ public class NotificationEntryManager implements
if (mPendingNotifications.size() == 0) {
pw.println("null");
} else {
- for (NotificationData.Entry entry : mPendingNotifications.values()) {
+ for (NotificationEntry entry : mPendingNotifications.values()) {
pw.println(entry.notification);
}
}
@@ -205,11 +207,11 @@ public class NotificationEntryManager implements
private void abortExistingInflation(String key) {
if (mPendingNotifications.containsKey(key)) {
- NotificationData.Entry entry = mPendingNotifications.get(key);
+ NotificationEntry entry = mPendingNotifications.get(key);
entry.abortTask();
mPendingNotifications.remove(key);
}
- NotificationData.Entry addedEntry = mNotificationData.get(key);
+ NotificationEntry addedEntry = mNotificationData.get(key);
if (addedEntry != null) {
addedEntry.abortTask();
}
@@ -230,7 +232,7 @@ public class NotificationEntryManager implements
}
}
- private void maybeScheduleUpdateNotificationViews(NotificationData.Entry entry) {
+ private void maybeScheduleUpdateNotificationViews(NotificationEntry entry) {
long audibleAlertTimeout = RECENTLY_ALERTED_THRESHOLD_MS
- (System.currentTimeMillis() - entry.lastAudiblyAlertedMs);
if (audibleAlertTimeout > 0) {
@@ -240,7 +242,7 @@ public class NotificationEntryManager implements
}
@Override
- public void onAsyncInflationFinished(NotificationData.Entry entry,
+ public void onAsyncInflationFinished(NotificationEntry entry,
@InflationFlag int inflatedFlags) {
mPendingNotifications.remove(entry.key);
// If there was an async task started after the removal, we don't want to add it back to
@@ -279,7 +281,7 @@ public class NotificationEntryManager implements
@Nullable NotificationVisibility visibility,
boolean forceRemove,
boolean removedByUser) {
- final NotificationData.Entry entry = mNotificationData.get(key);
+ final NotificationEntry entry = mNotificationData.get(key);
abortExistingInflation(key);
@@ -337,19 +339,19 @@ public class NotificationEntryManager implements
*
*/
private void handleGroupSummaryRemoved(String key) {
- NotificationData.Entry entry = mNotificationData.get(key);
+ NotificationEntry entry = mNotificationData.get(key);
if (entry != null && entry.rowExists() && entry.isSummaryWithChildren()) {
if (entry.notification.getOverrideGroupKey() != null && !entry.isRowDismissed()) {
// We don't want to remove children for autobundled notifications as they are not
// always cancelled. We only remove them if they were dismissed by the user.
return;
}
- List<NotificationData.Entry> childEntries = entry.getChildren();
+ List<NotificationEntry> childEntries = entry.getChildren();
if (childEntries == null) {
return;
}
for (int i = 0; i < childEntries.size(); i++) {
- NotificationData.Entry childEntry = childEntries.get(i);
+ NotificationEntry childEntry = childEntries.get(i);
boolean isForeground = (entry.notification.getNotification().flags
& Notification.FLAG_FOREGROUND_SERVICE) != 0;
boolean keepForReply =
@@ -369,10 +371,10 @@ public class NotificationEntryManager implements
}
public void updateNotificationsOnDensityOrFontScaleChanged() {
- ArrayList<NotificationData.Entry> userNotifications =
+ ArrayList<NotificationEntry> userNotifications =
mNotificationData.getNotificationsForCurrentUser();
for (int i = 0; i < userNotifications.size(); i++) {
- NotificationData.Entry entry = userNotifications.get(i);
+ NotificationEntry entry = userNotifications.get(i);
entry.onDensityOrFontScaleChanged();
boolean exposedGuts = entry.areGutsExposed();
if (exposedGuts) {
@@ -392,7 +394,7 @@ public class NotificationEntryManager implements
NotificationListenerService.Ranking ranking = new NotificationListenerService.Ranking();
rankingMap.getRanking(key, ranking);
- NotificationData.Entry entry = new NotificationData.Entry(notification, ranking);
+ NotificationEntry entry = new NotificationEntry(notification, ranking);
Dependency.get(LeakDetector.class).trackInstance(entry);
// Construct the expanded view.
@@ -445,7 +447,7 @@ public class NotificationEntryManager implements
final String key = notification.getKey();
abortExistingInflation(key);
- NotificationData.Entry entry = mNotificationData.get(key);
+ NotificationEntry entry = mNotificationData.get(key);
if (entry == null) {
return;
}
@@ -494,14 +496,14 @@ public class NotificationEntryManager implements
}
public void updateNotificationRanking(NotificationListenerService.RankingMap rankingMap) {
- List<NotificationData.Entry> entries = new ArrayList<>();
+ List<NotificationEntry> entries = new ArrayList<>();
entries.addAll(mNotificationData.getActiveNotifications());
entries.addAll(mPendingNotifications.values());
// Has a copy of the current UI adjustments.
ArrayMap<String, NotificationUiAdjustment> oldAdjustments = new ArrayMap<>();
ArrayMap<String, Integer> oldImportances = new ArrayMap<>();
- for (NotificationData.Entry entry : entries) {
+ for (NotificationEntry entry : entries) {
NotificationUiAdjustment adjustment =
NotificationUiAdjustment.extractFromNotificationEntry(entry);
oldAdjustments.put(entry.key, adjustment);
@@ -513,7 +515,7 @@ public class NotificationEntryManager implements
updateRankingOfPendingNotifications(rankingMap);
// By comparing the old and new UI adjustments, reinflate the view accordingly.
- for (NotificationData.Entry entry : entries) {
+ for (NotificationEntry entry : entries) {
getRowBinder().onNotificationRankingUpdated(
entry,
oldImportances.get(entry.key),
@@ -531,7 +533,7 @@ public class NotificationEntryManager implements
return;
}
NotificationListenerService.Ranking tmpRanking = new NotificationListenerService.Ranking();
- for (NotificationData.Entry pendingNotification : mPendingNotifications.values()) {
+ for (NotificationEntry pendingNotification : mPendingNotifications.values()) {
rankingMap.getRanking(pendingNotification.key, tmpRanking);
pendingNotification.populateFromRanking(tmpRanking);
}
@@ -542,7 +544,7 @@ public class NotificationEntryManager implements
* notifications whose views have not yet been inflated. In general, the system pretends like
* these don't exist, although there are a couple exceptions.
*/
- public Iterable<NotificationData.Entry> getPendingNotificationsIterator() {
+ public Iterable<NotificationEntry> getPendingNotificationsIterator() {
return mPendingNotifications.values();
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationFilter.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationFilter.java
index 700382a103b2..e199ead18a68 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationFilter.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationFilter.java
@@ -28,6 +28,8 @@ import com.android.internal.annotations.VisibleForTesting;
import com.android.systemui.Dependency;
import com.android.systemui.ForegroundServiceController;
import com.android.systemui.statusbar.NotificationLockscreenUserManager;
+import com.android.systemui.statusbar.notification.collection.NotificationData;
+import com.android.systemui.statusbar.notification.collection.NotificationEntry;
import com.android.systemui.statusbar.phone.NotificationGroupManager;
import com.android.systemui.statusbar.phone.ShadeController;
import com.android.systemui.statusbar.phone.StatusBar;
@@ -82,7 +84,7 @@ public class NotificationFilter {
/**
* @return true if the provided notification should NOT be shown right now.
*/
- public boolean shouldFilterOut(NotificationData.Entry entry) {
+ public boolean shouldFilterOut(NotificationEntry entry) {
final StatusBarNotification sbn = entry.notification;
if (!(getEnvironment().isDeviceProvisioned()
|| showNotificationEvenIfUnprovisioned(sbn))) {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationInterruptionStateProvider.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationInterruptionStateProvider.java
index 8bd0e9ad3c8b..fc7a2b37eca7 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationInterruptionStateProvider.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationInterruptionStateProvider.java
@@ -37,6 +37,7 @@ import com.android.internal.annotations.VisibleForTesting;
import com.android.systemui.Dependency;
import com.android.systemui.statusbar.NotificationPresenter;
import com.android.systemui.statusbar.StatusBarStateController;
+import com.android.systemui.statusbar.notification.collection.NotificationEntry;
import com.android.systemui.statusbar.phone.ShadeController;
import com.android.systemui.statusbar.policy.HeadsUpManager;
@@ -139,7 +140,7 @@ public class NotificationInterruptionStateProvider {
* @param entry the entry to check
* @return true if the entry should heads up, false otherwise
*/
- public boolean shouldHeadsUp(NotificationData.Entry entry) {
+ public boolean shouldHeadsUp(NotificationEntry entry) {
StatusBarNotification sbn = entry.notification;
if (getShadeController().isDozing()) {
@@ -227,7 +228,7 @@ public class NotificationInterruptionStateProvider {
* @param entry the entry to check
* @return true if the entry should ambient pulse, false otherwise
*/
- public boolean shouldPulse(NotificationData.Entry entry) {
+ public boolean shouldPulse(NotificationEntry entry) {
StatusBarNotification sbn = entry.notification;
if (!getShadeController().isDozing()) {
@@ -273,14 +274,14 @@ public class NotificationInterruptionStateProvider {
/**
* Common checks between heads up alerting and ambient pulse alerting. See
- * {@link #shouldHeadsUp(NotificationData.Entry)} and
- * {@link #shouldPulse(NotificationData.Entry)}. Notifications that fail any of these checks
+ * {@link #shouldHeadsUp(NotificationEntry)} and
+ * {@link #shouldPulse(NotificationEntry)}. Notifications that fail any of these checks
* should not alert at all.
*
* @param entry the entry to check
* @return true if these checks pass, false if the notification should not alert
*/
- protected boolean canAlertCommon(NotificationData.Entry entry) {
+ protected boolean canAlertCommon(NotificationEntry entry) {
StatusBarNotification sbn = entry.notification;
if (mNotificationFilter.shouldFilterOut(entry)) {
@@ -325,7 +326,7 @@ public class NotificationInterruptionStateProvider {
* @param sbn notification that might be heads upped
* @return false if the notification can not be heads upped
*/
- boolean canHeadsUp(NotificationData.Entry entry, StatusBarNotification sbn);
+ boolean canHeadsUp(NotificationEntry entry, StatusBarNotification sbn);
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationRowBinder.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationRowBinder.java
index 058efca51b21..cc302b16f7c1 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationRowBinder.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationRowBinder.java
@@ -42,6 +42,7 @@ import com.android.systemui.statusbar.NotificationLockscreenUserManager;
import com.android.systemui.statusbar.NotificationPresenter;
import com.android.systemui.statusbar.NotificationRemoteInputManager;
import com.android.systemui.statusbar.NotificationUiAdjustment;
+import com.android.systemui.statusbar.notification.collection.NotificationEntry;
import com.android.systemui.statusbar.notification.row.ExpandableNotificationRow;
import com.android.systemui.statusbar.notification.row.NotificationGutsManager;
import com.android.systemui.statusbar.notification.row.NotificationInflater;
@@ -126,7 +127,7 @@ public class NotificationRowBinder {
* Inflates the views for the given entry (possibly asynchronously).
*/
public void inflateViews(
- NotificationData.Entry entry,
+ NotificationEntry entry,
Runnable onDismissRunnable,
boolean isUpdate)
throws InflationException {
@@ -149,7 +150,7 @@ public class NotificationRowBinder {
}
}
- private void bindRow(NotificationData.Entry entry, PackageManager pmUser,
+ private void bindRow(NotificationEntry entry, PackageManager pmUser,
StatusBarNotification sbn, ExpandableNotificationRow row,
Runnable onDismissRunnable) {
row.setExpansionLogger(mExpansionLogger, entry.notification.getKey());
@@ -197,7 +198,7 @@ public class NotificationRowBinder {
* reinflating them.
*/
public void onNotificationRankingUpdated(
- NotificationData.Entry entry,
+ NotificationEntry entry,
@Nullable Integer oldImportance,
NotificationUiAdjustment oldAdjustment,
NotificationUiAdjustment newAdjustment,
@@ -224,7 +225,7 @@ public class NotificationRowBinder {
//TODO: This method associates a row with an entry, but eventually needs to not do that
private void updateNotification(
- NotificationData.Entry entry,
+ NotificationEntry entry,
PackageManager pmUser,
StatusBarNotification sbn,
ExpandableNotificationRow row,
@@ -292,7 +293,7 @@ public class NotificationRowBinder {
* @param sbn notification
* @param row row for the notification
*/
- void onBindRow(NotificationData.Entry entry, PackageManager pmUser,
+ void onBindRow(NotificationEntry entry, PackageManager pmUser,
StatusBarNotification sbn, ExpandableNotificationRow row);
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/VisibilityLocationProvider.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/VisibilityLocationProvider.java
index a194eef39b6d..f09c57d786ef 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/VisibilityLocationProvider.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/VisibilityLocationProvider.java
@@ -16,6 +16,8 @@
package com.android.systemui.statusbar.notification;
+import com.android.systemui.statusbar.notification.collection.NotificationEntry;
+
/**
* An object that can determine the visibility of a Notification.
*/
@@ -27,5 +29,5 @@ public interface VisibilityLocationProvider {
* @param entry
* @return true if row is in a visible location
*/
- boolean isInVisibleLocation(NotificationData.Entry entry);
+ boolean isInVisibleLocation(NotificationEntry entry);
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/VisualStabilityManager.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/VisualStabilityManager.java
index 8e6a93deec69..c886685424f7 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/VisualStabilityManager.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/VisualStabilityManager.java
@@ -21,6 +21,7 @@ import android.view.View;
import androidx.collection.ArraySet;
import com.android.systemui.statusbar.NotificationPresenter;
+import com.android.systemui.statusbar.notification.collection.NotificationEntry;
import com.android.systemui.statusbar.notification.row.ExpandableNotificationRow;
import com.android.systemui.statusbar.policy.OnHeadsUpChangedListener;
@@ -52,7 +53,7 @@ public class VisualStabilityManager implements OnHeadsUpChangedListener {
public VisualStabilityManager(NotificationEntryManager notificationEntryManager) {
notificationEntryManager.addNotificationEntryListener(new NotificationEntryListener() {
@Override
- public void onEntryReinflated(NotificationData.Entry entry) {
+ public void onEntryReinflated(NotificationEntry entry) {
if (entry.hasLowPriorityStateUpdated()) {
onLowPriorityUpdated(entry);
if (mPresenter != null) {
@@ -163,7 +164,7 @@ public class VisualStabilityManager implements OnHeadsUpChangedListener {
}
@Override
- public void onHeadsUpStateChanged(NotificationData.Entry entry, boolean isHeadsUp) {
+ public void onHeadsUpStateChanged(NotificationEntry entry, boolean isHeadsUp) {
if (isHeadsUp) {
// Heads up notifications should in general be allowed to reorder if they are out of
// view and stay at the current location if they aren't.
@@ -171,7 +172,7 @@ public class VisualStabilityManager implements OnHeadsUpChangedListener {
}
}
- private void onLowPriorityUpdated(NotificationData.Entry entry) {
+ private void onLowPriorityUpdated(NotificationEntry entry) {
mLowPriorityReorderingViews.add(entry.getRow());
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/NotificationData.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/NotificationData.java
new file mode 100644
index 000000000000..8c29fb50f00a
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/NotificationData.java
@@ -0,0 +1,424 @@
+/*
+ * 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.statusbar.notification.collection;
+
+import android.app.NotificationChannel;
+import android.app.NotificationManager;
+import android.service.notification.NotificationListenerService.Ranking;
+import android.service.notification.NotificationListenerService.RankingMap;
+import android.service.notification.SnoozeCriterion;
+import android.service.notification.StatusBarNotification;
+import android.util.ArrayMap;
+
+import com.android.internal.annotations.VisibleForTesting;
+import com.android.systemui.Dependency;
+import com.android.systemui.statusbar.NotificationMediaManager;
+import com.android.systemui.statusbar.notification.NotificationFilter;
+import com.android.systemui.statusbar.phone.NotificationGroupManager;
+import com.android.systemui.statusbar.policy.HeadsUpManager;
+
+import java.io.PrintWriter;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.Comparator;
+import java.util.List;
+import java.util.Objects;
+
+/**
+ * The list of currently displaying notifications.
+ */
+public class NotificationData {
+
+ private final NotificationFilter mNotificationFilter = Dependency.get(NotificationFilter.class);
+
+ /**
+ * These dependencies are late init-ed
+ */
+ private KeyguardEnvironment mEnvironment;
+ private NotificationMediaManager mMediaManager;
+
+ private HeadsUpManager mHeadsUpManager;
+
+ private final ArrayMap<String, NotificationEntry> mEntries = new ArrayMap<>();
+ private final ArrayList<NotificationEntry> mSortedAndFiltered = new ArrayList<>();
+ private final ArrayList<NotificationEntry> mFilteredForUser = new ArrayList<>();
+
+ private final NotificationGroupManager mGroupManager =
+ Dependency.get(NotificationGroupManager.class);
+
+ private RankingMap mRankingMap;
+ private final Ranking mTmpRanking = new Ranking();
+
+ public void setHeadsUpManager(HeadsUpManager headsUpManager) {
+ mHeadsUpManager = headsUpManager;
+ }
+
+ private final Comparator<NotificationEntry> mRankingComparator =
+ new Comparator<NotificationEntry>() {
+ private final Ranking mRankingA = new Ranking();
+ private final Ranking mRankingB = new Ranking();
+
+ @Override
+ public int compare(NotificationEntry a, NotificationEntry b) {
+ final StatusBarNotification na = a.notification;
+ final StatusBarNotification nb = b.notification;
+ int aImportance = NotificationManager.IMPORTANCE_DEFAULT;
+ int bImportance = NotificationManager.IMPORTANCE_DEFAULT;
+ int aRank = 0;
+ int bRank = 0;
+
+ if (mRankingMap != null) {
+ // RankingMap as received from NoMan
+ getRanking(a.key, mRankingA);
+ getRanking(b.key, mRankingB);
+ aImportance = mRankingA.getImportance();
+ bImportance = mRankingB.getImportance();
+ aRank = mRankingA.getRank();
+ bRank = mRankingB.getRank();
+ }
+
+ String mediaNotification = getMediaManager().getMediaNotificationKey();
+
+ // IMPORTANCE_MIN media streams are allowed to drift to the bottom
+ final boolean aMedia = a.key.equals(mediaNotification)
+ && aImportance > NotificationManager.IMPORTANCE_MIN;
+ final boolean bMedia = b.key.equals(mediaNotification)
+ && bImportance > NotificationManager.IMPORTANCE_MIN;
+
+ boolean aSystemMax = aImportance >= NotificationManager.IMPORTANCE_HIGH
+ && isSystemNotification(na);
+ boolean bSystemMax = bImportance >= NotificationManager.IMPORTANCE_HIGH
+ && isSystemNotification(nb);
+
+ boolean isHeadsUp = a.getRow().isHeadsUp();
+ if (isHeadsUp != b.getRow().isHeadsUp()) {
+ return isHeadsUp ? -1 : 1;
+ } else if (isHeadsUp) {
+ // Provide consistent ranking with headsUpManager
+ return mHeadsUpManager.compare(a, b);
+ } else if (a.getRow().isAmbientPulsing() != b.getRow().isAmbientPulsing()) {
+ return a.getRow().isAmbientPulsing() ? -1 : 1;
+ } else if (aMedia != bMedia) {
+ // Upsort current media notification.
+ return aMedia ? -1 : 1;
+ } else if (aSystemMax != bSystemMax) {
+ // Upsort PRIORITY_MAX system notifications
+ return aSystemMax ? -1 : 1;
+ } else if (aRank != bRank) {
+ return aRank - bRank;
+ } else {
+ return Long.compare(nb.getNotification().when, na.getNotification().when);
+ }
+ }
+ };
+
+ private KeyguardEnvironment getEnvironment() {
+ if (mEnvironment == null) {
+ mEnvironment = Dependency.get(KeyguardEnvironment.class);
+ }
+ return mEnvironment;
+ }
+
+ private NotificationMediaManager getMediaManager() {
+ if (mMediaManager == null) {
+ mMediaManager = Dependency.get(NotificationMediaManager.class);
+ }
+ return mMediaManager;
+ }
+
+ /**
+ * Returns the sorted list of active notifications (depending on {@link KeyguardEnvironment}
+ *
+ * <p>
+ * This call doesn't update the list of active notifications. Call {@link #filterAndSort()}
+ * when the environment changes.
+ * <p>
+ * Don't hold on to or modify the returned list.
+ */
+ public ArrayList<NotificationEntry> getActiveNotifications() {
+ return mSortedAndFiltered;
+ }
+
+ public ArrayList<NotificationEntry> getNotificationsForCurrentUser() {
+ mFilteredForUser.clear();
+
+ synchronized (mEntries) {
+ final int len = mEntries.size();
+ for (int i = 0; i < len; i++) {
+ NotificationEntry entry = mEntries.valueAt(i);
+ final StatusBarNotification sbn = entry.notification;
+ if (!getEnvironment().isNotificationForCurrentProfiles(sbn)) {
+ continue;
+ }
+ mFilteredForUser.add(entry);
+ }
+ }
+ return mFilteredForUser;
+ }
+
+ public NotificationEntry get(String key) {
+ return mEntries.get(key);
+ }
+
+ public void add(NotificationEntry entry) {
+ synchronized (mEntries) {
+ mEntries.put(entry.notification.getKey(), entry);
+ }
+ mGroupManager.onEntryAdded(entry);
+
+ updateRankingAndSort(mRankingMap);
+ }
+
+ public NotificationEntry remove(String key, RankingMap ranking) {
+ NotificationEntry removed;
+ synchronized (mEntries) {
+ removed = mEntries.remove(key);
+ }
+ if (removed == null) return null;
+ mGroupManager.onEntryRemoved(removed);
+ updateRankingAndSort(ranking);
+ return removed;
+ }
+
+ /** Updates the given notification entry with the provided ranking. */
+ public void update(
+ NotificationEntry entry,
+ RankingMap ranking,
+ StatusBarNotification notification) {
+ updateRanking(ranking);
+ final StatusBarNotification oldNotification = entry.notification;
+ entry.notification = notification;
+ mGroupManager.onEntryUpdated(entry, oldNotification);
+ }
+
+ public void updateRanking(RankingMap ranking) {
+ updateRankingAndSort(ranking);
+ }
+
+ public void updateAppOp(int appOp, int uid, String pkg, String key, boolean showIcon) {
+ synchronized (mEntries) {
+ final int len = mEntries.size();
+ for (int i = 0; i < len; i++) {
+ NotificationEntry entry = mEntries.valueAt(i);
+ if (uid == entry.notification.getUid()
+ && pkg.equals(entry.notification.getPackageName())
+ && key.equals(entry.key)) {
+ if (showIcon) {
+ entry.mActiveAppOps.add(appOp);
+ } else {
+ entry.mActiveAppOps.remove(appOp);
+ }
+ }
+ }
+ }
+ }
+
+ /**
+ * Returns true if this notification should be displayed in the high-priority notifications
+ * section (and on the lockscreen and status bar).
+ */
+ public boolean isHighPriority(StatusBarNotification statusBarNotification) {
+ if (mRankingMap != null) {
+ getRanking(statusBarNotification.getKey(), mTmpRanking);
+ if (mTmpRanking.getImportance() >= NotificationManager.IMPORTANCE_DEFAULT
+ || statusBarNotification.getNotification().isForegroundService()
+ || statusBarNotification.getNotification().hasMediaSession()) {
+ return true;
+ }
+ if (mGroupManager.isSummaryOfGroup(statusBarNotification)) {
+ final ArrayList<NotificationEntry> logicalChildren =
+ mGroupManager.getLogicalChildren(statusBarNotification);
+ for (NotificationEntry child : logicalChildren) {
+ if (isHighPriority(child.notification)) {
+ return true;
+ }
+ }
+ }
+ }
+ return false;
+ }
+
+ public boolean isAmbient(String key) {
+ if (mRankingMap != null) {
+ getRanking(key, mTmpRanking);
+ return mTmpRanking.isAmbient();
+ }
+ return false;
+ }
+
+ public int getVisibilityOverride(String key) {
+ if (mRankingMap != null) {
+ getRanking(key, mTmpRanking);
+ return mTmpRanking.getVisibilityOverride();
+ }
+ return Ranking.VISIBILITY_NO_OVERRIDE;
+ }
+
+ public int getImportance(String key) {
+ if (mRankingMap != null) {
+ getRanking(key, mTmpRanking);
+ return mTmpRanking.getImportance();
+ }
+ return NotificationManager.IMPORTANCE_UNSPECIFIED;
+ }
+
+ public String getOverrideGroupKey(String key) {
+ if (mRankingMap != null) {
+ getRanking(key, mTmpRanking);
+ return mTmpRanking.getOverrideGroupKey();
+ }
+ return null;
+ }
+
+ public List<SnoozeCriterion> getSnoozeCriteria(String key) {
+ if (mRankingMap != null) {
+ getRanking(key, mTmpRanking);
+ return mTmpRanking.getSnoozeCriteria();
+ }
+ return null;
+ }
+
+ public NotificationChannel getChannel(String key) {
+ if (mRankingMap != null) {
+ getRanking(key, mTmpRanking);
+ return mTmpRanking.getChannel();
+ }
+ return null;
+ }
+
+ public int getRank(String key) {
+ if (mRankingMap != null) {
+ getRanking(key, mTmpRanking);
+ return mTmpRanking.getRank();
+ }
+ return 0;
+ }
+
+ public boolean shouldHide(String key) {
+ if (mRankingMap != null) {
+ getRanking(key, mTmpRanking);
+ return mTmpRanking.isSuspended();
+ }
+ return false;
+ }
+
+ private void updateRankingAndSort(RankingMap ranking) {
+ if (ranking != null) {
+ mRankingMap = ranking;
+ synchronized (mEntries) {
+ final int len = mEntries.size();
+ for (int i = 0; i < len; i++) {
+ NotificationEntry entry = mEntries.valueAt(i);
+ if (!getRanking(entry.key, mTmpRanking)) {
+ continue;
+ }
+ final StatusBarNotification oldSbn = entry.notification.cloneLight();
+ final String overrideGroupKey = getOverrideGroupKey(entry.key);
+ if (!Objects.equals(oldSbn.getOverrideGroupKey(), overrideGroupKey)) {
+ entry.notification.setOverrideGroupKey(overrideGroupKey);
+ mGroupManager.onEntryUpdated(entry, oldSbn);
+ }
+ entry.populateFromRanking(mTmpRanking);
+ }
+ }
+ }
+ filterAndSort();
+ }
+
+ /**
+ * Get the ranking from the current ranking map.
+ *
+ * @param key the key to look up
+ * @param outRanking the ranking to populate
+ *
+ * @return {@code true} if the ranking was properly obtained.
+ */
+ @VisibleForTesting
+ protected boolean getRanking(String key, Ranking outRanking) {
+ return mRankingMap.getRanking(key, outRanking);
+ }
+
+ // TODO: This should not be public. Instead the Environment should notify this class when
+ // anything changed, and this class should call back the UI so it updates itself.
+ public void filterAndSort() {
+ mSortedAndFiltered.clear();
+
+ synchronized (mEntries) {
+ final int len = mEntries.size();
+ for (int i = 0; i < len; i++) {
+ NotificationEntry entry = mEntries.valueAt(i);
+
+ if (mNotificationFilter.shouldFilterOut(entry)) {
+ continue;
+ }
+
+ mSortedAndFiltered.add(entry);
+ }
+ }
+
+ Collections.sort(mSortedAndFiltered, mRankingComparator);
+ }
+
+ public void dump(PrintWriter pw, String indent) {
+ int filteredLen = mSortedAndFiltered.size();
+ pw.print(indent);
+ pw.println("active notifications: " + filteredLen);
+ int active;
+ for (active = 0; active < filteredLen; active++) {
+ NotificationEntry e = mSortedAndFiltered.get(active);
+ dumpEntry(pw, indent, active, e);
+ }
+ synchronized (mEntries) {
+ int totalLen = mEntries.size();
+ pw.print(indent);
+ pw.println("inactive notifications: " + (totalLen - active));
+ int inactiveCount = 0;
+ for (int i = 0; i < totalLen; i++) {
+ NotificationEntry entry = mEntries.valueAt(i);
+ if (!mSortedAndFiltered.contains(entry)) {
+ dumpEntry(pw, indent, inactiveCount, entry);
+ inactiveCount++;
+ }
+ }
+ }
+ }
+
+ private void dumpEntry(PrintWriter pw, String indent, int i, NotificationEntry e) {
+ getRanking(e.key, mTmpRanking);
+ pw.print(indent);
+ pw.println(" [" + i + "] key=" + e.key + " icon=" + e.icon);
+ StatusBarNotification n = e.notification;
+ pw.print(indent);
+ pw.println(" pkg=" + n.getPackageName() + " id=" + n.getId() + " importance="
+ + mTmpRanking.getImportance());
+ pw.print(indent);
+ pw.println(" notification=" + n.getNotification());
+ }
+
+ private static boolean isSystemNotification(StatusBarNotification sbn) {
+ String sbnPackage = sbn.getPackageName();
+ return "android".equals(sbnPackage) || "com.android.systemui".equals(sbnPackage);
+ }
+
+ /**
+ * Provides access to keyguard state and user settings dependent data.
+ */
+ public interface KeyguardEnvironment {
+ boolean isDeviceProvisioned();
+ boolean isNotificationForCurrentProfiles(StatusBarNotification sbn);
+ }
+}
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
new file mode 100644
index 000000000000..58aa02ccf440
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/NotificationEntry.java
@@ -0,0 +1,701 @@
+/*
+ * 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.statusbar.notification.collection;
+
+import static android.app.Notification.CATEGORY_ALARM;
+import static android.app.Notification.CATEGORY_CALL;
+import static android.app.Notification.CATEGORY_EVENT;
+import static android.app.Notification.CATEGORY_MESSAGE;
+import static android.app.Notification.CATEGORY_REMINDER;
+import static android.app.NotificationManager.Policy.SUPPRESSED_EFFECT_AMBIENT;
+import static android.app.NotificationManager.Policy.SUPPRESSED_EFFECT_FULL_SCREEN_INTENT;
+import static android.app.NotificationManager.Policy.SUPPRESSED_EFFECT_NOTIFICATION_LIST;
+import static android.app.NotificationManager.Policy.SUPPRESSED_EFFECT_PEEK;
+import static android.app.NotificationManager.Policy.SUPPRESSED_EFFECT_STATUS_BAR;
+
+import android.annotation.NonNull;
+import android.app.Notification;
+import android.app.NotificationChannel;
+import android.app.NotificationManager.Policy;
+import android.app.Person;
+import android.content.Context;
+import android.graphics.drawable.Icon;
+import android.os.Bundle;
+import android.os.Parcelable;
+import android.os.SystemClock;
+import android.service.notification.NotificationListenerService;
+import android.service.notification.SnoozeCriterion;
+import android.service.notification.StatusBarNotification;
+import android.util.ArraySet;
+import android.view.View;
+import android.widget.ImageView;
+
+import androidx.annotation.Nullable;
+
+import com.android.internal.annotations.VisibleForTesting;
+import com.android.internal.statusbar.StatusBarIcon;
+import com.android.internal.util.ArrayUtils;
+import com.android.internal.util.ContrastColorUtil;
+import com.android.systemui.statusbar.InflationTask;
+import com.android.systemui.statusbar.StatusBarIconView;
+import com.android.systemui.statusbar.notification.InflationException;
+import com.android.systemui.statusbar.notification.row.ExpandableNotificationRow;
+import com.android.systemui.statusbar.notification.row.NotificationGuts;
+import com.android.systemui.statusbar.notification.row.NotificationInflater;
+
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.List;
+import java.util.Objects;
+
+/**
+ * Represents a notification that the system UI knows about
+ *
+ * Whenever the NotificationManager tells us about the existence of a new notification, we wrap it
+ * in a NotificationEntry. Thus, every notification has an associated NotificationEntry, even if
+ * that notification is never displayed to the user (for example, if it's filtered out for some
+ * reason).
+ *
+ * Entries store information about the current state of the notification. Essentially:
+ * anything that needs to persist or be modifiable even when the notification's views don't
+ * exist. Any other state should be stored on the views/view controllers themselves.
+ *
+ * At the moment, there are many things here that shouldn't be and vice-versa. Hopefully we can
+ * clean this up in the future.
+ */
+public final class NotificationEntry {
+ private static final long LAUNCH_COOLDOWN = 2000;
+ private static final long REMOTE_INPUT_COOLDOWN = 500;
+ private static final long INITIALIZATION_DELAY = 400;
+ private static final long NOT_LAUNCHED_YET = -LAUNCH_COOLDOWN;
+ private static final int COLOR_INVALID = 1;
+ public final String key;
+ public StatusBarNotification notification;
+ public NotificationChannel channel;
+ public long lastAudiblyAlertedMs;
+ public boolean noisy;
+ public boolean ambient;
+ public int importance;
+ public StatusBarIconView icon;
+ public StatusBarIconView expandedIcon;
+ private boolean interruption;
+ public boolean autoRedacted; // whether the redacted notification was generated by us
+ public int targetSdk;
+ private long lastFullScreenIntentLaunchTime = NOT_LAUNCHED_YET;
+ public CharSequence remoteInputText;
+ public List<SnoozeCriterion> snoozeCriteria;
+ public int userSentiment = NotificationListenerService.Ranking.USER_SENTIMENT_NEUTRAL;
+ /** Smart Actions provided by the NotificationAssistantService. */
+ @NonNull
+ public List<Notification.Action> systemGeneratedSmartActions = Collections.emptyList();
+ public CharSequence[] smartReplies = new CharSequence[0];
+ @VisibleForTesting
+ public int suppressedVisualEffects;
+ public boolean suspended;
+
+ private NotificationEntry parent; // our parent (if we're in a group)
+ private ArrayList<NotificationEntry> children = new ArrayList<NotificationEntry>();
+ private ExpandableNotificationRow row; // the outer expanded view
+
+ private int mCachedContrastColor = COLOR_INVALID;
+ private int mCachedContrastColorIsFor = COLOR_INVALID;
+ private InflationTask mRunningTask = null;
+ private Throwable mDebugThrowable;
+ public CharSequence remoteInputTextWhenReset;
+ public long lastRemoteInputSent = NOT_LAUNCHED_YET;
+ public ArraySet<Integer> mActiveAppOps = new ArraySet<>(3);
+ public CharSequence headsUpStatusBarText;
+ public CharSequence headsUpStatusBarTextPublic;
+
+ private long initializationTime = -1;
+
+ /**
+ * Whether or not this row represents a system notification. Note that if this is
+ * {@code null}, that means we were either unable to retrieve the info or have yet to
+ * retrieve the info.
+ */
+ public Boolean mIsSystemNotification;
+
+ /**
+ * Has the user sent a reply through this Notification.
+ */
+ private boolean hasSentReply;
+
+ /**
+ * Whether this notification should be displayed as a bubble.
+ */
+ private boolean mIsBubble;
+
+ /**
+ * Whether the user has dismissed this notification when it was in bubble form.
+ */
+ private boolean mUserDismissedBubble;
+
+ public NotificationEntry(StatusBarNotification n) {
+ this(n, null);
+ }
+
+ public NotificationEntry(
+ StatusBarNotification n,
+ @Nullable NotificationListenerService.Ranking ranking) {
+ this.key = n.getKey();
+ this.notification = n;
+ if (ranking != null) {
+ populateFromRanking(ranking);
+ }
+ }
+
+ public void populateFromRanking(@NonNull NotificationListenerService.Ranking ranking) {
+ channel = ranking.getChannel();
+ lastAudiblyAlertedMs = ranking.getLastAudiblyAlertedMillis();
+ importance = ranking.getImportance();
+ ambient = ranking.isAmbient();
+ snoozeCriteria = ranking.getSnoozeCriteria();
+ userSentiment = ranking.getUserSentiment();
+ systemGeneratedSmartActions = ranking.getSmartActions() == null
+ ? Collections.emptyList() : ranking.getSmartActions();
+ smartReplies = ranking.getSmartReplies() == null
+ ? new CharSequence[0]
+ : ranking.getSmartReplies().toArray(new CharSequence[0]);
+ suppressedVisualEffects = ranking.getSuppressedVisualEffects();
+ suspended = ranking.isSuspended();
+ }
+
+ public void setInterruption() {
+ interruption = true;
+ }
+
+ public boolean hasInterrupted() {
+ return interruption;
+ }
+
+ public void setIsBubble(boolean bubbleable) {
+ mIsBubble = bubbleable;
+ }
+
+ public boolean isBubble() {
+ return mIsBubble;
+ }
+
+ public void setBubbleDismissed(boolean userDismissed) {
+ mUserDismissedBubble = userDismissed;
+ }
+
+ public boolean isBubbleDismissed() {
+ return mUserDismissedBubble;
+ }
+
+ /**
+ * Resets the notification entry to be re-used.
+ */
+ public void reset() {
+ if (row != null) {
+ row.reset();
+ }
+ }
+
+ public ExpandableNotificationRow getRow() {
+ return row;
+ }
+
+ //TODO: This will go away when we have a way to bind an entry to a row
+ public void setRow(ExpandableNotificationRow row) {
+ this.row = row;
+ }
+
+ @Nullable
+ public List<NotificationEntry> getChildren() {
+ if (children.size() <= 0) {
+ return null;
+ }
+
+ return children;
+ }
+
+ public void notifyFullScreenIntentLaunched() {
+ setInterruption();
+ lastFullScreenIntentLaunchTime = SystemClock.elapsedRealtime();
+ }
+
+ public boolean hasJustLaunchedFullScreenIntent() {
+ return SystemClock.elapsedRealtime() < lastFullScreenIntentLaunchTime + LAUNCH_COOLDOWN;
+ }
+
+ public boolean hasJustSentRemoteInput() {
+ return SystemClock.elapsedRealtime() < lastRemoteInputSent + REMOTE_INPUT_COOLDOWN;
+ }
+
+ public boolean hasFinishedInitialization() {
+ return initializationTime == -1
+ || SystemClock.elapsedRealtime() > initializationTime + INITIALIZATION_DELAY;
+ }
+
+ /**
+ * Create the icons for a notification
+ * @param context the context to create the icons with
+ * @param sbn the notification
+ * @throws InflationException Exception if required icons are not valid or specified
+ */
+ public void createIcons(Context context, StatusBarNotification sbn)
+ throws InflationException {
+ Notification n = sbn.getNotification();
+ final Icon smallIcon = n.getSmallIcon();
+ if (smallIcon == null) {
+ throw new InflationException("No small icon in notification from "
+ + sbn.getPackageName());
+ }
+
+ // Construct the icon.
+ icon = new StatusBarIconView(context,
+ sbn.getPackageName() + "/0x" + Integer.toHexString(sbn.getId()), sbn);
+ icon.setScaleType(ImageView.ScaleType.CENTER_INSIDE);
+
+ // Construct the expanded icon.
+ expandedIcon = new StatusBarIconView(context,
+ sbn.getPackageName() + "/0x" + Integer.toHexString(sbn.getId()), sbn);
+ expandedIcon.setScaleType(ImageView.ScaleType.CENTER_INSIDE);
+ final StatusBarIcon ic = new StatusBarIcon(
+ sbn.getUser(),
+ sbn.getPackageName(),
+ smallIcon,
+ n.iconLevel,
+ n.number,
+ StatusBarIconView.contentDescForNotification(context, n));
+ if (!icon.set(ic) || !expandedIcon.set(ic)) {
+ icon = null;
+ expandedIcon = null;
+ throw new InflationException("Couldn't create icon: " + ic);
+ }
+ expandedIcon.setVisibility(View.INVISIBLE);
+ expandedIcon.setOnVisibilityChangedListener(
+ newVisibility -> {
+ if (row != null) {
+ row.setIconsVisible(newVisibility != View.VISIBLE);
+ }
+ });
+ }
+
+ public void setIconTag(int key, Object tag) {
+ if (icon != null) {
+ icon.setTag(key, tag);
+ expandedIcon.setTag(key, tag);
+ }
+ }
+
+ /**
+ * Update the notification icons.
+ *
+ * @param context the context to create the icons with.
+ * @param sbn the notification to read the icon from.
+ * @throws InflationException Exception if required icons are not valid or specified
+ */
+ public void updateIcons(Context context, StatusBarNotification sbn)
+ throws InflationException {
+ if (icon != null) {
+ // Update the icon
+ Notification n = sbn.getNotification();
+ final StatusBarIcon ic = new StatusBarIcon(
+ notification.getUser(),
+ notification.getPackageName(),
+ n.getSmallIcon(),
+ n.iconLevel,
+ n.number,
+ StatusBarIconView.contentDescForNotification(context, n));
+ icon.setNotification(sbn);
+ expandedIcon.setNotification(sbn);
+ if (!icon.set(ic) || !expandedIcon.set(ic)) {
+ throw new InflationException("Couldn't update icon: " + ic);
+ }
+ }
+ }
+
+ public int getContrastedColor(Context context, boolean isLowPriority,
+ int backgroundColor) {
+ int rawColor = isLowPriority ? Notification.COLOR_DEFAULT :
+ notification.getNotification().color;
+ if (mCachedContrastColorIsFor == rawColor && mCachedContrastColor != COLOR_INVALID) {
+ return mCachedContrastColor;
+ }
+ final int contrasted = ContrastColorUtil.resolveContrastColor(context, rawColor,
+ backgroundColor);
+ mCachedContrastColorIsFor = rawColor;
+ mCachedContrastColor = contrasted;
+ return mCachedContrastColor;
+ }
+
+ /**
+ * Abort all existing inflation tasks
+ */
+ public void abortTask() {
+ if (mRunningTask != null) {
+ mRunningTask.abort();
+ mRunningTask = null;
+ }
+ }
+
+ public void setInflationTask(InflationTask abortableTask) {
+ // abort any existing inflation
+ InflationTask existing = mRunningTask;
+ abortTask();
+ mRunningTask = abortableTask;
+ if (existing != null && mRunningTask != null) {
+ mRunningTask.supersedeTask(existing);
+ }
+ }
+
+ public void onInflationTaskFinished() {
+ mRunningTask = null;
+ }
+
+ @VisibleForTesting
+ public InflationTask getRunningTask() {
+ return mRunningTask;
+ }
+
+ /**
+ * Set a throwable that is used for debugging
+ *
+ * @param debugThrowable the throwable to save
+ */
+ public void setDebugThrowable(Throwable debugThrowable) {
+ mDebugThrowable = debugThrowable;
+ }
+
+ public Throwable getDebugThrowable() {
+ return mDebugThrowable;
+ }
+
+ public void onRemoteInputInserted() {
+ lastRemoteInputSent = NOT_LAUNCHED_YET;
+ remoteInputTextWhenReset = null;
+ }
+
+ public void setHasSentReply() {
+ hasSentReply = true;
+ }
+
+ public boolean isLastMessageFromReply() {
+ if (!hasSentReply) {
+ return false;
+ }
+ Bundle extras = notification.getNotification().extras;
+ CharSequence[] replyTexts = extras.getCharSequenceArray(
+ Notification.EXTRA_REMOTE_INPUT_HISTORY);
+ if (!ArrayUtils.isEmpty(replyTexts)) {
+ return true;
+ }
+ Parcelable[] messages = extras.getParcelableArray(Notification.EXTRA_MESSAGES);
+ if (messages != null && messages.length > 0) {
+ Parcelable message = messages[messages.length - 1];
+ if (message instanceof Bundle) {
+ Notification.MessagingStyle.Message lastMessage =
+ Notification.MessagingStyle.Message.getMessageFromBundle(
+ (Bundle) message);
+ if (lastMessage != null) {
+ Person senderPerson = lastMessage.getSenderPerson();
+ if (senderPerson == null) {
+ return true;
+ }
+ Person user = extras.getParcelable(Notification.EXTRA_MESSAGING_PERSON);
+ return Objects.equals(user, senderPerson);
+ }
+ }
+ }
+ return false;
+ }
+
+ public void setInitializationTime(long time) {
+ if (initializationTime == -1) {
+ initializationTime = time;
+ }
+ }
+
+ public void sendAccessibilityEvent(int eventType) {
+ if (row != null) {
+ row.sendAccessibilityEvent(eventType);
+ }
+ }
+
+ /**
+ * Used by NotificationMediaManager to determine... things
+ * @return {@code true} if we are a media notification
+ */
+ public boolean isMediaNotification() {
+ if (row == null) return false;
+
+ return row.isMediaRow();
+ }
+
+ /**
+ * We are a top level child if our parent is the list of notifications duh
+ * @return {@code true} if we're a top level notification
+ */
+ public boolean isTopLevelChild() {
+ return row != null && row.isTopLevelChild();
+ }
+
+ public void resetUserExpansion() {
+ if (row != null) row.resetUserExpansion();
+ }
+
+ public void freeContentViewWhenSafe(@NotificationInflater.InflationFlag int inflationFlag) {
+ if (row != null) row.freeContentViewWhenSafe(inflationFlag);
+ }
+
+ public void setAmbientPulsing(boolean pulsing) {
+ if (row != null) row.setAmbientPulsing(pulsing);
+ }
+
+ public boolean rowExists() {
+ return row != null;
+ }
+
+ public boolean isRowDismissed() {
+ return row != null && row.isDismissed();
+ }
+
+ public boolean isRowRemoved() {
+ return row != null && row.isRemoved();
+ }
+
+ /**
+ * @return {@code true} if the row is null or removed
+ */
+ public boolean isRemoved() {
+ //TODO: recycling invalidates this
+ return row == null || row.isRemoved();
+ }
+
+ /**
+ * @return {@code true} if the row is null or dismissed
+ */
+ public boolean isDismissed() {
+ //TODO: recycling
+ return row == null || row.isDismissed();
+ }
+
+ public boolean isRowPinned() {
+ return row != null && row.isPinned();
+ }
+
+ public void setRowPinned(boolean pinned) {
+ if (row != null) row.setPinned(pinned);
+ }
+
+ public boolean isRowAnimatingAway() {
+ return row != null && row.isHeadsUpAnimatingAway();
+ }
+
+ public boolean isRowHeadsUp() {
+ return row != null && row.isHeadsUp();
+ }
+
+ public void setHeadsUp(boolean shouldHeadsUp) {
+ if (row != null) row.setHeadsUp(shouldHeadsUp);
+ }
+
+ public boolean mustStayOnScreen() {
+ return row != null && row.mustStayOnScreen();
+ }
+
+ public void setHeadsUpIsVisible() {
+ if (row != null) row.setHeadsUpIsVisible();
+ }
+
+ //TODO: i'm imagining a world where this isn't just the row, but I could be rwong
+ public ExpandableNotificationRow getHeadsUpAnimationView() {
+ return row;
+ }
+
+ public void setUserLocked(boolean userLocked) {
+ if (row != null) row.setUserLocked(userLocked);
+ }
+
+ public void setUserExpanded(boolean userExpanded, boolean allowChildExpansion) {
+ if (row != null) row.setUserExpanded(userExpanded, allowChildExpansion);
+ }
+
+ public void setGroupExpansionChanging(boolean changing) {
+ if (row != null) row.setGroupExpansionChanging(changing);
+ }
+
+ public void notifyHeightChanged(boolean needsAnimation) {
+ if (row != null) row.notifyHeightChanged(needsAnimation);
+ }
+
+ public void closeRemoteInput() {
+ if (row != null) row.closeRemoteInput();
+ }
+
+ public boolean areChildrenExpanded() {
+ return row != null && row.areChildrenExpanded();
+ }
+
+ public boolean keepInParent() {
+ return row != null && row.keepInParent();
+ }
+
+ //TODO: probably less confusing to say "is group fully visible"
+ public boolean isGroupNotFullyVisible() {
+ return row == null || row.isGroupNotFullyVisible();
+ }
+
+ public NotificationGuts getGuts() {
+ if (row != null) return row.getGuts();
+ return null;
+ }
+
+ public boolean hasLowPriorityStateUpdated() {
+ return row != null && row.hasLowPriorityStateUpdated();
+ }
+
+ public void removeRow() {
+ if (row != null) row.setRemoved();
+ }
+
+ public boolean isSummaryWithChildren() {
+ return row != null && row.isSummaryWithChildren();
+ }
+
+ public void setKeepInParent(boolean keep) {
+ if (row != null) row.setKeepInParent(keep);
+ }
+
+ public void onDensityOrFontScaleChanged() {
+ if (row != null) row.onDensityOrFontScaleChanged();
+ }
+
+ public boolean areGutsExposed() {
+ return row != null && row.getGuts() != null && row.getGuts().isExposed();
+ }
+
+ public boolean isChildInGroup() {
+ return parent == null;
+ }
+
+ public void setLowPriorityStateUpdated(boolean updated) {
+ if (row != null) row.setLowPriorityStateUpdated(updated);
+ }
+
+ /**
+ * @return Can the underlying notification be cleared? This can be different from whether the
+ * notification can be dismissed in case notifications are sensitive on the lockscreen.
+ * @see #canViewBeDismissed()
+ */
+ public boolean isClearable() {
+ if (notification == null || !notification.isClearable()) {
+ return false;
+ }
+ if (children.size() > 0) {
+ for (int i = 0; i < children.size(); i++) {
+ NotificationEntry child = children.get(i);
+ if (!child.isClearable()) {
+ return false;
+ }
+ }
+ }
+ return true;
+ }
+
+ public boolean canViewBeDismissed() {
+ if (row == null) return true;
+ return row.canViewBeDismissed();
+ }
+
+ @VisibleForTesting
+ boolean isExemptFromDndVisualSuppression() {
+ if (isNotificationBlockedByPolicy(notification.getNotification())) {
+ return false;
+ }
+
+ if ((notification.getNotification().flags
+ & Notification.FLAG_FOREGROUND_SERVICE) != 0) {
+ return true;
+ }
+ if (notification.getNotification().isMediaNotification()) {
+ return true;
+ }
+ if (mIsSystemNotification != null && mIsSystemNotification) {
+ return true;
+ }
+ return false;
+ }
+
+ private boolean shouldSuppressVisualEffect(int effect) {
+ if (isExemptFromDndVisualSuppression()) {
+ return false;
+ }
+ return (suppressedVisualEffects & effect) != 0;
+ }
+
+ /**
+ * Returns whether {@link Policy#SUPPRESSED_EFFECT_FULL_SCREEN_INTENT}
+ * is set for this entry.
+ */
+ public boolean shouldSuppressFullScreenIntent() {
+ return shouldSuppressVisualEffect(SUPPRESSED_EFFECT_FULL_SCREEN_INTENT);
+ }
+
+ /**
+ * Returns whether {@link Policy#SUPPRESSED_EFFECT_PEEK}
+ * is set for this entry.
+ */
+ public boolean shouldSuppressPeek() {
+ return shouldSuppressVisualEffect(SUPPRESSED_EFFECT_PEEK);
+ }
+
+ /**
+ * Returns whether {@link Policy#SUPPRESSED_EFFECT_STATUS_BAR}
+ * is set for this entry.
+ */
+ public boolean shouldSuppressStatusBar() {
+ return shouldSuppressVisualEffect(SUPPRESSED_EFFECT_STATUS_BAR);
+ }
+
+ /**
+ * Returns whether {@link Policy#SUPPRESSED_EFFECT_AMBIENT}
+ * is set for this entry.
+ */
+ public boolean shouldSuppressAmbient() {
+ return shouldSuppressVisualEffect(SUPPRESSED_EFFECT_AMBIENT);
+ }
+
+ /**
+ * Returns whether {@link Policy#SUPPRESSED_EFFECT_NOTIFICATION_LIST}
+ * is set for this entry.
+ */
+ public boolean shouldSuppressNotificationList() {
+ return shouldSuppressVisualEffect(SUPPRESSED_EFFECT_NOTIFICATION_LIST);
+ }
+
+ /**
+ * Categories that are explicitly called out on DND settings screens are always blocked, if
+ * DND has flagged them, even if they are foreground or system notifications that might
+ * otherwise visually bypass DND.
+ */
+ private static boolean isNotificationBlockedByPolicy(Notification n) {
+ return isCategory(CATEGORY_CALL, n)
+ || isCategory(CATEGORY_MESSAGE, n)
+ || isCategory(CATEGORY_ALARM, n)
+ || isCategory(CATEGORY_EVENT, n)
+ || isCategory(CATEGORY_REMINDER, n);
+ }
+
+ private static boolean isCategory(String category, Notification n) {
+ return Objects.equals(n.category, category);
+ }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/logging/NotificationLogger.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/logging/NotificationLogger.java
index 43048a2c087e..3eec38e14083 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/logging/NotificationLogger.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/logging/NotificationLogger.java
@@ -33,9 +33,9 @@ import com.android.systemui.UiOffloadThread;
import com.android.systemui.statusbar.NotificationListener;
import com.android.systemui.statusbar.StatusBarStateController;
import com.android.systemui.statusbar.StatusBarStateController.StateListener;
-import com.android.systemui.statusbar.notification.NotificationData;
import com.android.systemui.statusbar.notification.NotificationEntryListener;
import com.android.systemui.statusbar.notification.NotificationEntryManager;
+import com.android.systemui.statusbar.notification.collection.NotificationEntry;
import com.android.systemui.statusbar.notification.stack.NotificationListContainer;
import com.android.systemui.statusbar.policy.HeadsUpManager;
@@ -115,11 +115,11 @@ public class NotificationLogger implements StateListener {
// notifications.
// 3. Report newly visible and no-longer visible notifications.
// 4. Keep currently visible notifications for next report.
- ArrayList<NotificationData.Entry> activeNotifications = mEntryManager
+ ArrayList<NotificationEntry> activeNotifications = mEntryManager
.getNotificationData().getActiveNotifications();
int N = activeNotifications.size();
for (int i = 0; i < N; i++) {
- NotificationData.Entry entry = activeNotifications.get(i);
+ NotificationEntry entry = activeNotifications.get(i);
String key = entry.notification.getKey();
boolean isVisible = mListContainer.isInVisibleLocation(entry);
NotificationVisibility visObj = NotificationVisibility.obtain(key, i, N, isVisible);
@@ -167,7 +167,7 @@ public class NotificationLogger implements StateListener {
entryManager.addNotificationEntryListener(new NotificationEntryListener() {
@Override
public void onEntryRemoved(
- NotificationData.Entry entry,
+ NotificationEntry entry,
NotificationVisibility visibility,
boolean removedByUser) {
if (removedByUser && visibility != null) {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ExpandableNotificationRow.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ExpandableNotificationRow.java
index a58c7cde32a7..9e0dd8461d21 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ExpandableNotificationRow.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ExpandableNotificationRow.java
@@ -86,10 +86,10 @@ import com.android.systemui.statusbar.RemoteInputController;
import com.android.systemui.statusbar.StatusBarIconView;
import com.android.systemui.statusbar.notification.AboveShelfChangedListener;
import com.android.systemui.statusbar.notification.ActivityLaunchAnimator;
-import com.android.systemui.statusbar.notification.NotificationData;
import com.android.systemui.statusbar.notification.NotificationEntryManager;
import com.android.systemui.statusbar.notification.NotificationUtils;
import com.android.systemui.statusbar.notification.VisualStabilityManager;
+import com.android.systemui.statusbar.notification.collection.NotificationEntry;
import com.android.systemui.statusbar.notification.logging.NotificationCounters;
import com.android.systemui.statusbar.notification.row.NotificationInflater.InflationFlag;
import com.android.systemui.statusbar.notification.row.wrapper.NotificationViewWrapper;
@@ -199,7 +199,7 @@ public class ExpandableNotificationRow extends ActivatableNotificationView
private ExpansionLogger mLogger;
private String mLoggingKey;
private NotificationGuts mGuts;
- private NotificationData.Entry mEntry;
+ private NotificationEntry mEntry;
private StatusBarNotification mStatusBarNotification;
private String mAppName;
@@ -451,7 +451,7 @@ public class ExpandableNotificationRow extends ActivatableNotificationView
*
* @param entry the entry this row is tied to
*/
- public void setEntry(@NonNull NotificationData.Entry entry) {
+ public void setEntry(@NonNull NotificationEntry entry) {
mEntry = entry;
mStatusBarNotification = entry.notification;
cacheIsSystemNotification();
@@ -685,7 +685,7 @@ public class ExpandableNotificationRow extends ActivatableNotificationView
return mStatusBarNotification;
}
- public NotificationData.Entry getEntry() {
+ public NotificationEntry getEntry() {
return mEntry;
}
@@ -1422,7 +1422,7 @@ public class ExpandableNotificationRow extends ActivatableNotificationView
public void performDismiss(boolean fromAccessibility) {
if (isOnlyChildInGroup()) {
- NotificationData.Entry groupSummary =
+ NotificationEntry groupSummary =
mGroupManager.getLogicalGroupSummary(getStatusBarNotification());
if (groupSummary.isClearable()) {
// If this is the only child in the group, dismiss the group, but don't try to show
@@ -2538,7 +2538,7 @@ public class ExpandableNotificationRow extends ActivatableNotificationView
/**
* @return Whether this view is allowed to be dismissed. Only valid for visible notifications as
* otherwise some state might not be updated. To request about the general clearability
- * see {@link NotificationData.Entry#isClearable()}.
+ * see {@link NotificationEntry#isClearable()}.
*/
public boolean canViewBeDismissed() {
return mEntry.isClearable() && (!shouldShowPublic() || !mSensitiveHiddenInGeneral);
@@ -2969,7 +2969,7 @@ public class ExpandableNotificationRow extends ActivatableNotificationView
}
public interface OnExpandClickListener {
- void onExpandClicked(NotificationData.Entry clickedEntry, boolean nowExpanded);
+ void onExpandClicked(NotificationEntry clickedEntry, boolean nowExpanded);
}
@Override
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationContentView.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationContentView.java
index 02a310c29379..bf30cf9a53c0 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationContentView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationContentView.java
@@ -46,8 +46,8 @@ import com.android.systemui.R;
import com.android.systemui.statusbar.RemoteInputController;
import com.android.systemui.statusbar.SmartReplyController;
import com.android.systemui.statusbar.TransformableView;
-import com.android.systemui.statusbar.notification.NotificationData;
import com.android.systemui.statusbar.notification.NotificationUtils;
+import com.android.systemui.statusbar.notification.collection.NotificationEntry;
import com.android.systemui.statusbar.notification.row.wrapper.NotificationCustomViewWrapper;
import com.android.systemui.statusbar.notification.row.wrapper.NotificationViewWrapper;
import com.android.systemui.statusbar.phone.NotificationGroupManager;
@@ -1231,7 +1231,7 @@ public class NotificationContentView extends FrameLayout {
updateAllSingleLineViews();
}
- public void onNotificationUpdated(NotificationData.Entry entry) {
+ public void onNotificationUpdated(NotificationEntry entry) {
mStatusBarNotification = entry.notification;
mOnContentViewInactiveListeners.clear();
mBeforeN = entry.targetSdk < Build.VERSION_CODES.N;
@@ -1292,7 +1292,7 @@ public class NotificationContentView extends FrameLayout {
}
}
- private void applyRemoteInputAndSmartReply(final NotificationData.Entry entry) {
+ private void applyRemoteInputAndSmartReply(final NotificationEntry entry) {
if (mRemoteInputController == null) {
return;
}
@@ -1313,7 +1313,7 @@ public class NotificationContentView extends FrameLayout {
@VisibleForTesting
static SmartRepliesAndActions chooseSmartRepliesAndActions(
SmartReplyConstants smartReplyConstants,
- final NotificationData.Entry entry) {
+ final NotificationEntry entry) {
boolean enableAppGeneratedSmartReplies = (smartReplyConstants.isEnabled()
&& (!smartReplyConstants.requiresTargetingP()
|| entry.targetSdk >= Build.VERSION_CODES.P));
@@ -1370,7 +1370,7 @@ public class NotificationContentView extends FrameLayout {
smartReplies, smartActions, freeformRemoteInputActionPair != null);
}
- private void applyRemoteInput(NotificationData.Entry entry, boolean hasFreeformRemoteInput) {
+ private void applyRemoteInput(NotificationEntry entry, boolean hasFreeformRemoteInput) {
View bigContentView = mExpandedChild;
if (bigContentView != null) {
mExpandedRemoteInput = applyRemoteInput(bigContentView, entry, hasFreeformRemoteInput,
@@ -1402,7 +1402,7 @@ public class NotificationContentView extends FrameLayout {
mCachedHeadsUpRemoteInput = null;
}
- private RemoteInputView applyRemoteInput(View view, NotificationData.Entry entry,
+ private RemoteInputView applyRemoteInput(View view, NotificationEntry entry,
boolean hasRemoteInput, PendingIntent existingPendingIntent,
RemoteInputView cachedView, NotificationViewWrapper wrapper) {
View actionContainerCandidate = view.findViewById(
@@ -1470,7 +1470,7 @@ public class NotificationContentView extends FrameLayout {
}
private void applySmartReplyView(SmartRepliesAndActions smartRepliesAndActions,
- NotificationData.Entry entry) {
+ NotificationEntry entry) {
if (mExpandedChild != null) {
mExpandedSmartReplyView =
applySmartReplyView(mExpandedChild, smartRepliesAndActions, entry);
@@ -1496,7 +1496,7 @@ public class NotificationContentView extends FrameLayout {
}
private SmartReplyView applySmartReplyView(View view,
- SmartRepliesAndActions smartRepliesAndActions, NotificationData.Entry entry) {
+ SmartRepliesAndActions smartRepliesAndActions, NotificationEntry entry) {
View smartReplyContainerCandidate = view.findViewById(
com.android.internal.R.id.smart_reply_container);
if (!(smartReplyContainerCandidate instanceof LinearLayout)) {
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 ac4e5830d76b..bd1dfb181afe 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
@@ -48,7 +48,7 @@ import com.android.systemui.statusbar.NotificationPresenter;
import com.android.systemui.statusbar.StatusBarState;
import com.android.systemui.statusbar.StatusBarStateController;
import com.android.systemui.statusbar.notification.NotificationActivityStarter;
-import com.android.systemui.statusbar.notification.NotificationData;
+import com.android.systemui.statusbar.notification.collection.NotificationEntry;
import com.android.systemui.statusbar.notification.row.NotificationInfo.CheckSaveListener;
import com.android.systemui.statusbar.notification.stack.NotificationListContainer;
import com.android.systemui.statusbar.phone.StatusBar;
@@ -116,7 +116,7 @@ public class NotificationGutsManager implements Dumpable, NotificationLifetimeEx
mNotificationActivityStarter = notificationActivityStarter;
}
- public void onDensityOrFontScaleChanged(NotificationData.Entry entry) {
+ public void onDensityOrFontScaleChanged(NotificationEntry entry) {
setExposedGuts(entry.getGuts());
bindGuts(entry.getRow());
}
@@ -429,7 +429,7 @@ public class NotificationGutsManager implements Dumpable, NotificationLifetimeEx
}
@Override
- public boolean shouldExtendLifetime(NotificationData.Entry entry) {
+ public boolean shouldExtendLifetime(NotificationEntry entry) {
return entry != null
&&(mNotificationGutsExposed != null
&& entry.getGuts() != null
@@ -438,7 +438,7 @@ public class NotificationGutsManager implements Dumpable, NotificationLifetimeEx
}
@Override
- public void setShouldManageLifetime(NotificationData.Entry entry, boolean shouldExtend) {
+ public void setShouldManageLifetime(NotificationEntry entry, boolean shouldExtend) {
if (shouldExtend) {
mKeyToRemoveOnGutsClosed = entry.key;
if (Log.isLoggable(TAG, Log.DEBUG)) {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationInflater.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationInflater.java
index 9908049984d1..42ebfceca334 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationInflater.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationInflater.java
@@ -37,7 +37,7 @@ import com.android.internal.widget.ImageMessageConsumer;
import com.android.systemui.statusbar.InflationTask;
import com.android.systemui.statusbar.notification.InflationException;
import com.android.systemui.statusbar.notification.MediaNotificationProcessor;
-import com.android.systemui.statusbar.notification.NotificationData;
+import com.android.systemui.statusbar.notification.collection.NotificationEntry;
import com.android.systemui.statusbar.notification.row.wrapper.NotificationViewWrapper;
import com.android.systemui.statusbar.phone.StatusBar;
import com.android.systemui.util.Assert;
@@ -614,7 +614,7 @@ public class NotificationInflater {
@Nullable InflationCallback endListener, ExpandableNotificationRow row,
boolean redactAmbient) {
Assert.isMainThread();
- NotificationData.Entry entry = row.getEntry();
+ NotificationEntry entry = row.getEntry();
NotificationContentView privateLayout = row.getPrivateLayout();
NotificationContentView publicLayout = row.getPublicLayout();
if (runningInflations.isEmpty()) {
@@ -724,7 +724,7 @@ public class NotificationInflater {
* @param entry the entry with the content views set
* @param inflatedFlags the flags associated with the content views that were inflated
*/
- void onAsyncInflationFinished(NotificationData.Entry entry,
+ void onAsyncInflationFinished(NotificationEntry entry,
@InflationFlag int inflatedFlags);
/**
@@ -782,7 +782,7 @@ public class NotificationInflater {
mRedactAmbient = redactAmbient;
mRemoteViewClickHandler = remoteViewClickHandler;
mCallback = callback;
- NotificationData.Entry entry = row.getEntry();
+ NotificationEntry entry = row.getEntry();
entry.setInflationTask(this);
}
@@ -857,7 +857,7 @@ public class NotificationInflater {
}
@Override
- public void onAsyncInflationFinished(NotificationData.Entry entry,
+ public void onAsyncInflationFinished(NotificationEntry entry,
@InflationFlag int inflatedFlags) {
mRow.getEntry().onInflationTaskFinished();
mRow.onNotificationUpdated();
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/RowInflaterTask.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/RowInflaterTask.java
index 1741a0b6b37c..0160c547b336 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/RowInflaterTask.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/RowInflaterTask.java
@@ -25,7 +25,7 @@ import androidx.asynclayoutinflater.view.AsyncLayoutInflater;
import com.android.systemui.R;
import com.android.systemui.statusbar.InflationTask;
-import com.android.systemui.statusbar.notification.NotificationData;
+import com.android.systemui.statusbar.notification.collection.NotificationEntry;
/**
* An inflater task that asynchronously inflates a ExpandableNotificationRow
@@ -36,14 +36,14 @@ public class RowInflaterTask implements InflationTask, AsyncLayoutInflater.OnInf
private static final boolean TRACE_ORIGIN = true;
private RowInflationFinishedListener mListener;
- private NotificationData.Entry mEntry;
+ private NotificationEntry mEntry;
private boolean mCancelled;
private Throwable mInflateOrigin;
/**
* Inflates a new notificationView. This should not be called twice on this object
*/
- public void inflate(Context context, ViewGroup parent, NotificationData.Entry entry,
+ public void inflate(Context context, ViewGroup parent, NotificationEntry entry,
RowInflationFinishedListener listener) {
if (TRACE_ORIGIN) {
mInflateOrigin = new Throwable("inflate requested here");
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 670908fe175d..cbec37effe18 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
@@ -25,7 +25,7 @@ import com.android.systemui.R;
import com.android.systemui.statusbar.AmbientPulseManager;
import com.android.systemui.statusbar.NotificationShelf;
import com.android.systemui.statusbar.StatusBarState;
-import com.android.systemui.statusbar.notification.NotificationData;
+import com.android.systemui.statusbar.notification.collection.NotificationEntry;
import com.android.systemui.statusbar.notification.row.ActivatableNotificationView;
import com.android.systemui.statusbar.notification.row.ExpandableNotificationRow;
import com.android.systemui.statusbar.notification.row.ExpandableView;
@@ -358,7 +358,7 @@ public class AmbientState {
mPulsing = hasPulsing;
}
- public boolean isPulsing(NotificationData.Entry entry) {
+ public boolean isPulsing(NotificationEntry entry) {
if (!mPulsing || mAmbientPulseManager == null) {
return false;
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationListContainer.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationListContainer.java
index 1d5b9cce099d..f771be043c07 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationListContainer.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationListContainer.java
@@ -22,8 +22,8 @@ import android.view.View;
import android.view.ViewGroup;
import com.android.systemui.plugins.statusbar.NotificationSwipeActionHelper;
-import com.android.systemui.statusbar.notification.NotificationData;
import com.android.systemui.statusbar.notification.VisibilityLocationProvider;
+import com.android.systemui.statusbar.notification.collection.NotificationEntry;
import com.android.systemui.statusbar.notification.logging.NotificationLogger;
import com.android.systemui.statusbar.notification.row.ExpandableNotificationRow;
import com.android.systemui.statusbar.notification.row.ExpandableView;
@@ -117,7 +117,7 @@ public interface NotificationListContainer extends ExpandableView.OnHeightChange
* @param entry entry to get the view parent for
* @return the view parent for entry
*/
- ViewGroup getViewParentForNotification(NotificationData.Entry entry);
+ ViewGroup getViewParentForNotification(NotificationEntry entry);
/**
* Resets the currently exposed menu view.
@@ -140,7 +140,7 @@ public interface NotificationListContainer extends ExpandableView.OnHeightChange
*
* @param entry the entry whose view's view state needs to be cleaned up (say that 5 times fast)
*/
- void cleanUpViewStateForEntry(NotificationData.Entry entry);
+ void cleanUpViewStateForEntry(NotificationEntry entry);
/**
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationRoundnessManager.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationRoundnessManager.java
index 4f0831f1043c..941860177d1b 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationRoundnessManager.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationRoundnessManager.java
@@ -18,7 +18,7 @@ package com.android.systemui.statusbar.notification.stack;
import static com.android.systemui.statusbar.notification.stack.NotificationStackScrollLayout.NUM_SECTIONS;
-import com.android.systemui.statusbar.notification.NotificationData;
+import com.android.systemui.statusbar.notification.collection.NotificationEntry;
import com.android.systemui.statusbar.notification.row.ActivatableNotificationView;
import com.android.systemui.statusbar.notification.row.ExpandableNotificationRow;
import com.android.systemui.statusbar.notification.row.ExpandableView;
@@ -49,12 +49,12 @@ class NotificationRoundnessManager implements OnHeadsUpChangedListener {
}
@Override
- public void onHeadsUpPinned(NotificationData.Entry headsUp) {
+ public void onHeadsUpPinned(NotificationEntry headsUp) {
updateView(headsUp.getRow(), false /* animate */);
}
@Override
- public void onHeadsUpUnPinned(NotificationData.Entry headsUp) {
+ public void onHeadsUpUnPinned(NotificationEntry headsUp) {
updateView(headsUp.getRow(), true /* animate */);
}
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 1248cbff5e1a..e4b00dd6d38c 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
@@ -96,13 +96,13 @@ import com.android.systemui.statusbar.StatusBarState;
import com.android.systemui.statusbar.StatusBarStateController;
import com.android.systemui.statusbar.StatusBarStateController.StateListener;
import com.android.systemui.statusbar.notification.FakeShadowView;
-import com.android.systemui.statusbar.notification.NotificationData;
import com.android.systemui.statusbar.notification.NotificationEntryListener;
import com.android.systemui.statusbar.notification.NotificationEntryManager;
import com.android.systemui.statusbar.notification.NotificationUtils;
import com.android.systemui.statusbar.notification.ShadeViewRefactor;
import com.android.systemui.statusbar.notification.ShadeViewRefactor.RefactorComponent;
import com.android.systemui.statusbar.notification.VisualStabilityManager;
+import com.android.systemui.statusbar.notification.collection.NotificationEntry;
import com.android.systemui.statusbar.notification.logging.NotificationLogger;
import com.android.systemui.statusbar.notification.row.ActivatableNotificationView;
import com.android.systemui.statusbar.notification.row.ExpandableNotificationRow;
@@ -521,7 +521,7 @@ public class NotificationStackScrollLayout extends ViewGroup implements ScrollAd
mEntryManager.addNotificationEntryListener(new NotificationEntryListener() {
@Override
- public void onEntryUpdated(NotificationData.Entry entry) {
+ public void onEntryUpdated(NotificationEntry entry) {
if (!entry.notification.isClearable()) {
// The user may have performed a dismiss action on the notification, since it's
// not clearable we should snap it back.
@@ -602,14 +602,14 @@ public class NotificationStackScrollLayout extends ViewGroup implements ScrollAd
@ShadeViewRefactor(RefactorComponent.SHADE_VIEW)
public RemoteInputController.Delegate createDelegate() {
return new RemoteInputController.Delegate() {
- public void setRemoteInputActive(NotificationData.Entry entry,
+ public void setRemoteInputActive(NotificationEntry entry,
boolean remoteInputActive) {
mHeadsUpManager.setRemoteInputActive(entry, remoteInputActive);
entry.notifyHeightChanged(true /* needsAnimation */);
updateFooter();
}
- public void lockScrollTo(NotificationData.Entry entry) {
+ public void lockScrollTo(NotificationEntry entry) {
NotificationStackScrollLayout.this.lockScrollTo(entry.getRow());
}
@@ -922,7 +922,7 @@ public class NotificationStackScrollLayout extends ViewGroup implements ScrollAd
@Override
@ShadeViewRefactor(RefactorComponent.LAYOUT_ALGORITHM)
- public boolean isInVisibleLocation(NotificationData.Entry entry) {
+ public boolean isInVisibleLocation(NotificationEntry entry) {
ExpandableNotificationRow row = entry.getRow();
ExpandableViewState childViewState = row.getViewState();
@@ -1236,13 +1236,13 @@ public class NotificationStackScrollLayout extends ViewGroup implements ScrollAd
*/
@ShadeViewRefactor(RefactorComponent.COORDINATOR)
private int getTopHeadsUpPinnedHeight() {
- NotificationData.Entry topEntry = mHeadsUpManager.getTopEntry();
+ NotificationEntry topEntry = mHeadsUpManager.getTopEntry();
if (topEntry == null) {
return 0;
}
ExpandableNotificationRow row = topEntry.getRow();
if (row.isChildInGroup()) {
- final NotificationData.Entry groupSummary
+ final NotificationEntry groupSummary
= mGroupManager.getGroupSummary(row.getStatusBarNotification());
if (groupSummary != null) {
row = groupSummary.getRow();
@@ -1417,7 +1417,7 @@ public class NotificationStackScrollLayout extends ViewGroup implements ScrollAd
&& touchY >= top && touchY <= bottom && touchX >= left && touchX <= right) {
if (slidingChild instanceof ExpandableNotificationRow) {
ExpandableNotificationRow row = (ExpandableNotificationRow) slidingChild;
- NotificationData.Entry entry = row.getEntry();
+ NotificationEntry entry = row.getEntry();
if (!mIsExpanded && row.isHeadsUp() && row.isPinned()
&& mHeadsUpManager.getTopEntry().getRow() != row
&& mGroupManager.getGroupSummary(
@@ -1551,7 +1551,7 @@ public class NotificationStackScrollLayout extends ViewGroup implements ScrollAd
}
@ShadeViewRefactor(RefactorComponent.STATE_RESOLVER)
- private void snapViewIfNeeded(NotificationData.Entry entry) {
+ private void snapViewIfNeeded(NotificationEntry entry) {
ExpandableNotificationRow child = entry.getRow();
boolean animate = mIsExpanded || isPinnedHeadsUp(child);
// If the child is showing the notification menu snap to that
@@ -1561,7 +1561,7 @@ public class NotificationStackScrollLayout extends ViewGroup implements ScrollAd
@Override
@ShadeViewRefactor(RefactorComponent.ADAPTER)
- public ViewGroup getViewParentForNotification(NotificationData.Entry entry) {
+ public ViewGroup getViewParentForNotification(NotificationEntry entry) {
return this;
}
@@ -2064,7 +2064,7 @@ public class NotificationStackScrollLayout extends ViewGroup implements ScrollAd
}
@ShadeViewRefactor(RefactorComponent.SHADE_VIEW)
- private boolean isPulsing(NotificationData.Entry entry) {
+ private boolean isPulsing(NotificationEntry entry) {
return mAmbientState.isPulsing(entry);
}
@@ -2569,7 +2569,7 @@ public class NotificationStackScrollLayout extends ViewGroup implements ScrollAd
@ShadeViewRefactor(RefactorComponent.STATE_RESOLVER)
@Override
- public void cleanUpViewStateForEntry(NotificationData.Entry entry) {
+ public void cleanUpViewStateForEntry(NotificationEntry entry) {
View child = entry.getRow();
if (child == mSwipeHelper.getTranslatingParentView()) {
mSwipeHelper.clearTranslatingParentView();
@@ -2697,7 +2697,7 @@ public class NotificationStackScrollLayout extends ViewGroup implements ScrollAd
private boolean isChildInInvisibleGroup(View child) {
if (child instanceof ExpandableNotificationRow) {
ExpandableNotificationRow row = (ExpandableNotificationRow) child;
- NotificationData.Entry groupSummary =
+ NotificationEntry groupSummary =
mGroupManager.getGroupSummary(row.getStatusBarNotification());
if (groupSummary != null && groupSummary.getRow() != row) {
return row.getVisibility() == View.INVISIBLE;
@@ -4716,7 +4716,7 @@ public class NotificationStackScrollLayout extends ViewGroup implements ScrollAd
mHeadsUpManager.setAnimationStateHandler(this::setHeadsUpGoingAwayAnimationsAllowed);
}
- public void generateHeadsUpAnimation(NotificationData.Entry entry, boolean isHeadsUp) {
+ public void generateHeadsUpAnimation(NotificationEntry entry, boolean isHeadsUp) {
ExpandableNotificationRow row = entry.getHeadsUpAnimationView();
generateHeadsUpAnimation(row, isHeadsUp);
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/HeadsUpAppearanceController.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/HeadsUpAppearanceController.java
index d1e488ab2b4d..876b9028a9b6 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/HeadsUpAppearanceController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/HeadsUpAppearanceController.java
@@ -28,7 +28,7 @@ import com.android.systemui.R;
import com.android.systemui.plugins.DarkIconDispatcher;
import com.android.systemui.statusbar.CrossFadeHelper;
import com.android.systemui.statusbar.HeadsUpStatusBarView;
-import com.android.systemui.statusbar.notification.NotificationData;
+import com.android.systemui.statusbar.notification.collection.NotificationEntry;
import com.android.systemui.statusbar.notification.row.ExpandableNotificationRow;
import com.android.systemui.statusbar.notification.stack.NotificationStackScrollLayout;
import com.android.systemui.statusbar.policy.OnHeadsUpChangedListener;
@@ -143,7 +143,7 @@ public class HeadsUpAppearanceController implements OnHeadsUpChangedListener,
}
@Override
- public void onHeadsUpPinned(NotificationData.Entry entry) {
+ public void onHeadsUpPinned(NotificationEntry entry) {
updateTopEntry();
updateHeader(entry);
}
@@ -206,11 +206,11 @@ public class HeadsUpAppearanceController implements OnHeadsUpChangedListener,
}
private void updateTopEntry() {
- NotificationData.Entry newEntry = null;
+ NotificationEntry newEntry = null;
if (!mIsExpanded && mHeadsUpManager.hasPinnedHeadsUp()) {
newEntry = mHeadsUpManager.getTopEntry();
}
- NotificationData.Entry previousEntry = mHeadsUpStatusBarView.getShowingEntry();
+ NotificationEntry previousEntry = mHeadsUpStatusBarView.getShowingEntry();
mHeadsUpStatusBarView.setEntry(newEntry);
if (newEntry != previousEntry) {
boolean animateIsolation = false;
@@ -298,7 +298,7 @@ public class HeadsUpAppearanceController implements OnHeadsUpChangedListener,
}
@Override
- public void onHeadsUpUnPinned(NotificationData.Entry entry) {
+ public void onHeadsUpUnPinned(NotificationEntry entry) {
updateTopEntry();
updateHeader(entry);
}
@@ -338,7 +338,7 @@ public class HeadsUpAppearanceController implements OnHeadsUpChangedListener,
});
}
- public void updateHeader(NotificationData.Entry entry) {
+ public void updateHeader(NotificationEntry entry) {
ExpandableNotificationRow row = entry.getRow();
float headerVisibleAmount = 1.0f;
if (row.isPinned() || row.isHeadsUpAnimatingAway() || row == mTrackedChild) {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/HeadsUpManagerPhone.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/HeadsUpManagerPhone.java
index f4cfd4197637..0fada667dd2f 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/HeadsUpManagerPhone.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/HeadsUpManagerPhone.java
@@ -41,8 +41,8 @@ import com.android.systemui.bubbles.BubbleController;
import com.android.systemui.statusbar.StatusBarState;
import com.android.systemui.statusbar.StatusBarStateController;
import com.android.systemui.statusbar.StatusBarStateController.StateListener;
-import com.android.systemui.statusbar.notification.NotificationData;
import com.android.systemui.statusbar.notification.VisualStabilityManager;
+import com.android.systemui.statusbar.notification.collection.NotificationEntry;
import com.android.systemui.statusbar.notification.row.ExpandableNotificationRow;
import com.android.systemui.statusbar.policy.ConfigurationController;
import com.android.systemui.statusbar.policy.HeadsUpManager;
@@ -72,8 +72,8 @@ public class HeadsUpManagerPhone extends HeadsUpManager implements Dumpable,
private int mDisplayCutoutTouchableRegionSize;
private boolean mTrackingHeadsUp;
private HashSet<String> mSwipedOutKeys = new HashSet<>();
- private HashSet<NotificationData.Entry> mEntriesToRemoveAfterExpand = new HashSet<>();
- private ArraySet<NotificationData.Entry> mEntriesToRemoveWhenReorderingAllowed
+ private HashSet<NotificationEntry> mEntriesToRemoveAfterExpand = new HashSet<>();
+ private ArraySet<NotificationEntry> mEntriesToRemoveWhenReorderingAllowed
= new ArraySet<>();
private boolean mIsExpanded;
private int[] mTmpTwoArray = new int[2];
@@ -187,7 +187,7 @@ public class HeadsUpManagerPhone extends HeadsUpManager implements Dumpable,
releaseAllImmediately();
mReleaseOnExpandFinish = false;
} else {
- for (NotificationData.Entry entry : mEntriesToRemoveAfterExpand) {
+ for (NotificationEntry entry : mEntriesToRemoveAfterExpand) {
if (isAlerting(entry.key)) {
// Maybe the heads-up was removed already
removeAlertEntry(entry.key);
@@ -252,7 +252,7 @@ public class HeadsUpManagerPhone extends HeadsUpManager implements Dumpable,
* @param remoteInputActive True to notify active, False to notify inactive.
*/
public void setRemoteInputActive(
- @NonNull NotificationData.Entry entry, boolean remoteInputActive) {
+ @NonNull NotificationEntry entry, boolean remoteInputActive) {
HeadsUpEntryPhone headsUpEntry = getHeadsUpEntryPhone(entry.key);
if (headsUpEntry != null && headsUpEntry.remoteInputActive != remoteInputActive) {
headsUpEntry.remoteInputActive = remoteInputActive;
@@ -268,7 +268,7 @@ public class HeadsUpManagerPhone extends HeadsUpManager implements Dumpable,
* Sets whether an entry's menu row is exposed and therefore it should stick in the heads up
* area if it's pinned until it's hidden again.
*/
- public void setMenuShown(@NonNull NotificationData.Entry entry, boolean menuShown) {
+ public void setMenuShown(@NonNull NotificationEntry entry, boolean menuShown) {
HeadsUpEntry headsUpEntry = getHeadsUpEntry(entry.key);
if (headsUpEntry instanceof HeadsUpEntryPhone && entry.isRowPinned()) {
((HeadsUpEntryPhone) headsUpEntry).setMenuShownPinned(menuShown);
@@ -315,9 +315,9 @@ public class HeadsUpManagerPhone extends HeadsUpManager implements Dumpable,
return;
}
if (hasPinnedHeadsUp()) {
- NotificationData.Entry topEntry = getTopEntry();
+ NotificationEntry topEntry = getTopEntry();
if (topEntry.isChildInGroup()) {
- final NotificationData.Entry groupSummary
+ final NotificationEntry groupSummary
= mGroupManager.getGroupSummary(topEntry.notification);
if (groupSummary != null) {
topEntry = groupSummary;
@@ -374,7 +374,7 @@ public class HeadsUpManagerPhone extends HeadsUpManager implements Dumpable,
@Override
public void onReorderingAllowed() {
mAnimationStateHandler.setHeadsUpGoingAwayAnimationsAllowed(false);
- for (NotificationData.Entry entry : mEntriesToRemoveWhenReorderingAllowed) {
+ for (NotificationEntry entry : mEntriesToRemoveWhenReorderingAllowed) {
if (isAlerting(entry.key)) {
// Maybe the heads-up was removed already
removeAlertEntry(entry.key);
@@ -399,7 +399,7 @@ public class HeadsUpManagerPhone extends HeadsUpManager implements Dumpable,
}
@Override
- protected boolean shouldHeadsUpBecomePinned(NotificationData.Entry entry) {
+ protected boolean shouldHeadsUpBecomePinned(NotificationEntry entry) {
return mStatusBarState != StatusBarState.KEYGUARD && !mIsExpanded
|| super.shouldHeadsUpBecomePinned(entry);
}
@@ -488,7 +488,7 @@ public class HeadsUpManagerPhone extends HeadsUpManager implements Dumpable,
return super.isSticky() || mMenuShownPinned;
}
- public void setEntry(@NonNull final NotificationData.Entry entry) {
+ public void setEntry(@NonNull final NotificationEntry entry) {
Runnable removeHeadsUpRunnable = () -> {
if (!mVisualStabilityManager.isReorderingAllowed()) {
mEntriesToRemoveWhenReorderingAllowed.add(entry);
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/HeadsUpTouchHelper.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/HeadsUpTouchHelper.java
index 9c1c71a2dec8..dd200da56d20 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/HeadsUpTouchHelper.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/HeadsUpTouchHelper.java
@@ -21,7 +21,7 @@ import android.view.MotionEvent;
import android.view.ViewConfiguration;
import com.android.systemui.Gefingerpoken;
-import com.android.systemui.statusbar.notification.NotificationData;
+import com.android.systemui.statusbar.notification.collection.NotificationEntry;
import com.android.systemui.statusbar.notification.row.ExpandableNotificationRow;
import com.android.systemui.statusbar.notification.row.ExpandableView;
@@ -83,7 +83,7 @@ public class HeadsUpTouchHelper implements Gefingerpoken {
} else if (child == null && !mCallback.isExpanded()) {
// We might touch above the visible heads up child, but then we still would
// like to capture it.
- NotificationData.Entry topEntry = mHeadsUpManager.getTopEntry();
+ NotificationEntry topEntry = mHeadsUpManager.getTopEntry();
if (topEntry != null && topEntry.isRowPinned()) {
mPickedChild = topEntry.getRow();
mTouchingHeadsUpView = true;
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardEnvironmentImpl.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardEnvironmentImpl.java
index 927228eae20e..925a19d6f5eb 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardEnvironmentImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardEnvironmentImpl.java
@@ -22,7 +22,7 @@ import android.util.Log;
import com.android.systemui.Dependency;
import com.android.systemui.statusbar.NotificationLockscreenUserManager;
-import com.android.systemui.statusbar.notification.NotificationData.KeyguardEnvironment;
+import com.android.systemui.statusbar.notification.collection.NotificationData.KeyguardEnvironment;
import com.android.systemui.statusbar.policy.DeviceProvisionedController;
public class KeyguardEnvironmentImpl implements KeyguardEnvironment {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationGroupAlertTransferHelper.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationGroupAlertTransferHelper.java
index af3257ae423e..d364356b19fe 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationGroupAlertTransferHelper.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationGroupAlertTransferHelper.java
@@ -31,9 +31,9 @@ import com.android.systemui.statusbar.AmbientPulseManager.OnAmbientChangedListen
import com.android.systemui.statusbar.InflationTask;
import com.android.systemui.statusbar.StatusBarStateController;
import com.android.systemui.statusbar.StatusBarStateController.StateListener;
-import com.android.systemui.statusbar.notification.NotificationData.Entry;
import com.android.systemui.statusbar.notification.NotificationEntryListener;
import com.android.systemui.statusbar.notification.NotificationEntryManager;
+import com.android.systemui.statusbar.notification.collection.NotificationEntry;
import com.android.systemui.statusbar.notification.row.NotificationInflater.AsyncInflationTask;
import com.android.systemui.statusbar.notification.row.NotificationInflater.InflationFlag;
import com.android.systemui.statusbar.phone.NotificationGroupManager.NotificationGroup;
@@ -108,7 +108,7 @@ public class NotificationGroupAlertTransferHelper implements OnHeadsUpChangedLis
* @param entry notification to check
* @return true if the entry was transferred to and should inflate + alert
*/
- public boolean isAlertTransferPending(@NonNull Entry entry) {
+ public boolean isAlertTransferPending(@NonNull NotificationEntry entry) {
PendingAlertInfo alertInfo = mPendingAlerts.get(entry.key);
return alertInfo != null && alertInfo.isStillValid();
}
@@ -172,16 +172,16 @@ public class NotificationGroupAlertTransferHelper implements OnHeadsUpChangedLis
};
@Override
- public void onAmbientStateChanged(Entry entry, boolean isAmbient) {
+ public void onAmbientStateChanged(NotificationEntry entry, boolean isAmbient) {
onAlertStateChanged(entry, isAmbient, mAmbientPulseManager);
}
@Override
- public void onHeadsUpStateChanged(Entry entry, boolean isHeadsUp) {
+ public void onHeadsUpStateChanged(NotificationEntry entry, boolean isHeadsUp) {
onAlertStateChanged(entry, isHeadsUp, mHeadsUpManager);
}
- private void onAlertStateChanged(Entry entry, boolean isAlerting,
+ private void onAlertStateChanged(NotificationEntry entry, boolean isAlerting,
AlertingNotificationManager alertManager) {
if (isAlerting && mGroupManager.isSummaryOfSuppressedGroup(entry.notification)) {
handleSuppressedSummaryAlerted(entry, alertManager);
@@ -193,7 +193,7 @@ public class NotificationGroupAlertTransferHelper implements OnHeadsUpChangedLis
// Called when a new notification has been posted but is not inflated yet. We use this to
// see as early as we can if we need to abort a transfer.
@Override
- public void onPendingEntryAdded(Entry entry) {
+ public void onPendingEntryAdded(NotificationEntry entry) {
String groupKey = mGroupManager.getGroupKey(entry.notification);
GroupAlertEntry groupAlertEntry = mGroupAlertEntries.get(groupKey);
if (groupAlertEntry != null) {
@@ -204,7 +204,7 @@ public class NotificationGroupAlertTransferHelper implements OnHeadsUpChangedLis
// Called when the entry's reinflation has finished. If there is an alert pending, we
// then show the alert.
@Override
- public void onEntryReinflated(Entry entry) {
+ public void onEntryReinflated(NotificationEntry entry) {
PendingAlertInfo alertInfo = mPendingAlerts.remove(entry.key);
if (alertInfo != null) {
if (alertInfo.isStillValid()) {
@@ -219,7 +219,7 @@ public class NotificationGroupAlertTransferHelper implements OnHeadsUpChangedLis
@Override
public void onEntryRemoved(
- @Nullable Entry entry,
+ @Nullable NotificationEntry entry,
NotificationVisibility visibility,
boolean removedByUser) {
// Removes any alerts pending on this entry. Note that this will not stop any inflation
@@ -241,8 +241,8 @@ public class NotificationGroupAlertTransferHelper implements OnHeadsUpChangedLis
return 0;
}
int number = 0;
- Iterable<Entry> values = mEntryManager.getPendingNotificationsIterator();
- for (Entry entry : values) {
+ Iterable<NotificationEntry> values = mEntryManager.getPendingNotificationsIterator();
+ for (NotificationEntry entry : values) {
if (isPendingNotificationInGroup(entry, group) && onlySummaryAlerts(entry)) {
number++;
}
@@ -260,8 +260,8 @@ public class NotificationGroupAlertTransferHelper implements OnHeadsUpChangedLis
if (mEntryManager == null) {
return false;
}
- Iterable<Entry> values = mEntryManager.getPendingNotificationsIterator();
- for (Entry entry : values) {
+ Iterable<NotificationEntry> values = mEntryManager.getPendingNotificationsIterator();
+ for (NotificationEntry entry : values) {
if (isPendingNotificationInGroup(entry, group)) {
return true;
}
@@ -276,7 +276,7 @@ public class NotificationGroupAlertTransferHelper implements OnHeadsUpChangedLis
* @param group group to check
* @return true if the notification will add to the group, false o/w
*/
- private boolean isPendingNotificationInGroup(@NonNull Entry entry,
+ private boolean isPendingNotificationInGroup(@NonNull NotificationEntry entry,
@NonNull NotificationGroup group) {
String groupKey = mGroupManager.getGroupKey(group.summary.notification);
return mGroupManager.isGroupChild(entry.notification)
@@ -293,7 +293,7 @@ public class NotificationGroupAlertTransferHelper implements OnHeadsUpChangedLis
* @param summary the summary that is suppressed and alerting
* @param alertManager the alert manager that manages the alerting summary
*/
- private void handleSuppressedSummaryAlerted(@NonNull Entry summary,
+ private void handleSuppressedSummaryAlerted(@NonNull NotificationEntry summary,
@NonNull AlertingNotificationManager alertManager) {
StatusBarNotification sbn = summary.notification;
GroupAlertEntry groupAlertEntry =
@@ -309,7 +309,7 @@ public class NotificationGroupAlertTransferHelper implements OnHeadsUpChangedLis
return;
}
- Entry child = mGroupManager.getLogicalChildren(summary.notification).iterator().next();
+ NotificationEntry child = mGroupManager.getLogicalChildren(summary.notification).iterator().next();
if (child != null) {
if (child.getRow().keepInParent()
|| child.isRowRemoved()
@@ -333,7 +333,7 @@ public class NotificationGroupAlertTransferHelper implements OnHeadsUpChangedLis
* @param toEntry entry to transfer to
* @param alertManager alert manager for the alert type
*/
- private void transferAlertState(@NonNull Entry fromEntry, @NonNull Entry toEntry,
+ private void transferAlertState(@NonNull NotificationEntry fromEntry, @NonNull NotificationEntry toEntry,
@NonNull AlertingNotificationManager alertManager) {
alertManager.removeNotification(fromEntry.key, true /* releaseImmediately */);
alertNotificationWhenPossible(toEntry, alertManager);
@@ -353,13 +353,13 @@ public class NotificationGroupAlertTransferHelper implements OnHeadsUpChangedLis
private void checkShouldTransferBack(@NonNull GroupAlertEntry groupAlertEntry) {
if (SystemClock.elapsedRealtime() - groupAlertEntry.mLastAlertTransferTime
< ALERT_TRANSFER_TIMEOUT) {
- Entry summary = groupAlertEntry.mGroup.summary;
+ NotificationEntry summary = groupAlertEntry.mGroup.summary;
AlertingNotificationManager alertManager = getActiveAlertManager();
if (!onlySummaryAlerts(summary)) {
return;
}
- ArrayList<Entry> children = mGroupManager.getLogicalChildren(summary.notification);
+ ArrayList<NotificationEntry> children = mGroupManager.getLogicalChildren(summary.notification);
int numChildren = children.size();
int numPendingChildren = getPendingChildrenNotAlerting(groupAlertEntry.mGroup);
numChildren += numPendingChildren;
@@ -368,7 +368,7 @@ public class NotificationGroupAlertTransferHelper implements OnHeadsUpChangedLis
}
boolean releasedChild = false;
for (int i = 0; i < children.size(); i++) {
- Entry entry = children.get(i);
+ NotificationEntry entry = children.get(i);
if (onlySummaryAlerts(entry) && alertManager.isAlerting(entry.key)) {
releasedChild = true;
alertManager.removeNotification(entry.key, true /* releaseImmediately */);
@@ -399,7 +399,7 @@ public class NotificationGroupAlertTransferHelper implements OnHeadsUpChangedLis
* @param entry entry to show
* @param alertManager alert manager for the alert type
*/
- private void alertNotificationWhenPossible(@NonNull Entry entry,
+ private void alertNotificationWhenPossible(@NonNull NotificationEntry entry,
@NonNull AlertingNotificationManager alertManager) {
@InflationFlag int contentFlag = alertManager.getContentFlag();
if (!entry.getRow().isInflationFlagSet(contentFlag)) {
@@ -419,7 +419,7 @@ public class NotificationGroupAlertTransferHelper implements OnHeadsUpChangedLis
return mIsDozing ? mAmbientPulseManager : mHeadsUpManager;
}
- private boolean onlySummaryAlerts(Entry entry) {
+ private boolean onlySummaryAlerts(NotificationEntry entry) {
return entry.notification.getNotification().getGroupAlertBehavior()
== Notification.GROUP_ALERT_SUMMARY;
}
@@ -439,7 +439,7 @@ public class NotificationGroupAlertTransferHelper implements OnHeadsUpChangedLis
* the transfer is still valid if the notification is updated.
*/
final StatusBarNotification mOriginalNotification;
- final Entry mEntry;
+ final NotificationEntry mEntry;
/**
* The notification is still pending inflation but we've decided that we no longer need
@@ -450,7 +450,7 @@ public class NotificationGroupAlertTransferHelper implements OnHeadsUpChangedLis
*/
boolean mAbortOnInflation;
- PendingAlertInfo(Entry entry, AlertingNotificationManager alertManager) {
+ PendingAlertInfo(NotificationEntry entry, AlertingNotificationManager alertManager) {
mOriginalNotification = entry.notification;
mEntry = entry;
mAlertManager = alertManager;
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationGroupManager.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationGroupManager.java
index 3c1c0765a3b8..bb9e4183ba76 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationGroupManager.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationGroupManager.java
@@ -27,7 +27,7 @@ import com.android.systemui.statusbar.AmbientPulseManager.OnAmbientChangedListen
import com.android.systemui.statusbar.StatusBarState;
import com.android.systemui.statusbar.StatusBarStateController;
import com.android.systemui.statusbar.StatusBarStateController.StateListener;
-import com.android.systemui.statusbar.notification.NotificationData;
+import com.android.systemui.statusbar.notification.collection.NotificationEntry;
import com.android.systemui.statusbar.notification.row.ExpandableNotificationRow;
import com.android.systemui.statusbar.policy.HeadsUpManager;
import com.android.systemui.statusbar.policy.OnHeadsUpChangedListener;
@@ -97,7 +97,7 @@ public class NotificationGroupManager implements OnHeadsUpChangedListener,
}
}
- public void onEntryRemoved(NotificationData.Entry removed) {
+ public void onEntryRemoved(NotificationEntry removed) {
onEntryRemovedInternal(removed, removed.notification);
mIsolatedEntries.remove(removed.key);
}
@@ -109,7 +109,7 @@ public class NotificationGroupManager implements OnHeadsUpChangedListener,
* @param sbn the notification the entry has, which doesn't need to be the same as it's internal
* notification
*/
- private void onEntryRemovedInternal(NotificationData.Entry removed,
+ private void onEntryRemovedInternal(NotificationEntry removed,
final StatusBarNotification sbn) {
String groupKey = getGroupKey(sbn);
final NotificationGroup group = mGroupMap.get(groupKey);
@@ -136,7 +136,7 @@ public class NotificationGroupManager implements OnHeadsUpChangedListener,
}
}
- public void onEntryAdded(final NotificationData.Entry added) {
+ public void onEntryAdded(final NotificationEntry added) {
if (added.isRowRemoved()) {
added.setDebugThrowable(new Throwable());
}
@@ -152,7 +152,7 @@ public class NotificationGroupManager implements OnHeadsUpChangedListener,
}
}
if (isGroupChild) {
- NotificationData.Entry existing = group.children.get(added.key);
+ NotificationEntry existing = group.children.get(added.key);
if (existing != null && existing != added) {
Throwable existingThrowable = existing.getDebugThrowable();
Log.wtf(TAG, "Inconsistent entries found with the same key " + added.key
@@ -169,9 +169,9 @@ public class NotificationGroupManager implements OnHeadsUpChangedListener,
group.expanded = added.areChildrenExpanded();
updateSuppression(group);
if (!group.children.isEmpty()) {
- ArrayList<NotificationData.Entry> childrenCopy
+ ArrayList<NotificationEntry> childrenCopy
= new ArrayList<>(group.children.values());
- for (NotificationData.Entry child : childrenCopy) {
+ for (NotificationEntry child : childrenCopy) {
onEntryBecomingChild(child);
}
for (OnGroupChangeListener listener : mListeners) {
@@ -181,7 +181,7 @@ public class NotificationGroupManager implements OnHeadsUpChangedListener,
}
}
- private void onEntryBecomingChild(NotificationData.Entry entry) {
+ private void onEntryBecomingChild(NotificationEntry entry) {
if (shouldIsolate(entry)) {
isolateNotification(entry);
}
@@ -221,7 +221,7 @@ public class NotificationGroupManager implements OnHeadsUpChangedListener,
return count;
}
- private NotificationData.Entry getIsolatedChild(String groupKey) {
+ private NotificationEntry getIsolatedChild(String groupKey) {
for (StatusBarNotification sbn : mIsolatedEntries.values()) {
if (sbn.getGroupKey().equals(groupKey) && isIsolated(sbn)) {
return mGroupMap.get(sbn.getKey()).summary;
@@ -230,7 +230,7 @@ public class NotificationGroupManager implements OnHeadsUpChangedListener,
return null;
}
- public void onEntryUpdated(NotificationData.Entry entry,
+ public void onEntryUpdated(NotificationEntry entry,
StatusBarNotification oldNotification) {
String oldKey = oldNotification.getGroupKey();
String newKey = entry.notification.getGroupKey();
@@ -267,7 +267,7 @@ public class NotificationGroupManager implements OnHeadsUpChangedListener,
if (!isOnlyChild(sbn)) {
return false;
}
- NotificationData.Entry logicalGroupSummary = getLogicalGroupSummary(sbn);
+ NotificationEntry logicalGroupSummary = getLogicalGroupSummary(sbn);
return logicalGroupSummary != null
&& !logicalGroupSummary.notification.equals(sbn);
}
@@ -343,7 +343,7 @@ public class NotificationGroupManager implements OnHeadsUpChangedListener,
* Get the summary of a specified status bar notification. For isolated notification this return
* itself.
*/
- public NotificationData.Entry getGroupSummary(StatusBarNotification sbn) {
+ public NotificationEntry getGroupSummary(StatusBarNotification sbn) {
return getGroupSummary(getGroupKey(sbn));
}
@@ -352,12 +352,12 @@ public class NotificationGroupManager implements OnHeadsUpChangedListener,
* but the logical summary, i.e when a child is isolated, it still returns the summary as if
* it wasn't isolated.
*/
- public NotificationData.Entry getLogicalGroupSummary(StatusBarNotification sbn) {
+ public NotificationEntry getLogicalGroupSummary(StatusBarNotification sbn) {
return getGroupSummary(sbn.getGroupKey());
}
@Nullable
- private NotificationData.Entry getGroupSummary(String groupKey) {
+ private NotificationEntry getGroupSummary(String groupKey) {
NotificationGroup group = mGroupMap.get(groupKey);
//TODO: see if this can become an Entry
return group == null ? null
@@ -371,13 +371,13 @@ public class NotificationGroupManager implements OnHeadsUpChangedListener,
* @param summary summary of a group
* @return list of the children
*/
- public ArrayList<NotificationData.Entry> getLogicalChildren(StatusBarNotification summary) {
+ public ArrayList<NotificationEntry> getLogicalChildren(StatusBarNotification summary) {
NotificationGroup group = mGroupMap.get(summary.getGroupKey());
if (group == null) {
return null;
}
- ArrayList<NotificationData.Entry> children = new ArrayList<>(group.children.values());
- NotificationData.Entry isolatedChild = getIsolatedChild(summary.getGroupKey());
+ ArrayList<NotificationEntry> children = new ArrayList<>(group.children.values());
+ NotificationEntry isolatedChild = getIsolatedChild(summary.getGroupKey());
if (isolatedChild != null) {
children.add(isolatedChild);
}
@@ -443,24 +443,24 @@ public class NotificationGroupManager implements OnHeadsUpChangedListener,
}
@Override
- public void onHeadsUpPinned(NotificationData.Entry entry) {
+ public void onHeadsUpPinned(NotificationEntry entry) {
}
@Override
- public void onHeadsUpUnPinned(NotificationData.Entry entry) {
+ public void onHeadsUpUnPinned(NotificationEntry entry) {
}
@Override
- public void onAmbientStateChanged(NotificationData.Entry entry, boolean isAmbient) {
+ public void onAmbientStateChanged(NotificationEntry entry, boolean isAmbient) {
onAlertStateChanged(entry, isAmbient);
}
@Override
- public void onHeadsUpStateChanged(NotificationData.Entry entry, boolean isHeadsUp) {
+ public void onHeadsUpStateChanged(NotificationEntry entry, boolean isHeadsUp) {
onAlertStateChanged(entry, isHeadsUp);
}
- private void onAlertStateChanged(NotificationData.Entry entry, boolean isAlerting) {
+ private void onAlertStateChanged(NotificationEntry entry, boolean isAlerting) {
if (isAlerting) {
if (shouldIsolate(entry)) {
isolateNotification(entry);
@@ -479,7 +479,7 @@ public class NotificationGroupManager implements OnHeadsUpChangedListener,
* @return true if the entry should be isolated
*/
- private boolean shouldIsolate(NotificationData.Entry entry) {
+ private boolean shouldIsolate(NotificationEntry entry) {
StatusBarNotification sbn = entry.notification;
NotificationGroup notificationGroup = mGroupMap.get(sbn.getGroupKey());
if (!sbn.isGroup() || sbn.getNotification().isGroupSummary()) {
@@ -499,7 +499,7 @@ public class NotificationGroupManager implements OnHeadsUpChangedListener,
*
* @param entry the notification to isolate
*/
- private void isolateNotification(NotificationData.Entry entry) {
+ private void isolateNotification(NotificationEntry entry) {
StatusBarNotification sbn = entry.notification;
// We will be isolated now, so lets update the groups
@@ -523,7 +523,7 @@ public class NotificationGroupManager implements OnHeadsUpChangedListener,
*
* @param entry the notification to un-isolate
*/
- private void stopIsolatingNotification(NotificationData.Entry entry) {
+ private void stopIsolatingNotification(NotificationEntry entry) {
StatusBarNotification sbn = entry.notification;
if (mIsolatedEntries.containsKey(sbn.getKey())) {
// not isolated anymore, we need to update the groups
@@ -564,8 +564,8 @@ public class NotificationGroupManager implements OnHeadsUpChangedListener,
}
public static class NotificationGroup {
- public final HashMap<String, NotificationData.Entry> children = new HashMap<>();
- public NotificationData.Entry summary;
+ public final HashMap<String, NotificationEntry> children = new HashMap<>();
+ public NotificationEntry summary;
public boolean expanded;
/**
* Is this notification group suppressed, i.e its summary is hidden
@@ -580,7 +580,7 @@ public class NotificationGroupManager implements OnHeadsUpChangedListener,
? Log.getStackTraceString(summary.getDebugThrowable())
: "");
result += "\n children size: " + children.size();
- for (NotificationData.Entry child : children.values()) {
+ for (NotificationEntry child : children.values()) {
result += "\n " + child.notification
+ (child.getDebugThrowable() != null
? Log.getStackTraceString(child.getDebugThrowable())
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationIconAreaController.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationIconAreaController.java
index 056c8a7f5f5e..1fb5484196ae 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationIconAreaController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationIconAreaController.java
@@ -23,9 +23,9 @@ import com.android.systemui.plugins.DarkIconDispatcher;
import com.android.systemui.plugins.DarkIconDispatcher.DarkReceiver;
import com.android.systemui.statusbar.NotificationShelf;
import com.android.systemui.statusbar.StatusBarIconView;
-import com.android.systemui.statusbar.notification.NotificationData;
import com.android.systemui.statusbar.notification.NotificationEntryManager;
import com.android.systemui.statusbar.notification.NotificationUtils;
+import com.android.systemui.statusbar.notification.collection.NotificationEntry;
import com.android.systemui.statusbar.notification.row.ExpandableNotificationRow;
import com.android.systemui.tuner.TunerService;
@@ -182,7 +182,7 @@ public class NotificationIconAreaController implements DarkReceiver {
return mStatusBar.getStatusBarHeight();
}
- protected boolean shouldShowNotificationIcon(NotificationData.Entry entry,
+ protected boolean shouldShowNotificationIcon(NotificationEntry entry,
boolean showAmbient, boolean showLowPriority, boolean hideDismissed,
boolean hideRepliedMessages) {
if (mEntryManager.getNotificationData().isAmbient(entry.key) && !showAmbient) {
@@ -247,7 +247,7 @@ public class NotificationIconAreaController implements DarkReceiver {
* @param hideDismissed should dismissed icons be hidden
* @param hideRepliedMessages should messages that have been replied to be hidden
*/
- private void updateIconsForLayout(Function<NotificationData.Entry, StatusBarIconView> function,
+ private void updateIconsForLayout(Function<NotificationEntry, StatusBarIconView> function,
NotificationIconContainer hostLayout, boolean showAmbient, boolean showLowPriority,
boolean hideDismissed, boolean hideRepliedMessages) {
ArrayList<StatusBarIconView> toShow = new ArrayList<>(
@@ -257,7 +257,7 @@ public class NotificationIconAreaController implements DarkReceiver {
for (int i = 0; i < mNotificationScrollLayout.getChildCount(); i++) {
View view = mNotificationScrollLayout.getChildAt(i);
if (view instanceof ExpandableNotificationRow) {
- NotificationData.Entry ent = ((ExpandableNotificationRow) view).getEntry();
+ NotificationEntry ent = ((ExpandableNotificationRow) view).getEntry();
if (shouldShowNotificationIcon(ent, showAmbient, showLowPriority, hideDismissed,
hideRepliedMessages)) {
toShow.add(function.apply(ent));
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelView.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelView.java
index 16576ad6e3e1..d873b0cd1f26 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelView.java
@@ -76,9 +76,9 @@ import com.android.systemui.statusbar.StatusBarStateController;
import com.android.systemui.statusbar.StatusBarStateController.StateListener;
import com.android.systemui.statusbar.notification.ActivityLaunchAnimator;
import com.android.systemui.statusbar.notification.AnimatableProperty;
-import com.android.systemui.statusbar.notification.NotificationData;
import com.android.systemui.statusbar.notification.NotificationEntryManager;
import com.android.systemui.statusbar.notification.PropertyAnimator;
+import com.android.systemui.statusbar.notification.collection.NotificationEntry;
import com.android.systemui.statusbar.notification.row.ActivatableNotificationView;
import com.android.systemui.statusbar.notification.row.ExpandableNotificationRow;
import com.android.systemui.statusbar.notification.row.ExpandableView;
@@ -2489,12 +2489,12 @@ public class NotificationPanelView extends PanelView implements
}
@Override
- public void onHeadsUpPinned(NotificationData.Entry entry) {
+ public void onHeadsUpPinned(NotificationEntry entry) {
mNotificationStackScroller.generateHeadsUpAnimation(entry.getHeadsUpAnimationView(), true);
}
@Override
- public void onHeadsUpUnPinned(NotificationData.Entry entry) {
+ public void onHeadsUpUnPinned(NotificationEntry entry) {
// When we're unpinning the notification via active edge they remain heads-upped,
// we need to make sure that an animation happens in this case, otherwise the notification
@@ -2507,7 +2507,7 @@ public class NotificationPanelView extends PanelView implements
}
@Override
- public void onHeadsUpStateChanged(NotificationData.Entry entry, boolean isHeadsUp) {
+ public void onHeadsUpStateChanged(NotificationEntry entry, boolean isHeadsUp) {
mNotificationStackScroller.generateHeadsUpAnimation(entry, isHeadsUp);
}
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 977e33688831..6d78f7204163 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBar.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBar.java
@@ -192,12 +192,11 @@ import com.android.systemui.statusbar.notification.ActivityLaunchAnimator;
import com.android.systemui.statusbar.notification.NotificationActivityStarter;
import com.android.systemui.statusbar.notification.NotificationAlertingManager;
import com.android.systemui.statusbar.notification.NotificationClicker;
-import com.android.systemui.statusbar.notification.NotificationData;
-import com.android.systemui.statusbar.notification.NotificationData.Entry;
import com.android.systemui.statusbar.notification.NotificationEntryManager;
import com.android.systemui.statusbar.notification.NotificationInterruptionStateProvider;
import com.android.systemui.statusbar.notification.NotificationRowBinder;
import com.android.systemui.statusbar.notification.VisualStabilityManager;
+import com.android.systemui.statusbar.notification.collection.NotificationEntry;
import com.android.systemui.statusbar.notification.logging.NotificationLogger;
import com.android.systemui.statusbar.notification.row.ExpandableNotificationRow;
import com.android.systemui.statusbar.notification.row.NotificationGutsManager;
@@ -489,7 +488,7 @@ public class StatusBar extends SystemUI implements DemoMode,
private Runnable mLaunchTransitionEndRunnable;
protected boolean mLaunchTransitionFadingAway;
- private NotificationData.Entry mDraggedDownEntry;
+ private NotificationEntry mDraggedDownEntry;
private boolean mLaunchCameraOnScreenTurningOn;
private boolean mLaunchCameraOnFinishedGoingToSleep;
private int mLastCameraLaunchSource;
@@ -633,7 +632,7 @@ public class StatusBar extends SystemUI implements DemoMode,
mBubbleController.setExpandListener(mBubbleExpandListener);
KeyguardSliceProvider sliceProvider = KeyguardSliceProvider.getAttachedInstance();
if (sliceProvider != null) {
- sliceProvider.initDependencies();
+ sliceProvider.initDependencies(mMediaManager, mStatusBarStateController);
} else {
Log.w(TAG, "Cannot init KeyguardSliceProvider dependencies");
}
@@ -1510,21 +1509,21 @@ public class StatusBar extends SystemUI implements DemoMode,
}
@Override
- public void onHeadsUpPinned(NotificationData.Entry entry) {
+ public void onHeadsUpPinned(NotificationEntry entry) {
dismissVolumeDialog();
}
@Override
- public void onHeadsUpUnPinned(NotificationData.Entry entry) {
+ public void onHeadsUpUnPinned(NotificationEntry entry) {
}
@Override
- public void onHeadsUpStateChanged(Entry entry, boolean isHeadsUp) {
+ public void onHeadsUpStateChanged(NotificationEntry entry, boolean isHeadsUp) {
mEntryManager.updateNotificationRanking(null /* rankingMap */);
}
@Override
- public void onAmbientStateChanged(Entry entry, boolean isAmbient) {
+ public void onAmbientStateChanged(NotificationEntry entry, boolean isAmbient) {
mEntryManager.updateNotificationRanking(null);
if (isAmbient) {
mDozeServiceHost.fireNotificationPulse();
@@ -2551,11 +2550,11 @@ public class StatusBar extends SystemUI implements DemoMode,
};
public void resetUserExpandedStates() {
- ArrayList<Entry> activeNotifications = mEntryManager.getNotificationData()
+ ArrayList<NotificationEntry> activeNotifications = mEntryManager.getNotificationData()
.getActiveNotifications();
final int notificationCount = activeNotifications.size();
for (int i = 0; i < notificationCount; i++) {
- NotificationData.Entry entry = activeNotifications.get(i);
+ NotificationEntry entry = activeNotifications.get(i);
entry.resetUserExpansion();
}
}
@@ -3506,7 +3505,7 @@ public class StatusBar extends SystemUI implements DemoMode,
int userId = mLockscreenUserManager.getCurrentUserId();
ExpandableNotificationRow row = null;
- NotificationData.Entry entry = null;
+ NotificationEntry entry = null;
if (expandView instanceof ExpandableNotificationRow) {
entry = ((ExpandableNotificationRow) expandView).getEntry();
entry.setUserExpanded(true /* userExpanded */, true /* allowChildExpansion */);
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarNotificationActivityStarter.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarNotificationActivityStarter.java
index 8d1b911b101f..4f61009095c7 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarNotificationActivityStarter.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarNotificationActivityStarter.java
@@ -60,10 +60,10 @@ import com.android.systemui.statusbar.StatusBarState;
import com.android.systemui.statusbar.StatusBarStateController;
import com.android.systemui.statusbar.notification.ActivityLaunchAnimator;
import com.android.systemui.statusbar.notification.NotificationActivityStarter;
-import com.android.systemui.statusbar.notification.NotificationData;
import com.android.systemui.statusbar.notification.NotificationEntryListener;
import com.android.systemui.statusbar.notification.NotificationEntryManager;
import com.android.systemui.statusbar.notification.NotificationInterruptionStateProvider;
+import com.android.systemui.statusbar.notification.collection.NotificationEntry;
import com.android.systemui.statusbar.notification.row.ExpandableNotificationRow;
import com.android.systemui.statusbar.policy.HeadsUpUtil;
import com.android.systemui.statusbar.policy.KeyguardMonitor;
@@ -131,7 +131,7 @@ public class StatusBarNotificationActivityStarter implements NotificationActivit
mEntryManager.addNotificationEntryListener(new NotificationEntryListener() {
@Override
- public void onPendingEntryAdded(NotificationData.Entry entry) {
+ public void onPendingEntryAdded(NotificationEntry entry) {
handleFullScreenIntent(entry);
}
});
@@ -267,7 +267,7 @@ public class StatusBarNotificationActivityStarter implements NotificationActivit
}
}
Intent fillInIntent = null;
- NotificationData.Entry entry = row.getEntry();
+ NotificationEntry entry = row.getEntry();
CharSequence remoteInputText = null;
if (!TextUtils.isEmpty(entry.remoteInputText)) {
remoteInputText = entry.remoteInputText;
@@ -345,7 +345,7 @@ public class StatusBarNotificationActivityStarter implements NotificationActivit
}, null, false /* afterKeyguardGone */);
}
- private void handleFullScreenIntent(NotificationData.Entry entry) {
+ private void handleFullScreenIntent(NotificationEntry entry) {
boolean isHeadsUped = mNotificationInterruptionStateProvider.shouldHeadsUp(entry);
if (!isHeadsUped && entry.notification.getNotification().fullScreenIntent != null) {
if (shouldSuppressFullScreenIntent(entry)) {
@@ -413,7 +413,7 @@ public class StatusBarNotificationActivityStarter implements NotificationActivit
|| !mActivityLaunchAnimator.isAnimationPending();
}
- private boolean shouldSuppressFullScreenIntent(NotificationData.Entry entry) {
+ private boolean shouldSuppressFullScreenIntent(NotificationEntry entry) {
if (mPresenter.isDeviceInVrMode()) {
return true;
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarNotificationPresenter.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarNotificationPresenter.java
index fb3157a128d6..16c8e6232b00 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarNotificationPresenter.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarNotificationPresenter.java
@@ -60,12 +60,12 @@ import com.android.systemui.statusbar.StatusBarStateController;
import com.android.systemui.statusbar.notification.AboveShelfObserver;
import com.android.systemui.statusbar.notification.ActivityLaunchAnimator;
import com.android.systemui.statusbar.notification.NotificationAlertingManager;
-import com.android.systemui.statusbar.notification.NotificationData.Entry;
import com.android.systemui.statusbar.notification.NotificationEntryListener;
import com.android.systemui.statusbar.notification.NotificationEntryManager;
import com.android.systemui.statusbar.notification.NotificationInterruptionStateProvider;
import com.android.systemui.statusbar.notification.NotificationRowBinder;
import com.android.systemui.statusbar.notification.VisualStabilityManager;
+import com.android.systemui.statusbar.notification.collection.NotificationEntry;
import com.android.systemui.statusbar.notification.row.ActivatableNotificationView;
import com.android.systemui.statusbar.notification.row.ExpandableNotificationRow;
import com.android.systemui.statusbar.notification.row.NotificationGutsManager;
@@ -183,19 +183,19 @@ public class StatusBarNotificationPresenter implements NotificationPresenter,
Dependency.get(InitController.class).addPostInitTask(() -> {
NotificationEntryListener notificationEntryListener = new NotificationEntryListener() {
@Override
- public void onNotificationAdded(Entry entry) {
+ public void onNotificationAdded(NotificationEntry entry) {
// Recalculate the position of the sliding windows and the titles.
mShadeController.updateAreThereNotifications();
}
@Override
- public void onEntryUpdated(Entry entry) {
+ public void onEntryUpdated(NotificationEntry entry) {
mShadeController.updateAreThereNotifications();
}
@Override
public void onEntryRemoved(
- @Nullable Entry entry,
+ @Nullable NotificationEntry entry,
NotificationVisibility visibility,
boolean removedByUser) {
StatusBarNotificationPresenter.this.onNotificationRemoved(
@@ -258,10 +258,10 @@ public class StatusBarNotificationPresenter implements NotificationPresenter,
}
private void updateNotificationOnUiModeChanged() {
- ArrayList<Entry> userNotifications
+ ArrayList<NotificationEntry> userNotifications
= mEntryManager.getNotificationData().getNotificationsForCurrentUser();
for (int i = 0; i < userNotifications.size(); i++) {
- Entry entry = userNotifications.get(i);
+ NotificationEntry entry = userNotifications.get(i);
ExpandableNotificationRow row = entry.getRow();
if (row != null) {
row.onUiModeChanged();
@@ -323,7 +323,7 @@ public class StatusBarNotificationPresenter implements NotificationPresenter,
return !mEntryManager.getNotificationData().getActiveNotifications().isEmpty();
}
- public boolean canHeadsUp(Entry entry, StatusBarNotification sbn) {
+ public boolean canHeadsUp(NotificationEntry entry, StatusBarNotification sbn) {
if (mShadeController.isDozing()) {
return false;
}
@@ -381,7 +381,7 @@ public class StatusBarNotificationPresenter implements NotificationPresenter,
}
@Override
- public void onBindRow(Entry entry, PackageManager pmUser,
+ public void onBindRow(NotificationEntry entry, PackageManager pmUser,
StatusBarNotification sbn, ExpandableNotificationRow row) {
row.setAboveShelfChangedListener(mAboveShelfObserver);
row.setSecureStateProvider(mUnlockMethodCache::canSkipBouncer);
@@ -439,7 +439,7 @@ public class StatusBarNotificationPresenter implements NotificationPresenter,
}
@Override
- public void onExpandClicked(Entry clickedEntry, boolean nowExpanded) {
+ public void onExpandClicked(NotificationEntry clickedEntry, boolean nowExpanded) {
mHeadsUpManager.setExpanded(clickedEntry, nowExpanded);
if (mStatusBarStateController.getState() == StatusBarState.KEYGUARD && nowExpanded) {
mShadeController.goToLockedShade(clickedEntry.getRow());
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/HeadsUpManager.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/HeadsUpManager.java
index a02c9d51fecf..fd3f680e5e77 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/HeadsUpManager.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/HeadsUpManager.java
@@ -30,7 +30,7 @@ import android.util.Log;
import com.android.internal.logging.MetricsLogger;
import com.android.systemui.R;
import com.android.systemui.statusbar.AlertingNotificationManager;
-import com.android.systemui.statusbar.notification.NotificationData;
+import com.android.systemui.statusbar.notification.collection.NotificationEntry;
import com.android.systemui.statusbar.notification.row.NotificationInflater.InflationFlag;
import java.io.FileDescriptor;
@@ -108,11 +108,11 @@ public abstract class HeadsUpManager extends AlertingNotificationManager {
}
}
- protected boolean shouldHeadsUpBecomePinned(@NonNull NotificationData.Entry entry) {
+ protected boolean shouldHeadsUpBecomePinned(@NonNull NotificationEntry entry) {
return hasFullScreenIntent(entry);
}
- protected boolean hasFullScreenIntent(@NonNull NotificationData.Entry entry) {
+ protected boolean hasFullScreenIntent(@NonNull NotificationEntry entry) {
return entry.notification.getNotification().fullScreenIntent != null;
}
@@ -121,7 +121,7 @@ public abstract class HeadsUpManager extends AlertingNotificationManager {
if (Log.isLoggable(TAG, Log.VERBOSE)) {
Log.v(TAG, "setEntryPinned: " + isPinned);
}
- NotificationData.Entry entry = headsUpEntry.mEntry;
+ NotificationEntry entry = headsUpEntry.mEntry;
if (entry.isRowPinned() != isPinned) {
entry.setRowPinned(isPinned);
updatePinnedMode();
@@ -141,7 +141,7 @@ public abstract class HeadsUpManager extends AlertingNotificationManager {
@Override
protected void onAlertEntryAdded(AlertEntry alertEntry) {
- NotificationData.Entry entry = alertEntry.mEntry;
+ NotificationEntry entry = alertEntry.mEntry;
entry.setHeadsUp(true);
setEntryPinned((HeadsUpEntry) alertEntry, shouldHeadsUpBecomePinned(entry));
for (OnHeadsUpChangedListener listener : mListeners) {
@@ -151,7 +151,7 @@ public abstract class HeadsUpManager extends AlertingNotificationManager {
@Override
protected void onAlertEntryRemoved(AlertEntry alertEntry) {
- NotificationData.Entry entry = alertEntry.mEntry;
+ NotificationEntry entry = alertEntry.mEntry;
entry.setHeadsUp(false);
setEntryPinned((HeadsUpEntry) alertEntry, false /* isPinned */);
for (OnHeadsUpChangedListener listener : mListeners) {
@@ -222,7 +222,7 @@ public abstract class HeadsUpManager extends AlertingNotificationManager {
* Returns the top Heads Up Notification, which appears to show at first.
*/
@Nullable
- public NotificationData.Entry getTopEntry() {
+ public NotificationEntry getTopEntry() {
HeadsUpEntry topEntry = getTopHeadsUpEntry();
return (topEntry != null) ? topEntry.mEntry : null;
}
@@ -323,7 +323,7 @@ public abstract class HeadsUpManager extends AlertingNotificationManager {
* @return -1 if the first argument should be ranked higher than the second, 1 if the second
* one should be ranked higher and 0 if they are equal.
*/
- public int compare(@NonNull NotificationData.Entry a, @NonNull NotificationData.Entry b) {
+ public int compare(@NonNull NotificationEntry a, @NonNull NotificationEntry b) {
AlertEntry aEntry = getHeadsUpEntry(a.key);
AlertEntry bEntry = getHeadsUpEntry(b.key);
if (aEntry == null || bEntry == null) {
@@ -336,7 +336,7 @@ public abstract class HeadsUpManager extends AlertingNotificationManager {
* Set an entry to be expanded and therefore stick in the heads up area if it's pinned
* until it's collapsed again.
*/
- public void setExpanded(@NonNull NotificationData.Entry entry, boolean expanded) {
+ public void setExpanded(@NonNull NotificationEntry entry, boolean expanded) {
HeadsUpEntry headsUpEntry = getHeadsUpEntry(entry.key);
if (headsUpEntry != null && entry.isRowPinned()) {
headsUpEntry.setExpanded(expanded);
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/OnHeadsUpChangedListener.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/OnHeadsUpChangedListener.java
index 7ad547afdb53..438226ae082d 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/OnHeadsUpChangedListener.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/OnHeadsUpChangedListener.java
@@ -16,8 +16,7 @@
package com.android.systemui.statusbar.policy;
-import com.android.systemui.statusbar.notification.NotificationData;
-import com.android.systemui.statusbar.notification.row.ExpandableNotificationRow;
+import com.android.systemui.statusbar.notification.collection.NotificationEntry;
/**
* A listener to heads up changes
@@ -33,12 +32,12 @@ public interface OnHeadsUpChangedListener {
/**
* A notification was just pinned to the top.
*/
- default void onHeadsUpPinned(NotificationData.Entry entry) {}
+ default void onHeadsUpPinned(NotificationEntry entry) {}
/**
* A notification was just unpinned from the top.
*/
- default void onHeadsUpUnPinned(NotificationData.Entry entry) {}
+ default void onHeadsUpUnPinned(NotificationEntry entry) {}
/**
* A notification just became a heads up or turned back to its normal state.
@@ -46,5 +45,5 @@ public interface OnHeadsUpChangedListener {
* @param entry the entry of the changed notification
* @param isHeadsUp whether the notification is now a headsUp notification
*/
- default void onHeadsUpStateChanged(NotificationData.Entry entry, boolean isHeadsUp) {}
+ default void onHeadsUpStateChanged(NotificationEntry entry, boolean isHeadsUp) {}
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/RemoteInputView.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/RemoteInputView.java
index 866015e84af0..dfb02cffc6e0 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/RemoteInputView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/RemoteInputView.java
@@ -56,7 +56,7 @@ import com.android.systemui.Dependency;
import com.android.systemui.Interpolators;
import com.android.systemui.R;
import com.android.systemui.statusbar.RemoteInputController;
-import com.android.systemui.statusbar.notification.NotificationData;
+import com.android.systemui.statusbar.notification.collection.NotificationEntry;
import com.android.systemui.statusbar.notification.row.wrapper.NotificationViewWrapper;
import com.android.systemui.statusbar.notification.stack.StackStateAnimator;
@@ -83,7 +83,7 @@ public class RemoteInputView extends LinearLayout implements View.OnClickListene
private RemoteInputController mController;
private RemoteInputQuickSettingsDisabler mRemoteInputQuickSettingsDisabler;
- private NotificationData.Entry mEntry;
+ private NotificationEntry mEntry;
private boolean mRemoved;
@@ -180,7 +180,7 @@ public class RemoteInputView extends LinearLayout implements View.OnClickListene
}
public static RemoteInputView inflate(Context context, ViewGroup root,
- NotificationData.Entry entry,
+ NotificationEntry entry,
RemoteInputController controller) {
RemoteInputView v = (RemoteInputView)
LayoutInflater.from(context).inflate(R.layout.remote_input, root, false);
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/SmartReplyView.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/SmartReplyView.java
index f85d8038ab3f..5e5fc42ddeea 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/SmartReplyView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/SmartReplyView.java
@@ -36,8 +36,8 @@ import com.android.systemui.plugins.ActivityStarter;
import com.android.systemui.plugins.ActivityStarter.OnDismissAction;
import com.android.systemui.statusbar.NotificationRemoteInputManager;
import com.android.systemui.statusbar.SmartReplyController;
-import com.android.systemui.statusbar.notification.NotificationData;
import com.android.systemui.statusbar.notification.NotificationUtils;
+import com.android.systemui.statusbar.notification.collection.NotificationEntry;
import com.android.systemui.statusbar.phone.KeyguardDismissUtil;
import java.text.BreakIterator;
@@ -194,7 +194,7 @@ public class SmartReplyView extends ViewGroup {
*/
public void addRepliesFromRemoteInput(
SmartReplies smartReplies,
- SmartReplyController smartReplyController, NotificationData.Entry entry) {
+ SmartReplyController smartReplyController, NotificationEntry entry) {
if (smartReplies.remoteInput != null && smartReplies.pendingIntent != null) {
if (smartReplies.choices != null) {
for (int i = 0; i < smartReplies.choices.length; ++i) {
@@ -212,7 +212,7 @@ public class SmartReplyView extends ViewGroup {
* notification are shown.
*/
public void addSmartActions(SmartActions smartActions,
- SmartReplyController smartReplyController, NotificationData.Entry entry,
+ SmartReplyController smartReplyController, NotificationEntry entry,
HeadsUpManager headsUpManager) {
int numSmartActions = smartActions.actions.size();
for (int n = 0; n < numSmartActions; n++) {
@@ -235,7 +235,7 @@ public class SmartReplyView extends ViewGroup {
@VisibleForTesting
Button inflateReplyButton(Context context, ViewGroup root, int replyIndex,
SmartReplies smartReplies, SmartReplyController smartReplyController,
- NotificationData.Entry entry) {
+ NotificationEntry entry) {
Button b = (Button) LayoutInflater.from(context).inflate(
R.layout.smart_reply_button, root, false);
CharSequence choice = smartReplies.choices[replyIndex];
@@ -289,7 +289,7 @@ public class SmartReplyView extends ViewGroup {
@VisibleForTesting
Button inflateActionButton(Context context, ViewGroup root, int actionIndex,
SmartActions smartActions, SmartReplyController smartReplyController,
- NotificationData.Entry entry, HeadsUpManager headsUpManager) {
+ NotificationEntry entry, HeadsUpManager headsUpManager) {
Notification.Action action = smartActions.actions.get(actionIndex);
Button button = (Button) LayoutInflater.from(context).inflate(
R.layout.smart_action_button, root, false);
diff --git a/packages/SystemUI/tests/src/com/android/keyguard/KeyguardClockSwitchTest.java b/packages/SystemUI/tests/src/com/android/keyguard/KeyguardClockSwitchTest.java
index 415060244243..1844df5c070a 100644
--- a/packages/SystemUI/tests/src/com/android/keyguard/KeyguardClockSwitchTest.java
+++ b/packages/SystemUI/tests/src/com/android/keyguard/KeyguardClockSwitchTest.java
@@ -35,6 +35,8 @@ import android.testing.AndroidTestingRunner;
import android.testing.TestableLooper.RunWithLooper;
import android.text.TextPaint;
import android.view.LayoutInflater;
+import android.view.View;
+import android.view.ViewGroup;
import android.widget.FrameLayout;
import android.widget.TextClock;
@@ -42,6 +44,8 @@ import com.android.systemui.SysuiTestCase;
import com.android.systemui.plugins.ClockPlugin;
import com.android.systemui.plugins.PluginListener;
import com.android.systemui.shared.plugins.PluginManager;
+import com.android.systemui.statusbar.StatusBarState;
+import com.android.systemui.statusbar.StatusBarStateController;
import org.junit.Before;
import org.junit.Test;
@@ -60,6 +64,7 @@ import org.mockito.MockitoAnnotations;
public class KeyguardClockSwitchTest extends SysuiTestCase {
private PluginManager mPluginManager;
private FrameLayout mClockContainer;
+ private StatusBarStateController.StateListener mStateListener;
@Mock
TextClock mClockView;
@@ -75,6 +80,7 @@ public class KeyguardClockSwitchTest extends SysuiTestCase {
mClockContainer = mKeyguardClockSwitch.findViewById(R.id.clock_view);
MockitoAnnotations.initMocks(this);
when(mClockView.getPaint()).thenReturn(mock(TextPaint.class));
+ mStateListener = mKeyguardClockSwitch.getStateListener();
}
@Test
@@ -272,4 +278,28 @@ public class KeyguardClockSwitchTest extends SysuiTestCase {
verify(plugin).setStyle(style);
}
+
+ @Test
+ public void onStateChanged_InvisibleInShade() {
+ // GIVEN that the big clock container is visible
+ ViewGroup container = mock(ViewGroup.class);
+ when(container.getVisibility()).thenReturn(View.VISIBLE);
+ mKeyguardClockSwitch.setBigClockContainer(container);
+ // WHEN transitioned to SHADE state
+ mStateListener.onStateChanged(StatusBarState.SHADE);
+ // THEN the container is invisible.
+ verify(container).setVisibility(View.INVISIBLE);
+ }
+
+ @Test
+ public void onStateChanged_VisibleInKeyguard() {
+ // GIVEN that the big clock container is invisible
+ ViewGroup container = mock(ViewGroup.class);
+ when(container.getVisibility()).thenReturn(View.INVISIBLE);
+ mKeyguardClockSwitch.setBigClockContainer(container);
+ // WHEN transitioned to KEYGUARD state
+ mStateListener.onStateChanged(StatusBarState.KEYGUARD);
+ // THEN the container is visible.
+ verify(container).setVisibility(View.VISIBLE);
+ }
}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/ForegroundServiceControllerTest.java b/packages/SystemUI/tests/src/com/android/systemui/ForegroundServiceControllerTest.java
index f8912bcca302..9400d6d723e9 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/ForegroundServiceControllerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/ForegroundServiceControllerTest.java
@@ -36,9 +36,9 @@ import android.support.test.runner.AndroidJUnit4;
import android.widget.RemoteViews;
import com.android.internal.messages.nano.SystemMessageProto;
-import com.android.systemui.statusbar.notification.NotificationData;
import com.android.systemui.statusbar.notification.NotificationEntryListener;
import com.android.systemui.statusbar.notification.NotificationEntryManager;
+import com.android.systemui.statusbar.notification.collection.NotificationEntry;
import org.junit.Before;
import org.junit.Test;
@@ -391,18 +391,18 @@ public class ForegroundServiceControllerTest extends SysuiTestCase {
}
private void entryRemoved(StatusBarNotification notification) {
- mEntryListener.onEntryRemoved(new NotificationData.Entry(notification),
+ mEntryListener.onEntryRemoved(new NotificationEntry(notification),
null, false);
}
private void entryAdded(StatusBarNotification notification, int importance) {
- NotificationData.Entry entry = new NotificationData.Entry(notification);
+ NotificationEntry entry = new NotificationEntry(notification);
entry.importance = importance;
mEntryListener.onPendingEntryAdded(entry);
}
private void entryUpdated(StatusBarNotification notification, int importance) {
- NotificationData.Entry entry = new NotificationData.Entry(notification);
+ NotificationEntry entry = new NotificationEntry(notification);
entry.importance = importance;
mEntryListener.onEntryUpdated(entry);
}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/bubbles/BubbleControllerTest.java b/packages/SystemUI/tests/src/com/android/systemui/bubbles/BubbleControllerTest.java
index 31df4a3fc766..21d3652adca7 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/bubbles/BubbleControllerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/bubbles/BubbleControllerTest.java
@@ -33,9 +33,9 @@ import android.widget.FrameLayout;
import com.android.systemui.SysuiTestCase;
import com.android.systemui.statusbar.NotificationTestHelper;
-import com.android.systemui.statusbar.notification.NotificationData;
import com.android.systemui.statusbar.notification.NotificationEntryListener;
import com.android.systemui.statusbar.notification.NotificationEntryManager;
+import com.android.systemui.statusbar.notification.collection.NotificationData;
import com.android.systemui.statusbar.notification.row.ExpandableNotificationRow;
import com.android.systemui.statusbar.phone.DozeParameters;
import com.android.systemui.statusbar.phone.StatusBarWindowController;
diff --git a/packages/SystemUI/tests/src/com/android/systemui/keyguard/KeyguardSliceProviderTest.java b/packages/SystemUI/tests/src/com/android/systemui/keyguard/KeyguardSliceProviderTest.java
index a8ff0b21bab9..cfc19ef28c92 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/keyguard/KeyguardSliceProviderTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/keyguard/KeyguardSliceProviderTest.java
@@ -21,6 +21,7 @@ import static org.mockito.ArgumentMatchers.anyString;
import static org.mockito.ArgumentMatchers.eq;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.never;
+import static org.mockito.Mockito.reset;
import static org.mockito.Mockito.spy;
import static org.mockito.Mockito.verify;
@@ -44,6 +45,7 @@ import androidx.slice.core.SliceQuery;
import com.android.keyguard.KeyguardUpdateMonitor;
import com.android.systemui.SysuiTestCase;
import com.android.systemui.statusbar.NotificationMediaManager;
+import com.android.systemui.statusbar.StatusBarStateController;
import org.junit.Assert;
import org.junit.Before;
@@ -67,6 +69,8 @@ public class KeyguardSliceProviderTest extends SysuiTestCase {
private AlarmManager mAlarmManager;
@Mock
private NotificationMediaManager mNotificationMediaManager;
+ @Mock
+ private StatusBarStateController mStatusBarStateController;
private TestableKeyguardSliceProvider mProvider;
private boolean mIsZenMode;
@@ -76,7 +80,7 @@ public class KeyguardSliceProviderTest extends SysuiTestCase {
mIsZenMode = false;
mProvider = new TestableKeyguardSliceProvider();
mProvider.attachInfo(getContext(), null);
- mProvider.initDependencies();
+ mProvider.initDependencies(mNotificationMediaManager, mStatusBarStateController);
SliceProvider.setSpecs(new HashSet<>(Arrays.asList(SliceSpecs.LIST)));
}
@@ -98,6 +102,7 @@ public class KeyguardSliceProviderTest extends SysuiTestCase {
@Test
public void onBindSlice_readsMedia() {
MediaMetadata metadata = mock(MediaMetadata.class);
+ mProvider.onDozingChanged(true);
mProvider.onMetadataChanged(metadata);
mProvider.onBindSlice(mProvider.getUri());
verify(metadata).getText(eq(MediaMetadata.METADATA_KEY_TITLE));
@@ -162,7 +167,31 @@ public class KeyguardSliceProviderTest extends SysuiTestCase {
@Test
public void onMetadataChanged_updatesSlice() {
mProvider.onMetadataChanged(mock(MediaMetadata.class));
+ mProvider.onDozingChanged(true);
+ verify(mContentResolver).notifyChange(eq(mProvider.getUri()), eq(null));
+
+ // Hides after waking up
+ reset(mContentResolver);
+ mProvider.onDozingChanged(false);
+ verify(mContentResolver).notifyChange(eq(mProvider.getUri()), eq(null));
+
+ // And won't update slice if device is awake
+ reset(mContentResolver);
+ mProvider.onMetadataChanged(mock(MediaMetadata.class));
+ verify(mContentResolver, never()).notifyChange(eq(mProvider.getUri()), eq(null));
+ }
+
+ @Test
+ public void onDozingChanged_updatesSliceIfMedia() {
+ // Show media when dozing
+ mProvider.onMetadataChanged(mock(MediaMetadata.class));
+ mProvider.onDozingChanged(true);
verify(mContentResolver).notifyChange(eq(mProvider.getUri()), eq(null));
+
+ // Do not notify again if nothing changed
+ reset(mContentResolver);
+ mProvider.onDozingChanged(true);
+ verify(mContentResolver, never()).notifyChange(eq(mProvider.getUri()), eq(null));
}
private class TestableKeyguardSliceProvider extends KeyguardSliceProvider {
@@ -201,11 +230,6 @@ public class KeyguardSliceProviderTest extends SysuiTestCase {
protected String getFormattedDateLocked() {
return super.getFormattedDateLocked() + mCounter++;
}
-
- @Override
- public void initDependencies() {
- mMediaManager = mNotificationMediaManager;
- }
}
}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/AlertingNotificationManagerTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/AlertingNotificationManagerTest.java
index 9d0556f61398..f8957b204021 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/AlertingNotificationManagerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/AlertingNotificationManagerTest.java
@@ -36,7 +36,7 @@ import android.testing.TestableLooper;
import com.android.systemui.R;
import com.android.systemui.SysuiTestCase;
-import com.android.systemui.statusbar.notification.NotificationData;
+import com.android.systemui.statusbar.notification.collection.NotificationEntry;
import com.android.systemui.statusbar.notification.row.ExpandableNotificationRow;
@@ -67,7 +67,7 @@ public class AlertingNotificationManagerTest extends SysuiTestCase {
private AlertingNotificationManager mAlertingNotificationManager;
- protected NotificationData.Entry mEntry;
+ protected NotificationEntry mEntry;
protected Handler mTestHandler;
private StatusBarNotification mSbn;
protected boolean mTimedOut = false;
@@ -119,7 +119,7 @@ public class AlertingNotificationManagerTest extends SysuiTestCase {
public void setUp() {
mTestHandler = Handler.createAsync(Looper.myLooper());
mSbn = createNewNotification(0 /* id */);
- mEntry = new NotificationData.Entry(mSbn);
+ mEntry = new NotificationEntry(mSbn);
mEntry.setRow(mRow);
mAlertingNotificationManager = createAlertingNotificationManager();
@@ -170,7 +170,7 @@ public class AlertingNotificationManagerTest extends SysuiTestCase {
public void testReleaseAllImmediately() {
for (int i = 0; i < TEST_NUM_NOTIFICATIONS; i++) {
StatusBarNotification sbn = createNewNotification(i);
- NotificationData.Entry entry = new NotificationData.Entry(sbn);
+ NotificationEntry entry = new NotificationEntry(sbn);
entry.setRow(mRow);
mAlertingNotificationManager.showNotification(entry);
}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/NotificationListenerTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/NotificationListenerTest.java
index 65c04fe4bcd3..c880172e775a 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/NotificationListenerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/NotificationListenerTest.java
@@ -31,8 +31,9 @@ import android.testing.TestableLooper;
import com.android.systemui.Dependency;
import com.android.systemui.SysuiTestCase;
-import com.android.systemui.statusbar.notification.NotificationData;
import com.android.systemui.statusbar.notification.NotificationEntryManager;
+import com.android.systemui.statusbar.notification.collection.NotificationData;
+import com.android.systemui.statusbar.notification.collection.NotificationEntry;
import org.junit.Before;
import org.junit.Test;
@@ -85,7 +86,7 @@ public class NotificationListenerTest extends SysuiTestCase {
@Test
public void testNotificationUpdateCallsUpdateNotification() {
- when(mNotificationData.get(mSbn.getKey())).thenReturn(new NotificationData.Entry(mSbn));
+ when(mNotificationData.get(mSbn.getKey())).thenReturn(new NotificationEntry(mSbn));
mListener.onNotificationPosted(mSbn, mRanking);
TestableLooper.get(this).processAllMessages();
verify(mEntryManager).updateNotification(mSbn, mRanking);
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/NotificationLockscreenUserManagerTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/NotificationLockscreenUserManagerTest.java
index f168a490acf4..d7ca5b410e56 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/NotificationLockscreenUserManagerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/NotificationLockscreenUserManagerTest.java
@@ -16,7 +16,6 @@
package com.android.systemui.statusbar;
-import static android.content.Intent.ACTION_DEVICE_LOCKED_CHANGED;
import static android.content.Intent.ACTION_USER_SWITCHED;
import static junit.framework.Assert.assertFalse;
@@ -42,8 +41,8 @@ import android.testing.TestableLooper;
import com.android.systemui.Dependency;
import com.android.systemui.SysuiTestCase;
-import com.android.systemui.statusbar.notification.NotificationData;
import com.android.systemui.statusbar.notification.NotificationEntryManager;
+import com.android.systemui.statusbar.notification.collection.NotificationData;
import com.android.systemui.statusbar.phone.StatusBarKeyguardViewManager;
import com.android.systemui.statusbar.policy.DeviceProvisionedController;
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/NotificationRemoteInputManagerTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/NotificationRemoteInputManagerTest.java
index 150dcb9f841c..c159516d5bde 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/NotificationRemoteInputManagerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/NotificationRemoteInputManagerTest.java
@@ -24,8 +24,8 @@ import com.android.systemui.SysuiTestCase;
import com.android.systemui.statusbar.NotificationRemoteInputManager.RemoteInputActiveExtender;
import com.android.systemui.statusbar.NotificationRemoteInputManager.RemoteInputHistoryExtender;
import com.android.systemui.statusbar.NotificationRemoteInputManager.SmartReplyHistoryExtender;
-import com.android.systemui.statusbar.notification.NotificationData;
import com.android.systemui.statusbar.notification.NotificationEntryManager;
+import com.android.systemui.statusbar.notification.collection.NotificationEntry;
import com.android.systemui.statusbar.notification.row.ExpandableNotificationRow;
import com.android.systemui.statusbar.phone.ShadeController;
@@ -60,7 +60,7 @@ public class NotificationRemoteInputManagerTest extends SysuiTestCase {
private TestableNotificationRemoteInputManager mRemoteInputManager;
private StatusBarNotification mSbn;
- private NotificationData.Entry mEntry;
+ private NotificationEntry mEntry;
private RemoteInputHistoryExtender mRemoteInputHistoryExtender;
private SmartReplyHistoryExtender mSmartReplyHistoryExtender;
private RemoteInputActiveExtender mRemoteInputActiveExtender;
@@ -75,7 +75,7 @@ public class NotificationRemoteInputManagerTest extends SysuiTestCase {
Handler.createAsync(Looper.myLooper()));
mSbn = new StatusBarNotification(TEST_PACKAGE_NAME, TEST_PACKAGE_NAME, 0, null, TEST_UID,
0, new Notification(), UserHandle.CURRENT, null, 0);
- mEntry = new NotificationData.Entry(mSbn);
+ mEntry = new NotificationEntry(mSbn);
mEntry.setRow(mRow);
mRemoteInputManager.setUpWithPresenterForTest(mCallback,
@@ -170,7 +170,7 @@ public class NotificationRemoteInputManagerTest extends SysuiTestCase {
// Setup a notification entry with 1 remote input.
StatusBarNotification newSbn =
mRemoteInputManager.rebuildNotificationWithRemoteInput(mEntry, "A Reply", false);
- NotificationData.Entry entry = new NotificationData.Entry(newSbn);
+ NotificationEntry entry = new NotificationEntry(newSbn);
// Try rebuilding to add another reply.
newSbn = mRemoteInputManager.rebuildNotificationWithRemoteInput(entry, "Reply 2", true);
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/NotificationTestHelper.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/NotificationTestHelper.java
index fb5e8753c935..529da8251c57 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/NotificationTestHelper.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/NotificationTestHelper.java
@@ -32,7 +32,7 @@ import android.view.LayoutInflater;
import android.widget.RemoteViews;
import com.android.systemui.R;
-import com.android.systemui.statusbar.notification.NotificationData;
+import com.android.systemui.statusbar.notification.collection.NotificationEntry;
import com.android.systemui.statusbar.notification.row.ExpandableNotificationRow;
import com.android.systemui.statusbar.notification.row.NotificationInflater.InflationFlag;
import com.android.systemui.statusbar.notification.row.NotificationInflaterTest;
@@ -238,7 +238,7 @@ public class NotificationTestHelper {
mUser,
null /* overrideGroupKey */,
System.currentTimeMillis());
- NotificationData.Entry entry = new NotificationData.Entry(sbn);
+ NotificationEntry entry = new NotificationEntry(sbn);
entry.setRow(row);
entry.createIcons(mContext, sbn);
entry.channel = new NotificationChannel(
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/NotificationViewHierarchyManagerTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/NotificationViewHierarchyManagerTest.java
index e84e0f30c745..bf91305137e2 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/NotificationViewHierarchyManagerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/NotificationViewHierarchyManagerTest.java
@@ -38,10 +38,10 @@ import com.android.systemui.InitController;
import com.android.systemui.SysuiTestCase;
import com.android.systemui.bubbles.BubbleController;
import com.android.systemui.plugins.statusbar.NotificationSwipeActionHelper;
-import com.android.systemui.statusbar.notification.NotificationData;
-import com.android.systemui.statusbar.notification.NotificationData.Entry;
import com.android.systemui.statusbar.notification.NotificationEntryManager;
import com.android.systemui.statusbar.notification.VisualStabilityManager;
+import com.android.systemui.statusbar.notification.collection.NotificationData;
+import com.android.systemui.statusbar.notification.collection.NotificationEntry;
import com.android.systemui.statusbar.notification.logging.NotificationLogger;
import com.android.systemui.statusbar.notification.row.ExpandableNotificationRow;
import com.android.systemui.statusbar.notification.row.ExpandableView;
@@ -102,9 +102,9 @@ public class NotificationViewHierarchyManagerTest extends SysuiTestCase {
mViewHierarchyManager.setUpWithPresenter(mPresenter, mListContainer);
}
- private NotificationData.Entry createEntry() throws Exception {
+ private NotificationEntry createEntry() throws Exception {
ExpandableNotificationRow row = mHelper.createRow();
- NotificationData.Entry entry = new NotificationData.Entry(row.getStatusBarNotification());
+ NotificationEntry entry = new NotificationEntry(row.getStatusBarNotification());
entry.setRow(row);
return entry;
}
@@ -113,9 +113,9 @@ public class NotificationViewHierarchyManagerTest extends SysuiTestCase {
public void testNotificationsBecomingBundled() throws Exception {
// Tests 3 top level notifications becoming a single bundled notification with |entry0| as
// the summary.
- NotificationData.Entry entry0 = createEntry();
- NotificationData.Entry entry1 = createEntry();
- NotificationData.Entry entry2 = createEntry();
+ NotificationEntry entry0 = createEntry();
+ NotificationEntry entry1 = createEntry();
+ NotificationEntry entry2 = createEntry();
// Set up the prior state to look like three top level notifications.
mListContainer.addContainerView(entry0.getRow());
@@ -142,9 +142,9 @@ public class NotificationViewHierarchyManagerTest extends SysuiTestCase {
@Test
public void testNotificationsBecomingUnbundled() throws Exception {
// Tests a bundled notification becoming three top level notifications.
- NotificationData.Entry entry0 = createEntry();
- NotificationData.Entry entry1 = createEntry();
- NotificationData.Entry entry2 = createEntry();
+ NotificationEntry entry0 = createEntry();
+ NotificationEntry entry1 = createEntry();
+ NotificationEntry entry2 = createEntry();
entry0.getRow().addChildNotification(entry1.getRow());
entry0.getRow().addChildNotification(entry2.getRow());
@@ -173,8 +173,8 @@ public class NotificationViewHierarchyManagerTest extends SysuiTestCase {
@Test
public void testNotificationsBecomingSuppressed() throws Exception {
// Tests two top level notifications becoming a suppressed summary and a child.
- NotificationData.Entry entry0 = createEntry();
- NotificationData.Entry entry1 = createEntry();
+ NotificationEntry entry0 = createEntry();
+ NotificationEntry entry1 = createEntry();
entry0.getRow().addChildNotification(entry1.getRow());
// Set up the prior state to look like a top level notification.
@@ -199,7 +199,7 @@ public class NotificationViewHierarchyManagerTest extends SysuiTestCase {
@Test
public void testUpdateNotificationViews_appOps() throws Exception {
- NotificationData.Entry entry0 = createEntry();
+ NotificationEntry entry0 = createEntry();
entry0.setRow(spy(entry0.getRow()));
when(mNotificationData.getActiveNotifications()).thenReturn(
Lists.newArrayList(entry0));
@@ -264,7 +264,7 @@ public class NotificationViewHierarchyManagerTest extends SysuiTestCase {
public void setMaxDisplayedNotifications(int maxNotifications) {}
@Override
- public ViewGroup getViewParentForNotification(NotificationData.Entry entry) {
+ public ViewGroup getViewParentForNotification(NotificationEntry entry) {
return null;
}
@@ -280,10 +280,10 @@ public class NotificationViewHierarchyManagerTest extends SysuiTestCase {
}
@Override
- public void cleanUpViewStateForEntry(Entry entry) { }
+ public void cleanUpViewStateForEntry(NotificationEntry entry) { }
@Override
- public boolean isInVisibleLocation(Entry entry) {
+ public boolean isInVisibleLocation(NotificationEntry entry) {
return true;
}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/SmartReplyControllerTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/SmartReplyControllerTest.java
index e7a1f051a6df..6cca434bd8cb 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/SmartReplyControllerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/SmartReplyControllerTest.java
@@ -36,8 +36,8 @@ import android.testing.TestableLooper;
import com.android.internal.statusbar.IStatusBarService;
import com.android.systemui.R;
import com.android.systemui.SysuiTestCase;
-import com.android.systemui.statusbar.notification.NotificationData;
import com.android.systemui.statusbar.notification.NotificationEntryManager;
+import com.android.systemui.statusbar.notification.collection.NotificationEntry;
import com.android.systemui.statusbar.phone.ShadeController;
import org.junit.Before;
@@ -58,7 +58,7 @@ public class SmartReplyControllerTest extends SysuiTestCase {
private static final int TEST_ACTION_COUNT = 3;
private Notification mNotification;
- private NotificationData.Entry mEntry;
+ private NotificationEntry mEntry;
private SmartReplyController mSmartReplyController;
private NotificationRemoteInputManager mRemoteInputManager;
@@ -92,7 +92,7 @@ public class SmartReplyControllerTest extends SysuiTestCase {
mSbn = new StatusBarNotification(TEST_PACKAGE_NAME, TEST_PACKAGE_NAME, 0, null, TEST_UID,
0, mNotification, new UserHandle(ActivityManager.getCurrentUser()), null, 0);
- mEntry = new NotificationData.Entry(mSbn);
+ mEntry = new NotificationEntry(mSbn);
}
@Test
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/NotificationEntryManagerTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/NotificationEntryManagerTest.java
index 6197341acda5..4d22536f34f0 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/NotificationEntryManagerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/NotificationEntryManagerTest.java
@@ -65,7 +65,8 @@ import com.android.systemui.statusbar.NotificationRemoteInputManager;
import com.android.systemui.statusbar.RemoteInputController;
import com.android.systemui.statusbar.SmartReplyController;
import com.android.systemui.statusbar.StatusBarIconView;
-import com.android.systemui.statusbar.notification.NotificationData.KeyguardEnvironment;
+import com.android.systemui.statusbar.notification.collection.NotificationData.KeyguardEnvironment;
+import com.android.systemui.statusbar.notification.collection.NotificationEntry;
import com.android.systemui.statusbar.notification.row.ExpandableNotificationRow;
import com.android.systemui.statusbar.notification.row.NotificationGutsManager;
import com.android.systemui.statusbar.notification.row.NotificationInflater;
@@ -123,7 +124,7 @@ public class NotificationEntryManagerTest extends SysuiTestCase {
@Mock private RowInflaterTask mAsyncInflationTask;
@Mock private NotificationRowBinder mMockedRowBinder;
- private NotificationData.Entry mEntry;
+ private NotificationEntry mEntry;
private StatusBarNotification mSbn;
private TestableNotificationEntryManager mEntryManager;
private CountDownLatch mCountDownLatch;
@@ -137,7 +138,7 @@ public class NotificationEntryManagerTest extends SysuiTestCase {
}
@Override
- public void onAsyncInflationFinished(NotificationData.Entry entry,
+ public void onAsyncInflationFinished(NotificationEntry entry,
@NotificationInflater.InflationFlag int inflatedFlags) {
super.onAsyncInflationFinished(entry, inflatedFlags);
@@ -222,7 +223,7 @@ public class NotificationEntryManagerTest extends SysuiTestCase {
.setContentText("Text");
mSbn = new StatusBarNotification(TEST_PACKAGE_NAME, TEST_PACKAGE_NAME, 0, null, TEST_UID,
0, n.build(), new UserHandle(ActivityManager.getCurrentUser()), null, 0);
- mEntry = new NotificationData.Entry(mSbn);
+ mEntry = new NotificationEntry(mSbn);
mEntry.expandedIcon = mock(StatusBarIconView.class);
mEntryManager = new TestableNotificationEntryManager(mContext);
@@ -259,10 +260,10 @@ public class NotificationEntryManagerTest extends SysuiTestCase {
verify(mEntryListener, never()).onInflationError(any(), any());
// Row inflation:
- ArgumentCaptor<NotificationData.Entry> entryCaptor = ArgumentCaptor.forClass(
- NotificationData.Entry.class);
+ ArgumentCaptor<NotificationEntry> entryCaptor = ArgumentCaptor.forClass(
+ NotificationEntry.class);
verify(mBindCallback).onBindRow(entryCaptor.capture(), any(), eq(mSbn), any());
- NotificationData.Entry entry = entryCaptor.getValue();
+ NotificationEntry entry = entryCaptor.getValue();
verify(mRemoteInputManager).bindRow(entry.getRow());
// Row content inflation:
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/NotificationFilterTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/NotificationFilterTest.java
index da8bc01dc29d..387475f79cc2 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/NotificationFilterTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/NotificationFilterTest.java
@@ -40,6 +40,8 @@ import android.testing.TestableLooper.RunWithLooper;
import com.android.systemui.ForegroundServiceController;
import com.android.systemui.SysuiTestCase;
import com.android.systemui.statusbar.NotificationTestHelper;
+import com.android.systemui.statusbar.notification.collection.NotificationData;
+import com.android.systemui.statusbar.notification.collection.NotificationEntry;
import com.android.systemui.statusbar.notification.row.ExpandableNotificationRow;
import com.android.systemui.statusbar.phone.NotificationGroupManager;
import com.android.systemui.statusbar.phone.ShadeController;
@@ -191,12 +193,12 @@ public class NotificationFilterTest extends SysuiTestCase {
// test should filter out hidden notifications:
// hidden
- NotificationData.Entry entry = new NotificationData.Entry(mMockStatusBarNotification);
+ NotificationEntry entry = new NotificationEntry(mMockStatusBarNotification);
entry.suspended = true;
assertTrue(mNotificationFilter.shouldFilterOut(entry));
// not hidden
- entry = new NotificationData.Entry(mMockStatusBarNotification);
+ entry = new NotificationEntry(mMockStatusBarNotification);
entry.suspended = false;
assertFalse(mNotificationFilter.shouldFilterOut(entry));
}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/VisualStabilityManagerTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/VisualStabilityManagerTest.java
index 6fbd8c751285..813fc9d308e5 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/VisualStabilityManagerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/VisualStabilityManagerTest.java
@@ -29,6 +29,7 @@ import android.test.suitebuilder.annotation.SmallTest;
import com.android.systemui.SysuiTestCase;
import com.android.systemui.statusbar.NotificationPresenter;
+import com.android.systemui.statusbar.notification.collection.NotificationEntry;
import com.android.systemui.statusbar.notification.row.ExpandableNotificationRow;
import org.junit.Before;
@@ -44,13 +45,13 @@ public class VisualStabilityManagerTest extends SysuiTestCase {
private VisualStabilityManager.Callback mCallback = mock(VisualStabilityManager.Callback.class);
private VisibilityLocationProvider mLocationProvider = mock(VisibilityLocationProvider.class);
private ExpandableNotificationRow mRow = mock(ExpandableNotificationRow.class);
- private NotificationData.Entry mEntry;
+ private NotificationEntry mEntry;
@Before
public void setUp() {
mVisualStabilityManager.setUpWithPresenter(mock(NotificationPresenter.class));
mVisualStabilityManager.setVisibilityLocationProvider(mLocationProvider);
- mEntry = new NotificationData.Entry(mock(StatusBarNotification.class));
+ mEntry = new NotificationEntry(mock(StatusBarNotification.class));
mEntry.setRow(mRow);
}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/NotificationDataTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/NotificationDataTest.java
index 6f4de1cc6dd8..193f483058d6 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/NotificationDataTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/NotificationDataTest.java
@@ -14,7 +14,7 @@
* limitations under the License
*/
-package com.android.systemui.statusbar.notification;
+package com.android.systemui.statusbar.notification.collection;
import static android.app.AppOpsManager.OP_ACCEPT_HANDOVER;
import static android.app.AppOpsManager.OP_CAMERA;
@@ -59,7 +59,9 @@ import com.android.systemui.ForegroundServiceController;
import com.android.systemui.InitController;
import com.android.systemui.SysuiTestCase;
import com.android.systemui.statusbar.NotificationTestHelper;
-import com.android.systemui.statusbar.notification.NotificationData.KeyguardEnvironment;
+import com.android.systemui.statusbar.notification.collection.NotificationData;
+import com.android.systemui.statusbar.notification.collection.NotificationData.KeyguardEnvironment;
+import com.android.systemui.statusbar.notification.collection.NotificationEntry;
import com.android.systemui.statusbar.notification.row.ExpandableNotificationRow;
import com.android.systemui.statusbar.phone.NotificationGroupManager;
import com.android.systemui.statusbar.phone.ShadeController;
@@ -203,7 +205,7 @@ public class NotificationDataTest extends SysuiTestCase {
mRow.getEntry().notification)).thenReturn(false);
when(mEnvironment.isNotificationForCurrentProfiles(
row2.getEntry().notification)).thenReturn(true);
- ArrayList<NotificationData.Entry> result =
+ ArrayList<NotificationEntry> result =
mNotificationData.getNotificationsForCurrentUser();
assertEquals(result.size(), 1);
@@ -217,7 +219,7 @@ public class NotificationDataTest extends SysuiTestCase {
TEST_EXEMPT_DND_VISUAL_SUPPRESSION_KEY);
Notification n = mMockStatusBarNotification.getNotification();
n.flags = Notification.FLAG_FOREGROUND_SERVICE;
- NotificationData.Entry entry = new NotificationData.Entry(mMockStatusBarNotification);
+ NotificationEntry entry = new NotificationEntry(mMockStatusBarNotification);
mNotificationData.add(entry);
assertTrue(entry.isExemptFromDndVisualSuppression());
@@ -234,7 +236,7 @@ public class NotificationDataTest extends SysuiTestCase {
nb.setStyle(new Notification.MediaStyle().setMediaSession(mock(MediaSession.Token.class)));
n = nb.build();
when(mMockStatusBarNotification.getNotification()).thenReturn(n);
- NotificationData.Entry entry = new NotificationData.Entry(mMockStatusBarNotification);
+ NotificationEntry entry = new NotificationEntry(mMockStatusBarNotification);
mNotificationData.add(entry);
assertTrue(entry.isExemptFromDndVisualSuppression());
@@ -246,7 +248,7 @@ public class NotificationDataTest extends SysuiTestCase {
initStatusBarNotification(false);
when(mMockStatusBarNotification.getKey()).thenReturn(
TEST_EXEMPT_DND_VISUAL_SUPPRESSION_KEY);
- NotificationData.Entry entry = new NotificationData.Entry(mMockStatusBarNotification);
+ NotificationEntry entry = new NotificationEntry(mMockStatusBarNotification);
entry.mIsSystemNotification = true;
mNotificationData.add(entry);
@@ -259,7 +261,7 @@ public class NotificationDataTest extends SysuiTestCase {
initStatusBarNotification(false);
when(mMockStatusBarNotification.getKey()).thenReturn(
TEST_EXEMPT_DND_VISUAL_SUPPRESSION_KEY);
- NotificationData.Entry entry = new NotificationData.Entry(mMockStatusBarNotification);
+ NotificationEntry entry = new NotificationEntry(mMockStatusBarNotification);
entry.mIsSystemNotification = true;
mNotificationData.add(entry);
@@ -313,8 +315,8 @@ public class NotificationDataTest extends SysuiTestCase {
snoozeCriterions.add(snoozeCriterion);
when(ranking.getSnoozeCriteria()).thenReturn(snoozeCriterions);
- NotificationData.Entry entry =
- new NotificationData.Entry(mMockStatusBarNotification, ranking);
+ NotificationEntry entry =
+ new NotificationEntry(mMockStatusBarNotification, ranking);
assertEquals(systemGeneratedSmartActions, entry.systemGeneratedSmartActions);
assertEquals(NOTIFICATION_CHANNEL, entry.channel);
@@ -343,7 +345,7 @@ public class NotificationDataTest extends SysuiTestCase {
StatusBarNotification sbn = new StatusBarNotification("pkg", "pkg", 0, "tag", 0, 0,
notification, mContext.getUser(), "", 0);
- NotificationData.Entry entry = new NotificationData.Entry(sbn);
+ NotificationEntry entry = new NotificationEntry(sbn);
entry.setHasSentReply();
assertTrue(entry.isLastMessageFromReply());
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/logging/NotificationLoggerTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/logging/NotificationLoggerTest.java
index afdeb62a8f28..64725896cce5 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/logging/NotificationLoggerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/logging/NotificationLoggerTest.java
@@ -41,9 +41,10 @@ import com.android.systemui.SysuiTestCase;
import com.android.systemui.UiOffloadThread;
import com.android.systemui.statusbar.NotificationListener;
import com.android.systemui.statusbar.StatusBarStateController;
-import com.android.systemui.statusbar.notification.NotificationData;
import com.android.systemui.statusbar.notification.NotificationEntryListener;
import com.android.systemui.statusbar.notification.NotificationEntryManager;
+import com.android.systemui.statusbar.notification.collection.NotificationData;
+import com.android.systemui.statusbar.notification.collection.NotificationEntry;
import com.android.systemui.statusbar.notification.row.ExpandableNotificationRow;
import com.android.systemui.statusbar.notification.stack.NotificationListContainer;
@@ -77,7 +78,7 @@ public class NotificationLoggerTest extends SysuiTestCase {
@Mock private NotificationListener mListener;
@Captor private ArgumentCaptor<NotificationEntryListener> mEntryListenerCaptor;
- private NotificationData.Entry mEntry;
+ private NotificationEntry mEntry;
private TestableNotificationLogger mLogger;
private NotificationEntryListener mNotificationEntryListener;
private ConcurrentLinkedQueue<AssertionError> mErrorQueue = new ConcurrentLinkedQueue<>();
@@ -93,7 +94,7 @@ public class NotificationLoggerTest extends SysuiTestCase {
StatusBarNotification sbn = new StatusBarNotification(TEST_PACKAGE_NAME, TEST_PACKAGE_NAME,
0, null, TEST_UID,
0, new Notification(), UserHandle.CURRENT, null, 0);
- mEntry = new NotificationData.Entry(sbn);
+ mEntry = new NotificationEntry(sbn);
mEntry.setRow(mRow);
mLogger = new TestableNotificationLogger(mListener, Dependency.get(UiOffloadThread.class),
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/NotificationContentViewTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/NotificationContentViewTest.java
index 82b42c51622d..d94bf845ca5b 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/NotificationContentViewTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/NotificationContentViewTest.java
@@ -47,7 +47,7 @@ import android.view.View;
import com.android.systemui.R;
import com.android.systemui.SysuiTestCase;
-import com.android.systemui.statusbar.notification.NotificationData;
+import com.android.systemui.statusbar.notification.collection.NotificationEntry;
import com.android.systemui.statusbar.policy.SmartReplyConstants;
import org.junit.Before;
@@ -73,7 +73,7 @@ public class NotificationContentViewTest extends SysuiTestCase {
StatusBarNotification mStatusBarNotification;
@Mock
Notification mNotification;
- NotificationData.Entry mEntry;
+ NotificationEntry mEntry;
@Mock
RemoteInput mRemoteInput;
@Mock
@@ -107,7 +107,7 @@ public class NotificationContentViewTest extends SysuiTestCase {
// Smart replies and actions
when(mNotification.getAllowSystemGeneratedContextualActions()).thenReturn(true);
when(mStatusBarNotification.getNotification()).thenReturn(mNotification);
- mEntry = new NotificationData.Entry(mStatusBarNotification);
+ mEntry = new NotificationEntry(mStatusBarNotification);
when(mSmartReplyConstants.isEnabled()).thenReturn(true);
mActionIcon = Icon.createWithResource(mContext, R.drawable.ic_person);
}
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 ad43bea74089..0899c73ab07b 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
@@ -60,7 +60,7 @@ import com.android.systemui.plugins.statusbar.NotificationMenuRowPlugin;
import com.android.systemui.statusbar.NotificationPresenter;
import com.android.systemui.statusbar.NotificationTestHelper;
import com.android.systemui.statusbar.notification.NotificationActivityStarter;
-import com.android.systemui.statusbar.notification.NotificationData;
+import com.android.systemui.statusbar.notification.collection.NotificationEntry;
import com.android.systemui.statusbar.notification.row.NotificationGutsManager.OnSettingsClickListener;
import com.android.systemui.statusbar.notification.stack.NotificationStackScrollLayout;
import com.android.systemui.statusbar.policy.DeviceProvisionedController;
@@ -183,8 +183,8 @@ public class NotificationGutsManagerTest extends SysuiTestCase {
when(row.getGuts()).thenReturn(guts);
doNothing().when(row).inflateGuts();
- NotificationData.Entry realEntry = realRow.getEntry();
- NotificationData.Entry entry = spy(realEntry);
+ NotificationEntry realEntry = realRow.getEntry();
+ NotificationEntry entry = spy(realEntry);
when(entry.getRow()).thenReturn(row);
when(entry.getGuts()).thenReturn(guts);
@@ -443,7 +443,7 @@ public class NotificationGutsManagerTest extends SysuiTestCase {
NotificationGuts guts = new NotificationGuts(mContext);
ExpandableNotificationRow row = spy(createTestNotificationRow());
doReturn(guts).when(row).getGuts();
- NotificationData.Entry entry = row.getEntry();
+ NotificationEntry entry = row.getEntry();
entry.setRow(row);
mGutsManager.setExposedGuts(guts);
@@ -452,7 +452,7 @@ public class NotificationGutsManagerTest extends SysuiTestCase {
@Test
public void testSetShouldManageLifetime_setShouldManage() {
- NotificationData.Entry entry = createTestNotificationRow().getEntry();
+ NotificationEntry entry = createTestNotificationRow().getEntry();
mGutsManager.setShouldManageLifetime(entry, true /* shouldManage */);
assertTrue(entry.key.equals(mGutsManager.mKeyToRemoveOnGutsClosed));
@@ -460,7 +460,7 @@ public class NotificationGutsManagerTest extends SysuiTestCase {
@Test
public void testSetShouldManageLifetime_setShouldNotManage() {
- NotificationData.Entry entry = createTestNotificationRow().getEntry();
+ NotificationEntry entry = createTestNotificationRow().getEntry();
mGutsManager.mKeyToRemoveOnGutsClosed = entry.key;
mGutsManager.setShouldManageLifetime(entry, false /* shouldManage */);
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/NotificationInflaterTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/NotificationInflaterTest.java
index d6b706d73827..648df3cab33c 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/NotificationInflaterTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/NotificationInflaterTest.java
@@ -48,7 +48,7 @@ import com.android.systemui.R;
import com.android.systemui.SysuiTestCase;
import com.android.systemui.statusbar.InflationTask;
import com.android.systemui.statusbar.NotificationTestHelper;
-import com.android.systemui.statusbar.notification.NotificationData;
+import com.android.systemui.statusbar.notification.collection.NotificationEntry;
import org.junit.Assert;
import org.junit.Before;
@@ -88,7 +88,7 @@ public class NotificationInflaterTest extends SysuiTestCase {
}
@Override
- public void onAsyncInflationFinished(NotificationData.Entry entry,
+ public void onAsyncInflationFinished(NotificationEntry entry,
@NotificationInflater.InflationFlag int inflatedFlags) {
}
});
@@ -174,7 +174,7 @@ public class NotificationInflaterTest extends SysuiTestCase {
}
@Override
- public void onAsyncInflationFinished(NotificationData.Entry entry,
+ public void onAsyncInflationFinished(NotificationEntry entry,
@NotificationInflater.InflationFlag int inflatedFlags) {
countDownLatch.countDown();
}
@@ -256,7 +256,7 @@ public class NotificationInflaterTest extends SysuiTestCase {
}
@Override
- public void onAsyncInflationFinished(NotificationData.Entry entry,
+ public void onAsyncInflationFinished(NotificationEntry entry,
@NotificationInflater.InflationFlag int inflatedFlags) {
if (expectingException) {
exceptionHolder.setException(new RuntimeException(
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/NotificationMenuRowTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/NotificationMenuRowTest.java
index e4d019656072..04d7509f760f 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/NotificationMenuRowTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/NotificationMenuRowTest.java
@@ -35,7 +35,7 @@ import android.testing.ViewUtils;
import android.view.ViewGroup;
import com.android.systemui.plugins.statusbar.NotificationMenuRowPlugin;
-import com.android.systemui.statusbar.notification.NotificationData;
+import com.android.systemui.statusbar.notification.collection.NotificationEntry;
import com.android.systemui.utils.leaks.LeakCheckedTest;
import org.junit.Before;
@@ -54,7 +54,7 @@ public class NotificationMenuRowTest extends LeakCheckedTest {
public void setup() {
injectLeakCheckedDependencies(ALL_SUPPORTED_CLASSES);
mRow = mock(ExpandableNotificationRow.class);
- NotificationData.Entry entry = new NotificationData.Entry(
+ NotificationEntry entry = new NotificationEntry(
mock(StatusBarNotification.class));
entry.channel = mock(NotificationChannel.class);
when(mRow.getEntry()).thenReturn(entry);
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 b66d0ab78fd8..214404c8c295 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
@@ -53,9 +53,9 @@ import com.android.systemui.statusbar.NotificationShelf;
import com.android.systemui.statusbar.RemoteInputController;
import com.android.systemui.statusbar.StatusBarState;
import com.android.systemui.statusbar.StatusBarStateController;
-import com.android.systemui.statusbar.notification.NotificationData;
-import com.android.systemui.statusbar.notification.NotificationData.Entry;
import com.android.systemui.statusbar.notification.NotificationEntryManager;
+import com.android.systemui.statusbar.notification.collection.NotificationData;
+import com.android.systemui.statusbar.notification.collection.NotificationEntry;
import com.android.systemui.statusbar.notification.row.ExpandableNotificationRow;
import com.android.systemui.statusbar.notification.row.FooterView;
import com.android.systemui.statusbar.notification.row.NotificationBlockingHelperManager;
@@ -265,8 +265,8 @@ public class NotificationStackScrollLayoutTest extends SysuiTestCase {
@Test
public void testUpdateFooter_remoteInput() {
setBarStateForTest(StatusBarState.SHADE);
- ArrayList<Entry> entries = new ArrayList<>();
- entries.add(mock(Entry.class));
+ ArrayList<NotificationEntry> entries = new ArrayList<>();
+ entries.add(mock(NotificationEntry.class));
when(mNotificationData.getActiveNotifications()).thenReturn(entries);
ExpandableNotificationRow row = mock(ExpandableNotificationRow.class);
@@ -282,8 +282,8 @@ public class NotificationStackScrollLayoutTest extends SysuiTestCase {
@Test
public void testUpdateFooter_oneClearableNotification() {
setBarStateForTest(StatusBarState.SHADE);
- ArrayList<Entry> entries = new ArrayList<>();
- entries.add(mock(Entry.class));
+ ArrayList<NotificationEntry> entries = new ArrayList<>();
+ entries.add(mock(NotificationEntry.class));
when(mNotificationData.getActiveNotifications()).thenReturn(entries);
ExpandableNotificationRow row = mock(ExpandableNotificationRow.class);
@@ -298,8 +298,8 @@ public class NotificationStackScrollLayoutTest extends SysuiTestCase {
@Test
public void testUpdateFooter_oneNonClearableNotification() {
setBarStateForTest(StatusBarState.SHADE);
- ArrayList<Entry> entries = new ArrayList<>();
- entries.add(mock(Entry.class));
+ ArrayList<NotificationEntry> entries = new ArrayList<>();
+ entries.add(mock(NotificationEntry.class));
when(mEntryManager.getNotificationData().getActiveNotifications()).thenReturn(entries);
assertTrue(mEntryManager.getNotificationData().getActiveNotifications().size() != 0);
@@ -314,7 +314,7 @@ public class NotificationStackScrollLayoutTest extends SysuiTestCase {
// add notification
ExpandableNotificationRow row = mock(ExpandableNotificationRow.class);
- NotificationData.Entry entry = mock(NotificationData.Entry.class);
+ NotificationEntry entry = mock(NotificationEntry.class);
when(row.getEntry()).thenReturn(entry);
when(entry.isClearable()).thenReturn(true);
mStackScroller.addContainerView(row);
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/HeadsUpManagerPhoneTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/HeadsUpManagerPhoneTest.java
index 44deb10941ec..9ceb325204fe 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/HeadsUpManagerPhoneTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/HeadsUpManagerPhoneTest.java
@@ -16,15 +16,20 @@
package com.android.systemui.statusbar.phone;
-import android.view.View;
+import static junit.framework.Assert.assertFalse;
+import static junit.framework.Assert.assertTrue;
+
+import static org.mockito.Mockito.when;
+
import android.support.test.filters.SmallTest;
import android.testing.AndroidTestingRunner;
import android.testing.TestableLooper;
+import android.view.View;
import com.android.systemui.statusbar.AlertingNotificationManager;
import com.android.systemui.statusbar.AlertingNotificationManagerTest;
-import com.android.systemui.statusbar.notification.NotificationData;
import com.android.systemui.statusbar.notification.VisualStabilityManager;
+import com.android.systemui.statusbar.notification.collection.NotificationEntry;
import org.junit.Before;
import org.junit.Rule;
@@ -34,11 +39,6 @@ import org.mockito.Mock;
import org.mockito.junit.MockitoJUnit;
import org.mockito.junit.MockitoRule;
-import static junit.framework.Assert.assertTrue;
-import static junit.framework.Assert.assertFalse;
-
-import static org.mockito.Mockito.when;
-
@SmallTest
@RunWith(AndroidTestingRunner.class)
@TestableLooper.RunWithLooper
@@ -96,7 +96,7 @@ public class HeadsUpManagerPhoneTest extends AlertingNotificationManagerTest {
@Test
public void testCanRemoveImmediately_notTopEntry() {
- NotificationData.Entry laterEntry = new NotificationData.Entry(createNewNotification(1));
+ NotificationEntry laterEntry = new NotificationEntry(createNewNotification(1));
laterEntry.setRow(mRow);
mHeadsUpManager.showNotification(mEntry);
mHeadsUpManager.showNotification(laterEntry);
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/NotificationGroupAlertTransferHelperTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/NotificationGroupAlertTransferHelperTest.java
index 79695fd6d38d..cefd4acbfb5a 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/NotificationGroupAlertTransferHelperTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/NotificationGroupAlertTransferHelperTest.java
@@ -32,10 +32,9 @@ import android.testing.TestableLooper;
import com.android.systemui.SysuiTestCase;
import com.android.systemui.statusbar.AmbientPulseManager;
-import com.android.systemui.statusbar.notification.NotificationData;
-import com.android.systemui.statusbar.notification.NotificationData.Entry;
import com.android.systemui.statusbar.notification.NotificationEntryListener;
import com.android.systemui.statusbar.notification.NotificationEntryManager;
+import com.android.systemui.statusbar.notification.collection.NotificationEntry;
import com.android.systemui.statusbar.policy.HeadsUpManager;
import org.junit.Before;
@@ -64,7 +63,7 @@ public class NotificationGroupAlertTransferHelperTest extends SysuiTestCase {
@Captor
private ArgumentCaptor<NotificationEntryListener> mListenerCaptor;
private NotificationEntryListener mNotificationEntryListener;
- private final HashMap<String, Entry> mPendingEntries = new HashMap<>();
+ private final HashMap<String, NotificationEntry> mPendingEntries = new HashMap<>();
private final NotificationGroupTestHelper mGroupTestHelper =
new NotificationGroupTestHelper(mContext);
@@ -94,9 +93,9 @@ public class NotificationGroupAlertTransferHelperTest extends SysuiTestCase {
@Test
public void testSuppressedSummaryHeadsUpTransfersToChild() {
- Entry summaryEntry = mGroupTestHelper.createSummaryNotification();
+ NotificationEntry summaryEntry = mGroupTestHelper.createSummaryNotification();
mHeadsUpManager.showNotification(summaryEntry);
- Entry childEntry = mGroupTestHelper.createChildNotification();
+ NotificationEntry childEntry = mGroupTestHelper.createChildNotification();
// Summary will be suppressed because there is only one child.
mGroupManager.onEntryAdded(summaryEntry);
@@ -109,11 +108,11 @@ public class NotificationGroupAlertTransferHelperTest extends SysuiTestCase {
@Test
public void testSuppressedSummaryHeadsUpTransfersToChildButBackAgain() {
- NotificationData.Entry summaryEntry =
+ NotificationEntry summaryEntry =
mGroupTestHelper.createSummaryNotification(Notification.GROUP_ALERT_SUMMARY);
- NotificationData.Entry childEntry =
+ NotificationEntry childEntry =
mGroupTestHelper.createChildNotification(Notification.GROUP_ALERT_SUMMARY);
- NotificationData.Entry childEntry2 =
+ NotificationEntry childEntry2 =
mGroupTestHelper.createChildNotification(Notification.GROUP_ALERT_SUMMARY);
mHeadsUpManager.showNotification(summaryEntry);
// Trigger a transfer of alert state from summary to child.
@@ -133,11 +132,11 @@ public class NotificationGroupAlertTransferHelperTest extends SysuiTestCase {
@Test
public void testSuppressedSummaryHeadsUpDoesntTransferBackOnDozingChanged() {
- NotificationData.Entry summaryEntry =
+ NotificationEntry summaryEntry =
mGroupTestHelper.createSummaryNotification(Notification.GROUP_ALERT_SUMMARY);
- NotificationData.Entry childEntry =
+ NotificationEntry childEntry =
mGroupTestHelper.createChildNotification(Notification.GROUP_ALERT_SUMMARY);
- NotificationData.Entry childEntry2 =
+ NotificationEntry childEntry2 =
mGroupTestHelper.createChildNotification(Notification.GROUP_ALERT_SUMMARY);
mHeadsUpManager.showNotification(summaryEntry);
// Trigger a transfer of alert state from summary to child.
@@ -158,9 +157,9 @@ public class NotificationGroupAlertTransferHelperTest extends SysuiTestCase {
@Test
public void testSuppressedSummaryHeadsUpTransferDoesNotAlertChildIfUninflated() {
- Entry summaryEntry = mGroupTestHelper.createSummaryNotification();
+ NotificationEntry summaryEntry = mGroupTestHelper.createSummaryNotification();
mHeadsUpManager.showNotification(summaryEntry);
- Entry childEntry = mGroupTestHelper.createChildNotification();
+ NotificationEntry childEntry = mGroupTestHelper.createChildNotification();
when(childEntry.getRow().isInflationFlagSet(mHeadsUpManager.getContentFlag()))
.thenReturn(false);
@@ -176,9 +175,9 @@ public class NotificationGroupAlertTransferHelperTest extends SysuiTestCase {
@Test
public void testSuppressedSummaryHeadsUpTransferAlertsChildOnInflation() {
- Entry summaryEntry = mGroupTestHelper.createSummaryNotification();
+ NotificationEntry summaryEntry = mGroupTestHelper.createSummaryNotification();
mHeadsUpManager.showNotification(summaryEntry);
- Entry childEntry = mGroupTestHelper.createChildNotification();
+ NotificationEntry childEntry = mGroupTestHelper.createChildNotification();
when(childEntry.getRow().isInflationFlagSet(mHeadsUpManager.getContentFlag()))
.thenReturn(false);
@@ -196,13 +195,13 @@ public class NotificationGroupAlertTransferHelperTest extends SysuiTestCase {
@Test
public void testSuppressedSummaryHeadsUpTransferBackAbortsChildInflation() {
- NotificationData.Entry summaryEntry =
+ NotificationEntry summaryEntry =
mGroupTestHelper.createSummaryNotification(Notification.GROUP_ALERT_SUMMARY);
- NotificationData.Entry childEntry =
+ NotificationEntry childEntry =
mGroupTestHelper.createChildNotification(Notification.GROUP_ALERT_SUMMARY);
when(childEntry.getRow().isInflationFlagSet(mHeadsUpManager.getContentFlag()))
.thenReturn(false);
- NotificationData.Entry childEntry2 =
+ NotificationEntry childEntry2 =
mGroupTestHelper.createChildNotification(Notification.GROUP_ALERT_SUMMARY);
mHeadsUpManager.showNotification(summaryEntry);
// Trigger a transfer of alert state from summary to child.
@@ -226,9 +225,9 @@ public class NotificationGroupAlertTransferHelperTest extends SysuiTestCase {
@Test
public void testCleanUpPendingAlertInfo() {
- NotificationData.Entry summaryEntry =
+ NotificationEntry summaryEntry =
mGroupTestHelper.createSummaryNotification(Notification.GROUP_ALERT_SUMMARY);
- NotificationData.Entry childEntry =
+ NotificationEntry childEntry =
mGroupTestHelper.createChildNotification(Notification.GROUP_ALERT_SUMMARY);
when(childEntry.getRow().isInflationFlagSet(mHeadsUpManager.getContentFlag()))
.thenReturn(false);
@@ -244,9 +243,9 @@ public class NotificationGroupAlertTransferHelperTest extends SysuiTestCase {
@Test
public void testUpdateGroupChangeDoesNotTransfer() {
- NotificationData.Entry summaryEntry =
+ NotificationEntry summaryEntry =
mGroupTestHelper.createSummaryNotification(Notification.GROUP_ALERT_SUMMARY);
- NotificationData.Entry childEntry =
+ NotificationEntry childEntry =
mGroupTestHelper.createChildNotification(Notification.GROUP_ALERT_SUMMARY);
when(childEntry.getRow().isInflationFlagSet(mHeadsUpManager.getContentFlag()))
.thenReturn(false);
@@ -267,9 +266,9 @@ public class NotificationGroupAlertTransferHelperTest extends SysuiTestCase {
@Test
public void testUpdateChildToSummaryDoesNotTransfer() {
- NotificationData.Entry summaryEntry =
+ NotificationEntry summaryEntry =
mGroupTestHelper.createSummaryNotification(Notification.GROUP_ALERT_SUMMARY);
- NotificationData.Entry childEntry =
+ NotificationEntry childEntry =
mGroupTestHelper.createChildNotification(Notification.GROUP_ALERT_SUMMARY);
when(childEntry.getRow().isInflationFlagSet(mHeadsUpManager.getContentFlag()))
.thenReturn(false);
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/NotificationGroupManagerTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/NotificationGroupManagerTest.java
index b0bd1fba3760..ecb3e4d8067c 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/NotificationGroupManagerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/NotificationGroupManagerTest.java
@@ -29,7 +29,7 @@ import android.testing.TestableLooper;
import com.android.systemui.SysuiTestCase;
import com.android.systemui.statusbar.AmbientPulseManager;
-import com.android.systemui.statusbar.notification.NotificationData;
+import com.android.systemui.statusbar.notification.collection.NotificationEntry;
import com.android.systemui.statusbar.policy.HeadsUpManager;
import org.junit.Before;
@@ -69,8 +69,8 @@ public class NotificationGroupManagerTest extends SysuiTestCase {
@Test
public void testIsOnlyChildInGroup() {
- NotificationData.Entry childEntry = mGroupTestHelper.createChildNotification();
- NotificationData.Entry summaryEntry = mGroupTestHelper.createSummaryNotification();
+ NotificationEntry childEntry = mGroupTestHelper.createChildNotification();
+ NotificationEntry summaryEntry = mGroupTestHelper.createSummaryNotification();
mGroupManager.onEntryAdded(summaryEntry);
mGroupManager.onEntryAdded(childEntry);
@@ -80,8 +80,8 @@ public class NotificationGroupManagerTest extends SysuiTestCase {
@Test
public void testIsChildInGroupWithSummary() {
- NotificationData.Entry childEntry = mGroupTestHelper.createChildNotification();
- NotificationData.Entry summaryEntry = mGroupTestHelper.createSummaryNotification();
+ NotificationEntry childEntry = mGroupTestHelper.createChildNotification();
+ NotificationEntry summaryEntry = mGroupTestHelper.createSummaryNotification();
mGroupManager.onEntryAdded(summaryEntry);
mGroupManager.onEntryAdded(childEntry);
@@ -92,8 +92,8 @@ public class NotificationGroupManagerTest extends SysuiTestCase {
@Test
public void testIsSummaryOfGroupWithChildren() {
- NotificationData.Entry childEntry = mGroupTestHelper.createChildNotification();
- NotificationData.Entry summaryEntry = mGroupTestHelper.createSummaryNotification();
+ NotificationEntry childEntry = mGroupTestHelper.createChildNotification();
+ NotificationEntry summaryEntry = mGroupTestHelper.createSummaryNotification();
mGroupManager.onEntryAdded(summaryEntry);
mGroupManager.onEntryAdded(childEntry);
@@ -105,8 +105,8 @@ public class NotificationGroupManagerTest extends SysuiTestCase {
@Test
public void testRemoveChildFromGroupWithSummary() {
- NotificationData.Entry childEntry = mGroupTestHelper.createChildNotification();
- NotificationData.Entry summaryEntry = mGroupTestHelper.createSummaryNotification();
+ NotificationEntry childEntry = mGroupTestHelper.createChildNotification();
+ NotificationEntry summaryEntry = mGroupTestHelper.createSummaryNotification();
mGroupManager.onEntryAdded(summaryEntry);
mGroupManager.onEntryAdded(childEntry);
mGroupManager.onEntryAdded(mGroupTestHelper.createChildNotification());
@@ -118,8 +118,8 @@ public class NotificationGroupManagerTest extends SysuiTestCase {
@Test
public void testRemoveSummaryFromGroupWithSummary() {
- NotificationData.Entry childEntry = mGroupTestHelper.createChildNotification();
- NotificationData.Entry summaryEntry = mGroupTestHelper.createSummaryNotification();
+ NotificationEntry childEntry = mGroupTestHelper.createChildNotification();
+ NotificationEntry summaryEntry = mGroupTestHelper.createSummaryNotification();
mGroupManager.onEntryAdded(summaryEntry);
mGroupManager.onEntryAdded(childEntry);
mGroupManager.onEntryAdded(mGroupTestHelper.createChildNotification());
@@ -132,8 +132,8 @@ public class NotificationGroupManagerTest extends SysuiTestCase {
@Test
public void testHeadsUpEntryIsIsolated() {
- NotificationData.Entry childEntry = mGroupTestHelper.createChildNotification();
- NotificationData.Entry summaryEntry = mGroupTestHelper.createSummaryNotification();
+ NotificationEntry childEntry = mGroupTestHelper.createChildNotification();
+ NotificationEntry summaryEntry = mGroupTestHelper.createSummaryNotification();
mGroupManager.onEntryAdded(summaryEntry);
mGroupManager.onEntryAdded(childEntry);
mGroupManager.onEntryAdded(mGroupTestHelper.createChildNotification());
@@ -149,8 +149,8 @@ public class NotificationGroupManagerTest extends SysuiTestCase {
@Test
public void testAmbientPulseEntryIsIsolated() {
- NotificationData.Entry childEntry = mGroupTestHelper.createChildNotification();
- NotificationData.Entry summaryEntry = mGroupTestHelper.createSummaryNotification();
+ NotificationEntry childEntry = mGroupTestHelper.createChildNotification();
+ NotificationEntry summaryEntry = mGroupTestHelper.createSummaryNotification();
mGroupManager.onEntryAdded(summaryEntry);
mGroupManager.onEntryAdded(childEntry);
mGroupManager.onEntryAdded(mGroupTestHelper.createChildNotification());
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/NotificationGroupTestHelper.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/NotificationGroupTestHelper.java
index 7ad68eb1c9a3..e6b9778eb59f 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/NotificationGroupTestHelper.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/NotificationGroupTestHelper.java
@@ -27,7 +27,7 @@ import android.os.UserHandle;
import android.service.notification.StatusBarNotification;
import com.android.systemui.R;
-import com.android.systemui.statusbar.notification.NotificationData;
+import com.android.systemui.statusbar.notification.collection.NotificationEntry;
import com.android.systemui.statusbar.notification.row.ExpandableNotificationRow;
/**
@@ -44,23 +44,23 @@ public final class NotificationGroupTestHelper {
mContext = context;
}
- public NotificationData.Entry createSummaryNotification() {
+ public NotificationEntry createSummaryNotification() {
return createSummaryNotification(Notification.GROUP_ALERT_ALL);
}
- public NotificationData.Entry createSummaryNotification(int groupAlertBehavior) {
+ public NotificationEntry createSummaryNotification(int groupAlertBehavior) {
return createEntry(true, groupAlertBehavior);
}
- public NotificationData.Entry createChildNotification() {
+ public NotificationEntry createChildNotification() {
return createChildNotification(Notification.GROUP_ALERT_ALL);
}
- public NotificationData.Entry createChildNotification(int groupAlertBehavior) {
+ public NotificationEntry createChildNotification(int groupAlertBehavior) {
return createEntry(false, groupAlertBehavior);
}
- public NotificationData.Entry createEntry(boolean isSummary, int groupAlertBehavior) {
+ public NotificationEntry createEntry(boolean isSummary, int groupAlertBehavior) {
Notification notif = new Notification.Builder(mContext, TEST_CHANNEL_ID)
.setContentTitle("Title")
.setSmallIcon(R.drawable.ic_person)
@@ -79,7 +79,7 @@ public final class NotificationGroupTestHelper {
new UserHandle(ActivityManager.getCurrentUser()),
null /* overrideGroupKey */,
0 /* postTime */);
- NotificationData.Entry entry = new NotificationData.Entry(sbn);
+ NotificationEntry entry = new NotificationEntry(sbn);
ExpandableNotificationRow row = mock(ExpandableNotificationRow.class);
entry.setRow(row);
when(row.getEntry()).thenReturn(entry);
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarNotificationPresenterTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarNotificationPresenterTest.java
index 2bbfd7d8bb8d..12cb99575fb6 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarNotificationPresenterTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarNotificationPresenterTest.java
@@ -40,7 +40,7 @@ import com.android.systemui.SysuiTestCase;
import com.android.systemui.statusbar.CommandQueue;
import com.android.systemui.statusbar.notification.ActivityLaunchAnimator;
import com.android.systemui.statusbar.notification.NotificationAlertingManager;
-import com.android.systemui.statusbar.notification.NotificationData;
+import com.android.systemui.statusbar.notification.collection.NotificationEntry;
import com.android.systemui.statusbar.notification.row.ActivatableNotificationView;
import com.android.systemui.statusbar.notification.stack.NotificationListContainer;
@@ -82,7 +82,7 @@ public class StatusBarNotificationPresenterTest extends SysuiTestCase {
Notification n = new Notification.Builder(getContext(), "a").build();
StatusBarNotification sbn = new StatusBarNotification("a", "a", 0, "a", 0, 0, n,
UserHandle.of(0), null, 0);
- NotificationData.Entry entry = new NotificationData.Entry(sbn);
+ NotificationEntry entry = new NotificationEntry(sbn);
mCommandQueue.disable(DEFAULT_DISPLAY, StatusBarManager.DISABLE_EXPAND, 0,
false /* animate */);
TestableLooper.get(this).processAllMessages();
@@ -96,7 +96,7 @@ public class StatusBarNotificationPresenterTest extends SysuiTestCase {
Notification n = new Notification.Builder(getContext(), "a").build();
StatusBarNotification sbn = new StatusBarNotification("a", "a", 0, "a", 0, 0, n,
UserHandle.of(0), null, 0);
- NotificationData.Entry entry = new NotificationData.Entry(sbn);
+ NotificationEntry entry = new NotificationEntry(sbn);
mCommandQueue.disable(DEFAULT_DISPLAY, 0, StatusBarManager.DISABLE2_NOTIFICATION_SHADE,
false /* animate */);
TestableLooper.get(this).processAllMessages();
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarTest.java
index a45a5c4c3a0e..0d4046b6147b 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarTest.java
@@ -95,13 +95,13 @@ import com.android.systemui.statusbar.RemoteInputController;
import com.android.systemui.statusbar.StatusBarState;
import com.android.systemui.statusbar.StatusBarStateController;
import com.android.systemui.statusbar.notification.NotificationAlertingManager;
-import com.android.systemui.statusbar.notification.NotificationData;
-import com.android.systemui.statusbar.notification.NotificationData.Entry;
import com.android.systemui.statusbar.notification.NotificationEntryListener;
import com.android.systemui.statusbar.notification.NotificationEntryManager;
import com.android.systemui.statusbar.notification.NotificationFilter;
import com.android.systemui.statusbar.notification.NotificationInterruptionStateProvider;
import com.android.systemui.statusbar.notification.VisualStabilityManager;
+import com.android.systemui.statusbar.notification.collection.NotificationData;
+import com.android.systemui.statusbar.notification.collection.NotificationEntry;
import com.android.systemui.statusbar.notification.logging.NotificationLogger;
import com.android.systemui.statusbar.notification.row.NotificationGutsManager;
import com.android.systemui.statusbar.notification.stack.NotificationListContainer;
@@ -135,7 +135,7 @@ public class StatusBarTest extends SysuiTestCase {
@Mock private IDreamManager mDreamManager;
@Mock private ScrimController mScrimController;
@Mock private DozeScrimController mDozeScrimController;
- @Mock private ArrayList<Entry> mNotificationList;
+ @Mock private ArrayList<NotificationEntry> mNotificationList;
@Mock private BiometricUnlockController mBiometricUnlockController;
@Mock private NotificationData mNotificationData;
@Mock
@@ -409,7 +409,7 @@ public class StatusBarTest extends SysuiTestCase {
.build();
StatusBarNotification sbn = new StatusBarNotification("a", "a", 0, "a", 0, 0, n,
UserHandle.of(0), null, 0);
- NotificationData.Entry entry = new NotificationData.Entry(sbn);
+ NotificationEntry entry = new NotificationEntry(sbn);
entry.importance = IMPORTANCE_HIGH;
assertTrue(mNotificationInterruptionStateProvider.shouldHeadsUp(entry));
@@ -430,7 +430,7 @@ public class StatusBarTest extends SysuiTestCase {
.build();
StatusBarNotification sbn = new StatusBarNotification("a", "a", 0, "a", 0, 0, n,
UserHandle.of(0), null, 0);
- NotificationData.Entry entry = new NotificationData.Entry(sbn);
+ NotificationEntry entry = new NotificationEntry(sbn);
entry.importance = IMPORTANCE_HIGH;
assertFalse(mNotificationInterruptionStateProvider.shouldHeadsUp(entry));
@@ -447,7 +447,7 @@ public class StatusBarTest extends SysuiTestCase {
Notification n = new Notification.Builder(getContext(), "a").build();
StatusBarNotification sbn = new StatusBarNotification("a", "a", 0, "a", 0, 0, n,
UserHandle.of(0), null, 0);
- NotificationData.Entry entry = new NotificationData.Entry(sbn);
+ NotificationEntry entry = new NotificationEntry(sbn);
entry.suppressedVisualEffects = SUPPRESSED_EFFECT_PEEK;
entry.importance = IMPORTANCE_HIGH;
@@ -465,7 +465,7 @@ public class StatusBarTest extends SysuiTestCase {
Notification n = new Notification.Builder(getContext(), "a").build();
StatusBarNotification sbn = new StatusBarNotification("a", "a", 0, "a", 0, 0, n,
UserHandle.of(0), null, 0);
- NotificationData.Entry entry = new NotificationData.Entry(sbn);
+ NotificationEntry entry = new NotificationEntry(sbn);
entry.importance = IMPORTANCE_HIGH;
assertTrue(mNotificationInterruptionStateProvider.shouldHeadsUp(entry));
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/SmartReplyViewTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/SmartReplyViewTest.java
index c5bac9242b8b..fdc8ef12c6b0 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/SmartReplyViewTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/SmartReplyViewTest.java
@@ -50,7 +50,7 @@ import com.android.systemui.SysuiTestCase;
import com.android.systemui.plugins.ActivityStarter;
import com.android.systemui.plugins.ActivityStarter.OnDismissAction;
import com.android.systemui.statusbar.SmartReplyController;
-import com.android.systemui.statusbar.notification.NotificationData;
+import com.android.systemui.statusbar.notification.collection.NotificationEntry;
import com.android.systemui.statusbar.phone.KeyguardDismissUtil;
import com.android.systemui.statusbar.phone.ShadeController;
@@ -94,7 +94,7 @@ public class SmartReplyViewTest extends SysuiTestCase {
private int mSpacing;
@Mock private SmartReplyController mLogger;
- private NotificationData.Entry mEntry;
+ private NotificationEntry mEntry;
private Notification mNotification;
@Mock ActivityStarter mActivityStarter;
@@ -127,7 +127,7 @@ public class SmartReplyViewTest extends SysuiTestCase {
StatusBarNotification sbn = mock(StatusBarNotification.class);
when(sbn.getNotification()).thenReturn(mNotification);
when(sbn.getKey()).thenReturn(TEST_NOTIFICATION_KEY);
- mEntry = new NotificationData.Entry(sbn);
+ mEntry = new NotificationEntry(sbn);
mActionIcon = Icon.createWithResource(mContext, R.drawable.ic_person);
}
diff --git a/packages/services/PacProcessor/jni/com_android_pacprocessor_PacNative.cpp b/packages/services/PacProcessor/jni/com_android_pacprocessor_PacNative.cpp
index 846ff2517d12..a40cf1c06d07 100644
--- a/packages/services/PacProcessor/jni/com_android_pacprocessor_PacNative.cpp
+++ b/packages/services/PacProcessor/jni/com_android_pacprocessor_PacNative.cpp
@@ -27,23 +27,7 @@
namespace android {
-class ProxyErrorLogger : public net::ProxyErrorListener {
-public:
- ~ProxyErrorLogger() {
-
- }
- void AlertMessage(String16 message) {
- String8 str(message);
- ALOGD("Alert: %s", str.string());
- }
- void ErrorMessage(String16 message) {
- String8 str(message);
- ALOGE("Error: %s", str.string());
- }
-};
-
net::ProxyResolverV8* proxyResolver = NULL;
-ProxyErrorLogger* logger = NULL;
bool pacSet = false;
String16 jstringToString16(JNIEnv* env, jstring jstr) {
@@ -64,9 +48,7 @@ jstring string16ToJstring(JNIEnv* env, String16 string) {
static jboolean com_android_pacprocessor_PacNative_createV8ParserNativeLocked(JNIEnv* /* env */,
jobject) {
if (proxyResolver == NULL) {
- logger = new ProxyErrorLogger();
- proxyResolver = new net::ProxyResolverV8(net::ProxyResolverJSBindings::CreateDefault(),
- logger);
+ proxyResolver = new net::ProxyResolverV8(net::ProxyResolverJSBindings::CreateDefault());
pacSet = false;
return JNI_FALSE;
}
@@ -76,9 +58,7 @@ static jboolean com_android_pacprocessor_PacNative_createV8ParserNativeLocked(JN
static jboolean com_android_pacprocessor_PacNative_destroyV8ParserNativeLocked(JNIEnv* /* env */,
jobject) {
if (proxyResolver != NULL) {
- delete logger;
delete proxyResolver;
- logger = NULL;
proxyResolver = NULL;
return JNI_FALSE;
}
diff --git a/proto/src/metrics_constants/metrics_constants.proto b/proto/src/metrics_constants/metrics_constants.proto
index 3379b1b6d15a..2b399defc21b 100644
--- a/proto/src/metrics_constants/metrics_constants.proto
+++ b/proto/src/metrics_constants/metrics_constants.proto
@@ -3684,7 +3684,7 @@ message MetricsEvent {
ACTION_SETTINGS_TILE_CLICK = 830;
// OPEN: Notification unsnoozed. CLOSE: Notification snoozed. UPDATE: snoozed notification
- // updated
+ // updated. TYPE_DISMISS: snoozing canceled due to data being cleared on package
// CATEGORY: NOTIFICATION
// OS: O
NOTIFICATION_SNOOZED = 831;
diff --git a/services/Android.bp b/services/Android.bp
index 58a09977596f..01734f4051d3 100644
--- a/services/Android.bp
+++ b/services/Android.bp
@@ -28,6 +28,7 @@ java_library {
"services.net",
"services.print",
"services.restrictions",
+ "services.startop",
"services.usage",
"services.usb",
"services.voiceinteraction",
diff --git a/services/autofill/java/com/android/server/autofill/AutofillManagerService.java b/services/autofill/java/com/android/server/autofill/AutofillManagerService.java
index 1a6bee9daaf3..6cccd62d563f 100644
--- a/services/autofill/java/com/android/server/autofill/AutofillManagerService.java
+++ b/services/autofill/java/com/android/server/autofill/AutofillManagerService.java
@@ -70,6 +70,7 @@ import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.os.IResultReceiver;
import com.android.internal.util.DumpUtils;
import com.android.internal.util.Preconditions;
+import com.android.internal.util.SyncResultReceiver;
import com.android.server.FgThread;
import com.android.server.LocalServices;
import com.android.server.autofill.ui.AutoFillUI;
@@ -606,15 +607,15 @@ public final class AutofillManagerService
}
private void send(@NonNull IResultReceiver receiver, @Nullable String value) {
- send(receiver, AutofillManager.SyncResultReceiver.bundleFor(value));
+ send(receiver, SyncResultReceiver.bundleFor(value));
}
private void send(@NonNull IResultReceiver receiver, @Nullable String[] value) {
- send(receiver, AutofillManager.SyncResultReceiver.bundleFor(value));
+ send(receiver, SyncResultReceiver.bundleFor(value));
}
private void send(@NonNull IResultReceiver receiver, @Nullable Parcelable value) {
- send(receiver, AutofillManager.SyncResultReceiver.bundleFor(value));
+ send(receiver, SyncResultReceiver.bundleFor(value));
}
private void send(@NonNull IResultReceiver receiver, boolean value) {
diff --git a/services/autofill/java/com/android/server/autofill/AutofillManagerServiceImpl.java b/services/autofill/java/com/android/server/autofill/AutofillManagerServiceImpl.java
index 4b7efe1dfa71..a6bb049602a0 100644
--- a/services/autofill/java/com/android/server/autofill/AutofillManagerServiceImpl.java
+++ b/services/autofill/java/com/android/server/autofill/AutofillManagerServiceImpl.java
@@ -870,8 +870,11 @@ final class AutofillManagerServiceImpl
}
pw.print(prefix); pw.print("Default component: "); pw.println(getContext()
.getString(R.string.config_defaultAutofillService));
- pw.print(prefix); pw.print("mAugmentedAutofillNamer: ");
- mAugmentedAutofillResolver.dumpShort(pw); pw.println();
+
+ pw.print(prefix); pw.println("mAugmentedAutofillNamer: ");
+ pw.print(prefix2); mAugmentedAutofillResolver.dumpShort(pw); pw.println();
+ pw.print(prefix2); mAugmentedAutofillResolver.dumpShort(pw, mUserId); pw.println();
+
if (mRemoteAugmentedAutofillService != null) {
pw.print(prefix); pw.println("RemoteAugmentedAutofillService: ");
mRemoteAugmentedAutofillService.dump(prefix2, pw);
diff --git a/services/backup/java/com/android/server/backup/BackupManagerService.java b/services/backup/java/com/android/server/backup/BackupManagerService.java
index 6bd399042b29..12db4f37da58 100644
--- a/services/backup/java/com/android/server/backup/BackupManagerService.java
+++ b/services/backup/java/com/android/server/backup/BackupManagerService.java
@@ -39,7 +39,6 @@ import android.os.Binder;
import android.os.HandlerThread;
import android.os.IBinder;
import android.os.ParcelFileDescriptor;
-import android.os.RemoteException;
import android.os.Trace;
import android.os.UserHandle;
import android.util.Slog;
@@ -139,13 +138,7 @@ public class BackupManagerService {
mServiceUsers.put(userId, userBackupManagerService);
Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER, "backup enable");
- try {
- // TODO(b/121198604): Make enable file per-user and clean up indirection.
- mTrampoline.setBackupEnabledForUser(
- userId, UserBackupManagerFilePersistedSettings.readBackupEnableState(userId));
- } catch (RemoteException e) {
- // Can't happen, it's a local object.
- }
+ userBackupManagerService.initializeBackupEnableState();
Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER);
}
diff --git a/services/backup/java/com/android/server/backup/UserBackupManagerService.java b/services/backup/java/com/android/server/backup/UserBackupManagerService.java
index 725734a43946..b01117c438f0 100644
--- a/services/backup/java/com/android/server/backup/UserBackupManagerService.java
+++ b/services/backup/java/com/android/server/backup/UserBackupManagerService.java
@@ -560,6 +560,11 @@ public class UserBackupManagerService {
mWakelock = mPowerManager.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, "*backup*");
}
+ void initializeBackupEnableState() {
+ boolean isEnabled = UserBackupManagerFilePersistedSettings.readBackupEnableState(mUserId);
+ setBackupEnabled(isEnabled);
+ }
+
/** Cleans up state when the user of this service is stopped. */
void tearDownService() {
mUserBackupThread.quit();
diff --git a/services/backup/java/com/android/server/backup/internal/SetupObserver.java b/services/backup/java/com/android/server/backup/internal/SetupObserver.java
index defcacc50a18..62ae3eb8e192 100644
--- a/services/backup/java/com/android/server/backup/internal/SetupObserver.java
+++ b/services/backup/java/com/android/server/backup/internal/SetupObserver.java
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2018 The Android Open Source Project
+ * Copyright (C) 2019 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
diff --git a/services/contentcapture/java/com/android/server/contentcapture/ContentCapturePerUserService.java b/services/contentcapture/java/com/android/server/contentcapture/ContentCapturePerUserService.java
index c467935f1996..09aa4212654e 100644
--- a/services/contentcapture/java/com/android/server/contentcapture/ContentCapturePerUserService.java
+++ b/services/contentcapture/java/com/android/server/contentcapture/ContentCapturePerUserService.java
@@ -95,7 +95,7 @@ final class ContentCapturePerUserService
final ComponentName serviceComponentName = updateServiceInfoLocked();
if (serviceComponentName == null) {
- Slog.w(TAG, "updateRemoteService(): no service componennt name");
+ if (mMaster.debug) Slog.d(TAG, "updateRemoteService(): no service component name");
return;
}
@@ -163,7 +163,10 @@ final class ContentCapturePerUserService
@NonNull String sessionId, int uid, int flags,
@NonNull IResultReceiver clientReceiver) {
if (!isEnabledLocked()) {
- setClientState(clientReceiver, ContentCaptureSession.STATE_DISABLED, /* binder=*/ null);
+ // TODO: it would be better to split in differet reasons, like
+ // STATE_DISABLED_NO_SERVICE and STATE_DISABLED_BY_DEVICE_POLICY
+ setClientState(clientReceiver, ContentCaptureSession.STATE_DISABLED_NO_SERVICE,
+ /* binder= */ null);
return;
}
final ComponentName serviceComponentName = getServiceComponentName();
@@ -195,8 +198,8 @@ final class ContentCapturePerUserService
Slog.w(TAG, "startSession(id=" + existingSession + ", token=" + activityToken
+ ": ignoring because service is not set");
// TODO(b/111276913): use a new disabled state?
- setClientState(clientReceiver, ContentCaptureSession.STATE_DISABLED,
- /* binder=*/ null);
+ setClientState(clientReceiver, ContentCaptureSession.STATE_DISABLED_NO_SERVICE,
+ /* binder= */ null);
return;
}
@@ -285,7 +288,7 @@ final class ContentCapturePerUserService
final int numSessions = mSessions.size();
for (int i = 0; i < numSessions; i++) {
final ContentCaptureServerSession session = mSessions.valueAt(i);
- session.destroyLocked(true);
+ session.destroyLocked(/* notifyRemoteService= */ true);
}
mSessions.clear();
}
diff --git a/services/core/java/com/android/server/LocationManagerService.java b/services/core/java/com/android/server/LocationManagerService.java
index 2346cfc07a83..5cea56ebf2fc 100644
--- a/services/core/java/com/android/server/LocationManagerService.java
+++ b/services/core/java/com/android/server/LocationManagerService.java
@@ -64,7 +64,6 @@ import android.os.Bundle;
import android.os.Handler;
import android.os.IBinder;
import android.os.Looper;
-import android.os.Message;
import android.os.PowerManager;
import android.os.Process;
import android.os.RemoteException;
@@ -87,6 +86,7 @@ import com.android.internal.location.ProviderRequest;
import com.android.internal.os.BackgroundThread;
import com.android.internal.util.ArrayUtils;
import com.android.internal.util.DumpUtils;
+import com.android.internal.util.Preconditions;
import com.android.server.location.AbstractLocationProvider;
import com.android.server.location.ActivityRecognitionProxy;
import com.android.server.location.GeocoderProxy;
@@ -117,6 +117,11 @@ import java.util.Map;
import java.util.Map.Entry;
import java.util.NoSuchElementException;
import java.util.Set;
+import java.util.concurrent.Callable;
+import java.util.concurrent.CopyOnWriteArrayList;
+import java.util.concurrent.ExecutionException;
+import java.util.concurrent.Executors;
+import java.util.concurrent.FutureTask;
/**
* The service class that manages LocationProviders and issues location
@@ -171,10 +176,7 @@ public class LocationManagerService extends ILocationManager.Stub {
private static final LocationRequest DEFAULT_LOCATION_REQUEST = new LocationRequest();
private final Context mContext;
- private final AppOpsManager mAppOps;
-
- // used internally for synchronization
- private final Object mLock = new Object();
+ private AppOpsManager mAppOps;
// --- fields below are final after systemRunning() ---
private LocationFudger mLocationFudger;
@@ -186,7 +188,7 @@ public class LocationManagerService extends ILocationManager.Stub {
private GeocoderProxy mGeocodeProvider;
private GnssStatusListenerHelper mGnssStatusProvider;
private INetInitiatedListener mNetInitiatedListener;
- private LocationWorkerHandler mLocationHandler;
+ private final Handler mHandler;
private PassiveProvider mPassiveProvider; // track passive provider for special cases
private LocationBlacklist mBlacklist;
private GnssMeasurementsProvider mGnssMeasurementsProvider;
@@ -195,8 +197,6 @@ public class LocationManagerService extends ILocationManager.Stub {
private boolean mLocationControllerExtraPackageEnabled;
private IGpsGeofenceHardware mGpsGeofenceProxy;
- // --- fields below are protected by mLock ---
-
// Mock (test) providers
private final HashMap<String, MockProvider> mMockProviders =
new HashMap<>();
@@ -205,8 +205,8 @@ public class LocationManagerService extends ILocationManager.Stub {
private final HashMap<Object, Receiver> mReceivers = new HashMap<>();
// currently installed providers (with mocks replacing real providers)
- private final ArrayList<LocationProvider> mProviders =
- new ArrayList<>();
+ private final CopyOnWriteArrayList<LocationProvider> mProviders =
+ new CopyOnWriteArrayList<>();
// real providers, saved here when mocked out
private final HashMap<String, LocationProvider> mRealProviders =
@@ -232,8 +232,8 @@ public class LocationManagerService extends ILocationManager.Stub {
// all providers that operate over proxy, for authorizing incoming location and whitelisting
// throttling
- private final ArrayList<LocationProviderProxy> mProxyProviders =
- new ArrayList<>();
+ private final CopyOnWriteArrayList<LocationProviderProxy> mProxyProviders =
+ new CopyOnWriteArrayList<>();
private final ArraySet<String> mBackgroundThrottlePackageWhitelist = new ArraySet<>();
@@ -246,9 +246,6 @@ public class LocationManagerService extends ILocationManager.Stub {
private int mCurrentUserId = UserHandle.USER_SYSTEM;
private int[] mCurrentUserProfiles = new int[]{UserHandle.USER_SYSTEM};
- // Maximum age of last location returned to clients with foreground-only location permissions.
- private long mLastLocationMaxAgeMs;
-
private GnssLocationProvider.GnssSystemInfoProvider mGnssSystemInfoProvider;
private GnssLocationProvider.GnssMetricsProvider mGnssMetricsProvider;
@@ -261,7 +258,7 @@ public class LocationManagerService extends ILocationManager.Stub {
public LocationManagerService(Context context) {
super();
mContext = context;
- mAppOps = (AppOpsManager) context.getSystemService(Context.APP_OPS_SERVICE);
+ mHandler = BackgroundThread.getHandler();
// Let the package manager query which are the default location
// providers as they get certain permissions granted by default.
@@ -271,132 +268,92 @@ public class LocationManagerService extends ILocationManager.Stub {
userId -> mContext.getResources().getStringArray(
com.android.internal.R.array.config_locationProviderPackageNames));
- if (D) Log.d(TAG, "Constructed");
-
// most startup is deferred until systemRunning()
}
public void systemRunning() {
- synchronized (mLock) {
- if (D) Log.d(TAG, "systemRunning()");
-
- // fetch package manager
- mPackageManager = mContext.getPackageManager();
-
- // fetch power manager
- mPowerManager = (PowerManager) mContext.getSystemService(Context.POWER_SERVICE);
-
- // fetch activity manager
- mActivityManager
- = (ActivityManager) mContext.getSystemService(Context.ACTIVITY_SERVICE);
-
- // prepare worker thread
- mLocationHandler = new LocationWorkerHandler(BackgroundThread.get().getLooper());
-
- // prepare mLocationHandler's dependents
- mLocationFudger = new LocationFudger(mContext, mLocationHandler);
- mBlacklist = new LocationBlacklist(mContext, mLocationHandler);
- mBlacklist.init();
- mGeofenceManager = new GeofenceManager(mContext, mBlacklist);
-
- // Monitor for app ops mode changes.
- AppOpsManager.OnOpChangedListener callback
- = new AppOpsManager.OnOpChangedInternalListener() {
- public void onOpChanged(int op, String packageName) {
- mLocationHandler.post(() -> {
- synchronized (mLock) {
- for (Receiver receiver : mReceivers.values()) {
- receiver.updateMonitoring(true);
- }
- applyAllProviderRequirementsLocked();
- }
- });
- }
- };
- mAppOps.startWatchingMode(AppOpsManager.OP_COARSE_LOCATION, null,
- AppOpsManager.WATCH_FOREGROUND_CHANGES, callback);
+ runInternal(this::initialize);
+ }
+
+ private void initialize() {
+ Preconditions.checkState(Looper.myLooper() == mHandler.getLooper());
+
+ mAppOps = (AppOpsManager) mContext.getSystemService(Context.APP_OPS_SERVICE);
+ mPackageManager = mContext.getPackageManager();
+ mPowerManager = (PowerManager) mContext.getSystemService(Context.POWER_SERVICE);
+ mActivityManager = (ActivityManager) mContext.getSystemService(Context.ACTIVITY_SERVICE);
+
+ // prepare mHandler's dependents
+ mLocationFudger = new LocationFudger(mContext, mHandler);
+ mBlacklist = new LocationBlacklist(mContext, mHandler);
+ mBlacklist.init();
+ mGeofenceManager = new GeofenceManager(mContext, mBlacklist);
+
+ mAppOps.startWatchingMode(
+ AppOpsManager.OP_COARSE_LOCATION,
+ null,
+ AppOpsManager.WATCH_FOREGROUND_CHANGES,
+ new AppOpsManager.OnOpChangedInternalListener() {
+ public void onOpChanged(int op, String packageName) {
+ mHandler.post(() -> onAppOpChanged());
+ }
+ });
- PackageManager.OnPermissionsChangedListener permissionListener = uid -> {
- synchronized (mLock) {
- applyAllProviderRequirementsLocked();
- }
- };
- mPackageManager.addOnPermissionsChangeListener(permissionListener);
+ mPackageManager.addOnPermissionsChangeListener(
+ uid -> runInternal(this::onPermissionsChanged));
- // listen for background/foreground changes
- ActivityManager.OnUidImportanceListener uidImportanceListener =
- (uid, importance) -> mLocationHandler.post(
- () -> onUidImportanceChanged(uid, importance));
- mActivityManager.addOnUidImportanceListener(uidImportanceListener,
- FOREGROUND_IMPORTANCE_CUTOFF);
+ mActivityManager.addOnUidImportanceListener(
+ (uid, importance) -> mHandler.post(
+ () -> onUidImportanceChanged(uid, importance)),
+ FOREGROUND_IMPORTANCE_CUTOFF);
- mUserManager = (UserManager) mContext.getSystemService(Context.USER_SERVICE);
- updateUserProfiles(mCurrentUserId);
+ mUserManager = (UserManager) mContext.getSystemService(Context.USER_SERVICE);
+ updateUserProfiles(mCurrentUserId);
- updateBackgroundThrottlingWhitelistLocked();
- updateLastLocationMaxAgeLocked();
+ updateBackgroundThrottlingWhitelist();
- // prepare providers
- loadProvidersLocked();
- updateProvidersSettingsLocked();
- for (LocationProvider provider : mProviders) {
- applyRequirementsLocked(provider.getName());
- }
+ // prepare providers
+ loadProvidersLocked();
+ updateProvidersSettings();
+ for (LocationProvider provider : mProviders) {
+ applyRequirements(provider.getName());
}
// listen for settings changes
mContext.getContentResolver().registerContentObserver(
Settings.Secure.getUriFor(Settings.Secure.LOCATION_PROVIDERS_ALLOWED), true,
- new ContentObserver(mLocationHandler) {
+ new ContentObserver(mHandler) {
@Override
public void onChange(boolean selfChange) {
- synchronized (mLock) {
- updateProvidersSettingsLocked();
- }
+ onProviderAllowedChanged();
}
}, UserHandle.USER_ALL);
mContext.getContentResolver().registerContentObserver(
Settings.Global.getUriFor(Settings.Global.LOCATION_BACKGROUND_THROTTLE_INTERVAL_MS),
true,
- new ContentObserver(mLocationHandler) {
+ new ContentObserver(mHandler) {
@Override
public void onChange(boolean selfChange) {
- synchronized (mLock) {
- for (LocationProvider provider : mProviders) {
- applyRequirementsLocked(provider.getName());
- }
- }
+ onBackgroundThrottleIntervalChanged();
}
}, UserHandle.USER_ALL);
mContext.getContentResolver().registerContentObserver(
- Settings.Global.getUriFor(Settings.Global.LOCATION_LAST_LOCATION_MAX_AGE_MILLIS),
- true,
- new ContentObserver(mLocationHandler) {
- @Override
- public void onChange(boolean selfChange) {
- synchronized (mLock) {
- updateLastLocationMaxAgeLocked();
- }
- }
- }
- );
- mContext.getContentResolver().registerContentObserver(
Settings.Global.getUriFor(
Settings.Global.LOCATION_BACKGROUND_THROTTLE_PACKAGE_WHITELIST),
true,
- new ContentObserver(mLocationHandler) {
+ new ContentObserver(mHandler) {
@Override
public void onChange(boolean selfChange) {
- synchronized (mLock) {
- updateBackgroundThrottlingWhitelistLocked();
- for (LocationProvider provider : mProviders) {
- applyRequirementsLocked(provider.getName());
- }
- }
+ onBackgroundThrottleWhitelistChanged();
}
}, UserHandle.USER_ALL);
- mPackageMonitor.register(mContext, mLocationHandler.getLooper(), true);
+ new PackageMonitor() {
+ @Override
+ public void onPackageDisappeared(String packageName, int reason) {
+ LocationManagerService.this.onPackageDisappeared(packageName);
+ }
+ }.register(mContext, mHandler.getLooper(), true);
// listen for user change
IntentFilter intentFilter = new IntentFilter();
@@ -415,73 +372,170 @@ public class LocationManagerService extends ILocationManager.Stub {
updateUserProfiles(mCurrentUserId);
}
}
- }, UserHandle.ALL, intentFilter, null, mLocationHandler);
+ }, UserHandle.ALL, intentFilter, null, mHandler);
}
- private void onUidImportanceChanged(int uid, int importance) {
- boolean foreground = isImportanceForeground(importance);
- HashSet<String> affectedProviders = new HashSet<>(mRecordsByProvider.size());
- synchronized (mLock) {
- for (Entry<String, ArrayList<UpdateRecord>> entry
- : mRecordsByProvider.entrySet()) {
- String provider = entry.getKey();
- for (UpdateRecord record : entry.getValue()) {
- if (record.mReceiver.mIdentity.mUid == uid
- && record.mIsForegroundUid != foreground) {
- if (D) {
- Log.d(TAG, "request from uid " + uid + " is now "
- + (foreground ? "foreground" : "background)"));
- }
- record.updateForeground(foreground);
+ // will block until completion and propagate exceptions, and thus should be used from binder
+ // threads, particuarily binder threads from components that sit above LMS (ie, not location
+ // providers).
+ private void runFromBinderBlocking(Runnable runnable) throws RemoteException {
+ runFromBinderBlocking(Executors.callable(runnable));
+ }
- if (!isThrottlingExemptLocked(record.mReceiver.mIdentity)) {
- affectedProviders.add(provider);
- }
- }
+ // will block until completion and propagate exceptions, and thus should be used from binder
+ // threads, particuarily binder threads from components that sit above LMS (ie, not location
+ // providers).
+ private <T> T runFromBinderBlocking(Callable<T> callable) throws RemoteException {
+ FutureTask<T> task = new FutureTask<>(callable);
+ long identity = Binder.clearCallingIdentity();
+ try {
+ runInternal(task);
+ } finally {
+ Binder.restoreCallingIdentity(identity);
+ }
+ try {
+ return task.get();
+ } catch (ExecutionException e) {
+ // binder calls can handle 3 types of exceptions, runtimeexception and error (which can
+ // be thrown any time), and remote exception. we transfer all of these exceptions from
+ // the execution thread to the binder thread so that they may propagate normally. note
+ // that we are loosing some context in doing so (losing the stack trace from the binder
+ // thread).
+ if (e.getCause() instanceof RemoteException) {
+ throw (RemoteException) e.getCause();
+ } else if (e.getCause() instanceof RuntimeException) {
+ throw (RuntimeException) e.getCause();
+ } else if (e.getCause() instanceof Error) {
+ throw (Error) e.getCause();
+ }
+
+ // callers should not throw checked exceptions
+ Log.wtf(TAG, "caller threw checked exception", e);
+ throw new UnsupportedOperationException(e);
+ } catch (InterruptedException e) {
+ throw new RemoteException("Binder call interrupted", e, true, true);
+ }
+ }
+
+ // will return immediately and will not propagate exceptions. should be used for non-binder work
+ // that needs to be shifted onto the location thread, primarily listeners that do not support
+ // running on arbitrary threads.
+ private void runInternal(Runnable runnable) {
+ // it would be a better use of resources to use locks to manage cross thread access to
+ // various pieces on information. however, the history of the location package has mostly
+ // shown that this is difficult to maintain in a multi-dev environment, and tends to always
+ // lead towards the use of uber-locks and deadlocks. using a single thread to run everything
+ // is more understandable for most devs, and seems less likely to result in future bugs
+ if (Looper.myLooper() == mHandler.getLooper()) {
+ runnable.run();
+ } else {
+ mHandler.post(runnable);
+ }
+ }
+
+ private void onAppOpChanged() {
+ Preconditions.checkState(Looper.myLooper() == mHandler.getLooper());
+ for (Receiver receiver : mReceivers.values()) {
+ receiver.updateMonitoring(true);
+ }
+ for (LocationProvider p : mProviders) {
+ applyRequirements(p.getName());
+ }
+ }
+
+ private void onPermissionsChanged() {
+ Preconditions.checkState(Looper.myLooper() == mHandler.getLooper());
+ for (LocationProvider p : mProviders) {
+ applyRequirements(p.getName());
+ }
+ }
+
+ private void onProviderAllowedChanged() {
+ Preconditions.checkState(Looper.myLooper() == mHandler.getLooper());
+ updateProvidersSettings();
+ }
+
+ private void onPackageDisappeared(String packageName) {
+ ArrayList<Receiver> deadReceivers = null;
+
+ for (Receiver receiver : mReceivers.values()) {
+ if (receiver.mIdentity.mPackageName.equals(packageName)) {
+ if (deadReceivers == null) {
+ deadReceivers = new ArrayList<>();
}
+ deadReceivers.add(receiver);
}
- for (String provider : affectedProviders) {
- applyRequirementsLocked(provider);
+ }
+
+ // perform removal outside of mReceivers loop
+ if (deadReceivers != null) {
+ for (Receiver receiver : deadReceivers) {
+ removeUpdates(receiver);
}
+ }
+ }
- for (Entry<IBinder, Identity> entry : mGnssMeasurementsListeners.entrySet()) {
- Identity callerIdentity = entry.getValue();
- if (callerIdentity.mUid == uid) {
+ private void onUidImportanceChanged(int uid, int importance) {
+ Preconditions.checkState(Looper.myLooper() == mHandler.getLooper());
+ boolean foreground = isImportanceForeground(importance);
+ HashSet<String> affectedProviders = new HashSet<>(mRecordsByProvider.size());
+ for (Entry<String, ArrayList<UpdateRecord>> entry
+ : mRecordsByProvider.entrySet()) {
+ String provider = entry.getKey();
+ for (UpdateRecord record : entry.getValue()) {
+ if (record.mReceiver.mIdentity.mUid == uid
+ && record.mIsForegroundUid != foreground) {
if (D) {
- Log.d(TAG, "gnss measurements listener from uid " + uid
- + " is now " + (foreground ? "foreground" : "background)"));
+ Log.d(TAG, "request from uid " + uid + " is now "
+ + (foreground ? "foreground" : "background)"));
}
- if (foreground || isThrottlingExemptLocked(entry.getValue())) {
- mGnssMeasurementsProvider.addListener(
- IGnssMeasurementsListener.Stub.asInterface(entry.getKey()),
- callerIdentity.mUid, callerIdentity.mPackageName);
- } else {
- mGnssMeasurementsProvider.removeListener(
- IGnssMeasurementsListener.Stub.asInterface(entry.getKey()));
+ record.updateForeground(foreground);
+
+ if (!isThrottlingExemptLocked(record.mReceiver.mIdentity)) {
+ affectedProviders.add(provider);
}
}
}
+ }
+ for (String provider : affectedProviders) {
+ applyRequirements(provider);
+ }
- for (Entry<IBinder, Identity> entry : mGnssNavigationMessageListeners.entrySet()) {
- Identity callerIdentity = entry.getValue();
- if (callerIdentity.mUid == uid) {
- if (D) {
- Log.d(TAG, "gnss navigation message listener from uid "
- + uid + " is now "
- + (foreground ? "foreground" : "background)"));
- }
- if (foreground || isThrottlingExemptLocked(entry.getValue())) {
- mGnssNavigationMessageProvider.addListener(
- IGnssNavigationMessageListener.Stub.asInterface(entry.getKey()),
- callerIdentity.mUid, callerIdentity.mPackageName);
- } else {
- mGnssNavigationMessageProvider.removeListener(
- IGnssNavigationMessageListener.Stub.asInterface(entry.getKey()));
- }
+ for (Entry<IBinder, Identity> entry : mGnssMeasurementsListeners.entrySet()) {
+ Identity callerIdentity = entry.getValue();
+ if (callerIdentity.mUid == uid) {
+ if (D) {
+ Log.d(TAG, "gnss measurements listener from uid " + uid
+ + " is now " + (foreground ? "foreground" : "background)"));
+ }
+ if (foreground || isThrottlingExemptLocked(entry.getValue())) {
+ mGnssMeasurementsProvider.addListener(
+ IGnssMeasurementsListener.Stub.asInterface(entry.getKey()),
+ callerIdentity.mUid, callerIdentity.mPackageName);
+ } else {
+ mGnssMeasurementsProvider.removeListener(
+ IGnssMeasurementsListener.Stub.asInterface(entry.getKey()));
}
}
+ }
- // TODO(b/120449926): The GNSS status listeners should be handled similar to the above.
+ for (Entry<IBinder, Identity> entry : mGnssNavigationMessageListeners.entrySet()) {
+ Identity callerIdentity = entry.getValue();
+ if (callerIdentity.mUid == uid) {
+ if (D) {
+ Log.d(TAG, "gnss navigation message listener from uid "
+ + uid + " is now "
+ + (foreground ? "foreground" : "background)"));
+ }
+ if (foreground || isThrottlingExemptLocked(entry.getValue())) {
+ mGnssNavigationMessageProvider.addListener(
+ IGnssNavigationMessageListener.Stub.asInterface(entry.getKey()),
+ callerIdentity.mUid, callerIdentity.mPackageName);
+ } else {
+ mGnssNavigationMessageProvider.removeListener(
+ IGnssNavigationMessageListener.Stub.asInterface(entry.getKey()));
+ }
+ }
}
}
@@ -489,31 +543,33 @@ public class LocationManagerService extends ILocationManager.Stub {
return importance <= FOREGROUND_IMPORTANCE_CUTOFF;
}
- /**
- * Makes a list of userids that are related to the current user. This is
- * relevant when using managed profiles. Otherwise the list only contains
- * the current user.
- *
- * @param currentUserId the current user, who might have an alter-ego.
- */
- private void updateUserProfiles(int currentUserId) {
- int[] profileIds = mUserManager.getProfileIdsWithDisabled(currentUserId);
- synchronized (mLock) {
- mCurrentUserProfiles = profileIds;
+ private void onBackgroundThrottleIntervalChanged() {
+ Preconditions.checkState(Looper.myLooper() == mHandler.getLooper());
+ for (LocationProvider provider : mProviders) {
+ applyRequirements(provider.getName());
}
}
- /**
- * Checks if the specified userId matches any of the current foreground
- * users stored in mCurrentUserProfiles.
- */
- private boolean isCurrentProfile(int userId) {
- synchronized (mLock) {
- return ArrayUtils.contains(mCurrentUserProfiles, userId);
+ private void onBackgroundThrottleWhitelistChanged() {
+ Preconditions.checkState(Looper.myLooper() == mHandler.getLooper());
+ updateBackgroundThrottlingWhitelist();
+ for (LocationProvider provider : mProviders) {
+ applyRequirements(provider.getName());
}
}
+ private void updateUserProfiles(int currentUserId) {
+ Preconditions.checkState(Looper.myLooper() == mHandler.getLooper());
+ mCurrentUserProfiles = mUserManager.getProfileIdsWithDisabled(currentUserId);
+ }
+
+ private boolean isCurrentProfile(int userId) {
+ Preconditions.checkState(Looper.myLooper() == mHandler.getLooper());
+ return ArrayUtils.contains(mCurrentUserProfiles, userId);
+ }
+
private void ensureFallbackFusedProviderPresentLocked(String[] pkgs) {
+ Preconditions.checkState(Looper.myLooper() == mHandler.getLooper());
PackageManager pm = mContext.getPackageManager();
String systemPackageName = mContext.getPackageName();
ArrayList<HashSet<Signature>> sigSets = ServiceWatcher.getSignatureSets(mContext, pkgs);
@@ -584,12 +640,13 @@ public class LocationManagerService extends ILocationManager.Stub {
}
private void loadProvidersLocked() {
+ Preconditions.checkState(Looper.myLooper() == mHandler.getLooper());
// create a passive location provider, which is always enabled
LocationProvider passiveProviderManager = new LocationProvider(
LocationManager.PASSIVE_PROVIDER);
PassiveProvider passiveProvider = new PassiveProvider(passiveProviderManager);
- addProviderLocked(passiveProviderManager);
+ addProvider(passiveProviderManager);
mPassiveProvider = passiveProvider;
if (GnssLocationProvider.isSupported()) {
@@ -598,14 +655,14 @@ public class LocationManagerService extends ILocationManager.Stub {
LocationManager.GPS_PROVIDER);
GnssLocationProvider gnssProvider = new GnssLocationProvider(mContext,
gnssProviderManager,
- mLocationHandler.getLooper());
+ mHandler.getLooper());
mGnssSystemInfoProvider = gnssProvider.getGnssSystemInfoProvider();
mGnssBatchingProvider = gnssProvider.getGnssBatchingProvider();
mGnssMetricsProvider = gnssProvider.getGnssMetricsProvider();
mGnssStatusProvider = gnssProvider.getGnssStatusProvider();
mNetInitiatedListener = gnssProvider.getNetInitiatedListener();
- addProviderLocked(gnssProviderManager);
+ addProvider(gnssProviderManager);
mRealProviders.put(LocationManager.GPS_PROVIDER, gnssProviderManager);
mGnssMeasurementsProvider = gnssProvider.getGnssMeasurementsProvider();
mGnssNavigationMessageProvider = gnssProvider.getGnssNavigationMessageProvider();
@@ -647,7 +704,7 @@ public class LocationManagerService extends ILocationManager.Stub {
if (networkProvider != null) {
mRealProviders.put(LocationManager.NETWORK_PROVIDER, networkProviderManager);
mProxyProviders.add(networkProvider);
- addProviderLocked(networkProviderManager);
+ addProvider(networkProviderManager);
} else {
Slog.w(TAG, "no network location provider found");
}
@@ -663,7 +720,7 @@ public class LocationManagerService extends ILocationManager.Stub {
com.android.internal.R.string.config_fusedLocationProviderPackageName,
com.android.internal.R.array.config_locationProviderPackageNames);
if (fusedProvider != null) {
- addProviderLocked(fusedProviderManager);
+ addProvider(fusedProviderManager);
mProxyProviders.add(fusedProvider);
mRealProviders.put(LocationManager.FUSED_PROVIDER, fusedProviderManager);
} else {
@@ -728,28 +785,22 @@ public class LocationManagerService extends ILocationManager.Stub {
Boolean.parseBoolean(fragments[7]) /* supportsBearing */,
Integer.parseInt(fragments[8]) /* powerRequirement */,
Integer.parseInt(fragments[9]) /* accuracy */);
- addTestProviderLocked(name, properties);
+ addTestProvider(name, properties);
}
}
- /**
- * Called when the device's active user changes.
- *
- * @param userId the new active user's UserId
- */
private void switchUser(int userId) {
+ Preconditions.checkState(Looper.myLooper() == mHandler.getLooper());
if (mCurrentUserId == userId) {
return;
}
mBlacklist.switchUser(userId);
- mLocationHandler.removeMessages(MSG_LOCATION_CHANGED);
- synchronized (mLock) {
- mLastLocation.clear();
- mLastLocationCoarseInterval.clear();
- updateUserProfiles(userId);
- updateProvidersSettingsLocked();
- mCurrentUserId = userId;
- }
+ mHandler.removeMessages(MSG_LOCATION_CHANGED);
+ mLastLocation.clear();
+ mLastLocationCoarseInterval.clear();
+ updateUserProfiles(userId);
+ updateProvidersSettings();
+ mCurrentUserId = userId;
}
private static final class Identity {
@@ -808,10 +859,13 @@ public class LocationManagerService extends ILocationManager.Stub {
}
public void setRequest(ProviderRequest request, WorkSource workSource) {
+ Preconditions.checkState(Looper.myLooper() == mHandler.getLooper());
mProvider.setRequest(request, workSource);
}
public void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
+ Preconditions.checkState(Looper.myLooper() == mHandler.getLooper());
+
pw.println(mName + " provider:");
pw.println(" setting=" + mSettingsEnabled);
pw.println(" enabled=" + mEnabled);
@@ -820,34 +874,38 @@ public class LocationManagerService extends ILocationManager.Stub {
}
public long getStatusUpdateTime() {
+ Preconditions.checkState(Looper.myLooper() == mHandler.getLooper());
return mProvider.getStatusUpdateTime();
}
public int getStatus(Bundle extras) {
+ Preconditions.checkState(Looper.myLooper() == mHandler.getLooper());
return mProvider.getStatus(extras);
}
public void sendExtraCommand(String command, Bundle extras) {
+ Preconditions.checkState(Looper.myLooper() == mHandler.getLooper());
mProvider.sendExtraCommand(command, extras);
}
// called from any thread
@Override
public void onReportLocation(Location location) {
- runOnHandler(() -> LocationManagerService.this.reportLocation(location,
+ // no security check necessary because this is coming from an internal-only interface
+ runInternal(() -> LocationManagerService.this.handleLocationChanged(location,
mProvider == mPassiveProvider));
}
// called from any thread
@Override
public void onReportLocation(List<Location> locations) {
- runOnHandler(() -> LocationManagerService.this.reportLocationBatch(locations));
+ LocationManagerService.this.reportLocationBatch(locations);
}
// called from any thread
@Override
public void onSetEnabled(boolean enabled) {
- runOnHandler(() -> {
+ runInternal(() -> {
if (enabled == mEnabled) {
return;
}
@@ -872,18 +930,16 @@ public class LocationManagerService extends ILocationManager.Stub {
Settings.Secure.LOCATION_PROVIDERS_ALLOWED,
"-" + LocationManager.FUSED_PROVIDER, mCurrentUserId);
- synchronized (mLock) {
- if (!enabled) {
- // If any provider has been disabled, clear all last locations for all
- // providers. This is to be on the safe side in case a provider has location
- // derived from this disabled provider.
- mLastLocation.clear();
- mLastLocationCoarseInterval.clear();
- }
-
- updateProviderListenersLocked(mName);
+ if (!enabled) {
+ // If any provider has been disabled, clear all last locations for all
+ // providers. This is to be on the safe side in case a provider has location
+ // derived from this disabled provider.
+ mLastLocation.clear();
+ mLastLocationCoarseInterval.clear();
}
+ updateProviderListeners(mName);
+
mContext.sendBroadcastAsUser(new Intent(LocationManager.PROVIDERS_CHANGED_ACTION),
UserHandle.ALL);
});
@@ -891,34 +947,27 @@ public class LocationManagerService extends ILocationManager.Stub {
@Override
public void onSetProperties(ProviderProperties properties) {
- runOnHandler(() -> mProperties = properties);
+ runInternal(() -> {
+ mProperties = properties;
+ });
}
private void setSettingsEnabled(boolean enabled) {
- synchronized (mLock) {
- if (mSettingsEnabled == enabled) {
- return;
- }
-
- mSettingsEnabled = enabled;
- if (!mSettingsEnabled) {
- // if any provider has been disabled, clear all last locations for all
- // providers. this is to be on the safe side in case a provider has location
- // derived from this disabled provider.
- mLastLocation.clear();
- mLastLocationCoarseInterval.clear();
- updateProviderListenersLocked(mName);
- } else if (mEnabled) {
- updateProviderListenersLocked(mName);
- }
+ Preconditions.checkState(Looper.myLooper() == mHandler.getLooper());
+ if (mSettingsEnabled == enabled) {
+ return;
}
- }
- private void runOnHandler(Runnable runnable) {
- if (Looper.myLooper() == mLocationHandler.getLooper()) {
- runnable.run();
- } else {
- mLocationHandler.post(runnable);
+ mSettingsEnabled = enabled;
+ if (!mSettingsEnabled) {
+ // if any provider has been disabled, clear all last locations for all
+ // providers. this is to be on the safe side in case a provider has location
+ // derived from this disabled provider.
+ mLastLocation.clear();
+ mLastLocationCoarseInterval.clear();
+ updateProviderListeners(mName);
+ } else if (mEnabled) {
+ updateProviderListeners(mName);
}
}
}
@@ -1022,7 +1071,7 @@ public class LocationManagerService extends ILocationManager.Stub {
// See if receiver has any enabled update records. Also note if any update records
// are high power (has a high power provider with an interval under a threshold).
for (UpdateRecord updateRecord : mUpdateRecords.values()) {
- if (isAllowedByUserSettingsLockedForUser(updateRecord.mProvider,
+ if (isAllowedByUserSettingsForUser(updateRecord.mProvider,
mCurrentUserId)) {
requestingLocation = true;
LocationManagerService.LocationProvider locationProvider
@@ -1122,7 +1171,7 @@ public class LocationManagerService extends ILocationManager.Stub {
synchronized (this) {
// synchronize to ensure incrementPendingBroadcastsLocked()
// is called before decrementPendingBroadcasts()
- mPendingIntent.send(mContext, 0, statusChanged, this, mLocationHandler,
+ mPendingIntent.send(mContext, 0, statusChanged, this, mHandler,
getResolutionPermission(mAllowedResolutionLevel),
PendingIntentUtils.createDontSendToRestrictedAppsBundle(null));
// call this after broadcasting so we do not increment
@@ -1158,7 +1207,7 @@ public class LocationManagerService extends ILocationManager.Stub {
synchronized (this) {
// synchronize to ensure incrementPendingBroadcastsLocked()
// is called before decrementPendingBroadcasts()
- mPendingIntent.send(mContext, 0, locationChanged, this, mLocationHandler,
+ mPendingIntent.send(mContext, 0, locationChanged, this, mHandler,
getResolutionPermission(mAllowedResolutionLevel),
PendingIntentUtils.createDontSendToRestrictedAppsBundle(null));
// call this after broadcasting so we do not increment
@@ -1201,7 +1250,7 @@ public class LocationManagerService extends ILocationManager.Stub {
synchronized (this) {
// synchronize to ensure incrementPendingBroadcastsLocked()
// is called before decrementPendingBroadcasts()
- mPendingIntent.send(mContext, 0, providerIntent, this, mLocationHandler,
+ mPendingIntent.send(mContext, 0, providerIntent, this, mHandler,
getResolutionPermission(mAllowedResolutionLevel),
PendingIntentUtils.createDontSendToRestrictedAppsBundle(null));
// call this after broadcasting so we do not increment
@@ -1219,12 +1268,12 @@ public class LocationManagerService extends ILocationManager.Stub {
public void binderDied() {
if (D) Log.d(TAG, "Location listener died");
- synchronized (mLock) {
- removeUpdatesLocked(this);
- }
- synchronized (this) {
- clearPendingBroadcastsLocked();
- }
+ runInternal(() -> {
+ removeUpdates(this);
+ synchronized (this) {
+ clearPendingBroadcastsLocked();
+ }
+ });
}
@Override
@@ -1261,28 +1310,22 @@ public class LocationManagerService extends ILocationManager.Stub {
}
@Override
- public void locationCallbackFinished(ILocationListener listener) {
+ public void locationCallbackFinished(ILocationListener listener) throws RemoteException {
//Do not use getReceiverLocked here as that will add the ILocationListener to
//the receiver list if it is not found. If it is not found then the
//LocationListener was removed when it had a pending broadcast and should
//not be added back.
- synchronized (mLock) {
+ runFromBinderBlocking(() -> {
IBinder binder = listener.asBinder();
Receiver receiver = mReceivers.get(binder);
if (receiver != null) {
synchronized (receiver) {
- // so wakelock calls will succeed
- long identity = Binder.clearCallingIdentity();
receiver.decrementPendingBroadcastsLocked();
- Binder.restoreCallingIdentity(identity);
}
}
- }
+ });
}
- /**
- * Returns the year of the GNSS hardware.
- */
@Override
public int getGnssYearOfHardware() {
if (mGnssSystemInfoProvider != null) {
@@ -1292,10 +1335,6 @@ public class LocationManagerService extends ILocationManager.Stub {
}
}
-
- /**
- * Returns the model name of the GNSS hardware.
- */
@Override
@Nullable
public String getGnssHardwareModelName() {
@@ -1306,10 +1345,6 @@ public class LocationManagerService extends ILocationManager.Stub {
}
}
- /**
- * Runs some checks for GNSS (FINE) level permissions, used by several methods which directly
- * (try to) access GNSS information at this layer.
- */
private boolean hasGnssPermissions(String packageName) {
int allowedResolutionLevel = getCallerAllowedResolutionLevel();
checkResolutionLevelIsSufficientForProviderUse(
@@ -1329,9 +1364,6 @@ public class LocationManagerService extends ILocationManager.Stub {
return hasLocationAccess;
}
- /**
- * Returns the GNSS batching size, if available.
- */
@Override
public int getGnssBatchSize(String packageName) {
mContext.enforceCallingPermission(android.Manifest.permission.LOCATION_HARDWARE,
@@ -1344,10 +1376,6 @@ public class LocationManagerService extends ILocationManager.Stub {
}
}
- /**
- * Adds a callback for GNSS Batching events, if permissions allow, which are transported
- * to potentially multiple listeners by the BatchedLocationCallbackTransport above this.
- */
@Override
public boolean addGnssBatchingCallback(IBatchedLocationCallback callback, String packageName) {
mContext.enforceCallingPermission(android.Manifest.permission.LOCATION_HARDWARE,
@@ -1391,9 +1419,6 @@ public class LocationManagerService extends ILocationManager.Stub {
}
}
- /**
- * Removes callback for GNSS batching
- */
@Override
public void removeGnssBatchingCallback() {
try {
@@ -1408,10 +1433,6 @@ public class LocationManagerService extends ILocationManager.Stub {
mGnssBatchingDeathCallback = null;
}
-
- /**
- * Starts GNSS batching, if available.
- */
@Override
public boolean startGnssBatch(long periodNanos, boolean wakeOnFifoFull, String packageName) {
mContext.enforceCallingPermission(android.Manifest.permission.LOCATION_HARDWARE,
@@ -1432,9 +1453,6 @@ public class LocationManagerService extends ILocationManager.Stub {
return mGnssBatchingProvider.start(periodNanos, wakeOnFifoFull);
}
- /**
- * Flushes a GNSS batch in progress
- */
@Override
public void flushGnssBatch(String packageName) {
mContext.enforceCallingPermission(android.Manifest.permission.LOCATION_HARDWARE,
@@ -1454,9 +1472,6 @@ public class LocationManagerService extends ILocationManager.Stub {
}
}
- /**
- * Stops GNSS batching
- */
@Override
public boolean stopGnssBatch() {
mContext.enforceCallingPermission(android.Manifest.permission.LOCATION_HARDWARE,
@@ -1475,7 +1490,7 @@ public class LocationManagerService extends ILocationManager.Stub {
checkCallerIsProvider();
// Currently used only for GNSS locations - update permissions check if changed
- if (isAllowedByUserSettingsLockedForUser(LocationManager.GPS_PROVIDER, mCurrentUserId)) {
+ if (isAllowedByUserSettingsForUser(LocationManager.GPS_PROVIDER, mCurrentUserId)) {
if (mGnssBatchingCallback == null) {
Slog.e(TAG, "reportLocationBatch() called without active Callback");
return;
@@ -1490,35 +1505,28 @@ public class LocationManagerService extends ILocationManager.Stub {
}
}
- private void addProviderLocked(LocationProvider provider) {
+ private void addProvider(LocationProvider provider) {
+ Preconditions.checkState(Looper.myLooper() == mHandler.getLooper());
mProviders.add(provider);
mProvidersByName.put(provider.getName(), provider);
}
- private void removeProviderLocked(LocationProvider provider) {
+ private void removeProvider(LocationProvider provider) {
+ Preconditions.checkState(Looper.myLooper() == mHandler.getLooper());
mProviders.remove(provider);
mProvidersByName.remove(provider.getName());
}
- /**
- * Returns "true" if access to the specified location provider is allowed by the specified
- * user's settings. Access to all location providers is forbidden to non-location-provider
- * processes belonging to background users.
- *
- * @param provider the name of the location provider
- * @param userId the user id to query
- */
- private boolean isAllowedByUserSettingsLockedForUser(String provider, int userId) {
+ private boolean isAllowedByUserSettingsForUser(String provider, int userId) {
+ Preconditions.checkState(Looper.myLooper() == mHandler.getLooper());
if (LocationManager.PASSIVE_PROVIDER.equals(provider)) {
- return isLocationEnabledForUser(userId);
+ return isLocationEnabledForUserInternal(userId);
}
if (LocationManager.FUSED_PROVIDER.equals(provider)) {
- return isLocationEnabledForUser(userId);
+ return isLocationEnabledForUserInternal(userId);
}
- synchronized (mLock) {
- if (mMockProviders.containsKey(provider)) {
- return isLocationEnabledForUser(userId);
- }
+ if (mMockProviders.containsKey(provider)) {
+ return isLocationEnabledForUserInternal(userId);
}
long identity = Binder.clearCallingIdentity();
@@ -1533,29 +1541,14 @@ public class LocationManagerService extends ILocationManager.Stub {
}
}
-
- /**
- * Returns "true" if access to the specified location provider is allowed by the specified
- * user's settings. Access to all location providers is forbidden to non-location-provider
- * processes belonging to background users.
- *
- * @param provider the name of the location provider
- * @param uid the requestor's UID
- * @param userId the user id to query
- */
- private boolean isAllowedByUserSettingsLocked(String provider, int uid, int userId) {
+ private boolean isAllowedByUserSettings(String provider, int uid, int userId) {
+ Preconditions.checkState(Looper.myLooper() == mHandler.getLooper());
if (!isCurrentProfile(UserHandle.getUserId(uid)) && !isUidALocationProvider(uid)) {
return false;
}
- return isAllowedByUserSettingsLockedForUser(provider, userId);
+ return isAllowedByUserSettingsForUser(provider, userId);
}
- /**
- * Returns the permission string associated with the specified resolution level.
- *
- * @param resolutionLevel the resolution level
- * @return the permission string
- */
private String getResolutionPermission(int resolutionLevel) {
switch (resolutionLevel) {
case RESOLUTION_LEVEL_FINE:
@@ -1567,13 +1560,6 @@ public class LocationManagerService extends ILocationManager.Stub {
}
}
- /**
- * Returns the resolution level allowed to the given PID/UID pair.
- *
- * @param pid the PID
- * @param uid the UID
- * @return resolution level allowed to the pid/uid pair
- */
private int getAllowedResolutionLevel(int pid, int uid) {
if (mContext.checkPermission(android.Manifest.permission.ACCESS_FINE_LOCATION,
pid, uid) == PERMISSION_GRANTED) {
@@ -1586,32 +1572,16 @@ public class LocationManagerService extends ILocationManager.Stub {
}
}
- /**
- * Returns the resolution level allowed to the caller
- *
- * @return resolution level allowed to caller
- */
private int getCallerAllowedResolutionLevel() {
return getAllowedResolutionLevel(Binder.getCallingPid(), Binder.getCallingUid());
}
- /**
- * Throw SecurityException if specified resolution level is insufficient to use geofences.
- *
- * @param allowedResolutionLevel resolution level allowed to caller
- */
private void checkResolutionLevelIsSufficientForGeofenceUse(int allowedResolutionLevel) {
if (allowedResolutionLevel < RESOLUTION_LEVEL_FINE) {
throw new SecurityException("Geofence usage requires ACCESS_FINE_LOCATION permission");
}
}
- /**
- * Return the minimum resolution level required to use the specified location provider.
- *
- * @param provider the name of the location provider
- * @return minimum resolution level required for provider
- */
private int getMinimumResolutionLevelForProviderUse(String provider) {
if (LocationManager.GPS_PROVIDER.equals(provider) ||
LocationManager.PASSIVE_PROVIDER.equals(provider)) {
@@ -1643,13 +1613,6 @@ public class LocationManagerService extends ILocationManager.Stub {
return RESOLUTION_LEVEL_FINE; // if in doubt, require FINE
}
- /**
- * Throw SecurityException if specified resolution level is insufficient to use the named
- * location provider.
- *
- * @param allowedResolutionLevel resolution level allowed to caller
- * @param providerName the name of the location provider
- */
private void checkResolutionLevelIsSufficientForProviderUse(int allowedResolutionLevel,
String providerName) {
int requiredResolutionLevel = getMinimumResolutionLevelForProviderUse(providerName);
@@ -1668,20 +1631,6 @@ public class LocationManagerService extends ILocationManager.Stub {
}
}
- /**
- * Throw SecurityException if WorkSource use is not allowed (i.e. can't blame other packages
- * for battery).
- */
- private void checkDeviceStatsAllowed() {
- mContext.enforceCallingOrSelfPermission(
- android.Manifest.permission.UPDATE_DEVICE_STATS, null);
- }
-
- private void checkUpdateAppOpsAllowed() {
- mContext.enforceCallingOrSelfPermission(
- android.Manifest.permission.UPDATE_APP_OPS_STATS, null);
- }
-
public static int resolutionLevelToOp(int allowedResolutionLevel) {
if (allowedResolutionLevel != RESOLUTION_LEVEL_NONE) {
if (allowedResolutionLevel == RESOLUTION_LEVEL_COARSE) {
@@ -1739,19 +1688,15 @@ public class LocationManagerService extends ILocationManager.Stub {
*/
@Override
public List<String> getAllProviders() {
- ArrayList<String> out;
- synchronized (mLock) {
- out = new ArrayList<>(mProviders.size());
- for (LocationProvider provider : mProviders) {
- String name = provider.getName();
- if (LocationManager.FUSED_PROVIDER.equals(name)) {
- continue;
- }
- out.add(name);
+ ArrayList<String> providers = new ArrayList<>(mProviders.size());
+ for (LocationProvider provider : mProviders) {
+ String name = provider.getName();
+ if (LocationManager.FUSED_PROVIDER.equals(name)) {
+ continue;
}
+ providers.add(name);
}
- if (D) Log.d(TAG, "getAllProviders()=" + out);
- return out;
+ return providers;
}
/**
@@ -1760,39 +1705,33 @@ public class LocationManagerService extends ILocationManager.Stub {
* Can return passive provider, but never returns fused provider.
*/
@Override
- public List<String> getProviders(Criteria criteria, boolean enabledOnly) {
+ public List<String> getProviders(Criteria criteria, boolean enabledOnly)
+ throws RemoteException {
int allowedResolutionLevel = getCallerAllowedResolutionLevel();
- ArrayList<String> out;
int uid = Binder.getCallingUid();
- long identity = Binder.clearCallingIdentity();
- try {
- synchronized (mLock) {
- out = new ArrayList<>(mProviders.size());
- for (LocationProvider provider : mProviders) {
- String name = provider.getName();
- if (LocationManager.FUSED_PROVIDER.equals(name)) {
- continue;
- }
- if (allowedResolutionLevel >= getMinimumResolutionLevelForProviderUse(name)) {
- if (enabledOnly
- && !isAllowedByUserSettingsLocked(name, uid, mCurrentUserId)) {
- continue;
- }
- if (criteria != null
- && !android.location.LocationProvider.propertiesMeetCriteria(
- name, provider.getProperties(), criteria)) {
- continue;
- }
- out.add(name);
- }
+ return runFromBinderBlocking(() -> {
+ ArrayList<String> providers = new ArrayList<>(mProviders.size());
+ for (LocationProvider provider : mProviders) {
+ String name = provider.getName();
+ if (LocationManager.FUSED_PROVIDER.equals(name)) {
+ continue;
+ }
+ if (allowedResolutionLevel < getMinimumResolutionLevelForProviderUse(name)) {
+ continue;
+ }
+ if (enabledOnly
+ && !isAllowedByUserSettings(name, uid, mCurrentUserId)) {
+ continue;
+ }
+ if (criteria != null
+ && !android.location.LocationProvider.propertiesMeetCriteria(
+ name, provider.getProperties(), criteria)) {
+ continue;
}
+ providers.add(name);
}
- } finally {
- Binder.restoreCallingIdentity(identity);
- }
-
- if (D) Log.d(TAG, "getProviders()=" + out);
- return out;
+ return providers;
+ });
}
/**
@@ -1803,59 +1742,51 @@ public class LocationManagerService extends ILocationManager.Stub {
* some simplified logic.
*/
@Override
- public String getBestProvider(Criteria criteria, boolean enabledOnly) {
- String result;
-
+ public String getBestProvider(Criteria criteria, boolean enabledOnly) throws RemoteException {
List<String> providers = getProviders(criteria, enabledOnly);
- if (!providers.isEmpty()) {
- result = pickBest(providers);
- if (D) Log.d(TAG, "getBestProvider(" + criteria + ", " + enabledOnly + ")=" + result);
- return result;
+ if (providers.isEmpty()) {
+ providers = getProviders(null, enabledOnly);
}
- providers = getProviders(null, enabledOnly);
+
if (!providers.isEmpty()) {
- result = pickBest(providers);
- if (D) Log.d(TAG, "getBestProvider(" + criteria + ", " + enabledOnly + ")=" + result);
- return result;
+ if (providers.contains(LocationManager.GPS_PROVIDER)) {
+ return LocationManager.GPS_PROVIDER;
+ } else if (providers.contains(LocationManager.NETWORK_PROVIDER)) {
+ return LocationManager.NETWORK_PROVIDER;
+ } else {
+ return providers.get(0);
+ }
}
- if (D) Log.d(TAG, "getBestProvider(" + criteria + ", " + enabledOnly + ")=" + null);
return null;
}
- private String pickBest(List<String> providers) {
- if (providers.contains(LocationManager.GPS_PROVIDER)) {
- return LocationManager.GPS_PROVIDER;
- } else if (providers.contains(LocationManager.NETWORK_PROVIDER)) {
- return LocationManager.NETWORK_PROVIDER;
- } else {
- return providers.get(0);
- }
- }
-
@Override
- public boolean providerMeetsCriteria(String provider, Criteria criteria) {
- LocationProvider p = mProvidersByName.get(provider);
- if (p == null) {
- throw new IllegalArgumentException("provider=" + provider);
- }
+ public boolean providerMeetsCriteria(String provider, Criteria criteria)
+ throws RemoteException {
+ return runFromBinderBlocking(() -> {
+ LocationProvider p = mProvidersByName.get(provider);
+ if (p == null) {
+ throw new IllegalArgumentException("provider=" + provider);
+ }
- boolean result = android.location.LocationProvider.propertiesMeetCriteria(
- p.getName(), p.getProperties(), criteria);
- if (D) Log.d(TAG, "providerMeetsCriteria(" + provider + ", " + criteria + ")=" + result);
- return result;
+ return android.location.LocationProvider.propertiesMeetCriteria(
+ p.getName(), p.getProperties(), criteria);
+ });
}
- private void updateProvidersSettingsLocked() {
+ private void updateProvidersSettings() {
+ Preconditions.checkState(Looper.myLooper() == mHandler.getLooper());
for (LocationProvider p : mProviders) {
- p.setSettingsEnabled(isAllowedByUserSettingsLockedForUser(p.getName(), mCurrentUserId));
+ p.setSettingsEnabled(isAllowedByUserSettingsForUser(p.getName(), mCurrentUserId));
}
mContext.sendBroadcastAsUser(new Intent(LocationManager.MODE_CHANGED_ACTION),
UserHandle.ALL);
}
- private void updateProviderListenersLocked(String provider) {
+ private void updateProviderListeners(String provider) {
+ Preconditions.checkState(Looper.myLooper() == mHandler.getLooper());
LocationProvider p = mProvidersByName.get(provider);
if (p == null) return;
@@ -1880,14 +1811,15 @@ public class LocationManagerService extends ILocationManager.Stub {
if (deadReceivers != null) {
for (int i = deadReceivers.size() - 1; i >= 0; i--) {
- removeUpdatesLocked(deadReceivers.get(i));
+ removeUpdates(deadReceivers.get(i));
}
}
- applyRequirementsLocked(provider);
+ applyRequirements(provider);
}
- private void applyRequirementsLocked(String provider) {
+ private void applyRequirements(String provider) {
+ Preconditions.checkState(Looper.myLooper() == mHandler.getLooper());
LocationProvider p = mProvidersByName.get(provider);
if (p == null) return;
@@ -1993,14 +1925,13 @@ public class LocationManagerService extends ILocationManager.Stub {
}
@Override
- public String[] getBackgroundThrottlingWhitelist() {
- synchronized (mLock) {
- return mBackgroundThrottlePackageWhitelist.toArray(
- new String[0]);
- }
+ public String[] getBackgroundThrottlingWhitelist() throws RemoteException {
+ return runFromBinderBlocking(
+ () -> mBackgroundThrottlePackageWhitelist.toArray(new String[0]));
}
- private void updateBackgroundThrottlingWhitelistLocked() {
+ private void updateBackgroundThrottlingWhitelist() {
+ Preconditions.checkState(Looper.myLooper() == mHandler.getLooper());
String setting = Settings.Global.getString(
mContext.getContentResolver(),
Settings.Global.LOCATION_BACKGROUND_THROTTLE_PACKAGE_WHITELIST);
@@ -2015,15 +1946,8 @@ public class LocationManagerService extends ILocationManager.Stub {
Arrays.asList(setting.split(",")));
}
- private void updateLastLocationMaxAgeLocked() {
- mLastLocationMaxAgeMs =
- Settings.Global.getLong(
- mContext.getContentResolver(),
- Settings.Global.LOCATION_LAST_LOCATION_MAX_AGE_MILLIS,
- DEFAULT_LAST_LOCATION_MAX_AGE_MS);
- }
-
private boolean isThrottlingExemptLocked(Identity identity) {
+ Preconditions.checkState(Looper.myLooper() == mHandler.getLooper());
if (identity.mUid == Process.SYSTEM_UID) {
return true;
}
@@ -2105,7 +2029,7 @@ public class LocationManagerService extends ILocationManager.Stub {
// and also remove the Receiver if it has no more update records
if (receiverRecords.size() == 0) {
- removeUpdatesLocked(mReceiver);
+ removeUpdates(mReceiver);
}
}
@@ -2119,8 +2043,9 @@ public class LocationManagerService extends ILocationManager.Stub {
}
}
- private Receiver getReceiverLocked(ILocationListener listener, int pid, int uid,
+ private Receiver getReceiver(ILocationListener listener, int pid, int uid,
String packageName, WorkSource workSource, boolean hideFromAppOps) {
+ Preconditions.checkState(Looper.myLooper() == mHandler.getLooper());
IBinder binder = listener.asBinder();
Receiver receiver = mReceivers.get(binder);
if (receiver == null) {
@@ -2137,8 +2062,9 @@ public class LocationManagerService extends ILocationManager.Stub {
return receiver;
}
- private Receiver getReceiverLocked(PendingIntent intent, int pid, int uid, String packageName,
+ private Receiver getReceiver(PendingIntent intent, int pid, int uid, String packageName,
WorkSource workSource, boolean hideFromAppOps) {
+ Preconditions.checkState(Looper.myLooper() == mHandler.getLooper());
Receiver receiver = mReceivers.get(intent);
if (receiver == null) {
receiver = new Receiver(null, intent, pid, uid, packageName, workSource,
@@ -2202,29 +2128,9 @@ public class LocationManagerService extends ILocationManager.Stub {
throw new SecurityException("invalid package name: " + packageName);
}
- private void checkPendingIntent(PendingIntent intent) {
- if (intent == null) {
- throw new IllegalArgumentException("invalid pending intent: " + null);
- }
- }
-
- private Receiver checkListenerOrIntentLocked(ILocationListener listener, PendingIntent intent,
- int pid, int uid, String packageName, WorkSource workSource, boolean hideFromAppOps) {
- if (intent == null && listener == null) {
- throw new IllegalArgumentException("need either listener or intent");
- } else if (intent != null && listener != null) {
- throw new IllegalArgumentException("cannot register both listener and intent");
- } else if (intent != null) {
- checkPendingIntent(intent);
- return getReceiverLocked(intent, pid, uid, packageName, workSource, hideFromAppOps);
- } else {
- return getReceiverLocked(listener, pid, uid, packageName, workSource, hideFromAppOps);
- }
- }
-
@Override
public void requestLocationUpdates(LocationRequest request, ILocationListener listener,
- PendingIntent intent, String packageName) {
+ PendingIntent intent, String packageName) throws RemoteException {
if (request == null) request = DEFAULT_LOCATION_REQUEST;
checkPackageName(packageName);
int allowedResolutionLevel = getCallerAllowedResolutionLevel();
@@ -2232,11 +2138,13 @@ public class LocationManagerService extends ILocationManager.Stub {
request.getProvider());
WorkSource workSource = request.getWorkSource();
if (workSource != null && !workSource.isEmpty()) {
- checkDeviceStatsAllowed();
+ mContext.enforceCallingOrSelfPermission(
+ Manifest.permission.UPDATE_DEVICE_STATS, null);
}
boolean hideFromAppOps = request.getHideFromAppOps();
if (hideFromAppOps) {
- checkUpdateAppOpsAllowed();
+ mContext.enforceCallingOrSelfPermission(
+ Manifest.permission.UPDATE_APP_OPS_STATS, null);
}
boolean callerHasLocationHardwarePermission =
mContext.checkCallingPermission(android.Manifest.permission.LOCATION_HARDWARE)
@@ -2246,25 +2154,33 @@ public class LocationManagerService extends ILocationManager.Stub {
final int pid = Binder.getCallingPid();
final int uid = Binder.getCallingUid();
- // providers may use public location API's, need to clear identity
- long identity = Binder.clearCallingIdentity();
- try {
- // We don't check for MODE_IGNORED here; we will do that when we go to deliver
- // a location.
- checkLocationAccess(pid, uid, packageName, allowedResolutionLevel);
- synchronized (mLock) {
- Receiver recevier = checkListenerOrIntentLocked(listener, intent, pid, uid,
- packageName, workSource, hideFromAppOps);
- requestLocationUpdatesLocked(sanitizedRequest, recevier, uid, packageName);
- }
- } finally {
- Binder.restoreCallingIdentity(identity);
+ // We don't check for MODE_IGNORED here; we will do that when we go to deliver
+ // a location.
+ checkLocationAccess(pid, uid, packageName, allowedResolutionLevel);
+
+ if (intent == null && listener == null) {
+ throw new IllegalArgumentException("need either listener or intent");
+ } else if (intent != null && listener != null) {
+ throw new IllegalArgumentException("cannot register both listener and intent");
}
+
+ runFromBinderBlocking(() -> {
+ Receiver receiver;
+ if (intent != null) {
+ receiver = getReceiver(intent, pid, uid, packageName, workSource,
+ hideFromAppOps);
+ } else {
+ receiver = getReceiver(listener, pid, uid, packageName, workSource,
+ hideFromAppOps);
+ }
+ requestLocationUpdates(sanitizedRequest, receiver, uid, packageName);
+ });
}
- private void requestLocationUpdatesLocked(LocationRequest request, Receiver receiver,
+ private void requestLocationUpdates(LocationRequest request, Receiver receiver,
int uid, String packageName) {
+ Preconditions.checkState(Looper.myLooper() == mHandler.getLooper());
// Figure out the provider. Either its explicitly request (legacy use cases), or
// use the fused provider
if (request == null) request = DEFAULT_LOCATION_REQUEST;
@@ -2293,7 +2209,7 @@ public class LocationManagerService extends ILocationManager.Stub {
}
if (provider.isEnabled()) {
- applyRequirementsLocked(name);
+ applyRequirements(name);
} else {
// Notify the listener that updates are currently disabled
receiver.callProviderEnabledLocked(name, false);
@@ -2305,27 +2221,31 @@ public class LocationManagerService extends ILocationManager.Stub {
@Override
public void removeUpdates(ILocationListener listener, PendingIntent intent,
- String packageName) {
+ String packageName) throws RemoteException {
checkPackageName(packageName);
- final int pid = Binder.getCallingPid();
- final int uid = Binder.getCallingUid();
+ int pid = Binder.getCallingPid();
+ int uid = Binder.getCallingUid();
- synchronized (mLock) {
- Receiver receiver = checkListenerOrIntentLocked(listener, intent, pid, uid,
- packageName, null, false);
+ if (intent == null && listener == null) {
+ throw new IllegalArgumentException("need either listener or intent");
+ } else if (intent != null && listener != null) {
+ throw new IllegalArgumentException("cannot register both listener and intent");
+ }
- // providers may use public location API's, need to clear identity
- long identity = Binder.clearCallingIdentity();
- try {
- removeUpdatesLocked(receiver);
- } finally {
- Binder.restoreCallingIdentity(identity);
+ runFromBinderBlocking(() -> {
+ Receiver receiver;
+ if (intent != null) {
+ receiver = getReceiver(intent, pid, uid, packageName, null, false);
+ } else {
+ receiver = getReceiver(listener, pid, uid, packageName, null, false);
}
- }
+ removeUpdates(receiver);
+ });
}
- private void removeUpdatesLocked(Receiver receiver) {
+ private void removeUpdates(Receiver receiver) {
+ Preconditions.checkState(Looper.myLooper() == mHandler.getLooper());
if (D) Log.i(TAG, "remove " + Integer.toHexString(System.identityHashCode(receiver)));
if (mReceivers.remove(receiver.mKey) != null && receiver.isListener()) {
@@ -2352,20 +2272,14 @@ public class LocationManagerService extends ILocationManager.Stub {
// update provider
for (String provider : providers) {
- applyRequirementsLocked(provider);
- }
- }
-
- private void applyAllProviderRequirementsLocked() {
- for (LocationProvider p : mProviders) {
- applyRequirementsLocked(p.getName());
+ applyRequirements(provider);
}
}
@Override
- public Location getLastLocation(LocationRequest request, String packageName) {
- if (D) Log.d(TAG, "getLastLocation: " + request);
- if (request == null) request = DEFAULT_LOCATION_REQUEST;
+ public Location getLastLocation(LocationRequest r, String packageName) throws RemoteException {
+ if (D) Log.d(TAG, "getLastLocation: " + r);
+ LocationRequest request = r != null ? r : DEFAULT_LOCATION_REQUEST;
int allowedResolutionLevel = getCallerAllowedResolutionLevel();
checkPackageName(packageName);
checkResolutionLevelIsSufficientForProviderUse(allowedResolutionLevel,
@@ -2391,68 +2305,60 @@ public class LocationManagerService extends ILocationManager.Stub {
}
return null;
}
+ } finally {
+ Binder.restoreCallingIdentity(identity);
+ }
- synchronized (mLock) {
- // Figure out the provider. Either its explicitly request (deprecated API's),
- // or use the fused provider
- String name = request.getProvider();
- if (name == null) name = LocationManager.FUSED_PROVIDER;
- LocationProvider provider = mProvidersByName.get(name);
- if (provider == null) return null;
+ return runFromBinderBlocking(() -> {
+ // Figure out the provider. Either its explicitly request (deprecated API's),
+ // or use the fused provider
+ String name = request.getProvider();
+ if (name == null) name = LocationManager.FUSED_PROVIDER;
+ LocationProvider provider = mProvidersByName.get(name);
+ if (provider == null) return null;
- if (!isAllowedByUserSettingsLocked(name, uid, mCurrentUserId)) return null;
+ if (!isAllowedByUserSettings(name, uid, mCurrentUserId)) return null;
- Location location;
- if (allowedResolutionLevel < RESOLUTION_LEVEL_FINE) {
- // Make sure that an app with coarse permissions can't get frequent location
- // updates by calling LocationManager.getLastKnownLocation repeatedly.
- location = mLastLocationCoarseInterval.get(name);
- } else {
- location = mLastLocation.get(name);
- }
- if (location == null) {
- return null;
- }
+ Location location;
+ if (allowedResolutionLevel < RESOLUTION_LEVEL_FINE) {
+ // Make sure that an app with coarse permissions can't get frequent location
+ // updates by calling LocationManager.getLastKnownLocation repeatedly.
+ location = mLastLocationCoarseInterval.get(name);
+ } else {
+ location = mLastLocation.get(name);
+ }
+ if (location == null) {
+ return null;
+ }
- // Don't return stale location to apps with foreground-only location permission.
- String op = resolutionLevelToOpStr(allowedResolutionLevel);
- long locationAgeMs = SystemClock.elapsedRealtime() -
- location.getElapsedRealtimeNanos() / NANOS_PER_MILLI;
- if ((locationAgeMs > mLastLocationMaxAgeMs)
- && (mAppOps.unsafeCheckOp(op, uid, packageName)
- == AppOpsManager.MODE_FOREGROUND)) {
- return null;
- }
+ // Don't return stale location to apps with foreground-only location permission.
+ String op = resolutionLevelToOpStr(allowedResolutionLevel);
+ long locationAgeMs = SystemClock.elapsedRealtime()
+ - location.getElapsedRealtimeNanos() / NANOS_PER_MILLI;
+ if ((locationAgeMs > Settings.Global.getLong(
+ mContext.getContentResolver(),
+ Settings.Global.LOCATION_LAST_LOCATION_MAX_AGE_MILLIS,
+ DEFAULT_LAST_LOCATION_MAX_AGE_MS))
+ && (mAppOps.unsafeCheckOp(op, uid, packageName)
+ == AppOpsManager.MODE_FOREGROUND)) {
+ return null;
+ }
- if (allowedResolutionLevel < RESOLUTION_LEVEL_FINE) {
- Location noGPSLocation = location.getExtraLocation(
- Location.EXTRA_NO_GPS_LOCATION);
- if (noGPSLocation != null) {
- return new Location(mLocationFudger.getOrCreate(noGPSLocation));
- }
- } else {
- return new Location(location);
+ if (allowedResolutionLevel < RESOLUTION_LEVEL_FINE) {
+ Location noGPSLocation = location.getExtraLocation(
+ Location.EXTRA_NO_GPS_LOCATION);
+ if (noGPSLocation != null) {
+ return new Location(mLocationFudger.getOrCreate(noGPSLocation));
}
+ } else {
+ return new Location(location);
}
return null;
- } finally {
- Binder.restoreCallingIdentity(identity);
- }
+ });
}
- /**
- * Provides an interface to inject and set the last location if location is not available
- * currently.
- *
- * This helps in cases where the product (Cars for example) has saved the last known location
- * before powering off. This interface lets the client inject the saved location while the GPS
- * chipset is getting its first fix, there by improving user experience.
- *
- * @param location - Location object to inject
- * @return true if update was successful, false if not
- */
@Override
- public boolean injectLocation(Location location) {
+ public boolean injectLocation(Location location) throws RemoteException {
mContext.enforceCallingPermission(android.Manifest.permission.LOCATION_HARDWARE,
"Location Hardware permission not granted to inject location");
mContext.enforceCallingPermission(android.Manifest.permission.ACCESS_FINE_LOCATION,
@@ -2464,29 +2370,31 @@ public class LocationManagerService extends ILocationManager.Stub {
}
return false;
}
- LocationProvider p = null;
- String provider = location.getProvider();
- if (provider != null) {
- p = mProvidersByName.get(provider);
- }
- if (p == null) {
- if (D) {
- Log.d(TAG, "injectLocation(): unknown provider");
+
+ return runFromBinderBlocking(() -> {
+ LocationProvider p = null;
+ String provider = location.getProvider();
+ if (provider != null) {
+ p = mProvidersByName.get(provider);
}
- return false;
- }
- synchronized (mLock) {
- if (!isAllowedByUserSettingsLockedForUser(provider, mCurrentUserId)) {
+ if (p == null) {
+ if (D) {
+ Log.d(TAG, "injectLocation(): unknown provider");
+ }
+ return false;
+ }
+ if (!isAllowedByUserSettingsForUser(provider, mCurrentUserId)) {
if (D) {
- Log.d(TAG, "Location disabled in Settings for current user:" + mCurrentUserId);
+ Log.d(TAG, "Location disabled in Settings for current user:"
+ + mCurrentUserId);
}
return false;
} else {
// NOTE: If last location is already available, location is not injected. If
- // provider's normal source (like a GPS chipset) have already provided an output,
+ // provider's normal source (like a GPS chipset) have already provided an output
// there is no need to inject this location.
if (mLastLocation.get(provider) == null) {
- updateLastLocationLocked(location, provider);
+ updateLastLocation(location, provider);
} else {
if (D) {
Log.d(TAG, "injectLocation(): Location exists. Not updating");
@@ -2494,8 +2402,8 @@ public class LocationManagerService extends ILocationManager.Stub {
return false;
}
}
- }
- return true;
+ return true;
+ });
}
@Override
@@ -2504,7 +2412,9 @@ public class LocationManagerService extends ILocationManager.Stub {
if (request == null) request = DEFAULT_LOCATION_REQUEST;
int allowedResolutionLevel = getCallerAllowedResolutionLevel();
checkResolutionLevelIsSufficientForGeofenceUse(allowedResolutionLevel);
- checkPendingIntent(intent);
+ if (intent == null) {
+ throw new IllegalArgumentException("invalid pending intent: " + null);
+ }
checkPackageName(packageName);
checkResolutionLevelIsSufficientForProviderUse(allowedResolutionLevel,
request.getProvider());
@@ -2515,7 +2425,10 @@ public class LocationManagerService extends ILocationManager.Stub {
LocationRequest sanitizedRequest = createSanitizedRequest(request, allowedResolutionLevel,
callerHasLocationHardwarePermission);
- if (D) Log.d(TAG, "requestGeofence: " + sanitizedRequest + " " + geofence + " " + intent);
+ if (D) {
+ Log.d(TAG, "requestGeofence: " + sanitizedRequest + " " + geofence + " "
+ + intent);
+ }
// geo-fence manager uses the public location API, need to clear identity
int uid = Binder.getCallingUid();
@@ -2536,7 +2449,9 @@ public class LocationManagerService extends ILocationManager.Stub {
@Override
public void removeGeofence(Geofence geofence, PendingIntent intent, String packageName) {
- checkPendingIntent(intent);
+ if (intent == null) {
+ throw new IllegalArgumentException("invalid pending intent: " + null);
+ }
checkPackageName(packageName);
if (D) Log.d(TAG, "removeGeofence: " + geofence + " " + intent);
@@ -2568,14 +2483,14 @@ public class LocationManagerService extends ILocationManager.Stub {
@Override
public boolean addGnssMeasurementsListener(
- IGnssMeasurementsListener listener, String packageName) {
+ IGnssMeasurementsListener listener, String packageName) throws RemoteException {
if (!hasGnssPermissions(packageName) || mGnssMeasurementsProvider == null) {
return false;
}
- synchronized (mLock) {
- Identity callerIdentity
- = new Identity(Binder.getCallingUid(), Binder.getCallingPid(), packageName);
+ Identity callerIdentity =
+ new Identity(Binder.getCallingUid(), Binder.getCallingPid(), packageName);
+ return runFromBinderBlocking(() -> {
// TODO(b/120481270): Register for client death notification and update map.
mGnssMeasurementsListeners.put(listener.asBinder(), callerIdentity);
long identity = Binder.clearCallingIdentity();
@@ -2591,7 +2506,7 @@ public class LocationManagerService extends ILocationManager.Stub {
}
return true;
- }
+ });
}
@Override
@@ -2619,28 +2534,30 @@ public class LocationManagerService extends ILocationManager.Stub {
}
@Override
- public void removeGnssMeasurementsListener(IGnssMeasurementsListener listener) {
+ public void removeGnssMeasurementsListener(IGnssMeasurementsListener listener)
+ throws RemoteException {
if (mGnssMeasurementsProvider == null) {
return;
}
- synchronized (mLock) {
+ runFromBinderBlocking(() -> {
mGnssMeasurementsListeners.remove(listener.asBinder());
mGnssMeasurementsProvider.removeListener(listener);
- }
+ });
}
@Override
public boolean addGnssNavigationMessageListener(
IGnssNavigationMessageListener listener,
- String packageName) {
+ String packageName) throws RemoteException {
if (!hasGnssPermissions(packageName) || mGnssNavigationMessageProvider == null) {
return false;
}
- synchronized (mLock) {
- Identity callerIdentity
- = new Identity(Binder.getCallingUid(), Binder.getCallingPid(), packageName);
+ Identity callerIdentity =
+ new Identity(Binder.getCallingUid(), Binder.getCallingPid(), packageName);
+
+ return runFromBinderBlocking(() -> {
// TODO(b/120481270): Register for client death notification and update map.
mGnssNavigationMessageListeners.put(listener.asBinder(), callerIdentity);
long identity = Binder.clearCallingIdentity();
@@ -2656,21 +2573,23 @@ public class LocationManagerService extends ILocationManager.Stub {
}
return true;
- }
+ });
}
@Override
- public void removeGnssNavigationMessageListener(IGnssNavigationMessageListener listener) {
+ public void removeGnssNavigationMessageListener(IGnssNavigationMessageListener listener)
+ throws RemoteException {
if (mGnssNavigationMessageProvider != null) {
- synchronized (mLock) {
+ runFromBinderBlocking(() -> {
mGnssNavigationMessageListeners.remove(listener.asBinder());
mGnssNavigationMessageProvider.removeListener(listener);
- }
+ });
}
}
@Override
- public boolean sendExtraCommand(String provider, String command, Bundle extras) {
+ public boolean sendExtraCommand(String provider, String command, Bundle extras)
+ throws RemoteException {
if (provider == null) {
// throw NullPointerException to remain compatible with previous implementation
throw new NullPointerException();
@@ -2684,13 +2603,13 @@ public class LocationManagerService extends ILocationManager.Stub {
throw new SecurityException("Requires ACCESS_LOCATION_EXTRA_COMMANDS permission");
}
- synchronized (mLock) {
+ return runFromBinderBlocking(() -> {
LocationProvider p = mProvidersByName.get(provider);
if (p == null) return false;
p.sendExtraCommand(command, extras);
return true;
- }
+ });
}
@Override
@@ -2707,251 +2626,181 @@ public class LocationManagerService extends ILocationManager.Stub {
}
}
- /**
- * @return null if the provider does not exist
- * @throws SecurityException if the provider is not allowed to be
- * accessed by the caller
- */
@Override
- public ProviderProperties getProviderProperties(String provider) {
+ public ProviderProperties getProviderProperties(String provider) throws RemoteException {
checkResolutionLevelIsSufficientForProviderUse(getCallerAllowedResolutionLevel(),
provider);
- LocationProvider p;
- synchronized (mLock) {
- p = mProvidersByName.get(provider);
- }
-
- if (p == null) return null;
- return p.getProperties();
+ return runFromBinderBlocking(() -> {
+ LocationProvider p = mProvidersByName.get(provider);
+ if (p == null) return null;
+ return p.getProperties();
+ });
}
- /**
- * @return null if the provider does not exist
- * @throws SecurityException if the provider is not allowed to be
- * accessed by the caller
- */
@Override
- public String getNetworkProviderPackage() {
- LocationProvider p;
- synchronized (mLock) {
- p = mProvidersByName.get(LocationManager.NETWORK_PROVIDER);
- }
+ public String getNetworkProviderPackage() throws RemoteException {
+ return runFromBinderBlocking(() -> {
+ LocationProvider p = mProvidersByName.get(LocationManager.NETWORK_PROVIDER);
- if (p == null) {
+ if (p == null) {
+ return null;
+ }
+ if (p.mProvider instanceof LocationProviderProxy) {
+ return ((LocationProviderProxy) p.mProvider).getConnectedPackageName();
+ }
return null;
- }
- if (p.mProvider instanceof LocationProviderProxy) {
- return ((LocationProviderProxy) p.mProvider).getConnectedPackageName();
- }
- return null;
+ });
}
@Override
- public void setLocationControllerExtraPackage(String packageName) {
+ public void setLocationControllerExtraPackage(String packageName) throws RemoteException {
mContext.enforceCallingPermission(Manifest.permission.LOCATION_HARDWARE,
Manifest.permission.LOCATION_HARDWARE + " permission required");
- synchronized (mLock) {
- mLocationControllerExtraPackage = packageName;
- }
+
+ runFromBinderBlocking(() -> mLocationControllerExtraPackage = packageName);
}
@Override
- public String getLocationControllerExtraPackage() {
- synchronized (mLock) {
- return mLocationControllerExtraPackage;
- }
+ public String getLocationControllerExtraPackage() throws RemoteException {
+ return runFromBinderBlocking(() -> mLocationControllerExtraPackage);
}
@Override
- public void setLocationControllerExtraPackageEnabled(boolean enabled) {
+ public void setLocationControllerExtraPackageEnabled(boolean enabled) throws RemoteException {
mContext.enforceCallingPermission(Manifest.permission.LOCATION_HARDWARE,
Manifest.permission.LOCATION_HARDWARE + " permission required");
- synchronized (mLock) {
- mLocationControllerExtraPackageEnabled = enabled;
- }
+ runFromBinderBlocking(() -> mLocationControllerExtraPackageEnabled = enabled);
}
@Override
- public boolean isLocationControllerExtraPackageEnabled() {
- synchronized (mLock) {
- return mLocationControllerExtraPackageEnabled
- && (mLocationControllerExtraPackage != null);
- }
+ public boolean isLocationControllerExtraPackageEnabled() throws RemoteException {
+ return runFromBinderBlocking(() -> mLocationControllerExtraPackageEnabled
+ && (mLocationControllerExtraPackage != null));
}
- /**
- * Returns the current location enabled/disabled status for a user
- *
- * @param userId the id of the user
- * @return true if location is enabled
- */
@Override
- public boolean isLocationEnabledForUser(int userId) {
+ public boolean isLocationEnabledForUser(int userId) throws RemoteException {
// Check INTERACT_ACROSS_USERS permission if userId is not current user id.
- checkInteractAcrossUsersPermission(userId);
+ if (UserHandle.getCallingUserId() != userId) {
+ mContext.enforceCallingOrSelfPermission(
+ Manifest.permission.INTERACT_ACROSS_USERS,
+ "Requires INTERACT_ACROSS_USERS permission");
+ }
- long identity = Binder.clearCallingIdentity();
- try {
- synchronized (mLock) {
- final String allowedProviders = Settings.Secure.getStringForUser(
- mContext.getContentResolver(),
- Settings.Secure.LOCATION_PROVIDERS_ALLOWED,
- userId);
- if (allowedProviders == null) {
- return false;
- }
- final List<String> providerList = Arrays.asList(allowedProviders.split(","));
- for (String provider : mRealProviders.keySet()) {
- if (provider.equals(LocationManager.PASSIVE_PROVIDER)
- || provider.equals(LocationManager.FUSED_PROVIDER)) {
- continue;
- }
- if (providerList.contains(provider)) {
- return true;
- }
- }
- return false;
+ return runFromBinderBlocking(() -> isLocationEnabledForUserInternal(userId));
+ }
+
+ private boolean isLocationEnabledForUserInternal(int userId) {
+ Preconditions.checkState(Looper.myLooper() == mHandler.getLooper());
+
+ final String allowedProviders = Settings.Secure.getStringForUser(
+ mContext.getContentResolver(),
+ Settings.Secure.LOCATION_PROVIDERS_ALLOWED,
+ userId);
+ if (allowedProviders == null) {
+ return false;
+ }
+ final List<String> providerList = Arrays.asList(allowedProviders.split(","));
+
+ for (String provider : mRealProviders.keySet()) {
+ if (provider.equals(LocationManager.PASSIVE_PROVIDER)
+ || provider.equals(LocationManager.FUSED_PROVIDER)) {
+ continue;
+ }
+ if (providerList.contains(provider)) {
+ return true;
}
- } finally {
- Binder.restoreCallingIdentity(identity);
}
+ return false;
}
- /**
- * Enable or disable location for a user
- *
- * @param enabled true to enable location, false to disable location
- * @param userId the id of the user
- */
@Override
- public void setLocationEnabledForUser(boolean enabled, int userId) {
+ public void setLocationEnabledForUser(boolean enabled, int userId) throws RemoteException {
mContext.enforceCallingOrSelfPermission(
android.Manifest.permission.WRITE_SECURE_SETTINGS,
"Requires WRITE_SECURE_SETTINGS permission");
// Check INTERACT_ACROSS_USERS permission if userId is not current user id.
- checkInteractAcrossUsersPermission(userId);
-
- long identity = Binder.clearCallingIdentity();
- try {
- synchronized (mLock) {
- final Set<String> allRealProviders = mRealProviders.keySet();
- // Update all providers on device plus gps and network provider when disabling
- // location
- Set<String> allProvidersSet = new ArraySet<>(allRealProviders.size() + 2);
- allProvidersSet.addAll(allRealProviders);
- // When disabling location, disable gps and network provider that could have been
- // enabled by location mode api.
- if (!enabled) {
- allProvidersSet.add(LocationManager.GPS_PROVIDER);
- allProvidersSet.add(LocationManager.NETWORK_PROVIDER);
- }
- if (allProvidersSet.isEmpty()) {
- return;
- }
- // to ensure thread safety, we write the provider name with a '+' or '-'
- // and let the SettingsProvider handle it rather than reading and modifying
- // the list of enabled providers.
- final String prefix = enabled ? "+" : "-";
- StringBuilder locationProvidersAllowed = new StringBuilder();
- for (String provider : allProvidersSet) {
- if (provider.equals(LocationManager.PASSIVE_PROVIDER)
- || provider.equals(LocationManager.FUSED_PROVIDER)) {
- continue;
- }
- locationProvidersAllowed.append(prefix);
- locationProvidersAllowed.append(provider);
- locationProvidersAllowed.append(",");
+ if (UserHandle.getCallingUserId() != userId) {
+ mContext.enforceCallingOrSelfPermission(
+ Manifest.permission.INTERACT_ACROSS_USERS,
+ "Requires INTERACT_ACROSS_USERS permission");
+ }
+
+ runFromBinderBlocking(() -> {
+ final Set<String> allRealProviders = mRealProviders.keySet();
+ // Update all providers on device plus gps and network provider when disabling
+ // location
+ Set<String> allProvidersSet = new ArraySet<>(allRealProviders.size() + 2);
+ allProvidersSet.addAll(allRealProviders);
+ // When disabling location, disable gps and network provider that could have been
+ // enabled by location mode api.
+ if (!enabled) {
+ allProvidersSet.add(LocationManager.GPS_PROVIDER);
+ allProvidersSet.add(LocationManager.NETWORK_PROVIDER);
+ }
+ if (allProvidersSet.isEmpty()) {
+ return;
+ }
+ // to ensure thread safety, we write the provider name with a '+' or '-'
+ // and let the SettingsProvider handle it rather than reading and modifying
+ // the list of enabled providers.
+ final String prefix = enabled ? "+" : "-";
+ StringBuilder locationProvidersAllowed = new StringBuilder();
+ for (String provider : allProvidersSet) {
+ if (provider.equals(LocationManager.PASSIVE_PROVIDER)
+ || provider.equals(LocationManager.FUSED_PROVIDER)) {
+ continue;
}
- // Remove the trailing comma
- locationProvidersAllowed.setLength(locationProvidersAllowed.length() - 1);
- Settings.Secure.putStringForUser(
- mContext.getContentResolver(),
- Settings.Secure.LOCATION_PROVIDERS_ALLOWED,
- locationProvidersAllowed.toString(),
- userId);
+ locationProvidersAllowed.append(prefix);
+ locationProvidersAllowed.append(provider);
+ locationProvidersAllowed.append(",");
}
- } finally {
- Binder.restoreCallingIdentity(identity);
- }
+ // Remove the trailing comma
+ locationProvidersAllowed.setLength(locationProvidersAllowed.length() - 1);
+ Settings.Secure.putStringForUser(
+ mContext.getContentResolver(),
+ Settings.Secure.LOCATION_PROVIDERS_ALLOWED,
+ locationProvidersAllowed.toString(),
+ userId);
+ });
}
- /**
- * Returns the current enabled/disabled status of a location provider and user
- *
- * @param providerName name of the provider
- * @param userId the id of the user
- * @return true if the provider exists and is enabled
- */
@Override
- public boolean isProviderEnabledForUser(String providerName, int userId) {
+ public boolean isProviderEnabledForUser(String providerName, int userId)
+ throws RemoteException {
// Check INTERACT_ACROSS_USERS permission if userId is not current user id.
- checkInteractAcrossUsersPermission(userId);
-
- if (!isLocationEnabledForUser(userId)) {
- return false;
+ if (UserHandle.getCallingUserId() != userId) {
+ mContext.enforceCallingOrSelfPermission(
+ Manifest.permission.INTERACT_ACROSS_USERS,
+ "Requires INTERACT_ACROSS_USERS permission");
}
// Fused provider is accessed indirectly via criteria rather than the provider-based APIs,
// so we discourage its use
if (LocationManager.FUSED_PROVIDER.equals(providerName)) return false;
- long identity = Binder.clearCallingIdentity();
- try {
- LocationProvider provider;
- synchronized (mLock) {
- provider = mProvidersByName.get(providerName);
- }
- return provider != null && provider.isEnabled();
- } finally {
- Binder.restoreCallingIdentity(identity);
+ if (!isLocationEnabledForUser(userId)) {
+ return false;
}
+
+ return runFromBinderBlocking(() -> {
+ LocationProvider provider = mProvidersByName.get(providerName);
+ return provider != null && provider.isEnabled();
+ });
}
- /**
- * Enable or disable a single location provider.
- *
- * @param provider name of the provider
- * @param enabled true to enable the provider. False to disable the provider
- * @param userId the id of the user to set
- * @return true if the value was set, false on errors
- */
@Override
public boolean setProviderEnabledForUser(String provider, boolean enabled, int userId) {
return false;
}
- /**
- * Method for checking INTERACT_ACROSS_USERS permission if specified user id is not the same as
- * current user id
- *
- * @param userId the user id to get or set value
- */
- private void checkInteractAcrossUsersPermission(int userId) {
- int uid = Binder.getCallingUid();
- if (UserHandle.getUserId(uid) != userId) {
- if (ActivityManager.checkComponentPermission(
- android.Manifest.permission.INTERACT_ACROSS_USERS, uid, -1, true)
- != PERMISSION_GRANTED) {
- throw new SecurityException("Requires INTERACT_ACROSS_USERS permission");
- }
- }
- }
-
- /**
- * Returns "true" if the UID belongs to a bound location provider.
- *
- * @param uid the uid
- * @return true if uid belongs to a bound location provider
- */
private boolean isUidALocationProvider(int uid) {
if (uid == Process.SYSTEM_UID) {
return true;
}
- if (mGeocodeProvider != null) {
- if (doesUidHavePackage(uid, mGeocodeProvider.getConnectedPackageName())) return true;
- }
+
for (LocationProviderProxy proxy : mProxyProviders) {
if (doesUidHavePackage(uid, proxy.getConnectedPackageName())) return true;
}
@@ -2970,7 +2819,6 @@ public class LocationManagerService extends ILocationManager.Stub {
// providers installed oustide the system image. So
// also allow providers with a UID matching the
// currently bound package name
-
if (isUidALocationProvider(Binder.getCallingUid())) {
return;
}
@@ -2979,9 +2827,6 @@ public class LocationManagerService extends ILocationManager.Stub {
"or UID of a currently bound location provider");
}
- /**
- * Returns true if the given package belongs to the given uid.
- */
private boolean doesUidHavePackage(int uid, String packageName) {
if (packageName == null) {
return false;
@@ -2998,22 +2843,12 @@ public class LocationManagerService extends ILocationManager.Stub {
return false;
}
+ // TODO: will be removed in future
@Override
public void reportLocation(Location location, boolean passive) {
- checkCallerIsProvider();
-
- if (!location.isComplete()) {
- Log.w(TAG, "Dropping incomplete location: " + location);
- return;
- }
-
- mLocationHandler.removeMessages(MSG_LOCATION_CHANGED, location);
- Message m = Message.obtain(mLocationHandler, MSG_LOCATION_CHANGED, location);
- m.arg1 = (passive ? 1 : 0);
- mLocationHandler.sendMessageAtFrontOfQueue(m);
+ throw new IllegalStateException("operation unsupported");
}
-
private static boolean shouldBroadcastSafe(
Location loc, Location lastLoc, UpdateRecord record, long now) {
// Always broadcast the first update
@@ -3046,14 +2881,33 @@ public class LocationManagerService extends ILocationManager.Stub {
return record.mRealRequest.getExpireAt() >= now;
}
- private void handleLocationChangedLocked(Location location, boolean passive) {
- if (D) Log.d(TAG, "incoming location: " + location);
+ private void handleLocationChanged(Location location, boolean passive) {
+ Preconditions.checkState(Looper.myLooper() == mHandler.getLooper());
+
+ // create a working copy of the incoming Location so that the service can modify it without
+ // disturbing the caller's copy
+ Location myLocation = new Location(location);
+ String pr = myLocation.getProvider();
+
+ // set "isFromMockProvider" bit if location came from a mock provider. we do not clear this
+ // bit if location did not come from a mock provider because passive/fused providers can
+ // forward locations from mock providers, and should not grant them legitimacy in doing so.
+ if (!myLocation.isFromMockProvider() && isMockProvider(pr)) {
+ myLocation.setIsFromMockProvider(true);
+ }
+
+ if (!passive) {
+ // notify passive provider of the new location
+ mPassiveProvider.updateLocation(myLocation);
+ }
+
+ if (D) Log.d(TAG, "incoming location: " + myLocation);
long now = SystemClock.elapsedRealtime();
- String provider = (passive ? LocationManager.PASSIVE_PROVIDER : location.getProvider());
+ String provider = (passive ? LocationManager.PASSIVE_PROVIDER : myLocation.getProvider());
// Skip if the provider is unknown.
LocationProvider p = mProvidersByName.get(provider);
if (p == null) return;
- updateLastLocationLocked(location, provider);
+ updateLastLocation(myLocation, provider);
// mLastLocation should have been updated from the updateLastLocationLocked call above.
Location lastLocation = mLastLocation.get(provider);
if (lastLocation == null) {
@@ -3064,13 +2918,13 @@ public class LocationManagerService extends ILocationManager.Stub {
// Update last known coarse interval location if enough time has passed.
Location lastLocationCoarseInterval = mLastLocationCoarseInterval.get(provider);
if (lastLocationCoarseInterval == null) {
- lastLocationCoarseInterval = new Location(location);
+ lastLocationCoarseInterval = new Location(myLocation);
mLastLocationCoarseInterval.put(provider, lastLocationCoarseInterval);
}
- long timeDiffNanos = location.getElapsedRealtimeNanos()
+ long timeDiffNanos = myLocation.getElapsedRealtimeNanos()
- lastLocationCoarseInterval.getElapsedRealtimeNanos();
if (timeDiffNanos > LocationFudger.FASTEST_INTERVAL_MS * NANOS_PER_MILLI) {
- lastLocationCoarseInterval.set(location);
+ lastLocationCoarseInterval.set(myLocation);
}
// Don't ever return a coarse location that is more recent than the allowed update
// interval (i.e. don't allow an app to keep registering and unregistering for
@@ -3194,24 +3048,20 @@ public class LocationManagerService extends ILocationManager.Stub {
// remove dead records and receivers outside the loop
if (deadReceivers != null) {
for (Receiver receiver : deadReceivers) {
- removeUpdatesLocked(receiver);
+ removeUpdates(receiver);
}
}
if (deadUpdateRecords != null) {
for (UpdateRecord r : deadUpdateRecords) {
r.disposeLocked(true);
}
- applyRequirementsLocked(provider);
+ applyRequirements(provider);
}
}
- /**
- * Updates last location with the given location
- *
- * @param location new location to update
- * @param provider Location provider to update for
- */
- private void updateLastLocationLocked(Location location, String provider) {
+ private void updateLastLocation(Location location, String provider) {
+ Preconditions.checkState(Looper.myLooper() == mHandler.getLooper());
+
Location noGPSLocation = location.getExtraLocation(Location.EXTRA_NO_GPS_LOCATION);
Location lastNoGPSLocation;
Location lastLocation = mLastLocation.get(provider);
@@ -3229,75 +3079,11 @@ public class LocationManagerService extends ILocationManager.Stub {
lastLocation.set(location);
}
- private class LocationWorkerHandler extends Handler {
- public LocationWorkerHandler(Looper looper) {
- super(looper, null, true);
- }
-
- @Override
- public void handleMessage(Message msg) {
- switch (msg.what) {
- case MSG_LOCATION_CHANGED:
- handleLocationChanged((Location) msg.obj, msg.arg1 == 1);
- break;
- }
- }
- }
-
private boolean isMockProvider(String provider) {
- synchronized (mLock) {
- return mMockProviders.containsKey(provider);
- }
- }
-
- private void handleLocationChanged(Location location, boolean passive) {
- // create a working copy of the incoming Location so that the service can modify it without
- // disturbing the caller's copy
- Location myLocation = new Location(location);
- String provider = myLocation.getProvider();
-
- // set "isFromMockProvider" bit if location came from a mock provider. we do not clear this
- // bit if location did not come from a mock provider because passive/fused providers can
- // forward locations from mock providers, and should not grant them legitimacy in doing so.
- if (!myLocation.isFromMockProvider() && isMockProvider(provider)) {
- myLocation.setIsFromMockProvider(true);
- }
-
- synchronized (mLock) {
- if (!passive) {
- // notify passive provider of the new location
- mPassiveProvider.updateLocation(myLocation);
- }
- handleLocationChangedLocked(myLocation, passive);
- }
+ Preconditions.checkState(Looper.myLooper() == mHandler.getLooper());
+ return mMockProviders.containsKey(provider);
}
- private final PackageMonitor mPackageMonitor = new PackageMonitor() {
- @Override
- public void onPackageDisappeared(String packageName, int reason) {
- // remove all receivers associated with this package name
- synchronized (mLock) {
- ArrayList<Receiver> deadReceivers = null;
-
- for (Receiver receiver : mReceivers.values()) {
- if (receiver.mIdentity.mPackageName.equals(packageName)) {
- if (deadReceivers == null) {
- deadReceivers = new ArrayList<>();
- }
- deadReceivers.add(receiver);
- }
- }
-
- // perform removal outside of mReceivers loop
- if (deadReceivers != null) {
- for (Receiver receiver : deadReceivers) {
- removeUpdatesLocked(receiver);
- }
- }
- }
- }
- };
-
// Geocoder
@Override
@@ -3338,7 +3124,8 @@ public class LocationManagerService extends ILocationManager.Stub {
}
@Override
- public void addTestProvider(String name, ProviderProperties properties, String opPackageName) {
+ public void addTestProvider(String name, ProviderProperties properties, String opPackageName)
+ throws RemoteException {
if (!canCallerAccessMockLocation(opPackageName)) {
return;
}
@@ -3347,23 +3134,24 @@ public class LocationManagerService extends ILocationManager.Stub {
throw new IllegalArgumentException("Cannot mock the passive location provider");
}
- long identity = Binder.clearCallingIdentity();
- synchronized (mLock) {
+ runFromBinderBlocking(() -> {
// remove the real provider if we are replacing GPS or network provider
if (LocationManager.GPS_PROVIDER.equals(name)
|| LocationManager.NETWORK_PROVIDER.equals(name)
|| LocationManager.FUSED_PROVIDER.equals(name)) {
LocationProvider p = mProvidersByName.get(name);
if (p != null) {
- removeProviderLocked(p);
+ removeProvider(p);
}
}
- addTestProviderLocked(name, properties);
- }
- Binder.restoreCallingIdentity(identity);
+ addTestProvider(name, properties);
+ return null;
+ });
}
- private void addTestProviderLocked(String name, ProviderProperties properties) {
+ private void addTestProvider(String name, ProviderProperties properties) {
+ Preconditions.checkState(Looper.myLooper() == mHandler.getLooper());
+
if (mProvidersByName.get(name) != null) {
throw new IllegalArgumentException("Provider \"" + name + "\" already exists");
}
@@ -3371,122 +3159,103 @@ public class LocationManagerService extends ILocationManager.Stub {
LocationProvider provider = new LocationProvider(name);
MockProvider mockProvider = new MockProvider(provider, properties);
- addProviderLocked(provider);
+ addProvider(provider);
mMockProviders.put(name, mockProvider);
mLastLocation.put(name, null);
mLastLocationCoarseInterval.put(name, null);
}
@Override
- public void removeTestProvider(String provider, String opPackageName) {
+ public void removeTestProvider(String provider, String opPackageName) throws RemoteException {
if (!canCallerAccessMockLocation(opPackageName)) {
return;
}
- synchronized (mLock) {
+ runFromBinderBlocking(() -> {
MockProvider mockProvider = mMockProviders.remove(provider);
if (mockProvider == null) {
throw new IllegalArgumentException("Provider \"" + provider + "\" unknown");
}
- long identity = Binder.clearCallingIdentity();
- try {
- removeProviderLocked(mProvidersByName.get(provider));
+ removeProvider(mProvidersByName.get(provider));
- // reinstate real provider if available
- LocationProvider realProvider = mRealProviders.get(provider);
- if (realProvider != null) {
- addProviderLocked(realProvider);
- }
- mLastLocation.put(provider, null);
- mLastLocationCoarseInterval.put(provider, null);
- } finally {
- Binder.restoreCallingIdentity(identity);
+ // reinstate real provider if available
+ LocationProvider realProvider = mRealProviders.get(provider);
+ if (realProvider != null) {
+ addProvider(realProvider);
}
- }
+ mLastLocation.put(provider, null);
+ mLastLocationCoarseInterval.put(provider, null);
+ });
}
@Override
- public void setTestProviderLocation(String provider, Location loc, String opPackageName) {
+ public void setTestProviderLocation(String provider, Location loc, String opPackageName)
+ throws RemoteException {
if (!canCallerAccessMockLocation(opPackageName)) {
return;
}
- synchronized (mLock) {
+ runFromBinderBlocking(() -> {
MockProvider mockProvider = mMockProviders.get(provider);
if (mockProvider == null) {
throw new IllegalArgumentException("Provider \"" + provider + "\" unknown");
}
- // Ensure that the location is marked as being mock. There's some logic to do this in
- // handleLocationChanged(), but it fails if loc has the wrong provider (bug 33091107).
+ // Ensure that the location is marked as being mock. There's some logic to do this
+ // in handleLocationChanged(), but it fails if loc has the wrong provider
+ // (b/33091107).
Location mock = new Location(loc);
mock.setIsFromMockProvider(true);
if (!TextUtils.isEmpty(loc.getProvider()) && !provider.equals(loc.getProvider())) {
- // The location has an explicit provider that is different from the mock provider
- // name. The caller may be trying to fool us via bug 33091107.
+ // The location has an explicit provider that is different from the mock
+ // provider name. The caller may be trying to fool us via bug 33091107.
EventLog.writeEvent(0x534e4554, "33091107", Binder.getCallingUid(),
provider + "!=" + loc.getProvider());
}
- // clear calling identity so INSTALL_LOCATION_PROVIDER permission is not required
- long identity = Binder.clearCallingIdentity();
- try {
- mockProvider.setLocation(mock);
- } finally {
- Binder.restoreCallingIdentity(identity);
- }
- }
+ mockProvider.setLocation(mock);
+ });
}
@Override
- public void setTestProviderEnabled(String provider, boolean enabled, String opPackageName) {
+ public void setTestProviderEnabled(String provider, boolean enabled, String opPackageName)
+ throws RemoteException {
if (!canCallerAccessMockLocation(opPackageName)) {
return;
}
- synchronized (mLock) {
+ runFromBinderBlocking(() -> {
MockProvider mockProvider = mMockProviders.get(provider);
if (mockProvider == null) {
throw new IllegalArgumentException("Provider \"" + provider + "\" unknown");
}
- long identity = Binder.clearCallingIdentity();
- try {
- mockProvider.setEnabled(enabled);
- } finally {
- Binder.restoreCallingIdentity(identity);
- }
- }
+ mockProvider.setEnabled(enabled);
+ });
}
@Override
public void setTestProviderStatus(String provider, int status, Bundle extras, long updateTime,
- String opPackageName) {
+ String opPackageName) throws RemoteException {
if (!canCallerAccessMockLocation(opPackageName)) {
return;
}
- synchronized (mLock) {
+ runFromBinderBlocking(() -> {
MockProvider mockProvider = mMockProviders.get(provider);
if (mockProvider == null) {
throw new IllegalArgumentException("Provider \"" + provider + "\" unknown");
}
mockProvider.setStatus(status, extras, updateTime);
- }
- }
-
- private void log(String log) {
- if (Log.isLoggable(TAG, Log.VERBOSE)) {
- Slog.d(TAG, log);
- }
+ });
}
@Override
protected void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
if (!DumpUtils.checkDumpPermission(mContext, TAG, pw)) return;
- synchronized (mLock) {
+ Runnable dump = () -> {
if (args.length > 0 && args[0].equals("--gnssmetrics")) {
if (mGnssMetricsProvider != null) {
pw.append(mGnssMetricsProvider.getGnssMetricsAsProtoString());
@@ -3579,6 +3348,14 @@ public class LocationManagerService extends ILocationManager.Stub {
if (mGnssBatchingInProgress) {
pw.println(" GNSS batching in progress");
}
+ };
+
+ FutureTask<Void> task = new FutureTask<>(dump, null);
+ mHandler.postAtFrontOfQueue(task);
+ try {
+ task.get();
+ } catch (InterruptedException | ExecutionException e) {
+ pw.println("error dumping: " + e);
}
}
}
diff --git a/services/core/java/com/android/server/am/ActivityManagerService.java b/services/core/java/com/android/server/am/ActivityManagerService.java
index 7f2a206e2a8d..4f21ee8d8624 100644
--- a/services/core/java/com/android/server/am/ActivityManagerService.java
+++ b/services/core/java/com/android/server/am/ActivityManagerService.java
@@ -2429,16 +2429,21 @@ public class ActivityManagerService extends IActivityManager.Stub
return mBackgroundLaunchBroadcasts;
}
+ /**
+ * Returns true if the package {@code pkg1} running under user handle {@code uid1} is
+ * allowed association with the package {@code pkg2} running under user handle {@code uid2}.
+ * <p> If either of the packages are running as part of the core system, then the
+ * association is implicitly allowed.
+ */
boolean validateAssociationAllowedLocked(String pkg1, int uid1, String pkg2, int uid2) {
if (mAllowedAssociations == null) {
mAllowedAssociations = SystemConfig.getInstance().getAllowedAssociations();
}
// Interactions with the system uid are always allowed, since that is the core system
- // that everyone needs to be able to interact with.
- if (UserHandle.getAppId(uid1) == SYSTEM_UID) {
- return true;
- }
- if (UserHandle.getAppId(uid2) == SYSTEM_UID) {
+ // that everyone needs to be able to interact with. Also allow reflexive associations
+ // within the same uid.
+ if (uid1 == uid2 || UserHandle.getAppId(uid1) == SYSTEM_UID
+ || UserHandle.getAppId(uid2) == SYSTEM_UID) {
return true;
}
// We won't allow this association if either pkg1 or pkg2 has a limit on the
@@ -2454,6 +2459,8 @@ public class ActivityManagerService extends IActivityManager.Stub
if (pkgs != null) {
return pkgs.contains(pkg1);
}
+ // If no explicit associations are provided in the manifest, then assume the app is
+ // allowed associations with any package.
return true;
}
diff --git a/services/core/java/com/android/server/connectivity/NetworkMonitor.java b/services/core/java/com/android/server/connectivity/NetworkMonitor.java
index 9684f4c4ae19..2a000252d6f4 100644
--- a/services/core/java/com/android/server/connectivity/NetworkMonitor.java
+++ b/services/core/java/com/android/server/connectivity/NetworkMonitor.java
@@ -126,21 +126,21 @@ public class NetworkMonitor extends StateMachine {
private static final int DEFAULT_DATA_STALL_EVALUATION_TYPES =
(1 << DATA_STALL_EVALUATION_TYPE_DNS);
- static enum EvaluationResult {
+ enum EvaluationResult {
VALIDATED(true),
CAPTIVE_PORTAL(false);
- final boolean isValidated;
+ final boolean mIsValidated;
EvaluationResult(boolean isValidated) {
- this.isValidated = isValidated;
+ this.mIsValidated = isValidated;
}
}
- static enum ValidationStage {
+ enum ValidationStage {
FIRST_VALIDATION(true),
REVALIDATION(false);
- final boolean isFirstValidation;
+ final boolean mIsFirstValidation;
ValidationStage(boolean isFirstValidation) {
- this.isFirstValidation = isFirstValidation;
+ this.mIsFirstValidation = isFirstValidation;
}
}
@@ -251,7 +251,7 @@ public class NetworkMonitor extends StateMachine {
// Start mReevaluateDelayMs at this value and double.
private static final int INITIAL_REEVALUATE_DELAY_MS = 1000;
- private static final int MAX_REEVALUATE_DELAY_MS = 10*60*1000;
+ private static final int MAX_REEVALUATE_DELAY_MS = 10 * 60 * 1000;
// Before network has been evaluated this many times, ignore repeated reevaluate requests.
private static final int IGNORE_REEVALUATE_ATTEMPTS = 5;
private int mReevaluateToken = 0;
@@ -261,7 +261,7 @@ public class NetworkMonitor extends StateMachine {
// Stop blaming UID that requested re-evaluation after this many attempts.
private static final int BLAME_FOR_EVALUATION_ATTEMPTS = 5;
// Delay between reevaluations once a captive portal has been found.
- private static final int CAPTIVE_PORTAL_REEVALUATE_DELAY_MS = 10*60*1000;
+ private static final int CAPTIVE_PORTAL_REEVALUATE_DELAY_MS = 10 * 60 * 1000;
private static final int NUM_VALIDATION_LOG_LINES = 20;
@@ -393,10 +393,17 @@ public class NetworkMonitor extends StateMachine {
start();
}
+ /**
+ * Request the NetworkMonitor to reevaluate the network.
+ */
public void forceReevaluation(int responsibleUid) {
sendMessage(CMD_FORCE_REEVALUATION, responsibleUid, 0);
}
+ /**
+ * Send a notification to NetworkMonitor indicating that private DNS settings have changed.
+ * @param newCfg The new private DNS configuration.
+ */
public void notifyPrivateDnsSettingsChanged(PrivateDnsConfig newCfg) {
// Cancel any outstanding resolutions.
removeMessages(CMD_PRIVATE_DNS_SETTINGS_CHANGED);
@@ -655,8 +662,9 @@ public class NetworkMonitor extends StateMachine {
public boolean processMessage(Message message) {
switch (message.what) {
case CMD_REEVALUATE:
- if (message.arg1 != mReevaluateToken || mUserDoesNotWant)
+ if (message.arg1 != mReevaluateToken || mUserDoesNotWant) {
return HANDLED;
+ }
// Don't bother validating networks that don't satisfy the default request.
// This includes:
// - VPNs which can be considered explicitly desired by the user and the
@@ -813,9 +821,9 @@ public class NetworkMonitor extends StateMachine {
}
private boolean isStrictModeHostnameResolved() {
- return (mPrivateDnsConfig != null) &&
- mPrivateDnsConfig.hostname.equals(mPrivateDnsProviderHostname) &&
- (mPrivateDnsConfig.ips.length > 0);
+ return (mPrivateDnsConfig != null)
+ && mPrivateDnsConfig.hostname.equals(mPrivateDnsProviderHostname)
+ && (mPrivateDnsConfig.ips.length > 0);
}
private void resolveStrictModeHostname() {
@@ -852,9 +860,9 @@ public class NetworkMonitor extends StateMachine {
private boolean sendPrivateDnsProbe() {
// q.v. system/netd/server/dns/DnsTlsTransport.cpp
- final String ONE_TIME_HOSTNAME_SUFFIX = "-dnsotls-ds.metric.gstatic.com";
- final String host = UUID.randomUUID().toString().substring(0, 8) +
- ONE_TIME_HOSTNAME_SUFFIX;
+ final String oneTimeHostnameSuffix = "-dnsotls-ds.metric.gstatic.com";
+ final String host = UUID.randomUUID().toString().substring(0, 8)
+ + oneTimeHostnameSuffix;
final Stopwatch watch = new Stopwatch().start();
try {
final InetAddress[] ips = mNetworkAgentInfo.network().getAllByName(host);
@@ -966,7 +974,7 @@ public class NetworkMonitor extends StateMachine {
// most one per address family. This ensures we only wait up to 20 seconds for TCP connections
// to complete, regardless of how many IP addresses a host has.
private static class OneAddressPerFamilyNetwork extends Network {
- public OneAddressPerFamilyNetwork(Network network) {
+ OneAddressPerFamilyNetwork(Network network) {
// Always bypass Private DNS.
super(network.getPrivateDnsBypassingCopy());
}
@@ -1000,7 +1008,8 @@ public class NetworkMonitor extends StateMachine {
}
public boolean getWifiScansAlwaysAvailableDisabled() {
- return mDependencies.getSetting(mContext, Settings.Global.WIFI_SCAN_ALWAYS_AVAILABLE, 0) == 0;
+ return mDependencies.getSetting(
+ mContext, Settings.Global.WIFI_SCAN_ALWAYS_AVAILABLE, 0) == 0;
}
private String getCaptivePortalServerHttpsUrl() {
@@ -1246,10 +1255,10 @@ public class NetworkMonitor extends StateMachine {
// Time how long it takes to get a response to our request
long responseTimestamp = SystemClock.elapsedRealtime();
- validationLog(probeType, url, "time=" + (responseTimestamp - requestTimestamp) + "ms" +
- " ret=" + httpResponseCode +
- " request=" + requestHeader +
- " headers=" + urlConnection.getHeaderFields());
+ validationLog(probeType, url, "time=" + (responseTimestamp - requestTimestamp) + "ms"
+ + " ret=" + httpResponseCode
+ + " request=" + requestHeader
+ + " headers=" + urlConnection.getHeaderFields());
// NOTE: We may want to consider an "HTTP/1.0 204" response to be a captive
// portal. The only example of this seen so far was a captive portal. For
// the time being go with prior behavior of assuming it's not a captive
@@ -1267,7 +1276,7 @@ public class NetworkMonitor extends StateMachine {
// sign-in to an empty page. Probably the result of a broken transparent proxy.
// See http://b/9972012.
validationLog(probeType, url,
- "200 response with Content-length=0 interpreted as 204 response.");
+ "200 response with Content-length=0 interpreted as 204 response.");
httpResponseCode = CaptivePortalProbeResult.SUCCESS_CODE;
} else if (urlConnection.getContentLengthLong() == -1) {
// When no Content-length (default value == -1), attempt to read a byte from the
@@ -1309,7 +1318,7 @@ public class NetworkMonitor extends StateMachine {
private final boolean mIsHttps;
private volatile CaptivePortalProbeResult mResult = CaptivePortalProbeResult.FAILED;
- public ProbeThread(boolean isHttps) {
+ ProbeThread(boolean isHttps) {
mIsHttps = isHttps;
}
@@ -1443,8 +1452,10 @@ public class NetworkMonitor extends StateMachine {
if (cellInfo.isRegistered()) {
numRegisteredCellInfo++;
if (numRegisteredCellInfo > 1) {
- if (VDBG) logw("more than one registered CellInfo." +
- " Can't tell which is active. Bailing.");
+ if (VDBG) {
+ logw("more than one registered CellInfo."
+ + " Can't tell which is active. Bailing.");
+ }
return;
}
if (cellInfo instanceof CellInfoCdma) {
@@ -1492,14 +1503,14 @@ public class NetworkMonitor extends StateMachine {
}
private int networkEventType(ValidationStage s, EvaluationResult r) {
- if (s.isFirstValidation) {
- if (r.isValidated) {
+ if (s.mIsFirstValidation) {
+ if (r.mIsValidated) {
return NetworkEvent.NETWORK_FIRST_VALIDATION_SUCCESS;
} else {
return NetworkEvent.NETWORK_FIRST_VALIDATION_PORTAL_FOUND;
}
} else {
- if (r.isValidated) {
+ if (r.mIsValidated) {
return NetworkEvent.NETWORK_REVALIDATION_SUCCESS;
} else {
return NetworkEvent.NETWORK_REVALIDATION_PORTAL_FOUND;
@@ -1517,7 +1528,7 @@ public class NetworkMonitor extends StateMachine {
private void logValidationProbe(long durationMs, int probeType, int probeResult) {
int[] transports = mNetworkAgentInfo.networkCapabilities.getTransportTypes();
- boolean isFirstValidation = validationStage().isFirstValidation;
+ boolean isFirstValidation = validationStage().mIsFirstValidation;
ValidationProbeEvent ev = new ValidationProbeEvent();
ev.probeType = ValidationProbeEvent.makeProbeType(probeType, isFirstValidation);
ev.returnCode = probeResult;
@@ -1535,10 +1546,20 @@ public class NetworkMonitor extends StateMachine {
return new Random();
}
+ /**
+ * Get the value of a global integer setting.
+ * @param symbol Name of the setting
+ * @param defaultValue Value to return if the setting is not defined.
+ */
public int getSetting(Context context, String symbol, int defaultValue) {
return Settings.Global.getInt(context.getContentResolver(), symbol, defaultValue);
}
+ /**
+ * Get the value of a global String setting.
+ * @param symbol Name of the setting
+ * @param defaultValue Value to return if the setting is not defined.
+ */
public String getSetting(Context context, String symbol, String defaultValue) {
final String value = Settings.Global.getString(context.getContentResolver(), symbol);
return value != null ? value : defaultValue;
diff --git a/services/core/java/com/android/server/connectivity/tethering/TetheringDependencies.java b/services/core/java/com/android/server/connectivity/tethering/TetheringDependencies.java
index d56b167b9a75..7daf71dda73b 100644
--- a/services/core/java/com/android/server/connectivity/tethering/TetheringDependencies.java
+++ b/services/core/java/com/android/server/connectivity/tethering/TetheringDependencies.java
@@ -34,32 +34,53 @@ import java.util.ArrayList;
* @hide
*/
public class TetheringDependencies {
+ /**
+ * Get a reference to the offload hardware interface to be used by tethering.
+ */
public OffloadHardwareInterface getOffloadHardwareInterface(Handler h, SharedLog log) {
return new OffloadHardwareInterface(h, log);
}
+ /**
+ * Get a reference to the UpstreamNetworkMonitor to be used by tethering.
+ */
public UpstreamNetworkMonitor getUpstreamNetworkMonitor(Context ctx, StateMachine target,
SharedLog log, int what) {
return new UpstreamNetworkMonitor(ctx, target, log, what);
}
+ /**
+ * Get a reference to the IPv6TetheringCoordinator to be used by tethering.
+ */
public IPv6TetheringCoordinator getIPv6TetheringCoordinator(
ArrayList<IpServer> notifyList, SharedLog log) {
return new IPv6TetheringCoordinator(notifyList, log);
}
+ /**
+ * Get dependencies to be used by IpServer.
+ */
public IpServer.Dependencies getIpServerDependencies() {
return new IpServer.Dependencies();
}
+ /**
+ * Indicates whether tethering is supported on the device.
+ */
public boolean isTetheringSupported() {
return true;
}
+ /**
+ * Get the NetworkRequest that should be fulfilled by the default network.
+ */
public NetworkRequest getDefaultNetworkRequest() {
return null;
}
+ /**
+ * Get a reference to the EntitlementManager to be used by tethering.
+ */
public EntitlementManager getEntitlementManager(Context ctx, SharedLog log,
MockableSystemProperties systemProperties) {
return new EntitlementManager(ctx, log, systemProperties);
diff --git a/services/core/java/com/android/server/hdmi/Constants.java b/services/core/java/com/android/server/hdmi/Constants.java
index 1f0f94a7bf0b..5210270051c0 100644
--- a/services/core/java/com/android/server/hdmi/Constants.java
+++ b/services/core/java/com/android/server/hdmi/Constants.java
@@ -300,7 +300,7 @@ final class Constants {
* <p>Default is true.
*/
static final String PROPERTY_ARC_SUPPORT =
- "persist.sys.hdmi.property_arc_support";
+ "persist.sys.hdmi.property_arc_support";
/**
* Property to save the audio port to switch to when system audio control is on.
@@ -310,7 +310,7 @@ final class Constants {
* <p>Default is ARC port.
*/
static final String PROPERTY_SYSTEM_AUDIO_MODE_AUDIO_PORT =
- "persist.sys.hdmi.property_sytem_audio_mode_audio_port";
+ "persist.sys.hdmi.property_sytem_audio_mode_audio_port";
/**
* Property to save the ARC port id on system audio device.
@@ -320,6 +320,15 @@ final class Constants {
"persist.sys.hdmi.property_sytem_audio_device_arc_port";
/**
+ * Property to indicate if a CEC audio device should forward volume keys when system audio mode
+ * is off.
+ *
+ * <p>Default is false.
+ */
+ static final String PROPERTY_CEC_AUDIO_DEVICE_FORWARD_VOLUME_KEYS_SYSTEM_AUDIO_MODE_OFF =
+ "persist.sys.hdmi.property_cec_audio_device_forward_volume_keys_system_audio_mode_off";
+
+ /**
* Property to strip local audio of amplifier and use local speaker
* when TV does not support system audio mode.
*
diff --git a/services/core/java/com/android/server/hdmi/HdmiCecLocalDeviceAudioSystem.java b/services/core/java/com/android/server/hdmi/HdmiCecLocalDeviceAudioSystem.java
index 9690ba877c1e..2ac04d1e2de0 100644
--- a/services/core/java/com/android/server/hdmi/HdmiCecLocalDeviceAudioSystem.java
+++ b/services/core/java/com/android/server/hdmi/HdmiCecLocalDeviceAudioSystem.java
@@ -25,6 +25,7 @@ import android.media.AudioDeviceInfo;
import android.media.AudioManager;
import android.media.AudioSystem;
import android.os.SystemProperties;
+import android.provider.Settings.Global;
import com.android.internal.annotations.GuardedBy;
import com.android.internal.annotations.VisibleForTesting;
@@ -50,6 +51,11 @@ public class HdmiCecLocalDeviceAudioSystem extends HdmiCecLocalDevice {
private boolean mTvSystemAudioModeSupport;
+ // Whether the auido system will turn TV off when it's powering off
+ private boolean mAutoTvOff;
+ // Whether the auido system will broadcast standby to the system when it's powering off
+ private boolean mAutoDeviceOff;
+
// Whether ARC is available or not. "true" means that ARC is established between TV and
// AVR as audio receiver.
@ServiceThreadOnly private boolean mArcEstablished = false;
@@ -60,6 +66,10 @@ public class HdmiCecLocalDeviceAudioSystem extends HdmiCecLocalDevice {
// TODO(amyjojo) make System Audio Control controllable by users
/*mSystemAudioControlFeatureEnabled =
mService.readBooleanSetting(Global.HDMI_SYSTEM_AUDIO_CONTROL_ENABLED, true);*/
+ mAutoDeviceOff = mService.readBooleanSetting(
+ Global.HDMI_CONTROL_AUTO_DEVICE_OFF_ENABLED, true);
+ mAutoTvOff = mService.readBooleanSetting(
+ Global.HDMI_CONTROL_AUTO_TV_OFF_ENABLED, true);
}
@Override
@@ -74,6 +84,21 @@ public class HdmiCecLocalDeviceAudioSystem extends HdmiCecLocalDevice {
mSystemAudioActivated ? "true" : "false");
}
terminateSystemAudioMode();
+
+ HdmiLogger.debug(TAG + " onStandby, initiatedByCec:" + initiatedByCec
+ + ", mAutoDeviceOff: " + mAutoDeviceOff + ", mAutoTvOff: " + mAutoTvOff);
+ if (!mService.isControlEnabled() || initiatedByCec) {
+ return;
+ }
+ if (mAutoDeviceOff) {
+ mService.sendCecCommand(
+ HdmiCecMessageBuilder.buildStandby(mAddress, Constants.ADDR_BROADCAST));
+ } else if (mAutoTvOff) {
+ mService.sendCecCommand(
+ HdmiCecMessageBuilder.buildStandby(mAddress, Constants.ADDR_TV));
+ }
+ return;
+
}
@Override
@@ -491,4 +516,17 @@ public class HdmiCecLocalDeviceAudioSystem extends HdmiCecLocalDevice {
return mArcEstablished;
}
}
+
+ @ServiceThreadOnly
+ protected void setAutoTvOff(boolean autoTvOff) {
+ assertRunOnServiceThread();
+ mAutoTvOff = autoTvOff;
+ }
+
+ @Override
+ @ServiceThreadOnly
+ void setAutoDeviceOff(boolean autoDeviceOff) {
+ assertRunOnServiceThread();
+ mAutoDeviceOff = autoDeviceOff;
+ }
}
diff --git a/services/core/java/com/android/server/hdmi/HdmiControlService.java b/services/core/java/com/android/server/hdmi/HdmiControlService.java
index 3420b263eac5..e3a4084ab7f3 100644
--- a/services/core/java/com/android/server/hdmi/HdmiControlService.java
+++ b/services/core/java/com/android/server/hdmi/HdmiControlService.java
@@ -592,6 +592,11 @@ public class HdmiControlService extends SystemService {
}
// No need to propagate to HAL.
break;
+ case Global.HDMI_CONTROL_AUTO_TV_OFF_ENABLED:
+ if (isAudioSystemDevice()) {
+ audioSystem().setAutoTvOff(enabled);
+ }
+ break;
case Global.HDMI_SYSTEM_AUDIO_CONTROL_ENABLED:
if (isTvDeviceEnabled()) {
tv().setSystemAudioControlFeatureEnabled(enabled);
diff --git a/services/core/java/com/android/server/inputmethod/InputMethodManagerService.java b/services/core/java/com/android/server/inputmethod/InputMethodManagerService.java
index 5a7739c49b42..d45869e07586 100644
--- a/services/core/java/com/android/server/inputmethod/InputMethodManagerService.java
+++ b/services/core/java/com/android/server/inputmethod/InputMethodManagerService.java
@@ -291,6 +291,8 @@ public class InputMethodManagerService extends IInputMethodManager.Stub
new DebugFlag("debug.optimize_startinput", false);
}
+ @UserIdInt
+ private int mLastSwitchUserId;
final Context mContext;
final Resources mRes;
@@ -1436,6 +1438,8 @@ public class InputMethodManagerService extends IInputMethodManager.Stub
Slog.w(TAG, "Couldn't get current user ID; guessing it's 0", e);
}
+ mLastSwitchUserId = userId;
+
// mSettings should be created before buildInputMethodListLocked
mSettings = new InputMethodSettings(
mRes, context.getContentResolver(), mMethodMap, mMethodList, userId, !mSystemReady);
@@ -1523,6 +1527,8 @@ public class InputMethodManagerService extends IInputMethodManager.Stub
if (DEBUG) Slog.d(TAG, "Switching user stage 3/3. newUserId=" + newUserId
+ " selectedIme=" + mSettings.getSelectedInputMethod());
+
+ mLastSwitchUserId = newUserId;
}
void updateCurrentProfileIds() {
@@ -4424,6 +4430,10 @@ public class InputMethodManagerService extends IInputMethodManager.Stub
return refreshDebugProperties();
}
+ if ("get-last-switch-user-id".equals(cmd)) {
+ return mService.getLastSwitchUserId(this);
+ }
+
// For existing "adb shell ime <command>".
if ("ime".equals(cmd)) {
final String imeCommand = getNextArg();
@@ -4516,6 +4526,15 @@ public class InputMethodManagerService extends IInputMethodManager.Stub
// ----------------------------------------------------------------------
// Shell command handlers:
+ @BinderThread
+ @ShellCommandResult
+ private int getLastSwitchUserId(@NonNull ShellCommand shellCommand) {
+ synchronized (mMethodMap) {
+ shellCommand.getOutPrintWriter().println(mLastSwitchUserId);
+ return ShellCommandResult.SUCCESS;
+ }
+ }
+
/**
* Handles {@code adb shell ime list}.
* @param shellCommand {@link ShellCommand} object that is handling this command.
diff --git a/services/core/java/com/android/server/media/MediaSessionRecord.java b/services/core/java/com/android/server/media/MediaSessionRecord.java
index 139d8ac6a8d5..b70c64edc2cc 100644
--- a/services/core/java/com/android/server/media/MediaSessionRecord.java
+++ b/services/core/java/com/android/server/media/MediaSessionRecord.java
@@ -34,7 +34,6 @@ import android.media.session.ISessionControllerCallback;
import android.media.session.MediaController;
import android.media.session.MediaController.PlaybackInfo;
import android.media.session.MediaSession;
-import android.media.session.ParcelableVolumeInfo;
import android.media.session.PlaybackState;
import android.net.Uri;
import android.os.Binder;
@@ -628,7 +627,7 @@ public class MediaSessionRecord implements IBinder.DeathRecipient {
if (mDestroyed) {
return;
}
- ParcelableVolumeInfo info = mController.getVolumeAttributes();
+ PlaybackInfo info = mController.getVolumeAttributes();
for (int i = mControllerCallbackHolders.size() - 1; i >= 0; i--) {
ISessionControllerCallbackHolder holder = mControllerCallbackHolders.get(i);
try {
@@ -1233,14 +1232,14 @@ public class MediaSessionRecord implements IBinder.DeathRecipient {
}
@Override
- public ParcelableVolumeInfo getVolumeAttributes() {
+ public PlaybackInfo getVolumeAttributes() {
int volumeType;
AudioAttributes attributes;
synchronized (mLock) {
if (mVolumeType == PlaybackInfo.PLAYBACK_TYPE_REMOTE) {
int current = mOptimisticVolume != -1 ? mOptimisticVolume : mCurrentVolume;
- return new ParcelableVolumeInfo(
- mVolumeType, mAudioAttrs, mVolumeControlType, mMaxVolume, current);
+ return new PlaybackInfo(mVolumeType, mVolumeControlType, mMaxVolume, current,
+ mAudioAttrs);
}
volumeType = mVolumeType;
attributes = mAudioAttrs;
@@ -1248,8 +1247,8 @@ public class MediaSessionRecord implements IBinder.DeathRecipient {
int stream = AudioAttributes.toLegacyStreamType(attributes);
int max = mAudioManager.getStreamMaxVolume(stream);
int current = mAudioManager.getStreamVolume(stream);
- return new ParcelableVolumeInfo(
- volumeType, attributes, VolumeProvider.VOLUME_CONTROL_ABSOLUTE, max, current);
+ return new PlaybackInfo(volumeType, VolumeProvider.VOLUME_CONTROL_ABSOLUTE, max,
+ current, attributes);
}
@Override
diff --git a/services/core/java/com/android/server/notification/ManagedServices.java b/services/core/java/com/android/server/notification/ManagedServices.java
index 88d73fb10902..c222e6948a3d 100644
--- a/services/core/java/com/android/server/notification/ManagedServices.java
+++ b/services/core/java/com/android/server/notification/ManagedServices.java
@@ -767,6 +767,23 @@ abstract public class ManagedServices {
return installed;
}
+ protected Set<String> getAllowedPackages() {
+ final Set<String> allowedPackages = new ArraySet<>();
+ for (int k = 0; k < mApproved.size(); k++) {
+ ArrayMap<Boolean, ArraySet<String>> allowedByType = mApproved.valueAt(k);
+ for (int i = 0; i < allowedByType.size(); i++) {
+ final ArraySet<String> allowed = allowedByType.valueAt(i);
+ for (int j = 0; j < allowed.size(); j++) {
+ String pkgName = getPackageName(allowed.valueAt(j));
+ if (!TextUtils.isEmpty(pkgName)) {
+ allowedPackages.add(pkgName);
+ }
+ }
+ }
+ }
+ return allowedPackages;
+ }
+
private void trimApprovedListsAccordingToInstalledServices() {
int N = mApproved.size();
for (int i = 0 ; i < N; i++) {
diff --git a/services/core/java/com/android/server/notification/NotificationManagerService.java b/services/core/java/com/android/server/notification/NotificationManagerService.java
index 655daf89dda4..c68e0f98325e 100644
--- a/services/core/java/com/android/server/notification/NotificationManagerService.java
+++ b/services/core/java/com/android/server/notification/NotificationManagerService.java
@@ -1701,8 +1701,16 @@ public class NotificationManagerService extends SystemService {
}
private void sendRegisteredOnlyBroadcast(String action) {
- getContext().sendBroadcastAsUser(new Intent(action)
- .addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY), UserHandle.ALL, null);
+ Intent intent = new Intent(action);
+ getContext().sendBroadcastAsUser(intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY),
+ UserHandle.ALL, null);
+ // explicitly send the broadcast to all DND packages, even if they aren't currently running
+ intent.setFlags(0);
+ final Set<String> dndApprovedPackages = mConditionProviders.getAllowedPackages();
+ for (String pkg : dndApprovedPackages) {
+ intent.setPackage(pkg);
+ getContext().sendBroadcastAsUser(intent, UserHandle.ALL);
+ }
}
@Override
@@ -2641,6 +2649,9 @@ public class NotificationManagerService extends SystemService {
// Zen
mConditionProviders.onPackagesChanged(true, packages, uids);
+ // Snoozing
+ mSnoozeHelper.clearData(UserHandle.getUserId(uid), packageName);
+
// Reset notification preferences
if (!fromApp) {
mPreferencesHelper.onPackagesChanged(
diff --git a/services/core/java/com/android/server/notification/SnoozeHelper.java b/services/core/java/com/android/server/notification/SnoozeHelper.java
index 2b581d601ad5..abc98412e126 100644
--- a/services/core/java/com/android/server/notification/SnoozeHelper.java
+++ b/services/core/java/com/android/server/notification/SnoozeHelper.java
@@ -17,6 +17,7 @@ package com.android.server.notification;
import android.annotation.NonNull;
import android.app.AlarmManager;
+import android.app.Notification;
import android.app.PendingIntent;
import android.content.BroadcastReceiver;
import android.content.Context;
@@ -163,7 +164,6 @@ public class SnoozeHelper {
mSnoozedNotifications.get(userId).get(pkg);
if (recordsForPkg != null) {
final Set<Map.Entry<String, NotificationRecord>> records = recordsForPkg.entrySet();
- String key = null;
for (Map.Entry<String, NotificationRecord> record : records) {
final StatusBarNotification sbn = record.getValue().sbn;
if (Objects.equals(sbn.getTag(), tag) && sbn.getId() == id) {
@@ -305,6 +305,30 @@ public class SnoozeHelper {
}
}
+ protected void clearData(int userId, String pkg) {
+ ArrayMap<String, ArrayMap<String, NotificationRecord>> records =
+ mSnoozedNotifications.get(userId);
+ if (records == null) {
+ return;
+ }
+ ArrayMap<String, NotificationRecord> pkgRecords = records.get(pkg);
+ if (pkgRecords == null) {
+ return;
+ }
+ for (int i = pkgRecords.size() - 1; i >= 0; i--) {
+ final NotificationRecord r = pkgRecords.removeAt(i);
+ if (r != null) {
+ mPackages.remove(r.getKey());
+ mUsers.remove(r.getKey());
+ final PendingIntent pi = createPendingIntent(pkg, r.getKey(), userId);
+ mAm.cancel(pi);
+ MetricsLogger.action(r.getLogMaker()
+ .setCategory(MetricsProto.MetricsEvent.NOTIFICATION_SNOOZED)
+ .setType(MetricsProto.MetricsEvent.TYPE_DISMISS));
+ }
+ }
+ }
+
private PendingIntent createPendingIntent(String pkg, String key, int userId) {
return PendingIntent.getBroadcast(mContext,
REQUEST_CODE_REPOST,
diff --git a/services/core/java/com/android/server/notification/ZenModeHelper.java b/services/core/java/com/android/server/notification/ZenModeHelper.java
index e5b1878650d3..afc0b7230e27 100644
--- a/services/core/java/com/android/server/notification/ZenModeHelper.java
+++ b/services/core/java/com/android/server/notification/ZenModeHelper.java
@@ -375,8 +375,7 @@ public class ZenModeHelper {
newConfig = mConfig.copy();
for (int i = newConfig.automaticRules.size() - 1; i >= 0; i--) {
ZenRule rule = newConfig.automaticRules.get(newConfig.automaticRules.keyAt(i));
- if (rule.component.getPackageName().equals(packageName)
- && canManageAutomaticZenRule(rule)) {
+ if (rule.pkg.equals(packageName) && canManageAutomaticZenRule(rule)) {
newConfig.automaticRules.removeAt(i);
}
}
diff --git a/services/core/java/com/android/server/pm/PackageInstallerSession.java b/services/core/java/com/android/server/pm/PackageInstallerSession.java
index 982daa5df2d5..3cb771449e09 100644
--- a/services/core/java/com/android/server/pm/PackageInstallerSession.java
+++ b/services/core/java/com/android/server/pm/PackageInstallerSession.java
@@ -1374,7 +1374,8 @@ public class PackageInstallerSession extends IPackageInstallerSession.Stub {
"Missing existing base package");
}
// Default to require only if existing base has fs-verity.
- mVerityFound = params.mode == SessionParams.MODE_INHERIT_EXISTING
+ mVerityFound = PackageManagerServiceUtils.isApkVerityEnabled()
+ && params.mode == SessionParams.MODE_INHERIT_EXISTING
&& VerityUtils.hasFsverity(pkgInfo.applicationInfo.getBaseCodePath());
try {
diff --git a/services/core/java/com/android/server/pm/PackageManagerService.java b/services/core/java/com/android/server/pm/PackageManagerService.java
index fe89be6f73c4..522ab0bf93e2 100644
--- a/services/core/java/com/android/server/pm/PackageManagerService.java
+++ b/services/core/java/com/android/server/pm/PackageManagerService.java
@@ -8572,7 +8572,7 @@ public class PackageManagerService extends IPackageManager.Stub
* match one in a trusted source, and should be done separately.
*/
private boolean canSkipForcedApkVerification(String apkPath) {
- if (!PackageManagerServiceUtils.isLegacyApkVerityMode()) {
+ if (!PackageManagerServiceUtils.isLegacyApkVerityEnabled()) {
return VerityUtils.hasFsverity(apkPath);
}
@@ -16866,10 +16866,11 @@ public class PackageManagerService extends IPackageManager.Stub
*/
private void setUpFsVerityIfPossible(PackageParser.Package pkg) throws InstallerException,
PrepareFailure, IOException, DigestException, NoSuchAlgorithmException {
- if (!PackageManagerServiceUtils.isApkVerityEnabled()) {
+ final boolean standardMode = PackageManagerServiceUtils.isApkVerityEnabled();
+ final boolean legacyMode = PackageManagerServiceUtils.isLegacyApkVerityEnabled();
+ if (!standardMode && !legacyMode) {
return;
}
- final boolean legacyMode = PackageManagerServiceUtils.isLegacyApkVerityMode();
// Collect files we care for fs-verity setup.
ArrayMap<String, String> fsverityCandidates = new ArrayMap<>();
diff --git a/services/core/java/com/android/server/pm/PackageManagerServiceUtils.java b/services/core/java/com/android/server/pm/PackageManagerServiceUtils.java
index 25169a24d932..6134d3098e3b 100644
--- a/services/core/java/com/android/server/pm/PackageManagerServiceUtils.java
+++ b/services/core/java/com/android/server/pm/PackageManagerServiceUtils.java
@@ -555,19 +555,19 @@ public class PackageManagerServiceUtils {
/** Standard fs-verity. */
private static final int FSVERITY_ENABLED = 2;
- /** Returns true if APK Verity is enabled. */
+ /** Returns true if standard APK Verity is enabled. */
static boolean isApkVerityEnabled() {
- int mode = SystemProperties.getInt("ro.apk_verity.mode", FSVERITY_DISABLED);
- return mode == FSVERITY_LEGACY || mode == FSVERITY_ENABLED;
+ return SystemProperties.getInt("ro.apk_verity.mode", FSVERITY_DISABLED) == FSVERITY_ENABLED;
}
- static boolean isLegacyApkVerityMode() {
+ static boolean isLegacyApkVerityEnabled() {
return SystemProperties.getInt("ro.apk_verity.mode", FSVERITY_DISABLED) == FSVERITY_LEGACY;
}
/** Returns true to force apk verification if the updated package (in /data) is a priv app. */
static boolean isApkVerificationForced(@Nullable PackageSetting disabledPs) {
- return disabledPs != null && disabledPs.isPrivileged() && isApkVerityEnabled();
+ return disabledPs != null && disabledPs.isPrivileged() && (
+ isApkVerityEnabled() || isLegacyApkVerityEnabled());
}
/**
diff --git a/services/core/java/com/android/server/power/Notifier.java b/services/core/java/com/android/server/power/Notifier.java
index 5adc248cee79..c3f20aab568e 100644
--- a/services/core/java/com/android/server/power/Notifier.java
+++ b/services/core/java/com/android/server/power/Notifier.java
@@ -755,9 +755,10 @@ public class Notifier {
};
/**
- * Plays the wireless charging sound for both wireless and non-wireless charging
+ * If enabled, plays a sound and/or vibration when wireless or non-wireless charging has started
*/
- private void playChargingStartedSound(@UserIdInt int userId) {
+ private void playChargingStartedFeedback(@UserIdInt int userId) {
+ playChargingStartedVibration(userId);
final String soundPath = Settings.Global.getString(mContext.getContentResolver(),
Settings.Global.CHARGING_STARTED_SOUND);
if (isChargingFeedbackEnabled(userId) && soundPath != null) {
@@ -773,8 +774,7 @@ public class Notifier {
}
private void showWirelessChargingStarted(int batteryLevel, @UserIdInt int userId) {
- playWirelessChargingVibration(userId);
- playChargingStartedSound(userId);
+ playChargingStartedFeedback(userId);
if (mStatusBarManagerInternal != null) {
mStatusBarManagerInternal.showChargingAnimation(batteryLevel);
}
@@ -782,7 +782,7 @@ public class Notifier {
}
private void showWiredChargingStarted(@UserIdInt int userId) {
- playChargingStartedSound(userId);
+ playChargingStartedFeedback(userId);
mSuspendBlocker.release();
}
@@ -790,7 +790,7 @@ public class Notifier {
mTrustManager.setDeviceLockedForUser(userId, true /*locked*/);
}
- private void playWirelessChargingVibration(@UserIdInt int userId) {
+ private void playChargingStartedVibration(@UserIdInt int userId) {
final boolean vibrateEnabled = Settings.Secure.getIntForUser(mContext.getContentResolver(),
Settings.Secure.CHARGING_VIBRATION_ENABLED, 1, userId) != 0;
if (vibrateEnabled && isChargingFeedbackEnabled(userId)) {
diff --git a/services/core/java/com/android/server/power/batterysaver/BatterySaverStateMachine.java b/services/core/java/com/android/server/power/batterysaver/BatterySaverStateMachine.java
index f262f6dabbe0..a60f16d7ca27 100644
--- a/services/core/java/com/android/server/power/batterysaver/BatterySaverStateMachine.java
+++ b/services/core/java/com/android/server/power/batterysaver/BatterySaverStateMachine.java
@@ -15,8 +15,14 @@
*/
package com.android.server.power.batterysaver;
+import android.app.Notification;
+import android.app.NotificationChannel;
+import android.app.NotificationManager;
+import android.app.PendingIntent;
import android.content.ContentResolver;
import android.content.Context;
+import android.content.Intent;
+import android.content.res.Resources;
import android.database.ContentObserver;
import android.os.Handler;
import android.os.PowerManager;
@@ -26,6 +32,7 @@ import android.provider.Settings.Global;
import android.util.Slog;
import android.util.proto.ProtoOutputStream;
+import com.android.internal.R;
import com.android.internal.annotations.GuardedBy;
import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.os.BackgroundThread;
@@ -46,6 +53,8 @@ import java.io.PrintWriter;
*/
public class BatterySaverStateMachine {
private static final String TAG = "BatterySaverStateMachine";
+ private static final String DYNAMIC_MODE_NOTIF_CHANNEL_ID = "dynamic_mode_notification";
+ private static final int DYNAMIC_MODE_NOTIFICATION_ID = 1992;
private final Object mLock;
private static final boolean DEBUG = BatterySaverPolicy.DEBUG;
@@ -484,6 +493,13 @@ public class BatterySaverStateMachine {
}
mBatterySaverController.enableBatterySaver(enable, intReason);
+ // Handle triggering the notification to show/hide when appropriate
+ if (intReason == BatterySaverController.REASON_DYNAMIC_POWER_SAVINGS_AUTOMATIC_ON) {
+ runOnBgThread(this::triggerDynamicModeNotification);
+ } else if (!enable) {
+ runOnBgThread(this::hideDynamicModeNotification);
+ }
+
if (DEBUG) {
Slog.d(TAG, "Battery saver: Enabled=" + enable
+ " manual=" + manual
@@ -491,6 +507,44 @@ public class BatterySaverStateMachine {
}
}
+ private void triggerDynamicModeNotification() {
+ NotificationManager manager = mContext.getSystemService(NotificationManager.class);
+ ensureNotificationChannelExists(manager);
+
+ manager.notify(DYNAMIC_MODE_NOTIFICATION_ID, buildNotification());
+ }
+
+ private void ensureNotificationChannelExists(NotificationManager manager) {
+ NotificationChannel channel = new NotificationChannel(
+ DYNAMIC_MODE_NOTIF_CHANNEL_ID,
+ mContext.getText(
+ R.string.dynamic_mode_notification_channel_name),
+ NotificationManager.IMPORTANCE_DEFAULT);
+ channel.setSound(null, null);
+ manager.createNotificationChannel(channel);
+ }
+
+ private Notification buildNotification() {
+ Resources res = mContext.getResources();
+ Intent intent = new Intent(Intent.ACTION_POWER_USAGE_SUMMARY);
+ intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_CLEAR_TASK);
+ PendingIntent batterySaverIntent = PendingIntent.getActivity(
+ mContext, 0 /* requestCode */, intent, PendingIntent.FLAG_UPDATE_CURRENT);
+
+ return new Notification.Builder(mContext, DYNAMIC_MODE_NOTIF_CHANNEL_ID)
+ .setSmallIcon(R.drawable.ic_battery)
+ .setContentTitle(res.getString(R.string.dynamic_mode_notification_title))
+ .setContentText(res.getString(R.string.dynamic_mode_notification_summary))
+ .setContentIntent(batterySaverIntent)
+ .setOnlyAlertOnce(true)
+ .build();
+ }
+
+ private void hideDynamicModeNotification() {
+ NotificationManager manager = mContext.getSystemService(NotificationManager.class);
+ manager.cancel(DYNAMIC_MODE_NOTIFICATION_ID);
+ }
+
@GuardedBy("mLock")
private void updateSnoozingLocked(boolean snoozing, String reason) {
if (mBatterySaverSnoozing == snoozing) {
diff --git a/services/core/java/com/android/server/wallpaper/WallpaperManagerService.java b/services/core/java/com/android/server/wallpaper/WallpaperManagerService.java
index f00877030145..01bff07d1bb0 100644
--- a/services/core/java/com/android/server/wallpaper/WallpaperManagerService.java
+++ b/services/core/java/com/android/server/wallpaper/WallpaperManagerService.java
@@ -350,12 +350,34 @@ public class WallpaperManagerService extends IWallpaperManager.Stub
}
private void notifyWallpaperColorsChanged(@NonNull WallpaperData wallpaper, int which) {
+ if (wallpaper.connection != null) {
+ wallpaper.connection.forEachDisplayConnector(connector -> {
+ notifyWallpaperColorsChangedOnDisplay(wallpaper, which, connector.mDisplayId);
+ });
+ } else { // Lock wallpaper does not have WallpaperConnection.
+ notifyWallpaperColorsChangedOnDisplay(wallpaper, which, DEFAULT_DISPLAY);
+ }
+ }
+
+ private RemoteCallbackList<IWallpaperManagerCallback> getWallpaperCallbacks(int userId,
+ int displayId) {
+ RemoteCallbackList<IWallpaperManagerCallback> listeners = null;
+ final SparseArray<RemoteCallbackList<IWallpaperManagerCallback>> displayListeners =
+ mColorsChangedListeners.get(userId);
+ if (displayListeners != null) {
+ listeners = displayListeners.get(displayId);
+ }
+ return listeners;
+ }
+
+ private void notifyWallpaperColorsChangedOnDisplay(@NonNull WallpaperData wallpaper, int which,
+ int displayId) {
boolean needsExtraction;
synchronized (mLock) {
final RemoteCallbackList<IWallpaperManagerCallback> currentUserColorListeners =
- mColorsChangedListeners.get(wallpaper.userId);
+ getWallpaperCallbacks(wallpaper.userId, displayId);
final RemoteCallbackList<IWallpaperManagerCallback> userAllColorListeners =
- mColorsChangedListeners.get(UserHandle.USER_ALL);
+ getWallpaperCallbacks(UserHandle.USER_ALL, displayId);
// No-op until someone is listening to it.
if (emptyCallbackList(currentUserColorListeners) &&
emptyCallbackList(userAllColorListeners)) {
@@ -363,7 +385,7 @@ public class WallpaperManagerService extends IWallpaperManager.Stub
}
if (DEBUG) {
- Slog.v(TAG, "notifyWallpaperColorsChanged " + which);
+ Slog.v(TAG, "notifyWallpaperColorsChangedOnDisplay " + which);
}
needsExtraction = wallpaper.primaryColors == null;
@@ -371,7 +393,7 @@ public class WallpaperManagerService extends IWallpaperManager.Stub
// Let's notify the current values, it's fine if it's null, it just means
// that we don't know yet.
- notifyColorListeners(wallpaper.primaryColors, which, wallpaper.userId);
+ notifyColorListeners(wallpaper.primaryColors, which, wallpaper.userId, displayId);
if (needsExtraction) {
extractColors(wallpaper);
@@ -381,7 +403,7 @@ public class WallpaperManagerService extends IWallpaperManager.Stub
return;
}
}
- notifyColorListeners(wallpaper.primaryColors, which, wallpaper.userId);
+ notifyColorListeners(wallpaper.primaryColors, which, wallpaper.userId, displayId);
}
}
@@ -390,14 +412,14 @@ public class WallpaperManagerService extends IWallpaperManager.Stub
}
private void notifyColorListeners(@NonNull WallpaperColors wallpaperColors, int which,
- int userId) {
+ int userId, int displayId) {
final IWallpaperManagerCallback keyguardListener;
final ArrayList<IWallpaperManagerCallback> colorListeners = new ArrayList<>();
synchronized (mLock) {
final RemoteCallbackList<IWallpaperManagerCallback> currentUserColorListeners =
- mColorsChangedListeners.get(userId);
+ getWallpaperCallbacks(userId, displayId);
final RemoteCallbackList<IWallpaperManagerCallback> userAllColorListeners =
- mColorsChangedListeners.get(UserHandle.USER_ALL);
+ getWallpaperCallbacks(UserHandle.USER_ALL, displayId);
keyguardListener = mKeyguardListener;
if (currentUserColorListeners != null) {
@@ -427,7 +449,8 @@ public class WallpaperManagerService extends IWallpaperManager.Stub
}
}
- if (keyguardListener != null) {
+ // Only shows Keyguard on default display
+ if (keyguardListener != null && displayId == DEFAULT_DISPLAY) {
try {
keyguardListener.onWallpaperColorsChanged(wallpaperColors, which, userId);
} catch (RemoteException e) {
@@ -446,6 +469,11 @@ public class WallpaperManagerService extends IWallpaperManager.Stub
String cropFile = null;
int wallpaperId;
+ if (wallpaper.equals(mFallbackWallpaper)) {
+ extractDefaultImageWallpaperColors();
+ return;
+ }
+
synchronized (mLock) {
// Not having a wallpaperComponent means it's a lock screen wallpaper.
final boolean imageWallpaper = mImageWallpaper.equals(wallpaper.wallpaperComponent)
@@ -482,6 +510,39 @@ public class WallpaperManagerService extends IWallpaperManager.Stub
}
}
+ private void extractDefaultImageWallpaperColors() {
+ synchronized (mLock) {
+ if (mFallbackWallpaper.primaryColors != null) return;
+ }
+
+ if (DEBUG) Slog.d(TAG, "Extract default image wallpaper colors");
+ WallpaperColors colors = null;
+ final InputStream is = WallpaperManager.openDefaultWallpaper(mContext, FLAG_SYSTEM);
+ if (is != null) {
+ try {
+ final BitmapFactory.Options options = new BitmapFactory.Options();
+ final Bitmap bitmap = BitmapFactory.decodeStream(is, null, options);
+ if (bitmap != null) {
+ colors = WallpaperColors.fromBitmap(bitmap);
+ bitmap.recycle();
+ }
+ } catch (OutOfMemoryError e) {
+ Slog.w(TAG, "Can't decode default wallpaper stream", e);
+ } finally {
+ IoUtils.closeQuietly(is);
+ }
+ }
+
+ if (colors == null) {
+ Slog.e(TAG, "Extract default image wallpaper colors failed");
+ return;
+ }
+
+ synchronized (mLock) {
+ mFallbackWallpaper.primaryColors = colors;
+ }
+ }
+
/**
* Once a new wallpaper has been written via setWallpaper(...), it needs to be cropped
* for display.
@@ -696,6 +757,11 @@ public class WallpaperManagerService extends IWallpaperManager.Stub
targetWallpaper.connection.removeDisplayConnector(displayId);
removeDisplayData(displayId);
}
+ for (int i = mColorsChangedListeners.size() - 1; i >= 0; i--) {
+ final SparseArray<RemoteCallbackList<IWallpaperManagerCallback>> callbacks =
+ mColorsChangedListeners.valueAt(i);
+ callbacks.delete(displayId);
+ }
}
}
@@ -706,9 +772,11 @@ public class WallpaperManagerService extends IWallpaperManager.Stub
/**
* Map of color listeners per user id.
- * The key will be the id of a user or UserHandle.USER_ALL - for wildcard listeners.
+ * The first key will be the id of a user or UserHandle.USER_ALL - for wildcard listeners.
+ * The secondary key will be the display id, which means which display the listener is
+ * interested in.
*/
- private final SparseArray<RemoteCallbackList<IWallpaperManagerCallback>>
+ private final SparseArray<SparseArray<RemoteCallbackList<IWallpaperManagerCallback>>>
mColorsChangedListeners;
private WallpaperData mLastWallpaper;
private IWallpaperManagerCallback mKeyguardListener;
@@ -1228,9 +1296,10 @@ public class WallpaperManagerService extends IWallpaperManager.Stub
/**
* Called by a live wallpaper if its colors have changed.
* @param primaryColors representation of wallpaper primary colors
+ * @param displayId for which display
*/
@Override
- public void onWallpaperColorsChanged(WallpaperColors primaryColors) {
+ public void onWallpaperColorsChanged(WallpaperColors primaryColors, int displayId) {
int which;
synchronized (mLock) {
// Do not broadcast changes on ImageWallpaper since it's handled
@@ -1243,14 +1312,16 @@ public class WallpaperManagerService extends IWallpaperManager.Stub
// Live wallpapers always are system wallpapers.
which = FLAG_SYSTEM;
- // It's also the lock screen wallpaper when we don't have a bitmap in there
- WallpaperData lockedWallpaper = mLockWallpaperMap.get(mWallpaper.userId);
- if (lockedWallpaper == null) {
- which |= FLAG_LOCK;
+ // It's also the lock screen wallpaper when we don't have a bitmap in there.
+ if (displayId == DEFAULT_DISPLAY) {
+ final WallpaperData lockedWallpaper = mLockWallpaperMap.get(mWallpaper.userId);
+ if (lockedWallpaper == null) {
+ which |= FLAG_LOCK;
+ }
}
}
if (which != 0) {
- notifyWallpaperColorsChanged(mWallpaper, which);
+ notifyWallpaperColorsChangedOnDisplay(mWallpaper, which, displayId);
}
}
@@ -1277,16 +1348,12 @@ public class WallpaperManagerService extends IWallpaperManager.Stub
Slog.w(TAG, "Failed to set ambient mode state", e);
}
}
- // TODO(multi-display) So far, we have shared the same wallpaper on each display.
- // Once we have multiple wallpapers on multiple displays, please complete here.
- if (displayId == DEFAULT_DISPLAY) {
- try {
- // This will trigger onComputeColors in the wallpaper engine.
- // It's fine to be locked in here since the binder is oneway.
- connector.mEngine.requestWallpaperColors();
- } catch (RemoteException e) {
- Slog.w(TAG, "Failed to request wallpaper colors", e);
- }
+ try {
+ // This will trigger onComputeColors in the wallpaper engine.
+ // It's fine to be locked in here since the binder is oneway.
+ connector.mEngine.requestWallpaperColors();
+ } catch (RemoteException e) {
+ Slog.w(TAG, "Failed to request wallpaper colors", e);
}
}
}
@@ -1681,6 +1748,7 @@ public class WallpaperManagerService extends IWallpaperManager.Stub
FgThread.getHandler().post(() -> {
notifyWallpaperColorsChanged(systemWallpaper, FLAG_SYSTEM);
notifyWallpaperColorsChanged(lockWallpaper, FLAG_LOCK);
+ notifyWallpaperColorsChanged(mFallbackWallpaper, FLAG_SYSTEM);
});
}
@@ -1743,6 +1811,7 @@ public class WallpaperManagerService extends IWallpaperManager.Stub
// When clearing a wallpaper, broadcast new valid colors
if (data != null) {
notifyWallpaperColorsChanged(data, which);
+ notifyWallpaperColorsChanged(mFallbackWallpaper, FLAG_SYSTEM);
}
}
@@ -2084,35 +2153,47 @@ public class WallpaperManagerService extends IWallpaperManager.Stub
}
@Override
- public void registerWallpaperColorsCallback(IWallpaperManagerCallback cb, int userId) {
+ public void registerWallpaperColorsCallback(IWallpaperManagerCallback cb, int userId,
+ int displayId) {
userId = ActivityManager.handleIncomingUser(Binder.getCallingPid(), Binder.getCallingUid(),
userId, true, true, "registerWallpaperColorsCallback", null);
synchronized (mLock) {
- RemoteCallbackList<IWallpaperManagerCallback> userColorsChangedListeners =
- mColorsChangedListeners.get(userId);
- if (userColorsChangedListeners == null) {
- userColorsChangedListeners = new RemoteCallbackList<>();
- mColorsChangedListeners.put(userId, userColorsChangedListeners);
+ SparseArray<RemoteCallbackList<IWallpaperManagerCallback>>
+ userDisplayColorsChangedListeners = mColorsChangedListeners.get(userId);
+ if (userDisplayColorsChangedListeners == null) {
+ userDisplayColorsChangedListeners = new SparseArray<>();
+ mColorsChangedListeners.put(userId, userDisplayColorsChangedListeners);
+ }
+ RemoteCallbackList<IWallpaperManagerCallback> displayChangedListeners =
+ userDisplayColorsChangedListeners.get(displayId);
+ if (displayChangedListeners == null) {
+ displayChangedListeners = new RemoteCallbackList<>();
+ userDisplayColorsChangedListeners.put(displayId, displayChangedListeners);
}
- userColorsChangedListeners.register(cb);
+ displayChangedListeners.register(cb);
}
}
@Override
- public void unregisterWallpaperColorsCallback(IWallpaperManagerCallback cb, int userId) {
+ public void unregisterWallpaperColorsCallback(IWallpaperManagerCallback cb, int userId,
+ int displayId) {
userId = ActivityManager.handleIncomingUser(Binder.getCallingPid(), Binder.getCallingUid(),
userId, true, true, "unregisterWallpaperColorsCallback", null);
synchronized (mLock) {
- final RemoteCallbackList<IWallpaperManagerCallback> userColorsChangedListeners =
- mColorsChangedListeners.get(userId);
- if (userColorsChangedListeners != null) {
- userColorsChangedListeners.unregister(cb);
+ SparseArray<RemoteCallbackList<IWallpaperManagerCallback>>
+ userDisplayColorsChangedListeners = mColorsChangedListeners.get(userId);
+ if (userDisplayColorsChangedListeners != null) {
+ RemoteCallbackList<IWallpaperManagerCallback> displayChangedListeners =
+ userDisplayColorsChangedListeners.get(displayId);
+ if (displayChangedListeners != null) {
+ displayChangedListeners.unregister(cb);
+ }
}
}
}
/**
- * TODO(b/115486823) Extends this method with specific display.
+ * TODO(multi-display) Extends this method with specific display.
* Propagate ambient state to wallpaper engine.
*
* @param inAmbientMode {@code true} when in ambient mode, {@code false} otherwise.
@@ -2125,7 +2206,7 @@ public class WallpaperManagerService extends IWallpaperManager.Stub
final WallpaperData data = mWallpaperMap.get(mCurrentUserId);
if (data != null && data.connection != null && data.connection.mInfo != null
&& data.connection.mInfo.supportsAmbientMode()) {
- // TODO(b/115486823) Extends this method with specific display.
+ // TODO(multi-display) Extends this method with specific display.
engine = data.connection.getDisplayConnectorOrCreate(DEFAULT_DISPLAY).mEngine;
} else {
engine = null;
@@ -2151,7 +2232,8 @@ public class WallpaperManagerService extends IWallpaperManager.Stub
}
@Override
- public WallpaperColors getWallpaperColors(int which, int userId) throws RemoteException {
+ public WallpaperColors getWallpaperColors(int which, int userId, int displayId)
+ throws RemoteException {
if (which != FLAG_LOCK && which != FLAG_SYSTEM) {
throw new IllegalArgumentException("which should be either FLAG_LOCK or FLAG_SYSTEM");
}
@@ -2169,7 +2251,7 @@ public class WallpaperManagerService extends IWallpaperManager.Stub
// Try to get the system wallpaper anyway since it might
// also be the lock screen wallpaper
if (wallpaperData == null) {
- wallpaperData = mWallpaperMap.get(userId);
+ wallpaperData = findWallpaperAtDisplay(userId, displayId);
}
if (wallpaperData == null) {
@@ -2187,6 +2269,15 @@ public class WallpaperManagerService extends IWallpaperManager.Stub
}
}
+ private WallpaperData findWallpaperAtDisplay(int userId, int displayId) {
+ if (mFallbackWallpaper != null && mFallbackWallpaper.connection != null
+ && mFallbackWallpaper.connection.containsDisplay(displayId)) {
+ return mFallbackWallpaper;
+ } else {
+ return mWallpaperMap.get(userId);
+ }
+ }
+
@Override
public ParcelFileDescriptor setWallpaper(String name, String callingPackage,
Rect cropHint, boolean allowBackup, Bundle extras, int which,
@@ -2382,6 +2473,7 @@ public class WallpaperManagerService extends IWallpaperManager.Stub
if (shouldNotifyColors) {
notifyWallpaperColorsChanged(wallpaper, which);
+ notifyWallpaperColorsChanged(mFallbackWallpaper, FLAG_SYSTEM);
}
}
diff --git a/services/core/java/com/android/server/wm/AccessibilityController.java b/services/core/java/com/android/server/wm/AccessibilityController.java
index fe0b5c250da8..caebf1528270 100644
--- a/services/core/java/com/android/server/wm/AccessibilityController.java
+++ b/services/core/java/com/android/server/wm/AccessibilityController.java
@@ -1066,93 +1066,19 @@ final class AccessibilityController {
final int visibleWindowCount = visibleWindows.size();
HashSet<Integer> skipRemainingWindowsForTasks = new HashSet<>();
- for (int i = visibleWindowCount - 1; i >= 0; i--) {
- final WindowState windowState = visibleWindows.valueAt(i);
- final int flags = windowState.mAttrs.flags;
- final Task task = windowState.getTask();
- // If the window is part of a task that we're finished with - ignore.
- if (task != null && skipRemainingWindowsForTasks.contains(task.mTaskId)) {
- continue;
- }
-
- // Ignore non-touchable windows, except the split-screen divider, which is
- // occasionally non-touchable but still useful for identifying split-screen
- // mode.
- if (((flags & WindowManager.LayoutParams.FLAG_NOT_TOUCHABLE) != 0)
- && (windowState.mAttrs.type != TYPE_DOCK_DIVIDER)) {
- continue;
- }
+ // Iterate until we figure out what is touchable for the entire screen.
+ for (int i = visibleWindowCount - 1; i >= 0 && !unaccountedSpace.isEmpty(); i--) {
+ final WindowState windowState = visibleWindows.valueAt(i);
- // Compute the bounds in the screen.
final Rect boundsInScreen = mTempRect;
computeWindowBoundsInScreen(windowState, boundsInScreen);
- // If the window is completely covered by other windows - ignore.
- if (unaccountedSpace.quickReject(boundsInScreen)) {
- continue;
- }
-
- // Add windows of certain types not covered by modal windows.
- if (isReportedWindowType(windowState.mAttrs.type)) {
- // Add the window to the ones to be reported.
+ if (windowMattersToAccessibility(windowState, boundsInScreen, unaccountedSpace,
+ skipRemainingWindowsForTasks)) {
addPopulatedWindowInfo(windowState, boundsInScreen, windows, addedWindows);
- if (windowState.isFocused()) {
- focusedWindowAdded = true;
- }
- }
-
- if (windowState.mAttrs.type !=
- WindowManager.LayoutParams.TYPE_ACCESSIBILITY_OVERLAY) {
-
- // Account for the space this window takes if the window
- // is not an accessibility overlay which does not change
- // the reported windows.
- unaccountedSpace.op(boundsInScreen, unaccountedSpace,
- Region.Op.REVERSE_DIFFERENCE);
-
- // If a window is modal it prevents other windows from being touched
- if ((flags & (WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE
- | WindowManager.LayoutParams.FLAG_NOT_TOUCH_MODAL)) == 0) {
- // 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,
- Region.Op.REVERSE_DIFFERENCE);
-
- if (task != null) {
- // If the window is associated with a particular task, we can skip the
- // rest of the windows for that task.
- skipRemainingWindowsForTasks.add(task.mTaskId);
- continue;
- } else {
- // If the window is not associated with a particular task, then it is
- // globally modal. In this case we can skip all remaining windows.
- break;
- }
- }
- }
-
- // We figured out what is touchable for the entire screen - done.
- if (unaccountedSpace.isEmpty()) {
- break;
- }
- }
-
- // Always report the focused window.
- if (!focusedWindowAdded) {
- for (int i = visibleWindowCount - 1; i >= 0; i--) {
- WindowState windowState = visibleWindows.valueAt(i);
- if (windowState.isFocused()) {
- // Compute the bounds in the screen.
- Rect boundsInScreen = mTempRect;
- computeWindowBoundsInScreen(windowState, boundsInScreen);
-
- // Add the window to the ones to be reported.
- addPopulatedWindowInfo(
- windowState, boundsInScreen, windows, addedWindows);
- break;
- }
+ updateUnaccountedSpace(windowState, boundsInScreen, unaccountedSpace,
+ skipRemainingWindowsForTasks);
}
}
@@ -1221,6 +1147,73 @@ final class AccessibilityController {
clearAndRecycleWindows(windows);
}
+ private boolean windowMattersToAccessibility(WindowState windowState, Rect boundsInScreen,
+ Region unaccountedSpace, HashSet<Integer> skipRemainingWindowsForTasks) {
+ if (windowState.isFocused()) {
+ return true;
+ }
+
+ // If the window is part of a task that we're finished with - ignore.
+ final Task task = windowState.getTask();
+ if (task != null && skipRemainingWindowsForTasks.contains(task.mTaskId)) {
+ return false;
+ }
+
+ // Ignore non-touchable windows, except the split-screen divider, which is
+ // occasionally non-touchable but still useful for identifying split-screen
+ // mode.
+ if (((windowState.mAttrs.flags & WindowManager.LayoutParams.FLAG_NOT_TOUCHABLE) != 0)
+ && (windowState.mAttrs.type != TYPE_DOCK_DIVIDER)) {
+ return false;
+ }
+
+ // If the window is completely covered by other windows - ignore.
+ if (unaccountedSpace.quickReject(boundsInScreen)) {
+ return false;
+ }
+
+ // Add windows of certain types not covered by modal windows.
+ if (isReportedWindowType(windowState.mAttrs.type)) {
+ return true;
+ }
+
+ return false;
+ }
+
+ private void updateUnaccountedSpace(WindowState windowState, Rect boundsInScreen,
+ Region unaccountedSpace, HashSet<Integer> skipRemainingWindowsForTasks) {
+ if (windowState.mAttrs.type
+ != WindowManager.LayoutParams.TYPE_ACCESSIBILITY_OVERLAY) {
+
+ // Account for the space this window takes if the window
+ // is not an accessibility overlay which does not change
+ // the reported windows.
+ unaccountedSpace.op(boundsInScreen, unaccountedSpace,
+ Region.Op.REVERSE_DIFFERENCE);
+
+ // If a window is modal it prevents other windows from being touched
+ if ((windowState.mAttrs.flags & (WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE
+ | WindowManager.LayoutParams.FLAG_NOT_TOUCH_MODAL)) == 0) {
+ // 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,
+ Region.Op.REVERSE_DIFFERENCE);
+
+ final Task task = windowState.getTask();
+ if (task != null) {
+ // If the window is associated with a particular task, we can skip the
+ // rest of the windows for that task.
+ skipRemainingWindowsForTasks.add(task.mTaskId);
+ } else {
+ // If the window is not associated with a particular task, then it is
+ // globally modal. In this case we can skip all remaining windows.
+ unaccountedSpace.setEmpty();
+ }
+ }
+ }
+ }
+
private void computeWindowBoundsInScreen(WindowState windowState, Rect outBounds) {
// Get the touchable frame.
Region touchableRegion = mTempRegion1;
diff --git a/services/core/java/com/android/server/wm/ActivityRecord.java b/services/core/java/com/android/server/wm/ActivityRecord.java
index 8884615d2fe1..6f8f85f1af26 100644
--- a/services/core/java/com/android/server/wm/ActivityRecord.java
+++ b/services/core/java/com/android/server/wm/ActivityRecord.java
@@ -728,9 +728,10 @@ final class ActivityRecord extends ConfigurationContainer {
mLastReportedMultiWindowMode = inPictureInPictureMode;
final Configuration newConfig = new Configuration();
if (targetStackBounds != null && !targetStackBounds.isEmpty()) {
- task.computeResolvedOverrideConfiguration(newConfig,
- task.getParent().getConfiguration(),
- task.getRequestedOverrideConfiguration());
+ newConfig.setTo(task.getRequestedOverrideConfiguration());
+ Rect outBounds = newConfig.windowConfiguration.getBounds();
+ task.adjustForMinimalTaskDimensions(outBounds, outBounds);
+ task.computeConfigResourceOverrides(newConfig, task.getParent().getConfiguration());
}
schedulePictureInPictureModeChanged(newConfig);
scheduleMultiWindowModeChanged(newConfig);
@@ -2503,7 +2504,8 @@ final class ActivityRecord extends ConfigurationContainer {
return;
}
- final IBinder binder = freezeScreenIfNeeded ? appToken.asBinder() : null;
+ final IBinder binder =
+ (freezeScreenIfNeeded && appToken != null) ? appToken.asBinder() : null;
mAppWindowToken.setOrientation(requestedOrientation, binder, this);
}
@@ -2547,7 +2549,6 @@ final class ActivityRecord extends ConfigurationContainer {
// TODO(b/36505427): Consider moving this method and similar ones to ConfigurationContainer.
private void updateOverrideConfiguration() {
- mTmpConfig.unset();
computeBounds(mTmpBounds);
if (mTmpBounds.equals(getRequestedOverrideBounds())) {
@@ -2558,8 +2559,10 @@ final class ActivityRecord extends ConfigurationContainer {
// Bounds changed...update configuration to match.
if (!matchParentBounds()) {
- task.computeResolvedOverrideConfiguration(mTmpConfig,
- task.getParent().getConfiguration(), getRequestedOverrideConfiguration());
+ mTmpConfig.setTo(getRequestedOverrideConfiguration());
+ task.computeConfigResourceOverrides(mTmpConfig, task.getParent().getConfiguration());
+ } else {
+ mTmpConfig.unset();
}
onRequestedOverrideConfigurationChanged(mTmpConfig);
diff --git a/services/core/java/com/android/server/wm/AppWindowToken.java b/services/core/java/com/android/server/wm/AppWindowToken.java
index a5341ca11784..2157ef65da4c 100644
--- a/services/core/java/com/android/server/wm/AppWindowToken.java
+++ b/services/core/java/com/android/server/wm/AppWindowToken.java
@@ -1714,7 +1714,8 @@ class AppWindowToken extends WindowToken implements WindowManagerService.AppFree
if (mLetterbox == null) {
mLetterbox = new Letterbox(() -> makeChildSurface(null));
}
- mLetterbox.layout(getParent().getBounds(), w.getFrameLw());
+ getPosition(mTmpPoint);
+ mLetterbox.layout(getParent().getBounds(), w.getFrameLw(), mTmpPoint);
} else if (mLetterbox != null) {
mLetterbox.hide();
}
diff --git a/services/core/java/com/android/server/wm/ConfigurationContainer.java b/services/core/java/com/android/server/wm/ConfigurationContainer.java
index ded45c9e3079..650d0be76dc5 100644
--- a/services/core/java/com/android/server/wm/ConfigurationContainer.java
+++ b/services/core/java/com/android/server/wm/ConfigurationContainer.java
@@ -37,6 +37,7 @@ import static com.android.server.wm.ConfigurationContainerProto.OVERRIDE_CONFIGU
import android.annotation.CallSuper;
import android.app.WindowConfiguration;
import android.content.res.Configuration;
+import android.graphics.Point;
import android.graphics.Rect;
import android.util.proto.ProtoOutputStream;
@@ -243,6 +244,14 @@ public abstract class ConfigurationContainer<E extends ConfigurationContainer> {
}
/**
+ * Sets {@code out} to the top-left corner of the bounds as returned by {@link #getBounds()}.
+ */
+ public void getPosition(Point out) {
+ Rect bounds = getBounds();
+ out.set(bounds.left, bounds.top);
+ }
+
+ /**
* Returns the bounds requested on this container. These may not be the actual bounds the
* container ends up with due to policy constraints. The {@link Rect} handed back is
* shared for all calls to this method and should not be modified.
diff --git a/services/core/java/com/android/server/wm/DisplayContent.java b/services/core/java/com/android/server/wm/DisplayContent.java
index fecc8da3d645..740d47240bd0 100644
--- a/services/core/java/com/android/server/wm/DisplayContent.java
+++ b/services/core/java/com/android/server/wm/DisplayContent.java
@@ -3656,6 +3656,12 @@ class DisplayContent extends WindowContainer<DisplayContent.DisplayChildWindowCo
}
}
+ /** @returns the orientation of the display when it's rotation is ROTATION_0. */
+ int getNaturalOrientation() {
+ return mBaseDisplayWidth < mBaseDisplayHeight
+ ? ORIENTATION_PORTRAIT : ORIENTATION_LANDSCAPE;
+ }
+
void performLayout(boolean initial, boolean updateInputWindows) {
if (!isLayoutNeeded()) {
return;
diff --git a/services/core/java/com/android/server/wm/Letterbox.java b/services/core/java/com/android/server/wm/Letterbox.java
index 1a2aa2f252e6..33ff19415089 100644
--- a/services/core/java/com/android/server/wm/Letterbox.java
+++ b/services/core/java/com/android/server/wm/Letterbox.java
@@ -18,6 +18,7 @@ package com.android.server.wm;
import static android.view.SurfaceControl.HIDDEN;
+import android.graphics.Point;
import android.graphics.Rect;
import android.view.SurfaceControl;
@@ -30,6 +31,7 @@ import java.util.function.Supplier;
public class Letterbox {
private static final Rect EMPTY_RECT = new Rect();
+ private static final Point ZERO_POINT = new Point(0, 0);
private final Supplier<SurfaceControl.Builder> mFactory;
private final Rect mOuter = new Rect();
@@ -53,14 +55,19 @@ public class Letterbox {
* frames will be covered by black color surfaces.
*
* The caller must use {@link #applySurfaceChanges} to apply the new layout to the surface.
- *
* @param outer the outer frame of the letterbox (this frame will be black, except the area
- * that intersects with the {code inner} frame).
- * @param inner the inner frame of the letterbox (this frame will be clear)
+ * that intersects with the {code inner} frame), in global coordinates
+ * @param inner the inner frame of the letterbox (this frame will be clear), in global
+ * coordinates
+ * @param surfaceOrigin the origin of the surface factory in global coordinates
*/
- public void layout(Rect outer, Rect inner) {
+ public void layout(Rect outer, Rect inner, Point surfaceOrigin) {
mOuter.set(outer);
mInner.set(inner);
+ mOuter.offset(-surfaceOrigin.x, -surfaceOrigin.y);
+ mInner.offset(-surfaceOrigin.x, -surfaceOrigin.y);
+ outer = mOuter;
+ inner = mInner;
mTop.layout(outer.left, outer.top, inner.right, inner.top);
mLeft.layout(outer.left, inner.top, inner.left, outer.bottom);
@@ -94,7 +101,7 @@ public class Letterbox {
* The caller must use {@link #applySurfaceChanges} to apply the new layout to the surface.
*/
public void hide() {
- layout(EMPTY_RECT, EMPTY_RECT);
+ layout(EMPTY_RECT, EMPTY_RECT, ZERO_POINT);
}
/**
diff --git a/services/core/java/com/android/server/wm/Session.java b/services/core/java/com/android/server/wm/Session.java
index d85fdb03e4a6..937c9d9fc809 100644
--- a/services/core/java/com/android/server/wm/Session.java
+++ b/services/core/java/com/android/server/wm/Session.java
@@ -187,7 +187,7 @@ class Session extends IWindowSession.Stub implements IBinder.DeathRecipient {
Rect outFrame, Rect outOverscanInsets, Rect outContentInsets, Rect outVisibleInsets,
Rect outStableInsets, Rect outsets, Rect outBackdropFrame,
DisplayCutout.ParcelableWrapper cutout, MergedConfiguration mergedConfiguration,
- Surface outSurface, InsetsState outInsetsState) {
+ SurfaceControl outSurfaceControl, InsetsState outInsetsState) {
if (false) Slog.d(TAG_WM, ">>>>>> ENTERED relayout from "
+ Binder.getCallingPid());
Trace.traceBegin(TRACE_TAG_WINDOW_MANAGER, mRelayoutTag);
@@ -195,7 +195,7 @@ class Session extends IWindowSession.Stub implements IBinder.DeathRecipient {
requestedWidth, requestedHeight, viewFlags, flags, frameNumber,
outFrame, outOverscanInsets, outContentInsets, outVisibleInsets,
outStableInsets, outsets, outBackdropFrame, cutout,
- mergedConfiguration, outSurface, outInsetsState);
+ mergedConfiguration, outSurfaceControl, outInsetsState);
Trace.traceEnd(TRACE_TAG_WINDOW_MANAGER);
if (false) Slog.d(TAG_WM, "<<<<<< EXITING relayout to "
+ Binder.getCallingPid());
diff --git a/services/core/java/com/android/server/wm/TaskRecord.java b/services/core/java/com/android/server/wm/TaskRecord.java
index e3433228f2de..1d56f0489a8d 100644
--- a/services/core/java/com/android/server/wm/TaskRecord.java
+++ b/services/core/java/com/android/server/wm/TaskRecord.java
@@ -44,6 +44,9 @@ import static android.content.pm.ActivityInfo.RESIZE_MODE_FORCE_RESIZEABLE;
import static android.content.pm.ActivityInfo.RESIZE_MODE_RESIZEABLE;
import static android.content.pm.ActivityInfo.RESIZE_MODE_RESIZEABLE_AND_PIPABLE_DEPRECATED;
import static android.content.pm.ActivityInfo.RESIZE_MODE_RESIZEABLE_VIA_SDK_VERSION;
+import static android.content.res.Configuration.ORIENTATION_LANDSCAPE;
+import static android.content.res.Configuration.ORIENTATION_PORTRAIT;
+import static android.content.res.Configuration.ORIENTATION_UNDEFINED;
import static android.os.Trace.TRACE_TAG_ACTIVITY_MANAGER;
import static android.provider.Settings.Secure.USER_SETUP_COMPLETE;
import static android.view.Display.DEFAULT_DISPLAY;
@@ -1259,10 +1262,6 @@ class TaskRecord extends ConfigurationContainer {
setFrontOfTask();
}
- void addActivityAtBottom(ActivityRecord r) {
- addActivityAtIndex(0, r);
- }
-
void addActivityToTop(ActivityRecord r) {
addActivityAtIndex(mActivities.size(), r);
}
@@ -1278,6 +1277,34 @@ class TaskRecord extends ConfigurationContainer {
}
/**
+ * Checks if the root activity requires a particular orientation (either by override or
+ * activityInfo) and returns that. Otherwise, this returns ORIENTATION_UNDEFINED.
+ */
+ private int getRootActivityRequestedOrientation() {
+ ActivityRecord root = getRootActivity();
+ if (getRequestedOverrideConfiguration().orientation != ORIENTATION_UNDEFINED
+ || root == null) {
+ return getRequestedOverrideConfiguration().orientation;
+ }
+ int rootScreenOrientation = root.getOrientation();
+ if (rootScreenOrientation == ActivityInfo.SCREEN_ORIENTATION_NOSENSOR) {
+ // NOSENSOR means the display's "natural" orientation, so return that.
+ ActivityDisplay display = mStack != null ? mStack.getDisplay() : null;
+ if (display != null && display.mDisplayContent != null) {
+ return mStack.getDisplay().mDisplayContent.getNaturalOrientation();
+ }
+ } else if (rootScreenOrientation == ActivityInfo.SCREEN_ORIENTATION_LOCKED) {
+ // LOCKED means the activity's orientation remains unchanged, so return existing value.
+ return root.getConfiguration().orientation;
+ } else if (ActivityInfo.isFixedOrientationLandscape(rootScreenOrientation)) {
+ return ORIENTATION_LANDSCAPE;
+ } else if (ActivityInfo.isFixedOrientationPortrait(rootScreenOrientation)) {
+ return ORIENTATION_PORTRAIT;
+ }
+ return ORIENTATION_UNDEFINED;
+ }
+
+ /**
* Adds an activity {@param r} at the given {@param index}. The activity {@param r} must either
* be in the current task or unparented to any task.
*/
@@ -1741,7 +1768,7 @@ class TaskRecord extends ConfigurationContainer {
updateTaskDescription();
}
- private void adjustForMinimalTaskDimensions(Rect bounds, Rect previousBounds) {
+ void adjustForMinimalTaskDimensions(Rect bounds, Rect previousBounds) {
if (bounds == null) {
return;
}
@@ -1853,11 +1880,27 @@ class TaskRecord extends ConfigurationContainer {
@Override
public void onConfigurationChanged(Configuration newParentConfig) {
+ // Check if the new configuration supports persistent bounds (eg. is Freeform) and if so
+ // restore the last recorded non-fullscreen bounds.
+ final boolean prevPersistTaskBounds = getWindowConfiguration().persistTaskBounds();
+ final boolean nextPersistTaskBounds =
+ getRequestedOverrideConfiguration().windowConfiguration.persistTaskBounds()
+ || newParentConfig.windowConfiguration.persistTaskBounds();
+ if (!prevPersistTaskBounds && nextPersistTaskBounds
+ && mLastNonFullscreenBounds != null && !mLastNonFullscreenBounds.isEmpty()) {
+ // Bypass onRequestedOverrideConfigurationChanged here to avoid infinite loop.
+ getRequestedOverrideConfiguration().windowConfiguration
+ .setBounds(mLastNonFullscreenBounds);
+ }
+
final boolean wasInMultiWindowMode = inMultiWindowMode();
super.onConfigurationChanged(newParentConfig);
if (wasInMultiWindowMode != inMultiWindowMode()) {
mService.mStackSupervisor.scheduleUpdateMultiWindowMode(this);
}
+
+ // If the configuration supports persistent bounds (eg. Freeform), keep track of the
+ // current (non-fullscreen) bounds for persistence.
if (getWindowConfiguration().persistTaskBounds()) {
final Rect currentBounds = getRequestedOverrideBounds();
if (!currentBounds.isEmpty()) {
@@ -2047,7 +2090,7 @@ class TaskRecord extends ConfigurationContainer {
* configuring an "inherit-bounds" window which means that all configuration settings would
* just be inherited from the parent configuration.
**/
- void computeConfigResourceOverrides(@NonNull Configuration inOutConfig, @NonNull Rect bounds,
+ void computeConfigResourceOverrides(@NonNull Configuration inOutConfig,
@NonNull Configuration parentConfig) {
int windowingMode = inOutConfig.windowConfiguration.getWindowingMode();
if (windowingMode == WINDOWING_MODE_UNDEFINED) {
@@ -2060,6 +2103,7 @@ class TaskRecord extends ConfigurationContainer {
}
density *= DisplayMetrics.DENSITY_DEFAULT_SCALE;
+ final Rect bounds = inOutConfig.windowConfiguration.getBounds();
Rect outAppBounds = inOutConfig.windowConfiguration.getAppBounds();
if (outAppBounds == null || outAppBounds.isEmpty()) {
inOutConfig.windowConfiguration.setAppBounds(bounds);
@@ -2107,13 +2151,14 @@ class TaskRecord extends ConfigurationContainer {
// Iterating across all screen orientations, and return the minimum of the task
// width taking into account that the bounds might change because the snap
// algorithm snaps to a different value
- getSmallestScreenWidthDpForDockedBounds(bounds);
+ inOutConfig.smallestScreenWidthDp =
+ getSmallestScreenWidthDpForDockedBounds(bounds);
}
// otherwise, it will just inherit
}
}
- if (inOutConfig.orientation == Configuration.ORIENTATION_UNDEFINED) {
+ if (inOutConfig.orientation == ORIENTATION_UNDEFINED) {
inOutConfig.orientation = (inOutConfig.screenWidthDp <= inOutConfig.screenHeightDp)
? Configuration.ORIENTATION_PORTRAIT : Configuration.ORIENTATION_LANDSCAPE;
}
@@ -2134,36 +2179,56 @@ class TaskRecord extends ConfigurationContainer {
}
}
- // TODO(b/113900640): remove this once ActivityRecord is changed to not need it anymore.
- void computeResolvedOverrideConfiguration(Configuration inOutConfig, Configuration parentConfig,
- Configuration overrideConfig) {
- // Save previous bounds because adjustForMinimalTaskDimensions uses that to determine if it
- // changes left bound vs. right bound, or top bound vs. bottom bound.
- mTmpBounds.set(inOutConfig.windowConfiguration.getBounds());
-
- inOutConfig.setTo(overrideConfig);
-
- Rect outOverrideBounds = inOutConfig.windowConfiguration.getBounds();
- if (outOverrideBounds != null && !outOverrideBounds.isEmpty()) {
- adjustForMinimalTaskDimensions(outOverrideBounds, mTmpBounds);
-
- int windowingMode = overrideConfig.windowConfiguration.getWindowingMode();
- if (windowingMode == WINDOWING_MODE_UNDEFINED) {
- windowingMode = parentConfig.windowConfiguration.getWindowingMode();
- }
- if (windowingMode == WINDOWING_MODE_FREEFORM) {
- // by policy, make sure the window remains within parent
- fitWithinBounds(outOverrideBounds, parentConfig.windowConfiguration.getBounds());
+ @Override
+ void resolveOverrideConfiguration(Configuration newParentConfig) {
+ mTmpBounds.set(getResolvedOverrideConfiguration().windowConfiguration.getBounds());
+ super.resolveOverrideConfiguration(newParentConfig);
+ int windowingMode =
+ getRequestedOverrideConfiguration().windowConfiguration.getWindowingMode();
+ if (windowingMode == WINDOWING_MODE_UNDEFINED) {
+ windowingMode = newParentConfig.windowConfiguration.getWindowingMode();
+ }
+ Rect outOverrideBounds =
+ getResolvedOverrideConfiguration().windowConfiguration.getBounds();
+
+ if (windowingMode == WINDOWING_MODE_FULLSCREEN) {
+ // In FULLSCREEN mode, always start with empty bounds to indicate "fill parent"
+ outOverrideBounds.setEmpty();
+
+ // If the task or its root activity require a different orientation, make it fit the
+ // available bounds by scaling down its bounds.
+ int forcedOrientation = getRootActivityRequestedOrientation();
+ if (forcedOrientation != ORIENTATION_UNDEFINED
+ && forcedOrientation != newParentConfig.orientation) {
+ final Rect parentBounds = newParentConfig.windowConfiguration.getBounds();
+ final int parentWidth = parentBounds.width();
+ final int parentHeight = parentBounds.height();
+ final float aspect = ((float) parentHeight) / parentWidth;
+ if (forcedOrientation == ORIENTATION_LANDSCAPE) {
+ final int height = (int) (parentWidth / aspect);
+ final int top = parentBounds.centerY() - height / 2;
+ outOverrideBounds.set(
+ parentBounds.left, top, parentBounds.right, top + height);
+ } else {
+ final int width = (int) (parentHeight * aspect);
+ final int left = parentBounds.centerX() - width / 2;
+ outOverrideBounds.set(
+ left, parentBounds.top, left + width, parentBounds.bottom);
+ }
}
+ }
- computeConfigResourceOverrides(inOutConfig, outOverrideBounds, parentConfig);
+ if (outOverrideBounds.isEmpty()) {
+ // If the task fills the parent, just inherit all the other configs from parent.
+ return;
}
- }
- @Override
- void resolveOverrideConfiguration(Configuration newParentConfig) {
- computeResolvedOverrideConfiguration(getResolvedOverrideConfiguration(), newParentConfig,
- getRequestedOverrideConfiguration());
+ adjustForMinimalTaskDimensions(outOverrideBounds, mTmpBounds);
+ if (windowingMode == WINDOWING_MODE_FREEFORM) {
+ // by policy, make sure the window remains within parent somewhere
+ fitWithinBounds(outOverrideBounds, newParentConfig.windowConfiguration.getBounds());
+ }
+ computeConfigResourceOverrides(getResolvedOverrideConfiguration(), newParentConfig);
}
Rect updateOverrideConfigurationFromLaunchBounds() {
diff --git a/services/core/java/com/android/server/wm/TaskSnapshotSurface.java b/services/core/java/com/android/server/wm/TaskSnapshotSurface.java
index 9a56606aee7f..2d3e3aee4b7f 100644
--- a/services/core/java/com/android/server/wm/TaskSnapshotSurface.java
+++ b/services/core/java/com/android/server/wm/TaskSnapshotSurface.java
@@ -111,6 +111,7 @@ class TaskSnapshotSurface implements StartingSurface {
private static final String TITLE_FORMAT = "SnapshotStartingWindow for taskId=%s";
private final Window mWindow;
private final Surface mSurface;
+ private SurfaceControl mSurfaceControl;
private SurfaceControl mChildSurfaceControl;
private final IWindowSession mSession;
private final WindowManagerService mService;
@@ -136,7 +137,7 @@ class TaskSnapshotSurface implements StartingSurface {
final Window window = new Window();
final IWindowSession session = WindowManagerGlobal.getWindowSession();
window.setSession(session);
- final Surface surface = new Surface();
+ final SurfaceControl surfaceControl = new SurfaceControl();
final Rect tmpRect = new Rect();
final DisplayCutout.ParcelableWrapper tmpCutout = new DisplayCutout.ParcelableWrapper();
final Rect tmpFrame = new Rect();
@@ -213,14 +214,14 @@ class TaskSnapshotSurface implements StartingSurface {
// Local call.
}
final TaskSnapshotSurface snapshotSurface = new TaskSnapshotSurface(service, window,
- surface, snapshot, layoutParams.getTitle(), backgroundColor, statusBarColor,
+ surfaceControl, snapshot, layoutParams.getTitle(), backgroundColor, statusBarColor,
navigationBarColor, sysUiVis, windowFlags, windowPrivateFlags, taskBounds,
currentOrientation);
window.setOuter(snapshotSurface);
try {
session.relayout(window, window.mSeq, layoutParams, -1, -1, View.VISIBLE, 0, -1,
tmpFrame, tmpRect, tmpContentInsets, tmpRect, tmpStableInsets, tmpRect, tmpRect,
- tmpCutout, tmpMergedConfiguration, surface, mTmpInsetsState);
+ tmpCutout, tmpMergedConfiguration, surfaceControl, mTmpInsetsState);
} catch (RemoteException e) {
// Local call.
}
@@ -230,15 +231,16 @@ class TaskSnapshotSurface implements StartingSurface {
}
@VisibleForTesting
- TaskSnapshotSurface(WindowManagerService service, Window window, Surface surface,
+ TaskSnapshotSurface(WindowManagerService service, Window window, SurfaceControl surfaceControl,
TaskSnapshot snapshot, CharSequence title, int backgroundColor, int statusBarColor,
int navigationBarColor, int sysUiVis, int windowFlags, int windowPrivateFlags,
Rect taskBounds, int currentOrientation) {
mService = service;
+ mSurface = new Surface();
mHandler = new Handler(mService.mH.getLooper());
mSession = WindowManagerGlobal.getWindowSession();
mWindow = window;
- mSurface = surface;
+ mSurfaceControl = surfaceControl;
mSnapshot = snapshot;
mTitle = title;
mBackgroundPaint.setColor(backgroundColor != 0 ? backgroundColor : WHITE);
@@ -281,6 +283,8 @@ class TaskSnapshotSurface implements StartingSurface {
private void drawSnapshot() {
final GraphicBuffer buffer = mSnapshot.getSnapshot();
+ mSurface.copyFrom(mSurfaceControl);
+
if (DEBUG_STARTING_WINDOW) Slog.v(TAG, "Drawing snapshot surface sizeMismatch="
+ mSizeMismatch);
if (mSizeMismatch) {
@@ -310,13 +314,14 @@ class TaskSnapshotSurface implements StartingSurface {
if (!mSurface.isValid()) {
throw new IllegalStateException("mSurface does not hold a valid surface.");
}
- final SurfaceSession session = new SurfaceSession(mSurface);
+ final SurfaceSession session = new SurfaceSession();
// Keep a reference to it such that it doesn't get destroyed when finalized.
mChildSurfaceControl = new SurfaceControl.Builder(session)
.setName(mTitle + " - task-snapshot-surface")
.setBufferSize(buffer.getWidth(), buffer.getHeight())
.setFormat(buffer.getFormat())
+ .setParent(mSurfaceControl)
.build();
Surface surface = new Surface();
surface.copyFrom(mChildSurfaceControl);
diff --git a/services/core/java/com/android/server/wm/WindowManagerService.java b/services/core/java/com/android/server/wm/WindowManagerService.java
index f5f55e2ebf73..91aac7e0e8aa 100644
--- a/services/core/java/com/android/server/wm/WindowManagerService.java
+++ b/services/core/java/com/android/server/wm/WindowManagerService.java
@@ -1874,7 +1874,7 @@ public class WindowManagerService extends IWindowManager.Stub
long frameNumber, Rect outFrame, Rect outOverscanInsets, Rect outContentInsets,
Rect outVisibleInsets, Rect outStableInsets, Rect outOutsets, Rect outBackdropFrame,
DisplayCutout.ParcelableWrapper outCutout, MergedConfiguration mergedConfiguration,
- Surface outSurface, InsetsState outInsetsState) {
+ SurfaceControl outSurfaceControl, InsetsState outInsetsState) {
int result = 0;
boolean configChanged;
final boolean hasStatusBarPermission =
@@ -2047,7 +2047,7 @@ public class WindowManagerService extends IWindowManager.Stub
result = win.relayoutVisibleWindow(result, attrChanges, oldVisibility);
try {
- result = createSurfaceControl(outSurface, result, win, winAnimator);
+ result = createSurfaceControl(outSurfaceControl, result, win, winAnimator);
} catch (Exception e) {
displayContent.getInputMonitor().updateInputWindowsLw(true /*force*/);
@@ -2078,7 +2078,7 @@ public class WindowManagerService extends IWindowManager.Stub
// handled yet, or it might want to draw a last frame. If we already have a
// surface, let the client use that, but don't create new surface at this point.
Trace.traceBegin(TRACE_TAG_WINDOW_MANAGER, "relayoutWindow: getSurface");
- winAnimator.mSurfaceController.getSurface(outSurface);
+ winAnimator.mSurfaceController.getSurfaceControl(outSurfaceControl);
Trace.traceEnd(TRACE_TAG_WINDOW_MANAGER);
} else {
if (DEBUG_VISIBILITY) Slog.i(TAG_WM, "Releasing surface in: " + win);
@@ -2086,7 +2086,7 @@ public class WindowManagerService extends IWindowManager.Stub
try {
Trace.traceBegin(TRACE_TAG_WINDOW_MANAGER, "wmReleaseOutSurface_"
+ win.mAttrs.getTitle());
- outSurface.release();
+ outSurfaceControl.release();
} finally {
Trace.traceEnd(TRACE_TAG_WINDOW_MANAGER);
}
@@ -2182,7 +2182,7 @@ public class WindowManagerService extends IWindowManager.Stub
+ ", requestedHeight=" + requestedHeight
+ ", viewVisibility=" + viewVisibility
+ "\nRelayout returning frame=" + outFrame
- + ", surface=" + outSurface);
+ + ", surface=" + outSurfaceControl);
if (localLOGV || DEBUG_FOCUS) Slog.v(
TAG_WM, "Relayout of " + win + ": focusMayChange=" + focusMayChange);
@@ -2252,7 +2252,7 @@ public class WindowManagerService extends IWindowManager.Stub
return focusMayChange;
}
- private int createSurfaceControl(Surface outSurface, int result, WindowState win,
+ private int createSurfaceControl(SurfaceControl outSurfaceControl, int result, WindowState win,
WindowStateAnimator winAnimator) {
if (!win.mHasSurface) {
result |= RELAYOUT_RES_SURFACE_CHANGED;
@@ -2266,13 +2266,13 @@ public class WindowManagerService extends IWindowManager.Stub
Trace.traceEnd(TRACE_TAG_WINDOW_MANAGER);
}
if (surfaceController != null) {
- surfaceController.getSurface(outSurface);
- if (SHOW_TRANSACTIONS) Slog.i(TAG_WM, " OUT SURFACE " + outSurface + ": copied");
+ surfaceController.getSurfaceControl(outSurfaceControl);
+ if (SHOW_TRANSACTIONS) Slog.i(TAG_WM, " OUT SURFACE " + outSurfaceControl + ": copied");
} else {
// For some reason there isn't a surface. Clear the
// caller's object so they see the same state.
Slog.w(TAG_WM, "Failed to create surface control for " + win);
- outSurface.release();
+ outSurfaceControl.release();
}
return result;
@@ -6166,7 +6166,7 @@ public class WindowManagerService extends IWindowManager.Stub
dumpWindowsLocked(pw, true, null);
}
return;
- } else if ("all".equals(cmd) || "a".equals(cmd)) {
+ } else if ("all".equals(cmd)) {
synchronized (mGlobalLock) {
dumpWindowsLocked(pw, true, null);
}
diff --git a/services/core/java/com/android/server/wm/WindowSurfaceController.java b/services/core/java/com/android/server/wm/WindowSurfaceController.java
index ce627e23e6ee..c2a8e7efb5a5 100644
--- a/services/core/java/com/android/server/wm/WindowSurfaceController.java
+++ b/services/core/java/com/android/server/wm/WindowSurfaceController.java
@@ -478,8 +478,8 @@ class WindowSurfaceController {
return mSurfaceControl.getHandle();
}
- void getSurface(Surface outSurface) {
- outSurface.copyFrom(mSurfaceControl);
+ void getSurfaceControl(SurfaceControl outSurfaceControl) {
+ outSurfaceControl.copyFrom(mSurfaceControl);
}
int getLayer() {
diff --git a/services/devicepolicy/java/com/android/server/devicepolicy/AbUpdateInstaller.java b/services/devicepolicy/java/com/android/server/devicepolicy/AbUpdateInstaller.java
index 05912a5e3776..de5dd1749830 100644
--- a/services/devicepolicy/java/com/android/server/devicepolicy/AbUpdateInstaller.java
+++ b/services/devicepolicy/java/com/android/server/devicepolicy/AbUpdateInstaller.java
@@ -66,6 +66,9 @@ class AbUpdateInstaller extends UpdateInstaller {
map.put(
DOWNLOAD_STATE_INITIALIZATION_ERROR,
InstallUpdateCallback.UPDATE_ERROR_INCORRECT_OS_VERSION);
+ map.put(
+ UpdateEngine.ErrorCodeConstants.PAYLOAD_TIMESTAMP_ERROR,
+ InstallUpdateCallback.UPDATE_ERROR_INCORRECT_OS_VERSION);
// Error constants corresponding to errors related to bad update file.
map.put(
diff --git a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
index 781e1c4a41d9..7f6895a4cf83 100644
--- a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
+++ b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
@@ -4990,26 +4990,22 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager {
private boolean resetPasswordInternal(String password, long tokenHandle, byte[] token,
int flags, int callingUid, int userHandle) {
int quality;
- final int realQuality;
synchronized (getLockObject()) {
quality = getPasswordQuality(null, userHandle, /* parent */ false);
if (quality == DevicePolicyManager.PASSWORD_QUALITY_MANAGED) {
quality = PASSWORD_QUALITY_UNSPECIFIED;
}
final PasswordMetrics metrics = PasswordMetrics.computeForPassword(password);
- realQuality = metrics.quality;
- if (quality != PASSWORD_QUALITY_UNSPECIFIED) {
-
- if (realQuality < quality
- && quality != DevicePolicyManager.PASSWORD_QUALITY_COMPLEX) {
- Slog.w(LOG_TAG, "resetPassword: password quality 0x"
- + Integer.toHexString(realQuality)
- + " does not meet required quality 0x"
- + Integer.toHexString(quality));
- return false;
- }
- quality = Math.max(realQuality, quality);
+ final int realQuality = metrics.quality;
+ if (realQuality < quality
+ && quality != DevicePolicyManager.PASSWORD_QUALITY_COMPLEX) {
+ Slog.w(LOG_TAG, "resetPassword: password quality 0x"
+ + Integer.toHexString(realQuality)
+ + " does not meet required quality 0x"
+ + Integer.toHexString(quality));
+ return false;
}
+ quality = Math.max(realQuality, quality);
int length = getPasswordMinimumLength(null, userHandle, /* parent */ false);
if (password.length() < length) {
Slog.w(LOG_TAG, "resetPassword: password length " + password.length()
@@ -5086,7 +5082,7 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager {
try {
if (token == null) {
if (!TextUtils.isEmpty(password)) {
- mLockPatternUtils.saveLockPassword(password, null, realQuality, userHandle);
+ mLockPatternUtils.saveLockPassword(password, null, quality, userHandle);
} else {
mLockPatternUtils.clearLock(null, userHandle);
}
@@ -5095,7 +5091,7 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager {
result = mLockPatternUtils.setLockCredentialWithToken(password,
TextUtils.isEmpty(password) ? LockPatternUtils.CREDENTIAL_TYPE_NONE
: LockPatternUtils.CREDENTIAL_TYPE_PASSWORD,
- realQuality, tokenHandle, token, userHandle);
+ quality, tokenHandle, token, userHandle);
}
boolean requireEntry = (flags & DevicePolicyManager.RESET_PASSWORD_REQUIRE_ENTRY) != 0;
if (requireEntry) {
diff --git a/services/java/com/android/server/SystemServer.java b/services/java/com/android/server/SystemServer.java
index be09aea65073..4326c39c43a2 100644
--- a/services/java/com/android/server/SystemServer.java
+++ b/services/java/com/android/server/SystemServer.java
@@ -145,6 +145,7 @@ import com.android.server.webkit.WebViewUpdateService;
import com.android.server.wm.ActivityTaskManagerService;
import com.android.server.wm.WindowManagerGlobalLock;
import com.android.server.wm.WindowManagerService;
+import com.google.android.startop.iorap.IorapForwardingService;
import dalvik.system.VMRuntime;
@@ -1007,10 +1008,13 @@ public final class SystemServer {
mSystemServiceManager.startService(PinnerService.class);
traceEnd();
+ traceBeginAndSlog("IorapForwardingService");
+ mSystemServiceManager.startService(IorapForwardingService.class);
+ traceEnd();
+
traceBeginAndSlog("SignedConfigService");
SignedConfigService.registerUpdateReceiver(mSystemContext);
traceEnd();
-
} catch (RuntimeException e) {
Slog.e("System", "******************************************");
Slog.e("System", "************ Failure starting core service", e);
diff --git a/services/net/java/android/net/dhcp/DhcpLease.java b/services/net/java/android/net/dhcp/DhcpLease.java
index 6cdd2aa8579d..6849cfadc22a 100644
--- a/services/net/java/android/net/dhcp/DhcpLease.java
+++ b/services/net/java/android/net/dhcp/DhcpLease.java
@@ -58,6 +58,11 @@ public class DhcpLease {
mHostname = hostname;
}
+ /**
+ * Get the clientId associated with this lease, if any.
+ *
+ * <p>If the lease is not associated to a clientId, this returns null.
+ */
@Nullable
public byte[] getClientId() {
if (mClientId == null) {
@@ -97,6 +102,11 @@ public class DhcpLease {
(hostname == null ? mHostname : hostname));
}
+ /**
+ * Determine whether this lease matches a client with the specified parameters.
+ * @param clientId clientId of the client if any, or null otherwise.
+ * @param hwAddr Hardware address of the client.
+ */
public boolean matchesClient(@Nullable byte[] clientId, @NonNull MacAddress hwAddr) {
if (mClientId != null) {
return Arrays.equals(mClientId, clientId);
@@ -110,7 +120,7 @@ public class DhcpLease {
if (!(obj instanceof DhcpLease)) {
return false;
}
- final DhcpLease other = (DhcpLease)obj;
+ final DhcpLease other = (DhcpLease) obj;
return Arrays.equals(mClientId, other.mClientId)
&& mHwAddr.equals(other.mHwAddr)
&& mNetAddr.equals(other.mNetAddr)
diff --git a/services/net/java/android/net/dhcp/DhcpLeaseRepository.java b/services/net/java/android/net/dhcp/DhcpLeaseRepository.java
index 2dda42124c75..b3d0512ba447 100644
--- a/services/net/java/android/net/dhcp/DhcpLeaseRepository.java
+++ b/services/net/java/android/net/dhcp/DhcpLeaseRepository.java
@@ -29,8 +29,8 @@ import android.annotation.NonNull;
import android.annotation.Nullable;
import android.net.IpPrefix;
import android.net.MacAddress;
-import android.net.util.SharedLog;
import android.net.dhcp.DhcpServer.Clock;
+import android.net.util.SharedLog;
import android.util.ArrayMap;
import java.net.Inet4Address;
@@ -117,7 +117,7 @@ class DhcpLeaseRepository {
*/
private final LinkedHashMap<Inet4Address, Long> mDeclinedAddrs = new LinkedHashMap<>();
- public DhcpLeaseRepository(@NonNull IpPrefix prefix, @NonNull Set<Inet4Address> reservedAddrs,
+ DhcpLeaseRepository(@NonNull IpPrefix prefix, @NonNull Set<Inet4Address> reservedAddrs,
long leaseTimeMs, @NonNull SharedLog log, @NonNull Clock clock) {
updateParams(prefix, reservedAddrs, leaseTimeMs);
mLog = log;
@@ -250,8 +250,8 @@ class DhcpLeaseRepository {
// reqAddr null (RENEWING/REBINDING): client renewing its own lease for clientAddr.
// reqAddr set with sid not set (INIT-REBOOT): client verifying configuration.
// In both cases, throw if clientAddr or reqAddr does not match the known lease.
- throw new InvalidAddressException("Incorrect address for client in " +
- (reqAddr != null ? "INIT-REBOOT" : "RENEWING/REBINDING"));
+ throw new InvalidAddressException("Incorrect address for client in "
+ + (reqAddr != null ? "INIT-REBOOT" : "RENEWING/REBINDING"));
}
}
diff --git a/services/net/java/android/net/dhcp/DhcpPacketListener.java b/services/net/java/android/net/dhcp/DhcpPacketListener.java
index 6f620c5ce30e..dce8b619494e 100644
--- a/services/net/java/android/net/dhcp/DhcpPacketListener.java
+++ b/services/net/java/android/net/dhcp/DhcpPacketListener.java
@@ -32,32 +32,32 @@ import java.net.InetSocketAddress;
*/
abstract class DhcpPacketListener extends FdEventsReader<DhcpPacketListener.Payload> {
static final class Payload {
- final byte[] bytes = new byte[DhcpPacket.MAX_LENGTH];
- Inet4Address srcAddr;
- int srcPort;
+ protected final byte[] mBytes = new byte[DhcpPacket.MAX_LENGTH];
+ protected Inet4Address mSrcAddr;
+ protected int mSrcPort;
}
- public DhcpPacketListener(@NonNull Handler handler) {
+ DhcpPacketListener(@NonNull Handler handler) {
super(handler, new Payload());
}
@Override
protected int recvBufSize(@NonNull Payload buffer) {
- return buffer.bytes.length;
+ return buffer.mBytes.length;
}
@Override
protected final void handlePacket(@NonNull Payload recvbuf, int length) {
- if (recvbuf.srcAddr == null) {
+ if (recvbuf.mSrcAddr == null) {
return;
}
try {
- final DhcpPacket packet = DhcpPacket.decodeFullPacket(recvbuf.bytes, length,
+ final DhcpPacket packet = DhcpPacket.decodeFullPacket(recvbuf.mBytes, length,
DhcpPacket.ENCAP_BOOTP);
- onReceive(packet, recvbuf.srcAddr, recvbuf.srcPort);
+ onReceive(packet, recvbuf.mSrcAddr, recvbuf.mSrcPort);
} catch (DhcpPacket.ParseException e) {
- logParseError(recvbuf.bytes, length, e);
+ logParseError(recvbuf.mBytes, length, e);
}
}
@@ -66,11 +66,11 @@ abstract class DhcpPacketListener extends FdEventsReader<DhcpPacketListener.Payl
throws Exception {
final InetSocketAddress addr = new InetSocketAddress();
final int read = Os.recvfrom(
- fd, packetBuffer.bytes, 0, packetBuffer.bytes.length, 0 /* flags */, addr);
+ fd, packetBuffer.mBytes, 0, packetBuffer.mBytes.length, 0 /* flags */, addr);
// Buffers with null srcAddr will be dropped in handlePacket()
- packetBuffer.srcAddr = inet4AddrOrNull(addr);
- packetBuffer.srcPort = addr.getPort();
+ packetBuffer.mSrcAddr = inet4AddrOrNull(addr);
+ packetBuffer.mSrcPort = addr.getPort();
return read;
}
diff --git a/services/net/java/android/net/dhcp/DhcpServer.java b/services/net/java/android/net/dhcp/DhcpServer.java
index 35d29e75c0e4..641bba2ed306 100644
--- a/services/net/java/android/net/dhcp/DhcpServer.java
+++ b/services/net/java/android/net/dhcp/DhcpServer.java
@@ -101,6 +101,13 @@ public class DhcpServer {
@NonNull
private DhcpServingParams mServingParams;
+ /**
+ * Clock to be used by DhcpServer to track time for lease expiration.
+ *
+ * <p>The clock should track time as may be measured by clients obtaining a lease. It does not
+ * need to be monotonous across restarts of the server as long as leases are cleared when the
+ * server is stopped.
+ */
public static class Clock {
/**
* @see SystemClock#elapsedRealtime()
@@ -110,13 +117,43 @@ public class DhcpServer {
}
}
+ /**
+ * Dependencies for the DhcpServer. Useful to be mocked in tests.
+ */
public interface Dependencies {
+ /**
+ * Send a packet to the specified datagram socket.
+ *
+ * @param fd File descriptor of the socket.
+ * @param buffer Data to be sent.
+ * @param dst Destination address of the packet.
+ */
void sendPacket(@NonNull FileDescriptor fd, @NonNull ByteBuffer buffer,
@NonNull InetAddress dst) throws ErrnoException, IOException;
+
+ /**
+ * Create a DhcpLeaseRepository for the server.
+ * @param servingParams Parameters used to serve DHCP requests.
+ * @param log Log to be used by the repository.
+ * @param clock Clock that the repository must use to track time.
+ */
DhcpLeaseRepository makeLeaseRepository(@NonNull DhcpServingParams servingParams,
@NonNull SharedLog log, @NonNull Clock clock);
+
+ /**
+ * Create a packet listener that will send packets to be processed.
+ */
DhcpPacketListener makePacketListener();
+
+ /**
+ * Create a clock that the server will use to track time.
+ */
Clock makeClock();
+
+ /**
+ * Add an entry to the ARP cache table.
+ * @param fd Datagram socket file descriptor that must use the new entry.
+ */
void addArpEntry(@NonNull Inet4Address ipv4Addr, @NonNull MacAddress ethAddr,
@NonNull String ifname, @NonNull FileDescriptor fd) throws IOException;
}
@@ -134,7 +171,7 @@ public class DhcpServer {
return new DhcpLeaseRepository(
DhcpServingParams.makeIpPrefix(servingParams.serverAddr),
servingParams.excludedAddrs,
- servingParams.dhcpLeaseTimeSecs*1000, log.forSubComponent(REPO_TAG), clock);
+ servingParams.dhcpLeaseTimeSecs * 1000, log.forSubComponent(REPO_TAG), clock);
}
@Override
@@ -212,7 +249,7 @@ public class DhcpServer {
}
private class ServerHandler extends Handler {
- public ServerHandler(@NonNull Looper looper) {
+ ServerHandler(@NonNull Looper looper) {
super(looper);
}
@@ -496,22 +533,24 @@ public class DhcpServer {
}
private class PacketListener extends DhcpPacketListener {
- public PacketListener() {
+ PacketListener() {
super(mHandler);
}
@Override
- protected void onReceive(DhcpPacket packet, Inet4Address srcAddr, int srcPort) {
+ protected void onReceive(@NonNull DhcpPacket packet, @NonNull Inet4Address srcAddr,
+ int srcPort) {
processPacket(packet, srcPort);
}
@Override
- protected void logError(String msg, Exception e) {
+ protected void logError(@NonNull String msg, Exception e) {
mLog.e("Error receiving packet: " + msg, e);
}
@Override
- protected void logParseError(byte[] packet, int length, DhcpPacket.ParseException e) {
+ protected void logParseError(@NonNull byte[] packet, int length,
+ @NonNull DhcpPacket.ParseException e) {
mLog.e("Error parsing packet", e);
}
diff --git a/services/net/java/android/net/dhcp/DhcpServingParams.java b/services/net/java/android/net/dhcp/DhcpServingParams.java
index df15ba1c5507..2780814a2f33 100644
--- a/services/net/java/android/net/dhcp/DhcpServingParams.java
+++ b/services/net/java/android/net/dhcp/DhcpServingParams.java
@@ -17,6 +17,7 @@
package android.net.dhcp;
import static android.net.NetworkUtils.getPrefixMaskAsInet4Address;
+import static android.net.NetworkUtils.intToInet4AddressHTH;
import static android.net.dhcp.DhcpPacket.INFINITE_LEASE;
import static android.net.util.NetworkConstants.IPV4_MAX_MTU;
import static android.net.util.NetworkConstants.IPV4_MIN_MTU;
@@ -24,6 +25,7 @@ import static android.net.util.NetworkConstants.IPV4_MIN_MTU;
import static java.lang.Integer.toUnsignedLong;
import android.annotation.NonNull;
+import android.annotation.Nullable;
import android.net.IpPrefix;
import android.net.LinkAddress;
import android.net.NetworkUtils;
@@ -103,6 +105,37 @@ public class DhcpServingParams {
this.metered = metered;
}
+ /**
+ * Create parameters from a stable AIDL-compatible parcel.
+ */
+ public static DhcpServingParams fromParcelableObject(@NonNull DhcpServingParamsParcel parcel)
+ throws InvalidParameterException {
+ final LinkAddress serverAddr = new LinkAddress(
+ intToInet4AddressHTH(parcel.serverAddr),
+ parcel.serverAddrPrefixLength);
+ return new Builder()
+ .setServerAddr(serverAddr)
+ .setDefaultRouters(toInet4AddressSet(parcel.defaultRouters))
+ .setDnsServers(toInet4AddressSet(parcel.dnsServers))
+ .setExcludedAddrs(toInet4AddressSet(parcel.excludedAddrs))
+ .setDhcpLeaseTimeSecs(parcel.dhcpLeaseTimeSecs)
+ .setLinkMtu(parcel.linkMtu)
+ .setMetered(parcel.metered)
+ .build();
+ }
+
+ private static Set<Inet4Address> toInet4AddressSet(@Nullable int[] addrs) {
+ if (addrs == null) {
+ return new HashSet<>(0);
+ }
+
+ final HashSet<Inet4Address> res = new HashSet<>();
+ for (int addr : addrs) {
+ res.add(intToInet4AddressHTH(addr));
+ }
+ return res;
+ }
+
@NonNull
public Inet4Address getServerInet4Addr() {
return (Inet4Address) serverAddr.getAddress();
@@ -134,13 +167,13 @@ public class DhcpServingParams {
* of the parameters.
*/
public static class Builder {
- private LinkAddress serverAddr;
- private Set<Inet4Address> defaultRouters;
- private Set<Inet4Address> dnsServers;
- private Set<Inet4Address> excludedAddrs;
- private long dhcpLeaseTimeSecs;
- private int linkMtu = MTU_UNSET;
- private boolean metered;
+ private LinkAddress mServerAddr;
+ private Set<Inet4Address> mDefaultRouters;
+ private Set<Inet4Address> mDnsServers;
+ private Set<Inet4Address> mExcludedAddrs;
+ private long mDhcpLeaseTimeSecs;
+ private int mLinkMtu = MTU_UNSET;
+ private boolean mMetered;
/**
* Set the server address and served prefix for the DHCP server.
@@ -148,7 +181,7 @@ public class DhcpServingParams {
* <p>This parameter is required.
*/
public Builder setServerAddr(@NonNull LinkAddress serverAddr) {
- this.serverAddr = serverAddr;
+ this.mServerAddr = serverAddr;
return this;
}
@@ -159,7 +192,7 @@ public class DhcpServingParams {
* always be set explicitly before building the {@link DhcpServingParams}.
*/
public Builder setDefaultRouters(@NonNull Set<Inet4Address> defaultRouters) {
- this.defaultRouters = defaultRouters;
+ this.mDefaultRouters = defaultRouters;
return this;
}
@@ -189,7 +222,7 @@ public class DhcpServingParams {
* {@link DhcpServingParams}.
*/
public Builder setDnsServers(@NonNull Set<Inet4Address> dnsServers) {
- this.dnsServers = dnsServers;
+ this.mDnsServers = dnsServers;
return this;
}
@@ -219,7 +252,7 @@ public class DhcpServingParams {
* and do not need to be set here.
*/
public Builder setExcludedAddrs(@NonNull Set<Inet4Address> excludedAddrs) {
- this.excludedAddrs = excludedAddrs;
+ this.mExcludedAddrs = excludedAddrs;
return this;
}
@@ -239,7 +272,7 @@ public class DhcpServingParams {
* <p>This parameter is required.
*/
public Builder setDhcpLeaseTimeSecs(long dhcpLeaseTimeSecs) {
- this.dhcpLeaseTimeSecs = dhcpLeaseTimeSecs;
+ this.mDhcpLeaseTimeSecs = dhcpLeaseTimeSecs;
return this;
}
@@ -250,7 +283,7 @@ public class DhcpServingParams {
* is optional and defaults to {@link #MTU_UNSET}.
*/
public Builder setLinkMtu(int linkMtu) {
- this.linkMtu = linkMtu;
+ this.mLinkMtu = linkMtu;
return this;
}
@@ -260,7 +293,7 @@ public class DhcpServingParams {
* <p>If not set, the default value is false.
*/
public Builder setMetered(boolean metered) {
- this.metered = metered;
+ this.mMetered = metered;
return this;
}
@@ -274,54 +307,57 @@ public class DhcpServingParams {
*/
@NonNull
public DhcpServingParams build() throws InvalidParameterException {
- if (serverAddr == null) {
+ if (mServerAddr == null) {
throw new InvalidParameterException("Missing serverAddr");
}
- if (defaultRouters == null) {
+ if (mDefaultRouters == null) {
throw new InvalidParameterException("Missing defaultRouters");
}
- if (dnsServers == null) {
+ if (mDnsServers == null) {
// Empty set is OK, but enforce explicitly setting it
throw new InvalidParameterException("Missing dnsServers");
}
- if (dhcpLeaseTimeSecs <= 0 || dhcpLeaseTimeSecs > toUnsignedLong(INFINITE_LEASE)) {
- throw new InvalidParameterException("Invalid lease time: " + dhcpLeaseTimeSecs);
+ if (mDhcpLeaseTimeSecs <= 0 || mDhcpLeaseTimeSecs > toUnsignedLong(INFINITE_LEASE)) {
+ throw new InvalidParameterException("Invalid lease time: " + mDhcpLeaseTimeSecs);
}
- if (linkMtu != MTU_UNSET && (linkMtu < IPV4_MIN_MTU || linkMtu > IPV4_MAX_MTU)) {
- throw new InvalidParameterException("Invalid link MTU: " + linkMtu);
+ if (mLinkMtu != MTU_UNSET && (mLinkMtu < IPV4_MIN_MTU || mLinkMtu > IPV4_MAX_MTU)) {
+ throw new InvalidParameterException("Invalid link MTU: " + mLinkMtu);
}
- if (!serverAddr.isIPv4()) {
+ if (!mServerAddr.isIPv4()) {
throw new InvalidParameterException("serverAddr must be IPv4");
}
- if (serverAddr.getPrefixLength() < MIN_PREFIX_LENGTH
- || serverAddr.getPrefixLength() > MAX_PREFIX_LENGTH) {
+ if (mServerAddr.getPrefixLength() < MIN_PREFIX_LENGTH
+ || mServerAddr.getPrefixLength() > MAX_PREFIX_LENGTH) {
throw new InvalidParameterException("Prefix length is not in supported range");
}
- final IpPrefix prefix = makeIpPrefix(serverAddr);
- for (Inet4Address addr : defaultRouters) {
+ final IpPrefix prefix = makeIpPrefix(mServerAddr);
+ for (Inet4Address addr : mDefaultRouters) {
if (!prefix.contains(addr)) {
throw new InvalidParameterException(String.format(
- "Default router %s is not in server prefix %s", addr, serverAddr));
+ "Default router %s is not in server prefix %s", addr, mServerAddr));
}
}
final Set<Inet4Address> excl = new HashSet<>();
- if (excludedAddrs != null) {
- excl.addAll(excludedAddrs);
+ if (mExcludedAddrs != null) {
+ excl.addAll(mExcludedAddrs);
}
- excl.add((Inet4Address) serverAddr.getAddress());
- excl.addAll(defaultRouters);
- excl.addAll(dnsServers);
+ excl.add((Inet4Address) mServerAddr.getAddress());
+ excl.addAll(mDefaultRouters);
+ excl.addAll(mDnsServers);
- return new DhcpServingParams(serverAddr,
- Collections.unmodifiableSet(new HashSet<>(defaultRouters)),
- Collections.unmodifiableSet(new HashSet<>(dnsServers)),
+ return new DhcpServingParams(mServerAddr,
+ Collections.unmodifiableSet(new HashSet<>(mDefaultRouters)),
+ Collections.unmodifiableSet(new HashSet<>(mDnsServers)),
Collections.unmodifiableSet(excl),
- dhcpLeaseTimeSecs, linkMtu, metered);
+ mDhcpLeaseTimeSecs, mLinkMtu, mMetered);
}
}
+ /**
+ * Utility method to create an IpPrefix with the address and prefix length of a LinkAddress.
+ */
@NonNull
static IpPrefix makeIpPrefix(@NonNull LinkAddress addr) {
return new IpPrefix(addr.getAddress(), addr.getPrefixLength());
diff --git a/services/net/java/android/net/dhcp/DhcpServingParamsParcelExt.java b/services/net/java/android/net/dhcp/DhcpServingParamsParcelExt.java
new file mode 100644
index 000000000000..f068c3ac16e2
--- /dev/null
+++ b/services/net/java/android/net/dhcp/DhcpServingParamsParcelExt.java
@@ -0,0 +1,172 @@
+/*
+ * 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 android.net.dhcp;
+
+import static android.net.NetworkUtils.inet4AddressToIntHTH;
+
+import android.annotation.NonNull;
+import android.net.LinkAddress;
+
+import com.google.android.collect.Sets;
+
+import java.net.Inet4Address;
+import java.util.Collection;
+import java.util.Set;
+
+/**
+ * Subclass of {@link DhcpServingParamsParcel} with additional utility methods for building.
+ *
+ * <p>This utility class does not check for validity of the parameters: invalid parameters are
+ * reported by the receiving module when unparceling the parcel.
+ *
+ * @see DhcpServingParams
+ * @hide
+ */
+public class DhcpServingParamsParcelExt extends DhcpServingParamsParcel {
+ public static final int MTU_UNSET = 0;
+
+ /**
+ * Set the server address and served prefix for the DHCP server.
+ *
+ * <p>This parameter is required.
+ */
+ public DhcpServingParamsParcelExt setServerAddr(@NonNull LinkAddress serverAddr) {
+ this.serverAddr = inet4AddressToIntHTH((Inet4Address) serverAddr.getAddress());
+ this.serverAddrPrefixLength = serverAddr.getPrefixLength();
+ return this;
+ }
+
+ /**
+ * Set the default routers to be advertised to DHCP clients.
+ *
+ * <p>Each router must be inside the served prefix. This may be an empty set, but it must
+ * always be set explicitly.
+ */
+ public DhcpServingParamsParcelExt setDefaultRouters(@NonNull Set<Inet4Address> defaultRouters) {
+ this.defaultRouters = toIntArray(defaultRouters);
+ return this;
+ }
+
+ /**
+ * Set the default routers to be advertised to DHCP clients.
+ *
+ * <p>Each router must be inside the served prefix. This may be an empty list of routers,
+ * but it must always be set explicitly.
+ */
+ public DhcpServingParamsParcelExt setDefaultRouters(@NonNull Inet4Address... defaultRouters) {
+ return setDefaultRouters(Sets.newArraySet(defaultRouters));
+ }
+
+ /**
+ * Convenience method to build the parameters with no default router.
+ *
+ * <p>Equivalent to calling {@link #setDefaultRouters(Inet4Address...)} with no address.
+ */
+ public DhcpServingParamsParcelExt setNoDefaultRouter() {
+ return setDefaultRouters();
+ }
+
+ /**
+ * Set the DNS servers to be advertised to DHCP clients.
+ *
+ * <p>This may be an empty set, but it must always be set explicitly.
+ */
+ public DhcpServingParamsParcelExt setDnsServers(@NonNull Set<Inet4Address> dnsServers) {
+ this.dnsServers = toIntArray(dnsServers);
+ return this;
+ }
+
+ /**
+ * Set the DNS servers to be advertised to DHCP clients.
+ *
+ * <p>This may be an empty list of servers, but it must always be set explicitly.
+ */
+ public DhcpServingParamsParcelExt setDnsServers(@NonNull Inet4Address... dnsServers) {
+ return setDnsServers(Sets.newArraySet(dnsServers));
+ }
+
+ /**
+ * Convenience method to build the parameters with no DNS server.
+ *
+ * <p>Equivalent to calling {@link #setDnsServers(Inet4Address...)} with no address.
+ */
+ public DhcpServingParamsParcelExt setNoDnsServer() {
+ return setDnsServers();
+ }
+
+ /**
+ * Set excluded addresses that the DHCP server is not allowed to assign to clients.
+ *
+ * <p>This parameter is optional. DNS servers and default routers are always excluded
+ * and do not need to be set here.
+ */
+ public DhcpServingParamsParcelExt setExcludedAddrs(@NonNull Set<Inet4Address> excludedAddrs) {
+ this.excludedAddrs = toIntArray(excludedAddrs);
+ return this;
+ }
+
+ /**
+ * Set excluded addresses that the DHCP server is not allowed to assign to clients.
+ *
+ * <p>This parameter is optional. DNS servers and default routers are always excluded
+ * and do not need to be set here.
+ */
+ public DhcpServingParamsParcelExt setExcludedAddrs(@NonNull Inet4Address... excludedAddrs) {
+ return setExcludedAddrs(Sets.newArraySet(excludedAddrs));
+ }
+
+ /**
+ * Set the lease time for leases assigned by the DHCP server.
+ *
+ * <p>This parameter is required.
+ */
+ public DhcpServingParamsParcelExt setDhcpLeaseTimeSecs(long dhcpLeaseTimeSecs) {
+ this.dhcpLeaseTimeSecs = dhcpLeaseTimeSecs;
+ return this;
+ }
+
+ /**
+ * Set the link MTU to be advertised to DHCP clients.
+ *
+ * <p>If set to {@link #MTU_UNSET}, no MTU will be advertised to clients. This parameter
+ * is optional and defaults to {@link #MTU_UNSET}.
+ */
+ public DhcpServingParamsParcelExt setLinkMtu(int linkMtu) {
+ this.linkMtu = linkMtu;
+ return this;
+ }
+
+ /**
+ * Set whether the DHCP server should send the ANDROID_METERED vendor-specific option.
+ *
+ * <p>If not set, the default value is false.
+ */
+ public DhcpServingParamsParcelExt setMetered(boolean metered) {
+ this.metered = metered;
+ return this;
+ }
+
+ private static int[] toIntArray(@NonNull Collection<Inet4Address> addrs) {
+ int[] res = new int[addrs.size()];
+ int i = 0;
+ for (Inet4Address addr : addrs) {
+ res[i] = inet4AddressToIntHTH(addr);
+ i++;
+ }
+ return res;
+ }
+}
diff --git a/services/net/java/android/net/util/SharedLog.java b/services/net/java/android/net/util/SharedLog.java
index 5a73a4e492ee..74bc1470293f 100644
--- a/services/net/java/android/net/util/SharedLog.java
+++ b/services/net/java/android/net/util/SharedLog.java
@@ -35,8 +35,8 @@ import java.util.StringJoiner;
* @hide
*/
public class SharedLog {
- private final static int DEFAULT_MAX_RECORDS = 500;
- private final static String COMPONENT_DELIMITER = ".";
+ private static final int DEFAULT_MAX_RECORDS = 500;
+ private static final String COMPONENT_DELIMITER = ".";
private enum Category {
NONE,
@@ -69,6 +69,9 @@ public class SharedLog {
mComponent = component;
}
+ /**
+ * Create a SharedLog based on this log with an additional component prefix on each logged line.
+ */
public SharedLog forSubComponent(String component) {
if (!isRootLogInstance()) {
component = mComponent + COMPONENT_DELIMITER + component;
@@ -76,6 +79,11 @@ public class SharedLog {
return new SharedLog(mLocalLog, mTag, component);
}
+ /**
+ * Dump the contents of this log.
+ *
+ * <p>This method may be called on any thread.
+ */
public void dump(FileDescriptor fd, PrintWriter writer, String[] args) {
mLocalLog.readOnlyLocalLog().dump(fd, writer, args);
}
@@ -84,10 +92,21 @@ public class SharedLog {
// Methods that both log an entry and emit it to the system log.
//////
+ /**
+ * Log an error due to an exception. This does not include the exception stacktrace.
+ *
+ * <p>The log entry will be also added to the system log.
+ * @see #e(String, Throwable)
+ */
public void e(Exception e) {
Log.e(mTag, record(Category.ERROR, e.toString()));
}
+ /**
+ * Log an error message.
+ *
+ * <p>The log entry will be also added to the system log.
+ */
public void e(String msg) {
Log.e(mTag, record(Category.ERROR, msg));
}
@@ -96,7 +115,7 @@ public class SharedLog {
* Log an error due to an exception, with the exception stacktrace if provided.
*
* <p>The error and exception message appear in the shared log, but the stacktrace is only
- * logged in general log output (logcat).
+ * logged in general log output (logcat). The log entry will be also added to the system log.
*/
public void e(@NonNull String msg, @Nullable Throwable exception) {
if (exception == null) {
@@ -106,10 +125,20 @@ public class SharedLog {
Log.e(mTag, record(Category.ERROR, msg + ": " + exception.getMessage()), exception);
}
+ /**
+ * Log an informational message.
+ *
+ * <p>The log entry will be also added to the system log.
+ */
public void i(String msg) {
Log.i(mTag, record(Category.NONE, msg));
}
+ /**
+ * Log a warning message.
+ *
+ * <p>The log entry will be also added to the system log.
+ */
public void w(String msg) {
Log.w(mTag, record(Category.WARN, msg));
}
@@ -118,14 +147,30 @@ public class SharedLog {
// Methods that only log an entry (and do NOT emit to the system log).
//////
+ /**
+ * Log a general message to be only included in the in-memory log.
+ *
+ * <p>The log entry will *not* be added to the system log.
+ */
public void log(String msg) {
record(Category.NONE, msg);
}
+ /**
+ * Log a general, formatted message to be only included in the in-memory log.
+ *
+ * <p>The log entry will *not* be added to the system log.
+ * @see String#format(String, Object...)
+ */
public void logf(String fmt, Object... args) {
log(String.format(fmt, args));
}
+ /**
+ * Log a message with MARK level.
+ *
+ * <p>The log entry will *not* be added to the system log.
+ */
public void mark(String msg) {
record(Category.MARK, msg);
}
diff --git a/services/robotests/backup/src/com/android/server/backup/BackupManagerServiceTest.java b/services/robotests/backup/src/com/android/server/backup/BackupManagerServiceTest.java
index b682def9c224..769a9d4a2bd4 100644
--- a/services/robotests/backup/src/com/android/server/backup/BackupManagerServiceTest.java
+++ b/services/robotests/backup/src/com/android/server/backup/BackupManagerServiceTest.java
@@ -16,6 +16,7 @@
package com.android.server.backup;
+import static android.Manifest.permission.BACKUP;
import static android.Manifest.permission.INTERACT_ACROSS_USERS_FULL;
import static com.android.server.backup.testing.BackupManagerServiceTestUtils.startBackupThread;
@@ -27,7 +28,6 @@ import static org.junit.Assert.assertEquals;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.never;
import static org.mockito.Mockito.verify;
-import static org.mockito.Mockito.verifyNoMoreInteractions;
import static org.robolectric.Shadows.shadowOf;
import static org.testng.Assert.expectThrows;
@@ -201,7 +201,7 @@ public class BackupManagerServiceTest {
backupManagerService.stopServiceForUser(mUserOneId);
verify(mUserOneService).tearDownService();
- verifyNoMoreInteractions(mUserTwoService);
+ verify(mUserTwoService, never()).tearDownService();
}
/** Test that the service unregisters users when stopped. */
@@ -1542,6 +1542,7 @@ public class BackupManagerServiceTest {
}
private BackupManagerService createService() {
+ mShadowContext.grantPermissions(BACKUP);
return new BackupManagerService(
mContext, new Trampoline(mContext), startBackupThread(null));
}
diff --git a/services/robotests/backup/src/com/android/server/backup/internal/SetupObserverTest.java b/services/robotests/backup/src/com/android/server/backup/internal/SetupObserverTest.java
index b56b5e6132d5..b754356ca0cb 100644
--- a/services/robotests/backup/src/com/android/server/backup/internal/SetupObserverTest.java
+++ b/services/robotests/backup/src/com/android/server/backup/internal/SetupObserverTest.java
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2018 The Android Open Source Project
+ * Copyright (C) 2019 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
diff --git a/services/startop/Android.bp b/services/startop/Android.bp
new file mode 100644
index 000000000000..093b4ec66ddf
--- /dev/null
+++ b/services/startop/Android.bp
@@ -0,0 +1,24 @@
+/*
+ * 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.
+ */
+
+java_library_static {
+ name: "services.startop",
+
+ static_libs: [
+ // frameworks/base/startop/iorap
+ "services.startop.iorap",
+ ],
+}
diff --git a/services/tests/servicestests/src/com/android/server/display/DisplayManagerServiceTest.java b/services/tests/servicestests/src/com/android/server/display/DisplayManagerServiceTest.java
index abf90402250c..4742a73b17a8 100644
--- a/services/tests/servicestests/src/com/android/server/display/DisplayManagerServiceTest.java
+++ b/services/tests/servicestests/src/com/android/server/display/DisplayManagerServiceTest.java
@@ -389,7 +389,7 @@ public class DisplayManagerServiceTest {
if (attr == null) return; //sampling not supported on device, skip remainder of test.
boolean enabled = displayManager.setDisplayedContentSamplingEnabledInternal(0, true, 0, 0);
- assertTrue(!enabled);
+ assertTrue(enabled);
displayManager.setDisplayedContentSamplingEnabledInternal(0, false, 0, 0);
DisplayedContentSample sample = displayManager.getDisplayedContentSampleInternal(0, 0, 0);
diff --git a/services/tests/servicestests/src/com/android/server/hdmi/FakeNativeWrapper.java b/services/tests/servicestests/src/com/android/server/hdmi/FakeNativeWrapper.java
index 7484edd286f0..4255e37aac2d 100644
--- a/services/tests/servicestests/src/com/android/server/hdmi/FakeNativeWrapper.java
+++ b/services/tests/servicestests/src/com/android/server/hdmi/FakeNativeWrapper.java
@@ -18,8 +18,12 @@ package com.android.server.hdmi;
import android.hardware.hdmi.HdmiPortInfo;
import android.hardware.tv.cec.V1_0.SendMessageResult;
import android.os.MessageQueue;
+
import com.android.internal.annotations.VisibleForTesting;
import com.android.server.hdmi.HdmiCecController.NativeWrapper;
+
+import com.google.common.collect.Iterables;
+
import java.util.ArrayList;
import java.util.List;
@@ -45,7 +49,6 @@ final class FakeNativeWrapper implements NativeWrapper {
};
private final List<HdmiCecMessage> mResultMessages = new ArrayList<>();
- private HdmiCecMessage mResultMessage;
private int mMyPhysicalAddress = 0;
@Override
@@ -112,11 +115,12 @@ final class FakeNativeWrapper implements NativeWrapper {
return new ArrayList<>(mResultMessages);
}
- public HdmiCecMessage getOnlyResultMessage() throws Exception {
- if (mResultMessages.size() != 1) {
- throw new Exception("There is not exactly one message");
- }
- return mResultMessages.get(0);
+ public HdmiCecMessage getOnlyResultMessage() throws IllegalArgumentException {
+ return Iterables.getOnlyElement(mResultMessages);
+ }
+
+ public void clearResultMessages() {
+ mResultMessages.clear();
}
public void setPollAddressResponse(int logicalAddress, int response) {
diff --git a/services/tests/servicestests/src/com/android/server/hdmi/HdmiCecLocalDeviceAudioSystemTest.java b/services/tests/servicestests/src/com/android/server/hdmi/HdmiCecLocalDeviceAudioSystemTest.java
index 9e3a0eaa68f6..5286104633e1 100644
--- a/services/tests/servicestests/src/com/android/server/hdmi/HdmiCecLocalDeviceAudioSystemTest.java
+++ b/services/tests/servicestests/src/com/android/server/hdmi/HdmiCecLocalDeviceAudioSystemTest.java
@@ -20,18 +20,17 @@ 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;
import static com.android.server.hdmi.HdmiControlService.STANDBY_SCREEN_OFF;
-import static com.google.common.truth.Truth.assertThat;
-import static junit.framework.Assert.assertEquals;
-import static junit.framework.Assert.assertFalse;
-import static junit.framework.Assert.assertTrue;
+import static com.google.common.truth.Truth.assertThat;
import android.media.AudioManager;
import android.os.Looper;
import android.os.SystemProperties;
import android.os.test.TestLooper;
+
import androidx.test.InstrumentationRegistry;
import androidx.test.filters.SmallTest;
+
import com.android.server.hdmi.HdmiCecLocalDevice.ActiveSource;
import org.junit.Before;
@@ -115,7 +114,7 @@ public class HdmiCecLocalDeviceAudioSystemTest {
@Override
public void setWiredDeviceConnectionState(
- int type, int state, String address, String name) {
+ int type, int state, String address, String name) {
// Do nothing.
}
};
@@ -123,6 +122,11 @@ public class HdmiCecLocalDeviceAudioSystemTest {
@Override
void wakeUp() {}
+
+ @Override
+ boolean isControlEnabled() {
+ return true;
+ }
};
mMyLooper = mTestLooper.getLooper();
@@ -140,11 +144,12 @@ public class HdmiCecLocalDeviceAudioSystemTest {
// No TV device interacts with AVR so system audio control won't be turned on here
mHdmiControlService.allocateLogicalAddress(mLocalDevices, INITIATED_BY_ENABLE_CEC);
mTestLooper.dispatchAll();
+ mNativeWrapper.clearResultMessages();
SystemProperties.set(Constants.PROPERTY_ARC_SUPPORT, "true");
}
@Test
- public void handleGiveAudioStatus_volume_10_mute_true() {
+ public void handleGiveAudioStatus_volume_10_mute_true() throws Exception {
mMusicVolume = 10;
mMusicMute = true;
mMusicMaxVolume = 20;
@@ -154,14 +159,13 @@ public class HdmiCecLocalDeviceAudioSystemTest {
ADDR_AUDIO_SYSTEM, ADDR_TV, scaledVolume, true);
HdmiCecMessage messageGive =
HdmiCecMessageBuilder.buildGiveAudioStatus(ADDR_TV, ADDR_AUDIO_SYSTEM);
- assertThat(mHdmiCecLocalDeviceAudioSystem.handleGiveAudioStatus(messageGive))
- .isTrue();
+ assertThat(mHdmiCecLocalDeviceAudioSystem.handleGiveAudioStatus(messageGive)).isTrue();
mTestLooper.dispatchAll();
- assertThat(mNativeWrapper.getResultMessages()).contains(expectedMessage);
+ assertThat(mNativeWrapper.getOnlyResultMessage()).isEqualTo(expectedMessage);
}
@Test
- public void handleGiveSystemAudioModeStatus_originalOff() {
+ public void handleGiveSystemAudioModeStatus_originalOff() throws Exception {
HdmiCecMessage expectedMessage =
HdmiCecMessageBuilder.buildReportSystemAudioMode(ADDR_AUDIO_SYSTEM, ADDR_TV, false);
HdmiCecMessage messageGive =
@@ -169,7 +173,7 @@ public class HdmiCecLocalDeviceAudioSystemTest {
assertThat(mHdmiCecLocalDeviceAudioSystem.handleGiveSystemAudioModeStatus(messageGive))
.isTrue();
mTestLooper.dispatchAll();
- assertThat(mNativeWrapper.getResultMessages()).contains(expectedMessage);
+ assertThat(mNativeWrapper.getOnlyResultMessage()).isEqualTo(expectedMessage);
}
@Ignore("b/80297700")
@@ -228,7 +232,7 @@ public class HdmiCecLocalDeviceAudioSystemTest {
}
@Test
- public void handleSetSystemAudioMode_setOn_orignalOff() {
+ public void handleSetSystemAudioMode_setOn_orignalOff() throws Exception {
mMusicMute = true;
HdmiCecMessage messageSet =
HdmiCecMessageBuilder.buildSetSystemAudioMode(ADDR_TV, ADDR_AUDIO_SYSTEM, true);
@@ -240,23 +244,23 @@ public class HdmiCecLocalDeviceAudioSystemTest {
assertThat(mHdmiCecLocalDeviceAudioSystem.handleGiveSystemAudioModeStatus(messageGive))
.isTrue();
mTestLooper.dispatchAll();
- assertThat(mNativeWrapper.getResultMessages()).contains(expectedMessage);
+ assertThat(mNativeWrapper.getOnlyResultMessage()).isEqualTo(expectedMessage);
// Check if correctly turned on
+ mNativeWrapper.clearResultMessages();
expectedMessage =
HdmiCecMessageBuilder.buildReportSystemAudioMode(ADDR_AUDIO_SYSTEM, ADDR_TV, true);
- assertThat(mHdmiCecLocalDeviceAudioSystem.handleSetSystemAudioMode(messageSet))
- .isTrue();
+ assertThat(mHdmiCecLocalDeviceAudioSystem.handleSetSystemAudioMode(messageSet)).isTrue();
mTestLooper.dispatchAll();
assertThat(mHdmiCecLocalDeviceAudioSystem.handleGiveSystemAudioModeStatus(messageGive))
.isTrue();
mTestLooper.dispatchAll();
- assertThat(mNativeWrapper.getResultMessages()).contains(expectedMessage);
+ assertThat(mNativeWrapper.getOnlyResultMessage()).isEqualTo(expectedMessage);
assertThat(mMusicMute).isFalse();
}
@Ignore("b/80297700")
@Test
- public void handleSystemAudioModeRequest_turnOffByTv() {
+ public void handleSystemAudioModeRequest_turnOffByTv() throws Exception {
assertThat(mMusicMute).isFalse();
// Check if feature correctly turned off
HdmiCecMessage messageGive =
@@ -270,19 +274,21 @@ public class HdmiCecLocalDeviceAudioSystemTest {
assertThat(mHdmiCecLocalDeviceAudioSystem.handleSystemAudioModeRequest(messageRequestOff))
.isTrue();
mTestLooper.dispatchAll();
- assertThat(mNativeWrapper.getResultMessages()).contains(expectedMessage);
+ assertThat(mNativeWrapper.getOnlyResultMessage()).isEqualTo(expectedMessage);
+
+ mNativeWrapper.clearResultMessages();
expectedMessage =
HdmiCecMessageBuilder.buildReportSystemAudioMode(ADDR_AUDIO_SYSTEM, ADDR_TV, false);
assertThat(mHdmiCecLocalDeviceAudioSystem.handleGiveSystemAudioModeStatus(messageGive))
.isTrue();
mTestLooper.dispatchAll();
- assertThat(mNativeWrapper.getResultMessages()).contains(expectedMessage);
+ assertThat(mNativeWrapper.getOnlyResultMessage()).isEqualTo(expectedMessage);
assertThat(mMusicMute).isTrue();
}
@Ignore("b/80297700")
@Test
- public void onStandbyAudioSystem_currentSystemAudioControlOn() {
+ public void onStandbyAudioSystem_currentSystemAudioControlOn() throws Exception {
// Set system audio control on first
mHdmiCecLocalDeviceAudioSystem.setSystemAudioMode(true);
// Check if standby correctly turns off the feature
@@ -291,12 +297,12 @@ public class HdmiCecLocalDeviceAudioSystemTest {
HdmiCecMessage expectedMessage =
HdmiCecMessageBuilder.buildSetSystemAudioMode(
ADDR_AUDIO_SYSTEM, ADDR_BROADCAST, false);
- assertThat(mNativeWrapper.getResultMessages()).contains(expectedMessage);
+ assertThat(mNativeWrapper.getOnlyResultMessage()).isEqualTo(expectedMessage);
assertThat(mMusicMute).isTrue();
}
@Test
- public void systemAudioControlOnPowerOn_alwaysOn() {
+ public void systemAudioControlOnPowerOn_alwaysOn() throws Exception {
mHdmiCecLocalDeviceAudioSystem.removeAction(SystemAudioInitiationActionFromAvr.class);
mHdmiCecLocalDeviceAudioSystem.systemAudioControlOnPowerOn(
Constants.ALWAYS_SYSTEM_AUDIO_CONTROL_ON_POWER_ON, true);
@@ -307,7 +313,7 @@ public class HdmiCecLocalDeviceAudioSystemTest {
}
@Test
- public void systemAudioControlOnPowerOn_neverOn() {
+ public void systemAudioControlOnPowerOn_neverOn() throws Exception {
mHdmiCecLocalDeviceAudioSystem.removeAction(SystemAudioInitiationActionFromAvr.class);
mHdmiCecLocalDeviceAudioSystem.systemAudioControlOnPowerOn(
Constants.NEVER_SYSTEM_AUDIO_CONTROL_ON_POWER_ON, false);
@@ -318,7 +324,7 @@ public class HdmiCecLocalDeviceAudioSystemTest {
}
@Test
- public void systemAudioControlOnPowerOn_useLastState_off() {
+ public void systemAudioControlOnPowerOn_useLastState_off() throws Exception {
mHdmiCecLocalDeviceAudioSystem.removeAction(SystemAudioInitiationActionFromAvr.class);
mHdmiCecLocalDeviceAudioSystem.systemAudioControlOnPowerOn(
Constants.USE_LAST_STATE_SYSTEM_AUDIO_CONTROL_ON_POWER_ON, false);
@@ -329,7 +335,7 @@ public class HdmiCecLocalDeviceAudioSystemTest {
}
@Test
- public void systemAudioControlOnPowerOn_useLastState_on() {
+ public void systemAudioControlOnPowerOn_useLastState_on() throws Exception {
mHdmiCecLocalDeviceAudioSystem.removeAction(SystemAudioInitiationActionFromAvr.class);
mHdmiCecLocalDeviceAudioSystem.systemAudioControlOnPowerOn(
Constants.USE_LAST_STATE_SYSTEM_AUDIO_CONTROL_ON_POWER_ON, true);
@@ -340,18 +346,17 @@ public class HdmiCecLocalDeviceAudioSystemTest {
}
@Test
- public void handleActiveSource_updateActiveSource() {
+ public void handleActiveSource_updateActiveSource() throws Exception {
HdmiCecMessage message = HdmiCecMessageBuilder.buildActiveSource(ADDR_TV, 0x0000);
ActiveSource expectedActiveSource = new ActiveSource(ADDR_TV, 0x0000);
- assertThat(mHdmiCecLocalDeviceAudioSystem.handleActiveSource(message))
- .isTrue();
+ assertThat(mHdmiCecLocalDeviceAudioSystem.handleActiveSource(message)).isTrue();
mTestLooper.dispatchAll();
assertThat(mHdmiCecLocalDeviceAudioSystem.getActiveSource().equals(expectedActiveSource))
.isTrue();
}
@Test
- public void terminateSystemAudioMode_systemAudioModeOff() {
+ public void terminateSystemAudioMode_systemAudioModeOff() throws Exception {
mHdmiCecLocalDeviceAudioSystem.setSystemAudioMode(false);
assertThat(mHdmiCecLocalDeviceAudioSystem.isSystemAudioActivated()).isFalse();
mMusicMute = false;
@@ -361,12 +366,12 @@ public class HdmiCecLocalDeviceAudioSystemTest {
mHdmiCecLocalDeviceAudioSystem.terminateSystemAudioMode();
assertThat(mHdmiCecLocalDeviceAudioSystem.isSystemAudioActivated()).isFalse();
assertThat(mMusicMute).isFalse();
- assertThat(mNativeWrapper.getResultMessages()).doesNotContain(message);
+ assertThat(mNativeWrapper.getResultMessages()).isEmpty();
}
@Ignore("b/80297700")
@Test
- public void terminateSystemAudioMode_systemAudioModeOn() {
+ public void terminateSystemAudioMode_systemAudioModeOn() throws Exception {
mHdmiCecLocalDeviceAudioSystem.setSystemAudioMode(true);
assertThat(mHdmiCecLocalDeviceAudioSystem.isSystemAudioActivated()).isTrue();
mMusicMute = false;
@@ -381,124 +386,131 @@ public class HdmiCecLocalDeviceAudioSystemTest {
}
@Test
- public void isPhysicalAddressMeOrBelow_isMe() {
+ public void isPhysicalAddressMeOrBelow_isMe() throws Exception {
int targetPhysicalAddress = 0x1000;
mNativeWrapper.setPhysicalAddress(0x1000);
assertThat(mHdmiCecLocalDeviceAudioSystem.isPhysicalAddressMeOrBelow(targetPhysicalAddress))
- .isTrue();
+ .isTrue();
}
@Test
- public void isPhysicalAddressMeOrBelow_isBelow() {
+ public void isPhysicalAddressMeOrBelow_isBelow() throws Exception {
int targetPhysicalAddress = 0x1100;
mNativeWrapper.setPhysicalAddress(0x1000);
assertThat(mHdmiCecLocalDeviceAudioSystem.isPhysicalAddressMeOrBelow(targetPhysicalAddress))
- .isTrue();
+ .isTrue();
}
@Test
- public void isPhysicalAddressMeOrBelow_neitherMeNorBelow() {
+ public void isPhysicalAddressMeOrBelow_neitherMeNorBelow() throws Exception {
int targetPhysicalAddress = 0x3000;
mNativeWrapper.setPhysicalAddress(0x2000);
assertThat(mHdmiCecLocalDeviceAudioSystem.isPhysicalAddressMeOrBelow(targetPhysicalAddress))
- .isFalse();
+ .isFalse();
targetPhysicalAddress = 0x2200;
mNativeWrapper.setPhysicalAddress(0x3300);
assertThat(mHdmiCecLocalDeviceAudioSystem.isPhysicalAddressMeOrBelow(targetPhysicalAddress))
- .isFalse();
+ .isFalse();
targetPhysicalAddress = 0x2213;
mNativeWrapper.setPhysicalAddress(0x2212);
assertThat(mHdmiCecLocalDeviceAudioSystem.isPhysicalAddressMeOrBelow(targetPhysicalAddress))
- .isFalse();
+ .isFalse();
targetPhysicalAddress = 0x2340;
mNativeWrapper.setPhysicalAddress(0x2310);
assertThat(mHdmiCecLocalDeviceAudioSystem.isPhysicalAddressMeOrBelow(targetPhysicalAddress))
- .isFalse();
+ .isFalse();
}
@Test
- public void handleRequestArcInitiate_isNotDirectConnectedToTv() {
- HdmiCecMessage message = HdmiCecMessageBuilder
- .buildRequestArcInitiation(ADDR_TV, ADDR_AUDIO_SYSTEM);
- HdmiCecMessage expectedMessage = HdmiCecMessageBuilder
- .buildFeatureAbortCommand(
- ADDR_AUDIO_SYSTEM, ADDR_TV,
- Constants.MESSAGE_REQUEST_ARC_INITIATION,
- Constants.ABORT_NOT_IN_CORRECT_MODE);
+ public void handleRequestArcInitiate_isNotDirectConnectedToTv() throws Exception {
+ HdmiCecMessage message =
+ HdmiCecMessageBuilder.buildRequestArcInitiation(ADDR_TV, ADDR_AUDIO_SYSTEM);
+ HdmiCecMessage expectedMessage =
+ HdmiCecMessageBuilder.buildFeatureAbortCommand(
+ ADDR_AUDIO_SYSTEM,
+ ADDR_TV,
+ Constants.MESSAGE_REQUEST_ARC_INITIATION,
+ Constants.ABORT_NOT_IN_CORRECT_MODE);
mNativeWrapper.setPhysicalAddress(0x1100);
- assertThat(mHdmiCecLocalDeviceAudioSystem.handleRequestArcInitiate(message))
- .isTrue();
+ assertThat(mHdmiCecLocalDeviceAudioSystem.handleRequestArcInitiate(message)).isTrue();
mTestLooper.dispatchAll();
assertThat(mNativeWrapper.getResultMessages()).contains(expectedMessage);
}
@Test
- public void handleRequestArcInitiate_startArcInitiationActionFromAvr() {
- HdmiCecMessage message = HdmiCecMessageBuilder
- .buildRequestArcInitiation(ADDR_TV, ADDR_AUDIO_SYSTEM);
+ public void handleRequestArcInitiate_startArcInitiationActionFromAvr() throws Exception {
+ HdmiCecMessage message =
+ HdmiCecMessageBuilder.buildRequestArcInitiation(ADDR_TV, ADDR_AUDIO_SYSTEM);
mNativeWrapper.setPhysicalAddress(0x1000);
- mHdmiCecLocalDeviceAudioSystem.removeAction(
- ArcInitiationActionFromAvr.class);
+ mHdmiCecLocalDeviceAudioSystem.removeAction(ArcInitiationActionFromAvr.class);
- assertThat(mHdmiCecLocalDeviceAudioSystem.handleRequestArcInitiate(message))
- .isTrue();
+ assertThat(mHdmiCecLocalDeviceAudioSystem.handleRequestArcInitiate(message)).isTrue();
mTestLooper.dispatchAll();
- assertThat(mHdmiCecLocalDeviceAudioSystem
- .getActions(ArcInitiationActionFromAvr.class)).isNotEmpty();
+ assertThat(mHdmiCecLocalDeviceAudioSystem.getActions(ArcInitiationActionFromAvr.class))
+ .isNotEmpty();
}
@Test
- public void handleRequestArcTerminate_arcIsOn_startTerminationActionFromAvr() {
+ public void handleRequestArcTerminate_arcIsOn_startTerminationActionFromAvr() throws Exception {
mHdmiCecLocalDeviceAudioSystem.setArcStatus(true);
assertThat(mHdmiCecLocalDeviceAudioSystem.isArcEnabled()).isTrue();
- HdmiCecMessage message = HdmiCecMessageBuilder
- .buildRequestArcTermination(ADDR_TV, ADDR_AUDIO_SYSTEM);
- mHdmiCecLocalDeviceAudioSystem.removeAction(
- ArcTerminationActionFromAvr.class);
+ HdmiCecMessage message =
+ HdmiCecMessageBuilder.buildRequestArcTermination(ADDR_TV, ADDR_AUDIO_SYSTEM);
+ mHdmiCecLocalDeviceAudioSystem.removeAction(ArcTerminationActionFromAvr.class);
- assertThat(mHdmiCecLocalDeviceAudioSystem.handleRequestArcTermination(message))
- .isTrue();
+ assertThat(mHdmiCecLocalDeviceAudioSystem.handleRequestArcTermination(message)).isTrue();
mTestLooper.dispatchAll();
- assertThat(mHdmiCecLocalDeviceAudioSystem
- .getActions(ArcTerminationActionFromAvr.class)).isNotEmpty();
+ assertThat(mHdmiCecLocalDeviceAudioSystem.getActions(ArcTerminationActionFromAvr.class))
+ .isNotEmpty();
}
@Test
- public void handleRequestArcTerminate_arcIsNotOn() {
+ public void handleRequestArcTerminate_arcIsNotOn() throws Exception {
assertThat(mHdmiCecLocalDeviceAudioSystem.isArcEnabled()).isFalse();
- HdmiCecMessage message = HdmiCecMessageBuilder
- .buildRequestArcTermination(ADDR_TV, ADDR_AUDIO_SYSTEM);
- HdmiCecMessage expectedMessage = HdmiCecMessageBuilder
- .buildFeatureAbortCommand(
- ADDR_AUDIO_SYSTEM, ADDR_TV,
- Constants.MESSAGE_REQUEST_ARC_TERMINATION,
- Constants.ABORT_NOT_IN_CORRECT_MODE);
-
- assertThat(mHdmiCecLocalDeviceAudioSystem.handleRequestArcTermination(message))
- .isTrue();
+ HdmiCecMessage message =
+ HdmiCecMessageBuilder.buildRequestArcTermination(ADDR_TV, ADDR_AUDIO_SYSTEM);
+ HdmiCecMessage expectedMessage =
+ HdmiCecMessageBuilder.buildFeatureAbortCommand(
+ ADDR_AUDIO_SYSTEM,
+ ADDR_TV,
+ Constants.MESSAGE_REQUEST_ARC_TERMINATION,
+ Constants.ABORT_NOT_IN_CORRECT_MODE);
+
+ assertThat(mHdmiCecLocalDeviceAudioSystem.handleRequestArcTermination(message)).isTrue();
mTestLooper.dispatchAll();
assertThat(mNativeWrapper.getResultMessages()).contains(expectedMessage);
}
@Test
- public void handleRequestArcInit_arcIsNotSupported() {
- HdmiCecMessage message = HdmiCecMessageBuilder
- .buildRequestArcInitiation(ADDR_TV, ADDR_AUDIO_SYSTEM);
- HdmiCecMessage expectedMessage = HdmiCecMessageBuilder
- .buildFeatureAbortCommand(
- ADDR_AUDIO_SYSTEM, ADDR_TV,
- Constants.MESSAGE_REQUEST_ARC_INITIATION,
- Constants.ABORT_UNRECOGNIZED_OPCODE);
+ public void handleRequestArcInit_arcIsNotSupported() throws Exception {
+ HdmiCecMessage message =
+ HdmiCecMessageBuilder.buildRequestArcInitiation(ADDR_TV, ADDR_AUDIO_SYSTEM);
+ HdmiCecMessage expectedMessage =
+ HdmiCecMessageBuilder.buildFeatureAbortCommand(
+ ADDR_AUDIO_SYSTEM,
+ ADDR_TV,
+ Constants.MESSAGE_REQUEST_ARC_INITIATION,
+ Constants.ABORT_UNRECOGNIZED_OPCODE);
SystemProperties.set(Constants.PROPERTY_ARC_SUPPORT, "false");
- assertThat(mHdmiCecLocalDeviceAudioSystem.handleRequestArcInitiate(message))
- .isTrue();
+ assertThat(mHdmiCecLocalDeviceAudioSystem.handleRequestArcInitiate(message)).isTrue();
mTestLooper.dispatchAll();
- assertThat(mNativeWrapper.getResultMessages()).contains(expectedMessage);
+ assertThat(mNativeWrapper.getOnlyResultMessage()).isEqualTo(expectedMessage);
+ }
+
+ @Test
+ public void onStandby_setAutoDeviceOff_true() throws Exception {
+ HdmiCecMessage expectedMessage =
+ HdmiCecMessageBuilder.buildStandby(ADDR_AUDIO_SYSTEM, ADDR_BROADCAST);
+ mHdmiCecLocalDeviceAudioSystem.setAutoDeviceOff(true);
+ mHdmiCecLocalDeviceAudioSystem.onStandby(false, STANDBY_SCREEN_OFF);
+
+ mTestLooper.dispatchAll();
+ assertThat(mNativeWrapper.getOnlyResultMessage()).isEqualTo(expectedMessage);
}
}
diff --git a/services/tests/servicestests/src/com/android/server/usage/AppTimeLimitControllerTests.java b/services/tests/servicestests/src/com/android/server/usage/AppTimeLimitControllerTests.java
index 8496a961959d..b348aeef802e 100644
--- a/services/tests/servicestests/src/com/android/server/usage/AppTimeLimitControllerTests.java
+++ b/services/tests/servicestests/src/com/android/server/usage/AppTimeLimitControllerTests.java
@@ -699,10 +699,52 @@ public class AppTimeLimitControllerTests {
assertTrue(hasUsageSessionObserver(UID, OBS_ID1));
}
+ /** Verify the timeout message is delivered at the right time after past usage was reported */
+ @Test
+ public void testAppUsageObserver_PastUsage() throws Exception {
+ setTime(10_000L);
+ addAppUsageObserver(OBS_ID1, GROUP1, 6_000L);
+ setTime(20_000L);
+ startPastUsage(PKG_SOC1, 5_000);
+ setTime(21_000L);
+ assertTrue(mLimitReachedLatch.await(2_000L, TimeUnit.MILLISECONDS));
+ stopUsage(PKG_SOC1);
+ // Verify that the observer was removed
+ assertFalse(hasAppUsageObserver(UID, OBS_ID1));
+ }
+
+ /**
+ * Verify the timeout message is delivered at the right time after past usage was reported
+ * that overlaps with already known usage
+ */
+ @Test
+ public void testAppUsageObserver_PastUsageOverlap() throws Exception {
+ setTime(0L);
+ addAppUsageObserver(OBS_ID1, GROUP1, 20_000L);
+ setTime(10_000L);
+ startUsage(PKG_SOC1);
+ setTime(20_000L);
+ stopUsage(PKG_SOC1);
+ setTime(25_000L);
+ startPastUsage(PKG_SOC1, 9_000);
+ setTime(26_000L);
+ // the 4 seconds of overlapped usage should not be counted
+ assertFalse(mLimitReachedLatch.await(2_000L, TimeUnit.MILLISECONDS));
+ setTime(30_000L);
+ assertTrue(mLimitReachedLatch.await(4_000L, TimeUnit.MILLISECONDS));
+ stopUsage(PKG_SOC1);
+ // Verify that the observer was removed
+ assertFalse(hasAppUsageObserver(UID, OBS_ID1));
+ }
+
private void startUsage(String packageName) {
mController.noteUsageStart(packageName, USER_ID);
}
+ private void startPastUsage(String packageName, int timeAgo) {
+ mController.noteUsageStart(packageName, USER_ID, timeAgo);
+ }
+
private void stopUsage(String packageName) {
mController.noteUsageStop(packageName, USER_ID);
}
diff --git a/services/tests/uiservicestests/src/com/android/server/notification/ManagedServicesTest.java b/services/tests/uiservicestests/src/com/android/server/notification/ManagedServicesTest.java
index 8b65e763b088..20f72bfe9938 100644
--- a/services/tests/uiservicestests/src/com/android/server/notification/ManagedServicesTest.java
+++ b/services/tests/uiservicestests/src/com/android/server/notification/ManagedServicesTest.java
@@ -613,7 +613,7 @@ public class ManagedServicesTest extends UiServiceTestCase {
}
@Test
- public void testGetAllowedPackages() throws Exception {
+ public void testGetAllowedPackages_byUser() throws Exception {
for (int approvalLevel : new int[] {APPROVAL_BY_COMPONENT, APPROVAL_BY_PACKAGE}) {
ManagedServices service = new TestManagedServices(getContext(), mLock, mUserProfiles,
mIpm, approvalLevel);
@@ -681,6 +681,30 @@ public class ManagedServicesTest extends UiServiceTestCase {
}
@Test
+ public void testGetAllowedPackages() throws Exception {
+ ManagedServices service = new TestManagedServices(getContext(), mLock, mUserProfiles,
+ mIpm, APPROVAL_BY_COMPONENT);
+ loadXml(service);
+ service.mApprovalLevel = APPROVAL_BY_PACKAGE;
+ loadXml(service);
+
+ List<String> allowedPackages = new ArrayList<>();
+ allowedPackages.add("this.is.a.package.name");
+ allowedPackages.add("another.package");
+ allowedPackages.add("secondary");
+ allowedPackages.add("this.is.another.package");
+ allowedPackages.add("package");
+ allowedPackages.add("component");
+ allowedPackages.add("bananas!");
+
+ Set<String> actual = service.getAllowedPackages();
+ assertEquals(allowedPackages.size(), actual.size());
+ for (String pkg : allowedPackages) {
+ assertTrue(actual.contains(pkg));
+ }
+ }
+
+ @Test
public void testOnUserRemoved() throws Exception {
for (int approvalLevel : new int[] {APPROVAL_BY_COMPONENT, APPROVAL_BY_PACKAGE}) {
ManagedServices service = new TestManagedServices(getContext(), mLock, mUserProfiles,
diff --git a/services/tests/uiservicestests/src/com/android/server/notification/SnoozeHelperTest.java b/services/tests/uiservicestests/src/com/android/server/notification/SnoozeHelperTest.java
index 49f134fdeac0..174c5fa6a51e 100644
--- a/services/tests/uiservicestests/src/com/android/server/notification/SnoozeHelperTest.java
+++ b/services/tests/uiservicestests/src/com/android/server/notification/SnoozeHelperTest.java
@@ -299,6 +299,59 @@ public class SnoozeHelperTest extends UiServiceTestCase {
assertEquals(1, mSnoozeHelper.getSnoozed(UserHandle.USER_SYSTEM, "pkg").size());
}
+ @Test
+ public void testClearData() {
+ // snooze 2 from same package
+ NotificationRecord r = getNotificationRecord("pkg", 1, "one", UserHandle.SYSTEM);
+ NotificationRecord r2 = getNotificationRecord("pkg", 2, "two", UserHandle.SYSTEM);
+ mSnoozeHelper.snooze(r, 1000);
+ mSnoozeHelper.snooze(r2, 1000);
+ assertTrue(mSnoozeHelper.isSnoozed(
+ UserHandle.USER_SYSTEM, r.sbn.getPackageName(), r.getKey()));
+ assertTrue(mSnoozeHelper.isSnoozed(
+ UserHandle.USER_SYSTEM, r2.sbn.getPackageName(), r2.getKey()));
+
+ // clear data
+ mSnoozeHelper.clearData(UserHandle.USER_SYSTEM, "pkg");
+
+ // nothing snoozed; alarms canceled
+ assertFalse(mSnoozeHelper.isSnoozed(
+ UserHandle.USER_SYSTEM, r.sbn.getPackageName(), r.getKey()));
+ assertFalse(mSnoozeHelper.isSnoozed(
+ UserHandle.USER_SYSTEM, r2.sbn.getPackageName(), r2.getKey()));
+ // twice for initial snooze, twice for canceling the snooze
+ verify(mAm, times(4)).cancel(any(PendingIntent.class));
+ }
+
+ @Test
+ public void testClearData_otherRecordsUntouched() {
+ // 2 packages, 2 users
+ NotificationRecord r = getNotificationRecord("pkg", 1, "one", UserHandle.SYSTEM);
+ NotificationRecord r2 = getNotificationRecord("pkg", 2, "two", UserHandle.ALL);
+ NotificationRecord r3 = getNotificationRecord("pkg2", 3, "three", UserHandle.SYSTEM);
+ mSnoozeHelper.snooze(r, 1000);
+ mSnoozeHelper.snooze(r2, 1000);
+ mSnoozeHelper.snooze(r3, 1000);
+ assertTrue(mSnoozeHelper.isSnoozed(
+ UserHandle.USER_SYSTEM, r.sbn.getPackageName(), r.getKey()));
+ assertTrue(mSnoozeHelper.isSnoozed(
+ UserHandle.USER_ALL, r2.sbn.getPackageName(), r2.getKey()));
+ assertTrue(mSnoozeHelper.isSnoozed(
+ UserHandle.USER_SYSTEM, r3.sbn.getPackageName(), r3.getKey()));
+
+ // clear data
+ mSnoozeHelper.clearData(UserHandle.USER_SYSTEM, "pkg");
+
+ assertFalse(mSnoozeHelper.isSnoozed(
+ UserHandle.USER_SYSTEM, r.sbn.getPackageName(), r.getKey()));
+ assertTrue(mSnoozeHelper.isSnoozed(
+ UserHandle.USER_ALL, r2.sbn.getPackageName(), r2.getKey()));
+ assertTrue(mSnoozeHelper.isSnoozed(
+ UserHandle.USER_SYSTEM, r3.sbn.getPackageName(), r3.getKey()));
+ // once for each initial snooze, once for canceling one snooze
+ verify(mAm, times(4)).cancel(any(PendingIntent.class));
+ }
+
private NotificationRecord getNotificationRecord(String pkg, int id, String tag,
UserHandle user, String groupKey, boolean groupSummary) {
Notification n = new Notification.Builder(getContext(), TEST_CHANNEL_ID)
diff --git a/services/tests/wmtests/src/com/android/server/wm/ActivityTestsBase.java b/services/tests/wmtests/src/com/android/server/wm/ActivityTestsBase.java
index 569c6d4af37d..ee336a8c87f2 100644
--- a/services/tests/wmtests/src/com/android/server/wm/ActivityTestsBase.java
+++ b/services/tests/wmtests/src/com/android/server/wm/ActivityTestsBase.java
@@ -31,6 +31,7 @@ import static com.android.dx.mockito.inline.extended.ExtendedMockito.anyBoolean;
import static com.android.dx.mockito.inline.extended.ExtendedMockito.anyInt;
import static com.android.dx.mockito.inline.extended.ExtendedMockito.anyString;
import static com.android.dx.mockito.inline.extended.ExtendedMockito.doAnswer;
+import static com.android.dx.mockito.inline.extended.ExtendedMockito.doCallRealMethod;
import static com.android.dx.mockito.inline.extended.ExtendedMockito.doNothing;
import static com.android.dx.mockito.inline.extended.ExtendedMockito.doReturn;
import static com.android.dx.mockito.inline.extended.ExtendedMockito.mock;
@@ -38,6 +39,9 @@ import static com.android.dx.mockito.inline.extended.ExtendedMockito.spyOn;
import static com.android.server.wm.ActivityStack.REMOVE_TASK_MODE_DESTROYING;
import static com.android.server.wm.ActivityStackSupervisor.ON_TOP;
+import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.Mockito.doCallRealMethod;
+
import android.app.ActivityManagerInternal;
import android.app.ActivityOptions;
import android.app.IApplicationThread;
@@ -115,6 +119,10 @@ class ActivityTestsBase {
@After
public void tearDownBase() {
mTestInjector.tearDown();
+ if (mService != null) {
+ mService.setWindowManager(null);
+ mService = null;
+ }
}
ActivityTaskManagerService createActivityTaskManagerService() {
@@ -144,6 +152,13 @@ class ActivityTestsBase {
return display;
}
+ /** Creates and adds a {@link TestActivityDisplay} to supervisor at the given position. */
+ TestActivityDisplay addNewActivityDisplayAt(DisplayInfo info, int position) {
+ final TestActivityDisplay display = createNewActivityDisplay(info);
+ mRootActivityContainer.addChild(display, position);
+ return display;
+ }
+
/**
* Builder for creating new activities.
*/
@@ -234,6 +249,10 @@ class ActivityTestsBase {
mService.mStackSupervisor, null /* options */, null /* sourceRecord */);
spyOn(activity);
activity.mAppWindowToken = mock(AppWindowToken.class);
+ doCallRealMethod().when(activity.mAppWindowToken).getOrientationIgnoreVisibility();
+ doCallRealMethod().when(activity.mAppWindowToken)
+ .setOrientation(anyInt(), any(), any());
+ doCallRealMethod().when(activity.mAppWindowToken).setOrientation(anyInt());
doNothing().when(activity).removeWindowContainer();
if (mTaskRecord != null) {
@@ -346,6 +365,7 @@ class ActivityTestsBase {
mStack.addTask(task, true, "creating test task");
task.setStack(mStack);
task.setTask();
+ mStack.getWindowContainerController().mContainer.addChild(task.mTask, 0);
}
task.touchActiveTime();
@@ -365,7 +385,10 @@ class ActivityTestsBase {
setTask();
}
- private void setTask() {
+ void setTask() {
+ Task mockTask = mock(Task.class);
+ mockTask.mTaskRecord = this;
+ doCallRealMethod().when(mockTask).onDescendantOrientationChanged(any(), any());
setTask(mock(Task.class));
}
}
@@ -619,7 +642,13 @@ class ActivityTestsBase {
}
}
+ private static WindowManagerService sMockWindowManagerService;
+
private static WindowManagerService prepareMockWindowManager() {
+ if (sMockWindowManagerService != null) {
+ return sMockWindowManagerService;
+ }
+
final WindowManagerService service = mock(WindowManagerService.class);
service.mRoot = mock(RootWindowContainer.class);
@@ -631,6 +660,7 @@ class ActivityTestsBase {
return null;
}).when(service).inSurfaceTransaction(any());
+ sMockWindowManagerService = service;
return service;
}
diff --git a/services/tests/wmtests/src/com/android/server/wm/DisplayRotationTests.java b/services/tests/wmtests/src/com/android/server/wm/DisplayRotationTests.java
index 6b31e6fdbd28..198e7ce63f52 100644
--- a/services/tests/wmtests/src/com/android/server/wm/DisplayRotationTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/DisplayRotationTests.java
@@ -63,6 +63,7 @@ import com.android.server.statusbar.StatusBarManagerInternal;
import org.junit.After;
import org.junit.Before;
+import org.junit.BeforeClass;
import org.junit.Test;
import org.mockito.ArgumentCaptor;
@@ -86,7 +87,7 @@ public class DisplayRotationTests {
private StatusBarManagerInternal mPreviousStatusBarManagerInternal;
- private WindowManagerService mMockWm;
+ private static WindowManagerService sMockWm;
private DisplayContent mMockDisplayContent;
private DisplayPolicy mMockDisplayPolicy;
private Context mMockContext;
@@ -108,13 +109,16 @@ public class DisplayRotationTests {
private DisplayRotation mTarget;
+ @BeforeClass
+ public static void setUpOnce() {
+ sMockWm = mock(WindowManagerService.class);
+ sMockWm.mPowerManagerInternal = mock(PowerManagerInternal.class);
+ }
+
@Before
public void setUp() {
FakeSettingsProvider.clearSettingsProvider();
- mMockWm = mock(WindowManagerService.class);
- mMockWm.mPowerManagerInternal = mock(PowerManagerInternal.class);
-
mPreviousStatusBarManagerInternal = LocalServices.getService(
StatusBarManagerInternal.class);
LocalServices.removeServiceForTest(StatusBarManagerInternal.class);
@@ -452,7 +456,7 @@ public class DisplayRotationTests {
mOrientationSensorListener.onSensorChanged(createSensorEvent(Surface.ROTATION_90));
assertTrue(waitForUiHandler());
- verify(mMockWm).updateRotation(false, false);
+ verify(sMockWm).updateRotation(false, false);
}
@Test
@@ -833,8 +837,9 @@ public class DisplayRotationTests {
.thenReturn(mFakeSettingsProvider.getIContentProvider());
mMockDisplayWindowSettings = mock(DisplayWindowSettings.class);
- mTarget = new DisplayRotation(mMockWm, mMockDisplayContent, mMockDisplayPolicy,
+ mTarget = new DisplayRotation(sMockWm, mMockDisplayContent, mMockDisplayPolicy,
mMockDisplayWindowSettings, mMockContext, new Object());
+ reset(sMockWm);
captureObservers();
}
diff --git a/services/tests/wmtests/src/com/android/server/wm/LockTaskControllerTest.java b/services/tests/wmtests/src/com/android/server/wm/LockTaskControllerTest.java
index a9f150b10e73..e24eb75a2750 100644
--- a/services/tests/wmtests/src/com/android/server/wm/LockTaskControllerTest.java
+++ b/services/tests/wmtests/src/com/android/server/wm/LockTaskControllerTest.java
@@ -34,7 +34,12 @@ import static android.telecom.TelecomManager.EMERGENCY_DIALER_COMPONENT;
import static androidx.test.platform.app.InstrumentationRegistry.getInstrumentation;
+import static com.android.dx.mockito.inline.extended.ExtendedMockito.any;
+import static com.android.dx.mockito.inline.extended.ExtendedMockito.anyInt;
+import static com.android.dx.mockito.inline.extended.ExtendedMockito.anyString;
import static com.android.dx.mockito.inline.extended.ExtendedMockito.doAnswer;
+import static com.android.dx.mockito.inline.extended.ExtendedMockito.eq;
+import static com.android.dx.mockito.inline.extended.ExtendedMockito.isNull;
import static com.android.dx.mockito.inline.extended.ExtendedMockito.mock;
import static com.android.dx.mockito.inline.extended.ExtendedMockito.never;
import static com.android.dx.mockito.inline.extended.ExtendedMockito.reset;
@@ -47,10 +52,6 @@ import static com.android.server.wm.LockTaskController.STATUS_BAR_MASK_PINNED;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertTrue;
-import static org.mockito.ArgumentMatchers.any;
-import static org.mockito.ArgumentMatchers.anyInt;
-import static org.mockito.ArgumentMatchers.anyString;
-import static org.mockito.ArgumentMatchers.eq;
import android.app.StatusBarManager;
import android.app.admin.DevicePolicyManager;
@@ -115,6 +116,7 @@ public class LockTaskControllerTest {
private LockTaskController mLockTaskController;
private Context mContext;
+ private String mPackageName;
private String mLockToAppSetting;
@Before
@@ -122,6 +124,7 @@ public class LockTaskControllerTest {
MockitoAnnotations.initMocks(this);
mContext = getInstrumentation().getTargetContext();
+ mPackageName = mContext.getPackageName();
mLockToAppSetting = Settings.Secure.getString(mContext.getContentResolver(),
Settings.Secure.LOCK_TO_APP_EXIT_LOCKED);
@@ -146,6 +149,7 @@ public class LockTaskControllerTest {
@After
public void tearDown() throws Exception {
+ mLockTaskController.setWindowManager(null);
Settings.Secure.putString(mContext.getContentResolver(),
Settings.Secure.LOCK_TO_APP_EXIT_LOCKED, mLockToAppSetting);
}
@@ -223,7 +227,7 @@ public class LockTaskControllerTest {
// THEN lock task mode should be started
verifyLockTaskStarted(STATUS_BAR_MASK_PINNED, DISABLE2_NONE);
// THEN screen pinning toast should be shown
- verify(mStatusBarService).showPinningEnterExitToast(true /* entering */);
+ verify(mStatusBarService).showPinningEnterExitToast(eq(true /* entering */));
}
@Test
@@ -390,9 +394,9 @@ public class LockTaskControllerTest {
// THEN lock task mode should have been finished
verifyLockTaskStopped(times(1));
// THEN the keyguard should be shown
- verify(mLockPatternUtils).requireCredentialEntry(UserHandle.USER_ALL);
+ verify(mLockPatternUtils).requireCredentialEntry(eq(UserHandle.USER_ALL));
// THEN screen pinning toast should be shown
- verify(mStatusBarService).showPinningEnterExitToast(false /* entering */);
+ verify(mStatusBarService).showPinningEnterExitToast(eq(false /* entering */));
}
@Test
@@ -509,9 +513,9 @@ public class LockTaskControllerTest {
& ~DISABLE_HOME;
int expectedFlags2 = DISABLE2_MASK;
verify(mStatusBarService).disable(eq(expectedFlags), any(IBinder.class),
- eq(mContext.getPackageName()));
+ eq(mPackageName));
verify(mStatusBarService).disable2(eq(expectedFlags2), any(IBinder.class),
- eq(mContext.getPackageName()));
+ eq(mPackageName));
// reset invocation counter
reset(mStatusBarService);
@@ -526,9 +530,9 @@ public class LockTaskControllerTest {
expectedFlags2 = DISABLE2_MASK
& ~DISABLE2_NOTIFICATION_SHADE;
verify(mStatusBarService).disable(eq(expectedFlags), any(IBinder.class),
- eq(mContext.getPackageName()));
+ eq(mPackageName));
verify(mStatusBarService).disable2(eq(expectedFlags2), any(IBinder.class),
- eq(mContext.getPackageName()));
+ eq(mPackageName));
}
@Test
@@ -548,9 +552,9 @@ public class LockTaskControllerTest {
// THEN status bar shouldn't change
verify(mStatusBarService, never()).disable(anyInt(), any(IBinder.class),
- eq(mContext.getPackageName()));
+ eq(mPackageName));
verify(mStatusBarService, never()).disable2(anyInt(), any(IBinder.class),
- eq(mContext.getPackageName()));
+ eq(mPackageName));
}
@Test
@@ -657,14 +661,14 @@ public class LockTaskControllerTest {
verify(mWindowManager).disableKeyguard(any(IBinder.class), anyString(), eq(TEST_USER_ID));
// THEN the status bar should have been disabled
verify(mStatusBarService).disable(eq(statusBarMask), any(IBinder.class),
- eq(mContext.getPackageName()));
+ eq(mPackageName));
verify(mStatusBarService).disable2(eq(statusBarMask2), any(IBinder.class),
- eq(mContext.getPackageName()));
+ eq(mPackageName));
// THEN recents should have been notified
verify(mRecentTasks).onLockTaskModeStateChanged(anyInt(), eq(TEST_USER_ID));
// THEN the DO/PO should be informed about the operation
- verify(mDevicePolicyManager).notifyLockTaskModeChanged(true, TEST_PACKAGE_NAME,
- TEST_USER_ID);
+ verify(mDevicePolicyManager).notifyLockTaskModeChanged(eq(true), eq(TEST_PACKAGE_NAME),
+ eq(TEST_USER_ID));
}
private void verifyLockTaskStopped(VerificationMode mode) throws Exception {
@@ -672,11 +676,12 @@ public class LockTaskControllerTest {
verify(mWindowManager, mode).reenableKeyguard(any(IBinder.class), eq(TEST_USER_ID));
// THEN the status bar should have been disabled
verify(mStatusBarService, mode).disable(eq(StatusBarManager.DISABLE_NONE),
- any(IBinder.class), eq(mContext.getPackageName()));
+ any(IBinder.class), eq(mPackageName));
verify(mStatusBarService, mode).disable2(eq(StatusBarManager.DISABLE2_NONE),
- any(IBinder.class), eq(mContext.getPackageName()));
+ any(IBinder.class), eq(mPackageName));
// THEN the DO/PO should be informed about the operation
- verify(mDevicePolicyManager, mode).notifyLockTaskModeChanged(false, null, TEST_USER_ID);
+ verify(mDevicePolicyManager, mode).notifyLockTaskModeChanged(eq(false), isNull(),
+ eq(TEST_USER_ID));
}
/**
diff --git a/services/tests/wmtests/src/com/android/server/wm/RemoteAnimationControllerTest.java b/services/tests/wmtests/src/com/android/server/wm/RemoteAnimationControllerTest.java
index ad2a708b88d9..413b6f4b3905 100644
--- a/services/tests/wmtests/src/com/android/server/wm/RemoteAnimationControllerTest.java
+++ b/services/tests/wmtests/src/com/android/server/wm/RemoteAnimationControllerTest.java
@@ -143,8 +143,8 @@ public class RemoteAnimationControllerTest extends WindowTestsBase {
@Test
public void testTimeout_scaled() throws Exception {
- mWm.setAnimationScale(2, 5.0f);
try {
+ mWm.setAnimationScale(2, 5.0f);
final WindowState win = createWindow(null /* parent */, TYPE_BASE_APPLICATION,
"testWin");
final AnimationAdapter adapter = mController.createAnimationAdapter(win.mAppToken,
diff --git a/services/tests/wmtests/src/com/android/server/wm/ScreenDecorWindowTests.java b/services/tests/wmtests/src/com/android/server/wm/ScreenDecorWindowTests.java
index 36eccd1892a7..03aba39517eb 100644
--- a/services/tests/wmtests/src/com/android/server/wm/ScreenDecorWindowTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/ScreenDecorWindowTests.java
@@ -33,6 +33,8 @@ import static android.view.WindowManager.LayoutParams.FLAG_WATCH_OUTSIDE_TOUCH;
import static android.view.WindowManager.LayoutParams.PRIVATE_FLAG_IS_SCREEN_DECOR;
import static android.view.WindowManager.LayoutParams.TYPE_APPLICATION_OVERLAY;
+import static androidx.test.platform.app.InstrumentationRegistry.getInstrumentation;
+
import static com.google.common.truth.Truth.assertThat;
import static org.junit.Assert.assertEquals;
@@ -58,7 +60,6 @@ import android.view.WindowInsets;
import android.view.WindowManager;
import android.widget.TextView;
-import androidx.test.InstrumentationRegistry;
import androidx.test.filters.SmallTest;
import org.junit.After;
@@ -80,8 +81,8 @@ import java.util.function.BooleanSupplier;
@Presubmit
public class ScreenDecorWindowTests {
- private final Context mContext = InstrumentationRegistry.getTargetContext();
- private final Instrumentation mInstrumentation = InstrumentationRegistry.getInstrumentation();
+ private final Context mContext = getInstrumentation().getTargetContext();
+ private final Instrumentation mInstrumentation = getInstrumentation();
private WindowManager mWm;
private ArrayList<View> mWindows = new ArrayList<>();
diff --git a/services/tests/wmtests/src/com/android/server/wm/TaskRecordTests.java b/services/tests/wmtests/src/com/android/server/wm/TaskRecordTests.java
index 7da85af444d6..00bec3fa4936 100644
--- a/services/tests/wmtests/src/com/android/server/wm/TaskRecordTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/TaskRecordTests.java
@@ -21,6 +21,11 @@ import static android.app.WindowConfiguration.WINDOWING_MODE_FREEFORM;
import static android.app.WindowConfiguration.WINDOWING_MODE_FULLSCREEN;
import static android.content.Intent.FLAG_ACTIVITY_NEW_TASK;
import static android.content.Intent.FLAG_ACTIVITY_TASK_ON_HOME;
+import static android.content.pm.ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE;
+import static android.content.pm.ActivityInfo.SCREEN_ORIENTATION_PORTRAIT;
+import static android.content.pm.ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED;
+
+import static com.android.server.wm.WindowContainer.POSITION_TOP;
import static org.hamcrest.Matchers.not;
import static org.hamcrest.Matchers.sameInstance;
@@ -133,17 +138,6 @@ public class TaskRecordTests extends ActivityTestsBase {
assertTrue(task.returnsToHomeStack());
}
- /** Ensures that bounds are clipped to their parent. */
- @Test
- public void testAppBounds_BoundsClipping() {
- final Rect shiftedBounds = new Rect(mParentBounds);
- shiftedBounds.offset(10, 10);
- final Rect expectedBounds = new Rect(mParentBounds);
- expectedBounds.intersect(shiftedBounds);
- testStackBoundsConfiguration(WINDOWING_MODE_FULLSCREEN, mParentBounds, shiftedBounds,
- expectedBounds);
- }
-
/** Ensures that empty bounds are not propagated to the configuration. */
@Test
public void testAppBounds_EmptyBounds() {
@@ -167,18 +161,108 @@ public class TaskRecordTests extends ActivityTestsBase {
final Rect insetBounds = new Rect(mParentBounds);
insetBounds.inset(5, 5, 5, 5);
testStackBoundsConfiguration(
- WINDOWING_MODE_FULLSCREEN, mParentBounds, insetBounds, insetBounds);
+ WINDOWING_MODE_FREEFORM, mParentBounds, insetBounds, insetBounds);
}
- /** Ensures that full screen free form bounds are clipped */
+ /** Tests that the task bounds adjust properly to changes between FULLSCREEN and FREEFORM */
@Test
- public void testAppBounds_FullScreenFreeFormBounds() {
+ public void testBoundsOnModeChangeFreeformToFullscreen() {
ActivityDisplay display = mService.mRootActivityContainer.getDefaultDisplay();
+ ActivityStack stack = new StackBuilder(mRootActivityContainer).setDisplay(display)
+ .setWindowingMode(WINDOWING_MODE_FREEFORM).build();
+ TaskRecord task = stack.getChildAt(0);
+ task.getRootActivity().mAppWindowToken.setOrientation(SCREEN_ORIENTATION_UNSPECIFIED);
DisplayInfo info = new DisplayInfo();
display.mDisplay.getDisplayInfo(info);
final Rect fullScreenBounds = new Rect(0, 0, info.logicalWidth, info.logicalHeight);
- testStackBoundsConfiguration(WINDOWING_MODE_FULLSCREEN, mParentBounds, fullScreenBounds,
- mParentBounds);
+ final Rect freeformBounds = new Rect(fullScreenBounds);
+ freeformBounds.inset((int) (freeformBounds.width() * 0.2),
+ (int) (freeformBounds.height() * 0.2));
+ task.setBounds(freeformBounds);
+
+ assertEquals(freeformBounds, task.getBounds());
+
+ // FULLSCREEN inherits bounds
+ stack.setWindowingMode(WINDOWING_MODE_FULLSCREEN);
+ assertEquals(fullScreenBounds, task.getBounds());
+ assertEquals(freeformBounds, task.mLastNonFullscreenBounds);
+
+ // FREEFORM restores bounds
+ stack.setWindowingMode(WINDOWING_MODE_FREEFORM);
+ assertEquals(freeformBounds, task.getBounds());
+ }
+
+ /**
+ * This is a temporary hack to trigger an onConfigurationChange at the task level after an
+ * orientation is requested. Normally this is done by the onDescendentOrientationChanged call
+ * up the WM hierarchy, but since the WM hierarchy is mocked out, it doesn't happen here.
+ * TODO: remove this when we either get a WM hierarchy or when hierarchies are merged.
+ */
+ private void setActivityRequestedOrientation(ActivityRecord activity, int orientation) {
+ activity.setRequestedOrientation(orientation);
+ ConfigurationContainer taskRecord = activity.getParent();
+ taskRecord.onConfigurationChanged(taskRecord.getParent().getConfiguration());
+ }
+
+ /**
+ * Tests that a task with forced orientation has orientation-consistent bounds within the
+ * parent.
+ */
+ @Test
+ public void testFullscreenBoundsForcedOrientation() {
+ final Rect fullScreenBounds = new Rect(0, 0, 1920, 1080);
+ final Rect fullScreenBoundsPort = new Rect(0, 0, 1080, 1920);
+ DisplayInfo info = new DisplayInfo();
+ info.logicalWidth = fullScreenBounds.width();
+ info.logicalHeight = fullScreenBounds.height();
+ ActivityDisplay display = addNewActivityDisplayAt(info, POSITION_TOP);
+ assertTrue(mRootActivityContainer.getActivityDisplay(display.mDisplayId) != null);
+ ActivityStack stack = new StackBuilder(mRootActivityContainer)
+ .setWindowingMode(WINDOWING_MODE_FULLSCREEN).setDisplay(display).build();
+ TaskRecord task = stack.getChildAt(0);
+ ActivityRecord root = task.getRootActivity();
+ ActivityRecord top = new ActivityBuilder(mService).setTask(task).setStack(stack).build();
+ assertEquals(root, task.getRootActivity());
+
+ assertEquals(fullScreenBounds, task.getBounds());
+
+ // Setting app to fixed portrait fits within parent
+ setActivityRequestedOrientation(root, SCREEN_ORIENTATION_PORTRAIT);
+ assertEquals(root, task.getRootActivity());
+ assertEquals(SCREEN_ORIENTATION_PORTRAIT, task.getRootActivity().getOrientation());
+ assertTrue(task.getBounds().width() < task.getBounds().height());
+ assertEquals(fullScreenBounds.height(), task.getBounds().height());
+
+ // Setting non-root app has no effect
+ setActivityRequestedOrientation(root, SCREEN_ORIENTATION_LANDSCAPE);
+ assertTrue(task.getBounds().width() < task.getBounds().height());
+
+ // Setting app to unspecified restores
+ setActivityRequestedOrientation(root, SCREEN_ORIENTATION_UNSPECIFIED);
+ assertEquals(fullScreenBounds, task.getBounds());
+
+ // Setting app to fixed landscape and changing display
+ setActivityRequestedOrientation(root, SCREEN_ORIENTATION_LANDSCAPE);
+ display.setBounds(fullScreenBoundsPort);
+ assertTrue(task.getBounds().width() > task.getBounds().height());
+ assertEquals(fullScreenBoundsPort.width(), task.getBounds().width());
+
+ // in FREEFORM, no constraint
+ final Rect freeformBounds = new Rect(display.getBounds());
+ freeformBounds.inset((int) (freeformBounds.width() * 0.2),
+ (int) (freeformBounds.height() * 0.2));
+ stack.setWindowingMode(WINDOWING_MODE_FREEFORM);
+ task.setBounds(freeformBounds);
+ assertEquals(freeformBounds, task.getBounds());
+
+ // FULLSCREEN letterboxes bounds
+ stack.setWindowingMode(WINDOWING_MODE_FULLSCREEN);
+ assertTrue(task.getBounds().width() > task.getBounds().height());
+ assertEquals(fullScreenBoundsPort.width(), task.getBounds().width());
+
+ // FREEFORM restores bounds as before
+ stack.setWindowingMode(WINDOWING_MODE_FREEFORM);
+ assertEquals(freeformBounds, task.getBounds());
}
/** Ensures that the alias intent won't have target component resolved. */
diff --git a/services/tests/wmtests/src/com/android/server/wm/TaskSnapshotSurfaceTest.java b/services/tests/wmtests/src/com/android/server/wm/TaskSnapshotSurfaceTest.java
index 624ef9ba1653..ca815eca9a1f 100644
--- a/services/tests/wmtests/src/com/android/server/wm/TaskSnapshotSurfaceTest.java
+++ b/services/tests/wmtests/src/com/android/server/wm/TaskSnapshotSurfaceTest.java
@@ -39,6 +39,7 @@ import android.graphics.PixelFormat;
import android.graphics.Rect;
import android.platform.test.annotations.Presubmit;
import android.view.Surface;
+import android.view.SurfaceControl;
import androidx.test.filters.SmallTest;
@@ -65,7 +66,7 @@ public class TaskSnapshotSurfaceTest extends WindowTestsBase {
final TaskSnapshot snapshot = new TaskSnapshot(new ComponentName("", ""), buffer,
ORIENTATION_PORTRAIT, contentInsets, false, 1.0f, true /* isRealSnapshot */,
WINDOWING_MODE_FULLSCREEN, 0 /* systemUiVisibility */, false /* isTranslucent */);
- mSurface = new TaskSnapshotSurface(mWm, new Window(), new Surface(), snapshot, "Test",
+ mSurface = new TaskSnapshotSurface(mWm, new Window(), new SurfaceControl(), snapshot, "Test",
Color.WHITE, Color.RED, Color.BLUE, sysuiVis, windowFlags, 0, taskBounds,
ORIENTATION_PORTRAIT);
}
diff --git a/services/tests/wmtests/src/com/android/server/wm/WindowManagerServiceRule.java b/services/tests/wmtests/src/com/android/server/wm/WindowManagerServiceRule.java
deleted file mode 100644
index 04e433e98678..000000000000
--- a/services/tests/wmtests/src/com/android/server/wm/WindowManagerServiceRule.java
+++ /dev/null
@@ -1,223 +0,0 @@
-/*
- * 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.server.wm;
-
-import static android.testing.DexmakerShareClassLoaderRule.runWithDexmakerShareClassLoader;
-import static android.view.Display.DEFAULT_DISPLAY;
-
-import static androidx.test.platform.app.InstrumentationRegistry.getInstrumentation;
-
-import static com.android.dx.mockito.inline.extended.ExtendedMockito.doAnswer;
-import static com.android.dx.mockito.inline.extended.ExtendedMockito.doNothing;
-import static com.android.dx.mockito.inline.extended.ExtendedMockito.doReturn;
-import static com.android.dx.mockito.inline.extended.ExtendedMockito.mock;
-import static com.android.server.wm.WindowManagerDebugConfig.TAG_WM;
-
-import static org.mockito.ArgumentMatchers.any;
-import static org.mockito.ArgumentMatchers.anyInt;
-import static org.mockito.ArgumentMatchers.anyString;
-import static org.mockito.Mockito.when;
-
-import android.app.ActivityManagerInternal;
-import android.content.Context;
-import android.hardware.display.DisplayManagerInternal;
-import android.os.PowerManagerInternal;
-import android.os.PowerSaveState;
-import android.view.Display;
-import android.view.InputChannel;
-import android.view.SurfaceControl;
-import android.view.SurfaceControl.Transaction;
-
-import com.android.server.LocalServices;
-import com.android.server.input.InputManagerService;
-import com.android.server.policy.WindowManagerPolicy;
-
-import org.junit.rules.TestRule;
-import org.junit.runner.Description;
-import org.junit.runners.model.Statement;
-import org.mockito.invocation.InvocationOnMock;
-
-import java.lang.ref.WeakReference;
-import java.util.ArrayList;
-import java.util.List;
-
-/**
- * A test rule that sets up a fresh WindowManagerService instance before each test and makes sure
- * to properly tear it down after.
- *
- * <p>
- * Usage:
- * <pre>
- * {@literal @}Rule
- * public final WindowManagerServiceRule mWmRule = new WindowManagerServiceRule();
- * </pre>
- */
-public class WindowManagerServiceRule implements TestRule {
-
- private WindowManagerService mService;
- private TestWindowManagerPolicy mPolicy;
- // Record all {@link SurfaceControl.Transaction} created while testing and releases native
- // resources when test finishes.
- private final List<WeakReference<Transaction>> mSurfaceTransactions = new ArrayList<>();
- // Record all {@link SurfaceControl} created while testing and releases native resources when
- // test finishes.
- private final List<WeakReference<SurfaceControl>> mSurfaceControls = new ArrayList<>();
-
- @Override
- public Statement apply(Statement base, Description description) {
- return new Statement() {
- @Override
- public void evaluate() throws Throwable {
- runWithDexmakerShareClassLoader(this::setUp);
- try {
- base.evaluate();
- } finally {
- tearDown();
- }
- }
-
- private void setUp() {
- final Context context = getInstrumentation().getTargetContext();
-
- removeServices();
-
- LocalServices.addService(DisplayManagerInternal.class,
- mock(DisplayManagerInternal.class));
-
- LocalServices.addService(PowerManagerInternal.class,
- mock(PowerManagerInternal.class));
- final PowerManagerInternal pm =
- LocalServices.getService(PowerManagerInternal.class);
- doNothing().when(pm).registerLowPowerModeObserver(any());
- PowerSaveState state = new PowerSaveState.Builder().build();
- doReturn(state).when(pm).getLowPowerState(anyInt());
-
- LocalServices.addService(ActivityManagerInternal.class,
- mock(ActivityManagerInternal.class));
- LocalServices.addService(ActivityTaskManagerInternal.class,
- mock(ActivityTaskManagerInternal.class));
- final ActivityTaskManagerInternal atm =
- LocalServices.getService(ActivityTaskManagerInternal.class);
- doAnswer((InvocationOnMock invocationOnMock) -> {
- final Runnable runnable = invocationOnMock.<Runnable>getArgument(0);
- if (runnable != null) {
- runnable.run();
- }
- return null;
- }).when(atm).notifyKeyguardFlagsChanged(any(), anyInt());
-
- InputManagerService ims = mock(InputManagerService.class);
- // InputChannel is final and can't be mocked.
- InputChannel[] input = InputChannel.openInputChannelPair(TAG_WM);
- if (input != null && input.length > 1) {
- doReturn(input[1]).when(ims).monitorInput(anyString(), anyInt());
- }
- ActivityTaskManagerService atms = mock(ActivityTaskManagerService.class);
- when(atms.getGlobalLock()).thenReturn(new WindowManagerGlobalLock());
-
- mService = WindowManagerService.main(context, ims, false, false,
- mPolicy = new TestWindowManagerPolicy(
- WindowManagerServiceRule.this::getWindowManagerService), atms);
- mService.mTransactionFactory = () -> {
- final SurfaceControl.Transaction transaction = new SurfaceControl.Transaction();
- mSurfaceTransactions.add(new WeakReference<>(transaction));
- return transaction;
- };
- mService.mSurfaceBuilderFactory = session -> new SurfaceControl.Builder(session) {
- @Override
- public SurfaceControl build() {
- final SurfaceControl control = super.build();
- mSurfaceControls.add(new WeakReference<>(control));
- return control;
- }
- };
-
- mService.onInitReady();
-
- final Display display = mService.mDisplayManager.getDisplay(DEFAULT_DISPLAY);
- // Display creation is driven by the ActivityManagerService via
- // ActivityStackSupervisor. We emulate those steps here.
- mService.mRoot.createDisplayContent(display, mock(ActivityDisplay.class));
- }
-
- private void removeServices() {
- LocalServices.removeServiceForTest(DisplayManagerInternal.class);
- LocalServices.removeServiceForTest(PowerManagerInternal.class);
- LocalServices.removeServiceForTest(ActivityManagerInternal.class);
- LocalServices.removeServiceForTest(ActivityTaskManagerInternal.class);
- LocalServices.removeServiceForTest(WindowManagerInternal.class);
- LocalServices.removeServiceForTest(WindowManagerPolicy.class);
- }
-
- private void tearDown() {
- cancelAllPendingAnimations();
- waitUntilWindowManagerHandlersIdle();
- destroyAllSurfaceTransactions();
- destroyAllSurfaceControls();
- removeServices();
- mService = null;
- mPolicy = null;
- }
- };
- }
-
- WindowManagerService getWindowManagerService() {
- return mService;
- }
-
- private void cancelAllPendingAnimations() {
- for (final WeakReference<SurfaceControl> reference : mSurfaceControls) {
- final SurfaceControl sc = reference.get();
- if (sc != null) {
- mService.mSurfaceAnimationRunner.onAnimationCancelled(sc);
- }
- }
- }
-
- void waitUntilWindowManagerHandlersIdle() {
- final WindowManagerService wm = getWindowManagerService();
- if (wm == null) {
- return;
- }
- wm.mH.removeCallbacksAndMessages(null);
- wm.mAnimationHandler.removeCallbacksAndMessages(null);
- SurfaceAnimationThread.getHandler().removeCallbacksAndMessages(null);
- wm.mH.runWithScissors(() -> { }, 0);
- wm.mAnimationHandler.runWithScissors(() -> { }, 0);
- SurfaceAnimationThread.getHandler().runWithScissors(() -> { }, 0);
- }
-
- private void destroyAllSurfaceTransactions() {
- for (final WeakReference<Transaction> reference : mSurfaceTransactions) {
- final Transaction transaction = reference.get();
- if (transaction != null) {
- reference.clear();
- transaction.close();
- }
- }
- }
-
- private void destroyAllSurfaceControls() {
- for (final WeakReference<SurfaceControl> reference : mSurfaceControls) {
- final SurfaceControl control = reference.get();
- if (control != null) {
- reference.clear();
- control.destroy();
- }
- }
- }
-}
diff --git a/services/tests/wmtests/src/com/android/server/wm/WindowManagerServiceRuleTest.java b/services/tests/wmtests/src/com/android/server/wm/WindowManagerServiceRuleTest.java
deleted file mode 100644
index 343d35959df4..000000000000
--- a/services/tests/wmtests/src/com/android/server/wm/WindowManagerServiceRuleTest.java
+++ /dev/null
@@ -1,44 +0,0 @@
-/*
- * 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.server.wm;
-
-import static org.hamcrest.CoreMatchers.notNullValue;
-import static org.junit.Assert.assertThat;
-
-import android.platform.test.annotations.Presubmit;
-
-import androidx.test.filters.SmallTest;
-
-import org.junit.Rule;
-import org.junit.Test;
-
-/**
- * Build/InstallRun:
- * atest FrameworksServicesTests:WindowManagerServiceRuleTest
- */
-@Presubmit
-@SmallTest
-public class WindowManagerServiceRuleTest {
-
- @Rule
- public final WindowManagerServiceRule mRule = new WindowManagerServiceRule();
-
- @Test
- public void testWindowManagerSetUp() {
- assertThat(mRule.getWindowManagerService(), notNullValue());
- }
-}
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 5c3368bd25ac..3813891ef0e0 100644
--- a/services/tests/wmtests/src/com/android/server/wm/WindowTestsBase.java
+++ b/services/tests/wmtests/src/com/android/server/wm/WindowTestsBase.java
@@ -53,6 +53,7 @@ import android.view.WindowManager;
import com.android.server.AttributeCache;
import org.junit.After;
+import org.junit.AfterClass;
import org.junit.Before;
import org.junit.BeforeClass;
import org.junit.Rule;
@@ -95,17 +96,22 @@ class WindowTestsBase {
public final DexmakerShareClassLoaderRule mDexmakerShareClassLoaderRule =
new DexmakerShareClassLoaderRule();
- @Rule
- public final WindowManagerServiceRule mWmRule = new WindowManagerServiceRule();
-
- static WindowState.PowerManagerWrapper sPowerManagerWrapper; // TODO(roosa): make non-static.
+ static WindowState.PowerManagerWrapper sPowerManagerWrapper;
@BeforeClass
public static void setUpOnceBase() {
AttributeCache.init(getInstrumentation().getTargetContext());
+
+ WmServiceUtils.setUpWindowManagerService();
+
sPowerManagerWrapper = mock(WindowState.PowerManagerWrapper.class);
}
+ @AfterClass
+ public static void tearDonwOnceBase() {
+ WmServiceUtils.tearDownWindowManagerService();
+ }
+
@Before
public void setUpBase() {
// If @Before throws an exception, the error isn't logged. This will make sure any failures
@@ -115,7 +121,7 @@ class WindowTestsBase {
final Context context = getInstrumentation().getTargetContext();
- mWm = mWmRule.getWindowManagerService();
+ mWm = WmServiceUtils.getWindowManagerService();
beforeCreateDisplay();
context.getDisplay().getDisplayInfo(mDisplayInfo);
@@ -214,7 +220,7 @@ class WindowTestsBase {
* Waits until the main handler for WM has processed all messages.
*/
void waitUntilHandlersIdle() {
- mWmRule.waitUntilWindowManagerHandlersIdle();
+ WmServiceUtils.waitUntilWindowManagerHandlersIdle();
}
private WindowToken createWindowToken(
diff --git a/services/tests/wmtests/src/com/android/server/wm/WmServiceUtils.java b/services/tests/wmtests/src/com/android/server/wm/WmServiceUtils.java
new file mode 100644
index 000000000000..2465e5d89bb1
--- /dev/null
+++ b/services/tests/wmtests/src/com/android/server/wm/WmServiceUtils.java
@@ -0,0 +1,204 @@
+/*
+ * 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.server.wm;
+
+import static android.testing.DexmakerShareClassLoaderRule.runWithDexmakerShareClassLoader;
+import static android.view.Display.DEFAULT_DISPLAY;
+
+import static androidx.test.platform.app.InstrumentationRegistry.getInstrumentation;
+
+import static com.android.dx.mockito.inline.extended.ExtendedMockito.any;
+import static com.android.dx.mockito.inline.extended.ExtendedMockito.anyBoolean;
+import static com.android.dx.mockito.inline.extended.ExtendedMockito.anyInt;
+import static com.android.dx.mockito.inline.extended.ExtendedMockito.anyString;
+import static com.android.dx.mockito.inline.extended.ExtendedMockito.doAnswer;
+import static com.android.dx.mockito.inline.extended.ExtendedMockito.doNothing;
+import static com.android.dx.mockito.inline.extended.ExtendedMockito.doReturn;
+import static com.android.dx.mockito.inline.extended.ExtendedMockito.eq;
+import static com.android.dx.mockito.inline.extended.ExtendedMockito.mock;
+import static com.android.dx.mockito.inline.extended.ExtendedMockito.mockitoSession;
+import static com.android.dx.mockito.inline.extended.ExtendedMockito.nullable;
+import static com.android.dx.mockito.inline.extended.ExtendedMockito.spyOn;
+import static com.android.server.wm.WindowManagerDebugConfig.TAG_WM;
+
+import android.app.ActivityManagerInternal;
+import android.app.AppOpsManager;
+import android.content.BroadcastReceiver;
+import android.content.ContentResolver;
+import android.content.Context;
+import android.content.IntentFilter;
+import android.database.ContentObserver;
+import android.hardware.display.DisplayManagerInternal;
+import android.net.Uri;
+import android.os.Handler;
+import android.os.PowerManagerInternal;
+import android.os.PowerSaveState;
+import android.os.UserHandle;
+import android.view.Display;
+import android.view.InputChannel;
+
+import com.android.dx.mockito.inline.extended.StaticMockitoSession;
+import com.android.server.LocalServices;
+import com.android.server.LockGuard;
+import com.android.server.Watchdog;
+import com.android.server.input.InputManagerService;
+import com.android.server.policy.WindowManagerPolicy;
+
+import org.mockito.invocation.InvocationOnMock;
+import org.mockito.quality.Strictness;
+
+import java.util.concurrent.CountDownLatch;
+
+/**
+ * A Test utility class to create a mock {@link WindowManagerService} instance for tests.
+ */
+class WmServiceUtils {
+ private static StaticMockitoSession sMockitoSession;
+ private static WindowManagerService sService;
+ private static TestWindowManagerPolicy sPolicy;
+
+ static void setUpWindowManagerService() {
+ sMockitoSession = mockitoSession()
+ .spyStatic(LockGuard.class)
+ .spyStatic(Watchdog.class)
+ .strictness(Strictness.LENIENT)
+ .startMocking();
+
+ runWithDexmakerShareClassLoader(WmServiceUtils::setUpTestWindowService);
+ }
+
+ static void tearDownWindowManagerService() {
+ waitUntilWindowManagerHandlersIdle();
+ removeLocalServices();
+ sService = null;
+ sPolicy = null;
+
+ sMockitoSession.finishMocking();
+ }
+
+ private static void setUpTestWindowService() {
+ doReturn(null).when(() -> LockGuard.installLock(any(), anyInt()));
+ doReturn(mock(Watchdog.class)).when(Watchdog::getInstance);
+
+ final Context context = getInstrumentation().getTargetContext();
+ spyOn(context);
+
+ doReturn(null).when(context)
+ .registerReceiver(nullable(BroadcastReceiver.class), any(IntentFilter.class));
+ doReturn(null).when(context)
+ .registerReceiverAsUser(any(BroadcastReceiver.class), any(UserHandle.class),
+ any(IntentFilter.class), nullable(String.class), nullable(Handler.class));
+
+ final ContentResolver contentResolver = context.getContentResolver();
+ spyOn(contentResolver);
+ doNothing().when(contentResolver)
+ .registerContentObserver(any(Uri.class), anyBoolean(), any(ContentObserver.class),
+ anyInt());
+
+ final AppOpsManager appOpsManager = mock(AppOpsManager.class);
+ doReturn(appOpsManager).when(context)
+ .getSystemService(eq(Context.APP_OPS_SERVICE));
+
+ removeLocalServices();
+
+ final DisplayManagerInternal dmi = mock(DisplayManagerInternal.class);
+ LocalServices.addService(DisplayManagerInternal.class, dmi);
+
+ final PowerManagerInternal pmi = mock(PowerManagerInternal.class);
+ LocalServices.addService(PowerManagerInternal.class, pmi);
+ final PowerSaveState state = new PowerSaveState.Builder().build();
+ doReturn(state).when(pmi).getLowPowerState(anyInt());
+
+ final ActivityManagerInternal ami = mock(ActivityManagerInternal.class);
+ LocalServices.addService(ActivityManagerInternal.class, ami);
+
+ final ActivityTaskManagerInternal atmi = mock(ActivityTaskManagerInternal.class);
+ LocalServices.addService(ActivityTaskManagerInternal.class, atmi);
+ doAnswer((InvocationOnMock invocationOnMock) -> {
+ final Runnable runnable = invocationOnMock.getArgument(0);
+ if (runnable != null) {
+ runnable.run();
+ }
+ return null;
+ }).when(atmi).notifyKeyguardFlagsChanged(nullable(Runnable.class), anyInt());
+
+ final InputManagerService ims = mock(InputManagerService.class);
+ // InputChannel is final and can't be mocked.
+ final InputChannel[] input = InputChannel.openInputChannelPair(TAG_WM);
+ if (input != null && input.length > 1) {
+ doReturn(input[1]).when(ims).monitorInput(anyString(), anyInt());
+ }
+
+ final ActivityTaskManagerService atms = mock(ActivityTaskManagerService.class);
+ final WindowManagerGlobalLock wmLock = new WindowManagerGlobalLock();
+ doReturn(wmLock).when(atms).getGlobalLock();
+
+ sPolicy = new TestWindowManagerPolicy(WmServiceUtils::getWindowManagerService);
+ sService = WindowManagerService.main(context, ims, false, false, sPolicy, atms);
+
+ sService.onInitReady();
+
+ final Display display = sService.mDisplayManager.getDisplay(DEFAULT_DISPLAY);
+ // Display creation is driven by the ActivityManagerService via
+ // ActivityStackSupervisor. We emulate those steps here.
+ sService.mRoot.createDisplayContent(display, mock(ActivityDisplay.class));
+ }
+
+ private static void removeLocalServices() {
+ LocalServices.removeServiceForTest(DisplayManagerInternal.class);
+ LocalServices.removeServiceForTest(PowerManagerInternal.class);
+ LocalServices.removeServiceForTest(ActivityManagerInternal.class);
+ LocalServices.removeServiceForTest(ActivityTaskManagerInternal.class);
+ LocalServices.removeServiceForTest(WindowManagerInternal.class);
+ LocalServices.removeServiceForTest(WindowManagerPolicy.class);
+ }
+
+ static WindowManagerService getWindowManagerService() {
+ return sService;
+ }
+
+ static void waitUntilWindowManagerHandlersIdle() {
+ final WindowManagerService wm = getWindowManagerService();
+ if (wm == null) {
+ return;
+ }
+ // Removing delayed FORCE_GC message decreases time for waiting idle.
+ wm.mH.removeMessages(WindowManagerService.H.FORCE_GC);
+ waitHandlerIdle(wm.mH);
+ waitHandlerIdle(wm.mAnimationHandler);
+ waitHandlerIdle(SurfaceAnimationThread.getHandler());
+ }
+
+ private static void waitHandlerIdle(Handler handler) {
+ if (!handler.hasMessagesOrCallbacks()) {
+ return;
+ }
+ final CountDownLatch latch = new CountDownLatch(1);
+ // Wait for delayed messages are processed.
+ handler.getLooper().getQueue().addIdleHandler(() -> {
+ if (handler.hasMessagesOrCallbacks()) {
+ return true; // keep idle handler.
+ }
+ latch.countDown();
+ return false; // remove idle handler.
+ });
+ try {
+ latch.await();
+ } catch (InterruptedException e) {
+ }
+ }
+}
diff --git a/services/usage/java/com/android/server/usage/AppTimeLimitController.java b/services/usage/java/com/android/server/usage/AppTimeLimitController.java
index 8e1ede116abf..2ed11fe92e15 100644
--- a/services/usage/java/com/android/server/usage/AppTimeLimitController.java
+++ b/services/usage/java/com/android/server/usage/AppTimeLimitController.java
@@ -23,7 +23,6 @@ import android.os.Looper;
import android.os.Message;
import android.os.SystemClock;
import android.util.ArrayMap;
-import android.util.ArraySet;
import android.util.Slog;
import android.util.SparseArray;
@@ -62,6 +61,8 @@ public class AppTimeLimitController {
private static final long ONE_MINUTE = 60_000L;
+ private static final Integer ONE = new Integer(1);
+
/** Collection of data for each user that has reported usage */
@GuardedBy("mLock")
private final SparseArray<UserData> mUsers = new SparseArray<>();
@@ -79,11 +80,11 @@ public class AppTimeLimitController {
private @UserIdInt
int userId;
- /** Set of the currently active entities */
- private final ArraySet<String> currentlyActive = new ArraySet<>();
+ /** Count of the currently active entities */
+ public final ArrayMap<String, Integer> currentlyActive = new ArrayMap<>();
/** Map from entity name for quick lookup */
- private final ArrayMap<String, ArrayList<UsageGroup>> observedMap = new ArrayMap<>();
+ public final ArrayMap<String, ArrayList<UsageGroup>> observedMap = new ArrayMap<>();
private UserData(@UserIdInt int userId) {
this.userId = userId;
@@ -94,7 +95,7 @@ public class AppTimeLimitController {
// TODO: Consider using a bloom filter here if number of actives becomes large
final int size = entities.length;
for (int i = 0; i < size; i++) {
- if (currentlyActive.contains(entities[i])) {
+ if (currentlyActive.containsKey(entities[i])) {
return true;
}
}
@@ -137,7 +138,7 @@ public class AppTimeLimitController {
pw.print(" Currently Active:");
final int nActive = currentlyActive.size();
for (int i = 0; i < nActive; i++) {
- pw.print(currentlyActive.valueAt(i));
+ pw.print(currentlyActive.keyAt(i));
pw.print(", ");
}
pw.println();
@@ -233,6 +234,7 @@ public class AppTimeLimitController {
protected long mUsageTimeMs;
protected int mActives;
protected long mLastKnownUsageTimeMs;
+ protected long mLastUsageEndTimeMs;
protected WeakReference<UserData> mUserRef;
protected WeakReference<ObserverAppData> mObserverAppRef;
protected PendingIntent mLimitReachedCallback;
@@ -271,9 +273,15 @@ public class AppTimeLimitController {
@GuardedBy("mLock")
void noteUsageStart(long startTimeMs, long currentTimeMs) {
if (mActives++ == 0) {
+ // If last known usage ended after the start of this usage, there is overlap
+ // between the last usage session and this one. Avoid double counting by only
+ // counting from the end of the last session. This has a rare side effect that some
+ // usage will not be accounted for if the previous session started and stopped
+ // within this current usage.
+ startTimeMs = mLastUsageEndTimeMs > startTimeMs ? mLastUsageEndTimeMs : startTimeMs;
mLastKnownUsageTimeMs = startTimeMs;
final long timeRemaining =
- mTimeLimitMs - mUsageTimeMs + currentTimeMs - startTimeMs;
+ mTimeLimitMs - mUsageTimeMs - currentTimeMs + startTimeMs;
if (timeRemaining > 0) {
if (DEBUG) {
Slog.d(TAG, "Posting timeout for " + mObserverId + " for "
@@ -287,7 +295,7 @@ public class AppTimeLimitController {
mActives = mObserved.length;
final UserData user = mUserRef.get();
if (user == null) return;
- final Object[] array = user.currentlyActive.toArray();
+ final Object[] array = user.currentlyActive.keySet().toArray();
Slog.e(TAG,
"Too many noted usage starts! Observed entities: " + Arrays.toString(
mObserved) + " Active Entities: " + Arrays.toString(array));
@@ -300,6 +308,8 @@ public class AppTimeLimitController {
if (--mActives == 0) {
final boolean limitNotCrossed = mUsageTimeMs < mTimeLimitMs;
mUsageTimeMs += stopTimeMs - mLastKnownUsageTimeMs;
+
+ mLastUsageEndTimeMs = stopTimeMs;
if (limitNotCrossed && mUsageTimeMs >= mTimeLimitMs) {
// Crossed the limit
if (DEBUG) Slog.d(TAG, "MTB informing group obs=" + mObserverId);
@@ -312,7 +322,7 @@ public class AppTimeLimitController {
mActives = 0;
final UserData user = mUserRef.get();
if (user == null) return;
- final Object[] array = user.currentlyActive.toArray();
+ final Object[] array = user.currentlyActive.keySet().toArray();
Slog.e(TAG,
"Too many noted usage stops! Observed entities: " + Arrays.toString(
mObserved) + " Active Entities: " + Arrays.toString(array));
@@ -409,7 +419,6 @@ public class AppTimeLimitController {
}
class SessionUsageGroup extends UsageGroup {
- private long mLastUsageEndTimeMs;
private long mNewSessionThresholdMs;
private PendingIntent mSessionEndCallback;
@@ -451,7 +460,6 @@ public class AppTimeLimitController {
public void noteUsageStop(long stopTimeMs) {
super.noteUsageStop(stopTimeMs);
if (mActives == 0) {
- mLastUsageEndTimeMs = stopTimeMs;
if (mUsageTimeMs >= mTimeLimitMs) {
// Usage has ended. Schedule the session end callback to be triggered once
// the new session threshold has been reached
@@ -467,7 +475,10 @@ public class AppTimeLimitController {
UserData user = mUserRef.get();
if (user == null) return;
if (mListener != null) {
- mListener.onSessionEnd(mObserverId, user.userId, mUsageTimeMs, mSessionEndCallback);
+ mListener.onSessionEnd(mObserverId,
+ user.userId,
+ mUsageTimeMs,
+ mSessionEndCallback);
}
}
@@ -599,7 +610,7 @@ public class AppTimeLimitController {
// TODO: Consider using a bloom filter here if number of actives becomes large
final int size = group.mObserved.length;
for (int i = 0; i < size; i++) {
- if (user.currentlyActive.contains(group.mObserved[i])) {
+ if (user.currentlyActive.containsKey(group.mObserved[i])) {
// Entity is currently active. Start group's usage.
group.noteUsageStart(currentTimeMs);
}
@@ -717,21 +728,28 @@ public class AppTimeLimitController {
/**
* Called when an entity becomes active.
*
- * @param name The entity that became active
- * @param userId The user
+ * @param name The entity that became active
+ * @param userId The user
+ * @param timeAgoMs Time since usage was started
*/
- public void noteUsageStart(String name, int userId) throws IllegalArgumentException {
+ public void noteUsageStart(String name, int userId, long timeAgoMs)
+ throws IllegalArgumentException {
synchronized (mLock) {
UserData user = getOrCreateUserDataLocked(userId);
if (DEBUG) Slog.d(TAG, "Usage entity " + name + " became active");
- if (user.currentlyActive.contains(name)) {
- throw new IllegalArgumentException(
- "Unable to start usage for " + name + ", already in use");
+
+ final int index = user.currentlyActive.indexOfKey(name);
+ if (index >= 0) {
+ final Integer count = user.currentlyActive.valueAt(index);
+ if (count != null) {
+ // There are multiple instances of this entity. Just increment the count.
+ user.currentlyActive.setValueAt(index, count + 1);
+ return;
+ }
}
final long currentTime = getUptimeMillis();
- // Add to the list of active entities
- user.currentlyActive.add(name);
+ user.currentlyActive.put(name, ONE);
ArrayList<UsageGroup> groups = user.observedMap.get(name);
if (groups == null) return;
@@ -739,12 +757,22 @@ public class AppTimeLimitController {
final int size = groups.size();
for (int i = 0; i < size; i++) {
UsageGroup group = groups.get(i);
- group.noteUsageStart(currentTime);
+ group.noteUsageStart(currentTime - timeAgoMs, currentTime);
}
}
}
/**
+ * Called when an entity becomes active.
+ *
+ * @param name The entity that became active
+ * @param userId The user
+ */
+ public void noteUsageStart(String name, int userId) throws IllegalArgumentException {
+ noteUsageStart(name, userId, 0);
+ }
+
+ /**
* Called when an entity becomes inactive.
*
* @param name The entity that became inactive
@@ -754,10 +782,21 @@ public class AppTimeLimitController {
synchronized (mLock) {
UserData user = getOrCreateUserDataLocked(userId);
if (DEBUG) Slog.d(TAG, "Usage entity " + name + " became inactive");
- if (!user.currentlyActive.remove(name)) {
+
+ final int index = user.currentlyActive.indexOfKey(name);
+ if (index < 0) {
throw new IllegalArgumentException(
"Unable to stop usage for " + name + ", not in use");
}
+
+ final Integer count = user.currentlyActive.valueAt(index);
+ if (!count.equals(ONE)) {
+ // There are multiple instances of this entity. Just decrement the count.
+ user.currentlyActive.setValueAt(index, count - 1);
+ return;
+ }
+
+ user.currentlyActive.removeAt(index);
final long currentTime = getUptimeMillis();
// Check if any of the groups need to watch for this entity
@@ -769,6 +808,7 @@ public class AppTimeLimitController {
UsageGroup group = groups.get(i);
group.noteUsageStop(currentTime);
}
+
}
}
@@ -780,7 +820,8 @@ public class AppTimeLimitController {
@GuardedBy("mLock")
private void postInformSessionEndListenerLocked(SessionUsageGroup group, long timeout) {
- mHandler.sendMessageDelayed(mHandler.obtainMessage(MyHandler.MSG_INFORM_SESSION_END, group),
+ mHandler.sendMessageDelayed(
+ mHandler.obtainMessage(MyHandler.MSG_INFORM_SESSION_END, group),
timeout);
}
@@ -800,7 +841,27 @@ public class AppTimeLimitController {
mHandler.removeMessages(MyHandler.MSG_CHECK_TIMEOUT, group);
}
- void dump(PrintWriter pw) {
+ void dump(String[] args, PrintWriter pw) {
+ if (args != null) {
+ for (int i = 0; i < args.length; i++) {
+ String arg = args[i];
+ if ("actives".equals(arg)) {
+ synchronized (mLock) {
+ final int nUsers = mUsers.size();
+ for (int user = 0; user < nUsers; user++) {
+ final ArrayMap<String, Integer> actives =
+ mUsers.valueAt(user).currentlyActive;
+ final int nActive = actives.size();
+ for (int active = 0; active < nActive; active++) {
+ pw.println(actives.keyAt(active));
+ }
+ }
+ }
+ return;
+ }
+ }
+ }
+
synchronized (mLock) {
pw.println("\n App Time Limits");
final int nUsers = mUsers.size();
diff --git a/services/usage/java/com/android/server/usage/UsageStatsService.java b/services/usage/java/com/android/server/usage/UsageStatsService.java
index 57dc08fcd253..f146370b01d7 100644
--- a/services/usage/java/com/android/server/usage/UsageStatsService.java
+++ b/services/usage/java/com/android/server/usage/UsageStatsService.java
@@ -53,6 +53,7 @@ import android.os.Binder;
import android.os.Environment;
import android.os.FileUtils;
import android.os.Handler;
+import android.os.IBinder;
import android.os.IDeviceIdleController;
import android.os.Looper;
import android.os.Message;
@@ -105,6 +106,8 @@ public class UsageStatsService extends SystemService implements
private static final boolean ENABLE_KERNEL_UPDATES = true;
private static final File KERNEL_COUNTER_FILE = new File("/proc/uid_procstat/set");
+ private static final char TOKEN_DELIMITER = '/';
+
// Handler message types.
static final int MSG_REPORT_EVENT = 0;
static final int MSG_FLUSH_TO_DISK = 1;
@@ -135,6 +138,10 @@ public class UsageStatsService extends SystemService implements
/** Manages app time limit observers */
AppTimeLimitController mAppTimeLimit;
+ final SparseArray<ArraySet<String>> mUsageReporters = new SparseArray();
+ final SparseArray<String> mVisibleActivities = new SparseArray();
+
+
private UsageStatsManagerInternal.AppIdleStateChangeListener mStandbyChangeListener =
new UsageStatsManagerInternal.AppIdleStateChangeListener() {
@Override
@@ -270,7 +277,7 @@ public class UsageStatsService extends SystemService implements
mHandler.obtainMessage(MSG_REMOVE_USER, userId, 0).sendToTarget();
}
} else if (Intent.ACTION_USER_STARTED.equals(action)) {
- if (userId >=0) {
+ if (userId >= 0) {
mAppStandby.postCheckIdleStates(userId);
}
}
@@ -434,17 +441,46 @@ public class UsageStatsService extends SystemService implements
mAppStandby.reportEvent(event, elapsedRealtime, userId);
switch (event.mEventType) {
case Event.ACTIVITY_RESUMED:
- try {
- mAppTimeLimit.noteUsageStart(event.getPackageName(), userId);
- } catch (IllegalArgumentException iae) {
- Slog.e(TAG, "Failed to note usage start", iae);
+ synchronized (mVisibleActivities) {
+ mVisibleActivities.put(event.mInstanceId, event.getClassName());
+ try {
+ mAppTimeLimit.noteUsageStart(event.getPackageName(), userId);
+ } catch (IllegalArgumentException iae) {
+ Slog.e(TAG, "Failed to note usage start", iae);
+ }
}
break;
- case Event.ACTIVITY_PAUSED:
- try {
- mAppTimeLimit.noteUsageStop(event.getPackageName(), userId);
- } catch (IllegalArgumentException iae) {
- Slog.e(TAG, "Failed to note usage stop", iae);
+ case Event.ACTIVITY_STOPPED:
+ case Event.ACTIVITY_DESTROYED:
+ ArraySet<String> tokens;
+ synchronized (mUsageReporters) {
+ tokens = mUsageReporters.removeReturnOld(event.mInstanceId);
+ }
+ if (tokens != null) {
+ synchronized (tokens) {
+ final int size = tokens.size();
+ // Stop usage on behalf of a UsageReporter that stopped
+ for (int i = 0; i < size; i++) {
+ final String token = tokens.valueAt(i);
+ try {
+ mAppTimeLimit.noteUsageStop(
+ buildFullToken(event.getPackageName(), token), userId);
+ } catch (IllegalArgumentException iae) {
+ Slog.w(TAG, "Failed to stop usage for during reporter death: "
+ + iae);
+ }
+ }
+ }
+ }
+
+ synchronized (mVisibleActivities) {
+ if (mVisibleActivities.removeReturnOld(event.mInstanceId) != null) {
+ try {
+ mAppTimeLimit.noteUsageStop(event.getPackageName(), userId);
+ } catch (IllegalArgumentException iae) {
+ Slog.w(TAG, "Failed to note usage stop", iae);
+ }
+ }
}
break;
}
@@ -599,6 +635,14 @@ public class UsageStatsService extends SystemService implements
return beginTime <= currentTime && beginTime < endTime;
}
+ private String buildFullToken(String packageName, String token) {
+ final StringBuilder sb = new StringBuilder(packageName.length() + token.length() + 1);
+ sb.append(packageName);
+ sb.append(TOKEN_DELIMITER);
+ sb.append(token);
+ return sb.toString();
+ }
+
private void flushToDiskLocked() {
final int userCount = mUserState.size();
for (int i = 0; i < userCount; i++) {
@@ -627,8 +671,7 @@ public class UsageStatsService extends SystemService implements
String arg = args[i];
if ("--checkin".equals(arg)) {
checkin = true;
- } else
- if ("-c".equals(arg)) {
+ } else if ("-c".equals(arg)) {
compact = true;
} else if ("flush".equals(arg)) {
flushToDiskLocked();
@@ -637,6 +680,15 @@ public class UsageStatsService extends SystemService implements
} else if ("is-app-standby-enabled".equals(arg)) {
pw.println(mAppStandby.mAppIdleEnabled);
return;
+ } else if ("apptimelimit".equals(arg)) {
+ if (i + 1 >= args.length) {
+ mAppTimeLimit.dump(null, pw);
+ } else {
+ final String[] remainingArgs =
+ Arrays.copyOfRange(args, i + 1, args.length);
+ mAppTimeLimit.dump(remainingArgs, pw);
+ }
+ return;
} else if (arg != null && !arg.startsWith("-")) {
// Anything else that doesn't start with '-' is a pkg to filter
pkg = arg;
@@ -666,7 +718,7 @@ public class UsageStatsService extends SystemService implements
mAppStandby.dumpState(args, pw);
}
- mAppTimeLimit.dump(pw);
+ mAppTimeLimit.dump(null, pw);
}
}
@@ -1231,16 +1283,82 @@ public class UsageStatsService extends SystemService implements
final int userId = UserHandle.getUserId(callingUid);
final long token = Binder.clearCallingIdentity();
try {
- UsageStatsService.this.unregisterUsageSessionObserver(callingUid, sessionObserverId, userId);
+ UsageStatsService.this.unregisterUsageSessionObserver(callingUid, sessionObserverId,
+ userId);
} finally {
Binder.restoreCallingIdentity(token);
}
}
+
+ @Override
+ public void reportUsageStart(IBinder activity, String token, String callingPackage) {
+ reportPastUsageStart(activity, token, 0, callingPackage);
+ }
+
+ @Override
+ public void reportPastUsageStart(IBinder activity, String token, long timeAgoMs,
+ String callingPackage) {
+
+ final int callingUid = Binder.getCallingUid();
+ final int userId = UserHandle.getUserId(callingUid);
+ final long binderToken = Binder.clearCallingIdentity();
+ try {
+ ArraySet<String> tokens;
+ synchronized (mUsageReporters) {
+ tokens = mUsageReporters.get(activity.hashCode());
+ if (tokens == null) {
+ tokens = new ArraySet();
+ mUsageReporters.put(activity.hashCode(), tokens);
+ }
+ }
+
+ synchronized (tokens) {
+ if (!tokens.add(token)) {
+ throw new IllegalArgumentException(token + " for " + callingPackage
+ + " is already reported as started for this activity");
+ }
+ }
+
+ mAppTimeLimit.noteUsageStart(buildFullToken(callingPackage, token),
+ userId, timeAgoMs);
+ } finally {
+ Binder.restoreCallingIdentity(binderToken);
+ }
+ }
+
+ @Override
+ public void reportUsageStop(IBinder activity, String token, String callingPackage) {
+ final int callingUid = Binder.getCallingUid();
+ final int userId = UserHandle.getUserId(callingUid);
+ final long binderToken = Binder.clearCallingIdentity();
+ try {
+ ArraySet<String> tokens;
+ synchronized (mUsageReporters) {
+ tokens = mUsageReporters.get(activity.hashCode());
+ if (tokens == null) {
+ throw new IllegalArgumentException(
+ "Unknown reporter trying to stop token " + token + " for "
+ + callingPackage);
+ }
+ }
+
+ synchronized (tokens) {
+ if (!tokens.remove(token)) {
+ throw new IllegalArgumentException(token + " for " + callingPackage
+ + " is already reported as stopped for this activity");
+ }
+ }
+ mAppTimeLimit.noteUsageStop(buildFullToken(callingPackage, token), userId);
+ } finally {
+ Binder.restoreCallingIdentity(binderToken);
+ }
+ }
}
void registerAppUsageObserver(int callingUid, int observerId, String[] packages,
long timeLimitMs, PendingIntent callbackIntent, int userId) {
- mAppTimeLimit.addAppUsageObserver(callingUid, observerId, packages, timeLimitMs, callbackIntent,
+ mAppTimeLimit.addAppUsageObserver(callingUid, observerId, packages, timeLimitMs,
+ callbackIntent,
userId);
}
diff --git a/startop/iorap/Android.bp b/startop/iorap/Android.bp
index b3b09001e7ee..59a80fbae792 100644
--- a/startop/iorap/Android.bp
+++ b/startop/iorap/Android.bp
@@ -13,7 +13,7 @@
// limitations under the License.
java_library_static {
- name: "libiorap-java",
+ name: "services.startop.iorap",
aidl: {
include_dirs: [
@@ -21,6 +21,8 @@ java_library_static {
],
},
+ libs: ["services.core"],
+
srcs: [
":iorap-aidl",
"**/*.java",
diff --git a/startop/iorap/src/com/google/android/startop/iorap/AppLaunchEvent.java b/startop/iorap/src/com/google/android/startop/iorap/AppLaunchEvent.java
new file mode 100644
index 000000000000..c2e4581285fd
--- /dev/null
+++ b/startop/iorap/src/com/google/android/startop/iorap/AppLaunchEvent.java
@@ -0,0 +1,368 @@
+/*
+ * 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.google.android.startop.iorap;
+
+import android.annotation.LongDef;
+import android.annotation.NonNull;
+import android.annotation.Nullable;
+import android.content.ComponentName;
+import android.content.Intent;
+import android.content.pm.ActivityInfo;
+import android.os.Parcel;
+import android.os.Parcelable;
+
+// TODO: fix this. either move this class into system server or add a dependency on
+// these wm classes to libiorap-java and libiorap-java-tests (somehow).
+import com.android.server.wm.ActivityMetricsLaunchObserver;
+import com.android.server.wm.ActivityMetricsLaunchObserver.ActivityRecordProto;
+import com.android.server.wm.ActivityMetricsLaunchObserver.Temperature;
+
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.reflect.InvocationTargetException;
+import java.util.Objects;
+
+/**
+ * Provide a hint to iorapd that an app launch sequence has transitioned state.<br /><br />
+ *
+ * Knowledge of when an activity starts/stops can be used by iorapd to increase system
+ * performance (e.g. by launching perfetto tracing to record an io profile, or by
+ * playing back an ioprofile via readahead) over the long run.<br /><br />
+ *
+ * /@see com.google.android.startop.iorap.IIorap#onAppLaunchEvent <br /><br />
+ * @see com.android.server.wm.ActivityMetricsLaunchObserver
+ * ActivityMetricsLaunchObserver for the possible event states.
+ * @hide
+ */
+public abstract class AppLaunchEvent implements Parcelable {
+ @LongDef
+ @Retention(RetentionPolicy.SOURCE)
+ public @interface SequenceId {}
+
+ public final @SequenceId
+ long sequenceId;
+
+ protected AppLaunchEvent(@SequenceId long sequenceId) {
+ this.sequenceId = sequenceId;
+ }
+
+ @Override
+ public boolean equals(Object other) {
+ if (other instanceof AppLaunchEvent) {
+ return equals((AppLaunchEvent) other);
+ }
+ return false;
+ }
+
+ protected boolean equals(AppLaunchEvent other) {
+ return sequenceId == other.sequenceId;
+ }
+
+
+ @Override
+ public String toString() {
+ return getClass().getSimpleName() +
+ "{" + "sequenceId=" + Long.toString(sequenceId) +
+ toStringBody() + "}";
+ }
+
+ protected String toStringBody() { return ""; };
+
+ // List of possible variants:
+
+ public static final class IntentStarted extends AppLaunchEvent {
+ @NonNull
+ public final Intent intent;
+
+ public IntentStarted(@SequenceId long sequenceId, Intent intent) {
+ super(sequenceId);
+ this.intent = intent;
+
+ Objects.requireNonNull(intent, "intent");
+ }
+
+ @Override
+ public boolean equals(Object other) {
+ if (other instanceof IntentStarted) {
+ return intent.equals(((IntentStarted)other).intent) &&
+ super.equals(other);
+ }
+ return false;
+ }
+
+ @Override
+ protected String toStringBody() {
+ return ", intent=" + intent.toString();
+ }
+
+
+ @Override
+ protected void writeToParcelImpl(Parcel p, int flags) {
+ super.writeToParcelImpl(p, flags);
+ intent.writeToParcel(p, flags);
+ }
+
+ IntentStarted(Parcel p) {
+ super(p);
+ intent = Intent.CREATOR.createFromParcel(p);
+ }
+ }
+
+ public static final class IntentFailed extends AppLaunchEvent {
+ public IntentFailed(@SequenceId long sequenceId) {
+ super(sequenceId);
+ }
+
+ @Override
+ public boolean equals(Object other) {
+ if (other instanceof IntentFailed) {
+ return super.equals(other);
+ }
+ return false;
+ }
+
+ IntentFailed(Parcel p) {
+ super(p);
+ }
+ }
+
+ public static abstract class BaseWithActivityRecordData extends AppLaunchEvent {
+ public final @NonNull
+ @ActivityRecordProto byte[] activityRecordSnapshot;
+
+ protected BaseWithActivityRecordData(@SequenceId long sequenceId,
+ @NonNull @ActivityRecordProto byte[] snapshot) {
+ super(sequenceId);
+ activityRecordSnapshot = snapshot;
+
+ Objects.requireNonNull(snapshot, "snapshot");
+ }
+
+ @Override
+ public boolean equals(Object other) {
+ if (other instanceof BaseWithActivityRecordData) {
+ return activityRecordSnapshot.equals(
+ ((BaseWithActivityRecordData)other).activityRecordSnapshot) &&
+ super.equals(other);
+ }
+ return false;
+ }
+
+ @Override
+ protected String toStringBody() {
+ return ", " + activityRecordSnapshot.toString();
+ }
+
+ @Override
+ protected void writeToParcelImpl(Parcel p, int flags) {
+ super.writeToParcelImpl(p, flags);
+ ActivityRecordProtoParcelable.write(p, activityRecordSnapshot, flags);
+ }
+
+ BaseWithActivityRecordData(Parcel p) {
+ super(p);
+ activityRecordSnapshot = ActivityRecordProtoParcelable.create(p);
+ }
+ }
+
+ public static final class ActivityLaunched extends BaseWithActivityRecordData {
+ public final @ActivityMetricsLaunchObserver.Temperature
+ int temperature;
+
+ public ActivityLaunched(@SequenceId long sequenceId,
+ @NonNull @ActivityRecordProto byte[] snapshot,
+ @ActivityMetricsLaunchObserver.Temperature int temperature) {
+ super(sequenceId, snapshot);
+ this.temperature = temperature;
+ }
+
+ @Override
+ public boolean equals(Object other) {
+ if (other instanceof ActivityLaunched) {
+ return temperature == ((ActivityLaunched)other).temperature &&
+ super.equals(other);
+ }
+ return false;
+ }
+
+ @Override
+ protected String toStringBody() {
+ return ", temperature=" + Integer.toString(temperature);
+ }
+
+ @Override
+ protected void writeToParcelImpl(Parcel p, int flags) {
+ super.writeToParcelImpl(p, flags);
+ p.writeInt(temperature);
+ }
+
+ ActivityLaunched(Parcel p) {
+ super(p);
+ temperature = p.readInt();
+ }
+ }
+
+ public static final class ActivityLaunchFinished extends BaseWithActivityRecordData {
+ public ActivityLaunchFinished(@SequenceId long sequenceId,
+ @NonNull @ActivityRecordProto byte[] snapshot) {
+ super(sequenceId, snapshot);
+ }
+
+ @Override
+ public boolean equals(Object other) {
+ if (other instanceof ActivityLaunched) {
+ return super.equals(other);
+ }
+ return false;
+ }
+ }
+
+ public static class ActivityLaunchCancelled extends AppLaunchEvent {
+ public final @Nullable
+ @ActivityRecordProto byte[] activityRecordSnapshot;
+
+ public ActivityLaunchCancelled(@SequenceId long sequenceId,
+ @Nullable @ActivityRecordProto byte[] snapshot) {
+ super(sequenceId);
+ activityRecordSnapshot = snapshot;
+ }
+
+ @Override
+ public boolean equals(Object other) {
+ if (other instanceof ActivityLaunchCancelled) {
+ return Objects.equals(activityRecordSnapshot,
+ ((ActivityLaunchCancelled)other).activityRecordSnapshot) &&
+ super.equals(other);
+ }
+ return false;
+ }
+
+ @Override
+ protected String toStringBody() {
+ return ", " + activityRecordSnapshot.toString();
+ }
+
+ @Override
+ protected void writeToParcelImpl(Parcel p, int flags) {
+ super.writeToParcelImpl(p, flags);
+ if (activityRecordSnapshot != null) {
+ p.writeBoolean(true);
+ ActivityRecordProtoParcelable.write(p, activityRecordSnapshot, flags);
+ } else {
+ p.writeBoolean(false);
+ }
+ }
+
+ ActivityLaunchCancelled(Parcel p) {
+ super(p);
+ if (p.readBoolean()) {
+ activityRecordSnapshot = ActivityRecordProtoParcelable.create(p);
+ } else {
+ activityRecordSnapshot = null;
+ }
+ }
+ }
+
+ @Override
+ public @ContentsFlags int describeContents() { return 0; }
+
+ @Override
+ public void writeToParcel(Parcel p, @WriteFlags int flags) {
+ p.writeInt(getTypeIndex());
+
+ writeToParcelImpl(p, flags);
+ }
+
+
+ public static Creator<AppLaunchEvent> CREATOR =
+ new Creator<AppLaunchEvent>() {
+ @Override
+ public AppLaunchEvent createFromParcel(Parcel source) {
+ int typeIndex = source.readInt();
+
+ Class<?> kls = getClassFromTypeIndex(typeIndex);
+ if (kls == null) {
+ throw new IllegalArgumentException("Invalid type index: " + typeIndex);
+ }
+
+ try {
+ return (AppLaunchEvent) kls.getConstructor(Parcel.class).newInstance(source);
+ } catch (InstantiationException e) {
+ throw new AssertionError(e);
+ } catch (IllegalAccessException e) {
+ throw new AssertionError(e);
+ } catch (InvocationTargetException e) {
+ throw new AssertionError(e);
+ } catch (NoSuchMethodException e) {
+ throw new AssertionError(e);
+ }
+ }
+
+ @Override
+ public AppLaunchEvent[] newArray(int size) {
+ return new AppLaunchEvent[0];
+ }
+ };
+
+ protected void writeToParcelImpl(Parcel p, int flags) {
+ p.writeLong(sequenceId);
+ }
+
+ protected AppLaunchEvent(Parcel p) {
+ sequenceId = p.readLong();
+ }
+
+ private int getTypeIndex() {
+ for (int i = 0; i < sTypes.length; ++i) {
+ if (sTypes[i].equals(this.getClass())) {
+ return i;
+ }
+ }
+ throw new AssertionError("sTypes did not include this type: " + this.getClass());
+ }
+
+ private static @Nullable Class<?> getClassFromTypeIndex(int typeIndex) {
+ if (typeIndex >= 0 && typeIndex < sTypes.length) {
+ return sTypes[typeIndex];
+ }
+ return null;
+ }
+
+ // Index position matters: It is used to encode the specific type in parceling.
+ // Keep up-to-date with C++ side.
+ private static Class<?>[] sTypes = new Class[] {
+ IntentStarted.class,
+ IntentFailed.class,
+ ActivityLaunched.class,
+ ActivityLaunchFinished.class,
+ ActivityLaunchCancelled.class,
+ };
+
+ // TODO: move to @ActivityRecordProto byte[] once we have unit tests.
+ public static class ActivityRecordProtoParcelable {
+ public static void write(Parcel p, @ActivityRecordProto byte[] activityRecordSnapshot,
+ int flags) {
+ p.writeByteArray(activityRecordSnapshot);
+ }
+
+ public static @ActivityRecordProto byte[] create(Parcel p) {
+ byte[] data = p.createByteArray();
+
+ return data;
+ }
+ }
+}
diff --git a/startop/iorap/src/com/google/android/startop/iorap/IorapForwardingService.java b/startop/iorap/src/com/google/android/startop/iorap/IorapForwardingService.java
new file mode 100644
index 000000000000..7fcad360b8fe
--- /dev/null
+++ b/startop/iorap/src/com/google/android/startop/iorap/IorapForwardingService.java
@@ -0,0 +1,216 @@
+/*
+ * 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.google.android.startop.iorap;
+// TODO: rename to com.android.server.startop.iorap
+
+import android.annotation.NonNull;
+import android.annotation.Nullable;
+import android.content.ComponentName;
+import android.content.Context;
+import android.content.Intent;
+import android.content.pm.ActivityInfo;
+import android.os.IBinder;
+import android.os.Parcel;
+import android.os.RemoteException;
+import android.os.ServiceManager;
+import android.util.Log;
+
+import com.android.internal.annotations.VisibleForTesting;
+import com.android.server.LocalServices;
+import com.android.server.SystemService;
+import com.android.server.wm.ActivityMetricsLaunchObserver;
+import com.android.server.wm.ActivityMetricsLaunchObserver.ActivityRecordProto;
+import com.android.server.wm.ActivityMetricsLaunchObserver.Temperature;
+import com.android.server.wm.ActivityMetricsLaunchObserverRegistry;
+import com.android.server.wm.ActivityTaskManagerInternal;
+
+/**
+ * System-server-local proxy into the {@code IIorap} native service.
+ */
+public class IorapForwardingService extends SystemService {
+
+ public static final boolean DEBUG = true; // TODO: read from a getprop?
+ public static final String TAG = "IorapForwardingService";
+
+ private IIorap mIorapRemote;
+
+ /**
+ * Initializes the system service.
+ * <p>
+ * Subclasses must define a single argument constructor that accepts the context
+ * and passes it to super.
+ * </p>
+ *
+ * @param context The system server context.
+ */
+ public IorapForwardingService(Context context) {
+ super(context);
+ }
+
+ //<editor-fold desc="Providers">
+ /*
+ * Providers for external dependencies:
+ * - These are marked as protected to allow tests to inject different values via mocks.
+ */
+
+ @VisibleForTesting
+ protected ActivityMetricsLaunchObserverRegistry provideLaunchObserverRegistry() {
+ ActivityTaskManagerInternal amtInternal =
+ LocalServices.getService(ActivityTaskManagerInternal.class);
+ ActivityMetricsLaunchObserverRegistry launchObserverRegistry =
+ amtInternal.getLaunchObserverRegistry();
+ return launchObserverRegistry;
+ }
+
+ @VisibleForTesting
+ protected IIorap provideIorapRemote() {
+ try {
+ return IIorap.Stub.asInterface(ServiceManager.getServiceOrThrow("iorapd"));
+ } catch (ServiceManager.ServiceNotFoundException e) {
+ // TODO: how do we handle service being missing?
+ throw new AssertionError(e);
+ }
+ }
+
+ //</editor-fold>
+
+ @Override
+ public void onStart() {
+ if (DEBUG) {
+ Log.v(TAG, "onStart");
+ }
+
+ // Connect to the native binder service.
+ mIorapRemote = provideIorapRemote();
+ invokeRemote( () -> mIorapRemote.setTaskListener(new RemoteTaskListener()) );
+
+ // Listen to App Launch Sequence events from ActivityTaskManager,
+ // and forward them to the native binder service.
+ ActivityMetricsLaunchObserverRegistry launchObserverRegistry =
+ provideLaunchObserverRegistry();
+ launchObserverRegistry.registerLaunchObserver(new AppLaunchObserver());
+ }
+
+ private class AppLaunchObserver implements ActivityMetricsLaunchObserver {
+ // We add a synthetic sequence ID here to make it easier to differentiate new
+ // launch sequences on the native side.
+ private @AppLaunchEvent.SequenceId long mSequenceId = -1;
+
+ @Override
+ public void onIntentStarted(@NonNull Intent intent) {
+ // #onIntentStarted [is the only transition that] initiates a new launch sequence.
+ ++mSequenceId;
+
+ if (DEBUG) {
+ Log.v(TAG, String.format("AppLaunchObserver#onIntentStarted(%d, %s)",
+ mSequenceId, intent));
+ }
+
+ invokeRemote(() ->
+ mIorapRemote.onAppLaunchEvent(RequestId.nextValueForSequence(),
+ new AppLaunchEvent.IntentStarted(mSequenceId, intent))
+ );
+ }
+
+ @Override
+ public void onIntentFailed() {
+ if (DEBUG) {
+ Log.v(TAG, String.format("AppLaunchObserver#onIntentFailed(%d)", mSequenceId));
+ }
+
+ invokeRemote(() ->
+ mIorapRemote.onAppLaunchEvent(RequestId.nextValueForSequence(),
+ new AppLaunchEvent.IntentFailed(mSequenceId))
+ );
+ }
+
+ @Override
+ public void onActivityLaunched(@NonNull @ActivityRecordProto byte[] activity,
+ @Temperature int temperature) {
+ if (DEBUG) {
+ Log.v(TAG, String.format("AppLaunchObserver#onActivityLaunched(%d, %s, %d)",
+ mSequenceId, activity, temperature));
+ }
+
+ invokeRemote(() ->
+ mIorapRemote.onAppLaunchEvent(RequestId.nextValueForSequence(),
+ new AppLaunchEvent.ActivityLaunched(mSequenceId, activity, temperature))
+ );
+ }
+
+ @Override
+ public void onActivityLaunchCancelled(@Nullable @ActivityRecordProto byte[] activity) {
+ if (DEBUG) {
+ Log.v(TAG, String.format("AppLaunchObserver#onActivityLaunchCancelled(%d, %s)",
+ mSequenceId, activity));
+ }
+
+ invokeRemote(() ->
+ mIorapRemote.onAppLaunchEvent(RequestId.nextValueForSequence(),
+ new AppLaunchEvent.ActivityLaunchCancelled(mSequenceId,
+ activity)));
+ }
+
+ @Override
+ public void onActivityLaunchFinished(@NonNull @ActivityRecordProto byte[] activity) {
+ if (DEBUG) {
+ Log.v(TAG, String.format("AppLaunchObserver#onActivityLaunchFinished(%d, %s)",
+ mSequenceId, activity));
+ }
+
+ invokeRemote(() ->
+ mIorapRemote.onAppLaunchEvent(RequestId.nextValueForSequence(),
+ new AppLaunchEvent.ActivityLaunchCancelled(mSequenceId, activity))
+ );
+ }
+ }
+
+ private class RemoteTaskListener extends ITaskListener.Stub {
+ @Override
+ public void onProgress(RequestId requestId, TaskResult result) throws RemoteException {
+ if (DEBUG) {
+ Log.v(TAG,
+ String.format("RemoteTaskListener#onProgress(%s, %s)", requestId, result));
+ }
+
+ // TODO: implement rest.
+ }
+
+ @Override
+ public void onComplete(RequestId requestId, TaskResult result) throws RemoteException {
+ if (DEBUG) {
+ Log.v(TAG,
+ String.format("RemoteTaskListener#onComplete(%s, %s)", requestId, result));
+ }
+
+ // TODO: implement rest.
+ }
+ }
+
+ private interface RemoteRunnable {
+ void run() throws RemoteException;
+ }
+
+ private static void invokeRemote(RemoteRunnable r) {
+ try {
+ r.run();
+ } catch (RemoteException e) {
+ // TODO: what do we do with exceptions?
+ throw new AssertionError("not implemented", e);
+ }
+ }
+}
diff --git a/startop/iorap/src/com/google/android/startop/iorap/RequestId.java b/startop/iorap/src/com/google/android/startop/iorap/RequestId.java
index 2c79319a1459..adb3a910f7fe 100644
--- a/startop/iorap/src/com/google/android/startop/iorap/RequestId.java
+++ b/startop/iorap/src/com/google/android/startop/iorap/RequestId.java
@@ -71,7 +71,7 @@ public class RequestId implements Parcelable {
@Override
public String toString() {
- return String.format("{requestId: %ld}", requestId);
+ return String.format("{requestId: %d}", requestId);
}
@Override
diff --git a/startop/iorap/tests/Android.bp b/startop/iorap/tests/Android.bp
index 76057846e896..5ac4a46b81f1 100644
--- a/startop/iorap/tests/Android.bp
+++ b/startop/iorap/tests/Android.bp
@@ -18,8 +18,15 @@ java_library {
srcs: ["src/**/*.kt"],
static_libs: [
- // non-test dependencies
- "libiorap-java",
+ // Non-test dependencies
+
+ // library under test
+ "services.startop.iorap",
+ // need the system_server code to be on the classpath,
+ "services.core",
+
+ // Test Dependencies
+
// test android dependencies
"platform-test-annotations",
"android-support-test",
diff --git a/startop/view_compiler/Android.bp b/startop/view_compiler/Android.bp
index 82056e9a33fe..2fc3a0dd874e 100644
--- a/startop/view_compiler/Android.bp
+++ b/startop/view_compiler/Android.bp
@@ -22,17 +22,35 @@ cc_defaults {
shared_libs: [
"libbase",
"libdexfile",
+ "libz",
"slicer",
],
static_libs: [
"libtinyxml2",
+ "liblog",
+ "libutils",
+ "libziparchive",
],
+ cppflags: ["-std=c++17"],
+ target: {
+ android: {
+ shared_libs: [
+ "libandroidfw",
+ ],
+ },
+ host: {
+ static_libs: [
+ "libandroidfw",
+ ],
+ },
+ },
}
cc_library_host_static {
name: "libviewcompiler",
defaults: ["viewcompiler_defaults"],
srcs: [
+ "apk_layout_compiler.cc",
"dex_builder.cc",
"dex_layout_compiler.cc",
"java_lang_builder.cc",
diff --git a/startop/view_compiler/apk_layout_compiler.cc b/startop/view_compiler/apk_layout_compiler.cc
new file mode 100644
index 000000000000..e95041ba34a4
--- /dev/null
+++ b/startop/view_compiler/apk_layout_compiler.cc
@@ -0,0 +1,159 @@
+/*
+ * 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.
+ */
+
+#include "apk_layout_compiler.h"
+#include "dex_layout_compiler.h"
+#include "java_lang_builder.h"
+#include "layout_validation.h"
+#include "util.h"
+
+#include "androidfw/ApkAssets.h"
+#include "androidfw/AssetManager2.h"
+#include "androidfw/ResourceTypes.h"
+
+#include <iostream>
+#include <locale>
+
+#include "android-base/stringprintf.h"
+
+namespace startop {
+
+using android::ResXMLParser;
+using android::base::StringPrintf;
+
+class ResXmlVisitorAdapter {
+ public:
+ ResXmlVisitorAdapter(ResXMLParser* parser) : parser_{parser} {}
+
+ template <typename Visitor>
+ void Accept(Visitor* visitor) {
+ size_t depth{0};
+ do {
+ switch (parser_->next()) {
+ case ResXMLParser::START_DOCUMENT:
+ depth++;
+ visitor->VisitStartDocument();
+ break;
+ case ResXMLParser::END_DOCUMENT:
+ depth--;
+ visitor->VisitEndDocument();
+ break;
+ case ResXMLParser::START_TAG: {
+ depth++;
+ size_t name_length = 0;
+ const char16_t* name = parser_->getElementName(&name_length);
+ visitor->VisitStartTag(std::u16string{name, name_length});
+ break;
+ }
+ case ResXMLParser::END_TAG:
+ depth--;
+ visitor->VisitEndTag();
+ break;
+ default:;
+ }
+ } while (depth > 0 || parser_->getEventType() == ResXMLParser::FIRST_CHUNK_CODE);
+ }
+
+ private:
+ ResXMLParser* parser_;
+};
+
+bool CanCompileLayout(ResXMLParser* parser) {
+ ResXmlVisitorAdapter adapter{parser};
+ LayoutValidationVisitor visitor;
+ adapter.Accept(&visitor);
+
+ return visitor.can_compile();
+}
+
+void CompileApkLayouts(const std::string& filename, CompilationTarget target,
+ std::ostream& target_out) {
+ auto assets = android::ApkAssets::Load(filename);
+ android::AssetManager2 resources;
+ resources.SetApkAssets({assets.get()});
+
+ std::string package_name;
+
+ // TODO: handle multiple packages better
+ bool first = true;
+ for (const auto& package : assets->GetLoadedArsc()->GetPackages()) {
+ CHECK(first);
+ package_name = package->GetPackageName();
+ first = false;
+ }
+
+ dex::DexBuilder dex_file;
+ dex::ClassBuilder compiled_view{
+ dex_file.MakeClass(StringPrintf("%s.CompiledView", package_name.c_str()))};
+ std::vector<dex::MethodBuilder> methods;
+
+ assets->ForEachFile("res/", [&](const android::StringPiece& s, android::FileType) {
+ if (s == "layout") {
+ auto path = StringPrintf("res/%s/", s.to_string().c_str());
+ assets->ForEachFile(path, [&](const android::StringPiece& layout_file, android::FileType) {
+ auto layout_path = StringPrintf("%s%s", path.c_str(), layout_file.to_string().c_str());
+ android::ApkAssetsCookie cookie = android::kInvalidCookie;
+ auto asset = resources.OpenNonAsset(layout_path, android::Asset::ACCESS_RANDOM, &cookie);
+ CHECK(asset);
+ CHECK(android::kInvalidCookie != cookie);
+ const auto dynamic_ref_table = resources.GetDynamicRefTableForCookie(cookie);
+ CHECK(nullptr != dynamic_ref_table);
+ android::ResXMLTree xml_tree{dynamic_ref_table};
+ xml_tree.setTo(asset->getBuffer(/*wordAligned=*/true),
+ asset->getLength(),
+ /*copy_data=*/true);
+ android::ResXMLParser parser{xml_tree};
+ parser.restart();
+ if (CanCompileLayout(&parser)) {
+ parser.restart();
+ const std::string layout_name = startop::util::FindLayoutNameFromFilename(layout_path);
+ ResXmlVisitorAdapter adapter{&parser};
+ switch (target) {
+ case CompilationTarget::kDex: {
+ methods.push_back(compiled_view.CreateMethod(
+ layout_name,
+ dex::Prototype{dex::TypeDescriptor::FromClassname("android.view.View"),
+ dex::TypeDescriptor::FromClassname("android.content.Context"),
+ dex::TypeDescriptor::Int()}));
+ DexViewBuilder builder(&methods.back());
+ builder.Start();
+ LayoutCompilerVisitor visitor{&builder};
+ adapter.Accept(&visitor);
+ builder.Finish();
+ methods.back().Encode();
+ break;
+ }
+ case CompilationTarget::kJavaLanguage: {
+ JavaLangViewBuilder builder{package_name, layout_name, target_out};
+ builder.Start();
+ LayoutCompilerVisitor visitor{&builder};
+ adapter.Accept(&visitor);
+ builder.Finish();
+ break;
+ }
+ }
+ }
+ });
+ }
+ });
+
+ if (target == CompilationTarget::kDex) {
+ slicer::MemView image{dex_file.CreateImage()};
+ target_out.write(image.ptr<const char>(), image.size());
+ }
+}
+
+} // namespace startop
diff --git a/startop/view_compiler/apk_layout_compiler.h b/startop/view_compiler/apk_layout_compiler.h
new file mode 100644
index 000000000000..c85ddd65ac1b
--- /dev/null
+++ b/startop/view_compiler/apk_layout_compiler.h
@@ -0,0 +1,31 @@
+/*
+ * 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.
+ */
+
+#ifndef APK_LAYOUT_COMPILER_H_
+#define APK_LAYOUT_COMPILER_H_
+
+#include <string>
+
+namespace startop {
+
+enum class CompilationTarget { kJavaLanguage, kDex };
+
+void CompileApkLayouts(const std::string& filename, CompilationTarget target,
+ std::ostream& target_out);
+
+} // namespace startop
+
+#endif // APK_LAYOUT_COMPILER_H_ \ No newline at end of file
diff --git a/startop/view_compiler/main.cc b/startop/view_compiler/main.cc
index ae00187e1908..871a421cee2d 100644
--- a/startop/view_compiler/main.cc
+++ b/startop/view_compiler/main.cc
@@ -17,6 +17,7 @@
#include "gflags/gflags.h"
#include "android-base/stringprintf.h"
+#include "apk_layout_compiler.h"
#include "dex_builder.h"
#include "dex_layout_compiler.h"
#include "java_lang_builder.h"
@@ -46,6 +47,7 @@ using std::string;
constexpr char kStdoutFilename[]{"stdout"};
+DEFINE_bool(apk, false, "Compile layouts in an APK");
DEFINE_bool(dex, false, "Generate a DEX file instead of Java");
DEFINE_string(out, kStdoutFilename, "Where to write the generated class");
DEFINE_string(package, "", "The package name for the generated class (required)");
@@ -108,6 +110,21 @@ int main(int argc, char** argv) {
}
const char* const filename = argv[kFileNameParam];
+ const bool is_stdout = FLAGS_out == kStdoutFilename;
+
+ std::ofstream outfile;
+ if (!is_stdout) {
+ outfile.open(FLAGS_out);
+ }
+
+ if (FLAGS_apk) {
+ startop::CompileApkLayouts(
+ filename,
+ FLAGS_dex ? startop::CompilationTarget::kDex : startop::CompilationTarget::kJavaLanguage,
+ is_stdout ? std::cout : outfile);
+ return 0;
+ }
+
const string layout_name = startop::util::FindLayoutNameFromFilename(filename);
XMLDocument xml;
@@ -119,13 +136,6 @@ int main(int argc, char** argv) {
return 1;
}
- const bool is_stdout = FLAGS_out == kStdoutFilename;
-
- std::ofstream outfile;
- if (!is_stdout) {
- outfile.open(FLAGS_out);
- }
-
if (FLAGS_dex) {
DexBuilder dex_file;
string class_name = StringPrintf("%s.CompiledView", FLAGS_package.c_str());
diff --git a/telecomm/java/android/telecom/CallRedirectionService.java b/telecomm/java/android/telecom/CallRedirectionService.java
index b906d0bf3136..329911776993 100644
--- a/telecomm/java/android/telecom/CallRedirectionService.java
+++ b/telecomm/java/android/telecom/CallRedirectionService.java
@@ -16,6 +16,7 @@
package android.telecom;
+import android.annotation.NonNull;
import android.annotation.SdkConstant;
import android.app.Service;
import android.content.Intent;
@@ -27,8 +28,8 @@ import android.os.Message;
import android.os.RemoteException;
import com.android.internal.os.SomeArgs;
-import com.android.internal.telecom.ICallRedirectionService;
import com.android.internal.telecom.ICallRedirectionAdapter;
+import com.android.internal.telecom.ICallRedirectionService;
/**
* This service can be implemented to interact between Telecom and its implementor
@@ -62,22 +63,35 @@ public abstract class CallRedirectionService extends Service {
/**
* Telecom calls this method to inform the implemented {@link CallRedirectionService} of
- * a new outgoing call which is being placed.
+ * a new outgoing call which is being placed. Telecom does not request to redirect emergency
+ * calls and does not request to redirect calls with gateway information.
+ *
+ * <p>Telecom will cancel the call if Telecom does not receive a response in 5 seconds from
+ * the implemented {@link CallRedirectionService} set by users.
*
- * The implemented {@link CallRedirectionService} can call {@link #placeCallUnmodified()},
- * {@link #redirectCall(Uri, PhoneAccountHandle)}, and {@link #cancelCall()} only from here.
+ * <p>The implemented {@link CallRedirectionService} can call {@link #placeCallUnmodified()},
+ * {@link #redirectCall(Uri, PhoneAccountHandle, boolean)}, and {@link #cancelCall()} only
+ * from here.
*
- * @param handle the phone number dialed by the user
- * @param targetPhoneAccount the {@link PhoneAccountHandle} on which the call will be placed.
+ * @param handle the phone number dialed by the user, represented in E.164 format if possible
+ * @param initialPhoneAccount the {@link PhoneAccountHandle} on which the call will be placed.
+ * @param allowInteractiveResponse a boolean to tell if the implemented
+ * {@link CallRedirectionService} should allow interactive
+ * responses with users. Will be {@code false} if, for example
+ * the device is in car mode and the user would not be able to
+ * interact with their device.
*/
- public abstract void onPlaceCall(Uri handle, PhoneAccountHandle targetPhoneAccount);
+ public abstract void onPlaceCall(@NonNull Uri handle,
+ @NonNull PhoneAccountHandle initialPhoneAccount,
+ boolean allowInteractiveResponse);
/**
* The implemented {@link CallRedirectionService} calls this method to response a request
- * received via {@link #onPlaceCall(Uri, PhoneAccountHandle)} to inform Telecom that no changes
- * are required to the outgoing call, and that the call should be placed as-is.
+ * received via {@link #onPlaceCall(Uri, PhoneAccountHandle, boolean)} to inform Telecom that
+ * no changes are required to the outgoing call, and that the call should be placed as-is.
*
- * This can only be called from implemented {@link #onPlaceCall(Uri, PhoneAccountHandle)}.
+ * <p>This can only be called from implemented
+ * {@link #onPlaceCall(Uri, PhoneAccountHandle, boolean)}.
*
*/
public final void placeCallUnmodified() {
@@ -89,29 +103,39 @@ public abstract class CallRedirectionService extends Service {
/**
* The implemented {@link CallRedirectionService} calls this method to response a request
- * received via {@link #onPlaceCall(Uri, PhoneAccountHandle)} to inform Telecom that changes
- * are required to the phone number or/and {@link PhoneAccountHandle} for the outgoing call.
+ * received via {@link #onPlaceCall(Uri, PhoneAccountHandle, boolean)} to inform Telecom that
+ * changes are required to the phone number or/and {@link PhoneAccountHandle} for the outgoing
+ * call. Telecom will cancel the call if the implemented {@link CallRedirectionService}
+ * replies Telecom a handle for an emergency number.
*
- * This can only be called from implemented {@link #onPlaceCall(Uri, PhoneAccountHandle)}.
+ * <p>This can only be called from implemented
+ * {@link #onPlaceCall(Uri, PhoneAccountHandle, boolean)}.
*
* @param handle the new phone number to dial
* @param targetPhoneAccount the {@link PhoneAccountHandle} to use when placing the call.
* If {@code null}, no change will be made to the
* {@link PhoneAccountHandle} used to place the call.
+ * @param confirmFirst Telecom will ask users to confirm the redirection via a yes/no dialog
+ * if the confirmFirst is true, and if the redirection request of this
+ * response was sent with a true flag of allowInteractiveResponse via
+ * {@link #onPlaceCall(Uri, PhoneAccountHandle, boolean)}
*/
- public final void redirectCall(Uri handle, PhoneAccountHandle targetPhoneAccount) {
+ public final void redirectCall(@NonNull Uri handle,
+ @NonNull PhoneAccountHandle targetPhoneAccount,
+ boolean confirmFirst) {
try {
- mCallRedirectionAdapter.redirectCall(handle, targetPhoneAccount);
+ mCallRedirectionAdapter.redirectCall(handle, targetPhoneAccount, confirmFirst);
} catch (RemoteException e) {
}
}
/**
* The implemented {@link CallRedirectionService} calls this method to response a request
- * received via {@link #onPlaceCall(Uri, PhoneAccountHandle)} to inform Telecom that an outgoing
- * call should be canceled entirely.
+ * received via {@link #onPlaceCall(Uri, PhoneAccountHandle, boolean)} to inform Telecom that
+ * an outgoing call should be canceled entirely.
*
- * This can only be called from implemented {@link #onPlaceCall(Uri, PhoneAccountHandle)}.
+ * <p>This can only be called from implemented
+ * {@link #onPlaceCall(Uri, PhoneAccountHandle, boolean)}.
*
*/
public final void cancelCall() {
@@ -137,7 +161,8 @@ public abstract class CallRedirectionService extends Service {
SomeArgs args = (SomeArgs) msg.obj;
try {
mCallRedirectionAdapter = (ICallRedirectionAdapter) args.arg1;
- onPlaceCall((Uri) args.arg2, (PhoneAccountHandle) args.arg3);
+ onPlaceCall((Uri) args.arg2, (PhoneAccountHandle) args.arg3,
+ (boolean) args.arg4);
} finally {
args.recycle();
}
@@ -152,15 +177,20 @@ public abstract class CallRedirectionService extends Service {
* Telecom calls this method to inform the CallRedirectionService of a new outgoing call
* which is about to be placed.
* @param handle the phone number dialed by the user
- * @param targetPhoneAccount the URI of the number the user dialed
+ * @param initialPhoneAccount the URI of the number the user dialed
+ * @param allowInteractiveResponse a boolean to tell if the implemented
+ * {@link CallRedirectionService} should allow interactive
+ * responses with users.
*/
@Override
- public void placeCall(ICallRedirectionAdapter adapter, Uri handle,
- PhoneAccountHandle targetPhoneAccount) {
+ public void placeCall(@NonNull ICallRedirectionAdapter adapter, @NonNull Uri handle,
+ @NonNull PhoneAccountHandle initialPhoneAccount,
+ boolean allowInteractiveResponse) {
SomeArgs args = SomeArgs.obtain();
args.arg1 = adapter;
args.arg2 = handle;
- args.arg3 = targetPhoneAccount;
+ args.arg3 = initialPhoneAccount;
+ args.arg4 = allowInteractiveResponse;
mHandler.obtainMessage(MSG_PLACE_CALL, args).sendToTarget();
}
}
diff --git a/telecomm/java/com/android/internal/telecom/ICallRedirectionAdapter.aidl b/telecomm/java/com/android/internal/telecom/ICallRedirectionAdapter.aidl
index 46bf983f52a2..0a42a3f4f02e 100644
--- a/telecomm/java/com/android/internal/telecom/ICallRedirectionAdapter.aidl
+++ b/telecomm/java/com/android/internal/telecom/ICallRedirectionAdapter.aidl
@@ -31,5 +31,6 @@ oneway interface ICallRedirectionAdapter {
void placeCallUnmodified();
- void redirectCall(in Uri handle, in PhoneAccountHandle targetPhoneAccount);
+ void redirectCall(in Uri handle, in PhoneAccountHandle targetPhoneAccount,
+ boolean confirmFirst);
}
diff --git a/telecomm/java/com/android/internal/telecom/ICallRedirectionService.aidl b/telecomm/java/com/android/internal/telecom/ICallRedirectionService.aidl
index d8d360beb64d..c1bc44007b0b 100644
--- a/telecomm/java/com/android/internal/telecom/ICallRedirectionService.aidl
+++ b/telecomm/java/com/android/internal/telecom/ICallRedirectionService.aidl
@@ -30,5 +30,5 @@ import com.android.internal.telecom.ICallRedirectionAdapter;
*/
oneway interface ICallRedirectionService {
void placeCall(in ICallRedirectionAdapter adapter, in Uri handle,
- in PhoneAccountHandle targetPhoneAccount);
+ in PhoneAccountHandle initialPhoneAccount, boolean allowInteractiveResponse);
}
diff --git a/telephony/java/android/telephony/ims/RcsParticipant.java b/telephony/java/android/telephony/ims/RcsParticipant.java
index 70500aaa2e8b..f678ec7e435b 100644
--- a/telephony/java/android/telephony/ims/RcsParticipant.java
+++ b/telephony/java/android/telephony/ims/RcsParticipant.java
@@ -15,22 +15,111 @@
*/
package android.telephony.ims;
+import static android.telephony.ims.RcsMessageStore.TAG;
+
+import android.annotation.NonNull;
+import android.annotation.WorkerThread;
import android.os.Parcel;
import android.os.Parcelable;
+import android.os.RemoteException;
+import android.os.ServiceManager;
+import android.telephony.Rlog;
+import android.telephony.ims.aidl.IRcs;
+import android.text.TextUtils;
+
+import com.android.internal.util.Preconditions;
/**
* RcsParticipant is an RCS capable contact that can participate in {@link RcsThread}s.
* @hide - TODO(sahinc) make this public
*/
public class RcsParticipant implements Parcelable {
+ // The row ID of this participant in the database
+ private int mId;
+ // The phone number of this participant
+ private String mCanonicalAddress;
+ // The RCS alias of this participant. This is different than the name of the contact in the
+ // Contacts app - i.e. RCS protocol allows users to define aliases for themselves that doesn't
+ // require other users to add them as contacts and give them a name.
+ private String mAlias;
+
/**
- * Returns the row id of this participant.
+ * Constructor for {@link com.android.internal.telephony.ims.RcsMessageStoreController}
+ * to create instances of participants. This is not meant to be part of the SDK.
+ *
+ * @hide
+ */
+ public RcsParticipant(int id, @NonNull String canonicalAddress) {
+ mId = id;
+ mCanonicalAddress = canonicalAddress;
+ }
+
+ /**
+ * @return Returns the canonical address (i.e. normalized phone number) for this participant
+ */
+ public String getCanonicalAddress() {
+ return mCanonicalAddress;
+ }
+
+ /**
+ * Sets the canonical address for this participant and updates it in storage.
+ * @param canonicalAddress the canonical address to update to.
+ */
+ @WorkerThread
+ public void setCanonicalAddress(@NonNull String canonicalAddress) {
+ Preconditions.checkNotNull(canonicalAddress);
+ if (canonicalAddress.equals(mCanonicalAddress)) {
+ return;
+ }
+
+ mCanonicalAddress = canonicalAddress;
+
+ try {
+ IRcs iRcs = IRcs.Stub.asInterface(ServiceManager.getService("ircs"));
+ if (iRcs != null) {
+ iRcs.updateRcsParticipantCanonicalAddress(mId, mCanonicalAddress);
+ }
+ } catch (RemoteException re) {
+ Rlog.e(TAG, "RcsParticipant: Exception happened during setCanonicalAddress", re);
+ }
+ }
+
+ /**
+ * @return Returns the alias for this participant. Alias is usually the real name of the person
+ * themselves.
+ */
+ public String getAlias() {
+ return mAlias;
+ }
+
+ /**
+ * Sets the alias for this participant and persists it in storage. Alias is usually the real
+ * name of the person themselves.
+ */
+ @WorkerThread
+ public void setAlias(String alias) {
+ if (TextUtils.equals(mAlias, alias)) {
+ return;
+ }
+ mAlias = alias;
+
+ try {
+ IRcs iRcs = IRcs.Stub.asInterface(ServiceManager.getService("ircs"));
+ if (iRcs != null) {
+ iRcs.updateRcsParticipantAlias(mId, mAlias);
+ }
+ } catch (RemoteException re) {
+ Rlog.e(TAG, "RcsParticipant: Exception happened during setCanonicalAddress", re);
+ }
+ }
+
+ /**
+ * Returns the row id of this participant. This is not meant to be part of the SDK
*
- * TODO(sahinc) implement
* @hide
*/
public int getId() {
- return 12345;
+ return mId;
}
public static final Creator<RcsParticipant> CREATOR = new Creator<RcsParticipant>() {
@@ -46,6 +135,9 @@ public class RcsParticipant implements Parcelable {
};
protected RcsParticipant(Parcel in) {
+ mId = in.readInt();
+ mCanonicalAddress = in.readString();
+ mAlias = in.readString();
}
@Override
@@ -55,6 +147,8 @@ public class RcsParticipant implements Parcelable {
@Override
public void writeToParcel(Parcel dest, int flags) {
-
+ dest.writeInt(mId);
+ dest.writeString(mCanonicalAddress);
+ dest.writeString(mAlias);
}
}
diff --git a/telephony/java/android/telephony/ims/aidl/IRcs.aidl b/telephony/java/android/telephony/ims/aidl/IRcs.aidl
index 9badac5be230..0c958ba719f3 100644
--- a/telephony/java/android/telephony/ims/aidl/IRcs.aidl
+++ b/telephony/java/android/telephony/ims/aidl/IRcs.aidl
@@ -37,8 +37,13 @@ interface IRcs {
Rcs1To1Thread createRcs1To1Thread(in RcsParticipant participant);
- RcsParticipant createRcsParticipant(String canonicalAddress);
-
// RcsThread APIs
int getMessageCount(int rcsThreadId);
+
+ // RcsParticipant APIs
+ RcsParticipant createRcsParticipant(String canonicalAddress);
+
+ void updateRcsParticipantCanonicalAddress(int id, String canonicalAddress);
+
+ void updateRcsParticipantAlias(int id, String alias);
} \ No newline at end of file
diff --git a/tests/RcsTests/src/com/android/tests/ims/RcsParticipantTest.java b/tests/RcsTests/src/com/android/tests/ims/RcsParticipantTest.java
new file mode 100644
index 000000000000..c402dbffc84b
--- /dev/null
+++ b/tests/RcsTests/src/com/android/tests/ims/RcsParticipantTest.java
@@ -0,0 +1,46 @@
+/*
+ * 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.tests.ims;
+
+import static com.google.common.truth.Truth.assertThat;
+
+import android.os.Bundle;
+import android.support.test.runner.AndroidJUnit4;
+import android.telephony.ims.RcsParticipant;
+
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+@RunWith(AndroidJUnit4.class)
+public class RcsParticipantTest {
+ private static final int ID = 123;
+ private static final String ALIAS = "alias";
+ private static final String CANONICAL_ADDRESS = "+1234567890";
+
+ @Test
+ public void testCanUnparcel() {
+ RcsParticipant rcsParticipant = new RcsParticipant(ID, CANONICAL_ADDRESS);
+ rcsParticipant.setAlias(ALIAS);
+
+ Bundle bundle = new Bundle();
+ bundle.putParcelable("Some key", rcsParticipant);
+ rcsParticipant = bundle.getParcelable("Some key");
+
+ assertThat(rcsParticipant.getId()).isEqualTo(ID);
+ assertThat(rcsParticipant.getAlias()).isEqualTo(ALIAS);
+ assertThat(rcsParticipant.getCanonicalAddress()).isEqualTo(CANONICAL_ADDRESS);
+ }
+}
diff --git a/tests/UsageReportingTest/Android.mk b/tests/UsageReportingTest/Android.mk
new file mode 100644
index 000000000000..afb6e16b1fdf
--- /dev/null
+++ b/tests/UsageReportingTest/Android.mk
@@ -0,0 +1,17 @@
+LOCAL_PATH:= $(call my-dir)
+include $(CLEAR_VARS)
+
+LOCAL_MODULE_TAGS := tests
+
+# Only compile source java files in this apk.
+LOCAL_SRC_FILES := $(call all-java-files-under, src)
+
+LOCAL_USE_AAPT2 := true
+LOCAL_STATIC_ANDROID_LIBRARIES := androidx.legacy_legacy-support-v4
+
+LOCAL_CERTIFICATE := platform
+
+LOCAL_PACKAGE_NAME := UsageReportingTest
+LOCAL_PRIVATE_PLATFORM_APIS := true
+
+include $(BUILD_PACKAGE)
diff --git a/tests/UsageReportingTest/AndroidManifest.xml b/tests/UsageReportingTest/AndroidManifest.xml
new file mode 100644
index 000000000000..be0b09e972a5
--- /dev/null
+++ b/tests/UsageReportingTest/AndroidManifest.xml
@@ -0,0 +1,22 @@
+<?xml version="1.0" encoding="utf-8"?>
+
+<!--
+ Note: Add android:sharedUserId="android.uid.system" to the root element to simulate the system UID
+ caller case.
+-->
+
+<manifest xmlns:android="http://schemas.android.com/apk/res/android"
+ package="com.android.tests.usagereporter"
+ >
+
+ <application android:label="@string/reporter_app">
+ <activity android:name="UsageReporterActivity"
+ android:label="UsageReporter">
+ <intent-filter>
+ <action android:name="android.intent.action.MAIN" />
+ <category android:name="android.intent.category.LAUNCHER" />
+ </intent-filter>
+ </activity>
+
+ </application>
+</manifest>
diff --git a/tests/UsageReportingTest/res/layout/row_item.xml b/tests/UsageReportingTest/res/layout/row_item.xml
new file mode 100644
index 000000000000..1eb2dab29124
--- /dev/null
+++ b/tests/UsageReportingTest/res/layout/row_item.xml
@@ -0,0 +1,36 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- 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.
+-->
+
+<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+ android:orientation="horizontal"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent"
+ android:paddingLeft="16dp"
+ android:paddingRight="16dp"
+ android:background="@color/inactive_color">
+
+ <TextView android:id="@+id/token"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_weight="1"
+ android:textStyle="bold"/>
+
+ <Button android:id="@+id/start" style="@style/ActionButton"
+ android:text="@string/start" />
+
+ <Button android:id="@+id/stop" style="@style/ActionButton"
+ android:text="@string/stop" />
+</LinearLayout>
diff --git a/tests/UsageReportingTest/res/menu/main.xml b/tests/UsageReportingTest/res/menu/main.xml
new file mode 100644
index 000000000000..9847c2dce8f2
--- /dev/null
+++ b/tests/UsageReportingTest/res/menu/main.xml
@@ -0,0 +1,28 @@
+<?xml version="1.0" encoding="utf-8" ?>
+<!-- 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.
+-->
+
+<menu xmlns:android="http://schemas.android.com/apk/res/android">
+ <item android:id="@+id/add_token"
+ android:title="@string/add_token"/>
+ <item android:id="@+id/add_many_tokens"
+ android:title="@string/add_many_tokens"/>
+ <item android:id="@+id/stop_all"
+ android:title="@string/stop_all_tokens"/>
+ <group android:checkableBehavior="all">
+ <item android:id="@+id/restore_on_start"
+ android:title="@string/restore_tokens_on_start"/>
+ </group>
+</menu> \ No newline at end of file
diff --git a/tests/UsageReportingTest/res/values/colors.xml b/tests/UsageReportingTest/res/values/colors.xml
new file mode 100644
index 000000000000..03bcf8a60182
--- /dev/null
+++ b/tests/UsageReportingTest/res/values/colors.xml
@@ -0,0 +1,19 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- 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.
+-->
+<resources>
+ <color name="active_color">#FFF</color>
+ <color name="inactive_color">#AAA</color>
+</resources> \ No newline at end of file
diff --git a/tests/UsageReportingTest/res/values/strings.xml b/tests/UsageReportingTest/res/values/strings.xml
new file mode 100644
index 000000000000..015290e732a0
--- /dev/null
+++ b/tests/UsageReportingTest/res/values/strings.xml
@@ -0,0 +1,47 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- 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.
+-->
+
+<resources>
+ <!-- Do not translate -->
+ <string name="reporter_app">Usage Reporter App</string>
+ <!-- Do not translate -->
+ <string name="start">Start</string>
+ <!-- Do not translate -->
+ <string name="stop">Stop</string>
+ <!-- Do not translate -->
+ <string name="default_token">SuperSecretToken</string>
+
+ <!-- Do not translate -->
+ <string name="add_token">Add Token</string>
+ <!-- Do not translate -->
+ <string name="add_many_tokens">Add Many Tokens</string>
+ <!-- Do not translate -->
+ <string name="stop_all_tokens">Stop All</string>
+ <!-- Do not translate -->
+ <string name="restore_tokens_on_start">Readd Tokens on Start</string>
+
+
+ <!-- Do not translate -->
+ <string name="token_query">Enter token(s) (delimit tokens with commas)</string>
+ <!-- Do not translate -->
+ <string name="many_tokens_query">Generate how many tokens?</string>
+ <!-- Do not translate -->
+ <string name="stop_all_tokens_query">Stop all tokens?</string>
+ <!-- Do not translate -->
+ <string name="ok">OK</string>
+ <!-- Do not translate -->
+ <string name="cancel">Cancel</string>
+</resources> \ No newline at end of file
diff --git a/tests/UsageReportingTest/res/values/styles.xml b/tests/UsageReportingTest/res/values/styles.xml
new file mode 100644
index 000000000000..e5b86c5e836b
--- /dev/null
+++ b/tests/UsageReportingTest/res/values/styles.xml
@@ -0,0 +1,31 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- 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.
+-->
+
+<resources>
+ <style name="ActionButton">
+ <item name="android:layout_width">wrap_content</item>
+ <item name="android:layout_height">wrap_content</item>
+ <item name="android:textAppearance">@style/TextAppearance.ActionButton</item>
+ </style>
+
+ <style name="TextAppearance" parent="android:TextAppearance">
+ </style>
+
+ <style name="TextAppearance.ActionButton">
+ <item name="android:textStyle">italic</item>
+ </style>
+
+</resources>
diff --git a/tests/UsageReportingTest/src/com/android/tests/usagereporter/UsageReporterActivity.java b/tests/UsageReportingTest/src/com/android/tests/usagereporter/UsageReporterActivity.java
new file mode 100644
index 000000000000..946be8fe93d3
--- /dev/null
+++ b/tests/UsageReportingTest/src/com/android/tests/usagereporter/UsageReporterActivity.java
@@ -0,0 +1,320 @@
+/*
+ * 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.tests.usagereporter;
+
+import android.app.Activity;
+import android.app.AlertDialog;
+import android.app.ListActivity;
+import android.app.usage.UsageStatsManager;
+import android.content.Context;
+import android.content.DialogInterface;
+import android.os.Bundle;
+import android.text.InputType;
+import android.text.TextUtils;
+import android.util.ArraySet;
+import android.view.LayoutInflater;
+import android.view.Menu;
+import android.view.MenuInflater;
+import android.view.MenuItem;
+import android.view.View;
+import android.view.View.OnClickListener;
+import android.view.ViewGroup;
+import android.widget.BaseAdapter;
+import android.widget.Button;
+import android.widget.EditText;
+import android.widget.TextView;
+import android.widget.Toast;
+
+import java.util.ArrayList;
+
+public class UsageReporterActivity extends ListActivity {
+
+ private Activity mActivity;
+ private final ArrayList<String> mTokens = new ArrayList();
+ private final ArraySet<String> mActives = new ArraySet();
+ private UsageStatsManager mUsageStatsManager;
+ private Adapter mAdapter;
+ private boolean mRestoreOnStart = false;
+ private static Context sContext;
+
+ /** Called with the activity is first created. */
+ @Override
+ public void onCreate(Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
+
+ sContext = getApplicationContext();
+
+ mUsageStatsManager = (UsageStatsManager) getSystemService(Context.USAGE_STATS_SERVICE);
+
+ mAdapter = new Adapter();
+ setListAdapter(mAdapter);
+ }
+
+ @Override
+ protected void onStart() {
+ super.onStart();
+ mActivity = this;
+
+
+ if (mRestoreOnStart) {
+ ArrayList<String> removed = null;
+ for (String token : mActives) {
+ try {
+ mUsageStatsManager.reportUsageStart(mActivity, token);
+ } catch (Exception e) {
+ // Somthing went wrong, recover and move on
+ if (removed == null) {
+ removed = new ArrayList();
+ }
+ removed.add(token);
+ }
+ }
+ if (removed != null) {
+ for (String token : removed) {
+ mActives.remove(token);
+ }
+ }
+ } else {
+ mActives.clear();
+ }
+ }
+
+ /**
+ * Called when the activity is about to start interacting with the user.
+ */
+ @Override
+ protected void onResume() {
+ super.onResume();
+ mAdapter.notifyDataSetChanged();
+ }
+
+
+ /**
+ * Called when your activity's options menu needs to be created.
+ */
+ @Override
+ public boolean onCreateOptionsMenu(Menu menu) {
+ MenuInflater inflater = getMenuInflater();
+ inflater.inflate(R.menu.main, menu);
+ return super.onCreateOptionsMenu(menu);
+ }
+
+
+ /**
+ * Called when a menu item is selected.
+ */
+ @Override
+ public boolean onOptionsItemSelected(MenuItem item) {
+ switch (item.getItemId()) {
+ case R.id.add_token:
+ callAddToken();
+ return true;
+ case R.id.add_many_tokens:
+ callAddManyTokens();
+ return true;
+ case R.id.stop_all:
+ callStopAll();
+ return true;
+ case R.id.restore_on_start:
+ mRestoreOnStart = !mRestoreOnStart;
+ item.setChecked(mRestoreOnStart);
+ return true;
+ }
+
+ return super.onOptionsItemSelected(item);
+ }
+
+ private void callAddToken() {
+ final AlertDialog.Builder builder = new AlertDialog.Builder(this);
+ builder.setTitle(getString(R.string.token_query));
+ final EditText input = new EditText(this);
+ input.setInputType(InputType.TYPE_CLASS_TEXT);
+ input.setHint(getString(R.string.default_token));
+ builder.setView(input);
+
+ builder.setPositiveButton(getString(R.string.ok), new DialogInterface.OnClickListener() {
+ @Override
+ public void onClick(DialogInterface dialog, int which) {
+ String tokenNames = input.getText().toString().trim();
+ if (TextUtils.isEmpty(tokenNames)) {
+ tokenNames = getString(R.string.default_token);
+ }
+ String[] tokens = tokenNames.split(",");
+ for (String token : tokens) {
+ if (mTokens.contains(token)) continue;
+ mTokens.add(token);
+ }
+ mAdapter.notifyDataSetChanged();
+
+ }
+ });
+ builder.setNegativeButton(getString(R.string.cancel),
+ new DialogInterface.OnClickListener() {
+ @Override
+ public void onClick(DialogInterface dialog, int which) {
+ dialog.cancel();
+ }
+ });
+
+ builder.show();
+ }
+
+ private void callAddManyTokens() {
+ final AlertDialog.Builder builder = new AlertDialog.Builder(this);
+ builder.setTitle(getString(R.string.many_tokens_query));
+ final EditText input = new EditText(this);
+ input.setInputType(InputType.TYPE_CLASS_NUMBER);
+ builder.setView(input);
+
+ builder.setPositiveButton(getString(R.string.ok),
+ new DialogInterface.OnClickListener() {
+ @Override
+ public void onClick(DialogInterface dialog, int which) {
+ String val = input.getText().toString().trim();
+ if (TextUtils.isEmpty(val)) return;
+ int n = Integer.parseInt(val);
+ for (int i = 0; i < n; i++) {
+ final String token = getString(R.string.default_token) + i;
+ if (mTokens.contains(token)) continue;
+ mTokens.add(token);
+ }
+ mAdapter.notifyDataSetChanged();
+
+ }
+ });
+ builder.setNegativeButton(getString(R.string.cancel),
+ new DialogInterface.OnClickListener() {
+ @Override
+ public void onClick(DialogInterface dialog, int which) {
+ dialog.cancel();
+ }
+ });
+
+ builder.show();
+ }
+
+ private void callStopAll() {
+ final AlertDialog.Builder builder = new AlertDialog.Builder(this);
+ builder.setTitle(getString(R.string.stop_all_tokens_query));
+
+ builder.setPositiveButton(getString(R.string.ok), new DialogInterface.OnClickListener() {
+ @Override
+ public void onClick(DialogInterface dialog, int which) {
+ for (String token : mActives) {
+ mUsageStatsManager.reportUsageStop(mActivity, token);
+ }
+ mActives.clear();
+ mAdapter.notifyDataSetChanged();
+ }
+ });
+ builder.setNegativeButton(getString(R.string.cancel),
+ new DialogInterface.OnClickListener() {
+ @Override
+ public void onClick(DialogInterface dialog, int which) {
+ dialog.cancel();
+ }
+ });
+ builder.show();
+ }
+
+ /**
+ * A call-back for when the user presses the back button.
+ */
+ OnClickListener mStartListener = new OnClickListener() {
+ public void onClick(View v) {
+ final View parent = (View) v.getParent();
+ final String token = ((TextView) parent.findViewById(R.id.token)).getText().toString();
+ try {
+ mUsageStatsManager.reportUsageStart(mActivity, token);
+ } catch (Exception e) {
+ Toast.makeText(sContext, e.toString(), Toast.LENGTH_LONG).show();
+ }
+ parent.setBackgroundColor(getColor(R.color.active_color));
+ mActives.add(token);
+ }
+ };
+
+ /**
+ * A call-back for when the user presses the clear button.
+ */
+ OnClickListener mStopListener = new OnClickListener() {
+ public void onClick(View v) {
+ final View parent = (View) v.getParent();
+
+ final String token = ((TextView) parent.findViewById(R.id.token)).getText().toString();
+ try {
+ mUsageStatsManager.reportUsageStop(mActivity, token);
+ } catch (Exception e) {
+ Toast.makeText(sContext, e.toString(), Toast.LENGTH_LONG).show();
+ }
+ parent.setBackgroundColor(getColor(R.color.inactive_color));
+ mActives.remove(token);
+ }
+ };
+
+
+ private class Adapter extends BaseAdapter {
+ @Override
+ public int getCount() {
+ return mTokens.size();
+ }
+
+ @Override
+ public Object getItem(int position) {
+ return mTokens.get(position);
+ }
+
+ @Override
+ public long getItemId(int position) {
+ return position;
+ }
+
+ @Override
+ public View getView(int position, View convertView, ViewGroup parent) {
+ final ViewHolder holder;
+ if (convertView == null) {
+ convertView = LayoutInflater.from(UsageReporterActivity.this)
+ .inflate(R.layout.row_item, parent, false);
+ holder = new ViewHolder();
+ holder.tokenName = (TextView) convertView.findViewById(R.id.token);
+
+ holder.startButton = ((Button) convertView.findViewById(R.id.start));
+ holder.startButton.setOnClickListener(mStartListener);
+ holder.stopButton = ((Button) convertView.findViewById(R.id.stop));
+ holder.stopButton.setOnClickListener(mStopListener);
+ convertView.setTag(holder);
+ } else {
+ holder = (ViewHolder) convertView.getTag();
+ }
+
+ final String token = mTokens.get(position);
+ holder.tokenName.setText(mTokens.get(position));
+ if (mActives.contains(token)) {
+ convertView.setBackgroundColor(getColor(R.color.active_color));
+ } else {
+ convertView.setBackgroundColor(getColor(R.color.inactive_color));
+ }
+ return convertView;
+ }
+ }
+
+ private static class ViewHolder {
+ public TextView tokenName;
+ public Button startButton;
+ public Button stopButton;
+ }
+}
diff --git a/tests/UsageStatsTest/src/com/android/tests/usagestats/UsageStatsActivity.java b/tests/UsageStatsTest/src/com/android/tests/usagestats/UsageStatsActivity.java
index 3d8ce21a2c00..3c628f6e0013 100644
--- a/tests/UsageStatsTest/src/com/android/tests/usagestats/UsageStatsActivity.java
+++ b/tests/UsageStatsTest/src/com/android/tests/usagestats/UsageStatsActivity.java
@@ -155,7 +155,7 @@ public class UsageStatsActivity extends ListActivity {
intent.setPackage(getPackageName());
intent.putExtra(EXTRA_KEY_TIMEOUT, true);
mUsageStatsManager.registerAppUsageObserver(1, packages,
- 30, TimeUnit.SECONDS, PendingIntent.getActivity(UsageStatsActivity.this,
+ 60, TimeUnit.SECONDS, PendingIntent.getActivity(UsageStatsActivity.this,
1, intent, 0));
}
}
diff --git a/tests/WindowManagerStressTest/src/test/windowmanagerstresstest/MainActivity.java b/tests/WindowManagerStressTest/src/test/windowmanagerstresstest/MainActivity.java
index d5987a5373b4..85646987940f 100644
--- a/tests/WindowManagerStressTest/src/test/windowmanagerstresstest/MainActivity.java
+++ b/tests/WindowManagerStressTest/src/test/windowmanagerstresstest/MainActivity.java
@@ -28,6 +28,7 @@ import android.view.DisplayCutout;
import android.view.IWindowSession;
import android.view.InsetsState;
import android.view.Surface;
+import android.view.SurfaceControl;
import android.view.View;
import android.view.WindowManager;
import android.view.WindowManager.LayoutParams;
@@ -106,7 +107,7 @@ public class MainActivity extends Activity {
window.mSeq, mLayoutParams, -1, -1, View.VISIBLE, 0, -1, mTmpRect,
mTmpRect, mTmpRect, mTmpRect, mTmpRect, mTmpRect, mTmpRect,
new DisplayCutout.ParcelableWrapper(), new MergedConfiguration(),
- new Surface(), new InsetsState());
+ new SurfaceControl(), new InsetsState());
} catch (RemoteException e) {
e.printStackTrace();
}
diff --git a/tests/net/java/android/net/dhcp/DhcpLeaseRepositoryTest.java b/tests/net/java/android/net/dhcp/DhcpLeaseRepositoryTest.java
index 7f8e7b5456c2..ba0448c98387 100644
--- a/tests/net/java/android/net/dhcp/DhcpLeaseRepositoryTest.java
+++ b/tests/net/java/android/net/dhcp/DhcpLeaseRepositoryTest.java
@@ -35,8 +35,8 @@ import android.annotation.NonNull;
import android.annotation.Nullable;
import android.net.IpPrefix;
import android.net.MacAddress;
-import android.net.util.SharedLog;
import android.net.dhcp.DhcpServer.Clock;
+import android.net.util.SharedLog;
import android.support.test.filters.SmallTest;
import android.support.test.runner.AndroidJUnit4;
@@ -126,7 +126,7 @@ public class DhcpLeaseRepositoryTest {
mRepo.updateParams(new IpPrefix(TEST_SERVER_ADDR, 28), TEST_EXCL_SET, TEST_LEASE_TIME_MS);
// /28 should have 16 addresses, 14 w/o the first/last, 11 w/o excluded addresses
- requestAddresses((byte)11);
+ requestAddresses((byte) 11);
try {
mRepo.getOffer(null, TEST_MAC_2,
diff --git a/tests/net/java/android/net/dhcp/DhcpServingParamsParcelExtTest.java b/tests/net/java/android/net/dhcp/DhcpServingParamsParcelExtTest.java
new file mode 100644
index 000000000000..4a6f20a043bb
--- /dev/null
+++ b/tests/net/java/android/net/dhcp/DhcpServingParamsParcelExtTest.java
@@ -0,0 +1,113 @@
+/*
+ * 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 android.net.dhcp;
+
+import static android.net.InetAddresses.parseNumericAddress;
+
+import static com.google.android.collect.Sets.newHashSet;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertTrue;
+
+import android.net.LinkAddress;
+import android.support.test.filters.SmallTest;
+import android.support.test.runner.AndroidJUnit4;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+import java.net.Inet4Address;
+import java.util.Set;
+import java.util.stream.Collectors;
+import java.util.stream.IntStream;
+
+@RunWith(AndroidJUnit4.class)
+@SmallTest
+public class DhcpServingParamsParcelExtTest {
+ private static final Inet4Address TEST_ADDRESS = inet4Addr("192.168.0.123");
+ private static final int TEST_ADDRESS_PARCELED = 0xc0a8007b;
+ private static final int TEST_PREFIX_LENGTH = 17;
+ private static final int TEST_LEASE_TIME_SECS = 120;
+ private static final int TEST_MTU = 1000;
+ private static final Set<Inet4Address> TEST_ADDRESS_SET =
+ newHashSet(inet4Addr("192.168.1.123"), inet4Addr("192.168.1.124"));
+ private static final Set<Integer> TEST_ADDRESS_SET_PARCELED =
+ newHashSet(0xc0a8017b, 0xc0a8017c);
+
+ private DhcpServingParamsParcelExt mParcel;
+
+ @Before
+ public void setUp() {
+ mParcel = new DhcpServingParamsParcelExt();
+ }
+
+ @Test
+ public void testSetServerAddr() {
+ mParcel.setServerAddr(new LinkAddress(TEST_ADDRESS, TEST_PREFIX_LENGTH));
+
+ assertEquals(TEST_ADDRESS_PARCELED, mParcel.serverAddr);
+ assertEquals(TEST_PREFIX_LENGTH, mParcel.serverAddrPrefixLength);
+ }
+
+ @Test
+ public void testSetDefaultRouters() {
+ mParcel.setDefaultRouters(TEST_ADDRESS_SET);
+ assertEquals(TEST_ADDRESS_SET_PARCELED, asSet(mParcel.defaultRouters));
+ }
+
+ @Test
+ public void testSetDnsServers() {
+ mParcel.setDnsServers(TEST_ADDRESS_SET);
+ assertEquals(TEST_ADDRESS_SET_PARCELED, asSet(mParcel.dnsServers));
+ }
+
+ @Test
+ public void testSetExcludedAddrs() {
+ mParcel.setExcludedAddrs(TEST_ADDRESS_SET);
+ assertEquals(TEST_ADDRESS_SET_PARCELED, asSet(mParcel.excludedAddrs));
+ }
+
+ @Test
+ public void testSetDhcpLeaseTimeSecs() {
+ mParcel.setDhcpLeaseTimeSecs(TEST_LEASE_TIME_SECS);
+ assertEquals(TEST_LEASE_TIME_SECS, mParcel.dhcpLeaseTimeSecs);
+ }
+
+ @Test
+ public void testSetLinkMtu() {
+ mParcel.setLinkMtu(TEST_MTU);
+ assertEquals(TEST_MTU, mParcel.linkMtu);
+ }
+
+ @Test
+ public void testSetMetered() {
+ mParcel.setMetered(true);
+ assertTrue(mParcel.metered);
+ mParcel.setMetered(false);
+ assertFalse(mParcel.metered);
+ }
+
+ private static Inet4Address inet4Addr(String addr) {
+ return (Inet4Address) parseNumericAddress(addr);
+ }
+
+ private static Set<Integer> asSet(int[] ints) {
+ return IntStream.of(ints).boxed().collect(Collectors.toSet());
+ }
+}
diff --git a/tests/net/java/android/net/dhcp/DhcpServingParamsTest.java b/tests/net/java/android/net/dhcp/DhcpServingParamsTest.java
index b6a4073a64da..2ab224667b8a 100644
--- a/tests/net/java/android/net/dhcp/DhcpServingParamsTest.java
+++ b/tests/net/java/android/net/dhcp/DhcpServingParamsTest.java
@@ -16,6 +16,7 @@
package android.net.dhcp;
+import static android.net.NetworkUtils.inet4AddressToIntHTH;
import static android.net.dhcp.DhcpServingParams.MTU_UNSET;
import static junit.framework.Assert.assertEquals;
@@ -27,6 +28,7 @@ import static java.net.InetAddress.parseNumericAddress;
import android.annotation.NonNull;
import android.annotation.Nullable;
import android.net.LinkAddress;
+import android.net.NetworkUtils;
import android.net.dhcp.DhcpServingParams.InvalidParameterException;
import android.support.test.filters.SmallTest;
import android.support.test.runner.AndroidJUnit4;
@@ -35,8 +37,10 @@ import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
+import java.lang.reflect.Modifier;
import java.net.Inet4Address;
import java.util.Arrays;
+import java.util.Collection;
import java.util.HashSet;
import java.util.Set;
@@ -56,6 +60,7 @@ public class DhcpServingParamsTest {
private static final int TEST_MTU = 1500;
private static final Set<Inet4Address> TEST_EXCLUDED_ADDRS = new HashSet<>(
Arrays.asList(parseAddr("192.168.0.200"), parseAddr("192.168.0.201")));
+ private static final boolean TEST_METERED = true;
@Before
public void setUp() {
@@ -65,7 +70,8 @@ public class DhcpServingParamsTest {
.setDnsServers(TEST_DNS_SERVERS)
.setServerAddr(TEST_LINKADDR)
.setLinkMtu(TEST_MTU)
- .setExcludedAddrs(TEST_EXCLUDED_ADDRS);
+ .setExcludedAddrs(TEST_EXCLUDED_ADDRS)
+ .setMetered(TEST_METERED);
}
@Test
@@ -91,6 +97,7 @@ public class DhcpServingParamsTest {
assertEquals(TEST_DNS_SERVERS, params.dnsServers);
assertEquals(TEST_LINKADDR, params.serverAddr);
assertEquals(TEST_MTU, params.linkMtu);
+ assertEquals(TEST_METERED, params.metered);
assertContains(params.excludedAddrs, TEST_EXCLUDED_ADDRS);
assertContains(params.excludedAddrs, TEST_DEFAULT_ROUTERS);
@@ -159,6 +166,39 @@ public class DhcpServingParamsTest {
mBuilder.setDefaultRouters(parseAddr("192.168.254.254")).build();
}
+ @Test
+ public void testFromParcelableObject() throws InvalidParameterException {
+ final DhcpServingParams params = mBuilder.build();
+ final DhcpServingParamsParcel parcel = new DhcpServingParamsParcel();
+ parcel.defaultRouters = toIntArray(TEST_DEFAULT_ROUTERS);
+ parcel.dhcpLeaseTimeSecs = TEST_LEASE_TIME_SECS;
+ parcel.dnsServers = toIntArray(TEST_DNS_SERVERS);
+ parcel.serverAddr = inet4AddressToIntHTH(TEST_SERVER_ADDR);
+ parcel.serverAddrPrefixLength = TEST_LINKADDR.getPrefixLength();
+ parcel.linkMtu = TEST_MTU;
+ parcel.excludedAddrs = toIntArray(TEST_EXCLUDED_ADDRS);
+ parcel.metered = TEST_METERED;
+ final DhcpServingParams parceled = DhcpServingParams.fromParcelableObject(parcel);
+
+ assertEquals(params.defaultRouters, parceled.defaultRouters);
+ assertEquals(params.dhcpLeaseTimeSecs, parceled.dhcpLeaseTimeSecs);
+ assertEquals(params.dnsServers, parceled.dnsServers);
+ assertEquals(params.serverAddr, parceled.serverAddr);
+ assertEquals(params.linkMtu, parceled.linkMtu);
+ assertEquals(params.excludedAddrs, parceled.excludedAddrs);
+ assertEquals(params.metered, parceled.metered);
+
+ // Ensure that we do not miss any field if added in the future
+ final long numFields = Arrays.stream(DhcpServingParams.class.getDeclaredFields())
+ .filter(f -> !Modifier.isStatic(f.getModifiers()))
+ .count();
+ assertEquals(7, numFields);
+ }
+
+ private static int[] toIntArray(Collection<Inet4Address> addrs) {
+ return addrs.stream().mapToInt(NetworkUtils::inet4AddressToIntHTH).toArray();
+ }
+
private static <T> void assertContains(@NonNull Set<T> set, @NonNull Set<T> subset) {
for (final T elem : subset) {
assertContains(set, elem);
diff --git a/tests/net/java/android/net/ip/IpServerTest.java b/tests/net/java/android/net/ip/IpServerTest.java
index 2c675c68a076..017822896610 100644
--- a/tests/net/java/android/net/ip/IpServerTest.java
+++ b/tests/net/java/android/net/ip/IpServerTest.java
@@ -16,6 +16,16 @@
package android.net.ip;
+import static android.net.ConnectivityManager.TETHERING_BLUETOOTH;
+import static android.net.ConnectivityManager.TETHERING_USB;
+import static android.net.ConnectivityManager.TETHERING_WIFI;
+import static android.net.ConnectivityManager.TETHER_ERROR_ENABLE_NAT_ERROR;
+import static android.net.ConnectivityManager.TETHER_ERROR_NO_ERROR;
+import static android.net.ConnectivityManager.TETHER_ERROR_TETHER_IFACE_ERROR;
+import static android.net.ip.IpServer.STATE_AVAILABLE;
+import static android.net.ip.IpServer.STATE_TETHERED;
+import static android.net.ip.IpServer.STATE_UNAVAILABLE;
+
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertTrue;
@@ -31,16 +41,6 @@ import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.verifyNoMoreInteractions;
import static org.mockito.Mockito.when;
-import static android.net.ConnectivityManager.TETHER_ERROR_ENABLE_NAT_ERROR;
-import static android.net.ConnectivityManager.TETHER_ERROR_NO_ERROR;
-import static android.net.ConnectivityManager.TETHER_ERROR_TETHER_IFACE_ERROR;
-import static android.net.ConnectivityManager.TETHERING_BLUETOOTH;
-import static android.net.ConnectivityManager.TETHERING_USB;
-import static android.net.ConnectivityManager.TETHERING_WIFI;
-import static android.net.ip.IpServer.STATE_AVAILABLE;
-import static android.net.ip.IpServer.STATE_TETHERED;
-import static android.net.ip.IpServer.STATE_UNAVAILABLE;
-
import android.net.INetworkStatsService;
import android.net.InterfaceConfiguration;
import android.net.IpPrefix;
@@ -60,8 +60,6 @@ import android.support.test.filters.SmallTest;
import android.support.test.runner.AndroidJUnit4;
import android.text.TextUtils;
-import java.net.Inet4Address;
-
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
@@ -71,6 +69,8 @@ import org.mockito.InOrder;
import org.mockito.Mock;
import org.mockito.MockitoAnnotations;
+import java.net.Inet4Address;
+
@RunWith(AndroidJUnit4.class)
@SmallTest
public class IpServerTest {
diff --git a/wifi/java/android/net/wifi/IWifiManager.aidl b/wifi/java/android/net/wifi/IWifiManager.aidl
index 7b2f07d5cb68..fef0ed711b66 100644
--- a/wifi/java/android/net/wifi/IWifiManager.aidl
+++ b/wifi/java/android/net/wifi/IWifiManager.aidl
@@ -64,7 +64,7 @@ interface IWifiManager
Map getAllMatchingFqdnsForScanResults(in List<ScanResult> scanResult);
- List<OsuProvider> getMatchingOsuProviders(in List<ScanResult> scanResult);
+ Map getMatchingOsuProviders(in List<ScanResult> scanResult);
Map getMatchingPasspointConfigsForOsuProviders(in List<OsuProvider> osuProviders);
diff --git a/wifi/java/android/net/wifi/WifiInfo.java b/wifi/java/android/net/wifi/WifiInfo.java
index 7cdd16a6a4ed..af5ad512a424 100644
--- a/wifi/java/android/net/wifi/WifiInfo.java
+++ b/wifi/java/android/net/wifi/WifiInfo.java
@@ -114,6 +114,11 @@ public class WifiInfo implements Parcelable {
private boolean mTrusted;
/**
+ * OSU (Online Sign Up) AP for Passpoint R2.
+ */
+ private boolean mOsuAp;
+
+ /**
* Running total count of lost (not ACKed) transmitted unicast data packets.
* @hide
*/
@@ -190,6 +195,7 @@ public class WifiInfo implements Parcelable {
setFrequency(-1);
setMeteredHint(false);
setEphemeral(false);
+ setOsuAp(false);
txBad = 0;
txSuccess = 0;
rxSuccess = 0;
@@ -219,6 +225,7 @@ public class WifiInfo implements Parcelable {
mMeteredHint = source.mMeteredHint;
mEphemeral = source.mEphemeral;
mTrusted = source.mTrusted;
+ mOsuAp = source.mOsuAp;
txBad = source.txBad;
txRetries = source.txRetries;
txSuccess = source.txSuccess;
@@ -411,6 +418,15 @@ public class WifiInfo implements Parcelable {
return mTrusted;
}
+ /** {@hide} */
+ public void setOsuAp(boolean osuAp) {
+ mOsuAp = osuAp;
+ }
+
+ /** {@hide} */
+ public boolean isOsuAp() {
+ return mOsuAp;
+ }
/** @hide */
@UnsupportedAppUsage
@@ -565,6 +581,7 @@ public class WifiInfo implements Parcelable {
dest.writeLong(rxSuccess);
dest.writeDouble(rxSuccessRate);
mSupplicantState.writeToParcel(dest, flags);
+ dest.writeInt(mOsuAp ? 1 : 0);
}
/** Implement the Parcelable interface {@hide} */
@@ -600,6 +617,7 @@ public class WifiInfo implements Parcelable {
info.rxSuccess = in.readLong();
info.rxSuccessRate = in.readDouble();
info.mSupplicantState = SupplicantState.CREATOR.createFromParcel(in);
+ info.mOsuAp = in.readInt() != 0;
return info;
}
diff --git a/wifi/java/android/net/wifi/WifiManager.java b/wifi/java/android/net/wifi/WifiManager.java
index f2a3b42e1668..ad2ed81398c1 100644
--- a/wifi/java/android/net/wifi/WifiManager.java
+++ b/wifi/java/android/net/wifi/WifiManager.java
@@ -1234,12 +1234,13 @@ public class WifiManager {
* An empty list will be returned if no match is found.
*
* @param scanResults a list of ScanResult
- * @return A list of {@link OsuProvider} that does not contain duplicate entries.
+ * @return Map that consists {@link OsuProvider} and a list of matching {@link ScanResult}
* @throws UnsupportedOperationException if Passpoint is not enabled on the device.
* @hide
*/
@RequiresPermission(android.Manifest.permission.NETWORK_SETTINGS)
- public List<OsuProvider> getMatchingOsuProviders(List<ScanResult> scanResults) {
+ public Map<OsuProvider, List<ScanResult>> getMatchingOsuProviders(
+ List<ScanResult> scanResults) {
try {
return mService.getMatchingOsuProviders(scanResults);
} catch (RemoteException e) {
diff --git a/wifi/java/com/android/server/wifi/AbstractWifiService.java b/wifi/java/com/android/server/wifi/AbstractWifiService.java
index 23961080110e..3d328a117241 100644
--- a/wifi/java/com/android/server/wifi/AbstractWifiService.java
+++ b/wifi/java/com/android/server/wifi/AbstractWifiService.java
@@ -21,6 +21,7 @@ package com.android.server.wifi;
import android.content.pm.ParceledListSlice;
import android.net.DhcpInfo;
import android.net.Network;
+import android.net.wifi.IDppCallback;
import android.net.wifi.INetworkRequestMatchCallback;
import android.net.wifi.ISoftApCallback;
import android.net.wifi.ITrafficStateCallback;
@@ -35,6 +36,7 @@ import android.net.wifi.hotspot2.OsuProvider;
import android.net.wifi.hotspot2.PasspointConfiguration;
import android.os.IBinder;
import android.os.Messenger;
+import android.os.RemoteException;
import android.os.ResultReceiver;
import android.os.WorkSource;
@@ -124,7 +126,8 @@ public abstract class AbstractWifiService extends IWifiManager.Stub {
}
@Override
- public List<OsuProvider> getMatchingOsuProviders(List<ScanResult> scanResults) {
+ public Map<OsuProvider, List<ScanResult>> getMatchingOsuProviders(
+ List<ScanResult> scanResults) {
throw new UnsupportedOperationException();
}
@@ -470,4 +473,26 @@ public abstract class AbstractWifiService extends IWifiManager.Stub {
public String[] getFactoryMacAddresses() {
throw new UnsupportedOperationException();
}
+
+ @Override
+ public void setDeviceMobilityState(int state) {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public void startDppAsConfiguratorInitiator(IBinder binder, String enrolleeUri,
+ int selectedNetworkId, int netRole, IDppCallback callback) {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public void startDppAsEnrolleeInitiator(IBinder binder, String configuratorUri,
+ IDppCallback callback) {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public void stopDppSession() throws RemoteException {
+ throw new UnsupportedOperationException();
+ }
}
diff --git a/wifi/tests/src/android/net/wifi/WifiInfoTest.java b/wifi/tests/src/android/net/wifi/WifiInfoTest.java
index fb0af5fbcce3..677bf371c781 100644
--- a/wifi/tests/src/android/net/wifi/WifiInfoTest.java
+++ b/wifi/tests/src/android/net/wifi/WifiInfoTest.java
@@ -47,6 +47,7 @@ public class WifiInfoTest {
writeWifiInfo.txBad = TEST_TX_BAD;
writeWifiInfo.rxSuccess = TEST_RX_SUCCESS;
writeWifiInfo.setTrusted(true);
+ writeWifiInfo.setOsuAp(true);
Parcel parcel = Parcel.obtain();
writeWifiInfo.writeToParcel(parcel, 0);
@@ -60,5 +61,6 @@ public class WifiInfoTest {
assertEquals(TEST_TX_BAD, readWifiInfo.txBad);
assertEquals(TEST_RX_SUCCESS, readWifiInfo.rxSuccess);
assertTrue(readWifiInfo.isTrusted());
+ assertTrue(readWifiInfo.isOsuAp());
}
}