summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--Android.bp24
-rw-r--r--StubLibraries.bp1
-rw-r--r--apex/blobstore/service/java/com/android/server/blob/BlobStoreManagerService.java12
-rw-r--r--apex/jobscheduler/framework/java/android/app/job/JobParameters.java17
-rw-r--r--apex/jobscheduler/service/java/com/android/server/job/JobPackageTracker.java8
-rw-r--r--apex/jobscheduler/service/java/com/android/server/job/JobSchedulerService.java4
-rw-r--r--apex/jobscheduler/service/java/com/android/server/job/controllers/JobStatus.java22
-rw-r--r--apex/jobscheduler/service/java/com/android/server/usage/AppStandbyController.java100
-rw-r--r--apex/media/framework/java/android/media/MediaParser.java107
-rw-r--r--apex/permission/service/java/com/android/permission/persistence/RuntimePermissionsPersistence.java6
-rw-r--r--apex/permission/service/java/com/android/permission/persistence/RuntimePermissionsPersistenceImpl.java6
-rw-r--r--apex/permission/service/java/com/android/role/persistence/RolesPersistence.java6
-rw-r--r--apex/permission/service/java/com/android/role/persistence/RolesPersistenceImpl.java7
-rw-r--r--apex/statsd/Android.bp12
-rw-r--r--apex/statsd/statsd.rc (renamed from cmds/statsd/statsd.rc)12
-rw-r--r--api/current.txt372
-rw-r--r--api/module-lib-current.txt1
-rw-r--r--api/module-lib-lint-baseline.txt4
-rwxr-xr-xapi/system-current.txt673
-rw-r--r--api/test-current.txt9
-rw-r--r--cmds/hid/jni/com_android_commands_hid_Device.cpp26
-rw-r--r--cmds/hid/jni/com_android_commands_hid_Device.h2
-rw-r--r--cmds/hid/src/com/android/commands/hid/Device.java7
-rw-r--r--cmds/hid/src/com/android/commands/hid/Event.java33
-rw-r--r--cmds/hid/src/com/android/commands/hid/Hid.java2
-rw-r--r--cmds/statsd/Android.bp11
-rw-r--r--cmds/statsd/src/atoms.proto47
-rw-r--r--core/java/android/accessibilityservice/OWNERS1
-rw-r--r--core/java/android/app/ContextImpl.java66
-rw-r--r--core/java/android/app/TaskEmbedder.java2
-rw-r--r--core/java/android/app/WallpaperManager.java2
-rw-r--r--core/java/android/app/admin/DevicePolicyManager.java83
-rw-r--r--core/java/android/app/admin/IDevicePolicyManager.aidl3
-rw-r--r--core/java/android/content/ContentProvider.java9
-rw-r--r--core/java/android/content/ContentProviderNative.java29
-rw-r--r--core/java/android/content/ContentResolver.java53
-rw-r--r--core/java/android/content/Context.java27
-rw-r--r--core/java/android/content/ContextWrapper.java6
-rw-r--r--core/java/android/content/IContentProvider.java11
-rw-r--r--core/java/android/content/pm/IShortcutService.aidl2
-rw-r--r--core/java/android/content/pm/ResolveInfo.java12
-rw-r--r--core/java/android/content/pm/ShortcutInfo.java4
-rw-r--r--core/java/android/content/pm/ShortcutManager.java30
-rw-r--r--core/java/android/hardware/camera2/CameraDevice.java16
-rw-r--r--core/java/android/hardware/camera2/CameraManager.java5
-rw-r--r--core/java/android/hardware/camera2/params/MandatoryStreamCombination.java42
-rw-r--r--core/java/android/hardware/display/DeviceProductInfo.java18
-rw-r--r--core/java/android/net/ConnectivityManager.java11
-rw-r--r--core/java/android/net/IConnectivityManager.aidl5
-rw-r--r--core/java/android/net/NetworkCapabilities.java31
-rw-r--r--core/java/android/os/RecoverySystem.java6
-rw-r--r--core/java/android/os/StrictMode.java43
-rw-r--r--core/java/android/os/incremental/IncrementalStorage.java5
-rw-r--r--core/java/android/os/incremental/V4Signature.java13
-rw-r--r--core/java/android/os/storage/StorageManager.java56
-rw-r--r--core/java/android/os/strictmode/IncorrectContextUseViolation.java (renamed from packages/SystemUI/tests/src/com/android/systemui/screenshot/ScreenshotStubActivity.java)24
-rw-r--r--core/java/android/provider/Settings.java1
-rw-r--r--core/java/android/service/controls/ControlsProviderService.java44
-rw-r--r--core/java/android/util/LongSparseArray.java15
-rw-r--r--core/java/android/view/SurfaceView.java13
-rw-r--r--core/java/android/view/View.java3
-rw-r--r--core/java/android/view/WindowContainerTransaction.java44
-rw-r--r--core/java/android/view/WindowManagerImpl.java6
-rw-r--r--core/java/android/view/accessibility/OWNERS1
-rw-r--r--core/java/android/view/inputmethod/InputMethodManager.java120
-rw-r--r--core/java/android/widget/Editor.java107
-rw-r--r--core/java/android/widget/Magnifier.java83
-rw-r--r--core/java/android/widget/WidgetFlags.java67
-rw-r--r--core/java/com/android/internal/app/ChooserActivity.java6
-rw-r--r--core/java/com/android/internal/content/om/TEST_MAPPING12
-rw-r--r--core/java/com/android/internal/os/PowerProfile.java3
-rw-r--r--core/java/com/android/internal/os/TEST_MAPPING30
-rw-r--r--core/java/com/android/internal/util/function/LongObjPredicate.java35
-rw-r--r--core/java/com/android/internal/view/FloatingActionMode.java2
-rw-r--r--core/java/com/android/internal/view/IInputMethodClient.aidl1
-rw-r--r--core/java/com/android/internal/view/InputBindResult.java42
-rw-r--r--core/java/com/android/internal/view/RotationPolicy.java5
-rw-r--r--core/jni/android_os_storage_StorageManager.cpp20
-rw-r--r--core/jni/android_view_ThreadedRenderer.cpp1
-rw-r--r--core/jni/core_jni_helpers.h12
-rw-r--r--core/res/AndroidManifest.xml3
-rw-r--r--core/res/res/values/config.xml6
-rw-r--r--core/res/res/values/symbols.xml1
-rw-r--r--core/res/res/xml/power_profile.xml6
-rw-r--r--core/tests/coretests/src/android/content/ContentResolverTest.java8
-rw-r--r--core/tests/coretests/src/android/content/ContextTest.java11
-rw-r--r--core/tests/coretests/src/android/content/FakeProviderRemote.java6
-rw-r--r--core/tests/coretests/src/android/service/controls/ControlProviderServiceTest.java35
-rw-r--r--core/tests/coretests/src/android/util/LongSparseArrayTest.java54
-rw-r--r--core/tests/coretests/src/android/view/CutoutSpecificationTest.java19
-rw-r--r--core/tests/coretests/src/android/view/ImeInsetsSourceConsumerTest.java2
-rw-r--r--core/tests/coretests/src/android/view/InsetsControllerTest.java2
-rw-r--r--core/tests/coretests/src/android/view/InsetsSourceConsumerTest.java3
-rw-r--r--core/tests/coretests/src/android/view/ViewRootImplTest.java2
-rw-r--r--core/tests/coretests/src/android/widget/EditorCursorDragTest.java9
-rw-r--r--core/tests/coretests/src/android/widget/TextViewActivityTest.java58
-rw-r--r--core/tests/coretests/src/com/android/internal/policy/DecorContextTest.java5
-rw-r--r--libs/hwui/hwui/Bitmap.cpp14
-rw-r--r--libs/hwui/hwui/Bitmap.h6
-rw-r--r--libs/usb/Android.bp2
-rw-r--r--libs/usb/tests/AccessoryChat/Android.bp1
-rw-r--r--location/java/android/location/LocationManagerInternal.java16
-rw-r--r--location/java/com/android/internal/location/ILocationProvider.aidl2
-rw-r--r--location/lib/api/current.txt1
-rw-r--r--location/lib/java/com/android/location/provider/LocationProviderBase.java16
-rw-r--r--media/java/android/media/DrmInitData.java2
-rw-r--r--media/java/android/media/MediaCodec.java229
-rw-r--r--media/java/android/media/MediaRouter2.java18
-rw-r--r--media/java/android/media/tv/tuner/TunerUtils.java29
-rw-r--r--media/java/android/media/tv/tuner/filter/TimeFilter.java9
-rw-r--r--media/jni/Android.bp5
-rw-r--r--media/jni/android_media_tv_Tuner.cpp176
-rw-r--r--media/jni/android_media_tv_Tuner.h10
-rw-r--r--media/native/Android.bp1
-rw-r--r--packages/CarSystemUI/src/com/android/systemui/volume/CarVolumeDialogImpl.java21
-rw-r--r--packages/DynamicSystemInstallationService/res/values/strings.xml5
-rw-r--r--packages/DynamicSystemInstallationService/src/com/android/dynsystem/DynamicSystemInstallationService.java2
-rw-r--r--packages/SettingsLib/res/values/strings.xml12
-rw-r--r--packages/SettingsLib/src/com/android/settingslib/display/DisplayDensityUtils.java2
-rw-r--r--packages/SystemUI/Android.bp4
-rw-r--r--packages/SystemUI/AndroidManifest.xml3
-rw-r--r--packages/SystemUI/src/com/android/keyguard/KeyguardClockSwitch.java2
-rw-r--r--packages/SystemUI/src/com/android/keyguard/KeyguardDisplayManager.java16
-rw-r--r--packages/SystemUI/src/com/android/keyguard/KeyguardStatusView.java2
-rw-r--r--packages/SystemUI/src/com/android/keyguard/clock/ClockManager.java5
-rw-r--r--packages/SystemUI/src/com/android/systemui/ScreenDecorations.java4
-rw-r--r--packages/SystemUI/src/com/android/systemui/stackdivider/Divider.java3
-rw-r--r--packages/SystemUI/src/com/android/systemui/util/animation/PhysicsAnimator.kt37
-rw-r--r--packages/SystemUI/src/com/android/systemui/util/animation/PhysicsAnimatorTestUtils.kt26
-rw-r--r--packages/SystemUI/src/com/android/systemui/util/magnetictarget/MagnetizedObject.kt618
-rw-r--r--packages/SystemUI/tests/Android.mk3
-rw-r--r--packages/SystemUI/tests/AndroidManifest-base.xml21
-rw-r--r--packages/SystemUI/tests/AndroidManifest.xml7
-rw-r--r--packages/SystemUI/tests/src/com/android/keyguard/KeyguardPresentationTest.java4
-rw-r--r--packages/SystemUI/tests/src/com/android/keyguard/clock/ClockManagerTest.java2
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/NotificationRankingManagerTest.kt24
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/util/magnetictarget/MagnetizedObjectTest.kt442
-rw-r--r--packages/Tethering/common/TetheringLib/Android.bp1
-rw-r--r--packages/Tethering/common/TetheringLib/src/android/net/TetheringConstants.java3
-rw-r--r--packages/Tethering/src/com/android/server/connectivity/tethering/Tethering.java10
-rw-r--r--packages/WallpaperCropper/src/com/android/photos/views/TiledImageRenderer.java2
-rw-r--r--proto/src/system_messages.proto3
-rw-r--r--services/Android.bp3
-rw-r--r--services/accessibility/OWNERS1
-rw-r--r--services/api/current.txt12
-rw-r--r--services/api/lint-baseline.txt30
-rw-r--r--services/appwidget/java/com/android/server/appwidget/AppWidgetServiceImpl.java2
-rw-r--r--services/autofill/java/com/android/server/autofill/ui/CustomScrollView.java2
-rw-r--r--services/autofill/java/com/android/server/autofill/ui/FillUi.java4
-rw-r--r--services/backup/java/com/android/server/backup/restore/PerformUnifiedRestoreTask.java3
-rw-r--r--services/core/java/com/android/server/ConnectivityService.java91
-rw-r--r--services/core/java/com/android/server/LocationManagerService.java16
-rw-r--r--services/core/java/com/android/server/Watchdog.java2
-rw-r--r--services/core/java/com/android/server/am/ActiveServices.java50
-rw-r--r--services/core/java/com/android/server/am/ActivityManagerService.java10
-rw-r--r--services/core/java/com/android/server/am/CoreSettingsObserver.java66
-rw-r--r--services/core/java/com/android/server/am/ProcessList.java17
-rw-r--r--services/core/java/com/android/server/display/DisplayModeDirector.java14
-rw-r--r--services/core/java/com/android/server/inputmethod/InputMethodManagerService.java94
-rw-r--r--services/core/java/com/android/server/location/AbstractLocationProvider.java15
-rw-r--r--services/core/java/com/android/server/location/GnssLocationProvider.java5
-rw-r--r--services/core/java/com/android/server/location/LocationProviderProxy.java8
-rw-r--r--services/core/java/com/android/server/location/MockProvider.java5
-rw-r--r--services/core/java/com/android/server/location/MockableLocationProvider.java9
-rw-r--r--services/core/java/com/android/server/location/PassiveProvider.java5
-rw-r--r--services/core/java/com/android/server/pm/PackageManagerService.java24
-rw-r--r--services/core/java/com/android/server/pm/Settings.java7
-rw-r--r--services/core/java/com/android/server/pm/ShortcutPackage.java54
-rw-r--r--services/core/java/com/android/server/pm/ShortcutService.java45
-rw-r--r--services/core/java/com/android/server/role/RoleUserState.java6
-rw-r--r--services/core/java/com/android/server/stats/pull/StatsPullAtomService.java50
-rw-r--r--services/core/java/com/android/server/wm/ActivityRecord.java8
-rw-r--r--services/core/java/com/android/server/wm/ActivityStack.java168
-rw-r--r--services/core/java/com/android/server/wm/ActivityStackSupervisor.java70
-rw-r--r--services/core/java/com/android/server/wm/ActivityStarter.java5
-rw-r--r--services/core/java/com/android/server/wm/ActivityTaskManagerService.java20
-rw-r--r--services/core/java/com/android/server/wm/BoundsAnimationTarget.java2
-rw-r--r--services/core/java/com/android/server/wm/DisplayContent.java6
-rw-r--r--services/core/java/com/android/server/wm/DisplayPolicy.java24
-rw-r--r--services/core/java/com/android/server/wm/DisplayRotation.java10
-rw-r--r--services/core/java/com/android/server/wm/EnsureActivitiesVisibleHelper.java2
-rw-r--r--services/core/java/com/android/server/wm/InsetsStateController.java1
-rw-r--r--services/core/java/com/android/server/wm/RecentsAnimation.java2
-rw-r--r--services/core/java/com/android/server/wm/RecentsAnimationController.java2
-rw-r--r--services/core/java/com/android/server/wm/ResetTargetTaskHelper.java7
-rw-r--r--services/core/java/com/android/server/wm/RootWindowContainer.java31
-rw-r--r--services/core/java/com/android/server/wm/RunningTasks.java5
-rw-r--r--services/core/java/com/android/server/wm/Task.java74
-rw-r--r--services/core/java/com/android/server/wm/TaskOrganizerController.java9
-rw-r--r--services/core/java/com/android/server/wm/WindowContainer.java8
-rw-r--r--services/core/java/com/android/server/wm/WindowStateAnimator.java8
-rw-r--r--services/core/jni/com_android_server_location_GnssLocationProvider.cpp165
-rw-r--r--services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java84
-rw-r--r--services/java/com/android/server/SystemServer.java6
-rw-r--r--services/people/java/com/android/server/people/data/AbstractProtoDiskReadWriter.java25
-rw-r--r--services/people/java/com/android/server/people/data/ConversationStore.java32
-rw-r--r--services/people/java/com/android/server/people/data/DataManager.java105
-rw-r--r--services/people/java/com/android/server/people/data/Event.java54
-rw-r--r--services/people/java/com/android/server/people/data/EventHistoryImpl.java325
-rw-r--r--services/people/java/com/android/server/people/data/EventIndex.java75
-rw-r--r--services/people/java/com/android/server/people/data/EventList.java50
-rw-r--r--services/people/java/com/android/server/people/data/EventStore.java84
-rw-r--r--services/people/java/com/android/server/people/data/PackageData.java41
-rw-r--r--services/people/java/com/android/server/people/data/UserData.java5
-rw-r--r--services/people/java/com/android/server/people/prediction/AppTargetPredictor.java6
-rw-r--r--services/people/java/com/android/server/people/prediction/ShareTargetPredictor.java138
-rw-r--r--services/tests/mockingservicestests/src/com/android/server/job/controllers/JobStatusTest.java40
-rw-r--r--services/tests/servicestests/src/com/android/server/display/DisplayModeDirectorTest.java77
-rw-r--r--services/tests/servicestests/src/com/android/server/location/MockableLocationProviderTest.java10
-rw-r--r--services/tests/servicestests/src/com/android/server/location/test/FakeProvider.java3
-rw-r--r--services/tests/servicestests/src/com/android/server/people/data/AggregateEventHistoryImplTest.java14
-rw-r--r--services/tests/servicestests/src/com/android/server/people/data/DataManagerTest.java90
-rw-r--r--services/tests/servicestests/src/com/android/server/people/data/EventHistoryImplTest.java162
-rw-r--r--services/tests/servicestests/src/com/android/server/people/data/MockScheduledExecutorService.java47
-rw-r--r--services/tests/servicestests/src/com/android/server/people/data/UsageStatsQueryHelperTest.java40
-rw-r--r--services/tests/servicestests/src/com/android/server/people/prediction/ShareTargetPredictorTest.java186
-rw-r--r--services/tests/servicestests/src/com/android/server/pm/ShortcutManagerTest1.java107
-rw-r--r--services/tests/servicestests/src/com/android/server/usage/AppStandbyControllerTests.java51
-rw-r--r--services/tests/uiservicestests/Android.bp1
-rw-r--r--services/tests/uiservicestests/src/com/android/server/notification/PreferencesHelperTest.java47
-rw-r--r--services/tests/wmtests/src/com/android/server/wm/ActivityRecordTests.java8
-rw-r--r--services/tests/wmtests/src/com/android/server/wm/DisplayContentTests.java14
-rw-r--r--services/tests/wmtests/src/com/android/server/wm/DisplayPolicyLayoutTests.java2
-rw-r--r--services/tests/wmtests/src/com/android/server/wm/RootActivityContainerTests.java12
-rw-r--r--services/tests/wmtests/src/com/android/server/wm/TaskOrganizerTests.java2
-rw-r--r--services/tests/wmtests/src/com/android/server/wm/TaskStackTests.java13
-rw-r--r--services/usage/java/com/android/server/usage/StorageStatsService.java11
-rwxr-xr-xtelecomm/java/android/telecom/Connection.java4
-rw-r--r--telephony/java/android/telephony/Annotation.java2
-rwxr-xr-xtelephony/java/android/telephony/CarrierConfigManager.java65
-rw-r--r--telephony/java/android/telephony/DataFailCause.java22
-rw-r--r--telephony/java/android/telephony/PreciseDataConnectionState.java3
-rw-r--r--telephony/java/com/android/internal/telephony/DctConstants.java3
-rw-r--r--test-mock/src/android/test/mock/MockContentProvider.java18
-rw-r--r--test-mock/src/android/test/mock/MockContext.java6
-rw-r--r--test-mock/src/android/test/mock/MockIContentProvider.java15
-rw-r--r--tests/BootImageProfileTest/DISABLED_TEST_MAPPING (renamed from tests/BootImageProfileTest/TEST_MAPPING)0
-rw-r--r--tests/RollbackTest/MultiUserRollbackTest/src/com/android/tests/rollback/host/MultiUserRollbackTest.java42
-rw-r--r--tests/RollbackTest/RollbackTest/src/com/android/tests/rollback/MultiUserRollbackTest.java7
-rw-r--r--tests/net/AndroidManifest.xml1
-rw-r--r--tests/net/integration/src/com/android/server/net/integrationtests/TestNetworkStackService.kt2
-rw-r--r--tests/net/java/com/android/server/ConnectivityServiceTest.java109
-rw-r--r--tests/utils/testutils/java/com/android/server/wm/test/filters/FrameworksTestsFilter.java1
-rwxr-xr-xwifi/java/android/net/wifi/WifiOemMigrationHook.java2
244 files changed, 6095 insertions, 2321 deletions
diff --git a/Android.bp b/Android.bp
index 68efd59d10f7..b6483a0e3dc4 100644
--- a/Android.bp
+++ b/Android.bp
@@ -327,7 +327,6 @@ java_defaults {
"rs/java",
"sax/java",
"telecomm/java",
- "wifi/aidl-export",
],
},
}
@@ -1030,22 +1029,6 @@ aidl_interface {
},
}
-
-subdirs = [
- "cmds/*",
- "core/*",
- "libs/*",
- "media/*",
- "proto",
- "tools/*",
- "native/android",
- "native/graphics/jni",
-]
-
-optional_subdirs = [
- "core/tests/utiltests/jni",
-]
-
// TODO(b/77285514): remove this once the last few hidl interfaces have been
// updated to use hwbinder.stubs.
java_library {
@@ -1105,13 +1088,6 @@ python_binary_host {
}
filegroup {
- name: "framework-annotation-nonnull-srcs",
- srcs: [
- "core/java/android/annotation/NonNull.java",
- ],
-}
-
-filegroup {
name: "framework-media-annotation-srcs",
srcs: [
":framework-annotations",
diff --git a/StubLibraries.bp b/StubLibraries.bp
index 4616ced1226c..7f23df74d2da 100644
--- a/StubLibraries.bp
+++ b/StubLibraries.bp
@@ -49,7 +49,6 @@ stubs_defaults {
":opt-net-voip-srcs",
":core-current-stubs-source",
":core_public_api_files",
- ":ike-api-srcs",
],
// TODO(b/147699819): remove below aidl includes.
aidl: {
diff --git a/apex/blobstore/service/java/com/android/server/blob/BlobStoreManagerService.java b/apex/blobstore/service/java/com/android/server/blob/BlobStoreManagerService.java
index aae33d7b0a89..18b1108aab3a 100644
--- a/apex/blobstore/service/java/com/android/server/blob/BlobStoreManagerService.java
+++ b/apex/blobstore/service/java/com/android/server/blob/BlobStoreManagerService.java
@@ -858,12 +858,9 @@ public class BlobStoreManagerService extends SystemService {
writeBlobsInfoAsync();
// Cleanup any stale sessions.
- final ArrayList<Integer> indicesToRemove = new ArrayList<>();
for (int i = 0, userCount = mSessions.size(); i < userCount; ++i) {
final LongSparseArray<BlobStoreSession> userSessions = mSessions.valueAt(i);
- indicesToRemove.clear();
- for (int j = 0, sessionsCount = userSessions.size(); j < sessionsCount; ++j) {
- final BlobStoreSession blobStoreSession = userSessions.valueAt(j);
+ userSessions.removeIf((sessionId, blobStoreSession) -> {
boolean shouldRemove = false;
// Cleanup sessions which haven't been modified in a while.
@@ -880,13 +877,10 @@ public class BlobStoreManagerService extends SystemService {
if (shouldRemove) {
blobStoreSession.getSessionFile().delete();
mActiveBlobIds.remove(blobStoreSession.getSessionId());
- indicesToRemove.add(j);
deletedBlobIds.add(blobStoreSession.getSessionId());
}
- }
- for (int j = 0; j < indicesToRemove.size(); ++j) {
- userSessions.removeAt(indicesToRemove.get(j));
- }
+ return shouldRemove;
+ });
}
if (LOGV) {
Slog.v(TAG, "Completed idle maintenance; deleted "
diff --git a/apex/jobscheduler/framework/java/android/app/job/JobParameters.java b/apex/jobscheduler/framework/java/android/app/job/JobParameters.java
index b96161aba758..4c98b5fd3b56 100644
--- a/apex/jobscheduler/framework/java/android/app/job/JobParameters.java
+++ b/apex/jobscheduler/framework/java/android/app/job/JobParameters.java
@@ -77,11 +77,11 @@ public class JobParameters implements Parcelable {
/**
* @hide
- * @deprecated use {@link #getReasonCodeDescription(int)}
*/
- @Deprecated
- public static String getReasonName(int reason) {
- switch (reason) {
+ // TODO(142420609): make it @SystemApi for mainline
+ @NonNull
+ public static String getReasonCodeDescription(int reasonCode) {
+ switch (reasonCode) {
case REASON_CANCELED: return "canceled";
case REASON_CONSTRAINTS_NOT_SATISFIED: return "constraints";
case REASON_PREEMPT: return "preempt";
@@ -89,7 +89,7 @@ public class JobParameters implements Parcelable {
case REASON_DEVICE_IDLE: return "device_idle";
case REASON_DEVICE_THERMAL: return "thermal";
case REASON_RESTRAINED: return "restrained";
- default: return "unknown:" + reason;
+ default: return "unknown:" + reasonCode;
}
}
@@ -100,13 +100,6 @@ public class JobParameters implements Parcelable {
return JOB_STOP_REASON_CODES;
}
- /** @hide */
- // @SystemApi TODO make it a system api for mainline
- @NonNull
- public static String getReasonCodeDescription(int reasonCode) {
- return getReasonName(reasonCode);
- }
-
@UnsupportedAppUsage
private final int jobId;
private final PersistableBundle extras;
diff --git a/apex/jobscheduler/service/java/com/android/server/job/JobPackageTracker.java b/apex/jobscheduler/service/java/com/android/server/job/JobPackageTracker.java
index e28e5bd6c53d..d05034797f3d 100644
--- a/apex/jobscheduler/service/java/com/android/server/job/JobPackageTracker.java
+++ b/apex/jobscheduler/service/java/com/android/server/job/JobPackageTracker.java
@@ -359,7 +359,8 @@ public final class JobPackageTracker {
}
pw.print(pe.stopReasons.valueAt(k));
pw.print("x ");
- pw.print(JobParameters.getReasonName(pe.stopReasons.keyAt(k)));
+ pw.print(JobParameters
+ .getReasonCodeDescription(pe.stopReasons.keyAt(k)));
}
pw.println();
}
@@ -606,8 +607,9 @@ public final class JobPackageTracker {
if (reason != null) {
pw.print(mEventReasons[index]);
} else {
- pw.print(JobParameters.getReasonName((mEventCmds[index] & EVENT_STOP_REASON_MASK)
- >> EVENT_STOP_REASON_SHIFT));
+ pw.print(JobParameters.getReasonCodeDescription(
+ (mEventCmds[index] & EVENT_STOP_REASON_MASK)
+ >> EVENT_STOP_REASON_SHIFT));
}
}
pw.println();
diff --git a/apex/jobscheduler/service/java/com/android/server/job/JobSchedulerService.java b/apex/jobscheduler/service/java/com/android/server/job/JobSchedulerService.java
index ff7944d07310..c1e529f3f966 100644
--- a/apex/jobscheduler/service/java/com/android/server/job/JobSchedulerService.java
+++ b/apex/jobscheduler/service/java/com/android/server/job/JobSchedulerService.java
@@ -1963,7 +1963,7 @@ public class JobSchedulerService extends com.android.server.SystemService
if (restriction != null) {
final int reason = restriction.getReason();
serviceContext.cancelExecutingJobLocked(reason,
- "restricted due to " + JobParameters.getReasonName(reason));
+ "restricted due to " + JobParameters.getReasonCodeDescription(reason));
}
}
}
@@ -3110,7 +3110,7 @@ public class JobSchedulerService extends com.android.server.SystemService
final JobRestriction restriction = mJobRestrictions.get(i);
if (restriction.isJobRestricted(job)) {
final int reason = restriction.getReason();
- pw.write(" " + JobParameters.getReasonName(reason) + "[" + reason + "]");
+ pw.print(" " + JobParameters.getReasonCodeDescription(reason));
}
}
} else {
diff --git a/apex/jobscheduler/service/java/com/android/server/job/controllers/JobStatus.java b/apex/jobscheduler/service/java/com/android/server/job/controllers/JobStatus.java
index 789f20b44ce0..b63cc1918a7a 100644
--- a/apex/jobscheduler/service/java/com/android/server/job/controllers/JobStatus.java
+++ b/apex/jobscheduler/service/java/com/android/server/job/controllers/JobStatus.java
@@ -39,6 +39,7 @@ import android.util.Slog;
import android.util.TimeUtils;
import android.util.proto.ProtoOutputStream;
+import com.android.internal.util.ArrayUtils;
import com.android.internal.util.FrameworkStatsLog;
import com.android.server.LocalServices;
import com.android.server.job.GrantedUriPermissions;
@@ -97,6 +98,15 @@ public final class JobStatus {
| CONSTRAINT_IDLE;
/**
+ * Standard media URIs that contain the media files that might be important to the user.
+ * @see #mHasMediaBackupExemption
+ */
+ private static final Uri[] MEDIA_URIS_FOR_STANDBY_EXEMPTION = {
+ MediaStore.Images.Media.EXTERNAL_CONTENT_URI,
+ MediaStore.Video.Media.EXTERNAL_CONTENT_URI,
+ };
+
+ /**
* The constraints that we want to log to statsd.
*
* Constraints that can be inferred from other atoms have been excluded to avoid logging too
@@ -441,13 +451,13 @@ public final class JobStatus {
if (latestRunTimeElapsedMillis != NO_LATEST_RUNTIME) {
requiredConstraints |= CONSTRAINT_DEADLINE;
}
- boolean mediaOnly = false;
+ boolean exemptedMediaUrisOnly = false;
if (job.getTriggerContentUris() != null) {
requiredConstraints |= CONSTRAINT_CONTENT_TRIGGER;
- mediaOnly = true;
+ exemptedMediaUrisOnly = true;
for (JobInfo.TriggerContentUri uri : job.getTriggerContentUris()) {
- if (!MediaStore.AUTHORITY.equals(uri.getUri().getAuthority())) {
- mediaOnly = false;
+ if (!ArrayUtils.contains(MEDIA_URIS_FOR_STANDBY_EXEMPTION, uri.getUri())) {
+ exemptedMediaUrisOnly = false;
break;
}
}
@@ -475,8 +485,8 @@ public final class JobStatus {
job.getRequiredNetwork().networkCapabilities.setSingleUid(this.sourceUid);
}
final JobSchedulerInternal jsi = LocalServices.getService(JobSchedulerInternal.class);
- mHasMediaBackupExemption = !job.hasLateConstraint() && mediaOnly && requiresNetwork
- && this.sourcePackageName.equals(jsi.getMediaBackupPackage());
+ mHasMediaBackupExemption = !job.hasLateConstraint() && exemptedMediaUrisOnly
+ && requiresNetwork && this.sourcePackageName.equals(jsi.getMediaBackupPackage());
}
/** Copy constructor: used specifically when cloning JobStatus objects for persistence,
diff --git a/apex/jobscheduler/service/java/com/android/server/usage/AppStandbyController.java b/apex/jobscheduler/service/java/com/android/server/usage/AppStandbyController.java
index bf61eb4db29a..a4ab31d7b49a 100644
--- a/apex/jobscheduler/service/java/com/android/server/usage/AppStandbyController.java
+++ b/apex/jobscheduler/service/java/com/android/server/usage/AppStandbyController.java
@@ -65,6 +65,7 @@ import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.content.pm.ApplicationInfo;
+import android.content.pm.CrossProfileAppsInternal;
import android.content.pm.PackageInfo;
import android.content.pm.PackageManager;
import android.content.pm.PackageManagerInternal;
@@ -283,6 +284,12 @@ public class AppStandbyController implements AppStandbyInternal {
* start is the first usage of the app
*/
long mInitialForegroundServiceStartTimeoutMillis;
+ /**
+ * User usage that would elevate an app's standby bucket will also elevate the standby bucket of
+ * cross profile connected apps. Explicit standby bucket setting via
+ * {@link #setAppStandbyBucket(String, int, int, int, int)} will not be propagated.
+ */
+ boolean mLinkCrossProfileApps;
private volatile boolean mAppIdleEnabled;
private boolean mIsCharging;
@@ -445,10 +452,12 @@ public class AppStandbyController implements AppStandbyInternal {
continue;
}
if (!packageName.equals(providerPkgName)) {
+ final List<UserHandle> linkedProfiles = getCrossProfileTargets(packageName,
+ userId);
synchronized (mAppIdleLock) {
- reportNoninteractiveUsageLocked(packageName, userId, STANDBY_BUCKET_ACTIVE,
- REASON_SUB_USAGE_SYNC_ADAPTER, elapsedRealtime,
- mSyncAdapterTimeoutMillis);
+ reportNoninteractiveUsageCrossUserLocked(packageName, userId,
+ STANDBY_BUCKET_ACTIVE, REASON_SUB_USAGE_SYNC_ADAPTER,
+ elapsedRealtime, mSyncAdapterTimeoutMillis, linkedProfiles);
}
}
} catch (PackageManager.NameNotFoundException e) {
@@ -477,10 +486,10 @@ public class AppStandbyController implements AppStandbyInternal {
}
final long elapsedRealtime = mInjector.elapsedRealtime();
-
+ final List<UserHandle> linkedProfiles = getCrossProfileTargets(packageName, userId);
synchronized (mAppIdleLock) {
- reportNoninteractiveUsageLocked(packageName, userId, bucketToPromote,
- usageReason, elapsedRealtime, durationMillis);
+ reportNoninteractiveUsageCrossUserLocked(packageName, userId, bucketToPromote,
+ usageReason, elapsedRealtime, durationMillis, linkedProfiles);
}
}
@@ -492,10 +501,11 @@ public class AppStandbyController implements AppStandbyInternal {
final int currentBucket =
mAppIdleHistory.getAppStandbyBucket(packageName, userId, elapsedRealtime);
if (currentBucket == STANDBY_BUCKET_NEVER) {
+ final List<UserHandle> linkedProfiles = getCrossProfileTargets(packageName, userId);
// Bring the app out of the never bucket
- reportNoninteractiveUsageLocked(packageName, userId, STANDBY_BUCKET_WORKING_SET,
- REASON_SUB_USAGE_UNEXEMPTED_SYNC_SCHEDULED, elapsedRealtime,
- mUnexemptedSyncScheduledTimeoutMillis);
+ reportNoninteractiveUsageCrossUserLocked(packageName, userId,
+ STANDBY_BUCKET_WORKING_SET, REASON_SUB_USAGE_UNEXEMPTED_SYNC_SCHEDULED,
+ elapsedRealtime, mUnexemptedSyncScheduledTimeoutMillis, linkedProfiles);
}
}
}
@@ -504,14 +514,39 @@ public class AppStandbyController implements AppStandbyInternal {
if (!mAppIdleEnabled) return;
final long elapsedRealtime = mInjector.elapsedRealtime();
-
+ final List<UserHandle> linkedProfiles = getCrossProfileTargets(packageName, userId);
synchronized (mAppIdleLock) {
- reportNoninteractiveUsageLocked(packageName, userId, STANDBY_BUCKET_ACTIVE,
+ reportNoninteractiveUsageCrossUserLocked(packageName, userId, STANDBY_BUCKET_ACTIVE,
REASON_SUB_USAGE_EXEMPTED_SYNC_START, elapsedRealtime,
- mExemptedSyncStartTimeoutMillis);
+ mExemptedSyncStartTimeoutMillis, linkedProfiles);
+ }
+ }
+
+ /**
+ * Helper method to report indirect user usage of an app and handle reporting the usage
+ * against cross profile connected apps. <br>
+ * Use {@link #reportNoninteractiveUsageLocked(String, int, int, int, long, long)} if
+ * cross profile connected apps do not need to be handled.
+ */
+ private void reportNoninteractiveUsageCrossUserLocked(String packageName, int userId,
+ int bucket, int subReason, long elapsedRealtime, long nextCheckDelay,
+ List<UserHandle> otherProfiles) {
+ reportNoninteractiveUsageLocked(packageName, userId, bucket, subReason, elapsedRealtime,
+ nextCheckDelay);
+ final int size = otherProfiles.size();
+ for (int profileIndex = 0; profileIndex < size; profileIndex++) {
+ final int otherUserId = otherProfiles.get(profileIndex).getIdentifier();
+ reportNoninteractiveUsageLocked(packageName, otherUserId, bucket, subReason,
+ elapsedRealtime, nextCheckDelay);
}
}
+ /**
+ * Helper method to report indirect user usage of an app. <br>
+ * Use
+ * {@link #reportNoninteractiveUsageCrossUserLocked(String, int, int, int, long, long, List)}
+ * if cross profile connected apps need to be handled.
+ */
private void reportNoninteractiveUsageLocked(String packageName, int userId, int bucket,
int subReason, long elapsedRealtime, long nextCheckDelay) {
final AppUsageHistory appUsage = mAppIdleHistory.reportUsage(packageName, userId, bucket,
@@ -766,8 +801,16 @@ public class AppStandbyController implements AppStandbyInternal {
|| eventType == UsageEvents.Event.SLICE_PINNED
|| eventType == UsageEvents.Event.SLICE_PINNED_PRIV
|| eventType == UsageEvents.Event.FOREGROUND_SERVICE_START)) {
+ final String pkg = event.getPackageName();
+ final List<UserHandle> linkedProfiles = getCrossProfileTargets(pkg, userId);
synchronized (mAppIdleLock) {
- reportEventLocked(event.getPackageName(), eventType, elapsedRealtime, userId);
+ reportEventLocked(pkg, eventType, elapsedRealtime, userId);
+
+ final int size = linkedProfiles.size();
+ for (int profileIndex = 0; profileIndex < size; profileIndex++) {
+ final int linkedUserId = linkedProfiles.get(profileIndex).getIdentifier();
+ reportEventLocked(pkg, eventType, elapsedRealtime, linkedUserId);
+ }
}
}
}
@@ -826,6 +869,16 @@ public class AppStandbyController implements AppStandbyInternal {
}
}
+ /**
+ * Note: don't call this with the lock held since it makes calls to other system services.
+ */
+ private @NonNull List<UserHandle> getCrossProfileTargets(String pkg, int userId) {
+ synchronized (mAppIdleLock) {
+ if (!mLinkCrossProfileApps) return Collections.emptyList();
+ }
+ return mInjector.getValidCrossProfileTargets(pkg, userId);
+ }
+
private int usageEventToSubReason(int eventType) {
switch (eventType) {
case UsageEvents.Event.ACTIVITY_RESUMED: return REASON_SUB_USAGE_MOVE_TO_FOREGROUND;
@@ -1589,6 +1642,7 @@ public class AppStandbyController implements AppStandbyInternal {
private PackageManagerInternal mPackageManagerInternal;
private DisplayManager mDisplayManager;
private PowerManager mPowerManager;
+ private CrossProfileAppsInternal mCrossProfileAppsInternal;
int mBootPhase;
/**
* The minimum amount of time required since the last user interaction before an app can be
@@ -1620,6 +1674,8 @@ public class AppStandbyController implements AppStandbyInternal {
Context.DISPLAY_SERVICE);
mPowerManager = mContext.getSystemService(PowerManager.class);
mBatteryManager = mContext.getSystemService(BatteryManager.class);
+ mCrossProfileAppsInternal = LocalServices.getService(
+ CrossProfileAppsInternal.class);
final ActivityManager activityManager =
(ActivityManager) mContext.getSystemService(Context.ACTIVITY_SERVICE);
@@ -1727,6 +1783,17 @@ public class AppStandbyController implements AppStandbyInternal {
public boolean isDeviceIdleMode() {
return mPowerManager.isDeviceIdleMode();
}
+
+ public List<UserHandle> getValidCrossProfileTargets(String pkg, int userId) {
+ final int uid = mPackageManagerInternal.getPackageUidInternal(pkg, 0, userId);
+ if (uid < 0
+ || !mPackageManagerInternal.getPackage(uid).isCrossProfile()
+ || !mCrossProfileAppsInternal
+ .verifyUidHasInteractAcrossProfilePermission(pkg, uid)) {
+ return Collections.emptyList();
+ }
+ return mCrossProfileAppsInternal.getTargetUserProfiles(pkg, userId);
+ }
}
class AppStandbyHandler extends Handler {
@@ -1857,6 +1924,8 @@ public class AppStandbyController implements AppStandbyInternal {
"initial_foreground_service_start_duration";
private static final String KEY_AUTO_RESTRICTED_BUCKET_DELAY_MS =
"auto_restricted_bucket_delay_ms";
+ private static final String KEY_CROSS_PROFILE_APPS_SHARE_STANDBY_BUCKETS =
+ "cross_profile_apps_share_standby_buckets";
public static final long DEFAULT_STRONG_USAGE_TIMEOUT = 1 * ONE_HOUR;
public static final long DEFAULT_NOTIFICATION_TIMEOUT = 12 * ONE_HOUR;
public static final long DEFAULT_SYSTEM_UPDATE_TIMEOUT = 2 * ONE_HOUR;
@@ -1868,6 +1937,7 @@ public class AppStandbyController implements AppStandbyInternal {
public static final long DEFAULT_UNEXEMPTED_SYNC_SCHEDULED_TIMEOUT = 10 * ONE_MINUTE;
public static final long DEFAULT_INITIAL_FOREGROUND_SERVICE_START_TIMEOUT = 30 * ONE_MINUTE;
public static final long DEFAULT_AUTO_RESTRICTED_BUCKET_DELAY_MS = ONE_DAY;
+ public static final boolean DEFAULT_CROSS_PROFILE_APPS_SHARE_STANDBY_BUCKETS = true;
private final KeyValueListParser mParser = new KeyValueListParser(',');
@@ -1973,6 +2043,10 @@ public class AppStandbyController implements AppStandbyInternal {
mParser.getDurationMillis(KEY_AUTO_RESTRICTED_BUCKET_DELAY_MS,
COMPRESS_TIME
? ONE_MINUTE : DEFAULT_AUTO_RESTRICTED_BUCKET_DELAY_MS));
+
+ mLinkCrossProfileApps = mParser.getBoolean(
+ KEY_CROSS_PROFILE_APPS_SHARE_STANDBY_BUCKETS,
+ DEFAULT_CROSS_PROFILE_APPS_SHARE_STANDBY_BUCKETS);
}
// Check if app_idle_enabled has changed. Do this after getting the rest of the settings
diff --git a/apex/media/framework/java/android/media/MediaParser.java b/apex/media/framework/java/android/media/MediaParser.java
index 7d18578aff66..1ae0c22541c2 100644
--- a/apex/media/framework/java/android/media/MediaParser.java
+++ b/apex/media/framework/java/android/media/MediaParser.java
@@ -375,13 +375,13 @@ public final class MediaParser {
}
/**
- * Thrown if all extractors implementations provided to {@link #create} failed to sniff the
- * input content.
+ * Thrown if all parser implementations provided to {@link #create} failed to sniff the input
+ * content.
*/
public static final class UnrecognizedInputFormatException extends IOException {
/**
- * Creates a new instance which signals that the extractors with the given names failed to
+ * Creates a new instance which signals that the parsers with the given names failed to
* parse the input.
*/
@NonNull
@@ -389,7 +389,7 @@ public final class MediaParser {
private static UnrecognizedInputFormatException createForExtractors(
@NonNull String... extractorNames) {
StringBuilder builder = new StringBuilder();
- builder.append("None of the available extractors ( ");
+ builder.append("None of the available parsers ( ");
builder.append(extractorNames[0]);
for (int i = 1; i < extractorNames.length; i++) {
builder.append(", ");
@@ -411,10 +411,10 @@ public final class MediaParser {
// Instance creation methods.
/**
- * Creates an instance backed by the extractor with the given {@code name}. The returned
- * instance will attempt extraction without sniffing the content.
+ * Creates an instance backed by the parser with the given {@code name}. The returned instance
+ * will attempt parsing without sniffing the content.
*
- * @param name The name of the extractor that will be associated with the created instance.
+ * @param name The name of the parser that will be associated with the created instance.
* @param outputConsumer The {@link OutputConsumer} to which track data and samples are pushed.
* @return A new instance.
* @throws IllegalArgumentException If an invalid name is provided.
@@ -428,42 +428,42 @@ public final class MediaParser {
}
/**
- * Creates an instance whose backing extractor will be selected by sniffing the content during
- * the first {@link #advance} call. Extractor implementations will sniff the content in order of
- * appearance in {@code extractorNames}.
+ * Creates an instance whose backing parser will be selected by sniffing the content during the
+ * first {@link #advance} call. Parser implementations will sniff the content in order of
+ * appearance in {@code parserNames}.
*
* @param outputConsumer The {@link OutputConsumer} to which extracted data is output.
- * @param extractorNames The names of the extractors to sniff the content with. If empty, a
- * default array of names is used.
+ * @param parserNames The names of the parsers to sniff the content with. If empty, a default
+ * array of names is used.
* @return A new instance.
*/
@NonNull
public static MediaParser create(
- @NonNull OutputConsumer outputConsumer, @NonNull String... extractorNames) {
- assertValidNames(extractorNames);
- if (extractorNames.length == 0) {
- extractorNames = EXTRACTOR_FACTORIES_BY_NAME.keySet().toArray(new String[0]);
+ @NonNull OutputConsumer outputConsumer, @NonNull String... parserNames) {
+ assertValidNames(parserNames);
+ if (parserNames.length == 0) {
+ parserNames = EXTRACTOR_FACTORIES_BY_NAME.keySet().toArray(new String[0]);
}
- return new MediaParser(outputConsumer, /* sniff= */ true, extractorNames);
+ return new MediaParser(outputConsumer, /* sniff= */ true, parserNames);
}
// Misc static methods.
/**
- * Returns an immutable list with the names of the extractors that are suitable for container
+ * Returns an immutable list with the names of the parsers that are suitable for container
* formats with the given {@link MediaFormat}.
*
* <p>TODO: List which properties are taken into account. E.g. MimeType.
*/
@NonNull
- public static List<String> getExtractorNames(@NonNull MediaFormat mediaFormat) {
+ public static List<String> getParserNames(@NonNull MediaFormat mediaFormat) {
throw new UnsupportedOperationException();
}
// Private fields.
private final OutputConsumer mOutputConsumer;
- private final String[] mExtractorNamesPool;
+ private final String[] mParserNamesPool;
private final PositionHolder mPositionHolder;
private final InputReadingDataSource mDataSource;
private final ExtractorInputAdapter mScratchExtractorInputAdapter;
@@ -477,18 +477,18 @@ public final class MediaParser {
// Public methods.
/**
- * Returns the name of the backing extractor implementation.
+ * Returns the name of the backing parser implementation.
*
* <p>If this instance was creating using {@link #createByName}, the provided name is returned.
* If this instance was created using {@link #create}, this method will return null until the
- * first call to {@link #advance}, after which the name of the backing extractor implementation
- * is returned.
+ * first call to {@link #advance}, after which the name of the backing parser implementation is
+ * returned.
*
- * @return The name of the backing extractor implementation, or null if the backing extractor
+ * @return The name of the backing parser implementation, or null if the backing parser
* implementation has not yet been selected.
*/
@Nullable
- public String getExtractorName() {
+ public String getParserName() {
return mExtractorName;
}
@@ -499,7 +499,7 @@ public final class MediaParser {
* <p>This method will block until some progress has been made.
*
* <p>If this instance was created using {@link #create}. the first call to this method will
- * sniff the content with the extractors with the provided names.
+ * sniff the content with the parsers with the provided names.
*
* @param seekableInputReader The {@link SeekableInputReader} from which to obtain the media
* container data.
@@ -520,13 +520,15 @@ public final class MediaParser {
}
mDataSource.mInputReader = seekableInputReader;
- if (mExtractor == null) {
- for (String extractorName : mExtractorNamesPool) {
- Extractor extractor =
- EXTRACTOR_FACTORIES_BY_NAME.get(extractorName).createInstance();
+ // TODO: Apply parameters when creating extractor instances.
+ if (mExtractorName != null) {
+ mExtractor = EXTRACTOR_FACTORIES_BY_NAME.get(mExtractorName).createInstance();
+ } else if (mExtractor == null) {
+ for (String parserName : mParserNamesPool) {
+ Extractor extractor = EXTRACTOR_FACTORIES_BY_NAME.get(parserName).createInstance();
try {
if (extractor.sniff(mExtractorInput)) {
- mExtractorName = extractorName;
+ mExtractorName = parserName;
mExtractor = extractor;
mExtractor.init(new ExtractorOutputAdapter());
break;
@@ -540,7 +542,7 @@ public final class MediaParser {
}
}
if (mExtractor == null) {
- throw UnrecognizedInputFormatException.createForExtractors(mExtractorNamesPool);
+ throw UnrecognizedInputFormatException.createForExtractors(mParserNamesPool);
}
return true;
}
@@ -586,22 +588,21 @@ public final class MediaParser {
* Releases any acquired resources.
*
* <p>After calling this method, this instance becomes unusable and no other methods should be
- * invoked. DESIGN NOTE: Should be removed. There shouldn't be any resource for releasing.
+ * invoked.
*/
public void release() {
+ // TODO: Dump media metrics here.
mExtractorInput = null;
mExtractor = null;
}
// Private methods.
- private MediaParser(
- OutputConsumer outputConsumer, boolean sniff, String... extractorNamesPool) {
+ private MediaParser(OutputConsumer outputConsumer, boolean sniff, String... parserNamesPool) {
mOutputConsumer = outputConsumer;
- mExtractorNamesPool = extractorNamesPool;
+ mParserNamesPool = parserNamesPool;
if (!sniff) {
- mExtractorName = extractorNamesPool[0];
- mExtractor = EXTRACTOR_FACTORIES_BY_NAME.get(mExtractorName).createInstance();
+ mExtractorName = parserNamesPool[0];
}
mPositionHolder = new PositionHolder();
mDataSource = new InputReadingDataSource();
@@ -921,7 +922,7 @@ public final class MediaParser {
throw new IllegalArgumentException(
"Invalid extractor name: "
+ name
- + ". Supported extractors are: "
+ + ". Supported parsers are: "
+ TextUtils.join(", ", EXTRACTOR_FACTORIES_BY_NAME.keySet())
+ ".");
}
@@ -933,20 +934,20 @@ public final class MediaParser {
static {
// Using a LinkedHashMap to keep the insertion order when iterating over the keys.
LinkedHashMap<String, ExtractorFactory> extractorFactoriesByName = new LinkedHashMap<>();
- extractorFactoriesByName.put("exo.Ac3Extractor", Ac3Extractor::new);
- extractorFactoriesByName.put("exo.Ac4Extractor", Ac4Extractor::new);
- extractorFactoriesByName.put("exo.AdtsExtractor", AdtsExtractor::new);
- extractorFactoriesByName.put("exo.AmrExtractor", AmrExtractor::new);
- extractorFactoriesByName.put("exo.FlacExtractor", FlacExtractor::new);
- extractorFactoriesByName.put("exo.FlvExtractor", FlvExtractor::new);
- extractorFactoriesByName.put("exo.FragmentedMp4Extractor", FragmentedMp4Extractor::new);
- extractorFactoriesByName.put("exo.MatroskaExtractor", MatroskaExtractor::new);
- extractorFactoriesByName.put("exo.Mp3Extractor", Mp3Extractor::new);
- extractorFactoriesByName.put("exo.Mp4Extractor", Mp4Extractor::new);
- extractorFactoriesByName.put("exo.OggExtractor", OggExtractor::new);
- extractorFactoriesByName.put("exo.PsExtractor", PsExtractor::new);
- extractorFactoriesByName.put("exo.TsExtractor", TsExtractor::new);
- extractorFactoriesByName.put("exo.WavExtractor", WavExtractor::new);
+ extractorFactoriesByName.put("exo.Ac3Parser", Ac3Extractor::new);
+ extractorFactoriesByName.put("exo.Ac4Parser", Ac4Extractor::new);
+ extractorFactoriesByName.put("exo.AdtsParser", AdtsExtractor::new);
+ extractorFactoriesByName.put("exo.AmrParser", AmrExtractor::new);
+ extractorFactoriesByName.put("exo.FlacParser", FlacExtractor::new);
+ extractorFactoriesByName.put("exo.FlvParser", FlvExtractor::new);
+ extractorFactoriesByName.put("exo.FragmentedMp4Parser", FragmentedMp4Extractor::new);
+ extractorFactoriesByName.put("exo.MatroskaParser", MatroskaExtractor::new);
+ extractorFactoriesByName.put("exo.Mp3Parser", Mp3Extractor::new);
+ extractorFactoriesByName.put("exo.Mp4Parser", Mp4Extractor::new);
+ extractorFactoriesByName.put("exo.OggParser", OggExtractor::new);
+ extractorFactoriesByName.put("exo.PsParser", PsExtractor::new);
+ extractorFactoriesByName.put("exo.TsParser", TsExtractor::new);
+ extractorFactoriesByName.put("exo.WavParser", WavExtractor::new);
EXTRACTOR_FACTORIES_BY_NAME = Collections.unmodifiableMap(extractorFactoriesByName);
}
}
diff --git a/apex/permission/service/java/com/android/permission/persistence/RuntimePermissionsPersistence.java b/apex/permission/service/java/com/android/permission/persistence/RuntimePermissionsPersistence.java
index 6c7f82a11908..0d163cf55e4e 100644
--- a/apex/permission/service/java/com/android/permission/persistence/RuntimePermissionsPersistence.java
+++ b/apex/permission/service/java/com/android/permission/persistence/RuntimePermissionsPersistence.java
@@ -40,7 +40,7 @@ public interface RuntimePermissionsPersistence {
* @return the runtime permissions read
*/
@Nullable
- RuntimePermissionsState read(@NonNull UserHandle user);
+ RuntimePermissionsState readAsUser(@NonNull UserHandle user);
/**
* Write the runtime permissions to persistence.
@@ -50,7 +50,7 @@ public interface RuntimePermissionsPersistence {
* @param runtimePermissions the runtime permissions to write
* @param user the user to write for
*/
- void write(@NonNull RuntimePermissionsState runtimePermissions, @NonNull UserHandle user);
+ void writeAsUser(@NonNull RuntimePermissionsState runtimePermissions, @NonNull UserHandle user);
/**
* Delete the runtime permissions from persistence.
@@ -59,7 +59,7 @@ public interface RuntimePermissionsPersistence {
*
* @param user the user to delete for
*/
- void delete(@NonNull UserHandle user);
+ void deleteAsUser(@NonNull UserHandle user);
/**
* Create a new instance of {@link RuntimePermissionsPersistence} implementation.
diff --git a/apex/permission/service/java/com/android/permission/persistence/RuntimePermissionsPersistenceImpl.java b/apex/permission/service/java/com/android/permission/persistence/RuntimePermissionsPersistenceImpl.java
index 90b1c4b6ff5f..205ffc297945 100644
--- a/apex/permission/service/java/com/android/permission/persistence/RuntimePermissionsPersistenceImpl.java
+++ b/apex/permission/service/java/com/android/permission/persistence/RuntimePermissionsPersistenceImpl.java
@@ -67,7 +67,7 @@ public class RuntimePermissionsPersistenceImpl implements RuntimePermissionsPers
@Nullable
@Override
- public RuntimePermissionsState read(@NonNull UserHandle user) {
+ public RuntimePermissionsState readAsUser(@NonNull UserHandle user) {
File file = getFile(user);
try (FileInputStream inputStream = new AtomicFile(file).openRead()) {
XmlPullParser parser = Xml.newPullParser();
@@ -172,7 +172,7 @@ public class RuntimePermissionsPersistenceImpl implements RuntimePermissionsPers
}
@Override
- public void write(@NonNull RuntimePermissionsState runtimePermissions,
+ public void writeAsUser(@NonNull RuntimePermissionsState runtimePermissions,
@NonNull UserHandle user) {
File file = getFile(user);
AtomicFile atomicFile = new AtomicFile(file);
@@ -252,7 +252,7 @@ public class RuntimePermissionsPersistenceImpl implements RuntimePermissionsPers
}
@Override
- public void delete(@NonNull UserHandle user) {
+ public void deleteAsUser(@NonNull UserHandle user) {
getFile(user).delete();
}
diff --git a/apex/permission/service/java/com/android/role/persistence/RolesPersistence.java b/apex/permission/service/java/com/android/role/persistence/RolesPersistence.java
index 2908a3872df9..64d6545c87cf 100644
--- a/apex/permission/service/java/com/android/role/persistence/RolesPersistence.java
+++ b/apex/permission/service/java/com/android/role/persistence/RolesPersistence.java
@@ -40,7 +40,7 @@ public interface RolesPersistence {
* @return the roles read
*/
@Nullable
- RolesState read(@NonNull UserHandle user);
+ RolesState readAsUser(@NonNull UserHandle user);
/**
* Write the roles to persistence.
@@ -50,7 +50,7 @@ public interface RolesPersistence {
* @param roles the roles to write
* @param user the user to write for
*/
- void write(@NonNull RolesState roles, @NonNull UserHandle user);
+ void writeAsUser(@NonNull RolesState roles, @NonNull UserHandle user);
/**
* Delete the roles from persistence.
@@ -59,7 +59,7 @@ public interface RolesPersistence {
*
* @param user the user to delete for
*/
- void delete(@NonNull UserHandle user);
+ void deleteAsUser(@NonNull UserHandle user);
/**
* Create a new instance of {@link RolesPersistence} implementation.
diff --git a/apex/permission/service/java/com/android/role/persistence/RolesPersistenceImpl.java b/apex/permission/service/java/com/android/role/persistence/RolesPersistenceImpl.java
index 06fad77c495c..3031c8213982 100644
--- a/apex/permission/service/java/com/android/role/persistence/RolesPersistenceImpl.java
+++ b/apex/permission/service/java/com/android/role/persistence/RolesPersistenceImpl.java
@@ -65,7 +65,7 @@ public class RolesPersistenceImpl implements RolesPersistence {
@Nullable
@Override
- public RolesState read(@NonNull UserHandle user) {
+ public RolesState readAsUser(@NonNull UserHandle user) {
File file = getFile(user);
try (FileInputStream inputStream = new AtomicFile(file).openRead()) {
XmlPullParser parser = Xml.newPullParser();
@@ -146,8 +146,7 @@ public class RolesPersistenceImpl implements RolesPersistence {
}
@Override
- public void write(@NonNull RolesState roles,
- @NonNull UserHandle user) {
+ public void writeAsUser(@NonNull RolesState roles, @NonNull UserHandle user) {
File file = getFile(user);
AtomicFile atomicFile = new AtomicFile(file);
FileOutputStream outputStream = null;
@@ -206,7 +205,7 @@ public class RolesPersistenceImpl implements RolesPersistence {
}
@Override
- public void delete(@NonNull UserHandle user) {
+ public void deleteAsUser(@NonNull UserHandle user) {
getFile(user).delete();
}
diff --git a/apex/statsd/Android.bp b/apex/statsd/Android.bp
index 0e9311034ee0..2f3e2acb5d7a 100644
--- a/apex/statsd/Android.bp
+++ b/apex/statsd/Android.bp
@@ -21,14 +21,16 @@ apex {
apex_defaults {
native_shared_libs: [
"libstats_jni",
+ "libstatspull",
+ "libstatssocket",
],
- // binaries: ["vold"],
+ binaries: ["statsd"],
java_libs: [
"framework-statsd",
"service-statsd",
],
compile_multilib: "both",
- // prebuilts: ["my_prebuilt"],
+ prebuilts: ["com.android.os.statsd.init.rc"],
name: "com.android.os.statsd-defaults",
key: "com.android.os.statsd.key",
certificate: ":com.android.os.statsd.certificate",
@@ -47,6 +49,12 @@ android_app_certificate {
certificate: "com.android.os.statsd",
}
+prebuilt_etc {
+ name: "com.android.os.statsd.init.rc",
+ src: "statsd.rc",
+ filename: "init.rc",
+ installable: false,
+}
// JNI library for StatsLog.write
cc_library_shared {
diff --git a/cmds/statsd/statsd.rc b/apex/statsd/statsd.rc
index a98ecd586b42..605da2af0c19 100644
--- a/cmds/statsd/statsd.rc
+++ b/apex/statsd/statsd.rc
@@ -12,19 +12,9 @@
# See the License for the specific language governing permissions and
# limitations under the License.
-service statsd /system/bin/statsd
+service statsd /apex/com.android.os.statsd/bin/statsd
class main
socket statsdw dgram+passcred 0222 statsd statsd
user statsd
group statsd log
writepid /dev/cpuset/system-background/tasks
-
-on property:ro.statsd.enable=false
- stop statsd
-
-on post-fs-data
- # Create directory for statsd
- mkdir /data/misc/stats-data/ 0770 statsd system
- mkdir /data/misc/stats-service/ 0770 statsd system
- mkdir /data/misc/stats-active-metric/ 0770 statsd system
- mkdir /data/misc/train-info/ 0770 statsd system
diff --git a/api/current.txt b/api/current.txt
index c6bb79f5bf26..c69dbff53aca 100644
--- a/api/current.txt
+++ b/api/current.txt
@@ -32,6 +32,7 @@ package android {
field public static final String BIND_CARRIER_SERVICES = "android.permission.BIND_CARRIER_SERVICES";
field @Deprecated public static final String BIND_CHOOSER_TARGET_SERVICE = "android.permission.BIND_CHOOSER_TARGET_SERVICE";
field public static final String BIND_CONDITION_PROVIDER_SERVICE = "android.permission.BIND_CONDITION_PROVIDER_SERVICE";
+ field public static final String BIND_CONTROLS = "android.permission.BIND_CONTROLS";
field public static final String BIND_DEVICE_ADMIN = "android.permission.BIND_DEVICE_ADMIN";
field public static final String BIND_DREAM_SERVICE = "android.permission.BIND_DREAM_SERVICE";
field public static final String BIND_INCALL_SERVICE = "android.permission.BIND_INCALL_SERVICE";
@@ -6969,7 +6970,6 @@ package android.app.admin {
method public boolean removeOverrideApn(@NonNull android.content.ComponentName, int);
method public boolean removeUser(@NonNull android.content.ComponentName, @NonNull android.os.UserHandle);
method public boolean requestBugreport(@NonNull android.content.ComponentName);
- method public void requestSetLocationProviderAllowed(@NonNull android.content.ComponentName, @NonNull String, boolean);
method @Deprecated public boolean resetPassword(String, int);
method public boolean resetPasswordWithToken(@NonNull android.content.ComponentName, String, byte[], int);
method @Nullable public java.util.List<android.app.admin.NetworkEvent> retrieveNetworkLogs(@Nullable android.content.ComponentName, long);
@@ -12328,6 +12328,7 @@ package android.content.pm {
method public int describeContents();
method public void dump(android.util.Printer, String);
method public final int getIconResource();
+ method public boolean isCrossProfileIntentForwarderActivity();
method public android.graphics.drawable.Drawable loadIcon(android.content.pm.PackageManager);
method public CharSequence loadLabel(android.content.pm.PackageManager);
method public void writeToParcel(android.os.Parcel, int);
@@ -12466,6 +12467,7 @@ package android.content.pm {
method @NonNull public java.util.List<android.content.pm.ShortcutInfo> getShortcuts(int);
method public boolean isRateLimitingActive();
method public boolean isRequestPinShortcutSupported();
+ method public void pushDynamicShortcut(@NonNull android.content.pm.ShortcutInfo);
method public void removeAllDynamicShortcuts();
method public void removeDynamicShortcuts(@NonNull java.util.List<java.lang.String>);
method public void removeLongLivedShortcuts(@NonNull java.util.List<java.lang.String>);
@@ -24786,7 +24788,7 @@ package android.media {
}
public abstract class DrmInitData {
- method public abstract android.media.DrmInitData.SchemeInitData get(java.util.UUID);
+ method @Deprecated public abstract android.media.DrmInitData.SchemeInitData get(java.util.UUID);
method @NonNull public android.media.DrmInitData.SchemeInitData getSchemeInitDataAt(int);
method public int getSchemeInitDataCount();
}
@@ -25305,6 +25307,10 @@ package android.media {
method public void recycle();
}
+ public class MediaCodec.IncompatibleWithBlockModelException extends java.lang.RuntimeException {
+ ctor public MediaCodec.IncompatibleWithBlockModelException();
+ }
+
public static final class MediaCodec.LinearBlock {
method protected void finalize();
method public static boolean isCodecCopyFreeCompatible(@NonNull String[]);
@@ -25332,23 +25338,24 @@ package android.media {
}
public static final class MediaCodec.OutputFrame {
- method public void getChangedKeys(@NonNull java.util.Set<java.lang.String>);
method public int getFlags();
method @NonNull public android.media.MediaFormat getFormat();
method @Nullable public android.media.MediaCodec.GraphicBlock getGraphicBlock();
method @Nullable public android.media.MediaCodec.LinearBlock getLinearBlock();
method public long getPresentationTimeUs();
+ method public void retrieveChangedKeys(@NonNull java.util.Set<java.lang.String>);
}
public final class MediaCodec.QueueRequest {
method public void queue();
method @NonNull public android.media.MediaCodec.QueueRequest setByteBufferParameter(@NonNull String, @NonNull java.nio.ByteBuffer);
- method @NonNull public android.media.MediaCodec.QueueRequest setEncryptedLinearBlock(@NonNull android.media.MediaCodec.LinearBlock, int, @NonNull android.media.MediaCodec.CryptoInfo, long, int);
+ method @NonNull public android.media.MediaCodec.QueueRequest setFlags(int);
method @NonNull public android.media.MediaCodec.QueueRequest setFloatParameter(@NonNull String, float);
- method @NonNull public android.media.MediaCodec.QueueRequest setGraphicBlock(@NonNull android.media.MediaCodec.GraphicBlock, long, int);
+ method @NonNull public android.media.MediaCodec.QueueRequest setGraphicBlock(@NonNull android.media.MediaCodec.GraphicBlock);
method @NonNull public android.media.MediaCodec.QueueRequest setIntegerParameter(@NonNull String, int);
- method @NonNull public android.media.MediaCodec.QueueRequest setLinearBlock(@NonNull android.media.MediaCodec.LinearBlock, int, int, long, int);
+ method @NonNull public android.media.MediaCodec.QueueRequest setLinearBlock(@NonNull android.media.MediaCodec.LinearBlock, int, int, @Nullable android.media.MediaCodec.CryptoInfo);
method @NonNull public android.media.MediaCodec.QueueRequest setLongParameter(@NonNull String, long);
+ method @NonNull public android.media.MediaCodec.QueueRequest setPresentationTimeUs(long);
method @NonNull public android.media.MediaCodec.QueueRequest setStringParameter(@NonNull String, @NonNull String);
}
@@ -26402,8 +26409,8 @@ package android.media {
method public boolean advance(@NonNull android.media.MediaParser.SeekableInputReader) throws java.io.IOException, java.lang.InterruptedException;
method @NonNull public static android.media.MediaParser create(@NonNull android.media.MediaParser.OutputConsumer, @NonNull java.lang.String...);
method @NonNull public static android.media.MediaParser createByName(@NonNull String, @NonNull android.media.MediaParser.OutputConsumer);
- method @Nullable public String getExtractorName();
- method @NonNull public static java.util.List<java.lang.String> getExtractorNames(@NonNull android.media.MediaFormat);
+ method @Nullable public String getParserName();
+ method @NonNull public static java.util.List<java.lang.String> getParserNames(@NonNull android.media.MediaFormat);
method public void release();
method public void seek(@NonNull android.media.MediaParser.SeekPoint);
}
@@ -43399,6 +43406,7 @@ package android.service.controls {
method @NonNull public abstract java.util.concurrent.Flow.Publisher<android.service.controls.Control> publisherFor(@NonNull java.util.List<java.lang.String>);
method @Nullable public java.util.concurrent.Flow.Publisher<android.service.controls.Control> publisherForAllAvailable();
method @Nullable public java.util.concurrent.Flow.Publisher<android.service.controls.Control> publisherForSuggested();
+ method public static void requestAddControl(@NonNull android.content.Context, @NonNull android.content.ComponentName, @NonNull android.service.controls.Control);
field public static final String SERVICE_CONTROLS = "android.service.controls.ControlsProviderService";
field @NonNull public static final String TAG = "ControlsProviderService";
}
@@ -45645,7 +45653,7 @@ package android.telecom {
method public final android.telecom.CallAudioState getCallAudioState();
method public final String getCallerDisplayName();
method public final int getCallerDisplayNamePresentation();
- method public int getCallerNumberVerificationStatus();
+ method public final int getCallerNumberVerificationStatus();
method public final android.telecom.Conference getConference();
method public final java.util.List<android.telecom.Conferenceable> getConferenceables();
method public final int getConnectionCapabilities();
@@ -45698,7 +45706,7 @@ package android.telecom {
method public final void setAudioModeIsVoip(boolean);
method public final void setAudioRoute(int);
method public final void setCallerDisplayName(String, int);
- method public void setCallerNumberVerificationStatus(int);
+ method public final void setCallerNumberVerificationStatus(int);
method public final void setConferenceableConnections(java.util.List<android.telecom.Connection>);
method public final void setConferenceables(java.util.List<android.telecom.Conferenceable>);
method public final void setConnectionCapabilities(int);
@@ -47065,6 +47073,350 @@ package android.telephony {
field @NonNull public static final android.os.Parcelable.Creator<android.telephony.ClosedSubscriberGroupInfo> CREATOR;
}
+ public final class DataFailCause {
+ field public static final int ACCESS_ATTEMPT_ALREADY_IN_PROGRESS = 2219; // 0x8ab
+ field public static final int ACCESS_BLOCK = 2087; // 0x827
+ field public static final int ACCESS_BLOCK_ALL = 2088; // 0x828
+ field public static final int ACCESS_CLASS_DSAC_REJECTION = 2108; // 0x83c
+ field public static final int ACCESS_CONTROL_LIST_CHECK_FAILURE = 2128; // 0x850
+ field public static final int ACTIVATION_REJECTED_BCM_VIOLATION = 48; // 0x30
+ field public static final int ACTIVATION_REJECT_GGSN = 30; // 0x1e
+ field public static final int ACTIVATION_REJECT_UNSPECIFIED = 31; // 0x1f
+ field public static final int ACTIVE_PDP_CONTEXT_MAX_NUMBER_REACHED = 65; // 0x41
+ field public static final int APN_DISABLED = 2045; // 0x7fd
+ field public static final int APN_DISALLOWED_ON_ROAMING = 2059; // 0x80b
+ field public static final int APN_MISMATCH = 2054; // 0x806
+ field public static final int APN_PARAMETERS_CHANGED = 2060; // 0x80c
+ field public static final int APN_PENDING_HANDOVER = 2041; // 0x7f9
+ field public static final int APN_TYPE_CONFLICT = 112; // 0x70
+ field public static final int AUTH_FAILURE_ON_EMERGENCY_CALL = 122; // 0x7a
+ field public static final int BEARER_HANDLING_NOT_SUPPORTED = 60; // 0x3c
+ field public static final int CALL_DISALLOWED_IN_ROAMING = 2068; // 0x814
+ field public static final int CALL_PREEMPT_BY_EMERGENCY_APN = 127; // 0x7f
+ field public static final int CANNOT_ENCODE_OTA_MESSAGE = 2159; // 0x86f
+ field public static final int CDMA_ALERT_STOP = 2077; // 0x81d
+ field public static final int CDMA_INCOMING_CALL = 2076; // 0x81c
+ field public static final int CDMA_INTERCEPT = 2073; // 0x819
+ field public static final int CDMA_LOCK = 2072; // 0x818
+ field public static final int CDMA_RELEASE_DUE_TO_SO_REJECTION = 2075; // 0x81b
+ field public static final int CDMA_REORDER = 2074; // 0x81a
+ field public static final int CDMA_RETRY_ORDER = 2086; // 0x826
+ field public static final int CHANNEL_ACQUISITION_FAILURE = 2078; // 0x81e
+ field public static final int CLOSE_IN_PROGRESS = 2030; // 0x7ee
+ field public static final int COLLISION_WITH_NETWORK_INITIATED_REQUEST = 56; // 0x38
+ field public static final int COMPANION_IFACE_IN_USE = 118; // 0x76
+ field public static final int CONCURRENT_SERVICES_INCOMPATIBLE = 2083; // 0x823
+ field public static final int CONCURRENT_SERVICES_NOT_ALLOWED = 2091; // 0x82b
+ field public static final int CONCURRENT_SERVICE_NOT_SUPPORTED_BY_BASE_STATION = 2080; // 0x820
+ field public static final int CONDITIONAL_IE_ERROR = 100; // 0x64
+ field public static final int CONGESTION = 2106; // 0x83a
+ field public static final int CONNECTION_RELEASED = 2113; // 0x841
+ field public static final int CS_DOMAIN_NOT_AVAILABLE = 2181; // 0x885
+ field public static final int CS_FALLBACK_CALL_ESTABLISHMENT_NOT_ALLOWED = 2188; // 0x88c
+ field public static final int DATA_PLAN_EXPIRED = 2198; // 0x896
+ field public static final int DATA_ROAMING_SETTINGS_DISABLED = 2064; // 0x810
+ field public static final int DATA_SETTINGS_DISABLED = 2063; // 0x80f
+ field public static final int DBM_OR_SMS_IN_PROGRESS = 2211; // 0x8a3
+ field public static final int DDS_SWITCHED = 2065; // 0x811
+ field public static final int DDS_SWITCH_IN_PROGRESS = 2067; // 0x813
+ field public static final int DRB_RELEASED_BY_RRC = 2112; // 0x840
+ field public static final int DS_EXPLICIT_DEACTIVATION = 2125; // 0x84d
+ field public static final int DUAL_SWITCH = 2227; // 0x8b3
+ field public static final int DUN_CALL_DISALLOWED = 2056; // 0x808
+ field public static final int DUPLICATE_BEARER_ID = 2118; // 0x846
+ field public static final int EHRPD_TO_HRPD_FALLBACK = 2049; // 0x801
+ field public static final int EMBMS_NOT_ENABLED = 2193; // 0x891
+ field public static final int EMBMS_REGULAR_DEACTIVATION = 2195; // 0x893
+ field public static final int EMERGENCY_IFACE_ONLY = 116; // 0x74
+ field public static final int EMERGENCY_MODE = 2221; // 0x8ad
+ field public static final int EMM_ACCESS_BARRED = 115; // 0x73
+ field public static final int EMM_ACCESS_BARRED_INFINITE_RETRY = 121; // 0x79
+ field public static final int EMM_ATTACH_FAILED = 2115; // 0x843
+ field public static final int EMM_ATTACH_STARTED = 2116; // 0x844
+ field public static final int EMM_DETACHED = 2114; // 0x842
+ field public static final int EMM_T3417_EXPIRED = 2130; // 0x852
+ field public static final int EMM_T3417_EXT_EXPIRED = 2131; // 0x853
+ field public static final int EPS_SERVICES_AND_NON_EPS_SERVICES_NOT_ALLOWED = 2178; // 0x882
+ field public static final int EPS_SERVICES_NOT_ALLOWED_IN_PLMN = 2179; // 0x883
+ field public static final int ERROR_UNSPECIFIED = 65535; // 0xffff
+ field public static final int ESM_BAD_OTA_MESSAGE = 2122; // 0x84a
+ field public static final int ESM_BEARER_DEACTIVATED_TO_SYNC_WITH_NETWORK = 2120; // 0x848
+ field public static final int ESM_COLLISION_SCENARIOS = 2119; // 0x847
+ field public static final int ESM_CONTEXT_TRANSFERRED_DUE_TO_IRAT = 2124; // 0x84c
+ field public static final int ESM_DOWNLOAD_SERVER_REJECTED_THE_CALL = 2123; // 0x84b
+ field public static final int ESM_FAILURE = 2182; // 0x886
+ field public static final int ESM_INFO_NOT_RECEIVED = 53; // 0x35
+ field public static final int ESM_LOCAL_CAUSE_NONE = 2126; // 0x84e
+ field public static final int ESM_NW_ACTIVATED_DED_BEARER_WITH_ID_OF_DEF_BEARER = 2121; // 0x849
+ field public static final int ESM_PROCEDURE_TIME_OUT = 2155; // 0x86b
+ field public static final int ESM_UNKNOWN_EPS_BEARER_CONTEXT = 2111; // 0x83f
+ field public static final int EVDO_CONNECTION_DENY_BY_BILLING_OR_AUTHENTICATION_FAILURE = 2201; // 0x899
+ field public static final int EVDO_CONNECTION_DENY_BY_GENERAL_OR_NETWORK_BUSY = 2200; // 0x898
+ field public static final int EVDO_HDR_CHANGED = 2202; // 0x89a
+ field public static final int EVDO_HDR_CONNECTION_SETUP_TIMEOUT = 2206; // 0x89e
+ field public static final int EVDO_HDR_EXITED = 2203; // 0x89b
+ field public static final int EVDO_HDR_NO_SESSION = 2204; // 0x89c
+ field public static final int EVDO_USING_GPS_FIX_INSTEAD_OF_HDR_CALL = 2205; // 0x89d
+ field public static final int FADE = 2217; // 0x8a9
+ field public static final int FAILED_TO_ACQUIRE_COLOCATED_HDR = 2207; // 0x89f
+ field public static final int FEATURE_NOT_SUPP = 40; // 0x28
+ field public static final int FILTER_SEMANTIC_ERROR = 44; // 0x2c
+ field public static final int FILTER_SYTAX_ERROR = 45; // 0x2d
+ field public static final int FORBIDDEN_APN_NAME = 2066; // 0x812
+ field public static final int GPRS_REGISTRATION_FAIL = -2; // 0xfffffffe
+ field public static final int GPRS_SERVICES_AND_NON_GPRS_SERVICES_NOT_ALLOWED = 2097; // 0x831
+ field public static final int GPRS_SERVICES_NOT_ALLOWED = 2098; // 0x832
+ field public static final int GPRS_SERVICES_NOT_ALLOWED_IN_THIS_PLMN = 2103; // 0x837
+ field public static final int HANDOFF_PREFERENCE_CHANGED = 2251; // 0x8cb
+ field public static final int HDR_ACCESS_FAILURE = 2213; // 0x8a5
+ field public static final int HDR_FADE = 2212; // 0x8a4
+ field public static final int HDR_NO_LOCK_GRANTED = 2210; // 0x8a2
+ field public static final int IFACE_AND_POL_FAMILY_MISMATCH = 120; // 0x78
+ field public static final int IFACE_MISMATCH = 117; // 0x75
+ field public static final int ILLEGAL_ME = 2096; // 0x830
+ field public static final int ILLEGAL_MS = 2095; // 0x82f
+ field public static final int IMEI_NOT_ACCEPTED = 2177; // 0x881
+ field public static final int IMPLICITLY_DETACHED = 2100; // 0x834
+ field public static final int IMSI_UNKNOWN_IN_HOME_SUBSCRIBER_SERVER = 2176; // 0x880
+ field public static final int INCOMING_CALL_REJECTED = 2092; // 0x82c
+ field public static final int INSUFFICIENT_RESOURCES = 26; // 0x1a
+ field public static final int INTERFACE_IN_USE = 2058; // 0x80a
+ field public static final int INTERNAL_CALL_PREEMPT_BY_HIGH_PRIO_APN = 114; // 0x72
+ field public static final int INTERNAL_EPC_NONEPC_TRANSITION = 2057; // 0x809
+ field public static final int INVALID_CONNECTION_ID = 2156; // 0x86c
+ field public static final int INVALID_DNS_ADDR = 123; // 0x7b
+ field public static final int INVALID_EMM_STATE = 2190; // 0x88e
+ field public static final int INVALID_MANDATORY_INFO = 96; // 0x60
+ field public static final int INVALID_MODE = 2223; // 0x8af
+ field public static final int INVALID_PCSCF_ADDR = 113; // 0x71
+ field public static final int INVALID_PCSCF_OR_DNS_ADDRESS = 124; // 0x7c
+ field public static final int INVALID_PRIMARY_NSAPI = 2158; // 0x86e
+ field public static final int INVALID_SIM_STATE = 2224; // 0x8b0
+ field public static final int INVALID_TRANSACTION_ID = 81; // 0x51
+ field public static final int IPV6_ADDRESS_TRANSFER_FAILED = 2047; // 0x7ff
+ field public static final int IPV6_PREFIX_UNAVAILABLE = 2250; // 0x8ca
+ field public static final int IP_ADDRESS_MISMATCH = 119; // 0x77
+ field public static final int IP_VERSION_MISMATCH = 2055; // 0x807
+ field public static final int IRAT_HANDOVER_FAILED = 2194; // 0x892
+ field public static final int IS707B_MAX_ACCESS_PROBES = 2089; // 0x829
+ field public static final int LIMITED_TO_IPV4 = 2234; // 0x8ba
+ field public static final int LIMITED_TO_IPV6 = 2235; // 0x8bb
+ field public static final int LLC_SNDCP = 25; // 0x19
+ field public static final int LOCAL_END = 2215; // 0x8a7
+ field public static final int LOCATION_AREA_NOT_ALLOWED = 2102; // 0x836
+ field public static final int LOST_CONNECTION = 65540; // 0x10004
+ field public static final int LOWER_LAYER_REGISTRATION_FAILURE = 2197; // 0x895
+ field public static final int LOW_POWER_MODE_OR_POWERING_DOWN = 2044; // 0x7fc
+ field public static final int LTE_NAS_SERVICE_REQUEST_FAILED = 2117; // 0x845
+ field public static final int LTE_THROTTLING_NOT_REQUIRED = 2127; // 0x84f
+ field public static final int MAC_FAILURE = 2183; // 0x887
+ field public static final int MAXIMIUM_NSAPIS_EXCEEDED = 2157; // 0x86d
+ field public static final int MAXINUM_SIZE_OF_L2_MESSAGE_EXCEEDED = 2166; // 0x876
+ field public static final int MAX_ACCESS_PROBE = 2079; // 0x81f
+ field public static final int MAX_IPV4_CONNECTIONS = 2052; // 0x804
+ field public static final int MAX_IPV6_CONNECTIONS = 2053; // 0x805
+ field public static final int MAX_PPP_INACTIVITY_TIMER_EXPIRED = 2046; // 0x7fe
+ field public static final int MESSAGE_INCORRECT_SEMANTIC = 95; // 0x5f
+ field public static final int MESSAGE_TYPE_UNSUPPORTED = 97; // 0x61
+ field public static final int MIP_CONFIG_FAILURE = 2050; // 0x802
+ field public static final int MIP_FA_ADMIN_PROHIBITED = 2001; // 0x7d1
+ field public static final int MIP_FA_DELIVERY_STYLE_NOT_SUPPORTED = 2012; // 0x7dc
+ field public static final int MIP_FA_ENCAPSULATION_UNAVAILABLE = 2008; // 0x7d8
+ field public static final int MIP_FA_HOME_AGENT_AUTHENTICATION_FAILURE = 2004; // 0x7d4
+ field public static final int MIP_FA_INSUFFICIENT_RESOURCES = 2002; // 0x7d2
+ field public static final int MIP_FA_MALFORMED_REPLY = 2007; // 0x7d7
+ field public static final int MIP_FA_MALFORMED_REQUEST = 2006; // 0x7d6
+ field public static final int MIP_FA_MISSING_CHALLENGE = 2017; // 0x7e1
+ field public static final int MIP_FA_MISSING_HOME_ADDRESS = 2015; // 0x7df
+ field public static final int MIP_FA_MISSING_HOME_AGENT = 2014; // 0x7de
+ field public static final int MIP_FA_MISSING_NAI = 2013; // 0x7dd
+ field public static final int MIP_FA_MOBILE_NODE_AUTHENTICATION_FAILURE = 2003; // 0x7d3
+ field public static final int MIP_FA_REASON_UNSPECIFIED = 2000; // 0x7d0
+ field public static final int MIP_FA_REQUESTED_LIFETIME_TOO_LONG = 2005; // 0x7d5
+ field public static final int MIP_FA_REVERSE_TUNNEL_IS_MANDATORY = 2011; // 0x7db
+ field public static final int MIP_FA_REVERSE_TUNNEL_UNAVAILABLE = 2010; // 0x7da
+ field public static final int MIP_FA_STALE_CHALLENGE = 2018; // 0x7e2
+ field public static final int MIP_FA_UNKNOWN_CHALLENGE = 2016; // 0x7e0
+ field public static final int MIP_FA_VJ_HEADER_COMPRESSION_UNAVAILABLE = 2009; // 0x7d9
+ field public static final int MIP_HA_ADMIN_PROHIBITED = 2020; // 0x7e4
+ field public static final int MIP_HA_ENCAPSULATION_UNAVAILABLE = 2029; // 0x7ed
+ field public static final int MIP_HA_FOREIGN_AGENT_AUTHENTICATION_FAILURE = 2023; // 0x7e7
+ field public static final int MIP_HA_INSUFFICIENT_RESOURCES = 2021; // 0x7e5
+ field public static final int MIP_HA_MALFORMED_REQUEST = 2025; // 0x7e9
+ field public static final int MIP_HA_MOBILE_NODE_AUTHENTICATION_FAILURE = 2022; // 0x7e6
+ field public static final int MIP_HA_REASON_UNSPECIFIED = 2019; // 0x7e3
+ field public static final int MIP_HA_REGISTRATION_ID_MISMATCH = 2024; // 0x7e8
+ field public static final int MIP_HA_REVERSE_TUNNEL_IS_MANDATORY = 2028; // 0x7ec
+ field public static final int MIP_HA_REVERSE_TUNNEL_UNAVAILABLE = 2027; // 0x7eb
+ field public static final int MIP_HA_UNKNOWN_HOME_AGENT_ADDRESS = 2026; // 0x7ea
+ field public static final int MISSING_UNKNOWN_APN = 27; // 0x1b
+ field public static final int MODEM_APP_PREEMPTED = 2032; // 0x7f0
+ field public static final int MODEM_RESTART = 2037; // 0x7f5
+ field public static final int MSC_TEMPORARILY_NOT_REACHABLE = 2180; // 0x884
+ field public static final int MSG_AND_PROTOCOL_STATE_UNCOMPATIBLE = 101; // 0x65
+ field public static final int MSG_TYPE_NONCOMPATIBLE_STATE = 98; // 0x62
+ field public static final int MS_IDENTITY_CANNOT_BE_DERIVED_BY_THE_NETWORK = 2099; // 0x833
+ field public static final int MULTIPLE_PDP_CALL_NOT_ALLOWED = 2192; // 0x890
+ field public static final int MULTI_CONN_TO_SAME_PDN_NOT_ALLOWED = 55; // 0x37
+ field public static final int NAS_LAYER_FAILURE = 2191; // 0x88f
+ field public static final int NAS_REQUEST_REJECTED_BY_NETWORK = 2167; // 0x877
+ field public static final int NAS_SIGNALLING = 14; // 0xe
+ field public static final int NETWORK_FAILURE = 38; // 0x26
+ field public static final int NETWORK_INITIATED_DETACH_NO_AUTO_REATTACH = 2154; // 0x86a
+ field public static final int NETWORK_INITIATED_DETACH_WITH_AUTO_REATTACH = 2153; // 0x869
+ field public static final int NETWORK_INITIATED_TERMINATION = 2031; // 0x7ef
+ field public static final int NONE = 0; // 0x0
+ field public static final int NON_IP_NOT_SUPPORTED = 2069; // 0x815
+ field public static final int NORMAL_RELEASE = 2218; // 0x8aa
+ field public static final int NO_CDMA_SERVICE = 2084; // 0x824
+ field public static final int NO_COLLOCATED_HDR = 2225; // 0x8b1
+ field public static final int NO_EPS_BEARER_CONTEXT_ACTIVATED = 2189; // 0x88d
+ field public static final int NO_GPRS_CONTEXT = 2094; // 0x82e
+ field public static final int NO_HYBRID_HDR_SERVICE = 2209; // 0x8a1
+ field public static final int NO_PDP_CONTEXT_ACTIVATED = 2107; // 0x83b
+ field public static final int NO_RESPONSE_FROM_BASE_STATION = 2081; // 0x821
+ field public static final int NO_SERVICE = 2216; // 0x8a8
+ field public static final int NO_SERVICE_ON_GATEWAY = 2093; // 0x82d
+ field public static final int NSAPI_IN_USE = 35; // 0x23
+ field public static final int NULL_APN_DISALLOWED = 2061; // 0x80d
+ field public static final int OEM_DCFAILCAUSE_1 = 4097; // 0x1001
+ field public static final int OEM_DCFAILCAUSE_10 = 4106; // 0x100a
+ field public static final int OEM_DCFAILCAUSE_11 = 4107; // 0x100b
+ field public static final int OEM_DCFAILCAUSE_12 = 4108; // 0x100c
+ field public static final int OEM_DCFAILCAUSE_13 = 4109; // 0x100d
+ field public static final int OEM_DCFAILCAUSE_14 = 4110; // 0x100e
+ field public static final int OEM_DCFAILCAUSE_15 = 4111; // 0x100f
+ field public static final int OEM_DCFAILCAUSE_2 = 4098; // 0x1002
+ field public static final int OEM_DCFAILCAUSE_3 = 4099; // 0x1003
+ field public static final int OEM_DCFAILCAUSE_4 = 4100; // 0x1004
+ field public static final int OEM_DCFAILCAUSE_5 = 4101; // 0x1005
+ field public static final int OEM_DCFAILCAUSE_6 = 4102; // 0x1006
+ field public static final int OEM_DCFAILCAUSE_7 = 4103; // 0x1007
+ field public static final int OEM_DCFAILCAUSE_8 = 4104; // 0x1008
+ field public static final int OEM_DCFAILCAUSE_9 = 4105; // 0x1009
+ field public static final int ONLY_IPV4V6_ALLOWED = 57; // 0x39
+ field public static final int ONLY_IPV4_ALLOWED = 50; // 0x32
+ field public static final int ONLY_IPV6_ALLOWED = 51; // 0x33
+ field public static final int ONLY_NON_IP_ALLOWED = 58; // 0x3a
+ field public static final int ONLY_SINGLE_BEARER_ALLOWED = 52; // 0x34
+ field public static final int OPERATOR_BARRED = 8; // 0x8
+ field public static final int OTASP_COMMIT_IN_PROGRESS = 2208; // 0x8a0
+ field public static final int PDN_CONN_DOES_NOT_EXIST = 54; // 0x36
+ field public static final int PDN_INACTIVITY_TIMER_EXPIRED = 2051; // 0x803
+ field public static final int PDN_IPV4_CALL_DISALLOWED = 2033; // 0x7f1
+ field public static final int PDN_IPV4_CALL_THROTTLED = 2034; // 0x7f2
+ field public static final int PDN_IPV6_CALL_DISALLOWED = 2035; // 0x7f3
+ field public static final int PDN_IPV6_CALL_THROTTLED = 2036; // 0x7f4
+ field public static final int PDN_NON_IP_CALL_DISALLOWED = 2071; // 0x817
+ field public static final int PDN_NON_IP_CALL_THROTTLED = 2070; // 0x816
+ field public static final int PDP_ACTIVATE_MAX_RETRY_FAILED = 2109; // 0x83d
+ field public static final int PDP_DUPLICATE = 2104; // 0x838
+ field public static final int PDP_ESTABLISH_TIMEOUT_EXPIRED = 2161; // 0x871
+ field public static final int PDP_INACTIVE_TIMEOUT_EXPIRED = 2163; // 0x873
+ field public static final int PDP_LOWERLAYER_ERROR = 2164; // 0x874
+ field public static final int PDP_MODIFY_COLLISION = 2165; // 0x875
+ field public static final int PDP_MODIFY_TIMEOUT_EXPIRED = 2162; // 0x872
+ field public static final int PDP_PPP_NOT_SUPPORTED = 2038; // 0x7f6
+ field public static final int PDP_WITHOUT_ACTIVE_TFT = 46; // 0x2e
+ field public static final int PHONE_IN_USE = 2222; // 0x8ae
+ field public static final int PHYSICAL_LINK_CLOSE_IN_PROGRESS = 2040; // 0x7f8
+ field public static final int PLMN_NOT_ALLOWED = 2101; // 0x835
+ field public static final int PPP_AUTH_FAILURE = 2229; // 0x8b5
+ field public static final int PPP_CHAP_FAILURE = 2232; // 0x8b8
+ field public static final int PPP_CLOSE_IN_PROGRESS = 2233; // 0x8b9
+ field public static final int PPP_OPTION_MISMATCH = 2230; // 0x8b6
+ field public static final int PPP_PAP_FAILURE = 2231; // 0x8b7
+ field public static final int PPP_TIMEOUT = 2228; // 0x8b4
+ field public static final int PREF_RADIO_TECH_CHANGED = -4; // 0xfffffffc
+ field public static final int PROFILE_BEARER_INCOMPATIBLE = 2042; // 0x7fa
+ field public static final int PROTOCOL_ERRORS = 111; // 0x6f
+ field public static final int QOS_NOT_ACCEPTED = 37; // 0x25
+ field public static final int RADIO_ACCESS_BEARER_FAILURE = 2110; // 0x83e
+ field public static final int RADIO_ACCESS_BEARER_SETUP_FAILURE = 2160; // 0x870
+ field public static final int RADIO_NOT_AVAILABLE = 65537; // 0x10001
+ field public static final int RADIO_POWER_OFF = -5; // 0xfffffffb
+ field public static final int REDIRECTION_OR_HANDOFF_IN_PROGRESS = 2220; // 0x8ac
+ field public static final int REGISTRATION_FAIL = -1; // 0xffffffff
+ field public static final int REGULAR_DEACTIVATION = 36; // 0x24
+ field public static final int REJECTED_BY_BASE_STATION = 2082; // 0x822
+ field public static final int RRC_CONNECTION_ABORTED_AFTER_HANDOVER = 2173; // 0x87d
+ field public static final int RRC_CONNECTION_ABORTED_AFTER_IRAT_CELL_CHANGE = 2174; // 0x87e
+ field public static final int RRC_CONNECTION_ABORTED_DUE_TO_IRAT_CHANGE = 2171; // 0x87b
+ field public static final int RRC_CONNECTION_ABORTED_DURING_IRAT_CELL_CHANGE = 2175; // 0x87f
+ field public static final int RRC_CONNECTION_ABORT_REQUEST = 2151; // 0x867
+ field public static final int RRC_CONNECTION_ACCESS_BARRED = 2139; // 0x85b
+ field public static final int RRC_CONNECTION_ACCESS_STRATUM_FAILURE = 2137; // 0x859
+ field public static final int RRC_CONNECTION_ANOTHER_PROCEDURE_IN_PROGRESS = 2138; // 0x85a
+ field public static final int RRC_CONNECTION_CELL_NOT_CAMPED = 2144; // 0x860
+ field public static final int RRC_CONNECTION_CELL_RESELECTION = 2140; // 0x85c
+ field public static final int RRC_CONNECTION_CONFIG_FAILURE = 2141; // 0x85d
+ field public static final int RRC_CONNECTION_INVALID_REQUEST = 2168; // 0x878
+ field public static final int RRC_CONNECTION_LINK_FAILURE = 2143; // 0x85f
+ field public static final int RRC_CONNECTION_NORMAL_RELEASE = 2147; // 0x863
+ field public static final int RRC_CONNECTION_OUT_OF_SERVICE_DURING_CELL_REGISTER = 2150; // 0x866
+ field public static final int RRC_CONNECTION_RADIO_LINK_FAILURE = 2148; // 0x864
+ field public static final int RRC_CONNECTION_REESTABLISHMENT_FAILURE = 2149; // 0x865
+ field public static final int RRC_CONNECTION_REJECT_BY_NETWORK = 2146; // 0x862
+ field public static final int RRC_CONNECTION_RELEASED_SECURITY_NOT_ACTIVE = 2172; // 0x87c
+ field public static final int RRC_CONNECTION_RF_UNAVAILABLE = 2170; // 0x87a
+ field public static final int RRC_CONNECTION_SYSTEM_INFORMATION_BLOCK_READ_ERROR = 2152; // 0x868
+ field public static final int RRC_CONNECTION_SYSTEM_INTERVAL_FAILURE = 2145; // 0x861
+ field public static final int RRC_CONNECTION_TIMER_EXPIRED = 2142; // 0x85e
+ field public static final int RRC_CONNECTION_TRACKING_AREA_ID_CHANGED = 2169; // 0x879
+ field public static final int RRC_UPLINK_CONNECTION_RELEASE = 2134; // 0x856
+ field public static final int RRC_UPLINK_DATA_TRANSMISSION_FAILURE = 2132; // 0x854
+ field public static final int RRC_UPLINK_DELIVERY_FAILED_DUE_TO_HANDOVER = 2133; // 0x855
+ field public static final int RRC_UPLINK_ERROR_REQUEST_FROM_NAS = 2136; // 0x858
+ field public static final int RRC_UPLINK_RADIO_LINK_FAILURE = 2135; // 0x857
+ field public static final int RUIM_NOT_PRESENT = 2085; // 0x825
+ field public static final int SECURITY_MODE_REJECTED = 2186; // 0x88a
+ field public static final int SERVICE_NOT_ALLOWED_ON_PLMN = 2129; // 0x851
+ field public static final int SERVICE_OPTION_NOT_SUBSCRIBED = 33; // 0x21
+ field public static final int SERVICE_OPTION_NOT_SUPPORTED = 32; // 0x20
+ field public static final int SERVICE_OPTION_OUT_OF_ORDER = 34; // 0x22
+ field public static final int SIGNAL_LOST = -3; // 0xfffffffd
+ field public static final int SIM_CARD_CHANGED = 2043; // 0x7fb
+ field public static final int SYNCHRONIZATION_FAILURE = 2184; // 0x888
+ field public static final int TEST_LOOPBACK_REGULAR_DEACTIVATION = 2196; // 0x894
+ field public static final int TETHERED_CALL_ACTIVE = -6; // 0xfffffffa
+ field public static final int TFT_SEMANTIC_ERROR = 41; // 0x29
+ field public static final int TFT_SYTAX_ERROR = 42; // 0x2a
+ field public static final int THERMAL_EMERGENCY = 2090; // 0x82a
+ field public static final int THERMAL_MITIGATION = 2062; // 0x80e
+ field public static final int TRAT_SWAP_FAILED = 2048; // 0x800
+ field public static final int UE_INITIATED_DETACH_OR_DISCONNECT = 128; // 0x80
+ field public static final int UE_IS_ENTERING_POWERSAVE_MODE = 2226; // 0x8b2
+ field public static final int UE_RAT_CHANGE = 2105; // 0x839
+ field public static final int UE_SECURITY_CAPABILITIES_MISMATCH = 2185; // 0x889
+ field public static final int UMTS_HANDOVER_TO_IWLAN = 2199; // 0x897
+ field public static final int UMTS_REACTIVATION_REQ = 39; // 0x27
+ field public static final int UNACCEPTABLE_NETWORK_PARAMETER = 65538; // 0x10002
+ field public static final int UNACCEPTABLE_NON_EPS_AUTHENTICATION = 2187; // 0x88b
+ field public static final int UNKNOWN = 65536; // 0x10000
+ field public static final int UNKNOWN_INFO_ELEMENT = 99; // 0x63
+ field public static final int UNKNOWN_PDP_ADDRESS_TYPE = 28; // 0x1c
+ field public static final int UNKNOWN_PDP_CONTEXT = 43; // 0x2b
+ field public static final int UNPREFERRED_RAT = 2039; // 0x7f7
+ field public static final int UNSUPPORTED_1X_PREV = 2214; // 0x8a6
+ field public static final int UNSUPPORTED_APN_IN_CURRENT_PLMN = 66; // 0x42
+ field public static final int UNSUPPORTED_QCI_VALUE = 59; // 0x3b
+ field public static final int USER_AUTHENTICATION = 29; // 0x1d
+ field public static final int VSNCP_ADMINISTRATIVELY_PROHIBITED = 2245; // 0x8c5
+ field public static final int VSNCP_APN_UNAUTHORIZED = 2238; // 0x8be
+ field public static final int VSNCP_GEN_ERROR = 2237; // 0x8bd
+ field public static final int VSNCP_INSUFFICIENT_PARAMETERS = 2243; // 0x8c3
+ field public static final int VSNCP_NO_PDN_GATEWAY_ADDRESS = 2240; // 0x8c0
+ field public static final int VSNCP_PDN_EXISTS_FOR_THIS_APN = 2248; // 0x8c8
+ field public static final int VSNCP_PDN_GATEWAY_REJECT = 2242; // 0x8c2
+ field public static final int VSNCP_PDN_GATEWAY_UNREACHABLE = 2241; // 0x8c1
+ field public static final int VSNCP_PDN_ID_IN_USE = 2246; // 0x8c6
+ field public static final int VSNCP_PDN_LIMIT_EXCEEDED = 2239; // 0x8bf
+ field public static final int VSNCP_RECONNECT_NOT_ALLOWED = 2249; // 0x8c9
+ field public static final int VSNCP_RESOURCE_UNAVAILABLE = 2244; // 0x8c4
+ field public static final int VSNCP_SUBSCRIBER_LIMITATION = 2247; // 0x8c7
+ field public static final int VSNCP_TIMEOUT = 2236; // 0x8bc
+ }
+
public final class DisplayInfo implements android.os.Parcelable {
method public int describeContents();
method public int getNetworkType();
diff --git a/api/module-lib-current.txt b/api/module-lib-current.txt
index 7b66f735b5ad..6863221f7fda 100644
--- a/api/module-lib-current.txt
+++ b/api/module-lib-current.txt
@@ -30,7 +30,6 @@ package android.net {
}
public class TetheringConstants {
- ctor public TetheringConstants();
field public static final String EXTRA_ADD_TETHER_TYPE = "extraAddTetherType";
field public static final String EXTRA_PROVISION_CALLBACK = "extraProvisionCallback";
field public static final String EXTRA_REM_TETHER_TYPE = "extraRemTetherType";
diff --git a/api/module-lib-lint-baseline.txt b/api/module-lib-lint-baseline.txt
index 6e59596cb05f..56f7a02260a7 100644
--- a/api/module-lib-lint-baseline.txt
+++ b/api/module-lib-lint-baseline.txt
@@ -27,7 +27,3 @@ PrivateSuperclass: android.location.GnssAntennaInfo.PhaseCenterVariationCorrecti
Public class android.location.GnssAntennaInfo.PhaseCenterVariationCorrections extends private class android.location.GnssAntennaInfo.SphericalCorrections
PrivateSuperclass: android.location.GnssAntennaInfo.SignalGainCorrections:
Public class android.location.GnssAntennaInfo.SignalGainCorrections extends private class android.location.GnssAntennaInfo.SphericalCorrections
-
-
-StaticUtils: android.net.TetheringConstants:
- Fully-static utility classes must not have constructor
diff --git a/api/system-current.txt b/api/system-current.txt
index 3ef785700eee..9663c0c53a39 100755
--- a/api/system-current.txt
+++ b/api/system-current.txt
@@ -6747,337 +6747,6 @@ package android.net.apf {
}
-package android.net.eap {
-
- public final class EapSessionConfig {
- }
-
- public static final class EapSessionConfig.Builder {
- ctor public EapSessionConfig.Builder();
- method @NonNull public android.net.eap.EapSessionConfig build();
- method @NonNull public android.net.eap.EapSessionConfig.Builder setEapAkaConfig(int, int);
- method @NonNull public android.net.eap.EapSessionConfig.Builder setEapAkaPrimeConfig(int, int, @NonNull String, boolean);
- method @NonNull public android.net.eap.EapSessionConfig.Builder setEapIdentity(@NonNull byte[]);
- method @NonNull public android.net.eap.EapSessionConfig.Builder setEapMsChapV2Config(@NonNull String, @NonNull String);
- method @NonNull public android.net.eap.EapSessionConfig.Builder setEapSimConfig(int, int);
- }
-
- public static class EapSessionConfig.EapAkaConfig extends android.net.eap.EapSessionConfig.EapUiccConfig {
- }
-
- public static class EapSessionConfig.EapAkaPrimeConfig extends android.net.eap.EapSessionConfig.EapAkaConfig {
- method public boolean allowsMismatchedNetworkNames();
- method @NonNull public String getNetworkName();
- }
-
- public abstract static class EapSessionConfig.EapMethodConfig {
- method public int getMethodType();
- }
-
- public static class EapSessionConfig.EapMsChapV2Config extends android.net.eap.EapSessionConfig.EapMethodConfig {
- method @NonNull public String getPassword();
- method @NonNull public String getUsername();
- }
-
- public static class EapSessionConfig.EapSimConfig extends android.net.eap.EapSessionConfig.EapUiccConfig {
- }
-
- public abstract static class EapSessionConfig.EapUiccConfig extends android.net.eap.EapSessionConfig.EapMethodConfig {
- method public int getAppType();
- method public int getSubId();
- }
-
-}
-
-package android.net.ipsec.ike {
-
- public final class ChildSaProposal extends android.net.ipsec.ike.SaProposal {
- }
-
- public static final class ChildSaProposal.Builder {
- ctor public ChildSaProposal.Builder();
- method @NonNull public android.net.ipsec.ike.ChildSaProposal.Builder addDhGroup(int);
- method @NonNull public android.net.ipsec.ike.ChildSaProposal.Builder addEncryptionAlgorithm(int, int);
- method @NonNull public android.net.ipsec.ike.ChildSaProposal.Builder addIntegrityAlgorithm(int);
- method @NonNull public android.net.ipsec.ike.ChildSaProposal build();
- }
-
- public interface ChildSessionCallback {
- method public void onClosed();
- method public void onClosedExceptionally(@NonNull android.net.ipsec.ike.exceptions.IkeException);
- method public void onIpSecTransformCreated(@NonNull android.net.IpSecTransform, int);
- method public void onIpSecTransformDeleted(@NonNull android.net.IpSecTransform, int);
- method public void onOpened(@NonNull android.net.ipsec.ike.ChildSessionConfiguration);
- }
-
- public final class ChildSessionConfiguration {
- method @NonNull public java.util.List<android.net.ipsec.ike.IkeTrafficSelector> getInboundTrafficSelectors();
- method @NonNull public java.util.List<android.net.LinkAddress> getInternalAddresses();
- method @NonNull public java.util.List<java.net.InetAddress> getInternalDhcpServers();
- method @NonNull public java.util.List<java.net.InetAddress> getInternalDnsServers();
- method @NonNull public java.util.List<android.net.IpPrefix> getInternalSubnets();
- method @NonNull public java.util.List<android.net.ipsec.ike.IkeTrafficSelector> getOutboundTrafficSelectors();
- }
-
- public abstract class ChildSessionParams {
- method public long getHardLifetime();
- method @NonNull public java.util.List<android.net.ipsec.ike.IkeTrafficSelector> getLocalTrafficSelectors();
- method @NonNull public java.util.List<android.net.ipsec.ike.IkeTrafficSelector> getRemoteTrafficSelectors();
- method @NonNull public java.util.List<android.net.ipsec.ike.ChildSaProposal> getSaProposals();
- method public long getSoftLifetime();
- }
-
- public class IkeFqdnIdentification extends android.net.ipsec.ike.IkeIdentification {
- ctor public IkeFqdnIdentification(@NonNull String);
- field @NonNull public final String fqdn;
- }
-
- public abstract class IkeIdentification {
- }
-
- public final class IkeIpv4AddrIdentification extends android.net.ipsec.ike.IkeIdentification {
- ctor public IkeIpv4AddrIdentification(@NonNull java.net.Inet4Address);
- field @NonNull public final java.net.Inet4Address ipv4Address;
- }
-
- public class IkeIpv6AddrIdentification extends android.net.ipsec.ike.IkeIdentification {
- ctor public IkeIpv6AddrIdentification(@NonNull java.net.Inet6Address);
- field @NonNull public final java.net.Inet6Address ipv6Address;
- }
-
- public final class IkeKeyIdIdentification extends android.net.ipsec.ike.IkeIdentification {
- ctor public IkeKeyIdIdentification(@NonNull byte[]);
- field @NonNull public final byte[] keyId;
- }
-
- public final class IkeRfc822AddrIdentification extends android.net.ipsec.ike.IkeIdentification {
- ctor public IkeRfc822AddrIdentification(@NonNull String);
- field @NonNull public final String rfc822Name;
- }
-
- public final class IkeSaProposal extends android.net.ipsec.ike.SaProposal {
- method @NonNull public java.util.List<java.lang.Integer> getPseudorandomFunctions();
- }
-
- public static final class IkeSaProposal.Builder {
- ctor public IkeSaProposal.Builder();
- method @NonNull public android.net.ipsec.ike.IkeSaProposal.Builder addDhGroup(int);
- method @NonNull public android.net.ipsec.ike.IkeSaProposal.Builder addEncryptionAlgorithm(int, int);
- method @NonNull public android.net.ipsec.ike.IkeSaProposal.Builder addIntegrityAlgorithm(int);
- method @NonNull public android.net.ipsec.ike.IkeSaProposal.Builder addPseudorandomFunction(int);
- method @NonNull public android.net.ipsec.ike.IkeSaProposal build();
- }
-
- public final class IkeSession implements java.lang.AutoCloseable {
- ctor public IkeSession(@NonNull android.content.Context, @NonNull android.net.ipsec.ike.IkeSessionParams, @NonNull android.net.ipsec.ike.ChildSessionParams, @NonNull java.util.concurrent.Executor, @NonNull android.net.ipsec.ike.IkeSessionCallback, @NonNull android.net.ipsec.ike.ChildSessionCallback);
- method public void close();
- method public void closeChildSession(@NonNull android.net.ipsec.ike.ChildSessionCallback);
- method public void kill();
- method public void openChildSession(@NonNull android.net.ipsec.ike.ChildSessionParams, @NonNull android.net.ipsec.ike.ChildSessionCallback);
- }
-
- public interface IkeSessionCallback {
- method public void onClosed();
- method public void onClosedExceptionally(@NonNull android.net.ipsec.ike.exceptions.IkeException);
- method public void onError(@NonNull android.net.ipsec.ike.exceptions.IkeProtocolException);
- method public void onOpened(@NonNull android.net.ipsec.ike.IkeSessionConfiguration);
- }
-
- public final class IkeSessionConfiguration {
- method @NonNull public java.util.List<java.net.InetAddress> getPcscfServers();
- method @NonNull public String getRemoteApplicationVersion();
- method @NonNull public java.util.List<byte[]> getRemoteVendorIDs();
- method public boolean isIkeExtensionEnabled(int);
- field public static final int EXTENSION_TYPE_FRAGMENTATION = 1; // 0x1
- field public static final int EXTENSION_TYPE_MOBIKE = 2; // 0x2
- }
-
- public final class IkeSessionParams {
- method @NonNull public java.util.List<android.net.ipsec.ike.IkeSessionParams.IkeConfigRequest> getConfigurationRequests();
- method public long getHardLifetime();
- method @NonNull public android.net.ipsec.ike.IkeSessionParams.IkeAuthConfig getLocalAuthConfig();
- method @NonNull public android.net.ipsec.ike.IkeIdentification getLocalIdentification();
- method @NonNull public android.net.ipsec.ike.IkeSessionParams.IkeAuthConfig getRemoteAuthConfig();
- method @NonNull public android.net.ipsec.ike.IkeIdentification getRemoteIdentification();
- method @NonNull public java.util.List<android.net.ipsec.ike.IkeSaProposal> getSaProposals();
- method @NonNull public java.net.InetAddress getServerAddress();
- method public long getSoftLifetime();
- method @NonNull public android.net.IpSecManager.UdpEncapsulationSocket getUdpEncapsulationSocket();
- }
-
- public static final class IkeSessionParams.Builder {
- ctor public IkeSessionParams.Builder();
- method @NonNull public android.net.ipsec.ike.IkeSessionParams.Builder addPcscfServerRequest(@NonNull java.net.InetAddress);
- method @NonNull public android.net.ipsec.ike.IkeSessionParams.Builder addPcscfServerRequest(int);
- method @NonNull public android.net.ipsec.ike.IkeSessionParams.Builder addSaProposal(@NonNull android.net.ipsec.ike.IkeSaProposal);
- method @NonNull public android.net.ipsec.ike.IkeSessionParams build();
- method @NonNull public android.net.ipsec.ike.IkeSessionParams.Builder setAuthDigitalSignature(@Nullable java.security.cert.X509Certificate, @NonNull java.security.cert.X509Certificate, @NonNull java.security.PrivateKey);
- method @NonNull public android.net.ipsec.ike.IkeSessionParams.Builder setAuthDigitalSignature(@Nullable java.security.cert.X509Certificate, @NonNull java.security.cert.X509Certificate, @NonNull java.util.List<java.security.cert.X509Certificate>, @NonNull java.security.PrivateKey);
- method @NonNull public android.net.ipsec.ike.IkeSessionParams.Builder setAuthEap(@Nullable java.security.cert.X509Certificate, @NonNull android.net.eap.EapSessionConfig);
- method @NonNull public android.net.ipsec.ike.IkeSessionParams.Builder setAuthPsk(@NonNull byte[]);
- method @NonNull public android.net.ipsec.ike.IkeSessionParams.Builder setLifetime(long, long);
- method @NonNull public android.net.ipsec.ike.IkeSessionParams.Builder setLocalIdentification(@NonNull android.net.ipsec.ike.IkeIdentification);
- method @NonNull public android.net.ipsec.ike.IkeSessionParams.Builder setRemoteIdentification(@NonNull android.net.ipsec.ike.IkeIdentification);
- method @NonNull public android.net.ipsec.ike.IkeSessionParams.Builder setServerAddress(@NonNull java.net.InetAddress);
- method @NonNull public android.net.ipsec.ike.IkeSessionParams.Builder setUdpEncapsulationSocket(@NonNull android.net.IpSecManager.UdpEncapsulationSocket);
- }
-
- public static interface IkeSessionParams.ConfigRequestIpv4PcscfServer extends android.net.ipsec.ike.IkeSessionParams.IkeConfigRequest {
- method @Nullable public java.net.Inet4Address getAddress();
- }
-
- public static interface IkeSessionParams.ConfigRequestIpv6PcscfServer extends android.net.ipsec.ike.IkeSessionParams.IkeConfigRequest {
- method @Nullable public java.net.Inet6Address getAddress();
- }
-
- public abstract static class IkeSessionParams.IkeAuthConfig {
- }
-
- public static class IkeSessionParams.IkeAuthDigitalSignLocalConfig extends android.net.ipsec.ike.IkeSessionParams.IkeAuthConfig {
- method @NonNull public java.security.cert.X509Certificate getClientEndCertificate();
- method @NonNull public java.util.List<java.security.cert.X509Certificate> getIntermediateCertificates();
- method @NonNull public java.security.PrivateKey getPrivateKey();
- }
-
- public static class IkeSessionParams.IkeAuthDigitalSignRemoteConfig extends android.net.ipsec.ike.IkeSessionParams.IkeAuthConfig {
- method @Nullable public java.security.cert.X509Certificate getRemoteCaCert();
- }
-
- public static class IkeSessionParams.IkeAuthEapConfig extends android.net.ipsec.ike.IkeSessionParams.IkeAuthConfig {
- method @NonNull public android.net.eap.EapSessionConfig getEapConfig();
- }
-
- public static class IkeSessionParams.IkeAuthPskConfig extends android.net.ipsec.ike.IkeSessionParams.IkeAuthConfig {
- method @NonNull public byte[] getPsk();
- }
-
- public static interface IkeSessionParams.IkeConfigRequest {
- }
-
- public final class IkeTrafficSelector {
- ctor public IkeTrafficSelector(int, int, @NonNull java.net.InetAddress, @NonNull java.net.InetAddress);
- field public final int endPort;
- field @NonNull public final java.net.InetAddress endingAddress;
- field public final int startPort;
- field @NonNull public final java.net.InetAddress startingAddress;
- }
-
- public abstract class SaProposal {
- method @NonNull public java.util.List<java.lang.Integer> getDhGroups();
- method @NonNull public java.util.List<android.util.Pair<java.lang.Integer,java.lang.Integer>> getEncryptionAlgorithms();
- method @NonNull public java.util.List<java.lang.Integer> getIntegrityAlgorithms();
- field public static final int DH_GROUP_1024_BIT_MODP = 2; // 0x2
- field public static final int DH_GROUP_2048_BIT_MODP = 14; // 0xe
- field public static final int DH_GROUP_NONE = 0; // 0x0
- field public static final int ENCRYPTION_ALGORITHM_3DES = 3; // 0x3
- field public static final int ENCRYPTION_ALGORITHM_AES_CBC = 12; // 0xc
- field public static final int ENCRYPTION_ALGORITHM_AES_GCM_12 = 19; // 0x13
- field public static final int ENCRYPTION_ALGORITHM_AES_GCM_16 = 20; // 0x14
- field public static final int ENCRYPTION_ALGORITHM_AES_GCM_8 = 18; // 0x12
- field public static final int INTEGRITY_ALGORITHM_AES_XCBC_96 = 5; // 0x5
- field public static final int INTEGRITY_ALGORITHM_HMAC_SHA1_96 = 2; // 0x2
- field public static final int INTEGRITY_ALGORITHM_HMAC_SHA2_256_128 = 12; // 0xc
- field public static final int INTEGRITY_ALGORITHM_HMAC_SHA2_384_192 = 13; // 0xd
- field public static final int INTEGRITY_ALGORITHM_HMAC_SHA2_512_256 = 14; // 0xe
- field public static final int INTEGRITY_ALGORITHM_NONE = 0; // 0x0
- field public static final int KEY_LEN_AES_128 = 128; // 0x80
- field public static final int KEY_LEN_AES_192 = 192; // 0xc0
- field public static final int KEY_LEN_AES_256 = 256; // 0x100
- field public static final int KEY_LEN_UNUSED = 0; // 0x0
- field public static final int PSEUDORANDOM_FUNCTION_AES128_XCBC = 4; // 0x4
- field public static final int PSEUDORANDOM_FUNCTION_HMAC_SHA1 = 2; // 0x2
- }
-
- public final class TransportModeChildSessionParams extends android.net.ipsec.ike.ChildSessionParams {
- }
-
- public static final class TransportModeChildSessionParams.Builder {
- ctor public TransportModeChildSessionParams.Builder();
- method @NonNull public android.net.ipsec.ike.TransportModeChildSessionParams.Builder addInboundTrafficSelectors(@NonNull android.net.ipsec.ike.IkeTrafficSelector);
- method @NonNull public android.net.ipsec.ike.TransportModeChildSessionParams.Builder addOutboundTrafficSelectors(@NonNull android.net.ipsec.ike.IkeTrafficSelector);
- method @NonNull public android.net.ipsec.ike.TransportModeChildSessionParams.Builder addSaProposal(@NonNull android.net.ipsec.ike.ChildSaProposal);
- method @NonNull public android.net.ipsec.ike.TransportModeChildSessionParams build();
- method @NonNull public android.net.ipsec.ike.TransportModeChildSessionParams.Builder setLifetime(long, long);
- }
-
- public final class TunnelModeChildSessionParams extends android.net.ipsec.ike.ChildSessionParams {
- method @NonNull public java.util.List<android.net.ipsec.ike.TunnelModeChildSessionParams.TunnelModeChildConfigRequest> getConfigurationRequests();
- }
-
- public static final class TunnelModeChildSessionParams.Builder {
- ctor public TunnelModeChildSessionParams.Builder();
- method @NonNull public android.net.ipsec.ike.TunnelModeChildSessionParams.Builder addInboundTrafficSelectors(@NonNull android.net.ipsec.ike.IkeTrafficSelector);
- method @NonNull public android.net.ipsec.ike.TunnelModeChildSessionParams.Builder addInternalAddressRequest(int);
- method @NonNull public android.net.ipsec.ike.TunnelModeChildSessionParams.Builder addInternalAddressRequest(@NonNull java.net.Inet4Address);
- method @NonNull public android.net.ipsec.ike.TunnelModeChildSessionParams.Builder addInternalAddressRequest(@NonNull java.net.Inet6Address, int);
- method @NonNull public android.net.ipsec.ike.TunnelModeChildSessionParams.Builder addInternalDhcpServerRequest(int);
- method @NonNull public android.net.ipsec.ike.TunnelModeChildSessionParams.Builder addInternalDnsServerRequest(int);
- method @NonNull public android.net.ipsec.ike.TunnelModeChildSessionParams.Builder addOutboundTrafficSelectors(@NonNull android.net.ipsec.ike.IkeTrafficSelector);
- method @NonNull public android.net.ipsec.ike.TunnelModeChildSessionParams.Builder addSaProposal(@NonNull android.net.ipsec.ike.ChildSaProposal);
- method @NonNull public android.net.ipsec.ike.TunnelModeChildSessionParams build();
- method @NonNull public android.net.ipsec.ike.TunnelModeChildSessionParams.Builder setLifetime(long, long);
- }
-
- public static interface TunnelModeChildSessionParams.ConfigRequestIpv4Address extends android.net.ipsec.ike.TunnelModeChildSessionParams.TunnelModeChildConfigRequest {
- method @Nullable public java.net.Inet4Address getAddress();
- }
-
- public static interface TunnelModeChildSessionParams.ConfigRequestIpv4DhcpServer extends android.net.ipsec.ike.TunnelModeChildSessionParams.TunnelModeChildConfigRequest {
- method @Nullable public java.net.Inet4Address getAddress();
- }
-
- public static interface TunnelModeChildSessionParams.ConfigRequestIpv4DnsServer extends android.net.ipsec.ike.TunnelModeChildSessionParams.TunnelModeChildConfigRequest {
- method @Nullable public java.net.Inet4Address getAddress();
- }
-
- public static interface TunnelModeChildSessionParams.ConfigRequestIpv4Netmask extends android.net.ipsec.ike.TunnelModeChildSessionParams.TunnelModeChildConfigRequest {
- }
-
- public static interface TunnelModeChildSessionParams.ConfigRequestIpv6Address extends android.net.ipsec.ike.TunnelModeChildSessionParams.TunnelModeChildConfigRequest {
- method @Nullable public java.net.Inet6Address getAddress();
- method public int getPrefixLength();
- }
-
- public static interface TunnelModeChildSessionParams.ConfigRequestIpv6DnsServer extends android.net.ipsec.ike.TunnelModeChildSessionParams.TunnelModeChildConfigRequest {
- method @Nullable public java.net.Inet6Address getAddress();
- }
-
- public static interface TunnelModeChildSessionParams.TunnelModeChildConfigRequest {
- }
-
-}
-
-package android.net.ipsec.ike.exceptions {
-
- public abstract class IkeException extends java.lang.Exception {
- }
-
- public final class IkeInternalException extends android.net.ipsec.ike.exceptions.IkeException {
- }
-
- public abstract class IkeProtocolException extends android.net.ipsec.ike.exceptions.IkeException {
- method @Nullable public byte[] getErrorData();
- method public int getErrorType();
- field public static final int ERROR_TYPE_AUTHENTICATION_FAILED = 24; // 0x18
- field public static final int ERROR_TYPE_CHILD_SA_NOT_FOUND = 44; // 0x2c
- field public static final int ERROR_TYPE_FAILED_CP_REQUIRED = 37; // 0x25
- field public static final int ERROR_TYPE_INTERNAL_ADDRESS_FAILURE = 36; // 0x24
- field public static final int ERROR_TYPE_INVALID_IKE_SPI = 4; // 0x4
- field public static final int ERROR_TYPE_INVALID_KE_PAYLOAD = 17; // 0x11
- field public static final int ERROR_TYPE_INVALID_MAJOR_VERSION = 5; // 0x5
- field public static final int ERROR_TYPE_INVALID_MESSAGE_ID = 9; // 0x9
- field public static final int ERROR_TYPE_INVALID_SELECTORS = 39; // 0x27
- field public static final int ERROR_TYPE_INVALID_SYNTAX = 7; // 0x7
- field public static final int ERROR_TYPE_NO_ADDITIONAL_SAS = 35; // 0x23
- field public static final int ERROR_TYPE_NO_PROPOSAL_CHOSEN = 14; // 0xe
- field public static final int ERROR_TYPE_SINGLE_PAIR_REQUIRED = 34; // 0x22
- field public static final int ERROR_TYPE_TEMPORARY_FAILURE = 43; // 0x2b
- field public static final int ERROR_TYPE_TS_UNACCEPTABLE = 38; // 0x26
- field public static final int ERROR_TYPE_UNSUPPORTED_CRITICAL_PAYLOAD = 1; // 0x1
- }
-
-}
-
package android.net.metrics {
public final class ApfProgramEvent implements android.net.metrics.IpConnectivityLog.Event {
@@ -11400,347 +11069,7 @@ package android.telephony {
}
public final class DataFailCause {
- field public static final int ACCESS_ATTEMPT_ALREADY_IN_PROGRESS = 2219; // 0x8ab
- field public static final int ACCESS_BLOCK = 2087; // 0x827
- field public static final int ACCESS_BLOCK_ALL = 2088; // 0x828
- field public static final int ACCESS_CLASS_DSAC_REJECTION = 2108; // 0x83c
- field public static final int ACCESS_CONTROL_LIST_CHECK_FAILURE = 2128; // 0x850
- field public static final int ACTIVATION_REJECTED_BCM_VIOLATION = 48; // 0x30
- field public static final int ACTIVATION_REJECT_GGSN = 30; // 0x1e
- field public static final int ACTIVATION_REJECT_UNSPECIFIED = 31; // 0x1f
- field public static final int ACTIVE_PDP_CONTEXT_MAX_NUMBER_REACHED = 65; // 0x41
- field public static final int APN_DISABLED = 2045; // 0x7fd
- field public static final int APN_DISALLOWED_ON_ROAMING = 2059; // 0x80b
- field public static final int APN_MISMATCH = 2054; // 0x806
- field public static final int APN_PARAMETERS_CHANGED = 2060; // 0x80c
- field public static final int APN_PENDING_HANDOVER = 2041; // 0x7f9
- field public static final int APN_TYPE_CONFLICT = 112; // 0x70
- field public static final int AUTH_FAILURE_ON_EMERGENCY_CALL = 122; // 0x7a
- field public static final int BEARER_HANDLING_NOT_SUPPORTED = 60; // 0x3c
- field public static final int CALL_DISALLOWED_IN_ROAMING = 2068; // 0x814
- field public static final int CALL_PREEMPT_BY_EMERGENCY_APN = 127; // 0x7f
- field public static final int CANNOT_ENCODE_OTA_MESSAGE = 2159; // 0x86f
- field public static final int CDMA_ALERT_STOP = 2077; // 0x81d
- field public static final int CDMA_INCOMING_CALL = 2076; // 0x81c
- field public static final int CDMA_INTERCEPT = 2073; // 0x819
- field public static final int CDMA_LOCK = 2072; // 0x818
- field public static final int CDMA_RELEASE_DUE_TO_SO_REJECTION = 2075; // 0x81b
- field public static final int CDMA_REORDER = 2074; // 0x81a
- field public static final int CDMA_RETRY_ORDER = 2086; // 0x826
- field public static final int CHANNEL_ACQUISITION_FAILURE = 2078; // 0x81e
- field public static final int CLOSE_IN_PROGRESS = 2030; // 0x7ee
- field public static final int COLLISION_WITH_NETWORK_INITIATED_REQUEST = 56; // 0x38
- field public static final int COMPANION_IFACE_IN_USE = 118; // 0x76
- field public static final int CONCURRENT_SERVICES_INCOMPATIBLE = 2083; // 0x823
- field public static final int CONCURRENT_SERVICES_NOT_ALLOWED = 2091; // 0x82b
- field public static final int CONCURRENT_SERVICE_NOT_SUPPORTED_BY_BASE_STATION = 2080; // 0x820
- field public static final int CONDITIONAL_IE_ERROR = 100; // 0x64
- field public static final int CONGESTION = 2106; // 0x83a
- field public static final int CONNECTION_RELEASED = 2113; // 0x841
- field public static final int CS_DOMAIN_NOT_AVAILABLE = 2181; // 0x885
- field public static final int CS_FALLBACK_CALL_ESTABLISHMENT_NOT_ALLOWED = 2188; // 0x88c
- field public static final int DATA_PLAN_EXPIRED = 2198; // 0x896
- field public static final int DATA_ROAMING_SETTINGS_DISABLED = 2064; // 0x810
- field public static final int DATA_SETTINGS_DISABLED = 2063; // 0x80f
- field public static final int DBM_OR_SMS_IN_PROGRESS = 2211; // 0x8a3
- field public static final int DDS_SWITCHED = 2065; // 0x811
- field public static final int DDS_SWITCH_IN_PROGRESS = 2067; // 0x813
- field public static final int DRB_RELEASED_BY_RRC = 2112; // 0x840
- field public static final int DS_EXPLICIT_DEACTIVATION = 2125; // 0x84d
- field public static final int DUAL_SWITCH = 2227; // 0x8b3
- field public static final int DUN_CALL_DISALLOWED = 2056; // 0x808
- field public static final int DUPLICATE_BEARER_ID = 2118; // 0x846
- field public static final int EHRPD_TO_HRPD_FALLBACK = 2049; // 0x801
- field public static final int EMBMS_NOT_ENABLED = 2193; // 0x891
- field public static final int EMBMS_REGULAR_DEACTIVATION = 2195; // 0x893
- field public static final int EMERGENCY_IFACE_ONLY = 116; // 0x74
- field public static final int EMERGENCY_MODE = 2221; // 0x8ad
- field public static final int EMM_ACCESS_BARRED = 115; // 0x73
- field public static final int EMM_ACCESS_BARRED_INFINITE_RETRY = 121; // 0x79
- field public static final int EMM_ATTACH_FAILED = 2115; // 0x843
- field public static final int EMM_ATTACH_STARTED = 2116; // 0x844
- field public static final int EMM_DETACHED = 2114; // 0x842
- field public static final int EMM_T3417_EXPIRED = 2130; // 0x852
- field public static final int EMM_T3417_EXT_EXPIRED = 2131; // 0x853
- field public static final int EPS_SERVICES_AND_NON_EPS_SERVICES_NOT_ALLOWED = 2178; // 0x882
- field public static final int EPS_SERVICES_NOT_ALLOWED_IN_PLMN = 2179; // 0x883
- field public static final int ERROR_UNSPECIFIED = 65535; // 0xffff
- field public static final int ESM_BAD_OTA_MESSAGE = 2122; // 0x84a
- field public static final int ESM_BEARER_DEACTIVATED_TO_SYNC_WITH_NETWORK = 2120; // 0x848
- field public static final int ESM_COLLISION_SCENARIOS = 2119; // 0x847
- field public static final int ESM_CONTEXT_TRANSFERRED_DUE_TO_IRAT = 2124; // 0x84c
- field public static final int ESM_DOWNLOAD_SERVER_REJECTED_THE_CALL = 2123; // 0x84b
- field public static final int ESM_FAILURE = 2182; // 0x886
- field public static final int ESM_INFO_NOT_RECEIVED = 53; // 0x35
- field public static final int ESM_LOCAL_CAUSE_NONE = 2126; // 0x84e
- field public static final int ESM_NW_ACTIVATED_DED_BEARER_WITH_ID_OF_DEF_BEARER = 2121; // 0x849
- field public static final int ESM_PROCEDURE_TIME_OUT = 2155; // 0x86b
- field public static final int ESM_UNKNOWN_EPS_BEARER_CONTEXT = 2111; // 0x83f
- field public static final int EVDO_CONNECTION_DENY_BY_BILLING_OR_AUTHENTICATION_FAILURE = 2201; // 0x899
- field public static final int EVDO_CONNECTION_DENY_BY_GENERAL_OR_NETWORK_BUSY = 2200; // 0x898
- field public static final int EVDO_HDR_CHANGED = 2202; // 0x89a
- field public static final int EVDO_HDR_CONNECTION_SETUP_TIMEOUT = 2206; // 0x89e
- field public static final int EVDO_HDR_EXITED = 2203; // 0x89b
- field public static final int EVDO_HDR_NO_SESSION = 2204; // 0x89c
- field public static final int EVDO_USING_GPS_FIX_INSTEAD_OF_HDR_CALL = 2205; // 0x89d
- field public static final int FADE = 2217; // 0x8a9
- field public static final int FAILED_TO_ACQUIRE_COLOCATED_HDR = 2207; // 0x89f
- field public static final int FEATURE_NOT_SUPP = 40; // 0x28
- field public static final int FILTER_SEMANTIC_ERROR = 44; // 0x2c
- field public static final int FILTER_SYTAX_ERROR = 45; // 0x2d
- field public static final int FORBIDDEN_APN_NAME = 2066; // 0x812
- field public static final int GPRS_REGISTRATION_FAIL = -2; // 0xfffffffe
- field public static final int GPRS_SERVICES_AND_NON_GPRS_SERVICES_NOT_ALLOWED = 2097; // 0x831
- field public static final int GPRS_SERVICES_NOT_ALLOWED = 2098; // 0x832
- field public static final int GPRS_SERVICES_NOT_ALLOWED_IN_THIS_PLMN = 2103; // 0x837
- field public static final int HANDOFF_PREFERENCE_CHANGED = 2251; // 0x8cb
- field public static final int HDR_ACCESS_FAILURE = 2213; // 0x8a5
- field public static final int HDR_FADE = 2212; // 0x8a4
- field public static final int HDR_NO_LOCK_GRANTED = 2210; // 0x8a2
- field public static final int IFACE_AND_POL_FAMILY_MISMATCH = 120; // 0x78
- field public static final int IFACE_MISMATCH = 117; // 0x75
- field public static final int ILLEGAL_ME = 2096; // 0x830
- field public static final int ILLEGAL_MS = 2095; // 0x82f
- field public static final int IMEI_NOT_ACCEPTED = 2177; // 0x881
- field public static final int IMPLICITLY_DETACHED = 2100; // 0x834
- field public static final int IMSI_UNKNOWN_IN_HOME_SUBSCRIBER_SERVER = 2176; // 0x880
- field public static final int INCOMING_CALL_REJECTED = 2092; // 0x82c
- field public static final int INSUFFICIENT_RESOURCES = 26; // 0x1a
- field public static final int INTERFACE_IN_USE = 2058; // 0x80a
- field public static final int INTERNAL_CALL_PREEMPT_BY_HIGH_PRIO_APN = 114; // 0x72
- field public static final int INTERNAL_EPC_NONEPC_TRANSITION = 2057; // 0x809
- field public static final int INVALID_CONNECTION_ID = 2156; // 0x86c
- field public static final int INVALID_DNS_ADDR = 123; // 0x7b
- field public static final int INVALID_EMM_STATE = 2190; // 0x88e
- field public static final int INVALID_MANDATORY_INFO = 96; // 0x60
- field public static final int INVALID_MODE = 2223; // 0x8af
- field public static final int INVALID_PCSCF_ADDR = 113; // 0x71
- field public static final int INVALID_PCSCF_OR_DNS_ADDRESS = 124; // 0x7c
- field public static final int INVALID_PRIMARY_NSAPI = 2158; // 0x86e
- field public static final int INVALID_SIM_STATE = 2224; // 0x8b0
- field public static final int INVALID_TRANSACTION_ID = 81; // 0x51
- field public static final int IPV6_ADDRESS_TRANSFER_FAILED = 2047; // 0x7ff
- field public static final int IPV6_PREFIX_UNAVAILABLE = 2250; // 0x8ca
- field public static final int IP_ADDRESS_MISMATCH = 119; // 0x77
- field public static final int IP_VERSION_MISMATCH = 2055; // 0x807
- field public static final int IRAT_HANDOVER_FAILED = 2194; // 0x892
- field public static final int IS707B_MAX_ACCESS_PROBES = 2089; // 0x829
- field public static final int LIMITED_TO_IPV4 = 2234; // 0x8ba
- field public static final int LIMITED_TO_IPV6 = 2235; // 0x8bb
- field public static final int LLC_SNDCP = 25; // 0x19
- field public static final int LOCAL_END = 2215; // 0x8a7
- field public static final int LOCATION_AREA_NOT_ALLOWED = 2102; // 0x836
- field public static final int LOST_CONNECTION = 65540; // 0x10004
- field public static final int LOWER_LAYER_REGISTRATION_FAILURE = 2197; // 0x895
- field public static final int LOW_POWER_MODE_OR_POWERING_DOWN = 2044; // 0x7fc
- field public static final int LTE_NAS_SERVICE_REQUEST_FAILED = 2117; // 0x845
- field public static final int LTE_THROTTLING_NOT_REQUIRED = 2127; // 0x84f
- field public static final int MAC_FAILURE = 2183; // 0x887
- field public static final int MAXIMIUM_NSAPIS_EXCEEDED = 2157; // 0x86d
- field public static final int MAXINUM_SIZE_OF_L2_MESSAGE_EXCEEDED = 2166; // 0x876
- field public static final int MAX_ACCESS_PROBE = 2079; // 0x81f
- field public static final int MAX_IPV4_CONNECTIONS = 2052; // 0x804
- field public static final int MAX_IPV6_CONNECTIONS = 2053; // 0x805
- field public static final int MAX_PPP_INACTIVITY_TIMER_EXPIRED = 2046; // 0x7fe
- field public static final int MESSAGE_INCORRECT_SEMANTIC = 95; // 0x5f
- field public static final int MESSAGE_TYPE_UNSUPPORTED = 97; // 0x61
- field public static final int MIP_CONFIG_FAILURE = 2050; // 0x802
- field public static final int MIP_FA_ADMIN_PROHIBITED = 2001; // 0x7d1
- field public static final int MIP_FA_DELIVERY_STYLE_NOT_SUPPORTED = 2012; // 0x7dc
- field public static final int MIP_FA_ENCAPSULATION_UNAVAILABLE = 2008; // 0x7d8
- field public static final int MIP_FA_HOME_AGENT_AUTHENTICATION_FAILURE = 2004; // 0x7d4
- field public static final int MIP_FA_INSUFFICIENT_RESOURCES = 2002; // 0x7d2
- field public static final int MIP_FA_MALFORMED_REPLY = 2007; // 0x7d7
- field public static final int MIP_FA_MALFORMED_REQUEST = 2006; // 0x7d6
- field public static final int MIP_FA_MISSING_CHALLENGE = 2017; // 0x7e1
- field public static final int MIP_FA_MISSING_HOME_ADDRESS = 2015; // 0x7df
- field public static final int MIP_FA_MISSING_HOME_AGENT = 2014; // 0x7de
- field public static final int MIP_FA_MISSING_NAI = 2013; // 0x7dd
- field public static final int MIP_FA_MOBILE_NODE_AUTHENTICATION_FAILURE = 2003; // 0x7d3
- field public static final int MIP_FA_REASON_UNSPECIFIED = 2000; // 0x7d0
- field public static final int MIP_FA_REQUESTED_LIFETIME_TOO_LONG = 2005; // 0x7d5
- field public static final int MIP_FA_REVERSE_TUNNEL_IS_MANDATORY = 2011; // 0x7db
- field public static final int MIP_FA_REVERSE_TUNNEL_UNAVAILABLE = 2010; // 0x7da
- field public static final int MIP_FA_STALE_CHALLENGE = 2018; // 0x7e2
- field public static final int MIP_FA_UNKNOWN_CHALLENGE = 2016; // 0x7e0
- field public static final int MIP_FA_VJ_HEADER_COMPRESSION_UNAVAILABLE = 2009; // 0x7d9
- field public static final int MIP_HA_ADMIN_PROHIBITED = 2020; // 0x7e4
- field public static final int MIP_HA_ENCAPSULATION_UNAVAILABLE = 2029; // 0x7ed
- field public static final int MIP_HA_FOREIGN_AGENT_AUTHENTICATION_FAILURE = 2023; // 0x7e7
- field public static final int MIP_HA_INSUFFICIENT_RESOURCES = 2021; // 0x7e5
- field public static final int MIP_HA_MALFORMED_REQUEST = 2025; // 0x7e9
- field public static final int MIP_HA_MOBILE_NODE_AUTHENTICATION_FAILURE = 2022; // 0x7e6
- field public static final int MIP_HA_REASON_UNSPECIFIED = 2019; // 0x7e3
- field public static final int MIP_HA_REGISTRATION_ID_MISMATCH = 2024; // 0x7e8
- field public static final int MIP_HA_REVERSE_TUNNEL_IS_MANDATORY = 2028; // 0x7ec
- field public static final int MIP_HA_REVERSE_TUNNEL_UNAVAILABLE = 2027; // 0x7eb
- field public static final int MIP_HA_UNKNOWN_HOME_AGENT_ADDRESS = 2026; // 0x7ea
- field public static final int MISSING_UNKNOWN_APN = 27; // 0x1b
- field public static final int MODEM_APP_PREEMPTED = 2032; // 0x7f0
- field public static final int MODEM_RESTART = 2037; // 0x7f5
- field public static final int MSC_TEMPORARILY_NOT_REACHABLE = 2180; // 0x884
- field public static final int MSG_AND_PROTOCOL_STATE_UNCOMPATIBLE = 101; // 0x65
- field public static final int MSG_TYPE_NONCOMPATIBLE_STATE = 98; // 0x62
- field public static final int MS_IDENTITY_CANNOT_BE_DERIVED_BY_THE_NETWORK = 2099; // 0x833
- field public static final int MULTIPLE_PDP_CALL_NOT_ALLOWED = 2192; // 0x890
- field public static final int MULTI_CONN_TO_SAME_PDN_NOT_ALLOWED = 55; // 0x37
- field public static final int NAS_LAYER_FAILURE = 2191; // 0x88f
- field public static final int NAS_REQUEST_REJECTED_BY_NETWORK = 2167; // 0x877
- field public static final int NAS_SIGNALLING = 14; // 0xe
- field public static final int NETWORK_FAILURE = 38; // 0x26
- field public static final int NETWORK_INITIATED_DETACH_NO_AUTO_REATTACH = 2154; // 0x86a
- field public static final int NETWORK_INITIATED_DETACH_WITH_AUTO_REATTACH = 2153; // 0x869
- field public static final int NETWORK_INITIATED_TERMINATION = 2031; // 0x7ef
- field public static final int NONE = 0; // 0x0
- field public static final int NON_IP_NOT_SUPPORTED = 2069; // 0x815
- field public static final int NORMAL_RELEASE = 2218; // 0x8aa
- field public static final int NO_CDMA_SERVICE = 2084; // 0x824
- field public static final int NO_COLLOCATED_HDR = 2225; // 0x8b1
- field public static final int NO_EPS_BEARER_CONTEXT_ACTIVATED = 2189; // 0x88d
- field public static final int NO_GPRS_CONTEXT = 2094; // 0x82e
- field public static final int NO_HYBRID_HDR_SERVICE = 2209; // 0x8a1
- field public static final int NO_PDP_CONTEXT_ACTIVATED = 2107; // 0x83b
- field public static final int NO_RESPONSE_FROM_BASE_STATION = 2081; // 0x821
- field public static final int NO_SERVICE = 2216; // 0x8a8
- field public static final int NO_SERVICE_ON_GATEWAY = 2093; // 0x82d
- field public static final int NSAPI_IN_USE = 35; // 0x23
- field public static final int NULL_APN_DISALLOWED = 2061; // 0x80d
- field public static final int OEM_DCFAILCAUSE_1 = 4097; // 0x1001
- field public static final int OEM_DCFAILCAUSE_10 = 4106; // 0x100a
- field public static final int OEM_DCFAILCAUSE_11 = 4107; // 0x100b
- field public static final int OEM_DCFAILCAUSE_12 = 4108; // 0x100c
- field public static final int OEM_DCFAILCAUSE_13 = 4109; // 0x100d
- field public static final int OEM_DCFAILCAUSE_14 = 4110; // 0x100e
- field public static final int OEM_DCFAILCAUSE_15 = 4111; // 0x100f
- field public static final int OEM_DCFAILCAUSE_2 = 4098; // 0x1002
- field public static final int OEM_DCFAILCAUSE_3 = 4099; // 0x1003
- field public static final int OEM_DCFAILCAUSE_4 = 4100; // 0x1004
- field public static final int OEM_DCFAILCAUSE_5 = 4101; // 0x1005
- field public static final int OEM_DCFAILCAUSE_6 = 4102; // 0x1006
- field public static final int OEM_DCFAILCAUSE_7 = 4103; // 0x1007
- field public static final int OEM_DCFAILCAUSE_8 = 4104; // 0x1008
- field public static final int OEM_DCFAILCAUSE_9 = 4105; // 0x1009
- field public static final int ONLY_IPV4V6_ALLOWED = 57; // 0x39
- field public static final int ONLY_IPV4_ALLOWED = 50; // 0x32
- field public static final int ONLY_IPV6_ALLOWED = 51; // 0x33
- field public static final int ONLY_NON_IP_ALLOWED = 58; // 0x3a
- field public static final int ONLY_SINGLE_BEARER_ALLOWED = 52; // 0x34
- field public static final int OPERATOR_BARRED = 8; // 0x8
- field public static final int OTASP_COMMIT_IN_PROGRESS = 2208; // 0x8a0
- field public static final int PDN_CONN_DOES_NOT_EXIST = 54; // 0x36
- field public static final int PDN_INACTIVITY_TIMER_EXPIRED = 2051; // 0x803
- field public static final int PDN_IPV4_CALL_DISALLOWED = 2033; // 0x7f1
- field public static final int PDN_IPV4_CALL_THROTTLED = 2034; // 0x7f2
- field public static final int PDN_IPV6_CALL_DISALLOWED = 2035; // 0x7f3
- field public static final int PDN_IPV6_CALL_THROTTLED = 2036; // 0x7f4
- field public static final int PDN_NON_IP_CALL_DISALLOWED = 2071; // 0x817
- field public static final int PDN_NON_IP_CALL_THROTTLED = 2070; // 0x816
- field public static final int PDP_ACTIVATE_MAX_RETRY_FAILED = 2109; // 0x83d
- field public static final int PDP_DUPLICATE = 2104; // 0x838
- field public static final int PDP_ESTABLISH_TIMEOUT_EXPIRED = 2161; // 0x871
- field public static final int PDP_INACTIVE_TIMEOUT_EXPIRED = 2163; // 0x873
- field public static final int PDP_LOWERLAYER_ERROR = 2164; // 0x874
- field public static final int PDP_MODIFY_COLLISION = 2165; // 0x875
- field public static final int PDP_MODIFY_TIMEOUT_EXPIRED = 2162; // 0x872
- field public static final int PDP_PPP_NOT_SUPPORTED = 2038; // 0x7f6
- field public static final int PDP_WITHOUT_ACTIVE_TFT = 46; // 0x2e
- field public static final int PHONE_IN_USE = 2222; // 0x8ae
- field public static final int PHYSICAL_LINK_CLOSE_IN_PROGRESS = 2040; // 0x7f8
- field public static final int PLMN_NOT_ALLOWED = 2101; // 0x835
- field public static final int PPP_AUTH_FAILURE = 2229; // 0x8b5
- field public static final int PPP_CHAP_FAILURE = 2232; // 0x8b8
- field public static final int PPP_CLOSE_IN_PROGRESS = 2233; // 0x8b9
- field public static final int PPP_OPTION_MISMATCH = 2230; // 0x8b6
- field public static final int PPP_PAP_FAILURE = 2231; // 0x8b7
- field public static final int PPP_TIMEOUT = 2228; // 0x8b4
- field public static final int PREF_RADIO_TECH_CHANGED = -4; // 0xfffffffc
- field public static final int PROFILE_BEARER_INCOMPATIBLE = 2042; // 0x7fa
- field public static final int PROTOCOL_ERRORS = 111; // 0x6f
- field public static final int QOS_NOT_ACCEPTED = 37; // 0x25
- field public static final int RADIO_ACCESS_BEARER_FAILURE = 2110; // 0x83e
- field public static final int RADIO_ACCESS_BEARER_SETUP_FAILURE = 2160; // 0x870
- field public static final int RADIO_NOT_AVAILABLE = 65537; // 0x10001
- field public static final int RADIO_POWER_OFF = -5; // 0xfffffffb
- field public static final int REDIRECTION_OR_HANDOFF_IN_PROGRESS = 2220; // 0x8ac
- field public static final int REGISTRATION_FAIL = -1; // 0xffffffff
- field public static final int REGULAR_DEACTIVATION = 36; // 0x24
- field public static final int REJECTED_BY_BASE_STATION = 2082; // 0x822
- field public static final int RRC_CONNECTION_ABORTED_AFTER_HANDOVER = 2173; // 0x87d
- field public static final int RRC_CONNECTION_ABORTED_AFTER_IRAT_CELL_CHANGE = 2174; // 0x87e
- field public static final int RRC_CONNECTION_ABORTED_DUE_TO_IRAT_CHANGE = 2171; // 0x87b
- field public static final int RRC_CONNECTION_ABORTED_DURING_IRAT_CELL_CHANGE = 2175; // 0x87f
- field public static final int RRC_CONNECTION_ABORT_REQUEST = 2151; // 0x867
- field public static final int RRC_CONNECTION_ACCESS_BARRED = 2139; // 0x85b
- field public static final int RRC_CONNECTION_ACCESS_STRATUM_FAILURE = 2137; // 0x859
- field public static final int RRC_CONNECTION_ANOTHER_PROCEDURE_IN_PROGRESS = 2138; // 0x85a
- field public static final int RRC_CONNECTION_CELL_NOT_CAMPED = 2144; // 0x860
- field public static final int RRC_CONNECTION_CELL_RESELECTION = 2140; // 0x85c
- field public static final int RRC_CONNECTION_CONFIG_FAILURE = 2141; // 0x85d
- field public static final int RRC_CONNECTION_INVALID_REQUEST = 2168; // 0x878
- field public static final int RRC_CONNECTION_LINK_FAILURE = 2143; // 0x85f
- field public static final int RRC_CONNECTION_NORMAL_RELEASE = 2147; // 0x863
- field public static final int RRC_CONNECTION_OUT_OF_SERVICE_DURING_CELL_REGISTER = 2150; // 0x866
- field public static final int RRC_CONNECTION_RADIO_LINK_FAILURE = 2148; // 0x864
- field public static final int RRC_CONNECTION_REESTABLISHMENT_FAILURE = 2149; // 0x865
- field public static final int RRC_CONNECTION_REJECT_BY_NETWORK = 2146; // 0x862
- field public static final int RRC_CONNECTION_RELEASED_SECURITY_NOT_ACTIVE = 2172; // 0x87c
- field public static final int RRC_CONNECTION_RF_UNAVAILABLE = 2170; // 0x87a
- field public static final int RRC_CONNECTION_SYSTEM_INFORMATION_BLOCK_READ_ERROR = 2152; // 0x868
- field public static final int RRC_CONNECTION_SYSTEM_INTERVAL_FAILURE = 2145; // 0x861
- field public static final int RRC_CONNECTION_TIMER_EXPIRED = 2142; // 0x85e
- field public static final int RRC_CONNECTION_TRACKING_AREA_ID_CHANGED = 2169; // 0x879
- field public static final int RRC_UPLINK_CONNECTION_RELEASE = 2134; // 0x856
- field public static final int RRC_UPLINK_DATA_TRANSMISSION_FAILURE = 2132; // 0x854
- field public static final int RRC_UPLINK_DELIVERY_FAILED_DUE_TO_HANDOVER = 2133; // 0x855
- field public static final int RRC_UPLINK_ERROR_REQUEST_FROM_NAS = 2136; // 0x858
- field public static final int RRC_UPLINK_RADIO_LINK_FAILURE = 2135; // 0x857
- field public static final int RUIM_NOT_PRESENT = 2085; // 0x825
- field public static final int SECURITY_MODE_REJECTED = 2186; // 0x88a
- field public static final int SERVICE_NOT_ALLOWED_ON_PLMN = 2129; // 0x851
- field public static final int SERVICE_OPTION_NOT_SUBSCRIBED = 33; // 0x21
- field public static final int SERVICE_OPTION_NOT_SUPPORTED = 32; // 0x20
- field public static final int SERVICE_OPTION_OUT_OF_ORDER = 34; // 0x22
- field public static final int SIGNAL_LOST = -3; // 0xfffffffd
- field public static final int SIM_CARD_CHANGED = 2043; // 0x7fb
- field public static final int SYNCHRONIZATION_FAILURE = 2184; // 0x888
- field public static final int TEST_LOOPBACK_REGULAR_DEACTIVATION = 2196; // 0x894
- field public static final int TETHERED_CALL_ACTIVE = -6; // 0xfffffffa
- field public static final int TFT_SEMANTIC_ERROR = 41; // 0x29
- field public static final int TFT_SYTAX_ERROR = 42; // 0x2a
- field public static final int THERMAL_EMERGENCY = 2090; // 0x82a
- field public static final int THERMAL_MITIGATION = 2062; // 0x80e
- field public static final int TRAT_SWAP_FAILED = 2048; // 0x800
- field public static final int UE_INITIATED_DETACH_OR_DISCONNECT = 128; // 0x80
- field public static final int UE_IS_ENTERING_POWERSAVE_MODE = 2226; // 0x8b2
- field public static final int UE_RAT_CHANGE = 2105; // 0x839
- field public static final int UE_SECURITY_CAPABILITIES_MISMATCH = 2185; // 0x889
- field public static final int UMTS_HANDOVER_TO_IWLAN = 2199; // 0x897
- field public static final int UMTS_REACTIVATION_REQ = 39; // 0x27
- field public static final int UNACCEPTABLE_NETWORK_PARAMETER = 65538; // 0x10002
- field public static final int UNACCEPTABLE_NON_EPS_AUTHENTICATION = 2187; // 0x88b
- field public static final int UNKNOWN = 65536; // 0x10000
- field public static final int UNKNOWN_INFO_ELEMENT = 99; // 0x63
- field public static final int UNKNOWN_PDP_ADDRESS_TYPE = 28; // 0x1c
- field public static final int UNKNOWN_PDP_CONTEXT = 43; // 0x2b
- field public static final int UNPREFERRED_RAT = 2039; // 0x7f7
- field public static final int UNSUPPORTED_1X_PREV = 2214; // 0x8a6
- field public static final int UNSUPPORTED_APN_IN_CURRENT_PLMN = 66; // 0x42
- field public static final int UNSUPPORTED_QCI_VALUE = 59; // 0x3b
- field public static final int USER_AUTHENTICATION = 29; // 0x1d
- field public static final int VSNCP_ADMINISTRATIVELY_PROHIBITED = 2245; // 0x8c5
- field public static final int VSNCP_APN_UNATHORIZED = 2238; // 0x8be
- field public static final int VSNCP_GEN_ERROR = 2237; // 0x8bd
- field public static final int VSNCP_INSUFFICIENT_PARAMETERS = 2243; // 0x8c3
- field public static final int VSNCP_NO_PDN_GATEWAY_ADDRESS = 2240; // 0x8c0
- field public static final int VSNCP_PDN_EXISTS_FOR_THIS_APN = 2248; // 0x8c8
- field public static final int VSNCP_PDN_GATEWAY_REJECT = 2242; // 0x8c2
- field public static final int VSNCP_PDN_GATEWAY_UNREACHABLE = 2241; // 0x8c1
- field public static final int VSNCP_PDN_ID_IN_USE = 2246; // 0x8c6
- field public static final int VSNCP_PDN_LIMIT_EXCEEDED = 2239; // 0x8bf
- field public static final int VSNCP_RECONNECT_NOT_ALLOWED = 2249; // 0x8c9
- field public static final int VSNCP_RESOURCE_UNAVAILABLE = 2244; // 0x8c4
- field public static final int VSNCP_SUBSCRIBER_LIMITATION = 2247; // 0x8c7
- field public static final int VSNCP_TIMEOUT = 2236; // 0x8bc
+ field @Deprecated public static final int VSNCP_APN_UNATHORIZED = 2238; // 0x8be
}
public final class DataSpecificRegistrationInfo implements android.os.Parcelable {
diff --git a/api/test-current.txt b/api/test-current.txt
index 8a0be6960ae5..9e37a3c5be96 100644
--- a/api/test-current.txt
+++ b/api/test-current.txt
@@ -1478,6 +1478,10 @@ package android.media {
method @NonNull public String getOriginalId();
}
+ public class MediaRouter2.RoutingController {
+ method @NonNull public String getOriginalId();
+ }
+
public final class PlaybackParams implements android.os.Parcelable {
method public int getAudioStretchMode();
method public android.media.PlaybackParams setAudioStretchMode(int);
@@ -2534,6 +2538,11 @@ package android.os {
method public void log(android.os.StrictMode.ViolationInfo);
}
+ public static final class StrictMode.VmPolicy.Builder {
+ method @NonNull public android.os.StrictMode.VmPolicy.Builder detectIncorrectContextUse();
+ method @NonNull public android.os.StrictMode.VmPolicy.Builder permitIncorrectContextUse();
+ }
+
public class SystemConfigManager {
method @NonNull @RequiresPermission("android.permission.READ_CARRIER_APP_INFO") public java.util.Set<java.lang.String> getDisabledUntilUsedPreinstalledCarrierApps();
method @NonNull @RequiresPermission("android.permission.READ_CARRIER_APP_INFO") public java.util.Map<java.lang.String,java.util.List<java.lang.String>> getDisabledUntilUsedPreinstalledCarrierAssociatedApps();
diff --git a/cmds/hid/jni/com_android_commands_hid_Device.cpp b/cmds/hid/jni/com_android_commands_hid_Device.cpp
index f56dd6e4968e..95de6c506795 100644
--- a/cmds/hid/jni/com_android_commands_hid_Device.cpp
+++ b/cmds/hid/jni/com_android_commands_hid_Device.cpp
@@ -129,7 +129,7 @@ JNIEnv* DeviceCallback::getJNIEnv() {
}
std::unique_ptr<Device> Device::open(int32_t id, const char* name, int32_t vid, int32_t pid,
- const std::vector<uint8_t>& descriptor,
+ uint16_t bus, const std::vector<uint8_t>& descriptor,
std::unique_ptr<DeviceCallback> callback) {
size_t size = descriptor.size();
if (size > HID_MAX_DESCRIPTOR_SIZE) {
@@ -148,7 +148,7 @@ std::unique_ptr<Device> Device::open(int32_t id, const char* name, int32_t vid,
strlcpy(reinterpret_cast<char*>(ev.u.create2.name), name, sizeof(ev.u.create2.name));
memcpy(&ev.u.create2.rd_data, descriptor.data(), size * sizeof(ev.u.create2.rd_data[0]));
ev.u.create2.rd_size = size;
- ev.u.create2.bus = BUS_BLUETOOTH;
+ ev.u.create2.bus = bus;
ev.u.create2.vendor = vid;
ev.u.create2.product = pid;
ev.u.create2.version = 0;
@@ -293,8 +293,8 @@ std::vector<uint8_t> getData(JNIEnv* env, jbyteArray javaArray) {
return data;
}
-static jlong openDevice(JNIEnv* env, jclass /* clazz */, jstring rawName, jint id, jint vid, jint pid,
- jbyteArray rawDescriptor, jobject callback) {
+static jlong openDevice(JNIEnv* env, jclass /* clazz */, jstring rawName, jint id, jint vid,
+ jint pid, jint bus, jbyteArray rawDescriptor, jobject callback) {
ScopedUtfChars name(env, rawName);
if (name.c_str() == nullptr) {
return 0;
@@ -305,7 +305,7 @@ static jlong openDevice(JNIEnv* env, jclass /* clazz */, jstring rawName, jint i
std::unique_ptr<uhid::DeviceCallback> cb(new uhid::DeviceCallback(env, callback));
std::unique_ptr<uhid::Device> d =
- uhid::Device::open(id, reinterpret_cast<const char*>(name.c_str()), vid, pid, desc,
+ uhid::Device::open(id, reinterpret_cast<const char*>(name.c_str()), vid, pid, bus, desc,
std::move(cb));
return reinterpret_cast<jlong>(d.release());
}
@@ -339,14 +339,14 @@ static void closeDevice(JNIEnv* /* env */, jclass /* clazz */, jlong ptr) {
}
static JNINativeMethod sMethods[] = {
- { "nativeOpenDevice",
- "(Ljava/lang/String;III[B"
- "Lcom/android/commands/hid/Device$DeviceCallback;)J",
- reinterpret_cast<void*>(openDevice) },
- { "nativeSendReport", "(J[B)V", reinterpret_cast<void*>(sendReport) },
- { "nativeSendGetFeatureReportReply", "(JI[B)V",
- reinterpret_cast<void*>(sendGetFeatureReportReply) },
- { "nativeCloseDevice", "(J)V", reinterpret_cast<void*>(closeDevice) },
+ {"nativeOpenDevice",
+ "(Ljava/lang/String;IIII[B"
+ "Lcom/android/commands/hid/Device$DeviceCallback;)J",
+ reinterpret_cast<void*>(openDevice)},
+ {"nativeSendReport", "(J[B)V", reinterpret_cast<void*>(sendReport)},
+ {"nativeSendGetFeatureReportReply", "(JI[B)V",
+ reinterpret_cast<void*>(sendGetFeatureReportReply)},
+ {"nativeCloseDevice", "(J)V", reinterpret_cast<void*>(closeDevice)},
};
int register_com_android_commands_hid_Device(JNIEnv* env) {
diff --git a/cmds/hid/jni/com_android_commands_hid_Device.h b/cmds/hid/jni/com_android_commands_hid_Device.h
index 93ea881cfe28..7202b45adcde 100644
--- a/cmds/hid/jni/com_android_commands_hid_Device.h
+++ b/cmds/hid/jni/com_android_commands_hid_Device.h
@@ -43,7 +43,7 @@ private:
class Device {
public:
static std::unique_ptr<Device> open(int32_t id, const char* name, int32_t vid, int32_t pid,
- const std::vector<uint8_t>& descriptor,
+ uint16_t bus, const std::vector<uint8_t>& descriptor,
std::unique_ptr<DeviceCallback> callback);
~Device();
diff --git a/cmds/hid/src/com/android/commands/hid/Device.java b/cmds/hid/src/com/android/commands/hid/Device.java
index 874604ceb5e4..dade41511ae6 100644
--- a/cmds/hid/src/com/android/commands/hid/Device.java
+++ b/cmds/hid/src/com/android/commands/hid/Device.java
@@ -52,13 +52,13 @@ public class Device {
System.loadLibrary("hidcommand_jni");
}
- private static native long nativeOpenDevice(String name, int id, int vid, int pid,
+ private static native long nativeOpenDevice(String name, int id, int vid, int pid, int bus,
byte[] descriptor, DeviceCallback callback);
private static native void nativeSendReport(long ptr, byte[] data);
private static native void nativeSendGetFeatureReportReply(long ptr, int id, byte[] data);
private static native void nativeCloseDevice(long ptr);
- public Device(int id, String name, int vid, int pid, byte[] descriptor,
+ public Device(int id, String name, int vid, int pid, int bus, byte[] descriptor,
byte[] report, SparseArray<byte[]> featureReports, Map<ByteBuffer, byte[]> outputs) {
mId = id;
mThread = new HandlerThread("HidDeviceHandler");
@@ -70,6 +70,7 @@ public class Device {
args.argi1 = id;
args.argi2 = vid;
args.argi3 = pid;
+ args.argi4 = bus;
if (name != null) {
args.arg1 = name;
} else {
@@ -115,7 +116,7 @@ public class Device {
case MSG_OPEN_DEVICE:
SomeArgs args = (SomeArgs) msg.obj;
mPtr = nativeOpenDevice((String) args.arg1, args.argi1, args.argi2, args.argi3,
- (byte[]) args.arg2, new DeviceCallback());
+ args.argi4, (byte[]) args.arg2, new DeviceCallback());
pauseEvents();
break;
case MSG_SEND_REPORT:
diff --git a/cmds/hid/src/com/android/commands/hid/Event.java b/cmds/hid/src/com/android/commands/hid/Event.java
index 62587a70f10d..d4bf1d820a70 100644
--- a/cmds/hid/src/com/android/commands/hid/Event.java
+++ b/cmds/hid/src/com/android/commands/hid/Event.java
@@ -36,12 +36,28 @@ public class Event {
public static final String COMMAND_DELAY = "delay";
public static final String COMMAND_REPORT = "report";
+ // These constants come from "include/uapi/linux/input.h" in the kernel
+ enum Bus {
+ USB(0x03), BLUETOOTH(0x05);
+
+ Bus(int value) {
+ mValue = value;
+ }
+
+ int getValue() {
+ return mValue;
+ }
+
+ private int mValue;
+ }
+
private int mId;
private String mCommand;
private String mName;
private byte[] mDescriptor;
private int mVid;
private int mPid;
+ private Bus mBus;
private byte[] mReport;
private SparseArray<byte[]> mFeatureReports;
private Map<ByteBuffer, byte[]> mOutputs;
@@ -71,6 +87,10 @@ public class Event {
return mPid;
}
+ public int getBus() {
+ return mBus.getValue();
+ }
+
public byte[] getReport() {
return mReport;
}
@@ -94,6 +114,7 @@ public class Event {
+ ", descriptor=" + Arrays.toString(mDescriptor)
+ ", vid=" + mVid
+ ", pid=" + mPid
+ + ", bus=" + mBus
+ ", report=" + Arrays.toString(mReport)
+ ", feature_reports=" + mFeatureReports.toString()
+ ", outputs=" + mOutputs.toString()
@@ -144,6 +165,10 @@ public class Event {
mEvent.mPid = pid;
}
+ public void setBus(Bus bus) {
+ mEvent.mBus = bus;
+ }
+
public void setDuration(int duration) {
mEvent.mDuration = duration;
}
@@ -206,6 +231,9 @@ public class Event {
case "pid":
eb.setPid(readInt());
break;
+ case "bus":
+ eb.setBus(readBus());
+ break;
case "report":
eb.setReport(readData());
break;
@@ -264,6 +292,11 @@ public class Event {
return Integer.decode(val);
}
+ private Bus readBus() throws IOException {
+ String val = mReader.nextString();
+ return Bus.valueOf(val.toUpperCase());
+ }
+
private SparseArray<byte[]> readFeatureReports()
throws IllegalStateException, IOException {
SparseArray<byte[]> featureReports = new SparseArray<>();
diff --git a/cmds/hid/src/com/android/commands/hid/Hid.java b/cmds/hid/src/com/android/commands/hid/Hid.java
index 0ee2cc45932f..fac0ab2ef125 100644
--- a/cmds/hid/src/com/android/commands/hid/Hid.java
+++ b/cmds/hid/src/com/android/commands/hid/Hid.java
@@ -113,7 +113,7 @@ public class Hid {
"Tried to send command \"" + e.getCommand() + "\" to an unregistered device!");
}
int id = e.getId();
- Device d = new Device(id, e.getName(), e.getVendorId(), e.getProductId(),
+ Device d = new Device(id, e.getName(), e.getVendorId(), e.getProductId(), e.getBus(),
e.getDescriptor(), e.getReport(), e.getFeatureReports(), e.getOutputs());
mDevices.append(id, d);
}
diff --git a/cmds/statsd/Android.bp b/cmds/statsd/Android.bp
index 93522d4ff0a6..73a8f666b78e 100644
--- a/cmds/statsd/Android.bp
+++ b/cmds/statsd/Android.bp
@@ -217,7 +217,10 @@ cc_binary {
shared_libs: ["libgtest_prod"],
- init_rc: ["statsd.rc"],
+ apex_available: [
+ "com.android.os.statsd",
+ "test_com.android.os.statsd",
+ ],
}
// ==============
@@ -299,6 +302,11 @@ cc_test {
static_libs: [
"libgmock",
"libplatformprotos",
+
+ // TODO(b/149842105): Make libstatssocket shared and remove libcutils once statsd_test is
+ // moved to the apex.
+ "libstatssocket",
+ "libcutils",
],
proto: {
@@ -308,7 +316,6 @@ cc_test {
shared_libs: [
"libprotobuf-cpp-lite",
- "libstatssocket"
],
}
diff --git a/cmds/statsd/src/atoms.proto b/cmds/statsd/src/atoms.proto
index a4e8fdc10a3b..43d0fce316ad 100644
--- a/cmds/statsd/src/atoms.proto
+++ b/cmds/statsd/src/atoms.proto
@@ -392,6 +392,7 @@ message Atom {
WifiFailureStatReported wifi_failure_stat_reported = 252 [(module) = "wifi"];
WifiConnectionResultReported wifi_connection_result_reported = 253 [(module) = "wifi"];
AppFreezeChanged app_freeze_changed = 254 [(module) = "framework"];
+ SnapshotMergeReported snapshot_merge_reported = 255;
SdkExtensionStatus sdk_extension_status = 354;
}
@@ -4418,6 +4419,52 @@ message BootTimeEventErrorCode {
optional int32 error_code = 2;
}
+/**
+ * Collects Virtual A/B statistics related to the use of dm-snapshot performed
+ * after an OTA.
+ *
+ * Logged from:
+ * - system/core/fs_mgr/libsnapshot/snapshot.cpp
+ * - system/core/fs_mgr/libsnapshot/snapshotctl.cpp
+ */
+message SnapshotMergeReported {
+ // Keep in sync with
+ // system/core/fs_mgr/libsnapshot/android/snapshot/snapshot.proto
+ enum UpdateState {
+ // No update or merge is in progress.
+ NONE = 0;
+ // An update is applying; snapshots may already exist.
+ INITIATED = 1;
+ // An update is pending, but has not been successfully booted yet.
+ UNVERIFIED = 2;
+ // The kernel is merging in the background.
+ MERGING = 3;
+ // Post-merge cleanup steps could not be completed due to a transient
+ // error, but the next reboot will finish any pending operations.
+ MERGE_NEEDS_REBOOT = 4;
+ // Merging is complete, and needs to be acknowledged.
+ MERGE_COMPLETED = 5;
+ // Merging failed due to an unrecoverable error.
+ MERGE_FAILED = 6;
+ // The update was implicitly cancelled, either by a rollback or a flash
+ // operation via fastboot. This state can only be returned by WaitForMerge.
+ CANCELLED = 7;
+ };
+
+ // Status of the update after the merge attempts.
+ optional UpdateState final_state = 1;
+
+ // Time to complete a merge operation in milliseconds.
+ // A negative value corresponds to the case in which the merge operation
+ // was interrupted and resumed (e.g. in case of a system reboot during the
+ // merge).
+ optional int64 duration_millis = 2;
+
+ // Number of reboots that occurred after issuing and before completing the
+ // merge of all the snapshot devices.
+ optional int32 intermediate_reboots = 3;
+}
+
//////////////////////////////////////////////////////////////////////
// Pulled atoms below this line //
//////////////////////////////////////////////////////////////////////
diff --git a/core/java/android/accessibilityservice/OWNERS b/core/java/android/accessibilityservice/OWNERS
index 265674a74b7e..c6f42f719caa 100644
--- a/core/java/android/accessibilityservice/OWNERS
+++ b/core/java/android/accessibilityservice/OWNERS
@@ -1,3 +1,4 @@
svetoslavganov@google.com
pweaver@google.com
rhedjao@google.com
+qasid@google.com
diff --git a/core/java/android/app/ContextImpl.java b/core/java/android/app/ContextImpl.java
index 6b5bfda92cd0..8df26cbbb4f4 100644
--- a/core/java/android/app/ContextImpl.java
+++ b/core/java/android/app/ContextImpl.java
@@ -16,6 +16,9 @@
package android.app;
+import static android.content.pm.PackageManager.PERMISSION_GRANTED;
+import static android.os.StrictMode.vmIncorrectContextUseEnabled;
+
import android.annotation.IntDef;
import android.annotation.NonNull;
import android.annotation.Nullable;
@@ -64,6 +67,7 @@ import android.os.IBinder;
import android.os.Looper;
import android.os.Process;
import android.os.RemoteException;
+import android.os.StrictMode;
import android.os.Trace;
import android.os.UserHandle;
import android.os.UserManager;
@@ -247,6 +251,7 @@ class ContextImpl extends Context {
private boolean mIsSystemOrSystemUiContext;
private boolean mIsUiContext;
+ private boolean mIsAssociatedWithDisplay;
@GuardedBy("mSync")
private File mDatabasesDir;
@@ -1891,9 +1896,20 @@ class ContextImpl extends Context {
@Override
public Object getSystemService(String name) {
- if (isUiComponent(name) && !isUiContext()) {
- Log.w(TAG, name + " should be accessed from Activity or other visual Context");
+ // Check incorrect Context usage.
+ if (isUiComponent(name) && !isUiContext() && vmIncorrectContextUseEnabled()) {
+ final String errorMessage = "Tried to access visual service " + name
+ + " from a non-visual Context.";
+ final String message = "Visual services, such as WindowManager, WallpaperService or "
+ + "LayoutInflater should be accessed from Activity or other visual Context. "
+ + "Use an Activity or a Context created with "
+ + "Context#createWindowContext(int, Bundle), which are adjusted to the "
+ + "configuration and visual bounds of an area on screen.";
+ final Exception exception = new IllegalAccessException(errorMessage);
+ StrictMode.onIncorrectContextUsed(message, exception);
+ Log.e(TAG, errorMessage + message, exception);
}
+
return SystemServiceRegistry.getSystemService(this, name);
}
@@ -1902,8 +1918,17 @@ class ContextImpl extends Context {
return SystemServiceRegistry.getSystemServiceName(serviceClass);
}
- boolean isUiContext() {
- return mIsSystemOrSystemUiContext || mIsUiContext;
+ private boolean isUiContext() {
+ return mIsSystemOrSystemUiContext || mIsUiContext || isSystemOrSystemUI();
+ }
+
+ /**
+ * Temporary workaround to permit incorrect usages of Context by SystemUI.
+ * TODO(b/149790106): Fix usages and remove.
+ */
+ private boolean isSystemOrSystemUI() {
+ return ActivityThread.isSystem() || checkPermission("android.permission.STATUS_BAR_SERVICE",
+ Binder.getCallingPid(), Binder.getCallingUid()) == PERMISSION_GRANTED;
}
private static boolean isUiComponent(String name) {
@@ -1925,7 +1950,7 @@ class ContextImpl extends Context {
final int appId = UserHandle.getAppId(uid);
if (appId == Process.ROOT_UID || appId == Process.SYSTEM_UID) {
Slog.w(TAG, "Missing ActivityManager; assuming " + uid + " holds " + permission);
- return PackageManager.PERMISSION_GRANTED;
+ return PERMISSION_GRANTED;
}
Slog.w(TAG, "Missing ActivityManager; assuming " + uid + " does not hold "
+ permission);
@@ -1989,7 +2014,7 @@ class ContextImpl extends Context {
private void enforce(
String permission, int resultOfCheck,
boolean selfToo, int uid, String message) {
- if (resultOfCheck != PackageManager.PERMISSION_GRANTED) {
+ if (resultOfCheck != PERMISSION_GRANTED) {
throw new SecurityException(
(message != null ? (message + ": ") : "") +
(selfToo
@@ -2116,15 +2141,15 @@ class ContextImpl extends Context {
if ((modeFlags&Intent.FLAG_GRANT_READ_URI_PERMISSION) != 0) {
if (readPermission == null
|| checkPermission(readPermission, pid, uid)
- == PackageManager.PERMISSION_GRANTED) {
- return PackageManager.PERMISSION_GRANTED;
+ == PERMISSION_GRANTED) {
+ return PERMISSION_GRANTED;
}
}
if ((modeFlags&Intent.FLAG_GRANT_WRITE_URI_PERMISSION) != 0) {
if (writePermission == null
|| checkPermission(writePermission, pid, uid)
- == PackageManager.PERMISSION_GRANTED) {
- return PackageManager.PERMISSION_GRANTED;
+ == PERMISSION_GRANTED) {
+ return PERMISSION_GRANTED;
}
}
return uri != null ? checkUriPermission(uri, pid, uid, modeFlags)
@@ -2157,7 +2182,7 @@ class ContextImpl extends Context {
private void enforceForUri(
int modeFlags, int resultOfCheck, boolean selfToo,
int uid, Uri uri, String message) {
- if (resultOfCheck != PackageManager.PERMISSION_GRANTED) {
+ if (resultOfCheck != PERMISSION_GRANTED) {
throw new SecurityException(
(message != null ? (message + ": ") : "") +
(selfToo
@@ -2373,6 +2398,7 @@ class ContextImpl extends Context {
null, getDisplayAdjustments(displayId).getCompatibilityInfo(),
mResources.getLoaders()));
context.mDisplay = display;
+ context.mIsAssociatedWithDisplay = true;
return context;
}
@@ -2390,6 +2416,7 @@ class ContextImpl extends Context {
ContextImpl context = new ContextImpl(this, mMainThread, mPackageInfo, mFeatureId,
mSplitName, token, mUser, mFlags, mClassLoader, null);
context.mIsUiContext = true;
+ context.mIsAssociatedWithDisplay = true;
return context;
}
@@ -2440,6 +2467,19 @@ class ContextImpl extends Context {
@Override
public Display getDisplay() {
+ if (!mIsSystemOrSystemUiContext && !mIsAssociatedWithDisplay && !isSystemOrSystemUI()) {
+ throw new UnsupportedOperationException("Tried to obtain display from a Context not "
+ + "associated with one. Only visual Contexts (such as Activity or one created "
+ + "with Context#createWindowContext) or ones created with "
+ + "Context#createDisplayContext are associated with displays. Other types of "
+ + "Contexts are typically related to background entities and may return an "
+ + "arbitrary display.");
+ }
+ return getDisplayNoVerify();
+ }
+
+ @Override
+ public Display getDisplayNoVerify() {
if (mDisplay == null) {
return mResourcesManager.getAdjustedDisplay(Display.DEFAULT_DISPLAY,
mResources);
@@ -2450,13 +2490,14 @@ class ContextImpl extends Context {
@Override
public int getDisplayId() {
- final Display display = getDisplay();
+ final Display display = getDisplayNoVerify();
return display != null ? display.getDisplayId() : Display.DEFAULT_DISPLAY;
}
@Override
public void updateDisplay(int displayId) {
mDisplay = mResourcesManager.getAdjustedDisplay(displayId, mResources);
+ mIsAssociatedWithDisplay = true;
}
@Override
@@ -2630,6 +2671,7 @@ class ContextImpl extends Context {
ContextImpl context = new ContextImpl(null, mainThread, packageInfo, null,
activityInfo.splitName, activityToken, null, 0, classLoader, null);
context.mIsUiContext = true;
+ context.mIsAssociatedWithDisplay = true;
// Clamp display ID to DEFAULT_DISPLAY if it is INVALID_DISPLAY.
displayId = (displayId != Display.INVALID_DISPLAY) ? displayId : Display.DEFAULT_DISPLAY;
diff --git a/core/java/android/app/TaskEmbedder.java b/core/java/android/app/TaskEmbedder.java
index 761b225a7cdc..5ebcc46aa0d8 100644
--- a/core/java/android/app/TaskEmbedder.java
+++ b/core/java/android/app/TaskEmbedder.java
@@ -597,7 +597,7 @@ public class TaskEmbedder {
if (mTmpDisplayMetrics == null) {
mTmpDisplayMetrics = new DisplayMetrics();
}
- mContext.getDisplay().getMetrics(mTmpDisplayMetrics);
+ mContext.getDisplayNoVerify().getRealMetrics(mTmpDisplayMetrics);
return mTmpDisplayMetrics.densityDpi;
}
diff --git a/core/java/android/app/WallpaperManager.java b/core/java/android/app/WallpaperManager.java
index 5f74d2e1dd57..d9405e18a162 100644
--- a/core/java/android/app/WallpaperManager.java
+++ b/core/java/android/app/WallpaperManager.java
@@ -2097,7 +2097,7 @@ public class WallpaperManager {
public ColorManagementProxy(@NonNull Context context) {
// Get a list of supported wide gamut color spaces.
- Display display = context.getDisplay();
+ Display display = context.getDisplayNoVerify();
if (display != null) {
mSupportedColorSpaces.addAll(Arrays.asList(display.getSupportedWideColorGamut()));
}
diff --git a/core/java/android/app/admin/DevicePolicyManager.java b/core/java/android/app/admin/DevicePolicyManager.java
index 139b1796d8fc..55be08232e41 100644
--- a/core/java/android/app/admin/DevicePolicyManager.java
+++ b/core/java/android/app/admin/DevicePolicyManager.java
@@ -33,6 +33,7 @@ import android.annotation.SuppressLint;
import android.annotation.SystemApi;
import android.annotation.SystemService;
import android.annotation.TestApi;
+import android.annotation.UserHandleAware;
import android.annotation.UserIdInt;
import android.annotation.WorkerThread;
import android.app.Activity;
@@ -5740,6 +5741,25 @@ public class DevicePolicyManager {
}
/**
+ * Returns whether the admin has enabled always-on VPN lockdown for the current user.
+ *
+ * Only callable by the system.
+ * @hide
+ */
+ @UserHandleAware
+ public boolean isAlwaysOnVpnLockdownEnabled() {
+ throwIfParentInstance("isAlwaysOnVpnLockdownEnabled");
+ if (mService != null) {
+ try {
+ return mService.isAlwaysOnVpnLockdownEnabledForUser(myUserId());
+ } catch (RemoteException e) {
+ throw e.rethrowFromSystemServer();
+ }
+ }
+ return false;
+ }
+
+ /**
* Called by device or profile owner to query the set of packages that are allowed to access
* the network directly when always-on VPN is in lockdown mode but not connected. Returns
* {@code null} when always-on VPN is not active or not in lockdown mode.
@@ -5786,6 +5806,26 @@ public class DevicePolicyManager {
}
/**
+ * Returns the VPN package name if the admin has enabled always-on VPN on the current user,
+ * or {@code null} if none is set.
+ *
+ * Only callable by the system.
+ * @hide
+ */
+ @UserHandleAware
+ public @Nullable String getAlwaysOnVpnPackage() {
+ throwIfParentInstance("getAlwaysOnVpnPackage");
+ if (mService != null) {
+ try {
+ return mService.getAlwaysOnVpnPackageForUser(myUserId());
+ } catch (RemoteException e) {
+ throw e.rethrowFromSystemServer();
+ }
+ }
+ return null;
+ }
+
+ /**
* Called by an application that is administering the device to disable all cameras on the
* device, for this user. After setting this, no applications running as this user will be able
* to access any cameras on the device.
@@ -8949,49 +8989,6 @@ public class DevicePolicyManager {
}
/**
- * Called by device owners to request a location provider to change its allowed state. For a
- * provider to be enabled requires both that the master location setting is enabled, and that
- * the provider itself is allowed. Most location providers are always allowed. Some location
- * providers may have user consents or terms and conditions that must be accepted, or some other
- * type of blocker before they are allowed however. Every location provider is responsible for
- * its own allowed state.
- *
- * <p>This method requests that a location provider change its allowed state. For providers that
- * are always allowed and have no state to change, this will have no effect. If the provider
- * does require some consent, terms and conditions, or other blocking state, using this API
- * implies that the device owner is agreeing/disagreeing to any consents, terms and conditions,
- * etc, and the provider should make a best effort to adjust it's allowed state accordingly.
- *
- * <p>Location providers are generally only responsible for the current user, and callers must
- * assume that this method will only affect provider state for the current user. Callers are
- * responsible for tracking current user changes and re-updating provider state as necessary.
- *
- * <p>While providers are expected to make a best effort to honor this request, it is not a
- * given that all providers will support such a request. If a provider does change its state as
- * a result of this request, that may happen asynchronously after some delay. Test location
- * providers set through {@link android.location.LocationManager#addTestProvider} will respond
- * to this request to aide in testing.
- *
- * @param admin Which {@link DeviceAdminReceiver} this request is associated with
- * @param provider A location provider as listed by
- * {@link android.location.LocationManager#getAllProviders()}
- * @param providerAllowed Whether the location provider is being requested to enable or disable
- * itself
- * @throws SecurityException if {@code admin} is not a device owner.
- */
- public void requestSetLocationProviderAllowed(@NonNull ComponentName admin,
- @NonNull String provider, boolean providerAllowed) {
- throwIfParentInstance("requestSetLocationProviderAllowed");
- if (mService != null) {
- try {
- mService.requestSetLocationProviderAllowed(admin, provider, providerAllowed);
- } catch (RemoteException e) {
- throw e.rethrowFromSystemServer();
- }
- }
- }
-
- /**
* Called by profile or device owners to update {@link android.provider.Settings.Secure}
* settings. Validation that the value of the setting is in the correct form for the setting
* type should be performed by the caller.
diff --git a/core/java/android/app/admin/IDevicePolicyManager.aidl b/core/java/android/app/admin/IDevicePolicyManager.aidl
index 25c1e1205d2e..da48663145e1 100644
--- a/core/java/android/app/admin/IDevicePolicyManager.aidl
+++ b/core/java/android/app/admin/IDevicePolicyManager.aidl
@@ -196,7 +196,9 @@ interface IDevicePolicyManager {
boolean setAlwaysOnVpnPackage(in ComponentName who, String vpnPackage, boolean lockdown, in List<String> lockdownWhitelist);
String getAlwaysOnVpnPackage(in ComponentName who);
+ String getAlwaysOnVpnPackageForUser(int userHandle);
boolean isAlwaysOnVpnLockdownEnabled(in ComponentName who);
+ boolean isAlwaysOnVpnLockdownEnabledForUser(int userHandle);
List<String> getAlwaysOnVpnLockdownWhitelist(in ComponentName who);
void addPersistentPreferredActivity(in ComponentName admin, in IntentFilter filter, in ComponentName activity);
@@ -270,7 +272,6 @@ interface IDevicePolicyManager {
boolean hasLockdownAdminConfiguredNetworks(in ComponentName who);
void setLocationEnabled(in ComponentName who, boolean locationEnabled);
- void requestSetLocationProviderAllowed(in ComponentName who, in String provider, boolean providerAllowed);
boolean setTime(in ComponentName who, long millis);
boolean setTimeZone(in ComponentName who, String timeZone);
diff --git a/core/java/android/content/ContentProvider.java b/core/java/android/content/ContentProvider.java
index e1942da8ac7f..bd3298c79fff 100644
--- a/core/java/android/content/ContentProvider.java
+++ b/core/java/android/content/ContentProvider.java
@@ -580,6 +580,15 @@ public abstract class ContentProvider implements ContentInterface, ComponentCall
}
@Override
+ public void canonicalizeAsync(String callingPkg, @Nullable String featureId, Uri uri,
+ RemoteCallback callback) {
+ final Bundle result = new Bundle();
+ result.putParcelable(ContentResolver.REMOTE_CALLBACK_RESULT,
+ canonicalize(callingPkg, featureId, uri));
+ callback.sendResult(result);
+ }
+
+ @Override
public Uri uncanonicalize(String callingPkg, String featureId, Uri uri) {
uri = validateIncomingUri(uri);
int userId = getUserIdFromUri(uri);
diff --git a/core/java/android/content/ContentProviderNative.java b/core/java/android/content/ContentProviderNative.java
index 0f1442d864ba..7bc59013bcfe 100644
--- a/core/java/android/content/ContentProviderNative.java
+++ b/core/java/android/content/ContentProviderNative.java
@@ -359,6 +359,16 @@ abstract public class ContentProviderNative extends Binder implements IContentPr
return true;
}
+ case CANONICALIZE_ASYNC_TRANSACTION: {
+ data.enforceInterface(IContentProvider.descriptor);
+ String callingPkg = data.readString();
+ String featureId = data.readString();
+ Uri uri = Uri.CREATOR.createFromParcel(data);
+ RemoteCallback callback = RemoteCallback.CREATOR.createFromParcel(data);
+ canonicalizeAsync(callingPkg, featureId, uri, callback);
+ return true;
+ }
+
case UNCANONICALIZE_TRANSACTION:
{
data.enforceInterface(IContentProvider.descriptor);
@@ -823,6 +833,25 @@ final class ContentProviderProxy implements IContentProvider
}
@Override
+ /* oneway */ public void canonicalizeAsync(String callingPkg, @Nullable String featureId,
+ Uri uri, RemoteCallback callback) throws RemoteException {
+ Parcel data = Parcel.obtain();
+ try {
+ data.writeInterfaceToken(IContentProvider.descriptor);
+
+ data.writeString(callingPkg);
+ data.writeString(featureId);
+ uri.writeToParcel(data, 0);
+ callback.writeToParcel(data, 0);
+
+ mRemote.transact(IContentProvider.CANONICALIZE_ASYNC_TRANSACTION, data, null,
+ Binder.FLAG_ONEWAY);
+ } finally {
+ data.recycle();
+ }
+ }
+
+ @Override
public Uri uncanonicalize(String callingPkg, @Nullable String featureId, Uri url)
throws RemoteException {
Parcel data = Parcel.obtain();
diff --git a/core/java/android/content/ContentResolver.java b/core/java/android/content/ContentResolver.java
index 0e0161ff4e9f..b748cfa775ed 100644
--- a/core/java/android/content/ContentResolver.java
+++ b/core/java/android/content/ContentResolver.java
@@ -712,14 +712,17 @@ public abstract class ContentResolver implements ContentInterface {
* {@link #CONTENT_PROVIDER_PUBLISH_TIMEOUT_MILLIS}.
* @hide
*/
- public static final int CONTENT_PROVIDER_WAIT_TIMEOUT_MILLIS =
+ public static final int CONTENT_PROVIDER_READY_TIMEOUT_MILLIS =
CONTENT_PROVIDER_PUBLISH_TIMEOUT_MILLIS + 10 * 1000;
+ // Timeout given a ContentProvider that has already been started and connected to.
+ private static final int CONTENT_PROVIDER_TIMEOUT_MILLIS = 3 * 1000;
+
// Should be >= {@link #CONTENT_PROVIDER_WAIT_TIMEOUT_MILLIS}, because that's how
// long ActivityManagerService is giving a content provider to get published if a new process
// needs to be started for that.
- private static final int GET_TYPE_TIMEOUT_MILLIS =
- CONTENT_PROVIDER_WAIT_TIMEOUT_MILLIS + 5 * 1000;
+ private static final int REMOTE_CONTENT_PROVIDER_TIMEOUT_MILLIS =
+ CONTENT_PROVIDER_READY_TIMEOUT_MILLIS + CONTENT_PROVIDER_TIMEOUT_MILLIS;
public ContentResolver(@Nullable Context context) {
this(context, null);
@@ -833,10 +836,10 @@ public abstract class ContentResolver implements ContentInterface {
IContentProvider provider = acquireExistingProvider(url);
if (provider != null) {
try {
- final GetTypeResultListener resultListener = new GetTypeResultListener();
+ final StringResultListener resultListener = new StringResultListener();
provider.getTypeAsync(url, new RemoteCallback(resultListener));
- resultListener.waitForResult();
- return resultListener.type;
+ resultListener.waitForResult(CONTENT_PROVIDER_TIMEOUT_MILLIS);
+ return resultListener.result;
} catch (RemoteException e) {
// Arbitrary and not worth documenting, as Activity
// Manager will kill this process shortly anyway.
@@ -854,13 +857,13 @@ public abstract class ContentResolver implements ContentInterface {
}
try {
- GetTypeResultListener resultListener = new GetTypeResultListener();
+ final StringResultListener resultListener = new StringResultListener();
ActivityManager.getService().getProviderMimeTypeAsync(
ContentProvider.getUriWithoutUserId(url),
resolveUserId(url),
new RemoteCallback(resultListener));
- resultListener.waitForResult();
- return resultListener.type;
+ resultListener.waitForResult(REMOTE_CONTENT_PROVIDER_TIMEOUT_MILLIS);
+ return resultListener.result;
} catch (RemoteException e) {
// We just failed to send a oneway request to the System Server. Nothing to do.
return null;
@@ -870,27 +873,29 @@ public abstract class ContentResolver implements ContentInterface {
}
}
- private static class GetTypeResultListener implements RemoteCallback.OnResultListener {
+ private abstract static class ResultListener<T> implements RemoteCallback.OnResultListener {
@GuardedBy("this")
public boolean done;
@GuardedBy("this")
- public String type;
+ public T result;
@Override
public void onResult(Bundle result) {
synchronized (this) {
- type = result.getString(REMOTE_CALLBACK_RESULT);
+ this.result = getResultFromBundle(result);
done = true;
notifyAll();
}
}
- public void waitForResult() {
+ protected abstract T getResultFromBundle(Bundle result);
+
+ public void waitForResult(long timeout) {
synchronized (this) {
if (!done) {
try {
- wait(GET_TYPE_TIMEOUT_MILLIS);
+ wait(timeout);
} catch (InterruptedException e) {
// Ignore
}
@@ -899,6 +904,20 @@ public abstract class ContentResolver implements ContentInterface {
}
}
+ private static class StringResultListener extends ResultListener<String> {
+ @Override
+ protected String getResultFromBundle(Bundle result) {
+ return result.getString(REMOTE_CALLBACK_RESULT);
+ }
+ }
+
+ private static class UriResultListener extends ResultListener<Uri> {
+ @Override
+ protected Uri getResultFromBundle(Bundle result) {
+ return result.getParcelable(REMOTE_CALLBACK_RESULT);
+ }
+ }
+
/**
* Query for the possible MIME types for the representations the given
* content URL can be returned when opened as as stream with
@@ -1192,7 +1211,11 @@ public abstract class ContentResolver implements ContentInterface {
}
try {
- return provider.canonicalize(mPackageName, mFeatureId, url);
+ final UriResultListener resultListener = new UriResultListener();
+ provider.canonicalizeAsync(mPackageName, mFeatureId, url,
+ new RemoteCallback(resultListener));
+ resultListener.waitForResult(CONTENT_PROVIDER_TIMEOUT_MILLIS);
+ return resultListener.result;
} catch (RemoteException e) {
// Arbitrary and not worth documenting, as Activity
// Manager will kill this process shortly anyway.
diff --git a/core/java/android/content/Context.java b/core/java/android/content/Context.java
index ae12de027e6e..c6e84b7e46b0 100644
--- a/core/java/android/content/Context.java
+++ b/core/java/android/content/Context.java
@@ -3495,13 +3495,23 @@ public abstract class Context {
* <dl>
* <dt> {@link #WINDOW_SERVICE} ("window")
* <dd> The top-level window manager in which you can place custom
- * windows. The returned object is a {@link android.view.WindowManager}.
+ * windows. The returned object is a {@link android.view.WindowManager}. Must only be obtained
+ * from a visual context such as Activity or a Context created with
+ * {@link #createWindowContext(int, Bundle)}, which are adjusted to the configuration and
+ * visual bounds of an area on screen.
* <dt> {@link #LAYOUT_INFLATER_SERVICE} ("layout_inflater")
* <dd> A {@link android.view.LayoutInflater} for inflating layout resources
- * in this context.
+ * in this context. Must only be obtained from a visual context such as Activity or a Context
+ * created with {@link #createWindowContext(int, Bundle)}, which are adjusted to the
+ * configuration and visual bounds of an area on screen.
* <dt> {@link #ACTIVITY_SERVICE} ("activity")
* <dd> A {@link android.app.ActivityManager} for interacting with the
* global activity state of the system.
+ * <dt> {@link #WALLPAPER_SERVICE} ("wallpaper")
+ * <dd> A {@link android.service.wallpaper.WallpaperService} for accessing wallpapers in this
+ * context. Must only be obtained from a visual context such as Activity or a Context created
+ * with {@link #createWindowContext(int, Bundle)}, which are adjusted to the configuration and
+ * visual bounds of an area on screen.
* <dt> {@link #POWER_SERVICE} ("power")
* <dd> A {@link android.os.PowerManager} for controlling power
* management.
@@ -5901,6 +5911,8 @@ public abstract class Context {
* {@link #createDisplayContext(Display)} to get a display object associated with a Context, or
* {@link android.hardware.display.DisplayManager#getDisplay} to get a display object by id.
* @return Returns the {@link Display} object this context is associated with.
+ * @throws UnsupportedOperationException if the method is called on an instance that is not
+ * associated with any display.
*/
@Nullable
public Display getDisplay() {
@@ -5908,6 +5920,17 @@ public abstract class Context {
}
/**
+ * A version of {@link #getDisplay()} that does not perform a Context misuse check to be used by
+ * legacy APIs.
+ * TODO(b/149790106): Fix usages and remove.
+ * @hide
+ */
+ @Nullable
+ public Display getDisplayNoVerify() {
+ throw new RuntimeException("Not implemented. Must override in a subclass.");
+ }
+
+ /**
* Gets the ID of the display this context is associated with.
*
* @return display ID associated with this {@link Context}.
diff --git a/core/java/android/content/ContextWrapper.java b/core/java/android/content/ContextWrapper.java
index f6515e806caa..e5381ea0dd41 100644
--- a/core/java/android/content/ContextWrapper.java
+++ b/core/java/android/content/ContextWrapper.java
@@ -1003,6 +1003,12 @@ public class ContextWrapper extends Context {
return mBase.getDisplay();
}
+ /** @hide */
+ @Override
+ public @Nullable Display getDisplayNoVerify() {
+ return mBase.getDisplayNoVerify();
+ }
+
/**
* @hide
*/
diff --git a/core/java/android/content/IContentProvider.java b/core/java/android/content/IContentProvider.java
index 4658ba109d5f..37643da375df 100644
--- a/core/java/android/content/IContentProvider.java
+++ b/core/java/android/content/IContentProvider.java
@@ -45,7 +45,7 @@ public interface IContentProvider extends IInterface {
public String getType(Uri url) throws RemoteException;
/**
- * An oneway version of getType. The functionality is exactly the same, except that the
+ * A oneway version of getType. The functionality is exactly the same, except that the
* call returns immediately, and the resulting type is returned when available via
* a binder callback.
*/
@@ -126,6 +126,14 @@ public interface IContentProvider extends IInterface {
public Uri canonicalize(String callingPkg, @Nullable String featureId, Uri uri)
throws RemoteException;
+ /**
+ * A oneway version of canonicalize. The functionality is exactly the same, except that the
+ * call returns immediately, and the resulting type is returned when available via
+ * a binder callback.
+ */
+ void canonicalizeAsync(String callingPkg, @Nullable String featureId, Uri uri,
+ RemoteCallback callback) throws RemoteException;
+
public Uri uncanonicalize(String callingPkg, @Nullable String featureId, Uri uri)
throws RemoteException;
@@ -162,4 +170,5 @@ public interface IContentProvider extends IInterface {
static final int REFRESH_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION + 26;
static final int CHECK_URI_PERMISSION_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION + 27;
int GET_TYPE_ASYNC_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION + 28;
+ int CANONICALIZE_ASYNC_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION + 29;
}
diff --git a/core/java/android/content/pm/IShortcutService.aidl b/core/java/android/content/pm/IShortcutService.aidl
index 9e85fc301a0c..29a55b7a74da 100644
--- a/core/java/android/content/pm/IShortcutService.aidl
+++ b/core/java/android/content/pm/IShortcutService.aidl
@@ -76,4 +76,6 @@ interface IShortcutService {
void removeLongLivedShortcuts(String packageName, in List shortcutIds, int userId);
ParceledListSlice getShortcuts(String packageName, int matchFlags, int userId);
+
+ void pushDynamicShortcut(String packageName, in ShortcutInfo shortcut, int userId);
} \ No newline at end of file
diff --git a/core/java/android/content/pm/ResolveInfo.java b/core/java/android/content/pm/ResolveInfo.java
index 55846adf2f1f..82b07f24a906 100644
--- a/core/java/android/content/pm/ResolveInfo.java
+++ b/core/java/android/content/pm/ResolveInfo.java
@@ -39,6 +39,8 @@ import java.util.Comparator;
*/
public class ResolveInfo implements Parcelable {
private static final String TAG = "ResolveInfo";
+ private static final String INTENT_FORWARDER_ACTIVITY =
+ "com.android.internal.app.IntentForwarderActivity";
/**
* The activity or broadcast receiver that corresponds to this resolution
@@ -351,6 +353,16 @@ public class ResolveInfo implements Parcelable {
}
}
+ /**
+ * Returns whether this resolution represents the intent forwarder activity.
+ *
+ * @return whether this resolution represents the intent forwarder activity
+ */
+ public boolean isCrossProfileIntentForwarderActivity() {
+ return activityInfo != null
+ && INTENT_FORWARDER_ACTIVITY.equals(activityInfo.targetActivity);
+ }
+
public ResolveInfo() {
targetUserId = UserHandle.USER_CURRENT;
}
diff --git a/core/java/android/content/pm/ShortcutInfo.java b/core/java/android/content/pm/ShortcutInfo.java
index bde4f614a39e..49e8c052cbca 100644
--- a/core/java/android/content/pm/ShortcutInfo.java
+++ b/core/java/android/content/pm/ShortcutInfo.java
@@ -1726,11 +1726,11 @@ public final class ShortcutInfo implements Parcelable {
}
/**
- * @return true if pinned but neither static nor dynamic.
+ * @return true if pinned or cached, but neither static nor dynamic.
* @hide
*/
public boolean isFloating() {
- return isPinned() && !(isDynamic() || isManifestShortcut());
+ return (isPinned() || isCached()) && !(isDynamic() || isManifestShortcut());
}
/** @hide */
diff --git a/core/java/android/content/pm/ShortcutManager.java b/core/java/android/content/pm/ShortcutManager.java
index 3eea3f62fd46..35c99a13a152 100644
--- a/core/java/android/content/pm/ShortcutManager.java
+++ b/core/java/android/content/pm/ShortcutManager.java
@@ -24,6 +24,7 @@ import android.annotation.SystemApi;
import android.annotation.SystemService;
import android.annotation.TestApi;
import android.annotation.UserIdInt;
+import android.app.Notification;
import android.app.usage.UsageStatsManager;
import android.compat.annotation.UnsupportedAppUsage;
import android.content.ComponentName;
@@ -741,4 +742,33 @@ public class ShortcutManager {
throw e.rethrowFromSystemServer();
}
}
+
+ /**
+ * Publish a single dynamic shortcut. If there are already dynamic or pinned shortcuts with the
+ * same ID, each mutable shortcut is updated.
+ *
+ * <p>This method is useful when posting notifications which are tagged with shortcut IDs; In
+ * order to make sure shortcuts exist and are up-to-date, without the need to explicitly handle
+ * the shortcut count limit.
+ * @see android.app.NotificationManager#notify(int, Notification)
+ * @see Notification.Builder#setShortcutId(String)
+ *
+ * <p>If {@link #getMaxShortcutCountPerActivity()} is already reached, an existing shortcut with
+ * the lowest rank will be removed to add space for the new shortcut.
+ *
+ * <p>If the rank of the shortcut is not explicitly set, it will be set to zero, and shortcut
+ * will be added to the top of the list.
+ *
+ * @throws IllegalArgumentException if trying to update an immutable shortcut.
+ *
+ * @throws IllegalStateException when the user is locked.
+ */
+ public void pushDynamicShortcut(@NonNull ShortcutInfo shortcut) {
+ try {
+ mService.pushDynamicShortcut(mContext.getPackageName(), shortcut, injectMyUserId());
+ } catch (RemoteException e) {
+ throw e.rethrowFromSystemServer();
+ }
+ }
+
}
diff --git a/core/java/android/hardware/camera2/CameraDevice.java b/core/java/android/hardware/camera2/CameraDevice.java
index 24d931154533..cc0c1a309038 100644
--- a/core/java/android/hardware/camera2/CameraDevice.java
+++ b/core/java/android/hardware/camera2/CameraDevice.java
@@ -688,17 +688,19 @@ public abstract class CameraDevice implements AutoCloseable {
* <tr><th colspan="5">Concurrent stream guaranteed configurations</th></tr>
* <tr><th colspan="2" id="rb">Target 1</th><th colspan="2" id="rb">Target 2</th><th rowspan="2">Sample use case(s)</th> </tr>
* <tr><th>Type</th><th id="rb">Max size</th><th>Type</th><th id="rb">Max size</th> </tr>
- * <tr> <td>{@code YUV}</td><td id="rb">{@code MAXIMUM}</td> <td colspan="2" id="rb"></td> <td>In-app video / image processing.</td> </tr>
- * <tr> <td>{@code PRIV}</td><td id="rb">{@code MAXIMUM}</td> <td colspan="2" id="rb"></td> <td>In-app viewfinder analysis.</td> </tr>
- * <tr> <td>{@code YUV}</td><td id="rb">{@code MAXIMUM}</td> <td>{@code YUV }</td><td id="rb">{@code MAXIMUM}</td> <td>In-app video / processing with preview.</td> </tr>
- * <tr> <td>{@code YUV}</td><td id="rb">{@code MAXIMUM}</td> <td>{@code PRIV }</td><td id="rb">{@code MAXIMUM}</td> <td>In-app video / processing with preview.</td> </tr>
- * <tr> <td>{@code PRIV}</td><td id="rb">{@code MAXIMUM}</td> <td>{@code PRIV }</td><td id="rb">{@code MAXIMUM}</td> <td>Standard Recording.</td> </tr>
+ * <tr> <td>{@code YUV}</td><td id="rb">{@code s1440p}</td> <td colspan="2" id="rb"></td> <td>In-app video / image processing.</td> </tr>
+ * <tr> <td>{@code PRIV}</td><td id="rb">{@code s1440p}</td> <td colspan="2" id="rb"></td> <td>In-app viewfinder analysis.</td> </tr>
+ * <tr> <td>{@code JPEG}</td><td id="rb">{@code s1440p}</td> <td colspan="2" id="rb"></td> <td>No viewfinder still image capture.</td> </tr>
+ * <tr> <td>{@code YUV / PRIV}</td><td id="rb">{@code s720p}</td> <td>{@code JPEG}</td><td id="rb">{@code s1440p}</td> <td> Standard still imaging.</td> </tr>
+ * <tr> <td>{@code YUV / PRIV}</td><td id="rb">{@code s720p}</td> <td>{@code YUV / PRIV }</td><td id="rb">{@code s1440p}</td> <td>In-app video / processing with preview.</td> </tr>
* </table><br>
* </p>
*
- * <p> For guaranteed concurrent stream configurations, MAXIMUM refers to the camera device's
- * resolution for that format from {@link StreamConfigurationMap#getOutputSizes} or
+ * <p> For guaranteed concurrent stream configurations:</p>
+ * <p> s720p refers to the camera device's resolution for that format from {@link StreamConfigurationMap#getOutputSizes} or
* 720p(1280X720) whichever is lower. </p>
+ * <p> s1440p refers to the camera device's resolution for that format from {@link StreamConfigurationMap#getOutputSizes} or
+ * 1440p(1920X1440) whichever is lower. </p>
* <p>MONOCHROME-capability ({@link CameraCharacteristics#REQUEST_AVAILABLE_CAPABILITIES}
* includes {@link CameraMetadata#REQUEST_AVAILABLE_CAPABILITIES_MONOCHROME MONOCHROME}) devices
* supporting {@link android.graphics.ImageFormat#Y8 Y8} support substituting {@code YUV}
diff --git a/core/java/android/hardware/camera2/CameraManager.java b/core/java/android/hardware/camera2/CameraManager.java
index 17c83f3a7eb9..743ce7b46792 100644
--- a/core/java/android/hardware/camera2/CameraManager.java
+++ b/core/java/android/hardware/camera2/CameraManager.java
@@ -140,6 +140,11 @@ public final class CameraManager {
* <p>The set of combinations doesn't contain physical cameras that can only be used as
* part of a logical multi-camera device.</p>
*
+ * <p> If a new camera id becomes available through
+ * {@link AvailabilityCallback#onCameraUnavailable(String)}, clients can call
+ * this method to check if new combinations of camera ids which can stream concurrently are
+ * available.
+ *
* @return The set of combinations of currently connected camera devices, that may have
* sessions configured concurrently. The set of combinations will be empty if no such
* combinations are supported by the camera subsystem.
diff --git a/core/java/android/hardware/camera2/params/MandatoryStreamCombination.java b/core/java/android/hardware/camera2/params/MandatoryStreamCombination.java
index 41e1443d6866..f0fab6a99d14 100644
--- a/core/java/android/hardware/camera2/params/MandatoryStreamCombination.java
+++ b/core/java/android/hardware/camera2/params/MandatoryStreamCombination.java
@@ -267,7 +267,7 @@ public final class MandatoryStreamCombination {
mStreamsInformation.hashCode());
}
- private static enum SizeThreshold { VGA, PREVIEW, RECORD, MAXIMUM, s720p }
+ private static enum SizeThreshold { VGA, PREVIEW, RECORD, MAXIMUM, s720p, s1440p }
private static enum ReprocessType { NONE, PRIVATE, YUV }
private static final class StreamTemplate {
public int mFormat;
@@ -651,23 +651,38 @@ public final class MandatoryStreamCombination {
private static StreamCombinationTemplate sConcurrentStreamCombinations[] = {
new StreamCombinationTemplate(new StreamTemplate [] {
- new StreamTemplate(ImageFormat.YUV_420_888, SizeThreshold.s720p) },
+ new StreamTemplate(ImageFormat.YUV_420_888, SizeThreshold.s1440p) },
"In-app video / image processing"),
new StreamCombinationTemplate(new StreamTemplate [] {
- new StreamTemplate(ImageFormat.PRIVATE, SizeThreshold.s720p) },
+ new StreamTemplate(ImageFormat.PRIVATE, SizeThreshold.s1440p) },
"preview / preview to GPU"),
new StreamCombinationTemplate(new StreamTemplate [] {
+ new StreamTemplate(ImageFormat.JPEG, SizeThreshold.s1440p) },
+ "No view-finder still image capture"),
+ new StreamCombinationTemplate(new StreamTemplate [] {
new StreamTemplate(ImageFormat.YUV_420_888, SizeThreshold.s720p),
- new StreamTemplate(ImageFormat.YUV_420_888, SizeThreshold.s720p)},
- "In-app video / image processing with preview"),
+ new StreamTemplate(ImageFormat.YUV_420_888, SizeThreshold.s1440p)},
+ "Two-input in app video / image processing"),
new StreamCombinationTemplate(new StreamTemplate [] {
new StreamTemplate(ImageFormat.PRIVATE, SizeThreshold.s720p),
- new StreamTemplate(ImageFormat.YUV_420_888, SizeThreshold.s720p)},
+ new StreamTemplate(ImageFormat.PRIVATE, SizeThreshold.s1440p)},
+ "High resolution video recording with preview"),
+ new StreamCombinationTemplate(new StreamTemplate [] {
+ new StreamTemplate(ImageFormat.PRIVATE, SizeThreshold.s720p),
+ new StreamTemplate(ImageFormat.YUV_420_888, SizeThreshold.s1440p)},
+ "In-app video / image processing with preview"),
+ new StreamCombinationTemplate(new StreamTemplate [] {
+ new StreamTemplate(ImageFormat.YUV_420_888, SizeThreshold.s720p),
+ new StreamTemplate(ImageFormat.PRIVATE, SizeThreshold.s1440p)},
"In-app video / image processing with preview"),
new StreamCombinationTemplate(new StreamTemplate [] {
new StreamTemplate(ImageFormat.PRIVATE, SizeThreshold.s720p),
- new StreamTemplate(ImageFormat.PRIVATE, SizeThreshold.s720p)},
- "Standard Recording"),
+ new StreamTemplate(ImageFormat.JPEG, SizeThreshold.s1440p)},
+ "Standard stil image capture"),
+ new StreamCombinationTemplate(new StreamTemplate [] {
+ new StreamTemplate(ImageFormat.YUV_420_888, SizeThreshold.s720p),
+ new StreamTemplate(ImageFormat.JPEG, SizeThreshold.s1440p)},
+ "Standard still image capture"),
};
/**
@@ -720,6 +735,7 @@ public final class MandatoryStreamCombination {
+ " cannot have mandatory concurrent streams");
}
Size size720p = new Size(1280, 720);
+ Size size1440p = new Size(1920, 1440);
ArrayList<MandatoryStreamCombination> availableConcurrentStreamCombinations =
new ArrayList<MandatoryStreamCombination>();
@@ -732,8 +748,16 @@ public final class MandatoryStreamCombination {
for (StreamTemplate template : combTemplate.mStreamTemplates) {
MandatoryStreamInformation streamInfo;
List<Size> sizes = new ArrayList<Size>();
+ Size formatSize = null;
+ switch (template.mSizeThreshold) {
+ case s1440p:
+ formatSize = size1440p;
+ break;
+ default:
+ formatSize = size720p;
+ }
Size sizeChosen =
- getMinSize(size720p,
+ getMinSize(formatSize,
getMaxSize(mStreamConfigMap.getOutputSizes(template.mFormat)));
sizes.add(sizeChosen);
try {
diff --git a/core/java/android/hardware/display/DeviceProductInfo.java b/core/java/android/hardware/display/DeviceProductInfo.java
index 6ad7faed16d8..ce26cb0d7adc 100644
--- a/core/java/android/hardware/display/DeviceProductInfo.java
+++ b/core/java/android/hardware/display/DeviceProductInfo.java
@@ -28,21 +28,21 @@ import java.util.Objects;
* @hide
*/
public final class DeviceProductInfo implements Parcelable {
- final private String mName;
- final private String mManufacturerPnpId;
- final private String mProductId;
- final private Integer mModelYear;
- final private ManufactureDate mManufactureDate;
+ private final String mName;
+ private final String mManufacturerPnpId;
+ private final String mProductId;
+ private final Integer mModelYear;
+ private final ManufactureDate mManufactureDate;
public DeviceProductInfo(
String name,
String manufacturerPnpId,
- String productCode,
+ String productId,
Integer modelYear,
ManufactureDate manufactureDate) {
this.mName = name;
this.mManufacturerPnpId = manufacturerPnpId;
- this.mProductId = productCode;
+ this.mProductId = productId;
this.mModelYear = modelYear;
this.mManufactureDate = manufactureDate;
}
@@ -158,8 +158,8 @@ public final class DeviceProductInfo implements Parcelable {
* @hide
*/
public static class ManufactureDate implements Parcelable {
- final private Integer mWeek;
- final private Integer mYear;
+ private final Integer mWeek;
+ private final Integer mYear;
public ManufactureDate(Integer week, Integer year) {
mWeek = week;
diff --git a/core/java/android/net/ConnectivityManager.java b/core/java/android/net/ConnectivityManager.java
index ea26edef10d3..62eff4522d70 100644
--- a/core/java/android/net/ConnectivityManager.java
+++ b/core/java/android/net/ConnectivityManager.java
@@ -1279,7 +1279,8 @@ public class ConnectivityManager {
@UnsupportedAppUsage
public NetworkCapabilities[] getDefaultNetworkCapabilitiesForUser(int userId) {
try {
- return mService.getDefaultNetworkCapabilitiesForUser(userId);
+ return mService.getDefaultNetworkCapabilitiesForUser(
+ userId, mContext.getOpPackageName());
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
}
@@ -1361,7 +1362,7 @@ public class ConnectivityManager {
@Nullable
public NetworkCapabilities getNetworkCapabilities(@Nullable Network network) {
try {
- return mService.getNetworkCapabilities(network);
+ return mService.getNetworkCapabilities(network, mContext.getOpPackageName());
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
}
@@ -4039,10 +4040,9 @@ public class ConnectivityManager {
@NonNull PendingIntent operation) {
printStackTrace();
checkPendingIntentNotNull(operation);
- final String callingPackageName = mContext.getOpPackageName();
try {
mService.pendingRequestForNetwork(
- request.networkCapabilities, operation, callingPackageName);
+ request.networkCapabilities, operation, mContext.getOpPackageName());
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
} catch (ServiceSpecificException e) {
@@ -4154,10 +4154,9 @@ public class ConnectivityManager {
@NonNull PendingIntent operation) {
printStackTrace();
checkPendingIntentNotNull(operation);
- final String callingPackageName = mContext.getOpPackageName();
try {
mService.pendingListenForNetwork(
- request.networkCapabilities, operation, callingPackageName);
+ request.networkCapabilities, operation, mContext.getOpPackageName());
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
} catch (ServiceSpecificException e) {
diff --git a/core/java/android/net/IConnectivityManager.aidl b/core/java/android/net/IConnectivityManager.aidl
index 1c7628f6ad0a..d84d05d522c2 100644
--- a/core/java/android/net/IConnectivityManager.aidl
+++ b/core/java/android/net/IConnectivityManager.aidl
@@ -60,7 +60,8 @@ interface IConnectivityManager
NetworkInfo[] getAllNetworkInfo();
Network getNetworkForType(int networkType);
Network[] getAllNetworks();
- NetworkCapabilities[] getDefaultNetworkCapabilitiesForUser(int userId);
+ NetworkCapabilities[] getDefaultNetworkCapabilitiesForUser(
+ int userId, String callingPackageName);
boolean isNetworkSupported(int networkType);
@@ -69,7 +70,7 @@ interface IConnectivityManager
LinkProperties getLinkPropertiesForType(int networkType);
LinkProperties getLinkProperties(in Network network);
- NetworkCapabilities getNetworkCapabilities(in Network network);
+ NetworkCapabilities getNetworkCapabilities(in Network network, String callingPackageName);
@UnsupportedAppUsage
NetworkState[] getAllNetworkState();
diff --git a/core/java/android/net/NetworkCapabilities.java b/core/java/android/net/NetworkCapabilities.java
index f8b51dd9906b..83f99802b85f 100644
--- a/core/java/android/net/NetworkCapabilities.java
+++ b/core/java/android/net/NetworkCapabilities.java
@@ -830,6 +830,23 @@ public final class NetworkCapabilities implements Parcelable {
* <p>This field keeps track of the UID of the app that created this network and is in charge of
* its lifecycle. This could be the UID of apps such as the Wifi network suggestor, the running
* VPN, or Carrier Service app managing a cellular data connection.
+ *
+ * <p>For NetworkCapability instances being sent from ConnectivityService, this value MUST be
+ * reset to Process.INVALID_UID unless all the following conditions are met:
+ *
+ * <ol>
+ * <li>The destination app is the network owner
+ * <li>The destination app has the ACCESS_FINE_LOCATION permission granted
+ * <li>The user's location toggle is on
+ * </ol>
+ *
+ * This is because the owner UID is location-sensitive. The apps that request a network could
+ * know where the device is if they can tell for sure the system has connected to the network
+ * they requested.
+ *
+ * <p>This is populated by the network agents and for the NetworkCapabilities instance sent by
+ * an app to the System Server, the value MUST be reset to Process.INVALID_UID by the system
+ * server.
*/
private int mOwnerUid = Process.INVALID_UID;
@@ -842,7 +859,16 @@ public final class NetworkCapabilities implements Parcelable {
}
/**
- * Retrieves the UID of the owner app.
+ * Retrieves the UID of the app that owns this network.
+ *
+ * <p>For user privacy reasons, this field will only be populated if:
+ *
+ * <ol>
+ * <li>The calling app is the network owner
+ * <li>The calling app has the ACCESS_FINE_LOCATION permission granted
+ * <li>The user's location toggle is on
+ * </ol>
+ *
*/
public int getOwnerUid() {
return mOwnerUid;
@@ -880,8 +906,9 @@ public final class NetworkCapabilities implements Parcelable {
* @param administratorUids the UIDs to be set as administrators of this Network.
* @hide
*/
+ @NonNull
@SystemApi
- public @NonNull NetworkCapabilities setAdministratorUids(
+ public NetworkCapabilities setAdministratorUids(
@NonNull final List<Integer> administratorUids) {
mAdministratorUids.clear();
mAdministratorUids.addAll(administratorUids);
diff --git a/core/java/android/os/RecoverySystem.java b/core/java/android/os/RecoverySystem.java
index be2245820bb6..d60820ef0f57 100644
--- a/core/java/android/os/RecoverySystem.java
+++ b/core/java/android/os/RecoverySystem.java
@@ -16,6 +16,8 @@
package android.os;
+import static android.view.Display.DEFAULT_DISPLAY;
+
import static java.nio.charset.StandardCharsets.UTF_8;
import android.annotation.NonNull;
@@ -33,6 +35,7 @@ import android.content.Intent;
import android.content.IntentFilter;
import android.content.IntentSender;
import android.content.pm.PackageManager;
+import android.hardware.display.DisplayManager;
import android.provider.Settings;
import android.telephony.SubscriptionInfo;
import android.telephony.SubscriptionManager;
@@ -614,7 +617,8 @@ public class RecoverySystem {
// On TV, reboot quiescently if the screen is off
if (context.getPackageManager().hasSystemFeature(PackageManager.FEATURE_LEANBACK)) {
- if (context.getDisplay().getState() != Display.STATE_ON) {
+ DisplayManager dm = context.getSystemService(DisplayManager.class);
+ if (dm.getDisplay(DEFAULT_DISPLAY).getState() != Display.STATE_ON) {
reason += ",quiescent";
}
}
diff --git a/core/java/android/os/StrictMode.java b/core/java/android/os/StrictMode.java
index 3faaff73a0ea..e8af56478230 100644
--- a/core/java/android/os/StrictMode.java
+++ b/core/java/android/os/StrictMode.java
@@ -42,6 +42,7 @@ import android.os.strictmode.DiskWriteViolation;
import android.os.strictmode.ExplicitGcViolation;
import android.os.strictmode.FileUriExposedViolation;
import android.os.strictmode.ImplicitDirectBootViolation;
+import android.os.strictmode.IncorrectContextUseViolation;
import android.os.strictmode.InstanceCountViolation;
import android.os.strictmode.IntentReceiverLeakedViolation;
import android.os.strictmode.LeakedClosableViolation;
@@ -250,6 +251,7 @@ public final class StrictMode {
DETECT_VM_UNTAGGED_SOCKET,
DETECT_VM_NON_SDK_API_USAGE,
DETECT_VM_IMPLICIT_DIRECT_BOOT,
+ DETECT_VM_INCORRECT_CONTEXT_USE,
PENALTY_GATHER,
PENALTY_LOG,
PENALTY_DIALOG,
@@ -289,6 +291,8 @@ public final class StrictMode {
private static final int DETECT_VM_IMPLICIT_DIRECT_BOOT = 1 << 10;
/** @hide */
private static final int DETECT_VM_CREDENTIAL_PROTECTED_WHILE_LOCKED = 1 << 11;
+ /** @hide */
+ private static final int DETECT_VM_INCORRECT_CONTEXT_USE = 1 << 12;
/** @hide */
private static final int DETECT_VM_ALL = 0x0000ffff;
@@ -871,6 +875,9 @@ public final class StrictMode {
if (targetSdk >= Build.VERSION_CODES.Q) {
detectCredentialProtectedWhileLocked();
}
+ if (targetSdk >= Build.VERSION_CODES.R) {
+ detectIncorrectContextUse();
+ }
// TODO: Decide whether to detect non SDK API usage beyond a certain API level.
// TODO: enable detectImplicitDirectBoot() once system is less noisy
@@ -1028,6 +1035,32 @@ public final class StrictMode {
}
/**
+ * Detect attempts to invoke a method on a {@link Context} that is not suited for such
+ * operation.
+ * <p>An example of this is trying to obtain an instance of visual service (e.g.
+ * {@link android.view.WindowManager}) from a non-visual {@link Context}. This is not
+ * allowed, since a non-visual {@link Context} is not adjusted to any visual area, and
+ * therefore can report incorrect metrics or resources.
+ * @see Context#getDisplay()
+ * @see Context#getSystemService(String)
+ * @hide
+ */
+ @TestApi
+ public @NonNull Builder detectIncorrectContextUse() {
+ return enable(DETECT_VM_INCORRECT_CONTEXT_USE);
+ }
+
+ /**
+ * Disable detection of incorrect context use.
+ * TODO(b/149790106): Fix usages and remove.
+ * @hide
+ */
+ @TestApi
+ public @NonNull Builder permitIncorrectContextUse() {
+ return disable(DETECT_VM_INCORRECT_CONTEXT_USE);
+ }
+
+ /**
* Crashes the whole process on violation. This penalty runs at the end of all enabled
* penalties so you'll still get your logging or other violations before the process
* dies.
@@ -2057,6 +2090,11 @@ public final class StrictMode {
}
/** @hide */
+ public static boolean vmIncorrectContextUseEnabled() {
+ return (sVmPolicy.mask & DETECT_VM_INCORRECT_CONTEXT_USE) != 0;
+ }
+
+ /** @hide */
public static void onSqliteObjectLeaked(String message, Throwable originStack) {
onVmPolicyViolation(new SqliteObjectLeakedViolation(message, originStack));
}
@@ -2130,6 +2168,11 @@ public final class StrictMode {
onVmPolicyViolation(new ImplicitDirectBootViolation());
}
+ /** @hide */
+ public static void onIncorrectContextUsed(String message, Throwable originStack) {
+ onVmPolicyViolation(new IncorrectContextUseViolation(message, originStack));
+ }
+
/** Assume locked until we hear otherwise */
private static volatile boolean sUserKeyUnlocked = false;
diff --git a/core/java/android/os/incremental/IncrementalStorage.java b/core/java/android/os/incremental/IncrementalStorage.java
index f4e1f967dca8..dea495bf9327 100644
--- a/core/java/android/os/incremental/IncrementalStorage.java
+++ b/core/java/android/os/incremental/IncrementalStorage.java
@@ -434,6 +434,11 @@ public final class IncrementalStorage {
signature = V4Signature.readFrom(input);
}
+ if (!signature.isVersionSupported()) {
+ throw new IOException("v4 signature version " + signature.version
+ + " is not supported");
+ }
+
final byte[] rootHash = signature.verityRootHash;
final byte[] additionalData = signature.v3Digest;
final byte[] pkcs7Signature = signature.pkcs7SignatureBlock;
diff --git a/core/java/android/os/incremental/V4Signature.java b/core/java/android/os/incremental/V4Signature.java
index 6516917afd9d..17adfc8a05d9 100644
--- a/core/java/android/os/incremental/V4Signature.java
+++ b/core/java/android/os/incremental/V4Signature.java
@@ -31,7 +31,9 @@ import java.io.IOException;
*/
public class V4Signature {
public static final String EXT = ".idsig";
+ public static final int SUPPORTED_VERSION = 1;
+ public final int version;
public final byte[] verityRootHash;
public final byte[] v3Digest;
public final byte[] pkcs7SignatureBlock;
@@ -71,20 +73,27 @@ public class V4Signature {
}
}
+ boolean isVersionSupported() {
+ return this.version == SUPPORTED_VERSION;
+ }
+
static V4Signature readFrom(DataInputStream stream) throws IOException {
+ final int version = stream.readInt();
byte[] verityRootHash = readBytes(stream);
byte[] v3Digest = readBytes(stream);
byte[] pkcs7SignatureBlock = readBytes(stream);
- return new V4Signature(verityRootHash, v3Digest, pkcs7SignatureBlock);
+ return new V4Signature(version, verityRootHash, v3Digest, pkcs7SignatureBlock);
}
- V4Signature(byte[] verityRootHash, byte[] v3Digest, byte[] pkcs7SignatureBlock) {
+ V4Signature(int version, byte[] verityRootHash, byte[] v3Digest, byte[] pkcs7SignatureBlock) {
+ this.version = version;
this.verityRootHash = verityRootHash;
this.v3Digest = v3Digest;
this.pkcs7SignatureBlock = pkcs7SignatureBlock;
}
void writeTo(DataOutputStream stream) throws IOException {
+ stream.writeInt(this.version);
writeBytes(stream, this.verityRootHash);
writeBytes(stream, this.v3Digest);
writeBytes(stream, this.pkcs7SignatureBlock);
diff --git a/core/java/android/os/storage/StorageManager.java b/core/java/android/os/storage/StorageManager.java
index 8d04df0560f5..1454aac66d21 100644
--- a/core/java/android/os/storage/StorageManager.java
+++ b/core/java/android/os/storage/StorageManager.java
@@ -29,6 +29,7 @@ import static android.app.AppOpsManager.OP_WRITE_MEDIA_IMAGES;
import static android.app.AppOpsManager.OP_WRITE_MEDIA_VIDEO;
import static android.content.ContentResolver.DEPRECATE_DATA_PREFIX;
import static android.content.pm.PackageManager.PERMISSION_GRANTED;
+import static android.os.UserHandle.PER_USER_RANGE;
import android.annotation.BytesLong;
import android.annotation.CallbackExecutor;
@@ -2324,17 +2325,34 @@ public class StorageManager {
private static final String XATTR_CACHE_TOMBSTONE = "user.cache_tombstone";
- // Matches AID_MEDIA_RW in android_filesystem_config.h
- private static final int QUOTA_PROJECT_ID_MEDIA_NONE = 1023;
+ // Project IDs below must match android_projectid_config.h
+ /**
+ * Default project ID for files on external storage
+ *
+ * {@hide}
+ */
+ public static final int PROJECT_ID_EXT_DEFAULT = 1000;
- // Matches AID_MEDIA_IMAGE in android_filesystem_config.h
- private static final int QUOTA_PROJECT_ID_MEDIA_IMAGE = 1057;
+ /**
+ * project ID for audio files on external storage
+ *
+ * {@hide}
+ */
+ public static final int PROJECT_ID_EXT_MEDIA_AUDIO = 1001;
- // Matches AID_MEDIA_AUDIO in android_filesystem_config.h
- private static final int QUOTA_PROJECT_ID_MEDIA_AUDIO = 1055;
+ /**
+ * project ID for video files on external storage
+ *
+ * {@hide}
+ */
+ public static final int PROJECT_ID_EXT_MEDIA_VIDEO = 1002;
- // Matches AID_MEDIA_VIDEO in android_filesystem_config.h
- private static final int QUOTA_PROJECT_ID_MEDIA_VIDEO = 1056;
+ /**
+ * project ID for image files on external storage
+ *
+ * {@hide}
+ */
+ public static final int PROJECT_ID_EXT_MEDIA_IMAGE = 1003;
/**
* Constant for use with
@@ -2388,6 +2406,11 @@ public class StorageManager {
private static native boolean setQuotaProjectId(String path, long projectId);
+ private static long getProjectIdForUser(int userId, int projectId) {
+ // Much like UserHandle.getUid(), store the user ID in the upper bits
+ return userId * PER_USER_RANGE + projectId;
+ }
+
/**
* Let StorageManager know that the quota type for a file on external storage should
* be updated. Android tracks quotas for various media types. Consequently, this should be
@@ -2417,18 +2440,27 @@ public class StorageManager {
@QuotaType int quotaType) throws IOException {
long projectId;
final String filePath = path.getCanonicalPath();
+ final StorageVolume volume = getStorageVolume(path);
+ if (volume == null) {
+ throw new IllegalStateException("Failed to update quota type for " + filePath);
+ }
+
+ final int userId = volume.getOwner().getIdentifier();
+ if (userId < 0) {
+ throw new IllegalStateException("Failed to update quota type for " + filePath);
+ }
switch (quotaType) {
case QUOTA_TYPE_MEDIA_NONE:
- projectId = QUOTA_PROJECT_ID_MEDIA_NONE;
+ projectId = getProjectIdForUser(userId, PROJECT_ID_EXT_DEFAULT);
break;
case QUOTA_TYPE_MEDIA_AUDIO:
- projectId = QUOTA_PROJECT_ID_MEDIA_AUDIO;
+ projectId = getProjectIdForUser(userId, PROJECT_ID_EXT_MEDIA_AUDIO);
break;
case QUOTA_TYPE_MEDIA_VIDEO:
- projectId = QUOTA_PROJECT_ID_MEDIA_VIDEO;
+ projectId = getProjectIdForUser(userId, PROJECT_ID_EXT_MEDIA_VIDEO);
break;
case QUOTA_TYPE_MEDIA_IMAGE:
- projectId = QUOTA_PROJECT_ID_MEDIA_IMAGE;
+ projectId = getProjectIdForUser(userId, PROJECT_ID_EXT_MEDIA_IMAGE);
break;
default:
throw new IllegalArgumentException("Invalid quota type: " + quotaType);
diff --git a/packages/SystemUI/tests/src/com/android/systemui/screenshot/ScreenshotStubActivity.java b/core/java/android/os/strictmode/IncorrectContextUseViolation.java
index 0b871e433f5b..647db171e080 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/screenshot/ScreenshotStubActivity.java
+++ b/core/java/android/os/strictmode/IncorrectContextUseViolation.java
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2011 The Android Open Source Project
+ * Copyright (C) 2020 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -13,21 +13,23 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
-package com.android.systemui.screenshot;
-import android.app.Activity;
-import android.os.Bundle;
+package android.os.strictmode;
-import com.android.systemui.tests.R;
+import android.content.Context;
/**
- * A stub activity used in {@link ScreenshotTest}.
+ * Incorrect usage of {@link Context}, such as obtaining a visual service from non-visual
+ * {@link Context} instance.
+ * @see Context#getSystemService(String)
+ * @see Context#getDisplayNoVerify()
+ * @hide
*/
-public class ScreenshotStubActivity extends Activity {
+public final class IncorrectContextUseViolation extends Violation {
- @Override
- public void onCreate(Bundle savedInstanceState) {
- super.onCreate(savedInstanceState);
- setContentView(R.layout.main);
+ /** @hide */
+ public IncorrectContextUseViolation(String message, Throwable originStack) {
+ super(message);
+ initCause(originStack);
}
}
diff --git a/core/java/android/provider/Settings.java b/core/java/android/provider/Settings.java
index a082f09facba..b9abdf83e260 100644
--- a/core/java/android/provider/Settings.java
+++ b/core/java/android/provider/Settings.java
@@ -11509,6 +11509,7 @@ public final class Settings {
* exempted_sync_duration (long)
* system_interaction_duration (long)
* initial_foreground_service_start_duration (long)
+ * cross_profile_apps_share_standby_buckets (boolean)
* </pre>
*
* <p>
diff --git a/core/java/android/service/controls/ControlsProviderService.java b/core/java/android/service/controls/ControlsProviderService.java
index cb20db90f549..b23d0cd4bd93 100644
--- a/core/java/android/service/controls/ControlsProviderService.java
+++ b/core/java/android/service/controls/ControlsProviderService.java
@@ -15,11 +15,14 @@
*/
package android.service.controls;
+import android.Manifest;
import android.annotation.NonNull;
import android.annotation.Nullable;
import android.annotation.SdkConstant;
import android.annotation.SdkConstant.SdkConstantType;
import android.app.Service;
+import android.content.ComponentName;
+import android.content.Context;
import android.content.Intent;
import android.os.Bundle;
import android.os.Handler;
@@ -51,6 +54,20 @@ public abstract class ControlsProviderService extends Service {
@SdkConstant(SdkConstantType.SERVICE_ACTION)
public static final String SERVICE_CONTROLS =
"android.service.controls.ControlsProviderService";
+
+ /**
+ * @hide
+ */
+ @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
+ public static final String ACTION_ADD_CONTROL =
+ "android.service.controls.action.ADD_CONTROL";
+
+ /**
+ * @hide
+ */
+ public static final String EXTRA_CONTROL =
+ "android.service.controls.extra.CONTROL";
+
/**
* @hide
*/
@@ -325,6 +342,33 @@ public abstract class ControlsProviderService extends Service {
}
}
+ /**
+ * Request SystemUI to prompt the user to add a control to favorites.
+ *
+ * @param context A context
+ * @param componentName Component name of the {@link ControlsProviderService}
+ * @param control A stateless control to show to the user
+ */
+ public static void requestAddControl(@NonNull Context context,
+ @NonNull ComponentName componentName,
+ @NonNull Control control) {
+ Preconditions.checkNotNull(context);
+ Preconditions.checkNotNull(componentName);
+ Preconditions.checkNotNull(control);
+ final ComponentName sysuiComponent = ComponentName.unflattenFromString(
+ context.getResources().getString(
+ com.android.internal.R.string.config_systemUIServiceComponent));
+ Intent intent = new Intent(ACTION_ADD_CONTROL);
+ intent.putExtra(Intent.EXTRA_COMPONENT_NAME, componentName);
+ intent.setPackage(sysuiComponent.getPackageName());
+ if (isStatelessControl(control)) {
+ intent.putExtra(EXTRA_CONTROL, control);
+ } else {
+ intent.putExtra(EXTRA_CONTROL, new Control.StatelessBuilder(control).build());
+ }
+ context.sendBroadcast(intent, Manifest.permission.BIND_CONTROLS);
+ }
+
private static class SubscriptionAdapter extends IControlsSubscription.Stub {
final Subscription mSubscription;
diff --git a/core/java/android/util/LongSparseArray.java b/core/java/android/util/LongSparseArray.java
index 73e17a61d17f..55542d898784 100644
--- a/core/java/android/util/LongSparseArray.java
+++ b/core/java/android/util/LongSparseArray.java
@@ -16,15 +16,18 @@
package android.util;
+import android.annotation.NonNull;
import android.os.Parcel;
import com.android.internal.util.ArrayUtils;
import com.android.internal.util.GrowingArrayUtils;
import com.android.internal.util.Preconditions;
+import com.android.internal.util.function.LongObjPredicate;
import libcore.util.EmptyArray;
import java.util.Arrays;
+import java.util.Objects;
/**
* SparseArray mapping longs to Objects. Unlike a normal array of Objects,
@@ -145,6 +148,18 @@ public class LongSparseArray<E> implements Cloneable {
delete(key);
}
+ /** @hide */
+ @SuppressWarnings("unchecked")
+ public void removeIf(@NonNull LongObjPredicate<? super E> filter) {
+ Objects.requireNonNull(filter);
+ for (int i = 0; i < mSize; ++i) {
+ if (mValues[i] != DELETED && filter.test(mKeys[i], (E) mValues[i])) {
+ mValues[i] = DELETED;
+ mGarbage = true;
+ }
+ }
+ }
+
/**
* Removes the mapping at the specified index.
*
diff --git a/core/java/android/view/SurfaceView.java b/core/java/android/view/SurfaceView.java
index deff79d5486a..73707ca889dd 100644
--- a/core/java/android/view/SurfaceView.java
+++ b/core/java/android/view/SurfaceView.java
@@ -1586,6 +1586,19 @@ public class SurfaceView extends View implements ViewRootImpl.SurfaceChangedCall
info.addChild(wrapper.getLeashToken());
}
+ @Override
+ public int getImportantForAccessibility() {
+ final int mode = super.getImportantForAccessibility();
+ // If developers explicitly set the important mode for it, don't change the mode.
+ // Only change the mode to important when this SurfaceView isn't explicitly set and has
+ // an embedded hierarchy.
+ if (mRemoteAccessibilityEmbeddedConnection == null
+ || mode != IMPORTANT_FOR_ACCESSIBILITY_AUTO) {
+ return mode;
+ }
+ return IMPORTANT_FOR_ACCESSIBILITY_YES;
+ }
+
private void initEmbeddedHierarchyForAccessibility(SurfaceControlViewHost.SurfacePackage p) {
final IAccessibilityEmbeddedConnection connection = p.getAccessibilityEmbeddedConnection();
final RemoteAccessibilityEmbeddedConnection wrapper =
diff --git a/core/java/android/view/View.java b/core/java/android/view/View.java
index 4c7307ee5b8c..11ab5724d927 100644
--- a/core/java/android/view/View.java
+++ b/core/java/android/view/View.java
@@ -13442,8 +13442,7 @@ public class View implements Drawable.Callback, KeyEvent.Callback,
* @see #getImportantForAccessibility()
*/
public boolean isImportantForAccessibility() {
- final int mode = (mPrivateFlags2 & PFLAG2_IMPORTANT_FOR_ACCESSIBILITY_MASK)
- >> PFLAG2_IMPORTANT_FOR_ACCESSIBILITY_SHIFT;
+ final int mode = getImportantForAccessibility();
if (mode == IMPORTANT_FOR_ACCESSIBILITY_NO
|| mode == IMPORTANT_FOR_ACCESSIBILITY_NO_HIDE_DESCENDANTS) {
return false;
diff --git a/core/java/android/view/WindowContainerTransaction.java b/core/java/android/view/WindowContainerTransaction.java
index cf34b0bad78d..f406be9ebac7 100644
--- a/core/java/android/view/WindowContainerTransaction.java
+++ b/core/java/android/view/WindowContainerTransaction.java
@@ -26,6 +26,7 @@ import android.os.IBinder;
import android.os.Parcel;
import android.os.Parcelable;
import android.util.ArrayMap;
+import android.view.SurfaceControl;
import java.util.ArrayList;
import java.util.List;
@@ -77,8 +78,28 @@ public class WindowContainerTransaction implements Parcelable {
public WindowContainerTransaction scheduleFinishEnterPip(IWindowContainer container,
Rect bounds) {
Change chg = getOrCreateChange(container.asBinder());
- chg.mSchedulePipCallback = true;
chg.mPinnedBounds = new Rect(bounds);
+ chg.mChangeMask |= Change.CHANGE_PIP_CALLBACK;
+
+ return this;
+ }
+
+ /**
+ * Send a SurfaceControl transaction to the server, which the server will apply in sync with
+ * the next bounds change. As this uses deferred transaction and not BLAST it is only
+ * able to sync with a single window, and the first visible window in this hierarchy of type
+ * BASE_APPLICATION to resize will be used. If there are bound changes included in this
+ * WindowContainer transaction (from setBounds or scheduleFinishEnterPip), the SurfaceControl
+ * transaction will be synced with those bounds. If there are no changes, then
+ * the SurfaceControl transaction will be synced with the next bounds change. This means
+ * that you can call this, apply the WindowContainer transaction, and then later call
+ * dismissPip() to achieve synchronization.
+ */
+ public WindowContainerTransaction setBoundsChangeTransaction(IWindowContainer container,
+ SurfaceControl.Transaction t) {
+ Change chg = getOrCreateChange(container.asBinder());
+ chg.mBoundsChangeTransaction = t;
+ chg.mChangeMask |= Change.CHANGE_BOUNDS_TRANSACTION;
return this;
}
@@ -174,6 +195,8 @@ public class WindowContainerTransaction implements Parcelable {
*/
public static class Change implements Parcelable {
public static final int CHANGE_FOCUSABLE = 1;
+ public static final int CHANGE_BOUNDS_TRANSACTION = 1 << 1;
+ public static final int CHANGE_PIP_CALLBACK = 1 << 2;
private final Configuration mConfiguration = new Configuration();
private boolean mFocusable = true;
@@ -181,8 +204,8 @@ public class WindowContainerTransaction implements Parcelable {
private @ActivityInfo.Config int mConfigSetMask = 0;
private @WindowConfiguration.WindowConfig int mWindowSetMask = 0;
- private boolean mSchedulePipCallback = false;
private Rect mPinnedBounds = null;
+ private SurfaceControl.Transaction mBoundsChangeTransaction = null;
public Change() {}
@@ -192,11 +215,14 @@ public class WindowContainerTransaction implements Parcelable {
mChangeMask = in.readInt();
mConfigSetMask = in.readInt();
mWindowSetMask = in.readInt();
- mSchedulePipCallback = (in.readInt() != 0);
- if (mSchedulePipCallback ) {
+ if ((mChangeMask & Change.CHANGE_PIP_CALLBACK) != 0) {
mPinnedBounds = new Rect();
mPinnedBounds.readFromParcel(in);
}
+ if ((mChangeMask & Change.CHANGE_BOUNDS_TRANSACTION) != 0) {
+ mBoundsChangeTransaction =
+ SurfaceControl.Transaction.CREATOR.createFromParcel(in);
+ }
}
public Configuration getConfiguration() {
@@ -233,6 +259,10 @@ public class WindowContainerTransaction implements Parcelable {
return mPinnedBounds;
}
+ public SurfaceControl.Transaction getBoundsChangeTransaction() {
+ return mBoundsChangeTransaction;
+ }
+
@Override
public String toString() {
final boolean changesBounds =
@@ -264,10 +294,12 @@ public class WindowContainerTransaction implements Parcelable {
dest.writeInt(mConfigSetMask);
dest.writeInt(mWindowSetMask);
- dest.writeInt(mSchedulePipCallback ? 1 : 0);
- if (mSchedulePipCallback ) {
+ if (mPinnedBounds != null) {
mPinnedBounds.writeToParcel(dest, flags);
}
+ if (mBoundsChangeTransaction != null) {
+ mBoundsChangeTransaction.writeToParcel(dest, flags);
+ }
}
@Override
diff --git a/core/java/android/view/WindowManagerImpl.java b/core/java/android/view/WindowManagerImpl.java
index 56683dd9a5d1..d40f505f87a0 100644
--- a/core/java/android/view/WindowManagerImpl.java
+++ b/core/java/android/view/WindowManagerImpl.java
@@ -101,7 +101,7 @@ public final class WindowManagerImpl implements WindowManager {
@Override
public void addView(@NonNull View view, @NonNull ViewGroup.LayoutParams params) {
applyDefaultToken(params);
- mGlobal.addView(view, params, mContext.getDisplay(), mParentWindow);
+ mGlobal.addView(view, params, mContext.getDisplayNoVerify(), mParentWindow);
mIsViewAdded = true;
mLastView = view;
mLastParams = (WindowManager.LayoutParams) params;
@@ -158,7 +158,7 @@ public final class WindowManagerImpl implements WindowManager {
@Override
public Display getDefaultDisplay() {
- return mContext.getDisplay();
+ return mContext.getDisplayNoVerify();
}
@Override
@@ -240,7 +240,7 @@ public final class WindowManagerImpl implements WindowManager {
private Rect getMaximumBounds() {
// TODO(b/128338354): Current maximum bound is display size, but it should be displayArea
// bound after displayArea feature is finished.
- final Display display = mContext.getDisplay();
+ final Display display = mContext.getDisplayNoVerify();
final Point displaySize = new Point();
display.getRealSize(displaySize);
return new Rect(0, 0, displaySize.x, displaySize.y);
diff --git a/core/java/android/view/accessibility/OWNERS b/core/java/android/view/accessibility/OWNERS
index 265674a74b7e..c6f42f719caa 100644
--- a/core/java/android/view/accessibility/OWNERS
+++ b/core/java/android/view/accessibility/OWNERS
@@ -1,3 +1,4 @@
svetoslavganov@google.com
pweaver@google.com
rhedjao@google.com
+qasid@google.com
diff --git a/core/java/android/view/inputmethod/InputMethodManager.java b/core/java/android/view/inputmethod/InputMethodManager.java
index dbab81b129a9..39d5f5c396a1 100644
--- a/core/java/android/view/inputmethod/InputMethodManager.java
+++ b/core/java/android/view/inputmethod/InputMethodManager.java
@@ -93,12 +93,7 @@ import java.util.Comparator;
import java.util.List;
import java.util.Map;
import java.util.Objects;
-import java.util.concurrent.CancellationException;
import java.util.concurrent.CountDownLatch;
-import java.util.concurrent.ExecutionException;
-import java.util.concurrent.ExecutorService;
-import java.util.concurrent.Executors;
-import java.util.concurrent.Future;
import java.util.concurrent.ThreadFactory;
import java.util.concurrent.TimeUnit;
@@ -415,16 +410,6 @@ public final class InputMethodManager {
int mCursorCandEnd;
/**
- * Initial startInput with {@link StartInputReason.WINDOW_FOCUS_GAIN} is executed
- * in a background thread. Later, if there is an actual startInput it will wait on
- * main thread till the background thread completes.
- */
- private Future<?> mWindowFocusGainFuture;
-
- private ExecutorService mStartInputWorker = Executors.newSingleThreadExecutor(
- new ImeThreadFactory("StartInputWorker"));
-
- /**
* The instance that has previously been sent to the input method.
*/
private CursorAnchorInfo mCursorAnchorInfo = null;
@@ -612,41 +597,36 @@ public final class InputMethodManager {
final boolean forceNewFocus1 = forceNewFocus;
final int startInputFlags = getStartInputFlags(focusedView, 0);
- if (mWindowFocusGainFuture != null) {
- mWindowFocusGainFuture.cancel(false /* mayInterruptIfRunning */);
+ final ImeFocusController controller = getFocusController();
+ if (controller == null) {
+ return;
}
- mWindowFocusGainFuture = mStartInputWorker.submit(() -> {
- final ImeFocusController controller = getFocusController();
- if (controller == null) {
+ if (controller.checkFocus(forceNewFocus1, false)) {
+ // We need to restart input on the current focus view. This
+ // should be done in conjunction with telling the system service
+ // about the window gaining focus, to help make the transition
+ // smooth.
+ if (startInput(StartInputReason.WINDOW_FOCUS_GAIN,
+ focusedView, startInputFlags, softInputMode, windowFlags)) {
return;
}
- if (controller.checkFocus(forceNewFocus1, false)) {
- // We need to restart input on the current focus view. This
- // should be done in conjunction with telling the system service
- // about the window gaining focus, to help make the transition
- // smooth.
- if (startInput(StartInputReason.WINDOW_FOCUS_GAIN,
- focusedView, startInputFlags, softInputMode, windowFlags)) {
- return;
- }
- }
+ }
- synchronized (mH) {
- // For some reason we didn't do a startInput + windowFocusGain, so
- // we'll just do a window focus gain and call it a day.
- try {
- if (DEBUG) Log.v(TAG, "Reporting focus gain, without startInput");
- mService.startInputOrWindowGainedFocus(
- StartInputReason.WINDOW_FOCUS_GAIN_REPORT_ONLY, mClient,
- focusedView.getWindowToken(), startInputFlags, softInputMode,
- windowFlags,
- null, null, 0 /* missingMethodFlags */,
- mCurRootView.mContext.getApplicationInfo().targetSdkVersion);
- } catch (RemoteException e) {
- throw e.rethrowFromSystemServer();
- }
+ synchronized (mH) {
+ // For some reason we didn't do a startInput + windowFocusGain, so
+ // we'll just do a window focus gain and call it a day.
+ try {
+ if (DEBUG) Log.v(TAG, "Reporting focus gain, without startInput");
+ mService.startInputOrWindowGainedFocus(
+ StartInputReason.WINDOW_FOCUS_GAIN_REPORT_ONLY, mClient,
+ focusedView.getWindowToken(), startInputFlags, softInputMode,
+ windowFlags,
+ null, null, 0 /* missingMethodFlags */,
+ mCurRootView.mContext.getApplicationInfo().targetSdkVersion);
+ } catch (RemoteException e) {
+ throw e.rethrowFromSystemServer();
}
- });
+ }
}
/**
@@ -664,10 +644,6 @@ public final class InputMethodManager {
*/
@Override
public void setCurrentRootView(ViewRootImpl rootView) {
- if (mWindowFocusGainFuture != null) {
- mWindowFocusGainFuture.cancel(false /* mayInterruptIfRunning */);
- mWindowFocusGainFuture = null;
- }
synchronized (mH) {
if (mCurRootView != null) {
// Reset the last served view and restart window focus state of the root view.
@@ -845,19 +821,16 @@ public final class InputMethodManager {
} catch (RemoteException e) {
}
}
- }
- // Check focus again in case that "onWindowFocus" is called before
- // handling this message.
- final View servedView;
- synchronized (mH) {
- servedView = getServedViewLocked();
- }
- if (servedView != null && canStartInput(servedView)) {
- if (mCurRootView != null && mCurRootView.getImeFocusController()
- .checkFocus(mRestartOnNextWindowFocus, false)) {
- final int reason = active ? StartInputReason.ACTIVATED_BY_IMMS
- : StartInputReason.DEACTIVATED_BY_IMMS;
- mDelegate.startInput(reason, null, 0, 0, 0);
+ // Check focus again in case that "onWindowFocus" is called before
+ // handling this message.
+ final View servedView = getServedViewLocked();
+ if (servedView != null && canStartInput(servedView)) {
+ if (mCurRootView != null && mCurRootView.getImeFocusController()
+ .checkFocus(mRestartOnNextWindowFocus, false)) {
+ final int reason = active ? StartInputReason.ACTIVATED_BY_IMMS
+ : StartInputReason.DEACTIVATED_BY_IMMS;
+ mDelegate.startInput(reason, null, 0, 0, 0);
+ }
}
}
return;
@@ -1035,6 +1008,13 @@ public final class InputMethodManager {
}
@Override
+ public void scheduleStartInputIfNecessary(boolean fullscreen) {
+ // TODO(b/149859205): See if we can optimize this by having a fused dedicated operation.
+ mH.obtainMessage(MSG_SET_ACTIVE, 0 /* active */, fullscreen ? 1 : 0).sendToTarget();
+ mH.obtainMessage(MSG_SET_ACTIVE, 1 /* active */, fullscreen ? 1 : 0).sendToTarget();
+ }
+
+ @Override
public void reportFullscreenMode(boolean fullscreen) {
mH.obtainMessage(MSG_REPORT_FULLSCREEN_MODE, fullscreen ? 1 : 0, 0)
.sendToTarget();
@@ -1430,10 +1410,6 @@ public final class InputMethodManager {
*/
void clearBindingLocked() {
if (DEBUG) Log.v(TAG, "Clearing binding!");
- if (mWindowFocusGainFuture != null) {
- mWindowFocusGainFuture.cancel(false /* mayInterruptIfRunning */);
- mWindowFocusGainFuture = null;
- }
clearConnectionLocked();
setInputChannelLocked(null);
mBindSequence = -1;
@@ -1826,18 +1802,6 @@ public final class InputMethodManager {
boolean startInputInner(@StartInputReason int startInputReason,
@Nullable IBinder windowGainingFocus, @StartInputFlags int startInputFlags,
@SoftInputModeFlags int softInputMode, int windowFlags) {
- if (startInputReason != StartInputReason.WINDOW_FOCUS_GAIN
- && mWindowFocusGainFuture != null) {
- try {
- mWindowFocusGainFuture.get();
- } catch (ExecutionException | InterruptedException e) {
- // do nothing
- } catch (CancellationException e) {
- // window no longer has focus.
- return true;
- }
- }
-
final View view;
synchronized (mH) {
view = getServedViewLocked();
diff --git a/core/java/android/widget/Editor.java b/core/java/android/widget/Editor.java
index 9de1222c9ac6..13c1f67ef85b 100644
--- a/core/java/android/widget/Editor.java
+++ b/core/java/android/widget/Editor.java
@@ -83,6 +83,7 @@ import android.util.ArraySet;
import android.util.DisplayMetrics;
import android.util.Log;
import android.util.SparseArray;
+import android.util.TypedValue;
import android.view.ActionMode;
import android.view.ActionMode.Callback;
import android.view.ContextMenu;
@@ -151,9 +152,6 @@ public class Editor {
private static final String TAG = "Editor";
private static final boolean DEBUG_UNDO = false;
- // Specifies whether to allow starting a cursor drag by dragging anywhere over the text.
- @VisibleForTesting
- public static boolean FLAG_ENABLE_CURSOR_DRAG = true;
// Specifies whether to use the magnifier when pressing the insertion or selection handles.
private static final boolean FLAG_USE_MAGNIFIER = true;
@@ -387,13 +385,25 @@ public class Editor {
private final SuggestionHelper mSuggestionHelper = new SuggestionHelper();
- // Specifies whether the cursor control feature set is enabled.
- // This can only be true if the text view is editable.
- private boolean mCursorControlEnabled;
+ private boolean mFlagCursorDragFromAnywhereEnabled;
+ private boolean mFlagInsertionHandleGesturesEnabled;
// Specifies whether the new magnifier (with fish-eye effect) is enabled.
private final boolean mNewMagnifierEnabled;
+ // Line height range in DP for the new magnifier.
+ static private final int MIN_LINE_HEIGHT_FOR_MAGNIFIER = 20;
+ static private final int MAX_LINE_HEIGHT_FOR_MAGNIFIER = 32;
+ // Line height range in pixels for the new magnifier.
+ // - If the line height is bigger than the max, magnifier should be dismissed.
+ // - If the line height is smaller than the min, magnifier should apply a bigger zoom factor
+ // to make sure the text can be seen clearly.
+ private int mMinLineHeightForMagnifier;
+ private int mMaxLineHeightForMagnifier;
+ // The zoom factor initially configured.
+ // The actual zoom value may changes based on this initial zoom value.
+ private float mInitialZoom = 1f;
+
Editor(TextView textView) {
mTextView = textView;
// Synchronize the filter list, which places the undo input filter at the end.
@@ -402,26 +412,43 @@ public class Editor {
mHapticTextHandleEnabled = mTextView.getContext().getResources().getBoolean(
com.android.internal.R.bool.config_enableHapticTextHandle);
- mCursorControlEnabled = AppGlobals.getIntCoreSetting(
- WidgetFlags.KEY_ENABLE_CURSOR_CONTROL , 0) != 0;
+ mFlagCursorDragFromAnywhereEnabled = AppGlobals.getIntCoreSetting(
+ WidgetFlags.KEY_ENABLE_CURSOR_DRAG_FROM_ANYWHERE,
+ WidgetFlags.ENABLE_CURSOR_DRAG_FROM_ANYWHERE_DEFAULT ? 1 : 0) != 0;
+ mFlagInsertionHandleGesturesEnabled = AppGlobals.getIntCoreSetting(
+ WidgetFlags.KEY_ENABLE_INSERTION_HANDLE_GESTURES,
+ WidgetFlags.ENABLE_INSERTION_HANDLE_GESTURES_DEFAULT ? 1 : 0) != 0;
mNewMagnifierEnabled = AppGlobals.getIntCoreSetting(
- WidgetFlags.KEY_ENABLE_NEW_MAGNIFIER, 0) != 0;
+ WidgetFlags.KEY_ENABLE_NEW_MAGNIFIER,
+ WidgetFlags.ENABLE_NEW_MAGNIFIER_DEFAULT ? 1 : 0) != 0;
if (TextView.DEBUG_CURSOR) {
- logCursor("Editor", "Cursor control is %s.",
- mCursorControlEnabled ? "enabled" : "disabled");
+ logCursor("Editor", "Cursor drag from anywhere is %s.",
+ mFlagCursorDragFromAnywhereEnabled ? "enabled" : "disabled");
+ logCursor("Editor", "Insertion handle gestures is %s.",
+ mFlagInsertionHandleGesturesEnabled ? "enabled" : "disabled");
logCursor("Editor", "New magnifier is %s.",
mNewMagnifierEnabled ? "enabled" : "disabled");
}
}
@VisibleForTesting
- public void setCursorControlEnabled(boolean enabled) {
- mCursorControlEnabled = enabled;
+ public boolean getFlagCursorDragFromAnywhereEnabled() {
+ return mFlagCursorDragFromAnywhereEnabled;
+ }
+
+ @VisibleForTesting
+ public void setFlagCursorDragFromAnywhereEnabled(boolean enabled) {
+ mFlagCursorDragFromAnywhereEnabled = enabled;
+ }
+
+ @VisibleForTesting
+ public boolean getFlagInsertionHandleGesturesEnabled() {
+ return mFlagInsertionHandleGesturesEnabled;
}
@VisibleForTesting
- public boolean getCursorControlEnabled() {
- return mCursorControlEnabled;
+ public void setFlagInsertionHandleGesturesEnabled(boolean enabled) {
+ mFlagInsertionHandleGesturesEnabled = enabled;
}
// Lazy creates the magnifier animator.
@@ -440,12 +467,12 @@ public class Editor {
private Magnifier.Builder createBuilderWithInlineMagnifierDefaults() {
final Magnifier.Builder params = new Magnifier.Builder(mTextView);
- // TODO: supports changing the height/width dynamically because the text height can be
- // dynamically changed.
float zoom = AppGlobals.getFloatCoreSetting(
- WidgetFlags.KEY_MAGNIFIER_ZOOM_FACTOR, 1.5f);
+ WidgetFlags.KEY_MAGNIFIER_ZOOM_FACTOR,
+ WidgetFlags.MAGNIFIER_ZOOM_FACTOR_DEFAULT);
float aspectRatio = AppGlobals.getFloatCoreSetting(
- WidgetFlags.KEY_MAGNIFIER_ASPECT_RATIO, 5.5f);
+ WidgetFlags.KEY_MAGNIFIER_ASPECT_RATIO,
+ WidgetFlags.MAGNIFIER_ASPECT_RATIO_DEFAULT);
// Avoid invalid/unsupported values.
if (zoom < 1.2f || zoom > 1.8f) {
zoom = 1.5f;
@@ -454,13 +481,20 @@ public class Editor {
aspectRatio = 5.5f;
}
+ mInitialZoom = zoom;
+ mMinLineHeightForMagnifier = (int) TypedValue.applyDimension(
+ TypedValue.COMPLEX_UNIT_DIP, MIN_LINE_HEIGHT_FOR_MAGNIFIER,
+ mTextView.getContext().getResources().getDisplayMetrics());
+ mMaxLineHeightForMagnifier = (int) TypedValue.applyDimension(
+ TypedValue.COMPLEX_UNIT_DIP, MAX_LINE_HEIGHT_FOR_MAGNIFIER,
+ mTextView.getContext().getResources().getDisplayMetrics());
+
final Layout layout = mTextView.getLayout();
final int line = layout.getLineForOffset(mTextView.getSelectionStart());
final int sourceHeight =
layout.getLineBottomWithoutSpacing(line) - layout.getLineTop(line);
- // Slightly increase the height to avoid tooLargeTextForMagnifier() returns true.
- int height = (int)(sourceHeight * zoom) + 2;
- int width = (int)(aspectRatio * height);
+ final int height = (int)(sourceHeight * zoom);
+ final int width = (int)(aspectRatio * Math.max(sourceHeight, mMinLineHeightForMagnifier));
params.setFishEyeStyle()
.setSize(width, height)
@@ -4902,6 +4936,12 @@ public class Editor {
}
private boolean tooLargeTextForMagnifier() {
+ if (mNewMagnifierEnabled) {
+ Layout layout = mTextView.getLayout();
+ final int line = layout.getLineForOffset(getCurrentCursorOffset());
+ return layout.getLineBottomWithoutSpacing(line) - layout.getLineTop(line)
+ >= mMaxLineHeightForMagnifier;
+ }
final float magnifierContentHeight = Math.round(
mMagnifierAnimator.mMagnifier.getHeight()
/ mMagnifierAnimator.mMagnifier.getZoom());
@@ -5111,9 +5151,16 @@ public class Editor {
int lineRight = (int) layout.getLineRight(line);
lineRight += mTextView.getTotalPaddingLeft() - mTextView.getScrollX();
mMagnifierAnimator.mMagnifier.setSourceHorizontalBounds(lineLeft, lineRight);
+ final int lineHeight =
+ layout.getLineBottomWithoutSpacing(line) - layout.getLineTop(line);
+ float zoom = mInitialZoom;
+ if (lineHeight < mMinLineHeightForMagnifier) {
+ zoom = zoom * mMinLineHeightForMagnifier / lineHeight;
+ }
+ mMagnifierAnimator.mMagnifier.updateSourceFactors(lineHeight, zoom);
mMagnifierAnimator.mMagnifier.show(showPosInView.x, showPosInView.y);
} else {
- mMagnifierAnimator.show(showPosInView.x, showPosInView.y);
+ mMagnifierAnimator.show(showPosInView.x, showPosInView.y);
}
updateHandlesVisibility();
} else {
@@ -5259,11 +5306,13 @@ public class Editor {
int deltaHeight = 0;
int opacity = 255;
- if (mCursorControlEnabled) {
+ if (mFlagInsertionHandleGesturesEnabled) {
deltaHeight = AppGlobals.getIntCoreSetting(
- WidgetFlags.KEY_INSERTION_HANDLE_DELTA_HEIGHT, 25);
+ WidgetFlags.KEY_INSERTION_HANDLE_DELTA_HEIGHT,
+ WidgetFlags.INSERTION_HANDLE_DELTA_HEIGHT_DEFAULT);
opacity = AppGlobals.getIntCoreSetting(
- WidgetFlags.KEY_INSERTION_HANDLE_OPACITY, 50);
+ WidgetFlags.KEY_INSERTION_HANDLE_OPACITY,
+ WidgetFlags.INSERTION_HANDLE_OPACITY_DEFAULT);
// Avoid invalid/unsupported values.
if (deltaHeight < -25 || deltaHeight > 50) {
deltaHeight = 25;
@@ -5329,7 +5378,7 @@ public class Editor {
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
- if (mCursorControlEnabled) {
+ if (mFlagInsertionHandleGesturesEnabled) {
final int height = Math.max(
getPreferredHeight() + mDeltaHeight, mDrawable.getIntrinsicHeight());
setMeasuredDimension(getPreferredWidth(), height);
@@ -5340,7 +5389,7 @@ public class Editor {
@Override
public boolean onTouchEvent(MotionEvent ev) {
- if (mCursorControlEnabled && FLAG_ENABLE_CURSOR_DRAG) {
+ if (mFlagInsertionHandleGesturesEnabled && mFlagCursorDragFromAnywhereEnabled) {
// Should only enable touch through when cursor drag is enabled.
// Otherwise the insertion handle view cannot be moved.
return touchThrough(ev);
@@ -6031,7 +6080,7 @@ public class Editor {
}
if (mIsDraggingCursor) {
performCursorDrag(event);
- } else if (FLAG_ENABLE_CURSOR_DRAG
+ } else if (mFlagCursorDragFromAnywhereEnabled
&& mTextView.getLayout() != null
&& mTextView.isFocused()
&& mTouchState.isMovedEnoughForDrag()
diff --git a/core/java/android/widget/Magnifier.java b/core/java/android/widget/Magnifier.java
index 47ea1cbade93..a299b0185433 100644
--- a/core/java/android/widget/Magnifier.java
+++ b/core/java/android/widget/Magnifier.java
@@ -89,7 +89,7 @@ public final class Magnifier {
// The width of the window containing the magnifier.
private final int mWindowWidth;
// The height of the window containing the magnifier.
- private final int mWindowHeight;
+ private int mWindowHeight;
// The zoom applied to the view region copied to the magnifier view.
private float mZoom;
// The width of the content that will be copied to the magnifier.
@@ -485,6 +485,21 @@ public final class Magnifier {
}
/**
+ * Updates the factors of source which may impact the magnifier's size.
+ * This can be called while the magnifier is showing and moving.
+ * @param sourceHeight the new source height.
+ * @param zoom the new zoom factor.
+ */
+ void updateSourceFactors(final int sourceHeight, final float zoom) {
+ mZoom = zoom;
+ mSourceHeight = sourceHeight;
+ mWindowHeight = (int) (sourceHeight * zoom);
+ if (mWindow != null) {
+ mWindow.updateContentFactors(mWindowHeight, zoom);
+ }
+ }
+
+ /**
* Returns the zoom to be applied to the magnified view region copied to the magnifier.
* If the zoom is x and the magnifier window size is (width, height), the original size
* of the content being magnified will be (width / x, height / x).
@@ -904,7 +919,7 @@ public final class Magnifier {
private final Display mDisplay;
// The size of the content of the magnifier.
private final int mContentWidth;
- private final int mContentHeight;
+ private int mContentHeight;
// The insets of the content inside the allocated surface.
private final int mOffsetX;
private final int mOffsetY;
@@ -947,7 +962,7 @@ public final class Magnifier {
// The current content of the magnifier. It is mBitmap + mOverlay, only used for testing.
private Bitmap mCurrentContent;
- private final float mZoom;
+ private float mZoom;
// The width of the ramp region in pixels on the left & right sides of the fish-eye effect.
private final int mRamp;
// Whether is in the new magnifier style.
@@ -1009,11 +1024,11 @@ public final class Magnifier {
final RecordingCanvas canvas = mRenderer.getRootNode().beginRecording(width, height);
try {
- canvas.insertReorderBarrier();
+ canvas.enableZ();
canvas.drawRenderNode(mBitmapRenderNode);
- canvas.insertInorderBarrier();
+ canvas.disableZ();
canvas.drawRenderNode(mOverlayRenderNode);
- canvas.insertInorderBarrier();
+ canvas.disableZ();
} finally {
mRenderer.getRootNode().endRecording();
}
@@ -1034,15 +1049,66 @@ public final class Magnifier {
}
}
+ /**
+ * Updates the factors of content which may resize the window.
+ * @param contentHeight the new height of content.
+ * @param zoom the new zoom factor.
+ */
+ private void updateContentFactors(final int contentHeight, final float zoom) {
+ if (mContentHeight == contentHeight && mZoom == zoom) {
+ return;
+ }
+ if (mContentHeight < contentHeight) {
+ // Grows the surface height as necessary.
+ new SurfaceControl.Transaction().setBufferSize(
+ mSurfaceControl, mContentWidth, contentHeight).apply();
+ mSurface.copyFrom(mSurfaceControl);
+ mRenderer.setSurface(mSurface);
+
+ final Outline outline = new Outline();
+ outline.setRoundRect(0, 0, mContentWidth, contentHeight, 0);
+ outline.setAlpha(1.0f);
+
+ mBitmapRenderNode.setLeftTopRightBottom(mOffsetX, mOffsetY,
+ mOffsetX + mContentWidth, mOffsetY + contentHeight);
+ mBitmapRenderNode.setOutline(outline);
+
+ mOverlayRenderNode.setLeftTopRightBottom(mOffsetX, mOffsetY,
+ mOffsetX + mContentWidth, mOffsetY + contentHeight);
+ mOverlayRenderNode.setOutline(outline);
+
+ final RecordingCanvas canvas =
+ mRenderer.getRootNode().beginRecording(mContentWidth, contentHeight);
+ try {
+ canvas.enableZ();
+ canvas.drawRenderNode(mBitmapRenderNode);
+ canvas.disableZ();
+ canvas.drawRenderNode(mOverlayRenderNode);
+ canvas.disableZ();
+ } finally {
+ mRenderer.getRootNode().endRecording();
+ }
+ }
+ mContentHeight = contentHeight;
+ mZoom = zoom;
+ fillMeshMatrix();
+ }
+
private void createMeshMatrixForFishEyeEffect() {
mMeshWidth = 1;
mMeshHeight = 6;
+ mMeshLeft = new float[2 * (mMeshWidth + 1) * (mMeshHeight + 1)];
+ mMeshRight = new float[2 * (mMeshWidth + 1) * (mMeshHeight + 1)];
+ fillMeshMatrix();
+ }
+
+ private void fillMeshMatrix() {
+ mMeshWidth = 1;
+ mMeshHeight = 6;
final float w = mContentWidth;
final float h = mContentHeight;
final float h0 = h / mZoom;
final float dh = h - h0;
- mMeshLeft = new float[2 * (mMeshWidth + 1) * (mMeshHeight + 1)];
- mMeshRight = new float[2 * (mMeshWidth + 1) * (mMeshHeight + 1)];
for (int i = 0; i < 2 * (mMeshWidth + 1) * (mMeshHeight + 1); i += 2) {
// Calculates X value.
final int colIndex = i % (2 * (mMeshWidth + 1)) / 2;
@@ -1197,6 +1263,7 @@ public final class Magnifier {
if (mBitmap != null) {
mBitmap.recycle();
}
+ mOverlay.setCallback(null);
}
private void doDraw() {
diff --git a/core/java/android/widget/WidgetFlags.java b/core/java/android/widget/WidgetFlags.java
index 1a8e7a713e7a..bce5497a7c2d 100644
--- a/core/java/android/widget/WidgetFlags.java
+++ b/core/java/android/widget/WidgetFlags.java
@@ -17,27 +17,49 @@
package android.widget;
/**
- * Keeps the flags related to the Widget namespace in {@link DeviceConfig}.
+ * Flags in the {@link android.provider.DeviceConfig#NAMESPACE_WIDGET "widget" namespace}.
*
* @hide
*/
public final class WidgetFlags {
/**
- * Whether the cursor control feature set is enabled.
- * TODO: Makes this flag key visible to webview/chrome.
+ * Whether starting a cursor drag from anywhere in the text should be enabled.
*/
- public static final String ENABLE_CURSOR_CONTROL =
- "CursorControlFeature__enable_cursor_control";
+ public static final String ENABLE_CURSOR_DRAG_FROM_ANYWHERE =
+ "CursorControlFeature__enable_cursor_drag_from_anywhere";
/**
- * The key name used in app core settings for enable cursor control.
+ * The key used in app core settings for the flag {@link #ENABLE_CURSOR_DRAG_FROM_ANYWHERE}.
*/
- public static final String KEY_ENABLE_CURSOR_CONTROL = "widget__enable_cursor_control";
+ public static final String KEY_ENABLE_CURSOR_DRAG_FROM_ANYWHERE =
+ "widget__enable_cursor_drag_from_anywhere";
+
+ /**
+ * Default value for the flag {@link #ENABLE_CURSOR_DRAG_FROM_ANYWHERE}.
+ */
+ public static final boolean ENABLE_CURSOR_DRAG_FROM_ANYWHERE_DEFAULT = true;
+
+ /**
+ * Whether additional gestures should be enabled for the insertion cursor handle (e.g.
+ * long-press or double-tap on the handle to trigger selection).
+ */
+ public static final String ENABLE_INSERTION_HANDLE_GESTURES =
+ "CursorControlFeature__enable_insertion_handle_gestures";
+
+ /**
+ * The key used in app core settings for the flag {@link #ENABLE_INSERTION_HANDLE_GESTURES}.
+ */
+ public static final String KEY_ENABLE_INSERTION_HANDLE_GESTURES =
+ "widget__enable_insertion_handle_gestures";
+
+ /**
+ * Default value for the flag {@link #ENABLE_INSERTION_HANDLE_GESTURES}.
+ */
+ public static final boolean ENABLE_INSERTION_HANDLE_GESTURES_DEFAULT = false;
/**
* The flag of delta height applies to the insertion handle when cursor control flag is enabled.
- * The default value is 25.
*/
public static final String INSERTION_HANDLE_DELTA_HEIGHT =
"CursorControlFeature__insertion_handle_delta_height";
@@ -49,8 +71,13 @@ public final class WidgetFlags {
"widget__insertion_handle_delta_height";
/**
+ * Default value for the flag {@link #INSERTION_HANDLE_DELTA_HEIGHT}.
+ */
+ public static final int INSERTION_HANDLE_DELTA_HEIGHT_DEFAULT = 25;
+
+ /**
* The flag of opacity applies to the insertion handle when cursor control flag is enabled.
- * The opacity value is in the range of {0..100}. The default value is 50.
+ * The opacity value is in the range of {0..100}.
*/
public static final String INSERTION_HANDLE_OPACITY =
"CursorControlFeature__insertion_handle_opacity";
@@ -62,6 +89,11 @@ public final class WidgetFlags {
"widget__insertion_handle_opacity";
/**
+ * Default value for the flag {@link #INSERTION_HANDLE_OPACITY}.
+ */
+ public static final int INSERTION_HANDLE_OPACITY_DEFAULT = 50;
+
+ /**
* The flag of enabling the new magnifier.
*/
public static final String ENABLE_NEW_MAGNIFIER = "CursorControlFeature__enable_new_magnifier";
@@ -72,8 +104,12 @@ public final class WidgetFlags {
public static final String KEY_ENABLE_NEW_MAGNIFIER = "widget__enable_new_magnifier";
/**
+ * Default value for the flag {@link #ENABLE_NEW_MAGNIFIER}.
+ */
+ public static final boolean ENABLE_NEW_MAGNIFIER_DEFAULT = false;
+
+ /**
* The flag of zoom factor applies to the new magnifier.
- * The default value is 1.5f.
*/
public static final String MAGNIFIER_ZOOM_FACTOR =
"CursorControlFeature__magnifier_zoom_factor";
@@ -84,8 +120,12 @@ public final class WidgetFlags {
public static final String KEY_MAGNIFIER_ZOOM_FACTOR = "widget__magnifier_zoom_factor";
/**
+ * Default value for the flag {@link #MAGNIFIER_ZOOM_FACTOR}.
+ */
+ public static final float MAGNIFIER_ZOOM_FACTOR_DEFAULT = 1.5f;
+
+ /**
* The flag of aspect ratio (width/height) applies to the new magnifier.
- * The default value is 5.5f.
*/
public static final String MAGNIFIER_ASPECT_RATIO =
"CursorControlFeature__magnifier_aspect_ratio";
@@ -95,6 +135,11 @@ public final class WidgetFlags {
*/
public static final String KEY_MAGNIFIER_ASPECT_RATIO = "widget__magnifier_aspect_ratio";
+ /**
+ * Default value for the flag {@link #MAGNIFIER_ASPECT_RATIO}.
+ */
+ public static final float MAGNIFIER_ASPECT_RATIO_DEFAULT = 5.5f;
+
private WidgetFlags() {
}
}
diff --git a/core/java/com/android/internal/app/ChooserActivity.java b/core/java/com/android/internal/app/ChooserActivity.java
index a201a335622a..250b1ea5a4e9 100644
--- a/core/java/com/android/internal/app/ChooserActivity.java
+++ b/core/java/com/android/internal/app/ChooserActivity.java
@@ -1805,6 +1805,10 @@ public class ChooserActivity extends ResolverActivity implements
if (!TextUtils.isEmpty(dataString)) {
return new IntentFilter(intent.getAction(), dataString);
}
+ if (intent.getType() == null) {
+ Log.e(TAG, "Failed to get target intent filter: intent data and type are null");
+ return null;
+ }
IntentFilter intentFilter = new IntentFilter(intent.getAction(), intent.getType());
List<Uri> contentUris = new ArrayList<>();
if (Intent.ACTION_SEND.equals(intent.getAction())) {
@@ -1825,7 +1829,7 @@ public class ChooserActivity extends ResolverActivity implements
}
return intentFilter;
} catch (Exception e) {
- Log.e(TAG, "failed to get target intent filter", e);
+ Log.e(TAG, "Failed to get target intent filter", e);
return null;
}
}
diff --git a/core/java/com/android/internal/content/om/TEST_MAPPING b/core/java/com/android/internal/content/om/TEST_MAPPING
new file mode 100644
index 000000000000..4cb595b01681
--- /dev/null
+++ b/core/java/com/android/internal/content/om/TEST_MAPPING
@@ -0,0 +1,12 @@
+{
+ "presubmit": [
+ {
+ "name": "FrameworksCoreTests",
+ "options": [
+ {
+ "include-filter": "com.android.internal.content."
+ }
+ ]
+ }
+ ]
+} \ No newline at end of file
diff --git a/core/java/com/android/internal/os/PowerProfile.java b/core/java/com/android/internal/os/PowerProfile.java
index 3db8f4ed9408..add2304afe9d 100644
--- a/core/java/com/android/internal/os/PowerProfile.java
+++ b/core/java/com/android/internal/os/PowerProfile.java
@@ -393,6 +393,9 @@ public class PowerProfile {
}
public int getNumCoresInCpuCluster(int cluster) {
+ if (cluster < 0 || cluster >= mCpuClusters.length) {
+ return 0; // index out of bound
+ }
return mCpuClusters[cluster].numCpus;
}
diff --git a/core/java/com/android/internal/os/TEST_MAPPING b/core/java/com/android/internal/os/TEST_MAPPING
new file mode 100644
index 000000000000..f44b9fb7e723
--- /dev/null
+++ b/core/java/com/android/internal/os/TEST_MAPPING
@@ -0,0 +1,30 @@
+{
+ "presubmit": [
+ {
+ "name": "FrameworksCoreTests",
+ "options": [
+ {
+ "include-filter": "com.android.internal.os.KernelCpuUidFreqTimeReaderTest"
+ },
+ {
+ "include-filter": "com.android.internal.os.KernelCpuUidActiveTimeReaderTest"
+ },
+ {
+ "include-filter": "com.android.internal.os.KernelCpuUidClusterTimeReaderTest"
+ },
+ {
+ "include-filter": "com.android.internal.os.KernelSingleUidTimeReaderTest"
+ },
+ {
+ "include-filter": "com.android.internal.os.KernelCpuUidBpfMapReaderTest"
+ }
+
+ ],
+ "file_patterns": [
+ "KernelCpuUidTimeReader\\.java",
+ "KernelCpuUidBpfMapReader\\.java",
+ "KernelSingleUidTimeReader\\.java"
+ ]
+ }
+ ]
+}
diff --git a/core/java/com/android/internal/util/function/LongObjPredicate.java b/core/java/com/android/internal/util/function/LongObjPredicate.java
new file mode 100644
index 000000000000..9e4630744809
--- /dev/null
+++ b/core/java/com/android/internal/util/function/LongObjPredicate.java
@@ -0,0 +1,35 @@
+/*
+ * Copyright 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.android.internal.util.function;
+
+/**
+ * Represents a predicate (boolean-valued function) of a {@code long}-valued argument
+ * and an object-valued argument.
+ *
+ * @param <T> the type of the object-valued argument to the predicate
+ */
+@FunctionalInterface
+public interface LongObjPredicate<T> {
+ /**
+ * Evaluates this predicate on the given arguments.
+ *
+ * @param value the first input argument
+ * @param t the second input argument
+ * @return {@code true} if the input arguments match the predicate,
+ * otherwise {@code false}
+ */
+ boolean test(long value, T t);
+}
diff --git a/core/java/com/android/internal/view/FloatingActionMode.java b/core/java/com/android/internal/view/FloatingActionMode.java
index 69b1609377b7..633d6848030e 100644
--- a/core/java/com/android/internal/view/FloatingActionMode.java
+++ b/core/java/com/android/internal/view/FloatingActionMode.java
@@ -210,7 +210,7 @@ public final class FloatingActionMode extends ActionMode {
}
private boolean isContentRectWithinBounds() {
- mContext.getDisplay().getRealSize(mDisplaySize);
+ mContext.getDisplayNoVerify().getRealSize(mDisplaySize);
mScreenRect.set(0, 0, mDisplaySize.x, mDisplaySize.y);
return intersectsClosed(mContentRectOnScreen, mScreenRect)
diff --git a/core/java/com/android/internal/view/IInputMethodClient.aidl b/core/java/com/android/internal/view/IInputMethodClient.aidl
index 41f902e2f852..45090320c192 100644
--- a/core/java/com/android/internal/view/IInputMethodClient.aidl
+++ b/core/java/com/android/internal/view/IInputMethodClient.aidl
@@ -28,6 +28,7 @@ oneway interface IInputMethodClient {
void onBindMethod(in InputBindResult res);
void onUnbindMethod(int sequence, int unbindReason);
void setActive(boolean active, boolean fullscreen);
+ void scheduleStartInputIfNecessary(boolean fullscreen);
void reportFullscreenMode(boolean fullscreen);
void reportPreRendered(in EditorInfo info);
void applyImeVisibility(boolean setVisible);
diff --git a/core/java/com/android/internal/view/InputBindResult.java b/core/java/com/android/internal/view/InputBindResult.java
index a5964b509b3c..f29e95ccdf65 100644
--- a/core/java/com/android/internal/view/InputBindResult.java
+++ b/core/java/com/android/internal/view/InputBindResult.java
@@ -89,57 +89,64 @@ public final class InputBindResult implements Parcelable {
*/
int SUCCESS_WAITING_IME_BINDING = 2;
/**
+ * Indicates that {@link com.android.server.inputmethod.InputMethodManagerService} has a
+ * pending operation to switch to a different user.
+ *
+ * <p>Note that in this state even what would be the next current IME is not determined.</p>
+ */
+ int SUCCESS_WAITING_USER_SWITCHING = 3;
+ /**
* Indicates that this is not intended for starting input but just for reporting window
* focus change from the application process.
*
* <p>All other fields do not have meaningful value.</p>
*/
- int SUCCESS_REPORT_WINDOW_FOCUS_ONLY = 3;
+ int SUCCESS_REPORT_WINDOW_FOCUS_ONLY = 4;
/**
* Indicates somehow
* {@link
* com.android.server.inputmethod.InputMethodManagerService#startInputOrWindowGainedFocus}
* is trying to return null {@link InputBindResult}, which must never happen.
*/
- int ERROR_NULL = 4;
+ int ERROR_NULL = 5;
/**
* Indicates that {@link com.android.server.inputmethod.InputMethodManagerService}
* recognizes no IME.
*/
- int ERROR_NO_IME = 5;
+ int ERROR_NO_IME = 6;
/**
* Indicates that {@link android.view.inputmethod.EditorInfo#packageName} does not match
* the caller UID.
*
* @see android.view.inputmethod.EditorInfo#packageName
*/
- int ERROR_INVALID_PACKAGE_NAME = 6;
+ int ERROR_INVALID_PACKAGE_NAME = 7;
/**
* Indicates that the system is still in an early stage of the boot process and any 3rd
* party application is not allowed to run.
*
* @see com.android.server.SystemService#PHASE_THIRD_PARTY_APPS_CAN_START
*/
- int ERROR_SYSTEM_NOT_READY = 7;
+ int ERROR_SYSTEM_NOT_READY = 8;
/**
* Indicates that {@link com.android.server.inputmethod.InputMethodManagerService} tried to
* connect to an {@link android.inputmethodservice.InputMethodService} but failed.
*
* @see android.content.Context#bindServiceAsUser(Intent, ServiceConnection, int, UserHandle)
*/
- int ERROR_IME_NOT_CONNECTED = 8;
+ int ERROR_IME_NOT_CONNECTED = 9;
/**
* Indicates that the caller is not the foreground user, does not have
* {@link android.Manifest.permission#INTERACT_ACROSS_USERS_FULL} permission, or the user
* specified in {@link android.view.inputmethod.EditorInfo#targetInputMethodUser} is not
* running.
*/
- int ERROR_INVALID_USER = 9;
+ int ERROR_INVALID_USER = 10;
/**
* Indicates that the caller should have specified non-null
* {@link android.view.inputmethod.EditorInfo}.
*/
- int ERROR_NULL_EDITOR_INFO = 10;
+ int ERROR_NULL_EDITOR_INFO = 11;
/**
* Indicates that the target window the client specified cannot be the IME target right now.
*
@@ -149,24 +156,24 @@ public final class InputBindResult implements Parcelable {
*
* @see com.android.server.wm.WindowManagerInternal#isInputMethodClientFocus(int, int, int)
*/
- int ERROR_NOT_IME_TARGET_WINDOW = 11;
+ int ERROR_NOT_IME_TARGET_WINDOW = 12;
/**
* Indicates that focused view in the current window is not an editor.
*/
- int ERROR_NO_EDITOR = 12;
+ int ERROR_NO_EDITOR = 13;
/**
* Indicates that there is a mismatch in display ID between IME client and focused Window.
*/
- int ERROR_DISPLAY_ID_MISMATCH = 13;
+ int ERROR_DISPLAY_ID_MISMATCH = 14;
/**
* Indicates that current IME client is no longer allowed to access to the associated
* display.
*/
- int ERROR_INVALID_DISPLAY_ID = 14;
+ int ERROR_INVALID_DISPLAY_ID = 15;
/**
* Indicates that the client is not recognized by the system.
*/
- int ERROR_INVALID_CLIENT = 15;
+ int ERROR_INVALID_CLIENT = 16;
}
@ResultCode
@@ -299,6 +306,8 @@ public final class InputBindResult implements Parcelable {
return "SUCCESS_WAITING_IME_SESSION";
case ResultCode.SUCCESS_WAITING_IME_BINDING:
return "SUCCESS_WAITING_IME_BINDING";
+ case ResultCode.SUCCESS_WAITING_USER_SWITCHING:
+ return "SUCCESS_WAITING_USER_SWITCHING";
case ResultCode.SUCCESS_REPORT_WINDOW_FOCUS_ONLY:
return "SUCCESS_REPORT_WINDOW_FOCUS_ONLY";
case ResultCode.ERROR_NULL:
@@ -386,4 +395,11 @@ public final class InputBindResult implements Parcelable {
* Predefined error object for {@link ResultCode#ERROR_INVALID_CLIENT}.
*/
public static final InputBindResult INVALID_CLIENT = error(ResultCode.ERROR_INVALID_CLIENT);
+
+ /**
+ * Predefined <strong>success</strong> object for
+ * {@link ResultCode#SUCCESS_WAITING_USER_SWITCHING}.
+ */
+ public static final InputBindResult USER_SWITCHING =
+ error(ResultCode.SUCCESS_WAITING_USER_SWITCHING);
}
diff --git a/core/java/com/android/internal/view/RotationPolicy.java b/core/java/com/android/internal/view/RotationPolicy.java
index 13425e5e9bec..cfb2bf9df9ed 100644
--- a/core/java/com/android/internal/view/RotationPolicy.java
+++ b/core/java/com/android/internal/view/RotationPolicy.java
@@ -77,10 +77,7 @@ public final class RotationPolicy {
final Point size = new Point();
final IWindowManager wm = WindowManagerGlobal.getWindowManagerService();
try {
- final Display display = context.getDisplay();
- final int displayId = display != null
- ? display.getDisplayId()
- : Display.DEFAULT_DISPLAY;
+ final int displayId = context.getDisplayId();
wm.getInitialDisplaySize(displayId, size);
return size.x < size.y ?
Configuration.ORIENTATION_PORTRAIT : Configuration.ORIENTATION_LANDSCAPE;
diff --git a/core/jni/android_os_storage_StorageManager.cpp b/core/jni/android_os_storage_StorageManager.cpp
index aee6733ecf53..fd3e66b1bbce 100644
--- a/core/jni/android_os_storage_StorageManager.cpp
+++ b/core/jni/android_os_storage_StorageManager.cpp
@@ -15,6 +15,7 @@
*/
#define LOG_TAG "StorageManager"
+#include <android-base/file.h>
#include <android-base/logging.h>
#include <android-base/unique_fd.h>
#include <fcntl.h>
@@ -25,11 +26,30 @@
namespace android {
+static const char* kProcFilesystems = "/proc/filesystems";
+
+// Checks whether the passed in filesystem is listed in /proc/filesystems
+static bool IsFilesystemSupported(const std::string& fsType) {
+ std::string supported;
+ if (!android::base::ReadFileToString(kProcFilesystems, &supported)) {
+ PLOG(ERROR) << "Failed to read supported filesystems";
+ return false;
+ }
+ return supported.find(fsType + "\n") != std::string::npos;
+}
+
jboolean android_os_storage_StorageManager_setQuotaProjectId(JNIEnv* env, jobject self,
jstring path, jlong projectId) {
struct fsxattr fsx;
ScopedUtfChars utf_chars_path(env, path);
+ static bool sdcardFsSupported = IsFilesystemSupported("sdcardfs");
+ if (sdcardFsSupported) {
+ // sdcardfs doesn't support project ID quota tracking and takes care of quota
+ // in a different way.
+ return JNI_TRUE;
+ }
+
if (projectId > UINT32_MAX) {
LOG(ERROR) << "Invalid project id: " << projectId;
return JNI_FALSE;
diff --git a/core/jni/android_view_ThreadedRenderer.cpp b/core/jni/android_view_ThreadedRenderer.cpp
index 27c5a7302ba4..93449ffeae1b 100644
--- a/core/jni/android_view_ThreadedRenderer.cpp
+++ b/core/jni/android_view_ThreadedRenderer.cpp
@@ -186,6 +186,7 @@ static void android_view_ThreadedRenderer_setSurface(JNIEnv* env, jobject clazz,
proxy->setSwapBehavior(SwapBehavior::kSwap_discardBuffer);
}
proxy->setSurface(window, enableTimeout);
+ ANativeWindow_release(window);
}
static jboolean android_view_ThreadedRenderer_pause(JNIEnv* env, jobject clazz,
diff --git a/core/jni/core_jni_helpers.h b/core/jni/core_jni_helpers.h
index f03f42737134..8bb4d503cc82 100644
--- a/core/jni/core_jni_helpers.h
+++ b/core/jni/core_jni_helpers.h
@@ -47,28 +47,32 @@ static inline jclass FindClassOrDie(JNIEnv* env, const char* class_name) {
static inline jfieldID GetFieldIDOrDie(JNIEnv* env, jclass clazz, const char* field_name,
const char* field_signature) {
jfieldID res = env->GetFieldID(clazz, field_name, field_signature);
- LOG_ALWAYS_FATAL_IF(res == NULL, "Unable to find static field %s", field_name);
+ LOG_ALWAYS_FATAL_IF(res == NULL, "Unable to find static field %s with signature %s", field_name,
+ field_signature);
return res;
}
static inline jmethodID GetMethodIDOrDie(JNIEnv* env, jclass clazz, const char* method_name,
const char* method_signature) {
jmethodID res = env->GetMethodID(clazz, method_name, method_signature);
- LOG_ALWAYS_FATAL_IF(res == NULL, "Unable to find method %s", method_name);
+ LOG_ALWAYS_FATAL_IF(res == NULL, "Unable to find method %s with signature %s", method_name,
+ method_signature);
return res;
}
static inline jfieldID GetStaticFieldIDOrDie(JNIEnv* env, jclass clazz, const char* field_name,
const char* field_signature) {
jfieldID res = env->GetStaticFieldID(clazz, field_name, field_signature);
- LOG_ALWAYS_FATAL_IF(res == NULL, "Unable to find static field %s", field_name);
+ LOG_ALWAYS_FATAL_IF(res == NULL, "Unable to find static field %s with signature %s", field_name,
+ field_signature);
return res;
}
static inline jmethodID GetStaticMethodIDOrDie(JNIEnv* env, jclass clazz, const char* method_name,
const char* method_signature) {
jmethodID res = env->GetStaticMethodID(clazz, method_name, method_signature);
- LOG_ALWAYS_FATAL_IF(res == NULL, "Unable to find static method %s", method_name);
+ LOG_ALWAYS_FATAL_IF(res == NULL, "Unable to find static method %s with signature %s",
+ method_name, method_signature);
return res;
}
diff --git a/core/res/AndroidManifest.xml b/core/res/AndroidManifest.xml
index ddfc4b8e94a4..814b8acd63ac 100644
--- a/core/res/AndroidManifest.xml
+++ b/core/res/AndroidManifest.xml
@@ -3084,8 +3084,7 @@
<!-- Allows SystemUI to request third party controls.
<p>Should only be requested by the System and required by
- ControlsService declarations.
- @hide
+ {@link android.service.controls.ControlsProviderService} declarations.
-->
<permission android:name="android.permission.BIND_CONTROLS"
android:protectionLevel="signature" />
diff --git a/core/res/res/values/config.xml b/core/res/res/values/config.xml
index 6ca50811115e..68c86b263a75 100644
--- a/core/res/res/values/config.xml
+++ b/core/res/res/values/config.xml
@@ -2460,6 +2460,12 @@
rmem_min,rmem_def,rmem_max,wmem_min,wmem_def,wmem_max -->
<string name="config_ethernet_tcp_buffers" translatable="false">524288,1048576,3145728,524288,1048576,2097152</string>
+ <!-- What source to use to estimate link upstream and downstream bandwidth capacities.
+ Default is carrier_config, but it should be set to modem if the modem is returning
+ predictive (instead of instantaneous) bandwidth estimate.
+ Values are carrier_config and modem. -->
+ <string name="config_bandwidthEstimateSource">carrier_config</string>
+
<!-- Whether WiFi display is supported by this device.
There are many prerequisites for this feature to work correctly.
Here are a few of them:
diff --git a/core/res/res/values/symbols.xml b/core/res/res/values/symbols.xml
index 85c2a2a24749..1c9e2cd72f28 100644
--- a/core/res/res/values/symbols.xml
+++ b/core/res/res/values/symbols.xml
@@ -473,6 +473,7 @@
<java-symbol type="integer" name="config_num_physical_slots" />
<java-symbol type="array" name="config_integrityRuleProviderPackages" />
<java-symbol type="bool" name="config_useAssistantVolume" />
+ <java-symbol type="string" name="config_bandwidthEstimateSource" />
<java-symbol type="color" name="tab_indicator_text_v4" />
diff --git a/core/res/res/xml/power_profile.xml b/core/res/res/xml/power_profile.xml
index 899d630a51b7..d8ec72f33ddc 100644
--- a/core/res/res/xml/power_profile.xml
+++ b/core/res/res/xml/power_profile.xml
@@ -51,6 +51,12 @@
<value>0.1</value> <!-- ~1mA -->
</array>
+ <!-- Additional power consumption by CPU excluding cluster and core when
+ running -->
+ <array name="cpu.active">
+ <value>0.1</value>
+ </array>
+
<!-- A list of heterogeneous CPU clusters, where the value for each cluster represents the
number of CPU cores for that cluster.
diff --git a/core/tests/coretests/src/android/content/ContentResolverTest.java b/core/tests/coretests/src/android/content/ContentResolverTest.java
index 78c4420b9496..1737bd0fa20b 100644
--- a/core/tests/coretests/src/android/content/ContentResolverTest.java
+++ b/core/tests/coretests/src/android/content/ContentResolverTest.java
@@ -234,4 +234,12 @@ public class ContentResolverTest {
assertThat(type).isNull();
assertThat(end).isLessThan(start + 5000);
}
+
+ @Test
+ public void testCanonicalize() {
+ Uri canonical = mResolver.canonicalize(
+ Uri.parse("content://android.content.FakeProviderRemote/something"));
+ assertThat(canonical).isEqualTo(
+ Uri.parse("content://android.content.FakeProviderRemote/canonical"));
+ }
}
diff --git a/core/tests/coretests/src/android/content/ContextTest.java b/core/tests/coretests/src/android/content/ContextTest.java
index f074233070d1..f0997a68492b 100644
--- a/core/tests/coretests/src/android/content/ContextTest.java
+++ b/core/tests/coretests/src/android/content/ContextTest.java
@@ -16,11 +16,13 @@
package android.content;
+import static android.view.Display.DEFAULT_DISPLAY;
+
import static org.junit.Assert.assertEquals;
import android.app.ActivityThread;
+import android.hardware.display.DisplayManager;
import android.os.UserHandle;
-import android.view.WindowManager;
import androidx.test.InstrumentationRegistry;
import androidx.test.filters.SmallTest;
@@ -45,17 +47,16 @@ public class ContextTest {
final Context testContext =
InstrumentationRegistry.getInstrumentation().getTargetContext();
- assertEquals(testContext.getDisplay().getDisplayId(), testContext.getDisplayId());
+ assertEquals(testContext.getDisplayNoVerify().getDisplayId(), testContext.getDisplayId());
}
- // TODO(b/128338354): Re-visit this test after introducing WindowContext
@Test
public void testDisplayIdForDefaultDisplayContext() {
final Context testContext =
InstrumentationRegistry.getInstrumentation().getTargetContext();
- final WindowManager wm = testContext.getSystemService(WindowManager.class);
+ final DisplayManager dm = testContext.getSystemService(DisplayManager.class);
final Context defaultDisplayContext =
- testContext.createDisplayContext(wm.getDefaultDisplay());
+ testContext.createDisplayContext(dm.getDisplay(DEFAULT_DISPLAY));
assertEquals(defaultDisplayContext.getDisplay().getDisplayId(),
defaultDisplayContext.getDisplayId());
diff --git a/core/tests/coretests/src/android/content/FakeProviderRemote.java b/core/tests/coretests/src/android/content/FakeProviderRemote.java
index 7b9bdbcd7a17..1d7ba5d9be46 100644
--- a/core/tests/coretests/src/android/content/FakeProviderRemote.java
+++ b/core/tests/coretests/src/android/content/FakeProviderRemote.java
@@ -54,4 +54,10 @@ public class FakeProviderRemote extends ContentProvider {
public int update(Uri uri, ContentValues values, String selection, String[] selectionArgs) {
return 0;
}
+
+ @Override
+ public Uri canonicalize(Uri uri) {
+ return new Uri.Builder().scheme(uri.getScheme()).authority(uri.getAuthority())
+ .appendPath("canonical").build();
+ }
}
diff --git a/core/tests/coretests/src/android/service/controls/ControlProviderServiceTest.java b/core/tests/coretests/src/android/service/controls/ControlProviderServiceTest.java
index 78c88d71d953..4c2ca7eefcc1 100644
--- a/core/tests/coretests/src/android/service/controls/ControlProviderServiceTest.java
+++ b/core/tests/coretests/src/android/service/controls/ControlProviderServiceTest.java
@@ -25,9 +25,13 @@ import static org.mockito.Mockito.times;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
+import android.Manifest;
import android.app.PendingIntent;
+import android.content.ComponentName;
+import android.content.Context;
import android.content.IIntentSender;
import android.content.Intent;
+import android.content.res.Resources;
import android.os.Binder;
import android.os.Bundle;
import android.os.IBinder;
@@ -44,6 +48,7 @@ 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.MockitoAnnotations;
@@ -59,6 +64,11 @@ import java.util.function.Consumer;
@RunWith(AndroidJUnit4.class)
public class ControlProviderServiceTest {
+ private static final ComponentName TEST_SYSUI_COMPONENT =
+ ComponentName.unflattenFromString("sysui/.test.cls");
+ private static final ComponentName TEST_COMPONENT =
+ ComponentName.unflattenFromString("test.pkg/.test.cls");
+
private IBinder mToken = new Binder();
@Mock
private IControlsActionCallback.Stub mActionCallback;
@@ -66,6 +76,12 @@ public class ControlProviderServiceTest {
private IControlsSubscriber.Stub mSubscriber;
@Mock
private IIntentSender mIIntentSender;
+ @Mock
+ private Resources mResources;
+ @Mock
+ private Context mContext;
+ @Captor
+ private ArgumentCaptor<Intent> mIntentArgumentCaptor;
private PendingIntent mPendingIntent;
private FakeControlsProviderService mControlsProviderService;
@@ -81,6 +97,10 @@ public class ControlProviderServiceTest {
when(mSubscriber.asBinder()).thenCallRealMethod();
when(mSubscriber.queryLocalInterface(any())).thenReturn(mSubscriber);
+ when(mResources.getString(com.android.internal.R.string.config_systemUIServiceComponent))
+ .thenReturn(TEST_SYSUI_COMPONENT.flattenToString());
+ when(mContext.getResources()).thenReturn(mResources);
+
Bundle b = new Bundle();
b.putBinder(ControlsProviderService.CALLBACK_TOKEN, mToken);
Intent intent = new Intent();
@@ -223,6 +243,21 @@ public class ControlProviderServiceTest {
ControlAction.RESPONSE_OK);
}
+ @Test
+ public void testRequestAdd() {
+ Control control = new Control.StatelessBuilder("TEST_ID", mPendingIntent).build();
+ ControlsProviderService.requestAddControl(mContext, TEST_COMPONENT, control);
+
+ verify(mContext).sendBroadcast(mIntentArgumentCaptor.capture(),
+ eq(Manifest.permission.BIND_CONTROLS));
+ Intent intent = mIntentArgumentCaptor.getValue();
+ assertEquals(ControlsProviderService.ACTION_ADD_CONTROL, intent.getAction());
+ assertEquals(TEST_SYSUI_COMPONENT.getPackageName(), intent.getPackage());
+ assertEquals(TEST_COMPONENT, intent.getParcelableExtra(Intent.EXTRA_COMPONENT_NAME));
+ assertTrue(equals(control,
+ intent.getParcelableExtra(ControlsProviderService.EXTRA_CONTROL)));
+ }
+
private static boolean equals(Control c1, Control c2) {
if (c1 == c2) return true;
if (c1 == null || c2 == null) return false;
diff --git a/core/tests/coretests/src/android/util/LongSparseArrayTest.java b/core/tests/coretests/src/android/util/LongSparseArrayTest.java
new file mode 100644
index 000000000000..bf3f0f50f4bf
--- /dev/null
+++ b/core/tests/coretests/src/android/util/LongSparseArrayTest.java
@@ -0,0 +1,54 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package android.util;
+
+import static com.google.common.truth.Truth.assertThat;
+
+import androidx.test.ext.junit.runners.AndroidJUnit4;
+import androidx.test.filters.SmallTest;
+
+import com.android.internal.util.function.LongObjPredicate;
+
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+/**
+ * Tests for {@link LongSparseArray}.
+ */
+@SmallTest
+@RunWith(AndroidJUnit4.class)
+public class LongSparseArrayTest {
+ @Test
+ public void testRemoveIf() {
+ final LongSparseArray<Integer> sparseArray = new LongSparseArray();
+ for (int i = 0; i < 10; ++i) {
+ for (int j = 100; j < 110; ++j) {
+ sparseArray.put(i, j);
+ sparseArray.put(-i, j);
+ sparseArray.put(j, -i);
+ sparseArray.put(-j, -i);
+ }
+ }
+
+ final LongObjPredicate<Integer> predicate = (value, obj) -> (value < 0 && obj < 0);
+ sparseArray.removeIf(predicate);
+
+ for (int i = 0; i < sparseArray.size(); ++i) {
+ assertThat(predicate.test(sparseArray.keyAt(i), sparseArray.valueAt(i)))
+ .isFalse();
+ }
+ }
+}
diff --git a/core/tests/coretests/src/android/view/CutoutSpecificationTest.java b/core/tests/coretests/src/android/view/CutoutSpecificationTest.java
index b41f90c4689e..7872810717b8 100644
--- a/core/tests/coretests/src/android/view/CutoutSpecificationTest.java
+++ b/core/tests/coretests/src/android/view/CutoutSpecificationTest.java
@@ -21,10 +21,27 @@ import static com.google.common.truth.Truth.assertThat;
import static org.testng.Assert.assertThrows;
import android.graphics.Rect;
+import android.platform.test.annotations.Presubmit;
+
+import androidx.test.filters.SmallTest;
+import androidx.test.runner.AndroidJUnit4;
import org.junit.Before;
import org.junit.Test;
+import org.junit.runner.RunWith;
+/**
+ * Tests for {@link CutoutSpecification} used by {@link DisplayCutout}.
+ *
+ * <p>Build/Install/Run:
+ * atest FrameworksCoreTests:CutoutSpecificationTest
+ *
+ * <p>This test class is a part of Window Manager Service tests and specified in
+ * {@link com.android.server.wm.test.filters.FrameworksTestsFilter}.
+ */
+@RunWith(AndroidJUnit4.class)
+@SmallTest
+@Presubmit
public class CutoutSpecificationTest {
private static final String WITHOUT_BIND_CUTOUT_SPECIFICATION = "M 0,0\n"
+ "h 48\n"
@@ -344,7 +361,7 @@ public class CutoutSpecificationTest {
.parse("@bottom"
+ "M 0,0\n"
+ "v -10\n"
- + "h 10\n"
+ + "h -10\n"
+ "v 10\n"
+ "z\n"
+ "@right\n"
diff --git a/core/tests/coretests/src/android/view/ImeInsetsSourceConsumerTest.java b/core/tests/coretests/src/android/view/ImeInsetsSourceConsumerTest.java
index 7c78bce25b1c..7f0e0d2f54c7 100644
--- a/core/tests/coretests/src/android/view/ImeInsetsSourceConsumerTest.java
+++ b/core/tests/coretests/src/android/view/ImeInsetsSourceConsumerTest.java
@@ -61,7 +61,7 @@ public class ImeInsetsSourceConsumerTest {
.setName("testSurface")
.build();
InstrumentationRegistry.getInstrumentation().runOnMainSync(() -> {
- ViewRootImpl viewRootImpl = new ViewRootImpl(mContext, mContext.getDisplay());
+ ViewRootImpl viewRootImpl = new ViewRootImpl(mContext, mContext.getDisplayNoVerify());
try {
viewRootImpl.setView(new TextView(mContext), new LayoutParams(), null);
} catch (BadTokenException e) {
diff --git a/core/tests/coretests/src/android/view/InsetsControllerTest.java b/core/tests/coretests/src/android/view/InsetsControllerTest.java
index 24fe2a0a1823..7737b1a2a776 100644
--- a/core/tests/coretests/src/android/view/InsetsControllerTest.java
+++ b/core/tests/coretests/src/android/view/InsetsControllerTest.java
@@ -110,7 +110,7 @@ public class InsetsControllerTest {
InstrumentationRegistry.getInstrumentation().runOnMainSync(() -> {
Context context = InstrumentationRegistry.getTargetContext();
// cannot mock ViewRootImpl since it's final.
- mViewRoot = new ViewRootImpl(context, context.getDisplay());
+ mViewRoot = new ViewRootImpl(context, context.getDisplayNoVerify());
try {
mViewRoot.setView(new TextView(context), new LayoutParams(), null);
} catch (BadTokenException e) {
diff --git a/core/tests/coretests/src/android/view/InsetsSourceConsumerTest.java b/core/tests/coretests/src/android/view/InsetsSourceConsumerTest.java
index 5e9e2f0065ed..754c6791cade 100644
--- a/core/tests/coretests/src/android/view/InsetsSourceConsumerTest.java
+++ b/core/tests/coretests/src/android/view/InsetsSourceConsumerTest.java
@@ -77,7 +77,8 @@ public class InsetsSourceConsumerTest {
instrumentation.runOnMainSync(() -> {
final Context context = instrumentation.getTargetContext();
// cannot mock ViewRootImpl since it's final.
- final ViewRootImpl viewRootImpl = new ViewRootImpl(context, context.getDisplay());
+ final ViewRootImpl viewRootImpl = new ViewRootImpl(context,
+ context.getDisplayNoVerify());
try {
viewRootImpl.setView(new TextView(context), new LayoutParams(), null);
} catch (BadTokenException e) {
diff --git a/core/tests/coretests/src/android/view/ViewRootImplTest.java b/core/tests/coretests/src/android/view/ViewRootImplTest.java
index df6ed8c3fe0d..e2adbcc600d7 100644
--- a/core/tests/coretests/src/android/view/ViewRootImplTest.java
+++ b/core/tests/coretests/src/android/view/ViewRootImplTest.java
@@ -61,7 +61,7 @@ public class ViewRootImplTest {
InstrumentationRegistry.getInstrumentation().runOnMainSync(() -> {
mViewRootImpl = new ViewRootImplAccessor(
- new ViewRootImpl(mContext, mContext.getDisplay()));
+ new ViewRootImpl(mContext, mContext.getDisplayNoVerify()));
});
}
diff --git a/core/tests/coretests/src/android/widget/EditorCursorDragTest.java b/core/tests/coretests/src/android/widget/EditorCursorDragTest.java
index d7abfcc7d6d2..0a094c61d4d5 100644
--- a/core/tests/coretests/src/android/widget/EditorCursorDragTest.java
+++ b/core/tests/coretests/src/android/widget/EditorCursorDragTest.java
@@ -50,7 +50,6 @@ import com.android.frameworks.coretests.R;
import com.google.common.base.Strings;
-import org.junit.After;
import org.junit.Before;
import org.junit.Rule;
import org.junit.Test;
@@ -69,7 +68,6 @@ public class EditorCursorDragTest {
public ActivityTestRule<TextViewActivity> mActivityRule = new ActivityTestRule<>(
TextViewActivity.class);
- private boolean mOriginalFlagValue;
private Instrumentation mInstrumentation;
private Activity mActivity;
@@ -77,13 +75,6 @@ public class EditorCursorDragTest {
public void before() throws Throwable {
mInstrumentation = InstrumentationRegistry.getInstrumentation();
mActivity = mActivityRule.getActivity();
- mOriginalFlagValue = Editor.FLAG_ENABLE_CURSOR_DRAG;
- Editor.FLAG_ENABLE_CURSOR_DRAG = true;
- }
-
- @After
- public void after() throws Throwable {
- Editor.FLAG_ENABLE_CURSOR_DRAG = mOriginalFlagValue;
}
@Test
diff --git a/core/tests/coretests/src/android/widget/TextViewActivityTest.java b/core/tests/coretests/src/android/widget/TextViewActivityTest.java
index 0c38e7136655..88a6f9e4af4b 100644
--- a/core/tests/coretests/src/android/widget/TextViewActivityTest.java
+++ b/core/tests/coretests/src/android/widget/TextViewActivityTest.java
@@ -31,8 +31,8 @@ import static android.widget.espresso.TextViewActions.doubleTapAndDragHandle;
import static android.widget.espresso.TextViewActions.doubleTapAndDragOnText;
import static android.widget.espresso.TextViewActions.doubleTapHandle;
import static android.widget.espresso.TextViewActions.dragHandle;
-import static android.widget.espresso.TextViewActions.longPressAndDragOnText;
import static android.widget.espresso.TextViewActions.longPressAndDragHandle;
+import static android.widget.espresso.TextViewActions.longPressAndDragOnText;
import static android.widget.espresso.TextViewActions.longPressHandle;
import static android.widget.espresso.TextViewActions.longPressOnTextAtIndex;
import static android.widget.espresso.TextViewAssertions.doesNotHaveStyledText;
@@ -514,29 +514,26 @@ public class TextViewActivityTest {
onView(withId(R.id.textview)).check(hasInsertionPointerAtIndex(text.indexOf("f")));
}
- @Test
- public void testInsertionHandle_touchThrough() {
+ private void enableFlagsForInsertionHandleGestures() {
final TextView textView = mActivity.findViewById(R.id.textview);
- boolean cursorControlEnabled = textView.getEditorForTesting().getCursorControlEnabled();
- boolean cursorDragEnabled = Editor.FLAG_ENABLE_CURSOR_DRAG;
- textView.getEditorForTesting().setCursorControlEnabled(true);
- Editor.FLAG_ENABLE_CURSOR_DRAG = true;
+ final Editor editor = textView.getEditorForTesting();
+ editor.setFlagCursorDragFromAnywhereEnabled(true);
+ editor.setFlagInsertionHandleGesturesEnabled(true);
+ // Note: We don't need to reset these flags explicitly at the end of each test, because a
+ // fresh TextView and Editor will be created for each test.
+ }
+ @Test
+ public void testInsertionHandle_touchThrough() {
+ enableFlagsForInsertionHandleGestures();
testInsertionHandle();
testInsertionHandle_multiLine();
-
- textView.getEditorForTesting().setCursorControlEnabled(cursorControlEnabled);
- Editor.FLAG_ENABLE_CURSOR_DRAG = cursorDragEnabled;
}
@Test
public void testInsertionHandle_longPressToSelect() {
- // This test only makes sense when Cursor Control flag is enabled.
+ enableFlagsForInsertionHandleGestures();
final TextView textView = mActivity.findViewById(R.id.textview);
- boolean cursorControlEnabled = textView.getEditorForTesting().getCursorControlEnabled();
- boolean cursorDragEnabled = Editor.FLAG_ENABLE_CURSOR_DRAG;
- textView.getEditorForTesting().setCursorControlEnabled(true);
- Editor.FLAG_ENABLE_CURSOR_DRAG = true;
final String text = "hello the world";
onView(withId(R.id.textview)).perform(replaceText(text));
@@ -546,20 +543,12 @@ public class TextViewActivityTest {
onHandleView(com.android.internal.R.id.insertion_handle).perform(longPressHandle(textView));
onView(withId(R.id.textview)).check(hasSelection("world"));
-
- textView.getEditorForTesting().setCursorControlEnabled(cursorControlEnabled);
- Editor.FLAG_ENABLE_CURSOR_DRAG = cursorDragEnabled;
}
@Test
public void testInsertionHandle_longPressAndDragToSelect() {
- // This test only makes sense when Cursor Control flag is enabled.
+ enableFlagsForInsertionHandleGestures();
final TextView textView = mActivity.findViewById(R.id.textview);
- boolean cursorControlEnabled = textView.getEditorForTesting().getCursorControlEnabled();
- boolean cursorDragEnabled = Editor.FLAG_ENABLE_CURSOR_DRAG;
- textView.getEditorForTesting().setCursorControlEnabled(true);
- Editor.FLAG_ENABLE_CURSOR_DRAG = true;
-
final String text = "hello the world";
onView(withId(R.id.textview)).perform(replaceText(text));
@@ -569,19 +558,12 @@ public class TextViewActivityTest {
onHandleView(com.android.internal.R.id.insertion_handle)
.perform(longPressAndDragHandle(textView, Handle.INSERTION, text.indexOf('t')));
onView(withId(R.id.textview)).check(hasSelection("the world"));
-
- textView.getEditorForTesting().setCursorControlEnabled(cursorControlEnabled);
- Editor.FLAG_ENABLE_CURSOR_DRAG = cursorDragEnabled;
}
@Test
public void testInsertionHandle_doubleTapToSelect() {
- // This test only makes sense when Cursor Control flag is enabled.
+ enableFlagsForInsertionHandleGestures();
final TextView textView = mActivity.findViewById(R.id.textview);
- boolean cursorControlEnabled = textView.getEditorForTesting().getCursorControlEnabled();
- boolean cursorDragEnabled = Editor.FLAG_ENABLE_CURSOR_DRAG;
- textView.getEditorForTesting().setCursorControlEnabled(true);
- Editor.FLAG_ENABLE_CURSOR_DRAG = true;
final String text = "hello the world";
onView(withId(R.id.textview)).perform(replaceText(text));
@@ -591,19 +573,12 @@ public class TextViewActivityTest {
onHandleView(com.android.internal.R.id.insertion_handle).perform(doubleTapHandle(textView));
onView(withId(R.id.textview)).check(hasSelection("world"));
-
- textView.getEditorForTesting().setCursorControlEnabled(cursorControlEnabled);
- Editor.FLAG_ENABLE_CURSOR_DRAG = cursorDragEnabled;
}
@Test
public void testInsertionHandle_doubleTapAndDragToSelect() {
- // This test only makes sense when Cursor Control flag is enabled.
+ enableFlagsForInsertionHandleGestures();
final TextView textView = mActivity.findViewById(R.id.textview);
- boolean cursorControlEnabled = textView.getEditorForTesting().getCursorControlEnabled();
- boolean cursorDragEnabled = Editor.FLAG_ENABLE_CURSOR_DRAG;
- textView.getEditorForTesting().setCursorControlEnabled(true);
- Editor.FLAG_ENABLE_CURSOR_DRAG = true;
final String text = "hello the world";
onView(withId(R.id.textview)).perform(replaceText(text));
@@ -614,9 +589,6 @@ public class TextViewActivityTest {
onHandleView(com.android.internal.R.id.insertion_handle)
.perform(doubleTapAndDragHandle(textView, Handle.INSERTION, text.indexOf('t')));
onView(withId(R.id.textview)).check(hasSelection("the world"));
-
- textView.getEditorForTesting().setCursorControlEnabled(cursorControlEnabled);
- Editor.FLAG_ENABLE_CURSOR_DRAG = cursorDragEnabled;
}
@Test
diff --git a/core/tests/coretests/src/com/android/internal/policy/DecorContextTest.java b/core/tests/coretests/src/com/android/internal/policy/DecorContextTest.java
index cdcf23fc10bb..3e40466e4b64 100644
--- a/core/tests/coretests/src/com/android/internal/policy/DecorContextTest.java
+++ b/core/tests/coretests/src/com/android/internal/policy/DecorContextTest.java
@@ -53,7 +53,10 @@ public final class DecorContextTest {
@Test
public void testDecorContextWithDefaultDisplay() {
- DecorContext context = new DecorContext(mContext.getApplicationContext(), mContext);
+ Display defaultDisplay = new Display(DisplayManagerGlobal.getInstance(), DEFAULT_DISPLAY,
+ new DisplayInfo(), DisplayAdjustments.DEFAULT_DISPLAY_ADJUSTMENTS);
+ DecorContext context = new DecorContext(mContext.getApplicationContext(),
+ mContext.createDisplayContext(defaultDisplay));
assertDecorContextDisplay(DEFAULT_DISPLAY, context);
}
diff --git a/libs/hwui/hwui/Bitmap.cpp b/libs/hwui/hwui/Bitmap.cpp
index 914c04645289..56d951cdb338 100644
--- a/libs/hwui/hwui/Bitmap.cpp
+++ b/libs/hwui/hwui/Bitmap.cpp
@@ -150,11 +150,7 @@ sk_sp<Bitmap> Bitmap::createFrom(AHardwareBuffer* hardwareBuffer, sk_sp<SkColorS
AHardwareBuffer_Desc bufferDesc;
AHardwareBuffer_describe(hardwareBuffer, &bufferDesc);
SkImageInfo info = uirenderer::BufferDescriptionToImageInfo(bufferDesc, colorSpace);
-
- // If the stride is 0 we have to use the width as an approximation (eg, compressed buffer)
- const auto bufferStride = bufferDesc.stride > 0 ? bufferDesc.stride : bufferDesc.width;
- const size_t rowBytes = info.bytesPerPixel() * bufferStride;
- return sk_sp<Bitmap>(new Bitmap(hardwareBuffer, info, rowBytes, palette));
+ return createFrom(hardwareBuffer, info, bufferDesc, palette);
}
sk_sp<Bitmap> Bitmap::createFrom(AHardwareBuffer* hardwareBuffer, SkColorType colorType,
@@ -164,8 +160,14 @@ sk_sp<Bitmap> Bitmap::createFrom(AHardwareBuffer* hardwareBuffer, SkColorType co
AHardwareBuffer_describe(hardwareBuffer, &bufferDesc);
SkImageInfo info = SkImageInfo::Make(bufferDesc.width, bufferDesc.height,
colorType, alphaType, colorSpace);
+ return createFrom(hardwareBuffer, info, bufferDesc, palette);
+}
- const size_t rowBytes = info.bytesPerPixel() * bufferDesc.stride;
+sk_sp<Bitmap> Bitmap::createFrom(AHardwareBuffer* hardwareBuffer, const SkImageInfo& info,
+ const AHardwareBuffer_Desc& bufferDesc, BitmapPalette palette) {
+ // If the stride is 0 we have to use the width as an approximation (eg, compressed buffer)
+ const auto bufferStride = bufferDesc.stride > 0 ? bufferDesc.stride : bufferDesc.width;
+ const size_t rowBytes = info.bytesPerPixel() * bufferStride;
return sk_sp<Bitmap>(new Bitmap(hardwareBuffer, info, rowBytes, palette));
}
#endif
diff --git a/libs/hwui/hwui/Bitmap.h b/libs/hwui/hwui/Bitmap.h
index 3bfb7800f735..b8b59947a57b 100644
--- a/libs/hwui/hwui/Bitmap.h
+++ b/libs/hwui/hwui/Bitmap.h
@@ -169,6 +169,12 @@ private:
#ifdef __ANDROID__ // Layoutlib does not support hardware acceleration
Bitmap(AHardwareBuffer* buffer, const SkImageInfo& info, size_t rowBytes,
BitmapPalette palette);
+
+ // Common code for the two public facing createFrom(AHardwareBuffer*, ...)
+ // methods.
+ // bufferDesc is only used to compute rowBytes.
+ static sk_sp<Bitmap> createFrom(AHardwareBuffer* hardwareBuffer, const SkImageInfo& info,
+ const AHardwareBuffer_Desc& bufferDesc, BitmapPalette palette);
#endif
virtual ~Bitmap();
diff --git a/libs/usb/Android.bp b/libs/usb/Android.bp
index 027a7488f723..e752b55f5ef7 100644
--- a/libs/usb/Android.bp
+++ b/libs/usb/Android.bp
@@ -19,5 +19,3 @@ java_sdk_library {
srcs: ["src/**/*.java"],
api_packages: ["com.android.future.usb"],
}
-
-subdirs = ["tests/*"]
diff --git a/libs/usb/tests/AccessoryChat/Android.bp b/libs/usb/tests/AccessoryChat/Android.bp
index 63a670c67bfc..19ed3d3ef52e 100644
--- a/libs/usb/tests/AccessoryChat/Android.bp
+++ b/libs/usb/tests/AccessoryChat/Android.bp
@@ -1,4 +1,3 @@
-subdirs = ["accessorychat"]
//
// Copyright (C) 2011 The Android Open Source Project
//
diff --git a/location/java/android/location/LocationManagerInternal.java b/location/java/android/location/LocationManagerInternal.java
index 085602cbcd4f..6006d5079b07 100644
--- a/location/java/android/location/LocationManagerInternal.java
+++ b/location/java/android/location/LocationManagerInternal.java
@@ -27,22 +27,6 @@ import android.annotation.NonNull;
public abstract class LocationManagerInternal {
/**
- * Requests that a provider change its allowed state. A provider may or may not honor this
- * request, and if the provider does change its state as a result, that may happen
- * asynchronously after some delay.
- *
- * <p>Setting a provider's state to allowed implies that any consents or terms and conditions
- * that may be necessary to allow the provider are agreed to. Setting a providers state to
- * disallowed implies that any consents or terms and conditions have their agreement revoked.
- *
- * @param provider A location provider as listed by {@link LocationManager#getAllProviders()}
- * @param allowed Whether the location provider is being requested to allow or disallow
- * itself
- * @throws IllegalArgumentException if provider is null
- */
- public abstract void requestSetProviderAllowed(@NonNull String provider, boolean allowed);
-
- /**
* Returns true if the given provider is enabled for the given user.
*
* @param provider A location provider as listed by {@link LocationManager#getAllProviders()}
diff --git a/location/java/com/android/internal/location/ILocationProvider.aidl b/location/java/com/android/internal/location/ILocationProvider.aidl
index b7817ff1e1fc..4246c6cd1004 100644
--- a/location/java/com/android/internal/location/ILocationProvider.aidl
+++ b/location/java/com/android/internal/location/ILocationProvider.aidl
@@ -37,6 +37,4 @@ interface ILocationProvider {
@UnsupportedAppUsage
oneway void sendExtraCommand(String command, in Bundle extras);
-
- oneway void requestSetAllowed(boolean allowed);
}
diff --git a/location/lib/api/current.txt b/location/lib/api/current.txt
index 49fcaabe981a..9cc30d0d751e 100644
--- a/location/lib/api/current.txt
+++ b/location/lib/api/current.txt
@@ -17,7 +17,6 @@ package com.android.location.provider {
method @Deprecated protected int onGetStatus(android.os.Bundle);
method @Deprecated protected long onGetStatusUpdateTime();
method protected void onInit();
- method protected void onRequestSetAllowed(boolean);
method protected boolean onSendExtraCommand(@Nullable String, @Nullable android.os.Bundle);
method protected abstract void onSetRequest(com.android.location.provider.ProviderRequestUnbundled, android.os.WorkSource);
method public void reportLocation(android.location.Location);
diff --git a/location/lib/java/com/android/location/provider/LocationProviderBase.java b/location/lib/java/com/android/location/provider/LocationProviderBase.java
index bd29d8ac2a85..d3fb58fe257e 100644
--- a/location/lib/java/com/android/location/provider/LocationProviderBase.java
+++ b/location/lib/java/com/android/location/provider/LocationProviderBase.java
@@ -315,17 +315,6 @@ public abstract class LocationProviderBase {
return false;
}
- /**
- * Invoked when the system wishes to request that the provider sets its allowed state as
- * desired. This implies that the caller is providing/retracting consent for any terms and
- * conditions or consents associated with the provider.
- *
- * <p>It is generally only necessary to override this function if the provider has some barriers
- * or gates for enabling/disabling itself, in which case this function should handle those
- * appropriately. A provider that is always allowed has no need to override this function.
- */
- protected void onRequestSetAllowed(boolean allowed) {}
-
private final class Service extends ILocationProvider.Stub {
@Override
@@ -356,10 +345,5 @@ public abstract class LocationProviderBase {
public void sendExtraCommand(String command, Bundle extras) {
onSendExtraCommand(command, extras);
}
-
- @Override
- public void requestSetAllowed(boolean allowed) {
- onRequestSetAllowed(allowed);
- }
}
}
diff --git a/media/java/android/media/DrmInitData.java b/media/java/android/media/DrmInitData.java
index cc35f140dd7e..d803311fdae3 100644
--- a/media/java/android/media/DrmInitData.java
+++ b/media/java/android/media/DrmInitData.java
@@ -37,7 +37,9 @@ public abstract class DrmInitData {
*
* @param schemeUuid The DRM scheme's UUID.
* @return The initialization data for the scheme, or null if the scheme is not supported.
+ * @deprecated Use {@link #getSchemeInitDataCount} and {@link #getSchemeInitDataAt} instead.
*/
+ @Deprecated
public abstract SchemeInitData get(UUID schemeUuid);
/**
diff --git a/media/java/android/media/MediaCodec.java b/media/java/android/media/MediaCodec.java
index abc7e0b7be0e..f2b4db1afdac 100644
--- a/media/java/android/media/MediaCodec.java
+++ b/media/java/android/media/MediaCodec.java
@@ -1959,7 +1959,7 @@ final public class MediaCodec {
* If this codec is to be used with {@link LinearBlock} and/or {@link
* GraphicBlock}, pass this flag.
* <p>
- * When this flag is set, the following APIs throw IllegalStateException.
+ * When this flag is set, the following APIs throw {@link IncompatibleWithBlockModelException}.
* <ul>
* <li>{@link #getInputBuffer}
* <li>{@link #getInputImage}
@@ -1986,6 +1986,12 @@ final public class MediaCodec {
public @interface ConfigureFlag {}
/**
+ * Thrown when the codec is configured for block model and an incompatible API is called.
+ */
+ public class IncompatibleWithBlockModelException extends RuntimeException {
+ }
+
+ /**
* Configures a component.
*
* @param format The format of the input data (decoder) or the desired
@@ -2526,7 +2532,7 @@ final public class MediaCodec {
throws CryptoException {
synchronized(mBufferLock) {
if (mBufferMode != BUFFER_MODE_LEGACY) {
- throw new IllegalStateException();
+ throw new IncompatibleWithBlockModelException();
}
invalidateByteBuffer(mCachedInputBuffers, index);
mDequeuedInputBuffers.remove(index);
@@ -2778,7 +2784,7 @@ final public class MediaCodec {
int flags) throws CryptoException {
synchronized(mBufferLock) {
if (mBufferMode != BUFFER_MODE_LEGACY) {
- throw new IllegalStateException();
+ throw new IncompatibleWithBlockModelException();
}
invalidateByteBuffer(mCachedInputBuffers, index);
mDequeuedInputBuffers.remove(index);
@@ -2813,7 +2819,7 @@ final public class MediaCodec {
public final int dequeueInputBuffer(long timeoutUs) {
synchronized (mBufferLock) {
if (mBufferMode != BUFFER_MODE_LEGACY) {
- throw new IllegalStateException();
+ throw new IncompatibleWithBlockModelException();
}
}
int res = native_dequeueInputBuffer(timeoutUs);
@@ -2848,7 +2854,7 @@ final public class MediaCodec {
public boolean isMappable() {
synchronized (mLock) {
if (!mValid) {
- throw new IllegalStateException();
+ throw new IllegalStateException("The linear block is invalid");
}
return mMappable;
}
@@ -2867,10 +2873,10 @@ final public class MediaCodec {
public @NonNull ByteBuffer map() {
synchronized (mLock) {
if (!mValid) {
- throw new IllegalStateException();
+ throw new IllegalStateException("The linear block is invalid");
}
if (!mMappable) {
- throw new IllegalStateException();
+ throw new IllegalStateException("The linear block is not mappable");
}
if (mMapped == null) {
mMapped = native_map();
@@ -2896,7 +2902,7 @@ final public class MediaCodec {
public void recycle() {
synchronized (mLock) {
if (!mValid) {
- throw new IllegalStateException();
+ throw new IllegalStateException("The linear block is invalid");
}
if (mMapped != null) {
mMapped.setAccessible(false);
@@ -3002,7 +3008,7 @@ final public class MediaCodec {
public boolean isMappable() {
synchronized (mLock) {
if (!mValid) {
- throw new IllegalStateException();
+ throw new IllegalStateException("The graphic block is invalid");
}
return mMappable;
}
@@ -3021,10 +3027,10 @@ final public class MediaCodec {
public @NonNull Image map() {
synchronized (mLock) {
if (!mValid) {
- throw new IllegalStateException();
+ throw new IllegalStateException("The graphic block is invalid");
}
if (!mMappable) {
- throw new IllegalStateException();
+ throw new IllegalStateException("The graphic block is not mappable");
}
if (mMapped == null) {
mMapped = native_map();
@@ -3050,7 +3056,7 @@ final public class MediaCodec {
public void recycle() {
synchronized (mLock) {
if (!mValid) {
- throw new IllegalStateException();
+ throw new IllegalStateException("The graphic block is invalid");
}
if (mMapped != null) {
mMapped.close();
@@ -3127,8 +3133,9 @@ final public class MediaCodec {
if (buffer == null) {
buffer = new GraphicBlock();
}
- if (width < 0 || height < 0) {
- throw new IllegalArgumentException();
+ if (width <= 0 || height <= 0) {
+ throw new IllegalArgumentException(
+ "non-positive width or height: " + width + "x" + height);
}
synchronized (buffer.mLock) {
buffer.native_obtain(width, height, format, usage, codecNames);
@@ -3177,16 +3184,8 @@ final public class MediaCodec {
* @param block The linear block object
* @param offset The byte offset into the input buffer at which the data starts.
* @param size The number of bytes of valid input data.
- * @param presentationTimeUs The presentation timestamp in microseconds for this
- * buffer. This is normally the media time at which this
- * buffer should be presented (rendered). When using an output
- * surface, this will be propagated as the {@link
- * SurfaceTexture#getTimestamp timestamp} for the frame (after
- * conversion to nanoseconds).
- * @param flags A bitmask of flags
- * {@link #BUFFER_FLAG_CODEC_CONFIG} and {@link #BUFFER_FLAG_END_OF_STREAM}.
- * While not prohibited, most codecs do not use the
- * {@link #BUFFER_FLAG_KEY_FRAME} flag for input buffers.
+ * @param cryptoInfo Metadata describing the structure of the encrypted input sample.
+ * may be null if clear.
* @return this object
* @throws IllegalStateException if a buffer is already set
*/
@@ -3194,106 +3193,91 @@ final public class MediaCodec {
@NonNull LinearBlock block,
int offset,
int size,
- long presentationTimeUs,
- @BufferFlag int flags) {
+ @Nullable MediaCodec.CryptoInfo cryptoInfo) {
if (!isAccessible()) {
- throw new IllegalStateException();
+ throw new IllegalStateException("The request is stale");
}
if (mLinearBlock != null || mGraphicBlock != null) {
- throw new IllegalStateException();
+ throw new IllegalStateException("Cannot set block twice");
}
mLinearBlock = block;
mOffset = offset;
mSize = size;
- mPresentationTimeUs = presentationTimeUs;
- mFlags = flags;
+ mCryptoInfo = cryptoInfo;
return this;
}
/**
- * Set an encrypted linear block to this queue request. Exactly one
- * buffer must be set for a queue request before calling {@link #queue}.
+ * Set a graphic block to this queue request. Exactly one buffer must
+ * be set for a queue request before calling {@link #queue}.
*
- * @param block The linear block object
- * @param offset The byte offset into the input buffer at which the data starts.
- * @param presentationTimeUs The presentation timestamp in microseconds for this
- * buffer. This is normally the media time at which this
- * buffer should be presented (rendered). When using an output
- * surface, this will be propagated as the {@link
- * SurfaceTexture#getTimestamp timestamp} for the frame (after
- * conversion to nanoseconds).
- * @param cryptoInfo Metadata describing the structure of the encrypted input sample.
- * @param flags A bitmask of flags
- * {@link #BUFFER_FLAG_CODEC_CONFIG} and {@link #BUFFER_FLAG_END_OF_STREAM}.
- * While not prohibited, most codecs do not use the
- * {@link #BUFFER_FLAG_KEY_FRAME} flag for input buffers.
+ * @param block The graphic block object
* @return this object
* @throws IllegalStateException if a buffer is already set
*/
- public @NonNull QueueRequest setEncryptedLinearBlock(
- @NonNull LinearBlock block,
- int offset,
- @NonNull MediaCodec.CryptoInfo cryptoInfo,
- long presentationTimeUs,
- @BufferFlag int flags) {
+ public @NonNull QueueRequest setGraphicBlock(
+ @NonNull GraphicBlock block) {
if (!isAccessible()) {
- throw new IllegalStateException();
+ throw new IllegalStateException("The request is stale");
}
if (mLinearBlock != null || mGraphicBlock != null) {
- throw new IllegalStateException();
+ throw new IllegalStateException("Cannot set block twice");
}
- mLinearBlock = block;
- mOffset = offset;
- mCryptoInfo = cryptoInfo;
- mPresentationTimeUs = presentationTimeUs;
- mFlags = flags;
+ mGraphicBlock = block;
return this;
}
/**
- * Set a graphic block to this queue request. Exactly one buffer must
- * be set for a queue request before calling {@link #queue}.
+ * Set timestamp to this queue request.
*
- * @param block The graphic block object
* @param presentationTimeUs The presentation timestamp in microseconds for this
* buffer. This is normally the media time at which this
* buffer should be presented (rendered). When using an output
* surface, this will be propagated as the {@link
* SurfaceTexture#getTimestamp timestamp} for the frame (after
* conversion to nanoseconds).
+ * @return this object
+ */
+ public @NonNull QueueRequest setPresentationTimeUs(long presentationTimeUs) {
+ if (!isAccessible()) {
+ throw new IllegalStateException("The request is stale");
+ }
+ mPresentationTimeUs = presentationTimeUs;
+ return this;
+ }
+
+ /**
+ * Set flags to this queue request.
+ *
* @param flags A bitmask of flags
* {@link #BUFFER_FLAG_CODEC_CONFIG} and {@link #BUFFER_FLAG_END_OF_STREAM}.
* While not prohibited, most codecs do not use the
* {@link #BUFFER_FLAG_KEY_FRAME} flag for input buffers.
* @return this object
- * @throws IllegalStateException if a buffer is already set
*/
- public @NonNull QueueRequest setGraphicBlock(
- @NonNull GraphicBlock block,
- long presentationTimeUs,
- @BufferFlag int flags) {
+ public @NonNull QueueRequest setFlags(@BufferFlag int flags) {
if (!isAccessible()) {
- throw new IllegalStateException();
- }
- if (mLinearBlock != null || mGraphicBlock != null) {
- throw new IllegalStateException();
+ throw new IllegalStateException("The request is stale");
}
- mGraphicBlock = block;
- mPresentationTimeUs = presentationTimeUs;
mFlags = flags;
return this;
}
/**
- * Add a integer parameter. See {@link MediaFormat} for the list of
- * supported tunings. If there was {@link MediaCodec#setParameters}
+ * Add an integer parameter.
+ * See {@link MediaFormat} for an exhaustive list of supported keys with
+ * values of type int, that can also be set with {@link MediaFormat#setInteger}.
+ *
+ * If there was {@link MediaCodec#setParameters}
* call with the same key which is not processed by the codec yet, the
* value set from this method will override the unprocessed value.
+ *
+ * @return this object
*/
public @NonNull QueueRequest setIntegerParameter(
@NonNull String key, int value) {
if (!isAccessible()) {
- throw new IllegalStateException();
+ throw new IllegalStateException("The request is stale");
}
mTuningKeys.add(key);
mTuningValues.add(Integer.valueOf(value));
@@ -3301,15 +3285,20 @@ final public class MediaCodec {
}
/**
- * Add a long parameter. See {@link MediaFormat} for the list of
- * supported tunings. If there was {@link MediaCodec#setParameters}
+ * Add a long parameter.
+ * See {@link MediaFormat} for an exhaustive list of supported keys with
+ * values of type long, that can also be set with {@link MediaFormat#setLong}.
+ *
+ * If there was {@link MediaCodec#setParameters}
* call with the same key which is not processed by the codec yet, the
* value set from this method will override the unprocessed value.
+ *
+ * @return this object
*/
public @NonNull QueueRequest setLongParameter(
@NonNull String key, long value) {
if (!isAccessible()) {
- throw new IllegalStateException();
+ throw new IllegalStateException("The request is stale");
}
mTuningKeys.add(key);
mTuningValues.add(Long.valueOf(value));
@@ -3317,15 +3306,20 @@ final public class MediaCodec {
}
/**
- * Add a float parameter. See {@link MediaFormat} for the list of
- * supported tunings. If there was {@link MediaCodec#setParameters}
+ * Add a float parameter.
+ * See {@link MediaFormat} for an exhaustive list of supported keys with
+ * values of type float, that can also be set with {@link MediaFormat#setFloat}.
+ *
+ * If there was {@link MediaCodec#setParameters}
* call with the same key which is not processed by the codec yet, the
* value set from this method will override the unprocessed value.
+ *
+ * @return this object
*/
public @NonNull QueueRequest setFloatParameter(
@NonNull String key, float value) {
if (!isAccessible()) {
- throw new IllegalStateException();
+ throw new IllegalStateException("The request is stale");
}
mTuningKeys.add(key);
mTuningValues.add(Float.valueOf(value));
@@ -3333,15 +3327,20 @@ final public class MediaCodec {
}
/**
- * Add a {@link ByteBuffer} parameter. See {@link MediaFormat} for the list of
- * supported tunings. If there was {@link MediaCodec#setParameters}
+ * Add a {@link ByteBuffer} parameter.
+ * See {@link MediaFormat} for an exhaustive list of supported keys with
+ * values of byte buffer, that can also be set with {@link MediaFormat#setByteBuffer}.
+ *
+ * If there was {@link MediaCodec#setParameters}
* call with the same key which is not processed by the codec yet, the
* value set from this method will override the unprocessed value.
+ *
+ * @return this object
*/
public @NonNull QueueRequest setByteBufferParameter(
@NonNull String key, @NonNull ByteBuffer value) {
if (!isAccessible()) {
- throw new IllegalStateException();
+ throw new IllegalStateException("The request is stale");
}
mTuningKeys.add(key);
mTuningValues.add(value);
@@ -3349,15 +3348,20 @@ final public class MediaCodec {
}
/**
- * Add a string parameter. See {@link MediaFormat} for the list of
- * supported tunings. If there was {@link MediaCodec#setParameters}
+ * Add a string parameter.
+ * See {@link MediaFormat} for an exhaustive list of supported keys with
+ * values of type string, that can also be set with {@link MediaFormat#setString}.
+ *
+ * If there was {@link MediaCodec#setParameters}
* call with the same key which is not processed by the codec yet, the
* value set from this method will override the unprocessed value.
+ *
+ * @return this object
*/
public @NonNull QueueRequest setStringParameter(
@NonNull String key, @NonNull String value) {
if (!isAccessible()) {
- throw new IllegalStateException();
+ throw new IllegalStateException("The request is stale");
}
mTuningKeys.add(key);
mTuningValues.add(value);
@@ -3369,10 +3373,10 @@ final public class MediaCodec {
*/
public void queue() {
if (!isAccessible()) {
- throw new IllegalStateException();
+ throw new IllegalStateException("The request is stale");
}
if (mLinearBlock == null && mGraphicBlock == null) {
- throw new IllegalStateException();
+ throw new IllegalStateException("No block is set");
}
setAccessible(false);
if (mLinearBlock != null) {
@@ -3447,7 +3451,7 @@ final public class MediaCodec {
private final ArrayList<QueueRequest> mQueueRequests = new ArrayList<>();
/**
- * Return a clear {@link QueueRequest} object for an input slot index.
+ * Return a {@link QueueRequest} object for an input slot index.
*
* @param index input slot index from
* {@link Callback#onInputBufferAvailable}
@@ -3459,17 +3463,19 @@ final public class MediaCodec {
public @NonNull QueueRequest getQueueRequest(int index) {
synchronized (mBufferLock) {
if (mBufferMode != BUFFER_MODE_BLOCK) {
- throw new IllegalStateException();
+ throw new IllegalStateException("The codec is not configured for block model");
}
if (index < 0 || index >= mQueueRequests.size()) {
- throw new IllegalArgumentException();
+ throw new IndexOutOfBoundsException("Expected range of index: [0,"
+ + (mQueueRequests.size() - 1) + "]; actual: " + index);
}
QueueRequest request = mQueueRequests.get(index);
if (request == null) {
- throw new IllegalArgumentException();
+ throw new IllegalArgumentException("Unavailable index: " + index);
}
if (!request.isAccessible()) {
- throw new IllegalArgumentException();
+ throw new IllegalArgumentException(
+ "The request is stale at index " + index);
}
return request.clear();
}
@@ -3529,7 +3535,7 @@ final public class MediaCodec {
@NonNull BufferInfo info, long timeoutUs) {
synchronized (mBufferLock) {
if (mBufferMode != BUFFER_MODE_LEGACY) {
- throw new IllegalStateException();
+ throw new IncompatibleWithBlockModelException();
}
}
int res = native_dequeueOutputBuffer(info, timeoutUs);
@@ -3644,7 +3650,8 @@ final public class MediaCodec {
frame.clear();
break;
default:
- throw new IllegalStateException();
+ throw new IllegalStateException(
+ "Unrecognized buffer mode: " + mBufferMode);
}
}
releaseOutputBuffer(
@@ -3910,7 +3917,7 @@ final public class MediaCodec {
public ByteBuffer[] getInputBuffers() {
synchronized (mBufferLock) {
if (mBufferMode != BUFFER_MODE_LEGACY) {
- throw new IllegalStateException();
+ throw new IncompatibleWithBlockModelException();
}
if (mCachedInputBuffers == null) {
throw new IllegalStateException();
@@ -3946,7 +3953,7 @@ final public class MediaCodec {
public ByteBuffer[] getOutputBuffers() {
synchronized (mBufferLock) {
if (mBufferMode != BUFFER_MODE_LEGACY) {
- throw new IllegalStateException();
+ throw new IncompatibleWithBlockModelException();
}
if (mCachedOutputBuffers == null) {
throw new IllegalStateException();
@@ -3978,7 +3985,7 @@ final public class MediaCodec {
public ByteBuffer getInputBuffer(int index) {
synchronized (mBufferLock) {
if (mBufferMode != BUFFER_MODE_LEGACY) {
- throw new IllegalStateException();
+ throw new IncompatibleWithBlockModelException();
}
}
ByteBuffer newBuffer = getBuffer(true /* input */, index);
@@ -4012,7 +4019,7 @@ final public class MediaCodec {
public Image getInputImage(int index) {
synchronized (mBufferLock) {
if (mBufferMode != BUFFER_MODE_LEGACY) {
- throw new IllegalStateException();
+ throw new IncompatibleWithBlockModelException();
}
}
Image newImage = getImage(true /* input */, index);
@@ -4046,7 +4053,7 @@ final public class MediaCodec {
public ByteBuffer getOutputBuffer(int index) {
synchronized (mBufferLock) {
if (mBufferMode != BUFFER_MODE_LEGACY) {
- throw new IllegalStateException();
+ throw new IncompatibleWithBlockModelException();
}
}
ByteBuffer newBuffer = getBuffer(false /* input */, index);
@@ -4079,7 +4086,7 @@ final public class MediaCodec {
public Image getOutputImage(int index) {
synchronized (mBufferLock) {
if (mBufferMode != BUFFER_MODE_LEGACY) {
- throw new IllegalStateException();
+ throw new IncompatibleWithBlockModelException();
}
}
Image newImage = getImage(false /* input */, index);
@@ -4106,7 +4113,7 @@ final public class MediaCodec {
*/
public @Nullable LinearBlock getLinearBlock() {
if (mGraphicBlock != null) {
- throw new IllegalStateException();
+ throw new IllegalStateException("This output frame is not linear");
}
return mLinearBlock;
}
@@ -4118,7 +4125,7 @@ final public class MediaCodec {
*/
public @Nullable GraphicBlock getGraphicBlock() {
if (mLinearBlock != null) {
- throw new IllegalStateException();
+ throw new IllegalStateException("This output frame is not graphic");
}
return mGraphicBlock;
}
@@ -4139,7 +4146,7 @@ final public class MediaCodec {
/**
* Returns a read-only {@link MediaFormat} for this frame. The returned
- * object is valid only while the client is holding the output frame.
+ * object is valid only until the client calls {@link MediaCodec#releaseOutputBuffer}.
*/
public @NonNull MediaFormat getFormat() {
return mFormat;
@@ -4151,7 +4158,7 @@ final public class MediaCodec {
* Client can find out what the change is by querying {@link MediaFormat}
* object returned from {@link #getFormat}.
*/
- public void getChangedKeys(@NonNull Set<String> keys) {
+ public void retrieveChangedKeys(@NonNull Set<String> keys) {
keys.clear();
keys.addAll(mChangedKeys);
}
@@ -4211,17 +4218,19 @@ final public class MediaCodec {
public @NonNull OutputFrame getOutputFrame(int index) {
synchronized (mBufferLock) {
if (mBufferMode != BUFFER_MODE_BLOCK) {
- throw new IllegalStateException();
+ throw new IllegalStateException("The codec is not configured for block model");
}
if (index < 0 || index >= mOutputFrames.size()) {
- throw new IllegalArgumentException();
+ throw new IndexOutOfBoundsException("Expected range of index: [0,"
+ + (mQueueRequests.size() - 1) + "]; actual: " + index);
}
OutputFrame frame = mOutputFrames.get(index);
if (frame == null) {
- throw new IllegalArgumentException();
+ throw new IllegalArgumentException("Unavailable index: " + index);
}
if (!frame.isAccessible()) {
- throw new IllegalArgumentException();
+ throw new IllegalArgumentException(
+ "The output frame is stale at index " + index);
}
if (!frame.isLoaded()) {
native_getOutputFrame(frame, index);
diff --git a/media/java/android/media/MediaRouter2.java b/media/java/android/media/MediaRouter2.java
index 28bb4c192425..5942a3d05e67 100644
--- a/media/java/android/media/MediaRouter2.java
+++ b/media/java/android/media/MediaRouter2.java
@@ -21,6 +21,7 @@ import static com.android.internal.util.function.pooled.PooledLambda.obtainMessa
import android.annotation.CallbackExecutor;
import android.annotation.NonNull;
import android.annotation.Nullable;
+import android.annotation.TestApi;
import android.content.Context;
import android.os.Bundle;
import android.os.Handler;
@@ -721,8 +722,7 @@ public class MediaRouter2 {
RoutingController newController) {
for (TransferCallbackRecord record: mTransferCallbackRecords) {
record.mExecutor.execute(
- () -> record.mTransferCallback.onTransferred(oldController,
- newController));
+ () -> record.mTransferCallback.onTransferred(oldController, newController));
}
}
@@ -866,6 +866,20 @@ public class MediaRouter2 {
}
/**
+ * Gets the original session id set by
+ * {@link RoutingSessionInfo.Builder#Builder(String, String)}.
+ *
+ * @hide
+ */
+ @NonNull
+ @TestApi
+ public String getOriginalId() {
+ synchronized (mControllerLock) {
+ return mSessionInfo.getOriginalId();
+ }
+ }
+
+ /**
* @return the control hints used to control routing session if available.
*/
@Nullable
diff --git a/media/java/android/media/tv/tuner/TunerUtils.java b/media/java/android/media/tv/tuner/TunerUtils.java
index 5ecb8f0288fc..2258ee559ea0 100644
--- a/media/java/android/media/tv/tuner/TunerUtils.java
+++ b/media/java/android/media/tv/tuner/TunerUtils.java
@@ -16,6 +16,7 @@
package android.media.tv.tuner;
+import android.annotation.Nullable;
import android.content.Context;
import android.content.pm.PackageManager;
import android.hardware.tv.tuner.V1_0.Constants;
@@ -165,5 +166,33 @@ public final class TunerUtils {
"Invalid filter types. Main type=" + mainType + ", subtype=" + subtype);
}
+ /**
+ * Gets an throwable instance for the corresponding result.
+ */
+ @Nullable
+ public static void throwExceptionForResult(
+ @TunerConstants.Result int r, @Nullable String msg) {
+ if (msg == null) {
+ msg = "";
+ }
+ switch (r) {
+ case TunerConstants.RESULT_INVALID_ARGUMENT:
+ throw new IllegalArgumentException(msg);
+ case TunerConstants.RESULT_INVALID_STATE:
+ throw new IllegalStateException(msg);
+ case TunerConstants.RESULT_NOT_INITIALIZED:
+ throw new IllegalStateException("Invalid state: not initialized. " + msg);
+ case TunerConstants.RESULT_OUT_OF_MEMORY:
+ throw new OutOfMemoryError(msg);
+ case TunerConstants.RESULT_UNAVAILABLE:
+ throw new IllegalStateException("Invalid state: resource unavailable. " + msg);
+ case TunerConstants.RESULT_UNKNOWN_ERROR:
+ throw new RuntimeException("Unknown error" + msg);
+ default:
+ break;
+ }
+ throw new RuntimeException("Unexpected result " + r + ". " + msg);
+ }
+
private TunerUtils() {}
}
diff --git a/media/java/android/media/tv/tuner/filter/TimeFilter.java b/media/java/android/media/tv/tuner/filter/TimeFilter.java
index a926d59cdd03..371ccc44337a 100644
--- a/media/java/android/media/tv/tuner/filter/TimeFilter.java
+++ b/media/java/android/media/tv/tuner/filter/TimeFilter.java
@@ -17,7 +17,9 @@
package android.media.tv.tuner.filter;
import android.annotation.SystemApi;
+import android.media.tv.tuner.TunerConstants;
import android.media.tv.tuner.TunerConstants.Result;
+import android.media.tv.tuner.TunerUtils;
/**
* A timer filter is used to filter data based on timestamps.
@@ -51,6 +53,8 @@ public class TimeFilter implements AutoCloseable {
private native Long nativeGetSourceTime();
private native int nativeClose();
+ private long mNativeContext;
+
private boolean mEnable = false;
// Called by JNI code
@@ -139,6 +143,9 @@ public class TimeFilter implements AutoCloseable {
*/
@Override
public void close() {
- nativeClose();
+ int res = nativeClose();
+ if (res != TunerConstants.RESULT_SUCCESS) {
+ TunerUtils.throwExceptionForResult(res, "Failed to close time filter.");
+ }
}
}
diff --git a/media/jni/Android.bp b/media/jni/Android.bp
index c17b1b773bd5..47ec7e6c5593 100644
--- a/media/jni/Android.bp
+++ b/media/jni/Android.bp
@@ -160,8 +160,3 @@ cc_library_shared {
"-Wunreachable-code",
],
}
-
-subdirs = [
- "audioeffect",
- "soundpool",
-]
diff --git a/media/jni/android_media_tv_Tuner.cpp b/media/jni/android_media_tv_Tuner.cpp
index f4d2d030c6f1..4f31f6c091c9 100644
--- a/media/jni/android_media_tv_Tuner.cpp
+++ b/media/jni/android_media_tv_Tuner.cpp
@@ -118,10 +118,12 @@ using ::android::hardware::tv::tuner::V1_0::Result;
struct fields_t {
jfieldID tunerContext;
jfieldID filterContext;
+ jfieldID timeFilterContext;
jfieldID descramblerContext;
jfieldID dvrContext;
jmethodID frontendInitID;
jmethodID filterInitID;
+ jmethodID timeFilterInitID;
jmethodID dvrInitID;
jmethodID onFrontendEventID;
jmethodID onFilterStatusID;
@@ -237,6 +239,25 @@ sp<IFilter> Filter::getIFilter() {
return mFilterSp;
}
+/////////////// TimeFilter ///////////////////////
+
+TimeFilter::TimeFilter(sp<ITimeFilter> sp, jobject obj) : mTimeFilterSp(sp) {
+ JNIEnv *env = AndroidRuntime::getJNIEnv();
+ mTimeFilterObj = env->NewWeakGlobalRef(obj);
+}
+
+TimeFilter::~TimeFilter() {
+ ALOGD("~TimeFilter");
+ JNIEnv *env = AndroidRuntime::getJNIEnv();
+
+ env->DeleteWeakGlobalRef(mTimeFilterObj);
+ mTimeFilterObj = NULL;
+}
+
+sp<ITimeFilter> TimeFilter::getITimeFilter() {
+ return mTimeFilterSp;
+}
+
/////////////// FrontendCallback ///////////////////////
FrontendCallback::FrontendCallback(jweak tunerObj, FrontendId id) : mObject(tunerObj), mId(id) {}
@@ -841,6 +862,36 @@ jobject JTuner::openFilter(DemuxFilterType type, int bufferSize) {
return filterObj;
}
+jobject JTuner::openTimeFilter() {
+ if (mDemux == NULL) {
+ if (!openDemux()) {
+ return NULL;
+ }
+ }
+ sp<ITimeFilter> iTimeFilterSp;
+ Result res;
+ mDemux->openTimeFilter(
+ [&](Result r, const sp<ITimeFilter>& filter) {
+ iTimeFilterSp = filter;
+ res = r;
+ });
+
+ if (res != Result::SUCCESS || iTimeFilterSp == NULL) {
+ return NULL;
+ }
+
+ JNIEnv *env = AndroidRuntime::getJNIEnv();
+ jobject timeFilterObj =
+ env->NewObject(
+ env->FindClass("android/media/tv/tuner/filter/TimeFilter"),
+ gFields.timeFilterInitID);
+ sp<TimeFilter> timeFilterSp = new TimeFilter(iTimeFilterSp, timeFilterObj);
+ timeFilterSp->incStrong(timeFilterObj);
+ env->SetLongField(timeFilterObj, gFields.timeFilterContext, (jlong)timeFilterSp.get());
+
+ return timeFilterObj;
+}
+
jobject JTuner::openDvr(DvrType type, int bufferSize) {
ALOGD("JTuner::openDvr");
if (mDemux == NULL) {
@@ -1420,6 +1471,10 @@ static void android_media_tv_Tuner_native_init(JNIEnv *env) {
gFields.onFilterStatusID =
env->GetMethodID(filterClazz, "onFilterStatus", "(I)V");
+ jclass timeFilterClazz = env->FindClass("android/media/tv/tuner/filter/TimeFilter");
+ gFields.timeFilterContext = env->GetFieldID(timeFilterClazz, "mNativeContext", "J");
+ gFields.timeFilterInitID = env->GetMethodID(timeFilterClazz, "<init>", "()V");
+
jclass descramblerClazz = env->FindClass("android/media/tv/tuner/Descrambler");
gFields.descramblerContext = env->GetFieldID(descramblerClazz, "mNativeContext", "J");
gFields.descramblerInitID =
@@ -1515,18 +1570,35 @@ static jobject android_media_tv_Tuner_open_lnb_by_id(JNIEnv *env, jobject thiz,
static jobject android_media_tv_Tuner_open_filter(
JNIEnv *env, jobject thiz, jint type, jint subType, jlong bufferSize) {
sp<JTuner> tuner = getTuner(env, thiz);
+ DemuxFilterMainType mainType = static_cast<DemuxFilterMainType>(type);
DemuxFilterType filterType {
- .mainType = static_cast<DemuxFilterMainType>(type),
+ .mainType = mainType,
};
- // TODO: other sub types
- filterType.subType.tsFilterType(static_cast<DemuxTsFilterType>(subType));
+ switch(mainType) {
+ case DemuxFilterMainType::TS:
+ filterType.subType.tsFilterType(static_cast<DemuxTsFilterType>(subType));
+ break;
+ case DemuxFilterMainType::MMTP:
+ filterType.subType.mmtpFilterType(static_cast<DemuxMmtpFilterType>(subType));
+ break;
+ case DemuxFilterMainType::IP:
+ filterType.subType.ipFilterType(static_cast<DemuxIpFilterType>(subType));
+ break;
+ case DemuxFilterMainType::TLV:
+ filterType.subType.tlvFilterType(static_cast<DemuxTlvFilterType>(subType));
+ break;
+ case DemuxFilterMainType::ALP:
+ filterType.subType.alpFilterType(static_cast<DemuxAlpFilterType>(subType));
+ break;
+ }
return tuner->openFilter(filterType, bufferSize);
}
-static jobject android_media_tv_Tuner_open_time_filter(JNIEnv, jobject) {
- return NULL;
+static jobject android_media_tv_Tuner_open_time_filter(JNIEnv *env, jobject thiz) {
+ sp<JTuner> tuner = getTuner(env, thiz);
+ return tuner->openTimeFilter();
}
static DemuxFilterSectionBits getFilterSectionBits(JNIEnv *env, const jobject& settings) {
@@ -1987,26 +2059,98 @@ static int android_media_tv_Tuner_close_filter(JNIEnv*, jobject) {
return 0;
}
-// TODO: implement TimeFilter functions
+static sp<TimeFilter> getTimeFilter(JNIEnv *env, jobject filter) {
+ return (TimeFilter *)env->GetLongField(filter, gFields.timeFilterContext);
+}
+
static int android_media_tv_Tuner_time_filter_set_timestamp(
- JNIEnv, jobject, jlong) {
- return 0;
+ JNIEnv *env, jobject filter, jlong timestamp) {
+ sp<TimeFilter> filterSp = getTimeFilter(env, filter);
+ if (filterSp == NULL) {
+ ALOGD("Failed set timestamp: time filter not found");
+ return (int) Result::INVALID_STATE;
+ }
+ sp<ITimeFilter> iFilterSp = filterSp->getITimeFilter();
+ Result r = iFilterSp->setTimeStamp(static_cast<uint64_t>(timestamp));
+ return (int) r;
}
-static int android_media_tv_Tuner_time_filter_clear_timestamp(JNIEnv, jobject) {
- return 0;
+static int android_media_tv_Tuner_time_filter_clear_timestamp(JNIEnv *env, jobject filter) {
+ sp<TimeFilter> filterSp = getTimeFilter(env, filter);
+ if (filterSp == NULL) {
+ ALOGD("Failed clear timestamp: time filter not found");
+ return (int) Result::INVALID_STATE;
+ }
+ sp<ITimeFilter> iFilterSp = filterSp->getITimeFilter();
+ Result r = iFilterSp->clearTimeStamp();
+ return (int) r;
}
-static jobject android_media_tv_Tuner_time_filter_get_timestamp(JNIEnv, jobject) {
- return NULL;
+static jobject android_media_tv_Tuner_time_filter_get_timestamp(JNIEnv *env, jobject filter) {
+ sp<TimeFilter> filterSp = getTimeFilter(env, filter);
+ if (filterSp == NULL) {
+ ALOGD("Failed get timestamp: time filter not found");
+ return NULL;
+ }
+
+ sp<ITimeFilter> iFilterSp = filterSp->getITimeFilter();
+ Result res;
+ uint64_t timestamp;
+ iFilterSp->getTimeStamp(
+ [&](Result r, uint64_t t) {
+ res = r;
+ timestamp = t;
+ });
+ if (res != Result::SUCCESS) {
+ return NULL;
+ }
+
+ jclass longClazz = env->FindClass("java/lang/Long");
+ jmethodID longInit = env->GetMethodID(longClazz, "<init>", "(J)V");
+
+ jobject longObj = env->NewObject(longClazz, longInit, static_cast<jlong>(timestamp));
+ return longObj;
}
-static jobject android_media_tv_Tuner_time_filter_get_source_time(JNIEnv, jobject) {
- return NULL;
+static jobject android_media_tv_Tuner_time_filter_get_source_time(JNIEnv *env, jobject filter) {
+ sp<TimeFilter> filterSp = getTimeFilter(env, filter);
+ if (filterSp == NULL) {
+ ALOGD("Failed get source time: time filter not found");
+ return NULL;
+ }
+
+ sp<ITimeFilter> iFilterSp = filterSp->getITimeFilter();
+ Result res;
+ uint64_t timestamp;
+ iFilterSp->getSourceTime(
+ [&](Result r, uint64_t t) {
+ res = r;
+ timestamp = t;
+ });
+ if (res != Result::SUCCESS) {
+ return NULL;
+ }
+
+ jclass longClazz = env->FindClass("java/lang/Long");
+ jmethodID longInit = env->GetMethodID(longClazz, "<init>", "(J)V");
+
+ jobject longObj = env->NewObject(longClazz, longInit, static_cast<jlong>(timestamp));
+ return longObj;
}
-static int android_media_tv_Tuner_time_filter_close(JNIEnv, jobject) {
- return 0;
+static int android_media_tv_Tuner_time_filter_close(JNIEnv *env, jobject filter) {
+ sp<TimeFilter> filterSp = getTimeFilter(env, filter);
+ if (filterSp == NULL) {
+ ALOGD("Failed close time filter: time filter not found");
+ return (int) Result::INVALID_STATE;
+ }
+
+ Result r = filterSp->getITimeFilter()->close();
+ if (r == Result::SUCCESS) {
+ filterSp->decStrong(filter);
+ env->SetLongField(filter, gFields.timeFilterContext, 0);
+ }
+ return (int) r;
}
static jobject android_media_tv_Tuner_open_descrambler(JNIEnv *env, jobject thiz) {
diff --git a/media/jni/android_media_tv_Tuner.h b/media/jni/android_media_tv_Tuner.h
index d899bbd6467f..c5590b956eda 100644
--- a/media/jni/android_media_tv_Tuner.h
+++ b/media/jni/android_media_tv_Tuner.h
@@ -54,6 +54,7 @@ using ::android::hardware::tv::tuner::V1_0::IFrontend;
using ::android::hardware::tv::tuner::V1_0::IFrontendCallback;
using ::android::hardware::tv::tuner::V1_0::ILnb;
using ::android::hardware::tv::tuner::V1_0::ILnbCallback;
+using ::android::hardware::tv::tuner::V1_0::ITimeFilter;
using ::android::hardware::tv::tuner::V1_0::ITuner;
using ::android::hardware::tv::tuner::V1_0::LnbEventType;
using ::android::hardware::tv::tuner::V1_0::LnbId;
@@ -127,6 +128,14 @@ struct Filter : public RefBase {
jweak mFilterObj;
};
+struct TimeFilter : public RefBase {
+ TimeFilter(sp<ITimeFilter> sp, jweak obj);
+ ~TimeFilter();
+ sp<ITimeFilter> getITimeFilter();
+ sp<ITimeFilter> mTimeFilterSp;
+ jweak mTimeFilterObj;
+};
+
struct JTuner : public RefBase {
JTuner(JNIEnv *env, jobject thiz);
sp<ITuner> getTunerService();
@@ -142,6 +151,7 @@ struct JTuner : public RefBase {
jobject getLnbIds();
jobject openLnbById(int id);
jobject openFilter(DemuxFilterType type, int bufferSize);
+ jobject openTimeFilter();
jobject openDescrambler();
jobject openDvr(DvrType type, int bufferSize);
diff --git a/media/native/Android.bp b/media/native/Android.bp
deleted file mode 100644
index b44c2960127f..000000000000
--- a/media/native/Android.bp
+++ /dev/null
@@ -1 +0,0 @@
-subdirs = ["*"]
diff --git a/packages/CarSystemUI/src/com/android/systemui/volume/CarVolumeDialogImpl.java b/packages/CarSystemUI/src/com/android/systemui/volume/CarVolumeDialogImpl.java
index c9ac765dfc1d..873d7d7975e0 100644
--- a/packages/CarSystemUI/src/com/android/systemui/volume/CarVolumeDialogImpl.java
+++ b/packages/CarSystemUI/src/com/android/systemui/volume/CarVolumeDialogImpl.java
@@ -25,8 +25,11 @@ import android.app.Dialog;
import android.app.KeyguardManager;
import android.car.Car;
import android.car.media.CarAudioManager;
+import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.DialogInterface;
+import android.content.Intent;
+import android.content.IntentFilter;
import android.content.res.TypedArray;
import android.content.res.XmlResourceParser;
import android.graphics.Color;
@@ -38,6 +41,7 @@ import android.os.Debug;
import android.os.Handler;
import android.os.Looper;
import android.os.Message;
+import android.os.UserHandle;
import android.util.AttributeSet;
import android.util.Log;
import android.util.SparseArray;
@@ -171,6 +175,17 @@ public class CarVolumeDialogImpl implements VolumeDialog {
mCarAudioManager.registerCarVolumeCallback(mVolumeChangeCallback);
};
+ private final BroadcastReceiver mHomeButtonPressedBroadcastReceiver = new BroadcastReceiver() {
+ @Override
+ public void onReceive(Context context, Intent intent) {
+ if (!intent.getAction().equals(Intent.ACTION_CLOSE_SYSTEM_DIALOGS)) {
+ return;
+ }
+
+ dismissH(Events.DISMISS_REASON_VOLUME_CONTROLLER);
+ }
+ };
+
public CarVolumeDialogImpl(Context context) {
mContext = context;
mKeyguard = (KeyguardManager) mContext.getSystemService(Context.KEYGUARD_SERVICE);
@@ -204,12 +219,18 @@ public class CarVolumeDialogImpl implements VolumeDialog {
@Override
public void init(int windowType, Callback callback) {
initDialog();
+
+ mContext.registerReceiverAsUser(mHomeButtonPressedBroadcastReceiver, UserHandle.CURRENT,
+ new IntentFilter(Intent.ACTION_CLOSE_SYSTEM_DIALOGS), /* broadcastPermission= */
+ null, /* scheduler= */ null);
}
@Override
public void destroy() {
mHandler.removeCallbacksAndMessages(/* token= */ null);
+ mContext.unregisterReceiver(mHomeButtonPressedBroadcastReceiver);
+
cleanupAudioManager();
}
diff --git a/packages/DynamicSystemInstallationService/res/values/strings.xml b/packages/DynamicSystemInstallationService/res/values/strings.xml
index 25b7fc1b5ce2..e124be605cc7 100644
--- a/packages/DynamicSystemInstallationService/res/values/strings.xml
+++ b/packages/DynamicSystemInstallationService/res/values/strings.xml
@@ -27,10 +27,11 @@
<string name="notification_action_cancel">Cancel</string>
<!-- Action on notification: Discard installation [CHAR LIMIT=16] -->
<string name="notification_action_discard">Discard</string>
- <!-- Action on notification: Uninstall Dynamic System [CHAR LIMIT=16] -->
- <string name="notification_action_uninstall">Uninstall</string>
<!-- Action on notification: Restart to Dynamic System [CHAR LIMIT=16] -->
<string name="notification_action_reboot_to_dynsystem">Restart</string>
+ <!-- Action on notification: Restart to original Android version [CHAR LIMIT=16] -->
+ <string name="notification_action_reboot_to_origin">Restart</string>
+
<!-- Toast when installed Dynamic System is discarded [CHAR LIMIT=64] -->
<string name="toast_dynsystem_discarded">Discarded dynamic system</string>
diff --git a/packages/DynamicSystemInstallationService/src/com/android/dynsystem/DynamicSystemInstallationService.java b/packages/DynamicSystemInstallationService/src/com/android/dynsystem/DynamicSystemInstallationService.java
index 7affe8888628..37a77be52983 100644
--- a/packages/DynamicSystemInstallationService/src/com/android/dynsystem/DynamicSystemInstallationService.java
+++ b/packages/DynamicSystemInstallationService/src/com/android/dynsystem/DynamicSystemInstallationService.java
@@ -462,7 +462,7 @@ public class DynamicSystemInstallationService extends Service
.setStyle(new Notification.BigTextStyle().bigText(msgInUse));
builder.addAction(new Notification.Action.Builder(
- null, getString(R.string.notification_action_uninstall),
+ null, getString(R.string.notification_action_reboot_to_origin),
createPendingIntent(ACTION_REBOOT_TO_NORMAL)).build());
break;
diff --git a/packages/SettingsLib/res/values/strings.xml b/packages/SettingsLib/res/values/strings.xml
index 59881e7ba13d..d25e3e2ade01 100644
--- a/packages/SettingsLib/res/values/strings.xml
+++ b/packages/SettingsLib/res/values/strings.xml
@@ -886,6 +886,11 @@
<!-- UI debug setting: enable gpu debug layers summary [CHAR LIMIT=50] -->
<string name="enable_gpu_debug_layers_summary">Allow loading GPU debug layers for debug apps</string>
+ <!-- UI debug setting: enable verbose vendor logging [CHAR LIMIT=30] -->
+ <string name="enable_verbose_vendor_logging">Enable verbose vendor logging</string>
+ <!-- UI debug setting: enable verbose vendor logging summary [CHAR LIMIT=100] -->
+ <string name="enable_verbose_vendor_logging_summary">Allow additional vendor logs to be included in bug reports, may contain private information</string>
+
<!-- UI debug setting: scaling factor for window animations [CHAR LIMIT=25] -->
<string name="window_animation_scale_title">Window animation scale</string>
@@ -1260,9 +1265,12 @@
<!-- The notice header of Third-party licenses. not translatable -->
<string name="notice_header" translatable="false"></string>
- <!-- Name of the this device. [CHAR LIMIT=30] -->
- <string name="media_transfer_this_device_name">This device</string>
+ <!-- Name of the phone device. [CHAR LIMIT=30] -->
+ <string name="media_transfer_this_device_name">Phone speaker</string>
<!-- Warning message to tell user is have problem during profile connect, it need to turn off device and back on. [CHAR_LIMIT=NONE] -->
<string name="profile_connect_timeout_subtext">Problem connecting. Turn device off &amp; back on</string>
+
+ <!-- Name of the 3.5mm audio device. [CHAR LIMIT=40] -->
+ <string name="media_transfer_wired_device_name">Wired audio device</string>
</resources>
diff --git a/packages/SettingsLib/src/com/android/settingslib/display/DisplayDensityUtils.java b/packages/SettingsLib/src/com/android/settingslib/display/DisplayDensityUtils.java
index e0ca1ab0c07c..a38091debb64 100644
--- a/packages/SettingsLib/src/com/android/settingslib/display/DisplayDensityUtils.java
+++ b/packages/SettingsLib/src/com/android/settingslib/display/DisplayDensityUtils.java
@@ -97,7 +97,7 @@ public class DisplayDensityUtils {
final Resources res = context.getResources();
final DisplayMetrics metrics = new DisplayMetrics();
- context.getDisplay().getRealMetrics(metrics);
+ context.getDisplayNoVerify().getRealMetrics(metrics);
final int currentDensity = metrics.densityDpi;
int currentDensityIndex = -1;
diff --git a/packages/SystemUI/Android.bp b/packages/SystemUI/Android.bp
index de174b13a459..e0662309f571 100644
--- a/packages/SystemUI/Android.bp
+++ b/packages/SystemUI/Android.bp
@@ -86,7 +86,9 @@ filegroup {
android_library {
name: "SystemUI-tests",
- manifest: "tests/AndroidManifest.xml",
+ manifest: "tests/AndroidManifest-base.xml",
+ additional_manifests: ["tests/AndroidManifest.xml"],
+
resource_dirs: [
"tests/res",
"res-product",
diff --git a/packages/SystemUI/AndroidManifest.xml b/packages/SystemUI/AndroidManifest.xml
index 5458676e1061..e2410fec4dc2 100644
--- a/packages/SystemUI/AndroidManifest.xml
+++ b/packages/SystemUI/AndroidManifest.xml
@@ -696,8 +696,7 @@
<provider
android:name="com.android.keyguard.clock.ClockOptionsProvider"
android:authorities="com.android.keyguard.clock"
- android:enabled="false"
- android:exported="false"
+ android:exported="true"
android:grantUriPermissions="true">
</provider>
diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardClockSwitch.java b/packages/SystemUI/src/com/android/keyguard/KeyguardClockSwitch.java
index e475ef1d9761..6f06f6986c00 100644
--- a/packages/SystemUI/src/com/android/keyguard/KeyguardClockSwitch.java
+++ b/packages/SystemUI/src/com/android/keyguard/KeyguardClockSwitch.java
@@ -51,7 +51,7 @@ import javax.inject.Named;
public class KeyguardClockSwitch extends RelativeLayout {
private static final String TAG = "KeyguardClockSwitch";
- private static final boolean CUSTOM_CLOCKS_ENABLED = false;
+ private static final boolean CUSTOM_CLOCKS_ENABLED = true;
/**
* Animation fraction when text is transitioned to/from bold.
diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardDisplayManager.java b/packages/SystemUI/src/com/android/keyguard/KeyguardDisplayManager.java
index 571c4ae0e386..11bf24d27170 100644
--- a/packages/SystemUI/src/com/android/keyguard/KeyguardDisplayManager.java
+++ b/packages/SystemUI/src/com/android/keyguard/KeyguardDisplayManager.java
@@ -72,11 +72,12 @@ public class KeyguardDisplayManager {
@Override
public void onDisplayChanged(int displayId) {
if (displayId == DEFAULT_DISPLAY) return;
- final Display display = mDisplayService.getDisplay(displayId);
- if (display != null && mShowing) {
- final Presentation presentation = mPresentations.get(displayId);
- if (presentation != null && !presentation.getDisplay().equals(display)) {
- hidePresentation(displayId);
+ final Presentation presentation = mPresentations.get(displayId);
+ if (presentation != null && mShowing) {
+ hidePresentation(displayId);
+ // update DisplayInfo.
+ final Display display = mDisplayService.getDisplay(displayId);
+ if (display != null) {
showPresentation(display);
}
}
@@ -266,6 +267,11 @@ public class KeyguardDisplayManager {
}
@Override
+ public void cancel() {
+ // Do not allow anything to cancel KeyguardPresetation except KeyguardDisplayManager.
+ }
+
+ @Override
public void onDetachedFromWindow() {
mClock.removeCallbacks(mMoveTextRunnable);
}
diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardStatusView.java b/packages/SystemUI/src/com/android/keyguard/KeyguardStatusView.java
index 61caf3bc5d8f..241f96e19e38 100644
--- a/packages/SystemUI/src/com/android/keyguard/KeyguardStatusView.java
+++ b/packages/SystemUI/src/com/android/keyguard/KeyguardStatusView.java
@@ -149,7 +149,7 @@ public class KeyguardStatusView extends GridLayout implements
new WindowlessWindowManager(context.getResources().getConfiguration(),
surfaceControl, input);
mUniversalSmartspaceViewHost = new SurfaceControlViewHost(context,
- context.getDisplay(), windowlessWindowManager);
+ context.getDisplayNoVerify(), windowlessWindowManager);
WindowManager.LayoutParams layoutParams =
new WindowManager.LayoutParams(
surfaceControl.getWidth(),
diff --git a/packages/SystemUI/src/com/android/keyguard/clock/ClockManager.java b/packages/SystemUI/src/com/android/keyguard/clock/ClockManager.java
index 9cd4aec4617d..03674648d1e4 100644
--- a/packages/SystemUI/src/com/android/keyguard/clock/ClockManager.java
+++ b/packages/SystemUI/src/com/android/keyguard/clock/ClockManager.java
@@ -149,8 +149,6 @@ public final class ClockManager {
LayoutInflater layoutInflater = injectionInflater.injectable(LayoutInflater.from(context));
addBuiltinClock(() -> new DefaultClockController(res, layoutInflater, colorExtractor));
- addBuiltinClock(() -> new BubbleClockController(res, layoutInflater, colorExtractor));
- addBuiltinClock(() -> new AnalogClockController(res, layoutInflater, colorExtractor));
// Store the size of the display for generation of clock preview.
DisplayMetrics dm = res.getDisplayMetrics();
@@ -211,7 +209,8 @@ public final class ClockManager {
return mContentObserver;
}
- private void addBuiltinClock(Supplier<ClockPlugin> pluginSupplier) {
+ @VisibleForTesting
+ void addBuiltinClock(Supplier<ClockPlugin> pluginSupplier) {
ClockPlugin plugin = pluginSupplier.get();
mPreviewClocks.addClockPlugin(plugin);
mBuiltinClocks.add(pluginSupplier);
diff --git a/packages/SystemUI/src/com/android/systemui/ScreenDecorations.java b/packages/SystemUI/src/com/android/systemui/ScreenDecorations.java
index c9104dccce80..6ce6353147fb 100644
--- a/packages/SystemUI/src/com/android/systemui/ScreenDecorations.java
+++ b/packages/SystemUI/src/com/android/systemui/ScreenDecorations.java
@@ -96,6 +96,7 @@ public class ScreenDecorations extends SystemUI implements Tunable {
private static final boolean DEBUG_SCREENSHOT_ROUNDED_CORNERS =
SystemProperties.getBoolean("debug.screenshot_rounded_corners", false);
private static final boolean VERBOSE = false;
+ private static final boolean DEBUG_COLOR = DEBUG_SCREENSHOT_ROUNDED_CORNERS;
private DisplayManager mDisplayManager;
private boolean mIsRegistered;
@@ -454,6 +455,9 @@ public class ScreenDecorations extends SystemUI implements Tunable {
private void updateColorInversion(int colorsInvertedValue) {
int tint = colorsInvertedValue != 0 ? Color.WHITE : Color.BLACK;
+ if (DEBUG_COLOR) {
+ tint = Color.RED;
+ }
ColorStateList tintList = ColorStateList.valueOf(tint);
if (mOverlays == null) {
diff --git a/packages/SystemUI/src/com/android/systemui/stackdivider/Divider.java b/packages/SystemUI/src/com/android/systemui/stackdivider/Divider.java
index 2daefbde45a8..56cdff43e255 100644
--- a/packages/SystemUI/src/com/android/systemui/stackdivider/Divider.java
+++ b/packages/SystemUI/src/com/android/systemui/stackdivider/Divider.java
@@ -137,7 +137,8 @@ public class Divider extends SystemUI implements DividerView.DividerCallbacks,
try {
mLastImeTarget = ActivityTaskManager.getTaskOrganizerController()
.getImeTarget(displayId);
- mShouldAdjustForIme = !mSplitLayout.mDisplayLayout.isLandscape()
+ mShouldAdjustForIme = mLastImeTarget != null
+ && !mSplitLayout.mDisplayLayout.isLandscape()
&& (mLastImeTarget.asBinder()
== mSplits.mSecondary.token.asBinder());
} catch (RemoteException e) {
diff --git a/packages/SystemUI/src/com/android/systemui/util/animation/PhysicsAnimator.kt b/packages/SystemUI/src/com/android/systemui/util/animation/PhysicsAnimator.kt
index f4157f21e158..8625d63a3c7e 100644
--- a/packages/SystemUI/src/com/android/systemui/util/animation/PhysicsAnimator.kt
+++ b/packages/SystemUI/src/com/android/systemui/util/animation/PhysicsAnimator.kt
@@ -126,6 +126,13 @@ class PhysicsAnimator<T> private constructor (val target: T) {
internal var startAction: () -> Unit = ::startInternal
/**
+ * Action to run when [cancel] is called. This can be changed by
+ * [PhysicsAnimatorTestUtils.prepareForTest] to cancel animations from the main thread, which
+ * is required.
+ */
+ internal var cancelAction: (Set<FloatPropertyCompat<in T>>) -> Unit = ::cancelInternal
+
+ /**
* Springs a property to the given value, using the provided configuration settings.
*
* Springs are used when you know the exact value to which you want to animate. They can be
@@ -429,10 +436,13 @@ class PhysicsAnimator<T> private constructor (val target: T) {
max = max(currentValue, this.max)
}
- // Apply the configuration and start the animation. Since flings can't be
- // redirected while in motion, cancel it first.
+ // Flings can't be updated to a new position while maintaining velocity, because
+ // we're using the explicitly provided start velocity. Cancel any flings (or
+ // springs) on this property before flinging.
+ cancel(animatedProperty)
+
+ // Apply the configuration and start the animation.
getFlingAnimation(animatedProperty)
- .also { it.cancel() }
.also { flingConfig.applyToAnimation(it) }
.start()
}
@@ -707,11 +717,26 @@ class PhysicsAnimator<T> private constructor (val target: T) {
return springConfigs.keys.union(flingConfigs.keys)
}
+ /**
+ * Cancels the given properties. This is typically called immediately by [cancel], unless this
+ * animator is under test.
+ */
+ internal fun cancelInternal(properties: Set<FloatPropertyCompat<in T>>) {
+ for (property in properties) {
+ flingAnimations[property]?.cancel()
+ springAnimations[property]?.cancel()
+ }
+ }
+
/** Cancels all in progress animations on all properties. */
fun cancel() {
- for (dynamicAnim in flingAnimations.values.union(springAnimations.values)) {
- dynamicAnim.cancel()
- }
+ cancelAction(flingAnimations.keys)
+ cancelAction(springAnimations.keys)
+ }
+
+ /** Cancels in progress animations on the provided properties only. */
+ fun cancel(vararg properties: FloatPropertyCompat<in T>) {
+ cancelAction(properties.toSet())
}
/**
diff --git a/packages/SystemUI/src/com/android/systemui/util/animation/PhysicsAnimatorTestUtils.kt b/packages/SystemUI/src/com/android/systemui/util/animation/PhysicsAnimatorTestUtils.kt
index 965decd255a0..c50eeac80d7a 100644
--- a/packages/SystemUI/src/com/android/systemui/util/animation/PhysicsAnimatorTestUtils.kt
+++ b/packages/SystemUI/src/com/android/systemui/util/animation/PhysicsAnimatorTestUtils.kt
@@ -363,8 +363,12 @@ object PhysicsAnimatorTestUtils {
private val testEndListeners = ArrayList<PhysicsAnimator.EndListener<T>>()
private val testUpdateListeners = ArrayList<PhysicsAnimator.UpdateListener<T>>()
+ /** Whether we're currently in the middle of executing startInternal(). */
+ private var currentlyRunningStartInternal = false
+
init {
animator.startAction = ::startForTest
+ animator.cancelAction = ::cancelForTest
}
internal fun addTestEndListener(listener: PhysicsAnimator.EndListener<T>) {
@@ -437,7 +441,29 @@ object PhysicsAnimatorTestUtils {
}
})
+ currentlyRunningStartInternal = true
animator.startInternal()
+ currentlyRunningStartInternal = false
+ unblockLatch.countDown()
+ }
+
+ unblockLatch.await(timeoutMs, TimeUnit.MILLISECONDS)
+ }
+
+ private fun cancelForTest(properties: Set<FloatPropertyCompat<in T>>) {
+ // If this was called from startInternal, we are already on the animation thread, and
+ // should just call cancelInternal rather than posting it. If we post it, the
+ // cancellation will occur after the rest of startInternal() and we'll immediately
+ // cancel the animation we worked so hard to start!
+ if (currentlyRunningStartInternal) {
+ animator.cancelInternal(properties)
+ return
+ }
+
+ val unblockLatch = CountDownLatch(1)
+
+ animationThreadHandler.post {
+ animator.cancelInternal(properties)
unblockLatch.countDown()
}
diff --git a/packages/SystemUI/src/com/android/systemui/util/magnetictarget/MagnetizedObject.kt b/packages/SystemUI/src/com/android/systemui/util/magnetictarget/MagnetizedObject.kt
new file mode 100644
index 000000000000..2276ba19e432
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/util/magnetictarget/MagnetizedObject.kt
@@ -0,0 +1,618 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.android.systemui.util.magnetictarget
+
+import android.annotation.SuppressLint
+import android.content.Context
+import android.database.ContentObserver
+import android.graphics.PointF
+import android.os.Handler
+import android.os.UserHandle
+import android.os.VibrationEffect
+import android.os.Vibrator
+import android.provider.Settings
+import android.view.MotionEvent
+import android.view.VelocityTracker
+import android.view.View
+import androidx.dynamicanimation.animation.DynamicAnimation
+import androidx.dynamicanimation.animation.FloatPropertyCompat
+import androidx.dynamicanimation.animation.SpringForce
+import com.android.systemui.util.animation.PhysicsAnimator
+import kotlin.math.hypot
+
+/**
+ * Utility class for creating 'magnetized' objects that are attracted to one or more magnetic
+ * targets. Magnetic targets attract objects that are dragged near them, and hold them there unless
+ * they're moved away or released. Releasing objects inside a magnetic target typically performs an
+ * action on the object.
+ *
+ * MagnetizedObject also supports flinging to targets, which will result in the object being pulled
+ * into the target and released as if it was dragged into it.
+ *
+ * To use this class, either construct an instance with an object of arbitrary type, or use the
+ * [MagnetizedObject.magnetizeView] shortcut method if you're magnetizing a view. Then, set
+ * [magnetListener] to receive event callbacks. In your touch handler, pass all MotionEvents
+ * that move this object to [maybeConsumeMotionEvent]. If that method returns true, consider the
+ * event consumed by the MagnetizedObject and don't move the object unless it begins returning false
+ * again.
+ *
+ * @param context Context, used to retrieve a Vibrator instance for vibration effects.
+ * @param underlyingObject The actual object that we're magnetizing.
+ * @param xProperty Property that sets the x value of the object's position.
+ * @param yProperty Property that sets the y value of the object's position.
+ */
+abstract class MagnetizedObject<T : Any>(
+ val context: Context,
+
+ /** The actual object that is animated. */
+ val underlyingObject: T,
+
+ /** Property that gets/sets the object's X value. */
+ val xProperty: FloatPropertyCompat<in T>,
+
+ /** Property that gets/sets the object's Y value. */
+ val yProperty: FloatPropertyCompat<in T>
+) {
+
+ /** Return the width of the object. */
+ abstract fun getWidth(underlyingObject: T): Float
+
+ /** Return the height of the object. */
+ abstract fun getHeight(underlyingObject: T): Float
+
+ /**
+ * Fill the provided array with the location of the top-left of the object, relative to the
+ * entire screen. Compare to [View.getLocationOnScreen].
+ */
+ abstract fun getLocationOnScreen(underlyingObject: T, loc: IntArray)
+
+ /** Methods for listening to events involving a magnetized object. */
+ interface MagnetListener {
+
+ /**
+ * Called when touch events move within the magnetic field of a target, causing the
+ * object to animate to the target and become 'stuck' there. The animation happens
+ * automatically here - you should not move the object. You can, however, change its state
+ * to indicate to the user that it's inside the target and releasing it will have an effect.
+ *
+ * [maybeConsumeMotionEvent] is now returning true and will continue to do so until a call
+ * to [onUnstuckFromTarget] or [onReleasedInTarget].
+ *
+ * @param target The target that the object is now stuck to.
+ */
+ fun onStuckToTarget(target: MagneticTarget)
+
+ /**
+ * Called when the object is no longer stuck to a target. This means that either touch
+ * events moved outside of the magnetic field radius, or that a forceful fling out of the
+ * target was detected.
+ *
+ * The object won't be automatically animated out of the target, since you're responsible
+ * for moving the object again. You should move it (or animate it) using your own
+ * movement/animation logic.
+ *
+ * Reverse any effects applied in [onStuckToTarget] here.
+ *
+ * If [wasFlungOut] is true, [maybeConsumeMotionEvent] returned true for the ACTION_UP event
+ * that concluded the fling. If [wasFlungOut] is false, that means a drag gesture is ongoing
+ * and [maybeConsumeMotionEvent] is now returning false.
+ *
+ * @param target The target that this object was just unstuck from.
+ * @param velX The X velocity of the touch gesture when it exited the magnetic field.
+ * @param velY The Y velocity of the touch gesture when it exited the magnetic field.
+ * @param wasFlungOut Whether the object was unstuck via a fling gesture. This means that
+ * an ACTION_UP event was received, and that the gesture velocity was sufficient to conclude
+ * that the user wants to un-stick the object despite no touch events occurring outside of
+ * the magnetic field radius.
+ */
+ fun onUnstuckFromTarget(
+ target: MagneticTarget,
+ velX: Float,
+ velY: Float,
+ wasFlungOut: Boolean
+ )
+
+ /**
+ * Called when the object is released inside a target, or flung towards it with enough
+ * velocity to reach it.
+ *
+ * @param target The target that the object was released in.
+ */
+ fun onReleasedInTarget(target: MagneticTarget)
+ }
+
+ private val animator: PhysicsAnimator<T> = PhysicsAnimator.getInstance(underlyingObject)
+ private val objectLocationOnScreen = IntArray(2)
+
+ /**
+ * Targets that have been added to this object. These will all be considered when determining
+ * magnetic fields and fling trajectories.
+ */
+ private val associatedTargets = ArrayList<MagneticTarget>()
+
+ private val velocityTracker: VelocityTracker = VelocityTracker.obtain()
+ private val vibrator: Vibrator = context.getSystemService(Context.VIBRATOR_SERVICE) as Vibrator
+
+ /** Whether touch events are presently occurring within the magnetic field area of a target. */
+ val objectStuckToTarget: Boolean
+ get() = targetObjectIsStuckTo != null
+
+ /** The target the object is stuck to, or null if the object is not stuck to any target. */
+ private var targetObjectIsStuckTo: MagneticTarget? = null
+
+ /**
+ * Sets the listener to receive events. This must be set, or [maybeConsumeMotionEvent]
+ * will always return false and no magnetic effects will occur.
+ */
+ lateinit var magnetListener: MagnetizedObject.MagnetListener
+
+ /**
+ * Sets whether forcefully flinging the object vertically towards a target causes it to be
+ * attracted to the target and then released immediately, despite never being dragged within the
+ * magnetic field.
+ */
+ var flingToTargetEnabled = true
+
+ /**
+ * If fling to target is enabled, forcefully flinging the object towards a target will cause
+ * it to be attracted to the target and then released immediately, despite never being dragged
+ * within the magnetic field.
+ *
+ * This sets the width of the area considered 'near' enough a target to be considered a fling,
+ * in terms of percent of the target view's width. For example, setting this to 3f means that
+ * flings towards a 100px-wide target will be considered 'near' enough if they're towards the
+ * 300px-wide area around the target.
+ *
+ * Flings whose trajectory intersects the area will be attracted and released - even if the
+ * target view itself isn't intersected:
+ *
+ * | |
+ * | 0 |
+ * | / |
+ * | / |
+ * | X / |
+ * |.....###.....|
+ *
+ *
+ * Flings towards the target whose trajectories do not intersect the area will be treated as
+ * normal flings and the magnet will leave the object alone:
+ *
+ * | |
+ * | |
+ * | 0 |
+ * | / |
+ * | / X |
+ * |.....###.....|
+ *
+ */
+ var flingToTargetWidthPercent = 3f
+
+ /**
+ * Sets the minimum velocity (in pixels per second) required to fling an object to the target
+ * without dragging it into the magnetic field.
+ */
+ var flingToTargetMinVelocity = 4000f
+
+ /**
+ * Sets the minimum velocity (in pixels per second) required to fling un-stuck an object stuck
+ * to the target. If this velocity is reached, the object will be freed even if it wasn't moved
+ * outside the magnetic field radius.
+ */
+ var flingUnstuckFromTargetMinVelocity = 1000f
+
+ /**
+ * Sets the maximum velocity above which the object will not stick to the target. Even if the
+ * object is dragged through the magnetic field, it will not stick to the target until the
+ * velocity is below this value.
+ */
+ var stickToTargetMaxVelocity = 2000f
+
+ /**
+ * Enable or disable haptic vibration effects when the object interacts with the magnetic field.
+ *
+ * If you're experiencing crashes when the object enters targets, ensure that you have the
+ * android.permission.VIBRATE permission!
+ */
+ var hapticsEnabled = true
+
+ /** Whether the HAPTIC_FEEDBACK_ENABLED setting is true. */
+ private var systemHapticsEnabled = false
+
+ /** Default spring configuration to use for animating the object into a target. */
+ var springConfig = PhysicsAnimator.SpringConfig(
+ SpringForce.STIFFNESS_MEDIUM, SpringForce.DAMPING_RATIO_NO_BOUNCY)
+
+ /**
+ * Spring configuration to use to spring the object into a target specifically when it's flung
+ * towards (rather than dragged near) it.
+ */
+ var flungIntoTargetSpringConfig = springConfig
+
+ init {
+ val hapticSettingObserver =
+ object : ContentObserver(Handler.getMain()) {
+ override fun onChange(selfChange: Boolean) {
+ systemHapticsEnabled =
+ Settings.System.getIntForUser(
+ context.contentResolver,
+ Settings.System.HAPTIC_FEEDBACK_ENABLED,
+ 0,
+ UserHandle.USER_CURRENT) != 0
+ }
+ }
+
+ context.contentResolver.registerContentObserver(
+ Settings.System.getUriFor(Settings.System.HAPTIC_FEEDBACK_ENABLED),
+ true /* notifyForDescendants */, hapticSettingObserver)
+
+ // Trigger the observer once to initialize systemHapticsEnabled.
+ hapticSettingObserver.onChange(false /* selfChange */)
+ }
+
+ /**
+ * Adds the provided MagneticTarget to this object. The object will now be attracted to the
+ * target if it strays within its magnetic field or is flung towards it.
+ *
+ * If this target (or its magnetic field) overlaps another target added to this object, the
+ * prior target will take priority.
+ */
+ fun addTarget(target: MagneticTarget) {
+ associatedTargets.add(target)
+ target.updateLocationOnScreen()
+ }
+
+ /**
+ * Shortcut that accepts a View and a magnetic field radius and adds it as a magnetic target.
+ *
+ * @return The MagneticTarget instance for the given View. This can be used to change the
+ * target's magnetic field radius after it's been added. It can also be added to other
+ * magnetized objects.
+ */
+ fun addTarget(target: View, magneticFieldRadiusPx: Int): MagneticTarget {
+ return MagneticTarget(target, magneticFieldRadiusPx).also { addTarget(it) }
+ }
+
+ /**
+ * Removes the given target from this object. The target will no longer attract the object.
+ */
+ fun removeTarget(target: MagneticTarget) {
+ associatedTargets.remove(target)
+ }
+
+ /**
+ * Provide this method with all motion events that move the magnetized object. If the
+ * location of the motion events moves within the magnetic field of a target, or indicate a
+ * fling-to-target gesture, this method will return true and you should not move the object
+ * yourself until it returns false again.
+ *
+ * Note that even when this method returns true, you should continue to pass along new motion
+ * events so that we know when the events move back outside the magnetic field area.
+ *
+ * This method will always return false if you haven't set a [magnetListener].
+ */
+ fun maybeConsumeMotionEvent(ev: MotionEvent): Boolean {
+ // Short-circuit if we don't have a listener or any targets, since those are required.
+ if (associatedTargets.size == 0) {
+ return false
+ }
+
+ // When a gesture begins, recalculate target views' positions on the screen in case they
+ // have changed. Also, clear state.
+ if (ev.action == MotionEvent.ACTION_DOWN) {
+ updateTargetViewLocations()
+
+ // Clear the velocity tracker and assume we're not stuck to a target yet.
+ velocityTracker.clear()
+ targetObjectIsStuckTo = null
+ }
+
+ addMovement(ev)
+
+ val targetObjectIsInMagneticFieldOf = associatedTargets.firstOrNull { target ->
+ val distanceFromTargetCenter = hypot(
+ ev.rawX - target.centerOnScreen.x,
+ ev.rawY - target.centerOnScreen.y)
+ distanceFromTargetCenter < target.magneticFieldRadiusPx
+ }
+
+ // If we aren't currently stuck to a target, and we're in the magnetic field of a target,
+ // we're newly stuck.
+ val objectNewlyStuckToTarget =
+ !objectStuckToTarget && targetObjectIsInMagneticFieldOf != null
+
+ // If we are currently stuck to a target, we're in the magnetic field of a target, and that
+ // target isn't the one we're currently stuck to, then touch events have moved into a
+ // adjacent target's magnetic field.
+ val objectMovedIntoDifferentTarget =
+ objectStuckToTarget &&
+ targetObjectIsInMagneticFieldOf != null &&
+ targetObjectIsStuckTo != targetObjectIsInMagneticFieldOf
+
+ if (objectNewlyStuckToTarget || objectMovedIntoDifferentTarget) {
+ velocityTracker.computeCurrentVelocity(1000)
+ val velX = velocityTracker.xVelocity
+ val velY = velocityTracker.yVelocity
+
+ // If the object is moving too quickly within the magnetic field, do not stick it. This
+ // only applies to objects newly stuck to a target. If the object is moved into a new
+ // target, it wasn't moving at all (since it was stuck to the previous one).
+ if (objectNewlyStuckToTarget && hypot(velX, velY) > stickToTargetMaxVelocity) {
+ return false
+ }
+
+ // This touch event is newly within the magnetic field - let the listener know, and
+ // animate sticking to the magnet.
+ targetObjectIsStuckTo = targetObjectIsInMagneticFieldOf
+ cancelAnimations()
+ magnetListener.onStuckToTarget(targetObjectIsInMagneticFieldOf!!)
+ animateStuckToTarget(targetObjectIsInMagneticFieldOf!!, velX, velY, false)
+
+ vibrateIfEnabled(VibrationEffect.EFFECT_HEAVY_CLICK)
+ } else if (targetObjectIsInMagneticFieldOf == null && objectStuckToTarget) {
+ velocityTracker.computeCurrentVelocity(1000)
+
+ // This touch event is newly outside the magnetic field - let the listener know. It will
+ // move the object out of the target using its own movement logic.
+ cancelAnimations()
+ magnetListener.onUnstuckFromTarget(
+ targetObjectIsStuckTo!!, velocityTracker.xVelocity, velocityTracker.yVelocity,
+ wasFlungOut = false)
+ targetObjectIsStuckTo = null
+
+ vibrateIfEnabled(VibrationEffect.EFFECT_TICK)
+ }
+
+ // First, check for relevant gestures concluding with an ACTION_UP.
+ if (ev.action == MotionEvent.ACTION_UP) {
+
+ velocityTracker.computeCurrentVelocity(1000 /* units */)
+ val velX = velocityTracker.xVelocity
+ val velY = velocityTracker.yVelocity
+
+ // Cancel the magnetic animation since we might still be springing into the magnetic
+ // target, but we're about to fling away or release.
+ cancelAnimations()
+
+ if (objectStuckToTarget) {
+ if (hypot(velX, velY) > flingUnstuckFromTargetMinVelocity) {
+ // If the object is stuck, but it was forcefully flung away from the target,
+ // tell the listener so the object can be animated out of the target.
+ magnetListener.onUnstuckFromTarget(
+ targetObjectIsStuckTo!!, velX, velY, wasFlungOut = true)
+ } else {
+ // If the object is stuck and not flung away, it was released inside the target.
+ magnetListener.onReleasedInTarget(targetObjectIsStuckTo!!)
+ vibrateIfEnabled(VibrationEffect.EFFECT_HEAVY_CLICK)
+ }
+
+ // Either way, we're no longer stuck.
+ targetObjectIsStuckTo = null
+ return true
+ }
+
+ // The target we're flinging towards, or null if we're not flinging towards any target.
+ val flungToTarget = associatedTargets.firstOrNull { target ->
+ isForcefulFlingTowardsTarget(target, ev.rawX, ev.rawY, velX, velY)
+ }
+
+ if (flungToTarget != null) {
+ // If this is a fling-to-target, animate the object to the magnet and then release
+ // it.
+ magnetListener.onStuckToTarget(flungToTarget)
+ targetObjectIsStuckTo = flungToTarget
+
+ animateStuckToTarget(flungToTarget, velX, velY, true) {
+ targetObjectIsStuckTo = null
+ magnetListener.onReleasedInTarget(flungToTarget)
+ vibrateIfEnabled(VibrationEffect.EFFECT_HEAVY_CLICK)
+ }
+
+ return true
+ }
+
+ // If it's not either of those things, we are not interested.
+ return false
+ }
+
+ return objectStuckToTarget // Always consume touch events if the object is stuck.
+ }
+
+ /** Plays the given vibration effect if haptics are enabled. */
+ @SuppressLint("MissingPermission")
+ private fun vibrateIfEnabled(effect: Int) {
+ if (hapticsEnabled && systemHapticsEnabled) {
+ vibrator.vibrate(effect.toLong())
+ }
+ }
+
+ /** Adds the movement to the velocity tracker using raw coordinates. */
+ private fun addMovement(event: MotionEvent) {
+ // Add movement to velocity tracker using raw screen X and Y coordinates instead
+ // of window coordinates because the window frame may be moving at the same time.
+ val deltaX = event.rawX - event.x
+ val deltaY = event.rawY - event.y
+ event.offsetLocation(deltaX, deltaY)
+ velocityTracker.addMovement(event)
+ event.offsetLocation(-deltaX, -deltaY)
+ }
+
+ /** Animates sticking the object to the provided target with the given start velocities. */
+ private fun animateStuckToTarget(
+ target: MagneticTarget,
+ velX: Float,
+ velY: Float,
+ flung: Boolean,
+ after: (() -> Unit)? = null
+ ) {
+ target.updateLocationOnScreen()
+ getLocationOnScreen(underlyingObject, objectLocationOnScreen)
+
+ // Calculate the difference between the target's center coordinates and the object's.
+ // Animating the object's x/y properties by these values will center the object on top
+ // of the magnetic target.
+ val xDiff = target.centerOnScreen.x -
+ getWidth(underlyingObject) / 2f - objectLocationOnScreen[0]
+ val yDiff = target.centerOnScreen.y -
+ getHeight(underlyingObject) / 2f - objectLocationOnScreen[1]
+
+ val springConfig = if (flung) flungIntoTargetSpringConfig else springConfig
+
+ cancelAnimations()
+
+ // Animate to the center of the target.
+ animator
+ .spring(xProperty, xProperty.getValue(underlyingObject) + xDiff, velX,
+ springConfig)
+ .spring(yProperty, yProperty.getValue(underlyingObject) + yDiff, velY,
+ springConfig)
+
+ if (after != null) {
+ animator.withEndActions(after)
+ }
+
+ animator.start()
+ }
+
+ /**
+ * Whether or not the provided values match a 'fast fling' towards the provided target. If it
+ * does, we consider it a fling-to-target gesture.
+ */
+ private fun isForcefulFlingTowardsTarget(
+ target: MagneticTarget,
+ rawX: Float,
+ rawY: Float,
+ velX: Float,
+ velY: Float
+ ): Boolean {
+ if (!flingToTargetEnabled) {
+ return false
+ }
+
+ // Whether velocity is sufficient, depending on whether we're flinging into a target at the
+ // top or the bottom of the screen.
+ val velocitySufficient =
+ if (rawY < target.centerOnScreen.y) velY > flingToTargetMinVelocity
+ else velY < flingToTargetMinVelocity
+
+ if (!velocitySufficient) {
+ return false
+ }
+
+ // Whether the trajectory of the fling intersects the target area.
+ var targetCenterXIntercept = rawX
+
+ // Only do math if the X velocity is non-zero, otherwise X won't change.
+ if (velX != 0f) {
+ // Rise over run...
+ val slope = velY / velX
+ // ...y = mx + b, b = y / mx...
+ val yIntercept = rawY - slope * rawX
+
+ // ...calculate the x value when y = the target's y-coordinate.
+ targetCenterXIntercept = (target.centerOnScreen.y - yIntercept) / slope
+ }
+
+ // The width of the area we're looking for a fling towards.
+ val targetAreaWidth = target.targetView.width * flingToTargetWidthPercent
+
+ // Velocity was sufficient, so return true if the intercept is within the target area.
+ return targetCenterXIntercept > target.centerOnScreen.x - targetAreaWidth / 2 &&
+ targetCenterXIntercept < target.centerOnScreen.x + targetAreaWidth / 2
+ }
+
+ /** Cancel animations on this object's x/y properties. */
+ internal fun cancelAnimations() {
+ animator.cancel(xProperty, yProperty)
+ }
+
+ /** Updates the locations on screen of all of the [associatedTargets]. */
+ internal fun updateTargetViewLocations() {
+ associatedTargets.forEach { it.updateLocationOnScreen() }
+ }
+
+ /**
+ * Represents a target view with a magnetic field radius and cached center-on-screen
+ * coordinates.
+ *
+ * Instances of MagneticTarget are passed to a MagnetizedObject's [addTarget], and can then
+ * attract the object if it's dragged near or flung towards it. MagneticTargets can be added to
+ * multiple objects.
+ */
+ class MagneticTarget(
+ internal val targetView: View,
+ var magneticFieldRadiusPx: Int
+ ) {
+ internal val centerOnScreen = PointF()
+
+ private val tempLoc = IntArray(2)
+
+ fun updateLocationOnScreen() {
+ targetView.getLocationOnScreen(tempLoc)
+
+ // Add half of the target size to get the center, and subtract translation since the
+ // target could be animating in while we're doing this calculation.
+ centerOnScreen.set(
+ tempLoc[0] + targetView.width / 2f - targetView.translationX,
+ tempLoc[1] + targetView.height / 2f - targetView.translationY)
+ }
+ }
+
+ companion object {
+
+ /**
+ * Magnetizes the given view. Magnetized views are attracted to one or more magnetic
+ * targets. Magnetic targets attract objects that are dragged near them, and hold them there
+ * unless they're moved away or released. Releasing objects inside a magnetic target
+ * typically performs an action on the object.
+ *
+ * Magnetized views can also be flung to targets, which will result in the view being pulled
+ * into the target and released as if it was dragged into it.
+ *
+ * To use the returned MagnetizedObject<View> instance, first set [magnetListener] to
+ * receive event callbacks. In your touch handler, pass all MotionEvents that move this view
+ * to [maybeConsumeMotionEvent]. If that method returns true, consider the event consumed by
+ * MagnetizedObject and don't move the view unless it begins returning false again.
+ *
+ * The view will be moved via translationX/Y properties, and its
+ * width/height will be determined via getWidth()/getHeight(). If you are animating
+ * something other than a view, or want to position your view using properties other than
+ * translationX/Y, implement an instance of [MagnetizedObject].
+ *
+ * Note that the magnetic library can't re-order your view automatically. If the view
+ * renders on top of the target views, it will obscure the target when it sticks to it.
+ * You'll want to bring the view to the front in [MagnetListener.onStuckToTarget].
+ */
+ @JvmStatic
+ fun <T : View> magnetizeView(view: T): MagnetizedObject<T> {
+ return object : MagnetizedObject<T>(
+ view.context,
+ view,
+ DynamicAnimation.TRANSLATION_X,
+ DynamicAnimation.TRANSLATION_Y) {
+ override fun getWidth(underlyingObject: T): Float {
+ return underlyingObject.width.toFloat()
+ }
+
+ override fun getHeight(underlyingObject: T): Float {
+ return underlyingObject.height.toFloat() }
+
+ override fun getLocationOnScreen(underlyingObject: T, loc: IntArray) {
+ underlyingObject.getLocationOnScreen(loc)
+ }
+ }
+ }
+ }
+} \ No newline at end of file
diff --git a/packages/SystemUI/tests/Android.mk b/packages/SystemUI/tests/Android.mk
index e5f56d43f4d7..38da21e016ec 100644
--- a/packages/SystemUI/tests/Android.mk
+++ b/packages/SystemUI/tests/Android.mk
@@ -46,6 +46,9 @@ LOCAL_AAPT_FLAGS := --extra-packages com.android.systemui
# UI it doesn't own. This is necessary to allow screenshots to be taken
LOCAL_CERTIFICATE := platform
+LOCAL_FULL_LIBS_MANIFEST_FILES := $(LOCAL_PATH)/AndroidManifest.xml
+LOCAL_MANIFEST_FILE := AndroidManifest-base.xml
+
# Provide jack a list of classes to exclude from code coverage.
# This is needed because the SystemUITests compile SystemUI source directly, rather than using
# LOCAL_INSTRUMENTATION_FOR := SystemUI.
diff --git a/packages/SystemUI/tests/AndroidManifest-base.xml b/packages/SystemUI/tests/AndroidManifest-base.xml
new file mode 100644
index 000000000000..f08d3d2f48d4
--- /dev/null
+++ b/packages/SystemUI/tests/AndroidManifest-base.xml
@@ -0,0 +1,21 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2011 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"
+ xmlns:androidprv="http://schemas.android.com/apk/prv/res/android"
+ xmlns:tools="http://schemas.android.com/tools"
+ android:sharedUserId="android.uid.system"
+ package="com.android.systemui.tests" />
diff --git a/packages/SystemUI/tests/AndroidManifest.xml b/packages/SystemUI/tests/AndroidManifest.xml
index c51624b0994b..12c704881909 100644
--- a/packages/SystemUI/tests/AndroidManifest.xml
+++ b/packages/SystemUI/tests/AndroidManifest.xml
@@ -18,7 +18,7 @@
xmlns:androidprv="http://schemas.android.com/apk/prv/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:sharedUserId="android.uid.system"
- package="com.android.systemui.tests">
+ package="com.android.systemui" >
<uses-permission android:name="android.permission.SYSTEM_ALERT_WINDOW" />
<uses-permission android:name="android.permission.ACCESS_VOICE_INTERACTION_SERVICE" />
@@ -55,11 +55,6 @@
<application android:debuggable="true" android:largeHeap="true">
<uses-library android:name="android.test.runner" />
- <activity android:name="com.android.systemui.screenshot.ScreenshotStubActivity" />
-
- <service
- android:name="com.android.systemui.qs.external.TileLifecycleManagerTests$FakeTileService"
- android:process=":killable" />
<receiver android:name="com.android.systemui.SliceBroadcastRelayHandlerTest$Receiver">
<intent-filter>
diff --git a/packages/SystemUI/tests/src/com/android/keyguard/KeyguardPresentationTest.java b/packages/SystemUI/tests/src/com/android/keyguard/KeyguardPresentationTest.java
index b6ca8d8e4afb..7231b8a143d0 100644
--- a/packages/SystemUI/tests/src/com/android/keyguard/KeyguardPresentationTest.java
+++ b/packages/SystemUI/tests/src/com/android/keyguard/KeyguardPresentationTest.java
@@ -41,8 +41,8 @@ public class KeyguardPresentationTest extends SysuiTestCase {
InjectionInflationController inflationController = new InjectionInflationController(
SystemUIFactory.getInstance().getRootComponent());
Context context = getContext();
- KeyguardPresentation keyguardPresentation =
- new KeyguardPresentation(context, context.getDisplay(), inflationController);
+ KeyguardPresentation keyguardPresentation = new KeyguardPresentation(context,
+ context.getDisplayNoVerify(), inflationController);
keyguardPresentation.onCreate(null /*savedInstanceState */);
}
}
diff --git a/packages/SystemUI/tests/src/com/android/keyguard/clock/ClockManagerTest.java b/packages/SystemUI/tests/src/com/android/keyguard/clock/ClockManagerTest.java
index 3330d1e6d0a8..61991816a407 100644
--- a/packages/SystemUI/tests/src/com/android/keyguard/clock/ClockManagerTest.java
+++ b/packages/SystemUI/tests/src/com/android/keyguard/clock/ClockManagerTest.java
@@ -93,6 +93,8 @@ public final class ClockManagerTest extends SysuiTestCase {
mMockPluginManager, mMockColorExtractor, mMockContentResolver,
mMockCurrentUserObserable, mMockSettingsWrapper, mFakeDockManager);
+ mClockManager.addBuiltinClock(() -> new BubbleClockController(
+ getContext().getResources(), inflater, mMockColorExtractor));
mClockManager.addOnClockChangedListener(mMockListener1);
mClockManager.addOnClockChangedListener(mMockListener2);
reset(mMockListener1, mMockListener2);
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/NotificationRankingManagerTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/NotificationRankingManagerTest.kt
index 8e330c6f5049..45c51d42c250 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/NotificationRankingManagerTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/NotificationRankingManagerTest.kt
@@ -42,6 +42,7 @@ import org.junit.Before
import org.junit.Test
import org.junit.runner.RunWith
import org.mockito.Mockito.mock
+import org.mockito.Mockito.`when` as whenever
@SmallTest
@RunWith(AndroidTestingRunner::class)
@@ -52,18 +53,20 @@ class NotificationRankingManagerTest : SysuiTestCase() {
}
private lateinit var personNotificationIdentifier: PeopleNotificationIdentifier
private lateinit var rankingManager: TestableNotificationRankingManager
+ private lateinit var sectionsManager: NotificationSectionsFeatureManager
@Before
fun setup() {
personNotificationIdentifier =
mock(PeopleNotificationIdentifier::class.java)
+ sectionsManager = mock(NotificationSectionsFeatureManager::class.java)
rankingManager = TestableNotificationRankingManager(
lazyMedia,
mock(NotificationGroupManager::class.java),
mock(HeadsUpManager::class.java),
mock(NotificationFilter::class.java),
mock(NotificationEntryManagerLogger::class.java),
- mock(NotificationSectionsFeatureManager::class.java),
+ sectionsManager,
personNotificationIdentifier,
HighPriorityProvider(personNotificationIdentifier)
)
@@ -146,39 +149,42 @@ class NotificationRankingManagerTest : SysuiTestCase() {
@Test
fun testSort_importantPeople() {
+ whenever(sectionsManager.isFilteringEnabled()).thenReturn(true)
val aN = Notification.Builder(mContext, "test")
.setStyle(Notification.MessagingStyle(""))
.build()
- val aC = NotificationChannel("test", "", IMPORTANCE_DEFAULT)
- aC.setConversationId("parent", "convo")
val a = NotificationEntryBuilder()
.setImportance(IMPORTANCE_HIGH)
.setPkg("pkg")
.setOpPkg("pkg")
.setTag("tag")
.setNotification(aN)
- .setChannel(aC)
+ .setChannel(NotificationChannel("test", "", IMPORTANCE_DEFAULT))
.setUser(mContext.getUser())
.setOverrideGroupKey("")
.build()
+ whenever(personNotificationIdentifier.isImportantPeopleNotification(a.sbn, a.ranking))
+ .thenReturn(false)
+ whenever(personNotificationIdentifier.isPeopleNotification(a.sbn, a.ranking))
+ .thenReturn(true)
val bN = Notification.Builder(mContext, "test")
.setStyle(Notification.MessagingStyle(""))
.build()
- val bC = NotificationChannel("test", "", IMPORTANCE_DEFAULT)
- bC.setConversationId("parent", "convo")
- bC.setImportantConversation(true)
val b = NotificationEntryBuilder()
.setImportance(IMPORTANCE_HIGH)
.setPkg("pkg2")
.setOpPkg("pkg2")
.setTag("tag")
.setNotification(bN)
- .setChannel(bC)
+ .setChannel(NotificationChannel("test", "", IMPORTANCE_DEFAULT))
.setUser(mContext.getUser())
.setOverrideGroupKey("")
.build()
-
+ whenever(personNotificationIdentifier.isImportantPeopleNotification(a.sbn, a.ranking))
+ .thenReturn(false)
+ whenever(personNotificationIdentifier.isPeopleNotification(a.sbn, a.ranking))
+ .thenReturn(true)
assertEquals(
listOf(b, a),
diff --git a/packages/SystemUI/tests/src/com/android/systemui/util/magnetictarget/MagnetizedObjectTest.kt b/packages/SystemUI/tests/src/com/android/systemui/util/magnetictarget/MagnetizedObjectTest.kt
new file mode 100644
index 000000000000..f1672b1c644d
--- /dev/null
+++ b/packages/SystemUI/tests/src/com/android/systemui/util/magnetictarget/MagnetizedObjectTest.kt
@@ -0,0 +1,442 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.android.systemui.util.magnetictarget
+
+import android.testing.AndroidTestingRunner
+import android.testing.TestableLooper
+import android.view.MotionEvent
+import android.view.View
+import androidx.dynamicanimation.animation.FloatPropertyCompat
+import androidx.test.filters.SmallTest
+import com.android.systemui.SysuiTestCase
+import com.android.systemui.util.animation.PhysicsAnimatorTestUtils
+import org.junit.Assert.assertEquals
+import org.junit.Assert.assertFalse
+import org.junit.Assert.assertTrue
+import org.junit.Before
+import org.junit.Test
+import org.junit.runner.RunWith
+import org.mockito.ArgumentMatchers
+import org.mockito.ArgumentMatchers.anyFloat
+import org.mockito.Mockito
+import org.mockito.Mockito.`when`
+import org.mockito.Mockito.doAnswer
+import org.mockito.Mockito.mock
+import org.mockito.Mockito.never
+import org.mockito.Mockito.times
+import org.mockito.Mockito.verify
+import org.mockito.Mockito.verifyNoMoreInteractions
+
+@TestableLooper.RunWithLooper
+@RunWith(AndroidTestingRunner::class)
+@SmallTest
+class MagnetizedObjectTest : SysuiTestCase() {
+ /** Incrementing value for fake MotionEvent timestamps. */
+ private var time = 0L
+
+ /** Value to add to each new MotionEvent's timestamp. */
+ private var timeStep = 100
+
+ private val underlyingObject = this
+
+ private lateinit var targetView: View
+
+ private val targetSize = 200
+ private val targetCenterX = 500
+ private val targetCenterY = 900
+ private val magneticFieldRadius = 200
+
+ private var objectX = 0f
+ private var objectY = 0f
+ private val objectSize = 50f
+
+ private lateinit var magneticTarget: MagnetizedObject.MagneticTarget
+ private lateinit var magnetizedObject: MagnetizedObject<*>
+ private lateinit var magnetListener: MagnetizedObject.MagnetListener
+
+ private val xProperty = object : FloatPropertyCompat<MagnetizedObjectTest>("") {
+ override fun setValue(target: MagnetizedObjectTest?, value: Float) {
+ objectX = value
+ }
+ override fun getValue(target: MagnetizedObjectTest?): Float {
+ return objectX
+ }
+ }
+
+ private val yProperty = object : FloatPropertyCompat<MagnetizedObjectTest>("") {
+ override fun setValue(target: MagnetizedObjectTest?, value: Float) {
+ objectY = value
+ }
+
+ override fun getValue(target: MagnetizedObjectTest?): Float {
+ return objectY
+ }
+ }
+
+ @Before
+ fun setup() {
+ PhysicsAnimatorTestUtils.prepareForTest()
+
+ // Mock the view since a real view's getLocationOnScreen() won't work unless it's attached
+ // to a real window (it'll always return x = 0, y = 0).
+ targetView = mock(View::class.java)
+ `when`(targetView.context).thenReturn(context)
+
+ // The mock target view will pretend that it's 200x200, and at (400, 800). This means it's
+ // occupying the bounds (400, 800, 600, 1000) and it has a center of (500, 900).
+ `when`(targetView.width).thenReturn(targetSize) // width = 200
+ `when`(targetView.height).thenReturn(targetSize) // height = 200
+ doAnswer { invocation ->
+ (invocation.arguments[0] as IntArray).also { location ->
+ // Return the top left of the target.
+ location[0] = targetCenterX - targetSize / 2 // x = 400
+ location[1] = targetCenterY - targetSize / 2 // y = 800
+ }
+ }.`when`(targetView).getLocationOnScreen(ArgumentMatchers.any())
+ `when`(targetView.context).thenReturn(context)
+
+ magneticTarget = MagnetizedObject.MagneticTarget(targetView, magneticFieldRadius)
+
+ magnetListener = mock(MagnetizedObject.MagnetListener::class.java)
+ magnetizedObject = object : MagnetizedObject<MagnetizedObjectTest>(
+ context, underlyingObject, xProperty, yProperty) {
+ override fun getWidth(underlyingObject: MagnetizedObjectTest): Float {
+ return objectSize
+ }
+
+ override fun getHeight(underlyingObject: MagnetizedObjectTest): Float {
+ return objectSize
+ }
+
+ override fun getLocationOnScreen(
+ underlyingObject: MagnetizedObjectTest,
+ loc: IntArray
+ ) {
+ loc[0] = objectX.toInt()
+ loc[1] = objectY.toInt() }
+ }
+
+ magnetizedObject.magnetListener = magnetListener
+ magnetizedObject.addTarget(magneticTarget)
+
+ timeStep = 100
+ }
+
+ @Test
+ fun testMotionEventConsumption() {
+ // Start at (0, 0). No magnetic field here.
+ assertFalse(magnetizedObject.maybeConsumeMotionEvent(getMotionEvent(
+ x = 0, y = 0, action = MotionEvent.ACTION_DOWN)))
+
+ // Move to (400, 400), which is solidly outside the magnetic field.
+ assertFalse(magnetizedObject.maybeConsumeMotionEvent(getMotionEvent(
+ x = 200, y = 200)))
+
+ // Move to (305, 705). This would be in the magnetic field radius if magnetic fields were
+ // square. It's not, because they're not.
+ assertFalse(magnetizedObject.maybeConsumeMotionEvent(getMotionEvent(
+ x = targetCenterX - magneticFieldRadius + 5,
+ y = targetCenterY - magneticFieldRadius + 5)))
+
+ // Move to (400, 800). That's solidly in the radius so the magnetic target should begin
+ // consuming events.
+ assertTrue(magnetizedObject.maybeConsumeMotionEvent(getMotionEvent(
+ x = targetCenterX - 100,
+ y = targetCenterY - 100)))
+
+ // Release at (400, 800). Since we're in the magnetic target, it should return true and
+ // consume the ACTION_UP.
+ assertTrue(magnetizedObject.maybeConsumeMotionEvent(getMotionEvent(
+ x = 400, y = 800, action = MotionEvent.ACTION_UP)))
+
+ // ACTION_DOWN outside the field.
+ assertFalse(magnetizedObject.maybeConsumeMotionEvent(getMotionEvent(
+ x = 200, y = 200, action = MotionEvent.ACTION_DOWN)))
+
+ // Move to the center. We absolutely should consume events there.
+ assertTrue(magnetizedObject.maybeConsumeMotionEvent(getMotionEvent(
+ x = targetCenterX,
+ y = targetCenterY)))
+
+ // Drag out to (0, 0) and we should be returning false again.
+ assertFalse(magnetizedObject.maybeConsumeMotionEvent(getMotionEvent(
+ x = 0, y = 0)))
+
+ // The ACTION_UP event shouldn't be consumed either since it's outside the field.
+ assertFalse(magnetizedObject.maybeConsumeMotionEvent(getMotionEvent(
+ x = 0, y = 0, action = MotionEvent.ACTION_UP)))
+ }
+
+ @Test
+ fun testMotionEventConsumption_downInMagneticField() {
+ // We should consume DOWN events if they occur in the field.
+ assertTrue(magnetizedObject.maybeConsumeMotionEvent(getMotionEvent(
+ x = targetCenterX, y = targetCenterY, action = MotionEvent.ACTION_DOWN)))
+ }
+
+ @Test
+ fun testMoveIntoAroundAndOutOfMagneticField() {
+ // Move around but don't touch the magnetic field.
+ dispatchMotionEvents(
+ getMotionEvent(x = 0, y = 0, action = MotionEvent.ACTION_DOWN),
+ getMotionEvent(x = 100, y = 100),
+ getMotionEvent(x = 200, y = 200))
+
+ // You can't become unstuck if you were never stuck in the first place.
+ verify(magnetListener, never()).onStuckToTarget(magneticTarget)
+ verify(magnetListener, never()).onUnstuckFromTarget(
+ eq(magneticTarget), ArgumentMatchers.anyFloat(), ArgumentMatchers.anyFloat(),
+ eq(false))
+
+ // Move into and then around inside the magnetic field.
+ dispatchMotionEvents(
+ getMotionEvent(x = targetCenterX - 100, y = targetCenterY - 100),
+ getMotionEvent(x = targetCenterX, y = targetCenterY),
+ getMotionEvent(x = targetCenterX + 100, y = targetCenterY + 100))
+
+ // We should only have received one call to onStuckToTarget and none to unstuck.
+ verify(magnetListener, times(1)).onStuckToTarget(magneticTarget)
+ verify(magnetListener, never()).onUnstuckFromTarget(
+ eq(magneticTarget), ArgumentMatchers.anyFloat(), ArgumentMatchers.anyFloat(),
+ eq(false))
+
+ // Move out of the field and then release.
+ dispatchMotionEvents(
+ getMotionEvent(x = 100, y = 100),
+ getMotionEvent(x = 100, y = 100, action = MotionEvent.ACTION_UP))
+
+ // We should have received one unstuck call and no more stuck calls. We also should never
+ // have received an onReleasedInTarget call.
+ verify(magnetListener, times(1)).onUnstuckFromTarget(
+ eq(magneticTarget), ArgumentMatchers.anyFloat(), ArgumentMatchers.anyFloat(),
+ eq(false))
+ verifyNoMoreInteractions(magnetListener)
+ }
+
+ @Test
+ fun testMoveIntoOutOfAndBackIntoMagneticField() {
+ // Move into the field
+ dispatchMotionEvents(
+ getMotionEvent(
+ x = targetCenterX - magneticFieldRadius,
+ y = targetCenterY - magneticFieldRadius,
+ action = MotionEvent.ACTION_DOWN),
+ getMotionEvent(
+ x = targetCenterX, y = targetCenterY))
+
+ verify(magnetListener, times(1)).onStuckToTarget(magneticTarget)
+ verify(magnetListener, never()).onReleasedInTarget(magneticTarget)
+
+ // Move back out.
+ dispatchMotionEvents(
+ getMotionEvent(
+ x = targetCenterX - magneticFieldRadius,
+ y = targetCenterY - magneticFieldRadius))
+
+ verify(magnetListener, times(1)).onUnstuckFromTarget(
+ eq(magneticTarget), ArgumentMatchers.anyFloat(), ArgumentMatchers.anyFloat(),
+ eq(false))
+ verify(magnetListener, never()).onReleasedInTarget(magneticTarget)
+
+ // Move in again and release in the magnetic field.
+ dispatchMotionEvents(
+ getMotionEvent(x = targetCenterX - 100, y = targetCenterY - 100),
+ getMotionEvent(x = targetCenterX + 50, y = targetCenterY + 50),
+ getMotionEvent(x = targetCenterX, y = targetCenterY),
+ getMotionEvent(
+ x = targetCenterX, y = targetCenterY, action = MotionEvent.ACTION_UP))
+
+ verify(magnetListener, times(2)).onStuckToTarget(magneticTarget)
+ verify(magnetListener).onReleasedInTarget(magneticTarget)
+ verifyNoMoreInteractions(magnetListener)
+ }
+
+ @Test
+ fun testFlingTowardsTarget_towardsTarget() {
+ timeStep = 10
+
+ // Forcefully fling the object towards the target (but never touch the magnetic field).
+ dispatchMotionEvents(
+ getMotionEvent(
+ x = targetCenterX,
+ y = 0,
+ action = MotionEvent.ACTION_DOWN),
+ getMotionEvent(
+ x = targetCenterX,
+ y = targetCenterY / 2),
+ getMotionEvent(
+ x = targetCenterX,
+ y = targetCenterY - magneticFieldRadius * 2,
+ action = MotionEvent.ACTION_UP))
+
+ // Nevertheless it should have ended up stuck to the target.
+ verify(magnetListener, times(1)).onStuckToTarget(magneticTarget)
+ }
+
+ @Test
+ fun testFlingTowardsTarget_towardsButTooSlow() {
+ // Very, very slowly fling the object towards the target (but never touch the magnetic
+ // field). This value is only used to create MotionEvent timestamps, it will not block the
+ // test for 10 seconds.
+ timeStep = 10000
+ dispatchMotionEvents(
+ getMotionEvent(
+ x = targetCenterX,
+ y = 0,
+ action = MotionEvent.ACTION_DOWN),
+ getMotionEvent(
+ x = targetCenterX,
+ y = targetCenterY / 2),
+ getMotionEvent(
+ x = targetCenterX,
+ y = targetCenterY - magneticFieldRadius * 2,
+ action = MotionEvent.ACTION_UP))
+
+ // No sticking should have occurred.
+ verifyNoMoreInteractions(magnetListener)
+ }
+
+ @Test
+ fun testFlingTowardsTarget_missTarget() {
+ timeStep = 10
+ // Forcefully fling the object down, but not towards the target.
+ dispatchMotionEvents(
+ getMotionEvent(
+ x = 0,
+ y = 0,
+ action = MotionEvent.ACTION_DOWN),
+ getMotionEvent(
+ x = 0,
+ y = targetCenterY / 2),
+ getMotionEvent(
+ x = 0,
+ y = targetCenterY - magneticFieldRadius * 2,
+ action = MotionEvent.ACTION_UP))
+
+ verifyNoMoreInteractions(magnetListener)
+ }
+
+ @Test
+ fun testMagnetAnimation() {
+ // Make sure the object starts at (0, 0).
+ assertEquals(0f, objectX)
+ assertEquals(0f, objectY)
+
+ // Trigger the magnet animation, and block the test until it ends.
+ PhysicsAnimatorTestUtils.setAllAnimationsBlock(true)
+ magnetizedObject.maybeConsumeMotionEvent(getMotionEvent(
+ x = targetCenterX,
+ y = targetCenterY,
+ action = MotionEvent.ACTION_DOWN))
+
+ // The object's (top-left) position should now position it centered over the target.
+ assertEquals(targetCenterX - objectSize / 2, objectX)
+ assertEquals(targetCenterY - objectSize / 2, objectY)
+ }
+
+ @Test
+ fun testMultipleTargets() {
+ val secondMagneticTarget = getSecondMagneticTarget()
+
+ // Drag into the second target.
+ dispatchMotionEvents(
+ getMotionEvent(x = 0, y = 0, action = MotionEvent.ACTION_DOWN),
+ getMotionEvent(x = 100, y = 900))
+
+ // Verify that we received an onStuck for the second target, and no others.
+ verify(magnetListener).onStuckToTarget(secondMagneticTarget)
+ verifyNoMoreInteractions(magnetListener)
+
+ // Drag into the original target.
+ dispatchMotionEvents(
+ getMotionEvent(x = 0, y = 0),
+ getMotionEvent(x = 500, y = 900))
+
+ // We should have unstuck from the second one and stuck into the original one.
+ verify(magnetListener).onUnstuckFromTarget(
+ eq(secondMagneticTarget), anyFloat(), anyFloat(), eq(false))
+ verify(magnetListener).onStuckToTarget(magneticTarget)
+ verifyNoMoreInteractions(magnetListener)
+ }
+
+ @Test
+ fun testMultipleTargets_flingIntoSecond() {
+ val secondMagneticTarget = getSecondMagneticTarget()
+
+ timeStep = 10
+
+ // Fling towards the second target.
+ dispatchMotionEvents(
+ getMotionEvent(x = 100, y = 0, action = MotionEvent.ACTION_DOWN),
+ getMotionEvent(x = 100, y = 350),
+ getMotionEvent(x = 100, y = 650, action = MotionEvent.ACTION_UP))
+
+ // Verify that we received an onStuck for the second target.
+ verify(magnetListener).onStuckToTarget(secondMagneticTarget)
+
+ // Fling towards the first target.
+ dispatchMotionEvents(
+ getMotionEvent(x = 300, y = 0, action = MotionEvent.ACTION_DOWN),
+ getMotionEvent(x = 400, y = 350),
+ getMotionEvent(x = 500, y = 650, action = MotionEvent.ACTION_UP))
+
+ // Verify that we received onStuck for the original target.
+ verify(magnetListener).onStuckToTarget(magneticTarget)
+ }
+
+ private fun getSecondMagneticTarget(): MagnetizedObject.MagneticTarget {
+ // The first target view is at bounds (400, 800, 600, 1000) and it has a center of
+ // (500, 900). We'll add a second one at bounds (0, 800, 200, 1000) with center (100, 900).
+ val secondTargetView = mock(View::class.java)
+ var secondTargetCenterX = 100
+ var secondTargetCenterY = 900
+
+ `when`(secondTargetView.context).thenReturn(context)
+ `when`(secondTargetView.width).thenReturn(targetSize) // width = 200
+ `when`(secondTargetView.height).thenReturn(targetSize) // height = 200
+ doAnswer { invocation ->
+ (invocation.arguments[0] as IntArray).also { location ->
+ // Return the top left of the target.
+ location[0] = secondTargetCenterX - targetSize / 2 // x = 0
+ location[1] = secondTargetCenterY - targetSize / 2 // y = 800
+ }
+ }.`when`(secondTargetView).getLocationOnScreen(ArgumentMatchers.any())
+
+ return magnetizedObject.addTarget(secondTargetView, magneticFieldRadius)
+ }
+
+ /**
+ * Return a MotionEvent at the given coordinates, with the given action (or MOVE by default).
+ * The event's time fields will be incremented by 10ms each time this is called, so tha
+ * VelocityTracker works.
+ */
+ private fun getMotionEvent(
+ x: Int,
+ y: Int,
+ action: Int = MotionEvent.ACTION_MOVE
+ ): MotionEvent {
+ return MotionEvent.obtain(time, time, action, x.toFloat(), y.toFloat(), 0)
+ .also { time += timeStep }
+ }
+
+ /** Dispatch all of the provided events to the target view. */
+ private fun dispatchMotionEvents(vararg events: MotionEvent) {
+ events.forEach { magnetizedObject.maybeConsumeMotionEvent(it) }
+ }
+
+ /** Prevents Kotlin from being mad that eq() is nullable. */
+ private fun <T> eq(value: T): T = Mockito.eq(value) ?: value
+} \ No newline at end of file
diff --git a/packages/Tethering/common/TetheringLib/Android.bp b/packages/Tethering/common/TetheringLib/Android.bp
index cb0de7a860ac..1a3d5b659ee3 100644
--- a/packages/Tethering/common/TetheringLib/Android.bp
+++ b/packages/Tethering/common/TetheringLib/Android.bp
@@ -83,7 +83,6 @@ java_library {
name: "framework-tethering-stubs",
srcs: [":framework-tethering-stubs-sources"],
libs: ["framework-all"],
- static_libs: ["tethering-aidl-interfaces-java"],
sdk_version: "core_platform",
}
diff --git a/packages/Tethering/common/TetheringLib/src/android/net/TetheringConstants.java b/packages/Tethering/common/TetheringLib/src/android/net/TetheringConstants.java
index df87ac994d42..a18f5da60cad 100644
--- a/packages/Tethering/common/TetheringLib/src/android/net/TetheringConstants.java
+++ b/packages/Tethering/common/TetheringLib/src/android/net/TetheringConstants.java
@@ -33,6 +33,9 @@ import android.os.ResultReceiver;
*/
@SystemApi(client = MODULE_LIBRARIES)
public class TetheringConstants {
+ /** An explicit private class to avoid exposing constructor.*/
+ private TetheringConstants() { }
+
/**
* Extra used for communicating with the TetherService. Includes the type of tethering to
* enable if any.
diff --git a/packages/Tethering/src/com/android/server/connectivity/tethering/Tethering.java b/packages/Tethering/src/com/android/server/connectivity/tethering/Tethering.java
index 6261def6a939..72fe95b227a2 100644
--- a/packages/Tethering/src/com/android/server/connectivity/tethering/Tethering.java
+++ b/packages/Tethering/src/com/android/server/connectivity/tethering/Tethering.java
@@ -314,9 +314,13 @@ public class Tethering {
startStateMachineUpdaters(mHandler);
startTrackDefaultNetwork();
- getWifiManager().registerSoftApCallback(
- mHandler::post /* executor */,
- new TetheringSoftApCallback());
+
+ final WifiManager wifiManager = getWifiManager();
+ if (wifiManager != null) {
+ wifiManager.registerSoftApCallback(
+ mHandler::post /* executor */,
+ new TetheringSoftApCallback());
+ }
}
private void startStateMachineUpdaters(Handler handler) {
diff --git a/packages/WallpaperCropper/src/com/android/photos/views/TiledImageRenderer.java b/packages/WallpaperCropper/src/com/android/photos/views/TiledImageRenderer.java
index fcb113e90720..210fdc662bed 100644
--- a/packages/WallpaperCropper/src/com/android/photos/views/TiledImageRenderer.java
+++ b/packages/WallpaperCropper/src/com/android/photos/views/TiledImageRenderer.java
@@ -163,7 +163,7 @@ public class TiledImageRenderer {
private static boolean isHighResolution(Context context) {
DisplayMetrics metrics = new DisplayMetrics();
- context.getDisplay().getMetrics(metrics);
+ context.getDisplayNoVerify().getMetrics(metrics);
return metrics.heightPixels > 2048 || metrics.widthPixels > 2048;
}
diff --git a/proto/src/system_messages.proto b/proto/src/system_messages.proto
index eda3fb9c8698..cff55046fc2b 100644
--- a/proto/src/system_messages.proto
+++ b/proto/src/system_messages.proto
@@ -252,6 +252,9 @@ message SystemMessage {
// Package: android
NOTE_ID_WIFI_SIM_REQUIRED = 60;
+ // Inform the user a foreground service while-in-use permission is restricted.
+ NOTE_FOREGROUND_SERVICE_WHILE_IN_USE_PERMISSION = 61;
+
// ADD_NEW_IDS_ABOVE_THIS_LINE
// Legacy IDs with arbitrary values appear below
// Legacy IDs existed as stable non-conflicting constants prior to the O release
diff --git a/services/Android.bp b/services/Android.bp
index c77e75da66ba..db6e21a62ff3 100644
--- a/services/Android.bp
+++ b/services/Android.bp
@@ -114,9 +114,10 @@ droidstubs {
name: "services-stubs.sources",
srcs: [":services-all-sources"],
installable: false,
- // TODO: remove the --hide options below
args: " --show-annotation android.annotation.SystemApi\\(client=android.annotation.SystemApi.Client.SYSTEM_SERVER\\)" +
" --hide-annotation android.annotation.Hide" +
+ " --hide InternalClasses" + // com.android.* classes are okay in this interface
+ // TODO: remove the --hide options below
" --hide-package com.google.android.startop.iorap" +
" --hide ReferencesHidden" +
" --hide DeprecationMismatch" +
diff --git a/services/accessibility/OWNERS b/services/accessibility/OWNERS
index 265674a74b7e..c6f42f719caa 100644
--- a/services/accessibility/OWNERS
+++ b/services/accessibility/OWNERS
@@ -1,3 +1,4 @@
svetoslavganov@google.com
pweaver@google.com
rhedjao@google.com
+qasid@google.com
diff --git a/services/api/current.txt b/services/api/current.txt
index 8a82e610c233..26a65f21ed83 100644
--- a/services/api/current.txt
+++ b/services/api/current.txt
@@ -3,9 +3,9 @@ package com.android.permission.persistence {
public interface RuntimePermissionsPersistence {
method @NonNull public static com.android.permission.persistence.RuntimePermissionsPersistence createInstance();
- method public void delete(@NonNull android.os.UserHandle);
- method @Nullable public com.android.permission.persistence.RuntimePermissionsState read(@NonNull android.os.UserHandle);
- method public void write(@NonNull com.android.permission.persistence.RuntimePermissionsState, @NonNull android.os.UserHandle);
+ method public void deleteAsUser(@NonNull android.os.UserHandle);
+ method @Nullable public com.android.permission.persistence.RuntimePermissionsState readAsUser(@NonNull android.os.UserHandle);
+ method public void writeAsUser(@NonNull com.android.permission.persistence.RuntimePermissionsState, @NonNull android.os.UserHandle);
}
public final class RuntimePermissionsState {
@@ -30,9 +30,9 @@ package com.android.role.persistence {
public interface RolesPersistence {
method @NonNull public static com.android.role.persistence.RolesPersistence createInstance();
- method public void delete(@NonNull android.os.UserHandle);
- method @Nullable public com.android.role.persistence.RolesState read(@NonNull android.os.UserHandle);
- method public void write(@NonNull com.android.role.persistence.RolesState, @NonNull android.os.UserHandle);
+ method public void deleteAsUser(@NonNull android.os.UserHandle);
+ method @Nullable public com.android.role.persistence.RolesState readAsUser(@NonNull android.os.UserHandle);
+ method public void writeAsUser(@NonNull com.android.role.persistence.RolesState, @NonNull android.os.UserHandle);
}
public final class RolesState {
diff --git a/services/api/lint-baseline.txt b/services/api/lint-baseline.txt
index 0b8658cf469d..e985ddb5352b 100644
--- a/services/api/lint-baseline.txt
+++ b/services/api/lint-baseline.txt
@@ -1,35 +1,5 @@
// Baseline format: 1.0
-InternalClasses: com.android.permission.persistence.RuntimePermissionsPersistence:
- Internal classes must not be exposed
-InternalClasses: com.android.permission.persistence.RuntimePermissionsState:
- Internal classes must not be exposed
-InternalClasses: com.android.permission.persistence.RuntimePermissionsState.PermissionState:
- Internal classes must not be exposed
-InternalClasses: com.android.role.persistence.RolesPersistence:
- Internal classes must not be exposed
-InternalClasses: com.android.role.persistence.RolesState:
- Internal classes must not be exposed
-InternalClasses: com.android.server.SystemService:
- Internal classes must not be exposed
-InternalClasses: com.android.server.SystemService.TargetUser:
- Internal classes must not be exposed
-
-
ProtectedMember: com.android.server.SystemService#publishBinderService(String, android.os.IBinder):
Protected methods not allowed; must be public: method com.android.server.SystemService.publishBinderService(String,android.os.IBinder)}
ProtectedMember: com.android.server.SystemService#publishBinderService(String, android.os.IBinder, boolean):
Protected methods not allowed; must be public: method com.android.server.SystemService.publishBinderService(String,android.os.IBinder,boolean)}
-
-
-UserHandleName: com.android.permission.persistence.RuntimePermissionsPersistence#delete(android.os.UserHandle):
- Method taking UserHandle should be named `doFooAsUser` or `queryFooForUser`, was `delete`
-UserHandleName: com.android.permission.persistence.RuntimePermissionsPersistence#read(android.os.UserHandle):
- Method taking UserHandle should be named `doFooAsUser` or `queryFooForUser`, was `read`
-UserHandleName: com.android.permission.persistence.RuntimePermissionsPersistence#write(com.android.permission.persistence.RuntimePermissionsState, android.os.UserHandle):
- Method taking UserHandle should be named `doFooAsUser` or `queryFooForUser`, was `write`
-UserHandleName: com.android.role.persistence.RolesPersistence#delete(android.os.UserHandle):
- Method taking UserHandle should be named `doFooAsUser` or `queryFooForUser`, was `delete`
-UserHandleName: com.android.role.persistence.RolesPersistence#read(android.os.UserHandle):
- Method taking UserHandle should be named `doFooAsUser` or `queryFooForUser`, was `read`
-UserHandleName: com.android.role.persistence.RolesPersistence#write(com.android.role.persistence.RolesState, android.os.UserHandle):
- Method taking UserHandle should be named `doFooAsUser` or `queryFooForUser`, was `write`
diff --git a/services/appwidget/java/com/android/server/appwidget/AppWidgetServiceImpl.java b/services/appwidget/java/com/android/server/appwidget/AppWidgetServiceImpl.java
index 7151d2b86e83..a8a27916f56a 100644
--- a/services/appwidget/java/com/android/server/appwidget/AppWidgetServiceImpl.java
+++ b/services/appwidget/java/com/android/server/appwidget/AppWidgetServiceImpl.java
@@ -281,7 +281,7 @@ class AppWidgetServiceImpl extends IAppWidgetService.Stub implements WidgetBacku
}
private void computeMaximumWidgetBitmapMemory() {
- Display display = mContext.getDisplay();
+ Display display = mContext.getDisplayNoVerify();
Point size = new Point();
display.getRealSize(size);
// Cap memory usage at 1.5 times the size of the display
diff --git a/services/autofill/java/com/android/server/autofill/ui/CustomScrollView.java b/services/autofill/java/com/android/server/autofill/ui/CustomScrollView.java
index 813fc8d5f561..14bd7d78f3bf 100644
--- a/services/autofill/java/com/android/server/autofill/ui/CustomScrollView.java
+++ b/services/autofill/java/com/android/server/autofill/ui/CustomScrollView.java
@@ -75,7 +75,7 @@ public class CustomScrollView extends ScrollView {
final TypedValue typedValue = new TypedValue();
final Point point = new Point();
final Context context = getContext();
- context.getDisplay().getSize(point);
+ context.getDisplayNoVerify().getSize(point);
context.getTheme().resolveAttribute(R.attr.autofillSaveCustomSubtitleMaxHeight,
typedValue, true);
final View child = getChildAt(0);
diff --git a/services/autofill/java/com/android/server/autofill/ui/FillUi.java b/services/autofill/java/com/android/server/autofill/ui/FillUi.java
index 5dc43ef8ad56..344b92f43089 100644
--- a/services/autofill/java/com/android/server/autofill/ui/FillUi.java
+++ b/services/autofill/java/com/android/server/autofill/ui/FillUi.java
@@ -165,7 +165,7 @@ final class FillUi {
// In full screen we only initialize size once assuming screen size never changes
if (mFullScreen) {
final Point outPoint = mTempPoint;
- mContext.getDisplay().getSize(outPoint);
+ mContext.getDisplayNoVerify().getSize(outPoint);
// full with of screen and half height of screen
mContentWidth = LayoutParams.MATCH_PARENT;
mContentHeight = outPoint.y / 2;
@@ -559,7 +559,7 @@ final class FillUi {
}
private static void resolveMaxWindowSize(Context context, Point outPoint) {
- context.getDisplay().getSize(outPoint);
+ context.getDisplayNoVerify().getSize(outPoint);
final TypedValue typedValue = sTempTypedValue;
context.getTheme().resolveAttribute(R.attr.autofillDatasetPickerMaxWidth,
typedValue, true);
diff --git a/services/backup/java/com/android/server/backup/restore/PerformUnifiedRestoreTask.java b/services/backup/java/com/android/server/backup/restore/PerformUnifiedRestoreTask.java
index 3c37f737f8be..e434be648dcb 100644
--- a/services/backup/java/com/android/server/backup/restore/PerformUnifiedRestoreTask.java
+++ b/services/backup/java/com/android/server/backup/restore/PerformUnifiedRestoreTask.java
@@ -76,9 +76,7 @@ import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.util.ArrayList;
-import java.util.Collections;
import java.util.List;
-import java.util.Map;
import java.util.Objects;
import java.util.Set;
@@ -802,6 +800,7 @@ public class PerformUnifiedRestoreTask implements BackupRestoreTask {
final int size = in.getDataSize();
if (excludedKeysForPackage != null && excludedKeysForPackage.contains(key)) {
+ Slog.i(TAG, "Skipping blocked key " + key);
in.skipEntityData();
continue;
}
diff --git a/services/core/java/com/android/server/ConnectivityService.java b/services/core/java/com/android/server/ConnectivityService.java
index f7eabac3b21f..e48ef5a528be 100644
--- a/services/core/java/com/android/server/ConnectivityService.java
+++ b/services/core/java/com/android/server/ConnectivityService.java
@@ -1534,7 +1534,8 @@ public class ConnectivityService extends IConnectivityManager.Stub
}
@Override
- public NetworkCapabilities[] getDefaultNetworkCapabilitiesForUser(int userId) {
+ public NetworkCapabilities[] getDefaultNetworkCapabilitiesForUser(
+ int userId, String callingPackageName) {
// The basic principle is: if an app's traffic could possibly go over a
// network, without the app doing anything multinetwork-specific,
// (hence, by "default"), then include that network's capabilities in
@@ -1556,7 +1557,10 @@ public class ConnectivityService extends IConnectivityManager.Stub
NetworkAgentInfo nai = getDefaultNetwork();
NetworkCapabilities nc = getNetworkCapabilitiesInternal(nai);
if (nc != null) {
- result.put(nai.network, nc);
+ result.put(
+ nai.network,
+ maybeSanitizeLocationInfoForCaller(
+ nc, Binder.getCallingUid(), callingPackageName));
}
synchronized (mVpns) {
@@ -1566,10 +1570,12 @@ public class ConnectivityService extends IConnectivityManager.Stub
Network[] networks = vpn.getUnderlyingNetworks();
if (networks != null) {
for (Network network : networks) {
- nai = getNetworkAgentInfoForNetwork(network);
- nc = getNetworkCapabilitiesInternal(nai);
+ nc = getNetworkCapabilitiesInternal(network);
if (nc != null) {
- result.put(network, nc);
+ result.put(
+ network,
+ maybeSanitizeLocationInfoForCaller(
+ nc, Binder.getCallingUid(), callingPackageName));
}
}
}
@@ -1636,20 +1642,26 @@ public class ConnectivityService extends IConnectivityManager.Stub
}
}
+ private NetworkCapabilities getNetworkCapabilitiesInternal(Network network) {
+ return getNetworkCapabilitiesInternal(getNetworkAgentInfoForNetwork(network));
+ }
+
private NetworkCapabilities getNetworkCapabilitiesInternal(NetworkAgentInfo nai) {
if (nai == null) return null;
synchronized (nai) {
if (nai.networkCapabilities == null) return null;
return networkCapabilitiesRestrictedForCallerPermissions(
- nai.networkCapabilities,
- Binder.getCallingPid(), Binder.getCallingUid());
+ nai.networkCapabilities, Binder.getCallingPid(), Binder.getCallingUid());
}
}
@Override
- public NetworkCapabilities getNetworkCapabilities(Network network) {
+ public NetworkCapabilities getNetworkCapabilities(Network network, String callingPackageName) {
+ mAppOpsManager.checkPackage(Binder.getCallingUid(), callingPackageName);
enforceAccessPermission();
- return getNetworkCapabilitiesInternal(getNetworkAgentInfoForNetwork(network));
+ return maybeSanitizeLocationInfoForCaller(
+ getNetworkCapabilitiesInternal(network),
+ Binder.getCallingUid(), callingPackageName);
}
@VisibleForTesting
@@ -1665,20 +1677,34 @@ public class ConnectivityService extends IConnectivityManager.Stub
}
newNc.setAdministratorUids(Collections.EMPTY_LIST);
- maybeSanitizeLocationInfoForCaller(newNc, callerUid);
-
return newNc;
}
- private void maybeSanitizeLocationInfoForCaller(
- NetworkCapabilities nc, int callerUid) {
- // TODO(b/142072839): Conditionally reset the owner UID if the following
- // conditions are not met:
- // 1. The destination app is the network owner
- // 2. The destination app has the ACCESS_COARSE_LOCATION permission granted
- // if target SDK<29 or otherwise has the ACCESS_FINE_LOCATION permission granted
- // 3. The user's location toggle is on
- nc.setOwnerUid(INVALID_UID);
+ @VisibleForTesting
+ @Nullable
+ NetworkCapabilities maybeSanitizeLocationInfoForCaller(
+ @Nullable NetworkCapabilities nc, int callerUid, @NonNull String callerPkgName) {
+ if (nc == null) {
+ return null;
+ }
+ final NetworkCapabilities newNc = new NetworkCapabilities(nc);
+ if (callerUid != newNc.getOwnerUid()) {
+ newNc.setOwnerUid(INVALID_UID);
+ return newNc;
+ }
+
+ Binder.withCleanCallingIdentity(
+ () -> {
+ if (!mLocationPermissionChecker.checkLocationPermission(
+ callerPkgName, null /* featureId */, callerUid, null /* message */)) {
+ // Caller does not have the requisite location permissions. Reset the
+ // owner's UID in the NetworkCapabilities.
+ newNc.setOwnerUid(INVALID_UID);
+ }
+ }
+ );
+
+ return newNc;
}
private LinkProperties linkPropertiesRestrictedForCallerPermissions(
@@ -1753,7 +1779,7 @@ public class ConnectivityService extends IConnectivityManager.Stub
public boolean isActiveNetworkMetered() {
enforceAccessPermission();
- final NetworkCapabilities caps = getNetworkCapabilities(getActiveNetwork());
+ final NetworkCapabilities caps = getNetworkCapabilitiesInternal(getActiveNetwork());
if (caps != null) {
return !caps.hasCapability(NetworkCapabilities.NET_CAPABILITY_NOT_METERED);
} else {
@@ -5330,8 +5356,8 @@ public class ConnectivityService extends IConnectivityManager.Stub
}
public String toString() {
- return "uid/pid:" + mUid + "/" + mPid + " " + request +
- (mPendingIntent == null ? "" : " to trigger " + mPendingIntent);
+ return "uid/pid:" + mUid + "/" + mPid + " " + request
+ + (mPendingIntent == null ? "" : " to trigger " + mPendingIntent);
}
}
@@ -6408,8 +6434,13 @@ public class ConnectivityService extends IConnectivityManager.Stub
}
switch (notificationType) {
case ConnectivityManager.CALLBACK_AVAILABLE: {
- putParcelable(bundle, networkCapabilitiesRestrictedForCallerPermissions(
- networkAgent.networkCapabilities, nri.mPid, nri.mUid));
+ final NetworkCapabilities nc =
+ networkCapabilitiesRestrictedForCallerPermissions(
+ networkAgent.networkCapabilities, nri.mPid, nri.mUid);
+ putParcelable(
+ bundle,
+ maybeSanitizeLocationInfoForCaller(
+ nc, nri.mUid, nri.request.getRequestorPackageName()));
putParcelable(bundle, linkPropertiesRestrictedForCallerPermissions(
networkAgent.linkProperties, nri.mPid, nri.mUid));
// For this notification, arg1 contains the blocked status.
@@ -6422,9 +6453,13 @@ public class ConnectivityService extends IConnectivityManager.Stub
}
case ConnectivityManager.CALLBACK_CAP_CHANGED: {
// networkAgent can't be null as it has been accessed a few lines above.
- final NetworkCapabilities nc = networkCapabilitiesRestrictedForCallerPermissions(
- networkAgent.networkCapabilities, nri.mPid, nri.mUid);
- putParcelable(bundle, nc);
+ final NetworkCapabilities netCap =
+ networkCapabilitiesRestrictedForCallerPermissions(
+ networkAgent.networkCapabilities, nri.mPid, nri.mUid);
+ putParcelable(
+ bundle,
+ maybeSanitizeLocationInfoForCaller(
+ netCap, nri.mUid, nri.request.getRequestorPackageName()));
break;
}
case ConnectivityManager.CALLBACK_IP_CHANGED: {
diff --git a/services/core/java/com/android/server/LocationManagerService.java b/services/core/java/com/android/server/LocationManagerService.java
index 5db5115b4afe..d515332815d6 100644
--- a/services/core/java/com/android/server/LocationManagerService.java
+++ b/services/core/java/com/android/server/LocationManagerService.java
@@ -862,10 +862,6 @@ public class LocationManagerService extends ILocationManager.Stub {
}
}
- public void requestSetAllowed(boolean allowed) {
- mProvider.requestSetAllowed(allowed);
- }
-
public void onUserStarted(int userId) {
synchronized (mLock) {
// clear the user's enabled state in order to force a reevalution of whether the
@@ -2931,18 +2927,6 @@ public class LocationManagerService extends ILocationManager.Stub {
private class LocalService extends LocationManagerInternal {
@Override
- public void requestSetProviderAllowed(String provider, boolean allowed) {
- Preconditions.checkArgument(provider != null, "invalid null provider");
-
- synchronized (mLock) {
- LocationProviderManager manager = getLocationProviderManager(provider);
- if (manager != null) {
- manager.requestSetAllowed(allowed);
- }
- }
- }
-
- @Override
public boolean isProviderEnabledForUser(@NonNull String provider, int userId) {
synchronized (mLock) {
LocationProviderManager manager = getLocationProviderManager(provider);
diff --git a/services/core/java/com/android/server/Watchdog.java b/services/core/java/com/android/server/Watchdog.java
index a1ccd8459c69..8900eee6f50f 100644
--- a/services/core/java/com/android/server/Watchdog.java
+++ b/services/core/java/com/android/server/Watchdog.java
@@ -100,7 +100,7 @@ public class Watchdog extends Thread {
"media.codec", // vendor/bin/hw/android.hardware.media.omx@1.0-service
"media.swcodec", // /apex/com.android.media.swcodec/bin/mediaswcodec
"com.android.bluetooth", // Bluetooth service
- "/system/bin/statsd", // Stats daemon
+ "/apex/com.android.os.statsd/bin/statsd", // Stats daemon
};
public static final List<String> HAL_INTERFACES_OF_INTEREST = Arrays.asList(
diff --git a/services/core/java/com/android/server/am/ActiveServices.java b/services/core/java/com/android/server/am/ActiveServices.java
index 50f43b5c1bae..2bcb28de5d9c 100644
--- a/services/core/java/com/android/server/am/ActiveServices.java
+++ b/services/core/java/com/android/server/am/ActiveServices.java
@@ -62,7 +62,6 @@ import android.content.pm.PackageManager;
import android.content.pm.ParceledListSlice;
import android.content.pm.ResolveInfo;
import android.content.pm.ServiceInfo;
-import android.content.res.Resources;
import android.net.Uri;
import android.os.Binder;
import android.os.Build;
@@ -91,7 +90,6 @@ import android.util.SparseArray;
import android.util.TimeUtils;
import android.util.proto.ProtoOutputStream;
import android.webkit.WebViewZygote;
-import android.widget.Toast;
import com.android.internal.R;
import com.android.internal.app.procstats.ServiceState;
@@ -4687,20 +4685,35 @@ public final class ActiveServices {
}
// TODO: remove this toast after feature development is done
- private void showWhileInUsePermissionInFgsBlockedToastLocked(String callingPackage) {
- final Resources res = mAm.mContext.getResources();
- final String toastMsg = res.getString(
- R.string.allow_while_in_use_permission_in_fgs, callingPackage);
- mAm.mUiHandler.post(() -> {
- Toast.makeText(mAm.mContext, toastMsg, Toast.LENGTH_LONG).show();
- });
+ private void showWhileInUsePermissionInFgsBlockedNotificationLocked(String callingPackage,
+ String detailInfo) {
+ final Context context = mAm.mContext;
+ final String title = "Foreground Service While-in-use Permission Restricted";
+ final String content = "App affected:" + callingPackage + ", please file a bug report";
+ Notification.Builder n =
+ new Notification.Builder(context,
+ SystemNotificationChannels.ALERTS)
+ .setSmallIcon(R.drawable.stat_sys_vitals)
+ .setWhen(0)
+ .setColor(context.getColor(
+ com.android.internal.R.color.system_notification_accent_color))
+ .setTicker(title)
+ .setContentTitle(title)
+ .setContentText(content)
+ .setStyle(new Notification.BigTextStyle().bigText(detailInfo));
+ final NotificationManager notificationManager =
+ (NotificationManager) context.getSystemService(context.NOTIFICATION_SERVICE);
+ notificationManager.notifyAsUser(null,
+ SystemMessageProto.SystemMessage.NOTE_FOREGROUND_SERVICE_WHILE_IN_USE_PERMISSION,
+ n.build(), UserHandle.ALL);
}
// TODO: remove this toast after feature development is done
// show a toast message to ask user to file a bugreport so we know how many apps are impacted by
// the new background started foreground service while-in-use permission restriction.
- void showWhileInUseDebugToastLocked(int uid, int op, int mode) {
- StringBuilder sb = new StringBuilder();
+ void showWhileInUseDebugNotificationLocked(int uid, int op, int mode) {
+ StringBuilder packageNameBuilder = new StringBuilder();
+ StringBuilder detailInfoBuilder = new StringBuilder();
for (int i = mAm.mProcessList.mLruProcesses.size() - 1; i >= 0; i--) {
ProcessRecord pr = mAm.mProcessList.mLruProcesses.get(i);
if (pr.uid != uid) {
@@ -4713,17 +4726,22 @@ public final class ActiveServices {
}
if (!r.mAllowWhileInUsePermissionInFgs
&& r.mInfoDenyWhileInUsePermissionInFgs != null) {
- Slog.wtf(TAG, r.mInfoDenyWhileInUsePermissionInFgs
- + " affected while-use-permission:" + AppOpsManager.opToPublicName(op));
- sb.append(r.mRecentCallingPackage + " ");
+ final String msg = r.mInfoDenyWhileInUsePermissionInFgs
+ + " affected while-in-use permission:"
+ + AppOpsManager.opToPublicName(op);
+ Slog.wtf(TAG, msg);
+ packageNameBuilder.append(r.mRecentCallingPackage + " ");
+ detailInfoBuilder.append(msg);
+ detailInfoBuilder.append("\n");
}
}
}
- final String callingPackageStr = sb.toString();
+ final String callingPackageStr = packageNameBuilder.toString();
if (mAm.mConstants.mFlagForegroundServiceStartsLoggingEnabled
&& !callingPackageStr.isEmpty()) {
- showWhileInUsePermissionInFgsBlockedToastLocked(callingPackageStr);
+ showWhileInUsePermissionInFgsBlockedNotificationLocked(callingPackageStr,
+ detailInfoBuilder.toString());
}
}
}
diff --git a/services/core/java/com/android/server/am/ActivityManagerService.java b/services/core/java/com/android/server/am/ActivityManagerService.java
index 6bf5aa3f19d8..a529f24eff1c 100644
--- a/services/core/java/com/android/server/am/ActivityManagerService.java
+++ b/services/core/java/com/android/server/am/ActivityManagerService.java
@@ -7271,7 +7271,7 @@ public class ActivityManagerService extends IActivityManager.Stub
// Wait for the provider to be published...
final long timeout =
- SystemClock.uptimeMillis() + ContentResolver.CONTENT_PROVIDER_WAIT_TIMEOUT_MILLIS;
+ SystemClock.uptimeMillis() + ContentResolver.CONTENT_PROVIDER_READY_TIMEOUT_MILLIS;
boolean timedOut = false;
synchronized (cpr) {
while (cpr.provider == null) {
@@ -14610,6 +14610,11 @@ public class ActivityManagerService extends IActivityManager.Stub
if (index < 0) {
ProcessList.remove(app.pid);
}
+
+ // Remove provider publish timeout because we will start a new timeout when the
+ // restarted process is attaching (if the process contains launching providers).
+ mHandler.removeMessages(CONTENT_PROVIDER_PUBLISH_TIMEOUT_MSG, app);
+
mProcessList.addProcessNameLocked(app);
app.pendingStart = false;
mProcessList.startProcessLocked(app,
@@ -19338,7 +19343,8 @@ public class ActivityManagerService extends IActivityManager.Stub
@Override
public void showWhileInUseDebugToast(int uid, int op, int mode) {
synchronized (ActivityManagerService.this) {
- ActivityManagerService.this.mServices.showWhileInUseDebugToastLocked(uid, op, mode);
+ ActivityManagerService.this.mServices.showWhileInUseDebugNotificationLocked(
+ uid, op, mode);
}
}
}
diff --git a/services/core/java/com/android/server/am/CoreSettingsObserver.java b/services/core/java/com/android/server/am/CoreSettingsObserver.java
index a03f0bb4e399..48ceba976502 100644
--- a/services/core/java/com/android/server/am/CoreSettingsObserver.java
+++ b/services/core/java/com/android/server/am/CoreSettingsObserver.java
@@ -16,6 +16,7 @@
package com.android.server.am;
+import android.annotation.NonNull;
import android.app.ActivityThread;
import android.content.Context;
import android.database.ContentObserver;
@@ -32,6 +33,7 @@ import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
+import java.util.Objects;
/**
* Helper class for watching a set of core settings which the framework
@@ -42,16 +44,20 @@ import java.util.Map;
final class CoreSettingsObserver extends ContentObserver {
private static final String LOG_TAG = CoreSettingsObserver.class.getSimpleName();
- private static class DeviceConfigEntry {
+ private static class DeviceConfigEntry<T> {
String namespace;
String flag;
String coreSettingKey;
- Class<?> type;
- DeviceConfigEntry(String namespace, String flag, String coreSettingKey, Class<?> type) {
+ Class<T> type;
+ T defaultValue;
+
+ DeviceConfigEntry(String namespace, String flag, String coreSettingKey, Class<T> type,
+ @NonNull T defaultValue) {
this.namespace = namespace;
this.flag = flag;
this.coreSettingKey = coreSettingKey;
this.type = type;
+ this.defaultValue = Objects.requireNonNull(defaultValue);
}
}
@@ -105,24 +111,34 @@ final class CoreSettingsObserver extends ContentObserver {
sGlobalSettingToTypeMap.put(Settings.Global.GAME_DRIVER_SPHAL_LIBRARIES, String.class);
// add other global settings here...
- sDeviceConfigEntries.add(new DeviceConfigEntry(
- DeviceConfig.NAMESPACE_WIDGET, WidgetFlags.ENABLE_CURSOR_CONTROL,
- WidgetFlags.KEY_ENABLE_CURSOR_CONTROL, boolean.class));
- sDeviceConfigEntries.add(new DeviceConfigEntry(
+ sDeviceConfigEntries.add(new DeviceConfigEntry<Boolean>(
+ DeviceConfig.NAMESPACE_WIDGET, WidgetFlags.ENABLE_CURSOR_DRAG_FROM_ANYWHERE,
+ WidgetFlags.KEY_ENABLE_CURSOR_DRAG_FROM_ANYWHERE, boolean.class,
+ WidgetFlags.ENABLE_CURSOR_DRAG_FROM_ANYWHERE_DEFAULT));
+ sDeviceConfigEntries.add(new DeviceConfigEntry<Boolean>(
+ DeviceConfig.NAMESPACE_WIDGET, WidgetFlags.ENABLE_INSERTION_HANDLE_GESTURES,
+ WidgetFlags.KEY_ENABLE_INSERTION_HANDLE_GESTURES, boolean.class,
+ WidgetFlags.ENABLE_INSERTION_HANDLE_GESTURES_DEFAULT));
+ sDeviceConfigEntries.add(new DeviceConfigEntry<Integer>(
DeviceConfig.NAMESPACE_WIDGET, WidgetFlags.INSERTION_HANDLE_DELTA_HEIGHT,
- WidgetFlags.KEY_INSERTION_HANDLE_DELTA_HEIGHT, int.class));
- sDeviceConfigEntries.add(new DeviceConfigEntry(
+ WidgetFlags.KEY_INSERTION_HANDLE_DELTA_HEIGHT, int.class,
+ WidgetFlags.INSERTION_HANDLE_DELTA_HEIGHT_DEFAULT));
+ sDeviceConfigEntries.add(new DeviceConfigEntry<Integer>(
DeviceConfig.NAMESPACE_WIDGET, WidgetFlags.INSERTION_HANDLE_OPACITY,
- WidgetFlags.KEY_INSERTION_HANDLE_OPACITY, int.class));
- sDeviceConfigEntries.add(new DeviceConfigEntry(
+ WidgetFlags.KEY_INSERTION_HANDLE_OPACITY, int.class,
+ WidgetFlags.INSERTION_HANDLE_OPACITY_DEFAULT));
+ sDeviceConfigEntries.add(new DeviceConfigEntry<Boolean>(
DeviceConfig.NAMESPACE_WIDGET, WidgetFlags.ENABLE_NEW_MAGNIFIER,
- WidgetFlags.KEY_ENABLE_NEW_MAGNIFIER, boolean.class));
- sDeviceConfigEntries.add(new DeviceConfigEntry(
+ WidgetFlags.KEY_ENABLE_NEW_MAGNIFIER, boolean.class,
+ WidgetFlags.ENABLE_NEW_MAGNIFIER_DEFAULT));
+ sDeviceConfigEntries.add(new DeviceConfigEntry<Float>(
DeviceConfig.NAMESPACE_WIDGET, WidgetFlags.MAGNIFIER_ZOOM_FACTOR,
- WidgetFlags.KEY_MAGNIFIER_ZOOM_FACTOR, float.class));
- sDeviceConfigEntries.add(new DeviceConfigEntry(
+ WidgetFlags.KEY_MAGNIFIER_ZOOM_FACTOR, float.class,
+ WidgetFlags.MAGNIFIER_ZOOM_FACTOR_DEFAULT));
+ sDeviceConfigEntries.add(new DeviceConfigEntry<Float>(
DeviceConfig.NAMESPACE_WIDGET, WidgetFlags.MAGNIFIER_ASPECT_RATIO,
- WidgetFlags.KEY_MAGNIFIER_ASPECT_RATIO, float.class));
+ WidgetFlags.KEY_MAGNIFIER_ASPECT_RATIO, float.class,
+ WidgetFlags.MAGNIFIER_ASPECT_RATIO_DEFAULT));
// add other device configs here...
}
@@ -216,23 +232,29 @@ final class CoreSettingsObserver extends ContentObserver {
}
}
+ @SuppressWarnings("unchecked")
private void populateSettingsFromDeviceConfig() {
- for (DeviceConfigEntry entry : sDeviceConfigEntries) {
+ for (DeviceConfigEntry<?> entry : sDeviceConfigEntries) {
if (entry.type == String.class) {
+ String defaultValue = ((DeviceConfigEntry<String>) entry).defaultValue;
mCoreSettings.putString(entry.coreSettingKey,
- DeviceConfig.getString(entry.namespace, entry.flag, ""));
+ DeviceConfig.getString(entry.namespace, entry.flag, defaultValue));
} else if (entry.type == int.class) {
+ int defaultValue = ((DeviceConfigEntry<Integer>) entry).defaultValue;
mCoreSettings.putInt(entry.coreSettingKey,
- DeviceConfig.getInt(entry.namespace, entry.flag, 0));
+ DeviceConfig.getInt(entry.namespace, entry.flag, defaultValue));
} else if (entry.type == float.class) {
+ float defaultValue = ((DeviceConfigEntry<Float>) entry).defaultValue;
mCoreSettings.putFloat(entry.coreSettingKey,
- DeviceConfig.getFloat(entry.namespace, entry.flag, 0));
+ DeviceConfig.getFloat(entry.namespace, entry.flag, defaultValue));
} else if (entry.type == long.class) {
+ long defaultValue = ((DeviceConfigEntry<Long>) entry).defaultValue;
mCoreSettings.putLong(entry.coreSettingKey,
- DeviceConfig.getLong(entry.namespace, entry.flag, 0));
+ DeviceConfig.getLong(entry.namespace, entry.flag, defaultValue));
} else if (entry.type == boolean.class) {
+ boolean defaultValue = ((DeviceConfigEntry<Boolean>) entry).defaultValue;
mCoreSettings.putInt(entry.coreSettingKey,
- DeviceConfig.getBoolean(entry.namespace, entry.flag, false) ? 1 : 0);
+ DeviceConfig.getBoolean(entry.namespace, entry.flag, defaultValue) ? 1 : 0);
}
}
}
diff --git a/services/core/java/com/android/server/am/ProcessList.java b/services/core/java/com/android/server/am/ProcessList.java
index 0dc44f79d19f..22559c426348 100644
--- a/services/core/java/com/android/server/am/ProcessList.java
+++ b/services/core/java/com/android/server/am/ProcessList.java
@@ -345,6 +345,14 @@ public final class ProcessList {
@EnabledAfter(targetSdkVersion = VersionCodes.Q)
private static final long NATIVE_HEAP_POINTER_TAGGING = 135754954; // This is a bug id.
+ /**
+ * Apps have no access to the private data directories of any other app, even if the other
+ * app has made them world-readable.
+ */
+ @ChangeId
+ @EnabledAfter(targetSdkVersion = VersionCodes.Q)
+ private static final long APP_DATA_DIRECTORY_ISOLATION = 143937733; // See b/143937733
+
ActivityManagerService mService = null;
// To kill process groups asynchronously
@@ -2070,7 +2078,14 @@ public final class ProcessList {
}
final int minTargetSdk = DeviceConfig.getInt(DeviceConfig.NAMESPACE_ACTIVITY_MANAGER,
ANDROID_APP_DATA_ISOLATION_MIN_SDK, Build.VERSION_CODES.R);
- return app.info.targetSdkVersion >= minTargetSdk;
+ if (app.info.targetSdkVersion < minTargetSdk) {
+ return false;
+ }
+
+ // TODO(b/147266020): Remove non-standard gating above & switch to isChangeEnabled.
+ mPlatformCompat.reportChange(APP_DATA_DIRECTORY_ISOLATION, app.info);
+
+ return true;
}
private Map<String, Pair<String, Long>> getPackageAppDataInfoMap(PackageManagerInternal pmInt,
diff --git a/services/core/java/com/android/server/display/DisplayModeDirector.java b/services/core/java/com/android/server/display/DisplayModeDirector.java
index 8bbeabf779d2..7cb84585a57c 100644
--- a/services/core/java/com/android/server/display/DisplayModeDirector.java
+++ b/services/core/java/com/android/server/display/DisplayModeDirector.java
@@ -73,7 +73,7 @@ public class DisplayModeDirector {
private static final int GLOBAL_ID = -1;
// The tolerance within which we consider something approximately equals.
- private static final float EPSILON = 0.01f;
+ private static final float FLOAT_TOLERANCE = 0.01f;
private final Object mLock = new Object();
private final Context mContext;
@@ -267,8 +267,8 @@ public class DisplayModeDirector {
// Some refresh rates are calculated based on frame timings, so they aren't *exactly*
// equal to expected refresh rate. Given that, we apply a bit of tolerance to this
// comparison.
- if (refreshRate < (minRefreshRate - EPSILON)
- || refreshRate > (maxRefreshRate + EPSILON)) {
+ if (refreshRate < (minRefreshRate - FLOAT_TOLERANCE)
+ || refreshRate > (maxRefreshRate + FLOAT_TOLERANCE)) {
if (DEBUG) {
Slog.w(TAG, "Discarding mode " + mode.getModeId()
+ ", outside refresh rate bounds"
@@ -487,12 +487,18 @@ public class DisplayModeDirector {
public RefreshRateRange() {}
public RefreshRateRange(float min, float max) {
- if (min < 0 || max < 0 || min > max) {
+ if (min < 0 || max < 0 || min > max + FLOAT_TOLERANCE) {
Slog.e(TAG, "Wrong values for min and max when initializing RefreshRateRange : "
+ min + " " + max);
this.min = this.max = 0;
return;
}
+ if (min > max) {
+ // Min and max are within epsilon of each other, but in the wrong order.
+ float t = min;
+ min = max;
+ max = t;
+ }
this.min = min;
this.max = max;
}
diff --git a/services/core/java/com/android/server/inputmethod/InputMethodManagerService.java b/services/core/java/com/android/server/inputmethod/InputMethodManagerService.java
index d7cb192fdd36..87262a844b18 100644
--- a/services/core/java/com/android/server/inputmethod/InputMethodManagerService.java
+++ b/services/core/java/com/android/server/inputmethod/InputMethodManagerService.java
@@ -1388,6 +1388,44 @@ public class InputMethodManagerService extends IInputMethodManager.Stub
}
}
+ private static final class UserSwitchHandlerTask implements Runnable {
+ final InputMethodManagerService mService;
+
+ @UserIdInt
+ final int mToUserId;
+
+ @Nullable
+ IInputMethodClient mClientToBeReset;
+
+ UserSwitchHandlerTask(InputMethodManagerService service, @UserIdInt int toUserId,
+ @Nullable IInputMethodClient clientToBeReset) {
+ mService = service;
+ mToUserId = toUserId;
+ mClientToBeReset = clientToBeReset;
+ }
+
+ @Override
+ public void run() {
+ synchronized (mService.mMethodMap) {
+ if (mService.mUserSwitchHandlerTask != this) {
+ // This task was already canceled before it is handled here. So do nothing.
+ return;
+ }
+ mService.switchUserOnHandlerLocked(mService.mUserSwitchHandlerTask.mToUserId,
+ mClientToBeReset);
+ mService.mUserSwitchHandlerTask = null;
+ }
+ }
+ }
+
+ /**
+ * When non-{@code null}, this represents pending user-switch task, which is to be executed as
+ * a handler callback. This needs to be set and unset only within the lock.
+ */
+ @Nullable
+ @GuardedBy("mMethodMap")
+ private UserSwitchHandlerTask mUserSwitchHandlerTask;
+
public static final class Lifecycle extends SystemService {
private InputMethodManagerService mService;
@@ -1406,8 +1444,9 @@ public class InputMethodManagerService extends IInputMethodManager.Stub
@Override
public void onSwitchUser(@UserIdInt int userHandle) {
// Called on ActivityManager thread.
- // TODO: Dispatch this to a worker thread as needed.
- mService.onSwitchUser(userHandle);
+ synchronized (mService.mMethodMap) {
+ mService.scheduleSwitchUserTaskLocked(userHandle, null /* clientToBeReset */);
+ }
}
@Override
@@ -1447,10 +1486,20 @@ public class InputMethodManagerService extends IInputMethodManager.Stub
}
}
- void onSwitchUser(@UserIdInt int userId) {
- synchronized (mMethodMap) {
- switchUserLocked(userId);
+ @GuardedBy("mMethodMap")
+ void scheduleSwitchUserTaskLocked(@UserIdInt int userId,
+ @Nullable IInputMethodClient clientToBeReset) {
+ if (mUserSwitchHandlerTask != null) {
+ if (mUserSwitchHandlerTask.mToUserId == userId) {
+ mUserSwitchHandlerTask.mClientToBeReset = clientToBeReset;
+ return;
+ }
+ mHandler.removeCallbacks(mUserSwitchHandlerTask);
}
+ final UserSwitchHandlerTask task = new UserSwitchHandlerTask(this, userId,
+ clientToBeReset);
+ mUserSwitchHandlerTask = task;
+ mHandler.post(task);
}
public InputMethodManagerService(Context context) {
@@ -1538,7 +1587,8 @@ public class InputMethodManagerService extends IInputMethodManager.Stub
}
@GuardedBy("mMethodMap")
- private void switchUserLocked(int newUserId) {
+ private void switchUserOnHandlerLocked(@UserIdInt int newUserId,
+ IInputMethodClient clientToBeReset) {
if (DEBUG) Slog.d(TAG, "Switching user stage 1/3. newUserId=" + newUserId
+ " currentUserId=" + mSettings.getCurrentUserId());
@@ -1589,6 +1639,18 @@ public class InputMethodManagerService extends IInputMethodManager.Stub
+ " selectedIme=" + mSettings.getSelectedInputMethod());
mLastSwitchUserId = newUserId;
+
+ if (mIsInteractive && clientToBeReset != null) {
+ final ClientState cs = mClients.get(clientToBeReset.asBinder());
+ if (cs == null) {
+ // The client is already gone.
+ return;
+ }
+ try {
+ cs.client.scheduleStartInputIfNecessary(mInFullscreenMode);
+ } catch (RemoteException e) {
+ }
+ }
}
void updateCurrentProfileIds() {
@@ -3072,6 +3134,22 @@ public class InputMethodManagerService extends IInputMethodManager.Stub
return InputBindResult.NOT_IME_TARGET_WINDOW;
}
+ if (mUserSwitchHandlerTask != null) {
+ // There is already an on-going pending user switch task.
+ final int nextUserId = mUserSwitchHandlerTask.mToUserId;
+ if (userId == nextUserId) {
+ scheduleSwitchUserTaskLocked(userId, cs.client);
+ return InputBindResult.USER_SWITCHING;
+ }
+ for (int profileId : mUserManager.getProfileIdsWithDisabled(nextUserId)) {
+ if (profileId == userId) {
+ scheduleSwitchUserTaskLocked(userId, cs.client);
+ return InputBindResult.USER_SWITCHING;
+ }
+ }
+ return InputBindResult.INVALID_USER;
+ }
+
// cross-profile access is always allowed here to allow profile-switching.
if (!mSettings.isCurrentProfile(userId)) {
Slog.w(TAG, "A background user is requesting window. Hiding IME.");
@@ -3083,8 +3161,10 @@ public class InputMethodManagerService extends IInputMethodManager.Stub
}
if (userId != mSettings.getCurrentUserId()) {
- switchUserLocked(userId);
+ scheduleSwitchUserTaskLocked(userId, cs.client);
+ return InputBindResult.USER_SWITCHING;
}
+
// Master feature flag that overrides other conditions and forces IME preRendering.
if (DEBUG) {
Slog.v(TAG, "IME PreRendering MASTER flag: "
diff --git a/services/core/java/com/android/server/location/AbstractLocationProvider.java b/services/core/java/com/android/server/location/AbstractLocationProvider.java
index 433ec435c8d1..e9d94a5430fe 100644
--- a/services/core/java/com/android/server/location/AbstractLocationProvider.java
+++ b/services/core/java/com/android/server/location/AbstractLocationProvider.java
@@ -366,21 +366,6 @@ public abstract class AbstractLocationProvider {
protected abstract void onExtraCommand(int uid, int pid, String command, Bundle extras);
/**
- * Requests a provider to enable itself for the given user id.
- */
- public final void requestSetAllowed(boolean allowed) {
- // all calls into the provider must be moved onto the provider thread to prevent deadlock
- mExecutor.execute(
- obtainRunnable(AbstractLocationProvider::onRequestSetAllowed, this, allowed)
- .recycleOnUse());
- }
-
- /**
- * Always invoked on the provider executor.
- */
- protected abstract void onRequestSetAllowed(boolean allowed);
-
- /**
* Dumps debug or log information. May be invoked from any thread.
*/
public abstract void dump(FileDescriptor fd, PrintWriter pw, String[] args);
diff --git a/services/core/java/com/android/server/location/GnssLocationProvider.java b/services/core/java/com/android/server/location/GnssLocationProvider.java
index 5f44e042b5e9..685fb9eb38f5 100644
--- a/services/core/java/com/android/server/location/GnssLocationProvider.java
+++ b/services/core/java/com/android/server/location/GnssLocationProvider.java
@@ -1229,11 +1229,6 @@ public class GnssLocationProvider extends AbstractLocationProvider implements
}
}
- @Override
- protected void onRequestSetAllowed(boolean allowed) {
- // do nothing - the gnss provider is always allowed
- }
-
private void deleteAidingData(Bundle extras) {
int flags;
diff --git a/services/core/java/com/android/server/location/LocationProviderProxy.java b/services/core/java/com/android/server/location/LocationProviderProxy.java
index 96ffaa6c0bff..87208a7f36f5 100644
--- a/services/core/java/com/android/server/location/LocationProviderProxy.java
+++ b/services/core/java/com/android/server/location/LocationProviderProxy.java
@@ -205,14 +205,6 @@ public class LocationProviderProxy extends AbstractLocationProvider {
}
@Override
- public void onRequestSetAllowed(boolean allowed) {
- mServiceWatcher.runOnBinder(binder -> {
- ILocationProvider service = ILocationProvider.Stub.asInterface(binder);
- service.requestSetAllowed(allowed);
- });
- }
-
- @Override
public void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
mServiceWatcher.dump(fd, pw, args);
}
diff --git a/services/core/java/com/android/server/location/MockProvider.java b/services/core/java/com/android/server/location/MockProvider.java
index b45b66017062..5ec06ca25581 100644
--- a/services/core/java/com/android/server/location/MockProvider.java
+++ b/services/core/java/com/android/server/location/MockProvider.java
@@ -64,11 +64,6 @@ public class MockProvider extends AbstractLocationProvider {
protected void onExtraCommand(int uid, int pid, String command, Bundle extras) {}
@Override
- protected void onRequestSetAllowed(boolean allowed) {
- setAllowed(allowed);
- }
-
- @Override
public void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
pw.println("last mock location=" + mLocation);
}
diff --git a/services/core/java/com/android/server/location/MockableLocationProvider.java b/services/core/java/com/android/server/location/MockableLocationProvider.java
index f43669e488d1..0f358e97bc98 100644
--- a/services/core/java/com/android/server/location/MockableLocationProvider.java
+++ b/services/core/java/com/android/server/location/MockableLocationProvider.java
@@ -224,15 +224,6 @@ public class MockableLocationProvider extends AbstractLocationProvider {
}
}
- @Override
- protected void onRequestSetAllowed(boolean allowed) {
- synchronized (mOwnerLock) {
- if (mProvider != null) {
- mProvider.onRequestSetAllowed(allowed);
- }
- }
- }
-
/**
* Dumps the current provider implementation.
*/
diff --git a/services/core/java/com/android/server/location/PassiveProvider.java b/services/core/java/com/android/server/location/PassiveProvider.java
index 54dffff8b1df..1ba38cc4d999 100644
--- a/services/core/java/com/android/server/location/PassiveProvider.java
+++ b/services/core/java/com/android/server/location/PassiveProvider.java
@@ -79,10 +79,5 @@ public class PassiveProvider extends AbstractLocationProvider {
protected void onExtraCommand(int uid, int pid, String command, Bundle extras) {}
@Override
- protected void onRequestSetAllowed(boolean allowed) {
- // do nothing - the passive provider is always allowed
- }
-
- @Override
public void dump(FileDescriptor fd, PrintWriter pw, String[] args) {}
}
diff --git a/services/core/java/com/android/server/pm/PackageManagerService.java b/services/core/java/com/android/server/pm/PackageManagerService.java
index a464ca717690..92507e5a0e25 100644
--- a/services/core/java/com/android/server/pm/PackageManagerService.java
+++ b/services/core/java/com/android/server/pm/PackageManagerService.java
@@ -104,6 +104,9 @@ import static com.android.internal.app.IntentForwarderActivity.FORWARD_INTENT_TO
import static com.android.internal.content.NativeLibraryHelper.LIB_DIR_NAME;
import static com.android.internal.util.ArrayUtils.emptyIfNull;
import static com.android.internal.util.ArrayUtils.filter;
+import static com.android.internal.util.FrameworkStatsLog.BOOT_TIME_EVENT_DURATION__EVENT__OTA_PACKAGE_MANAGER_DATA_APP_AVG_SCAN_TIME;
+import static com.android.internal.util.FrameworkStatsLog.BOOT_TIME_EVENT_DURATION__EVENT__OTA_PACKAGE_MANAGER_INIT_TIME;
+import static com.android.internal.util.FrameworkStatsLog.BOOT_TIME_EVENT_DURATION__EVENT__OTA_PACKAGE_MANAGER_SYSTEM_APP_AVG_SCAN_TIME;
import static com.android.server.pm.ComponentResolver.RESOLVE_PRIORITY_SORTER;
import static com.android.server.pm.InstructionSets.getAppDexInstructionSets;
import static com.android.server.pm.InstructionSets.getDexCodeInstructionSet;
@@ -3000,8 +3003,11 @@ public class PackageManagerService extends IPackageManager.Stub
+ (systemPackagesCount == 0 ? 0 : systemScanTime / systemPackagesCount)
+ " , cached: " + cachedSystemApps);
if (mIsUpgrade && systemPackagesCount > 0) {
- MetricsLogger.histogram(null, "ota_package_manager_system_app_avg_scan_time",
- ((int) systemScanTime) / systemPackagesCount);
+ //CHECKSTYLE:OFF IndentationCheck
+ FrameworkStatsLog.write(FrameworkStatsLog.BOOT_TIME_EVENT_DURATION_REPORTED,
+ BOOT_TIME_EVENT_DURATION__EVENT__OTA_PACKAGE_MANAGER_SYSTEM_APP_AVG_SCAN_TIME,
+ systemScanTime / systemPackagesCount);
+ //CHECKSTYLE:ON IndentationCheck
}
if (!mOnlyCore) {
EventLog.writeEvent(EventLogTags.BOOT_PROGRESS_PMS_DATA_SCAN_START,
@@ -3128,8 +3134,12 @@ public class PackageManagerService extends IPackageManager.Stub
+ (dataPackagesCount == 0 ? 0 : dataScanTime / dataPackagesCount)
+ " , cached: " + cachedNonSystemApps);
if (mIsUpgrade && dataPackagesCount > 0) {
- MetricsLogger.histogram(null, "ota_package_manager_data_app_avg_scan_time",
- ((int) dataScanTime) / dataPackagesCount);
+ //CHECKSTYLE:OFF IndentationCheck
+ FrameworkStatsLog.write(
+ FrameworkStatsLog.BOOT_TIME_EVENT_DURATION_REPORTED,
+ BOOT_TIME_EVENT_DURATION__EVENT__OTA_PACKAGE_MANAGER_DATA_APP_AVG_SCAN_TIME,
+ dataScanTime / dataPackagesCount);
+ //CHECKSTYLE:OFF IndentationCheck
}
}
mExpectingBetter.clear();
@@ -3390,8 +3400,10 @@ public class PackageManagerService extends IPackageManager.Stub
}
mDexManager.load(userPackages);
if (mIsUpgrade) {
- MetricsLogger.histogram(null, "ota_package_manager_init_time",
- (int) (SystemClock.uptimeMillis() - startTime));
+ FrameworkStatsLog.write(
+ FrameworkStatsLog.BOOT_TIME_EVENT_DURATION_REPORTED,
+ BOOT_TIME_EVENT_DURATION__EVENT__OTA_PACKAGE_MANAGER_INIT_TIME,
+ SystemClock.uptimeMillis() - startTime);
}
} // synchronized (mLock)
} // synchronized (mInstallLock)
diff --git a/services/core/java/com/android/server/pm/Settings.java b/services/core/java/com/android/server/pm/Settings.java
index 6c2ace8b4163..42b2eebd63a7 100644
--- a/services/core/java/com/android/server/pm/Settings.java
+++ b/services/core/java/com/android/server/pm/Settings.java
@@ -5407,7 +5407,7 @@ public final class Settings {
packagePermissions, sharedUserPermissions);
}
- mPersistence.write(runtimePermissions, UserHandle.of(userId));
+ mPersistence.writeAsUser(runtimePermissions, UserHandle.of(userId));
}
@NonNull
@@ -5461,12 +5461,13 @@ public final class Settings {
}
public void deleteUserRuntimePermissionsFile(int userId) {
- mPersistence.delete(UserHandle.of(userId));
+ mPersistence.deleteAsUser(UserHandle.of(userId));
}
@GuardedBy("Settings.this.mLock")
public void readStateForUserSyncLPr(int userId) {
- RuntimePermissionsState runtimePermissions = mPersistence.read(UserHandle.of(userId));
+ RuntimePermissionsState runtimePermissions = mPersistence.readAsUser(UserHandle.of(
+ userId));
if (runtimePermissions == null) {
readLegacyStateForUserSyncLPr(userId);
writePermissionsForUserAsyncLPr(userId);
diff --git a/services/core/java/com/android/server/pm/ShortcutPackage.java b/services/core/java/com/android/server/pm/ShortcutPackage.java
index c37ceb3bc1b0..2de9858d91f9 100644
--- a/services/core/java/com/android/server/pm/ShortcutPackage.java
+++ b/services/core/java/com/android/server/pm/ShortcutPackage.java
@@ -310,6 +310,60 @@ class ShortcutPackage extends ShortcutPackageItem {
}
/**
+ * Push a shortcut. If the max number of dynamic shortcuts is already reached, remove the
+ * shortcut with the lowest rank before adding the new shortcut.
+ */
+ public boolean pushDynamicShortcut(@NonNull ShortcutInfo newShortcut) {
+ Preconditions.checkArgument(newShortcut.isEnabled(),
+ "pushDynamicShortcuts() cannot publish disabled shortcuts");
+
+ newShortcut.addFlags(ShortcutInfo.FLAG_DYNAMIC);
+
+ final ShortcutInfo oldShortcut = mShortcuts.get(newShortcut.getId());
+ boolean wasPinned = false;
+
+ if (oldShortcut == null) {
+ final ShortcutService service = mShortcutUser.mService;
+ final int maxShortcuts = service.getMaxActivityShortcuts();
+
+ final ArrayMap<ComponentName, ArrayList<ShortcutInfo>> all =
+ sortShortcutsToActivities();
+ final ArrayList<ShortcutInfo> activityShortcuts = all.get(newShortcut.getActivity());
+
+ if (activityShortcuts != null && activityShortcuts.size() == maxShortcuts) {
+ // Max has reached. Delete the shortcut with lowest rank.
+
+ // Sort by isManifestShortcut() and getRank().
+ Collections.sort(activityShortcuts, mShortcutTypeAndRankComparator);
+
+ final ShortcutInfo shortcut = activityShortcuts.get(maxShortcuts - 1);
+ if (shortcut.isManifestShortcut()) {
+ // All shortcuts are manifest shortcuts and cannot be removed.
+ Slog.e(TAG, "Failed to remove manifest shortcut while pushing dynamic shortcut "
+ + newShortcut.getId());
+ return false;
+ }
+
+ deleteDynamicWithId(shortcut.getId(), /*ignoreInvisible=*/ true);
+ }
+ } else {
+ // It's an update case.
+ // Make sure the target is updatable. (i.e. should be mutable.)
+ oldShortcut.ensureUpdatableWith(newShortcut, /*isUpdating=*/ false);
+
+ wasPinned = oldShortcut.isPinned();
+ }
+
+ // If it was originally pinned, the new one should be pinned too.
+ if (wasPinned) {
+ newShortcut.addFlags(ShortcutInfo.FLAG_PINNED);
+ }
+
+ forceReplaceShortcutInner(newShortcut);
+ return true;
+ }
+
+ /**
* Remove all shortcuts that aren't pinned, cached nor dynamic.
*/
private void removeOrphans() {
diff --git a/services/core/java/com/android/server/pm/ShortcutService.java b/services/core/java/com/android/server/pm/ShortcutService.java
index 12f7d5c27459..54f9f761241f 100644
--- a/services/core/java/com/android/server/pm/ShortcutService.java
+++ b/services/core/java/com/android/server/pm/ShortcutService.java
@@ -133,6 +133,7 @@ import java.lang.annotation.RetentionPolicy;
import java.net.URISyntaxException;
import java.nio.charset.StandardCharsets;
import java.util.ArrayList;
+import java.util.Arrays;
import java.util.Collections;
import java.util.List;
import java.util.Objects;
@@ -1946,6 +1947,50 @@ public class ShortcutService extends IShortcutService.Stub {
}
@Override
+ public void pushDynamicShortcut(String packageName, ShortcutInfo shortcut,
+ @UserIdInt int userId) {
+ verifyCaller(packageName, userId);
+ verifyShortcutInfoPackage(packageName, shortcut);
+
+ final boolean unlimited = injectHasUnlimitedShortcutsApiCallsPermission(
+ injectBinderCallingPid(), injectBinderCallingUid());
+
+ synchronized (mLock) {
+ throwIfUserLockedL(userId);
+
+ final ShortcutPackage ps = getPackageShortcutsForPublisherLocked(packageName, userId);
+
+ ps.ensureNotImmutable(shortcut.getId(), /*ignoreInvisible=*/ true);
+ fillInDefaultActivity(Arrays.asList(shortcut));
+
+ if (!shortcut.hasRank()) {
+ shortcut.setRank(0);
+ }
+ // Initialize the implicit ranks for ShortcutPackage.adjustRanks().
+ ps.clearAllImplicitRanks();
+ shortcut.setImplicitRank(0);
+
+ // Validate the shortcut.
+ fixUpIncomingShortcutInfo(shortcut, /* forUpdate= */ false);
+
+ // When ranks are changing, we need to insert between ranks, so set the
+ // "rank changed" flag.
+ shortcut.setRankChanged();
+
+ // Push it.
+ if (!ps.pushDynamicShortcut(shortcut)) {
+ return;
+ }
+
+ // Lastly, adjust the ranks.
+ ps.adjustRanks();
+ }
+ packageShortcutsChanged(packageName, userId);
+
+ verifyStates();
+ }
+
+ @Override
public boolean requestPinShortcut(String packageName, ShortcutInfo shortcut,
IntentSender resultIntent, int userId) {
Objects.requireNonNull(shortcut);
diff --git a/services/core/java/com/android/server/role/RoleUserState.java b/services/core/java/com/android/server/role/RoleUserState.java
index 9f4ca3c6c4ea..97ce6bd7f369 100644
--- a/services/core/java/com/android/server/role/RoleUserState.java
+++ b/services/core/java/com/android/server/role/RoleUserState.java
@@ -364,12 +364,12 @@ public class RoleUserState {
(Map<String, Set<String>>) (Map<String, ?>) snapshotRolesLocked());
}
- mPersistence.write(roles, UserHandle.of(mUserId));
+ mPersistence.writeAsUser(roles, UserHandle.of(mUserId));
}
private void readFile() {
synchronized (mLock) {
- RolesState roles = mPersistence.read(UserHandle.of(mUserId));
+ RolesState roles = mPersistence.readAsUser(UserHandle.of(mUserId));
if (roles == null) {
readLegacyFileLocked();
scheduleWriteFileLocked();
@@ -545,7 +545,7 @@ public class RoleUserState {
throw new IllegalStateException("This RoleUserState has already been destroyed");
}
mWriteHandler.removeCallbacksAndMessages(null);
- mPersistence.delete(UserHandle.of(mUserId));
+ mPersistence.deleteAsUser(UserHandle.of(mUserId));
mDestroyed = true;
}
}
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 47a26f576949..e7345280603c 100644
--- a/services/core/java/com/android/server/stats/pull/StatsPullAtomService.java
+++ b/services/core/java/com/android/server/stats/pull/StatsPullAtomService.java
@@ -41,6 +41,7 @@ import android.app.AppOpsManager.HistoricalPackageOps;
import android.app.AppOpsManager.HistoricalUidOps;
import android.app.INotificationManager;
import android.app.ProcessMemoryState;
+import android.app.RuntimeAppOpAccessMessage;
import android.app.StatsManager;
import android.app.StatsManager.PullAtomMetadata;
import android.bluetooth.BluetoothActivityEnergyInfo;
@@ -377,6 +378,8 @@ public class StatsPullAtomService extends SystemService {
return pullFaceSettings(atomTag, data);
case FrameworkStatsLog.APP_OPS:
return pullAppOps(atomTag, data);
+ case FrameworkStatsLog.RUNTIME_APP_OP_ACCESS:
+ return pullRuntimeAppOpAccessMessage(atomTag, data);
case FrameworkStatsLog.NOTIFICATION_REMOTE_VIEWS:
return pullNotificationRemoteViews(atomTag, data);
case FrameworkStatsLog.DANGEROUS_PERMISSION_STATE_SAMPLED:
@@ -539,6 +542,7 @@ public class StatsPullAtomService extends SystemService {
registerAppsOnExternalStorageInfo();
registerFaceSettings();
registerAppOps();
+ registerRuntimeAppOpAccessMessage();
registerNotificationRemoteViews();
registerDangerousPermissionState();
registerDangerousPermissionStateSampled();
@@ -2834,6 +2838,17 @@ public class StatsPullAtomService extends SystemService {
}
+ private void registerRuntimeAppOpAccessMessage() {
+ int tagId = FrameworkStatsLog.RUNTIME_APP_OP_ACCESS;
+ mStatsManager.registerPullAtomCallback(
+ tagId,
+ null, // use default PullAtomMetadata values
+ BackgroundThread.getExecutor(),
+ mStatsCallbackImpl
+ );
+
+ }
+
int pullAppOps(int atomTag, List<StatsEvent> pulledData) {
final long token = Binder.clearCallingIdentity();
try {
@@ -2894,6 +2909,41 @@ public class StatsPullAtomService extends SystemService {
return StatsManager.PULL_SUCCESS;
}
+ int pullRuntimeAppOpAccessMessage(int atomTag, List<StatsEvent> pulledData) {
+ final long token = Binder.clearCallingIdentity();
+ try {
+ AppOpsManager appOps = mContext.getSystemService(AppOpsManager.class);
+
+ RuntimeAppOpAccessMessage message = appOps.collectRuntimeAppOpAccessMessage();
+ if (message == null) {
+ Slog.i(TAG, "No runtime appop access message collected");
+ return StatsManager.PULL_SUCCESS;
+ }
+
+ StatsEvent.Builder e = StatsEvent.newBuilder();
+ e.setAtomId(atomTag);
+ e.writeInt(message.getUid());
+ e.writeString(message.getPackageName());
+ e.writeString(message.getOp());
+ if (message.getFeatureId() == null) {
+ e.writeString("");
+ } else {
+ e.writeString(message.getFeatureId());
+ }
+ e.writeString(message.getMessage());
+ e.writeInt(message.getSamplingStrategy());
+
+ pulledData.add(e.build());
+ } catch (Throwable t) {
+ // TODO: catch exceptions at a more granular level
+ Slog.e(TAG, "Could not read runtime appop access message", t);
+ return StatsManager.PULL_SKIP;
+ } finally {
+ Binder.restoreCallingIdentity(token);
+ }
+ return StatsManager.PULL_SUCCESS;
+ }
+
static void unpackStreamedData(int atomTag, List<StatsEvent> pulledData,
List<ParcelFileDescriptor> statsFiles) throws IOException {
InputStream stream = new ParcelFileDescriptor.AutoCloseInputStream(statsFiles.get(0));
diff --git a/services/core/java/com/android/server/wm/ActivityRecord.java b/services/core/java/com/android/server/wm/ActivityRecord.java
index 4cc4851164ee..04fae976e2f4 100644
--- a/services/core/java/com/android/server/wm/ActivityRecord.java
+++ b/services/core/java/com/android/server/wm/ActivityRecord.java
@@ -1163,8 +1163,12 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A
// An activity is considered to be in multi-window mode if its task isn't fullscreen.
final boolean inMultiWindowMode = inMultiWindowMode();
if (inMultiWindowMode != mLastReportedMultiWindowMode) {
- mLastReportedMultiWindowMode = inMultiWindowMode;
- scheduleMultiWindowModeChanged(getConfiguration());
+ if (!inMultiWindowMode && mLastReportedPictureInPictureMode) {
+ updatePictureInPictureMode(null, false);
+ } else {
+ mLastReportedMultiWindowMode = inMultiWindowMode;
+ scheduleMultiWindowModeChanged(getConfiguration());
+ }
}
}
diff --git a/services/core/java/com/android/server/wm/ActivityStack.java b/services/core/java/com/android/server/wm/ActivityStack.java
index 688f47475d8b..2f1cc0532ccc 100644
--- a/services/core/java/com/android/server/wm/ActivityStack.java
+++ b/services/core/java/com/android/server/wm/ActivityStack.java
@@ -658,8 +658,8 @@ class ActivityStack extends Task implements BoundsAnimationTarget {
}
@Override
- public void resolveOverrideConfiguration(Configuration newParentConfig) {
- super.resolveOverrideConfiguration(newParentConfig);
+ public void resolveTileOverrideConfiguration(Configuration newParentConfig) {
+ super.resolveTileOverrideConfiguration(newParentConfig);
if (mTile != null) {
// If this is a virtual child of a tile, simulate the parent-child relationship
mTile.updateResolvedConfig(getResolvedOverrideConfiguration());
@@ -742,8 +742,8 @@ class ActivityStack extends Task implements BoundsAnimationTarget {
setBounds(newBounds);
} else if (overrideWindowingMode != WINDOWING_MODE_PINNED) {
// For pinned stack, resize is now part of the {@link WindowContainerTransaction}
- resize(new Rect(newBounds), null /* tempTaskBounds */,
- null /* tempTaskInsetBounds */, PRESERVE_WINDOWS, true /* deferResume */);
+ resize(new Rect(newBounds), null /* configBounds */,
+ PRESERVE_WINDOWS, true /* deferResume */);
}
}
if (prevIsAlwaysOnTop != isAlwaysOnTop()) {
@@ -952,8 +952,8 @@ class ActivityStack extends Task implements BoundsAnimationTarget {
}
if (!Objects.equals(getRequestedOverrideBounds(), mTmpRect2)) {
- resize(mTmpRect2, null /* tempTaskBounds */, null /* tempTaskInsetBounds */,
- false /* preserveWindows */, true /* deferResume */);
+ resize(mTmpRect2, null /*configBounds*/,
+ false /*preserveWindows*/, true /*deferResume*/);
}
} finally {
if (showRecents && !alreadyInSplitScreenMode && isOnHomeDisplay()
@@ -1118,20 +1118,15 @@ class ActivityStack extends Task implements BoundsAnimationTarget {
return r.getTask().mTaskId != taskId && r.appToken != notTop && r.canBeTopRunning();
}
- ActivityRecord isInStackLocked(IBinder token) {
- final ActivityRecord r = ActivityRecord.forTokenLocked(token);
- return isInStackLocked(r);
- }
-
ActivityRecord isInStackLocked(ActivityRecord r) {
if (r == null) {
return null;
}
- final Task task = r.getTask();
- final ActivityStack stack = r.getRootTask();
- if (stack != null && task.mChildren.contains(r) && mChildren.contains(task)) {
- if (stack != this) Slog.w(TAG,
- "Illegal state! task does not point to stack it is in.");
+ final Task task = r.getRootTask();
+ if (task != null && r.isDescendantOf(task)) {
+ if (task != this) Slog.w(TAG, "Illegal state! task does not point to stack it is in. "
+ + "stack=" + this + " task=" + task + " r=" + r
+ + " callers=" + Debug.getCallers(15, "\n"));
return r;
}
return null;
@@ -1207,7 +1202,7 @@ class ActivityStack extends Task implements BoundsAnimationTarget {
}
getDisplay().positionStackAtBottom(this, reason);
- if (task != null) {
+ if (task != null && task != this) {
positionChildAtBottom(task);
}
@@ -1251,12 +1246,12 @@ class ActivityStack extends Task implements BoundsAnimationTarget {
mCurrentUser = userId;
super.switchUser(userId);
- forAllTasks((t) -> {
- if (t.showToCurrentUser()) {
+ forAllLeafTasks((t) -> {
+ if (t.showToCurrentUser() && t != this) {
mChildren.remove(t);
mChildren.add(t);
}
- }, true /* traverseTopToBottom */, this);
+ }, true /* traverseTopToBottom */);
}
void minimalResumeActivityLocked(ActivityRecord r) {
@@ -2450,16 +2445,16 @@ class ActivityStack extends Task implements BoundsAnimationTarget {
boolean newTask, boolean keepCurTransition, ActivityOptions options) {
Task rTask = r.getTask();
final boolean allowMoveToFront = options == null || !options.getAvoidMoveToFront();
- final boolean hasTask = hasChild(rTask);
+ final boolean isOrhasTask = rTask == this || hasChild(rTask);
// mLaunchTaskBehind tasks get placed at the back of the task stack.
- if (!r.mLaunchTaskBehind && allowMoveToFront && (!hasTask || newTask)) {
+ if (!r.mLaunchTaskBehind && allowMoveToFront && (!isOrhasTask || newTask)) {
// Last activity in task had been removed or ActivityManagerService is reusing task.
// Insert or replace.
// Might not even be in.
positionChildAtTop(rTask);
}
Task task = null;
- if (!newTask && hasTask) {
+ if (!newTask && isOrhasTask) {
final ActivityRecord occludingActivity = getActivity(
(ar) -> !ar.finishing && ar.occludesParent(), true, rTask);
if (occludingActivity != null) {
@@ -2717,7 +2712,7 @@ class ActivityStack extends Task implements BoundsAnimationTarget {
void finishVoiceTask(IVoiceInteractionSession session) {
final PooledConsumer c = PooledLambda.obtainConsumer(ActivityStack::finishIfVoiceTask,
PooledLambda.__(Task.class), session.asBinder());
- forAllTasks(c, true /* traverseTopToBottom */, this);
+ forAllLeafTasks(c, true /* traverseTopToBottom */);
c.recycle();
}
@@ -2818,8 +2813,7 @@ class ActivityStack extends Task implements BoundsAnimationTarget {
return false;
}
final Task task = srec.getTask();
-
- if (!mChildren.contains(task) || !task.hasChild(srec)) {
+ if (!srec.isDescendantOf(this)) {
return false;
}
@@ -2932,20 +2926,20 @@ class ActivityStack extends Task implements BoundsAnimationTarget {
getDisplay().mDisplayContent.prepareAppTransition(transit, false);
}
- final void moveTaskToFrontLocked(Task tr, boolean noAnimation, ActivityOptions options,
+ final void moveTaskToFront(Task tr, boolean noAnimation, ActivityOptions options,
AppTimeTracker timeTracker, String reason) {
- moveTaskToFrontLocked(tr, noAnimation, options, timeTracker, !DEFER_RESUME, reason);
+ moveTaskToFront(tr, noAnimation, options, timeTracker, !DEFER_RESUME, reason);
}
- final void moveTaskToFrontLocked(Task tr, boolean noAnimation, ActivityOptions options,
+ final void moveTaskToFront(Task tr, boolean noAnimation, ActivityOptions options,
AppTimeTracker timeTracker, boolean deferResume, String reason) {
if (DEBUG_SWITCH) Slog.v(TAG_SWITCH, "moveTaskToFront: " + tr);
final ActivityStack topStack = getDisplay().getTopStack();
- final ActivityRecord topActivity = topStack != null ? topStack.getTopNonFinishingActivity() : null;
- final int numTasks = getChildCount();
- final int index = mChildren.indexOf(tr);
- if (numTasks == 0 || index < 0) {
+ final ActivityRecord topActivity = topStack != null
+ ? topStack.getTopNonFinishingActivity() : null;
+
+ if (tr != this && !tr.isDescendantOf(this)) {
// nothing to do!
if (noAnimation) {
ActivityOptions.abort(options);
@@ -3099,24 +3093,30 @@ class ActivityStack extends Task implements BoundsAnimationTarget {
// TODO: Can only be called from special methods in ActivityStackSupervisor.
// Need to consolidate those calls points into this resize method so anyone can call directly.
- void resize(Rect bounds, Rect tempTaskBounds, Rect tempTaskInsetBounds,
- boolean preserveWindows, boolean deferResume) {
- if (!updateBoundsAllowed(bounds)) {
+ void resize(Rect displayedBounds, Rect configBounds, boolean preserveWindows,
+ boolean deferResume) {
+ if (!updateBoundsAllowed(displayedBounds)) {
return;
}
Trace.traceBegin(TRACE_TAG_WINDOW_MANAGER, "stack.resize_" + getRootTaskId());
mAtmService.deferWindowLayout();
try {
+ // TODO: Why not just set this on the stack directly vs. on each tasks?
// Update override configurations of all tasks in the stack.
- final Rect taskBounds = tempTaskBounds != null ? tempTaskBounds : bounds;
final PooledConsumer c = PooledLambda.obtainConsumer(
ActivityStack::processTaskResizeBounds, PooledLambda.__(Task.class),
- taskBounds, tempTaskInsetBounds);
- forAllTasks(c, true /* traverseTopToBottom */, this);
+ displayedBounds, configBounds);
+ forAllTasks(c, true /* traverseTopToBottom */);
c.recycle();
- setBounds(bounds);
+ if (mBoundsAnimating) {
+ // Force to update task surface bounds and relayout windows, since configBounds
+ // remains unchanged during bounds animation.
+ updateSurfaceBounds();
+ getDisplay().setLayoutNeeded();
+ mWmService.requestTraversal();
+ }
if (!deferResume) {
ensureVisibleActivitiesConfiguration(topRunningActivity(), preserveWindows);
@@ -3127,15 +3127,16 @@ class ActivityStack extends Task implements BoundsAnimationTarget {
}
}
- private static void processTaskResizeBounds(Task task, Rect bounds, Rect insetBounds) {
+ private static void processTaskResizeBounds(
+ Task task, Rect displayedBounds, Rect configBounds) {
if (!task.isResizeable()) return;
- if (insetBounds != null && !insetBounds.isEmpty()) {
- task.setOverrideDisplayedBounds(bounds);
- task.setBounds(insetBounds);
+ if (configBounds != null && !configBounds.isEmpty()) {
+ task.setOverrideDisplayedBounds(displayedBounds);
+ task.setBounds(configBounds);
} else {
task.setOverrideDisplayedBounds(null);
- task.setBounds(bounds);
+ task.setBounds(displayedBounds);
}
}
@@ -3150,7 +3151,7 @@ class ActivityStack extends Task implements BoundsAnimationTarget {
final PooledConsumer c = PooledLambda.obtainConsumer(ActivityStack::setTaskBounds,
PooledLambda.__(Task.class), bounds);
- forAllTasks(c, true /* traverseTopToBottom */, this);
+ forAllLeafTasks(c, true /* traverseTopToBottom */);
c.recycle();
}
@@ -3166,7 +3167,7 @@ class ActivityStack extends Task implements BoundsAnimationTarget {
final PooledConsumer c = PooledLambda.obtainConsumer(ActivityStack::setTaskDisplayedBounds,
PooledLambda.__(Task.class), bounds);
- forAllTasks(c, true /* traverseTopToBottom */, this);
+ forAllLeafTasks(c, true /* traverseTopToBottom */);
c.recycle();
}
@@ -3262,7 +3263,7 @@ class ActivityStack extends Task implements BoundsAnimationTarget {
return false;
}
final String prefix = " ";
- forAllTasks((task) -> {
+ forAllLeafTasks((task) -> {
if (needSep) {
pw.println("");
}
@@ -3280,7 +3281,7 @@ class ActivityStack extends Task implements BoundsAnimationTarget {
false /* traverseTopToBottom */);
dumpHistoryList(fd, pw, activities, prefix, "Hist", true, !dumpAll, dumpClient,
dumpPackage, false, null, task);
- }, true /* traverseTopToBottom */, this);
+ }, true /* traverseTopToBottom */);
return true;
}
@@ -3331,19 +3332,33 @@ class ActivityStack extends Task implements BoundsAnimationTarget {
}
}
- Task createTask(int taskId, ActivityInfo info, Intent intent, boolean toTop) {
- return createTask(taskId, info, intent, null /*voiceSession*/, null /*voiceInteractor*/,
+ Task reuseOrCreateTask(ActivityInfo info, Intent intent, boolean toTop) {
+ return reuseOrCreateTask(info, intent, null /*voiceSession*/, null /*voiceInteractor*/,
toTop, null /*activity*/, null /*source*/, null /*options*/);
}
+ // TODO: Can be removed once we change callpoints creating stacks to be creating tasks.
+ /** Either returns this current task to be re-used or creates a new child task. */
+ Task reuseOrCreateTask(ActivityInfo info, Intent intent, IVoiceInteractionSession voiceSession,
+ IVoiceInteractor voiceInteractor, boolean toTop, ActivityRecord activity,
+ ActivityRecord source, ActivityOptions options) {
+
+ Task task;
+ if (DisplayContent.alwaysCreateStack(getWindowingMode(), getActivityType())) {
+ // This stack will only contain one task, so just return itself since all stacks ara now
+ // tasks and all tasks are now stacks.
+ task = reuseAsLeafTask(voiceSession, voiceInteractor, info, activity);
+ } else {
+ // Create child task since this stack can contain multiple tasks.
+ final int taskId = activity != null
+ ? mStackSupervisor.getNextTaskIdForUser(activity.mUserId)
+ : mStackSupervisor.getNextTaskIdForUser();
+ task = Task.create(
+ mAtmService, taskId, info, intent, voiceSession, voiceInteractor, this);
+
+ // add the task to stack first, mTaskPositioner might need the stack association
+ addChild(task, toTop, (info.flags & FLAG_SHOW_FOR_ALL_USERS) != 0);
+ }
- Task createTask(int taskId, ActivityInfo info, Intent intent,
- IVoiceInteractionSession voiceSession, IVoiceInteractor voiceInteractor,
- boolean toTop, ActivityRecord activity, ActivityRecord source,
- ActivityOptions options) {
- final Task task = Task.create(
- mAtmService, taskId, info, intent, voiceSession, voiceInteractor, this);
- // add the task to stack first, mTaskPositioner might need the stack association
- addChild(task, toTop, (info.flags & FLAG_SHOW_FOR_ALL_USERS) != 0);
int displayId = getDisplayId();
if (displayId == INVALID_DISPLAY) displayId = DEFAULT_DISPLAY;
final boolean isLockscreenShown = mAtmService.mStackSupervisor.getKeyguardController()
@@ -3353,6 +3368,7 @@ class ActivityStack extends Task implements BoundsAnimationTarget {
&& !matchParentBounds() && task.isResizeable() && !isLockscreenShown) {
task.setBounds(getRequestedOverrideBounds());
}
+
return task;
}
@@ -3559,10 +3575,6 @@ class ActivityStack extends Task implements BoundsAnimationTarget {
"Can't exit pinned mode if it's not pinned already.");
}
- if (mChildren.size() != 1) {
- throw new RuntimeException("There should be only one task in a pinned stack.");
- }
-
// give pinned stack a chance to save current bounds, this should happen before reparent.
final ActivityRecord top = topRunningNonOverlayTaskActivity();
if (top != null && top.isVisible()) {
@@ -3592,12 +3604,12 @@ class ActivityStack extends Task implements BoundsAnimationTarget {
final PooledConsumer c = PooledLambda.obtainConsumer(
ActivityStackSupervisor::updatePictureInPictureMode, mStackSupervisor,
PooledLambda.__(Task.class), targetStackBounds, forceUpdate);
- forAllTasks(c, true /* traverseTopToBottom */, this);
+ forAllLeafTasks(c, true /* traverseTopToBottom */);
c.recycle();
}
void prepareFreezingTaskBounds() {
- forAllTasks(Task::prepareFreezingBounds, true /* traverseTopToBottom */, this);
+ forAllLeafTasks(Task::prepareFreezingBounds, true /* traverseTopToBottom */);
}
/**
@@ -3629,7 +3641,7 @@ class ActivityStack extends Task implements BoundsAnimationTarget {
final PooledConsumer c = PooledLambda.obtainConsumer(Task::alignToAdjustedBounds,
PooledLambda.__(Task.class), adjusted ? mAdjustedBounds : getRawBounds(),
insetBounds, alignBottom);
- forAllTasks(c, true /* traverseTopToBottom */, this);
+ forAllLeafTasks(c, true /* traverseTopToBottom */);
c.recycle();
}
@@ -3902,6 +3914,12 @@ class ActivityStack extends Task implements BoundsAnimationTarget {
return;
}
+ if (child == this) {
+ // TODO: Fix call-points
+ moveToFront("positionChildAtTop");
+ return;
+ }
+
positionChildAt(POSITION_TOP, child, true /* includingParents */);
child.updateTaskMovement(true);
@@ -4316,19 +4334,19 @@ class ActivityStack extends Task implements BoundsAnimationTarget {
* to the list of to be drawn windows the service is waiting for.
*/
void beginImeAdjustAnimation() {
- forAllTasks((t) -> {
+ forAllLeafTasks((t) -> {
if (t.hasContentToDisplay()) {
t.setDragResizing(true, DRAG_RESIZE_MODE_DOCKED_DIVIDER);
t.setWaitingForDrawnIfResizingChanged();
}
- }, true /* traverseTopToBottom */, this);
+ }, true /* traverseTopToBottom */);
}
/** Resets the resizing state of all windows. */
void endImeAdjustAnimation() {
- forAllTasks((t) -> {
+ forAllLeafTasks((t) -> {
t.setDragResizing(false, DRAG_RESIZE_MODE_DOCKED_DIVIDER);
- }, true /* traverseTopToBottom */, this);
+ }, true /* traverseTopToBottom */);
}
private int getMinTopStackBottom(final Rect displayContentRect, int originalStackBottom) {
@@ -4572,19 +4590,15 @@ class ActivityStack extends Task implements BoundsAnimationTarget {
return task != null;
}
- public boolean setPinnedStackSize(Rect stackBounds, Rect tempTaskBounds) {
+ public boolean setPinnedStackSize(Rect displayedBounds, Rect configBounds) {
// Hold the lock since this is called from the BoundsAnimator running on the UiThread
synchronized (mWmService.mGlobalLock) {
if (mCancelCurrentBoundsAnimation) {
return false;
}
+ mStackSupervisor.resizePinnedStack(displayedBounds, configBounds);
}
- try {
- mWmService.mActivityTaskManager.resizePinnedStack(stackBounds, tempTaskBounds);
- } catch (RemoteException e) {
- // I don't believe you.
- }
return true;
}
@@ -4730,7 +4744,7 @@ class ActivityStack extends Task implements BoundsAnimationTarget {
/** Called immediately prior to resizing the tasks at the end of the pinned stack animation. */
void onPipAnimationEndResize() {
mBoundsAnimating = false;
- forAllTasks(Task::clearPreserveNonFloatingState, false /* traverseTopToBottom */, this);
+ forAllLeafTasks(Task::clearPreserveNonFloatingState, false /* traverseTopToBottom */);
mWmService.requestTraversal();
}
diff --git a/services/core/java/com/android/server/wm/ActivityStackSupervisor.java b/services/core/java/com/android/server/wm/ActivityStackSupervisor.java
index 70cd01b44f05..97b638820a8a 100644
--- a/services/core/java/com/android/server/wm/ActivityStackSupervisor.java
+++ b/services/core/java/com/android/server/wm/ActivityStackSupervisor.java
@@ -419,14 +419,29 @@ public class ActivityStackSupervisor implements RecentTasks.Callbacks {
mTopTask = fromStack.getTopMostTask();
final PooledConsumer c = PooledLambda.obtainConsumer(
- MoveTaskToFullscreenHelper::processTask, this, PooledLambda.__(Task.class));
- fromStack.forAllTasks(c, false /* traverseTopToBottom */, fromStack);
+ MoveTaskToFullscreenHelper::processLeafTask, this, PooledLambda.__(Task.class));
+ fromStack.forAllLeafTasks(c, false /* traverseTopToBottom */);
c.recycle();
mToDisplay = null;
mTopTask = null;
}
- private void processTask(Task task) {
+ private void processLeafTask(Task task) {
+ // This is a one level task that we don't need to create stack for reparenting to.
+ if (task.isRootTask() && DisplayContent.alwaysCreateStack(WINDOWING_MODE_FULLSCREEN,
+ task.getActivityType())) {
+ final ActivityStack stack = (ActivityStack) task;
+ stack.setWindowingMode(WINDOWING_MODE_FULLSCREEN);
+ if (mToDisplay.getDisplayId() != stack.getDisplayId()) {
+ mToDisplay.moveStackToDisplay(stack, mOnTop);
+ } else if (mOnTop) {
+ mToDisplay.positionStackAtTop(stack, false /* includingParents */);
+ } else {
+ mToDisplay.positionStackAtBottom(stack);
+ }
+ return;
+ }
+
final ActivityStack toStack = mToDisplay.getOrCreateStack(
null, mTmpOptions, task, task.getActivityType(), mOnTop);
@@ -1428,8 +1443,7 @@ public class ActivityStackSupervisor implements RecentTasks.Callbacks {
// still need moveTaskToFrontLocked() below for any transition settings.
}
if (stack.shouldResizeStackWithLaunchBounds()) {
- stack.resize(bounds, null /* tempTaskBounds */, null /* tempTaskInsetBounds */,
- !PRESERVE_WINDOWS, !DEFER_RESUME);
+ stack.resize(bounds, null /* configBounds */, !PRESERVE_WINDOWS, !DEFER_RESUME);
} else {
// WM resizeTask must be done after the task is moved to the correct stack,
// because Task's setBounds() also updates dim layer's bounds, but that has
@@ -1443,7 +1457,7 @@ public class ActivityStackSupervisor implements RecentTasks.Callbacks {
}
final ActivityRecord r = task.getTopNonFinishingActivity();
- currentStack.moveTaskToFrontLocked(task, false /* noAnimation */, options,
+ currentStack.moveTaskToFront(task, false /* noAnimation */, options,
r == null ? null : r.appTimeTracker, reason);
if (DEBUG_STACK) Slog.d(TAG_STACK,
@@ -1589,7 +1603,7 @@ public class ActivityStackSupervisor implements RecentTasks.Callbacks {
false /* deferResume */);
}
- void resizeDockedStackLocked(Rect dockedBounds, Rect tempDockedTaskBounds,
+ void resizeDockedStackLocked(Rect displayedBounds, Rect tempDockedTaskBounds,
Rect tempDockedTaskInsetBounds, Rect tempOtherTaskBounds, Rect tempOtherTaskInsetBounds,
boolean preserveWindows, boolean deferResume) {
@@ -1607,7 +1621,7 @@ public class ActivityStackSupervisor implements RecentTasks.Callbacks {
if (mDockedStackResizing) {
mHasPendingDockedBounds = true;
- mPendingDockedBounds = copyOrNull(dockedBounds);
+ mPendingDockedBounds = copyOrNull(displayedBounds);
mPendingTempDockedTaskBounds = copyOrNull(tempDockedTaskBounds);
mPendingTempDockedTaskInsetBounds = copyOrNull(tempDockedTaskInsetBounds);
mPendingTempOtherTaskBounds = copyOrNull(tempOtherTaskBounds);
@@ -1620,13 +1634,13 @@ public class ActivityStackSupervisor implements RecentTasks.Callbacks {
// Don't allow re-entry while resizing. E.g. due to docked stack detaching.
mAllowDockedStackResize = false;
ActivityRecord r = stack.topRunningActivity();
- stack.resize(dockedBounds, tempDockedTaskBounds, tempDockedTaskInsetBounds,
+ stack.resize(displayedBounds, tempDockedTaskBounds,
!PRESERVE_WINDOWS, DEFER_RESUME);
// TODO: Checking for isAttached might not be needed as if the user passes in null
// dockedBounds then they want the docked stack to be dismissed.
if (stack.getWindowingMode() == WINDOWING_MODE_FULLSCREEN
- || (dockedBounds == null && !stack.isAttached())) {
+ || (displayedBounds == null && !stack.isAttached())) {
// The dock stack either was dismissed or went fullscreen, which is kinda the same.
// In this case we make all other static stacks fullscreen and move all
// docked stack tasks to the fullscreen stack.
@@ -1654,7 +1668,7 @@ public class ActivityStackSupervisor implements RecentTasks.Callbacks {
// interaction.
continue;
}
- current.getStackDockedModeBounds(dockedBounds,
+ current.getStackDockedModeBounds(displayedBounds,
tempOtherTaskBounds /* currentTempTaskBounds */,
tempRect /* outStackBounds */,
otherTaskRect /* outTempTaskBounds */);
@@ -1669,9 +1683,7 @@ public class ActivityStackSupervisor implements RecentTasks.Callbacks {
+ " non-fullscreen stack");
}
- current.resize(tempRect,
- !otherTaskRect.isEmpty() ? otherTaskRect : tempOtherTaskBounds,
- tempOtherTaskInsetBounds, preserveWindows, deferResume);
+ current.resize(tempRect, tempOtherTaskBounds, preserveWindows, deferResume);
}
}
if (!deferResume) {
@@ -1684,7 +1696,7 @@ public class ActivityStackSupervisor implements RecentTasks.Callbacks {
}
}
- void resizePinnedStackLocked(Rect pinnedBounds, Rect tempPinnedTaskBounds) {
+ void resizePinnedStack(Rect displayedBounds, Rect inConfigBounds) {
// TODO(multi-display): The display containing the stack should be passed in.
final ActivityStack stack =
mRootWindowContainer.getDefaultDisplay().getRootPinnedTask();
@@ -1696,23 +1708,22 @@ public class ActivityStackSupervisor implements RecentTasks.Callbacks {
Trace.traceBegin(TRACE_TAG_WINDOW_MANAGER, "resizePinnedStack");
mService.deferWindowLayout();
try {
- Rect insetBounds = null;
- if (tempPinnedTaskBounds != null && stack.isAnimatingBoundsToFullscreen()) {
+ Rect configBounds = null;
+ if (inConfigBounds != null) {
// Use 0,0 as the position for the inset rect because we are headed for fullscreen.
- insetBounds = tempRect;
- insetBounds.top = 0;
- insetBounds.left = 0;
- insetBounds.right = tempPinnedTaskBounds.width();
- insetBounds.bottom = tempPinnedTaskBounds.height();
+ configBounds = tempRect;
+ configBounds.top = 0;
+ configBounds.left = 0;
+ configBounds.right = inConfigBounds.width();
+ configBounds.bottom = inConfigBounds.height();
}
- if (pinnedBounds != null && tempPinnedTaskBounds == null) {
+ if (displayedBounds != null && inConfigBounds == null) {
// We have finished the animation into PiP, and are resizing the tasks to match the
// stack bounds, while layouts are deferred, update any task state as a part of
// transitioning it from fullscreen into a floating state.
stack.onPipAnimationEndResize();
}
- stack.resize(pinnedBounds, tempPinnedTaskBounds, insetBounds, !PRESERVE_WINDOWS,
- !DEFER_RESUME);
+ stack.resize(displayedBounds, configBounds, !PRESERVE_WINDOWS, !DEFER_RESUME);
} finally {
mService.continueWindowLayout();
Trace.traceEnd(TRACE_TAG_WINDOW_MANAGER);
@@ -1742,7 +1753,7 @@ public class ActivityStackSupervisor implements RecentTasks.Callbacks {
} else {
final PooledConsumer c = PooledLambda.obtainConsumer(
ActivityStackSupervisor::processRemoveTask, this, PooledLambda.__(Task.class));
- stack.forAllTasks(c, true /* traverseTopToBottom */, stack);
+ stack.forAllLeafTasks(c, true /* traverseTopToBottom */);
c.recycle();
}
}
@@ -2755,6 +2766,10 @@ public class ActivityStackSupervisor implements RecentTasks.Callbacks {
deferUpdateRecentsHomeStackBounds();
// TODO(multi-display): currently recents animation only support default display.
mWindowManager.prepareAppTransition(TRANSIT_DOCK_TASK_FROM_RECENTS, false);
+ // TODO(task-hierarchy): Remove when tiles are in hierarchy.
+ // Unset launching windowing mode to prevent creating split-screen-primary stack
+ // in RWC#anyTaskForId() below.
+ activityOptions.setLaunchWindowingMode(WINDOWING_MODE_UNDEFINED);
}
task = mRootWindowContainer.anyTaskForId(taskId,
@@ -2764,6 +2779,9 @@ public class ActivityStackSupervisor implements RecentTasks.Callbacks {
mWindowManager.executeAppTransition();
throw new IllegalArgumentException(
"startActivityFromRecents: Task " + taskId + " not found.");
+ } else if (windowingMode == WINDOWING_MODE_SPLIT_SCREEN_PRIMARY
+ && task.getWindowingMode() != windowingMode) {
+ mService.moveTaskToSplitScreenPrimaryTile(task, true /* toTop */);
}
if (windowingMode != WINDOWING_MODE_SPLIT_SCREEN_PRIMARY) {
diff --git a/services/core/java/com/android/server/wm/ActivityStarter.java b/services/core/java/com/android/server/wm/ActivityStarter.java
index 2a2ab4b79166..600a125cdf43 100644
--- a/services/core/java/com/android/server/wm/ActivityStarter.java
+++ b/services/core/java/com/android/server/wm/ActivityStarter.java
@@ -2366,7 +2366,7 @@ class ActivityStarter {
// task on top there.
// Defer resuming the top activity while moving task to top, since the
// current task-top activity may not be the activity that should be resumed.
- mTargetStack.moveTaskToFrontLocked(intentTask, mNoAnimation, mOptions,
+ mTargetStack.moveTaskToFront(intentTask, mNoAnimation, mOptions,
mStartActivity.appTimeTracker, DEFER_RESUME,
"bringingFoundTaskToFront");
mMovedToFront = !isSplitScreenTopStack;
@@ -2396,8 +2396,7 @@ class ActivityStarter {
private void setNewTask(Task taskToAffiliate) {
final boolean toTop = !mLaunchTaskBehind && !mAvoidMoveToFront;
- final Task task = mTargetStack.createTask(
- mSupervisor.getNextTaskIdForUser(mStartActivity.mUserId),
+ final Task task = mTargetStack.reuseOrCreateTask(
mNewTaskInfo != null ? mNewTaskInfo : mStartActivity.info,
mNewTaskIntent != null ? mNewTaskIntent : mIntent, mVoiceSession,
mVoiceInteractor, toTop, mStartActivity, mSourceRecord, mOptions);
diff --git a/services/core/java/com/android/server/wm/ActivityTaskManagerService.java b/services/core/java/com/android/server/wm/ActivityTaskManagerService.java
index 882d5c70de25..344d4a58c749 100644
--- a/services/core/java/com/android/server/wm/ActivityTaskManagerService.java
+++ b/services/core/java/com/android/server/wm/ActivityTaskManagerService.java
@@ -2760,9 +2760,17 @@ public class ActivityTaskManagerService extends IActivityTaskManager.Stub {
throw new IllegalArgumentException("setTaskWindowingMode: Attempt to move"
+ " non-standard task " + taskId + " to split-screen windowing mode");
}
+ if (!task.supportsSplitScreenWindowingMode()) {
+ return false;
+ }
final int prevMode = task.getWindowingMode();
- final ActivityStack stack = task.getStack();
+ moveTaskToSplitScreenPrimaryTile(task, toTop);
+ return prevMode != task.getWindowingMode();
+ }
+
+ void moveTaskToSplitScreenPrimaryTile(Task task, boolean toTop) {
+ ActivityStack stack = task.getStack();
TaskTile tile = null;
for (int i = stack.getDisplay().getStackCount() - 1; i >= 0; --i) {
tile = stack.getDisplay().getStackAt(i).asTile();
@@ -2776,7 +2784,6 @@ public class ActivityTaskManagerService extends IActivityTaskManager.Stub {
WindowContainerTransaction wct = new WindowContainerTransaction();
wct.reparent(stack.mRemoteToken, tile.mRemoteToken, toTop);
mTaskOrganizerController.applyContainerTransaction(wct, null);
- return prevMode != task.getWindowingMode();
}
/**
@@ -3247,8 +3254,9 @@ public class ActivityTaskManagerService extends IActivityTaskManager.Stub {
}
final ActivityStack stack = r.getRootTask();
- final Task task = stack.createTask(
- mStackSupervisor.getNextTaskIdForUser(r.mUserId), ainfo, intent, !ON_TOP);
+ final Task task = stack.getDisplay().createStack(stack.getWindowingMode(),
+ stack.getActivityType(), !ON_TOP, ainfo, intent);
+
if (!mRecentTasks.addToBottom(task)) {
// The app has too many tasks already and we can't add any more
stack.removeChild(task, "addAppTask");
@@ -4426,12 +4434,12 @@ public class ActivityTaskManagerService extends IActivityTaskManager.Stub {
}
@Override
- public void resizePinnedStack(Rect pinnedBounds, Rect tempPinnedTaskBounds) {
+ public void resizePinnedStack(Rect displayedBounds, Rect configBounds) {
enforceCallerIsRecentsOrHasPermission(MANAGE_ACTIVITY_STACKS, "resizePinnedStack()");
final long ident = Binder.clearCallingIdentity();
try {
synchronized (mGlobalLock) {
- mStackSupervisor.resizePinnedStackLocked(pinnedBounds, tempPinnedTaskBounds);
+ mStackSupervisor.resizePinnedStack(displayedBounds, configBounds);
}
} finally {
Binder.restoreCallingIdentity(ident);
diff --git a/services/core/java/com/android/server/wm/BoundsAnimationTarget.java b/services/core/java/com/android/server/wm/BoundsAnimationTarget.java
index 9f54e49e0022..b1d535904fab 100644
--- a/services/core/java/com/android/server/wm/BoundsAnimationTarget.java
+++ b/services/core/java/com/android/server/wm/BoundsAnimationTarget.java
@@ -52,7 +52,7 @@ interface BoundsAnimationTarget {
* animation is now invalid and not required. In such a case, the cancel will trigger the
* animation end callback as well, but will not send any further size changes.
*/
- boolean setPinnedStackSize(Rect stackBounds, Rect taskBounds);
+ boolean setPinnedStackSize(Rect displayedBounds, Rect configBounds);
/** Sets the alpha of the animation target */
boolean setPinnedStackAlpha(float alpha);
diff --git a/services/core/java/com/android/server/wm/DisplayContent.java b/services/core/java/com/android/server/wm/DisplayContent.java
index e60ab3fdc31c..0029dc8c3c25 100644
--- a/services/core/java/com/android/server/wm/DisplayContent.java
+++ b/services/core/java/com/android/server/wm/DisplayContent.java
@@ -4415,7 +4415,7 @@ class DisplayContent extends WindowContainer<DisplayContent.DisplayChildWindowCo
ArrayList<Task> getVisibleTasks() {
final ArrayList<Task> visibleTasks = new ArrayList<>();
forAllTasks(task -> {
- if (!task.isRootTask() && task.isVisible()) {
+ if (task.isLeafTask() && task.isVisible()) {
visibleTasks.add(task);
}
});
@@ -4537,6 +4537,8 @@ class DisplayContent extends WindowContainer<DisplayContent.DisplayChildWindowCo
true /* includingParents */);
}
+ child.updateTaskMovement(moveToTop);
+
setLayoutNeeded();
}
@@ -5790,7 +5792,7 @@ class DisplayContent extends WindowContainer<DisplayContent.DisplayChildWindowCo
return null;
}
- boolean alwaysCreateStack(int windowingMode, int activityType) {
+ static boolean alwaysCreateStack(int windowingMode, int activityType) {
// Always create a stack for fullscreen, freeform, and split-screen-secondary windowing
// modes so that we can manage visual ordering and return types correctly.
return activityType == ACTIVITY_TYPE_STANDARD
diff --git a/services/core/java/com/android/server/wm/DisplayPolicy.java b/services/core/java/com/android/server/wm/DisplayPolicy.java
index e443fe42a82e..f02a9dd61107 100644
--- a/services/core/java/com/android/server/wm/DisplayPolicy.java
+++ b/services/core/java/com/android/server/wm/DisplayPolicy.java
@@ -131,7 +131,6 @@ import android.graphics.Rect;
import android.graphics.Region;
import android.hardware.input.InputManager;
import android.hardware.power.V1_0.PowerHint;
-import android.os.Binder;
import android.os.Handler;
import android.os.Looper;
import android.os.Message;
@@ -304,6 +303,8 @@ public class DisplayPolicy {
private boolean mIsFreeformWindowOverlappingWithNavBar;
+ private boolean mLastImmersiveMode;
+
private final StatusBarController mStatusBarController;
private final BarController mNavigationBarController;
@@ -3182,8 +3183,8 @@ public class DisplayPolicy {
if (nb) mNavigationBarController.showTransient();
updateSystemUiVisibilityLw();
}
- mImmersiveModeConfirmation.confirmCurrentPrompt();
}
+ mImmersiveModeConfirmation.confirmCurrentPrompt();
}
}
@@ -3210,7 +3211,7 @@ public class DisplayPolicy {
updateSystemUiVisibilityLw();
}
- private int updateSystemUiVisibilityLw() {
+ int updateSystemUiVisibilityLw() {
// If there is no window focused, there will be nobody to handle the events
// anyway, so just hang on in whatever state we're in until things settle down.
WindowState winCandidate = mFocusedWindow != null ? mFocusedWindow
@@ -3566,9 +3567,11 @@ public class DisplayPolicy {
vis = mStatusBarController.updateVisibilityLw(transientStatusBarAllowed, oldVis, vis);
// update navigation bar
- boolean oldImmersiveMode = isImmersiveMode(oldVis);
- boolean newImmersiveMode = isImmersiveMode(vis);
+ boolean newInsetsMode = ViewRootImpl.sNewInsetsMode == NEW_INSETS_MODE_FULL;
+ boolean oldImmersiveMode = newInsetsMode ? mLastImmersiveMode : isImmersiveMode(oldVis);
+ boolean newImmersiveMode = newInsetsMode ? isImmersiveMode(win) : isImmersiveMode(vis);
if (oldImmersiveMode != newImmersiveMode) {
+ mLastImmersiveMode = newImmersiveMode;
final String pkg = win.getOwningPackage();
mImmersiveModeConfirmation.immersiveModeChangedLw(pkg, newImmersiveMode,
mService.mPolicy.isUserSetupComplete(),
@@ -3673,6 +3676,7 @@ public class DisplayPolicy {
}
}
+ // TODO(b/118118435): Remove this after migration
private boolean isImmersiveMode(int vis) {
final int flags = View.SYSTEM_UI_FLAG_IMMERSIVE | View.SYSTEM_UI_FLAG_IMMERSIVE_STICKY;
return mNavigationBar != null
@@ -3681,6 +3685,16 @@ public class DisplayPolicy {
&& canHideNavigationBar();
}
+ private boolean isImmersiveMode(WindowState win) {
+ final int behavior = win.mAttrs.insetsFlags.behavior;
+ return mNavigationBar != null
+ && canHideNavigationBar()
+ && (behavior == BEHAVIOR_SHOW_BARS_BY_SWIPE
+ || behavior == BEHAVIOR_SHOW_TRANSIENT_BARS_BY_SWIPE)
+ && getInsetsPolicy().isHidden(ITYPE_NAVIGATION_BAR)
+ && win != getNotificationShade();
+ }
+
/**
* @return whether the navigation bar can be hidden, e.g. the device has a navigation bar
*/
diff --git a/services/core/java/com/android/server/wm/DisplayRotation.java b/services/core/java/com/android/server/wm/DisplayRotation.java
index 64c5faa24454..57babb0eeaa0 100644
--- a/services/core/java/com/android/server/wm/DisplayRotation.java
+++ b/services/core/java/com/android/server/wm/DisplayRotation.java
@@ -558,16 +558,14 @@ public class DisplayRotation {
@VisibleForTesting
boolean shouldRotateSeamlessly(int oldRotation, int newRotation, boolean forceUpdate) {
- final WindowState w = mDisplayPolicy.getTopFullscreenOpaqueWindow();
- if (w == null) {
- return false;
- }
// Display doesn't need to be frozen because application has been started in correct
// rotation already, so the rest of the windows can use seamless rotation.
- if (w.mToken.hasFixedRotationTransform()) {
+ if (mDisplayContent.mFixedRotationLaunchingApp != null) {
return true;
}
- if (w != mDisplayContent.mCurrentFocus) {
+
+ final WindowState w = mDisplayPolicy.getTopFullscreenOpaqueWindow();
+ if (w == null || w != mDisplayContent.mCurrentFocus) {
return false;
}
// We only enable seamless rotation if the top window has requested it and is in the
diff --git a/services/core/java/com/android/server/wm/EnsureActivitiesVisibleHelper.java b/services/core/java/com/android/server/wm/EnsureActivitiesVisibleHelper.java
index 9d985d7048e5..c92de2b84df6 100644
--- a/services/core/java/com/android/server/wm/EnsureActivitiesVisibleHelper.java
+++ b/services/core/java/com/android/server/wm/EnsureActivitiesVisibleHelper.java
@@ -76,7 +76,7 @@ class EnsureActivitiesVisibleHelper {
// to be visible (such as performing Recents animation).
final boolean resumeTopActivity = mTop != null && !mTop.mLaunchTaskBehind
&& mContiner.isTopActivityFocusable()
- && mContiner.isInStackLocked(starting) == null;
+ && (starting == null || !starting.isDescendantOf(mContiner));
final PooledConsumer f = PooledLambda.obtainConsumer(
EnsureActivitiesVisibleHelper::setActivityVisibilityState, this,
diff --git a/services/core/java/com/android/server/wm/InsetsStateController.java b/services/core/java/com/android/server/wm/InsetsStateController.java
index a8fe34953cee..b3890cd84196 100644
--- a/services/core/java/com/android/server/wm/InsetsStateController.java
+++ b/services/core/java/com/android/server/wm/InsetsStateController.java
@@ -182,6 +182,7 @@ class InsetsStateController {
}
if (changed) {
notifyInsetsChanged();
+ mDisplayContent.getDisplayPolicy().updateSystemUiVisibilityLw();
}
}
diff --git a/services/core/java/com/android/server/wm/RecentsAnimation.java b/services/core/java/com/android/server/wm/RecentsAnimation.java
index b0492be5f542..e92bbaae71d3 100644
--- a/services/core/java/com/android/server/wm/RecentsAnimation.java
+++ b/services/core/java/com/android/server/wm/RecentsAnimation.java
@@ -334,7 +334,7 @@ class RecentsAnimation implements RecentsAnimationCallbacks,
if (sendUserLeaveHint) {
// Setting this allows the previous app to PiP.
mStackSupervisor.mUserLeaving = true;
- targetStack.moveTaskToFrontLocked(targetActivity.getTask(),
+ targetStack.moveTaskToFront(targetActivity.getTask(),
true /* noAnimation */, null /* activityOptions */,
targetActivity.appTimeTracker,
"RecentsAnimation.onAnimationFinished()");
diff --git a/services/core/java/com/android/server/wm/RecentsAnimationController.java b/services/core/java/com/android/server/wm/RecentsAnimationController.java
index e923e6413546..57c877fcdfef 100644
--- a/services/core/java/com/android/server/wm/RecentsAnimationController.java
+++ b/services/core/java/com/android/server/wm/RecentsAnimationController.java
@@ -376,7 +376,7 @@ public class RecentsAnimationController implements DeathRecipient {
final PooledConsumer c = PooledLambda.obtainConsumer((t, outList) ->
{ if (!outList.contains(t)) outList.add(t); }, PooledLambda.__(Task.class),
visibleTasks);
- targetStack.forAllTasks(c, true /* traverseTopToBottom */, targetStack);
+ targetStack.forAllLeafTasks(c, true /* traverseTopToBottom */);
c.recycle();
}
diff --git a/services/core/java/com/android/server/wm/ResetTargetTaskHelper.java b/services/core/java/com/android/server/wm/ResetTargetTaskHelper.java
index 63346b9a3e5b..45f8a15979f4 100644
--- a/services/core/java/com/android/server/wm/ResetTargetTaskHelper.java
+++ b/services/core/java/com/android/server/wm/ResetTargetTaskHelper.java
@@ -67,7 +67,7 @@ class ResetTargetTaskHelper {
final PooledConsumer c = PooledLambda.obtainConsumer(
ResetTargetTaskHelper::processTask, this, PooledLambda.__(Task.class));
- targetTask.mWmService.mRoot.forAllTasks(c, true /*traverseTopToBottom*/, mTargetStack);
+ targetTask.mWmService.mRoot.forAllLeafTasks(c, true /*traverseTopToBottom*/);
c.recycle();
processPendingReparentActivities();
@@ -245,9 +245,8 @@ class ResetTargetTaskHelper {
if (DEBUG_TASKS) Slog.v(TAG_TASKS, "Start pushing activity "
+ r + " out to bottom task " + targetTask);
} else {
- targetTask = mTargetStack.createTask(
- atmService.mStackSupervisor.getNextTaskIdForUser(r.mUserId), r.info,
- null /* intent */, false /* toTop */);
+ targetTask = mTargetStack.reuseOrCreateTask(
+ r.info, null /*intent*/, false /*toTop*/);
targetTask.affinityIntent = r.intent;
createdTasks.add(targetTask);
if (DEBUG_TASKS) Slog.v(TAG_TASKS, "Start pushing activity "
diff --git a/services/core/java/com/android/server/wm/RootWindowContainer.java b/services/core/java/com/android/server/wm/RootWindowContainer.java
index 2596452eb46a..aa6bdfd1aa5b 100644
--- a/services/core/java/com/android/server/wm/RootWindowContainer.java
+++ b/services/core/java/com/android/server/wm/RootWindowContainer.java
@@ -2137,10 +2137,7 @@ class RootWindowContainer extends WindowContainer<DisplayContent>
r.getActivityType(), ON_TOP, r.info, r.intent);
// There are multiple activities in the task and moving the top activity should
// reveal/leave the other activities in their original task.
-
- Task newTask = stack.createTask(mStackSupervisor.getNextTaskIdForUser(r.mUserId),
- r.info, r.intent, true);
- r.reparent(newTask, MAX_VALUE, "moveActivityToStack");
+ r.reparent(stack, MAX_VALUE, "moveActivityToStack");
}
stack.setWindowingMode(WINDOWING_MODE_PINNED);
@@ -2407,7 +2404,7 @@ class RootWindowContainer extends WindowContainer<DisplayContent>
final PooledConsumer c = PooledLambda.obtainConsumer(
RootWindowContainer::processTaskForStackInfo, PooledLambda.__(Task.class), info,
currentIndex);
- stack.forAllTasks(c, false /* traverseTopToBottom */, stack);
+ stack.forAllLeafTasks(c, false /* traverseTopToBottom */);
c.recycle();
final ActivityRecord top = stack.topRunningActivity();
@@ -3302,7 +3299,7 @@ class RootWindowContainer extends WindowContainer<DisplayContent>
final PooledConsumer c = PooledLambda.obtainConsumer(
RootWindowContainer::taskTopActivityIsUser, this, PooledLambda.__(Task.class),
userId);
- forAllTasks(c);
+ forAllLeafTasks(c, true /* traverseTopToBottom */);
c.recycle();
} finally {
mService.continueWindowLayout();
@@ -3321,14 +3318,6 @@ class RootWindowContainer extends WindowContainer<DisplayContent>
* @return {@code true} if the top activity looks like it belongs to {@param userId}.
*/
private void taskTopActivityIsUser(Task task, @UserIdInt int userId) {
- // TODO(b/80414790): having utilities to loop for all leaf tasks from caller vs. checking
- // leaf tasks here.
- if (!task.isLeafTask()) {
- // No op if not a leaf task since we don't want to report root tasks to
- // TaskStackListeners.
- return;
- }
-
// To handle the case that work app is in the task but just is not the top one.
final ActivityRecord activityRecord = task.getTopNonFinishingActivity();
final ActivityRecord resultTo = (activityRecord != null ? activityRecord.resultTo : null);
@@ -3430,18 +3419,8 @@ class RootWindowContainer extends WindowContainer<DisplayContent>
}
ActivityRecord isInAnyStack(IBinder token) {
- int numDisplays = getChildCount();
- for (int displayNdx = 0; displayNdx < numDisplays; ++displayNdx) {
- final DisplayContent display = getChildAt(displayNdx);
- for (int stackNdx = display.getStackCount() - 1; stackNdx >= 0; --stackNdx) {
- final ActivityStack stack = display.getStackAt(stackNdx);
- final ActivityRecord r = stack.isInStackLocked(token);
- if (r != null) {
- return r;
- }
- }
- }
- return null;
+ final ActivityRecord r = ActivityRecord.forTokenLocked(token);
+ return (r != null && r.isDescendantOf(this)) ? r : null;
}
@VisibleForTesting
diff --git a/services/core/java/com/android/server/wm/RunningTasks.java b/services/core/java/com/android/server/wm/RunningTasks.java
index 6ebbf776feba..9593ea070509 100644
--- a/services/core/java/com/android/server/wm/RunningTasks.java
+++ b/services/core/java/com/android/server/wm/RunningTasks.java
@@ -76,7 +76,7 @@ class RunningTasks {
final PooledConsumer c = PooledLambda.obtainConsumer(RunningTasks::processTask, this,
PooledLambda.__(Task.class));
- root.forAllTasks(c, false);
+ root.forAllLeafTasks(c, false);
c.recycle();
// Take the first {@param maxNum} tasks and create running task infos for them
@@ -93,9 +93,6 @@ class RunningTasks {
}
private void processTask(Task task) {
- if (task.isRootTask()) {
- return;
- }
if (task.getTopNonFinishingActivity() == null) {
// Skip if there are no activities in the task
return;
diff --git a/services/core/java/com/android/server/wm/Task.java b/services/core/java/com/android/server/wm/Task.java
index c7f2cc7f3692..f93e39282dd6 100644
--- a/services/core/java/com/android/server/wm/Task.java
+++ b/services/core/java/com/android/server/wm/Task.java
@@ -225,8 +225,8 @@ class Task extends WindowContainer<WindowContainer> {
String affinity; // The affinity name for this task, or null; may change identity.
String rootAffinity; // Initial base affinity, or null; does not change from initial root.
- final IVoiceInteractionSession voiceSession; // Voice interaction session driving task
- final IVoiceInteractor voiceInteractor; // Associated interactor to provide to app
+ IVoiceInteractionSession voiceSession; // Voice interaction session driving task
+ IVoiceInteractor voiceInteractor; // Associated interactor to provide to app
Intent intent; // The original intent that started the task. Note that this value can
// be null.
Intent affinityIntent; // Intent of affinity-moved activity that started this task.
@@ -422,6 +422,8 @@ class Task extends WindowContainer<WindowContainer> {
/** When set, will force the task to report as invisible. */
boolean mForceHidden = false;
+ SurfaceControl.Transaction mMainWindowSizeChangeTransaction;
+
private final FindRootHelper mFindRootHelper = new FindRootHelper();
private class FindRootHelper {
private ActivityRecord mRoot;
@@ -571,6 +573,15 @@ class Task extends WindowContainer<WindowContainer> {
mAtmService.getTaskChangeNotificationController().notifyTaskCreated(_taskId, realActivity);
}
+ Task reuseAsLeafTask(IVoiceInteractionSession _voiceSession, IVoiceInteractor _voiceInteractor,
+ ActivityInfo info, ActivityRecord activity) {
+ voiceSession = _voiceSession;
+ voiceInteractor = _voiceInteractor;
+ setIntent(activity);
+ setMinDimensions(info);
+ return this;
+ }
+
private void cleanUpResourcesForDestroy(ConfigurationContainer oldParent) {
if (hasChild()) {
return;
@@ -1004,7 +1015,7 @@ class Task extends WindowContainer<WindowContainer> {
}
/** Sets the original minimal width and height. */
- private void setMinDimensions(ActivityInfo info) {
+ void setMinDimensions(ActivityInfo info) {
if (info != null && info.windowLayout != null) {
mMinWidth = info.windowLayout.minWidth;
mMinHeight = info.windowLayout.minHeight;
@@ -2176,16 +2187,20 @@ class Task extends WindowContainer<WindowContainer> {
return Configuration.reduceScreenLayout(sourceScreenLayout, longSize, shortSize);
}
+ void resolveTileOverrideConfiguration(Configuration newParentConfig) {
+ super.resolveOverrideConfiguration(newParentConfig);
+ }
+
@Override
void resolveOverrideConfiguration(Configuration newParentConfig) {
- if (isRootTask()) {
- super.resolveOverrideConfiguration(newParentConfig);
+ if (!isLeafTask()) {
+ resolveTileOverrideConfiguration(newParentConfig);
return;
}
mTmpBounds.set(getResolvedOverrideConfiguration().windowConfiguration.getBounds());
- super.resolveOverrideConfiguration(newParentConfig);
+ resolveTileOverrideConfiguration(newParentConfig);
int windowingMode =
- getRequestedOverrideConfiguration().windowConfiguration.getWindowingMode();
+ getResolvedOverrideConfiguration().windowConfiguration.getWindowingMode();
if (windowingMode == WINDOWING_MODE_UNDEFINED) {
windowingMode = newParentConfig.windowConfiguration.getWindowingMode();
}
@@ -2392,7 +2407,7 @@ class Task extends WindowContainer<WindowContainer> {
final int[] currentCount = {0};
final PooledConsumer c = PooledLambda.obtainConsumer((t, count) -> { count[0]++; },
PooledLambda.__(Task.class), currentCount);
- forAllTasks(c, false /* traverseTopToBottom */, this);
+ forAllLeafTasks(c, false /* traverseTopToBottom */);
c.recycle();
return currentCount[0];
}
@@ -2614,6 +2629,7 @@ class Task extends WindowContainer<WindowContainer> {
*/
void setOverrideDisplayedBounds(Rect overrideDisplayedBounds) {
if (overrideDisplayedBounds != null) {
+ adjustForMinimalTaskDimensions(overrideDisplayedBounds, mOverrideDisplayedBounds);
mOverrideDisplayedBounds.set(overrideDisplayedBounds);
} else {
mOverrideDisplayedBounds.setEmpty();
@@ -3074,16 +3090,33 @@ class Task extends WindowContainer<WindowContainer> {
}
@Override
- void forAllTasks(Consumer<Task> callback, boolean traverseTopToBottom, Task excludedTask) {
- super.forAllTasks(callback, traverseTopToBottom, excludedTask);
- if (excludedTask != this) {
- callback.accept(this);
+ void forAllLeafTasks(Consumer<Task> callback, boolean traverseTopToBottom) {
+ final int count = mChildren.size();
+ boolean isLeafTask = true;
+ if (traverseTopToBottom) {
+ for (int i = count - 1; i >= 0; --i) {
+ final Task child = mChildren.get(i).asTask();
+ if (child != null) {
+ isLeafTask = false;
+ child.forAllLeafTasks(callback, traverseTopToBottom);
+ }
+ }
+ } else {
+ for (int i = 0; i < count; i++) {
+ final Task child = mChildren.get(i).asTask();
+ if (child != null) {
+ isLeafTask = false;
+ child.forAllLeafTasks(callback, traverseTopToBottom);
+ }
+ }
}
+ if (isLeafTask) callback.accept(this);
}
@Override
void forAllTasks(Consumer<Task> callback, boolean traverseTopToBottom) {
- forAllTasks(callback, traverseTopToBottom, null /* excludedTask */);
+ super.forAllTasks(callback, traverseTopToBottom);
+ callback.accept(this);
}
@Override
@@ -3265,7 +3298,7 @@ class Task extends WindowContainer<WindowContainer> {
pw.print(" effectiveUid="); UserHandle.formatUid(pw, effectiveUid);
pw.print(" mCallingUid="); UserHandle.formatUid(pw, mCallingUid);
pw.print(" mUserSetupComplete="); pw.print(mUserSetupComplete);
- pw.print(" mCallingPackage="); pw.println(mCallingPackage);
+ pw.print(" mCallingPackage="); pw.print(mCallingPackage);
pw.print(" mCallingFeatureId="); pw.println(mCallingFeatureId);
if (affinity != null || rootAffinity != null) {
pw.print(prefix); pw.print("affinity="); pw.print(affinity);
@@ -3979,4 +4012,17 @@ class Task extends WindowContainer<WindowContainer> {
mAtmService.mTaskOrganizerController.dispatchTaskInfoChanged(
this, true /* force */);
}
+
+ /**
+ * See {@link WindowContainerTransaction#setBoundsChangeTransaction}. In short this
+ * transaction will be consumed by the next BASE_APPLICATION window within our hierarchy
+ * to resize, and it will defer the transaction until that resize frame completes.
+ */
+ void setMainWindowSizeChangeTransaction(SurfaceControl.Transaction t) {
+ mMainWindowSizeChangeTransaction = t;
+ }
+
+ SurfaceControl.Transaction getMainWindowSizeChangeTransaction() {
+ return mMainWindowSizeChangeTransaction;
+ }
}
diff --git a/services/core/java/com/android/server/wm/TaskOrganizerController.java b/services/core/java/com/android/server/wm/TaskOrganizerController.java
index 4d5621cd5b32..6caa27c7fa6f 100644
--- a/services/core/java/com/android/server/wm/TaskOrganizerController.java
+++ b/services/core/java/com/android/server/wm/TaskOrganizerController.java
@@ -547,8 +547,7 @@ class TaskOrganizerController extends ITaskOrganizerController.Stub
final ActivityStack stack = (ActivityStack) container;
if (stack.inPinnedWindowingMode()) {
stack.resize(config.windowConfiguration.getBounds(),
- null /* tempTaskBounds */, null /* tempTaskInsetBounds */,
- PRESERVE_WINDOWS, true /* deferResume */);
+ null /* configBounds */, PRESERVE_WINDOWS, true /* deferResume */);
}
}
}
@@ -557,6 +556,12 @@ class TaskOrganizerController extends ITaskOrganizerController.Stub
WindowContainerTransaction.Change c) {
int effects = sanitizeAndApplyChange(wc, c);
+ final SurfaceControl.Transaction t = c.getBoundsChangeTransaction();
+ if (t != null) {
+ Task tr = (Task) wc;
+ tr.setMainWindowSizeChangeTransaction(t);
+ }
+
Rect enterPipBounds = c.getEnterPipBounds();
if (enterPipBounds != null) {
Task tr = (Task) wc;
diff --git a/services/core/java/com/android/server/wm/WindowContainer.java b/services/core/java/com/android/server/wm/WindowContainer.java
index da996dcce50d..7a4d0b0d9169 100644
--- a/services/core/java/com/android/server/wm/WindowContainer.java
+++ b/services/core/java/com/android/server/wm/WindowContainer.java
@@ -615,7 +615,7 @@ class WindowContainer<E extends WindowContainer> extends ConfigurationContainer<
void positionChildAt(int position, E child, boolean includingParents) {
if (child.getParent() != this) {
- throw new IllegalArgumentException("removeChild: container=" + child.getName()
+ throw new IllegalArgumentException("positionChildAt: container=" + child.getName()
+ " is not a child of container=" + getName()
+ " current parent=" + child.getParent());
}
@@ -1459,15 +1459,15 @@ class WindowContainer<E extends WindowContainer> extends ConfigurationContainer<
}
}
- void forAllTasks(Consumer<Task> callback, boolean traverseTopToBottom, Task excludedTask) {
+ void forAllLeafTasks(Consumer<Task> callback, boolean traverseTopToBottom) {
final int count = mChildren.size();
if (traverseTopToBottom) {
for (int i = count - 1; i >= 0; --i) {
- mChildren.get(i).forAllTasks(callback, traverseTopToBottom, excludedTask);
+ mChildren.get(i).forAllLeafTasks(callback, traverseTopToBottom);
}
} else {
for (int i = 0; i < count; i++) {
- mChildren.get(i).forAllTasks(callback, traverseTopToBottom, excludedTask);
+ mChildren.get(i).forAllLeafTasks(callback, traverseTopToBottom);
}
}
}
diff --git a/services/core/java/com/android/server/wm/WindowStateAnimator.java b/services/core/java/com/android/server/wm/WindowStateAnimator.java
index 9552df7b5899..a1a9af680e92 100644
--- a/services/core/java/com/android/server/wm/WindowStateAnimator.java
+++ b/services/core/java/com/android/server/wm/WindowStateAnimator.java
@@ -873,6 +873,14 @@ class WindowStateAnimator {
clipRect = mTmpClipRect;
}
+ if (mSurfaceResized && (mAttrType == TYPE_BASE_APPLICATION) &&
+ (task != null) && (task.getMainWindowSizeChangeTransaction() != null)) {
+ mSurfaceController.deferTransactionUntil(mWin.getDeferTransactionBarrier(),
+ mWin.getFrameNumber());
+ SurfaceControl.mergeToGlobalTransaction(task.getMainWindowSizeChangeTransaction());
+ task.setMainWindowSizeChangeTransaction(null);
+ }
+
float surfaceWidth = mSurfaceController.getWidth();
float surfaceHeight = mSurfaceController.getHeight();
diff --git a/services/core/jni/com_android_server_location_GnssLocationProvider.cpp b/services/core/jni/com_android_server_location_GnssLocationProvider.cpp
index 36ed9a5a383f..336934e5fb03 100644
--- a/services/core/jni/com_android_server_location_GnssLocationProvider.cpp
+++ b/services/core/jni/com_android_server_location_GnssLocationProvider.cpp
@@ -166,7 +166,10 @@ using android::hardware::gnss::V2_0::ElapsedRealtimeFlags;
using MeasurementCorrections_V1_0 = android::hardware::gnss::measurement_corrections::V1_0::MeasurementCorrections;
using MeasurementCorrections_V1_1 = android::hardware::gnss::measurement_corrections::V1_1::MeasurementCorrections;
-using android::hardware::gnss::measurement_corrections::V1_0::SingleSatCorrection;
+using SingleSatCorrection_V1_0 =
+ android::hardware::gnss::measurement_corrections::V1_0::SingleSatCorrection;
+using SingleSatCorrection_V1_1 =
+ android::hardware::gnss::measurement_corrections::V1_1::SingleSatCorrection;
using android::hardware::gnss::measurement_corrections::V1_0::ReflectingPlane;
using android::hidl::base::V1_0::IBase;
@@ -3124,6 +3127,91 @@ static jboolean
return JNI_FALSE;
}
+static SingleSatCorrection_V1_0 getSingleSatCorrection_1_0_withoutConstellation(
+ JNIEnv* env, jobject singleSatCorrectionObj) {
+ jint correctionFlags = env->CallIntMethod(singleSatCorrectionObj, method_correctionSatFlags);
+ jint satId = env->CallIntMethod(singleSatCorrectionObj, method_correctionSatId);
+ jfloat carrierFreqHz =
+ env->CallFloatMethod(singleSatCorrectionObj, method_correctionSatCarrierFreq);
+ jfloat probSatIsLos =
+ env->CallFloatMethod(singleSatCorrectionObj, method_correctionSatIsLosProb);
+ jfloat eplMeters = env->CallFloatMethod(singleSatCorrectionObj, method_correctionSatEpl);
+ jfloat eplUncMeters = env->CallFloatMethod(singleSatCorrectionObj, method_correctionSatEplUnc);
+ uint16_t corrFlags = static_cast<uint16_t>(correctionFlags);
+ jobject reflectingPlaneObj;
+ bool has_ref_plane = (corrFlags & GnssSingleSatCorrectionFlags::HAS_REFLECTING_PLANE) != 0;
+ if (has_ref_plane) {
+ reflectingPlaneObj =
+ env->CallObjectMethod(singleSatCorrectionObj, method_correctionSatRefPlane);
+ }
+
+ ReflectingPlane reflectingPlane;
+ if (has_ref_plane) {
+ jdouble latitudeDegreesRefPlane =
+ env->CallDoubleMethod(reflectingPlaneObj, method_correctionPlaneLatDeg);
+ jdouble longitudeDegreesRefPlane =
+ env->CallDoubleMethod(reflectingPlaneObj, method_correctionPlaneLngDeg);
+ jdouble altitudeDegreesRefPlane =
+ env->CallDoubleMethod(reflectingPlaneObj, method_correctionPlaneAltDeg);
+ jdouble azimuthDegreeRefPlane =
+ env->CallDoubleMethod(reflectingPlaneObj, method_correctionPlaneAzimDeg);
+ reflectingPlane = {
+ .latitudeDegrees = latitudeDegreesRefPlane,
+ .longitudeDegrees = longitudeDegreesRefPlane,
+ .altitudeMeters = altitudeDegreesRefPlane,
+ .azimuthDegrees = azimuthDegreeRefPlane,
+ };
+ }
+
+ SingleSatCorrection_V1_0 singleSatCorrection = {
+ .singleSatCorrectionFlags = corrFlags,
+ .svid = static_cast<uint16_t>(satId),
+ .carrierFrequencyHz = carrierFreqHz,
+ .probSatIsLos = probSatIsLos,
+ .excessPathLengthMeters = eplMeters,
+ .excessPathLengthUncertaintyMeters = eplUncMeters,
+ .reflectingPlane = reflectingPlane,
+ };
+
+ return singleSatCorrection;
+}
+
+static void getSingleSatCorrectionList_1_1(JNIEnv* env, jobject singleSatCorrectionList,
+ hidl_vec<SingleSatCorrection_V1_1>& list) {
+ for (uint16_t i = 0; i < list.size(); ++i) {
+ jobject singleSatCorrectionObj =
+ env->CallObjectMethod(singleSatCorrectionList, method_correctionListGet, i);
+
+ SingleSatCorrection_V1_0 singleSatCorrection_1_0 =
+ getSingleSatCorrection_1_0_withoutConstellation(env, singleSatCorrectionObj);
+
+ jint constType = env->CallIntMethod(singleSatCorrectionObj, method_correctionSatConstType);
+
+ SingleSatCorrection_V1_1 singleSatCorrection_1_1 = {
+ .v1_0 = singleSatCorrection_1_0,
+ .constellation = static_cast<GnssConstellationType_V2_0>(constType),
+ };
+
+ list[i] = singleSatCorrection_1_1;
+ }
+}
+
+static void getSingleSatCorrectionList_1_0(JNIEnv* env, jobject singleSatCorrectionList,
+ hidl_vec<SingleSatCorrection_V1_0>& list) {
+ for (uint16_t i = 0; i < list.size(); ++i) {
+ jobject singleSatCorrectionObj =
+ env->CallObjectMethod(singleSatCorrectionList, method_correctionListGet, i);
+
+ SingleSatCorrection_V1_0 singleSatCorrection =
+ getSingleSatCorrection_1_0_withoutConstellation(env, singleSatCorrectionObj);
+
+ jint constType = env->CallIntMethod(singleSatCorrectionObj, method_correctionSatConstType);
+
+ singleSatCorrection.constellation = static_cast<GnssConstellationType_V1_0>(constType),
+
+ list[i] = singleSatCorrection;
+ }
+}
static jboolean
android_location_GnssMeasurementCorrectionsProvider_inject_gnss_measurement_corrections(
JNIEnv* env,
@@ -3146,64 +3234,6 @@ static jboolean
ALOGI("Empty correction list injected....Returning with no HAL injection");
return JNI_TRUE;
}
- hidl_vec<SingleSatCorrection> list(len);
-
- for (uint16_t i = 0; i < len; ++i) {
- jobject singleSatCorrectionObj = env->CallObjectMethod(
- singleSatCorrectionList, method_correctionListGet, i);
-
- jint correctionFlags =
- env->CallIntMethod(singleSatCorrectionObj, method_correctionSatFlags);
- jint constType = env->CallIntMethod(singleSatCorrectionObj,
- method_correctionSatConstType);
- jint satId =
- env->CallIntMethod(singleSatCorrectionObj, method_correctionSatId);
- jfloat carrierFreqHz = env->CallFloatMethod(
- singleSatCorrectionObj, method_correctionSatCarrierFreq);
- jfloat probSatIsLos = env->CallFloatMethod(singleSatCorrectionObj,
- method_correctionSatIsLosProb);
- jfloat eplMeters =
- env->CallFloatMethod(singleSatCorrectionObj, method_correctionSatEpl);
- jfloat eplUncMeters = env->CallFloatMethod(singleSatCorrectionObj,
- method_correctionSatEplUnc);
- uint16_t corrFlags = static_cast<uint16_t>(correctionFlags);
- jobject reflectingPlaneObj;
- bool has_ref_plane = (corrFlags & GnssSingleSatCorrectionFlags::HAS_REFLECTING_PLANE) != 0;
- if (has_ref_plane) {
- reflectingPlaneObj = env->CallObjectMethod(
- singleSatCorrectionObj, method_correctionSatRefPlane);
- }
-
- ReflectingPlane reflectingPlane;
- if (has_ref_plane) {
- jdouble latitudeDegreesRefPlane = env->CallDoubleMethod(
- reflectingPlaneObj, method_correctionPlaneLatDeg);
- jdouble longitudeDegreesRefPlane = env->CallDoubleMethod(
- reflectingPlaneObj, method_correctionPlaneLngDeg);
- jdouble altitudeDegreesRefPlane = env->CallDoubleMethod(
- reflectingPlaneObj, method_correctionPlaneAltDeg);
- jdouble azimuthDegreeRefPlane = env->CallDoubleMethod(
- reflectingPlaneObj, method_correctionPlaneAzimDeg);
- reflectingPlane = {
- .latitudeDegrees = latitudeDegreesRefPlane,
- .longitudeDegrees = longitudeDegreesRefPlane,
- .altitudeMeters = altitudeDegreesRefPlane,
- .azimuthDegrees = azimuthDegreeRefPlane,
- };
- }
-
- SingleSatCorrection singleSatCorrection = {
- .singleSatCorrectionFlags = corrFlags,
- .constellation = static_cast<GnssConstellationType_V1_0>(constType),
- .svid = static_cast<uint16_t>(satId),
- .carrierFrequencyHz = carrierFreqHz,
- .probSatIsLos = probSatIsLos,
- .excessPathLengthMeters = eplMeters,
- .excessPathLengthUncertaintyMeters = eplUncMeters,
- .reflectingPlane = reflectingPlane,
- };
- list[i] = singleSatCorrection;
- }
jdouble latitudeDegreesCorr = env->CallDoubleMethod(
correctionsObj, method_correctionsGetLatitudeDegrees);
@@ -3225,7 +3255,6 @@ static jboolean
.horizontalPositionUncertaintyMeters = horizontalPositionUncertaintyMeters,
.verticalPositionUncertaintyMeters = verticalPositionUncertaintyMeters,
.toaGpsNanosecondsOfWeek = static_cast<uint64_t>(toaGpsNanosOfWeek),
- .satCorrections = list,
};
if (gnssCorrectionsIface_V1_1 != nullptr) {
@@ -3237,17 +3266,25 @@ static jboolean
jfloat environmentBearingUncertaintyDegreesCorr = env->CallFloatMethod(
correctionsObj, method_correctionsGetEnvironmentBearingUncertaintyDegrees);
+ hidl_vec<SingleSatCorrection_V1_1> list(len);
+ getSingleSatCorrectionList_1_1(env, singleSatCorrectionList, list);
+
MeasurementCorrections_V1_1 measurementCorrections_1_1 = {
- .v1_0 = measurementCorrections_1_0,
- .hasEnvironmentBearing = static_cast<bool>(hasEnvironmentBearingCorr),
- .environmentBearingDegrees = environmentBearingDegreesCorr,
- .environmentBearingUncertaintyDegrees = environmentBearingUncertaintyDegreesCorr,
+ .v1_0 = measurementCorrections_1_0,
+ .hasEnvironmentBearing = static_cast<bool>(hasEnvironmentBearingCorr),
+ .environmentBearingDegrees = environmentBearingDegreesCorr,
+ .environmentBearingUncertaintyDegrees = environmentBearingUncertaintyDegreesCorr,
+ .satCorrections = list,
};
auto result = gnssCorrectionsIface_V1_1->setCorrections_1_1(measurementCorrections_1_1);
return checkHidlReturn(result, "IMeasurementCorrections 1.1 setCorrections() failed.");
}
+ hidl_vec<SingleSatCorrection_V1_0> list(len);
+ getSingleSatCorrectionList_1_0(env, singleSatCorrectionList, list);
+ measurementCorrections_1_0.satCorrections = list;
+
auto result = gnssCorrectionsIface_V1_0->setCorrections(measurementCorrections_1_0);
return checkHidlReturn(result, "IMeasurementCorrections 1.0 setCorrections() failed.");
}
diff --git a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
index 421bfa44c788..b192dbd93249 100644
--- a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
+++ b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
@@ -186,7 +186,6 @@ import android.database.Cursor;
import android.graphics.Bitmap;
import android.graphics.Color;
import android.location.LocationManager;
-import android.location.LocationManagerInternal;
import android.media.AudioManager;
import android.media.IAudioService;
import android.net.ConnectivityManager;
@@ -1073,7 +1072,8 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager {
private static final String TAG_SUSPEND_PERSONAL_APPS = "suspend-personal-apps";
private static final String TAG_PROFILE_MAXIMUM_TIME_OFF = "profile-max-time-off";
private static final String TAG_PROFILE_OFF_DEADLINE = "profile-off-deadline";
-
+ private static final String TAG_ALWAYS_ON_VPN_PACKAGE = "vpn-package";
+ private static final String TAG_ALWAYS_ON_VPN_LOCKDOWN = "vpn-lockdown";
DeviceAdminInfo info;
@@ -1202,6 +1202,9 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager {
// Time by which the profile should be turned on according to System.currentTimeMillis().
long mProfileOffDeadline = 0;
+ public String mAlwaysOnVpnPackage;
+ public boolean mAlwaysOnVpnLockdown;
+
ActiveAdmin(DeviceAdminInfo _info, boolean parent) {
info = _info;
@@ -1442,6 +1445,12 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager {
if (mProfileMaximumTimeOff != 0) {
writeAttributeValueToXml(out, TAG_PROFILE_OFF_DEADLINE, mProfileOffDeadline);
}
+ if (!TextUtils.isEmpty(mAlwaysOnVpnPackage)) {
+ writeAttributeValueToXml(out, TAG_ALWAYS_ON_VPN_PACKAGE, mAlwaysOnVpnPackage);
+ }
+ if (mAlwaysOnVpnLockdown) {
+ writeAttributeValueToXml(out, TAG_ALWAYS_ON_VPN_LOCKDOWN, mAlwaysOnVpnLockdown);
+ }
}
void writeTextToXml(XmlSerializer out, String tag, String text) throws IOException {
@@ -1687,6 +1696,11 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager {
} else if (TAG_PROFILE_OFF_DEADLINE.equals(tag)) {
mProfileOffDeadline =
Long.parseLong(parser.getAttributeValue(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));
} else {
Slog.w(LOG_TAG, "Unknown admin tag: " + tag);
XmlUtils.skipCurrentTag(parser);
@@ -1919,6 +1933,10 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager {
pw.println(mProfileMaximumTimeOff);
pw.print("mProfileOffDeadline=");
pw.println(mProfileOffDeadline);
+ pw.print("mAlwaysOnVpnPackage=");
+ pw.println(mAlwaysOnVpnPackage);
+ pw.print("mAlwaysOnVpnLockdown=");
+ pw.println(mAlwaysOnVpnLockdown);
}
}
@@ -2112,10 +2130,6 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager {
return mContext.getSystemService(LocationManager.class);
}
- LocationManagerInternal getLocationManagerInternal() {
- return LocalServices.getService(LocationManagerInternal.class);
- }
-
IWindowManager getIWindowManager() {
return IWindowManager.Stub
.asInterface(ServiceManager.getService(Context.WINDOW_SERVICE));
@@ -6781,10 +6795,10 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager {
* @throws UnsupportedOperationException if the package does not support being set as always-on.
*/
@Override
- public boolean setAlwaysOnVpnPackage(ComponentName admin, String vpnPackage, boolean lockdown,
+ public boolean setAlwaysOnVpnPackage(ComponentName who, String vpnPackage, boolean lockdown,
List<String> lockdownWhitelist)
throws SecurityException {
- enforceProfileOrDeviceOwner(admin);
+ enforceProfileOrDeviceOwner(who);
final int userId = mInjector.userHandleGetCallingUserId();
mInjector.binderWithCleanCallingIdentity(() -> {
@@ -6810,12 +6824,22 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager {
}
DevicePolicyEventLogger
.createEvent(DevicePolicyEnums.SET_ALWAYS_ON_VPN_PACKAGE)
- .setAdmin(admin)
+ .setAdmin(who)
.setStrings(vpnPackage)
.setBoolean(lockdown)
.setInt(lockdownWhitelist != null ? lockdownWhitelist.size() : 0)
.write();
});
+ synchronized (getLockObject()) {
+ ActiveAdmin admin = getActiveAdminForCallerLocked(who,
+ DeviceAdminInfo.USES_POLICY_PROFILE_OWNER);
+ if (!TextUtils.equals(vpnPackage, admin.mAlwaysOnVpnPackage)
+ || lockdown != admin.mAlwaysOnVpnLockdown) {
+ admin.mAlwaysOnVpnPackage = vpnPackage;
+ admin.mAlwaysOnVpnLockdown = lockdown;
+ saveSettingsLocked(userId);
+ }
+ }
return true;
}
@@ -6829,6 +6853,15 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager {
}
@Override
+ public String getAlwaysOnVpnPackageForUser(int userHandle) {
+ enforceSystemCaller("getAlwaysOnVpnPackageForUser");
+ synchronized (getLockObject()) {
+ ActiveAdmin admin = getDeviceOrProfileOwnerAdminLocked(userHandle);
+ return admin != null ? admin.mAlwaysOnVpnPackage : null;
+ }
+ }
+
+ @Override
public boolean isAlwaysOnVpnLockdownEnabled(ComponentName admin) throws SecurityException {
enforceProfileOrDeviceOwner(admin);
@@ -6838,6 +6871,15 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager {
}
@Override
+ public boolean isAlwaysOnVpnLockdownEnabledForUser(int userHandle) {
+ enforceSystemCaller("isAlwaysOnVpnLockdownEnabledForUser");
+ synchronized (getLockObject()) {
+ ActiveAdmin admin = getDeviceOrProfileOwnerAdminLocked(userHandle);
+ return admin != null ? admin.mAlwaysOnVpnLockdown : null;
+ }
+ }
+
+ @Override
public List<String> getAlwaysOnVpnLockdownWhitelist(ComponentName admin)
throws SecurityException {
enforceProfileOrDeviceOwner(admin);
@@ -8987,6 +9029,19 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager {
return null;
}
+ /**
+ * Returns the ActiveAdmin associated wit the PO or DO on the given user.
+ * @param userHandle
+ * @return
+ */
+ private @Nullable ActiveAdmin getDeviceOrProfileOwnerAdminLocked(int userHandle) {
+ ActiveAdmin admin = getProfileOwnerAdminLocked(userHandle);
+ if (admin == null && getDeviceOwnerUserId() == userHandle) {
+ admin = getDeviceOwnerAdminLocked();
+ }
+ return admin;
+ }
+
@GuardedBy("getLockObject()")
ActiveAdmin getProfileOwnerOfOrganizationOwnedDeviceLocked(int userHandle) {
return mInjector.binderWithCleanCallingIdentity(() -> {
@@ -11643,17 +11698,6 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager {
}
@Override
- public void requestSetLocationProviderAllowed(ComponentName who, String provider,
- boolean providerAllowed) {
- Objects.requireNonNull(who, "ComponentName is null");
- enforceDeviceOwner(who);
-
- mInjector.binderWithCleanCallingIdentity(
- () -> mInjector.getLocationManagerInternal().requestSetProviderAllowed(provider,
- providerAllowed));
- }
-
- @Override
public boolean setTime(ComponentName who, long millis) {
Objects.requireNonNull(who, "ComponentName is null in setTime");
enforceDeviceOwnerOrProfileOwnerOnOrganizationOwnedDevice(who);
diff --git a/services/java/com/android/server/SystemServer.java b/services/java/com/android/server/SystemServer.java
index 569986c46186..b5d3d18b4350 100644
--- a/services/java/com/android/server/SystemServer.java
+++ b/services/java/com/android/server/SystemServer.java
@@ -44,7 +44,6 @@ import android.database.sqlite.SQLiteGlobal;
import android.graphics.GraphicsStatsService;
import android.hardware.display.DisplayManagerInternal;
import android.net.ConnectivityModuleConnector;
-import android.net.ITetheringConnector;
import android.net.NetworkStackClient;
import android.os.BaseBundle;
import android.os.Binder;
@@ -298,6 +297,9 @@ public final class SystemServer {
"com.android.server.blob.BlobStoreManagerService";
private static final String APP_SEARCH_MANAGER_SERVICE_CLASS =
"com.android.server.appsearch.AppSearchManagerService";
+
+ private static final String TETHERING_CONNECTOR_CLASS = "android.net.ITetheringConnector";
+
private static final String PERSISTENT_DATA_BLOCK_PROP = "ro.frp.pst";
private static final String UNCRYPT_PACKAGE_FILE = "/cache/recovery/uncrypt_file";
@@ -2331,7 +2333,7 @@ public final class SystemServer {
try {
// TODO: hide implementation details, b/146312721.
ConnectivityModuleConnector.getInstance().startModuleService(
- ITetheringConnector.class.getName(),
+ TETHERING_CONNECTOR_CLASS,
PERMISSION_MAINLINE_NETWORK_STACK, service -> {
ServiceManager.addService(Context.TETHERING_SERVICE, service,
false /* allowIsolated */,
diff --git a/services/people/java/com/android/server/people/data/AbstractProtoDiskReadWriter.java b/services/people/java/com/android/server/people/data/AbstractProtoDiskReadWriter.java
index 203e9804bfa3..7672cd0040ec 100644
--- a/services/people/java/com/android/server/people/data/AbstractProtoDiskReadWriter.java
+++ b/services/people/java/com/android/server/people/data/AbstractProtoDiskReadWriter.java
@@ -51,15 +51,18 @@ import java.util.concurrent.TimeoutException;
abstract class AbstractProtoDiskReadWriter<T> {
private static final String TAG = AbstractProtoDiskReadWriter.class.getSimpleName();
+
+ // Common disk write delay that will be appropriate for most scenarios.
+ private static final long DEFAULT_DISK_WRITE_DELAY = 2L * DateUtils.MINUTE_IN_MILLIS;
private static final long SHUTDOWN_DISK_WRITE_TIMEOUT = 5L * DateUtils.SECOND_IN_MILLIS;
private final File mRootDir;
private final ScheduledExecutorService mScheduledExecutorService;
- private final long mWriteDelayMs;
@GuardedBy("this")
private ScheduledFuture<?> mScheduledFuture;
+ // File name -> data class
@GuardedBy("this")
private Map<String, T> mScheduledFileDataMap = new ArrayMap<>();
@@ -75,15 +78,15 @@ abstract class AbstractProtoDiskReadWriter<T> {
*/
abstract ProtoStreamReader<T> protoStreamReader();
- AbstractProtoDiskReadWriter(@NonNull File rootDir, long writeDelayMs,
+ AbstractProtoDiskReadWriter(@NonNull File rootDir,
@NonNull ScheduledExecutorService scheduledExecutorService) {
mRootDir = rootDir;
- mWriteDelayMs = writeDelayMs;
mScheduledExecutorService = scheduledExecutorService;
}
@WorkerThread
- void delete(@NonNull String fileName) {
+ synchronized void delete(@NonNull String fileName) {
+ mScheduledFileDataMap.remove(fileName);
final File file = getFile(fileName);
if (!file.exists()) {
return;
@@ -174,7 +177,7 @@ abstract class AbstractProtoDiskReadWriter<T> {
}
mScheduledFuture = mScheduledExecutorService.schedule(this::flushScheduledData,
- mWriteDelayMs, TimeUnit.MILLISECONDS);
+ DEFAULT_DISK_WRITE_DELAY, TimeUnit.MILLISECONDS);
}
/**
@@ -183,7 +186,13 @@ abstract class AbstractProtoDiskReadWriter<T> {
*/
@MainThread
synchronized void saveImmediately(@NonNull String fileName, @NonNull T data) {
- if (mScheduledExecutorService.isShutdown()) {
+ mScheduledFileDataMap.put(fileName, data);
+ triggerScheduledFlushEarly();
+ }
+
+ @MainThread
+ private synchronized void triggerScheduledFlushEarly() {
+ if (mScheduledFileDataMap.isEmpty() || mScheduledExecutorService.isShutdown()) {
return;
}
// Cancel existing future.
@@ -194,7 +203,6 @@ abstract class AbstractProtoDiskReadWriter<T> {
mScheduledFuture.cancel(true);
}
- mScheduledFileDataMap.put(fileName, data);
// Submit flush and blocks until it completes. Blocking will prevent the device from
// shutting down before flushing completes.
Future<?> future = mScheduledExecutorService.submit(this::flushScheduledData);
@@ -212,9 +220,10 @@ abstract class AbstractProtoDiskReadWriter<T> {
return;
}
for (String fileName : mScheduledFileDataMap.keySet()) {
- T data = mScheduledFileDataMap.remove(fileName);
+ T data = mScheduledFileDataMap.get(fileName);
writeTo(fileName, data);
}
+ mScheduledFileDataMap.clear();
mScheduledFuture = null;
}
diff --git a/services/people/java/com/android/server/people/data/ConversationStore.java b/services/people/java/com/android/server/people/data/ConversationStore.java
index 3afb209ae5cd..62e9da83869c 100644
--- a/services/people/java/com/android/server/people/data/ConversationStore.java
+++ b/services/people/java/com/android/server/people/data/ConversationStore.java
@@ -23,7 +23,6 @@ import android.annotation.WorkerThread;
import android.content.LocusId;
import android.net.Uri;
import android.text.TextUtils;
-import android.text.format.DateUtils;
import android.util.ArrayMap;
import android.util.Slog;
import android.util.proto.ProtoInputStream;
@@ -50,8 +49,6 @@ class ConversationStore {
private static final String CONVERSATIONS_FILE_NAME = "conversations";
- private static final long DISK_WRITE_DELAY = 2L * DateUtils.MINUTE_IN_MILLIS;
-
// Shortcut ID -> Conversation Info
@GuardedBy("this")
private final Map<String, ConversationInfo> mConversationInfoMap = new ArrayMap<>();
@@ -92,7 +89,7 @@ class ConversationStore {
*/
@MainThread
void loadConversationsFromDisk() {
- mScheduledExecutorService.submit(() -> {
+ mScheduledExecutorService.execute(() -> {
synchronized (this) {
ConversationInfosProtoDiskReadWriter conversationInfosProtoDiskReadWriter =
getConversationInfosProtoDiskReadWriter();
@@ -194,6 +191,15 @@ class ConversationStore {
return getConversation(mNotifChannelIdToShortcutIdMap.get(notifChannelId));
}
+ synchronized void onDestroy() {
+ mConversationInfoMap.clear();
+ mContactUriToShortcutIdMap.clear();
+ mLocusIdToShortcutIdMap.clear();
+ mNotifChannelIdToShortcutIdMap.clear();
+ mPhoneNumberToShortcutIdMap.clear();
+ mConversationInfosProtoDiskReadWriter.deleteConversationsFile();
+ }
+
@MainThread
private synchronized void updateConversationsInMemory(
@NonNull ConversationInfo conversationInfo) {
@@ -239,8 +245,7 @@ class ConversationStore {
}
if (mConversationInfosProtoDiskReadWriter == null) {
mConversationInfosProtoDiskReadWriter = new ConversationInfosProtoDiskReadWriter(
- mPackageDir, CONVERSATIONS_FILE_NAME, DISK_WRITE_DELAY,
- mScheduledExecutorService);
+ mPackageDir, CONVERSATIONS_FILE_NAME, mScheduledExecutorService);
}
return mConversationInfosProtoDiskReadWriter;
}
@@ -264,16 +269,16 @@ class ConversationStore {
return conversationInfo;
}
- /** Reads and writes {@link ConversationInfo} on disk. */
- static class ConversationInfosProtoDiskReadWriter extends
+ /** Reads and writes {@link ConversationInfo}s on disk. */
+ private static class ConversationInfosProtoDiskReadWriter extends
AbstractProtoDiskReadWriter<List<ConversationInfo>> {
private final String mConversationInfoFileName;
- ConversationInfosProtoDiskReadWriter(@NonNull File baseDir,
+ ConversationInfosProtoDiskReadWriter(@NonNull File rootDir,
@NonNull String conversationInfoFileName,
- long writeDelayMs, @NonNull ScheduledExecutorService scheduledExecutorService) {
- super(baseDir, writeDelayMs, scheduledExecutorService);
+ @NonNull ScheduledExecutorService scheduledExecutorService) {
+ super(rootDir, scheduledExecutorService);
mConversationInfoFileName = conversationInfoFileName;
}
@@ -328,5 +333,10 @@ class ConversationStore {
void saveConversationsImmediately(@NonNull List<ConversationInfo> conversationInfos) {
saveImmediately(mConversationInfoFileName, conversationInfos);
}
+
+ @WorkerThread
+ void deleteConversationsFile() {
+ delete(mConversationInfoFileName);
+ }
}
}
diff --git a/services/people/java/com/android/server/people/data/DataManager.java b/services/people/java/com/android/server/people/data/DataManager.java
index 6b97c98b0029..27c169227637 100644
--- a/services/people/java/com/android/server/people/data/DataManager.java
+++ b/services/people/java/com/android/server/people/data/DataManager.java
@@ -51,7 +51,6 @@ import android.provider.Telephony.MmsSms;
import android.service.notification.NotificationListenerService;
import android.service.notification.StatusBarNotification;
import android.telecom.TelecomManager;
-import android.text.TextUtils;
import android.text.format.DateUtils;
import android.util.ArraySet;
import android.util.SparseArray;
@@ -275,40 +274,35 @@ public class DataManager {
mContext.getPackageName(), intentFilter, callingUserId);
}
- /** Reports the {@link AppTargetEvent} from App Prediction Manager. */
- public void reportAppTargetEvent(@NonNull AppTargetEvent event,
+ /** Reports the sharing related {@link AppTargetEvent} from App Prediction Manager. */
+ public void reportShareTargetEvent(@NonNull AppTargetEvent event,
@Nullable IntentFilter intentFilter) {
AppTarget appTarget = event.getTarget();
- ShortcutInfo shortcutInfo = appTarget != null ? appTarget.getShortcutInfo() : null;
- if (shortcutInfo == null || event.getAction() != AppTargetEvent.ACTION_LAUNCH) {
- return;
- }
- PackageData packageData = getPackage(appTarget.getPackageName(),
- appTarget.getUser().getIdentifier());
- if (packageData == null) {
+ if (appTarget == null || event.getAction() != AppTargetEvent.ACTION_LAUNCH) {
return;
}
+ UserData userData = getUnlockedUserData(appTarget.getUser().getIdentifier());
+ PackageData packageData = userData.getOrCreatePackageData(appTarget.getPackageName());
+ String mimeType = intentFilter != null ? intentFilter.getDataType(0) : null;
+ @Event.EventType int eventType = mimeTypeToShareEventType(mimeType);
+ EventHistoryImpl eventHistory;
if (ChooserActivity.LAUNCH_LOCATON_DIRECT_SHARE.equals(event.getLaunchLocation())) {
- String mimeType = intentFilter != null ? intentFilter.getDataType(0) : null;
- String shortcutId = shortcutInfo.getId();
- if (packageData.getConversationStore().getConversation(shortcutId) == null
- || TextUtils.isEmpty(mimeType)) {
+ // Direct share event
+ if (appTarget.getShortcutInfo() == null) {
return;
}
- EventHistoryImpl eventHistory = packageData.getEventStore().getOrCreateEventHistory(
- EventStore.CATEGORY_SHORTCUT_BASED, shortcutInfo.getId());
- @Event.EventType int eventType;
- if (mimeType.startsWith("text/")) {
- eventType = Event.TYPE_SHARE_TEXT;
- } else if (mimeType.startsWith("image/")) {
- eventType = Event.TYPE_SHARE_IMAGE;
- } else if (mimeType.startsWith("video/")) {
- eventType = Event.TYPE_SHARE_VIDEO;
- } else {
- eventType = Event.TYPE_SHARE_OTHER;
+ String shortcutId = appTarget.getShortcutInfo().getId();
+ if (packageData.getConversationStore().getConversation(shortcutId) == null) {
+ addOrUpdateConversationInfo(appTarget.getShortcutInfo());
}
- eventHistory.addEvent(new Event(System.currentTimeMillis(), eventType));
+ eventHistory = packageData.getEventStore().getOrCreateEventHistory(
+ EventStore.CATEGORY_SHORTCUT_BASED, shortcutId);
+ } else {
+ // App share event
+ eventHistory = packageData.getEventStore().getOrCreateEventHistory(
+ EventStore.CATEGORY_CLASS_BASED, appTarget.getClassName());
}
+ eventHistory.addEvent(new Event(System.currentTimeMillis(), eventType));
}
/** Prunes the data for the specified user. */
@@ -319,12 +313,11 @@ public class DataManager {
}
pruneUninstalledPackageData(userData);
- long currentTimeMillis = System.currentTimeMillis();
userData.forAllPackages(packageData -> {
if (signal.isCanceled()) {
return;
}
- packageData.getEventStore().pruneOldEvents(currentTimeMillis);
+ packageData.getEventStore().pruneOldEvents();
if (!packageData.isDefaultDialer()) {
packageData.getEventStore().deleteEventHistories(EventStore.CATEGORY_CALL);
}
@@ -335,6 +328,17 @@ public class DataManager {
});
}
+ private int mimeTypeToShareEventType(String mimeType) {
+ if (mimeType.startsWith("text/")) {
+ return Event.TYPE_SHARE_TEXT;
+ } else if (mimeType.startsWith("image/")) {
+ return Event.TYPE_SHARE_IMAGE;
+ } else if (mimeType.startsWith("video/")) {
+ return Event.TYPE_SHARE_VIDEO;
+ }
+ return Event.TYPE_SHARE_OTHER;
+ }
+
private void pruneUninstalledPackageData(@NonNull UserData userData) {
Set<String> installApps = new ArraySet<>();
mPackageManagerInternal.forEachInstalledPackage(
@@ -410,12 +414,13 @@ public class DataManager {
EventStore.CATEGORY_SHORTCUT_BASED, shortcutId);
}
+ private boolean isPersonShortcut(@NonNull ShortcutInfo shortcutInfo) {
+ return shortcutInfo.getPersons() != null && shortcutInfo.getPersons().length != 0;
+ }
+
@VisibleForTesting
@WorkerThread
- void onShortcutAddedOrUpdated(@NonNull ShortcutInfo shortcutInfo) {
- if (shortcutInfo.getPersons() == null || shortcutInfo.getPersons().length == 0) {
- return;
- }
+ void addOrUpdateConversationInfo(@NonNull ShortcutInfo shortcutInfo) {
UserData userData = getUnlockedUserData(shortcutInfo.getUserId());
if (userData == null) {
return;
@@ -431,24 +436,24 @@ public class DataManager {
builder.setShortcutId(shortcutInfo.getId());
builder.setLocusId(shortcutInfo.getLocusId());
builder.setShortcutFlags(shortcutInfo.getFlags());
-
- Person person = shortcutInfo.getPersons()[0];
- builder.setPersonImportant(person.isImportant());
- builder.setPersonBot(person.isBot());
- String contactUri = person.getUri();
- if (contactUri != null) {
- ContactsQueryHelper helper = mInjector.createContactsQueryHelper(mContext);
- if (helper.query(contactUri)) {
- builder.setContactUri(helper.getContactUri());
- builder.setContactStarred(helper.isStarred());
- builder.setContactPhoneNumber(helper.getPhoneNumber());
+ builder.setContactUri(null);
+ builder.setContactPhoneNumber(null);
+ builder.setContactStarred(false);
+
+ if (shortcutInfo.getPersons() != null && shortcutInfo.getPersons().length != 0) {
+ Person person = shortcutInfo.getPersons()[0];
+ builder.setPersonImportant(person.isImportant());
+ builder.setPersonBot(person.isBot());
+ String contactUri = person.getUri();
+ if (contactUri != null) {
+ ContactsQueryHelper helper = mInjector.createContactsQueryHelper(mContext);
+ if (helper.query(contactUri)) {
+ builder.setContactUri(helper.getContactUri());
+ builder.setContactStarred(helper.isStarred());
+ builder.setContactPhoneNumber(helper.getPhoneNumber());
+ }
}
- } else {
- builder.setContactUri(null);
- builder.setContactPhoneNumber(null);
- builder.setContactStarred(false);
}
-
conversationStore.addOrUpdate(builder.build());
}
@@ -626,7 +631,9 @@ public class DataManager {
List<ShortcutInfo> shortcuts = getShortcuts(packageName, userId,
/*shortcutIds=*/ null);
for (ShortcutInfo shortcut : shortcuts) {
- onShortcutAddedOrUpdated(shortcut);
+ if (isPersonShortcut(shortcut)) {
+ addOrUpdateConversationInfo(shortcut);
+ }
}
});
}
diff --git a/services/people/java/com/android/server/people/data/Event.java b/services/people/java/com/android/server/people/data/Event.java
index 81411c00db51..a929f6f68427 100644
--- a/services/people/java/com/android/server/people/data/Event.java
+++ b/services/people/java/com/android/server/people/data/Event.java
@@ -20,7 +20,13 @@ import android.annotation.IntDef;
import android.annotation.NonNull;
import android.text.format.DateFormat;
import android.util.ArraySet;
+import android.util.Slog;
+import android.util.proto.ProtoInputStream;
+import android.util.proto.ProtoOutputStream;
+import com.android.server.people.PeopleEventProto;
+
+import java.io.IOException;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.util.Objects;
@@ -29,6 +35,8 @@ import java.util.Set;
/** An event representing the interaction with a specific conversation or app. */
public class Event {
+ private static final String TAG = Event.class.getSimpleName();
+
public static final int TYPE_SHORTCUT_INVOCATION = 1;
public static final int TYPE_NOTIFICATION_POSTED = 2;
@@ -142,6 +150,36 @@ public class Event {
return mDurationSeconds;
}
+ /** Writes field members to {@link ProtoOutputStream}. */
+ void writeToProto(@NonNull ProtoOutputStream protoOutputStream) {
+ protoOutputStream.write(PeopleEventProto.EVENT_TYPE, mType);
+ protoOutputStream.write(PeopleEventProto.TIME, mTimestamp);
+ protoOutputStream.write(PeopleEventProto.DURATION, mDurationSeconds);
+ }
+
+ /** Reads from {@link ProtoInputStream} and constructs {@link Event}. */
+ @NonNull
+ static Event readFromProto(@NonNull ProtoInputStream protoInputStream) throws IOException {
+ Event.Builder builder = new Event.Builder();
+ while (protoInputStream.nextField() != ProtoInputStream.NO_MORE_FIELDS) {
+ switch (protoInputStream.getFieldNumber()) {
+ case (int) PeopleEventProto.EVENT_TYPE:
+ builder.setType(protoInputStream.readInt(PeopleEventProto.EVENT_TYPE));
+ break;
+ case (int) PeopleEventProto.TIME:
+ builder.setTimestamp(protoInputStream.readLong(PeopleEventProto.TIME));
+ break;
+ case (int) PeopleEventProto.DURATION:
+ builder.setDurationSeconds(protoInputStream.readInt(PeopleEventProto.DURATION));
+ break;
+ default:
+ Slog.w(TAG, "Could not read undefined field: "
+ + protoInputStream.getFieldNumber());
+ }
+ }
+ return builder.build();
+ }
+
@Override
public boolean equals(Object obj) {
if (this == obj) {
@@ -177,12 +215,14 @@ public class Event {
/** Builder class for {@link Event} objects. */
static class Builder {
- private final long mTimestamp;
+ private long mTimestamp;
- private final int mType;
+ private int mType;
private int mDurationSeconds;
+ private Builder() {}
+
Builder(long timestamp, @EventType int type) {
mTimestamp = timestamp;
mType = type;
@@ -193,6 +233,16 @@ public class Event {
return this;
}
+ private Builder setTimestamp(long timestamp) {
+ mTimestamp = timestamp;
+ return this;
+ }
+
+ private Builder setType(int type) {
+ mType = type;
+ return this;
+ }
+
Event build() {
return new Event(this);
}
diff --git a/services/people/java/com/android/server/people/data/EventHistoryImpl.java b/services/people/java/com/android/server/people/data/EventHistoryImpl.java
index 6bef1db5582e..85661c622fc2 100644
--- a/services/people/java/com/android/server/people/data/EventHistoryImpl.java
+++ b/services/people/java/com/android/server/people/data/EventHistoryImpl.java
@@ -16,42 +16,149 @@
package com.android.server.people.data;
+import android.annotation.MainThread;
import android.annotation.NonNull;
+import android.annotation.Nullable;
+import android.annotation.WorkerThread;
+import android.net.Uri;
+import android.text.format.DateUtils;
+import android.util.ArrayMap;
+import android.util.Slog;
import android.util.SparseArray;
+import android.util.proto.ProtoInputStream;
+import com.android.internal.annotations.GuardedBy;
import com.android.internal.annotations.VisibleForTesting;
+import com.android.server.people.PeopleEventIndexesProto;
+import com.android.server.people.PeopleEventsProto;
+import com.android.server.people.TypedPeopleEventIndexProto;
+import com.google.android.collect.Lists;
+
+import java.io.File;
+import java.io.IOException;
import java.util.List;
+import java.util.Map;
import java.util.Set;
+import java.util.concurrent.ScheduledExecutorService;
+
class EventHistoryImpl implements EventHistory {
+ private static final long MAX_EVENTS_AGE = 4L * DateUtils.HOUR_IN_MILLIS;
+ private static final long PRUNE_OLD_EVENTS_DELAY = 15L * DateUtils.MINUTE_IN_MILLIS;
+
+ private static final String EVENTS_DIR = "events";
+ private static final String INDEXES_DIR = "indexes";
+
private final Injector mInjector;
+ private final ScheduledExecutorService mScheduledExecutorService;
+ private final EventsProtoDiskReadWriter mEventsProtoDiskReadWriter;
+ private final EventIndexesProtoDiskReadWriter mEventIndexesProtoDiskReadWriter;
// Event Type -> Event Index
+ @GuardedBy("this")
private final SparseArray<EventIndex> mEventIndexArray = new SparseArray<>();
+ @GuardedBy("this")
private final EventList mRecentEvents = new EventList();
- EventHistoryImpl() {
- mInjector = new Injector();
+ private long mLastPruneTime;
+
+ EventHistoryImpl(@NonNull File rootDir,
+ @NonNull ScheduledExecutorService scheduledExecutorService) {
+ this(new Injector(), rootDir, scheduledExecutorService);
}
@VisibleForTesting
- EventHistoryImpl(Injector injector) {
+ EventHistoryImpl(@NonNull Injector injector, @NonNull File rootDir,
+ @NonNull ScheduledExecutorService scheduledExecutorService) {
mInjector = injector;
+ mScheduledExecutorService = scheduledExecutorService;
+ mLastPruneTime = injector.currentTimeMillis();
+
+ File eventsDir = new File(rootDir, EVENTS_DIR);
+ mEventsProtoDiskReadWriter = new EventsProtoDiskReadWriter(eventsDir,
+ mScheduledExecutorService);
+ File indexesDir = new File(rootDir, INDEXES_DIR);
+ mEventIndexesProtoDiskReadWriter = new EventIndexesProtoDiskReadWriter(indexesDir,
+ scheduledExecutorService);
+ }
+
+ @WorkerThread
+ @NonNull
+ static Map<String, EventHistoryImpl> eventHistoriesImplFromDisk(File categoryDir,
+ ScheduledExecutorService scheduledExecutorService) {
+ return eventHistoriesImplFromDisk(new Injector(), categoryDir, scheduledExecutorService);
+ }
+
+ @VisibleForTesting
+ @NonNull
+ static Map<String, EventHistoryImpl> eventHistoriesImplFromDisk(Injector injector,
+ File categoryDir, ScheduledExecutorService scheduledExecutorService) {
+ Map<String, EventHistoryImpl> results = new ArrayMap<>();
+ File[] keyDirs = categoryDir.listFiles(File::isDirectory);
+ if (keyDirs == null) {
+ return results;
+ }
+ for (File keyDir : keyDirs) {
+ File[] dirContents = keyDir.listFiles(
+ (dir, name) -> EVENTS_DIR.equals(name) || INDEXES_DIR.equals(name));
+ if (dirContents != null && dirContents.length == 2) {
+ EventHistoryImpl eventHistory = new EventHistoryImpl(injector, keyDir,
+ scheduledExecutorService);
+ eventHistory.loadFromDisk();
+ results.put(Uri.decode(keyDir.getName()), eventHistory);
+ }
+ }
+ return results;
+ }
+
+ /**
+ * Loads recent events and indexes from disk to memory in a background thread. This should be
+ * called after the device powers on and the user has been unlocked.
+ */
+ @VisibleForTesting
+ @MainThread
+ synchronized void loadFromDisk() {
+ mScheduledExecutorService.execute(() -> {
+ synchronized (this) {
+ EventList diskEvents = mEventsProtoDiskReadWriter.loadRecentEventsFromDisk();
+ if (diskEvents != null) {
+ diskEvents.removeOldEvents(mInjector.currentTimeMillis() - MAX_EVENTS_AGE);
+ mRecentEvents.addAll(diskEvents.getAllEvents());
+ }
+
+ SparseArray<EventIndex> diskIndexes =
+ mEventIndexesProtoDiskReadWriter.loadIndexesFromDisk();
+ if (diskIndexes != null) {
+ for (int i = 0; i < diskIndexes.size(); i++) {
+ mEventIndexArray.put(diskIndexes.keyAt(i), diskIndexes.valueAt(i));
+ }
+ }
+ }
+ });
+ }
+
+ /**
+ * Flushes events and indexes immediately. This should be called when device is powering off.
+ */
+ @MainThread
+ synchronized void saveToDisk() {
+ mEventsProtoDiskReadWriter.saveEventsImmediately(mRecentEvents);
+ mEventIndexesProtoDiskReadWriter.saveIndexesImmediately(mEventIndexArray);
}
@Override
@NonNull
- public EventIndex getEventIndex(@Event.EventType int eventType) {
+ public synchronized EventIndex getEventIndex(@Event.EventType int eventType) {
EventIndex eventIndex = mEventIndexArray.get(eventType);
return eventIndex != null ? new EventIndex(eventIndex) : mInjector.createEventIndex();
}
@Override
@NonNull
- public EventIndex getEventIndex(Set<Integer> eventTypes) {
+ public synchronized EventIndex getEventIndex(Set<Integer> eventTypes) {
EventIndex combined = mInjector.createEventIndex();
for (@Event.EventType int eventType : eventTypes) {
EventIndex eventIndex = mEventIndexArray.get(eventType);
@@ -64,29 +171,42 @@ class EventHistoryImpl implements EventHistory {
@Override
@NonNull
- public List<Event> queryEvents(Set<Integer> eventTypes, long startTime, long endTime) {
+ public synchronized List<Event> queryEvents(Set<Integer> eventTypes, long startTime,
+ long endTime) {
return mRecentEvents.queryEvents(eventTypes, startTime, endTime);
}
- void addEvent(Event event) {
- EventIndex eventIndex = mEventIndexArray.get(event.getType());
- if (eventIndex == null) {
- eventIndex = mInjector.createEventIndex();
- mEventIndexArray.put(event.getType(), eventIndex);
- }
- eventIndex.addEvent(event.getTimestamp());
- mRecentEvents.add(event);
+ synchronized void addEvent(Event event) {
+ pruneOldEvents();
+ addEventInMemory(event);
+ mEventsProtoDiskReadWriter.scheduleEventsSave(mRecentEvents);
+ mEventIndexesProtoDiskReadWriter.scheduleIndexesSave(mEventIndexArray);
}
- void onDestroy() {
+ synchronized void onDestroy() {
mEventIndexArray.clear();
mRecentEvents.clear();
- // TODO: STOPSHIP: Delete the data files.
+ mEventsProtoDiskReadWriter.deleteRecentEventsFile();
+ mEventIndexesProtoDiskReadWriter.deleteIndexesFile();
}
/** Deletes the events data that exceeds the retention period. */
- void pruneOldEvents(long currentTimeMillis) {
- // TODO: STOPSHIP: Delete the old events data files.
+ synchronized void pruneOldEvents() {
+ long currentTime = mInjector.currentTimeMillis();
+ if (currentTime - mLastPruneTime > PRUNE_OLD_EVENTS_DELAY) {
+ mRecentEvents.removeOldEvents(currentTime - MAX_EVENTS_AGE);
+ mLastPruneTime = currentTime;
+ }
+ }
+
+ private synchronized void addEventInMemory(Event event) {
+ EventIndex eventIndex = mEventIndexArray.get(event.getType());
+ if (eventIndex == null) {
+ eventIndex = mInjector.createEventIndex();
+ mEventIndexArray.put(event.getType(), eventIndex);
+ }
+ eventIndex.addEvent(event.getTimestamp());
+ mRecentEvents.add(event);
}
@VisibleForTesting
@@ -95,5 +215,174 @@ class EventHistoryImpl implements EventHistory {
EventIndex createEventIndex() {
return new EventIndex();
}
+
+ long currentTimeMillis() {
+ return System.currentTimeMillis();
+ }
+ }
+
+ /** Reads and writes {@link Event}s on disk. */
+ private static class EventsProtoDiskReadWriter extends AbstractProtoDiskReadWriter<EventList> {
+
+ private static final String TAG = EventsProtoDiskReadWriter.class.getSimpleName();
+
+ private static final String RECENT_FILE = "recent";
+
+
+ EventsProtoDiskReadWriter(@NonNull File rootDir,
+ @NonNull ScheduledExecutorService scheduledExecutorService) {
+ super(rootDir, scheduledExecutorService);
+ rootDir.mkdirs();
+ }
+
+ @Override
+ ProtoStreamWriter<EventList> protoStreamWriter() {
+ return (protoOutputStream, data) -> {
+ for (Event event : data.getAllEvents()) {
+ long token = protoOutputStream.start(PeopleEventsProto.EVENTS);
+ event.writeToProto(protoOutputStream);
+ protoOutputStream.end(token);
+ }
+ };
+ }
+
+ @Override
+ ProtoStreamReader<EventList> protoStreamReader() {
+ return protoInputStream -> {
+ List<Event> results = Lists.newArrayList();
+ try {
+ while (protoInputStream.nextField() != ProtoInputStream.NO_MORE_FIELDS) {
+ if (protoInputStream.getFieldNumber() != (int) PeopleEventsProto.EVENTS) {
+ continue;
+ }
+ long token = protoInputStream.start(PeopleEventsProto.EVENTS);
+ Event event = Event.readFromProto(protoInputStream);
+ protoInputStream.end(token);
+ results.add(event);
+ }
+ } catch (IOException e) {
+ Slog.e(TAG, "Failed to read protobuf input stream.", e);
+ }
+ EventList eventList = new EventList();
+ eventList.addAll(results);
+ return eventList;
+ };
+ }
+
+ @MainThread
+ void scheduleEventsSave(EventList recentEvents) {
+ scheduleSave(RECENT_FILE, recentEvents);
+ }
+
+ @MainThread
+ void saveEventsImmediately(EventList recentEvents) {
+ saveImmediately(RECENT_FILE, recentEvents);
+ }
+
+ /**
+ * Loads recent events from disk. This should be called when device is powered on.
+ */
+ @WorkerThread
+ @Nullable
+ EventList loadRecentEventsFromDisk() {
+ return read(RECENT_FILE);
+ }
+
+ @WorkerThread
+ void deleteRecentEventsFile() {
+ delete(RECENT_FILE);
+ }
+ }
+
+ /** Reads and writes {@link EventIndex}s on disk. */
+ private static class EventIndexesProtoDiskReadWriter extends
+ AbstractProtoDiskReadWriter<SparseArray<EventIndex>> {
+
+ private static final String TAG = EventIndexesProtoDiskReadWriter.class.getSimpleName();
+
+ private static final String INDEXES_FILE = "index";
+
+ EventIndexesProtoDiskReadWriter(@NonNull File rootDir,
+ @NonNull ScheduledExecutorService scheduledExecutorService) {
+ super(rootDir, scheduledExecutorService);
+ rootDir.mkdirs();
+ }
+
+ @Override
+ ProtoStreamWriter<SparseArray<EventIndex>> protoStreamWriter() {
+ return (protoOutputStream, data) -> {
+ for (int i = 0; i < data.size(); i++) {
+ @Event.EventType int eventType = data.keyAt(i);
+ EventIndex index = data.valueAt(i);
+ long token = protoOutputStream.start(PeopleEventIndexesProto.TYPED_INDEXES);
+ protoOutputStream.write(TypedPeopleEventIndexProto.EVENT_TYPE, eventType);
+ long indexToken = protoOutputStream.start(TypedPeopleEventIndexProto.INDEX);
+ index.writeToProto(protoOutputStream);
+ protoOutputStream.end(indexToken);
+ protoOutputStream.end(token);
+ }
+ };
+ }
+
+ @Override
+ ProtoStreamReader<SparseArray<EventIndex>> protoStreamReader() {
+ return protoInputStream -> {
+ SparseArray<EventIndex> results = new SparseArray<>();
+ try {
+ while (protoInputStream.nextField() != ProtoInputStream.NO_MORE_FIELDS) {
+ if (protoInputStream.getFieldNumber()
+ != (int) PeopleEventIndexesProto.TYPED_INDEXES) {
+ continue;
+ }
+ long token = protoInputStream.start(PeopleEventIndexesProto.TYPED_INDEXES);
+ @Event.EventType int eventType = 0;
+ EventIndex index = EventIndex.EMPTY;
+ while (protoInputStream.nextField() != ProtoInputStream.NO_MORE_FIELDS) {
+ switch (protoInputStream.getFieldNumber()) {
+ case (int) TypedPeopleEventIndexProto.EVENT_TYPE:
+ eventType = protoInputStream.readInt(
+ TypedPeopleEventIndexProto.EVENT_TYPE);
+ break;
+ case (int) TypedPeopleEventIndexProto.INDEX:
+ long indexToken = protoInputStream.start(
+ TypedPeopleEventIndexProto.INDEX);
+ index = EventIndex.readFromProto(protoInputStream);
+ protoInputStream.end(indexToken);
+ break;
+ default:
+ Slog.w(TAG, "Could not read undefined field: "
+ + protoInputStream.getFieldNumber());
+ }
+ }
+ results.append(eventType, index);
+ protoInputStream.end(token);
+ }
+ } catch (IOException e) {
+ Slog.e(TAG, "Failed to read protobuf input stream.", e);
+ }
+ return results;
+ };
+ }
+
+ @MainThread
+ void scheduleIndexesSave(SparseArray<EventIndex> indexes) {
+ scheduleSave(INDEXES_FILE, indexes);
+ }
+
+ @MainThread
+ void saveIndexesImmediately(SparseArray<EventIndex> indexes) {
+ saveImmediately(INDEXES_FILE, indexes);
+ }
+
+ @WorkerThread
+ @Nullable
+ SparseArray<EventIndex> loadIndexesFromDisk() {
+ return read(INDEXES_FILE);
+ }
+
+ @WorkerThread
+ void deleteIndexesFile() {
+ delete(INDEXES_FILE);
+ }
}
}
diff --git a/services/people/java/com/android/server/people/data/EventIndex.java b/services/people/java/com/android/server/people/data/EventIndex.java
index 069ec0e80ee4..47b620773180 100644
--- a/services/people/java/com/android/server/people/data/EventIndex.java
+++ b/services/people/java/com/android/server/people/data/EventIndex.java
@@ -21,9 +21,14 @@ import android.annotation.NonNull;
import android.annotation.Nullable;
import android.text.format.DateFormat;
import android.util.Range;
+import android.util.Slog;
+import android.util.proto.ProtoInputStream;
+import android.util.proto.ProtoOutputStream;
import com.android.internal.annotations.VisibleForTesting;
+import com.android.server.people.PeopleEventIndexProto;
+import java.io.IOException;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.time.Instant;
@@ -34,6 +39,7 @@ import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.List;
+import java.util.Objects;
import java.util.TimeZone;
import java.util.function.Function;
@@ -60,6 +66,7 @@ import java.util.function.Function;
* </pre>
*/
public class EventIndex {
+ private static final String TAG = EventIndex.class.getSimpleName();
private static final int RETENTION_DAYS = 63;
@@ -118,22 +125,23 @@ public class EventIndex {
private final Injector mInjector;
EventIndex() {
- mInjector = new Injector();
- mEventBitmaps = new long[]{0L, 0L, 0L, 0L};
- mLastUpdatedTime = mInjector.currentTimeMillis();
+ this(new Injector());
}
- EventIndex(EventIndex from) {
- mInjector = new Injector();
- mEventBitmaps = Arrays.copyOf(from.mEventBitmaps, TIME_SLOT_TYPES_COUNT);
- mLastUpdatedTime = from.mLastUpdatedTime;
+ EventIndex(@NonNull EventIndex from) {
+ this(from.mInjector, Arrays.copyOf(from.mEventBitmaps, TIME_SLOT_TYPES_COUNT),
+ from.mLastUpdatedTime);
}
@VisibleForTesting
- EventIndex(Injector injector) {
+ EventIndex(@NonNull Injector injector) {
+ this(injector, new long[]{0L, 0L, 0L, 0L}, injector.currentTimeMillis());
+ }
+
+ private EventIndex(@NonNull Injector injector, long[] eventBitmaps, long lastUpdatedTime) {
mInjector = injector;
- mEventBitmaps = new long[]{0L, 0L, 0L, 0L};
- mLastUpdatedTime = mInjector.currentTimeMillis();
+ mEventBitmaps = eventBitmaps;
+ mLastUpdatedTime = lastUpdatedTime;
}
/**
@@ -232,6 +240,31 @@ public class EventIndex {
return sb.toString();
}
+ @Override
+ public boolean equals(Object obj) {
+ if (this == obj) {
+ return true;
+ }
+ if (!(obj instanceof EventIndex)) {
+ return false;
+ }
+ EventIndex other = (EventIndex) obj;
+ return mLastUpdatedTime == other.mLastUpdatedTime
+ && Arrays.equals(mEventBitmaps, other.mEventBitmaps);
+ }
+
+ @Override
+ public int hashCode() {
+ return Objects.hash(mLastUpdatedTime, mEventBitmaps);
+ }
+
+ synchronized void writeToProto(@NonNull ProtoOutputStream protoOutputStream) {
+ for (long bitmap : mEventBitmaps) {
+ protoOutputStream.write(PeopleEventIndexProto.EVENT_BITMAPS, bitmap);
+ }
+ protoOutputStream.write(PeopleEventIndexProto.LAST_UPDATED_TIME, mLastUpdatedTime);
+ }
+
/** Shifts the event bitmaps to make them up-to-date. */
private void updateEventBitmaps(long currentTimeMillis) {
for (int slotType = 0; slotType < TIME_SLOT_TYPES_COUNT; slotType++) {
@@ -249,6 +282,28 @@ public class EventIndex {
mLastUpdatedTime = currentTimeMillis;
}
+ static EventIndex readFromProto(@NonNull ProtoInputStream protoInputStream) throws IOException {
+ int bitmapIndex = 0;
+ long[] eventBitmaps = new long[TIME_SLOT_TYPES_COUNT];
+ long lastUpdated = 0L;
+ while (protoInputStream.nextField() != ProtoInputStream.NO_MORE_FIELDS) {
+ switch (protoInputStream.getFieldNumber()) {
+ case (int) PeopleEventIndexProto.EVENT_BITMAPS:
+ eventBitmaps[bitmapIndex++] = protoInputStream.readLong(
+ PeopleEventIndexProto.EVENT_BITMAPS);
+ break;
+ case (int) PeopleEventIndexProto.LAST_UPDATED_TIME:
+ lastUpdated = protoInputStream.readLong(
+ PeopleEventIndexProto.LAST_UPDATED_TIME);
+ break;
+ default:
+ Slog.e(TAG, "Could not read undefined field: "
+ + protoInputStream.getFieldNumber());
+ }
+ }
+ return new EventIndex(new Injector(), eventBitmaps, lastUpdated);
+ }
+
private static LocalDateTime toLocalDateTime(long epochMilli) {
return LocalDateTime.ofInstant(
Instant.ofEpochMilli(epochMilli), TimeZone.getDefault().toZoneId());
diff --git a/services/people/java/com/android/server/people/data/EventList.java b/services/people/java/com/android/server/people/data/EventList.java
index d770f912ea40..3788d6c92acf 100644
--- a/services/people/java/com/android/server/people/data/EventList.java
+++ b/services/people/java/com/android/server/people/data/EventList.java
@@ -18,6 +18,8 @@ package com.android.server.people.data;
import android.annotation.NonNull;
+import com.android.internal.util.CollectionUtils;
+
import java.util.ArrayList;
import java.util.List;
import java.util.Set;
@@ -41,6 +43,16 @@ class EventList {
mEvents.add(index, event);
}
+
+ /**
+ * Call #add on each event to keep the order.
+ */
+ void addAll(@NonNull List<Event> events) {
+ for (Event event : events) {
+ add(event);
+ }
+ }
+
/**
* Returns a {@link List} of {@link Event}s whose timestamps are between the specified {@code
* fromTimestamp}, inclusive, and {@code toTimestamp} exclusive, and match the specified event
@@ -73,6 +85,44 @@ class EventList {
mEvents.clear();
}
+ /**
+ * Returns a copy of events.
+ */
+ @NonNull
+ List<Event> getAllEvents() {
+ return CollectionUtils.copyOf(mEvents);
+ }
+
+ /**
+ * Remove events that are older than the specified cut off threshold timestamp.
+ */
+ void removeOldEvents(long cutOffThreshold) {
+
+ // Everything before the cut off is considered old, and should be removed.
+ int cutOffIndex = firstIndexOnOrAfter(cutOffThreshold);
+ if (cutOffIndex == 0) {
+ return;
+ }
+
+ // Clear entire list if the cut off is greater than the last element.
+ int eventsSize = mEvents.size();
+ if (cutOffIndex == eventsSize) {
+ mEvents.clear();
+ return;
+ }
+
+ // Reorder the list starting from the cut off index.
+ int i = 0;
+ for (; cutOffIndex < eventsSize; i++, cutOffIndex++) {
+ mEvents.set(i, mEvents.get(cutOffIndex));
+ }
+
+ // Clear the list after reordering.
+ if (eventsSize > i) {
+ mEvents.subList(i, eventsSize).clear();
+ }
+ }
+
/** Returns the first index whose timestamp is greater or equal to the provided timestamp. */
private int firstIndexOnOrAfter(long timestamp) {
int result = mEvents.size();
diff --git a/services/people/java/com/android/server/people/data/EventStore.java b/services/people/java/com/android/server/people/data/EventStore.java
index c8d44ac07106..00d4241fc5f7 100644
--- a/services/people/java/com/android/server/people/data/EventStore.java
+++ b/services/people/java/com/android/server/people/data/EventStore.java
@@ -17,16 +17,22 @@
package com.android.server.people.data;
import android.annotation.IntDef;
+import android.annotation.MainThread;
import android.annotation.NonNull;
import android.annotation.Nullable;
+import android.net.Uri;
import android.util.ArrayMap;
+import com.android.internal.annotations.GuardedBy;
+
+import java.io.File;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.Set;
+import java.util.concurrent.ScheduledExecutorService;
import java.util.function.Predicate;
/** The store that stores and accesses the events data for a package. */
@@ -57,14 +63,58 @@ class EventStore {
@Retention(RetentionPolicy.SOURCE)
@interface EventCategory {}
+ @GuardedBy("this")
private final List<Map<String, EventHistoryImpl>> mEventHistoryMaps = new ArrayList<>();
+ private final List<File> mEventsCategoryDirs = new ArrayList<>();
+ private final ScheduledExecutorService mScheduledExecutorService;
- EventStore() {
+ EventStore(@NonNull File packageDir,
+ @NonNull ScheduledExecutorService scheduledExecutorService) {
mEventHistoryMaps.add(CATEGORY_SHORTCUT_BASED, new ArrayMap<>());
mEventHistoryMaps.add(CATEGORY_LOCUS_ID_BASED, new ArrayMap<>());
mEventHistoryMaps.add(CATEGORY_CALL, new ArrayMap<>());
mEventHistoryMaps.add(CATEGORY_SMS, new ArrayMap<>());
mEventHistoryMaps.add(CATEGORY_CLASS_BASED, new ArrayMap<>());
+
+ File eventDir = new File(packageDir, "event");
+ mEventsCategoryDirs.add(CATEGORY_SHORTCUT_BASED, new File(eventDir, "shortcut"));
+ mEventsCategoryDirs.add(CATEGORY_LOCUS_ID_BASED, new File(eventDir, "locus"));
+ mEventsCategoryDirs.add(CATEGORY_CALL, new File(eventDir, "call"));
+ mEventsCategoryDirs.add(CATEGORY_SMS, new File(eventDir, "sms"));
+ mEventsCategoryDirs.add(CATEGORY_CLASS_BASED, new File(eventDir, "class"));
+
+ mScheduledExecutorService = scheduledExecutorService;
+ }
+
+ /**
+ * Loads existing {@link EventHistoryImpl}s from disk. This should be called when device powers
+ * on and user is unlocked.
+ */
+ @MainThread
+ void loadFromDisk() {
+ mScheduledExecutorService.execute(() -> {
+ synchronized (this) {
+ for (@EventCategory int category = 0; category < mEventsCategoryDirs.size();
+ category++) {
+ File categoryDir = mEventsCategoryDirs.get(category);
+ Map<String, EventHistoryImpl> existingEventHistoriesImpl =
+ EventHistoryImpl.eventHistoriesImplFromDisk(categoryDir,
+ mScheduledExecutorService);
+ mEventHistoryMaps.get(category).putAll(existingEventHistoriesImpl);
+ }
+ }
+ });
+ }
+
+ /**
+ * Flushes all {@link EventHistoryImpl}s to disk. Should be called when device is shutting down.
+ */
+ synchronized void saveToDisk() {
+ for (Map<String, EventHistoryImpl> map : mEventHistoryMaps) {
+ for (EventHistoryImpl eventHistory : map.values()) {
+ eventHistory.saveToDisk();
+ }
+ }
}
/**
@@ -74,7 +124,7 @@ class EventStore {
* name.
*/
@Nullable
- EventHistory getEventHistory(@EventCategory int category, String key) {
+ synchronized EventHistory getEventHistory(@EventCategory int category, String key) {
return mEventHistoryMaps.get(category).get(key);
}
@@ -87,8 +137,11 @@ class EventStore {
* name.
*/
@NonNull
- EventHistoryImpl getOrCreateEventHistory(@EventCategory int category, String key) {
- return mEventHistoryMaps.get(category).computeIfAbsent(key, k -> new EventHistoryImpl());
+ synchronized EventHistoryImpl getOrCreateEventHistory(@EventCategory int category, String key) {
+ return mEventHistoryMaps.get(category).computeIfAbsent(key,
+ k -> new EventHistoryImpl(
+ new File(mEventsCategoryDirs.get(category), Uri.encode(key)),
+ mScheduledExecutorService));
}
/**
@@ -97,7 +150,7 @@ class EventStore {
* @param key Category-specific key, it can be shortcut ID, locus ID, phone number, or class
* name.
*/
- void deleteEventHistory(@EventCategory int category, String key) {
+ synchronized void deleteEventHistory(@EventCategory int category, String key) {
EventHistoryImpl eventHistory = mEventHistoryMaps.get(category).remove(key);
if (eventHistory != null) {
eventHistory.onDestroy();
@@ -105,16 +158,18 @@ class EventStore {
}
/** Deletes all the events and index data for the specified category from disk. */
- void deleteEventHistories(@EventCategory int category) {
+ synchronized void deleteEventHistories(@EventCategory int category) {
+ for (EventHistoryImpl eventHistory : mEventHistoryMaps.get(category).values()) {
+ eventHistory.onDestroy();
+ }
mEventHistoryMaps.get(category).clear();
- // TODO: Implement this method to delete the data from disk.
}
/** Deletes the events data that exceeds the retention period. */
- void pruneOldEvents(long currentTimeMillis) {
+ synchronized void pruneOldEvents() {
for (Map<String, EventHistoryImpl> map : mEventHistoryMaps) {
for (EventHistoryImpl eventHistory : map.values()) {
- eventHistory.pruneOldEvents(currentTimeMillis);
+ eventHistory.pruneOldEvents();
}
}
}
@@ -125,7 +180,8 @@ class EventStore {
*
* @param keyChecker Check whether there exists a conversation contains this key.
*/
- void pruneOrphanEventHistories(@EventCategory int category, Predicate<String> keyChecker) {
+ synchronized void pruneOrphanEventHistories(@EventCategory int category,
+ Predicate<String> keyChecker) {
Set<String> keys = mEventHistoryMaps.get(category).keySet();
List<String> keysToDelete = new ArrayList<>();
for (String key : keys) {
@@ -141,4 +197,12 @@ class EventStore {
}
}
}
+
+ synchronized void onDestroy() {
+ for (Map<String, EventHistoryImpl> map : mEventHistoryMaps) {
+ for (EventHistoryImpl eventHistory : map.values()) {
+ eventHistory.onDestroy();
+ }
+ }
+ }
}
diff --git a/services/people/java/com/android/server/people/data/PackageData.java b/services/people/java/com/android/server/people/data/PackageData.java
index c55f97205bc5..d47e2cc1ba90 100644
--- a/services/people/java/com/android/server/people/data/PackageData.java
+++ b/services/people/java/com/android/server/people/data/PackageData.java
@@ -27,8 +27,10 @@ import android.annotation.Nullable;
import android.annotation.UserIdInt;
import android.content.LocusId;
import android.text.TextUtils;
+import android.util.ArrayMap;
import java.io.File;
+import java.util.Map;
import java.util.concurrent.ScheduledExecutorService;
import java.util.function.Consumer;
import java.util.function.Predicate;
@@ -63,22 +65,50 @@ public class PackageData {
mUserId = userId;
mPackageDataDir = new File(perUserPeopleDataDir, mPackageName);
+ mPackageDataDir.mkdirs();
+
mConversationStore = new ConversationStore(mPackageDataDir, scheduledExecutorService,
helper);
- mEventStore = new EventStore();
+ mEventStore = new EventStore(mPackageDataDir, scheduledExecutorService);
mIsDefaultDialerPredicate = isDefaultDialerPredicate;
mIsDefaultSmsAppPredicate = isDefaultSmsAppPredicate;
}
- /** Called when user is unlocked. */
- void loadFromDisk() {
- mPackageDataDir.mkdirs();
+ /**
+ * Returns a map of package directory names as keys and their associated {@link PackageData}.
+ * This should be called when device is powered on and unlocked.
+ */
+ @NonNull
+ static Map<String, PackageData> packagesDataFromDisk(@UserIdInt int userId,
+ @NonNull Predicate<String> isDefaultDialerPredicate,
+ @NonNull Predicate<String> isDefaultSmsAppPredicate,
+ @NonNull ScheduledExecutorService scheduledExecutorService,
+ @NonNull File perUserPeopleDataDir,
+ @NonNull ContactsQueryHelper helper) {
+ Map<String, PackageData> results = new ArrayMap<>();
+ File[] packageDirs = perUserPeopleDataDir.listFiles(File::isDirectory);
+ if (packageDirs == null) {
+ return results;
+ }
+ for (File packageDir : packageDirs) {
+ PackageData packageData = new PackageData(packageDir.getName(), userId,
+ isDefaultDialerPredicate, isDefaultSmsAppPredicate, scheduledExecutorService,
+ perUserPeopleDataDir, helper);
+ packageData.loadFromDisk();
+ results.put(packageDir.getName(), packageData);
+ }
+ return results;
+ }
+
+ private void loadFromDisk() {
mConversationStore.loadConversationsFromDisk();
+ mEventStore.loadFromDisk();
}
/** Called when device is shutting down. */
void saveToDisk() {
mConversationStore.saveConversationsToDisk();
+ mEventStore.saveToDisk();
}
@NonNull
@@ -222,6 +252,7 @@ public class PackageData {
}
void onDestroy() {
- // TODO: STOPSHIP: Implements this method for the case of package being uninstalled.
+ mEventStore.onDestroy();
+ mConversationStore.onDestroy();
}
}
diff --git a/services/people/java/com/android/server/people/data/UserData.java b/services/people/java/com/android/server/people/data/UserData.java
index 7ca4b6c76a36..d3cecceed884 100644
--- a/services/people/java/com/android/server/people/data/UserData.java
+++ b/services/people/java/com/android/server/people/data/UserData.java
@@ -73,9 +73,8 @@ class UserData {
// Ensures per user root directory for people data is present, and attempt to load
// data from disk.
mPerUserPeopleDataDir.mkdirs();
- for (PackageData packageData : mPackageDataMap.values()) {
- packageData.loadFromDisk();
- }
+ mPackageDataMap.putAll(PackageData.packagesDataFromDisk(mUserId, this::isDefaultDialer,
+ this::isDefaultSmsApp, mScheduledExecutorService, mPerUserPeopleDataDir, mHelper));
}
void setUserStopped() {
diff --git a/services/people/java/com/android/server/people/prediction/AppTargetPredictor.java b/services/people/java/com/android/server/people/prediction/AppTargetPredictor.java
index 19cf8af5d66b..c89dadc3fbd6 100644
--- a/services/people/java/com/android/server/people/prediction/AppTargetPredictor.java
+++ b/services/people/java/com/android/server/people/prediction/AppTargetPredictor.java
@@ -73,6 +73,7 @@ public class AppTargetPredictor {
*/
@MainThread
public void onAppTargetEvent(AppTargetEvent event) {
+ mCallbackExecutor.execute(() -> reportAppTargetEvent(event));
}
/**
@@ -104,6 +105,11 @@ public class AppTargetPredictor {
return mUpdatePredictionsMethod;
}
+ /** To be overridden by the subclass to report app target event. */
+ @WorkerThread
+ void reportAppTargetEvent(AppTargetEvent event) {
+ }
+
/** To be overridden by the subclass to predict the targets. */
@WorkerThread
void predictTargets() {
diff --git a/services/people/java/com/android/server/people/prediction/ShareTargetPredictor.java b/services/people/java/com/android/server/people/prediction/ShareTargetPredictor.java
index 90d821641149..8e5d75be12b7 100644
--- a/services/people/java/com/android/server/people/prediction/ShareTargetPredictor.java
+++ b/services/people/java/com/android/server/people/prediction/ShareTargetPredictor.java
@@ -16,7 +16,6 @@
package com.android.server.people.prediction;
-import android.annotation.MainThread;
import android.annotation.NonNull;
import android.annotation.Nullable;
import android.annotation.UserIdInt;
@@ -28,15 +27,18 @@ import android.app.prediction.AppTargetId;
import android.content.IntentFilter;
import android.content.pm.ShortcutInfo;
import android.content.pm.ShortcutManager.ShareShortcutInfo;
+import android.util.Range;
import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.app.ChooserActivity;
import com.android.server.people.data.ConversationInfo;
import com.android.server.people.data.DataManager;
+import com.android.server.people.data.Event;
import com.android.server.people.data.EventHistory;
import com.android.server.people.data.PackageData;
import java.util.ArrayList;
+import java.util.Collections;
import java.util.List;
import java.util.function.Consumer;
@@ -52,89 +54,139 @@ class ShareTargetPredictor extends AppTargetPredictor {
ChooserActivity.APP_PREDICTION_INTENT_FILTER_KEY);
}
- @MainThread
+ /** Reports chosen history of direct/app share targets. */
+ @WorkerThread
@Override
- public void onAppTargetEvent(AppTargetEvent event) {
- getDataManager().reportAppTargetEvent(event, mIntentFilter);
+ void reportAppTargetEvent(AppTargetEvent event) {
+ getDataManager().reportShareTargetEvent(event, mIntentFilter);
}
+ /** Provides prediction on direct share targets */
@WorkerThread
@Override
- protected void predictTargets() {
- List<ShareTarget> shareTargets = getShareTargets();
- // TODO: Rank the share targets with the data in ShareTarget.mConversationData.
- List<AppTarget> appTargets = new ArrayList<>();
- for (ShareTarget shareTarget : shareTargets) {
-
- ShortcutInfo shortcutInfo = shareTarget.getShareShortcutInfo().getShortcutInfo();
- AppTargetId appTargetId = new AppTargetId(shortcutInfo.getId());
- String shareTargetClassName =
- shareTarget.getShareShortcutInfo().getTargetComponent().getClassName();
- AppTarget appTarget = new AppTarget.Builder(appTargetId, shortcutInfo)
- .setClassName(shareTargetClassName)
- .build();
- appTargets.add(appTarget);
- if (appTargets.size() >= getPredictionContext().getPredictedTargetCount()) {
- break;
- }
+ void predictTargets() {
+ List<ShareTarget> shareTargets = getDirectShareTargets();
+ rankTargets(shareTargets);
+ List<AppTarget> res = new ArrayList<>();
+ for (int i = 0; i < Math.min(getPredictionContext().getPredictedTargetCount(),
+ shareTargets.size()); i++) {
+ res.add(shareTargets.get(i).getAppTarget());
}
- updatePredictions(appTargets);
+ updatePredictions(res);
}
- @VisibleForTesting
- List<ShareTarget> getShareTargets() {
+ /** Provides prediction on app share targets */
+ @WorkerThread
+ @Override
+ void sortTargets(List<AppTarget> targets, Consumer<List<AppTarget>> callback) {
+ List<ShareTarget> shareTargets = getAppShareTargets(targets);
+ rankTargets(shareTargets);
+ List<AppTarget> appTargetList = new ArrayList<>();
+ shareTargets.forEach(t -> appTargetList.add(t.getAppTarget()));
+ callback.accept(appTargetList);
+ }
+
+ private void rankTargets(List<ShareTarget> shareTargets) {
+ // Rank targets based on recency of sharing history only for the moment.
+ // TODO: Take more factors into ranking, e.g. frequency, mime type, foreground app.
+ Collections.sort(shareTargets, (t1, t2) -> {
+ if (t1.getEventHistory() == null) {
+ return 1;
+ }
+ if (t2.getEventHistory() == null) {
+ return -1;
+ }
+ Range<Long> timeSlot1 = t1.getEventHistory().getEventIndex(
+ Event.SHARE_EVENT_TYPES).getMostRecentActiveTimeSlot();
+ Range<Long> timeSlot2 = t2.getEventHistory().getEventIndex(
+ Event.SHARE_EVENT_TYPES).getMostRecentActiveTimeSlot();
+ if (timeSlot1 == null) {
+ return 1;
+ } else if (timeSlot2 == null) {
+ return -1;
+ } else {
+ return -Long.compare(timeSlot1.getUpper(), timeSlot2.getUpper());
+ }
+ });
+ }
+
+ private List<ShareTarget> getDirectShareTargets() {
List<ShareTarget> shareTargets = new ArrayList<>();
List<ShareShortcutInfo> shareShortcuts =
getDataManager().getShareShortcuts(mIntentFilter, mCallingUserId);
for (ShareShortcutInfo shareShortcut : shareShortcuts) {
ShortcutInfo shortcutInfo = shareShortcut.getShortcutInfo();
+ AppTarget appTarget = new AppTarget.Builder(
+ new AppTargetId(shortcutInfo.getId()),
+ shortcutInfo)
+ .setClassName(shareShortcut.getTargetComponent().getClassName())
+ .build();
String packageName = shortcutInfo.getPackage();
int userId = shortcutInfo.getUserId();
PackageData packageData = getDataManager().getPackage(packageName, userId);
- ConversationData conversationData = null;
+ ConversationInfo conversationInfo = null;
+ EventHistory eventHistory = null;
if (packageData != null) {
String shortcutId = shortcutInfo.getId();
- ConversationInfo conversationInfo =
- packageData.getConversationInfo(shortcutId);
-
+ conversationInfo = packageData.getConversationInfo(shortcutId);
if (conversationInfo != null) {
- EventHistory eventHistory = packageData.getEventHistory(shortcutId);
- conversationData = new ConversationData(
- packageName, userId, conversationInfo, eventHistory);
+ eventHistory = packageData.getEventHistory(shortcutId);
}
}
- shareTargets.add(new ShareTarget(shareShortcut, conversationData));
+ shareTargets.add(new ShareTarget(appTarget, eventHistory, conversationInfo));
}
return shareTargets;
}
+ private List<ShareTarget> getAppShareTargets(List<AppTarget> targets) {
+ List<ShareTarget> shareTargets = new ArrayList<>();
+ for (AppTarget target : targets) {
+ PackageData packageData = getDataManager().getPackage(target.getPackageName(),
+ target.getUser().getIdentifier());
+ shareTargets.add(new ShareTarget(target,
+ packageData == null ? null
+ : packageData.getClassLevelEventHistory(target.getClassName()), null));
+ }
+ return shareTargets;
+ }
+
@VisibleForTesting
static class ShareTarget {
@NonNull
- private final ShareShortcutInfo mShareShortcutInfo;
+ private final AppTarget mAppTarget;
@Nullable
- private final ConversationData mConversationData;
-
- private ShareTarget(@NonNull ShareShortcutInfo shareShortcutInfo,
- @Nullable ConversationData conversationData) {
- mShareShortcutInfo = shareShortcutInfo;
- mConversationData = conversationData;
+ private final EventHistory mEventHistory;
+ @Nullable
+ private final ConversationInfo mConversationInfo;
+
+ private ShareTarget(@NonNull AppTarget appTarget,
+ @Nullable EventHistory eventHistory,
+ @Nullable ConversationInfo conversationInfo) {
+ mAppTarget = appTarget;
+ mEventHistory = eventHistory;
+ mConversationInfo = conversationInfo;
}
@NonNull
@VisibleForTesting
- ShareShortcutInfo getShareShortcutInfo() {
- return mShareShortcutInfo;
+ AppTarget getAppTarget() {
+ return mAppTarget;
+ }
+
+ @Nullable
+ @VisibleForTesting
+ EventHistory getEventHistory() {
+ return mEventHistory;
}
@Nullable
@VisibleForTesting
- ConversationData getConversationData() {
- return mConversationData;
+ ConversationInfo getConversationInfo() {
+ return mConversationInfo;
}
}
}
diff --git a/services/tests/mockingservicestests/src/com/android/server/job/controllers/JobStatusTest.java b/services/tests/mockingservicestests/src/com/android/server/job/controllers/JobStatusTest.java
index d7a3cfd8aeca..1bf9c2a0822e 100644
--- a/services/tests/mockingservicestests/src/com/android/server/job/controllers/JobStatusTest.java
+++ b/services/tests/mockingservicestests/src/com/android/server/job/controllers/JobStatusTest.java
@@ -73,7 +73,9 @@ public class JobStatusTest {
private static final double DELTA = 0.00001;
private static final String TEST_PACKAGE = "job.test.package";
private static final ComponentName TEST_JOB_COMPONENT = new ComponentName(TEST_PACKAGE, "test");
- private static final Uri TEST_MEDIA_URI = Uri.parse("content://media/path/to/media");
+
+ private static final Uri IMAGES_MEDIA_URI = MediaStore.Images.Media.EXTERNAL_CONTENT_URI;
+ private static final Uri VIDEO_MEDIA_URI = MediaStore.Video.Media.EXTERNAL_CONTENT_URI;
@Mock
private JobSchedulerInternal mJobSchedulerInternal;
@@ -127,7 +129,7 @@ public class JobStatusTest {
@Test
public void testMediaBackupExemption_lateConstraint() {
final JobInfo triggerContentJob = new JobInfo.Builder(42, TEST_JOB_COMPONENT)
- .addTriggerContentUri(new JobInfo.TriggerContentUri(TEST_MEDIA_URI, 0))
+ .addTriggerContentUri(new JobInfo.TriggerContentUri(IMAGES_MEDIA_URI, 0))
.setOverrideDeadline(12)
.setRequiredNetworkType(JobInfo.NETWORK_TYPE_ANY)
.build();
@@ -138,7 +140,7 @@ public class JobStatusTest {
@Test
public void testMediaBackupExemption_noConnectivityConstraint() {
final JobInfo triggerContentJob = new JobInfo.Builder(42, TEST_JOB_COMPONENT)
- .addTriggerContentUri(new JobInfo.TriggerContentUri(TEST_MEDIA_URI, 0))
+ .addTriggerContentUri(new JobInfo.TriggerContentUri(IMAGES_MEDIA_URI, 0))
.build();
when(mJobSchedulerInternal.getMediaBackupPackage()).thenReturn(TEST_PACKAGE);
assertEffectiveBucketForMediaExemption(createJobStatus(triggerContentJob), false);
@@ -156,7 +158,7 @@ public class JobStatusTest {
@Test
public void testMediaBackupExemption_wrongSourcePackage() {
final JobInfo networkContentJob = new JobInfo.Builder(42, TEST_JOB_COMPONENT)
- .addTriggerContentUri(new JobInfo.TriggerContentUri(TEST_MEDIA_URI, 0))
+ .addTriggerContentUri(new JobInfo.TriggerContentUri(IMAGES_MEDIA_URI, 0))
.setRequiredNetworkType(JobInfo.NETWORK_TYPE_ANY)
.build();
when(mJobSchedulerInternal.getMediaBackupPackage()).thenReturn("not.test.package");
@@ -164,11 +166,12 @@ public class JobStatusTest {
}
@Test
- public void testMediaBackupExemption_nonMediaUri() {
- final Uri nonMediaUri = Uri.parse("content://not-media/any/path");
+ public void testMediaBackupExemption_nonEligibleUri() {
+ final Uri nonEligibleUri = MediaStore.AUTHORITY_URI.buildUpon()
+ .appendPath("any_path").build();
final JobInfo networkContentJob = new JobInfo.Builder(42, TEST_JOB_COMPONENT)
- .addTriggerContentUri(new JobInfo.TriggerContentUri(TEST_MEDIA_URI, 0))
- .addTriggerContentUri(new JobInfo.TriggerContentUri(nonMediaUri, 0))
+ .addTriggerContentUri(new JobInfo.TriggerContentUri(IMAGES_MEDIA_URI, 0))
+ .addTriggerContentUri(new JobInfo.TriggerContentUri(nonEligibleUri, 0))
.setRequiredNetworkType(JobInfo.NETWORK_TYPE_ANY)
.build();
when(mJobSchedulerInternal.getMediaBackupPackage()).thenReturn(TEST_PACKAGE);
@@ -177,12 +180,25 @@ public class JobStatusTest {
@Test
public void testMediaBackupExemptionGranted() {
- final JobInfo networkContentJob = new JobInfo.Builder(42, TEST_JOB_COMPONENT)
- .addTriggerContentUri(new JobInfo.TriggerContentUri(TEST_MEDIA_URI, 0))
+ when(mJobSchedulerInternal.getMediaBackupPackage()).thenReturn(TEST_PACKAGE);
+ final JobInfo imageUriJob = new JobInfo.Builder(42, TEST_JOB_COMPONENT)
+ .addTriggerContentUri(new JobInfo.TriggerContentUri(IMAGES_MEDIA_URI, 0))
.setRequiredNetworkType(JobInfo.NETWORK_TYPE_ANY)
.build();
- when(mJobSchedulerInternal.getMediaBackupPackage()).thenReturn(TEST_PACKAGE);
- assertEffectiveBucketForMediaExemption(createJobStatus(networkContentJob), true);
+ assertEffectiveBucketForMediaExemption(createJobStatus(imageUriJob), true);
+
+ final JobInfo videoUriJob = new JobInfo.Builder(42, TEST_JOB_COMPONENT)
+ .addTriggerContentUri(new JobInfo.TriggerContentUri(VIDEO_MEDIA_URI, 0))
+ .setRequiredNetworkType(JobInfo.NETWORK_TYPE_ANY)
+ .build();
+ assertEffectiveBucketForMediaExemption(createJobStatus(videoUriJob), true);
+
+ final JobInfo bothUriJob = new JobInfo.Builder(42, TEST_JOB_COMPONENT)
+ .addTriggerContentUri(new JobInfo.TriggerContentUri(IMAGES_MEDIA_URI, 0))
+ .addTriggerContentUri(new JobInfo.TriggerContentUri(VIDEO_MEDIA_URI, 0))
+ .setRequiredNetworkType(JobInfo.NETWORK_TYPE_ANY)
+ .build();
+ assertEffectiveBucketForMediaExemption(createJobStatus(bothUriJob), true);
}
@Test
diff --git a/services/tests/servicestests/src/com/android/server/display/DisplayModeDirectorTest.java b/services/tests/servicestests/src/com/android/server/display/DisplayModeDirectorTest.java
index 25d077823a3f..feae1e173f52 100644
--- a/services/tests/servicestests/src/com/android/server/display/DisplayModeDirectorTest.java
+++ b/services/tests/servicestests/src/com/android/server/display/DisplayModeDirectorTest.java
@@ -29,6 +29,12 @@ import androidx.test.InstrumentationRegistry;
import androidx.test.filters.SmallTest;
import androidx.test.runner.AndroidJUnit4;
+import com.android.server.display.DisplayModeDirector.DesiredDisplayModeSpecs;
+import com.android.server.display.DisplayModeDirector.RefreshRateRange;
+import com.android.server.display.DisplayModeDirector.Vote;
+
+import com.google.common.truth.Truth;
+
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
@@ -37,6 +43,9 @@ import org.mockito.MockitoAnnotations;
@SmallTest
@RunWith(AndroidJUnit4.class)
public class DisplayModeDirectorTest {
+ // The tolerance within which we consider something approximately equals.
+ private static final float FLOAT_TOLERANCE = 0.01f;
+
private Context mContext;
@Before
@@ -56,30 +65,22 @@ public class DisplayModeDirectorTest {
modes[i - minFps] = new Display.Mode(
/*modeId=*/i, /*width=*/1000, /*height=*/1000, /*refreshRate=*/i);
}
- SparseArray<Display.Mode[]> supportedModesByDisplay = new SparseArray<Display.Mode[]>();
+ SparseArray<Display.Mode[]> supportedModesByDisplay = new SparseArray<>();
supportedModesByDisplay.put(displayId, modes);
director.injectSupportedModesByDisplay(supportedModesByDisplay);
- SparseArray<Display.Mode> defaultModesByDisplay = new SparseArray<Display.Mode>();
+ SparseArray<Display.Mode> defaultModesByDisplay = new SparseArray<>();
defaultModesByDisplay.put(displayId, modes[0]);
director.injectDefaultModeByDisplay(defaultModesByDisplay);
return director;
}
- private int[] intRange(int min, int max) {
- int[] range = new int[max - min + 1];
- for (int i = min; i <= max; i++) {
- range[i - min] = i;
- }
- return range;
- }
-
@Test
public void testDisplayModeVoting() {
int displayId = 0;
// With no votes present, DisplayModeDirector should allow any refresh rate.
- assertEquals(new DisplayModeDirector.DesiredDisplayModeSpecs(/*baseModeId=*/60,
- new DisplayModeDirector.RefreshRateRange(0f, Float.POSITIVE_INFINITY)),
+ assertEquals(new DesiredDisplayModeSpecs(/*baseModeId=*/60,
+ new RefreshRateRange(0f, Float.POSITIVE_INFINITY)),
createDisplayModeDirectorWithDisplayFpsRange(60, 90).getDesiredDisplayModeSpecs(
displayId));
@@ -93,20 +94,16 @@ public class DisplayModeDirectorTest {
int maxFps = 90;
DisplayModeDirector director = createDisplayModeDirectorWithDisplayFpsRange(60, 90);
assertTrue(2 * numPriorities < maxFps - minFps + 1);
- SparseArray<DisplayModeDirector.Vote> votes =
- new SparseArray<DisplayModeDirector.Vote>();
- SparseArray<SparseArray<DisplayModeDirector.Vote>> votesByDisplay =
- new SparseArray<SparseArray<DisplayModeDirector.Vote>>();
+ SparseArray<Vote> votes = new SparseArray<>();
+ SparseArray<SparseArray<Vote>> votesByDisplay = new SparseArray<>();
votesByDisplay.put(displayId, votes);
for (int i = 0; i < numPriorities; i++) {
- int priority = DisplayModeDirector.Vote.MIN_PRIORITY + i;
- votes.put(
- priority, DisplayModeDirector.Vote.forRefreshRates(minFps + i, maxFps - i));
+ int priority = Vote.MIN_PRIORITY + i;
+ votes.put(priority, Vote.forRefreshRates(minFps + i, maxFps - i));
director.injectVotesByDisplay(votesByDisplay);
- assertEquals(
- new DisplayModeDirector.DesiredDisplayModeSpecs(
+ assertEquals(new DesiredDisplayModeSpecs(
/*baseModeId=*/minFps + i,
- new DisplayModeDirector.RefreshRateRange(minFps + i, maxFps - i)),
+ new RefreshRateRange(minFps + i, maxFps - i)),
director.getDesiredDisplayModeSpecs(displayId));
}
}
@@ -116,19 +113,35 @@ public class DisplayModeDirectorTest {
{
assertTrue(numPriorities >= 2);
DisplayModeDirector director = createDisplayModeDirectorWithDisplayFpsRange(60, 90);
- SparseArray<DisplayModeDirector.Vote> votes =
- new SparseArray<DisplayModeDirector.Vote>();
- SparseArray<SparseArray<DisplayModeDirector.Vote>> votesByDisplay =
- new SparseArray<SparseArray<DisplayModeDirector.Vote>>();
+ SparseArray<Vote> votes = new SparseArray<>();
+ SparseArray<SparseArray<Vote>> votesByDisplay = new SparseArray<>();
votesByDisplay.put(displayId, votes);
- votes.put(DisplayModeDirector.Vote.MAX_PRIORITY,
- DisplayModeDirector.Vote.forRefreshRates(65, 85));
- votes.put(DisplayModeDirector.Vote.MIN_PRIORITY,
- DisplayModeDirector.Vote.forRefreshRates(70, 80));
+ votes.put(Vote.MAX_PRIORITY, Vote.forRefreshRates(65, 85));
+ votes.put(Vote.MIN_PRIORITY, Vote.forRefreshRates(70, 80));
director.injectVotesByDisplay(votesByDisplay);
- assertEquals(new DisplayModeDirector.DesiredDisplayModeSpecs(/*baseModeId=*/70,
- new DisplayModeDirector.RefreshRateRange(70, 80)),
+ assertEquals(new DesiredDisplayModeSpecs(/*baseModeId=*/70,
+ new RefreshRateRange(70, 80)),
director.getDesiredDisplayModeSpecs(displayId));
}
}
+
+ @Test
+ public void testVotingWithFloatingPointErrors() {
+ int displayId = 0;
+ DisplayModeDirector director = createDisplayModeDirectorWithDisplayFpsRange(50, 90);
+ SparseArray<Vote> votes = new SparseArray<>();
+ SparseArray<SparseArray<Vote>> votesByDisplay = new SparseArray<>();
+ votesByDisplay.put(displayId, votes);
+ float error = FLOAT_TOLERANCE / 4;
+ votes.put(Vote.PRIORITY_USER_SETTING_PEAK_REFRESH_RATE, Vote.forRefreshRates(0, 60));
+ votes.put(Vote.PRIORITY_APP_REQUEST_SIZE, Vote.forRefreshRates(60 + error, 60 + error));
+ votes.put(Vote.PRIORITY_APP_REQUEST_REFRESH_RATE,
+ Vote.forRefreshRates(60 - error, 60 - error));
+ director.injectVotesByDisplay(votesByDisplay);
+ DesiredDisplayModeSpecs desiredSpecs = director.getDesiredDisplayModeSpecs(displayId);
+
+ Truth.assertThat(desiredSpecs.refreshRateRange.min).isWithin(FLOAT_TOLERANCE).of(60);
+ Truth.assertThat(desiredSpecs.refreshRateRange.max).isWithin(FLOAT_TOLERANCE).of(60);
+ Truth.assertThat(desiredSpecs.baseModeId).isEqualTo(60);
+ }
}
diff --git a/services/tests/servicestests/src/com/android/server/location/MockableLocationProviderTest.java b/services/tests/servicestests/src/com/android/server/location/MockableLocationProviderTest.java
index 6fafe113d90d..9b076e8edb52 100644
--- a/services/tests/servicestests/src/com/android/server/location/MockableLocationProviderTest.java
+++ b/services/tests/servicestests/src/com/android/server/location/MockableLocationProviderTest.java
@@ -118,16 +118,6 @@ public class MockableLocationProviderTest {
}
@Test
- public void testRequestSetAllowed() {
- mProvider.requestSetAllowed(true);
- verify(mRealProvider, times(1)).onRequestSetAllowed(true);
-
- mProvider.setMockProvider(mMockProvider);
- mProvider.requestSetAllowed(true);
- verify(mMockProvider, times(1)).onRequestSetAllowed(true);
- }
-
- @Test
public void testSendExtraCommand() {
mProvider.sendExtraCommand(0, 0, "command", null);
verify(mRealProvider, times(1)).onExtraCommand(0, 0, "command", null);
diff --git a/services/tests/servicestests/src/com/android/server/location/test/FakeProvider.java b/services/tests/servicestests/src/com/android/server/location/test/FakeProvider.java
index 762080fe5745..5943f67494f8 100644
--- a/services/tests/servicestests/src/com/android/server/location/test/FakeProvider.java
+++ b/services/tests/servicestests/src/com/android/server/location/test/FakeProvider.java
@@ -38,8 +38,5 @@ public class FakeProvider extends AbstractLocationProvider {
protected void onExtraCommand(int uid, int pid, String command, Bundle extras) {}
@Override
- protected void onRequestSetAllowed(boolean allowed) {}
-
- @Override
public void dump(FileDescriptor fd, PrintWriter pw, String[] args) {}
}
diff --git a/services/tests/servicestests/src/com/android/server/people/data/AggregateEventHistoryImplTest.java b/services/tests/servicestests/src/com/android/server/people/data/AggregateEventHistoryImplTest.java
index b614a4f91d28..443718d94be6 100644
--- a/services/tests/servicestests/src/com/android/server/people/data/AggregateEventHistoryImplTest.java
+++ b/services/tests/servicestests/src/com/android/server/people/data/AggregateEventHistoryImplTest.java
@@ -21,11 +21,16 @@ import static com.android.server.people.data.TestUtils.timestamp;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertTrue;
+import android.content.Context;
+
+import androidx.test.InstrumentationRegistry;
+
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.junit.runners.JUnit4;
+import java.io.File;
import java.util.List;
@RunWith(JUnit4.class)
@@ -60,11 +65,16 @@ public final class AggregateEventHistoryImplTest {
EventHistoryImpl.Injector injector = new EventHistoryImplInjector();
- mEventHistory1 = new EventHistoryImpl(injector);
+ Context ctx = InstrumentationRegistry.getContext();
+ File testDir = new File(ctx.getCacheDir(), "testdir");
+ MockScheduledExecutorService mockScheduledExecutorService =
+ new MockScheduledExecutorService();
+
+ mEventHistory1 = new EventHistoryImpl(injector, testDir, mockScheduledExecutorService);
mEventHistory1.addEvent(E1);
mEventHistory1.addEvent(E2);
- mEventHistory2 = new EventHistoryImpl(injector);
+ mEventHistory2 = new EventHistoryImpl(injector, testDir, mockScheduledExecutorService);
mEventHistory2.addEvent(E3);
mEventHistory2.addEvent(E4);
}
diff --git a/services/tests/servicestests/src/com/android/server/people/data/DataManagerTest.java b/services/tests/servicestests/src/com/android/server/people/data/DataManagerTest.java
index f73a4b5776b6..b54317b768c5 100644
--- a/services/tests/servicestests/src/com/android/server/people/data/DataManagerTest.java
+++ b/services/tests/servicestests/src/com/android/server/people/data/DataManagerTest.java
@@ -100,6 +100,7 @@ public final class DataManagerTest {
private static final int USER_ID_PRIMARY_MANAGED = 10;
private static final int USER_ID_SECONDARY = 11;
private static final String TEST_PKG_NAME = "pkg";
+ private static final String TEST_CLASS_NAME = "class";
private static final String TEST_SHORTCUT_ID = "sc";
private static final String CONTACT_URI = "content://com.android.contacts/contacts/lookup/123";
private static final String PHONE_NUMBER = "+1234567890";
@@ -206,13 +207,13 @@ public final class DataManagerTest {
mDataManager.onUserUnlocked(USER_ID_PRIMARY_MANAGED);
mDataManager.onUserUnlocked(USER_ID_SECONDARY);
- mDataManager.onShortcutAddedOrUpdated(
+ mDataManager.addOrUpdateConversationInfo(
buildShortcutInfo("pkg_1", USER_ID_PRIMARY, "sc_1",
buildPerson(true, false)));
- mDataManager.onShortcutAddedOrUpdated(
+ mDataManager.addOrUpdateConversationInfo(
buildShortcutInfo("pkg_2", USER_ID_PRIMARY_MANAGED, "sc_2",
buildPerson(false, true)));
- mDataManager.onShortcutAddedOrUpdated(
+ mDataManager.addOrUpdateConversationInfo(
buildShortcutInfo("pkg_3", USER_ID_SECONDARY, "sc_3", buildPerson()));
List<ConversationInfo> conversations = getConversationsInPrimary();
@@ -236,9 +237,9 @@ public final class DataManagerTest {
@Test
public void testAccessConversationForUnlockedUsersOnly() {
mDataManager.onUserUnlocked(USER_ID_PRIMARY);
- mDataManager.onShortcutAddedOrUpdated(
+ mDataManager.addOrUpdateConversationInfo(
buildShortcutInfo("pkg_1", USER_ID_PRIMARY, "sc_1", buildPerson()));
- mDataManager.onShortcutAddedOrUpdated(
+ mDataManager.addOrUpdateConversationInfo(
buildShortcutInfo("pkg_2", USER_ID_PRIMARY_MANAGED, "sc_2", buildPerson()));
List<ConversationInfo> conversations = getConversationsInPrimary();
@@ -261,11 +262,12 @@ public final class DataManagerTest {
}
@Test
- public void testReportAppTargetEvent() throws IntentFilter.MalformedMimeTypeException {
+ public void testReportAppTargetEvent_directSharing()
+ throws IntentFilter.MalformedMimeTypeException {
mDataManager.onUserUnlocked(USER_ID_PRIMARY);
ShortcutInfo shortcut = buildShortcutInfo(TEST_PKG_NAME, USER_ID_PRIMARY, TEST_SHORTCUT_ID,
buildPerson());
- mDataManager.onShortcutAddedOrUpdated(shortcut);
+ mDataManager.addOrUpdateConversationInfo(shortcut);
AppTarget appTarget = new AppTarget.Builder(new AppTargetId(TEST_SHORTCUT_ID), shortcut)
.build();
@@ -274,7 +276,55 @@ public final class DataManagerTest {
.setLaunchLocation(ChooserActivity.LAUNCH_LOCATON_DIRECT_SHARE)
.build();
IntentFilter intentFilter = new IntentFilter(Intent.ACTION_SEND, "image/jpg");
- mDataManager.reportAppTargetEvent(appTargetEvent, intentFilter);
+ mDataManager.reportShareTargetEvent(appTargetEvent, intentFilter);
+
+ List<Range<Long>> activeShareTimeSlots = getActiveSlotsForTestShortcut(
+ Event.SHARE_EVENT_TYPES);
+ assertEquals(1, activeShareTimeSlots.size());
+ }
+
+ @Test
+ public void testReportAppTargetEvent_directSharing_createConversation()
+ throws IntentFilter.MalformedMimeTypeException {
+ mDataManager.onUserUnlocked(USER_ID_PRIMARY);
+ ShortcutInfo shortcut = buildShortcutInfo(TEST_PKG_NAME, USER_ID_PRIMARY, TEST_SHORTCUT_ID,
+ null);
+ AppTarget appTarget = new AppTarget.Builder(new AppTargetId(TEST_SHORTCUT_ID), shortcut)
+ .build();
+ AppTargetEvent appTargetEvent =
+ new AppTargetEvent.Builder(appTarget, AppTargetEvent.ACTION_LAUNCH)
+ .setLaunchLocation(ChooserActivity.LAUNCH_LOCATON_DIRECT_SHARE)
+ .build();
+ IntentFilter intentFilter = new IntentFilter(Intent.ACTION_SEND, "image/jpg");
+
+ mDataManager.reportShareTargetEvent(appTargetEvent, intentFilter);
+
+ List<Range<Long>> activeShareTimeSlots = getActiveSlotsForTestShortcut(
+ Event.SHARE_EVENT_TYPES);
+ assertEquals(1, activeShareTimeSlots.size());
+ ConversationInfo conversationInfo = mDataManager.getPackage(TEST_PKG_NAME, USER_ID_PRIMARY)
+ .getConversationStore()
+ .getConversation(TEST_SHORTCUT_ID);
+ assertNotNull(conversationInfo);
+ assertEquals(conversationInfo.getShortcutId(), TEST_SHORTCUT_ID);
+ }
+
+ @Test
+ public void testReportAppTargetEvent_appSharing()
+ throws IntentFilter.MalformedMimeTypeException {
+ mDataManager.onUserUnlocked(USER_ID_PRIMARY);
+ AppTarget appTarget = new AppTarget.Builder(
+ new AppTargetId(TEST_SHORTCUT_ID),
+ TEST_PKG_NAME,
+ UserHandle.of(USER_ID_PRIMARY))
+ .setClassName(TEST_CLASS_NAME)
+ .build();
+ AppTargetEvent appTargetEvent =
+ new AppTargetEvent.Builder(appTarget, AppTargetEvent.ACTION_LAUNCH)
+ .build();
+ IntentFilter intentFilter = new IntentFilter(Intent.ACTION_SEND, "image/jpg");
+
+ mDataManager.reportShareTargetEvent(appTargetEvent, intentFilter);
List<Range<Long>> activeShareTimeSlots = getActiveSlotsForTestShortcut(
Event.SHARE_EVENT_TYPES);
@@ -288,7 +338,7 @@ public final class DataManagerTest {
ShortcutInfo shortcut = buildShortcutInfo(TEST_PKG_NAME, USER_ID_PRIMARY, TEST_SHORTCUT_ID,
buildPerson());
- mDataManager.onShortcutAddedOrUpdated(shortcut);
+ mDataManager.addOrUpdateConversationInfo(shortcut);
final String newPhoneNumber = "+1000000000";
mInjector.mContactsQueryHelper.mIsStarred = true;
@@ -312,7 +362,7 @@ public final class DataManagerTest {
ShortcutInfo shortcut = buildShortcutInfo(TEST_PKG_NAME, USER_ID_PRIMARY, TEST_SHORTCUT_ID,
buildPerson());
- mDataManager.onShortcutAddedOrUpdated(shortcut);
+ mDataManager.addOrUpdateConversationInfo(shortcut);
NotificationListenerService listenerService =
mDataManager.getNotificationListenerServiceForTesting(USER_ID_PRIMARY);
@@ -330,7 +380,7 @@ public final class DataManagerTest {
ShortcutInfo shortcut = buildShortcutInfo(TEST_PKG_NAME, USER_ID_PRIMARY, TEST_SHORTCUT_ID,
buildPerson());
- mDataManager.onShortcutAddedOrUpdated(shortcut);
+ mDataManager.addOrUpdateConversationInfo(shortcut);
NotificationListenerService listenerService =
mDataManager.getNotificationListenerServiceForTesting(USER_ID_PRIMARY);
@@ -350,7 +400,7 @@ public final class DataManagerTest {
ShortcutInfo shortcut = buildShortcutInfo(TEST_PKG_NAME, USER_ID_PRIMARY, TEST_SHORTCUT_ID,
buildPerson());
- mDataManager.onShortcutAddedOrUpdated(shortcut);
+ mDataManager.addOrUpdateConversationInfo(shortcut);
NotificationListenerService listenerService =
mDataManager.getNotificationListenerServiceForTesting(USER_ID_PRIMARY);
@@ -375,7 +425,7 @@ public final class DataManagerTest {
ShortcutInfo shortcut = buildShortcutInfo(TEST_PKG_NAME, USER_ID_PRIMARY, TEST_SHORTCUT_ID,
buildPerson());
- mDataManager.onShortcutAddedOrUpdated(shortcut);
+ mDataManager.addOrUpdateConversationInfo(shortcut);
NotificationListenerService listenerService =
mDataManager.getNotificationListenerServiceForTesting(USER_ID_PRIMARY);
@@ -401,7 +451,7 @@ public final class DataManagerTest {
ShortcutInfo shortcut = buildShortcutInfo(TEST_PKG_NAME, USER_ID_PRIMARY, TEST_SHORTCUT_ID,
buildPerson());
- mDataManager.onShortcutAddedOrUpdated(shortcut);
+ mDataManager.addOrUpdateConversationInfo(shortcut);
NotificationListenerService listenerService =
mDataManager.getNotificationListenerServiceForTesting(USER_ID_PRIMARY);
@@ -430,7 +480,7 @@ public final class DataManagerTest {
ShortcutInfo shortcut = buildShortcutInfo(TEST_PKG_NAME, USER_ID_PRIMARY, TEST_SHORTCUT_ID,
buildPerson());
- mDataManager.onShortcutAddedOrUpdated(shortcut);
+ mDataManager.addOrUpdateConversationInfo(shortcut);
ContentObserver contentObserver = mDataManager.getCallLogContentObserverForTesting();
contentObserver.onChange(false);
@@ -453,7 +503,7 @@ public final class DataManagerTest {
ShortcutInfo shortcut = buildShortcutInfo(TEST_PKG_NAME, USER_ID_PRIMARY, TEST_SHORTCUT_ID,
buildPerson());
- mDataManager.onShortcutAddedOrUpdated(shortcut);
+ mDataManager.addOrUpdateConversationInfo(shortcut);
mDataManager.getUserDataForTesting(USER_ID_PRIMARY).setDefaultSmsApp(TEST_PKG_NAME);
ContentObserver contentObserver = mDataManager.getMmsSmsContentObserverForTesting();
@@ -476,7 +526,7 @@ public final class DataManagerTest {
ShortcutInfo shortcut = buildShortcutInfo(TEST_PKG_NAME, USER_ID_PRIMARY, TEST_SHORTCUT_ID,
buildPerson());
- mDataManager.onShortcutAddedOrUpdated(shortcut);
+ mDataManager.addOrUpdateConversationInfo(shortcut);
assertNotNull(mDataManager.getPackage(TEST_PKG_NAME, USER_ID_PRIMARY));
PackageMonitor packageMonitor = mDataManager.getPackageMonitorForTesting(USER_ID_PRIMARY);
@@ -493,7 +543,7 @@ public final class DataManagerTest {
ShortcutInfo shortcut = buildShortcutInfo(TEST_PKG_NAME, USER_ID_PRIMARY, TEST_SHORTCUT_ID,
buildPerson());
- mDataManager.onShortcutAddedOrUpdated(shortcut);
+ mDataManager.addOrUpdateConversationInfo(shortcut);
assertNotNull(mDataManager.getPackage(TEST_PKG_NAME, USER_ID_PRIMARY));
doAnswer(ans -> null).when(mPackageManagerInternal)
@@ -508,7 +558,7 @@ public final class DataManagerTest {
ShortcutInfo shortcut = buildShortcutInfo(TEST_PKG_NAME, USER_ID_PRIMARY, TEST_SHORTCUT_ID,
buildPerson());
- mDataManager.onShortcutAddedOrUpdated(shortcut);
+ mDataManager.addOrUpdateConversationInfo(shortcut);
long currentTimestamp = System.currentTimeMillis();
mInjector.mCallLogQueryHelper.mEventConsumer.accept(PHONE_NUMBER,
@@ -529,7 +579,7 @@ public final class DataManagerTest {
ShortcutInfo shortcut = buildShortcutInfo(TEST_PKG_NAME, USER_ID_PRIMARY, TEST_SHORTCUT_ID,
buildPerson());
- mDataManager.onShortcutAddedOrUpdated(shortcut);
+ mDataManager.addOrUpdateConversationInfo(shortcut);
mDataManager.getUserDataForTesting(USER_ID_PRIMARY).setDefaultSmsApp(TEST_PKG_NAME);
long currentTimestamp = System.currentTimeMillis();
diff --git a/services/tests/servicestests/src/com/android/server/people/data/EventHistoryImplTest.java b/services/tests/servicestests/src/com/android/server/people/data/EventHistoryImplTest.java
index 43e1001f2aee..825ca1065e73 100644
--- a/services/tests/servicestests/src/com/android/server/people/data/EventHistoryImplTest.java
+++ b/services/tests/servicestests/src/com/android/server/people/data/EventHistoryImplTest.java
@@ -21,18 +21,27 @@ import static com.android.server.people.data.TestUtils.timestamp;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertTrue;
+import android.content.Context;
+import android.os.FileUtils;
+import android.text.format.DateUtils;
+
+import androidx.test.InstrumentationRegistry;
+
+import com.google.android.collect.Lists;
import com.google.android.collect.Sets;
+import org.junit.After;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.junit.runners.JUnit4;
+import java.io.File;
import java.util.List;
+import java.util.Map;
@RunWith(JUnit4.class)
public final class EventHistoryImplTest {
-
private static final long CURRENT_TIMESTAMP = timestamp("01-30 18:50");
private static final Event E1 = new Event(timestamp("01-06 05:26"),
@@ -41,26 +50,48 @@ public final class EventHistoryImplTest {
Event.TYPE_NOTIFICATION_OPENED);
private static final Event E3 = new Event(timestamp("01-30 03:06"),
Event.TYPE_SHARE_IMAGE);
- private static final Event E4 = new Event(timestamp("01-30 18:14"),
+ private static final Event E4 = new Event(timestamp("01-30 16:14"),
+ Event.TYPE_SMS_INCOMING);
+ private static final Event E5 = new Event(timestamp("01-30 18:30"),
Event.TYPE_SMS_INCOMING);
+ private static final EventIndex.Injector EVENT_INDEX_INJECTOR = new EventIndex.Injector() {
+ @Override
+ long currentTimeMillis() {
+ return CURRENT_TIMESTAMP;
+ }
+ };
+ private static final EventHistoryImpl.Injector EVENT_HISTORY_INJECTOR =
+ new EventHistoryImpl.Injector() {
+ @Override
+ EventIndex createEventIndex() {
+ return new EventIndex(EVENT_INDEX_INJECTOR);
+ }
+
+ @Override
+ long currentTimeMillis() {
+ return CURRENT_TIMESTAMP;
+ }
+ };
+
private EventHistoryImpl mEventHistory;
+ private File mCacheDir;
+ private File mFile;
+ private MockScheduledExecutorService mMockScheduledExecutorService;
@Before
public void setUp() {
- EventIndex.Injector eventIndexInjector = new EventIndex.Injector() {
- @Override
- long currentTimeMillis() {
- return CURRENT_TIMESTAMP;
- }
- };
- EventHistoryImpl.Injector eventHistoryInjector = new EventHistoryImpl.Injector() {
- @Override
- EventIndex createEventIndex() {
- return new EventIndex(eventIndexInjector);
- }
- };
- mEventHistory = new EventHistoryImpl(eventHistoryInjector);
+ Context ctx = InstrumentationRegistry.getContext();
+ mCacheDir = ctx.getCacheDir();
+ mFile = new File(mCacheDir, "testdir");
+ mMockScheduledExecutorService = new MockScheduledExecutorService();
+ mEventHistory = new EventHistoryImpl(EVENT_HISTORY_INJECTOR, mFile,
+ mMockScheduledExecutorService);
+ }
+
+ @After
+ public void tearDown() {
+ FileUtils.deleteContentsAndDir(mFile);
}
@Test
@@ -115,4 +146,105 @@ public final class EventHistoryImplTest {
Sets.newArraySet(Event.TYPE_SHARE_IMAGE), 0L, Long.MAX_VALUE);
assertEquals(1, events.size());
}
+
+ @Test
+ public void testPersistenceAndRestoration() {
+ mEventHistory.addEvent(E1);
+ mEventHistory.addEvent(E2);
+ mEventHistory.addEvent(E3);
+ mEventHistory.addEvent(E4);
+ mEventHistory.addEvent(E5);
+
+ // futures of events and event index flush.
+ long futuresExecuted = mMockScheduledExecutorService.fastForwardTime(
+ 3L * DateUtils.MINUTE_IN_MILLIS);
+ assertEquals(2, futuresExecuted);
+
+ EventIndex indexBeforePowerOff = mEventHistory.getEventIndex(Event.ALL_EVENT_TYPES);
+
+ resetAndLoadEventHistory();
+
+ List<Event> events = mEventHistory.queryEvents(Event.ALL_EVENT_TYPES, 0L, Long.MAX_VALUE);
+ assertEquals(2, events.size());
+ assertTrue(events.containsAll(Lists.newArrayList(E4, E5)));
+
+ EventIndex indexAfterPowerOff = mEventHistory.getEventIndex(Event.ALL_EVENT_TYPES);
+ assertEquals(indexBeforePowerOff, indexAfterPowerOff);
+ }
+
+ @Test
+ public void testMimicDevicePowerOff() {
+ mEventHistory.addEvent(E1);
+ mEventHistory.addEvent(E2);
+ mEventHistory.addEvent(E3);
+ mEventHistory.addEvent(E4);
+ mEventHistory.addEvent(E5);
+ mEventHistory.saveToDisk();
+
+ EventIndex indexBeforePowerOff = mEventHistory.getEventIndex(Event.ALL_EVENT_TYPES);
+
+ // Ensure that futures were cancelled and the immediate flush occurred.
+ assertEquals(0, mMockScheduledExecutorService.getFutures().size());
+
+ // Expect to see 2 executes from #saveToDisk, one for events and another for index.
+ assertEquals(2, mMockScheduledExecutorService.getExecutes().size());
+
+ resetAndLoadEventHistory();
+
+ List<Event> events = mEventHistory.queryEvents(Event.ALL_EVENT_TYPES, 0L, Long.MAX_VALUE);
+ assertEquals(2, events.size());
+ assertTrue(events.containsAll(Lists.newArrayList(E4, E5)));
+
+ EventIndex indexAfterPowerOff = mEventHistory.getEventIndex(Event.ALL_EVENT_TYPES);
+ assertEquals(indexBeforePowerOff, indexAfterPowerOff);
+ }
+
+ @Test
+ public void testOnDestroy() {
+ mEventHistory.addEvent(E1);
+ mEventHistory.addEvent(E2);
+ mEventHistory.addEvent(E3);
+ mEventHistory.addEvent(E4);
+ mEventHistory.addEvent(E5);
+ mEventHistory.saveToDisk();
+
+ mEventHistory.onDestroy();
+
+ List<Event> events = mEventHistory.queryEvents(Event.ALL_EVENT_TYPES, 0L, Long.MAX_VALUE);
+ assertTrue(events.isEmpty());
+
+ EventIndex index = mEventHistory.getEventIndex(Event.ALL_EVENT_TYPES);
+ assertTrue(index.isEmpty());
+ }
+
+ @Test
+ public void testEventHistoriesImplFromDisk() {
+ mEventHistory.addEvent(E1);
+ mEventHistory.addEvent(E2);
+ mEventHistory.addEvent(E3);
+ mEventHistory.addEvent(E4);
+ mEventHistory.addEvent(E5);
+ mEventHistory.saveToDisk();
+
+ EventIndex indexBefore = mEventHistory.getEventIndex(Event.ALL_EVENT_TYPES);
+
+ Map<String, EventHistoryImpl> map = EventHistoryImpl.eventHistoriesImplFromDisk(
+ EVENT_HISTORY_INJECTOR, mCacheDir, mMockScheduledExecutorService);
+ assertEquals(1, map.size());
+ assertTrue(map.containsKey("testdir"));
+
+ List<Event> events = map.get("testdir").queryEvents(Event.ALL_EVENT_TYPES, 0L,
+ Long.MAX_VALUE);
+ assertEquals(2, events.size());
+ assertTrue(events.containsAll(Lists.newArrayList(E4, E5)));
+
+ EventIndex indexAfter = map.get("testdir").getEventIndex(Event.ALL_EVENT_TYPES);
+ assertEquals(indexBefore, indexAfter);
+ }
+
+ private void resetAndLoadEventHistory() {
+ mEventHistory = new EventHistoryImpl(EVENT_HISTORY_INJECTOR, mFile,
+ mMockScheduledExecutorService);
+ mEventHistory.loadFromDisk();
+ }
}
diff --git a/services/tests/servicestests/src/com/android/server/people/data/MockScheduledExecutorService.java b/services/tests/servicestests/src/com/android/server/people/data/MockScheduledExecutorService.java
index 8b8ba1247a4b..aecbc8d031e1 100644
--- a/services/tests/servicestests/src/com/android/server/people/data/MockScheduledExecutorService.java
+++ b/services/tests/servicestests/src/com/android/server/people/data/MockScheduledExecutorService.java
@@ -54,8 +54,8 @@ class MockScheduledExecutorService implements ScheduledExecutorService {
long totalExecuted = 0;
for (MockScheduledFuture<?> future : futuresCopy) {
if (future.getDelay() < mTimeElapsedMillis) {
- future.getCommand().run();
- mExecutes.add(future.getCommand());
+ future.getRunnable().run();
+ mExecutes.add(future.getRunnable());
totalExecuted += 1;
} else {
mFutures.add(future);
@@ -96,7 +96,8 @@ class MockScheduledExecutorService implements ScheduledExecutorService {
@Override
public ScheduledFuture<?> scheduleAtFixedRate(Runnable command, long initialDelay, long period,
TimeUnit unit) {
- throw new UnsupportedOperationException();
+ Preconditions.checkState(unit == TimeUnit.MILLISECONDS);
+ return new MockScheduledFuture<>(command, period, unit);
}
@Override
@@ -132,7 +133,13 @@ class MockScheduledExecutorService implements ScheduledExecutorService {
@Override
public <T> Future<T> submit(Callable<T> task) {
- throw new UnsupportedOperationException();
+ MockScheduledFuture<T> future = new MockScheduledFuture<>(task, 0, TimeUnit.MILLISECONDS);
+ try {
+ future.getCallable().call();
+ } catch (Exception e) {
+ e.printStackTrace();
+ }
+ return future;
}
@Override
@@ -141,11 +148,11 @@ class MockScheduledExecutorService implements ScheduledExecutorService {
}
@Override
- public Future<?> submit(Runnable command) {
- mExecutes.add(command);
- MockScheduledFuture<?> future = new MockScheduledFuture<>(command, 0,
+ public Future<?> submit(Runnable runnable) {
+ mExecutes.add(runnable);
+ MockScheduledFuture<?> future = new MockScheduledFuture<>(runnable, 0,
TimeUnit.MILLISECONDS);
- future.getCommand().run();
+ future.getRunnable().run();
return future;
}
@@ -181,12 +188,22 @@ class MockScheduledExecutorService implements ScheduledExecutorService {
class MockScheduledFuture<V> implements ScheduledFuture<V> {
- private final Runnable mCommand;
+ private final Runnable mRunnable;
+ private final Callable<V> mCallable;
private final long mDelay;
private boolean mCancelled = false;
- MockScheduledFuture(Runnable command, long delay, TimeUnit timeUnit) {
- mCommand = command;
+ MockScheduledFuture(Runnable runnable, long delay, TimeUnit timeUnit) {
+ this(runnable, null, delay);
+ }
+
+ MockScheduledFuture(Callable<V> callable, long delay, TimeUnit timeUnit) {
+ this(null, callable, delay);
+ }
+
+ private MockScheduledFuture(Runnable runnable, Callable<V> callable, long delay) {
+ mCallable = callable;
+ mRunnable = runnable;
mDelay = delay;
}
@@ -194,8 +211,12 @@ class MockScheduledExecutorService implements ScheduledExecutorService {
return mDelay;
}
- public Runnable getCommand() {
- return mCommand;
+ public Runnable getRunnable() {
+ return mRunnable;
+ }
+
+ public Callable<V> getCallable() {
+ return mCallable;
}
@Override
diff --git a/services/tests/servicestests/src/com/android/server/people/data/UsageStatsQueryHelperTest.java b/services/tests/servicestests/src/com/android/server/people/data/UsageStatsQueryHelperTest.java
index d444466cdef5..418067fd14f8 100644
--- a/services/tests/servicestests/src/com/android/server/people/data/UsageStatsQueryHelperTest.java
+++ b/services/tests/servicestests/src/com/android/server/people/data/UsageStatsQueryHelperTest.java
@@ -16,6 +16,8 @@
package com.android.server.people.data;
+import static com.android.server.people.data.TestUtils.timestamp;
+
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertTrue;
@@ -62,7 +64,8 @@ public final class UsageStatsQueryHelperTest {
private static final LocusId LOCUS_ID_1 = new LocusId("locus_1");
private static final LocusId LOCUS_ID_2 = new LocusId("locus_2");
- @Mock private UsageStatsManagerInternal mUsageStatsManagerInternal;
+ @Mock
+ private UsageStatsManagerInternal mUsageStatsManagerInternal;
private TestPackageData mPackageData;
private UsageStatsQueryHelper mHelper;
@@ -233,7 +236,7 @@ public final class UsageStatsQueryHelperTest {
private static class TestPackageData extends PackageData {
private final TestConversationStore mConversationStore;
- private final TestEventStore mEventStore = new TestEventStore();
+ private final TestEventStore mEventStore;
TestPackageData(@NonNull String packageName, @UserIdInt int userId,
@NonNull Predicate<String> isDefaultDialerPredicate,
@@ -244,6 +247,7 @@ public final class UsageStatsQueryHelperTest {
scheduledExecutorService, rootDir, helper);
mConversationStore = new TestConversationStore(rootDir, scheduledExecutorService,
helper);
+ mEventStore = new TestEventStore(rootDir, scheduledExecutorService);
}
@Override
@@ -261,8 +265,31 @@ public final class UsageStatsQueryHelperTest {
private static class TestEventStore extends EventStore {
- private final EventHistoryImpl mShortcutEventHistory = new TestEventHistoryImpl();
- private final EventHistoryImpl mLocusEventHistory = new TestEventHistoryImpl();
+ private static final long CURRENT_TIMESTAMP = timestamp("01-30 18:50");
+ private static final EventIndex.Injector EVENT_INDEX_INJECTOR = new EventIndex.Injector() {
+ @Override
+ long currentTimeMillis() {
+ return CURRENT_TIMESTAMP;
+ }
+ };
+ private static final EventHistoryImpl.Injector EVENT_HISTORY_INJECTOR =
+ new EventHistoryImpl.Injector() {
+ @Override
+ EventIndex createEventIndex() {
+ return new EventIndex(EVENT_INDEX_INJECTOR);
+ }
+ };
+
+ private final EventHistoryImpl mShortcutEventHistory;
+ private final EventHistoryImpl mLocusEventHistory;
+
+ TestEventStore(File rootDir, ScheduledExecutorService scheduledExecutorService) {
+ super(rootDir, scheduledExecutorService);
+ mShortcutEventHistory = new TestEventHistoryImpl(EVENT_HISTORY_INJECTOR, rootDir,
+ scheduledExecutorService);
+ mLocusEventHistory = new TestEventHistoryImpl(EVENT_HISTORY_INJECTOR, rootDir,
+ scheduledExecutorService);
+ }
@Override
@NonNull
@@ -280,6 +307,11 @@ public final class UsageStatsQueryHelperTest {
private final List<Event> mEvents = new ArrayList<>();
+ TestEventHistoryImpl(Injector injector, File rootDir,
+ ScheduledExecutorService scheduledExecutorService) {
+ super(injector, rootDir, scheduledExecutorService);
+ }
+
@Override
@NonNull
public List<Event> queryEvents(Set<Integer> eventTypes, long startTime, long endTime) {
diff --git a/services/tests/servicestests/src/com/android/server/people/prediction/ShareTargetPredictorTest.java b/services/tests/servicestests/src/com/android/server/people/prediction/ShareTargetPredictorTest.java
index f498a9450c9e..c6cd34732acf 100644
--- a/services/tests/servicestests/src/com/android/server/people/prediction/ShareTargetPredictorTest.java
+++ b/services/tests/servicestests/src/com/android/server/people/prediction/ShareTargetPredictorTest.java
@@ -16,16 +16,19 @@
package com.android.server.people.prediction;
+import static com.google.common.truth.Truth.assertThat;
+
import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.assertNotNull;
-import static org.junit.Assert.assertNull;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.ArgumentMatchers.anyInt;
-import static org.mockito.ArgumentMatchers.anyString;
+import static org.mockito.ArgumentMatchers.anySet;
import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
import android.app.prediction.AppPredictionContext;
+import android.app.prediction.AppTarget;
+import android.app.prediction.AppTargetId;
import android.content.ComponentName;
import android.content.Context;
import android.content.Intent;
@@ -33,22 +36,26 @@ import android.content.pm.ShortcutInfo;
import android.content.pm.ShortcutManager.ShareShortcutInfo;
import android.os.Bundle;
import android.os.UserHandle;
+import android.util.Range;
import com.android.server.people.data.ConversationInfo;
import com.android.server.people.data.DataManager;
import com.android.server.people.data.EventHistory;
+import com.android.server.people.data.EventIndex;
import com.android.server.people.data.PackageData;
-import com.android.server.people.prediction.ShareTargetPredictor.ShareTarget;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.junit.runners.JUnit4;
+import org.mockito.ArgumentCaptor;
+import org.mockito.Captor;
import org.mockito.Mock;
import org.mockito.MockitoAnnotations;
import java.util.ArrayList;
import java.util.List;
+import java.util.function.Consumer;
@RunWith(JUnit4.class)
public final class ShareTargetPredictorTest {
@@ -57,17 +64,32 @@ public final class ShareTargetPredictorTest {
private static final int NUM_PREDICTED_TARGETS = 5;
private static final int USER_ID = 0;
private static final String PACKAGE_1 = "pkg1";
- private static final String CLASS_1 = "cls1";
private static final String PACKAGE_2 = "pkg2";
+ private static final String PACKAGE_3 = "pkg3";
+ private static final String CLASS_1 = "cls1";
private static final String CLASS_2 = "cls2";
@Mock private Context mContext;
@Mock private DataManager mDataManager;
+ @Mock private Consumer<List<AppTarget>> mUpdatePredictionsMethod;
@Mock private PackageData mPackageData1;
@Mock private PackageData mPackageData2;
+ @Mock private EventHistory mEventHistory1;
+ @Mock private EventHistory mEventHistory2;
+ @Mock private EventHistory mEventHistory3;
+ @Mock private EventHistory mEventHistory4;
+ @Mock private EventHistory mEventHistory5;
+ @Mock private EventHistory mEventHistory6;
- private List<ShareShortcutInfo> mShareShortcuts = new ArrayList<>();
+ @Mock private EventIndex mEventIndex1;
+ @Mock private EventIndex mEventIndex2;
+ @Mock private EventIndex mEventIndex3;
+ @Mock private EventIndex mEventIndex4;
+ @Mock private EventIndex mEventIndex5;
+ @Mock private EventIndex mEventIndex6;
+ @Captor private ArgumentCaptor<List<AppTarget>> mAppTargetCaptor;
+ private List<ShareShortcutInfo> mShareShortcuts = new ArrayList<>();
private ShareTargetPredictor mPredictor;
@Before
@@ -84,11 +106,11 @@ public final class ShareTargetPredictorTest {
.setExtras(new Bundle())
.build();
mPredictor = new ShareTargetPredictor(
- predictionContext, targets -> { }, mDataManager, USER_ID);
+ predictionContext, mUpdatePredictionsMethod, mDataManager, USER_ID);
}
@Test
- public void testGetShareTargets() {
+ public void testPredictTargets() {
mShareShortcuts.add(buildShareShortcut(PACKAGE_1, CLASS_1, "sc1"));
mShareShortcuts.add(buildShareShortcut(PACKAGE_1, CLASS_1, "sc2"));
mShareShortcuts.add(buildShareShortcut(PACKAGE_2, CLASS_2, "sc3"));
@@ -99,24 +121,148 @@ public final class ShareTargetPredictorTest {
when(mPackageData2.getConversationInfo("sc3")).thenReturn(mock(ConversationInfo.class));
// "sc4" does not have a ConversationInfo.
- when(mPackageData1.getEventHistory(anyString())).thenReturn(mock(EventHistory.class));
- when(mPackageData2.getEventHistory(anyString())).thenReturn(mock(EventHistory.class));
+ when(mPackageData1.getEventHistory("sc1")).thenReturn(mEventHistory1);
+ when(mPackageData1.getEventHistory("sc2")).thenReturn(mEventHistory2);
+ when(mPackageData2.getEventHistory("sc3")).thenReturn(mEventHistory3);
+ when(mEventHistory1.getEventIndex(anySet())).thenReturn(mEventIndex1);
+ when(mEventHistory2.getEventIndex(anySet())).thenReturn(mEventIndex2);
+ when(mEventHistory3.getEventIndex(anySet())).thenReturn(mEventIndex3);
+ when(mEventIndex1.getMostRecentActiveTimeSlot()).thenReturn(new Range<>(1L, 2L));
+ when(mEventIndex2.getMostRecentActiveTimeSlot()).thenReturn(new Range<>(2L, 3L));
+ when(mEventIndex3.getMostRecentActiveTimeSlot()).thenReturn(new Range<>(3L, 4L));
- List<ShareTarget> shareTargets = mPredictor.getShareTargets();
+ mPredictor.predictTargets();
- assertEquals(4, shareTargets.size());
+ verify(mUpdatePredictionsMethod).accept(mAppTargetCaptor.capture());
+ List<AppTarget> res = mAppTargetCaptor.getValue();
+ assertEquals(4, res.size());
+
+ assertEquals("sc3", res.get(0).getId().getId());
+ assertEquals(CLASS_2, res.get(0).getClassName());
+ assertEquals(PACKAGE_2, res.get(0).getPackageName());
+
+ assertEquals("sc2", res.get(1).getId().getId());
+ assertEquals(CLASS_1, res.get(1).getClassName());
+ assertEquals(PACKAGE_1, res.get(1).getPackageName());
+
+ assertEquals("sc1", res.get(2).getId().getId());
+ assertEquals(CLASS_1, res.get(2).getClassName());
+ assertEquals(PACKAGE_1, res.get(2).getPackageName());
+
+ assertEquals("sc4", res.get(3).getId().getId());
+ assertEquals(CLASS_2, res.get(3).getClassName());
+ assertEquals(PACKAGE_2, res.get(3).getPackageName());
+ }
+
+ @Test
+ public void testPredictTargets_reachTargetsLimit() {
+ mShareShortcuts.add(buildShareShortcut(PACKAGE_1, CLASS_1, "sc1"));
+ mShareShortcuts.add(buildShareShortcut(PACKAGE_1, CLASS_1, "sc2"));
+ mShareShortcuts.add(buildShareShortcut(PACKAGE_2, CLASS_2, "sc3"));
+ mShareShortcuts.add(buildShareShortcut(PACKAGE_2, CLASS_2, "sc4"));
+ mShareShortcuts.add(buildShareShortcut(PACKAGE_1, CLASS_1, "sc5"));
+ mShareShortcuts.add(buildShareShortcut(PACKAGE_2, CLASS_2, "sc6"));
+
+ when(mPackageData1.getConversationInfo("sc1")).thenReturn(mock(ConversationInfo.class));
+ when(mPackageData1.getConversationInfo("sc2")).thenReturn(mock(ConversationInfo.class));
+ when(mPackageData2.getConversationInfo("sc3")).thenReturn(mock(ConversationInfo.class));
+ when(mPackageData2.getConversationInfo("sc4")).thenReturn(mock(ConversationInfo.class));
+ when(mPackageData1.getConversationInfo("sc5")).thenReturn(mock(ConversationInfo.class));
+ when(mPackageData2.getConversationInfo("sc6")).thenReturn(mock(ConversationInfo.class));
+
+ when(mPackageData1.getEventHistory("sc1")).thenReturn(mEventHistory1);
+ when(mPackageData1.getEventHistory("sc2")).thenReturn(mEventHistory2);
+ when(mPackageData2.getEventHistory("sc3")).thenReturn(mEventHistory3);
+ when(mPackageData2.getEventHistory("sc4")).thenReturn(mEventHistory4);
+ when(mPackageData1.getEventHistory("sc5")).thenReturn(mEventHistory5);
+ when(mPackageData2.getEventHistory("sc6")).thenReturn(mEventHistory6);
+
+ when(mEventHistory1.getEventIndex(anySet())).thenReturn(mEventIndex1);
+ when(mEventHistory2.getEventIndex(anySet())).thenReturn(mEventIndex2);
+ when(mEventHistory3.getEventIndex(anySet())).thenReturn(mEventIndex3);
+ when(mEventHistory4.getEventIndex(anySet())).thenReturn(mEventIndex4);
+ when(mEventHistory5.getEventIndex(anySet())).thenReturn(mEventIndex5);
+ when(mEventHistory6.getEventIndex(anySet())).thenReturn(mEventIndex6);
+ when(mEventIndex1.getMostRecentActiveTimeSlot()).thenReturn(new Range<>(1L, 2L));
+ when(mEventIndex2.getMostRecentActiveTimeSlot()).thenReturn(new Range<>(2L, 3L));
+ when(mEventIndex3.getMostRecentActiveTimeSlot()).thenReturn(new Range<>(3L, 4L));
+ when(mEventIndex4.getMostRecentActiveTimeSlot()).thenReturn(new Range<>(4L, 5L));
+ when(mEventIndex5.getMostRecentActiveTimeSlot()).thenReturn(new Range<>(5L, 6L));
+ when(mEventIndex6.getMostRecentActiveTimeSlot()).thenReturn(new Range<>(6L, 7L));
+
+ mPredictor.predictTargets();
+
+ verify(mUpdatePredictionsMethod).accept(mAppTargetCaptor.capture());
+ List<AppTarget> res = mAppTargetCaptor.getValue();
+ assertEquals(5, res.size());
+
+ assertEquals("sc6", res.get(0).getId().getId());
+ assertEquals(CLASS_2, res.get(0).getClassName());
+ assertEquals(PACKAGE_2, res.get(0).getPackageName());
+
+ assertEquals("sc5", res.get(1).getId().getId());
+ assertEquals(CLASS_1, res.get(1).getClassName());
+ assertEquals(PACKAGE_1, res.get(1).getPackageName());
+
+ assertEquals("sc4", res.get(2).getId().getId());
+ assertEquals(CLASS_2, res.get(2).getClassName());
+ assertEquals(PACKAGE_2, res.get(2).getPackageName());
+
+ assertEquals("sc3", res.get(3).getId().getId());
+ assertEquals(CLASS_2, res.get(3).getClassName());
+ assertEquals(PACKAGE_2, res.get(3).getPackageName());
+
+ assertEquals("sc2", res.get(4).getId().getId());
+ assertEquals(CLASS_1, res.get(4).getClassName());
+ assertEquals(PACKAGE_1, res.get(4).getPackageName());
+ }
+
+ @Test
+ public void testSortTargets() {
+ AppTarget appTarget1 = new AppTarget.Builder(
+ new AppTargetId("cls1#pkg1"), PACKAGE_1, UserHandle.of(USER_ID))
+ .setClassName(CLASS_1)
+ .build();
+ AppTarget appTarget2 = new AppTarget.Builder(
+ new AppTargetId("cls2#pkg1"), PACKAGE_1, UserHandle.of(USER_ID))
+ .setClassName(CLASS_2)
+ .build();
+ AppTarget appTarget3 = new AppTarget.Builder(
+ new AppTargetId("cls1#pkg2"), PACKAGE_2, UserHandle.of(USER_ID))
+ .setClassName(CLASS_1)
+ .build();
+ AppTarget appTarget4 = new AppTarget.Builder(
+ new AppTargetId("cls2#pkg2"), PACKAGE_2, UserHandle.of(USER_ID))
+ .setClassName(CLASS_2)
+ .build();
+ AppTarget appTarget5 = new AppTarget.Builder(
+ new AppTargetId("cls1#pkg3"), PACKAGE_3, UserHandle.of(USER_ID))
+ .setClassName(CLASS_1)
+ .build();
- assertEquals("sc1", shareTargets.get(0).getShareShortcutInfo().getShortcutInfo().getId());
- assertNotNull(shareTargets.get(0).getConversationData());
+ when(mPackageData1.getClassLevelEventHistory(CLASS_1)).thenReturn(mEventHistory1);
+ when(mPackageData1.getClassLevelEventHistory(CLASS_2)).thenReturn(mEventHistory2);
+ when(mPackageData2.getClassLevelEventHistory(CLASS_1)).thenReturn(mEventHistory3);
+ when(mPackageData2.getClassLevelEventHistory(CLASS_2)).thenReturn(mEventHistory4);
+ // PackageData of PACKAGE_3 is empty.
+ when(mDataManager.getPackage(PACKAGE_3, USER_ID)).thenReturn(null);
- assertEquals("sc2", shareTargets.get(1).getShareShortcutInfo().getShortcutInfo().getId());
- assertNotNull(shareTargets.get(1).getConversationData());
+ when(mEventHistory1.getEventIndex(anySet())).thenReturn(mEventIndex1);
+ when(mEventHistory2.getEventIndex(anySet())).thenReturn(mEventIndex2);
+ when(mEventHistory3.getEventIndex(anySet())).thenReturn(mEventIndex3);
+ when(mEventHistory4.getEventIndex(anySet())).thenReturn(mEventIndex4);
+ when(mEventIndex1.getMostRecentActiveTimeSlot()).thenReturn(new Range<>(1L, 2L));
+ when(mEventIndex2.getMostRecentActiveTimeSlot()).thenReturn(new Range<>(2L, 3L));
+ when(mEventIndex3.getMostRecentActiveTimeSlot()).thenReturn(new Range<>(3L, 4L));
+ when(mEventIndex4.getMostRecentActiveTimeSlot()).thenReturn(new Range<>(4L, 5L));
- assertEquals("sc3", shareTargets.get(2).getShareShortcutInfo().getShortcutInfo().getId());
- assertNotNull(shareTargets.get(2).getConversationData());
+ mPredictor.sortTargets(
+ List.of(appTarget1, appTarget2, appTarget3, appTarget4, appTarget5),
+ mUpdatePredictionsMethod);
- assertEquals("sc4", shareTargets.get(3).getShareShortcutInfo().getShortcutInfo().getId());
- assertNull(shareTargets.get(3).getConversationData());
+ verify(mUpdatePredictionsMethod).accept(mAppTargetCaptor.capture());
+ assertThat(mAppTargetCaptor.getValue()).containsExactly(
+ appTarget4, appTarget3, appTarget2, appTarget1, appTarget5);
}
private ShareShortcutInfo buildShareShortcut(
diff --git a/services/tests/servicestests/src/com/android/server/pm/ShortcutManagerTest1.java b/services/tests/servicestests/src/com/android/server/pm/ShortcutManagerTest1.java
index 2936bdd8501b..56460fb6f0a0 100644
--- a/services/tests/servicestests/src/com/android/server/pm/ShortcutManagerTest1.java
+++ b/services/tests/servicestests/src/com/android/server/pm/ShortcutManagerTest1.java
@@ -379,6 +379,113 @@ public class ShortcutManagerTest1 extends BaseShortcutManagerTest {
});
}
+ public void testPushDynamicShortcut() {
+
+ setCaller(CALLING_PACKAGE_1, USER_0);
+
+ final ShortcutInfo s1 = makeShortcut("s1");
+ final ShortcutInfo s2 = makeShortcut("s2");
+ final ShortcutInfo s3 = makeShortcut("s3");
+ final ShortcutInfo s4 = makeShortcut("s4");
+
+ final ShortcutInfo s10 = makeShortcut("s10");
+ final ShortcutInfo s11 = makeShortcut("s11");
+ final ShortcutInfo s12 = makeShortcut("s12");
+ final ShortcutInfo s13 = makeShortcut("s13");
+ final ShortcutInfo s14 = makeShortcut("s14");
+
+ // Test push as first shortcut
+ mManager.pushDynamicShortcut(s1);
+ assertShortcutIds(assertAllNotKeyFieldsOnly(mManager.getDynamicShortcuts()), "s1");
+ assertEquals(0, getCallerShortcut("s1").getRank());
+
+ // Test push when other shortcuts exist
+ assertTrue(mManager.setDynamicShortcuts(list(s1, s2)));
+ assertShortcutIds(assertAllNotKeyFieldsOnly(mManager.getDynamicShortcuts()), "s1", "s2");
+ mManager.pushDynamicShortcut(s3);
+ assertShortcutIds(assertAllNotKeyFieldsOnly(mManager.getDynamicShortcuts()),
+ "s1", "s2", "s3");
+ assertEquals(0, getCallerShortcut("s3").getRank());
+ assertEquals(1, getCallerShortcut("s1").getRank());
+ assertEquals(2, getCallerShortcut("s2").getRank());
+
+ mInjectedCurrentTimeMillis += INTERVAL; // reset
+
+ // Push with set rank
+ s4.setRank(2);
+ mManager.pushDynamicShortcut(s4);
+ assertEquals(2, getCallerShortcut("s4").getRank());
+ assertEquals(3, getCallerShortcut("s2").getRank());
+
+ // Push existing shortcut with set rank
+ final ShortcutInfo s4_2 = makeShortcut("s4");
+ s4_2.setRank(4);
+ mManager.pushDynamicShortcut(s4_2);
+ assertEquals(2, getCallerShortcut("s2").getRank());
+ assertEquals(3, getCallerShortcut("s4").getRank());
+
+ mInjectedCurrentTimeMillis += INTERVAL; // reset
+
+ // Test push as last
+ assertTrue(mManager.addDynamicShortcuts(makeShortcuts("s5", "s6", "s7", "s8", "s9")));
+ mManager.pushDynamicShortcut(s10);
+ assertShortcutIds(assertAllNotKeyFieldsOnly(mManager.getDynamicShortcuts()),
+ "s1", "s2", "s3", "s4", "s5", "s6", "s7", "s8", "s9", "s10");
+ assertEquals(0, getCallerShortcut("s10").getRank());
+ assertEquals(1, getCallerShortcut("s5").getRank());
+ assertEquals(6, getCallerShortcut("s3").getRank());
+ assertEquals(7, getCallerShortcut("s1").getRank());
+ assertEquals(8, getCallerShortcut("s2").getRank());
+ assertEquals(9, getCallerShortcut("s4").getRank());
+
+ // Push when max has already reached
+ mManager.pushDynamicShortcut(s11);
+ assertShortcutIds(assertAllNotKeyFieldsOnly(mManager.getDynamicShortcuts()),
+ "s1", "s2", "s3", "s5", "s6", "s7", "s8", "s9", "s10", "s11");
+ assertEquals(0, getCallerShortcut("s11").getRank());
+ assertEquals(1, getCallerShortcut("s10").getRank());
+ assertEquals(9, getCallerShortcut("s2").getRank());
+
+ mInjectedCurrentTimeMillis += INTERVAL; // reset
+
+ // Push with different activity
+ s12.setActivity(makeComponent(ShortcutActivity2.class));
+ mManager.pushDynamicShortcut(s12);
+ assertEquals(makeComponent(ShortcutActivity2.class),
+ getCallerShortcut("s12").getActivity());
+ assertEquals(0, getCallerShortcut("s12").getRank());
+
+ // Push to update shortcut with different activity
+ final ShortcutInfo s1_2 = makeShortcut("s1");
+ s1_2.setActivity(makeComponent(ShortcutActivity2.class));
+ s1_2.setRank(1);
+ mManager.pushDynamicShortcut(s1_2);
+ assertEquals(0, getCallerShortcut("s12").getRank());
+ assertEquals(1, getCallerShortcut("s1").getRank());
+ assertEquals(0, getCallerShortcut("s11").getRank());
+ assertEquals(1, getCallerShortcut("s10").getRank());
+ assertEquals(7, getCallerShortcut("s3").getRank());
+ assertEquals(8, getCallerShortcut("s2").getRank());
+
+ mInjectedCurrentTimeMillis += INTERVAL; // reset
+
+ // Test push when dropped shortcut is cached
+ s13.setLongLived();
+ s13.setRank(100);
+ mManager.pushDynamicShortcut(s13);
+ assertEquals(9, getCallerShortcut("s13").getRank());
+ runWithCaller(LAUNCHER_1, USER_0, () -> {
+ mLauncherApps.cacheShortcuts(CALLING_PACKAGE_1, list("s13"), HANDLE_USER_0);
+ });
+
+ mManager.pushDynamicShortcut(s14);
+ assertShortcutIds(assertAllNotKeyFieldsOnly(mManager.getDynamicShortcuts()),
+ "s1", "s2", "s3", "s5", "s6", "s7", "s8", "s9", "s10", "s11", "s12", "s14");
+ // Verify s13 stayed as cached
+ assertShortcutIds(mManager.getShortcuts(ShortcutManager.FLAG_MATCH_CACHED),
+ "s13");
+ }
+
public void testUnlimitedCalls() {
setCaller(CALLING_PACKAGE_1, USER_0);
diff --git a/services/tests/servicestests/src/com/android/server/usage/AppStandbyControllerTests.java b/services/tests/servicestests/src/com/android/server/usage/AppStandbyControllerTests.java
index 9e577636c1b3..0fdffd554b36 100644
--- a/services/tests/servicestests/src/com/android/server/usage/AppStandbyControllerTests.java
+++ b/services/tests/servicestests/src/com/android/server/usage/AppStandbyControllerTests.java
@@ -66,6 +66,7 @@ import android.hardware.display.DisplayManager;
import android.os.Handler;
import android.os.Looper;
import android.os.RemoteException;
+import android.os.UserHandle;
import android.platform.test.annotations.Presubmit;
import android.util.ArraySet;
import android.view.Display;
@@ -83,6 +84,7 @@ import org.junit.runner.RunWith;
import java.io.File;
import java.util.ArrayList;
import java.util.Arrays;
+import java.util.Collections;
import java.util.List;
import java.util.Set;
import java.util.concurrent.TimeUnit;
@@ -101,6 +103,8 @@ public class AppStandbyControllerTests {
private static final int UID_EXEMPTED_1 = 10001;
private static final int USER_ID = 0;
private static final int USER_ID2 = 10;
+ private static final UserHandle USER_HANDLE_USER2 = new UserHandle(USER_ID2);
+ private static final int USER_ID3 = 11;
private static final String PACKAGE_UNKNOWN = "com.example.unknown";
@@ -150,6 +154,8 @@ public class AppStandbyControllerTests {
boolean mDisplayOn;
DisplayManager.DisplayListener mDisplayListener;
String mBoundWidgetPackage = PACKAGE_EXEMPTED_1;
+ int[] mRunningUsers = new int[] {USER_ID};
+ List<UserHandle> mCrossProfileTargets = Collections.emptyList();
MyInjector(Context context, Looper looper) {
super(context, looper);
@@ -212,7 +218,7 @@ public class AppStandbyControllerTests {
@Override
int[] getRunningUserIds() {
- return new int[] {USER_ID};
+ return mRunningUsers;
}
@Override
@@ -248,6 +254,11 @@ public class AppStandbyControllerTests {
return false;
}
+ @Override
+ public List<UserHandle> getValidCrossProfileTargets(String pkg, int userId) {
+ return mCrossProfileTargets;
+ }
+
// Internal methods
void setDisplayOn(boolean on) {
@@ -379,10 +390,15 @@ public class AppStandbyControllerTests {
}
private void assertTimeout(AppStandbyController controller, long elapsedTime, int bucket) {
+ assertTimeout(controller, elapsedTime, bucket, USER_ID);
+ }
+
+ private void assertTimeout(AppStandbyController controller, long elapsedTime, int bucket,
+ int userId) {
mInjector.mElapsedRealtime = elapsedTime;
- controller.checkIdleStates(USER_ID);
+ controller.checkIdleStates(userId);
assertEquals(bucket,
- controller.getAppStandbyBucket(PACKAGE_1, USER_ID, mInjector.mElapsedRealtime,
+ controller.getAppStandbyBucket(PACKAGE_1, userId, mInjector.mElapsedRealtime,
false));
}
@@ -397,7 +413,11 @@ public class AppStandbyControllerTests {
}
private int getStandbyBucket(AppStandbyController controller, String packageName) {
- return controller.getAppStandbyBucket(packageName, USER_ID, mInjector.mElapsedRealtime,
+ return getStandbyBucket(USER_ID, controller, packageName);
+ }
+
+ private int getStandbyBucket(int userId, AppStandbyController controller, String packageName) {
+ return controller.getAppStandbyBucket(packageName, userId, mInjector.mElapsedRealtime,
true);
}
@@ -1012,6 +1032,29 @@ public class AppStandbyControllerTests {
assertIsNotActiveAdmin(ADMIN_PKG2, USER_ID);
}
+ @Test
+ public void testUserInteraction_CrossProfile() throws Exception {
+ mInjector.mRunningUsers = new int[] {USER_ID, USER_ID2, USER_ID3};
+ mInjector.mCrossProfileTargets = Arrays.asList(USER_HANDLE_USER2);
+ reportEvent(mController, USER_INTERACTION, 0, PACKAGE_1);
+ assertEquals("Cross profile connected package bucket should be elevated on usage",
+ STANDBY_BUCKET_ACTIVE, getStandbyBucket(USER_ID2, mController, PACKAGE_1));
+ assertEquals("Not Cross profile connected package bucket should not be elevated on usage",
+ STANDBY_BUCKET_NEVER, getStandbyBucket(USER_ID3, mController, PACKAGE_1));
+
+ assertTimeout(mController, WORKING_SET_THRESHOLD - 1, STANDBY_BUCKET_ACTIVE, USER_ID);
+ assertTimeout(mController, WORKING_SET_THRESHOLD - 1, STANDBY_BUCKET_ACTIVE, USER_ID2);
+
+ assertTimeout(mController, WORKING_SET_THRESHOLD + 1, STANDBY_BUCKET_WORKING_SET, USER_ID);
+ assertTimeout(mController, WORKING_SET_THRESHOLD + 1, STANDBY_BUCKET_WORKING_SET, USER_ID2);
+
+ mInjector.mCrossProfileTargets = Collections.emptyList();
+ reportEvent(mController, USER_INTERACTION, 0, PACKAGE_1);
+ assertEquals("No longer cross profile connected package bucket should not be "
+ + "elevated on usage",
+ STANDBY_BUCKET_WORKING_SET, getStandbyBucket(USER_ID2, mController, PACKAGE_1));
+ }
+
private String getAdminAppsStr(int userId) {
return getAdminAppsStr(userId, mController.getActiveAdminAppsForTest(userId));
}
diff --git a/services/tests/uiservicestests/Android.bp b/services/tests/uiservicestests/Android.bp
index 3f0cda3b8e5a..b7199f7cdd5a 100644
--- a/services/tests/uiservicestests/Android.bp
+++ b/services/tests/uiservicestests/Android.bp
@@ -29,6 +29,7 @@ android_test {
libs: [
"android.test.runner",
"android.test.base",
+ "android.test.mock",
],
dxflags: ["--multi-dex"],
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 7f9732bb350a..58299614efe8 100644
--- a/services/tests/uiservicestests/src/com/android/server/notification/PreferencesHelperTest.java
+++ b/services/tests/uiservicestests/src/com/android/server/notification/PreferencesHelperTest.java
@@ -36,9 +36,10 @@ import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertTrue;
import static org.mockito.ArgumentMatchers.any;
-import static org.mockito.Matchers.anyInt;
-import static org.mockito.Matchers.anyString;
-import static org.mockito.Matchers.eq;
+import static org.mockito.ArgumentMatchers.anyInt;
+import static org.mockito.ArgumentMatchers.anyString;
+import static org.mockito.ArgumentMatchers.eq;
+import static org.mockito.Mockito.doReturn;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.never;
import static org.mockito.Mockito.reset;
@@ -67,6 +68,7 @@ import android.provider.Settings;
import android.provider.Settings.Global;
import android.provider.Settings.Secure;
import android.service.notification.ConversationChannelWrapper;
+import android.test.mock.MockIContentProvider;
import android.test.suitebuilder.annotation.SmallTest;
import android.testing.TestableContentResolver;
import android.util.ArrayMap;
@@ -87,6 +89,7 @@ import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.Mock;
import org.mockito.MockitoAnnotations;
+import org.mockito.Spy;
import org.xmlpull.v1.XmlPullParser;
import org.xmlpull.v1.XmlSerializer;
@@ -123,7 +126,7 @@ public class PreferencesHelperTest extends UiServiceTestCase {
@Mock NotificationUsageStats mUsageStats;
@Mock RankingHandler mHandler;
@Mock PackageManager mPm;
- @Mock IContentProvider mTestIContentProvider;
+ @Spy IContentProvider mTestIContentProvider = new MockIContentProvider();
@Mock Context mContext;
@Mock ZenModeHelper mMockZenModeHelper;
@@ -170,12 +173,12 @@ public class PreferencesHelperTest extends UiServiceTestCase {
when(testContentProvider.getIContentProvider()).thenReturn(mTestIContentProvider);
contentResolver.addProvider(TEST_AUTHORITY, testContentProvider);
- when(mTestIContentProvider.canonicalize(any(), any(), eq(SOUND_URI)))
- .thenReturn(CANONICAL_SOUND_URI);
- when(mTestIContentProvider.canonicalize(any(), any(), eq(CANONICAL_SOUND_URI)))
- .thenReturn(CANONICAL_SOUND_URI);
- when(mTestIContentProvider.uncanonicalize(any(), any(), eq(CANONICAL_SOUND_URI)))
- .thenReturn(SOUND_URI);
+ doReturn(CANONICAL_SOUND_URI)
+ .when(mTestIContentProvider).canonicalize(any(), any(), eq(SOUND_URI));
+ doReturn(CANONICAL_SOUND_URI)
+ .when(mTestIContentProvider).canonicalize(any(), any(), eq(CANONICAL_SOUND_URI));
+ doReturn(SOUND_URI)
+ .when(mTestIContentProvider).uncanonicalize(any(), any(), eq(CANONICAL_SOUND_URI));
mTestNotificationPolicy = new NotificationManager.Policy(0, 0, 0, 0,
NotificationManager.Policy.STATE_CHANNELS_BYPASSING_DND, 0);
@@ -506,12 +509,13 @@ public class PreferencesHelperTest extends UiServiceTestCase {
.appendQueryParameter("title", "Test")
.appendQueryParameter("canonical", "1")
.build();
- when(mTestIContentProvider.canonicalize(any(), any(), eq(CANONICAL_SOUND_URI)))
- .thenReturn(canonicalBasedOnLocal);
- when(mTestIContentProvider.uncanonicalize(any(), any(), eq(CANONICAL_SOUND_URI)))
- .thenReturn(localUri);
- when(mTestIContentProvider.uncanonicalize(any(), any(), eq(canonicalBasedOnLocal)))
- .thenReturn(localUri);
+ doReturn(canonicalBasedOnLocal)
+ .when(mTestIContentProvider).canonicalize(any(), any(), eq(CANONICAL_SOUND_URI));
+ doReturn(localUri)
+ .when(mTestIContentProvider).uncanonicalize(any(), any(), eq(CANONICAL_SOUND_URI));
+ doReturn(localUri)
+ .when(mTestIContentProvider).uncanonicalize(any(), any(),
+ eq(canonicalBasedOnLocal));
NotificationChannel channel =
new NotificationChannel("id", "name", IMPORTANCE_LOW);
@@ -530,10 +534,10 @@ public class PreferencesHelperTest extends UiServiceTestCase {
@Test
public void testRestoreXml_withNonExistentCanonicalizedSoundUri() throws Exception {
Thread.sleep(3000);
- when(mTestIContentProvider.canonicalize(any(), any(), eq(CANONICAL_SOUND_URI)))
- .thenReturn(null);
- when(mTestIContentProvider.uncanonicalize(any(), any(), eq(CANONICAL_SOUND_URI)))
- .thenReturn(null);
+ doReturn(null)
+ .when(mTestIContentProvider).canonicalize(any(), any(), eq(CANONICAL_SOUND_URI));
+ doReturn(null)
+ .when(mTestIContentProvider).uncanonicalize(any(), any(), eq(CANONICAL_SOUND_URI));
NotificationChannel channel =
new NotificationChannel("id", "name", IMPORTANCE_LOW);
@@ -557,7 +561,8 @@ public class PreferencesHelperTest extends UiServiceTestCase {
@Test
public void testRestoreXml_withUncanonicalizedNonLocalSoundUri() throws Exception {
// Not a local uncanonicalized uri, simulating that it fails to exist locally
- when(mTestIContentProvider.canonicalize(any(), any(), eq(SOUND_URI))).thenReturn(null);
+ doReturn(null)
+ .when(mTestIContentProvider).canonicalize(any(), any(), eq(SOUND_URI));
String id = "id";
String backupWithUncanonicalizedSoundUri = "<ranking version=\"1\">\n"
+ "<package name=\"" + PKG_N_MR1 + "\" show_badge=\"true\">\n"
diff --git a/services/tests/wmtests/src/com/android/server/wm/ActivityRecordTests.java b/services/tests/wmtests/src/com/android/server/wm/ActivityRecordTests.java
index a0ea7290ec01..c9c3649783b8 100644
--- a/services/tests/wmtests/src/com/android/server/wm/ActivityRecordTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/ActivityRecordTests.java
@@ -1025,9 +1025,9 @@ public class ActivityRecordTests extends ActivityTestsBase {
public void testDestroyIfPossible_lastActivityAboveEmptyHomeStack() {
// Empty the home stack.
final ActivityStack homeStack = mActivity.getDisplay().getRootHomeTask();
- homeStack.forAllTasks((t) -> {
+ homeStack.forAllLeafTasks((t) -> {
homeStack.removeChild(t, "test");
- }, true /* traverseTopToBottom */, homeStack);
+ }, true /* traverseTopToBottom */);
mActivity.finishing = true;
doReturn(false).when(mRootWindowContainer).resumeFocusedStacksTopActivities();
spyOn(mStack);
@@ -1051,9 +1051,9 @@ public class ActivityRecordTests extends ActivityTestsBase {
public void testCompleteFinishing_lastActivityAboveEmptyHomeStack() {
// Empty the home stack.
final ActivityStack homeStack = mActivity.getDisplay().getRootHomeTask();
- homeStack.forAllTasks((t) -> {
+ homeStack.forAllLeafTasks((t) -> {
homeStack.removeChild(t, "test");
- }, true /* traverseTopToBottom */, homeStack);
+ }, true /* traverseTopToBottom */);
mActivity.finishing = true;
spyOn(mStack);
diff --git a/services/tests/wmtests/src/com/android/server/wm/DisplayContentTests.java b/services/tests/wmtests/src/com/android/server/wm/DisplayContentTests.java
index 1a8f2a6b65f5..b3c6b22bf265 100644
--- a/services/tests/wmtests/src/com/android/server/wm/DisplayContentTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/DisplayContentTests.java
@@ -27,6 +27,7 @@ import static android.view.Display.DEFAULT_DISPLAY;
import static android.view.DisplayCutout.BOUNDS_POSITION_LEFT;
import static android.view.DisplayCutout.BOUNDS_POSITION_TOP;
import static android.view.DisplayCutout.fromBoundingRect;
+import static android.view.Surface.ROTATION_0;
import static android.view.Surface.ROTATION_90;
import static android.view.View.SYSTEM_UI_FLAG_FULLSCREEN;
import static android.view.View.SYSTEM_UI_FLAG_HIDE_NAVIGATION;
@@ -998,12 +999,10 @@ public class DisplayContentTests extends WindowTestsBase {
public void testApplyTopFixedRotationTransform() {
mWm.mIsFixedRotationTransformEnabled = true;
final Configuration config90 = new Configuration();
- mDisplayContent.getDisplayRotation().setRotation(ROTATION_90);
- mDisplayContent.computeScreenConfiguration(config90);
- mDisplayContent.onRequestedOverrideConfigurationChanged(config90);
+ mDisplayContent.computeScreenConfiguration(config90, ROTATION_90);
final Configuration config = new Configuration();
- mDisplayContent.getDisplayRotation().setRotation(Surface.ROTATION_0);
+ mDisplayContent.getDisplayRotation().setRotation(ROTATION_0);
mDisplayContent.computeScreenConfiguration(config);
mDisplayContent.onRequestedOverrideConfigurationChanged(config);
@@ -1014,11 +1013,18 @@ public class DisplayContentTests extends WindowTestsBase {
app.setRequestedOrientation(SCREEN_ORIENTATION_LANDSCAPE);
assertTrue(app.isFixedRotationTransforming());
+ assertTrue(mDisplayContent.getDisplayRotation().shouldRotateSeamlessly(
+ ROTATION_0 /* oldRotation */, ROTATION_90 /* newRotation */,
+ false /* forceUpdate */));
+ // The display should keep current orientation and the rotated configuration should apply
+ // to the activity.
assertEquals(config.orientation, mDisplayContent.getConfiguration().orientation);
assertEquals(config90.orientation, app.getConfiguration().orientation);
+ assertEquals(config90.windowConfiguration.getBounds(), app.getBounds());
mDisplayContent.mAppTransition.notifyAppTransitionFinishedLocked(app.token);
+ // The display should be rotated after the launch is finished.
assertFalse(app.hasFixedRotationTransform());
assertEquals(config90.orientation, mDisplayContent.getConfiguration().orientation);
}
diff --git a/services/tests/wmtests/src/com/android/server/wm/DisplayPolicyLayoutTests.java b/services/tests/wmtests/src/com/android/server/wm/DisplayPolicyLayoutTests.java
index ba577454f9d5..2b0ad890aae1 100644
--- a/services/tests/wmtests/src/com/android/server/wm/DisplayPolicyLayoutTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/DisplayPolicyLayoutTests.java
@@ -605,6 +605,7 @@ public class DisplayPolicyLayoutTests extends DisplayPolicyTestsBase {
mWindow.mAttrs.flags =
FLAG_LAYOUT_IN_SCREEN | FLAG_LAYOUT_INSET_DECOR | FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS;
+ mWindow.mAttrs.setFitInsetsTypes(0 /* types */);
addWindow(mWindow);
mDisplayPolicy.beginLayoutLw(mFrames, 0 /* UI mode */);
@@ -625,6 +626,7 @@ public class DisplayPolicyLayoutTests extends DisplayPolicyTestsBase {
mWindow.mAttrs.flags =
FLAG_LAYOUT_IN_SCREEN | FLAG_LAYOUT_INSET_DECOR | FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS;
+ mWindow.mAttrs.setFitInsetsTypes(0 /* types */);
mWindow.mAttrs.layoutInDisplayCutoutMode = LAYOUT_IN_DISPLAY_CUTOUT_MODE_NEVER;
addWindow(mWindow);
diff --git a/services/tests/wmtests/src/com/android/server/wm/RootActivityContainerTests.java b/services/tests/wmtests/src/com/android/server/wm/RootActivityContainerTests.java
index dd466731389e..ec2026255f8e 100644
--- a/services/tests/wmtests/src/com/android/server/wm/RootActivityContainerTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/RootActivityContainerTests.java
@@ -313,8 +313,8 @@ public class RootActivityContainerTests extends ActivityTestsBase {
*/
@Test
public void testResizeDockedStackForSplitScreenPrimary() {
- final Rect taskSize = new Rect(0, 0, 1000, 1000);
- final Rect stackSize = new Rect(0, 0, 300, 300);
+ final Rect configSize = new Rect(0, 0, 1000, 1000);
+ final Rect displayedSize = new Rect(0, 0, 300, 300);
// Create primary split-screen stack with a task.
final ActivityStack primaryStack = new StackBuilder(mRootWindowContainer)
@@ -325,11 +325,13 @@ public class RootActivityContainerTests extends ActivityTestsBase {
final Task task = primaryStack.getTopMostTask();
// Resize dock stack.
- mService.resizeDockedStack(stackSize, taskSize, null, null, null);
+ mService.resizeDockedStack(displayedSize, configSize, null, null, null);
// Verify dock stack & its task bounds if is equal as resized result.
- assertEquals(stackSize, primaryStack.getBounds());
- assertEquals(taskSize, task.getBounds());
+ assertEquals(displayedSize, primaryStack.getDisplayedBounds());
+ assertEquals(displayedSize, primaryStack.getDisplayedBounds());
+ assertEquals(configSize, primaryStack.getBounds());
+ assertEquals(configSize, task.getBounds());
}
/**
diff --git a/services/tests/wmtests/src/com/android/server/wm/TaskOrganizerTests.java b/services/tests/wmtests/src/com/android/server/wm/TaskOrganizerTests.java
index cd53eced948f..45b51cf9d2db 100644
--- a/services/tests/wmtests/src/com/android/server/wm/TaskOrganizerTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/TaskOrganizerTests.java
@@ -28,6 +28,7 @@ import static android.app.WindowConfiguration.WINDOWING_MODE_SPLIT_SCREEN_SECOND
import static android.app.WindowConfiguration.WINDOWING_MODE_UNDEFINED;
import static android.view.WindowManager.LayoutParams.TYPE_APPLICATION;
+import static com.android.dx.mockito.inline.extended.ExtendedMockito.doNothing;
import static com.android.dx.mockito.inline.extended.ExtendedMockito.doReturn;
import static com.android.dx.mockito.inline.extended.ExtendedMockito.mock;
import static com.android.dx.mockito.inline.extended.ExtendedMockito.never;
@@ -300,6 +301,7 @@ public class TaskOrganizerTests extends WindowTestsBase {
Rect newSize = new Rect(10, 10, 300, 300);
Configuration c = new Configuration(tile1.getRequestedOverrideConfiguration());
c.windowConfiguration.setBounds(newSize);
+ doNothing().when(stack).adjustForMinimalTaskDimensions(any(), any());
tile1.onRequestedOverrideConfigurationChanged(c);
assertEquals(newSize, stack.getBounds());
diff --git a/services/tests/wmtests/src/com/android/server/wm/TaskStackTests.java b/services/tests/wmtests/src/com/android/server/wm/TaskStackTests.java
index 6e4be88a31fe..6387a3b7c474 100644
--- a/services/tests/wmtests/src/com/android/server/wm/TaskStackTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/TaskStackTests.java
@@ -16,9 +16,11 @@
package com.android.server.wm;
+import static android.app.WindowConfiguration.WINDOWING_MODE_SPLIT_SCREEN_SECONDARY;
import static android.content.pm.ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE;
import static android.content.pm.ActivityInfo.SCREEN_ORIENTATION_PORTRAIT;
+import static com.android.dx.mockito.inline.extended.ExtendedMockito.doNothing;
import static com.android.dx.mockito.inline.extended.ExtendedMockito.doReturn;
import static com.android.dx.mockito.inline.extended.ExtendedMockito.spyOn;
import static com.android.dx.mockito.inline.extended.ExtendedMockito.times;
@@ -33,6 +35,7 @@ import static org.junit.Assert.assertNull;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.Mockito.clearInvocations;
+import android.app.WindowConfiguration;
import android.graphics.Rect;
import android.platform.test.annotations.Presubmit;
@@ -184,6 +187,16 @@ public class TaskStackTests extends WindowTestsBase {
doReturn(stackOutset).when(stack).getStackOutset();
doReturn(true).when(stack).inMultiWindowMode();
+ // Mock the resolved override windowing mode to non-fullscreen
+ final WindowConfiguration windowConfiguration =
+ stack.getResolvedOverrideConfiguration().windowConfiguration;
+ spyOn(windowConfiguration);
+ doReturn(WINDOWING_MODE_SPLIT_SCREEN_SECONDARY)
+ .when(windowConfiguration).getWindowingMode();
+
+ // Prevent adjust task dimensions
+ doNothing().when(stack).adjustForMinimalTaskDimensions(any(), any());
+
final Rect stackBounds = new Rect(200, 200, 800, 1000);
// Update surface position and size by the given bounds.
stack.setBounds(stackBounds);
diff --git a/services/usage/java/com/android/server/usage/StorageStatsService.java b/services/usage/java/com/android/server/usage/StorageStatsService.java
index 18b640ff6bf5..c3d3d83f02fa 100644
--- a/services/usage/java/com/android/server/usage/StorageStatsService.java
+++ b/services/usage/java/com/android/server/usage/StorageStatsService.java
@@ -86,6 +86,7 @@ import java.util.function.Consumer;
public class StorageStatsService extends IStorageStatsManager.Stub {
private static final String TAG = "StorageStatsService";
+ private static final String PROP_STORAGE_CRATES = "fw.storage_crates";
private static final String PROP_DISABLE_QUOTA = "fw.disable_quota";
private static final String PROP_VERIFY_STORAGE = "fw.verify_storage";
@@ -595,6 +596,13 @@ public class StorageStatsService extends IStorageStatsManager.Stub {
Uri.parse("content://com.android.externalstorage.documents/"), null, false);
}
+ private static void checkCratesEnable() {
+ final boolean enable = SystemProperties.getBoolean(PROP_STORAGE_CRATES, false);
+ if (!enable) {
+ throw new IllegalStateException("Storage Crate feature is disabled.");
+ }
+ }
+
/**
* To enforce the calling or self to have the {@link android.Manifest.permission#MANAGE_CRATES}
* permission.
@@ -650,6 +658,7 @@ public class StorageStatsService extends IStorageStatsManager.Stub {
@Override
public ParceledListSlice<CrateInfo> queryCratesForPackage(String volumeUuid,
@NonNull String packageName, @UserIdInt int userId, @NonNull String callingPackage) {
+ checkCratesEnable();
if (userId != UserHandle.getCallingUserId()) {
mContext.enforceCallingOrSelfPermission(
android.Manifest.permission.INTERACT_ACROSS_USERS, TAG);
@@ -677,6 +686,7 @@ public class StorageStatsService extends IStorageStatsManager.Stub {
@Override
public ParceledListSlice<CrateInfo> queryCratesForUid(String volumeUuid, int uid,
@NonNull String callingPackage) {
+ checkCratesEnable();
final int userId = UserHandle.getUserId(uid);
if (userId != UserHandle.getCallingUserId()) {
mContext.enforceCallingOrSelfPermission(
@@ -718,6 +728,7 @@ public class StorageStatsService extends IStorageStatsManager.Stub {
@Override
public ParceledListSlice<CrateInfo> queryCratesForUser(String volumeUuid, int userId,
@NonNull String callingPackage) {
+ checkCratesEnable();
if (userId != UserHandle.getCallingUserId()) {
mContext.enforceCallingOrSelfPermission(
android.Manifest.permission.INTERACT_ACROSS_USERS, TAG);
diff --git a/telecomm/java/android/telecom/Connection.java b/telecomm/java/android/telecom/Connection.java
index 3564add65113..4604cd2e2e75 100755
--- a/telecomm/java/android/telecom/Connection.java
+++ b/telecomm/java/android/telecom/Connection.java
@@ -3576,7 +3576,7 @@ public abstract class Connection extends Conferenceable {
* ATIS-1000082.
* @return the verification status.
*/
- public @VerificationStatus int getCallerNumberVerificationStatus() {
+ public final @VerificationStatus int getCallerNumberVerificationStatus() {
return mCallerNumberVerificationStatus;
}
@@ -3588,7 +3588,7 @@ public abstract class Connection extends Conferenceable {
* by
* {@link ConnectionService#onCreateIncomingConnection(PhoneAccountHandle, ConnectionRequest)}.
*/
- public void setCallerNumberVerificationStatus(
+ public final void setCallerNumberVerificationStatus(
@VerificationStatus int callerNumberVerificationStatus) {
mCallerNumberVerificationStatus = callerNumberVerificationStatus;
}
diff --git a/telephony/java/android/telephony/Annotation.java b/telephony/java/android/telephony/Annotation.java
index a27c4802c306..9ae86c8c586b 100644
--- a/telephony/java/android/telephony/Annotation.java
+++ b/telephony/java/android/telephony/Annotation.java
@@ -432,7 +432,7 @@ public class Annotation {
DataFailCause.LIMITED_TO_IPV6,
DataFailCause.VSNCP_TIMEOUT,
DataFailCause.VSNCP_GEN_ERROR,
- DataFailCause.VSNCP_APN_UNATHORIZED,
+ DataFailCause.VSNCP_APN_UNAUTHORIZED,
DataFailCause.VSNCP_PDN_LIMIT_EXCEEDED,
DataFailCause.VSNCP_NO_PDN_GATEWAY_ADDRESS,
DataFailCause.VSNCP_PDN_GATEWAY_UNREACHABLE,
diff --git a/telephony/java/android/telephony/CarrierConfigManager.java b/telephony/java/android/telephony/CarrierConfigManager.java
index 5c6ca4574397..a7e52ea21758 100755
--- a/telephony/java/android/telephony/CarrierConfigManager.java
+++ b/telephony/java/android/telephony/CarrierConfigManager.java
@@ -36,6 +36,8 @@ import android.telephony.ims.ImsReasonInfo;
import com.android.internal.telephony.ICarrierConfigLoader;
import com.android.telephony.Rlog;
+import java.util.concurrent.TimeUnit;
+
/**
* Provides access to telephony configuration values that are carrier-specific.
*/
@@ -2479,6 +2481,21 @@ public class CarrierConfigManager {
"parameters_use_for_5g_nr_signal_bar_int";
/**
+ * String array of default bandwidth values per network type.
+ * The entries should be of form "network_name:downstream,upstream", with values in Kbps.
+ * @hide
+ */
+ public static final String KEY_BANDWIDTH_STRING_ARRAY = "bandwidth_string_array";
+
+ /**
+ * For NR (non-standalone), whether to use the LTE value instead of NR value as the default for
+ * upstream bandwidth. Downstream bandwidth will still use the NR value as the default.
+ * @hide
+ */
+ public static final String KEY_BANDWIDTH_NR_NSA_USE_LTE_VALUE_FOR_UPSTREAM_BOOL =
+ "bandwidth_nr_nsa_use_lte_value_for_upstream_bool";
+
+ /**
* Key identifying if voice call barring notification is required to be shown to the user.
* @hide
*/
@@ -2980,6 +2997,33 @@ public class CarrierConfigManager {
"5g_icon_display_grace_period_sec_int";
/**
+ * Controls time in milliseconds until DcTracker reevaluates 5G connection state.
+ */
+ public static final String KEY_5G_WATCHDOG_TIME_MS_LONG = "5g_watchdog_time_long";
+
+ /**
+ * Whether NR (non-standalone) should be unmetered for all frequencies.
+ * If either {@link #KEY_UNMETERED_NR_NSA_MMWAVE_BOOL} or
+ * {@link #KEY_UNMETERED_NR_NSA_SUB6_BOOL} are true, then this value will be ignored.
+ * @hide
+ */
+ public static final String KEY_UNMETERED_NR_NSA_BOOL = "unmetered_nr_nsa_bool";
+
+ /**
+ * Whether NR (non-standalone) frequencies above 6GHz (millimeter wave) should be unmetered.
+ * If this is true, then the value for {@link #KEY_UNMETERED_NR_NSA_BOOL} will be ignored.
+ * @hide
+ */
+ public static final String KEY_UNMETERED_NR_NSA_MMWAVE_BOOL = "unmetered_nr_nsa_mmwave_bool";
+
+ /**
+ * Whether NR (non-standalone) frequencies below 6GHz (sub6) should be unmetered.
+ * If this is true, then the value for {@link #KEY_UNMETERED_NR_NSA_BOOL} will be ignored.
+ * @hide
+ */
+ public static final String KEY_UNMETERED_NR_NSA_SUB6_BOOL = "unmetered_nr_nsa_sub6_bool";
+
+ /**
* Support ASCII 7-BIT encoding for long SMS. This carrier config is used to enable
* this feature.
* @hide
@@ -3051,11 +3095,6 @@ public class CarrierConfigManager {
"ping_test_before_data_switch_bool";
/**
- * Controls time in milliseconds until DcTracker reevaluates 5G connection state.
- */
- public static final String KEY_5G_WATCHDOG_TIME_MS_LONG =
- "5g_watchdog_time_long";
- /**
* Controls whether to switch data to primary from opportunistic subscription
* if primary is out of service. This control only affects system or 1st party app
* initiated data switch, but will not override data switch initiated by privileged carrier apps
@@ -3931,6 +3970,13 @@ public class CarrierConfigManager {
});
sDefaults.putInt(KEY_PARAMETERS_USE_FOR_5G_NR_SIGNAL_BAR_INT,
CellSignalStrengthNr.USE_SSRSRP);
+ sDefaults.putStringArray(KEY_BANDWIDTH_STRING_ARRAY, new String[]{
+ "GPRS:24,24", "EDGE:70,18", "UMTS:115,115", "CDMA-IS95A:14,14", "CDMA-IS95B:14,14",
+ "1xRTT:30,30", "EvDo-rev.0:750,48", "EvDo-rev.A:950,550", "HSDPA:4300,620",
+ "HSUPA:4300,1800", "HSPA:4300,1800", "EvDo-rev.B:1500,550:", "eHRPD:750,48",
+ "HSPAP:13000,3400", "TD-SCDMA:115,115", "LTE:30000,15000", "NR_NSA:47000,15000",
+ "NR_NSA_MMWAVE:145000,15000", "NR_SA:145000,15000"});
+ sDefaults.putBoolean(KEY_BANDWIDTH_NR_NSA_USE_LTE_VALUE_FOR_UPSTREAM_BOOL, false);
sDefaults.putString(KEY_WCDMA_DEFAULT_SIGNAL_STRENGTH_MEASUREMENT_STRING, "rssi");
sDefaults.putBoolean(KEY_CONFIG_SHOW_ORIG_DIAL_STRING_FOR_CDMA_BOOL, false);
sDefaults.putBoolean(KEY_SHOW_CALL_BLOCKING_DISABLED_NOTIFICATION_ALWAYS_BOOL, false);
@@ -3946,6 +3992,11 @@ public class CarrierConfigManager {
sDefaults.putString(KEY_5G_ICON_CONFIGURATION_STRING,
"connected_mmwave:5G,connected:5G");
sDefaults.putInt(KEY_5G_ICON_DISPLAY_GRACE_PERIOD_SEC_INT, 0);
+ /* Default value is 1 hour. */
+ sDefaults.putLong(KEY_5G_WATCHDOG_TIME_MS_LONG, 3600000);
+ sDefaults.putBoolean(KEY_UNMETERED_NR_NSA_BOOL, false);
+ sDefaults.putBoolean(KEY_UNMETERED_NR_NSA_MMWAVE_BOOL, false);
+ sDefaults.putBoolean(KEY_UNMETERED_NR_NSA_SUB6_BOOL, false);
sDefaults.putBoolean(KEY_ASCII_7_BIT_SUPPORT_FOR_LONG_MESSAGE_BOOL, false);
/* Default value is minimum RSRP level needed for SIGNAL_STRENGTH_GOOD */
sDefaults.putInt(KEY_OPPORTUNISTIC_NETWORK_ENTRY_THRESHOLD_RSRP_INT, -108);
@@ -3964,8 +4015,6 @@ public class CarrierConfigManager {
/* Default value is 3 seconds. */
sDefaults.putLong(KEY_OPPORTUNISTIC_NETWORK_DATA_SWITCH_EXIT_HYSTERESIS_TIME_LONG, 3000);
sDefaults.putBoolean(KEY_PING_TEST_BEFORE_DATA_SWITCH_BOOL, true);
- /* Default value is 1 hour. */
- sDefaults.putLong(KEY_5G_WATCHDOG_TIME_MS_LONG, 3600000);
sDefaults.putBoolean(KEY_SWITCH_DATA_TO_PRIMARY_IF_PRIMARY_IS_OOS_BOOL, true);
/* Default value is 60 seconds. */
sDefaults.putLong(KEY_OPPORTUNISTIC_NETWORK_PING_PONG_TIME_LONG, 60000);
@@ -4007,7 +4056,7 @@ public class CarrierConfigManager {
sDefaults.putAll(Wifi.getDefaults());
sDefaults.putBoolean(ENABLE_EAP_METHOD_PREFIX_BOOL, false);
sDefaults.putBoolean(KEY_SHOW_FORWARDED_NUMBER_BOOL, false);
- sDefaults.putLong(KEY_DATA_SWITCH_VALIDATION_MIN_GAP_LONG, 0);
+ sDefaults.putLong(KEY_DATA_SWITCH_VALIDATION_MIN_GAP_LONG, TimeUnit.DAYS.toMillis(1));
}
/**
diff --git a/telephony/java/android/telephony/DataFailCause.java b/telephony/java/android/telephony/DataFailCause.java
index e1c4bef0dd65..8b7a243c30e6 100644
--- a/telephony/java/android/telephony/DataFailCause.java
+++ b/telephony/java/android/telephony/DataFailCause.java
@@ -30,10 +30,8 @@ import java.util.Map;
import java.util.Set;
/**
- * Returned as the reason for a data connection failure as defined by modem and some local errors.
- * @hide
+ * DataFailCause collects data connection failure causes code from different sources.
*/
-@SystemApi
public final class DataFailCause {
/** There is no failure */
public static final int NONE = 0;
@@ -841,8 +839,19 @@ public final class DataFailCause {
/**
* Data call bring up fails in the VSNCP phase due to a network rejection of the VSNCP
* configuration request because the requested APN is unauthorized.
+ *
+ * @deprecated Use {@link #VSNCP_APN_UNAUTHORIZED} instead.
+ *
+ * @hide
+ */
+ @SystemApi
+ @Deprecated
+ public static final int VSNCP_APN_UNATHORIZED = 0x8BE; // NOTYPO
+ /**
+ * Data call bring up fails in the VSNCP phase due to a network rejection of the VSNCP
+ * configuration request because the requested APN is unauthorized.
*/
- public static final int VSNCP_APN_UNATHORIZED = 0x8BE;
+ public static final int VSNCP_APN_UNAUTHORIZED = 0x8BE;
/**
* Data call bring up fails in the VSNCP phase due to a network rejection of the VSNCP
* configuration request because the PDN limit has been exceeded.
@@ -1318,6 +1327,7 @@ public final class DataFailCause {
sFailCauseMap.put(VSNCP_TIMEOUT, "VSNCP_TIMEOUT");
sFailCauseMap.put(VSNCP_GEN_ERROR, "VSNCP_GEN_ERROR");
sFailCauseMap.put(VSNCP_APN_UNATHORIZED, "VSNCP_APN_UNATHORIZED");
+ sFailCauseMap.put(VSNCP_APN_UNAUTHORIZED, "VSNCP_APN_UNAUTHORIZED");
sFailCauseMap.put(VSNCP_PDN_LIMIT_EXCEEDED, "VSNCP_PDN_LIMIT_EXCEEDED");
sFailCauseMap.put(VSNCP_NO_PDN_GATEWAY_ADDRESS, "VSNCP_NO_PDN_GATEWAY_ADDRESS");
sFailCauseMap.put(VSNCP_PDN_GATEWAY_UNREACHABLE, "VSNCP_PDN_GATEWAY_UNREACHABLE");
@@ -1423,8 +1433,8 @@ public final class DataFailCause {
if (configManager != null) {
PersistableBundle b = configManager.getConfigForSubId(subId);
if (b != null) {
- String[] permanentFailureStrings = b.getStringArray(CarrierConfigManager.
- KEY_CARRIER_DATA_CALL_PERMANENT_FAILURE_STRINGS);
+ String[] permanentFailureStrings = b.getStringArray(CarrierConfigManager
+ .KEY_CARRIER_DATA_CALL_PERMANENT_FAILURE_STRINGS);
if (permanentFailureStrings != null) {
permanentFailureSet = new HashSet<>();
for (Map.Entry<Integer, String> e : sFailCauseMap.entrySet()) {
diff --git a/telephony/java/android/telephony/PreciseDataConnectionState.java b/telephony/java/android/telephony/PreciseDataConnectionState.java
index 708adebb6db3..e37a9b9e7a8c 100644
--- a/telephony/java/android/telephony/PreciseDataConnectionState.java
+++ b/telephony/java/android/telephony/PreciseDataConnectionState.java
@@ -257,8 +257,7 @@ public final class PreciseDataConnectionState implements Parcelable {
* Return the cause code for the most recent change in {@link #getState}. In the event of an
* error, this cause code will be non-zero.
*/
- // FIXME(b144774287): some of these cause codes should have a prescribed meaning.
- public int getLastCauseCode() {
+ public @DataFailureCause int getLastCauseCode() {
return mFailCause;
}
diff --git a/telephony/java/com/android/internal/telephony/DctConstants.java b/telephony/java/com/android/internal/telephony/DctConstants.java
index 1449a62fbf35..f61d4e14f1d3 100644
--- a/telephony/java/com/android/internal/telephony/DctConstants.java
+++ b/telephony/java/com/android/internal/telephony/DctConstants.java
@@ -114,6 +114,7 @@ public class DctConstants {
public static final int EVENT_SERVICE_STATE_CHANGED = BASE + 52;
public static final int EVENT_5G_TIMER_HYSTERESIS = BASE + 53;
public static final int EVENT_5G_TIMER_WATCHDOG = BASE + 54;
+ public static final int EVENT_UPDATE_CARRIER_CONFIGS = BASE + 55;
/***** Constants *****/
@@ -123,4 +124,6 @@ public class DctConstants {
public static final String APN_TYPE_KEY = "apnType";
public static final String PROVISIONING_URL_KEY = "provisioningUrl";
+ public static final String BANDWIDTH_SOURCE_MODEM_KEY = "modem";
+ public static final String BANDWIDTH_SOURCE_CARRIER_CONFIG_KEY = "carrier_config";
}
diff --git a/test-mock/src/android/test/mock/MockContentProvider.java b/test-mock/src/android/test/mock/MockContentProvider.java
index f7ec11c79476..d1d64d39b688 100644
--- a/test-mock/src/android/test/mock/MockContentProvider.java
+++ b/test-mock/src/android/test/mock/MockContentProvider.java
@@ -156,6 +156,12 @@ public class MockContentProvider extends ContentProvider {
}
@Override
+ public void canonicalizeAsync(String callingPkg, String featureId, Uri uri,
+ RemoteCallback callback) {
+ MockContentProvider.this.canonicalizeAsync(uri, callback);
+ }
+
+ @Override
public Uri uncanonicalize(String callingPkg, @Nullable String featureId, Uri uri)
throws RemoteException {
return MockContentProvider.this.uncanonicalize(uri);
@@ -292,6 +298,18 @@ public class MockContentProvider extends ContentProvider {
/**
* @hide
*/
+ @SuppressWarnings("deprecation")
+ public void canonicalizeAsync(Uri uri, RemoteCallback callback) {
+ AsyncTask.SERIAL_EXECUTOR.execute(() -> {
+ final Bundle bundle = new Bundle();
+ bundle.putParcelable(ContentResolver.REMOTE_CALLBACK_RESULT, canonicalize(uri));
+ callback.sendResult(bundle);
+ });
+ }
+
+ /**
+ * @hide
+ */
public boolean refresh(Uri url, Bundle args) {
throw new UnsupportedOperationException("unimplemented mock method call");
}
diff --git a/test-mock/src/android/test/mock/MockContext.java b/test-mock/src/android/test/mock/MockContext.java
index 359c44849634..2c6604759813 100644
--- a/test-mock/src/android/test/mock/MockContext.java
+++ b/test-mock/src/android/test/mock/MockContext.java
@@ -834,6 +834,12 @@ public class MockContext extends Context {
/** @hide */
@Override
+ public Display getDisplayNoVerify() {
+ throw new UnsupportedOperationException();
+ }
+
+ /** @hide */
+ @Override
public int getDisplayId() {
throw new UnsupportedOperationException();
}
diff --git a/test-mock/src/android/test/mock/MockIContentProvider.java b/test-mock/src/android/test/mock/MockIContentProvider.java
index 1831bcdf9df7..223bcc59039d 100644
--- a/test-mock/src/android/test/mock/MockIContentProvider.java
+++ b/test-mock/src/android/test/mock/MockIContentProvider.java
@@ -145,12 +145,23 @@ public class MockIContentProvider implements IContentProvider {
}
@Override
- public Uri canonicalize(String callingPkg, @Nullable String featureId, Uri uri)
- throws RemoteException {
+ public Uri canonicalize(String callingPkg, @Nullable String featureId, Uri uri) {
throw new UnsupportedOperationException("unimplemented mock method");
}
@Override
+ @SuppressWarnings("deprecation")
+ public void canonicalizeAsync(String callingPkg, String featureId, Uri uri,
+ RemoteCallback remoteCallback) {
+ AsyncTask.SERIAL_EXECUTOR.execute(() -> {
+ final Bundle bundle = new Bundle();
+ bundle.putParcelable(ContentResolver.REMOTE_CALLBACK_RESULT,
+ canonicalize(callingPkg, featureId, uri));
+ remoteCallback.sendResult(bundle);
+ });
+ }
+
+ @Override
public Uri uncanonicalize(String callingPkg, @Nullable String featureId, Uri uri)
throws RemoteException {
throw new UnsupportedOperationException("unimplemented mock method");
diff --git a/tests/BootImageProfileTest/TEST_MAPPING b/tests/BootImageProfileTest/DISABLED_TEST_MAPPING
index 1b569f9455bf..1b569f9455bf 100644
--- a/tests/BootImageProfileTest/TEST_MAPPING
+++ b/tests/BootImageProfileTest/DISABLED_TEST_MAPPING
diff --git a/tests/RollbackTest/MultiUserRollbackTest/src/com/android/tests/rollback/host/MultiUserRollbackTest.java b/tests/RollbackTest/MultiUserRollbackTest/src/com/android/tests/rollback/host/MultiUserRollbackTest.java
index 52f6eba4072b..e616ac46830f 100644
--- a/tests/RollbackTest/MultiUserRollbackTest/src/com/android/tests/rollback/host/MultiUserRollbackTest.java
+++ b/tests/RollbackTest/MultiUserRollbackTest/src/com/android/tests/rollback/host/MultiUserRollbackTest.java
@@ -27,6 +27,8 @@ import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
+import java.util.concurrent.TimeUnit;
+
/**
* Runs rollback tests for multiple users.
*/
@@ -41,7 +43,6 @@ public class MultiUserRollbackTest extends BaseHostJUnit4Test {
@After
public void tearDown() throws Exception {
- getDevice().switchUser(mOriginalUserId);
getDevice().executeShellCommand("pm uninstall com.android.cts.install.lib.testapp.A");
removeSecondaryUserIfNecessary();
}
@@ -49,9 +50,9 @@ public class MultiUserRollbackTest extends BaseHostJUnit4Test {
@Before
public void setup() throws Exception {
mOriginalUserId = getDevice().getCurrentUser();
- installPackageAsUser("RollbackTest.apk", true, mOriginalUserId);
- createAndSwitchToSecondaryUserIfNecessary();
- installPackageAsUser("RollbackTest.apk", true, mSecondaryUserId);
+ createAndStartSecondaryUser();
+ // TODO(b/149733368): Remove the '-g' workaround when the bug is fixed.
+ installPackage("RollbackTest.apk", "-g --user all");
}
@Test
@@ -64,7 +65,6 @@ public class MultiUserRollbackTest extends BaseHostJUnit4Test {
runPhaseForUsers("testMultipleUsersInstallV1", mOriginalUserId, mSecondaryUserId);
runPhaseForUsers("testMultipleUsersUpgradeToV2", mOriginalUserId);
runPhaseForUsers("testMultipleUsersUpdateUserData", mOriginalUserId, mSecondaryUserId);
- switchToUser(mOriginalUserId);
getDevice().executeShellCommand("pm rollback-app com.android.cts.install.lib.testapp.A");
runPhaseForUsers("testMultipleUsersVerifyUserdataRollback", mOriginalUserId,
mSecondaryUserId);
@@ -74,11 +74,11 @@ public class MultiUserRollbackTest extends BaseHostJUnit4Test {
* Run the phase for the given user ids, in the order they are given.
*/
private void runPhaseForUsers(String phase, int... userIds) throws Exception {
+ final long timeout = TimeUnit.MINUTES.toMillis(10);
for (int userId: userIds) {
- switchToUser(userId);
- assertTrue(runDeviceTests("com.android.tests.rollback",
+ assertTrue(runDeviceTests(getDevice(), "com.android.tests.rollback",
"com.android.tests.rollback.MultiUserRollbackTest",
- phase));
+ phase, userId, timeout));
}
}
@@ -89,21 +89,7 @@ public class MultiUserRollbackTest extends BaseHostJUnit4Test {
}
}
- private void createAndSwitchToSecondaryUserIfNecessary() throws Exception {
- if (mSecondaryUserId == -1) {
- mOriginalUserId = getDevice().getCurrentUser();
- mSecondaryUserId = getDevice().createUser("MultiUserRollbackTest_User"
- + System.currentTimeMillis());
- switchToUser(mSecondaryUserId);
- }
- }
-
- private void switchToUser(int userId) throws Exception {
- if (getDevice().getCurrentUser() == userId) {
- return;
- }
-
- assertTrue(getDevice().switchUser(userId));
+ private void awaitUserUnlocked(int userId) throws Exception {
for (int i = 0; i < SWITCH_USER_COMPLETED_NUMBER_OF_POLLS; ++i) {
String userState = getDevice().executeShellCommand("am get-started-user-state "
+ userId);
@@ -112,6 +98,14 @@ public class MultiUserRollbackTest extends BaseHostJUnit4Test {
}
Thread.sleep(SWITCH_USER_COMPLETED_POLL_INTERVAL_IN_MILLIS);
}
- fail("User switch to user " + userId + " timed out");
+ fail("Timed out in unlocking user: " + userId);
+ }
+
+ private void createAndStartSecondaryUser() throws Exception {
+ String name = "MultiUserRollbackTest_User" + System.currentTimeMillis();
+ mSecondaryUserId = getDevice().createUser(name);
+ getDevice().startUser(mSecondaryUserId);
+ // Note we can't install apps on a locked user
+ awaitUserUnlocked(mSecondaryUserId);
}
}
diff --git a/tests/RollbackTest/RollbackTest/src/com/android/tests/rollback/MultiUserRollbackTest.java b/tests/RollbackTest/RollbackTest/src/com/android/tests/rollback/MultiUserRollbackTest.java
index 0ffe041b0377..400bb04f0fab 100644
--- a/tests/RollbackTest/RollbackTest/src/com/android/tests/rollback/MultiUserRollbackTest.java
+++ b/tests/RollbackTest/RollbackTest/src/com/android/tests/rollback/MultiUserRollbackTest.java
@@ -17,13 +17,11 @@
package com.android.tests.rollback;
import static com.android.cts.rollback.lib.RollbackInfoSubject.assertThat;
-import static com.android.cts.rollback.lib.RollbackUtils.getUniqueRollbackInfoForPackage;
import static com.google.common.truth.Truth.assertThat;
import android.Manifest;
import android.content.rollback.RollbackInfo;
-import android.content.rollback.RollbackManager;
import com.android.cts.install.lib.Install;
import com.android.cts.install.lib.InstallUtils;
@@ -77,13 +75,10 @@ public class MultiUserRollbackTest {
*/
@Test
public void testMultipleUsersUpgradeToV2() throws Exception {
- RollbackManager rm = RollbackUtils.getRollbackManager();
assertThat(InstallUtils.getInstalledVersion(TestApp.A)).isEqualTo(1);
Install.single(TestApp.A2).setEnableRollback().commit();
assertThat(InstallUtils.getInstalledVersion(TestApp.A)).isEqualTo(2);
- RollbackInfo rollback = getUniqueRollbackInfoForPackage(
- rm.getAvailableRollbacks(), TestApp.A);
- assertThat(rollback).isNotNull();
+ RollbackInfo rollback = RollbackUtils.waitForAvailableRollback(TestApp.A);
assertThat(rollback).packagesContainsExactly(
Rollback.from(TestApp.A2).to(TestApp.A1));
}
diff --git a/tests/net/AndroidManifest.xml b/tests/net/AndroidManifest.xml
index 638b6d1d7b5a..480b12be91c8 100644
--- a/tests/net/AndroidManifest.xml
+++ b/tests/net/AndroidManifest.xml
@@ -50,6 +50,7 @@
<application>
<uses-library android:name="android.test.runner" />
+ <uses-library android:name="android.net.ipsec.ike" />
</application>
<instrumentation
diff --git a/tests/net/integration/src/com/android/server/net/integrationtests/TestNetworkStackService.kt b/tests/net/integration/src/com/android/server/net/integrationtests/TestNetworkStackService.kt
index 490c46794e3d..23caf4952991 100644
--- a/tests/net/integration/src/com/android/server/net/integrationtests/TestNetworkStackService.kt
+++ b/tests/net/integration/src/com/android/server/net/integrationtests/TestNetworkStackService.kt
@@ -26,6 +26,7 @@ import android.net.util.SharedLog
import android.os.IBinder
import com.android.networkstack.metrics.DataStallStatsUtils
import com.android.networkstack.netlink.TcpSocketTracker
+import com.android.server.NetworkStackService
import com.android.server.NetworkStackService.NetworkMonitorConnector
import com.android.server.NetworkStackService.NetworkStackConnector
import com.android.server.connectivity.NetworkMonitor
@@ -88,6 +89,7 @@ class TestNetworkStackService : Service() {
val nm = NetworkMonitor(this@TestNetworkStackService, cb,
this.network,
mock(IpConnectivityLog::class.java), mock(SharedLog::class.java),
+ mock(NetworkStackService.NetworkStackServiceManager::class.java),
NetworkMonitorDeps(privateDnsBypassNetwork),
mock(DataStallStatsUtils::class.java),
mock(TcpSocketTracker::class.java))
diff --git a/tests/net/java/com/android/server/ConnectivityServiceTest.java b/tests/net/java/com/android/server/ConnectivityServiceTest.java
index 220cdce0d178..6d4a1b265171 100644
--- a/tests/net/java/com/android/server/ConnectivityServiceTest.java
+++ b/tests/net/java/com/android/server/ConnectivityServiceTest.java
@@ -1180,6 +1180,10 @@ public class ConnectivityServiceTest {
Arrays.asList(new UserInfo[] {
new UserInfo(VPN_USER, "", 0),
}));
+ final ApplicationInfo applicationInfo = new ApplicationInfo();
+ applicationInfo.targetSdkVersion = Build.VERSION_CODES.Q;
+ when(mPackageManager.getApplicationInfoAsUser(anyString(), anyInt(), any()))
+ .thenReturn(applicationInfo);
// InstrumentationTestRunner prepares a looper, but AndroidJUnitRunner does not.
// http://b/25897652 .
@@ -3042,7 +3046,7 @@ public class ConnectivityServiceTest {
networkCapabilities.addTransportType(TRANSPORT_WIFI)
.setNetworkSpecifier(new MatchAllNetworkSpecifier());
mService.requestNetwork(networkCapabilities, null, 0, null,
- ConnectivityManager.TYPE_WIFI, TEST_PACKAGE_NAME);
+ ConnectivityManager.TYPE_WIFI, mContext.getPackageName());
});
class NonParcelableSpecifier extends NetworkSpecifier {
@@ -6439,17 +6443,89 @@ public class ConnectivityServiceTest {
assertEquals(wifiLp, mService.getActiveLinkProperties());
}
+ private void setupLocationPermissions(
+ int targetSdk, boolean locationToggle, String op, String perm) throws Exception {
+ final ApplicationInfo applicationInfo = new ApplicationInfo();
+ applicationInfo.targetSdkVersion = targetSdk;
+ when(mPackageManager.getApplicationInfoAsUser(anyString(), anyInt(), any()))
+ .thenReturn(applicationInfo);
+
+ when(mLocationManager.isLocationEnabledForUser(any())).thenReturn(locationToggle);
+
+ if (op != null) {
+ when(mAppOpsManager.noteOp(eq(op), eq(Process.myUid()), eq(mContext.getPackageName())))
+ .thenReturn(AppOpsManager.MODE_ALLOWED);
+ }
+
+ if (perm != null) {
+ mServiceContext.setPermission(perm, PERMISSION_GRANTED);
+ }
+ }
+
+ private int getOwnerUidNetCapsForCallerPermission(int ownerUid, int callerUid) {
+ final NetworkCapabilities netCap = new NetworkCapabilities().setOwnerUid(ownerUid);
+
+ return mService
+ .maybeSanitizeLocationInfoForCaller(netCap, callerUid, mContext.getPackageName())
+ .getOwnerUid();
+ }
+
+ @Test
+ public void testMaybeSanitizeLocationInfoForCallerWithFineLocationAfterQ() throws Exception {
+ setupLocationPermissions(Build.VERSION_CODES.Q, true, AppOpsManager.OPSTR_FINE_LOCATION,
+ Manifest.permission.ACCESS_FINE_LOCATION);
+
+ final int myUid = Process.myUid();
+ assertEquals(myUid, getOwnerUidNetCapsForCallerPermission(myUid, myUid));
+ }
+
+ @Test
+ public void testMaybeSanitizeLocationInfoForCallerWithCoarseLocationPreQ() throws Exception {
+ setupLocationPermissions(Build.VERSION_CODES.P, true, AppOpsManager.OPSTR_COARSE_LOCATION,
+ Manifest.permission.ACCESS_COARSE_LOCATION);
+
+ final int myUid = Process.myUid();
+ assertEquals(myUid, getOwnerUidNetCapsForCallerPermission(myUid, myUid));
+ }
+
+ @Test
+ public void testMaybeSanitizeLocationInfoForCallerLocationOff() throws Exception {
+ // Test that even with fine location permission, and UIDs matching, the UID is sanitized.
+ setupLocationPermissions(Build.VERSION_CODES.Q, false, AppOpsManager.OPSTR_FINE_LOCATION,
+ Manifest.permission.ACCESS_FINE_LOCATION);
+
+ final int myUid = Process.myUid();
+ assertEquals(Process.INVALID_UID, getOwnerUidNetCapsForCallerPermission(myUid, myUid));
+ }
+
+ @Test
+ public void testMaybeSanitizeLocationInfoForCallerWrongUid() throws Exception {
+ // Test that even with fine location permission, not being the owner leads to sanitization.
+ setupLocationPermissions(Build.VERSION_CODES.Q, true, AppOpsManager.OPSTR_FINE_LOCATION,
+ Manifest.permission.ACCESS_FINE_LOCATION);
+
+ final int myUid = Process.myUid();
+ assertEquals(Process.INVALID_UID, getOwnerUidNetCapsForCallerPermission(myUid + 1, myUid));
+ }
+
@Test
- public void testNetworkCapabilitiesRestrictedForCallerPermissions() {
- int callerUid = Process.myUid();
- final NetworkCapabilities originalNc = new NetworkCapabilities();
- originalNc.setOwnerUid(callerUid);
+ public void testMaybeSanitizeLocationInfoForCallerWithCoarseLocationAfterQ() throws Exception {
+ // Test that not having fine location permission leads to sanitization.
+ setupLocationPermissions(Build.VERSION_CODES.Q, true, AppOpsManager.OPSTR_COARSE_LOCATION,
+ Manifest.permission.ACCESS_COARSE_LOCATION);
+
+ // Test that without the location permission, the owner field is sanitized.
+ final int myUid = Process.myUid();
+ assertEquals(Process.INVALID_UID, getOwnerUidNetCapsForCallerPermission(myUid, myUid));
+ }
- final NetworkCapabilities newNc =
- mService.networkCapabilitiesRestrictedForCallerPermissions(
- originalNc, Process.myPid(), callerUid);
+ @Test
+ public void testMaybeSanitizeLocationInfoForCallerWithoutLocationPermission() throws Exception {
+ setupLocationPermissions(Build.VERSION_CODES.Q, true, null /* op */, null /* perm */);
- assertEquals(Process.INVALID_UID, newNc.getOwnerUid());
+ // Test that without the location permission, the owner field is sanitized.
+ final int myUid = Process.myUid();
+ assertEquals(Process.INVALID_UID, getOwnerUidNetCapsForCallerPermission(myUid, myUid));
}
private void setupConnectionOwnerUid(int vpnOwnerUid, @VpnManager.VpnType int vpnType)
@@ -6735,21 +6811,6 @@ public class ConnectivityServiceTest {
mContext.getOpPackageName()));
}
- private void setupLocationPermissions(
- int targetSdk, boolean locationToggle, String op, String perm) throws Exception {
- final ApplicationInfo applicationInfo = new ApplicationInfo();
- applicationInfo.targetSdkVersion = targetSdk;
- when(mPackageManager.getApplicationInfoAsUser(anyString(), anyInt(), any()))
- .thenReturn(applicationInfo);
-
- when(mLocationManager.isLocationEnabledForUser(any())).thenReturn(locationToggle);
-
- when(mAppOpsManager.noteOp(eq(op), eq(Process.myUid()), eq(mContext.getPackageName())))
- .thenReturn(AppOpsManager.MODE_ALLOWED);
-
- mServiceContext.setPermission(perm, PERMISSION_GRANTED);
- }
-
private void setUpConnectivityDiagnosticsCallback() throws Exception {
final NetworkRequest request = new NetworkRequest.Builder().build();
when(mConnectivityDiagnosticsCallback.asBinder()).thenReturn(mIBinder);
diff --git a/tests/utils/testutils/java/com/android/server/wm/test/filters/FrameworksTestsFilter.java b/tests/utils/testutils/java/com/android/server/wm/test/filters/FrameworksTestsFilter.java
index 957216e17925..26916bcffcfb 100644
--- a/tests/utils/testutils/java/com/android/server/wm/test/filters/FrameworksTestsFilter.java
+++ b/tests/utils/testutils/java/com/android/server/wm/test/filters/FrameworksTestsFilter.java
@@ -38,6 +38,7 @@ public final class FrameworksTestsFilter extends SelectTest {
"android.app.activity.ActivityThreadClientTest",
// Test specifications for FrameworksCoreTests.
"android.app.servertransaction.", // all tests under the package.
+ "android.view.CutoutSpecificationTest",
"android.view.DisplayCutoutTest",
"android.view.InsetsAnimationControlImplTest",
"android.view.InsetsControllerTest",
diff --git a/wifi/java/android/net/wifi/WifiOemMigrationHook.java b/wifi/java/android/net/wifi/WifiOemMigrationHook.java
index 44dbb98a8ab8..5301dd013363 100755
--- a/wifi/java/android/net/wifi/WifiOemMigrationHook.java
+++ b/wifi/java/android/net/wifi/WifiOemMigrationHook.java
@@ -437,7 +437,7 @@ public final class WifiOemMigrationHook {
Settings.Global.WIFI_SCAN_THROTTLE_ENABLED, 1) == 1)
.setVerboseLoggingEnabled(
Settings.Global.getInt(context.getContentResolver(),
- Settings.Global.WIFI_VERBOSE_LOGGING_ENABLED, 1) == 1)
+ Settings.Global.WIFI_VERBOSE_LOGGING_ENABLED, 0) == 1)
.build();
}
}