summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--apex/Android.bp1
-rw-r--r--apex/appsearch/framework/api/current.txt71
-rw-r--r--apex/appsearch/framework/java/android/app/appsearch/AppSearchBatchResult.java5
-rw-r--r--apex/appsearch/framework/java/android/app/appsearch/AppSearchResult.java8
-rw-r--r--apex/appsearch/framework/java/android/app/appsearch/GetByUriRequest.java3
-rw-r--r--apex/appsearch/framework/java/android/app/appsearch/PutDocumentsRequest.java5
-rw-r--r--apex/appsearch/framework/java/android/app/appsearch/RemoveByUriRequest.java3
-rw-r--r--apex/appsearch/framework/java/android/app/appsearch/SetSchemaRequest.java9
-rw-r--r--apex/statsd/framework/Android.bp6
-rw-r--r--core/api/current.txt14
-rw-r--r--core/api/system-current.txt7
-rw-r--r--core/api/test-current.txt4
-rw-r--r--core/java/android/accessibilityservice/AccessibilityService.java22
-rw-r--r--core/java/android/accessibilityservice/IAccessibilityServiceConnection.aidl2
-rw-r--r--core/java/android/app/ActivityManager.java39
-rw-r--r--core/java/android/app/ActivityThread.java38
-rw-r--r--core/java/android/app/ApplicationPackageManager.java15
-rw-r--r--core/java/android/app/LoadedApk.java2
-rw-r--r--core/java/android/app/Notification.java4
-rw-r--r--core/java/android/app/NotificationChannel.java81
-rw-r--r--core/java/android/app/NotificationChannelGroup.java20
-rw-r--r--core/java/android/app/ResourcesManager.java2
-rw-r--r--core/java/android/app/admin/DeviceAdminInfo.java12
-rw-r--r--core/java/android/app/admin/DevicePolicyManager.java157
-rw-r--r--core/java/android/app/admin/FactoryResetProtectionPolicy.java16
-rw-r--r--core/java/android/app/admin/SystemUpdateInfo.java30
-rw-r--r--core/java/android/app/admin/SystemUpdatePolicy.java59
-rw-r--r--core/java/android/app/role/IRoleManager.aidl6
-rw-r--r--core/java/android/app/role/RoleManager.java56
-rw-r--r--core/java/android/appwidget/AppWidgetProviderInfo.java3
-rw-r--r--core/java/android/content/SyncAdaptersCache.java8
-rw-r--r--core/java/android/content/pm/IPackageInstallerSession.aidl1
-rw-r--r--core/java/android/content/pm/IntentFilterVerificationInfo.java29
-rw-r--r--core/java/android/content/pm/PackageInstaller.java25
-rw-r--r--core/java/android/content/pm/PackageUserState.java6
-rw-r--r--core/java/android/content/pm/RegisteredServicesCache.java20
-rw-r--r--core/java/android/content/pm/SuspendDialogInfo.java35
-rw-r--r--core/java/android/content/pm/XmlSerializerAndParser.java16
-rw-r--r--core/java/android/hardware/display/BrightnessConfiguration.java59
-rw-r--r--core/java/android/hardware/display/BrightnessCorrection.java27
-rw-r--r--core/java/android/net/Ikev2VpnProfile.java15
-rw-r--r--core/java/android/net/IpSecTransform.java104
-rw-r--r--core/java/android/net/LinkProperties.java3
-rw-r--r--core/java/android/net/NetworkIdentity.java15
-rw-r--r--core/java/android/os/Debug.java8
-rw-r--r--core/java/android/permission/IPermissionManager.aidl4
-rw-r--r--core/java/android/permission/PermissionManagerInternal.java31
-rw-r--r--core/java/android/service/notification/NotificationListenerService.java15
-rw-r--r--core/java/android/service/notification/ZenModeConfig.java96
-rw-r--r--core/java/android/util/Xml.java45
-rw-r--r--core/java/android/uwb/AdapterStateListener.java149
-rw-r--r--core/java/android/uwb/IUwbAdapter.aidl11
-rw-r--r--core/java/android/uwb/StateChangeReason.aidl5
-rw-r--r--core/java/android/uwb/UwbManager.java91
-rw-r--r--core/java/android/view/IPinnedStackController.aidl32
-rw-r--r--core/java/android/view/IPinnedStackListener.aidl7
-rw-r--r--core/java/android/view/IWindowManager.aidl21
-rw-r--r--core/java/android/view/ViewRootImpl.java9
-rw-r--r--core/java/android/view/accessibility/AccessibilityManager.java89
-rw-r--r--core/java/android/view/accessibility/IAccessibilityManager.aidl4
-rw-r--r--core/java/android/view/accessibility/IAccessibilityManagerClient.aidl2
-rw-r--r--core/java/com/android/internal/os/BatteryStatsImpl.java47
-rw-r--r--core/java/com/android/internal/util/BinaryXmlSerializer.java2
-rw-r--r--core/java/com/android/internal/util/XmlUtils.java15
-rw-r--r--core/java/com/android/server/BootReceiver.java16
-rw-r--r--core/jni/android_os_Debug.cpp3
-rw-r--r--core/res/res/drawable/view_accessibility_focused.xml4
-rw-r--r--core/res/res/layout/notification_top_line_views.xml2
-rw-r--r--core/res/res/values/colors.xml2
-rw-r--r--core/res/res/values/config.xml27
-rw-r--r--core/res/res/values/dimens.xml3
-rw-r--r--core/res/res/values/symbols.xml7
-rw-r--r--core/tests/coretests/src/android/content/pm/RegisteredServicesCacheTest.java8
-rw-r--r--core/tests/coretests/src/android/hardware/display/BrightnessConfigurationTest.java10
-rw-r--r--core/tests/coretests/src/android/util/BinaryXmlTest.java61
-rw-r--r--core/tests/coretests/src/android/util/XmlTest.java4
-rw-r--r--core/tests/coretests/src/android/view/accessibility/AccessibilityManagerTest.java25
-rw-r--r--core/tests/coretests/src/android/view/accessibility/AccessibilityServiceConnectionImpl.java2
-rw-r--r--core/tests/coretests/src/com/android/internal/accessibility/AccessibilityShortcutControllerTest.java4
-rw-r--r--core/tests/uwbtests/Android.bp1
-rw-r--r--core/tests/uwbtests/src/android/uwb/AdapterStateListenerTest.java311
-rw-r--r--data/etc/services.core.protolog.json36
-rw-r--r--errorprone/refaster/EfficientXml.java24
-rw-r--r--errorprone/refaster/EfficientXml.java.refasterbin36469 -> 38713 bytes
-rw-r--r--graphics/java/android/graphics/fonts/SystemFonts.java32
-rw-r--r--libs/WindowManager/Shell/res/layout/split_divider.xml4
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/apppairs/AppPair.java91
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/apppairs/AppPairLayout.java211
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/apppairs/DividerView.java56
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/common/split/DividerView.java171
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/common/split/SplitLayout.java205
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/common/split/SplitWindowManager.java115
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/pip/PinnedStackListenerForwarder.java16
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/pip/phone/PipController.java6
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/pip/phone/PipMenuView.java2
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/pip/phone/PipTouchHandler.java25
-rw-r--r--libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/CommonAssertions.kt114
-rw-r--r--libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/apppairs/AppPairsTest.kt8
-rw-r--r--libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/EnterExitPipTest.kt8
-rw-r--r--libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/PipOrientationTest.kt8
-rw-r--r--libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/PipRotationTest.kt14
-rw-r--r--libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/PipSplitScreenTest.kt8
-rw-r--r--libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/splitscreen/EnterSplitScreenTest.kt8
-rw-r--r--libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/splitscreen/ExitSplitScreenTest.kt4
-rw-r--r--libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/apppairs/AppPairLayoutTests.java89
-rw-r--r--libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/apppairs/AppPairTests.java6
-rw-r--r--libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/apppairs/AppPairsControllerTests.java6
-rw-r--r--libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/apppairs/AppPairsPoolTests.java7
-rw-r--r--libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/common/split/SplitLayoutTests.java106
-rw-r--r--libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/common/split/SplitWindowManagerTests.java66
-rw-r--r--location/java/android/location/LocationManager.java13
-rw-r--r--media/java/android/media/AudioSystem.java3
-rw-r--r--media/java/android/media/tv/tuner/Tuner.java43
-rw-r--r--media/java/android/media/tv/tuner/frontend/FrontendStatus.java109
-rw-r--r--native/android/Android.bp5
-rw-r--r--native/android/activity_manager.cpp226
-rw-r--r--native/android/include_platform/android/activity_manager.h176
-rw-r--r--native/android/libandroid.map.txt4
-rw-r--r--native/android/tests/activitymanager/UidImportanceHelperApps/Android.bp11
-rw-r--r--native/android/tests/activitymanager/UidImportanceHelperApps/HelperAppManifest.xml33
-rw-r--r--native/android/tests/activitymanager/UidImportanceHelperApps/src/com/android/tests/UidImportanceHelper/MainActivity.java107
-rw-r--r--native/android/tests/activitymanager/nativeTests/Android.bp39
-rw-r--r--native/android/tests/activitymanager/nativeTests/AndroidTest.xml53
-rw-r--r--native/android/tests/activitymanager/nativeTests/src/ActivityManagerNativeTest.cpp139
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/NotificationLockscreenUserManagerImpl.java5
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/KeyguardCoordinator.java2
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/notification/row/wrapper/NotificationHeaderViewWrapper.java5
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardBouncer.java19
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/phone/LockscreenLockIconController.java46
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBar.java8
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarKeyguardViewManager.java5
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/policy/RemoteInputView.java70
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/accessibility/MagnificationModeSwitchTest.java171
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/statusbar/RankingBuilder.java2
-rw-r--r--services/accessibility/java/com/android/server/accessibility/AbstractAccessibilityServiceConnection.java3
-rw-r--r--services/accessibility/java/com/android/server/accessibility/AccessibilityManagerService.java39
-rw-r--r--services/accessibility/java/com/android/server/accessibility/AccessibilityServiceConnection.java32
-rw-r--r--services/accessibility/java/com/android/server/accessibility/AccessibilityUserState.java53
-rw-r--r--services/appwidget/java/com/android/server/appwidget/AppWidgetServiceImpl.java162
-rw-r--r--services/art-profile54
-rw-r--r--services/core/java/com/android/server/ConnectivityService.java6
-rw-r--r--services/core/java/com/android/server/PackageWatchdog.java102
-rw-r--r--services/core/java/com/android/server/SensorPrivacyService.java2
-rw-r--r--services/core/java/com/android/server/accounts/AccountAuthenticatorCache.java8
-rw-r--r--services/core/java/com/android/server/adb/AdbDebuggingManager.java25
-rw-r--r--services/core/java/com/android/server/am/ActivityManagerService.java57
-rw-r--r--services/core/java/com/android/server/audio/AudioService.java1
-rw-r--r--services/core/java/com/android/server/biometrics/BiometricService.java12
-rw-r--r--services/core/java/com/android/server/biometrics/sensors/face/FaceService.java31
-rw-r--r--services/core/java/com/android/server/biometrics/sensors/face/FaceUtils.java8
-rw-r--r--services/core/java/com/android/server/biometrics/sensors/face/hidl/BiometricTestSessionImpl.java3
-rw-r--r--services/core/java/com/android/server/biometrics/sensors/face/hidl/Face10.java17
-rw-r--r--services/core/java/com/android/server/biometrics/sensors/fingerprint/FingerprintService.java4
-rw-r--r--services/core/java/com/android/server/biometrics/sensors/fingerprint/FingerprintUtils.java6
-rw-r--r--services/core/java/com/android/server/biometrics/sensors/fingerprint/hidl/BiometricTestSessionImpl.java2
-rw-r--r--services/core/java/com/android/server/biometrics/sensors/fingerprint/hidl/Fingerprint21.java31
-rw-r--r--services/core/java/com/android/server/biometrics/sensors/fingerprint/hidl/Fingerprint21UdfpsMock.java6
-rw-r--r--services/core/java/com/android/server/content/SyncStorageEngine.java24
-rw-r--r--services/core/java/com/android/server/display/BrightnessTracker.java7
-rw-r--r--services/core/java/com/android/server/display/PersistentDataStore.java16
-rw-r--r--services/core/java/com/android/server/input/PersistentDataStore.java2
-rw-r--r--services/core/java/com/android/server/location/timezone/BinderLocationTimeZoneProvider.java2
-rw-r--r--services/core/java/com/android/server/location/timezone/LocationTimeZoneManagerService.java44
-rw-r--r--services/core/java/com/android/server/location/timezone/LocationTimeZoneProviderProxy.java12
-rw-r--r--services/core/java/com/android/server/location/timezone/RealLocationTimeZoneProviderProxy.java26
-rw-r--r--services/core/java/com/android/server/location/timezone/SimulatedLocationTimeZoneProviderProxy.java5
-rwxr-xr-xservices/core/java/com/android/server/notification/NotificationManagerService.java73
-rw-r--r--services/core/java/com/android/server/notification/PreferencesHelper.java110
-rw-r--r--services/core/java/com/android/server/notification/RankingConfig.java2
-rw-r--r--services/core/java/com/android/server/notification/SnoozeHelper.java4
-rw-r--r--services/core/java/com/android/server/notification/VisibilityExtractor.java49
-rw-r--r--services/core/java/com/android/server/notification/ZenModeHelper.java3
-rw-r--r--services/core/java/com/android/server/pm/DefaultAppProvider.java187
-rw-r--r--services/core/java/com/android/server/pm/PackageAbiHelper.java2
-rw-r--r--services/core/java/com/android/server/pm/PackageAbiHelperImpl.java6
-rw-r--r--services/core/java/com/android/server/pm/PackageInstallerSession.java26
-rw-r--r--services/core/java/com/android/server/pm/PackageManagerService.java723
-rw-r--r--services/core/java/com/android/server/pm/Settings.java84
-rw-r--r--services/core/java/com/android/server/pm/TEST_MAPPING8
-rw-r--r--services/core/java/com/android/server/pm/UserManagerService.java33
-rw-r--r--services/core/java/com/android/server/pm/UserRestrictionsUtils.java8
-rw-r--r--services/core/java/com/android/server/pm/permission/LegacyPermission.java10
-rw-r--r--services/core/java/com/android/server/pm/permission/PermissionManagerService.java279
-rw-r--r--services/core/java/com/android/server/pm/permission/PermissionManagerServiceInternal.java162
-rw-r--r--services/core/java/com/android/server/policy/DeviceStateProviderImpl.java35
-rw-r--r--services/core/java/com/android/server/role/RoleManagerService.java181
-rw-r--r--services/core/java/com/android/server/rollback/Rollback.java15
-rw-r--r--services/core/java/com/android/server/stats/pull/StatsPullAtomService.java27
-rw-r--r--services/core/java/com/android/server/stats/pull/SystemMemoryUtil.java77
-rw-r--r--services/core/java/com/android/server/timezonedetector/GeolocationTimeZoneSuggestion.java2
-rw-r--r--services/core/java/com/android/server/tv/PersistentDataStore.java13
-rw-r--r--services/core/java/com/android/server/tv/tunerresourcemanager/UseCasePriorityHints.java5
-rw-r--r--services/core/java/com/android/server/utils/quota/MultiRateLimiter.java183
-rw-r--r--services/core/java/com/android/server/wallpaper/WallpaperManagerService.java4
-rw-r--r--services/core/java/com/android/server/wm/AppWarnings.java14
-rw-r--r--services/core/java/com/android/server/wm/ConfigurationContainerListener.java2
-rw-r--r--services/core/java/com/android/server/wm/DisplayArea.java7
-rw-r--r--services/core/java/com/android/server/wm/DisplayAreaPolicy.java5
-rw-r--r--services/core/java/com/android/server/wm/DisplayAreaPolicyBuilder.java26
-rw-r--r--services/core/java/com/android/server/wm/DisplayContent.java54
-rw-r--r--services/core/java/com/android/server/wm/DisplayWindowSettingsProvider.java28
-rw-r--r--services/core/java/com/android/server/wm/PinnedStackController.java16
-rw-r--r--services/core/java/com/android/server/wm/RootDisplayArea.java15
-rw-r--r--services/core/java/com/android/server/wm/TaskDisplayArea.java14
-rw-r--r--services/core/java/com/android/server/wm/WindowContainer.java25
-rw-r--r--services/core/java/com/android/server/wm/WindowContainerListener.java30
-rw-r--r--services/core/java/com/android/server/wm/WindowContextListenerController.java248
-rw-r--r--services/core/java/com/android/server/wm/WindowManagerService.java58
-rw-r--r--services/core/java/com/android/server/wm/WindowToken.java1
-rw-r--r--services/core/xsd/device-state-config/device-state-config.xsd2
-rw-r--r--services/core/xsd/device-state-config/schema/current.txt4
-rw-r--r--services/devicepolicy/java/com/android/server/devicepolicy/ActiveAdmin.java173
-rw-r--r--services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyData.java95
-rw-r--r--services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java25
-rw-r--r--services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerServiceShellCommand.java15
-rw-r--r--services/devicepolicy/java/com/android/server/devicepolicy/OneTimeSafetyChecker.java67
-rw-r--r--services/devicepolicy/java/com/android/server/devicepolicy/Owners.java53
-rw-r--r--services/devicepolicy/java/com/android/server/devicepolicy/TransferOwnershipMetadataManager.java7
-rw-r--r--services/tests/mockingservicestests/Android.bp20
-rw-r--r--services/tests/mockingservicestests/src/com/android/server/pm/MockSystem.kt662
-rw-r--r--services/tests/mockingservicestests/src/com/android/server/pm/PackageManagerServiceBootTest.kt173
-rw-r--r--services/tests/mockingservicestests/src/com/android/server/utils/quota/MultiRateLimiterTest.java197
-rw-r--r--services/tests/mockingservicestests/utils-mockito/com/android/server/extendedtestutils/ExtendedMockitoUtils.kt41
-rw-r--r--services/tests/servicestests/Android.bp10
-rw-r--r--services/tests/servicestests/src/com/android/server/accessibility/AccessibilityManagerServiceTest.java6
-rw-r--r--services/tests/servicestests/src/com/android/server/accessibility/AccessibilityUserStateTest.java33
-rw-r--r--services/tests/servicestests/src/com/android/server/hdmi/HdmiCecMessageValidatorTest.java24
-rw-r--r--services/tests/servicestests/src/com/android/server/pm/PackageSettingBuilder.java18
-rw-r--r--services/tests/servicestests/src/com/android/server/pm/ScanTests.java3
-rw-r--r--services/tests/servicestests/src/com/android/server/policy/DeviceStateProviderImplTest.java15
-rw-r--r--services/tests/servicestests/utils-mockito/com/android/server/testutils/MockitoUtils.kt5
-rw-r--r--services/tests/uiservicestests/src/com/android/server/notification/BuzzBeepBlinkTest.java3
-rw-r--r--services/tests/uiservicestests/src/com/android/server/notification/NotificationListenerServiceTest.java9
-rwxr-xr-xservices/tests/uiservicestests/src/com/android/server/notification/NotificationManagerServiceTest.java69
-rw-r--r--services/tests/uiservicestests/src/com/android/server/notification/PreferencesHelperTest.java48
-rw-r--r--services/tests/uiservicestests/src/com/android/server/notification/RoleObserverTest.java4
-rw-r--r--services/tests/uiservicestests/src/com/android/server/notification/VisibilityExtractorTest.java246
-rw-r--r--services/tests/wmtests/src/com/android/server/wm/DisplayAreaGroupTest.java2
-rw-r--r--services/tests/wmtests/src/com/android/server/wm/DisplayAreaPolicyBuilderTest.java12
-rw-r--r--services/tests/wmtests/src/com/android/server/wm/DisplayAreaTest.java24
-rw-r--r--services/tests/wmtests/src/com/android/server/wm/DualDisplayAreaGroupPolicyTest.java14
-rw-r--r--services/tests/wmtests/src/com/android/server/wm/SystemServicesTestRule.java2
-rw-r--r--services/tests/wmtests/src/com/android/server/wm/TaskDisplayAreaTests.java42
-rw-r--r--services/tests/wmtests/src/com/android/server/wm/TestDisplayContent.java2
-rw-r--r--services/tests/wmtests/src/com/android/server/wm/WindowContainerTests.java45
-rw-r--r--services/tests/wmtests/src/com/android/server/wm/WindowContextListenerControllerTests.java173
-rw-r--r--services/tests/wmtests/src/com/android/server/wm/WindowTokenTests.java6
-rw-r--r--startop/iorap/src/com/google/android/startop/iorap/IorapForwardingService.java178
-rw-r--r--startop/iorap/src/com/google/android/startop/iorap/JobScheduledEvent.java30
-rw-r--r--telecomm/java/android/telecom/TelecomManager.java61
-rw-r--r--telephony/java/android/telephony/CellInfo.java52
-rw-r--r--telephony/java/android/telephony/CellInfoCdma.java9
-rw-r--r--telephony/java/android/telephony/CellInfoGsm.java8
-rw-r--r--telephony/java/android/telephony/CellInfoLte.java9
-rw-r--r--telephony/java/android/telephony/CellInfoNr.java8
-rw-r--r--telephony/java/android/telephony/CellInfoTdscdma.java8
-rw-r--r--telephony/java/android/telephony/CellInfoWcdma.java8
-rw-r--r--telephony/java/android/telephony/CellSignalStrengthLte.java63
-rw-r--r--telephony/java/android/telephony/CellSignalStrengthNr.java106
-rw-r--r--telephony/java/android/telephony/SignalStrength.java15
-rw-r--r--telephony/java/android/telephony/TelephonyManager.java49
-rw-r--r--telephony/java/android/telephony/ims/stub/ImsConfigImplBase.java2
-rw-r--r--tests/FlickerTests/src/com/android/server/wm/flicker/rotation/ChangeAppRotationTest.kt2
-rw-r--r--tests/PackageWatchdog/src/com/android/server/PackageWatchdogTest.java77
-rw-r--r--tests/StagedInstallTest/TEST_MAPPING2
-rw-r--r--wifi/TEST_MAPPING5
-rw-r--r--wifi/api/current.txt2
-rw-r--r--wifi/java/android/net/wifi/SoftApConfiguration.java6
-rw-r--r--wifi/java/android/net/wifi/WifiManager.java40
-rw-r--r--wifi/java/android/net/wifi/WifiNetworkSuggestion.java3
-rw-r--r--wifi/java/android/net/wifi/hotspot2/PasspointConfiguration.java88
-rw-r--r--wifi/tests/src/android/net/wifi/WifiNetworkSuggestionTest.java23
272 files changed, 8761 insertions, 3074 deletions
diff --git a/apex/Android.bp b/apex/Android.bp
index 0a535a8fe9b9..4e80acb64e05 100644
--- a/apex/Android.bp
+++ b/apex/Android.bp
@@ -15,6 +15,7 @@
mainline_stubs_args =
"--error UnhiddenSystemApi " +
"--hide BroadcastBehavior " +
+ "--hide CallbackInterface " +
"--hide DeprecationMismatch " +
"--hide HiddenSuperclass " +
"--hide HiddenTypedefConstant " +
diff --git a/apex/appsearch/framework/api/current.txt b/apex/appsearch/framework/api/current.txt
index 2be873cc8bca..380c64679fab 100644
--- a/apex/appsearch/framework/api/current.txt
+++ b/apex/appsearch/framework/api/current.txt
@@ -1,6 +1,27 @@
// Signature format: 2.0
package android.app.appsearch {
+ public final class AppSearchBatchResult<KeyType, ValueType> {
+ method @NonNull public java.util.Map<KeyType,android.app.appsearch.AppSearchResult<ValueType>> getFailures();
+ method @NonNull public java.util.Map<KeyType,ValueType> getSuccesses();
+ method public boolean isSuccess();
+ }
+
+ public final class AppSearchResult<ValueType> {
+ method @Nullable public String getErrorMessage();
+ method public int getResultCode();
+ method @Nullable public ValueType getResultValue();
+ method public boolean isSuccess();
+ field public static final int RESULT_INTERNAL_ERROR = 2; // 0x2
+ field public static final int RESULT_INVALID_ARGUMENT = 3; // 0x3
+ field public static final int RESULT_INVALID_SCHEMA = 7; // 0x7
+ field public static final int RESULT_IO_ERROR = 4; // 0x4
+ field public static final int RESULT_NOT_FOUND = 6; // 0x6
+ field public static final int RESULT_OK = 0; // 0x0
+ field public static final int RESULT_OUT_OF_SPACE = 5; // 0x5
+ field public static final int RESULT_UNKNOWN_ERROR = 1; // 0x1
+ }
+
public final class AppSearchSchema {
method @NonNull public java.util.List<android.app.appsearch.AppSearchSchema.PropertyConfig> getProperties();
method @NonNull public String getSchemaType();
@@ -85,6 +106,43 @@ package android.app.appsearch {
method @NonNull public BuilderType setTtlMillis(long);
}
+ public final class GetByUriRequest {
+ method @NonNull public String getNamespace();
+ method @NonNull public java.util.Set<java.lang.String> getUris();
+ }
+
+ public static final class GetByUriRequest.Builder {
+ ctor public GetByUriRequest.Builder();
+ method @NonNull public android.app.appsearch.GetByUriRequest.Builder addUri(@NonNull java.lang.String...);
+ method @NonNull public android.app.appsearch.GetByUriRequest.Builder addUri(@NonNull java.util.Collection<java.lang.String>);
+ method @NonNull public android.app.appsearch.GetByUriRequest build();
+ method @NonNull public android.app.appsearch.GetByUriRequest.Builder setNamespace(@NonNull String);
+ }
+
+ public final class PutDocumentsRequest {
+ method @NonNull public java.util.List<android.app.appsearch.GenericDocument> getDocuments();
+ }
+
+ public static final class PutDocumentsRequest.Builder {
+ ctor public PutDocumentsRequest.Builder();
+ method @NonNull public android.app.appsearch.PutDocumentsRequest.Builder addGenericDocument(@NonNull android.app.appsearch.GenericDocument...);
+ method @NonNull public android.app.appsearch.PutDocumentsRequest.Builder addGenericDocument(@NonNull java.util.Collection<android.app.appsearch.GenericDocument>);
+ method @NonNull public android.app.appsearch.PutDocumentsRequest build();
+ }
+
+ public final class RemoveByUriRequest {
+ method @NonNull public String getNamespace();
+ method @NonNull public java.util.Set<java.lang.String> getUris();
+ }
+
+ public static final class RemoveByUriRequest.Builder {
+ ctor public RemoveByUriRequest.Builder();
+ method @NonNull public android.app.appsearch.RemoveByUriRequest.Builder addUri(@NonNull java.lang.String...);
+ method @NonNull public android.app.appsearch.RemoveByUriRequest.Builder addUri(@NonNull java.util.Collection<java.lang.String>);
+ method @NonNull public android.app.appsearch.RemoveByUriRequest build();
+ method @NonNull public android.app.appsearch.RemoveByUriRequest.Builder setNamespace(@NonNull String);
+ }
+
public final class SearchResult {
method @NonNull public android.app.appsearch.GenericDocument getDocument();
method @NonNull public java.util.List<android.app.appsearch.SearchResult.MatchInfo> getMatches();
@@ -139,5 +197,18 @@ package android.app.appsearch {
method @NonNull public android.app.appsearch.SearchSpec.Builder setTermMatch(int);
}
+ public final class SetSchemaRequest {
+ method @NonNull public java.util.Set<android.app.appsearch.AppSearchSchema> getSchemas();
+ method public boolean isForceOverride();
+ }
+
+ public static final class SetSchemaRequest.Builder {
+ ctor public SetSchemaRequest.Builder();
+ method @NonNull public android.app.appsearch.SetSchemaRequest.Builder addSchema(@NonNull android.app.appsearch.AppSearchSchema...);
+ method @NonNull public android.app.appsearch.SetSchemaRequest.Builder addSchema(@NonNull java.util.Collection<android.app.appsearch.AppSearchSchema>);
+ method @NonNull public android.app.appsearch.SetSchemaRequest build();
+ method @NonNull public android.app.appsearch.SetSchemaRequest.Builder setForceOverride(boolean);
+ }
+
}
diff --git a/apex/appsearch/framework/java/android/app/appsearch/AppSearchBatchResult.java b/apex/appsearch/framework/java/android/app/appsearch/AppSearchBatchResult.java
index 98daa66183a3..97cfe36fca80 100644
--- a/apex/appsearch/framework/java/android/app/appsearch/AppSearchBatchResult.java
+++ b/apex/appsearch/framework/java/android/app/appsearch/AppSearchBatchResult.java
@@ -33,7 +33,6 @@ import java.util.Map;
*
* @param <KeyType> The type of the keys for {@link #getSuccesses} and {@link #getFailures}.
* @param <ValueType> The type of result objects associated with the keys.
- * @hide
*/
public final class AppSearchBatchResult<KeyType, ValueType> implements Parcelable {
@NonNull private final Map<KeyType, ValueType> mSuccesses;
@@ -51,6 +50,7 @@ public final class AppSearchBatchResult<KeyType, ValueType> implements Parcelabl
mFailures = Collections.unmodifiableMap(in.readHashMap(/*loader=*/ null));
}
+ /** @hide */
@Override
public void writeToParcel(@NonNull Parcel dest, int flags) {
dest.writeMap(mSuccesses);
@@ -100,11 +100,14 @@ public final class AppSearchBatchResult<KeyType, ValueType> implements Parcelabl
return "{\n successes: " + mSuccesses + "\n failures: " + mFailures + "\n}";
}
+ /** @hide */
@Override
public int describeContents() {
return 0;
}
+ /** @hide */
+ @NonNull
public static final Creator<AppSearchBatchResult> CREATOR =
new Creator<AppSearchBatchResult>() {
@NonNull
diff --git a/apex/appsearch/framework/java/android/app/appsearch/AppSearchResult.java b/apex/appsearch/framework/java/android/app/appsearch/AppSearchResult.java
index 6e2ed70cca01..76225e40c56e 100644
--- a/apex/appsearch/framework/java/android/app/appsearch/AppSearchResult.java
+++ b/apex/appsearch/framework/java/android/app/appsearch/AppSearchResult.java
@@ -32,7 +32,6 @@ import java.util.Objects;
* Information about the success or failure of an AppSearch call.
*
* @param <ValueType> The type of result object for successful calls.
- * @hide
*/
public final class AppSearchResult<ValueType> implements Parcelable {
/**
@@ -107,6 +106,7 @@ public final class AppSearchResult<ValueType> implements Parcelable {
mErrorMessage = in.readString();
}
+ /** @hide */
@Override
public void writeToParcel(@NonNull Parcel dest, int flags) {
dest.writeInt(mResultCode);
@@ -181,13 +181,15 @@ public final class AppSearchResult<ValueType> implements Parcelable {
return "[FAILURE(" + mResultCode + ")]: " + mErrorMessage;
}
+ /** @hide */
@Override
public int describeContents() {
return 0;
}
- public static final Creator<AppSearchResult> CREATOR =
- new Creator<AppSearchResult>() {
+ /** @hide */
+ @NonNull
+ public static final Creator<AppSearchResult> CREATOR = new Creator<AppSearchResult>() {
@NonNull
@Override
public AppSearchResult createFromParcel(@NonNull Parcel in) {
diff --git a/apex/appsearch/framework/java/android/app/appsearch/GetByUriRequest.java b/apex/appsearch/framework/java/android/app/appsearch/GetByUriRequest.java
index 053d401d06dc..b1cf50484306 100644
--- a/apex/appsearch/framework/java/android/app/appsearch/GetByUriRequest.java
+++ b/apex/appsearch/framework/java/android/app/appsearch/GetByUriRequest.java
@@ -29,8 +29,7 @@ import java.util.Set;
/**
* Encapsulates a request to retrieve documents by namespace and URI.
*
- * @see AppSearchSession#getByUri
- * @hide
+ * @see AppSearchManager#getByUri
*/
public final class GetByUriRequest {
private final String mNamespace;
diff --git a/apex/appsearch/framework/java/android/app/appsearch/PutDocumentsRequest.java b/apex/appsearch/framework/java/android/app/appsearch/PutDocumentsRequest.java
index 42f1ff2a716a..1e37277be55e 100644
--- a/apex/appsearch/framework/java/android/app/appsearch/PutDocumentsRequest.java
+++ b/apex/appsearch/framework/java/android/app/appsearch/PutDocumentsRequest.java
@@ -29,10 +29,9 @@ import java.util.Collections;
import java.util.List;
/**
- * Encapsulates a request to index a document into an {@link AppSearchSession} database.
+ * Encapsulates a request to index a document into an {@link AppSearchManager} database.
*
- * @see AppSearchSession#putDocuments
- * @hide
+ * @see AppSearchManager#putDocuments
*/
public final class PutDocumentsRequest {
private final List<GenericDocument> mDocuments;
diff --git a/apex/appsearch/framework/java/android/app/appsearch/RemoveByUriRequest.java b/apex/appsearch/framework/java/android/app/appsearch/RemoveByUriRequest.java
index 3d83c390fbad..1c17547574a6 100644
--- a/apex/appsearch/framework/java/android/app/appsearch/RemoveByUriRequest.java
+++ b/apex/appsearch/framework/java/android/app/appsearch/RemoveByUriRequest.java
@@ -29,8 +29,7 @@ import java.util.Set;
/**
* Encapsulates a request to remove documents by namespace and URI.
*
- * @see AppSearchSession#removeByUri
- * @hide
+ * @see AppSearchManager#removeByUri
*/
public final class RemoveByUriRequest {
private final String mNamespace;
diff --git a/apex/appsearch/framework/java/android/app/appsearch/SetSchemaRequest.java b/apex/appsearch/framework/java/android/app/appsearch/SetSchemaRequest.java
index 3e472fd01939..081fb7202c2d 100644
--- a/apex/appsearch/framework/java/android/app/appsearch/SetSchemaRequest.java
+++ b/apex/appsearch/framework/java/android/app/appsearch/SetSchemaRequest.java
@@ -30,10 +30,9 @@ import java.util.List;
import java.util.Set;
/**
- * Encapsulates a request to update the schema of an {@link AppSearchSession} database.
+ * Encapsulates a request to update the schema of an {@link AppSearchManager} database.
*
- * @see AppSearchSession#setSchema
- * @hide
+ * @see AppSearchManager#setSchema
*/
public final class SetSchemaRequest {
private final Set<AppSearchSchema> mSchemas;
@@ -82,9 +81,9 @@ public final class SetSchemaRequest {
* follow the new schema.
*
* <p>By default, this is {@code false} and schema incompatibility causes the {@link
- * AppSearchSession#setSchema} call to fail.
+ * AppSearchManager#setSchema} call to fail.
*
- * @see AppSearchSession#setSchema
+ * @see AppSearchManager#setSchema
*/
@NonNull
public Builder setForceOverride(boolean forceOverride) {
diff --git a/apex/statsd/framework/Android.bp b/apex/statsd/framework/Android.bp
index bf4323ddfb0b..e4299f52ff7d 100644
--- a/apex/statsd/framework/Android.bp
+++ b/apex/statsd/framework/Android.bp
@@ -45,6 +45,7 @@ filegroup {
visibility: [
"//frameworks/base", // For the "global" stubs.
"//frameworks/base/apex/statsd:__subpackages__",
+ "//packages/modules/StatsD/apex:__subpackages__",
],
}
java_sdk_library {
@@ -72,7 +73,10 @@ java_sdk_library {
hostdex: true, // for hiddenapi check
- impl_library_visibility: ["//frameworks/base/apex/statsd/framework/test:__subpackages__"],
+ impl_library_visibility: [
+ "//frameworks/base/apex/statsd/framework/test:__subpackages__",
+ "//packages/modules/StatsD/apex/framework/test:__subpackages__",
+ ],
apex_available: [
"com.android.os.statsd",
diff --git a/core/api/current.txt b/core/api/current.txt
index f748c24e9181..15e985cddef7 100644
--- a/core/api/current.txt
+++ b/core/api/current.txt
@@ -2883,6 +2883,7 @@ package android.accessibilityservice {
method protected void onServiceConnected();
method public void onSystemActionsChanged();
method public final boolean performGlobalAction(int);
+ method public void setAccessibilityFocusAppearance(int, @ColorInt int);
method public void setGestureDetectionPassthroughRegion(int, @NonNull android.graphics.Region);
method public final void setServiceInfo(android.accessibilityservice.AccessibilityServiceInfo);
method public void setTouchExplorationPassthroughRegion(int, @NonNull android.graphics.Region);
@@ -7150,6 +7151,7 @@ package android.app.admin {
field @RequiresPermission(android.Manifest.permission.REQUEST_PASSWORD_COMPLEXITY) public static final String EXTRA_PASSWORD_COMPLEXITY = "android.app.extra.PASSWORD_COMPLEXITY";
field public static final String EXTRA_PROVISIONING_ACCOUNT_TO_MIGRATE = "android.app.extra.PROVISIONING_ACCOUNT_TO_MIGRATE";
field public static final String EXTRA_PROVISIONING_ADMIN_EXTRAS_BUNDLE = "android.app.extra.PROVISIONING_ADMIN_EXTRAS_BUNDLE";
+ field public static final String EXTRA_PROVISIONING_ALLOWED_PROVISIONING_MODES = "android.app.extra.PROVISIONING_ALLOWED_PROVISIONING_MODES";
field public static final String EXTRA_PROVISIONING_DEVICE_ADMIN_COMPONENT_NAME = "android.app.extra.PROVISIONING_DEVICE_ADMIN_COMPONENT_NAME";
field public static final String EXTRA_PROVISIONING_DEVICE_ADMIN_MINIMUM_VERSION_CODE = "android.app.extra.PROVISIONING_DEVICE_ADMIN_MINIMUM_VERSION_CODE";
field public static final String EXTRA_PROVISIONING_DEVICE_ADMIN_PACKAGE_CHECKSUM = "android.app.extra.PROVISIONING_DEVICE_ADMIN_PACKAGE_CHECKSUM";
@@ -7254,6 +7256,7 @@ package android.app.admin {
field public static final int PRIVATE_DNS_SET_NO_ERROR = 0; // 0x0
field public static final int PROVISIONING_MODE_FULLY_MANAGED_DEVICE = 1; // 0x1
field public static final int PROVISIONING_MODE_MANAGED_PROFILE = 2; // 0x2
+ field public static final int PROVISIONING_MODE_MANAGED_PROFILE_ON_PERSONAL_DEVICE = 3; // 0x3
field public static final int RESET_PASSWORD_DO_NOT_ASK_CREDENTIALS_ON_BOOT = 2; // 0x2
field public static final int RESET_PASSWORD_REQUIRE_ENTRY = 1; // 0x1
field public static final int SKIP_SETUP_WIZARD = 1; // 0x1
@@ -42460,6 +42463,7 @@ package android.service.notification {
method public CharSequence getImportanceExplanation();
method public String getKey();
method public long getLastAudiblyAlertedMillis();
+ method public int getLockscreenVisibilityOverride();
method public String getOverrideGroupKey();
method public int getRank();
method @NonNull public java.util.List<android.app.Notification.Action> getSmartActions();
@@ -42473,6 +42477,7 @@ package android.service.notification {
field public static final int USER_SENTIMENT_NEGATIVE = -1; // 0xffffffff
field public static final int USER_SENTIMENT_NEUTRAL = 0; // 0x0
field public static final int USER_SENTIMENT_POSITIVE = 1; // 0x1
+ field public static final int VISIBILITY_NO_OVERRIDE = -1000; // 0xfffffc18
}
public static class NotificationListenerService.RankingMap implements android.os.Parcelable {
@@ -44860,14 +44865,19 @@ package android.telecom {
field public static final String EXTRA_DEFAULT_CALL_SCREENING_APP_COMPONENT_NAME = "android.telecom.extra.DEFAULT_CALL_SCREENING_APP_COMPONENT_NAME";
field public static final String EXTRA_DISCONNECT_CAUSE = "android.telecom.extra.DISCONNECT_CAUSE";
field public static final String EXTRA_HANDLE = "android.telecom.extra.HANDLE";
+ field public static final String EXTRA_HAS_PICTURE = "android.telecom.extra.HAS_PICTURE";
field public static final String EXTRA_INCOMING_CALL_ADDRESS = "android.telecom.extra.INCOMING_CALL_ADDRESS";
field public static final String EXTRA_INCOMING_CALL_EXTRAS = "android.telecom.extra.INCOMING_CALL_EXTRAS";
+ field public static final String EXTRA_INCOMING_PICTURE = "android.telecom.extra.INCOMING_PICTURE";
field public static final String EXTRA_INCOMING_VIDEO_STATE = "android.telecom.extra.INCOMING_VIDEO_STATE";
field public static final String EXTRA_IS_DEFAULT_CALL_SCREENING_APP = "android.telecom.extra.IS_DEFAULT_CALL_SCREENING_APP";
+ field public static final String EXTRA_LOCATION = "android.telecom.extra.LOCATION";
field public static final String EXTRA_NOTIFICATION_COUNT = "android.telecom.extra.NOTIFICATION_COUNT";
field public static final String EXTRA_NOTIFICATION_PHONE_NUMBER = "android.telecom.extra.NOTIFICATION_PHONE_NUMBER";
field public static final String EXTRA_OUTGOING_CALL_EXTRAS = "android.telecom.extra.OUTGOING_CALL_EXTRAS";
+ field public static final String EXTRA_OUTGOING_PICTURE = "android.telecom.extra.OUTGOING_PICTURE";
field public static final String EXTRA_PHONE_ACCOUNT_HANDLE = "android.telecom.extra.PHONE_ACCOUNT_HANDLE";
+ field public static final String EXTRA_PRIORITY = "android.telecom.extra.PRIORITY";
field public static final String EXTRA_START_CALL_WITH_RTT = "android.telecom.extra.START_CALL_WITH_RTT";
field public static final String EXTRA_START_CALL_WITH_SPEAKERPHONE = "android.telecom.extra.START_CALL_WITH_SPEAKERPHONE";
field public static final String EXTRA_START_CALL_WITH_VIDEO_STATE = "android.telecom.extra.START_CALL_WITH_VIDEO_STATE";
@@ -44883,6 +44893,8 @@ package android.telecom {
field public static final int PRESENTATION_PAYPHONE = 4; // 0x4
field public static final int PRESENTATION_RESTRICTED = 2; // 0x2
field public static final int PRESENTATION_UNKNOWN = 3; // 0x3
+ field public static final int PRIORITY_NORMAL = 0; // 0x0
+ field public static final int PRIORITY_URGENT = 1; // 0x1
}
public class VideoProfile implements android.os.Parcelable {
@@ -54611,6 +54623,8 @@ package android.view.accessibility {
method public void addAccessibilityStateChangeListener(@NonNull android.view.accessibility.AccessibilityManager.AccessibilityStateChangeListener, @Nullable android.os.Handler);
method public boolean addTouchExplorationStateChangeListener(@NonNull android.view.accessibility.AccessibilityManager.TouchExplorationStateChangeListener);
method public void addTouchExplorationStateChangeListener(@NonNull android.view.accessibility.AccessibilityManager.TouchExplorationStateChangeListener, @Nullable android.os.Handler);
+ method @ColorInt public int getAccessibilityFocusColor();
+ method public int getAccessibilityFocusStrokeWidth();
method @Deprecated public java.util.List<android.content.pm.ServiceInfo> getAccessibilityServiceList();
method public java.util.List<android.accessibilityservice.AccessibilityServiceInfo> getEnabledAccessibilityServiceList(int);
method public java.util.List<android.accessibilityservice.AccessibilityServiceInfo> getInstalledAccessibilityServiceList();
diff --git a/core/api/system-current.txt b/core/api/system-current.txt
index a49f71f6530c..3a769d5d5a71 100644
--- a/core/api/system-current.txt
+++ b/core/api/system-current.txt
@@ -878,11 +878,13 @@ package android.app.admin {
field public static final String EXTRA_PROVISIONING_DEVICE_ADMIN_PACKAGE_ICON_URI = "android.app.extra.PROVISIONING_DEVICE_ADMIN_PACKAGE_ICON_URI";
field public static final String EXTRA_PROVISIONING_DEVICE_ADMIN_PACKAGE_LABEL = "android.app.extra.PROVISIONING_DEVICE_ADMIN_PACKAGE_LABEL";
field public static final String EXTRA_PROVISIONING_ORGANIZATION_NAME = "android.app.extra.PROVISIONING_ORGANIZATION_NAME";
+ field public static final String EXTRA_PROVISIONING_SUPPORTED_MODES = "android.app.extra.PROVISIONING_SUPPORTED_MODES";
field public static final String EXTRA_PROVISIONING_SUPPORT_URL = "android.app.extra.PROVISIONING_SUPPORT_URL";
field public static final String EXTRA_PROVISIONING_TRIGGER = "android.app.extra.PROVISIONING_TRIGGER";
field public static final String EXTRA_RESTRICTION = "android.app.extra.RESTRICTION";
field public static final int PROVISIONING_TRIGGER_CLOUD_ENROLLMENT = 1; // 0x1
- field public static final int PROVISIONING_TRIGGER_PERSISTENT_DEVICE_OWNER = 3; // 0x3
+ field public static final int PROVISIONING_TRIGGER_MANAGED_ACCOUNT = 4; // 0x4
+ field @Deprecated public static final int PROVISIONING_TRIGGER_PERSISTENT_DEVICE_OWNER = 3; // 0x3
field public static final int PROVISIONING_TRIGGER_QR_CODE = 2; // 0x2
field public static final int PROVISIONING_TRIGGER_UNSPECIFIED = 0; // 0x0
field public static final int STATE_USER_PROFILE_COMPLETE = 4; // 0x4
@@ -891,6 +893,9 @@ package android.app.admin {
field public static final int STATE_USER_SETUP_FINALIZED = 3; // 0x3
field public static final int STATE_USER_SETUP_INCOMPLETE = 1; // 0x1
field public static final int STATE_USER_UNMANAGED = 0; // 0x0
+ field public static final int SUPPORTED_MODES_ORGANIZATION_AND_PERSONALLY_OWNED = 3; // 0x3
+ field public static final int SUPPORTED_MODES_ORGANIZATION_OWNED = 1; // 0x1
+ field public static final int SUPPORTED_MODES_PERSONALLY_OWNED = 2; // 0x2
}
public final class SystemUpdatePolicy implements android.os.Parcelable {
diff --git a/core/api/test-current.txt b/core/api/test-current.txt
index 51edd03515e1..80a160a67fdd 100644
--- a/core/api/test-current.txt
+++ b/core/api/test-current.txt
@@ -987,9 +987,9 @@ package android.media {
}
public class AudioSystem {
- method public static float getMasterBalance();
+ method @RequiresPermission(android.Manifest.permission.MODIFY_AUDIO_SETTINGS) public static float getMasterBalance();
method public static final int getNumStreamTypes();
- method public static int setMasterBalance(float);
+ method @RequiresPermission(android.Manifest.permission.MODIFY_AUDIO_SETTINGS) public static int setMasterBalance(float);
field public static final int DEVICE_ROLE_DISABLED = 2; // 0x2
field public static final int DEVICE_ROLE_NONE = 0; // 0x0
field public static final int DEVICE_ROLE_PREFERRED = 1; // 0x1
diff --git a/core/java/android/accessibilityservice/AccessibilityService.java b/core/java/android/accessibilityservice/AccessibilityService.java
index 0ad9e446dfc7..8e50184c96e0 100644
--- a/core/java/android/accessibilityservice/AccessibilityService.java
+++ b/core/java/android/accessibilityservice/AccessibilityService.java
@@ -18,6 +18,7 @@ package android.accessibilityservice;
import android.accessibilityservice.GestureDescription.MotionEventGenerator;
import android.annotation.CallbackExecutor;
+import android.annotation.ColorInt;
import android.annotation.IntDef;
import android.annotation.NonNull;
import android.annotation.Nullable;
@@ -2118,6 +2119,27 @@ public abstract class AccessibilityService extends Service {
}
/**
+ * Sets the strokeWidth and color of the accessibility focus rectangle.
+ *
+ * @param strokeWidth The stroke width of the rectangle in pixels.
+ * Setting this value to zero results in no focus rectangle being drawn.
+ * @param color The color of the rectangle.
+ */
+ public void setAccessibilityFocusAppearance(int strokeWidth, @ColorInt int color) {
+ IAccessibilityServiceConnection connection =
+ AccessibilityInteractionClient.getInstance().getConnection(mConnectionId);
+ if (connection != null) {
+ try {
+ connection.setFocusAppearance(strokeWidth, color);
+ } catch (RemoteException re) {
+ Log.w(LOG_TAG, "Error while setting the strokeWidth and color of the "
+ + "accessibility focus rectangle", re);
+ re.rethrowFromSystemServer();
+ }
+ }
+ }
+
+ /**
* Implement to return the implementation of the internal accessibility
* service interface.
*/
diff --git a/core/java/android/accessibilityservice/IAccessibilityServiceConnection.aidl b/core/java/android/accessibilityservice/IAccessibilityServiceConnection.aidl
index 0b3b9b2ecae1..ab21dc9f14ad 100644
--- a/core/java/android/accessibilityservice/IAccessibilityServiceConnection.aidl
+++ b/core/java/android/accessibilityservice/IAccessibilityServiceConnection.aidl
@@ -115,4 +115,6 @@ interface IAccessibilityServiceConnection {
void setGestureDetectionPassthroughRegion(int displayId, in Region region);
void setTouchExplorationPassthroughRegion(int displayId, in Region region);
+
+ void setFocusAppearance(int strokeWidth, int color);
}
diff --git a/core/java/android/app/ActivityManager.java b/core/java/android/app/ActivityManager.java
index e3048dff1bda..38a22d8ade94 100644
--- a/core/java/android/app/ActivityManager.java
+++ b/core/java/android/app/ActivityManager.java
@@ -77,6 +77,8 @@ import android.util.ArrayMap;
import android.util.DisplayMetrics;
import android.util.Singleton;
import android.util.Size;
+import android.util.TypedXmlPullParser;
+import android.util.TypedXmlSerializer;
import android.view.Surface;
import android.view.WindowInsetsController.Appearance;
@@ -1502,57 +1504,54 @@ public class ActivityManager {
}
/** @hide */
- public void saveToXml(XmlSerializer out) throws IOException {
+ public void saveToXml(TypedXmlSerializer out) throws IOException {
if (mLabel != null) {
out.attribute(null, ATTR_TASKDESCRIPTIONLABEL, mLabel);
}
if (mColorPrimary != 0) {
- out.attribute(null, ATTR_TASKDESCRIPTIONCOLOR_PRIMARY,
- Integer.toHexString(mColorPrimary));
+ out.attributeIntHex(null, ATTR_TASKDESCRIPTIONCOLOR_PRIMARY, mColorPrimary);
}
if (mColorBackground != 0) {
- out.attribute(null, ATTR_TASKDESCRIPTIONCOLOR_BACKGROUND,
- Integer.toHexString(mColorBackground));
+ out.attributeIntHex(null, ATTR_TASKDESCRIPTIONCOLOR_BACKGROUND, mColorBackground);
}
if (mIconFilename != null) {
out.attribute(null, ATTR_TASKDESCRIPTIONICON_FILENAME, mIconFilename);
}
if (mIcon != null && mIcon.getType() == Icon.TYPE_RESOURCE) {
- out.attribute(null, ATTR_TASKDESCRIPTIONICON_RESOURCE,
- Integer.toString(mIcon.getResId()));
+ out.attributeInt(null, ATTR_TASKDESCRIPTIONICON_RESOURCE, mIcon.getResId());
out.attribute(null, ATTR_TASKDESCRIPTIONICON_RESOURCE_PACKAGE,
mIcon.getResPackage());
}
}
/** @hide */
- public void restoreFromXml(XmlPullParser in) {
+ public void restoreFromXml(TypedXmlPullParser in) {
final String label = in.getAttributeValue(null, ATTR_TASKDESCRIPTIONLABEL);
if (label != null) {
setLabel(label);
}
- final String colorPrimary = in.getAttributeValue(null,
- ATTR_TASKDESCRIPTIONCOLOR_PRIMARY);
- if (colorPrimary != null) {
- setPrimaryColor((int) Long.parseLong(colorPrimary, 16));
+ final int colorPrimary = in.getAttributeIntHex(null,
+ ATTR_TASKDESCRIPTIONCOLOR_PRIMARY, 0);
+ if (colorPrimary != 0) {
+ setPrimaryColor(colorPrimary);
}
- final String colorBackground = in.getAttributeValue(null,
- ATTR_TASKDESCRIPTIONCOLOR_BACKGROUND);
- if (colorBackground != null) {
- setBackgroundColor((int) Long.parseLong(colorBackground, 16));
+ final int colorBackground = in.getAttributeIntHex(null,
+ ATTR_TASKDESCRIPTIONCOLOR_BACKGROUND, 0);
+ if (colorBackground != 0) {
+ setBackgroundColor(colorBackground);
}
final String iconFilename = in.getAttributeValue(null,
ATTR_TASKDESCRIPTIONICON_FILENAME);
if (iconFilename != null) {
setIconFilename(iconFilename);
}
- final String iconResourceId = in.getAttributeValue(null,
- ATTR_TASKDESCRIPTIONICON_RESOURCE);
+ final int iconResourceId = in.getAttributeInt(null,
+ ATTR_TASKDESCRIPTIONICON_RESOURCE, Resources.ID_NULL);
final String iconResourcePackage = in.getAttributeValue(null,
ATTR_TASKDESCRIPTIONICON_RESOURCE_PACKAGE);
- if (iconResourceId != null && iconResourcePackage != null) {
+ if (iconResourceId != Resources.ID_NULL && iconResourcePackage != null) {
setIcon(Icon.createWithResource(iconResourcePackage,
- Integer.parseInt(iconResourceId, 10)));
+ iconResourceId));
}
}
diff --git a/core/java/android/app/ActivityThread.java b/core/java/android/app/ActivityThread.java
index 433182b38efd..ed6dea815e4c 100644
--- a/core/java/android/app/ActivityThread.java
+++ b/core/java/android/app/ActivityThread.java
@@ -85,6 +85,7 @@ import android.database.sqlite.SQLiteDebug.DbStats;
import android.graphics.Bitmap;
import android.graphics.Canvas;
import android.graphics.HardwareRenderer;
+import android.graphics.Rect;
import android.graphics.Typeface;
import android.hardware.display.DisplayManagerGlobal;
import android.inputmethodservice.InputMethodService;
@@ -5592,10 +5593,13 @@ public final class ActivityThread extends ClientTransactionHandler {
// If the new config is the same as the config this Activity is already running with and
// the override config also didn't change, then don't bother calling
// onConfigurationChanged.
+ // TODO(b/173090263): Use diff instead after the improvement of AssetManager and
+ // ResourcesImpl constructions.
final int diff = activity.mCurrentConfig.diffPublicOnly(newConfig);
- if (diff == 0 && !movedToDifferentDisplay
- && mResourcesManager.isSameResourcesOverrideConfig(activityToken,
- amOverrideConfig)) {
+
+ if (diff == 0 && !shouldUpdateWindowMetricsBounds(activity.mCurrentConfig, newConfig)
+ && !movedToDifferentDisplay && mResourcesManager.isSameResourcesOverrideConfig(
+ activityToken, amOverrideConfig)) {
// Nothing significant, don't proceed with updating and reporting.
return null;
} else if ((~activity.mActivityInfo.getRealConfigChanged() & diff) == 0) {
@@ -5647,6 +5651,26 @@ public final class ActivityThread extends ClientTransactionHandler {
return configToReport;
}
+ // TODO(b/173090263): Remove this method after the improvement of AssetManager and ResourcesImpl
+ // constructions.
+ /**
+ * Returns {@code true} if the metrics reported by {@link android.view.WindowMetrics} APIs
+ * should be updated.
+ *
+ * @see WindowManager#getCurrentWindowMetrics()
+ * @see WindowManager#getMaximumWindowMetrics()
+ */
+ private static boolean shouldUpdateWindowMetricsBounds(@NonNull Configuration currentConfig,
+ @NonNull Configuration newConfig) {
+ final Rect currentBounds = currentConfig.windowConfiguration.getBounds();
+ final Rect newBounds = newConfig.windowConfiguration.getBounds();
+
+ final Rect currentMaxBounds = currentConfig.windowConfiguration.getMaxBounds();
+ final Rect newMaxBounds = newConfig.windowConfiguration.getMaxBounds();
+
+ return !currentBounds.equals(newBounds) || !currentMaxBounds.equals(newMaxBounds);
+ }
+
public final void applyConfigurationToResources(Configuration config) {
synchronized (mResourcesManager) {
mResourcesManager.applyConfigurationToResourcesLocked(config, null);
@@ -5881,7 +5905,7 @@ public final class ActivityThread extends ClientTransactionHandler {
/**
* Sets the supplied {@code overrideConfig} as pending for the {@code activityToken}. Calling
* this method prevents any calls to
- * {@link #handleActivityConfigurationChanged(IBinder, Configuration, int, boolean)} from
+ * {@link #handleActivityConfigurationChanged(ActivityClientRecord, Configuration, int)} from
* processing any configurations older than {@code overrideConfig}.
*/
@Override
@@ -5903,8 +5927,8 @@ public final class ActivityThread extends ClientTransactionHandler {
/**
* Handle new activity configuration and/or move to a different display. This method is a noop
- * if {@link #updatePendingActivityConfiguration(IBinder, Configuration)} has been called with
- * a newer config than {@code overrideConfig}.
+ * if {@link #updatePendingActivityConfiguration(ActivityClientRecord, Configuration)} has been
+ * called with a newer config than {@code overrideConfig}.
*
* @param r Target activity record.
* @param overrideConfig Activity override config.
@@ -5969,7 +5993,7 @@ public final class ActivityThread extends ClientTransactionHandler {
/**
* Checks if the display id of activity is different from the given one. Note that
- * {@link #INVALID_DISPLAY} means no difference.
+ * {@link Display#INVALID_DISPLAY} means no difference.
*/
private static boolean isDifferentDisplay(@NonNull Activity activity, int displayId) {
return displayId != INVALID_DISPLAY && displayId != activity.getDisplayId();
diff --git a/core/java/android/app/ApplicationPackageManager.java b/core/java/android/app/ApplicationPackageManager.java
index 34437afb614a..3642d318e820 100644
--- a/core/java/android/app/ApplicationPackageManager.java
+++ b/core/java/android/app/ApplicationPackageManager.java
@@ -30,6 +30,7 @@ import android.annotation.Nullable;
import android.annotation.StringRes;
import android.annotation.UserIdInt;
import android.annotation.XmlRes;
+import android.app.role.RoleManager;
import android.compat.annotation.UnsupportedAppUsage;
import android.content.ComponentName;
import android.content.ContentResolver;
@@ -2306,20 +2307,14 @@ public class ApplicationPackageManager extends PackageManager {
@Override
public String getDefaultBrowserPackageNameAsUser(int userId) {
- try {
- return mPermissionManager.getDefaultBrowser(userId);
- } catch (RemoteException e) {
- throw e.rethrowFromSystemServer();
- }
+ RoleManager roleManager = mContext.getSystemService(RoleManager.class);
+ return roleManager.getBrowserRoleHolder(userId);
}
@Override
public boolean setDefaultBrowserPackageNameAsUser(String packageName, int userId) {
- try {
- return mPermissionManager.setDefaultBrowser(packageName, userId);
- } catch (RemoteException e) {
- throw e.rethrowFromSystemServer();
- }
+ RoleManager roleManager = mContext.getSystemService(RoleManager.class);
+ return roleManager.setBrowserRoleHolder(packageName, userId);
}
@Override
diff --git a/core/java/android/app/LoadedApk.java b/core/java/android/app/LoadedApk.java
index 6535387acdf3..99785e1e73f4 100644
--- a/core/java/android/app/LoadedApk.java
+++ b/core/java/android/app/LoadedApk.java
@@ -1284,7 +1284,7 @@ public final class LoadedApk {
Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER);
throw new RuntimeException(
"Unable to instantiate application " + appClass
- + ": " + e.toString(), e);
+ + " package " + mPackageName + ": " + e.toString(), e);
}
}
mActivityThread.mAllApplications.add(app);
diff --git a/core/java/android/app/Notification.java b/core/java/android/app/Notification.java
index a1135809fd4c..82f61a4c615a 100644
--- a/core/java/android/app/Notification.java
+++ b/core/java/android/app/Notification.java
@@ -83,6 +83,7 @@ import android.util.Log;
import android.util.Pair;
import android.util.SparseArray;
import android.util.proto.ProtoOutputStream;
+import android.view.ContextThemeWrapper;
import android.view.Gravity;
import android.view.View;
import android.view.ViewGroup;
@@ -6120,8 +6121,11 @@ public class Notification implements Parcelable
int defaultColor = mInNightMode ? Color.BLACK : Color.WHITE;
Resources.Theme theme = mContext.getTheme();
if (theme == null) {
+ // Running unit tests with mocked context
return defaultColor;
}
+ theme = new ContextThemeWrapper(mContext, R.style.Theme_DeviceDefault_DayNight)
+ .getTheme();
TypedArray ta = theme.obtainStyledAttributes(new int[]{R.attr.colorBackground});
if (ta == null) {
return defaultColor;
diff --git a/core/java/android/app/NotificationChannel.java b/core/java/android/app/NotificationChannel.java
index 080aac9a9e6a..b1a8f9b0ba33 100644
--- a/core/java/android/app/NotificationChannel.java
+++ b/core/java/android/app/NotificationChannel.java
@@ -32,9 +32,12 @@ import android.os.Parcelable;
import android.provider.Settings;
import android.service.notification.NotificationListenerService;
import android.text.TextUtils;
+import android.util.TypedXmlPullParser;
+import android.util.TypedXmlSerializer;
import android.util.proto.ProtoOutputStream;
import com.android.internal.util.Preconditions;
+import com.android.internal.util.XmlUtils;
import org.json.JSONException;
import org.json.JSONObject;
@@ -869,7 +872,7 @@ public final class NotificationChannel implements Parcelable {
* @hide
*/
public void populateFromXmlForRestore(XmlPullParser parser, Context context) {
- populateFromXml(parser, true, context);
+ populateFromXml(XmlUtils.makeTyped(parser), true, context);
}
/**
@@ -877,13 +880,13 @@ public final class NotificationChannel implements Parcelable {
*/
@SystemApi
public void populateFromXml(XmlPullParser parser) {
- populateFromXml(parser, false, null);
+ populateFromXml(XmlUtils.makeTyped(parser), false, null);
}
/**
* If {@param forRestore} is true, {@param Context} MUST be non-null.
*/
- private void populateFromXml(XmlPullParser parser, boolean forRestore,
+ private void populateFromXml(TypedXmlPullParser parser, boolean forRestore,
@Nullable Context context) {
Preconditions.checkArgument(!forRestore || context != null,
"forRestore is true but got null context");
@@ -941,14 +944,14 @@ public final class NotificationChannel implements Parcelable {
*/
@SystemApi
public void writeXml(XmlSerializer out) throws IOException {
- writeXml(out, false, null);
+ writeXml(XmlUtils.makeTyped(out), false, null);
}
/**
* @hide
*/
public void writeXmlForBackup(XmlSerializer out, Context context) throws IOException {
- writeXml(out, true, context);
+ writeXml(XmlUtils.makeTyped(out), true, context);
}
private Uri getSoundForBackup(Context context) {
@@ -967,7 +970,7 @@ public final class NotificationChannel implements Parcelable {
/**
* If {@param forBackup} is true, {@param Context} MUST be non-null.
*/
- private void writeXml(XmlSerializer out, boolean forBackup, @Nullable Context context)
+ private void writeXml(TypedXmlSerializer out, boolean forBackup, @Nullable Context context)
throws IOException {
Preconditions.checkArgument(!forBackup || context != null,
"forBackup is true but got null context");
@@ -980,62 +983,58 @@ public final class NotificationChannel implements Parcelable {
out.attribute(null, ATT_DESC, getDescription());
}
if (getImportance() != DEFAULT_IMPORTANCE) {
- out.attribute(
- null, ATT_IMPORTANCE, Integer.toString(getImportance()));
+ out.attributeInt(null, ATT_IMPORTANCE, getImportance());
}
if (canBypassDnd()) {
- out.attribute(
- null, ATT_PRIORITY, Integer.toString(Notification.PRIORITY_MAX));
+ out.attributeInt(null, ATT_PRIORITY, Notification.PRIORITY_MAX);
}
if (getLockscreenVisibility() != DEFAULT_VISIBILITY) {
- out.attribute(null, ATT_VISIBILITY,
- Integer.toString(getLockscreenVisibility()));
+ out.attributeInt(null, ATT_VISIBILITY, getLockscreenVisibility());
}
Uri sound = forBackup ? getSoundForBackup(context) : getSound();
if (sound != null) {
out.attribute(null, ATT_SOUND, sound.toString());
}
if (getAudioAttributes() != null) {
- out.attribute(null, ATT_USAGE, Integer.toString(getAudioAttributes().getUsage()));
- out.attribute(null, ATT_CONTENT_TYPE,
- Integer.toString(getAudioAttributes().getContentType()));
- out.attribute(null, ATT_FLAGS, Integer.toString(getAudioAttributes().getFlags()));
+ out.attributeInt(null, ATT_USAGE, getAudioAttributes().getUsage());
+ out.attributeInt(null, ATT_CONTENT_TYPE, getAudioAttributes().getContentType());
+ out.attributeInt(null, ATT_FLAGS, getAudioAttributes().getFlags());
}
if (shouldShowLights()) {
- out.attribute(null, ATT_LIGHTS, Boolean.toString(shouldShowLights()));
+ out.attributeBoolean(null, ATT_LIGHTS, shouldShowLights());
}
if (getLightColor() != DEFAULT_LIGHT_COLOR) {
- out.attribute(null, ATT_LIGHT_COLOR, Integer.toString(getLightColor()));
+ out.attributeInt(null, ATT_LIGHT_COLOR, getLightColor());
}
if (shouldVibrate()) {
- out.attribute(null, ATT_VIBRATION_ENABLED, Boolean.toString(shouldVibrate()));
+ out.attributeBoolean(null, ATT_VIBRATION_ENABLED, shouldVibrate());
}
if (getVibrationPattern() != null) {
out.attribute(null, ATT_VIBRATION, longArrayToString(getVibrationPattern()));
}
if (getUserLockedFields() != 0) {
- out.attribute(null, ATT_USER_LOCKED, Integer.toString(getUserLockedFields()));
+ out.attributeInt(null, ATT_USER_LOCKED, getUserLockedFields());
}
if (isFgServiceShown()) {
- out.attribute(null, ATT_FG_SERVICE_SHOWN, Boolean.toString(isFgServiceShown()));
+ out.attributeBoolean(null, ATT_FG_SERVICE_SHOWN, isFgServiceShown());
}
if (canShowBadge()) {
- out.attribute(null, ATT_SHOW_BADGE, Boolean.toString(canShowBadge()));
+ out.attributeBoolean(null, ATT_SHOW_BADGE, canShowBadge());
}
if (isDeleted()) {
- out.attribute(null, ATT_DELETED, Boolean.toString(isDeleted()));
+ out.attributeBoolean(null, ATT_DELETED, isDeleted());
}
if (getGroup() != null) {
out.attribute(null, ATT_GROUP, getGroup());
}
if (isBlockable()) {
- out.attribute(null, ATT_BLOCKABLE_SYSTEM, Boolean.toString(isBlockable()));
+ out.attributeBoolean(null, ATT_BLOCKABLE_SYSTEM, isBlockable());
}
if (getAllowBubbles() != DEFAULT_ALLOW_BUBBLE) {
- out.attribute(null, ATT_ALLOW_BUBBLE, Integer.toString(getAllowBubbles()));
+ out.attributeInt(null, ATT_ALLOW_BUBBLE, getAllowBubbles());
}
if (getOriginalImportance() != DEFAULT_IMPORTANCE) {
- out.attribute(null, ATT_ORIG_IMP, Integer.toString(getOriginalImportance()));
+ out.attributeInt(null, ATT_ORIG_IMP, getOriginalImportance());
}
if (getParentChannelId() != null) {
out.attribute(null, ATT_PARENT_CHANNEL, getParentChannelId());
@@ -1044,10 +1043,10 @@ public final class NotificationChannel implements Parcelable {
out.attribute(null, ATT_CONVERSATION_ID, getConversationId());
}
if (isDemoted()) {
- out.attribute(null, ATT_DEMOTE, Boolean.toString(isDemoted()));
+ out.attributeBoolean(null, ATT_DEMOTE, isDemoted());
}
if (isImportantConversation()) {
- out.attribute(null, ATT_IMP_CONVERSATION, Boolean.toString(isImportantConversation()));
+ out.attributeBoolean(null, ATT_IMP_CONVERSATION, isImportantConversation());
}
// mImportanceLockedDefaultApp and mImportanceLockedByOEM have a different source of
@@ -1099,7 +1098,7 @@ public final class NotificationChannel implements Parcelable {
return record;
}
- private static AudioAttributes safeAudioAttributes(XmlPullParser parser) {
+ private static AudioAttributes safeAudioAttributes(TypedXmlPullParser parser) {
int usage = safeInt(parser, ATT_USAGE, AudioAttributes.USAGE_NOTIFICATION);
int contentType = safeInt(parser, ATT_CONTENT_TYPE,
AudioAttributes.CONTENT_TYPE_SONIFICATION);
@@ -1111,32 +1110,20 @@ public final class NotificationChannel implements Parcelable {
.build();
}
- private static Uri safeUri(XmlPullParser parser, String att) {
+ private static Uri safeUri(TypedXmlPullParser parser, String att) {
final String val = parser.getAttributeValue(null, att);
return val == null ? null : Uri.parse(val);
}
- private static int safeInt(XmlPullParser parser, String att, int defValue) {
- final String val = parser.getAttributeValue(null, att);
- return tryParseInt(val, defValue);
- }
-
- private static int tryParseInt(String value, int defValue) {
- if (TextUtils.isEmpty(value)) return defValue;
- try {
- return Integer.parseInt(value);
- } catch (NumberFormatException e) {
- return defValue;
- }
+ private static int safeInt(TypedXmlPullParser parser, String att, int defValue) {
+ return parser.getAttributeInt(null, att, defValue);
}
- private static boolean safeBool(XmlPullParser parser, String att, boolean defValue) {
- final String value = parser.getAttributeValue(null, att);
- if (TextUtils.isEmpty(value)) return defValue;
- return Boolean.parseBoolean(value);
+ private static boolean safeBool(TypedXmlPullParser parser, String att, boolean defValue) {
+ return parser.getAttributeBoolean(null, att, defValue);
}
- private static long[] safeLongArray(XmlPullParser parser, String att, long[] defValue) {
+ private static long[] safeLongArray(TypedXmlPullParser parser, String att, long[] defValue) {
final String attributeValue = parser.getAttributeValue(null, att);
if (TextUtils.isEmpty(attributeValue)) return defValue;
String[] values = attributeValue.split(DELIMITER);
diff --git a/core/java/android/app/NotificationChannelGroup.java b/core/java/android/app/NotificationChannelGroup.java
index ec7fa332b23f..cd6df0b231d9 100644
--- a/core/java/android/app/NotificationChannelGroup.java
+++ b/core/java/android/app/NotificationChannelGroup.java
@@ -23,12 +23,12 @@ import android.content.Intent;
import android.os.Parcel;
import android.os.Parcelable;
import android.text.TextUtils;
+import android.util.TypedXmlPullParser;
+import android.util.TypedXmlSerializer;
import android.util.proto.ProtoOutputStream;
import org.json.JSONException;
import org.json.JSONObject;
-import org.xmlpull.v1.XmlPullParser;
-import org.xmlpull.v1.XmlSerializer;
import java.io.IOException;
import java.util.ArrayList;
@@ -228,22 +228,16 @@ public final class NotificationChannelGroup implements Parcelable {
/**
* @hide
*/
- public void populateFromXml(XmlPullParser parser) {
+ public void populateFromXml(TypedXmlPullParser parser) {
// Name, id, and importance are set in the constructor.
setDescription(parser.getAttributeValue(null, ATT_DESC));
- setBlocked(safeBool(parser, ATT_BLOCKED, false));
- }
-
- private static boolean safeBool(XmlPullParser parser, String att, boolean defValue) {
- final String value = parser.getAttributeValue(null, att);
- if (TextUtils.isEmpty(value)) return defValue;
- return Boolean.parseBoolean(value);
+ setBlocked(parser.getAttributeBoolean(null, ATT_BLOCKED, false));
}
/**
* @hide
*/
- public void writeXml(XmlSerializer out) throws IOException {
+ public void writeXml(TypedXmlSerializer out) throws IOException {
out.startTag(null, TAG_GROUP);
out.attribute(null, ATT_ID, getId());
@@ -253,8 +247,8 @@ public final class NotificationChannelGroup implements Parcelable {
if (getDescription() != null) {
out.attribute(null, ATT_DESC, getDescription().toString());
}
- out.attribute(null, ATT_BLOCKED, Boolean.toString(isBlocked()));
- out.attribute(null, ATT_USER_LOCKED, Integer.toString(mUserLockedFields));
+ out.attributeBoolean(null, ATT_BLOCKED, isBlocked());
+ out.attributeInt(null, ATT_USER_LOCKED, mUserLockedFields);
out.endTag(null, TAG_GROUP);
}
diff --git a/core/java/android/app/ResourcesManager.java b/core/java/android/app/ResourcesManager.java
index 36d5b5eb9fdf..772833cc6d2d 100644
--- a/core/java/android/app/ResourcesManager.java
+++ b/core/java/android/app/ResourcesManager.java
@@ -1178,6 +1178,8 @@ public class ResourcesManager {
continue;
}
+ // TODO(b/173090263): Improve the performance of AssetManager & ResourcesImpl
+ // constructions.
final ResourcesImpl resourcesImpl =
findOrCreateResourcesImplForKeyLocked(newKey);
if (resourcesImpl != null && resourcesImpl != resources.getImpl()) {
diff --git a/core/java/android/app/admin/DeviceAdminInfo.java b/core/java/android/app/admin/DeviceAdminInfo.java
index 1ee8e4fce58b..41256d09d0ed 100644
--- a/core/java/android/app/admin/DeviceAdminInfo.java
+++ b/core/java/android/app/admin/DeviceAdminInfo.java
@@ -37,11 +37,12 @@ import android.util.AttributeSet;
import android.util.Log;
import android.util.Printer;
import android.util.SparseArray;
+import android.util.TypedXmlPullParser;
+import android.util.TypedXmlSerializer;
import android.util.Xml;
import org.xmlpull.v1.XmlPullParser;
import org.xmlpull.v1.XmlPullParserException;
-import org.xmlpull.v1.XmlSerializer;
import java.io.IOException;
import java.util.ArrayList;
@@ -472,16 +473,15 @@ public final class DeviceAdminInfo implements Parcelable {
}
/** @hide */
- public void writePoliciesToXml(XmlSerializer out)
+ public void writePoliciesToXml(TypedXmlSerializer out)
throws IllegalArgumentException, IllegalStateException, IOException {
- out.attribute(null, "flags", Integer.toString(mUsesPolicies));
+ out.attributeInt(null, "flags", mUsesPolicies);
}
/** @hide */
- public void readPoliciesFromXml(XmlPullParser parser)
+ public void readPoliciesFromXml(TypedXmlPullParser parser)
throws XmlPullParserException, IOException {
- mUsesPolicies = Integer.parseInt(
- parser.getAttributeValue(null, "flags"));
+ mUsesPolicies = parser.getAttributeInt(null, "flags");
}
public void dump(Printer pw, String prefix) {
diff --git a/core/java/android/app/admin/DevicePolicyManager.java b/core/java/android/app/admin/DevicePolicyManager.java
index 5eb1922a163c..da1219bdd19c 100644
--- a/core/java/android/app/admin/DevicePolicyManager.java
+++ b/core/java/android/app/admin/DevicePolicyManager.java
@@ -1206,7 +1206,7 @@ public class DevicePolicyManager {
* <ul>
* <li>By the admin app when performing the admin-integrated
* provisioning flow as a result of the {@link #ACTION_GET_PROVISIONING_MODE} activity</li>
- * <li>With intent action {@link #ACTION_PROVISION_MANAGED_DEVICE}</li>
+ * <li>For managed account enrollment</li>
* </ul>
*
* <p>If the education screens are skipped, it is the admin application's responsibility
@@ -1229,9 +1229,37 @@ public class DevicePolicyManager {
"android.app.extra.PROVISIONING_USE_MOBILE_DATA";
/**
+ * Possible values for {@link #EXTRA_PROVISIONING_TRIGGER}.
+ *
+ * @hide
+ */
+ @IntDef(prefix = { "PROVISIONING_TRIGGER_" }, value = {
+ PROVISIONING_TRIGGER_UNSPECIFIED,
+ PROVISIONING_TRIGGER_CLOUD_ENROLLMENT,
+ PROVISIONING_TRIGGER_QR_CODE,
+ PROVISIONING_TRIGGER_PERSISTENT_DEVICE_OWNER,
+ PROVISIONING_TRIGGER_MANAGED_ACCOUNT
+ })
+ @Retention(RetentionPolicy.SOURCE)
+ public @interface ProvisioningTrigger {}
+
+ /**
+ * Possible values for {@link #EXTRA_PROVISIONING_SUPPORTED_MODES}.
+ *
+ * @hide
+ */
+ @IntDef(prefix = { "SUPPORTED_MODES_" }, value = {
+ SUPPORTED_MODES_ORGANIZATION_OWNED,
+ SUPPORTED_MODES_PERSONALLY_OWNED,
+ SUPPORTED_MODES_ORGANIZATION_AND_PERSONALLY_OWNED
+ })
+ @Retention(RetentionPolicy.SOURCE)
+ public @interface ProvisioningConfiguration {}
+
+ /**
* A String extra holding the provisioning trigger. It could be one of
* {@link #PROVISIONING_TRIGGER_CLOUD_ENROLLMENT}, {@link #PROVISIONING_TRIGGER_QR_CODE},
- * {@link #PROVISIONING_TRIGGER_PERSISTENT_DEVICE_OWNER} or {@link
+ * {@link #PROVISIONING_TRIGGER_MANAGED_ACCOUNT} or {@link
* #PROVISIONING_TRIGGER_UNSPECIFIED}.
*
* <p>Use in an intent with action {@link
@@ -1247,7 +1275,7 @@ public class DevicePolicyManager {
* trigger has not been specified.
* @see #PROVISIONING_TRIGGER_CLOUD_ENROLLMENT
* @see #PROVISIONING_TRIGGER_QR_CODE
- * @see #PROVISIONING_TRIGGER_PERSISTENT_DEVICE_OWNER
+ * @see #PROVISIONING_TRIGGER_MANAGED_ACCOUNT
* @hide
*/
@SystemApi
@@ -1257,7 +1285,7 @@ public class DevicePolicyManager {
* A value for {@link #EXTRA_PROVISIONING_TRIGGER} indicating that the provisioning
* trigger is cloud enrollment.
* @see #PROVISIONING_TRIGGER_QR_CODE
- * @see #PROVISIONING_TRIGGER_PERSISTENT_DEVICE_OWNER
+ * @see #PROVISIONING_TRIGGER_MANAGED_ACCOUNT
* @see #PROVISIONING_TRIGGER_UNSPECIFIED
* @hide
*/
@@ -1268,7 +1296,7 @@ public class DevicePolicyManager {
* A value for {@link #EXTRA_PROVISIONING_TRIGGER} indicating that the provisioning
* trigger is the QR code scanner.
* @see #PROVISIONING_TRIGGER_CLOUD_ENROLLMENT
- * @see #PROVISIONING_TRIGGER_PERSISTENT_DEVICE_OWNER
+ * @see #PROVISIONING_TRIGGER_MANAGED_ACCOUNT
* @see #PROVISIONING_TRIGGER_UNSPECIFIED
* @hide
*/
@@ -1278,15 +1306,78 @@ public class DevicePolicyManager {
/**
* A value for {@link #EXTRA_PROVISIONING_TRIGGER} indicating that the provisioning
* trigger is persistent device owner enrollment.
+ * @deprecated Use the broader {@link #PROVISIONING_TRIGGER_MANAGED_ACCOUNT} instead
* @see #PROVISIONING_TRIGGER_CLOUD_ENROLLMENT
* @see #PROVISIONING_TRIGGER_QR_CODE
* @see #PROVISIONING_TRIGGER_UNSPECIFIED
* @hide
*/
@SystemApi
+ @Deprecated
public static final int PROVISIONING_TRIGGER_PERSISTENT_DEVICE_OWNER = 3;
/**
+ * A value for {@link #EXTRA_PROVISIONING_TRIGGER} indicating that the provisioning
+ * trigger is managed account enrollment.
+ * @see #PROVISIONING_TRIGGER_CLOUD_ENROLLMENT
+ * @see #PROVISIONING_TRIGGER_QR_CODE
+ * @see #PROVISIONING_TRIGGER_UNSPECIFIED
+ * @hide
+ */
+ @SystemApi
+ public static final int PROVISIONING_TRIGGER_MANAGED_ACCOUNT = 4;
+
+ /**
+ * A value for {@link #EXTRA_PROVISIONING_SUPPORTED_MODES} indicating that provisioning is
+ * organization-owned.
+ *
+ * <p>Using this value will cause the admin app's {@link #ACTION_GET_PROVISIONING_MODE}
+ * activity to have the {@link #EXTRA_PROVISIONING_ALLOWED_PROVISIONING_MODES} array extra
+ * contain {@link #PROVISIONING_MODE_MANAGED_PROFILE} and {@link
+ * #PROVISIONING_MODE_FULLY_MANAGED_DEVICE}.
+ *
+ * <p>Also, if this value is set, the admin app's {@link #ACTION_GET_PROVISIONING_MODE} activity
+ * will not receive the {@link #EXTRA_PROVISIONING_IMEI} and {@link
+ * #EXTRA_PROVISIONING_SERIAL_NUMBER} extras.
+ *
+ * @hide
+ */
+ @SystemApi
+ public static final int SUPPORTED_MODES_ORGANIZATION_OWNED = 1;
+
+ /**
+ * A value for {@link #EXTRA_PROVISIONING_SUPPORTED_MODES} indicating that provisioning is
+ * personally-owned.
+ *
+ * <p>Using this value will cause the admin app's {@link #ACTION_GET_PROVISIONING_MODE}
+ * activity to have the {@link #EXTRA_PROVISIONING_ALLOWED_PROVISIONING_MODES} array extra
+ * contain only {@link #PROVISIONING_MODE_MANAGED_PROFILE}.
+ *
+ * @hide
+ */
+ @SystemApi
+ public static final int SUPPORTED_MODES_PERSONALLY_OWNED = 2;
+
+ /**
+ * A value for {@link #EXTRA_PROVISIONING_SUPPORTED_MODES} indicating that provisioning could
+ * be organization-owned or personally-owned.
+ *
+ * <p>Using this value will cause the admin app's {@link #ACTION_GET_PROVISIONING_MODE}
+ * activity to have the {@link #EXTRA_PROVISIONING_ALLOWED_PROVISIONING_MODES} array extra
+ * contain {@link
+ * #PROVISIONING_MODE_MANAGED_PROFILE}, {@link #PROVISIONING_MODE_FULLY_MANAGED_DEVICE} and
+ * {@link #PROVISIONING_MODE_MANAGED_PROFILE_ON_PERSONAL_DEVICE}.
+ *
+ * <p>Also, if this value is set, the admin app's {@link #ACTION_GET_PROVISIONING_MODE} activity
+ * will not receive the {@link #EXTRA_PROVISIONING_IMEI} and {@link
+ * #EXTRA_PROVISIONING_SERIAL_NUMBER} extras.
+ *
+ * @hide
+ */
+ @SystemApi
+ public static final int SUPPORTED_MODES_ORGANIZATION_AND_PERSONALLY_OWNED = 3;
+
+ /**
* This MIME type is used for starting the device owner provisioning.
*
* <p>During device owner provisioning a device admin app is set as the owner of the device.
@@ -2379,16 +2470,57 @@ public class DevicePolicyManager {
/**
* An intent extra holding the provisioning mode returned by the administrator.
- * The value for this extra should be one of the following:
- * <ul>
- * <li>{@link #PROVISIONING_MODE_FULLY_MANAGED_DEVICE}</li>
- * <li>{@link #PROVISIONING_MODE_MANAGED_PROFILE}</li>
- * </ul>
+ * The value of this extra must be one of the values provided in {@link
+ * #EXTRA_PROVISIONING_ALLOWED_PROVISIONING_MODES}, which is provided as an intent extra to
+ * the admin app's {@link #ACTION_GET_PROVISIONING_MODE} activity.
+ *
+ * @see #PROVISIONING_MODE_FULLY_MANAGED_DEVICE
+ * @see #PROVISIONING_MODE_MANAGED_PROFILE
*/
public static final String EXTRA_PROVISIONING_MODE =
"android.app.extra.PROVISIONING_MODE";
/**
+ * An integer extra indication what provisioning modes should be available for the admin app
+ * to pick.
+ *
+ * <p>The default value is {@link #SUPPORTED_MODES_ORGANIZATION_OWNED}.
+ *
+ * <p>The value of this extra will determine the contents of the {@link
+ * #EXTRA_PROVISIONING_ALLOWED_PROVISIONING_MODES} array that is passed to the admin app as an
+ * extra to its {@link #ACTION_GET_PROVISIONING_MODE} activity.
+ *
+ * <p>If one of the possible admin app choices is a personally-owned work profile, then the
+ * IMEI and serial number will not be passed to the admin app's {@link
+ * #ACTION_GET_PROVISIONING_MODE} activity via the {@link #EXTRA_PROVISIONING_IMEI} and {@link
+ * #EXTRA_PROVISIONING_SERIAL_NUMBER} respectively.
+ *
+ * <p>This extra is only respected when provided alongside the {@link
+ * #ACTION_PROVISION_MANAGED_DEVICE_FROM_TRUSTED_SOURCE} intent action.
+ *
+ * @see #SUPPORTED_MODES_ORGANIZATION_OWNED
+ * @see #SUPPORTED_MODES_PERSONALLY_OWNED
+ * @see #SUPPORTED_MODES_ORGANIZATION_AND_PERSONALLY_OWNED
+ * @hide
+ */
+ @SystemApi
+ public static final String EXTRA_PROVISIONING_SUPPORTED_MODES =
+ "android.app.extra.PROVISIONING_SUPPORTED_MODES";
+
+ /**
+ * An {@link ArrayList} of {@link Integer} extra specifying the allowed provisioning modes.
+ * <p>This extra will be passed to the admin app's {@link #ACTION_GET_PROVISIONING_MODE}
+ * activity, whose result intent must contain {@link #EXTRA_PROVISIONING_MODE} set to one of
+ * the values in this array.
+ * <p>If the value set to {@link #EXTRA_PROVISIONING_MODE} is not in the array,
+ * provisioning will fail.
+ * @see #PROVISIONING_MODE_MANAGED_PROFILE
+ * @see #PROVISIONING_MODE_FULLY_MANAGED_DEVICE
+ */
+ public static final String EXTRA_PROVISIONING_ALLOWED_PROVISIONING_MODES =
+ "android.app.extra.PROVISIONING_ALLOWED_PROVISIONING_MODES";
+
+ /**
* The provisioning mode for fully managed device.
*/
public static final int PROVISIONING_MODE_FULLY_MANAGED_DEVICE = 1;
@@ -2399,6 +2531,11 @@ public class DevicePolicyManager {
public static final int PROVISIONING_MODE_MANAGED_PROFILE = 2;
/**
+ * The provisioning mode for a work profile on a personal device.
+ */
+ public static final int PROVISIONING_MODE_MANAGED_PROFILE_ON_PERSONAL_DEVICE = 3;
+
+ /**
* Activity action: Starts the administrator to show policy compliance for the provisioning.
* This action is used any time that the administrator has an opportunity to show policy
* compliance before the end of setup wizard. This could happen as part of the admin-integrated
diff --git a/core/java/android/app/admin/FactoryResetProtectionPolicy.java b/core/java/android/app/admin/FactoryResetProtectionPolicy.java
index aa94e817c152..40ae1f0c11ea 100644
--- a/core/java/android/app/admin/FactoryResetProtectionPolicy.java
+++ b/core/java/android/app/admin/FactoryResetProtectionPolicy.java
@@ -26,10 +26,10 @@ import android.content.ComponentName;
import android.os.Parcel;
import android.os.Parcelable;
import android.util.Log;
+import android.util.TypedXmlPullParser;
+import android.util.TypedXmlSerializer;
-import org.xmlpull.v1.XmlPullParser;
import org.xmlpull.v1.XmlPullParserException;
-import org.xmlpull.v1.XmlSerializer;
import java.io.IOException;
import java.util.ArrayList;
@@ -201,10 +201,10 @@ public final class FactoryResetProtectionPolicy implements Parcelable {
* @hide
*/
@Nullable
- public static FactoryResetProtectionPolicy readFromXml(@NonNull XmlPullParser parser) {
+ public static FactoryResetProtectionPolicy readFromXml(@NonNull TypedXmlPullParser parser) {
try {
- boolean factoryResetProtectionEnabled = Boolean.parseBoolean(
- parser.getAttributeValue(null, KEY_FACTORY_RESET_PROTECTION_ENABLED));
+ boolean factoryResetProtectionEnabled = parser.getAttributeBoolean(null,
+ KEY_FACTORY_RESET_PROTECTION_ENABLED, false);
List<String> factoryResetProtectionAccounts = new ArrayList<>();
int outerDepth = parser.getDepth();
@@ -232,9 +232,9 @@ public final class FactoryResetProtectionPolicy implements Parcelable {
/**
* @hide
*/
- public void writeToXml(@NonNull XmlSerializer out) throws IOException {
- out.attribute(null, KEY_FACTORY_RESET_PROTECTION_ENABLED,
- Boolean.toString(mFactoryResetProtectionEnabled));
+ public void writeToXml(@NonNull TypedXmlSerializer out) throws IOException {
+ out.attributeBoolean(null, KEY_FACTORY_RESET_PROTECTION_ENABLED,
+ mFactoryResetProtectionEnabled);
for (String account : mFactoryResetProtectionAccounts) {
out.startTag(null, KEY_FACTORY_RESET_PROTECTION_ACCOUNT);
out.attribute(null, ATTR_VALUE, account);
diff --git a/core/java/android/app/admin/SystemUpdateInfo.java b/core/java/android/app/admin/SystemUpdateInfo.java
index 53b238633fec..b88bf76c96ca 100644
--- a/core/java/android/app/admin/SystemUpdateInfo.java
+++ b/core/java/android/app/admin/SystemUpdateInfo.java
@@ -21,9 +21,11 @@ import android.annotation.Nullable;
import android.os.Build;
import android.os.Parcel;
import android.os.Parcelable;
+import android.util.Log;
+import android.util.TypedXmlPullParser;
+import android.util.TypedXmlSerializer;
-import org.xmlpull.v1.XmlPullParser;
-import org.xmlpull.v1.XmlSerializer;
+import org.xmlpull.v1.XmlPullParserException;
import java.io.IOException;
import java.lang.annotation.Retention;
@@ -34,6 +36,7 @@ import java.util.Objects;
* A class containing information about a pending system update.
*/
public final class SystemUpdateInfo implements Parcelable {
+ private static final String TAG = "SystemUpdateInfo";
/**
* Represents it is unknown whether the system update is a security patch.
@@ -125,27 +128,32 @@ public final class SystemUpdateInfo implements Parcelable {
};
/** @hide */
- public void writeToXml(XmlSerializer out, String tag) throws IOException {
+ public void writeToXml(TypedXmlSerializer out, String tag) throws IOException {
out.startTag(null, tag);
- out.attribute(null, ATTR_RECEIVED_TIME, String.valueOf(mReceivedTime));
- out.attribute(null, ATTR_SECURITY_PATCH_STATE, String.valueOf(mSecurityPatchState));
+ out.attributeLong(null, ATTR_RECEIVED_TIME, mReceivedTime);
+ out.attributeInt(null, ATTR_SECURITY_PATCH_STATE, mSecurityPatchState);
out.attribute(null, ATTR_ORIGINAL_BUILD , Build.FINGERPRINT);
out.endTag(null, tag);
}
/** @hide */
@Nullable
- public static SystemUpdateInfo readFromXml(XmlPullParser parser) {
+ public static SystemUpdateInfo readFromXml(TypedXmlPullParser parser) {
// If an OTA has been applied (build fingerprint has changed), discard stale info.
final String buildFingerprint = parser.getAttributeValue(null, ATTR_ORIGINAL_BUILD );
if (!Build.FINGERPRINT.equals(buildFingerprint)) {
return null;
}
- final long receivedTime =
- Long.parseLong(parser.getAttributeValue(null, ATTR_RECEIVED_TIME));
- final int securityPatchState =
- Integer.parseInt(parser.getAttributeValue(null, ATTR_SECURITY_PATCH_STATE));
- return new SystemUpdateInfo(receivedTime, securityPatchState);
+ try {
+ final long receivedTime =
+ parser.getAttributeLong(null, ATTR_RECEIVED_TIME);
+ final int securityPatchState =
+ parser.getAttributeInt(null, ATTR_SECURITY_PATCH_STATE);
+ return new SystemUpdateInfo(receivedTime, securityPatchState);
+ } catch (XmlPullParserException e) {
+ Log.w(TAG, "Load xml failed", e);
+ return null;
+ }
}
@Override
diff --git a/core/java/android/app/admin/SystemUpdatePolicy.java b/core/java/android/app/admin/SystemUpdatePolicy.java
index 2ba2c0425b2f..68ac4ccf210a 100644
--- a/core/java/android/app/admin/SystemUpdatePolicy.java
+++ b/core/java/android/app/admin/SystemUpdatePolicy.java
@@ -26,10 +26,10 @@ import android.os.Parcel;
import android.os.Parcelable;
import android.util.Log;
import android.util.Pair;
+import android.util.TypedXmlPullParser;
+import android.util.TypedXmlSerializer;
-import org.xmlpull.v1.XmlPullParser;
import org.xmlpull.v1.XmlPullParserException;
-import org.xmlpull.v1.XmlSerializer;
import java.io.IOException;
import java.lang.annotation.Retention;
@@ -741,38 +741,31 @@ public final class SystemUpdatePolicy implements Parcelable {
* system server from a validated policy object previously.
* @hide
*/
- public static SystemUpdatePolicy restoreFromXml(XmlPullParser parser) {
+ public static SystemUpdatePolicy restoreFromXml(TypedXmlPullParser parser) {
try {
SystemUpdatePolicy policy = new SystemUpdatePolicy();
- String value = parser.getAttributeValue(null, KEY_POLICY_TYPE);
- if (value != null) {
- policy.mPolicyType = Integer.parseInt(value);
-
- value = parser.getAttributeValue(null, KEY_INSTALL_WINDOW_START);
- if (value != null) {
- policy.mMaintenanceWindowStart = Integer.parseInt(value);
- }
- value = parser.getAttributeValue(null, KEY_INSTALL_WINDOW_END);
- if (value != null) {
- policy.mMaintenanceWindowEnd = Integer.parseInt(value);
+ policy.mPolicyType =
+ parser.getAttributeInt(null, KEY_POLICY_TYPE, TYPE_UNKNOWN);
+ policy.mMaintenanceWindowStart =
+ parser.getAttributeInt(null, KEY_INSTALL_WINDOW_START, 0);
+ policy.mMaintenanceWindowEnd =
+ parser.getAttributeInt(null, KEY_INSTALL_WINDOW_END, 0);
+
+ int outerDepth = parser.getDepth();
+ int type;
+ while ((type = parser.next()) != END_DOCUMENT
+ && (type != END_TAG || parser.getDepth() > outerDepth)) {
+ if (type == END_TAG || type == TEXT) {
+ continue;
}
-
- int outerDepth = parser.getDepth();
- int type;
- while ((type = parser.next()) != END_DOCUMENT
- && (type != END_TAG || parser.getDepth() > outerDepth)) {
- if (type == END_TAG || type == TEXT) {
- continue;
- }
- if (!parser.getName().equals(KEY_FREEZE_TAG)) {
- continue;
- }
- policy.mFreezePeriods.add(new FreezePeriod(
- MonthDay.parse(parser.getAttributeValue(null, KEY_FREEZE_START)),
- MonthDay.parse(parser.getAttributeValue(null, KEY_FREEZE_END))));
+ if (!parser.getName().equals(KEY_FREEZE_TAG)) {
+ continue;
}
- return policy;
+ policy.mFreezePeriods.add(new FreezePeriod(
+ MonthDay.parse(parser.getAttributeValue(null, KEY_FREEZE_START)),
+ MonthDay.parse(parser.getAttributeValue(null, KEY_FREEZE_END))));
}
+ return policy;
} catch (NumberFormatException | XmlPullParserException | IOException e) {
// Fail through
Log.w(TAG, "Load xml failed", e);
@@ -783,10 +776,10 @@ public final class SystemUpdatePolicy implements Parcelable {
/**
* @hide
*/
- public void saveToXml(XmlSerializer out) throws IOException {
- out.attribute(null, KEY_POLICY_TYPE, Integer.toString(mPolicyType));
- out.attribute(null, KEY_INSTALL_WINDOW_START, Integer.toString(mMaintenanceWindowStart));
- out.attribute(null, KEY_INSTALL_WINDOW_END, Integer.toString(mMaintenanceWindowEnd));
+ public void saveToXml(TypedXmlSerializer out) throws IOException {
+ out.attributeInt(null, KEY_POLICY_TYPE, mPolicyType);
+ out.attributeInt(null, KEY_INSTALL_WINDOW_START, mMaintenanceWindowStart);
+ out.attributeInt(null, KEY_INSTALL_WINDOW_END, mMaintenanceWindowEnd);
for (int i = 0; i < mFreezePeriods.size(); i++) {
FreezePeriod interval = mFreezePeriods.get(i);
out.startTag(null, KEY_FREEZE_TAG);
diff --git a/core/java/android/app/role/IRoleManager.aidl b/core/java/android/app/role/IRoleManager.aidl
index 6d790b381ace..5fc25f0422e2 100644
--- a/core/java/android/app/role/IRoleManager.aidl
+++ b/core/java/android/app/role/IRoleManager.aidl
@@ -53,5 +53,9 @@ interface IRoleManager {
List<String> getHeldRolesFromController(in String packageName);
- String getDefaultSmsPackage(int userId);
+ String getBrowserRoleHolder(int userId);
+
+ boolean setBrowserRoleHolder(String packageName, int userId);
+
+ String getSmsRoleHolder(int userId);
}
diff --git a/core/java/android/app/role/RoleManager.java b/core/java/android/app/role/RoleManager.java
index 408ce0f2ab1a..8b2e07b09701 100644
--- a/core/java/android/app/role/RoleManager.java
+++ b/core/java/android/app/role/RoleManager.java
@@ -613,12 +613,56 @@ public final class RoleManager {
}
/**
- * Allows getting the role holder for {@link #ROLE_SMS} without
- * {@link Manifest.permission#OBSERVE_ROLE_HOLDERS}, as required by
- * {@link android.provider.Telephony.Sms#getDefaultSmsPackage(Context)}
+ * Get the role holder of {@link #ROLE_BROWSER} without requiring
+ * {@link Manifest.permission#OBSERVE_ROLE_HOLDERS}, as in
+ * {@link android.content.pm.PackageManager#getDefaultBrowserPackageNameAsUser(int)}
+ *
+ * @param userId the user ID
+ * @return the package name of the default browser, or {@code null} if none
+ *
+ * @hide
+ */
+ @Nullable
+ //@SystemApi(client = SystemApi.Client.MODULE_LIBRARIES)
+ public String getBrowserRoleHolder(@UserIdInt int userId) {
+ try {
+ return mService.getBrowserRoleHolder(userId);
+ } catch (RemoteException e) {
+ throw e.rethrowFromSystemServer();
+ }
+ }
+
+ /**
+ * Set the role holder of {@link #ROLE_BROWSER} requiring
+ * {@link Manifest.permission.SET_PREFERRED_APPLICATIONS} instead of
+ * {@link Manifest.permission#MANAGE_ROLE_HOLDERS}, as in
+ * {@link android.content.pm.PackageManager#setDefaultBrowserPackageNameAsUser(String, int)}
+ *
+ * @param packageName the package name of the default browser, or {@code null} if none
+ * @param userId the user ID
+ * @return whether the default browser was set successfully
+ *
+ * @hide
+ */
+ @Nullable
+ @RequiresPermission(Manifest.permission.SET_PREFERRED_APPLICATIONS)
+ //@SystemApi(client = SystemApi.Client.MODULE_LIBRARIES)
+ public boolean setBrowserRoleHolder(@Nullable String packageName, @UserIdInt int userId) {
+ try {
+ return mService.setBrowserRoleHolder(packageName, userId);
+ } catch (RemoteException e) {
+ throw e.rethrowFromSystemServer();
+ }
+ }
+
+ /**
+ * Allows getting the role holder for {@link #ROLE_SMS} without requiring
+ * {@link Manifest.permission#OBSERVE_ROLE_HOLDERS}, as in
+ * {@link android.provider.Telephony.Sms#getDefaultSmsPackage(Context)}.
+ *
+ * @param userId the user ID to get the default SMS package for
+ * @return the package name of the default SMS app, or {@code null} if none
*
- * @param userId The user ID to get the default SMS package for.
- * @return the package name of the default SMS app, or {@code null} if not configured.
* @hide
*/
@Nullable
@@ -626,7 +670,7 @@ public final class RoleManager {
@TestApi
public String getSmsRoleHolder(@UserIdInt int userId) {
try {
- return mService.getDefaultSmsPackage(userId);
+ return mService.getSmsRoleHolder(userId);
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
}
diff --git a/core/java/android/appwidget/AppWidgetProviderInfo.java b/core/java/android/appwidget/AppWidgetProviderInfo.java
index 130a20dfb07b..c4333ac44e34 100644
--- a/core/java/android/appwidget/AppWidgetProviderInfo.java
+++ b/core/java/android/appwidget/AppWidgetProviderInfo.java
@@ -68,6 +68,9 @@ public class AppWidgetProviderInfo implements Parcelable {
@Retention(RetentionPolicy.SOURCE)
public @interface ResizeModeFlags {}
+ /** {@hide} */
+ public static final int WIDGET_CATEGORY_UNKNOWN = -1;
+
/**
* Indicates that the widget can be displayed on the home screen. This is the default value.
*/
diff --git a/core/java/android/content/SyncAdaptersCache.java b/core/java/android/content/SyncAdaptersCache.java
index 58445a7f9242..495f94f98f95 100644
--- a/core/java/android/content/SyncAdaptersCache.java
+++ b/core/java/android/content/SyncAdaptersCache.java
@@ -25,12 +25,12 @@ import android.text.TextUtils;
import android.util.ArrayMap;
import android.util.AttributeSet;
import android.util.SparseArray;
+import android.util.TypedXmlPullParser;
+import android.util.TypedXmlSerializer;
import com.android.internal.annotations.GuardedBy;
-import org.xmlpull.v1.XmlPullParser;
import org.xmlpull.v1.XmlPullParserException;
-import org.xmlpull.v1.XmlSerializer;
import java.io.IOException;
import java.util.ArrayList;
@@ -142,12 +142,12 @@ public class SyncAdaptersCache extends RegisteredServicesCache<SyncAdapterType>
}
static class MySerializer implements XmlSerializerAndParser<SyncAdapterType> {
- public void writeAsXml(SyncAdapterType item, XmlSerializer out) throws IOException {
+ public void writeAsXml(SyncAdapterType item, TypedXmlSerializer out) throws IOException {
out.attribute(null, "authority", item.authority);
out.attribute(null, "accountType", item.accountType);
}
- public SyncAdapterType createFromXml(XmlPullParser parser)
+ public SyncAdapterType createFromXml(TypedXmlPullParser parser)
throws IOException, XmlPullParserException {
final String authority = parser.getAttributeValue(null, "authority");
final String accountType = parser.getAttributeValue(null, "accountType");
diff --git a/core/java/android/content/pm/IPackageInstallerSession.aidl b/core/java/android/content/pm/IPackageInstallerSession.aidl
index 6ccbc36e26f6..9a73be9d44a4 100644
--- a/core/java/android/content/pm/IPackageInstallerSession.aidl
+++ b/core/java/android/content/pm/IPackageInstallerSession.aidl
@@ -33,6 +33,7 @@ interface IPackageInstallerSession {
ParcelFileDescriptor openRead(String name);
void write(String name, long offsetBytes, long lengthBytes, in ParcelFileDescriptor fd);
+ void stageViaHardLink(String target);
void addChecksums(String name, in Checksum[] checksums);
diff --git a/core/java/android/content/pm/IntentFilterVerificationInfo.java b/core/java/android/content/pm/IntentFilterVerificationInfo.java
index 0a913acba9f5..56b8bd80a06a 100644
--- a/core/java/android/content/pm/IntentFilterVerificationInfo.java
+++ b/core/java/android/content/pm/IntentFilterVerificationInfo.java
@@ -16,11 +16,11 @@
package android.content.pm;
-import static android.content.pm.PackageManager.INTENT_FILTER_DOMAIN_VERIFICATION_STATUS_UNDEFINED;
-import static android.content.pm.PackageManager.INTENT_FILTER_DOMAIN_VERIFICATION_STATUS_ASK;
import static android.content.pm.PackageManager.INTENT_FILTER_DOMAIN_VERIFICATION_STATUS_ALWAYS;
import static android.content.pm.PackageManager.INTENT_FILTER_DOMAIN_VERIFICATION_STATUS_ALWAYS_ASK;
+import static android.content.pm.PackageManager.INTENT_FILTER_DOMAIN_VERIFICATION_STATUS_ASK;
import static android.content.pm.PackageManager.INTENT_FILTER_DOMAIN_VERIFICATION_STATUS_NEVER;
+import static android.content.pm.PackageManager.INTENT_FILTER_DOMAIN_VERIFICATION_STATUS_UNDEFINED;
import android.annotation.SystemApi;
import android.os.Parcel;
@@ -28,12 +28,13 @@ import android.os.Parcelable;
import android.text.TextUtils;
import android.util.ArraySet;
import android.util.Log;
+import android.util.TypedXmlPullParser;
+import android.util.TypedXmlSerializer;
import com.android.internal.util.XmlUtils;
import org.xmlpull.v1.XmlPullParser;
import org.xmlpull.v1.XmlPullParserException;
-import org.xmlpull.v1.XmlSerializer;
import java.io.IOException;
import java.util.ArrayList;
@@ -72,7 +73,7 @@ public final class IntentFilterVerificationInfo implements Parcelable {
}
/** @hide */
- public IntentFilterVerificationInfo(XmlPullParser parser)
+ public IntentFilterVerificationInfo(TypedXmlPullParser parser)
throws IOException, XmlPullParserException {
readFromXml(parser);
}
@@ -121,7 +122,7 @@ public final class IntentFilterVerificationInfo implements Parcelable {
return sb.toString();
}
- String getStringFromXml(XmlPullParser parser, String attribute, String defaultValue) {
+ String getStringFromXml(TypedXmlPullParser parser, String attribute, String defaultValue) {
String value = parser.getAttributeValue(null, attribute);
if (value == null) {
String msg = "Missing element under " + TAG +": " + attribute + " at " +
@@ -133,20 +134,12 @@ public final class IntentFilterVerificationInfo implements Parcelable {
}
}
- int getIntFromXml(XmlPullParser parser, String attribute, int defaultValue) {
- String value = parser.getAttributeValue(null, attribute);
- if (TextUtils.isEmpty(value)) {
- String msg = "Missing element under " + TAG +": " + attribute + " at " +
- parser.getPositionDescription();
- Log.w(TAG, msg);
- return defaultValue;
- } else {
- return Integer.parseInt(value);
- }
+ int getIntFromXml(TypedXmlPullParser parser, String attribute, int defaultValue) {
+ return parser.getAttributeInt(null, attribute, defaultValue);
}
/** @hide */
- public void readFromXml(XmlPullParser parser) throws XmlPullParserException,
+ public void readFromXml(TypedXmlPullParser parser) throws XmlPullParserException,
IOException {
mPackageName = getStringFromXml(parser, ATTR_PACKAGE_NAME, null);
if (mPackageName == null) {
@@ -182,9 +175,9 @@ public final class IntentFilterVerificationInfo implements Parcelable {
}
/** @hide */
- public void writeToXml(XmlSerializer serializer) throws IOException {
+ public void writeToXml(TypedXmlSerializer serializer) throws IOException {
serializer.attribute(null, ATTR_PACKAGE_NAME, mPackageName);
- serializer.attribute(null, ATTR_STATUS, String.valueOf(mStatus));
+ serializer.attributeInt(null, ATTR_STATUS, mStatus);
for (String str : mDomains) {
serializer.startTag(null, TAG_DOMAIN);
serializer.attribute(null, ATTR_DOMAIN_NAME, str);
diff --git a/core/java/android/content/pm/PackageInstaller.java b/core/java/android/content/pm/PackageInstaller.java
index 0dcfd38294b9..d4a98f82a4f7 100644
--- a/core/java/android/content/pm/PackageInstaller.java
+++ b/core/java/android/content/pm/PackageInstaller.java
@@ -1049,6 +1049,31 @@ public class PackageInstaller {
}
/**
+ * Populate an APK file by creating a hard link to avoid the need to copy.
+ * <p>
+ * Note this API is used by RollbackManager only and can only be called from system_server.
+ * {@code target} will be relabeled if link is created successfully. RollbackManager has
+ * to delete {@code target} when the session is committed successfully to avoid SELinux
+ * label conflicts.
+ * <p>
+ * Note No more bytes should be written to the file once the link is created successfully.
+ *
+ * @param target the path of the link target
+ *
+ * @hide
+ */
+ public void stageViaHardLink(String target) throws IOException {
+ try {
+ mSession.stageViaHardLink(target);
+ } catch (RuntimeException e) {
+ ExceptionUtils.maybeUnwrapIOException(e);
+ throw e;
+ } catch (RemoteException e) {
+ throw e.rethrowFromSystemServer();
+ }
+ }
+
+ /**
* Ensure that any outstanding data for given stream has been committed
* to disk. This is only valid for streams returned from
* {@link #openWrite(String, long, long)}.
diff --git a/core/java/android/content/pm/PackageUserState.java b/core/java/android/content/pm/PackageUserState.java
index 2fca980e764c..99258712030c 100644
--- a/core/java/android/content/pm/PackageUserState.java
+++ b/core/java/android/content/pm/PackageUserState.java
@@ -41,6 +41,8 @@ import android.util.ArraySet;
import android.util.DebugUtils;
import android.util.Pair;
import android.util.Slog;
+import android.util.TypedXmlPullParser;
+import android.util.TypedXmlSerializer;
import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.util.ArrayUtils;
@@ -560,7 +562,7 @@ public class PackageUserState {
* @param out the {@link XmlSerializer} object
* @throws IOException
*/
- public void saveToXml(XmlSerializer out) throws IOException {
+ public void saveToXml(TypedXmlSerializer out) throws IOException {
if (dialogInfo != null) {
out.startTag(null, TAG_DIALOG_INFO);
dialogInfo.saveToXml(out);
@@ -594,7 +596,7 @@ public class PackageUserState {
* @param in the reader
* @return
*/
- public static SuspendParams restoreFromXml(XmlPullParser in) throws IOException {
+ public static SuspendParams restoreFromXml(TypedXmlPullParser in) throws IOException {
SuspendDialogInfo readDialogInfo = null;
PersistableBundle readAppExtras = null;
PersistableBundle readLauncherExtras = null;
diff --git a/core/java/android/content/pm/RegisteredServicesCache.java b/core/java/android/content/pm/RegisteredServicesCache.java
index 192470e964e0..7ecb11248d23 100644
--- a/core/java/android/content/pm/RegisteredServicesCache.java
+++ b/core/java/android/content/pm/RegisteredServicesCache.java
@@ -36,21 +36,21 @@ import android.util.IntArray;
import android.util.Log;
import android.util.Slog;
import android.util.SparseArray;
+import android.util.TypedXmlPullParser;
+import android.util.TypedXmlSerializer;
import android.util.Xml;
import com.android.internal.annotations.GuardedBy;
import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.util.ArrayUtils;
-import com.android.internal.util.FastXmlSerializer;
+
+import libcore.io.IoUtils;
import com.google.android.collect.Lists;
import com.google.android.collect.Maps;
-import libcore.io.IoUtils;
-
import org.xmlpull.v1.XmlPullParser;
import org.xmlpull.v1.XmlPullParserException;
-import org.xmlpull.v1.XmlSerializer;
import java.io.File;
import java.io.FileDescriptor;
@@ -58,7 +58,6 @@ import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.PrintWriter;
-import java.nio.charset.StandardCharsets;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
@@ -672,8 +671,7 @@ public abstract class RegisteredServicesCache<V> {
*/
private void readPersistentServicesLocked(InputStream is)
throws XmlPullParserException, IOException {
- XmlPullParser parser = Xml.newPullParser();
- parser.setInput(is, StandardCharsets.UTF_8.name());
+ TypedXmlPullParser parser = Xml.resolvePullParser(is);
int eventType = parser.getEventType();
while (eventType != XmlPullParser.START_TAG
&& eventType != XmlPullParser.END_DOCUMENT) {
@@ -690,8 +688,7 @@ public abstract class RegisteredServicesCache<V> {
if (service == null) {
break;
}
- String uidString = parser.getAttributeValue(null, "uid");
- final int uid = Integer.parseInt(uidString);
+ final int uid = parser.getAttributeInt(null, "uid");
final int userId = UserHandle.getUserId(uid);
final UserServices<V> user = findOrCreateUserLocked(userId,
false /*loadFromFileIfNew*/) ;
@@ -762,14 +759,13 @@ public abstract class RegisteredServicesCache<V> {
FileOutputStream fos = null;
try {
fos = atomicFile.startWrite();
- XmlSerializer out = new FastXmlSerializer();
- out.setOutput(fos, StandardCharsets.UTF_8.name());
+ TypedXmlSerializer out = Xml.resolveSerializer(fos);
out.startDocument(null, true);
out.setFeature("http://xmlpull.org/v1/doc/features.html#indent-output", true);
out.startTag(null, "services");
for (Map.Entry<V, Integer> service : user.persistentServices.entrySet()) {
out.startTag(null, "service");
- out.attribute(null, "uid", Integer.toString(service.getValue()));
+ out.attributeInt(null, "uid", service.getValue());
mSerializerAndParser.writeAsXml(service.getKey(), out);
out.endTag(null, "service");
}
diff --git a/core/java/android/content/pm/SuspendDialogInfo.java b/core/java/android/content/pm/SuspendDialogInfo.java
index 851a08116f56..60f321883e98 100644
--- a/core/java/android/content/pm/SuspendDialogInfo.java
+++ b/core/java/android/content/pm/SuspendDialogInfo.java
@@ -29,13 +29,12 @@ import android.os.Parcel;
import android.os.Parcelable;
import android.os.PersistableBundle;
import android.util.Slog;
+import android.util.TypedXmlPullParser;
+import android.util.TypedXmlSerializer;
import com.android.internal.util.Preconditions;
import com.android.internal.util.XmlUtils;
-import org.xmlpull.v1.XmlPullParser;
-import org.xmlpull.v1.XmlSerializer;
-
import java.io.IOException;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
@@ -169,38 +168,38 @@ public final class SuspendDialogInfo implements Parcelable {
/**
* @hide
*/
- public void saveToXml(XmlSerializer out) throws IOException {
+ public void saveToXml(TypedXmlSerializer out) throws IOException {
if (mIconResId != ID_NULL) {
- XmlUtils.writeIntAttribute(out, XML_ATTR_ICON_RES_ID, mIconResId);
+ out.attributeInt(null, XML_ATTR_ICON_RES_ID, mIconResId);
}
if (mTitleResId != ID_NULL) {
- XmlUtils.writeIntAttribute(out, XML_ATTR_TITLE_RES_ID, mTitleResId);
+ out.attributeInt(null, XML_ATTR_TITLE_RES_ID, mTitleResId);
}
if (mDialogMessageResId != ID_NULL) {
- XmlUtils.writeIntAttribute(out, XML_ATTR_DIALOG_MESSAGE_RES_ID, mDialogMessageResId);
+ out.attributeInt(null, XML_ATTR_DIALOG_MESSAGE_RES_ID, mDialogMessageResId);
} else {
XmlUtils.writeStringAttribute(out, XML_ATTR_DIALOG_MESSAGE, mDialogMessage);
}
if (mNeutralButtonTextResId != ID_NULL) {
- XmlUtils.writeIntAttribute(out, XML_ATTR_BUTTON_TEXT_RES_ID, mNeutralButtonTextResId);
+ out.attributeInt(null, XML_ATTR_BUTTON_TEXT_RES_ID, mNeutralButtonTextResId);
}
- XmlUtils.writeIntAttribute(out, XML_ATTR_BUTTON_ACTION, mNeutralButtonAction);
+ out.attributeInt(null, XML_ATTR_BUTTON_ACTION, mNeutralButtonAction);
}
/**
* @hide
*/
- public static SuspendDialogInfo restoreFromXml(XmlPullParser in) {
+ public static SuspendDialogInfo restoreFromXml(TypedXmlPullParser in) {
final SuspendDialogInfo.Builder dialogInfoBuilder = new SuspendDialogInfo.Builder();
try {
- final int iconId = XmlUtils.readIntAttribute(in, XML_ATTR_ICON_RES_ID, ID_NULL);
- final int titleId = XmlUtils.readIntAttribute(in, XML_ATTR_TITLE_RES_ID, ID_NULL);
- final int buttonTextId = XmlUtils.readIntAttribute(in, XML_ATTR_BUTTON_TEXT_RES_ID,
- ID_NULL);
- final int buttonAction = XmlUtils.readIntAttribute(in, XML_ATTR_BUTTON_ACTION,
- BUTTON_ACTION_MORE_DETAILS);
- final int dialogMessageResId = XmlUtils.readIntAttribute(
- in, XML_ATTR_DIALOG_MESSAGE_RES_ID, ID_NULL);
+ final int iconId = in.getAttributeInt(null, XML_ATTR_ICON_RES_ID, ID_NULL);
+ final int titleId = in.getAttributeInt(null, XML_ATTR_TITLE_RES_ID, ID_NULL);
+ final int buttonTextId =
+ in.getAttributeInt(null, XML_ATTR_BUTTON_TEXT_RES_ID, ID_NULL);
+ final int buttonAction =
+ in.getAttributeInt(null, XML_ATTR_BUTTON_ACTION, BUTTON_ACTION_MORE_DETAILS);
+ final int dialogMessageResId =
+ in.getAttributeInt(null, XML_ATTR_DIALOG_MESSAGE_RES_ID, ID_NULL);
final String dialogMessage = XmlUtils.readStringAttribute(in, XML_ATTR_DIALOG_MESSAGE);
if (iconId != ID_NULL) {
diff --git a/core/java/android/content/pm/XmlSerializerAndParser.java b/core/java/android/content/pm/XmlSerializerAndParser.java
index 5dce83902f78..51cd6ca60f59 100644
--- a/core/java/android/content/pm/XmlSerializerAndParser.java
+++ b/core/java/android/content/pm/XmlSerializerAndParser.java
@@ -17,6 +17,10 @@
package android.content.pm;
import android.compat.annotation.UnsupportedAppUsage;
+import android.util.TypedXmlPullParser;
+import android.util.TypedXmlSerializer;
+
+import com.android.internal.util.XmlUtils;
import org.xmlpull.v1.XmlPullParser;
import org.xmlpull.v1.XmlPullParserException;
@@ -26,8 +30,16 @@ import java.io.IOException;
/** @hide */
public interface XmlSerializerAndParser<T> {
+ void writeAsXml(T item, TypedXmlSerializer out) throws IOException;
+ T createFromXml(TypedXmlPullParser parser) throws IOException, XmlPullParserException;
+
@UnsupportedAppUsage
- void writeAsXml(T item, XmlSerializer out) throws IOException;
+ default void writeAsXml(T item, XmlSerializer out) throws IOException {
+ writeAsXml(item, XmlUtils.makeTyped(out));
+ }
+
@UnsupportedAppUsage
- T createFromXml(XmlPullParser parser) throws IOException, XmlPullParserException;
+ default T createFromXml(XmlPullParser parser) throws IOException, XmlPullParserException {
+ return createFromXml(XmlUtils.makeTyped(parser));
+ }
}
diff --git a/core/java/android/hardware/display/BrightnessConfiguration.java b/core/java/android/hardware/display/BrightnessConfiguration.java
index d9c1063cd39d..366734e9bf11 100644
--- a/core/java/android/hardware/display/BrightnessConfiguration.java
+++ b/core/java/android/hardware/display/BrightnessConfiguration.java
@@ -24,13 +24,13 @@ import android.content.pm.ApplicationInfo;
import android.os.Parcel;
import android.os.Parcelable;
import android.util.Pair;
+import android.util.TypedXmlPullParser;
+import android.util.TypedXmlSerializer;
import com.android.internal.util.Preconditions;
import com.android.internal.util.XmlUtils;
-import org.xmlpull.v1.XmlPullParser;
import org.xmlpull.v1.XmlPullParserException;
-import org.xmlpull.v1.XmlSerializer;
import java.io.IOException;
import java.util.ArrayList;
@@ -343,15 +343,15 @@ public final class BrightnessConfiguration implements Parcelable {
*
* @hide
*/
- public void saveToXml(@NonNull XmlSerializer serializer) throws IOException {
+ public void saveToXml(@NonNull TypedXmlSerializer serializer) throws IOException {
serializer.startTag(null, TAG_BRIGHTNESS_CURVE);
if (mDescription != null) {
serializer.attribute(null, ATTR_DESCRIPTION, mDescription);
}
for (int i = 0; i < mLux.length; i++) {
serializer.startTag(null, TAG_BRIGHTNESS_POINT);
- serializer.attribute(null, ATTR_LUX, Float.toString(mLux[i]));
- serializer.attribute(null, ATTR_NITS, Float.toString(mNits[i]));
+ serializer.attributeFloat(null, ATTR_LUX, mLux[i]);
+ serializer.attributeFloat(null, ATTR_NITS, mNits[i]);
serializer.endTag(null, TAG_BRIGHTNESS_POINT);
}
serializer.endTag(null, TAG_BRIGHTNESS_CURVE);
@@ -370,7 +370,7 @@ public final class BrightnessConfiguration implements Parcelable {
final int category = entry.getKey();
final BrightnessCorrection correction = entry.getValue();
serializer.startTag(null, TAG_BRIGHTNESS_CORRECTION);
- serializer.attribute(null, ATTR_CATEGORY, Integer.toString(category));
+ serializer.attributeInt(null, ATTR_CATEGORY, category);
correction.saveToXml(serializer);
serializer.endTag(null, TAG_BRIGHTNESS_CORRECTION);
}
@@ -378,19 +378,18 @@ public final class BrightnessConfiguration implements Parcelable {
serializer.startTag(null, TAG_BRIGHTNESS_PARAMS);
if (mShouldCollectColorSamples) {
- serializer.attribute(null, ATTR_COLLECT_COLOR, Boolean.toString(true));
+ serializer.attributeBoolean(null, ATTR_COLLECT_COLOR, true);
}
if (mShortTermModelTimeout >= 0) {
- serializer.attribute(null, ATTR_MODEL_TIMEOUT,
- Long.toString(mShortTermModelTimeout));
+ serializer.attributeLong(null, ATTR_MODEL_TIMEOUT, mShortTermModelTimeout);
}
if (!Float.isNaN(mShortTermModelLowerLuxMultiplier)) {
- serializer.attribute(null, ATTR_MODEL_LOWER_BOUND,
- Float.toString(mShortTermModelLowerLuxMultiplier));
+ serializer.attributeFloat(null, ATTR_MODEL_LOWER_BOUND,
+ mShortTermModelLowerLuxMultiplier);
}
if (!Float.isNaN(mShortTermModelUpperLuxMultiplier)) {
- serializer.attribute(null, ATTR_MODEL_UPPER_BOUND,
- Float.toString(mShortTermModelUpperLuxMultiplier));
+ serializer.attributeFloat(null, ATTR_MODEL_UPPER_BOUND,
+ mShortTermModelUpperLuxMultiplier);
}
serializer.endTag(null, TAG_BRIGHTNESS_PARAMS);
}
@@ -408,7 +407,7 @@ public final class BrightnessConfiguration implements Parcelable {
*
* @hide
*/
- public static BrightnessConfiguration loadFromXml(@NonNull XmlPullParser parser)
+ public static BrightnessConfiguration loadFromXml(@NonNull TypedXmlPullParser parser)
throws IOException, XmlPullParserException {
String description = null;
List<Float> luxList = new ArrayList<>();
@@ -440,22 +439,17 @@ public final class BrightnessConfiguration implements Parcelable {
continue;
}
final String packageName = parser.getAttributeValue(null, ATTR_PACKAGE_NAME);
- final String categoryText = parser.getAttributeValue(null, ATTR_CATEGORY);
+ final int category = parser.getAttributeInt(null, ATTR_CATEGORY, -1);
BrightnessCorrection correction = BrightnessCorrection.loadFromXml(parser);
if (packageName != null) {
correctionsByPackageName.put(packageName, correction);
- } else if (categoryText != null) {
- try {
- final int category = Integer.parseInt(categoryText);
- correctionsByCategory.put(category, correction);
- } catch (NullPointerException | NumberFormatException e) {
- continue;
- }
+ } else if (category != -1) {
+ correctionsByCategory.put(category, correction);
}
}
} else if (TAG_BRIGHTNESS_PARAMS.equals(parser.getName())) {
shouldCollectColorSamples =
- Boolean.parseBoolean(parser.getAttributeValue(null, ATTR_COLLECT_COLOR));
+ parser.getAttributeBoolean(null, ATTR_COLLECT_COLOR, false);
Long timeout = loadLongFromXml(parser, ATTR_MODEL_TIMEOUT);
if (timeout != null) {
shortTermModelTimeout = timeout;
@@ -491,23 +485,16 @@ public final class BrightnessConfiguration implements Parcelable {
return builder.build();
}
- private static float loadFloatFromXml(XmlPullParser parser, String attribute) {
- final String string = parser.getAttributeValue(null, attribute);
- try {
- return Float.parseFloat(string);
- } catch (NullPointerException | NumberFormatException e) {
- return Float.NaN;
- }
+ private static float loadFloatFromXml(TypedXmlPullParser parser, String attribute) {
+ return parser.getAttributeFloat(null, attribute, Float.NaN);
}
- private static Long loadLongFromXml(XmlPullParser parser, String attribute) {
- final String string = parser.getAttributeValue(null, attribute);
+ private static Long loadLongFromXml(TypedXmlPullParser parser, String attribute) {
try {
- return Long.parseLong(string);
- } catch (NullPointerException | NumberFormatException e) {
- // Ignoring
+ return parser.getAttributeLong(null, attribute);
+ } catch (Exception e) {
+ return null;
}
- return null;
}
/**
diff --git a/core/java/android/hardware/display/BrightnessCorrection.java b/core/java/android/hardware/display/BrightnessCorrection.java
index bbfc45edb89a..2919ec3fbf08 100644
--- a/core/java/android/hardware/display/BrightnessCorrection.java
+++ b/core/java/android/hardware/display/BrightnessCorrection.java
@@ -23,12 +23,12 @@ import android.annotation.SystemApi;
import android.os.Parcel;
import android.os.Parcelable;
import android.util.MathUtils;
+import android.util.TypedXmlPullParser;
+import android.util.TypedXmlSerializer;
import com.android.internal.util.XmlUtils;
-import org.xmlpull.v1.XmlPullParser;
import org.xmlpull.v1.XmlPullParserException;
-import org.xmlpull.v1.XmlSerializer;
import java.io.IOException;
@@ -153,7 +153,7 @@ public final class BrightnessCorrection implements Parcelable {
*
* @hide
*/
- public void saveToXml(XmlSerializer serializer) throws IOException {
+ public void saveToXml(TypedXmlSerializer serializer) throws IOException {
mImplementation.saveToXml(serializer);
}
@@ -170,7 +170,7 @@ public final class BrightnessCorrection implements Parcelable {
*
* @hide
*/
- public static BrightnessCorrection loadFromXml(XmlPullParser parser) throws IOException,
+ public static BrightnessCorrection loadFromXml(TypedXmlPullParser parser) throws IOException,
XmlPullParserException {
final int depth = parser.getDepth();
while (XmlUtils.nextElementWithin(parser, depth)) {
@@ -181,20 +181,15 @@ public final class BrightnessCorrection implements Parcelable {
return null;
}
- private static float loadFloatFromXml(XmlPullParser parser, String attribute) {
- final String string = parser.getAttributeValue(null, attribute);
- try {
- return Float.parseFloat(string);
- } catch (NullPointerException | NumberFormatException e) {
- return Float.NaN;
- }
+ private static float loadFloatFromXml(TypedXmlPullParser parser, String attribute) {
+ return parser.getAttributeFloat(null, attribute, Float.NaN);
}
private interface BrightnessCorrectionImplementation {
float apply(float brightness);
String toString();
void writeToParcel(Parcel dest);
- void saveToXml(XmlSerializer serializer) throws IOException;
+ void saveToXml(TypedXmlSerializer serializer) throws IOException;
// Package-private static methods:
// static BrightnessCorrection readFromParcel(Parcel in);
// static BrightnessCorrection loadFromXml(XmlPullParser parser) throws IOException,
@@ -263,10 +258,10 @@ public final class BrightnessCorrection implements Parcelable {
}
@Override
- public void saveToXml(XmlSerializer serializer) throws IOException {
+ public void saveToXml(TypedXmlSerializer serializer) throws IOException {
serializer.startTag(null, TAG_SCALE_AND_TRANSLATE_LOG);
- serializer.attribute(null, ATTR_SCALE, Float.toString(mScale));
- serializer.attribute(null, ATTR_TRANSLATE, Float.toString(mTranslate));
+ serializer.attributeFloat(null, ATTR_SCALE, mScale);
+ serializer.attributeFloat(null, ATTR_TRANSLATE, mTranslate);
serializer.endTag(null, TAG_SCALE_AND_TRANSLATE_LOG);
}
@@ -276,7 +271,7 @@ public final class BrightnessCorrection implements Parcelable {
return BrightnessCorrection.createScaleAndTranslateLog(scale, translate);
}
- static BrightnessCorrection loadFromXml(XmlPullParser parser) throws IOException,
+ static BrightnessCorrection loadFromXml(TypedXmlPullParser parser) throws IOException,
XmlPullParserException {
final float scale = loadFloatFromXml(parser, ATTR_SCALE);
final float translate = loadFloatFromXml(parser, ATTR_TRANSLATE);
diff --git a/core/java/android/net/Ikev2VpnProfile.java b/core/java/android/net/Ikev2VpnProfile.java
index 9876fc650f21..183f500572bd 100644
--- a/core/java/android/net/Ikev2VpnProfile.java
+++ b/core/java/android/net/Ikev2VpnProfile.java
@@ -16,12 +16,9 @@
package android.net;
-import static android.net.PlatformVpnProfile.TYPE_IKEV2_IPSEC_PSK;
-import static android.net.PlatformVpnProfile.TYPE_IKEV2_IPSEC_RSA;
-import static android.net.PlatformVpnProfile.TYPE_IKEV2_IPSEC_USER_PASS;
-
import static com.android.internal.annotations.VisibleForTesting.Visibility;
import static com.android.internal.util.Preconditions.checkStringNotEmpty;
+import static com.android.net.module.util.NetworkStackConstants.IPV6_MIN_MTU;
import android.annotation.NonNull;
import android.annotation.Nullable;
@@ -158,9 +155,8 @@ public final class Ikev2VpnProfile extends PlatformVpnProfile {
// IPv6 MTU is greater; since profiles may be started by the system on IPv4 and IPv6
// networks, the VPN must provide a link fulfilling the stricter of the two conditions
// (at least that of the IPv6 MTU).
- if (mMaxMtu < LinkProperties.MIN_MTU_V6) {
- throw new IllegalArgumentException(
- "Max MTU must be at least" + LinkProperties.MIN_MTU_V6);
+ if (mMaxMtu < IPV6_MIN_MTU) {
+ throw new IllegalArgumentException("Max MTU must be at least" + IPV6_MIN_MTU);
}
switch (mType) {
@@ -811,9 +807,8 @@ public final class Ikev2VpnProfile extends PlatformVpnProfile {
// IPv6 MTU is greater; since profiles may be started by the system on IPv4 and IPv6
// networks, the VPN must provide a link fulfilling the stricter of the two conditions
// (at least that of the IPv6 MTU).
- if (mtu < LinkProperties.MIN_MTU_V6) {
- throw new IllegalArgumentException(
- "Max MTU must be at least " + LinkProperties.MIN_MTU_V6);
+ if (mtu < IPV6_MIN_MTU) {
+ throw new IllegalArgumentException("Max MTU must be at least " + IPV6_MIN_MTU);
}
mMaxMtu = mtu;
return this;
diff --git a/core/java/android/net/IpSecTransform.java b/core/java/android/net/IpSecTransform.java
index fa1497dcbc43..b48c1fdaf1b2 100644
--- a/core/java/android/net/IpSecTransform.java
+++ b/core/java/android/net/IpSecTransform.java
@@ -17,8 +17,6 @@ package android.net;
import static android.net.IpSecManager.INVALID_RESOURCE_ID;
-import static com.android.internal.util.Preconditions.checkNotNull;
-
import android.annotation.IntDef;
import android.annotation.NonNull;
import android.annotation.Nullable;
@@ -28,7 +26,6 @@ import android.annotation.SystemApi;
import android.content.Context;
import android.content.pm.PackageManager;
import android.os.Binder;
-import android.os.Handler;
import android.os.IBinder;
import android.os.RemoteException;
import android.os.ServiceManager;
@@ -182,7 +179,6 @@ public final class IpSecTransform implements AutoCloseable {
try {
IIpSecService svc = getIpSecService();
svc.deleteTransform(mResourceId);
- stopNattKeepalive();
} catch (RemoteException e) {
throw e.rethrowAsRuntimeException();
} catch (Exception e) {
@@ -213,36 +209,6 @@ public final class IpSecTransform implements AutoCloseable {
private int mResourceId;
private final Context mContext;
private final CloseGuard mCloseGuard = CloseGuard.get();
- private ConnectivityManager.PacketKeepalive mKeepalive;
- private Handler mCallbackHandler;
- private final ConnectivityManager.PacketKeepaliveCallback mKeepaliveCallback =
- new ConnectivityManager.PacketKeepaliveCallback() {
-
- @Override
- public void onStarted() {
- synchronized (this) {
- mCallbackHandler.post(() -> mUserKeepaliveCallback.onStarted());
- }
- }
-
- @Override
- public void onStopped() {
- synchronized (this) {
- mKeepalive = null;
- mCallbackHandler.post(() -> mUserKeepaliveCallback.onStopped());
- }
- }
-
- @Override
- public void onError(int error) {
- synchronized (this) {
- mKeepalive = null;
- mCallbackHandler.post(() -> mUserKeepaliveCallback.onError(error));
- }
- }
- };
-
- private NattKeepaliveCallback mUserKeepaliveCallback;
/** @hide */
@VisibleForTesting
@@ -274,76 +240,6 @@ public final class IpSecTransform implements AutoCloseable {
public void onError(int error) {}
}
- /**
- * Start a NAT-T keepalive session for the current transform.
- *
- * For a transform that is using UDP encapsulated IPv4, NAT-T offloading provides
- * a power efficient mechanism of sending NAT-T packets at a specified interval.
- *
- * @param userCallback a {@link #NattKeepaliveCallback} to receive asynchronous status
- * information about the requested NAT-T keepalive session.
- * @param intervalSeconds the interval between NAT-T keepalives being sent. The
- * the allowed range is between 20 and 3600 seconds.
- * @param handler a handler on which to post callbacks when received.
- *
- * @hide
- */
- @RequiresPermission(anyOf = {
- android.Manifest.permission.MANAGE_IPSEC_TUNNELS,
- android.Manifest.permission.PACKET_KEEPALIVE_OFFLOAD
- })
- public void startNattKeepalive(@NonNull NattKeepaliveCallback userCallback,
- int intervalSeconds, @NonNull Handler handler) throws IOException {
- checkNotNull(userCallback);
- if (intervalSeconds < 20 || intervalSeconds > 3600) {
- throw new IllegalArgumentException("Invalid NAT-T keepalive interval");
- }
- checkNotNull(handler);
- if (mResourceId == INVALID_RESOURCE_ID) {
- throw new IllegalStateException(
- "Packet keepalive cannot be started for an inactive transform");
- }
-
- synchronized (mKeepaliveCallback) {
- if (mKeepaliveCallback != null) {
- throw new IllegalStateException("Keepalive already active");
- }
-
- mUserKeepaliveCallback = userCallback;
- ConnectivityManager cm = (ConnectivityManager) mContext.getSystemService(
- Context.CONNECTIVITY_SERVICE);
- mKeepalive = cm.startNattKeepalive(
- mConfig.getNetwork(), intervalSeconds, mKeepaliveCallback,
- NetworkUtils.numericToInetAddress(mConfig.getSourceAddress()),
- 4500, // FIXME urgently, we need to get the port number from the Encap socket
- NetworkUtils.numericToInetAddress(mConfig.getDestinationAddress()));
- mCallbackHandler = handler;
- }
- }
-
- /**
- * Stop an ongoing NAT-T keepalive session.
- *
- * Calling this API will request that an ongoing NAT-T keepalive session be terminated.
- * If this API is not called when a Transform is closed, the underlying NAT-T session will
- * be terminated automatically.
- *
- * @hide
- */
- @RequiresPermission(anyOf = {
- android.Manifest.permission.MANAGE_IPSEC_TUNNELS,
- android.Manifest.permission.PACKET_KEEPALIVE_OFFLOAD
- })
- public void stopNattKeepalive() {
- synchronized (mKeepaliveCallback) {
- if (mKeepalive == null) {
- Log.e(TAG, "No active keepalive to stop");
- return;
- }
- mKeepalive.stop();
- }
- }
-
/** This class is used to build {@link IpSecTransform} objects. */
public static class Builder {
private Context mContext;
diff --git a/core/java/android/net/LinkProperties.java b/core/java/android/net/LinkProperties.java
index 81e6e788734b..e41ed72b259c 100644
--- a/core/java/android/net/LinkProperties.java
+++ b/core/java/android/net/LinkProperties.java
@@ -82,8 +82,7 @@ public final class LinkProperties implements Parcelable {
private static final int MIN_MTU = 68;
- /** @hide */
- public static final int MIN_MTU_V6 = 1280;
+ private static final int MIN_MTU_V6 = 1280;
private static final int MAX_MTU = 10000;
diff --git a/core/java/android/net/NetworkIdentity.java b/core/java/android/net/NetworkIdentity.java
index 74a336d36b57..e65c27c2f4bb 100644
--- a/core/java/android/net/NetworkIdentity.java
+++ b/core/java/android/net/NetworkIdentity.java
@@ -17,7 +17,6 @@
package android.net;
import static android.net.ConnectivityManager.TYPE_WIFI;
-import static android.net.ConnectivityManager.isNetworkTypeMobile;
import android.annotation.Nullable;
import android.content.Context;
@@ -26,7 +25,6 @@ import android.net.wifi.WifiManager;
import android.os.Build;
import android.service.NetworkIdentityProto;
import android.telephony.Annotation.NetworkType;
-import android.util.Slog;
import android.util.proto.ProtoOutputStream;
import java.util.Objects;
@@ -194,18 +192,9 @@ public class NetworkIdentity implements Comparable<NetworkIdentity> {
boolean metered = !state.networkCapabilities.hasCapability(
NetworkCapabilities.NET_CAPABILITY_NOT_METERED);
- if (isNetworkTypeMobile(type)) {
- if (state.subscriberId == null) {
- if (state.networkInfo.getState() != NetworkInfo.State.DISCONNECTED &&
- state.networkInfo.getState() != NetworkInfo.State.UNKNOWN) {
- Slog.w(TAG, "Active mobile network without subscriber! ni = "
- + state.networkInfo);
- }
- }
-
- subscriberId = state.subscriberId;
+ subscriberId = state.subscriberId;
- } else if (type == TYPE_WIFI) {
+ if (type == TYPE_WIFI) {
if (state.networkId != null) {
networkId = state.networkId;
} else {
diff --git a/core/java/android/os/Debug.java b/core/java/android/os/Debug.java
index a4af0dbed0bd..e2e1bbe8487f 100644
--- a/core/java/android/os/Debug.java
+++ b/core/java/android/os/Debug.java
@@ -1946,7 +1946,13 @@ public final class Debug
*/
public static final int MEMINFO_KRECLAIMABLE = 15;
/** @hide */
- public static final int MEMINFO_COUNT = 16;
+ public static final int MEMINFO_ACTIVE = 16;
+ /** @hide */
+ public static final int MEMINFO_INACTIVE = 17;
+ /** @hide */
+ public static final int MEMINFO_UNEVICTABLE = 18;
+ /** @hide */
+ public static final int MEMINFO_COUNT = 19;
/**
* Retrieves /proc/meminfo. outSizes is filled with fields
diff --git a/core/java/android/permission/IPermissionManager.aidl b/core/java/android/permission/IPermissionManager.aidl
index 100166814975..9855a9a98cfb 100644
--- a/core/java/android/permission/IPermissionManager.aidl
+++ b/core/java/android/permission/IPermissionManager.aidl
@@ -73,10 +73,6 @@ interface IPermissionManager {
void resetRuntimePermissions();
- boolean setDefaultBrowser(String packageName, int userId);
-
- String getDefaultBrowser(int userId);
-
void grantDefaultPermissionsToEnabledCarrierApps(in String[] packageNames, int userId);
void grantDefaultPermissionsToEnabledImsServices(in String[] packageNames, int userId);
diff --git a/core/java/android/permission/PermissionManagerInternal.java b/core/java/android/permission/PermissionManagerInternal.java
index 3134ec06fe50..71674311965c 100644
--- a/core/java/android/permission/PermissionManagerInternal.java
+++ b/core/java/android/permission/PermissionManagerInternal.java
@@ -21,10 +21,6 @@ import android.annotation.Nullable;
import android.annotation.UserIdInt;
import android.os.UserHandle;
-import com.android.internal.util.function.TriFunction;
-
-import java.util.function.BiFunction;
-
/**
* Internal interfaces to be used by other components within the system server.
*
@@ -50,33 +46,6 @@ public abstract class PermissionManagerInternal {
@UserIdInt int userId);
}
- /** Interface to override permission checks via composition */
- public interface CheckPermissionDelegate {
- /**
- * Checks whether the given package has been granted the specified permission.
- *
- * @return If the package has the permission, PERMISSION_GRANTED is
- * returned. If it does not have the permission, PERMISSION_DENIED
- * is returned.
- *
- * @see android.content.pm.PackageManager#checkPermission(String, String)
- */
- int checkPermission(String permName, String pkgName, int userId,
- TriFunction<String, String, Integer, Integer> superImpl);
-
- /**
- /**
- * Checks whether the given uid has been granted the specified permission.
- *
- * @return If the package has the permission, PERMISSION_GRANTED is
- * returned. If it does not have the permission, PERMISSION_DENIED
- * is returned.
- *
- */
- int checkUidPermission(String permName, int uid,
- BiFunction<String, Integer, Integer> superImpl);
- }
-
/**
* Get the state of the runtime permissions as xml file.
*
diff --git a/core/java/android/service/notification/NotificationListenerService.java b/core/java/android/service/notification/NotificationListenerService.java
index aa9e289345db..440eeb1619f0 100644
--- a/core/java/android/service/notification/NotificationListenerService.java
+++ b/core/java/android/service/notification/NotificationListenerService.java
@@ -1517,8 +1517,10 @@ public abstract class NotificationListenerService extends Service {
*/
public static class Ranking {
- /** Value signifying that the user has not expressed a per-app visibility override value.
- * @hide */
+ /**
+ * Value signifying that the user and device policy manager have not expressed a lockscreen
+ * visibility override for a notification.
+ */
public static final int VISIBILITY_NO_OVERRIDE = NotificationManager.VISIBILITY_NO_OVERRIDE;
/**
@@ -1695,14 +1697,13 @@ public abstract class NotificationListenerService extends Service {
}
/**
- * Returns the user specified visibility for the package that posted
- * this notification, or
+ * Returns the user or device policy manager specified visibility (see
+ * {@link Notification#VISIBILITY_PRIVATE}, {@link Notification#VISIBILITY_PUBLIC},
+ * {@link Notification#VISIBILITY_SECRET}) for this notification, or
* {@link NotificationListenerService.Ranking#VISIBILITY_NO_OVERRIDE} if
* no such preference has been expressed.
- * @hide
*/
- @UnsupportedAppUsage
- public int getVisibilityOverride() {
+ public int getLockscreenVisibilityOverride() {
return mVisibilityOverride;
}
diff --git a/core/java/android/service/notification/ZenModeConfig.java b/core/java/android/service/notification/ZenModeConfig.java
index 787a81bac3c0..12d905588e1e 100644
--- a/core/java/android/service/notification/ZenModeConfig.java
+++ b/core/java/android/service/notification/ZenModeConfig.java
@@ -45,13 +45,14 @@ import android.text.format.DateFormat;
import android.util.ArrayMap;
import android.util.ArraySet;
import android.util.Slog;
+import android.util.TypedXmlPullParser;
+import android.util.TypedXmlSerializer;
import android.util.proto.ProtoOutputStream;
import com.android.internal.R;
import org.xmlpull.v1.XmlPullParser;
import org.xmlpull.v1.XmlPullParserException;
-import org.xmlpull.v1.XmlSerializer;
import java.io.IOException;
import java.util.ArrayList;
@@ -515,7 +516,7 @@ public class ZenModeConfig implements Parcelable {
}
}
- public static ZenModeConfig readXml(XmlPullParser parser)
+ public static ZenModeConfig readXml(TypedXmlPullParser parser)
throws XmlPullParserException, IOException {
int type = parser.getEventType();
if (type != XmlPullParser.START_TAG) return null;
@@ -611,28 +612,28 @@ public class ZenModeConfig implements Parcelable {
* @param version uses XML_VERSION if version is null
* @throws IOException
*/
- public void writeXml(XmlSerializer out, Integer version) throws IOException {
+ public void writeXml(TypedXmlSerializer out, Integer version) throws IOException {
out.startTag(null, ZEN_TAG);
out.attribute(null, ZEN_ATT_VERSION, version == null
? Integer.toString(XML_VERSION) : Integer.toString(version));
- out.attribute(null, ZEN_ATT_USER, Integer.toString(user));
+ out.attributeInt(null, ZEN_ATT_USER, user);
out.startTag(null, ALLOW_TAG);
- out.attribute(null, ALLOW_ATT_CALLS, Boolean.toString(allowCalls));
- out.attribute(null, ALLOW_ATT_REPEAT_CALLERS, Boolean.toString(allowRepeatCallers));
- out.attribute(null, ALLOW_ATT_MESSAGES, Boolean.toString(allowMessages));
- out.attribute(null, ALLOW_ATT_REMINDERS, Boolean.toString(allowReminders));
- out.attribute(null, ALLOW_ATT_EVENTS, Boolean.toString(allowEvents));
- out.attribute(null, ALLOW_ATT_CALLS_FROM, Integer.toString(allowCallsFrom));
- out.attribute(null, ALLOW_ATT_MESSAGES_FROM, Integer.toString(allowMessagesFrom));
- out.attribute(null, ALLOW_ATT_ALARMS, Boolean.toString(allowAlarms));
- out.attribute(null, ALLOW_ATT_MEDIA, Boolean.toString(allowMedia));
- out.attribute(null, ALLOW_ATT_SYSTEM, Boolean.toString(allowSystem));
- out.attribute(null, ALLOW_ATT_CONV, Boolean.toString(allowConversations));
- out.attribute(null, ALLOW_ATT_CONV_FROM, Integer.toString(allowConversationsFrom));
+ out.attributeBoolean(null, ALLOW_ATT_CALLS, allowCalls);
+ out.attributeBoolean(null, ALLOW_ATT_REPEAT_CALLERS, allowRepeatCallers);
+ out.attributeBoolean(null, ALLOW_ATT_MESSAGES, allowMessages);
+ out.attributeBoolean(null, ALLOW_ATT_REMINDERS, allowReminders);
+ out.attributeBoolean(null, ALLOW_ATT_EVENTS, allowEvents);
+ out.attributeInt(null, ALLOW_ATT_CALLS_FROM, allowCallsFrom);
+ out.attributeInt(null, ALLOW_ATT_MESSAGES_FROM, allowMessagesFrom);
+ out.attributeBoolean(null, ALLOW_ATT_ALARMS, allowAlarms);
+ out.attributeBoolean(null, ALLOW_ATT_MEDIA, allowMedia);
+ out.attributeBoolean(null, ALLOW_ATT_SYSTEM, allowSystem);
+ out.attributeBoolean(null, ALLOW_ATT_CONV, allowConversations);
+ out.attributeInt(null, ALLOW_ATT_CONV_FROM, allowConversationsFrom);
out.endTag(null, ALLOW_TAG);
out.startTag(null, DISALLOW_TAG);
- out.attribute(null, DISALLOW_ATT_VISUAL_EFFECTS, Integer.toString(suppressedVisualEffects));
+ out.attributeInt(null, DISALLOW_ATT_VISUAL_EFFECTS, suppressedVisualEffects);
out.endTag(null, DISALLOW_TAG);
if (manualRule != null) {
@@ -651,14 +652,13 @@ public class ZenModeConfig implements Parcelable {
}
out.startTag(null, STATE_TAG);
- out.attribute(null, STATE_ATT_CHANNELS_BYPASSING_DND,
- Boolean.toString(areChannelsBypassingDnd));
+ out.attributeBoolean(null, STATE_ATT_CHANNELS_BYPASSING_DND, areChannelsBypassingDnd);
out.endTag(null, STATE_TAG);
out.endTag(null, ZEN_TAG);
}
- public static ZenRule readRuleXml(XmlPullParser parser) {
+ public static ZenRule readRuleXml(TypedXmlPullParser parser) {
final ZenRule rt = new ZenRule();
rt.enabled = safeBoolean(parser, RULE_ATT_ENABLED, true);
rt.name = parser.getAttributeValue(null, RULE_ATT_NAME);
@@ -691,12 +691,12 @@ public class ZenModeConfig implements Parcelable {
return rt;
}
- public static void writeRuleXml(ZenRule rule, XmlSerializer out) throws IOException {
- out.attribute(null, RULE_ATT_ENABLED, Boolean.toString(rule.enabled));
+ public static void writeRuleXml(ZenRule rule, TypedXmlSerializer out) throws IOException {
+ out.attributeBoolean(null, RULE_ATT_ENABLED, rule.enabled);
if (rule.name != null) {
out.attribute(null, RULE_ATT_NAME, rule.name);
}
- out.attribute(null, RULE_ATT_ZEN, Integer.toString(rule.zenMode));
+ out.attributeInt(null, RULE_ATT_ZEN, rule.zenMode);
if (rule.component != null) {
out.attribute(null, RULE_ATT_COMPONENT, rule.component.flattenToString());
}
@@ -707,7 +707,7 @@ public class ZenModeConfig implements Parcelable {
if (rule.conditionId != null) {
out.attribute(null, RULE_ATT_CONDITION_ID, rule.conditionId.toString());
}
- out.attribute(null, RULE_ATT_CREATION_TIME, Long.toString(rule.creationTime));
+ out.attributeLong(null, RULE_ATT_CREATION_TIME, rule.creationTime);
if (rule.enabler != null) {
out.attribute(null, RULE_ATT_ENABLER, rule.enabler);
}
@@ -717,10 +717,10 @@ public class ZenModeConfig implements Parcelable {
if (rule.zenPolicy != null) {
writeZenPolicyXml(rule.zenPolicy, out);
}
- out.attribute(null, RULE_ATT_MODIFIED, Boolean.toString(rule.modified));
+ out.attributeBoolean(null, RULE_ATT_MODIFIED, rule.modified);
}
- public static Condition readConditionXml(XmlPullParser parser) {
+ public static Condition readConditionXml(TypedXmlPullParser parser) {
final Uri id = safeUri(parser, CONDITION_ATT_ID);
if (id == null) return null;
final String summary = parser.getAttributeValue(null, CONDITION_ATT_SUMMARY);
@@ -737,21 +737,21 @@ public class ZenModeConfig implements Parcelable {
}
}
- public static void writeConditionXml(Condition c, XmlSerializer out) throws IOException {
+ public static void writeConditionXml(Condition c, TypedXmlSerializer out) throws IOException {
out.attribute(null, CONDITION_ATT_ID, c.id.toString());
out.attribute(null, CONDITION_ATT_SUMMARY, c.summary);
out.attribute(null, CONDITION_ATT_LINE1, c.line1);
out.attribute(null, CONDITION_ATT_LINE2, c.line2);
- out.attribute(null, CONDITION_ATT_ICON, Integer.toString(c.icon));
- out.attribute(null, CONDITION_ATT_STATE, Integer.toString(c.state));
- out.attribute(null, CONDITION_ATT_FLAGS, Integer.toString(c.flags));
+ out.attributeInt(null, CONDITION_ATT_ICON, c.icon);
+ out.attributeInt(null, CONDITION_ATT_STATE, c.state);
+ out.attributeInt(null, CONDITION_ATT_FLAGS, c.flags);
}
/**
* Read the zen policy from xml
* Returns null if no zen policy exists
*/
- public static ZenPolicy readZenPolicyXml(XmlPullParser parser) {
+ public static ZenPolicy readZenPolicyXml(TypedXmlPullParser parser) {
boolean policySet = false;
ZenPolicy.Builder builder = new ZenPolicy.Builder();
@@ -845,7 +845,7 @@ public class ZenModeConfig implements Parcelable {
/**
* Writes zen policy to xml
*/
- public static void writeZenPolicyXml(ZenPolicy policy, XmlSerializer out)
+ public static void writeZenPolicyXml(ZenPolicy policy, TypedXmlSerializer out)
throws IOException {
writeZenPolicyState(ALLOW_ATT_CALLS_FROM, policy.getPriorityCallSenders(), out);
writeZenPolicyState(ALLOW_ATT_MESSAGES_FROM, policy.getPriorityMessageSenders(), out);
@@ -868,16 +868,16 @@ public class ZenModeConfig implements Parcelable {
out);
}
- private static void writeZenPolicyState(String attr, int val, XmlSerializer out)
+ private static void writeZenPolicyState(String attr, int val, TypedXmlSerializer out)
throws IOException {
if (Objects.equals(attr, ALLOW_ATT_CALLS_FROM)
|| Objects.equals(attr, ALLOW_ATT_MESSAGES_FROM)) {
if (val != ZenPolicy.PEOPLE_TYPE_UNSET) {
- out.attribute(null, attr, Integer.toString(val));
+ out.attributeInt(null, attr, val);
}
} else {
if (val != ZenPolicy.STATE_UNSET) {
- out.attribute(null, attr, Integer.toString(val));
+ out.attributeInt(null, attr, val);
}
}
}
@@ -894,15 +894,16 @@ public class ZenModeConfig implements Parcelable {
return source >= SOURCE_ANYONE && source <= MAX_SOURCE;
}
- private static Boolean unsafeBoolean(XmlPullParser parser, String att) {
- final String val = parser.getAttributeValue(null, att);
- if (TextUtils.isEmpty(val)) return null;
- return Boolean.parseBoolean(val);
+ private static Boolean unsafeBoolean(TypedXmlPullParser parser, String att) {
+ try {
+ return parser.getAttributeBoolean(null, att);
+ } catch (Exception e) {
+ return null;
+ }
}
- private static boolean safeBoolean(XmlPullParser parser, String att, boolean defValue) {
- final String val = parser.getAttributeValue(null, att);
- return safeBoolean(val, defValue);
+ private static boolean safeBoolean(TypedXmlPullParser parser, String att, boolean defValue) {
+ return parser.getAttributeBoolean(null, att, defValue);
}
private static boolean safeBoolean(String val, boolean defValue) {
@@ -910,24 +911,23 @@ public class ZenModeConfig implements Parcelable {
return Boolean.parseBoolean(val);
}
- private static int safeInt(XmlPullParser parser, String att, int defValue) {
- final String val = parser.getAttributeValue(null, att);
- return tryParseInt(val, defValue);
+ private static int safeInt(TypedXmlPullParser parser, String att, int defValue) {
+ return parser.getAttributeInt(null, att, defValue);
}
- private static ComponentName safeComponentName(XmlPullParser parser, String att) {
+ private static ComponentName safeComponentName(TypedXmlPullParser parser, String att) {
final String val = parser.getAttributeValue(null, att);
if (TextUtils.isEmpty(val)) return null;
return ComponentName.unflattenFromString(val);
}
- private static Uri safeUri(XmlPullParser parser, String att) {
+ private static Uri safeUri(TypedXmlPullParser parser, String att) {
final String val = parser.getAttributeValue(null, att);
if (TextUtils.isEmpty(val)) return null;
return Uri.parse(val);
}
- private static long safeLong(XmlPullParser parser, String att, long defValue) {
+ private static long safeLong(TypedXmlPullParser parser, String att, long defValue) {
final String val = parser.getAttributeValue(null, att);
return tryParseLong(val, defValue);
}
diff --git a/core/java/android/util/Xml.java b/core/java/android/util/Xml.java
index cc6ed2e4539e..c8193b3b0dbb 100644
--- a/core/java/android/util/Xml.java
+++ b/core/java/android/util/Xml.java
@@ -18,6 +18,8 @@ package android.util;
import android.annotation.NonNull;
import android.annotation.Nullable;
+import android.system.ErrnoException;
+import android.system.Os;
import com.android.internal.util.BinaryXmlPullParser;
import com.android.internal.util.BinaryXmlSerializer;
@@ -35,7 +37,7 @@ import org.xmlpull.v1.XmlPullParserException;
import org.xmlpull.v1.XmlSerializer;
import java.io.BufferedInputStream;
-import java.io.BufferedOutputStream;
+import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
@@ -43,6 +45,7 @@ import java.io.Reader;
import java.io.StringReader;
import java.io.UnsupportedEncodingException;
import java.nio.charset.StandardCharsets;
+import java.util.Arrays;
/**
* XML utility methods.
@@ -59,6 +62,12 @@ public class Xml {
public static String FEATURE_RELAXED = "http://xmlpull.org/v1/doc/features.html#relaxed";
/**
+ * Feature flag: when set, {@link #resolveSerializer(OutputStream)} will
+ * emit binary XML by default.
+ */
+ private static final boolean ENABLE_BINARY_DEFAULT = false;
+
+ /**
* Parses the given xml string and fires events on the given SAX handler.
*/
public static void parse(String xml, ContentHandler contentHandler)
@@ -119,6 +128,7 @@ public class Xml {
*
* @hide
*/
+ @SuppressWarnings("AndroidFrameworkEfficientXml")
public static @NonNull TypedXmlPullParser newFastPullParser() {
return XmlUtils.makeTyped(newPullParser());
}
@@ -151,8 +161,28 @@ public class Xml {
*/
public static @NonNull TypedXmlPullParser resolvePullParser(@NonNull InputStream in)
throws IOException {
- // TODO: add support for binary format
- final TypedXmlPullParser xml = newFastPullParser();
+ final byte[] magic = new byte[4];
+ if (in instanceof FileInputStream) {
+ try {
+ Os.pread(((FileInputStream) in).getFD(), magic, 0, magic.length, 0);
+ } catch (ErrnoException e) {
+ throw e.rethrowAsIOException();
+ }
+ } else {
+ if (!in.markSupported()) {
+ in = new BufferedInputStream(in);
+ }
+ in.mark(4);
+ in.read(magic);
+ in.reset();
+ }
+
+ final TypedXmlPullParser xml;
+ if (Arrays.equals(magic, BinaryXmlSerializer.PROTOCOL_MAGIC_VERSION_0)) {
+ xml = newBinaryPullParser();
+ } else {
+ xml = newFastPullParser();
+ }
try {
xml.setInput(in, StandardCharsets.UTF_8.name());
} catch (XmlPullParserException e) {
@@ -177,6 +207,7 @@ public class Xml {
*
* @hide
*/
+ @SuppressWarnings("AndroidFrameworkEfficientXml")
public static @NonNull TypedXmlSerializer newFastSerializer() {
return XmlUtils.makeTyped(new FastXmlSerializer());
}
@@ -209,8 +240,12 @@ public class Xml {
*/
public static @NonNull TypedXmlSerializer resolveSerializer(@NonNull OutputStream out)
throws IOException {
- // TODO: add support for binary format
- final TypedXmlSerializer xml = newFastSerializer();
+ final TypedXmlSerializer xml;
+ if (ENABLE_BINARY_DEFAULT) {
+ xml = newBinarySerializer();
+ } else {
+ xml = newFastSerializer();
+ }
xml.setOutput(out, StandardCharsets.UTF_8.name());
return xml;
}
diff --git a/core/java/android/uwb/AdapterStateListener.java b/core/java/android/uwb/AdapterStateListener.java
new file mode 100644
index 000000000000..8875af385238
--- /dev/null
+++ b/core/java/android/uwb/AdapterStateListener.java
@@ -0,0 +1,149 @@
+/*
+ * Copyright 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.uwb;
+
+import android.annotation.NonNull;
+import android.os.Binder;
+import android.os.RemoteException;
+import android.util.Log;
+import android.uwb.UwbManager.AdapterStateCallback;
+import android.uwb.UwbManager.AdapterStateCallback.StateChangedReason;
+
+import java.util.HashMap;
+import java.util.Map;
+import java.util.concurrent.Executor;
+
+/**
+ * @hide
+ */
+public class AdapterStateListener extends IUwbAdapterStateCallbacks.Stub {
+ private static final String TAG = "Uwb.StateListener";
+
+ private final IUwbAdapter mAdapter;
+ private boolean mIsRegistered = false;
+
+ private final Map<AdapterStateCallback, Executor> mCallbackMap = new HashMap<>();
+
+ @StateChangedReason
+ private int mAdapterStateChangeReason = AdapterStateCallback.STATE_CHANGED_REASON_ERROR_UNKNOWN;
+ private boolean mAdapterEnabledState = false;
+
+ public AdapterStateListener(@NonNull IUwbAdapter adapter) {
+ mAdapter = adapter;
+ }
+
+ /**
+ * Register an {@link AdapterStateCallback} with this {@link AdapterStateListener}
+ *
+ * @param executor an {@link Executor} to execute given callback
+ * @param callback user implementation of the {@link AdapterStateCallback}
+ */
+ public void register(@NonNull Executor executor, @NonNull AdapterStateCallback callback) {
+ synchronized (this) {
+ if (mCallbackMap.containsKey(callback)) {
+ return;
+ }
+
+ mCallbackMap.put(callback, executor);
+
+ if (!mIsRegistered) {
+ try {
+ mAdapter.registerAdapterStateCallbacks(this);
+ mIsRegistered = true;
+ } catch (RemoteException e) {
+ Log.w(TAG, "Failed to register adapter state callback");
+ executor.execute(() -> callback.onStateChanged(false,
+ AdapterStateCallback.STATE_CHANGED_REASON_ERROR_UNKNOWN));
+ }
+ } else {
+ sendCurrentState(callback);
+ }
+ }
+ }
+
+ /**
+ * Unregister the specified {@link AdapterStateCallback}
+ *
+ * @param callback user implementation of the {@link AdapterStateCallback}
+ */
+ public void unregister(@NonNull AdapterStateCallback callback) {
+ synchronized (this) {
+ if (!mCallbackMap.containsKey(callback)) {
+ return;
+ }
+
+ mCallbackMap.remove(callback);
+
+ if (mCallbackMap.isEmpty() && mIsRegistered) {
+ try {
+ mAdapter.unregisterAdapterStateCallbacks(this);
+ } catch (RemoteException e) {
+ Log.w(TAG, "Failed to unregister AdapterStateCallback with service");
+ }
+ mIsRegistered = false;
+ }
+ }
+ }
+
+ private void sendCurrentState(@NonNull AdapterStateCallback callback) {
+ synchronized (this) {
+ Executor executor = mCallbackMap.get(callback);
+
+ final long identity = Binder.clearCallingIdentity();
+ try {
+ executor.execute(() -> callback.onStateChanged(
+ mAdapterEnabledState, mAdapterStateChangeReason));
+ } finally {
+ Binder.restoreCallingIdentity(identity);
+ }
+ }
+ }
+
+ @Override
+ public void onAdapterStateChanged(boolean isEnabled, int reason) {
+ synchronized (this) {
+ @StateChangedReason int localReason =
+ convertToStateChangedReason(reason);
+ mAdapterEnabledState = isEnabled;
+ mAdapterStateChangeReason = localReason;
+ for (AdapterStateCallback cb : mCallbackMap.keySet()) {
+ sendCurrentState(cb);
+ }
+ }
+ }
+
+ private static @StateChangedReason int convertToStateChangedReason(
+ @StateChangeReason int reason) {
+ switch (reason) {
+ case StateChangeReason.ALL_SESSIONS_CLOSED:
+ return AdapterStateCallback.STATE_CHANGED_REASON_ALL_SESSIONS_CLOSED;
+
+ case StateChangeReason.SESSION_STARTED:
+ return AdapterStateCallback.STATE_CHANGED_REASON_SESSION_STARTED;
+
+ case StateChangeReason.SYSTEM_POLICY:
+ return AdapterStateCallback.STATE_CHANGED_REASON_SYSTEM_POLICY;
+
+ case StateChangeReason.SYSTEM_BOOT:
+ return AdapterStateCallback.STATE_CHANGED_REASON_SYSTEM_BOOT;
+
+ case StateChangeReason.UNKNOWN:
+ default:
+ return AdapterStateCallback.STATE_CHANGED_REASON_ERROR_UNKNOWN;
+ }
+ }
+}
diff --git a/core/java/android/uwb/IUwbAdapter.aidl b/core/java/android/uwb/IUwbAdapter.aidl
index d29ed34804f1..2c8b2e462510 100644
--- a/core/java/android/uwb/IUwbAdapter.aidl
+++ b/core/java/android/uwb/IUwbAdapter.aidl
@@ -98,11 +98,18 @@ interface IUwbAdapter {
int getMaxSimultaneousSessions();
/**
- * Get the maximum number of remote devices per session
+ * Get the maximum number of remote devices per session when local device is initiator
*
* @return the maximum number of remote devices supported in a single session
*/
- int getMaxRemoteDevicesPerSession();
+ int getMaxRemoteDevicesPerInitiatorSession();
+
+ /**
+ * Get the maximum number of remote devices per session when local device is responder
+ *
+ * @return the maximum number of remote devices supported in a single session
+ */
+ int getMaxRemoteDevicesPerResponderSession();
/**
* Provides the capabilities and features of the device
diff --git a/core/java/android/uwb/StateChangeReason.aidl b/core/java/android/uwb/StateChangeReason.aidl
index 46a6e2edfa22..28eaf9f2b24e 100644
--- a/core/java/android/uwb/StateChangeReason.aidl
+++ b/core/java/android/uwb/StateChangeReason.aidl
@@ -41,5 +41,10 @@ enum StateChangeReason {
* The adapter state changed because of a device system change.
*/
SYSTEM_POLICY,
+
+ /**
+ * Used to signal the first adapter state message after boot
+ */
+ SYSTEM_BOOT,
}
diff --git a/core/java/android/uwb/UwbManager.java b/core/java/android/uwb/UwbManager.java
index 6488490b8863..ed5cf3625525 100644
--- a/core/java/android/uwb/UwbManager.java
+++ b/core/java/android/uwb/UwbManager.java
@@ -16,6 +16,7 @@
package android.uwb;
+import android.annotation.CallbackExecutor;
import android.annotation.IntDef;
import android.annotation.NonNull;
import android.annotation.SuppressLint;
@@ -23,10 +24,13 @@ import android.annotation.SystemService;
import android.content.Context;
import android.os.IBinder;
import android.os.PersistableBundle;
+import android.os.RemoteException;
import android.os.ServiceManager;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
+import java.util.ArrayList;
+import java.util.HashSet;
import java.util.List;
import java.util.Set;
import java.util.concurrent.Executor;
@@ -45,6 +49,8 @@ public final class UwbManager {
private IUwbAdapter mUwbAdapter;
private static final String SERVICE_NAME = "uwb";
+ private AdapterStateListener mAdapterStateListener;
+
/**
* Interface for receiving UWB adapter state changes
*/
@@ -109,6 +115,7 @@ public final class UwbManager {
*/
private UwbManager(IUwbAdapter adapter) {
mUwbAdapter = adapter;
+ mAdapterStateListener = new AdapterStateListener(adapter);
}
/**
@@ -140,8 +147,9 @@ public final class UwbManager {
* @param executor an {@link Executor} to execute given callback
* @param callback user implementation of the {@link AdapterStateCallback}
*/
- public void registerAdapterStateCallback(Executor executor, AdapterStateCallback callback) {
- throw new UnsupportedOperationException();
+ public void registerAdapterStateCallback(@NonNull @CallbackExecutor Executor executor,
+ @NonNull AdapterStateCallback callback) {
+ mAdapterStateListener.register(executor, callback);
}
/**
@@ -153,8 +161,8 @@ public final class UwbManager {
*
* @param callback user implementation of the {@link AdapterStateCallback}
*/
- public void unregisterAdapterStateCallback(AdapterStateCallback callback) {
- throw new UnsupportedOperationException();
+ public void unregisterAdapterStateCallback(@NonNull AdapterStateCallback callback) {
+ mAdapterStateListener.unregister(callback);
}
/**
@@ -167,7 +175,11 @@ public final class UwbManager {
*/
@NonNull
public PersistableBundle getSpecificationInfo() {
- throw new UnsupportedOperationException();
+ try {
+ return mUwbAdapter.getSpecificationInfo();
+ } catch (RemoteException e) {
+ throw e.rethrowFromSystemServer();
+ }
}
/**
@@ -176,7 +188,11 @@ public final class UwbManager {
* @return true if ranging is supported
*/
public boolean isRangingSupported() {
- throw new UnsupportedOperationException();
+ try {
+ return mUwbAdapter.isRangingSupported();
+ } catch (RemoteException e) {
+ throw e.rethrowFromSystemServer();
+ }
}
@Retention(RetentionPolicy.SOURCE)
@@ -225,7 +241,24 @@ public final class UwbManager {
*/
@AngleOfArrivalSupportType
public int getAngleOfArrivalSupport() {
- throw new UnsupportedOperationException();
+ try {
+ switch (mUwbAdapter.getAngleOfArrivalSupport()) {
+ case AngleOfArrivalSupport.TWO_DIMENSIONAL:
+ return ANGLE_OF_ARRIVAL_SUPPORT_TYPE_2D;
+
+ case AngleOfArrivalSupport.THREE_DIMENSIONAL_HEMISPHERICAL:
+ return ANGLE_OF_ARRIVAL_SUPPORT_TYPE_3D_HEMISPHERICAL;
+
+ case AngleOfArrivalSupport.THREE_DIMENSIONAL_SPHERICAL:
+ return ANGLE_OF_ARRIVAL_SUPPORT_TYPE_3D_SPHERICAL;
+
+ case AngleOfArrivalSupport.NONE:
+ default:
+ return ANGLE_OF_ARRIVAL_SUPPORT_TYPE_NONE;
+ }
+ } catch (RemoteException e) {
+ throw e.rethrowFromSystemServer();
+ }
}
/**
@@ -239,7 +272,15 @@ public final class UwbManager {
*/
@NonNull
public List<Integer> getSupportedChannelNumbers() {
- throw new UnsupportedOperationException();
+ List<Integer> channels = new ArrayList<>();
+ try {
+ for (int channel : mUwbAdapter.getSupportedChannels()) {
+ channels.add(channel);
+ }
+ } catch (RemoteException e) {
+ throw e.rethrowFromSystemServer();
+ }
+ return channels;
}
/**
@@ -250,7 +291,15 @@ public final class UwbManager {
*/
@NonNull
public Set<Integer> getSupportedPreambleCodeIndices() {
- throw new UnsupportedOperationException();
+ Set<Integer> preambles = new HashSet<>();
+ try {
+ for (int preamble : mUwbAdapter.getSupportedPreambleCodes()) {
+ preambles.add(preamble);
+ }
+ } catch (RemoteException e) {
+ throw e.rethrowFromSystemServer();
+ }
+ return preambles;
}
/**
@@ -262,7 +311,11 @@ public final class UwbManager {
*/
@SuppressLint("MethodNameUnits")
public long elapsedRealtimeResolutionNanos() {
- throw new UnsupportedOperationException();
+ try {
+ return mUwbAdapter.getTimestampResolutionNanos();
+ } catch (RemoteException e) {
+ throw e.rethrowFromSystemServer();
+ }
}
/**
@@ -271,7 +324,11 @@ public final class UwbManager {
* @return the maximum allowed number of simultaneously open {@link RangingSession} instances.
*/
public int getMaxSimultaneousSessions() {
- throw new UnsupportedOperationException();
+ try {
+ return mUwbAdapter.getMaxSimultaneousSessions();
+ } catch (RemoteException e) {
+ throw e.rethrowFromSystemServer();
+ }
}
/**
@@ -281,7 +338,11 @@ public final class UwbManager {
* @return the maximum number of remote devices per {@link RangingSession}
*/
public int getMaxRemoteDevicesPerInitiatorSession() {
- throw new UnsupportedOperationException();
+ try {
+ return mUwbAdapter.getMaxRemoteDevicesPerInitiatorSession();
+ } catch (RemoteException e) {
+ throw e.rethrowFromSystemServer();
+ }
}
/**
@@ -291,7 +352,11 @@ public final class UwbManager {
* @return the maximum number of remote devices per {@link RangingSession}
*/
public int getMaxRemoteDevicesPerResponderSession() {
- throw new UnsupportedOperationException();
+ try {
+ return mUwbAdapter.getMaxRemoteDevicesPerResponderSession();
+ } catch (RemoteException e) {
+ throw e.rethrowFromSystemServer();
+ }
}
/**
diff --git a/core/java/android/view/IPinnedStackController.aidl b/core/java/android/view/IPinnedStackController.aidl
deleted file mode 100644
index 1cf83a3f1e79..000000000000
--- a/core/java/android/view/IPinnedStackController.aidl
+++ /dev/null
@@ -1,32 +0,0 @@
-/**
- * Copyright (c) 2016, The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.view;
-
-import android.graphics.Rect;
-
-/**
- * An interface to the PinnedStackController to update it of state changes, and to query
- * information based on the current state.
- *
- * @hide
- */
-interface IPinnedStackController {
- /**
- * @return what WM considers to be the current device rotation.
- */
- int getDisplayRotation();
-}
diff --git a/core/java/android/view/IPinnedStackListener.aidl b/core/java/android/view/IPinnedStackListener.aidl
index f49fee36ca7e..84dd8af5e342 100644
--- a/core/java/android/view/IPinnedStackListener.aidl
+++ b/core/java/android/view/IPinnedStackListener.aidl
@@ -21,7 +21,6 @@ import android.content.ComponentName;
import android.content.pm.ParceledListSlice;
import android.graphics.Rect;
import android.view.DisplayInfo;
-import android.view.IPinnedStackController;
/**
* Listener for changes to the pinned stack made by the WindowManager.
@@ -31,12 +30,6 @@ import android.view.IPinnedStackController;
oneway interface IPinnedStackListener {
/**
- * Called when the listener is registered and provides an interface to call back to the pinned
- * stack controller to update the controller of the pinned stack state.
- */
- void onListenerRegistered(IPinnedStackController controller);
-
- /**
* Called when the window manager has detected a change that would cause the movement bounds
* to be changed (ie. after configuration change, aspect ratio change, etc).
*/
diff --git a/core/java/android/view/IWindowManager.aidl b/core/java/android/view/IWindowManager.aidl
index a23b7e193024..025a977d5420 100644
--- a/core/java/android/view/IWindowManager.aidl
+++ b/core/java/android/view/IWindowManager.aidl
@@ -780,4 +780,25 @@ interface IWindowManager
* verified.
*/
boolean verifyImpressionToken(in ImpressionToken impressionToken);
+
+ /**
+ * Registers a listener for a {@link android.app.WindowContext} to handle configuration changes
+ * from the server side.
+ *
+ * @param clientToken the window context's token
+ * @param type Window type of the window context
+ * @param displayId The display associated with the window context
+ * @param options A bundle used to pass window-related options and choose the right DisplayArea
+ *
+ * @return {@code true} if the listener was registered successfully.
+ */
+ boolean registerWindowContextListener(IBinder clientToken, int type, int displayId,
+ in Bundle options);
+
+ /**
+ * Unregisters a listener which registered with {@link #registerWindowContextListener()}.
+ *
+ * @param clientToken the window context's token
+ */
+ void unregisterWindowContextListener(IBinder clientToken);
}
diff --git a/core/java/android/view/ViewRootImpl.java b/core/java/android/view/ViewRootImpl.java
index 349b84899f9d..2d633cbeb353 100644
--- a/core/java/android/view/ViewRootImpl.java
+++ b/core/java/android/view/ViewRootImpl.java
@@ -119,6 +119,7 @@ import android.graphics.Rect;
import android.graphics.Region;
import android.graphics.RenderNode;
import android.graphics.drawable.Drawable;
+import android.graphics.drawable.GradientDrawable;
import android.hardware.display.DisplayManager;
import android.hardware.display.DisplayManager.DisplayListener;
import android.hardware.input.InputManager;
@@ -4414,6 +4415,14 @@ public final class ViewRootImpl implements ViewParent,
mView.mContext.getDrawable(value.resourceId);
}
}
+ // Sets the focus appearance data into the accessibility focus drawable.
+ if (mAttachInfo.mAccessibilityFocusDrawable instanceof GradientDrawable) {
+ final GradientDrawable drawable =
+ (GradientDrawable) mAttachInfo.mAccessibilityFocusDrawable;
+ drawable.setStroke(mAccessibilityManager.getAccessibilityFocusStrokeWidth(),
+ mAccessibilityManager.getAccessibilityFocusColor());
+ }
+
return mAttachInfo.mAccessibilityFocusDrawable;
}
diff --git a/core/java/android/view/accessibility/AccessibilityManager.java b/core/java/android/view/accessibility/AccessibilityManager.java
index a8534faf43e5..56dcd5951e5e 100644
--- a/core/java/android/view/accessibility/AccessibilityManager.java
+++ b/core/java/android/view/accessibility/AccessibilityManager.java
@@ -19,9 +19,11 @@ package android.view.accessibility;
import static android.accessibilityservice.AccessibilityServiceInfo.FLAG_ENABLE_ACCESSIBILITY_VOLUME;
import android.Manifest;
+import android.accessibilityservice.AccessibilityService;
import android.accessibilityservice.AccessibilityServiceInfo;
import android.accessibilityservice.AccessibilityServiceInfo.FeedbackType;
import android.accessibilityservice.AccessibilityShortcutInfo;
+import android.annotation.ColorInt;
import android.annotation.IntDef;
import android.annotation.NonNull;
import android.annotation.Nullable;
@@ -59,6 +61,7 @@ import android.view.IWindow;
import android.view.View;
import android.view.accessibility.AccessibilityEvent.EventType;
+import com.android.internal.R;
import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.util.IntPair;
@@ -233,6 +236,11 @@ public final class AccessibilityManager {
private int mPerformingAction = 0;
+ /** The stroke width of the focus rectangle in pixels */
+ private int mFocusStrokeWidth;
+ /** The color of the focus rectangle */
+ private int mFocusColor;
+
@UnsupportedAppUsage
private final ArrayMap<AccessibilityStateChangeListener, Handler>
mAccessibilityStateChangeListeners = new ArrayMap<>();
@@ -410,6 +418,13 @@ public final class AccessibilityManager {
public void setRelevantEventTypes(int eventTypes) {
mRelevantEventTypes = eventTypes;
}
+
+ @Override
+ public void setFocusAppearance(int strokeWidth, int color) {
+ synchronized (mLock) {
+ updateFocusAppearanceLocked(strokeWidth, color);
+ }
+ }
};
/**
@@ -457,6 +472,7 @@ public final class AccessibilityManager {
mHandler = new Handler(context.getMainLooper(), mCallback);
mUserId = userId;
synchronized (mLock) {
+ initialFocusAppearanceLocked(context.getResources());
tryConnectToServiceLocked(service);
}
}
@@ -464,18 +480,26 @@ public final class AccessibilityManager {
/**
* Create an instance.
*
+ * @param context A {@link Context}.
* @param handler The handler to use
* @param service An interface to the backing service.
* @param userId User id under which to run.
+ * @param serviceConnect {@code true} to connect the service or
+ * {@code false} not to connect the service.
*
* @hide
*/
- public AccessibilityManager(Handler handler, IAccessibilityManager service, int userId) {
+ @VisibleForTesting
+ public AccessibilityManager(Context context, Handler handler, IAccessibilityManager service,
+ int userId, boolean serviceConnect) {
mCallback = new MyCallback();
mHandler = handler;
mUserId = userId;
synchronized (mLock) {
- tryConnectToServiceLocked(service);
+ initialFocusAppearanceLocked(context.getResources());
+ if (serviceConnect) {
+ tryConnectToServiceLocked(service);
+ }
}
}
@@ -954,6 +978,32 @@ public final class AccessibilityManager {
}
/**
+ * Gets the strokeWidth of the focus rectangle. This value can be set by
+ * {@link AccessibilityService}.
+ *
+ * @return The strokeWidth of the focus rectangle in pixels.
+ *
+ */
+ public int getAccessibilityFocusStrokeWidth() {
+ synchronized (mLock) {
+ return mFocusStrokeWidth;
+ }
+ }
+
+ /**
+ * Gets the color of the focus rectangle. This value can be set by
+ * {@link AccessibilityService}.
+ *
+ * @return The color of the focus rectangle.
+ *
+ */
+ public @ColorInt int getAccessibilityFocusColor() {
+ synchronized (mLock) {
+ return mFocusColor;
+ }
+ }
+
+ /**
* Get the preparers that are registered for an accessibility ID
*
* @param id The ID of interest
@@ -1551,6 +1601,7 @@ public final class AccessibilityManager {
setStateLocked(IntPair.first(userStateAndRelevantEvents));
mRelevantEventTypes = IntPair.second(userStateAndRelevantEvents);
updateUiTimeout(service.getRecommendedTimeoutMillis());
+ updateFocusAppearanceLocked(service.getFocusStrokeWidth(), service.getFocusColor());
mService = service;
} catch (RemoteException re) {
Log.e(LOG_TAG, "AccessibilityManagerService is dead", re);
@@ -1635,6 +1686,40 @@ public final class AccessibilityManager {
}
/**
+ * Updates the stroke width and color of the focus rectangle.
+ *
+ * @param strokeWidth The strokeWidth of the focus rectangle.
+ * @param color The color of the focus rectangle.
+ */
+ private void updateFocusAppearanceLocked(int strokeWidth, int color) {
+ if (mFocusStrokeWidth == strokeWidth && mFocusColor == color) {
+ return;
+ }
+ mFocusStrokeWidth = strokeWidth;
+ mFocusColor = color;
+ }
+
+ /**
+ * Sets the stroke width and color of the focus rectangle to default value.
+ *
+ * @param resource The resources.
+ */
+ private void initialFocusAppearanceLocked(Resources resource) {
+ try {
+ mFocusStrokeWidth = resource.getDimensionPixelSize(
+ R.dimen.accessibility_focus_highlight_stroke_width);
+ mFocusColor = resource.getColor(R.color.accessibility_focus_highlight_color);
+ } catch (Resources.NotFoundException re) {
+ // Sets the stroke width and color to default value by hardcoded for making
+ // the Talkback can work normally.
+ mFocusStrokeWidth = (int) (4 * resource.getDisplayMetrics().density);
+ mFocusColor = 0xbf39b500;
+ Log.e(LOG_TAG, "Error while initialing the focus appearance data then setting to"
+ + " default value by hardcoded", re);
+ }
+ }
+
+ /**
* Determines if the accessibility button within the system navigation area is supported.
*
* @return {@code true} if the accessibility button is supported on this device,
diff --git a/core/java/android/view/accessibility/IAccessibilityManager.aidl b/core/java/android/view/accessibility/IAccessibilityManager.aidl
index 5d3c72015ee3..c71ea53c414d 100644
--- a/core/java/android/view/accessibility/IAccessibilityManager.aidl
+++ b/core/java/android/view/accessibility/IAccessibilityManager.aidl
@@ -92,4 +92,8 @@ interface IAccessibilityManager {
void associateEmbeddedHierarchy(IBinder host, IBinder embedded);
void disassociateEmbeddedHierarchy(IBinder token);
+
+ int getFocusStrokeWidth();
+
+ int getFocusColor();
}
diff --git a/core/java/android/view/accessibility/IAccessibilityManagerClient.aidl b/core/java/android/view/accessibility/IAccessibilityManagerClient.aidl
index 94b9ad1c3279..041399ccb8ec 100644
--- a/core/java/android/view/accessibility/IAccessibilityManagerClient.aidl
+++ b/core/java/android/view/accessibility/IAccessibilityManagerClient.aidl
@@ -29,4 +29,6 @@ oneway interface IAccessibilityManagerClient {
void notifyServicesStateChanged(long updatedUiTimeout);
void setRelevantEventTypes(int eventTypes);
+
+ void setFocusAppearance(int strokeWidth, int color);
}
diff --git a/core/java/com/android/internal/os/BatteryStatsImpl.java b/core/java/com/android/internal/os/BatteryStatsImpl.java
index dcd74fd1ad3e..fb6eb97253e3 100644
--- a/core/java/com/android/internal/os/BatteryStatsImpl.java
+++ b/core/java/com/android/internal/os/BatteryStatsImpl.java
@@ -90,6 +90,8 @@ import android.util.SparseArray;
import android.util.SparseIntArray;
import android.util.SparseLongArray;
import android.util.TimeUtils;
+import android.util.TypedXmlPullParser;
+import android.util.TypedXmlSerializer;
import android.util.Xml;
import android.view.Display;
@@ -112,7 +114,6 @@ import libcore.util.EmptyArray;
import org.xmlpull.v1.XmlPullParser;
import org.xmlpull.v1.XmlPullParserException;
-import org.xmlpull.v1.XmlSerializer;
import java.io.ByteArrayOutputStream;
import java.io.File;
@@ -10830,8 +10831,7 @@ public class BatteryStatsImpl extends BatteryStats {
}
final ByteArrayOutputStream memStream = new ByteArrayOutputStream();
try {
- XmlSerializer out = new FastXmlSerializer();
- out.setOutput(memStream, StandardCharsets.UTF_8.name());
+ TypedXmlSerializer out = Xml.resolveSerializer(memStream);
writeDailyItemsLocked(out);
final long initialTimeMs = SystemClock.uptimeMillis() - startTimeMs;
BackgroundThread.getHandler().post(new Runnable() {
@@ -10861,15 +10861,15 @@ public class BatteryStatsImpl extends BatteryStats {
}
}
- private void writeDailyItemsLocked(XmlSerializer out) throws IOException {
+ private void writeDailyItemsLocked(TypedXmlSerializer out) throws IOException {
StringBuilder sb = new StringBuilder(64);
out.startDocument(null, true);
out.startTag(null, "daily-items");
for (int i=0; i<mDailyItems.size(); i++) {
final DailyItem dit = mDailyItems.get(i);
out.startTag(null, "item");
- out.attribute(null, "start", Long.toString(dit.mStartTime));
- out.attribute(null, "end", Long.toString(dit.mEndTime));
+ out.attributeLong(null, "start", dit.mStartTime);
+ out.attributeLong(null, "end", dit.mEndTime);
writeDailyLevelSteps(out, "dis", dit.mDischargeSteps, sb);
writeDailyLevelSteps(out, "chg", dit.mChargeSteps, sb);
if (dit.mPackageChanges != null) {
@@ -10878,7 +10878,7 @@ public class BatteryStatsImpl extends BatteryStats {
if (pc.mUpdate) {
out.startTag(null, "upd");
out.attribute(null, "pkg", pc.mPackageName);
- out.attribute(null, "ver", Long.toString(pc.mVersionCode));
+ out.attributeLong(null, "ver", pc.mVersionCode);
out.endTag(null, "upd");
} else {
out.startTag(null, "rem");
@@ -10893,11 +10893,11 @@ public class BatteryStatsImpl extends BatteryStats {
out.endDocument();
}
- private void writeDailyLevelSteps(XmlSerializer out, String tag, LevelStepTracker steps,
+ private void writeDailyLevelSteps(TypedXmlSerializer out, String tag, LevelStepTracker steps,
StringBuilder tmpBuilder) throws IOException {
if (steps != null) {
out.startTag(null, tag);
- out.attribute(null, "n", Integer.toString(steps.mNumStepDurations));
+ out.attributeInt(null, "n", steps.mNumStepDurations);
for (int i=0; i<steps.mNumStepDurations; i++) {
out.startTag(null, "s");
tmpBuilder.setLength(0);
@@ -10919,10 +10919,9 @@ public class BatteryStatsImpl extends BatteryStats {
return;
}
try {
- XmlPullParser parser = Xml.newPullParser();
- parser.setInput(stream, StandardCharsets.UTF_8.name());
+ TypedXmlPullParser parser = Xml.resolvePullParser(stream);
readDailyItemsLocked(parser);
- } catch (XmlPullParserException e) {
+ } catch (IOException e) {
} finally {
try {
stream.close();
@@ -10931,7 +10930,7 @@ public class BatteryStatsImpl extends BatteryStats {
}
}
- private void readDailyItemsLocked(XmlPullParser parser) {
+ private void readDailyItemsLocked(TypedXmlPullParser parser) {
try {
int type;
while ((type = parser.next()) != XmlPullParser.START_TAG
@@ -10975,17 +10974,11 @@ public class BatteryStatsImpl extends BatteryStats {
}
}
- void readDailyItemTagLocked(XmlPullParser parser) throws NumberFormatException,
+ void readDailyItemTagLocked(TypedXmlPullParser parser) throws NumberFormatException,
XmlPullParserException, IOException {
DailyItem dit = new DailyItem();
- String attr = parser.getAttributeValue(null, "start");
- if (attr != null) {
- dit.mStartTime = Long.parseLong(attr);
- }
- attr = parser.getAttributeValue(null, "end");
- if (attr != null) {
- dit.mEndTime = Long.parseLong(attr);
- }
+ dit.mStartTime = parser.getAttributeLong(null, "start", 0);
+ dit.mEndTime = parser.getAttributeLong(null, "end", 0);
int outerDepth = parser.getDepth();
int type;
while ((type = parser.next()) != XmlPullParser.END_DOCUMENT
@@ -11006,8 +10999,7 @@ public class BatteryStatsImpl extends BatteryStats {
PackageChange pc = new PackageChange();
pc.mUpdate = true;
pc.mPackageName = parser.getAttributeValue(null, "pkg");
- String verStr = parser.getAttributeValue(null, "ver");
- pc.mVersionCode = verStr != null ? Long.parseLong(verStr) : 0;
+ pc.mVersionCode = parser.getAttributeLong(null, "ver", 0);
dit.mPackageChanges.add(pc);
XmlUtils.skipCurrentTag(parser);
} else if (tagName.equals("rem")) {
@@ -11028,16 +11020,15 @@ public class BatteryStatsImpl extends BatteryStats {
mDailyItems.add(dit);
}
- void readDailyItemTagDetailsLocked(XmlPullParser parser, DailyItem dit, boolean isCharge,
+ void readDailyItemTagDetailsLocked(TypedXmlPullParser parser, DailyItem dit, boolean isCharge,
String tag)
throws NumberFormatException, XmlPullParserException, IOException {
- final String numAttr = parser.getAttributeValue(null, "n");
- if (numAttr == null) {
+ final int num = parser.getAttributeInt(null, "n", -1);
+ if (num == -1) {
Slog.w(TAG, "Missing 'n' attribute at " + parser.getPositionDescription());
XmlUtils.skipCurrentTag(parser);
return;
}
- final int num = Integer.parseInt(numAttr);
LevelStepTracker steps = new LevelStepTracker(num);
if (isCharge) {
dit.mChargeSteps = steps;
diff --git a/core/java/com/android/internal/util/BinaryXmlSerializer.java b/core/java/com/android/internal/util/BinaryXmlSerializer.java
index d3fcf71ba399..bc3b1f8bef57 100644
--- a/core/java/com/android/internal/util/BinaryXmlSerializer.java
+++ b/core/java/com/android/internal/util/BinaryXmlSerializer.java
@@ -69,7 +69,7 @@ public final class BinaryXmlSerializer implements TypedXmlSerializer {
* {@code ABX_}, representing "Android Binary XML." The final byte is a
* version number which may be incremented as the protocol changes.
*/
- static final byte[] PROTOCOL_MAGIC_VERSION_0 = new byte[] { 0x41, 0x42, 0x58, 0x00 };
+ public static final byte[] PROTOCOL_MAGIC_VERSION_0 = new byte[] { 0x41, 0x42, 0x58, 0x00 };
/**
* Internal token which represents an attribute associated with the most
diff --git a/core/java/com/android/internal/util/XmlUtils.java b/core/java/com/android/internal/util/XmlUtils.java
index 8eb0e280350f..244efc596926 100644
--- a/core/java/com/android/internal/util/XmlUtils.java
+++ b/core/java/com/android/internal/util/XmlUtils.java
@@ -53,6 +53,7 @@ import java.util.Set;
public class XmlUtils {
private static final String STRING_ARRAY_SEPARATOR = ":";
+ @SuppressWarnings("AndroidFrameworkEfficientXml")
private static class ForcedTypedXmlSerializer extends XmlSerializerWrapper
implements TypedXmlSerializer {
public ForcedTypedXmlSerializer(XmlSerializer wrapped) {
@@ -133,6 +134,7 @@ public class XmlUtils {
}
}
+ @SuppressWarnings("AndroidFrameworkEfficientXml")
private static class ForcedTypedXmlPullParser extends XmlPullParserWrapper
implements TypedXmlPullParser {
public ForcedTypedXmlPullParser(XmlPullParser wrapped) {
@@ -1715,6 +1717,7 @@ public class XmlUtils {
}
}
+ @SuppressWarnings("AndroidFrameworkEfficientXml")
public static int readIntAttribute(XmlPullParser in, String name, int defaultValue) {
if (in instanceof TypedXmlPullParser) {
return ((TypedXmlPullParser) in).getAttributeInt(null, name, defaultValue);
@@ -1730,6 +1733,7 @@ public class XmlUtils {
}
}
+ @SuppressWarnings("AndroidFrameworkEfficientXml")
public static int readIntAttribute(XmlPullParser in, String name) throws IOException {
if (in instanceof TypedXmlPullParser) {
try {
@@ -1746,6 +1750,7 @@ public class XmlUtils {
}
}
+ @SuppressWarnings("AndroidFrameworkEfficientXml")
public static void writeIntAttribute(XmlSerializer out, String name, int value)
throws IOException {
if (out instanceof TypedXmlSerializer) {
@@ -1755,6 +1760,7 @@ public class XmlUtils {
out.attribute(null, name, Integer.toString(value));
}
+ @SuppressWarnings("AndroidFrameworkEfficientXml")
public static long readLongAttribute(XmlPullParser in, String name, long defaultValue) {
if (in instanceof TypedXmlPullParser) {
return ((TypedXmlPullParser) in).getAttributeLong(null, name, defaultValue);
@@ -1770,6 +1776,7 @@ public class XmlUtils {
}
}
+ @SuppressWarnings("AndroidFrameworkEfficientXml")
public static long readLongAttribute(XmlPullParser in, String name) throws IOException {
if (in instanceof TypedXmlPullParser) {
try {
@@ -1786,6 +1793,7 @@ public class XmlUtils {
}
}
+ @SuppressWarnings("AndroidFrameworkEfficientXml")
public static void writeLongAttribute(XmlSerializer out, String name, long value)
throws IOException {
if (out instanceof TypedXmlSerializer) {
@@ -1795,6 +1803,7 @@ public class XmlUtils {
out.attribute(null, name, Long.toString(value));
}
+ @SuppressWarnings("AndroidFrameworkEfficientXml")
public static float readFloatAttribute(XmlPullParser in, String name) throws IOException {
if (in instanceof TypedXmlPullParser) {
try {
@@ -1811,6 +1820,7 @@ public class XmlUtils {
}
}
+ @SuppressWarnings("AndroidFrameworkEfficientXml")
public static void writeFloatAttribute(XmlSerializer out, String name, float value)
throws IOException {
if (out instanceof TypedXmlSerializer) {
@@ -1820,10 +1830,12 @@ public class XmlUtils {
out.attribute(null, name, Float.toString(value));
}
+ @SuppressWarnings("AndroidFrameworkEfficientXml")
public static boolean readBooleanAttribute(XmlPullParser in, String name) {
return readBooleanAttribute(in, name, false);
}
+ @SuppressWarnings("AndroidFrameworkEfficientXml")
public static boolean readBooleanAttribute(XmlPullParser in, String name,
boolean defaultValue) {
if (in instanceof TypedXmlPullParser) {
@@ -1837,6 +1849,7 @@ public class XmlUtils {
}
}
+ @SuppressWarnings("AndroidFrameworkEfficientXml")
public static void writeBooleanAttribute(XmlSerializer out, String name, boolean value)
throws IOException {
if (out instanceof TypedXmlSerializer) {
@@ -1869,6 +1882,7 @@ public class XmlUtils {
}
}
+ @SuppressWarnings("AndroidFrameworkEfficientXml")
public static byte[] readByteArrayAttribute(XmlPullParser in, String name) {
if (in instanceof TypedXmlPullParser) {
try {
@@ -1885,6 +1899,7 @@ public class XmlUtils {
}
}
+ @SuppressWarnings("AndroidFrameworkEfficientXml")
public static void writeByteArrayAttribute(XmlSerializer out, String name, byte[] value)
throws IOException {
if (value != null) {
diff --git a/core/java/com/android/server/BootReceiver.java b/core/java/com/android/server/BootReceiver.java
index ac2361dff560..b4d8e506c61a 100644
--- a/core/java/com/android/server/BootReceiver.java
+++ b/core/java/com/android/server/BootReceiver.java
@@ -35,24 +35,23 @@ import android.text.TextUtils;
import android.util.AtomicFile;
import android.util.EventLog;
import android.util.Slog;
+import android.util.TypedXmlPullParser;
+import android.util.TypedXmlSerializer;
import android.util.Xml;
import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.logging.MetricsLogger;
-import com.android.internal.util.FastXmlSerializer;
import com.android.internal.util.FrameworkStatsLog;
import com.android.internal.util.XmlUtils;
import org.xmlpull.v1.XmlPullParser;
import org.xmlpull.v1.XmlPullParserException;
-import org.xmlpull.v1.XmlSerializer;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
-import java.nio.charset.StandardCharsets;
import java.util.HashMap;
import java.util.Iterator;
import java.util.regex.Matcher;
@@ -712,8 +711,7 @@ public class BootReceiver extends BroadcastReceiver {
HashMap<String, Long> timestamps = new HashMap<String, Long>();
boolean success = false;
try (final FileInputStream stream = sFile.openRead()) {
- XmlPullParser parser = Xml.newPullParser();
- parser.setInput(stream, StandardCharsets.UTF_8.name());
+ TypedXmlPullParser parser = Xml.resolvePullParser(stream);
int type;
while ((type = parser.next()) != XmlPullParser.START_TAG
@@ -735,8 +733,7 @@ public class BootReceiver extends BroadcastReceiver {
String tagName = parser.getName();
if (tagName.equals("log")) {
final String filename = parser.getAttributeValue(null, "filename");
- final long timestamp = Long.valueOf(parser.getAttributeValue(
- null, "timestamp"));
+ final long timestamp = parser.getAttributeLong(null, "timestamp");
timestamps.put(filename, timestamp);
} else {
Slog.w(TAG, "Unknown tag: " + parser.getName());
@@ -775,8 +772,7 @@ public class BootReceiver extends BroadcastReceiver {
}
try {
- XmlSerializer out = new FastXmlSerializer();
- out.setOutput(stream, StandardCharsets.UTF_8.name());
+ TypedXmlSerializer out = Xml.resolveSerializer(stream);
out.startDocument(null, true);
out.startTag(null, "log-files");
@@ -785,7 +781,7 @@ public class BootReceiver extends BroadcastReceiver {
String filename = itor.next();
out.startTag(null, "log");
out.attribute(null, "filename", filename);
- out.attribute(null, "timestamp", timestamps.get(filename).toString());
+ out.attributeLong(null, "timestamp", timestamps.get(filename));
out.endTag(null, "log");
}
diff --git a/core/jni/android_os_Debug.cpp b/core/jni/android_os_Debug.cpp
index 5a859aabce7b..bf79a4472fa5 100644
--- a/core/jni/android_os_Debug.cpp
+++ b/core/jni/android_os_Debug.cpp
@@ -571,6 +571,9 @@ enum {
MEMINFO_PAGE_TABLES,
MEMINFO_KERNEL_STACK,
MEMINFO_KERNEL_RECLAIMABLE,
+ MEMINFO_ACTIVE,
+ MEMINFO_INACTIVE,
+ MEMINFO_UNEVICTABLE,
MEMINFO_COUNT
};
diff --git a/core/res/res/drawable/view_accessibility_focused.xml b/core/res/res/drawable/view_accessibility_focused.xml
index 025916b35f40..aa3031e5cf26 100644
--- a/core/res/res/drawable/view_accessibility_focused.xml
+++ b/core/res/res/drawable/view_accessibility_focused.xml
@@ -17,8 +17,8 @@
<shape xmlns:android="http://schemas.android.com/apk/res/android" >
<stroke
- android:width="4dp"
- android:color="@color/accessibility_focus_highlight" />
+ android:width="@dimen/accessibility_focus_highlight_stroke_width"
+ android:color="@color/accessibility_focus_highlight_color" />
<corners android:radius="2dp" />
diff --git a/core/res/res/layout/notification_top_line_views.xml b/core/res/res/layout/notification_top_line_views.xml
index c71e8863502c..60507eddba22 100644
--- a/core/res/res/layout/notification_top_line_views.xml
+++ b/core/res/res/layout/notification_top_line_views.xml
@@ -88,7 +88,7 @@
<DateTimeView
android:id="@+id/time"
- android:textAppearance="@style/TextAppearance.Material.Notification.Time"
+ android:textAppearance="@style/TextAppearance.DeviceDefault.Notification.Time"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginStart="@dimen/notification_header_separating_margin"
diff --git a/core/res/res/values/colors.xml b/core/res/res/values/colors.xml
index 0079d8cd0276..110e77a8aa05 100644
--- a/core/res/res/values/colors.xml
+++ b/core/res/res/values/colors.xml
@@ -159,7 +159,7 @@
<color name="keyguard_avatar_nick_color">#ffffffff</color>
<color name="keyguard_avatar_frame_pressed_color">#ff35b5e5</color>
- <color name="accessibility_focus_highlight">#bf39b500</color>
+ <color name="accessibility_focus_highlight_color">#bf39b500</color>
<color name="autofilled_highlight">#4dffeb3b</color>
<color name="system_notification_accent_color">#ff607D8B</color>
diff --git a/core/res/res/values/config.xml b/core/res/res/values/config.xml
index 84e6f12c0b51..40e11cb92d3e 100644
--- a/core/res/res/values/config.xml
+++ b/core/res/res/values/config.xml
@@ -1613,21 +1613,28 @@
<!-- Whether the geolocation time zone detection feature is enabled. -->
<bool name="config_enableGeolocationTimeZoneDetection" translatable="false">true</bool>
- <!-- Whether to enable primary location time zone provider overlay which allows the primary
- location time zone provider to be replaced by an app at run-time. When disabled, only the
+ <!-- Whether the primary LocationTimeZoneProvider is enabled device.
+ Ignored if config_enableGeolocationTimeZoneDetection is false -->
+ <bool name="config_enablePrimaryLocationTimeZoneProvider" translatable="false">false</bool>
+ <!-- Used when enablePrimaryLocationTimeZoneProvider is true. Controls whether to enable primary
+ location time zone provider overlay which allows the primary location time zone provider to
+ be replaced by an app at run-time. When disabled, only the
config_primaryLocationTimeZoneProviderPackageName package will be searched for the primary
location time zone provider, otherwise any system package is eligible. Anyone who wants to
- disable the overlay mechanism can set it to false. -->
+ disable the runtime overlay mechanism can set it to false. -->
<bool name="config_enablePrimaryLocationTimeZoneOverlay" translatable="false">false</bool>
<!-- Package name providing the primary location time zone provider. Used only when
config_enablePrimaryLocationTimeZoneOverlay is false. -->
<string name="config_primaryLocationTimeZoneProviderPackageName" translatable="false">@null</string>
- <!-- Whether to enable secondary location time zone provider overlay which allows the secondary
- location time zone provider to be replaced by an app at run-time. When disabled, only the
- config_secondaryLocationTimeZoneProviderPackageName package will be searched for the
- secondary location time zone provider, otherwise any system package is eligible. Anyone who
- wants to disable the overlay mechanism can set it to false. -->
+ <!-- Whether the secondary LocationTimeZoneProvider is enabled device.
+ Ignored if config_enableGeolocationTimeZoneDetection is false -->
+ <bool name="config_enableSecondaryLocationTimeZoneProvider" translatable="false">true</bool>
+ <!-- Used when enableSecondaryLocationTimeZoneProvider is true. Controls whether to enable
+ secondary location time zone provider overlay which allows the primary location time zone
+ provider to config_secondaryLocationTimeZoneProviderPackageName package will be searched
+ for the secondary location time zone provider, otherwise any system package is eligible.
+ Anyone who wants to disable the runtime overlay mechanism can set it to false. -->
<bool name="config_enableSecondaryLocationTimeZoneOverlay" translatable="false">false</bool>
<!-- Package name providing the secondary location time zone provider. Used only when
config_enableSecondaryLocationTimeZoneOverlay is false.
@@ -4515,7 +4522,7 @@
<integer name="config_pdp_reject_retry_delay_ms">-1</integer>
<!-- Whether or not to enable the binder heavy hitter watcher by default -->
- <bool name="config_defaultBinderHeavyHitterWatcherEnabled">true</bool>
+ <bool name="config_defaultBinderHeavyHitterWatcherEnabled">false</bool>
<!-- The default batch size for the binder heavy hitter watcher -->
<integer name="config_defaultBinderHeavyHitterWatcherBatchSize">2000</integer>
@@ -4526,7 +4533,7 @@
</item>
<!-- Whether or not to enable the binder heavy hitter auto sampler by default -->
- <bool name="config_defaultBinderHeavyHitterAutoSamplerEnabled">true</bool>
+ <bool name="config_defaultBinderHeavyHitterAutoSamplerEnabled">false</bool>
<!-- The default batch size for the binder heavy hitter auto sampler -->
<integer name="config_defaultBinderHeavyHitterAutoSamplerBatchSize">400</integer>
diff --git a/core/res/res/values/dimens.xml b/core/res/res/values/dimens.xml
index 4bcabff109ea..05db741643e8 100644
--- a/core/res/res/values/dimens.xml
+++ b/core/res/res/values/dimens.xml
@@ -553,6 +553,9 @@
<!-- Width of the outline stroke used by the accessibility screen magnification indicator -->
<dimen name="accessibility_magnification_indicator_width">4dip</dimen>
+ <!-- Width of the outline stroke used by the accessibility focus rectangle -->
+ <dimen name="accessibility_focus_highlight_stroke_width">4dp</dimen>
+
<!-- Margin around the various security views -->
<dimen name="keyguard_muliuser_selector_margin">8dp</dimen>
diff --git a/core/res/res/values/symbols.xml b/core/res/res/values/symbols.xml
index cd00fbf204cf..e50eee6afa91 100644
--- a/core/res/res/values/symbols.xml
+++ b/core/res/res/values/symbols.xml
@@ -2168,8 +2168,10 @@
<java-symbol type="string" name="config_deviceConfiguratorPackageName" />
<java-symbol type="array" name="config_autoTimeSourcesPriority" />
<java-symbol type="bool" name="config_enableGeolocationTimeZoneDetection" />
+ <java-symbol type="bool" name="config_enablePrimaryLocationTimeZoneProvider" />
<java-symbol type="bool" name="config_enablePrimaryLocationTimeZoneOverlay" />
<java-symbol type="string" name="config_primaryLocationTimeZoneProviderPackageName" />
+ <java-symbol type="bool" name="config_enableSecondaryLocationTimeZoneProvider" />
<java-symbol type="bool" name="config_enableSecondaryLocationTimeZoneOverlay" />
<java-symbol type="string" name="config_secondaryLocationTimeZoneProviderPackageName" />
@@ -4115,4 +4117,9 @@
<!-- Component with platform query permissions for AppSearch -->
<java-symbol type="string" name="config_defaultAppSearchPlatformQuerierComponent" />
+
+ <!-- Color used by the accessibility focus rectangle -->
+ <java-symbol type="color" name="accessibility_focus_highlight_color" />
+ <!-- Width of the outline stroke used by the accessibility focus rectangle -->
+ <java-symbol type="dimen" name="accessibility_focus_highlight_stroke_width" />
</resources>
diff --git a/core/tests/coretests/src/android/content/pm/RegisteredServicesCacheTest.java b/core/tests/coretests/src/android/content/pm/RegisteredServicesCacheTest.java
index 365e97ded928..e04d9034d2c1 100644
--- a/core/tests/coretests/src/android/content/pm/RegisteredServicesCacheTest.java
+++ b/core/tests/coretests/src/android/content/pm/RegisteredServicesCacheTest.java
@@ -24,12 +24,12 @@ import android.os.UserHandle;
import android.test.AndroidTestCase;
import android.util.AttributeSet;
import android.util.SparseArray;
+import android.util.TypedXmlPullParser;
+import android.util.TypedXmlSerializer;
import androidx.test.filters.LargeTest;
-import org.xmlpull.v1.XmlPullParser;
import org.xmlpull.v1.XmlPullParserException;
-import org.xmlpull.v1.XmlSerializer;
import java.io.ByteArrayInputStream;
import java.io.File;
@@ -308,12 +308,12 @@ public class RegisteredServicesCacheTest extends AndroidTestCase {
static class TestSerializer implements XmlSerializerAndParser<TestServiceType> {
- public void writeAsXml(TestServiceType item, XmlSerializer out) throws IOException {
+ public void writeAsXml(TestServiceType item, TypedXmlSerializer out) throws IOException {
out.attribute(null, "type", item.type);
out.attribute(null, "value", item.value);
}
- public TestServiceType createFromXml(XmlPullParser parser)
+ public TestServiceType createFromXml(TypedXmlPullParser parser)
throws IOException, XmlPullParserException {
final String type = parser.getAttributeValue(null, "type");
final String value = parser.getAttributeValue(null, "value");
diff --git a/core/tests/coretests/src/android/hardware/display/BrightnessConfigurationTest.java b/core/tests/coretests/src/android/hardware/display/BrightnessConfigurationTest.java
index 4370462279b2..e750454a01ff 100644
--- a/core/tests/coretests/src/android/hardware/display/BrightnessConfigurationTest.java
+++ b/core/tests/coretests/src/android/hardware/display/BrightnessConfigurationTest.java
@@ -23,18 +23,16 @@ import static org.junit.Assert.fail;
import android.os.Parcel;
import android.util.Pair;
+import android.util.TypedXmlPullParser;
+import android.util.TypedXmlSerializer;
import android.util.Xml;
import androidx.test.filters.SmallTest;
import androidx.test.runner.AndroidJUnit4;
-import com.android.internal.util.FastXmlSerializer;
-
import org.junit.Test;
import org.junit.runner.RunWith;
-import org.xmlpull.v1.XmlPullParser;
import org.xmlpull.v1.XmlPullParserException;
-import org.xmlpull.v1.XmlSerializer;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
@@ -163,7 +161,7 @@ public class BrightnessConfigurationTest {
BrightnessConfiguration config = builder.build();
ByteArrayOutputStream baos = new ByteArrayOutputStream();
- XmlSerializer out = new FastXmlSerializer();
+ TypedXmlSerializer out = Xml.newFastSerializer();
out.setOutput(baos, StandardCharsets.UTF_8.name());
out.startDocument(null, true);
config.saveToXml(out);
@@ -171,7 +169,7 @@ public class BrightnessConfigurationTest {
baos.flush();
ByteArrayInputStream input = new ByteArrayInputStream(baos.toByteArray());
- XmlPullParser parser = Xml.newPullParser();
+ TypedXmlPullParser parser = Xml.newFastPullParser();
parser.setInput(input, StandardCharsets.UTF_8.name());
BrightnessConfiguration loadedConfig = BrightnessConfiguration.loadFromXml(parser);
diff --git a/core/tests/coretests/src/android/util/BinaryXmlTest.java b/core/tests/coretests/src/android/util/BinaryXmlTest.java
index be63a0ecc65f..6fa5a2343361 100644
--- a/core/tests/coretests/src/android/util/BinaryXmlTest.java
+++ b/core/tests/coretests/src/android/util/BinaryXmlTest.java
@@ -20,6 +20,8 @@ import static android.util.XmlTest.assertNext;
import static android.util.XmlTest.buildPersistableBundle;
import static android.util.XmlTest.doPersistableBundleRead;
import static android.util.XmlTest.doPersistableBundleWrite;
+import static android.util.XmlTest.doVerifyRead;
+import static android.util.XmlTest.doVerifyWrite;
import static org.junit.Assert.assertEquals;
import static org.xmlpull.v1.XmlPullParser.START_TAG;
@@ -33,6 +35,11 @@ import org.junit.runner.RunWith;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.FileOutputStream;
+import java.io.InputStream;
+import java.io.OutputStream;
import java.nio.charset.StandardCharsets;
@RunWith(AndroidJUnit4.class)
@@ -96,4 +103,58 @@ public class BinaryXmlTest {
final PersistableBundle actual = doPersistableBundleRead(secondIn, os.toByteArray());
assertEquals(expected.toString(), actual.toString());
}
+
+ @Test
+ public void testResolve_File() throws Exception {
+ {
+ final File file = File.createTempFile("fast", ".xml");
+ try (OutputStream os = new FileOutputStream(file)) {
+ TypedXmlSerializer xml = Xml.newFastSerializer();
+ xml.setOutput(os, StandardCharsets.UTF_8.name());
+ doVerifyWrite(xml);
+ }
+ try (InputStream is = new FileInputStream(file)) {
+ doVerifyRead(Xml.resolvePullParser(is));
+ }
+ }
+ {
+ final File file = File.createTempFile("binary", ".xml");
+ try (OutputStream os = new FileOutputStream(file)) {
+ TypedXmlSerializer xml = Xml.newBinarySerializer();
+ xml.setOutput(os, StandardCharsets.UTF_8.name());
+ doVerifyWrite(xml);
+ }
+ try (InputStream is = new FileInputStream(file)) {
+ doVerifyRead(Xml.resolvePullParser(is));
+ }
+ }
+ }
+
+ @Test
+ public void testResolve_Memory() throws Exception {
+ {
+ final byte[] data;
+ try (ByteArrayOutputStream os = new ByteArrayOutputStream()) {
+ TypedXmlSerializer xml = Xml.newFastSerializer();
+ xml.setOutput(os, StandardCharsets.UTF_8.name());
+ doVerifyWrite(xml);
+ data = os.toByteArray();
+ }
+ try (InputStream is = new ByteArrayInputStream(data)) {
+ doVerifyRead(Xml.resolvePullParser(is));
+ }
+ }
+ {
+ final byte[] data;
+ try (ByteArrayOutputStream os = new ByteArrayOutputStream()) {
+ TypedXmlSerializer xml = Xml.newBinarySerializer();
+ xml.setOutput(os, StandardCharsets.UTF_8.name());
+ doVerifyWrite(xml);
+ data = os.toByteArray();
+ }
+ try (InputStream is = new ByteArrayInputStream(data)) {
+ doVerifyRead(Xml.resolvePullParser(is));
+ }
+ }
+ }
}
diff --git a/core/tests/coretests/src/android/util/XmlTest.java b/core/tests/coretests/src/android/util/XmlTest.java
index 5ae17c46944f..a8fc6f933605 100644
--- a/core/tests/coretests/src/android/util/XmlTest.java
+++ b/core/tests/coretests/src/android/util/XmlTest.java
@@ -205,7 +205,7 @@ public class XmlTest {
private static final byte[] TEST_BYTES = new byte[] { 0, 1, 2, 3, 4, 3, 2, 1, 0 };
private static final byte[] TEST_BYTES_EMPTY = new byte[0];
- private static void doVerifyWrite(TypedXmlSerializer out) throws Exception {
+ static void doVerifyWrite(TypedXmlSerializer out) throws Exception {
out.startDocument(StandardCharsets.UTF_8.name(), true);
out.startTag(null, "one");
{
@@ -244,7 +244,7 @@ public class XmlTest {
out.endDocument();
}
- private static void doVerifyRead(TypedXmlPullParser in) throws Exception {
+ static void doVerifyRead(TypedXmlPullParser in) throws Exception {
assertEquals(START_DOCUMENT, in.getEventType());
assertNext(in, START_TAG, "one", 1);
{
diff --git a/core/tests/coretests/src/android/view/accessibility/AccessibilityManagerTest.java b/core/tests/coretests/src/android/view/accessibility/AccessibilityManagerTest.java
index 8e2490789a6f..75116d8c6df2 100644
--- a/core/tests/coretests/src/android/view/accessibility/AccessibilityManagerTest.java
+++ b/core/tests/coretests/src/android/view/accessibility/AccessibilityManagerTest.java
@@ -38,6 +38,7 @@ import android.os.UserHandle;
import androidx.test.InstrumentationRegistry;
import androidx.test.runner.AndroidJUnit4;
+import com.android.internal.R;
import com.android.internal.util.IntPair;
import com.android.server.accessibility.test.MessageCapturingHandler;
@@ -73,12 +74,18 @@ public class AccessibilityManagerTest {
@Mock private IAccessibilityManager mMockService;
private MessageCapturingHandler mHandler;
private Instrumentation mInstrumentation;
+ private int mFocusStrokeWidthDefaultValue;
+ private int mFocusColorDefaultValue;
@Before
public void setUp() throws Exception {
MockitoAnnotations.initMocks(this);
mHandler = new MessageCapturingHandler(null);
mInstrumentation = InstrumentationRegistry.getInstrumentation();
+ mFocusStrokeWidthDefaultValue = mInstrumentation.getContext().getResources()
+ .getDimensionPixelSize(R.dimen.accessibility_focus_highlight_stroke_width);
+ mFocusColorDefaultValue = mInstrumentation.getContext().getResources().getColor(
+ R.color.accessibility_focus_highlight_color);
}
@After
@@ -94,8 +101,12 @@ public class AccessibilityManagerTest {
when(mMockService.addClient(any(IAccessibilityManagerClient.class), anyInt()))
.thenReturn(serviceReturnValue);
+ when(mMockService.getFocusStrokeWidth()).thenReturn(mFocusStrokeWidthDefaultValue);
+ when(mMockService.getFocusColor()).thenReturn(mFocusColorDefaultValue);
+
AccessibilityManager manager =
- new AccessibilityManager(mHandler, mMockService, UserHandle.USER_CURRENT);
+ new AccessibilityManager(mInstrumentation.getContext(), mHandler, mMockService,
+ UserHandle.USER_CURRENT, true);
verify(mMockService).addClient(any(IAccessibilityManagerClient.class), anyInt());
mHandler.setCallback(manager.getCallback());
@@ -205,4 +216,16 @@ public class AccessibilityManagerTest {
verify(mMockService).setWindowMagnificationConnection(connection);
}
+
+ @Test
+ public void testGetDefaultValueOfFocusAppearanceData() {
+ AccessibilityManager manager =
+ new AccessibilityManager(mInstrumentation.getContext(), mHandler, null,
+ UserHandle.USER_CURRENT, false);
+
+ assertEquals(mFocusStrokeWidthDefaultValue,
+ manager.getAccessibilityFocusStrokeWidth());
+ assertEquals(mFocusColorDefaultValue,
+ manager.getAccessibilityFocusColor());
+ }
}
diff --git a/core/tests/coretests/src/android/view/accessibility/AccessibilityServiceConnectionImpl.java b/core/tests/coretests/src/android/view/accessibility/AccessibilityServiceConnectionImpl.java
index 75a7504cac2f..cfdb2b769a08 100644
--- a/core/tests/coretests/src/android/view/accessibility/AccessibilityServiceConnectionImpl.java
+++ b/core/tests/coretests/src/android/view/accessibility/AccessibilityServiceConnectionImpl.java
@@ -161,4 +161,6 @@ public class AccessibilityServiceConnectionImpl extends IAccessibilityServiceCon
public void setTouchExplorationPassthroughRegion(int displayId, Region region) {}
public void setGestureDetectionPassthroughRegion(int displayId, Region region) {}
+
+ public void setFocusAppearance(int strokeWidth, int color) {}
}
diff --git a/core/tests/coretests/src/com/android/internal/accessibility/AccessibilityShortcutControllerTest.java b/core/tests/coretests/src/com/android/internal/accessibility/AccessibilityShortcutControllerTest.java
index c17c36eba2dc..6baf3056be32 100644
--- a/core/tests/coretests/src/com/android/internal/accessibility/AccessibilityShortcutControllerTest.java
+++ b/core/tests/coretests/src/com/android/internal/accessibility/AccessibilityShortcutControllerTest.java
@@ -68,6 +68,7 @@ import android.view.accessibility.AccessibilityManager;
import android.view.accessibility.IAccessibilityManager;
import android.widget.Toast;
+import androidx.test.InstrumentationRegistry;
import androidx.test.runner.AndroidJUnit4;
import com.android.internal.R;
@@ -148,7 +149,8 @@ public class AccessibilityShortcutControllerTest {
// Use the extra level of indirection in the object to mock framework objects
AccessibilityManager accessibilityManager =
- new AccessibilityManager(mHandler, mAccessibilityManagerService, 0);
+ new AccessibilityManager(InstrumentationRegistry.getContext(), mHandler,
+ mAccessibilityManagerService, 0, true);
when(mFrameworkObjectProvider.getAccessibilityManagerInstance(mContext))
.thenReturn(accessibilityManager);
when(mContext.getSystemService(Context.ACCESSIBILITY_SERVICE))
diff --git a/core/tests/uwbtests/Android.bp b/core/tests/uwbtests/Android.bp
index c41c346b131a..8ee86f470c9e 100644
--- a/core/tests/uwbtests/Android.bp
+++ b/core/tests/uwbtests/Android.bp
@@ -17,6 +17,7 @@ android_test {
static_libs: [
"androidx.test.ext.junit",
"androidx.test.rules",
+ "mockito-target-minus-junit4",
],
libs: [
"android.test.runner",
diff --git a/core/tests/uwbtests/src/android/uwb/AdapterStateListenerTest.java b/core/tests/uwbtests/src/android/uwb/AdapterStateListenerTest.java
new file mode 100644
index 000000000000..ce67ef7868e8
--- /dev/null
+++ b/core/tests/uwbtests/src/android/uwb/AdapterStateListenerTest.java
@@ -0,0 +1,311 @@
+/*
+ * Copyright 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.uwb;
+
+import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.ArgumentMatchers.anyBoolean;
+import static org.mockito.ArgumentMatchers.anyInt;
+import static org.mockito.Mockito.doAnswer;
+import static org.mockito.Mockito.doThrow;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.times;
+import static org.mockito.Mockito.verify;
+
+
+import android.os.RemoteException;
+import android.uwb.UwbManager.AdapterStateCallback;
+
+import androidx.test.ext.junit.runners.AndroidJUnit4;
+import androidx.test.filters.SmallTest;
+
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.invocation.InvocationOnMock;
+import org.mockito.stubbing.Answer;
+
+import java.util.ArrayList;
+import java.util.List;
+import java.util.concurrent.Executor;
+
+/**
+ * Test of {@link AdapterStateListener}.
+ */
+@SmallTest
+@RunWith(AndroidJUnit4.class)
+public class AdapterStateListenerTest {
+
+ IUwbAdapter mUwbAdapter = mock(IUwbAdapter.class);
+
+ Answer mRegisterSuccessAnswer = new Answer() {
+ public Object answer(InvocationOnMock invocation) {
+ Object[] args = invocation.getArguments();
+ IUwbAdapterStateCallbacks cb = (IUwbAdapterStateCallbacks) args[0];
+ try {
+ cb.onAdapterStateChanged(false, StateChangeReason.UNKNOWN);
+ } catch (RemoteException e) {
+ // Nothing to do
+ }
+ return new Object();
+ }
+ };
+
+ Throwable mThrowRemoteException = new RemoteException("RemoteException");
+
+ private static Executor getExecutor() {
+ return new Executor() {
+ @Override
+ public void execute(Runnable command) {
+ command.run();
+ }
+ };
+ }
+
+ private static void verifyCallbackStateChangedInvoked(
+ AdapterStateCallback callback, int numTimes) {
+ verify(callback, times(numTimes)).onStateChanged(anyBoolean(), anyInt());
+ }
+
+ @Test
+ public void testRegister_RegisterUnregister() throws RemoteException {
+ doAnswer(mRegisterSuccessAnswer).when(mUwbAdapter).registerAdapterStateCallbacks(any());
+
+ AdapterStateListener adapterStateListener = new AdapterStateListener(mUwbAdapter);
+ AdapterStateCallback callback1 = mock(AdapterStateCallback.class);
+ AdapterStateCallback callback2 = mock(AdapterStateCallback.class);
+
+ // Verify that the adapter state listener registered with the UWB Adapter
+ adapterStateListener.register(getExecutor(), callback1);
+ verify(mUwbAdapter, times(1)).registerAdapterStateCallbacks(any());
+ verifyCallbackStateChangedInvoked(callback1, 1);
+ verifyCallbackStateChangedInvoked(callback2, 0);
+
+ // Register a second client and no new call to UWB Adapter
+ adapterStateListener.register(getExecutor(), callback2);
+ verify(mUwbAdapter, times(1)).registerAdapterStateCallbacks(any());
+ verifyCallbackStateChangedInvoked(callback1, 1);
+ verifyCallbackStateChangedInvoked(callback2, 1);
+
+ // Unregister first callback
+ adapterStateListener.unregister(callback1);
+ verify(mUwbAdapter, times(1)).registerAdapterStateCallbacks(any());
+ verify(mUwbAdapter, times(0)).unregisterAdapterStateCallbacks(any());
+ verifyCallbackStateChangedInvoked(callback1, 1);
+ verifyCallbackStateChangedInvoked(callback2, 1);
+
+ // Unregister second callback
+ adapterStateListener.unregister(callback2);
+ verify(mUwbAdapter, times(1)).registerAdapterStateCallbacks(any());
+ verify(mUwbAdapter, times(1)).unregisterAdapterStateCallbacks(any());
+ verifyCallbackStateChangedInvoked(callback1, 1);
+ verifyCallbackStateChangedInvoked(callback2, 1);
+ }
+
+ @Test
+ public void testRegister_FirstRegisterFails() throws RemoteException {
+ AdapterStateListener adapterStateListener = new AdapterStateListener(mUwbAdapter);
+ AdapterStateCallback callback1 = mock(AdapterStateCallback.class);
+ AdapterStateCallback callback2 = mock(AdapterStateCallback.class);
+
+ // Throw a remote exception whenever first registering
+ doThrow(mThrowRemoteException).when(mUwbAdapter).registerAdapterStateCallbacks(any());
+
+ adapterStateListener.register(getExecutor(), callback1);
+ verify(mUwbAdapter, times(1)).registerAdapterStateCallbacks(any());
+
+ // No longer throw an exception, instead succeed
+ doAnswer(mRegisterSuccessAnswer).when(mUwbAdapter).registerAdapterStateCallbacks(any());
+
+ // Register a different callback
+ adapterStateListener.register(getExecutor(), callback2);
+ verify(mUwbAdapter, times(2)).registerAdapterStateCallbacks(any());
+
+ // Ensure first callback was invoked again
+ verifyCallbackStateChangedInvoked(callback1, 2);
+ verifyCallbackStateChangedInvoked(callback2, 1);
+ }
+
+ @Test
+ public void testRegister_RegisterSameCallbackTwice() throws RemoteException {
+ AdapterStateListener adapterStateListener = new AdapterStateListener(mUwbAdapter);
+ AdapterStateCallback callback = mock(AdapterStateCallback.class);
+ doAnswer(mRegisterSuccessAnswer).when(mUwbAdapter).registerAdapterStateCallbacks(any());
+
+ adapterStateListener.register(getExecutor(), callback);
+ verifyCallbackStateChangedInvoked(callback, 1);
+
+ adapterStateListener.register(getExecutor(), callback);
+ verifyCallbackStateChangedInvoked(callback, 1);
+
+ // Invoke a state change and ensure the callback is only called once
+ adapterStateListener.onAdapterStateChanged(false, StateChangeReason.UNKNOWN);
+ verifyCallbackStateChangedInvoked(callback, 2);
+ }
+
+ @Test
+ public void testCallback_RunViaExecutor_Success() throws RemoteException {
+ // Verify that the callbacks are invoked on the executor when successful
+ doAnswer(mRegisterSuccessAnswer).when(mUwbAdapter).registerAdapterStateCallbacks(any());
+ runViaExecutor();
+ }
+
+ @Test
+ public void testCallback_RunViaExecutor_Failure() throws RemoteException {
+ // Verify that the callbacks are invoked on the executor when there is a remote exception
+ doThrow(mThrowRemoteException).when(mUwbAdapter).registerAdapterStateCallbacks(any());
+ runViaExecutor();
+ }
+
+ private void runViaExecutor() {
+ AdapterStateListener adapterStateListener = new AdapterStateListener(mUwbAdapter);
+ AdapterStateCallback callback = mock(AdapterStateCallback.class);
+
+ Executor executor = mock(Executor.class);
+
+ // Do not run commands received and ensure that the callback is not invoked
+ doAnswer(new ExecutorAnswer(false)).when(executor).execute(any());
+ adapterStateListener.register(executor, callback);
+ verify(executor, times(1)).execute(any());
+ verifyCallbackStateChangedInvoked(callback, 0);
+
+ // Manually invoke the callback and ensure callback is not invoked
+ adapterStateListener.onAdapterStateChanged(false, StateChangeReason.UNKNOWN);
+ verify(executor, times(2)).execute(any());
+ verifyCallbackStateChangedInvoked(callback, 0);
+
+ // Run the command that the executor receives
+ doAnswer(new ExecutorAnswer(true)).when(executor).execute(any());
+ adapterStateListener.onAdapterStateChanged(false, StateChangeReason.UNKNOWN);
+ verify(executor, times(3)).execute(any());
+ verifyCallbackStateChangedInvoked(callback, 1);
+ }
+
+ class ExecutorAnswer implements Answer {
+
+ final boolean mShouldRun;
+ ExecutorAnswer(boolean shouldRun) {
+ mShouldRun = shouldRun;
+ }
+
+ @Override
+ public Object answer(InvocationOnMock invocation) throws Throwable {
+ if (mShouldRun) {
+ ((Runnable) invocation.getArgument(0)).run();
+ }
+ return null;
+ }
+ }
+
+ @Test
+ public void testNotify_AllCallbacksNotified() throws RemoteException {
+ doAnswer(mRegisterSuccessAnswer).when(mUwbAdapter).registerAdapterStateCallbacks(any());
+
+ AdapterStateListener adapterStateListener = new AdapterStateListener(mUwbAdapter);
+ List<AdapterStateCallback> callbacks = new ArrayList<>();
+ for (int i = 0; i < 10; i++) {
+ AdapterStateCallback callback = mock(AdapterStateCallback.class);
+ adapterStateListener.register(getExecutor(), callback);
+ callbacks.add(callback);
+ }
+
+ // Ensure every callback got the initial state
+ for (AdapterStateCallback callback : callbacks) {
+ verifyCallbackStateChangedInvoked(callback, 1);
+ }
+
+ // Invoke a state change and ensure all callbacks are invoked
+ adapterStateListener.onAdapterStateChanged(true, StateChangeReason.ALL_SESSIONS_CLOSED);
+ for (AdapterStateCallback callback : callbacks) {
+ verifyCallbackStateChangedInvoked(callback, 2);
+ }
+ }
+
+ @Test
+ public void testStateChange_CorrectValue() {
+ AdapterStateListener adapterStateListener = new AdapterStateListener(mUwbAdapter);
+
+ AdapterStateCallback callback = mock(AdapterStateCallback.class);
+
+ adapterStateListener.register(getExecutor(), callback);
+
+ runStateChangeValue(StateChangeReason.ALL_SESSIONS_CLOSED,
+ AdapterStateCallback.STATE_CHANGED_REASON_ALL_SESSIONS_CLOSED);
+
+ runStateChangeValue(StateChangeReason.SESSION_STARTED,
+ AdapterStateCallback.STATE_CHANGED_REASON_SESSION_STARTED);
+
+ runStateChangeValue(StateChangeReason.SYSTEM_BOOT,
+ AdapterStateCallback.STATE_CHANGED_REASON_SYSTEM_BOOT);
+
+ runStateChangeValue(StateChangeReason.SYSTEM_POLICY,
+ AdapterStateCallback.STATE_CHANGED_REASON_SYSTEM_POLICY);
+
+ runStateChangeValue(StateChangeReason.UNKNOWN,
+ AdapterStateCallback.STATE_CHANGED_REASON_ERROR_UNKNOWN);
+ }
+
+ private void runStateChangeValue(@StateChangeReason int reasonIn,
+ @AdapterStateCallback.StateChangedReason int reasonOut) {
+ AdapterStateListener adapterStateListener = new AdapterStateListener(mUwbAdapter);
+ AdapterStateCallback callback = mock(AdapterStateCallback.class);
+ adapterStateListener.register(getExecutor(), callback);
+
+ adapterStateListener.onAdapterStateChanged(false, reasonIn);
+ verify(callback, times(1)).onStateChanged(false, reasonOut);
+
+ adapterStateListener.onAdapterStateChanged(true, reasonIn);
+ verify(callback, times(1)).onStateChanged(true, reasonOut);
+ }
+
+ @Test
+ public void testStateChange_FirstRegisterGetsCorrectState() throws RemoteException {
+ AdapterStateListener adapterStateListener = new AdapterStateListener(mUwbAdapter);
+ AdapterStateCallback callback = mock(AdapterStateCallback.class);
+
+ Answer registerAnswer = new Answer() {
+ public Object answer(InvocationOnMock invocation) {
+ Object[] args = invocation.getArguments();
+ IUwbAdapterStateCallbacks cb = (IUwbAdapterStateCallbacks) args[0];
+ try {
+ cb.onAdapterStateChanged(true, StateChangeReason.SESSION_STARTED);
+ } catch (RemoteException e) {
+ // Nothing to do
+ }
+ return new Object();
+ }
+ };
+
+ doAnswer(registerAnswer).when(mUwbAdapter).registerAdapterStateCallbacks(any());
+
+ adapterStateListener.register(getExecutor(), callback);
+ verify(callback).onStateChanged(true,
+ AdapterStateCallback.STATE_CHANGED_REASON_SESSION_STARTED);
+ }
+
+ @Test
+ public void testStateChange_SecondRegisterGetsCorrectState() {
+ AdapterStateListener adapterStateListener = new AdapterStateListener(mUwbAdapter);
+ AdapterStateCallback callback1 = mock(AdapterStateCallback.class);
+ AdapterStateCallback callback2 = mock(AdapterStateCallback.class);
+
+ adapterStateListener.register(getExecutor(), callback1);
+ adapterStateListener.onAdapterStateChanged(true, StateChangeReason.SYSTEM_BOOT);
+
+ adapterStateListener.register(getExecutor(), callback2);
+ verify(callback2).onStateChanged(true,
+ AdapterStateCallback.STATE_CHANGED_REASON_SYSTEM_BOOT);
+ }
+}
diff --git a/data/etc/services.core.protolog.json b/data/etc/services.core.protolog.json
index 1dace8125ae1..a5667b2f0a8a 100644
--- a/data/etc/services.core.protolog.json
+++ b/data/etc/services.core.protolog.json
@@ -85,6 +85,12 @@
"group": "WM_DEBUG_REMOTE_ANIMATIONS",
"at": "com\/android\/server\/wm\/RemoteAnimationController.java"
},
+ "-2014162875": {
+ "message": "Could not register window container listener token=%s, container=%s",
+ "level": "ERROR",
+ "group": "WM_ERROR",
+ "at": "com\/android\/server\/wm\/WindowContextListenerController.java"
+ },
"-2012562539": {
"message": "startAnimation(): Notify animation start:",
"level": "DEBUG",
@@ -811,6 +817,12 @@
"group": "WM_DEBUG_FOCUS",
"at": "com\/android\/server\/wm\/DisplayContent.java"
},
+ "-1136467585": {
+ "message": "The listener does not exist.",
+ "level": "INFO",
+ "group": "WM_DEBUG_ADD_REMOVE",
+ "at": "com\/android\/server\/wm\/WindowContextListenerController.java"
+ },
"-1136139407": {
"message": "no-history finish of %s",
"level": "DEBUG",
@@ -1819,6 +1831,18 @@
"group": "WM_DEBUG_TASKS",
"at": "com\/android\/server\/wm\/ActivityTaskManagerService.java"
},
+ "90764070": {
+ "message": "Could not report token removal to the window token client.",
+ "level": "WARN",
+ "group": "WM_ERROR",
+ "at": "com\/android\/server\/wm\/WindowContextListenerController.java"
+ },
+ "91350919": {
+ "message": "Attempted to set IME flag to a display that does not exist: %d",
+ "level": "WARN",
+ "group": "WM_ERROR",
+ "at": "com\/android\/server\/wm\/WindowManagerService.java"
+ },
"94402792": {
"message": "Moving to RESUMED: %s (in existing)",
"level": "VERBOSE",
@@ -1963,6 +1987,12 @@
"group": "WM_DEBUG_WINDOW_ORGANIZER",
"at": "com\/android\/server\/wm\/TaskOrganizerController.java"
},
+ "236210101": {
+ "message": "registerWindowContextListener: trying to add listener to a non-existing display:%d",
+ "level": "WARN",
+ "group": "WM_ERROR",
+ "at": "com\/android\/server\/wm\/WindowManagerService.java"
+ },
"241961619": {
"message": "Adding %s to %s",
"level": "VERBOSE",
@@ -3403,6 +3433,12 @@
"group": "WM_DEBUG_TASKS",
"at": "com\/android\/server\/wm\/RootWindowContainer.java"
},
+ "1948483534": {
+ "message": "Could not report config changes to the window token client.",
+ "level": "WARN",
+ "group": "WM_ERROR",
+ "at": "com\/android\/server\/wm\/WindowContextListenerController.java"
+ },
"1964565370": {
"message": "Starting remote animation",
"level": "INFO",
diff --git a/errorprone/refaster/EfficientXml.java b/errorprone/refaster/EfficientXml.java
index bd1ddfc92e91..ae797c46b77e 100644
--- a/errorprone/refaster/EfficientXml.java
+++ b/errorprone/refaster/EfficientXml.java
@@ -292,6 +292,30 @@ public class EfficientXml {
}
}
+ class BooleanToStringTrue {
+ @BeforeTemplate
+ void before(TypedXmlSerializer out, String n) throws Exception {
+ out.attribute(null, n, "true");
+ }
+
+ @AfterTemplate
+ void after(TypedXmlSerializer out, String n) throws Exception {
+ out.attributeBoolean(null, n, true);
+ }
+ }
+
+ class BooleanToStringFalse {
+ @BeforeTemplate
+ void before(TypedXmlSerializer out, String n) throws Exception {
+ out.attribute(null, n, "false");
+ }
+
+ @AfterTemplate
+ void after(TypedXmlSerializer out, String n) throws Exception {
+ out.attributeBoolean(null, n, false);
+ }
+ }
+
class BooleanFromString {
@BeforeTemplate
boolean beforeParse(TypedXmlPullParser in, String n) throws Exception {
diff --git a/errorprone/refaster/EfficientXml.java.refaster b/errorprone/refaster/EfficientXml.java.refaster
index f2974fffb83b..750c2dbe98c0 100644
--- a/errorprone/refaster/EfficientXml.java.refaster
+++ b/errorprone/refaster/EfficientXml.java.refaster
Binary files differ
diff --git a/graphics/java/android/graphics/fonts/SystemFonts.java b/graphics/java/android/graphics/fonts/SystemFonts.java
index 28943baf9503..fb6ea99be7ab 100644
--- a/graphics/java/android/graphics/fonts/SystemFonts.java
+++ b/graphics/java/android/graphics/fonts/SystemFonts.java
@@ -88,31 +88,19 @@ public final class SystemFonts {
}
private static @NonNull Set<Font> collectAllFonts() {
- Map<String, Typeface> map = Typeface.getSystemFontMap();
- HashSet<NativeFont.Font> seenFonts = new HashSet<>();
- HashSet<Font> result = new HashSet<>();
- for (Typeface typeface : map.values()) {
- List<NativeFont.Family> families = NativeFont.readTypeface(typeface);
- for (NativeFont.Family family : families) {
- for (NativeFont.Font font : family.getFonts()) {
- if (seenFonts.contains(font)) {
- continue;
- }
- seenFonts.add(font);
- try {
- result.add(new Font.Builder(font.getFile(), family.getLocale())
- .setFontVariationSettings(font.getAxes())
- .setTtcIndex(font.getIndex())
- .setWeight(font.getStyle().getWeight())
- .setSlant(font.getStyle().getSlant())
- .build());
- } catch (IOException e) {
- Log.w(TAG, "Failed to load " + font.getFile(), e);
- }
+ final FontCustomizationParser.Result oemCustomization =
+ readFontCustomization("/product/etc/fonts_customization.xml", "/product/fonts/");
+ Map<String, FontFamily[]> map = new ArrayMap<>();
+ buildSystemFallback("/system/etc/fonts.xml", "/system/fonts/", oemCustomization, map);
+ Set<Font> res = new HashSet<>();
+ for (FontFamily[] families : map.values()) {
+ for (FontFamily family : families) {
+ for (int i = 0; i < family.getSize(); ++i) {
+ res.add(family.getFont(i));
}
}
}
- return result;
+ return res;
}
private static @Nullable ByteBuffer mmap(@NonNull String fullPath) {
diff --git a/libs/WindowManager/Shell/res/layout/split_divider.xml b/libs/WindowManager/Shell/res/layout/split_divider.xml
index b86f36a14d17..341fe617b2d0 100644
--- a/libs/WindowManager/Shell/res/layout/split_divider.xml
+++ b/libs/WindowManager/Shell/res/layout/split_divider.xml
@@ -14,7 +14,7 @@
~ limitations under the License.
-->
-<com.android.wm.shell.apppairs.DividerView
+<com.android.wm.shell.common.split.DividerView
xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_height="match_parent"
android:layout_width="match_parent">
@@ -24,4 +24,4 @@
android:id="@+id/docked_divider_background"
android:background="@color/docked_divider_background"/>
-</com.android.wm.shell.apppairs.DividerView>
+</com.android.wm.shell.common.split.DividerView>
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/apppairs/AppPair.java b/libs/WindowManager/Shell/src/com/android/wm/shell/apppairs/AppPair.java
index d3032f83fc1c..cfbf8452ddae 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/apppairs/AppPair.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/apppairs/AppPair.java
@@ -29,11 +29,13 @@ import android.window.WindowContainerToken;
import android.window.WindowContainerTransaction;
import androidx.annotation.NonNull;
+import androidx.annotation.Nullable;
import com.android.internal.protolog.common.ProtoLog;
import com.android.wm.shell.ShellTaskOrganizer;
import com.android.wm.shell.common.DisplayController;
import com.android.wm.shell.common.SyncTransactionQueue;
+import com.android.wm.shell.common.split.SplitLayout;
import java.io.PrintWriter;
@@ -42,7 +44,7 @@ import java.io.PrintWriter;
* {@link #mTaskInfo1} and {@link #mTaskInfo2} in the pair.
* Also includes all UI for managing the pair like the divider.
*/
-class AppPair implements ShellTaskOrganizer.TaskListener {
+class AppPair implements ShellTaskOrganizer.TaskListener, SplitLayout.LayoutChangeListener {
private static final String TAG = AppPair.class.getSimpleName();
private ActivityManager.RunningTaskInfo mRootTaskInfo;
@@ -55,7 +57,7 @@ class AppPair implements ShellTaskOrganizer.TaskListener {
private final AppPairsController mController;
private final SyncTransactionQueue mSyncQueue;
private final DisplayController mDisplayController;
- private AppPairLayout mAppPairLayout;
+ private SplitLayout mSplitLayout;
AppPair(AppPairsController controller) {
mController = controller;
@@ -92,11 +94,9 @@ class AppPair implements ShellTaskOrganizer.TaskListener {
mTaskInfo1 = task1;
mTaskInfo2 = task2;
- mAppPairLayout = new AppPairLayout(
+ mSplitLayout = new SplitLayout(
mDisplayController.getDisplayContext(mRootTaskInfo.displayId),
- mDisplayController.getDisplay(mRootTaskInfo.displayId),
- mRootTaskInfo.configuration,
- mRootTaskLeash);
+ mRootTaskInfo.configuration, this, mRootTaskLeash);
final WindowContainerToken token1 = task1.token;
final WindowContainerToken token2 = task2.token;
@@ -107,8 +107,8 @@ class AppPair implements ShellTaskOrganizer.TaskListener {
.reparent(token2, mRootTaskInfo.token, true /* onTop */)
.setWindowingMode(token1, WINDOWING_MODE_MULTI_WINDOW)
.setWindowingMode(token2, WINDOWING_MODE_MULTI_WINDOW)
- .setBounds(token1, mAppPairLayout.getBounds1())
- .setBounds(token2, mAppPairLayout.getBounds2())
+ .setBounds(token1, mSplitLayout.getBounds1())
+ .setBounds(token2, mSplitLayout.getBounds2())
// Moving the root task to top after the child tasks were repareted , or the root
// task cannot be visible and focused.
.reorder(mRootTaskInfo.token, true);
@@ -117,6 +117,10 @@ class AppPair implements ShellTaskOrganizer.TaskListener {
}
void unpair() {
+ unpair(null /* toTopToken */);
+ }
+
+ private void unpair(@Nullable WindowContainerToken toTopToken) {
final WindowContainerToken token1 = mTaskInfo1.token;
final WindowContainerToken token2 = mTaskInfo2.token;
final WindowContainerTransaction wct = new WindowContainerTransaction();
@@ -124,16 +128,16 @@ class AppPair implements ShellTaskOrganizer.TaskListener {
// Reparent out of this container and reset windowing mode.
wct.setHidden(mRootTaskInfo.token, true)
.reorder(mRootTaskInfo.token, false)
- .reparent(token1, null, false /* onTop */)
- .reparent(token2, null, false /* onTop */)
+ .reparent(token1, null, token1 == toTopToken /* onTop */)
+ .reparent(token2, null, token2 == toTopToken /* onTop */)
.setWindowingMode(token1, WINDOWING_MODE_UNDEFINED)
.setWindowingMode(token2, WINDOWING_MODE_UNDEFINED);
mController.getTaskOrganizer().applyTransaction(wct);
mTaskInfo1 = null;
mTaskInfo2 = null;
- mAppPairLayout.release();
- mAppPairLayout = null;
+ mSplitLayout.release();
+ mSplitLayout = null;
}
@Override
@@ -153,17 +157,17 @@ class AppPair implements ShellTaskOrganizer.TaskListener {
if (mTaskLeash1 == null || mTaskLeash2 == null) return;
- mAppPairLayout.init();
- final SurfaceControl dividerLeash = mAppPairLayout.getDividerLeash();
- final Rect dividerBounds = mAppPairLayout.getDividerBounds();
+ mSplitLayout.init();
+ final SurfaceControl dividerLeash = mSplitLayout.getDividerLeash();
+ final Rect dividerBounds = mSplitLayout.getDividerBounds();
// TODO: Is there more we need to do here?
mSyncQueue.runInSync(t -> {
- t.setPosition(mTaskLeash1, mTaskInfo1.positionInParent.x,
- mTaskInfo1.positionInParent.y)
+ t.setLayer(dividerLeash, Integer.MAX_VALUE)
+ .setPosition(mTaskLeash1, mTaskInfo1.positionInParent.x,
+ mTaskInfo1.positionInParent.y)
.setPosition(mTaskLeash2, mTaskInfo2.positionInParent.x,
mTaskInfo2.positionInParent.y)
- .setLayer(dividerLeash, Integer.MAX_VALUE)
.setPosition(dividerLeash, dividerBounds.left, dividerBounds.top)
.show(mRootTaskLeash)
.show(mTaskLeash1)
@@ -185,14 +189,14 @@ class AppPair implements ShellTaskOrganizer.TaskListener {
}
mRootTaskInfo = taskInfo;
- if (mAppPairLayout != null
- && mAppPairLayout.updateConfiguration(mRootTaskInfo.configuration)) {
+ if (mSplitLayout != null
+ && mSplitLayout.updateConfiguration(mRootTaskInfo.configuration)) {
// Update bounds when root bounds or its orientation changed.
final WindowContainerTransaction wct = new WindowContainerTransaction();
- final SurfaceControl dividerLeash = mAppPairLayout.getDividerLeash();
- final Rect dividerBounds = mAppPairLayout.getDividerBounds();
- final Rect bounds1 = mAppPairLayout.getBounds1();
- final Rect bounds2 = mAppPairLayout.getBounds2();
+ final SurfaceControl dividerLeash = mSplitLayout.getDividerLeash();
+ final Rect dividerBounds = mSplitLayout.getDividerBounds();
+ final Rect bounds1 = mSplitLayout.getBounds1();
+ final Rect bounds2 = mSplitLayout.getBounds2();
wct.setBounds(mTaskInfo1.token, bounds1)
.setBounds(mTaskInfo2.token, bounds2);
@@ -200,7 +204,9 @@ class AppPair implements ShellTaskOrganizer.TaskListener {
mSyncQueue.runInSync(t -> t
.setPosition(mTaskLeash1, bounds1.left, bounds1.top)
.setPosition(mTaskLeash2, bounds2.left, bounds2.top)
- .setPosition(dividerLeash, dividerBounds.left, dividerBounds.top));
+ .setPosition(dividerLeash, dividerBounds.left, dividerBounds.top)
+ // Resets layer to divider bar to make sure it is always on top.
+ .setLayer(dividerLeash, Integer.MAX_VALUE));
}
} else if (taskInfo.taskId == getTaskId1()) {
mTaskInfo1 = taskInfo;
@@ -242,4 +248,39 @@ class AppPair implements ShellTaskOrganizer.TaskListener {
public String toString() {
return TAG + "#" + getRootTaskId();
}
+
+ @Override
+ public void onSnappedToDismiss(boolean snappedToEnd) {
+ unpair(snappedToEnd ? mTaskInfo1.token : mTaskInfo2.token /* toTopToken */);
+ }
+
+ @Override
+ public void onBoundsChanging(SplitLayout layout) {
+ final SurfaceControl dividerLeash = mSplitLayout.getDividerLeash();
+ if (dividerLeash == null) return;
+ final Rect dividerBounds = layout.getDividerBounds();
+ final Rect bounds1 = layout.getBounds1();
+ final Rect bounds2 = layout.getBounds2();
+ mSyncQueue.runInSync(t -> t
+ .setPosition(dividerLeash, dividerBounds.left, dividerBounds.top)
+ .setPosition(mTaskLeash1, bounds1.left, bounds1.top)
+ .setPosition(mTaskLeash2, bounds2.left, bounds2.top));
+ }
+
+ @Override
+ public void onBoundsChanged(SplitLayout layout) {
+ final SurfaceControl dividerLeash = mSplitLayout.getDividerLeash();
+ if (dividerLeash == null) return;
+ final Rect dividerBounds = layout.getDividerBounds();
+ final Rect bounds1 = layout.getBounds1();
+ final Rect bounds2 = layout.getBounds2();
+ final WindowContainerTransaction wct = new WindowContainerTransaction();
+ wct.setBounds(mTaskInfo1.token, bounds1)
+ .setBounds(mTaskInfo2.token, bounds2);
+ mController.getTaskOrganizer().applyTransaction(wct);
+ mSyncQueue.runInSync(t -> t
+ .setPosition(dividerLeash, dividerBounds.left, dividerBounds.top)
+ .setPosition(mTaskLeash1, bounds1.left, bounds1.top)
+ .setPosition(mTaskLeash2, bounds2.left, bounds2.top));
+ }
}
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/apppairs/AppPairLayout.java b/libs/WindowManager/Shell/src/com/android/wm/shell/apppairs/AppPairLayout.java
deleted file mode 100644
index 8c8655e1ff1f..000000000000
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/apppairs/AppPairLayout.java
+++ /dev/null
@@ -1,211 +0,0 @@
-/*
- * Copyright (C) 2020 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.wm.shell.apppairs;
-
-import static android.view.WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE;
-import static android.view.WindowManager.LayoutParams.FLAG_NOT_TOUCH_MODAL;
-import static android.view.WindowManager.LayoutParams.FLAG_SLIPPERY;
-import static android.view.WindowManager.LayoutParams.FLAG_SPLIT_TOUCH;
-import static android.view.WindowManager.LayoutParams.FLAG_WATCH_OUTSIDE_TOUCH;
-import static android.view.WindowManager.LayoutParams.PRIVATE_FLAG_NO_MOVE_ANIMATION;
-import static android.view.WindowManager.LayoutParams.TYPE_DOCK_DIVIDER;
-
-import android.content.Context;
-import android.content.res.Configuration;
-import android.graphics.PixelFormat;
-import android.graphics.Rect;
-import android.graphics.Region;
-import android.os.Binder;
-import android.os.IBinder;
-import android.view.Display;
-import android.view.IWindow;
-import android.view.LayoutInflater;
-import android.view.SurfaceControl;
-import android.view.SurfaceControlViewHost;
-import android.view.WindowManager;
-import android.view.WindowlessWindowManager;
-
-import com.android.wm.shell.R;
-
-/**
- * Records and handles layout of a pair of apps.
- */
-final class AppPairLayout {
- private static final String DIVIDER_WINDOW_TITLE = "AppPairDivider";
- private final Display mDisplay;
- private final int mDividerWindowWidth;
- private final int mDividerWindowInsets;
- private final AppPairWindowManager mAppPairWindowManager;
-
- private Context mContext;
- private Rect mRootBounds;
- private DIVIDE_POLICY mDividePolicy;
-
- private SurfaceControlViewHost mViewHost;
- private SurfaceControl mDividerLeash;
-
- AppPairLayout(
- Context context,
- Display display,
- Configuration configuration,
- SurfaceControl rootLeash) {
- mContext = context.createConfigurationContext(configuration);
- mDisplay = display;
- mRootBounds = configuration.windowConfiguration.getBounds();
- mDividerWindowWidth = mContext.getResources().getDimensionPixelSize(
- com.android.internal.R.dimen.docked_stack_divider_thickness);
- mDividerWindowInsets = mContext.getResources().getDimensionPixelSize(
- com.android.internal.R.dimen.docked_stack_divider_insets);
-
- mAppPairWindowManager = new AppPairWindowManager(configuration, rootLeash);
- mDividePolicy = DIVIDE_POLICY.MIDDLE;
- mDividePolicy.update(mRootBounds, mDividerWindowWidth, mDividerWindowInsets);
- }
-
- boolean updateConfiguration(Configuration configuration) {
- mAppPairWindowManager.setConfiguration(configuration);
- final Rect rootBounds = configuration.windowConfiguration.getBounds();
- if (isIdenticalBounds(mRootBounds, rootBounds)) {
- return false;
- }
-
- mContext = mContext.createConfigurationContext(configuration);
- mRootBounds = rootBounds;
- mDividePolicy.update(mRootBounds, mDividerWindowWidth, mDividerWindowInsets);
- release();
- init();
- return true;
- }
-
- Rect getBounds1() {
- return mDividePolicy.mBounds1;
- }
-
- Rect getBounds2() {
- return mDividePolicy.mBounds2;
- }
-
- Rect getDividerBounds() {
- return mDividePolicy.mDividerBounds;
- }
-
- SurfaceControl getDividerLeash() {
- return mDividerLeash;
- }
-
- void release() {
- if (mViewHost == null) {
- return;
- }
- mViewHost.release();
- mDividerLeash = null;
- mViewHost = null;
- }
-
- void init() {
- if (mViewHost == null) {
- mViewHost = new SurfaceControlViewHost(mContext, mDisplay, mAppPairWindowManager);
- }
-
- final DividerView dividerView = (DividerView) LayoutInflater.from(mContext)
- .inflate(R.layout.split_divider, null);
-
- WindowManager.LayoutParams lp = new WindowManager.LayoutParams(
- mDividePolicy.mDividerBounds.width(),
- mDividePolicy.mDividerBounds.height(),
- TYPE_DOCK_DIVIDER,
- FLAG_NOT_FOCUSABLE | FLAG_NOT_TOUCH_MODAL | FLAG_WATCH_OUTSIDE_TOUCH
- | FLAG_SPLIT_TOUCH | FLAG_SLIPPERY,
- PixelFormat.TRANSLUCENT);
- lp.token = new Binder();
- lp.setTitle(DIVIDER_WINDOW_TITLE);
- lp.privateFlags |= PRIVATE_FLAG_NO_MOVE_ANIMATION;
-
- mViewHost.setView(dividerView, lp);
- mDividerLeash = mAppPairWindowManager.getSurfaceControl(mViewHost.getWindowToken());
- }
-
- private static boolean isIdenticalBounds(Rect bounds1, Rect bounds2) {
- return bounds1.left == bounds2.left && bounds1.top == bounds2.top
- && bounds1.right == bounds2.right && bounds1.bottom == bounds2.bottom;
- }
-
- /**
- * Indicates the policy of placing divider bar and corresponding split-screens.
- */
- // TODO(172704238): add more divide policy and provide snap to resize feature for divider bar.
- enum DIVIDE_POLICY {
- MIDDLE;
-
- void update(Rect rootBounds, int dividerWindowWidth, int dividerWindowInsets) {
- final int dividerOffset = dividerWindowWidth / 2;
- final int boundsOffset = dividerOffset - dividerWindowInsets;
-
- mDividerBounds = new Rect(rootBounds);
- mBounds1 = new Rect(rootBounds);
- mBounds2 = new Rect(rootBounds);
-
- switch (this) {
- case MIDDLE:
- default:
- if (isLandscape(rootBounds)) {
- mDividerBounds.left = rootBounds.width() / 2 - dividerOffset;
- mDividerBounds.right = rootBounds.width() / 2 + dividerOffset;
- mBounds1.left = rootBounds.width() / 2 + boundsOffset;
- mBounds2.right = rootBounds.width() / 2 - boundsOffset;
- } else {
- mDividerBounds.top = rootBounds.height() / 2 - dividerOffset;
- mDividerBounds.bottom = rootBounds.height() / 2 + dividerOffset;
- mBounds1.bottom = rootBounds.height() / 2 - boundsOffset;
- mBounds2.top = rootBounds.height() / 2 + boundsOffset;
- }
- }
- }
-
- private boolean isLandscape(Rect bounds) {
- return bounds.width() > bounds.height();
- }
-
- Rect mDividerBounds;
- Rect mBounds1;
- Rect mBounds2;
- }
-
- /**
- * WindowManger for app pair. Holds view hierarchy for the root task.
- */
- private static final class AppPairWindowManager extends WindowlessWindowManager {
- AppPairWindowManager(Configuration config, SurfaceControl rootSurface) {
- super(config, rootSurface, null /* hostInputToken */);
- }
-
- @Override
- public void setTouchRegion(IBinder window, Region region) {
- super.setTouchRegion(window, region);
- }
-
- @Override
- public SurfaceControl getSurfaceControl(IWindow window) {
- return super.getSurfaceControl(window);
- }
-
- @Override
- public void setConfiguration(Configuration configuration) {
- super.setConfiguration(configuration);
- }
- }
-}
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/apppairs/DividerView.java b/libs/WindowManager/Shell/src/com/android/wm/shell/apppairs/DividerView.java
deleted file mode 100644
index 41b5e47e7fa9..000000000000
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/apppairs/DividerView.java
+++ /dev/null
@@ -1,56 +0,0 @@
-/*
- * Copyright (C) 2020 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.wm.shell.apppairs;
-
-import android.content.Context;
-import android.util.AttributeSet;
-import android.view.View;
-import android.widget.FrameLayout;
-
-import androidx.annotation.NonNull;
-import androidx.annotation.Nullable;
-
-/**
- * Stack divider for app pair.
- */
-public class DividerView extends FrameLayout {
- public DividerView(@NonNull Context context) {
- super(context);
- }
-
- public DividerView(@NonNull Context context,
- @Nullable AttributeSet attrs) {
- super(context, attrs);
- }
-
- public DividerView(@NonNull Context context, @Nullable AttributeSet attrs, int defStyleAttr) {
- super(context, attrs, defStyleAttr);
- }
-
- public DividerView(@NonNull Context context, @Nullable AttributeSet attrs, int defStyleAttr,
- int defStyleRes) {
- super(context, attrs, defStyleAttr, defStyleRes);
- }
-
- void show() {
- post(() -> setVisibility(View.VISIBLE));
- }
-
- void hide() {
- post(() -> setVisibility(View.INVISIBLE));
- }
-}
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/common/split/DividerView.java b/libs/WindowManager/Shell/src/com/android/wm/shell/common/split/DividerView.java
new file mode 100644
index 000000000000..50d9fe8629ac
--- /dev/null
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/common/split/DividerView.java
@@ -0,0 +1,171 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.wm.shell.common.split;
+
+import static android.content.res.Configuration.ORIENTATION_LANDSCAPE;
+import static android.view.WindowManager.LayoutParams.FLAG_SLIPPERY;
+
+import android.content.Context;
+import android.util.AttributeSet;
+import android.view.MotionEvent;
+import android.view.SurfaceControlViewHost;
+import android.view.VelocityTracker;
+import android.view.View;
+import android.view.ViewConfiguration;
+import android.view.WindowManager;
+import android.widget.FrameLayout;
+
+import androidx.annotation.NonNull;
+import androidx.annotation.Nullable;
+
+import com.android.internal.policy.DividerSnapAlgorithm;
+
+/**
+ * Stack divider for app pair.
+ */
+// TODO(b/172704238): add handle view to indicate touching status.
+public class DividerView extends FrameLayout implements View.OnTouchListener {
+ private final int mTouchSlop = ViewConfiguration.get(getContext()).getScaledTouchSlop();
+
+ private SplitLayout mSplitLayout;
+ private SurfaceControlViewHost mViewHost;
+ private DragListener mDragListener;
+
+ private VelocityTracker mVelocityTracker;
+ private boolean mMoving;
+ private int mStartPos;
+
+ public DividerView(@NonNull Context context) {
+ super(context);
+ }
+
+ public DividerView(@NonNull Context context,
+ @Nullable AttributeSet attrs) {
+ super(context, attrs);
+ }
+
+ public DividerView(@NonNull Context context, @Nullable AttributeSet attrs, int defStyleAttr) {
+ super(context, attrs, defStyleAttr);
+ }
+
+ public DividerView(@NonNull Context context, @Nullable AttributeSet attrs, int defStyleAttr,
+ int defStyleRes) {
+ super(context, attrs, defStyleAttr, defStyleRes);
+ }
+
+ /** Sets up essential dependencies of the divider bar. */
+ public void setup(
+ SplitLayout layout,
+ SurfaceControlViewHost viewHost,
+ @Nullable DragListener dragListener) {
+ mSplitLayout = layout;
+ mViewHost = viewHost;
+ mDragListener = dragListener;
+ }
+
+ @Override
+ protected void onFinishInflate() {
+ super.onFinishInflate();
+ setOnTouchListener(this);
+ }
+
+ @Override
+ public boolean onTouch(View v, MotionEvent event) {
+ if (mSplitLayout == null) {
+ return false;
+ }
+
+ final int action = event.getAction() & MotionEvent.ACTION_MASK;
+ final boolean isLandscape = isLandscape();
+ // Using raw xy to prevent lost track of motion events while moving divider bar.
+ final int touchPos = isLandscape ? (int) event.getRawX() : (int) event.getRawY();
+ switch (action) {
+ case MotionEvent.ACTION_DOWN:
+ mVelocityTracker = VelocityTracker.obtain();
+ mVelocityTracker.addMovement(event);
+ setSlippery(false);
+ mStartPos = touchPos;
+ mMoving = false;
+ break;
+ case MotionEvent.ACTION_MOVE:
+ mVelocityTracker.addMovement(event);
+ if (!mMoving && Math.abs(touchPos - mStartPos) > mTouchSlop) {
+ mStartPos = touchPos;
+ mMoving = true;
+ if (mDragListener != null) {
+ mDragListener.onDragStart();
+ }
+ }
+ if (mMoving) {
+ final int position = mSplitLayout.getDividePosition() + touchPos - mStartPos;
+ mSplitLayout.updateDividePosition(position);
+ }
+ break;
+ case MotionEvent.ACTION_UP:
+ case MotionEvent.ACTION_CANCEL:
+ mVelocityTracker.addMovement(event);
+ mVelocityTracker.computeCurrentVelocity(1000 /* units */);
+ final float velocity = isLandscape
+ ? mVelocityTracker.getXVelocity()
+ : mVelocityTracker.getYVelocity();
+ setSlippery(true);
+ mMoving = false;
+ if (mDragListener != null) {
+ mDragListener.onDragEnd();
+ }
+
+ final int position = mSplitLayout.getDividePosition() + touchPos - mStartPos;
+ final DividerSnapAlgorithm.SnapTarget snapTarget =
+ mSplitLayout.findSnapTarget(position, velocity);
+ mSplitLayout.setSnapTarget(snapTarget);
+ break;
+ }
+ return true;
+ }
+
+ private void setSlippery(boolean slippery) {
+ if (mViewHost == null) {
+ return;
+ }
+
+ final WindowManager.LayoutParams lp = (WindowManager.LayoutParams) getLayoutParams();
+ final boolean isSlippery = (lp.flags & FLAG_SLIPPERY) != 0;
+ if (isSlippery == slippery) {
+ return;
+ }
+
+ if (slippery) {
+ lp.flags |= FLAG_SLIPPERY;
+ } else {
+ lp.flags &= ~FLAG_SLIPPERY;
+ }
+ mViewHost.relayout(lp);
+ }
+
+ private boolean isLandscape() {
+ return getResources().getConfiguration().orientation == ORIENTATION_LANDSCAPE;
+ }
+
+ /** Monitors dragging action of the divider bar. */
+ // TODO(b/172704238): add listeners to deal with resizing state of the app windows.
+ public interface DragListener {
+ /** Called when start dragging. */
+ void onDragStart();
+ /** Called when stop dragging. */
+ void onDragEnd();
+ }
+}
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/common/split/SplitLayout.java b/libs/WindowManager/Shell/src/com/android/wm/shell/common/split/SplitLayout.java
new file mode 100644
index 000000000000..e11037f55cfa
--- /dev/null
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/common/split/SplitLayout.java
@@ -0,0 +1,205 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.wm.shell.common.split;
+
+import static android.view.WindowManager.DOCKED_LEFT;
+import static android.view.WindowManager.DOCKED_TOP;
+
+import static com.android.internal.policy.DividerSnapAlgorithm.SnapTarget.FLAG_DISMISS_END;
+import static com.android.internal.policy.DividerSnapAlgorithm.SnapTarget.FLAG_DISMISS_START;
+
+import android.content.Context;
+import android.content.res.Configuration;
+import android.content.res.Resources;
+import android.graphics.Rect;
+import android.view.SurfaceControl;
+
+import androidx.annotation.Nullable;
+
+import com.android.internal.policy.DividerSnapAlgorithm;
+
+/**
+ * Records and handles layout of splits. Helps to calculate proper bounds when configuration or
+ * divide position changes.
+ */
+public class SplitLayout {
+ private final int mDividerWindowWidth;
+ private final int mDividerInsets;
+ private final int mDividerSize;
+
+ private final Rect mRootBounds = new Rect();
+ private final Rect mDividerBounds = new Rect();
+ private final Rect mBounds1 = new Rect();
+ private final Rect mBounds2 = new Rect();
+ private final LayoutChangeListener mLayoutChangeListener;
+ private final SplitWindowManager mSplitWindowManager;
+
+ private Context mContext;
+ private DividerSnapAlgorithm mDividerSnapAlgorithm;
+ private int mDividePosition;
+
+ public SplitLayout(Context context, Configuration configuration,
+ LayoutChangeListener layoutChangeListener, SurfaceControl rootLeash) {
+ mContext = context.createConfigurationContext(configuration);
+ mLayoutChangeListener = layoutChangeListener;
+ mSplitWindowManager = new SplitWindowManager(mContext, configuration, rootLeash);
+
+ mDividerWindowWidth = context.getResources().getDimensionPixelSize(
+ com.android.internal.R.dimen.docked_stack_divider_thickness);
+ mDividerInsets = context.getResources().getDimensionPixelSize(
+ com.android.internal.R.dimen.docked_stack_divider_insets);
+ mDividerSize = mDividerWindowWidth - mDividerInsets * 2;
+
+ mRootBounds.set(configuration.windowConfiguration.getBounds());
+ mDividerSnapAlgorithm = getSnapAlgorithm(context.getResources(), mRootBounds);
+ mDividePosition = mDividerSnapAlgorithm.getMiddleTarget().position;
+ updateBounds(mDividePosition);
+ }
+
+ /** Gets bounds of the primary split. */
+ public Rect getBounds1() {
+ return mBounds1;
+ }
+
+ /** Gets bounds of the secondary split. */
+ public Rect getBounds2() {
+ return mBounds2;
+ }
+
+ /** Gets bounds of divider window. */
+ public Rect getDividerBounds() {
+ return mDividerBounds;
+ }
+
+ /** Returns leash of the current divider bar. */
+ @Nullable
+ public SurfaceControl getDividerLeash() {
+ return mSplitWindowManager == null ? null : mSplitWindowManager.getSurfaceControl();
+ }
+
+ int getDividePosition() {
+ return mDividePosition;
+ }
+
+ /** Applies new configuration, returns {@code false} if there's no effect to the layout. */
+ public boolean updateConfiguration(Configuration configuration) {
+ final Rect rootBounds = configuration.windowConfiguration.getBounds();
+ if (mRootBounds.equals(rootBounds)) {
+ return false;
+ }
+
+ mContext = mContext.createConfigurationContext(configuration);
+ mSplitWindowManager.setConfiguration(configuration);
+ mRootBounds.set(rootBounds);
+ mDividerSnapAlgorithm = getSnapAlgorithm(mContext.getResources(), mRootBounds);
+ mDividePosition = mDividerSnapAlgorithm.getMiddleTarget().position;
+ updateBounds(mDividePosition);
+ release();
+ init();
+ return true;
+ }
+
+ /** Updates recording bounds of divider window and both of the splits. */
+ private void updateBounds(int position) {
+ mDividerBounds.set(mRootBounds);
+ mBounds1.set(mRootBounds);
+ mBounds2.set(mRootBounds);
+ if (isLandscape(mRootBounds)) {
+ mDividerBounds.left = position - mDividerInsets;
+ mDividerBounds.right = mDividerBounds.left + mDividerWindowWidth;
+ mBounds1.right = mBounds1.left + position;
+ mBounds2.left = mBounds1.right + mDividerSize;
+ } else {
+ mDividerBounds.top = position - mDividerInsets;
+ mDividerBounds.bottom = mDividerBounds.top + mDividerWindowWidth;
+ mBounds1.bottom = mBounds1.top + position;
+ mBounds2.top = mBounds1.bottom + mDividerSize;
+ }
+ }
+
+ /** Inflates {@link DividerView} on the root surface. */
+ public void init() {
+ mSplitWindowManager.init(this);
+ }
+
+ /** Releases the surface holding the current {@link DividerView}. */
+ public void release() {
+ mSplitWindowManager.release();
+ }
+
+ /**
+ * Updates bounds with the passing position. Usually used to update recording bounds while
+ * performing animation or dragging divider bar to resize the splits.
+ */
+ public void updateDividePosition(int position) {
+ updateBounds(position);
+ mLayoutChangeListener.onBoundsChanging(this);
+ }
+
+ /**
+ * Sets new divide position and updates bounds correspondingly. Notifies listener if the new
+ * target indicates dismissing split.
+ */
+ public void setSnapTarget(DividerSnapAlgorithm.SnapTarget snapTarget) {
+ switch(snapTarget.flag) {
+ case FLAG_DISMISS_START:
+ mLayoutChangeListener.onSnappedToDismiss(false /* snappedToEnd */);
+ break;
+ case FLAG_DISMISS_END:
+ mLayoutChangeListener.onSnappedToDismiss(true /* snappedToEnd */);
+ break;
+ default:
+ mDividePosition = snapTarget.position;
+ updateBounds(mDividePosition);
+ mLayoutChangeListener.onBoundsChanged(this);
+ break;
+ }
+ }
+
+ /**
+ * Returns {@link DividerSnapAlgorithm.SnapTarget} which matches passing position and velocity.
+ */
+ public DividerSnapAlgorithm.SnapTarget findSnapTarget(int position, float velocity) {
+ return mDividerSnapAlgorithm.calculateSnapTarget(position, velocity);
+ }
+
+ private DividerSnapAlgorithm getSnapAlgorithm(Resources resources, Rect rootBounds) {
+ final boolean isLandscape = isLandscape(rootBounds);
+ return new DividerSnapAlgorithm(
+ resources,
+ rootBounds.width(),
+ rootBounds.height(),
+ mDividerSize,
+ !isLandscape,
+ new Rect() /* insets */,
+ isLandscape ? DOCKED_LEFT : DOCKED_TOP /* dockSide */);
+ }
+
+ private static boolean isLandscape(Rect bounds) {
+ return bounds.width() > bounds.height();
+ }
+
+ /** Listens layout change event. */
+ public interface LayoutChangeListener {
+ /** Calls when dismissing split. */
+ void onSnappedToDismiss(boolean snappedToEnd);
+ /** Calls when the bounds is changing due to animation or dragging divider bar. */
+ void onBoundsChanging(SplitLayout layout);
+ /** Calls when the target bounds changed. */
+ void onBoundsChanged(SplitLayout layout);
+ }
+}
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/common/split/SplitWindowManager.java b/libs/WindowManager/Shell/src/com/android/wm/shell/common/split/SplitWindowManager.java
new file mode 100644
index 000000000000..542867d83e29
--- /dev/null
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/common/split/SplitWindowManager.java
@@ -0,0 +1,115 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.wm.shell.common.split;
+
+import static android.view.WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE;
+import static android.view.WindowManager.LayoutParams.FLAG_NOT_TOUCH_MODAL;
+import static android.view.WindowManager.LayoutParams.FLAG_SLIPPERY;
+import static android.view.WindowManager.LayoutParams.FLAG_SPLIT_TOUCH;
+import static android.view.WindowManager.LayoutParams.FLAG_WATCH_OUTSIDE_TOUCH;
+import static android.view.WindowManager.LayoutParams.PRIVATE_FLAG_NO_MOVE_ANIMATION;
+import static android.view.WindowManager.LayoutParams.TYPE_DOCK_DIVIDER;
+
+import android.content.Context;
+import android.content.res.Configuration;
+import android.graphics.PixelFormat;
+import android.graphics.Rect;
+import android.graphics.Region;
+import android.os.Binder;
+import android.os.IBinder;
+import android.view.IWindow;
+import android.view.LayoutInflater;
+import android.view.SurfaceControl;
+import android.view.SurfaceControlViewHost;
+import android.view.WindowManager;
+import android.view.WindowlessWindowManager;
+
+import androidx.annotation.Nullable;
+
+import com.android.wm.shell.R;
+
+/**
+ * Holds view hierarchy of a root surface and helps to inflate {@link DividerView} for a split.
+ */
+public final class SplitWindowManager extends WindowlessWindowManager {
+ private static final String DIVIDER_WINDOW_TITLE = "SplitDivider";
+
+ private Context mContext;
+ private SurfaceControlViewHost mViewHost;
+
+ public SplitWindowManager(Context context, Configuration config, SurfaceControl rootSurface) {
+ super(config, rootSurface, null /* hostInputToken */);
+ mContext = context.createConfigurationContext(config);
+ }
+
+ @Override
+ public void setTouchRegion(IBinder window, Region region) {
+ super.setTouchRegion(window, region);
+ }
+
+ @Override
+ public SurfaceControl getSurfaceControl(IWindow window) {
+ return super.getSurfaceControl(window);
+ }
+
+ @Override
+ public void setConfiguration(Configuration configuration) {
+ super.setConfiguration(configuration);
+ mContext = mContext.createConfigurationContext(configuration);
+ }
+
+ /** Inflates {@link DividerView} on to the root surface. */
+ void init(SplitLayout splitLayout) {
+ if (mViewHost == null) {
+ mViewHost = new SurfaceControlViewHost(mContext, mContext.getDisplay(), this);
+ }
+
+ final Rect dividerBounds = splitLayout.getDividerBounds();
+ final DividerView dividerView = (DividerView) LayoutInflater.from(mContext)
+ .inflate(R.layout.split_divider, null /* root */);
+
+ WindowManager.LayoutParams lp = new WindowManager.LayoutParams(
+ dividerBounds.width(), dividerBounds.height(), TYPE_DOCK_DIVIDER,
+ FLAG_NOT_FOCUSABLE | FLAG_NOT_TOUCH_MODAL | FLAG_WATCH_OUTSIDE_TOUCH
+ | FLAG_SPLIT_TOUCH | FLAG_SLIPPERY,
+ PixelFormat.TRANSLUCENT);
+ lp.token = new Binder();
+ lp.setTitle(DIVIDER_WINDOW_TITLE);
+ lp.privateFlags |= PRIVATE_FLAG_NO_MOVE_ANIMATION;
+ mViewHost.setView(dividerView, lp);
+ dividerView.setup(splitLayout, mViewHost, null /* dragListener */);
+ }
+
+ /**
+ * Releases the surface control of the current {@link DividerView} and tear down the view
+ * hierarchy.
+ */
+ void release() {
+ if (mViewHost == null) return;
+ mViewHost.release();
+ mViewHost = null;
+ }
+
+ /**
+ * Gets {@link SurfaceControl} of the surface holding divider view. @return {@code null} if not
+ * feasible.
+ */
+ @Nullable
+ SurfaceControl getSurfaceControl() {
+ return mViewHost == null ? null : getSurfaceControl(mViewHost.getWindowToken());
+ }
+}
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/PinnedStackListenerForwarder.java b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/PinnedStackListenerForwarder.java
index 6145b7c71c09..5593268588fd 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/PinnedStackListenerForwarder.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/PinnedStackListenerForwarder.java
@@ -21,7 +21,6 @@ import android.content.ComponentName;
import android.content.pm.ParceledListSlice;
import android.os.RemoteException;
import android.view.DisplayInfo;
-import android.view.IPinnedStackController;
import android.view.IPinnedStackListener;
import android.view.WindowManagerGlobal;
@@ -62,12 +61,6 @@ public class PinnedStackListenerForwarder {
displayId, mListenerImpl);
}
- private void onListenerRegistered(IPinnedStackController controller) {
- for (PinnedStackListener listener : mListeners) {
- listener.onListenerRegistered(controller);
- }
- }
-
private void onMovementBoundsChanged(boolean fromImeAdjustment) {
for (PinnedStackListener listener : mListeners) {
listener.onMovementBoundsChanged(fromImeAdjustment);
@@ -113,13 +106,6 @@ public class PinnedStackListenerForwarder {
@BinderThread
private class PinnedStackListenerImpl extends IPinnedStackListener.Stub {
@Override
- public void onListenerRegistered(IPinnedStackController controller) {
- mShellMainExecutor.execute(() -> {
- PinnedStackListenerForwarder.this.onListenerRegistered(controller);
- });
- }
-
- @Override
public void onMovementBoundsChanged(boolean fromImeAdjustment) {
mShellMainExecutor.execute(() -> {
PinnedStackListenerForwarder.this.onMovementBoundsChanged(fromImeAdjustment);
@@ -174,8 +160,6 @@ public class PinnedStackListenerForwarder {
* Subclasses can ignore those methods they do not intend to take action upon.
*/
public static class PinnedStackListener {
- public void onListenerRegistered(IPinnedStackController controller) {}
-
public void onMovementBoundsChanged(boolean fromImeAdjustment) {}
public void onImeVisibilityChanged(boolean imeVisible, int imeHeight) {}
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/phone/PipController.java b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/phone/PipController.java
index 119ef6d60bea..3234ef6ccf66 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/phone/PipController.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/phone/PipController.java
@@ -41,7 +41,6 @@ import android.util.Log;
import android.util.Pair;
import android.util.Slog;
import android.view.DisplayInfo;
-import android.view.IPinnedStackController;
import android.view.WindowManagerGlobal;
import android.window.WindowContainerTransaction;
@@ -162,11 +161,6 @@ public class PipController implements Pip, PipTaskOrganizer.PipTransitionCallbac
private class PipControllerPinnedStackListener extends
PinnedStackListenerForwarder.PinnedStackListener {
@Override
- public void onListenerRegistered(IPinnedStackController controller) {
- mTouchHandler.setPinnedStackController(controller);
- }
-
- @Override
public void onImeVisibilityChanged(boolean imeVisible, int imeHeight) {
mPipBoundsState.setImeVisibility(imeVisible, imeHeight);
mTouchHandler.onImeVisibilityChanged(imeVisible, imeHeight);
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/phone/PipMenuView.java b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/phone/PipMenuView.java
index 4e991f2e919b..2e10fc93cafb 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/phone/PipMenuView.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/phone/PipMenuView.java
@@ -475,7 +475,7 @@ public class PipMenuView extends FrameLayout {
final Intent settingsIntent = new Intent(ACTION_PICTURE_IN_PICTURE_SETTINGS,
Uri.fromParts("package", topPipActivityInfo.first.getPackageName(), null));
settingsIntent.setFlags(FLAG_ACTIVITY_NEW_TASK | FLAG_ACTIVITY_CLEAR_TASK);
- mContext.startActivityAsUser(settingsIntent, UserHandle.CURRENT);
+ mContext.startActivityAsUser(settingsIntent, UserHandle.of(topPipActivityInfo.second));
}
}
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/phone/PipTouchHandler.java b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/phone/PipTouchHandler.java
index 1ab31f846db7..b7cfad9030f7 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/phone/PipTouchHandler.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/phone/PipTouchHandler.java
@@ -31,11 +31,8 @@ import android.graphics.Point;
import android.graphics.PointF;
import android.graphics.Rect;
import android.os.Handler;
-import android.os.RemoteException;
import android.provider.DeviceConfig;
-import android.util.Log;
import android.util.Size;
-import android.view.IPinnedStackController;
import android.view.InputEvent;
import android.view.MotionEvent;
import android.view.ViewConfiguration;
@@ -76,7 +73,6 @@ public class PipTouchHandler {
private final PipDismissTargetHandler mPipDismissTargetHandler;
private PipResizeGestureHandler mPipResizeGestureHandler;
- private IPinnedStackController mPinnedStackController;
private WeakReference<Consumer<Rect>> mPipExclusionBoundsChangeListener;
private final PhonePipMenuController mMenuController;
@@ -464,10 +460,6 @@ public class PipTouchHandler {
if (!(inputEvent instanceof MotionEvent)) {
return true;
}
- // Skip touch handling until we are bound to the controller
- if (mPinnedStackController == null) {
- return true;
- }
MotionEvent ev = (MotionEvent) inputEvent;
if (!mPipBoundsState.isStashed() && mPipResizeGestureHandler.willStartResizeGesture(ev)) {
@@ -591,13 +583,6 @@ public class PipTouchHandler {
}
/**
- * Sets the controller to update the system of changes from user interaction.
- */
- void setPinnedStackController(IPinnedStackController controller) {
- mPinnedStackController = controller;
- }
-
- /**
* Sets the menu visibility.
*/
private void setMenuState(int menuState, boolean resize, Runnable callback) {
@@ -625,13 +610,9 @@ public class PipTouchHandler {
// bounds which are now stale. In such a case we defer the animation to the
// normal bounds until after the next onMovementBoundsChanged() call to get the
// bounds in the new orientation
- try {
- int displayRotation = mPinnedStackController.getDisplayRotation();
- if (mDisplayRotation != displayRotation) {
- mDeferResizeToNormalBoundsUntilRotation = displayRotation;
- }
- } catch (RemoteException e) {
- Log.e(TAG, "Could not get display rotation from controller");
+ int displayRotation = mContext.getDisplay().getRotation();
+ if (mDisplayRotation != displayRotation) {
+ mDeferResizeToNormalBoundsUntilRotation = displayRotation;
}
}
diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/CommonAssertions.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/CommonAssertions.kt
index 0fb43e263d05..3ed53fb221a7 100644
--- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/CommonAssertions.kt
+++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/CommonAssertions.kt
@@ -18,78 +18,6 @@ package com.android.wm.shell.flicker
import com.android.server.wm.flicker.dsl.EventLogAssertion
import com.android.server.wm.flicker.dsl.LayersAssertion
-import com.android.server.wm.flicker.dsl.WmAssertion
-import com.android.server.wm.flicker.helpers.WindowUtils
-
-@JvmOverloads
-fun WmAssertion.statusBarWindowIsAlwaysVisible(
- bugId: Int = 0,
- enabled: Boolean = bugId == 0
-) {
- all("statusBarWindowIsAlwaysVisible", bugId, enabled) {
- this.showsAboveAppWindow(FlickerTestBase.STATUS_BAR_WINDOW_TITLE)
- }
-}
-
-@JvmOverloads
-fun WmAssertion.navBarWindowIsAlwaysVisible(
- bugId: Int = 0,
- enabled: Boolean = bugId == 0
-) {
- all("navBarWindowIsAlwaysVisible", bugId, enabled) {
- this.showsAboveAppWindow(FlickerTestBase.NAVIGATION_BAR_WINDOW_TITLE)
- }
-}
-
-@JvmOverloads
-fun LayersAssertion.noUncoveredRegions(
- beginRotation: Int,
- endRotation: Int = beginRotation,
- allStates: Boolean = true,
- bugId: Int = 0,
- enabled: Boolean = bugId == 0
-) {
- val startingBounds = WindowUtils.getDisplayBounds(beginRotation)
- val endingBounds = WindowUtils.getDisplayBounds(endRotation)
- if (allStates) {
- all("noUncoveredRegions", bugId, enabled) {
- if (startingBounds == endingBounds) {
- this.coversAtLeastRegion(startingBounds)
- } else {
- this.coversAtLeastRegion(startingBounds)
- .then()
- .coversAtLeastRegion(endingBounds)
- }
- }
- } else {
- start("noUncoveredRegions_StartingPos") {
- this.coversAtLeastRegion(startingBounds)
- }
- end("noUncoveredRegions_EndingPos") {
- this.coversAtLeastRegion(endingBounds)
- }
- }
-}
-
-@JvmOverloads
-fun LayersAssertion.statusBarLayerIsAlwaysVisible(
- bugId: Int = 0,
- enabled: Boolean = bugId == 0
-) {
- all("statusBarLayerIsAlwaysVisible", bugId, enabled) {
- this.showsLayer(FlickerTestBase.STATUS_BAR_WINDOW_TITLE)
- }
-}
-
-@JvmOverloads
-fun LayersAssertion.navBarLayerIsAlwaysVisible(
- bugId: Int = 0,
- enabled: Boolean = bugId == 0
-) {
- all("navBarLayerIsAlwaysVisible", bugId, enabled) {
- this.showsLayer(FlickerTestBase.NAVIGATION_BAR_WINDOW_TITLE)
- }
-}
@JvmOverloads
fun LayersAssertion.appPairsDividerIsVisible(
@@ -131,48 +59,6 @@ fun LayersAssertion.dockedStackDividerIsInvisible(
}
}
-@JvmOverloads
-fun LayersAssertion.navBarLayerRotatesAndScales(
- beginRotation: Int,
- endRotation: Int = beginRotation,
- bugId: Int = 0,
- enabled: Boolean = bugId == 0
-) {
- val startingPos = WindowUtils.getNavigationBarPosition(beginRotation)
- val endingPos = WindowUtils.getNavigationBarPosition(endRotation)
-
- start("navBarLayerRotatesAndScales_StartingPos", bugId, enabled) {
- this.hasVisibleRegion(FlickerTestBase.NAVIGATION_BAR_WINDOW_TITLE, startingPos)
- }
- end("navBarLayerRotatesAndScales_EndingPost", bugId, enabled) {
- this.hasVisibleRegion(FlickerTestBase.NAVIGATION_BAR_WINDOW_TITLE, endingPos)
- }
-
- if (startingPos == endingPos) {
- all("navBarLayerRotatesAndScales", bugId, enabled) {
- this.hasVisibleRegion(FlickerTestBase.NAVIGATION_BAR_WINDOW_TITLE, startingPos)
- }
- }
-}
-
-@JvmOverloads
-fun LayersAssertion.statusBarLayerRotatesScales(
- beginRotation: Int,
- endRotation: Int = beginRotation,
- bugId: Int = 0,
- enabled: Boolean = bugId == 0
-) {
- val startingPos = WindowUtils.getStatusBarPosition(beginRotation)
- val endingPos = WindowUtils.getStatusBarPosition(endRotation)
-
- start("statusBarLayerRotatesScales_StartingPos", bugId, enabled) {
- this.hasVisibleRegion(FlickerTestBase.STATUS_BAR_WINDOW_TITLE, startingPos)
- }
- end("statusBarLayerRotatesScales_EndingPos", bugId, enabled) {
- this.hasVisibleRegion(FlickerTestBase.STATUS_BAR_WINDOW_TITLE, endingPos)
- }
-}
-
fun EventLogAssertion.focusChanges(
vararg windows: String,
bugId: Int = 0,
diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/apppairs/AppPairsTest.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/apppairs/AppPairsTest.kt
index ced99de21a46..7ac91b065fca 100644
--- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/apppairs/AppPairsTest.kt
+++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/apppairs/AppPairsTest.kt
@@ -29,10 +29,10 @@ import com.android.wm.shell.flicker.helpers.AppPairsHelper
import com.android.wm.shell.flicker.helpers.AppPairsHelper.Companion.TEST_REPETITIONS
import com.android.wm.shell.flicker.appPairsDividerIsInvisible
import com.android.wm.shell.flicker.appPairsDividerIsVisible
-import com.android.wm.shell.flicker.navBarLayerIsAlwaysVisible
-import com.android.wm.shell.flicker.navBarWindowIsAlwaysVisible
-import com.android.wm.shell.flicker.statusBarLayerIsAlwaysVisible
-import com.android.wm.shell.flicker.statusBarWindowIsAlwaysVisible
+import com.android.server.wm.flicker.navBarWindowIsAlwaysVisible
+import com.android.server.wm.flicker.statusBarLayerIsAlwaysVisible
+import com.android.server.wm.flicker.navBarLayerIsAlwaysVisible
+import com.android.server.wm.flicker.statusBarWindowIsAlwaysVisible
import org.junit.FixMethodOrder
import org.junit.Test
import org.junit.runner.RunWith
diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/EnterExitPipTest.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/EnterExitPipTest.kt
index 0663eb344f46..c9396aa7ea63 100644
--- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/EnterExitPipTest.kt
+++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/EnterExitPipTest.kt
@@ -23,10 +23,10 @@ import com.android.server.wm.flicker.helpers.WindowUtils
import com.android.server.wm.flicker.helpers.wakeUpAndGoToHomeScreen
import com.android.wm.shell.flicker.helpers.FixedAppHelper
import com.android.wm.shell.flicker.helpers.PipAppHelper
-import com.android.wm.shell.flicker.navBarLayerIsAlwaysVisible
-import com.android.wm.shell.flicker.navBarWindowIsAlwaysVisible
-import com.android.wm.shell.flicker.statusBarLayerIsAlwaysVisible
-import com.android.wm.shell.flicker.statusBarWindowIsAlwaysVisible
+import com.android.server.wm.flicker.navBarWindowIsAlwaysVisible
+import com.android.server.wm.flicker.statusBarLayerIsAlwaysVisible
+import com.android.server.wm.flicker.navBarLayerIsAlwaysVisible
+import com.android.server.wm.flicker.statusBarWindowIsAlwaysVisible
import com.android.wm.shell.flicker.testapp.Components.PipActivity.EXTRA_ENTER_PIP
import org.junit.FixMethodOrder
import org.junit.Test
diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/PipOrientationTest.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/PipOrientationTest.kt
index 322034ce7688..76aabc1b83cf 100644
--- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/PipOrientationTest.kt
+++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/PipOrientationTest.kt
@@ -24,10 +24,10 @@ import com.android.server.wm.flicker.helpers.WindowUtils
import com.android.server.wm.flicker.helpers.wakeUpAndGoToHomeScreen
import com.android.wm.shell.flicker.helpers.FixedAppHelper
import com.android.wm.shell.flicker.helpers.PipAppHelper
-import com.android.wm.shell.flicker.navBarLayerIsAlwaysVisible
-import com.android.wm.shell.flicker.navBarWindowIsAlwaysVisible
-import com.android.wm.shell.flicker.statusBarLayerIsAlwaysVisible
-import com.android.wm.shell.flicker.statusBarWindowIsAlwaysVisible
+import com.android.server.wm.flicker.navBarWindowIsAlwaysVisible
+import com.android.server.wm.flicker.statusBarLayerIsAlwaysVisible
+import com.android.server.wm.flicker.navBarLayerIsAlwaysVisible
+import com.android.server.wm.flicker.statusBarWindowIsAlwaysVisible
import com.android.wm.shell.flicker.testapp.Components.PipActivity.ACTION_ENTER_PIP
import com.android.wm.shell.flicker.testapp.Components.PipActivity.ACTION_SET_REQUESTED_ORIENTATION
import com.android.wm.shell.flicker.testapp.Components.PipActivity.EXTRA_ENTER_PIP
diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/PipRotationTest.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/PipRotationTest.kt
index 96d98d56e069..a67b3b760c49 100644
--- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/PipRotationTest.kt
+++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/PipRotationTest.kt
@@ -31,13 +31,13 @@ import com.android.server.wm.flicker.repetitions
import com.android.server.wm.flicker.startRotation
import com.android.wm.shell.flicker.helpers.FixedAppHelper
import com.android.wm.shell.flicker.helpers.PipAppHelper
-import com.android.wm.shell.flicker.navBarLayerIsAlwaysVisible
-import com.android.wm.shell.flicker.navBarLayerRotatesAndScales
-import com.android.wm.shell.flicker.navBarWindowIsAlwaysVisible
-import com.android.wm.shell.flicker.noUncoveredRegions
-import com.android.wm.shell.flicker.statusBarLayerIsAlwaysVisible
-import com.android.wm.shell.flicker.statusBarLayerRotatesScales
-import com.android.wm.shell.flicker.statusBarWindowIsAlwaysVisible
+import com.android.server.wm.flicker.navBarWindowIsAlwaysVisible
+import com.android.server.wm.flicker.statusBarLayerIsAlwaysVisible
+import com.android.server.wm.flicker.navBarLayerIsAlwaysVisible
+import com.android.server.wm.flicker.statusBarWindowIsAlwaysVisible
+import com.android.server.wm.flicker.noUncoveredRegions
+import com.android.server.wm.flicker.navBarLayerRotatesAndScales
+import com.android.server.wm.flicker.statusBarLayerRotatesScales
import com.android.wm.shell.flicker.testapp.Components.PipActivity.EXTRA_ENTER_PIP
import org.junit.FixMethodOrder
import org.junit.runner.RunWith
diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/PipSplitScreenTest.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/PipSplitScreenTest.kt
index d20552f0739d..f79b21ff278d 100644
--- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/PipSplitScreenTest.kt
+++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/PipSplitScreenTest.kt
@@ -28,10 +28,10 @@ import com.android.server.wm.flicker.helpers.wakeUpAndGoToHomeScreen
import com.android.wm.shell.flicker.helpers.ImeAppHelper
import com.android.wm.shell.flicker.helpers.FixedAppHelper
import com.android.wm.shell.flicker.helpers.PipAppHelper
-import com.android.wm.shell.flicker.navBarLayerIsAlwaysVisible
-import com.android.wm.shell.flicker.navBarWindowIsAlwaysVisible
-import com.android.wm.shell.flicker.statusBarLayerIsAlwaysVisible
-import com.android.wm.shell.flicker.statusBarWindowIsAlwaysVisible
+import com.android.server.wm.flicker.navBarWindowIsAlwaysVisible
+import com.android.server.wm.flicker.statusBarLayerIsAlwaysVisible
+import com.android.server.wm.flicker.navBarLayerIsAlwaysVisible
+import com.android.server.wm.flicker.statusBarWindowIsAlwaysVisible
import com.android.wm.shell.flicker.testapp.Components.PipActivity.EXTRA_ENTER_PIP
import org.junit.FixMethodOrder
import org.junit.Test
diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/splitscreen/EnterSplitScreenTest.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/splitscreen/EnterSplitScreenTest.kt
index c61a0f171714..5570a562a515 100644
--- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/splitscreen/EnterSplitScreenTest.kt
+++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/splitscreen/EnterSplitScreenTest.kt
@@ -25,10 +25,10 @@ import com.android.server.wm.flicker.helpers.launchSplitScreen
import com.android.server.wm.flicker.helpers.wakeUpAndGoToHomeScreen
import com.android.wm.shell.flicker.dockedStackDividerIsVisible
import com.android.wm.shell.flicker.helpers.SplitScreenHelper.Companion.TEST_REPETITIONS
-import com.android.wm.shell.flicker.navBarLayerIsAlwaysVisible
-import com.android.wm.shell.flicker.navBarWindowIsAlwaysVisible
-import com.android.wm.shell.flicker.statusBarWindowIsAlwaysVisible
-import com.android.wm.shell.flicker.statusBarLayerIsAlwaysVisible
+import com.android.server.wm.flicker.navBarWindowIsAlwaysVisible
+import com.android.server.wm.flicker.statusBarLayerIsAlwaysVisible
+import com.android.server.wm.flicker.navBarLayerIsAlwaysVisible
+import com.android.server.wm.flicker.statusBarWindowIsAlwaysVisible
import org.junit.FixMethodOrder
import org.junit.Test
import org.junit.runner.RunWith
diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/splitscreen/ExitSplitScreenTest.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/splitscreen/ExitSplitScreenTest.kt
index bf9286980b9a..7c47d1f1b1ae 100644
--- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/splitscreen/ExitSplitScreenTest.kt
+++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/splitscreen/ExitSplitScreenTest.kt
@@ -29,8 +29,8 @@ import com.android.server.wm.flicker.helpers.resizeSplitScreen
import com.android.server.wm.flicker.helpers.wakeUpAndGoToHomeScreen
import com.android.wm.shell.flicker.dockedStackDividerIsInvisible
import com.android.wm.shell.flicker.helpers.SplitScreenHelper.Companion.TEST_REPETITIONS
-import com.android.wm.shell.flicker.navBarWindowIsAlwaysVisible
-import com.android.wm.shell.flicker.statusBarWindowIsAlwaysVisible
+import com.android.server.wm.flicker.navBarWindowIsAlwaysVisible
+import com.android.server.wm.flicker.statusBarWindowIsAlwaysVisible
import org.junit.FixMethodOrder
import org.junit.Test
import org.junit.runner.RunWith
diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/apppairs/AppPairLayoutTests.java b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/apppairs/AppPairLayoutTests.java
deleted file mode 100644
index c9d32c4b1f76..000000000000
--- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/apppairs/AppPairLayoutTests.java
+++ /dev/null
@@ -1,89 +0,0 @@
-/*
- * Copyright (C) 2020 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.wm.shell.apppairs;
-
-import static android.content.res.Configuration.ORIENTATION_LANDSCAPE;
-import static android.content.res.Configuration.ORIENTATION_PORTRAIT;
-
-import static com.google.common.truth.Truth.assertThat;
-
-import android.content.res.Configuration;
-import android.graphics.Rect;
-import android.view.Display;
-import android.view.SurfaceControl;
-
-import androidx.test.annotation.UiThreadTest;
-import androidx.test.ext.junit.runners.AndroidJUnit4;
-import androidx.test.filters.SmallTest;
-
-import com.android.wm.shell.ShellTestCase;
-
-import org.junit.After;
-import org.junit.Before;
-import org.junit.Test;
-import org.junit.runner.RunWith;
-import org.mockito.Mock;
-import org.mockito.MockitoAnnotations;
-
-/** Tests for {@link AppPairLayout} */
-@SmallTest
-@RunWith(AndroidJUnit4.class)
-public class AppPairLayoutTests extends ShellTestCase {
- @Mock SurfaceControl mSurfaceControl;
- private Display mDisplay;
- private Configuration mConfiguration;
- private AppPairLayout mAppPairLayout;
-
- @Before
- public void setup() {
- MockitoAnnotations.initMocks(this);
- mConfiguration = getConfiguration(false);
- mDisplay = mContext.getDisplay();
- mAppPairLayout = new AppPairLayout(mContext, mDisplay, mConfiguration, mSurfaceControl);
- }
-
- @After
- @UiThreadTest
- public void tearDown() {
- mAppPairLayout.release();
- }
-
- @Test
- @UiThreadTest
- public void testUpdateConfiguration() {
- assertThat(mAppPairLayout.updateConfiguration(getConfiguration(false))).isFalse();
- assertThat(mAppPairLayout.updateConfiguration(getConfiguration(true))).isTrue();
- }
-
- @Test
- @UiThreadTest
- public void testInitRelease() {
- mAppPairLayout.init();
- assertThat(mAppPairLayout.getDividerLeash()).isNotNull();
- mAppPairLayout.release();
- assertThat(mAppPairLayout.getDividerLeash()).isNull();
- }
-
- private static Configuration getConfiguration(boolean isLandscape) {
- final Configuration configuration = new Configuration();
- configuration.unset();
- configuration.orientation = isLandscape ? ORIENTATION_LANDSCAPE : ORIENTATION_PORTRAIT;
- configuration.windowConfiguration.setBounds(
- new Rect(0, 0, isLandscape ? 2160 : 1080, isLandscape ? 1080 : 2160));
- return configuration;
- }
-}
diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/apppairs/AppPairTests.java b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/apppairs/AppPairTests.java
index f12648a7f709..8dbc1d56bcc2 100644
--- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/apppairs/AppPairTests.java
+++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/apppairs/AppPairTests.java
@@ -55,13 +55,13 @@ public class AppPairTests extends ShellTestCase {
@Before
public void setUp() {
MockitoAnnotations.initMocks(this);
+ when(mDisplayController.getDisplayContext(anyInt())).thenReturn(mContext);
+ when(mDisplayController.getDisplay(anyInt())).thenReturn(
+ mContext.getSystemService(DisplayManager.class).getDisplay(DEFAULT_DISPLAY));
mController = new TestAppPairsController(
mTaskOrganizer,
mSyncQueue,
mDisplayController);
- when(mDisplayController.getDisplayContext(anyInt())).thenReturn(mContext);
- when(mDisplayController.getDisplay(anyInt())).thenReturn(
- mContext.getSystemService(DisplayManager.class).getDisplay(DEFAULT_DISPLAY));
}
@After
diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/apppairs/AppPairsControllerTests.java b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/apppairs/AppPairsControllerTests.java
index f8c68d2018da..fada694a4c07 100644
--- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/apppairs/AppPairsControllerTests.java
+++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/apppairs/AppPairsControllerTests.java
@@ -55,14 +55,14 @@ public class AppPairsControllerTests extends ShellTestCase {
@Before
public void setUp() {
MockitoAnnotations.initMocks(this);
+ when(mDisplayController.getDisplayContext(anyInt())).thenReturn(mContext);
+ when(mDisplayController.getDisplay(anyInt())).thenReturn(
+ mContext.getSystemService(DisplayManager.class).getDisplay(DEFAULT_DISPLAY));
mController = new TestAppPairsController(
mTaskOrganizer,
mSyncQueue,
mDisplayController);
mPool = mController.getPool();
- when(mDisplayController.getDisplayContext(anyInt())).thenReturn(mContext);
- when(mDisplayController.getDisplay(anyInt())).thenReturn(
- mContext.getSystemService(DisplayManager.class).getDisplay(DEFAULT_DISPLAY));
}
@After
diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/apppairs/AppPairsPoolTests.java b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/apppairs/AppPairsPoolTests.java
index 8ece913de53f..a3f134ee97ed 100644
--- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/apppairs/AppPairsPoolTests.java
+++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/apppairs/AppPairsPoolTests.java
@@ -18,10 +18,14 @@ package com.android.wm.shell.apppairs;
import static com.google.common.truth.Truth.assertThat;
+import static org.mockito.ArgumentMatchers.anyInt;
+import static org.mockito.Mockito.when;
+
import androidx.test.ext.junit.runners.AndroidJUnit4;
import androidx.test.filters.SmallTest;
import com.android.wm.shell.ShellTaskOrganizer;
+import com.android.wm.shell.ShellTestCase;
import com.android.wm.shell.common.DisplayController;
import com.android.wm.shell.common.SyncTransactionQueue;
@@ -35,7 +39,7 @@ import org.mockito.MockitoAnnotations;
/** Tests for {@link AppPairsPool} */
@SmallTest
@RunWith(AndroidJUnit4.class)
-public class AppPairsPoolTests {
+public class AppPairsPoolTests extends ShellTestCase {
private TestAppPairsController mController;
private TestAppPairsPool mPool;
@Mock private SyncTransactionQueue mSyncQueue;
@@ -45,6 +49,7 @@ public class AppPairsPoolTests {
@Before
public void setUp() {
MockitoAnnotations.initMocks(this);
+ when(mDisplayController.getDisplayContext(anyInt())).thenReturn(mContext);
mController = new TestAppPairsController(
mTaskOrganizer,
mSyncQueue,
diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/common/split/SplitLayoutTests.java b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/common/split/SplitLayoutTests.java
new file mode 100644
index 000000000000..d87f4c60fad4
--- /dev/null
+++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/common/split/SplitLayoutTests.java
@@ -0,0 +1,106 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.wm.shell.common.split;
+
+import static android.content.res.Configuration.ORIENTATION_LANDSCAPE;
+import static android.content.res.Configuration.ORIENTATION_PORTRAIT;
+
+import static com.google.common.truth.Truth.assertThat;
+
+import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.ArgumentMatchers.anyInt;
+import static org.mockito.ArgumentMatchers.eq;
+import static org.mockito.Mockito.verify;
+
+import android.content.res.Configuration;
+import android.graphics.Rect;
+import android.view.SurfaceControl;
+
+import androidx.test.annotation.UiThreadTest;
+import androidx.test.ext.junit.runners.AndroidJUnit4;
+import androidx.test.filters.SmallTest;
+
+import com.android.internal.policy.DividerSnapAlgorithm;
+import com.android.wm.shell.ShellTestCase;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.Mock;
+import org.mockito.MockitoAnnotations;
+
+/** Tests for {@link SplitLayout} */
+@SmallTest
+@RunWith(AndroidJUnit4.class)
+public class SplitLayoutTests extends ShellTestCase {
+ @Mock SplitLayout.LayoutChangeListener mLayoutChangeListener;
+ @Mock SurfaceControl mRootLeash;
+ private SplitLayout mSplitLayout;
+
+ @Before
+ public void setup() {
+ MockitoAnnotations.initMocks(this);
+ mSplitLayout = new SplitLayout(
+ mContext,
+ getConfiguration(false),
+ mLayoutChangeListener,
+ mRootLeash);
+ }
+
+ @Test
+ @UiThreadTest
+ public void testUpdateConfiguration() {
+ assertThat(mSplitLayout.updateConfiguration(getConfiguration(false))).isFalse();
+ assertThat(mSplitLayout.updateConfiguration(getConfiguration(true))).isTrue();
+ }
+
+ @Test
+ public void testUpdateDividePosition() {
+ mSplitLayout.updateDividePosition(anyInt());
+ verify(mLayoutChangeListener).onBoundsChanging(any(SplitLayout.class));
+ }
+
+ @Test
+ public void testSetSnapTarget() {
+ DividerSnapAlgorithm.SnapTarget snapTarget = getSnapTarget(0,
+ DividerSnapAlgorithm.SnapTarget.FLAG_NONE);
+ mSplitLayout.setSnapTarget(snapTarget);
+ verify(mLayoutChangeListener).onBoundsChanged(any(SplitLayout.class));
+
+ // verify it callbacks properly when the snap target indicates dismissing split.
+ snapTarget = getSnapTarget(0, DividerSnapAlgorithm.SnapTarget.FLAG_DISMISS_START);
+ mSplitLayout.setSnapTarget(snapTarget);
+ verify(mLayoutChangeListener).onSnappedToDismiss(eq(false));
+ snapTarget = getSnapTarget(0, DividerSnapAlgorithm.SnapTarget.FLAG_DISMISS_END);
+ mSplitLayout.setSnapTarget(snapTarget);
+ verify(mLayoutChangeListener).onSnappedToDismiss(eq(true));
+ }
+
+ private static Configuration getConfiguration(boolean isLandscape) {
+ final Configuration configuration = new Configuration();
+ configuration.unset();
+ configuration.orientation = isLandscape ? ORIENTATION_LANDSCAPE : ORIENTATION_PORTRAIT;
+ configuration.windowConfiguration.setBounds(
+ new Rect(0, 0, isLandscape ? 2160 : 1080, isLandscape ? 1080 : 2160));
+ return configuration;
+ }
+
+ private static DividerSnapAlgorithm.SnapTarget getSnapTarget(int position, int flag) {
+ return new DividerSnapAlgorithm.SnapTarget(
+ position /* position */, position /* taskPosition */, flag);
+ }
+}
diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/common/split/SplitWindowManagerTests.java b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/common/split/SplitWindowManagerTests.java
new file mode 100644
index 000000000000..aa0eb2f95ed8
--- /dev/null
+++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/common/split/SplitWindowManagerTests.java
@@ -0,0 +1,66 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.wm.shell.common.split;
+
+import static com.google.common.truth.Truth.assertThat;
+
+import static org.mockito.Mockito.when;
+
+import android.content.res.Configuration;
+import android.graphics.Rect;
+import android.view.SurfaceControl;
+
+import androidx.test.annotation.UiThreadTest;
+import androidx.test.ext.junit.runners.AndroidJUnit4;
+import androidx.test.filters.SmallTest;
+
+import com.android.wm.shell.ShellTestCase;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.Mock;
+import org.mockito.MockitoAnnotations;
+
+/** Tests for {@link SplitWindowManager} */
+@SmallTest
+@RunWith(AndroidJUnit4.class)
+public class SplitWindowManagerTests extends ShellTestCase {
+ @Mock SurfaceControl mSurfaceControl;
+ @Mock SplitLayout mSplitLayout;
+ private SplitWindowManager mSplitWindowManager;
+
+ @Before
+ public void setup() {
+ MockitoAnnotations.initMocks(this);
+ final Configuration configuration = new Configuration();
+ configuration.setToDefaults();
+ mSplitWindowManager = new SplitWindowManager(mContext, configuration, mSurfaceControl);
+ when(mSplitLayout.getDividerBounds()).thenReturn(
+ new Rect(0, 0, configuration.windowConfiguration.getBounds().width(),
+ configuration.windowConfiguration.getBounds().height()));
+ }
+
+ @Test
+ @UiThreadTest
+ public void testInitRelease() {
+ mSplitWindowManager.init(mSplitLayout);
+ assertThat(mSplitWindowManager.getSurfaceControl()).isNotNull();
+ mSplitWindowManager.release();
+ assertThat(mSplitWindowManager.getSurfaceControl()).isNull();
+ }
+}
diff --git a/location/java/android/location/LocationManager.java b/location/java/android/location/LocationManager.java
index 047b809bc766..604c4a1de8f9 100644
--- a/location/java/android/location/LocationManager.java
+++ b/location/java/android/location/LocationManager.java
@@ -1509,8 +1509,15 @@ public class LocationManager {
}
/**
- * Removes location updates for the specified {@link LocationListener}. Following this call,
- * the listener will not receive any more invocations of any kind.
+ * Removes all location updates for the specified {@link LocationListener}. The given listener
+ * is guaranteed not to receive any invocations that <b>happens-after</b> this method is
+ * invoked.
+ *
+ * <p>If the given listener has any batched requests, this method will not flush any incomplete
+ * location batches before stopping location updates. If you wish to flush any pending locations
+ * before stopping, you must first call {@link #requestFlush(String, LocationListener, int)} and
+ * then call this method once the flush is complete. If this method is invoked before the flush
+ * is complete, you may not receive the flushed locations.
*
* @param listener listener that no longer needs location updates
*
@@ -1537,6 +1544,8 @@ public class LocationManager {
* Removes location updates for the specified {@link PendingIntent}. Following this call, the
* PendingIntent will no longer receive location updates.
*
+ * <p>See {@link #removeUpdates(LocationListener)} for more detail on how this method works.
+ *
* @param pendingIntent pending intent that no longer needs location updates
*
* @throws IllegalArgumentException if pendingIntent is null
diff --git a/media/java/android/media/AudioSystem.java b/media/java/android/media/AudioSystem.java
index 39bdf9557595..bd27f6d068bc 100644
--- a/media/java/android/media/AudioSystem.java
+++ b/media/java/android/media/AudioSystem.java
@@ -18,6 +18,7 @@ package android.media;
import android.annotation.IntDef;
import android.annotation.NonNull;
+import android.annotation.RequiresPermission;
import android.annotation.TestApi;
import android.bluetooth.BluetoothCodecConfig;
import android.compat.annotation.UnsupportedAppUsage;
@@ -1550,9 +1551,11 @@ public class AudioSystem
/** @hide returns master balance value in range -1.f -> 1.f, where 0.f is dead center. */
@TestApi
+ @RequiresPermission(android.Manifest.permission.MODIFY_AUDIO_SETTINGS)
public static native float getMasterBalance();
/** @hide Changes the audio balance of the device. */
@TestApi
+ @RequiresPermission(android.Manifest.permission.MODIFY_AUDIO_SETTINGS)
public static native int setMasterBalance(float balance);
// helpers for android.media.AudioManager.getProperty(), see description there for meaning
diff --git a/media/java/android/media/tv/tuner/Tuner.java b/media/java/android/media/tv/tuner/Tuner.java
index c2613716cd07..da14ee1f3212 100644
--- a/media/java/android/media/tv/tuner/Tuner.java
+++ b/media/java/android/media/tv/tuner/Tuner.java
@@ -60,6 +60,7 @@ import com.android.internal.util.FrameworkStatsLog;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
+import java.lang.ref.WeakReference;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashMap;
@@ -296,8 +297,8 @@ public class Tuner implements AutoCloseable {
private Executor mOnResourceLostListenerExecutor;
private Integer mDemuxHandle;
- private Map<Integer, Descrambler> mDescramblers = new HashMap<>();
- private List<Filter> mFilters = new ArrayList<>();
+ private Map<Integer, WeakReference<Descrambler>> mDescramblers = new HashMap<>();
+ private List<WeakReference<Filter>> mFilters = new ArrayList<WeakReference<Filter>>();
private final TunerResourceManager.ResourcesReclaimListener mResourceListener =
new TunerResourceManager.ResourcesReclaimListener() {
@@ -486,18 +487,28 @@ public class Tuner implements AutoCloseable {
if (mLnb != null) {
mLnb.close();
}
- if (!mDescramblers.isEmpty()) {
- for (Map.Entry<Integer, Descrambler> d : mDescramblers.entrySet()) {
- d.getValue().close();
- mTunerResourceManager.releaseDescrambler(d.getKey(), mClientId);
+ synchronized (mDescramblers) {
+ if (!mDescramblers.isEmpty()) {
+ for (Map.Entry<Integer, WeakReference<Descrambler>> d : mDescramblers.entrySet()) {
+ Descrambler descrambler = d.getValue().get();
+ if (descrambler != null) {
+ descrambler.close();
+ }
+ mTunerResourceManager.releaseDescrambler(d.getKey(), mClientId);
+ }
+ mDescramblers.clear();
}
- mDescramblers.clear();
}
- if (!mFilters.isEmpty()) {
- for (Filter f : mFilters) {
- f.close();
+ synchronized (mFilters) {
+ if (!mFilters.isEmpty()) {
+ for (WeakReference<Filter> weakFilter : mFilters) {
+ Filter filter = weakFilter.get();
+ if (filter != null) {
+ filter.close();
+ }
+ }
+ mFilters.clear();
}
- mFilters.clear();
}
if (mDemuxHandle != null) {
int res = nativeCloseDemux(mDemuxHandle);
@@ -1183,7 +1194,10 @@ public class Tuner implements AutoCloseable {
if (mHandler == null) {
mHandler = createEventHandler();
}
- mFilters.add(filter);
+ synchronized (mFilters) {
+ WeakReference<Filter> weakFilter = new WeakReference<Filter>(filter);
+ mFilters.add(weakFilter);
+ }
}
return filter;
}
@@ -1351,7 +1365,10 @@ public class Tuner implements AutoCloseable {
int handle = descramblerHandle[0];
Descrambler descrambler = nativeOpenDescramblerByHandle(handle);
if (descrambler != null) {
- mDescramblers.put(handle, descrambler);
+ synchronized (mDescramblers) {
+ WeakReference weakDescrambler = new WeakReference<Descrambler>(descrambler);
+ mDescramblers.put(handle, weakDescrambler);
+ }
} else {
mTunerResourceManager.releaseDescrambler(handle, mClientId);
}
diff --git a/media/java/android/media/tv/tuner/frontend/FrontendStatus.java b/media/java/android/media/tv/tuner/frontend/FrontendStatus.java
index af1ff01a3ebe..6dd41ffeed40 100644
--- a/media/java/android/media/tv/tuner/frontend/FrontendStatus.java
+++ b/media/java/android/media/tv/tuner/frontend/FrontendStatus.java
@@ -28,7 +28,7 @@ import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
/**
- * Frontend status.
+ * A Frontend Status class that contains the metrics of the active frontend.
*
* @hide
*/
@@ -461,7 +461,7 @@ public class FrontendStatus {
}
/**
- * Lock status for Demod.
+ * Gets if the demod is currently locked or not.
*/
public boolean isDemodLocked() {
if (mIsDemodLocked == null) {
@@ -470,7 +470,7 @@ public class FrontendStatus {
return mIsDemodLocked;
}
/**
- * Gets Signal to Noise Ratio in thousandths of a deciBel (0.001dB).
+ * Gets the current Signal to Noise Ratio in thousandths of a deciBel (0.001dB).
*/
public int getSnr() {
if (mSnr == null) {
@@ -479,7 +479,7 @@ public class FrontendStatus {
return mSnr;
}
/**
- * Gets Bit Error Ratio.
+ * Gets the current Bit Error Ratio.
*
* <p>The number of error bit per 1 billion bits.
*/
@@ -491,7 +491,7 @@ public class FrontendStatus {
}
/**
- * Gets Packages Error Ratio.
+ * Gets the current Packages Error Ratio.
*
* <p>The number of error package per 1 billion packages.
*/
@@ -502,7 +502,7 @@ public class FrontendStatus {
return mPer;
}
/**
- * Gets Bit Error Ratio before Forward Error Correction (FEC).
+ * Gets the current Bit Error Ratio before Forward Error Correction (FEC).
*
* <p>The number of error bit per 1 billion bits before FEC.
*/
@@ -513,7 +513,7 @@ public class FrontendStatus {
return mPerBer;
}
/**
- * Gets Signal Quality in percent.
+ * Gets the current Signal Quality in percent.
*/
public int getSignalQuality() {
if (mSignalQuality == null) {
@@ -522,7 +522,7 @@ public class FrontendStatus {
return mSignalQuality;
}
/**
- * Gets Signal Strength in thousandths of a dBm (0.001dBm).
+ * Gets the current Signal Strength in thousandths of a dBm (0.001dBm).
*/
public int getSignalStrength() {
if (mSignalStrength == null) {
@@ -531,7 +531,7 @@ public class FrontendStatus {
return mSignalStrength;
}
/**
- * Gets symbol rate in symbols per second.
+ * Gets the current symbol rate in symbols per second.
*/
public int getSymbolRate() {
if (mSymbolRate == null) {
@@ -540,7 +540,7 @@ public class FrontendStatus {
return mSymbolRate;
}
/**
- * Gets Inner Forward Error Correction type as specified in ETSI EN 300 468 V1.15.1
+ * Gets the current Inner Forward Error Correction type as specified in ETSI EN 300 468 V1.15.1
* and ETSI EN 302 307-2 V1.1.1.
*/
@FrontendSettings.InnerFec
@@ -551,7 +551,7 @@ public class FrontendStatus {
return mInnerFec;
}
/**
- * Gets modulation.
+ * Gets the currently configured modulation.
*/
@FrontendModulation
public int getModulation() {
@@ -561,7 +561,7 @@ public class FrontendStatus {
return mModulation;
}
/**
- * Gets Spectral Inversion for DVBC.
+ * Gets the currently configured Spectral Inversion for DVBC.
*/
@FrontendSettings.FrontendSpectralInversion
public int getSpectralInversion() {
@@ -571,7 +571,7 @@ public class FrontendStatus {
return mInversion;
}
/**
- * Gets Power Voltage Type for LNB.
+ * Gets the current Power Voltage Type for LNB.
*/
@Lnb.Voltage
public int getLnbVoltage() {
@@ -581,7 +581,7 @@ public class FrontendStatus {
return mLnbVoltage;
}
/**
- * Gets Physical Layer Pipe ID.
+ * Gets the current Physical Layer Pipe ID.
*/
public int getPlpId() {
if (mPlpId == null) {
@@ -599,7 +599,7 @@ public class FrontendStatus {
return mIsEwbs;
}
/**
- * Gets Automatic Gain Control value which is normalized from 0 to 255.
+ * Gets the current Automatic Gain Control value which is normalized from 0 to 255.
*/
public int getAgc() {
if (mAgc == null) {
@@ -617,7 +617,7 @@ public class FrontendStatus {
return mIsLnaOn;
}
/**
- * Gets Error status by layer.
+ * Gets the current Error information by layer.
*/
@NonNull
public boolean[] getLayerErrors() {
@@ -627,7 +627,7 @@ public class FrontendStatus {
return mIsLayerErrors;
}
/**
- * Gets Modulation Error Ratio in thousandths of a deciBel (0.001dB).
+ * Gets the current Modulation Error Ratio in thousandths of a deciBel (0.001dB).
*/
public int getMer() {
if (mMer == null) {
@@ -636,7 +636,7 @@ public class FrontendStatus {
return mMer;
}
/**
- * Gets frequency difference in Hz.
+ * Gets the current frequency difference in Hz.
*
* <p>Difference between tuning frequency and actual locked frequency.
*/
@@ -647,7 +647,7 @@ public class FrontendStatus {
return mFreqOffset;
}
/**
- * Gets hierarchy Type for DVBT.
+ * Gets the current hierarchy Type for DVBT.
*/
@DvbtFrontendSettings.Hierarchy
public int getHierarchy() {
@@ -657,7 +657,7 @@ public class FrontendStatus {
return mHierarchy;
}
/**
- * Gets lock status for RF.
+ * Gets if the RF is locked or not.
*/
public boolean isRfLocked() {
if (mIsRfLocked == null) {
@@ -666,7 +666,7 @@ public class FrontendStatus {
return mIsRfLocked;
}
/**
- * Gets an array of PLP status for tuned PLPs for ATSC3 frontend.
+ * Gets an array of the current tuned PLPs information of ATSC3 frontend.
*/
@NonNull
public Atsc3PlpTuningInfo[] getAtsc3PlpTuningInfo() {
@@ -677,9 +677,9 @@ public class FrontendStatus {
}
/**
- * Gets an array of extended bit error ratio status.
+ * Gets an array of the current extended bit error ratio.
*
- * <p>This status query is only supported by Tuner HAL 1.1 or higher. Use
+ * <p>This query is only supported by Tuner HAL 1.1 or higher. Use
* {@link TunerVersionChecker.getTunerVersion()} to check the version.
*/
@NonNull
@@ -693,10 +693,9 @@ public class FrontendStatus {
}
/**
- * Gets an array of code rates status. The {@link FrontendSettings.InnerFec} would be used to
- * show the code rate.
+ * Gets an array of the current code rates.
*
- * <p>This status query is only supported by Tuner HAL 1.1 or higher. Use
+ * <p>This query is only supported by Tuner HAL 1.1 or higher. Use
* {@link TunerVersionChecker.getTunerVersion()} to check the version.
*/
@NonNull
@@ -711,9 +710,9 @@ public class FrontendStatus {
}
/**
- * Gets bandwidth status.
+ * Gets the current bandwidth information.
*
- * <p>This status query is only supported by Tuner HAL 1.1 or higher. Use
+ * <p>This query is only supported by Tuner HAL 1.1 or higher. Use
* {@link TunerVersionChecker.getTunerVersion()} to check the version.
*/
@FrontendBandwidth
@@ -727,9 +726,9 @@ public class FrontendStatus {
}
/**
- * Gets guard interval status.
+ * Gets the current guard interval information.
*
- * <p>This status query is only supported by Tuner HAL 1.1 or higher. Use
+ * <p>This query is only supported by Tuner HAL 1.1 or higher. Use
* {@link TunerVersionChecker.getTunerVersion()} to check the version.
*/
@FrontendGuardInterval
@@ -743,9 +742,9 @@ public class FrontendStatus {
}
/**
- * Gets tansmission mode status.
+ * Gets the current transmission mode information.
*
- * <p>This status query is only supported by Tuner HAL 1.1 or higher. Use
+ * <p>This query is only supported by Tuner HAL 1.1 or higher. Use
* {@link TunerVersionChecker.getTunerVersion()} to check the version.
*/
@FrontendTransmissionMode
@@ -759,10 +758,10 @@ public class FrontendStatus {
}
/**
- * Gets the Uncorrectable Error Counts of the frontend's Physical Layer Pipe (PLP) since the
- * last tune operation.
+ * Gets the current Uncorrectable Error Counts of the frontend's Physical Layer Pipe (PLP)
+ * since the last tune operation.
*
- * <p>This status query is only supported by Tuner HAL 1.1 or higher. Use
+ * <p>This query is only supported by Tuner HAL 1.1 or higher. Use
* {@link TunerVersionChecker.getTunerVersion()} to check the version.
*/
public int getUec() {
@@ -775,9 +774,9 @@ public class FrontendStatus {
}
/**
- * Gets the current DVB-T2 system id status.
+ * Gets the current DVB-T2 system id.
*
- * <p>This status query is only supported by Tuner HAL 1.1 or higher. Use
+ * <p>This query is only supported by Tuner HAL 1.1 or higher. Use
* {@link TunerVersionChecker.getTunerVersion()} to check the version.
*/
@IntRange(from = 0, to = 0xffff)
@@ -791,10 +790,9 @@ public class FrontendStatus {
}
/**
- * Gets an array of interleaving status. Array value should be within {@link
- * FrontendInterleaveMode}.
+ * Gets an array of the current interleaving mode information.
*
- * <p>This status query is only supported by Tuner HAL 1.1 or higher. Use
+ * <p>This query is only supported by Tuner HAL 1.1 or higher. Use
* {@link TunerVersionChecker.getTunerVersion()} to check the version.
*/
@NonNull
@@ -809,9 +807,10 @@ public class FrontendStatus {
}
/**
- * Gets an array of the segments status in ISDB-T Specification of all the channels.
+ * Gets an array of the current segments information in ISDB-T Specification of all the
+ * channels.
*
- * <p>This status query is only supported by Tuner HAL 1.1 or higher. Use
+ * <p>This query is only supported by Tuner HAL 1.1 or higher. Use
* {@link TunerVersionChecker.getTunerVersion()} to check the version.
*/
@NonNull
@@ -828,7 +827,7 @@ public class FrontendStatus {
/**
* Gets an array of the Transport Stream Data Rate in BPS of the current channel.
*
- * <p>This status query is only supported by Tuner HAL 1.1 or higher. Use
+ * <p>This query is only supported by Tuner HAL 1.1 or higher. Use
* {@link TunerVersionChecker.getTunerVersion()} to check the version.
*/
@NonNull
@@ -842,13 +841,13 @@ public class FrontendStatus {
}
/**
- * Gets an array of the extended modulations status. Array value should be withink {@link
- * FrontendModulation}.
+ * Gets an array of the current extended modulations information.
*
- * <p>This status query is only supported by Tuner HAL 1.1 or higher. Use
+ * <p>This query is only supported by Tuner HAL 1.1 or higher. Use
* {@link TunerVersionChecker.getTunerVersion()} to check the version.
*/
@NonNull
+ @FrontendModulation
public int[] getExtendedModulations() {
TunerVersionChecker.checkHigherOrEqualVersionTo(
TunerVersionChecker.TUNER_VERSION_1_1, "getExtendedModulations status");
@@ -859,9 +858,9 @@ public class FrontendStatus {
}
/**
- * Gets roll off status.
+ * Gets the current roll off information.
*
- * <p>This status query is only supported by Tuner HAL 1.1 or higher. Use
+ * <p>This query is only supported by Tuner HAL 1.1 or higher. Use
* {@link TunerVersionChecker.getTunerVersion()} to check the version.
*/
@FrontendRollOff
@@ -875,9 +874,9 @@ public class FrontendStatus {
}
/**
- * Gets is MISO enabled status.
+ * Gets is MISO enabled or not.
*
- * <p>This status query is only supported by Tuner HAL 1.1 or higher. Use
+ * <p>This query is only supported by Tuner HAL 1.1 or higher. Use
* {@link TunerVersionChecker.getTunerVersion()} to check the version.
*/
public boolean isMisoEnabled() {
@@ -890,9 +889,9 @@ public class FrontendStatus {
}
/**
- * Gets is the Code Rate of the frontend is linear or not status.
+ * Gets is the Code Rate of the frontend is linear or not.
*
- * <p>This status query is only supported by Tuner HAL 1.1 or higher. Use
+ * <p>This query is only supported by Tuner HAL 1.1 or higher. Use
* {@link TunerVersionChecker.getTunerVersion()} to check the version.
*/
public boolean isLinear() {
@@ -905,9 +904,9 @@ public class FrontendStatus {
}
/**
- * Gets is the Short Frames enabled or not status.
+ * Gets is the Short Frames enabled or not.
*
- * <p>This status query is only supported by Tuner HAL 1.1 or higher. Use
+ * <p>This query is only supported by Tuner HAL 1.1 or higher. Use
* {@link TunerVersionChecker.getTunerVersion()} to check the version.
*/
public boolean isShortFramesEnabled() {
@@ -920,7 +919,7 @@ public class FrontendStatus {
}
/**
- * Status for each tuning Physical Layer Pipes.
+ * Information of each tuning Physical Layer Pipes.
*/
public static class Atsc3PlpTuningInfo {
private final int mPlpId;
diff --git a/native/android/Android.bp b/native/android/Android.bp
index 7793d6c45d5e..6db4da95f6db 100644
--- a/native/android/Android.bp
+++ b/native/android/Android.bp
@@ -36,6 +36,7 @@ cc_library_shared {
defaults: ["libandroid_defaults"],
srcs: [
+ "activity_manager.cpp",
"asset_manager.cpp",
"choreographer.cpp",
"configuration.cpp",
@@ -95,6 +96,10 @@ cc_library_shared {
include_dirs: ["bionic/libc/dns/include"],
+ local_include_dirs: [ "include_platform", ],
+
+ export_include_dirs: [ "include_platform", ],
+
version_script: "libandroid.map.txt",
stubs: {
symbol_file: "libandroid.map.txt",
diff --git a/native/android/activity_manager.cpp b/native/android/activity_manager.cpp
new file mode 100644
index 000000000000..82f4569b871e
--- /dev/null
+++ b/native/android/activity_manager.cpp
@@ -0,0 +1,226 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#define LOG_NDEBUG 0
+#define LOG_TAG "AActivityManager"
+#include <utils/Log.h>
+
+#include <android/activity_manager.h>
+#include <binder/ActivityManager.h>
+
+namespace android {
+namespace activitymanager {
+
+// Global instance of ActivityManager, service is obtained only on first use.
+static ActivityManager gAm;
+// String tag used with ActivityManager.
+static const String16& getTag() {
+ static String16 tag("libandroid");
+ return tag;
+}
+
+struct UidObserver : public BnUidObserver, public virtual IBinder::DeathRecipient {
+ explicit UidObserver(const AActivityManager_onUidImportance& cb,
+ int32_t cutpoint, void* cookie)
+ : mCallback(cb), mImportanceCutpoint(cutpoint), mCookie(cookie), mRegistered(false) {}
+ bool registerSelf();
+ void unregisterSelf();
+
+ // IUidObserver
+ void onUidGone(uid_t uid, bool disabled) override;
+ void onUidActive(uid_t uid) override;
+ void onUidIdle(uid_t uid, bool disabled) override;
+ void onUidStateChanged(uid_t uid, int32_t procState, int64_t procStateSeq,
+ int32_t capability) override;
+
+ // IBinder::DeathRecipient implementation
+ void binderDied(const wp<IBinder>& who) override;
+
+ static int32_t procStateToImportance(int32_t procState);
+ static int32_t importanceToProcState(int32_t importance);
+
+ AActivityManager_onUidImportance mCallback;
+ int32_t mImportanceCutpoint;
+ void* mCookie;
+ std::mutex mRegisteredLock;
+ bool mRegistered GUARDED_BY(mRegisteredLock);
+};
+
+//static
+int32_t UidObserver::procStateToImportance(int32_t procState) {
+ // TODO: remove this after adding Importance to onUidStateChanged callback.
+ if (procState == ActivityManager::PROCESS_STATE_NONEXISTENT) {
+ return AACTIVITYMANAGER_IMPORTANCE_GONE;
+ } else if (procState >= ActivityManager::PROCESS_STATE_HOME) {
+ return AACTIVITYMANAGER_IMPORTANCE_CACHED;
+ } else if (procState == ActivityManager::PROCESS_STATE_HEAVY_WEIGHT) {
+ return AACTIVITYMANAGER_IMPORTANCE_CANT_SAVE_STATE;
+ } else if (procState >= ActivityManager::PROCESS_STATE_TOP_SLEEPING) {
+ return AACTIVITYMANAGER_IMPORTANCE_TOP_SLEEPING;
+ } else if (procState >= ActivityManager::PROCESS_STATE_SERVICE) {
+ return AACTIVITYMANAGER_IMPORTANCE_SERVICE;
+ } else if (procState >= ActivityManager::PROCESS_STATE_TRANSIENT_BACKGROUND) {
+ return AACTIVITYMANAGER_IMPORTANCE_PERCEPTIBLE;
+ } else if (procState >= ActivityManager::PROCESS_STATE_IMPORTANT_FOREGROUND) {
+ return AACTIVITYMANAGER_IMPORTANCE_VISIBLE;
+ } else if (procState >= ActivityManager::PROCESS_STATE_FOREGROUND_SERVICE) {
+ return AACTIVITYMANAGER_IMPORTANCE_FOREGROUND_SERVICE;
+ } else {
+ return AACTIVITYMANAGER_IMPORTANCE_FOREGROUND;
+ }
+}
+
+//static
+int32_t UidObserver::importanceToProcState(int32_t importance) {
+ // TODO: remove this after adding Importance to onUidStateChanged callback.
+ if (importance == AACTIVITYMANAGER_IMPORTANCE_GONE) {
+ return ActivityManager::PROCESS_STATE_NONEXISTENT;
+ } else if (importance >= AACTIVITYMANAGER_IMPORTANCE_CACHED) {
+ return ActivityManager::PROCESS_STATE_HOME;
+ } else if (importance >= AACTIVITYMANAGER_IMPORTANCE_CANT_SAVE_STATE) {
+ return ActivityManager::PROCESS_STATE_HEAVY_WEIGHT;
+ } else if (importance >= AACTIVITYMANAGER_IMPORTANCE_TOP_SLEEPING) {
+ return ActivityManager::PROCESS_STATE_TOP_SLEEPING;
+ } else if (importance >= AACTIVITYMANAGER_IMPORTANCE_SERVICE) {
+ return ActivityManager::PROCESS_STATE_SERVICE;
+ } else if (importance >= AACTIVITYMANAGER_IMPORTANCE_PERCEPTIBLE) {
+ return ActivityManager::PROCESS_STATE_TRANSIENT_BACKGROUND;
+ } else if (importance >= AACTIVITYMANAGER_IMPORTANCE_VISIBLE) {
+ return ActivityManager::PROCESS_STATE_IMPORTANT_FOREGROUND;
+ } else if (importance >= AACTIVITYMANAGER_IMPORTANCE_FOREGROUND_SERVICE) {
+ return ActivityManager::PROCESS_STATE_FOREGROUND_SERVICE;
+ } else {
+ return ActivityManager::PROCESS_STATE_TOP;
+ }
+}
+
+
+void UidObserver::onUidGone(uid_t uid, bool disabled __unused) {
+ std::scoped_lock lock{mRegisteredLock};
+
+ if (mRegistered && mCallback) {
+ mCallback(uid, AACTIVITYMANAGER_IMPORTANCE_GONE, mCookie);
+ }
+}
+
+void UidObserver::onUidActive(uid_t uid __unused) {}
+
+void UidObserver::onUidIdle(uid_t uid __unused, bool disabled __unused) {}
+
+void UidObserver::onUidStateChanged(uid_t uid, int32_t procState,
+ int64_t procStateSeq __unused,
+ int32_t capability __unused) {
+ std::scoped_lock lock{mRegisteredLock};
+
+ if (mRegistered && mCallback) {
+ mCallback(uid, procStateToImportance(procState), mCookie);
+ }
+}
+
+void UidObserver::binderDied(const wp<IBinder>& /*who*/) {
+ // ActivityManager is dead, try to re-register.
+ {
+ std::scoped_lock lock{mRegisteredLock};
+ // If client already unregistered, don't try to re-register.
+ if (!mRegistered) {
+ return;
+ }
+ // Clear mRegistered to re-register.
+ mRegistered = false;
+ }
+ registerSelf();
+}
+
+bool UidObserver::registerSelf() {
+ std::scoped_lock lock{mRegisteredLock};
+ if (mRegistered) {
+ return true;
+ }
+
+ status_t res = gAm.linkToDeath(this);
+ if (res != OK) {
+ ALOGE("UidObserver: Failed to linkToDeath with ActivityManager (err %d)", res);
+ return false;
+ }
+
+ // TODO: it seems only way to get all changes is to set cutoff to PROCESS_STATE_UNKNOWN.
+ // But there is no equivalent of PROCESS_STATE_UNKNOWN in the UidImportance.
+ // If mImportanceCutpoint is < 0, use PROCESS_STATE_UNKNOWN instead.
+ res = gAm.registerUidObserver(
+ this,
+ ActivityManager::UID_OBSERVER_GONE | ActivityManager::UID_OBSERVER_PROCSTATE,
+ (mImportanceCutpoint < 0) ? ActivityManager::PROCESS_STATE_UNKNOWN
+ : importanceToProcState(mImportanceCutpoint),
+ getTag());
+ if (res != OK) {
+ ALOGE("UidObserver: Failed to register with ActivityManager (err %d)", res);
+ gAm.unlinkToDeath(this);
+ return false;
+ }
+
+ mRegistered = true;
+ ALOGV("UidObserver: Registered with ActivityManager");
+ return true;
+}
+
+void UidObserver::unregisterSelf() {
+ std::scoped_lock lock{mRegisteredLock};
+
+ if (mRegistered) {
+ gAm.unregisterUidObserver(this);
+ gAm.unlinkToDeath(this);
+ mRegistered = false;
+ }
+
+ ALOGV("UidObserver: Unregistered with ActivityManager");
+}
+
+} // activitymanager
+} // android
+
+using namespace android;
+using namespace activitymanager;
+
+struct AActivityManager_UidImportanceListener : public UidObserver {
+};
+
+AActivityManager_UidImportanceListener* AActivityManager_addUidImportanceListener(
+ AActivityManager_onUidImportance onUidImportance, int32_t importanceCutpoint, void* cookie) {
+ sp<UidObserver> observer(new UidObserver(onUidImportance, importanceCutpoint, cookie));
+ if (observer == nullptr || !observer->registerSelf()) {
+ return nullptr;
+ }
+ observer->incStrong((void *)AActivityManager_addUidImportanceListener);
+ return static_cast<AActivityManager_UidImportanceListener*>(observer.get());
+}
+
+void AActivityManager_removeUidImportanceListener(
+ AActivityManager_UidImportanceListener* listener) {
+ if (listener != nullptr) {
+ UidObserver* observer = static_cast<UidObserver*>(listener);
+ observer->unregisterSelf();
+ observer->decStrong((void *)AActivityManager_addUidImportanceListener);
+ }
+}
+
+bool AActivityManager_isUidActive(uid_t uid) {
+ return gAm.isUidActive(uid, getTag());
+}
+
+int32_t AActivityManager_getUidImportance(uid_t uid) {
+ return UidObserver::procStateToImportance(gAm.getUidProcessState(uid, getTag()));
+}
+
diff --git a/native/android/include_platform/android/activity_manager.h b/native/android/include_platform/android/activity_manager.h
new file mode 100644
index 000000000000..0ecd56d512a2
--- /dev/null
+++ b/native/android/include_platform/android/activity_manager.h
@@ -0,0 +1,176 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef __AACTIVITYMANAGER_H__
+#define __AACTIVITYMANAGER_H__
+
+#include <sys/cdefs.h>
+#include <sys/types.h>
+
+__BEGIN_DECLS
+
+struct AActivityManager_UidImportanceListener;
+typedef struct AActivityManager_UidImportanceListener AActivityManager_UidImportanceListener;
+
+/**
+ * Callback interface when Uid Importance has changed for a uid.
+ *
+ * This callback will be called on an arbitrary thread. Calls to a given listener will be
+ * serialized.
+ *
+ * @param uid the uid for which the importance has changed.
+ * @param uidImportance the new uidImportance for the uid.
+ * @cookie the same cookie when the UidImportanceListener was added.
+ *
+ * Introduced in API 31.
+ */
+typedef void (*AActivityManager_onUidImportance)(uid_t uid, int32_t uidImportance, void* cookie);
+
+/**
+ * ActivityManager Uid Importance constants.
+ *
+ * Introduced in API 31.
+ */
+enum {
+ /**
+ * Constant for Uid Importance: This process is running the
+ * foreground UI; that is, it is the thing currently at the top of the screen
+ * that the user is interacting with.
+ */
+ AACTIVITYMANAGER_IMPORTANCE_FOREGROUND = 100,
+
+ /**
+ * Constant for Uid Importance: This process is running a foreground
+ * service, for example to perform music playback even while the user is
+ * not immediately in the app. This generally indicates that the process
+ * is doing something the user actively cares about.
+ */
+ AACTIVITYMANAGER_IMPORTANCE_FOREGROUND_SERVICE = 125,
+
+ /**
+ * Constant for Uid Importance: This process is running something
+ * that is actively visible to the user, though not in the immediate
+ * foreground. This may be running a window that is behind the current
+ * foreground (so paused and with its state saved, not interacting with
+ * the user, but visible to them to some degree); it may also be running
+ * other services under the system's control that it inconsiders important.
+ */
+ AACTIVITYMANAGER_IMPORTANCE_VISIBLE = 200,
+
+ /**
+ * Constant for Uid Importance: This process is not something the user
+ * is directly aware of, but is otherwise perceptible to them to some degree.
+ */
+ AACTIVITYMANAGER_IMPORTANCE_PERCEPTIBLE = 230,
+
+ /**
+ * Constant for Uid Importance: This process contains services
+ * that should remain running. These are background services apps have
+ * started, not something the user is aware of, so they may be killed by
+ * the system relatively freely (though it is generally desired that they
+ * stay running as long as they want to).
+ */
+ AACTIVITYMANAGER_IMPORTANCE_SERVICE = 300,
+
+ /**
+ * Constant for Uid Importance: This process is running the foreground
+ * UI, but the device is asleep so it is not visible to the user. Though the
+ * system will try hard to keep its process from being killed, in all other
+ * ways we consider it a kind of cached process, with the limitations that go
+ * along with that state: network access, running background services, etc.
+ */
+ AACTIVITYMANAGER_IMPORTANCE_TOP_SLEEPING = 325,
+
+ /**
+ * Constant for Uid Importance: This process is running an
+ * application that can not save its state, and thus can't be killed
+ * while in the background. This will be used with apps that have
+ * {@link android.R.attr#cantSaveState} set on their application tag.
+ */
+ AACTIVITYMANAGER_IMPORTANCE_CANT_SAVE_STATE = 350,
+
+ /**
+ * Constant for Uid Importance: This process process contains
+ * cached code that is expendable, not actively running any app components
+ * we care about.
+ */
+ AACTIVITYMANAGER_IMPORTANCE_CACHED = 400,
+
+ /**
+ * Constant for Uid Importance: This process does not exist.
+ */
+ AACTIVITYMANAGER_IMPORTANCE_GONE = 1000,
+};
+
+#if __ANDROID_API__ >= 31
+
+/**
+ * Adds a UidImportanceListener to the ActivityManager.
+ *
+ * This API requires android.Manifest.permission.PACKAGE_USAGE_STATS permission.
+ *
+ * @param onUidImportance the listener callback that will receive change reports.
+ *
+ * @param importanceCutpoint the level of importance in which the caller is interested
+ * in differences. For example, if AACTIVITYMANAGER_IMPORTANCE_PERCEPTIBLE is used
+ * here, you will receive a call each time a uid's importance transitions between being
+ * <= AACTIVITYMANAGER_IMPORTANCE_PERCEPTIBLE and > AACTIVITYMANAGER_IMPORTANCE_PERCEPTIBLE.
+ *
+ * @param cookie a cookie that will be passed back to the listener callback.
+ *
+ * @return an opaque pointer of AActivityManager_UidImportanceListener, or nullptr
+ * upon failure. Upon success, the returned AActivityManager_UidImportanceListener pointer
+ * must be removed and released through AActivityManager_removeUidImportanceListener.
+ */
+AActivityManager_UidImportanceListener* AActivityManager_addUidImportanceListener(
+ AActivityManager_onUidImportance onUidImportance,
+ int32_t importanceCutpoint,
+ void* cookie) __INTRODUCED_IN(31);
+
+/**
+ * Removes a UidImportanceListener that was added with AActivityManager_addUidImportanceListener.
+ *
+ * When this returns, it's guaranteed the listener callback will no longer be invoked.
+ *
+ * @param listener the UidImportanceListener to be removed.
+ */
+void AActivityManager_removeUidImportanceListener(
+ AActivityManager_UidImportanceListener* listener) __INTRODUCED_IN(31);
+
+/**
+ * Queries if a uid is currently active.
+ *
+ * This API requires android.Manifest.permission.PACKAGE_USAGE_STATS permission.
+ *
+ * @return true if the uid is active, false otherwise.
+ */
+bool AActivityManager_isUidActive(uid_t uid) __INTRODUCED_IN(31);
+
+/**
+ * Queries the current Uid Importance value of a uid.
+ *
+ * This API requires android.Manifest.permission.PACKAGE_USAGE_STATS permission.
+ *
+ * @param uid the uid for which the importance value is queried.
+ * @return the current uid importance value for uid.
+ */
+int32_t AActivityManager_getUidImportance(uid_t uid) __INTRODUCED_IN(31);
+
+#endif // __ANDROID_API__ >= 31
+
+__END_DECLS
+
+#endif // __AACTIVITYMANAGER_H__
diff --git a/native/android/libandroid.map.txt b/native/android/libandroid.map.txt
index eca67bd7d211..8fa3acf502bc 100644
--- a/native/android/libandroid.map.txt
+++ b/native/android/libandroid.map.txt
@@ -1,5 +1,9 @@
LIBANDROID {
global:
+ AActivityManager_addUidImportanceListener; # apex # introduced=31
+ AActivityManager_removeUidImportanceListener; # apex # introduced=31
+ AActivityManager_isUidActive; # apex # introduced=31
+ AActivityManager_getUidImportance; # apex # introduced=31
AAssetDir_close;
AAssetDir_getNextFileName;
AAssetDir_rewind;
diff --git a/native/android/tests/activitymanager/UidImportanceHelperApps/Android.bp b/native/android/tests/activitymanager/UidImportanceHelperApps/Android.bp
new file mode 100644
index 000000000000..1a51218616d2
--- /dev/null
+++ b/native/android/tests/activitymanager/UidImportanceHelperApps/Android.bp
@@ -0,0 +1,11 @@
+android_test_helper_app {
+ name: "UidImportanceHelperApp",
+ manifest: "HelperAppManifest.xml",
+ static_libs: ["androidx.test.rules"],
+ sdk_version: "test_current",
+ srcs: ["src/**/*.java"],
+ test_suites: [
+ "general-tests",
+ ],
+}
+
diff --git a/native/android/tests/activitymanager/UidImportanceHelperApps/HelperAppManifest.xml b/native/android/tests/activitymanager/UidImportanceHelperApps/HelperAppManifest.xml
new file mode 100644
index 000000000000..3583b33756e9
--- /dev/null
+++ b/native/android/tests/activitymanager/UidImportanceHelperApps/HelperAppManifest.xml
@@ -0,0 +1,33 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2020 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+
+<manifest xmlns:android="http://schemas.android.com/apk/res/android"
+ package="com.android.tests.UidImportanceHelper"
+ android:versionCode="1"
+ android:versionName="1.0" >
+
+ <application android:label="UidImportanceHelper">
+ <activity android:name="com.android.tests.UidImportanceHelper.MainActivity"
+ android:exported="true">
+ <intent-filter>
+ <action android:name="android.intent.action.MAIN" />
+ <category android:name="android.intent.category.DEFAULT"/>
+ <category android:name="android.intent.category.LAUNCHER" />
+ </intent-filter>
+ </activity>
+ </application>
+</manifest>
+
diff --git a/native/android/tests/activitymanager/UidImportanceHelperApps/src/com/android/tests/UidImportanceHelper/MainActivity.java b/native/android/tests/activitymanager/UidImportanceHelperApps/src/com/android/tests/UidImportanceHelper/MainActivity.java
new file mode 100644
index 000000000000..db0f2b5ed967
--- /dev/null
+++ b/native/android/tests/activitymanager/UidImportanceHelperApps/src/com/android/tests/UidImportanceHelper/MainActivity.java
@@ -0,0 +1,107 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.android.tests.UidImportanceHelper;
+
+import android.app.Activity;
+import android.content.Intent;
+import android.os.Bundle;
+import android.util.Log;
+
+/**
+ * This is an empty activity for testing the UID policy of media transcoding service.
+ */
+public class MainActivity extends Activity {
+ private static final String TAG = "MainActivity";
+
+ // Called at the start of the full lifetime.
+ @Override
+ public void onCreate(Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
+ // Initialize Activity and inflate the UI.
+ }
+
+ // Called after onCreate has finished, use to restore UI state
+ @Override
+ public void onRestoreInstanceState(Bundle savedInstanceState) {
+ super.onRestoreInstanceState(savedInstanceState);
+ // Restore UI state from the savedInstanceState.
+ // This bundle has also been passed to onCreate.
+ // Will only be called if the Activity has been
+ // killed by the system since it was last visible.
+ }
+
+ // Called before subsequent visible lifetimes
+ // for an activity process.
+ @Override
+ public void onRestart() {
+ super.onRestart();
+ // Load changes knowing that the Activity has already
+ // been visible within this process.
+ }
+
+ // Called at the start of the visible lifetime.
+ @Override
+ public void onStart() {
+ super.onStart();
+ // Apply any required UI change now that the Activity is visible.
+ }
+
+ // Called at the start of the active lifetime.
+ @Override
+ public void onResume() {
+ super.onResume();
+ // Resume any paused UI updates, threads, or processes required
+ // by the Activity but suspended when it was inactive.
+ }
+
+ // Called to save UI state changes at the
+ // end of the active lifecycle.
+ @Override
+ public void onSaveInstanceState(Bundle savedInstanceState) {
+ // Save UI state changes to the savedInstanceState.
+ // This bundle will be passed to onCreate and
+ // onRestoreInstanceState if the process is
+ // killed and restarted by the run time.
+ super.onSaveInstanceState(savedInstanceState);
+ }
+
+ // Called at the end of the active lifetime.
+ @Override
+ public void onPause() {
+ // Suspend UI updates, threads, or CPU intensive processes
+ // that don't need to be updated when the Activity isn't
+ // the active foreground Activity.
+ super.onPause();
+ }
+
+ // Called at the end of the visible lifetime.
+ @Override
+ public void onStop() {
+ // Suspend remaining UI updates, threads, or processing
+ // that aren't required when the Activity isn't visible.
+ // Persist all edits or state changes
+ // as after this call the process is likely to be killed.
+ super.onStop();
+ }
+
+ // Sometimes called at the end of the full lifetime.
+ @Override
+ public void onDestroy() {
+ // Clean up any resources including ending threads,
+ // closing database connections etc.
+ super.onDestroy();
+ }
+}
diff --git a/native/android/tests/activitymanager/nativeTests/Android.bp b/native/android/tests/activitymanager/nativeTests/Android.bp
new file mode 100644
index 000000000000..d4b5015ad8f3
--- /dev/null
+++ b/native/android/tests/activitymanager/nativeTests/Android.bp
@@ -0,0 +1,39 @@
+cc_test {
+ name: "ActivityManagerNativeTestCases",
+
+ multilib: {
+ lib32: {
+ suffix: "32",
+ },
+ lib64: {
+ suffix: "64",
+ },
+ },
+
+ srcs: ["src/ActivityManagerNativeTest.cpp"],
+
+ shared_libs: [
+ "liblog",
+ "libutils",
+ "libandroid",
+ "libbinder",
+ ],
+
+ static_libs: [
+ "libbase",
+ "libgtest",
+ ],
+ stl: "c++_shared",
+
+ test_suites: [
+ "general-tests",
+ ],
+
+ cflags: [
+ "-Werror",
+ "-Wall",
+ ],
+ required: [
+ "UidImportanceHelperApp",
+ ],
+}
diff --git a/native/android/tests/activitymanager/nativeTests/AndroidTest.xml b/native/android/tests/activitymanager/nativeTests/AndroidTest.xml
new file mode 100644
index 000000000000..bf6287ad4883
--- /dev/null
+++ b/native/android/tests/activitymanager/nativeTests/AndroidTest.xml
@@ -0,0 +1,53 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2020 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+<configuration description="Config for ActivityManager native test cases">
+ <option name="test-suite-tag" value="apct" />
+ <option name="test-suite-tag" value="apct-native" />
+ <option name="config-descriptor:metadata" key="component" value="framework" />
+ <option name="config-descriptor:metadata" key="parameter" value="instant_app" />
+ <option name="config-descriptor:metadata" key="parameter" value="multi_abi" />
+ <option name="config-descriptor:metadata" key="parameter" value="secondary_user" />
+
+ <!-- Force root to allow registering UidImportanceListener from native test -->
+ <target_preparer class="com.android.tradefed.targetprep.RootTargetPreparer">
+ <option name="force-root" value="true" />
+ </target_preparer>
+ <target_preparer class="com.android.tradefed.targetprep.RunCommandTargetPreparer">
+ <option name="run-command" value="input keyevent KEYCODE_WAKEUP" />
+ <option name="run-command" value="wm dismiss-keyguard" />
+ </target_preparer>
+ <!-- Install the helper apk -->
+ <target_preparer class="com.android.tradefed.targetprep.suite.SuiteApkInstaller">
+ <option name="cleanup-apks" value="true" />
+ <option name="test-file-name" value="UidImportanceHelperApp.apk" />
+ </target_preparer>
+
+ <target_preparer class="com.android.compatibility.common.tradefed.targetprep.FilePusher">
+ <option name="cleanup" value="true" />
+ <option name="push" value="ActivityManagerNativeTestCases->/data/local/tmp/ActivityManagerNativeTestCases" />
+ <option name="append-bitness" value="true" />
+ </target_preparer>
+
+ <test class="com.android.tradefed.testtype.GTest" >
+ <option name="native-test-device-path" value="/data/local/tmp" />
+ <option name="module-name" value="ActivityManagerNativeTestCases" />
+ <option name="runtime-hint" value="1m" />
+ </test>
+
+ <!-- Controller that will skip the module if a native bridge situation is detected -->
+ <!-- For example: module wants to run arm and device is x86 -->
+ <object type="module_controller" class="com.android.tradefed.testtype.suite.module.NativeBridgeModuleController" />
+</configuration>
diff --git a/native/android/tests/activitymanager/nativeTests/src/ActivityManagerNativeTest.cpp b/native/android/tests/activitymanager/nativeTests/src/ActivityManagerNativeTest.cpp
new file mode 100644
index 000000000000..75ba0ffb229a
--- /dev/null
+++ b/native/android/tests/activitymanager/nativeTests/src/ActivityManagerNativeTest.cpp
@@ -0,0 +1,139 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#define LOG_TAG "ActivityManagerNativeTest"
+
+#include <android-base/logging.h>
+#include <android/activity_manager.h>
+#include <binder/PermissionController.h>
+#include <binder/ProcessState.h>
+#include <gtest/gtest.h>
+
+constexpr const char* kTestPackage = "com.android.tests.UidImportanceHelper";
+constexpr const char* kTestActivity = "com.android.tests.UidImportanceHelper.MainActivity";
+constexpr int64_t kEventTimeoutUs = 500000;
+
+//-----------------------------------------------------------------
+class ActivityManagerNativeTest : public ::testing::Test {
+protected:
+ ActivityManagerNativeTest() : mUidObserver(nullptr), mTestAppUid(-1), mLastUidImportance(-1) {}
+
+ virtual ~ActivityManagerNativeTest() {}
+
+ /* Test setup*/
+ virtual void SetUp() { android::ProcessState::self()->startThreadPool(); }
+
+ /* Test tear down */
+ virtual void TearDown() {}
+
+ bool waitForImportance(int32_t val, int64_t timeoutUs) {
+ std::unique_lock lock(mLock);
+
+ if (mLastUidImportance != val && timeoutUs > 0) {
+ mCondition.wait_for(lock, std::chrono::microseconds(timeoutUs));
+ }
+
+ return mLastUidImportance == val;
+ }
+
+ void onUidImportanceChanged(uid_t uid, int32_t uidImportance) {
+ LOG(ERROR) << "OnUidImportance: uid " << uid << ", importance " << uidImportance;
+ std::unique_lock lock(mLock);
+
+ if (uid == mTestAppUid) {
+ mLastUidImportance = uidImportance;
+ mCondition.notify_one();
+ }
+ }
+
+ static void OnUidImportance(uid_t uid, int32_t uidImportance, void* cookie) {
+ ActivityManagerNativeTest* owner = reinterpret_cast<ActivityManagerNativeTest*>(cookie);
+ owner->onUidImportanceChanged(uid, uidImportance);
+ }
+
+ AActivityManager_UidImportanceListener* mUidObserver;
+ uid_t mTestAppUid;
+ std::mutex mLock;
+ std::condition_variable mCondition;
+ int32_t mLastUidImportance;
+};
+
+static bool getUidForPackage(const char* packageName, /*inout*/ uid_t& uid) {
+ android::PermissionController pc;
+ uid = pc.getPackageUid(android::String16(packageName), 0);
+ if (uid <= 0) {
+ ALOGE("Unknown package: '%s'", packageName);
+ return false;
+ }
+ return true;
+}
+
+struct ShellHelper {
+ static bool RunCmd(const std::string& cmdStr) {
+ int ret = system(cmdStr.c_str());
+ if (ret != 0) {
+ LOG(ERROR) << "Failed to run cmd: " << cmdStr << ", exitcode " << ret;
+ return false;
+ }
+ return true;
+ }
+
+ static bool Start(const char* packageName, const char* activityName) {
+ return RunCmd("am start -W " + std::string(packageName) + "/" + std::string(activityName) +
+ " &> /dev/null");
+ }
+
+ static bool Stop(const char* packageName) {
+ return RunCmd("am force-stop " + std::string(packageName));
+ }
+};
+
+//-------------------------------------------------------------------------------------------------
+TEST_F(ActivityManagerNativeTest, testUidImportance) {
+ pid_t selfPid = ::getpid();
+ uid_t selfUid = ::getuid();
+
+ uid_t testAppUid;
+ EXPECT_TRUE(getUidForPackage(kTestPackage, testAppUid));
+ LOG(INFO) << "testUidImportance: uidselfUid" << selfUid << ", selfPid " << selfPid
+ << ", testAppUid " << testAppUid;
+ mTestAppUid = testAppUid;
+
+ // Expect the initial UidImportance to be GONE.
+ EXPECT_FALSE(AActivityManager_isUidActive(testAppUid));
+ EXPECT_EQ(AActivityManager_getUidImportance(testAppUid), AACTIVITYMANAGER_IMPORTANCE_GONE);
+
+ mUidObserver = AActivityManager_addUidImportanceListener(&OnUidImportance,
+ AACTIVITYMANAGER_IMPORTANCE_FOREGROUND,
+ (void*)this);
+ EXPECT_TRUE(mUidObserver != nullptr);
+
+ // Start the test activity, and expect to receive UidImportance change to FOREGROUND.
+ EXPECT_TRUE(ShellHelper::Start(kTestPackage, kTestActivity));
+ EXPECT_TRUE(waitForImportance(AACTIVITYMANAGER_IMPORTANCE_FOREGROUND, kEventTimeoutUs));
+ EXPECT_TRUE(AActivityManager_isUidActive(testAppUid));
+ EXPECT_EQ(AActivityManager_getUidImportance(testAppUid),
+ AACTIVITYMANAGER_IMPORTANCE_FOREGROUND);
+
+ // Stop the test activity, and expect to receive UidImportance change to GONE.
+ EXPECT_TRUE(ShellHelper::Stop(kTestPackage));
+ EXPECT_TRUE(waitForImportance(AACTIVITYMANAGER_IMPORTANCE_GONE, kEventTimeoutUs));
+ EXPECT_FALSE(AActivityManager_isUidActive(testAppUid));
+ EXPECT_EQ(AActivityManager_getUidImportance(testAppUid), AACTIVITYMANAGER_IMPORTANCE_GONE);
+
+ AActivityManager_removeUidImportanceListener(mUidObserver);
+ mUidObserver = nullptr;
+}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationLockscreenUserManagerImpl.java b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationLockscreenUserManagerImpl.java
index 3c4830272099..7eb921b9e6bb 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationLockscreenUserManagerImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationLockscreenUserManagerImpl.java
@@ -335,7 +335,7 @@ public class NotificationLockscreenUserManagerImpl implements
}
NotificationEntry visibleEntry = getEntryManager().getActiveNotificationUnfiltered(key);
return isLockscreenPublicMode(mCurrentUserId) && visibleEntry != null
- && visibleEntry.getRanking().getVisibilityOverride() == VISIBILITY_SECRET;
+ && visibleEntry.getRanking().getLockscreenVisibilityOverride() == VISIBILITY_SECRET;
}
public boolean shouldShowOnKeyguard(NotificationEntry entry) {
@@ -513,7 +513,8 @@ public class NotificationLockscreenUserManagerImpl implements
}
NotificationEntry entry = getEntryManager().getActiveNotificationUnfiltered(key);
return entry != null
- && entry.getRanking().getVisibilityOverride() == Notification.VISIBILITY_PRIVATE;
+ && entry.getRanking().getLockscreenVisibilityOverride()
+ == Notification.VISIBILITY_PRIVATE;
}
private void updateCurrentProfilesCache() {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/KeyguardCoordinator.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/KeyguardCoordinator.java
index b1c6f535ba87..23d5369833c5 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/KeyguardCoordinator.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/KeyguardCoordinator.java
@@ -120,7 +120,7 @@ public class KeyguardCoordinator implements Coordinator {
// notifications to show in public mode
if (mLockscreenUserManager.isLockscreenPublicMode(currUserId)
|| mLockscreenUserManager.isLockscreenPublicMode(notifUserId)) {
- if (entry.getRanking().getVisibilityOverride() == VISIBILITY_SECRET) {
+ if (entry.getRanking().getLockscreenVisibilityOverride() == VISIBILITY_SECRET) {
return true;
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/wrapper/NotificationHeaderViewWrapper.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/wrapper/NotificationHeaderViewWrapper.java
index 37d5da24a704..7c5d4a3efee7 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/wrapper/NotificationHeaderViewWrapper.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/wrapper/NotificationHeaderViewWrapper.java
@@ -20,6 +20,7 @@ import static com.android.systemui.statusbar.notification.TransformState.TRANSFO
import android.app.Notification;
import android.content.Context;
+import android.content.res.ColorStateList;
import android.util.ArraySet;
import android.view.NotificationHeaderView;
import android.view.NotificationTopLineView;
@@ -168,9 +169,11 @@ public class NotificationHeaderViewWrapper extends NotificationViewWrapper {
public void applyConversationSkin() {
if (mAppNameText != null) {
+ final ColorStateList colors = mAppNameText.getTextColors();
mAppNameText.setTextAppearance(
com.android.internal.R.style
.TextAppearance_DeviceDefault_Notification_Conversation_AppName);
+ mAppNameText.setTextColor(colors);
MarginLayoutParams layoutParams = (MarginLayoutParams) mAppNameText.getLayoutParams();
layoutParams.setMarginStart(0);
}
@@ -189,11 +192,13 @@ public class NotificationHeaderViewWrapper extends NotificationViewWrapper {
public void clearConversationSkin() {
if (mAppNameText != null) {
+ final ColorStateList colors = mAppNameText.getTextColors();
final int textAppearance = Utils.getThemeAttr(
mAppNameText.getContext(),
com.android.internal.R.attr.notificationHeaderTextAppearance,
com.android.internal.R.style.TextAppearance_DeviceDefault_Notification_Info);
mAppNameText.setTextAppearance(textAppearance);
+ mAppNameText.setTextColor(colors);
MarginLayoutParams layoutParams = (MarginLayoutParams) mAppNameText.getLayoutParams();
final int marginStart = mAppNameText.getResources().getDimensionPixelSize(
com.android.internal.R.dimen.notification_header_app_name_margin_start);
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardBouncer.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardBouncer.java
index 9854f5450df1..4ca9c5db013c 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardBouncer.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardBouncer.java
@@ -289,6 +289,8 @@ public class KeyguardBouncer {
SysUiStatsLog.KEYGUARD_BOUNCER_STATE_CHANGED__STATE__HIDDEN);
mDismissCallbackRegistry.notifyDismissCancelled();
}
+ mExpansion = EXPANSION_HIDDEN;
+ dispatchExpansionChanged();
mIsScrimmed = false;
mFalsingCollector.onBouncerHidden();
mCallback.onBouncerVisiblityChanged(false /* shown */);
@@ -377,6 +379,7 @@ public class KeyguardBouncer {
*/
public void setExpansion(float fraction) {
float oldExpansion = mExpansion;
+ boolean expansionChanged = mExpansion != fraction;
mExpansion = fraction;
if (mKeyguardViewController != null && !mIsAnimatingAway) {
mKeyguardViewController.setExpansion(fraction);
@@ -394,6 +397,10 @@ public class KeyguardBouncer {
mKeyguardViewController.onStartingToHide();
}
}
+
+ if (expansionChanged) {
+ dispatchExpansionChanged();
+ }
}
public boolean willDismissWithAction() {
@@ -518,6 +525,12 @@ public class KeyguardBouncer {
}
}
+ private void dispatchExpansionChanged() {
+ for (BouncerExpansionCallback callback : mExpansionCallbacks) {
+ callback.onExpansionChanged(mExpansion);
+ }
+ }
+
public void dump(PrintWriter pw) {
pw.println("KeyguardBouncer");
pw.println(" isShowing(): " + isShowing());
@@ -534,6 +547,12 @@ public class KeyguardBouncer {
void onStartingToHide();
void onStartingToShow();
void onFullyHidden();
+
+ /**
+ * From 0f {@link KeyguardBouncer#EXPANSION_VISIBLE} when fully visible
+ * to 1f {@link KeyguardBouncer#EXPANSION_HIDDEN} when fully hidden
+ */
+ default void onExpansionChanged(float bouncerHideAmount) {}
}
/** Create a {@link KeyguardBouncer} once a container and bouncer callback are available. */
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/LockscreenLockIconController.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/LockscreenLockIconController.java
index 0e7e2fd8173c..547a3705266a 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/LockscreenLockIconController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/LockscreenLockIconController.java
@@ -23,6 +23,7 @@ import static com.android.systemui.statusbar.phone.LockIcon.STATE_LOCKED;
import static com.android.systemui.statusbar.phone.LockIcon.STATE_LOCK_OPEN;
import static com.android.systemui.statusbar.phone.LockIcon.STATE_SCANNING_FACE;
+import android.animation.ArgbEvaluator;
import android.content.res.Configuration;
import android.content.res.Resources;
import android.content.res.TypedArray;
@@ -38,6 +39,7 @@ import com.android.internal.logging.nano.MetricsProto;
import com.android.internal.widget.LockPatternUtils;
import com.android.keyguard.KeyguardUpdateMonitor;
import com.android.keyguard.KeyguardUpdateMonitorCallback;
+import com.android.settingslib.Utils;
import com.android.systemui.R;
import com.android.systemui.dagger.SysUISingleton;
import com.android.systemui.dagger.qualifiers.Main;
@@ -84,7 +86,7 @@ public class LockscreenLockIconController {
private boolean mDocked;
private boolean mWakeAndUnlockRunning;
private boolean mShowingLaunchAffordance;
- private boolean mBouncerShowing;
+ private float mBouncerHiddenAmount = KeyguardBouncer.EXPANSION_HIDDEN;
private boolean mBouncerShowingScrimmed;
private boolean mFingerprintUnlock;
private int mStatusBarState = StatusBarState.SHADE;
@@ -104,6 +106,8 @@ public class LockscreenLockIconController {
mSimLocked = mKeyguardUpdateMonitor.isSimPinSecure();
mConfigurationListener.onThemeChanged();
+
+ updateColor();
update();
}
@@ -348,7 +352,6 @@ public class LockscreenLockIconController {
*/
public void attach(LockIcon lockIcon) {
mLockIcon = lockIcon;
- updateColor();
mLockIcon.setOnClickListener(this::handleClick);
mLockIcon.setOnLongClickListener(this::handleLongClick);
@@ -408,20 +411,44 @@ public class LockscreenLockIconController {
/** Sets whether the bouncer is showing. */
public void setBouncerShowingScrimmed(boolean showing, boolean scrimmed) {
- mBouncerShowing = showing;
mBouncerShowingScrimmed = scrimmed;
update();
}
+ /**
+ * Sets how hidden the bouncer is, where 0f is fully visible and 1f is fully hidden
+ * See {@link KeyguardBouncer#EXPANSION_VISIBLE} and {@link KeyguardBouncer#EXPANSION_HIDDEN}.
+ */
+ public void setBouncerHideAmount(float hideAmount) {
+ mBouncerHiddenAmount = hideAmount;
+ updateColor();
+ }
+
private void updateColor() {
if (mLockIcon == null) {
return;
}
- TypedArray typedArray = mLockIcon.getContext().getTheme().obtainStyledAttributes(
- null, new int[]{ android.R.attr.textColorPrimary }, 0, 0);
- int iconColor = typedArray.getColor(0, Color.WHITE);
- typedArray.recycle();
+ int iconColor = -1;
+ if (mBouncerHiddenAmount == KeyguardBouncer.EXPANSION_VISIBLE) {
+ TypedArray typedArray = mLockIcon.getContext().getTheme().obtainStyledAttributes(
+ null, new int[]{ android.R.attr.textColorPrimary }, 0, 0);
+ iconColor = typedArray.getColor(0, Color.WHITE);
+ typedArray.recycle();
+ } else if (mBouncerHiddenAmount == KeyguardBouncer.EXPANSION_HIDDEN) {
+ iconColor = Utils.getColorAttrDefaultColor(
+ mLockIcon.getContext(), com.android.systemui.R.attr.wallpaperTextColor);
+ } else {
+ // bouncer is transitioning
+ TypedArray typedArray = mLockIcon.getContext().getTheme().obtainStyledAttributes(
+ null, new int[]{ android.R.attr.textColorPrimary }, 0, 0);
+ int bouncerIconColor = typedArray.getColor(0, Color.WHITE);
+ typedArray.recycle();
+ int keyguardIconColor = Utils.getColorAttrDefaultColor(
+ mLockIcon.getContext(), com.android.systemui.R.attr.wallpaperTextColor);
+ iconColor = (int) new ArgbEvaluator().evaluate(
+ mBouncerHiddenAmount, bouncerIconColor, keyguardIconColor);
+ }
mLockIcon.updateColor(iconColor);
}
@@ -520,10 +547,7 @@ public class LockscreenLockIconController {
return changed;
}
boolean onAodOrDocked = mStatusBarStateController.isDozing() || mDocked;
- boolean onKeyguardWithoutBouncer = mStatusBarState == StatusBarState.KEYGUARD
- && !mBouncerShowing;
- boolean invisible = onAodOrDocked || mWakeAndUnlockRunning || mShowingLaunchAffordance
- || onKeyguardWithoutBouncer;
+ boolean invisible = onAodOrDocked || mWakeAndUnlockRunning || mShowingLaunchAffordance;
boolean fingerprintOrBypass = mFingerprintUnlock
|| mKeyguardBypassController.getBypassEnabled();
if (fingerprintOrBypass && !mBouncerShowingScrimmed) {
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 9e872ab65591..981f9a662deb 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBar.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBar.java
@@ -3794,6 +3794,14 @@ public class StatusBar extends SystemUI implements DemoMode,
}
/**
+ * Sets how hidden the bouncer is, where 0f is fully visible and 1f is fully hidden
+ * See {@link KeyguardBouncer#EXPANSION_VISIBLE} and {@link KeyguardBouncer#EXPANSION_HIDDEN}.
+ */
+ public void setBouncerHideAmount(float hideAmount) {
+ mLockscreenLockIconController.setBouncerHideAmount(hideAmount);
+ }
+
+ /**
* Collapses the notification shade if it is tracking or expanded.
*/
public void collapseShade() {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarKeyguardViewManager.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarKeyguardViewManager.java
index b912614ba3e8..055b78a2c000 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarKeyguardViewManager.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarKeyguardViewManager.java
@@ -130,6 +130,11 @@ public class StatusBarKeyguardViewManager implements RemoteInputController.Callb
updateStates();
updateLockIcon();
}
+
+ @Override
+ public void onExpansionChanged(float hideAmount) {
+ mStatusBar.setBouncerHideAmount(hideAmount);
+ }
};
private final DockManager.DockEventListener mDockEventListener =
new DockManager.DockEventListener() {
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 46ddc3b809a7..6c5251b02291 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/RemoteInputView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/RemoteInputView.java
@@ -18,7 +18,6 @@ package com.android.systemui.statusbar.policy;
import android.animation.Animator;
import android.animation.AnimatorListenerAdapter;
-import android.annotation.NonNull;
import android.annotation.Nullable;
import android.app.ActivityManager;
import android.app.Notification;
@@ -75,6 +74,7 @@ import com.android.systemui.statusbar.notification.row.wrapper.NotificationViewW
import com.android.systemui.statusbar.notification.stack.StackStateAnimator;
import com.android.systemui.statusbar.phone.LightBarController;
+import java.util.Collection;
import java.util.HashMap;
import java.util.function.Consumer;
@@ -315,8 +315,7 @@ public class RemoteInputView extends LinearLayout implements View.OnClickListene
mRemoteInputs = remoteInputs;
mRemoteInput = remoteInput;
mEditText.setHint(mRemoteInput.getLabel());
- mEditText.mSupportedMimeTypes = (remoteInput.getAllowedDataTypes() == null) ? null
- : remoteInput.getAllowedDataTypes().toArray(new String[0]);
+ mEditText.setSupportedMimeTypes(remoteInput.getAllowedDataTypes());
mEntry.editedSuggestionInfo = editedSuggestionInfo;
if (editedSuggestionInfo != null) {
@@ -570,12 +569,13 @@ public class RemoteInputView extends LinearLayout implements View.OnClickListene
*/
public static class RemoteEditText extends EditText {
+ private final OnReceiveContentListener mOnReceiveContentListener = this::onReceiveContent;
+
private final Drawable mBackground;
private RemoteInputView mRemoteInputView;
boolean mShowImeOnInputConnection;
private LightBarController mLightBarController;
UserHandle mUser;
- private String[] mSupportedMimeTypes;
public RemoteEditText(Context context, AttributeSet attrs) {
super(context, attrs);
@@ -583,39 +583,14 @@ public class RemoteInputView extends LinearLayout implements View.OnClickListene
mLightBarController = Dependency.get(LightBarController.class);
}
- @Override
- protected void onFinishInflate() {
- super.onFinishInflate();
- if (mSupportedMimeTypes != null && mSupportedMimeTypes.length > 0) {
- setOnReceiveContentListener(mSupportedMimeTypes,
- new OnReceiveContentListener() {
- @Override
- @Nullable
- public ContentInfo onReceiveContent(@NonNull View view,
- @NonNull ContentInfo payload) {
- Pair<ContentInfo, ContentInfo> split = payload.partition(
- item -> item.getUri() != null);
- ContentInfo uriContent = split.first;
- ContentInfo remaining = split.second;
- if (uriContent != null) {
- ClipData clip = uriContent.getClip();
- ClipDescription description = clip.getDescription();
- if (clip.getItemCount() > 1
- || description.getMimeTypeCount() < 1
- || remaining != null) {
- // TODO(b/172363500): Update to loop over all the items
- return payload;
- }
- Uri contentUri = clip.getItemAt(0).getUri();
- String mimeType = description.getMimeType(0);
- Intent dataIntent = mRemoteInputView
- .prepareRemoteInputFromData(mimeType, contentUri);
- mRemoteInputView.sendRemoteInput(dataIntent);
- }
- return remaining;
- }
- });
+ void setSupportedMimeTypes(@Nullable Collection<String> mimeTypes) {
+ String[] types = null;
+ OnReceiveContentListener listener = null;
+ if (mimeTypes != null && !mimeTypes.isEmpty()) {
+ types = mimeTypes.toArray(new String[0]);
+ listener = mOnReceiveContentListener;
}
+ setOnReceiveContentListener(types, listener);
}
private void defocusIfNeeded(boolean animate) {
@@ -759,5 +734,28 @@ public class RemoteInputView extends LinearLayout implements View.OnClickListene
setBackground(null);
}
}
+
+ private ContentInfo onReceiveContent(View view, ContentInfo payload) {
+ Pair<ContentInfo, ContentInfo> split =
+ payload.partition(item -> item.getUri() != null);
+ ContentInfo uriItems = split.first;
+ ContentInfo remainingItems = split.second;
+ if (uriItems != null) {
+ ClipData clip = uriItems.getClip();
+ ClipDescription description = clip.getDescription();
+ if (clip.getItemCount() > 1
+ || description.getMimeTypeCount() < 1
+ || remainingItems != null) {
+ // TODO(b/172363500): Update to loop over all the items
+ return payload;
+ }
+ Uri contentUri = clip.getItemAt(0).getUri();
+ String mimeType = description.getMimeType(0);
+ Intent dataIntent =
+ mRemoteInputView.prepareRemoteInputFromData(mimeType, contentUri);
+ mRemoteInputView.sendRemoteInput(dataIntent);
+ }
+ return remainingItems;
+ }
}
}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/accessibility/MagnificationModeSwitchTest.java b/packages/SystemUI/tests/src/com/android/systemui/accessibility/MagnificationModeSwitchTest.java
index a0ae35ffef00..11150432f757 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/accessibility/MagnificationModeSwitchTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/accessibility/MagnificationModeSwitchTest.java
@@ -29,20 +29,23 @@ import static com.android.systemui.accessibility.MagnificationModeSwitch.FADING_
import static com.android.systemui.accessibility.MagnificationModeSwitch.getIconResId;
import static junit.framework.Assert.assertEquals;
+import static junit.framework.Assert.assertNotNull;
import static org.hamcrest.CoreMatchers.hasItems;
import static org.hamcrest.MatcherAssert.assertThat;
import static org.mockito.ArgumentMatchers.any;
-import static org.mockito.ArgumentMatchers.anyFloat;
import static org.mockito.ArgumentMatchers.anyInt;
import static org.mockito.ArgumentMatchers.anyLong;
import static org.mockito.ArgumentMatchers.eq;
import static org.mockito.Mockito.doAnswer;
+import static org.mockito.Mockito.doNothing;
+import static org.mockito.Mockito.doReturn;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
import android.content.Context;
import android.content.pm.ActivityInfo;
+import android.os.SystemClock;
import android.os.UserHandle;
import android.provider.Settings;
import android.testing.AndroidTestingRunner;
@@ -60,15 +63,18 @@ import androidx.test.filters.SmallTest;
import com.android.systemui.R;
import com.android.systemui.SysuiTestCase;
+import org.junit.After;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.ArgumentCaptor;
-import org.mockito.Captor;
import org.mockito.Mock;
import org.mockito.Mockito;
import org.mockito.MockitoAnnotations;
+import java.util.ArrayList;
+import java.util.List;
+
@SmallTest
@RunWith(AndroidTestingRunner.class)
public class MagnificationModeSwitchTest extends SysuiTestCase {
@@ -81,11 +87,10 @@ public class MagnificationModeSwitchTest extends SysuiTestCase {
private AccessibilityManager mAccessibilityManager;
@Mock
private WindowManager mWindowManager;
- @Mock
private ViewPropertyAnimator mViewPropertyAnimator;
private MagnificationModeSwitch mMagnificationModeSwitch;
- @Captor
- private ArgumentCaptor<View.OnTouchListener> mTouchListenerCaptor;
+ private View.OnTouchListener mTouchListener;
+ private List<MotionEvent> mMotionEvents = new ArrayList<>();
@Before
public void setUp() throws Exception {
@@ -97,9 +102,23 @@ public class MagnificationModeSwitchTest extends SysuiTestCase {
mContext.addMockSystemService(Context.WINDOW_SERVICE, mWindowManager);
mContext.addMockSystemService(Context.ACCESSIBILITY_SERVICE, mAccessibilityManager);
mSpyImageView = Mockito.spy(new ImageView(mContext));
- resetMockImageViewAndAnimator();
-
+ mViewPropertyAnimator = Mockito.spy(mSpyImageView.animate());
+ resetAndStubMockImageViewAndAnimator();
+ doAnswer((invocation) -> {
+ mTouchListener = invocation.getArgument(0);
+ return null;
+ }).when(mSpyImageView).setOnTouchListener(
+ any(View.OnTouchListener.class));
mMagnificationModeSwitch = new MagnificationModeSwitch(mContext, mSpyImageView);
+ assertNotNull(mTouchListener);
+ }
+
+ @After
+ public void tearDown() {
+ for (MotionEvent event:mMotionEvents) {
+ event.recycle();
+ }
+ mMotionEvents.clear();
}
@Test
@@ -124,7 +143,7 @@ public class MagnificationModeSwitchTest extends SysuiTestCase {
}
@Test
- public void showMagnificationButton_a11yTimeout_autoFadeOut() {
+ public void showMagnificationButton_setA11yTimeout_postDelayedAnimationWithA11yTimeout() {
final int a11yTimeout = 12345;
when(mAccessibilityManager.getRecommendedTimeoutMillis(anyInt(), anyInt())).thenReturn(
a11yTimeout);
@@ -134,14 +153,21 @@ public class MagnificationModeSwitchTest extends SysuiTestCase {
verify(mAccessibilityManager).getRecommendedTimeoutMillis(
DEFAULT_FADE_OUT_ANIMATION_DELAY_MS, AccessibilityManager.FLAG_CONTENT_ICONS
| AccessibilityManager.FLAG_CONTENT_CONTROLS);
- final ArgumentCaptor<Runnable> fadeOutCaptor = ArgumentCaptor.forClass(Runnable.class);
- final ArgumentCaptor<Long> fadeOutDelay = ArgumentCaptor.forClass(Long.class);
- verify(mSpyImageView).postOnAnimationDelayed(fadeOutCaptor.capture(),
- fadeOutDelay.capture());
- assertEquals(a11yTimeout, (long) fadeOutDelay.getValue());
+ verify(mSpyImageView).postOnAnimationDelayed(any(Runnable.class), eq((long) a11yTimeout));
+ }
+
+ @Test
+ public void showMagnificationButton_windowMode_verifyAnimationEndAction() {
+ // Execute the runnable immediately to run the animation.
+ doAnswer((invocation) -> {
+ final Runnable action = invocation.getArgument(0);
+ action.run();
+ return null;
+ }).when(mSpyImageView).postOnAnimationDelayed(any(Runnable.class), anyLong());
+
+ mMagnificationModeSwitch.showButton(ACCESSIBILITY_MAGNIFICATION_MODE_WINDOW);
// Verify the end action after fade-out.
- fadeOutCaptor.getValue().run();
final ArgumentCaptor<Runnable> endActionCaptor = ArgumentCaptor.forClass(Runnable.class);
verify(mViewPropertyAnimator).withEndAction(endActionCaptor.capture());
@@ -154,7 +180,7 @@ public class MagnificationModeSwitchTest extends SysuiTestCase {
@Test
public void onConfigurationChanged_buttonIsShowing_setImageResource() {
mMagnificationModeSwitch.showButton(ACCESSIBILITY_MAGNIFICATION_MODE_FULLSCREEN);
- resetMockImageViewAndAnimator();
+ resetAndStubMockImageViewAndAnimator();
mMagnificationModeSwitch.onConfigurationChanged(ActivityInfo.CONFIG_DENSITY);
@@ -165,42 +191,46 @@ public class MagnificationModeSwitchTest extends SysuiTestCase {
@Test
public void performSingleTap_fullscreenMode_removeViewAndChangeSettingsValue() {
mMagnificationModeSwitch.showButton(ACCESSIBILITY_MAGNIFICATION_MODE_FULLSCREEN);
- resetMockImageViewAndAnimator();
+ resetAndStubMockImageViewAndAnimator();
// Perform a single-tap
- final View.OnTouchListener listener = mTouchListenerCaptor.getValue();
- listener.onTouch(mSpyImageView, MotionEvent.obtain(
- 0, 0, ACTION_DOWN, 100, 100, 0));
+ final long downTime = SystemClock.uptimeMillis();
+ mTouchListener.onTouch(mSpyImageView,
+ obtainMotionEvent(downTime, 0, ACTION_DOWN, 100, 100));
+
verify(mViewPropertyAnimator).cancel();
- resetMockImageViewAndAnimator();
- listener.onTouch(mSpyImageView, MotionEvent.obtain(
- 0, ViewConfiguration.getTapTimeout(), ACTION_UP, 100, 100, 0));
+ resetAndStubMockImageViewAndAnimator();
+ mTouchListener.onTouch(mSpyImageView,
+ obtainMotionEvent(downTime, downTime, ACTION_UP, 100, 100));
+
verifyTapAction(ACCESSIBILITY_MAGNIFICATION_MODE_WINDOW);
}
@Test
- public void showMagnificationButton_performDragging_updateViewLayout() {
+ public void performDragging_showMagnificationButton_updateViewLayout() {
mMagnificationModeSwitch.showButton(ACCESSIBILITY_MAGNIFICATION_MODE_FULLSCREEN);
- resetMockImageViewAndAnimator();
-
- // Perform dragging
- final View.OnTouchListener listener = mTouchListenerCaptor.getValue();
- final int offset = ViewConfiguration.get(mContext).getScaledTouchSlop();
+ resetAndStubMockImageViewAndAnimator();
final int previousMode = Settings.Secure.getIntForUser(mContext.getContentResolver(),
Settings.Secure.ACCESSIBILITY_MAGNIFICATION_MODE, 0, UserHandle.USER_CURRENT);
- listener.onTouch(mSpyImageView, MotionEvent.obtain(
- 0, 0, ACTION_DOWN, 100, 100, 0));
+
+ // Perform dragging
+ final int offset = ViewConfiguration.get(mContext).getScaledTouchSlop() + 10;
+ final long downTime = SystemClock.uptimeMillis();
+ mTouchListener.onTouch(mSpyImageView, obtainMotionEvent(
+ downTime, 0, ACTION_DOWN, 100, 100));
verify(mViewPropertyAnimator).cancel();
- listener.onTouch(mSpyImageView, MotionEvent.obtain(
- 0, ViewConfiguration.getTapTimeout(), ACTION_MOVE, 100 + offset, 100, 0));
+ mTouchListener.onTouch(mSpyImageView,
+ obtainMotionEvent(downTime, downTime, ACTION_MOVE, 100 + offset,
+ 100));
verify(mWindowManager).updateViewLayout(eq(mSpyImageView),
any(WindowManager.LayoutParams.class));
- resetMockImageViewAndAnimator();
- listener.onTouch(mSpyImageView, MotionEvent.obtain(
- 0, ViewConfiguration.getTapTimeout() + 10, ACTION_UP, 100 + offset, 100, 0));
+ resetAndStubMockImageViewAndAnimator();
+ mTouchListener.onTouch(mSpyImageView, obtainMotionEvent(
+ downTime, downTime, ACTION_UP, 100 + offset, 100));
+
assertModeUnchanged(previousMode);
assertShowFadingAnimation(FADE_OUT_ALPHA);
}
@@ -208,18 +238,17 @@ public class MagnificationModeSwitchTest extends SysuiTestCase {
@Test
public void performSingleTapActionCanceled_showButtonAnimation() {
mMagnificationModeSwitch.showButton(ACCESSIBILITY_MAGNIFICATION_MODE_FULLSCREEN);
- resetMockImageViewAndAnimator();
-
- // Perform single tap
- final View.OnTouchListener listener = mTouchListenerCaptor.getValue();
+ resetAndStubMockImageViewAndAnimator();
final int previousMode = Settings.Secure.getInt(mContext.getContentResolver(),
Settings.Secure.ACCESSIBILITY_MAGNIFICATION_MODE, 0);
- listener.onTouch(mSpyImageView, MotionEvent.obtain(
- 0, 0, ACTION_DOWN, 100, 100, 0));
- resetMockImageViewAndAnimator();
- listener.onTouch(mSpyImageView, MotionEvent.obtain(
- 0, ViewConfiguration.getTapTimeout(), ACTION_CANCEL, 100, 100, 0));
+ final long downTime = SystemClock.uptimeMillis();
+ mTouchListener.onTouch(mSpyImageView, obtainMotionEvent(
+ downTime, downTime, ACTION_DOWN, 100, 100));
+ resetAndStubMockImageViewAndAnimator();
+ mTouchListener.onTouch(mSpyImageView, obtainMotionEvent(
+ downTime, downTime, ACTION_CANCEL, 100, 100));
+
assertModeUnchanged(previousMode);
assertShowFadingAnimation(FADE_OUT_ALPHA);
}
@@ -227,21 +256,21 @@ public class MagnificationModeSwitchTest extends SysuiTestCase {
@Test
public void performDraggingActionCanceled_showButtonAnimation() {
mMagnificationModeSwitch.showButton(ACCESSIBILITY_MAGNIFICATION_MODE_FULLSCREEN);
- resetMockImageViewAndAnimator();
-
- // Perform dragging
- final View.OnTouchListener listener = mTouchListenerCaptor.getValue();
- final int offset = ViewConfiguration.get(mContext).getScaledTouchSlop();
+ resetAndStubMockImageViewAndAnimator();
final int previousMode = Settings.Secure.getInt(mContext.getContentResolver(),
Settings.Secure.ACCESSIBILITY_MAGNIFICATION_MODE, 0);
- listener.onTouch(mSpyImageView, MotionEvent.obtain(
- 0, 0, ACTION_DOWN, 100, 100, 0));
- listener.onTouch(mSpyImageView, MotionEvent.obtain(
- 0, ViewConfiguration.getTapTimeout(), ACTION_MOVE, 100 + offset, 100, 0));
-
- resetMockImageViewAndAnimator();
- listener.onTouch(mSpyImageView, MotionEvent.obtain(
- 0, ViewConfiguration.getTapTimeout(), ACTION_CANCEL, 100 + offset, 100, 0));
+
+ // Perform dragging
+ final long downTime = SystemClock.uptimeMillis();
+ final int offset = ViewConfiguration.get(mContext).getScaledTouchSlop() + 10;
+ mTouchListener.onTouch(mSpyImageView, obtainMotionEvent(
+ 0, 0, ACTION_DOWN, 100, 100));
+ mTouchListener.onTouch(mSpyImageView, obtainMotionEvent(
+ downTime, downTime, ACTION_MOVE, 100 + offset, 100));
+ resetAndStubMockImageViewAndAnimator();
+ mTouchListener.onTouch(mSpyImageView, obtainMotionEvent(
+ downTime, downTime, ACTION_CANCEL, 100 + offset, 100));
+
assertModeUnchanged(previousMode);
assertShowFadingAnimation(FADE_OUT_ALPHA);
}
@@ -266,7 +295,7 @@ public class MagnificationModeSwitchTest extends SysuiTestCase {
@Test
public void performA11yActions_showWindowModeButton_verifyTapAction() {
mMagnificationModeSwitch.showButton(ACCESSIBILITY_MAGNIFICATION_MODE_WINDOW);
- resetMockImageViewAndAnimator();
+ resetAndStubMockImageViewAndAnimator();
mSpyImageView.performAccessibilityAction(
ACTION_CLICK.getId(), null);
@@ -278,7 +307,7 @@ public class MagnificationModeSwitchTest extends SysuiTestCase {
public void showButton_showFadeOutAnimation_fadeOutAnimationCanceled() {
mMagnificationModeSwitch.showButton(ACCESSIBILITY_MAGNIFICATION_MODE_FULLSCREEN);
assertShowFadingAnimation(FADE_OUT_ALPHA);
- resetMockImageViewAndAnimator();
+ resetAndStubMockImageViewAndAnimator();
mMagnificationModeSwitch.showButton(ACCESSIBILITY_MAGNIFICATION_MODE_FULLSCREEN);
@@ -327,7 +356,7 @@ public class MagnificationModeSwitchTest extends SysuiTestCase {
} else { // Fade-out
verify(mSpyImageView).postOnAnimationDelayed(runnableCaptor.capture(), anyLong());
}
- resetMockAnimator();
+ resetAndStubMockAnimator();
runnableCaptor.getValue().run();
@@ -336,20 +365,15 @@ public class MagnificationModeSwitchTest extends SysuiTestCase {
verify(mViewPropertyAnimator).start();
}
- private void resetMockImageViewAndAnimator() {
+ private void resetAndStubMockImageViewAndAnimator() {
+ resetAndStubMockAnimator();
Mockito.reset(mSpyImageView);
- doAnswer(invocation -> null).when(mSpyImageView).setOnTouchListener(
- mTouchListenerCaptor.capture());
- resetMockAnimator();
+ doReturn(mViewPropertyAnimator).when(mSpyImageView).animate();
}
- private void resetMockAnimator() {
+ private void resetAndStubMockAnimator() {
Mockito.reset(mViewPropertyAnimator);
- when(mViewPropertyAnimator.setDuration(anyLong())).thenReturn(mViewPropertyAnimator);
- when(mViewPropertyAnimator.alpha(anyFloat())).thenReturn(mViewPropertyAnimator);
- when(mViewPropertyAnimator.withEndAction(any(Runnable.class))).thenReturn(
- mViewPropertyAnimator);
- when(mSpyImageView.animate()).thenReturn(mViewPropertyAnimator);
+ doNothing().when(mViewPropertyAnimator).start();
}
/**
@@ -366,4 +390,11 @@ public class MagnificationModeSwitchTest extends SysuiTestCase {
Settings.Secure.ACCESSIBILITY_MAGNIFICATION_MODE, 0, UserHandle.USER_CURRENT);
assertEquals(expectedMode, actualMode);
}
+
+ private MotionEvent obtainMotionEvent(long downTime, long eventTime, int action, float x,
+ float y) {
+ MotionEvent event = MotionEvent.obtain(downTime, eventTime, action, x, y, 0);
+ mMotionEvents.add(event);
+ return event;
+ }
}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/RankingBuilder.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/RankingBuilder.java
index 152c51e1f9f4..ac699f7192c8 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/RankingBuilder.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/RankingBuilder.java
@@ -65,7 +65,7 @@ public class RankingBuilder {
mKey = ranking.getKey();
mRank = ranking.getRank();
mMatchesInterruptionFilter = ranking.matchesInterruptionFilter();
- mVisibilityOverride = ranking.getVisibilityOverride();
+ mVisibilityOverride = ranking.getLockscreenVisibilityOverride();
mSuppressedVisualEffects = ranking.getSuppressedVisualEffects();
mImportance = ranking.getImportance();
mExplanation = ranking.getImportanceExplanation();
diff --git a/services/accessibility/java/com/android/server/accessibility/AbstractAccessibilityServiceConnection.java b/services/accessibility/java/com/android/server/accessibility/AbstractAccessibilityServiceConnection.java
index d6d4e4f6c746..8f093c7e6674 100644
--- a/services/accessibility/java/com/android/server/accessibility/AbstractAccessibilityServiceConnection.java
+++ b/services/accessibility/java/com/android/server/accessibility/AbstractAccessibilityServiceConnection.java
@@ -1797,4 +1797,7 @@ abstract class AbstractAccessibilityServiceConnection extends IAccessibilityServ
public void setTouchExplorationPassthroughRegion(int displayId, Region region) {
mSystemSupport.setTouchExplorationPassthroughRegion(displayId, region);
}
+
+ @Override
+ public void setFocusAppearance(int strokeWidth, int color) { }
}
diff --git a/services/accessibility/java/com/android/server/accessibility/AccessibilityManagerService.java b/services/accessibility/java/com/android/server/accessibility/AccessibilityManagerService.java
index be2f8f16a412..c6919ad24572 100644
--- a/services/accessibility/java/com/android/server/accessibility/AccessibilityManagerService.java
+++ b/services/accessibility/java/com/android/server/accessibility/AccessibilityManagerService.java
@@ -1968,6 +1968,7 @@ public class AccessibilityManagerService extends IAccessibilityManager.Stub
// Update the capabilities before the mode.
updateMagnificationCapabilitiesSettingsChangeLocked(userState);
updateMagnificationModeChangeSettingsLocked(userState);
+ updateFocusAppearanceDataLocked(userState);
}
private void updateWindowsForAccessibilityCallbackLocked(AccessibilityUserState userState) {
@@ -3012,6 +3013,30 @@ public class AccessibilityManagerService extends IAccessibilityManager.Stub
}
}
+ /**
+ * Gets the stroke width of the focus rectangle.
+ * @return The stroke width.
+ */
+ public int getFocusStrokeWidth() {
+ synchronized (mLock) {
+ final AccessibilityUserState userState = getCurrentUserStateLocked();
+
+ return userState.getFocusStrokeWidthLocked();
+ }
+ }
+
+ /**
+ * Gets the color of the focus rectangle.
+ * @return The color.
+ */
+ public int getFocusColor() {
+ synchronized (mLock) {
+ final AccessibilityUserState userState = getCurrentUserStateLocked();
+
+ return userState.getFocusColorLocked();
+ }
+ }
+
@Override
public void dump(FileDescriptor fd, final PrintWriter pw, String[] args) {
if (!DumpUtils.checkDumpPermission(mContext, LOG_TAG, pw)) return;
@@ -3623,4 +3648,18 @@ public class AccessibilityManagerService extends IAccessibilityManager.Stub
}
}
}
+
+ private void updateFocusAppearanceDataLocked(AccessibilityUserState userState) {
+ if (userState.mUserId != mCurrentUserId) {
+ return;
+ }
+
+ mMainHandler.post(() -> {
+ broadcastToClients(userState, ignoreRemoteException(client -> {
+ client.mCallback.setFocusAppearance(userState.getFocusStrokeWidthLocked(),
+ userState.getFocusColorLocked());
+ }));
+ });
+
+ }
}
diff --git a/services/accessibility/java/com/android/server/accessibility/AccessibilityServiceConnection.java b/services/accessibility/java/com/android/server/accessibility/AccessibilityServiceConnection.java
index e48d11d17f40..5d67992316a2 100644
--- a/services/accessibility/java/com/android/server/accessibility/AccessibilityServiceConnection.java
+++ b/services/accessibility/java/com/android/server/accessibility/AccessibilityServiceConnection.java
@@ -120,6 +120,8 @@ class AccessibilityServiceConnection extends AbstractAccessibilityServiceConnect
AccessibilityUserState userState = mUserStateWeakReference.get();
if (userState == null) return;
userState.removeServiceLocked(this);
+ userState.resetFocusAppearanceLocked();
+ mSystemSupport.onClientChangeLocked(false);
mSystemSupport.getFullScreenMagnificationController().resetAllIfNeeded(mId);
mActivityTaskManagerService.setAllowAppSwitches(mComponentName.flattenToString(), -1,
userState.mUserId);
@@ -144,6 +146,7 @@ class AccessibilityServiceConnection extends AbstractAccessibilityServiceConnect
} finally {
Binder.restoreCallingIdentity(identity);
}
+ userState.resetFocusAppearanceLocked();
mSystemSupport.onClientChangeLocked(false);
}
}
@@ -310,6 +313,7 @@ class AccessibilityServiceConnection extends AbstractAccessibilityServiceConnect
AccessibilityUserState userState = mUserStateWeakReference.get();
if (userState != null) {
userState.serviceDisconnectedLocked(this);
+ userState.resetFocusAppearanceLocked();
}
resetLocked();
mSystemSupport.getFullScreenMagnificationController().resetAllIfNeeded(mId);
@@ -391,4 +395,32 @@ class AccessibilityServiceConnection extends AbstractAccessibilityServiceConnect
}
}
}
+
+ @Override
+ public void setFocusAppearance(int strokeWidth, int color) {
+ AccessibilityUserState userState = mUserStateWeakReference.get();
+ if (userState == null) {
+ return;
+ }
+
+ synchronized (mLock) {
+ if (!hasRightsToCurrentUserLocked()) {
+ return;
+ }
+
+ if (!mSecurityPolicy.checkAccessibilityAccess(this)) {
+ return;
+ }
+
+ if (userState.getFocusStrokeWidthLocked() == strokeWidth
+ && userState.getFocusColorLocked() == color) {
+ return;
+ }
+
+ // Sets the appearance data in the A11yUserState.
+ userState.setFocusAppearanceLocked(strokeWidth, color);
+ // Updates the appearance data in the A11yManager.
+ mSystemSupport.onClientChangeLocked(false);
+ }
+ }
}
diff --git a/services/accessibility/java/com/android/server/accessibility/AccessibilityUserState.java b/services/accessibility/java/com/android/server/accessibility/AccessibilityUserState.java
index 240c7ff061c8..90e2fdfa2f03 100644
--- a/services/accessibility/java/com/android/server/accessibility/AccessibilityUserState.java
+++ b/services/accessibility/java/com/android/server/accessibility/AccessibilityUserState.java
@@ -45,6 +45,7 @@ import android.util.Slog;
import android.view.accessibility.AccessibilityManager;
import android.view.accessibility.IAccessibilityManagerClient;
+import com.android.internal.R;
import com.android.internal.accessibility.AccessibilityShortcutController;
import java.io.FileDescriptor;
@@ -122,6 +123,15 @@ class AccessibilityUserState {
// The magnification capabilities used to know magnification mode could be switched.
private int mMagnificationCapabilities = ACCESSIBILITY_MAGNIFICATION_MODE_FULLSCREEN;
+ /** The stroke width of the focus rectangle in pixels */
+ private int mFocusStrokeWidth;
+ /** The color of the focus rectangle */
+ private int mFocusColor;
+ // The default value of the focus stroke width.
+ private final int mFocusStrokeWidthDefaultValue;
+ // The default value of the focus color.
+ private final int mFocusColorDefaultValue;
+
private Context mContext;
@SoftKeyboardShowMode
@@ -140,6 +150,12 @@ class AccessibilityUserState {
mUserId = userId;
mContext = context;
mServiceInfoChangeListener = serviceInfoChangeListener;
+ mFocusStrokeWidthDefaultValue = mContext.getResources().getDimensionPixelSize(
+ R.dimen.accessibility_focus_highlight_stroke_width);
+ mFocusColorDefaultValue = mContext.getResources().getColor(
+ R.color.accessibility_focus_highlight_color);
+ mFocusStrokeWidth = mFocusStrokeWidthDefaultValue;
+ mFocusColor = mFocusColorDefaultValue;
}
boolean isHandlingAccessibilityEventsLocked() {
@@ -178,6 +194,7 @@ class AccessibilityUserState {
mUserNonInteractiveUiTimeout = 0;
mUserInteractiveUiTimeout = 0;
mMagnificationMode = ACCESSIBILITY_MAGNIFICATION_MODE_FULLSCREEN;
+ resetFocusAppearanceLocked();
}
void addServiceLocked(AccessibilityServiceConnection serviceConnection) {
@@ -880,4 +897,40 @@ class AccessibilityUserState {
}
return false;
}
+
+ /**
+ * Gets the stroke width of the focus rectangle.
+ * @return The stroke width.
+ */
+ public int getFocusStrokeWidthLocked() {
+ return mFocusStrokeWidth;
+ }
+
+ /**
+ * Gets the color of the focus rectangle.
+ * @return The color.
+ */
+ public int getFocusColorLocked() {
+ return mFocusColor;
+ }
+
+ /**
+ * Sets the stroke width and color of the focus rectangle.
+ *
+ * @param strokeWidth The strokeWidth of the focus rectangle.
+ * @param color The color of the focus rectangle.
+ */
+ public void setFocusAppearanceLocked(int strokeWidth, int color) {
+ mFocusStrokeWidth = strokeWidth;
+ mFocusColor = color;
+ }
+
+ /**
+ * Resets the stroke width and color of the focus rectangle to the default value.
+ *
+ */
+ public void resetFocusAppearanceLocked() {
+ mFocusStrokeWidth = mFocusStrokeWidthDefaultValue;
+ mFocusColor = mFocusColorDefaultValue;
+ }
}
diff --git a/services/appwidget/java/com/android/server/appwidget/AppWidgetServiceImpl.java b/services/appwidget/java/com/android/server/appwidget/AppWidgetServiceImpl.java
index f1988e9f8b6b..449063d95770 100644
--- a/services/appwidget/java/com/android/server/appwidget/AppWidgetServiceImpl.java
+++ b/services/appwidget/java/com/android/server/appwidget/AppWidgetServiceImpl.java
@@ -19,6 +19,7 @@ package com.android.server.appwidget;
import static android.content.Context.KEYGUARD_SERVICE;
import static android.content.Intent.FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS;
import static android.content.Intent.FLAG_ACTIVITY_NEW_TASK;
+
import static com.android.server.pm.PackageManagerService.PLATFORM_PACKAGE_NAME;
import android.annotation.UserIdInt;
@@ -102,6 +103,7 @@ import android.util.proto.ProtoOutputStream;
import android.view.Display;
import android.view.View;
import android.widget.RemoteViews;
+
import com.android.internal.R;
import com.android.internal.app.SuspendedAppActivity;
import com.android.internal.app.UnlaunchableAppActivity;
@@ -111,11 +113,14 @@ import com.android.internal.os.BackgroundThread;
import com.android.internal.os.SomeArgs;
import com.android.internal.util.ArrayUtils;
import com.android.internal.util.DumpUtils;
-import com.android.internal.util.FastXmlSerializer;
import com.android.internal.widget.IRemoteViewsFactory;
import com.android.server.LocalServices;
import com.android.server.WidgetBackupProvider;
import com.android.server.policy.IconUtilities;
+
+import org.xmlpull.v1.XmlPullParser;
+import org.xmlpull.v1.XmlPullParserException;
+
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.File;
@@ -137,9 +142,6 @@ import java.util.Map;
import java.util.Objects;
import java.util.Set;
import java.util.concurrent.atomic.AtomicLong;
-import org.xmlpull.v1.XmlPullParser;
-import org.xmlpull.v1.XmlPullParserException;
-import org.xmlpull.v1.XmlSerializer;
class AppWidgetServiceImpl extends IAppWidgetService.Stub implements WidgetBackupProvider,
OnCrossProfileWidgetProvidersChangeListener {
@@ -2497,85 +2499,80 @@ class AppWidgetServiceImpl extends IAppWidgetService.Stub implements WidgetBacku
}
}
- private static void serializeProvider(XmlSerializer out, Provider p) throws IOException {
+ private static void serializeProvider(TypedXmlSerializer out, Provider p) throws IOException {
out.startTag(null, "p");
out.attribute(null, "pkg", p.info.provider.getPackageName());
out.attribute(null, "cl", p.info.provider.getClassName());
- out.attribute(null, "tag", Integer.toHexString(p.tag));
+ out.attributeIntHex(null, "tag", p.tag);
if (!TextUtils.isEmpty(p.infoTag)) {
out.attribute(null, "info_tag", p.infoTag);
}
out.endTag(null, "p");
}
- private static void serializeHost(XmlSerializer out, Host host) throws IOException {
+ private static void serializeHost(TypedXmlSerializer out, Host host) throws IOException {
out.startTag(null, "h");
out.attribute(null, "pkg", host.id.packageName);
- out.attribute(null, "id", Integer.toHexString(host.id.hostId));
- out.attribute(null, "tag", Integer.toHexString(host.tag));
+ out.attributeIntHex(null, "id", host.id.hostId);
+ out.attributeIntHex(null, "tag", host.tag);
out.endTag(null, "h");
}
- private static void serializeAppWidget(XmlSerializer out, Widget widget,
+ private static void serializeAppWidget(TypedXmlSerializer out, Widget widget,
boolean saveRestoreCompleted) throws IOException {
out.startTag(null, "g");
- out.attribute(null, "id", Integer.toHexString(widget.appWidgetId));
- out.attribute(null, "rid", Integer.toHexString(widget.restoredId));
- out.attribute(null, "h", Integer.toHexString(widget.host.tag));
+ out.attributeIntHex(null, "id", widget.appWidgetId);
+ out.attributeIntHex(null, "rid", widget.restoredId);
+ out.attributeIntHex(null, "h", widget.host.tag);
if (widget.provider != null) {
- out.attribute(null, "p", Integer.toHexString(widget.provider.tag));
+ out.attributeIntHex(null, "p", widget.provider.tag);
}
if (widget.options != null) {
int minWidth = widget.options.getInt(AppWidgetManager.OPTION_APPWIDGET_MIN_WIDTH);
int minHeight = widget.options.getInt(AppWidgetManager.OPTION_APPWIDGET_MIN_HEIGHT);
int maxWidth = widget.options.getInt(AppWidgetManager.OPTION_APPWIDGET_MAX_WIDTH);
int maxHeight = widget.options.getInt(AppWidgetManager.OPTION_APPWIDGET_MAX_HEIGHT);
- out.attribute(null, "min_width", Integer.toHexString((minWidth > 0) ? minWidth : 0));
- out.attribute(null, "min_height", Integer.toHexString((minHeight > 0) ? minHeight : 0));
- out.attribute(null, "max_width", Integer.toHexString((maxWidth > 0) ? maxWidth : 0));
- out.attribute(null, "max_height", Integer.toHexString((maxHeight > 0) ? maxHeight : 0));
- out.attribute(null, "host_category", Integer.toHexString(widget.options.getInt(
- AppWidgetManager.OPTION_APPWIDGET_HOST_CATEGORY)));
+ out.attributeIntHex(null, "min_width", (minWidth > 0) ? minWidth : 0);
+ out.attributeIntHex(null, "min_height", (minHeight > 0) ? minHeight : 0);
+ out.attributeIntHex(null, "max_width", (maxWidth > 0) ? maxWidth : 0);
+ out.attributeIntHex(null, "max_height", (maxHeight > 0) ? maxHeight : 0);
+ out.attributeIntHex(null, "host_category", widget.options.getInt(
+ AppWidgetManager.OPTION_APPWIDGET_HOST_CATEGORY));
if (saveRestoreCompleted) {
boolean restoreCompleted = widget.options.getBoolean(
AppWidgetManager.OPTION_APPWIDGET_RESTORE_COMPLETED);
- out.attribute(null, "restore_completed", Boolean.toString(restoreCompleted));
+ out.attributeBoolean(null, "restore_completed", restoreCompleted);
}
}
out.endTag(null, "g");
}
- private static Bundle parseWidgetIdOptions(XmlPullParser parser) {
+ private static Bundle parseWidgetIdOptions(TypedXmlPullParser parser) {
Bundle options = new Bundle();
- String restoreCompleted = parser.getAttributeValue(null, "restore_completed");
- if (restoreCompleted != null) {
- options.putBoolean(AppWidgetManager.OPTION_APPWIDGET_RESTORE_COMPLETED,
- Boolean.valueOf(restoreCompleted));
- }
- String minWidthString = parser.getAttributeValue(null, "min_width");
- if (minWidthString != null) {
- options.putInt(AppWidgetManager.OPTION_APPWIDGET_MIN_WIDTH,
- Integer.parseInt(minWidthString, 16));
- }
- String minHeightString = parser.getAttributeValue(null, "min_height");
- if (minHeightString != null) {
- options.putInt(AppWidgetManager.OPTION_APPWIDGET_MIN_HEIGHT,
- Integer.parseInt(minHeightString, 16));
- }
- String maxWidthString = parser.getAttributeValue(null, "max_width");
- if (maxWidthString != null) {
- options.putInt(AppWidgetManager.OPTION_APPWIDGET_MAX_WIDTH,
- Integer.parseInt(maxWidthString, 16));
- }
- String maxHeightString = parser.getAttributeValue(null, "max_height");
- if (maxHeightString != null) {
- options.putInt(AppWidgetManager.OPTION_APPWIDGET_MAX_HEIGHT,
- Integer.parseInt(maxHeightString, 16));
- }
- String categoryString = parser.getAttributeValue(null, "host_category");
- if (categoryString != null) {
- options.putInt(AppWidgetManager.OPTION_APPWIDGET_HOST_CATEGORY,
- Integer.parseInt(categoryString, 16));
+ boolean restoreCompleted = parser.getAttributeBoolean(null, "restore_completed", false);
+ if (restoreCompleted) {
+ options.putBoolean(AppWidgetManager.OPTION_APPWIDGET_RESTORE_COMPLETED, true);
+ }
+ int minWidth = parser.getAttributeIntHex(null, "min_width", -1);
+ if (minWidth != -1) {
+ options.putInt(AppWidgetManager.OPTION_APPWIDGET_MIN_WIDTH, minWidth);
+ }
+ int minHeight = parser.getAttributeIntHex(null, "min_height", -1);
+ if (minHeight != -1) {
+ options.putInt(AppWidgetManager.OPTION_APPWIDGET_MIN_HEIGHT, minHeight);
+ }
+ int maxWidth = parser.getAttributeIntHex(null, "max_width", -1);
+ if (maxWidth != -1) {
+ options.putInt(AppWidgetManager.OPTION_APPWIDGET_MAX_WIDTH, maxWidth);
+ }
+ int maxHeight = parser.getAttributeIntHex(null, "max_height", -1);
+ if (maxHeight != -1) {
+ options.putInt(AppWidgetManager.OPTION_APPWIDGET_MAX_HEIGHT, maxHeight);
+ }
+ int category = parser.getAttributeIntHex(null, "host_category",
+ AppWidgetProviderInfo.WIDGET_CATEGORY_UNKNOWN);
+ if (category != AppWidgetProviderInfo.WIDGET_CATEGORY_UNKNOWN) {
+ options.putInt(AppWidgetManager.OPTION_APPWIDGET_HOST_CATEGORY, category);
}
return options;
}
@@ -3080,7 +3077,7 @@ class AppWidgetServiceImpl extends IAppWidgetService.Stub implements WidgetBacku
TypedXmlSerializer out = Xml.resolveSerializer(stream);
out.startDocument(null, true);
out.startTag(null, "gs");
- out.attribute(null, "version", String.valueOf(CURRENT_VERSION));
+ out.attributeInt(null, "version", CURRENT_VERSION);
N = mProviders.size();
for (int i = 0; i < N; i++) {
@@ -3149,12 +3146,7 @@ class AppWidgetServiceImpl extends IAppWidgetService.Stub implements WidgetBacku
if (type == XmlPullParser.START_TAG) {
String tag = parser.getName();
if ("gs".equals(tag)) {
- String attributeValue = parser.getAttributeValue(null, "version");
- try {
- version = Integer.parseInt(attributeValue);
- } catch (NumberFormatException e) {
- version = 0;
- }
+ version = parser.getAttributeInt(null, "version", 0);
} else if ("p".equals(tag)) {
legacyProviderIndex++;
// TODO: do we need to check that this package has the same signature
@@ -3193,9 +3185,8 @@ class AppWidgetServiceImpl extends IAppWidgetService.Stub implements WidgetBacku
mProviders.add(provider);
}
- String tagAttribute = parser.getAttributeValue(null, "tag");
- final int providerTag = !TextUtils.isEmpty(tagAttribute)
- ? Integer.parseInt(tagAttribute, 16) : legacyProviderIndex;
+ final int providerTag = parser.getAttributeIntHex(null, "tag",
+ legacyProviderIndex);
provider.tag = providerTag;
provider.infoTag = parser.getAttributeValue(null, "info_tag");
@@ -3221,12 +3212,9 @@ class AppWidgetServiceImpl extends IAppWidgetService.Stub implements WidgetBacku
if (!host.zombie || mSafeMode) {
// In safe mode, we don't discard the hosts we don't recognize
// so that they're not pruned from our list. Otherwise, we do.
- final int hostId = Integer.parseInt(parser.getAttributeValue(
- null, "id"), 16);
-
- String tagAttribute = parser.getAttributeValue(null, "tag");
- final int hostTag = !TextUtils.isEmpty(tagAttribute)
- ? Integer.parseInt(tagAttribute, 16) : legacyHostIndex;
+ final int hostId = parser.getAttributeIntHex(null, "id");
+ final int hostTag = parser.getAttributeIntHex(null, "tag",
+ legacyHostIndex);
host.tag = hostTag;
host.id = new HostId(uid, hostId, pkg);
@@ -3241,21 +3229,17 @@ class AppWidgetServiceImpl extends IAppWidgetService.Stub implements WidgetBacku
}
} else if ("g".equals(tag)) {
Widget widget = new Widget();
- widget.appWidgetId = Integer.parseInt(parser.getAttributeValue(
- null, "id"), 16);
+ widget.appWidgetId = parser.getAttributeIntHex(null, "id");
setMinAppWidgetIdLocked(userId, widget.appWidgetId + 1);
// restored ID is allowed to be absent
- String restoredIdString = parser.getAttributeValue(null, "rid");
- widget.restoredId = (restoredIdString == null) ? 0
- : Integer.parseInt(restoredIdString, 16);
+ widget.restoredId = parser.getAttributeIntHex(null, "rid", 0);
widget.options = parseWidgetIdOptions(parser);
- final int hostTag = Integer.parseInt(parser.getAttributeValue(
- null, "h"), 16);
+ final int hostTag = parser.getAttributeIntHex(null, "h");
String providerString = parser.getAttributeValue(null, "p");
- final int providerTag = (providerString != null) ? Integer.parseInt(
- parser.getAttributeValue(null, "p"), 16) : TAG_UNDEFINED;
+ final int providerTag = (providerString != null)
+ ? parser.getAttributeIntHex(null, "p") : TAG_UNDEFINED;
// We can match widgets with hosts and providers only after hosts
// and providers for all users have been loaded since the widget
@@ -4372,11 +4356,11 @@ class AppWidgetServiceImpl extends IAppWidgetService.Stub implements WidgetBacku
}
try {
- XmlSerializer out = new FastXmlSerializer();
+ TypedXmlSerializer out = Xml.newFastSerializer();
out.setOutput(stream, StandardCharsets.UTF_8.name());
out.startDocument(null, true);
out.startTag(null, "ws"); // widget state
- out.attribute(null, "version", String.valueOf(WIDGET_STATE_VERSION));
+ out.attributeInt(null, "version", WIDGET_STATE_VERSION);
out.attribute(null, "pkg", backedupPackage);
// Remember all the providers that are currently hosted or published
@@ -4464,7 +4448,7 @@ class AppWidgetServiceImpl extends IAppWidgetService.Stub implements WidgetBacku
// Hosts mentioned in the widget dataset by ordinal
ArrayList<Host> restoredHosts = new ArrayList<>();
- XmlPullParser parser = Xml.newPullParser();
+ TypedXmlPullParser parser = Xml.newFastPullParser();
parser.setInput(stream, StandardCharsets.UTF_8.name());
synchronized (mLock) {
@@ -4474,11 +4458,9 @@ class AppWidgetServiceImpl extends IAppWidgetService.Stub implements WidgetBacku
if (type == XmlPullParser.START_TAG) {
final String tag = parser.getName();
if ("ws".equals(tag)) {
- String version = parser.getAttributeValue(null, "version");
-
- final int versionNumber = Integer.parseInt(version);
+ final int versionNumber = parser.getAttributeInt(null, "version");
if (versionNumber > WIDGET_STATE_VERSION) {
- Slog.w(TAG, "Unable to process state version " + version);
+ Slog.w(TAG, "Unable to process state version " + versionNumber);
return;
}
@@ -4520,8 +4502,7 @@ class AppWidgetServiceImpl extends IAppWidgetService.Stub implements WidgetBacku
String pkg = parser.getAttributeValue(null, "pkg");
final int uid = getUidForPackage(pkg, userId);
- final int hostId = Integer.parseInt(
- parser.getAttributeValue(null, "id"), 16);
+ final int hostId = parser.getAttributeIntHex(null, "id");
HostId id = new HostId(uid, hostId, pkg);
Host h = lookupOrAddHostLocked(id);
@@ -4532,17 +4513,14 @@ class AppWidgetServiceImpl extends IAppWidgetService.Stub implements WidgetBacku
+ "]: {" + h.id + "}");
}
} else if ("g".equals(tag)) {
- int restoredId = Integer.parseInt(
- parser.getAttributeValue(null, "id"), 16);
- int hostIndex = Integer.parseInt(
- parser.getAttributeValue(null, "h"), 16);
+ int restoredId = parser.getAttributeIntHex(null, "id");
+ int hostIndex = parser.getAttributeIntHex(null, "h");
Host host = restoredHosts.get(hostIndex);
Provider p = null;
- String prov = parser.getAttributeValue(null, "p");
- if (prov != null) {
+ int which = parser.getAttributeIntHex(null, "p", -1);
+ if (which != -1) {
// could have been null if the app had allocated an id
// but not yet established a binding under that id
- int which = Integer.parseInt(prov, 16);
p = restoredProviders.get(which);
}
diff --git a/services/art-profile b/services/art-profile
index 23a2e16bdb5d..287e6094bfe0 100644
--- a/services/art-profile
+++ b/services/art-profile
@@ -32073,6 +32073,32 @@ PLcom/android/server/wm/AccessibilityController;->removeObserverOfEmbeddedDispla
PLcom/android/server/wm/AccessibilityController;->setMagnificationCallbacksLocked(ILcom/android/server/wm/WindowManagerInternal$MagnificationCallbacks;)Z
PLcom/android/server/wm/AccessibilityController;->setMagnificationSpecLocked(ILandroid/view/MagnificationSpec;)V
PLcom/android/server/wm/AccessibilityController;->setWindowsForAccessibilityCallbackLocked(ILcom/android/server/wm/WindowManagerInternal$WindowsForAccessibilityCallback;)Z
+HPLcom/android/server/wm/ActivityClientController;->activityDestroyed(Landroid/os/IBinder;)V
+HPLcom/android/server/wm/ActivityClientController;->activityIdle(Landroid/os/IBinder;Landroid/content/res/Configuration;Z)V
+HPLcom/android/server/wm/ActivityClientController;->activityPaused(Landroid/os/IBinder;)V
+PLcom/android/server/wm/ActivityClientController;->activityRelaunched(Landroid/os/IBinder;)V
+HPLcom/android/server/wm/ActivityClientController;->activityResumed(Landroid/os/IBinder;)V
+HPLcom/android/server/wm/ActivityClientController;->activityStopped(Landroid/os/IBinder;Landroid/os/Bundle;Landroid/os/PersistableBundle;Ljava/lang/CharSequence;)V
+HPLcom/android/server/wm/ActivityClientController;->activityTopResumedStateLost()V
+PLcom/android/server/wm/ActivityClientController;->ensureValidPictureInPictureActivityParamsLocked(Ljava/lang/String;Landroid/os/IBinder;Landroid/app/PictureInPictureParams;)Lcom/android/server/wm/ActivityRecord;
+PLcom/android/server/wm/ActivityClientController;->enterPictureInPictureMode(Landroid/os/IBinder;Landroid/app/PictureInPictureParams;)Z
+HPLcom/android/server/wm/ActivityClientController;->getActivityOptions(Landroid/os/IBinder;)Landroid/os/Bundle;
+PLcom/android/server/wm/ActivityClientController;->getCallingRecord(Landroid/os/IBinder;)Lcom/android/server/wm/ActivityRecord;
+PLcom/android/server/wm/ActivityClientController;->isTopOfTask(Landroid/os/IBinder;)Z
+PLcom/android/server/wm/ActivityClientController;->moveActivityTaskToBack(Landroid/os/IBinder;Z)Z
+PLcom/android/server/wm/ActivityClientController;->navigateUpTo(Landroid/os/IBinder;Landroid/content/Intent;ILandroid/content/Intent;)Z
+HPLcom/android/server/wm/ActivityClientController;->notifyActivityDrawn(Landroid/os/IBinder;)V
+HPLcom/android/server/wm/ActivityClientController;->onBackPressedOnTaskRoot(Landroid/os/IBinder;)V
+PLcom/android/server/wm/ActivityClientController;->overridePendingTransition(Landroid/os/IBinder;Ljava/lang/String;II)V
+PLcom/android/server/wm/ActivityClientController;->registerRemoteAnimations(Landroid/os/IBinder;Landroid/view/RemoteAnimationDefinition;)V
+PLcom/android/server/wm/ActivityClientController;->releaseActivityInstance(Landroid/os/IBinder;)Z
+PLcom/android/server/wm/ActivityClientController;->reportActivityFullyDrawn(Landroid/os/IBinder;Z)V
+HPLcom/android/server/wm/ActivityClientController;->reportSizeConfigurations(Landroid/os/IBinder;[I[I[I)V
+PLcom/android/server/wm/ActivityClientController;->setDisablePreviewScreenshots(Landroid/os/IBinder;Z)V
+PLcom/android/server/wm/ActivityClientController;->setShowWhenLocked(Landroid/os/IBinder;Z)V
+HPLcom/android/server/wm/ActivityClientController;->setTaskDescription(Landroid/os/IBinder;Landroid/app/ActivityManager$TaskDescription;)V
+PLcom/android/server/wm/ActivityClientController;->setTurnScreenOn(Landroid/os/IBinder;Z)V
+PLcom/android/server/wm/ActivityClientController;->unregisterRemoteAnimations(Landroid/os/IBinder;)V
HSPLcom/android/server/wm/ActivityMetricsLogger$LaunchingState;-><init>()V
HSPLcom/android/server/wm/ActivityMetricsLogger$LaunchingState;->access$000(Lcom/android/server/wm/ActivityMetricsLogger$LaunchingState;)J
HSPLcom/android/server/wm/ActivityMetricsLogger$LaunchingState;->access$002(Lcom/android/server/wm/ActivityMetricsLogger$LaunchingState;J)J
@@ -32859,13 +32885,6 @@ HSPLcom/android/server/wm/ActivityTaskManagerService;->access$300(Lcom/android/s
HSPLcom/android/server/wm/ActivityTaskManagerService;->access$602(Lcom/android/server/wm/ActivityTaskManagerService;Lcom/android/server/wm/BackgroundActivityStartCallback;)Lcom/android/server/wm/BackgroundActivityStartCallback;
PLcom/android/server/wm/ActivityTaskManagerService;->access$802(Lcom/android/server/wm/ActivityTaskManagerService;Z)Z
HSPLcom/android/server/wm/ActivityTaskManagerService;->access$900(Lcom/android/server/wm/ActivityTaskManagerService;)Z
-HPLcom/android/server/wm/ActivityTaskManagerService;->activityDestroyed(Landroid/os/IBinder;)V
-HPLcom/android/server/wm/ActivityTaskManagerService;->activityIdle(Landroid/os/IBinder;Landroid/content/res/Configuration;Z)V
-HPLcom/android/server/wm/ActivityTaskManagerService;->activityPaused(Landroid/os/IBinder;)V
-PLcom/android/server/wm/ActivityTaskManagerService;->activityRelaunched(Landroid/os/IBinder;)V
-HPLcom/android/server/wm/ActivityTaskManagerService;->activityResumed(Landroid/os/IBinder;)V
-HPLcom/android/server/wm/ActivityTaskManagerService;->activityStopped(Landroid/os/IBinder;Landroid/os/Bundle;Landroid/os/PersistableBundle;Ljava/lang/CharSequence;)V
-HPLcom/android/server/wm/ActivityTaskManagerService;->activityTopResumedStateLost()V
HSPLcom/android/server/wm/ActivityTaskManagerService;->addWindowLayoutReasons(I)V
HPLcom/android/server/wm/ActivityTaskManagerService;->applyUpdateLockStateLocked(Lcom/android/server/wm/ActivityRecord;)V
HPLcom/android/server/wm/ActivityTaskManagerService;->applyUpdateVrModeLocked(Lcom/android/server/wm/ActivityRecord;)V
@@ -32898,8 +32917,6 @@ HPLcom/android/server/wm/ActivityTaskManagerService;->enforceNotIsolatedCaller(L
HPLcom/android/server/wm/ActivityTaskManagerService;->enforceTaskPermission(Ljava/lang/String;)V
PLcom/android/server/wm/ActivityTaskManagerService;->enqueueAssistContext(ILandroid/content/Intent;Ljava/lang/String;Landroid/app/IAssistDataReceiver;Landroid/os/Bundle;Landroid/os/IBinder;ZZILandroid/os/Bundle;JI)Lcom/android/server/wm/ActivityTaskManagerService$PendingAssistExtras;
HSPLcom/android/server/wm/ActivityTaskManagerService;->ensureConfigAndVisibilityAfterUpdate(Lcom/android/server/wm/ActivityRecord;I)Z
-PLcom/android/server/wm/ActivityTaskManagerService;->ensureValidPictureInPictureActivityParamsLocked(Ljava/lang/String;Landroid/os/IBinder;Landroid/app/PictureInPictureParams;)Lcom/android/server/wm/ActivityRecord;
-PLcom/android/server/wm/ActivityTaskManagerService;->enterPictureInPictureMode(Landroid/os/IBinder;Landroid/app/PictureInPictureParams;)Z
PLcom/android/server/wm/ActivityTaskManagerService;->enterPictureInPictureMode(Lcom/android/server/wm/ActivityRecord;Landroid/app/PictureInPictureParams;)Z
PLcom/android/server/wm/ActivityTaskManagerService;->expireStartAsCallerTokenMsg(Landroid/os/IBinder;)V
HPLcom/android/server/wm/ActivityTaskManagerService;->finishActivity(Landroid/os/IBinder;ILandroid/content/Intent;I)Z
@@ -32909,7 +32926,6 @@ PLcom/android/server/wm/ActivityTaskManagerService;->finishSubActivity(Landroid/
PLcom/android/server/wm/ActivityTaskManagerService;->finishVoiceTask(Landroid/service/voice/IVoiceInteractionSession;)V
PLcom/android/server/wm/ActivityTaskManagerService;->forgetStartAsCallerTokenMsg(Landroid/os/IBinder;)V
PLcom/android/server/wm/ActivityTaskManagerService;->getActivityClassForToken(Landroid/os/IBinder;)Landroid/content/ComponentName;
-HPLcom/android/server/wm/ActivityTaskManagerService;->getActivityOptions(Landroid/os/IBinder;)Landroid/os/Bundle;
HSPLcom/android/server/wm/ActivityTaskManagerService;->getActivityStartController()Lcom/android/server/wm/ActivityStartController;
PLcom/android/server/wm/ActivityTaskManagerService;->getAllRootTaskInfosOnDisplay(I)Ljava/util/List;
HSPLcom/android/server/wm/ActivityTaskManagerService;->getAppInfoForUser(Landroid/content/pm/ApplicationInfo;I)Landroid/content/pm/ApplicationInfo;
@@ -32919,7 +32935,6 @@ HPLcom/android/server/wm/ActivityTaskManagerService;->getAppWarningsLocked()Lcom
HSPLcom/android/server/wm/ActivityTaskManagerService;->getBackgroundActivityStartCallback()Lcom/android/server/wm/BackgroundActivityStartCallback;
PLcom/android/server/wm/ActivityTaskManagerService;->getCallingActivity(Landroid/os/IBinder;)Landroid/content/ComponentName;
PLcom/android/server/wm/ActivityTaskManagerService;->getCallingPackage(Landroid/os/IBinder;)Ljava/lang/String;
-PLcom/android/server/wm/ActivityTaskManagerService;->getCallingRecordLocked(Landroid/os/IBinder;)Lcom/android/server/wm/ActivityRecord;
PLcom/android/server/wm/ActivityTaskManagerService;->getConfiguration()Landroid/content/res/Configuration;
PLcom/android/server/wm/ActivityTaskManagerService;->getCurrentUserId()I
HPLcom/android/server/wm/ActivityTaskManagerService;->getDeviceConfigurationInfo()Landroid/content/pm/ConfigurationInfo;
@@ -32984,7 +32999,6 @@ PLcom/android/server/wm/ActivityTaskManagerService;->isKeyguardLocked()Z
HPLcom/android/server/wm/ActivityTaskManagerService;->isSameApp(ILjava/lang/String;)Z
HSPLcom/android/server/wm/ActivityTaskManagerService;->isSleepingLocked()Z
HPLcom/android/server/wm/ActivityTaskManagerService;->isSleepingOrShuttingDownLocked()Z
-PLcom/android/server/wm/ActivityTaskManagerService;->isTopOfTask(Landroid/os/IBinder;)Z
HPLcom/android/server/wm/ActivityTaskManagerService;->isUidForeground(I)Z
HPLcom/android/server/wm/ActivityTaskManagerService;->keyguardGoingAway(I)V
PLcom/android/server/wm/ActivityTaskManagerService;->lambda$4YLTqMi21jZ51BFcKX_h_gIoeGg(Lcom/android/server/wm/ActivityTaskManagerService;Ljava/util/Locale;)V
@@ -33000,33 +33014,22 @@ HPLcom/android/server/wm/ActivityTaskManagerService;->lambda$setLockScreenShown$
PLcom/android/server/wm/ActivityTaskManagerService;->lambda$tPFRgtovnZu_2Zm4sCcLa9-oBto(Lcom/android/server/wm/ActivityTaskManagerService;Landroid/os/IBinder;)V
PLcom/android/server/wm/ActivityTaskManagerService;->lambda$uDPnzqVuuoVSFA7RJcXFWsrCwrY(Lcom/android/server/wm/ActivityTaskManagerService;ILandroid/content/res/Configuration;)V
PLcom/android/server/wm/ActivityTaskManagerService;->logAppTooSlow(Lcom/android/server/wm/WindowProcessController;JLjava/lang/String;)V
-PLcom/android/server/wm/ActivityTaskManagerService;->moveActivityTaskToBack(Landroid/os/IBinder;Z)Z
PLcom/android/server/wm/ActivityTaskManagerService;->moveTaskToFrontLocked(Landroid/app/IApplicationThread;Ljava/lang/String;IILcom/android/server/wm/SafeActivityOptions;)V
-PLcom/android/server/wm/ActivityTaskManagerService;->navigateUpTo(Landroid/os/IBinder;Landroid/content/Intent;ILandroid/content/Intent;)Z
-HPLcom/android/server/wm/ActivityTaskManagerService;->notifyActivityDrawn(Landroid/os/IBinder;)V
-HSPLcom/android/server/wm/ActivityTaskManagerService;->notifyEnterAnimationComplete(Landroid/os/IBinder;)V
-PLcom/android/server/wm/ActivityTaskManagerService;->notifyLaunchTaskBehindComplete(Landroid/os/IBinder;)V
PLcom/android/server/wm/ActivityTaskManagerService;->notifyTaskPersisterLocked(Lcom/android/server/wm/Task;Z)V
HSPLcom/android/server/wm/ActivityTaskManagerService;->onActivityManagerInternalAdded()V
-HPLcom/android/server/wm/ActivityTaskManagerService;->onBackPressedOnTaskRoot(Landroid/os/IBinder;)V
HSPLcom/android/server/wm/ActivityTaskManagerService;->onInitPowerManagement()V
HPLcom/android/server/wm/ActivityTaskManagerService;->onScreenAwakeChanged(Z)V
HSPLcom/android/server/wm/ActivityTaskManagerService;->onStartActivitySetDidAppSwitch()V
HSPLcom/android/server/wm/ActivityTaskManagerService;->onSystemReady()V
-PLcom/android/server/wm/ActivityTaskManagerService;->overridePendingTransition(Landroid/os/IBinder;Ljava/lang/String;II)V
PLcom/android/server/wm/ActivityTaskManagerService;->pendingAssistExtrasTimedOut(Lcom/android/server/wm/ActivityTaskManagerService$PendingAssistExtras;)V
PLcom/android/server/wm/ActivityTaskManagerService;->postFinishBooting(ZZ)V
PLcom/android/server/wm/ActivityTaskManagerService;->registerRemoteAnimationForNextActivityStart(Ljava/lang/String;Landroid/view/RemoteAnimationAdapter;)V
-PLcom/android/server/wm/ActivityTaskManagerService;->registerRemoteAnimations(Landroid/os/IBinder;Landroid/view/RemoteAnimationDefinition;)V
HPLcom/android/server/wm/ActivityTaskManagerService;->registerTaskStackListener(Landroid/app/ITaskStackListener;)V
PLcom/android/server/wm/ActivityTaskManagerService;->relaunchReasonToString(I)Ljava/lang/String;
-PLcom/android/server/wm/ActivityTaskManagerService;->releaseActivityInstance(Landroid/os/IBinder;)Z
PLcom/android/server/wm/ActivityTaskManagerService;->releaseSomeActivities(Landroid/app/IApplicationThread;)V
PLcom/android/server/wm/ActivityTaskManagerService;->removeRootTasksInWindowingModes([I)V
PLcom/android/server/wm/ActivityTaskManagerService;->removeTask(I)Z
-PLcom/android/server/wm/ActivityTaskManagerService;->reportActivityFullyDrawn(Landroid/os/IBinder;Z)V
PLcom/android/server/wm/ActivityTaskManagerService;->reportAssistContextExtras(Landroid/os/IBinder;Landroid/os/Bundle;Landroid/app/assist/AssistStructure;Landroid/app/assist/AssistContent;Landroid/net/Uri;)V
-HPLcom/android/server/wm/ActivityTaskManagerService;->reportSizeConfigurations(Landroid/os/IBinder;[I[I[I)V
PLcom/android/server/wm/ActivityTaskManagerService;->requestAssistContextExtras(ILandroid/app/IAssistDataReceiver;Landroid/os/Bundle;Landroid/os/IBinder;ZZ)Z
PLcom/android/server/wm/ActivityTaskManagerService;->requestAutofillData(Landroid/app/IAssistDataReceiver;Landroid/os/Bundle;Landroid/os/IBinder;I)Z
PLcom/android/server/wm/ActivityTaskManagerService;->requestStartActivityPermissionToken(Landroid/os/IBinder;)Landroid/os/IBinder;
@@ -33039,7 +33042,6 @@ PLcom/android/server/wm/ActivityTaskManagerService;->sendPutConfigurationForUser
PLcom/android/server/wm/ActivityTaskManagerService;->setBooted(Z)V
PLcom/android/server/wm/ActivityTaskManagerService;->setBooting(Z)V
HSPLcom/android/server/wm/ActivityTaskManagerService;->setDeviceOwnerUid(I)V
-PLcom/android/server/wm/ActivityTaskManagerService;->setDisablePreviewScreenshots(Landroid/os/IBinder;Z)V
PLcom/android/server/wm/ActivityTaskManagerService;->setFocusedTask(I)V
PLcom/android/server/wm/ActivityTaskManagerService;->setImmersive(Landroid/os/IBinder;Z)V
HPLcom/android/server/wm/ActivityTaskManagerService;->setLockScreenShown(ZZ)V
@@ -33047,10 +33049,7 @@ PLcom/android/server/wm/ActivityTaskManagerService;->setPictureInPictureParams(L
HSPLcom/android/server/wm/ActivityTaskManagerService;->setRecentTasks(Lcom/android/server/wm/RecentTasks;)V
PLcom/android/server/wm/ActivityTaskManagerService;->setRequestedOrientation(Landroid/os/IBinder;I)V
HPLcom/android/server/wm/ActivityTaskManagerService;->setResumedActivityUncheckLocked(Lcom/android/server/wm/ActivityRecord;Ljava/lang/String;)V
-PLcom/android/server/wm/ActivityTaskManagerService;->setShowWhenLocked(Landroid/os/IBinder;Z)V
PLcom/android/server/wm/ActivityTaskManagerService;->setSplitScreenResizing(Z)V
-HPLcom/android/server/wm/ActivityTaskManagerService;->setTaskDescription(Landroid/os/IBinder;Landroid/app/ActivityManager$TaskDescription;)V
-PLcom/android/server/wm/ActivityTaskManagerService;->setTurnScreenOn(Landroid/os/IBinder;Z)V
HSPLcom/android/server/wm/ActivityTaskManagerService;->setUsageStatsManager(Landroid/app/usage/UsageStatsManagerInternal;)V
HSPLcom/android/server/wm/ActivityTaskManagerService;->setWindowManager(Lcom/android/server/wm/WindowManagerService;)V
PLcom/android/server/wm/ActivityTaskManagerService;->shouldDisableNonVrUiLocked()Z
@@ -33070,7 +33069,6 @@ HPLcom/android/server/wm/ActivityTaskManagerService;->startTimeTrackingFocusedAc
PLcom/android/server/wm/ActivityTaskManagerService;->stopAppSwitches()V
PLcom/android/server/wm/ActivityTaskManagerService;->stopLockTaskModeInternal(Landroid/os/IBinder;Z)V
PLcom/android/server/wm/ActivityTaskManagerService;->stopSystemLockTaskMode()V
-PLcom/android/server/wm/ActivityTaskManagerService;->unregisterRemoteAnimations(Landroid/os/IBinder;)V
HPLcom/android/server/wm/ActivityTaskManagerService;->unregisterTaskStackListener(Landroid/app/ITaskStackListener;)V
HPLcom/android/server/wm/ActivityTaskManagerService;->updateActivityUsageStats(Lcom/android/server/wm/ActivityRecord;I)V
HPLcom/android/server/wm/ActivityTaskManagerService;->updateBatteryStats(Lcom/android/server/wm/ActivityRecord;Z)V
diff --git a/services/core/java/com/android/server/ConnectivityService.java b/services/core/java/com/android/server/ConnectivityService.java
index 22134e5b408a..ee9d49244d7e 100644
--- a/services/core/java/com/android/server/ConnectivityService.java
+++ b/services/core/java/com/android/server/ConnectivityService.java
@@ -8200,8 +8200,10 @@ public class ConnectivityService extends IConnectivityManager.Stub
final NetworkRequestInfo nri = cbInfo.mRequestInfo;
- if (uid != nri.mUid) {
- if (VDBG) loge("Different uid than registrant attempting to unregister cb");
+ // Caller's UID must either be the registrants (if they are unregistering) or the System's
+ // (if the Binder died)
+ if (uid != nri.mUid && uid != Process.SYSTEM_UID) {
+ if (DBG) loge("Uid(" + uid + ") not registrant's (" + nri.mUid + ") or System's");
return;
}
diff --git a/services/core/java/com/android/server/PackageWatchdog.java b/services/core/java/com/android/server/PackageWatchdog.java
index 9bf63cbbb25e..99a1d86d244e 100644
--- a/services/core/java/com/android/server/PackageWatchdog.java
+++ b/services/core/java/com/android/server/PackageWatchdog.java
@@ -52,9 +52,7 @@ import com.android.internal.util.XmlUtils;
import libcore.io.IoUtils;
-import org.xmlpull.v1.XmlPullParser;
import org.xmlpull.v1.XmlPullParserException;
-import org.xmlpull.v1.XmlSerializer;
import java.io.File;
import java.io.FileNotFoundException;
@@ -149,6 +147,7 @@ public class PackageWatchdog {
private static final String ATTR_DURATION = "duration";
private static final String ATTR_EXPLICIT_HEALTH_CHECK_DURATION = "health-check-duration";
private static final String ATTR_PASSED_HEALTH_CHECK = "passed-health-check";
+ private static final String ATTR_MITIGATION_CALLS = "mitigation-calls";
@GuardedBy("PackageWatchdog.class")
private static PackageWatchdog sPackageWatchdog;
@@ -779,7 +778,6 @@ public class PackageWatchdog {
@GuardedBy("mLock")
private Set<String> getPackagesPendingHealthChecksLocked() {
- Slog.d(TAG, "Getting all observed packages pending health checks");
Set<String> packages = new ArraySet<>();
Iterator<ObserverInternal> oit = mAllObservers.values().iterator();
while (oit.hasNext()) {
@@ -828,7 +826,6 @@ public class PackageWatchdog {
Slog.i(TAG, "Cancelling state sync, nothing to sync");
mUptimeAtLastStateSync = 0;
} else {
- Slog.i(TAG, "Scheduling next state sync in " + durationMs + "ms");
mUptimeAtLastStateSync = mSystemClock.uptimeMillis();
mShortTaskHandler.postDelayed(mSyncStateWithScheduledReason, durationMs);
}
@@ -869,7 +866,6 @@ public class PackageWatchdog {
return;
}
- Slog.i(TAG, "Removing " + elapsedMs + "ms from all packages on all observers");
Iterator<ObserverInternal> it = mAllObservers.values().iterator();
while (it.hasNext()) {
ObserverInternal observer = it.next();
@@ -1067,6 +1063,33 @@ public class PackageWatchdog {
}
}
+ /** Convert a {@code LongArrayQueue} to a String of comma-separated values. */
+ public static String longArrayQueueToString(LongArrayQueue queue) {
+ if (queue.size() > 0) {
+ StringBuilder sb = new StringBuilder();
+ sb.append(queue.get(0));
+ for (int i = 1; i < queue.size(); i++) {
+ sb.append(",");
+ sb.append(queue.get(i));
+ }
+ return sb.toString();
+ }
+ return "";
+ }
+
+ /** Parse a comma-separated String of longs into a LongArrayQueue. */
+ public static LongArrayQueue parseLongArrayQueue(String commaSeparatedValues) {
+ LongArrayQueue result = new LongArrayQueue();
+ if (!TextUtils.isEmpty(commaSeparatedValues)) {
+ String[] values = commaSeparatedValues.split(",");
+ for (String value : values) {
+ result.addLast(Long.parseLong(value));
+ }
+ }
+ return result;
+ }
+
+
/** Dump status of every observer in mAllObservers. */
public void dump(IndentingPrintWriter pw) {
pw.println("Package Watchdog status");
@@ -1240,16 +1263,7 @@ public class PackageWatchdog {
while (XmlUtils.nextElementWithin(parser, innerDepth)) {
if (TAG_PACKAGE.equals(parser.getName())) {
try {
- String packageName = parser.getAttributeValue(
- null, ATTR_NAME);
- long duration = parser.getAttributeLong(
- null, ATTR_DURATION);
- long healthCheckDuration = parser.getAttributeLong(
- null, ATTR_EXPLICIT_HEALTH_CHECK_DURATION);
- boolean hasPassedHealthCheck = parser.getAttributeBoolean(
- null, ATTR_PASSED_HEALTH_CHECK, false);
- MonitoredPackage pkg = watchdog.newMonitoredPackage(packageName,
- duration, healthCheckDuration, hasPassedHealthCheck);
+ MonitoredPackage pkg = watchdog.parseMonitoredPackage(parser);
if (pkg != null) {
packages.add(pkg);
}
@@ -1305,16 +1319,31 @@ public class PackageWatchdog {
MonitoredPackage newMonitoredPackage(
String name, long durationMs, boolean hasPassedHealthCheck) {
- return newMonitoredPackage(name, durationMs, Long.MAX_VALUE, hasPassedHealthCheck);
+ return newMonitoredPackage(name, durationMs, Long.MAX_VALUE, hasPassedHealthCheck,
+ new LongArrayQueue());
}
MonitoredPackage newMonitoredPackage(String name, long durationMs, long healthCheckDurationMs,
- boolean hasPassedHealthCheck) {
+ boolean hasPassedHealthCheck, LongArrayQueue mitigationCalls) {
VersionedPackage pkg = getVersionedPackage(name);
if (pkg == null) {
return null;
}
- return new MonitoredPackage(pkg, durationMs, healthCheckDurationMs, hasPassedHealthCheck);
+ return new MonitoredPackage(pkg, durationMs, healthCheckDurationMs,
+ hasPassedHealthCheck, mitigationCalls);
+ }
+
+ MonitoredPackage parseMonitoredPackage(TypedXmlPullParser parser)
+ throws XmlPullParserException {
+ String packageName = parser.getAttributeValue(null, ATTR_NAME);
+ long duration = parser.getAttributeLong(null, ATTR_DURATION);
+ long healthCheckDuration = parser.getAttributeLong(null,
+ ATTR_EXPLICIT_HEALTH_CHECK_DURATION);
+ boolean hasPassedHealthCheck = parser.getAttributeBoolean(null, ATTR_PASSED_HEALTH_CHECK);
+ LongArrayQueue mitigationCalls = parseLongArrayQueue(
+ parser.getAttributeValue(null, ATTR_MITIGATION_CALLS));
+ return newMonitoredPackage(packageName,
+ duration, healthCheckDuration, hasPassedHealthCheck, mitigationCalls);
}
/**
@@ -1332,7 +1361,7 @@ public class PackageWatchdog {
// Times when an observer was called to mitigate this package's failure. Sorted in
// ascending order.
@GuardedBy("mLock")
- private final LongArrayQueue mMitigationCalls = new LongArrayQueue();
+ private final LongArrayQueue mMitigationCalls;
// One of STATE_[ACTIVE|INACTIVE|PASSED|FAILED]. Updated on construction and after
// methods that could change the health check state: handleElapsedTimeLocked and
// tryPassHealthCheckLocked
@@ -1353,12 +1382,14 @@ public class PackageWatchdog {
@GuardedBy("mLock")
private long mHealthCheckDurationMs = Long.MAX_VALUE;
- private MonitoredPackage(VersionedPackage pkg, long durationMs,
- long healthCheckDurationMs, boolean hasPassedHealthCheck) {
+ MonitoredPackage(VersionedPackage pkg, long durationMs,
+ long healthCheckDurationMs, boolean hasPassedHealthCheck,
+ LongArrayQueue mitigationCalls) {
mPackage = pkg;
mDurationMs = durationMs;
mHealthCheckDurationMs = healthCheckDurationMs;
mHasPassedHealthCheck = hasPassedHealthCheck;
+ mMitigationCalls = mitigationCalls;
updateHealthCheckStateLocked();
}
@@ -1370,6 +1401,8 @@ public class PackageWatchdog {
out.attributeLong(null, ATTR_DURATION, mDurationMs);
out.attributeLong(null, ATTR_EXPLICIT_HEALTH_CHECK_DURATION, mHealthCheckDurationMs);
out.attributeBoolean(null, ATTR_PASSED_HEALTH_CHECK, mHasPassedHealthCheck);
+ LongArrayQueue normalizedCalls = normalizeMitigationCalls();
+ out.attribute(null, ATTR_MITIGATION_CALLS, longArrayQueueToString(normalizedCalls));
out.endTag(null, TAG_PACKAGE);
}
@@ -1423,6 +1456,23 @@ public class PackageWatchdog {
}
/**
+ * Before writing to disk, make the mitigation call timestamps relative to the current
+ * system uptime. This is because they need to be relative to the uptime which will reset
+ * at the next boot.
+ *
+ * @return a LongArrayQueue of the mitigation calls relative to the current system uptime.
+ */
+ @GuardedBy("mLock")
+ public LongArrayQueue normalizeMitigationCalls() {
+ LongArrayQueue normalized = new LongArrayQueue();
+ final long now = mSystemClock.uptimeMillis();
+ for (int i = 0; i < mMitigationCalls.size(); i++) {
+ normalized.addLast(mMitigationCalls.get(i) - now);
+ }
+ return normalized;
+ }
+
+ /**
* Sets the initial health check duration.
*
* @return the new health check state
@@ -1582,6 +1632,16 @@ public class PackageWatchdog {
private long toPositive(long value) {
return value > 0 ? value : Long.MAX_VALUE;
}
+
+ /** Compares the equality of this object with another {@link MonitoredPackage}. */
+ @VisibleForTesting
+ boolean isEqualTo(MonitoredPackage pkg) {
+ return (getName().equals(pkg.getName()))
+ && mDurationMs == pkg.mDurationMs
+ && mHasPassedHealthCheck == pkg.mHasPassedHealthCheck
+ && mHealthCheckDurationMs == pkg.mHealthCheckDurationMs
+ && (mMitigationCalls.toString()).equals(pkg.mMitigationCalls.toString());
+ }
}
/**
diff --git a/services/core/java/com/android/server/SensorPrivacyService.java b/services/core/java/com/android/server/SensorPrivacyService.java
index d30e9fb002e0..51e2b12bcee4 100644
--- a/services/core/java/com/android/server/SensorPrivacyService.java
+++ b/services/core/java/com/android/server/SensorPrivacyService.java
@@ -158,7 +158,7 @@ public final class SensorPrivacyService extends SystemService {
XmlUtils.beginDocument(parser, XML_TAG_SENSOR_PRIVACY);
parser.next();
String tagName = parser.getName();
- enabled = Boolean.valueOf(parser.getAttributeValue(null, XML_ATTRIBUTE_ENABLED));
+ enabled = parser.getAttributeBoolean(null, XML_ATTRIBUTE_ENABLED, false);
} catch (IOException | XmlPullParserException e) {
Log.e(TAG, "Caught an exception reading the state from storage: ", e);
// Delete the file to prevent the same error on subsequent calls and assume sensor
diff --git a/services/core/java/com/android/server/accounts/AccountAuthenticatorCache.java b/services/core/java/com/android/server/accounts/AccountAuthenticatorCache.java
index b9453db8eb0a..725bccf76bb9 100644
--- a/services/core/java/com/android/server/accounts/AccountAuthenticatorCache.java
+++ b/services/core/java/com/android/server/accounts/AccountAuthenticatorCache.java
@@ -27,10 +27,10 @@ import android.content.res.Resources;
import android.content.res.TypedArray;
import android.text.TextUtils;
import android.util.AttributeSet;
+import android.util.TypedXmlPullParser;
+import android.util.TypedXmlSerializer;
-import org.xmlpull.v1.XmlPullParser;
import org.xmlpull.v1.XmlPullParserException;
-import org.xmlpull.v1.XmlSerializer;
import java.io.IOException;
@@ -83,13 +83,13 @@ import java.io.IOException;
private static class MySerializer implements XmlSerializerAndParser<AuthenticatorDescription> {
@Override
- public void writeAsXml(AuthenticatorDescription item, XmlSerializer out)
+ public void writeAsXml(AuthenticatorDescription item, TypedXmlSerializer out)
throws IOException {
out.attribute(null, "type", item.type);
}
@Override
- public AuthenticatorDescription createFromXml(XmlPullParser parser)
+ public AuthenticatorDescription createFromXml(TypedXmlPullParser parser)
throws IOException, XmlPullParserException {
return AuthenticatorDescription.newKey(parser.getAttributeValue(null, "type"));
}
diff --git a/services/core/java/com/android/server/adb/AdbDebuggingManager.java b/services/core/java/com/android/server/adb/AdbDebuggingManager.java
index d99b195351f1..1f35b88c8cbd 100644
--- a/services/core/java/com/android/server/adb/AdbDebuggingManager.java
+++ b/services/core/java/com/android/server/adb/AdbDebuggingManager.java
@@ -71,7 +71,6 @@ import android.util.Xml;
import com.android.internal.R;
import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.messages.nano.SystemMessageProto.SystemMessage;
-import com.android.internal.util.FastXmlSerializer;
import com.android.internal.util.FrameworkStatsLog;
import com.android.internal.util.XmlUtils;
import com.android.internal.util.dump.DualDumpOutputStream;
@@ -79,7 +78,6 @@ import com.android.server.FgThread;
import org.xmlpull.v1.XmlPullParser;
import org.xmlpull.v1.XmlPullParserException;
-import org.xmlpull.v1.XmlSerializer;
import java.io.BufferedReader;
import java.io.File;
@@ -89,7 +87,6 @@ import java.io.FileReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
-import java.nio.charset.StandardCharsets;
import java.security.MessageDigest;
import java.security.SecureRandom;
import java.util.AbstractMap;
@@ -1757,21 +1754,21 @@ public class AdbDebuggingManager {
dump.write("user_keys", AdbDebuggingManagerProto.USER_KEYS,
FileUtils.readTextFile(new File("/data/misc/adb/adb_keys"), 0, null));
} catch (IOException e) {
- Slog.e(TAG, "Cannot read user keys", e);
+ Slog.i(TAG, "Cannot read user keys", e);
}
try {
dump.write("system_keys", AdbDebuggingManagerProto.SYSTEM_KEYS,
FileUtils.readTextFile(new File("/adb_keys"), 0, null));
} catch (IOException e) {
- Slog.e(TAG, "Cannot read system keys", e);
+ Slog.i(TAG, "Cannot read system keys", e);
}
try {
dump.write("keystore", AdbDebuggingManagerProto.KEYSTORE,
FileUtils.readTextFile(getAdbTempKeysFile(), 0, null));
} catch (IOException e) {
- Slog.e(TAG, "Cannot read keystore: ", e);
+ Slog.i(TAG, "Cannot read keystore: ", e);
}
dump.end(token);
@@ -1966,9 +1963,9 @@ public class AdbDebuggingManager {
String key = parser.getAttributeValue(null, XML_ATTRIBUTE_KEY);
long connectionTime;
try {
- connectionTime = Long.valueOf(
- parser.getAttributeValue(null, XML_ATTRIBUTE_LAST_CONNECTION));
- } catch (NumberFormatException e) {
+ connectionTime = parser.getAttributeLong(null,
+ XML_ATTRIBUTE_LAST_CONNECTION);
+ } catch (XmlPullParserException e) {
Slog.e(TAG,
"Caught a NumberFormatException parsing the last connection time: "
+ e);
@@ -2020,9 +2017,9 @@ public class AdbDebuggingManager {
String key = parser.getAttributeValue(null, XML_ATTRIBUTE_KEY);
long connectionTime;
try {
- connectionTime = Long.valueOf(
- parser.getAttributeValue(null, XML_ATTRIBUTE_LAST_CONNECTION));
- } catch (NumberFormatException e) {
+ connectionTime = parser.getAttributeLong(null,
+ XML_ATTRIBUTE_LAST_CONNECTION);
+ } catch (XmlPullParserException e) {
Slog.e(TAG,
"Caught a NumberFormatException parsing the last connection time: "
+ e);
@@ -2150,8 +2147,8 @@ public class AdbDebuggingManager {
for (Map.Entry<String, Long> keyEntry : mKeyMap.entrySet()) {
serializer.startTag(null, XML_TAG_ADB_KEY);
serializer.attribute(null, XML_ATTRIBUTE_KEY, keyEntry.getKey());
- serializer.attribute(null, XML_ATTRIBUTE_LAST_CONNECTION,
- String.valueOf(keyEntry.getValue()));
+ serializer.attributeLong(null, XML_ATTRIBUTE_LAST_CONNECTION,
+ keyEntry.getValue());
serializer.endTag(null, XML_TAG_ADB_KEY);
}
for (String bssid : mTrustedNetworks) {
diff --git a/services/core/java/com/android/server/am/ActivityManagerService.java b/services/core/java/com/android/server/am/ActivityManagerService.java
index 63128ced8f93..bcd122d33f7d 100644
--- a/services/core/java/com/android/server/am/ActivityManagerService.java
+++ b/services/core/java/com/android/server/am/ActivityManagerService.java
@@ -265,7 +265,6 @@ import android.os.UserManager;
import android.os.WorkSource;
import android.os.storage.IStorageManager;
import android.os.storage.StorageManager;
-import android.permission.PermissionManagerInternal.CheckPermissionDelegate;
import android.provider.DeviceConfig;
import android.provider.Settings;
import android.server.ServerProtoEnums;
@@ -326,7 +325,6 @@ import com.android.internal.util.MemInfoReader;
import com.android.internal.util.Preconditions;
import com.android.internal.util.function.HeptFunction;
import com.android.internal.util.function.QuadFunction;
-import com.android.internal.util.function.TriFunction;
import com.android.server.AlarmManagerInternal;
import com.android.server.AttributeCache;
import com.android.server.DeviceIdleInternal;
@@ -394,7 +392,6 @@ import java.util.Locale;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.Executor;
-import java.util.function.BiFunction;
public class ActivityManagerService extends IActivityManager.Stub
implements Watchdog.Monitor, BatteryStatsImpl.BatteryCallback {
@@ -14486,7 +14483,7 @@ public class ActivityManagerService extends IActivityManager.Stub
mAppOpsService.setMode(AppOpsManager.OP_NO_ISOLATED_STORAGE, app.uid,
app.info.packageName, AppOpsManager.MODE_ERRORED);
mAppOpsService.setAppOpsServiceDelegate(null);
- getPermissionManagerInternalLocked().setCheckPermissionDelegate(null);
+ getPermissionManagerInternalLocked().stopShellPermissionIdentityDelegation();
mHandler.obtainMessage(SHUTDOWN_UI_AUTOMATION_CONNECTION_MSG,
instr.mUiAutomationConnection).sendToTarget();
}
@@ -17201,12 +17198,6 @@ public class ActivityManagerService extends IActivityManager.Stub
// We allow delegation only to one instrumentation started from the shell
synchronized (ActivityManagerService.this) {
- // If there is a delegate it should be the same instance for app ops and permissions.
- if (mAppOpsService.getAppOpsServiceDelegate()
- != getPermissionManagerInternalLocked().getCheckPermissionDelegate()) {
- throw new IllegalStateException("Bad shell delegate state");
- }
-
// If the delegate is already set up for the target UID, nothing to do.
if (mAppOpsService.getAppOpsServiceDelegate() != null) {
if (!(mAppOpsService.getAppOpsServiceDelegate() instanceof ShellDelegate)) {
@@ -17235,10 +17226,14 @@ public class ActivityManagerService extends IActivityManager.Stub
}
// Hook them up...
- final ShellDelegate shellDelegate = new ShellDelegate(
- instr.mTargetInfo.packageName, delegateUid, permissions);
+ final ShellDelegate shellDelegate = new ShellDelegate(delegateUid,
+ permissions);
mAppOpsService.setAppOpsServiceDelegate(shellDelegate);
- getPermissionManagerInternalLocked().setCheckPermissionDelegate(shellDelegate);
+ final String packageName = instr.mTargetInfo.packageName;
+ final List<String> permissionNames = permissions != null ?
+ Arrays.asList(permissions) : null;
+ getPermissionManagerInternalLocked().startShellPermissionIdentityDelegation(
+ delegateUid, packageName, permissionNames);
return;
}
}
@@ -17252,17 +17247,15 @@ public class ActivityManagerService extends IActivityManager.Stub
}
synchronized (ActivityManagerService.this) {
mAppOpsService.setAppOpsServiceDelegate(null);
- getPermissionManagerInternalLocked().setCheckPermissionDelegate(null);
+ getPermissionManagerInternalLocked().stopShellPermissionIdentityDelegation();
}
}
- private class ShellDelegate implements CheckOpsDelegate, CheckPermissionDelegate {
- private final String mTargetPackageName;
+ private class ShellDelegate implements CheckOpsDelegate {
private final int mTargetUid;
private @Nullable String[] mPermissions;
- ShellDelegate(String targetPackageName, int targetUid, @Nullable String[] permissions) {
- mTargetPackageName = targetPackageName;
+ ShellDelegate(int targetUid, @Nullable String[] permissions) {
mTargetUid = targetUid;
mPermissions = permissions;
}
@@ -17325,34 +17318,6 @@ public class ActivityManagerService extends IActivityManager.Stub
message, shouldCollectMessage);
}
- @Override
- public int checkPermission(String permName, String pkgName, int userId,
- TriFunction<String, String, Integer, Integer> superImpl) {
- if (mTargetPackageName.equals(pkgName) && isTargetPermission(permName)) {
- final long identity = Binder.clearCallingIdentity();
- try {
- return superImpl.apply(permName, "com.android.shell", userId);
- } finally {
- Binder.restoreCallingIdentity(identity);
- }
- }
- return superImpl.apply(permName, pkgName, userId);
- }
-
- @Override
- public int checkUidPermission(String permName, int uid,
- BiFunction<String, Integer, Integer> superImpl) {
- if (uid == mTargetUid && isTargetPermission(permName)) {
- final long identity = Binder.clearCallingIdentity();
- try {
- return superImpl.apply(permName, Process.SHELL_UID);
- } finally {
- Binder.restoreCallingIdentity(identity);
- }
- }
- return superImpl.apply(permName, uid);
- }
-
private boolean isTargetOp(int code) {
// null permissions means all ops are targeted
if (mPermissions == null) {
diff --git a/services/core/java/com/android/server/audio/AudioService.java b/services/core/java/com/android/server/audio/AudioService.java
index 89150aee44ad..4d971a51e885 100644
--- a/services/core/java/com/android/server/audio/AudioService.java
+++ b/services/core/java/com/android/server/audio/AudioService.java
@@ -545,7 +545,6 @@ public class AudioService extends IAudioService.Stub
AudioSystem.DEVICE_OUT_DGTL_DOCK_HEADSET,
AudioSystem.DEVICE_OUT_ANLG_DOCK_HEADSET,
AudioSystem.DEVICE_OUT_HDMI_ARC,
- AudioSystem.DEVICE_OUT_SPDIF,
AudioSystem.DEVICE_OUT_AUX_LINE));
// Devices for which the volume is always max, no volume panel
Set<Integer> mFullVolumeDevices = new HashSet<>();
diff --git a/services/core/java/com/android/server/biometrics/BiometricService.java b/services/core/java/com/android/server/biometrics/BiometricService.java
index 0194259d6289..75e1938656e3 100644
--- a/services/core/java/com/android/server/biometrics/BiometricService.java
+++ b/services/core/java/com/android/server/biometrics/BiometricService.java
@@ -30,6 +30,7 @@ import android.app.admin.DevicePolicyManager;
import android.app.trust.ITrustManager;
import android.content.ContentResolver;
import android.content.Context;
+import android.content.pm.PackageManager;
import android.database.ContentObserver;
import android.hardware.biometrics.BiometricAuthenticator;
import android.hardware.biometrics.BiometricConstants;
@@ -809,12 +810,13 @@ public class BiometricService extends SystemService {
public List<FingerprintSensorPropertiesInternal> getFingerprintSensorProperties(
Context context) {
- final FingerprintManager fpm = context.getSystemService(FingerprintManager.class);
- if (fpm != null) {
- return fpm.getSensorPropertiesInternal();
- } else {
- return new ArrayList<>();
+ if (context.getPackageManager().hasSystemFeature(PackageManager.FEATURE_FINGERPRINT)) {
+ final FingerprintManager fpm = context.getSystemService(FingerprintManager.class);
+ if (fpm != null) {
+ return fpm.getSensorPropertiesInternal();
+ }
}
+ return new ArrayList<>();
}
}
diff --git a/services/core/java/com/android/server/biometrics/sensors/face/FaceService.java b/services/core/java/com/android/server/biometrics/sensors/face/FaceService.java
index 7dc2cba0b974..cb56e8cd4b7f 100644
--- a/services/core/java/com/android/server/biometrics/sensors/face/FaceService.java
+++ b/services/core/java/com/android/server/biometrics/sensors/face/FaceService.java
@@ -127,17 +127,6 @@ public class FaceService extends SystemService implements BiometricServiceCallba
return properties;
}
- @NonNull
- private List<Face> getEnrolledFaces(int userId, String opPackageName) {
- final Pair<Integer, ServiceProvider> provider = getSingleProvider();
- if (provider == null) {
- Slog.w(TAG, "Null provider for getEnrolledFaces, caller: " + opPackageName);
- return Collections.emptyList();
- }
-
- return provider.second.getEnrolledFaces(provider.first, userId);
- }
-
/**
* Receives the incoming binder calls from FaceManager.
*/
@@ -438,6 +427,7 @@ public class FaceService extends SystemService implements BiometricServiceCallba
pw.println("Dumping for sensorId: " + props.sensorId
+ ", provider: " + provider.getClass().getSimpleName());
provider.dumpInternal(props.sensorId, pw);
+ pw.println();
}
}
}
@@ -471,7 +461,13 @@ public class FaceService extends SystemService implements BiometricServiceCallba
Utils.checkPermission(getContext(), INTERACT_ACROSS_USERS);
}
- return FaceService.this.getEnrolledFaces(userId, opPackageName);
+ final ServiceProvider provider = getProviderForSensor(sensorId);
+ if (provider == null) {
+ Slog.w(TAG, "Null provider for getEnrolledFaces, caller: " + opPackageName);
+ return Collections.emptyList();
+ }
+
+ return provider.getEnrolledFaces(sensorId, userId);
}
@Override // Binder call
@@ -482,7 +478,16 @@ public class FaceService extends SystemService implements BiometricServiceCallba
Utils.checkPermission(getContext(), INTERACT_ACROSS_USERS);
}
- return !FaceService.this.getEnrolledFaces(userId, opPackageName).isEmpty();
+ final ServiceProvider provider = getProviderForSensor(sensorId);
+ if (provider == null) {
+ Slog.w(TAG, "Null provider for hasEnrolledFaces, caller: " + opPackageName);
+ return false;
+ }
+
+ final boolean enrolled = provider.getEnrolledFaces(sensorId, userId).size() > 0;
+ Slog.d(TAG, "hasEnrolledFaces, sensor: " + sensorId + ", enrolled: " + enrolled);
+
+ return provider.getEnrolledFaces(sensorId, userId).size() > 0;
}
@Override // Binder call
diff --git a/services/core/java/com/android/server/biometrics/sensors/face/FaceUtils.java b/services/core/java/com/android/server/biometrics/sensors/face/FaceUtils.java
index a0ffe58c779b..a0cd4a56ea12 100644
--- a/services/core/java/com/android/server/biometrics/sensors/face/FaceUtils.java
+++ b/services/core/java/com/android/server/biometrics/sensors/face/FaceUtils.java
@@ -72,13 +72,13 @@ public class FaceUtils implements BiometricUtils<Face> {
}
/**
- * Legacy getter for {@link android.hardware.biometrics.face.V1_0} and its extended subclasses,
- * which do not support a well defined sensorId from the HAL.
+ * Legacy getter for {@link android.hardware.biometrics.face.V1_0} and its extended subclasses.
+ * Framework-side cache is always stored in the same file, regardless of sensorId.
*/
- public static FaceUtils getInstance() {
+ public static FaceUtils getLegacyInstance(int sensorId) {
// Note that sensorId for legacy services can be hard-coded to 0 since it's only used
// to index into the sensor states map.
- return getInstance(0 /* sensorId */, LEGACY_FACE_FILE);
+ return getInstance(sensorId, LEGACY_FACE_FILE);
}
private FaceUtils(String fileName) {
diff --git a/services/core/java/com/android/server/biometrics/sensors/face/hidl/BiometricTestSessionImpl.java b/services/core/java/com/android/server/biometrics/sensors/face/hidl/BiometricTestSessionImpl.java
index 4c983fb5fa6c..9ed8f789aaa2 100644
--- a/services/core/java/com/android/server/biometrics/sensors/face/hidl/BiometricTestSessionImpl.java
+++ b/services/core/java/com/android/server/biometrics/sensors/face/hidl/BiometricTestSessionImpl.java
@@ -153,7 +153,8 @@ public class BiometricTestSessionImpl extends ITestSession.Stub {
Utils.checkPermission(mContext, TEST_BIOMETRIC);
// Fake authentication with any of the existing fingers
- List<Face> faces = FaceUtils.getInstance().getBiometricsForUser(mContext, userId);
+ List<Face> faces = FaceUtils.getLegacyInstance(mSensorId)
+ .getBiometricsForUser(mContext, userId);
if (faces.isEmpty()) {
Slog.w(TAG, "No faces, returning");
return;
diff --git a/services/core/java/com/android/server/biometrics/sensors/face/hidl/Face10.java b/services/core/java/com/android/server/biometrics/sensors/face/hidl/Face10.java
index d384bc645d61..c4e4d1fe0f82 100644
--- a/services/core/java/com/android/server/biometrics/sensors/face/hidl/Face10.java
+++ b/services/core/java/com/android/server/biometrics/sensors/face/hidl/Face10.java
@@ -166,7 +166,7 @@ public class Face10 implements IHwBinder.DeathRecipient, ServiceProvider {
@Override
public void onEnrollResult(long deviceId, int faceId, int userId, int remaining) {
mHandler.post(() -> {
- final CharSequence name = FaceUtils.getInstance()
+ final CharSequence name = FaceUtils.getLegacyInstance(mSensorId)
.getUniqueName(mContext, userId);
final Face face = new Face(name, faceId, deviceId);
@@ -471,7 +471,7 @@ public class Face10 implements IHwBinder.DeathRecipient, ServiceProvider {
@Override
@NonNull
public List<Face> getEnrolledFaces(int sensorId, int userId) {
- return FaceUtils.getInstance().getBiometricsForUser(mContext, userId);
+ return FaceUtils.getLegacyInstance(mSensorId).getBiometricsForUser(mContext, userId);
}
@Override
@@ -610,8 +610,8 @@ public class Face10 implements IHwBinder.DeathRecipient, ServiceProvider {
final FaceEnrollClient client = new FaceEnrollClient(mContext, mLazyDaemon, token,
new ClientMonitorCallbackConverter(receiver), userId, hardwareAuthToken,
- opPackageName, FaceUtils.getInstance(), disabledFeatures, ENROLL_TIMEOUT_SEC,
- surfaceHandle, mSensorId);
+ opPackageName, FaceUtils.getLegacyInstance(mSensorId), disabledFeatures,
+ ENROLL_TIMEOUT_SEC, surfaceHandle, mSensorId);
mScheduler.scheduleClientMonitor(client, new ClientMonitor.Callback() {
@Override
@@ -665,7 +665,7 @@ public class Face10 implements IHwBinder.DeathRecipient, ServiceProvider {
final FaceRemovalClient client = new FaceRemovalClient(mContext, mLazyDaemon, token,
new ClientMonitorCallbackConverter(receiver), faceId, userId, opPackageName,
- FaceUtils.getInstance(), mSensorId, mAuthenticatorIds);
+ FaceUtils.getLegacyInstance(mSensorId), mSensorId, mAuthenticatorIds);
mScheduler.scheduleClientMonitor(client);
});
}
@@ -748,7 +748,7 @@ public class Face10 implements IHwBinder.DeathRecipient, ServiceProvider {
final List<Face> enrolledList = getEnrolledFaces(mSensorId, userId);
final FaceInternalCleanupClient client = new FaceInternalCleanupClient(mContext,
mLazyDaemon, userId, mContext.getOpPackageName(), mSensorId, enrolledList,
- FaceUtils.getInstance(), mAuthenticatorIds);
+ FaceUtils.getLegacyInstance(mSensorId), mAuthenticatorIds);
mScheduler.scheduleClientMonitor(client);
});
}
@@ -777,7 +777,7 @@ public class Face10 implements IHwBinder.DeathRecipient, ServiceProvider {
final long userToken = proto.start(SensorStateProto.USER_STATES);
proto.write(UserStateProto.USER_ID, userId);
- proto.write(UserStateProto.NUM_ENROLLED, FaceUtils.getInstance()
+ proto.write(UserStateProto.NUM_ENROLLED, FaceUtils.getLegacyInstance(mSensorId)
.getBiometricsForUser(mContext, userId).size());
proto.end(userToken);
}
@@ -801,7 +801,8 @@ public class Face10 implements IHwBinder.DeathRecipient, ServiceProvider {
JSONArray sets = new JSONArray();
for (UserInfo user : UserManager.get(mContext).getUsers()) {
final int userId = user.getUserHandle().getIdentifier();
- final int c = FaceUtils.getInstance().getBiometricsForUser(mContext, userId).size();
+ final int c = FaceUtils.getLegacyInstance(mSensorId)
+ .getBiometricsForUser(mContext, userId).size();
JSONObject set = new JSONObject();
set.put("id", userId);
set.put("count", c);
diff --git a/services/core/java/com/android/server/biometrics/sensors/fingerprint/FingerprintService.java b/services/core/java/com/android/server/biometrics/sensors/fingerprint/FingerprintService.java
index 0cbd440a6a25..61f9cc40d233 100644
--- a/services/core/java/com/android/server/biometrics/sensors/fingerprint/FingerprintService.java
+++ b/services/core/java/com/android/server/biometrics/sensors/fingerprint/FingerprintService.java
@@ -587,13 +587,13 @@ public class FingerprintService extends SystemService implements BiometricServic
@Nullable byte [] hardwareAuthToken, String opPackageName) {
Utils.checkPermission(getContext(), RESET_FINGERPRINT_LOCKOUT);
- final Pair<Integer, ServiceProvider> provider = getSingleProvider();
+ final ServiceProvider provider = getProviderForSensor(sensorId);
if (provider == null) {
Slog.w(TAG, "Null provider for resetLockout, caller: " + opPackageName);
return;
}
- provider.second.scheduleResetLockout(sensorId, userId, hardwareAuthToken);
+ provider.scheduleResetLockout(sensorId, userId, hardwareAuthToken);
}
@Override
diff --git a/services/core/java/com/android/server/biometrics/sensors/fingerprint/FingerprintUtils.java b/services/core/java/com/android/server/biometrics/sensors/fingerprint/FingerprintUtils.java
index 6da86502b64c..b3d2419901e4 100644
--- a/services/core/java/com/android/server/biometrics/sensors/fingerprint/FingerprintUtils.java
+++ b/services/core/java/com/android/server/biometrics/sensors/fingerprint/FingerprintUtils.java
@@ -75,12 +75,12 @@ public class FingerprintUtils implements BiometricUtils<Fingerprint> {
/**
* Legacy getter for {@link android.hardware.biometrics.fingerprint.V2_1} ands its extended
- * subclasses, which do not support a well defined sensorId from the HAL.
+ * subclasses. Framework-side cache is always stored in the same file, regardless of sensorId.
*/
- public static FingerprintUtils getInstance() {
+ public static FingerprintUtils getLegacyInstance(int sensorId) {
// Note that sensorId for legacy services can be hard-coded to 0 since it's only used
// to index into the sensor states map.
- return getInstance(0 /* sensorId */, LEGACY_FINGERPRINT_FILE);
+ return getInstance(sensorId, LEGACY_FINGERPRINT_FILE);
}
private FingerprintUtils(String fileName) {
diff --git a/services/core/java/com/android/server/biometrics/sensors/fingerprint/hidl/BiometricTestSessionImpl.java b/services/core/java/com/android/server/biometrics/sensors/fingerprint/hidl/BiometricTestSessionImpl.java
index 65ce34d31b61..74549b917e82 100644
--- a/services/core/java/com/android/server/biometrics/sensors/fingerprint/hidl/BiometricTestSessionImpl.java
+++ b/services/core/java/com/android/server/biometrics/sensors/fingerprint/hidl/BiometricTestSessionImpl.java
@@ -144,7 +144,7 @@ public class BiometricTestSessionImpl extends ITestSession.Stub {
Utils.checkPermission(mContext, TEST_BIOMETRIC);
// Fake authentication with any of the existing fingers
- List<Fingerprint> fingerprints = FingerprintUtils.getInstance()
+ List<Fingerprint> fingerprints = FingerprintUtils.getLegacyInstance(mSensorId)
.getBiometricsForUser(mContext, userId);
if (fingerprints.isEmpty()) {
Slog.w(TAG, "No fingerprints, returning");
diff --git a/services/core/java/com/android/server/biometrics/sensors/fingerprint/hidl/Fingerprint21.java b/services/core/java/com/android/server/biometrics/sensors/fingerprint/hidl/Fingerprint21.java
index 7c5b7c92c1c6..b8d27aa61806 100644
--- a/services/core/java/com/android/server/biometrics/sensors/fingerprint/hidl/Fingerprint21.java
+++ b/services/core/java/com/android/server/biometrics/sensors/fingerprint/hidl/Fingerprint21.java
@@ -111,6 +111,7 @@ public class Fingerprint21 implements IHwBinder.DeathRecipient, ServiceProvider
@NonNull private final HalResultController mHalResultController;
@Nullable private IUdfpsOverlayController mUdfpsOverlayController;
private int mCurrentUserId = UserHandle.USER_NULL;
+ private final int mSensorId;
private final class BiometricTaskStackListener extends TaskStackListener {
@Override
@@ -167,13 +168,15 @@ public class Fingerprint21 implements IHwBinder.DeathRecipient, ServiceProvider
void onHardwareUnavailable();
}
+ private final int mSensorId;
@NonNull private final Context mContext;
@NonNull final Handler mHandler;
@NonNull final BiometricScheduler mScheduler;
@Nullable private Callback mCallback;
- HalResultController(@NonNull Context context, @NonNull Handler handler,
+ HalResultController(int sensorId, @NonNull Context context, @NonNull Handler handler,
@NonNull BiometricScheduler scheduler) {
+ mSensorId = sensorId;
mContext = context;
mHandler = handler;
mScheduler = scheduler;
@@ -194,7 +197,7 @@ public class Fingerprint21 implements IHwBinder.DeathRecipient, ServiceProvider
}
final int currentUserId = client.getTargetUserId();
- final CharSequence name = FingerprintUtils.getInstance()
+ final CharSequence name = FingerprintUtils.getLegacyInstance(mSensorId)
.getUniqueName(mContext, currentUserId);
final Fingerprint fingerprint = new Fingerprint(name, groupId, fingerId, deviceId);
@@ -307,6 +310,7 @@ public class Fingerprint21 implements IHwBinder.DeathRecipient, ServiceProvider
@NonNull LockoutResetDispatcher lockoutResetDispatcher,
@NonNull HalResultController controller) {
mContext = context;
+ mSensorId = sensorId;
mScheduler = scheduler;
mHandler = handler;
mActivityTaskManager = ActivityTaskManager.getInstance();
@@ -361,7 +365,8 @@ public class Fingerprint21 implements IHwBinder.DeathRecipient, ServiceProvider
final Handler handler = new Handler(Looper.getMainLooper());
final BiometricScheduler scheduler =
new BiometricScheduler(TAG, gestureAvailabilityDispatcher);
- final HalResultController controller = new HalResultController(context, handler, scheduler);
+ final HalResultController controller = new HalResultController(sensorId, context, handler,
+ scheduler);
return new Fingerprint21(context, scheduler, handler, sensorId, strength,
lockoutResetDispatcher, controller);
}
@@ -549,7 +554,7 @@ public class Fingerprint21 implements IHwBinder.DeathRecipient, ServiceProvider
final FingerprintEnrollClient client = new FingerprintEnrollClient(mContext,
mLazyDaemon, token, new ClientMonitorCallbackConverter(receiver), userId,
- hardwareAuthToken, opPackageName, FingerprintUtils.getInstance(),
+ hardwareAuthToken, opPackageName, FingerprintUtils.getLegacyInstance(mSensorId),
ENROLL_TIMEOUT_SEC, mSensorProperties.sensorId, mUdfpsOverlayController);
mScheduler.scheduleClientMonitor(client, new ClientMonitor.Callback() {
@Override
@@ -624,7 +629,7 @@ public class Fingerprint21 implements IHwBinder.DeathRecipient, ServiceProvider
final FingerprintRemovalClient client = new FingerprintRemovalClient(mContext,
mLazyDaemon, token, new ClientMonitorCallbackConverter(receiver), fingerId,
- userId, opPackageName, FingerprintUtils.getInstance(),
+ userId, opPackageName, FingerprintUtils.getLegacyInstance(mSensorId),
mSensorProperties.sensorId, mAuthenticatorIds);
mScheduler.scheduleClientMonitor(client);
});
@@ -638,8 +643,8 @@ public class Fingerprint21 implements IHwBinder.DeathRecipient, ServiceProvider
mSensorProperties.sensorId, userId);
final FingerprintInternalCleanupClient client = new FingerprintInternalCleanupClient(
mContext, mLazyDaemon, userId, mContext.getOpPackageName(),
- mSensorProperties.sensorId, enrolledList, FingerprintUtils.getInstance(),
- mAuthenticatorIds);
+ mSensorProperties.sensorId, enrolledList,
+ FingerprintUtils.getLegacyInstance(mSensorId), mAuthenticatorIds);
mScheduler.scheduleClientMonitor(client);
});
}
@@ -657,14 +662,15 @@ public class Fingerprint21 implements IHwBinder.DeathRecipient, ServiceProvider
@Override
public void rename(int sensorId, int fingerId, int userId, @NonNull String name) {
mHandler.post(() -> {
- FingerprintUtils.getInstance().renameBiometricForUser(mContext, userId, fingerId, name);
+ FingerprintUtils.getLegacyInstance(mSensorId)
+ .renameBiometricForUser(mContext, userId, fingerId, name);
});
}
@Override
@NonNull
public List<Fingerprint> getEnrolledFingerprints(int sensorId, int userId) {
- return FingerprintUtils.getInstance().getBiometricsForUser(mContext, userId);
+ return FingerprintUtils.getLegacyInstance(mSensorId).getBiometricsForUser(mContext, userId);
}
@Override
@@ -716,7 +722,7 @@ public class Fingerprint21 implements IHwBinder.DeathRecipient, ServiceProvider
final long userToken = proto.start(SensorStateProto.USER_STATES);
proto.write(UserStateProto.USER_ID, userId);
- proto.write(UserStateProto.NUM_ENROLLED, FingerprintUtils.getInstance()
+ proto.write(UserStateProto.NUM_ENROLLED, FingerprintUtils.getLegacyInstance(mSensorId)
.getBiometricsForUser(mContext, userId).size());
proto.end(userToken);
}
@@ -737,7 +743,8 @@ public class Fingerprint21 implements IHwBinder.DeathRecipient, ServiceProvider
proto.write(FingerprintUserStatsProto.USER_ID, userId);
proto.write(FingerprintUserStatsProto.NUM_FINGERPRINTS,
- FingerprintUtils.getInstance().getBiometricsForUser(mContext, userId).size());
+ FingerprintUtils.getLegacyInstance(mSensorId)
+ .getBiometricsForUser(mContext, userId).size());
// Normal fingerprint authentications (e.g. lockscreen)
long countsToken = proto.start(FingerprintUserStatsProto.NORMAL);
@@ -777,7 +784,7 @@ public class Fingerprint21 implements IHwBinder.DeathRecipient, ServiceProvider
JSONArray sets = new JSONArray();
for (UserInfo user : UserManager.get(mContext).getUsers()) {
final int userId = user.getUserHandle().getIdentifier();
- final int N = FingerprintUtils.getInstance()
+ final int N = FingerprintUtils.getLegacyInstance(mSensorId)
.getBiometricsForUser(mContext, userId).size();
JSONObject set = new JSONObject();
set.put("id", userId);
diff --git a/services/core/java/com/android/server/biometrics/sensors/fingerprint/hidl/Fingerprint21UdfpsMock.java b/services/core/java/com/android/server/biometrics/sensors/fingerprint/hidl/Fingerprint21UdfpsMock.java
index e4933e40ccd5..791d224b9728 100644
--- a/services/core/java/com/android/server/biometrics/sensors/fingerprint/hidl/Fingerprint21UdfpsMock.java
+++ b/services/core/java/com/android/server/biometrics/sensors/fingerprint/hidl/Fingerprint21UdfpsMock.java
@@ -210,9 +210,9 @@ public class Fingerprint21UdfpsMock extends Fingerprint21 implements TrustManage
@NonNull private Fingerprint21UdfpsMock mFingerprint21;
@Nullable private LastAuthArgs mLastAuthArgs;
- MockHalResultController(@NonNull Context context, @NonNull Handler handler,
+ MockHalResultController(int sensorId, @NonNull Context context, @NonNull Handler handler,
@NonNull BiometricScheduler scheduler) {
- super(context, handler, scheduler);
+ super(sensorId, context, handler, scheduler);
}
void init(@NonNull RestartAuthRunnable restartAuthRunnable,
@@ -280,7 +280,7 @@ public class Fingerprint21UdfpsMock extends Fingerprint21 implements TrustManage
final TestableBiometricScheduler scheduler =
new TestableBiometricScheduler(TAG, gestureAvailabilityDispatcher);
final MockHalResultController controller =
- new MockHalResultController(context, handler, scheduler);
+ new MockHalResultController(sensorId, context, handler, scheduler);
return new Fingerprint21UdfpsMock(context, scheduler, handler, sensorId, strength,
lockoutResetDispatcher, controller);
}
diff --git a/services/core/java/com/android/server/content/SyncStorageEngine.java b/services/core/java/com/android/server/content/SyncStorageEngine.java
index d27cb16ecc51..668142b7e8ee 100644
--- a/services/core/java/com/android/server/content/SyncStorageEngine.java
+++ b/services/core/java/com/android/server/content/SyncStorageEngine.java
@@ -1804,10 +1804,8 @@ public class SyncStorageEngine {
int id = -1;
try {
id = parser.getAttributeInt(null, "id");
- } catch (NumberFormatException e) {
+ } catch (XmlPullParserException e) {
Slog.e(TAG, "error parsing the id of the authority", e);
- } catch (NullPointerException e) {
- Slog.e(TAG, "the id of the authority is null", e);
}
if (id >= 0) {
String authorityName = parser.getAttributeValue(null, "authority");
@@ -1920,28 +1918,26 @@ public class SyncStorageEngine {
private void parseExtra(TypedXmlPullParser parser, Bundle extras) {
String name = parser.getAttributeValue(null, "name");
String type = parser.getAttributeValue(null, "type");
- String value1 = parser.getAttributeValue(null, "value1");
- String value2 = parser.getAttributeValue(null, "value2");
try {
if ("long".equals(type)) {
- extras.putLong(name, Long.parseLong(value1));
+ extras.putLong(name, parser.getAttributeLong(null, "value1"));
} else if ("integer".equals(type)) {
- extras.putInt(name, Integer.parseInt(value1));
+ extras.putInt(name, parser.getAttributeInt(null, "value1"));
} else if ("double".equals(type)) {
- extras.putDouble(name, Double.parseDouble(value1));
+ extras.putDouble(name, parser.getAttributeDouble(null, "value1"));
} else if ("float".equals(type)) {
- extras.putFloat(name, Float.parseFloat(value1));
+ extras.putFloat(name, parser.getAttributeFloat(null, "value1"));
} else if ("boolean".equals(type)) {
- extras.putBoolean(name, Boolean.parseBoolean(value1));
+ extras.putBoolean(name, parser.getAttributeBoolean(null, "value1"));
} else if ("string".equals(type)) {
- extras.putString(name, value1);
+ extras.putString(name, parser.getAttributeValue(null, "value1"));
} else if ("account".equals(type)) {
+ final String value1 = parser.getAttributeValue(null, "value1");
+ final String value2 = parser.getAttributeValue(null, "value2");
extras.putParcelable(name, new Account(value1, value2));
}
- } catch (NumberFormatException e) {
- Slog.e(TAG, "error parsing bundle value", e);
- } catch (NullPointerException e) {
+ } catch (XmlPullParserException e) {
Slog.e(TAG, "error parsing bundle value", e);
}
}
diff --git a/services/core/java/com/android/server/display/BrightnessTracker.java b/services/core/java/com/android/server/display/BrightnessTracker.java
index 2a0e21919704..7a8ba9f4380c 100644
--- a/services/core/java/com/android/server/display/BrightnessTracker.java
+++ b/services/core/java/com/android/server/display/BrightnessTracker.java
@@ -668,12 +668,11 @@ public class BrightnessTracker {
builder.setUserBrightnessPoint(
parser.getAttributeBoolean(null, ATTR_USER_POINT, false));
- String colorSampleDurationString =
- parser.getAttributeValue(null, ATTR_COLOR_SAMPLE_DURATION);
+ long colorSampleDuration =
+ parser.getAttributeLong(null, ATTR_COLOR_SAMPLE_DURATION, -1);
String colorValueBucketsString =
parser.getAttributeValue(null, ATTR_COLOR_VALUE_BUCKETS);
- if (colorSampleDurationString != null && colorValueBucketsString != null) {
- long colorSampleDuration = Long.parseLong(colorSampleDurationString);
+ if (colorSampleDuration != -1 && colorValueBucketsString != null) {
String[] buckets = colorValueBucketsString.split(",");
long[] bucketValues = new long[buckets.length];
for (int i = 0; i < bucketValues.length; ++i) {
diff --git a/services/core/java/com/android/server/display/PersistentDataStore.java b/services/core/java/com/android/server/display/PersistentDataStore.java
index b0820e81ec09..a62642b1f842 100644
--- a/services/core/java/com/android/server/display/PersistentDataStore.java
+++ b/services/core/java/com/android/server/display/PersistentDataStore.java
@@ -31,17 +31,12 @@ import android.util.Xml;
import android.view.Display;
import com.android.internal.annotations.VisibleForTesting;
-import com.android.internal.util.FastXmlSerializer;
import com.android.internal.util.XmlUtils;
import libcore.io.IoUtils;
-import org.xmlpull.v1.XmlPullParser;
import org.xmlpull.v1.XmlPullParserException;
-import org.xmlpull.v1.XmlSerializer;
-import java.io.BufferedInputStream;
-import java.io.BufferedOutputStream;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
@@ -49,7 +44,6 @@ import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.io.PrintWriter;
-import java.nio.charset.StandardCharsets;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Map;
@@ -628,15 +622,7 @@ final class PersistentDataStore {
}
String packageName = parser.getAttributeValue(null, ATTR_PACKAGE_NAME);
- String timeStampString = parser.getAttributeValue(null, ATTR_TIME_STAMP);
- long timeStamp = -1;
- if (timeStampString != null) {
- try {
- timeStamp = Long.parseLong(timeStampString);
- } catch (NumberFormatException nfe) {
- // Ignore we will just not restore the timestamp.
- }
- }
+ long timeStamp = parser.getAttributeLong(null, ATTR_TIME_STAMP, -1);
try {
BrightnessConfiguration config =
diff --git a/services/core/java/com/android/server/input/PersistentDataStore.java b/services/core/java/com/android/server/input/PersistentDataStore.java
index a735a8f9d305..6cec2723b141 100644
--- a/services/core/java/com/android/server/input/PersistentDataStore.java
+++ b/services/core/java/com/android/server/input/PersistentDataStore.java
@@ -510,7 +510,7 @@ final class PersistentDataStore {
serializer.startTag(null, "keyboard-layout");
serializer.attribute(null, "descriptor", layout);
if (layout.equals(mCurrentKeyboardLayout)) {
- serializer.attribute(null, "current", "true");
+ serializer.attributeBoolean(null, "current", true);
}
serializer.endTag(null, "keyboard-layout");
}
diff --git a/services/core/java/com/android/server/location/timezone/BinderLocationTimeZoneProvider.java b/services/core/java/com/android/server/location/timezone/BinderLocationTimeZoneProvider.java
index b4bcd7b10c42..fd8cf707e697 100644
--- a/services/core/java/com/android/server/location/timezone/BinderLocationTimeZoneProvider.java
+++ b/services/core/java/com/android/server/location/timezone/BinderLocationTimeZoneProvider.java
@@ -55,7 +55,7 @@ class BinderLocationTimeZoneProvider extends LocationTimeZoneProvider {
@Override
void onInitialize() {
- mProxy.setListener(new LocationTimeZoneProviderProxy.Listener() {
+ mProxy.initialize(new LocationTimeZoneProviderProxy.Listener() {
@Override
public void onReportLocationTimeZoneEvent(
@NonNull LocationTimeZoneEvent locationTimeZoneEvent) {
diff --git a/services/core/java/com/android/server/location/timezone/LocationTimeZoneManagerService.java b/services/core/java/com/android/server/location/timezone/LocationTimeZoneManagerService.java
index b7c7476844a5..c8a1db6681ff 100644
--- a/services/core/java/com/android/server/location/timezone/LocationTimeZoneManagerService.java
+++ b/services/core/java/com/android/server/location/timezone/LocationTimeZoneManagerService.java
@@ -19,6 +19,7 @@ package com.android.server.location.timezone;
import android.annotation.NonNull;
import android.annotation.Nullable;
import android.content.Context;
+import android.content.res.Resources;
import android.os.Binder;
import android.os.ResultReceiver;
import android.os.ShellCallback;
@@ -27,6 +28,7 @@ import android.util.IndentingPrintWriter;
import android.util.Log;
import android.util.Slog;
+import com.android.internal.R;
import com.android.internal.annotations.GuardedBy;
import com.android.internal.util.DumpUtils;
import com.android.server.FgThread;
@@ -179,36 +181,45 @@ public class LocationTimeZoneManagerService extends Binder {
}
private LocationTimeZoneProvider createPrimaryProvider() {
+ Resources resources = mContext.getResources();
+ if (!resources.getBoolean(R.bool.config_enablePrimaryLocationTimeZoneProvider)) {
+ return new NullLocationTimeZoneProvider(mThreadingDomain, PRIMARY_PROVIDER_NAME);
+ }
+
LocationTimeZoneProviderProxy proxy;
if (isInSimulationMode(PRIMARY_PROVIDER_NAME)) {
proxy = new SimulatedLocationTimeZoneProviderProxy(mContext, mThreadingDomain);
} else {
- proxy = RealLocationTimeZoneProviderProxy.createAndRegister(
+ proxy = new RealLocationTimeZoneProviderProxy(
mContext,
mThreadingDomain,
PRIMARY_LOCATION_TIME_ZONE_SERVICE_ACTION,
- com.android.internal.R.bool.config_enablePrimaryLocationTimeZoneOverlay,
- com.android.internal.R.string.config_primaryLocationTimeZoneProviderPackageName
+ R.bool.config_enablePrimaryLocationTimeZoneOverlay,
+ R.string.config_primaryLocationTimeZoneProviderPackageName
);
}
- return createLocationTimeZoneProvider(PRIMARY_PROVIDER_NAME, proxy);
+ return new BinderLocationTimeZoneProvider(mThreadingDomain, PRIMARY_PROVIDER_NAME, proxy);
}
private LocationTimeZoneProvider createSecondaryProvider() {
+ Resources resources = mContext.getResources();
+ if (!resources.getBoolean(R.bool.config_enableSecondaryLocationTimeZoneProvider)) {
+ return new NullLocationTimeZoneProvider(mThreadingDomain, SECONDARY_PROVIDER_NAME);
+ }
+
LocationTimeZoneProviderProxy proxy;
if (isInSimulationMode(SECONDARY_PROVIDER_NAME)) {
proxy = new SimulatedLocationTimeZoneProviderProxy(mContext, mThreadingDomain);
} else {
- proxy = RealLocationTimeZoneProviderProxy.createAndRegister(
+ proxy = new RealLocationTimeZoneProviderProxy(
mContext,
mThreadingDomain,
SECONDARY_LOCATION_TIME_ZONE_SERVICE_ACTION,
- com.android.internal.R.bool.config_enableSecondaryLocationTimeZoneOverlay,
- com.android.internal.R.string
- .config_secondaryLocationTimeZoneProviderPackageName
+ R.bool.config_enableSecondaryLocationTimeZoneOverlay,
+ R.string.config_secondaryLocationTimeZoneProviderPackageName
);
}
- return createLocationTimeZoneProvider(SECONDARY_PROVIDER_NAME, proxy);
+ return new BinderLocationTimeZoneProvider(mThreadingDomain, SECONDARY_PROVIDER_NAME, proxy);
}
private boolean isInSimulationMode(String providerName) {
@@ -216,21 +227,6 @@ public class LocationTimeZoneManagerService extends Binder {
SIMULATION_MODE_SYSTEM_PROPERTY_PREFIX + providerName, false);
}
- private LocationTimeZoneProvider createLocationTimeZoneProvider(
- @NonNull String providerName, @NonNull LocationTimeZoneProviderProxy proxy) {
- LocationTimeZoneProvider provider;
- if (proxy != null) {
- debugLog("LocationTimeZoneProvider found for providerName=" + providerName);
- provider = new BinderLocationTimeZoneProvider(mThreadingDomain,
- providerName, proxy);
- } else {
- debugLog("No LocationTimeZoneProvider found for providerName=" + providerName
- + ": stubbing");
- provider = new NullLocationTimeZoneProvider(mThreadingDomain, providerName);
- }
- return provider;
- }
-
@Override
public void onShellCommand(FileDescriptor in, FileDescriptor out,
FileDescriptor err, String[] args, ShellCallback callback,
diff --git a/services/core/java/com/android/server/location/timezone/LocationTimeZoneProviderProxy.java b/services/core/java/com/android/server/location/timezone/LocationTimeZoneProviderProxy.java
index 1b4706f8801e..8a0259d12a6c 100644
--- a/services/core/java/com/android/server/location/timezone/LocationTimeZoneProviderProxy.java
+++ b/services/core/java/com/android/server/location/timezone/LocationTimeZoneProviderProxy.java
@@ -70,9 +70,11 @@ abstract class LocationTimeZoneProviderProxy implements Dumpable {
}
/**
- * Sets the listener. The listener can expect to receive all events after this point.
+ * Initializes the proxy. The supplied listener can expect to receive all events after this
+ * point. This method also calls {@link #onInitialize()} for subclasses to handle their own
+ * initialization.
*/
- void setListener(@NonNull Listener listener) {
+ void initialize(@NonNull Listener listener) {
Objects.requireNonNull(listener);
synchronized (mSharedLock) {
if (mListener != null) {
@@ -80,9 +82,15 @@ abstract class LocationTimeZoneProviderProxy implements Dumpable {
}
this.mListener = listener;
}
+ onInitialize();
}
/**
+ * Initializes the proxy. This is called after {@link #mListener} is set.
+ */
+ abstract void onInitialize();
+
+ /**
* Sets a new request for the provider.
*/
abstract void setRequest(@NonNull LocationTimeZoneProviderRequest request);
diff --git a/services/core/java/com/android/server/location/timezone/RealLocationTimeZoneProviderProxy.java b/services/core/java/com/android/server/location/timezone/RealLocationTimeZoneProviderProxy.java
index cd6d3592af0e..1a012882305f 100644
--- a/services/core/java/com/android/server/location/timezone/RealLocationTimeZoneProviderProxy.java
+++ b/services/core/java/com/android/server/location/timezone/RealLocationTimeZoneProviderProxy.java
@@ -41,23 +41,6 @@ import java.util.Objects;
*/
class RealLocationTimeZoneProviderProxy extends LocationTimeZoneProviderProxy {
- /**
- * Creates and registers this proxy. If no suitable service is available for the proxy, returns
- * null.
- */
- @Nullable
- static LocationTimeZoneProviderProxy createAndRegister(
- @NonNull Context context, @NonNull ThreadingDomain threadingDomain,
- @NonNull String action, int enableOverlayResId, int nonOverlayPackageResId) {
- RealLocationTimeZoneProviderProxy proxy = new RealLocationTimeZoneProviderProxy(
- context, threadingDomain, action, enableOverlayResId, nonOverlayPackageResId);
- if (proxy.register()) {
- return proxy;
- } else {
- return null;
- }
- }
-
@NonNull private final ServiceWatcher mServiceWatcher;
@GuardedBy("mProxyLock")
@@ -66,7 +49,7 @@ class RealLocationTimeZoneProviderProxy extends LocationTimeZoneProviderProxy {
@GuardedBy("mProxyLock")
@NonNull private LocationTimeZoneProviderRequest mRequest;
- private RealLocationTimeZoneProviderProxy(
+ RealLocationTimeZoneProviderProxy(
@NonNull Context context, @NonNull ThreadingDomain threadingDomain,
@NonNull String action, int enableOverlayResId,
int nonOverlayPackageResId) {
@@ -77,6 +60,13 @@ class RealLocationTimeZoneProviderProxy extends LocationTimeZoneProviderProxy {
enableOverlayResId, nonOverlayPackageResId);
}
+ @Override
+ void onInitialize() {
+ if (!register()) {
+ throw new IllegalStateException("Unable to register binder proxy");
+ }
+ }
+
private boolean register() {
boolean resolves = mServiceWatcher.checkServiceResolves();
if (resolves) {
diff --git a/services/core/java/com/android/server/location/timezone/SimulatedLocationTimeZoneProviderProxy.java b/services/core/java/com/android/server/location/timezone/SimulatedLocationTimeZoneProviderProxy.java
index 604ff74e71ac..5e66a99a93fa 100644
--- a/services/core/java/com/android/server/location/timezone/SimulatedLocationTimeZoneProviderProxy.java
+++ b/services/core/java/com/android/server/location/timezone/SimulatedLocationTimeZoneProviderProxy.java
@@ -49,6 +49,11 @@ class SimulatedLocationTimeZoneProviderProxy extends LocationTimeZoneProviderPro
mRequest = LocationTimeZoneProviderRequest.EMPTY_REQUEST;
}
+ @Override
+ void onInitialize() {
+ // No-op - nothing to do for the simulated provider.
+ }
+
void simulate(@NonNull SimulatedBinderProviderEvent event) {
mThreadingDomain.assertCurrentThread();
diff --git a/services/core/java/com/android/server/notification/NotificationManagerService.java b/services/core/java/com/android/server/notification/NotificationManagerService.java
index ee860e3ac6d7..9efbb6964aeb 100755
--- a/services/core/java/com/android/server/notification/NotificationManagerService.java
+++ b/services/core/java/com/android/server/notification/NotificationManagerService.java
@@ -277,6 +277,7 @@ import com.android.server.pm.PackageManagerService;
import com.android.server.policy.PhoneWindowManager;
import com.android.server.statusbar.StatusBarManagerInternal;
import com.android.server.uri.UriGrantsManagerInternal;
+import com.android.server.utils.quota.MultiRateLimiter;
import com.android.server.wm.ActivityTaskManagerInternal;
import com.android.server.wm.BackgroundActivityStartCallback;
import com.android.server.wm.WindowManagerInternal;
@@ -298,6 +299,7 @@ import java.io.InputStream;
import java.io.OutputStream;
import java.io.PrintWriter;
import java.nio.charset.StandardCharsets;
+import java.time.Duration;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashSet;
@@ -371,6 +373,20 @@ public class NotificationManagerService extends SystemService {
RoleManager.ROLE_EMERGENCY
};
+ // Used for rate limiting toasts by package.
+ static final String TOAST_QUOTA_TAG = "toast_quota_tag";
+
+ // This constant defines rate limits applied to showing toasts. The numbers are set in a way
+ // such that an aggressive toast showing strategy would result in a roughly 1.5x longer wait
+ // time (before the package is allowed to show toasts again) each time the toast rate limit is
+ // reached. It's meant to protect the user against apps spamming them with toasts (either
+ // accidentally or on purpose).
+ private static final MultiRateLimiter.RateLimit[] TOAST_RATE_LIMITS = {
+ MultiRateLimiter.RateLimit.create(3, Duration.ofSeconds(20)),
+ MultiRateLimiter.RateLimit.create(5, Duration.ofSeconds(42)),
+ MultiRateLimiter.RateLimit.create(6, Duration.ofSeconds(68)),
+ };
+
// When #matchesCallFilter is called from the ringer, wait at most
// 3s to resolve the contacts. This timeout is required since
// ContactsProvider might take a long time to start up.
@@ -422,6 +438,16 @@ public class NotificationManagerService extends SystemService {
@EnabledAfter(targetSdkVersion = Build.VERSION_CODES.R)
private static final long NOTIFICATION_TRAMPOLINE_BLOCK = 167676448L;
+ /**
+ * Rate limit showing toasts, on a per package basis.
+ *
+ * It limits the effects of {@link android.widget.Toast#show()} calls to prevent overburdening
+ * the user with too many toasts in a limited time. Any attempt to show more toasts than allowed
+ * in a certain time frame will result in the toast being discarded.
+ */
+ @ChangeId
+ private static final long RATE_LIMIT_TOASTS = 154198299L;
+
private IActivityManager mAm;
private ActivityTaskManagerInternal mAtm;
private ActivityManager mActivityManager;
@@ -500,6 +526,9 @@ public class NotificationManagerService extends SystemService {
@GuardedBy("mToastQueue")
private boolean mIsCurrentToastShown = false;
+ // Used for rate limiting toasts by package.
+ private MultiRateLimiter mToastRateLimiter;
+
// The last key in this list owns the hardware.
ArrayList<String> mLights = new ArrayList<>();
@@ -1662,6 +1691,11 @@ public class NotificationManagerService extends SystemService {
= Settings.Secure.getUriFor(Settings.Secure.NOTIFICATION_HISTORY_ENABLED);
private final Uri NOTIFICATION_SHOW_MEDIA_ON_QUICK_SETTINGS_URI
= Settings.Global.getUriFor(Settings.Global.SHOW_MEDIA_ON_QUICK_SETTINGS);
+ private final Uri LOCK_SCREEN_ALLOW_PRIVATE_NOTIFICATIONS
+ = Settings.Secure.getUriFor(
+ Settings.Secure.LOCK_SCREEN_ALLOW_PRIVATE_NOTIFICATIONS);
+ private final Uri LOCK_SCREEN_SHOW_NOTIFICATIONS
+ = Settings.Secure.getUriFor(Settings.Secure.LOCK_SCREEN_SHOW_NOTIFICATIONS);
SettingsObserver(Handler handler) {
super(handler);
@@ -1681,6 +1715,11 @@ public class NotificationManagerService extends SystemService {
false, this, UserHandle.USER_ALL);
resolver.registerContentObserver(NOTIFICATION_SHOW_MEDIA_ON_QUICK_SETTINGS_URI,
false, this, UserHandle.USER_ALL);
+
+ resolver.registerContentObserver(LOCK_SCREEN_ALLOW_PRIVATE_NOTIFICATIONS,
+ false, this, UserHandle.USER_ALL);
+ resolver.registerContentObserver(LOCK_SCREEN_SHOW_NOTIFICATIONS,
+ false, this, UserHandle.USER_ALL);
update(null);
}
@@ -1722,6 +1761,12 @@ public class NotificationManagerService extends SystemService {
if (uri == null || NOTIFICATION_SHOW_MEDIA_ON_QUICK_SETTINGS_URI.equals(uri)) {
mPreferencesHelper.updateMediaNotificationFilteringEnabled();
}
+ if (uri == null || LOCK_SCREEN_ALLOW_PRIVATE_NOTIFICATIONS.equals(uri)) {
+ mPreferencesHelper.updateLockScreenPrivateNotifications();
+ }
+ if (uri == null || LOCK_SCREEN_SHOW_NOTIFICATIONS.equals(uri)) {
+ mPreferencesHelper.updateLockScreenShowNotifications();
+ }
}
}
@@ -1915,7 +1960,8 @@ public class NotificationManagerService extends SystemService {
DevicePolicyManagerInternal dpm, IUriGrantsManager ugm,
UriGrantsManagerInternal ugmInternal, AppOpsManager appOps, UserManager userManager,
NotificationHistoryManager historyManager, StatsManager statsManager,
- TelephonyManager telephonyManager, ActivityManagerInternal ami) {
+ TelephonyManager telephonyManager, ActivityManagerInternal ami,
+ MultiRateLimiter toastRateLimiter) {
mHandler = handler;
Resources resources = getContext().getResources();
mMaxPackageEnqueueRate = Settings.Global.getFloat(getContext().getContentResolver(),
@@ -2107,6 +2153,8 @@ public class NotificationManagerService extends SystemService {
com.android.internal.R.array.config_notificationMsgPkgsAllowedAsConvos));
mStatsManager = statsManager;
+ mToastRateLimiter = toastRateLimiter;
+
// register for various Intents.
// If this is called within a test, make sure to unregister the intent receivers by
// calling onDestroy()
@@ -2217,7 +2265,8 @@ public class NotificationManagerService extends SystemService {
mStatsManager = (StatsManager) getContext().getSystemService(
Context.STATS_MANAGER),
getContext().getSystemService(TelephonyManager.class),
- LocalServices.getService(ActivityManagerInternal.class));
+ LocalServices.getService(ActivityManagerInternal.class),
+ createToastRateLimiter());
publishBinderService(Context.NOTIFICATION_SERVICE, mService, /* allowIsolated= */ false,
DUMP_FLAG_PRIORITY_CRITICAL | DUMP_FLAG_PRIORITY_NORMAL);
@@ -2855,6 +2904,10 @@ public class NotificationManagerService extends SystemService {
return mInternalService;
}
+ private MultiRateLimiter createToastRateLimiter() {
+ return new MultiRateLimiter.Builder(getContext()).addRateLimits(TOAST_RATE_LIMITS).build();
+ }
+
@VisibleForTesting
final IBinder mService = new INotificationManager.Stub() {
// Toasts
@@ -3591,8 +3644,9 @@ public class NotificationManagerService extends SystemService {
public ParceledListSlice<ConversationChannelWrapper> getConversations(
boolean onlyImportant) {
enforceSystemOrSystemUI("getConversations");
+ IntArray userIds = mUserProfiles.getCurrentProfileIds();
ArrayList<ConversationChannelWrapper> conversations =
- mPreferencesHelper.getConversations(onlyImportant);
+ mPreferencesHelper.getConversations(userIds, onlyImportant);
for (ConversationChannelWrapper conversation : conversations) {
if (mShortcutHelper == null) {
conversation.setShortcutInfo(null);
@@ -7329,10 +7383,21 @@ public class NotificationManagerService extends SystemService {
ToastRecord record = mToastQueue.get(0);
while (record != null) {
- if (record.show()) {
+ int userId = UserHandle.getUserId(record.uid);
+ boolean rateLimitingEnabled =
+ CompatChanges.isChangeEnabled(RATE_LIMIT_TOASTS, record.uid);
+ boolean isWithinQuota =
+ mToastRateLimiter.isWithinQuota(userId, record.pkg, TOAST_QUOTA_TAG);
+ if ((!rateLimitingEnabled || isWithinQuota) && record.show()) {
scheduleDurationReachedLocked(record);
mIsCurrentToastShown = true;
+ if (rateLimitingEnabled) {
+ mToastRateLimiter.noteEvent(userId, record.pkg, TOAST_QUOTA_TAG);
+ }
return;
+ } else if (rateLimitingEnabled && !isWithinQuota) {
+ Slog.w(TAG, "Package " + record.pkg + " is above allowed toast quota, the "
+ + "following toast was blocked and discarded: " + record);
}
int index = mToastQueue.indexOf(record);
if (index >= 0) {
diff --git a/services/core/java/com/android/server/notification/PreferencesHelper.java b/services/core/java/com/android/server/notification/PreferencesHelper.java
index 1c0349d1b51f..cbd973aeaf6a 100644
--- a/services/core/java/com/android/server/notification/PreferencesHelper.java
+++ b/services/core/java/com/android/server/notification/PreferencesHelper.java
@@ -52,6 +52,7 @@ import android.service.notification.RankingHelperProto;
import android.text.TextUtils;
import android.util.ArrayMap;
import android.util.ArraySet;
+import android.util.IntArray;
import android.util.Pair;
import android.util.Slog;
import android.util.SparseBooleanArray;
@@ -170,6 +171,8 @@ public class PreferencesHelper implements RankingConfig {
private final AppOpsManager mAppOps;
private SparseBooleanArray mBadgingEnabled;
+ private SparseBooleanArray mLockScreenShowNotifications;
+ private SparseBooleanArray mLockScreenPrivateNotifications;
private boolean mBubblesEnabledGlobally = DEFAULT_GLOBAL_ALLOW_BUBBLE;
private boolean mIsMediaNotificationFilteringEnabled = DEFAULT_MEDIA_NOTIFICATION_FILTERING;
private boolean mAreChannelsBypassingDnd;
@@ -1379,36 +1382,39 @@ public class PreferencesHelper implements RankingConfig {
return null;
}
- public ArrayList<ConversationChannelWrapper> getConversations(boolean onlyImportant) {
+ public ArrayList<ConversationChannelWrapper> getConversations(IntArray userIds,
+ boolean onlyImportant) {
synchronized (mPackagePreferences) {
ArrayList<ConversationChannelWrapper> conversations = new ArrayList<>();
-
for (PackagePreferences p : mPackagePreferences.values()) {
- int N = p.channels.size();
- for (int i = 0; i < N; i++) {
- final NotificationChannel nc = p.channels.valueAt(i);
- if (!TextUtils.isEmpty(nc.getConversationId()) && !nc.isDeleted()
- && !nc.isDemoted()
- && (nc.isImportantConversation() || !onlyImportant)) {
- ConversationChannelWrapper conversation = new ConversationChannelWrapper();
- conversation.setPkg(p.pkg);
- conversation.setUid(p.uid);
- conversation.setNotificationChannel(nc);
- conversation.setParentChannelLabel(
- p.channels.get(nc.getParentChannelId()).getName());
- boolean blockedByGroup = false;
- if (nc.getGroup() != null) {
- NotificationChannelGroup group = p.groups.get(nc.getGroup());
- if (group != null) {
- if (group.isBlocked()) {
- blockedByGroup = true;
- } else {
- conversation.setGroupLabel(group.getName());
+ if (userIds.binarySearch(UserHandle.getUserId(p.uid)) >= 0) {
+ int N = p.channels.size();
+ for (int i = 0; i < N; i++) {
+ final NotificationChannel nc = p.channels.valueAt(i);
+ if (!TextUtils.isEmpty(nc.getConversationId()) && !nc.isDeleted()
+ && !nc.isDemoted()
+ && (nc.isImportantConversation() || !onlyImportant)) {
+ ConversationChannelWrapper conversation =
+ new ConversationChannelWrapper();
+ conversation.setPkg(p.pkg);
+ conversation.setUid(p.uid);
+ conversation.setNotificationChannel(nc);
+ conversation.setParentChannelLabel(
+ p.channels.get(nc.getParentChannelId()).getName());
+ boolean blockedByGroup = false;
+ if (nc.getGroup() != null) {
+ NotificationChannelGroup group = p.groups.get(nc.getGroup());
+ if (group != null) {
+ if (group.isBlocked()) {
+ blockedByGroup = true;
+ } else {
+ conversation.setGroupLabel(group.getName());
+ }
}
}
- }
- if (!blockedByGroup) {
- conversations.add(conversation);
+ if (!blockedByGroup) {
+ conversations.add(conversation);
+ }
}
}
}
@@ -2401,6 +2407,60 @@ public class PreferencesHelper implements RankingConfig {
return mBadgingEnabled.get(userId, DEFAULT_SHOW_BADGE);
}
+ public void updateLockScreenPrivateNotifications() {
+ if (mLockScreenPrivateNotifications == null) {
+ mLockScreenPrivateNotifications = new SparseBooleanArray();
+ }
+ boolean changed = false;
+ // update the cached values
+ for (int index = 0; index < mLockScreenPrivateNotifications.size(); index++) {
+ int userId = mLockScreenPrivateNotifications.keyAt(index);
+ final boolean oldValue = mLockScreenPrivateNotifications.get(userId);
+ final boolean newValue = Settings.Secure.getIntForUser(mContext.getContentResolver(),
+ Settings.Secure.LOCK_SCREEN_ALLOW_PRIVATE_NOTIFICATIONS, 1, userId) != 0;
+ mLockScreenPrivateNotifications.put(userId, newValue);
+ changed |= oldValue != newValue;
+ }
+ if (changed) {
+ updateConfig();
+ }
+ }
+
+ public void updateLockScreenShowNotifications() {
+ if (mLockScreenShowNotifications == null) {
+ mLockScreenShowNotifications = new SparseBooleanArray();
+ }
+ boolean changed = false;
+ // update the cached values
+ for (int index = 0; index < mLockScreenShowNotifications.size(); index++) {
+ int userId = mLockScreenShowNotifications.keyAt(index);
+ final boolean oldValue = mLockScreenShowNotifications.get(userId);
+ final boolean newValue = Settings.Secure.getIntForUser(mContext.getContentResolver(),
+ Settings.Secure.LOCK_SCREEN_SHOW_NOTIFICATIONS, 1, userId) != 0;
+ mLockScreenShowNotifications.put(userId, newValue);
+ changed |= oldValue != newValue;
+ }
+ if (changed) {
+ updateConfig();
+ }
+ }
+
+ @Override
+ public boolean canShowNotificationsOnLockscreen(int userId) {
+ if (mLockScreenShowNotifications == null) {
+ mLockScreenShowNotifications = new SparseBooleanArray();
+ }
+ return mLockScreenShowNotifications.get(userId, true);
+ }
+
+ @Override
+ public boolean canShowPrivateNotificationsOnLockScreen(int userId) {
+ if (mLockScreenPrivateNotifications == null) {
+ mLockScreenPrivateNotifications = new SparseBooleanArray();
+ }
+ return mLockScreenPrivateNotifications.get(userId, true);
+ }
+
public void unlockAllNotificationChannels() {
synchronized (mPackagePreferences) {
final int numPackagePreferences = mPackagePreferences.size();
diff --git a/services/core/java/com/android/server/notification/RankingConfig.java b/services/core/java/com/android/server/notification/RankingConfig.java
index b2827bae40bc..8991ced21fbd 100644
--- a/services/core/java/com/android/server/notification/RankingConfig.java
+++ b/services/core/java/com/android/server/notification/RankingConfig.java
@@ -34,6 +34,8 @@ public interface RankingConfig {
/** Returns true when feature is enabled that shows media notifications in quick settings. */
boolean isMediaNotificationFilteringEnabled();
boolean isGroupBlocked(String packageName, int uid, String groupId);
+ boolean canShowNotificationsOnLockscreen(int userId);
+ boolean canShowPrivateNotificationsOnLockScreen(int userId);
Collection<NotificationChannelGroup> getNotificationChannelGroups(String pkg,
int uid);
diff --git a/services/core/java/com/android/server/notification/SnoozeHelper.java b/services/core/java/com/android/server/notification/SnoozeHelper.java
index b5ca2abf8afe..2122b9c19805 100644
--- a/services/core/java/com/android/server/notification/SnoozeHelper.java
+++ b/services/core/java/com/android/server/notification/SnoozeHelper.java
@@ -558,8 +558,8 @@ public class SnoozeHelper {
if (value < currentTime) {
return;
}
- out.attribute(null, XML_SNOOZED_NOTIFICATION_TIME,
- value.toString());
+ out.attributeLong(null, XML_SNOOZED_NOTIFICATION_TIME,
+ value);
});
writeXml(out, mPersistedSnoozedNotificationsWithContext,
XML_SNOOZED_NOTIFICATION_CONTEXT,
diff --git a/services/core/java/com/android/server/notification/VisibilityExtractor.java b/services/core/java/com/android/server/notification/VisibilityExtractor.java
index db548465d4b8..a363601b56e9 100644
--- a/services/core/java/com/android/server/notification/VisibilityExtractor.java
+++ b/services/core/java/com/android/server/notification/VisibilityExtractor.java
@@ -15,8 +15,11 @@
*/
package com.android.server.notification;
+import android.app.Notification;
+import android.app.NotificationManager;
+import android.app.admin.DevicePolicyManager;
import android.content.Context;
-import android.service.notification.NotificationListenerService;
+import android.os.UserHandle;
import android.util.Slog;
/**
@@ -27,9 +30,11 @@ public class VisibilityExtractor implements NotificationSignalExtractor {
private static final boolean DBG = false;
private RankingConfig mConfig;
+ private DevicePolicyManager mDpm;
public void initialize(Context ctx, NotificationUsageStats usageStats) {
if (DBG) Slog.d(TAG, "Initializing " + getClass().getSimpleName() + ".");
+ mDpm = ctx.getSystemService(DevicePolicyManager.class);
}
public RankingReconsideration process(NotificationRecord record) {
@@ -43,7 +48,38 @@ public class VisibilityExtractor implements NotificationSignalExtractor {
return null;
}
- record.setPackageVisibilityOverride(record.getChannel().getLockscreenVisibility());
+ int userId = record.getUserId();
+
+ if (userId == UserHandle.USER_ALL) {
+ record.setPackageVisibilityOverride(record.getChannel().getLockscreenVisibility());
+ } else {
+ boolean userCanShowNotifications =
+ mConfig.canShowNotificationsOnLockscreen(userId);
+ boolean dpmCanShowNotifications = adminAllowsKeyguardFeature(userId,
+ DevicePolicyManager.KEYGUARD_DISABLE_SECURE_NOTIFICATIONS);
+ boolean channelCanShowNotifications = record.getChannel().getLockscreenVisibility()
+ != Notification.VISIBILITY_SECRET;
+
+ if (!userCanShowNotifications || !dpmCanShowNotifications
+ || !channelCanShowNotifications) {
+ record.setPackageVisibilityOverride(Notification.VISIBILITY_SECRET);
+ } else {
+ // notifications are allowed but should they be redacted?
+
+ boolean userCanShowContents =
+ mConfig.canShowPrivateNotificationsOnLockScreen(userId);
+ boolean dpmCanShowContents = adminAllowsKeyguardFeature(userId,
+ DevicePolicyManager.KEYGUARD_DISABLE_UNREDACTED_NOTIFICATIONS);
+ boolean channelCanShowContents = record.getChannel().getLockscreenVisibility()
+ != Notification.VISIBILITY_PRIVATE;
+
+ if (!userCanShowContents || !dpmCanShowContents || !channelCanShowContents) {
+ record.setPackageVisibilityOverride(Notification.VISIBILITY_PRIVATE);
+ } else {
+ record.setPackageVisibilityOverride(NotificationManager.VISIBILITY_NO_OVERRIDE);
+ }
+ }
+ }
return null;
}
@@ -57,4 +93,13 @@ public class VisibilityExtractor implements NotificationSignalExtractor {
public void setZenHelper(ZenModeHelper helper) {
}
+
+ private boolean adminAllowsKeyguardFeature(int userHandle, int feature) {
+ if (userHandle == UserHandle.USER_ALL) {
+ return true;
+ }
+ final int dpmFlags = mDpm.getKeyguardDisabledFeatures(null /* admin */, userHandle);
+ return (dpmFlags & feature) == 0;
+ }
+
}
diff --git a/services/core/java/com/android/server/notification/ZenModeHelper.java b/services/core/java/com/android/server/notification/ZenModeHelper.java
index 94f46ba6bc60..5cd22e0bd72d 100644
--- a/services/core/java/com/android/server/notification/ZenModeHelper.java
+++ b/services/core/java/com/android/server/notification/ZenModeHelper.java
@@ -81,6 +81,7 @@ import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.logging.MetricsLogger;
import com.android.internal.messages.nano.SystemMessageProto.SystemMessage;
import com.android.internal.notification.SystemNotificationChannels;
+import com.android.internal.util.XmlUtils;
import com.android.server.LocalServices;
import libcore.io.IoUtils;
@@ -1165,7 +1166,7 @@ public class ZenModeHelper {
try {
parser = resources.getXml(R.xml.default_zen_mode_config);
while (parser.next() != XmlPullParser.END_DOCUMENT) {
- final ZenModeConfig config = ZenModeConfig.readXml(parser);
+ final ZenModeConfig config = ZenModeConfig.readXml(XmlUtils.makeTyped(parser));
if (config != null) return config;
}
} catch (Exception e) {
diff --git a/services/core/java/com/android/server/pm/DefaultAppProvider.java b/services/core/java/com/android/server/pm/DefaultAppProvider.java
new file mode 100644
index 000000000000..cc11fb2c00bd
--- /dev/null
+++ b/services/core/java/com/android/server/pm/DefaultAppProvider.java
@@ -0,0 +1,187 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.server.pm;
+
+import android.annotation.NonNull;
+import android.annotation.Nullable;
+import android.annotation.UserIdInt;
+import android.app.role.RoleManager;
+import android.os.Binder;
+import android.os.UserHandle;
+import android.util.Slog;
+
+import com.android.internal.infra.AndroidFuture;
+import com.android.internal.util.CollectionUtils;
+import com.android.server.FgThread;
+import com.android.server.pm.permission.PermissionManagerServiceInternal;
+
+import java.util.concurrent.ExecutionException;
+import java.util.concurrent.Executor;
+import java.util.concurrent.TimeUnit;
+import java.util.concurrent.TimeoutException;
+import java.util.function.Consumer;
+import java.util.function.Supplier;
+
+/**
+ * Interacts with {@link RoleManager} to provide and manage default apps.
+ */
+public class DefaultAppProvider {
+ @NonNull
+ private final Supplier<RoleManager> mRoleManagerSupplier;
+ @NonNull
+ private final PermissionManagerServiceInternal mPermissionManager;
+
+ /**
+ * Create a new instance of this class
+ *
+ * @param roleManagerSupplier the supplier for {@link RoleManager}
+ * @param permissionManager the {@link PermissionManagerServiceInternal}
+ */
+ public DefaultAppProvider(@NonNull Supplier<RoleManager> roleManagerSupplier, @NonNull
+ PermissionManagerServiceInternal permissionManager) {
+ mRoleManagerSupplier = roleManagerSupplier;
+ mPermissionManager = permissionManager;
+ }
+
+ /**
+ * Get the package name of the default browser.
+ *
+ * @param userId the user ID
+ * @return the package name of the default browser, or {@code null} if none
+ */
+ @Nullable
+ public String getDefaultBrowser(@UserIdInt int userId) {
+ return getRoleHolder(RoleManager.ROLE_BROWSER, userId);
+ }
+
+ /**
+ * Set the package name of the default browser.
+ *
+ * @param packageName package name of the default browser, or {@code null} to unset
+ * @param async whether the operation should be asynchronous
+ * @param doGrant whether to grant default permissions
+ * @param userId the user ID
+ * @return whether the default browser was successfully set.
+ */
+ public boolean setDefaultBrowser(@Nullable String packageName, boolean async, boolean doGrant,
+ @UserIdInt int userId) {
+ if (userId == UserHandle.USER_ALL) {
+ return false;
+ }
+ final RoleManager roleManager = mRoleManagerSupplier.get();
+ if (roleManager == null) {
+ return false;
+ }
+ final UserHandle user = UserHandle.of(userId);
+ final Executor executor = FgThread.getExecutor();
+ final AndroidFuture<Void> future = new AndroidFuture<>();
+ final Consumer<Boolean> callback = successful -> {
+ if (successful) {
+ future.complete(null);
+ } else {
+ future.completeExceptionally(new RuntimeException());
+ }
+ };
+ final long identity = Binder.clearCallingIdentity();
+ try {
+ if (packageName != null) {
+ roleManager.addRoleHolderAsUser(RoleManager.ROLE_BROWSER, packageName, 0, user,
+ executor, callback);
+ } else {
+ roleManager.clearRoleHoldersAsUser(RoleManager.ROLE_BROWSER, 0, user, executor,
+ callback);
+ }
+ if (!async) {
+ try {
+ future.get(5, TimeUnit.SECONDS);
+ } catch (InterruptedException | ExecutionException | TimeoutException e) {
+ Slog.e(PackageManagerService.TAG, "Exception while setting default browser: "
+ + packageName, e);
+ return false;
+ }
+ }
+ if (doGrant && packageName != null) {
+ mPermissionManager.grantDefaultPermissionsToDefaultBrowser(packageName, userId);
+ }
+ } finally {
+ Binder.restoreCallingIdentity(identity);
+ }
+ return true;
+ }
+
+ /**
+ * Get the package name of the default dialer.
+ *
+ * @param userId the user ID
+ * @return the package name of the default dialer, or {@code null} if none
+ */
+ @Nullable
+ public String getDefaultDialer(@NonNull int userId) {
+ return getRoleHolder(RoleManager.ROLE_DIALER, userId);
+ }
+
+ /**
+ * Get the package name of the default home.
+ *
+ * @param userId the user ID
+ * @return the package name of the default home, or {@code null} if none
+ */
+ @Nullable
+ public String getDefaultHome(@NonNull int userId) {
+ return getRoleHolder(RoleManager.ROLE_HOME, userId);
+ }
+
+ /**
+ * Set the package name of the default home.
+ *
+ * @param packageName package name of the default home
+ * @param userId the user ID
+ * @param executor the {@link Executor} to execute callback on
+ * @param callback the callback made after the default home as been updated
+ * @return whether the default home was set
+ */
+ public boolean setDefaultHome(@NonNull String packageName, @UserIdInt int userId,
+ @NonNull Executor executor, @NonNull Consumer<Boolean> callback) {
+ final RoleManager roleManager = mRoleManagerSupplier.get();
+ if (roleManager == null) {
+ return false;
+ }
+ final long identity = Binder.clearCallingIdentity();
+ try {
+ roleManager.addRoleHolderAsUser(RoleManager.ROLE_HOME, packageName, 0,
+ UserHandle.of(userId), executor, callback);
+ } finally {
+ Binder.restoreCallingIdentity(identity);
+ }
+ return true;
+ }
+
+ @Nullable
+ private String getRoleHolder(@NonNull String roleName, @NonNull int userId) {
+ final RoleManager roleManager = mRoleManagerSupplier.get();
+ if (roleManager == null) {
+ return null;
+ }
+ final long identity = Binder.clearCallingIdentity();
+ try {
+ return CollectionUtils.firstOrNull(roleManager.getRoleHoldersAsUser(roleName,
+ UserHandle.of(userId)));
+ } finally {
+ Binder.restoreCallingIdentity(identity);
+ }
+ }
+}
diff --git a/services/core/java/com/android/server/pm/PackageAbiHelper.java b/services/core/java/com/android/server/pm/PackageAbiHelper.java
index 30b1c2c93a45..24a3e520fe1b 100644
--- a/services/core/java/com/android/server/pm/PackageAbiHelper.java
+++ b/services/core/java/com/android/server/pm/PackageAbiHelper.java
@@ -55,7 +55,7 @@ public interface PackageAbiHelper {
* If {@code extractLibs} is true, native libraries are extracted from the app if required.
*/
Pair<Abis, NativeLibraryPaths> derivePackageAbi(AndroidPackage pkg, boolean isUpdatedSystemApp,
- String cpuAbiOverride) throws PackageManagerException;
+ String cpuAbiOverride, File appLib32InstallDir) throws PackageManagerException;
/**
* Calculates adjusted ABIs for a set of packages belonging to a shared user so that they all
diff --git a/services/core/java/com/android/server/pm/PackageAbiHelperImpl.java b/services/core/java/com/android/server/pm/PackageAbiHelperImpl.java
index da4ea16d0bfd..71b99bd4ced2 100644
--- a/services/core/java/com/android/server/pm/PackageAbiHelperImpl.java
+++ b/services/core/java/com/android/server/pm/PackageAbiHelperImpl.java
@@ -296,7 +296,7 @@ final class PackageAbiHelperImpl implements PackageAbiHelper {
@Override
public Pair<Abis, NativeLibraryPaths> derivePackageAbi(AndroidPackage pkg,
- boolean isUpdatedSystemApp, String cpuAbiOverride)
+ boolean isUpdatedSystemApp, String cpuAbiOverride, File appLib32InstallDir)
throws PackageManagerException {
// Give ourselves some initial paths; we'll come back for another
// pass once we've determined ABI below.
@@ -304,7 +304,7 @@ final class PackageAbiHelperImpl implements PackageAbiHelper {
String pkgRawSecondaryCpuAbi = AndroidPackageUtils.getRawSecondaryCpuAbi(pkg);
final NativeLibraryPaths initialLibraryPaths = deriveNativeLibraryPaths(
new Abis(pkgRawPrimaryCpuAbi, pkgRawSecondaryCpuAbi),
- PackageManagerService.sAppLib32InstallDir, pkg.getPath(),
+ appLib32InstallDir, pkg.getPath(),
pkg.getBaseApkPath(), pkg.isSystem(),
isUpdatedSystemApp);
@@ -452,7 +452,7 @@ final class PackageAbiHelperImpl implements PackageAbiHelper {
final Abis abis = new Abis(primaryCpuAbi, secondaryCpuAbi);
return new Pair<>(abis,
- deriveNativeLibraryPaths(abis, PackageManagerService.sAppLib32InstallDir,
+ deriveNativeLibraryPaths(abis, appLib32InstallDir,
pkg.getPath(), pkg.getBaseApkPath(), pkg.isSystem(),
isUpdatedSystemApp));
}
diff --git a/services/core/java/com/android/server/pm/PackageInstallerSession.java b/services/core/java/com/android/server/pm/PackageInstallerSession.java
index ade0b42664d9..0aebe721b103 100644
--- a/services/core/java/com/android/server/pm/PackageInstallerSession.java
+++ b/services/core/java/com/android/server/pm/PackageInstallerSession.java
@@ -104,6 +104,7 @@ import android.os.ParcelableException;
import android.os.Process;
import android.os.RemoteException;
import android.os.RevocableFileDescriptor;
+import android.os.SELinux;
import android.os.SystemProperties;
import android.os.UserHandle;
import android.os.incremental.IStorageHealthListener;
@@ -1088,6 +1089,31 @@ public class PackageInstallerSession extends IPackageInstallerSession.Stub {
}
}
+ @Override
+ public void stageViaHardLink(String path) {
+ final int callingUid = Binder.getCallingUid();
+ if (callingUid != Process.SYSTEM_UID) {
+ throw new SecurityException("link() can only be run by the system");
+ }
+
+ try {
+ final File target = new File(path);
+ final File source = new File(stageDir, target.getName());
+ try {
+ Os.link(path, source.getAbsolutePath());
+ // Grant READ access for APK to be read successfully
+ Os.chmod(source.getAbsolutePath(), 0644);
+ } catch (ErrnoException e) {
+ e.rethrowAsIOException();
+ }
+ if (!SELinux.restorecon(source)) {
+ throw new IOException("Can't relabel file: " + source);
+ }
+ } catch (IOException e) {
+ throw ExceptionUtils.wrap(e);
+ }
+ }
+
private ParcelFileDescriptor openTargetInternal(String path, int flags, int mode)
throws IOException, ErrnoException {
// TODO: this should delegate to DCS so the system process avoids
diff --git a/services/core/java/com/android/server/pm/PackageManagerService.java b/services/core/java/com/android/server/pm/PackageManagerService.java
index 9a0be06b914e..6aa4589cad98 100644
--- a/services/core/java/com/android/server/pm/PackageManagerService.java
+++ b/services/core/java/com/android/server/pm/PackageManagerService.java
@@ -152,6 +152,7 @@ import android.app.ResourcesManager;
import android.app.admin.IDevicePolicyManager;
import android.app.admin.SecurityLog;
import android.app.backup.IBackupManager;
+import android.app.role.RoleManager;
import android.compat.annotation.ChangeId;
import android.compat.annotation.EnabledAfter;
import android.content.BroadcastReceiver;
@@ -448,7 +449,6 @@ import java.util.concurrent.atomic.AtomicInteger;
import java.util.function.BiConsumer;
import java.util.function.Consumer;
import java.util.function.Predicate;
-import java.util.function.Supplier;
/**
* Keep track of all those APKs everywhere.
@@ -732,8 +732,6 @@ public class PackageManagerService extends IPackageManager.Stub
private static final int INCREMENTAL_STORAGE_UNHEALTHY_TIMEOUT_MS = 7000;
private static final int INCREMENTAL_STORAGE_UNHEALTHY_MONITORING_MS = 60000;
- final ServiceThread mHandlerThread;
-
final Handler mHandler;
private final ProcessLoggingHandler mProcessLoggingHandler;
@@ -761,12 +759,14 @@ public class PackageManagerService extends IPackageManager.Stub
final Installer mInstaller;
/** Directory where installed applications are stored */
- private static final File sAppInstallDir =
- new File(Environment.getDataDirectory(), "app");
+ private final File mAppInstallDir;
/** Directory where installed application's 32-bit native libraries are copied. */
@VisibleForTesting
- static final File sAppLib32InstallDir =
- new File(Environment.getDataDirectory(), "app-lib");
+ final File mAppLib32InstallDir;
+
+ private static File getAppLib32InstallDir() {
+ return new File(Environment.getDataDirectory(), "app-lib");
+ }
// ----------------------------------------------------------------
@@ -832,6 +832,11 @@ public class PackageManagerService extends IPackageManager.Stub
boolean mFirstBoot;
+ private final boolean mIsEngBuild;
+ private final boolean mIsUserDebugBuild;
+ private final String mIncrementalVersion;
+
+
PackageManagerInternal.ExternalSourcesPolicy mExternalSourcesPolicy;
@GuardedBy("mAvailableFeatures")
@@ -866,6 +871,8 @@ public class PackageManagerService extends IPackageManager.Stub
private final Injector mInjector;
+ private final SystemWrapper mSystemWrapper;
+
/**
* The list of all system partitions that may contain packages in ascending order of
* specificity (the more generic, the earlier in the list a partition appears).
@@ -896,6 +903,10 @@ public class PackageManagerService extends IPackageManager.Stub
T produce(Injector injector, PackageManagerService packageManager);
}
+ interface ProducerWithArgument<T, R> {
+ T produce(Injector injector, PackageManagerService packageManager, R argument);
+ }
+
interface ServiceProducer {
<T> T produce(Class<T> c);
}
@@ -924,6 +935,8 @@ public class PackageManagerService extends IPackageManager.Stub
private final Object mInstallLock;
private final Handler mBackgroundHandler;
private final Executor mBackgroundExecutor;
+ private final List<ScanPartition> mSystemPartitions;
+
// ----- producers -----
private final Singleton<ComponentResolver> mComponentResolverProducer;
@@ -940,13 +953,23 @@ public class PackageManagerService extends IPackageManager.Stub
private final Singleton<ViewCompiler> mViewCompilerProducer;
private final Singleton<IPermissionManager> mPermissionManagerProducer;
private final Singleton<IncrementalManager> mIncrementalManagerProducer;
+ private final Singleton<DefaultAppProvider> mDefaultAppProviderProducer;
+ private final Singleton<DisplayMetrics> mDisplayMetricsProducer;
+ private final Producer<PackageParser2> mScanningCachingPackageParserProducer;
+ private final Producer<PackageParser2> mScanningPackageParserProducer;
+ private final Producer<PackageParser2> mPreparingPackageParserProducer;
+ private final Singleton<PackageInstallerService> mPackageInstallerServiceProducer;
+ private final ProducerWithArgument<InstantAppResolverConnection, ComponentName>
+ mInstantAppResolverConnectionProducer;
private final SystemWrapper mSystemWrapper;
private final ServiceProducer mGetLocalServiceProducer;
private final ServiceProducer mGetSystemServiceProducer;
+ private final Singleton<ModuleInfoProvider> mModuleInfoProviderProducer;
Injector(Context context, Object lock, Installer installer,
Object installLock, PackageAbiHelper abiHelper,
Handler backgroundHandler,
+ List<ScanPartition> systemPartitions,
Producer<ComponentResolver> componentResolverProducer,
Producer<PermissionManagerServiceInternal> permissionManagerServiceProducer,
Producer<UserManagerService> userManagerProducer,
@@ -961,6 +984,15 @@ public class PackageManagerService extends IPackageManager.Stub
Producer<IPermissionManager> permissionManagerProducer,
Producer<ViewCompiler> viewCompilerProducer,
Producer<IncrementalManager> incrementalManagerProducer,
+ Producer<DefaultAppProvider> defaultAppProviderProducer,
+ Producer<DisplayMetrics> displayMetricsProducer,
+ Producer<PackageParser2> scanningCachingPackageParserProducer,
+ Producer<PackageParser2> scanningPackageParserProducer,
+ Producer<PackageParser2> preparingPackageParserProducer,
+ Producer<PackageInstallerService> packageInstallerServiceProducer,
+ ProducerWithArgument<InstantAppResolverConnection, ComponentName>
+ instantAppResolverConnectionProducer,
+ Producer<ModuleInfoProvider> moduleInfoProviderProducer,
SystemWrapper systemWrapper,
ServiceProducer getLocalServiceProducer,
ServiceProducer getSystemServiceProducer) {
@@ -971,6 +1003,7 @@ public class PackageManagerService extends IPackageManager.Stub
mInstallLock = installLock;
mBackgroundHandler = backgroundHandler;
mBackgroundExecutor = new HandlerExecutor(backgroundHandler);
+ mSystemPartitions = systemPartitions;
mComponentResolverProducer = new Singleton<>(componentResolverProducer);
mPermissionManagerServiceProducer = new Singleton<>(permissionManagerServiceProducer);
mUserManagerProducer = new Singleton<>(userManagerProducer);
@@ -985,6 +1018,14 @@ public class PackageManagerService extends IPackageManager.Stub
mPermissionManagerProducer = new Singleton<>(permissionManagerProducer);
mViewCompilerProducer = new Singleton<>(viewCompilerProducer);
mIncrementalManagerProducer = new Singleton<>(incrementalManagerProducer);
+ mDefaultAppProviderProducer = new Singleton<>(defaultAppProviderProducer);
+ mDisplayMetricsProducer = new Singleton<>(displayMetricsProducer);
+ mScanningCachingPackageParserProducer = scanningCachingPackageParserProducer;
+ mScanningPackageParserProducer = scanningPackageParserProducer;
+ mPreparingPackageParserProducer = preparingPackageParserProducer;
+ mPackageInstallerServiceProducer = new Singleton<>(packageInstallerServiceProducer);
+ mInstantAppResolverConnectionProducer = instantAppResolverConnectionProducer;
+ mModuleInfoProviderProducer = new Singleton<>(moduleInfoProviderProducer);
mSystemWrapper = systemWrapper;
mGetLocalServiceProducer = getLocalServiceProducer;
mGetSystemServiceProducer = getSystemServiceProducer;
@@ -1010,6 +1051,10 @@ public class PackageManagerService extends IPackageManager.Stub
return mInstallLock;
}
+ public List<ScanPartition> getSystemPartitions() {
+ return mSystemPartitions;
+ }
+
public UserManagerService getUserManagerService() {
return mUserManagerProducer.get(this, mPackageManager);
}
@@ -1082,6 +1127,10 @@ public class PackageManagerService extends IPackageManager.Stub
return mBackgroundExecutor;
}
+ public DisplayMetrics getDisplayMetrics() {
+ return mDisplayMetricsProducer.get(this, mPackageManager);
+ }
+
public <T> T getLocalService(Class<T> c) {
return mGetLocalServiceProducer.produce(c);
}
@@ -1097,53 +1146,63 @@ public class PackageManagerService extends IPackageManager.Stub
public IncrementalManager getIncrementalManager() {
return mIncrementalManagerProducer.get(this, mPackageManager);
}
- }
- /** Provides an abstraction to static access to system state. */
- public interface SystemWrapper {
- /** @see SystemProperties#get(String) */
- String getProperty(String key);
- /** @see SystemProperties#getInt(String, int) */
- int getPropertyInt(String key, int defValue);
- /** @see SystemProperties#getBoolean(String, boolean) */
- boolean getPropertyBoolean(String key, boolean defValue);
- /** @see SystemProperties#digestOf(String...) */
- String digestOfProperties(@NonNull String... keys);
- /** @see SystemProperties#set(String, String) */
- void setProperty(String key, String value);
- /** @see Build.VERSION#SDK_INT */
- int getSdkInt();
- }
+ public DefaultAppProvider getDefaultAppProvider() {
+ return mDefaultAppProviderProducer.get(this, mPackageManager);
+ }
- private static class DefaultSystemWrapper implements SystemWrapper {
- @Override
- public String getProperty(String key) {
- return SystemProperties.get(key);
+ public PackageParser2 getScanningCachingPackageParser() {
+ return mScanningCachingPackageParserProducer.produce(this, mPackageManager);
+ }
+ public PackageParser2 getScanningPackageParser() {
+ return mScanningPackageParserProducer.produce(this, mPackageManager);
+ }
+ public PackageParser2 getPreparingPackageParser() {
+ return mPreparingPackageParserProducer.produce(this, mPackageManager);
}
- @Override
- public int getPropertyInt(String key, int defValue) {
- return SystemProperties.getInt(key, defValue);
+ public PackageInstallerService getPackageInstallerService() {
+ return mPackageInstallerServiceProducer.get(this, mPackageManager);
}
- @Override
- public boolean getPropertyBoolean(String key, boolean defValue) {
- return SystemProperties.getBoolean(key, defValue);
+ public InstantAppResolverConnection getInstantAppResolverConnection(
+ ComponentName instantAppResolverComponent) {
+ return mInstantAppResolverConnectionProducer.produce(
+ this, mPackageManager, instantAppResolverComponent);
}
- @Override
- public String digestOfProperties(String... keys) {
- return SystemProperties.digestOf(keys);
+ public ModuleInfoProvider getModuleInfoProvider() {
+ return mModuleInfoProviderProducer.get(this, mPackageManager);
}
+ }
+
+ /** Provides an abstraction to static access to system state. */
+ public interface SystemWrapper {
+ void disablePackageCaches();
+ void enablePackageCaches();
+ }
+
+ private static class DefaultSystemWrapper implements SystemWrapper {
@Override
- public void setProperty(String key, String value) {
- SystemProperties.set(key, value);
+ public void disablePackageCaches() {
+ // disable all package caches that shouldn't apply within system server
+ PackageManager.disableApplicationInfoCache();
+ PackageManager.disablePackageInfoCache();
+ ApplicationPackageManager.invalidateGetPackagesForUidCache();
+ ApplicationPackageManager.disableGetPackagesForUidCache();
+ ApplicationPackageManager.invalidateHasSystemFeatureCache();
+
+ // Avoid invalidation-thrashing by preventing cache invalidations from causing property
+ // writes if the cache isn't enabled yet. We re-enable writes later when we're
+ // done initializing.
+ PackageManager.corkPackageInfoCache();
}
@Override
- public int getSdkInt() {
- return Build.VERSION.SDK_INT;
+ public void enablePackageCaches() {
+ // Uncork cache invalidations and allow clients to cache package information.
+ PackageManager.uncorkPackageInfoCache();
}
}
@@ -1154,13 +1213,13 @@ public class PackageManagerService extends IPackageManager.Stub
public ArtManagerService artManagerService;
public @Nullable String configuratorPackage;
public int defParseFlags;
+ public DefaultAppProvider defaultAppProvider;
public DexManager dexManager;
public List<ScanPartition> dirsToScanAsSystem;
public @Nullable String documenterPackage;
public boolean factoryTest;
public ArrayMap<String, FeatureInfo> availableFeatures;
public Handler handler;
- public ServiceThread handlerThread;
public @Nullable String incidentReportApproverPackage;
public IncrementalManager incrementalManager;
public PackageInstallerService installerService;
@@ -1206,6 +1265,13 @@ public class PackageManagerService extends IPackageManager.Stub
public ArrayMap<String, AndroidPackage> packages;
public boolean enableFreeCacheV2;
public int sdkVersion;
+ public SystemWrapper systemWrapper;
+ public File appInstallDir;
+ public File appLib32InstallDir;
+ public boolean isEngBuild;
+ public boolean isUserDebugBuild;
+ public int sdkInt = Build.VERSION.SDK_INT;
+ public String incrementalVersion = Build.VERSION.INCREMENTAL;
}
private final AppsFilter mAppsFilter;
@@ -1307,6 +1373,8 @@ public class PackageManagerService extends IPackageManager.Stub
private final IncrementalManager mIncrementalManager;
+ private final DefaultAppProvider mDefaultAppProvider;
+
private final PackageProperty mPackageProperty = new PackageProperty();
private static class IFVerificationParams {
@@ -1803,7 +1871,7 @@ public class PackageManagerService extends IPackageManager.Stub
for (int index = 0; i < size && index < numComponents; index++) {
packages[i] = componentsToBroadcast.keyAt(index);
components[i] = componentsToBroadcast.valueAt(index);
- final PackageSetting ps = mSettings.mPackages.get(packages[i]);
+ final PackageSetting ps = mSettings.getPackageLPr(packages[i]);
uids[i] = (ps != null)
? UserHandle.getUid(packageUserId, ps.appId)
: -1;
@@ -2310,7 +2378,7 @@ public class PackageManagerService extends IPackageManager.Stub
synchronized (mLock) {
newBroadcastAllowList = mAppsFilter.getVisibilityAllowList(
getPackageSettingInternal(res.name, Process.SYSTEM_UID),
- updateUserIds, mSettings.mPackages);
+ updateUserIds, mSettings.getPackagesLocked());
}
sendPackageBroadcast(Intent.ACTION_PACKAGE_ADDED, packageName,
extras, 0 /*flags*/,
@@ -2747,6 +2815,7 @@ public class PackageManagerService extends IPackageManager.Stub
Injector injector = new Injector(
context, lock, installer, installLock, new PackageAbiHelperImpl(),
backgroundHandler,
+ SYSTEM_PARTITIONS,
(i, pm) -> new ComponentResolver(i.getUserManagerService(), pm.mPmInternal, lock),
(i, pm) -> PermissionManagerService.create(context),
(i, pm) -> new UserManagerService(context, pm,
@@ -2768,12 +2837,37 @@ public class PackageManagerService extends IPackageManager.Stub
(i, pm) -> (IPermissionManager) ServiceManager.getService("permissionmgr"),
(i, pm) -> new ViewCompiler(i.getInstallLock(), i.getInstaller()),
(i, pm) -> (IncrementalManager)
- pm.mContext.getSystemService(Context.INCREMENTAL_SERVICE),
+ i.getContext().getSystemService(Context.INCREMENTAL_SERVICE),
+ (i, pm) -> new DefaultAppProvider(() -> context.getSystemService(RoleManager.class),
+ i.getPermissionManagerServiceInternal()),
+ (i, pm) -> new DisplayMetrics(),
+ (i, pm) -> new PackageParser2(pm.mSeparateProcesses, pm.mOnlyCore,
+ i.getDisplayMetrics(), pm.mCacheDir,
+ pm.mPackageParserCallback) /* scanningCachingPackageParserProducer */,
+ (i, pm) -> new PackageParser2(pm.mSeparateProcesses, pm.mOnlyCore,
+ i.getDisplayMetrics(), null,
+ pm.mPackageParserCallback) /* scanningPackageParserProducer */,
+ (i, pm) -> new PackageParser2(pm.mSeparateProcesses, false, i.getDisplayMetrics(),
+ null, pm.mPackageParserCallback) /* preparingPackageParserProducer */,
+ // Prepare a supplier of package parser for the staging manager to parse apex file
+ // during the staging installation.
+ (i, pm) -> new PackageInstallerService(
+ i.getContext(), pm, i::getScanningPackageParser),
+ (i, pm, cn) -> new InstantAppResolverConnection(
+ i.getContext(), cn, Intent.ACTION_RESOLVE_INSTANT_APP_PACKAGE),
+ (i, pm) -> new ModuleInfoProvider(i.getContext(), pm),
new DefaultSystemWrapper(),
LocalServices::getService,
context::getSystemService);
- PackageManagerService m = new PackageManagerService(injector, onlyCore, factoryTest);
+
+ if (Build.VERSION.SDK_INT <= 0) {
+ Slog.w(TAG, "**** ro.build.version.sdk not set!");
+ }
+
+ PackageManagerService m = new PackageManagerService(injector, onlyCore, factoryTest,
+ Build.FINGERPRINT, Build.IS_ENG, Build.IS_USERDEBUG, Build.VERSION.SDK_INT,
+ Build.VERSION.INCREMENTAL);
t.traceEnd(); // "create package manager"
final CompatChange.ChangeListener selinuxChangeListener = packageName -> {
@@ -2833,11 +2927,6 @@ public class PackageManagerService extends IPackageManager.Stub
}
}
- private static void getDefaultDisplayMetrics(
- DisplayManager displayManager, DisplayMetrics metrics) {
- displayManager.getDisplay(Display.DEFAULT_DISPLAY).getMetrics(metrics);
- }
-
/**
* Requests that files preopted on a secondary system partition be copied to the data partition
* if possible. Note that the actual copying of the files is accomplished by init for security
@@ -2847,14 +2936,13 @@ public class PackageManagerService extends IPackageManager.Stub
private static void requestCopyPreoptedFiles(Injector injector) {
final int WAIT_TIME_MS = 100;
final String CP_PREOPT_PROPERTY = "sys.cppreopt";
- if (injector.getSystemWrapper().getPropertyInt("ro.cp_system_other_odex", 0) == 1) {
- injector.getSystemWrapper().setProperty(CP_PREOPT_PROPERTY, "requested");
+ if (SystemProperties.getInt("ro.cp_system_other_odex", 0) == 1) {
+ SystemProperties.set(CP_PREOPT_PROPERTY, "requested");
// We will wait for up to 100 seconds.
final long timeStart = SystemClock.uptimeMillis();
final long timeEnd = timeStart + 100 * 1000;
long timeNow = timeStart;
- while (!injector.getSystemWrapper()
- .getProperty(CP_PREOPT_PROPERTY).equals("finished")) {
+ while (!SystemProperties.get(CP_PREOPT_PROPERTY).equals("finished")) {
try {
Thread.sleep(WAIT_TIME_MS);
} catch (InterruptedException e) {
@@ -2862,7 +2950,7 @@ public class PackageManagerService extends IPackageManager.Stub
}
timeNow = SystemClock.uptimeMillis();
if (timeNow > timeEnd) {
- injector.getSystemWrapper().setProperty(CP_PREOPT_PROPERTY, "timed-out");
+ SystemProperties.set(CP_PREOPT_PROPERTY, "timed-out");
Slog.wtf(TAG, "cppreopt did not finish!");
break;
}
@@ -2939,16 +3027,15 @@ public class PackageManagerService extends IPackageManager.Stub
mPermissionManager = injector.getPermissionManagerServiceInternal();
mSettings = injector.getSettings();
mUserManager = injector.getUserManagerService();
-
mApexManager = testParams.apexManager;
mArtManagerService = testParams.artManagerService;
mAvailableFeatures = testParams.availableFeatures;
mDefParseFlags = testParams.defParseFlags;
+ mDefaultAppProvider = testParams.defaultAppProvider;
mDexManager = testParams.dexManager;
mDirsToScanAsSystem = testParams.dirsToScanAsSystem;
mFactoryTest = testParams.factoryTest;
mHandler = testParams.handler;
- mHandlerThread = testParams.handlerThread;
mIncrementalManager = testParams.incrementalManager;
mInstallerService = testParams.installerService;
mInstantAppRegistry = testParams.instantAppRegistry;
@@ -2993,49 +3080,46 @@ public class PackageManagerService extends IPackageManager.Stub
mServicesExtensionPackageName = testParams.servicesExtensionPackageName;
mSharedSystemSharedLibraryPackageName = testParams.sharedSystemSharedLibraryPackageName;
mOverlayConfigSignaturePackage = testParams.overlayConfigSignaturePackage;
-
mResolveComponentName = testParams.resolveComponentName;
mPackages.putAll(testParams.packages);
mEnableFreeCacheV2 = testParams.enableFreeCacheV2;
mSdkVersion = testParams.sdkVersion;
- }
-
- public PackageManagerService(Injector injector, boolean onlyCore, boolean factoryTest) {
- PackageManager.disableApplicationInfoCache();
- PackageManager.disablePackageInfoCache();
- ApplicationPackageManager.invalidateGetPackagesForUidCache();
- ApplicationPackageManager.disableGetPackagesForUidCache();
- ApplicationPackageManager.invalidateHasSystemFeatureCache();
-
- // Avoid invalidation-thrashing by preventing cache invalidations from causing property
- // writes if the cache isn't enabled yet. We re-enable writes later when we're
- // done initializing.
- PackageManager.corkPackageInfoCache();
+ mSystemWrapper = testParams.systemWrapper;
+ mAppInstallDir = testParams.appInstallDir;
+ mAppLib32InstallDir = testParams.appLib32InstallDir;
+ mIsEngBuild = testParams.isEngBuild;
+ mIsUserDebugBuild = testParams.isUserDebugBuild;
+ mIncrementalVersion = testParams.incrementalVersion;
+ }
+
+ public PackageManagerService(Injector injector, boolean onlyCore, boolean factoryTest,
+ final String buildFingerprint, final boolean isEngBuild,
+ final boolean isUserDebugBuild, final int sdkVersion, final String incrementalVersion) {
+ mIsEngBuild = isEngBuild;
+ mIsUserDebugBuild = isUserDebugBuild;
+ mSdkVersion = sdkVersion;
+ mIncrementalVersion = incrementalVersion;
+ mInjector = injector;
+ mInjector.getSystemWrapper().disablePackageCaches();
final TimingsTraceAndSlog t = new TimingsTraceAndSlog(TAG + "Timing",
Trace.TRACE_TAG_PACKAGE_MANAGER);
mPendingBroadcasts = new PendingPackageBroadcasts();
- mInjector = injector;
mInjector.bootstrap(this);
mLock = injector.getLock();
mInstallLock = injector.getInstallLock();
LockGuard.installLock(mLock, LockGuard.INDEX_PACKAGES);
EventLog.writeEvent(EventLogTags.BOOT_PROGRESS_PMS_START,
SystemClock.uptimeMillis());
- mSdkVersion = injector.getSystemWrapper().getSdkInt();
-
- if (mSdkVersion <= 0) {
- Slog.w(TAG, "**** ro.build.version.sdk not set!");
- }
+ mSystemWrapper = injector.getSystemWrapper();
mContext = injector.getContext();
mFactoryTest = factoryTest;
mOnlyCore = onlyCore;
- mMetrics = new DisplayMetrics();
+ mMetrics = injector.getDisplayMetrics();
mInstaller = injector.getInstaller();
- mEnableFreeCacheV2 =
- injector.getSystemWrapper().getPropertyBoolean("fw.free_cache_v2", true);
+ mEnableFreeCacheV2 = SystemProperties.getBoolean("fw.free_cache_v2", true);
// Create sub-components that provide services / data. Order here is important.
t.traceBegin("createSubComponents");
@@ -3051,6 +3135,7 @@ public class PackageManagerService extends IPackageManager.Stub
mSettings = injector.getSettings();
mPermissionManagerService = injector.getPermissionManagerService();
mIncrementalManager = mInjector.getIncrementalManager();
+ mDefaultAppProvider = mInjector.getDefaultAppProvider();
PlatformCompat platformCompat = mInjector.getCompatibility();
mPackageParserCallback = new PackageParser2.Callback() {
@Override
@@ -3086,8 +3171,8 @@ public class PackageManagerService extends IPackageManager.Stub
ApplicationInfo.FLAG_SYSTEM, ApplicationInfo.PRIVATE_FLAG_PRIVILEGED);
t.traceEnd();
- String separateProcesses =
- injector.getSystemWrapper().getProperty("debug.separate_processes");
+ String separateProcesses = SystemProperties.get("debug.separate_processes");
+
if (separateProcesses != null && separateProcesses.length() > 0) {
if ("*".equals(separateProcesses)) {
mDefParseFlags = PackageParser.PARSE_IGNORE_PROCESSES;
@@ -3110,7 +3195,8 @@ public class PackageManagerService extends IPackageManager.Stub
mMoveCallbacks = new MoveCallbacks(FgThread.get().getLooper());
mViewCompiler = injector.getViewCompiler();
- getDefaultDisplayMetrics(mInjector.getSystemService(DisplayManager.class), mMetrics);
+ mContext.getSystemService(DisplayManager.class)
+ .getDisplay(Display.DEFAULT_DISPLAY).getMetrics(mMetrics);
t.traceBegin("get system config");
SystemConfig systemConfig = injector.getSystemConfig();
@@ -3132,18 +3218,21 @@ public class PackageManagerService extends IPackageManager.Stub
}
mDirsToScanAsSystem = new ArrayList<>();
- mDirsToScanAsSystem.addAll(SYSTEM_PARTITIONS);
+ mDirsToScanAsSystem.addAll(injector.getSystemPartitions());
mDirsToScanAsSystem.addAll(scanPartitions);
Slog.d(TAG, "Directories scanned as system partitions: " + mDirsToScanAsSystem);
+ mAppInstallDir = new File(Environment.getDataDirectory(), "app");
+ mAppLib32InstallDir = getAppLib32InstallDir();
+
// CHECKSTYLE:OFF IndentationCheck
synchronized (mInstallLock) {
// writer
synchronized (mLock) {
- mHandlerThread = new ServiceThread(TAG,
+ HandlerThread handlerThread = new ServiceThread(TAG,
Process.THREAD_PRIORITY_BACKGROUND, true /*allowIo*/);
- mHandlerThread.start();
- mHandler = new PackageHandler(mHandlerThread.getLooper());
+ handlerThread.start();
+ mHandler = new PackageHandler(handlerThread.getLooper());
mProcessLoggingHandler = new ProcessLoggingHandler();
Watchdog.getInstance().addThread(mHandler, WATCHDOG_TIMEOUT);
mInstantAppRegistry = new InstantAppRegistry(this, mPermissionManager);
@@ -3188,12 +3277,13 @@ public class PackageManagerService extends IPackageManager.Stub
// Clean up orphaned packages for which the code path doesn't exist
// and they are an update to a system app - caused by bug/32321269
- final int packageSettingCount = mSettings.mPackages.size();
+ final ArrayMap<String, PackageSetting> packageSettings = mSettings.getPackagesLocked();
+ final int packageSettingCount = packageSettings.size();
for (int i = packageSettingCount - 1; i >= 0; i--) {
- PackageSetting ps = mSettings.mPackages.valueAt(i);
+ PackageSetting ps = packageSettings.valueAt(i);
if (!isExternal(ps) && (ps.getPath() == null || !ps.getPath().exists())
&& mSettings.getDisabledSystemPkgLPr(ps.name) != null) {
- mSettings.mPackages.removeAt(i);
+ packageSettings.removeAt(i);
mSettings.enableSystemPackageLPw(ps.name);
}
}
@@ -3228,9 +3318,10 @@ public class PackageManagerService extends IPackageManager.Stub
File frameworkDir = new File(Environment.getRootDirectory(), "framework");
final VersionInfo ver = mSettings.getInternalVersion();
- mIsUpgrade = !Build.FINGERPRINT.equals(ver.fingerprint);
+ mIsUpgrade =
+ !buildFingerprint.equals(ver.fingerprint);
if (mIsUpgrade) {
- logCriticalInfo(Log.INFO,
+ PackageManagerServiceUtils.logCriticalInfo(Log.INFO,
"Upgrading from " + ver.fingerprint + " to " + Build.FINGERPRINT);
}
@@ -3248,13 +3339,13 @@ public class PackageManagerService extends IPackageManager.Stub
// Save the names of pre-existing packages prior to scanning, so we can determine
// which system packages are completely new due to an upgrade.
if (isDeviceUpgrading()) {
- mExistingPackages = new ArraySet<>(mSettings.mPackages.size());
- for (PackageSetting ps : mSettings.mPackages.values()) {
+ mExistingPackages = new ArraySet<>(packageSettings.size());
+ for (PackageSetting ps : packageSettings.values()) {
mExistingPackages.add(ps.name);
}
}
- mCacheDir = preparePackageParserCache(injector);
+ mCacheDir = preparePackageParserCache(mIsEngBuild);
// Set flag to monitor and not change apk file paths when
// scanning install directories.
@@ -3267,8 +3358,7 @@ public class PackageManagerService extends IPackageManager.Stub
final int systemParseFlags = mDefParseFlags | PackageParser.PARSE_IS_SYSTEM_DIR;
final int systemScanFlags = scanFlags | SCAN_AS_SYSTEM;
- PackageParser2 packageParser = new PackageParser2(mSeparateProcesses, mOnlyCore,
- mMetrics, mCacheDir, mPackageParserCallback);
+ PackageParser2 packageParser = injector.getScanningCachingPackageParser();
ExecutorService executorService = ParallelPackageParser.makeExecutorService();
// Prepare apex package info before scanning APKs, these information are needed when
@@ -3331,8 +3421,8 @@ public class PackageManagerService extends IPackageManager.Stub
// Iterates PackageSettings in reversed order because the item could be removed
// during the iteration.
- for (int index = mSettings.mPackages.size() - 1; index >= 0; index--) {
- final PackageSetting ps = mSettings.mPackages.valueAt(index);
+ for (int index = packageSettings.size() - 1; index >= 0; index--) {
+ final PackageSetting ps = packageSettings.valueAt(index);
/*
* If this is not a system app, it can't be a
@@ -3413,7 +3503,7 @@ public class PackageManagerService extends IPackageManager.Stub
if (!mOnlyCore) {
EventLog.writeEvent(EventLogTags.BOOT_PROGRESS_PMS_DATA_SCAN_START,
SystemClock.uptimeMillis());
- scanDirTracedLI(sAppInstallDir, 0, scanFlags | SCAN_REQUIRE_KNOWN, 0,
+ scanDirTracedLI(mAppInstallDir, 0, scanFlags | SCAN_REQUIRE_KNOWN, 0,
packageParser, executorService);
}
@@ -3470,7 +3560,7 @@ public class PackageManagerService extends IPackageManager.Stub
// previously scanned and known to the system], but, we don't have
// a package [ie. there was an error scanning it from the /data
// partition], completely remove the package data.
- final PackageSetting ps = mSettings.mPackages.get(packageName);
+ final PackageSetting ps = mSettings.getPackageLPr(packageName);
if (ps != null && mPackages.get(packageName) == null) {
removePackageDataLIF(ps, userIds, null, 0, false);
@@ -3596,7 +3686,7 @@ public class PackageManagerService extends IPackageManager.Stub
// Now that we know all the packages we are keeping,
// read and update their last usage times.
- mPackageUsage.read(mSettings.mPackages);
+ mPackageUsage.read(packageSettings);
mCompilerStats.read();
EventLog.writeEvent(EventLogTags.BOOT_PROGRESS_PMS_SCAN_END,
@@ -3689,8 +3779,8 @@ public class PackageManagerService extends IPackageManager.Stub
// profile compilation (without waiting to collect a fresh set of profiles).
if (mIsUpgrade && !mOnlyCore) {
Slog.i(TAG, "Build fingerprint changed; clearing code caches");
- for (int i = 0; i < mSettings.mPackages.size(); i++) {
- final PackageSetting ps = mSettings.mPackages.valueAt(i);
+ for (int i = 0; i < packageSettings.size(); i++) {
+ final PackageSetting ps = packageSettings.valueAt(i);
if (Objects.equals(StorageManager.UUID_PRIVATE_INTERNAL, ps.volumeUuid)) {
// No apps are running this early, so no need to freeze
clearAppDataLIF(ps.pkg, UserHandle.USER_ALL,
@@ -3706,9 +3796,9 @@ public class PackageManagerService extends IPackageManager.Stub
// their icons in launcher.
if (!mOnlyCore && mIsPreQUpgrade) {
Slog.i(TAG, "Whitelisting all existing apps to hide their icons");
- int size = mSettings.mPackages.size();
+ int size = packageSettings.size();
for (int i = 0; i < size; i++) {
- final PackageSetting ps = mSettings.mPackages.valueAt(i);
+ final PackageSetting ps = packageSettings.valueAt(i);
if ((ps.pkgFlags & ApplicationInfo.FLAG_SYSTEM) != 0) {
continue;
}
@@ -3777,23 +3867,16 @@ public class PackageManagerService extends IPackageManager.Stub
}
}
- // Prepare a supplier of package parser for the staging manager to parse apex file
- // during the staging installation.
- final Supplier<PackageParser2> apexParserSupplier = () -> new PackageParser2(
- mSeparateProcesses, mOnlyCore, mMetrics, null /* cacheDir */,
- mPackageParserCallback);
- mInstallerService = new PackageInstallerService(mContext, this, apexParserSupplier);
- final Pair<ComponentName, String> instantAppResolverComponent =
- getInstantAppResolverLPr();
+ mInstallerService = mInjector.getPackageInstallerService();
+ final ComponentName instantAppResolverComponent = getInstantAppResolverLPr();
if (instantAppResolverComponent != null) {
if (DEBUG_INSTANT) {
Slog.d(TAG, "Set ephemeral resolver: " + instantAppResolverComponent);
}
- mInstantAppResolverConnection = new InstantAppResolverConnection(
- mContext, instantAppResolverComponent.first,
- instantAppResolverComponent.second);
+ mInstantAppResolverConnection =
+ mInjector.getInstantAppResolverConnection(instantAppResolverComponent);
mInstantAppResolverSettingsComponent =
- getInstantAppResolverSettingsLPr(instantAppResolverComponent.first);
+ getInstantAppResolverSettingsLPr(instantAppResolverComponent);
} else {
mInstantAppResolverConnection = null;
mInstantAppResolverSettingsComponent = null;
@@ -3823,10 +3906,8 @@ public class PackageManagerService extends IPackageManager.Stub
} // synchronized (mInstallLock)
// CHECKSTYLE:ON IndentationCheck
- mModuleInfoProvider = new ModuleInfoProvider(mContext, this);
-
- // Uncork cache invalidations and allow clients to cache package information.
- PackageManager.uncorkPackageInfoCache();
+ mModuleInfoProvider = mInjector.getModuleInfoProvider();
+ mInjector.getSystemWrapper().enablePackageCaches();
// Now after opening every single application zip, make sure they
// are all flushed. Not really needed, but keeps things nice and
@@ -3874,7 +3955,7 @@ public class PackageManagerService extends IPackageManager.Stub
continue;
}
// skip if the package has been disabled by the user
- final PackageSetting ps = mSettings.mPackages.get(packageName);
+ final PackageSetting ps = mSettings.getPackageLPr(packageName);
if (ps != null) {
final int enabledState = ps.getEnabled(UserHandle.USER_SYSTEM);
if (enabledState == PackageManager.COMPONENT_ENABLED_STATE_DISABLED_USER) {
@@ -3899,7 +3980,7 @@ public class PackageManagerService extends IPackageManager.Stub
// disable any stub still left; these failed to install the full application
for (int i = systemStubPackageNames.size() - 1; i >= 0; --i) {
final String pkgName = systemStubPackageNames.get(i);
- final PackageSetting ps = mSettings.mPackages.get(pkgName);
+ final PackageSetting ps = mSettings.getPackageLPr(pkgName);
ps.setEnabled(PackageManager.COMPONENT_ENABLED_STATE_DISABLED,
UserHandle.USER_SYSTEM, "android");
logCriticalInfo(Log.ERROR, "Stub disabled; pkg: " + pkgName);
@@ -3956,7 +4037,7 @@ public class PackageManagerService extends IPackageManager.Stub
} finally {
// Disable the package; the stub by itself is not runnable
synchronized (mLock) {
- final PackageSetting stubPs = mSettings.mPackages.get(
+ final PackageSetting stubPs = mSettings.getPackageLPr(
stubPkg.getPackageName());
if (stubPs != null) {
stubPs.setEnabled(COMPONENT_ENABLED_STATE_DISABLED,
@@ -4076,19 +4157,18 @@ public class PackageManagerService extends IPackageManager.Stub
setUpInstantAppInstallerActivityLP(getInstantAppInstallerLPr());
}
- private static @Nullable File preparePackageParserCache(Injector injector) {
+ private @Nullable File preparePackageParserCache(boolean forEngBuild) {
if (!FORCE_PACKAGE_PARSED_CACHE_ENABLED) {
if (!DEFAULT_PACKAGE_PARSER_CACHE_ENABLED) {
return null;
}
// Disable package parsing on eng builds to allow for faster incremental development.
- if (Build.IS_ENG) {
+ if (forEngBuild) {
return null;
}
- if (injector.getSystemWrapper()
- .getPropertyBoolean("pm.boot.disable_package_cache", false)) {
+ if (SystemProperties.getBoolean("pm.boot.disable_package_cache", false)) {
Slog.i(TAG, "Disabling package parser cache due to system property.");
return null;
}
@@ -4104,8 +4184,7 @@ public class PackageManagerService extends IPackageManager.Stub
// identify cached items. In particular, changing the value of certain
// feature flags should cause us to invalidate any caches.
final String cacheName = FORCE_PACKAGE_PARSED_CACHE_ENABLED ? "debug"
- : injector.getSystemWrapper().digestOfProperties(
- "ro.build.fingerprint");
+ : SystemProperties.digestOf("ro.build.fingerprint");
// Reconcile cache directories, keeping only what we'd actually use.
for (File cacheDir : FileUtils.listFilesOrEmpty(cacheBaseDir)) {
@@ -4134,14 +4213,15 @@ public class PackageManagerService extends IPackageManager.Stub
// NOTE: When no BUILD_NUMBER is set by the build system, it defaults to a build
// that starts with "eng." to signify that this is an engineering build and not
// destined for release.
- if (Build.IS_USERDEBUG && Build.VERSION.INCREMENTAL.startsWith("eng.")) {
+ if (mIsUserDebugBuild && mIncrementalVersion.startsWith("eng.")) {
Slog.w(TAG, "Wiping cache directory because the system partition changed.");
// Heuristic: If the /system directory has been modified recently due to an "adb sync"
// or a regular make, then blow away the cache. Note that mtimes are *NOT* reliable
// in general and should not be used for production changes. In this specific case,
// we know that they will work.
- File frameworkDir = new File(Environment.getRootDirectory(), "framework");
+ File frameworkDir =
+ new File(Environment.getRootDirectory(), "framework");
if (cacheDir.lastModified() < frameworkDir.lastModified()) {
FileUtils.deleteContents(cacheBaseDir);
cacheDir = FileUtils.createDir(cacheBaseDir, cacheName);
@@ -4167,7 +4247,7 @@ public class PackageManagerService extends IPackageManager.Stub
public boolean isDeviceUpgrading() {
// allow instant applications
// The system property allows testing ota flow when upgraded to the same image.
- return mIsUpgrade || mInjector.getSystemWrapper().getPropertyBoolean(
+ return mIsUpgrade || SystemProperties.getBoolean(
"persist.pm.mock-upgrade", false /* default */);
}
@@ -4301,15 +4381,15 @@ public class PackageManagerService extends IPackageManager.Stub
return null;
}
synchronized (mLock) {
- final Pair<ComponentName, String> instantAppResolver = getInstantAppResolverLPr();
+ final ComponentName instantAppResolver = getInstantAppResolverLPr();
if (instantAppResolver == null) {
return null;
}
- return instantAppResolver.first;
+ return instantAppResolver;
}
}
- private @Nullable Pair<ComponentName, String> getInstantAppResolverLPr() {
+ private @Nullable ComponentName getInstantAppResolverLPr() {
final String[] packageArray =
mContext.getResources().getStringArray(R.array.config_ephemeralResolverPackage);
if (packageArray.length == 0 && !Build.IS_DEBUGGABLE) {
@@ -4324,8 +4404,7 @@ public class PackageManagerService extends IPackageManager.Stub
MATCH_DIRECT_BOOT_AWARE
| MATCH_DIRECT_BOOT_UNAWARE
| (!Build.IS_DEBUGGABLE ? MATCH_SYSTEM_ONLY : 0);
- String actionName = Intent.ACTION_RESOLVE_INSTANT_APP_PACKAGE;
- final Intent resolverIntent = new Intent(actionName);
+ final Intent resolverIntent = new Intent(Intent.ACTION_RESOLVE_INSTANT_APP_PACKAGE);
List<ResolveInfo> resolvers = queryIntentServicesInternal(resolverIntent, null,
resolveFlags, UserHandle.USER_SYSTEM, callingUid, false /*includeInstantApps*/);
final int N = resolvers.size();
@@ -4357,7 +4436,7 @@ public class PackageManagerService extends IPackageManager.Stub
Slog.v(TAG, "Ephemeral resolver found;"
+ " pkg: " + packageName + ", info:" + info);
}
- return new Pair<>(new ComponentName(packageName, info.serviceInfo.name), actionName);
+ return new ComponentName(packageName, info.serviceInfo.name);
}
if (DEBUG_INSTANT) {
Slog.v(TAG, "Ephemeral resolver NOT found");
@@ -4367,7 +4446,7 @@ public class PackageManagerService extends IPackageManager.Stub
@GuardedBy("mLock")
private @Nullable ActivityInfo getInstantAppInstallerLPr() {
- String[] orderedActions = Build.IS_ENG
+ String[] orderedActions = mIsEngBuild
? new String[]{
Intent.ACTION_INSTALL_INSTANT_APP_PACKAGE + "_TEST",
Intent.ACTION_INSTALL_INSTANT_APP_PACKAGE}
@@ -4378,7 +4457,7 @@ public class PackageManagerService extends IPackageManager.Stub
MATCH_DIRECT_BOOT_AWARE
| MATCH_DIRECT_BOOT_UNAWARE
| Intent.FLAG_IGNORE_EPHEMERAL
- | (!Build.IS_ENG ? MATCH_SYSTEM_ONLY : 0);
+ | (mIsEngBuild ? 0 : MATCH_SYSTEM_ONLY);
final Intent intent = new Intent();
intent.addCategory(Intent.CATEGORY_DEFAULT);
intent.setDataAndType(Uri.fromFile(new File("foo.apk")), PACKAGE_MIME_TYPE);
@@ -4398,8 +4477,9 @@ public class PackageManagerService extends IPackageManager.Stub
Iterator<ResolveInfo> iter = matches.iterator();
while (iter.hasNext()) {
final ResolveInfo rInfo = iter.next();
- if (checkPermission(Manifest.permission.INSTALL_PACKAGES,
- rInfo.activityInfo.packageName, 0) == PERMISSION_GRANTED || Build.IS_ENG) {
+ if (checkPermission(
+ Manifest.permission.INSTALL_PACKAGES,
+ rInfo.activityInfo.packageName, 0) == PERMISSION_GRANTED || mIsEngBuild) {
continue;
}
iter.remove();
@@ -4627,7 +4707,7 @@ public class PackageManagerService extends IPackageManager.Stub
enforceCrossUserPermission(callingUid, userId, false, false, "checkPackageStartable");
final boolean userKeyUnlocked = StorageManager.isUserKeyUnlocked(userId);
synchronized (mLock) {
- final PackageSetting ps = mSettings.mPackages.get(packageName);
+ final PackageSetting ps = mSettings.getPackageLPr(packageName);
if (ps == null || shouldFilterApplicationLocked(ps, callingUid, userId)) {
throw new SecurityException("Package " + packageName + " was not found!");
}
@@ -4743,7 +4823,7 @@ public class PackageManagerService extends IPackageManager.Stub
return generatePackageInfo(ps, flags, userId);
}
if (!matchFactoryOnly && (flags & MATCH_KNOWN_PACKAGES) != 0) {
- final PackageSetting ps = mSettings.mPackages.get(packageName);
+ final PackageSetting ps = mSettings.getPackageLPr(packageName);
if (ps == null) return null;
if (filterSharedLibPackageLPr(ps, filterCallingUid, userId, flags)) {
return null;
@@ -4951,7 +5031,7 @@ public class PackageManagerService extends IPackageManager.Stub
final int callingUserId = UserHandle.getUserId(callingUid);
final boolean canViewInstantApps = canViewInstantApps(callingUid, callingUserId);
for (int i=names.length-1; i>=0; i--) {
- final PackageSetting ps = mSettings.mPackages.get(names[i]);
+ final PackageSetting ps = mSettings.getPackageLPr(names[i]);
boolean translateName = false;
if (ps != null && ps.realName != null) {
final boolean targetIsInstantApp = ps.getInstantApp(callingUserId);
@@ -4981,7 +5061,7 @@ public class PackageManagerService extends IPackageManager.Stub
final String cur = mSettings.getRenamedPackageLPr(names[i]);
boolean translateName = false;
if (cur != null) {
- final PackageSetting ps = mSettings.mPackages.get(names[i]);
+ final PackageSetting ps = mSettings.getPackageLPr(names[i]);
final boolean targetIsInstantApp =
ps != null && ps.getInstantApp(callingUserId);
translateName = !targetIsInstantApp
@@ -5017,7 +5097,7 @@ public class PackageManagerService extends IPackageManager.Stub
return UserHandle.getUid(userId, p.getUid());
}
if ((flags & MATCH_KNOWN_PACKAGES) != 0) {
- final PackageSetting ps = mSettings.mPackages.get(packageName);
+ final PackageSetting ps = mSettings.getPackageLPr(packageName);
if (ps != null && ps.isMatch(flags)
&& !shouldFilterApplicationLocked(ps, callingUid, userId)) {
return UserHandle.getUid(userId, ps.appId);
@@ -5049,7 +5129,7 @@ public class PackageManagerService extends IPackageManager.Stub
return mPermissionManager.getGidsForUid(UserHandle.getUid(userId, ps.appId));
}
if ((flags & MATCH_KNOWN_PACKAGES) != 0) {
- final PackageSetting ps = mSettings.mPackages.get(packageName);
+ final PackageSetting ps = mSettings.getPackageLPr(packageName);
if (ps != null && ps.isMatch(flags)
&& !shouldFilterApplicationLocked(ps, callingUid, userId)) {
return mPermissionManager.getGidsForUid(UserHandle.getUid(userId, ps.appId));
@@ -5075,7 +5155,7 @@ public class PackageManagerService extends IPackageManager.Stub
private ApplicationInfo generateApplicationInfoFromSettingsLPw(String packageName, int flags,
int filterCallingUid, int userId) {
if (!mUserManager.exists(userId)) return null;
- PackageSetting ps = mSettings.mPackages.get(packageName);
+ PackageSetting ps = mSettings.getPackageLPr(packageName);
if (ps != null) {
if (filterSharedLibPackageLPr(ps, filterCallingUid, userId, flags)) {
return null;
@@ -5133,7 +5213,7 @@ public class PackageManagerService extends IPackageManager.Stub
TAG, "getApplicationInfo " + packageName
+ ": " + p);
if (p != null) {
- PackageSetting ps = mSettings.mPackages.get(packageName);
+ PackageSetting ps = mSettings.getPackageLPr(packageName);
if (ps == null) return null;
if (filterSharedLibPackageLPr(ps, filterCallingUid, userId, flags)) {
return null;
@@ -5602,7 +5682,7 @@ public class PackageManagerService extends IPackageManager.Stub
if (a == null) {
return false;
}
- PackageSetting ps = mSettings.mPackages.get(component.getPackageName());
+ PackageSetting ps = mSettings.getPackageLPr(component.getPackageName());
if (ps == null) {
return false;
}
@@ -5642,7 +5722,7 @@ public class PackageManagerService extends IPackageManager.Stub
}
if (mSettings.isEnabledAndMatchLPr(pkg, a, flags, userId)) {
- PackageSetting ps = mSettings.mPackages.get(component.getPackageName());
+ PackageSetting ps = mSettings.getPackageLPr(component.getPackageName());
if (ps == null) return null;
if (shouldFilterApplicationLocked(
ps, callingUid, component, TYPE_RECEIVER, userId)) {
@@ -5802,9 +5882,9 @@ public class PackageManagerService extends IPackageManager.Stub
private List<VersionedPackage> getPackagesUsingSharedLibraryLPr(
SharedLibraryInfo libInfo, int flags, int userId) {
List<VersionedPackage> versionedPackages = null;
- final int packageCount = mSettings.mPackages.size();
+ final int packageCount = mSettings.getPackagesLocked().size();
for (int i = 0; i < packageCount; i++) {
- PackageSetting ps = mSettings.mPackages.valueAt(i);
+ PackageSetting ps = mSettings.getPackagesLocked().valueAt(i);
if (ps == null) {
continue;
@@ -5863,7 +5943,7 @@ public class PackageManagerService extends IPackageManager.Stub
AndroidPackage pkg = mPackages.get(s.getPackageName());
if (mSettings.isEnabledAndMatchLPr(pkg, s, flags, userId)) {
- PackageSetting ps = mSettings.mPackages.get(component.getPackageName());
+ PackageSetting ps = mSettings.getPackageLPr(component.getPackageName());
if (ps == null) return null;
if (shouldFilterApplicationLocked(
ps, callingUid, component, TYPE_SERVICE, userId)) {
@@ -5897,7 +5977,7 @@ public class PackageManagerService extends IPackageManager.Stub
}
if (mSettings.isEnabledAndMatchLPr(pkg, p, flags, userId)) {
- PackageSetting ps = mSettings.mPackages.get(component.getPackageName());
+ PackageSetting ps = mSettings.getPackageLPr(component.getPackageName());
if (ps == null) return null;
if (shouldFilterApplicationLocked(
ps, callingUid, component, TYPE_PROVIDER, userId)) {
@@ -6034,7 +6114,7 @@ public class PackageManagerService extends IPackageManager.Stub
final String packageName = changedPackages.get(i);
if (packageName != null) {
// Filter out the changes if the calling package should not be able to see it.
- final PackageSetting ps = mSettings.mPackages.get(packageName);
+ final PackageSetting ps = mSettings.getPackageLPr(packageName);
if (shouldFilterApplicationLocked(ps, callingUid, userId)) {
continue;
}
@@ -6055,7 +6135,7 @@ public class PackageManagerService extends IPackageManager.Stub
res.addAll(mAvailableFeatures.values());
}
final FeatureInfo fi = new FeatureInfo();
- fi.reqGlEsVersion = mInjector.getSystemWrapper().getPropertyInt("ro.opengles.version",
+ fi.reqGlEsVersion = SystemProperties.getInt("ro.opengles.version",
FeatureInfo.GL_ES_VERSION_UNDEFINED);
res.add(fi);
@@ -6781,7 +6861,7 @@ public class PackageManagerService extends IPackageManager.Stub
for (int n = 0; n < count; n++) {
final ResolveInfo info = resolvedActivities.get(n);
final String packageName = info.activityInfo.packageName;
- final PackageSetting ps = mSettings.mPackages.get(packageName);
+ final PackageSetting ps = mSettings.getPackageLPr(packageName);
if (ps != null) {
// only check domain verification status if the app is not a browser
if (!info.handleAllWebDataURI) {
@@ -6863,7 +6943,7 @@ public class PackageManagerService extends IPackageManager.Stub
// If we have an ephemeral app, use it
if (ri.activityInfo.applicationInfo.isInstantApp()) {
final String packageName = ri.activityInfo.packageName;
- final PackageSetting ps = mSettings.mPackages.get(packageName);
+ final PackageSetting ps = mSettings.getPackageLPr(packageName);
final long packedStatus = getDomainVerificationStatusLPr(ps, userId);
final int status = (int)(packedStatus >> 32);
if (status != INTENT_FILTER_DOMAIN_VERIFICATION_STATUS_ALWAYS_ASK) {
@@ -7297,7 +7377,7 @@ public class PackageManagerService extends IPackageManager.Stub
private List<CrossProfileIntentFilter> getMatchingCrossProfileIntentFilters(Intent intent,
String resolvedType, int userId) {
- CrossProfileIntentResolver resolver = mSettings.getCrossProfileIntentResolvers(userId);
+ CrossProfileIntentResolver resolver = mSettings.getCrossProfileIntentResolver(userId);
if (resolver != null) {
return resolver.queryIntent(intent, resolvedType, false /*defaultOnly*/, userId);
}
@@ -7545,7 +7625,7 @@ public class PackageManagerService extends IPackageManager.Stub
for (int i = instantApps.size() - 1; i >= 0; --i) {
final ResolveInfo info = instantApps.get(i);
final String packageName = info.activityInfo.packageName;
- final PackageSetting ps = mSettings.mPackages.get(packageName);
+ final PackageSetting ps = mSettings.getPackageLPr(packageName);
if (ps.getInstantApp(userId)) {
final long packedStatus = getDomainVerificationStatusLPr(ps, userId);
final int status = (int)(packedStatus >> 32);
@@ -7600,7 +7680,7 @@ public class PackageManagerService extends IPackageManager.Stub
if (intent.isWebIntent() && auxiliaryResponse == null) {
return result;
}
- final PackageSetting ps = mSettings.mPackages.get(mInstantAppInstallerActivity.packageName);
+ final PackageSetting ps = mSettings.getPackageLPr(mInstantAppInstallerActivity.packageName);
if (ps == null
|| !ps.readUserState(userId).isEnabled(mInstantAppInstallerActivity, 0)) {
return result;
@@ -7660,7 +7740,7 @@ public class PackageManagerService extends IPackageManager.Stub
continue;
}
String packageName = riTargetUser.activityInfo.packageName;
- PackageSetting ps = mSettings.mPackages.get(packageName);
+ PackageSetting ps = mSettings.getPackageLPr(packageName);
if (ps == null) {
continue;
}
@@ -7885,7 +7965,7 @@ public class PackageManagerService extends IPackageManager.Stub
for (int n=0; n<count; n++) {
ResolveInfo info = candidates.get(n);
String packageName = info.activityInfo.packageName;
- PackageSetting ps = mSettings.mPackages.get(packageName);
+ PackageSetting ps = mSettings.getPackageLPr(packageName);
if (ps != null) {
// Add to the special match all list (Browser use case)
if (info.handleAllWebDataURI) {
@@ -7964,8 +8044,8 @@ public class PackageManagerService extends IPackageManager.Stub
} else {
// Browser/generic handling case. If there's a default browser, go straight
// to that (but only if there is no other higher-priority match).
- final String defaultBrowserPackageName =
- mPermissionManager.getDefaultBrowser(userId);
+ final String defaultBrowserPackageName = mDefaultAppProvider.getDefaultBrowser(
+ userId);
int maxMatchPrio = 0;
ResolveInfo defaultBrowserMatch = null;
final int numCandidates = matchAllList.size();
@@ -8749,8 +8829,8 @@ public class PackageManagerService extends IPackageManager.Stub
synchronized (mLock) {
ArrayList<PackageInfo> list;
if (listUninstalled) {
- list = new ArrayList<>(mSettings.mPackages.size());
- for (PackageSetting ps : mSettings.mPackages.values()) {
+ list = new ArrayList<>(mSettings.getPackagesLocked().size());
+ for (PackageSetting ps : mSettings.getPackagesLocked().values()) {
if (listFactory) {
if (!ps.isSystem()) {
continue;
@@ -8862,7 +8942,7 @@ public class PackageManagerService extends IPackageManager.Stub
ArrayList<PackageInfo> list = new ArrayList<>();
boolean[] tmpBools = new boolean[permissions.length];
if (listUninstalled) {
- for (PackageSetting ps : mSettings.mPackages.values()) {
+ for (PackageSetting ps : mSettings.getPackagesLocked().values()) {
addPackageHoldingPermissions(list, ps, permissions, tmpBools, flags,
userId);
}
@@ -8907,8 +8987,8 @@ public class PackageManagerService extends IPackageManager.Stub
synchronized (mLock) {
ArrayList<ApplicationInfo> list;
if (listUninstalled) {
- list = new ArrayList<>(mSettings.mPackages.size());
- for (PackageSetting ps : mSettings.mPackages.values()) {
+ list = new ArrayList<>(mSettings.getPackagesLocked().size());
+ for (PackageSetting ps : mSettings.getPackagesLocked().values()) {
ApplicationInfo ai;
int effectiveFlags = flags;
if (ps.isSystem()) {
@@ -9000,7 +9080,7 @@ public class PackageManagerService extends IPackageManager.Stub
if (Process.isIsolated(callingUid)) {
callingUid = mIsolatedOwners.get(callingUid);
}
- final PackageSetting ps = mSettings.mPackages.get(packageName);
+ final PackageSetting ps = mSettings.getPackageLPr(packageName);
final boolean returnAllowed =
ps != null
&& (isCallerSameApp(packageName, callingUid)
@@ -9099,7 +9179,7 @@ public class PackageManagerService extends IPackageManager.Stub
if (p.isPersistent()
&& (!mSafeMode || p.isSystem())
&& (matchesUnaware || matchesAware)) {
- PackageSetting ps = mSettings.mPackages.get(p.getPackageName());
+ PackageSetting ps = mSettings.getPackageLPr(p.getPackageName());
if (ps != null) {
ApplicationInfo ai = PackageInfoUtils.generateApplicationInfo(p, flags,
ps.readUserState(userId), userId, ps);
@@ -9144,7 +9224,7 @@ public class PackageManagerService extends IPackageManager.Stub
if (!mSettings.isEnabledAndMatchLPr(providerInfo, flags, userId)) {
return null;
}
- final PackageSetting ps = mSettings.mPackages.get(providerInfo.packageName);
+ final PackageSetting ps = mSettings.getPackageLPr(providerInfo.packageName);
final ComponentName component =
new ComponentName(providerInfo.packageName, providerInfo.name);
if (shouldFilterApplicationLocked(ps, callingUid, component, TYPE_PROVIDER, userId)) {
@@ -9184,7 +9264,7 @@ public class PackageManagerService extends IPackageManager.Stub
if (!mSettings.isEnabledAndMatchLPr(providerInfo, flags, userId)) {
continue;
}
- final PackageSetting ps = mSettings.mPackages.get(providerInfo.packageName);
+ final PackageSetting ps = mSettings.getPackageLPr(providerInfo.packageName);
final ComponentName component =
new ComponentName(providerInfo.packageName, providerInfo.name);
if (shouldFilterApplicationLocked(
@@ -9213,7 +9293,7 @@ public class PackageManagerService extends IPackageManager.Stub
final int callingUid = Binder.getCallingUid();
final int callingUserId = UserHandle.getUserId(callingUid);
String packageName = component.getPackageName();
- final PackageSetting ps = mSettings.mPackages.get(packageName);
+ final PackageSetting ps = mSettings.getPackageLPr(packageName);
AndroidPackage pkg = mPackages.get(packageName);
if (ps == null || pkg == null) return null;
if (shouldFilterApplicationLocked(
@@ -9445,8 +9525,7 @@ public class PackageManagerService extends IPackageManager.Stub
Trace.traceBegin(TRACE_TAG_PACKAGE_MANAGER, "parsePackage");
final ParsedPackage parsedPackage;
- try (PackageParser2 pp = new PackageParser2(mSeparateProcesses, mOnlyCore, mMetrics, null,
- mPackageParserCallback)) {
+ try (PackageParser2 pp = mInjector.getScanningPackageParser()) {
parsedPackage = pp.parsePackage(scanFile, parseFlags, false);
} catch (PackageParserException e) {
throw PackageManagerException.from(e);
@@ -9740,7 +9819,7 @@ public class PackageManagerService extends IPackageManager.Stub
pkgName, getSettingsVersionForPackage(parsedPackage)),
Collections.singletonMap(pkgName,
getSharedLibLatestVersionSetting(scanResult))),
- mSettings.mKeySetManagerService, mInjector);
+ mSettings.getKeySetManagerService(), mInjector);
appIdCreated = optimisticallyRegisterAppId(scanResult);
commitReconciledScanResultLocked(
reconcileResult.get(pkgName), mUserManager.getUserIds());
@@ -10051,7 +10130,7 @@ public class PackageManagerService extends IPackageManager.Stub
List<PackageSetting> pkgSettings;
synchronized (mLock) {
pkgSettings = PackageManagerServiceUtils.getPackagesForDexopt(
- mSettings.mPackages.values(), this);
+ mSettings.getPackagesLocked().values(), this);
}
List<AndroidPackage> pkgs = new ArrayList<>(pkgSettings.size());
@@ -10196,7 +10275,7 @@ public class PackageManagerService extends IPackageManager.Stub
pkgCompilationReason = PackageManagerService.REASON_BACKGROUND_DEXOPT;
}
- if (mInjector.getSystemWrapper().getPropertyBoolean(PRECOMPILE_LAYOUTS, false)) {
+ if (SystemProperties.getBoolean(PRECOMPILE_LAYOUTS, false)) {
mArtManagerService.compileLayouts(pkg);
}
@@ -10409,7 +10488,7 @@ public class PackageManagerService extends IPackageManager.Stub
// Package could not be found. Report failure.
return PackageDexOptimizer.DEX_OPT_FAILED;
}
- mPackageUsage.maybeWriteAsync(mSettings.mPackages);
+ mPackageUsage.maybeWriteAsync(mSettings.getPackagesLocked());
mCompilerStats.maybeWriteAsync();
}
final long callingId = Binder.clearCallingIdentity();
@@ -10639,7 +10718,7 @@ public class PackageManagerService extends IPackageManager.Stub
PackageWatchdog.getInstance(mContext).writeNow();
synchronized (mLock) {
- mPackageUsage.writeNow(mSettings.mPackages);
+ mPackageUsage.writeNow(mSettings.getPackagesLocked());
// This is the last chance to write out pending restriction settings
if (mHandler.hasMessages(WRITE_PACKAGE_RESTRICTIONS)) {
@@ -10769,7 +10848,7 @@ public class PackageManagerService extends IPackageManager.Stub
private void clearAppDataLeafLIF(AndroidPackage pkg, int userId, int flags) {
final PackageSetting ps;
synchronized (mLock) {
- ps = mSettings.mPackages.get(pkg.getPackageName());
+ ps = mSettings.getPackageLPr(pkg.getPackageName());
}
for (int realUserId : resolveUserIds(userId)) {
final long ceDataInode = (ps != null) ? ps.getCeDataInode(realUserId) : 0;
@@ -10793,7 +10872,7 @@ public class PackageManagerService extends IPackageManager.Stub
private void destroyAppDataLeafLIF(AndroidPackage pkg, int userId, int flags) {
final PackageSetting ps;
synchronized (mLock) {
- ps = mSettings.mPackages.get(pkg.getPackageName());
+ ps = mSettings.getPackageLPr(pkg.getPackageName());
}
for (int realUserId : resolveUserIds(userId)) {
final long ceDataInode = (ps != null) ? ps.getCeDataInode(realUserId) : 0;
@@ -11173,7 +11252,7 @@ public class PackageManagerService extends IPackageManager.Stub
}
private int getVendorPartitionVersion() {
- final String version = mInjector.getSystemWrapper().getProperty("ro.vndk.version");
+ final String version = SystemProperties.get("ro.vndk.version");
if (!version.isEmpty()) {
try {
return Integer.parseInt(version);
@@ -11384,7 +11463,7 @@ public class PackageManagerService extends IPackageManager.Stub
// to allowlist their privileged permissions just like other
// priv-apps.
synchronized (mLock) {
- PackageSetting platformPkgSetting = mSettings.mPackages.get("android");
+ PackageSetting platformPkgSetting = mSettings.getPackageLPr("android");
if ((compareSignatures(platformPkgSetting.signatures.mSigningDetails.signatures,
pkg.getSigningDetails().signatures)
!= PackageManager.SIGNATURE_MATCH)) {
@@ -11506,6 +11585,7 @@ public class PackageManagerService extends IPackageManager.Stub
parsedPackage.setVersionCode(mSdkVersion)
.setVersionCodeMajor(0);
}
+
final AndroidPackage oldPkg = request.oldPkg;
final @ParseFlags int parseFlags = request.parseFlags;
final @ScanFlags int scanFlags = request.scanFlags;
@@ -11545,7 +11625,7 @@ public class PackageManagerService extends IPackageManager.Stub
if (reconciledPkg.installArgs != null) {
InstallSource installSource = reconciledPkg.installArgs.installSource;
if (installSource.initiatingPackageName != null) {
- final PackageSetting ips = mSettings.mPackages.get(
+ final PackageSetting ips = mSettings.getPackageLPr(
installSource.initiatingPackageName);
if (ips != null) {
installSource = installSource.setInitiatingPackageSignatures(
@@ -11575,7 +11655,7 @@ public class PackageManagerService extends IPackageManager.Stub
reconciledPkg.collectedSharedLibraryInfos, allUsers);
}
- final KeySetManagerService ksms = mSettings.mKeySetManagerService;
+ final KeySetManagerService ksms = mSettings.getKeySetManagerService();
if (reconciledPkg.removeAppKeySetData) {
ksms.removeAppKeySetDataLPw(pkg.getPackageName());
}
@@ -11937,12 +12017,13 @@ public class PackageManagerService extends IPackageManager.Stub
final String cpuAbiOverride = deriveAbiOverride(request.cpuAbiOverride);
final boolean isUpdatedSystemApp = pkgSetting.getPkgState().isUpdatedSystemApp();
+ final File appLib32InstallDir = getAppLib32InstallDir();
if ((scanFlags & SCAN_NEW_INSTALL) == 0) {
if (needToDeriveAbi) {
Trace.traceBegin(TRACE_TAG_PACKAGE_MANAGER, "derivePackageAbi");
final Pair<PackageAbiHelper.Abis, PackageAbiHelper.NativeLibraryPaths> derivedAbi =
packageAbiHelper.derivePackageAbi(parsedPackage, isUpdatedSystemApp,
- cpuAbiOverride);
+ cpuAbiOverride, appLib32InstallDir);
derivedAbi.first.applyTo(parsedPackage);
derivedAbi.second.applyTo(parsedPackage);
Trace.traceEnd(TRACE_TAG_PACKAGE_MANAGER);
@@ -11960,7 +12041,7 @@ public class PackageManagerService extends IPackageManager.Stub
abis.applyTo(pkgSetting);
final PackageAbiHelper.NativeLibraryPaths nativeLibraryPaths =
packageAbiHelper.deriveNativeLibraryPaths(parsedPackage,
- isUpdatedSystemApp, sAppLib32InstallDir);
+ isUpdatedSystemApp, appLib32InstallDir);
nativeLibraryPaths.applyTo(parsedPackage);
}
} else {
@@ -11972,7 +12053,7 @@ public class PackageManagerService extends IPackageManager.Stub
final PackageAbiHelper.NativeLibraryPaths nativeLibraryPaths =
packageAbiHelper.deriveNativeLibraryPaths(parsedPackage,
- isUpdatedSystemApp, sAppLib32InstallDir);
+ isUpdatedSystemApp, appLib32InstallDir);
nativeLibraryPaths.applyTo(parsedPackage);
if (DEBUG_ABI_SELECTION) {
@@ -11998,7 +12079,7 @@ public class PackageManagerService extends IPackageManager.Stub
// package path (after the rename away from the stage path).
final PackageAbiHelper.NativeLibraryPaths nativeLibraryPaths =
packageAbiHelper.deriveNativeLibraryPaths(parsedPackage, isUpdatedSystemApp,
- sAppLib32InstallDir);
+ appLib32InstallDir);
nativeLibraryPaths.applyTo(parsedPackage);
}
@@ -12293,7 +12374,7 @@ public class PackageManagerService extends IPackageManager.Stub
}
// Make sure we're not adding any bogus keyset info
- final KeySetManagerService ksms = mSettings.mKeySetManagerService;
+ final KeySetManagerService ksms = mSettings.getKeySetManagerService();
ksms.assertScannedPackageValid(pkg);
synchronized (mLock) {
@@ -12511,7 +12592,7 @@ public class PackageManagerService extends IPackageManager.Stub
}
if (sharedUserSetting != null && sharedUserSetting.isPrivileged()) {
// Exempt SharedUsers signed with the platform key.
- PackageSetting platformPkgSetting = mSettings.mPackages.get("android");
+ PackageSetting platformPkgSetting = mSettings.getPackageLPr("android");
if (!comparePackageSignatures(platformPkgSetting,
pkg.getSigningDetails().signatures)) {
throw new PackageManagerException("Apps that share a user with a " +
@@ -12685,7 +12766,7 @@ public class PackageManagerService extends IPackageManager.Stub
continue;
}
for (VersionedPackage dependentPackage : dependents) {
- final PackageSetting ps = mSettings.mPackages.get(
+ final PackageSetting ps = mSettings.getPackageLPr(
dependentPackage.getPackageName());
if (ps != null) {
ps.setOverlayPathsForLibrary(libraryInfo.getName(), null, currentUserId);
@@ -12844,7 +12925,6 @@ public class PackageManagerService extends IPackageManager.Stub
synchronized (mLock) {
// We don't expect installation to fail beyond this point
-
// Add the new setting to mSettings
mSettings.insertPackageSettingLPw(pkgSetting, pkg);
// Add the new setting to mPackages
@@ -12854,7 +12934,7 @@ public class PackageManagerService extends IPackageManager.Stub
}
// Add the package's KeySets to the global KeySetManagerService
- KeySetManagerService ksms = mSettings.mKeySetManagerService;
+ KeySetManagerService ksms = mSettings.getKeySetManagerService();
ksms.addScannedPackageLPw(pkg);
mComponentResolver.addAllComponents(pkg, chatty);
@@ -13329,7 +13409,7 @@ public class PackageManagerService extends IPackageManager.Stub
packageName, extras, 0, null, null, userIds, instantUserIds,
mAppsFilter.getVisibilityAllowList(
getPackageSettingInternal(packageName, Process.SYSTEM_UID),
- userIds, mSettings.mPackages));
+ userIds, mSettings.getPackagesLocked()));
if (sendBootCompleted && !ArrayUtils.isEmpty(userIds)) {
mHandler.post(() -> {
for (int userId : userIds) {
@@ -13400,7 +13480,7 @@ public class PackageManagerService extends IPackageManager.Stub
boolean sendRemoved = false;
// writer
synchronized (mLock) {
- pkgSetting = mSettings.mPackages.get(packageName);
+ pkgSetting = mSettings.getPackageLPr(packageName);
if (pkgSetting == null) {
return false;
}
@@ -13466,7 +13546,7 @@ public class PackageManagerService extends IPackageManager.Stub
}
synchronized (mLock) {
- final PackageSetting pkgSetting = mSettings.mPackages.get(packageName);
+ final PackageSetting pkgSetting = mSettings.getPackageLPr(packageName);
if (pkgSetting == null || !pkgSetting.isSystem()) {
return;
}
@@ -13493,7 +13573,7 @@ public class PackageManagerService extends IPackageManager.Stub
}
synchronized (mLock) {
- final PackageSetting pkgSetting = mSettings.mPackages.get(packageName);
+ final PackageSetting pkgSetting = mSettings.getPackageLPr(packageName);
// The target app should always be in system
if (pkgSetting == null || !pkgSetting.isSystem()) {
return false;
@@ -13580,7 +13660,7 @@ public class PackageManagerService extends IPackageManager.Stub
try {
// writer
synchronized (mLock) {
- ps = mSettings.mPackages.get(packageName);
+ ps = mSettings.getPackageLPr(packageName);
if (ps == null) {
return true;
}
@@ -13641,7 +13721,7 @@ public class PackageManagerService extends IPackageManager.Stub
// writer
synchronized (mLock) {
- pkgSetting = mSettings.mPackages.get(packageName);
+ pkgSetting = mSettings.getPackageLPr(packageName);
if (pkgSetting == null) {
return PackageManager.INSTALL_FAILED_INVALID_URI;
}
@@ -13791,7 +13871,7 @@ public class PackageManagerService extends IPackageManager.Stub
final String packageName = packageNames[i];
final PackageSetting pkgSetting;
synchronized (mLock) {
- pkgSetting = mSettings.mPackages.get(packageName);
+ pkgSetting = mSettings.getPackageLPr(packageName);
if (pkgSetting == null
|| shouldFilterApplicationLocked(pkgSetting, callingUid, userId)) {
Slog.w(TAG, "Could not find package setting for package: " + packageName
@@ -13889,7 +13969,7 @@ public class PackageManagerService extends IPackageManager.Stub
}
final PackageSetting pkgSetting;
synchronized (mLock) {
- pkgSetting = mSettings.mPackages.get(packageName);
+ pkgSetting = mSettings.getPackageLPr(packageName);
if (pkgSetting == null
|| shouldFilterApplicationLocked(pkgSetting, callingUid, userId)) {
Slog.w(TAG, "Could not find package setting for package: " + packageName
@@ -13942,7 +14022,7 @@ public class PackageManagerService extends IPackageManager.Stub
private Bundle getSuspendedPackageAppExtrasInternal(String packageName, int userId) {
synchronized (mLock) {
- final PackageSetting ps = mSettings.mPackages.get(packageName);
+ final PackageSetting ps = mSettings.getPackageLPr(packageName);
if (ps == null) {
return null;
}
@@ -13997,7 +14077,7 @@ public class PackageManagerService extends IPackageManager.Stub
enforceCrossUserPermission(callingUid, userId, true /* requireFullPermission */,
false /* checkShell */, "isPackageSuspendedForUser for user " + userId);
synchronized (mLock) {
- final PackageSetting ps = mSettings.mPackages.get(packageName);
+ final PackageSetting ps = mSettings.getPackageLPr(packageName);
if (ps == null || shouldFilterApplicationLocked(ps, callingUid, userId)) {
throw new IllegalArgumentException("Unknown target package: " + packageName);
}
@@ -14015,7 +14095,7 @@ public class PackageManagerService extends IPackageManager.Stub
boolean isSuspendingAnyPackages(String suspendingPackage, int userId) {
synchronized (mLock) {
- for (final PackageSetting ps : mSettings.mPackages.values()) {
+ for (final PackageSetting ps : mSettings.getPackagesLocked().values()) {
if (ps.isSuspendedBy(suspendingPackage, userId)) {
return true;
}
@@ -14041,7 +14121,7 @@ public class PackageManagerService extends IPackageManager.Stub
final IntArray unsuspendedUids = new IntArray();
synchronized (mLock) {
for (String packageName : packagesToChange) {
- final PackageSetting ps = mSettings.mPackages.get(packageName);
+ final PackageSetting ps = mSettings.getPackageLPr(packageName);
if (ps != null && ps.getSuspended(userId)) {
ps.removeSuspension(suspendingPackagePredicate, userId);
if (!ps.getSuspended(userId)) {
@@ -14082,7 +14162,7 @@ public class PackageManagerService extends IPackageManager.Stub
final IntArray changedUids = new IntArray();
synchronized (mLock) {
for (String packageName : packagesToChange) {
- final PackageSetting ps = mSettings.mPackages.get(packageName);
+ final PackageSetting ps = mSettings.getPackageLPr(packageName);
if (ps != null && ps.getDistractionFlags(userId) != 0) {
ps.setDistractionFlags(0, userId);
changedPackages.add(ps.name);
@@ -14138,7 +14218,7 @@ public class PackageManagerService extends IPackageManager.Stub
continue;
}
synchronized (mLock) {
- final PackageSetting ps = mSettings.mPackages.get(packageNames[i]);
+ final PackageSetting ps = mSettings.getPackageLPr(packageNames[i]);
if (ps == null || shouldFilterApplicationLocked(ps, callingUid, userId)) {
Slog.w(TAG, "Could not find package setting for package: " + packageNames[i]);
unactionablePackages.add(packageNames[i]);
@@ -14162,8 +14242,8 @@ public class PackageManagerService extends IPackageManager.Stub
final boolean isCallerOwner = isCallerDeviceOrProfileOwner(userId);
final long callingId = Binder.clearCallingIdentity();
try {
- final String activeLauncherPackageName = mPermissionManager.getDefaultHome(userId);
- final String dialerPackageName = mPermissionManager.getDefaultDialer(userId);
+ final String activeLauncherPackageName = mDefaultAppProvider.getDefaultHome(userId);
+ final String dialerPackageName = mDefaultAppProvider.getDefaultDialer(userId);
for (int i = 0; i < packageNames.length; i++) {
canSuspend[i] = false;
final String packageName = packageNames[i];
@@ -14485,7 +14565,7 @@ public class PackageManagerService extends IPackageManager.Stub
// Check if the developer wants to skip verification for ADB installs
if ((installFlags & PackageManager.INSTALL_DISABLE_VERIFICATION) != 0) {
synchronized (mLock) {
- if (mSettings.mPackages.get(pkgInfoLite.packageName) == null) {
+ if (mSettings.getPackageLPr(pkgInfoLite.packageName) == null) {
// Always verify fresh install
return true;
}
@@ -14552,7 +14632,7 @@ public class PackageManagerService extends IPackageManager.Stub
return INTENT_FILTER_DOMAIN_VERIFICATION_STATUS_UNDEFINED;
}
synchronized (mLock) {
- final PackageSetting ps = mSettings.mPackages.get(packageName);
+ final PackageSetting ps = mSettings.getPackageLPr(packageName);
if (ps == null
|| shouldFilterApplicationLocked(
ps, callingUid, UserHandle.getUserId(callingUid))) {
@@ -14569,7 +14649,7 @@ public class PackageManagerService extends IPackageManager.Stub
boolean result = false;
synchronized (mLock) {
- final PackageSetting ps = mSettings.mPackages.get(packageName);
+ final PackageSetting ps = mSettings.getPackageLPr(packageName);
if (shouldFilterApplicationLocked(
ps, Binder.getCallingUid(), UserHandle.getCallingUserId())) {
return false;
@@ -14590,7 +14670,7 @@ public class PackageManagerService extends IPackageManager.Stub
return ParceledListSlice.emptyList();
}
synchronized (mLock) {
- final PackageSetting ps = mSettings.mPackages.get(packageName);
+ final PackageSetting ps = mSettings.getPackageLPr(packageName);
if (shouldFilterApplicationLocked(ps, callingUid, UserHandle.getUserId(callingUid))) {
return ParceledListSlice.emptyList();
}
@@ -14655,7 +14735,7 @@ public class PackageManagerService extends IPackageManager.Stub
}
// writer
synchronized (mLock) {
- PackageSetting targetPackageSetting = mSettings.mPackages.get(targetPackage);
+ PackageSetting targetPackageSetting = mSettings.getPackageLPr(targetPackage);
if (targetPackageSetting == null
|| shouldFilterApplicationLocked(
targetPackageSetting, callingUid, UserHandle.getUserId(callingUid))) {
@@ -14664,7 +14744,7 @@ public class PackageManagerService extends IPackageManager.Stub
PackageSetting installerPackageSetting;
if (installerPackageName != null) {
- installerPackageSetting = mSettings.mPackages.get(installerPackageName);
+ installerPackageSetting = mSettings.getPackageLPr(installerPackageName);
if (installerPackageSetting == null) {
throw new IllegalArgumentException("Unknown installer package: "
+ installerPackageName);
@@ -14706,7 +14786,7 @@ public class PackageManagerService extends IPackageManager.Stub
String targetInstallerPackageName =
targetPackageSetting.installSource.installerPackageName;
PackageSetting targetInstallerPkgSetting = targetInstallerPackageName == null ? null :
- mSettings.mPackages.get(targetInstallerPackageName);
+ mSettings.getPackageLPr(targetInstallerPackageName);
if (targetInstallerPkgSetting != null) {
if (compareSignatures(callerSignature,
@@ -14757,7 +14837,7 @@ public class PackageManagerService extends IPackageManager.Stub
mInjector.getSystemService(AppOpsManager.class).checkPackage(Binder.getCallingUid(),
callerPackageName);
synchronized (mLock) {
- PackageSetting ps = mSettings.mPackages.get(packageName);
+ PackageSetting ps = mSettings.getPackageLPr(packageName);
if (ps == null) {
throw new IllegalArgumentException("Unknown target package " + packageName);
}
@@ -16498,7 +16578,7 @@ public class PackageManagerService extends IPackageManager.Stub
// For system-bundled packages, we assume that installing an upgraded version
// of the package implies that the user actually wants to run that new code,
// so we enable the package.
- final PackageSetting ps = mSettings.mPackages.get(pkgName);
+ final PackageSetting ps = mSettings.getPackageLPr(pkgName);
final int userId = installArgs.user.getIdentifier();
if (ps != null) {
if (pkg.isSystem()) {
@@ -16543,7 +16623,7 @@ public class PackageManagerService extends IPackageManager.Stub
// TODO(146804378): Support overlaying static shared libraries
continue;
}
- final PackageSetting libPs = mSettings.mPackages.get(
+ final PackageSetting libPs = mSettings.getPackageLPr(
sharedLib.getPackageName());
if (libPs == null) {
continue;
@@ -16956,8 +17036,7 @@ public class PackageManagerService extends IPackageManager.Stub
&& compareSignatures(sharedUserSignatures,
parsedPackage.getSigningDetails().signatures)
!= PackageManager.SIGNATURE_MATCH) {
- if (injector.getSystemWrapper()
- .getPropertyInt("ro.product.first_api_level", 0) <= 29) {
+ if (SystemProperties.getInt("ro.product.first_api_level", 0) <= 29) {
// Mismatched signatures is an error and silently skipping system
// packages will likely break the device in unforeseen ways.
// However, we allow the device to boot anyway because, prior to Q,
@@ -17147,7 +17226,7 @@ public class PackageManagerService extends IPackageManager.Stub
reconciledPkg.pkgSetting.lastUpdateTime = System.currentTimeMillis();
res.removedInfo.broadcastAllowList = mAppsFilter.getVisibilityAllowList(
- reconciledPkg.pkgSetting, request.mAllUsers, mSettings.mPackages);
+ reconciledPkg.pkgSetting, request.mAllUsers, mSettings.getPackagesLocked());
if (reconciledPkg.prepareResult.system) {
// Remove existing system package
removePackageLI(oldPackage, true);
@@ -17171,7 +17250,7 @@ public class PackageManagerService extends IPackageManager.Stub
executeDeletePackageLIF(reconciledPkg.deletePackageAction, packageName,
true, request.mAllUsers, false, parsedPackage);
} catch (SystemDeleteException e) {
- if (Build.IS_ENG) {
+ if (mIsEngBuild) {
throw new RuntimeException("Unexpected failure", e);
// ignore; not possible for non-system app
}
@@ -17192,7 +17271,7 @@ public class PackageManagerService extends IPackageManager.Stub
}
// Update the in-memory copy of the previous code paths.
- PackageSetting ps1 = mSettings.mPackages.get(
+ PackageSetting ps1 = mSettings.getPackageLPr(
reconciledPkg.prepareResult.existingPackage.getPackageName());
if ((reconciledPkg.installArgs.installFlags & PackageManager.DONT_KILL_APP)
== 0) {
@@ -17221,7 +17300,7 @@ public class PackageManagerService extends IPackageManager.Stub
AndroidPackage pkg = commitReconciledScanResultLocked(reconciledPkg, request.mAllUsers);
updateSettingsLI(pkg, reconciledPkg.installArgs, request.mAllUsers, res);
- final PackageSetting ps = mSettings.mPackages.get(packageName);
+ final PackageSetting ps = mSettings.getPackageLPr(packageName);
if (ps != null) {
res.newUsers = ps.queryInstalledUsers(mUserManager.getUserIds(), true);
ps.setUpdateAvailable(false /*updateAvailable*/);
@@ -17331,7 +17410,7 @@ public class PackageManagerService extends IPackageManager.Stub
try {
Trace.traceBegin(TRACE_TAG_PACKAGE_MANAGER, "reconcilePackages");
reconciledPackages = reconcilePackagesLocked(
- reconcileRequest, mSettings.mKeySetManagerService, mInjector);
+ reconcileRequest, mSettings.getKeySetManagerService(), mInjector);
} catch (ReconcileFailure e) {
for (InstallRequest request : requests) {
request.installResult.setError("Reconciliation failed...", e);
@@ -17466,7 +17545,7 @@ public class PackageManagerService extends IPackageManager.Stub
if (performDexopt) {
// Compile the layout resources.
- if (mInjector.getSystemWrapper().getPropertyBoolean(PRECOMPILE_LAYOUTS, false)) {
+ if (SystemProperties.getBoolean(PRECOMPILE_LAYOUTS, false)) {
Trace.traceBegin(TRACE_TAG_PACKAGE_MANAGER, "compileLayouts");
mViewCompiler.compileLayouts(pkg);
Trace.traceEnd(TRACE_TAG_PACKAGE_MANAGER);
@@ -17809,7 +17888,7 @@ public class PackageManagerService extends IPackageManager.Stub
final SigningDetails sourceSigningDetails = (sourcePackageSetting == null
? SigningDetails.UNKNOWN : sourcePackageSetting.getSigningDetails());
- final KeySetManagerService ksms = mSettings.mKeySetManagerService;
+ final KeySetManagerService ksms = mSettings.getKeySetManagerService();
if (sourcePackageName.equals(parsedPackage.getPackageName())
&& (ksms.shouldCheckUpgradeKeySetLocked(
sourcePackageSetting, scanFlags))) {
@@ -17893,8 +17972,7 @@ public class PackageManagerService extends IPackageManager.Stub
Trace.traceBegin(TRACE_TAG_PACKAGE_MANAGER, "parsePackage");
final ParsedPackage parsedPackage;
- try (PackageParser2 pp = new PackageParser2(mSeparateProcesses, false, mMetrics, null,
- mPackageParserCallback)) {
+ try (PackageParser2 pp = mInjector.getPreparingPackageParser()) {
parsedPackage = pp.parsePackage(tmpPackageFile, parseFlags, false);
AndroidPackageUtils.validatePackageDexMetadata(parsedPackage);
} catch (PackageParserException e) {
@@ -17943,8 +18021,8 @@ public class PackageManagerService extends IPackageManager.Stub
if (args.signingDetails != PackageParser.SigningDetails.UNKNOWN) {
parsedPackage.setSigningDetails(args.signingDetails);
} else {
- parsedPackage.setSigningDetails(
- ParsingPackageUtils.getSigningDetails(parsedPackage, false /* skipVerify */));
+ parsedPackage.setSigningDetails(ParsingPackageUtils.getSigningDetails(
+ parsedPackage, false /* skipVerify */));
}
} catch (PackageParserException e) {
throw new PrepareFailure("Failed collect during installPackageLI", e);
@@ -18008,7 +18086,7 @@ public class PackageManagerService extends IPackageManager.Stub
}
}
- PackageSetting ps = mSettings.mPackages.get(pkgName);
+ PackageSetting ps = mSettings.getPackageLPr(pkgName);
if (ps != null) {
if (DEBUG_INSTALL) Slog.d(TAG, "Existing package: " + ps);
@@ -18027,7 +18105,7 @@ public class PackageManagerService extends IPackageManager.Stub
// Quick validity check that we're signed correctly if updating;
// we'll check this again later when scanning, but we want to
// bail early here before tripping over redefined permissions.
- final KeySetManagerService ksms = mSettings.mKeySetManagerService;
+ final KeySetManagerService ksms = mSettings.getKeySetManagerService();
if (ksms.shouldCheckUpgradeKeySetLocked(signatureCheckPs, scanFlags)) {
if (!ksms.checkUpgradeKeySetLocked(signatureCheckPs, parsedPackage)) {
throw new PrepareFailure(INSTALL_FAILED_UPDATE_INCOMPATIBLE, "Package "
@@ -18208,7 +18286,7 @@ public class PackageManagerService extends IPackageManager.Stub
scanFlags |= SCAN_MOVE;
synchronized (mLock) {
- final PackageSetting ps = mSettings.mPackages.get(pkgName);
+ final PackageSetting ps = mSettings.getPackageLPr(pkgName);
if (ps == null) {
res.setError(INSTALL_FAILED_INTERNAL_ERROR,
"Missing settings for moved package " + pkgName);
@@ -18237,7 +18315,7 @@ public class PackageManagerService extends IPackageManager.Stub
final Pair<PackageAbiHelper.Abis, PackageAbiHelper.NativeLibraryPaths>
derivedAbi = mInjector.getAbiHelper().derivePackageAbi(parsedPackage,
isUpdatedSystemAppFromExistingSetting || isUpdatedSystemAppInferred,
- abiOverride);
+ abiOverride, mAppLib32InstallDir);
derivedAbi.first.applyTo(parsedPackage);
derivedAbi.second.applyTo(parsedPackage);
} catch (PackageManagerException pme) {
@@ -18306,11 +18384,11 @@ public class PackageManagerService extends IPackageManager.Stub
"replacePackageLI: new=" + parsedPackage + ", old=" + oldPackage);
}
- ps = mSettings.mPackages.get(pkgName11);
+ ps = mSettings.getPackageLPr(pkgName11);
disabledPs = mSettings.getDisabledSystemPkgLPr(ps);
// verify signatures are valid
- final KeySetManagerService ksms = mSettings.mKeySetManagerService;
+ final KeySetManagerService ksms = mSettings.getKeySetManagerService();
if (ksms.shouldCheckUpgradeKeySetLocked(ps, scanFlags)) {
if (!ksms.checkUpgradeKeySetLocked(ps, parsedPackage)) {
throw new PrepareFailure(INSTALL_FAILED_UPDATE_INCOMPATIBLE,
@@ -18513,7 +18591,7 @@ public class PackageManagerService extends IPackageManager.Stub
ArrayMap<String, String> fsverityCandidates = new ArrayMap<>();
if (legacyMode) {
synchronized (mLock) {
- final PackageSetting ps = mSettings.mPackages.get(pkg.getPackageName());
+ final PackageSetting ps = mSettings.getPackageLPr(pkg.getPackageName());
if (ps != null && ps.isPrivileged()) {
fsverityCandidates.put(pkg.getBaseApkPath(), null);
if (pkg.getSplitCodePaths() != null) {
@@ -18931,7 +19009,7 @@ public class PackageManagerService extends IPackageManager.Stub
// Queue up an async operation since the package deletion may take a little while.
mHandler.post(() -> {
int returnCode;
- final PackageSetting ps = mSettings.mPackages.get(internalPackageName);
+ final PackageSetting ps = mSettings.getPackageLPr(internalPackageName);
boolean doDeletePackage = true;
if (ps != null) {
final boolean targetIsInstantApp =
@@ -19209,7 +19287,7 @@ public class PackageManagerService extends IPackageManager.Stub
int[] allUsers;
/** enabled state of the uninstalled application */
synchronized (mLock) {
- uninstalledPs = mSettings.mPackages.get(packageName);
+ uninstalledPs = mSettings.getPackageLPr(packageName);
if (uninstalledPs == null) {
Slog.w(TAG, "Not removing non-existent package " + packageName);
return PackageManager.DELETE_FAILED_INTERNAL_ERROR;
@@ -19508,7 +19586,7 @@ public class PackageManagerService extends IPackageManager.Stub
synchronized (mLock) {
clearIntentFilterVerificationsLPw(deletedPs.name, UserHandle.USER_ALL, true);
clearDefaultBrowserIfNeeded(packageName);
- mSettings.mKeySetManagerService.removeAppKeySetDataLPw(packageName);
+ mSettings.getKeySetManagerService().removeAppKeySetDataLPw(packageName);
mAppsFilter.removePackage(getPackageSetting(packageName));
removedAppId = mSettings.removePackageLPw(packageName);
if (outInfo != null) {
@@ -19658,7 +19736,7 @@ public class PackageManagerService extends IPackageManager.Stub
// We've re-installed the stub; make sure it's disabled here. If package was
// originally enabled, we'll install the compressed version of the application
// and re-enable it afterward.
- final PackageSetting stubPs = mSettings.mPackages.get(deletedPkg.getPackageName());
+ final PackageSetting stubPs = mSettings.getPackageLPr(deletedPkg.getPackageName());
if (stubPs != null) {
int userId = action.user == null
? UserHandle.USER_ALL : action.user.getIdentifier();
@@ -19714,7 +19792,7 @@ public class PackageManagerService extends IPackageManager.Stub
// writer
synchronized (mLock) {
- PackageSetting ps = mSettings.mPackages.get(pkg.getPackageName());
+ PackageSetting ps = mSettings.getPackageLPr(pkg.getPackageName());
final boolean applyUserRestrictions = origUserHandles != null;
if (applyUserRestrictions) {
@@ -19807,7 +19885,7 @@ public class PackageManagerService extends IPackageManager.Stub
@Override
public boolean getBlockUninstallForUser(String packageName, int userId) {
synchronized (mLock) {
- final PackageSetting ps = mSettings.mPackages.get(packageName);
+ final PackageSetting ps = mSettings.getPackageLPr(packageName);
if (ps == null || shouldFilterApplicationLocked(ps, Binder.getCallingUid(), userId)) {
return false;
}
@@ -19819,7 +19897,7 @@ public class PackageManagerService extends IPackageManager.Stub
public boolean setRequiredForSystemUser(String packageName, boolean systemUserApp) {
enforceSystemOrRoot("setRequiredForSystemUser can only be run by the system or root");
synchronized (mLock) {
- PackageSetting ps = mSettings.mPackages.get(packageName);
+ PackageSetting ps = mSettings.getPackageLPr(packageName);
if (ps == null) {
Log.w(TAG, "Package doesn't exist: " + packageName);
return false;
@@ -19887,7 +19965,7 @@ public class PackageManagerService extends IPackageManager.Stub
ParsedPackage replacingPackage) {
final DeletePackageAction action;
synchronized (mLock) {
- final PackageSetting ps = mSettings.mPackages.get(packageName);
+ final PackageSetting ps = mSettings.getPackageLPr(packageName);
final PackageSetting disabledPs = mSettings.getDisabledSystemPkgLPr(ps);
action = mayDeletePackageLocked(outInfo, ps, disabledPs, flags, user);
}
@@ -20177,7 +20255,7 @@ public class PackageManagerService extends IPackageManager.Stub
PackageSetting ps;
synchronized (mLock) {
pkg = mPackages.get(packageName);
- ps = mSettings.mPackages.get(packageName);
+ ps = mSettings.getPackageLPr(packageName);
if (pkg == null) {
if (ps != null) {
pkg = ps.pkg;
@@ -20314,7 +20392,7 @@ public class PackageManagerService extends IPackageManager.Stub
private boolean getPackageSizeInfoLI(String packageName, int userId, PackageStats stats) {
final PackageSetting ps;
synchronized (mLock) {
- ps = mSettings.mPackages.get(packageName);
+ ps = mSettings.getPackageLPr(packageName);
if (ps == null) {
Slog.w(TAG, "Failed to find settings for " + packageName);
return false;
@@ -20621,10 +20699,10 @@ public class PackageManagerService extends IPackageManager.Stub
}
private void clearDefaultBrowserIfNeededForUser(String packageName, int userId) {
- final String defaultBrowserPackageName = mPermissionManager.getDefaultBrowser(userId);
+ final String defaultBrowserPackageName = mDefaultAppProvider.getDefaultBrowser(userId);
if (!TextUtils.isEmpty(defaultBrowserPackageName)) {
if (packageName.equals(defaultBrowserPackageName)) {
- mPermissionManager.setDefaultBrowser(null, true, true, userId);
+ mDefaultAppProvider.setDefaultBrowser(null, true, true, userId);
}
}
}
@@ -20639,7 +20717,7 @@ public class PackageManagerService extends IPackageManager.Stub
// If this browser is restored from user's backup, do not clear
// default-browser state for this user
if (installReason != PackageManager.INSTALL_REASON_DEVICE_RESTORE) {
- mPermissionManager.setDefaultBrowser(null, true, true, userId);
+ mDefaultAppProvider.setDefaultBrowser(null, true, true, userId);
}
}
@@ -20678,7 +20756,7 @@ public class PackageManagerService extends IPackageManager.Stub
// significant refactoring to keep all default apps in the package
// manager (cleaner but more work) or have the services provide
// callbacks to the package manager to request a default app reset.
- mPermissionManager.setDefaultBrowser(null, true, true, userId);
+ mDefaultAppProvider.setDefaultBrowser(null, true, true, userId);
resetNetworkPolicies(userId);
synchronized (mLock) {
scheduleWritePackageRestrictionsLocked(userId);
@@ -20912,8 +20990,8 @@ public class PackageManagerService extends IPackageManager.Stub
defaultBrowser = mSettings.removeDefaultBrowserPackageNameLPw(userId1);
}
if (defaultBrowser != null) {
- mPermissionManager
- .setDefaultBrowser(defaultBrowser, false, false, userId1);
+ mDefaultAppProvider.setDefaultBrowser(defaultBrowser, false, false,
+ userId1);
}
});
} catch (Exception e) {
@@ -21153,7 +21231,7 @@ public class PackageManagerService extends IPackageManager.Stub
}
allHomeCandidates.addAll(resolveInfos);
- final String packageName = mPermissionManager.getDefaultHome(userId);
+ final String packageName = mDefaultAppProvider.getDefaultHome(userId);
if (packageName == null) {
return null;
}
@@ -21207,7 +21285,7 @@ public class PackageManagerService extends IPackageManager.Stub
final String packageName = preferredResolveInfo != null
&& preferredResolveInfo.activityInfo != null
? preferredResolveInfo.activityInfo.packageName : null;
- final String currentPackageName = mPermissionManager.getDefaultHome(userId);
+ final String currentPackageName = mDefaultAppProvider.getDefaultHome(userId);
if (TextUtils.equals(currentPackageName, packageName)) {
return false;
}
@@ -21222,12 +21300,12 @@ public class PackageManagerService extends IPackageManager.Stub
// Keep the default home package in RoleManager.
return false;
}
- mPermissionManager.setDefaultHome(packageName, userId, (successful) -> {
- if (successful) {
- postPreferredActivityChangedBroadcast(userId);
- }
- });
- return true;
+ return mDefaultAppProvider.setDefaultHome(packageName, userId, mContext.getMainExecutor(),
+ successful -> {
+ if (successful) {
+ postPreferredActivityChangedBroadcast(userId);
+ }
+ });
}
@Override
@@ -21490,7 +21568,7 @@ public class PackageManagerService extends IPackageManager.Stub
public void setUpdateAvailable(String packageName, boolean updateAvailable) {
mContext.enforceCallingOrSelfPermission(android.Manifest.permission.INSTALL_PACKAGES, null);
synchronized (mLock) {
- final PackageSetting pkgSetting = mSettings.mPackages.get(packageName);
+ final PackageSetting pkgSetting = mSettings.getPackageLPr(packageName);
if (pkgSetting != null) {
pkgSetting.setUpdateAvailable(updateAvailable);
}
@@ -21615,7 +21693,7 @@ public class PackageManagerService extends IPackageManager.Stub
// reader
synchronized (mLock) {
- pkgSetting = mSettings.mPackages.get(packageName);
+ pkgSetting = mSettings.getPackageLPr(packageName);
if (pkgSetting == null) {
if (!isCallerInstantApp) {
if (className == null) {
@@ -21879,7 +21957,7 @@ public class PackageManagerService extends IPackageManager.Stub
return;
}
broadcastAllowList = isInstantApp ? null : mAppsFilter.getVisibilityAllowList(setting,
- userIds, mSettings.mPackages);
+ userIds, mSettings.getPackagesLocked());
}
sendPackageBroadcast(Intent.ACTION_PACKAGE_CHANGED, packageName, extras, flags, null, null,
userIds, instantUserIds, broadcastAllowList);
@@ -21899,7 +21977,7 @@ public class PackageManagerService extends IPackageManager.Stub
true /* checkShell */, "stop package");
// writer
synchronized (mLock) {
- final PackageSetting ps = mSettings.mPackages.get(packageName);
+ final PackageSetting ps = mSettings.getPackageLPr(packageName);
if (!shouldFilterApplicationLocked(ps, callingUid, userId)
&& mSettings.setPackageStoppedStateLPw(this, packageName, stopped,
allowedByPermission, callingUid, userId)) {
@@ -21918,7 +21996,7 @@ public class PackageManagerService extends IPackageManager.Stub
}
String installerPackageName = installSource.installerPackageName;
if (installerPackageName != null) {
- final PackageSetting ps = mSettings.mPackages.get(installerPackageName);
+ final PackageSetting ps = mSettings.getPackageLPr(installerPackageName);
if (ps == null || shouldFilterApplicationLocked(ps, callingUid,
UserHandle.getUserId(callingUid))) {
installerPackageName = null;
@@ -21947,7 +22025,7 @@ public class PackageManagerService extends IPackageManager.Stub
installerPackageName = installSource.installerPackageName;
if (installerPackageName != null) {
- final PackageSetting ps = mSettings.mPackages.get(installerPackageName);
+ final PackageSetting ps = mSettings.getPackageLPr(installerPackageName);
if (ps == null || shouldFilterApplicationLocked(ps, callingUid, userId)) {
installerPackageName = null;
}
@@ -21972,7 +22050,7 @@ public class PackageManagerService extends IPackageManager.Stub
initiatingPackageName = installerPackageName;
} else {
initiatingPackageName = installSource.initiatingPackageName;
- final PackageSetting ps = mSettings.mPackages.get(initiatingPackageName);
+ final PackageSetting ps = mSettings.getPackageLPr(initiatingPackageName);
if (ps == null || shouldFilterApplicationLocked(ps, callingUid, userId)) {
initiatingPackageName = null;
}
@@ -21981,7 +22059,7 @@ public class PackageManagerService extends IPackageManager.Stub
originatingPackageName = installSource.originatingPackageName;
if (originatingPackageName != null) {
- final PackageSetting ps = mSettings.mPackages.get(originatingPackageName);
+ final PackageSetting ps = mSettings.getPackageLPr(originatingPackageName);
if (ps == null || shouldFilterApplicationLocked(ps, callingUid, userId)) {
originatingPackageName = null;
}
@@ -22014,7 +22092,7 @@ public class PackageManagerService extends IPackageManager.Stub
@GuardedBy("mLock")
@Nullable
private InstallSource getInstallSourceLocked(String packageName, int callingUid) {
- final PackageSetting ps = mSettings.mPackages.get(packageName);
+ final PackageSetting ps = mSettings.getPackageLPr(packageName);
// Installer info for Apex is not stored in PackageManager
if (ps == null && mApexManager.isApexPackage(packageName)) {
@@ -22677,13 +22755,14 @@ public class PackageManagerService extends IPackageManager.Stub
&& dumpState.isDumping(DumpState.DUMP_DOMAIN_PREFERRED)
&& packageName == null) {
pw.println();
- int count = mSettings.mPackages.size();
+ int count = mSettings.getPackagesLocked().size();
if (count == 0) {
pw.println("No applications!");
pw.println();
} else {
final String prefix = " ";
- Collection<PackageSetting> allPackageSettings = mSettings.mPackages.values();
+ Collection<PackageSetting> allPackageSettings =
+ mSettings.getPackagesLocked().values();
if (allPackageSettings.size() == 0) {
pw.println("No domain preferred apps!");
pw.println();
@@ -22740,7 +22819,7 @@ public class PackageManagerService extends IPackageManager.Stub
}
if (!checkin && dumpState.isDumping(DumpState.DUMP_KEYSETS)) {
- mSettings.mKeySetManagerService.dumpLPr(pw, packageName, dumpState);
+ mSettings.getKeySetManagerService().dumpLPr(pw, packageName, dumpState);
}
if (dumpState.isDumping(DumpState.DUMP_PACKAGES)) {
@@ -22871,7 +22950,7 @@ public class PackageManagerService extends IPackageManager.Stub
if (ArrayUtils.isEmpty(apkList)) {
return;
}
- String sku = mInjector.getSystemWrapper().getProperty("ro.boot.hardware.sku");
+ String sku = SystemProperties.get("ro.boot.hardware.sku");
if (!TextUtils.isEmpty(sku) && ArrayUtils.contains(skuArray, sku)) {
return;
}
@@ -22967,7 +23046,7 @@ public class PackageManagerService extends IPackageManager.Stub
ipw.increaseIndent();
Collection<PackageSetting> pkgSettings;
if (packageName != null) {
- PackageSetting targetPkgSetting = mSettings.mPackages.get(packageName);
+ PackageSetting targetPkgSetting = mSettings.getPackageLPr(packageName);
if (targetPkgSetting != null) {
pkgSettings = Collections.singletonList(targetPkgSetting);
} else {
@@ -22975,7 +23054,7 @@ public class PackageManagerService extends IPackageManager.Stub
return;
}
} else {
- pkgSettings = mSettings.mPackages.values();
+ pkgSettings = mSettings.getPackagesLocked().values();
}
for (PackageSetting pkgSetting : pkgSettings) {
@@ -23276,7 +23355,7 @@ public class PackageManagerService extends IPackageManager.Stub
// Normalize package name to handle renamed packages
packageName = normalizePackageNameLPr(packageName);
- final PackageSetting ps = mSettings.mPackages.get(packageName);
+ final PackageSetting ps = mSettings.getPackageLPr(packageName);
if (ps == null) {
throw new PackageManagerException("Package " + packageName + " is unknown");
} else if (!TextUtils.equals(volumeUuid, ps.volumeUuid)) {
@@ -23293,9 +23372,9 @@ public class PackageManagerService extends IPackageManager.Stub
private List<String> collectAbsoluteCodePaths() {
synchronized (mLock) {
List<String> codePaths = new ArrayList<>();
- final int packageCount = mSettings.mPackages.size();
+ final int packageCount = mSettings.getPackagesLocked().size();
for (int i = 0; i < packageCount; i++) {
- final PackageSetting ps = mSettings.mPackages.valueAt(i);
+ final PackageSetting ps = mSettings.getPackagesLocked().valueAt(i);
codePaths.add(ps.getPath().getAbsolutePath());
}
return codePaths;
@@ -23497,7 +23576,7 @@ public class PackageManagerService extends IPackageManager.Stub
private void prepareAppDataAfterInstallLIF(AndroidPackage pkg) {
final PackageSetting ps;
synchronized (mLock) {
- ps = mSettings.mPackages.get(pkg.getPackageName());
+ ps = mSettings.getPackageLPr(pkg.getPackageName());
mSettings.writeKernelMappingLPr(ps);
}
@@ -23574,7 +23653,7 @@ public class PackageManagerService extends IPackageManager.Stub
final PackageSetting ps;
synchronized (mLock) {
- ps = mSettings.mPackages.get(pkg.getPackageName());
+ ps = mSettings.getPackageLPr(pkg.getPackageName());
}
final String volumeUuid = pkg.getVolumeUuid();
final String packageName = pkg.getPackageName();
@@ -23769,7 +23848,7 @@ public class PackageManagerService extends IPackageManager.Stub
mPackageName = packageName;
mWeFroze = mFrozenPackages.add(mPackageName);
- final PackageSetting ps = mSettings.mPackages.get(mPackageName);
+ final PackageSetting ps = mSettings.getPackageLPr(mPackageName);
if (ps != null) {
killApplication(ps.name, ps.appId, userId, killReason);
}
@@ -23851,7 +23930,7 @@ public class PackageManagerService extends IPackageManager.Stub
// reader
synchronized (mLock) {
final AndroidPackage pkg = mPackages.get(packageName);
- final PackageSetting ps = mSettings.mPackages.get(packageName);
+ final PackageSetting ps = mSettings.getPackageLPr(packageName);
if (pkg == null
|| ps == null
|| shouldFilterApplicationLocked(ps, callingUid, user.getIdentifier())) {
@@ -24182,9 +24261,9 @@ public class PackageManagerService extends IPackageManager.Stub
private void removeUnusedPackagesLPw(UserManagerService userManager, final int userId) {
final boolean DEBUG_CLEAN_APKS = false;
int [] users = userManager.getUserIds();
- final int numPackages = mSettings.mPackages.size();
+ final int numPackages = mSettings.getPackagesLocked().size();
for (int index = 0; index < numPackages; index++) {
- final PackageSetting ps = mSettings.mPackages.valueAt(index);
+ final PackageSetting ps = mSettings.getPackagesLocked().valueAt(index);
if (ps.pkg == null) {
continue;
}
@@ -24353,7 +24432,7 @@ public class PackageManagerService extends IPackageManager.Stub
Slog.w(TAG, "KeySet requested for filtered package: " + packageName);
throw new IllegalArgumentException("Unknown package: " + packageName);
}
- final KeySetManagerService ksms = mSettings.mKeySetManagerService;
+ final KeySetManagerService ksms = mSettings.getKeySetManagerService();
return new KeySet(ksms.getKeySetByAliasAndPackageNameLPr(packageName, alias));
}
}
@@ -24382,7 +24461,7 @@ public class PackageManagerService extends IPackageManager.Stub
&& Process.SYSTEM_UID != callingUid) {
throw new SecurityException("May not access signing KeySet of other apps.");
}
- final KeySetManagerService ksms = mSettings.mKeySetManagerService;
+ final KeySetManagerService ksms = mSettings.getKeySetManagerService();
return new KeySet(ksms.getSigningKeySetByPackageNameLPr(packageName));
}
}
@@ -24406,7 +24485,7 @@ public class PackageManagerService extends IPackageManager.Stub
}
IBinder ksh = ks.getToken();
if (ksh instanceof KeySetHandle) {
- final KeySetManagerService ksms = mSettings.mKeySetManagerService;
+ final KeySetManagerService ksms = mSettings.getKeySetManagerService();
return ksms.packageIsSignedByLPr(packageName, (KeySetHandle) ksh);
}
return false;
@@ -24432,7 +24511,7 @@ public class PackageManagerService extends IPackageManager.Stub
}
IBinder ksh = ks.getToken();
if (ksh instanceof KeySetHandle) {
- final KeySetManagerService ksms = mSettings.mKeySetManagerService;
+ final KeySetManagerService ksms = mSettings.getKeySetManagerService();
return ksms.packageIsSignedByExactlyLPr(packageName, (KeySetHandle) ksh);
}
return false;
@@ -24441,7 +24520,7 @@ public class PackageManagerService extends IPackageManager.Stub
@GuardedBy("mLock")
private void deletePackageIfUnusedLPr(final String packageName) {
- PackageSetting ps = mSettings.mPackages.get(packageName);
+ PackageSetting ps = mSettings.getPackageLPr(packageName);
if (ps == null) {
return;
}
@@ -24777,7 +24856,7 @@ public class PackageManagerService extends IPackageManager.Stub
@Override
public boolean isPlatformSigned(String packageName) {
- PackageSetting packageSetting = mSettings.mPackages.get(packageName);
+ PackageSetting packageSetting = mSettings.getPackageLPr(packageName);
if (packageSetting == null) {
return false;
}
@@ -24977,7 +25056,7 @@ public class PackageManagerService extends IPackageManager.Stub
private String[] getKnownPackageNamesInternal(int knownPackage, int userId) {
switch (knownPackage) {
case PackageManagerInternal.PACKAGE_BROWSER:
- return new String[]{mPermissionManager.getDefaultBrowser(userId)};
+ return new String[] { mDefaultAppProvider.getDefaultBrowser(userId) };
case PackageManagerInternal.PACKAGE_INSTALLER:
return filterOnlySystemPackages(mRequiredInstallerPackage);
case PackageManagerInternal.PACKAGE_SETUP_WIZARD:
@@ -25066,7 +25145,7 @@ public class PackageManagerService extends IPackageManager.Stub
@Override
public long getCeDataInode(String packageName, int userId) {
synchronized (mLock) {
- final PackageSetting ps = mSettings.mPackages.get(packageName);
+ final PackageSetting ps = mSettings.getPackageLPr(packageName);
if (ps != null) {
return ps.getCeDataInode(userId);
}
@@ -25077,7 +25156,7 @@ public class PackageManagerService extends IPackageManager.Stub
@Override
public Bundle getSuspendedPackageLauncherExtras(String packageName, int userId) {
synchronized (mLock) {
- final PackageSetting ps = mSettings.mPackages.get(packageName);
+ final PackageSetting ps = mSettings.getPackageLPr(packageName);
final Bundle allExtras = new Bundle();
if (ps != null) {
final PackageUserState pus = ps.readUserState(userId);
@@ -25099,7 +25178,7 @@ public class PackageManagerService extends IPackageManager.Stub
@Override
public boolean isPackageSuspended(String packageName, int userId) {
synchronized (mLock) {
- final PackageSetting ps = mSettings.mPackages.get(packageName);
+ final PackageSetting ps = mSettings.getPackageLPr(packageName);
return (ps != null) ? ps.getSuspended(userId) : false;
}
}
@@ -25144,7 +25223,7 @@ public class PackageManagerService extends IPackageManager.Stub
@Override
public String getSuspendingPackage(String suspendedPackage, int userId) {
synchronized (mLock) {
- final PackageSetting ps = mSettings.mPackages.get(suspendedPackage);
+ final PackageSetting ps = mSettings.getPackageLPr(suspendedPackage);
if (ps != null) {
final PackageUserState pus = ps.readUserState(userId);
if (pus.suspended) {
@@ -25166,7 +25245,7 @@ public class PackageManagerService extends IPackageManager.Stub
public SuspendDialogInfo getSuspendedDialogInfo(String suspendedPackage,
String suspendingPackage, int userId) {
synchronized (mLock) {
- final PackageSetting ps = mSettings.mPackages.get(suspendedPackage);
+ final PackageSetting ps = mSettings.getPackageLPr(suspendedPackage);
if (ps != null) {
final PackageUserState pus = ps.readUserState(userId);
if (pus.suspended) {
@@ -25182,7 +25261,7 @@ public class PackageManagerService extends IPackageManager.Stub
@Override
public int getDistractingPackageRestrictions(String packageName, int userId) {
synchronized (mLock) {
- final PackageSetting ps = mSettings.mPackages.get(packageName);
+ final PackageSetting ps = mSettings.getPackageLPr(packageName);
return (ps != null) ? ps.getDistractionFlags(userId) : RESTRICTION_NONE;
}
}
@@ -25278,7 +25357,7 @@ public class PackageManagerService extends IPackageManager.Stub
@Override
public boolean isPackageEphemeral(int userId, String packageName) {
synchronized (mLock) {
- final PackageSetting ps = mSettings.mPackages.get(packageName);
+ final PackageSetting ps = mSettings.getPackageLPr(packageName);
return ps != null ? ps.getInstantApp(userId) : false;
}
}
@@ -25469,7 +25548,7 @@ public class PackageManagerService extends IPackageManager.Stub
continue;
}
for (VersionedPackage dependent : dependents) {
- final PackageSetting ps = mSettings.mPackages.get(
+ final PackageSetting ps = mSettings.getPackageLPr(
dependent.getPackageName());
if (ps == null) {
continue;
@@ -25480,7 +25559,7 @@ public class PackageManagerService extends IPackageManager.Stub
}
}
- final PackageSetting ps = mSettings.mPackages.get(targetPackageName);
+ final PackageSetting ps = mSettings.getPackageLPr(targetPackageName);
ps.setOverlayPaths(overlayPaths, userId);
outUpdatedPackageNames.add(targetPackageName);
@@ -25550,7 +25629,7 @@ public class PackageManagerService extends IPackageManager.Stub
@Override
public boolean canAccessComponent(int callingUid, ComponentName component, int userId) {
synchronized (mLock) {
- final PackageSetting ps = mSettings.mPackages.get(component.getPackageName());
+ final PackageSetting ps = mSettings.getPackageLPr(component.getPackageName());
return ps != null && !PackageManagerService.this.shouldFilterApplicationLocked(
ps, callingUid, component, TYPE_UNKNOWN, userId);
}
@@ -25616,8 +25695,8 @@ public class PackageManagerService extends IPackageManager.Stub
@Override
public void forEachPackageSetting(Consumer<PackageSetting> actionLocked) {
synchronized (mLock) {
- for (int index = 0; index < mSettings.mPackages.size(); index++) {
- actionLocked.accept(mSettings.mPackages.valueAt(index));
+ for (int index = 0; index < mSettings.getPackagesLocked().size(); index++) {
+ actionLocked.accept(mSettings.getPackagesLocked().valueAt(index));
}
}
}
@@ -25793,7 +25872,7 @@ public class PackageManagerService extends IPackageManager.Stub
return false;
}
final PackageSetting installerPackageSetting =
- mSettings.mPackages.get(packageSetting.installSource.installerPackageName);
+ mSettings.getPackageLPr(packageSetting.installSource.installerPackageName);
return installerPackageSetting != null
&& UserHandle.isSameApp(installerPackageSetting.appId, callingUid);
}
@@ -25894,7 +25973,7 @@ public class PackageManagerService extends IPackageManager.Stub
PackageManagerInternal.InstalledLoadingProgressCallback callback) {
final PackageSetting ps;
synchronized (mLock) {
- ps = mSettings.mPackages.get(packageName);
+ ps = mSettings.getPackageLPr(packageName);
if (ps == null) {
Slog.w(TAG, "Failed unregistering loading progress callback. Package "
+ packageName + " is not installed");
@@ -25957,7 +26036,7 @@ public class PackageManagerService extends IPackageManager.Stub
@GuardedBy("mLock")
@NonNull
private String[] getSharedUserPackagesForPackageLocked(String packageName, int userId) {
- final PackageSetting packageSetting = mSettings.mPackages.get(packageName);
+ final PackageSetting packageSetting = mSettings.getPackageLPr(packageName);
if (packageSetting == null || !packageSetting.isSharedUser()) {
return EmptyArray.STRING;
}
@@ -26034,7 +26113,7 @@ public class PackageManagerService extends IPackageManager.Stub
synchronized (mLock) {
packageName = resolveInternalPackageNameInternalLocked(
packageName, PackageManager.VERSION_CODE_HIGHEST, callingUid);
- return mSettings.mPackages.get(packageName);
+ return mSettings.getPackageLPr(packageName);
}
}
@@ -26125,7 +26204,7 @@ public class PackageManagerService extends IPackageManager.Stub
enforceCrossUserPermission(callingUid, userId, true /* requireFullPermission */,
false /* checkShell */, "get install reason");
synchronized (mLock) {
- final PackageSetting ps = mSettings.mPackages.get(packageName);
+ final PackageSetting ps = mSettings.getPackageLPr(packageName);
if (shouldFilterApplicationLocked(ps, callingUid, userId)) {
return PackageManager.INSTALL_REASON_UNKNOWN;
}
@@ -26298,7 +26377,7 @@ public class PackageManagerService extends IPackageManager.Stub
long currentTimeInMillis = System.currentTimeMillis();
synchronized (mLock) {
for (AndroidPackage pkg : mPackages.values()) {
- PackageSetting ps = mSettings.mPackages.get(pkg.getPackageName());
+ PackageSetting ps = mSettings.getPackageLPr(pkg.getPackageName());
if (ps == null) {
continue;
}
@@ -26410,7 +26489,7 @@ public class PackageManagerService extends IPackageManager.Stub
@Override
public void setMimeGroup(String packageName, String mimeGroup, List<String> mimeTypes) {
- boolean changed = mSettings.mPackages.get(packageName)
+ boolean changed = mSettings.getPackageLPr(packageName)
.setMimeGroup(mimeGroup, mimeTypes);
if (changed) {
@@ -26420,7 +26499,7 @@ public class PackageManagerService extends IPackageManager.Stub
@Override
public List<String> getMimeGroup(String packageName, String mimeGroup) {
- return mSettings.mPackages.get(packageName).getMimeGroup(mimeGroup);
+ return mSettings.getPackageLPr(packageName).getMimeGroup(mimeGroup);
}
/**
diff --git a/services/core/java/com/android/server/pm/Settings.java b/services/core/java/com/android/server/pm/Settings.java
index f47b4b46fdd4..cb4c6a9fd564 100644
--- a/services/core/java/com/android/server/pm/Settings.java
+++ b/services/core/java/com/android/server/pm/Settings.java
@@ -475,6 +475,14 @@ public final class Settings {
return mPackages.get(pkgName);
}
+ ArrayMap<String, PackageSetting> getPackagesLocked() {
+ return mPackages;
+ }
+
+ KeySetManagerService getKeySetManagerService() {
+ return mKeySetManagerService;
+ }
+
String getRenamedPackageLPr(String pkgName) {
return mRenamedPackages.get(pkgName);
}
@@ -1969,28 +1977,28 @@ public final class Settings {
serializer.attributeLong(null, ATTR_CE_DATA_INODE, ustate.ceDataInode);
}
if (!ustate.installed) {
- serializer.attribute(null, ATTR_INSTALLED, "false");
+ serializer.attributeBoolean(null, ATTR_INSTALLED, false);
}
if (ustate.stopped) {
- serializer.attribute(null, ATTR_STOPPED, "true");
+ serializer.attributeBoolean(null, ATTR_STOPPED, true);
}
if (ustate.notLaunched) {
- serializer.attribute(null, ATTR_NOT_LAUNCHED, "true");
+ serializer.attributeBoolean(null, ATTR_NOT_LAUNCHED, true);
}
if (ustate.hidden) {
- serializer.attribute(null, ATTR_HIDDEN, "true");
+ serializer.attributeBoolean(null, ATTR_HIDDEN, true);
}
if (ustate.distractionFlags != 0) {
serializer.attributeInt(null, ATTR_DISTRACTION_FLAGS, ustate.distractionFlags);
}
if (ustate.suspended) {
- serializer.attribute(null, ATTR_SUSPENDED, "true");
+ serializer.attributeBoolean(null, ATTR_SUSPENDED, true);
}
if (ustate.instantApp) {
- serializer.attribute(null, ATTR_INSTANT_APP, "true");
+ serializer.attributeBoolean(null, ATTR_INSTANT_APP, true);
}
if (ustate.virtualPreload) {
- serializer.attribute(null, ATTR_VIRTUAL_PRELOAD, "true");
+ serializer.attributeBoolean(null, ATTR_VIRTUAL_PRELOAD, true);
}
if (ustate.enabled != COMPONENT_ENABLED_STATE_DEFAULT) {
serializer.attributeInt(null, ATTR_ENABLED, ustate.enabled);
@@ -2731,7 +2739,7 @@ public final class Settings {
serializer.attributeInt(null, "sharedUserId", pkg.appId);
}
if (pkg.uidError) {
- serializer.attribute(null, "uidError", "true");
+ serializer.attributeBoolean(null, "uidError", true);
}
InstallSource installSource = pkg.installSource;
if (installSource.installerPackageName != null) {
@@ -2742,13 +2750,13 @@ public final class Settings {
installSource.installerAttributionTag);
}
if (installSource.isOrphaned) {
- serializer.attribute(null, "isOrphaned", "true");
+ serializer.attributeBoolean(null, "isOrphaned", true);
}
if (installSource.initiatingPackageName != null) {
serializer.attribute(null, "installInitiator", installSource.initiatingPackageName);
}
if (installSource.isInitiatingPackageUninstalled) {
- serializer.attribute(null, "installInitiatorUninstalled", "true");
+ serializer.attributeBoolean(null, "installInitiatorUninstalled", true);
}
if (installSource.originatingPackageName != null) {
serializer.attribute(null, "installOriginator", installSource.originatingPackageName);
@@ -2760,16 +2768,16 @@ public final class Settings {
serializer.attributeInt(null, "categoryHint", pkg.categoryHint);
}
if (pkg.updateAvailable) {
- serializer.attribute(null, "updateAvailable", "true");
+ serializer.attributeBoolean(null, "updateAvailable", true);
}
if (pkg.forceQueryableOverride) {
- serializer.attribute(null, "forceQueryable", "true");
+ serializer.attributeBoolean(null, "forceQueryable", true);
}
if (pkg.isPackageStartable()) {
- serializer.attribute(null, "isStartable", "true");
+ serializer.attributeBoolean(null, "isStartable", true);
}
if (pkg.isPackageLoading()) {
- serializer.attribute(null, "isLoading", "true");
+ serializer.attributeBoolean(null, "isLoading", true);
}
writeUsesStaticLibLPw(serializer, pkg.usesStaticLibraries, pkg.usesStaticLibrariesVersions);
@@ -3500,14 +3508,14 @@ public final class Settings {
String systemStr = null;
String installerPackageName = null;
String installerAttributionTag = null;
- String isOrphaned = null;
+ boolean isOrphaned = false;
String installOriginatingPackageName = null;
String installInitiatingPackageName = null;
- String installInitiatorUninstalled = null;
+ boolean installInitiatorUninstalled = false;
String volumeUuid = null;
- String updateAvailable = null;
+ boolean updateAvailable = false;
int categoryHint = ApplicationInfo.CATEGORY_UNDEFINED;
- String uidError = null;
+ boolean uidError = false;
int pkgFlags = 0;
int pkgPrivateFlags = 0;
long timeStamp = 0;
@@ -3515,14 +3523,14 @@ public final class Settings {
long lastUpdateTime = 0;
PackageSetting packageSetting = null;
long versionCode = 0;
- String installedForceQueryable = null;
- String isStartable = null;
- String isLoading = null;
+ boolean installedForceQueryable = false;
+ boolean isStartable = false;
+ boolean isLoading = false;
try {
name = parser.getAttributeValue(null, ATTR_NAME);
realName = parser.getAttributeValue(null, "realName");
userId = parser.getAttributeInt(null, "userId", 0);
- uidError = parser.getAttributeValue(null, "uidError");
+ uidError = parser.getAttributeBoolean(null, "uidError", false);
sharedUserId = parser.getAttributeInt(null, "sharedUserId", 0);
codePathStr = parser.getAttributeValue(null, "codePath");
@@ -3532,10 +3540,10 @@ public final class Settings {
primaryCpuAbiString = parser.getAttributeValue(null, "primaryCpuAbi");
secondaryCpuAbiString = parser.getAttributeValue(null, "secondaryCpuAbi");
cpuAbiOverrideString = parser.getAttributeValue(null, "cpuAbiOverride");
- updateAvailable = parser.getAttributeValue(null, "updateAvailable");
- installedForceQueryable = parser.getAttributeValue(null, "forceQueryable");
- isStartable = parser.getAttributeValue(null, "isStartable");
- isLoading = parser.getAttributeValue(null, "isLoading");
+ updateAvailable = parser.getAttributeBoolean(null, "updateAvailable", false);
+ installedForceQueryable = parser.getAttributeBoolean(null, "forceQueryable", false);
+ isStartable = parser.getAttributeBoolean(null, "isStartable", false);
+ isLoading = parser.getAttributeBoolean(null, "isLoading", false);
if (primaryCpuAbiString == null && legacyCpuAbiString != null) {
primaryCpuAbiString = legacyCpuAbiString;
@@ -3544,11 +3552,11 @@ public final class Settings {
versionCode = parser.getAttributeLong(null, "version", 0);
installerPackageName = parser.getAttributeValue(null, "installer");
installerAttributionTag = parser.getAttributeValue(null, "installerAttributionTag");
- isOrphaned = parser.getAttributeValue(null, "isOrphaned");
+ isOrphaned = parser.getAttributeBoolean(null, "isOrphaned", false);
installInitiatingPackageName = parser.getAttributeValue(null, "installInitiator");
installOriginatingPackageName = parser.getAttributeValue(null, "installOriginator");
- installInitiatorUninstalled = parser.getAttributeValue(null,
- "installInitiatorUninstalled");
+ installInitiatorUninstalled = parser.getAttributeBoolean(null,
+ "installInitiatorUninstalled", false);
volumeUuid = parser.getAttributeValue(null, "volumeUuid");
categoryHint = parser.getAttributeInt(null, "categoryHint",
ApplicationInfo.CATEGORY_UNDEFINED);
@@ -3670,21 +3678,20 @@ public final class Settings {
+ userId + " at " + parser.getPositionDescription());
}
if (packageSetting != null) {
- packageSetting.uidError = "true".equals(uidError);
+ packageSetting.uidError = uidError;
InstallSource installSource = InstallSource.create(
installInitiatingPackageName, installOriginatingPackageName,
- installerPackageName, installerAttributionTag, "true".equals(isOrphaned),
- "true".equals(installInitiatorUninstalled));
+ installerPackageName, installerAttributionTag, isOrphaned,
+ installInitiatorUninstalled);
packageSetting.installSource = installSource;
packageSetting.volumeUuid = volumeUuid;
packageSetting.categoryHint = categoryHint;
packageSetting.legacyNativeLibraryPathString = legacyNativeLibraryPathStr;
packageSetting.primaryCpuAbiString = primaryCpuAbiString;
packageSetting.secondaryCpuAbiString = secondaryCpuAbiString;
- packageSetting.updateAvailable = "true".equals(updateAvailable);
- packageSetting.forceQueryableOverride = "true".equals(installedForceQueryable);
- packageSetting.incrementalStates = new IncrementalStates("true".equals(isStartable),
- "true".equals(isLoading));
+ packageSetting.updateAvailable = updateAvailable;
+ packageSetting.forceQueryableOverride = installedForceQueryable;
+ packageSetting.incrementalStates = new IncrementalStates(isStartable, isLoading);
// Handle legacy string here for single-user mode
final String enabledStr = parser.getAttributeValue(null, ATTR_ENABLED);
if (enabledStr != null) {
@@ -3914,7 +3921,7 @@ public final class Settings {
{
name = parser.getAttributeValue(null, ATTR_NAME);
int userId = parser.getAttributeInt(null, "userId", 0);
- if ("true".equals(parser.getAttributeValue(null, "system"))) {
+ if (parser.getAttributeBoolean(null, "system", false)) {
pkgFlags |= ApplicationInfo.FLAG_SYSTEM;
}
if (name == null) {
@@ -5554,7 +5561,8 @@ public final class Settings {
return mPreferredActivities.get(userId);
}
- CrossProfileIntentResolver getCrossProfileIntentResolvers(int userId) {
+ @Nullable
+ CrossProfileIntentResolver getCrossProfileIntentResolver(int userId) {
return mCrossProfileIntentResolvers.get(userId);
}
diff --git a/services/core/java/com/android/server/pm/TEST_MAPPING b/services/core/java/com/android/server/pm/TEST_MAPPING
index 7d48d0a6e266..e913829ea9e2 100644
--- a/services/core/java/com/android/server/pm/TEST_MAPPING
+++ b/services/core/java/com/android/server/pm/TEST_MAPPING
@@ -30,6 +30,14 @@
]
},
{
+ "name": "FrameworksMockingServicesTests",
+ "options": [
+ {
+ "include-filter": "com.android.server.pm."
+ }
+ ]
+ },
+ {
"name": "CtsContentTestCases",
"options": [
{
diff --git a/services/core/java/com/android/server/pm/UserManagerService.java b/services/core/java/com/android/server/pm/UserManagerService.java
index cc814bcc7760..62ac57062ac6 100644
--- a/services/core/java/com/android/server/pm/UserManagerService.java
+++ b/services/core/java/com/android/server/pm/UserManagerService.java
@@ -2918,16 +2918,16 @@ public class UserManagerService extends IUserManager.Stub {
serializer.attribute(null, ATTR_ICON_PATH, userInfo.iconPath);
}
if (userInfo.partial) {
- serializer.attribute(null, ATTR_PARTIAL, "true");
+ serializer.attributeBoolean(null, ATTR_PARTIAL, true);
}
if (userInfo.preCreated) {
- serializer.attribute(null, ATTR_PRE_CREATED, "true");
+ serializer.attributeBoolean(null, ATTR_PRE_CREATED, true);
}
if (userInfo.convertedFromPreCreated) {
- serializer.attribute(null, ATTR_CONVERTED_FROM_PRE_CREATED, "true");
+ serializer.attributeBoolean(null, ATTR_CONVERTED_FROM_PRE_CREATED, true);
}
if (userInfo.guestToRemove) {
- serializer.attribute(null, ATTR_GUEST_TO_REMOVE, "true");
+ serializer.attributeBoolean(null, ATTR_GUEST_TO_REMOVE, true);
}
if (userInfo.profileGroupId != UserInfo.NO_PROFILE_GROUP_ID) {
serializer.attributeInt(null, ATTR_PROFILE_GROUP_ID, userInfo.profileGroupId);
@@ -3121,22 +3121,10 @@ public class UserManagerService extends IUserManager.Stub {
profileBadge = parser.getAttributeInt(null, ATTR_PROFILE_BADGE, 0);
restrictedProfileParentId = parser.getAttributeInt(null,
ATTR_RESTRICTED_PROFILE_PARENT_ID, UserInfo.NO_PROFILE_GROUP_ID);
- String valueString = parser.getAttributeValue(null, ATTR_PARTIAL);
- if ("true".equals(valueString)) {
- partial = true;
- }
- valueString = parser.getAttributeValue(null, ATTR_PRE_CREATED);
- if ("true".equals(valueString)) {
- preCreated = true;
- }
- valueString = parser.getAttributeValue(null, ATTR_CONVERTED_FROM_PRE_CREATED);
- if ("true".equals(valueString)) {
- converted = true;
- }
- valueString = parser.getAttributeValue(null, ATTR_GUEST_TO_REMOVE);
- if ("true".equals(valueString)) {
- guestToRemove = true;
- }
+ partial = parser.getAttributeBoolean(null, ATTR_PARTIAL, false);
+ preCreated = parser.getAttributeBoolean(null, ATTR_PRE_CREATED, false);
+ converted = parser.getAttributeBoolean(null, ATTR_CONVERTED_FROM_PRE_CREATED, false);
+ guestToRemove = parser.getAttributeBoolean(null, ATTR_GUEST_TO_REMOVE, false);
seedAccountName = parser.getAttributeValue(null, ATTR_SEED_ACCOUNT_NAME);
seedAccountType = parser.getAttributeValue(null, ATTR_SEED_ACCOUNT_TYPE);
@@ -4257,10 +4245,9 @@ public class UserManagerService extends IUserManager.Stub {
if (type == XmlPullParser.START_TAG && parser.getName().equals(TAG_ENTRY)) {
String key = parser.getAttributeValue(null, ATTR_KEY);
String valType = parser.getAttributeValue(null, ATTR_VALUE_TYPE);
- String multiple = parser.getAttributeValue(null, ATTR_MULTIPLE);
- if (multiple != null) {
+ int count = parser.getAttributeInt(null, ATTR_MULTIPLE, -1);
+ if (count != -1) {
values.clear();
- int count = Integer.parseInt(multiple);
while (count > 0 && (type = parser.next()) != XmlPullParser.END_DOCUMENT) {
if (type == XmlPullParser.START_TAG
&& parser.getName().equals(TAG_VALUE)) {
diff --git a/services/core/java/com/android/server/pm/UserRestrictionsUtils.java b/services/core/java/com/android/server/pm/UserRestrictionsUtils.java
index 0ac3030ba5dc..51dff4063850 100644
--- a/services/core/java/com/android/server/pm/UserRestrictionsUtils.java
+++ b/services/core/java/com/android/server/pm/UserRestrictionsUtils.java
@@ -344,7 +344,7 @@ public class UserRestrictionsUtils {
}
if (USER_RESTRICTIONS.contains(key)) {
if (restrictions.getBoolean(key)) {
- serializer.attribute(null, key, "true");
+ serializer.attributeBoolean(null, key, true);
}
continue;
}
@@ -360,9 +360,9 @@ public class UserRestrictionsUtils {
public static void readRestrictions(TypedXmlPullParser parser, Bundle restrictions) {
restrictions.clear();
for (String key : USER_RESTRICTIONS) {
- final String value = parser.getAttributeValue(null, key);
- if (value != null) {
- restrictions.putBoolean(key, Boolean.parseBoolean(value));
+ final boolean value = parser.getAttributeBoolean(null, key, false);
+ if (value) {
+ restrictions.putBoolean(key, true);
}
}
}
diff --git a/services/core/java/com/android/server/pm/permission/LegacyPermission.java b/services/core/java/com/android/server/pm/permission/LegacyPermission.java
index 6a4eb63c8d7e..ca3a2e2e2da7 100644
--- a/services/core/java/com/android/server/pm/permission/LegacyPermission.java
+++ b/services/core/java/com/android/server/pm/permission/LegacyPermission.java
@@ -167,16 +167,12 @@ public final class LegacyPermission {
private static int readInt(@NonNull TypedXmlPullParser parser, @Nullable String namespace,
@NonNull String name, int defaultValue) {
- final String value = parser.getAttributeValue(namespace, name);
- if (value == null) {
- return defaultValue;
- }
try {
- return Integer.parseInt(value);
- } catch (NumberFormatException e) {
+ return parser.getAttributeInt(namespace, name);
+ } catch (Exception ignored) {
PackageManagerService.reportSettingsProblem(Log.WARN,
"Error in package manager settings: attribute " + name
- + " has bad integer value " + value + " at "
+ + " has bad integer value at "
+ parser.getPositionDescription());
return defaultValue;
}
diff --git a/services/core/java/com/android/server/pm/permission/PermissionManagerService.java b/services/core/java/com/android/server/pm/permission/PermissionManagerService.java
index 48e18f1b8b38..7ed887d9680a 100644
--- a/services/core/java/com/android/server/pm/permission/PermissionManagerService.java
+++ b/services/core/java/com/android/server/pm/permission/PermissionManagerService.java
@@ -114,7 +114,6 @@ import android.permission.IPermissionManager;
import android.permission.PermissionControllerManager;
import android.permission.PermissionManager;
import android.permission.PermissionManagerInternal;
-import android.permission.PermissionManagerInternal.CheckPermissionDelegate;
import android.permission.PermissionManagerInternal.OnRuntimePermissionStateChangedListener;
import android.text.TextUtils;
import android.util.ArrayMap;
@@ -138,6 +137,7 @@ import com.android.internal.util.CollectionUtils;
import com.android.internal.util.DumpUtils;
import com.android.internal.util.IntPair;
import com.android.internal.util.Preconditions;
+import com.android.internal.util.function.TriFunction;
import com.android.internal.util.function.pooled.PooledLambda;
import com.android.server.FgThread;
import com.android.server.LocalServices;
@@ -151,9 +151,6 @@ import com.android.server.pm.UserManagerInternal;
import com.android.server.pm.UserManagerService;
import com.android.server.pm.parsing.PackageInfoUtils;
import com.android.server.pm.parsing.pkg.AndroidPackage;
-import com.android.server.pm.permission.PermissionManagerServiceInternal.DefaultBrowserProvider;
-import com.android.server.pm.permission.PermissionManagerServiceInternal.DefaultDialerProvider;
-import com.android.server.pm.permission.PermissionManagerServiceInternal.DefaultHomeProvider;
import com.android.server.policy.PermissionPolicyInternal;
import com.android.server.policy.SoftRestrictedPermissionPolicy;
@@ -176,7 +173,7 @@ import java.util.concurrent.CompletableFuture;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.TimeoutException;
-import java.util.function.Consumer;
+import java.util.function.BiFunction;
/**
* Manages all permissions and handles permissions related tasks.
@@ -304,15 +301,6 @@ public class PermissionManagerService extends IPermissionManager.Stub {
@NonNull
private final OnPermissionChangeListeners mOnPermissionChangeListeners;
- @GuardedBy("mLock")
- private DefaultBrowserProvider mDefaultBrowserProvider;
-
- @GuardedBy("mLock")
- private DefaultDialerProvider mDefaultDialerProvider;
-
- @GuardedBy("mLock")
- private DefaultHomeProvider mDefaultHomeProvider;
-
// TODO: Take a look at the methods defined in the callback.
// The callback was initially created to support the split between permission
// manager and the package manager. However, it's started to be used for other
@@ -2018,60 +2006,6 @@ public class PermissionManagerService extends IPermissionManager.Stub {
}
@Override
- public String getDefaultBrowser(int userId) {
- final int callingUid = Binder.getCallingUid();
- if (UserHandle.getUserId(callingUid) != userId) {
- mContext.enforceCallingOrSelfPermission(
- android.Manifest.permission.INTERACT_ACROSS_USERS_FULL, null);
- }
- if (mPackageManagerInt.getInstantAppPackageName(callingUid) != null) {
- return null;
- }
- DefaultBrowserProvider provider;
- synchronized (mLock) {
- provider = mDefaultBrowserProvider;
- }
- return provider != null ? provider.getDefaultBrowser(userId) : null;
- }
-
- @Override
- public boolean setDefaultBrowser(String packageName, int userId) {
- mContext.enforceCallingOrSelfPermission(
- android.Manifest.permission.SET_PREFERRED_APPLICATIONS, null);
- if (UserHandle.getCallingUserId() != userId) {
- mContext.enforceCallingOrSelfPermission(
- android.Manifest.permission.INTERACT_ACROSS_USERS_FULL, null);
- }
- return setDefaultBrowserInternal(packageName, false, true, userId);
- }
-
- private boolean setDefaultBrowserInternal(String packageName, boolean async,
- boolean doGrant, int userId) {
- if (userId == UserHandle.USER_ALL) {
- return false;
- }
- DefaultBrowserProvider provider;
- synchronized (mLock) {
- provider = mDefaultBrowserProvider;
- }
- if (provider == null) {
- return false;
- }
- if (async) {
- provider.setDefaultBrowserAsync(packageName, userId);
- } else {
- if (!provider.setDefaultBrowser(packageName, userId)) {
- return false;
- }
- }
- if (doGrant && packageName != null) {
- mDefaultPermissionGrantPolicy.grantDefaultPermissionsToDefaultBrowser(packageName,
- userId);
- }
- return true;
- }
-
- @Override
public void grantDefaultPermissionsToEnabledCarrierApps(String[] packageNames, int userId) {
final int callingUid = Binder.getCallingUid();
PackageManagerServiceUtils
@@ -2360,6 +2294,32 @@ public class PermissionManagerService extends IPermissionManager.Stub {
}
}
+ private void startShellPermissionIdentityDelegationInternal(int uid,
+ @NonNull String packageName, @Nullable List<String> permissionNames) {
+ synchronized (mLock) {
+ final CheckPermissionDelegate oldDelegate = mCheckPermissionDelegate;
+ if (oldDelegate != null && oldDelegate.getDelegatedUid() != uid) {
+ throw new SecurityException(
+ "Shell can delegate permissions only to one UID at a time");
+ }
+ final ShellDelegate delegate = new ShellDelegate(uid, packageName, permissionNames);
+ setCheckPermissionDelegateLocked(delegate);
+ }
+ }
+
+ private void stopShellPermissionIdentityDelegationInternal() {
+ synchronized (mLock) {
+ setCheckPermissionDelegateLocked(null);
+ }
+ }
+
+ private void setCheckPermissionDelegateLocked(@Nullable CheckPermissionDelegate delegate) {
+ if (delegate != null || mCheckPermissionDelegate != null) {
+ PackageManager.invalidatePackageInfoCache();
+ }
+ mCheckPermissionDelegate = delegate;
+ }
+
/**
* If the app is updated, and has scoped storage permissions, then it is possible that the
* app updated in an attempt to get unscoped storage. If so, revoke all storage permissions.
@@ -5233,62 +5193,15 @@ public class PermissionManagerService extends IPermissionManager.Stub {
}
@Override
- public CheckPermissionDelegate getCheckPermissionDelegate() {
- synchronized (mLock) {
- return mCheckPermissionDelegate;
- }
- }
-
- @Override
- public void setCheckPermissionDelegate(CheckPermissionDelegate delegate) {
- synchronized (mLock) {
- if (delegate != null || mCheckPermissionDelegate != null) {
- PackageManager.invalidatePackageInfoCache();
- }
- mCheckPermissionDelegate = delegate;
- }
- }
-
- @Override
- public void setDefaultBrowserProvider(@NonNull DefaultBrowserProvider provider) {
- synchronized (mLock) {
- mDefaultBrowserProvider = provider;
- }
- }
-
- @Override
- public void setDefaultBrowser(String packageName, boolean async, boolean doGrant,
- int userId) {
- setDefaultBrowserInternal(packageName, async, doGrant, userId);
- }
-
- @Override
- public void setDefaultDialerProvider(@NonNull DefaultDialerProvider provider) {
- synchronized (mLock) {
- mDefaultDialerProvider = provider;
- }
- }
-
- @Override
- public void setDefaultHomeProvider(@NonNull DefaultHomeProvider provider) {
- synchronized (mLock) {
- mDefaultHomeProvider = provider;
- }
+ public void startShellPermissionIdentityDelegation(int uid, @NonNull String packageName,
+ @Nullable List<String> permissionNames) {
+ Objects.requireNonNull(packageName, "packageName");
+ startShellPermissionIdentityDelegationInternal(uid, packageName, permissionNames);
}
@Override
- public void setDefaultHome(String packageName, int userId, Consumer<Boolean> callback) {
- if (userId == UserHandle.USER_ALL) {
- return;
- }
- DefaultHomeProvider provider;
- synchronized (mLock) {
- provider = mDefaultHomeProvider;
- }
- if (provider == null) {
- return;
- }
- provider.setDefaultHomeAsync(packageName, userId, callback);
+ public void stopShellPermissionIdentityDelegation() {
+ stopShellPermissionIdentityDelegationInternal();
}
@Override
@@ -5332,30 +5245,10 @@ public class PermissionManagerService extends IPermissionManager.Stub {
}
@Override
- public String getDefaultBrowser(int userId) {
- DefaultBrowserProvider provider;
- synchronized (mLock) {
- provider = mDefaultBrowserProvider;
- }
- return provider != null ? provider.getDefaultBrowser(userId) : null;
- }
-
- @Override
- public String getDefaultDialer(int userId) {
- DefaultDialerProvider provider;
- synchronized (mLock) {
- provider = mDefaultDialerProvider;
- }
- return provider != null ? provider.getDefaultDialer(userId) : null;
- }
-
- @Override
- public String getDefaultHome(int userId) {
- DefaultHomeProvider provider;
- synchronized (mLock) {
- provider = mDefaultHomeProvider;
- }
- return provider != null ? provider.getDefaultHome(userId) : null;
+ public void grantDefaultPermissionsToDefaultBrowser(@NonNull String packageName,
+ @UserIdInt int userId) {
+ mDefaultPermissionGrantPolicy.grantDefaultPermissionsToDefaultBrowser(packageName,
+ userId);
}
@Override
@@ -5545,6 +5438,102 @@ public class PermissionManagerService extends IPermissionManager.Stub {
}
/**
+ * Interface to intercept permission checks and optionally pass through to the original
+ * implementation.
+ */
+ private interface CheckPermissionDelegate {
+ /**
+ * Get the UID whose permission checks is being delegated.
+ *
+ * @return the UID
+ */
+ int getDelegatedUid();
+
+ /**
+ * Check whether the given package has been granted the specified permission.
+ *
+ * @param permissionName the name of the permission to be checked
+ * @param packageName the name of the package to be checked
+ * @param userId the user ID
+ * @param superImpl the original implementation that can be delegated to
+ * @return {@link android.content.pm.PackageManager.PERMISSION_GRANTED} if the package has
+ * the permission, or {@link android.content.pm.PackageManager.PERMISSION_DENITED} otherwise
+ *
+ * @see android.content.pm.PackageManager#checkPermission(String, String)
+ */
+ int checkPermission(@NonNull String permissionName, @NonNull String packageName,
+ @UserIdInt int userId,
+ @NonNull TriFunction<String, String, Integer, Integer> superImpl);
+
+ /**
+ * Check whether the given UID has been granted the specified permission.
+ *
+ * @param permissionName the name of the permission to be checked
+ * @param uid the UID to be checked
+ * @param superImpl the original implementation that can be delegated to
+ * @return {@link android.content.pm.PackageManager.PERMISSION_GRANTED} if the package has
+ * the permission, or {@link android.content.pm.PackageManager.PERMISSION_DENITED} otherwise
+ */
+ int checkUidPermission(@NonNull String permissionName, int uid,
+ BiFunction<String, Integer, Integer> superImpl);
+ }
+
+ private class ShellDelegate implements CheckPermissionDelegate {
+ private final int mDelegatedUid;
+ @NonNull
+ private final String mDelegatedPackageName;
+ @Nullable
+ private final List<String> mDelegatedPermissionNames;
+
+ public ShellDelegate(int delegatedUid, @NonNull String delegatedPackageName,
+ @Nullable List<String> delegatedPermissionNames) {
+ mDelegatedUid = delegatedUid;
+ mDelegatedPackageName = delegatedPackageName;
+ mDelegatedPermissionNames = delegatedPermissionNames;
+ }
+
+ @Override
+ public int getDelegatedUid() {
+ return mDelegatedUid;
+ }
+
+ @Override
+ public int checkPermission(@NonNull String permissionName, @NonNull String packageName,
+ int userId, @NonNull TriFunction<String, String, Integer, Integer> superImpl) {
+ if (mDelegatedPackageName.equals(packageName)
+ && isDelegatedPermission(permissionName)) {
+ final long identity = Binder.clearCallingIdentity();
+ try {
+ return superImpl.apply(permissionName, "com.android.shell", userId);
+ } finally {
+ Binder.restoreCallingIdentity(identity);
+ }
+ }
+ return superImpl.apply(permissionName, packageName, userId);
+ }
+
+ @Override
+ public int checkUidPermission(@NonNull String permissionName, int uid,
+ @NonNull BiFunction<String, Integer, Integer> superImpl) {
+ if (uid == mDelegatedUid && isDelegatedPermission(permissionName)) {
+ final long identity = Binder.clearCallingIdentity();
+ try {
+ return superImpl.apply(permissionName, Process.SHELL_UID);
+ } finally {
+ Binder.restoreCallingIdentity(identity);
+ }
+ }
+ return superImpl.apply(permissionName, uid);
+ }
+
+ private boolean isDelegatedPermission(@NonNull String permissionName) {
+ // null permissions means all permissions are targeted
+ return mDelegatedPermissionNames == null
+ || mDelegatedPermissionNames.contains(permissionName);
+ }
+ }
+
+ /**
* Allows injection of services and method responses to facilitate testing.
*
* <p>Test classes can create a mock of this class and pass it to the PermissionManagerService
diff --git a/services/core/java/com/android/server/pm/permission/PermissionManagerServiceInternal.java b/services/core/java/com/android/server/pm/permission/PermissionManagerServiceInternal.java
index f924651f1051..e006fa784cce 100644
--- a/services/core/java/com/android/server/pm/permission/PermissionManagerServiceInternal.java
+++ b/services/core/java/com/android/server/pm/permission/PermissionManagerServiceInternal.java
@@ -30,7 +30,6 @@ import java.util.Collections;
import java.util.List;
import java.util.Objects;
import java.util.Set;
-import java.util.function.Consumer;
/**
* Internal interfaces services.
@@ -66,82 +65,6 @@ public abstract class PermissionManagerServiceInternal extends PermissionManager
String[] getPackages(String authority, int userId);
}
- /**
- * Provider for default browser
- */
- public interface DefaultBrowserProvider {
-
- /**
- * Get the package name of the default browser.
- *
- * @param userId the user id
- *
- * @return the package name of the default browser, or {@code null} if none
- */
- @Nullable
- String getDefaultBrowser(@UserIdInt int userId);
-
- /**
- * Set the package name of the default browser.
- *
- * @param packageName package name of the default browser, or {@code null} to remove
- * @param userId the user id
- *
- * @return whether the default browser was successfully set.
- */
- boolean setDefaultBrowser(@Nullable String packageName, @UserIdInt int userId);
-
- /**
- * Set the package name of the default browser asynchronously.
- *
- * @param packageName package name of the default browser, or {@code null} to remove
- * @param userId the user id
- */
- void setDefaultBrowserAsync(@Nullable String packageName, @UserIdInt int userId);
- }
-
- /**
- * Provider for default dialer
- */
- public interface DefaultDialerProvider {
-
- /**
- * Get the package name of the default dialer.
- *
- * @param userId the user id
- *
- * @return the package name of the default dialer, or {@code null} if none
- */
- @Nullable
- String getDefaultDialer(@UserIdInt int userId);
- }
-
- /**
- * Provider for default home
- */
- public interface DefaultHomeProvider {
-
- /**
- * Get the package name of the default home.
- *
- * @param userId the user id
- *
- * @return the package name of the default home, or {@code null} if none
- */
- @Nullable
- String getDefaultHome(@UserIdInt int userId);
-
- /**
- * Set the package name of the default home.
- *
- * @param packageName package name of the default home, or {@code null} to remove
- * @param userId the user id
- * @param callback the callback made after the default home as been updated
- */
- void setDefaultHomeAsync(@Nullable String packageName, @UserIdInt int userId,
- @NonNull Consumer<Boolean> callback);
- }
-
public abstract void systemReady();
/**
@@ -257,18 +180,24 @@ public abstract class PermissionManagerServiceInternal extends PermissionManager
@PermissionInfo.ProtectionFlags int protectionFlags);
/**
- * Returns the delegate used to influence permission checking.
+ * Start delegate the permission identity of the shell UID to the given UID.
*
- * @return The delegate instance.
+ * @param uid the UID to delegate shell permission identity to
+ * @param packageName the name of the package to delegate shell permission identity to
+ * @param permissionNames the names of the permissions to delegate shell permission identity
+ * for, or {@code null} for all permissions
*/
- public abstract @Nullable CheckPermissionDelegate getCheckPermissionDelegate();
+ //@SystemApi(client = SystemApi.Client.SYSTEM_SERVER)
+ public abstract void startShellPermissionIdentityDelegation(int uid,
+ @NonNull String packageName, @Nullable List<String> permissionNames);
/**
- * Sets the delegate used to influence permission checking.
+ * Stop delegating the permission identity of the shell UID.
*
- * @param delegate A delegate instance or {@code null} to clear.
+ * @see #startShellPermissionIdentityDelegation(int, String, List)
*/
- public abstract void setCheckPermissionDelegate(@Nullable CheckPermissionDelegate delegate);
+ //@SystemApi(client = SystemApi.Client.SYSTEM_SERVER)
+ public abstract void stopShellPermissionIdentityDelegation();
/**
* Sets the dialer application packages provider.
@@ -319,69 +248,12 @@ public abstract class PermissionManagerServiceInternal extends PermissionManager
public abstract void setVoiceInteractionPackagesProvider(PackagesProvider provider);
/**
- * Sets the default browser provider.
- *
- * @param provider the provider
- */
- public abstract void setDefaultBrowserProvider(@NonNull DefaultBrowserProvider provider);
-
- /**
- * Sets the package name of the default browser provider for the given user.
- *
- * @param packageName The package name of the default browser or {@code null}
- * to clear the default browser
- * @param async If {@code true}, set the default browser asynchronously,
- * otherwise set it synchronously
- * @param doGrant If {@code true} and if {@code packageName} is not {@code null},
- * perform default permission grants on the browser, otherwise skip the
- * default permission grants.
- * @param userId The user to set the default browser for.
- */
- public abstract void setDefaultBrowser(@Nullable String packageName, boolean async,
- boolean doGrant, @UserIdInt int userId);
-
- /**
- * Sets the default dialer provider.
- *
- * @param provider the provider
- */
- public abstract void setDefaultDialerProvider(@NonNull DefaultDialerProvider provider);
-
- /**
- * Sets the default home provider.
- *
- * @param provider the provider
- */
- public abstract void setDefaultHomeProvider(@NonNull DefaultHomeProvider provider);
-
- /**
- * Asynchronously sets the package name of the default home provider for the given user.
- *
- * @param packageName The package name of the default home or {@code null}
- * to clear the default browser
- * @param userId The user to set the default browser for
- * @param callback Invoked after the default home has been set
- */
- public abstract void setDefaultHome(@Nullable String packageName, @UserIdInt int userId,
- @NonNull Consumer<Boolean> callback);
-
- /**
- * Returns the default browser package name for the given user.
- */
- @Nullable
- public abstract String getDefaultBrowser(@UserIdInt int userId);
-
- /**
- * Returns the default dialer package name for the given user.
- */
- @Nullable
- public abstract String getDefaultDialer(@UserIdInt int userId);
-
- /**
- * Returns the default home package name for the given user.
+ * Requests granting of the default permissions to the current default browser.
+ * @param packageName The default browser package name.
+ * @param userId The user for which to grant the permissions.
*/
- @Nullable
- public abstract String getDefaultHome(@UserIdInt int userId);
+ public abstract void grantDefaultPermissionsToDefaultBrowser(
+ @NonNull String packageName, @UserIdInt int userId);
/**
* Requests granting of the default permissions to the current default Use Open Wifi app.
diff --git a/services/core/java/com/android/server/policy/DeviceStateProviderImpl.java b/services/core/java/com/android/server/policy/DeviceStateProviderImpl.java
index 321bb8c0251d..cc1f8d620d1f 100644
--- a/services/core/java/com/android/server/policy/DeviceStateProviderImpl.java
+++ b/services/core/java/com/android/server/policy/DeviceStateProviderImpl.java
@@ -158,7 +158,6 @@ public final class DeviceStateProviderImpl implements DeviceStateProvider,
// switch there is no need to register for a callback.
boolean shouldListenToLidSwitch = false;
- final SensorManager sensorManager = mContext.getSystemService(SensorManager.class);
// The set of Sensor(s) that this instance should register to receive SensorEvent(s) from.
final ArraySet<Sensor> sensorsToListenTo = new ArraySet<>();
@@ -182,19 +181,10 @@ public final class DeviceStateProviderImpl implements DeviceStateProvider,
List<SensorCondition> sensorConditions = conditions.getSensor();
for (int j = 0; j < sensorConditions.size(); j++) {
SensorCondition sensorCondition = sensorConditions.get(j);
- final int expectedSensorType = sensorCondition.getType().intValue();
+ final String expectedSensorType = sensorCondition.getType();
final String expectedSensorName = sensorCondition.getName();
- List<Sensor> sensors = sensorManager.getSensorList(expectedSensorType);
- Sensor foundSensor = null;
- for (int sensorIndex = 0; sensorIndex < sensors.size(); sensorIndex++) {
- Sensor sensor = sensors.get(sensorIndex);
- if (sensor.getName().equals(expectedSensorName)) {
- foundSensor = sensor;
- break;
- }
- }
-
+ final Sensor foundSensor = findSensor(expectedSensorType, expectedSensorName);
if (foundSensor == null) {
throw new IllegalStateException("Failed to find Sensor with type: "
+ expectedSensorType + " and name: " + expectedSensorName);
@@ -221,12 +211,33 @@ public final class DeviceStateProviderImpl implements DeviceStateProvider,
inputManager.registerLidSwitchCallback(this);
}
+ final SensorManager sensorManager = mContext.getSystemService(SensorManager.class);
for (int i = 0; i < sensorsToListenTo.size(); i++) {
Sensor sensor = sensorsToListenTo.valueAt(i);
sensorManager.registerListener(this, sensor, SensorManager.SENSOR_DELAY_FASTEST);
}
}
+ @Nullable
+ private Sensor findSensor(String type, String name) {
+ final SensorManager sensorManager = mContext.getSystemService(SensorManager.class);
+ final List<Sensor> sensors = sensorManager.getSensorList(Sensor.TYPE_ALL);
+ for (int sensorIndex = 0; sensorIndex < sensors.size(); sensorIndex++) {
+ final Sensor sensor = sensors.get(sensorIndex);
+ final String sensorType = sensor.getStringType();
+ final String sensorName = sensor.getName();
+
+ if (sensorType == null || sensorName == null) {
+ continue;
+ }
+
+ if (sensorType.equals(type) && sensorName.equals(name)) {
+ return sensor;
+ }
+ }
+ return null;
+ }
+
@Override
public void setListener(Listener listener) {
synchronized (mLock) {
diff --git a/services/core/java/com/android/server/role/RoleManagerService.java b/services/core/java/com/android/server/role/RoleManagerService.java
index ab6ada2f85f7..3d91a8502097 100644
--- a/services/core/java/com/android/server/role/RoleManagerService.java
+++ b/services/core/java/com/android/server/role/RoleManagerService.java
@@ -83,7 +83,6 @@ import java.util.Objects;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.TimeoutException;
-import java.util.function.Consumer;
/**
* Service for role management.
@@ -162,12 +161,6 @@ public class RoleManagerService extends SystemService implements RoleUserState.C
LocalServices.addService(RoleManagerInternal.class, new Internal());
- PermissionManagerServiceInternal permissionManagerInternal =
- LocalServices.getService(PermissionManagerServiceInternal.class);
- permissionManagerInternal.setDefaultBrowserProvider(new DefaultBrowserProvider());
- permissionManagerInternal.setDefaultDialerProvider(new DefaultDialerProvider());
- permissionManagerInternal.setDefaultHomeProvider(new DefaultHomeProvider());
-
registerUserRemovedReceiver();
}
@@ -657,12 +650,84 @@ public class RoleManagerService extends SystemService implements RoleUserState.C
resultReceiver);
}
+ @Nullable
@Override
- public String getDefaultSmsPackage(int userId) {
+ public String getBrowserRoleHolder(@UserIdInt int userId) {
+ final int callingUid = Binder.getCallingUid();
+ if (UserHandle.getUserId(callingUid) != userId) {
+ getContext().enforceCallingOrSelfPermission(
+ android.Manifest.permission.INTERACT_ACROSS_USERS_FULL, null);
+ }
+ final PackageManagerInternal packageManager = LocalServices.getService(
+ PackageManagerInternal.class);
+ if (packageManager.getInstantAppPackageName(callingUid) != null) {
+ return null;
+ }
+
final long identity = Binder.clearCallingIdentity();
try {
- return CollectionUtils.firstOrNull(
- getRoleHoldersAsUser(RoleManager.ROLE_SMS, userId));
+ return CollectionUtils.firstOrNull(getRoleHoldersAsUser(RoleManager.ROLE_BROWSER,
+ userId));
+ } finally {
+ Binder.restoreCallingIdentity(identity);
+ }
+ }
+
+ @Override
+ public boolean setBrowserRoleHolder(@Nullable String packageName, @UserIdInt int userId) {
+ final Context context = getContext();
+ context.enforceCallingOrSelfPermission(
+ android.Manifest.permission.SET_PREFERRED_APPLICATIONS, null);
+ if (UserHandle.getCallingUserId() != userId) {
+ context.enforceCallingOrSelfPermission(
+ android.Manifest.permission.INTERACT_ACROSS_USERS_FULL, null);
+ }
+
+ if (!mUserManagerInternal.exists(userId)) {
+ return false;
+ }
+
+ final AndroidFuture<Void> future = new AndroidFuture<>();
+ final RemoteCallback callback = new RemoteCallback(result -> {
+ boolean successful = result != null;
+ if (successful) {
+ future.complete(null);
+ } else {
+ future.completeExceptionally(new RuntimeException());
+ }
+ });
+ final long identity = Binder.clearCallingIdentity();
+ try {
+ if (packageName != null) {
+ addRoleHolderAsUser(RoleManager.ROLE_BROWSER, packageName, 0, userId, callback);
+ } else {
+ clearRoleHoldersAsUser(RoleManager.ROLE_BROWSER, 0, userId, callback);
+ }
+ try {
+ future.get(5, TimeUnit.SECONDS);
+ } catch (InterruptedException | ExecutionException | TimeoutException e) {
+ Slog.e(LOG_TAG, "Exception while setting default browser: " + packageName, e);
+ return false;
+ }
+
+ if (packageName != null) {
+ final PermissionManagerServiceInternal permissionManager =
+ LocalServices.getService(PermissionManagerServiceInternal.class);
+ permissionManager.grantDefaultPermissionsToDefaultBrowser(packageName, userId);
+ }
+ } finally {
+ Binder.restoreCallingIdentity(identity);
+ }
+
+ return true;
+ }
+
+ @Override
+ public String getSmsRoleHolder(int userId) {
+ final long identity = Binder.clearCallingIdentity();
+ try {
+ return CollectionUtils.firstOrNull(getRoleHoldersAsUser(RoleManager.ROLE_SMS,
+ userId));
} finally {
Binder.restoreCallingIdentity(identity);
}
@@ -718,100 +783,4 @@ public class RoleManagerService extends SystemService implements RoleUserState.C
return getOrCreateUserState(userId).getRolesAndHolders();
}
}
-
- private class DefaultBrowserProvider implements
- PermissionManagerServiceInternal.DefaultBrowserProvider {
-
- @Nullable
- @Override
- public String getDefaultBrowser(@UserIdInt int userId) {
- return CollectionUtils.firstOrNull(getOrCreateUserState(userId).getRoleHolders(
- RoleManager.ROLE_BROWSER));
- }
-
- @Override
- public boolean setDefaultBrowser(@Nullable String packageName, @UserIdInt int userId) {
- AndroidFuture<Void> future = new AndroidFuture<>();
- RemoteCallback callback = new RemoteCallback(result -> {
- boolean successful = result != null;
- if (successful) {
- future.complete(null);
- } else {
- future.completeExceptionally(new RuntimeException());
- }
- });
- if (packageName != null) {
- getOrCreateController(userId).onAddRoleHolder(RoleManager.ROLE_BROWSER,
- packageName, 0, callback);
- } else {
- getOrCreateController(userId).onClearRoleHolders(RoleManager.ROLE_BROWSER, 0,
- callback);
- }
- try {
- future.get(5, TimeUnit.SECONDS);
- return true;
- } catch (InterruptedException | ExecutionException | TimeoutException e) {
- Slog.e(LOG_TAG, "Exception while setting default browser: " + packageName, e);
- return false;
- }
- }
-
- @Override
- public void setDefaultBrowserAsync(@Nullable String packageName, @UserIdInt int userId) {
- RemoteCallback callback = new RemoteCallback(result -> {
- boolean successful = result != null;
- if (!successful) {
- Slog.e(LOG_TAG, "Failed to set default browser: " + packageName);
- }
- });
- if (packageName != null) {
- getOrCreateController(userId).onAddRoleHolder(RoleManager.ROLE_BROWSER,
- packageName, 0, callback);
- } else {
- getOrCreateController(userId).onClearRoleHolders(RoleManager.ROLE_BROWSER, 0,
- callback);
- }
- }
- }
-
- private class DefaultDialerProvider implements
- PermissionManagerServiceInternal.DefaultDialerProvider {
-
- @Nullable
- @Override
- public String getDefaultDialer(@UserIdInt int userId) {
- return CollectionUtils.firstOrNull(getOrCreateUserState(userId).getRoleHolders(
- RoleManager.ROLE_DIALER));
- }
- }
-
- private class DefaultHomeProvider implements
- PermissionManagerServiceInternal.DefaultHomeProvider {
-
- @Nullable
- @Override
- public String getDefaultHome(@UserIdInt int userId) {
- return CollectionUtils.firstOrNull(getOrCreateUserState(userId).getRoleHolders(
- RoleManager.ROLE_HOME));
- }
-
- @Override
- public void setDefaultHomeAsync(@Nullable String packageName, @UserIdInt int userId,
- @NonNull Consumer<Boolean> callback) {
- RemoteCallback remoteCallback = new RemoteCallback(result -> {
- boolean successful = result != null;
- if (!successful) {
- Slog.e(LOG_TAG, "Failed to set default home: " + packageName);
- }
- callback.accept(successful);
- });
- if (packageName != null) {
- getOrCreateController(userId).onAddRoleHolder(RoleManager.ROLE_HOME,
- packageName, 0, remoteCallback);
- } else {
- getOrCreateController(userId).onClearRoleHolders(RoleManager.ROLE_HOME, 0,
- remoteCallback);
- }
- }
- }
}
diff --git a/services/core/java/com/android/server/rollback/Rollback.java b/services/core/java/com/android/server/rollback/Rollback.java
index 63ed416f2859..d9b67024018b 100644
--- a/services/core/java/com/android/server/rollback/Rollback.java
+++ b/services/core/java/com/android/server/rollback/Rollback.java
@@ -581,9 +581,18 @@ class Rollback {
ParcelFileDescriptor.MODE_READ_ONLY)) {
final long token = Binder.clearCallingIdentity();
try {
- session.write(packageCodePath.getName(), 0,
- packageCodePath.length(),
- fd);
+ boolean fallbackToCopy = false;
+ try {
+ // Populate apk/apex files using hard links to avoid copy
+ session.stageViaHardLink(packageCodePath.getAbsolutePath());
+ } catch (Exception ignore) {
+ fallbackToCopy = true;
+ }
+ if (fallbackToCopy) {
+ session.write(packageCodePath.getName(), 0,
+ packageCodePath.length(),
+ fd);
+ }
} finally {
Binder.restoreCallingIdentity(token);
}
diff --git a/services/core/java/com/android/server/stats/pull/StatsPullAtomService.java b/services/core/java/com/android/server/stats/pull/StatsPullAtomService.java
index d3b1ac6e6096..cf20cf4c0c9f 100644
--- a/services/core/java/com/android/server/stats/pull/StatsPullAtomService.java
+++ b/services/core/java/com/android/server/stats/pull/StatsPullAtomService.java
@@ -502,6 +502,8 @@ public class StatsPullAtomService extends SystemService {
synchronized (mProcessSystemIonHeapSizeLock) {
return pullProcessSystemIonHeapSizeLocked(atomTag, data);
}
+ case FrameworkStatsLog.SYSTEM_MEMORY:
+ return pullSystemMemory(atomTag, data);
case FrameworkStatsLog.TEMPERATURE:
synchronized (mTemperatureLock) {
return pullTemperatureLocked(atomTag, data);
@@ -796,6 +798,7 @@ public class StatsPullAtomService extends SystemService {
registerSystemIonHeapSize();
registerIonHeapSize();
registerProcessSystemIonHeapSize();
+ registerSystemMemory();
registerTemperature();
registerCoolingDevice();
registerBinderCallsStats();
@@ -1913,6 +1916,30 @@ public class StatsPullAtomService extends SystemService {
return StatsManager.PULL_SUCCESS;
}
+ private void registerSystemMemory() {
+ int tagId = FrameworkStatsLog.SYSTEM_MEMORY;
+ mStatsManager.setPullAtomCallback(
+ tagId,
+ null, // use default PullAtomMetadata values
+ DIRECT_EXECUTOR,
+ mStatsCallbackImpl
+ );
+ }
+
+ int pullSystemMemory(int atomTag, List<StatsEvent> pulledData) {
+ SystemMemoryUtil.Metrics metrics = SystemMemoryUtil.getMetrics();
+ pulledData.add(
+ FrameworkStatsLog.buildStatsEvent(
+ atomTag,
+ metrics.unreclaimableSlabKb,
+ metrics.vmallocUsedKb,
+ metrics.pageTablesKb,
+ metrics.kernelStackKb,
+ metrics.totalIonKb,
+ metrics.unaccountedKb));
+ return StatsManager.PULL_SUCCESS;
+ }
+
private void registerTemperature() {
int tagId = FrameworkStatsLog.TEMPERATURE;
mStatsManager.setPullAtomCallback(
diff --git a/services/core/java/com/android/server/stats/pull/SystemMemoryUtil.java b/services/core/java/com/android/server/stats/pull/SystemMemoryUtil.java
new file mode 100644
index 000000000000..99fc7c11c5b3
--- /dev/null
+++ b/services/core/java/com/android/server/stats/pull/SystemMemoryUtil.java
@@ -0,0 +1,77 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.server.stats.pull;
+
+import android.os.Debug;
+
+/**
+ * Snapshots system-wide memory stats and computes unaccounted memory.
+ * Thread-safe.
+ */
+final class SystemMemoryUtil {
+ private SystemMemoryUtil() {}
+
+ static Metrics getMetrics() {
+ int totalIonKb = (int) Debug.getIonHeapsSizeKb();
+
+ long[] mInfos = new long[Debug.MEMINFO_COUNT];
+ Debug.getMemInfo(mInfos);
+
+ long kReclaimableKb = mInfos[Debug.MEMINFO_KRECLAIMABLE];
+ // Note: MEMINFO_KRECLAIMABLE includes MEMINFO_SLAB_RECLAIMABLE and ION pools.
+ // Fall back to using MEMINFO_SLAB_RECLAIMABLE in case of older kernels that do
+ // not include KReclaimable meminfo field.
+ if (kReclaimableKb == 0) {
+ kReclaimableKb = mInfos[Debug.MEMINFO_SLAB_RECLAIMABLE];
+ }
+
+ long accountedKb = mInfos[Debug.MEMINFO_FREE]
+ + mInfos[Debug.MEMINFO_ZRAM_TOTAL]
+ + mInfos[Debug.MEMINFO_BUFFERS]
+ + mInfos[Debug.MEMINFO_ACTIVE]
+ + mInfos[Debug.MEMINFO_INACTIVE]
+ + mInfos[Debug.MEMINFO_UNEVICTABLE]
+ + mInfos[Debug.MEMINFO_SLAB_UNRECLAIMABLE]
+ + kReclaimableKb
+ + mInfos[Debug.MEMINFO_VM_ALLOC_USED]
+ + mInfos[Debug.MEMINFO_PAGE_TABLES]
+ + Math.max(totalIonKb, 0);
+
+ if (!Debug.isVmapStack()) {
+ // See b/146088882
+ accountedKb += mInfos[Debug.MEMINFO_KERNEL_STACK];
+ }
+
+ Metrics result = new Metrics();
+ result.unreclaimableSlabKb = (int) mInfos[Debug.MEMINFO_SLAB_UNRECLAIMABLE];
+ result.vmallocUsedKb = (int) mInfos[Debug.MEMINFO_VM_ALLOC_USED];
+ result.pageTablesKb = (int) mInfos[Debug.MEMINFO_PAGE_TABLES];
+ result.kernelStackKb = (int) mInfos[Debug.MEMINFO_KERNEL_STACK];
+ result.totalIonKb = totalIonKb;
+ result.unaccountedKb = (int) (mInfos[Debug.MEMINFO_TOTAL] - accountedKb);
+ return result;
+ }
+
+ static final class Metrics {
+ public int unreclaimableSlabKb;
+ public int vmallocUsedKb;
+ public int pageTablesKb;
+ public int kernelStackKb;
+ public int totalIonKb;
+ public int unaccountedKb;
+ }
+}
diff --git a/services/core/java/com/android/server/timezonedetector/GeolocationTimeZoneSuggestion.java b/services/core/java/com/android/server/timezonedetector/GeolocationTimeZoneSuggestion.java
index 118899add968..1867ee207958 100644
--- a/services/core/java/com/android/server/timezonedetector/GeolocationTimeZoneSuggestion.java
+++ b/services/core/java/com/android/server/timezonedetector/GeolocationTimeZoneSuggestion.java
@@ -61,7 +61,7 @@ import java.util.StringTokenizer;
*/
public final class GeolocationTimeZoneSuggestion {
- @NonNull private final List<String> mZoneIds;
+ @Nullable private final List<String> mZoneIds;
@Nullable private ArrayList<String> mDebugInfo;
public GeolocationTimeZoneSuggestion(@Nullable List<String> zoneIds) {
diff --git a/services/core/java/com/android/server/tv/PersistentDataStore.java b/services/core/java/com/android/server/tv/PersistentDataStore.java
index d3c9b3bbe7f5..72556a75a4b5 100644
--- a/services/core/java/com/android/server/tv/PersistentDataStore.java
+++ b/services/core/java/com/android/server/tv/PersistentDataStore.java
@@ -30,23 +30,17 @@ import android.util.TypedXmlPullParser;
import android.util.TypedXmlSerializer;
import android.util.Xml;
-import com.android.internal.util.FastXmlSerializer;
import com.android.internal.util.XmlUtils;
import libcore.io.IoUtils;
-import org.xmlpull.v1.XmlPullParser;
import org.xmlpull.v1.XmlPullParserException;
-import org.xmlpull.v1.XmlSerializer;
-import java.io.BufferedInputStream;
-import java.io.BufferedOutputStream;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
-import java.nio.charset.StandardCharsets;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
@@ -246,12 +240,7 @@ final class PersistentDataStore {
if (parser.getName().equals(TAG_BLOCKED_RATINGS)) {
loadBlockedRatingsFromXml(parser);
} else if (parser.getName().equals(TAG_PARENTAL_CONTROLS)) {
- String enabled = parser.getAttributeValue(null, ATTR_ENABLED);
- if (TextUtils.isEmpty(enabled)) {
- throw new XmlPullParserException(
- "Missing " + ATTR_ENABLED + " attribute on " + TAG_PARENTAL_CONTROLS);
- }
- mParentalControlsEnabled = Boolean.parseBoolean(enabled);
+ mParentalControlsEnabled = parser.getAttributeBoolean(null, ATTR_ENABLED);
}
}
}
diff --git a/services/core/java/com/android/server/tv/tunerresourcemanager/UseCasePriorityHints.java b/services/core/java/com/android/server/tv/tunerresourcemanager/UseCasePriorityHints.java
index beb11ed4ea0c..7f49eead19fa 100644
--- a/services/core/java/com/android/server/tv/tunerresourcemanager/UseCasePriorityHints.java
+++ b/services/core/java/com/android/server/tv/tunerresourcemanager/UseCasePriorityHints.java
@@ -192,8 +192,9 @@ public class UseCasePriorityHints {
}
}
- private int readAttributeToInt(String attributeName, TypedXmlPullParser parser) {
- return Integer.valueOf(parser.getAttributeValue(null, attributeName));
+ private int readAttributeToInt(String attributeName, TypedXmlPullParser parser)
+ throws XmlPullParserException {
+ return parser.getAttributeInt(null, attributeName);
}
private void addNewUseCasePriority(int useCase, int fgPriority, int bgPriority) {
diff --git a/services/core/java/com/android/server/utils/quota/MultiRateLimiter.java b/services/core/java/com/android/server/utils/quota/MultiRateLimiter.java
new file mode 100644
index 000000000000..fdbe4b425d39
--- /dev/null
+++ b/services/core/java/com/android/server/utils/quota/MultiRateLimiter.java
@@ -0,0 +1,183 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.server.utils.quota;
+
+import android.annotation.NonNull;
+import android.annotation.Nullable;
+import android.content.Context;
+
+import com.android.internal.annotations.GuardedBy;
+import com.android.internal.annotations.VisibleForTesting;
+
+import java.time.Duration;
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * Can be used to rate limit events per app based on multiple rates at the same time. For example,
+ * it can limit an event to happen only:
+ *
+ * <li>5 times in 20 seconds</li>
+ * and
+ * <li>6 times in 40 seconds</li>
+ * and
+ * <li>10 times in 1 hour</li>
+ *
+ * <p><br>
+ * All listed rates apply at the same time, and the UPTC will be out of quota if it doesn't satisfy
+ * all the given rates. The underlying mechanism used is
+ * {@link com.android.server.utils.quota.CountQuotaTracker}, so all its conditions apply, as well
+ * as an additional constraint: all the user-package-tag combinations (UPTC) are considered to be in
+ * the same {@link com.android.server.utils.quota.Category}.
+ * </p>
+ *
+ * @hide
+ */
+public class MultiRateLimiter {
+
+ private static final CountQuotaTracker[] EMPTY_TRACKER_ARRAY = {};
+
+ private final Object mLock = new Object();
+ @GuardedBy("mLock")
+ private final CountQuotaTracker[] mQuotaTrackers;
+
+ private MultiRateLimiter(List<CountQuotaTracker> quotaTrackers) {
+ mQuotaTrackers = quotaTrackers.toArray(EMPTY_TRACKER_ARRAY);
+ }
+
+ /** Record that an event happened and count it towards the given quota. */
+ public void noteEvent(int userId, @NonNull String packageName, @Nullable String tag) {
+ synchronized (mLock) {
+ noteEventLocked(userId, packageName, tag);
+ }
+ }
+
+ /** Check whether the given UPTC is allowed to trigger an event. */
+ public boolean isWithinQuota(int userId, @NonNull String packageName, @Nullable String tag) {
+ synchronized (mLock) {
+ return isWithinQuotaLocked(userId, packageName, tag);
+ }
+ }
+
+ @GuardedBy("mLock")
+ private void noteEventLocked(int userId, @NonNull String packageName, @Nullable String tag) {
+ for (CountQuotaTracker quotaTracker : mQuotaTrackers) {
+ quotaTracker.noteEvent(userId, packageName, tag);
+ }
+ }
+
+ @GuardedBy("mLock")
+ private boolean isWithinQuotaLocked(int userId, @NonNull String packageName,
+ @Nullable String tag) {
+ for (CountQuotaTracker quotaTracker : mQuotaTrackers) {
+ if (!quotaTracker.isWithinQuota(userId, packageName, tag)) {
+ return false;
+ }
+ }
+ return true;
+ }
+
+ /** Can create a new {@link MultiRateLimiter}. */
+ public static class Builder {
+
+ private final List<CountQuotaTracker> mQuotaTrackers;
+ private final Context mContext;
+ private final Categorizer mCategorizer;
+ private final Category mCategory;
+ @Nullable private final QuotaTracker.Injector mInjector;
+
+ /**
+ * Creates a new builder and allows to inject an object that can be used
+ * to manipulate elapsed time in tests.
+ */
+ @VisibleForTesting
+ Builder(Context context, QuotaTracker.Injector injector) {
+ this.mQuotaTrackers = new ArrayList<>();
+ this.mContext = context;
+ this.mInjector = injector;
+ this.mCategorizer = Categorizer.SINGLE_CATEGORIZER;
+ this.mCategory = Category.SINGLE_CATEGORY;
+ }
+
+ /** Creates a new builder for {@link MultiRateLimiter}. */
+ public Builder(Context context) {
+ this(context, null);
+ }
+
+ /**
+ * Adds another rate limit to be used in {@link MultiRateLimiter}.
+ *
+ * @param limit The maximum event count an app can have in the rolling time window.
+ * @param windowSize The rolling time window to use when checking quota usage.
+ */
+ public Builder addRateLimit(int limit, Duration windowSize) {
+ CountQuotaTracker countQuotaTracker;
+ if (mInjector != null) {
+ countQuotaTracker = new CountQuotaTracker(mContext, mCategorizer, mInjector);
+ } else {
+ countQuotaTracker = new CountQuotaTracker(mContext, mCategorizer);
+ }
+ countQuotaTracker.setCountLimit(mCategory, limit, windowSize.toMillis());
+ mQuotaTrackers.add(countQuotaTracker);
+ return this;
+ }
+
+ /** Adds another rate limit to be used in {@link MultiRateLimiter}. */
+ public Builder addRateLimit(@NonNull RateLimit rateLimit) {
+ return addRateLimit(rateLimit.mLimit, rateLimit.mWindowSize);
+ }
+
+ /** Adds all given rate limits that will be used in {@link MultiRateLimiter}. */
+ public Builder addRateLimits(@NonNull RateLimit[] rateLimits) {
+ for (RateLimit rateLimit : rateLimits) {
+ addRateLimit(rateLimit);
+ }
+ return this;
+ }
+
+ /**
+ * Return a new {@link com.android.server.utils.quota.MultiRateLimiter} using set rate
+ * limit.
+ */
+ public MultiRateLimiter build() {
+ return new MultiRateLimiter(mQuotaTrackers);
+ }
+ }
+
+ /** Helper class that describes a rate limit. */
+ public static class RateLimit {
+ public final int mLimit;
+ public final Duration mWindowSize;
+
+ /**
+ * @param limit The maximum count of some occurrence in the rolling time window.
+ * @param windowSize The rolling time window to use when checking quota usage.
+ */
+ private RateLimit(int limit, Duration windowSize) {
+ this.mLimit = limit;
+ this.mWindowSize = windowSize;
+ }
+
+ /**
+ * @param limit The maximum count of some occurrence in the rolling time window.
+ * @param windowSize The rolling time window to use when checking quota usage.
+ */
+ public static RateLimit create(int limit, Duration windowSize) {
+ return new RateLimit(limit, windowSize);
+ }
+ }
+}
diff --git a/services/core/java/com/android/server/wallpaper/WallpaperManagerService.java b/services/core/java/com/android/server/wallpaper/WallpaperManagerService.java
index c3d5874de609..31984531d31f 100644
--- a/services/core/java/com/android/server/wallpaper/WallpaperManagerService.java
+++ b/services/core/java/com/android/server/wallpaper/WallpaperManagerService.java
@@ -2984,7 +2984,7 @@ public class WallpaperManagerService extends IWallpaperManager.Stub
}
if (wallpaper.allowBackup) {
- out.attribute(null, "backup", "true");
+ out.attributeBoolean(null, "backup", true);
}
out.endTag(null, tag);
@@ -3249,7 +3249,7 @@ public class WallpaperManagerService extends IWallpaperManager.Stub
wallpaper.primaryColors = new WallpaperColors(primary, secondary, tertiary, colorHints);
}
wallpaper.name = parser.getAttributeValue(null, "name");
- wallpaper.allowBackup = "true".equals(parser.getAttributeValue(null, "backup"));
+ wallpaper.allowBackup = parser.getAttributeBoolean(null, "backup", false);
}
// Called by SystemBackupAgent after files are restored to disk.
diff --git a/services/core/java/com/android/server/wm/AppWarnings.java b/services/core/java/com/android/server/wm/AppWarnings.java
index 55200b566979..994f07959f3b 100644
--- a/services/core/java/com/android/server/wm/AppWarnings.java
+++ b/services/core/java/com/android/server/wm/AppWarnings.java
@@ -31,16 +31,12 @@ import android.util.TypedXmlPullParser;
import android.util.TypedXmlSerializer;
import android.util.Xml;
-import com.android.internal.util.FastXmlSerializer;
-
import org.xmlpull.v1.XmlPullParser;
import org.xmlpull.v1.XmlPullParserException;
-import org.xmlpull.v1.XmlSerializer;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
-import java.nio.charset.StandardCharsets;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Map;
@@ -541,15 +537,7 @@ class AppWarnings {
if ("package".equals(tagName)) {
final String name = parser.getAttributeValue(null, "name");
if (name != null) {
- final String flags = parser.getAttributeValue(
- null, "flags");
- int flagsInt = 0;
- if (flags != null) {
- try {
- flagsInt = Integer.parseInt(flags);
- } catch (NumberFormatException e) {
- }
- }
+ int flagsInt = parser.getAttributeInt(null, "flags", 0);
mPackageFlags.put(name, flagsInt);
}
}
diff --git a/services/core/java/com/android/server/wm/ConfigurationContainerListener.java b/services/core/java/com/android/server/wm/ConfigurationContainerListener.java
index 3d84e1752e6a..ce6b7f917991 100644
--- a/services/core/java/com/android/server/wm/ConfigurationContainerListener.java
+++ b/services/core/java/com/android/server/wm/ConfigurationContainerListener.java
@@ -23,7 +23,7 @@ import android.content.res.Configuration;
*/
public interface ConfigurationContainerListener {
- /** {@see ConfigurationContainer#onRequestedOverrideConfigurationChanged} */
+ /** @see ConfigurationContainer#onRequestedOverrideConfigurationChanged */
default void onRequestedOverrideConfigurationChanged(Configuration overrideConfiguration) {}
/** Called when new merged override configuration is reported. */
diff --git a/services/core/java/com/android/server/wm/DisplayArea.java b/services/core/java/com/android/server/wm/DisplayArea.java
index cd3f32278165..15483cb90ce2 100644
--- a/services/core/java/com/android/server/wm/DisplayArea.java
+++ b/services/core/java/com/android/server/wm/DisplayArea.java
@@ -174,6 +174,13 @@ public class DisplayArea<T extends WindowContainer> extends WindowContainer<T> {
return false;
}
+ if (mDisplayContent.mFocusedApp != null) {
+ // We record the last focused TDA that respects orientation request, check if this
+ // change may affect it.
+ mDisplayContent.onLastFocusedTaskDisplayAreaChanged(
+ mDisplayContent.mFocusedApp.getDisplayArea());
+ }
+
// The orientation request from this DA may now be respected.
if (!ignoreOrientationRequest) {
return mDisplayContent.updateOrientation();
diff --git a/services/core/java/com/android/server/wm/DisplayAreaPolicy.java b/services/core/java/com/android/server/wm/DisplayAreaPolicy.java
index 7573e92e82a8..d4b319a525da 100644
--- a/services/core/java/com/android/server/wm/DisplayAreaPolicy.java
+++ b/services/core/java/com/android/server/wm/DisplayAreaPolicy.java
@@ -35,6 +35,7 @@ import static com.android.server.wm.DisplayAreaPolicyBuilder.Feature;
import static com.android.server.wm.DisplayAreaPolicyBuilder.HierarchyBuilder;
import android.content.res.Resources;
+import android.os.Bundle;
import android.text.TextUtils;
import java.util.ArrayList;
@@ -71,6 +72,10 @@ public abstract class DisplayAreaPolicy {
*/
public abstract void addWindow(WindowToken token);
+ /** Gets the {@link DisplayArea} which a {@link WindowToken} is about to be attached to. */
+ public abstract DisplayArea.Tokens getDisplayAreaForWindowToken(int type, Bundle options,
+ boolean ownerCanManageAppTokens, boolean roundedCornerOverlay);
+
/**
* Gets the set of {@link DisplayArea} that are created for the given feature to apply to.
*/
diff --git a/services/core/java/com/android/server/wm/DisplayAreaPolicyBuilder.java b/services/core/java/com/android/server/wm/DisplayAreaPolicyBuilder.java
index 8421faa249aa..c8fadf62eb2f 100644
--- a/services/core/java/com/android/server/wm/DisplayAreaPolicyBuilder.java
+++ b/services/core/java/com/android/server/wm/DisplayAreaPolicyBuilder.java
@@ -137,12 +137,12 @@ class DisplayAreaPolicyBuilder {
private ArrayList<HierarchyBuilder> mDisplayAreaGroupHierarchyBuilders = new ArrayList<>();
/**
- * When a window is created, the policy will use this function to select the
- * {@link RootDisplayArea} to place that window in. The selected root can be either the one of
- * the {@link #mRootHierarchyBuilder} or the one of any of the
+ * When a window is created, the policy will use this function, which takes window type and
+ * options, to select the {@link RootDisplayArea} to place that window in. The selected root
+ * can be either the one of the {@link #mRootHierarchyBuilder} or the one of any of the
* {@link #mDisplayAreaGroupHierarchyBuilders}.
**/
- @Nullable private BiFunction<WindowToken, Bundle, RootDisplayArea> mSelectRootForWindowFunc;
+ @Nullable private BiFunction<Integer, Bundle, RootDisplayArea> mSelectRootForWindowFunc;
/** Defines the root hierarchy for the whole logical display. */
DisplayAreaPolicyBuilder setRootHierarchy(HierarchyBuilder rootHierarchyBuilder) {
@@ -162,7 +162,7 @@ class DisplayAreaPolicyBuilder {
/** The policy will use this function to find the root to place windows in. */
DisplayAreaPolicyBuilder setSelectRootForWindowFunc(
- BiFunction<WindowToken, Bundle, RootDisplayArea> selectRootForWindowFunc) {
+ BiFunction<Integer, Bundle, RootDisplayArea> selectRootForWindowFunc) {
mSelectRootForWindowFunc = selectRootForWindowFunc;
return this;
}
@@ -655,19 +655,19 @@ class DisplayAreaPolicyBuilder {
static class Result extends DisplayAreaPolicy {
final List<RootDisplayArea> mDisplayAreaGroupRoots;
- final BiFunction<WindowToken, Bundle, RootDisplayArea> mSelectRootForWindowFunc;
+ final BiFunction<Integer, Bundle, RootDisplayArea> mSelectRootForWindowFunc;
private final TaskDisplayArea mDefaultTaskDisplayArea;
Result(WindowManagerService wmService, RootDisplayArea root,
List<RootDisplayArea> displayAreaGroupRoots,
- @Nullable BiFunction<WindowToken, Bundle, RootDisplayArea>
+ @Nullable BiFunction<Integer, Bundle, RootDisplayArea>
selectRootForWindowFunc) {
super(wmService, root);
mDisplayAreaGroupRoots = Collections.unmodifiableList(displayAreaGroupRoots);
mSelectRootForWindowFunc = selectRootForWindowFunc == null
// Always return the highest level root of the logical display when the func is
// not specified.
- ? (window, options) -> mRoot
+ ? (type, options) -> mRoot
: selectRootForWindowFunc;
// Cache the default TaskDisplayArea for quick access.
@@ -689,7 +689,8 @@ class DisplayAreaPolicyBuilder {
@VisibleForTesting
DisplayArea.Tokens findAreaForToken(WindowToken token) {
- return mSelectRootForWindowFunc.apply(token, token.mOptions).findAreaForToken(token);
+ return mSelectRootForWindowFunc.apply(token.windowType, token.mOptions)
+ .findAreaForToken(token);
}
@VisibleForTesting
@@ -727,6 +728,13 @@ class DisplayAreaPolicyBuilder {
public TaskDisplayArea getDefaultTaskDisplayArea() {
return mDefaultTaskDisplayArea;
}
+
+ @Override
+ public DisplayArea.Tokens getDisplayAreaForWindowToken(int type, Bundle options,
+ boolean ownerCanManageAppTokens, boolean roundedCornerOverlay) {
+ return mSelectRootForWindowFunc.apply(type, options).findAreaForToken(type,
+ ownerCanManageAppTokens, roundedCornerOverlay);
+ }
}
static class PendingArea {
diff --git a/services/core/java/com/android/server/wm/DisplayContent.java b/services/core/java/com/android/server/wm/DisplayContent.java
index bcd78b1bdad3..e88f8e390833 100644
--- a/services/core/java/com/android/server/wm/DisplayContent.java
+++ b/services/core/java/com/android/server/wm/DisplayContent.java
@@ -165,6 +165,7 @@ import android.graphics.Region.Op;
import android.hardware.display.DisplayManagerInternal;
import android.metrics.LogMaker;
import android.os.Binder;
+import android.os.Bundle;
import android.os.Debug;
import android.os.Handler;
import android.os.IBinder;
@@ -488,8 +489,13 @@ class DisplayContent extends RootDisplayArea implements WindowManagerPolicy.Disp
*/
ActivityRecord mFocusedApp = null;
- /** The last focused {@link TaskDisplayArea} on this display. */
- private TaskDisplayArea mLastFocusedTaskDisplayArea = null;
+ /**
+ * We only respect the orientation request from apps below this {@link TaskDisplayArea}.
+ * It is the last focused {@link TaskDisplayArea} on this display that handles orientation
+ * request.
+ */
+ @Nullable
+ private TaskDisplayArea mOrientationRequestingTaskDisplayArea = null;
/**
* The launching activity which is using fixed rotation transformation.
@@ -3325,7 +3331,7 @@ class DisplayContent extends RootDisplayArea implements WindowManagerPolicy.Disp
// Called even if the focused app is not changed in case the app is moved to a different
// TaskDisplayArea.
- setLastFocusedTaskDisplayArea(newFocus.getDisplayArea());
+ onLastFocusedTaskDisplayAreaChanged(newFocus.getDisplayArea());
}
if (mFocusedApp == newFocus) {
return false;
@@ -3339,16 +3345,27 @@ class DisplayContent extends RootDisplayArea implements WindowManagerPolicy.Disp
}
/** Called when the focused {@link TaskDisplayArea} on this display may have changed. */
- @VisibleForTesting
- void setLastFocusedTaskDisplayArea(@Nullable TaskDisplayArea taskDisplayArea) {
- if (taskDisplayArea != null) {
- mLastFocusedTaskDisplayArea = taskDisplayArea;
+ void onLastFocusedTaskDisplayAreaChanged(@Nullable TaskDisplayArea taskDisplayArea) {
+ // Only record the TaskDisplayArea that handles orientation request.
+ if (taskDisplayArea != null && taskDisplayArea.handlesOrientationChangeFromDescendant()) {
+ mOrientationRequestingTaskDisplayArea = taskDisplayArea;
+ return;
+ }
+
+ // If the previous TDA no longer handles orientation request, clear it.
+ if (mOrientationRequestingTaskDisplayArea != null
+ && !mOrientationRequestingTaskDisplayArea
+ .handlesOrientationChangeFromDescendant()) {
+ mOrientationRequestingTaskDisplayArea = null;
}
}
- /** Gets the last focused {@link TaskDisplayArea} on this display. */
- TaskDisplayArea getLastFocusedTaskDisplayArea() {
- return mLastFocusedTaskDisplayArea;
+ /**
+ * Gets the {@link TaskDisplayArea} that we respect orientation requests from apps below it.
+ */
+ @Nullable
+ TaskDisplayArea getOrientationRequestingTaskDisplayArea() {
+ return mOrientationRequestingTaskDisplayArea;
}
/** Updates the layer assignment of windows on this display. */
@@ -4775,7 +4792,6 @@ class DisplayContent extends RootDisplayArea implements WindowManagerPolicy.Disp
return getWindowContainers().getSurfaceControl();
}
- @VisibleForTesting
DisplayArea.Tokens getImeContainer() {
return mImeWindowsContainers;
}
@@ -5731,4 +5747,20 @@ class DisplayContent extends RootDisplayArea implements WindowManagerPolicy.Disp
MagnificationSpec getMagnificationSpec() {
return mMagnificationSpec;
}
+
+ DisplayArea getAreaForWindowToken(int windowType, Bundle options,
+ boolean ownerCanManageAppToken, boolean roundedCornerOverlay) {
+ // TODO(b/159767464): figure out how to find an appropriate TDA.
+ if (windowType >= FIRST_APPLICATION_WINDOW && windowType <= LAST_APPLICATION_WINDOW) {
+ return getDefaultTaskDisplayArea();
+ }
+ // Return IME container here because it could be in one of sub RootDisplayAreas depending on
+ // the focused edit text. Also, the RootDisplayArea choosing strategy is implemented by
+ // the server side, but not mSelectRootForWindowFunc customized by OEM.
+ if (windowType == TYPE_INPUT_METHOD || windowType == TYPE_INPUT_METHOD_DIALOG) {
+ return getImeContainer();
+ }
+ return mDisplayAreaPolicy.getDisplayAreaForWindowToken(windowType, options,
+ ownerCanManageAppToken, roundedCornerOverlay);
+ }
}
diff --git a/services/core/java/com/android/server/wm/DisplayWindowSettingsProvider.java b/services/core/java/com/android/server/wm/DisplayWindowSettingsProvider.java
index f4fdd7370e9c..57c947f572d9 100644
--- a/services/core/java/com/android/server/wm/DisplayWindowSettingsProvider.java
+++ b/services/core/java/com/android/server/wm/DisplayWindowSettingsProvider.java
@@ -450,12 +450,12 @@ class DisplayWindowSettingsProvider implements SettingsProvider {
out.attributeInt(null, "windowingMode", settingsEntry.mWindowingMode);
}
if (settingsEntry.mUserRotationMode != null) {
- out.attribute(null, "userRotationMode",
- settingsEntry.mUserRotationMode.toString());
+ out.attributeInt(null, "userRotationMode",
+ settingsEntry.mUserRotationMode);
}
if (settingsEntry.mUserRotation != null) {
- out.attribute(null, "userRotation",
- settingsEntry.mUserRotation.toString());
+ out.attributeInt(null, "userRotation",
+ settingsEntry.mUserRotation);
}
if (settingsEntry.mForcedWidth != 0 && settingsEntry.mForcedHeight != 0) {
out.attributeInt(null, "forcedWidth", settingsEntry.mForcedWidth);
@@ -465,30 +465,30 @@ class DisplayWindowSettingsProvider implements SettingsProvider {
out.attributeInt(null, "forcedDensity", settingsEntry.mForcedDensity);
}
if (settingsEntry.mForcedScalingMode != null) {
- out.attribute(null, "forcedScalingMode",
- settingsEntry.mForcedScalingMode.toString());
+ out.attributeInt(null, "forcedScalingMode",
+ settingsEntry.mForcedScalingMode);
}
if (settingsEntry.mRemoveContentMode != REMOVE_CONTENT_MODE_UNDEFINED) {
out.attributeInt(null, "removeContentMode", settingsEntry.mRemoveContentMode);
}
if (settingsEntry.mShouldShowWithInsecureKeyguard != null) {
- out.attribute(null, "shouldShowWithInsecureKeyguard",
- settingsEntry.mShouldShowWithInsecureKeyguard.toString());
+ out.attributeBoolean(null, "shouldShowWithInsecureKeyguard",
+ settingsEntry.mShouldShowWithInsecureKeyguard);
}
if (settingsEntry.mShouldShowSystemDecors != null) {
- out.attribute(null, "shouldShowSystemDecors",
- settingsEntry.mShouldShowSystemDecors.toString());
+ out.attributeBoolean(null, "shouldShowSystemDecors",
+ settingsEntry.mShouldShowSystemDecors);
}
if (settingsEntry.mImePolicy != null) {
out.attributeInt(null, "imePolicy", settingsEntry.mImePolicy);
}
if (settingsEntry.mFixedToUserRotation != null) {
- out.attribute(null, "fixedToUserRotation",
- settingsEntry.mFixedToUserRotation.toString());
+ out.attributeInt(null, "fixedToUserRotation",
+ settingsEntry.mFixedToUserRotation);
}
if (settingsEntry.mIgnoreOrientationRequest != null) {
- out.attribute(null, "ignoreOrientationRequest",
- settingsEntry.mIgnoreOrientationRequest.toString());
+ out.attributeBoolean(null, "ignoreOrientationRequest",
+ settingsEntry.mIgnoreOrientationRequest);
}
out.endTag(null, "display");
}
diff --git a/services/core/java/com/android/server/wm/PinnedStackController.java b/services/core/java/com/android/server/wm/PinnedStackController.java
index 52ada472f0aa..fd42b2467d19 100644
--- a/services/core/java/com/android/server/wm/PinnedStackController.java
+++ b/services/core/java/com/android/server/wm/PinnedStackController.java
@@ -29,7 +29,6 @@ import android.util.DisplayMetrics;
import android.util.Log;
import android.util.Slog;
import android.view.DisplayInfo;
-import android.view.IPinnedStackController;
import android.view.IPinnedStackListener;
import java.io.PrintWriter;
@@ -63,8 +62,6 @@ class PinnedStackController {
private final PinnedStackListenerDeathHandler mPinnedStackListenerDeathHandler =
new PinnedStackListenerDeathHandler();
- private final PinnedStackControllerCallback mCallbacks = new PinnedStackControllerCallback();
-
/** Whether the PiP is entering or leaving. */
private boolean mIsPipWindowingModeChanging;
@@ -86,18 +83,6 @@ class PinnedStackController {
private final DisplayMetrics mTmpMetrics = new DisplayMetrics();
/**
- * The callback object passed to listeners for them to notify the controller of state changes.
- */
- private class PinnedStackControllerCallback extends IPinnedStackController.Stub {
- @Override
- public int getDisplayRotation() {
- synchronized (mService.mGlobalLock) {
- return mDisplayInfo.rotation;
- }
- }
- }
-
- /**
* Handler for the case where the listener dies.
*/
private class PinnedStackListenerDeathHandler implements IBinder.DeathRecipient {
@@ -141,7 +126,6 @@ class PinnedStackController {
void registerPinnedStackListener(IPinnedStackListener listener) {
try {
listener.asBinder().linkToDeath(mPinnedStackListenerDeathHandler, 0);
- listener.onListenerRegistered(mCallbacks);
mPinnedStackListener = listener;
notifyDisplayInfoChanged(mDisplayInfo);
notifyImeVisibilityChanged(mIsImeShowing, mImeHeight);
diff --git a/services/core/java/com/android/server/wm/RootDisplayArea.java b/services/core/java/com/android/server/wm/RootDisplayArea.java
index c4fcea68a6fc..393055eab111 100644
--- a/services/core/java/com/android/server/wm/RootDisplayArea.java
+++ b/services/core/java/com/android/server/wm/RootDisplayArea.java
@@ -106,12 +106,23 @@ class RootDisplayArea extends DisplayArea<DisplayArea> {
}
/** Finds the {@link DisplayArea.Tokens} that this type of window should be attached to. */
+ @Nullable
DisplayArea.Tokens findAreaForToken(WindowToken token) {
- int windowLayerFromType = token.getWindowLayerFromType();
+ return findAreaForToken(token.windowType, token.mOwnerCanManageAppTokens,
+ token.mRoundedCornerOverlay);
+ }
+
+ @Nullable
+ DisplayArea.Tokens findAreaForToken(int windowType, boolean ownerCanManageAppTokens,
+ boolean roundedCornerOverlay) {
+ // TODO(b/159767464): cover TYPE_INPUT_METHOD(_DIALOG) case here. mAreaForLayer doesn't
+ // contain IME container.
+ int windowLayerFromType = mWmService.mPolicy.getWindowLayerFromTypeLw(windowType,
+ ownerCanManageAppTokens);
if (windowLayerFromType == APPLICATION_LAYER) {
throw new IllegalArgumentException(
"There shouldn't be WindowToken on APPLICATION_LAYER");
- } else if (token.mRoundedCornerOverlay) {
+ } else if (roundedCornerOverlay) {
windowLayerFromType = mAreaForLayer.length - 1;
}
return mAreaForLayer[windowLayerFromType];
diff --git a/services/core/java/com/android/server/wm/TaskDisplayArea.java b/services/core/java/com/android/server/wm/TaskDisplayArea.java
index 4498a8c82583..9425602763c5 100644
--- a/services/core/java/com/android/server/wm/TaskDisplayArea.java
+++ b/services/core/java/com/android/server/wm/TaskDisplayArea.java
@@ -641,9 +641,7 @@ final class TaskDisplayArea extends DisplayArea<Task> {
@Override
int getOrientation(int candidate) {
mLastOrientationSource = null;
- // Only allow to specify orientation if this TDA is not set to ignore orientation request,
- // and it has the focus.
- if (mIgnoreOrientationRequest || !isLastFocused()) {
+ if (!canSpecifyOrientation()) {
return SCREEN_ORIENTATION_UNSET;
}
@@ -1918,10 +1916,14 @@ final class TaskDisplayArea extends DisplayArea<Task> {
return lastReparentedStack;
}
- /** Whether this task display area is the last focused one on this logical display. */
+ /** Whether this task display area can request orientation. */
@VisibleForTesting
- boolean isLastFocused() {
- return mDisplayContent.getLastFocusedTaskDisplayArea() == this;
+ boolean canSpecifyOrientation() {
+ // Only allow to specify orientation if this TDA is not set to ignore orientation request,
+ // and it is the last focused one on this logical display that can request orientation
+ // request.
+ return !mIgnoreOrientationRequest
+ && mDisplayContent.getOrientationRequestingTaskDisplayArea() == this;
}
@Override
diff --git a/services/core/java/com/android/server/wm/WindowContainer.java b/services/core/java/com/android/server/wm/WindowContainer.java
index 6242fe9a1444..adc7a227861a 100644
--- a/services/core/java/com/android/server/wm/WindowContainer.java
+++ b/services/core/java/com/android/server/wm/WindowContainer.java
@@ -98,6 +98,7 @@ import java.lang.ref.WeakReference;
import java.util.ArrayList;
import java.util.Comparator;
import java.util.LinkedList;
+import java.util.List;
import java.util.function.BiFunction;
import java.util.function.Consumer;
import java.util.function.Function;
@@ -314,6 +315,8 @@ class WindowContainer<E extends WindowContainer> extends ConfigurationContainer<
final SurfaceControl.Transaction mSyncTransaction;
@SyncState int mSyncState = SYNC_STATE_NONE;
+ private final List<WindowContainerListener> mListeners = new ArrayList<>();
+
WindowContainer(WindowManagerService wms) {
mWmService = wms;
mPendingTransaction = wms.mTransactionFactory.get();
@@ -637,6 +640,10 @@ class WindowContainer<E extends WindowContainer> extends ConfigurationContainer<
if (mParent != null) {
mParent.removeChild(this);
}
+
+ for (int i = mListeners.size() - 1; i >= 0; --i) {
+ mListeners.get(i).onRemoved();
+ }
}
/**
@@ -819,6 +826,9 @@ class WindowContainer<E extends WindowContainer> extends ConfigurationContainer<
final WindowContainer child = mChildren.get(i);
child.onDisplayChanged(dc);
}
+ for (int i = mListeners.size() - 1; i >= 0; --i) {
+ mListeners.get(i).onDisplayChanged(dc);
+ }
}
DisplayContent getDisplayContent() {
@@ -3106,4 +3116,19 @@ class WindowContainer<E extends WindowContainer> extends ConfigurationContainer<
mSyncState = SYNC_STATE_NONE;
prepareSync();
}
+
+ void registerWindowContainerListener(WindowContainerListener listener) {
+ if (mListeners.contains(listener)) {
+ return;
+ }
+ mListeners.add(listener);
+ // Also register to ConfigurationChangeListener to receive configuration changes.
+ registerConfigurationChangeListener(listener);
+ listener.onDisplayChanged(getDisplayContent());
+ }
+
+ void unregisterWindowContainerListener(WindowContainerListener listener) {
+ mListeners.remove(listener);
+ unregisterConfigurationChangeListener(listener);
+ }
}
diff --git a/services/core/java/com/android/server/wm/WindowContainerListener.java b/services/core/java/com/android/server/wm/WindowContainerListener.java
new file mode 100644
index 000000000000..ac1fe173dd09
--- /dev/null
+++ b/services/core/java/com/android/server/wm/WindowContainerListener.java
@@ -0,0 +1,30 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.server.wm;
+
+/**
+ * Interface for listening to changes in a {@link WindowContainer}. A usage of this listener is
+ * to receive the changes and propagate them to the client side.
+ */
+interface WindowContainerListener extends ConfigurationContainerListener {
+
+ /** @see WindowContainer#onDisplayChanged(DisplayContent) */
+ default void onDisplayChanged(DisplayContent dc) {}
+
+ /** Called when {@link WindowContainer#removeImmediately()} is invoked. */
+ default void onRemoved() {}
+}
diff --git a/services/core/java/com/android/server/wm/WindowContextListenerController.java b/services/core/java/com/android/server/wm/WindowContextListenerController.java
new file mode 100644
index 000000000000..051ece38b26f
--- /dev/null
+++ b/services/core/java/com/android/server/wm/WindowContextListenerController.java
@@ -0,0 +1,248 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.server.wm;
+
+import static android.view.Display.INVALID_DISPLAY;
+
+import static com.android.internal.protolog.ProtoLogGroup.WM_DEBUG_ADD_REMOVE;
+import static com.android.internal.protolog.ProtoLogGroup.WM_ERROR;
+
+import android.annotation.NonNull;
+import android.app.IWindowToken;
+import android.content.res.Configuration;
+import android.os.Bundle;
+import android.os.IBinder;
+import android.os.RemoteException;
+import android.util.ArrayMap;
+import android.view.View;
+import android.view.ViewGroup;
+
+import com.android.internal.annotations.VisibleForTesting;
+import com.android.internal.protolog.common.ProtoLog;
+
+import java.util.Map;
+import java.util.Objects;
+
+/**
+ * A controller to register/unregister {@link WindowContainerListener} for
+ * {@link android.app.WindowContext}.
+ *
+ * <ul>
+ * <li>When a {@link android.app.WindowContext} is created, it registers the listener via
+ * {@link WindowManagerService#registerWindowContextListener(IBinder, int, int, Bundle)}
+ * automatically.</li>
+ * <li>When the {@link android.app.WindowContext} adds the first window to the screen via
+ * {@link android.view.WindowManager#addView(View, ViewGroup.LayoutParams)},
+ * {@link WindowManagerService} then updates the {@link WindowContextListenerImpl} to listen
+ * to corresponding {@link WindowToken} via this controller.</li>
+ * <li>When the {@link android.app.WindowContext} is GCed, it unregisters the previously
+ * registered listener via
+ * {@link WindowManagerService#unregisterWindowContextListener(IBinder)}.
+ * {@link WindowManagerService} is also responsible for removing the
+ * {@link android.app.WindowContext} created {@link WindowToken}.</li>
+ * </ul>
+ * <p>Note that the listener may be removed earlier than the
+ * {@link #unregisterWindowContainerListener(IBinder)} if the listened {@link WindowContainer} was
+ * removed. An example is that the {@link DisplayArea} is removed when users unfold the
+ * foldable devices. Another example is that the associated external display is detached.</p>
+ */
+class WindowContextListenerController {
+ @VisibleForTesting
+ final Map<IBinder, WindowContextListenerImpl> mListeners = new ArrayMap<>();
+
+ /**
+ * Registers the listener to a {@code container} which is associated with
+ * a {@code clientToken}, which is a {@link android.app.WindowContext} representation. If the
+ * listener associated with {@code clientToken} hasn't been initialized yet, create one
+ * {@link WindowContextListenerImpl}. Otherwise, the listener associated with
+ * {@code clientToken} switches to listen to the {@code container}.
+ *
+ * @param clientToken the token to associate with the listener
+ * @param container the {@link WindowContainer} which the listener is going to listen to.
+ * @param ownerUid the caller UID
+ */
+ void registerWindowContainerListener(@NonNull IBinder clientToken,
+ @NonNull WindowContainer container, int ownerUid) {
+ WindowContextListenerImpl listener = mListeners.get(clientToken);
+ if (listener == null) {
+ listener = new WindowContextListenerImpl(clientToken, container, ownerUid);
+ listener.register();
+ } else {
+ listener.updateContainer(container);
+ }
+ }
+
+ void unregisterWindowContainerListener(IBinder clientToken) {
+ final WindowContextListenerImpl listener = mListeners.get(clientToken);
+ // Listeners may be removed earlier. An example is the display where the listener is
+ // located is detached. In this case, all window containers on the display, as well as
+ // their listeners will be removed before their listeners are unregistered.
+ if (listener == null) {
+ return;
+ }
+ listener.unregister();
+ }
+
+ boolean assertCallerCanRemoveListener(IBinder clientToken, boolean callerCanManageAppTokens,
+ int callingUid) {
+ final WindowContextListenerImpl listener = mListeners.get(clientToken);
+ if (listener == null) {
+ ProtoLog.i(WM_DEBUG_ADD_REMOVE, "The listener does not exist.");
+ return false;
+ }
+ if (callerCanManageAppTokens) {
+ return true;
+ }
+ if (callingUid != listener.mOwnerUid) {
+ throw new UnsupportedOperationException("Uid mismatch. Caller uid is " + callingUid
+ + ", while the listener's owner is from " + listener.mOwnerUid);
+ }
+ return true;
+ }
+
+ @VisibleForTesting
+ class WindowContextListenerImpl implements WindowContainerListener {
+ @NonNull private final IBinder mClientToken;
+ private final int mOwnerUid;
+ @NonNull private WindowContainer mContainer;
+
+ private DeathRecipient mDeathRecipient;
+
+ private int mLastReportedDisplay = INVALID_DISPLAY;
+ private Configuration mLastReportedConfig;
+
+ private WindowContextListenerImpl(IBinder clientToken, WindowContainer container,
+ int ownerUid) {
+ mClientToken = clientToken;
+ mContainer = Objects.requireNonNull(container);
+ mOwnerUid = ownerUid;
+
+ final DeathRecipient deathRecipient = new DeathRecipient();
+ try {
+ deathRecipient.linkToDeath();
+ mDeathRecipient = deathRecipient;
+ } catch (RemoteException e) {
+ ProtoLog.e(WM_ERROR, "Could not register window container listener token=%s, "
+ + "container=%s", mClientToken, mContainer);
+ }
+ }
+
+ /** TEST ONLY: returns the {@link WindowContainer} of the listener */
+ @VisibleForTesting
+ WindowContainer getWindowContainer() {
+ return mContainer;
+ }
+
+ private void updateContainer(WindowContainer newContainer) {
+ if (mContainer.equals(newContainer)) {
+ return;
+ }
+ mContainer.unregisterWindowContainerListener(this);
+ mContainer = newContainer;
+ clear();
+ register();
+ }
+
+ private void register() {
+ if (mDeathRecipient == null) {
+ throw new IllegalStateException("Invalid client token: " + mClientToken);
+ }
+ mListeners.putIfAbsent(mClientToken, this);
+ mContainer.registerWindowContainerListener(this);
+ reportConfigToWindowTokenClient();
+ }
+
+ private void unregister() {
+ mContainer.unregisterWindowContainerListener(this);
+ mListeners.remove(mClientToken);
+ }
+
+ private void clear() {
+ mLastReportedConfig = null;
+ mLastReportedDisplay = INVALID_DISPLAY;
+ }
+
+ @Override
+ public void onRequestedOverrideConfigurationChanged(Configuration overrideConfiguration) {
+ reportConfigToWindowTokenClient();
+ }
+
+ @Override
+ public void onDisplayChanged(DisplayContent dc) {
+ reportConfigToWindowTokenClient();
+ }
+
+ private void reportConfigToWindowTokenClient() {
+ if (mDeathRecipient == null) {
+ throw new IllegalStateException("Invalid client token: " + mClientToken);
+ }
+
+ if (mLastReportedConfig == null) {
+ mLastReportedConfig = new Configuration();
+ }
+ final Configuration config = mContainer.getConfiguration();
+ final int displayId = mContainer.getDisplayContent().getDisplayId();
+ if (config.equals(mLastReportedConfig) && displayId == mLastReportedDisplay) {
+ // No changes since last reported time.
+ return;
+ }
+
+ mLastReportedConfig.setTo(config);
+ mLastReportedDisplay = displayId;
+
+ IWindowToken windowTokenClient = IWindowToken.Stub.asInterface(mClientToken);
+ try {
+ windowTokenClient.onConfigurationChanged(config, displayId);
+ } catch (RemoteException e) {
+ ProtoLog.w(WM_ERROR, "Could not report config changes to the window token client.");
+ }
+ }
+
+ @Override
+ public void onRemoved() {
+ if (mDeathRecipient == null) {
+ throw new IllegalStateException("Invalid client token: " + mClientToken);
+ }
+ mDeathRecipient.unlinkToDeath();
+ IWindowToken windowTokenClient = IWindowToken.Stub.asInterface(mClientToken);
+ try {
+ windowTokenClient.onWindowTokenRemoved();
+ } catch (RemoteException e) {
+ ProtoLog.w(WM_ERROR, "Could not report token removal to the window token client.");
+ }
+ unregister();
+ }
+
+ private class DeathRecipient implements IBinder.DeathRecipient {
+ @Override
+ public void binderDied() {
+ synchronized (mContainer.mWmService.mGlobalLock) {
+ mDeathRecipient = null;
+ unregister();
+ }
+ }
+
+ void linkToDeath() throws RemoteException {
+ mClientToken.linkToDeath(this, 0);
+ }
+
+ void unlinkToDeath() {
+ mClientToken.unlinkToDeath(this, 0);
+ }
+ }
+ }
+}
diff --git a/services/core/java/com/android/server/wm/WindowManagerService.java b/services/core/java/com/android/server/wm/WindowManagerService.java
index 37834cc4b8b0..8fd342c25bc3 100644
--- a/services/core/java/com/android/server/wm/WindowManagerService.java
+++ b/services/core/java/com/android/server/wm/WindowManagerService.java
@@ -769,6 +769,8 @@ public class WindowManagerService extends IWindowManager.Stub
final AnrController mAnrController;
private final ImpressionAttestationController mImpressionAttestationController;
+ private final WindowContextListenerController mWindowContextListenerController =
+ new WindowContextListenerController();
@VisibleForTesting
final class SettingsObserver extends ContentObserver {
@@ -2627,6 +2629,10 @@ public class WindowManagerService extends IWindowManager.Stub
}
boolean checkCallingPermission(String permission, String func) {
+ return checkCallingPermission(permission, func, true /* printLog */);
+ }
+
+ boolean checkCallingPermission(String permission, String func, boolean printLog) {
// Quick check: if the calling permission is me, it's all okay.
if (Binder.getCallingPid() == myPid()) {
return true;
@@ -2636,8 +2642,10 @@ public class WindowManagerService extends IWindowManager.Stub
== PackageManager.PERMISSION_GRANTED) {
return true;
}
- ProtoLog.w(WM_ERROR, "Permission Denial: %s from pid=%d, uid=%d requires %s",
- func, Binder.getCallingPid(), Binder.getCallingUid(), permission);
+ if (printLog) {
+ ProtoLog.w(WM_ERROR, "Permission Denial: %s from pid=%d, uid=%d requires %s",
+ func, Binder.getCallingPid(), Binder.getCallingUid(), permission);
+ }
return false;
}
@@ -2730,6 +2738,52 @@ public class WindowManagerService extends IWindowManager.Stub
}
@Override
+ public boolean registerWindowContextListener(IBinder clientToken, int type, int displayId,
+ Bundle options) {
+ final boolean callerCanManageAppTokens = checkCallingPermission(MANAGE_APP_TOKENS,
+ "registerWindowContextListener", false /* printLog */);
+ final int callingUid = Binder.getCallingUid();
+ final long origId = Binder.clearCallingIdentity();
+ try {
+ synchronized (mGlobalLock) {
+ final DisplayContent dc = mRoot.getDisplayContentOrCreate(displayId);
+ if (dc == null) {
+ ProtoLog.w(WM_ERROR, "registerWindowContextListener: trying to add listener to"
+ + " a non-existing display:%d", displayId);
+ return false;
+ }
+ // TODO(b/155340867): Investigate if we still need roundedCornerOverlay after
+ // the feature b/155340867 is completed.
+ final DisplayArea da = dc.getAreaForWindowToken(type, options,
+ callerCanManageAppTokens, false /* roundedCornerOverlay */);
+ mWindowContextListenerController.registerWindowContainerListener(clientToken, da,
+ callingUid);
+ return true;
+ }
+ } finally {
+ Binder.restoreCallingIdentity(origId);
+ }
+ }
+
+ @Override
+ public void unregisterWindowContextListener(IBinder clientToken) {
+ final boolean callerCanManageAppTokens = checkCallingPermission(MANAGE_APP_TOKENS,
+ "unregisterWindowContextListener", false /* printLog */);
+ final int callingUid = Binder.getCallingUid();
+ final long origId = Binder.clearCallingIdentity();
+ try {
+ synchronized (mGlobalLock) {
+ if (mWindowContextListenerController.assertCallerCanRemoveListener(clientToken,
+ callerCanManageAppTokens, callingUid)) {
+ mWindowContextListenerController.unregisterWindowContainerListener(clientToken);
+ }
+ }
+ } finally {
+ Binder.restoreCallingIdentity(origId);
+ }
+ }
+
+ @Override
public boolean isWindowToken(IBinder binder) {
synchronized (mGlobalLock) {
final WindowToken windowToken = mRoot.getWindowToken(binder);
diff --git a/services/core/java/com/android/server/wm/WindowToken.java b/services/core/java/com/android/server/wm/WindowToken.java
index 5ced6a52050b..34875ed70889 100644
--- a/services/core/java/com/android/server/wm/WindowToken.java
+++ b/services/core/java/com/android/server/wm/WindowToken.java
@@ -419,6 +419,7 @@ class WindowToken extends WindowContainer<WindowState> {
reportWindowTokenRemovedToClient();
}
+ // TODO(b/159767464): Remove after we migrate to listener approach.
private void reportWindowTokenRemovedToClient() {
if (!shouldReportToClient()) {
return;
diff --git a/services/core/xsd/device-state-config/device-state-config.xsd b/services/core/xsd/device-state-config/device-state-config.xsd
index 0d8c08c93ff2..501450398fc3 100644
--- a/services/core/xsd/device-state-config/device-state-config.xsd
+++ b/services/core/xsd/device-state-config/device-state-config.xsd
@@ -57,8 +57,8 @@
<xs:complexType name="sensorCondition">
<xs:sequence>
+ <xs:element name="type" type="xs:string" />
<xs:element name="name" type="xs:string" />
- <xs:element name="type" type="xs:positiveInteger" />
<xs:element name="value" type="numericRange" maxOccurs="unbounded" />
</xs:sequence>
</xs:complexType>
diff --git a/services/core/xsd/device-state-config/schema/current.txt b/services/core/xsd/device-state-config/schema/current.txt
index 667d1add5a98..b396af0fa0c6 100644
--- a/services/core/xsd/device-state-config/schema/current.txt
+++ b/services/core/xsd/device-state-config/schema/current.txt
@@ -44,10 +44,10 @@ package com.android.server.policy.devicestate.config {
public class SensorCondition {
ctor public SensorCondition();
method public String getName();
- method public java.math.BigInteger getType();
+ method public String getType();
method public java.util.List<com.android.server.policy.devicestate.config.NumericRange> getValue();
method public void setName(String);
- method public void setType(java.math.BigInteger);
+ method public void setType(String);
}
public class XmlParser {
diff --git a/services/devicepolicy/java/com/android/server/devicepolicy/ActiveAdmin.java b/services/devicepolicy/java/com/android/server/devicepolicy/ActiveAdmin.java
index 1a147b9f73e4..a281180d77d1 100644
--- a/services/devicepolicy/java/com/android/server/devicepolicy/ActiveAdmin.java
+++ b/services/devicepolicy/java/com/android/server/devicepolicy/ActiveAdmin.java
@@ -40,14 +40,14 @@ import android.util.ArraySet;
import android.util.IndentingPrintWriter;
import android.util.Log;
import android.util.Slog;
+import android.util.TypedXmlPullParser;
+import android.util.TypedXmlSerializer;
import com.android.internal.util.Preconditions;
import com.android.internal.util.XmlUtils;
import com.android.server.pm.UserRestrictionsUtils;
-import org.xmlpull.v1.XmlPullParser;
import org.xmlpull.v1.XmlPullParserException;
-import org.xmlpull.v1.XmlSerializer;
import java.io.IOException;
import java.util.ArrayList;
@@ -300,7 +300,7 @@ class ActiveAdmin {
return UserHandle.of(UserHandle.getUserId(info.getActivityInfo().applicationInfo.uid));
}
- void writeToXml(XmlSerializer out)
+ void writeToXml(TypedXmlSerializer out)
throws IllegalArgumentException, IllegalStateException, IOException {
out.startTag(null, TAG_POLICIES);
info.writePoliciesToXml(out);
@@ -413,11 +413,11 @@ class ActiveAdmin {
}
if (isNetworkLoggingEnabled) {
out.startTag(null, TAG_IS_NETWORK_LOGGING_ENABLED);
- out.attribute(null, ATTR_VALUE, Boolean.toString(isNetworkLoggingEnabled));
- out.attribute(null, ATTR_NUM_NETWORK_LOGGING_NOTIFICATIONS,
- Integer.toString(numNetworkLoggingNotifications));
- out.attribute(null, ATTR_LAST_NETWORK_LOGGING_NOTIFICATION,
- Long.toString(lastNetworkLoggingNotificationTimeMs));
+ out.attributeBoolean(null, ATTR_VALUE, isNetworkLoggingEnabled);
+ out.attributeInt(null, ATTR_NUM_NETWORK_LOGGING_NOTIFICATIONS,
+ numNetworkLoggingNotifications);
+ out.attributeLong(null, ATTR_LAST_NETWORK_LOGGING_NOTIFICATION,
+ lastNetworkLoggingNotificationTimeMs);
out.endTag(null, TAG_IS_NETWORK_LOGGING_ENABLED);
}
if (disabledKeyguardFeatures != DEF_KEYGUARD_FEATURES_DISABLED) {
@@ -535,13 +535,13 @@ class ActiveAdmin {
}
}
- void writeTextToXml(XmlSerializer out, String tag, String text) throws IOException {
+ void writeTextToXml(TypedXmlSerializer out, String tag, String text) throws IOException {
out.startTag(null, tag);
out.text(text);
out.endTag(null, tag);
}
- void writePackageListToXml(XmlSerializer out, String outerTag,
+ void writePackageListToXml(TypedXmlSerializer out, String outerTag,
List<String> packageList)
throws IllegalArgumentException, IllegalStateException, IOException {
if (packageList == null) {
@@ -550,35 +550,35 @@ class ActiveAdmin {
writeAttributeValuesToXml(out, outerTag, TAG_PACKAGE_LIST_ITEM, packageList);
}
- void writeAttributeValueToXml(XmlSerializer out, String tag, String value)
+ void writeAttributeValueToXml(TypedXmlSerializer out, String tag, String value)
throws IOException {
out.startTag(null, tag);
out.attribute(null, ATTR_VALUE, value);
out.endTag(null, tag);
}
- void writeAttributeValueToXml(XmlSerializer out, String tag, int value)
+ void writeAttributeValueToXml(TypedXmlSerializer out, String tag, int value)
throws IOException {
out.startTag(null, tag);
- out.attribute(null, ATTR_VALUE, Integer.toString(value));
+ out.attributeInt(null, ATTR_VALUE, value);
out.endTag(null, tag);
}
- void writeAttributeValueToXml(XmlSerializer out, String tag, long value)
+ void writeAttributeValueToXml(TypedXmlSerializer out, String tag, long value)
throws IOException {
out.startTag(null, tag);
- out.attribute(null, ATTR_VALUE, Long.toString(value));
+ out.attributeLong(null, ATTR_VALUE, value);
out.endTag(null, tag);
}
- void writeAttributeValueToXml(XmlSerializer out, String tag, boolean value)
+ void writeAttributeValueToXml(TypedXmlSerializer out, String tag, boolean value)
throws IOException {
out.startTag(null, tag);
- out.attribute(null, ATTR_VALUE, Boolean.toString(value));
+ out.attributeBoolean(null, ATTR_VALUE, value);
out.endTag(null, tag);
}
- void writeAttributeValuesToXml(XmlSerializer out, String outerTag, String innerTag,
+ void writeAttributeValuesToXml(TypedXmlSerializer out, String outerTag, String innerTag,
@NonNull Collection<String> values) throws IOException {
out.startTag(null, outerTag);
for (String value : values) {
@@ -589,7 +589,7 @@ class ActiveAdmin {
out.endTag(null, outerTag);
}
- void readFromXml(XmlPullParser parser, boolean shouldOverridePolicies)
+ void readFromXml(TypedXmlPullParser parser, boolean shouldOverridePolicies)
throws XmlPullParserException, IOException {
int outerDepth = parser.getDepth();
int type;
@@ -606,47 +606,33 @@ class ActiveAdmin {
info.readPoliciesFromXml(parser);
}
} else if (TAG_PASSWORD_QUALITY.equals(tag)) {
- mPasswordPolicy.quality = Integer.parseInt(
- parser.getAttributeValue(null, ATTR_VALUE));
+ mPasswordPolicy.quality = parser.getAttributeInt(null, ATTR_VALUE);
} else if (TAG_MIN_PASSWORD_LENGTH.equals(tag)) {
- mPasswordPolicy.length = Integer.parseInt(
- parser.getAttributeValue(null, ATTR_VALUE));
+ mPasswordPolicy.length = parser.getAttributeInt(null, ATTR_VALUE);
} else if (TAG_PASSWORD_HISTORY_LENGTH.equals(tag)) {
- passwordHistoryLength = Integer.parseInt(
- parser.getAttributeValue(null, ATTR_VALUE));
+ passwordHistoryLength = parser.getAttributeInt(null, ATTR_VALUE);
} else if (TAG_MIN_PASSWORD_UPPERCASE.equals(tag)) {
- mPasswordPolicy.upperCase = Integer.parseInt(
- parser.getAttributeValue(null, ATTR_VALUE));
+ mPasswordPolicy.upperCase = parser.getAttributeInt(null, ATTR_VALUE);
} else if (TAG_MIN_PASSWORD_LOWERCASE.equals(tag)) {
- mPasswordPolicy.lowerCase = Integer.parseInt(
- parser.getAttributeValue(null, ATTR_VALUE));
+ mPasswordPolicy.lowerCase = parser.getAttributeInt(null, ATTR_VALUE);
} else if (TAG_MIN_PASSWORD_LETTERS.equals(tag)) {
- mPasswordPolicy.letters = Integer.parseInt(
- parser.getAttributeValue(null, ATTR_VALUE));
+ mPasswordPolicy.letters = parser.getAttributeInt(null, ATTR_VALUE);
} else if (TAG_MIN_PASSWORD_NUMERIC.equals(tag)) {
- mPasswordPolicy.numeric = Integer.parseInt(
- parser.getAttributeValue(null, ATTR_VALUE));
+ mPasswordPolicy.numeric = parser.getAttributeInt(null, ATTR_VALUE);
} else if (TAG_MIN_PASSWORD_SYMBOLS.equals(tag)) {
- mPasswordPolicy.symbols = Integer.parseInt(
- parser.getAttributeValue(null, ATTR_VALUE));
+ mPasswordPolicy.symbols = parser.getAttributeInt(null, ATTR_VALUE);
} else if (TAG_MIN_PASSWORD_NONLETTER.equals(tag)) {
- mPasswordPolicy.nonLetter = Integer.parseInt(
- parser.getAttributeValue(null, ATTR_VALUE));
+ mPasswordPolicy.nonLetter = parser.getAttributeInt(null, ATTR_VALUE);
} else if (TAG_PASSWORD_QUALITY_APPLIES_TO_PARENT.equals(tag)) {
- mPasswordPolicyAppliesToParent = Boolean.parseBoolean(
- parser.getAttributeValue(null, ATTR_VALUE));
+ mPasswordPolicyAppliesToParent = parser.getAttributeBoolean(null, ATTR_VALUE);
} else if (TAG_MAX_TIME_TO_UNLOCK.equals(tag)) {
- maximumTimeToUnlock = Long.parseLong(
- parser.getAttributeValue(null, ATTR_VALUE));
+ maximumTimeToUnlock = parser.getAttributeLong(null, ATTR_VALUE);
} else if (TAG_STRONG_AUTH_UNLOCK_TIMEOUT.equals(tag)) {
- strongAuthUnlockTimeout = Long.parseLong(
- parser.getAttributeValue(null, ATTR_VALUE));
+ strongAuthUnlockTimeout = parser.getAttributeLong(null, ATTR_VALUE);
} else if (TAG_MAX_FAILED_PASSWORD_WIPE.equals(tag)) {
- maximumFailedPasswordsForWipe = Integer.parseInt(
- parser.getAttributeValue(null, ATTR_VALUE));
+ maximumFailedPasswordsForWipe = parser.getAttributeInt(null, ATTR_VALUE);
} else if (TAG_SPECIFIES_GLOBAL_PROXY.equals(tag)) {
- specifiesGlobalProxy = Boolean.parseBoolean(
- parser.getAttributeValue(null, ATTR_VALUE));
+ specifiesGlobalProxy = parser.getAttributeBoolean(null, ATTR_VALUE, false);
} else if (TAG_GLOBAL_PROXY_SPEC.equals(tag)) {
globalProxySpec =
parser.getAttributeValue(null, ATTR_VALUE);
@@ -654,48 +640,36 @@ class ActiveAdmin {
globalProxyExclusionList =
parser.getAttributeValue(null, ATTR_VALUE);
} else if (TAG_PASSWORD_EXPIRATION_TIMEOUT.equals(tag)) {
- passwordExpirationTimeout = Long.parseLong(
- parser.getAttributeValue(null, ATTR_VALUE));
+ passwordExpirationTimeout = parser.getAttributeLong(null, ATTR_VALUE);
} else if (TAG_PASSWORD_EXPIRATION_DATE.equals(tag)) {
- passwordExpirationDate = Long.parseLong(
- parser.getAttributeValue(null, ATTR_VALUE));
+ passwordExpirationDate = parser.getAttributeLong(null, ATTR_VALUE);
} else if (TAG_ENCRYPTION_REQUESTED.equals(tag)) {
- encryptionRequested = Boolean.parseBoolean(
- parser.getAttributeValue(null, ATTR_VALUE));
+ encryptionRequested = parser.getAttributeBoolean(null, ATTR_VALUE, false);
} else if (TAG_TEST_ONLY_ADMIN.equals(tag)) {
- testOnlyAdmin = Boolean.parseBoolean(
- parser.getAttributeValue(null, ATTR_VALUE));
+ testOnlyAdmin = parser.getAttributeBoolean(null, ATTR_VALUE, false);
} else if (TAG_DISABLE_CAMERA.equals(tag)) {
- disableCamera = Boolean.parseBoolean(
- parser.getAttributeValue(null, ATTR_VALUE));
+ disableCamera = parser.getAttributeBoolean(null, ATTR_VALUE, false);
} else if (TAG_DISABLE_CALLER_ID.equals(tag)) {
- disableCallerId = Boolean.parseBoolean(
- parser.getAttributeValue(null, ATTR_VALUE));
+ disableCallerId = parser.getAttributeBoolean(null, ATTR_VALUE, false);
} else if (TAG_DISABLE_CONTACTS_SEARCH.equals(tag)) {
- disableContactsSearch = Boolean.parseBoolean(
- parser.getAttributeValue(null, ATTR_VALUE));
+ disableContactsSearch = parser.getAttributeBoolean(null, ATTR_VALUE, false);
} else if (TAG_DISABLE_BLUETOOTH_CONTACT_SHARING.equals(tag)) {
- disableBluetoothContactSharing = Boolean.parseBoolean(parser
- .getAttributeValue(null, ATTR_VALUE));
+ disableBluetoothContactSharing =
+ parser.getAttributeBoolean(null, ATTR_VALUE, false);
} else if (TAG_DISABLE_SCREEN_CAPTURE.equals(tag)) {
- disableScreenCapture = Boolean.parseBoolean(
- parser.getAttributeValue(null, ATTR_VALUE));
+ disableScreenCapture = parser.getAttributeBoolean(null, ATTR_VALUE, false);
} else if (TAG_REQUIRE_AUTO_TIME.equals(tag)) {
- requireAutoTime = Boolean.parseBoolean(
- parser.getAttributeValue(null, ATTR_VALUE));
+ requireAutoTime = parser.getAttributeBoolean(null, ATTR_VALUE, false);
} else if (TAG_FORCE_EPHEMERAL_USERS.equals(tag)) {
- forceEphemeralUsers = Boolean.parseBoolean(
- parser.getAttributeValue(null, ATTR_VALUE));
+ forceEphemeralUsers = parser.getAttributeBoolean(null, ATTR_VALUE, false);
} else if (TAG_IS_NETWORK_LOGGING_ENABLED.equals(tag)) {
- isNetworkLoggingEnabled = Boolean.parseBoolean(
- parser.getAttributeValue(null, ATTR_VALUE));
- lastNetworkLoggingNotificationTimeMs = Long.parseLong(
- parser.getAttributeValue(null, ATTR_LAST_NETWORK_LOGGING_NOTIFICATION));
- numNetworkLoggingNotifications = Integer.parseInt(
- parser.getAttributeValue(null, ATTR_NUM_NETWORK_LOGGING_NOTIFICATIONS));
+ isNetworkLoggingEnabled = parser.getAttributeBoolean(null, ATTR_VALUE, false);
+ lastNetworkLoggingNotificationTimeMs = parser.getAttributeLong(null,
+ ATTR_LAST_NETWORK_LOGGING_NOTIFICATION);
+ numNetworkLoggingNotifications = parser.getAttributeInt(null,
+ ATTR_NUM_NETWORK_LOGGING_NOTIFICATIONS);
} else if (TAG_DISABLE_KEYGUARD_FEATURES.equals(tag)) {
- disabledKeyguardFeatures = Integer.parseInt(
- parser.getAttributeValue(null, ATTR_VALUE));
+ disabledKeyguardFeatures = parser.getAttributeInt(null, ATTR_VALUE);
} else if (TAG_DISABLE_ACCOUNT_MANAGEMENT.equals(tag)) {
readAttributeValues(
parser, TAG_ACCOUNT_TYPE, accountTypesWithManagementDisabled);
@@ -721,7 +695,7 @@ class ActiveAdmin {
parser, TAG_RESTRICTION, defaultEnabledRestrictionsAlreadySet);
} else if (TAG_SHORT_SUPPORT_MESSAGE.equals(tag)) {
type = parser.next();
- if (type == XmlPullParser.TEXT) {
+ if (type == TypedXmlPullParser.TEXT) {
shortSupportMessage = parser.getText();
} else {
Log.w(DevicePolicyManagerService.LOG_TAG,
@@ -729,7 +703,7 @@ class ActiveAdmin {
}
} else if (TAG_LONG_SUPPORT_MESSAGE.equals(tag)) {
type = parser.next();
- if (type == XmlPullParser.TEXT) {
+ if (type == TypedXmlPullParser.TEXT) {
longSupportMessage = parser.getText();
} else {
Log.w(DevicePolicyManagerService.LOG_TAG,
@@ -740,22 +714,20 @@ class ActiveAdmin {
parentAdmin = new ActiveAdmin(info, /* parent */ true);
parentAdmin.readFromXml(parser, shouldOverridePolicies);
} else if (TAG_ORGANIZATION_COLOR.equals(tag)) {
- organizationColor = Integer.parseInt(
- parser.getAttributeValue(null, ATTR_VALUE));
+ organizationColor = parser.getAttributeInt(null, ATTR_VALUE);
} else if (TAG_ORGANIZATION_NAME.equals(tag)) {
type = parser.next();
- if (type == XmlPullParser.TEXT) {
+ if (type == TypedXmlPullParser.TEXT) {
organizationName = parser.getText();
} else {
Log.w(DevicePolicyManagerService.LOG_TAG,
"Missing text when loading organization name");
}
} else if (TAG_IS_LOGOUT_ENABLED.equals(tag)) {
- isLogoutEnabled = Boolean.parseBoolean(
- parser.getAttributeValue(null, ATTR_VALUE));
+ isLogoutEnabled = parser.getAttributeBoolean(null, ATTR_VALUE, false);
} else if (TAG_START_USER_SESSION_MESSAGE.equals(tag)) {
type = parser.next();
- if (type == XmlPullParser.TEXT) {
+ if (type == TypedXmlPullParser.TEXT) {
startUserSessionMessage = parser.getText();
} else {
Log.w(DevicePolicyManagerService.LOG_TAG,
@@ -763,7 +735,7 @@ class ActiveAdmin {
}
} else if (TAG_END_USER_SESSION_MESSAGE.equals(tag)) {
type = parser.next();
- if (type == XmlPullParser.TEXT) {
+ if (type == TypedXmlPullParser.TEXT) {
endUserSessionMessage = parser.getText();
} else {
Log.w(DevicePolicyManagerService.LOG_TAG,
@@ -779,24 +751,21 @@ class ActiveAdmin {
mFactoryResetProtectionPolicy = FactoryResetProtectionPolicy.readFromXml(
parser);
} else if (TAG_SUSPEND_PERSONAL_APPS.equals(tag)) {
- mSuspendPersonalApps = Boolean.parseBoolean(
- parser.getAttributeValue(null, ATTR_VALUE));
+ mSuspendPersonalApps = parser.getAttributeBoolean(null, ATTR_VALUE, false);
} else if (TAG_PROFILE_MAXIMUM_TIME_OFF.equals(tag)) {
mProfileMaximumTimeOffMillis =
- Long.parseLong(parser.getAttributeValue(null, ATTR_VALUE));
+ parser.getAttributeLong(null, ATTR_VALUE);
} else if (TAG_PROFILE_OFF_DEADLINE.equals(tag)) {
mProfileOffDeadline =
- Long.parseLong(parser.getAttributeValue(null, ATTR_VALUE));
+ parser.getAttributeLong(null, ATTR_VALUE);
} else if (TAG_ALWAYS_ON_VPN_PACKAGE.equals(tag)) {
mAlwaysOnVpnPackage = parser.getAttributeValue(null, ATTR_VALUE);
} else if (TAG_ALWAYS_ON_VPN_LOCKDOWN.equals(tag)) {
- mAlwaysOnVpnLockdown = Boolean.parseBoolean(
- parser.getAttributeValue(null, ATTR_VALUE));
+ mAlwaysOnVpnLockdown = parser.getAttributeBoolean(null, ATTR_VALUE, false);
} else if (TAG_COMMON_CRITERIA_MODE.equals(tag)) {
- mCommonCriteriaMode = Boolean.parseBoolean(
- parser.getAttributeValue(null, ATTR_VALUE));
+ mCommonCriteriaMode = parser.getAttributeBoolean(null, ATTR_VALUE, false);
} else if (TAG_PASSWORD_COMPLEXITY.equals(tag)) {
- mPasswordComplexity = Integer.parseInt(parser.getAttributeValue(null, ATTR_VALUE));
+ mPasswordComplexity = parser.getAttributeInt(null, ATTR_VALUE);
} else {
Slog.w(DevicePolicyManagerService.LOG_TAG, "Unknown admin tag: " + tag);
XmlUtils.skipCurrentTag(parser);
@@ -804,14 +773,14 @@ class ActiveAdmin {
}
}
- private List<String> readPackageList(XmlPullParser parser,
+ private List<String> readPackageList(TypedXmlPullParser parser,
String tag) throws XmlPullParserException, IOException {
List<String> result = new ArrayList<String>();
int outerDepth = parser.getDepth();
int outerType;
- while ((outerType = parser.next()) != XmlPullParser.END_DOCUMENT
- && (outerType != XmlPullParser.END_TAG || parser.getDepth() > outerDepth)) {
- if (outerType == XmlPullParser.END_TAG || outerType == XmlPullParser.TEXT) {
+ while ((outerType = parser.next()) != TypedXmlPullParser.END_DOCUMENT
+ && (outerType != TypedXmlPullParser.END_TAG || parser.getDepth() > outerDepth)) {
+ if (outerType == TypedXmlPullParser.END_TAG || outerType == TypedXmlPullParser.TEXT) {
continue;
}
String outerTag = parser.getName();
@@ -832,7 +801,7 @@ class ActiveAdmin {
}
private void readAttributeValues(
- XmlPullParser parser, String tag, Collection<String> result)
+ TypedXmlPullParser parser, String tag, Collection<String> result)
throws XmlPullParserException, IOException {
result.clear();
int outerDepthDAM = parser.getDepth();
@@ -854,7 +823,7 @@ class ActiveAdmin {
@NonNull
private ArrayMap<String, TrustAgentInfo> getAllTrustAgentInfos(
- XmlPullParser parser, String tag) throws XmlPullParserException, IOException {
+ TypedXmlPullParser parser, String tag) throws XmlPullParserException, IOException {
int outerDepthDAM = parser.getDepth();
int typeDAM;
final ArrayMap<String, TrustAgentInfo> result = new ArrayMap<>();
@@ -876,7 +845,7 @@ class ActiveAdmin {
return result;
}
- private TrustAgentInfo getTrustAgentInfo(XmlPullParser parser, String tag)
+ private TrustAgentInfo getTrustAgentInfo(TypedXmlPullParser parser, String tag)
throws XmlPullParserException, IOException {
int outerDepthDAM = parser.getDepth();
int typeDAM;
diff --git a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyData.java b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyData.java
index 8a585ec62d00..31ba1991ee72 100644
--- a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyData.java
+++ b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyData.java
@@ -170,24 +170,19 @@ class DevicePolicyData {
}
if (policyData.mUserSetupComplete) {
if (VERBOSE_LOG) Slog.v(TAG, "setting " + ATTR_SETUP_COMPLETE + " to true");
- out.attribute(null, ATTR_SETUP_COMPLETE,
- Boolean.toString(true));
+ out.attributeBoolean(null, ATTR_SETUP_COMPLETE, true);
}
if (policyData.mPaired) {
- out.attribute(null, ATTR_DEVICE_PAIRED,
- Boolean.toString(true));
+ out.attributeBoolean(null, ATTR_DEVICE_PAIRED, true);
}
if (policyData.mDeviceProvisioningConfigApplied) {
- out.attribute(null, ATTR_DEVICE_PROVISIONING_CONFIG_APPLIED,
- Boolean.toString(true));
+ out.attributeBoolean(null, ATTR_DEVICE_PROVISIONING_CONFIG_APPLIED, true);
}
if (policyData.mUserProvisioningState != DevicePolicyManager.STATE_USER_UNMANAGED) {
- out.attribute(null, ATTR_PROVISIONING_STATE,
- Integer.toString(policyData.mUserProvisioningState));
+ out.attributeInt(null, ATTR_PROVISIONING_STATE, policyData.mUserProvisioningState);
}
if (policyData.mPermissionPolicy != DevicePolicyManager.PERMISSION_POLICY_PROMPT) {
- out.attribute(null, ATTR_PERMISSION_POLICY,
- Integer.toString(policyData.mPermissionPolicy));
+ out.attributeInt(null, ATTR_PERMISSION_POLICY, policyData.mPermissionPolicy);
}
// Serialize delegations.
@@ -217,13 +212,13 @@ class DevicePolicyData {
if (policyData.mPasswordOwner >= 0) {
out.startTag(null, "password-owner");
- out.attribute(null, "value", Integer.toString(policyData.mPasswordOwner));
+ out.attributeInt(null, "value", policyData.mPasswordOwner);
out.endTag(null, "password-owner");
}
if (policyData.mFailedPasswordAttempts != 0) {
out.startTag(null, "failed-password-attempts");
- out.attribute(null, "value", Integer.toString(policyData.mFailedPasswordAttempts));
+ out.attributeInt(null, "value", policyData.mFailedPasswordAttempts);
out.endTag(null, "failed-password-attempts");
}
@@ -232,8 +227,7 @@ class DevicePolicyData {
// security reasons, we don't want to store the full set of active password metrics.
if (isFdeDevice) {
out.startTag(null, TAG_PASSWORD_VALIDITY);
- out.attribute(null, ATTR_VALUE,
- Boolean.toString(policyData.mPasswordValidAtLastCheckpoint));
+ out.attributeBoolean(null, ATTR_VALUE, policyData.mPasswordValidAtLastCheckpoint);
out.endTag(null, TAG_PASSWORD_VALIDITY);
}
@@ -252,19 +246,19 @@ class DevicePolicyData {
if (policyData.mLockTaskFeatures != DevicePolicyManager.LOCK_TASK_FEATURE_NONE) {
out.startTag(null, TAG_LOCK_TASK_FEATURES);
- out.attribute(null, ATTR_VALUE, Integer.toString(policyData.mLockTaskFeatures));
+ out.attributeInt(null, ATTR_VALUE, policyData.mLockTaskFeatures);
out.endTag(null, TAG_LOCK_TASK_FEATURES);
}
if (policyData.mSecondaryLockscreenEnabled) {
out.startTag(null, TAG_SECONDARY_LOCK_SCREEN);
- out.attribute(null, ATTR_VALUE, Boolean.toString(true));
+ out.attributeBoolean(null, ATTR_VALUE, true);
out.endTag(null, TAG_SECONDARY_LOCK_SCREEN);
}
if (policyData.mStatusBarDisabled) {
out.startTag(null, TAG_STATUS_BAR);
- out.attribute(null, ATTR_DISABLED, Boolean.toString(policyData.mStatusBarDisabled));
+ out.attributeBoolean(null, ATTR_DISABLED, policyData.mStatusBarDisabled);
out.endTag(null, TAG_STATUS_BAR);
}
@@ -281,29 +275,25 @@ class DevicePolicyData {
if (policyData.mLastSecurityLogRetrievalTime >= 0) {
out.startTag(null, TAG_LAST_SECURITY_LOG_RETRIEVAL);
- out.attribute(null, ATTR_VALUE,
- Long.toString(policyData.mLastSecurityLogRetrievalTime));
+ out.attributeLong(null, ATTR_VALUE, policyData.mLastSecurityLogRetrievalTime);
out.endTag(null, TAG_LAST_SECURITY_LOG_RETRIEVAL);
}
if (policyData.mLastBugReportRequestTime >= 0) {
out.startTag(null, TAG_LAST_BUG_REPORT_REQUEST);
- out.attribute(null, ATTR_VALUE,
- Long.toString(policyData.mLastBugReportRequestTime));
+ out.attributeLong(null, ATTR_VALUE, policyData.mLastBugReportRequestTime);
out.endTag(null, TAG_LAST_BUG_REPORT_REQUEST);
}
if (policyData.mLastNetworkLogsRetrievalTime >= 0) {
out.startTag(null, TAG_LAST_NETWORK_LOG_RETRIEVAL);
- out.attribute(null, ATTR_VALUE,
- Long.toString(policyData.mLastNetworkLogsRetrievalTime));
+ out.attributeLong(null, ATTR_VALUE, policyData.mLastNetworkLogsRetrievalTime);
out.endTag(null, TAG_LAST_NETWORK_LOG_RETRIEVAL);
}
if (policyData.mAdminBroadcastPending) {
out.startTag(null, TAG_ADMIN_BROADCAST_PENDING);
- out.attribute(null, ATTR_VALUE,
- Boolean.toString(policyData.mAdminBroadcastPending));
+ out.attributeBoolean(null, ATTR_VALUE, policyData.mAdminBroadcastPending);
out.endTag(null, TAG_ADMIN_BROADCAST_PENDING);
}
@@ -315,8 +305,7 @@ class DevicePolicyData {
if (policyData.mPasswordTokenHandle != 0) {
out.startTag(null, TAG_PASSWORD_TOKEN_HANDLE);
- out.attribute(null, ATTR_VALUE,
- Long.toString(policyData.mPasswordTokenHandle));
+ out.attributeLong(null, ATTR_VALUE, policyData.mPasswordTokenHandle);
out.endTag(null, TAG_PASSWORD_TOKEN_HANDLE);
}
@@ -340,7 +329,7 @@ class DevicePolicyData {
if (policyData.mAppsSuspended) {
out.startTag(null, TAG_APPS_SUSPENDED);
- out.attribute(null, ATTR_VALUE, Boolean.toString(policyData.mAppsSuspended));
+ out.attributeBoolean(null, ATTR_VALUE, policyData.mAppsSuspended);
out.endTag(null, TAG_APPS_SUSPENDED);
}
@@ -413,13 +402,13 @@ class DevicePolicyData {
if (Boolean.toString(true).equals(deviceProvisioningConfigApplied)) {
policy.mDeviceProvisioningConfigApplied = true;
}
- String provisioningState = parser.getAttributeValue(null, ATTR_PROVISIONING_STATE);
- if (!TextUtils.isEmpty(provisioningState)) {
- policy.mUserProvisioningState = Integer.parseInt(provisioningState);
+ int provisioningState = parser.getAttributeInt(null, ATTR_PROVISIONING_STATE, -1);
+ if (provisioningState != -1) {
+ policy.mUserProvisioningState = provisioningState;
}
- String permissionPolicy = parser.getAttributeValue(null, ATTR_PERMISSION_POLICY);
- if (!TextUtils.isEmpty(permissionPolicy)) {
- policy.mPermissionPolicy = Integer.parseInt(permissionPolicy);
+ int permissionPolicy = parser.getAttributeInt(null, ATTR_PERMISSION_POLICY, -1);
+ if (permissionPolicy != -1) {
+ policy.mPermissionPolicy = permissionPolicy;
}
parser.next();
@@ -472,37 +461,34 @@ class DevicePolicyData {
scopes.add(scope);
}
} else if ("failed-password-attempts".equals(tag)) {
- policy.mFailedPasswordAttempts = Integer.parseInt(
- parser.getAttributeValue(null, "value"));
+ policy.mFailedPasswordAttempts = parser.getAttributeInt(null, "value");
} else if ("password-owner".equals(tag)) {
- policy.mPasswordOwner = Integer.parseInt(
- parser.getAttributeValue(null, "value"));
+ policy.mPasswordOwner = parser.getAttributeInt(null, "value");
} else if (TAG_ACCEPTED_CA_CERTIFICATES.equals(tag)) {
policy.mAcceptedCaCertificates.add(parser.getAttributeValue(null, ATTR_NAME));
} else if (TAG_LOCK_TASK_COMPONENTS.equals(tag)) {
policy.mLockTaskPackages.add(parser.getAttributeValue(null, "name"));
} else if (TAG_LOCK_TASK_FEATURES.equals(tag)) {
- policy.mLockTaskFeatures = Integer.parseInt(
- parser.getAttributeValue(null, ATTR_VALUE));
+ policy.mLockTaskFeatures = parser.getAttributeInt(null, ATTR_VALUE);
} else if (TAG_SECONDARY_LOCK_SCREEN.equals(tag)) {
- policy.mSecondaryLockscreenEnabled = Boolean.parseBoolean(
- parser.getAttributeValue(null, ATTR_VALUE));
+ policy.mSecondaryLockscreenEnabled =
+ parser.getAttributeBoolean(null, ATTR_VALUE, false);
} else if (TAG_STATUS_BAR.equals(tag)) {
- policy.mStatusBarDisabled = Boolean.parseBoolean(
- parser.getAttributeValue(null, ATTR_DISABLED));
+ policy.mStatusBarDisabled =
+ parser.getAttributeBoolean(null, ATTR_DISABLED, false);
} else if (TAG_DO_NOT_ASK_CREDENTIALS_ON_BOOT.equals(tag)) {
policy.mDoNotAskCredentialsOnBoot = true;
} else if (TAG_AFFILIATION_ID.equals(tag)) {
policy.mAffiliationIds.add(parser.getAttributeValue(null, ATTR_ID));
} else if (TAG_LAST_SECURITY_LOG_RETRIEVAL.equals(tag)) {
- policy.mLastSecurityLogRetrievalTime = Long.parseLong(
- parser.getAttributeValue(null, ATTR_VALUE));
+ policy.mLastSecurityLogRetrievalTime =
+ parser.getAttributeLong(null, ATTR_VALUE);
} else if (TAG_LAST_BUG_REPORT_REQUEST.equals(tag)) {
- policy.mLastBugReportRequestTime = Long.parseLong(
- parser.getAttributeValue(null, ATTR_VALUE));
+ policy.mLastBugReportRequestTime =
+ parser.getAttributeLong(null, ATTR_VALUE);
} else if (TAG_LAST_NETWORK_LOG_RETRIEVAL.equals(tag)) {
- policy.mLastNetworkLogsRetrievalTime = Long.parseLong(
- parser.getAttributeValue(null, ATTR_VALUE));
+ policy.mLastNetworkLogsRetrievalTime =
+ parser.getAttributeLong(null, ATTR_VALUE);
} else if (TAG_ADMIN_BROADCAST_PENDING.equals(tag)) {
String pending = parser.getAttributeValue(null, ATTR_VALUE);
policy.mAdminBroadcastPending = Boolean.toString(true).equals(pending);
@@ -515,12 +501,11 @@ class DevicePolicyData {
} else if (TAG_PASSWORD_VALIDITY.equals(tag)) {
if (isFdeDevice) {
// This flag is only used for FDE devices
- policy.mPasswordValidAtLastCheckpoint = Boolean.parseBoolean(
- parser.getAttributeValue(null, ATTR_VALUE));
+ policy.mPasswordValidAtLastCheckpoint =
+ parser.getAttributeBoolean(null, ATTR_VALUE, false);
}
} else if (TAG_PASSWORD_TOKEN_HANDLE.equals(tag)) {
- policy.mPasswordTokenHandle = Long.parseLong(
- parser.getAttributeValue(null, ATTR_VALUE));
+ policy.mPasswordTokenHandle = parser.getAttributeLong(null, ATTR_VALUE);
} else if (TAG_CURRENT_INPUT_METHOD_SET.equals(tag)) {
policy.mCurrentInputMethodSet = true;
} else if (TAG_OWNER_INSTALLED_CA_CERT.equals(tag)) {
@@ -530,7 +515,7 @@ class DevicePolicyData {
parser.getAttributeValue(null, ATTR_NAME));
} else if (TAG_APPS_SUSPENDED.equals(tag)) {
policy.mAppsSuspended =
- Boolean.parseBoolean(parser.getAttributeValue(null, ATTR_VALUE));
+ parser.getAttributeBoolean(null, ATTR_VALUE, false);
} else {
Slog.w(TAG, "Unknown tag: " + tag);
XmlUtils.skipCurrentTag(parser);
diff --git a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
index 98bb52963725..6f22f1139ba9 100644
--- a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
+++ b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
@@ -983,17 +983,29 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager {
@Override
public void setDevicePolicySafetyChecker(DevicePolicySafetyChecker safetyChecker) {
- Slog.i(LOG_TAG, "Setting DevicePolicySafetyChecker as " + safetyChecker.getClass());
+ Slog.i(LOG_TAG, "Setting DevicePolicySafetyChecker as " + safetyChecker);
mSafetyChecker = safetyChecker;
}
/**
+ * Used by {@link OneTimeSafetyChecker} only.
+ */
+ DevicePolicySafetyChecker getDevicePolicySafetyChecker() {
+ return mSafetyChecker;
+ }
+
+ /**
* Checks if it's safe to execute the given {@code operation}.
*
* @throws UnsafeStateException if it's not safe to execute the operation.
*/
private void checkCanExecuteOrThrowUnsafe(@DevicePolicyOperation int operation) {
if (!canExecute(operation)) {
+ if (mSafetyChecker == null) {
+ // Happens on CTS after it's set just once (by OneTimeSafetyChecker)
+ throw new UnsafeStateException(operation);
+ }
+ // Let mSafetyChecker customize it (for example, by explaining how to retry)
throw mSafetyChecker.newUnsafeStateException(operation);
}
}
@@ -1006,6 +1018,17 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager {
}
/**
+ * Used by {@code cmd device_policy} to set the result of the next safety operation check.
+ */
+ void setNextOperationSafety(@DevicePolicyOperation int operation, boolean safe) {
+ Preconditions.checkCallAuthorization(
+ hasCallingOrSelfPermission(permission.MANAGE_DEVICE_ADMINS));
+ Slog.i(LOG_TAG, "setNextOperationSafety(" + DevicePolicyManager.operationToString(operation)
+ + ", " + safe + ")");
+ mSafetyChecker = new OneTimeSafetyChecker(this, operation, safe);
+ }
+
+ /**
* Unit test will subclass it to inject mocks.
*/
@VisibleForTesting
diff --git a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerServiceShellCommand.java b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerServiceShellCommand.java
index 0b0aee9afa6d..22866b45911d 100644
--- a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerServiceShellCommand.java
+++ b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerServiceShellCommand.java
@@ -24,6 +24,7 @@ import java.util.Objects;
final class DevicePolicyManagerServiceShellCommand extends ShellCommand {
private static final String CMD_IS_SAFE_OPERATION = "is-operation-safe";
+ private static final String CMD_SET_SAFE_OPERATION = "set-operation-safe";
private final DevicePolicyManagerService mService;
@@ -48,6 +49,8 @@ final class DevicePolicyManagerServiceShellCommand extends ShellCommand {
switch (cmd) {
case CMD_IS_SAFE_OPERATION:
return runIsSafeOperation(pw);
+ case CMD_SET_SAFE_OPERATION:
+ return runSetSafeOperation(pw);
default:
return onInvalidCommand(pw, cmd);
}
@@ -70,6 +73,9 @@ final class DevicePolicyManagerServiceShellCommand extends ShellCommand {
pw.printf(" Prints this help text.\n\n");
pw.printf(" %s <OPERATION_ID>\n", CMD_IS_SAFE_OPERATION);
pw.printf(" Checks if the give operation is safe \n\n");
+ pw.printf(" %s <OPERATION_ID> <true|false>\n", CMD_SET_SAFE_OPERATION);
+ pw.printf(" Emulates the result of the next call to check if the given operation is safe"
+ + " \n\n");
}
private int runIsSafeOperation(PrintWriter pw) {
@@ -79,4 +85,13 @@ final class DevicePolicyManagerServiceShellCommand extends ShellCommand {
safe ? "SAFE" : "UNSAFE");
return 0;
}
+
+ private int runSetSafeOperation(PrintWriter pw) {
+ int operation = Integer.parseInt(getNextArgRequired());
+ boolean safe = getNextArg().equals("true");
+ mService.setNextOperationSafety(operation, safe);
+ pw.printf("Next call to check operation %s will return %s\n",
+ DevicePolicyManager.operationToString(operation), safe ? "SAFE" : "UNSAFE");
+ return 0;
+ }
}
diff --git a/services/devicepolicy/java/com/android/server/devicepolicy/OneTimeSafetyChecker.java b/services/devicepolicy/java/com/android/server/devicepolicy/OneTimeSafetyChecker.java
new file mode 100644
index 000000000000..b0f8bfb713ab
--- /dev/null
+++ b/services/devicepolicy/java/com/android/server/devicepolicy/OneTimeSafetyChecker.java
@@ -0,0 +1,67 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.android.server.devicepolicy;
+
+import static android.app.admin.DevicePolicyManager.operationToString;
+
+import android.app.admin.DevicePolicyManager.DevicePolicyOperation;
+import android.app.admin.DevicePolicySafetyChecker;
+import android.util.Slog;
+
+import java.util.Objects;
+
+//TODO(b/172376923): add unit tests
+
+/**
+ * {@code DevicePolicySafetyChecker} implementation that overrides the real checker for just
+ * one command.
+ *
+ * <p>Used only for debugging and CTS tests.
+ */
+final class OneTimeSafetyChecker implements DevicePolicySafetyChecker {
+
+ private static final String TAG = OneTimeSafetyChecker.class.getSimpleName();
+
+ private final DevicePolicyManagerService mService;
+ private final DevicePolicySafetyChecker mRealSafetyChecker;
+ private final @DevicePolicyOperation int mOperation;
+ private final boolean mSafe;
+
+ OneTimeSafetyChecker(DevicePolicyManagerService service,
+ @DevicePolicyOperation int operation, boolean safe) {
+ mService = Objects.requireNonNull(service);
+ mOperation = operation;
+ mSafe = safe;
+ mRealSafetyChecker = service.getDevicePolicySafetyChecker();
+ Slog.i(TAG, "Saving real DevicePolicySafetyChecker as " + mRealSafetyChecker);
+ }
+
+ @Override
+ public boolean isDevicePolicyOperationSafe(@DevicePolicyOperation int operation) {
+ String name = operationToString(operation);
+ boolean safe = true;
+ if (operation == mOperation) {
+ safe = mSafe;
+ } else {
+ Slog.wtf(TAG, "invalid call to isDevicePolicyOperationSafe(): asked for " + name
+ + ", should be " + operationToString(mOperation));
+ }
+ Slog.i(TAG, "isDevicePolicyOperationSafe(" + name + "): returning " + safe
+ + " and restoring DevicePolicySafetyChecker to " + mRealSafetyChecker);
+ mService.setDevicePolicySafetyChecker(mRealSafetyChecker);
+ return safe;
+ }
+}
diff --git a/services/devicepolicy/java/com/android/server/devicepolicy/Owners.java b/services/devicepolicy/java/com/android/server/devicepolicy/Owners.java
index 8ef69822750f..79a82b8e7175 100644
--- a/services/devicepolicy/java/com/android/server/devicepolicy/Owners.java
+++ b/services/devicepolicy/java/com/android/server/devicepolicy/Owners.java
@@ -43,22 +43,18 @@ import android.util.TypedXmlSerializer;
import android.util.Xml;
import com.android.internal.annotations.VisibleForTesting;
-import com.android.internal.util.FastXmlSerializer;
import com.android.server.LocalServices;
import com.android.server.pm.UserManagerInternal;
import com.android.server.wm.ActivityTaskManagerInternal;
import libcore.io.IoUtils;
-import org.xmlpull.v1.XmlPullParser;
import org.xmlpull.v1.XmlPullParserException;
-import org.xmlpull.v1.XmlSerializer;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
-import java.nio.charset.StandardCharsets;
import java.time.LocalDate;
import java.util.List;
import java.util.Map;
@@ -558,11 +554,10 @@ class Owners {
}
try {
InputStream input = new AtomicFile(file).openRead();
- XmlPullParser parser = Xml.newPullParser();
- parser.setInput(input, StandardCharsets.UTF_8.name());
+ TypedXmlPullParser parser = Xml.resolvePullParser(input);
int type;
- while ((type=parser.next()) != XmlPullParser.END_DOCUMENT) {
- if (type!=XmlPullParser.START_TAG) {
+ while ((type=parser.next()) != TypedXmlPullParser.END_DOCUMENT) {
+ if (type!=TypedXmlPullParser.START_TAG) {
continue;
}
@@ -581,7 +576,7 @@ class Owners {
String profileOwnerName = parser.getAttributeValue(null, ATTR_NAME);
String profileOwnerComponentStr =
parser.getAttributeValue(null, ATTR_COMPONENT_NAME);
- int userId = Integer.parseInt(parser.getAttributeValue(null, ATTR_USERID));
+ int userId = parser.getAttributeInt(null, ATTR_USERID);
OwnerInfo profileOwnerInfo = null;
if (profileOwnerComponentStr != null) {
ComponentName admin = ComponentName.unflattenFromString(
@@ -781,12 +776,12 @@ class Owners {
int type;
int depth = 0;
- while ((type = parser.next()) != XmlPullParser.END_DOCUMENT) {
+ while ((type = parser.next()) != TypedXmlPullParser.END_DOCUMENT) {
switch (type) {
- case XmlPullParser.START_TAG:
+ case TypedXmlPullParser.START_TAG:
depth++;
break;
- case XmlPullParser.END_TAG:
+ case TypedXmlPullParser.END_TAG:
depth--;
// fallthrough
default:
@@ -813,9 +808,9 @@ class Owners {
}
}
- abstract void writeInner(XmlSerializer out) throws IOException;
+ abstract void writeInner(TypedXmlSerializer out) throws IOException;
- abstract boolean readInner(XmlPullParser parser, int depth, String tag);
+ abstract boolean readInner(TypedXmlPullParser parser, int depth, String tag);
}
private class DeviceOwnerReadWriter extends FileReadWriter {
@@ -831,11 +826,11 @@ class Owners {
}
@Override
- void writeInner(XmlSerializer out) throws IOException {
+ void writeInner(TypedXmlSerializer out) throws IOException {
if (mDeviceOwner != null) {
mDeviceOwner.writeToXml(out, TAG_DEVICE_OWNER);
out.startTag(null, TAG_DEVICE_OWNER_CONTEXT);
- out.attribute(null, ATTR_USERID, String.valueOf(mDeviceOwnerUserId));
+ out.attributeInt(null, ATTR_USERID, mDeviceOwnerUserId);
out.endTag(null, TAG_DEVICE_OWNER_CONTEXT);
}
@@ -863,7 +858,7 @@ class Owners {
}
@Override
- boolean readInner(XmlPullParser parser, int depth, String tag) {
+ boolean readInner(TypedXmlPullParser parser, int depth, String tag) {
if (depth > 2) {
return true; // Ignore
}
@@ -873,13 +868,8 @@ class Owners {
mDeviceOwnerUserId = UserHandle.USER_SYSTEM; // Set default
break;
case TAG_DEVICE_OWNER_CONTEXT: {
- final String userIdString =
- parser.getAttributeValue(null, ATTR_USERID);
- try {
- mDeviceOwnerUserId = Integer.parseInt(userIdString);
- } catch (NumberFormatException e) {
- Slog.e(TAG, "Error parsing user-id " + userIdString);
- }
+ mDeviceOwnerUserId = parser.getAttributeInt(null, ATTR_USERID,
+ mDeviceOwnerUserId);
break;
}
case TAG_DEVICE_INITIALIZER:
@@ -927,7 +917,7 @@ class Owners {
}
@Override
- void writeInner(XmlSerializer out) throws IOException {
+ void writeInner(TypedXmlSerializer out) throws IOException {
final OwnerInfo profileOwner = mProfileOwners.get(mUserId);
if (profileOwner != null) {
profileOwner.writeToXml(out, TAG_PROFILE_OWNER);
@@ -935,7 +925,7 @@ class Owners {
}
@Override
- boolean readInner(XmlPullParser parser, int depth, String tag) {
+ boolean readInner(TypedXmlPullParser parser, int depth, String tag) {
if (depth > 2) {
return true; // Ignore
}
@@ -985,7 +975,7 @@ class Owners {
this.isOrganizationOwnedDevice = isOrganizationOwnedDevice;
}
- public void writeToXml(XmlSerializer out, String tag) throws IOException {
+ public void writeToXml(TypedXmlSerializer out, String tag) throws IOException {
out.startTag(null, tag);
out.attribute(null, ATTR_PACKAGE, packageName);
if (name != null) {
@@ -994,8 +984,7 @@ class Owners {
if (admin != null) {
out.attribute(null, ATTR_COMPONENT_NAME, admin.flattenToString());
}
- out.attribute(null, ATTR_USER_RESTRICTIONS_MIGRATED,
- String.valueOf(userRestrictionsMigrated));
+ out.attributeBoolean(null, ATTR_USER_RESTRICTIONS_MIGRATED, userRestrictionsMigrated);
if (remoteBugreportUri != null) {
out.attribute(null, ATTR_REMOTE_BUGREPORT_URI, remoteBugreportUri);
}
@@ -1003,13 +992,13 @@ class Owners {
out.attribute(null, ATTR_REMOTE_BUGREPORT_HASH, remoteBugreportHash);
}
if (isOrganizationOwnedDevice) {
- out.attribute(null, ATTR_PROFILE_OWNER_OF_ORG_OWNED_DEVICE,
- String.valueOf(isOrganizationOwnedDevice));
+ out.attributeBoolean(null, ATTR_PROFILE_OWNER_OF_ORG_OWNED_DEVICE,
+ isOrganizationOwnedDevice);
}
out.endTag(null, tag);
}
- public static OwnerInfo readFromXml(XmlPullParser parser) {
+ public static OwnerInfo readFromXml(TypedXmlPullParser parser) {
final String packageName = parser.getAttributeValue(null, ATTR_PACKAGE);
final String name = parser.getAttributeValue(null, ATTR_NAME);
final String componentName =
diff --git a/services/devicepolicy/java/com/android/server/devicepolicy/TransferOwnershipMetadataManager.java b/services/devicepolicy/java/com/android/server/devicepolicy/TransferOwnershipMetadataManager.java
index 58ece0748d8b..289ed364e2a3 100644
--- a/services/devicepolicy/java/com/android/server/devicepolicy/TransferOwnershipMetadataManager.java
+++ b/services/devicepolicy/java/com/android/server/devicepolicy/TransferOwnershipMetadataManager.java
@@ -29,18 +29,15 @@ import android.util.TypedXmlSerializer;
import android.util.Xml;
import com.android.internal.annotations.VisibleForTesting;
-import com.android.internal.util.FastXmlSerializer;
import com.android.internal.util.Preconditions;
import org.xmlpull.v1.XmlPullParser;
import org.xmlpull.v1.XmlPullParserException;
-import org.xmlpull.v1.XmlSerializer;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
-import java.nio.charset.StandardCharsets;
import java.util.Objects;
/**
@@ -106,7 +103,7 @@ class TransferOwnershipMetadataManager {
return false;
}
- private void insertSimpleTag(XmlSerializer serializer, String tagName, String value)
+ private void insertSimpleTag(TypedXmlSerializer serializer, String tagName, String value)
throws IOException {
serializer.startTag(null, tagName);
serializer.text(value);
@@ -132,7 +129,7 @@ class TransferOwnershipMetadataManager {
return null;
}
- private Metadata parseMetadataFile(XmlPullParser parser)
+ private Metadata parseMetadataFile(TypedXmlPullParser parser)
throws XmlPullParserException, IOException {
int type;
final int outerDepth = parser.getDepth();
diff --git a/services/tests/mockingservicestests/Android.bp b/services/tests/mockingservicestests/Android.bp
index 8fc5c085999e..03083c1f00b2 100644
--- a/services/tests/mockingservicestests/Android.bp
+++ b/services/tests/mockingservicestests/Android.bp
@@ -15,7 +15,7 @@
android_test {
name: "FrameworksMockingServicesTests",
- srcs: ["src/**/*.java"],
+ srcs: ["src/**/*.java", "src/**/*.kt"],
static_libs: [
"services.core",
@@ -29,6 +29,10 @@ android_test {
"mockito-target-extended-minus-junit4",
"platform-test-annotations",
"truth-prebuilt",
+ "hamcrest-library",
+ "servicestests-utils-mockito-extended",
+ "mockingservicestests-utils-mockito",
+ "servicestests-core-utils",
"testables",
// TODO: remove once Android migrates to JUnit 4.12, which provides assertThrows
"testng",
@@ -54,3 +58,17 @@ android_test {
enabled: false,
},
}
+
+java_library {
+ name: "mockingservicestests-utils-mockito",
+ srcs: [
+ "utils-mockito/**/*.kt",
+ ],
+ static_libs: [
+ "junit",
+ "mockito-target-extended-minus-junit4",
+ ],
+ libs: [
+ "android.test.runner",
+ ],
+} \ No newline at end of file
diff --git a/services/tests/mockingservicestests/src/com/android/server/pm/MockSystem.kt b/services/tests/mockingservicestests/src/com/android/server/pm/MockSystem.kt
new file mode 100644
index 000000000000..edae08a3bfe1
--- /dev/null
+++ b/services/tests/mockingservicestests/src/com/android/server/pm/MockSystem.kt
@@ -0,0 +1,662 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.android.server.pm
+
+import android.content.Context
+import android.content.Intent
+import android.content.pm.ActivityInfo
+import android.content.pm.ApplicationInfo
+import android.content.pm.FallbackCategoryProvider
+import android.content.pm.FeatureInfo
+import android.content.pm.PackageParser.SigningDetails
+import android.content.pm.ResolveInfo
+import android.content.pm.ServiceInfo
+import android.content.pm.Signature
+import android.content.pm.UserInfo
+import android.content.pm.parsing.ParsingPackage
+import android.content.pm.parsing.ParsingPackageUtils
+import android.content.res.Resources
+import android.hardware.display.DisplayManager
+import android.os.Build
+import android.os.Environment
+import android.os.SystemProperties
+import android.os.UserHandle
+import android.os.UserManager
+import android.os.incremental.IncrementalManager
+import android.permission.IPermissionManager
+import android.util.ArrayMap
+import android.util.DisplayMetrics
+import android.util.EventLog
+import android.view.Display
+import com.android.dx.mockito.inline.extended.ExtendedMockito
+import com.android.dx.mockito.inline.extended.ExtendedMockito.any
+import com.android.dx.mockito.inline.extended.ExtendedMockito.anyBoolean
+import com.android.dx.mockito.inline.extended.ExtendedMockito.anyInt
+import com.android.dx.mockito.inline.extended.ExtendedMockito.anyString
+import com.android.dx.mockito.inline.extended.ExtendedMockito.argThat
+import com.android.dx.mockito.inline.extended.ExtendedMockito.doReturn
+import com.android.dx.mockito.inline.extended.ExtendedMockito.eq
+import com.android.dx.mockito.inline.extended.ExtendedMockito.spy
+import com.android.dx.mockito.inline.extended.StaticMockitoSession
+import com.android.dx.mockito.inline.extended.StaticMockitoSessionBuilder
+import com.android.internal.R
+import com.android.server.LocalServices
+import com.android.server.LockGuard
+import com.android.server.SystemConfig
+import com.android.server.SystemServerInitThreadPool
+import com.android.server.compat.PlatformCompat
+import com.android.server.extendedtestutils.wheneverStatic
+import com.android.server.pm.dex.DexManager
+import com.android.server.pm.parsing.PackageParser2
+import com.android.server.pm.parsing.pkg.AndroidPackage
+import com.android.server.pm.parsing.pkg.PackageImpl
+import com.android.server.pm.parsing.pkg.ParsedPackage
+import com.android.server.pm.permission.PermissionManagerServiceInternal
+import com.android.server.testutils.mock
+import com.android.server.testutils.nullable
+import com.android.server.testutils.whenever
+import org.junit.Assert
+import org.junit.rules.TestRule
+import org.junit.runner.Description
+import org.junit.runners.model.Statement
+import org.mockito.AdditionalMatchers.or
+import org.mockito.invocation.InvocationOnMock
+import org.mockito.quality.Strictness
+import java.io.File
+import java.io.IOException
+import java.nio.file.Files
+import java.security.PublicKey
+import java.security.cert.CertificateException
+import java.util.Arrays
+import java.util.Random
+import java.util.concurrent.FutureTask
+
+/**
+ * A utility for mocking behavior of the system and dependencies when testing PackageManagerService
+ *
+ * Create one of these and call [stageNominalSystemState] as a basis for additional behavior in most
+ * tests.
+ */
+class MockSystem(withSession: (StaticMockitoSessionBuilder) -> Unit = {}) {
+ private val random = Random()
+ val mocks = Mocks()
+ val packageCacheDirectory: File =
+ Files.createTempDirectory("packageCache").toFile()
+ val rootDirectory: File =
+ Files.createTempDirectory("root").toFile()
+ val dataAppDirectory: File =
+ File(Files.createTempDirectory("data").toFile(), "app")
+ val frameworkSignature: SigningDetails = SigningDetails(arrayOf(generateSpySignature()), 3)
+ val systemPartitions: List<PackageManagerService.ScanPartition> =
+ redirectScanPartitions(PackageManagerService.SYSTEM_PARTITIONS)
+ val session: StaticMockitoSession
+
+ /** Tracks temporary files created by this class during the running of a test. */
+ private val createdFiles = ArrayList<File>()
+
+ /** Settings that are expected to be added as part of the test */
+ private val mPendingPackageAdds: MutableList<Pair<String, PackageSetting>> = ArrayList()
+
+ /** Settings simulated to be stored on disk */
+ private val mPreExistingSettings = ArrayMap<String, PackageSetting>()
+
+ /** The active map simulating the in memory storage of Settings */
+ private val mSettingsMap = ArrayMap<String, PackageSetting>()
+
+ init {
+ val apply = ExtendedMockito.mockitoSession()
+ .strictness(Strictness.LENIENT)
+ .mockStatic(SystemProperties::class.java)
+ .mockStatic(SystemConfig::class.java)
+ .mockStatic(SELinuxMMAC::class.java)
+ .mockStatic(FallbackCategoryProvider::class.java)
+ .mockStatic(PackageManagerServiceUtils::class.java)
+ .mockStatic(Environment::class.java)
+ .mockStatic(SystemServerInitThreadPool::class.java)
+ .mockStatic(ParsingPackageUtils::class.java)
+ .mockStatic(LockGuard::class.java)
+ .mockStatic(EventLog::class.java)
+ .mockStatic(LocalServices::class.java)
+ .apply(withSession)
+ session = apply.startMocking()
+ whenever(mocks.settings.insertPackageSettingLPw(
+ any(PackageSetting::class.java), any(AndroidPackage::class.java))) {
+ val name: String = (getArgument<Any>(0) as PackageSetting).name
+ val pendingAdd =
+ mPendingPackageAdds.firstOrNull { it.first == name } ?: return@whenever null
+ mPendingPackageAdds.remove(pendingAdd)
+ mSettingsMap[name] = pendingAdd.second
+ null
+ }
+ whenever(mocks.settings.addPackageLPw(nullable(), nullable(), nullable(), nullable(),
+ nullable(), nullable(), nullable(), nullable(), nullable(), nullable(), nullable(),
+ nullable(), nullable(), nullable())) {
+ val name: String = getArgument(0)
+ val pendingAdd = mPendingPackageAdds.firstOrNull { it.first == name }
+ ?: return@whenever null
+ mPendingPackageAdds.remove(pendingAdd)
+ mSettingsMap[name] = pendingAdd.second
+ pendingAdd.second
+ }
+ whenever(mocks.settings.packagesLocked).thenReturn(mSettingsMap)
+ whenever(mocks.settings.getPackageLPr(anyString())) { mSettingsMap[getArgument<Any>(0)] }
+ whenever(mocks.settings.readLPw(nullable())) {
+ mSettingsMap.putAll(mPreExistingSettings)
+ !mPreExistingSettings.isEmpty()
+ }
+ }
+
+ /** Collection of mocks used for PackageManagerService tests. */
+
+ class Mocks {
+ val lock = Any()
+ val installLock = Any()
+ val injector: PackageManagerService.Injector = mock()
+ val systemWrapper: PackageManagerService.SystemWrapper = mock()
+ val context: Context = mock()
+ val userManagerService: UserManagerService = mock()
+ val componentResolver: ComponentResolver = mock()
+ val permissionManagerInternal: PermissionManagerServiceInternal = mock()
+ val incrementalManager: IncrementalManager = mock()
+ val platformCompat: PlatformCompat = mock()
+ val settings: Settings = mock()
+ val resources: Resources = mock()
+ val systemConfig: SystemConfig = mock()
+ val apexManager: ApexManager = mock()
+ val userManagerInternal: UserManagerInternal = mock()
+ val packageParser: PackageParser2 = mock()
+ val keySetManagerService: KeySetManagerService = mock()
+ val packageAbiHelper: PackageAbiHelper = mock()
+ val appsFilter: AppsFilter = mock()
+ val dexManager: DexManager = mock()
+ val installer: Installer = mock()
+ val displayMetrics: DisplayMetrics = mock()
+ val permissionManager: IPermissionManager = mock()
+ }
+
+ companion object {
+ private const val DEVICE_PROVISIONING_PACKAGE_NAME =
+ "com.example.android.device.provisioning"
+ private val DEFAULT_AVAILABLE_FEATURES_MAP = ArrayMap<String, FeatureInfo>()
+ private val DEFAULT_ACTIVE_APEX_INFO_LIST = emptyList<ApexManager.ActiveApexInfo>()
+ private val DEFAULT_SHARED_LIBRARIES_LIST =
+ ArrayMap<String, SystemConfig.SharedLibraryEntry>()
+ private val DEFAULT_USERS = Arrays.asList(
+ UserInfo(UserHandle.USER_SYSTEM, "primary", "",
+ UserInfo.FLAG_PRIMARY or UserInfo.FLAG_SYSTEM or UserInfo.FLAG_FULL,
+ UserManager.USER_TYPE_FULL_SYSTEM))
+ public val DEFAULT_VERSION_INFO = Settings.VersionInfo()
+
+ init {
+ DEFAULT_VERSION_INFO.fingerprint = "abcdef"
+ DEFAULT_VERSION_INFO.sdkVersion = Build.VERSION_CODES.R
+ DEFAULT_VERSION_INFO.databaseVersion = Settings.CURRENT_DATABASE_VERSION
+ }
+ }
+
+ /**
+ * Clean up any potentially dangling state. This should be run at the end of every test to
+ * account for changes to static memory, such as [LocalServices]
+ */
+ fun cleanup() {
+ createdFiles.forEach(File::delete)
+ createdFiles.clear()
+ mSettingsMap.clear()
+ mPendingPackageAdds.clear()
+ mPreExistingSettings.clear()
+ session.finishMocking()
+ }
+
+ /**
+ * Run this method to ensure that all expected actions were executed, such as pending
+ * [Settings] adds.
+ */
+ fun validateFinalState() {
+ if (mPendingPackageAdds.isNotEmpty()) {
+ Assert.fail(
+ "Not all expected settings were added: ${mPendingPackageAdds.map { it.first }}")
+ }
+ }
+
+ /**
+ * This method stages enough of system startup to execute the PackageManagerService constructor
+ * successfullly.
+ */
+ @Throws(Exception::class)
+ fun stageNominalSystemState() {
+ whenever(mocks.injector.context).thenReturn(mocks.context)
+ whenever(mocks.injector.lock).thenReturn(mocks.lock)
+ whenever(mocks.injector.installLock).thenReturn(mocks.installLock)
+ whenever(mocks.injector.systemWrapper).thenReturn(mocks.systemWrapper)
+ whenever(mocks.injector.userManagerService).thenReturn(mocks.userManagerService)
+ whenever(mocks.injector.componentResolver).thenReturn(mocks.componentResolver)
+ whenever(mocks.injector.permissionManagerServiceInternal) {
+ mocks.permissionManagerInternal
+ }
+ whenever(mocks.injector.permissionManagerService).thenReturn(mocks.permissionManager)
+ whenever(mocks.injector.incrementalManager).thenReturn(mocks.incrementalManager)
+ whenever(mocks.injector.compatibility).thenReturn(mocks.platformCompat)
+ whenever(mocks.injector.settings).thenReturn(mocks.settings)
+ whenever(mocks.injector.dexManager).thenReturn(mocks.dexManager)
+ whenever(mocks.injector.systemConfig).thenReturn(mocks.systemConfig)
+ whenever(mocks.injector.apexManager).thenReturn(mocks.apexManager)
+ whenever(mocks.injector.scanningCachingPackageParser).thenReturn(mocks.packageParser)
+ whenever(mocks.injector.scanningPackageParser).thenReturn(mocks.packageParser)
+ whenever(mocks.injector.systemPartitions).thenReturn(systemPartitions)
+ whenever(mocks.injector.appsFilter).thenReturn(mocks.appsFilter)
+ whenever(mocks.injector.abiHelper).thenReturn(mocks.packageAbiHelper)
+ whenever(mocks.injector.userManagerInternal).thenReturn(mocks.userManagerInternal)
+ whenever(mocks.injector.installer).thenReturn(mocks.installer)
+ whenever(mocks.injector.displayMetrics).thenReturn(mocks.displayMetrics)
+ wheneverStatic { SystemConfig.getInstance() }.thenReturn(mocks.systemConfig)
+ whenever(mocks.systemConfig.availableFeatures).thenReturn(DEFAULT_AVAILABLE_FEATURES_MAP)
+ whenever(mocks.systemConfig.sharedLibraries).thenReturn(DEFAULT_SHARED_LIBRARIES_LIST)
+ wheneverStatic { SystemProperties.getBoolean("fw.free_cache_v2", true) }.thenReturn(true)
+ wheneverStatic { Environment.getPackageCacheDirectory() }.thenReturn(packageCacheDirectory)
+ wheneverStatic { SystemProperties.digestOf("ro.build.fingerprint") }.thenReturn("cacheName")
+ wheneverStatic { Environment.getRootDirectory() }.thenReturn(rootDirectory)
+ wheneverStatic { SystemServerInitThreadPool.submit(any(Runnable::class.java), anyString())}
+ .thenAnswer { FutureTask<Any?>(it.getArgument(0), null) }
+
+ wheneverStatic { Environment.getDataDirectory() }.thenReturn(dataAppDirectory.parentFile)
+ wheneverStatic { Environment.getDataSystemDirectory() }
+ .thenReturn(File(dataAppDirectory.parentFile, "system"))
+ whenever(mocks.context.resources).thenReturn(mocks.resources)
+ whenever(mocks.resources.getString(R.string.config_deviceProvisioningPackage)) {
+ DEVICE_PROVISIONING_PACKAGE_NAME
+ }
+ whenever(mocks.apexManager.activeApexInfos).thenReturn(DEFAULT_ACTIVE_APEX_INFO_LIST)
+ whenever(mocks.settings.packagesLocked).thenReturn(mSettingsMap)
+ whenever(mocks.settings.internalVersion).thenReturn(DEFAULT_VERSION_INFO)
+ whenever(mocks.settings.keySetManagerService).thenReturn(mocks.keySetManagerService)
+ whenever(mocks.settings.keySetManagerService).thenReturn(mocks.keySetManagerService)
+ whenever(mocks.packageAbiHelper.derivePackageAbi(
+ any(AndroidPackage::class.java), anyBoolean(), nullable(), any(File::class.java))) {
+ android.util.Pair(PackageAbiHelper.Abis("", ""),
+ PackageAbiHelper.NativeLibraryPaths("", false, "", ""))
+ }
+ whenever(mocks.userManagerInternal.getUsers(true, false, false)).thenReturn(DEFAULT_USERS)
+ whenever(mocks.userManagerService.userIds).thenReturn(intArrayOf(0))
+ whenever(mocks.userManagerService.exists(0)).thenReturn(true)
+ whenever(mocks.packageAbiHelper.deriveNativeLibraryPaths(
+ any(AndroidPackage::class.java), anyBoolean(), any(File::class.java))) {
+ PackageAbiHelper.NativeLibraryPaths("", false, "", "")
+ }
+ // everything visible by default
+ whenever(mocks.appsFilter.shouldFilterApplication(
+ anyInt(), nullable(), nullable(), anyInt())) { false }
+
+ val displayManager: DisplayManager = mock()
+ whenever(mocks.context.getSystemService(DisplayManager::class.java))
+ .thenReturn(displayManager)
+ val display: Display = mock()
+ whenever(displayManager.getDisplay(Display.DEFAULT_DISPLAY)).thenReturn(display)
+
+ stageFrameworkScan()
+ stageInstallerScan()
+ stageServicesExtensionScan()
+ stageSystemSharedLibraryScan()
+ stagePermissionsControllerScan()
+ stageInstantAppResolverScan()
+ }
+
+ /**
+ * This method will stage the parsing and scanning of a package as well as add it to the
+ * [PackageSetting]s read from disk.
+ */
+ @Throws(Exception::class)
+ fun stageScanExistingPackage(
+ packageName: String,
+ versionCode: Long,
+ parent: File?,
+ withPackage: (PackageImpl) -> PackageImpl = { it },
+ withSetting:
+ (PackageSettingBuilder) -> PackageSettingBuilder = { it },
+ withExistingSetting:
+ (PackageSettingBuilder) -> PackageSettingBuilder = { it }
+ ) {
+ val existingSettingBuilderRef = arrayOfNulls<PackageSettingBuilder>(1)
+ stageScanNewPackage(packageName, versionCode, parent, withPackage,
+ withSetting = { settingBuilder ->
+ withSetting(settingBuilder)
+ existingSettingBuilderRef[0] = settingBuilder
+ settingBuilder
+ })
+ existingSettingBuilderRef[0]?.setPackage(null)
+ val packageSetting = existingSettingBuilderRef[0]?.let { withExistingSetting(it) }!!.build()
+ addPreExistingSetting(packageName, packageSetting)
+ }
+
+ /**
+ * This method will stage a [PackageSetting] read from disk, but does not stage any scanning
+ * or parsing of the package.
+ */
+ fun addPreExistingSetting(packageName: String, packageSetting: PackageSetting) {
+ mPreExistingSettings[packageName] = packageSetting
+ }
+
+ /**
+ * This method will stage the parsing and scanning of a package but will not add it to the set
+ * of [PackageSetting]s read from disk.
+ */
+ @Throws(Exception::class)
+ fun stageScanNewPackage(
+ packageName: String,
+ versionCode: Long,
+ parent: File?,
+ withPackage: (PackageImpl) -> PackageImpl = { it },
+ withSetting: (PackageSettingBuilder) -> PackageSettingBuilder = { it }
+ ) {
+ val pair = createBasicAndroidPackage(parent, packageName, versionCode)
+ val apkPath = pair.first
+ val pkg = withPackage(pair.second)
+ stageParse(apkPath, pkg)
+ val parentFile = apkPath.parentFile
+ val settingBuilder = withSetting(createBasicSettingBuilder(parentFile, pkg))
+ stageSettingInsert(packageName, settingBuilder.build())
+ }
+
+ /**
+ * Creates a simple package that should reasonably parse for scan operations. This can be used
+ * as a basis for more complicated packages.
+ */
+ fun createBasicAndroidPackage(
+ parent: File?,
+ packageName: String,
+ versionCode: Long,
+ signingDetails: SigningDetails =
+ createRandomSigningDetails()
+ ): Pair<File, PackageImpl> {
+ val apkPath = File(File(parent, packageName), "base.apk")
+ val pkg = PackageImpl.forTesting(packageName, apkPath.parentFile.path) as PackageImpl
+ pkg.signingDetails = signingDetails
+ wheneverStatic { ParsingPackageUtils.getSigningDetails(eq(pkg), anyBoolean()) }
+ .thenReturn(signingDetails)
+ pkg.versionCode = versionCode.toInt()
+ pkg.versionCodeMajor = (versionCode shr 32).toInt()
+ pkg.targetSdkVersion = Build.VERSION_CODES.CUR_DEVELOPMENT
+ return Pair(apkPath, pkg)
+ }
+
+ /**
+ * This method will create a spy of a [SigningDetails] object to be used when simulating the
+ * collection of signatures.
+ */
+ fun createRandomSigningDetails(): SigningDetails {
+ val signingDetails = spy(SigningDetails(arrayOf(generateSpySignature()),
+ SigningDetails.SignatureSchemeVersion.SIGNING_BLOCK_V3))
+ doReturn(true).whenever(signingDetails).checkCapability(
+ anyString(), anyInt())
+ doReturn(true).whenever(signingDetails).checkCapability(
+ any(SigningDetails::class.java), anyInt())
+ return signingDetails
+ }
+
+ /**
+ * This method will create a basic [PackageSettingBuilder] from an [AndroidPackage] with all of
+ * the necessary parameters to be returned by a simple scan. This can be used as a basis for
+ * more complicated settings.
+ */
+ fun createBasicSettingBuilder(parentFile: File, pkg: AndroidPackage): PackageSettingBuilder {
+ return createBasicSettingBuilder(parentFile, pkg.packageName, pkg.longVersionCode,
+ pkg.signingDetails)
+ .setPackage(pkg)
+ }
+
+ /**
+ * This method will create a basic [PackageSettingBuilder] with all of the necessary parameters
+ * to be returned by a simple scan. This can be used as a basis for more complicated settings.
+ */
+ fun createBasicSettingBuilder(
+ parentFile: File,
+ packageName: String,
+ versionCode: Long,
+ signingDetails: SigningDetails
+ ): PackageSettingBuilder {
+ return PackageSettingBuilder()
+ .setCodePath(parentFile.path)
+ .setName(packageName)
+ .setPVersionCode(versionCode)
+ .setSigningDetails(signingDetails)
+ }
+
+ fun createBasicApplicationInfo(pkg: ParsingPackage): ApplicationInfo {
+ val applicationInfo: ApplicationInfo = mock()
+ applicationInfo.packageName = pkg.packageName
+ return applicationInfo
+ }
+
+ fun createBasicActivityInfo(
+ pkg: ParsingPackage,
+ applicationInfo: ApplicationInfo?,
+ className: String?
+ ):
+ ActivityInfo {
+ val activityInfo = ActivityInfo()
+ activityInfo.applicationInfo = applicationInfo
+ activityInfo.packageName = pkg.packageName
+ activityInfo.name = className
+ return activityInfo
+ }
+
+ fun createBasicServiceInfo(
+ pkg: ParsingPackage,
+ applicationInfo: ApplicationInfo?,
+ className: String?
+ ):
+ ServiceInfo {
+ val serviceInfo = ServiceInfo()
+ serviceInfo.applicationInfo = applicationInfo
+ serviceInfo.packageName = pkg.packageName
+ serviceInfo.name = className
+ return serviceInfo
+ }
+
+ /** Finds the appropriate partition, if available, based on a scan flag unique to it. */
+ fun getPartitionFromFlag(scanFlagMask: Int): PackageManagerService.ScanPartition =
+ systemPartitions.first { (it.scanFlag and scanFlagMask) != 0 }
+
+ @Throws(Exception::class)
+ private fun stageParse(path: File, parseResult: ParsingPackage): ParsedPackage {
+ val basePath = path.parentFile
+ basePath.mkdirs()
+ path.createNewFile()
+ createdFiles.add(path)
+ val parsedPackage = parseResult.hideAsParsed() as ParsedPackage
+ whenever(mocks.packageParser.parsePackage(
+ or(eq(path), eq(basePath)), anyInt(), anyBoolean())) { parsedPackage }
+ return parsedPackage
+ }
+
+ private fun stageSettingInsert(name: String, setting: PackageSetting): PackageSetting {
+ mPendingPackageAdds.add(Pair(name, setting))
+ return setting
+ }
+
+ @Throws(Exception::class)
+ private fun stageFrameworkScan() {
+ val apk = File(File(rootDirectory, "framework"), "framework-res.apk")
+ val frameworkPkg = PackageImpl.forTesting("android",
+ apk.parentFile.path) as PackageImpl
+ wheneverStatic { ParsingPackageUtils.getSigningDetails(frameworkPkg, true) }
+ .thenReturn(frameworkSignature)
+ stageParse(apk, frameworkPkg)
+ stageSettingInsert("android",
+ PackageSettingBuilder().setCodePath(apk.path).setName(
+ "android").setPackage(frameworkPkg).build())
+ }
+
+ @Throws(Exception::class)
+ private fun stageInstantAppResolverScan() {
+ whenever(mocks.resources.getStringArray(R.array.config_ephemeralResolverPackage)) {
+ arrayOf("com.android.test.ephemeral.resolver")
+ }
+ stageScanNewPackage("com.android.test.ephemeral.resolver",
+ 1L, getPartitionFromFlag(PackageManagerService.SCAN_AS_PRODUCT).privAppFolder,
+ withPackage = { pkg: PackageImpl ->
+ val applicationInfo: ApplicationInfo = createBasicApplicationInfo(pkg)
+ whenever(applicationInfo.isPrivilegedApp).thenReturn(true)
+ mockQueryServices(Intent.ACTION_RESOLVE_INSTANT_APP_PACKAGE,
+ createBasicServiceInfo(pkg, applicationInfo, "test.EphemeralService"))
+ mockQueryActivities(Intent.ACTION_INSTANT_APP_RESOLVER_SETTINGS,
+ createBasicActivityInfo(pkg, applicationInfo, "test.SettingsActivity"))
+ pkg
+ },
+ withSetting = { setting: PackageSettingBuilder ->
+ setting.setPkgFlags(ApplicationInfo.FLAG_SYSTEM)
+ })
+ }
+
+ @Throws(Exception::class)
+ private fun stagePermissionsControllerScan() {
+ stageScanNewPackage("com.android.permissions.controller",
+ 1L, systemPartitions[0].privAppFolder,
+ withPackage = { pkg: PackageImpl ->
+ val applicationInfo: ApplicationInfo = createBasicApplicationInfo(pkg)
+ whenever(applicationInfo.isPrivilegedApp).thenReturn(true)
+ mockQueryActivities(Intent.ACTION_MANAGE_PERMISSIONS,
+ createBasicActivityInfo(
+ pkg, applicationInfo, "test.PermissionActivity"))
+ pkg
+ },
+ withSetting = { setting: PackageSettingBuilder ->
+ setting.setPkgFlags(ApplicationInfo.FLAG_SYSTEM)
+ })
+ }
+
+ @Throws(Exception::class)
+ private fun stageSystemSharedLibraryScan() {
+ stageScanNewPackage("android.ext.shared",
+ 1L, systemPartitions[0].appFolder,
+ withPackage = { it.addLibraryName("android.ext.shared") as PackageImpl },
+ withSetting = { setting: PackageSettingBuilder ->
+ setting.setPkgFlags(ApplicationInfo.FLAG_SYSTEM)
+ }
+ )
+ }
+
+ @Throws(Exception::class)
+ private fun stageServicesExtensionScan() {
+ whenever(mocks.context.getString(R.string.config_servicesExtensionPackage)) {
+ "com.android.test.services.extension"
+ }
+ stageScanNewPackage("com.android.test.services.extension",
+ 1L, getPartitionFromFlag(PackageManagerService.SCAN_AS_SYSTEM_EXT).privAppFolder,
+ withSetting = { setting: PackageSettingBuilder ->
+ setting.setPkgFlags(ApplicationInfo.FLAG_SYSTEM)
+ })
+ }
+
+ @Throws(Exception::class)
+ private fun stageInstallerScan() {
+ stageScanNewPackage(
+ "com.android.test.installer",
+ 1L, getPartitionFromFlag(PackageManagerService.SCAN_AS_PRODUCT).privAppFolder,
+ withPackage = { pkg: PackageImpl ->
+ val applicationInfo: ApplicationInfo = createBasicApplicationInfo(pkg)
+ whenever(applicationInfo.isPrivilegedApp).thenReturn(true)
+ val installerActivity: ActivityInfo = createBasicActivityInfo(
+ pkg, applicationInfo, "test.InstallerActivity")
+ mockQueryActivities(Intent.ACTION_INSTALL_PACKAGE, installerActivity)
+ mockQueryActivities(Intent.ACTION_UNINSTALL_PACKAGE, installerActivity)
+ mockQueryActivities(Intent.ACTION_INSTALL_INSTANT_APP_PACKAGE,
+ installerActivity)
+ pkg
+ },
+ withSetting = { setting: PackageSettingBuilder ->
+ setting.setPkgFlags(ApplicationInfo.FLAG_SYSTEM)
+ }
+ )
+ }
+
+ private fun mockQueryActivities(action: String, vararg activities: ActivityInfo) {
+ whenever(mocks.componentResolver.queryActivities(
+ argThat { intent: Intent? -> intent != null && (action == intent.action) },
+ nullable(), anyInt(), anyInt())) {
+ ArrayList(activities.asList().map { info: ActivityInfo? ->
+ ResolveInfo().apply { activityInfo = info }
+ })
+ }
+ }
+
+ private fun mockQueryServices(action: String, vararg services: ServiceInfo) {
+ whenever(mocks.componentResolver.queryServices(
+ argThat { intent: Intent? -> intent != null && (action == intent.action) },
+ nullable(), anyInt(), anyInt())) {
+ ArrayList(services.asList().map { info ->
+ ResolveInfo().apply { serviceInfo = info }
+ })
+ }
+ }
+
+ fun generateSpySignature(): Signature {
+ val bytes = ByteArray(32)
+ random.nextBytes(bytes)
+ val signature = spy(Signature(bytes))
+ try {
+ val mockPublicKey: PublicKey = mock()
+ doReturn(mockPublicKey).whenever(signature).getPublicKey()
+ } catch (e: CertificateException) {
+ throw RuntimeException(e)
+ }
+ return signature
+ }
+
+ /** Override get*Folder methods to point to temporary local directories */
+
+ @Throws(IOException::class)
+ private fun redirectScanPartitions(partitions: List<PackageManagerService.ScanPartition>):
+ List<PackageManagerService.ScanPartition> {
+ val spiedPartitions: MutableList<PackageManagerService.ScanPartition> =
+ ArrayList(partitions.size)
+ for (partition: PackageManagerService.ScanPartition in partitions) {
+ val spy = spy(partition)
+ val newRoot = Files.createTempDirectory(partition.folder.name).toFile()
+ whenever(spy.overlayFolder).thenReturn(File(newRoot, "overlay"))
+ whenever(spy.appFolder).thenReturn(File(newRoot, "app"))
+ whenever(spy.privAppFolder).thenReturn(File(newRoot, "priv-app"))
+ whenever(spy.folder).thenReturn(newRoot)
+ spiedPartitions.add(spy)
+ }
+ return spiedPartitions
+ }
+}
+
+/**
+ * Sets up a basic [MockSystem] for use in a test method. This will create a MockSystem before the
+ * test method and any [org.junit.Before] annotated methods. It can then be used to access the
+ * MockSystem via the [system] method or the mocks directly via [mocks].
+ */
+class MockSystemRule : TestRule {
+ var mockSystem: MockSystem? = null
+ override fun apply(base: Statement?, description: Description?) = object : Statement() {
+ @Throws(Throwable::class)
+ override fun evaluate() {
+ mockSystem = MockSystem()
+ try {
+ base!!.evaluate()
+ } finally {
+ mockSystem?.cleanup()
+ mockSystem = null
+ }
+ }
+ }
+
+ /** Fetch the [MockSystem] instance prepared for this test */
+ fun system(): MockSystem = mockSystem!!
+ /** Fetch the [MockSystem.Mocks] prepared for this test */
+ fun mocks(): MockSystem.Mocks = mockSystem!!.mocks
+}
diff --git a/services/tests/mockingservicestests/src/com/android/server/pm/PackageManagerServiceBootTest.kt b/services/tests/mockingservicestests/src/com/android/server/pm/PackageManagerServiceBootTest.kt
new file mode 100644
index 000000000000..bd44c360b518
--- /dev/null
+++ b/services/tests/mockingservicestests/src/com/android/server/pm/PackageManagerServiceBootTest.kt
@@ -0,0 +1,173 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.android.server.pm
+
+import android.content.pm.ApplicationInfo.FLAG_SYSTEM
+import android.content.pm.ApplicationInfo.PRIVATE_FLAG_PRIVILEGED
+import android.content.pm.PackageManager
+import android.content.pm.PackageParser
+import android.os.Build
+import android.os.Process
+import android.util.Log
+import com.android.server.pm.parsing.pkg.AndroidPackage
+import com.android.server.testutils.whenever
+import org.hamcrest.MatcherAssert.assertThat
+import org.hamcrest.Matchers.equalTo
+import org.hamcrest.Matchers.notNullValue
+import org.hamcrest.collection.IsMapContaining.hasKey
+import org.hamcrest.core.IsNot.not
+import org.junit.Before
+import org.junit.Rule
+import org.junit.Test
+import org.junit.runner.RunWith
+import org.junit.runners.JUnit4
+import org.mockito.ArgumentMatchers.anyBoolean
+import org.mockito.ArgumentMatchers.anyInt
+import org.mockito.ArgumentMatchers.argThat
+import org.mockito.Mockito
+import org.mockito.Mockito.verify
+import java.io.File
+
+@RunWith(JUnit4::class)
+class PackageManagerServiceBootTest {
+
+ @Rule
+ @JvmField
+ val rule = MockSystemRule()
+
+ @Before
+ @Throws(Exception::class)
+ fun setup() {
+ Log.i("system.out", "setup", Exception())
+ rule.system().stageNominalSystemState()
+ }
+
+ private fun createPackageManagerService(): PackageManagerService {
+ return PackageManagerService(rule.mocks().injector,
+ false /*coreOnly*/,
+ false /*factoryTest*/,
+ MockSystem.DEFAULT_VERSION_INFO.fingerprint,
+ false /*isEngBuild*/,
+ false /*isUserDebugBuild*/,
+ Build.VERSION_CODES.CUR_DEVELOPMENT,
+ Build.VERSION.INCREMENTAL)
+ }
+
+ @Test
+ @Throws(Exception::class)
+ fun simpleConstruction() {
+ val pm = createPackageManagerService()
+ verify(rule.mocks().injector).bootstrap(pm)
+ verify(rule.mocks().settings).addSharedUserLPw("android.uid.system",
+ Process.SYSTEM_UID, FLAG_SYSTEM, PRIVATE_FLAG_PRIVILEGED)
+ verify(rule.mocks().settings).addSharedUserLPw("android.uid.phone",
+ Process.PHONE_UID, FLAG_SYSTEM, PRIVATE_FLAG_PRIVILEGED)
+ verify(rule.mocks().settings).addSharedUserLPw("android.uid.log",
+ Process.LOG_UID, FLAG_SYSTEM, PRIVATE_FLAG_PRIVILEGED)
+ verify(rule.mocks().settings).addSharedUserLPw("android.uid.nfc",
+ Process.NFC_UID, FLAG_SYSTEM, PRIVATE_FLAG_PRIVILEGED)
+ verify(rule.mocks().settings).addSharedUserLPw("android.uid.bluetooth",
+ Process.BLUETOOTH_UID, FLAG_SYSTEM, PRIVATE_FLAG_PRIVILEGED)
+ verify(rule.mocks().settings).addSharedUserLPw("android.uid.shell",
+ Process.SHELL_UID, FLAG_SYSTEM, PRIVATE_FLAG_PRIVILEGED)
+ verify(rule.mocks().settings).addSharedUserLPw("android.uid.se",
+ Process.SE_UID, FLAG_SYSTEM, PRIVATE_FLAG_PRIVILEGED)
+ verify(rule.mocks().settings).addSharedUserLPw("android.uid.networkstack",
+ Process.NETWORK_STACK_UID, FLAG_SYSTEM, PRIVATE_FLAG_PRIVILEGED)
+ rule.system().validateFinalState()
+ }
+
+ @Test
+ @Throws(Exception::class)
+ fun existingDataPackage_remains() {
+ rule.system().stageScanExistingPackage("a.data.package", 1L, rule.system().dataAppDirectory)
+ val pm = createPackageManagerService()
+ rule.system().validateFinalState()
+ assertThat(pm.mPackages, hasKey("a.data.package"))
+ }
+
+ @Test
+ @Throws(Exception::class)
+ fun unexpectedDataPackage_isRemoved() {
+ rule.system().stageScanNewPackage(
+ "a.data.package", 1L, rule.system().dataAppDirectory)
+ val pm = createPackageManagerService()
+ verify(rule.mocks().settings, Mockito.never()).insertPackageSettingLPw(
+ argThat { setting: PackageSetting -> setting.name == "a.data.package" },
+ argThat { pkg: AndroidPackage -> pkg.packageName == "a.data.package" })
+ assertThat(pm.mPackages, not(hasKey("a.data.package")))
+ }
+
+ @Test
+ @Throws(Exception::class)
+ fun expectedPackageMissing_doesNotReplace() {
+ // setup existing package
+ rule.system().stageScanExistingPackage("a.data.package", 1L,
+ rule.system().dataAppDirectory)
+ // simulate parsing failure for any path containing the package name.
+ whenever(rule.mocks().packageParser.parsePackage(
+ argThat { path: File -> path.path.contains("a.data.package") },
+ anyInt(),
+ anyBoolean()))
+ .thenThrow(PackageParser.PackageParserException(
+ PackageManager.INSTALL_FAILED_INVALID_APK, "Oh no!"))
+ val pm = createPackageManagerService()
+ verify(rule.mocks().settings, Mockito.never()).insertPackageSettingLPw(
+ argThat { setting: PackageSetting -> setting.name == "a.data.package" },
+ argThat { pkg: AndroidPackage -> pkg.packageName == "a.data.package" })
+ assertThat(pm.mPackages, not(hasKey("a.data.package")))
+ }
+
+ @Test
+ @Throws(Exception::class)
+ fun expectingBetter_updateStillBetter() {
+ // Debug.waitForDebugger()
+ val systemAppPackageName = "com.android.test.updated.system.app"
+ val systemAppSigningDetails = rule.system().createRandomSigningDetails()
+ val systemVersionParent = rule.system()
+ .getPartitionFromFlag(PackageManagerService.SCAN_AS_PRODUCT).privAppFolder
+
+ // system app v1 is disabled
+ whenever(rule.mocks().settings.isDisabledSystemPackageLPr(systemAppPackageName)) {
+ true
+ }
+ whenever(rule.mocks().settings.getDisabledSystemPkgLPr(systemAppPackageName)) {
+ rule.system().createBasicSettingBuilder(
+ File(systemVersionParent, systemAppPackageName),
+ systemAppPackageName, 1, systemAppSigningDetails).build()
+ }
+
+ // system app v3 is on data/app
+ rule.system().stageScanExistingPackage(
+ systemAppPackageName,
+ 3,
+ rule.system().dataAppDirectory,
+ withPackage = { it.apply { signingDetails = systemAppSigningDetails } },
+ withExistingSetting = { it.setPkgFlags(FLAG_SYSTEM) })
+
+ // system app v2 is scanned from system
+ rule.system().stageScanNewPackage(systemAppPackageName, 2, systemVersionParent,
+ withPackage = { it.apply { signingDetails = systemAppSigningDetails } },
+ withSetting = { it.setPkgFlags(FLAG_SYSTEM) })
+
+ val pm = createPackageManagerService()
+
+ assertThat("system package should exist after boot",
+ pm.mPackages[systemAppPackageName], notNullValue())
+ assertThat("system package should remain at version on data/app",
+ pm.mPackages[systemAppPackageName]!!.longVersionCode, equalTo(3))
+ }
+} \ No newline at end of file
diff --git a/services/tests/mockingservicestests/src/com/android/server/utils/quota/MultiRateLimiterTest.java b/services/tests/mockingservicestests/src/com/android/server/utils/quota/MultiRateLimiterTest.java
new file mode 100644
index 000000000000..df533f3c122a
--- /dev/null
+++ b/services/tests/mockingservicestests/src/com/android/server/utils/quota/MultiRateLimiterTest.java
@@ -0,0 +1,197 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.server.utils.quota;
+
+import static com.google.common.truth.Truth.assertThat;
+
+import android.testing.TestableContext;
+
+import androidx.test.InstrumentationRegistry;
+import androidx.test.filters.SmallTest;
+
+import org.junit.Rule;
+import org.junit.Test;
+
+import java.time.Duration;
+
+@SmallTest
+public class MultiRateLimiterTest {
+
+ private static final int USER_ID = 1;
+ private static final String PACKAGE_NAME_1 = "com.android.package.one";
+ private static final String PACKAGE_NAME_2 = "com.android.package.two";
+ private static final String TAG = "tag";
+
+ @Rule
+ public final TestableContext mContext =
+ new TestableContext(InstrumentationRegistry.getContext(), null);
+
+ private final InjectorForTest mInjector = new InjectorForTest();
+
+ private static class InjectorForTest extends QuotaTracker.Injector {
+ Duration mElapsedTime = Duration.ZERO;
+
+ @Override
+ public long getElapsedRealtime() {
+ return mElapsedTime.toMillis();
+ }
+
+ @Override
+ public boolean isAlarmManagerReady() {
+ return true;
+ }
+ }
+
+ @Test
+ public void testSingleRateLimit_belowLimit_isWithinQuota() {
+ MultiRateLimiter multiRateLimiter = new MultiRateLimiter.Builder(mContext, mInjector)
+ .addRateLimit(3, Duration.ofSeconds(20))
+ .build();
+
+ // Three quick events are within quota.
+ mInjector.mElapsedTime = Duration.ZERO;
+ assertThat(multiRateLimiter.isWithinQuota(USER_ID, PACKAGE_NAME_1, TAG)).isTrue();
+ multiRateLimiter.noteEvent(USER_ID, PACKAGE_NAME_1, TAG);
+
+ mInjector.mElapsedTime = Duration.ofMillis(50);
+ assertThat(multiRateLimiter.isWithinQuota(USER_ID, PACKAGE_NAME_1, TAG)).isTrue();
+ multiRateLimiter.noteEvent(USER_ID, PACKAGE_NAME_1, TAG);
+
+ mInjector.mElapsedTime = Duration.ofMillis(100);
+ assertThat(multiRateLimiter.isWithinQuota(USER_ID, PACKAGE_NAME_1, TAG)).isTrue();
+ }
+
+ @Test
+ public void testSingleRateLimit_aboveLimit_isNotWithinQuota() {
+ MultiRateLimiter multiRateLimiter = new MultiRateLimiter.Builder(mContext, mInjector)
+ .addRateLimit(3, Duration.ofSeconds(20))
+ .build();
+
+ mInjector.mElapsedTime = Duration.ZERO;
+ multiRateLimiter.noteEvent(USER_ID, PACKAGE_NAME_1, TAG);
+
+ mInjector.mElapsedTime = Duration.ofMillis(50);
+ multiRateLimiter.noteEvent(USER_ID, PACKAGE_NAME_1, TAG);
+
+ mInjector.mElapsedTime = Duration.ofMillis(100);
+ multiRateLimiter.noteEvent(USER_ID, PACKAGE_NAME_1, TAG);
+
+ mInjector.mElapsedTime = Duration.ofMillis(150);
+ // We hit the limit, 4th event in under 20 seconds is not within quota.
+ assertThat(multiRateLimiter.isWithinQuota(USER_ID, PACKAGE_NAME_1, TAG)).isFalse();
+ }
+
+ @Test
+ public void testSingleRateLimit_afterGoingAboveQuotaAndWaitingWindow_isBackWithinQuota() {
+ MultiRateLimiter multiRateLimiter = new MultiRateLimiter.Builder(mContext, mInjector)
+ .addRateLimit(3, Duration.ofSeconds(20))
+ .build();
+
+ mInjector.mElapsedTime = Duration.ZERO;
+ multiRateLimiter.noteEvent(USER_ID, PACKAGE_NAME_1, TAG);
+
+ mInjector.mElapsedTime = Duration.ofMillis(50);
+ multiRateLimiter.noteEvent(USER_ID, PACKAGE_NAME_1, TAG);
+
+ mInjector.mElapsedTime = Duration.ofMillis(100);
+ multiRateLimiter.noteEvent(USER_ID, PACKAGE_NAME_1, TAG);
+
+ mInjector.mElapsedTime = Duration.ofMillis(150);
+ // We hit the limit, 4th event in under 20 seconds is not within quota.
+ assertThat(multiRateLimiter.isWithinQuota(USER_ID, PACKAGE_NAME_1, TAG)).isFalse();
+
+ mInjector.mElapsedTime = Duration.ofSeconds(21);
+ // 20 seconds have passed, we're again within quota.
+ assertThat(multiRateLimiter.isWithinQuota(USER_ID, PACKAGE_NAME_1, TAG)).isTrue();
+ }
+
+ @Test
+ public void createMultipleRateLimits_testTheyLimitsAsExpected() {
+ MultiRateLimiter multiRateLimiter = new MultiRateLimiter.Builder(mContext, mInjector)
+ .addRateLimit(3, Duration.ofSeconds(20)) // 1st limit
+ .addRateLimit(4, Duration.ofSeconds(40)) // 2nd limit
+ .addRateLimit(5, Duration.ofSeconds(60)) // 3rd limit
+ .build();
+
+ // Testing the 1st limit
+ mInjector.mElapsedTime = Duration.ZERO;
+ assertThat(multiRateLimiter.isWithinQuota(USER_ID, PACKAGE_NAME_1, TAG)).isTrue();
+ multiRateLimiter.noteEvent(USER_ID, PACKAGE_NAME_1, TAG);
+
+ mInjector.mElapsedTime = Duration.ofMillis(50);
+ assertThat(multiRateLimiter.isWithinQuota(USER_ID, PACKAGE_NAME_1, TAG)).isTrue();
+ multiRateLimiter.noteEvent(USER_ID, PACKAGE_NAME_1, TAG);
+
+ mInjector.mElapsedTime = Duration.ofMillis(100);
+ assertThat(multiRateLimiter.isWithinQuota(USER_ID, PACKAGE_NAME_1, TAG)).isTrue();
+ multiRateLimiter.noteEvent(USER_ID, PACKAGE_NAME_1, TAG);
+
+ mInjector.mElapsedTime = Duration.ofMillis(150);
+ assertThat(multiRateLimiter.isWithinQuota(USER_ID, PACKAGE_NAME_1, TAG)).isFalse();
+
+ mInjector.mElapsedTime = Duration.ofSeconds(21);
+ assertThat(multiRateLimiter.isWithinQuota(USER_ID, PACKAGE_NAME_1, TAG)).isTrue();
+ multiRateLimiter.noteEvent(USER_ID, PACKAGE_NAME_1, TAG);
+
+ // Testing the 2nd limit
+ mInjector.mElapsedTime = Duration.ofSeconds(35);
+ assertThat(multiRateLimiter.isWithinQuota(USER_ID, PACKAGE_NAME_1, TAG)).isFalse();
+
+ mInjector.mElapsedTime = Duration.ofSeconds(42);
+ assertThat(multiRateLimiter.isWithinQuota(USER_ID, PACKAGE_NAME_1, TAG)).isTrue();
+ multiRateLimiter.noteEvent(USER_ID, PACKAGE_NAME_1, TAG);
+
+ // Testing the 3rd limit.
+ mInjector.mElapsedTime = Duration.ofSeconds(43);
+ assertThat(multiRateLimiter.isWithinQuota(USER_ID, PACKAGE_NAME_1, TAG)).isFalse();
+
+ mInjector.mElapsedTime = Duration.ofSeconds(62);
+ assertThat(multiRateLimiter.isWithinQuota(USER_ID, PACKAGE_NAME_1, TAG)).isTrue();
+ multiRateLimiter.noteEvent(USER_ID, PACKAGE_NAME_1, TAG);
+ }
+
+ @Test
+ public void createSingleRateLimit_testItLimitsOnlyGivenUptc() {
+ MultiRateLimiter multiRateLimiter = new MultiRateLimiter.Builder(mContext, mInjector)
+ .addRateLimit(3, Duration.ofSeconds(20))
+ .build();
+
+ mInjector.mElapsedTime = Duration.ZERO;
+ assertThat(multiRateLimiter.isWithinQuota(USER_ID, PACKAGE_NAME_1, TAG)).isTrue();
+ assertThat(multiRateLimiter.isWithinQuota(USER_ID, PACKAGE_NAME_2, TAG)).isTrue();
+ multiRateLimiter.noteEvent(USER_ID, PACKAGE_NAME_1, TAG);
+
+ mInjector.mElapsedTime = Duration.ofMillis(50);
+ assertThat(multiRateLimiter.isWithinQuota(USER_ID, PACKAGE_NAME_1, TAG)).isTrue();
+ assertThat(multiRateLimiter.isWithinQuota(USER_ID, PACKAGE_NAME_2, TAG)).isTrue();
+ multiRateLimiter.noteEvent(USER_ID, PACKAGE_NAME_1, TAG);
+
+ mInjector.mElapsedTime = Duration.ofMillis(100);
+ assertThat(multiRateLimiter.isWithinQuota(USER_ID, PACKAGE_NAME_1, TAG)).isTrue();
+ assertThat(multiRateLimiter.isWithinQuota(USER_ID, PACKAGE_NAME_2, TAG)).isTrue();
+ multiRateLimiter.noteEvent(USER_ID, PACKAGE_NAME_1, TAG);
+
+ mInjector.mElapsedTime = Duration.ofMillis(150);
+ assertThat(multiRateLimiter.isWithinQuota(USER_ID, PACKAGE_NAME_1, TAG)).isFalse();
+ // Different userId - packageName - tag combination is still allowed.
+ assertThat(multiRateLimiter.isWithinQuota(USER_ID, PACKAGE_NAME_2, TAG)).isTrue();
+
+ mInjector.mElapsedTime = Duration.ofSeconds(21);
+ assertThat(multiRateLimiter.isWithinQuota(USER_ID, PACKAGE_NAME_1, TAG)).isTrue();
+ assertThat(multiRateLimiter.isWithinQuota(USER_ID, PACKAGE_NAME_2, TAG)).isTrue();
+ }
+}
diff --git a/services/tests/mockingservicestests/utils-mockito/com/android/server/extendedtestutils/ExtendedMockitoUtils.kt b/services/tests/mockingservicestests/utils-mockito/com/android/server/extendedtestutils/ExtendedMockitoUtils.kt
new file mode 100644
index 000000000000..72ae77e48e25
--- /dev/null
+++ b/services/tests/mockingservicestests/utils-mockito/com/android/server/extendedtestutils/ExtendedMockitoUtils.kt
@@ -0,0 +1,41 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.server.extendedtestutils
+
+import com.android.dx.mockito.inline.extended.ExtendedMockito
+import com.android.dx.mockito.inline.extended.MockedMethod
+import com.android.dx.mockito.inline.extended.StaticCapableStubber
+import org.mockito.stubbing.Answer
+
+fun <T> StaticCapableStubber.wheneverStatic(methodCall: MockedMethod<T>) {
+ this.`when`(methodCall)
+}
+
+fun <T> wheneverStatic(mockedMethod: MockedMethod<T>) = object : CustomStaticStubber<T> {
+ override fun thenAnswer(answer: Answer<T>) {
+ ExtendedMockito.doAnswer(answer).wheneverStatic(mockedMethod)
+ }
+
+ override fun thenReturn(value: T) {
+ ExtendedMockito.doReturn(value).wheneverStatic(mockedMethod)
+ }
+}
+
+interface CustomStaticStubber<T> {
+ fun thenAnswer(answer: Answer<T>)
+ fun thenReturn(value: T)
+}
diff --git a/services/tests/servicestests/Android.bp b/services/tests/servicestests/Android.bp
index 343b156e443a..89770fe39d60 100644
--- a/services/tests/servicestests/Android.bp
+++ b/services/tests/servicestests/Android.bp
@@ -111,6 +111,16 @@ android_test {
}
java_library {
+ name: "servicestests-core-utils",
+ srcs: [
+ "src/com/android/server/pm/PackageSettingBuilder.java",
+ ],
+ static_libs: [
+ "services.core",
+ ],
+}
+
+java_library {
name: "servicestests-utils",
srcs: [
"utils/**/*.java",
diff --git a/services/tests/servicestests/src/com/android/server/accessibility/AccessibilityManagerServiceTest.java b/services/tests/servicestests/src/com/android/server/accessibility/AccessibilityManagerServiceTest.java
index 3f3d5e5106c5..839bc93ba00f 100644
--- a/services/tests/servicestests/src/com/android/server/accessibility/AccessibilityManagerServiceTest.java
+++ b/services/tests/servicestests/src/com/android/server/accessibility/AccessibilityManagerServiceTest.java
@@ -35,6 +35,7 @@ import android.content.pm.ApplicationInfo;
import android.content.pm.PackageManager;
import android.content.pm.ResolveInfo;
import android.content.pm.ServiceInfo;
+import android.content.res.Resources;
import android.graphics.drawable.Icon;
import android.os.IBinder;
import android.os.UserHandle;
@@ -94,6 +95,8 @@ public class AccessibilityManagerServiceTest extends AndroidTestCase {
@Mock private IAccessibilityServiceClient mMockServiceClient;
@Mock private WindowMagnificationManager mMockWindowMagnificationMgr;
@Mock private MagnificationController mMockMagnificationController;
+ @Mock private Resources mMockResources;
+
private AccessibilityUserState mUserState;
private MessageCapturingHandler mHandler = new MessageCapturingHandler(null);
@@ -121,6 +124,9 @@ public class AccessibilityManagerServiceTest extends AndroidTestCase {
mMockA11yDisplayListener,
mMockMagnificationController);
+ mMockResources = mock(Resources.class);
+ when(mMockContext.getResources()).thenReturn(mMockResources);
+
final AccessibilityUserState userState = new AccessibilityUserState(
mA11yms.getCurrentUserIdLocked(), mMockContext, mA11yms);
mA11yms.mUserStates.put(mA11yms.getCurrentUserIdLocked(), userState);
diff --git a/services/tests/servicestests/src/com/android/server/accessibility/AccessibilityUserStateTest.java b/services/tests/servicestests/src/com/android/server/accessibility/AccessibilityUserStateTest.java
index fbfb0455bd46..81ca92cc3c8c 100644
--- a/services/tests/servicestests/src/com/android/server/accessibility/AccessibilityUserStateTest.java
+++ b/services/tests/servicestests/src/com/android/server/accessibility/AccessibilityUserStateTest.java
@@ -42,11 +42,16 @@ import static org.mockito.Mockito.when;
import android.accessibilityservice.AccessibilityServiceInfo;
import android.content.ComponentName;
import android.content.Context;
+import android.content.res.Resources;
+import android.graphics.Color;
import android.provider.Settings;
import android.test.mock.MockContentResolver;
import android.testing.DexmakerShareClassLoaderRule;
import android.util.ArraySet;
+import androidx.test.InstrumentationRegistry;
+
+import com.android.internal.R;
import com.android.internal.util.test.FakeSettingsProvider;
import org.junit.After;
@@ -90,8 +95,13 @@ public class AccessibilityUserStateTest {
private AccessibilityUserState mUserState;
+ private int mFocusStrokeWidthDefaultValue;
+ private int mFocusColorDefaultValue;
+
@Before
public void setUp() {
+ final Resources resources = InstrumentationRegistry.getContext().getResources();
+
MockitoAnnotations.initMocks(this);
FakeSettingsProvider.clearSettingsProvider();
mMockResolver = new MockContentResolver();
@@ -99,6 +109,11 @@ public class AccessibilityUserStateTest {
when(mMockContext.getContentResolver()).thenReturn(mMockResolver);
when(mMockServiceInfo.getComponentName()).thenReturn(COMPONENT_NAME);
when(mMockConnection.getServiceInfo()).thenReturn(mMockServiceInfo);
+ when(mMockContext.getResources()).thenReturn(resources);
+
+ mFocusStrokeWidthDefaultValue =
+ resources.getDimensionPixelSize(R.dimen.accessibility_focus_highlight_stroke_width);
+ mFocusColorDefaultValue = resources.getColor(R.color.accessibility_focus_highlight_color);
mUserState = new AccessibilityUserState(USER_ID, mMockContext, mMockListener);
}
@@ -129,6 +144,7 @@ public class AccessibilityUserStateTest {
mUserState.setUserNonInteractiveUiTimeoutLocked(30);
mUserState.setUserInteractiveUiTimeoutLocked(30);
mUserState.setMagnificationModeLocked(ACCESSIBILITY_MAGNIFICATION_MODE_WINDOW);
+ mUserState.setFocusAppearanceLocked(20, Color.BLUE);
mUserState.onSwitchToAnotherUserLocked();
@@ -150,6 +166,8 @@ public class AccessibilityUserStateTest {
assertEquals(0, mUserState.getUserInteractiveUiTimeoutLocked());
assertEquals(ACCESSIBILITY_MAGNIFICATION_MODE_FULLSCREEN,
mUserState.getMagnificationModeLocked());
+ assertEquals(mFocusStrokeWidthDefaultValue, mUserState.getFocusStrokeWidthLocked());
+ assertEquals(mFocusColorDefaultValue, mUserState.getFocusColorLocked());
}
@Test
@@ -350,6 +368,21 @@ public class AccessibilityUserStateTest {
mUserState.getMagnificationModeLocked());
}
+ @Test
+ public void setFocusAppearanceData_returnExpectedFocusAppearanceData() {
+ final int focusStrokeWidthValue = 100;
+ final int focusColorValue = Color.BLUE;
+
+ assertEquals(mFocusStrokeWidthDefaultValue, mUserState.getFocusStrokeWidthLocked());
+ assertEquals(mFocusColorDefaultValue, mUserState.getFocusColorLocked());
+
+ mUserState.setFocusAppearanceLocked(focusStrokeWidthValue, focusColorValue);
+
+ assertEquals(focusStrokeWidthValue, mUserState.getFocusStrokeWidthLocked());
+ assertEquals(focusColorValue, mUserState.getFocusColorLocked());
+
+ }
+
private int getSecureIntForUser(String key, int userId) {
return Settings.Secure.getIntForUser(mMockResolver, key, -1, userId);
}
diff --git a/services/tests/servicestests/src/com/android/server/hdmi/HdmiCecMessageValidatorTest.java b/services/tests/servicestests/src/com/android/server/hdmi/HdmiCecMessageValidatorTest.java
index a05cbb48a3f7..6285f58d07b3 100644
--- a/services/tests/servicestests/src/com/android/server/hdmi/HdmiCecMessageValidatorTest.java
+++ b/services/tests/servicestests/src/com/android/server/hdmi/HdmiCecMessageValidatorTest.java
@@ -56,6 +56,30 @@ public class HdmiCecMessageValidatorTest {
}
@Test
+ public void isValid_unregisteredSource() {
+ // Message invokes a broadcast response
+ // <Get Menu Language>
+ assertMessageValidity("F4:91").isEqualTo(OK);
+ // <Request Active Source>
+ assertMessageValidity("FF:85").isEqualTo(OK);
+
+ // Message by CEC Switch
+ // <Routing Change>
+ assertMessageValidity("FF:80:00:00:10:00").isEqualTo(OK);
+
+ // <Routing Information>
+ assertMessageValidity("FF:81:10:00").isEqualTo(OK);
+
+ // Standby
+ assertMessageValidity("F4:36").isEqualTo(OK);
+ assertMessageValidity("FF:36").isEqualTo(OK);
+
+ // <Report Physical Address> / <Active Source>
+ assertMessageValidity("FF:84:10:00:04").isEqualTo(OK);
+ assertMessageValidity("FF:82:10:00").isEqualTo(OK);
+ }
+
+ @Test
public void isValid_giveDevicePowerStatus() {
assertMessageValidity("04:8F").isEqualTo(OK);
diff --git a/services/tests/servicestests/src/com/android/server/pm/PackageSettingBuilder.java b/services/tests/servicestests/src/com/android/server/pm/PackageSettingBuilder.java
index f8e92ad71d8e..84551c51052c 100644
--- a/services/tests/servicestests/src/com/android/server/pm/PackageSettingBuilder.java
+++ b/services/tests/servicestests/src/com/android/server/pm/PackageSettingBuilder.java
@@ -22,6 +22,7 @@ import android.util.ArraySet;
import android.util.SparseArray;
import com.android.server.pm.parsing.pkg.AndroidPackage;
+import com.android.server.pm.parsing.pkg.PackageImpl;
import java.io.File;
import java.util.Map;
@@ -38,14 +39,14 @@ public class PackageSettingBuilder {
private int mPkgFlags;
private int mPrivateFlags;
private int mSharedUserId;
- private String[] mUsesStaticLibraries;
- private long[] mUsesStaticLibrariesVersions;
- private Map<String, ArraySet<String>> mMimeGroups;
private String mVolumeUuid;
+ private int mAppId;
private SparseArray<PackageUserState> mUserStates = new SparseArray<>();
private AndroidPackage mPkg;
- private int mAppId;
private InstallSource mInstallSource;
+ private String[] mUsesStaticLibraries;
+ private long[] mUsesStaticLibrariesVersions;
+ private Map<String, ArraySet<String>> mMimeGroups;
private PackageParser.SigningDetails mSigningDetails;
public PackageSettingBuilder setPackage(AndroidPackage pkg) {
@@ -143,6 +144,14 @@ public class PackageSettingBuilder {
return this;
}
+ public PackageSettingBuilder setInstallState(int userId, boolean installed) {
+ if (mUserStates.indexOfKey(userId) < 0) {
+ mUserStates.put(userId, new PackageUserState());
+ }
+ mUserStates.get(userId).installed = installed;
+ return this;
+ }
+
public PackageSettingBuilder setInstallSource(InstallSource installSource) {
mInstallSource = installSource;
return this;
@@ -173,6 +182,5 @@ public class PackageSettingBuilder {
packageSetting.setUserState(mUserStates.keyAt(i), mUserStates.valueAt(i));
}
return packageSetting;
-
}
}
diff --git a/services/tests/servicestests/src/com/android/server/pm/ScanTests.java b/services/tests/servicestests/src/com/android/server/pm/ScanTests.java
index fcbb5ed1140c..d8c3979c9cf9 100644
--- a/services/tests/servicestests/src/com/android/server/pm/ScanTests.java
+++ b/services/tests/servicestests/src/com/android/server/pm/ScanTests.java
@@ -101,7 +101,8 @@ public class ScanTests {
@Before
public void setupDefaultAbiBehavior() throws Exception {
when(mMockPackageAbiHelper.derivePackageAbi(
- any(AndroidPackage.class), anyBoolean(), nullable(String.class)))
+ any(AndroidPackage.class), anyBoolean(), nullable(String.class),
+ any(File.class)))
.thenReturn(new Pair<>(
new PackageAbiHelper.Abis("derivedPrimary", "derivedSecondary"),
new PackageAbiHelper.NativeLibraryPaths(
diff --git a/services/tests/servicestests/src/com/android/server/policy/DeviceStateProviderImplTest.java b/services/tests/servicestests/src/com/android/server/policy/DeviceStateProviderImplTest.java
index 92942bb91528..e816cbebd73f 100644
--- a/services/tests/servicestests/src/com/android/server/policy/DeviceStateProviderImplTest.java
+++ b/services/tests/servicestests/src/com/android/server/policy/DeviceStateProviderImplTest.java
@@ -23,6 +23,7 @@ import static com.android.server.policy.DeviceStateProviderImpl.DEFAULT_DEVICE_S
import static org.junit.Assert.assertArrayEquals;
import static org.junit.Assert.assertEquals;
+import static org.mockito.ArgumentMatchers.anyInt;
import static org.mockito.Mockito.eq;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.never;
@@ -170,16 +171,16 @@ public final class DeviceStateProviderImplTest {
@Test
public void create_sensor() throws Exception {
- Sensor sensor = newSensor("sensor", Sensor.TYPE_HINGE_ANGLE);
- when(mSensorManager.getSensorList(eq(sensor.getType()))).thenReturn(List.of(sensor));
+ Sensor sensor = newSensor("sensor", Sensor.STRING_TYPE_HINGE_ANGLE);
+ when(mSensorManager.getSensorList(anyInt())).thenReturn(List.of(sensor));
String configString = "<device-state-config>\n"
+ " <device-state>\n"
+ " <identifier>1</identifier>\n"
+ " <conditions>\n"
+ " <sensor>\n"
+ + " <type>" + sensor.getStringType() + "</type>\n"
+ " <name>" + sensor.getName() + "</name>\n"
- + " <type>" + sensor.getType() + "</type>\n"
+ " <value>\n"
+ " <max>90</max>\n"
+ " </value>\n"
@@ -190,8 +191,8 @@ public final class DeviceStateProviderImplTest {
+ " <identifier>2</identifier>\n"
+ " <conditions>\n"
+ " <sensor>\n"
+ + " <type>" + sensor.getStringType() + "</type>\n"
+ " <name>" + sensor.getName() + "</name>\n"
- + " <type>" + sensor.getType() + "</type>\n"
+ " <value>\n"
+ " <min-inclusive>90</min-inclusive>\n"
+ " <max>180</max>\n"
@@ -203,8 +204,8 @@ public final class DeviceStateProviderImplTest {
+ " <identifier>3</identifier>\n"
+ " <conditions>\n"
+ " <sensor>\n"
+ + " <type>" + sensor.getStringType() + "</type>\n"
+ " <name>" + sensor.getName() + "</name>\n"
- + " <type>" + sensor.getType() + "</type>\n"
+ " <value>\n"
+ " <min-inclusive>180</min-inclusive>\n"
+ " </value>\n"
@@ -262,13 +263,13 @@ public final class DeviceStateProviderImplTest {
assertEquals(1, mIntegerCaptor.getValue().intValue());
}
- private static Sensor newSensor(String name, int type) throws Exception {
+ private static Sensor newSensor(String name, String type) throws Exception {
Constructor<Sensor> constructor = Sensor.class.getDeclaredConstructor();
constructor.setAccessible(true);
Sensor sensor = constructor.newInstance();
FieldSetter.setField(sensor, Sensor.class.getDeclaredField("mName"), name);
- FieldSetter.setField(sensor, Sensor.class.getDeclaredField("mType"), type);
+ FieldSetter.setField(sensor, Sensor.class.getDeclaredField("mStringType"), type);
return sensor;
}
diff --git a/services/tests/servicestests/utils-mockito/com/android/server/testutils/MockitoUtils.kt b/services/tests/servicestests/utils-mockito/com/android/server/testutils/MockitoUtils.kt
index 59cbd1ce1d7b..4c82818f71e4 100644
--- a/services/tests/servicestests/utils-mockito/com/android/server/testutils/MockitoUtils.kt
+++ b/services/tests/servicestests/utils-mockito/com/android/server/testutils/MockitoUtils.kt
@@ -17,6 +17,7 @@
package com.android.server.testutils
import org.mockito.Answers
+import org.mockito.ArgumentMatchers
import org.mockito.Mockito
import org.mockito.invocation.InvocationOnMock
import org.mockito.stubbing.Answer
@@ -53,7 +54,7 @@ inline fun <reified T> mock(block: T.() -> Unit = {}) = Mockito.mock(T::class.ja
fun <T> spy(value: T, block: T.() -> Unit = {}) = Mockito.spy(value).apply(block)
-fun <Type> Stubber.whenever(mock: Type) = Mockito.`when`(mock)
+fun <Type> Stubber.whenever(mock: Type) = this.`when`(mock)
fun <Type : Any?> whenever(mock: Type) = Mockito.`when`(mock)
@Suppress("UNCHECKED_CAST")
@@ -81,3 +82,5 @@ inline fun <reified T> spyThrowOnUnmocked(value: T?, block: T.() -> Unit = {}):
inline fun <reified T> mockThrowOnUnmocked(block: T.() -> Unit = {}) =
spyThrowOnUnmocked<T>(null, block)
+
+inline fun <reified T : Any> nullable() = ArgumentMatchers.nullable(T::class.java) \ No newline at end of file
diff --git a/services/tests/uiservicestests/src/com/android/server/notification/BuzzBeepBlinkTest.java b/services/tests/uiservicestests/src/com/android/server/notification/BuzzBeepBlinkTest.java
index 00f706b13c58..32cb2a3a2540 100644
--- a/services/tests/uiservicestests/src/com/android/server/notification/BuzzBeepBlinkTest.java
+++ b/services/tests/uiservicestests/src/com/android/server/notification/BuzzBeepBlinkTest.java
@@ -153,7 +153,8 @@ public class BuzzBeepBlinkTest extends UiServiceTestCase {
AccessibilityEvent.TYPES_ALL_MASK);
when(mAccessibilityService.addClient(any(), anyInt())).thenReturn(serviceReturnValue);
AccessibilityManager accessibilityManager =
- new AccessibilityManager(Handler.getMain(), mAccessibilityService, 0);
+ new AccessibilityManager(getContext(), Handler.getMain(), mAccessibilityService,
+ 0, true);
verify(mAccessibilityService).addClient(any(IAccessibilityManagerClient.class), anyInt());
assertTrue(accessibilityManager.isEnabled());
diff --git a/services/tests/uiservicestests/src/com/android/server/notification/NotificationListenerServiceTest.java b/services/tests/uiservicestests/src/com/android/server/notification/NotificationListenerServiceTest.java
index fdc089ee2f7e..9b37e76e4c65 100644
--- a/services/tests/uiservicestests/src/com/android/server/notification/NotificationListenerServiceTest.java
+++ b/services/tests/uiservicestests/src/com/android/server/notification/NotificationListenerServiceTest.java
@@ -102,7 +102,7 @@ public class NotificationListenerServiceTest extends UiServiceTestCase {
String key = mKeys[i];
Ranking ranking = new Ranking();
service.getCurrentRanking().getRanking(key, ranking);
- assertEquals(getVisibilityOverride(i), ranking.getVisibilityOverride());
+ assertEquals(getVisibilityOverride(i), ranking.getLockscreenVisibilityOverride());
assertEquals(getOverrideGroupKey(key), ranking.getOverrideGroupKey());
assertEquals(!isIntercepted(i), ranking.matchesInterruptionFilter());
assertEquals(getSuppressedVisualEffects(i), ranking.getSuppressedVisualEffects());
@@ -173,7 +173,7 @@ public class NotificationListenerServiceTest extends UiServiceTestCase {
tweak.getKey(),
tweak.getRank(),
!tweak.matchesInterruptionFilter(), // note the inversion here!
- tweak.getVisibilityOverride(),
+ tweak.getLockscreenVisibilityOverride(),
tweak.getSuppressedVisualEffects(),
tweak.getImportance(),
tweak.getImportanceExplanation(),
@@ -424,7 +424,7 @@ public class NotificationListenerServiceTest extends UiServiceTestCase {
assertEquals(comment, a.getKey(), b.getKey());
assertEquals(comment, a.getRank(), b.getRank());
assertEquals(comment, a.matchesInterruptionFilter(), b.matchesInterruptionFilter());
- assertEquals(comment, a.getVisibilityOverride(), b.getVisibilityOverride());
+ assertEquals(comment, a.getLockscreenVisibilityOverride(), b.getLockscreenVisibilityOverride());
assertEquals(comment, a.getSuppressedVisualEffects(), b.getSuppressedVisualEffects());
assertEquals(comment, a.getImportance(), b.getImportance());
assertEquals(comment, a.getImportanceExplanation(), b.getImportanceExplanation());
@@ -440,7 +440,8 @@ public class NotificationListenerServiceTest extends UiServiceTestCase {
assertEquals(comment, a.getSmartReplies(), b.getSmartReplies());
assertEquals(comment, a.canBubble(), b.canBubble());
assertEquals(comment, a.isConversation(), b.isConversation());
- assertEquals(comment, a.getConversationShortcutInfo().getId(), b.getConversationShortcutInfo().getId());
+ assertEquals(comment, a.getConversationShortcutInfo().getId(),
+ b.getConversationShortcutInfo().getId());
assertActionsEqual(a.getSmartActions(), b.getSmartActions());
}
diff --git a/services/tests/uiservicestests/src/com/android/server/notification/NotificationManagerServiceTest.java b/services/tests/uiservicestests/src/com/android/server/notification/NotificationManagerServiceTest.java
index 5cf529a239dc..762ec93712cb 100755
--- a/services/tests/uiservicestests/src/com/android/server/notification/NotificationManagerServiceTest.java
+++ b/services/tests/uiservicestests/src/com/android/server/notification/NotificationManagerServiceTest.java
@@ -183,6 +183,7 @@ import com.android.server.notification.NotificationManagerService.NotificationAs
import com.android.server.notification.NotificationManagerService.NotificationListeners;
import com.android.server.statusbar.StatusBarManagerInternal;
import com.android.server.uri.UriGrantsManagerInternal;
+import com.android.server.utils.quota.MultiRateLimiter;
import com.android.server.wm.ActivityTaskManagerInternal;
import com.android.server.wm.WindowManagerInternal;
@@ -295,6 +296,8 @@ public class NotificationManagerServiceTest extends UiServiceTestCase {
NotificationHistoryManager mHistoryManager;
@Mock
StatsManager mStatsManager;
+ @Mock
+ MultiRateLimiter mToastRateLimiter;
BroadcastReceiver mPackageIntentReceiver;
NotificationRecordLoggerFake mNotificationRecordLogger = new NotificationRecordLoggerFake();
private InstanceIdSequence mNotificationInstanceIdSequence = new InstanceIdSequenceFake(
@@ -486,7 +489,7 @@ public class NotificationManagerServiceTest extends UiServiceTestCase {
mGroupHelper, mAm, mAtm, mAppUsageStats,
mock(DevicePolicyManagerInternal.class), mUgm, mUgmInternal,
mAppOpsManager, mUm, mHistoryManager, mStatsManager,
- mock(TelephonyManager.class), mAmi);
+ mock(TelephonyManager.class), mAmi, mToastRateLimiter);
mService.onBootPhase(SystemService.PHASE_SYSTEM_SERVICES_READY);
mService.setAudioManager(mAudioManager);
@@ -566,7 +569,7 @@ public class NotificationManagerServiceTest extends UiServiceTestCase {
try {
mService.onDestroy();
- } catch (IllegalStateException e) {
+ } catch (IllegalStateException | IllegalArgumentException e) {
// can throw if a broadcast receiver was never registered
}
@@ -4888,6 +4891,7 @@ public class NotificationManagerServiceTest extends UiServiceTestCase {
final String testPackage = "testPackageName";
assertEquals(0, mService.mToastQueue.size());
mService.isSystemUid = false;
+ setToastRateIsWithinQuota(true);
// package is not suspended
when(mPackageManager.isPackageSuspendedForUser(testPackage, UserHandle.getUserId(mUid)))
@@ -4910,6 +4914,7 @@ public class NotificationManagerServiceTest extends UiServiceTestCase {
final String testPackage = "testPackageName";
assertEquals(0, mService.mToastQueue.size());
mService.isSystemUid = false;
+ setToastRateIsWithinQuota(true);
// package is not suspended
when(mPackageManager.isPackageSuspendedForUser(testPackage, UserHandle.getUserId(mUid)))
@@ -4928,6 +4933,7 @@ public class NotificationManagerServiceTest extends UiServiceTestCase {
final String testPackage = "testPackageName";
assertEquals(0, mService.mToastQueue.size());
mService.isSystemUid = false;
+ setToastRateIsWithinQuota(true);
// package is not suspended
when(mPackageManager.isPackageSuspendedForUser(testPackage, UserHandle.getUserId(mUid)))
@@ -4950,10 +4956,32 @@ public class NotificationManagerServiceTest extends UiServiceTestCase {
}
@Test
+ public void testToastRateLimiterCanPreventsShowCallForCustomToast() throws Exception {
+ final String testPackage = "testPackageName";
+ assertEquals(0, mService.mToastQueue.size());
+ mService.isSystemUid = false;
+ setToastRateIsWithinQuota(false); // rate limit reached
+
+ // package is not suspended
+ when(mPackageManager.isPackageSuspendedForUser(testPackage, UserHandle.getUserId(mUid)))
+ .thenReturn(false);
+
+ setAppInForegroundForToasts(mUid, true);
+
+ Binder token = new Binder();
+ ITransientNotification callback = mock(ITransientNotification.class);
+ INotificationManager nmService = (INotificationManager) mService.mService;
+
+ nmService.enqueueToast(testPackage, token, callback, 2000, 0);
+ verify(callback, times(0)).show(any());
+ }
+
+ @Test
public void testAllowForegroundTextToasts() throws Exception {
final String testPackage = "testPackageName";
assertEquals(0, mService.mToastQueue.size());
mService.isSystemUid = false;
+ setToastRateIsWithinQuota(true);
// package is not suspended
when(mPackageManager.isPackageSuspendedForUser(testPackage, UserHandle.getUserId(mUid)))
@@ -4972,6 +5000,7 @@ public class NotificationManagerServiceTest extends UiServiceTestCase {
final String testPackage = "testPackageName";
assertEquals(0, mService.mToastQueue.size());
mService.isSystemUid = false;
+ setToastRateIsWithinQuota(true);
// package is not suspended
when(mPackageManager.isPackageSuspendedForUser(testPackage, UserHandle.getUserId(mUid)))
@@ -4990,6 +5019,7 @@ public class NotificationManagerServiceTest extends UiServiceTestCase {
final String testPackage = "testPackageName";
assertEquals(0, mService.mToastQueue.size());
mService.isSystemUid = false;
+ setToastRateIsWithinQuota(true);
// package is not suspended
when(mPackageManager.isPackageSuspendedForUser(testPackage, UserHandle.getUserId(mUid)))
@@ -5013,11 +5043,31 @@ public class NotificationManagerServiceTest extends UiServiceTestCase {
}
@Test
+ public void testToastRateLimiterCanPreventsShowCallForTextToast() throws Exception {
+ final String testPackage = "testPackageName";
+ assertEquals(0, mService.mToastQueue.size());
+ mService.isSystemUid = false;
+ setToastRateIsWithinQuota(false); // rate limit reached
+
+ // package is not suspended
+ when(mPackageManager.isPackageSuspendedForUser(testPackage, UserHandle.getUserId(mUid)))
+ .thenReturn(false);
+
+ Binder token = new Binder();
+ INotificationManager nmService = (INotificationManager) mService.mService;
+
+ nmService.enqueueTextToast(testPackage, token, "Text", 2000, 0, null);
+ verify(mStatusBar, times(0))
+ .showToast(anyInt(), any(), any(), any(), any(), anyInt(), any());
+ }
+
+ @Test
public void backgroundSystemCustomToast_callsSetProcessImportantAsForegroundForToast() throws
Exception {
final String testPackage = "testPackageName";
assertEquals(0, mService.mToastQueue.size());
mService.isSystemUid = true;
+ setToastRateIsWithinQuota(true);
// package is not suspended
when(mPackageManager.isPackageSuspendedForUser(testPackage, UserHandle.getUserId(mUid)))
@@ -5042,6 +5092,7 @@ public class NotificationManagerServiceTest extends UiServiceTestCase {
final String testPackage = "testPackageName";
assertEquals(0, mService.mToastQueue.size());
mService.isSystemUid = false;
+ setToastRateIsWithinQuota(true);
// package is not suspended
when(mPackageManager.isPackageSuspendedForUser(testPackage, UserHandle.getUserId(mUid)))
@@ -5062,6 +5113,7 @@ public class NotificationManagerServiceTest extends UiServiceTestCase {
final String testPackage = "testPackageName";
assertEquals(0, mService.mToastQueue.size());
mService.isSystemUid = false;
+ setToastRateIsWithinQuota(true);
// package is not suspended
when(mPackageManager.isPackageSuspendedForUser(testPackage, UserHandle.getUserId(mUid)))
@@ -5081,6 +5133,7 @@ public class NotificationManagerServiceTest extends UiServiceTestCase {
final String testPackage = "testPackageName";
assertEquals(0, mService.mToastQueue.size());
mService.isSystemUid = false;
+ setToastRateIsWithinQuota(true);
// package is not suspended
when(mPackageManager.isPackageSuspendedForUser(testPackage, UserHandle.getUserId(mUid)))
@@ -5097,6 +5150,7 @@ public class NotificationManagerServiceTest extends UiServiceTestCase {
final String testPackage = "testPackageName";
assertEquals(0, mService.mToastQueue.size());
mService.isSystemUid = false;
+ setToastRateIsWithinQuota(true);
// package is suspended
when(mPackageManager.isPackageSuspendedForUser(testPackage, UserHandle.getUserId(mUid)))
@@ -5117,6 +5171,7 @@ public class NotificationManagerServiceTest extends UiServiceTestCase {
final String testPackage = "testPackageName";
assertEquals(0, mService.mToastQueue.size());
mService.isSystemUid = false;
+ setToastRateIsWithinQuota(true);
// package is not suspended
when(mPackageManager.isPackageSuspendedForUser(testPackage, UserHandle.getUserId(mUid)))
@@ -5139,6 +5194,7 @@ public class NotificationManagerServiceTest extends UiServiceTestCase {
final String testPackage = "testPackageName";
assertEquals(0, mService.mToastQueue.size());
mService.isSystemUid = true;
+ setToastRateIsWithinQuota(true);
// package is suspended
when(mPackageManager.isPackageSuspendedForUser(testPackage, UserHandle.getUserId(mUid)))
@@ -5161,6 +5217,7 @@ public class NotificationManagerServiceTest extends UiServiceTestCase {
final String testPackage = "testPackageName";
assertEquals(0, mService.mToastQueue.size());
mService.isSystemUid = false;
+ setToastRateIsWithinQuota(true);
// package is not suspended
when(mPackageManager.isPackageSuspendedForUser(testPackage, UserHandle.getUserId(mUid)))
@@ -5188,6 +5245,14 @@ public class NotificationManagerServiceTest extends UiServiceTestCase {
when(mAtm.hasResumedActivity(uid)).thenReturn(inForeground);
}
+ private void setToastRateIsWithinQuota(boolean isWithinQuota) {
+ when(mToastRateLimiter.isWithinQuota(
+ anyInt(),
+ anyString(),
+ eq(NotificationManagerService.TOAST_QUOTA_TAG)))
+ .thenReturn(isWithinQuota);
+ }
+
@Test
public void testOnPanelRevealedAndHidden() {
int items = 5;
diff --git a/services/tests/uiservicestests/src/com/android/server/notification/PreferencesHelperTest.java b/services/tests/uiservicestests/src/com/android/server/notification/PreferencesHelperTest.java
index 98c4a2da6a4f..4d2a4784b5d9 100644
--- a/services/tests/uiservicestests/src/com/android/server/notification/PreferencesHelperTest.java
+++ b/services/tests/uiservicestests/src/com/android/server/notification/PreferencesHelperTest.java
@@ -97,6 +97,7 @@ import android.test.suitebuilder.annotation.SmallTest;
import android.testing.TestableContentResolver;
import android.util.ArrayMap;
import android.util.ArraySet;
+import android.util.IntArray;
import android.util.Pair;
import android.util.StatsEvent;
import android.util.TypedXmlPullParser;
@@ -3320,7 +3321,8 @@ public class PreferencesHelperTest extends UiServiceTestCase {
channel2.setImportantConversation(true);
mHelper.createNotificationChannel(PKG_O, UID_O, channel2, true, false);
- List<ConversationChannelWrapper> convos = mHelper.getConversations(false);
+ List<ConversationChannelWrapper> convos =
+ mHelper.getConversations(IntArray.wrap(new int[] {0}), false);
assertEquals(3, convos.size());
assertTrue(conversationWrapperContainsChannel(convos, channel));
@@ -3329,6 +3331,44 @@ public class PreferencesHelperTest extends UiServiceTestCase {
}
@Test
+ public void testGetConversations_multiUser() {
+ String convoId = "convo";
+ NotificationChannel messages =
+ new NotificationChannel("messages", "Messages", IMPORTANCE_DEFAULT);
+ mHelper.createNotificationChannel(PKG_O, UID_O, messages, true, false);
+
+ NotificationChannel messagesUser10 =
+ new NotificationChannel("messages", "Messages", IMPORTANCE_DEFAULT);
+ mHelper.createNotificationChannel(
+ PKG_O, UID_O + UserHandle.PER_USER_RANGE, messagesUser10, true, false);
+
+ NotificationChannel messagesFromB =
+ new NotificationChannel("B person msgs", "messages from B", IMPORTANCE_DEFAULT);
+ messagesFromB.setConversationId(messages.getId(), "different convo");
+ mHelper.createNotificationChannel(PKG_O, UID_O, messagesFromB, true, false);
+
+ NotificationChannel messagesFromBUser10 =
+ new NotificationChannel("B person msgs", "messages from B", IMPORTANCE_DEFAULT);
+ messagesFromBUser10.setConversationId(messagesUser10.getId(), "different convo");
+ mHelper.createNotificationChannel(
+ PKG_O, UID_O + UserHandle.PER_USER_RANGE, messagesFromBUser10, true, false);
+
+
+ List<ConversationChannelWrapper> convos =
+ mHelper.getConversations(IntArray.wrap(new int[] {0}), false);
+
+ assertEquals(1, convos.size());
+ assertTrue(conversationWrapperContainsChannel(convos, messagesFromB));
+
+ convos =
+ mHelper.getConversations(IntArray.wrap(new int[] {0, UserHandle.getUserId(UID_O + UserHandle.PER_USER_RANGE)}), false);
+
+ assertEquals(2, convos.size());
+ assertTrue(conversationWrapperContainsChannel(convos, messagesFromB));
+ assertTrue(conversationWrapperContainsChannel(convos, messagesFromBUser10));
+ }
+
+ @Test
public void testGetConversations_notDemoted() {
String convoId = "convo";
NotificationChannel messages =
@@ -3358,7 +3398,8 @@ public class PreferencesHelperTest extends UiServiceTestCase {
channel2.setImportantConversation(true);
mHelper.createNotificationChannel(PKG_O, UID_O, channel2, true, false);
- List<ConversationChannelWrapper> convos = mHelper.getConversations(false);
+ List<ConversationChannelWrapper> convos =
+ mHelper.getConversations(IntArray.wrap(new int[] {0}), false);
assertEquals(2, convos.size());
assertTrue(conversationWrapperContainsChannel(convos, channel));
@@ -3396,7 +3437,8 @@ public class PreferencesHelperTest extends UiServiceTestCase {
channel2.setConversationId(calls.getId(), convoId);
mHelper.createNotificationChannel(PKG_O, UID_O, channel2, true, false);
- List<ConversationChannelWrapper> convos = mHelper.getConversations(true);
+ List<ConversationChannelWrapper> convos =
+ mHelper.getConversations(IntArray.wrap(new int[] {0}), true);
assertEquals(2, convos.size());
assertTrue(conversationWrapperContainsChannel(convos, channel));
diff --git a/services/tests/uiservicestests/src/com/android/server/notification/RoleObserverTest.java b/services/tests/uiservicestests/src/com/android/server/notification/RoleObserverTest.java
index a80f62ab09ee..4ce237e3aadc 100644
--- a/services/tests/uiservicestests/src/com/android/server/notification/RoleObserverTest.java
+++ b/services/tests/uiservicestests/src/com/android/server/notification/RoleObserverTest.java
@@ -67,6 +67,7 @@ import com.android.server.lights.LightsManager;
import com.android.server.notification.NotificationManagerService.NotificationAssistants;
import com.android.server.notification.NotificationManagerService.NotificationListeners;
import com.android.server.uri.UriGrantsManagerInternal;
+import com.android.server.utils.quota.MultiRateLimiter;
import com.android.server.wm.ActivityTaskManagerInternal;
import com.android.server.wm.WindowManagerInternal;
@@ -156,7 +157,8 @@ public class RoleObserverTest extends UiServiceTestCase {
mock(UriGrantsManagerInternal.class),
mock(AppOpsManager.class), mUm, mock(NotificationHistoryManager.class),
mock(StatsManager.class), mock(TelephonyManager.class),
- mock(ActivityManagerInternal.class));
+ mock(ActivityManagerInternal.class),
+ mock(MultiRateLimiter.class));
} catch (SecurityException e) {
if (!e.getMessage().contains("Permission Denial: not allowed to send broadcast")) {
throw e;
diff --git a/services/tests/uiservicestests/src/com/android/server/notification/VisibilityExtractorTest.java b/services/tests/uiservicestests/src/com/android/server/notification/VisibilityExtractorTest.java
new file mode 100644
index 000000000000..3998129659c6
--- /dev/null
+++ b/services/tests/uiservicestests/src/com/android/server/notification/VisibilityExtractorTest.java
@@ -0,0 +1,246 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.android.server.notification;
+
+import static android.app.Notification.VISIBILITY_PRIVATE;
+import static android.app.Notification.VISIBILITY_SECRET;
+import static android.app.NotificationManager.IMPORTANCE_DEFAULT;
+import static android.app.NotificationManager.IMPORTANCE_HIGH;
+import static android.app.NotificationManager.IMPORTANCE_UNSPECIFIED;
+import static android.app.NotificationManager.Policy.SUPPRESSED_EFFECT_BADGE;
+import static android.app.NotificationManager.Policy.SUPPRESSED_EFFECT_LIGHTS;
+import static android.app.NotificationManager.VISIBILITY_NO_OVERRIDE;
+import static android.app.admin.DevicePolicyManager.KEYGUARD_DISABLE_SECURE_NOTIFICATIONS;
+import static android.app.admin.DevicePolicyManager.KEYGUARD_DISABLE_UNREDACTED_NOTIFICATIONS;
+
+import static junit.framework.Assert.assertEquals;
+import static junit.framework.Assert.assertFalse;
+import static junit.framework.Assert.assertTrue;
+
+import static org.mockito.Mockito.when;
+
+import android.app.ActivityManager;
+import android.app.Notification;
+import android.app.Notification.Builder;
+import android.app.NotificationChannel;
+import android.app.PendingIntent;
+import android.app.admin.DevicePolicyManager;
+import android.content.Intent;
+import android.graphics.drawable.Icon;
+import android.media.session.MediaSession;
+import android.os.UserHandle;
+import android.service.notification.StatusBarNotification;
+import android.test.suitebuilder.annotation.SmallTest;
+
+import androidx.test.runner.AndroidJUnit4;
+
+import com.android.server.UiServiceTestCase;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.Mock;
+import org.mockito.MockitoAnnotations;
+
+@SmallTest
+@RunWith(AndroidJUnit4.class)
+public class VisibilityExtractorTest extends UiServiceTestCase {
+
+ @Mock RankingConfig mConfig;
+ @Mock
+ DevicePolicyManager mDpm;
+
+ private String mPkg = "com.android.server.notification";
+ private int mId = 1001;
+ private String mTag = null;
+ private int mUid = 1000;
+ private int mPid = 2000;
+ private int mUser = ActivityManager.getCurrentUser();
+
+ @Before
+ public void setUp() {
+ MockitoAnnotations.initMocks(this);
+ mContext.addMockSystemService(DevicePolicyManager.class, mDpm);
+ }
+
+ private NotificationRecord getNotificationRecord(int visibility) {
+ NotificationChannel channel = new NotificationChannel("a", "a", IMPORTANCE_DEFAULT);
+ channel.setLockscreenVisibility(visibility);
+ when(mConfig.getNotificationChannel(mPkg, mUid, "a", false)).thenReturn(channel);
+
+ final Builder builder = new Builder(getContext())
+ .setContentTitle("foo")
+ .setSmallIcon(android.R.drawable.sym_def_app_icon);
+
+ Notification n = builder.build();
+ StatusBarNotification sbn = new StatusBarNotification(mPkg, mPkg, mId, mTag, mUid,
+ mPid, n, UserHandle.of(mUser), null, System.currentTimeMillis());
+ NotificationRecord r = new NotificationRecord(getContext(), sbn, channel);
+ return r;
+ }
+
+ //
+ // Tests
+ //
+
+ @Test
+ public void testGlobalAllDpmAllChannelAll() {
+ VisibilityExtractor extractor = new VisibilityExtractor();
+ extractor.setConfig(mConfig);
+ extractor.initialize(mContext, null);
+
+ when(mConfig.canShowNotificationsOnLockscreen(mUser)).thenReturn(true);
+ when(mConfig.canShowPrivateNotificationsOnLockScreen(mUser)).thenReturn(true);
+
+ when(mDpm.getKeyguardDisabledFeatures(null, mUser)).thenReturn(0);
+
+ NotificationRecord r = getNotificationRecord(VISIBILITY_NO_OVERRIDE);
+
+ extractor.process(r);
+
+ assertEquals(VISIBILITY_NO_OVERRIDE, r.getPackageVisibilityOverride());
+ }
+
+ @Test
+ public void testGlobalNoneDpmAllChannelAll() {
+ VisibilityExtractor extractor = new VisibilityExtractor();
+ extractor.setConfig(mConfig);
+ extractor.initialize(mContext, null);
+
+ when(mConfig.canShowNotificationsOnLockscreen(mUser)).thenReturn(false);
+ when(mConfig.canShowPrivateNotificationsOnLockScreen(mUser)).thenReturn(true);
+
+ when(mDpm.getKeyguardDisabledFeatures(null, mUser)).thenReturn(0);
+
+ NotificationRecord r = getNotificationRecord(VISIBILITY_NO_OVERRIDE);
+
+ extractor.process(r);
+
+ assertEquals(VISIBILITY_SECRET, r.getPackageVisibilityOverride());
+ }
+
+ @Test
+ public void testGlobalSomeDpmAllChannelAll() {
+ VisibilityExtractor extractor = new VisibilityExtractor();
+ extractor.setConfig(mConfig);
+ extractor.initialize(mContext, null);
+
+ when(mConfig.canShowNotificationsOnLockscreen(mUser)).thenReturn(true);
+ when(mConfig.canShowPrivateNotificationsOnLockScreen(mUser)).thenReturn(false);
+
+ when(mDpm.getKeyguardDisabledFeatures(null, mUser)).thenReturn(0);
+
+ NotificationRecord r = getNotificationRecord(VISIBILITY_NO_OVERRIDE);
+
+ extractor.process(r);
+
+ assertEquals(VISIBILITY_PRIVATE, r.getPackageVisibilityOverride());
+ }
+
+ @Test
+ public void testGlobalAllDpmNoneChannelAll() {
+ VisibilityExtractor extractor = new VisibilityExtractor();
+ extractor.setConfig(mConfig);
+ extractor.initialize(mContext, null);
+
+ when(mConfig.canShowNotificationsOnLockscreen(mUser)).thenReturn(true);
+ when(mConfig.canShowPrivateNotificationsOnLockScreen(mUser)).thenReturn(true);
+
+ when(mDpm.getKeyguardDisabledFeatures(null, mUser)).thenReturn(
+ KEYGUARD_DISABLE_SECURE_NOTIFICATIONS);
+
+ NotificationRecord r = getNotificationRecord(VISIBILITY_NO_OVERRIDE);
+
+ extractor.process(r);
+
+ assertEquals(VISIBILITY_SECRET, r.getPackageVisibilityOverride());
+ }
+
+ @Test
+ public void testGlobalAllDpmSomeChannelAll() {
+ VisibilityExtractor extractor = new VisibilityExtractor();
+ extractor.setConfig(mConfig);
+ extractor.initialize(mContext, null);
+
+ when(mConfig.canShowNotificationsOnLockscreen(mUser)).thenReturn(true);
+ when(mConfig.canShowPrivateNotificationsOnLockScreen(mUser)).thenReturn(true);
+
+ when(mDpm.getKeyguardDisabledFeatures(null, mUser)).thenReturn(
+ KEYGUARD_DISABLE_UNREDACTED_NOTIFICATIONS);
+
+ NotificationRecord r = getNotificationRecord(VISIBILITY_NO_OVERRIDE);
+
+ extractor.process(r);
+
+ assertEquals(VISIBILITY_PRIVATE, r.getPackageVisibilityOverride());
+ }
+
+ @Test
+ public void testGlobalAllDpmAllChannelNone() {
+ VisibilityExtractor extractor = new VisibilityExtractor();
+ extractor.setConfig(mConfig);
+ extractor.initialize(mContext, null);
+
+ when(mConfig.canShowNotificationsOnLockscreen(mUser)).thenReturn(true);
+ when(mConfig.canShowPrivateNotificationsOnLockScreen(mUser)).thenReturn(true);
+
+ when(mDpm.getKeyguardDisabledFeatures(null, mUser)).thenReturn(0);
+
+ NotificationRecord r = getNotificationRecord(VISIBILITY_SECRET);
+
+ extractor.process(r);
+
+ assertEquals(VISIBILITY_SECRET, r.getPackageVisibilityOverride());
+ }
+
+ @Test
+ public void testGlobalAllDpmAllChannelSome() {
+ VisibilityExtractor extractor = new VisibilityExtractor();
+ extractor.setConfig(mConfig);
+ extractor.initialize(mContext, null);
+
+ when(mConfig.canShowNotificationsOnLockscreen(mUser)).thenReturn(true);
+ when(mConfig.canShowPrivateNotificationsOnLockScreen(mUser)).thenReturn(true);
+
+ when(mDpm.getKeyguardDisabledFeatures(null, mUser)).thenReturn(0);
+
+ NotificationRecord r = getNotificationRecord(VISIBILITY_PRIVATE);
+
+ extractor.process(r);
+
+ assertEquals(VISIBILITY_PRIVATE, r.getPackageVisibilityOverride());
+ }
+
+ @Test
+ public void testGlobalAllDpmSomeChannelNone() {
+ VisibilityExtractor extractor = new VisibilityExtractor();
+ extractor.setConfig(mConfig);
+ extractor.initialize(mContext, null);
+
+ when(mConfig.canShowNotificationsOnLockscreen(mUser)).thenReturn(true);
+ when(mConfig.canShowPrivateNotificationsOnLockScreen(mUser)).thenReturn(true);
+
+ when(mDpm.getKeyguardDisabledFeatures(null, mUser)).thenReturn(
+ KEYGUARD_DISABLE_UNREDACTED_NOTIFICATIONS);
+
+ NotificationRecord r = getNotificationRecord(VISIBILITY_SECRET);
+
+ extractor.process(r);
+
+ assertEquals(VISIBILITY_SECRET, r.getPackageVisibilityOverride());
+ }
+
+}
diff --git a/services/tests/wmtests/src/com/android/server/wm/DisplayAreaGroupTest.java b/services/tests/wmtests/src/com/android/server/wm/DisplayAreaGroupTest.java
index bc91c709aeb1..f536cd0b0ed4 100644
--- a/services/tests/wmtests/src/com/android/server/wm/DisplayAreaGroupTest.java
+++ b/services/tests/wmtests/src/com/android/server/wm/DisplayAreaGroupTest.java
@@ -61,7 +61,7 @@ public class DisplayAreaGroupTest extends WindowTestsBase {
mTaskDisplayArea = new TaskDisplayArea(
mDisplayContent, mWm, "TDA1", FEATURE_VENDOR_FIRST + 1);
mDisplayAreaGroup.addChild(mTaskDisplayArea, POSITION_TOP);
- mDisplayContent.setLastFocusedTaskDisplayArea(mTaskDisplayArea);
+ mDisplayContent.onLastFocusedTaskDisplayAreaChanged(mTaskDisplayArea);
}
@Test
diff --git a/services/tests/wmtests/src/com/android/server/wm/DisplayAreaPolicyBuilderTest.java b/services/tests/wmtests/src/com/android/server/wm/DisplayAreaPolicyBuilderTest.java
index 811ff4acb995..e47913fba7ab 100644
--- a/services/tests/wmtests/src/com/android/server/wm/DisplayAreaPolicyBuilderTest.java
+++ b/services/tests/wmtests/src/com/android/server/wm/DisplayAreaPolicyBuilderTest.java
@@ -47,6 +47,7 @@ import static org.testng.Assert.assertThrows;
import static java.util.stream.Collectors.toList;
import android.content.res.Resources;
+import android.os.Binder;
import android.os.Bundle;
import android.os.IBinder;
import android.platform.test.annotations.Presubmit;
@@ -585,8 +586,8 @@ public class DisplayAreaPolicyBuilderTest {
.setTaskDisplayAreas(mTaskDisplayAreaList))
.addDisplayAreaGroupHierarchy(hierarchy1)
.addDisplayAreaGroupHierarchy(hierarchy2)
- .setSelectRootForWindowFunc((token, options) -> {
- if (token.windowType == TYPE_STATUS_BAR) {
+ .setSelectRootForWindowFunc((type, options) -> {
+ if (type == TYPE_STATUS_BAR) {
return mGroupRoot1;
}
return mGroupRoot2;
@@ -740,10 +741,9 @@ public class DisplayAreaPolicyBuilderTest {
}
private WindowToken tokenOfType(int type) {
- WindowToken m = mock(WindowToken.class);
- when(m.getWindowLayerFromType()).thenReturn(
- mPolicy.getWindowLayerFromTypeLw(type, false /* canAddInternalSystemWindow */));
- return m;
+ WindowToken token = new WindowToken(mWms, new Binder(), type, false /* persistOnEmpty */,
+ mDisplayContent, false /* ownerCanManageAppTokens */);
+ return token;
}
private static void assertMatchLayerOrder(List<DisplayArea<?>> actualOrder,
diff --git a/services/tests/wmtests/src/com/android/server/wm/DisplayAreaTest.java b/services/tests/wmtests/src/com/android/server/wm/DisplayAreaTest.java
index 025c5a6bb180..6f5a874114ea 100644
--- a/services/tests/wmtests/src/com/android/server/wm/DisplayAreaTest.java
+++ b/services/tests/wmtests/src/com/android/server/wm/DisplayAreaTest.java
@@ -458,8 +458,7 @@ public class DisplayAreaTest extends WindowTestsBase {
@Test
public void testSetIgnoreOrientationRequest_notCallSuperOnDescendantOrientationChanged() {
- final TaskDisplayArea tda =
- mDisplayContent.getDefaultTaskDisplayArea();
+ final TaskDisplayArea tda = mDisplayContent.getDefaultTaskDisplayArea();
final Task stack =
new TaskBuilder(mSupervisor).setOnTop(!ON_TOP).setCreateActivity(true).build();
final ActivityRecord activity = stack.getTopNonFinishingActivity();
@@ -478,6 +477,27 @@ public class DisplayAreaTest extends WindowTestsBase {
verify(mDisplayContent).onDescendantOrientationChanged(any());
}
+ @Test
+ public void testSetIgnoreOrientationRequest_updateOrientationRequestingTaskDisplayArea() {
+ final TaskDisplayArea tda = mDisplayContent.getDefaultTaskDisplayArea();
+ final Task stack =
+ new TaskBuilder(mSupervisor).setOnTop(!ON_TOP).setCreateActivity(true).build();
+ final ActivityRecord activity = stack.getTopNonFinishingActivity();
+
+ mDisplayContent.setFocusedApp(activity);
+ assertThat(mDisplayContent.getOrientationRequestingTaskDisplayArea()).isEqualTo(tda);
+
+ // TDA is no longer handling orientation request, clear the last focused TDA.
+ tda.setIgnoreOrientationRequest(true /* ignoreOrientationRequest */);
+
+ assertThat(mDisplayContent.getOrientationRequestingTaskDisplayArea()).isNull();
+
+ // TDA now handles orientation request, update last focused TDA based on the focused app.
+ tda.setIgnoreOrientationRequest(false /* ignoreOrientationRequest */);
+
+ assertThat(mDisplayContent.getOrientationRequestingTaskDisplayArea()).isEqualTo(tda);
+ }
+
private static class TestDisplayArea<T extends WindowContainer> extends DisplayArea<T> {
private TestDisplayArea(WindowManagerService wms, Rect bounds) {
super(wms, ANY, "half display area");
diff --git a/services/tests/wmtests/src/com/android/server/wm/DualDisplayAreaGroupPolicyTest.java b/services/tests/wmtests/src/com/android/server/wm/DualDisplayAreaGroupPolicyTest.java
index 73e886f67cd3..eebc207d2d4f 100644
--- a/services/tests/wmtests/src/com/android/server/wm/DualDisplayAreaGroupPolicyTest.java
+++ b/services/tests/wmtests/src/com/android/server/wm/DualDisplayAreaGroupPolicyTest.java
@@ -110,7 +110,7 @@ public class DualDisplayAreaGroupPolicyTest extends WindowTestsBase {
@Test
public void testNotIgnoreOrientationRequest_differentOrientationFromDisplay_reversesRequest() {
mFirstRoot.setIgnoreOrientationRequest(false /* ignoreOrientationRequest */);
- mDisplay.setLastFocusedTaskDisplayArea(mFirstTda);
+ mDisplay.onLastFocusedTaskDisplayAreaChanged(mFirstTda);
prepareUnresizable(mFirstActivity, SCREEN_ORIENTATION_LANDSCAPE);
@@ -127,7 +127,7 @@ public class DualDisplayAreaGroupPolicyTest extends WindowTestsBase {
public void testNotIgnoreOrientationRequest_onlyRespectsFocusedTaskDisplayArea() {
mFirstRoot.setIgnoreOrientationRequest(false /* ignoreOrientationRequest */);
mSecondRoot.setIgnoreOrientationRequest(false /* ignoreOrientationRequest */);
- mDisplay.setLastFocusedTaskDisplayArea(mFirstTda);
+ mDisplay.onLastFocusedTaskDisplayAreaChanged(mFirstTda);
// Second TDA is not focused, so Display won't get the request
prepareUnresizable(mSecondActivity, SCREEN_ORIENTATION_LANDSCAPE);
@@ -144,7 +144,7 @@ public class DualDisplayAreaGroupPolicyTest extends WindowTestsBase {
public void testIgnoreOrientationRequest_displayDoesNotReceiveOrientationChange() {
mFirstRoot.setIgnoreOrientationRequest(true /* ignoreOrientationRequest */);
mSecondRoot.setIgnoreOrientationRequest(true /* ignoreOrientationRequest */);
- mDisplay.setLastFocusedTaskDisplayArea(mFirstTda);
+ mDisplay.onLastFocusedTaskDisplayAreaChanged(mFirstTda);
prepareUnresizable(mFirstActivity, SCREEN_ORIENTATION_LANDSCAPE);
@@ -156,7 +156,7 @@ public class DualDisplayAreaGroupPolicyTest extends WindowTestsBase {
public void testLaunchPortraitApp_fillsDisplayAreaGroup() {
mFirstRoot.setIgnoreOrientationRequest(true /* ignoreOrientationRequest */);
mSecondRoot.setIgnoreOrientationRequest(true /* ignoreOrientationRequest */);
- mDisplay.setLastFocusedTaskDisplayArea(mFirstTda);
+ mDisplay.onLastFocusedTaskDisplayAreaChanged(mFirstTda);
prepareUnresizable(mFirstActivity, SCREEN_ORIENTATION_PORTRAIT);
final Rect dagBounds = new Rect(mFirstRoot.getBounds());
@@ -174,7 +174,7 @@ public class DualDisplayAreaGroupPolicyTest extends WindowTestsBase {
public void testLaunchPortraitApp_sizeCompatAfterRotation() {
mFirstRoot.setIgnoreOrientationRequest(true /* ignoreOrientationRequest */);
mSecondRoot.setIgnoreOrientationRequest(true /* ignoreOrientationRequest */);
- mDisplay.setLastFocusedTaskDisplayArea(mFirstTda);
+ mDisplay.onLastFocusedTaskDisplayAreaChanged(mFirstTda);
prepareUnresizable(mFirstActivity, SCREEN_ORIENTATION_PORTRAIT);
final Rect dagBounds = new Rect(mFirstRoot.getBounds());
@@ -207,7 +207,7 @@ public class DualDisplayAreaGroupPolicyTest extends WindowTestsBase {
public void testLaunchLandscapeApp_taskIsLetterboxInDisplayAreaGroup() {
mFirstRoot.setIgnoreOrientationRequest(true /* ignoreOrientationRequest */);
mSecondRoot.setIgnoreOrientationRequest(true /* ignoreOrientationRequest */);
- mDisplay.setLastFocusedTaskDisplayArea(mFirstTda);
+ mDisplay.onLastFocusedTaskDisplayAreaChanged(mFirstTda);
prepareUnresizable(mFirstActivity, SCREEN_ORIENTATION_LANDSCAPE);
final Rect dagBounds = new Rect(mFirstRoot.getBounds());
@@ -227,7 +227,7 @@ public class DualDisplayAreaGroupPolicyTest extends WindowTestsBase {
public void testLaunchLandscapeApp_taskLetterboxBecomesActivityLetterboxAfterRotation() {
mFirstRoot.setIgnoreOrientationRequest(true /* ignoreOrientationRequest */);
mSecondRoot.setIgnoreOrientationRequest(true /* ignoreOrientationRequest */);
- mDisplay.setLastFocusedTaskDisplayArea(mFirstTda);
+ mDisplay.onLastFocusedTaskDisplayAreaChanged(mFirstTda);
prepareUnresizable(mFirstActivity, SCREEN_ORIENTATION_LANDSCAPE);
final Rect dagBounds = new Rect(mFirstRoot.getBounds());
diff --git a/services/tests/wmtests/src/com/android/server/wm/SystemServicesTestRule.java b/services/tests/wmtests/src/com/android/server/wm/SystemServicesTestRule.java
index 83e3d22345e1..e1bc90a2551c 100644
--- a/services/tests/wmtests/src/com/android/server/wm/SystemServicesTestRule.java
+++ b/services/tests/wmtests/src/com/android/server/wm/SystemServicesTestRule.java
@@ -325,7 +325,7 @@ public class SystemServicesTestRule implements TestRule {
final TaskDisplayArea taskDisplayArea = display.getDefaultTaskDisplayArea();
// Set the default focused TDA.
- display.setLastFocusedTaskDisplayArea(taskDisplayArea);
+ display.onLastFocusedTaskDisplayAreaChanged(taskDisplayArea);
spyOn(taskDisplayArea);
final Task homeStack = taskDisplayArea.getRootTask(
WINDOWING_MODE_FULLSCREEN, ACTIVITY_TYPE_HOME);
diff --git a/services/tests/wmtests/src/com/android/server/wm/TaskDisplayAreaTests.java b/services/tests/wmtests/src/com/android/server/wm/TaskDisplayAreaTests.java
index d80f81642474..1c93e0f7e185 100644
--- a/services/tests/wmtests/src/com/android/server/wm/TaskDisplayAreaTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/TaskDisplayAreaTests.java
@@ -262,20 +262,50 @@ public class TaskDisplayAreaTests extends WindowTestsBase {
// Activity on TDA1 is focused
mDisplayContent.setFocusedApp(firstActivity);
- assertThat(firstTaskDisplayArea.isLastFocused()).isTrue();
- assertThat(secondTaskDisplayArea.isLastFocused()).isFalse();
+ assertThat(firstTaskDisplayArea.canSpecifyOrientation()).isTrue();
+ assertThat(secondTaskDisplayArea.canSpecifyOrientation()).isFalse();
// No focused app, TDA1 is still recorded as last focused.
mDisplayContent.setFocusedApp(null);
- assertThat(firstTaskDisplayArea.isLastFocused()).isTrue();
- assertThat(secondTaskDisplayArea.isLastFocused()).isFalse();
+ assertThat(firstTaskDisplayArea.canSpecifyOrientation()).isTrue();
+ assertThat(secondTaskDisplayArea.canSpecifyOrientation()).isFalse();
// Activity on TDA2 is focused
mDisplayContent.setFocusedApp(secondActivity);
- assertThat(firstTaskDisplayArea.isLastFocused()).isFalse();
- assertThat(secondTaskDisplayArea.isLastFocused()).isTrue();
+ assertThat(firstTaskDisplayArea.canSpecifyOrientation()).isFalse();
+ assertThat(secondTaskDisplayArea.canSpecifyOrientation()).isTrue();
+ }
+
+ @Test
+ public void testIsLastFocused_onlyCountIfTaskDisplayAreaHandlesOrientationRequest() {
+ final TaskDisplayArea firstTaskDisplayArea = mDisplayContent.getDefaultTaskDisplayArea();
+ final TaskDisplayArea secondTaskDisplayArea = createTaskDisplayArea(
+ mDisplayContent, mRootWindowContainer.mWmService, "TestTaskDisplayArea",
+ FEATURE_VENDOR_FIRST);
+ final Task firstStack = firstTaskDisplayArea.createRootTask(
+ WINDOWING_MODE_FULLSCREEN, ACTIVITY_TYPE_STANDARD, false /* onTop */);
+ final Task secondStack = secondTaskDisplayArea.createRootTask(
+ WINDOWING_MODE_FULLSCREEN, ACTIVITY_TYPE_STANDARD, false /* onTop */);
+ final ActivityRecord firstActivity = new ActivityBuilder(mAtm)
+ .setTask(firstStack).build();
+ final ActivityRecord secondActivity = new ActivityBuilder(mAtm)
+ .setTask(secondStack).build();
+ firstTaskDisplayArea.setIgnoreOrientationRequest(true /* ignoreOrientationRequest */);
+ secondTaskDisplayArea.setIgnoreOrientationRequest(false /* ignoreOrientationRequest */);
+
+ // Activity on TDA1 is focused, but TDA1 doesn't respect orientation request
+ mDisplayContent.setFocusedApp(firstActivity);
+
+ assertThat(firstTaskDisplayArea.canSpecifyOrientation()).isFalse();
+ assertThat(secondTaskDisplayArea.canSpecifyOrientation()).isFalse();
+
+ // Activity on TDA2 is focused, and TDA2 respects orientation request
+ mDisplayContent.setFocusedApp(secondActivity);
+
+ assertThat(firstTaskDisplayArea.canSpecifyOrientation()).isFalse();
+ assertThat(secondTaskDisplayArea.canSpecifyOrientation()).isTrue();
}
@Test
diff --git a/services/tests/wmtests/src/com/android/server/wm/TestDisplayContent.java b/services/tests/wmtests/src/com/android/server/wm/TestDisplayContent.java
index b1065914a925..ae85ceb72958 100644
--- a/services/tests/wmtests/src/com/android/server/wm/TestDisplayContent.java
+++ b/services/tests/wmtests/src/com/android/server/wm/TestDisplayContent.java
@@ -161,7 +161,7 @@ class TestDisplayContent extends DisplayContent {
mService.mRootWindowContainer.addChild(newDisplay, mPosition);
// Set the default focused TDA.
- newDisplay.setLastFocusedTaskDisplayArea(newDisplay.getDefaultTaskDisplayArea());
+ newDisplay.onLastFocusedTaskDisplayAreaChanged(newDisplay.getDefaultTaskDisplayArea());
return newDisplay;
}
diff --git a/services/tests/wmtests/src/com/android/server/wm/WindowContainerTests.java b/services/tests/wmtests/src/com/android/server/wm/WindowContainerTests.java
index c4bcfdbcf89d..b0b8afd6c3a4 100644
--- a/services/tests/wmtests/src/com/android/server/wm/WindowContainerTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/WindowContainerTests.java
@@ -948,6 +948,36 @@ public class WindowContainerTests extends WindowTestsBase {
assertFalse(act.isAnimating(PARENTS));
}
+ @Test
+ public void testRegisterWindowContainerListener() {
+ final WindowContainer container = new WindowContainer(mWm);
+ container.mDisplayContent = mDisplayContent;
+ final TestWindowContainerListener listener = new TestWindowContainerListener();
+ Configuration config = container.getConfiguration();
+ Rect bounds = new Rect(0, 0, 10, 10);
+ config.windowConfiguration.setBounds(bounds);
+ config.densityDpi = 100;
+ container.onRequestedOverrideConfigurationChanged(config);
+ container.registerWindowContainerListener(listener);
+
+ assertEquals(mDisplayContent, listener.mDisplayContent);
+ assertEquals(bounds, listener.mConfiguration.windowConfiguration.getBounds());
+ assertEquals(100, listener.mConfiguration.densityDpi);
+
+ container.onDisplayChanged(mDefaultDisplay);
+ assertEquals(listener.mDisplayContent, mDefaultDisplay);
+
+ config = new Configuration();
+ bounds = new Rect(0, 0, 20, 20);
+ config.windowConfiguration.setBounds(bounds);
+ config.densityDpi = 200;
+
+ container.onRequestedOverrideConfigurationChanged(config);
+
+ assertEquals(bounds, listener.mConfiguration.windowConfiguration.getBounds());
+ assertEquals(200, listener.mConfiguration.densityDpi);
+ }
+
/* Used so we can gain access to some protected members of the {@link WindowContainer} class */
private static class TestWindowContainer extends WindowContainer<TestWindowContainer> {
private final int mLayer;
@@ -1131,4 +1161,19 @@ public class WindowContainerTests extends WindowTestsBase {
mSession.kill();
}
}
+
+ private static class TestWindowContainerListener implements WindowContainerListener {
+ private Configuration mConfiguration = new Configuration();
+ private DisplayContent mDisplayContent;
+
+ @Override
+ public void onRequestedOverrideConfigurationChanged(Configuration overrideConfiguration) {
+ mConfiguration.setTo(overrideConfiguration);
+ }
+
+ @Override
+ public void onDisplayChanged(DisplayContent dc) {
+ mDisplayContent = dc;
+ }
+ }
}
diff --git a/services/tests/wmtests/src/com/android/server/wm/WindowContextListenerControllerTests.java b/services/tests/wmtests/src/com/android/server/wm/WindowContextListenerControllerTests.java
new file mode 100644
index 000000000000..67067ee08e41
--- /dev/null
+++ b/services/tests/wmtests/src/com/android/server/wm/WindowContextListenerControllerTests.java
@@ -0,0 +1,173 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.server.wm;
+
+import static android.view.Display.DEFAULT_DISPLAY;
+import static android.view.WindowManager.LayoutParams.TYPE_APPLICATION_OVERLAY;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertTrue;
+
+import android.app.IWindowToken;
+import android.content.res.Configuration;
+import android.graphics.Rect;
+import android.os.Binder;
+import android.os.IBinder;
+import android.platform.test.annotations.Presubmit;
+
+import androidx.test.filters.SmallTest;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+/**
+ * Build/Install/Run:
+ * atest WmTests:WindowContextListenerControllerTests
+ */
+@SmallTest
+@Presubmit
+@RunWith(WindowTestRunner.class)
+public class WindowContextListenerControllerTests extends WindowTestsBase {
+ private WindowContextListenerController mController;
+
+ private static final int TEST_UID = 12345;
+ private static final int ANOTHER_UID = 1000;
+
+ private final IBinder mClientToken = new Binder();
+ private WindowContainer mContainer;
+
+ @Before
+ public void setUp() {
+ mController = new WindowContextListenerController();
+ mContainer = createTestWindowToken(TYPE_APPLICATION_OVERLAY, mDisplayContent);
+ }
+
+ @Test
+ public void testRegisterWindowContextListener() {
+ mController.registerWindowContainerListener(mClientToken, mContainer, -1);
+
+ assertEquals(1, mController.mListeners.size());
+
+ final IBinder clientToken = new Binder();
+ mController.registerWindowContainerListener(clientToken, mContainer, -1);
+
+ assertEquals(2, mController.mListeners.size());
+
+ final WindowContainer container = createTestWindowToken(TYPE_APPLICATION_OVERLAY,
+ mDefaultDisplay);
+ mController.registerWindowContainerListener(mClientToken, container, -1);
+
+ // The number of listeners doesn't increase since the listener just gets updated.
+ assertEquals(2, mController.mListeners.size());
+
+ WindowContextListenerController.WindowContextListenerImpl listener =
+ mController.mListeners.get(mClientToken);
+ assertEquals(container, listener.getWindowContainer());
+ }
+
+ @Test
+ public void testRegisterWindowContextListenerClientConfigPropagation() {
+ final TestWindowTokenClient clientToken = new TestWindowTokenClient();
+
+ final Configuration config1 = mContainer.getConfiguration();
+ final Rect bounds1 = new Rect(0, 0, 10, 10);
+ config1.windowConfiguration.setBounds(bounds1);
+ config1.densityDpi = 100;
+ mContainer.onRequestedOverrideConfigurationChanged(config1);
+
+ mController.registerWindowContainerListener(clientToken, mContainer, -1);
+
+ assertEquals(bounds1, clientToken.mConfiguration.windowConfiguration.getBounds());
+ assertEquals(config1.densityDpi, clientToken.mConfiguration.densityDpi);
+ assertEquals(mDisplayContent.mDisplayId, clientToken.mDisplayId);
+
+ // Update the WindowContainer.
+ final WindowContainer container = createTestWindowToken(TYPE_APPLICATION_OVERLAY,
+ mDefaultDisplay);
+ final Configuration config2 = container.getConfiguration();
+ final Rect bounds2 = new Rect(0, 0, 20, 20);
+ config2.windowConfiguration.setBounds(bounds2);
+ config2.densityDpi = 200;
+ container.onRequestedOverrideConfigurationChanged(config2);
+
+ mController.registerWindowContainerListener(clientToken, container, -1);
+
+ assertEquals(bounds2, clientToken.mConfiguration.windowConfiguration.getBounds());
+ assertEquals(config2.densityDpi, clientToken.mConfiguration.densityDpi);
+ assertEquals(DEFAULT_DISPLAY, clientToken.mDisplayId);
+
+ // Update the configuration of WindowContainer.
+ container.onRequestedOverrideConfigurationChanged(config1);
+
+ assertEquals(bounds1, clientToken.mConfiguration.windowConfiguration.getBounds());
+ assertEquals(config1.densityDpi, clientToken.mConfiguration.densityDpi);
+
+ // Update the display of WindowContainer.
+ container.onDisplayChanged(mDisplayContent);
+
+ assertEquals(mDisplayContent.mDisplayId, clientToken.mDisplayId);
+ }
+
+ @Test
+ public void testCanCallerRemoveListener_NullListener_ReturnFalse() {
+ assertFalse(mController.assertCallerCanRemoveListener(mClientToken,
+ true /* callerCanManagerAppTokens */, TEST_UID));
+ }
+
+ @Test
+ public void testCanCallerRemoveListener_CanManageAppTokens_ReturnTrue() {
+ mController.registerWindowContainerListener(mClientToken, mContainer, TEST_UID);
+
+ assertTrue(mController.assertCallerCanRemoveListener(mClientToken,
+ true /* callerCanManagerAppTokens */, ANOTHER_UID));
+ }
+
+ @Test
+ public void testCanCallerRemoveListener_SameUid_ReturnTrue() {
+ mController.registerWindowContainerListener(mClientToken, mContainer, TEST_UID);
+
+ assertTrue(mController.assertCallerCanRemoveListener(mClientToken,
+ false /* callerCanManagerAppTokens */, TEST_UID));
+ }
+
+ @Test(expected = UnsupportedOperationException.class)
+ public void testCanCallerRemoveListener_DifferentUid_ThrowException() {
+ mController.registerWindowContainerListener(mClientToken, mContainer, TEST_UID);
+
+ mController.assertCallerCanRemoveListener(mClientToken,
+ false /* callerCanManagerAppTokens */, ANOTHER_UID);
+ }
+
+ private class TestWindowTokenClient extends IWindowToken.Stub {
+ private Configuration mConfiguration;
+ private int mDisplayId;
+ private boolean mRemoved;
+
+ @Override
+ public void onConfigurationChanged(Configuration configuration, int displayId) {
+ mConfiguration = configuration;
+ mDisplayId = displayId;
+ }
+
+ @Override
+ public void onWindowTokenRemoved() {
+ mRemoved = true;
+ }
+ }
+}
diff --git a/services/tests/wmtests/src/com/android/server/wm/WindowTokenTests.java b/services/tests/wmtests/src/com/android/server/wm/WindowTokenTests.java
index e0785c13a336..462df300fdfd 100644
--- a/services/tests/wmtests/src/com/android/server/wm/WindowTokenTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/WindowTokenTests.java
@@ -231,7 +231,7 @@ public class WindowTokenTests extends WindowTestsBase {
@Test
public void testWindowAttachedWithOptions() {
- BiFunction<WindowToken, Bundle, RootDisplayArea> selectFunc =
+ BiFunction<Integer, Bundle, RootDisplayArea> selectFunc =
((DisplayAreaPolicyBuilder.Result) mDisplayContent.mDisplayAreaPolicy)
.mSelectRootForWindowFunc;
spyOn(selectFunc);
@@ -241,7 +241,7 @@ public class WindowTokenTests extends WindowTestsBase {
true /* ownerCanManageAppTokens */, INVALID_UID, true /* roundedCornerOverlay */,
false /* fromClientToken */, null /* options */);
- verify(selectFunc).apply(token1, null);
+ verify(selectFunc).apply(token1.windowType, null);
final Bundle options = new Bundle();
final WindowToken token2 = new WindowToken(mDisplayContent.mWmService, mock(IBinder.class),
@@ -249,6 +249,6 @@ public class WindowTokenTests extends WindowTestsBase {
true /* ownerCanManageAppTokens */, INVALID_UID, true /* roundedCornerOverlay */,
false /* fromClientToken */, options /* options */);
- verify(selectFunc).apply(token2, options);
+ verify(selectFunc).apply(token2.windowType, options);
}
}
diff --git a/startop/iorap/src/com/google/android/startop/iorap/IorapForwardingService.java b/startop/iorap/src/com/google/android/startop/iorap/IorapForwardingService.java
index 3104c7e7e0a1..1a0e5269d51a 100644
--- a/startop/iorap/src/com/google/android/startop/iorap/IorapForwardingService.java
+++ b/startop/iorap/src/com/google/android/startop/iorap/IorapForwardingService.java
@@ -34,6 +34,7 @@ import android.os.Parcel;
import android.os.RemoteException;
import android.os.ServiceManager;
import android.os.SystemProperties;
+import android.provider.DeviceConfig;
import android.util.ArraySet;
import android.util.Log;
@@ -42,15 +43,20 @@ import com.android.server.IoThread;
import com.android.server.LocalServices;
import com.android.server.SystemService;
import com.android.server.pm.BackgroundDexOptService;
+import com.android.server.pm.PackageManagerService;
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;
+import java.time.Duration;
import java.util.ArrayList;
import java.util.concurrent.TimeUnit;
+import java.util.concurrent.atomic.AtomicBoolean;
+import java.util.function.BooleanSupplier;
import java.util.HashMap;
+import java.util.List;
/**
* System-server-local proxy into the {@code IIorap} native service.
@@ -65,6 +71,7 @@ public class IorapForwardingService extends SystemService {
/** $> adb shell 'setprop iorapd.forwarding_service.wtf_crash true' */
private static boolean WTF_CRASH = SystemProperties.getBoolean(
"iorapd.forwarding_service.wtf_crash", false);
+ private static final Duration TIMEOUT = Duration.ofSeconds(600L);
// "Unique" job ID from the service name. Also equal to 283673059.
public static final int JOB_ID_IORAPD = encodeEnglishAlphabetStringIntoInt("iorapd");
@@ -80,6 +87,12 @@ public class IorapForwardingService extends SystemService {
private volatile IorapdJobService mJobService; // Write-once (null -> non-null forever).
private volatile static IorapForwardingService sSelfService; // Write once (null -> non-null).
+
+ /**
+ * Atomics set to true if the JobScheduler requests an abort.
+ */
+ private final AtomicBoolean mAbortIdleCompilation = new AtomicBoolean(false);
+
/**
* Initializes the system service.
* <p>
@@ -154,9 +167,27 @@ public class IorapForwardingService extends SystemService {
@VisibleForTesting
protected boolean isIorapEnabled() {
+ // These two mendel flags should match those in iorapd native process
+ // system/iorapd/src/common/property.h
+ boolean isTracingEnabled =
+ getMendelFlag("iorap_perfetto_enable", "iorapd.perfetto.enable", false);
+ boolean isReadAheadEnabled =
+ getMendelFlag("iorap_readahead_enable", "iorapd.readahead.enable", false);
// Same as the property in iorapd.rc -- disabling this will mean the 'iorapd' binder process
// never comes up, so all binder connections will fail indefinitely.
- return IS_ENABLED;
+ return IS_ENABLED && (isTracingEnabled || isReadAheadEnabled);
+ }
+
+ private boolean getMendelFlag(String mendelFlag, String sysProperty, boolean defaultValue) {
+ // TODO(yawanng) use DeviceConfig to get mendel property.
+ // DeviceConfig doesn't work and the reason is not clear.
+ // Provider service is already up before IORapForwardService.
+ String mendelProperty = "persist.device_config."
+ + DeviceConfig.NAMESPACE_RUNTIME_NATIVE_BOOT
+ + "."
+ + mendelFlag;
+ return SystemProperties.getBoolean(mendelProperty,
+ SystemProperties.getBoolean(sysProperty, defaultValue));
}
//</editor-fold>
@@ -239,7 +270,9 @@ public class IorapForwardingService extends SystemService {
//
// TODO: it would be good to get nodified of 'adb shell stop iorapd' to avoid
// printing this warning.
- Log.w(TAG, "Failed to connect to iorapd, is it down? Delay for " + sleepTime);
+ if (DEBUG) {
+ Log.v(TAG, "Failed to connect to iorapd, is it down? Delay for " + sleepTime);
+ }
// Use a handler instead of Thread#sleep to avoid backing up the binder thread
// when this is called from the death recipient callback.
@@ -275,7 +308,9 @@ public class IorapForwardingService extends SystemService {
// Connect to the native binder service.
mIorapRemote = provideIorapRemote();
if (mIorapRemote == null) {
- Log.e(TAG, "connectToRemoteAndConfigure - null iorap remote. check for Log.wtf?");
+ if (DEBUG) {
+ Log.e(TAG, "connectToRemoteAndConfigure - null iorap remote. check for Log.wtf?");
+ }
return false;
}
invokeRemote(mIorapRemote,
@@ -542,32 +577,86 @@ public class IorapForwardingService extends SystemService {
// Tell iorapd to start a background job.
Log.d(TAG, "Starting background job: " + params.toString());
- // We wait until that job's sequence ID returns to us with 'Completed',
- RequestId request;
- synchronized (mLock) {
- // TODO: would be cleaner if we got the request from the 'invokeRemote' function.
- // Better yet, consider a Pair<RequestId, Future<TaskResult>> or similar.
- request = RequestId.nextValueForSequence();
- mRunningJobs.put(request, params);
- }
+ mAbortIdleCompilation.set(false);
+ // PackageManagerService starts before IORap service.
+ PackageManagerService pm = (PackageManagerService)ServiceManager.getService("package");
+ List<String> pkgs = pm.getAllPackages();
+ runIdleCompilationAsync(params, pkgs);
+ return true;
+ }
- if (!invokeRemote(mIorapRemote, (IIorap remote) ->
- remote.onJobScheduledEvent(request,
- JobScheduledEvent.createIdleMaintenance(
- JobScheduledEvent.TYPE_START_JOB,
- params))
- )) {
- synchronized (mLock) {
- mRunningJobs.remove(request); // Avoid memory leaks.
+ private void runIdleCompilationAsync(final JobParameters params, final List<String> pkgs) {
+ new Thread("IORap_IdleCompilation") {
+ @Override
+ public void run() {
+ for (int i = 0; i < pkgs.size(); i++) {
+ String pkg = pkgs.get(i);
+ if (mAbortIdleCompilation.get()) {
+ Log.i(TAG, "The idle compilation is aborted");
+ return;
+ }
+
+ // We wait until that job's sequence ID returns to us with 'Completed',
+ RequestId request;
+ synchronized (mLock) {
+ // TODO: would be cleaner if we got the request from the
+ // 'invokeRemote' function. Better yet, consider
+ // a Pair<RequestId, Future<TaskResult>> or similar.
+ request = RequestId.nextValueForSequence();
+ mRunningJobs.put(request, params);
+ }
+
+ Log.i(TAG, String.format("IORap compile package: %s, [%d/%d]",
+ pkg, i + 1, pkgs.size()));
+ boolean shouldUpdateVersions = (i == 0);
+ if (!invokeRemote(mIorapRemote, (IIorap remote) ->
+ remote.onJobScheduledEvent(request,
+ JobScheduledEvent.createIdleMaintenance(
+ JobScheduledEvent.TYPE_START_JOB,
+ params,
+ pkg,
+ shouldUpdateVersions)))) {
+ synchronized (mLock) {
+ mRunningJobs.remove(request); // Avoid memory leaks.
+ }
+ }
+
+ // Wait until the job is complete and removed from the running jobs.
+ retryWithTimeout(TIMEOUT, () -> {
+ synchronized (mLock) {
+ return !mRunningJobs.containsKey(request);
+ }
+ });
+ }
+
+ // Finish the job after all packages are compiled.
+ if (mProxy != null) {
+ mProxy.jobFinished(params, /*reschedule*/false);
+ }
}
+ }.start();
+ }
- // Something went wrong on the remote side. Treat the job as being
- // 'already finished' (i.e. immediately release wake lock).
- return false;
- }
+ /** Retry until timeout. */
+ private boolean retryWithTimeout(final Duration timeout, BooleanSupplier supplier) {
+ long totalSleepTimeMs = 0L;
+ long sleepIntervalMs = 10L;
+ while (true) {
+ if (supplier.getAsBoolean()) {
+ return true;
+ }
+ try {
+ TimeUnit.MILLISECONDS.sleep(sleepIntervalMs);
+ } catch (InterruptedException e) {
+ Log.e(TAG, e.getMessage());
+ return false;
+ }
- // True -> keep the wakelock acquired until #jobFinished is called.
- return true;
+ totalSleepTimeMs += sleepIntervalMs;
+ if (totalSleepTimeMs > timeout.toMillis()) {
+ return false;
+ }
+ }
}
// Called by system to prematurely stop the job.
@@ -575,32 +664,7 @@ public class IorapForwardingService extends SystemService {
public boolean onStopJob(JobParameters params) {
// As this is unexpected behavior, print a warning.
Log.w(TAG, "onStopJob(params=" + params.toString() + ")");
-
- // No longer track this job (avoids a memory leak).
- boolean wasTracking = false;
- synchronized (mLock) {
- for (HashMap.Entry<RequestId, JobParameters> entry : mRunningJobs.entrySet()) {
- if (entry.getValue().getJobId() == params.getJobId()) {
- mRunningJobs.remove(entry.getKey());
- wasTracking = true;
- }
- }
- }
-
- // Notify iorapd to stop (abort) the job.
- if (wasTracking) {
- invokeRemote(mIorapRemote, (IIorap remote) ->
- remote.onJobScheduledEvent(RequestId.nextValueForSequence(),
- JobScheduledEvent.createIdleMaintenance(
- JobScheduledEvent.TYPE_STOP_JOB,
- params))
- );
- } else {
- // Even weirder. This could only be considered "correct" if iorapd reported success
- // concurrently to the JobService requesting an onStopJob.
- Log.e(TAG, "Untracked onStopJob request"); // see above Log.w for the params.
- }
-
+ mAbortIdleCompilation.set(true);
// Yes, retry the job at a later time no matter what.
return true;
@@ -626,18 +690,6 @@ public class IorapForwardingService extends SystemService {
}
Log.d(TAG, "Finished background job: " + jobParameters.toString());
-
- // Job is successful and periodic. Do not 'reschedule' according to the back-off
- // criteria.
- //
- // This releases the wakelock that was acquired in #onStartJob.
-
- IorapdJobServiceProxy proxy = mProxy;
- if (proxy != null) {
- proxy.jobFinished(jobParameters, /*reschedule*/false);
- }
- // Cannot call 'jobFinished' on 'this' because it was not constructed
- // from the JobService, so it would get an NPE when calling mEngine.
}
public void onIorapdDisconnected() {
diff --git a/startop/iorap/src/com/google/android/startop/iorap/JobScheduledEvent.java b/startop/iorap/src/com/google/android/startop/iorap/JobScheduledEvent.java
index 2055b206dd7a..b91dd71fd28c 100644
--- a/startop/iorap/src/com/google/android/startop/iorap/JobScheduledEvent.java
+++ b/startop/iorap/src/com/google/android/startop/iorap/JobScheduledEvent.java
@@ -55,6 +55,10 @@ public class JobScheduledEvent implements Parcelable {
/** @see JobParameters#getJobId() */
public final int jobId;
+ public final String packageName;
+
+ public final boolean shouldUpdateVersions;
+
/** Device is 'idle' and it's charging (plugged in). */
public static final int SORT_IDLE_MAINTENANCE = 0;
private static final int SORT_MAX = 0;
@@ -77,14 +81,22 @@ public class JobScheduledEvent implements Parcelable {
* Only the job ID is retained from {@code jobParams}, all other param info is dropped.
*/
@NonNull
- public static JobScheduledEvent createIdleMaintenance(@Type int type, JobParameters jobParams) {
- return new JobScheduledEvent(type, jobParams.getJobId(), SORT_IDLE_MAINTENANCE);
+ public static JobScheduledEvent createIdleMaintenance(
+ @Type int type, JobParameters jobParams, String packageName, boolean shouldUpdateVersions) {
+ return new JobScheduledEvent(
+ type, jobParams.getJobId(), SORT_IDLE_MAINTENANCE, packageName, shouldUpdateVersions);
}
- private JobScheduledEvent(@Type int type, int jobId, @Sort int sort) {
+ private JobScheduledEvent(@Type int type,
+ int jobId,
+ @Sort int sort,
+ String packageName,
+ boolean shouldUpdateVersions) {
this.type = type;
this.jobId = jobId;
this.sort = sort;
+ this.packageName = packageName;
+ this.shouldUpdateVersions = shouldUpdateVersions;
checkConstructorArguments();
}
@@ -108,12 +120,16 @@ public class JobScheduledEvent implements Parcelable {
private boolean equals(JobScheduledEvent other) {
return type == other.type &&
jobId == other.jobId &&
- sort == other.sort;
+ sort == other.sort &&
+ packageName.equals(other.packageName) &&
+ shouldUpdateVersions == other.shouldUpdateVersions;
}
@Override
public String toString() {
- return String.format("{type: %d, jobId: %d, sort: %d}", type, jobId, sort);
+ return String.format(
+ "{type: %d, jobId: %d, sort: %d, packageName: %s, shouldUpdateVersions %b}",
+ type, jobId, sort, packageName, shouldUpdateVersions);
}
//<editor-fold desc="Binder boilerplate">
@@ -122,6 +138,8 @@ public class JobScheduledEvent implements Parcelable {
out.writeInt(type);
out.writeInt(jobId);
out.writeInt(sort);
+ out.writeString(packageName);
+ out.writeBoolean(shouldUpdateVersions);
// We do not parcel the entire JobParameters here because there is no C++ equivalent
// of that class [which the iorapd side of the binder interface requires].
@@ -131,6 +149,8 @@ public class JobScheduledEvent implements Parcelable {
this.type = in.readInt();
this.jobId = in.readInt();
this.sort = in.readInt();
+ this.packageName = in.readString();
+ this.shouldUpdateVersions = in.readBoolean();
checkConstructorArguments();
}
diff --git a/telecomm/java/android/telecom/TelecomManager.java b/telecomm/java/android/telecom/TelecomManager.java
index 960b0df40061..5b03863efc7d 100644
--- a/telecomm/java/android/telecom/TelecomManager.java
+++ b/telecomm/java/android/telecom/TelecomManager.java
@@ -268,10 +268,69 @@ public class TelecomManager {
/**
* Optional extra for {@link android.content.Intent#ACTION_CALL} containing a string call
* subject which will be associated with an outgoing call. Should only be specified if the
- * {@link PhoneAccount} supports the capability {@link PhoneAccount#CAPABILITY_CALL_SUBJECT}.
+ * {@link PhoneAccount} supports the capability {@link PhoneAccount#CAPABILITY_CALL_SUBJECT}
+ * or {@link PhoneAccount#CAPABILITY_CALL_COMPOSER}.
*/
public static final String EXTRA_CALL_SUBJECT = "android.telecom.extra.CALL_SUBJECT";
+ // Values for EXTRA_PRIORITY
+ /**
+ * Indicates the call composer call priority is normal.
+ *
+ * Reference: RCC.20 Section 2.4.4.2
+ */
+ public static final int PRIORITY_NORMAL = 0;
+
+ /**
+ * Indicates the call composer call priority is urgent.
+ *
+ * Reference: RCC.20 Section 2.4.4.2
+ */
+ public static final int PRIORITY_URGENT = 1;
+
+ /**
+ * Extra for the call composer call priority, either {@link #PRIORITY_NORMAL} or
+ * {@link #PRIORITY_URGENT}.
+ *
+ * Reference: RCC.20 Section 2.4.4.2
+ */
+ public static final String EXTRA_PRIORITY = "android.telecom.extra.PRIORITY";
+
+ /**
+ * Extra for the call composer call location, an {@link android.location.Location} parcelable
+ * class to represent the geolocation as a latitude and longitude pair.
+ *
+ * Reference: RCC.20 Section 2.4.3.2
+ */
+ public static final String EXTRA_LOCATION = "android.telecom.extra.LOCATION";
+
+ /**
+ * A boolean extra set on incoming calls to indicate that the call has a picture specified.
+ * Given that image download could take a (short) time, the EXTRA is set immediately upon
+ * adding the call to the Dialer app, this allows the Dialer app to reserve space for an image
+ * if one is expected. The EXTRA may be unset if the image download ends up failing for some
+ * reason.
+ */
+ public static final String EXTRA_HAS_PICTURE = "android.telecom.extra.HAS_PICTURE";
+
+ /**
+ * A URI representing the picture that was downloaded when a call is received.
+ * This is a content URI within the call log provider which can be used to open a file
+ * descriptor. This could be set a short time after a call is added to the Dialer app if the
+ * download is delayed for some reason. The Dialer app will receive a callback via
+ * {@link Call.Callback#onDetailsChanged} when this value has changed.
+ *
+ * Reference: RCC.20 Section 2.4.3.2
+ */
+ public static final String EXTRA_INCOMING_PICTURE = "android.telecom.extra.INCOMING_PICTURE";
+
+ // TODO(hallliu), This UUID is obtained from TelephonyManager#uploadCallComposerPicture.
+ /**
+ * A ParcelUuid used as a token to represent a picture that was uploaded prior to the call
+ * being placed.
+ */
+ public static final String EXTRA_OUTGOING_PICTURE = "android.telecom.extra.OUTGOING_PICTURE";
+
/**
* The extra used by a {@link ConnectionService} to provide the handle of the caller that
* has initiated a new incoming call.
diff --git a/telephony/java/android/telephony/CellInfo.java b/telephony/java/android/telephony/CellInfo.java
index b381ccecde47..189a4b898886 100644
--- a/telephony/java/android/telephony/CellInfo.java
+++ b/telephony/java/android/telephony/CellInfo.java
@@ -21,7 +21,6 @@ import android.annotation.IntDef;
import android.annotation.NonNull;
import android.compat.annotation.UnsupportedAppUsage;
import android.hardware.radio.V1_4.CellInfo.Info;
-import android.hardware.radio.V1_5.CellInfo.CellInfoRatSpecificInfo;
import android.os.Parcel;
import android.os.Parcelable;
@@ -352,6 +351,13 @@ public abstract class CellInfo implements Parcelable {
}
/** @hide */
+ protected CellInfo(android.hardware.radio.V1_6.CellInfo ci, long timeStamp) {
+ this.mRegistered = ci.registered;
+ this.mTimeStamp = timeStamp;
+ this.mCellConnectionStatus = ci.connectionStatus;
+ }
+
+ /** @hide */
public static CellInfo create(android.hardware.radio.V1_0.CellInfo ci) {
if (ci == null) return null;
switch(ci.cellInfoType) {
@@ -395,17 +401,49 @@ public abstract class CellInfo implements Parcelable {
public static CellInfo create(android.hardware.radio.V1_5.CellInfo ci, long timeStamp) {
if (ci == null) return null;
switch (ci.ratSpecificInfo.getDiscriminator()) {
- case CellInfoRatSpecificInfo.hidl_discriminator.gsm:
+ case android.hardware.radio.V1_5.CellInfo
+ .CellInfoRatSpecificInfo.hidl_discriminator.gsm:
+ return new CellInfoGsm(ci, timeStamp);
+ case android.hardware.radio.V1_5.CellInfo
+ .CellInfoRatSpecificInfo.hidl_discriminator.cdma:
+ return new CellInfoCdma(ci, timeStamp);
+ case android.hardware.radio.V1_5.CellInfo
+ .CellInfoRatSpecificInfo.hidl_discriminator.lte:
+ return new CellInfoLte(ci, timeStamp);
+ case android.hardware.radio.V1_5.CellInfo
+ .CellInfoRatSpecificInfo.hidl_discriminator.wcdma:
+ return new CellInfoWcdma(ci, timeStamp);
+ case android.hardware.radio.V1_5.CellInfo
+ .CellInfoRatSpecificInfo.hidl_discriminator.tdscdma:
+ return new CellInfoTdscdma(ci, timeStamp);
+ case android.hardware.radio.V1_5.CellInfo
+ .CellInfoRatSpecificInfo.hidl_discriminator.nr:
+ return new CellInfoNr(ci, timeStamp);
+ default: return null;
+ }
+ }
+
+ /** @hide */
+ public static CellInfo create(android.hardware.radio.V1_6.CellInfo ci, long timeStamp) {
+ if (ci == null) return null;
+ switch (ci.ratSpecificInfo.getDiscriminator()) {
+ case android.hardware.radio.V1_6.CellInfo
+ .CellInfoRatSpecificInfo.hidl_discriminator.gsm:
return new CellInfoGsm(ci, timeStamp);
- case CellInfoRatSpecificInfo.hidl_discriminator.cdma:
+ case android.hardware.radio.V1_6.CellInfo
+ .CellInfoRatSpecificInfo.hidl_discriminator.cdma:
return new CellInfoCdma(ci, timeStamp);
- case CellInfoRatSpecificInfo.hidl_discriminator.lte:
+ case android.hardware.radio.V1_6.CellInfo
+ .CellInfoRatSpecificInfo.hidl_discriminator.lte:
return new CellInfoLte(ci, timeStamp);
- case CellInfoRatSpecificInfo.hidl_discriminator.wcdma:
+ case android.hardware.radio.V1_6.CellInfo
+ .CellInfoRatSpecificInfo.hidl_discriminator.wcdma:
return new CellInfoWcdma(ci, timeStamp);
- case CellInfoRatSpecificInfo.hidl_discriminator.tdscdma:
+ case android.hardware.radio.V1_6.CellInfo
+ .CellInfoRatSpecificInfo.hidl_discriminator.tdscdma:
return new CellInfoTdscdma(ci, timeStamp);
- case CellInfoRatSpecificInfo.hidl_discriminator.nr:
+ case android.hardware.radio.V1_6.CellInfo
+ .CellInfoRatSpecificInfo.hidl_discriminator.nr:
return new CellInfoNr(ci, timeStamp);
default: return null;
}
diff --git a/telephony/java/android/telephony/CellInfoCdma.java b/telephony/java/android/telephony/CellInfoCdma.java
index 3ce99facfdb1..dbb30d29eb87 100644
--- a/telephony/java/android/telephony/CellInfoCdma.java
+++ b/telephony/java/android/telephony/CellInfoCdma.java
@@ -87,6 +87,15 @@ public final class CellInfoCdma extends CellInfo implements Parcelable {
new CellSignalStrengthCdma(cic.signalStrengthCdma, cic.signalStrengthEvdo);
}
+ /** @hide */
+ public CellInfoCdma(android.hardware.radio.V1_6.CellInfo ci, long timeStamp) {
+ super(ci, timeStamp);
+ final android.hardware.radio.V1_2.CellInfoCdma cic = ci.ratSpecificInfo.cdma();
+ mCellIdentityCdma = new CellIdentityCdma(cic.cellIdentityCdma);
+ mCellSignalStrengthCdma =
+ new CellSignalStrengthCdma(cic.signalStrengthCdma, cic.signalStrengthEvdo);
+ }
+
/**
* @return a {@link CellIdentityCdma} instance.
*/
diff --git a/telephony/java/android/telephony/CellInfoGsm.java b/telephony/java/android/telephony/CellInfoGsm.java
index e296e613362a..e1d996e87fcf 100644
--- a/telephony/java/android/telephony/CellInfoGsm.java
+++ b/telephony/java/android/telephony/CellInfoGsm.java
@@ -82,6 +82,14 @@ public final class CellInfoGsm extends CellInfo implements Parcelable {
mCellSignalStrengthGsm = new CellSignalStrengthGsm(cig.signalStrengthGsm);
}
+ /** @hide */
+ public CellInfoGsm(android.hardware.radio.V1_6.CellInfo ci, long timeStamp) {
+ super(ci, timeStamp);
+ final android.hardware.radio.V1_5.CellInfoGsm cig = ci.ratSpecificInfo.gsm();
+ mCellIdentityGsm = new CellIdentityGsm(cig.cellIdentityGsm);
+ mCellSignalStrengthGsm = new CellSignalStrengthGsm(cig.signalStrengthGsm);
+ }
+
/**
* @return a {@link CellIdentityGsm} instance.
*/
diff --git a/telephony/java/android/telephony/CellInfoLte.java b/telephony/java/android/telephony/CellInfoLte.java
index 6f812341756b..39b320afdac9 100644
--- a/telephony/java/android/telephony/CellInfoLte.java
+++ b/telephony/java/android/telephony/CellInfoLte.java
@@ -91,6 +91,15 @@ public final class CellInfoLte extends CellInfo implements Parcelable {
mCellConfig = new CellConfigLte();
}
+ /** @hide */
+ public CellInfoLte(android.hardware.radio.V1_6.CellInfo ci, long timeStamp) {
+ super(ci, timeStamp);
+ final android.hardware.radio.V1_6.CellInfoLte cil = ci.ratSpecificInfo.lte();
+ mCellIdentityLte = new CellIdentityLte(cil.cellIdentityLte);
+ mCellSignalStrengthLte = new CellSignalStrengthLte(cil.signalStrengthLte);
+ mCellConfig = new CellConfigLte();
+ }
+
/**
* @return a {@link CellIdentityLte} instance.
*/
diff --git a/telephony/java/android/telephony/CellInfoNr.java b/telephony/java/android/telephony/CellInfoNr.java
index e01e8f0d5b51..12e6a38bfdc0 100644
--- a/telephony/java/android/telephony/CellInfoNr.java
+++ b/telephony/java/android/telephony/CellInfoNr.java
@@ -68,6 +68,14 @@ public final class CellInfoNr extends CellInfo {
mCellSignalStrength = new CellSignalStrengthNr(cil.signalStrengthNr);
}
+ /** @hide */
+ public CellInfoNr(android.hardware.radio.V1_6.CellInfo ci, long timeStamp) {
+ super(ci, timeStamp);
+ final android.hardware.radio.V1_6.CellInfoNr cil = ci.ratSpecificInfo.nr();
+ mCellIdentity = new CellIdentityNr(cil.cellIdentityNr);
+ mCellSignalStrength = new CellSignalStrengthNr(cil.signalStrengthNr);
+ }
+
/**
* @return a {@link CellIdentityNr} instance.
*/
diff --git a/telephony/java/android/telephony/CellInfoTdscdma.java b/telephony/java/android/telephony/CellInfoTdscdma.java
index 038c49ac37ee..994b317a47fd 100644
--- a/telephony/java/android/telephony/CellInfoTdscdma.java
+++ b/telephony/java/android/telephony/CellInfoTdscdma.java
@@ -85,6 +85,14 @@ public final class CellInfoTdscdma extends CellInfo implements Parcelable {
mCellSignalStrengthTdscdma = new CellSignalStrengthTdscdma(cit.signalStrengthTdscdma);
}
+ /** @hide */
+ public CellInfoTdscdma(android.hardware.radio.V1_6.CellInfo ci, long timeStamp) {
+ super(ci, timeStamp);
+ final android.hardware.radio.V1_5.CellInfoTdscdma cit = ci.ratSpecificInfo.tdscdma();
+ mCellIdentityTdscdma = new CellIdentityTdscdma(cit.cellIdentityTdscdma);
+ mCellSignalStrengthTdscdma = new CellSignalStrengthTdscdma(cit.signalStrengthTdscdma);
+ }
+
/**
* @return a {@link CellIdentityTdscdma} instance.
*/
diff --git a/telephony/java/android/telephony/CellInfoWcdma.java b/telephony/java/android/telephony/CellInfoWcdma.java
index c74955f807b0..62ac0b8ae04e 100644
--- a/telephony/java/android/telephony/CellInfoWcdma.java
+++ b/telephony/java/android/telephony/CellInfoWcdma.java
@@ -80,6 +80,14 @@ public final class CellInfoWcdma extends CellInfo implements Parcelable {
mCellSignalStrengthWcdma = new CellSignalStrengthWcdma(ciw.signalStrengthWcdma);
}
+ /** @hide */
+ public CellInfoWcdma(android.hardware.radio.V1_6.CellInfo ci, long timeStamp) {
+ super(ci, timeStamp);
+ final android.hardware.radio.V1_5.CellInfoWcdma ciw = ci.ratSpecificInfo.wcdma();
+ mCellIdentityWcdma = new CellIdentityWcdma(ciw.cellIdentityWcdma);
+ mCellSignalStrengthWcdma = new CellSignalStrengthWcdma(ciw.signalStrengthWcdma);
+ }
+
/**
* @return a {@link CellIdentityWcdma} instance.
*/
diff --git a/telephony/java/android/telephony/CellSignalStrengthLte.java b/telephony/java/android/telephony/CellSignalStrengthLte.java
index 47a8f72a2337..db7d10ae8ce4 100644
--- a/telephony/java/android/telephony/CellSignalStrengthLte.java
+++ b/telephony/java/android/telephony/CellSignalStrengthLte.java
@@ -86,6 +86,15 @@ public final class CellSignalStrengthLte extends CellSignalStrength implements P
private int mRsrq;
@UnsupportedAppUsage(maxTargetSdk = android.os.Build.VERSION_CODES.P)
private int mRssnr;
+ /**
+ * CSI channel quality indicator (CQI) table index. There are multiple CQI tables.
+ * The definition of CQI in each table is different.
+ *
+ * Reference: 3GPP TS 136.213 section 7.2.3.
+ *
+ * Range [1, 6].
+ */
+ private int mCqiTableIndex;
@UnsupportedAppUsage(maxTargetSdk = android.os.Build.VERSION_CODES.P)
private int mCqi;
@UnsupportedAppUsage(maxTargetSdk = android.os.Build.VERSION_CODES.P)
@@ -120,24 +129,42 @@ public final class CellSignalStrengthLte extends CellSignalStrength implements P
* @param rsrp in dBm [-140,-43], UNKNOWN
* @param rsrq in dB [-34, 3], UNKNOWN
* @param rssnr in dB [-20, +30], UNKNOWN
+ * @param cqiTableIndex [1, 6], UNKNOWN
* @param cqi [0, 15], UNKNOWN
* @param timingAdvance [0, 1282], UNKNOWN
*
*/
/** @hide */
- public CellSignalStrengthLte(int rssi, int rsrp, int rsrq, int rssnr, int cqi,
- int timingAdvance) {
-
+ public CellSignalStrengthLte(int rssi, int rsrp, int rsrq, int rssnr, int cqiTableIndex,
+ int cqi, int timingAdvance) {
mRssi = inRangeOrUnavailable(rssi, -113, -51);
mSignalStrength = mRssi;
mRsrp = inRangeOrUnavailable(rsrp, -140, -43);
mRsrq = inRangeOrUnavailable(rsrq, -34, 3);
mRssnr = inRangeOrUnavailable(rssnr, -20, 30);
+ mCqiTableIndex = inRangeOrUnavailable(cqiTableIndex, 1, 6);
mCqi = inRangeOrUnavailable(cqi, 0, 15);
mTimingAdvance = inRangeOrUnavailable(timingAdvance, 0, 1282);
updateLevel(null, null);
}
+ /**
+ * Construct a cell signal strength
+ *
+ * @param rssi in dBm [-113,-51], UNKNOWN
+ * @param rsrp in dBm [-140,-43], UNKNOWN
+ * @param rsrq in dB [-34, 3], UNKNOWN
+ * @param rssnr in dB [-20, +30], UNKNOWN
+ * @param cqi [0, 15], UNKNOWN
+ * @param timingAdvance [0, 1282], UNKNOWN
+ *
+ */
+ /** @hide */
+ public CellSignalStrengthLte(int rssi, int rsrp, int rsrq, int rssnr, int cqi,
+ int timingAdvance) {
+ this(rssi, rsrp, rsrq, rssnr, CellInfo.UNAVAILABLE, cqi, timingAdvance);
+ }
+
/** @hide */
public CellSignalStrengthLte(android.hardware.radio.V1_0.LteSignalStrength lte) {
// Convert from HAL values as part of construction.
@@ -148,6 +175,16 @@ public final class CellSignalStrengthLte extends CellSignalStrength implements P
}
/** @hide */
+ public CellSignalStrengthLte(android.hardware.radio.V1_6.LteSignalStrength lte) {
+ // Convert from HAL values as part of construction.
+ this(convertRssiAsuToDBm(lte.base.signalStrength),
+ lte.base.rsrp != CellInfo.UNAVAILABLE ? -lte.base.rsrp : lte.base.rsrp,
+ lte.base.rsrq != CellInfo.UNAVAILABLE ? -lte.base.rsrq : lte.base.rsrq,
+ convertRssnrUnitFromTenDbToDB(lte.base.rssnr), lte.cqiTableIndex, lte.base.cqi,
+ lte.base.timingAdvance);
+ }
+
+ /** @hide */
public CellSignalStrengthLte(CellSignalStrengthLte s) {
copyFrom(s);
}
@@ -159,6 +196,7 @@ public final class CellSignalStrengthLte extends CellSignalStrength implements P
mRsrp = s.mRsrp;
mRsrq = s.mRsrq;
mRssnr = s.mRssnr;
+ mCqiTableIndex = s.mCqiTableIndex;
mCqi = s.mCqi;
mTimingAdvance = s.mTimingAdvance;
mLevel = s.mLevel;
@@ -179,6 +217,7 @@ public final class CellSignalStrengthLte extends CellSignalStrength implements P
mRsrp = CellInfo.UNAVAILABLE;
mRsrq = CellInfo.UNAVAILABLE;
mRssnr = CellInfo.UNAVAILABLE;
+ mCqiTableIndex = CellInfo.UNAVAILABLE;
mCqi = CellInfo.UNAVAILABLE;
mTimingAdvance = CellInfo.UNAVAILABLE;
mLevel = SIGNAL_STRENGTH_NONE_OR_UNKNOWN;
@@ -402,6 +441,17 @@ public final class CellSignalStrengthLte extends CellSignalStrength implements P
}
/**
+ * Get table index for channel quality indicator
+ *
+ * @return the CQI table index if available or
+ * {@link android.telephony.CellInfo#UNAVAILABLE UNAVAILABLE} if unavailable.
+ */
+ /** @hide */
+ public int getCqiTableIndex() {
+ return mCqiTableIndex;
+ }
+
+ /**
* Get channel quality indicator
*
* @return the CQI if available or
@@ -454,7 +504,8 @@ public final class CellSignalStrengthLte extends CellSignalStrength implements P
@Override
public int hashCode() {
- return Objects.hash(mRssi, mRsrp, mRsrq, mRssnr, mCqi, mTimingAdvance, mLevel);
+ return Objects.hash(mRssi, mRsrp, mRsrq, mRssnr, mCqiTableIndex, mCqi, mTimingAdvance,
+ mLevel);
}
private static final CellSignalStrengthLte sInvalid = new CellSignalStrengthLte();
@@ -476,6 +527,7 @@ public final class CellSignalStrengthLte extends CellSignalStrength implements P
&& mRsrp == s.mRsrp
&& mRsrq == s.mRsrq
&& mRssnr == s.mRssnr
+ && mCqiTableIndex == s.mCqiTableIndex
&& mCqi == s.mCqi
&& mTimingAdvance == s.mTimingAdvance
&& mLevel == s.mLevel;
@@ -491,6 +543,7 @@ public final class CellSignalStrengthLte extends CellSignalStrength implements P
+ " rsrp=" + mRsrp
+ " rsrq=" + mRsrq
+ " rssnr=" + mRssnr
+ + " cqiTableIndex=" + mCqiTableIndex
+ " cqi=" + mCqi
+ " ta=" + mTimingAdvance
+ " level=" + mLevel
@@ -508,6 +561,7 @@ public final class CellSignalStrengthLte extends CellSignalStrength implements P
dest.writeInt(mRsrp);
dest.writeInt(mRsrq);
dest.writeInt(mRssnr);
+ dest.writeInt(mCqiTableIndex);
dest.writeInt(mCqi);
dest.writeInt(mTimingAdvance);
dest.writeInt(mLevel);
@@ -523,6 +577,7 @@ public final class CellSignalStrengthLte extends CellSignalStrength implements P
mRsrp = in.readInt();
mRsrq = in.readInt();
mRssnr = in.readInt();
+ mCqiTableIndex = in.readInt();
mCqi = in.readInt();
mTimingAdvance = in.readInt();
mLevel = in.readInt();
diff --git a/telephony/java/android/telephony/CellSignalStrengthNr.java b/telephony/java/android/telephony/CellSignalStrengthNr.java
index 766019ec382a..1518190bb7f7 100644
--- a/telephony/java/android/telephony/CellSignalStrengthNr.java
+++ b/telephony/java/android/telephony/CellSignalStrengthNr.java
@@ -18,6 +18,7 @@ package android.telephony;
import android.annotation.IntDef;
import android.annotation.IntRange;
+import android.annotation.NonNull;
import android.os.Parcel;
import android.os.Parcelable;
import android.os.PersistableBundle;
@@ -27,7 +28,10 @@ import com.android.telephony.Rlog;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.util.Arrays;
+import java.util.Collections;
+import java.util.List;
import java.util.Objects;
+import java.util.stream.Collectors;
/**
* 5G NR signal strength related information.
@@ -109,6 +113,28 @@ public final class CellSignalStrengthNr extends CellSignalStrength implements Pa
private int mCsiRsrp;
private int mCsiRsrq;
private int mCsiSinr;
+ /**
+ * CSI channel quality indicator (CQI) table index. There are multiple CQI tables.
+ * The definition of CQI in each table is different.
+ *
+ * Reference: 3GPP TS 138.214 section 5.2.2.1.
+ *
+ * Range [1, 3].
+ */
+ private int mCsiCqiTableIndex;
+ /**
+ * CSI channel quality indicators (CQI) for all subbands.
+ *
+ * If the CQI report is for the entire wideband, a single CQI index is provided.
+ * If the CQI report is for all subbands, one CQI index is provided for each subband,
+ * in ascending order of subband index.
+ * If CQI is not available, the CQI report is empty.
+ *
+ * Reference: 3GPP TS 138.214 section 5.2.2.1.
+ *
+ * Range [0, 15] for each CQI.
+ */
+ private List<Integer> mCsiCqiReport;;
private int mSsRsrp;
private int mSsRsrq;
private int mSsSinr;
@@ -138,16 +164,22 @@ public final class CellSignalStrengthNr extends CellSignalStrength implements Pa
* @param csiRsrp CSI reference signal received power.
* @param csiRsrq CSI reference signal received quality.
* @param csiSinr CSI signal-to-noise and interference ratio.
+ * @param csiCqiTableIndex CSI CSI channel quality indicator (CQI) table index.
+ * @param csiCqiReport CSI channel quality indicators (CQI) for all subbands.
* @param ssRsrp SS reference signal received power.
* @param ssRsrq SS reference signal received quality.
* @param ssSinr SS signal-to-noise and interference ratio.
* @hide
*/
- public CellSignalStrengthNr(
- int csiRsrp, int csiRsrq, int csiSinr, int ssRsrp, int ssRsrq, int ssSinr) {
+ public CellSignalStrengthNr(int csiRsrp, int csiRsrq, int csiSinr, int csiCqiTableIndex,
+ List<Integer> csiCqiReport, int ssRsrp, int ssRsrq, int ssSinr) {
mCsiRsrp = inRangeOrUnavailable(csiRsrp, -140, -44);
mCsiRsrq = inRangeOrUnavailable(csiRsrq, -20, -3);
mCsiSinr = inRangeOrUnavailable(csiSinr, -23, 23);
+ mCsiCqiTableIndex = inRangeOrUnavailable(csiCqiTableIndex, 1, 3);
+ mCsiCqiReport = csiCqiReport.stream()
+ .map(cqi -> new Integer(inRangeOrUnavailable(cqi.intValue(), 1, 3)))
+ .collect(Collectors.toList());
mSsRsrp = inRangeOrUnavailable(ssRsrp, -140, -44);
mSsRsrq = inRangeOrUnavailable(ssRsrq, -43, 20);
mSsSinr = inRangeOrUnavailable(ssSinr, -23, 40);
@@ -155,6 +187,21 @@ public final class CellSignalStrengthNr extends CellSignalStrength implements Pa
}
/**
+ * @param csiRsrp CSI reference signal received power.
+ * @param csiRsrq CSI reference signal received quality.
+ * @param csiSinr CSI signal-to-noise and interference ratio.
+ * @param ssRsrp SS reference signal received power.
+ * @param ssRsrq SS reference signal received quality.
+ * @param ssSinr SS signal-to-noise and interference ratio.
+ * @hide
+ */
+ public CellSignalStrengthNr(
+ int csiRsrp, int csiRsrq, int csiSinr, int ssRsrp, int ssRsrq, int ssSinr) {
+ this(csiRsrp, csiRsrq, csiSinr, CellInfo.UNAVAILABLE, Collections.emptyList(),
+ ssRsrp, ssRsrq, ssSinr);
+ }
+
+ /**
* @hide
* @param ss signal strength from modem.
*/
@@ -164,6 +211,15 @@ public final class CellSignalStrengthNr extends CellSignalStrength implements Pa
}
/**
+ * @hide
+ * @param ss signal strength from modem.
+ */
+ public CellSignalStrengthNr(android.hardware.radio.V1_6.NrSignalStrength ss) {
+ this(flip(ss.base.csiRsrp), flip(ss.base.csiRsrq), ss.base.csiSinr, ss.csiCqiTableIndex,
+ ss.csiCqiReport, flip(ss.base.ssRsrp), flip(ss.base.ssRsrq), ss.base.ssSinr);
+ }
+
+ /**
* Flip sign cell strength value when taking in the value from hal
* @param val cell strength value
* @return flipped value
@@ -232,6 +288,36 @@ public final class CellSignalStrengthNr extends CellSignalStrength implements Pa
return mCsiSinr;
}
+ /**
+ * Return CSI channel quality indicator (CQI) table index. There are multiple CQI tables.
+ * The definition of CQI in each table is different.
+ *
+ * Reference: 3GPP TS 138.214 section 5.2.2.1.
+ *
+ * Range [1, 3].
+ */
+ /** @hide */
+ public int getCsiCqiTableIndex() {
+ return mCsiCqiTableIndex;
+ }
+ /**
+ * Return a list of CSI channel quality indicators (CQI) for all subbands.
+ *
+ * If the CQI report is for the entire wideband, a single CQI index is provided.
+ * If the CQI report is for all subbands, one CQI index is provided for each subband,
+ * in ascending order of subband index.
+ * If CQI is not available, the CQI report is empty.
+ *
+ * Reference: 3GPP TS 138.214 section 5.2.2.1.
+ *
+ * Range [0, 15] for each CQI.
+ */
+ /** @hide */
+ @NonNull
+ public List<Integer> getCsiCqiReport() {
+ return mCsiCqiReport;
+ }
+
@Override
public int describeContents() {
return 0;
@@ -243,6 +329,8 @@ public final class CellSignalStrengthNr extends CellSignalStrength implements Pa
dest.writeInt(mCsiRsrp);
dest.writeInt(mCsiRsrq);
dest.writeInt(mCsiSinr);
+ dest.writeInt(mCsiCqiTableIndex);
+ dest.writeList(mCsiCqiReport);
dest.writeInt(mSsRsrp);
dest.writeInt(mSsRsrq);
dest.writeInt(mSsSinr);
@@ -253,6 +341,8 @@ public final class CellSignalStrengthNr extends CellSignalStrength implements Pa
mCsiRsrp = in.readInt();
mCsiRsrq = in.readInt();
mCsiSinr = in.readInt();
+ mCsiCqiTableIndex = in.readInt();
+ mCsiCqiReport = in.readArrayList(Integer.class.getClassLoader());
mSsRsrp = in.readInt();
mSsRsrq = in.readInt();
mSsSinr = in.readInt();
@@ -265,6 +355,8 @@ public final class CellSignalStrengthNr extends CellSignalStrength implements Pa
mCsiRsrp = CellInfo.UNAVAILABLE;
mCsiRsrq = CellInfo.UNAVAILABLE;
mCsiSinr = CellInfo.UNAVAILABLE;
+ mCsiCqiTableIndex = CellInfo.UNAVAILABLE;
+ mCsiCqiReport = Collections.emptyList();
mSsRsrp = CellInfo.UNAVAILABLE;
mSsRsrq = CellInfo.UNAVAILABLE;
mSsSinr = CellInfo.UNAVAILABLE;
@@ -408,6 +500,8 @@ public final class CellSignalStrengthNr extends CellSignalStrength implements Pa
mCsiRsrp = s.mCsiRsrp;
mCsiRsrq = s.mCsiRsrq;
mCsiSinr = s.mCsiSinr;
+ mCsiCqiTableIndex = s.mCsiCqiTableIndex;
+ mCsiCqiReport = s.mCsiCqiReport;
mSsRsrp = s.mSsRsrp;
mSsRsrq = s.mSsRsrq;
mSsSinr = s.mSsSinr;
@@ -423,7 +517,8 @@ public final class CellSignalStrengthNr extends CellSignalStrength implements Pa
@Override
public int hashCode() {
- return Objects.hash(mCsiRsrp, mCsiRsrq, mCsiSinr, mSsRsrp, mSsRsrq, mSsSinr, mLevel);
+ return Objects.hash(mCsiRsrp, mCsiRsrq, mCsiSinr, mCsiCqiTableIndex,
+ mCsiCqiReport, mSsRsrp, mSsRsrq, mSsSinr, mLevel);
}
private static final CellSignalStrengthNr sInvalid = new CellSignalStrengthNr();
@@ -439,6 +534,8 @@ public final class CellSignalStrengthNr extends CellSignalStrength implements Pa
if (obj instanceof CellSignalStrengthNr) {
CellSignalStrengthNr o = (CellSignalStrengthNr) obj;
return mCsiRsrp == o.mCsiRsrp && mCsiRsrq == o.mCsiRsrq && mCsiSinr == o.mCsiSinr
+ && mCsiCqiTableIndex == o.mCsiCqiTableIndex
+ && mCsiCqiReport.equals(o.mCsiCqiReport)
&& mSsRsrp == o.mSsRsrp && mSsRsrq == o.mSsRsrq && mSsSinr == o.mSsSinr
&& mLevel == o.mLevel;
}
@@ -451,7 +548,8 @@ public final class CellSignalStrengthNr extends CellSignalStrength implements Pa
.append(TAG + ":{")
.append(" csiRsrp = " + mCsiRsrp)
.append(" csiRsrq = " + mCsiRsrq)
- .append(" csiSinr = " + mCsiSinr)
+ .append(" csiCqiTableIndex = " + mCsiCqiTableIndex)
+ .append(" csiCqiReport = " + mCsiCqiReport)
.append(" ssRsrp = " + mSsRsrp)
.append(" ssRsrq = " + mSsRsrq)
.append(" ssSinr = " + mSsSinr)
diff --git a/telephony/java/android/telephony/SignalStrength.java b/telephony/java/android/telephony/SignalStrength.java
index 7bd0bc0b69ce..b317c5557108 100644
--- a/telephony/java/android/telephony/SignalStrength.java
+++ b/telephony/java/android/telephony/SignalStrength.java
@@ -187,6 +187,21 @@ public class SignalStrength implements Parcelable {
new CellSignalStrengthNr(signalStrength.nr));
}
+ /**
+ * Constructor for Radio HAL V1.6.
+ *
+ * @param signalStrength signal strength reported from modem.
+ * @hide
+ */
+ public SignalStrength(android.hardware.radio.V1_6.SignalStrength signalStrength) {
+ this(new CellSignalStrengthCdma(signalStrength.cdma, signalStrength.evdo),
+ new CellSignalStrengthGsm(signalStrength.gsm),
+ new CellSignalStrengthWcdma(signalStrength.wcdma),
+ new CellSignalStrengthTdscdma(signalStrength.tdscdma),
+ new CellSignalStrengthLte(signalStrength.lte),
+ new CellSignalStrengthNr(signalStrength.nr));
+ }
+
private CellSignalStrength getPrimary() {
// This behavior is intended to replicate the legacy behavior of getLevel() by prioritizing
// newer faster RATs for default/for display purposes.
diff --git a/telephony/java/android/telephony/TelephonyManager.java b/telephony/java/android/telephony/TelephonyManager.java
index 886ec33af2b8..9e4228473c3e 100644
--- a/telephony/java/android/telephony/TelephonyManager.java
+++ b/telephony/java/android/telephony/TelephonyManager.java
@@ -12290,23 +12290,15 @@ public class TelephonyManager {
@NonNull
public Map<Integer, List<EmergencyNumber>> getEmergencyNumberList(
@EmergencyServiceCategories int categories) {
- Map<Integer, List<EmergencyNumber>> emergencyNumberList = new HashMap<>();
+ Map<Integer, List<EmergencyNumber>> emergencyNumberListForCategories = new HashMap<>();
try {
ITelephony telephony = getITelephony();
if (telephony != null) {
- emergencyNumberList = telephony.getEmergencyNumberList(
- mContext.getOpPackageName(), mContext.getAttributionTag());
- if (emergencyNumberList != null) {
- for (Integer subscriptionId : emergencyNumberList.keySet()) {
- List<EmergencyNumber> numberList = emergencyNumberList.get(subscriptionId);
- for (EmergencyNumber number : numberList) {
- if (!number.isInEmergencyServiceCategories(categories)) {
- numberList.remove(number);
- }
- }
- }
- }
- return emergencyNumberList;
+ Map<Integer, List<EmergencyNumber>> emergencyNumberList =
+ telephony.getEmergencyNumberList(mContext.getOpPackageName(),
+ mContext.getAttributionTag());
+ emergencyNumberListForCategories =
+ filterEmergencyNumbersByCategories(emergencyNumberList, categories);
} else {
throw new IllegalStateException("telephony service is null.");
}
@@ -12314,7 +12306,34 @@ public class TelephonyManager {
Log.e(TAG, "getEmergencyNumberList with Categories RemoteException", ex);
ex.rethrowAsRuntimeException();
}
- return emergencyNumberList;
+ return emergencyNumberListForCategories;
+ }
+
+ /**
+ * Filter emergency numbers with categories.
+ *
+ * @hide
+ */
+ @VisibleForTesting
+ public Map<Integer, List<EmergencyNumber>> filterEmergencyNumbersByCategories(
+ Map<Integer, List<EmergencyNumber>> emergencyNumberList,
+ @EmergencyServiceCategories int categories) {
+ Map<Integer, List<EmergencyNumber>> emergencyNumberListForCategories = new HashMap<>();
+ if (emergencyNumberList != null) {
+ for (Integer subscriptionId : emergencyNumberList.keySet()) {
+ List<EmergencyNumber> allNumbersForSub = emergencyNumberList.get(
+ subscriptionId);
+ List<EmergencyNumber> numbersForCategoriesPerSub = new ArrayList<>();
+ for (EmergencyNumber number : allNumbersForSub) {
+ if (number.isInEmergencyServiceCategories(categories)) {
+ numbersForCategoriesPerSub.add(number);
+ }
+ }
+ emergencyNumberListForCategories.put(
+ subscriptionId, numbersForCategoriesPerSub);
+ }
+ }
+ return emergencyNumberListForCategories;
}
/**
diff --git a/telephony/java/android/telephony/ims/stub/ImsConfigImplBase.java b/telephony/java/android/telephony/ims/stub/ImsConfigImplBase.java
index e0290a5dc2af..e757d9f70ccc 100644
--- a/telephony/java/android/telephony/ims/stub/ImsConfigImplBase.java
+++ b/telephony/java/android/telephony/ims/stub/ImsConfigImplBase.java
@@ -126,7 +126,7 @@ public class ImsConfigImplBase {
*/
@Override
public synchronized String getConfigString(int item) throws RemoteException {
- if (mProvisionedIntValue.containsKey(item)) {
+ if (mProvisionedStringValue.containsKey(item)) {
return mProvisionedStringValue.get(item);
} else {
String retVal = getImsConfigImpl().getConfigString(item);
diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/rotation/ChangeAppRotationTest.kt b/tests/FlickerTests/src/com/android/server/wm/flicker/rotation/ChangeAppRotationTest.kt
index 0db064ab79c5..9d4a71874f67 100644
--- a/tests/FlickerTests/src/com/android/server/wm/flicker/rotation/ChangeAppRotationTest.kt
+++ b/tests/FlickerTests/src/com/android/server/wm/flicker/rotation/ChangeAppRotationTest.kt
@@ -67,7 +67,7 @@ class ChangeAppRotationTest(
val instrumentation = InstrumentationRegistry.getInstrumentation()
val testApp = StandardAppHelper(instrumentation,
"com.android.server.wm.flicker.testapp", "SimpleApp")
- return FlickerTestRunnerFactory(instrumentation)
+ return FlickerTestRunnerFactory(instrumentation, repetitions = 10)
.buildRotationTest { configuration ->
withTestName {
buildTestTag(
diff --git a/tests/PackageWatchdog/src/com/android/server/PackageWatchdogTest.java b/tests/PackageWatchdog/src/com/android/server/PackageWatchdogTest.java
index 9738e58543e1..104758de49f1 100644
--- a/tests/PackageWatchdog/src/com/android/server/PackageWatchdogTest.java
+++ b/tests/PackageWatchdog/src/com/android/server/PackageWatchdogTest.java
@@ -22,6 +22,7 @@ import static com.android.dx.mockito.inline.extended.ExtendedMockito.doAnswer;
import static com.google.common.truth.Truth.assertThat;
+import static org.junit.Assert.assertTrue;
import static org.junit.Assert.fail;
import static org.mockito.ArgumentMatchers.anyInt;
import static org.mockito.ArgumentMatchers.anyLong;
@@ -43,10 +44,15 @@ import android.os.SystemProperties;
import android.os.test.TestLooper;
import android.provider.DeviceConfig;
import android.util.AtomicFile;
+import android.util.LongArrayQueue;
+import android.util.TypedXmlPullParser;
+import android.util.TypedXmlSerializer;
+import android.util.Xml;
import androidx.test.InstrumentationRegistry;
import com.android.dx.mockito.inline.extended.ExtendedMockito;
+import com.android.internal.util.XmlUtils;
import com.android.server.PackageWatchdog.HealthCheckState;
import com.android.server.PackageWatchdog.MonitoredPackage;
import com.android.server.PackageWatchdog.PackageHealthObserver;
@@ -64,6 +70,7 @@ import org.mockito.quality.Strictness;
import org.mockito.stubbing.Answer;
import java.io.File;
+import java.io.FileOutputStream;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
@@ -739,7 +746,8 @@ public class PackageWatchdogTest {
false /* hasPassedHealthCheck */);
MonitoredPackage m2 = wd.newMonitoredPackage(APP_B, LONG_DURATION, false);
MonitoredPackage m3 = wd.newMonitoredPackage(APP_C, LONG_DURATION, false);
- MonitoredPackage m4 = wd.newMonitoredPackage(APP_D, LONG_DURATION, SHORT_DURATION, true);
+ MonitoredPackage m4 = wd.newMonitoredPackage(APP_D, LONG_DURATION, SHORT_DURATION, true,
+ new LongArrayQueue());
// Verify transition: inactive -> active -> passed
// Verify initially inactive
@@ -1210,6 +1218,73 @@ public class PackageWatchdogTest {
assertThat(observer.mMitigationCounts).isEqualTo(List.of(1, 2, 3, 3, 2, 3));
}
+ @Test
+ public void testNormalizingMitigationCalls() {
+ PackageWatchdog watchdog = createWatchdog();
+
+ LongArrayQueue mitigationCalls = new LongArrayQueue();
+ mitigationCalls.addLast(1000);
+ mitigationCalls.addLast(2000);
+ mitigationCalls.addLast(3000);
+
+ MonitoredPackage pkg = watchdog.newMonitoredPackage(
+ "test", 123, 456, true, mitigationCalls);
+
+ // Make current system uptime 10000ms.
+ moveTimeForwardAndDispatch(9999);
+
+ LongArrayQueue expectedCalls = pkg.normalizeMitigationCalls();
+
+ assertThat(expectedCalls.size()).isEqualTo(mitigationCalls.size());
+
+ for (int i = 0; i < mitigationCalls.size(); i++) {
+ assertThat(expectedCalls.get(i)).isEqualTo(mitigationCalls.get(i) - 10000);
+ }
+ }
+
+ /**
+ * Ensure that a {@link MonitoredPackage} may be correctly written and read in order to persist
+ * across reboots.
+ */
+ @Test
+ public void testWritingAndReadingMonitoredPackage() throws Exception {
+ PackageWatchdog watchdog = createWatchdog();
+
+ LongArrayQueue mitigationCalls = new LongArrayQueue();
+ mitigationCalls.addLast(1000);
+ mitigationCalls.addLast(2000);
+ mitigationCalls.addLast(3000);
+ MonitoredPackage writePkg = watchdog.newMonitoredPackage(
+ "test.package", 1000, 2000, true, mitigationCalls);
+
+ // Move time forward so that the current uptime is 4000ms. Therefore, the written mitigation
+ // calls will each be reduced by 4000.
+ moveTimeForwardAndDispatch(3999);
+ LongArrayQueue expectedCalls = new LongArrayQueue();
+ expectedCalls.addLast(-3000);
+ expectedCalls.addLast(-2000);
+ expectedCalls.addLast(-1000);
+ MonitoredPackage expectedPkg = watchdog.newMonitoredPackage(
+ "test.package", 1000, 2000, true, expectedCalls);
+
+ // Write the package
+ File tmpFile = File.createTempFile("package-watchdog-test", ".xml");
+ AtomicFile testFile = new AtomicFile(tmpFile);
+ FileOutputStream stream = testFile.startWrite();
+ TypedXmlSerializer outputSerializer = Xml.resolveSerializer(stream);
+ outputSerializer.startDocument(null, true);
+ writePkg.writeLocked(outputSerializer);
+ outputSerializer.endDocument();
+ testFile.finishWrite(stream);
+
+ // Read the package
+ TypedXmlPullParser parser = Xml.resolvePullParser(testFile.openRead());
+ XmlUtils.beginDocument(parser, "package");
+ MonitoredPackage readPkg = watchdog.parseMonitoredPackage(parser);
+
+ assertTrue(readPkg.isEqualTo(expectedPkg));
+ }
+
private void adoptShellPermissions(String... permissions) {
InstrumentationRegistry
.getInstrumentation()
diff --git a/tests/StagedInstallTest/TEST_MAPPING b/tests/StagedInstallTest/TEST_MAPPING
index 5a7a5a766b88..fa2a60b21b50 100644
--- a/tests/StagedInstallTest/TEST_MAPPING
+++ b/tests/StagedInstallTest/TEST_MAPPING
@@ -1,5 +1,5 @@
{
- "presubmit": [
+ "presubmit-large": [
{
"name": "StagedInstallInternalTest"
}
diff --git a/wifi/TEST_MAPPING b/wifi/TEST_MAPPING
index 8c515109a309..7ddc30872cb9 100644
--- a/wifi/TEST_MAPPING
+++ b/wifi/TEST_MAPPING
@@ -1,5 +1,5 @@
{
- "presubmit": [
+ "presubmit-large": [
{
"name": "CtsWifiTestCases",
"options": [
@@ -11,9 +11,6 @@
],
"mainline-presubmit": [
{
- "name": "FrameworksWifiApiTests[com.google.android.wifi.apex]"
- },
- {
"name": "CtsWifiTestCases[com.google.android.wifi.apex]",
"options": [
{
diff --git a/wifi/api/current.txt b/wifi/api/current.txt
index ce2b8ca4f2cd..e11b33efcc33 100644
--- a/wifi/api/current.txt
+++ b/wifi/api/current.txt
@@ -332,6 +332,7 @@ package android.net.wifi {
method public boolean is5GHzBandSupported();
method public boolean is6GHzBandSupported();
method @RequiresPermission(android.Manifest.permission.ACCESS_WIFI_STATE) public boolean isAutoWakeupEnabled();
+ method public boolean isBridgedApConcurrencySupported();
method @Deprecated public boolean isDeviceToApRttSupported();
method public boolean isEasyConnectSupported();
method public boolean isEnhancedOpenSupported();
@@ -342,6 +343,7 @@ package android.net.wifi {
method @Deprecated public boolean isScanAlwaysAvailable();
method @RequiresPermission(android.Manifest.permission.ACCESS_WIFI_STATE) public boolean isScanThrottleEnabled();
method public boolean isStaApConcurrencySupported();
+ method public boolean isStaBridgedApConcurrencySupported();
method public boolean isTdlsSupported();
method public boolean isWapiSupported();
method public boolean isWifiEnabled();
diff --git a/wifi/java/android/net/wifi/SoftApConfiguration.java b/wifi/java/android/net/wifi/SoftApConfiguration.java
index fddc8899a0c8..226d1a368223 100644
--- a/wifi/java/android/net/wifi/SoftApConfiguration.java
+++ b/wifi/java/android/net/wifi/SoftApConfiguration.java
@@ -935,6 +935,9 @@ public final class SoftApConfiguration implements Parcelable {
* on the requested bands (if possible).
* <p>
*
+ * Use {@link WifiManager#isBridgedApConcurrencySupported()} to determine
+ * whether or not concurrent APs are supported.
+ *
* @param bands Array of the {@link #BandType}.
* @return Builder for chaining.
* @throws IllegalArgumentException when more than 2 bands are set or an invalid band type
@@ -1007,6 +1010,9 @@ public final class SoftApConfiguration implements Parcelable {
* The {@link SoftApCapability#getSupportedChannelList(int)} can be used to obtain
* valid channels in each band.
*
+ * Use {@link WifiManager#isBridgedApConcurrencySupported()} to determine
+ * whether or not concurrent APs are supported.
+ *
* <p>
* If not set, the default for the channel is the special value 0 which has the framework
* auto-select a valid channel from the band configured with {@link #setBands(int[])}.
diff --git a/wifi/java/android/net/wifi/WifiManager.java b/wifi/java/android/net/wifi/WifiManager.java
index e5aeead2dec0..2b931a380f43 100644
--- a/wifi/java/android/net/wifi/WifiManager.java
+++ b/wifi/java/android/net/wifi/WifiManager.java
@@ -2489,6 +2489,12 @@ public class WifiManager {
/** @hide */
public static final long WIFI_FEATURE_SAE_PK = 0x10000000000L; // SAE-PK
+ /** @hide */
+ public static final long WIFI_FEATURE_STA_BRIDGED_AP = 0x20000000000L; // STA + Bridged AP
+
+ /** @hide */
+ public static final long WIFI_FEATURE_BRIDGED_AP = 0x40000000000L; // Bridged AP
+
private long getSupportedFeatures() {
try {
return mService.getSupportedFeatures();
@@ -2689,6 +2695,40 @@ public class WifiManager {
}
/**
+ * Query whether the device supports Station (STA) + Bridged access point (AP)
+ * concurrency or not.
+ *
+ * The bridged AP support means that the device supports AP + AP concurrency with the 2 APs
+ * bridged together.
+ *
+ * See {@link SoftApConfiguration.Builder#setBands(int[])}
+ * or {@link SoftApConfiguration.Builder#setChannels(SparseIntArray)} to configure bridged AP
+ * when the bridged AP supported.
+ *
+ * @return true if this device supports STA + bridged AP concurrency, false otherwise.
+ */
+ public boolean isStaBridgedApConcurrencySupported() {
+ return isFeatureSupported(WIFI_FEATURE_STA_BRIDGED_AP);
+ }
+
+ /**
+ * Query whether the device supports Bridged Access point (AP) concurrency or not.
+ *
+ * The bridged AP support means that the device supports AP + AP concurrency with the 2 APs
+ * bridged together.
+ *
+ * See {@link SoftApConfiguration.Builder#setBands(int[])}
+ * or {@link SoftApConfiguration.Builder#setChannels(SparseIntArray)} to configure bridged AP
+ * when the bridged AP supported.
+ *
+ * @return true if this device supports bridged AP concurrency, false otherwise.
+ */
+ public boolean isBridgedApConcurrencySupported() {
+ return isFeatureSupported(WIFI_FEATURE_BRIDGED_AP);
+ }
+
+
+ /**
* Interface for Wi-Fi activity energy info listener. Should be implemented by applications and
* set when calling {@link WifiManager#getWifiActivityEnergyInfoAsync}.
*
diff --git a/wifi/java/android/net/wifi/WifiNetworkSuggestion.java b/wifi/java/android/net/wifi/WifiNetworkSuggestion.java
index e606d533a532..b7450c538ff8 100644
--- a/wifi/java/android/net/wifi/WifiNetworkSuggestion.java
+++ b/wifi/java/android/net/wifi/WifiNetworkSuggestion.java
@@ -917,6 +917,9 @@ public final class WifiNetworkSuggestion implements Parcelable {
mPasspointConfiguration.setCarrierId(mCarrierId);
mPasspointConfiguration.setSubscriptionId(mSubscriptionId);
mPasspointConfiguration.setMeteredOverride(wifiConfiguration.meteredOverride);
+ mPasspointConfiguration.setOemPrivate(mIsNetworkOemPrivate);
+ mPasspointConfiguration.setOemPaid(mIsNetworkOemPaid);
+ mPasspointConfiguration.setCarrierMerged(mIsCarrierMerged);
wifiConfiguration.macRandomizationSetting = mIsEnhancedMacRandomizationEnabled
? WifiConfiguration.RANDOMIZATION_ENHANCED
: WifiConfiguration.RANDOMIZATION_PERSISTENT;
diff --git a/wifi/java/android/net/wifi/hotspot2/PasspointConfiguration.java b/wifi/java/android/net/wifi/hotspot2/PasspointConfiguration.java
index 357c5bcfa265..006fbaa028bd 100644
--- a/wifi/java/android/net/wifi/hotspot2/PasspointConfiguration.java
+++ b/wifi/java/android/net/wifi/hotspot2/PasspointConfiguration.java
@@ -474,6 +474,27 @@ public final class PasspointConfiguration implements Parcelable {
*/
private boolean mIsEnhancedMacRandomizationEnabled = false;
+
+ /**
+ * Indicate whether the network is oem paid or not. Networks are considered oem paid
+ * if the corresponding connection is only available to system apps.
+ * @hide
+ */
+ private boolean mIsOemPaid;
+
+ /**
+ * Indicate whether the network is oem private or not. Networks are considered oem private
+ * if the corresponding connection is only available to system apps.
+ * @hide
+ */
+ private boolean mIsOemPrivate;
+
+ /**
+ * Indicate whether or not the network is a carrier merged network.
+ * @hide
+ */
+ private boolean mIsCarrierMerged;
+
/**
* Indicates if the end user has expressed an explicit opinion about the
* meteredness of this network, such as through the Settings app.
@@ -589,6 +610,54 @@ public final class PasspointConfiguration implements Parcelable {
}
/**
+ * Set whether the network is oem paid or not.
+ * @hide
+ */
+ public void setOemPaid(boolean isOemPaid) {
+ mIsOemPaid = isOemPaid;
+ }
+
+ /**
+ * Get whether the network is oem paid or not.
+ * @hide
+ */
+ public boolean isOemPaid() {
+ return mIsOemPaid;
+ }
+
+ /**
+ * Set whether the network is oem private or not.
+ * @hide
+ */
+ public void setOemPrivate(boolean isOemPrivate) {
+ mIsOemPrivate = isOemPrivate;
+ }
+
+ /**
+ * Get whether the network is oem private or not.
+ * @hide
+ */
+ public boolean isOemPrivate() {
+ return mIsOemPrivate;
+ }
+
+ /**
+ * Set whether the network is carrier merged or not.
+ * @hide
+ */
+ public void setCarrierMerged(boolean isCarrierMerged) {
+ mIsCarrierMerged = isCarrierMerged;
+ }
+
+ /**
+ * Get whether the network is carrier merged or not.
+ * @hide
+ */
+ public boolean isCarrierMerged() {
+ return mIsCarrierMerged;
+ }
+
+ /**
* Constructor for creating PasspointConfiguration with default values.
*/
public PasspointConfiguration() {}
@@ -635,6 +704,9 @@ public final class PasspointConfiguration implements Parcelable {
mIsMacRandomizationEnabled = source.mIsMacRandomizationEnabled;
mIsEnhancedMacRandomizationEnabled = source.mIsEnhancedMacRandomizationEnabled;
mMeteredOverride = source.mMeteredOverride;
+ mIsCarrierMerged = source.mIsCarrierMerged;
+ mIsOemPaid = source.mIsOemPaid;
+ mIsOemPrivate = source.mIsOemPrivate;
}
@Override
@@ -669,6 +741,9 @@ public final class PasspointConfiguration implements Parcelable {
dest.writeBoolean(mIsEnhancedMacRandomizationEnabled);
dest.writeInt(mMeteredOverride);
dest.writeInt(mSubscriptionId);
+ dest.writeBoolean(mIsCarrierMerged);
+ dest.writeBoolean(mIsOemPaid);
+ dest.writeBoolean(mIsOemPrivate);
}
@Override
@@ -700,6 +775,9 @@ public final class PasspointConfiguration implements Parcelable {
&& mUsageLimitTimeLimitInMinutes == that.mUsageLimitTimeLimitInMinutes
&& mCarrierId == that.mCarrierId
&& mSubscriptionId == that.mSubscriptionId
+ && mIsOemPrivate == that.mIsOemPrivate
+ && mIsOemPaid == that.mIsOemPaid
+ && mIsCarrierMerged == that.mIsCarrierMerged
&& mIsAutojoinEnabled == that.mIsAutojoinEnabled
&& mIsMacRandomizationEnabled == that.mIsMacRandomizationEnabled
&& mIsEnhancedMacRandomizationEnabled == that.mIsEnhancedMacRandomizationEnabled
@@ -715,7 +793,8 @@ public final class PasspointConfiguration implements Parcelable {
mSubscriptionExpirationTimeMillis, mUsageLimitUsageTimePeriodInMinutes,
mUsageLimitStartTimeInMillis, mUsageLimitDataLimit, mUsageLimitTimeLimitInMinutes,
mServiceFriendlyNames, mCarrierId, mIsAutojoinEnabled, mIsMacRandomizationEnabled,
- mIsEnhancedMacRandomizationEnabled, mMeteredOverride, mSubscriptionId);
+ mIsEnhancedMacRandomizationEnabled, mMeteredOverride, mSubscriptionId,
+ mIsCarrierMerged, mIsOemPaid, mIsOemPrivate);
}
@Override
@@ -774,6 +853,9 @@ public final class PasspointConfiguration implements Parcelable {
builder.append("mIsMacRandomizationEnabled:" + mIsMacRandomizationEnabled);
builder.append("mIsEnhancedMacRandomizationEnabled:" + mIsEnhancedMacRandomizationEnabled);
builder.append("mMeteredOverride:" + mMeteredOverride);
+ builder.append("mIsCarrierMerged:" + mIsCarrierMerged);
+ builder.append("mIsOemPaid:" + mIsOemPaid);
+ builder.append("mIsOemPrivate" + mIsOemPrivate);
return builder.toString();
}
@@ -884,6 +966,10 @@ public final class PasspointConfiguration implements Parcelable {
config.mIsEnhancedMacRandomizationEnabled = in.readBoolean();
config.mMeteredOverride = in.readInt();
config.mSubscriptionId = in.readInt();
+ config.mIsCarrierMerged = in.readBoolean();
+ config.mIsOemPaid = in.readBoolean();
+ config.mIsOemPrivate = in.readBoolean();
+
return config;
}
diff --git a/wifi/tests/src/android/net/wifi/WifiNetworkSuggestionTest.java b/wifi/tests/src/android/net/wifi/WifiNetworkSuggestionTest.java
index 643a78c38f91..5e829188f93f 100644
--- a/wifi/tests/src/android/net/wifi/WifiNetworkSuggestionTest.java
+++ b/wifi/tests/src/android/net/wifi/WifiNetworkSuggestionTest.java
@@ -809,7 +809,7 @@ public class WifiNetworkSuggestionTest {
/**
* Ensure {@link WifiNetworkSuggestion.Builder#build()} throws an exception
* when both {@link WifiNetworkSuggestion.Builder#setWpa3Passphrase(String)} and
- * {@link WifiNetworkSuggestion.Builderi
+ * {@link WifiNetworkSuggestion.Builder
* #setWpa3EnterpriseStandardModeConfig(WifiEnterpriseConfig)}
* are invoked.
*/
@@ -1310,6 +1310,7 @@ public class WifiNetworkSuggestionTest {
.build();
assertTrue(suggestion.isOemPaid());
assertFalse(suggestion.isUserAllowedToManuallyConnect);
+ assertTrue(suggestion.getPasspointConfig().isOemPaid());
}
/**
@@ -1345,6 +1346,7 @@ public class WifiNetworkSuggestionTest {
.build();
assertTrue(suggestion.isOemPrivate());
assertFalse(suggestion.isUserAllowedToManuallyConnect);
+ assertTrue(suggestion.getPasspointConfig().isOemPrivate());
}
/**
@@ -1439,6 +1441,25 @@ public class WifiNetworkSuggestionTest {
}
/**
+ * Validate {@link WifiNetworkSuggestion.Builder#setCarrierMerged(boolean)} (boolean)} set the
+ * correct value to the passpoint network.
+ */
+ @Test
+ public void testSetCarrierMergedNetworkOnPasspointNetwork() {
+ assumeTrue(SdkLevel.isAtLeastS());
+
+ PasspointConfiguration passpointConfiguration = PasspointTestUtils.createConfig();
+ WifiNetworkSuggestion suggestion = new WifiNetworkSuggestion.Builder()
+ .setPasspointConfig(passpointConfiguration)
+ .setSubscriptionId(1)
+ .setCarrierMerged(true)
+ .setIsMetered(true)
+ .build();
+ assertTrue(suggestion.isCarrierMerged());
+ assertTrue(suggestion.getPasspointConfig().isCarrierMerged());
+ }
+
+ /**
* Ensure {@link WifiNetworkSuggestion.Builder#build()} throws an exception
* when set both {@link WifiNetworkSuggestion.Builder#setCarrierMerged(boolean)} (boolean)}
* to true on a network is not metered.