summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--Android.bp1
-rw-r--r--Android.mk5
-rw-r--r--StubLibraries.bp20
-rw-r--r--apex/blobstore/service/java/com/android/server/blob/BlobMetadata.java10
-rw-r--r--apex/blobstore/service/java/com/android/server/blob/BlobStoreManagerService.java21
-rw-r--r--apex/permission/framework/Android.bp9
-rw-r--r--apex/statsd/framework/Android.bp30
-rw-r--r--api/current.txt41
-rwxr-xr-xapi/system-current.txt13
-rw-r--r--cmds/content/src/com/android/commands/content/Content.java193
-rw-r--r--cmds/statsd/Android.bp1
-rw-r--r--cmds/statsd/src/atoms.proto60
-rw-r--r--cmds/statsd/src/metrics/MetricsManager.cpp2
-rw-r--r--cmds/statsd/src/metrics/MetricsManager.h4
-rw-r--r--cmds/statsd/src/metrics/metrics_manager_util.cpp13
-rw-r--r--cmds/statsd/src/metrics/metrics_manager_util.h1
-rw-r--r--cmds/statsd/src/statsd_metadata.proto63
-rw-r--r--cmds/statsd/tests/MetricsManager_test.cpp35
-rw-r--r--cmds/statsd/tests/metrics/EventMetricProducer_test.cpp152
-rw-r--r--cmds/statsd/tests/metrics/GaugeMetricProducer_test.cpp1465
-rw-r--r--cmds/statsd/tests/statsd_test_util.cpp14
-rw-r--r--cmds/statsd/tests/statsd_test_util.h2
-rw-r--r--core/java/android/app/AppOpsManager.java29
-rw-r--r--core/java/android/app/ApplicationExitInfo.java8
-rw-r--r--core/java/android/app/ContextImpl.java5
-rw-r--r--core/java/android/app/IActivityManager.aidl4
-rw-r--r--core/java/android/app/IActivityTaskManager.aidl4
-rw-r--r--core/java/android/app/ResourcesManager.java24
-rw-r--r--core/java/android/app/TaskEmbedder.java24
-rw-r--r--core/java/android/app/admin/DevicePolicyManager.java8
-rw-r--r--core/java/android/app/admin/FactoryResetProtectionPolicy.java18
-rw-r--r--core/java/android/content/ContentProvider.java38
-rw-r--r--core/java/android/content/pm/CrossProfileApps.java28
-rw-r--r--core/java/android/content/pm/ICrossProfileApps.aidl1
-rw-r--r--core/java/android/content/pm/PackageInstaller.java7
-rw-r--r--core/java/android/hardware/biometrics/IBiometricServiceReceiverInternal.aidl4
-rw-r--r--core/java/android/inputmethodservice/InputMethodService.java5
-rw-r--r--core/java/android/os/Process.java12
-rw-r--r--core/java/android/os/RecoverySystem.java17
-rw-r--r--core/java/android/os/ZygoteProcess.java38
-rw-r--r--core/java/android/os/storage/StorageManager.java7
-rw-r--r--core/java/android/provider/Settings.java7
-rw-r--r--core/java/android/service/autofill/InlinePresentation.java3
-rw-r--r--core/java/android/service/controls/actions/ControlAction.java3
-rw-r--r--core/java/android/view/Display.java14
-rw-r--r--core/java/android/view/SurfaceControlViewHost.java1
-rw-r--r--core/java/android/view/View.java2
-rw-r--r--core/java/android/view/ViewConfiguration.java6
-rw-r--r--core/java/android/view/WindowManagerImpl.java9
-rw-r--r--core/java/android/view/WindowMetrics.java31
-rw-r--r--core/java/android/view/autofill/AutofillManager.java3
-rw-r--r--core/java/android/view/autofill/AutofillPopupWindow.java7
-rw-r--r--core/java/com/android/internal/accessibility/AccessibilityShortcutController.java7
-rw-r--r--core/java/com/android/internal/app/AbstractMultiProfilePagerAdapter.java15
-rw-r--r--core/java/com/android/internal/app/AccessibilityButtonChooserActivity.java32
-rw-r--r--core/java/com/android/internal/app/ChooserActivity.java2
-rw-r--r--core/java/com/android/internal/os/Zygote.java29
-rw-r--r--core/java/com/android/internal/os/ZygoteArguments.java15
-rw-r--r--core/java/com/android/internal/os/ZygoteConnection.java3
-rw-r--r--core/java/com/android/internal/view/menu/MenuPopupHelper.java8
-rw-r--r--core/jni/android_media_AudioProductStrategies.cpp21
-rw-r--r--core/jni/com_android_internal_os_Zygote.cpp109
-rw-r--r--core/proto/android/app/enums.proto4
-rw-r--r--core/res/AndroidManifest.xml19
-rw-r--r--core/res/res/layout/resolver_empty_states.xml2
-rw-r--r--core/res/res/values-h480dp/bools.xml2
-rw-r--r--core/res/res/values/attrs_manifest.xml3
-rw-r--r--core/res/res/values/bools.xml2
-rw-r--r--core/res/res/values/public.xml2
-rw-r--r--core/res/res/values/strings.xml5
-rw-r--r--core/res/res/values/symbols.xml2
-rw-r--r--core/tests/coretests/BstatsTestApp/src/com/android/coretests/apps/bstatstestapp/TestService.java8
-rw-r--r--core/tests/coretests/src/android/content/ContentResolverTest.java20
-rw-r--r--core/tests/coretests/src/android/content/FakeProviderRemote.java3
-rw-r--r--core/tests/coretests/src/android/content/res/ResourcesManagerTest.java4
-rw-r--r--core/tests/coretests/src/android/util/GridScenario.java2
-rw-r--r--core/tests/coretests/src/android/util/ListScenario.java2
-rw-r--r--core/tests/coretests/src/android/util/ScrollViewScenario.java2
-rw-r--r--core/tests/coretests/src/android/view/BigCache.java8
-rw-r--r--core/tests/coretests/src/android/view/ScaleGestureDetectorTest.java8
-rw-r--r--core/tests/coretests/src/android/view/WindowMetricsTest.java12
-rw-r--r--core/tests/coretests/src/android/view/menu/ContextMenuTest.java6
-rw-r--r--core/tests/coretests/src/android/widget/EditorCursorDragTest.java6
-rw-r--r--core/tests/coretests/src/android/widget/EditorTouchStateTest.java2
-rw-r--r--core/tests/coretests/src/android/widget/focus/ListOfInternalSelectionViews.java2
-rw-r--r--core/tests/coretests/src/android/widget/gridview/touch/GridTouchVerticalSpacingStackFromBottomTest.java4
-rw-r--r--core/tests/coretests/src/android/widget/listview/AdjacentListsWithAdjacentISVsInside.java2
-rw-r--r--core/tests/coretests/src/com/android/internal/accessibility/AccessibilityShortcutControllerTest.java35
-rw-r--r--media/java/android/media/AudioSystem.java2
-rw-r--r--media/java/android/media/audiopolicy/AudioProductStrategy.java4
-rw-r--r--media/jni/android_media_tv_Tuner.cpp42
-rw-r--r--media/jni/android_media_tv_Tuner.h1
-rw-r--r--media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/helpers/CameraTestUtils.java8
-rw-r--r--packages/FakeOemFeatures/src/com/android/fakeoemfeatures/FakeApp.java6
-rw-r--r--packages/FakeOemFeatures/src/com/android/fakeoemfeatures/FakeBackgroundService.java12
-rw-r--r--packages/PackageInstaller/src/com/android/packageinstaller/PackageInstallerActivity.java4
-rw-r--r--packages/SettingsLib/src/com/android/settingslib/accessibility/AccessibilityUtils.java13
-rw-r--r--packages/SettingsLib/src/com/android/settingslib/core/instrumentation/MetricsFeatureProvider.java16
-rw-r--r--packages/SettingsLib/src/com/android/settingslib/media/LocalMediaManager.java37
-rw-r--r--packages/SettingsLib/src/com/android/settingslib/wifi/WifiStatusTracker.java50
-rw-r--r--packages/SettingsLib/tests/robotests/src/com/android/settingslib/core/instrumentation/MetricsFeatureProviderTest.java32
-rw-r--r--packages/SettingsProvider/src/android/provider/settings/backup/SecureSettings.java1
-rw-r--r--packages/SettingsProvider/src/android/provider/settings/validators/SecureSettingsValidators.java3
-rw-r--r--packages/SettingsProvider/src/com/android/providers/settings/SettingsProtoDumpUtil.java3
-rw-r--r--packages/SettingsProvider/src/com/android/providers/settings/SettingsProvider.java19
-rw-r--r--packages/Shell/AndroidManifest.xml2
-rw-r--r--packages/Shell/src/com/android/shell/BugreportProgressService.java10
-rw-r--r--packages/SystemUI/res/layout/controls_base_item.xml4
-rw-r--r--packages/SystemUI/res/values/dimens.xml1
-rw-r--r--packages/SystemUI/res/values/strings.xml22
-rw-r--r--packages/SystemUI/shared/src/com/android/systemui/shared/system/ActivityManagerWrapper.java14
-rw-r--r--packages/SystemUI/src/com/android/keyguard/KeyguardUpdateMonitor.java39
-rw-r--r--packages/SystemUI/src/com/android/systemui/biometrics/AuthCredentialView.java79
-rw-r--r--packages/SystemUI/src/com/android/systemui/bubbles/BubbleData.java13
-rw-r--r--packages/SystemUI/src/com/android/systemui/controls/controller/ControlsControllerImpl.kt36
-rw-r--r--packages/SystemUI/src/com/android/systemui/controls/ui/ChallengeDialogs.kt78
-rw-r--r--packages/SystemUI/src/com/android/systemui/controls/ui/ControlViewHolder.kt7
-rw-r--r--packages/SystemUI/src/com/android/systemui/controls/ui/ControlsUiControllerImpl.kt10
-rw-r--r--packages/SystemUI/src/com/android/systemui/controls/ui/RenderInfo.kt2
-rw-r--r--packages/SystemUI/src/com/android/systemui/controls/ui/ToggleRangeBehavior.kt4
-rw-r--r--packages/SystemUI/src/com/android/systemui/keyguard/KeyguardSliceProvider.java3
-rw-r--r--packages/SystemUI/src/com/android/systemui/pip/phone/PipResizeGestureHandler.java4
-rw-r--r--packages/SystemUI/src/com/android/systemui/qs/QSPanel.java30
-rw-r--r--packages/SystemUI/src/com/android/systemui/recents/RecentsOnboarding.java6
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/phone/EdgeBackGestureHandler.java133
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/policy/WifiSignalController.java13
-rw-r--r--packages/SystemUI/tests/src/com/android/keyguard/KeyguardUpdateMonitorTest.java20
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/bubbles/BubbleControllerTest.java19
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/controls/controller/ControlsControllerImplTest.kt2
-rw-r--r--packages/Tethering/common/TetheringLib/Android.bp6
-rw-r--r--packages/Tethering/src/com/android/server/connectivity/tethering/Tethering.java52
-rw-r--r--packages/Tethering/src/com/android/server/connectivity/tethering/TetheringNotificationUpdater.java86
-rw-r--r--packages/Tethering/tests/unit/src/com/android/server/connectivity/tethering/TetheringNotificationUpdaterTest.kt262
-rw-r--r--packages/Tethering/tests/unit/src/com/android/server/connectivity/tethering/TetheringTest.java12
-rw-r--r--packages/WallpaperCropper/src/com/android/wallpapercropper/WallpaperCropActivity.java5
-rw-r--r--services/Android.bp5
-rw-r--r--services/accessibility/java/com/android/server/accessibility/AccessibilityManagerService.java11
-rw-r--r--services/autofill/java/com/android/server/autofill/ui/InlineSuggestionFactory.java3
-rw-r--r--services/core/java/com/android/server/BatteryService.java3
-rw-r--r--services/core/java/com/android/server/BluetoothManagerService.java133
-rw-r--r--services/core/java/com/android/server/NetworkManagementService.java1
-rw-r--r--services/core/java/com/android/server/StorageManagerService.java12
-rw-r--r--services/core/java/com/android/server/am/ActivityManagerService.java30
-rw-r--r--services/core/java/com/android/server/am/ProcessList.java74
-rw-r--r--services/core/java/com/android/server/audio/AudioService.java58
-rw-r--r--services/core/java/com/android/server/audio/RecordingActivityMonitor.java33
-rw-r--r--services/core/java/com/android/server/biometrics/AuthService.java11
-rw-r--r--services/core/java/com/android/server/biometrics/AuthenticationClient.java12
-rw-r--r--services/core/java/com/android/server/biometrics/BiometricService.java34
-rw-r--r--services/core/java/com/android/server/biometrics/BiometricServiceBase.java11
-rw-r--r--services/core/java/com/android/server/biometrics/face/FaceService.java5
-rw-r--r--services/core/java/com/android/server/biometrics/fingerprint/FingerprintService.java5
-rw-r--r--services/core/java/com/android/server/display/LocalDisplayAdapter.java8
-rw-r--r--services/core/java/com/android/server/input/InputManagerService.java6
-rw-r--r--services/core/java/com/android/server/lights/LightsManager.java4
-rw-r--r--services/core/java/com/android/server/lights/LightsService.java126
-rwxr-xr-xservices/core/java/com/android/server/notification/NotificationManagerService.java12
-rw-r--r--services/core/java/com/android/server/pm/ApexManager.java308
-rw-r--r--services/core/java/com/android/server/pm/CrossProfileAppsServiceImpl.java21
-rw-r--r--services/core/java/com/android/server/pm/PackageInstallerService.java8
-rw-r--r--services/core/java/com/android/server/pm/PackageInstallerSession.java3
-rw-r--r--services/core/java/com/android/server/pm/PackageManagerService.java4
-rw-r--r--services/core/java/com/android/server/pm/permission/PermissionManagerService.java14
-rw-r--r--services/core/java/com/android/server/policy/SoftRestrictedPermissionPolicy.java12
-rw-r--r--services/core/java/com/android/server/power/PowerManagerService.java4
-rw-r--r--services/core/java/com/android/server/power/ThermalManagerService.java6
-rw-r--r--services/core/java/com/android/server/timezonedetector/TimeZoneDetectorShellCommand.java8
-rw-r--r--services/core/java/com/android/server/wallpaper/WallpaperManagerService.java17
-rw-r--r--services/core/java/com/android/server/wm/ActivityRecord.java2
-rw-r--r--services/core/java/com/android/server/wm/ActivityStack.java15
-rw-r--r--services/core/java/com/android/server/wm/ActivityTaskManagerService.java14
-rw-r--r--services/core/java/com/android/server/wm/AppTransitionController.java1
-rw-r--r--services/core/java/com/android/server/wm/DisplayContent.java40
-rw-r--r--services/core/java/com/android/server/wm/DisplayRotation.java7
-rw-r--r--services/core/java/com/android/server/wm/InputMonitor.java21
-rw-r--r--services/core/java/com/android/server/wm/InsetsPolicy.java3
-rw-r--r--services/core/java/com/android/server/wm/RecentTasks.java24
-rw-r--r--services/core/java/com/android/server/wm/RecentsAnimation.java6
-rw-r--r--services/core/java/com/android/server/wm/RecentsAnimationController.java2
-rw-r--r--services/core/java/com/android/server/wm/RootWindowContainer.java31
-rw-r--r--services/core/java/com/android/server/wm/RunningTasks.java34
-rw-r--r--services/core/java/com/android/server/wm/Task.java3
-rw-r--r--services/core/java/com/android/server/wm/TaskOrganizerController.java81
-rw-r--r--services/core/java/com/android/server/wm/TaskPositioner.java5
-rw-r--r--services/core/java/com/android/server/wm/WallpaperController.java14
-rw-r--r--services/core/java/com/android/server/wm/WindowManagerService.java10
-rw-r--r--services/core/java/com/android/server/wm/WindowSurfacePlacer.java4
-rw-r--r--services/core/java/com/android/server/wm/WindowToken.java40
-rw-r--r--services/core/jni/com_android_server_input_InputManagerService.cpp63
-rw-r--r--services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java4
-rw-r--r--services/java/com/android/server/SystemServer.java5
-rw-r--r--services/people/java/com/android/server/people/data/DataManager.java31
-rw-r--r--services/people/java/com/android/server/people/data/UsageStatsQueryHelper.java58
-rw-r--r--services/people/java/com/android/server/people/prediction/ShareTargetPredictor.java59
-rw-r--r--services/people/java/com/android/server/people/prediction/SharesheetModelScorer.java406
-rw-r--r--services/robotests/src/com/android/server/pm/CrossProfileAppsServiceImplRoboTest.java18
-rw-r--r--services/tests/servicestests/src/com/android/server/biometrics/BiometricServiceTest.java75
-rw-r--r--services/tests/servicestests/src/com/android/server/people/data/UsageStatsQueryHelperTest.java81
-rw-r--r--services/tests/servicestests/src/com/android/server/people/prediction/ShareTargetPredictorTest.java25
-rw-r--r--services/tests/servicestests/src/com/android/server/people/prediction/SharesheetModelScorerTest.java406
-rw-r--r--services/tests/servicestests/src/com/android/server/pm/ApexManagerTest.java23
-rw-r--r--services/tests/servicestests/src/com/android/server/tv/tunerresourcemanager/TunerResourceManagerServiceTest.java2
-rw-r--r--services/tests/servicestests/src/com/android/server/tv/tunerresourcemanager/UseCasePriorityHintsTest.java2
-rw-r--r--services/tests/wmtests/src/com/android/server/wm/ActivityStackTests.java30
-rw-r--r--services/tests/wmtests/src/com/android/server/wm/AppTransitionTests.java4
-rw-r--r--services/tests/wmtests/src/com/android/server/wm/AppWindowTokenTests.java2
-rw-r--r--services/tests/wmtests/src/com/android/server/wm/RecentTasksTest.java34
-rw-r--r--services/tests/wmtests/src/com/android/server/wm/RecentsAnimationControllerTest.java6
-rw-r--r--services/tests/wmtests/src/com/android/server/wm/RootActivityContainerTests.java16
-rw-r--r--services/tests/wmtests/src/com/android/server/wm/RunningTasksTest.java20
-rw-r--r--services/tests/wmtests/src/com/android/server/wm/SizeCompatTests.java2
-rwxr-xr-xtelecomm/java/android/telecom/ConnectionService.java4
-rw-r--r--telephony/common/com/android/internal/telephony/TelephonyPermissions.java30
-rw-r--r--telephony/java/android/telephony/AccessNetworkConstants.java41
-rw-r--r--telephony/java/android/telephony/AccessNetworkUtils.java46
-rw-r--r--telephony/java/android/telephony/CellSignalStrengthCdma.java2
-rw-r--r--telephony/java/android/telephony/CellSignalStrengthGsm.java2
-rw-r--r--telephony/java/android/telephony/SmsManager.java2
-rw-r--r--telephony/java/android/telephony/SubscriptionManager.java18
-rw-r--r--test-runner/src/android/test/TouchUtils.java2
-rw-r--r--tests/AppLaunch/src/com/android/tests/applaunch/AppLaunch.java46
-rw-r--r--tests/BlobStoreTestUtils/src/com/android/utils/blob/DummyBlobData.java4
-rw-r--r--tests/MirrorSurfaceTest/src/com/google/android/test/mirrorsurface/MirrorSurfaceActivity.java5
-rw-r--r--wifi/java/android/net/wifi/SoftApConfiguration.java5
224 files changed, 4898 insertions, 2197 deletions
diff --git a/Android.bp b/Android.bp
index b0e0b35a1f76..7f4cd849ab77 100644
--- a/Android.bp
+++ b/Android.bp
@@ -722,6 +722,7 @@ filegroup {
srcs: [
"core/java/android/annotation/StringDef.java",
"core/java/android/net/annotations/PolicyDirection.java",
+ "core/java/com/android/internal/util/HexDump.java",
"core/java/com/android/internal/util/IState.java",
"core/java/com/android/internal/util/State.java",
"core/java/com/android/internal/util/StateMachine.java",
diff --git a/Android.mk b/Android.mk
index aea0c951052f..3b307146770e 100644
--- a/Android.mk
+++ b/Android.mk
@@ -39,11 +39,6 @@ INTERNAL_SDK_SOURCE_DIRS := $(addprefix $(LOCAL_PATH)/,$(dirs_to_document))
$(call dist-for-goals,sdk,$(INTERNAL_PLATFORM_API_FILE))
$(call dist-for-goals,sdk,$(INTERNAL_PLATFORM_SYSTEM_API_FILE))
$(call dist-for-goals,sdk,$(INTERNAL_PLATFORM_TEST_API_FILE))
-$(call dist-for-goals,sdk,$(INTERNAL_PLATFORM_API_FILE):apistubs/android/public/api/android.txt)
-$(call dist-for-goals,sdk,$(INTERNAL_PLATFORM_SYSTEM_API_FILE):apistubs/android/system/api/android.txt)
-$(call dist-for-goals,sdk,$(INTERNAL_PLATFORM_TEST_API_FILE):apistubs/android/test/api/android.txt)
-$(call dist-for-goals,sdk,$(INTERNAL_PLATFORM_MODULE_LIB_API_FILE):apistubs/android/module-lib/api/android.txt)
-$(call dist-for-goals,sdk,$(INTERNAL_PLATFORM_SYSTEM_SERVER_API_FILE):apistubs/android/system-server/api/android.txt)
# sdk.atree needs to copy the whole dir: $(OUT_DOCS)/offline-sdk to the final zip.
# So keep offline-sdk-timestamp target here, and unzip offline-sdk-docs.zip to
diff --git a/StubLibraries.bp b/StubLibraries.bp
index 12f211df4549..ccd873352a33 100644
--- a/StubLibraries.bp
+++ b/StubLibraries.bp
@@ -115,6 +115,11 @@ droidstubs {
baseline_file: "api/lint-baseline.txt",
},
},
+ dist: {
+ targets: ["sdk", "win_sdk"],
+ dir: "apistubs/android/public/api",
+ dest: "android.txt",
+ },
jdiff_enabled: true,
}
@@ -156,6 +161,11 @@ droidstubs {
baseline_file: "api/system-lint-baseline.txt",
},
},
+ dist: {
+ targets: ["sdk", "win_sdk"],
+ dir: "apistubs/android/system/api",
+ dest: "android.txt",
+ },
jdiff_enabled: true,
}
@@ -179,6 +189,11 @@ droidstubs {
baseline_file: "api/test-lint-baseline.txt",
},
},
+ dist: {
+ targets: ["sdk", "win_sdk"],
+ dir: "apistubs/android/test/api",
+ dest: "android.txt",
+ },
}
/////////////////////////////////////////////////////////////////////
@@ -214,6 +229,11 @@ droidstubs {
baseline_file: "api/module-lib-lint-baseline.txt",
},
},
+ dist: {
+ targets: ["sdk", "win_sdk"],
+ dir: "apistubs/android/module-lib/api",
+ dest: "android.txt",
+ },
}
diff --git a/apex/blobstore/service/java/com/android/server/blob/BlobMetadata.java b/apex/blobstore/service/java/com/android/server/blob/BlobMetadata.java
index e5a685f15df8..c8ca44b6ef74 100644
--- a/apex/blobstore/service/java/com/android/server/blob/BlobMetadata.java
+++ b/apex/blobstore/service/java/com/android/server/blob/BlobMetadata.java
@@ -116,7 +116,7 @@ class BlobMetadata {
return mUserId;
}
- void addCommitter(@NonNull Committer committer) {
+ void addOrReplaceCommitter(@NonNull Committer committer) {
synchronized (mMetadataLock) {
// We need to override the committer data, so first remove any existing
// committer before adding the new one.
@@ -139,6 +139,12 @@ class BlobMetadata {
}
}
+ void removeCommitter(@NonNull Committer committer) {
+ synchronized (mMetadataLock) {
+ mCommitters.remove(committer);
+ }
+ }
+
void removeInvalidCommitters(SparseArray<String> packages) {
synchronized (mMetadataLock) {
mCommitters.removeIf(committer ->
@@ -154,7 +160,7 @@ class BlobMetadata {
}
}
- void addLeasee(String callingPackage, int callingUid, int descriptionResId,
+ void addOrReplaceLeasee(String callingPackage, int callingUid, int descriptionResId,
CharSequence description, long leaseExpiryTimeMillis) {
synchronized (mMetadataLock) {
// We need to override the leasee data, so first remove any existing
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 65ccb997343b..e472d052f32f 100644
--- a/apex/blobstore/service/java/com/android/server/blob/BlobStoreManagerService.java
+++ b/apex/blobstore/service/java/com/android/server/blob/BlobStoreManagerService.java
@@ -401,7 +401,7 @@ public class BlobStoreManagerService extends SystemService {
throw new LimitExceededException("Total amount of data with an active lease"
+ " is exceeding the max limit");
}
- blobMetadata.addLeasee(callingPackage, callingUid,
+ blobMetadata.addOrReplaceLeasee(callingPackage, callingUid,
descriptionResId, description, leaseExpiryTimeMillis);
if (LOGV) {
Slog.v(TAG, "Acquired lease on " + blobHandle
@@ -573,12 +573,16 @@ public class BlobStoreManagerService extends SystemService {
final Committer newCommitter = new Committer(session.getOwnerPackageName(),
session.getOwnerUid(), session.getBlobAccessMode());
final Committer existingCommitter = blob.getExistingCommitter(newCommitter);
- blob.addCommitter(newCommitter);
+ blob.addOrReplaceCommitter(newCommitter);
try {
writeBlobsInfoLocked();
session.sendCommitCallbackResult(COMMIT_RESULT_SUCCESS);
} catch (Exception e) {
- blob.addCommitter(existingCommitter);
+ if (existingCommitter == null) {
+ blob.removeCommitter(newCommitter);
+ } else {
+ blob.addOrReplaceCommitter(existingCommitter);
+ }
session.sendCommitCallbackResult(COMMIT_RESULT_ERROR);
}
getUserSessionsLocked(UserHandle.getUserId(session.getOwnerUid()))
@@ -1349,8 +1353,15 @@ public class BlobStoreManagerService extends SystemService {
mContext.enforceCallingOrSelfPermission(android.Manifest.permission.DUMP,
"Caller is not allowed to call this; caller=" + Binder.getCallingUid());
- mHandler.post(PooledLambda.obtainRunnable(remoteCallback::sendResult, null)
- .recycleOnUse());
+ // We post messages back and forth between mHandler thread and mBackgroundHandler
+ // thread while committing a blob. We need to replicate the same pattern here to
+ // ensure pending messages have been handled.
+ mHandler.post(() -> {
+ mBackgroundHandler.post(() -> {
+ mHandler.post(PooledLambda.obtainRunnable(remoteCallback::sendResult, null)
+ .recycleOnUse());
+ });
+ });
}
@Override
diff --git a/apex/permission/framework/Android.bp b/apex/permission/framework/Android.bp
index 6d962008460f..3fefeb51aa11 100644
--- a/apex/permission/framework/Android.bp
+++ b/apex/permission/framework/Android.bp
@@ -84,20 +84,17 @@ droidstubs {
java_library {
name: "framework-permission-stubs-publicapi",
srcs: [ ":framework-permission-stubs-srcs-publicapi" ],
- sdk_version: "system_current",
- installable: false,
+ defaults: ["framework-module-stubs-lib-defaults-publicapi"],
}
java_library {
name: "framework-permission-stubs-systemapi",
srcs: [ ":framework-permission-stubs-srcs-systemapi" ],
- sdk_version: "system_current",
- installable: false,
+ defaults: ["framework-module-stubs-lib-defaults-systemapi"],
}
java_library {
name: "framework-permission-stubs-module_libs_api",
srcs: [ ":framework-permission-stubs-srcs-module_libs_api" ],
- sdk_version: "system_current",
- installable: false,
+ defaults: ["framework-module-stubs-lib-defaults-module_libs_api"],
}
diff --git a/apex/statsd/framework/Android.bp b/apex/statsd/framework/Android.bp
index 8185bb036b22..804eb030e795 100644
--- a/apex/statsd/framework/Android.bp
+++ b/apex/statsd/framework/Android.bp
@@ -46,19 +46,11 @@ filegroup {
"//frameworks/base/apex/statsd:__subpackages__",
],
}
-
-java_defaults {
- name: "framework-statsd-defaults",
- sdk_version: "module_current",
- libs: [ "framework-annotations-lib" ],
-}
-
java_library {
name: "framework-statsd",
- defaults: [
- "framework-statsd-defaults",
- ],
installable: true,
+ sdk_version: "module_current",
+ libs: [ "framework-annotations-lib" ],
srcs: [
":framework-statsd-sources",
@@ -129,39 +121,33 @@ droidstubs {
java_library {
name: "framework-statsd-stubs-publicapi",
- defaults: [
- "framework-statsd-defaults",
- ],
+ defaults: ["framework-module-stubs-lib-defaults-publicapi"],
srcs: [ ":framework-statsd-stubs-srcs-publicapi" ],
visibility: [
"//frameworks/base", // Framework
"//frameworks/base/apex/statsd", // statsd apex
- ]
+ ],
}
java_library {
name: "framework-statsd-stubs-systemapi",
- defaults: [
- "framework-statsd-defaults",
- ],
+ defaults: ["framework-module-stubs-lib-defaults-systemapi"],
srcs: [ ":framework-statsd-stubs-srcs-systemapi" ],
visibility: [
"//frameworks/base", // Framework
"//frameworks/base/apex/statsd", // statsd apex
- ]
+ ],
}
java_library {
name: "framework-statsd-stubs-module_libs_api",
- defaults: [
- "framework-statsd-defaults",
- ],
+ defaults: ["framework-module-stubs-lib-defaults-module_libs_api"],
srcs: [ ":framework-statsd-stubs-srcs-module_libs_api" ],
visibility: [
"//frameworks/base", // Framework
"//frameworks/base/apex/statsd", // statsd apex
"//frameworks/opt/net/wifi/service" // wifi service
- ]
+ ],
}
android_test {
diff --git a/api/current.txt b/api/current.txt
index eb16b5e560c7..aca06fe4d3a6 100644
--- a/api/current.txt
+++ b/api/current.txt
@@ -9,7 +9,6 @@ package android {
ctor public Manifest.permission();
field public static final String ACCEPT_HANDOVER = "android.permission.ACCEPT_HANDOVER";
field public static final String ACCESS_BACKGROUND_LOCATION = "android.permission.ACCESS_BACKGROUND_LOCATION";
- field public static final String ACCESS_CALL_AUDIO = "android.permission.ACCESS_CALL_AUDIO";
field public static final String ACCESS_CHECKIN_PROPERTIES = "android.permission.ACCESS_CHECKIN_PROPERTIES";
field public static final String ACCESS_COARSE_LOCATION = "android.permission.ACCESS_COARSE_LOCATION";
field public static final String ACCESS_FINE_LOCATION = "android.permission.ACCESS_FINE_LOCATION";
@@ -278,7 +277,7 @@ package android {
field public static final int activityCloseExitAnimation = 16842939; // 0x10100bb
field public static final int activityOpenEnterAnimation = 16842936; // 0x10100b8
field public static final int activityOpenExitAnimation = 16842937; // 0x10100b9
- field public static final int actor = 16844312; // 0x1010618
+ field public static final int actor = 16844313; // 0x1010619
field public static final int addPrintersActivity = 16843750; // 0x10103e6
field public static final int addStatesFromChildren = 16842992; // 0x10100f0
field public static final int adjustViewBounds = 16843038; // 0x101011e
@@ -328,7 +327,7 @@ package android {
field public static final int autoLink = 16842928; // 0x10100b0
field public static final int autoMirrored = 16843754; // 0x10103ea
field public static final int autoRemoveFromRecents = 16843847; // 0x1010447
- field public static final int autoRevokePermissions = 16844308; // 0x1010614
+ field public static final int autoRevokePermissions = 16844309; // 0x1010615
field public static final int autoSizeMaxTextSize = 16844102; // 0x1010546
field public static final int autoSizeMinTextSize = 16844088; // 0x1010538
field public static final int autoSizePresetSizes = 16844087; // 0x1010537
@@ -710,7 +709,7 @@ package android {
field public static final int gravity = 16842927; // 0x10100af
field public static final int gridViewStyle = 16842865; // 0x1010071
field public static final int groupIndicator = 16843019; // 0x101010b
- field public static final int gwpAsanMode = 16844311; // 0x1010617
+ field public static final int gwpAsanMode = 16844312; // 0x1010618
field public static final int hand_hour = 16843011; // 0x1010103
field public static final int hand_minute = 16843012; // 0x1010104
field public static final int handle = 16843354; // 0x101025a
@@ -955,7 +954,7 @@ package android {
field public static final int mediaRouteButtonStyle = 16843693; // 0x10103ad
field public static final int mediaRouteTypes = 16843694; // 0x10103ae
field public static final int menuCategory = 16843230; // 0x10101de
- field public static final int mimeGroup = 16844310; // 0x1010616
+ field public static final int mimeGroup = 16844311; // 0x1010617
field public static final int mimeType = 16842790; // 0x1010026
field public static final int min = 16844089; // 0x1010539
field public static final int minAspectRatio = 16844187; // 0x101059b
@@ -1084,7 +1083,7 @@ package android {
field public static final int preferenceScreenStyle = 16842891; // 0x101008b
field public static final int preferenceStyle = 16842894; // 0x101008e
field public static final int presentationTheme = 16843712; // 0x10103c0
- field public static final int preserveLegacyExternalStorage = 16844309; // 0x1010615
+ field public static final int preserveLegacyExternalStorage = 16844310; // 0x1010616
field public static final int previewImage = 16843482; // 0x10102da
field public static final int primaryContentAlpha = 16844114; // 0x1010552
field public static final int priority = 16842780; // 0x101001c
@@ -45923,13 +45922,9 @@ package android.telecom {
method public void onConference(android.telecom.Connection, android.telecom.Connection);
method public void onConnectionServiceFocusGained();
method public void onConnectionServiceFocusLost();
- method @Nullable public android.telecom.Conference onCreateIncomingConference(@Nullable android.telecom.PhoneAccountHandle, @Nullable android.telecom.ConnectionRequest);
- method public void onCreateIncomingConferenceFailed(@Nullable android.telecom.PhoneAccountHandle, @Nullable android.telecom.ConnectionRequest);
method public android.telecom.Connection onCreateIncomingConnection(android.telecom.PhoneAccountHandle, android.telecom.ConnectionRequest);
method public void onCreateIncomingConnectionFailed(android.telecom.PhoneAccountHandle, android.telecom.ConnectionRequest);
method public android.telecom.Connection onCreateIncomingHandoverConnection(android.telecom.PhoneAccountHandle, android.telecom.ConnectionRequest);
- method @Nullable public android.telecom.Conference onCreateOutgoingConference(@Nullable android.telecom.PhoneAccountHandle, @Nullable android.telecom.ConnectionRequest);
- method public void onCreateOutgoingConferenceFailed(@Nullable android.telecom.PhoneAccountHandle, @Nullable android.telecom.ConnectionRequest);
method public android.telecom.Connection onCreateOutgoingConnection(android.telecom.PhoneAccountHandle, android.telecom.ConnectionRequest);
method public void onCreateOutgoingConnectionFailed(android.telecom.PhoneAccountHandle, android.telecom.ConnectionRequest);
method public android.telecom.Connection onCreateOutgoingHandoverConnection(android.telecom.PhoneAccountHandle, android.telecom.ConnectionRequest);
@@ -46419,14 +46414,26 @@ package android.telephony {
field public static final int BAND_46 = 46; // 0x2e
field public static final int BAND_47 = 47; // 0x2f
field public static final int BAND_48 = 48; // 0x30
+ field public static final int BAND_49 = 49; // 0x31
field public static final int BAND_5 = 5; // 0x5
+ field public static final int BAND_50 = 50; // 0x32
+ field public static final int BAND_51 = 51; // 0x33
+ field public static final int BAND_52 = 52; // 0x34
+ field public static final int BAND_53 = 53; // 0x35
field public static final int BAND_6 = 6; // 0x6
field public static final int BAND_65 = 65; // 0x41
field public static final int BAND_66 = 66; // 0x42
field public static final int BAND_68 = 68; // 0x44
field public static final int BAND_7 = 7; // 0x7
field public static final int BAND_70 = 70; // 0x46
+ field public static final int BAND_71 = 71; // 0x47
+ field public static final int BAND_72 = 72; // 0x48
+ field public static final int BAND_73 = 73; // 0x49
+ field public static final int BAND_74 = 74; // 0x4a
field public static final int BAND_8 = 8; // 0x8
+ field public static final int BAND_85 = 85; // 0x55
+ field public static final int BAND_87 = 87; // 0x57
+ field public static final int BAND_88 = 88; // 0x58
field public static final int BAND_9 = 9; // 0x9
}
@@ -46490,7 +46497,13 @@ package android.telephony {
field public static final int BAND_83 = 83; // 0x53
field public static final int BAND_84 = 84; // 0x54
field public static final int BAND_86 = 86; // 0x56
+ field public static final int BAND_89 = 89; // 0x59
field public static final int BAND_90 = 90; // 0x5a
+ field public static final int BAND_91 = 91; // 0x5b
+ field public static final int BAND_92 = 92; // 0x5c
+ field public static final int BAND_93 = 93; // 0x5d
+ field public static final int BAND_94 = 94; // 0x5e
+ field public static final int BAND_95 = 95; // 0x5f
}
public static final class AccessNetworkConstants.UtranBand {
@@ -47778,7 +47791,7 @@ package android.telephony {
method public String createAppSpecificSmsToken(android.app.PendingIntent);
method @Nullable public String createAppSpecificSmsTokenWithPackageInfo(@Nullable String, @NonNull android.app.PendingIntent);
method public java.util.ArrayList<java.lang.String> divideMessage(String);
- method @Deprecated public void downloadMultimediaMessage(android.content.Context, String, android.net.Uri, android.os.Bundle, android.app.PendingIntent);
+ method public void downloadMultimediaMessage(android.content.Context, String, android.net.Uri, android.os.Bundle, android.app.PendingIntent);
method @NonNull public android.os.Bundle getCarrierConfigValues();
method public static android.telephony.SmsManager getDefault();
method public static int getDefaultSmsSubscriptionId();
@@ -47788,7 +47801,7 @@ package android.telephony {
method public int getSubscriptionId();
method public void injectSmsPdu(byte[], String, android.app.PendingIntent);
method public void sendDataMessage(String, String, short, byte[], android.app.PendingIntent, android.app.PendingIntent);
- method @Deprecated public void sendMultimediaMessage(android.content.Context, android.net.Uri, String, android.os.Bundle, android.app.PendingIntent);
+ method public void sendMultimediaMessage(android.content.Context, android.net.Uri, String, android.os.Bundle, android.app.PendingIntent);
method public void sendMultipartTextMessage(String, String, java.util.ArrayList<java.lang.String>, java.util.ArrayList<android.app.PendingIntent>, java.util.ArrayList<android.app.PendingIntent>);
method public void sendMultipartTextMessage(@NonNull String, @Nullable String, @NonNull java.util.List<java.lang.String>, @Nullable java.util.List<android.app.PendingIntent>, @Nullable java.util.List<android.app.PendingIntent>, long);
method public void sendMultipartTextMessage(@NonNull String, @Nullable String, @NonNull java.util.List<java.lang.String>, @Nullable java.util.List<android.app.PendingIntent>, @Nullable java.util.List<android.app.PendingIntent>, @NonNull String, @Nullable String);
@@ -55753,8 +55766,8 @@ package android.view {
}
public final class WindowMetrics {
- ctor public WindowMetrics(@NonNull android.util.Size, @NonNull android.view.WindowInsets);
- method @NonNull public android.util.Size getSize();
+ ctor public WindowMetrics(@NonNull android.graphics.Rect, @NonNull android.view.WindowInsets);
+ method @NonNull public android.graphics.Rect getBounds();
method @NonNull public android.view.WindowInsets getWindowInsets();
}
diff --git a/api/system-current.txt b/api/system-current.txt
index 7e25382f06d9..e5fd4d39e758 100755
--- a/api/system-current.txt
+++ b/api/system-current.txt
@@ -368,7 +368,6 @@ package android.app {
method @RequiresPermission("android.permission.MANAGE_APP_OPS_MODES") public void setUidMode(@NonNull String, int, int);
field public static final String OPSTR_ACCEPT_HANDOVER = "android:accept_handover";
field public static final String OPSTR_ACCESS_ACCESSIBILITY = "android:access_accessibility";
- field public static final String OPSTR_ACCESS_CALL_AUDIO = "android:access_call_audio";
field public static final String OPSTR_ACCESS_NOTIFICATIONS = "android:access_notifications";
field public static final String OPSTR_ACTIVATE_VPN = "android:activate_vpn";
field public static final String OPSTR_ASSIST_SCREENSHOT = "android:assist_screenshot";
@@ -2030,10 +2029,10 @@ package android.content.pm {
}
public static class PackageInstaller.Session implements java.io.Closeable {
- method public void addFile(int, @NonNull String, long, @NonNull byte[], @Nullable byte[]);
+ method @RequiresPermission("com.android.permission.USE_INSTALLER_V2") public void addFile(int, @NonNull String, long, @NonNull byte[], @Nullable byte[]);
method @RequiresPermission(android.Manifest.permission.INSTALL_PACKAGES) public void commitTransferred(@NonNull android.content.IntentSender);
- method @Nullable public android.content.pm.DataLoaderParams getDataLoaderParams();
- method public void removeFile(int, @NonNull String);
+ method @Nullable @RequiresPermission("com.android.permission.USE_INSTALLER_V2") public android.content.pm.DataLoaderParams getDataLoaderParams();
+ method @RequiresPermission("com.android.permission.USE_INSTALLER_V2") public void removeFile(int, @NonNull String);
}
public static class PackageInstaller.SessionInfo implements android.os.Parcelable {
@@ -2054,7 +2053,7 @@ package android.content.pm {
public static class PackageInstaller.SessionParams implements android.os.Parcelable {
method @RequiresPermission(android.Manifest.permission.ALLOCATE_AGGRESSIVE) public void setAllocateAggressive(boolean);
method @Deprecated public void setAllowDowngrade(boolean);
- method @RequiresPermission(android.Manifest.permission.INSTALL_PACKAGES) public void setDataLoaderParams(@NonNull android.content.pm.DataLoaderParams);
+ method @RequiresPermission(allOf={android.Manifest.permission.INSTALL_PACKAGES, "com.android.permission.USE_INSTALLER_V2"}) public void setDataLoaderParams(@NonNull android.content.pm.DataLoaderParams);
method public void setDontKillApp(boolean);
method public void setEnableRollback(boolean);
method public void setEnableRollback(boolean, int);
@@ -8395,12 +8394,12 @@ package android.os {
public class RecoverySystem {
method @RequiresPermission(android.Manifest.permission.RECOVERY) public static void cancelScheduledUpdate(android.content.Context) throws java.io.IOException;
- method @RequiresPermission(android.Manifest.permission.RECOVERY) public static boolean clearPrepareForUnattendedUpdate(@NonNull android.content.Context) throws java.io.IOException;
+ method @RequiresPermission(android.Manifest.permission.RECOVERY) public static void clearPrepareForUnattendedUpdate(@NonNull android.content.Context) throws java.io.IOException;
method @RequiresPermission(android.Manifest.permission.RECOVERY) public static void installPackage(android.content.Context, java.io.File, boolean) throws java.io.IOException;
method @RequiresPermission(android.Manifest.permission.RECOVERY) public static void prepareForUnattendedUpdate(@NonNull android.content.Context, @NonNull String, @Nullable android.content.IntentSender) throws java.io.IOException;
method @RequiresPermission(android.Manifest.permission.RECOVERY) public static void processPackage(android.content.Context, java.io.File, android.os.RecoverySystem.ProgressListener, android.os.Handler) throws java.io.IOException;
method @RequiresPermission(android.Manifest.permission.RECOVERY) public static void processPackage(android.content.Context, java.io.File, android.os.RecoverySystem.ProgressListener) throws java.io.IOException;
- method @RequiresPermission(android.Manifest.permission.RECOVERY) public static boolean rebootAndApply(@NonNull android.content.Context, @NonNull String, @NonNull String) throws java.io.IOException;
+ method @RequiresPermission(android.Manifest.permission.RECOVERY) public static void rebootAndApply(@NonNull android.content.Context, @NonNull String, @NonNull String) throws java.io.IOException;
method @RequiresPermission(allOf={android.Manifest.permission.RECOVERY, android.Manifest.permission.REBOOT}) public static void rebootWipeAb(android.content.Context, java.io.File, String) throws java.io.IOException;
method @RequiresPermission(android.Manifest.permission.RECOVERY) public static void scheduleUpdateOnBoot(android.content.Context, java.io.File) throws java.io.IOException;
method public static boolean verifyPackageCompatibility(java.io.File) throws java.io.IOException;
diff --git a/cmds/content/src/com/android/commands/content/Content.java b/cmds/content/src/com/android/commands/content/Content.java
index 59544a971e5f..ca1d598ee7d7 100644
--- a/cmds/content/src/com/android/commands/content/Content.java
+++ b/cmds/content/src/com/android/commands/content/Content.java
@@ -32,8 +32,11 @@ import android.os.ParcelFileDescriptor;
import android.os.Process;
import android.os.UserHandle;
import android.text.TextUtils;
+import android.util.Pair;
import java.io.FileDescriptor;
+import java.util.ArrayList;
+import java.util.List;
/**
* This class is a command line utility for manipulating content. A client
@@ -72,7 +75,7 @@ public class Content {
"usage: adb shell content [subcommand] [options]\n"
+ "\n"
+ "usage: adb shell content insert --uri <URI> [--user <USER_ID>]"
- + " --bind <BINDING> [--bind <BINDING>...]\n"
+ + " --bind <BINDING> [--bind <BINDING>...] [--extra <BINDING>...]\n"
+ " <URI> a content provider URI.\n"
+ " <BINDING> binds a typed value to a column and is formatted:\n"
+ " <COLUMN_NAME>:<TYPE>:<COLUMN_VALUE> where:\n"
@@ -84,7 +87,8 @@ public class Content {
+ " adb shell content insert --uri content://settings/secure --bind name:s:new_setting"
+ " --bind value:s:new_value\n"
+ "\n"
- + "usage: adb shell content update --uri <URI> [--user <USER_ID>] [--where <WHERE>]\n"
+ + "usage: adb shell content update --uri <URI> [--user <USER_ID>]"
+ + " [--where <WHERE>] [--extra <BINDING>...]\n"
+ " <WHERE> is a SQL style where clause in quotes (You have to escape single quotes"
+ " - see example below).\n"
+ " Example:\n"
@@ -93,14 +97,15 @@ public class Content {
+ " value:s:newer_value --where \"name=\'new_setting\'\"\n"
+ "\n"
+ "usage: adb shell content delete --uri <URI> [--user <USER_ID>] --bind <BINDING>"
- + " [--bind <BINDING>...] [--where <WHERE>]\n"
+ + " [--bind <BINDING>...] [--where <WHERE>] [--extra <BINDING>...]\n"
+ " Example:\n"
+ " # Remove \"new_setting\" secure setting.\n"
+ " adb shell content delete --uri content://settings/secure "
+ "--where \"name=\'new_setting\'\"\n"
+ "\n"
+ "usage: adb shell content query --uri <URI> [--user <USER_ID>]"
- + " [--projection <PROJECTION>] [--where <WHERE>] [--sort <SORT_ORDER>]\n"
+ + " [--projection <PROJECTION>] [--where <WHERE>] [--sort <SORT_ORDER>]"
+ + " [--extra <BINDING>...]\n"
+ " <PROJECTION> is a list of colon separated column names and is formatted:\n"
+ " <COLUMN_NAME>[:<COLUMN_NAME>...]\n"
+ " <SORT_ORDER> is the order in which rows in the result should be sorted.\n"
@@ -196,6 +201,7 @@ public class Content {
Uri uri = null;
int userId = UserHandle.USER_SYSTEM;
ContentValues values = new ContentValues();
+ Bundle extras = new Bundle();
for (String argument; (argument = mTokenizer.nextArg()) != null;) {
if (ARGUMENT_URI.equals(argument)) {
uri = Uri.parse(argumentValueRequired(argument));
@@ -203,6 +209,8 @@ public class Content {
userId = Integer.parseInt(argumentValueRequired(argument));
} else if (ARGUMENT_BIND.equals(argument)) {
parseBindValue(values);
+ } else if (ARGUMENT_EXTRA.equals(argument)) {
+ parseBindValue(extras);
} else {
throw new IllegalArgumentException("Unsupported argument: " + argument);
}
@@ -215,20 +223,23 @@ public class Content {
throw new IllegalArgumentException("Bindings not specified."
+ " Did you specify --bind argument(s)?");
}
- return new InsertCommand(uri, userId, values);
+ return new InsertCommand(uri, userId, values, extras);
}
private DeleteCommand parseDeleteCommand() {
Uri uri = null;
int userId = UserHandle.USER_SYSTEM;
- String where = null;
+ Bundle extras = new Bundle();
for (String argument; (argument = mTokenizer.nextArg())!= null;) {
if (ARGUMENT_URI.equals(argument)) {
uri = Uri.parse(argumentValueRequired(argument));
} else if (ARGUMENT_USER.equals(argument)) {
userId = Integer.parseInt(argumentValueRequired(argument));
} else if (ARGUMENT_WHERE.equals(argument)) {
- where = argumentValueRequired(argument);
+ extras.putString(ContentResolver.QUERY_ARG_SQL_SELECTION,
+ argumentValueRequired(argument));
+ } else if (ARGUMENT_EXTRA.equals(argument)) {
+ parseBindValue(extras);
} else {
throw new IllegalArgumentException("Unsupported argument: " + argument);
}
@@ -237,23 +248,26 @@ public class Content {
throw new IllegalArgumentException("Content provider URI not specified."
+ " Did you specify --uri argument?");
}
- return new DeleteCommand(uri, userId, where);
+ return new DeleteCommand(uri, userId, extras);
}
private UpdateCommand parseUpdateCommand() {
Uri uri = null;
int userId = UserHandle.USER_SYSTEM;
- String where = null;
ContentValues values = new ContentValues();
+ Bundle extras = new Bundle();
for (String argument; (argument = mTokenizer.nextArg())!= null;) {
if (ARGUMENT_URI.equals(argument)) {
uri = Uri.parse(argumentValueRequired(argument));
} else if (ARGUMENT_USER.equals(argument)) {
userId = Integer.parseInt(argumentValueRequired(argument));
} else if (ARGUMENT_WHERE.equals(argument)) {
- where = argumentValueRequired(argument);
+ extras.putString(ContentResolver.QUERY_ARG_SQL_SELECTION,
+ argumentValueRequired(argument));
} else if (ARGUMENT_BIND.equals(argument)) {
parseBindValue(values);
+ } else if (ARGUMENT_EXTRA.equals(argument)) {
+ parseBindValue(extras);
} else {
throw new IllegalArgumentException("Unsupported argument: " + argument);
}
@@ -266,7 +280,7 @@ public class Content {
throw new IllegalArgumentException("Bindings not specified."
+ " Did you specify --bind argument(s)?");
}
- return new UpdateCommand(uri, userId, values, where);
+ return new UpdateCommand(uri, userId, values, extras);
}
public CallCommand parseCallCommand() {
@@ -274,7 +288,7 @@ public class Content {
int userId = UserHandle.USER_SYSTEM;
String arg = null;
Uri uri = null;
- ContentValues values = new ContentValues();
+ Bundle extras = new Bundle();
for (String argument; (argument = mTokenizer.nextArg())!= null;) {
if (ARGUMENT_URI.equals(argument)) {
uri = Uri.parse(argumentValueRequired(argument));
@@ -285,11 +299,10 @@ public class Content {
} else if (ARGUMENT_ARG.equals(argument)) {
arg = argumentValueRequired(argument);
} else if (ARGUMENT_EXTRA.equals(argument)) {
- parseBindValue(values);
+ parseBindValue(extras);
} else {
throw new IllegalArgumentException("Unsupported argument: " + argument);
}
-
}
if (uri == null) {
throw new IllegalArgumentException("Content provider URI not specified."
@@ -298,7 +311,7 @@ public class Content {
if (method == null) {
throw new IllegalArgumentException("Content provider method not specified.");
}
- return new CallCommand(uri, userId, method, arg, values);
+ return new CallCommand(uri, userId, method, arg, extras);
}
private GetTypeCommand parseGetTypeCommand() {
@@ -363,19 +376,22 @@ public class Content {
Uri uri = null;
int userId = UserHandle.USER_SYSTEM;
String[] projection = null;
- String sort = null;
- String where = null;
+ Bundle extras = new Bundle();
for (String argument; (argument = mTokenizer.nextArg())!= null;) {
if (ARGUMENT_URI.equals(argument)) {
uri = Uri.parse(argumentValueRequired(argument));
} else if (ARGUMENT_USER.equals(argument)) {
userId = Integer.parseInt(argumentValueRequired(argument));
} else if (ARGUMENT_WHERE.equals(argument)) {
- where = argumentValueRequired(argument);
+ extras.putString(ContentResolver.QUERY_ARG_SQL_SELECTION,
+ argumentValueRequired(argument));
} else if (ARGUMENT_SORT.equals(argument)) {
- sort = argumentValueRequired(argument);
+ extras.putString(ContentResolver.QUERY_ARG_SQL_SORT_ORDER,
+ argumentValueRequired(argument));
} else if (ARGUMENT_PROJECTION.equals(argument)) {
projection = argumentValueRequired(argument).split("[\\s]*:[\\s]*");
+ } else if (ARGUMENT_EXTRA.equals(argument)) {
+ parseBindValue(extras);
} else {
throw new IllegalArgumentException("Unsupported argument: " + argument);
}
@@ -384,40 +400,76 @@ public class Content {
throw new IllegalArgumentException("Content provider URI not specified."
+ " Did you specify --uri argument?");
}
- return new QueryCommand(uri, userId, projection, where, sort);
+ return new QueryCommand(uri, userId, projection, extras);
+ }
+
+ private List<String> splitWithEscaping(String argument, char splitChar) {
+ final List<String> res = new ArrayList<>();
+ final StringBuilder cur = new StringBuilder();
+ for (int i = 0; i < argument.length(); i++) {
+ char c = argument.charAt(i);
+ if (c == '\\') {
+ if (++i == argument.length()) {
+ throw new IllegalArgumentException("Invalid escaping");
+ } else {
+ // Skip escaping char and insert next
+ c = argument.charAt(i);
+ cur.append(c);
+ }
+ } else if (c == splitChar) {
+ // Splitting char means next string
+ res.add(cur.toString());
+ cur.setLength(0);
+ } else {
+ // Copy non-escaping and non-splitting char
+ cur.append(c);
+ }
+ }
+ res.add(cur.toString());
+ return res;
}
- private void parseBindValue(ContentValues values) {
+ private Pair<String, Object> parseBindValue() {
String argument = mTokenizer.nextArg();
if (TextUtils.isEmpty(argument)) {
throw new IllegalArgumentException("Binding not well formed: " + argument);
}
- final int firstColonIndex = argument.indexOf(COLON);
- if (firstColonIndex < 0) {
+ final List<String> split = splitWithEscaping(argument, COLON.charAt(0));
+ if (split.size() != 3) {
throw new IllegalArgumentException("Binding not well formed: " + argument);
}
- final int secondColonIndex = argument.indexOf(COLON, firstColonIndex + 1);
- if (secondColonIndex < 0) {
- throw new IllegalArgumentException("Binding not well formed: " + argument);
- }
- String column = argument.substring(0, firstColonIndex);
- String type = argument.substring(firstColonIndex + 1, secondColonIndex);
- String value = argument.substring(secondColonIndex + 1);
+ String column = split.get(0);
+ String type = split.get(1);
+ String value = split.get(2);
if (TYPE_STRING.equals(type)) {
- values.put(column, value);
+ return Pair.create(column, value);
} else if (TYPE_BOOLEAN.equalsIgnoreCase(type)) {
- values.put(column, Boolean.parseBoolean(value));
- } else if (TYPE_INTEGER.equalsIgnoreCase(type) || TYPE_LONG.equalsIgnoreCase(type)) {
- values.put(column, Long.parseLong(value));
- } else if (TYPE_FLOAT.equalsIgnoreCase(type) || TYPE_DOUBLE.equalsIgnoreCase(type)) {
- values.put(column, Double.parseDouble(value));
+ return Pair.create(column, Boolean.parseBoolean(value));
+ } else if (TYPE_INTEGER.equalsIgnoreCase(type)) {
+ return Pair.create(column, Integer.parseInt(value));
+ } else if (TYPE_LONG.equalsIgnoreCase(type)) {
+ return Pair.create(column, Long.parseLong(value));
+ } else if (TYPE_FLOAT.equalsIgnoreCase(type)) {
+ return Pair.create(column, Float.parseFloat(value));
+ } else if (TYPE_DOUBLE.equalsIgnoreCase(type)) {
+ return Pair.create(column, Double.parseDouble(value));
} else if (TYPE_NULL.equalsIgnoreCase(type)) {
- values.putNull(column);
+ return Pair.create(column, null);
} else {
throw new IllegalArgumentException("Unsupported type: " + type);
}
}
+ private void parseBindValue(ContentValues values) {
+ final Pair<String, Object> columnValue = parseBindValue();
+ values.putObject(columnValue.first, columnValue.second);
+ }
+
+ private void parseBindValue(Bundle extras) {
+ final Pair<String, Object> columnValue = parseBindValue();
+ extras.putObject(columnValue.first, columnValue.second);
+ }
+
private String argumentValueRequired(String argument) {
String value = mTokenizer.nextArg();
if (TextUtils.isEmpty(value) || value.startsWith(ARGUMENT_PREFIX)) {
@@ -500,60 +552,43 @@ public class Content {
private static class InsertCommand extends Command {
final ContentValues mContentValues;
+ final Bundle mExtras;
- public InsertCommand(Uri uri, int userId, ContentValues contentValues) {
+ public InsertCommand(Uri uri, int userId, ContentValues contentValues, Bundle extras) {
super(uri, userId);
mContentValues = contentValues;
+ mExtras = extras;
}
@Override
public void onExecute(IContentProvider provider) throws Exception {
- provider.insert(resolveCallingPackage(), null, mUri, mContentValues, null);
+ provider.insert(resolveCallingPackage(), null, mUri, mContentValues, mExtras);
}
}
private static class DeleteCommand extends Command {
- final String mWhere;
+ final Bundle mExtras;
- public DeleteCommand(Uri uri, int userId, String where) {
+ public DeleteCommand(Uri uri, int userId, Bundle extras) {
super(uri, userId);
- mWhere = where;
+ mExtras = extras;
}
@Override
public void onExecute(IContentProvider provider) throws Exception {
- provider.delete(resolveCallingPackage(), null, mUri,
- ContentResolver.createSqlQueryBundle(mWhere, null));
+ provider.delete(resolveCallingPackage(), null, mUri, mExtras);
}
}
private static class CallCommand extends Command {
final String mMethod, mArg;
- Bundle mExtras = null;
+ final Bundle mExtras;
- public CallCommand(Uri uri, int userId, String method, String arg, ContentValues values) {
+ public CallCommand(Uri uri, int userId, String method, String arg, Bundle extras) {
super(uri, userId);
mMethod = method;
mArg = arg;
- if (values != null) {
- mExtras = new Bundle();
- for (String key : values.keySet()) {
- final Object val = values.get(key);
- if (val instanceof String) {
- mExtras.putString(key, (String) val);
- } else if (val instanceof Float) {
- mExtras.putFloat(key, (Float) val);
- } else if (val instanceof Double) {
- mExtras.putDouble(key, (Double) val);
- } else if (val instanceof Boolean) {
- mExtras.putBoolean(key, (Boolean) val);
- } else if (val instanceof Integer) {
- mExtras.putInt(key, (Integer) val);
- } else if (val instanceof Long) {
- mExtras.putLong(key, (Long) val);
- }
- }
- }
+ mExtras = extras;
}
@Override
@@ -604,21 +639,20 @@ public class Content {
}
}
- private static class QueryCommand extends DeleteCommand {
+ private static class QueryCommand extends Command {
final String[] mProjection;
- final String mSortOrder;
+ final Bundle mExtras;
- public QueryCommand(
- Uri uri, int userId, String[] projection, String where, String sortOrder) {
- super(uri, userId, where);
+ public QueryCommand(Uri uri, int userId, String[] projection, Bundle extras) {
+ super(uri, userId);
mProjection = projection;
- mSortOrder = sortOrder;
+ mExtras = extras;
}
@Override
public void onExecute(IContentProvider provider) throws Exception {
Cursor cursor = provider.query(resolveCallingPackage(), null, mUri, mProjection,
- ContentResolver.createSqlQueryBundle(mWhere, null, mSortOrder), null);
+ mExtras, null);
if (cursor == null) {
System.out.println("No result found.");
return;
@@ -670,18 +704,19 @@ public class Content {
}
}
- private static class UpdateCommand extends InsertCommand {
- final String mWhere;
+ private static class UpdateCommand extends Command {
+ final ContentValues mValues;
+ final Bundle mExtras;
- public UpdateCommand(Uri uri, int userId, ContentValues contentValues, String where) {
- super(uri, userId, contentValues);
- mWhere = where;
+ public UpdateCommand(Uri uri, int userId, ContentValues values, Bundle extras) {
+ super(uri, userId);
+ mValues = values;
+ mExtras = extras;
}
@Override
public void onExecute(IContentProvider provider) throws Exception {
- provider.update(resolveCallingPackage(), null, mUri, mContentValues,
- ContentResolver.createSqlQueryBundle(mWhere, null));
+ provider.update(resolveCallingPackage(), null, mUri, mValues, mExtras);
}
}
diff --git a/cmds/statsd/Android.bp b/cmds/statsd/Android.bp
index 6fe098c2a123..45f21ae8e3e1 100644
--- a/cmds/statsd/Android.bp
+++ b/cmds/statsd/Android.bp
@@ -97,6 +97,7 @@ cc_defaults {
"src/stats_log_util.cpp",
"src/statscompanion_util.cpp",
"src/statsd_config.proto",
+ "src/statsd_metadata.proto",
"src/StatsLogProcessor.cpp",
"src/StatsService.cpp",
"src/storage/StorageManager.cpp",
diff --git a/cmds/statsd/src/atoms.proto b/cmds/statsd/src/atoms.proto
index f8b274979c17..979f950f2770 100644
--- a/cmds/statsd/src/atoms.proto
+++ b/cmds/statsd/src/atoms.proto
@@ -510,6 +510,7 @@ message Atom {
VoiceCallRatUsage voice_call_rat_usage = 10077 [(module) = "telephony"];
SimSlotState sim_slot_state = 10078 [(module) = "telephony"];
SupportedRadioAccessFamily supported_radio_access_family = 10079 [(module) = "telephony"];
+ SettingSnapshot setting_snapshot = 10080 [(module) = "framework"];
}
// DO NOT USE field numbers above 100,000 in AOSP.
@@ -2752,21 +2753,32 @@ message PhoneStateChanged {
message BackGesture {
enum BackType {
- DEFAULT_BACK_TYPE = 0;
- COMPLETED = 1;
- COMPLETED_REJECTED = 2; // successful because coming from rejected area
- INCOMPLETE_EXCLUDED = 3; // would have been successful but in the exclusion area
- INCOMPLETE = 4;
+ DEFAULT_BACK_TYPE = 0;
+ COMPLETED = 1;
+ COMPLETED_REJECTED = 2; // successful because coming from rejected area
+ INCOMPLETE_EXCLUDED = 3; // would have been successful but in the exclusion area
+ INCOMPLETE = 4; // Unsuccessful, for reasons other than below.
+ INCOMPLETE_FAR_FROM_EDGE = 5; // Unsuccessful, far from the edge.
+ INCOMPLETE_MULTI_TOUCH = 6; // Unsuccessful, multi touch.
+ INCOMPLETE_LONG_PRESS = 7; // Unsuccessful, long press.
+ INCOMPLETE_VERTICAL_MOVE = 8; // Unsuccessful, move vertically.
}
optional BackType type = 1;
- optional int32 y_coordinate = 2; // y coordinate for ACTION_DOWN event
+ optional int32 y_coordinate = 2 [deprecated = true]; // y coordinate for ACTION_DOWN event
+ optional int32 start_x = 4; // X coordinate for ACTION_DOWN event.
+ optional int32 start_y = 5; // Y coordinate for ACTION_DOWN event.
+ optional int32 end_x = 6; // X coordinate for ACTION_MOVE event.
+ optional int32 end_y = 7; // Y coordinate for ACTION_MOVE event.
+ optional int32 left_boundary = 8; // left edge width + left inset
+ optional int32 right_boundary = 9; // screen width - (right edge width + right inset)
+
enum WindowHorizontalLocation {
DEFAULT_LOCATION = 0;
LEFT = 1;
RIGHT = 2;
}
- optional WindowHorizontalLocation x_location = 3;
+ optional WindowHorizontalLocation x_location = 3 [deprecated = true];
}
message ExclusionRectStateChanged {
@@ -8999,3 +9011,37 @@ message RankingSelected {
// Which of the ranked targets got picked, default starting position 0.
optional int32 position_picked = 4;
}
+
+/**
+ * Logs settings provider values.
+ *
+ * Use DeviceConfig.getProperties to get a list Setting key, query the data from content provider,
+ * then write the value to proto.
+ *
+ */
+message SettingSnapshot {
+
+ // Setting key
+ optional string name = 1;
+
+ enum SettingsValueType {
+ NOTASSIGNED = 0;
+ ASSIGNED_BOOL_TYPE = 1;
+ ASSIGNED_INT_TYPE = 2;
+ ASSIGNED_FLOAT_TYPE = 3;
+ ASSIGNED_STRING_TYPE = 4;
+ };
+ // Setting value type
+ optional SettingsValueType type = 2;
+
+ optional bool bool_value = 3;
+
+ optional int32 int_value = 4;
+
+ optional float float_value = 5;
+
+ optional string str_value = 6;
+
+ // Android user index. 0 for primary user, 10, 11 for secondary or profile user
+ optional int32 user_id = 7;
+}
diff --git a/cmds/statsd/src/metrics/MetricsManager.cpp b/cmds/statsd/src/metrics/MetricsManager.cpp
index 6f54ea7d86c2..fca48f96f56d 100644
--- a/cmds/statsd/src/metrics/MetricsManager.cpp
+++ b/cmds/statsd/src/metrics/MetricsManager.cpp
@@ -80,7 +80,7 @@ MetricsManager::MetricsManager(const ConfigKey& key, const StatsdConfig& config,
mAllMetricProducers, mAllAnomalyTrackers, mAllPeriodicAlarmTrackers,
mConditionToMetricMap, mTrackerToMetricMap, mTrackerToConditionMap,
mActivationAtomTrackerToMetricMap, mDeactivationAtomTrackerToMetricMap,
- mMetricIndexesWithActivation, mNoReportMetricIds);
+ mAlertTrackerMap, mMetricIndexesWithActivation, mNoReportMetricIds);
mHashStringsInReport = config.hash_strings_in_metric_report();
mVersionStringsInReport = config.version_strings_in_metric_report();
diff --git a/cmds/statsd/src/metrics/MetricsManager.h b/cmds/statsd/src/metrics/MetricsManager.h
index 6d20822fd54c..7500ec91ce30 100644
--- a/cmds/statsd/src/metrics/MetricsManager.h
+++ b/cmds/statsd/src/metrics/MetricsManager.h
@@ -230,6 +230,10 @@ private:
// Maps deactivation triggering event to MetricProducers.
std::unordered_map<int, std::vector<int>> mDeactivationAtomTrackerToMetricMap;
+ // Maps AlertIds to the index of the corresponding AnomalyTracker stored in mAllAnomalyTrackers.
+ // The map is used in LoadMetadata to more efficiently lookup AnomalyTrackers from an AlertId.
+ std::unordered_map<int64_t, int> mAlertTrackerMap;
+
std::vector<int> mMetricIndexesWithActivation;
void initLogSourceWhiteList();
diff --git a/cmds/statsd/src/metrics/metrics_manager_util.cpp b/cmds/statsd/src/metrics/metrics_manager_util.cpp
index 40a313a14eab..e5fe87acc720 100644
--- a/cmds/statsd/src/metrics/metrics_manager_util.cpp
+++ b/cmds/statsd/src/metrics/metrics_manager_util.cpp
@@ -830,10 +830,10 @@ bool initMetrics(const ConfigKey& key, const StatsdConfig& config, const int64_t
bool initAlerts(const StatsdConfig& config,
const unordered_map<int64_t, int>& metricProducerMap,
+ unordered_map<int64_t, int>& alertTrackerMap,
const sp<AlarmMonitor>& anomalyAlarmMonitor,
vector<sp<MetricProducer>>& allMetricProducers,
vector<sp<AnomalyTracker>>& allAnomalyTrackers) {
- unordered_map<int64_t, int> anomalyTrackerMap;
for (int i = 0; i < config.alert_size(); i++) {
const Alert& alert = config.alert(i);
const auto& itr = metricProducerMap.find(alert.metric_id());
@@ -858,7 +858,7 @@ bool initAlerts(const StatsdConfig& config,
// The ALOGW for this invalid alert was already displayed in addAnomalyTracker().
return false;
}
- anomalyTrackerMap.insert(std::make_pair(alert.id(), allAnomalyTrackers.size()));
+ alertTrackerMap.insert(std::make_pair(alert.id(), allAnomalyTrackers.size()));
allAnomalyTrackers.push_back(anomalyTracker);
}
for (int i = 0; i < config.subscription_size(); ++i) {
@@ -872,8 +872,8 @@ bool initAlerts(const StatsdConfig& config,
(long long)subscription.id());
return false;
}
- const auto& itr = anomalyTrackerMap.find(subscription.rule_id());
- if (itr == anomalyTrackerMap.end()) {
+ const auto& itr = alertTrackerMap.find(subscription.rule_id());
+ if (itr == alertTrackerMap.end()) {
ALOGW("subscription \"%lld\" has unknown rule id: \"%lld\"",
(long long)subscription.id(), (long long)subscription.rule_id());
return false;
@@ -944,6 +944,7 @@ bool initStatsdConfig(const ConfigKey& key, const StatsdConfig& config, UidMap&
unordered_map<int, std::vector<int>>& trackerToConditionMap,
unordered_map<int, std::vector<int>>& activationAtomTrackerToMetricMap,
unordered_map<int, std::vector<int>>& deactivationAtomTrackerToMetricMap,
+ unordered_map<int64_t, int>& alertTrackerMap,
vector<int>& metricsWithActivation,
std::set<int64_t>& noReportMetricIds) {
unordered_map<int64_t, int> logTrackerMap;
@@ -976,8 +977,8 @@ bool initStatsdConfig(const ConfigKey& key, const StatsdConfig& config, UidMap&
ALOGE("initMetricProducers failed");
return false;
}
- if (!initAlerts(config, metricProducerMap, anomalyAlarmMonitor, allMetricProducers,
- allAnomalyTrackers)) {
+ if (!initAlerts(config, metricProducerMap, alertTrackerMap, anomalyAlarmMonitor,
+ allMetricProducers, allAnomalyTrackers)) {
ALOGE("initAlerts failed");
return false;
}
diff --git a/cmds/statsd/src/metrics/metrics_manager_util.h b/cmds/statsd/src/metrics/metrics_manager_util.h
index 5ebb232694a4..a8ccc6289b9a 100644
--- a/cmds/statsd/src/metrics/metrics_manager_util.h
+++ b/cmds/statsd/src/metrics/metrics_manager_util.h
@@ -128,6 +128,7 @@ bool initStatsdConfig(const ConfigKey& key, const StatsdConfig& config, UidMap&
std::unordered_map<int, std::vector<int>>& trackerToConditionMap,
unordered_map<int, std::vector<int>>& activationAtomTrackerToMetricMap,
unordered_map<int, std::vector<int>>& deactivationAtomTrackerToMetricMap,
+ std::unordered_map<int64_t, int>& alertTrackerMap,
vector<int>& metricsWithActivation,
std::set<int64_t>& noReportMetricIds);
diff --git a/cmds/statsd/src/statsd_metadata.proto b/cmds/statsd/src/statsd_metadata.proto
new file mode 100644
index 000000000000..e00fe33655ca
--- /dev/null
+++ b/cmds/statsd/src/statsd_metadata.proto
@@ -0,0 +1,63 @@
+/*
+ * 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.
+ */
+
+syntax = "proto2";
+
+package android.os.statsd.metadata;
+
+message ConfigKey {
+ optional int64 config_id = 1;
+ optional int32 uid = 2;
+}
+
+message Field {
+ optional int32 tag = 1;
+ optional int32 field = 2;
+}
+
+message FieldValue {
+ optional Field field = 1;
+ oneof value {
+ int32 value_int = 2;
+ int64 value_long = 3;
+ float value_float = 4;
+ double value_double = 5;
+ string value_str = 6;
+ bytes value_storage = 7;
+ }
+}
+
+message MetricDimensionKey {
+ repeated FieldValue dimension_key_in_what = 1;
+ repeated FieldValue state_values_key = 2;
+}
+
+message AlertMetadata {
+ optional int64 alert_id = 1;
+ // The earliest time the alert can be fired again in wall clock time.
+ optional int32 last_refractory_ends_sec = 2;
+ optional MetricDimensionKey dimension_key = 3;
+}
+
+// All metadata for a config in statsd
+message StatsMetadata {
+ optional ConfigKey config_key = 1;
+ repeated AlertMetadata alert_metadata = 2;
+}
+
+message StatsMetadataList {
+ repeated StatsMetadata stats_metadata = 1;
+} \ No newline at end of file
diff --git a/cmds/statsd/tests/MetricsManager_test.cpp b/cmds/statsd/tests/MetricsManager_test.cpp
index 71adc5789d92..356e40b9b99d 100644
--- a/cmds/statsd/tests/MetricsManager_test.cpp
+++ b/cmds/statsd/tests/MetricsManager_test.cpp
@@ -40,6 +40,7 @@ using android::os::statsd::Predicate;
#ifdef __ANDROID__
const ConfigKey kConfigKey(0, 12345);
+const long kAlertId = 3;
const long timeBaseSec = 1000;
@@ -85,7 +86,7 @@ StatsdConfig buildGoodConfig() {
config.add_no_report_metric(3);
auto alert = config.add_alert();
- alert->set_id(3);
+ alert->set_id(kAlertId);
alert->set_metric_id(3);
alert->set_num_buckets(10);
alert->set_refractory_period_secs(100);
@@ -218,7 +219,7 @@ StatsdConfig buildDimensionMetricsWithMultiTags() {
metric->mutable_dimensions_in_what()->add_child()->set_field(1);
auto alert = config.add_alert();
- alert->set_id(103);
+ alert->set_id(kAlertId);
alert->set_metric_id(3);
alert->set_num_buckets(10);
alert->set_refractory_period_secs(100);
@@ -284,6 +285,7 @@ TEST(MetricsManagerTest, TestGoodConfig) {
unordered_map<int, std::vector<int>> trackerToConditionMap;
unordered_map<int, std::vector<int>> activationAtomTrackerToMetricMap;
unordered_map<int, std::vector<int>> deactivationAtomTrackerToMetricMap;
+ unordered_map<int64_t, int> alertTrackerMap;
vector<int> metricsWithActivation;
std::set<int64_t> noReportMetricIds;
@@ -293,10 +295,14 @@ TEST(MetricsManagerTest, TestGoodConfig) {
allAnomalyTrackers, allAlarmTrackers, conditionToMetricMap,
trackerToMetricMap, trackerToConditionMap,
activationAtomTrackerToMetricMap, deactivationAtomTrackerToMetricMap,
- metricsWithActivation, noReportMetricIds));
+ alertTrackerMap, metricsWithActivation,
+ noReportMetricIds));
EXPECT_EQ(1u, allMetricProducers.size());
EXPECT_EQ(1u, allAnomalyTrackers.size());
EXPECT_EQ(1u, noReportMetricIds.size());
+ EXPECT_EQ(1u, alertTrackerMap.size());
+ EXPECT_NE(alertTrackerMap.find(kAlertId), alertTrackerMap.end());
+ EXPECT_EQ(alertTrackerMap.find(kAlertId)->second, 0);
}
TEST(MetricsManagerTest, TestDimensionMetricsWithMultiTags) {
@@ -316,6 +322,7 @@ TEST(MetricsManagerTest, TestDimensionMetricsWithMultiTags) {
unordered_map<int, std::vector<int>> trackerToConditionMap;
unordered_map<int, std::vector<int>> activationAtomTrackerToMetricMap;
unordered_map<int, std::vector<int>> deactivationAtomTrackerToMetricMap;
+ unordered_map<int64_t, int> alertTrackerMap;
vector<int> metricsWithActivation;
std::set<int64_t> noReportMetricIds;
@@ -325,7 +332,8 @@ TEST(MetricsManagerTest, TestDimensionMetricsWithMultiTags) {
allAnomalyTrackers, allAlarmTrackers, conditionToMetricMap,
trackerToMetricMap, trackerToConditionMap,
activationAtomTrackerToMetricMap, deactivationAtomTrackerToMetricMap,
- metricsWithActivation, noReportMetricIds));
+ alertTrackerMap, metricsWithActivation,
+ noReportMetricIds));
}
TEST(MetricsManagerTest, TestCircleLogMatcherDependency) {
@@ -345,6 +353,7 @@ TEST(MetricsManagerTest, TestCircleLogMatcherDependency) {
unordered_map<int, std::vector<int>> trackerToConditionMap;
unordered_map<int, std::vector<int>> activationAtomTrackerToMetricMap;
unordered_map<int, std::vector<int>> deactivationAtomTrackerToMetricMap;
+ unordered_map<int64_t, int> alertTrackerMap;
vector<int> metricsWithActivation;
std::set<int64_t> noReportMetricIds;
@@ -354,7 +363,8 @@ TEST(MetricsManagerTest, TestCircleLogMatcherDependency) {
allAnomalyTrackers, allAlarmTrackers, conditionToMetricMap,
trackerToMetricMap, trackerToConditionMap,
activationAtomTrackerToMetricMap, deactivationAtomTrackerToMetricMap,
- metricsWithActivation, noReportMetricIds));
+ alertTrackerMap, metricsWithActivation,
+ noReportMetricIds));
}
TEST(MetricsManagerTest, TestMissingMatchers) {
@@ -374,6 +384,7 @@ TEST(MetricsManagerTest, TestMissingMatchers) {
unordered_map<int, std::vector<int>> trackerToConditionMap;
unordered_map<int, std::vector<int>> activationAtomTrackerToMetricMap;
unordered_map<int, std::vector<int>> deactivationAtomTrackerToMetricMap;
+ unordered_map<int64_t, int> alertTrackerMap;
vector<int> metricsWithActivation;
std::set<int64_t> noReportMetricIds;
EXPECT_FALSE(initStatsdConfig(kConfigKey, config, uidMap, pullerManager, anomalyAlarmMonitor,
@@ -382,7 +393,8 @@ TEST(MetricsManagerTest, TestMissingMatchers) {
allAnomalyTrackers, allAlarmTrackers, conditionToMetricMap,
trackerToMetricMap, trackerToConditionMap,
activationAtomTrackerToMetricMap, deactivationAtomTrackerToMetricMap,
- metricsWithActivation, noReportMetricIds));
+ alertTrackerMap, metricsWithActivation,
+ noReportMetricIds));
}
TEST(MetricsManagerTest, TestMissingPredicate) {
@@ -402,6 +414,7 @@ TEST(MetricsManagerTest, TestMissingPredicate) {
unordered_map<int, std::vector<int>> trackerToConditionMap;
unordered_map<int, std::vector<int>> activationAtomTrackerToMetricMap;
unordered_map<int, std::vector<int>> deactivationAtomTrackerToMetricMap;
+ unordered_map<int64_t, int> alertTrackerMap;
vector<int> metricsWithActivation;
std::set<int64_t> noReportMetricIds;
EXPECT_FALSE(initStatsdConfig(kConfigKey, config, uidMap, pullerManager, anomalyAlarmMonitor,
@@ -410,7 +423,7 @@ TEST(MetricsManagerTest, TestMissingPredicate) {
allAnomalyTrackers, allAlarmTrackers, conditionToMetricMap,
trackerToMetricMap, trackerToConditionMap,
activationAtomTrackerToMetricMap, deactivationAtomTrackerToMetricMap,
- metricsWithActivation, noReportMetricIds));
+ alertTrackerMap, metricsWithActivation, noReportMetricIds));
}
TEST(MetricsManagerTest, TestCirclePredicateDependency) {
@@ -430,6 +443,7 @@ TEST(MetricsManagerTest, TestCirclePredicateDependency) {
unordered_map<int, std::vector<int>> trackerToConditionMap;
unordered_map<int, std::vector<int>> activationAtomTrackerToMetricMap;
unordered_map<int, std::vector<int>> deactivationAtomTrackerToMetricMap;
+ unordered_map<int64_t, int> alertTrackerMap;
vector<int> metricsWithActivation;
std::set<int64_t> noReportMetricIds;
@@ -439,7 +453,8 @@ TEST(MetricsManagerTest, TestCirclePredicateDependency) {
allAnomalyTrackers, allAlarmTrackers, conditionToMetricMap,
trackerToMetricMap, trackerToConditionMap,
activationAtomTrackerToMetricMap, deactivationAtomTrackerToMetricMap,
- metricsWithActivation, noReportMetricIds));
+ alertTrackerMap, metricsWithActivation,
+ noReportMetricIds));
}
TEST(MetricsManagerTest, testAlertWithUnknownMetric) {
@@ -459,6 +474,7 @@ TEST(MetricsManagerTest, testAlertWithUnknownMetric) {
unordered_map<int, std::vector<int>> trackerToConditionMap;
unordered_map<int, std::vector<int>> activationAtomTrackerToMetricMap;
unordered_map<int, std::vector<int>> deactivationAtomTrackerToMetricMap;
+ unordered_map<int64_t, int> alertTrackerMap;
vector<int> metricsWithActivation;
std::set<int64_t> noReportMetricIds;
@@ -468,7 +484,8 @@ TEST(MetricsManagerTest, testAlertWithUnknownMetric) {
allAnomalyTrackers, allAlarmTrackers, conditionToMetricMap,
trackerToMetricMap, trackerToConditionMap,
activationAtomTrackerToMetricMap, deactivationAtomTrackerToMetricMap,
- metricsWithActivation, noReportMetricIds));
+ alertTrackerMap, metricsWithActivation,
+ noReportMetricIds));
}
#else
diff --git a/cmds/statsd/tests/metrics/EventMetricProducer_test.cpp b/cmds/statsd/tests/metrics/EventMetricProducer_test.cpp
index 0f39efd51b58..e58bbb7893d7 100644
--- a/cmds/statsd/tests/metrics/EventMetricProducer_test.cpp
+++ b/cmds/statsd/tests/metrics/EventMetricProducer_test.cpp
@@ -13,14 +13,17 @@
// limitations under the License.
#include "src/metrics/EventMetricProducer.h"
-#include "metrics_test_helper.h"
-#include "tests/statsd_test_util.h"
#include <gmock/gmock.h>
#include <gtest/gtest.h>
#include <stdio.h>
+
#include <vector>
+#include "metrics_test_helper.h"
+#include "stats_event.h"
+#include "tests/statsd_test_util.h"
+
using namespace testing;
using android::sp;
using std::set;
@@ -35,6 +38,22 @@ namespace statsd {
const ConfigKey kConfigKey(0, 12345);
+namespace {
+void makeLogEvent(LogEvent* logEvent, int32_t atomId, int64_t timestampNs, string str) {
+ AStatsEvent* statsEvent = AStatsEvent_obtain();
+ AStatsEvent_setAtomId(statsEvent, atomId);
+ AStatsEvent_overwriteTimestamp(statsEvent, timestampNs);
+
+ AStatsEvent_writeString(statsEvent, str.c_str());
+ AStatsEvent_build(statsEvent);
+
+ size_t size;
+ uint8_t* buf = AStatsEvent_getBuffer(statsEvent, &size);
+ logEvent->parseBuffer(buf, size);
+ AStatsEvent_release(statsEvent);
+}
+} // anonymous namespace
+
TEST(EventMetricProducerTest, TestNoCondition) {
int64_t bucketStartTimeNs = 10000000000;
int64_t eventStartTimeNs = bucketStartTimeNs + 1;
@@ -43,8 +62,11 @@ TEST(EventMetricProducerTest, TestNoCondition) {
EventMetric metric;
metric.set_id(1);
- LogEvent event1(1 /*tag id*/, bucketStartTimeNs + 1);
- LogEvent event2(1 /*tag id*/, bucketStartTimeNs + 2);
+ LogEvent event1(/*uid=*/0, /*pid=*/0);
+ CreateNoValuesLogEvent(&event1, 1 /*tagId*/, bucketStartTimeNs + 1);
+
+ LogEvent event2(/*uid=*/0, /*pid=*/0);
+ CreateNoValuesLogEvent(&event2, 1 /*tagId*/, bucketStartTimeNs + 2);
sp<MockConditionWizard> wizard = new NaggyMock<MockConditionWizard>();
@@ -54,8 +76,17 @@ TEST(EventMetricProducerTest, TestNoCondition) {
eventProducer.onMatchedLogEvent(1 /*matcher index*/, event1);
eventProducer.onMatchedLogEvent(1 /*matcher index*/, event2);
- // TODO(b/110561136): get the report and check the content after the ProtoOutputStream change
- // is done eventProducer.onDumpReport();
+ // Check dump report content.
+ ProtoOutputStream output;
+ std::set<string> strSet;
+ eventProducer.onDumpReport(bucketStartTimeNs + 20, true /*include current partial bucket*/,
+ true /*erase data*/, FAST, &strSet, &output);
+
+ StatsLogReport report = outputStreamToProto(&output);
+ EXPECT_TRUE(report.has_event_metrics());
+ EXPECT_EQ(2, report.event_metrics().data_size());
+ EXPECT_EQ(bucketStartTimeNs + 1, report.event_metrics().data(0).elapsed_timestamp_nanos());
+ EXPECT_EQ(bucketStartTimeNs + 2, report.event_metrics().data(1).elapsed_timestamp_nanos());
}
TEST(EventMetricProducerTest, TestEventsWithNonSlicedCondition) {
@@ -67,8 +98,11 @@ TEST(EventMetricProducerTest, TestEventsWithNonSlicedCondition) {
metric.set_id(1);
metric.set_condition(StringToId("SCREEN_ON"));
- LogEvent event1(1, bucketStartTimeNs + 1);
- LogEvent event2(1, bucketStartTimeNs + 10);
+ LogEvent event1(/*uid=*/0, /*pid=*/0);
+ CreateNoValuesLogEvent(&event1, 1 /*tagId*/, bucketStartTimeNs + 1);
+
+ LogEvent event2(/*uid=*/0, /*pid=*/0);
+ CreateNoValuesLogEvent(&event2, 1 /*tagId*/, bucketStartTimeNs + 10);
sp<MockConditionWizard> wizard = new NaggyMock<MockConditionWizard>();
@@ -81,51 +115,67 @@ TEST(EventMetricProducerTest, TestEventsWithNonSlicedCondition) {
eventProducer.onMatchedLogEvent(1 /*matcher index*/, event2);
- // TODO: get the report and check the content after the ProtoOutputStream change is done.
- // eventProducer.onDumpReport();
+ // Check dump report content.
+ ProtoOutputStream output;
+ std::set<string> strSet;
+ eventProducer.onDumpReport(bucketStartTimeNs + 20, true /*include current partial bucket*/,
+ true /*erase data*/, FAST, &strSet, &output);
+
+ StatsLogReport report = outputStreamToProto(&output);
+ EXPECT_TRUE(report.has_event_metrics());
+ EXPECT_EQ(1, report.event_metrics().data_size());
+ EXPECT_EQ(bucketStartTimeNs + 1, report.event_metrics().data(0).elapsed_timestamp_nanos());
}
-// TODO(b/149590301): Update this test to use new socket schema.
-//TEST(EventMetricProducerTest, TestEventsWithSlicedCondition) {
-// int64_t bucketStartTimeNs = 10000000000;
-// int64_t bucketSizeNs = 30 * 1000 * 1000 * 1000LL;
-//
-// int tagId = 1;
-// int conditionTagId = 2;
-//
-// EventMetric metric;
-// metric.set_id(1);
-// metric.set_condition(StringToId("APP_IN_BACKGROUND_PER_UID_AND_SCREEN_ON"));
-// MetricConditionLink* link = metric.add_links();
-// link->set_condition(StringToId("APP_IN_BACKGROUND_PER_UID"));
-// buildSimpleAtomFieldMatcher(tagId, 1, link->mutable_fields_in_what());
-// buildSimpleAtomFieldMatcher(conditionTagId, 2, link->mutable_fields_in_condition());
-//
-// LogEvent event1(tagId, bucketStartTimeNs + 1);
-// EXPECT_TRUE(event1.write("111"));
-// event1.init();
-// ConditionKey key1;
-// key1[StringToId("APP_IN_BACKGROUND_PER_UID")] = {getMockedDimensionKey(conditionTagId, 2, "111")};
-//
-// LogEvent event2(tagId, bucketStartTimeNs + 10);
-// EXPECT_TRUE(event2.write("222"));
-// event2.init();
-// ConditionKey key2;
-// key2[StringToId("APP_IN_BACKGROUND_PER_UID")] = {getMockedDimensionKey(conditionTagId, 2, "222")};
-//
-// sp<MockConditionWizard> wizard = new NaggyMock<MockConditionWizard>();
-// EXPECT_CALL(*wizard, query(_, key1, _)).WillOnce(Return(ConditionState::kFalse));
-//
-// EXPECT_CALL(*wizard, query(_, key2, _)).WillOnce(Return(ConditionState::kTrue));
-//
-// EventMetricProducer eventProducer(kConfigKey, metric, 1, wizard, bucketStartTimeNs);
-//
-// eventProducer.onMatchedLogEvent(1 /*matcher index*/, event1);
-// eventProducer.onMatchedLogEvent(1 /*matcher index*/, event2);
-//
-// // TODO: get the report and check the content after the ProtoOutputStream change is done.
-// // eventProducer.onDumpReport();
-//}
+TEST(EventMetricProducerTest, TestEventsWithSlicedCondition) {
+ int64_t bucketStartTimeNs = 10000000000;
+ int64_t bucketSizeNs = 30 * 1000 * 1000 * 1000LL;
+
+ int tagId = 1;
+ int conditionTagId = 2;
+
+ EventMetric metric;
+ metric.set_id(1);
+ metric.set_condition(StringToId("APP_IN_BACKGROUND_PER_UID_AND_SCREEN_ON"));
+ MetricConditionLink* link = metric.add_links();
+ link->set_condition(StringToId("APP_IN_BACKGROUND_PER_UID"));
+ buildSimpleAtomFieldMatcher(tagId, 1, link->mutable_fields_in_what());
+ buildSimpleAtomFieldMatcher(conditionTagId, 2, link->mutable_fields_in_condition());
+
+ LogEvent event1(/*uid=*/0, /*pid=*/0);
+ makeLogEvent(&event1, 1 /*tagId*/, bucketStartTimeNs + 1, "111");
+ ConditionKey key1;
+ key1[StringToId("APP_IN_BACKGROUND_PER_UID")] = {
+ getMockedDimensionKey(conditionTagId, 2, "111")};
+
+ LogEvent event2(/*uid=*/0, /*pid=*/0);
+ makeLogEvent(&event2, 1 /*tagId*/, bucketStartTimeNs + 10, "222");
+ ConditionKey key2;
+ key2[StringToId("APP_IN_BACKGROUND_PER_UID")] = {
+ getMockedDimensionKey(conditionTagId, 2, "222")};
+
+ sp<MockConditionWizard> wizard = new NaggyMock<MockConditionWizard>();
+ // Condition is false for first event.
+ EXPECT_CALL(*wizard, query(_, key1, _)).WillOnce(Return(ConditionState::kFalse));
+ // Condition is true for second event.
+ EXPECT_CALL(*wizard, query(_, key2, _)).WillOnce(Return(ConditionState::kTrue));
+
+ EventMetricProducer eventProducer(kConfigKey, metric, 1, wizard, bucketStartTimeNs);
+
+ eventProducer.onMatchedLogEvent(1 /*matcher index*/, event1);
+ eventProducer.onMatchedLogEvent(1 /*matcher index*/, event2);
+
+ // Check dump report content.
+ ProtoOutputStream output;
+ std::set<string> strSet;
+ eventProducer.onDumpReport(bucketStartTimeNs + 20, true /*include current partial bucket*/,
+ true /*erase data*/, FAST, &strSet, &output);
+
+ StatsLogReport report = outputStreamToProto(&output);
+ EXPECT_TRUE(report.has_event_metrics());
+ EXPECT_EQ(1, report.event_metrics().data_size());
+ EXPECT_EQ(bucketStartTimeNs + 10, report.event_metrics().data(0).elapsed_timestamp_nanos());
+}
} // namespace statsd
} // namespace os
diff --git a/cmds/statsd/tests/metrics/GaugeMetricProducer_test.cpp b/cmds/statsd/tests/metrics/GaugeMetricProducer_test.cpp
index 609324e91daa..d372ffd7e689 100644
--- a/cmds/statsd/tests/metrics/GaugeMetricProducer_test.cpp
+++ b/cmds/statsd/tests/metrics/GaugeMetricProducer_test.cpp
@@ -26,6 +26,7 @@
#include "src/matchers/SimpleLogMatchingTracker.h"
#include "src/metrics/MetricProducer.h"
#include "src/stats_log_util.h"
+#include "stats_event.h"
#include "tests/statsd_test_util.h"
using namespace testing;
@@ -53,6 +54,28 @@ const int64_t bucket3StartTimeNs = bucketStartTimeNs + 2 * bucketSizeNs;
const int64_t bucket4StartTimeNs = bucketStartTimeNs + 3 * bucketSizeNs;
const int64_t eventUpgradeTimeNs = bucketStartTimeNs + 15 * NS_PER_SEC;
+namespace {
+shared_ptr<LogEvent> makeLogEvent(int32_t atomId, int64_t timestampNs, int32_t value1, string str1,
+ int32_t value2) {
+ AStatsEvent* statsEvent = AStatsEvent_obtain();
+ AStatsEvent_setAtomId(statsEvent, atomId);
+ AStatsEvent_overwriteTimestamp(statsEvent, timestampNs);
+
+ AStatsEvent_writeInt32(statsEvent, value1);
+ AStatsEvent_writeString(statsEvent, str1.c_str());
+ AStatsEvent_writeInt32(statsEvent, value2);
+ AStatsEvent_build(statsEvent);
+
+ size_t size;
+ uint8_t* buf = AStatsEvent_getBuffer(statsEvent, &size);
+ shared_ptr<LogEvent> logEvent = std::make_shared<LogEvent>(/*uid=*/0, /*pid=*/0);
+ logEvent->parseBuffer(buf, size);
+ AStatsEvent_release(statsEvent);
+
+ return logEvent;
+}
+} // anonymous namespace
+
/*
* Tests that the first bucket works correctly
*/
@@ -88,769 +111,685 @@ TEST(GaugeMetricProducerTest, TestFirstBucket) {
EXPECT_EQ(660000000005, gaugeProducer.getCurrentBucketEndTimeNs());
}
-// TODO(b/149590301): Update these tests to use new socket schema.
-//TEST(GaugeMetricProducerTest, TestPulledEventsNoCondition) {
-// GaugeMetric metric;
-// metric.set_id(metricId);
-// metric.set_bucket(ONE_MINUTE);
-// metric.mutable_gauge_fields_filter()->set_include_all(false);
-// metric.set_max_pull_delay_sec(INT_MAX);
-// auto gaugeFieldMatcher = metric.mutable_gauge_fields_filter()->mutable_fields();
-// gaugeFieldMatcher->set_field(tagId);
-// gaugeFieldMatcher->add_child()->set_field(1);
-// gaugeFieldMatcher->add_child()->set_field(3);
-//
-// sp<MockConditionWizard> wizard = new NaggyMock<MockConditionWizard>();
-//
-// UidMap uidMap;
-// SimpleAtomMatcher atomMatcher;
-// atomMatcher.set_atom_id(tagId);
-// sp<EventMatcherWizard> eventMatcherWizard = new EventMatcherWizard({
-// new SimpleLogMatchingTracker(atomMatcherId, logEventMatcherIndex, atomMatcher, uidMap)});
-//
-// sp<MockStatsPullerManager> pullerManager = new StrictMock<MockStatsPullerManager>();
-// EXPECT_CALL(*pullerManager, RegisterReceiver(tagId, _, _, _)).WillOnce(Return());
-// EXPECT_CALL(*pullerManager, UnRegisterReceiver(tagId, _)).WillOnce(Return());
-// EXPECT_CALL(*pullerManager, Pull(tagId, _))
-// .WillOnce(Invoke([](int tagId, vector<std::shared_ptr<LogEvent>>* data) {
-// data->clear();
-// shared_ptr<LogEvent> event = make_shared<LogEvent>(tagId, bucketStartTimeNs + 10);
-// event->write(3);
-// event->write("some value");
-// event->write(11);
-// event->init();
-// data->push_back(event);
-// return true;
-// }));
-//
-// GaugeMetricProducer gaugeProducer(kConfigKey, metric, -1 /*-1 meaning no condition*/, wizard,
-// logEventMatcherIndex, eventMatcherWizard,
-// tagId, -1, tagId, bucketStartTimeNs, bucketStartTimeNs,
-// pullerManager);
-//
-// vector<shared_ptr<LogEvent>> allData;
-// allData.clear();
-// shared_ptr<LogEvent> event = make_shared<LogEvent>(tagId, bucket2StartTimeNs + 1);
-// event->write(10);
-// event->write("some value");
-// event->write(11);
-// event->init();
-// allData.push_back(event);
-//
-// gaugeProducer.onDataPulled(allData, /** succeed */ true, bucket2StartTimeNs);
-// EXPECT_EQ(1UL, gaugeProducer.mCurrentSlicedBucket->size());
-// auto it = gaugeProducer.mCurrentSlicedBucket->begin()->second.front().mFields->begin();
-// EXPECT_EQ(INT, it->mValue.getType());
-// EXPECT_EQ(10, it->mValue.int_value);
-// it++;
-// EXPECT_EQ(11, it->mValue.int_value);
-// EXPECT_EQ(1UL, gaugeProducer.mPastBuckets.size());
-// EXPECT_EQ(3, gaugeProducer.mPastBuckets.begin()->second.back().mGaugeAtoms
-// .front().mFields->begin()->mValue.int_value);
-//
-// allData.clear();
-// std::shared_ptr<LogEvent> event2 = std::make_shared<LogEvent>(tagId, bucket3StartTimeNs + 10);
-// event2->write(24);
-// event2->write("some value");
-// event2->write(25);
-// event2->init();
-// allData.push_back(event2);
-// gaugeProducer.onDataPulled(allData, /** succeed */ true, bucket3StartTimeNs);
-// EXPECT_EQ(1UL, gaugeProducer.mCurrentSlicedBucket->size());
-// it = gaugeProducer.mCurrentSlicedBucket->begin()->second.front().mFields->begin();
-// EXPECT_EQ(INT, it->mValue.getType());
-// EXPECT_EQ(24, it->mValue.int_value);
-// it++;
-// EXPECT_EQ(INT, it->mValue.getType());
-// EXPECT_EQ(25, it->mValue.int_value);
-// // One dimension.
-// EXPECT_EQ(1UL, gaugeProducer.mPastBuckets.size());
-// EXPECT_EQ(2UL, gaugeProducer.mPastBuckets.begin()->second.size());
-// it = gaugeProducer.mPastBuckets.begin()->second.back().mGaugeAtoms.front().mFields->begin();
-// EXPECT_EQ(INT, it->mValue.getType());
-// EXPECT_EQ(10L, it->mValue.int_value);
-// it++;
-// EXPECT_EQ(INT, it->mValue.getType());
-// EXPECT_EQ(11L, it->mValue.int_value);
-//
-// gaugeProducer.flushIfNeededLocked(bucket4StartTimeNs);
-// EXPECT_EQ(0UL, gaugeProducer.mCurrentSlicedBucket->size());
-// // One dimension.
-// EXPECT_EQ(1UL, gaugeProducer.mPastBuckets.size());
-// EXPECT_EQ(3UL, gaugeProducer.mPastBuckets.begin()->second.size());
-// it = gaugeProducer.mPastBuckets.begin()->second.back().mGaugeAtoms.front().mFields->begin();
-// EXPECT_EQ(INT, it->mValue.getType());
-// EXPECT_EQ(24L, it->mValue.int_value);
-// it++;
-// EXPECT_EQ(INT, it->mValue.getType());
-// EXPECT_EQ(25L, it->mValue.int_value);
-//}
-//
-//TEST(GaugeMetricProducerTest, TestPushedEventsWithUpgrade) {
-// sp<AlarmMonitor> alarmMonitor;
-// GaugeMetric metric;
-// metric.set_id(metricId);
-// metric.set_bucket(ONE_MINUTE);
-// metric.mutable_gauge_fields_filter()->set_include_all(true);
-//
-// Alert alert;
-// alert.set_id(101);
-// alert.set_metric_id(metricId);
-// alert.set_trigger_if_sum_gt(25);
-// alert.set_num_buckets(100);
-// sp<MockConditionWizard> wizard = new NaggyMock<MockConditionWizard>();
-// sp<MockStatsPullerManager> pullerManager = new StrictMock<MockStatsPullerManager>();
-//
-// UidMap uidMap;
-// SimpleAtomMatcher atomMatcher;
-// atomMatcher.set_atom_id(tagId);
-// sp<EventMatcherWizard> eventMatcherWizard = new EventMatcherWizard({
-// new SimpleLogMatchingTracker(atomMatcherId, logEventMatcherIndex, atomMatcher, uidMap)});
-//
-// GaugeMetricProducer gaugeProducer(kConfigKey, metric, -1 /*-1 meaning no condition*/, wizard,
-// logEventMatcherIndex, eventMatcherWizard,
-// -1 /* -1 means no pulling */, -1, tagId, bucketStartTimeNs,
-// bucketStartTimeNs, pullerManager);
-//
-// sp<AnomalyTracker> anomalyTracker = gaugeProducer.addAnomalyTracker(alert, alarmMonitor);
-// EXPECT_TRUE(anomalyTracker != nullptr);
-//
-// shared_ptr<LogEvent> event1 = make_shared<LogEvent>(tagId, bucketStartTimeNs + 10);
-// event1->write(1);
-// event1->write(10);
-// event1->init();
-// gaugeProducer.onMatchedLogEvent(1 /*log matcher index*/, *event1);
-// EXPECT_EQ(1UL, (*gaugeProducer.mCurrentSlicedBucket).count(DEFAULT_METRIC_DIMENSION_KEY));
-//
-// gaugeProducer.notifyAppUpgrade(eventUpgradeTimeNs, "ANY.APP", 1, 1);
-// EXPECT_EQ(0UL, (*gaugeProducer.mCurrentSlicedBucket).count(DEFAULT_METRIC_DIMENSION_KEY));
-// EXPECT_EQ(1UL, gaugeProducer.mPastBuckets[DEFAULT_METRIC_DIMENSION_KEY].size());
-// EXPECT_EQ(0L, gaugeProducer.mCurrentBucketNum);
-// EXPECT_EQ(eventUpgradeTimeNs, gaugeProducer.mCurrentBucketStartTimeNs);
-// // Partial buckets are not sent to anomaly tracker.
-// EXPECT_EQ(0, anomalyTracker->getSumOverPastBuckets(DEFAULT_METRIC_DIMENSION_KEY));
-//
-// // Create an event in the same partial bucket.
-// shared_ptr<LogEvent> event2 = make_shared<LogEvent>(tagId, bucketStartTimeNs + 59 * NS_PER_SEC);
-// event2->write(1);
-// event2->write(10);
-// event2->init();
-// gaugeProducer.onMatchedLogEvent(1 /*log matcher index*/, *event2);
-// EXPECT_EQ(0L, gaugeProducer.mCurrentBucketNum);
-// EXPECT_EQ(1UL, gaugeProducer.mPastBuckets[DEFAULT_METRIC_DIMENSION_KEY].size());
-// EXPECT_EQ((int64_t)eventUpgradeTimeNs, gaugeProducer.mCurrentBucketStartTimeNs);
-// // Partial buckets are not sent to anomaly tracker.
-// EXPECT_EQ(0, anomalyTracker->getSumOverPastBuckets(DEFAULT_METRIC_DIMENSION_KEY));
-//
-// // Next event should trigger creation of new bucket and send previous full bucket to anomaly
-// // tracker.
-// shared_ptr<LogEvent> event3 = make_shared<LogEvent>(tagId, bucketStartTimeNs + 65 * NS_PER_SEC);
-// event3->write(1);
-// event3->write(10);
-// event3->init();
-// gaugeProducer.onMatchedLogEvent(1 /*log matcher index*/, *event3);
-// EXPECT_EQ(1L, gaugeProducer.mCurrentBucketNum);
-// EXPECT_EQ(2UL, gaugeProducer.mPastBuckets[DEFAULT_METRIC_DIMENSION_KEY].size());
-// EXPECT_EQ((int64_t)bucketStartTimeNs + bucketSizeNs, gaugeProducer.mCurrentBucketStartTimeNs);
-// EXPECT_EQ(1, anomalyTracker->getSumOverPastBuckets(DEFAULT_METRIC_DIMENSION_KEY));
-//
-// // Next event should trigger creation of new bucket.
-// shared_ptr<LogEvent> event4 =
-// make_shared<LogEvent>(tagId, bucketStartTimeNs + 125 * NS_PER_SEC);
-// event4->write(1);
-// event4->write(10);
-// event4->init();
-// gaugeProducer.onMatchedLogEvent(1 /*log matcher index*/, *event4);
-// EXPECT_EQ(2L, gaugeProducer.mCurrentBucketNum);
-// EXPECT_EQ(3UL, gaugeProducer.mPastBuckets[DEFAULT_METRIC_DIMENSION_KEY].size());
-// EXPECT_EQ(2, anomalyTracker->getSumOverPastBuckets(DEFAULT_METRIC_DIMENSION_KEY));
-//}
-//
-//TEST(GaugeMetricProducerTest, TestPulledWithUpgrade) {
-// GaugeMetric metric;
-// metric.set_id(metricId);
-// metric.set_bucket(ONE_MINUTE);
-// metric.set_max_pull_delay_sec(INT_MAX);
-// auto gaugeFieldMatcher = metric.mutable_gauge_fields_filter()->mutable_fields();
-// gaugeFieldMatcher->set_field(tagId);
-// gaugeFieldMatcher->add_child()->set_field(2);
-//
-// sp<MockConditionWizard> wizard = new NaggyMock<MockConditionWizard>();
-//
-// UidMap uidMap;
-// SimpleAtomMatcher atomMatcher;
-// atomMatcher.set_atom_id(tagId);
-// sp<EventMatcherWizard> eventMatcherWizard =
-// new EventMatcherWizard({new SimpleLogMatchingTracker(
-// atomMatcherId, logEventMatcherIndex, atomMatcher, uidMap)});
-//
-// sp<MockStatsPullerManager> pullerManager = new StrictMock<MockStatsPullerManager>();
-// EXPECT_CALL(*pullerManager, RegisterReceiver(tagId, _, _, _)).WillOnce(Return());
-// EXPECT_CALL(*pullerManager, UnRegisterReceiver(tagId, _)).WillOnce(Return());
-// EXPECT_CALL(*pullerManager, Pull(tagId, _))
-// .WillOnce(Return(false))
-// .WillOnce(Invoke([](int tagId, vector<std::shared_ptr<LogEvent>>* data) {
-// data->clear();
-// shared_ptr<LogEvent> event = make_shared<LogEvent>(tagId, eventUpgradeTimeNs);
-// event->write("some value");
-// event->write(2);
-// event->init();
-// data->push_back(event);
-// return true;
-// }));
-//
-// GaugeMetricProducer gaugeProducer(kConfigKey, metric, -1 /*-1 meaning no condition*/, wizard,
-// logEventMatcherIndex, eventMatcherWizard, tagId, -1, tagId,
-// bucketStartTimeNs, bucketStartTimeNs, pullerManager);
-//
-// vector<shared_ptr<LogEvent>> allData;
-// shared_ptr<LogEvent> event = make_shared<LogEvent>(tagId, bucketStartTimeNs + 1);
-// event->write("some value");
-// event->write(1);
-// event->init();
-// allData.push_back(event);
-// gaugeProducer.onDataPulled(allData, /** succeed */ true, bucketStartTimeNs);
-// EXPECT_EQ(1UL, gaugeProducer.mCurrentSlicedBucket->size());
-// EXPECT_EQ(1, gaugeProducer.mCurrentSlicedBucket->begin()
-// ->second.front()
-// .mFields->begin()
-// ->mValue.int_value);
-//
-// gaugeProducer.notifyAppUpgrade(eventUpgradeTimeNs, "ANY.APP", 1, 1);
-// EXPECT_EQ(1UL, gaugeProducer.mPastBuckets[DEFAULT_METRIC_DIMENSION_KEY].size());
-// EXPECT_EQ(0L, gaugeProducer.mCurrentBucketNum);
-// EXPECT_EQ((int64_t)eventUpgradeTimeNs, gaugeProducer.mCurrentBucketStartTimeNs);
-// EXPECT_EQ(1UL, gaugeProducer.mCurrentSlicedBucket->size());
-// EXPECT_EQ(2, gaugeProducer.mCurrentSlicedBucket->begin()
-// ->second.front()
-// .mFields->begin()
-// ->mValue.int_value);
-//
-// allData.clear();
-// event = make_shared<LogEvent>(tagId, bucketStartTimeNs + bucketSizeNs + 1);
-// event->write("some value");
-// event->write(3);
-// event->init();
-// allData.push_back(event);
-// gaugeProducer.onDataPulled(allData, /** succeed */ true, bucketStartTimeNs + bucketSizeNs);
-// EXPECT_EQ(2UL, gaugeProducer.mPastBuckets[DEFAULT_METRIC_DIMENSION_KEY].size());
-// EXPECT_EQ(1UL, gaugeProducer.mCurrentSlicedBucket->size());
-// EXPECT_EQ(3, gaugeProducer.mCurrentSlicedBucket->begin()
-// ->second.front()
-// .mFields->begin()
-// ->mValue.int_value);
-//}
-//
-//TEST(GaugeMetricProducerTest, TestPulledWithAppUpgradeDisabled) {
-// GaugeMetric metric;
-// metric.set_id(metricId);
-// metric.set_bucket(ONE_MINUTE);
-// metric.set_max_pull_delay_sec(INT_MAX);
-// metric.set_split_bucket_for_app_upgrade(false);
-// auto gaugeFieldMatcher = metric.mutable_gauge_fields_filter()->mutable_fields();
-// gaugeFieldMatcher->set_field(tagId);
-// gaugeFieldMatcher->add_child()->set_field(2);
-//
-// sp<MockConditionWizard> wizard = new NaggyMock<MockConditionWizard>();
-//
-// UidMap uidMap;
-// SimpleAtomMatcher atomMatcher;
-// atomMatcher.set_atom_id(tagId);
-// sp<EventMatcherWizard> eventMatcherWizard = new EventMatcherWizard({
-// new SimpleLogMatchingTracker(atomMatcherId, logEventMatcherIndex, atomMatcher, uidMap)});
-//
-// sp<MockStatsPullerManager> pullerManager = new StrictMock<MockStatsPullerManager>();
-// EXPECT_CALL(*pullerManager, RegisterReceiver(tagId, _, _, _)).WillOnce(Return());
-// EXPECT_CALL(*pullerManager, UnRegisterReceiver(tagId, _)).WillOnce(Return());
-// EXPECT_CALL(*pullerManager, Pull(tagId, _)).WillOnce(Return(false));
-//
-// GaugeMetricProducer gaugeProducer(kConfigKey, metric, -1 /*-1 meaning no condition*/, wizard,
-// logEventMatcherIndex, eventMatcherWizard,
-// tagId, -1, tagId, bucketStartTimeNs, bucketStartTimeNs,
-// pullerManager);
-//
-// vector<shared_ptr<LogEvent>> allData;
-// shared_ptr<LogEvent> event = make_shared<LogEvent>(tagId, bucketStartTimeNs + 1);
-// event->write("some value");
-// event->write(1);
-// event->init();
-// allData.push_back(event);
-// gaugeProducer.onDataPulled(allData, /** succeed */ true, bucketStartTimeNs);
-// EXPECT_EQ(1UL, gaugeProducer.mCurrentSlicedBucket->size());
-// EXPECT_EQ(1, gaugeProducer.mCurrentSlicedBucket->begin()
-// ->second.front()
-// .mFields->begin()
-// ->mValue.int_value);
-//
-// gaugeProducer.notifyAppUpgrade(eventUpgradeTimeNs, "ANY.APP", 1, 1);
-// EXPECT_EQ(0UL, gaugeProducer.mPastBuckets[DEFAULT_METRIC_DIMENSION_KEY].size());
-// EXPECT_EQ(0L, gaugeProducer.mCurrentBucketNum);
-// EXPECT_EQ(bucketStartTimeNs, gaugeProducer.mCurrentBucketStartTimeNs);
-// EXPECT_EQ(1UL, gaugeProducer.mCurrentSlicedBucket->size());
-// EXPECT_EQ(1, gaugeProducer.mCurrentSlicedBucket->begin()
-// ->second.front()
-// .mFields->begin()
-// ->mValue.int_value);
-//}
-//
-//TEST(GaugeMetricProducerTest, TestPulledEventsWithCondition) {
-// GaugeMetric metric;
-// metric.set_id(metricId);
-// metric.set_bucket(ONE_MINUTE);
-// metric.set_max_pull_delay_sec(INT_MAX);
-// auto gaugeFieldMatcher = metric.mutable_gauge_fields_filter()->mutable_fields();
-// gaugeFieldMatcher->set_field(tagId);
-// gaugeFieldMatcher->add_child()->set_field(2);
-// metric.set_condition(StringToId("SCREEN_ON"));
-//
-// sp<MockConditionWizard> wizard = new NaggyMock<MockConditionWizard>();
-//
-// UidMap uidMap;
-// SimpleAtomMatcher atomMatcher;
-// atomMatcher.set_atom_id(tagId);
-// sp<EventMatcherWizard> eventMatcherWizard = new EventMatcherWizard({
-// new SimpleLogMatchingTracker(atomMatcherId, logEventMatcherIndex, atomMatcher, uidMap)});
-//
-// sp<MockStatsPullerManager> pullerManager = new StrictMock<MockStatsPullerManager>();
-// EXPECT_CALL(*pullerManager, RegisterReceiver(tagId, _, _, _)).WillOnce(Return());
-// EXPECT_CALL(*pullerManager, UnRegisterReceiver(tagId, _)).WillOnce(Return());
-// EXPECT_CALL(*pullerManager, Pull(tagId, _))
-// .WillOnce(Invoke([](int tagId, vector<std::shared_ptr<LogEvent>>* data) {
-// data->clear();
-// shared_ptr<LogEvent> event = make_shared<LogEvent>(tagId, bucketStartTimeNs + 10);
-// event->write("some value");
-// event->write(100);
-// event->init();
-// data->push_back(event);
-// return true;
-// }));
-//
-// GaugeMetricProducer gaugeProducer(kConfigKey, metric, 1, wizard,
-// logEventMatcherIndex, eventMatcherWizard, tagId, -1, tagId,
-// bucketStartTimeNs, bucketStartTimeNs, pullerManager);
-//
-// gaugeProducer.onConditionChanged(true, bucketStartTimeNs + 8);
-// EXPECT_EQ(1UL, gaugeProducer.mCurrentSlicedBucket->size());
-// EXPECT_EQ(100, gaugeProducer.mCurrentSlicedBucket->begin()
-// ->second.front()
-// .mFields->begin()
-// ->mValue.int_value);
-// EXPECT_EQ(0UL, gaugeProducer.mPastBuckets.size());
-//
-// vector<shared_ptr<LogEvent>> allData;
-// allData.clear();
-// shared_ptr<LogEvent> event = make_shared<LogEvent>(tagId, bucket2StartTimeNs + 1);
-// event->write("some value");
-// event->write(110);
-// event->init();
-// allData.push_back(event);
-// gaugeProducer.onDataPulled(allData, /** succeed */ true, bucket2StartTimeNs);
-//
-// EXPECT_EQ(1UL, gaugeProducer.mCurrentSlicedBucket->size());
-// EXPECT_EQ(110, gaugeProducer.mCurrentSlicedBucket->begin()
-// ->second.front()
-// .mFields->begin()
-// ->mValue.int_value);
-// EXPECT_EQ(1UL, gaugeProducer.mPastBuckets.size());
-// EXPECT_EQ(100, gaugeProducer.mPastBuckets.begin()
-// ->second.back()
-// .mGaugeAtoms.front()
-// .mFields->begin()
-// ->mValue.int_value);
-//
-// gaugeProducer.onConditionChanged(false, bucket2StartTimeNs + 10);
-// gaugeProducer.flushIfNeededLocked(bucket3StartTimeNs + 10);
-// EXPECT_EQ(1UL, gaugeProducer.mPastBuckets.size());
-// EXPECT_EQ(2UL, gaugeProducer.mPastBuckets.begin()->second.size());
-// EXPECT_EQ(110L, gaugeProducer.mPastBuckets.begin()
-// ->second.back()
-// .mGaugeAtoms.front()
-// .mFields->begin()
-// ->mValue.int_value);
-//}
-//
-//TEST(GaugeMetricProducerTest, TestPulledEventsWithSlicedCondition) {
-// const int conditionTag = 65;
-// GaugeMetric metric;
-// metric.set_id(1111111);
-// metric.set_bucket(ONE_MINUTE);
-// metric.mutable_gauge_fields_filter()->set_include_all(true);
-// metric.set_condition(StringToId("APP_DIED"));
-// metric.set_max_pull_delay_sec(INT_MAX);
-// auto dim = metric.mutable_dimensions_in_what();
-// dim->set_field(tagId);
-// dim->add_child()->set_field(1);
-//
-// UidMap uidMap;
-// SimpleAtomMatcher atomMatcher;
-// atomMatcher.set_atom_id(tagId);
-// sp<EventMatcherWizard> eventMatcherWizard = new EventMatcherWizard({
-// new SimpleLogMatchingTracker(atomMatcherId, logEventMatcherIndex, atomMatcher, uidMap)});
-//
-// sp<MockConditionWizard> wizard = new NaggyMock<MockConditionWizard>();
-// EXPECT_CALL(*wizard, query(_, _, _))
-// .WillRepeatedly(
-// Invoke([](const int conditionIndex, const ConditionKey& conditionParameters,
-// const bool isPartialLink) {
-// int pos[] = {1, 0, 0};
-// Field f(conditionTag, pos, 0);
-// HashableDimensionKey key;
-// key.mutableValues()->emplace_back(f, Value((int32_t)1000000));
-//
-// return ConditionState::kTrue;
-// }));
-//
-// sp<MockStatsPullerManager> pullerManager = new StrictMock<MockStatsPullerManager>();
-// EXPECT_CALL(*pullerManager, RegisterReceiver(tagId, _, _, _)).WillOnce(Return());
-// EXPECT_CALL(*pullerManager, UnRegisterReceiver(tagId, _)).WillOnce(Return());
-// EXPECT_CALL(*pullerManager, Pull(tagId, _))
-// .WillOnce(Invoke([](int tagId, vector<std::shared_ptr<LogEvent>>* data) {
-// data->clear();
-// shared_ptr<LogEvent> event = make_shared<LogEvent>(tagId, bucketStartTimeNs + 10);
-// event->write(1000);
-// event->write(100);
-// event->init();
-// data->push_back(event);
-// return true;
-// }));
-//
-// GaugeMetricProducer gaugeProducer(kConfigKey, metric, 1, wizard,
-// logEventMatcherIndex, eventMatcherWizard, tagId, -1, tagId,
-// bucketStartTimeNs, bucketStartTimeNs, pullerManager);
-//
-// gaugeProducer.onSlicedConditionMayChange(true, bucketStartTimeNs + 8);
-//
-// EXPECT_EQ(1UL, gaugeProducer.mCurrentSlicedBucket->size());
-// const auto& key = gaugeProducer.mCurrentSlicedBucket->begin()->first;
-// EXPECT_EQ(1UL, key.getDimensionKeyInWhat().getValues().size());
-// EXPECT_EQ(1000, key.getDimensionKeyInWhat().getValues()[0].mValue.int_value);
-//
-// EXPECT_EQ(0UL, gaugeProducer.mPastBuckets.size());
-//
-// vector<shared_ptr<LogEvent>> allData;
-// allData.clear();
-// shared_ptr<LogEvent> event = make_shared<LogEvent>(tagId, bucket2StartTimeNs + 1);
-// event->write(1000);
-// event->write(110);
-// event->init();
-// allData.push_back(event);
-// gaugeProducer.onDataPulled(allData, /** succeed */ true, bucket2StartTimeNs);
-//
-// EXPECT_EQ(1UL, gaugeProducer.mCurrentSlicedBucket->size());
-// EXPECT_EQ(1UL, gaugeProducer.mPastBuckets.size());
-//}
-//
-//TEST(GaugeMetricProducerTest, TestPulledEventsAnomalyDetection) {
-// sp<AlarmMonitor> alarmMonitor;
-// sp<MockConditionWizard> wizard = new NaggyMock<MockConditionWizard>();
-//
-// sp<MockStatsPullerManager> pullerManager = new StrictMock<MockStatsPullerManager>();
-// EXPECT_CALL(*pullerManager, RegisterReceiver(tagId, _, _, _)).WillOnce(Return());
-// EXPECT_CALL(*pullerManager, UnRegisterReceiver(tagId, _)).WillOnce(Return());
-// EXPECT_CALL(*pullerManager, Pull(tagId, _)).WillOnce(Return(false));
-//
-// GaugeMetric metric;
-// metric.set_id(metricId);
-// metric.set_bucket(ONE_MINUTE);
-// metric.set_max_pull_delay_sec(INT_MAX);
-// auto gaugeFieldMatcher = metric.mutable_gauge_fields_filter()->mutable_fields();
-// gaugeFieldMatcher->set_field(tagId);
-// gaugeFieldMatcher->add_child()->set_field(2);
-//
-// UidMap uidMap;
-// SimpleAtomMatcher atomMatcher;
-// atomMatcher.set_atom_id(tagId);
-// sp<EventMatcherWizard> eventMatcherWizard = new EventMatcherWizard({
-// new SimpleLogMatchingTracker(atomMatcherId, logEventMatcherIndex, atomMatcher, uidMap)});
-//
-// GaugeMetricProducer gaugeProducer(kConfigKey, metric, -1 /*-1 meaning no condition*/, wizard,
-// logEventMatcherIndex, eventMatcherWizard,
-// tagId, -1, tagId, bucketStartTimeNs, bucketStartTimeNs,
-// pullerManager);
-//
-// Alert alert;
-// alert.set_id(101);
-// alert.set_metric_id(metricId);
-// alert.set_trigger_if_sum_gt(25);
-// alert.set_num_buckets(2);
-// const int32_t refPeriodSec = 60;
-// alert.set_refractory_period_secs(refPeriodSec);
-// sp<AnomalyTracker> anomalyTracker = gaugeProducer.addAnomalyTracker(alert, alarmMonitor);
-//
-// int tagId = 1;
-// std::shared_ptr<LogEvent> event1 = std::make_shared<LogEvent>(tagId, bucketStartTimeNs + 1);
-// event1->write("some value");
-// event1->write(13);
-// event1->init();
-//
-// gaugeProducer.onDataPulled({event1}, /** succeed */ true, bucketStartTimeNs);
-// EXPECT_EQ(1UL, gaugeProducer.mCurrentSlicedBucket->size());
-// EXPECT_EQ(13L, gaugeProducer.mCurrentSlicedBucket->begin()
-// ->second.front()
-// .mFields->begin()
-// ->mValue.int_value);
-// EXPECT_EQ(anomalyTracker->getRefractoryPeriodEndsSec(DEFAULT_METRIC_DIMENSION_KEY), 0U);
-//
-// std::shared_ptr<LogEvent> event2 =
-// std::make_shared<LogEvent>(tagId, bucketStartTimeNs + bucketSizeNs + 20);
-// event2->write("some value");
-// event2->write(15);
-// event2->init();
-//
-// gaugeProducer.onDataPulled({event2}, /** succeed */ true, bucketStartTimeNs + bucketSizeNs);
-// EXPECT_EQ(1UL, gaugeProducer.mCurrentSlicedBucket->size());
-// EXPECT_EQ(15L, gaugeProducer.mCurrentSlicedBucket->begin()
-// ->second.front()
-// .mFields->begin()
-// ->mValue.int_value);
-// EXPECT_EQ(anomalyTracker->getRefractoryPeriodEndsSec(DEFAULT_METRIC_DIMENSION_KEY),
-// std::ceil(1.0 * event2->GetElapsedTimestampNs() / NS_PER_SEC) + refPeriodSec);
-//
-// std::shared_ptr<LogEvent> event3 =
-// std::make_shared<LogEvent>(tagId, bucketStartTimeNs + 2 * bucketSizeNs + 10);
-// event3->write("some value");
-// event3->write(26);
-// event3->init();
-//
-// gaugeProducer.onDataPulled({event3}, /** succeed */ true, bucket2StartTimeNs + 2 * bucketSizeNs);
-// EXPECT_EQ(1UL, gaugeProducer.mCurrentSlicedBucket->size());
-// EXPECT_EQ(26L, gaugeProducer.mCurrentSlicedBucket->begin()
-// ->second.front()
-// .mFields->begin()
-// ->mValue.int_value);
-// EXPECT_EQ(anomalyTracker->getRefractoryPeriodEndsSec(DEFAULT_METRIC_DIMENSION_KEY),
-// std::ceil(1.0 * event2->GetElapsedTimestampNs() / NS_PER_SEC + refPeriodSec));
-//
-// // The event4 does not have the gauge field. Thus the current bucket value is 0.
-// std::shared_ptr<LogEvent> event4 =
-// std::make_shared<LogEvent>(tagId, bucketStartTimeNs + 3 * bucketSizeNs + 10);
-// event4->write("some value");
-// event4->init();
-// gaugeProducer.onDataPulled({event4}, /** succeed */ true, bucketStartTimeNs + 3 * bucketSizeNs);
-// EXPECT_EQ(1UL, gaugeProducer.mCurrentSlicedBucket->size());
-// EXPECT_TRUE(gaugeProducer.mCurrentSlicedBucket->begin()->second.front().mFields->empty());
-//}
-//
-//TEST(GaugeMetricProducerTest, TestPullOnTrigger) {
-// GaugeMetric metric;
-// metric.set_id(metricId);
-// metric.set_bucket(ONE_MINUTE);
-// metric.set_sampling_type(GaugeMetric::FIRST_N_SAMPLES);
-// metric.mutable_gauge_fields_filter()->set_include_all(false);
-// metric.set_max_pull_delay_sec(INT_MAX);
-// auto gaugeFieldMatcher = metric.mutable_gauge_fields_filter()->mutable_fields();
-// gaugeFieldMatcher->set_field(tagId);
-// gaugeFieldMatcher->add_child()->set_field(1);
-//
-// sp<MockConditionWizard> wizard = new NaggyMock<MockConditionWizard>();
-//
-// UidMap uidMap;
-// SimpleAtomMatcher atomMatcher;
-// atomMatcher.set_atom_id(tagId);
-// sp<EventMatcherWizard> eventMatcherWizard = new EventMatcherWizard({
-// new SimpleLogMatchingTracker(atomMatcherId, logEventMatcherIndex, atomMatcher, uidMap)});
-//
-// sp<MockStatsPullerManager> pullerManager = new StrictMock<MockStatsPullerManager>();
-// EXPECT_CALL(*pullerManager, Pull(tagId, _))
-// .WillOnce(Invoke([](int tagId, vector<std::shared_ptr<LogEvent>>* data) {
-// data->clear();
-// shared_ptr<LogEvent> event = make_shared<LogEvent>(tagId, bucketStartTimeNs + 10);
-// event->write(4);
-// event->init();
-// data->push_back(event);
-// return true;
-// }))
-// .WillOnce(Invoke([](int tagId, vector<std::shared_ptr<LogEvent>>* data) {
-// data->clear();
-// shared_ptr<LogEvent> event = make_shared<LogEvent>(tagId, bucketStartTimeNs + 20);
-// event->write(5);
-// event->init();
-// data->push_back(event);
-// return true;
-// }))
-// .WillOnce(Return(true));
-//
-// int triggerId = 5;
-// GaugeMetricProducer gaugeProducer(kConfigKey, metric, -1 /*-1 meaning no condition*/, wizard,
-// logEventMatcherIndex, eventMatcherWizard,
-// tagId, triggerId, tagId, bucketStartTimeNs, bucketStartTimeNs,
-// pullerManager);
-//
-// vector<shared_ptr<LogEvent>> allData;
-//
-// EXPECT_EQ(0UL, gaugeProducer.mCurrentSlicedBucket->size());
-// LogEvent trigger(triggerId, bucketStartTimeNs + 10);
-// trigger.init();
-// gaugeProducer.onMatchedLogEvent(1 /*log matcher index*/, trigger);
-// EXPECT_EQ(1UL, gaugeProducer.mCurrentSlicedBucket->begin()->second.size());
-// trigger.setElapsedTimestampNs(bucketStartTimeNs + 20);
-// gaugeProducer.onMatchedLogEvent(1 /*log matcher index*/, trigger);
-// EXPECT_EQ(2UL, gaugeProducer.mCurrentSlicedBucket->begin()->second.size());
-// trigger.setElapsedTimestampNs(bucket2StartTimeNs + 1);
-// gaugeProducer.onMatchedLogEvent(1 /*log matcher index*/, trigger);
-//
-// EXPECT_EQ(1UL, gaugeProducer.mPastBuckets.size());
-// EXPECT_EQ(2UL, gaugeProducer.mPastBuckets.begin()->second.back().mGaugeAtoms.size());
-// EXPECT_EQ(4, gaugeProducer.mPastBuckets.begin()
-// ->second.back()
-// .mGaugeAtoms[0]
-// .mFields->begin()
-// ->mValue.int_value);
-// EXPECT_EQ(5, gaugeProducer.mPastBuckets.begin()
-// ->second.back()
-// .mGaugeAtoms[1]
-// .mFields->begin()
-// ->mValue.int_value);
-//}
-//
-//TEST(GaugeMetricProducerTest, TestRemoveDimensionInOutput) {
-// GaugeMetric metric;
-// metric.set_id(metricId);
-// metric.set_bucket(ONE_MINUTE);
-// metric.set_sampling_type(GaugeMetric::FIRST_N_SAMPLES);
-// metric.mutable_gauge_fields_filter()->set_include_all(true);
-// metric.set_max_pull_delay_sec(INT_MAX);
-// auto dimensionMatcher = metric.mutable_dimensions_in_what();
-// // use field 1 as dimension.
-// dimensionMatcher->set_field(tagId);
-// dimensionMatcher->add_child()->set_field(1);
-//
-// sp<MockConditionWizard> wizard = new NaggyMock<MockConditionWizard>();
-//
-// UidMap uidMap;
-// SimpleAtomMatcher atomMatcher;
-// atomMatcher.set_atom_id(tagId);
-// sp<EventMatcherWizard> eventMatcherWizard = new EventMatcherWizard({
-// new SimpleLogMatchingTracker(atomMatcherId, logEventMatcherIndex, atomMatcher, uidMap)});
-//
-// sp<MockStatsPullerManager> pullerManager = new StrictMock<MockStatsPullerManager>();
-// EXPECT_CALL(*pullerManager, Pull(tagId, _))
-// .WillOnce(Invoke([](int tagId, vector<std::shared_ptr<LogEvent>>* data) {
-// data->clear();
-// shared_ptr<LogEvent> event = make_shared<LogEvent>(tagId, bucketStartTimeNs + 3);
-// event->write(3);
-// event->write(4);
-// event->init();
-// data->push_back(event);
-// return true;
-// }))
-// .WillOnce(Invoke([](int tagId, vector<std::shared_ptr<LogEvent>>* data) {
-// data->clear();
-// shared_ptr<LogEvent> event = make_shared<LogEvent>(tagId, bucketStartTimeNs + 10);
-// event->write(4);
-// event->write(5);
-// event->init();
-// data->push_back(event);
-// return true;
-// }))
-// .WillOnce(Invoke([](int tagId, vector<std::shared_ptr<LogEvent>>* data) {
-// data->clear();
-// shared_ptr<LogEvent> event = make_shared<LogEvent>(tagId, bucketStartTimeNs + 20);
-// event->write(4);
-// event->write(6);
-// event->init();
-// data->push_back(event);
-// return true;
-// }))
-// .WillOnce(Return(true));
-//
-// int triggerId = 5;
-// GaugeMetricProducer gaugeProducer(kConfigKey, metric, -1 /*-1 meaning no condition*/, wizard,
-// logEventMatcherIndex, eventMatcherWizard,
-// tagId, triggerId, tagId, bucketStartTimeNs, bucketStartTimeNs,
-// pullerManager);
-//
-// vector<shared_ptr<LogEvent>> allData;
-//
-// LogEvent trigger(triggerId, bucketStartTimeNs + 3);
-// trigger.init();
-// gaugeProducer.onMatchedLogEvent(1 /*log matcher index*/, trigger);
-// EXPECT_EQ(1UL, gaugeProducer.mCurrentSlicedBucket->size());
-// trigger.setElapsedTimestampNs(bucketStartTimeNs + 10);
-// gaugeProducer.onMatchedLogEvent(1 /*log matcher index*/, trigger);
-// EXPECT_EQ(2UL, gaugeProducer.mCurrentSlicedBucket->size());
-// EXPECT_EQ(1UL, gaugeProducer.mCurrentSlicedBucket->begin()->second.size());
-// trigger.setElapsedTimestampNs(bucketStartTimeNs + 20);
-// gaugeProducer.onMatchedLogEvent(1 /*log matcher index*/, trigger);
-// EXPECT_EQ(2UL, gaugeProducer.mCurrentSlicedBucket->begin()->second.size());
-// trigger.setElapsedTimestampNs(bucket2StartTimeNs + 1);
-// gaugeProducer.onMatchedLogEvent(1 /*log matcher index*/, trigger);
-//
-// EXPECT_EQ(2UL, gaugeProducer.mPastBuckets.size());
-// auto bucketIt = gaugeProducer.mPastBuckets.begin();
-// EXPECT_EQ(1UL, bucketIt->second.back().mGaugeAtoms.size());
-// EXPECT_EQ(3, bucketIt->first.getDimensionKeyInWhat().getValues().begin()->mValue.int_value);
-// EXPECT_EQ(4, bucketIt->second.back().mGaugeAtoms[0].mFields->begin()->mValue.int_value);
-// bucketIt++;
-// EXPECT_EQ(2UL, bucketIt->second.back().mGaugeAtoms.size());
-// EXPECT_EQ(4, bucketIt->first.getDimensionKeyInWhat().getValues().begin()->mValue.int_value);
-// EXPECT_EQ(5, bucketIt->second.back().mGaugeAtoms[0].mFields->begin()->mValue.int_value);
-// EXPECT_EQ(6, bucketIt->second.back().mGaugeAtoms[1].mFields->begin()->mValue.int_value);
-//}
-//
-///*
-// * Test that BUCKET_TOO_SMALL dump reason is logged when a flushed bucket size
-// * is smaller than the "min_bucket_size_nanos" specified in the metric config.
-// */
-//TEST(GaugeMetricProducerTest_BucketDrop, TestBucketDropWhenBucketTooSmall) {
-// GaugeMetric metric;
-// metric.set_id(metricId);
-// metric.set_bucket(FIVE_MINUTES);
-// metric.set_sampling_type(GaugeMetric::FIRST_N_SAMPLES);
-// metric.set_min_bucket_size_nanos(10000000000); // 10 seconds
-//
-// sp<MockConditionWizard> wizard = new NaggyMock<MockConditionWizard>();
-//
-// UidMap uidMap;
-// SimpleAtomMatcher atomMatcher;
-// atomMatcher.set_atom_id(tagId);
-// sp<EventMatcherWizard> eventMatcherWizard = new EventMatcherWizard({
-// new SimpleLogMatchingTracker(atomMatcherId, logEventMatcherIndex, atomMatcher, uidMap)});
-//
-// sp<MockStatsPullerManager> pullerManager = new StrictMock<MockStatsPullerManager>();
-// EXPECT_CALL(*pullerManager, Pull(tagId, _))
-// // Bucket start.
-// .WillOnce(Invoke([](int tagId, vector<std::shared_ptr<LogEvent>>* data) {
-// data->clear();
-// shared_ptr<LogEvent> event = make_shared<LogEvent>(tagId, bucketStartTimeNs);
-// event->write("field1");
-// event->write(10);
-// event->init();
-// data->push_back(event);
-// return true;
-// }));
-//
-// int triggerId = 5;
-// GaugeMetricProducer gaugeProducer(kConfigKey, metric, -1 /*-1 meaning no condition*/, wizard,
-// logEventMatcherIndex, eventMatcherWizard,
-// tagId, triggerId, tagId, bucketStartTimeNs, bucketStartTimeNs,
-// pullerManager);
-//
-// LogEvent trigger(triggerId, bucketStartTimeNs + 3);
-// trigger.init();
-// gaugeProducer.onMatchedLogEvent(1 /*log matcher index*/, trigger);
-//
-// // Check dump report.
-// ProtoOutputStream output;
-// std::set<string> strSet;
-// gaugeProducer.onDumpReport(bucketStartTimeNs + 9000000, true /* include recent buckets */,
-// true, FAST /* dump_latency */, &strSet, &output);
-//
-// StatsLogReport report = outputStreamToProto(&output);
-// EXPECT_TRUE(report.has_gauge_metrics());
-// EXPECT_EQ(0, report.gauge_metrics().data_size());
-// EXPECT_EQ(1, report.gauge_metrics().skipped_size());
-//
-// EXPECT_EQ(NanoToMillis(bucketStartTimeNs),
-// report.gauge_metrics().skipped(0).start_bucket_elapsed_millis());
-// EXPECT_EQ(NanoToMillis(bucketStartTimeNs + 9000000),
-// report.gauge_metrics().skipped(0).end_bucket_elapsed_millis());
-// EXPECT_EQ(1, report.gauge_metrics().skipped(0).drop_event_size());
-//
-// auto dropEvent = report.gauge_metrics().skipped(0).drop_event(0);
-// EXPECT_EQ(BucketDropReason::BUCKET_TOO_SMALL, dropEvent.drop_reason());
-// EXPECT_EQ(NanoToMillis(bucketStartTimeNs + 9000000), dropEvent.drop_time_millis());
-//}
+TEST(GaugeMetricProducerTest, TestPulledEventsNoCondition) {
+ GaugeMetric metric;
+ metric.set_id(metricId);
+ metric.set_bucket(ONE_MINUTE);
+ metric.mutable_gauge_fields_filter()->set_include_all(false);
+ metric.set_max_pull_delay_sec(INT_MAX);
+ auto gaugeFieldMatcher = metric.mutable_gauge_fields_filter()->mutable_fields();
+ gaugeFieldMatcher->set_field(tagId);
+ gaugeFieldMatcher->add_child()->set_field(1);
+ gaugeFieldMatcher->add_child()->set_field(3);
+
+ sp<MockConditionWizard> wizard = new NaggyMock<MockConditionWizard>();
+
+ UidMap uidMap;
+ SimpleAtomMatcher atomMatcher;
+ atomMatcher.set_atom_id(tagId);
+ sp<EventMatcherWizard> eventMatcherWizard =
+ new EventMatcherWizard({new SimpleLogMatchingTracker(
+ atomMatcherId, logEventMatcherIndex, atomMatcher, uidMap)});
+
+ sp<MockStatsPullerManager> pullerManager = new StrictMock<MockStatsPullerManager>();
+ EXPECT_CALL(*pullerManager, RegisterReceiver(tagId, _, _, _)).WillOnce(Return());
+ EXPECT_CALL(*pullerManager, UnRegisterReceiver(tagId, _)).WillOnce(Return());
+ EXPECT_CALL(*pullerManager, Pull(tagId, _))
+ .WillOnce(Invoke([](int tagId, vector<std::shared_ptr<LogEvent>>* data) {
+ data->clear();
+ data->push_back(makeLogEvent(tagId, bucketStartTimeNs + 10, 3, "some value", 11));
+ return true;
+ }));
+
+ GaugeMetricProducer gaugeProducer(kConfigKey, metric, -1 /*-1 meaning no condition*/, wizard,
+ logEventMatcherIndex, eventMatcherWizard, tagId, -1, tagId,
+ bucketStartTimeNs, bucketStartTimeNs, pullerManager);
+
+ vector<shared_ptr<LogEvent>> allData;
+ allData.clear();
+ allData.push_back(makeLogEvent(tagId, bucket2StartTimeNs + 1, 10, "some value", 11));
+
+ gaugeProducer.onDataPulled(allData, /** succeed */ true, bucket2StartTimeNs);
+ EXPECT_EQ(1UL, gaugeProducer.mCurrentSlicedBucket->size());
+ auto it = gaugeProducer.mCurrentSlicedBucket->begin()->second.front().mFields->begin();
+ EXPECT_EQ(INT, it->mValue.getType());
+ EXPECT_EQ(10, it->mValue.int_value);
+ it++;
+ EXPECT_EQ(11, it->mValue.int_value);
+ EXPECT_EQ(1UL, gaugeProducer.mPastBuckets.size());
+ EXPECT_EQ(3, gaugeProducer.mPastBuckets.begin()
+ ->second.back()
+ .mGaugeAtoms.front()
+ .mFields->begin()
+ ->mValue.int_value);
+
+ allData.clear();
+ allData.push_back(makeLogEvent(tagId, bucket3StartTimeNs + 10, 24, "some value", 25));
+ gaugeProducer.onDataPulled(allData, /** succeed */ true, bucket3StartTimeNs);
+ EXPECT_EQ(1UL, gaugeProducer.mCurrentSlicedBucket->size());
+ it = gaugeProducer.mCurrentSlicedBucket->begin()->second.front().mFields->begin();
+ EXPECT_EQ(INT, it->mValue.getType());
+ EXPECT_EQ(24, it->mValue.int_value);
+ it++;
+ EXPECT_EQ(INT, it->mValue.getType());
+ EXPECT_EQ(25, it->mValue.int_value);
+ // One dimension.
+ EXPECT_EQ(1UL, gaugeProducer.mPastBuckets.size());
+ EXPECT_EQ(2UL, gaugeProducer.mPastBuckets.begin()->second.size());
+ it = gaugeProducer.mPastBuckets.begin()->second.back().mGaugeAtoms.front().mFields->begin();
+ EXPECT_EQ(INT, it->mValue.getType());
+ EXPECT_EQ(10L, it->mValue.int_value);
+ it++;
+ EXPECT_EQ(INT, it->mValue.getType());
+ EXPECT_EQ(11L, it->mValue.int_value);
+
+ gaugeProducer.flushIfNeededLocked(bucket4StartTimeNs);
+ EXPECT_EQ(0UL, gaugeProducer.mCurrentSlicedBucket->size());
+ // One dimension.
+ EXPECT_EQ(1UL, gaugeProducer.mPastBuckets.size());
+ EXPECT_EQ(3UL, gaugeProducer.mPastBuckets.begin()->second.size());
+ it = gaugeProducer.mPastBuckets.begin()->second.back().mGaugeAtoms.front().mFields->begin();
+ EXPECT_EQ(INT, it->mValue.getType());
+ EXPECT_EQ(24L, it->mValue.int_value);
+ it++;
+ EXPECT_EQ(INT, it->mValue.getType());
+ EXPECT_EQ(25L, it->mValue.int_value);
+}
+
+TEST(GaugeMetricProducerTest, TestPushedEventsWithUpgrade) {
+ sp<AlarmMonitor> alarmMonitor;
+ GaugeMetric metric;
+ metric.set_id(metricId);
+ metric.set_bucket(ONE_MINUTE);
+ metric.mutable_gauge_fields_filter()->set_include_all(true);
+
+ Alert alert;
+ alert.set_id(101);
+ alert.set_metric_id(metricId);
+ alert.set_trigger_if_sum_gt(25);
+ alert.set_num_buckets(100);
+ sp<MockConditionWizard> wizard = new NaggyMock<MockConditionWizard>();
+ sp<MockStatsPullerManager> pullerManager = new StrictMock<MockStatsPullerManager>();
+
+ UidMap uidMap;
+ SimpleAtomMatcher atomMatcher;
+ atomMatcher.set_atom_id(tagId);
+ sp<EventMatcherWizard> eventMatcherWizard =
+ new EventMatcherWizard({new SimpleLogMatchingTracker(
+ atomMatcherId, logEventMatcherIndex, atomMatcher, uidMap)});
+
+ GaugeMetricProducer gaugeProducer(kConfigKey, metric, -1 /*-1 meaning no condition*/, wizard,
+ logEventMatcherIndex, eventMatcherWizard,
+ -1 /* -1 means no pulling */, -1, tagId, bucketStartTimeNs,
+ bucketStartTimeNs, pullerManager);
+
+ sp<AnomalyTracker> anomalyTracker = gaugeProducer.addAnomalyTracker(alert, alarmMonitor);
+ EXPECT_TRUE(anomalyTracker != nullptr);
+
+ LogEvent event1(/*uid=*/0, /*pid=*/0);
+ CreateTwoValueLogEvent(&event1, tagId, bucketStartTimeNs + 10, 1, 10);
+ gaugeProducer.onMatchedLogEvent(1 /*log matcher index*/, event1);
+ EXPECT_EQ(1UL, (*gaugeProducer.mCurrentSlicedBucket).count(DEFAULT_METRIC_DIMENSION_KEY));
+
+ gaugeProducer.notifyAppUpgrade(eventUpgradeTimeNs, "ANY.APP", 1, 1);
+ EXPECT_EQ(0UL, (*gaugeProducer.mCurrentSlicedBucket).count(DEFAULT_METRIC_DIMENSION_KEY));
+ EXPECT_EQ(1UL, gaugeProducer.mPastBuckets[DEFAULT_METRIC_DIMENSION_KEY].size());
+ EXPECT_EQ(0L, gaugeProducer.mCurrentBucketNum);
+ EXPECT_EQ(eventUpgradeTimeNs, gaugeProducer.mCurrentBucketStartTimeNs);
+ // Partial buckets are not sent to anomaly tracker.
+ EXPECT_EQ(0, anomalyTracker->getSumOverPastBuckets(DEFAULT_METRIC_DIMENSION_KEY));
+
+ // Create an event in the same partial bucket.
+ LogEvent event2(/*uid=*/0, /*pid=*/0);
+ CreateTwoValueLogEvent(&event2, tagId, bucketStartTimeNs + 59 * NS_PER_SEC, 1, 10);
+ gaugeProducer.onMatchedLogEvent(1 /*log matcher index*/, event2);
+ EXPECT_EQ(0L, gaugeProducer.mCurrentBucketNum);
+ EXPECT_EQ(1UL, gaugeProducer.mPastBuckets[DEFAULT_METRIC_DIMENSION_KEY].size());
+ EXPECT_EQ((int64_t)eventUpgradeTimeNs, gaugeProducer.mCurrentBucketStartTimeNs);
+ // Partial buckets are not sent to anomaly tracker.
+ EXPECT_EQ(0, anomalyTracker->getSumOverPastBuckets(DEFAULT_METRIC_DIMENSION_KEY));
+
+ // Next event should trigger creation of new bucket and send previous full bucket to anomaly
+ // tracker.
+ LogEvent event3(/*uid=*/0, /*pid=*/0);
+ CreateTwoValueLogEvent(&event3, tagId, bucketStartTimeNs + 65 * NS_PER_SEC, 1, 10);
+ gaugeProducer.onMatchedLogEvent(1 /*log matcher index*/, event3);
+ EXPECT_EQ(1L, gaugeProducer.mCurrentBucketNum);
+ EXPECT_EQ(2UL, gaugeProducer.mPastBuckets[DEFAULT_METRIC_DIMENSION_KEY].size());
+ EXPECT_EQ((int64_t)bucketStartTimeNs + bucketSizeNs, gaugeProducer.mCurrentBucketStartTimeNs);
+ EXPECT_EQ(1, anomalyTracker->getSumOverPastBuckets(DEFAULT_METRIC_DIMENSION_KEY));
+
+ // Next event should trigger creation of new bucket.
+ LogEvent event4(/*uid=*/0, /*pid=*/0);
+ CreateTwoValueLogEvent(&event4, tagId, bucketStartTimeNs + 125 * NS_PER_SEC, 1, 10);
+ gaugeProducer.onMatchedLogEvent(1 /*log matcher index*/, event4);
+ EXPECT_EQ(2L, gaugeProducer.mCurrentBucketNum);
+ EXPECT_EQ(3UL, gaugeProducer.mPastBuckets[DEFAULT_METRIC_DIMENSION_KEY].size());
+ EXPECT_EQ(2, anomalyTracker->getSumOverPastBuckets(DEFAULT_METRIC_DIMENSION_KEY));
+}
+
+TEST(GaugeMetricProducerTest, TestPulledWithUpgrade) {
+ GaugeMetric metric;
+ metric.set_id(metricId);
+ metric.set_bucket(ONE_MINUTE);
+ metric.set_max_pull_delay_sec(INT_MAX);
+ auto gaugeFieldMatcher = metric.mutable_gauge_fields_filter()->mutable_fields();
+ gaugeFieldMatcher->set_field(tagId);
+ gaugeFieldMatcher->add_child()->set_field(2);
+
+ sp<MockConditionWizard> wizard = new NaggyMock<MockConditionWizard>();
+
+ UidMap uidMap;
+ SimpleAtomMatcher atomMatcher;
+ atomMatcher.set_atom_id(tagId);
+ sp<EventMatcherWizard> eventMatcherWizard =
+ new EventMatcherWizard({new SimpleLogMatchingTracker(
+ atomMatcherId, logEventMatcherIndex, atomMatcher, uidMap)});
+
+ sp<MockStatsPullerManager> pullerManager = new StrictMock<MockStatsPullerManager>();
+ EXPECT_CALL(*pullerManager, RegisterReceiver(tagId, _, _, _)).WillOnce(Return());
+ EXPECT_CALL(*pullerManager, UnRegisterReceiver(tagId, _)).WillOnce(Return());
+ EXPECT_CALL(*pullerManager, Pull(tagId, _))
+ .WillOnce(Return(false))
+ .WillOnce(Invoke([](int tagId, vector<std::shared_ptr<LogEvent>>* data) {
+ data->clear();
+ data->push_back(CreateRepeatedValueLogEvent(tagId, eventUpgradeTimeNs, 2));
+ return true;
+ }));
+
+ GaugeMetricProducer gaugeProducer(kConfigKey, metric, -1 /*-1 meaning no condition*/, wizard,
+ logEventMatcherIndex, eventMatcherWizard, tagId, -1, tagId,
+ bucketStartTimeNs, bucketStartTimeNs, pullerManager);
+
+ vector<shared_ptr<LogEvent>> allData;
+ allData.push_back(CreateRepeatedValueLogEvent(tagId, bucketStartTimeNs + 1, 1));
+ gaugeProducer.onDataPulled(allData, /** succeed */ true, bucketStartTimeNs);
+ EXPECT_EQ(1UL, gaugeProducer.mCurrentSlicedBucket->size());
+ EXPECT_EQ(1, gaugeProducer.mCurrentSlicedBucket->begin()
+ ->second.front()
+ .mFields->begin()
+ ->mValue.int_value);
+
+ gaugeProducer.notifyAppUpgrade(eventUpgradeTimeNs, "ANY.APP", 1, 1);
+ EXPECT_EQ(1UL, gaugeProducer.mPastBuckets[DEFAULT_METRIC_DIMENSION_KEY].size());
+ EXPECT_EQ(0L, gaugeProducer.mCurrentBucketNum);
+ EXPECT_EQ((int64_t)eventUpgradeTimeNs, gaugeProducer.mCurrentBucketStartTimeNs);
+ EXPECT_EQ(1UL, gaugeProducer.mCurrentSlicedBucket->size());
+ EXPECT_EQ(2, gaugeProducer.mCurrentSlicedBucket->begin()
+ ->second.front()
+ .mFields->begin()
+ ->mValue.int_value);
+
+ allData.clear();
+ allData.push_back(CreateRepeatedValueLogEvent(tagId, bucketStartTimeNs + bucketSizeNs + 1, 3));
+ gaugeProducer.onDataPulled(allData, /** succeed */ true, bucketStartTimeNs + bucketSizeNs);
+ EXPECT_EQ(2UL, gaugeProducer.mPastBuckets[DEFAULT_METRIC_DIMENSION_KEY].size());
+ EXPECT_EQ(1UL, gaugeProducer.mCurrentSlicedBucket->size());
+ EXPECT_EQ(3, gaugeProducer.mCurrentSlicedBucket->begin()
+ ->second.front()
+ .mFields->begin()
+ ->mValue.int_value);
+}
+
+TEST(GaugeMetricProducerTest, TestPulledWithAppUpgradeDisabled) {
+ GaugeMetric metric;
+ metric.set_id(metricId);
+ metric.set_bucket(ONE_MINUTE);
+ metric.set_max_pull_delay_sec(INT_MAX);
+ metric.set_split_bucket_for_app_upgrade(false);
+ auto gaugeFieldMatcher = metric.mutable_gauge_fields_filter()->mutable_fields();
+ gaugeFieldMatcher->set_field(tagId);
+ gaugeFieldMatcher->add_child()->set_field(2);
+
+ sp<MockConditionWizard> wizard = new NaggyMock<MockConditionWizard>();
+
+ UidMap uidMap;
+ SimpleAtomMatcher atomMatcher;
+ atomMatcher.set_atom_id(tagId);
+ sp<EventMatcherWizard> eventMatcherWizard =
+ new EventMatcherWizard({new SimpleLogMatchingTracker(
+ atomMatcherId, logEventMatcherIndex, atomMatcher, uidMap)});
+
+ sp<MockStatsPullerManager> pullerManager = new StrictMock<MockStatsPullerManager>();
+ EXPECT_CALL(*pullerManager, RegisterReceiver(tagId, _, _, _)).WillOnce(Return());
+ EXPECT_CALL(*pullerManager, UnRegisterReceiver(tagId, _)).WillOnce(Return());
+ EXPECT_CALL(*pullerManager, Pull(tagId, _)).WillOnce(Return(false));
+
+ GaugeMetricProducer gaugeProducer(kConfigKey, metric, -1 /*-1 meaning no condition*/, wizard,
+ logEventMatcherIndex, eventMatcherWizard, tagId, -1, tagId,
+ bucketStartTimeNs, bucketStartTimeNs, pullerManager);
+
+ vector<shared_ptr<LogEvent>> allData;
+ allData.push_back(CreateRepeatedValueLogEvent(tagId, bucketStartTimeNs + 1, 1));
+ gaugeProducer.onDataPulled(allData, /** succeed */ true, bucketStartTimeNs);
+ EXPECT_EQ(1UL, gaugeProducer.mCurrentSlicedBucket->size());
+ EXPECT_EQ(1, gaugeProducer.mCurrentSlicedBucket->begin()
+ ->second.front()
+ .mFields->begin()
+ ->mValue.int_value);
+
+ gaugeProducer.notifyAppUpgrade(eventUpgradeTimeNs, "ANY.APP", 1, 1);
+ EXPECT_EQ(0UL, gaugeProducer.mPastBuckets[DEFAULT_METRIC_DIMENSION_KEY].size());
+ EXPECT_EQ(0L, gaugeProducer.mCurrentBucketNum);
+ EXPECT_EQ(bucketStartTimeNs, gaugeProducer.mCurrentBucketStartTimeNs);
+ EXPECT_EQ(1UL, gaugeProducer.mCurrentSlicedBucket->size());
+ EXPECT_EQ(1, gaugeProducer.mCurrentSlicedBucket->begin()
+ ->second.front()
+ .mFields->begin()
+ ->mValue.int_value);
+}
+
+TEST(GaugeMetricProducerTest, TestPulledEventsWithCondition) {
+ GaugeMetric metric;
+ metric.set_id(metricId);
+ metric.set_bucket(ONE_MINUTE);
+ metric.set_max_pull_delay_sec(INT_MAX);
+ auto gaugeFieldMatcher = metric.mutable_gauge_fields_filter()->mutable_fields();
+ gaugeFieldMatcher->set_field(tagId);
+ gaugeFieldMatcher->add_child()->set_field(2);
+ metric.set_condition(StringToId("SCREEN_ON"));
+
+ sp<MockConditionWizard> wizard = new NaggyMock<MockConditionWizard>();
+
+ UidMap uidMap;
+ SimpleAtomMatcher atomMatcher;
+ atomMatcher.set_atom_id(tagId);
+ sp<EventMatcherWizard> eventMatcherWizard =
+ new EventMatcherWizard({new SimpleLogMatchingTracker(
+ atomMatcherId, logEventMatcherIndex, atomMatcher, uidMap)});
+
+ sp<MockStatsPullerManager> pullerManager = new StrictMock<MockStatsPullerManager>();
+ EXPECT_CALL(*pullerManager, RegisterReceiver(tagId, _, _, _)).WillOnce(Return());
+ EXPECT_CALL(*pullerManager, UnRegisterReceiver(tagId, _)).WillOnce(Return());
+ EXPECT_CALL(*pullerManager, Pull(tagId, _))
+ .WillOnce(Invoke([](int tagId, vector<std::shared_ptr<LogEvent>>* data) {
+ data->clear();
+ data->push_back(CreateRepeatedValueLogEvent(tagId, bucketStartTimeNs + 10, 100));
+ return true;
+ }));
+
+ GaugeMetricProducer gaugeProducer(kConfigKey, metric, 1, wizard, logEventMatcherIndex,
+ eventMatcherWizard, tagId, -1, tagId, bucketStartTimeNs,
+ bucketStartTimeNs, pullerManager);
+
+ gaugeProducer.onConditionChanged(true, bucketStartTimeNs + 8);
+ EXPECT_EQ(1UL, gaugeProducer.mCurrentSlicedBucket->size());
+ EXPECT_EQ(100, gaugeProducer.mCurrentSlicedBucket->begin()
+ ->second.front()
+ .mFields->begin()
+ ->mValue.int_value);
+ EXPECT_EQ(0UL, gaugeProducer.mPastBuckets.size());
+
+ vector<shared_ptr<LogEvent>> allData;
+ allData.clear();
+ allData.push_back(CreateRepeatedValueLogEvent(tagId, bucket2StartTimeNs + 1, 110));
+ gaugeProducer.onDataPulled(allData, /** succeed */ true, bucket2StartTimeNs);
+
+ EXPECT_EQ(1UL, gaugeProducer.mCurrentSlicedBucket->size());
+ EXPECT_EQ(110, gaugeProducer.mCurrentSlicedBucket->begin()
+ ->second.front()
+ .mFields->begin()
+ ->mValue.int_value);
+ EXPECT_EQ(1UL, gaugeProducer.mPastBuckets.size());
+ EXPECT_EQ(100, gaugeProducer.mPastBuckets.begin()
+ ->second.back()
+ .mGaugeAtoms.front()
+ .mFields->begin()
+ ->mValue.int_value);
+
+ gaugeProducer.onConditionChanged(false, bucket2StartTimeNs + 10);
+ gaugeProducer.flushIfNeededLocked(bucket3StartTimeNs + 10);
+ EXPECT_EQ(1UL, gaugeProducer.mPastBuckets.size());
+ EXPECT_EQ(2UL, gaugeProducer.mPastBuckets.begin()->second.size());
+ EXPECT_EQ(110L, gaugeProducer.mPastBuckets.begin()
+ ->second.back()
+ .mGaugeAtoms.front()
+ .mFields->begin()
+ ->mValue.int_value);
+}
+
+TEST(GaugeMetricProducerTest, TestPulledEventsWithSlicedCondition) {
+ const int conditionTag = 65;
+ GaugeMetric metric;
+ metric.set_id(1111111);
+ metric.set_bucket(ONE_MINUTE);
+ metric.mutable_gauge_fields_filter()->set_include_all(true);
+ metric.set_condition(StringToId("APP_DIED"));
+ metric.set_max_pull_delay_sec(INT_MAX);
+ auto dim = metric.mutable_dimensions_in_what();
+ dim->set_field(tagId);
+ dim->add_child()->set_field(1);
+
+ UidMap uidMap;
+ SimpleAtomMatcher atomMatcher;
+ atomMatcher.set_atom_id(tagId);
+ sp<EventMatcherWizard> eventMatcherWizard =
+ new EventMatcherWizard({new SimpleLogMatchingTracker(
+ atomMatcherId, logEventMatcherIndex, atomMatcher, uidMap)});
+
+ sp<MockConditionWizard> wizard = new NaggyMock<MockConditionWizard>();
+ EXPECT_CALL(*wizard, query(_, _, _))
+ .WillRepeatedly(
+ Invoke([](const int conditionIndex, const ConditionKey& conditionParameters,
+ const bool isPartialLink) {
+ int pos[] = {1, 0, 0};
+ Field f(conditionTag, pos, 0);
+ HashableDimensionKey key;
+ key.mutableValues()->emplace_back(f, Value((int32_t)1000000));
+
+ return ConditionState::kTrue;
+ }));
+
+ sp<MockStatsPullerManager> pullerManager = new StrictMock<MockStatsPullerManager>();
+ EXPECT_CALL(*pullerManager, RegisterReceiver(tagId, _, _, _)).WillOnce(Return());
+ EXPECT_CALL(*pullerManager, UnRegisterReceiver(tagId, _)).WillOnce(Return());
+ EXPECT_CALL(*pullerManager, Pull(tagId, _))
+ .WillOnce(Invoke([](int tagId, vector<std::shared_ptr<LogEvent>>* data) {
+ data->clear();
+ data->push_back(CreateTwoValueLogEvent(tagId, bucketStartTimeNs + 10, 1000, 100));
+ return true;
+ }));
+
+ GaugeMetricProducer gaugeProducer(kConfigKey, metric, 1, wizard, logEventMatcherIndex,
+ eventMatcherWizard, tagId, -1, tagId, bucketStartTimeNs,
+ bucketStartTimeNs, pullerManager);
+
+ gaugeProducer.onSlicedConditionMayChange(true, bucketStartTimeNs + 8);
+
+ EXPECT_EQ(1UL, gaugeProducer.mCurrentSlicedBucket->size());
+ const auto& key = gaugeProducer.mCurrentSlicedBucket->begin()->first;
+ EXPECT_EQ(1UL, key.getDimensionKeyInWhat().getValues().size());
+ EXPECT_EQ(1000, key.getDimensionKeyInWhat().getValues()[0].mValue.int_value);
+
+ EXPECT_EQ(0UL, gaugeProducer.mPastBuckets.size());
+
+ vector<shared_ptr<LogEvent>> allData;
+ allData.clear();
+ allData.push_back(CreateTwoValueLogEvent(tagId, bucket2StartTimeNs + 1, 1000, 110));
+ gaugeProducer.onDataPulled(allData, /** succeed */ true, bucket2StartTimeNs);
+
+ EXPECT_EQ(1UL, gaugeProducer.mCurrentSlicedBucket->size());
+ EXPECT_EQ(1UL, gaugeProducer.mPastBuckets.size());
+}
+
+TEST(GaugeMetricProducerTest, TestPulledEventsAnomalyDetection) {
+ sp<AlarmMonitor> alarmMonitor;
+ sp<MockConditionWizard> wizard = new NaggyMock<MockConditionWizard>();
+
+ sp<MockStatsPullerManager> pullerManager = new StrictMock<MockStatsPullerManager>();
+ EXPECT_CALL(*pullerManager, RegisterReceiver(tagId, _, _, _)).WillOnce(Return());
+ EXPECT_CALL(*pullerManager, UnRegisterReceiver(tagId, _)).WillOnce(Return());
+ EXPECT_CALL(*pullerManager, Pull(tagId, _)).WillOnce(Return(false));
+
+ GaugeMetric metric;
+ metric.set_id(metricId);
+ metric.set_bucket(ONE_MINUTE);
+ metric.set_max_pull_delay_sec(INT_MAX);
+ auto gaugeFieldMatcher = metric.mutable_gauge_fields_filter()->mutable_fields();
+ gaugeFieldMatcher->set_field(tagId);
+ gaugeFieldMatcher->add_child()->set_field(2);
+
+ UidMap uidMap;
+ SimpleAtomMatcher atomMatcher;
+ atomMatcher.set_atom_id(tagId);
+ sp<EventMatcherWizard> eventMatcherWizard =
+ new EventMatcherWizard({new SimpleLogMatchingTracker(
+ atomMatcherId, logEventMatcherIndex, atomMatcher, uidMap)});
+
+ GaugeMetricProducer gaugeProducer(kConfigKey, metric, -1 /*-1 meaning no condition*/, wizard,
+ logEventMatcherIndex, eventMatcherWizard, tagId, -1, tagId,
+ bucketStartTimeNs, bucketStartTimeNs, pullerManager);
+
+ Alert alert;
+ alert.set_id(101);
+ alert.set_metric_id(metricId);
+ alert.set_trigger_if_sum_gt(25);
+ alert.set_num_buckets(2);
+ const int32_t refPeriodSec = 60;
+ alert.set_refractory_period_secs(refPeriodSec);
+ sp<AnomalyTracker> anomalyTracker = gaugeProducer.addAnomalyTracker(alert, alarmMonitor);
+
+ int tagId = 1;
+ vector<shared_ptr<LogEvent>> allData;
+ allData.clear();
+ allData.push_back(CreateRepeatedValueLogEvent(tagId, bucketStartTimeNs + 1, 13));
+ gaugeProducer.onDataPulled(allData, /** succeed */ true, bucketStartTimeNs);
+ EXPECT_EQ(1UL, gaugeProducer.mCurrentSlicedBucket->size());
+ EXPECT_EQ(13L, gaugeProducer.mCurrentSlicedBucket->begin()
+ ->second.front()
+ .mFields->begin()
+ ->mValue.int_value);
+ EXPECT_EQ(anomalyTracker->getRefractoryPeriodEndsSec(DEFAULT_METRIC_DIMENSION_KEY), 0U);
+
+ std::shared_ptr<LogEvent> event2 =
+ CreateRepeatedValueLogEvent(tagId, bucketStartTimeNs + bucketSizeNs + 20, 15);
+
+ allData.clear();
+ allData.push_back(event2);
+ gaugeProducer.onDataPulled(allData, /** succeed */ true, bucketStartTimeNs + bucketSizeNs);
+ EXPECT_EQ(1UL, gaugeProducer.mCurrentSlicedBucket->size());
+ EXPECT_EQ(15L, gaugeProducer.mCurrentSlicedBucket->begin()
+ ->second.front()
+ .mFields->begin()
+ ->mValue.int_value);
+ EXPECT_EQ(anomalyTracker->getRefractoryPeriodEndsSec(DEFAULT_METRIC_DIMENSION_KEY),
+ std::ceil(1.0 * event2->GetElapsedTimestampNs() / NS_PER_SEC) + refPeriodSec);
+
+ allData.clear();
+ allData.push_back(
+ CreateRepeatedValueLogEvent(tagId, bucketStartTimeNs + 2 * bucketSizeNs + 10, 26));
+ gaugeProducer.onDataPulled(allData, /** succeed */ true, bucket2StartTimeNs + 2 * bucketSizeNs);
+ EXPECT_EQ(1UL, gaugeProducer.mCurrentSlicedBucket->size());
+ EXPECT_EQ(26L, gaugeProducer.mCurrentSlicedBucket->begin()
+ ->second.front()
+ .mFields->begin()
+ ->mValue.int_value);
+ EXPECT_EQ(anomalyTracker->getRefractoryPeriodEndsSec(DEFAULT_METRIC_DIMENSION_KEY),
+ std::ceil(1.0 * event2->GetElapsedTimestampNs() / NS_PER_SEC + refPeriodSec));
+
+ // This event does not have the gauge field. Thus the current bucket value is 0.
+ allData.clear();
+ allData.push_back(CreateNoValuesLogEvent(tagId, bucketStartTimeNs + 3 * bucketSizeNs + 10));
+ gaugeProducer.onDataPulled(allData, /** succeed */ true, bucketStartTimeNs + 3 * bucketSizeNs);
+ EXPECT_EQ(1UL, gaugeProducer.mCurrentSlicedBucket->size());
+ EXPECT_TRUE(gaugeProducer.mCurrentSlicedBucket->begin()->second.front().mFields->empty());
+}
+
+TEST(GaugeMetricProducerTest, TestPullOnTrigger) {
+ GaugeMetric metric;
+ metric.set_id(metricId);
+ metric.set_bucket(ONE_MINUTE);
+ metric.set_sampling_type(GaugeMetric::FIRST_N_SAMPLES);
+ metric.mutable_gauge_fields_filter()->set_include_all(false);
+ metric.set_max_pull_delay_sec(INT_MAX);
+ auto gaugeFieldMatcher = metric.mutable_gauge_fields_filter()->mutable_fields();
+ gaugeFieldMatcher->set_field(tagId);
+ gaugeFieldMatcher->add_child()->set_field(1);
+
+ sp<MockConditionWizard> wizard = new NaggyMock<MockConditionWizard>();
+
+ UidMap uidMap;
+ SimpleAtomMatcher atomMatcher;
+ atomMatcher.set_atom_id(tagId);
+ sp<EventMatcherWizard> eventMatcherWizard =
+ new EventMatcherWizard({new SimpleLogMatchingTracker(
+ atomMatcherId, logEventMatcherIndex, atomMatcher, uidMap)});
+
+ sp<MockStatsPullerManager> pullerManager = new StrictMock<MockStatsPullerManager>();
+ EXPECT_CALL(*pullerManager, Pull(tagId, _))
+ .WillOnce(Invoke([](int tagId, vector<std::shared_ptr<LogEvent>>* data) {
+ data->clear();
+ data->push_back(CreateRepeatedValueLogEvent(tagId, bucketStartTimeNs + 10, 4));
+ return true;
+ }))
+ .WillOnce(Invoke([](int tagId, vector<std::shared_ptr<LogEvent>>* data) {
+ data->clear();
+ data->push_back(CreateRepeatedValueLogEvent(tagId, bucketStartTimeNs + 20, 5));
+ return true;
+ }))
+ .WillOnce(Return(true));
+
+ int triggerId = 5;
+ GaugeMetricProducer gaugeProducer(kConfigKey, metric, -1 /*-1 meaning no condition*/, wizard,
+ logEventMatcherIndex, eventMatcherWizard, tagId, triggerId,
+ tagId, bucketStartTimeNs, bucketStartTimeNs, pullerManager);
+
+ EXPECT_EQ(0UL, gaugeProducer.mCurrentSlicedBucket->size());
+
+ LogEvent triggerEvent(/*uid=*/0, /*pid=*/0);
+ CreateNoValuesLogEvent(&triggerEvent, triggerId, bucketStartTimeNs + 10);
+ gaugeProducer.onMatchedLogEvent(1 /*log matcher index*/, triggerEvent);
+ EXPECT_EQ(1UL, gaugeProducer.mCurrentSlicedBucket->begin()->second.size());
+ triggerEvent.setElapsedTimestampNs(bucketStartTimeNs + 20);
+ gaugeProducer.onMatchedLogEvent(1 /*log matcher index*/, triggerEvent);
+ EXPECT_EQ(2UL, gaugeProducer.mCurrentSlicedBucket->begin()->second.size());
+ triggerEvent.setElapsedTimestampNs(bucket2StartTimeNs + 1);
+ gaugeProducer.onMatchedLogEvent(1 /*log matcher index*/, triggerEvent);
+
+ EXPECT_EQ(1UL, gaugeProducer.mPastBuckets.size());
+ EXPECT_EQ(2UL, gaugeProducer.mPastBuckets.begin()->second.back().mGaugeAtoms.size());
+ EXPECT_EQ(4, gaugeProducer.mPastBuckets.begin()
+ ->second.back()
+ .mGaugeAtoms[0]
+ .mFields->begin()
+ ->mValue.int_value);
+ EXPECT_EQ(5, gaugeProducer.mPastBuckets.begin()
+ ->second.back()
+ .mGaugeAtoms[1]
+ .mFields->begin()
+ ->mValue.int_value);
+}
+
+TEST(GaugeMetricProducerTest, TestRemoveDimensionInOutput) {
+ GaugeMetric metric;
+ metric.set_id(metricId);
+ metric.set_bucket(ONE_MINUTE);
+ metric.set_sampling_type(GaugeMetric::FIRST_N_SAMPLES);
+ metric.mutable_gauge_fields_filter()->set_include_all(true);
+ metric.set_max_pull_delay_sec(INT_MAX);
+ auto dimensionMatcher = metric.mutable_dimensions_in_what();
+ // use field 1 as dimension.
+ dimensionMatcher->set_field(tagId);
+ dimensionMatcher->add_child()->set_field(1);
+
+ sp<MockConditionWizard> wizard = new NaggyMock<MockConditionWizard>();
+
+ UidMap uidMap;
+ SimpleAtomMatcher atomMatcher;
+ atomMatcher.set_atom_id(tagId);
+ sp<EventMatcherWizard> eventMatcherWizard =
+ new EventMatcherWizard({new SimpleLogMatchingTracker(
+ atomMatcherId, logEventMatcherIndex, atomMatcher, uidMap)});
+
+ sp<MockStatsPullerManager> pullerManager = new StrictMock<MockStatsPullerManager>();
+ EXPECT_CALL(*pullerManager, Pull(tagId, _))
+ .WillOnce(Invoke([](int tagId, vector<std::shared_ptr<LogEvent>>* data) {
+ data->clear();
+ data->push_back(CreateTwoValueLogEvent(tagId, bucketStartTimeNs + 3, 3, 4));
+ return true;
+ }))
+ .WillOnce(Invoke([](int tagId, vector<std::shared_ptr<LogEvent>>* data) {
+ data->clear();
+ data->push_back(CreateTwoValueLogEvent(tagId, bucketStartTimeNs + 10, 4, 5));
+ return true;
+ }))
+ .WillOnce(Invoke([](int tagId, vector<std::shared_ptr<LogEvent>>* data) {
+ data->clear();
+ data->push_back(CreateTwoValueLogEvent(tagId, bucketStartTimeNs + 20, 4, 6));
+ return true;
+ }))
+ .WillOnce(Return(true));
+
+ int triggerId = 5;
+ GaugeMetricProducer gaugeProducer(kConfigKey, metric, -1 /*-1 meaning no condition*/, wizard,
+ logEventMatcherIndex, eventMatcherWizard, tagId, triggerId,
+ tagId, bucketStartTimeNs, bucketStartTimeNs, pullerManager);
+
+ LogEvent triggerEvent(/*uid=*/0, /*pid=*/0);
+ CreateNoValuesLogEvent(&triggerEvent, triggerId, bucketStartTimeNs + 3);
+ gaugeProducer.onMatchedLogEvent(1 /*log matcher index*/, triggerEvent);
+ EXPECT_EQ(1UL, gaugeProducer.mCurrentSlicedBucket->size());
+ triggerEvent.setElapsedTimestampNs(bucketStartTimeNs + 10);
+ gaugeProducer.onMatchedLogEvent(1 /*log matcher index*/, triggerEvent);
+ EXPECT_EQ(2UL, gaugeProducer.mCurrentSlicedBucket->size());
+ EXPECT_EQ(1UL, gaugeProducer.mCurrentSlicedBucket->begin()->second.size());
+ triggerEvent.setElapsedTimestampNs(bucketStartTimeNs + 20);
+ gaugeProducer.onMatchedLogEvent(1 /*log matcher index*/, triggerEvent);
+ EXPECT_EQ(2UL, gaugeProducer.mCurrentSlicedBucket->begin()->second.size());
+ triggerEvent.setElapsedTimestampNs(bucket2StartTimeNs + 1);
+ gaugeProducer.onMatchedLogEvent(1 /*log matcher index*/, triggerEvent);
+
+ EXPECT_EQ(2UL, gaugeProducer.mPastBuckets.size());
+ auto bucketIt = gaugeProducer.mPastBuckets.begin();
+ EXPECT_EQ(1UL, bucketIt->second.back().mGaugeAtoms.size());
+ EXPECT_EQ(3, bucketIt->first.getDimensionKeyInWhat().getValues().begin()->mValue.int_value);
+ EXPECT_EQ(4, bucketIt->second.back().mGaugeAtoms[0].mFields->begin()->mValue.int_value);
+ bucketIt++;
+ EXPECT_EQ(2UL, bucketIt->second.back().mGaugeAtoms.size());
+ EXPECT_EQ(4, bucketIt->first.getDimensionKeyInWhat().getValues().begin()->mValue.int_value);
+ EXPECT_EQ(5, bucketIt->second.back().mGaugeAtoms[0].mFields->begin()->mValue.int_value);
+ EXPECT_EQ(6, bucketIt->second.back().mGaugeAtoms[1].mFields->begin()->mValue.int_value);
+}
+
+/*
+ * Test that BUCKET_TOO_SMALL dump reason is logged when a flushed bucket size
+ * is smaller than the "min_bucket_size_nanos" specified in the metric config.
+ */
+TEST(GaugeMetricProducerTest_BucketDrop, TestBucketDropWhenBucketTooSmall) {
+ GaugeMetric metric;
+ metric.set_id(metricId);
+ metric.set_bucket(FIVE_MINUTES);
+ metric.set_sampling_type(GaugeMetric::FIRST_N_SAMPLES);
+ metric.set_min_bucket_size_nanos(10000000000); // 10 seconds
+
+ sp<MockConditionWizard> wizard = new NaggyMock<MockConditionWizard>();
+
+ UidMap uidMap;
+ SimpleAtomMatcher atomMatcher;
+ atomMatcher.set_atom_id(tagId);
+ sp<EventMatcherWizard> eventMatcherWizard =
+ new EventMatcherWizard({new SimpleLogMatchingTracker(
+ atomMatcherId, logEventMatcherIndex, atomMatcher, uidMap)});
+
+ sp<MockStatsPullerManager> pullerManager = new StrictMock<MockStatsPullerManager>();
+ EXPECT_CALL(*pullerManager, Pull(tagId, _))
+ // Bucket start.
+ .WillOnce(Invoke([](int tagId, vector<std::shared_ptr<LogEvent>>* data) {
+ data->clear();
+ data->push_back(CreateRepeatedValueLogEvent(tagId, bucketStartTimeNs, 10));
+ return true;
+ }));
+
+ int triggerId = 5;
+ GaugeMetricProducer gaugeProducer(kConfigKey, metric, -1 /*-1 meaning no condition*/, wizard,
+ logEventMatcherIndex, eventMatcherWizard, tagId, triggerId,
+ tagId, bucketStartTimeNs, bucketStartTimeNs, pullerManager);
+
+ LogEvent triggerEvent(/*uid=*/0, /*pid=*/0);
+ CreateNoValuesLogEvent(&triggerEvent, triggerId, bucketStartTimeNs + 3);
+ gaugeProducer.onMatchedLogEvent(1 /*log matcher index*/, triggerEvent);
+
+ // Check dump report.
+ ProtoOutputStream output;
+ std::set<string> strSet;
+ gaugeProducer.onDumpReport(bucketStartTimeNs + 9000000, true /* include recent buckets */, true,
+ FAST /* dump_latency */, &strSet, &output);
+
+ StatsLogReport report = outputStreamToProto(&output);
+ EXPECT_TRUE(report.has_gauge_metrics());
+ EXPECT_EQ(0, report.gauge_metrics().data_size());
+ EXPECT_EQ(1, report.gauge_metrics().skipped_size());
+
+ EXPECT_EQ(NanoToMillis(bucketStartTimeNs),
+ report.gauge_metrics().skipped(0).start_bucket_elapsed_millis());
+ EXPECT_EQ(NanoToMillis(bucketStartTimeNs + 9000000),
+ report.gauge_metrics().skipped(0).end_bucket_elapsed_millis());
+ EXPECT_EQ(1, report.gauge_metrics().skipped(0).drop_event_size());
+
+ auto dropEvent = report.gauge_metrics().skipped(0).drop_event(0);
+ EXPECT_EQ(BucketDropReason::BUCKET_TOO_SMALL, dropEvent.drop_reason());
+ EXPECT_EQ(NanoToMillis(bucketStartTimeNs + 9000000), dropEvent.drop_time_millis());
+}
} // namespace statsd
} // namespace os
diff --git a/cmds/statsd/tests/statsd_test_util.cpp b/cmds/statsd/tests/statsd_test_util.cpp
index c7838fcddb53..8c8836b94f56 100644
--- a/cmds/statsd/tests/statsd_test_util.cpp
+++ b/cmds/statsd/tests/statsd_test_util.cpp
@@ -428,7 +428,7 @@ shared_ptr<LogEvent> CreateTwoValueLogEvent(int atomId, int64_t eventTimeNs, int
return logEvent;
}
-//
+
void CreateTwoValueLogEvent(LogEvent* logEvent, int atomId, int64_t eventTimeNs, int32_t value1,
int32_t value2) {
AStatsEvent* statsEvent = AStatsEvent_obtain();
@@ -531,6 +531,18 @@ shared_ptr<LogEvent> CreateNoValuesLogEvent(int atomId, int64_t eventTimeNs) {
return logEvent;
}
+void CreateNoValuesLogEvent(LogEvent* logEvent, int atomId, int64_t eventTimeNs) {
+ AStatsEvent* statsEvent = AStatsEvent_obtain();
+ AStatsEvent_setAtomId(statsEvent, atomId);
+ AStatsEvent_overwriteTimestamp(statsEvent, eventTimeNs);
+ AStatsEvent_build(statsEvent);
+
+ size_t size;
+ uint8_t* buf = AStatsEvent_getBuffer(statsEvent, &size);
+ logEvent->parseBuffer(buf, size);
+ AStatsEvent_release(statsEvent);
+}
+
std::unique_ptr<LogEvent> CreateScreenStateChangedEvent(
uint64_t timestampNs, const android::view::DisplayStateEnum state) {
AStatsEvent* statsEvent = AStatsEvent_obtain();
diff --git a/cmds/statsd/tests/statsd_test_util.h b/cmds/statsd/tests/statsd_test_util.h
index 05e1572e3aa9..7c017554d511 100644
--- a/cmds/statsd/tests/statsd_test_util.h
+++ b/cmds/statsd/tests/statsd_test_util.h
@@ -187,6 +187,8 @@ void CreateRepeatedValueLogEvent(LogEvent* logEvent, int atomId, int64_t eventTi
std::shared_ptr<LogEvent> CreateNoValuesLogEvent(int atomId, int64_t eventTimeNs);
+void CreateNoValuesLogEvent(LogEvent* logEvent, int atomId, int64_t eventTimeNs);
+
// Create log event for screen state changed.
std::unique_ptr<LogEvent> CreateScreenStateChangedEvent(
uint64_t timestampNs, const android::view::DisplayStateEnum state);
diff --git a/core/java/android/app/AppOpsManager.java b/core/java/android/app/AppOpsManager.java
index 26db8f3ecb54..a5dcefcf3ab7 100644
--- a/core/java/android/app/AppOpsManager.java
+++ b/core/java/android/app/AppOpsManager.java
@@ -1088,8 +1088,9 @@ public class AppOpsManager {
public static final int OP_ACTIVATE_PLATFORM_VPN = AppProtoEnums.APP_OP_ACTIVATE_PLATFORM_VPN;
/** @hide */
public static final int OP_LOADER_USAGE_STATS = AppProtoEnums.APP_OP_LOADER_USAGE_STATS;
- /** @hide Access telephony call audio */
- public static final int OP_ACCESS_CALL_AUDIO = AppProtoEnums.APP_OP_ACCESS_CALL_AUDIO;
+
+ // App op deprecated/removed.
+ private static final int OP_DEPRECATED_1 = AppProtoEnums.APP_OP_DEPRECATED_1;
/** @hide Auto-revoke app permissions if app is unused for an extended period */
public static final int OP_AUTO_REVOKE_PERMISSIONS_IF_UNUSED =
@@ -1396,9 +1397,6 @@ public class AppOpsManager {
@SystemApi
public static final String OPSTR_MANAGE_EXTERNAL_STORAGE =
"android:manage_external_storage";
- /** @hide Access telephony call audio */
- @SystemApi
- public static final String OPSTR_ACCESS_CALL_AUDIO = "android:access_call_audio";
/** @hide Auto-revoke app permissions if app is unused for an extended period */
@SystemApi
@@ -1498,7 +1496,6 @@ public class AppOpsManager {
OP_MANAGE_EXTERNAL_STORAGE,
OP_INTERACT_ACROSS_PROFILES,
OP_LOADER_USAGE_STATS,
- OP_ACCESS_CALL_AUDIO,
OP_AUTO_REVOKE_PERMISSIONS_IF_UNUSED,
OP_AUTO_REVOKE_MANAGED_BY_INSTALLER,
};
@@ -1608,7 +1605,7 @@ public class AppOpsManager {
OP_INTERACT_ACROSS_PROFILES, //INTERACT_ACROSS_PROFILES
OP_ACTIVATE_PLATFORM_VPN, // ACTIVATE_PLATFORM_VPN
OP_LOADER_USAGE_STATS, // LOADER_USAGE_STATS
- OP_ACCESS_CALL_AUDIO, // ACCESS_CALL_AUDIO
+ OP_DEPRECATED_1, // deprecated
OP_AUTO_REVOKE_PERMISSIONS_IF_UNUSED, //AUTO_REVOKE_PERMISSIONS_IF_UNUSED
OP_AUTO_REVOKE_MANAGED_BY_INSTALLER, //OP_AUTO_REVOKE_MANAGED_BY_INSTALLER
};
@@ -1713,7 +1710,7 @@ public class AppOpsManager {
OPSTR_INTERACT_ACROSS_PROFILES,
OPSTR_ACTIVATE_PLATFORM_VPN,
OPSTR_LOADER_USAGE_STATS,
- OPSTR_ACCESS_CALL_AUDIO,
+ "", // deprecated
OPSTR_AUTO_REVOKE_PERMISSIONS_IF_UNUSED,
OPSTR_AUTO_REVOKE_MANAGED_BY_INSTALLER,
};
@@ -1819,7 +1816,7 @@ public class AppOpsManager {
"INTERACT_ACROSS_PROFILES",
"ACTIVATE_PLATFORM_VPN",
"LOADER_USAGE_STATS",
- "ACCESS_CALL_AUDIO",
+ "deprecated",
"AUTO_REVOKE_PERMISSIONS_IF_UNUSED",
"AUTO_REVOKE_MANAGED_BY_INSTALLER",
};
@@ -1926,7 +1923,7 @@ public class AppOpsManager {
android.Manifest.permission.INTERACT_ACROSS_PROFILES,
null, // no permission for OP_ACTIVATE_PLATFORM_VPN
android.Manifest.permission.LOADER_USAGE_STATS,
- Manifest.permission.ACCESS_CALL_AUDIO,
+ null, // deprecated operation
null, // no permission for OP_AUTO_REVOKE_PERMISSIONS_IF_UNUSED
null, // no permission for OP_AUTO_REVOKE_MANAGED_BY_INSTALLER
};
@@ -2033,7 +2030,7 @@ public class AppOpsManager {
null, // INTERACT_ACROSS_PROFILES
null, // ACTIVATE_PLATFORM_VPN
null, // LOADER_USAGE_STATS
- null, // ACCESS_CALL_AUDIO
+ null, // deprecated operation
null, // AUTO_REVOKE_PERMISSIONS_IF_UNUSED
null, // AUTO_REVOKE_MANAGED_BY_INSTALLER
};
@@ -2139,7 +2136,7 @@ public class AppOpsManager {
null, // INTERACT_ACROSS_PROFILES
null, // ACTIVATE_PLATFORM_VPN
null, // LOADER_USAGE_STATS
- null, // ACCESS_CALL_AUDIO
+ null, // deprecated operation
null, // AUTO_REVOKE_PERMISSIONS_IF_UNUSED
null, // AUTO_REVOKE_MANAGED_BY_INSTALLER
};
@@ -2244,7 +2241,7 @@ public class AppOpsManager {
AppOpsManager.MODE_DEFAULT, // INTERACT_ACROSS_PROFILES
AppOpsManager.MODE_IGNORED, // ACTIVATE_PLATFORM_VPN
AppOpsManager.MODE_DEFAULT, // LOADER_USAGE_STATS
- AppOpsManager.MODE_DEFAULT, // ACCESS_CALL_AUDIO
+ AppOpsManager.MODE_IGNORED, // deprecated operation
AppOpsManager.MODE_DEFAULT, // OP_AUTO_REVOKE_PERMISSIONS_IF_UNUSED
AppOpsManager.MODE_ALLOWED, // OP_AUTO_REVOKE_MANAGED_BY_INSTALLER
};
@@ -2353,7 +2350,7 @@ public class AppOpsManager {
false, // INTERACT_ACROSS_PROFILES
false, // ACTIVATE_PLATFORM_VPN
false, // LOADER_USAGE_STATS
- false, // ACCESS_CALL_AUDIO
+ false, // deprecated operation
false, // AUTO_REVOKE_PERMISSIONS_IF_UNUSED
false, // AUTO_REVOKE_MANAGED_BY_INSTALLER
};
@@ -8446,7 +8443,9 @@ public class AppOpsManager {
/**
* Pulls current AppOps access report and picks package and op to watch for next access report
- *
+ * Returns null if no reports were collected since last call. There is no guarantee of report
+ * collection, hence this method should be called periodically even if no report was collected
+ * to pick different package and op to watch.
* @hide
*/
@SystemApi
diff --git a/core/java/android/app/ApplicationExitInfo.java b/core/java/android/app/ApplicationExitInfo.java
index 61be01f9f6c0..0ecc003a33bd 100644
--- a/core/java/android/app/ApplicationExitInfo.java
+++ b/core/java/android/app/ApplicationExitInfo.java
@@ -499,9 +499,11 @@ public final class ApplicationExitInfo implements Parcelable {
/**
* Return the defining kernel user identifier, maybe different from {@link #getRealUid} and
- * {@link #getPackageUid}, if an external service was bound with the flag
- * {@link android.content.Context#BIND_EXTERNAL_SERVICE} - in this case, this field here
- * will be the kernel user identifier of the external service provider.
+ * {@link #getPackageUid}, if an external service has the
+ * {@link android.R.styleable#AndroidManifestService_useAppZygote android:useAppZygote} set
+ * to <code>true<code> and was bound with the flag
+ * {@link android.content.Context#BIND_EXTERNAL_SERVICE} - in this case, this field here will
+ * be the kernel user identifier of the external service provider.
*/
public int getDefiningUid() {
return mDefiningUid;
diff --git a/core/java/android/app/ContextImpl.java b/core/java/android/app/ContextImpl.java
index 9ccfe8df14c2..17fd4efec9cc 100644
--- a/core/java/android/app/ContextImpl.java
+++ b/core/java/android/app/ContextImpl.java
@@ -2414,8 +2414,7 @@ class ContextImpl extends Context {
: CompatibilityInfo.DEFAULT_COMPATIBILITY_INFO;
final List<ResourcesLoader> loaders = mResources.getLoaders();
- // TODO(b/128338354): Rename to createTokenResources
- return mResourcesManager.createBaseActivityResources(mToken, resDir, splitResDirs,
+ return mResourcesManager.createBaseTokenResources(mToken, resDir, splitResDirs,
overlayDirs, libDirs, displayId, null /* overrideConfig */,
compatInfo, mClassLoader, loaders);
}
@@ -2684,7 +2683,7 @@ class ContextImpl extends Context {
// Create the base resources for which all configuration contexts for this Activity
// will be rebased upon.
- context.setResources(resourcesManager.createBaseActivityResources(activityToken,
+ context.setResources(resourcesManager.createBaseTokenResources(activityToken,
packageInfo.getResDir(),
splitDirs,
packageInfo.getOverlayDirs(),
diff --git a/core/java/android/app/IActivityManager.aidl b/core/java/android/app/IActivityManager.aidl
index b8221b4efa2f..833bfed573b2 100644
--- a/core/java/android/app/IActivityManager.aidl
+++ b/core/java/android/app/IActivityManager.aidl
@@ -99,6 +99,7 @@ interface IActivityManager {
void unregisterUidObserver(in IUidObserver observer);
boolean isUidActive(int uid, String callingPackage);
int getUidProcessState(int uid, in String callingPackage);
+ boolean isUidActiveOrForeground(int uid, String callingPackage);
// =============== End of transactions used on native side as well ============================
// Special low-level communication with activity manager.
@@ -143,9 +144,6 @@ interface IActivityManager {
void attachApplication(in IApplicationThread app, long startSeq);
List<ActivityManager.RunningTaskInfo> getTasks(int maxNum);
@UnsupportedAppUsage
- List<ActivityManager.RunningTaskInfo> getFilteredTasks(int maxNum, int ignoreActivityType,
- int ignoreWindowingMode);
- @UnsupportedAppUsage
void moveTaskToFront(in IApplicationThread caller, in String callingPackage, int task,
int flags, in Bundle options);
@UnsupportedAppUsage
diff --git a/core/java/android/app/IActivityTaskManager.aidl b/core/java/android/app/IActivityTaskManager.aidl
index 03717ecd4038..8b8ebe80f01f 100644
--- a/core/java/android/app/IActivityTaskManager.aidl
+++ b/core/java/android/app/IActivityTaskManager.aidl
@@ -155,8 +155,8 @@ interface IActivityTaskManager {
boolean removeTask(int taskId);
void removeAllVisibleRecentTasks();
List<ActivityManager.RunningTaskInfo> getTasks(int maxNum);
- List<ActivityManager.RunningTaskInfo> getFilteredTasks(int maxNum, int ignoreActivityType,
- int ignoreWindowingMode);
+ List<ActivityManager.RunningTaskInfo> getFilteredTasks(int maxNum,
+ boolean filterOnlyVisibleRecents);
boolean shouldUpRecreateTask(in IBinder token, in String destAffinity);
boolean navigateUpTo(in IBinder token, in Intent target, int resultCode,
in Intent resultData);
diff --git a/core/java/android/app/ResourcesManager.java b/core/java/android/app/ResourcesManager.java
index 5f756033390b..392c05ac5949 100644
--- a/core/java/android/app/ResourcesManager.java
+++ b/core/java/android/app/ResourcesManager.java
@@ -695,26 +695,26 @@ public class ResourcesManager {
}
/**
- * Creates base resources for an Activity. Calls to
+ * Creates base resources for a binder token. Calls to
* {@link #getResources(IBinder, String, String[], String[], String[], int, Configuration,
- * CompatibilityInfo, ClassLoader, List)} with the same activityToken will have their override
+ * CompatibilityInfo, ClassLoader, List)} with the same binder token will have their override
* configurations merged with the one specified here.
*
- * @param activityToken Represents an Activity.
+ * @param token Represents an {@link Activity} or {@link WindowContext}.
* @param resDir The base resource path. Can be null (only framework resources will be loaded).
* @param splitResDirs An array of split resource paths. Can be null.
* @param overlayDirs An array of overlay paths. Can be null.
* @param libDirs An array of resource library paths. Can be null.
* @param displayId The ID of the display for which to create the resources.
* @param overrideConfig The configuration to apply on top of the base configuration. Can be
- * null. This provides the base override for this Activity.
+ * {@code null}. This provides the base override for this token.
* @param compatInfo The compatibility settings to use. Cannot be null. A default to use is
* {@link CompatibilityInfo#DEFAULT_COMPATIBILITY_INFO}.
* @param classLoader The class loader to use when inflating Resources. If null, the
* {@link ClassLoader#getSystemClassLoader()} is used.
* @return a Resources object from which to access resources.
*/
- public @Nullable Resources createBaseActivityResources(@NonNull IBinder activityToken,
+ public @Nullable Resources createBaseTokenResources(@NonNull IBinder token,
@Nullable String resDir,
@Nullable String[] splitResDirs,
@Nullable String[] overlayDirs,
@@ -739,24 +739,24 @@ public class ResourcesManager {
classLoader = classLoader != null ? classLoader : ClassLoader.getSystemClassLoader();
if (DEBUG) {
- Slog.d(TAG, "createBaseActivityResources activity=" + activityToken
+ Slog.d(TAG, "createBaseActivityResources activity=" + token
+ " with key=" + key);
}
synchronized (this) {
// Force the creation of an ActivityResourcesStruct.
- getOrCreateActivityResourcesStructLocked(activityToken);
+ getOrCreateActivityResourcesStructLocked(token);
}
// Update any existing Activity Resources references.
- updateResourcesForActivity(activityToken, overrideConfig, displayId,
+ updateResourcesForActivity(token, overrideConfig, displayId,
false /* movedToDifferentDisplay */);
- cleanupReferences(activityToken);
- rebaseKeyForActivity(activityToken, key);
+ cleanupReferences(token);
+ rebaseKeyForActivity(token, key);
synchronized (this) {
- Resources resources = findResourcesForActivityLocked(activityToken, key,
+ Resources resources = findResourcesForActivityLocked(token, key,
classLoader);
if (resources != null) {
return resources;
@@ -764,7 +764,7 @@ public class ResourcesManager {
}
// Now request an actual Resources object.
- return createResources(activityToken, key, classLoader);
+ return createResources(token, key, classLoader);
} finally {
Trace.traceEnd(Trace.TRACE_TAG_RESOURCES);
}
diff --git a/core/java/android/app/TaskEmbedder.java b/core/java/android/app/TaskEmbedder.java
index 5ebcc46aa0d8..b8ad30840173 100644
--- a/core/java/android/app/TaskEmbedder.java
+++ b/core/java/android/app/TaskEmbedder.java
@@ -16,6 +16,7 @@
package android.app;
+import static android.app.WindowConfiguration.WINDOWING_MODE_MULTI_WINDOW;
import static android.hardware.display.DisplayManager.VIRTUAL_DISPLAY_FLAG_DESTROY_CONTENT_ON_REMOVAL;
import static android.hardware.display.DisplayManager.VIRTUAL_DISPLAY_FLAG_OWN_CONTENT_ONLY;
import static android.hardware.display.DisplayManager.VIRTUAL_DISPLAY_FLAG_PUBLIC;
@@ -291,7 +292,7 @@ public class TaskEmbedder {
* @see #startActivity(PendingIntent)
*/
public void startActivity(@NonNull Intent intent) {
- final ActivityOptions options = prepareActivityOptions();
+ final ActivityOptions options = prepareActivityOptions(null);
mContext.startActivity(intent, options.toBundle());
}
@@ -304,7 +305,7 @@ public class TaskEmbedder {
* @see #startActivity(PendingIntent)
*/
public void startActivity(@NonNull Intent intent, UserHandle user) {
- final ActivityOptions options = prepareActivityOptions();
+ final ActivityOptions options = prepareActivityOptions(null);
mContext.startActivityAsUser(intent, options.toBundle(), user);
}
@@ -316,7 +317,7 @@ public class TaskEmbedder {
* @see #startActivity(Intent)
*/
public void startActivity(@NonNull PendingIntent pendingIntent) {
- final ActivityOptions options = prepareActivityOptions();
+ final ActivityOptions options = prepareActivityOptions(null);
try {
pendingIntent.send(null /* context */, 0 /* code */, null /* intent */,
null /* onFinished */, null /* handler */, null /* requiredPermission */,
@@ -337,8 +338,7 @@ public class TaskEmbedder {
*/
public void startActivity(@NonNull PendingIntent pendingIntent, @Nullable Intent fillInIntent,
@NonNull ActivityOptions options) {
-
- options.setLaunchDisplayId(mVirtualDisplay.getDisplay().getDisplayId());
+ prepareActivityOptions(options);
try {
pendingIntent.send(mContext, 0 /* code */, fillInIntent,
null /* onFinished */, null /* handler */, null /* requiredPermission */,
@@ -364,21 +364,25 @@ public class TaskEmbedder {
@NonNull ActivityOptions options, @Nullable Rect sourceBounds) {
LauncherApps service =
(LauncherApps) mContext.getSystemService(Context.LAUNCHER_APPS_SERVICE);
- options.setLaunchDisplayId(mVirtualDisplay.getDisplay().getDisplayId());
+ prepareActivityOptions(options);
service.startShortcut(shortcut, sourceBounds, options.toBundle());
}
/**
- * Check if container is ready to launch and create {@link ActivityOptions} to target the
- * virtual display.
+ * Check if container is ready to launch and modify {@param options} to target the virtual
+ * display, creating them if necessary.
*/
- private ActivityOptions prepareActivityOptions() {
+ private ActivityOptions prepareActivityOptions(ActivityOptions options) {
if (mVirtualDisplay == null) {
throw new IllegalStateException(
"Trying to start activity before ActivityView is ready.");
}
- final ActivityOptions options = ActivityOptions.makeBasic();
+ if (options == null) {
+ options = ActivityOptions.makeBasic();
+ }
options.setLaunchDisplayId(getDisplayId());
+ options.setLaunchWindowingMode(WINDOWING_MODE_MULTI_WINDOW);
+ options.setTaskAlwaysOnTop(true);
return options;
}
diff --git a/core/java/android/app/admin/DevicePolicyManager.java b/core/java/android/app/admin/DevicePolicyManager.java
index c4458b30c2db..10309a9b4a03 100644
--- a/core/java/android/app/admin/DevicePolicyManager.java
+++ b/core/java/android/app/admin/DevicePolicyManager.java
@@ -4424,11 +4424,13 @@ public class DevicePolicyManager {
* the current factory reset protection (FRP) policy set previously by
* {@link #setFactoryResetProtectionPolicy}.
* <p>
- * This method can also be called by the FRP management agent on device, in which case,
- * it can pass {@code null} as the ComponentName.
+ * This method can also be called by the FRP management agent on device or with the permission
+ * {@link android.Manifest.permission#MASTER_CLEAR}, in which case, it can pass {@code null}
+ * as the ComponentName.
*
* @param admin Which {@link DeviceAdminReceiver} this request is associated with or
- * {@code null} if called by the FRP management agent on device.
+ * {@code null} if called by the FRP management agent on device or with the
+ * permission {@link android.Manifest.permission#MASTER_CLEAR}.
* @return The current FRP policy object or {@code null} if no policy is set.
* @throws SecurityException if {@code admin} is not a device owner, a profile owner of
* an organization-owned device or the FRP management agent.
diff --git a/core/java/android/app/admin/FactoryResetProtectionPolicy.java b/core/java/android/app/admin/FactoryResetProtectionPolicy.java
index 954db0459f99..aa94e817c152 100644
--- a/core/java/android/app/admin/FactoryResetProtectionPolicy.java
+++ b/core/java/android/app/admin/FactoryResetProtectionPolicy.java
@@ -43,6 +43,12 @@ import java.util.List;
* reset protection policy for the device by calling the {@code DevicePolicyManager} method
* {@link DevicePolicyManager#setFactoryResetProtectionPolicy(ComponentName,
* FactoryResetProtectionPolicy)}}.
+ * <p>
+ * Normally factory reset protection does not kick in if the device is factory reset via Settings.
+ * This is also the case when a device owner sets factory reset protection policy. However,
+ * when a profile owner of an organization-owned device sets factory reset protection policy that
+ * locks the device to specific accounts, the policy will take effect even if factory reset is
+ * performed from Settings.
*
* @see DevicePolicyManager#setFactoryResetProtectionPolicy
* @see DevicePolicyManager#getFactoryResetProtectionPolicy
@@ -236,4 +242,16 @@ public final class FactoryResetProtectionPolicy implements Parcelable {
}
}
+ /**
+ * Returns if the policy will result in factory reset protection being locked to
+ * admin-specified accounts.
+ * <p>
+ * When a device has a non-empty factory reset protection policy, trusted factory reset
+ * via Settings will no longer remove factory reset protection from the device.
+ * @hide
+ */
+ public boolean isNotEmpty() {
+ return !mFactoryResetProtectionAccounts.isEmpty() && mFactoryResetProtectionEnabled;
+ }
+
}
diff --git a/core/java/android/content/ContentProvider.java b/core/java/android/content/ContentProvider.java
index 31c3232f4714..9cf6569a6220 100644
--- a/core/java/android/content/ContentProvider.java
+++ b/core/java/android/content/ContentProvider.java
@@ -307,19 +307,7 @@ public abstract class ContentProvider implements ContentInterface, ComponentCall
try {
result.putString(ContentResolver.REMOTE_CALLBACK_RESULT, getType(uri));
} catch (Exception e) {
- Parcel parcel = Parcel.obtain();
- try {
- try {
- parcel.writeException(e);
- } catch (Exception ex) {
- // getType threw an unparcelable exception. Wrap the message into
- // a parcelable exception type
- parcel.writeException(new IllegalStateException(e.getMessage()));
- }
- result.putByteArray(ContentResolver.REMOTE_CALLBACK_ERROR, parcel.marshall());
- } finally {
- parcel.recycle();
- }
+ putExceptionInBundle(result, ContentResolver.REMOTE_CALLBACK_ERROR, e);
}
callback.sendResult(result);
}
@@ -602,8 +590,12 @@ public abstract class ContentProvider implements ContentInterface, ComponentCall
public void canonicalizeAsync(String callingPkg, @Nullable String attributionTag, Uri uri,
RemoteCallback callback) {
final Bundle result = new Bundle();
- result.putParcelable(ContentResolver.REMOTE_CALLBACK_RESULT,
- canonicalize(callingPkg, attributionTag, uri));
+ try {
+ result.putParcelable(ContentResolver.REMOTE_CALLBACK_RESULT,
+ canonicalize(callingPkg, attributionTag, uri));
+ } catch (Exception e) {
+ putExceptionInBundle(result, ContentResolver.REMOTE_CALLBACK_ERROR, e);
+ }
callback.sendResult(result);
}
@@ -717,6 +709,22 @@ public abstract class ContentProvider implements ContentInterface, ComponentCall
return AppOpsManager.MODE_ALLOWED;
}
+
+ private void putExceptionInBundle(Bundle bundle, String key, Exception e) {
+ Parcel parcel = Parcel.obtain();
+ try {
+ try {
+ parcel.writeException(e);
+ } catch (Exception ex) {
+ // getType threw an unparcelable exception. Wrap the message into
+ // a parcelable exception type
+ parcel.writeException(new IllegalStateException(e.getMessage()));
+ }
+ bundle.putByteArray(key, parcel.marshall());
+ } finally {
+ parcel.recycle();
+ }
+ }
}
boolean checkUser(int pid, int uid, Context context) {
diff --git a/core/java/android/content/pm/CrossProfileApps.java b/core/java/android/content/pm/CrossProfileApps.java
index 6ba811e077ac..7578ede2648d 100644
--- a/core/java/android/content/pm/CrossProfileApps.java
+++ b/core/java/android/content/pm/CrossProfileApps.java
@@ -487,6 +487,34 @@ public class CrossProfileApps {
}
}
+ /**
+ * Clears the app-op for {@link android.Manifest.permission#INTERACT_ACROSS_PROFILES} back to
+ * its default value for every package on the device.
+ *
+ * <p>This method can be used to ensure that app-op state is not left around on existing users
+ * for previously-configured profiles.
+ *
+ * <p>If the caller does not have the {@link android.Manifest.permission
+ * #CONFIGURE_INTERACT_ACROSS_PROFILES} permission, then they must have the permissions that
+ * would have been required to call {@link android.app.AppOpsManager#setMode(int, int, String,
+ * int)}, which includes {@link android.Manifest.permission#MANAGE_APP_OPS_MODES}.
+ *
+ * <p>Also requires either {@link android.Manifest.permission#INTERACT_ACROSS_USERS} or {@link
+ * android.Manifest.permission#INTERACT_ACROSS_USERS_FULL}.
+ *
+ * @hide
+ */
+ @RequiresPermission(
+ allOf={android.Manifest.permission.CONFIGURE_INTERACT_ACROSS_PROFILES,
+ android.Manifest.permission.INTERACT_ACROSS_USERS})
+ public void clearInteractAcrossProfilesAppOps() {
+ try {
+ mService.clearInteractAcrossProfilesAppOps();
+ } catch (RemoteException ex) {
+ throw ex.rethrowFromSystemServer();
+ }
+ }
+
private void verifyCanAccessUser(UserHandle userHandle) {
if (!getTargetUserProfiles().contains(userHandle)) {
throw new SecurityException("Not allowed to access " + userHandle);
diff --git a/core/java/android/content/pm/ICrossProfileApps.aidl b/core/java/android/content/pm/ICrossProfileApps.aidl
index 9b0dae221538..e2850f111c4f 100644
--- a/core/java/android/content/pm/ICrossProfileApps.aidl
+++ b/core/java/android/content/pm/ICrossProfileApps.aidl
@@ -40,4 +40,5 @@ interface ICrossProfileApps {
boolean canConfigureInteractAcrossProfiles(in String packageName);
boolean canUserAttemptToConfigureInteractAcrossProfiles(in String packageName);
void resetInteractAcrossProfilesAppOps(in List<String> packageNames);
+ void clearInteractAcrossProfilesAppOps();
}
diff --git a/core/java/android/content/pm/PackageInstaller.java b/core/java/android/content/pm/PackageInstaller.java
index 50bee854c027..1e0b2e358e17 100644
--- a/core/java/android/content/pm/PackageInstaller.java
+++ b/core/java/android/content/pm/PackageInstaller.java
@@ -1118,6 +1118,7 @@ public class PackageInstaller {
* {@hide}
*/
@SystemApi
+ @RequiresPermission(android.Manifest.permission.USE_INSTALLER_V2)
public @Nullable DataLoaderParams getDataLoaderParams() {
try {
DataLoaderParamsParcel data = mSession.getDataLoaderParams();
@@ -1157,6 +1158,7 @@ public class PackageInstaller {
* {@hide}
*/
@SystemApi
+ @RequiresPermission(android.Manifest.permission.USE_INSTALLER_V2)
public void addFile(@FileLocation int location, @NonNull String name, long lengthBytes,
@NonNull byte[] metadata, @Nullable byte[] signature) {
try {
@@ -1180,6 +1182,7 @@ public class PackageInstaller {
* {@hide}
*/
@SystemApi
+ @RequiresPermission(android.Manifest.permission.USE_INSTALLER_V2)
public void removeFile(@FileLocation int location, @NonNull String name) {
try {
mSession.removeFile(location, name);
@@ -1927,7 +1930,9 @@ public class PackageInstaller {
* {@hide}
*/
@SystemApi
- @RequiresPermission(Manifest.permission.INSTALL_PACKAGES)
+ @RequiresPermission(allOf = {
+ Manifest.permission.INSTALL_PACKAGES,
+ Manifest.permission.USE_INSTALLER_V2})
public void setDataLoaderParams(@NonNull DataLoaderParams dataLoaderParams) {
this.dataLoaderParams = dataLoaderParams;
}
diff --git a/core/java/android/hardware/biometrics/IBiometricServiceReceiverInternal.aidl b/core/java/android/hardware/biometrics/IBiometricServiceReceiverInternal.aidl
index 8bcaf828be97..e7219caf6cd8 100644
--- a/core/java/android/hardware/biometrics/IBiometricServiceReceiverInternal.aidl
+++ b/core/java/android/hardware/biometrics/IBiometricServiceReceiverInternal.aidl
@@ -26,7 +26,9 @@ package android.hardware.biometrics;
oneway interface IBiometricServiceReceiverInternal {
// Notify BiometricService that authentication was successful. If user confirmation is required,
// the auth token must be submitted into KeyStore.
- void onAuthenticationSucceeded(boolean requireConfirmation, in byte[] token);
+ // TODO(b/151967372): Strength should be changed to authenticatorId
+ void onAuthenticationSucceeded(boolean requireConfirmation, in byte[] token,
+ boolean isStrongBiometric);
// Notify BiometricService authentication was rejected.
void onAuthenticationFailed();
// Notify BiometricService than an error has occured. Forward to the correct receiver depending
diff --git a/core/java/android/inputmethodservice/InputMethodService.java b/core/java/android/inputmethodservice/InputMethodService.java
index 6daded4ee641..782fff2f69e0 100644
--- a/core/java/android/inputmethodservice/InputMethodService.java
+++ b/core/java/android/inputmethodservice/InputMethodService.java
@@ -60,7 +60,6 @@ import android.text.method.MovementMethod;
import android.util.Log;
import android.util.PrintWriterPrinter;
import android.util.Printer;
-import android.util.Size;
import android.view.Gravity;
import android.view.KeyCharacterMap;
import android.view.KeyEvent;
@@ -1480,8 +1479,8 @@ public class InputMethodService extends AbstractInputMethodService {
*/
public int getMaxWidth() {
final WindowManager windowManager = getSystemService(WindowManager.class);
- final Size windowSize = windowManager.getCurrentWindowMetrics().getSize();
- return windowSize.getWidth();
+ final Rect windowBounds = windowManager.getCurrentWindowMetrics().getBounds();
+ return windowBounds.width();
}
/**
diff --git a/core/java/android/os/Process.java b/core/java/android/os/Process.java
index b7b3c4fc8add..5d2c9d18c00c 100644
--- a/core/java/android/os/Process.java
+++ b/core/java/android/os/Process.java
@@ -607,6 +607,9 @@ public class Process {
* started.
* @param pkgDataInfoMap Map from related package names to private data directory
* volume UUID and inode number.
+ * @param whitelistedDataInfoMap Map from whitelisted package names to private data directory
+ * volume UUID and inode number.
+ * @param bindMountAppsData whether zygote needs to mount CE and DE data.
* @param bindMountAppStorageDirs whether zygote needs to mount Android/obb and Android/data.
* @param zygoteArgs Additional arguments to supply to the zygote process.
* @return An object that describes the result of the attempt to start the process.
@@ -631,13 +634,17 @@ public class Process {
@Nullable long[] disabledCompatChanges,
@Nullable Map<String, Pair<String, Long>>
pkgDataInfoMap,
+ @Nullable Map<String, Pair<String, Long>>
+ whitelistedDataInfoMap,
+ boolean bindMountAppsData,
boolean bindMountAppStorageDirs,
@Nullable String[] zygoteArgs) {
return ZYGOTE_PROCESS.start(processClass, niceName, uid, gid, gids,
runtimeFlags, mountExternal, targetSdkVersion, seInfo,
abi, instructionSet, appDataDir, invokeWith, packageName,
zygotePolicyFlags, isTopApp, disabledCompatChanges,
- pkgDataInfoMap, bindMountAppStorageDirs, zygoteArgs);
+ pkgDataInfoMap, whitelistedDataInfoMap, bindMountAppsData,
+ bindMountAppStorageDirs, zygoteArgs);
}
/** @hide */
@@ -661,7 +668,8 @@ public class Process {
runtimeFlags, mountExternal, targetSdkVersion, seInfo,
abi, instructionSet, appDataDir, invokeWith, packageName,
/*zygotePolicyFlags=*/ ZYGOTE_POLICY_FLAG_EMPTY, /*isTopApp=*/ false,
- disabledCompatChanges, /* pkgDataInfoMap */ null, false, zygoteArgs);
+ disabledCompatChanges, /* pkgDataInfoMap */ null,
+ /* whitelistedDataInfoMap */ null, false, false, zygoteArgs);
}
/**
diff --git a/core/java/android/os/RecoverySystem.java b/core/java/android/os/RecoverySystem.java
index d60820ef0f57..8cdcd49cb2cc 100644
--- a/core/java/android/os/RecoverySystem.java
+++ b/core/java/android/os/RecoverySystem.java
@@ -665,15 +665,17 @@ public class RecoverySystem {
* the preparation for unattended update is reset.
*
* @param context the Context to use.
- * @throws IOException if there were any errors setting up unattended update
+ * @throws IOException if there were any errors clearing the unattended update state
* @hide
*/
@SystemApi
@RequiresPermission(android.Manifest.permission.RECOVERY)
- public static boolean clearPrepareForUnattendedUpdate(@NonNull Context context)
+ public static void clearPrepareForUnattendedUpdate(@NonNull Context context)
throws IOException {
RecoverySystem rs = (RecoverySystem) context.getSystemService(Context.RECOVERY_SERVICE);
- return rs.clearLskf();
+ if (!rs.clearLskf()) {
+ throw new IOException("could not reset unattended update state");
+ }
}
/**
@@ -684,21 +686,22 @@ public class RecoverySystem {
* @param context the Context to use.
* @param updateToken the token used to call {@link #prepareForUnattendedUpdate} before
* @param reason the reboot reason to give to the {@link PowerManager}
- * @throws IOException if there were any errors setting up unattended update
- * @return false if the reboot couldn't proceed because the device wasn't ready for an
+ * @throws IOException if the reboot couldn't proceed because the device wasn't ready for an
* unattended reboot or if the {@code updateToken} did not match the previously
* given token
* @hide
*/
@SystemApi
@RequiresPermission(android.Manifest.permission.RECOVERY)
- public static boolean rebootAndApply(@NonNull Context context, @NonNull String updateToken,
+ public static void rebootAndApply(@NonNull Context context, @NonNull String updateToken,
@NonNull String reason) throws IOException {
if (updateToken == null) {
throw new NullPointerException("updateToken == null");
}
RecoverySystem rs = (RecoverySystem) context.getSystemService(Context.RECOVERY_SERVICE);
- return rs.rebootWithLskf(updateToken, reason);
+ if (!rs.rebootWithLskf(updateToken, reason)) {
+ throw new IOException("system not prepared to apply update");
+ }
}
/**
diff --git a/core/java/android/os/ZygoteProcess.java b/core/java/android/os/ZygoteProcess.java
index 5f3f14facd75..a4c99c006d80 100644
--- a/core/java/android/os/ZygoteProcess.java
+++ b/core/java/android/os/ZygoteProcess.java
@@ -333,6 +333,9 @@ public class ZygoteProcess {
* started.
* @param pkgDataInfoMap Map from related package names to private data directory
* volume UUID and inode number.
+ * @param whitelistedDataInfoMap Map from whitelisted package names to private data directory
+ * volume UUID and inode number.
+ * @param bindMountAppsData whether zygote needs to mount CE and DE data.
* @param bindMountAppStorageDirs whether zygote needs to mount Android/obb and Android/data.
*
* @param zygoteArgs Additional arguments to supply to the Zygote process.
@@ -355,6 +358,9 @@ public class ZygoteProcess {
@Nullable long[] disabledCompatChanges,
@Nullable Map<String, Pair<String, Long>>
pkgDataInfoMap,
+ @Nullable Map<String, Pair<String, Long>>
+ whitelistedDataInfoMap,
+ boolean bindMountAppsData,
boolean bindMountAppStorageDirs,
@Nullable String[] zygoteArgs) {
// TODO (chriswailes): Is there a better place to check this value?
@@ -367,7 +373,8 @@ public class ZygoteProcess {
runtimeFlags, mountExternal, targetSdkVersion, seInfo,
abi, instructionSet, appDataDir, invokeWith, /*startChildZygote=*/ false,
packageName, zygotePolicyFlags, isTopApp, disabledCompatChanges,
- pkgDataInfoMap, bindMountAppStorageDirs, zygoteArgs);
+ pkgDataInfoMap, whitelistedDataInfoMap, bindMountAppsData,
+ bindMountAppStorageDirs, zygoteArgs);
} catch (ZygoteStartFailedEx ex) {
Log.e(LOG_TAG,
"Starting VM process through Zygote failed");
@@ -608,6 +615,9 @@ public class ZygoteProcess {
* @param disabledCompatChanges a list of disabled compat changes for the process being started.
* @param pkgDataInfoMap Map from related package names to private data directory volume UUID
* and inode number.
+ * @param whitelistedDataInfoMap Map from whitelisted package names to private data directory
+ * volume UUID and inode number.
+ * @param bindMountAppsData whether zygote needs to mount CE and DE data.
* @param bindMountAppStorageDirs whether zygote needs to mount Android/obb and Android/data.
* @param extraArgs Additional arguments to supply to the zygote process.
* @return An object that describes the result of the attempt to start the process.
@@ -631,6 +641,9 @@ public class ZygoteProcess {
@Nullable long[] disabledCompatChanges,
@Nullable Map<String, Pair<String, Long>>
pkgDataInfoMap,
+ @Nullable Map<String, Pair<String, Long>>
+ whitelistedDataInfoMap,
+ boolean bindMountAppsData,
boolean bindMountAppStorageDirs,
@Nullable String[] extraArgs)
throws ZygoteStartFailedEx {
@@ -728,11 +741,33 @@ public class ZygoteProcess {
}
argsForZygote.add(sb.toString());
}
+ if (whitelistedDataInfoMap != null && whitelistedDataInfoMap.size() > 0) {
+ StringBuilder sb = new StringBuilder();
+ sb.append(Zygote.WHITELISTED_DATA_INFO_MAP);
+ sb.append("=");
+ boolean started = false;
+ for (Map.Entry<String, Pair<String, Long>> entry : whitelistedDataInfoMap.entrySet()) {
+ if (started) {
+ sb.append(',');
+ }
+ started = true;
+ sb.append(entry.getKey());
+ sb.append(',');
+ sb.append(entry.getValue().first);
+ sb.append(',');
+ sb.append(entry.getValue().second);
+ }
+ argsForZygote.add(sb.toString());
+ }
if (bindMountAppStorageDirs) {
argsForZygote.add(Zygote.BIND_MOUNT_APP_STORAGE_DIRS);
}
+ if (bindMountAppsData) {
+ argsForZygote.add(Zygote.BIND_MOUNT_APP_DATA_DIRS);
+ }
+
if (disabledCompatChanges != null && disabledCompatChanges.length > 0) {
StringBuilder sb = new StringBuilder();
sb.append("--disabled-compat-changes=");
@@ -1291,6 +1326,7 @@ public class ZygoteProcess {
true /* startChildZygote */, null /* packageName */,
ZYGOTE_POLICY_FLAG_SYSTEM_PROCESS /* zygotePolicyFlags */, false /* isTopApp */,
null /* disabledCompatChanges */, null /* pkgDataInfoMap */,
+ null /* whitelistedDataInfoMap */, false /* bindMountAppsData*/,
/* bindMountAppStorageDirs */ false, extraArgs);
} catch (ZygoteStartFailedEx ex) {
diff --git a/core/java/android/os/storage/StorageManager.java b/core/java/android/os/storage/StorageManager.java
index a68cc3dfe0e4..aee32ed769ac 100644
--- a/core/java/android/os/storage/StorageManager.java
+++ b/core/java/android/os/storage/StorageManager.java
@@ -162,7 +162,12 @@ public class StorageManager {
/** {@hide} */
public static final String PROP_SETTINGS_FUSE = FeatureFlagUtils.PERSIST_PREFIX
+ FeatureFlagUtils.SETTINGS_FUSE_FLAG;
-
+ /**
+ * Property that determines whether {@link OP_LEGACY_STORAGE} is sticky for
+ * legacy apps.
+ * @hide
+ */
+ public static final String PROP_LEGACY_OP_STICKY = "persist.sys.legacy_storage_sticky";
/** {@hide} */
public static final String UUID_PRIVATE_INTERNAL = null;
diff --git a/core/java/android/provider/Settings.java b/core/java/android/provider/Settings.java
index 60f10cd884ca..bbcb9d9249af 100644
--- a/core/java/android/provider/Settings.java
+++ b/core/java/android/provider/Settings.java
@@ -6564,13 +6564,6 @@ public final class Settings {
* Setting specifying if the accessibility shortcut is enabled.
* @hide
*/
- public static final String ACCESSIBILITY_SHORTCUT_ENABLED =
- "accessibility_shortcut_enabled";
-
- /**
- * Setting specifying if the accessibility shortcut is enabled.
- * @hide
- */
public static final String ACCESSIBILITY_SHORTCUT_ON_LOCK_SCREEN =
"accessibility_shortcut_on_lock_screen";
diff --git a/core/java/android/service/autofill/InlinePresentation.java b/core/java/android/service/autofill/InlinePresentation.java
index a9addba375af..b6a8ced29f72 100644
--- a/core/java/android/service/autofill/InlinePresentation.java
+++ b/core/java/android/service/autofill/InlinePresentation.java
@@ -49,7 +49,8 @@ public final class InlinePresentation implements Parcelable {
private final @NonNull InlinePresentationSpec mInlinePresentationSpec;
/**
- * Indicates whether the UI should be pinned, hence non-scrollable, in the host.
+ * Indicates whether the UI should be pinned, hence non-scrollable and non-filterable, in the
+ * host.
*/
private final boolean mPinned;
diff --git a/core/java/android/service/controls/actions/ControlAction.java b/core/java/android/service/controls/actions/ControlAction.java
index 37a75f0e9e5a..10f526d6565c 100644
--- a/core/java/android/service/controls/actions/ControlAction.java
+++ b/core/java/android/service/controls/actions/ControlAction.java
@@ -136,7 +136,8 @@ public abstract class ControlAction {
/**
* Response code for the {@code consumer} in
* {@link ControlsProviderService#performControlAction} indicating that in order for the action
- * to be performed, acknowledgment from the user is required.
+ * to be performed, acknowledgment from the user is required. Any non-empty string returned
+ * from {@link #getChallengeValue} shall be treated as a positive acknowledgment.
*/
public static final @ResponseResult int RESPONSE_CHALLENGE_ACK = 3;
/**
diff --git a/core/java/android/view/Display.java b/core/java/android/view/Display.java
index dffcafe1de0e..0ccb1e055c46 100644
--- a/core/java/android/view/Display.java
+++ b/core/java/android/view/Display.java
@@ -57,8 +57,8 @@ import java.util.List;
* <li>The application display area specifies the part of the display that may contain
* an application window, excluding the system decorations. The application display area may
* be smaller than the real display area because the system subtracts the space needed
- * for decor elements such as the status bar. Use {@link WindowMetrics#getSize()} to query the
- * application window size.</li>
+ * for decor elements such as the status bar. Use {@link WindowMetrics#getBounds()} to query the
+ * application window bounds.</li>
* <li>The real display area specifies the part of the display that contains content
* including the system decorations. Even so, the real display area may be smaller than the
* physical size of the display if the window manager is emulating a smaller display
@@ -673,7 +673,7 @@ public final class Display {
*
* @param outSize A {@link Point} object to receive the size information.
* @deprecated Use {@link WindowManager#getCurrentWindowMetrics()} to obtain an instance of
- * {@link WindowMetrics} and use {@link WindowMetrics#getSize()} instead.
+ * {@link WindowMetrics} and use {@link WindowMetrics#getBounds()} instead.
*/
@Deprecated
public void getSize(Point outSize) {
@@ -689,7 +689,7 @@ public final class Display {
* Gets the size of the display as a rectangle, in pixels.
*
* @param outSize A {@link Rect} object to receive the size information.
- * @deprecated Use {@link WindowMetrics#getSize()} to get the dimensions of the application
+ * @deprecated Use {@link WindowMetrics#getBounds()} to get the dimensions of the application
* window area.
*/
@Deprecated
@@ -755,7 +755,7 @@ public final class Display {
}
/**
- * @deprecated Use {@link WindowMetrics#getSize()} instead.
+ * @deprecated Use {@link WindowMetrics#getBounds#width()} instead.
*/
@Deprecated
public int getWidth() {
@@ -766,7 +766,7 @@ public final class Display {
}
/**
- * @deprecated Use {@link WindowMetrics#getSize()} instead.
+ * @deprecated Use {@link WindowMetrics#getBounds()#height()} instead.
*/
@Deprecated
public int getHeight() {
@@ -1105,7 +1105,7 @@ public final class Display {
* </p>
*
* @param outMetrics A {@link DisplayMetrics} object to receive the metrics.
- * @deprecated Use {@link WindowMetrics#getSize()} to get the dimensions of the application
+ * @deprecated Use {@link WindowMetrics#getBounds()} to get the dimensions of the application
* window area, and {@link Configuration#densityDpi} to get the current density.
*/
@Deprecated
diff --git a/core/java/android/view/SurfaceControlViewHost.java b/core/java/android/view/SurfaceControlViewHost.java
index cd22ad6151b8..fe70ff7a1dbf 100644
--- a/core/java/android/view/SurfaceControlViewHost.java
+++ b/core/java/android/view/SurfaceControlViewHost.java
@@ -192,6 +192,7 @@ public class SurfaceControlViewHost {
final WindowManager.LayoutParams lp =
new WindowManager.LayoutParams(width, height,
WindowManager.LayoutParams.TYPE_APPLICATION, 0, PixelFormat.TRANSPARENT);
+ lp.flags |= WindowManager.LayoutParams.FLAG_HARDWARE_ACCELERATED;
setView(view, lp);
}
diff --git a/core/java/android/view/View.java b/core/java/android/view/View.java
index d69357bc503d..4922917c911c 100644
--- a/core/java/android/view/View.java
+++ b/core/java/android/view/View.java
@@ -3475,7 +3475,7 @@ public class View implements Drawable.Callback, KeyEvent.Callback,
/**
* Flag indicating the field should not have yellow highlight when autofilled.
*/
- private static final int PFLAG4_AUTOFILL_HIDE_HIGHLIGHT = 0x100;
+ private static final int PFLAG4_AUTOFILL_HIDE_HIGHLIGHT = 0x200;
/* End of masks for mPrivateFlags4 */
diff --git a/core/java/android/view/ViewConfiguration.java b/core/java/android/view/ViewConfiguration.java
index 04260c47eda3..4bea623716dc 100644
--- a/core/java/android/view/ViewConfiguration.java
+++ b/core/java/android/view/ViewConfiguration.java
@@ -23,11 +23,11 @@ import android.compat.annotation.UnsupportedAppUsage;
import android.content.Context;
import android.content.res.Configuration;
import android.content.res.Resources;
+import android.graphics.Rect;
import android.os.Build;
import android.os.RemoteException;
import android.provider.Settings;
import android.util.DisplayMetrics;
-import android.util.Size;
import android.util.SparseArray;
import android.util.TypedValue;
@@ -410,8 +410,8 @@ public class ViewConfiguration {
// Size of the screen in bytes, in ARGB_8888 format
final WindowManager windowManager = context.getSystemService(WindowManager.class);
- final Size maxWindowSize = windowManager.getMaximumWindowMetrics().getSize();
- mMaximumDrawingCacheSize = 4 * maxWindowSize.getWidth() * maxWindowSize.getHeight();
+ final Rect maxWindowBounds = windowManager.getMaximumWindowMetrics().getBounds();
+ mMaximumDrawingCacheSize = 4 * maxWindowBounds.width() * maxWindowBounds.height();
mOverscrollDistance = (int) (sizeAndDensity * OVERSCROLL_DISTANCE + 0.5f);
mOverflingDistance = (int) (sizeAndDensity * OVERFLING_DISTANCE + 0.5f);
diff --git a/core/java/android/view/WindowManagerImpl.java b/core/java/android/view/WindowManagerImpl.java
index 8bf1ade876ca..316a5f2c88d2 100644
--- a/core/java/android/view/WindowManagerImpl.java
+++ b/core/java/android/view/WindowManagerImpl.java
@@ -35,7 +35,6 @@ import android.graphics.Region;
import android.os.Bundle;
import android.os.IBinder;
import android.os.RemoteException;
-import android.util.Size;
import com.android.internal.os.IResultReceiver;
@@ -220,7 +219,7 @@ public final class WindowManagerImpl implements WindowManager {
final Context context = mParentWindow != null ? mParentWindow.getContext() : mContext;
final Rect bounds = getCurrentBounds(context);
- return new WindowMetrics(toSize(bounds), computeWindowInsets(bounds));
+ return new WindowMetrics(bounds, computeWindowInsets(bounds));
}
private static Rect getCurrentBounds(Context context) {
@@ -232,11 +231,7 @@ public final class WindowManagerImpl implements WindowManager {
@Override
public WindowMetrics getMaximumWindowMetrics() {
final Rect maxBounds = getMaximumBounds();
- return new WindowMetrics(toSize(maxBounds), computeWindowInsets(maxBounds));
- }
-
- private Size toSize(Rect frame) {
- return new Size(frame.width(), frame.height());
+ return new WindowMetrics(maxBounds, computeWindowInsets(maxBounds));
}
private Rect getMaximumBounds() {
diff --git a/core/java/android/view/WindowMetrics.java b/core/java/android/view/WindowMetrics.java
index ab5a06eb99de..86ef87997a07 100644
--- a/core/java/android/view/WindowMetrics.java
+++ b/core/java/android/view/WindowMetrics.java
@@ -18,10 +18,10 @@ package android.view;
import android.annotation.NonNull;
import android.graphics.Point;
-import android.util.Size;
+import android.graphics.Rect;
/**
- * Metrics about a Window, consisting of the size and {@link WindowInsets}.
+ * Metrics about a Window, consisting of the bounds and {@link WindowInsets}.
* <p>
* This is usually obtained from {@link WindowManager#getCurrentWindowMetrics()} and
* {@link WindowManager#getMaximumWindowMetrics()}.
@@ -31,21 +31,22 @@ import android.util.Size;
* @see WindowManager#getMaximumWindowMetrics()
*/
public final class WindowMetrics {
- private final @NonNull Size mSize;
+ private final @NonNull Rect mBounds;
private final @NonNull WindowInsets mWindowInsets;
- public WindowMetrics(@NonNull Size size, @NonNull WindowInsets windowInsets) {
- mSize = size;
+ public WindowMetrics(@NonNull Rect bounds, @NonNull WindowInsets windowInsets) {
+ mBounds = bounds;
mWindowInsets = windowInsets;
}
/**
- * Returns the size of the window.
+ * Returns the bounds of the area associated with this window or visual context.
* <p>
- * <b>Note that this reports a different size than {@link Display#getSize(Point)}.</b>
- * This method reports the window size including all system bars area, while
- * {@link Display#getSize(Point)} reports the area excluding navigation bars and display cutout
- * areas. The value reported by {@link Display#getSize(Point)} can be obtained by using:
+ * <b>Note that the size of the reported bounds can have different size than
+ * {@link Display#getSize(Point)}.</b> This method reports the window size including all system
+ * bar areas, while {@link Display#getSize(Point)} reports the area excluding navigation bars
+ * and display cutout areas. The value reported by {@link Display#getSize(Point)} can be
+ * obtained by using:
* <pre class="prettyprint">
* final WindowMetrics metrics = windowManager.getCurrentMetrics();
* // Gets all excluding insets
@@ -66,16 +67,16 @@ public final class WindowMetrics {
* </pre>
* </p>
*
- * @return window size in pixel.
+ * @return window bounds in pixels.
*/
- public @NonNull Size getSize() {
- return mSize;
+ public @NonNull Rect getBounds() {
+ return mBounds;
}
/**
- * Returns the {@link WindowInsets} of the window.
+ * Returns the {@link WindowInsets} of the area associated with this window or visual context.
*
- * @return the {@link WindowInsets} of the window.
+ * @return the {@link WindowInsets} of the visual area.
*/
public @NonNull WindowInsets getWindowInsets() {
return mWindowInsets;
diff --git a/core/java/android/view/autofill/AutofillManager.java b/core/java/android/view/autofill/AutofillManager.java
index 39a9ed4a82e7..267a5a6561af 100644
--- a/core/java/android/view/autofill/AutofillManager.java
+++ b/core/java/android/view/autofill/AutofillManager.java
@@ -1242,9 +1242,10 @@ public final class AutofillManager {
if (mLastAutofilledData.containsKey(id)) {
value = view.getAutofillValue();
valueWasRead = true;
+ final boolean hideHighlight = mLastAutofilledData.keySet().size() == 1;
if (Objects.equals(mLastAutofilledData.get(id), value)) {
- view.setAutofilled(true, false);
+ view.setAutofilled(true, hideHighlight);
} else {
view.setAutofilled(false, false);
mLastAutofilledData.remove(id);
diff --git a/core/java/android/view/autofill/AutofillPopupWindow.java b/core/java/android/view/autofill/AutofillPopupWindow.java
index 8d3dc83bca0c..2ead352fd199 100644
--- a/core/java/android/view/autofill/AutofillPopupWindow.java
+++ b/core/java/android/view/autofill/AutofillPopupWindow.java
@@ -25,7 +25,6 @@ import android.os.IBinder;
import android.os.RemoteException;
import android.transition.Transition;
import android.util.Log;
-import android.util.Size;
import android.view.View;
import android.view.View.OnTouchListener;
import android.view.ViewTreeObserver;
@@ -129,10 +128,10 @@ public class AutofillPopupWindow extends PopupWindow {
// Gravity.BOTTOM because PopupWindow base class does not expose computeGravity().
final WindowManager windowManager = anchor.getContext()
.getSystemService(WindowManager.class);
- final Size windowSize = windowManager.getCurrentWindowMetrics().getSize();
- width = windowSize.getWidth();
+ final Rect windowBounds = windowManager.getCurrentWindowMetrics().getBounds();
+ width = windowBounds.width();
if (height != LayoutParams.MATCH_PARENT) {
- offsetY = windowSize.getHeight() - height;
+ offsetY = windowBounds.height() - height;
}
actualAnchor = anchor;
} else if (virtualBounds != null) {
diff --git a/core/java/com/android/internal/accessibility/AccessibilityShortcutController.java b/core/java/com/android/internal/accessibility/AccessibilityShortcutController.java
index 54ea57a6cae4..d64b5f1118dc 100644
--- a/core/java/com/android/internal/accessibility/AccessibilityShortcutController.java
+++ b/core/java/com/android/internal/accessibility/AccessibilityShortcutController.java
@@ -144,9 +144,6 @@ public class AccessibilityShortcutController {
Settings.Secure.getUriFor(Settings.Secure.ACCESSIBILITY_SHORTCUT_TARGET_SERVICE),
false, co, UserHandle.USER_ALL);
mContext.getContentResolver().registerContentObserver(
- Settings.Secure.getUriFor(Settings.Secure.ACCESSIBILITY_SHORTCUT_ENABLED),
- false, co, UserHandle.USER_ALL);
- mContext.getContentResolver().registerContentObserver(
Settings.Secure.getUriFor(Settings.Secure.ACCESSIBILITY_SHORTCUT_ON_LOCK_SCREEN),
false, co, UserHandle.USER_ALL);
mContext.getContentResolver().registerContentObserver(
@@ -174,8 +171,6 @@ public class AccessibilityShortcutController {
public void onSettingsChanged() {
final boolean hasShortcutTarget = hasShortcutTarget();
final ContentResolver cr = mContext.getContentResolver();
- final boolean enabled = Settings.Secure.getIntForUser(
- cr, Settings.Secure.ACCESSIBILITY_SHORTCUT_ENABLED, 1, mUserId) == 1;
// Enable the shortcut from the lockscreen by default if the dialog has been shown
final int dialogAlreadyShown = Settings.Secure.getIntForUser(
cr, Settings.Secure.ACCESSIBILITY_SHORTCUT_DIALOG_SHOWN, DialogStaus.NOT_SHOWN,
@@ -183,7 +178,7 @@ public class AccessibilityShortcutController {
mEnabledOnLockScreen = Settings.Secure.getIntForUser(
cr, Settings.Secure.ACCESSIBILITY_SHORTCUT_ON_LOCK_SCREEN,
dialogAlreadyShown, mUserId) == 1;
- mIsShortcutEnabled = enabled && hasShortcutTarget;
+ mIsShortcutEnabled = hasShortcutTarget;
}
/**
diff --git a/core/java/com/android/internal/app/AbstractMultiProfilePagerAdapter.java b/core/java/com/android/internal/app/AbstractMultiProfilePagerAdapter.java
index ae9ce655ff3a..c53516389cd9 100644
--- a/core/java/com/android/internal/app/AbstractMultiProfilePagerAdapter.java
+++ b/core/java/com/android/internal/app/AbstractMultiProfilePagerAdapter.java
@@ -387,9 +387,6 @@ public abstract class AbstractMultiProfilePagerAdapter extends PagerAdapter {
resetViewVisibilitiesForWorkProfileEmptyState(emptyStateView);
emptyStateView.setVisibility(View.VISIBLE);
- ImageView icon = emptyStateView.findViewById(R.id.resolver_empty_state_icon);
- icon.setImageResource(iconRes);
-
TextView title = emptyStateView.findViewById(R.id.resolver_empty_state_title);
title.setText(titleRes);
@@ -401,9 +398,17 @@ public abstract class AbstractMultiProfilePagerAdapter extends PagerAdapter {
subtitle.setVisibility(View.GONE);
}
+ ImageView icon = emptyStateView.findViewById(R.id.resolver_empty_state_icon);
Button button = emptyStateView.findViewById(R.id.resolver_empty_state_button);
- button.setVisibility(buttonOnClick != null ? View.VISIBLE : View.GONE);
- button.setOnClickListener(buttonOnClick);
+ if (!getContext().getResources().getBoolean(R.bool.resolver_landscape_phone)) {
+ icon.setVisibility(View.VISIBLE);
+ icon.setImageResource(iconRes);
+ button.setVisibility(buttonOnClick != null ? View.VISIBLE : View.GONE);
+ button.setOnClickListener(buttonOnClick);
+ } else {
+ icon.setVisibility(View.GONE);
+ button.setVisibility(View.GONE);
+ }
activeListAdapter.markTabLoaded();
}
diff --git a/core/java/com/android/internal/app/AccessibilityButtonChooserActivity.java b/core/java/com/android/internal/app/AccessibilityButtonChooserActivity.java
index c40864131a2e..51b13345a6c3 100644
--- a/core/java/com/android/internal/app/AccessibilityButtonChooserActivity.java
+++ b/core/java/com/android/internal/app/AccessibilityButtonChooserActivity.java
@@ -169,13 +169,41 @@ public class AccessibilityButtonChooserActivity extends Activity {
private static List<AccessibilityButtonTarget> getInstalledServiceTargets(
@NonNull Context context) {
final List<AccessibilityButtonTarget> targets = new ArrayList<>();
- targets.addAll(getAccessibilityServiceTargets(context));
- targets.addAll(getAccessibilityActivityTargets(context));
+ targets.addAll(getAccessibilityFilteredTargets(context));
targets.addAll(getWhiteListingServiceTargets(context));
return targets;
}
+ private static List<AccessibilityButtonTarget> getAccessibilityFilteredTargets(
+ @NonNull Context context) {
+ final List<AccessibilityButtonTarget> serviceTargets =
+ getAccessibilityServiceTargets(context);
+ final List<AccessibilityButtonTarget> activityTargets =
+ getAccessibilityActivityTargets(context);
+
+ for (AccessibilityButtonTarget activityTarget : activityTargets) {
+ serviceTargets.removeIf(serviceTarget -> {
+ final ComponentName serviceComponentName =
+ ComponentName.unflattenFromString(serviceTarget.getId());
+ final ComponentName activityComponentName =
+ ComponentName.unflattenFromString(activityTarget.getId());
+ final boolean isSamePackageName = activityComponentName.getPackageName().equals(
+ serviceComponentName.getPackageName());
+ final boolean isSameLabel = activityTarget.getLabel().equals(
+ serviceTarget.getLabel());
+
+ return isSamePackageName && isSameLabel;
+ });
+ }
+
+ final List<AccessibilityButtonTarget> targets = new ArrayList<>();
+ targets.addAll(serviceTargets);
+ targets.addAll(activityTargets);
+
+ return targets;
+ }
+
private static List<AccessibilityButtonTarget> getAccessibilityServiceTargets(
@NonNull Context context) {
final AccessibilityManager ams = context.getSystemService(AccessibilityManager.class);
diff --git a/core/java/com/android/internal/app/ChooserActivity.java b/core/java/com/android/internal/app/ChooserActivity.java
index a1a434d3bc64..dca682e4ee29 100644
--- a/core/java/com/android/internal/app/ChooserActivity.java
+++ b/core/java/com/android/internal/app/ChooserActivity.java
@@ -2674,7 +2674,7 @@ public class ChooserActivity extends ResolverActivity implements
*/
private boolean shouldShowStickyContentPreview() {
return shouldShowStickyContentPreviewNoOrientationCheck()
- && getResources().getBoolean(R.bool.sharesheet_show_content_preview);
+ && !getResources().getBoolean(R.bool.resolver_landscape_phone);
}
private boolean shouldShowStickyContentPreviewNoOrientationCheck() {
diff --git a/core/java/com/android/internal/os/Zygote.java b/core/java/com/android/internal/os/Zygote.java
index ff03f1a1a2ab..c75898994f3e 100644
--- a/core/java/com/android/internal/os/Zygote.java
+++ b/core/java/com/android/internal/os/Zygote.java
@@ -205,9 +205,15 @@ public final class Zygote {
/** List of packages with the same uid, and its app data info: volume uuid and inode. */
public static final String PKG_DATA_INFO_MAP = "--pkg-data-info-map";
+ /** List of whitelisted packages and its app data info: volume uuid and inode. */
+ public static final String WHITELISTED_DATA_INFO_MAP = "--whitelisted-data-info-map";
+
/** Bind mount app storage dirs to lower fs not via fuse */
public static final String BIND_MOUNT_APP_STORAGE_DIRS = "--bind-mount-storage-dirs";
+ /** Bind mount app storage dirs to lower fs not via fuse */
+ public static final String BIND_MOUNT_APP_DATA_DIRS = "--bind-mount-data-dirs";
+
/**
* An extraArg passed when a zygote process is forking a child-zygote, specifying a name
* in the abstract socket namespace. This socket name is what the new child zygote
@@ -313,6 +319,8 @@ public final class Zygote {
* @param isTopApp true if the process is for top (high priority) application.
* @param pkgDataInfoList A list that stores related packages and its app data
* info: volume uuid and inode.
+ * @param whitelistedDataInfoList Like pkgDataInfoList, but it's for whitelisted apps.
+ * @param bindMountAppDataDirs True if the zygote needs to mount data dirs.
* @param bindMountAppStorageDirs True if the zygote needs to mount storage dirs.
*
* @return 0 if this is the child, pid of the child
@@ -321,13 +329,15 @@ public final class Zygote {
static int forkAndSpecialize(int uid, int gid, int[] gids, int runtimeFlags,
int[][] rlimits, int mountExternal, String seInfo, String niceName, int[] fdsToClose,
int[] fdsToIgnore, boolean startChildZygote, String instructionSet, String appDataDir,
- boolean isTopApp, String[] pkgDataInfoList, boolean bindMountAppStorageDirs) {
+ boolean isTopApp, String[] pkgDataInfoList, String[] whitelistedDataInfoList,
+ boolean bindMountAppDataDirs, boolean bindMountAppStorageDirs) {
ZygoteHooks.preFork();
int pid = nativeForkAndSpecialize(
uid, gid, gids, runtimeFlags, rlimits, mountExternal, seInfo, niceName, fdsToClose,
fdsToIgnore, startChildZygote, instructionSet, appDataDir, isTopApp,
- pkgDataInfoList, bindMountAppStorageDirs);
+ pkgDataInfoList, whitelistedDataInfoList, bindMountAppDataDirs,
+ bindMountAppStorageDirs);
if (pid == 0) {
// Note that this event ends at the end of handleChildProc,
Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER, "PostFork");
@@ -344,6 +354,7 @@ public final class Zygote {
int runtimeFlags, int[][] rlimits, int mountExternal, String seInfo, String niceName,
int[] fdsToClose, int[] fdsToIgnore, boolean startChildZygote, String instructionSet,
String appDataDir, boolean isTopApp, String[] pkgDataInfoList,
+ String[] whitelistedDataInfoList, boolean bindMountAppDataDirs,
boolean bindMountAppStorageDirs);
/**
@@ -371,15 +382,19 @@ public final class Zygote {
* volume uuid and CE dir inode. For example, pkgDataInfoList = [app_a_pkg_name,
* app_a_data_volume_uuid, app_a_ce_inode, app_b_pkg_name, app_b_data_volume_uuid,
* app_b_ce_inode, ...];
+ * @param whitelistedDataInfoList Like pkgDataInfoList, but it's for whitelisted apps.
+ * @param bindMountAppDataDirs True if the zygote needs to mount data dirs.
* @param bindMountAppStorageDirs True if the zygote needs to mount storage dirs.
*/
private static void specializeAppProcess(int uid, int gid, int[] gids, int runtimeFlags,
int[][] rlimits, int mountExternal, String seInfo, String niceName,
boolean startChildZygote, String instructionSet, String appDataDir, boolean isTopApp,
- String[] pkgDataInfoList, boolean bindMountAppStorageDirs) {
+ String[] pkgDataInfoList, String[] whitelistedDataInfoList,
+ boolean bindMountAppDataDirs, boolean bindMountAppStorageDirs) {
nativeSpecializeAppProcess(uid, gid, gids, runtimeFlags, rlimits, mountExternal, seInfo,
niceName, startChildZygote, instructionSet, appDataDir, isTopApp,
- pkgDataInfoList, bindMountAppStorageDirs);
+ pkgDataInfoList, whitelistedDataInfoList,
+ bindMountAppDataDirs, bindMountAppStorageDirs);
// Note that this event ends at the end of handleChildProc.
Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER, "PostFork");
@@ -399,7 +414,8 @@ public final class Zygote {
private static native void nativeSpecializeAppProcess(int uid, int gid, int[] gids,
int runtimeFlags, int[][] rlimits, int mountExternal, String seInfo, String niceName,
boolean startChildZygote, String instructionSet, String appDataDir, boolean isTopApp,
- String[] pkgDataInfoList, boolean bindMountAppStorageDirs);
+ String[] pkgDataInfoList, String[] whitelistedDataInfoList,
+ boolean bindMountAppDataDirs, boolean bindMountAppStorageDirs);
/**
* Called to do any initialization before starting an application.
@@ -724,7 +740,8 @@ public final class Zygote {
args.mRuntimeFlags, rlimits, args.mMountExternal,
args.mSeInfo, args.mNiceName, args.mStartChildZygote,
args.mInstructionSet, args.mAppDataDir, args.mIsTopApp,
- args.mPkgDataInfoList, args.mBindMountAppStorageDirs);
+ args.mPkgDataInfoList, args.mWhitelistedDataInfoList,
+ args.mBindMountAppDataDirs, args.mBindMountAppStorageDirs);
Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER);
diff --git a/core/java/com/android/internal/os/ZygoteArguments.java b/core/java/com/android/internal/os/ZygoteArguments.java
index 1a63765fcaa6..94c1f71a26db 100644
--- a/core/java/com/android/internal/os/ZygoteArguments.java
+++ b/core/java/com/android/internal/os/ZygoteArguments.java
@@ -227,11 +227,22 @@ class ZygoteArguments {
String[] mPkgDataInfoList;
/**
+ * A list that stores all whitelisted app data info: volume uuid and inode.
+ * Null if it does need to do app data isolation.
+ */
+ String[] mWhitelistedDataInfoList;
+
+ /**
* @see Zygote#BIND_MOUNT_APP_STORAGE_DIRS
*/
boolean mBindMountAppStorageDirs;
/**
+ * @see Zygote#BIND_MOUNT_APP_DATA_DIRS
+ */
+ boolean mBindMountAppDataDirs;
+
+ /**
* Constructs instance and parses args
*
* @param args zygote command-line args
@@ -452,8 +463,12 @@ class ZygoteArguments {
}
} else if (arg.startsWith(Zygote.PKG_DATA_INFO_MAP)) {
mPkgDataInfoList = getAssignmentList(arg);
+ } else if (arg.startsWith(Zygote.WHITELISTED_DATA_INFO_MAP)) {
+ mWhitelistedDataInfoList = getAssignmentList(arg);
} else if (arg.equals(Zygote.BIND_MOUNT_APP_STORAGE_DIRS)) {
mBindMountAppStorageDirs = true;
+ } else if (arg.equals(Zygote.BIND_MOUNT_APP_DATA_DIRS)) {
+ mBindMountAppDataDirs = true;
} else {
break;
}
diff --git a/core/java/com/android/internal/os/ZygoteConnection.java b/core/java/com/android/internal/os/ZygoteConnection.java
index bc8dfd4aa402..6e880d43b73e 100644
--- a/core/java/com/android/internal/os/ZygoteConnection.java
+++ b/core/java/com/android/internal/os/ZygoteConnection.java
@@ -258,7 +258,8 @@ class ZygoteConnection {
parsedArgs.mRuntimeFlags, rlimits, parsedArgs.mMountExternal, parsedArgs.mSeInfo,
parsedArgs.mNiceName, fdsToClose, fdsToIgnore, parsedArgs.mStartChildZygote,
parsedArgs.mInstructionSet, parsedArgs.mAppDataDir, parsedArgs.mIsTopApp,
- parsedArgs.mPkgDataInfoList, parsedArgs.mBindMountAppStorageDirs);
+ parsedArgs.mPkgDataInfoList,parsedArgs.mWhitelistedDataInfoList,
+ parsedArgs.mBindMountAppDataDirs, parsedArgs.mBindMountAppStorageDirs);
try {
if (pid == 0) {
diff --git a/core/java/com/android/internal/view/menu/MenuPopupHelper.java b/core/java/com/android/internal/view/menu/MenuPopupHelper.java
index 0aeaa47ba3d8..980943ebea5a 100644
--- a/core/java/com/android/internal/view/menu/MenuPopupHelper.java
+++ b/core/java/com/android/internal/view/menu/MenuPopupHelper.java
@@ -22,14 +22,10 @@ import android.annotation.Nullable;
import android.annotation.StyleRes;
import android.compat.annotation.UnsupportedAppUsage;
import android.content.Context;
-import android.graphics.Point;
import android.graphics.Rect;
-import android.util.Size;
-import android.view.Display;
import android.view.Gravity;
import android.view.View;
import android.view.WindowManager;
-import android.view.WindowMetrics;
import android.widget.PopupWindow.OnDismissListener;
import com.android.internal.view.menu.MenuPresenter.Callback;
@@ -227,9 +223,9 @@ public class MenuPopupHelper implements MenuHelper {
@NonNull
private MenuPopup createPopup() {
final WindowManager windowManager = mContext.getSystemService(WindowManager.class);
- final Size maxWindowSize = windowManager.getMaximumWindowMetrics().getSize();
+ final Rect maxWindowBounds = windowManager.getMaximumWindowMetrics().getBounds();
- final int smallestWidth = Math.min(maxWindowSize.getWidth(), maxWindowSize.getHeight());
+ final int smallestWidth = Math.min(maxWindowBounds.width(), maxWindowBounds.height());
final int minSmallestWidthCascading = mContext.getResources().getDimensionPixelSize(
com.android.internal.R.dimen.cascading_menus_min_smallest_width);
final boolean enableCascadingSubmenus = smallestWidth >= minSmallestWidthCascading;
diff --git a/core/jni/android_media_AudioProductStrategies.cpp b/core/jni/android_media_AudioProductStrategies.cpp
index 17a02b24c697..34be2a52344d 100644
--- a/core/jni/android_media_AudioProductStrategies.cpp
+++ b/core/jni/android_media_AudioProductStrategies.cpp
@@ -85,10 +85,23 @@ static jint convertAudioProductStrategiesFromNative(
jStrategyId = static_cast<jint>(strategy.getId());
// Audio Attributes Group array
- std::map<int, std::vector<AudioAttributes> > groups;
+ int attrGroupIndex = 0;
+ std::map<int /**attributesGroupIndex*/, std::vector<AudioAttributes> > groups;
for (const auto &attr : strategy.getAudioAttributes()) {
- int attrGroupId = attr.getGroupId();
- groups[attrGroupId].push_back(attr);
+ int groupId = attr.getGroupId();
+ int streamType = attr.getStreamType();
+ const auto &iter = std::find_if(begin(groups), end(groups),
+ [groupId, streamType](const auto &iter) {
+ const auto &frontAttr = iter.second.front();
+ return frontAttr.getGroupId() == groupId && frontAttr.getStreamType() == streamType;
+ });
+ // Same Volume Group Id and same stream type
+ if (iter != end(groups)) {
+ groups[iter->first].push_back(attr);
+ } else {
+ // Add a new Group of AudioAttributes for this product strategy
+ groups[attrGroupIndex++].push_back(attr);
+ }
}
numAttributesGroups = groups.size();
@@ -97,7 +110,7 @@ static jint convertAudioProductStrategiesFromNative(
for (const auto &iter : groups) {
std::vector<AudioAttributes> audioAttributesGroups = iter.second;
jint numAttributes = audioAttributesGroups.size();
- jint jGroupId = iter.first;
+ jint jGroupId = audioAttributesGroups.front().getGroupId();
jint jLegacyStreamType = audioAttributesGroups.front().getStreamType();
jStatus = JNIAudioAttributeHelper::getJavaArray(env, &jAudioAttributes, numAttributes);
diff --git a/core/jni/com_android_internal_os_Zygote.cpp b/core/jni/com_android_internal_os_Zygote.cpp
index ea3c0fa9fc3c..aa2d1b5fa02b 100644
--- a/core/jni/com_android_internal_os_Zygote.cpp
+++ b/core/jni/com_android_internal_os_Zygote.cpp
@@ -110,7 +110,6 @@ using android::base::StringAppendF;
using android::base::StringPrintf;
using android::base::WriteStringToFile;
using android::base::GetBoolProperty;
-using android::base::GetProperty;
#define CREATE_ERROR(...) StringPrintf("%s:%d: ", __FILE__, __LINE__). \
append(StringPrintf(__VA_ARGS__))
@@ -170,18 +169,6 @@ static int gSystemServerSocketFd = -1;
static constexpr int DEFAULT_DATA_DIR_PERMISSION = 0751;
-/**
- * Property to control if app data isolation is enabled.
- */
-static const std::string ANDROID_APP_DATA_ISOLATION_ENABLED_PROPERTY =
- "persist.zygote.app_data_isolation";
-
-/**
- * Property to enable app data isolation for sdcard obb or data in vold.
- */
-static const std::string ANDROID_VOLD_APP_DATA_ISOLATION_ENABLED_PROPERTY =
- "persist.sys.vold_app_data_isolation_enabled";
-
static constexpr const uint64_t UPPER_HALF_WORD_MASK = 0xFFFF'FFFF'0000'0000;
static constexpr const uint64_t LOWER_HALF_WORD_MASK = 0x0000'0000'FFFF'FFFF;
@@ -1319,20 +1306,13 @@ static void relabelAllDirs(const char* path, security_context_t context, fail_fn
* be decrypted after storage is decrypted.
*
*/
-static void isolateAppData(JNIEnv* env, jobjectArray pkg_data_info_list,
- uid_t uid, const char* process_name, jstring managed_nice_name,
- fail_fn_t fail_fn) {
+static void isolateAppData(JNIEnv* env, const std::vector<std::string>& merged_data_info_list,
+ uid_t uid, const char* process_name,
+ jstring managed_nice_name, fail_fn_t fail_fn) {
const userid_t userId = multiuser_get_user_id(uid);
- auto extract_fn = std::bind(ExtractJString, env, process_name, managed_nice_name, _1);
-
- int size = (pkg_data_info_list != nullptr) ? env->GetArrayLength(pkg_data_info_list) : 0;
- // Size should be a multiple of 3, as it contains list of <package_name, volume_uuid, inode>
- if ((size % 3) != 0) {
- fail_fn(CREATE_ERROR("Wrong pkg_inode_list size %d", size));
- }
- ensureInAppMountNamespace(fail_fn);
+ int size = merged_data_info_list.size();
// Mount tmpfs on all possible data directories, so app no longer see the original apps data.
char internalCePath[PATH_MAX];
@@ -1377,14 +1357,10 @@ static void isolateAppData(JNIEnv* env, jobjectArray pkg_data_info_list,
bool legacySymlinkCreated = false;
for (int i = 0; i < size; i += 3) {
- jstring package_str = (jstring) (env->GetObjectArrayElement(pkg_data_info_list, i));
- std::string packageName = extract_fn(package_str).value();
+ std::string const & packageName = merged_data_info_list[i];
+ std::string const & volUuid = merged_data_info_list[i + 1];
+ std::string const & inode = merged_data_info_list[i + 2];
- jstring vol_str = (jstring) (env->GetObjectArrayElement(pkg_data_info_list, i + 1));
- std::string volUuid = extract_fn(vol_str).value();
-
- jstring inode_str = (jstring) (env->GetObjectArrayElement(pkg_data_info_list, i + 2));
- std::string inode = extract_fn(inode_str).value();
std::string::size_type sz;
long long ceDataInode = std::stoll(inode, &sz);
@@ -1482,6 +1458,48 @@ static void isolateAppData(JNIEnv* env, jobjectArray pkg_data_info_list,
freecon(dataDataContext);
}
+static void insertPackagesToMergedList(JNIEnv* env,
+ std::vector<std::string>& merged_data_info_list,
+ jobjectArray data_info_list, const char* process_name,
+ jstring managed_nice_name, fail_fn_t fail_fn) {
+
+ auto extract_fn = std::bind(ExtractJString, env, process_name, managed_nice_name, _1);
+
+ int size = (data_info_list != nullptr) ? env->GetArrayLength(data_info_list) : 0;
+ // Size should be a multiple of 3, as it contains list of <package_name, volume_uuid, inode>
+ if ((size % 3) != 0) {
+ fail_fn(CREATE_ERROR("Wrong data_info_list size %d", size));
+ }
+
+ for (int i = 0; i < size; i += 3) {
+ jstring package_str = (jstring) (env->GetObjectArrayElement(data_info_list, i));
+ std::string packageName = extract_fn(package_str).value();
+ merged_data_info_list.push_back(packageName);
+
+ jstring vol_str = (jstring) (env->GetObjectArrayElement(data_info_list, i + 1));
+ std::string volUuid = extract_fn(vol_str).value();
+ merged_data_info_list.push_back(volUuid);
+
+ jstring inode_str = (jstring) (env->GetObjectArrayElement(data_info_list, i + 2));
+ std::string inode = extract_fn(inode_str).value();
+ merged_data_info_list.push_back(inode);
+ }
+}
+
+static void isolateAppData(JNIEnv* env, jobjectArray pkg_data_info_list,
+ jobjectArray whitelisted_data_info_list, uid_t uid, const char* process_name,
+ jstring managed_nice_name, fail_fn_t fail_fn) {
+
+ ensureInAppMountNamespace(fail_fn);
+ std::vector<std::string> merged_data_info_list;
+ insertPackagesToMergedList(env, merged_data_info_list, pkg_data_info_list,
+ process_name, managed_nice_name, fail_fn);
+ insertPackagesToMergedList(env, merged_data_info_list, whitelisted_data_info_list,
+ process_name, managed_nice_name, fail_fn);
+
+ isolateAppData(env, merged_data_info_list, uid, process_name, managed_nice_name, fail_fn);
+}
+
/**
* Like isolateAppData(), isolate jit profile directories, so apps don't see what
* other apps are installed by reading content inside /data/misc/profiles/cur.
@@ -1594,7 +1612,9 @@ static void SpecializeCommon(JNIEnv* env, uid_t uid, gid_t gid, jintArray gids,
jstring managed_nice_name, bool is_system_server,
bool is_child_zygote, jstring managed_instruction_set,
jstring managed_app_data_dir, bool is_top_app,
- jobjectArray pkg_data_info_list, bool mount_storage_dirs) {
+ jobjectArray pkg_data_info_list,
+ jobjectArray whitelisted_data_info_list,
+ bool mount_data_dirs, bool mount_storage_dirs) {
const char* process_name = is_system_server ? "system_server" : "zygote";
auto fail_fn = std::bind(ZygoteFailure, env, process_name, managed_nice_name, _1);
auto extract_fn = std::bind(ExtractJString, env, process_name, managed_nice_name, _1);
@@ -1628,9 +1648,9 @@ static void SpecializeCommon(JNIEnv* env, uid_t uid, gid_t gid, jintArray gids,
// give a null in same_uid_pkgs and private_volumes so they don't need app data isolation.
// Isolated process / webview / app zygote should be gated by SELinux and file permission
// so they can't even traverse CE / DE directories.
- if (pkg_data_info_list != nullptr
- && GetBoolProperty(ANDROID_APP_DATA_ISOLATION_ENABLED_PROPERTY, true)) {
- isolateAppData(env, pkg_data_info_list, uid, process_name, managed_nice_name, fail_fn);
+ if (mount_data_dirs) {
+ isolateAppData(env, pkg_data_info_list, whitelisted_data_info_list,
+ uid, process_name, managed_nice_name, fail_fn);
isolateJitProfile(env, pkg_data_info_list, uid, process_name, managed_nice_name, fail_fn);
}
if ((mount_external != MOUNT_EXTERNAL_INSTALLER) && mount_storage_dirs) {
@@ -2003,7 +2023,8 @@ static jint com_android_internal_os_Zygote_nativeForkAndSpecialize(
jint mount_external, jstring se_info, jstring nice_name,
jintArray managed_fds_to_close, jintArray managed_fds_to_ignore, jboolean is_child_zygote,
jstring instruction_set, jstring app_data_dir, jboolean is_top_app,
- jobjectArray pkg_data_info_list, jboolean mount_storage_dirs) {
+ jobjectArray pkg_data_info_list, jobjectArray whitelisted_data_info_list,
+ jboolean mount_data_dirs, jboolean mount_storage_dirs) {
jlong capabilities = CalculateCapabilities(env, uid, gid, gids, is_child_zygote);
if (UNLIKELY(managed_fds_to_close == nullptr)) {
@@ -2041,6 +2062,8 @@ static jint com_android_internal_os_Zygote_nativeForkAndSpecialize(
mount_external, se_info, nice_name, false,
is_child_zygote == JNI_TRUE, instruction_set, app_data_dir,
is_top_app == JNI_TRUE, pkg_data_info_list,
+ whitelisted_data_info_list,
+ mount_data_dirs == JNI_TRUE,
mount_storage_dirs == JNI_TRUE);
}
return pid;
@@ -2076,7 +2099,8 @@ static jint com_android_internal_os_Zygote_nativeForkSystemServer(
permitted_capabilities, effective_capabilities,
MOUNT_EXTERNAL_DEFAULT, nullptr, nullptr, true,
false, nullptr, nullptr, /* is_top_app= */ false,
- /* pkg_data_info_list */ nullptr, false);
+ /* pkg_data_info_list */ nullptr,
+ /* whitelisted_data_info_list */ nullptr, false, false);
} else if (pid > 0) {
// The zygote process checks whether the child process has died or not.
ALOGI("System server process %d has been created", pid);
@@ -2206,15 +2230,16 @@ static void com_android_internal_os_Zygote_nativeSpecializeAppProcess(
jint runtime_flags, jobjectArray rlimits,
jint mount_external, jstring se_info, jstring nice_name,
jboolean is_child_zygote, jstring instruction_set, jstring app_data_dir, jboolean is_top_app,
- jobjectArray pkg_data_info_list, jboolean mount_storage_dirs) {
+ jobjectArray pkg_data_info_list, jobjectArray whitelisted_data_info_list,
+ jboolean mount_data_dirs, jboolean mount_storage_dirs) {
jlong capabilities = CalculateCapabilities(env, uid, gid, gids, is_child_zygote);
SpecializeCommon(env, uid, gid, gids, runtime_flags, rlimits,
capabilities, capabilities,
mount_external, se_info, nice_name, false,
is_child_zygote == JNI_TRUE, instruction_set, app_data_dir,
- is_top_app == JNI_TRUE, pkg_data_info_list,
- mount_storage_dirs == JNI_TRUE);
+ is_top_app == JNI_TRUE, pkg_data_info_list, whitelisted_data_info_list,
+ mount_data_dirs == JNI_TRUE, mount_storage_dirs == JNI_TRUE);
}
/**
@@ -2408,7 +2433,7 @@ static jint com_android_internal_os_Zygote_nativeParseSigChld(JNIEnv* env, jclas
static const JNINativeMethod gMethods[] = {
{"nativeForkAndSpecialize",
"(II[II[[IILjava/lang/String;Ljava/lang/String;[I[IZLjava/lang/String;Ljava/lang/"
- "String;Z[Ljava/lang/String;Z)I",
+ "String;Z[Ljava/lang/String;[Ljava/lang/String;ZZ)I",
(void*)com_android_internal_os_Zygote_nativeForkAndSpecialize},
{"nativeForkSystemServer", "(II[II[[IJJ)I",
(void*)com_android_internal_os_Zygote_nativeForkSystemServer},
@@ -2421,7 +2446,7 @@ static const JNINativeMethod gMethods[] = {
{"nativeForkUsap", "(II[IZ)I", (void*)com_android_internal_os_Zygote_nativeForkUsap},
{"nativeSpecializeAppProcess",
"(II[II[[IILjava/lang/String;Ljava/lang/String;ZLjava/lang/String;Ljava/lang/"
- "String;Z[Ljava/lang/String;Z)V",
+ "String;Z[Ljava/lang/String;[Ljava/lang/String;ZZ)V",
(void*)com_android_internal_os_Zygote_nativeSpecializeAppProcess},
{"nativeInitNativeState", "(Z)V",
(void*)com_android_internal_os_Zygote_nativeInitNativeState},
diff --git a/core/proto/android/app/enums.proto b/core/proto/android/app/enums.proto
index 42437d5b44a0..563ef145b79c 100644
--- a/core/proto/android/app/enums.proto
+++ b/core/proto/android/app/enums.proto
@@ -203,9 +203,7 @@ enum AppOpEnum {
APP_OP_INTERACT_ACROSS_PROFILES = 93;
APP_OP_ACTIVATE_PLATFORM_VPN = 94;
APP_OP_LOADER_USAGE_STATS = 95;
- APP_OP_ACCESS_CALL_AUDIO = 96;
+ APP_OP_DEPRECATED_1 = 96 [deprecated = true];
APP_OP_AUTO_REVOKE_PERMISSIONS_IF_UNUSED = 97;
APP_OP_AUTO_REVOKE_MANAGED_BY_INSTALLER = 98;
}
-
-
diff --git a/core/res/AndroidManifest.xml b/core/res/AndroidManifest.xml
index 84d9ce288069..eae614546dfb 100644
--- a/core/res/AndroidManifest.xml
+++ b/core/res/AndroidManifest.xml
@@ -1213,15 +1213,6 @@
android:description="@string/permdesc_acceptHandovers"
android:protectionLevel="dangerous" />
- <!-- Allows an application assigned to the Dialer role to be granted access to the telephony
- call audio streams, both TX and RX.
- <p>Protection level: signature|appop
- -->
- <permission android:name="android.permission.ACCESS_CALL_AUDIO"
- android.label="@string/permlab_accessCallAudio"
- android:description="@string/permdesc_accessCallAudio"
- android:protectionLevel="signature|appop" />
-
<!-- ====================================================================== -->
<!-- Permissions for accessing the device microphone -->
<!-- ====================================================================== -->
@@ -3654,6 +3645,16 @@
<permission android:name="com.android.permission.INSTALL_EXISTING_PACKAGES"
android:protectionLevel="signature|privileged" />
+ <!-- Allows an application to use the package installer v2 APIs.
+ <p>The package installer v2 APIs are still a work in progress and we're
+ currently validating they work in all scenarios.
+ <p>Not for use by third-party applications.
+ TODO(b/152310230): remove this permission once the APIs are confirmed to be sufficient.
+ @hide
+ -->
+ <permission android:name="com.android.permission.USE_INSTALLER_V2"
+ android:protectionLevel="signature|verifier" />
+
<!-- @SystemApi @TestApi Allows an application to clear user data.
<p>Not for use by third-party applications
@hide
diff --git a/core/res/res/layout/resolver_empty_states.xml b/core/res/res/layout/resolver_empty_states.xml
index 210feaf092a7..c7e1a21aa642 100644
--- a/core/res/res/layout/resolver_empty_states.xml
+++ b/core/res/res/layout/resolver_empty_states.xml
@@ -22,11 +22,11 @@
android:orientation="vertical"
android:gravity="center_horizontal"
android:visibility="gone"
+ android:paddingTop="48dp"
android:paddingStart="24dp"
android:paddingEnd="24dp">
<ImageView
android:id="@+id/resolver_empty_state_icon"
- android:layout_marginTop="48dp"
android:layout_width="24dp"
android:layout_height="24dp"
android:layout_centerHorizontal="true" />
diff --git a/core/res/res/values-h480dp/bools.xml b/core/res/res/values-h480dp/bools.xml
index 65e3ae6e71ec..7896d9bfe2b1 100644
--- a/core/res/res/values-h480dp/bools.xml
+++ b/core/res/res/values-h480dp/bools.xml
@@ -16,5 +16,5 @@
-->
<resources>
- <bool name="sharesheet_show_content_preview">true</bool>
+ <bool name="resolver_landscape_phone">false</bool>
</resources> \ No newline at end of file
diff --git a/core/res/res/values/attrs_manifest.xml b/core/res/res/values/attrs_manifest.xml
index 28eb98b07690..2a41542d38e4 100644
--- a/core/res/res/values/attrs_manifest.xml
+++ b/core/res/res/values/attrs_manifest.xml
@@ -1827,6 +1827,9 @@
<attr name="gwpAsanMode" />
+ <!-- @hide no longer used, kept to preserve padding -->
+ <attr name="allowAutoRevokePermissionsExemption" format="boolean" />
+
<attr name="autoRevokePermissions">
<enum name="allowed" value="0" />
<enum name="discouraged" value="1" />
diff --git a/core/res/res/values/bools.xml b/core/res/res/values/bools.xml
index c5127dccdae7..fe296c704095 100644
--- a/core/res/res/values/bools.xml
+++ b/core/res/res/values/bools.xml
@@ -29,5 +29,5 @@
<p>The main purpose is for OEMs to customize the rendering of the
lockscreen, setting this to true should come with customized drawables. -->
<bool name="use_lock_pattern_drawable">false</bool>
- <bool name="sharesheet_show_content_preview">false</bool>
+ <bool name="resolver_landscape_phone">true</bool>
</resources>
diff --git a/core/res/res/values/public.xml b/core/res/res/values/public.xml
index e694e160009e..738688b36257 100644
--- a/core/res/res/values/public.xml
+++ b/core/res/res/values/public.xml
@@ -3014,6 +3014,8 @@
<!-- @hide @SystemApi -->
<public name="minExtensionVersion" />
<public name="allowNativeHeapPointerTagging" />
+ <!-- @hide no longer used, kept to preserve padding -->
+ <public name="allowAutoRevokePermissionsExemption"/>
<public name="autoRevokePermissions" />
<public name="preserveLegacyExternalStorage" />
<public name="mimeGroup" />
diff --git a/core/res/res/values/strings.xml b/core/res/res/values/strings.xml
index 06f776013233..5b880365657c 100644
--- a/core/res/res/values/strings.xml
+++ b/core/res/res/values/strings.xml
@@ -5482,11 +5482,6 @@
<!-- Error message. This text lets the user know that their current personal apps can't open this specific content. [CHAR LIMIT=NONE] -->
<string name="resolver_no_personal_apps_available_resolve">No personal apps can open this content</string>
- <!-- Title of an application permission, listed so the user can choose whether they want to allow the application to do this. [CHAR LIMIT=NONE] -->
- <string name="permlab_accessCallAudio">Record or play audio in telephony calls</string>
- <!-- Description of an application permission, listed so the user can choose whether they want to allow the application to do this. [CHAR LIMIT=NONE] -->
- <string name="permdesc_accessCallAudio">Allows this app, when assigned as default dialer application, to record or play audio in telephony calls.</string>
-
<!-- Icc depersonalization related strings -->
<!-- Label text for PIN entry widget on SIM Network Depersonalization panel [CHAR LIMIT=none] -->
<string name="PERSOSUBSTATE_SIM_NETWORK_ENTRY">SIM network unlock PIN</string>
diff --git a/core/res/res/values/symbols.xml b/core/res/res/values/symbols.xml
index 0adef7513bb5..22caf4c2a37d 100644
--- a/core/res/res/values/symbols.xml
+++ b/core/res/res/values/symbols.xml
@@ -3929,7 +3929,7 @@
<java-symbol type="dimen" name="resolver_empty_state_height" />
<java-symbol type="dimen" name="resolver_empty_state_height_with_tabs" />
<java-symbol type="dimen" name="resolver_max_collapsed_height_with_tabs" />
- <java-symbol type="bool" name="sharesheet_show_content_preview" />
+ <java-symbol type="bool" name="resolver_landscape_phone" />
<java-symbol type="dimen" name="resolver_tab_text_size" />
<!-- Toast message for background started foreground service while-in-use permission restriction feature -->
diff --git a/core/tests/coretests/BstatsTestApp/src/com/android/coretests/apps/bstatstestapp/TestService.java b/core/tests/coretests/BstatsTestApp/src/com/android/coretests/apps/bstatstestapp/TestService.java
index 79b803a0cda6..0cd0643ee8c0 100644
--- a/core/tests/coretests/BstatsTestApp/src/com/android/coretests/apps/bstatstestapp/TestService.java
+++ b/core/tests/coretests/BstatsTestApp/src/com/android/coretests/apps/bstatstestapp/TestService.java
@@ -25,13 +25,13 @@ import android.app.Service;
import android.content.Context;
import android.content.Intent;
import android.graphics.Color;
+import android.graphics.Rect;
import android.hardware.display.DisplayManager;
import android.os.Handler;
import android.os.IBinder;
import android.os.Process;
import android.os.RemoteException;
import android.util.Log;
-import android.util.Size;
import android.view.Display;
import android.view.Gravity;
import android.view.View;
@@ -119,15 +119,15 @@ public class TestService extends Service {
@Override
public void showApplicationOverlay() throws RemoteException {
final WindowManager wm = mOverlayContext.getSystemService(WindowManager.class);
- final Size size = wm.getCurrentWindowMetrics().getSize();
+ final Rect bounds = wm.getCurrentWindowMetrics().getBounds();
final WindowManager.LayoutParams wmlp = new WindowManager.LayoutParams(
TYPE_APPLICATION_OVERLAY,
WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE
| WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON
| WindowManager.LayoutParams.FLAG_NOT_TOUCHABLE);
- wmlp.width = size.getWidth() / 2;
- wmlp.height = size.getHeight() / 2;
+ wmlp.width = bounds.width() / 2;
+ wmlp.height = bounds.height() / 2;
wmlp.gravity = Gravity.CENTER | Gravity.LEFT;
wmlp.setTitle(TAG);
diff --git a/core/tests/coretests/src/android/content/ContentResolverTest.java b/core/tests/coretests/src/android/content/ContentResolverTest.java
index 57e5dd8f8f20..f48e66681cc7 100644
--- a/core/tests/coretests/src/android/content/ContentResolverTest.java
+++ b/core/tests/coretests/src/android/content/ContentResolverTest.java
@@ -238,12 +238,9 @@ public class ContentResolverTest {
@Test
public void testGetType_providerException() {
- try {
- mResolver.getType(Uri.parse("content://android.content.FakeProviderRemote/error"));
- fail("Expected IllegalArgumentException");
- } catch (IllegalArgumentException e) {
- // Expected
- }
+ String type =
+ mResolver.getType(Uri.parse("content://android.content.FakeProviderRemote/error"));
+ assertThat(type).isNull();
}
@Test
@@ -253,4 +250,15 @@ public class ContentResolverTest {
assertThat(canonical).isEqualTo(
Uri.parse("content://android.content.FakeProviderRemote/canonical"));
}
+
+ @Test
+ public void testCanonicalize_providerException() {
+ try {
+ mResolver.canonicalize(
+ Uri.parse("content://android.content.FakeProviderRemote/error"));
+ fail("Expected IllegalArgumentException");
+ } catch (IllegalArgumentException e) {
+ // Expected
+ }
+ }
}
diff --git a/core/tests/coretests/src/android/content/FakeProviderRemote.java b/core/tests/coretests/src/android/content/FakeProviderRemote.java
index a32009493094..8bc56607f555 100644
--- a/core/tests/coretests/src/android/content/FakeProviderRemote.java
+++ b/core/tests/coretests/src/android/content/FakeProviderRemote.java
@@ -60,6 +60,9 @@ public class FakeProviderRemote extends ContentProvider {
@Override
public Uri canonicalize(Uri uri) {
+ if (uri.getPath() != null && uri.getPath().contains("error")) {
+ throw new IllegalArgumentException("Expected exception");
+ }
return new Uri.Builder().scheme(uri.getScheme()).authority(uri.getAuthority())
.appendPath("canonical").build();
}
diff --git a/core/tests/coretests/src/android/content/res/ResourcesManagerTest.java b/core/tests/coretests/src/android/content/res/ResourcesManagerTest.java
index df5c9d2df90b..4114b28a7252 100644
--- a/core/tests/coretests/src/android/content/res/ResourcesManagerTest.java
+++ b/core/tests/coretests/src/android/content/res/ResourcesManagerTest.java
@@ -184,7 +184,7 @@ public class ResourcesManagerTest extends TestCase {
@SmallTest
public void testThemesGetUpdatedWithNewImpl() {
Binder activity1 = new Binder();
- Resources resources1 = mResourcesManager.createBaseActivityResources(
+ Resources resources1 = mResourcesManager.createBaseTokenResources(
activity1, APP_ONE_RES_DIR, null, null, null, Display.DEFAULT_DISPLAY, null,
CompatibilityInfo.DEFAULT_COMPATIBILITY_INFO, null, null);
assertNotNull(resources1);
@@ -217,7 +217,7 @@ public class ResourcesManagerTest extends TestCase {
// Create a Resources for the Activity.
Configuration config1 = new Configuration();
config1.densityDpi = 280;
- Resources resources1 = mResourcesManager.createBaseActivityResources(
+ Resources resources1 = mResourcesManager.createBaseTokenResources(
activity1, APP_ONE_RES_DIR, null, null, null, Display.DEFAULT_DISPLAY, config1,
CompatibilityInfo.DEFAULT_COMPATIBILITY_INFO, null, null);
assertNotNull(resources1);
diff --git a/core/tests/coretests/src/android/util/GridScenario.java b/core/tests/coretests/src/android/util/GridScenario.java
index 4809a213ab48..e7ee1cd59c7c 100644
--- a/core/tests/coretests/src/android/util/GridScenario.java
+++ b/core/tests/coretests/src/android/util/GridScenario.java
@@ -233,7 +233,7 @@ public abstract class GridScenario extends Activity {
// turn off title bar
requestWindowFeature(Window.FEATURE_NO_TITLE);
- mScreenHeight = getWindowManager().getCurrentWindowMetrics().getSize().getHeight();
+ mScreenHeight = getWindowManager().getCurrentWindowMetrics().getBounds().height();
final Params params = new Params();
init(params);
diff --git a/core/tests/coretests/src/android/util/ListScenario.java b/core/tests/coretests/src/android/util/ListScenario.java
index d4e5a438d855..74dc4b4b34a1 100644
--- a/core/tests/coretests/src/android/util/ListScenario.java
+++ b/core/tests/coretests/src/android/util/ListScenario.java
@@ -306,7 +306,7 @@ public abstract class ListScenario extends Activity {
requestWindowFeature(Window.FEATURE_NO_TITLE);
- mScreenHeight = getWindowManager().getCurrentWindowMetrics().getSize().getHeight();
+ mScreenHeight = getWindowManager().getCurrentWindowMetrics().getBounds().height();
final Params params = createParams();
init(params);
diff --git a/core/tests/coretests/src/android/util/ScrollViewScenario.java b/core/tests/coretests/src/android/util/ScrollViewScenario.java
index 2c0aa7362dfa..ab1a642a9327 100644
--- a/core/tests/coretests/src/android/util/ScrollViewScenario.java
+++ b/core/tests/coretests/src/android/util/ScrollViewScenario.java
@@ -239,7 +239,7 @@ public abstract class ScrollViewScenario extends Activity {
// for test stability, turn off title bar
requestWindowFeature(Window.FEATURE_NO_TITLE);
- int screenHeight = getWindowManager().getCurrentWindowMetrics().getSize().getHeight()
+ int screenHeight = getWindowManager().getCurrentWindowMetrics().getBounds().height()
- 25;
mLinearLayout = new LinearLayout(this);
mLinearLayout.setOrientation(LinearLayout.VERTICAL);
diff --git a/core/tests/coretests/src/android/view/BigCache.java b/core/tests/coretests/src/android/view/BigCache.java
index e465a859218a..3038e79abd72 100644
--- a/core/tests/coretests/src/android/view/BigCache.java
+++ b/core/tests/coretests/src/android/view/BigCache.java
@@ -17,8 +17,8 @@
package android.view;
import android.app.Activity;
+import android.graphics.Rect;
import android.os.Bundle;
-import android.util.Size;
import android.widget.LinearLayout;
import android.widget.ScrollView;
@@ -39,9 +39,9 @@ public class BigCache extends Activity {
ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.WRAP_CONTENT));
final int cacheSize = ViewConfiguration.getMaximumDrawingCacheSize();
- final Size windowSize = getWindowManager().getCurrentWindowMetrics().getSize();
- final int screenWidth = windowSize.getWidth();
- final int screenHeight = windowSize.getHeight();
+ final Rect windowBounds = getWindowManager().getCurrentWindowMetrics().getBounds();
+ final int screenWidth = windowBounds.width();
+ final int screenHeight = windowBounds.height();
final View tiny = new View(this);
tiny.setId(R.id.a);
diff --git a/core/tests/coretests/src/android/view/ScaleGestureDetectorTest.java b/core/tests/coretests/src/android/view/ScaleGestureDetectorTest.java
index 039387c85b11..46e55faae8b6 100644
--- a/core/tests/coretests/src/android/view/ScaleGestureDetectorTest.java
+++ b/core/tests/coretests/src/android/view/ScaleGestureDetectorTest.java
@@ -22,7 +22,7 @@ import static androidx.test.espresso.matcher.ViewMatchers.withId;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertTrue;
-import android.util.Size;
+import android.graphics.Rect;
import android.widget.TextView;
import androidx.test.filters.LargeTest;
@@ -55,9 +55,9 @@ public class ScaleGestureDetectorTest {
// Specify start and end coordinates with respect to the window size.
final WindowManager wm = mScaleGestureActivity.getSystemService(WindowManager.class);
- final Size windowSize = wm.getCurrentWindowMetrics().getSize();
- final int windowWidth = windowSize.getWidth();
- final int windowHeight = windowSize.getHeight();
+ final Rect windowBounds = wm.getCurrentWindowMetrics().getBounds();
+ final int windowWidth = windowBounds.width();
+ final int windowHeight = windowBounds.height();
// Obtain coordinates to perform pinch and zoom from the center, to 75% of the display.
final int centerX = windowWidth / 2;
diff --git a/core/tests/coretests/src/android/view/WindowMetricsTest.java b/core/tests/coretests/src/android/view/WindowMetricsTest.java
index fa6886075bfd..74524bf6d76f 100644
--- a/core/tests/coretests/src/android/view/WindowMetricsTest.java
+++ b/core/tests/coretests/src/android/view/WindowMetricsTest.java
@@ -22,10 +22,10 @@ import static android.view.WindowManager.LayoutParams.TYPE_APPLICATION_OVERLAY;
import static org.junit.Assert.assertTrue;
import android.content.Context;
+import android.graphics.Rect;
import android.hardware.display.DisplayManager;
import android.os.Handler;
import android.platform.test.annotations.Presubmit;
-import android.util.Size;
import androidx.test.filters.FlakyTest;
import androidx.test.filters.SmallTest;
@@ -87,10 +87,12 @@ public class WindowMetricsTest {
private static void verifyMetricsSanity(WindowMetrics currentMetrics,
WindowMetrics maxMetrics) {
- Size currentSize = currentMetrics.getSize();
- Size maxSize = maxMetrics.getSize();
+ Rect currentBounds = currentMetrics.getBounds();
+ Rect maxBounds = maxMetrics.getBounds();
- assertTrue(maxSize.getWidth() >= currentSize.getWidth());
- assertTrue(maxSize.getHeight() >= currentSize.getHeight());
+ assertTrue(maxBounds.width() >= currentBounds.width());
+ assertTrue(maxBounds.height() >= currentBounds.height());
+ assertTrue(maxBounds.left >= 0);
+ assertTrue(maxBounds.top >= 0);
}
}
diff --git a/core/tests/coretests/src/android/view/menu/ContextMenuTest.java b/core/tests/coretests/src/android/view/menu/ContextMenuTest.java
index d5825e20163c..4bd9ccd8d4d3 100644
--- a/core/tests/coretests/src/android/view/menu/ContextMenuTest.java
+++ b/core/tests/coretests/src/android/view/menu/ContextMenuTest.java
@@ -16,9 +16,9 @@
package android.view.menu;
+import android.graphics.Rect;
import android.test.ActivityInstrumentationTestCase;
import android.util.PollingCheck;
-import android.util.Size;
import android.view.View;
import android.view.WindowManager;
import android.widget.espresso.ContextMenuUtils;
@@ -81,8 +81,8 @@ public class ContextMenuTest extends ActivityInstrumentationTestCase<ContextMenu
*/
private int getMinScreenDimension() {
final WindowManager windowManager = getActivity().getSystemService(WindowManager.class);
- final Size maxWindowSize = windowManager.getMaximumWindowMetrics().getSize();
- return Math.min(maxWindowSize.getWidth(), maxWindowSize.getHeight());
+ final Rect maxWindowBounds = windowManager.getMaximumWindowMetrics().getBounds();
+ return Math.min(maxWindowBounds.width(), maxWindowBounds.height());
}
/**
diff --git a/core/tests/coretests/src/android/widget/EditorCursorDragTest.java b/core/tests/coretests/src/android/widget/EditorCursorDragTest.java
index 1b5ce8fd4ce5..9a93dbf67d33 100644
--- a/core/tests/coretests/src/android/widget/EditorCursorDragTest.java
+++ b/core/tests/coretests/src/android/widget/EditorCursorDragTest.java
@@ -37,6 +37,7 @@ import static org.junit.Assert.assertTrue;
import android.app.Activity;
import android.app.Instrumentation;
import android.graphics.Rect;
+import android.platform.test.annotations.Presubmit;
import android.text.Layout;
import android.text.Spannable;
import android.text.SpannableString;
@@ -48,7 +49,7 @@ import android.view.MotionEvent;
import android.view.View;
import androidx.test.InstrumentationRegistry;
-import androidx.test.filters.SmallTest;
+import androidx.test.filters.MediumTest;
import androidx.test.filters.Suppress;
import androidx.test.rule.ActivityTestRule;
import androidx.test.runner.AndroidJUnit4;
@@ -67,7 +68,8 @@ import java.util.Set;
import java.util.concurrent.atomic.AtomicLong;
@RunWith(AndroidJUnit4.class)
-@SmallTest
+@MediumTest
+@Presubmit
public class EditorCursorDragTest {
private static final String LOG_TAG = EditorCursorDragTest.class.getSimpleName();
diff --git a/core/tests/coretests/src/android/widget/EditorTouchStateTest.java b/core/tests/coretests/src/android/widget/EditorTouchStateTest.java
index 3dc001d68a02..ec75e40f1334 100644
--- a/core/tests/coretests/src/android/widget/EditorTouchStateTest.java
+++ b/core/tests/coretests/src/android/widget/EditorTouchStateTest.java
@@ -22,6 +22,7 @@ import static junit.framework.Assert.assertTrue;
import static org.hamcrest.MatcherAssert.assertThat;
import static org.hamcrest.Matchers.is;
+import android.platform.test.annotations.Presubmit;
import android.view.InputDevice;
import android.view.MotionEvent;
import android.view.ViewConfiguration;
@@ -36,6 +37,7 @@ import org.junit.runners.JUnit4;
@RunWith(JUnit4.class)
@SmallTest
+@Presubmit
public class EditorTouchStateTest {
private EditorTouchState mTouchState;
diff --git a/core/tests/coretests/src/android/widget/focus/ListOfInternalSelectionViews.java b/core/tests/coretests/src/android/widget/focus/ListOfInternalSelectionViews.java
index 8e90a824c873..d51cc328e4fb 100644
--- a/core/tests/coretests/src/android/widget/focus/ListOfInternalSelectionViews.java
+++ b/core/tests/coretests/src/android/widget/focus/ListOfInternalSelectionViews.java
@@ -111,7 +111,7 @@ public class ListOfInternalSelectionViews extends Activity {
protected void onCreate(Bundle icicle) {
super.onCreate(icicle);
- mScreenHeight = getWindowManager().getCurrentWindowMetrics().getSize().getHeight();
+ mScreenHeight = getWindowManager().getCurrentWindowMetrics().getBounds().height();
Bundle extras = getIntent().getExtras();
if (extras != null) {
diff --git a/core/tests/coretests/src/android/widget/gridview/touch/GridTouchVerticalSpacingStackFromBottomTest.java b/core/tests/coretests/src/android/widget/gridview/touch/GridTouchVerticalSpacingStackFromBottomTest.java
index fd1dbfc63708..5cedd13533e7 100644
--- a/core/tests/coretests/src/android/widget/gridview/touch/GridTouchVerticalSpacingStackFromBottomTest.java
+++ b/core/tests/coretests/src/android/widget/gridview/touch/GridTouchVerticalSpacingStackFromBottomTest.java
@@ -106,8 +106,8 @@ public class GridTouchVerticalSpacingStackFromBottomTest extends ActivityInstrum
int firstTop = firstChild.getTop();
- int windowHeight = mActivity.getWindowManager().getCurrentWindowMetrics().getSize()
- .getHeight();
+ int windowHeight = mActivity.getWindowManager().getCurrentWindowMetrics().getBounds()
+ .height();
int distance = TouchUtils.dragViewBy(this, firstChild,
Gravity.BOTTOM | Gravity.CENTER_HORIZONTAL, 0, (int) (windowHeight * 0.75f));
diff --git a/core/tests/coretests/src/android/widget/listview/AdjacentListsWithAdjacentISVsInside.java b/core/tests/coretests/src/android/widget/listview/AdjacentListsWithAdjacentISVsInside.java
index e6195b147045..5cca766e1b1e 100644
--- a/core/tests/coretests/src/android/widget/listview/AdjacentListsWithAdjacentISVsInside.java
+++ b/core/tests/coretests/src/android/widget/listview/AdjacentListsWithAdjacentISVsInside.java
@@ -66,7 +66,7 @@ public class AdjacentListsWithAdjacentISVsInside extends Activity {
super.onCreate(savedInstanceState);
final int desiredHeight =
- (int) (0.8 * getWindowManager().getCurrentWindowMetrics().getSize().getHeight());
+ (int) (0.8 * getWindowManager().getCurrentWindowMetrics().getBounds().height());
mLeftListView = new ListView(this);
mLeftListView.setAdapter(new AdjacentISVAdapter(desiredHeight));
diff --git a/core/tests/coretests/src/com/android/internal/accessibility/AccessibilityShortcutControllerTest.java b/core/tests/coretests/src/com/android/internal/accessibility/AccessibilityShortcutControllerTest.java
index 9af0ed0ab826..4a33da680585 100644
--- a/core/tests/coretests/src/com/android/internal/accessibility/AccessibilityShortcutControllerTest.java
+++ b/core/tests/coretests/src/com/android/internal/accessibility/AccessibilityShortcutControllerTest.java
@@ -17,7 +17,6 @@
package com.android.internal.accessibility;
import static android.provider.Settings.Secure.ACCESSIBILITY_SHORTCUT_DIALOG_SHOWN;
-import static android.provider.Settings.Secure.ACCESSIBILITY_SHORTCUT_ENABLED;
import static android.provider.Settings.Secure.ACCESSIBILITY_SHORTCUT_ON_LOCK_SCREEN;
import static android.provider.Settings.Secure.ACCESSIBILITY_SHORTCUT_TARGET_SERVICE;
import static android.view.accessibility.AccessibilityManager.ACCESSIBILITY_SHORTCUT_KEY;
@@ -102,10 +101,8 @@ public class AccessibilityShortcutControllerTest {
private static final long[] VIBRATOR_PATTERN_LONG = {VIBRATOR_PATTERN_1, VIBRATOR_PATTERN_2};
// Convenience values for enabling/disabling to make code more readable
- private static final int DISABLED = 0;
private static final int ENABLED_EXCEPT_LOCK_SCREEN = 1;
private static final int ENABLED_INCLUDING_LOCK_SCREEN = 2;
- private static final int DISABLED_BUT_LOCK_SCREEN_ON = 3;
private @Mock Context mContext;
private @Mock FrameworkObjectProvider mFrameworkObjectProvider;
@@ -225,14 +222,6 @@ public class AccessibilityShortcutControllerTest {
}
@Test
- public void testShortcutAvailable_disabledWithValidServiceWhenCreated_shouldReturnFalse()
- throws Exception {
- configureValidShortcutService();
- configureShortcutEnabled(DISABLED_BUT_LOCK_SCREEN_ON);
- assertFalse(getController().isAccessibilityShortcutAvailable(false));
- }
-
- @Test
public void testShortcutAvailable_onLockScreenButDisabledThere_shouldReturnFalse()
throws Exception {
configureValidShortcutService();
@@ -285,20 +274,8 @@ public class AccessibilityShortcutControllerTest {
}
@Test
- public void testShortcutAvailable_whenShortcutBecomesDisabled_shouldReturnFalse()
- throws Exception {
- configureShortcutEnabled(ENABLED_EXCEPT_LOCK_SCREEN);
- configureValidShortcutService();
- AccessibilityShortcutController accessibilityShortcutController = getController();
- configureShortcutEnabled(DISABLED);
- accessibilityShortcutController.onSettingsChanged();
- assertFalse(accessibilityShortcutController.isAccessibilityShortcutAvailable(false));
- }
-
- @Test
public void testShortcutAvailable_whenShortcutBecomesEnabled_shouldReturnTrue()
throws Exception {
- configureShortcutEnabled(DISABLED);
configureValidShortcutService();
AccessibilityShortcutController accessibilityShortcutController = getController();
configureShortcutEnabled(ENABLED_EXCEPT_LOCK_SCREEN);
@@ -594,31 +571,19 @@ public class AccessibilityShortcutControllerTest {
}
private void configureShortcutEnabled(int enabledValue) {
- final boolean enabled;
final boolean lockscreen;
switch (enabledValue) {
- case DISABLED:
- enabled = false;
- lockscreen = false;
- break;
- case DISABLED_BUT_LOCK_SCREEN_ON:
- enabled = false;
- lockscreen = true;
- break;
case ENABLED_INCLUDING_LOCK_SCREEN:
- enabled = true;
lockscreen = true;
break;
case ENABLED_EXCEPT_LOCK_SCREEN:
- enabled = true;
lockscreen = false;
break;
default:
throw new IllegalArgumentException();
}
- Settings.Secure.putInt(mContentResolver, ACCESSIBILITY_SHORTCUT_ENABLED, enabled ? 1 : 0);
Settings.Secure.putInt(
mContentResolver, ACCESSIBILITY_SHORTCUT_ON_LOCK_SCREEN, lockscreen ? 1 : 0);
}
diff --git a/media/java/android/media/AudioSystem.java b/media/java/android/media/AudioSystem.java
index 8b973a177f90..0a56accd1636 100644
--- a/media/java/android/media/AudioSystem.java
+++ b/media/java/android/media/AudioSystem.java
@@ -708,6 +708,8 @@ public class AudioSystem
DEVICE_IN_ALL_USB_SET.add(DEVICE_IN_USB_HEADSET);
}
+ public static final String LEGACY_REMOTE_SUBMIX_ADDRESS = "0";
+
// device states, must match AudioSystem::device_connection_state
@UnsupportedAppUsage
public static final int DEVICE_STATE_UNAVAILABLE = 0;
diff --git a/media/java/android/media/audiopolicy/AudioProductStrategy.java b/media/java/android/media/audiopolicy/AudioProductStrategy.java
index f9dbc50e20cf..090f78e4e4f7 100644
--- a/media/java/android/media/audiopolicy/AudioProductStrategy.java
+++ b/media/java/android/media/audiopolicy/AudioProductStrategy.java
@@ -374,8 +374,8 @@ public final class AudioProductStrategy implements Parcelable {
if (refAttr.equals(sDefaultAttributes)) {
return false;
}
- return ((refAttr.getUsage() == AudioAttributes.USAGE_UNKNOWN)
- || (attr.getUsage() == refAttr.getUsage()))
+ return ((refAttr.getSystemUsage() == AudioAttributes.USAGE_UNKNOWN)
+ || (attr.getSystemUsage() == refAttr.getSystemUsage()))
&& ((refAttr.getContentType() == AudioAttributes.CONTENT_TYPE_UNKNOWN)
|| (attr.getContentType() == refAttr.getContentType()))
&& ((refAttr.getAllFlags() == 0)
diff --git a/media/jni/android_media_tv_Tuner.cpp b/media/jni/android_media_tv_Tuner.cpp
index 29dfd730a84c..9310d38c3bd1 100644
--- a/media/jni/android_media_tv_Tuner.cpp
+++ b/media/jni/android_media_tv_Tuner.cpp
@@ -40,6 +40,7 @@ using ::android::hardware::tv::tuner::V1_0::DataFormat;
using ::android::hardware::tv::tuner::V1_0::DemuxAlpFilterSettings;
using ::android::hardware::tv::tuner::V1_0::DemuxAlpFilterType;
using ::android::hardware::tv::tuner::V1_0::DemuxAlpLengthType;
+using ::android::hardware::tv::tuner::V1_0::DemuxCapabilities;
using ::android::hardware::tv::tuner::V1_0::DemuxFilterAvSettings;
using ::android::hardware::tv::tuner::V1_0::DemuxFilterDownloadEvent;
using ::android::hardware::tv::tuner::V1_0::DemuxFilterDownloadSettings;
@@ -1382,6 +1383,42 @@ jobject JTuner::openDvr(DvrType type, jlong bufferSize) {
return dvrObj;
}
+jobject JTuner::getDemuxCaps() {
+ DemuxCapabilities caps;
+ Result res;
+ mTuner->getDemuxCaps([&](Result r, const DemuxCapabilities& demuxCaps) {
+ caps = demuxCaps;
+ res = r;
+ });
+ if (res != Result::SUCCESS) {
+ return NULL;
+ }
+ JNIEnv *env = AndroidRuntime::getJNIEnv();
+ jclass clazz = env->FindClass("android/media/tv/tuner/DemuxCapabilities");
+ jmethodID capsInit = env->GetMethodID(clazz, "<init>", "(IIIIIIIIIJI[IZ)V");
+
+ jint numDemux = caps.numDemux;
+ jint numRecord = caps.numRecord;
+ jint numPlayback = caps.numPlayback;
+ jint numTsFilter = caps.numTsFilter;
+ jint numSectionFilter = caps.numSectionFilter;
+ jint numAudioFilter = caps.numAudioFilter;
+ jint numVideoFilter = caps.numVideoFilter;
+ jint numPesFilter = caps.numPesFilter;
+ jint numPcrFilter = caps.numPcrFilter;
+ jlong numBytesInSectionFilter = caps.numBytesInSectionFilter;
+ jint filterCaps = static_cast<jint>(caps.filterCaps);
+ jboolean bTimeFilter = caps.bTimeFilter;
+
+ jintArray linkCaps = env->NewIntArray(caps.linkCaps.size());
+ env->SetIntArrayRegion(
+ linkCaps, 0, caps.linkCaps.size(), reinterpret_cast<jint*>(&caps.linkCaps[0]));
+
+ return env->NewObject(clazz, capsInit, numDemux, numRecord, numPlayback, numTsFilter,
+ numSectionFilter, numAudioFilter, numVideoFilter, numPesFilter, numPcrFilter,
+ numBytesInSectionFilter, filterCaps, linkCaps, bTimeFilter);
+}
+
} // namespace android
////////////////////////////////////////////////////////////////////////////////
@@ -2739,8 +2776,9 @@ static jobject android_media_tv_Tuner_open_dvr_playback(
return tuner->openDvr(DvrType::PLAYBACK, bufferSize);
}
-static jobject android_media_tv_Tuner_get_demux_caps(JNIEnv*, jobject) {
- return NULL;
+static jobject android_media_tv_Tuner_get_demux_caps(JNIEnv* env, jobject thiz) {
+ sp<JTuner> tuner = getTuner(env, thiz);
+ return tuner->getDemuxCaps();
}
static int android_media_tv_Tuner_attach_filter(JNIEnv *env, jobject dvr, jobject filter) {
diff --git a/media/jni/android_media_tv_Tuner.h b/media/jni/android_media_tv_Tuner.h
index 5d2bba6c8aa2..18aac285e7c0 100644
--- a/media/jni/android_media_tv_Tuner.h
+++ b/media/jni/android_media_tv_Tuner.h
@@ -185,6 +185,7 @@ struct JTuner : public RefBase {
jobject openTimeFilter();
jobject openDescrambler();
jobject openDvr(DvrType type, jlong bufferSize);
+ jobject getDemuxCaps();
protected:
Result openDemux();
diff --git a/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/helpers/CameraTestUtils.java b/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/helpers/CameraTestUtils.java
index 25220951dd7b..daeb731ad457 100644
--- a/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/helpers/CameraTestUtils.java
+++ b/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/helpers/CameraTestUtils.java
@@ -2210,14 +2210,14 @@ public class CameraTestUtils extends Assert {
}
public static Size getPreviewSizeBound(WindowManager windowManager, Size bound) {
- Size windowSize = windowManager.getCurrentWindowMetrics().getSize();
+ Rect windowBounds = windowManager.getCurrentWindowMetrics().getBounds();
- int width = windowSize.getWidth();
- int height = windowSize.getHeight();
+ int width = windowBounds.width();
+ int height = windowBounds.height();
if (height > width) {
height = width;
- width = windowSize.getHeight();
+ width = windowBounds.height();
}
if (bound.getWidth() <= width &&
diff --git a/packages/FakeOemFeatures/src/com/android/fakeoemfeatures/FakeApp.java b/packages/FakeOemFeatures/src/com/android/fakeoemfeatures/FakeApp.java
index d4eb2a9c75d0..a2da23e918d2 100644
--- a/packages/FakeOemFeatures/src/com/android/fakeoemfeatures/FakeApp.java
+++ b/packages/FakeOemFeatures/src/com/android/fakeoemfeatures/FakeApp.java
@@ -28,11 +28,11 @@ import android.content.ComponentName;
import android.content.Context;
import android.content.Intent;
import android.content.ServiceConnection;
+import android.graphics.Rect;
import android.hardware.display.DisplayManager;
import android.os.Handler;
import android.os.IBinder;
import android.os.Message;
-import android.util.Size;
import android.util.Slog;
import android.view.Display;
import android.view.ViewGroup;
@@ -134,8 +134,8 @@ public class FakeApp extends Application {
}
lp.width = ViewGroup.LayoutParams.MATCH_PARENT;
lp.height = ViewGroup.LayoutParams.MATCH_PARENT;
- Size maxWindowSize = wm.getMaximumWindowMetrics().getSize();
- int maxSize = Math.max(maxWindowSize.getWidth(), maxWindowSize.getHeight());
+ Rect maxWindowBounds = wm.getMaximumWindowMetrics().getBounds();
+ int maxSize = Math.max(maxWindowBounds.width(), maxWindowBounds.height());
maxSize *= 2;
lp.x = maxSize;
lp.y = maxSize;
diff --git a/packages/FakeOemFeatures/src/com/android/fakeoemfeatures/FakeBackgroundService.java b/packages/FakeOemFeatures/src/com/android/fakeoemfeatures/FakeBackgroundService.java
index df00eee63b50..e2120f80f1c9 100644
--- a/packages/FakeOemFeatures/src/com/android/fakeoemfeatures/FakeBackgroundService.java
+++ b/packages/FakeOemFeatures/src/com/android/fakeoemfeatures/FakeBackgroundService.java
@@ -19,22 +19,22 @@ package com.android.fakeoemfeatures;
import static android.view.Display.DEFAULT_DISPLAY;
import static android.view.WindowManager.LayoutParams.TYPE_APPLICATION_OVERLAY;
-import java.util.ArrayList;
-import java.util.Random;
-
import android.app.Dialog;
import android.app.Service;
import android.content.Context;
import android.content.Intent;
+import android.graphics.Rect;
import android.hardware.display.DisplayManager;
import android.os.Handler;
import android.os.IBinder;
import android.os.Message;
-import android.util.Size;
import android.view.Display;
import android.view.ViewGroup;
import android.view.WindowManager;
+import java.util.ArrayList;
+import java.util.Random;
+
public class FakeBackgroundService extends Service {
final ArrayList<int[]> mAllocs = new ArrayList<int[]>();
@@ -99,8 +99,8 @@ public class FakeBackgroundService extends Service {
// Create an instance of WindowManager that is adjusted to the area of the display dedicated
// for windows with type TYPE_APPLICATION_OVERLAY.
final WindowManager wm = windowContext.getSystemService(WindowManager.class);
- Size maxWindowSize = wm.getMaximumWindowMetrics().getSize();
- int maxSize = Math.max(maxWindowSize.getWidth(), maxWindowSize.getHeight());
+ Rect maxWindowBounds = wm.getMaximumWindowMetrics().getBounds();
+ int maxSize = Math.max(maxWindowBounds.width(), maxWindowBounds.height());
maxSize *= 2;
lp.x = maxSize;
lp.y = maxSize;
diff --git a/packages/PackageInstaller/src/com/android/packageinstaller/PackageInstallerActivity.java b/packages/PackageInstaller/src/com/android/packageinstaller/PackageInstallerActivity.java
index a2fa46130076..a95677d0202f 100644
--- a/packages/PackageInstaller/src/com/android/packageinstaller/PackageInstallerActivity.java
+++ b/packages/PackageInstaller/src/com/android/packageinstaller/PackageInstallerActivity.java
@@ -406,6 +406,10 @@ public class PackageInstallerActivity extends AlertActivity {
mOk = mAlert.getButton(DialogInterface.BUTTON_POSITIVE);
mOk.setEnabled(false);
+
+ if (!mOk.isInTouchMode()) {
+ mAlert.getButton(DialogInterface.BUTTON_NEGATIVE).requestFocus();
+ }
}
/**
diff --git a/packages/SettingsLib/src/com/android/settingslib/accessibility/AccessibilityUtils.java b/packages/SettingsLib/src/com/android/settingslib/accessibility/AccessibilityUtils.java
index 2b841967d4a8..59735f413f9d 100644
--- a/packages/SettingsLib/src/com/android/settingslib/accessibility/AccessibilityUtils.java
+++ b/packages/SettingsLib/src/com/android/settingslib/accessibility/AccessibilityUtils.java
@@ -189,19 +189,6 @@ public class AccessibilityUtils {
return context.getString(R.string.config_defaultAccessibilityService);
}
- /**
- * Check if the accessibility shortcut is enabled for a user
- *
- * @param context A valid context
- * @param userId The user of interest
- * @return {@code true} if the shortcut is enabled for the user. {@code false} otherwise.
- * Note that the shortcut may be enabled, but no action associated with it.
- */
- public static boolean isShortcutEnabled(Context context, int userId) {
- return Settings.Secure.getIntForUser(context.getContentResolver(),
- Settings.Secure.ACCESSIBILITY_SHORTCUT_ENABLED, 1, userId) == 1;
- }
-
private static Set<ComponentName> getInstalledServices(Context context) {
final Set<ComponentName> installedServices = new HashSet<>();
installedServices.clear();
diff --git a/packages/SettingsLib/src/com/android/settingslib/core/instrumentation/MetricsFeatureProvider.java b/packages/SettingsLib/src/com/android/settingslib/core/instrumentation/MetricsFeatureProvider.java
index c34c365c1bfa..7ef080178a2f 100644
--- a/packages/SettingsLib/src/com/android/settingslib/core/instrumentation/MetricsFeatureProvider.java
+++ b/packages/SettingsLib/src/com/android/settingslib/core/instrumentation/MetricsFeatureProvider.java
@@ -169,6 +169,22 @@ public class MetricsFeatureProvider {
sourceMetricsCategory);
}
+ /**
+ * Logs an event when the intent is started by Profile select dialog.
+ *
+ * @return true if the intent is loggable, otherwise false
+ */
+ public boolean logStartedIntentWithProfile(Intent intent, int sourceMetricsCategory,
+ boolean isWorkProfile) {
+ if (intent == null) {
+ return false;
+ }
+ final ComponentName cn = intent.getComponent();
+ final String key = cn != null ? cn.flattenToString() : intent.getAction();
+ return logSettingsTileClick(key + (isWorkProfile ? "/work" : "/personal"),
+ sourceMetricsCategory);
+ }
+
private boolean logSettingsTileClick(String logKey, int sourceMetricsCategory) {
if (TextUtils.isEmpty(logKey)) {
// Not loggable
diff --git a/packages/SettingsLib/src/com/android/settingslib/media/LocalMediaManager.java b/packages/SettingsLib/src/com/android/settingslib/media/LocalMediaManager.java
index 922caeb0a817..df0de68b1fb9 100644
--- a/packages/SettingsLib/src/com/android/settingslib/media/LocalMediaManager.java
+++ b/packages/SettingsLib/src/com/android/settingslib/media/LocalMediaManager.java
@@ -69,9 +69,9 @@ public class LocalMediaManager implements BluetoothCallback {
private MediaDevice mOnTransferBluetoothDevice;
@VisibleForTesting
- List<MediaDevice> mMediaDevices = new ArrayList<>();
+ List<MediaDevice> mMediaDevices = new CopyOnWriteArrayList<>();
@VisibleForTesting
- List<MediaDevice> mDisconnectedMediaDevices = new ArrayList<>();
+ List<MediaDevice> mDisconnectedMediaDevices = new CopyOnWriteArrayList<>();
@VisibleForTesting
MediaDevice mPhoneDevice;
@VisibleForTesting
@@ -207,6 +207,7 @@ public class LocalMediaManager implements BluetoothCallback {
public void stopScan() {
mInfoMediaManager.unregisterCallback(mMediaDeviceCallback);
mInfoMediaManager.stopScan();
+ unRegisterDeviceAttributeChangeCallback();
}
/**
@@ -397,32 +398,34 @@ public class LocalMediaManager implements BluetoothCallback {
}
private List<MediaDevice> buildDisconnectedBluetoothDevice() {
- for (MediaDevice device : mDisconnectedMediaDevices) {
- ((BluetoothMediaDevice) device).getCachedDevice()
- .unregisterCallback(mDeviceAttributeChangeCallback);
- }
- mDisconnectedMediaDevices.clear();
final List<BluetoothDevice> bluetoothDevices =
mBluetoothAdapter.getMostRecentlyConnectedDevices();
final CachedBluetoothDeviceManager cachedDeviceManager =
mLocalBluetoothManager.getCachedDeviceManager();
+ final List<CachedBluetoothDevice> cachedBluetoothDeviceList = new ArrayList<>();
for (BluetoothDevice device : bluetoothDevices) {
final CachedBluetoothDevice cachedDevice =
cachedDeviceManager.findDevice(device);
if (cachedDevice != null) {
if (cachedDevice.getBondState() == BluetoothDevice.BOND_BONDED
&& !cachedDevice.isConnected()) {
- final MediaDevice mediaDevice = new BluetoothMediaDevice(mContext,
- cachedDevice,
- null, null, mPackageName);
- if (!mMediaDevices.contains(mediaDevice)) {
- cachedDevice.registerCallback(mDeviceAttributeChangeCallback);
- mDisconnectedMediaDevices.add(mediaDevice);
- }
+ cachedBluetoothDeviceList.add(cachedDevice);
}
}
}
+
+ unRegisterDeviceAttributeChangeCallback();
+ mDisconnectedMediaDevices.clear();
+ for (CachedBluetoothDevice cachedDevice : cachedBluetoothDeviceList) {
+ final MediaDevice mediaDevice = new BluetoothMediaDevice(mContext,
+ cachedDevice,
+ null, null, mPackageName);
+ if (!mMediaDevices.contains(mediaDevice)) {
+ cachedDevice.registerCallback(mDeviceAttributeChangeCallback);
+ mDisconnectedMediaDevices.add(mediaDevice);
+ }
+ }
return new ArrayList<>(mDisconnectedMediaDevices);
}
@@ -473,6 +476,12 @@ public class LocalMediaManager implements BluetoothCallback {
}
}
+ private void unRegisterDeviceAttributeChangeCallback() {
+ for (MediaDevice device : mDisconnectedMediaDevices) {
+ ((BluetoothMediaDevice) device).getCachedDevice()
+ .unregisterCallback(mDeviceAttributeChangeCallback);
+ }
+ }
/**
* Callback for notifying device information updating
diff --git a/packages/SettingsLib/src/com/android/settingslib/wifi/WifiStatusTracker.java b/packages/SettingsLib/src/com/android/settingslib/wifi/WifiStatusTracker.java
index 8bf48e59165e..c713d7813a54 100644
--- a/packages/SettingsLib/src/com/android/settingslib/wifi/WifiStatusTracker.java
+++ b/packages/SettingsLib/src/com/android/settingslib/wifi/WifiStatusTracker.java
@@ -17,6 +17,7 @@ import static android.net.NetworkCapabilities.NET_CAPABILITY_VALIDATED;
import android.content.Context;
import android.content.Intent;
import android.net.ConnectivityManager;
+import android.net.ConnectivityManager.NetworkCallback;
import android.net.Network;
import android.net.NetworkCapabilities;
import android.net.NetworkInfo;
@@ -36,7 +37,10 @@ import com.android.settingslib.R;
import java.util.List;
-public class WifiStatusTracker extends ConnectivityManager.NetworkCallback {
+/**
+ * Track status of Wi-Fi for the Sys UI.
+ */
+public class WifiStatusTracker {
private final Context mContext;
private final WifiNetworkScoreCache mWifiNetworkScoreCache;
private final WifiManager mWifiManager;
@@ -55,8 +59,9 @@ public class WifiStatusTracker extends ConnectivityManager.NetworkCallback {
.clearCapabilities()
.addCapability(NetworkCapabilities.NET_CAPABILITY_NOT_VPN)
.addTransportType(NetworkCapabilities.TRANSPORT_WIFI).build();
- private final ConnectivityManager.NetworkCallback mNetworkCallback = new ConnectivityManager
- .NetworkCallback() {
+ private final NetworkCallback mNetworkCallback = new NetworkCallback() {
+ // Note: onCapabilitiesChanged is guaranteed to be called "immediately" after onAvailable
+ // and onLinkPropertiesChanged.
@Override
public void onCapabilitiesChanged(
Network network, NetworkCapabilities networkCapabilities) {
@@ -64,11 +69,35 @@ public class WifiStatusTracker extends ConnectivityManager.NetworkCallback {
mCallback.run();
}
};
+ private final NetworkCallback mDefaultNetworkCallback = new NetworkCallback() {
+ @Override
+ public void onCapabilitiesChanged(Network network, NetworkCapabilities nc) {
+ // network is now the default network, and its capabilities are nc.
+ // This method will always be called immediately after the network becomes the
+ // default, in addition to any time the capabilities change while the network is
+ // the default.
+ mDefaultNetwork = network;
+ mDefaultNetworkCapabilities = nc;
+ updateStatusLabel();
+ mCallback.run();
+ }
+ @Override
+ public void onLost(Network network) {
+ // The system no longer has a default network.
+ mDefaultNetwork = null;
+ mDefaultNetworkCapabilities = null;
+ updateStatusLabel();
+ mCallback.run();
+ }
+ };
+ private Network mDefaultNetwork = null;
+ private NetworkCapabilities mDefaultNetworkCapabilities = null;
private final Runnable mCallback;
private WifiInfo mWifiInfo;
public boolean enabled;
public boolean isCaptivePortal;
+ public boolean isDefaultNetwork;
public int state;
public boolean connected;
public String ssid;
@@ -94,11 +123,13 @@ public class WifiStatusTracker extends ConnectivityManager.NetworkCallback {
mWifiNetworkScoreCache.registerListener(mCacheListener);
mConnectivityManager.registerNetworkCallback(
mNetworkRequest, mNetworkCallback, mHandler);
+ mConnectivityManager.registerDefaultNetworkCallback(mDefaultNetworkCallback, mHandler);
} else {
mNetworkScoreManager.unregisterNetworkScoreCache(NetworkKey.TYPE_WIFI,
mWifiNetworkScoreCache);
mWifiNetworkScoreCache.unregisterListener();
mConnectivityManager.unregisterNetworkCallback(mNetworkCallback);
+ mConnectivityManager.unregisterNetworkCallback(mDefaultNetworkCallback);
}
}
@@ -154,8 +185,17 @@ public class WifiStatusTracker extends ConnectivityManager.NetworkCallback {
}
private void updateStatusLabel() {
- final NetworkCapabilities networkCapabilities
- = mConnectivityManager.getNetworkCapabilities(mWifiManager.getCurrentNetwork());
+ NetworkCapabilities networkCapabilities;
+ final Network currentWifiNetwork = mWifiManager.getCurrentNetwork();
+ if (currentWifiNetwork != null && currentWifiNetwork.equals(mDefaultNetwork)) {
+ // Wifi is connected and the default network.
+ isDefaultNetwork = true;
+ networkCapabilities = mDefaultNetworkCapabilities;
+ } else {
+ isDefaultNetwork = false;
+ networkCapabilities = mConnectivityManager.getNetworkCapabilities(
+ mWifiManager.getCurrentNetwork());
+ }
isCaptivePortal = false;
if (networkCapabilities != null) {
if (networkCapabilities.hasCapability(NET_CAPABILITY_CAPTIVE_PORTAL)) {
diff --git a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/core/instrumentation/MetricsFeatureProviderTest.java b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/core/instrumentation/MetricsFeatureProviderTest.java
index ed0857ca21dc..204a93333d81 100644
--- a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/core/instrumentation/MetricsFeatureProviderTest.java
+++ b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/core/instrumentation/MetricsFeatureProviderTest.java
@@ -164,6 +164,38 @@ public class MetricsFeatureProviderTest {
}
@Test
+ public void logStartedIntentWithProfile_isPersonalProfile_shouldTagPersonal() {
+ final Intent intent = new Intent().setComponent(new ComponentName("pkg", "cls"));
+
+ final boolean loggable = mProvider.logStartedIntentWithProfile(intent,
+ MetricsEvent.SETTINGS_GESTURES, false);
+
+ assertThat(loggable).isTrue();
+ verify(mLogWriter).action(
+ MetricsEvent.SETTINGS_GESTURES,
+ MetricsEvent.ACTION_SETTINGS_TILE_CLICK,
+ SettingsEnums.PAGE_UNKNOWN,
+ "pkg/cls/personal",
+ 0);
+ }
+
+ @Test
+ public void logStartedIntentWithProfile_isWorkProfile_shouldTagWork() {
+ final Intent intent = new Intent().setComponent(new ComponentName("pkg", "cls"));
+
+ final boolean loggable = mProvider.logStartedIntentWithProfile(intent,
+ MetricsEvent.SETTINGS_GESTURES, true);
+
+ assertThat(loggable).isTrue();
+ verify(mLogWriter).action(
+ MetricsEvent.SETTINGS_GESTURES,
+ MetricsEvent.ACTION_SETTINGS_TILE_CLICK,
+ SettingsEnums.PAGE_UNKNOWN,
+ "pkg/cls/work",
+ 0);
+ }
+
+ @Test
public void getAttribution_noActivity_shouldReturnUnknown() {
assertThat(mProvider.getAttribution(null /* activity */))
.isEqualTo(SettingsEnums.PAGE_UNKNOWN);
diff --git a/packages/SettingsProvider/src/android/provider/settings/backup/SecureSettings.java b/packages/SettingsProvider/src/android/provider/settings/backup/SecureSettings.java
index d350d9df37b8..d320df9c24ba 100644
--- a/packages/SettingsProvider/src/android/provider/settings/backup/SecureSettings.java
+++ b/packages/SettingsProvider/src/android/provider/settings/backup/SecureSettings.java
@@ -48,7 +48,6 @@ public class SecureSettings {
Settings.Secure.ACCESSIBILITY_SHORTCUT_TARGET_SERVICE,
Settings.Secure.ACCESSIBILITY_BUTTON_TARGET_COMPONENT,
Settings.Secure.ACCESSIBILITY_SHORTCUT_DIALOG_SHOWN,
- Settings.Secure.ACCESSIBILITY_SHORTCUT_ENABLED,
Settings.Secure.ACCESSIBILITY_SHORTCUT_ON_LOCK_SCREEN,
Settings.Secure.ACCESSIBILITY_HIGH_TEXT_CONTRAST_ENABLED,
Settings.Secure.ACCESSIBILITY_CAPTIONING_PRESET,
diff --git a/packages/SettingsProvider/src/android/provider/settings/validators/SecureSettingsValidators.java b/packages/SettingsProvider/src/android/provider/settings/validators/SecureSettingsValidators.java
index 4d33b627f4e2..8801a9c32a36 100644
--- a/packages/SettingsProvider/src/android/provider/settings/validators/SecureSettingsValidators.java
+++ b/packages/SettingsProvider/src/android/provider/settings/validators/SecureSettingsValidators.java
@@ -25,10 +25,10 @@ import static android.provider.settings.validators.SettingsValidators.COMMA_SEPA
import static android.provider.settings.validators.SettingsValidators.COMPONENT_NAME_VALIDATOR;
import static android.provider.settings.validators.SettingsValidators.JSON_OBJECT_VALIDATOR;
import static android.provider.settings.validators.SettingsValidators.LOCALE_VALIDATOR;
+import static android.provider.settings.validators.SettingsValidators.NONE_NEGATIVE_LONG_VALIDATOR;
import static android.provider.settings.validators.SettingsValidators.NON_NEGATIVE_INTEGER_VALIDATOR;
import static android.provider.settings.validators.SettingsValidators.NULLABLE_COMPONENT_NAME_VALIDATOR;
import static android.provider.settings.validators.SettingsValidators.PACKAGE_NAME_VALIDATOR;
-import static android.provider.settings.validators.SettingsValidators.NONE_NEGATIVE_LONG_VALIDATOR;
import static android.provider.settings.validators.SettingsValidators.TILE_LIST_VALIDATOR;
import static android.provider.settings.validators.SettingsValidators.TTS_LIST_VALIDATOR;
@@ -82,7 +82,6 @@ public class SecureSettingsValidators {
Secure.ACCESSIBILITY_BUTTON_TARGET_COMPONENT,
ACCESSIBILITY_SHORTCUT_TARGET_LIST_VALIDATOR);
VALIDATORS.put(Secure.ACCESSIBILITY_SHORTCUT_DIALOG_SHOWN, BOOLEAN_VALIDATOR);
- VALIDATORS.put(Secure.ACCESSIBILITY_SHORTCUT_ENABLED, BOOLEAN_VALIDATOR);
VALIDATORS.put(Secure.ACCESSIBILITY_SHORTCUT_ON_LOCK_SCREEN, BOOLEAN_VALIDATOR);
VALIDATORS.put(Secure.ACCESSIBILITY_HIGH_TEXT_CONTRAST_ENABLED, BOOLEAN_VALIDATOR);
VALIDATORS.put(
diff --git a/packages/SettingsProvider/src/com/android/providers/settings/SettingsProtoDumpUtil.java b/packages/SettingsProvider/src/com/android/providers/settings/SettingsProtoDumpUtil.java
index af74121a11c9..b22caf0edc66 100644
--- a/packages/SettingsProvider/src/com/android/providers/settings/SettingsProtoDumpUtil.java
+++ b/packages/SettingsProvider/src/com/android/providers/settings/SettingsProtoDumpUtil.java
@@ -1781,9 +1781,6 @@ class SettingsProtoDumpUtil {
Settings.Secure.ACCESSIBILITY_LARGE_POINTER_ICON,
SecureSettingsProto.Accessibility.LARGE_POINTER_ICON);
dumpSetting(s, p,
- Settings.Secure.ACCESSIBILITY_SHORTCUT_ENABLED,
- SecureSettingsProto.Accessibility.SHORTCUT_ENABLED);
- dumpSetting(s, p,
Settings.Secure.ACCESSIBILITY_SHORTCUT_ON_LOCK_SCREEN,
SecureSettingsProto.Accessibility.SHORTCUT_ON_LOCK_SCREEN);
dumpSetting(s, p,
diff --git a/packages/SettingsProvider/src/com/android/providers/settings/SettingsProvider.java b/packages/SettingsProvider/src/com/android/providers/settings/SettingsProvider.java
index 5a9d7497b641..2fde87c08ad5 100644
--- a/packages/SettingsProvider/src/com/android/providers/settings/SettingsProvider.java
+++ b/packages/SettingsProvider/src/com/android/providers/settings/SettingsProvider.java
@@ -3436,7 +3436,7 @@ public class SettingsProvider extends ContentProvider {
}
private final class UpgradeController {
- private static final int SETTINGS_VERSION = 188;
+ private static final int SETTINGS_VERSION = 189;
private final int mUserId;
@@ -4759,6 +4759,23 @@ public class SettingsProvider extends ContentProvider {
currentVersion = 188;
}
+ if (currentVersion == 188) {
+ // Deprecate ACCESSIBILITY_SHORTCUT_ENABLED, and migrate it
+ // to ACCESSIBILITY_SHORTCUT_TARGET_SERVICE.
+ final SettingsState secureSettings = getSecureSettingsLocked(userId);
+ final Setting shortcutEnabled = secureSettings.getSettingLocked(
+ "accessibility_shortcut_enabled");
+ if ("0".equals(shortcutEnabled.getValue())) {
+ // Clear shortcut key targets list setting.
+ secureSettings.insertSettingLocked(
+ Secure.ACCESSIBILITY_SHORTCUT_TARGET_SERVICE,
+ "", null /* tag */, false /* makeDefault */,
+ SettingsState.SYSTEM_PACKAGE_NAME);
+ }
+ secureSettings.deleteSettingLocked("accessibility_shortcut_enabled");
+ currentVersion = 189;
+ }
+
// vXXX: Add new settings above this point.
if (currentVersion != newVersion) {
diff --git a/packages/Shell/AndroidManifest.xml b/packages/Shell/AndroidManifest.xml
index c7fb00a8130c..4771c4139a5b 100644
--- a/packages/Shell/AndroidManifest.xml
+++ b/packages/Shell/AndroidManifest.xml
@@ -81,6 +81,8 @@
<uses-permission android:name="android.permission.READ_INPUT_STATE" />
<uses-permission android:name="android.permission.SET_ORIENTATION" />
<uses-permission android:name="android.permission.INSTALL_PACKAGES" />
+ <!-- TODO(b/152310230): remove once APIs are confirmed to be sufficient -->
+ <uses-permission android:name="com.android.permission.USE_INSTALLER_V2" />
<uses-permission android:name="android.permission.MOVE_PACKAGE" />
<uses-permission android:name="android.permission.CLEAR_APP_USER_DATA" />
<uses-permission android:name="android.permission.CLEAR_APP_CACHE" />
diff --git a/packages/Shell/src/com/android/shell/BugreportProgressService.java b/packages/Shell/src/com/android/shell/BugreportProgressService.java
index 64e52376effd..0ae00e1ac8b5 100644
--- a/packages/Shell/src/com/android/shell/BugreportProgressService.java
+++ b/packages/Shell/src/com/android/shell/BugreportProgressService.java
@@ -1019,8 +1019,11 @@ public class BugreportProgressService extends Service {
* Wraps up bugreport generation and triggers a notification to share the bugreport.
*/
private void onBugreportFinished(BugreportInfo info) {
+ if (!TextUtils.isEmpty(info.shareTitle)) {
+ info.setTitle(info.shareTitle);
+ }
Log.d(TAG, "Bugreport finished with title: " + info.getTitle()
- + " and shareDescription: " + info.shareDescription);
+ + " and shareDescription: " + info.shareDescription);
info.finished = new AtomicBoolean(true);
synchronized (mLock) {
@@ -1795,7 +1798,9 @@ public class BugreportProgressService extends Service {
/**
* User-provided, detailed description of the bugreport; when set, will be added to the body
- * of the {@link Intent#ACTION_SEND_MULTIPLE} intent.
+ * of the {@link Intent#ACTION_SEND_MULTIPLE} intent. This is shown in the app where the
+ * bugreport is being shared as an attachment. This is not related/dependant on
+ * {@code shareDescription}.
*/
private String description;
@@ -2130,7 +2135,6 @@ public class BugreportProgressService extends Service {
return new BugreportInfo[size];
}
};
-
}
@GuardedBy("mLock")
diff --git a/packages/SystemUI/res/layout/controls_base_item.xml b/packages/SystemUI/res/layout/controls_base_item.xml
index 7708b8e9db6c..6e1fd2072b32 100644
--- a/packages/SystemUI/res/layout/controls_base_item.xml
+++ b/packages/SystemUI/res/layout/controls_base_item.xml
@@ -30,8 +30,8 @@
<ImageView
android:id="@+id/icon"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
+ android:layout_width="@dimen/control_icon_size"
+ android:layout_height="@dimen/control_icon_size"
android:paddingTop="@dimen/control_padding_adjustment"
android:clickable="false"
android:focusable="false"
diff --git a/packages/SystemUI/res/values/dimens.xml b/packages/SystemUI/res/values/dimens.xml
index 432cd749abbd..ee7f5230145e 100644
--- a/packages/SystemUI/res/values/dimens.xml
+++ b/packages/SystemUI/res/values/dimens.xml
@@ -1225,6 +1225,7 @@
<dimen name="controls_top_margin">44dp</dimen>
<dimen name="control_header_text_size">22sp</dimen>
<dimen name="control_text_size">14sp</dimen>
+ <dimen name="control_icon_size">24dp</dimen>
<dimen name="control_spacing">4dp</dimen>
<dimen name="control_list_divider">1dp</dimen>
<dimen name="control_corner_radius">12dp</dimen>
diff --git a/packages/SystemUI/res/values/strings.xml b/packages/SystemUI/res/values/strings.xml
index c8c35c704297..8a3a16e9a6cf 100644
--- a/packages/SystemUI/res/values/strings.xml
+++ b/packages/SystemUI/res/values/strings.xml
@@ -374,9 +374,31 @@
<string name="biometric_dialog_wrong_password">Wrong password</string>
<!-- Error string shown when the user enters too many incorrect attempts [CHAR LIMIT=120]-->
<string name="biometric_dialog_credential_too_many_attempts">Too many incorrect attempts.\nTry again in <xliff:g id="number">%d</xliff:g> seconds.</string>
+
<!-- Error string shown when the user enters an incorrect PIN/pattern/password and it counts towards the max attempts before the data on the device is wiped. [CHAR LIMIT=NONE]-->
<string name="biometric_dialog_credential_attempts_before_wipe">Try again. Attempt <xliff:g id="attempts" example="1">%1$d</xliff:g> of <xliff:g id="max_attempts" example="3">%2$d</xliff:g>.</string>
+ <!-- Title of a dialog shown when the user only has one attempt left to provide the correct PIN/pattern/password before the device, one of its users, or a work profile is wiped. [CHAR LIMIT=NONE] -->
+ <string name="biometric_dialog_last_attempt_before_wipe_dialog_title">Your data will be deleted</string>
+ <!-- Content of a dialog shown when the user only has one attempt left to provide the correct lock pattern before the device is wiped. [CHAR LIMIT=NONE] -->
+ <string name="biometric_dialog_last_pattern_attempt_before_wipe_device">If you enter an incorrect pattern on the next attempt, this device\u2019s data will be deleted.</string>
+ <!-- Content of a dialog shown when the user only has one attempt left to provide the correct PIN before the device is wiped. [CHAR LIMIT=NONE] -->
+ <string name="biometric_dialog_last_pin_attempt_before_wipe_device">If you enter an incorrect PIN on the next attempt, this device\u2019s data will be deleted.</string>
+ <!-- Content of a dialog shown when the user only has one attempt left to provide the correct password before the device is wiped. [CHAR LIMIT=NONE] -->
+ <string name="biometric_dialog_last_password_attempt_before_wipe_device">If you enter an incorrect password on the next attempt, this device\u2019s data will be deleted.</string>
+ <!-- Content of a dialog shown when the user only has one attempt left to provide the correct lock pattern before the user is removed. [CHAR LIMIT=NONE] -->
+ <string name="biometric_dialog_last_pattern_attempt_before_wipe_user">If you enter an incorrect pattern on the next attempt, this user will be deleted.</string>
+ <!-- Content of a dialog shown when the user only has one attempt left to provide the correct PIN before the user is removed. [CHAR LIMIT=NONE] -->
+ <string name="biometric_dialog_last_pin_attempt_before_wipe_user">If you enter an incorrect PIN on the next attempt, this user will be deleted.</string>
+ <!-- Content of a dialog shown when the user only has one attempt left to provide the correct password before the user is removed. [CHAR LIMIT=NONE] -->
+ <string name="biometric_dialog_last_password_attempt_before_wipe_user">If you enter an incorrect password on the next attempt, this user will be deleted.</string>
+ <!-- Content of a dialog shown when the user only has one attempt left to provide the correct pattern before the work profile is removed. [CHAR LIMIT=NONE] -->
+ <string name="biometric_dialog_last_pattern_attempt_before_wipe_profile">If you enter an incorrect pattern on the next attempt, your work profile and its data will be deleted.</string>
+ <!-- Content of a dialog shown when the user only has one attempt left to provide the correct PIN before the work profile is removed. [CHAR LIMIT=NONE] -->
+ <string name="biometric_dialog_last_pin_attempt_before_wipe_profile">If you enter an incorrect PIN on the next attempt, your work profile and its data will be deleted.</string>
+ <!-- Content of a dialog shown when the user only has one attempt left to provide the correct password before the work profile is removed. [CHAR LIMIT=NONE] -->
+ <string name="biometric_dialog_last_password_attempt_before_wipe_profile">If you enter an incorrect password on the next attempt, your work profile and its data will be deleted.</string>
+
<!-- Content of a dialog shown when the user has failed to provide the device lock too many times and the device is wiped. [CHAR LIMIT=NONE] -->
<string name="biometric_dialog_failed_attempts_now_wiping_device">Too many incorrect attempts. This device\u2019s data will be deleted.</string>
<!-- Content of a dialog shown when the user has failed to provide the user lock too many times and the user is removed. [CHAR LIMIT=NONE] -->
diff --git a/packages/SystemUI/shared/src/com/android/systemui/shared/system/ActivityManagerWrapper.java b/packages/SystemUI/shared/src/com/android/systemui/shared/system/ActivityManagerWrapper.java
index 49e3e5724988..3bda3c8df699 100644
--- a/packages/SystemUI/shared/src/com/android/systemui/shared/system/ActivityManagerWrapper.java
+++ b/packages/SystemUI/shared/src/com/android/systemui/shared/system/ActivityManagerWrapper.java
@@ -20,9 +20,7 @@ import static android.app.ActivityManager.LOCK_TASK_MODE_LOCKED;
import static android.app.ActivityManager.LOCK_TASK_MODE_NONE;
import static android.app.ActivityManager.LOCK_TASK_MODE_PINNED;
import static android.app.ActivityManager.RECENT_IGNORE_UNAVAILABLE;
-import static android.app.WindowConfiguration.ACTIVITY_TYPE_RECENTS;
import static android.app.WindowConfiguration.ACTIVITY_TYPE_UNDEFINED;
-import static android.app.WindowConfiguration.WINDOWING_MODE_PINNED;
import static android.app.WindowConfiguration.WINDOWING_MODE_SPLIT_SCREEN_PRIMARY;
import static android.app.WindowConfiguration.WINDOWING_MODE_SPLIT_SCREEN_SECONDARY;
import static android.app.WindowConfiguration.WINDOWING_MODE_UNDEFINED;
@@ -38,7 +36,6 @@ import android.app.ActivityTaskManager;
import android.app.AppGlobals;
import android.app.IAssistDataReceiver;
import android.app.WindowConfiguration;
-import android.app.WindowConfiguration.ActivityType;
import android.content.ContentResolver;
import android.content.Context;
import android.content.Intent;
@@ -113,15 +110,18 @@ public class ActivityManagerWrapper {
* @return the top running task (can be {@code null}).
*/
public ActivityManager.RunningTaskInfo getRunningTask() {
- return getRunningTask(ACTIVITY_TYPE_RECENTS /* ignoreActivityType */);
+ return getRunningTask(false /* filterVisibleRecents */);
}
- public ActivityManager.RunningTaskInfo getRunningTask(@ActivityType int ignoreActivityType) {
+ /**
+ * @return the top running task filtering only for tasks that can be visible in the recent tasks
+ * list (can be {@code null}).
+ */
+ public ActivityManager.RunningTaskInfo getRunningTask(boolean filterOnlyVisibleRecents) {
// Note: The set of running tasks from the system is ordered by recency
try {
List<ActivityManager.RunningTaskInfo> tasks =
- ActivityTaskManager.getService().getFilteredTasks(1, ignoreActivityType,
- WINDOWING_MODE_PINNED /* ignoreWindowingMode */);
+ ActivityTaskManager.getService().getFilteredTasks(1, filterOnlyVisibleRecents);
if (tasks.isEmpty()) {
return null;
}
diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardUpdateMonitor.java b/packages/SystemUI/src/com/android/keyguard/KeyguardUpdateMonitor.java
index 3afe19f926ec..7cbc840afed4 100644
--- a/packages/SystemUI/src/com/android/keyguard/KeyguardUpdateMonitor.java
+++ b/packages/SystemUI/src/com/android/keyguard/KeyguardUpdateMonitor.java
@@ -127,6 +127,7 @@ public class KeyguardUpdateMonitor implements TrustManager.TrustListener, Dumpab
private static final boolean DEBUG = KeyguardConstants.DEBUG;
private static final boolean DEBUG_SIM_STATES = KeyguardConstants.DEBUG_SIM_STATES;
private static final boolean DEBUG_FACE = true;
+ private static final boolean DEBUG_SPEW = false;
private static final int LOW_BATTERY_THRESHOLD = 20;
private static final String ACTION_FACE_UNLOCK_STARTED
@@ -324,7 +325,8 @@ public class KeyguardUpdateMonitor implements TrustManager.TrustListener, Dumpab
}
};
- private class BiometricAuthenticated {
+ @VisibleForTesting
+ static class BiometricAuthenticated {
private final boolean mAuthenticated;
private final boolean mIsStrongBiometric;
@@ -338,11 +340,14 @@ public class KeyguardUpdateMonitor implements TrustManager.TrustListener, Dumpab
private SparseBooleanArray mUserHasTrust = new SparseBooleanArray();
private SparseBooleanArray mUserTrustIsManaged = new SparseBooleanArray();
private SparseBooleanArray mUserTrustIsUsuallyManaged = new SparseBooleanArray();
- private SparseArray<BiometricAuthenticated> mUserFingerprintAuthenticated = new SparseArray<>();
- private SparseArray<BiometricAuthenticated> mUserFaceAuthenticated = new SparseArray<>();
private SparseBooleanArray mUserFaceUnlockRunning = new SparseBooleanArray();
private Map<Integer, Intent> mSecondaryLockscreenRequirement = new HashMap<Integer, Intent>();
+ @VisibleForTesting
+ SparseArray<BiometricAuthenticated> mUserFingerprintAuthenticated = new SparseArray<>();
+ @VisibleForTesting
+ SparseArray<BiometricAuthenticated> mUserFaceAuthenticated = new SparseArray<>();
+
private static int sCurrentUser;
private Runnable mUpdateBiometricListeningState = this::updateBiometricListeningState;
@@ -1850,11 +1855,33 @@ public class KeyguardUpdateMonitor implements TrustManager.TrustListener, Dumpab
// Only listen if this KeyguardUpdateMonitor belongs to the primary user. There is an
// instance of KeyguardUpdateMonitor for each user but KeyguardUpdateMonitor is user-aware.
- return (mBouncer || mAuthInterruptActive || awakeKeyguard || shouldListenForFaceAssistant())
+ final boolean shouldListen =
+ (mBouncer || mAuthInterruptActive || awakeKeyguard
+ || shouldListenForFaceAssistant())
&& !mSwitchingUser && !isFaceDisabled(user) && becauseCannotSkipBouncer
&& !mKeyguardGoingAway && mFaceSettingEnabledForUser.get(user) && !mLockIconPressed
&& strongAuthAllowsScanning && mIsPrimaryUser
&& !mSecureCameraLaunched;
+
+ // Too chatty, but very useful when debugging issues.
+ if (DEBUG_SPEW) {
+ Log.v(TAG, "shouldListenForFace(" + user + ")=" + shouldListen + "... "
+ + ", mBouncer: " + mBouncer
+ + ", mAuthInterruptActive: " + mAuthInterruptActive
+ + ", awakeKeyguard: " + awakeKeyguard
+ + ", shouldListenForFaceAssistant: " + shouldListenForFaceAssistant()
+ + ", mSwitchingUser: " + mSwitchingUser
+ + ", isFaceDisabled(" + user + "): " + isFaceDisabled(user)
+ + ", becauseCannotSkipBouncer: " + becauseCannotSkipBouncer
+ + ", mKeyguardGoingAway: " + mKeyguardGoingAway
+ + ", mFaceSettingEnabledForUser(" + user + "): "
+ + mFaceSettingEnabledForUser.get(user)
+ + ", mLockIconPressed: " + mLockIconPressed
+ + ", strongAuthAllowsScanning: " + strongAuthAllowsScanning
+ + ", isPrimaryUser: " + mIsPrimaryUser
+ + ", mSecureCameraLaunched: " + mSecureCameraLaunched);
+ }
+ return shouldListen;
}
/**
@@ -2049,8 +2076,10 @@ public class KeyguardUpdateMonitor implements TrustManager.TrustListener, Dumpab
/**
* Handle {@link #MSG_USER_SWITCHING}
*/
- private void handleUserSwitching(int userId, IRemoteCallback reply) {
+ @VisibleForTesting
+ void handleUserSwitching(int userId, IRemoteCallback reply) {
Assert.isMainThread();
+ clearBiometricRecognized();
mUserTrustIsUsuallyManaged.put(userId, mTrustManager.isTrustUsuallyManaged(userId));
for (int i = 0; i < mCallbacks.size(); i++) {
KeyguardUpdateMonitorCallback cb = mCallbacks.get(i).get();
diff --git a/packages/SystemUI/src/com/android/systemui/biometrics/AuthCredentialView.java b/packages/SystemUI/src/com/android/systemui/biometrics/AuthCredentialView.java
index 13f3c0fce5c2..b006bc1351a3 100644
--- a/packages/SystemUI/src/com/android/systemui/biometrics/AuthCredentialView.java
+++ b/packages/SystemUI/src/com/android/systemui/biometrics/AuthCredentialView.java
@@ -347,21 +347,35 @@ public abstract class AuthCredentialView extends LinearLayout {
showError(message);
}
- // Only show popup dialog before wipe.
+ // Only show dialog if <=1 attempts are left before wiping.
final int remainingAttempts = maxAttempts - numAttempts;
- if (remainingAttempts <= 0) {
- showNowWipingMessage();
- mContainerView.animateAway(AuthDialogCallback.DISMISSED_ERROR);
+ if (remainingAttempts == 1) {
+ showLastAttemptBeforeWipeDialog();
+ } else if (remainingAttempts <= 0) {
+ showNowWipingDialog();
}
return true;
}
- private void showNowWipingMessage() {
+ private void showLastAttemptBeforeWipeDialog() {
+ final AlertDialog alertDialog = new AlertDialog.Builder(mContext)
+ .setTitle(R.string.biometric_dialog_last_attempt_before_wipe_dialog_title)
+ .setMessage(
+ getLastAttemptBeforeWipeMessageRes(getUserTypeForWipe(), mCredentialType))
+ .setPositiveButton(android.R.string.ok, null)
+ .create();
+ alertDialog.getWindow().setType(WindowManager.LayoutParams.TYPE_STATUS_BAR_SUB_PANEL);
+ alertDialog.show();
+ }
+
+ private void showNowWipingDialog() {
final AlertDialog alertDialog = new AlertDialog.Builder(mContext)
.setMessage(getNowWipingMessageRes(getUserTypeForWipe()))
.setPositiveButton(R.string.biometric_dialog_now_wiping_dialog_dismiss, null)
+ .setOnDismissListener(
+ dialog -> mContainerView.animateAway(AuthDialogCallback.DISMISSED_ERROR))
.create();
- alertDialog.getWindow().setType(WindowManager.LayoutParams.TYPE_SYSTEM_ALERT);
+ alertDialog.getWindow().setType(WindowManager.LayoutParams.TYPE_STATUS_BAR_SUB_PANEL);
alertDialog.show();
}
@@ -377,6 +391,59 @@ public abstract class AuthCredentialView extends LinearLayout {
}
}
+ private static @StringRes int getLastAttemptBeforeWipeMessageRes(
+ @UserType int userType, @Utils.CredentialType int credentialType) {
+ switch (userType) {
+ case USER_TYPE_PRIMARY:
+ return getLastAttemptBeforeWipeDeviceMessageRes(credentialType);
+ case USER_TYPE_MANAGED_PROFILE:
+ return getLastAttemptBeforeWipeProfileMessageRes(credentialType);
+ case USER_TYPE_SECONDARY:
+ return getLastAttemptBeforeWipeUserMessageRes(credentialType);
+ default:
+ throw new IllegalArgumentException("Unrecognized user type:" + userType);
+ }
+ }
+
+ private static @StringRes int getLastAttemptBeforeWipeDeviceMessageRes(
+ @Utils.CredentialType int credentialType) {
+ switch (credentialType) {
+ case Utils.CREDENTIAL_PIN:
+ return R.string.biometric_dialog_last_pin_attempt_before_wipe_device;
+ case Utils.CREDENTIAL_PATTERN:
+ return R.string.biometric_dialog_last_pattern_attempt_before_wipe_device;
+ case Utils.CREDENTIAL_PASSWORD:
+ default:
+ return R.string.biometric_dialog_last_password_attempt_before_wipe_device;
+ }
+ }
+
+ private static @StringRes int getLastAttemptBeforeWipeProfileMessageRes(
+ @Utils.CredentialType int credentialType) {
+ switch (credentialType) {
+ case Utils.CREDENTIAL_PIN:
+ return R.string.biometric_dialog_last_pin_attempt_before_wipe_profile;
+ case Utils.CREDENTIAL_PATTERN:
+ return R.string.biometric_dialog_last_pattern_attempt_before_wipe_profile;
+ case Utils.CREDENTIAL_PASSWORD:
+ default:
+ return R.string.biometric_dialog_last_password_attempt_before_wipe_profile;
+ }
+ }
+
+ private static @StringRes int getLastAttemptBeforeWipeUserMessageRes(
+ @Utils.CredentialType int credentialType) {
+ switch (credentialType) {
+ case Utils.CREDENTIAL_PIN:
+ return R.string.biometric_dialog_last_pin_attempt_before_wipe_user;
+ case Utils.CREDENTIAL_PATTERN:
+ return R.string.biometric_dialog_last_pattern_attempt_before_wipe_user;
+ case Utils.CREDENTIAL_PASSWORD:
+ default:
+ return R.string.biometric_dialog_last_password_attempt_before_wipe_user;
+ }
+ }
+
private static @StringRes int getNowWipingMessageRes(@UserType int userType) {
switch (userType) {
case USER_TYPE_PRIMARY:
diff --git a/packages/SystemUI/src/com/android/systemui/bubbles/BubbleData.java b/packages/SystemUI/src/com/android/systemui/bubbles/BubbleData.java
index 8bc35f4058e9..2bd15188b7d3 100644
--- a/packages/SystemUI/src/com/android/systemui/bubbles/BubbleData.java
+++ b/packages/SystemUI/src/com/android/systemui/bubbles/BubbleData.java
@@ -208,7 +208,7 @@ public class BubbleData {
b -> {
notificationEntryUpdated(bubble, /* suppressFlyout */
false, /* showInShade */ true);
- setSelectedBubbleInternal(bubble);
+ setSelectedBubble(bubble);
},
mContext, stack, factory);
dispatchPendingChanges();
@@ -761,6 +761,17 @@ public class BubbleData {
}
@VisibleForTesting(visibility = PRIVATE)
+ Bubble getOverflowBubbleWithKey(String key) {
+ for (int i = 0; i < mOverflowBubbles.size(); i++) {
+ Bubble bubble = mOverflowBubbles.get(i);
+ if (bubble.getKey().equals(key)) {
+ return bubble;
+ }
+ }
+ return null;
+ }
+
+ @VisibleForTesting(visibility = PRIVATE)
void setTimeSource(TimeSource timeSource) {
mTimeSource = timeSource;
}
diff --git a/packages/SystemUI/src/com/android/systemui/controls/controller/ControlsControllerImpl.kt b/packages/SystemUI/src/com/android/systemui/controls/controller/ControlsControllerImpl.kt
index 6c49c82acdc0..118fcbb20f26 100644
--- a/packages/SystemUI/src/com/android/systemui/controls/controller/ControlsControllerImpl.kt
+++ b/packages/SystemUI/src/com/android/systemui/controls/controller/ControlsControllerImpl.kt
@@ -252,10 +252,17 @@ class ControlsControllerImpl @Inject constructor (
it.controlId in favoritesForComponentKeys
)
}
+ val removedControls = mutableListOf<ControlStatus>()
+ Favorites.getStructuresForComponent(componentName).forEach { st ->
+ st.controls.forEach {
+ if (it.controlId in removed) {
+ val r = createRemovedStatus(componentName, it, st.structure)
+ removedControls.add(r)
+ }
+ }
+ }
val loadData = createLoadDataObject(
- Favorites.getControlsForComponent(componentName)
- .filter { it.controlId in removed }
- .map { createRemovedStatus(componentName, it) } +
+ removedControls +
controlsWithFavorite,
favoritesForComponentKeys
)
@@ -266,17 +273,15 @@ class ControlsControllerImpl @Inject constructor (
override fun error(message: String) {
loadCanceller = null
executor.execute {
- val loadData = Favorites.getControlsForComponent(componentName)
- .let { controls ->
- val keys = controls.map { it.controlId }
- createLoadDataObject(
- controls.map {
- createRemovedStatus(componentName, it, false)
- },
- keys,
- true
- )
- }
+ val controls = Favorites.getStructuresForComponent(componentName)
+ .flatMap { st ->
+ st.controls.map {
+ createRemovedStatus(componentName, it, st.structure,
+ false)
+ }
+ }
+ val keys = controls.map { it.control.controlId }
+ val loadData = createLoadDataObject(controls, keys, true)
dataCallback.accept(loadData)
}
}
@@ -372,6 +377,7 @@ class ControlsControllerImpl @Inject constructor (
private fun createRemovedStatus(
componentName: ComponentName,
controlInfo: ControlInfo,
+ structure: CharSequence,
setRemoved: Boolean = true
): ControlStatus {
val intent = Intent(Intent.ACTION_MAIN).apply {
@@ -384,6 +390,8 @@ class ControlsControllerImpl @Inject constructor (
0)
val control = Control.StatelessBuilder(controlInfo.controlId, pendingIntent)
.setTitle(controlInfo.controlTitle)
+ .setSubtitle(controlInfo.controlSubtitle)
+ .setStructure(structure)
.setDeviceType(controlInfo.deviceType)
.build()
return ControlStatus(control, componentName, true, setRemoved)
diff --git a/packages/SystemUI/src/com/android/systemui/controls/ui/ChallengeDialogs.kt b/packages/SystemUI/src/com/android/systemui/controls/ui/ChallengeDialogs.kt
index 15c2a0afe819..a7a41033bb5d 100644
--- a/packages/SystemUI/src/com/android/systemui/controls/ui/ChallengeDialogs.kt
+++ b/packages/SystemUI/src/com/android/systemui/controls/ui/ChallengeDialogs.kt
@@ -34,24 +34,29 @@ import com.android.systemui.R
/**
* Creates all dialogs for challengeValues that can occur from a call to
- * {@link ControlsProviderService#performControlAction}. The types of challenge
- * responses are listed in {@link ControlAction.ResponseResult}.
+ * [ControlsProviderService#performControlAction]. The types of challenge responses are listed in
+ * [ControlAction.ResponseResult].
*/
object ChallengeDialogs {
- fun createPinDialog(cvh: ControlViewHolder): Dialog? {
+ private const val WINDOW_TYPE = WindowManager.LayoutParams.TYPE_VOLUME_OVERLAY
+ private const val STYLE = android.R.style.Theme_DeviceDefault_Dialog_Alert
+
+ /**
+ * AlertDialogs to handle [ControlAction#RESPONSE_CHALLENGE_PIN] and
+ * [ControlAction#RESPONSE_CHALLENGE_PIN] responses, decided by the useAlphaNumeric
+ * parameter.
+ */
+ fun createPinDialog(cvh: ControlViewHolder, useAlphaNumeric: Boolean): Dialog? {
val lastAction = cvh.lastAction
if (lastAction == null) {
Log.e(ControlsUiController.TAG,
"PIN Dialog attempted but no last action is set. Will not show")
return null
}
- val builder = AlertDialog.Builder(
- cvh.context,
- android.R.style.Theme_DeviceDefault_Dialog_Alert
- ).apply {
+ val builder = AlertDialog.Builder(cvh.context, STYLE).apply {
val res = cvh.context.resources
- setTitle(res.getString(R.string.controls_pin_verify, *arrayOf(cvh.title.getText())))
+ setTitle(res.getString(R.string.controls_pin_verify, cvh.title.getText()))
setView(R.layout.controls_dialog_pin)
setPositiveButton(
android.R.string.ok,
@@ -71,25 +76,64 @@ object ChallengeDialogs {
}
return builder.create().apply {
getWindow().apply {
- setType(WindowManager.LayoutParams.TYPE_VOLUME_OVERLAY)
+ setType(WINDOW_TYPE)
setSoftInputMode(WindowManager.LayoutParams.SOFT_INPUT_STATE_VISIBLE)
}
setOnShowListener(DialogInterface.OnShowListener { _ ->
val editText = requireViewById<EditText>(R.id.controls_pin_input)
- requireViewById<CheckBox>(R.id.controls_pin_use_alpha).setOnClickListener { v ->
- if ((v as CheckBox).isChecked) {
- editText.setInputType(
- InputType.TYPE_CLASS_TEXT or InputType.TYPE_TEXT_VARIATION_PASSWORD)
- } else {
- editText.setInputType(
- InputType.TYPE_CLASS_NUMBER or InputType.TYPE_NUMBER_VARIATION_PASSWORD)
- }
+ val useAlphaCheckBox = requireViewById<CheckBox>(R.id.controls_pin_use_alpha)
+ useAlphaCheckBox.setChecked(useAlphaNumeric)
+ setInputType(editText, useAlphaCheckBox.isChecked())
+ requireViewById<CheckBox>(R.id.controls_pin_use_alpha).setOnClickListener { _ ->
+ setInputType(editText, useAlphaCheckBox.isChecked())
}
editText.requestFocus()
})
}
}
+ /**
+ * AlertDialogs to handle [ControlAction#RESPONSE_CHALLENGE_ACK] response type.
+ */
+ fun createConfirmationDialog(cvh: ControlViewHolder): Dialog? {
+ val lastAction = cvh.lastAction
+ if (lastAction == null) {
+ Log.e(ControlsUiController.TAG,
+ "Confirmation Dialog attempted but no last action is set. Will not show")
+ return null
+ }
+ val builder = AlertDialog.Builder(cvh.context, STYLE).apply {
+ val res = cvh.context.resources
+ setMessage(res.getString(
+ R.string.controls_confirmation_message, cvh.title.getText()))
+ setPositiveButton(
+ android.R.string.ok,
+ DialogInterface.OnClickListener { dialog, _ ->
+ cvh.action(addChallengeValue(lastAction, "true"))
+ dialog.dismiss()
+ })
+ setNegativeButton(
+ android.R.string.cancel,
+ DialogInterface.OnClickListener { dialog, _ -> dialog.cancel() }
+ )
+ }
+ return builder.create().apply {
+ getWindow().apply {
+ setType(WINDOW_TYPE)
+ }
+ }
+ }
+
+ private fun setInputType(editText: EditText, useTextInput: Boolean) {
+ if (useTextInput) {
+ editText.setInputType(
+ InputType.TYPE_CLASS_TEXT or InputType.TYPE_TEXT_VARIATION_PASSWORD)
+ } else {
+ editText.setInputType(
+ InputType.TYPE_CLASS_NUMBER or InputType.TYPE_NUMBER_VARIATION_PASSWORD)
+ }
+ }
+
private fun addChallengeValue(action: ControlAction, challengeValue: String): ControlAction {
val id = action.getTemplateId()
return when (action) {
diff --git a/packages/SystemUI/src/com/android/systemui/controls/ui/ControlViewHolder.kt b/packages/SystemUI/src/com/android/systemui/controls/ui/ControlViewHolder.kt
index 9f5dd02b4514..7d3a86091869 100644
--- a/packages/SystemUI/src/com/android/systemui/controls/ui/ControlViewHolder.kt
+++ b/packages/SystemUI/src/com/android/systemui/controls/ui/ControlViewHolder.kt
@@ -21,6 +21,7 @@ import android.graphics.drawable.ClipDrawable
import android.graphics.drawable.GradientDrawable
import android.graphics.drawable.LayerDrawable
import android.service.controls.Control
+import android.service.controls.DeviceTypes
import android.service.controls.actions.ControlAction
import android.service.controls.templates.ControlTemplate
import android.service.controls.templates.StatelessTemplate
@@ -156,7 +157,11 @@ class ControlViewHolder(
statusExtra.setTextColor(fg)
icon.setImageDrawable(ri.icon)
- icon.setImageTintList(fg)
+
+ // do not color app icons
+ if (deviceType != DeviceTypes.TYPE_ROUTINE) {
+ icon.setImageTintList(fg)
+ }
(clipLayer.getDrawable() as GradientDrawable).apply {
setColor(context.getResources().getColor(bg, context.getTheme()))
diff --git a/packages/SystemUI/src/com/android/systemui/controls/ui/ControlsUiControllerImpl.kt b/packages/SystemUI/src/com/android/systemui/controls/ui/ControlsUiControllerImpl.kt
index b0db4370f38d..05a0c45c2e15 100644
--- a/packages/SystemUI/src/com/android/systemui/controls/ui/ControlsUiControllerImpl.kt
+++ b/packages/SystemUI/src/com/android/systemui/controls/ui/ControlsUiControllerImpl.kt
@@ -442,7 +442,15 @@ class ControlsUiControllerImpl @Inject constructor (
controlViewsById.get(key)?.let { cvh ->
when (response) {
ControlAction.RESPONSE_CHALLENGE_PIN -> {
- activeDialog = ChallengeDialogs.createPinDialog(cvh)
+ activeDialog = ChallengeDialogs.createPinDialog(cvh, false)
+ activeDialog?.show()
+ }
+ ControlAction.RESPONSE_CHALLENGE_PASSPHRASE -> {
+ activeDialog = ChallengeDialogs.createPinDialog(cvh, true)
+ activeDialog?.show()
+ }
+ ControlAction.RESPONSE_CHALLENGE_ACK -> {
+ activeDialog = ChallengeDialogs.createConfirmationDialog(cvh)
activeDialog?.show()
}
else -> cvh.actionResponse(response)
diff --git a/packages/SystemUI/src/com/android/systemui/controls/ui/RenderInfo.kt b/packages/SystemUI/src/com/android/systemui/controls/ui/RenderInfo.kt
index 27e46497b20a..810ea65c7873 100644
--- a/packages/SystemUI/src/com/android/systemui/controls/ui/RenderInfo.kt
+++ b/packages/SystemUI/src/com/android/systemui/controls/ui/RenderInfo.kt
@@ -64,7 +64,7 @@ data class RenderInfo(
val iconState = deviceIconMap.getValue(iconKey)
val resourceId = iconState[enabled]
- var icon: Drawable? = null
+ var icon: Drawable?
if (resourceId == APP_ICON_ID) {
icon = appIconMap.get(componentName)
if (icon == null) {
diff --git a/packages/SystemUI/src/com/android/systemui/controls/ui/ToggleRangeBehavior.kt b/packages/SystemUI/src/com/android/systemui/controls/ui/ToggleRangeBehavior.kt
index c495c58fff2a..f79c8b2393d0 100644
--- a/packages/SystemUI/src/com/android/systemui/controls/ui/ToggleRangeBehavior.kt
+++ b/packages/SystemUI/src/com/android/systemui/controls/ui/ToggleRangeBehavior.kt
@@ -64,12 +64,13 @@ class ToggleRangeBehavior : Behavior {
val gestureListener = ToggleRangeGestureListener(cvh.layout)
val gestureDetector = GestureDetector(context, gestureListener)
- cvh.layout.setOnTouchListener { _: View, e: MotionEvent ->
+ cvh.layout.setOnTouchListener { v: View, e: MotionEvent ->
if (gestureDetector.onTouchEvent(e)) {
return@setOnTouchListener true
}
if (e.getAction() == MotionEvent.ACTION_UP && gestureListener.isDragging) {
+ v.getParent().requestDisallowInterceptTouchEvent(false)
gestureListener.isDragging = false
endUpdateRange()
return@setOnTouchListener true
@@ -254,6 +255,7 @@ class ToggleRangeBehavior : Behavior {
yDiff: Float
): Boolean {
if (!isDragging) {
+ v.getParent().requestDisallowInterceptTouchEvent(true)
this@ToggleRangeBehavior.beginUpdateRange()
isDragging = true
}
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardSliceProvider.java b/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardSliceProvider.java
index 2cc3d9e22a7d..96494cfe640f 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardSliceProvider.java
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardSliceProvider.java
@@ -305,7 +305,8 @@ public class KeyguardSliceProvider extends SliceProvider implements
oldInstance.onDestroy();
}
mDatePattern = getContext().getString(R.string.system_ui_aod_date_pattern);
- mPendingIntent = PendingIntent.getActivity(getContext(), 0, new Intent(), 0);
+ mPendingIntent = PendingIntent.getActivity(getContext(), 0,
+ new Intent(getContext(), KeyguardSliceProvider.class), 0);
mMediaManager.addCallback(this);
mStatusBarStateController.addCallback(this);
mNextAlarmController.addCallback(this);
diff --git a/packages/SystemUI/src/com/android/systemui/pip/phone/PipResizeGestureHandler.java b/packages/SystemUI/src/com/android/systemui/pip/phone/PipResizeGestureHandler.java
index 1a01cfedb82e..0b076559ae36 100644
--- a/packages/SystemUI/src/com/android/systemui/pip/phone/PipResizeGestureHandler.java
+++ b/packages/SystemUI/src/com/android/systemui/pip/phone/PipResizeGestureHandler.java
@@ -99,14 +99,14 @@ public class PipResizeGestureHandler {
mEnablePipResize = DeviceConfig.getBoolean(
DeviceConfig.NAMESPACE_SYSTEMUI,
PIP_USER_RESIZE,
- /* defaultValue = */ false);
+ /* defaultValue = */ true);
deviceConfig.addOnPropertiesChangedListener(DeviceConfig.NAMESPACE_SYSTEMUI, mMainExecutor,
new DeviceConfig.OnPropertiesChangedListener() {
@Override
public void onPropertiesChanged(DeviceConfig.Properties properties) {
if (properties.getKeyset().contains(PIP_USER_RESIZE)) {
mEnablePipResize = properties.getBoolean(
- PIP_USER_RESIZE, /* defaultValue = */ false);
+ PIP_USER_RESIZE, /* defaultValue = */ true);
}
}
});
diff --git a/packages/SystemUI/src/com/android/systemui/qs/QSPanel.java b/packages/SystemUI/src/com/android/systemui/qs/QSPanel.java
index 5ccf8c7e9212..33cc086a8d9f 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/QSPanel.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/QSPanel.java
@@ -133,6 +133,9 @@ public class QSPanel extends LinearLayout implements Tunable, Callback, Brightne
new LocalMediaManager.DeviceCallback() {
@Override
public void onDeviceListUpdate(List<MediaDevice> devices) {
+ if (mLocalMediaManager == null) {
+ return;
+ }
MediaDevice currentDevice = mLocalMediaManager.getCurrentConnectedDevice();
// Check because this can be called several times while changing devices
if (mDevice == null || !mDevice.equals(currentDevice)) {
@@ -293,14 +296,17 @@ public class QSPanel extends LinearLayout implements Tunable, Callback, Brightne
if (mMediaPlayers.size() > 0) {
((View) mMediaCarousel.getParent()).setVisibility(View.VISIBLE);
- // Set up listener for device changes
- // TODO: integrate with MediaTransferManager?
- InfoMediaManager imm =
- new InfoMediaManager(mContext, null, null, mLocalBluetoothManager);
- mLocalMediaManager = new LocalMediaManager(mContext, mLocalBluetoothManager, imm, null);
- mLocalMediaManager.startScan();
- mDevice = mLocalMediaManager.getCurrentConnectedDevice();
- mLocalMediaManager.registerCallback(mDeviceCallback);
+ if (mLocalMediaManager == null) {
+ // Set up listener for device changes
+ // TODO: integrate with MediaTransferManager?
+ InfoMediaManager imm =
+ new InfoMediaManager(mContext, null, null, mLocalBluetoothManager);
+ mLocalMediaManager = new LocalMediaManager(mContext, mLocalBluetoothManager, imm,
+ null);
+ mLocalMediaManager.startScan();
+ mDevice = mLocalMediaManager.getCurrentConnectedDevice();
+ mLocalMediaManager.registerCallback(mDeviceCallback);
+ }
}
}
@@ -323,8 +329,11 @@ public class QSPanel extends LinearLayout implements Tunable, Callback, Brightne
mMediaCarousel.removeView(player.getView());
if (mMediaPlayers.size() == 0) {
((View) mMediaCarousel.getParent()).setVisibility(View.GONE);
- mLocalMediaManager.stopScan();
- mLocalMediaManager.unregisterCallback(mDeviceCallback);
+ if (mLocalMediaManager != null) {
+ mLocalMediaManager.stopScan();
+ mLocalMediaManager.unregisterCallback(mDeviceCallback);
+ mLocalMediaManager = null;
+ }
}
return true;
}
@@ -397,6 +406,7 @@ public class QSPanel extends LinearLayout implements Tunable, Callback, Brightne
if (mLocalMediaManager != null) {
mLocalMediaManager.stopScan();
mLocalMediaManager.unregisterCallback(mDeviceCallback);
+ mLocalMediaManager = null;
}
super.onDetachedFromWindow();
}
diff --git a/packages/SystemUI/src/com/android/systemui/recents/RecentsOnboarding.java b/packages/SystemUI/src/com/android/systemui/recents/RecentsOnboarding.java
index aa6444973a6f..3b3d9dde3b7e 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/RecentsOnboarding.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/RecentsOnboarding.java
@@ -17,7 +17,6 @@
package com.android.systemui.recents;
import static android.app.WindowConfiguration.ACTIVITY_TYPE_STANDARD;
-import static android.app.WindowConfiguration.ACTIVITY_TYPE_UNDEFINED;
import static android.view.WindowManagerPolicyConstants.NAV_BAR_MODE_3BUTTON;
import static com.android.systemui.Prefs.Key.DISMISSED_RECENTS_SWIPE_UP_ONBOARDING_COUNT;
@@ -27,8 +26,7 @@ import static com.android.systemui.Prefs.Key.HAS_SEEN_RECENTS_SWIPE_UP_ONBOARDIN
import static com.android.systemui.Prefs.Key.OVERVIEW_OPENED_COUNT;
import static com.android.systemui.Prefs.Key.OVERVIEW_OPENED_FROM_HOME_COUNT;
import static com.android.systemui.shared.system.LauncherEventUtil.DISMISS;
-import static com.android.systemui.shared.system.LauncherEventUtil
- .RECENTS_QUICK_SCRUB_ONBOARDING_TIP;
+import static com.android.systemui.shared.system.LauncherEventUtil.RECENTS_QUICK_SCRUB_ONBOARDING_TIP;
import static com.android.systemui.shared.system.LauncherEventUtil.RECENTS_SWIPE_UP_ONBOARDING_TIP;
import static com.android.systemui.shared.system.LauncherEventUtil.VISIBLE;
@@ -139,7 +137,7 @@ public class RecentsOnboarding {
private void onAppLaunch() {
ActivityManager.RunningTaskInfo info = ActivityManagerWrapper.getInstance()
- .getRunningTask(ACTIVITY_TYPE_UNDEFINED /* ignoreActivityType */);
+ .getRunningTask();
if (info == null) {
return;
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/EdgeBackGestureHandler.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/EdgeBackGestureHandler.java
index adca10ff7677..ecfe1168b7f0 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/EdgeBackGestureHandler.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/EdgeBackGestureHandler.java
@@ -110,10 +110,14 @@ public class EdgeBackGestureHandler implements DisplayListener,
private final float mTouchSlop;
// Duration after which we consider the event as longpress.
private final int mLongPressTimeout;
+ // The back gesture type
+ private int mBackType;
private final PointF mDownPoint = new PointF();
+ private final PointF mEndPoint = new PointF();
private boolean mThresholdCrossed = false;
private boolean mAllowGesture = false;
+ private boolean mLogGesture = false;
private boolean mInRejectedExclusion = false;
private boolean mIsOnLeftEdge;
@@ -141,24 +145,16 @@ public class EdgeBackGestureHandler implements DisplayListener,
mOverviewProxyService.notifyBackAction(true, (int) mDownPoint.x,
(int) mDownPoint.y, false /* isButton */, !mIsOnLeftEdge);
- int backtype = (mInRejectedExclusion
- ? SysUiStatsLog.BACK_GESTURE__TYPE__COMPLETED_REJECTED :
- SysUiStatsLog.BACK_GESTURE__TYPE__COMPLETED);
- SysUiStatsLog.write(SysUiStatsLog.BACK_GESTURE_REPORTED_REPORTED, backtype,
- (int) mDownPoint.y, mIsOnLeftEdge
- ? SysUiStatsLog.BACK_GESTURE__X_LOCATION__LEFT :
- SysUiStatsLog.BACK_GESTURE__X_LOCATION__RIGHT);
+ logGesture(mInRejectedExclusion
+ ? SysUiStatsLog.BACK_GESTURE__TYPE__COMPLETED_REJECTED
+ : SysUiStatsLog.BACK_GESTURE__TYPE__COMPLETED);
}
@Override
public void cancelBack() {
+ logGesture(SysUiStatsLog.BACK_GESTURE__TYPE__INCOMPLETE);
mOverviewProxyService.notifyBackAction(false, (int) mDownPoint.x,
(int) mDownPoint.y, false /* isButton */, !mIsOnLeftEdge);
- int backtype = SysUiStatsLog.BACK_GESTURE__TYPE__INCOMPLETE;
- SysUiStatsLog.write(SysUiStatsLog.BACK_GESTURE_REPORTED_REPORTED, backtype,
- (int) mDownPoint.y, mIsOnLeftEdge
- ? SysUiStatsLog.BACK_GESTURE__X_LOCATION__LEFT :
- SysUiStatsLog.BACK_GESTURE__X_LOCATION__RIGHT);
}
};
@@ -331,39 +327,55 @@ public class EdgeBackGestureHandler implements DisplayListener,
}
private boolean isWithinTouchRegion(int x, int y) {
- // Disallow if too far from the edge
- if (x > mEdgeWidthLeft + mLeftInset
- && x < (mDisplaySize.x - mEdgeWidthRight - mRightInset)) {
+ // Disallow if we are in the bottom gesture area
+ if (y >= (mDisplaySize.y - mBottomGestureHeight)) {
return false;
}
- // Disallow if we are in the bottom gesture area
- if (y >= (mDisplaySize.y - mBottomGestureHeight)) {
+ // If the point is way too far (twice the margin), it is
+ // not interesting to us for logging purposes, nor we
+ // should process it. Simply return false and keep
+ // mLogGesture = false.
+ if (x > 2 * (mEdgeWidthLeft + mLeftInset)
+ && x < (mDisplaySize.x - 2 * (mEdgeWidthRight + mRightInset))) {
return false;
}
+ // Denotes whether we should proceed with the gesture.
+ // Even if it is false, we may want to log it assuming
+ // it is not invalid due to exclusion.
+ boolean withinRange = x <= mEdgeWidthLeft + mLeftInset
+ || x >= (mDisplaySize.x - mEdgeWidthRight - mRightInset);
+
// Always allow if the user is in a transient sticky immersive state
if (mIsNavBarShownTransiently) {
- return true;
+ mLogGesture = true;
+ return withinRange;
}
- boolean isInExcludedRegion = mExcludeRegion.contains(x, y);
- if (isInExcludedRegion) {
- mOverviewProxyService.notifyBackAction(false /* completed */, -1, -1,
- false /* isButton */, !mIsOnLeftEdge);
- SysUiStatsLog.write(SysUiStatsLog.BACK_GESTURE_REPORTED_REPORTED,
- SysUiStatsLog.BACK_GESTURE__TYPE__INCOMPLETE_EXCLUDED, y,
- mIsOnLeftEdge ? SysUiStatsLog.BACK_GESTURE__X_LOCATION__LEFT :
- SysUiStatsLog.BACK_GESTURE__X_LOCATION__RIGHT);
- } else {
- mInRejectedExclusion = mUnrestrictedExcludeRegion.contains(x, y);
+ if (mExcludeRegion.contains(x, y)) {
+ if (withinRange) {
+ // Log as exclusion only if it is in acceptable range in the first place.
+ mOverviewProxyService.notifyBackAction(
+ false /* completed */, -1, -1, false /* isButton */, !mIsOnLeftEdge);
+ // We don't have the end point for logging purposes.
+ mEndPoint.x = -1;
+ mEndPoint.y = -1;
+ mLogGesture = true;
+ logGesture(SysUiStatsLog.BACK_GESTURE__TYPE__INCOMPLETE_EXCLUDED);
+ }
+ return false;
}
- return !isInExcludedRegion;
+
+ mInRejectedExclusion = mUnrestrictedExcludeRegion.contains(x, y);
+ mLogGesture = true;
+ return withinRange;
}
private void cancelGesture(MotionEvent ev) {
// Send action cancel to reset all the touch events
mAllowGesture = false;
+ mLogGesture = false;
mInRejectedExclusion = false;
MotionEvent cancelEv = MotionEvent.obtain(ev);
cancelEv.setAction(MotionEvent.ACTION_CANCEL);
@@ -371,51 +383,86 @@ public class EdgeBackGestureHandler implements DisplayListener,
cancelEv.recycle();
}
+ private void logGesture(int backType) {
+ if (!mLogGesture) {
+ return;
+ }
+ mLogGesture = false;
+ SysUiStatsLog.write(SysUiStatsLog.BACK_GESTURE_REPORTED_REPORTED, backType,
+ (int) mDownPoint.y, mIsOnLeftEdge
+ ? SysUiStatsLog.BACK_GESTURE__X_LOCATION__LEFT
+ : SysUiStatsLog.BACK_GESTURE__X_LOCATION__RIGHT,
+ (int) mDownPoint.x, (int) mDownPoint.y,
+ (int) mEndPoint.x, (int) mEndPoint.y,
+ mEdgeWidthLeft + mLeftInset,
+ mDisplaySize.x - (mEdgeWidthRight + mRightInset));
+ }
+
private void onMotionEvent(MotionEvent ev) {
int action = ev.getActionMasked();
if (action == MotionEvent.ACTION_DOWN) {
// Verify if this is in within the touch region and we aren't in immersive mode, and
// either the bouncer is showing or the notification panel is hidden
mIsOnLeftEdge = ev.getX() <= mEdgeWidthLeft + mLeftInset;
+ mLogGesture = false;
mInRejectedExclusion = false;
mAllowGesture = !QuickStepContract.isBackGestureDisabled(mSysUiFlags)
&& isWithinTouchRegion((int) ev.getX(), (int) ev.getY());
if (mAllowGesture) {
mEdgeBackPlugin.setIsLeftPanel(mIsOnLeftEdge);
mEdgeBackPlugin.onMotionEvent(ev);
-
+ }
+ if (mLogGesture) {
mDownPoint.set(ev.getX(), ev.getY());
+ mEndPoint.set(-1, -1);
mThresholdCrossed = false;
}
-
- } else if (mAllowGesture) {
+ } else if (mAllowGesture || mLogGesture) {
if (!mThresholdCrossed) {
+ mEndPoint.x = (int) ev.getX();
+ mEndPoint.y = (int) ev.getY();
if (action == MotionEvent.ACTION_POINTER_DOWN) {
- // We do not support multi touch for back gesture
- cancelGesture(ev);
+ if (mAllowGesture) {
+ logGesture(SysUiStatsLog.BACK_GESTURE__TYPE__INCOMPLETE_MULTI_TOUCH);
+ // We do not support multi touch for back gesture
+ cancelGesture(ev);
+ }
+ mLogGesture = false;
return;
} else if (action == MotionEvent.ACTION_MOVE) {
if ((ev.getEventTime() - ev.getDownTime()) > mLongPressTimeout) {
- cancelGesture(ev);
+ if (mAllowGesture) {
+ logGesture(SysUiStatsLog.BACK_GESTURE__TYPE__INCOMPLETE_LONG_PRESS);
+ cancelGesture(ev);
+ }
+ mLogGesture = false;
return;
}
float dx = Math.abs(ev.getX() - mDownPoint.x);
float dy = Math.abs(ev.getY() - mDownPoint.y);
if (dy > dx && dy > mTouchSlop) {
- cancelGesture(ev);
+ if (mAllowGesture) {
+ logGesture(SysUiStatsLog.BACK_GESTURE__TYPE__INCOMPLETE_VERTICAL_MOVE);
+ cancelGesture(ev);
+ }
+ mLogGesture = false;
return;
-
} else if (dx > dy && dx > mTouchSlop) {
- mThresholdCrossed = true;
- // Capture inputs
- mInputMonitor.pilferPointers();
+ if (mAllowGesture) {
+ mThresholdCrossed = true;
+ // Capture inputs
+ mInputMonitor.pilferPointers();
+ } else {
+ logGesture(SysUiStatsLog.BACK_GESTURE__TYPE__INCOMPLETE_FAR_FROM_EDGE);
+ }
}
}
-
}
- // forward touch
- mEdgeBackPlugin.onMotionEvent(ev);
+ if (mAllowGesture) {
+ // forward touch
+ mEdgeBackPlugin.onMotionEvent(ev);
+ }
}
Dependency.get(ProtoTracer.class).update();
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/WifiSignalController.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/WifiSignalController.java
index 7c963869ed47..c2fc18fe21a1 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/WifiSignalController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/WifiSignalController.java
@@ -37,10 +37,10 @@ import java.util.Objects;
public class WifiSignalController extends
SignalController<WifiSignalController.WifiState, SignalController.IconGroup> {
- private final boolean mHasMobileData;
+ private final boolean mHasMobileDataFeature;
private final WifiStatusTracker mWifiTracker;
- public WifiSignalController(Context context, boolean hasMobileData,
+ public WifiSignalController(Context context, boolean hasMobileDataFeature,
CallbackHandler callbackHandler, NetworkControllerImpl networkController,
WifiManager wifiManager) {
super("WifiSignalController", context, NetworkCapabilities.TRANSPORT_WIFI,
@@ -52,7 +52,7 @@ public class WifiSignalController extends
mWifiTracker = new WifiStatusTracker(mContext, wifiManager, networkScoreManager,
connectivityManager, this::handleStatusUpdated);
mWifiTracker.setListening(true);
- mHasMobileData = hasMobileData;
+ mHasMobileDataFeature = hasMobileDataFeature;
if (wifiManager != null) {
wifiManager.registerTrafficStateCallback(context.getMainExecutor(),
new WifiTrafficStateCallback());
@@ -85,9 +85,10 @@ public class WifiSignalController extends
// only show wifi in the cluster if connected or if wifi-only
boolean visibleWhenEnabled = mContext.getResources().getBoolean(
R.bool.config_showWifiIndicatorWhenEnabled);
- boolean wifiVisible = mCurrentState.enabled
- && ((mCurrentState.connected && mCurrentState.inetCondition == 1)
- || !mHasMobileData || visibleWhenEnabled);
+ boolean wifiVisible = mCurrentState.enabled && (
+ (mCurrentState.connected && mCurrentState.inetCondition == 1)
+ || !mHasMobileDataFeature || mWifiTracker.isDefaultNetwork
+ || visibleWhenEnabled);
String wifiDesc = mCurrentState.connected ? mCurrentState.ssid : null;
boolean ssidPresent = wifiVisible && mCurrentState.ssid != null;
String contentDescription = getTextIfExists(getContentDescription()).toString();
diff --git a/packages/SystemUI/tests/src/com/android/keyguard/KeyguardUpdateMonitorTest.java b/packages/SystemUI/tests/src/com/android/keyguard/KeyguardUpdateMonitorTest.java
index 9d9ba1bc91b9..eecde7218d28 100644
--- a/packages/SystemUI/tests/src/com/android/keyguard/KeyguardUpdateMonitorTest.java
+++ b/packages/SystemUI/tests/src/com/android/keyguard/KeyguardUpdateMonitorTest.java
@@ -52,6 +52,7 @@ import android.hardware.face.FaceManager;
import android.hardware.fingerprint.FingerprintManager;
import android.os.Bundle;
import android.os.Handler;
+import android.os.IRemoteCallback;
import android.os.UserHandle;
import android.os.UserManager;
import android.telephony.ServiceState;
@@ -63,6 +64,7 @@ import android.testing.TestableContext;
import android.testing.TestableLooper;
import com.android.internal.telephony.TelephonyIntents;
+import com.android.keyguard.KeyguardUpdateMonitor.BiometricAuthenticated;
import com.android.systemui.SysuiTestCase;
import com.android.systemui.broadcast.BroadcastDispatcher;
import com.android.systemui.dump.DumpManager;
@@ -506,6 +508,24 @@ public class KeyguardUpdateMonitorTest extends SysuiTestCase {
}
@Test
+ public void testBiometricsCleared_whenUserSwitches() throws Exception {
+ final IRemoteCallback reply = new IRemoteCallback.Stub() {
+ @Override
+ public void sendResult(Bundle data) {} // do nothing
+ };
+ final BiometricAuthenticated dummyAuthentication =
+ new BiometricAuthenticated(true /* authenticated */, true /* strong */);
+ mKeyguardUpdateMonitor.mUserFaceAuthenticated.put(0 /* user */, dummyAuthentication);
+ mKeyguardUpdateMonitor.mUserFingerprintAuthenticated.put(0 /* user */, dummyAuthentication);
+ assertThat(mKeyguardUpdateMonitor.mUserFingerprintAuthenticated.size()).isEqualTo(1);
+ assertThat(mKeyguardUpdateMonitor.mUserFaceAuthenticated.size()).isEqualTo(1);
+
+ mKeyguardUpdateMonitor.handleUserSwitching(10 /* user */, reply);
+ assertThat(mKeyguardUpdateMonitor.mUserFingerprintAuthenticated.size()).isEqualTo(0);
+ assertThat(mKeyguardUpdateMonitor.mUserFaceAuthenticated.size()).isEqualTo(0);
+ }
+
+ @Test
public void testGetUserCanSkipBouncer_whenTrust() {
int user = KeyguardUpdateMonitor.getCurrentUser();
mKeyguardUpdateMonitor.onTrustChanged(true /* enabled */, user, 0 /* flags */);
diff --git a/packages/SystemUI/tests/src/com/android/systemui/bubbles/BubbleControllerTest.java b/packages/SystemUI/tests/src/com/android/systemui/bubbles/BubbleControllerTest.java
index 4f16031741bc..6f3fbb9cbd2c 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/bubbles/BubbleControllerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/bubbles/BubbleControllerTest.java
@@ -92,6 +92,8 @@ import com.android.systemui.statusbar.policy.ZenModeController;
import com.android.systemui.util.FloatingContentCoordinator;
import com.android.systemui.util.InjectionInflationController;
+import com.google.common.collect.ImmutableList;
+
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
@@ -318,6 +320,23 @@ public class BubbleControllerTest extends SysuiTestCase {
}
@Test
+ public void testPromoteBubble_autoExpand() {
+ mBubbleController.updateBubble(mRow2.getEntry());
+ mBubbleController.updateBubble(mRow.getEntry());
+ mBubbleController.removeBubble(
+ mRow.getEntry(), BubbleController.DISMISS_USER_GESTURE);
+
+ Bubble b = mBubbleData.getOverflowBubbleWithKey(mRow.getEntry().getKey());
+ assertThat(mBubbleData.getOverflowBubbles()).isEqualTo(ImmutableList.of(b));
+
+ Bubble b2 = mBubbleData.getBubbleWithKey(mRow2.getEntry().getKey());
+ assertThat(mBubbleData.getSelectedBubble()).isEqualTo(b2);
+
+ mBubbleController.promoteBubbleFromOverflow(b);
+ assertThat(mBubbleData.getSelectedBubble()).isEqualTo(b);
+ }
+
+ @Test
public void testRemoveBubble_withDismissedNotif() {
mEntryListener.onPendingEntryAdded(mRow.getEntry());
mBubbleController.updateBubble(mRow.getEntry());
diff --git a/packages/SystemUI/tests/src/com/android/systemui/controls/controller/ControlsControllerImplTest.kt b/packages/SystemUI/tests/src/com/android/systemui/controls/controller/ControlsControllerImplTest.kt
index d5a654dc2b6f..eb4d438600d8 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/controls/controller/ControlsControllerImplTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/controls/controller/ControlsControllerImplTest.kt
@@ -307,6 +307,7 @@ class ControlsControllerImplTest : SysuiTestCase() {
assertEquals(1, controls.size)
val controlStatus = controls[0]
assertEquals(TEST_CONTROL_ID, controlStatus.control.controlId)
+ assertEquals(TEST_STRUCTURE_INFO.structure, controlStatus.control.structure)
assertTrue(controlStatus.favorite)
assertTrue(controlStatus.removed)
@@ -337,6 +338,7 @@ class ControlsControllerImplTest : SysuiTestCase() {
assertEquals(1, controls.size)
val controlStatus = controls[0]
assertEquals(TEST_CONTROL_ID, controlStatus.control.controlId)
+ assertEquals(TEST_STRUCTURE_INFO.structure, controlStatus.control.structure)
assertTrue(controlStatus.favorite)
assertFalse(controlStatus.removed)
diff --git a/packages/Tethering/common/TetheringLib/Android.bp b/packages/Tethering/common/TetheringLib/Android.bp
index 00d0d9c428ff..6af5fe54f281 100644
--- a/packages/Tethering/common/TetheringLib/Android.bp
+++ b/packages/Tethering/common/TetheringLib/Android.bp
@@ -126,17 +126,17 @@ droidstubs {
java_library {
name: "framework-tethering-stubs-publicapi",
srcs: [":framework-tethering-stubs-srcs-publicapi"],
- sdk_version: "current",
+ defaults: ["framework-module-stubs-lib-defaults-publicapi"],
}
java_library {
name: "framework-tethering-stubs-systemapi",
srcs: [":framework-tethering-stubs-srcs-systemapi"],
- sdk_version: "system_current",
+ defaults: ["framework-module-stubs-lib-defaults-systemapi"],
}
java_library {
name: "framework-tethering-stubs-module_libs_api",
srcs: [":framework-tethering-stubs-srcs-module_libs_api"],
- sdk_version: "module_current",
+ defaults: ["framework-module-stubs-lib-defaults-systemapi"],
}
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 36113acf97d3..c84892d675f9 100644
--- a/packages/Tethering/src/com/android/server/connectivity/tethering/Tethering.java
+++ b/packages/Tethering/src/com/android/server/connectivity/tethering/Tethering.java
@@ -303,7 +303,8 @@ public class Tethering {
final UserManager userManager = (UserManager) mContext.getSystemService(
Context.USER_SERVICE);
- mTetheringRestriction = new UserRestrictionActionListener(userManager, this);
+ mTetheringRestriction = new UserRestrictionActionListener(
+ userManager, this, mNotificationUpdater);
mExecutor = new TetheringThreadExecutor(mHandler);
mActiveDataSubIdListener = new ActiveDataSubIdListener(mExecutor);
@@ -369,9 +370,10 @@ public class Tethering {
mActiveDataSubId = subId;
updateConfiguration();
+ mNotificationUpdater.onActiveDataSubscriptionIdChanged(subId);
// To avoid launching unexpected provisioning checks, ignore re-provisioning
// when no CarrierConfig loaded yet. Assume reevaluateSimCardProvisioning()
- // ill be triggered again when CarrierConfig is loaded.
+ // will be triggered again when CarrierConfig is loaded.
if (mEntitlementMgr.getCarrierConfig(mConfig) != null) {
mEntitlementMgr.reevaluateSimCardProvisioning(mConfig);
} else {
@@ -431,9 +433,7 @@ public class Tethering {
// Called by wifi when the number of soft AP clients changed.
@Override
public void onConnectedClientsChanged(final List<WifiClient> clients) {
- if (mConnectedClientsTracker.updateConnectedClients(mForwardedDownstreams, clients)) {
- reportTetherClientsChanged(mConnectedClientsTracker.getLastTetheredClients());
- }
+ updateConnectedClients(clients);
}
}
@@ -635,7 +635,10 @@ public class Tethering {
Context.ETHERNET_SERVICE);
synchronized (mPublicSync) {
if (enable) {
- if (mEthernetCallback != null) return TETHER_ERROR_NO_ERROR;
+ if (mEthernetCallback != null) {
+ Log.d(TAG, "Ethernet tethering already started");
+ return TETHER_ERROR_NO_ERROR;
+ }
mEthernetCallback = new EthernetCallback();
mEthernetIfaceRequest = em.requestTetheredInterface(mExecutor, mEthernetCallback);
@@ -996,11 +999,14 @@ public class Tethering {
protected static class UserRestrictionActionListener {
private final UserManager mUserManager;
private final Tethering mWrapper;
+ private final TetheringNotificationUpdater mNotificationUpdater;
public boolean mDisallowTethering;
- public UserRestrictionActionListener(UserManager um, Tethering wrapper) {
+ public UserRestrictionActionListener(@NonNull UserManager um, @NonNull Tethering wrapper,
+ @NonNull TetheringNotificationUpdater updater) {
mUserManager = um;
mWrapper = wrapper;
+ mNotificationUpdater = updater;
mDisallowTethering = false;
}
@@ -1019,13 +1025,21 @@ public class Tethering {
return;
}
- // TODO: Add user restrictions notification.
- final boolean isTetheringActiveOnDevice = (mWrapper.getTetheredIfaces().length != 0);
-
- if (newlyDisallowed && isTetheringActiveOnDevice) {
- mWrapper.untetherAll();
- // TODO(b/148139325): send tetheringSupported on restriction change
+ if (!newlyDisallowed) {
+ // Clear the restricted notification when user is allowed to have tethering
+ // function.
+ mNotificationUpdater.tetheringRestrictionLifted();
+ return;
}
+
+ // Restricted notification is shown when tethering function is disallowed on
+ // user's device.
+ mNotificationUpdater.notifyTetheringDisabledByRestriction();
+
+ // Untether from all downstreams since tethering is disallowed.
+ mWrapper.untetherAll();
+
+ // TODO(b/148139325): send tetheringSupported on restriction change
}
}
@@ -1559,6 +1573,7 @@ public class Tethering {
mIPv6TetheringCoordinator.removeActiveDownstream(who);
mOffload.excludeDownstreamInterface(who.interfaceName());
mForwardedDownstreams.remove(who);
+ updateConnectedClients(null /* wifiClients */);
// If this is a Wi-Fi interface, tell WifiManager of any errors
// or the inactive serving state.
@@ -2141,6 +2156,12 @@ public class Tethering {
return false;
}
+ private void updateConnectedClients(final List<WifiClient> wifiClients) {
+ if (mConnectedClientsTracker.updateConnectedClients(mForwardedDownstreams, wifiClients)) {
+ reportTetherClientsChanged(mConnectedClientsTracker.getLastTetheredClients());
+ }
+ }
+
private IpServer.Callback makeControlCallback() {
return new IpServer.Callback() {
@Override
@@ -2155,10 +2176,7 @@ public class Tethering {
@Override
public void dhcpLeasesChanged() {
- if (mConnectedClientsTracker.updateConnectedClients(
- mForwardedDownstreams, null /* wifiClients */)) {
- reportTetherClientsChanged(mConnectedClientsTracker.getLastTetheredClients());
- }
+ updateConnectedClients(null /* wifiClients */);
}
};
}
diff --git a/packages/Tethering/src/com/android/server/connectivity/tethering/TetheringNotificationUpdater.java b/packages/Tethering/src/com/android/server/connectivity/tethering/TetheringNotificationUpdater.java
index b97f75268a3b..992cdd8de6a7 100644
--- a/packages/Tethering/src/com/android/server/connectivity/tethering/TetheringNotificationUpdater.java
+++ b/packages/Tethering/src/com/android/server/connectivity/tethering/TetheringNotificationUpdater.java
@@ -29,12 +29,14 @@ import android.content.Intent;
import android.content.res.Resources;
import android.os.UserHandle;
import android.provider.Settings;
+import android.telephony.SubscriptionManager;
import android.text.TextUtils;
import android.util.Log;
import android.util.SparseArray;
import androidx.annotation.ArrayRes;
import androidx.annotation.DrawableRes;
+import androidx.annotation.IntDef;
import androidx.annotation.IntRange;
import androidx.annotation.NonNull;
@@ -54,10 +56,15 @@ import com.android.networkstack.tethering.R;
public class TetheringNotificationUpdater {
private static final String TAG = TetheringNotificationUpdater.class.getSimpleName();
private static final String CHANNEL_ID = "TETHERING_STATUS";
+ private static final String WIFI_DOWNSTREAM = "WIFI";
+ private static final String USB_DOWNSTREAM = "USB";
+ private static final String BLUETOOTH_DOWNSTREAM = "BT";
private static final boolean NOTIFY_DONE = true;
private static final boolean NO_NOTIFY = false;
// Id to update and cancel tethering notification. Must be unique within the tethering app.
- private static final int NOTIFY_ID = 20191115;
+ private static final int ENABLE_NOTIFICATION_ID = 1000;
+ // Id to update and cancel restricted notification. Must be unique within the tethering app.
+ private static final int RESTRICTED_NOTIFICATION_ID = 1001;
@VisibleForTesting
static final int NO_ICON_ID = 0;
@VisibleForTesting
@@ -65,14 +72,25 @@ public class TetheringNotificationUpdater {
private final Context mContext;
private final NotificationManager mNotificationManager;
private final NotificationChannel mChannel;
- // Downstream type is one of ConnectivityManager.TETHERING_* constants, 0 1 or 2.
- // This value has to be made 1 2 and 4, and OR'd with the others.
+
// WARNING : the constructor is called on a different thread. Thread safety therefore
// relies on this value being initialized to 0, and not any other value. If you need
// to change this, you will need to change the thread where the constructor is invoked,
// or to introduce synchronization.
+ // Downstream type is one of ConnectivityManager.TETHERING_* constants, 0 1 or 2.
+ // This value has to be made 1 2 and 4, and OR'd with the others.
private int mDownstreamTypesMask = DOWNSTREAM_NONE;
+ // WARNING : this value is not able to being initialized to 0 and must have volatile because
+ // telephony service is not guaranteed that is up before tethering service starts. If telephony
+ // is up later than tethering, TetheringNotificationUpdater will use incorrect and valid
+ // subscription id(0) to query resources. Therefore, initialized subscription id must be
+ // INVALID_SUBSCRIPTION_ID.
+ private volatile int mActiveDataSubId = SubscriptionManager.INVALID_SUBSCRIPTION_ID;
+
+ @IntDef({ENABLE_NOTIFICATION_ID, RESTRICTED_NOTIFICATION_ID})
+ @interface NotificationId {}
+
public TetheringNotificationUpdater(@NonNull final Context context) {
mContext = context;
mNotificationManager = (NotificationManager) context.createContextAsUser(UserHandle.ALL, 0)
@@ -88,19 +106,46 @@ public class TetheringNotificationUpdater {
public void onDownstreamChanged(@IntRange(from = 0, to = 7) final int downstreamTypesMask) {
if (mDownstreamTypesMask == downstreamTypesMask) return;
mDownstreamTypesMask = downstreamTypesMask;
- updateNotification();
+ updateEnableNotification();
+ }
+
+ /** Called when active data subscription id changed */
+ public void onActiveDataSubscriptionIdChanged(final int subId) {
+ if (mActiveDataSubId == subId) return;
+ mActiveDataSubId = subId;
+ updateEnableNotification();
}
- private void updateNotification() {
+ @VisibleForTesting
+ Resources getResourcesForSubId(@NonNull final Context c, final int subId) {
+ return SubscriptionManager.getResourcesForSubId(c, subId);
+ }
+
+ private void updateEnableNotification() {
final boolean tetheringInactive = mDownstreamTypesMask <= DOWNSTREAM_NONE;
if (tetheringInactive || setupNotification() == NO_NOTIFY) {
- clearNotification();
+ clearNotification(ENABLE_NOTIFICATION_ID);
}
}
- private void clearNotification() {
- mNotificationManager.cancel(null /* tag */, NOTIFY_ID);
+ @VisibleForTesting
+ void tetheringRestrictionLifted() {
+ clearNotification(RESTRICTED_NOTIFICATION_ID);
+ }
+
+ private void clearNotification(@NotificationId final int id) {
+ mNotificationManager.cancel(null /* tag */, id);
+ }
+
+ @VisibleForTesting
+ void notifyTetheringDisabledByRestriction() {
+ final Resources res = getResourcesForSubId(mContext, mActiveDataSubId);
+ final String title = res.getString(R.string.disable_tether_notification_title);
+ final String message = res.getString(R.string.disable_tether_notification_message);
+
+ showNotification(R.drawable.stat_sys_tether_general, title, message,
+ RESTRICTED_NOTIFICATION_ID);
}
/**
@@ -110,16 +155,17 @@ public class TetheringNotificationUpdater {
*
* @return downstream types mask value.
*/
+ @VisibleForTesting
@IntRange(from = 0, to = 7)
- private int getDownstreamTypesMask(@NonNull final String types) {
+ int getDownstreamTypesMask(@NonNull final String types) {
int downstreamTypesMask = DOWNSTREAM_NONE;
final String[] downstreams = types.split("\\|");
for (String downstream : downstreams) {
- if ("USB".equals(downstream.trim())) {
+ if (USB_DOWNSTREAM.equals(downstream.trim())) {
downstreamTypesMask |= (1 << TETHERING_USB);
- } else if ("WIFI".equals(downstream.trim())) {
+ } else if (WIFI_DOWNSTREAM.equals(downstream.trim())) {
downstreamTypesMask |= (1 << TETHERING_WIFI);
- } else if ("BT".equals(downstream.trim())) {
+ } else if (BLUETOOTH_DOWNSTREAM.equals(downstream.trim())) {
downstreamTypesMask |= (1 << TETHERING_BLUETOOTH);
}
}
@@ -134,9 +180,8 @@ public class TetheringNotificationUpdater {
*
* @return {@link android.util.SparseArray} with downstream types and icon id info.
*/
- @NonNull
- private SparseArray<Integer> getIcons(@ArrayRes int id) {
- final Resources res = mContext.getResources();
+ @VisibleForTesting
+ SparseArray<Integer> getIcons(@ArrayRes int id, @NonNull Resources res) {
final String[] array = res.getStringArray(id);
final SparseArray<Integer> icons = new SparseArray<>();
for (String config : array) {
@@ -161,8 +206,9 @@ public class TetheringNotificationUpdater {
}
private boolean setupNotification() {
- final Resources res = mContext.getResources();
- final SparseArray<Integer> downstreamIcons = getIcons(R.array.tethering_notification_icons);
+ final Resources res = getResourcesForSubId(mContext, mActiveDataSubId);
+ final SparseArray<Integer> downstreamIcons =
+ getIcons(R.array.tethering_notification_icons, res);
final int iconId = downstreamIcons.get(mDownstreamTypesMask, NO_ICON_ID);
if (iconId == NO_ICON_ID) return NO_NOTIFY;
@@ -170,12 +216,12 @@ public class TetheringNotificationUpdater {
final String title = res.getString(R.string.tethering_notification_title);
final String message = res.getString(R.string.tethering_notification_message);
- showNotification(iconId, title, message);
+ showNotification(iconId, title, message, ENABLE_NOTIFICATION_ID);
return NOTIFY_DONE;
}
private void showNotification(@DrawableRes final int iconId, @NonNull final String title,
- @NonNull final String message) {
+ @NonNull final String message, @NotificationId final int id) {
final Intent intent = new Intent(Settings.ACTION_TETHER_SETTINGS);
final PendingIntent pi = PendingIntent.getActivity(
mContext.createContextAsUser(UserHandle.CURRENT, 0),
@@ -193,6 +239,6 @@ public class TetheringNotificationUpdater {
.setContentIntent(pi)
.build();
- mNotificationManager.notify(null /* tag */, NOTIFY_ID, notification);
+ mNotificationManager.notify(null /* tag */, id, notification);
}
}
diff --git a/packages/Tethering/tests/unit/src/com/android/server/connectivity/tethering/TetheringNotificationUpdaterTest.kt b/packages/Tethering/tests/unit/src/com/android/server/connectivity/tethering/TetheringNotificationUpdaterTest.kt
new file mode 100644
index 000000000000..b86949185c69
--- /dev/null
+++ b/packages/Tethering/tests/unit/src/com/android/server/connectivity/tethering/TetheringNotificationUpdaterTest.kt
@@ -0,0 +1,262 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.server.connectivity.tethering
+
+import android.app.Notification
+import android.app.NotificationManager
+import android.content.Context
+import android.content.res.Resources
+import android.net.ConnectivityManager.TETHERING_BLUETOOTH
+import android.net.ConnectivityManager.TETHERING_USB
+import android.net.ConnectivityManager.TETHERING_WIFI
+import android.os.UserHandle
+import android.telephony.SubscriptionManager.INVALID_SUBSCRIPTION_ID
+import androidx.test.platform.app.InstrumentationRegistry
+import androidx.test.filters.SmallTest
+import androidx.test.runner.AndroidJUnit4
+import com.android.internal.util.test.BroadcastInterceptingContext
+import com.android.networkstack.tethering.R
+import com.android.server.connectivity.tethering.TetheringNotificationUpdater.DOWNSTREAM_NONE
+import org.junit.Assert.assertEquals
+import org.junit.Before
+import org.junit.Test
+import org.junit.runner.RunWith
+import org.mockito.ArgumentCaptor
+import org.mockito.ArgumentMatchers.any
+import org.mockito.ArgumentMatchers.anyInt
+import org.mockito.ArgumentMatchers.eq
+import org.mockito.Mock
+import org.mockito.Mockito.doReturn
+import org.mockito.Mockito.never
+import org.mockito.Mockito.reset
+import org.mockito.Mockito.times
+import org.mockito.Mockito.verifyZeroInteractions
+import org.mockito.Mockito.verify
+import org.mockito.MockitoAnnotations
+
+const val TEST_SUBID = 1
+const val WIFI_ICON_ID = 1
+const val USB_ICON_ID = 2
+const val BT_ICON_ID = 3
+const val GENERAL_ICON_ID = 4
+const val WIFI_MASK = 1 shl TETHERING_WIFI
+const val USB_MASK = 1 shl TETHERING_USB
+const val BT_MASK = 1 shl TETHERING_BLUETOOTH
+const val TITTLE = "Tethering active"
+const val MESSAGE = "Tap here to set up."
+const val TEST_TITTLE = "Hotspot active"
+const val TEST_MESSAGE = "Tap to set up hotspot."
+
+@RunWith(AndroidJUnit4::class)
+@SmallTest
+class TetheringNotificationUpdaterTest {
+ // lateinit used here for mocks as they need to be reinitialized between each test and the test
+ // should crash if they are used before being initialized.
+ @Mock private lateinit var mockContext: Context
+ @Mock private lateinit var notificationManager: NotificationManager
+ @Mock private lateinit var defaultResources: Resources
+ @Mock private lateinit var testResources: Resources
+
+ // lateinit for this class under test, as it should be reset to a different instance for every
+ // tests but should always be initialized before use (or the test should crash).
+ private lateinit var notificationUpdater: TetheringNotificationUpdater
+
+ private val ENABLE_ICON_CONFIGS = arrayOf(
+ "USB;android.test:drawable/usb", "BT;android.test:drawable/bluetooth",
+ "WIFI|BT;android.test:drawable/general", "WIFI|USB;android.test:drawable/general",
+ "USB|BT;android.test:drawable/general", "WIFI|USB|BT;android.test:drawable/general")
+
+ private inner class TestContext(c: Context) : BroadcastInterceptingContext(c) {
+ override fun createContextAsUser(user: UserHandle, flags: Int) =
+ if (user == UserHandle.ALL) mockContext else this
+ }
+
+ private inner class WrappedNotificationUpdater(c: Context) : TetheringNotificationUpdater(c) {
+ override fun getResourcesForSubId(context: Context, subId: Int) =
+ if (subId == TEST_SUBID) testResources else defaultResources
+ }
+
+ private fun setupResources() {
+ doReturn(ENABLE_ICON_CONFIGS).`when`(defaultResources)
+ .getStringArray(R.array.tethering_notification_icons)
+ doReturn(arrayOf("WIFI;android.test:drawable/wifi")).`when`(testResources)
+ .getStringArray(R.array.tethering_notification_icons)
+ doReturn(TITTLE).`when`(defaultResources).getString(R.string.tethering_notification_title)
+ doReturn(MESSAGE).`when`(defaultResources)
+ .getString(R.string.tethering_notification_message)
+ doReturn(TEST_TITTLE).`when`(testResources).getString(R.string.tethering_notification_title)
+ doReturn(TEST_MESSAGE).`when`(testResources)
+ .getString(R.string.tethering_notification_message)
+ doReturn(USB_ICON_ID).`when`(defaultResources)
+ .getIdentifier(eq("android.test:drawable/usb"), any(), any())
+ doReturn(BT_ICON_ID).`when`(defaultResources)
+ .getIdentifier(eq("android.test:drawable/bluetooth"), any(), any())
+ doReturn(GENERAL_ICON_ID).`when`(defaultResources)
+ .getIdentifier(eq("android.test:drawable/general"), any(), any())
+ doReturn(WIFI_ICON_ID).`when`(testResources)
+ .getIdentifier(eq("android.test:drawable/wifi"), any(), any())
+ }
+
+ @Before
+ fun setUp() {
+ MockitoAnnotations.initMocks(this)
+ val context = TestContext(InstrumentationRegistry.getInstrumentation().context)
+ doReturn(notificationManager).`when`(mockContext)
+ .getSystemService(Context.NOTIFICATION_SERVICE)
+ notificationUpdater = WrappedNotificationUpdater(context)
+ setupResources()
+ }
+
+ private fun Notification.title() = this.extras.getString(Notification.EXTRA_TITLE)
+ private fun Notification.text() = this.extras.getString(Notification.EXTRA_TEXT)
+
+ private fun verifyNotification(iconId: Int = 0, title: String = "", text: String = "") {
+ verify(notificationManager, never()).cancel(any(), anyInt())
+
+ val notificationCaptor = ArgumentCaptor.forClass(Notification::class.java)
+ verify(notificationManager, times(1))
+ .notify(any(), anyInt(), notificationCaptor.capture())
+
+ val notification = notificationCaptor.getValue()
+ assertEquals(iconId, notification.smallIcon.resId)
+ assertEquals(title, notification.title())
+ assertEquals(text, notification.text())
+
+ reset(notificationManager)
+ }
+
+ private fun verifyNoNotification() {
+ verify(notificationManager, times(1)).cancel(any(), anyInt())
+ verify(notificationManager, never()).notify(any(), anyInt(), any())
+
+ reset(notificationManager)
+ }
+
+ @Test
+ fun testNotificationWithDownstreamChanged() {
+ // Wifi downstream. No notification.
+ notificationUpdater.onDownstreamChanged(WIFI_MASK)
+ verifyNoNotification()
+
+ // Same downstream changed. Nothing happened.
+ notificationUpdater.onDownstreamChanged(WIFI_MASK)
+ verifyZeroInteractions(notificationManager)
+
+ // Wifi and usb downstreams. Show enable notification
+ notificationUpdater.onDownstreamChanged(WIFI_MASK or USB_MASK)
+ verifyNotification(GENERAL_ICON_ID, TITTLE, MESSAGE)
+
+ // Usb downstream. Still show enable notification.
+ notificationUpdater.onDownstreamChanged(USB_MASK)
+ verifyNotification(USB_ICON_ID, TITTLE, MESSAGE)
+
+ // No downstream. No notification.
+ notificationUpdater.onDownstreamChanged(DOWNSTREAM_NONE)
+ verifyNoNotification()
+ }
+
+ @Test
+ fun testNotificationWithActiveDataSubscriptionIdChanged() {
+ // Usb downstream. Showed enable notification with default resource.
+ notificationUpdater.onDownstreamChanged(USB_MASK)
+ verifyNotification(USB_ICON_ID, TITTLE, MESSAGE)
+
+ // Same subId changed. Nothing happened.
+ notificationUpdater.onActiveDataSubscriptionIdChanged(INVALID_SUBSCRIPTION_ID)
+ verifyZeroInteractions(notificationManager)
+
+ // Set test sub id. Clear notification with test resource.
+ notificationUpdater.onActiveDataSubscriptionIdChanged(TEST_SUBID)
+ verifyNoNotification()
+
+ // Wifi downstream. Show enable notification with test resource.
+ notificationUpdater.onDownstreamChanged(WIFI_MASK)
+ verifyNotification(WIFI_ICON_ID, TEST_TITTLE, TEST_MESSAGE)
+
+ // No downstream. No notification.
+ notificationUpdater.onDownstreamChanged(DOWNSTREAM_NONE)
+ verifyNoNotification()
+ }
+
+ private fun assertIconNumbers(number: Int, configs: Array<String?>) {
+ doReturn(configs).`when`(defaultResources)
+ .getStringArray(R.array.tethering_notification_icons)
+ assertEquals(number, notificationUpdater.getIcons(
+ R.array.tethering_notification_icons, defaultResources).size())
+ }
+
+ @Test
+ fun testGetIcons() {
+ assertIconNumbers(0, arrayOfNulls<String>(0))
+ assertIconNumbers(0, arrayOf(null, ""))
+ assertIconNumbers(3, arrayOf(
+ // These configurations are invalid with wrong strings or symbols.
+ ";", ",", "|", "|,;", "WIFI", "1;2", " U SB; ", "bt;", "WIFI;USB;BT", "WIFI|USB|BT",
+ "WIFI,BT,USB", " WIFI| | | USB, test:drawable/test",
+ // This configuration is valid with two downstream types (USB, BT).
+ "USB|,,,,,|BT;drawable/test ",
+ // This configuration is valid with one downstream types (WIFI).
+ " WIFI ; android.test:drawable/xxx "))
+ }
+
+ @Test
+ fun testGetDownstreamTypesMask() {
+ assertEquals(DOWNSTREAM_NONE, notificationUpdater.getDownstreamTypesMask(""))
+ assertEquals(DOWNSTREAM_NONE, notificationUpdater.getDownstreamTypesMask("1"))
+ assertEquals(DOWNSTREAM_NONE, notificationUpdater.getDownstreamTypesMask("WIFI_P2P"))
+ assertEquals(DOWNSTREAM_NONE, notificationUpdater.getDownstreamTypesMask("usb"))
+ assertEquals(WIFI_MASK, notificationUpdater.getDownstreamTypesMask(" WIFI "))
+ assertEquals(USB_MASK, notificationUpdater.getDownstreamTypesMask("USB | B T"))
+ assertEquals(BT_MASK, notificationUpdater.getDownstreamTypesMask(" WIFI: | BT"))
+ assertEquals(WIFI_MASK or USB_MASK,
+ notificationUpdater.getDownstreamTypesMask("1|2|USB|WIFI|BLUETOOTH||"))
+ }
+
+ @Test
+ fun testSetupRestrictedNotification() {
+ val title = InstrumentationRegistry.getInstrumentation().context.resources
+ .getString(R.string.disable_tether_notification_title)
+ val message = InstrumentationRegistry.getInstrumentation().context.resources
+ .getString(R.string.disable_tether_notification_message)
+ val disallowTitle = "Tether function is disallowed"
+ val disallowMessage = "Please contact your admin"
+ doReturn(title).`when`(defaultResources)
+ .getString(R.string.disable_tether_notification_title)
+ doReturn(message).`when`(defaultResources)
+ .getString(R.string.disable_tether_notification_message)
+ doReturn(disallowTitle).`when`(testResources)
+ .getString(R.string.disable_tether_notification_title)
+ doReturn(disallowMessage).`when`(testResources)
+ .getString(R.string.disable_tether_notification_message)
+
+ // User restrictions on. Show restricted notification.
+ notificationUpdater.notifyTetheringDisabledByRestriction()
+ verifyNotification(R.drawable.stat_sys_tether_general, title, message)
+
+ // User restrictions off. Clear notification.
+ notificationUpdater.tetheringRestrictionLifted()
+ verifyNoNotification()
+
+ // Set test sub id. No notification.
+ notificationUpdater.onActiveDataSubscriptionIdChanged(TEST_SUBID)
+ verifyNoNotification()
+
+ // User restrictions on again. Show restricted notification with test resource.
+ notificationUpdater.notifyTetheringDisabledByRestriction()
+ verifyNotification(R.drawable.stat_sys_tether_general, disallowTitle, disallowMessage)
+ }
+} \ No newline at end of file
diff --git a/packages/Tethering/tests/unit/src/com/android/server/connectivity/tethering/TetheringTest.java b/packages/Tethering/tests/unit/src/com/android/server/connectivity/tethering/TetheringTest.java
index 60d7ad1c5b1e..5ead1106d75a 100644
--- a/packages/Tethering/tests/unit/src/com/android/server/connectivity/tethering/TetheringTest.java
+++ b/packages/Tethering/tests/unit/src/com/android/server/connectivity/tethering/TetheringTest.java
@@ -210,7 +210,6 @@ public class TetheringTest {
private PhoneStateListener mPhoneStateListener;
private InterfaceConfigurationParcel mInterfaceConfiguration;
-
private class TestContext extends BroadcastInterceptingContext {
TestContext(Context base) {
super(base);
@@ -1073,13 +1072,15 @@ public class TetheringTest {
when(mUserManager.getUserRestrictions()).thenReturn(newRestrictions);
final Tethering.UserRestrictionActionListener ural =
- new Tethering.UserRestrictionActionListener(mUserManager, mockTethering);
+ new Tethering.UserRestrictionActionListener(
+ mUserManager, mockTethering, mNotificationUpdater);
ural.mDisallowTethering = currentDisallow;
ural.onUserRestrictionsChanged();
- verify(mockTethering, times(expectedInteractionsWithShowNotification))
- .untetherAll();
+ verify(mNotificationUpdater, times(expectedInteractionsWithShowNotification))
+ .notifyTetheringDisabledByRestriction();
+ verify(mockTethering, times(expectedInteractionsWithShowNotification)).untetherAll();
}
@Test
@@ -1087,7 +1088,7 @@ public class TetheringTest {
final String[] emptyActiveIfacesList = new String[]{};
final boolean currDisallow = false;
final boolean nextDisallow = true;
- final int expectedInteractionsWithShowNotification = 0;
+ final int expectedInteractionsWithShowNotification = 1;
runUserRestrictionsChange(currDisallow, nextDisallow, emptyActiveIfacesList,
expectedInteractionsWithShowNotification);
@@ -1399,6 +1400,7 @@ public class TetheringTest {
mPhoneStateListener.onActiveDataSubscriptionIdChanged(fakeSubId);
final TetheringConfiguration newConfig = mTethering.getTetheringConfiguration();
assertEquals(fakeSubId, newConfig.activeDataSubId);
+ verify(mNotificationUpdater, times(1)).onActiveDataSubscriptionIdChanged(eq(fakeSubId));
}
@Test
diff --git a/packages/WallpaperCropper/src/com/android/wallpapercropper/WallpaperCropActivity.java b/packages/WallpaperCropper/src/com/android/wallpapercropper/WallpaperCropActivity.java
index 6112da5cd13b..fe9f60fe2859 100644
--- a/packages/WallpaperCropper/src/com/android/wallpapercropper/WallpaperCropActivity.java
+++ b/packages/WallpaperCropper/src/com/android/wallpapercropper/WallpaperCropActivity.java
@@ -37,7 +37,6 @@ import android.net.Uri;
import android.os.AsyncTask;
import android.os.Bundle;
import android.util.Log;
-import android.util.Size;
import android.view.Display;
import android.view.View;
import android.widget.Toast;
@@ -358,8 +357,8 @@ public class WallpaperCropActivity extends Activity {
// Get the crop
boolean ltr = mCropView.getLayoutDirection() == View.LAYOUT_DIRECTION_LTR;
- Size windowSize = getWindowManager().getCurrentWindowMetrics().getSize();
- boolean isPortrait = windowSize.getWidth() < windowSize.getHeight();
+ Rect windowBounds = getWindowManager().getCurrentWindowMetrics().getBounds();
+ boolean isPortrait = windowBounds.width() < windowBounds.height();
Point defaultWallpaperSize = getDefaultWallpaperSize(getResources(),
getDisplay());
diff --git a/services/Android.bp b/services/Android.bp
index 490481c7e5a2..52c5993a2862 100644
--- a/services/Android.bp
+++ b/services/Android.bp
@@ -142,6 +142,11 @@ droidstubs {
baseline_file: "api/lint-baseline.txt",
},
},
+ dist: {
+ targets: ["sdk", "win_sdk"],
+ dir: "apistubs/android/system-server/api",
+ dest: "android.txt",
+ },
}
java_library {
diff --git a/services/accessibility/java/com/android/server/accessibility/AccessibilityManagerService.java b/services/accessibility/java/com/android/server/accessibility/AccessibilityManagerService.java
index 60c3d7859984..1b180e3357d7 100644
--- a/services/accessibility/java/com/android/server/accessibility/AccessibilityManagerService.java
+++ b/services/accessibility/java/com/android/server/accessibility/AccessibilityManagerService.java
@@ -2001,17 +2001,6 @@ public class AccessibilityManagerService extends IAccessibilityManager.Stub
Settings.Secure.ACCESSIBILITY_SHORTCUT_TARGET_SERVICE,
userState.mUserId, currentTargets, str -> str);
scheduleNotifyClientsOfServicesStateChangeLocked(userState);
-
- // Disable accessibility shortcut key if there's no shortcut installed.
- if (currentTargets.isEmpty()) {
- final long identity = Binder.clearCallingIdentity();
- try {
- Settings.Secure.putIntForUser(mContext.getContentResolver(),
- Settings.Secure.ACCESSIBILITY_SHORTCUT_ENABLED, 0, userState.mUserId);
- } finally {
- Binder.restoreCallingIdentity(identity);
- }
- }
}
private boolean canRequestAndRequestsTouchExplorationLocked(
diff --git a/services/autofill/java/com/android/server/autofill/ui/InlineSuggestionFactory.java b/services/autofill/java/com/android/server/autofill/ui/InlineSuggestionFactory.java
index c39e93a84b48..2306329e689c 100644
--- a/services/autofill/java/com/android/server/autofill/ui/InlineSuggestionFactory.java
+++ b/services/autofill/java/com/android/server/autofill/ui/InlineSuggestionFactory.java
@@ -165,7 +165,8 @@ public final class InlineSuggestionFactory {
Slog.w(TAG, "InlinePresentation not found in dataset");
continue;
}
- if (!includeDataset(dataset, fieldIndex, filterText)) {
+ if (!inlinePresentation.isPinned() // don't filter pinned suggestions
+ && !includeDataset(dataset, fieldIndex, filterText)) {
continue;
}
InlineSuggestion inlineSuggestion = createInlineSuggestion(isAugmented, dataset,
diff --git a/services/core/java/com/android/server/BatteryService.java b/services/core/java/com/android/server/BatteryService.java
index f1f5005b23db..8dd4fa6d8fd1 100644
--- a/services/core/java/com/android/server/BatteryService.java
+++ b/services/core/java/com/android/server/BatteryService.java
@@ -1101,6 +1101,9 @@ public final class BatteryService extends SystemService {
* Synchronize on BatteryService.
*/
public void updateLightsLocked() {
+ if (mBatteryLight == null) {
+ return;
+ }
final int level = mHealthInfo.batteryLevel;
final int status = mHealthInfo.batteryStatus;
if (level < mLowBatteryWarningLevel) {
diff --git a/services/core/java/com/android/server/BluetoothManagerService.java b/services/core/java/com/android/server/BluetoothManagerService.java
index 03ca1c610f82..1bf559a17021 100644
--- a/services/core/java/com/android/server/BluetoothManagerService.java
+++ b/services/core/java/com/android/server/BluetoothManagerService.java
@@ -112,9 +112,13 @@ class BluetoothManagerService extends IBluetoothManager.Stub {
private static final int USER_SWITCHED_TIME_MS = 200;
// Delay for the addProxy function in msec
private static final int ADD_PROXY_DELAY_MS = 100;
+ // Delay for retrying enable and disable in msec
+ private static final int ENABLE_DISABLE_DELAY_MS = 300;
private static final int MESSAGE_ENABLE = 1;
private static final int MESSAGE_DISABLE = 2;
+ private static final int MESSAGE_HANDLE_ENABLE_DELAYED = 3;
+ private static final int MESSAGE_HANDLE_DISABLE_DELAYED = 4;
private static final int MESSAGE_REGISTER_ADAPTER = 20;
private static final int MESSAGE_UNREGISTER_ADAPTER = 21;
private static final int MESSAGE_REGISTER_STATE_CHANGE_CALLBACK = 30;
@@ -136,6 +140,7 @@ class BluetoothManagerService extends IBluetoothManager.Stub {
private static final int RESTORE_SETTING_TO_OFF = 0;
private static final int MAX_ERROR_RESTART_RETRIES = 6;
+ private static final int MAX_WAIT_FOR_ENABLE_DISABLE_RETRIES = 10;
// Bluetooth persisted setting is off
private static final int BLUETOOTH_OFF = 0;
@@ -166,6 +171,8 @@ class BluetoothManagerService extends IBluetoothManager.Stub {
private final ReentrantReadWriteLock mBluetoothLock = new ReentrantReadWriteLock();
private boolean mBinding;
private boolean mUnbinding;
+ private int mWaitForEnableRetry;
+ private int mWaitForDisableRetry;
private BluetoothAirplaneModeListener mBluetoothAirplaneModeListener;
@@ -1678,8 +1685,18 @@ class BluetoothManagerService extends IBluetoothManager.Stub {
break;
case MESSAGE_ENABLE:
+ int quietEnable = msg.arg1;
+ if (mHandler.hasMessages(MESSAGE_HANDLE_DISABLE_DELAYED)
+ || mHandler.hasMessages(MESSAGE_HANDLE_ENABLE_DELAYED)) {
+ // We are handling enable or disable right now, wait for it.
+ mHandler.sendMessageDelayed(mHandler.obtainMessage(MESSAGE_ENABLE,
+ quietEnable, 0), ENABLE_DISABLE_DELAY_MS);
+ break;
+ }
+
if (DBG) {
- Slog.d(TAG, "MESSAGE_ENABLE(" + msg.arg1 + "): mBluetooth = " + mBluetooth);
+ Slog.d(TAG, "MESSAGE_ENABLE(" + quietEnable + "): mBluetooth = "
+ + mBluetooth);
}
mHandler.removeMessages(MESSAGE_RESTART_BLUETOOTH_SERVICE);
mEnable = true;
@@ -1702,7 +1719,7 @@ class BluetoothManagerService extends IBluetoothManager.Stub {
mBluetoothLock.readLock().unlock();
}
- mQuietEnable = (msg.arg1 == 1);
+ mQuietEnable = (quietEnable == 1);
if (mBluetooth == null) {
handleEnable(mQuietEnable);
} else {
@@ -1711,8 +1728,8 @@ class BluetoothManagerService extends IBluetoothManager.Stub {
// the previous Bluetooth process has exited. The
// waiting period has three components:
// (a) Wait until the local state is STATE_OFF. This
- // is accomplished by
- // "waitForState(Set.of(BluetoothAdapter.STATE_OFF))".
+ // is accomplished by sending delay a message
+ // MESSAGE_HANDLE_ENABLE_DELAYED
// (b) Wait until the STATE_OFF state is updated to
// all components.
// (c) Wait until the Bluetooth process exits, and
@@ -1722,33 +1739,108 @@ class BluetoothManagerService extends IBluetoothManager.Stub {
// message. The delay time is backed off if Bluetooth
// continuously failed to turn on itself.
//
- waitForState(Set.of(BluetoothAdapter.STATE_OFF));
- Message restartMsg =
- mHandler.obtainMessage(MESSAGE_RESTART_BLUETOOTH_SERVICE);
- mHandler.sendMessageDelayed(restartMsg, getServiceRestartMs());
+ mWaitForEnableRetry = 0;
+ Message enableDelayedMsg =
+ mHandler.obtainMessage(MESSAGE_HANDLE_ENABLE_DELAYED);
+ mHandler.sendMessageDelayed(enableDelayedMsg, ENABLE_DISABLE_DELAY_MS);
}
break;
case MESSAGE_DISABLE:
+ if (mHandler.hasMessages(MESSAGE_HANDLE_DISABLE_DELAYED) || mBinding
+ || mHandler.hasMessages(MESSAGE_HANDLE_ENABLE_DELAYED)) {
+ // We are handling enable or disable right now, wait for it.
+ mHandler.sendMessageDelayed(mHandler.obtainMessage(MESSAGE_DISABLE),
+ ENABLE_DISABLE_DELAY_MS);
+ break;
+ }
+
if (DBG) {
- Slog.d(TAG, "MESSAGE_DISABLE: mBluetooth = " + mBluetooth);
+ Slog.d(TAG, "MESSAGE_DISABLE: mBluetooth = " + mBluetooth
+ + ", mBinding = " + mBinding);
}
mHandler.removeMessages(MESSAGE_RESTART_BLUETOOTH_SERVICE);
+
if (mEnable && mBluetooth != null) {
- waitForState(Set.of(BluetoothAdapter.STATE_ON));
+ mWaitForDisableRetry = 0;
+ Message disableDelayedMsg =
+ mHandler.obtainMessage(MESSAGE_HANDLE_DISABLE_DELAYED, 0, 0);
+ mHandler.sendMessageDelayed(disableDelayedMsg, ENABLE_DISABLE_DELAY_MS);
+ } else {
mEnable = false;
handleDisable();
- waitForState(Set.of(BluetoothAdapter.STATE_OFF,
- BluetoothAdapter.STATE_TURNING_ON,
- BluetoothAdapter.STATE_TURNING_OFF,
- BluetoothAdapter.STATE_BLE_TURNING_ON,
- BluetoothAdapter.STATE_BLE_ON,
- BluetoothAdapter.STATE_BLE_TURNING_OFF));
- } else {
+ }
+ break;
+
+ case MESSAGE_HANDLE_ENABLE_DELAYED: {
+ // The Bluetooth is turning off, wait for STATE_OFF
+ if (mState != BluetoothAdapter.STATE_OFF) {
+ if (mWaitForEnableRetry < MAX_WAIT_FOR_ENABLE_DISABLE_RETRIES) {
+ mWaitForEnableRetry++;
+ Message enableDelayedMsg =
+ mHandler.obtainMessage(MESSAGE_HANDLE_ENABLE_DELAYED);
+ mHandler.sendMessageDelayed(enableDelayedMsg, ENABLE_DISABLE_DELAY_MS);
+ break;
+ } else {
+ Slog.e(TAG, "Wait for STATE_OFF timeout");
+ }
+ }
+ // Either state is changed to STATE_OFF or reaches the maximum retry, we
+ // should move forward to the next step.
+ mWaitForEnableRetry = 0;
+ Message restartMsg =
+ mHandler.obtainMessage(MESSAGE_RESTART_BLUETOOTH_SERVICE);
+ mHandler.sendMessageDelayed(restartMsg, getServiceRestartMs());
+ Slog.d(TAG, "Handle enable is finished");
+ break;
+ }
+
+ case MESSAGE_HANDLE_DISABLE_DELAYED: {
+ boolean disabling = (msg.arg1 == 1);
+ Slog.d(TAG, "MESSAGE_HANDLE_DISABLE_DELAYED: disabling:" + disabling);
+ if (!disabling) {
+ // The Bluetooth is turning on, wait for STATE_ON
+ if (mState != BluetoothAdapter.STATE_ON) {
+ if (mWaitForDisableRetry < MAX_WAIT_FOR_ENABLE_DISABLE_RETRIES) {
+ mWaitForDisableRetry++;
+ Message disableDelayedMsg = mHandler.obtainMessage(
+ MESSAGE_HANDLE_DISABLE_DELAYED, 0, 0);
+ mHandler.sendMessageDelayed(disableDelayedMsg,
+ ENABLE_DISABLE_DELAY_MS);
+ break;
+ } else {
+ Slog.e(TAG, "Wait for STATE_ON timeout");
+ }
+ }
+ // Either state is changed to STATE_ON or reaches the maximum retry, we
+ // should move forward to the next step.
+ mWaitForDisableRetry = 0;
mEnable = false;
handleDisable();
+ // Wait for state exiting STATE_ON
+ Message disableDelayedMsg =
+ mHandler.obtainMessage(MESSAGE_HANDLE_DISABLE_DELAYED, 1, 0);
+ mHandler.sendMessageDelayed(disableDelayedMsg, ENABLE_DISABLE_DELAY_MS);
+ } else {
+ // The Bluetooth is turning off, wait for exiting STATE_ON
+ if (mState == BluetoothAdapter.STATE_ON) {
+ if (mWaitForDisableRetry < MAX_WAIT_FOR_ENABLE_DISABLE_RETRIES) {
+ mWaitForDisableRetry++;
+ Message disableDelayedMsg = mHandler.obtainMessage(
+ MESSAGE_HANDLE_DISABLE_DELAYED, 1, 0);
+ mHandler.sendMessageDelayed(disableDelayedMsg,
+ ENABLE_DISABLE_DELAY_MS);
+ break;
+ } else {
+ Slog.e(TAG, "Wait for exiting STATE_ON timeout");
+ }
+ }
+ // Either state is exited from STATE_ON or reaches the maximum retry, we
+ // should move forward to the next step.
+ Slog.d(TAG, "Handle disable is finished");
}
break;
+ }
case MESSAGE_RESTORE_USER_SETTING:
if ((msg.arg1 == RESTORE_SETTING_TO_OFF) && mEnable) {
@@ -2124,6 +2216,7 @@ class BluetoothManagerService extends IBluetoothManager.Stub {
try {
mBluetoothLock.writeLock().lock();
if ((mBluetooth == null) && (!mBinding)) {
+ Slog.d(TAG, "binding Bluetooth service");
//Start bind timeout and bind
Message timeoutMsg = mHandler.obtainMessage(MESSAGE_TIMEOUT_BIND);
mHandler.sendMessageDelayed(timeoutMsg, TIMEOUT_BIND_MS);
@@ -2493,6 +2586,12 @@ class BluetoothManagerService extends IBluetoothManager.Stub {
writer.println(" " + app.getPackageName());
}
+ writer.println("\nBluetoothManagerService:");
+ writer.println(" mEnable:" + mEnable);
+ writer.println(" mQuietEnable:" + mQuietEnable);
+ writer.println(" mEnableExternal:" + mEnableExternal);
+ writer.println(" mQuietEnableExternal:" + mQuietEnableExternal);
+
writer.println("");
writer.flush();
if (args.length == 0) {
diff --git a/services/core/java/com/android/server/NetworkManagementService.java b/services/core/java/com/android/server/NetworkManagementService.java
index 1bb3c3ac0cda..0ddfa1c16a0a 100644
--- a/services/core/java/com/android/server/NetworkManagementService.java
+++ b/services/core/java/com/android/server/NetworkManagementService.java
@@ -886,6 +886,7 @@ public class NetworkManagementService extends INetworkManagementService.Stub {
@Override
public void setIPv6AddrGenMode(String iface, int mode) throws ServiceSpecificException {
+ NetworkStack.checkNetworkStackPermission(mContext);
try {
mNetdService.setIPv6AddrGenMode(iface, mode);
} catch (RemoteException e) {
diff --git a/services/core/java/com/android/server/StorageManagerService.java b/services/core/java/com/android/server/StorageManagerService.java
index bb9446078da6..4d8c86c87e9e 100644
--- a/services/core/java/com/android/server/StorageManagerService.java
+++ b/services/core/java/com/android/server/StorageManagerService.java
@@ -43,6 +43,7 @@ import static android.os.storage.OnObbStateChangeListener.ERROR_PERMISSION_DENIE
import static android.os.storage.OnObbStateChangeListener.MOUNTED;
import static android.os.storage.OnObbStateChangeListener.UNMOUNTED;
import static android.os.storage.StorageManager.PROP_FUSE;
+import static android.os.storage.StorageManager.PROP_LEGACY_OP_STICKY;
import static android.os.storage.StorageManager.PROP_SETTINGS_FUSE;
import static com.android.internal.util.XmlUtils.readIntAttribute;
@@ -903,6 +904,7 @@ class StorageManagerService extends IStorageManager.Stub
refreshIsolatedStorageSettings();
}
});
+ updateLegacyStorageOpSticky();
// For now, simply clone property when it changes
DeviceConfig.addOnPropertiesChangedListener(DeviceConfig.NAMESPACE_STORAGE_NATIVE_BOOT,
mContext.getMainExecutor(), (properties) -> {
@@ -1779,6 +1781,13 @@ class StorageManagerService extends IStorageManager.Stub
}
}
+ private void updateLegacyStorageOpSticky() {
+ final boolean propertyValue = DeviceConfig.getBoolean(
+ DeviceConfig.NAMESPACE_STORAGE_NATIVE_BOOT,
+ "legacy_storage_op_sticky", true);
+ SystemProperties.set(PROP_LEGACY_OP_STICKY, propertyValue ? "true" : "false");
+ }
+
private void start() {
connectStoraged();
connectVold();
@@ -4450,9 +4459,8 @@ class StorageManagerService extends IStorageManager.Stub
String.format("/storage/emulated/%d/Android/data/%s/",
userId, pkg);
- int appUid =
- UserHandle.getUid(userId, mPmInternal.getPackage(pkg).getUid());
// Create package obb and data dir if it doesn't exist.
+ int appUid = UserHandle.getUid(userId, mPmInternal.getPackage(pkg).getUid());
File file = new File(packageObbDir);
if (!file.exists()) {
vold.setupAppDir(packageObbDir, appUid);
diff --git a/services/core/java/com/android/server/am/ActivityManagerService.java b/services/core/java/com/android/server/am/ActivityManagerService.java
index 4cfcd2b218d1..38405e1ccc03 100644
--- a/services/core/java/com/android/server/am/ActivityManagerService.java
+++ b/services/core/java/com/android/server/am/ActivityManagerService.java
@@ -185,8 +185,6 @@ import android.app.PendingIntent;
import android.app.ProcessMemoryState;
import android.app.ProfilerInfo;
import android.app.WaitResult;
-import android.app.WindowConfiguration.ActivityType;
-import android.app.WindowConfiguration.WindowingMode;
import android.app.backup.IBackupManager;
import android.app.usage.UsageEvents;
import android.app.usage.UsageEvents.Event;
@@ -6513,13 +6511,6 @@ public class ActivityManagerService extends IActivityManager.Stub
}
@Override
- public List<RunningTaskInfo> getFilteredTasks(int maxNum, @ActivityType int ignoreActivityType,
- @WindowingMode int ignoreWindowingMode) {
- return mActivityTaskManager.getFilteredTasks(
- maxNum, ignoreActivityType, ignoreWindowingMode);
- }
-
- @Override
public void cancelTaskWindowTransition(int taskId) {
mActivityTaskManager.cancelTaskWindowTransition(taskId);
}
@@ -8780,6 +8771,27 @@ public class ActivityManagerService extends IActivityManager.Stub
}
@Override
+ public boolean isUidActiveOrForeground(int uid, String callingPackage) {
+ if (!hasUsageStatsPermission(callingPackage)) {
+ enforceCallingPermission(android.Manifest.permission.PACKAGE_USAGE_STATS,
+ "isUidActiveOrForeground");
+ }
+ synchronized (this) {
+ final boolean isActive = isUidActiveLocked(uid);
+ if (isActive) {
+ return true;
+ }
+ }
+ final boolean isForeground = mAtmInternal.isUidForeground(uid);
+ if (isForeground) {
+ Slog.wtf(TAG, "isUidActiveOrForeground: isUidActive false but "
+ + " isUidForeground true, uid:" + uid
+ + " callingPackage:" + callingPackage);
+ }
+ return isForeground;
+ }
+
+ @Override
public void setPersistentVrThread(int tid) {
mActivityTaskManager.setPersistentVrThread(tid);
}
diff --git a/services/core/java/com/android/server/am/ProcessList.java b/services/core/java/com/android/server/am/ProcessList.java
index 4d08bd2e0ed7..bee0e055cf3f 100644
--- a/services/core/java/com/android/server/am/ProcessList.java
+++ b/services/core/java/com/android/server/am/ProcessList.java
@@ -98,6 +98,7 @@ import android.provider.DeviceConfig;
import android.system.Os;
import android.text.TextUtils;
import android.util.ArrayMap;
+import android.util.ArraySet;
import android.util.EventLog;
import android.util.LongSparseArray;
import android.util.Pair;
@@ -138,6 +139,7 @@ import java.util.BitSet;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
+import java.util.Set;
/**
* Activity manager code dealing with processes.
@@ -2155,15 +2157,6 @@ public final class ProcessList {
result.put(packageName, Pair.create(volumeUuid, inode));
}
}
- if (mAppDataIsolationWhitelistedApps != null) {
- for (String packageName : mAppDataIsolationWhitelistedApps) {
- String volumeUuid = pmInt.getPackage(packageName).getVolumeUuid();
- long inode = pmInt.getCeDataInode(packageName, userId);
- if (inode != 0) {
- result.put(packageName, Pair.create(volumeUuid, inode));
- }
- }
- }
return result;
}
@@ -2184,34 +2177,42 @@ public final class ProcessList {
app.setHasForegroundActivities(true);
}
- StorageManagerInternal storageManagerInternal = LocalServices.getService(
- StorageManagerInternal.class);
final Map<String, Pair<String, Long>> pkgDataInfoMap;
+ final Map<String, Pair<String, Long>> whitelistedAppDataInfoMap;
boolean bindMountAppStorageDirs = false;
-
- if (shouldIsolateAppData(app)) {
- // Get all packages belongs to the same shared uid. sharedPackages is empty array
- // if it doesn't have shared uid.
- final PackageManagerInternal pmInt = mService.getPackageManagerInternalLocked();
- final String[] sharedPackages = pmInt.getSharedUserPackagesForPackage(
- app.info.packageName, app.userId);
- pkgDataInfoMap = getPackageAppDataInfoMap(pmInt, sharedPackages.length == 0
- ? new String[]{app.info.packageName} : sharedPackages, uid);
-
- int userId = UserHandle.getUserId(uid);
- if (mVoldAppDataIsolationEnabled && UserHandle.isApp(app.uid) &&
- !storageManagerInternal.isExternalStorageService(uid)) {
- bindMountAppStorageDirs = true;
- if (!storageManagerInternal.prepareStorageDirs(userId, pkgDataInfoMap.keySet(),
- app.processName)) {
- // Cannot prepare Android/app and Android/obb directory,
- // so we won't mount it in zygote.
- app.bindMountPending = true;
- bindMountAppStorageDirs = false;
- }
+ boolean bindMountAppsData = shouldIsolateAppData(app);
+
+ // Get all packages belongs to the same shared uid. sharedPackages is empty array
+ // if it doesn't have shared uid.
+ final PackageManagerInternal pmInt = mService.getPackageManagerInternalLocked();
+ final String[] sharedPackages = pmInt.getSharedUserPackagesForPackage(
+ app.info.packageName, app.userId);
+ final String[] targetPackagesList = sharedPackages.length == 0
+ ? new String[]{app.info.packageName} : sharedPackages;
+ pkgDataInfoMap = getPackageAppDataInfoMap(pmInt, targetPackagesList, uid);
+
+ // Remove all packages in pkgDataInfoMap from mAppDataIsolationWhitelistedApps, so
+ // it won't be mounted twice.
+ final Set<String> whitelistedApps = new ArraySet<>(mAppDataIsolationWhitelistedApps);
+ for (String pkg : targetPackagesList) {
+ whitelistedApps.remove(pkg);
+ }
+ whitelistedAppDataInfoMap = getPackageAppDataInfoMap(pmInt,
+ whitelistedApps.toArray(new String[0]), uid);
+
+ int userId = UserHandle.getUserId(uid);
+ StorageManagerInternal storageManagerInternal = LocalServices.getService(
+ StorageManagerInternal.class);
+ if (mVoldAppDataIsolationEnabled && UserHandle.isApp(app.uid) &&
+ !storageManagerInternal.isExternalStorageService(uid)) {
+ bindMountAppStorageDirs = true;
+ if (!storageManagerInternal.prepareStorageDirs(userId, pkgDataInfoMap.keySet(),
+ app.processName)) {
+ // Cannot prepare Android/app and Android/obb directory,
+ // so we won't mount it in zygote.
+ app.bindMountPending = true;
+ bindMountAppStorageDirs = false;
}
- } else {
- pkgDataInfoMap = null;
}
final Process.ProcessStartResult startResult;
@@ -2229,7 +2230,8 @@ public final class ProcessList {
app.info.targetSdkVersion, seInfo, requiredAbi, instructionSet,
app.info.dataDir, null, app.info.packageName,
/*zygotePolicyFlags=*/ ZYGOTE_POLICY_FLAG_EMPTY, isTopApp,
- app.mDisabledCompatChanges, pkgDataInfoMap, bindMountAppStorageDirs,
+ app.mDisabledCompatChanges, pkgDataInfoMap, whitelistedAppDataInfoMap,
+ bindMountAppsData, bindMountAppStorageDirs,
new String[]{PROC_START_SEQ_IDENT + app.startSeq});
} else {
startResult = Process.start(entryPoint,
@@ -2237,7 +2239,7 @@ public final class ProcessList {
app.info.targetSdkVersion, seInfo, requiredAbi, instructionSet,
app.info.dataDir, invokeWith, app.info.packageName, zygotePolicyFlags,
isTopApp, app.mDisabledCompatChanges, pkgDataInfoMap,
- bindMountAppStorageDirs,
+ whitelistedAppDataInfoMap, bindMountAppsData, bindMountAppStorageDirs,
new String[]{PROC_START_SEQ_IDENT + app.startSeq});
}
checkSlow(startTime, "startProcess: returned from zygote!");
diff --git a/services/core/java/com/android/server/audio/AudioService.java b/services/core/java/com/android/server/audio/AudioService.java
index ada3e4269f6a..94675ab7d795 100644
--- a/services/core/java/com/android/server/audio/AudioService.java
+++ b/services/core/java/com/android/server/audio/AudioService.java
@@ -776,6 +776,8 @@ public class AudioService extends IAudioService.Stub
mDeviceBroker = new AudioDeviceBroker(mContext, this);
+ mRecordMonitor = new RecordingActivityMonitor(mContext);
+
// must be called before readPersistedSettings() which needs a valid mStreamVolumeAlias[]
// array initialized by updateStreamVolumeAlias()
updateStreamVolumeAlias(false /*updateVolumes*/, TAG);
@@ -797,8 +799,6 @@ public class AudioService extends IAudioService.Stub
mMediaFocusControl = new MediaFocusControl(mContext, mPlaybackMonitor);
- mRecordMonitor = new RecordingActivityMonitor(mContext);
-
readAndSetLowRamDevice();
mIsCallScreeningModeSupported = AudioSystem.isCallScreeningModeSupported();
@@ -1981,8 +1981,7 @@ public class AudioService extends IAudioService.Stub
}
flags &= ~AudioManager.FLAG_FIXED_VOLUME;
- if ((streamTypeAlias == AudioSystem.STREAM_MUSIC) &&
- mFixedVolumeDevices.contains(device)) {
+ if (streamTypeAlias == AudioSystem.STREAM_MUSIC && isFixedVolumeDevice(device)) {
flags |= AudioManager.FLAG_FIXED_VOLUME;
// Always toggle between max safe volume and 0 for fixed volume devices where safe
@@ -2059,7 +2058,7 @@ public class AudioService extends IAudioService.Stub
!checkSafeMediaVolume(streamTypeAlias, aliasIndex + step, device)) {
Log.e(TAG, "adjustStreamVolume() safe volume index = " + oldIndex);
mVolumeController.postDisplaySafeVolumeWarning(flags);
- } else if (!mFullVolumeDevices.contains(device)
+ } else if (!isFullVolumeDevice(device)
&& (streamState.adjustIndex(direction * step, device, caller)
|| streamState.mIsMuted)) {
// Post message to set system volume (it in turn will post a
@@ -2121,7 +2120,7 @@ public class AudioService extends IAudioService.Stub
if (mHdmiCecSink
&& streamTypeAlias == AudioSystem.STREAM_MUSIC
// vol change on a full volume device
- && mFullVolumeDevices.contains(device)) {
+ && isFullVolumeDevice(device)) {
int keyCode = KeyEvent.KEYCODE_UNKNOWN;
switch (direction) {
case AudioManager.ADJUST_RAISE:
@@ -2325,6 +2324,13 @@ public class AudioService extends IAudioService.Stub
// For legacy reason, propagate to all streams associated to this volume group
for (final int groupedStream : vgs.getLegacyStreamTypes()) {
+ try {
+ ensureValidStreamType(groupedStream);
+ } catch (IllegalArgumentException e) {
+ Log.d(TAG, "volume group " + volumeGroup + " has internal streams (" + groupedStream
+ + "), do not change associated stream volume");
+ continue;
+ }
setStreamVolume(groupedStream, index, flags, callingPackage, callingPackage,
Binder.getCallingUid());
}
@@ -2590,8 +2596,7 @@ public class AudioService extends IAudioService.Stub
}
flags &= ~AudioManager.FLAG_FIXED_VOLUME;
- if ((streamTypeAlias == AudioSystem.STREAM_MUSIC) &&
- mFixedVolumeDevices.contains(device)) {
+ if (streamTypeAlias == AudioSystem.STREAM_MUSIC && isFixedVolumeDevice(device)) {
flags |= AudioManager.FLAG_FIXED_VOLUME;
// volume is either 0 or max allowed for fixed volume devices
@@ -2780,7 +2785,7 @@ public class AudioService extends IAudioService.Stub
if (streamType == AudioSystem.STREAM_MUSIC) {
flags = updateFlagsForTvPlatform(flags);
- if (mFullVolumeDevices.contains(device)) {
+ if (isFullVolumeDevice(device)) {
flags &= ~AudioManager.FLAG_SHOW_UI;
}
}
@@ -2826,7 +2831,7 @@ public class AudioService extends IAudioService.Stub
int device,
boolean force,
String caller) {
- if (mFullVolumeDevices.contains(device)) {
+ if (isFullVolumeDevice(device)) {
return;
}
VolumeStreamState streamState = mStreamStates[streamType];
@@ -3036,7 +3041,7 @@ public class AudioService extends IAudioService.Stub
index = 0;
}
if (index != 0 && (mStreamVolumeAlias[streamType] == AudioSystem.STREAM_MUSIC) &&
- mFixedVolumeDevices.contains(device)) {
+ isFixedVolumeDevice(device)) {
index = mStreamStates[streamType].getMaxIndex();
}
return (index + 5) / 10;
@@ -4883,10 +4888,6 @@ public class AudioService extends IAudioService.Stub
public void applyAllVolumes() {
synchronized (VolumeGroupState.class) {
- if (mLegacyStreamType != AudioSystem.STREAM_DEFAULT) {
- // No-op to avoid regression with stream based volume management
- return;
- }
// apply device specific volumes first
int index;
for (int i = 0; i < mIndexMap.size(); i++) {
@@ -5166,7 +5167,7 @@ public class AudioService extends IAudioService.Stub
} else if (AudioSystem.DEVICE_OUT_ALL_A2DP_SET.contains(device)
&& isAvrcpAbsVolSupported) {
index = getAbsoluteVolumeIndex((getIndex(device) + 5)/10);
- } else if (mFullVolumeDevices.contains(device)) {
+ } else if (isFullVolumeDevice(device)) {
index = (mIndexMax + 5)/10;
} else if (device == AudioSystem.DEVICE_OUT_HEARING_AID) {
index = (mIndexMax + 5)/10;
@@ -5189,7 +5190,7 @@ public class AudioService extends IAudioService.Stub
} else if (AudioSystem.DEVICE_OUT_ALL_A2DP_SET.contains(device)
&& isAvrcpAbsVolSupported) {
index = getAbsoluteVolumeIndex((getIndex(device) + 5)/10);
- } else if (mFullVolumeDevices.contains(device)) {
+ } else if (isFullVolumeDevice(device)) {
index = (mIndexMax + 5)/10;
} else if (device == AudioSystem.DEVICE_OUT_HEARING_AID) {
index = (mIndexMax + 5)/10;
@@ -5390,8 +5391,8 @@ public class AudioService extends IAudioService.Stub
for (int i = 0; i < mIndexMap.size(); i++) {
int device = mIndexMap.keyAt(i);
int index = mIndexMap.valueAt(i);
- if (mFullVolumeDevices.contains(device)
- || (mFixedVolumeDevices.contains(device) && index != 0)) {
+ if (isFullVolumeDevice(device)
+ || (isFixedVolumeDevice(device) && index != 0)) {
mIndexMap.put(device, mIndexMax);
}
applyDeviceVolume_syncVSS(device, isAvrcpAbsVolSupported);
@@ -8236,4 +8237,23 @@ public class AudioService extends IAudioService.Stub
new HashMap<IBinder, AudioPolicyProxy>();
@GuardedBy("mAudioPolicies")
private int mAudioPolicyCounter = 0;
+
+ //======================
+ // Helper functions for full and fixed volume device
+ //======================
+ private boolean isFixedVolumeDevice(int deviceType) {
+ if (deviceType == AudioSystem.DEVICE_OUT_REMOTE_SUBMIX
+ && mRecordMonitor.isLegacyRemoteSubmixActive()) {
+ return false;
+ }
+ return mFixedVolumeDevices.contains(deviceType);
+ }
+
+ private boolean isFullVolumeDevice(int deviceType) {
+ if (deviceType == AudioSystem.DEVICE_OUT_REMOTE_SUBMIX
+ && mRecordMonitor.isLegacyRemoteSubmixActive()) {
+ return false;
+ }
+ return mFullVolumeDevices.contains(deviceType);
+ }
}
diff --git a/services/core/java/com/android/server/audio/RecordingActivityMonitor.java b/services/core/java/com/android/server/audio/RecordingActivityMonitor.java
index 5c5096251e79..65f221899818 100644
--- a/services/core/java/com/android/server/audio/RecordingActivityMonitor.java
+++ b/services/core/java/com/android/server/audio/RecordingActivityMonitor.java
@@ -18,6 +18,7 @@ package com.android.server.audio;
import android.content.Context;
import android.content.pm.PackageManager;
+import android.media.AudioDeviceInfo;
import android.media.AudioFormat;
import android.media.AudioManager;
import android.media.AudioRecordingConfiguration;
@@ -35,6 +36,8 @@ import java.util.ArrayList;
import java.util.Date;
import java.util.Iterator;
import java.util.List;
+import java.util.concurrent.atomic.AtomicBoolean;
+import java.util.concurrent.atomic.AtomicInteger;
/**
* Class to receive and dispatch updates from AudioSystem about recording configurations.
@@ -49,6 +52,16 @@ public final class RecordingActivityMonitor implements AudioSystem.AudioRecordin
// playback configurations that do not contain uid/package name information.
private boolean mHasPublicClients = false;
+
+ // When legacy remote submix device is active, remote submix device should not be fixed and
+ // full volume device. When legacy remote submix device is active, there will be a recording
+ // activity using device with type as {@link AudioSystem.DEVICE_OUT_REMOTE_SUBMIX} and address
+ // as {@link AudioSystem.LEGACY_REMOTE_SUBMIX_ADDRESS}. Cache riid of legacy remote submix
+ // since remote submix state is not cached in mRecordStates.
+ private AtomicInteger mLegacyRemoteSubmixRiid =
+ new AtomicInteger(AudioManager.RECORD_RIID_INVALID);
+ private AtomicBoolean mLegacyRemoteSubmixActive = new AtomicBoolean(false);
+
static final class RecordingState {
private final int mRiid;
private final RecorderDeathHandler mDeathHandler;
@@ -137,6 +150,16 @@ public final class RecordingActivityMonitor implements AudioSystem.AudioRecordin
final AudioRecordingConfiguration config = createRecordingConfiguration(
uid, session, source, recordingInfo,
portId, silenced, activeSource, clientEffects, effects);
+ if (source == MediaRecorder.AudioSource.REMOTE_SUBMIX) {
+ final AudioDeviceInfo device = config.getAudioDevice();
+ if (AudioSystem.LEGACY_REMOTE_SUBMIX_ADDRESS.equals(device.getAddress())) {
+ mLegacyRemoteSubmixRiid.set(riid);
+ if (event == AudioManager.RECORD_CONFIG_EVENT_START
+ || event == AudioManager.RECORD_CONFIG_EVENT_UPDATE) {
+ mLegacyRemoteSubmixActive.set(true);
+ }
+ }
+ }
if (MediaRecorder.isSystemOnlyAudioSource(source)) {
// still want to log event, it just won't appear in recording configurations;
sEventLogger.log(new RecordingEvent(event, riid, config).printLog(TAG));
@@ -170,6 +193,9 @@ public final class RecordingActivityMonitor implements AudioSystem.AudioRecordin
* Receive an event from the client about a tracked recorder
*/
public void recorderEvent(int riid, int event) {
+ if (mLegacyRemoteSubmixRiid.get() == riid) {
+ mLegacyRemoteSubmixActive.set(event == AudioManager.RECORDER_STATE_STARTED);
+ }
int configEvent = event == AudioManager.RECORDER_STATE_STARTED
? AudioManager.RECORD_CONFIG_EVENT_START :
event == AudioManager.RECORDER_STATE_STOPPED
@@ -323,6 +349,13 @@ public final class RecordingActivityMonitor implements AudioSystem.AudioRecordin
}
/**
+ * Return true if legacy remote submix device is active. Otherwise, return false.
+ */
+ boolean isLegacyRemoteSubmixActive() {
+ return mLegacyRemoteSubmixActive.get();
+ }
+
+ /**
* Create a recording configuration from the provided parameters
* @param uid
* @param session
diff --git a/services/core/java/com/android/server/biometrics/AuthService.java b/services/core/java/com/android/server/biometrics/AuthService.java
index d45ffd9918e4..ff8e3a973641 100644
--- a/services/core/java/com/android/server/biometrics/AuthService.java
+++ b/services/core/java/com/android/server/biometrics/AuthService.java
@@ -202,8 +202,7 @@ public class AuthService extends SystemService {
// Only allow internal clients to call canAuthenticate with a different userId.
final int callingUserId = UserHandle.getCallingUserId();
- Slog.d(TAG, "canAuthenticate, userId: " + userId + ", callingUserId: " + callingUserId
- + ", authenticators: " + authenticators);
+
if (userId != callingUserId) {
checkInternalPermission();
} else {
@@ -212,8 +211,14 @@ public class AuthService extends SystemService {
final long identity = Binder.clearCallingIdentity();
try {
- return mBiometricService.canAuthenticate(
+ final int result = mBiometricService.canAuthenticate(
opPackageName, userId, callingUserId, authenticators);
+ Slog.d(TAG, "canAuthenticate"
+ + ", userId: " + userId
+ + ", callingUserId: " + callingUserId
+ + ", authenticators: " + authenticators
+ + ", result: " + result);
+ return result;
} finally {
Binder.restoreCallingIdentity(identity);
}
diff --git a/services/core/java/com/android/server/biometrics/AuthenticationClient.java b/services/core/java/com/android/server/biometrics/AuthenticationClient.java
index 766e5c4d638f..5d334c22f2db 100644
--- a/services/core/java/com/android/server/biometrics/AuthenticationClient.java
+++ b/services/core/java/com/android/server/biometrics/AuthenticationClient.java
@@ -66,6 +66,8 @@ public abstract class AuthenticationClient extends ClientMonitor {
public abstract boolean wasUserDetected();
+ public abstract boolean isStrongBiometric();
+
public AuthenticationClient(Context context, Constants constants,
BiometricServiceBase.DaemonWrapper daemon, long halDeviceId, IBinder token,
BiometricServiceBase.ServiceListener listener, int targetUserId, int groupId, long opId,
@@ -167,9 +169,15 @@ public abstract class AuthenticationClient extends ClientMonitor {
}
if (isBiometricPrompt() && listener != null) {
// BiometricService will add the token to keystore
- listener.onAuthenticationSucceededInternal(mRequireConfirmation, byteToken);
+ listener.onAuthenticationSucceededInternal(mRequireConfirmation, byteToken,
+ isStrongBiometric());
} else if (!isBiometricPrompt() && listener != null) {
- KeyStore.getInstance().addAuthToken(byteToken);
+ if (isStrongBiometric()) {
+ KeyStore.getInstance().addAuthToken(byteToken);
+ } else {
+ Slog.d(getLogTag(), "Skipping addAuthToken");
+ }
+
try {
// Explicitly have if/else here to make it super obvious in case the code is
// touched in the future.
diff --git a/services/core/java/com/android/server/biometrics/BiometricService.java b/services/core/java/com/android/server/biometrics/BiometricService.java
index e7c09baf3aeb..233416d663d9 100644
--- a/services/core/java/com/android/server/biometrics/BiometricService.java
+++ b/services/core/java/com/android/server/biometrics/BiometricService.java
@@ -266,7 +266,8 @@ public class BiometricService extends SystemService {
SomeArgs args = (SomeArgs) msg.obj;
handleAuthenticationSucceeded(
(boolean) args.arg1 /* requireConfirmation */,
- (byte[]) args.arg2 /* token */);
+ (byte[]) args.arg2 /* token */,
+ (boolean) args.arg3 /* isStrongBiometric */);
args.recycle();
break;
}
@@ -568,10 +569,12 @@ public class BiometricService extends SystemService {
final IBiometricServiceReceiverInternal mInternalReceiver =
new IBiometricServiceReceiverInternal.Stub() {
@Override
- public void onAuthenticationSucceeded(boolean requireConfirmation, byte[] token) {
+ public void onAuthenticationSucceeded(boolean requireConfirmation, byte[] token,
+ boolean isStrongBiometric) {
SomeArgs args = SomeArgs.obtain();
args.arg1 = requireConfirmation;
args.arg2 = token;
+ args.arg3 = isStrongBiometric;
mHandler.obtainMessage(MSG_ON_AUTHENTICATION_SUCCEEDED, args).sendToTarget();
}
@@ -761,8 +764,13 @@ public class BiometricService extends SystemService {
+ " config_biometric_sensors?");
}
+ // Note that we allow BIOMETRIC_CONVENIENCE to register because BiometricService
+ // also does / will do other things such as keep track of lock screen timeout, etc.
+ // Just because a biometric is registered does not mean it can participate in
+ // the android.hardware.biometrics APIs.
if (strength != Authenticators.BIOMETRIC_STRONG
- && strength != Authenticators.BIOMETRIC_WEAK) {
+ && strength != Authenticators.BIOMETRIC_WEAK
+ && strength != Authenticators.BIOMETRIC_CONVENIENCE) {
throw new IllegalStateException("Unsupported strength");
}
@@ -1189,8 +1197,10 @@ public class BiometricService extends SystemService {
BiometricConstants.BIOMETRIC_ERROR_NO_DEVICE_CREDENTIAL);
}
} else {
+ // This should not be possible via the public API surface and is here mainly for
+ // "correctness". An exception should have been thrown before getting here.
Slog.e(TAG, "No authenticators requested");
- return new Pair<>(TYPE_NONE, BiometricConstants.BIOMETRIC_ERROR_HW_UNAVAILABLE);
+ return new Pair<>(TYPE_NONE, BiometricConstants.BIOMETRIC_ERROR_HW_NOT_PRESENT);
}
}
@@ -1286,7 +1296,8 @@ public class BiometricService extends SystemService {
return modality;
}
- private void handleAuthenticationSucceeded(boolean requireConfirmation, byte[] token) {
+ private void handleAuthenticationSucceeded(boolean requireConfirmation, byte[] token,
+ boolean isStrongBiometric) {
try {
// Should never happen, log this to catch bad HAL behavior (e.g. auth succeeded
// after user dismissed/canceled dialog).
@@ -1295,9 +1306,16 @@ public class BiometricService extends SystemService {
return;
}
- // Store the auth token and submit it to keystore after the dialog is confirmed /
- // animating away.
- mCurrentAuthSession.mTokenEscrow = token;
+ if (isStrongBiometric) {
+ // Store the auth token and submit it to keystore after the dialog is confirmed /
+ // animating away.
+ mCurrentAuthSession.mTokenEscrow = token;
+ } else {
+ if (token != null) {
+ Slog.w(TAG, "Dropping authToken for non-strong biometric");
+ }
+ }
+
if (!requireConfirmation) {
mCurrentAuthSession.mState = STATE_AUTHENTICATED_PENDING_SYSUI;
} else {
diff --git a/services/core/java/com/android/server/biometrics/BiometricServiceBase.java b/services/core/java/com/android/server/biometrics/BiometricServiceBase.java
index ebd407d0e981..45b93834c1e2 100644
--- a/services/core/java/com/android/server/biometrics/BiometricServiceBase.java
+++ b/services/core/java/com/android/server/biometrics/BiometricServiceBase.java
@@ -413,8 +413,8 @@ public abstract class BiometricServiceBase extends SystemService
throw new UnsupportedOperationException("Stub!");
}
- default void onAuthenticationSucceededInternal(boolean requireConfirmation, byte[] token)
- throws RemoteException {
+ default void onAuthenticationSucceededInternal(boolean requireConfirmation, byte[] token,
+ boolean isStrongBiometric) throws RemoteException {
throw new UnsupportedOperationException("Stub!");
}
@@ -451,10 +451,11 @@ public abstract class BiometricServiceBase extends SystemService
}
@Override
- public void onAuthenticationSucceededInternal(boolean requireConfirmation, byte[] token)
- throws RemoteException {
+ public void onAuthenticationSucceededInternal(boolean requireConfirmation, byte[] token,
+ boolean isStrongBiometric) throws RemoteException {
if (getWrapperReceiver() != null) {
- getWrapperReceiver().onAuthenticationSucceeded(requireConfirmation, token);
+ getWrapperReceiver().onAuthenticationSucceeded(requireConfirmation, token,
+ isStrongBiometric);
}
}
diff --git a/services/core/java/com/android/server/biometrics/face/FaceService.java b/services/core/java/com/android/server/biometrics/face/FaceService.java
index fd54129a3263..3ecf87c6860f 100644
--- a/services/core/java/com/android/server/biometrics/face/FaceService.java
+++ b/services/core/java/com/android/server/biometrics/face/FaceService.java
@@ -236,6 +236,11 @@ public class FaceService extends BiometricServiceBase {
}
@Override
+ public boolean isStrongBiometric() {
+ return FaceService.this.isStrongBiometric();
+ }
+
+ @Override
public boolean onAuthenticated(BiometricAuthenticator.Identifier identifier,
boolean authenticated, ArrayList<Byte> token) {
final boolean result = super.onAuthenticated(identifier, authenticated, token);
diff --git a/services/core/java/com/android/server/biometrics/fingerprint/FingerprintService.java b/services/core/java/com/android/server/biometrics/fingerprint/FingerprintService.java
index acb1a2ffb754..8520f5aa0632 100644
--- a/services/core/java/com/android/server/biometrics/fingerprint/FingerprintService.java
+++ b/services/core/java/com/android/server/biometrics/fingerprint/FingerprintService.java
@@ -161,6 +161,11 @@ public class FingerprintService extends BiometricServiceBase {
}
@Override
+ public boolean isStrongBiometric() {
+ return FingerprintService.this.isStrongBiometric();
+ }
+
+ @Override
public int handleFailedAttempt() {
final int currentUser = ActivityManager.getCurrentUser();
mFailedAttempts.put(currentUser, mFailedAttempts.get(currentUser, 0) + 1);
diff --git a/services/core/java/com/android/server/display/LocalDisplayAdapter.java b/services/core/java/com/android/server/display/LocalDisplayAdapter.java
index 05a757bde179..8eb771046e6d 100644
--- a/services/core/java/com/android/server/display/LocalDisplayAdapter.java
+++ b/services/core/java/com/android/server/display/LocalDisplayAdapter.java
@@ -646,7 +646,9 @@ final class LocalDisplayAdapter extends DisplayAdapter {
+ "id=" + physicalDisplayId
+ ", state=" + Display.stateToString(state) + ")");
}
- mBacklight.setVrMode(isVrEnabled);
+ if (mBacklight != null) {
+ mBacklight.setVrMode(isVrEnabled);
+ }
}
private void setDisplayState(int state) {
@@ -708,7 +710,9 @@ final class LocalDisplayAdapter extends DisplayAdapter {
BrightnessSynchronizer.brightnessFloatToInt(getContext(),
brightness));
}
- mBacklight.setBrightness(brightness);
+ if (mBacklight != null) {
+ mBacklight.setBrightness(brightness);
+ }
Trace.traceCounter(Trace.TRACE_TAG_POWER,
"ScreenBrightness",
BrightnessSynchronizer.brightnessFloatToInt(
diff --git a/services/core/java/com/android/server/input/InputManagerService.java b/services/core/java/com/android/server/input/InputManagerService.java
index 0b22586bb373..e6129b9b1f32 100644
--- a/services/core/java/com/android/server/input/InputManagerService.java
+++ b/services/core/java/com/android/server/input/InputManagerService.java
@@ -76,7 +76,6 @@ import android.view.InputChannel;
import android.view.InputDevice;
import android.view.InputEvent;
import android.view.InputMonitor;
-import android.view.InputWindowHandle;
import android.view.KeyEvent;
import android.view.PointerIcon;
import android.view.Surface;
@@ -221,8 +220,7 @@ public class InputManagerService extends IInputManager.Stub
int policyFlags);
private static native VerifiedInputEvent nativeVerifyInputEvent(long ptr, InputEvent event);
private static native void nativeToggleCapsLock(long ptr, int deviceId);
- private static native void nativeSetInputWindows(long ptr, InputWindowHandle[] windowHandles,
- int displayId);
+ private static native void nativeDisplayRemoved(long ptr, int displayId);
private static native void nativeSetInputDispatchMode(long ptr, boolean enabled, boolean frozen);
private static native void nativeSetSystemUiVisibility(long ptr, int visibility);
private static native void nativeSetFocusedApplication(long ptr,
@@ -1536,7 +1534,7 @@ public class InputManagerService extends IInputManager.Stub
/** Clean up input window handles of the given display. */
public void onDisplayRemoved(int displayId) {
- nativeSetInputWindows(mPtr, null /* windowHandles */, displayId);
+ nativeDisplayRemoved(mPtr, displayId);
}
@Override
diff --git a/services/core/java/com/android/server/lights/LightsManager.java b/services/core/java/com/android/server/lights/LightsManager.java
index 521913a0c439..706c74137755 100644
--- a/services/core/java/com/android/server/lights/LightsManager.java
+++ b/services/core/java/com/android/server/lights/LightsManager.java
@@ -16,6 +16,7 @@
package com.android.server.lights;
+import android.annotation.Nullable;
import android.hardware.light.V2_0.Type;
public abstract class LightsManager {
@@ -30,7 +31,8 @@ public abstract class LightsManager {
public static final int LIGHT_ID_COUNT = Type.COUNT;
/**
- * Returns the logical light with the given type.
+ * Returns the logical light with the given type, if it exists, or null.
*/
+ @Nullable
public abstract LogicalLight getLight(int id);
}
diff --git a/services/core/java/com/android/server/lights/LightsService.java b/services/core/java/com/android/server/lights/LightsService.java
index a42dec8b575f..3c6e8d29cae0 100644
--- a/services/core/java/com/android/server/lights/LightsService.java
+++ b/services/core/java/com/android/server/lights/LightsService.java
@@ -52,8 +52,8 @@ public class LightsService extends SystemService {
static final String TAG = "LightsService";
static final boolean DEBUG = false;
- private LightImpl[] mLights = null;
- private SparseArray<LightImpl> mLightsById = null;
+ private final LightImpl[] mLightsByType = new LightImpl[LightsManager.LIGHT_ID_COUNT];
+ private final SparseArray<LightImpl> mLightsById = new SparseArray<>();
private ILights mVintfLights = null;
@@ -96,8 +96,8 @@ public class LightsService extends SystemService {
synchronized (LightsService.this) {
final List<Light> lights = new ArrayList<Light>();
for (int i = 0; i < mLightsById.size(); i++) {
- HwLight hwLight = mLightsById.valueAt(i).getHwLight();
- if (!isSystemLight(hwLight)) {
+ if (!mLightsById.valueAt(i).isSystemLight()) {
+ HwLight hwLight = mLightsById.valueAt(i).mHwLight;
lights.add(new Light(hwLight.id, hwLight.ordinal, hwLight.type));
}
}
@@ -138,7 +138,7 @@ public class LightsService extends SystemService {
synchronized (LightsService.this) {
final LightImpl light = mLightsById.get(lightId);
- if (light == null || isSystemLight(light.getHwLight())) {
+ if (light == null || light.isSystemLight()) {
throw new IllegalArgumentException("Invalid light: " + lightId);
}
return new LightState(light.getColor());
@@ -184,9 +184,8 @@ public class LightsService extends SystemService {
private void checkRequestIsValid(int[] lightIds) {
for (int i = 0; i < lightIds.length; i++) {
final LightImpl light = mLightsById.get(lightIds[i]);
- final HwLight hwLight = light.getHwLight();
- Preconditions.checkState(light != null && !isSystemLight(hwLight),
- "invalid lightId " + hwLight.id);
+ Preconditions.checkState(light != null && !light.isSystemLight(),
+ "Invalid lightId " + lightIds[i]);
}
}
@@ -205,9 +204,8 @@ public class LightsService extends SystemService {
}
for (int i = 0; i < mLightsById.size(); i++) {
LightImpl light = mLightsById.valueAt(i);
- HwLight hwLight = light.getHwLight();
- if (!isSystemLight(hwLight)) {
- LightState state = states.get(hwLight.id);
+ if (!light.isSystemLight()) {
+ LightState state = states.get(light.mHwLight.id);
if (state != null) {
light.setColor(state.getColor());
} else {
@@ -385,26 +383,22 @@ public class LightsService extends SystemService {
int brightnessMode) {
Trace.traceBegin(Trace.TRACE_TAG_POWER, "setLightState(" + mHwLight.id + ", 0x"
+ Integer.toHexString(color) + ")");
- if (mVintfLights != null) {
- HwLightState lightState = new HwLightState();
- lightState.color = color;
- lightState.flashMode = (byte) mode;
- lightState.flashOnMs = onMS;
- lightState.flashOffMs = offMS;
- lightState.brightnessMode = (byte) brightnessMode;
- try {
+ try {
+ if (mVintfLights != null) {
+ HwLightState lightState = new HwLightState();
+ lightState.color = color;
+ lightState.flashMode = (byte) mode;
+ lightState.flashOnMs = onMS;
+ lightState.flashOffMs = offMS;
+ lightState.brightnessMode = (byte) brightnessMode;
mVintfLights.setLightState(mHwLight.id, lightState);
- } catch (RemoteException | UnsupportedOperationException ex) {
- Slog.e(TAG, "Failed issuing setLightState", ex);
- } finally {
- Trace.traceEnd(Trace.TRACE_TAG_POWER);
- }
- } else {
- try {
+ } else {
setLight_native(mHwLight.id, color, mode, onMS, offMS, brightnessMode);
- } finally {
- Trace.traceEnd(Trace.TRACE_TAG_POWER);
}
+ } catch (RemoteException | UnsupportedOperationException ex) {
+ Slog.e(TAG, "Failed issuing setLightState", ex);
+ } finally {
+ Trace.traceEnd(Trace.TRACE_TAG_POWER);
}
}
@@ -412,8 +406,14 @@ public class LightsService extends SystemService {
return mVrModeEnabled && mUseLowPersistenceForVR;
}
- private HwLight getHwLight() {
- return mHwLight;
+ /**
+ * Returns whether a light is system-use-only or should be accessible to
+ * applications using the {@link android.hardware.lights.LightsManager} API.
+ */
+ private boolean isSystemLight() {
+ // LIGHT_ID_COUNT comes from the 2.0 HIDL HAL and only contains system lights.
+ // Newly-added lights are made available via the public LightsManager API.
+ return (0 <= mHwLight.type && mHwLight.type < LightsManager.LIGHT_ID_COUNT);
}
private int getColor() {
@@ -451,36 +451,37 @@ public class LightsService extends SystemService {
}
private void populateAvailableLights(Context context) {
- mLights = new LightImpl[LightsManager.LIGHT_ID_COUNT];
- mLightsById = new SparseArray<>();
-
if (mVintfLights != null) {
- try {
- for (HwLight availableLight : mVintfLights.getLights()) {
- LightImpl light = new LightImpl(context, availableLight);
- int type = (int) availableLight.type;
- if (0 <= type && type < mLights.length && mLights[type] == null) {
- mLights[type] = light;
- }
- mLightsById.put(availableLight.id, light);
- }
- } catch (RemoteException ex) {
- Slog.e(TAG, "Unable to get lights for initialization", ex);
+ populateAvailableLightsFromAidl(context);
+ } else {
+ populateAvailableLightsFromHidl(context);
+ }
+
+ for (int i = mLightsById.size() - 1; i >= 0; i--) {
+ final int type = mLightsById.keyAt(i);
+ if (0 <= type && type < mLightsByType.length) {
+ mLightsByType[type] = mLightsById.valueAt(i);
}
}
+ }
- // In the case where only the old HAL is available, all lights will be initialized here
- for (int i = 0; i < mLights.length; i++) {
- if (mLights[i] == null) {
- // The ordinal can be anything if there is only 1 light of each type. Set it to 1.
- HwLight light = new HwLight();
- light.id = (byte) i;
- light.ordinal = 1;
- light.type = (byte) i;
-
- mLights[i] = new LightImpl(context, light);
- mLightsById.put(i, mLights[i]);
+ private void populateAvailableLightsFromAidl(Context context) {
+ try {
+ for (HwLight hwLight : mVintfLights.getLights()) {
+ mLightsById.put(hwLight.id, new LightImpl(context, hwLight));
}
+ } catch (RemoteException ex) {
+ Slog.e(TAG, "Unable to get lights from HAL", ex);
+ }
+ }
+
+ private void populateAvailableLightsFromHidl(Context context) {
+ for (int i = 0; i < mLightsByType.length; i++) {
+ HwLight hwLight = new HwLight();
+ hwLight.id = (byte) i;
+ hwLight.ordinal = 1;
+ hwLight.type = (byte) i;
+ mLightsById.put(hwLight.id, new LightImpl(context, hwLight));
}
}
@@ -505,25 +506,14 @@ public class LightsService extends SystemService {
private final LightsManager mService = new LightsManager() {
@Override
public LogicalLight getLight(int lightType) {
- if (mLights != null && 0 <= lightType && lightType < mLights.length) {
- return mLights[lightType];
+ if (mLightsByType != null && 0 <= lightType && lightType < mLightsByType.length) {
+ return mLightsByType[lightType];
} else {
return null;
}
}
};
- /**
- * Returns whether a light is system-use-only or should be accessible to
- * applications using the {@link android.hardware.lights.LightsManager} API.
- */
- private static boolean isSystemLight(HwLight light) {
- // LIGHT_ID_COUNT comes from the 2.0 HIDL HAL and only contains system
- // lights. Newly added lights will be made available via the
- // LightsManager API.
- return 0 <= light.type && light.type < LightsManager.LIGHT_ID_COUNT;
- }
-
static native void setLight_native(int light, int color, int mode,
int onMS, int offMS, int brightnessMode);
}
diff --git a/services/core/java/com/android/server/notification/NotificationManagerService.java b/services/core/java/com/android/server/notification/NotificationManagerService.java
index 7f805bef520d..31dc09416ac8 100755
--- a/services/core/java/com/android/server/notification/NotificationManagerService.java
+++ b/services/core/java/com/android/server/notification/NotificationManagerService.java
@@ -1579,7 +1579,9 @@ public class NotificationManagerService extends SystemService {
}
} else if (action.equals(Intent.ACTION_USER_PRESENT)) {
// turn off LED when user passes through lock screen
- mNotificationLight.turnOff();
+ if (mNotificationLight != null) {
+ mNotificationLight.turnOff();
+ }
} else if (action.equals(Intent.ACTION_USER_SWITCHED)) {
final int userId = intent.getIntExtra(Intent.EXTRA_USER_HANDLE, USER_NULL);
mUserProfiles.updateCache(context);
@@ -4193,7 +4195,7 @@ public class NotificationManagerService extends SystemService {
@Override
public int getInterruptionFilterFromListener(INotificationListener token)
throws RemoteException {
- synchronized (mNotificationLight) {
+ synchronized (mNotificationLock) {
return mInterruptionFilter;
}
}
@@ -6773,7 +6775,7 @@ public class NotificationManagerService extends SystemService {
if (canShowLightsLocked(record, aboveThreshold)) {
mLights.add(key);
updateLightsLocked();
- if (mUseAttentionLight) {
+ if (mUseAttentionLight && mAttentionLight != null) {
mAttentionLight.pulse();
}
blink = true;
@@ -7974,6 +7976,10 @@ public class NotificationManagerService extends SystemService {
@GuardedBy("mNotificationLock")
void updateLightsLocked()
{
+ if (mNotificationLight == null) {
+ return;
+ }
+
// handle notification lights
NotificationRecord ledNotification = null;
while (ledNotification == null && !mLights.isEmpty()) {
diff --git a/services/core/java/com/android/server/pm/ApexManager.java b/services/core/java/com/android/server/pm/ApexManager.java
index c37ea8ba68bd..c97f33b5103f 100644
--- a/services/core/java/com/android/server/pm/ApexManager.java
+++ b/services/core/java/com/android/server/pm/ApexManager.java
@@ -16,22 +16,22 @@
package com.android.server.pm;
+import static android.os.Trace.TRACE_TAG_PACKAGE_MANAGER;
+
import android.annotation.IntDef;
+import android.annotation.NonNull;
import android.annotation.Nullable;
import android.apex.ApexInfo;
import android.apex.ApexInfoList;
import android.apex.ApexSessionInfo;
import android.apex.ApexSessionParams;
import android.apex.IApexService;
-import android.content.BroadcastReceiver;
-import android.content.Context;
-import android.content.Intent;
-import android.content.IntentFilter;
import android.content.pm.ApplicationInfo;
import android.content.pm.PackageInfo;
import android.content.pm.PackageInstaller;
import android.content.pm.PackageManager;
import android.content.pm.PackageParser;
+import android.content.pm.parsing.PackageInfoWithoutStateUtils;
import android.os.Environment;
import android.os.RemoteException;
import android.os.ServiceManager;
@@ -44,8 +44,9 @@ import android.util.Slog;
import com.android.internal.annotations.GuardedBy;
import com.android.internal.annotations.VisibleForTesting;
-import com.android.internal.os.BackgroundThread;
import com.android.internal.util.IndentingPrintWriter;
+import com.android.internal.util.Preconditions;
+import com.android.server.pm.parsing.PackageParser2;
import com.android.server.pm.parsing.pkg.AndroidPackage;
import com.android.server.utils.TimingsTraceAndSlog;
@@ -61,7 +62,9 @@ import java.util.HashSet;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
+import java.util.Objects;
import java.util.Set;
+import java.util.concurrent.ExecutorService;
import java.util.stream.Collectors;
/**
@@ -72,7 +75,7 @@ public abstract class ApexManager {
private static final String TAG = "ApexManager";
- static final int MATCH_ACTIVE_PACKAGE = 1 << 0;
+ public static final int MATCH_ACTIVE_PACKAGE = 1 << 0;
static final int MATCH_FACTORY_PACKAGE = 1 << 1;
private static final Singleton<ApexManager> sApexManagerSingleton =
@@ -139,7 +142,14 @@ public abstract class ApexManager {
*/
public abstract List<ActiveApexInfo> getActiveApexInfos();
- abstract void systemReady(Context context);
+ /**
+ * Called by package manager service to scan apex package files when device boots up.
+ *
+ * @param packageParser The package parser which supports caches.
+ * @param executorService An executor to support parallel package parsing.
+ */
+ abstract void scanApexPackagesTraced(@NonNull PackageParser2 packageParser,
+ @NonNull ExecutorService executorService);
/**
* Retrieves information about an APEX package.
@@ -154,7 +164,7 @@ public abstract class ApexManager {
* is not found.
*/
@Nullable
- abstract PackageInfo getPackageInfo(String packageName, @PackageInfoFlags int flags);
+ public abstract PackageInfo getPackageInfo(String packageName, @PackageInfoFlags int flags);
/**
* Retrieves information about all active APEX packages.
@@ -189,6 +199,27 @@ public abstract class ApexManager {
abstract boolean isApexPackage(String packageName);
/**
+ * Whether the APEX package is pre-installed or not.
+ *
+ * @param packageInfo the package to check
+ * @return {@code true} if this package is pre-installed, {@code false} otherwise.
+ */
+ public static boolean isFactory(@NonNull PackageInfo packageInfo) {
+ return (packageInfo.applicationInfo.flags & ApplicationInfo.FLAG_SYSTEM) != 0;
+ }
+
+ /**
+ * Returns the active apex package's name that contains the (apk) package.
+ *
+ * @param containedPackage The (apk) package that might be in a apex
+ * @return the apex package's name of {@code null} if the {@code containedPackage} is not inside
+ * any apex.
+ */
+ @Nullable
+ public abstract String getActiveApexPackageNameContainingPackage(
+ @NonNull AndroidPackage containedPackage);
+
+ /**
* Retrieves information about an apexd staged session i.e. the internal state used by apexd to
* track the different states of a session.
*
@@ -342,7 +373,7 @@ public abstract class ApexManager {
* difference between {@code packageName} and {@code apexModuleName}.
*/
@GuardedBy("mLock")
- private Map<String, List<String>> mApksInApex = new ArrayMap<>();
+ private ArrayMap<String, List<String>> mApksInApex = new ArrayMap<>();
@GuardedBy("mLock")
private List<PackageInfo> mAllPackagesCache;
@@ -357,7 +388,7 @@ public abstract class ApexManager {
* the apk container to {@code apexModuleName} of the apex-payload inside.
*/
@GuardedBy("mLock")
- private Map<String, String> mPackageNameToApexModuleName;
+ private ArrayMap<String, String> mPackageNameToApexModuleName;
ApexManagerImpl(IApexService apexService) {
mApexService = apexService;
@@ -373,16 +404,6 @@ public abstract class ApexManager {
return (packageInfo.applicationInfo.flags & ApplicationInfo.FLAG_INSTALLED) != 0;
}
- /**
- * Whether the APEX package is pre-installed or not.
- *
- * @param packageInfo the package to check
- * @return {@code true} if this package is pre-installed, {@code false} otherwise.
- */
- private static boolean isFactory(PackageInfo packageInfo) {
- return (packageInfo.applicationInfo.flags & ApplicationInfo.FLAG_SYSTEM) != 0;
- }
-
@Override
public List<ActiveApexInfo> getActiveApexInfos() {
final TimingsTraceAndSlog t = new TimingsTraceAndSlog(TAG + "Timing",
@@ -411,104 +432,94 @@ public abstract class ApexManager {
}
@Override
- void systemReady(Context context) {
- context.registerReceiver(new BroadcastReceiver() {
- @Override
- public void onReceive(Context context, Intent intent) {
- // Post populateAllPackagesCacheIfNeeded to a background thread, since it's
- // expensive to run it in broadcast handler thread.
- BackgroundThread.getHandler().post(() -> populateAllPackagesCacheIfNeeded());
- context.unregisterReceiver(this);
- }
- }, new IntentFilter(Intent.ACTION_BOOT_COMPLETED));
- }
-
- private void populatePackageNameToApexModuleNameIfNeeded() {
- synchronized (mLock) {
- if (mPackageNameToApexModuleName != null) {
- return;
- }
- try {
- mPackageNameToApexModuleName = new ArrayMap<>();
- final ApexInfo[] allPkgs = mApexService.getAllPackages();
- for (int i = 0; i < allPkgs.length; i++) {
- ApexInfo ai = allPkgs[i];
- PackageParser.PackageLite pkgLite;
- try {
- File apexFile = new File(ai.modulePath);
- pkgLite = PackageParser.parsePackageLite(apexFile, 0);
- } catch (PackageParser.PackageParserException pe) {
- throw new IllegalStateException("Unable to parse: "
- + ai.modulePath, pe);
- }
- mPackageNameToApexModuleName.put(pkgLite.packageName, ai.moduleName);
- }
- } catch (RemoteException re) {
- Slog.e(TAG, "Unable to retrieve packages from apexservice: ", re);
- throw new RuntimeException(re);
+ void scanApexPackagesTraced(@NonNull PackageParser2 packageParser,
+ @NonNull ExecutorService executorService) {
+ Trace.traceBegin(TRACE_TAG_PACKAGE_MANAGER, "scanApexPackagesTraced");
+ try {
+ synchronized (mLock) {
+ scanApexPackagesInternalLocked(packageParser, executorService);
}
+ } finally {
+ Trace.traceEnd(TRACE_TAG_PACKAGE_MANAGER);
}
}
- private void populateAllPackagesCacheIfNeeded() {
- synchronized (mLock) {
- if (mAllPackagesCache != null) {
- return;
- }
- try {
- mAllPackagesCache = new ArrayList<>();
- HashSet<String> activePackagesSet = new HashSet<>();
- HashSet<String> factoryPackagesSet = new HashSet<>();
- final ApexInfo[] allPkgs = mApexService.getAllPackages();
- for (ApexInfo ai : allPkgs) {
- // If the device is using flattened APEX, don't report any APEX
- // packages since they won't be managed or updated by PackageManager.
- if ((new File(ai.modulePath)).isDirectory()) {
- break;
- }
- int flags = PackageManager.GET_META_DATA
- | PackageManager.GET_SIGNING_CERTIFICATES
- | PackageManager.GET_SIGNATURES;
- PackageParser.Package pkg;
- try {
- File apexFile = new File(ai.modulePath);
- PackageParser pp = new PackageParser();
- pkg = pp.parsePackage(apexFile, flags, false);
- PackageParser.collectCertificates(pkg, false);
- } catch (PackageParser.PackageParserException pe) {
- throw new IllegalStateException("Unable to parse: " + ai, pe);
- }
+ @GuardedBy("mLock")
+ private void scanApexPackagesInternalLocked(PackageParser2 packageParser,
+ ExecutorService executorService) {
+ final ApexInfo[] allPkgs;
+ try {
+ mAllPackagesCache = new ArrayList<>();
+ mPackageNameToApexModuleName = new ArrayMap<>();
+ allPkgs = mApexService.getAllPackages();
+ } catch (RemoteException re) {
+ Slog.e(TAG, "Unable to retrieve packages from apexservice: " + re.toString());
+ throw new RuntimeException(re);
+ }
+ if (allPkgs.length == 0) {
+ return;
+ }
+ int flags = PackageManager.GET_META_DATA
+ | PackageManager.GET_SIGNING_CERTIFICATES
+ | PackageManager.GET_SIGNATURES;
+ ArrayMap<File, ApexInfo> parsingApexInfo = new ArrayMap<>();
+ ParallelPackageParser parallelPackageParser =
+ new ParallelPackageParser(packageParser, executorService);
+
+ for (ApexInfo ai : allPkgs) {
+ File apexFile = new File(ai.modulePath);
+ parallelPackageParser.submit(apexFile, flags);
+ parsingApexInfo.put(apexFile, ai);
+ }
- final PackageInfo packageInfo =
- PackageParser.generatePackageInfo(pkg, ai, flags);
- mAllPackagesCache.add(packageInfo);
- if (ai.isActive) {
- if (activePackagesSet.contains(packageInfo.packageName)) {
- throw new IllegalStateException(
- "Two active packages have the same name: "
- + packageInfo.packageName);
- }
- activePackagesSet.add(packageInfo.packageName);
+ HashSet<String> activePackagesSet = new HashSet<>();
+ HashSet<String> factoryPackagesSet = new HashSet<>();
+ // Process results one by one
+ for (int i = 0; i < parsingApexInfo.size(); i++) {
+ ParallelPackageParser.ParseResult parseResult = parallelPackageParser.take();
+ Throwable throwable = parseResult.throwable;
+ ApexInfo ai = parsingApexInfo.get(parseResult.scanFile);
+
+ if (throwable == null) {
+ final PackageInfo packageInfo = PackageInfoWithoutStateUtils.generate(
+ parseResult.parsedPackage, ai, flags);
+ if (packageInfo == null) {
+ throw new IllegalStateException("Unable to generate package info: "
+ + ai.modulePath);
+ }
+ mAllPackagesCache.add(packageInfo);
+ mPackageNameToApexModuleName.put(packageInfo.packageName, ai.moduleName);
+ if (ai.isActive) {
+ if (activePackagesSet.contains(packageInfo.packageName)) {
+ throw new IllegalStateException(
+ "Two active packages have the same name: "
+ + packageInfo.packageName);
}
- if (ai.isFactory) {
- if (factoryPackagesSet.contains(packageInfo.packageName)) {
- throw new IllegalStateException(
- "Two factory packages have the same name: "
- + packageInfo.packageName);
- }
- factoryPackagesSet.add(packageInfo.packageName);
+ activePackagesSet.add(packageInfo.packageName);
+ }
+ if (ai.isFactory) {
+ if (factoryPackagesSet.contains(packageInfo.packageName)) {
+ throw new IllegalStateException(
+ "Two factory packages have the same name: "
+ + packageInfo.packageName);
}
+ factoryPackagesSet.add(packageInfo.packageName);
}
- } catch (RemoteException re) {
- Slog.e(TAG, "Unable to retrieve packages from apexservice: " + re.toString());
- throw new RuntimeException(re);
+ } else if (throwable instanceof PackageParser.PackageParserException) {
+ throw new IllegalStateException("Unable to parse: " + ai.modulePath, throwable);
+ } else {
+ throw new IllegalStateException("Unexpected exception occurred while parsing "
+ + ai.modulePath, throwable);
}
}
}
@Override
- @Nullable PackageInfo getPackageInfo(String packageName, @PackageInfoFlags int flags) {
- populateAllPackagesCacheIfNeeded();
+ @Nullable
+ public PackageInfo getPackageInfo(String packageName,
+ @PackageInfoFlags int flags) {
+ Preconditions.checkState(mAllPackagesCache != null,
+ "APEX packages have not been scanned");
boolean matchActive = (flags & MATCH_ACTIVE_PACKAGE) != 0;
boolean matchFactory = (flags & MATCH_FACTORY_PACKAGE) != 0;
for (PackageInfo packageInfo: mAllPackagesCache) {
@@ -525,7 +536,8 @@ public abstract class ApexManager {
@Override
List<PackageInfo> getActivePackages() {
- populateAllPackagesCacheIfNeeded();
+ Preconditions.checkState(mAllPackagesCache != null,
+ "APEX packages have not been scanned");
return mAllPackagesCache
.stream()
.filter(item -> isActive(item))
@@ -534,7 +546,8 @@ public abstract class ApexManager {
@Override
List<PackageInfo> getFactoryPackages() {
- populateAllPackagesCacheIfNeeded();
+ Preconditions.checkState(mAllPackagesCache != null,
+ "APEX packages have not been scanned");
return mAllPackagesCache
.stream()
.filter(item -> isFactory(item))
@@ -543,7 +556,8 @@ public abstract class ApexManager {
@Override
List<PackageInfo> getInactivePackages() {
- populateAllPackagesCacheIfNeeded();
+ Preconditions.checkState(mAllPackagesCache != null,
+ "APEX packages have not been scanned");
return mAllPackagesCache
.stream()
.filter(item -> !isActive(item))
@@ -553,7 +567,8 @@ public abstract class ApexManager {
@Override
boolean isApexPackage(String packageName) {
if (!isApexSupported()) return false;
- populateAllPackagesCacheIfNeeded();
+ Preconditions.checkState(mAllPackagesCache != null,
+ "APEX packages have not been scanned");
for (PackageInfo packageInfo : mAllPackagesCache) {
if (packageInfo.packageName.equals(packageName)) {
return true;
@@ -563,6 +578,36 @@ public abstract class ApexManager {
}
@Override
+ @Nullable
+ public String getActiveApexPackageNameContainingPackage(
+ @NonNull AndroidPackage containedPackage) {
+ Preconditions.checkState(mPackageNameToApexModuleName != null,
+ "APEX packages have not been scanned");
+
+ Objects.requireNonNull(containedPackage);
+
+ synchronized (mLock) {
+ int numApksInApex = mApksInApex.size();
+ for (int apkInApexNum = 0; apkInApexNum < numApksInApex; apkInApexNum++) {
+ if (mApksInApex.valueAt(apkInApexNum).contains(
+ containedPackage.getPackageName())) {
+ String apexModuleName = mApksInApex.keyAt(apkInApexNum);
+
+ int numApexPkgs = mPackageNameToApexModuleName.size();
+ for (int apexPkgNum = 0; apexPkgNum < numApexPkgs; apexPkgNum++) {
+ if (mPackageNameToApexModuleName.valueAt(apexPkgNum).equals(
+ apexModuleName)) {
+ return mPackageNameToApexModuleName.keyAt(apexPkgNum);
+ }
+ }
+ }
+ }
+ }
+
+ return null;
+ }
+
+ @Override
@Nullable ApexSessionInfo getStagedSessionInfo(int sessionId) {
try {
ApexSessionInfo apexSessionInfo = mApexService.getStagedSessionInfo(sessionId);
@@ -684,8 +729,9 @@ public abstract class ApexManager {
@Override
List<String> getApksInApex(String apexPackageName) {
- populatePackageNameToApexModuleNameIfNeeded();
synchronized (mLock) {
+ Preconditions.checkState(mPackageNameToApexModuleName != null,
+ "APEX packages have not been scanned");
String moduleName = mPackageNameToApexModuleName.get(apexPackageName);
if (moduleName == null) {
return Collections.emptyList();
@@ -697,17 +743,19 @@ public abstract class ApexManager {
@Override
@Nullable
public String getApexModuleNameForPackageName(String apexPackageName) {
- populatePackageNameToApexModuleNameIfNeeded();
synchronized (mLock) {
+ Preconditions.checkState(mPackageNameToApexModuleName != null,
+ "APEX packages have not been scanned");
return mPackageNameToApexModuleName.get(apexPackageName);
}
}
@Override
public long snapshotCeData(int userId, int rollbackId, String apexPackageName) {
- populatePackageNameToApexModuleNameIfNeeded();
String apexModuleName;
synchronized (mLock) {
+ Preconditions.checkState(mPackageNameToApexModuleName != null,
+ "APEX packages have not been scanned");
apexModuleName = mPackageNameToApexModuleName.get(apexPackageName);
}
if (apexModuleName == null) {
@@ -724,9 +772,10 @@ public abstract class ApexManager {
@Override
public boolean restoreCeData(int userId, int rollbackId, String apexPackageName) {
- populatePackageNameToApexModuleNameIfNeeded();
String apexModuleName;
synchronized (mLock) {
+ Preconditions.checkState(mPackageNameToApexModuleName != null,
+ "APEX packages have not been scanned");
apexModuleName = mPackageNameToApexModuleName.get(apexPackageName);
}
if (apexModuleName == null) {
@@ -797,15 +846,7 @@ public abstract class ApexManager {
void dump(PrintWriter pw, @Nullable String packageName) {
final IndentingPrintWriter ipw = new IndentingPrintWriter(pw, " ", 120);
try {
- populateAllPackagesCacheIfNeeded();
ipw.println();
- ipw.println("Active APEX packages:");
- dumpFromPackagesCache(getActivePackages(), packageName, ipw);
- ipw.println("Inactive APEX packages:");
- dumpFromPackagesCache(getInactivePackages(), packageName, ipw);
- ipw.println("Factory APEX packages:");
- dumpFromPackagesCache(getFactoryPackages(), packageName, ipw);
- ipw.increaseIndent();
ipw.println("APEX session state:");
ipw.increaseIndent();
final ApexSessionInfo[] sessions = mApexService.getSessions();
@@ -834,6 +875,17 @@ public abstract class ApexManager {
ipw.decreaseIndent();
}
ipw.decreaseIndent();
+ ipw.println();
+ if (mAllPackagesCache == null) {
+ ipw.println("APEX packages have not been scanned");
+ return;
+ }
+ ipw.println("Active APEX packages:");
+ dumpFromPackagesCache(getActivePackages(), packageName, ipw);
+ ipw.println("Inactive APEX packages:");
+ dumpFromPackagesCache(getInactivePackages(), packageName, ipw);
+ ipw.println("Factory APEX packages:");
+ dumpFromPackagesCache(getFactoryPackages(), packageName, ipw);
} catch (RemoteException e) {
ipw.println("Couldn't communicate with apexd.");
}
@@ -879,12 +931,13 @@ public abstract class ApexManager {
}
@Override
- void systemReady(Context context) {
+ void scanApexPackagesTraced(@NonNull PackageParser2 packageParser,
+ @NonNull ExecutorService executorService) {
// No-op
}
@Override
- PackageInfo getPackageInfo(String packageName, int flags) {
+ public PackageInfo getPackageInfo(String packageName, int flags) {
return null;
}
@@ -909,6 +962,15 @@ public abstract class ApexManager {
}
@Override
+ @Nullable
+ public String getActiveApexPackageNameContainingPackage(
+ @NonNull AndroidPackage containedPackage) {
+ Objects.requireNonNull(containedPackage);
+
+ return null;
+ }
+
+ @Override
ApexSessionInfo getStagedSessionInfo(int sessionId) {
throw new UnsupportedOperationException();
}
diff --git a/services/core/java/com/android/server/pm/CrossProfileAppsServiceImpl.java b/services/core/java/com/android/server/pm/CrossProfileAppsServiceImpl.java
index 7069818e3894..40876754eae8 100644
--- a/services/core/java/com/android/server/pm/CrossProfileAppsServiceImpl.java
+++ b/services/core/java/com/android/server/pm/CrossProfileAppsServiceImpl.java
@@ -64,6 +64,7 @@ import com.android.server.wm.ActivityTaskManagerInternal;
import java.util.ArrayList;
import java.util.List;
import java.util.Objects;
+import java.util.stream.Collectors;
public class CrossProfileAppsServiceImpl extends ICrossProfileApps.Stub {
private static final String TAG = "CrossProfileAppsService";
@@ -447,7 +448,7 @@ public class CrossProfileAppsServiceImpl extends ICrossProfileApps.Stub {
final int uid = mInjector.getPackageManager()
.getPackageUidAsUser(packageName, /* flags= */ 0, userId);
if (currentModeEquals(newMode, packageName, uid)) {
- Slog.w(TAG, "Attempt to set mode to existing value of " + newMode + " for "
+ Slog.i(TAG, "Attempt to set mode to existing value of " + newMode + " for "
+ packageName + " on user ID " + userId);
return;
}
@@ -577,6 +578,24 @@ public class CrossProfileAppsServiceImpl extends ICrossProfileApps.Stub {
setInteractAcrossProfilesAppOp(packageName, AppOpsManager.opToDefaultMode(op));
}
+ @Override
+ public void clearInteractAcrossProfilesAppOps() {
+ final int defaultMode =
+ AppOpsManager.opToDefaultMode(
+ AppOpsManager.permissionToOp(Manifest.permission.INTERACT_ACROSS_PROFILES));
+ findAllPackageNames()
+ .forEach(packageName -> setInteractAcrossProfilesAppOp(packageName, defaultMode));
+ }
+
+ private List<String> findAllPackageNames() {
+ return mInjector.getPackageManagerInternal()
+ .getInstalledApplications(
+ /* flags= */ 0, mInjector.getCallingUserId(), mInjector.getCallingUid())
+ .stream()
+ .map(applicationInfo -> applicationInfo.packageName)
+ .collect(Collectors.toList());
+ }
+
CrossProfileAppsInternal getLocalService() {
return mLocalService;
}
diff --git a/services/core/java/com/android/server/pm/PackageInstallerService.java b/services/core/java/com/android/server/pm/PackageInstallerService.java
index 2ff3d2a3a938..8ff7ea9d61dd 100644
--- a/services/core/java/com/android/server/pm/PackageInstallerService.java
+++ b/services/core/java/com/android/server/pm/PackageInstallerService.java
@@ -490,6 +490,14 @@ public class PackageInstallerService extends IPackageInstaller.Stub implements
throw new SecurityException("User restriction prevents installing");
}
+ if (params.dataLoaderParams != null
+ && mContext.checkCallingOrSelfPermission(Manifest.permission.USE_INSTALLER_V2)
+ != PackageManager.PERMISSION_GRANTED) {
+ throw new SecurityException("You need the "
+ + "com.android.permission.USE_INSTALLER_V2 permission "
+ + "to use a data loader");
+ }
+
String requestedInstallerPackageName = params.installerPackageName != null
? params.installerPackageName : installerPackageName;
diff --git a/services/core/java/com/android/server/pm/PackageInstallerSession.java b/services/core/java/com/android/server/pm/PackageInstallerSession.java
index 348a4cb77163..42ed20654a2c 100644
--- a/services/core/java/com/android/server/pm/PackageInstallerSession.java
+++ b/services/core/java/com/android/server/pm/PackageInstallerSession.java
@@ -2479,12 +2479,14 @@ public class PackageInstallerSession extends IPackageInstallerSession.Stub {
@Override
public DataLoaderParamsParcel getDataLoaderParams() {
+ mContext.enforceCallingOrSelfPermission(Manifest.permission.USE_INSTALLER_V2, null);
return params.dataLoaderParams != null ? params.dataLoaderParams.getData() : null;
}
@Override
public void addFile(int location, String name, long lengthBytes, byte[] metadata,
byte[] signature) {
+ mContext.enforceCallingOrSelfPermission(Manifest.permission.USE_INSTALLER_V2, null);
if (!isDataLoaderInstallation()) {
throw new IllegalStateException(
"Cannot add files to non-data loader installation session.");
@@ -2517,6 +2519,7 @@ public class PackageInstallerSession extends IPackageInstallerSession.Stub {
@Override
public void removeFile(int location, String name) {
+ mContext.enforceCallingOrSelfPermission(Manifest.permission.USE_INSTALLER_V2, null);
if (!isDataLoaderInstallation()) {
throw new IllegalStateException(
"Cannot add files to non-data loader installation session.");
diff --git a/services/core/java/com/android/server/pm/PackageManagerService.java b/services/core/java/com/android/server/pm/PackageManagerService.java
index 58a9d9c5f6bf..34363c8df8f6 100644
--- a/services/core/java/com/android/server/pm/PackageManagerService.java
+++ b/services/core/java/com/android/server/pm/PackageManagerService.java
@@ -2900,6 +2900,9 @@ public class PackageManagerService extends IPackageManager.Stub
mMetrics, mCacheDir, mPackageParserCallback);
ExecutorService executorService = ParallelPackageParser.makeExecutorService();
+ // Prepare apex package info before scanning APKs, these information are needed when
+ // scanning apk in apex.
+ mApexManager.scanApexPackagesTraced(packageParser, executorService);
// Collect vendor/product/system_ext overlay packages. (Do this before scanning
// any apps.)
// For security and version matching reason, only consider overlay packages if they
@@ -20696,7 +20699,6 @@ public class PackageManagerService extends IPackageManager.Stub
storage.registerListener(mStorageListener);
mInstallerService.systemReady();
- mApexManager.systemReady(mContext);
mPackageDexOptimizer.systemReady();
mInjector.getStorageManagerInternal().addExternalStoragePolicy(
diff --git a/services/core/java/com/android/server/pm/permission/PermissionManagerService.java b/services/core/java/com/android/server/pm/permission/PermissionManagerService.java
index 04c965e69588..765ecb9710cb 100644
--- a/services/core/java/com/android/server/pm/permission/PermissionManagerService.java
+++ b/services/core/java/com/android/server/pm/permission/PermissionManagerService.java
@@ -42,6 +42,7 @@ import static android.os.Trace.TRACE_TAG_PACKAGE_MANAGER;
import static android.permission.PermissionManager.KILL_APP_REASON_GIDS_CHANGED;
import static android.permission.PermissionManager.KILL_APP_REASON_PERMISSIONS_REVOKED;
+import static com.android.server.pm.ApexManager.MATCH_ACTIVE_PACKAGE;
import static com.android.server.pm.PackageManagerService.DEBUG_INSTALL;
import static com.android.server.pm.PackageManagerService.DEBUG_PACKAGE_SCANNING;
import static com.android.server.pm.PackageManagerService.DEBUG_PERMISSIONS;
@@ -130,6 +131,7 @@ import com.android.server.LocalServices;
import com.android.server.ServiceThread;
import com.android.server.SystemConfig;
import com.android.server.Watchdog;
+import com.android.server.pm.ApexManager;
import com.android.server.pm.PackageManagerServiceUtils;
import com.android.server.pm.PackageSetting;
import com.android.server.pm.SharedUserSetting;
@@ -3317,8 +3319,16 @@ public class PermissionManagerService extends IPermissionManager.Stub {
if (!privappPermissionsDisable && privilegedPermission && pkg.isPrivileged()
&& !platformPackage && platformPermission) {
if (!hasPrivappWhitelistEntry(perm, pkg)) {
- // Only report violations for apps on system image
- if (!mSystemReady && !pkgSetting.getPkgState().isUpdatedSystemApp()) {
+ ApexManager apexMgr = ApexManager.getInstance();
+ String apexContainingPkg = apexMgr.getActiveApexPackageNameContainingPackage(pkg);
+
+ // Only enforce whitelist this on boot
+ if (!mSystemReady
+ // Updated system apps do not need to be whitelisted
+ && !pkgSetting.getPkgState().isUpdatedSystemApp()
+ // Apps that are in updated apexs' do not need to be whitelisted
+ && (apexContainingPkg == null || apexMgr.isFactory(
+ apexMgr.getPackageInfo(apexContainingPkg, MATCH_ACTIVE_PACKAGE)))) {
// it's only a reportable violation if the permission isn't explicitly denied
ArraySet<String> deniedPermissions = null;
if (pkg.isVendor()) {
diff --git a/services/core/java/com/android/server/policy/SoftRestrictedPermissionPolicy.java b/services/core/java/com/android/server/policy/SoftRestrictedPermissionPolicy.java
index 39aeafc345ea..d6c48a00d33d 100644
--- a/services/core/java/com/android/server/policy/SoftRestrictedPermissionPolicy.java
+++ b/services/core/java/com/android/server/policy/SoftRestrictedPermissionPolicy.java
@@ -26,6 +26,7 @@ import static android.content.pm.PackageManager.FLAG_PERMISSION_RESTRICTION_INST
import static android.content.pm.PackageManager.FLAG_PERMISSION_RESTRICTION_SYSTEM_EXEMPT;
import static android.content.pm.PackageManager.FLAG_PERMISSION_RESTRICTION_UPGRADE_EXEMPT;
import static android.content.pm.PackageManager.PERMISSION_GRANTED;
+import static android.os.storage.StorageManager.PROP_LEGACY_OP_STICKY;
import static java.lang.Integer.min;
@@ -36,6 +37,7 @@ import android.content.Context;
import android.content.pm.ApplicationInfo;
import android.content.pm.PackageManager;
import android.os.Build;
+import android.os.SystemProperties;
import android.os.UserHandle;
import android.os.storage.StorageManagerInternal;
@@ -63,6 +65,9 @@ public abstract class SoftRestrictedPermissionPolicy {
}
};
+ private static final boolean isLegacyStorageAppOpStickyGlobal = SystemProperties.getBoolean(
+ PROP_LEGACY_OP_STICKY, /*defaultValue*/true);
+
/**
* TargetSDK is per package. To make sure two apps int the same shared UID do not fight over
* what to set, always compute the combined targetSDK.
@@ -136,9 +141,12 @@ public abstract class SoftRestrictedPermissionPolicy {
shouldPreserveLegacyExternalStorage = pkg.hasPreserveLegacyExternalStorage()
&& smInternal.hasLegacyExternalStorage(appInfo.uid);
targetSDK = getMinimumTargetSDK(context, appInfo, user);
+ // LEGACY_STORAGE op is normally sticky for apps targetig <= Q.
+ // However, this device can be configured to make it non-sticky.
+ boolean isLegacyAppOpSticky = isLegacyStorageAppOpStickyGlobal
+ && targetSDK <= Build.VERSION_CODES.Q;
shouldApplyRestriction = (flags & FLAG_PERMISSION_APPLY_RESTRICTION) != 0
- || (targetSDK > Build.VERSION_CODES.Q
- && !shouldPreserveLegacyExternalStorage);
+ || (!isLegacyAppOpSticky && !shouldPreserveLegacyExternalStorage);
} else {
isWhiteListed = false;
shouldApplyRestriction = false;
diff --git a/services/core/java/com/android/server/power/PowerManagerService.java b/services/core/java/com/android/server/power/PowerManagerService.java
index 5025835b5a59..86ff926af7d4 100644
--- a/services/core/java/com/android/server/power/PowerManagerService.java
+++ b/services/core/java/com/android/server/power/PowerManagerService.java
@@ -3531,7 +3531,9 @@ public final class PowerManagerService extends SystemService
}
// Control light outside of lock.
- light.setFlashing(color, LogicalLight.LIGHT_FLASH_HARDWARE, (on ? 3 : 0), 0);
+ if (light != null) {
+ light.setFlashing(color, LogicalLight.LIGHT_FLASH_HARDWARE, (on ? 3 : 0), 0);
+ }
}
private void setDozeAfterScreenOffInternal(boolean on) {
diff --git a/services/core/java/com/android/server/power/ThermalManagerService.java b/services/core/java/com/android/server/power/ThermalManagerService.java
index 74c3a9ec375b..2783d0b83254 100644
--- a/services/core/java/com/android/server/power/ThermalManagerService.java
+++ b/services/core/java/com/android/server/power/ThermalManagerService.java
@@ -767,7 +767,7 @@ public class ThermalManagerService extends SystemService {
protected boolean connectToHal() {
synchronized (mHalLock) {
try {
- mThermalHal10 = android.hardware.thermal.V1_0.IThermal.getService();
+ mThermalHal10 = android.hardware.thermal.V1_0.IThermal.getService(true);
mThermalHal10.linkToDeath(new DeathRecipient(),
THERMAL_HAL_DEATH_COOKIE);
Slog.i(TAG,
@@ -902,7 +902,7 @@ public class ThermalManagerService extends SystemService {
protected boolean connectToHal() {
synchronized (mHalLock) {
try {
- mThermalHal11 = android.hardware.thermal.V1_1.IThermal.getService();
+ mThermalHal11 = android.hardware.thermal.V1_1.IThermal.getService(true);
mThermalHal11.linkToDeath(new DeathRecipient(),
THERMAL_HAL_DEATH_COOKIE);
mThermalHal11.registerThermalCallback(mThermalCallback11);
@@ -1046,7 +1046,7 @@ public class ThermalManagerService extends SystemService {
protected boolean connectToHal() {
synchronized (mHalLock) {
try {
- mThermalHal20 = android.hardware.thermal.V2_0.IThermal.getService();
+ mThermalHal20 = android.hardware.thermal.V2_0.IThermal.getService(true);
mThermalHal20.linkToDeath(new DeathRecipient(), THERMAL_HAL_DEATH_COOKIE);
mThermalHal20.registerThermalChangedCallback(mThermalCallback20, false,
0 /* not used */);
diff --git a/services/core/java/com/android/server/timezonedetector/TimeZoneDetectorShellCommand.java b/services/core/java/com/android/server/timezonedetector/TimeZoneDetectorShellCommand.java
index b051bab71f12..8ff2a1b6364b 100644
--- a/services/core/java/com/android/server/timezonedetector/TimeZoneDetectorShellCommand.java
+++ b/services/core/java/com/android/server/timezonedetector/TimeZoneDetectorShellCommand.java
@@ -37,9 +37,9 @@ class TimeZoneDetectorShellCommand extends ShellCommand {
}
switch (cmd) {
- case "suggestTelephonyTimeZone":
+ case "suggest_telephony_time_zone":
return runSuggestTelephonyTimeZone();
- case "suggestManualTimeZone":
+ case "suggest_manual_time_zone":
return runSuggestManualTimeZone();
default: {
return handleDefaultCommands(cmd);
@@ -105,9 +105,9 @@ class TimeZoneDetectorShellCommand extends ShellCommand {
pw.println("Time Zone Detector (time_zone_detector) commands:");
pw.println(" help");
pw.println(" Print this help text.");
- pw.println(" suggestTelephonyTimeZone");
+ pw.println(" suggest_telephony_time_zone");
pw.println(" --suggestion <telephony suggestion opts>");
- pw.println(" suggestManualTimeZone");
+ pw.println(" suggest_manual_time_zone");
pw.println(" --suggestion <manual suggestion opts>");
pw.println();
ManualTimeZoneSuggestion.printCommandLineOpts(pw);
diff --git a/services/core/java/com/android/server/wallpaper/WallpaperManagerService.java b/services/core/java/com/android/server/wallpaper/WallpaperManagerService.java
index 722d9f7e7c38..ddf166eb0bd5 100644
--- a/services/core/java/com/android/server/wallpaper/WallpaperManagerService.java
+++ b/services/core/java/com/android/server/wallpaper/WallpaperManagerService.java
@@ -2441,9 +2441,8 @@ public class WallpaperManagerService extends IWallpaperManager.Stub
* the caller here writes new bitmap data.
*/
if (which == FLAG_SYSTEM && mLockWallpaperMap.get(userId) == null) {
- if (DEBUG) {
- Slog.i(TAG, "Migrating system->lock to preserve");
- }
+ Slog.i(TAG, "Migrating current wallpaper to be lock-only before"
+ + "updating system wallpaper");
migrateSystemToLockWallpaperLocked(userId);
}
@@ -2511,6 +2510,8 @@ public class WallpaperManagerService extends IWallpaperManager.Stub
ParcelFileDescriptor fd = ParcelFileDescriptor.open(wallpaper.wallpaperFile,
MODE_CREATE|MODE_READ_WRITE|MODE_TRUNCATE);
if (!SELinux.restorecon(wallpaper.wallpaperFile)) {
+ Slog.w(TAG, "restorecon failed for wallpaper file: " +
+ wallpaper.wallpaperFile.getPath());
return null;
}
wallpaper.name = name;
@@ -2520,10 +2521,8 @@ public class WallpaperManagerService extends IWallpaperManager.Stub
}
// Nullify field to require new computation
wallpaper.primaryColors = null;
- if (DEBUG) {
- Slog.v(TAG, "updateWallpaperBitmapLocked() : id=" + wallpaper.wallpaperId
- + " name=" + name + " file=" + wallpaper.wallpaperFile.getName());
- }
+ Slog.v(TAG, "updateWallpaperBitmapLocked() : id=" + wallpaper.wallpaperId
+ + " name=" + name + " file=" + wallpaper.wallpaperFile.getName());
return fd;
} catch (FileNotFoundException e) {
Slog.w(TAG, "Error setting wallpaper", e);
@@ -2556,7 +2555,7 @@ public class WallpaperManagerService extends IWallpaperManager.Stub
WallpaperData wallpaper;
synchronized (mLock) {
- if (DEBUG) Slog.v(TAG, "setWallpaperComponent name=" + name);
+ Slog.v(TAG, "setWallpaperComponent name=" + name);
wallpaper = mWallpaperMap.get(userId);
if (wallpaper == null) {
throw new IllegalStateException("Wallpaper not yet initialized for user " + userId);
@@ -2571,6 +2570,8 @@ public class WallpaperManagerService extends IWallpaperManager.Stub
if (mLockWallpaperMap.get(userId) == null) {
// We're using the static imagery and there is no lock-specific image in place,
// therefore it's a shared system+lock image that we need to migrate.
+ Slog.i(TAG, "Migrating current wallpaper to be lock-only before"
+ + "updating system wallpaper");
migrateSystemToLockWallpaperLocked(userId);
}
}
diff --git a/services/core/java/com/android/server/wm/ActivityRecord.java b/services/core/java/com/android/server/wm/ActivityRecord.java
index 3477d82f4d71..2f814f598a05 100644
--- a/services/core/java/com/android/server/wm/ActivityRecord.java
+++ b/services/core/java/com/android/server/wm/ActivityRecord.java
@@ -2085,7 +2085,7 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A
/** Returns true if this activity is opaque and fills the entire space of this task. */
boolean occludesParent() {
- return mOccludesParent;
+ return !finishing && mOccludesParent;
}
boolean setOccludesParent(boolean occludesParent) {
diff --git a/services/core/java/com/android/server/wm/ActivityStack.java b/services/core/java/com/android/server/wm/ActivityStack.java
index fa0ad505f1a9..90898597c265 100644
--- a/services/core/java/com/android/server/wm/ActivityStack.java
+++ b/services/core/java/com/android/server/wm/ActivityStack.java
@@ -2342,8 +2342,7 @@ class ActivityStack extends Task {
if (!newTask && isOrhasTask) {
// Starting activity cannot be occluding activity, otherwise starting window could be
// remove immediately without transferring to starting activity.
- final ActivityRecord occludingActivity = getActivity(
- (ar) -> !ar.finishing && ar.occludesParent(), true, r);
+ final ActivityRecord occludingActivity = getOccludingActivityAbove(r);
if (occludingActivity != null) {
// Here it is! Now, if this is not yet visible (occluded by another task) to the
// user, then just add it without starting; it will get started when the user
@@ -3069,6 +3068,14 @@ class ActivityStack extends Task {
task.setOverrideDisplayedBounds(bounds == null || bounds.isEmpty() ? null : bounds);
}
+ /**
+ * Returns the top-most activity that occludes the given one, or @{code null} if none.
+ */
+ @Nullable
+ private ActivityRecord getOccludingActivityAbove(ActivityRecord activity) {
+ return getActivity((ar) -> ar.occludesParent(), true /* traverseTopToBottom */, activity);
+ }
+
boolean willActivityBeVisible(IBinder token) {
final ActivityRecord r = ActivityRecord.forTokenLocked(token);
if (r == null) {
@@ -3076,9 +3083,7 @@ class ActivityStack extends Task {
}
// See if there is an occluding activity on-top of this one.
- final ActivityRecord occludingActivity = getActivity((ar) ->
- ar.occludesParent() && !ar.finishing,
- r, false /*includeBoundary*/, true /*traverseTopToBottom*/);
+ final ActivityRecord occludingActivity = getOccludingActivityAbove(r);
if (occludingActivity != null) return false;
if (r.finishing) Slog.e(TAG, "willActivityBeVisible: Returning false,"
diff --git a/services/core/java/com/android/server/wm/ActivityTaskManagerService.java b/services/core/java/com/android/server/wm/ActivityTaskManagerService.java
index a5b0026398b6..bf92542cdd63 100644
--- a/services/core/java/com/android/server/wm/ActivityTaskManagerService.java
+++ b/services/core/java/com/android/server/wm/ActivityTaskManagerService.java
@@ -32,7 +32,6 @@ import static android.app.ActivityManagerInternal.ALLOW_NON_FULL;
import static android.app.ActivityTaskManager.INVALID_TASK_ID;
import static android.app.ActivityTaskManager.RESIZE_MODE_PRESERVE_WINDOW;
import static android.app.WindowConfiguration.ACTIVITY_TYPE_DREAM;
-import static android.app.WindowConfiguration.ACTIVITY_TYPE_UNDEFINED;
import static android.app.WindowConfiguration.WINDOWING_MODE_FREEFORM;
import static android.app.WindowConfiguration.WINDOWING_MODE_FULLSCREEN;
import static android.app.WindowConfiguration.WINDOWING_MODE_PINNED;
@@ -2615,13 +2614,16 @@ public class ActivityTaskManagerService extends IActivityTaskManager.Stub {
@Override
public List<ActivityManager.RunningTaskInfo> getTasks(int maxNum) {
- return getFilteredTasks(maxNum, ACTIVITY_TYPE_UNDEFINED, WINDOWING_MODE_UNDEFINED);
+ return getFilteredTasks(maxNum, false /* filterForVisibleRecents */);
}
+ /**
+ * @param filterOnlyVisibleRecents whether to filter the tasks based on whether they would ever
+ * be visible in the recent task list in systemui
+ */
@Override
public List<ActivityManager.RunningTaskInfo> getFilteredTasks(int maxNum,
- @WindowConfiguration.ActivityType int ignoreActivityType,
- @WindowConfiguration.WindowingMode int ignoreWindowingMode) {
+ boolean filterOnlyVisibleRecents) {
final int callingUid = Binder.getCallingUid();
final int callingPid = Binder.getCallingPid();
final boolean crossUser = isCrossUserAllowed(callingPid, callingUid);
@@ -2637,8 +2639,8 @@ public class ActivityTaskManagerService extends IActivityTaskManager.Stub {
if (DEBUG_ALL) Slog.v(TAG, "getTasks: max=" + maxNum);
final boolean allowed = isGetTasksAllowed("getTasks", callingPid, callingUid);
- mRootWindowContainer.getRunningTasks(maxNum, list, ignoreActivityType,
- ignoreWindowingMode, callingUid, allowed, crossUser, callingProfileIds);
+ mRootWindowContainer.getRunningTasks(maxNum, list, filterOnlyVisibleRecents, callingUid,
+ allowed, crossUser, callingProfileIds);
}
return list;
diff --git a/services/core/java/com/android/server/wm/AppTransitionController.java b/services/core/java/com/android/server/wm/AppTransitionController.java
index 6a47c9e217f8..654ccc80f8a8 100644
--- a/services/core/java/com/android/server/wm/AppTransitionController.java
+++ b/services/core/java/com/android/server/wm/AppTransitionController.java
@@ -618,6 +618,7 @@ public class AppTransitionController {
Animation anim = mService.mPolicy.createKeyguardWallpaperExit(
(flags & TRANSIT_FLAG_KEYGUARD_GOING_AWAY_TO_SHADE) != 0);
if (anim != null) {
+ anim.scaleCurrentDuration(mService.getTransitionAnimationScaleLocked());
mDisplayContent.mWallpaperController.startWallpaperAnimation(anim);
}
}
diff --git a/services/core/java/com/android/server/wm/DisplayContent.java b/services/core/java/com/android/server/wm/DisplayContent.java
index 6c5428c69377..88c9b2cc0cb9 100644
--- a/services/core/java/com/android/server/wm/DisplayContent.java
+++ b/services/core/java/com/android/server/wm/DisplayContent.java
@@ -1317,8 +1317,6 @@ class DisplayContent extends WindowContainer<DisplayContent.DisplayChildWindowCo
if (mDisplayRotation.isWaitingForRemoteRotation()) {
return;
}
- // Clear the record because the display will sync to current rotation.
- mFixedRotationLaunchingApp = null;
final boolean configUpdated = updateDisplayOverrideConfigurationLocked();
if (configUpdated) {
@@ -1509,7 +1507,7 @@ class DisplayContent extends WindowContainer<DisplayContent.DisplayChildWindowCo
startFixedRotationTransform(r, rotation);
mAppTransition.registerListenerLocked(new WindowManagerInternal.AppTransitionListener() {
void done() {
- r.clearFixedRotationTransform();
+ r.finishFixedRotationTransform();
mAppTransition.unregisterListener(this);
}
@@ -1538,7 +1536,8 @@ class DisplayContent extends WindowContainer<DisplayContent.DisplayChildWindowCo
if (token != mFixedRotationLaunchingApp) {
return false;
}
- if (updateOrientation()) {
+ // Update directly because the app which will change the orientation of display is ready.
+ if (mDisplayRotation.updateOrientation(getOrientation(), false /* forceUpdate */)) {
sendNewConfiguration();
return true;
}
@@ -1584,7 +1583,7 @@ class DisplayContent extends WindowContainer<DisplayContent.DisplayChildWindowCo
* @param oldRotation the rotation we are coming from.
* @param rotation the rotation to apply.
*/
- void applyRotationLocked(final int oldRotation, final int rotation) {
+ private void applyRotation(final int oldRotation, final int rotation) {
mDisplayRotation.applyCurrentRotation(rotation);
final boolean rotateSeamlessly = mDisplayRotation.isRotatingSeamlessly();
final Transaction transaction = getPendingTransaction();
@@ -3210,7 +3209,7 @@ class DisplayContent extends WindowContainer<DisplayContent.DisplayChildWindowCo
if (mode == UPDATE_FOCUS_PLACING_SURFACES) {
performLayout(true /*initial*/, updateInputWindows);
} else if (mode == UPDATE_FOCUS_REMOVING_FOCUS) {
- mWmService.mRoot.performSurfacePlacement(false);
+ mWmService.mRoot.performSurfacePlacement();
}
}
@@ -3847,7 +3846,7 @@ class DisplayContent extends WindowContainer<DisplayContent.DisplayChildWindowCo
}
// TODO: Super crazy long method that should be broken down...
- void applySurfaceChangesTransaction(boolean recoveringMemory) {
+ void applySurfaceChangesTransaction() {
final WindowSurfacePlacer surfacePlacer = mWmService.mWindowPlacerLocked;
mTmpUpdateAllDrawn.clear();
@@ -4432,6 +4431,7 @@ class DisplayContent extends WindowContainer<DisplayContent.DisplayChildWindowCo
position = findPositionForStack(position, stack, true /* adding */);
super.addChild(stack, position);
+ mAtmService.updateSleepIfNeededLocked();
// The reparenting case is handled in WindowContainer.
if (!stack.mReparenting) {
@@ -4443,6 +4443,7 @@ class DisplayContent extends WindowContainer<DisplayContent.DisplayChildWindowCo
protected void removeChild(ActivityStack stack) {
super.removeChild(stack);
mDisplayContent.onStackRemoved(stack);
+ mAtmService.updateSleepIfNeededLocked();
removeStackReferenceIfNeeded(stack);
}
@@ -5648,7 +5649,6 @@ class DisplayContent extends WindowContainer<DisplayContent.DisplayChildWindowCo
void addStack(ActivityStack stack, int position) {
setStackOnDisplay(stack, position);
positionStackAt(stack, position);
- mAtmService.updateSleepIfNeededLocked();
}
void addStackReferenceIfNeeded(ActivityStack stack) {
@@ -5667,7 +5667,6 @@ class DisplayContent extends WindowContainer<DisplayContent.DisplayChildWindowCo
mPreferredTopFocusableStack = null;
}
releaseSelfIfNeeded();
- mAtmService.updateSleepIfNeededLocked();
onStackOrderChanged(stack);
}
@@ -6493,15 +6492,20 @@ class DisplayContent extends WindowContainer<DisplayContent.DisplayChildWindowCo
@Override
public void onRequestedOverrideConfigurationChanged(Configuration overrideConfiguration) {
- final int currRotation =
- getRequestedOverrideConfiguration().windowConfiguration.getRotation();
- if (currRotation != ROTATION_UNDEFINED
- && currRotation != overrideConfiguration.windowConfiguration.getRotation()) {
- applyRotationLocked(currRotation,
- overrideConfiguration.windowConfiguration.getRotation());
- }
- mCurrentOverrideConfigurationChanges =
- getRequestedOverrideConfiguration().diff(overrideConfiguration);
+ final Configuration currOverrideConfig = getRequestedOverrideConfiguration();
+ final int currRotation = currOverrideConfig.windowConfiguration.getRotation();
+ final int overrideRotation = overrideConfiguration.windowConfiguration.getRotation();
+ if (currRotation != ROTATION_UNDEFINED && currRotation != overrideRotation) {
+ if (mFixedRotationLaunchingApp != null) {
+ mFixedRotationLaunchingApp.clearFixedRotationTransform(
+ () -> applyRotation(currRotation, overrideRotation));
+ // Clear the record because the display will sync to current rotation.
+ mFixedRotationLaunchingApp = null;
+ } else {
+ applyRotation(currRotation, overrideRotation);
+ }
+ }
+ mCurrentOverrideConfigurationChanges = currOverrideConfig.diff(overrideConfiguration);
super.onRequestedOverrideConfigurationChanged(overrideConfiguration);
mCurrentOverrideConfigurationChanges = 0;
mWmService.setNewDisplayOverrideConfiguration(overrideConfiguration, this);
diff --git a/services/core/java/com/android/server/wm/DisplayRotation.java b/services/core/java/com/android/server/wm/DisplayRotation.java
index 60b817c13236..af89a05bfa62 100644
--- a/services/core/java/com/android/server/wm/DisplayRotation.java
+++ b/services/core/java/com/android/server/wm/DisplayRotation.java
@@ -484,11 +484,8 @@ public class DisplayRotation {
prepareNormalRotationAnimation();
}
- // TODO(b/147469351): Remove the restriction.
- if (mDisplayContent.mFixedRotationLaunchingApp == null) {
- // Give a remote handler (system ui) some time to reposition things.
- startRemoteRotation(oldRotation, mRotation);
- }
+ // Give a remote handler (system ui) some time to reposition things.
+ startRemoteRotation(oldRotation, mRotation);
return true;
}
diff --git a/services/core/java/com/android/server/wm/InputMonitor.java b/services/core/java/com/android/server/wm/InputMonitor.java
index 88cdd1781aee..18332b9484c0 100644
--- a/services/core/java/com/android/server/wm/InputMonitor.java
+++ b/services/core/java/com/android/server/wm/InputMonitor.java
@@ -62,7 +62,7 @@ final class InputMonitor {
// When true, need to call updateInputWindowsLw().
private boolean mUpdateInputWindowsNeeded = true;
private boolean mUpdateInputWindowsPending;
- private boolean mApplyImmediately;
+ private boolean mUpdateInputWindowsImmediately;
// Currently focused input window handle.
private InputWindowHandle mFocusedInputWindowHandle;
@@ -347,14 +347,20 @@ final class InputMonitor {
}
}
- void updateInputWindowsImmediately() {
+ /**
+ * Immediately update the input transaction and merge into the passing Transaction that could be
+ * collected and applied later.
+ */
+ void updateInputWindowsImmediately(SurfaceControl.Transaction t) {
mHandler.removeCallbacks(mUpdateInputWindows);
- mApplyImmediately = true;
+ mUpdateInputWindowsImmediately = true;
mUpdateInputWindows.run();
- mApplyImmediately = false;
+ mUpdateInputWindowsImmediately = false;
+ t.merge(mInputTransaction);
}
- /* Called when the current input focus changes.
+ /**
+ * Called when the current input focus changes.
* Layer assignment is assumed to be complete by the time this is called.
*/
public void setInputFocusLw(WindowState newWindow, boolean updateInputWindows) {
@@ -465,10 +471,7 @@ final class InputMonitor {
if (mAddWallpaperInputConsumerHandle) {
mWallpaperInputConsumer.show(mInputTransaction, 0);
}
-
- if (mApplyImmediately) {
- mInputTransaction.apply();
- } else {
+ if (!mUpdateInputWindowsImmediately) {
mDisplayContent.getPendingTransaction().merge(mInputTransaction);
mDisplayContent.scheduleAnimation();
}
diff --git a/services/core/java/com/android/server/wm/InsetsPolicy.java b/services/core/java/com/android/server/wm/InsetsPolicy.java
index ac6e75c717ff..fda70d14db2b 100644
--- a/services/core/java/com/android/server/wm/InsetsPolicy.java
+++ b/services/core/java/com/android/server/wm/InsetsPolicy.java
@@ -97,7 +97,8 @@ class InsetsPolicy {
private void updateHideNavInputEventReceiver() {
mPolicy.updateHideNavInputEventReceiver(!isHidden(ITYPE_NAVIGATION_BAR),
- mFocusedWin.mAttrs.insetsFlags.behavior != BEHAVIOR_SHOW_BARS_BY_TOUCH);
+ mFocusedWin != null
+ && mFocusedWin.mAttrs.insetsFlags.behavior != BEHAVIOR_SHOW_BARS_BY_TOUCH);
}
boolean isHidden(@InternalInsetsType int type) {
diff --git a/services/core/java/com/android/server/wm/RecentTasks.java b/services/core/java/com/android/server/wm/RecentTasks.java
index 244ba82ce32c..12be9df55fad 100644
--- a/services/core/java/com/android/server/wm/RecentTasks.java
+++ b/services/core/java/com/android/server/wm/RecentTasks.java
@@ -25,6 +25,7 @@ import static android.app.WindowConfiguration.ACTIVITY_TYPE_DREAM;
import static android.app.WindowConfiguration.ACTIVITY_TYPE_HOME;
import static android.app.WindowConfiguration.ACTIVITY_TYPE_RECENTS;
import static android.app.WindowConfiguration.ACTIVITY_TYPE_UNDEFINED;
+import static android.app.WindowConfiguration.WINDOWING_MODE_MULTI_WINDOW;
import static android.app.WindowConfiguration.WINDOWING_MODE_PINNED;
import static android.app.WindowConfiguration.WINDOWING_MODE_SPLIT_SCREEN_PRIMARY;
import static android.app.WindowConfiguration.WINDOWING_MODE_UNDEFINED;
@@ -1309,6 +1310,7 @@ class RecentTasks {
== FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS) {
return false;
}
+ break;
}
// Ignore certain windowing modes
@@ -1316,23 +1318,21 @@ class RecentTasks {
case WINDOWING_MODE_PINNED:
return false;
case WINDOWING_MODE_SPLIT_SCREEN_PRIMARY:
- if (DEBUG_RECENTS_TRIM_TASKS) Slog.d(TAG, "\ttop=" + task.getStack().getTopMostTask());
+ if (DEBUG_RECENTS_TRIM_TASKS) {
+ Slog.d(TAG, "\ttop=" + task.getStack().getTopMostTask());
+ }
final ActivityStack stack = task.getStack();
if (stack != null && stack.getTopMostTask() == task) {
// Only the non-top task of the primary split screen mode is visible
return false;
}
- }
-
- // Tasks managed by/associated with an ActivityView should be excluded from recents.
- // singleTaskInstance is set on the VirtualDisplay managed by ActivityView
- // TODO(b/126185105): Find a different signal to use besides isSingleTaskInstance
- final ActivityStack stack = task.getStack();
- if (stack != null) {
- DisplayContent display = stack.getDisplay();
- if (display != null && display.isSingleTaskInstance()) {
- return false;
- }
+ break;
+ case WINDOWING_MODE_MULTI_WINDOW:
+ // Ignore tasks that are always on top
+ if (task.isAlwaysOnTop()) {
+ return false;
+ }
+ break;
}
// If we're in lock task mode, ignore the root task
diff --git a/services/core/java/com/android/server/wm/RecentsAnimation.java b/services/core/java/com/android/server/wm/RecentsAnimation.java
index 9089240fe9d1..057592c0c2fc 100644
--- a/services/core/java/com/android/server/wm/RecentsAnimation.java
+++ b/services/core/java/com/android/server/wm/RecentsAnimation.java
@@ -400,6 +400,12 @@ class RecentsAnimation implements RecentsAnimationCallbacks,
throw e;
} finally {
mService.continueWindowLayout();
+ // Make sure the surfaces are updated with the latest state. Sometimes the
+ // surface placement may be skipped if display configuration is changed (i.e.
+ // {@link DisplayContent#mWaitingForConfig} is true).
+ if (mWindowManager.mRoot.isLayoutNeeded()) {
+ mWindowManager.mRoot.performSurfacePlacement();
+ }
Trace.traceEnd(TRACE_TAG_WINDOW_MANAGER);
}
});
diff --git a/services/core/java/com/android/server/wm/RecentsAnimationController.java b/services/core/java/com/android/server/wm/RecentsAnimationController.java
index 3e5cb50d6101..a30b70de267d 100644
--- a/services/core/java/com/android/server/wm/RecentsAnimationController.java
+++ b/services/core/java/com/android/server/wm/RecentsAnimationController.java
@@ -667,7 +667,7 @@ public class RecentsAnimationController implements DeathRecipient {
mTargetActivityRecord.token);
}
if (mTargetActivityRecord.hasFixedRotationTransform()) {
- mTargetActivityRecord.clearFixedRotationTransform();
+ mTargetActivityRecord.finishFixedRotationTransform();
}
}
diff --git a/services/core/java/com/android/server/wm/RootWindowContainer.java b/services/core/java/com/android/server/wm/RootWindowContainer.java
index b2920ee1d4aa..ff174278878f 100644
--- a/services/core/java/com/android/server/wm/RootWindowContainer.java
+++ b/services/core/java/com/android/server/wm/RootWindowContainer.java
@@ -796,10 +796,10 @@ class RootWindowContainer extends WindowContainer<DisplayContent>
return leakedSurface || killedApps;
}
- void performSurfacePlacement(boolean recoveringMemory) {
+ void performSurfacePlacement() {
Trace.traceBegin(TRACE_TAG_WINDOW_MANAGER, "performSurfacePlacement");
try {
- performSurfacePlacementNoTrace(recoveringMemory);
+ performSurfacePlacementNoTrace();
} finally {
Trace.traceEnd(TRACE_TAG_WINDOW_MANAGER);
}
@@ -807,7 +807,7 @@ class RootWindowContainer extends WindowContainer<DisplayContent>
// "Something has changed! Let's make it correct now."
// TODO: Super crazy long method that should be broken down...
- void performSurfacePlacementNoTrace(boolean recoveringMemory) {
+ void performSurfacePlacementNoTrace() {
if (DEBUG_WINDOW_TRACE) Slog.v(TAG, "performSurfacePlacementInner: entry. Called by "
+ Debug.getCallers(3));
@@ -842,7 +842,7 @@ class RootWindowContainer extends WindowContainer<DisplayContent>
Trace.traceBegin(TRACE_TAG_WINDOW_MANAGER, "applySurfaceChanges");
mWmService.openSurfaceTransaction();
try {
- applySurfaceChangesTransaction(recoveringMemory);
+ applySurfaceChangesTransaction();
} catch (RuntimeException e) {
Slog.wtf(TAG, "Unhandled exception in Window Manager", e);
} finally {
@@ -1042,7 +1042,7 @@ class RootWindowContainer extends WindowContainer<DisplayContent>
}
}
- private void applySurfaceChangesTransaction(boolean recoveringMemory) {
+ private void applySurfaceChangesTransaction() {
mHoldScreenWindow = null;
mObscuringWindow = null;
@@ -1065,7 +1065,7 @@ class RootWindowContainer extends WindowContainer<DisplayContent>
final int count = mChildren.size();
for (int j = 0; j < count; ++j) {
final DisplayContent dc = mChildren.get(j);
- dc.applySurfaceChangesTransaction(recoveringMemory);
+ dc.applySurfaceChangesTransaction();
}
// Give the display manager a chance to adjust properties like display rotation if it needs
@@ -2852,7 +2852,8 @@ class RootWindowContainer extends WindowContainer<DisplayContent>
* @param candidateTask The possible task the activity might be put in.
* @return Existing stack if there is a valid one, new dynamic stack if it is valid or null.
*/
- private ActivityStack getValidLaunchStackOnDisplay(int displayId, @NonNull ActivityRecord r,
+ @VisibleForTesting
+ ActivityStack getValidLaunchStackOnDisplay(int displayId, @NonNull ActivityRecord r,
@Nullable Task candidateTask, @Nullable ActivityOptions options,
@Nullable LaunchParamsController.LaunchParams launchParams) {
final DisplayContent displayContent = getDisplayContentOrCreate(displayId);
@@ -2873,6 +2874,13 @@ class RootWindowContainer extends WindowContainer<DisplayContent>
if (attachedDisplayId == INVALID_DISPLAY || attachedDisplayId == displayId) {
return candidateTask.getStack();
}
+ // Or the candidate task is already a root task that can be reused by reparenting
+ // it to the target display.
+ if (candidateTask.isRootTask()) {
+ final ActivityStack stack = candidateTask.getStack();
+ displayContent.moveStackToDisplay(stack, true /* onTop */);
+ return stack;
+ }
}
int windowingMode;
@@ -3385,11 +3393,10 @@ class RootWindowContainer extends WindowContainer<DisplayContent>
@VisibleForTesting
void getRunningTasks(int maxNum, List<ActivityManager.RunningTaskInfo> list,
- @WindowConfiguration.ActivityType int ignoreActivityType,
- @WindowConfiguration.WindowingMode int ignoreWindowingMode, int callingUid,
- boolean allowed, boolean crossUser, ArraySet<Integer> profileIds) {
- mStackSupervisor.getRunningTasks().getTasks(maxNum, list, ignoreActivityType,
- ignoreWindowingMode, this, callingUid, allowed, crossUser, profileIds);
+ boolean filterOnlyVisibleRecents, int callingUid, boolean allowed, boolean crossUser,
+ ArraySet<Integer> profileIds) {
+ mStackSupervisor.getRunningTasks().getTasks(maxNum, list, filterOnlyVisibleRecents, this,
+ callingUid, allowed, crossUser, profileIds);
}
void sendPowerHintForLaunchStartIfNeeded(boolean forceSend, ActivityRecord targetActivity) {
diff --git a/services/core/java/com/android/server/wm/RunningTasks.java b/services/core/java/com/android/server/wm/RunningTasks.java
index 02077fbf453e..3509ba72d058 100644
--- a/services/core/java/com/android/server/wm/RunningTasks.java
+++ b/services/core/java/com/android/server/wm/RunningTasks.java
@@ -16,12 +16,10 @@
package com.android.server.wm;
-import static android.app.WindowConfiguration.ACTIVITY_TYPE_UNDEFINED;
-import static android.app.WindowConfiguration.WINDOWING_MODE_UNDEFINED;
+import static android.app.WindowConfiguration.ACTIVITY_TYPE_HOME;
+import static android.app.WindowConfiguration.ACTIVITY_TYPE_RECENTS;
import android.app.ActivityManager.RunningTaskInfo;
-import android.app.WindowConfiguration.ActivityType;
-import android.app.WindowConfiguration.WindowingMode;
import android.os.UserHandle;
import android.util.ArraySet;
@@ -49,13 +47,13 @@ class RunningTasks {
private boolean mCrossUser;
private ArraySet<Integer> mProfileIds;
private boolean mAllowed;
- private int mIgnoreActivityType;
- private int mIgnoreWindowingMode;
+ private boolean mFilterOnlyVisibleRecents;
private ActivityStack mTopDisplayFocusStack;
+ private RecentTasks mRecentTasks;
- void getTasks(int maxNum, List<RunningTaskInfo> list, @ActivityType int ignoreActivityType,
- @WindowingMode int ignoreWindowingMode, RootWindowContainer root,
- int callingUid, boolean allowed, boolean crossUser, ArraySet<Integer> profileIds) {
+ void getTasks(int maxNum, List<RunningTaskInfo> list, boolean filterOnlyVisibleRecents,
+ RootWindowContainer root, int callingUid, boolean allowed, boolean crossUser,
+ ArraySet<Integer> profileIds) {
// Return early if there are no tasks to fetch
if (maxNum <= 0) {
return;
@@ -68,9 +66,9 @@ class RunningTasks {
mCrossUser = crossUser;
mProfileIds = profileIds;
mAllowed = allowed;
- mIgnoreActivityType = ignoreActivityType;
- mIgnoreWindowingMode = ignoreWindowingMode;
+ mFilterOnlyVisibleRecents = filterOnlyVisibleRecents;
mTopDisplayFocusStack = root.getTopDisplayFocusedStack();
+ mRecentTasks = root.mService.getRecentTasks();
final PooledConsumer c = PooledLambda.obtainConsumer(RunningTasks::processTask, this,
PooledLambda.__(Task.class));
@@ -107,14 +105,12 @@ class RunningTasks {
return;
}
}
- if (mIgnoreActivityType != ACTIVITY_TYPE_UNDEFINED
- && task.getActivityType() == mIgnoreActivityType) {
- // Skip ignored activity type
- return;
- }
- if (mIgnoreWindowingMode != WINDOWING_MODE_UNDEFINED
- && task.getWindowingMode() == mIgnoreWindowingMode) {
- // Skip ignored windowing mode
+ if (mFilterOnlyVisibleRecents
+ && task.getActivityType() != ACTIVITY_TYPE_HOME
+ && task.getActivityType() != ACTIVITY_TYPE_RECENTS
+ && !mRecentTasks.isVisibleRecentTask(task)) {
+ // Skip if this task wouldn't be visibile (ever) from recents, with an exception for the
+ // home & recent tasks
return;
}
diff --git a/services/core/java/com/android/server/wm/Task.java b/services/core/java/com/android/server/wm/Task.java
index f19c10637c9b..7a41ea57610d 100644
--- a/services/core/java/com/android/server/wm/Task.java
+++ b/services/core/java/com/android/server/wm/Task.java
@@ -4111,8 +4111,7 @@ class Task extends WindowContainer<WindowContainer> {
return true;
}
- // Called on Binder death.
- void taskOrganizerDied() {
+ void taskOrganizerUnregistered() {
mTaskOrganizer = null;
mLastTaskOrganizerWindowingMode = -1;
onTaskOrganizerChanged();
diff --git a/services/core/java/com/android/server/wm/TaskOrganizerController.java b/services/core/java/com/android/server/wm/TaskOrganizerController.java
index 05b721b8ee81..4382e9d578ad 100644
--- a/services/core/java/com/android/server/wm/TaskOrganizerController.java
+++ b/services/core/java/com/android/server/wm/TaskOrganizerController.java
@@ -34,6 +34,7 @@ import android.os.Binder;
import android.os.IBinder;
import android.os.RemoteException;
import android.util.Slog;
+import android.util.SparseArray;
import android.window.ITaskOrganizer;
import android.window.ITaskOrganizerController;
import android.window.IWindowContainer;
@@ -42,6 +43,7 @@ import com.android.internal.util.ArrayUtils;
import java.util.ArrayList;
import java.util.HashMap;
+import java.util.LinkedList;
import java.util.List;
import java.util.WeakHashMap;
@@ -51,6 +53,7 @@ import java.util.WeakHashMap;
*/
class TaskOrganizerController extends ITaskOrganizerController.Stub {
private static final String TAG = "TaskOrganizerController";
+ private static final LinkedList<TaskOrganizerState> EMPTY_LIST = new LinkedList<>();
/**
* Masks specifying which configurations are important to report back to an organizer when
@@ -73,32 +76,20 @@ class TaskOrganizerController extends ITaskOrganizerController.Stub {
@Override
public void binderDied() {
synchronized (mGlobalLock) {
- final TaskOrganizerState state =
- mTaskOrganizerStates.get(mTaskOrganizer.asBinder());
- state.releaseTasks();
- mTaskOrganizerStates.remove(mTaskOrganizer.asBinder());
- if (mTaskOrganizersForWindowingMode.get(mWindowingMode) == mTaskOrganizer) {
- mTaskOrganizersForWindowingMode.remove(mWindowingMode);
- }
+ final TaskOrganizerState state = mTaskOrganizerStates.remove(
+ mTaskOrganizer.asBinder());
+ state.dispose();
}
}
};
- class TaskOrganizerState {
- ITaskOrganizer mOrganizer;
- DeathRecipient mDeathRecipient;
- int mWindowingMode;
-
- ArrayList<Task> mOrganizedTasks = new ArrayList<>();
-
- // Save the TaskOrganizer which we replaced registration for
- // so it can be re-registered if we unregister.
- TaskOrganizerState mReplacementFor;
- boolean mDisposed = false;
+ private class TaskOrganizerState {
+ private final ITaskOrganizer mOrganizer;
+ private final DeathRecipient mDeathRecipient;
+ private final int mWindowingMode;
+ private final ArrayList<Task> mOrganizedTasks = new ArrayList<>();
-
- TaskOrganizerState(ITaskOrganizer organizer, int windowingMode,
- @Nullable TaskOrganizerState replacing) {
+ TaskOrganizerState(ITaskOrganizer organizer, int windowingMode) {
mOrganizer = organizer;
mDeathRecipient = new DeathRecipient(organizer, windowingMode);
try {
@@ -107,7 +98,6 @@ class TaskOrganizerController extends ITaskOrganizerController.Stub {
Slog.e(TAG, "TaskOrganizer failed to register death recipient");
}
mWindowingMode = windowingMode;
- mReplacementFor = replacing;
}
void addTask(Task t) {
@@ -129,35 +119,26 @@ class TaskOrganizerController extends ITaskOrganizerController.Stub {
}
void dispose() {
- mDisposed = true;
releaseTasks();
- handleReplacement();
+ mTaskOrganizersForWindowingMode.get(mWindowingMode).remove(this);
}
- void releaseTasks() {
+ private void releaseTasks() {
for (int i = mOrganizedTasks.size() - 1; i >= 0; i--) {
final Task t = mOrganizedTasks.get(i);
- t.taskOrganizerDied();
removeTask(t);
- }
- }
-
- void handleReplacement() {
- if (mReplacementFor != null && !mReplacementFor.mDisposed) {
- mTaskOrganizersForWindowingMode.put(mWindowingMode, mReplacementFor);
+ t.taskOrganizerUnregistered();
}
}
void unlinkDeath() {
- mDisposed = true;
mOrganizer.asBinder().unlinkToDeath(mDeathRecipient, 0);
}
- };
-
-
- final HashMap<Integer, TaskOrganizerState> mTaskOrganizersForWindowingMode = new HashMap();
- final HashMap<IBinder, TaskOrganizerState> mTaskOrganizerStates = new HashMap();
+ }
+ private final SparseArray<LinkedList<TaskOrganizerState>> mTaskOrganizersForWindowingMode =
+ new SparseArray<>();
+ private final HashMap<IBinder, TaskOrganizerState> mTaskOrganizerStates = new HashMap<>();
private final WeakHashMap<Task, RunningTaskInfo> mLastSentTaskInfos = new WeakHashMap<>();
private final ArrayList<Task> mPendingTaskInfoChanges = new ArrayList<>();
@@ -196,11 +177,17 @@ class TaskOrganizerController extends ITaskOrganizerController.Stub {
Slog.w(TAG, "Task organizer already exists for windowing mode: "
+ windowingMode);
}
- final TaskOrganizerState previousState =
- mTaskOrganizersForWindowingMode.get(windowingMode);
- final TaskOrganizerState state = new TaskOrganizerState(organizer, windowingMode,
- previousState);
- mTaskOrganizersForWindowingMode.put(windowingMode, state);
+
+ LinkedList<TaskOrganizerState> states;
+ if (mTaskOrganizersForWindowingMode.contains(windowingMode)) {
+ states = mTaskOrganizersForWindowingMode.get(windowingMode);
+ } else {
+ states = new LinkedList<>();
+ mTaskOrganizersForWindowingMode.put(windowingMode, states);
+ }
+ final TaskOrganizerState previousState = states.peekLast();
+ final TaskOrganizerState state = new TaskOrganizerState(organizer, windowingMode);
+ states.add(state);
mTaskOrganizerStates.put(organizer.asBinder(), state);
if (previousState == null) {
@@ -221,16 +208,14 @@ class TaskOrganizerController extends ITaskOrganizerController.Stub {
@Override
public void unregisterTaskOrganizer(ITaskOrganizer organizer) {
- final TaskOrganizerState state = mTaskOrganizerStates.get(organizer.asBinder());
+ final TaskOrganizerState state = mTaskOrganizerStates.remove(organizer.asBinder());
state.unlinkDeath();
- if (mTaskOrganizersForWindowingMode.get(state.mWindowingMode) == state) {
- mTaskOrganizersForWindowingMode.remove(state.mWindowingMode);
- }
state.dispose();
}
ITaskOrganizer getTaskOrganizer(int windowingMode) {
- final TaskOrganizerState state = mTaskOrganizersForWindowingMode.get(windowingMode);
+ final TaskOrganizerState state = mTaskOrganizersForWindowingMode.get(windowingMode,
+ EMPTY_LIST).peekLast();
if (state == null) {
return null;
}
diff --git a/services/core/java/com/android/server/wm/TaskPositioner.java b/services/core/java/com/android/server/wm/TaskPositioner.java
index f046e8adc478..be0d6f8a0b9f 100644
--- a/services/core/java/com/android/server/wm/TaskPositioner.java
+++ b/services/core/java/com/android/server/wm/TaskPositioner.java
@@ -268,8 +268,9 @@ class TaskPositioner implements IBinder.DeathRecipient {
mDisplayContent.getDisplayRotation().pause();
// Notify InputMonitor to take mDragWindowHandle.
- mDisplayContent.getInputMonitor().updateInputWindowsImmediately();
- new SurfaceControl.Transaction().syncInputWindows().apply(true);
+ final SurfaceControl.Transaction t = mService.mTransactionFactory.get();
+ mDisplayContent.getInputMonitor().updateInputWindowsImmediately(t);
+ t.syncInputWindows().apply();
final DisplayMetrics displayMetrics = displayContent.getDisplayMetrics();
mMinVisibleWidth = dipToPixel(MINIMUM_VISIBLE_WIDTH_IN_DP, displayMetrics);
diff --git a/services/core/java/com/android/server/wm/WallpaperController.java b/services/core/java/com/android/server/wm/WallpaperController.java
index 57d0a335a688..29a2e18f46a8 100644
--- a/services/core/java/com/android/server/wm/WallpaperController.java
+++ b/services/core/java/com/android/server/wm/WallpaperController.java
@@ -142,11 +142,13 @@ class WallpaperController {
mFindResults.setUseTopWallpaperAsTarget(true);
}
- final boolean keyguardGoingAwayWithWallpaper = (w.mActivityRecord != null
- && w.mActivityRecord.isAnimating(TRANSITION | PARENTS)
- && AppTransition.isKeyguardGoingAwayTransit(w.mActivityRecord.getTransit())
- && (w.mActivityRecord.getTransitFlags()
- & TRANSIT_FLAG_KEYGUARD_GOING_AWAY_WITH_WALLPAPER) != 0);
+ final WindowContainer animatingContainer = w.mActivityRecord != null
+ ? w.mActivityRecord.getAnimatingContainer() : null;
+ final boolean keyguardGoingAwayWithWallpaper = (animatingContainer != null
+ && animatingContainer.isAnimating(TRANSITION | PARENTS)
+ && AppTransition.isKeyguardGoingAwayTransit(animatingContainer.mTransit)
+ && (animatingContainer.mTransitFlags
+ & TRANSIT_FLAG_KEYGUARD_GOING_AWAY_WITH_WALLPAPER) != 0);
boolean needsShowWhenLockedWallpaper = false;
if ((w.mAttrs.flags & FLAG_SHOW_WHEN_LOCKED) != 0
@@ -166,8 +168,6 @@ class WallpaperController {
final RecentsAnimationController recentsAnimationController =
mService.getRecentsAnimationController();
- final WindowContainer animatingContainer =
- w.mActivityRecord != null ? w.mActivityRecord.getAnimatingContainer() : null;
final boolean animationWallpaper = animatingContainer != null
&& animatingContainer.getAnimation() != null
&& animatingContainer.getAnimation().getShowWallpaper();
diff --git a/services/core/java/com/android/server/wm/WindowManagerService.java b/services/core/java/com/android/server/wm/WindowManagerService.java
index 23ba528b6aee..075772566d56 100644
--- a/services/core/java/com/android/server/wm/WindowManagerService.java
+++ b/services/core/java/com/android/server/wm/WindowManagerService.java
@@ -7746,19 +7746,23 @@ public class WindowManagerService extends IWindowManager.Stub
public void syncInputTransactions() {
waitForAnimationsToComplete();
+ // Collect all input transactions from all displays to make sure we could sync all input
+ // windows at same time.
+ final SurfaceControl.Transaction t = mTransactionFactory.get();
synchronized (mGlobalLock) {
mWindowPlacerLocked.performSurfacePlacementIfScheduled();
mRoot.forAllDisplays(displayContent ->
- displayContent.getInputMonitor().updateInputWindowsImmediately());
+ displayContent.getInputMonitor().updateInputWindowsImmediately(t));
}
- mTransactionFactory.get().syncInputWindows().apply(true);
+ t.syncInputWindows().apply();
}
private void waitForAnimationsToComplete() {
synchronized (mGlobalLock) {
long timeoutRemaining = ANIMATION_COMPLETED_TIMEOUT_MS;
- while (mRoot.isAnimating(TRANSITION | CHILDREN) && timeoutRemaining > 0) {
+ while ((mAnimator.isAnimationScheduled()
+ || mRoot.isAnimating(TRANSITION | CHILDREN)) && timeoutRemaining > 0) {
long startTime = System.currentTimeMillis();
try {
mGlobalLock.wait(timeoutRemaining);
diff --git a/services/core/java/com/android/server/wm/WindowSurfacePlacer.java b/services/core/java/com/android/server/wm/WindowSurfacePlacer.java
index 0cfdebc6792d..6b9fbcbf459f 100644
--- a/services/core/java/com/android/server/wm/WindowSurfacePlacer.java
+++ b/services/core/java/com/android/server/wm/WindowSurfacePlacer.java
@@ -157,9 +157,7 @@ class WindowSurfacePlacer {
mInLayout = true;
- boolean recoveringMemory = false;
if (!mService.mForceRemoves.isEmpty()) {
- recoveringMemory = true;
// Wait a little bit for things to settle down, and off we go.
while (!mService.mForceRemoves.isEmpty()) {
final WindowState ws = mService.mForceRemoves.remove(0);
@@ -177,7 +175,7 @@ class WindowSurfacePlacer {
}
try {
- mService.mRoot.performSurfacePlacement(recoveringMemory);
+ mService.mRoot.performSurfacePlacement();
mInLayout = false;
diff --git a/services/core/java/com/android/server/wm/WindowToken.java b/services/core/java/com/android/server/wm/WindowToken.java
index 850c36238513..3c2b6ec9711d 100644
--- a/services/core/java/com/android/server/wm/WindowToken.java
+++ b/services/core/java/com/android/server/wm/WindowToken.java
@@ -480,26 +480,42 @@ class WindowToken extends WindowContainer<WindowState> {
}
/**
- * Clears the transformation and continue updating the orientation change of display. Only the
- * state owner can clear the transform state.
+ * Finishes the transform and continue updating the orientation change of display. Only the
+ * state owner can finish the transform state.
*/
- void clearFixedRotationTransform() {
+ void finishFixedRotationTransform() {
+ if (mFixedRotationTransformState == null || mFixedRotationTransformState.mOwner != this) {
+ return;
+ }
+ final boolean changed =
+ mDisplayContent.continueUpdateOrientationForDiffOrienLaunchingApp(this);
+ // If it is not the launching app or the display is not rotated, make sure the transform is
+ // cleared and the configuration is restored from parent.
+ if (!changed) {
+ clearFixedRotationTransform(null /* applyDisplayRotation */);
+ onConfigurationChanged(getParent().getConfiguration());
+ }
+ }
+
+ /**
+ * Clears the transform and apply display rotation if the action is given. The caller needs to
+ * refresh the configuration of this container after this method call.
+ */
+ void clearFixedRotationTransform(Runnable applyDisplayRotation) {
final FixedRotationTransformState state = mFixedRotationTransformState;
- if (state == null || state.mOwner != this) {
+ if (state == null) {
return;
}
+
state.resetTransform();
// Clear the flag so if the display will be updated to the same orientation, the transform
- // won't take effect. The state is cleared at the end, because it is used to indicate that
- // other windows can use seamless rotation when applying rotation to display.
+ // won't take effect.
state.mIsTransforming = false;
- final boolean changed =
- mDisplayContent.continueUpdateOrientationForDiffOrienLaunchingApp(this);
- // If it is not the launching app or the display is not rotated, make sure the merged
- // override configuration is restored from parent.
- if (!changed) {
- onMergedOverrideConfigurationChanged();
+ if (applyDisplayRotation != null) {
+ applyDisplayRotation.run();
}
+ // The state is cleared at the end, because it is used to indicate that other windows can
+ // use seamless rotation when applying rotation to display.
for (int i = state.mAssociatedTokens.size() - 1; i >= 0; i--) {
state.mAssociatedTokens.get(i).mFixedRotationTransformState = null;
}
diff --git a/services/core/jni/com_android_server_input_InputManagerService.cpp b/services/core/jni/com_android_server_input_InputManagerService.cpp
index e3f9ae8969b3..9bc5d34c11af 100644
--- a/services/core/jni/com_android_server_input_InputManagerService.cpp
+++ b/services/core/jni/com_android_server_input_InputManagerService.cpp
@@ -206,7 +206,7 @@ public:
status_t unregisterInputChannel(JNIEnv* env, const sp<InputChannel>& inputChannel);
status_t pilferPointers(const sp<IBinder>& token);
- void setInputWindows(JNIEnv* env, jobjectArray windowHandleObjArray, int32_t displayId);
+ void displayRemoved(JNIEnv* env, int32_t displayId);
void setFocusedApplication(JNIEnv* env, int32_t displayId, jobject applicationHandleObj);
void setFocusedDisplay(JNIEnv* env, int32_t displayId);
void setInputDispatchMode(bool enabled, bool frozen);
@@ -771,55 +771,10 @@ void NativeInputManager::getDispatcherConfiguration(InputDispatcherConfiguration
}
}
-void NativeInputManager::setInputWindows(JNIEnv* env, jobjectArray windowHandleObjArray,
- int32_t displayId) {
- std::vector<sp<InputWindowHandle> > windowHandles;
-
- if (windowHandleObjArray) {
- jsize length = env->GetArrayLength(windowHandleObjArray);
- for (jsize i = 0; i < length; i++) {
- jobject windowHandleObj = env->GetObjectArrayElement(windowHandleObjArray, i);
- if (! windowHandleObj) {
- break; // found null element indicating end of used portion of the array
- }
-
- sp<InputWindowHandle> windowHandle =
- android_view_InputWindowHandle_getHandle(env, windowHandleObj);
- if (windowHandle != nullptr) {
- windowHandles.push_back(windowHandle);
- }
- env->DeleteLocalRef(windowHandleObj);
- }
- }
-
- mInputManager->getDispatcher()->setInputWindows(windowHandles, displayId);
-
- // Do this after the dispatcher has updated the window handle state.
- bool newPointerGesturesEnabled = true;
- size_t numWindows = windowHandles.size();
- for (size_t i = 0; i < numWindows; i++) {
- const sp<InputWindowHandle>& windowHandle = windowHandles[i];
- const InputWindowInfo* windowInfo = windowHandle->getInfo();
- if (windowInfo && windowInfo->hasFocus && (windowInfo->inputFeatures
- & InputWindowInfo::INPUT_FEATURE_DISABLE_TOUCH_PAD_GESTURES)) {
- newPointerGesturesEnabled = false;
- }
- }
-
- bool pointerGesturesEnabledChanged = false;
- { // acquire lock
- AutoMutex _l(mLock);
-
- if (mLocked.pointerGesturesEnabled != newPointerGesturesEnabled) {
- mLocked.pointerGesturesEnabled = newPointerGesturesEnabled;
- pointerGesturesEnabledChanged = true;
- }
- } // release lock
-
- if (pointerGesturesEnabledChanged) {
- mInputManager->getReader()->requestRefreshConfiguration(
- InputReaderConfiguration::CHANGE_POINTER_GESTURE_ENABLEMENT);
- }
+void NativeInputManager::displayRemoved(JNIEnv* env, int32_t displayId) {
+ // Set an empty list to remove all handles from the specific display.
+ std::vector<sp<InputWindowHandle>> windowHandles;
+ mInputManager->getDispatcher()->setInputWindows({{displayId, windowHandles}});
}
void NativeInputManager::setFocusedApplication(JNIEnv* env, int32_t displayId,
@@ -1567,11 +1522,10 @@ static void nativeToggleCapsLock(JNIEnv* env, jclass /* clazz */,
im->getInputManager()->getReader()->toggleCapsLockState(deviceId);
}
-static void nativeSetInputWindows(JNIEnv* env, jclass /* clazz */,
- jlong ptr, jobjectArray windowHandleObjArray, jint displayId) {
+static void nativeDisplayRemoved(JNIEnv* env, jclass /* clazz */, jlong ptr, jint displayId) {
NativeInputManager* im = reinterpret_cast<NativeInputManager*>(ptr);
- im->setInputWindows(env, windowHandleObjArray, displayId);
+ im->displayRemoved(env, displayId);
}
static void nativeSetFocusedApplication(JNIEnv* env, jclass /* clazz */,
@@ -1815,8 +1769,7 @@ static const JNINativeMethod gInputManagerMethods[] = {
{"nativeVerifyInputEvent", "(JLandroid/view/InputEvent;)Landroid/view/VerifiedInputEvent;",
(void*)nativeVerifyInputEvent},
{"nativeToggleCapsLock", "(JI)V", (void*)nativeToggleCapsLock},
- {"nativeSetInputWindows", "(J[Landroid/view/InputWindowHandle;I)V",
- (void*)nativeSetInputWindows},
+ {"nativeDisplayRemoved", "(JI)V", (void*)nativeDisplayRemoved},
{"nativeSetFocusedApplication", "(JILandroid/view/InputApplicationHandle;)V",
(void*)nativeSetFocusedApplication},
{"nativeSetFocusedDisplay", "(JI)V", (void*)nativeSetFocusedDisplay},
diff --git a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
index 09fab3e29fe0..e304bca4553c 100644
--- a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
+++ b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
@@ -7171,7 +7171,9 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager {
ActiveAdmin admin;
synchronized (getLockObject()) {
if (who == null) {
- if ((frpManagementAgentUid != mInjector.binderGetCallingUid())) {
+ if ((frpManagementAgentUid != mInjector.binderGetCallingUid())
+ && (mContext.checkCallingPermission(permission.MASTER_CLEAR)
+ != PackageManager.PERMISSION_GRANTED)) {
throw new SecurityException(
"Must be called by the FRP management agent on device");
}
diff --git a/services/java/com/android/server/SystemServer.java b/services/java/com/android/server/SystemServer.java
index b019e9dd03ba..c631eebe4a01 100644
--- a/services/java/com/android/server/SystemServer.java
+++ b/services/java/com/android/server/SystemServer.java
@@ -144,7 +144,6 @@ import com.android.server.power.ThermalManagerService;
import com.android.server.recoverysystem.RecoverySystemService;
import com.android.server.restrictions.RestrictionsManagerService;
import com.android.server.role.RoleManagerService;
-import com.android.server.rollback.RollbackManagerService;
import com.android.server.security.FileIntegrityService;
import com.android.server.security.KeyAttestationApplicationIdProviderService;
import com.android.server.security.KeyChainSystemService;
@@ -294,6 +293,8 @@ public final class SystemServer {
"com.android.server.DeviceIdleController";
private static final String BLOB_STORE_MANAGER_SERVICE_CLASS =
"com.android.server.blob.BlobStoreManagerService";
+ private static final String ROLLBACK_MANAGER_SERVICE_CLASS =
+ "com.android.server.rollback.RollbackManagerService";
private static final String TETHERING_CONNECTOR_CLASS = "android.net.ITetheringConnector";
@@ -964,7 +965,7 @@ public final class SystemServer {
// Manages apk rollbacks.
t.traceBegin("StartRollbackManagerService");
- mSystemServiceManager.startService(RollbackManagerService.class);
+ mSystemServiceManager.startService(ROLLBACK_MANAGER_SERVICE_CLASS);
t.traceEnd();
// Service to capture bugreports.
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 ae8d5743668a..136ee91dd685 100644
--- a/services/people/java/com/android/server/people/data/DataManager.java
+++ b/services/people/java/com/android/server/people/data/DataManager.java
@@ -26,6 +26,7 @@ import android.app.NotificationManager;
import android.app.Person;
import android.app.prediction.AppTarget;
import android.app.prediction.AppTargetEvent;
+import android.app.usage.UsageEvents;
import android.content.BroadcastReceiver;
import android.content.ComponentName;
import android.content.ContentResolver;
@@ -70,6 +71,7 @@ import com.android.server.notification.NotificationManagerInternal;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
+import java.util.Map;
import java.util.Set;
import java.util.concurrent.Executor;
import java.util.concurrent.Executors;
@@ -237,6 +239,27 @@ public class DataManager {
eventHistory.addEvent(new Event(System.currentTimeMillis(), eventType));
}
+ /**
+ * Queries events for moving app to foreground between {@code startTime} and {@code endTime}.
+ */
+ @NonNull
+ public List<UsageEvents.Event> queryAppMovingToForegroundEvents(@UserIdInt int callingUserId,
+ long startTime, long endTime) {
+ return UsageStatsQueryHelper.queryAppMovingToForegroundEvents(callingUserId, startTime,
+ endTime);
+ }
+
+ /**
+ * Queries launch counts of apps within {@code packageNameFilter} between {@code startTime}
+ * and {@code endTime}.
+ */
+ @NonNull
+ public Map<String, Integer> queryAppLaunchCount(@UserIdInt int callingUserId, long startTime,
+ long endTime, Set<String> packageNameFilter) {
+ return UsageStatsQueryHelper.queryAppLaunchCount(callingUserId, startTime, endTime,
+ packageNameFilter);
+ }
+
/** Prunes the data for the specified user. */
public void pruneDataForUser(@UserIdInt int userId, @NonNull CancellationSignal signal) {
UserData userData = getUnlockedUserData(userId);
@@ -382,7 +405,13 @@ public class DataManager {
}
}
- private int mimeTypeToShareEventType(String mimeType) {
+ /**
+ * Converts {@code mimeType} to {@link Event.EventType}.
+ */
+ public int mimeTypeToShareEventType(String mimeType) {
+ if (mimeType == null) {
+ return Event.TYPE_SHARE_OTHER;
+ }
if (mimeType.startsWith("text/")) {
return Event.TYPE_SHARE_TEXT;
} else if (mimeType.startsWith("image/")) {
diff --git a/services/people/java/com/android/server/people/data/UsageStatsQueryHelper.java b/services/people/java/com/android/server/people/data/UsageStatsQueryHelper.java
index 72f1abb70e34..6e6fea93c803 100644
--- a/services/people/java/com/android/server/people/data/UsageStatsQueryHelper.java
+++ b/services/people/java/com/android/server/people/data/UsageStatsQueryHelper.java
@@ -19,6 +19,8 @@ package com.android.server.people.data;
import android.annotation.NonNull;
import android.annotation.UserIdInt;
import android.app.usage.UsageEvents;
+import android.app.usage.UsageStats;
+import android.app.usage.UsageStatsManager;
import android.app.usage.UsageStatsManagerInternal;
import android.content.ComponentName;
import android.content.LocusId;
@@ -27,7 +29,10 @@ import android.util.ArrayMap;
import com.android.server.LocalServices;
+import java.util.ArrayList;
+import java.util.List;
import java.util.Map;
+import java.util.Set;
import java.util.function.Function;
/** A helper class that queries {@link UsageStatsManagerInternal}. */
@@ -46,7 +51,7 @@ class UsageStatsQueryHelper {
*/
UsageStatsQueryHelper(@UserIdInt int userId,
Function<String, PackageData> packageDataGetter) {
- mUsageStatsManagerInternal = LocalServices.getService(UsageStatsManagerInternal.class);
+ mUsageStatsManagerInternal = getUsageStatsManagerInternal();
mUserId = userId;
mPackageDataGetter = packageDataGetter;
}
@@ -106,6 +111,53 @@ class UsageStatsQueryHelper {
return mLastEventTimestamp;
}
+ /**
+ * Queries {@link UsageStatsManagerInternal} events for moving app to foreground between
+ * {@code startTime} and {@code endTime}.
+ *
+ * @return a list containing events moving app to foreground.
+ */
+ static List<UsageEvents.Event> queryAppMovingToForegroundEvents(@UserIdInt int userId,
+ long startTime, long endTime) {
+ List<UsageEvents.Event> res = new ArrayList<>();
+ UsageEvents usageEvents = getUsageStatsManagerInternal().queryEventsForUser(userId,
+ startTime, endTime,
+ UsageEvents.HIDE_SHORTCUT_EVENTS | UsageEvents.HIDE_LOCUS_EVENTS);
+ if (usageEvents == null) {
+ return res;
+ }
+ while (usageEvents.hasNextEvent()) {
+ UsageEvents.Event e = new UsageEvents.Event();
+ usageEvents.getNextEvent(e);
+ if (e.getEventType() == UsageEvents.Event.ACTIVITY_RESUMED) {
+ res.add(e);
+ }
+ }
+ return res;
+ }
+
+ /**
+ * Queries {@link UsageStatsManagerInternal} for launch count of apps within {@code
+ * packageNameFilter} between {@code startTime} and {@code endTime}.obfuscateInstantApps
+ *
+ * @return a map which keys are package names and values are app launch counts.
+ */
+ static Map<String, Integer> queryAppLaunchCount(@UserIdInt int userId, long startTime,
+ long endTime, Set<String> packageNameFilter) {
+ List<UsageStats> stats = getUsageStatsManagerInternal().queryUsageStatsForUser(userId,
+ UsageStatsManager.INTERVAL_BEST, startTime, endTime,
+ /* obfuscateInstantApps= */ false);
+ Map<String, Integer> aggregatedStats = new ArrayMap<>();
+ for (UsageStats stat : stats) {
+ String packageName = stat.getPackageName();
+ if (packageNameFilter.contains(packageName)) {
+ aggregatedStats.put(packageName,
+ aggregatedStats.getOrDefault(packageName, 0) + stat.getAppLaunchCount());
+ }
+ }
+ return aggregatedStats;
+ }
+
private void onInAppConversationEnded(@NonNull PackageData packageData,
@NonNull UsageEvents.Event endEvent) {
ComponentName activityName =
@@ -138,4 +190,8 @@ class UsageStatsQueryHelper {
EventStore.CATEGORY_LOCUS_ID_BASED, locusId.getId());
eventHistory.addEvent(event);
}
+
+ private static UsageStatsManagerInternal getUsageStatsManagerInternal() {
+ return LocalServices.getService(UsageStatsManagerInternal.class);
+ }
}
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 8e5d75be12b7..d09d0b379769 100644
--- a/services/people/java/com/android/server/people/prediction/ShareTargetPredictor.java
+++ b/services/people/java/com/android/server/people/prediction/ShareTargetPredictor.java
@@ -27,13 +27,11 @@ 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;
@@ -42,6 +40,9 @@ import java.util.Collections;
import java.util.List;
import java.util.function.Consumer;
+/**
+ * Predictor that predicts the {@link AppTarget} the user is most likely to open on share sheet.
+ */
class ShareTargetPredictor extends AppTargetPredictor {
private final IntentFilter mIntentFilter;
@@ -66,7 +67,9 @@ class ShareTargetPredictor extends AppTargetPredictor {
@Override
void predictTargets() {
List<ShareTarget> shareTargets = getDirectShareTargets();
- rankTargets(shareTargets);
+ SharesheetModelScorer.computeScore(shareTargets, getShareEventType(mIntentFilter),
+ System.currentTimeMillis());
+ Collections.sort(shareTargets, (t1, t2) -> -Float.compare(t1.getScore(), t2.getScore()));
List<AppTarget> res = new ArrayList<>();
for (int i = 0; i < Math.min(getPredictionContext().getPredictedTargetCount(),
shareTargets.size()); i++) {
@@ -80,36 +83,16 @@ class ShareTargetPredictor extends AppTargetPredictor {
@Override
void sortTargets(List<AppTarget> targets, Consumer<List<AppTarget>> callback) {
List<ShareTarget> shareTargets = getAppShareTargets(targets);
- rankTargets(shareTargets);
+ SharesheetModelScorer.computeScoreForAppShare(shareTargets,
+ getShareEventType(mIntentFilter), getPredictionContext().getPredictedTargetCount(),
+ System.currentTimeMillis(), getDataManager(),
+ mCallingUserId);
+ Collections.sort(shareTargets, (t1, t2) -> -Float.compare(t1.getScore(), t2.getScore()));
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 =
@@ -153,6 +136,11 @@ class ShareTargetPredictor extends AppTargetPredictor {
return shareTargets;
}
+ private int getShareEventType(IntentFilter intentFilter) {
+ String mimeType = intentFilter != null ? intentFilter.getDataType(0) : null;
+ return getDataManager().mimeTypeToShareEventType(mimeType);
+ }
+
@VisibleForTesting
static class ShareTarget {
@@ -162,13 +150,16 @@ class ShareTargetPredictor extends AppTargetPredictor {
private final EventHistory mEventHistory;
@Nullable
private final ConversationInfo mConversationInfo;
+ private float mScore;
- private ShareTarget(@NonNull AppTarget appTarget,
+ @VisibleForTesting
+ ShareTarget(@NonNull AppTarget appTarget,
@Nullable EventHistory eventHistory,
@Nullable ConversationInfo conversationInfo) {
mAppTarget = appTarget;
mEventHistory = eventHistory;
mConversationInfo = conversationInfo;
+ mScore = 0f;
}
@NonNull
@@ -188,5 +179,15 @@ class ShareTargetPredictor extends AppTargetPredictor {
ConversationInfo getConversationInfo() {
return mConversationInfo;
}
+
+ @VisibleForTesting
+ float getScore() {
+ return mScore;
+ }
+
+ @VisibleForTesting
+ void setScore(float score) {
+ mScore = score;
+ }
}
}
diff --git a/services/people/java/com/android/server/people/prediction/SharesheetModelScorer.java b/services/people/java/com/android/server/people/prediction/SharesheetModelScorer.java
new file mode 100644
index 000000000000..0ac5724210da
--- /dev/null
+++ b/services/people/java/com/android/server/people/prediction/SharesheetModelScorer.java
@@ -0,0 +1,406 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.server.people.prediction;
+
+import android.annotation.NonNull;
+import android.annotation.Nullable;
+import android.annotation.UserIdInt;
+import android.app.usage.UsageEvents;
+import android.util.ArrayMap;
+import android.util.Pair;
+import android.util.Range;
+import android.util.Slog;
+
+import com.android.internal.annotations.VisibleForTesting;
+import com.android.internal.app.ChooserActivity;
+import com.android.server.people.data.DataManager;
+import com.android.server.people.data.Event;
+
+import java.time.Duration;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.Comparator;
+import java.util.List;
+import java.util.Map;
+import java.util.PriorityQueue;
+import java.util.concurrent.TimeUnit;
+
+/** Ranking scorer for Sharesheet targets. */
+class SharesheetModelScorer {
+
+ private static final String TAG = "SharesheetModelScorer";
+ private static final boolean DEBUG = false;
+ private static final Integer RECENCY_SCORE_COUNT = 6;
+ private static final float RECENCY_INITIAL_BASE_SCORE = 0.4F;
+ private static final float RECENCY_SCORE_INITIAL_DECAY = 0.05F;
+ private static final float RECENCY_SCORE_SUBSEQUENT_DECAY = 0.02F;
+ private static final long ONE_MONTH_WINDOW = TimeUnit.DAYS.toMillis(30);
+ private static final long FOREGROUND_APP_PROMO_TIME_WINDOW = TimeUnit.MINUTES.toMillis(10);
+ private static final float FREQUENTLY_USED_APP_SCORE_DECAY = 0.9F;
+ @VisibleForTesting
+ static final float FOREGROUND_APP_WEIGHT = 0F;
+ @VisibleForTesting
+ static final String CHOOSER_ACTIVITY = ChooserActivity.class.getSimpleName();
+
+ // Keep constructor private to avoid class being instantiated.
+ private SharesheetModelScorer() {
+ }
+
+ /**
+ * Computes each target's recency, frequency and frequency of the same {@code shareEventType}
+ * based on past sharing history. Update {@link ShareTargetPredictor.ShareTargetScore}.
+ */
+ static void computeScore(List<ShareTargetPredictor.ShareTarget> shareTargets,
+ int shareEventType, long now) {
+ if (shareTargets.isEmpty()) {
+ return;
+ }
+ float totalFreqScore = 0f;
+ int freqScoreCount = 0;
+ float totalMimeFreqScore = 0f;
+ int mimeFreqScoreCount = 0;
+ // Top of this heap has lowest rank.
+ PriorityQueue<Pair<ShareTargetRankingScore, Range<Long>>> recencyMinHeap =
+ new PriorityQueue<>(RECENCY_SCORE_COUNT,
+ Comparator.comparingLong(p -> p.second.getUpper()));
+ List<ShareTargetRankingScore> scoreList = new ArrayList<>(shareTargets.size());
+ for (ShareTargetPredictor.ShareTarget target : shareTargets) {
+ ShareTargetRankingScore shareTargetScore = new ShareTargetRankingScore();
+ scoreList.add(shareTargetScore);
+ if (target.getEventHistory() == null) {
+ continue;
+ }
+ // Counts frequency
+ List<Range<Long>> timeSlots = target.getEventHistory().getEventIndex(
+ Event.SHARE_EVENT_TYPES).getActiveTimeSlots();
+ if (!timeSlots.isEmpty()) {
+ for (Range<Long> timeSlot : timeSlots) {
+ shareTargetScore.incrementFrequencyScore(
+ getFreqDecayedOnElapsedTime(now - timeSlot.getLower()));
+ }
+ totalFreqScore += shareTargetScore.getFrequencyScore();
+ freqScoreCount++;
+ }
+ // Counts frequency for sharing same mime type
+ List<Range<Long>> timeSlotsOfSameType = target.getEventHistory().getEventIndex(
+ shareEventType).getActiveTimeSlots();
+ if (!timeSlotsOfSameType.isEmpty()) {
+ for (Range<Long> timeSlot : timeSlotsOfSameType) {
+ shareTargetScore.incrementMimeFrequencyScore(
+ getFreqDecayedOnElapsedTime(now - timeSlot.getLower()));
+ }
+ totalMimeFreqScore += shareTargetScore.getMimeFrequencyScore();
+ mimeFreqScoreCount++;
+ }
+ // Records most recent targets
+ Range<Long> mostRecentTimeSlot = target.getEventHistory().getEventIndex(
+ Event.SHARE_EVENT_TYPES).getMostRecentActiveTimeSlot();
+ if (mostRecentTimeSlot == null) {
+ continue;
+ }
+ if (recencyMinHeap.size() < RECENCY_SCORE_COUNT
+ || mostRecentTimeSlot.getUpper() > recencyMinHeap.peek().second.getUpper()) {
+ if (recencyMinHeap.size() == RECENCY_SCORE_COUNT) {
+ recencyMinHeap.poll();
+ }
+ recencyMinHeap.offer(new Pair(shareTargetScore, mostRecentTimeSlot));
+ }
+ }
+ // Calculates recency score
+ while (!recencyMinHeap.isEmpty()) {
+ float recencyScore = RECENCY_INITIAL_BASE_SCORE;
+ if (recencyMinHeap.size() > 1) {
+ recencyScore = RECENCY_INITIAL_BASE_SCORE - RECENCY_SCORE_INITIAL_DECAY
+ - RECENCY_SCORE_SUBSEQUENT_DECAY * (recencyMinHeap.size() - 2);
+ }
+ recencyMinHeap.poll().first.setRecencyScore(recencyScore);
+ }
+
+ Float avgFreq = freqScoreCount != 0 ? totalFreqScore / freqScoreCount : 0f;
+ Float avgMimeFreq = mimeFreqScoreCount != 0 ? totalMimeFreqScore / mimeFreqScoreCount : 0f;
+ for (int i = 0; i < scoreList.size(); i++) {
+ ShareTargetPredictor.ShareTarget target = shareTargets.get(i);
+ ShareTargetRankingScore targetScore = scoreList.get(i);
+ // Normalizes freq and mimeFreq score
+ targetScore.setFrequencyScore(normalizeFreqScore(
+ avgFreq.equals(0f) ? 0f : targetScore.getFrequencyScore() / avgFreq));
+ targetScore.setMimeFrequencyScore(normalizeMimeFreqScore(avgMimeFreq.equals(0f) ? 0f
+ : targetScore.getMimeFrequencyScore() / avgMimeFreq));
+ // Calculates total score
+ targetScore.setTotalScore(
+ probOR(probOR(targetScore.getRecencyScore(), targetScore.getFrequencyScore()),
+ targetScore.getMimeFrequencyScore()));
+ target.setScore(targetScore.getTotalScore());
+
+ if (DEBUG) {
+ Slog.d(TAG, String.format(
+ "SharesheetModel: packageName: %s, className: %s, shortcutId: %s, "
+ + "recency:%.2f, freq_all:%.2f, freq_mime:%.2f, total:%.2f",
+ target.getAppTarget().getPackageName(),
+ target.getAppTarget().getClassName(),
+ target.getAppTarget().getShortcutInfo() != null
+ ? target.getAppTarget().getShortcutInfo().getId() : null,
+ targetScore.getRecencyScore(),
+ targetScore.getFrequencyScore(),
+ targetScore.getMimeFrequencyScore(),
+ targetScore.getTotalScore()));
+ }
+ }
+ }
+
+ /**
+ * Computes ranking score for app sharing. Update {@link ShareTargetPredictor.ShareTargetScore}.
+ */
+ static void computeScoreForAppShare(List<ShareTargetPredictor.ShareTarget> shareTargets,
+ int shareEventType, int targetsLimit, long now, @NonNull DataManager dataManager,
+ @UserIdInt int callingUserId) {
+ computeScore(shareTargets, shareEventType, now);
+ postProcess(shareTargets, targetsLimit, dataManager, callingUserId);
+ }
+
+ private static void postProcess(List<ShareTargetPredictor.ShareTarget> shareTargets,
+ int targetsLimit, @NonNull DataManager dataManager, @UserIdInt int callingUserId) {
+ // Populates a map which key is package name and value is list of shareTargets descended
+ // on total score.
+ Map<String, List<ShareTargetPredictor.ShareTarget>> shareTargetMap = new ArrayMap<>();
+ for (ShareTargetPredictor.ShareTarget shareTarget : shareTargets) {
+ String packageName = shareTarget.getAppTarget().getPackageName();
+ shareTargetMap.computeIfAbsent(packageName, key -> new ArrayList<>());
+ List<ShareTargetPredictor.ShareTarget> targetsList = shareTargetMap.get(packageName);
+ int index = 0;
+ while (index < targetsList.size()) {
+ if (shareTarget.getScore() > targetsList.get(index).getScore()) {
+ break;
+ }
+ index++;
+ }
+ targetsList.add(index, shareTarget);
+ }
+ promoteForegroundApp(shareTargetMap, dataManager, callingUserId);
+ promoteFrequentlyUsedApps(shareTargetMap, targetsLimit, dataManager, callingUserId);
+ }
+
+ /**
+ * Promotes frequently used sharing apps, if recommended apps based on sharing history have not
+ * reached the limit (e.g. user did not share any content in last couple weeks)
+ */
+ private static void promoteFrequentlyUsedApps(
+ Map<String, List<ShareTargetPredictor.ShareTarget>> shareTargetMap, int targetsLimit,
+ @NonNull DataManager dataManager, @UserIdInt int callingUserId) {
+ int validPredictionNum = 0;
+ float minValidScore = 1f;
+ for (List<ShareTargetPredictor.ShareTarget> targets : shareTargetMap.values()) {
+ for (ShareTargetPredictor.ShareTarget target : targets) {
+ if (target.getScore() > 0f) {
+ validPredictionNum++;
+ minValidScore = Math.min(target.getScore(), minValidScore);
+ }
+ }
+ }
+ // Skips if recommended apps based on sharing history have already reached the limit.
+ if (validPredictionNum >= targetsLimit) {
+ return;
+ }
+ long now = System.currentTimeMillis();
+ Map<String, Integer> appLaunchCountsMap = dataManager.queryAppLaunchCount(
+ callingUserId, now - ONE_MONTH_WINDOW, now, shareTargetMap.keySet());
+ List<Pair<String, Integer>> appLaunchCounts = new ArrayList<>();
+ for (Map.Entry<String, Integer> entry : appLaunchCountsMap.entrySet()) {
+ if (entry.getValue() > 0) {
+ appLaunchCounts.add(new Pair(entry.getKey(), entry.getValue()));
+ }
+ }
+ Collections.sort(appLaunchCounts, (p1, p2) -> -Integer.compare(p1.second, p2.second));
+ for (Pair<String, Integer> entry : appLaunchCounts) {
+ if (!shareTargetMap.containsKey(entry.first)) {
+ continue;
+ }
+ ShareTargetPredictor.ShareTarget target = shareTargetMap.get(entry.first).get(0);
+ if (target.getScore() > 0f) {
+ continue;
+ }
+ minValidScore *= FREQUENTLY_USED_APP_SCORE_DECAY;
+ target.setScore(minValidScore);
+ if (DEBUG) {
+ Slog.d(TAG, String.format(
+ "SharesheetModel: promoteFrequentUsedApps packageName: %s, className: %s,"
+ + " total:%.2f",
+ target.getAppTarget().getPackageName(),
+ target.getAppTarget().getClassName(),
+ target.getScore()));
+ }
+ validPredictionNum++;
+ if (validPredictionNum == targetsLimit) {
+ return;
+ }
+ }
+ }
+
+ /**
+ * Promotes the foreground app just prior to source sharing app. Share often occurs between
+ * two apps the user is switching.
+ */
+ private static void promoteForegroundApp(
+ Map<String, List<ShareTargetPredictor.ShareTarget>> shareTargetMap,
+ @NonNull DataManager dataManager, @UserIdInt int callingUserId) {
+ String sharingForegroundApp = findSharingForegroundApp(shareTargetMap, dataManager,
+ callingUserId);
+ if (sharingForegroundApp != null) {
+ ShareTargetPredictor.ShareTarget target = shareTargetMap.get(sharingForegroundApp).get(
+ 0);
+ target.setScore(probOR(target.getScore(), FOREGROUND_APP_WEIGHT));
+ if (DEBUG) {
+ Slog.d(TAG, String.format(
+ "SharesheetModel: promoteForegroundApp packageName: %s, className: %s, "
+ + "total:%.2f",
+ target.getAppTarget().getPackageName(),
+ target.getAppTarget().getClassName(),
+ target.getScore()));
+ }
+ }
+ }
+
+ /**
+ * Find the foreground app just prior to source sharing app from usageStatsManager. Returns null
+ * if it is not available.
+ */
+ @Nullable
+ private static String findSharingForegroundApp(
+ Map<String, List<ShareTargetPredictor.ShareTarget>> shareTargetMap,
+ @NonNull DataManager dataManager, @UserIdInt int callingUserId) {
+ String sharingForegroundApp = null;
+ long now = System.currentTimeMillis();
+ List<UsageEvents.Event> events = dataManager.queryAppMovingToForegroundEvents(
+ callingUserId, now - FOREGROUND_APP_PROMO_TIME_WINDOW, now);
+ String sourceApp = null;
+ for (int i = events.size() - 1; i >= 0; i--) {
+ String className = events.get(i).getClassName();
+ String packageName = events.get(i).getPackageName();
+ if (packageName == null || (className != null && className.contains(CHOOSER_ACTIVITY))
+ || packageName.contains(CHOOSER_ACTIVITY)) {
+ continue;
+ }
+ if (sourceApp == null) {
+ sourceApp = packageName;
+ } else if (!packageName.equals(sourceApp) && shareTargetMap.containsKey(packageName)) {
+ sharingForegroundApp = packageName;
+ break;
+ }
+ }
+ return sharingForegroundApp;
+ }
+
+ /**
+ * Probabilistic OR (also known as the algebraic sum). If a <= 1 and b <= 1, the result will be
+ * <= 1.0.
+ */
+ private static float probOR(float a, float b) {
+ return 1f - (1f - a) * (1f - b);
+ }
+
+ /** Counts frequency of share targets. Decays frequency for old shares. */
+ private static float getFreqDecayedOnElapsedTime(long elapsedTimeMillis) {
+ Duration duration = Duration.ofMillis(elapsedTimeMillis);
+ if (duration.compareTo(Duration.ofDays(1)) <= 0) {
+ return 1.0f;
+ } else if (duration.compareTo(Duration.ofDays(3)) <= 0) {
+ return 0.9f;
+ } else if (duration.compareTo(Duration.ofDays(7)) <= 0) {
+ return 0.8f;
+ } else if (duration.compareTo(Duration.ofDays(14)) <= 0) {
+ return 0.7f;
+ } else {
+ return 0.6f;
+ }
+ }
+
+ /** Normalizes frequency score. */
+ private static float normalizeFreqScore(double freqRatio) {
+ if (freqRatio >= 2.5) {
+ return 0.2f;
+ } else if (freqRatio >= 1.5) {
+ return 0.15f;
+ } else if (freqRatio >= 1.0) {
+ return 0.1f;
+ } else if (freqRatio >= 0.75) {
+ return 0.05f;
+ } else {
+ return 0f;
+ }
+ }
+
+ /** Normalizes mimetype-specific frequency score. */
+ private static float normalizeMimeFreqScore(double freqRatio) {
+ if (freqRatio >= 2.0) {
+ return 0.2f;
+ } else if (freqRatio >= 1.2) {
+ return 0.15f;
+ } else if (freqRatio > 0.0) {
+ return 0.1f;
+ } else {
+ return 0f;
+ }
+ }
+
+ private static class ShareTargetRankingScore {
+
+ private float mRecencyScore = 0f;
+ private float mFrequencyScore = 0f;
+ private float mMimeFrequencyScore = 0f;
+ private float mTotalScore = 0f;
+
+ float getTotalScore() {
+ return mTotalScore;
+ }
+
+ void setTotalScore(float totalScore) {
+ mTotalScore = totalScore;
+ }
+
+ float getRecencyScore() {
+ return mRecencyScore;
+ }
+
+ void setRecencyScore(float recencyScore) {
+ mRecencyScore = recencyScore;
+ }
+
+ float getFrequencyScore() {
+ return mFrequencyScore;
+ }
+
+ void setFrequencyScore(float frequencyScore) {
+ mFrequencyScore = frequencyScore;
+ }
+
+ void incrementFrequencyScore(float incremental) {
+ mFrequencyScore += incremental;
+ }
+
+ float getMimeFrequencyScore() {
+ return mMimeFrequencyScore;
+ }
+
+ void setMimeFrequencyScore(float mimeFrequencyScore) {
+ mMimeFrequencyScore = mimeFrequencyScore;
+ }
+
+ void incrementMimeFrequencyScore(float incremental) {
+ mMimeFrequencyScore += incremental;
+ }
+ }
+}
diff --git a/services/robotests/src/com/android/server/pm/CrossProfileAppsServiceImplRoboTest.java b/services/robotests/src/com/android/server/pm/CrossProfileAppsServiceImplRoboTest.java
index acdb68142178..138f9829c088 100644
--- a/services/robotests/src/com/android/server/pm/CrossProfileAppsServiceImplRoboTest.java
+++ b/services/robotests/src/com/android/server/pm/CrossProfileAppsServiceImplRoboTest.java
@@ -17,6 +17,7 @@
package com.android.server.pm;
import static android.app.AppOpsManager.MODE_ALLOWED;
+import static android.app.AppOpsManager.MODE_DEFAULT;
import static android.app.AppOpsManager.OP_INTERACT_ACROSS_PROFILES;
import static android.content.Intent.FLAG_RECEIVER_FOREGROUND;
import static android.content.Intent.FLAG_RECEIVER_INCLUDE_BACKGROUND;
@@ -104,6 +105,7 @@ public class CrossProfileAppsServiceImplRoboTest {
private final CrossProfileAppsServiceImpl mCrossProfileAppsServiceImpl =
new CrossProfileAppsServiceImpl(mContext, mInjector);
private final Map<UserHandle, Set<Intent>> mSentUserBroadcasts = new HashMap<>();
+ private final Map<Integer, List<ApplicationInfo>> installedApplications = new HashMap<>();
@Mock private PackageManagerInternal mPackageManagerInternal;
@Mock private IPackageManager mIPackageManager;
@@ -112,12 +114,18 @@ public class CrossProfileAppsServiceImplRoboTest {
@Before
public void initializeMocks() throws Exception {
MockitoAnnotations.initMocks(this);
+ initializeInstalledApplicationsMock();
mockCrossProfileAppInstalledAndEnabledOnEachProfile();
mockCrossProfileAppRequestsInteractAcrossProfiles();
mockCrossProfileAppRegistersBroadcastReceiver();
mockCrossProfileAppWhitelisted();
}
+ private void initializeInstalledApplicationsMock() {
+ when(mPackageManagerInternal.getInstalledApplications(anyInt(), anyInt(), eq(CALLING_UID)))
+ .thenAnswer(invocation -> installedApplications.get(invocation.getArgument(1)));
+ }
+
private void mockCrossProfileAppInstalledAndEnabledOnEachProfile() {
// They are enabled by default, so we simply have to ensure that a package info with an
// application info is returned.
@@ -138,11 +146,14 @@ public class CrossProfileAppsServiceImplRoboTest {
when(mPackageManagerInternal.getPackage(uid))
.thenReturn(((ParsedPackage) PackageImpl.forTesting(CROSS_PROFILE_APP_PACKAGE_NAME)
.hideAsParsed()).hideAsFinal());
+ installedApplications.putIfAbsent(userId, new ArrayList<>());
+ installedApplications.get(userId).add(packageInfo.applicationInfo);
}
private PackageInfo buildTestPackageInfo() {
PackageInfo packageInfo = new PackageInfo();
packageInfo.applicationInfo = new ApplicationInfo();
+ packageInfo.applicationInfo.packageName = CROSS_PROFILE_APP_PACKAGE_NAME;
return packageInfo;
}
@@ -451,6 +462,13 @@ public class CrossProfileAppsServiceImplRoboTest {
.isTrue();
}
+ @Test
+ public void clearInteractAcrossProfilesAppOps() {
+ explicitlySetInteractAcrossProfilesAppOp(MODE_ALLOWED);
+ mCrossProfileAppsServiceImpl.clearInteractAcrossProfilesAppOps();
+ assertThat(getCrossProfileAppOp()).isEqualTo(MODE_DEFAULT);
+ }
+
private void explicitlySetInteractAcrossProfilesAppOp(@Mode int mode) {
explicitlySetInteractAcrossProfilesAppOp(PERSONAL_PROFILE_UID, mode);
}
diff --git a/services/tests/servicestests/src/com/android/server/biometrics/BiometricServiceTest.java b/services/tests/servicestests/src/com/android/server/biometrics/BiometricServiceTest.java
index 3ad905476190..d2925263125d 100644
--- a/services/tests/servicestests/src/com/android/server/biometrics/BiometricServiceTest.java
+++ b/services/tests/servicestests/src/com/android/server/biometrics/BiometricServiceTest.java
@@ -64,10 +64,13 @@ import com.android.internal.statusbar.IStatusBarService;
import org.junit.Before;
import org.junit.Test;
+import org.mockito.AdditionalMatchers;
import org.mockito.ArgumentCaptor;
import org.mockito.Mock;
import org.mockito.MockitoAnnotations;
+import java.util.Random;
+
@SmallTest
public class BiometricServiceTest {
@@ -347,9 +350,19 @@ public class BiometricServiceTest {
}
@Test
- public void testAuthenticate_happyPathWithoutConfirmation() throws Exception {
+ public void testAuthenticate_happyPathWithoutConfirmation_strongBiometric() throws Exception {
setupAuthForOnly(BiometricAuthenticator.TYPE_FINGERPRINT, Authenticators.BIOMETRIC_STRONG);
+ testAuthenticate_happyPathWithoutConfirmation(true /* isStrongBiometric */);
+ }
+
+ @Test
+ public void testAuthenticate_happyPathWithoutConfirmation_weakBiometric() throws Exception {
+ setupAuthForOnly(BiometricAuthenticator.TYPE_FINGERPRINT, Authenticators.BIOMETRIC_WEAK);
+ testAuthenticate_happyPathWithoutConfirmation(false /* isStrongBiometric */);
+ }
+ private void testAuthenticate_happyPathWithoutConfirmation(boolean isStrongBiometric)
+ throws Exception {
// Start testing the happy path
invokeAuthenticate(mBiometricService.mImpl, mReceiver1, false /* requireConfirmation */,
null /* authenticators */);
@@ -397,9 +410,11 @@ public class BiometricServiceTest {
anyLong() /* sessionId */);
// Hardware authenticated
+ final byte[] HAT = generateRandomHAT();
mBiometricService.mInternalReceiver.onAuthenticationSucceeded(
false /* requireConfirmation */,
- new byte[69] /* HAT */);
+ HAT,
+ isStrongBiometric /* isStrongBiometric */);
waitForIdle();
// Waiting for SystemUI to send dismissed callback
assertEquals(mBiometricService.mCurrentAuthSession.mState,
@@ -413,7 +428,11 @@ public class BiometricServiceTest {
null /* credentialAttestation */);
waitForIdle();
// HAT sent to keystore
- verify(mBiometricService.mKeyStore).addAuthToken(any(byte[].class));
+ if (isStrongBiometric) {
+ verify(mBiometricService.mKeyStore).addAuthToken(AdditionalMatchers.aryEq(HAT));
+ } else {
+ verify(mBiometricService.mKeyStore, never()).addAuthToken(any(byte[].class));
+ }
// Send onAuthenticated to client
verify(mReceiver1).onAuthenticationSucceeded(
BiometricPrompt.AUTHENTICATION_RESULT_TYPE_BIOMETRIC);
@@ -447,16 +466,29 @@ public class BiometricServiceTest {
}
@Test
- public void testAuthenticate_happyPathWithConfirmation() throws Exception {
+ public void testAuthenticate_happyPathWithConfirmation_strongBiometric() throws Exception {
setupAuthForOnly(BiometricAuthenticator.TYPE_FACE, Authenticators.BIOMETRIC_STRONG);
+ testAuthenticate_happyPathWithConfirmation(true /* isStrongBiometric */);
+ }
+
+ @Test
+ public void testAuthenticate_happyPathWithConfirmation_weakBiometric() throws Exception {
+ setupAuthForOnly(BiometricAuthenticator.TYPE_FACE, Authenticators.BIOMETRIC_WEAK);
+ testAuthenticate_happyPathWithConfirmation(false /* isStrongBiometric */);
+ }
+
+ private void testAuthenticate_happyPathWithConfirmation(boolean isStrongBiometric)
+ throws Exception {
invokeAuthenticateAndStart(mBiometricService.mImpl, mReceiver1,
true /* requireConfirmation */, null /* authenticators */);
// Test authentication succeeded goes to PENDING_CONFIRMATION and that the HAT is not
// sent to KeyStore yet
+ final byte[] HAT = generateRandomHAT();
mBiometricService.mInternalReceiver.onAuthenticationSucceeded(
true /* requireConfirmation */,
- new byte[69] /* HAT */);
+ HAT,
+ isStrongBiometric /* isStrongBiometric */);
waitForIdle();
// Waiting for SystemUI to send confirmation callback
assertEquals(mBiometricService.mCurrentAuthSession.mState,
@@ -468,7 +500,11 @@ public class BiometricServiceTest {
BiometricPrompt.DISMISSED_REASON_BIOMETRIC_CONFIRMED,
null /* credentialAttestation */);
waitForIdle();
- verify(mBiometricService.mKeyStore).addAuthToken(any(byte[].class));
+ if (isStrongBiometric) {
+ verify(mBiometricService.mKeyStore).addAuthToken(AdditionalMatchers.aryEq(HAT));
+ } else {
+ verify(mBiometricService.mKeyStore, never()).addAuthToken(any(byte[].class));
+ }
verify(mReceiver1).onAuthenticationSucceeded(
BiometricPrompt.AUTHENTICATION_RESULT_TYPE_BIOMETRIC);
}
@@ -909,7 +945,8 @@ public class BiometricServiceTest {
mBiometricService.mInternalReceiver.onAuthenticationSucceeded(
true /* requireConfirmation */,
- new byte[69] /* HAT */);
+ new byte[69] /* HAT */,
+ true /* isStrongBiometric */);
mBiometricService.mInternalReceiver.onDialogDismissed(
BiometricPrompt.DISMISSED_REASON_USER_CANCEL, null /* credentialAttestation */);
waitForIdle();
@@ -927,6 +964,7 @@ public class BiometricServiceTest {
eq(BiometricAuthenticator.TYPE_FACE),
eq(BiometricConstants.BIOMETRIC_ERROR_USER_CANCELED),
eq(0 /* vendorCode */));
+ verify(mBiometricService.mKeyStore, never()).addAuthToken(any(byte[].class));
assertNull(mBiometricService.mCurrentAuthSession);
}
@@ -1238,20 +1276,6 @@ public class BiometricServiceTest {
mFingerprintAuthenticator);
}
- @Test(expected = IllegalStateException.class)
- public void testRegistrationWithUnsupportedStrength_throwsIllegalStateException()
- throws Exception {
- mBiometricService = new BiometricService(mContext, mInjector);
- mBiometricService.onStart();
-
- // Only STRONG and WEAK are supported. Let's enforce that CONVENIENCE cannot be
- // registered. If there is a compelling reason, we can remove this constraint.
- mBiometricService.mImpl.registerAuthenticator(
- 0 /* id */, 2 /* modality */,
- Authenticators.BIOMETRIC_CONVENIENCE /* strength */,
- mFingerprintAuthenticator);
- }
-
@Test(expected = IllegalArgumentException.class)
public void testRegistrationWithNullAuthenticator_throwsIllegalArgumentException()
throws Exception {
@@ -1508,4 +1532,13 @@ public class BiometricServiceTest {
private static void waitForIdle() {
InstrumentationRegistry.getInstrumentation().waitForIdleSync();
}
+
+ private byte[] generateRandomHAT() {
+ byte[] HAT = new byte[69];
+ Random random = new Random();
+ random.nextBytes(HAT);
+ return HAT;
+ }
+
+
}
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 7934d33f907d..03d9ad51e6c5 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
@@ -21,15 +21,16 @@ 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;
+import static org.mockito.ArgumentMatchers.anyBoolean;
import static org.mockito.ArgumentMatchers.anyInt;
import static org.mockito.ArgumentMatchers.anyLong;
-import static org.mockito.ArgumentMatchers.eq;
import static org.mockito.Mockito.when;
import android.annotation.NonNull;
import android.annotation.Nullable;
import android.annotation.UserIdInt;
import android.app.usage.UsageEvents;
+import android.app.usage.UsageStats;
import android.app.usage.UsageStatsManagerInternal;
import android.content.Context;
import android.content.LocusId;
@@ -50,6 +51,7 @@ import java.io.File;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
+import java.util.Map;
import java.util.Set;
import java.util.concurrent.ScheduledExecutorService;
import java.util.function.Predicate;
@@ -58,7 +60,8 @@ import java.util.function.Predicate;
public final class UsageStatsQueryHelperTest {
private static final int USER_ID_PRIMARY = 0;
- private static final String PKG_NAME = "pkg";
+ private static final String PKG_NAME_1 = "pkg_1";
+ private static final String PKG_NAME_2 = "pkg_2";
private static final String ACTIVITY_NAME = "TestActivity";
private static final String SHORTCUT_ID = "abc";
private static final LocusId LOCUS_ID_1 = new LocusId("locus_1");
@@ -80,7 +83,7 @@ public final class UsageStatsQueryHelperTest {
File testDir = new File(ctx.getCacheDir(), "testdir");
ScheduledExecutorService scheduledExecutorService = new MockScheduledExecutorService();
- mPackageData = new TestPackageData(PKG_NAME, USER_ID_PRIMARY, pkg -> false, pkg -> false,
+ mPackageData = new TestPackageData(PKG_NAME_1, USER_ID_PRIMARY, pkg -> false, pkg -> false,
scheduledExecutorService, testDir);
mPackageData.mConversationStore.mConversationInfo = new ConversationInfo.Builder()
.setShortcutId(SHORTCUT_ID)
@@ -173,10 +176,72 @@ public final class UsageStatsQueryHelperTest {
assertEquals(createInAppConversationEvent(130_000L, 30), events.get(2));
}
+ @Test
+ public void testQueryAppMovingToForegroundEvents() {
+ addUsageEvents(
+ createShortcutInvocationEvent(100_000L),
+ createActivityResumedEvent(110_000L),
+ createActivityStoppedEvent(120_000L),
+ createActivityResumedEvent(130_000L));
+
+ List<UsageEvents.Event> events = mHelper.queryAppMovingToForegroundEvents(USER_ID_PRIMARY,
+ 90_000L,
+ 200_000L);
+
+ assertEquals(2, events.size());
+ assertEquals(UsageEvents.Event.ACTIVITY_RESUMED, events.get(0).getEventType());
+ assertEquals(110_000L, events.get(0).getTimeStamp());
+ assertEquals(UsageEvents.Event.ACTIVITY_RESUMED, events.get(1).getEventType());
+ assertEquals(130_000L, events.get(1).getTimeStamp());
+ }
+
+ @Test
+ public void testQueryAppLaunchCount() {
+
+ UsageStats packageStats1 = createUsageStats(PKG_NAME_1, 2);
+ UsageStats packageStats2 = createUsageStats(PKG_NAME_1, 3);
+ UsageStats packageStats3 = createUsageStats(PKG_NAME_2, 1);
+ when(mUsageStatsManagerInternal.queryUsageStatsForUser(anyInt(), anyInt(), anyLong(),
+ anyLong(), anyBoolean())).thenReturn(
+ List.of(packageStats1, packageStats2, packageStats3));
+
+ Map<String, Integer> appLaunchCounts = mHelper.queryAppLaunchCount(USER_ID_PRIMARY, 90_000L,
+ 200_000L, Set.of(PKG_NAME_1, PKG_NAME_2));
+
+ assertEquals(2, appLaunchCounts.size());
+ assertEquals(5, (long) appLaunchCounts.get(PKG_NAME_1));
+ assertEquals(1, (long) appLaunchCounts.get(PKG_NAME_2));
+ }
+
+ @Test
+ public void testQueryAppLaunchCount_packageNameFiltered() {
+
+ UsageStats packageStats1 = createUsageStats(PKG_NAME_1, 2);
+ UsageStats packageStats2 = createUsageStats(PKG_NAME_1, 3);
+ UsageStats packageStats3 = createUsageStats(PKG_NAME_2, 1);
+ when(mUsageStatsManagerInternal.queryUsageStatsForUser(anyInt(), anyInt(), anyLong(),
+ anyLong(), anyBoolean())).thenReturn(
+ List.of(packageStats1, packageStats2, packageStats3));
+
+ Map<String, Integer> appLaunchCounts = mHelper.queryAppLaunchCount(USER_ID_PRIMARY, 90_000L,
+ 200_000L,
+ Set.of(PKG_NAME_1));
+
+ assertEquals(1, appLaunchCounts.size());
+ assertEquals(5, (long) appLaunchCounts.get(PKG_NAME_1));
+ }
+
private void addUsageEvents(UsageEvents.Event... events) {
UsageEvents usageEvents = new UsageEvents(Arrays.asList(events), new String[]{});
when(mUsageStatsManagerInternal.queryEventsForUser(anyInt(), anyLong(), anyLong(),
- eq(UsageEvents.SHOW_ALL_EVENT_DATA))).thenReturn(usageEvents);
+ anyInt())).thenReturn(usageEvents);
+ }
+
+ private static UsageStats createUsageStats(String packageName, int launchCount) {
+ UsageStats packageStats = new UsageStats();
+ packageStats.mPackageName = packageName;
+ packageStats.mAppLaunchCount = launchCount;
+ return packageStats;
}
private static <T> void addLocalServiceMock(Class<T> clazz, T mock) {
@@ -203,9 +268,15 @@ public final class UsageStatsQueryHelperTest {
return e;
}
+ private static UsageEvents.Event createActivityResumedEvent(long timestamp) {
+ UsageEvents.Event e = createUsageEvent(UsageEvents.Event.ACTIVITY_RESUMED, timestamp);
+ e.mClass = ACTIVITY_NAME;
+ return e;
+ }
+
private static UsageEvents.Event createUsageEvent(int eventType, long timestamp) {
UsageEvents.Event e = new UsageEvents.Event(eventType, timestamp);
- e.mPackage = PKG_NAME;
+ e.mPackage = PKG_NAME_1;
return e;
}
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 c6cd34732acf..1480627b9b9f 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
@@ -127,6 +127,9 @@ public final class ShareTargetPredictorTest {
when(mEventHistory1.getEventIndex(anySet())).thenReturn(mEventIndex1);
when(mEventHistory2.getEventIndex(anySet())).thenReturn(mEventIndex2);
when(mEventHistory3.getEventIndex(anySet())).thenReturn(mEventIndex3);
+ when(mEventHistory1.getEventIndex(anyInt())).thenReturn(mEventIndex1);
+ when(mEventHistory2.getEventIndex(anyInt())).thenReturn(mEventIndex2);
+ when(mEventHistory3.getEventIndex(anyInt())).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));
@@ -183,6 +186,12 @@ public final class ShareTargetPredictorTest {
when(mEventHistory4.getEventIndex(anySet())).thenReturn(mEventIndex4);
when(mEventHistory5.getEventIndex(anySet())).thenReturn(mEventIndex5);
when(mEventHistory6.getEventIndex(anySet())).thenReturn(mEventIndex6);
+ when(mEventHistory1.getEventIndex(anyInt())).thenReturn(mEventIndex1);
+ when(mEventHistory2.getEventIndex(anyInt())).thenReturn(mEventIndex2);
+ when(mEventHistory3.getEventIndex(anyInt())).thenReturn(mEventIndex3);
+ when(mEventHistory4.getEventIndex(anyInt())).thenReturn(mEventIndex4);
+ when(mEventHistory5.getEventIndex(anyInt())).thenReturn(mEventIndex5);
+ when(mEventHistory6.getEventIndex(anyInt())).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));
@@ -220,19 +229,19 @@ public final class ShareTargetPredictorTest {
@Test
public void testSortTargets() {
AppTarget appTarget1 = new AppTarget.Builder(
- new AppTargetId("cls1#pkg1"), PACKAGE_1, UserHandle.of(USER_ID))
+ 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))
+ 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))
+ 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))
+ new AppTargetId("cls2#pkg2"), PACKAGE_2, UserHandle.of(USER_ID))
.setClassName(CLASS_2)
.build();
AppTarget appTarget5 = new AppTarget.Builder(
@@ -251,6 +260,10 @@ public final class ShareTargetPredictorTest {
when(mEventHistory2.getEventIndex(anySet())).thenReturn(mEventIndex2);
when(mEventHistory3.getEventIndex(anySet())).thenReturn(mEventIndex3);
when(mEventHistory4.getEventIndex(anySet())).thenReturn(mEventIndex4);
+ when(mEventHistory1.getEventIndex(anyInt())).thenReturn(mEventIndex1);
+ when(mEventHistory2.getEventIndex(anyInt())).thenReturn(mEventIndex2);
+ when(mEventHistory3.getEventIndex(anyInt())).thenReturn(mEventIndex3);
+ when(mEventHistory4.getEventIndex(anyInt())).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));
@@ -265,14 +278,14 @@ public final class ShareTargetPredictorTest {
appTarget4, appTarget3, appTarget2, appTarget1, appTarget5);
}
- private ShareShortcutInfo buildShareShortcut(
+ private static ShareShortcutInfo buildShareShortcut(
String packageName, String className, String shortcutId) {
ShortcutInfo shortcutInfo = buildShortcut(packageName, shortcutId);
ComponentName componentName = new ComponentName(packageName, className);
return new ShareShortcutInfo(shortcutInfo, componentName);
}
- private ShortcutInfo buildShortcut(String packageName, String shortcutId) {
+ private static ShortcutInfo buildShortcut(String packageName, String shortcutId) {
Context mockContext = mock(Context.class);
when(mockContext.getPackageName()).thenReturn(packageName);
when(mockContext.getUserId()).thenReturn(USER_ID);
diff --git a/services/tests/servicestests/src/com/android/server/people/prediction/SharesheetModelScorerTest.java b/services/tests/servicestests/src/com/android/server/people/prediction/SharesheetModelScorerTest.java
new file mode 100644
index 000000000000..9d96d6b7d861
--- /dev/null
+++ b/services/tests/servicestests/src/com/android/server/people/prediction/SharesheetModelScorerTest.java
@@ -0,0 +1,406 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.server.people.prediction;
+
+import static org.junit.Assert.assertEquals;
+import static org.mockito.ArgumentMatchers.anyInt;
+import static org.mockito.ArgumentMatchers.anyLong;
+import static org.mockito.ArgumentMatchers.anySet;
+import static org.mockito.Mockito.never;
+import static org.mockito.Mockito.times;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.when;
+
+import android.app.prediction.AppTarget;
+import android.app.prediction.AppTargetId;
+import android.app.usage.UsageEvents;
+import android.os.UserHandle;
+import android.util.Range;
+
+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.EventIndex;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.JUnit4;
+import org.mockito.Mock;
+import org.mockito.MockitoAnnotations;
+
+import java.time.Duration;
+import java.util.List;
+import java.util.Map;
+
+@RunWith(JUnit4.class)
+public final class SharesheetModelScorerTest {
+
+ private static final int USER_ID = 0;
+ private static final String PACKAGE_1 = "pkg1";
+ 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";
+ private static final double DELTA = 1e-6;
+ private static final long NOW = System.currentTimeMillis();
+ private static final Range<Long> WITHIN_ONE_DAY = new Range(
+ NOW - Duration.ofHours(23).toMillis(),
+ NOW - Duration.ofHours(22).toMillis());
+ private static final Range<Long> TWO_DAYS_AGO = new Range(
+ NOW - Duration.ofHours(50).toMillis(),
+ NOW - Duration.ofHours(49).toMillis());
+ private static final Range<Long> FIVE_DAYS_AGO = new Range(
+ NOW - Duration.ofDays(6).toMillis(),
+ NOW - Duration.ofDays(5).toMillis());
+ private static final Range<Long> EIGHT_DAYS_AGO = new Range(
+ NOW - Duration.ofDays(9).toMillis(),
+ NOW - Duration.ofDays(8).toMillis());
+ private static final Range<Long> TWELVE_DAYS_AGO = new Range(
+ NOW - Duration.ofDays(13).toMillis(),
+ NOW - Duration.ofDays(12).toMillis());
+ private static final Range<Long> TWENTY_DAYS_AGO = new Range(
+ NOW - Duration.ofDays(21).toMillis(),
+ NOW - Duration.ofDays(20).toMillis());
+ private static final Range<Long> FOUR_WEEKS_AGO = new Range(
+ NOW - Duration.ofDays(29).toMillis(),
+ NOW - Duration.ofDays(28).toMillis());
+
+ @Mock
+ private DataManager mDataManager;
+ @Mock
+ private EventHistory mEventHistory1;
+ @Mock
+ private EventHistory mEventHistory2;
+ @Mock
+ private EventHistory mEventHistory3;
+ @Mock
+ private EventHistory mEventHistory4;
+ @Mock
+ private EventHistory mEventHistory5;
+ @Mock
+ private EventIndex mEventIndex1;
+ @Mock
+ private EventIndex mEventIndex2;
+ @Mock
+ private EventIndex mEventIndex3;
+ @Mock
+ private EventIndex mEventIndex4;
+ @Mock
+ private EventIndex mEventIndex5;
+ @Mock
+ private EventIndex mEventIndex6;
+ @Mock
+ private EventIndex mEventIndex7;
+ @Mock
+ private EventIndex mEventIndex8;
+ @Mock
+ private EventIndex mEventIndex9;
+ @Mock
+ private EventIndex mEventIndex10;
+
+ private ShareTargetPredictor.ShareTarget mShareTarget1;
+ private ShareTargetPredictor.ShareTarget mShareTarget2;
+ private ShareTargetPredictor.ShareTarget mShareTarget3;
+ private ShareTargetPredictor.ShareTarget mShareTarget4;
+ private ShareTargetPredictor.ShareTarget mShareTarget5;
+ private ShareTargetPredictor.ShareTarget mShareTarget6;
+
+ @Before
+ public void setUp() {
+ MockitoAnnotations.initMocks(this);
+
+ mShareTarget1 = new ShareTargetPredictor.ShareTarget(
+ new AppTarget.Builder(
+ new AppTargetId("cls1#pkg1"), PACKAGE_1, UserHandle.of(USER_ID))
+ .setClassName(CLASS_1).build(),
+ mEventHistory1, null);
+ mShareTarget2 = new ShareTargetPredictor.ShareTarget(
+ new AppTarget.Builder(new AppTargetId("cls2#pkg1"), PACKAGE_1,
+ UserHandle.of(USER_ID)).setClassName(CLASS_2).build(),
+ mEventHistory2, null);
+ mShareTarget3 = new ShareTargetPredictor.ShareTarget(
+ new AppTarget.Builder(
+ new AppTargetId("cls1#pkg2"), PACKAGE_2, UserHandle.of(USER_ID))
+ .setClassName(CLASS_1).build(),
+ mEventHistory3, null);
+ mShareTarget4 = new ShareTargetPredictor.ShareTarget(
+ new AppTarget.Builder(
+ new AppTargetId("cls2#pkg2"), PACKAGE_2, UserHandle.of(USER_ID))
+ .setClassName(CLASS_2).build(),
+ mEventHistory4, null);
+ mShareTarget5 = new ShareTargetPredictor.ShareTarget(
+ new AppTarget.Builder(
+ new AppTargetId("cls1#pkg3"), PACKAGE_3, UserHandle.of(USER_ID))
+ .setClassName(CLASS_1).build(),
+ mEventHistory5, null);
+ mShareTarget6 = new ShareTargetPredictor.ShareTarget(
+ new AppTarget.Builder(
+ new AppTargetId("cls2#pkg3"), PACKAGE_3, UserHandle.of(USER_ID))
+ .setClassName(CLASS_2).build(),
+ null, null);
+ }
+
+ @Test
+ public void testComputeScore() {
+ // Frequency and recency
+ 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(mEventIndex1.getActiveTimeSlots()).thenReturn(
+ List.of(WITHIN_ONE_DAY, TWO_DAYS_AGO, FIVE_DAYS_AGO));
+ when(mEventIndex2.getActiveTimeSlots()).thenReturn(List.of(TWO_DAYS_AGO, TWELVE_DAYS_AGO));
+ when(mEventIndex3.getActiveTimeSlots()).thenReturn(List.of(FIVE_DAYS_AGO, TWENTY_DAYS_AGO));
+ when(mEventIndex4.getActiveTimeSlots()).thenReturn(
+ List.of(EIGHT_DAYS_AGO, TWELVE_DAYS_AGO, FOUR_WEEKS_AGO));
+ when(mEventIndex5.getActiveTimeSlots()).thenReturn(List.of());
+
+ when(mEventIndex1.getMostRecentActiveTimeSlot()).thenReturn(WITHIN_ONE_DAY);
+ when(mEventIndex2.getMostRecentActiveTimeSlot()).thenReturn(TWO_DAYS_AGO);
+ when(mEventIndex3.getMostRecentActiveTimeSlot()).thenReturn(FIVE_DAYS_AGO);
+ when(mEventIndex4.getMostRecentActiveTimeSlot()).thenReturn(EIGHT_DAYS_AGO);
+ when(mEventIndex5.getMostRecentActiveTimeSlot()).thenReturn(null);
+
+ // Frequency of the same mime type
+ when(mEventHistory1.getEventIndex(Event.TYPE_SHARE_TEXT)).thenReturn(mEventIndex6);
+ when(mEventHistory2.getEventIndex(Event.TYPE_SHARE_TEXT)).thenReturn(mEventIndex7);
+ when(mEventHistory3.getEventIndex(Event.TYPE_SHARE_TEXT)).thenReturn(mEventIndex8);
+ when(mEventHistory4.getEventIndex(Event.TYPE_SHARE_TEXT)).thenReturn(mEventIndex9);
+ when(mEventHistory5.getEventIndex(Event.TYPE_SHARE_TEXT)).thenReturn(mEventIndex10);
+
+ when(mEventIndex6.getActiveTimeSlots()).thenReturn(List.of(TWO_DAYS_AGO));
+ when(mEventIndex7.getActiveTimeSlots()).thenReturn(List.of(TWO_DAYS_AGO, TWELVE_DAYS_AGO));
+ when(mEventIndex8.getActiveTimeSlots()).thenReturn(List.of());
+ when(mEventIndex9.getActiveTimeSlots()).thenReturn(List.of(EIGHT_DAYS_AGO));
+ when(mEventIndex10.getActiveTimeSlots()).thenReturn(List.of());
+
+ SharesheetModelScorer.computeScore(
+ List.of(mShareTarget1, mShareTarget2, mShareTarget3, mShareTarget4, mShareTarget5,
+ mShareTarget6),
+ Event.TYPE_SHARE_TEXT,
+ NOW);
+
+ // Verification
+ assertEquals(0.514f, mShareTarget1.getScore(), DELTA);
+ assertEquals(0.475125f, mShareTarget2.getScore(), DELTA);
+ assertEquals(0.33f, mShareTarget3.getScore(), DELTA);
+ assertEquals(0.4411f, mShareTarget4.getScore(), DELTA);
+ assertEquals(0f, mShareTarget5.getScore(), DELTA);
+ assertEquals(0f, mShareTarget6.getScore(), DELTA);
+ }
+
+ @Test
+ public void testComputeScoreForAppShare() {
+ // Frequency and recency
+ 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(mEventIndex1.getActiveTimeSlots()).thenReturn(
+ List.of(WITHIN_ONE_DAY, TWO_DAYS_AGO, FIVE_DAYS_AGO));
+ when(mEventIndex2.getActiveTimeSlots()).thenReturn(List.of(TWO_DAYS_AGO, TWELVE_DAYS_AGO));
+ when(mEventIndex3.getActiveTimeSlots()).thenReturn(List.of(FIVE_DAYS_AGO, TWENTY_DAYS_AGO));
+ when(mEventIndex4.getActiveTimeSlots()).thenReturn(
+ List.of(EIGHT_DAYS_AGO, TWELVE_DAYS_AGO, FOUR_WEEKS_AGO));
+ when(mEventIndex5.getActiveTimeSlots()).thenReturn(List.of());
+
+ when(mEventIndex1.getMostRecentActiveTimeSlot()).thenReturn(WITHIN_ONE_DAY);
+ when(mEventIndex2.getMostRecentActiveTimeSlot()).thenReturn(TWO_DAYS_AGO);
+ when(mEventIndex3.getMostRecentActiveTimeSlot()).thenReturn(FIVE_DAYS_AGO);
+ when(mEventIndex4.getMostRecentActiveTimeSlot()).thenReturn(EIGHT_DAYS_AGO);
+ when(mEventIndex5.getMostRecentActiveTimeSlot()).thenReturn(null);
+
+ // Frequency of the same mime type
+ when(mEventHistory1.getEventIndex(Event.TYPE_SHARE_TEXT)).thenReturn(mEventIndex6);
+ when(mEventHistory2.getEventIndex(Event.TYPE_SHARE_TEXT)).thenReturn(mEventIndex7);
+ when(mEventHistory3.getEventIndex(Event.TYPE_SHARE_TEXT)).thenReturn(mEventIndex8);
+ when(mEventHistory4.getEventIndex(Event.TYPE_SHARE_TEXT)).thenReturn(mEventIndex9);
+ when(mEventHistory5.getEventIndex(Event.TYPE_SHARE_TEXT)).thenReturn(mEventIndex10);
+
+ when(mEventIndex6.getActiveTimeSlots()).thenReturn(List.of(TWO_DAYS_AGO));
+ when(mEventIndex7.getActiveTimeSlots()).thenReturn(List.of(TWO_DAYS_AGO, TWELVE_DAYS_AGO));
+ when(mEventIndex8.getActiveTimeSlots()).thenReturn(List.of());
+ when(mEventIndex9.getActiveTimeSlots()).thenReturn(List.of(EIGHT_DAYS_AGO));
+ when(mEventIndex10.getActiveTimeSlots()).thenReturn(List.of());
+
+ SharesheetModelScorer.computeScoreForAppShare(
+ List.of(mShareTarget1, mShareTarget2, mShareTarget3, mShareTarget4, mShareTarget5,
+ mShareTarget6),
+ Event.TYPE_SHARE_TEXT, 20, NOW, mDataManager, USER_ID);
+
+ // Verification
+ assertEquals(0.514f, mShareTarget1.getScore(), DELTA);
+ assertEquals(0.475125f, mShareTarget2.getScore(), DELTA);
+ assertEquals(0.33f, mShareTarget3.getScore(), DELTA);
+ assertEquals(0.4411f, mShareTarget4.getScore(), DELTA);
+ assertEquals(0f, mShareTarget5.getScore(), DELTA);
+ assertEquals(0f, mShareTarget6.getScore(), DELTA);
+ }
+
+ @Test
+ public void testComputeScoreForAppShare_promoteFrequentlyUsedApps() {
+ 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(mEventHistory1.getEventIndex(Event.TYPE_SHARE_TEXT)).thenReturn(mEventIndex6);
+ when(mEventHistory2.getEventIndex(Event.TYPE_SHARE_TEXT)).thenReturn(mEventIndex7);
+ when(mEventHistory3.getEventIndex(Event.TYPE_SHARE_TEXT)).thenReturn(mEventIndex8);
+ when(mEventHistory4.getEventIndex(Event.TYPE_SHARE_TEXT)).thenReturn(mEventIndex9);
+ when(mEventHistory5.getEventIndex(Event.TYPE_SHARE_TEXT)).thenReturn(mEventIndex10);
+ when(mDataManager.queryAppLaunchCount(anyInt(), anyLong(), anyLong(), anySet()))
+ .thenReturn(
+ Map.of(PACKAGE_1, 1,
+ PACKAGE_2, 2,
+ PACKAGE_3, 3));
+
+ SharesheetModelScorer.computeScoreForAppShare(
+ List.of(mShareTarget1, mShareTarget2, mShareTarget3, mShareTarget4, mShareTarget5,
+ mShareTarget6),
+ Event.TYPE_SHARE_TEXT, 20, NOW, mDataManager, USER_ID);
+
+ verify(mDataManager, times(1)).queryAppLaunchCount(anyInt(), anyLong(), anyLong(),
+ anySet());
+ assertEquals(0.9f, mShareTarget5.getScore(), DELTA);
+ assertEquals(0.81f, mShareTarget3.getScore(), DELTA);
+ assertEquals(0.729f, mShareTarget1.getScore(), DELTA);
+ assertEquals(0f, mShareTarget2.getScore(), DELTA);
+ assertEquals(0f, mShareTarget4.getScore(), DELTA);
+ assertEquals(0f, mShareTarget6.getScore(), DELTA);
+ }
+
+ @Test
+ public void testComputeScoreForAppShare_skipPromoteFrequentlyUsedAppsWhenReachesLimit() {
+ 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(mEventHistory1.getEventIndex(Event.TYPE_SHARE_TEXT)).thenReturn(mEventIndex6);
+ when(mEventHistory2.getEventIndex(Event.TYPE_SHARE_TEXT)).thenReturn(mEventIndex7);
+ when(mEventHistory3.getEventIndex(Event.TYPE_SHARE_TEXT)).thenReturn(mEventIndex8);
+ when(mEventHistory4.getEventIndex(Event.TYPE_SHARE_TEXT)).thenReturn(mEventIndex9);
+ when(mEventHistory5.getEventIndex(Event.TYPE_SHARE_TEXT)).thenReturn(mEventIndex10);
+ when(mEventIndex1.getMostRecentActiveTimeSlot()).thenReturn(WITHIN_ONE_DAY);
+ when(mEventIndex2.getMostRecentActiveTimeSlot()).thenReturn(TWO_DAYS_AGO);
+ when(mEventIndex3.getMostRecentActiveTimeSlot()).thenReturn(FIVE_DAYS_AGO);
+ when(mEventIndex4.getMostRecentActiveTimeSlot()).thenReturn(EIGHT_DAYS_AGO);
+ when(mEventIndex5.getMostRecentActiveTimeSlot()).thenReturn(null);
+ when(mDataManager.queryAppLaunchCount(anyInt(), anyLong(), anyLong(), anySet()))
+ .thenReturn(
+ Map.of(PACKAGE_1, 1,
+ PACKAGE_2, 2,
+ PACKAGE_3, 3));
+
+ SharesheetModelScorer.computeScoreForAppShare(
+ List.of(mShareTarget1, mShareTarget2, mShareTarget3, mShareTarget4, mShareTarget5,
+ mShareTarget6),
+ Event.TYPE_SHARE_TEXT, 4, NOW, mDataManager, USER_ID);
+
+ verify(mDataManager, never()).queryAppLaunchCount(anyInt(), anyLong(), anyLong(), anySet());
+ assertEquals(0.4f, mShareTarget1.getScore(), DELTA);
+ assertEquals(0.35f, mShareTarget2.getScore(), DELTA);
+ assertEquals(0.33f, mShareTarget3.getScore(), DELTA);
+ assertEquals(0.31f, mShareTarget4.getScore(), DELTA);
+ assertEquals(0f, mShareTarget5.getScore(), DELTA);
+ assertEquals(0f, mShareTarget6.getScore(), DELTA);
+ }
+
+ @Test
+ public void testComputeScoreForAppShare_promoteForegroundApp() {
+ 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(mEventHistory1.getEventIndex(Event.TYPE_SHARE_TEXT)).thenReturn(mEventIndex6);
+ when(mEventHistory2.getEventIndex(Event.TYPE_SHARE_TEXT)).thenReturn(mEventIndex7);
+ when(mEventHistory3.getEventIndex(Event.TYPE_SHARE_TEXT)).thenReturn(mEventIndex8);
+ when(mEventHistory4.getEventIndex(Event.TYPE_SHARE_TEXT)).thenReturn(mEventIndex9);
+ when(mEventHistory5.getEventIndex(Event.TYPE_SHARE_TEXT)).thenReturn(mEventIndex10);
+ when(mDataManager.queryAppMovingToForegroundEvents(anyInt(), anyLong(),
+ anyLong())).thenReturn(
+ List.of(createUsageEvent(PACKAGE_2),
+ createUsageEvent(PACKAGE_3),
+ createUsageEvent(SharesheetModelScorer.CHOOSER_ACTIVITY),
+ createUsageEvent(PACKAGE_3),
+ createUsageEvent(PACKAGE_3))
+ );
+
+ SharesheetModelScorer.computeScoreForAppShare(
+ List.of(mShareTarget1, mShareTarget2, mShareTarget3, mShareTarget4, mShareTarget5,
+ mShareTarget6),
+ Event.TYPE_SHARE_TEXT, 20, NOW, mDataManager, USER_ID);
+
+ verify(mDataManager, times(1)).queryAppMovingToForegroundEvents(anyInt(), anyLong(),
+ anyLong());
+ assertEquals(0f, mShareTarget1.getScore(), DELTA);
+ assertEquals(0f, mShareTarget2.getScore(), DELTA);
+ assertEquals(SharesheetModelScorer.FOREGROUND_APP_WEIGHT, mShareTarget3.getScore(), DELTA);
+ assertEquals(0f, mShareTarget4.getScore(), DELTA);
+ assertEquals(0f, mShareTarget5.getScore(), DELTA);
+ assertEquals(0f, mShareTarget6.getScore(), DELTA);
+ }
+
+ @Test
+ public void testComputeScoreForAppShare_skipPromoteForegroundAppWhenNoValidForegroundApp() {
+ 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(mEventHistory1.getEventIndex(Event.TYPE_SHARE_TEXT)).thenReturn(mEventIndex6);
+ when(mEventHistory2.getEventIndex(Event.TYPE_SHARE_TEXT)).thenReturn(mEventIndex7);
+ when(mEventHistory3.getEventIndex(Event.TYPE_SHARE_TEXT)).thenReturn(mEventIndex8);
+ when(mEventHistory4.getEventIndex(Event.TYPE_SHARE_TEXT)).thenReturn(mEventIndex9);
+ when(mEventHistory5.getEventIndex(Event.TYPE_SHARE_TEXT)).thenReturn(mEventIndex10);
+ when(mDataManager.queryAppMovingToForegroundEvents(anyInt(), anyLong(),
+ anyLong())).thenReturn(
+ List.of(createUsageEvent(PACKAGE_3),
+ createUsageEvent(PACKAGE_3),
+ createUsageEvent(SharesheetModelScorer.CHOOSER_ACTIVITY),
+ createUsageEvent(PACKAGE_3),
+ createUsageEvent(PACKAGE_3))
+ );
+
+ SharesheetModelScorer.computeScoreForAppShare(
+ List.of(mShareTarget1, mShareTarget2, mShareTarget3, mShareTarget4, mShareTarget5,
+ mShareTarget6),
+ Event.TYPE_SHARE_TEXT, 20, NOW, mDataManager, USER_ID);
+
+ verify(mDataManager, times(1)).queryAppMovingToForegroundEvents(anyInt(), anyLong(),
+ anyLong());
+ assertEquals(0f, mShareTarget1.getScore(), DELTA);
+ assertEquals(0f, mShareTarget2.getScore(), DELTA);
+ assertEquals(0f, mShareTarget3.getScore(), DELTA);
+ assertEquals(0f, mShareTarget4.getScore(), DELTA);
+ assertEquals(0f, mShareTarget5.getScore(), DELTA);
+ assertEquals(0f, mShareTarget6.getScore(), DELTA);
+ }
+
+ private static UsageEvents.Event createUsageEvent(String packageName) {
+ UsageEvents.Event e = new UsageEvents.Event();
+ e.mPackage = packageName;
+ return e;
+ }
+}
diff --git a/services/tests/servicestests/src/com/android/server/pm/ApexManagerTest.java b/services/tests/servicestests/src/com/android/server/pm/ApexManagerTest.java
index 40ada2aedd59..db1bbab7ed94 100644
--- a/services/tests/servicestests/src/com/android/server/pm/ApexManagerTest.java
+++ b/services/tests/servicestests/src/com/android/server/pm/ApexManagerTest.java
@@ -43,6 +43,7 @@ import androidx.test.platform.app.InstrumentationRegistry;
import androidx.test.runner.AndroidJUnit4;
import com.android.frameworks.servicestests.R;
+import com.android.server.pm.parsing.PackageParser2;
import org.junit.Before;
import org.junit.Test;
@@ -63,6 +64,7 @@ public class ApexManagerTest {
private static final int[] TEST_CHILD_SESSION_ID = {8888, 7777};
private ApexManager mApexManager;
private Context mContext;
+ private PackageParser2 mPackageParser2;
private IApexService mApexService = mock(IApexService.class);
@@ -70,11 +72,14 @@ public class ApexManagerTest {
public void setUp() throws RemoteException {
mContext = InstrumentationRegistry.getInstrumentation().getContext();
mApexManager = new ApexManager.ApexManagerImpl(mApexService);
+ mPackageParser2 = new PackageParser2(null, false, null, null, null);
}
@Test
public void testGetPackageInfo_setFlagsMatchActivePackage() throws RemoteException {
when(mApexService.getAllPackages()).thenReturn(createApexInfo(true, false));
+ mApexManager.scanApexPackagesTraced(mPackageParser2,
+ ParallelPackageParser.makeExecutorService());
final PackageInfo activePkgPi = mApexManager.getPackageInfo(TEST_APEX_PKG,
ApexManager.MATCH_ACTIVE_PACKAGE);
@@ -90,6 +95,8 @@ public class ApexManagerTest {
@Test
public void testGetPackageInfo_setFlagsMatchFactoryPackage() throws RemoteException {
when(mApexService.getAllPackages()).thenReturn(createApexInfo(false, true));
+ mApexManager.scanApexPackagesTraced(mPackageParser2,
+ ParallelPackageParser.makeExecutorService());
PackageInfo factoryPkgPi = mApexManager.getPackageInfo(TEST_APEX_PKG,
ApexManager.MATCH_FACTORY_PACKAGE);
@@ -105,6 +112,8 @@ public class ApexManagerTest {
@Test
public void testGetPackageInfo_setFlagsNone() throws RemoteException {
when(mApexService.getAllPackages()).thenReturn(createApexInfo(false, true));
+ mApexManager.scanApexPackagesTraced(mPackageParser2,
+ ParallelPackageParser.makeExecutorService());
assertThat(mApexManager.getPackageInfo(TEST_APEX_PKG, 0)).isNull();
}
@@ -112,6 +121,8 @@ public class ApexManagerTest {
@Test
public void testGetActivePackages() throws RemoteException {
when(mApexService.getAllPackages()).thenReturn(createApexInfo(true, true));
+ mApexManager.scanApexPackagesTraced(mPackageParser2,
+ ParallelPackageParser.makeExecutorService());
assertThat(mApexManager.getActivePackages()).isNotEmpty();
}
@@ -119,6 +130,8 @@ public class ApexManagerTest {
@Test
public void testGetActivePackages_noneActivePackages() throws RemoteException {
when(mApexService.getAllPackages()).thenReturn(createApexInfo(false, true));
+ mApexManager.scanApexPackagesTraced(mPackageParser2,
+ ParallelPackageParser.makeExecutorService());
assertThat(mApexManager.getActivePackages()).isEmpty();
}
@@ -126,6 +139,8 @@ public class ApexManagerTest {
@Test
public void testGetFactoryPackages() throws RemoteException {
when(mApexService.getAllPackages()).thenReturn(createApexInfo(false, true));
+ mApexManager.scanApexPackagesTraced(mPackageParser2,
+ ParallelPackageParser.makeExecutorService());
assertThat(mApexManager.getFactoryPackages()).isNotEmpty();
}
@@ -133,6 +148,8 @@ public class ApexManagerTest {
@Test
public void testGetFactoryPackages_noneFactoryPackages() throws RemoteException {
when(mApexService.getAllPackages()).thenReturn(createApexInfo(true, false));
+ mApexManager.scanApexPackagesTraced(mPackageParser2,
+ ParallelPackageParser.makeExecutorService());
assertThat(mApexManager.getFactoryPackages()).isEmpty();
}
@@ -140,6 +157,8 @@ public class ApexManagerTest {
@Test
public void testGetInactivePackages() throws RemoteException {
when(mApexService.getAllPackages()).thenReturn(createApexInfo(false, true));
+ mApexManager.scanApexPackagesTraced(mPackageParser2,
+ ParallelPackageParser.makeExecutorService());
assertThat(mApexManager.getInactivePackages()).isNotEmpty();
}
@@ -147,6 +166,8 @@ public class ApexManagerTest {
@Test
public void testGetInactivePackages_noneInactivePackages() throws RemoteException {
when(mApexService.getAllPackages()).thenReturn(createApexInfo(true, false));
+ mApexManager.scanApexPackagesTraced(mPackageParser2,
+ ParallelPackageParser.makeExecutorService());
assertThat(mApexManager.getInactivePackages()).isEmpty();
}
@@ -154,6 +175,8 @@ public class ApexManagerTest {
@Test
public void testIsApexPackage() throws RemoteException {
when(mApexService.getAllPackages()).thenReturn(createApexInfo(false, true));
+ mApexManager.scanApexPackagesTraced(mPackageParser2,
+ ParallelPackageParser.makeExecutorService());
assertThat(mApexManager.isApexPackage(TEST_APEX_PKG)).isTrue();
}
diff --git a/services/tests/servicestests/src/com/android/server/tv/tunerresourcemanager/TunerResourceManagerServiceTest.java b/services/tests/servicestests/src/com/android/server/tv/tunerresourcemanager/TunerResourceManagerServiceTest.java
index 155c6ddd4507..fcbd5072ae35 100644
--- a/services/tests/servicestests/src/com/android/server/tv/tunerresourcemanager/TunerResourceManagerServiceTest.java
+++ b/services/tests/servicestests/src/com/android/server/tv/tunerresourcemanager/TunerResourceManagerServiceTest.java
@@ -34,6 +34,7 @@ import android.media.tv.tunerresourcemanager.TunerFrontendInfo;
import android.media.tv.tunerresourcemanager.TunerFrontendRequest;
import android.media.tv.tunerresourcemanager.TunerResourceManager;
import android.os.RemoteException;
+import android.platform.test.annotations.Presubmit;
import androidx.test.InstrumentationRegistry;
import androidx.test.filters.SmallTest;
@@ -54,6 +55,7 @@ import java.util.Map;
* Tests for {@link TunerResourceManagerService} class.
*/
@SmallTest
+@Presubmit
@RunWith(JUnit4.class)
public class TunerResourceManagerServiceTest {
private static final String TAG = "TunerResourceManagerServiceTest";
diff --git a/services/tests/servicestests/src/com/android/server/tv/tunerresourcemanager/UseCasePriorityHintsTest.java b/services/tests/servicestests/src/com/android/server/tv/tunerresourcemanager/UseCasePriorityHintsTest.java
index ab5665ba99fc..2ff178eba3e1 100644
--- a/services/tests/servicestests/src/com/android/server/tv/tunerresourcemanager/UseCasePriorityHintsTest.java
+++ b/services/tests/servicestests/src/com/android/server/tv/tunerresourcemanager/UseCasePriorityHintsTest.java
@@ -18,6 +18,7 @@ package com.android.server.tv.tunerresourcemanager;
import static com.google.common.truth.Truth.assertThat;
import android.media.tv.TvInputService;
+import android.platform.test.annotations.Presubmit;
import android.util.Slog;
import androidx.test.filters.SmallTest;
@@ -36,6 +37,7 @@ import java.nio.charset.StandardCharsets;
* Tests for {@link UseCasePriorityHints} class.
*/
@SmallTest
+@Presubmit
@RunWith(JUnit4.class)
public class UseCasePriorityHintsTest {
private static final String TAG = "UseCasePriorityHintsTest";
diff --git a/services/tests/wmtests/src/com/android/server/wm/ActivityStackTests.java b/services/tests/wmtests/src/com/android/server/wm/ActivityStackTests.java
index 52fc3de89451..12934ee8bb78 100644
--- a/services/tests/wmtests/src/com/android/server/wm/ActivityStackTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/ActivityStackTests.java
@@ -27,6 +27,7 @@ import static android.app.WindowConfiguration.WINDOWING_MODE_SPLIT_SCREEN_SECOND
import static android.app.WindowConfiguration.WINDOWING_MODE_UNDEFINED;
import static android.content.pm.ActivityInfo.FLAG_RESUME_WHILE_PAUSING;
+import static com.android.dx.mockito.inline.extended.ExtendedMockito.doCallRealMethod;
import static com.android.dx.mockito.inline.extended.ExtendedMockito.doNothing;
import static com.android.dx.mockito.inline.extended.ExtendedMockito.doReturn;
import static com.android.dx.mockito.inline.extended.ExtendedMockito.mock;
@@ -56,7 +57,6 @@ import static org.mockito.ArgumentMatchers.any;
import static org.mockito.ArgumentMatchers.anyBoolean;
import static org.mockito.ArgumentMatchers.anyString;
import static org.mockito.ArgumentMatchers.eq;
-import static org.mockito.Mockito.mock;
import android.app.ActivityManager;
import android.app.IApplicationThread;
@@ -1157,6 +1157,34 @@ public class ActivityStackTests extends ActivityTestsBase {
}
@Test
+ public void testCheckBehindFullscreenActivity() {
+ final ActivityRecord bottomActivity =
+ new ActivityBuilder(mService).setStack(mStack).setTask(mTask).build();
+ final ActivityRecord topActivity =
+ new ActivityBuilder(mService).setStack(mStack).setTask(mTask).build();
+ doReturn(true).when(mStack).shouldBeVisible(any());
+ assertTrue(mStack.checkBehindFullscreenActivity(bottomActivity,
+ null /* handleBehindFullscreenActivity */));
+ assertFalse(mStack.checkBehindFullscreenActivity(topActivity,
+ null /* handleBehindFullscreenActivity */));
+
+ doReturn(false).when(topActivity).occludesParent();
+ assertFalse(mStack.checkBehindFullscreenActivity(bottomActivity,
+ null /* handleBehindFullscreenActivity */));
+ assertFalse(mStack.checkBehindFullscreenActivity(topActivity,
+ null /* handleBehindFullscreenActivity */));
+
+ final ActivityRecord finishingActivity =
+ new ActivityBuilder(mService).setStack(mStack).setTask(mTask).build();
+ finishingActivity.finishing = true;
+ doCallRealMethod().when(finishingActivity).occludesParent();
+ assertFalse(mStack.checkBehindFullscreenActivity(bottomActivity,
+ null /* handleBehindFullscreenActivity */));
+ assertFalse(mStack.checkBehindFullscreenActivity(topActivity,
+ null /* handleBehindFullscreenActivity */));
+ }
+
+ @Test
public void testClearUnknownAppVisibilityBehindFullscreenActivity() {
final UnknownAppVisibilityController unknownAppVisibilityController =
mDefaultDisplay.mDisplayContent.mUnknownAppVisibilityController;
diff --git a/services/tests/wmtests/src/com/android/server/wm/AppTransitionTests.java b/services/tests/wmtests/src/com/android/server/wm/AppTransitionTests.java
index c71d8194f889..08e492a7b0ff 100644
--- a/services/tests/wmtests/src/com/android/server/wm/AppTransitionTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/AppTransitionTests.java
@@ -28,7 +28,6 @@ import static android.view.WindowManager.TRANSIT_KEYGUARD_UNOCCLUDE;
import static androidx.test.platform.app.InstrumentationRegistry.getInstrumentation;
-import static com.android.dx.mockito.inline.extended.ExtendedMockito.anyBoolean;
import static com.android.dx.mockito.inline.extended.ExtendedMockito.doNothing;
import static com.android.dx.mockito.inline.extended.ExtendedMockito.doReturn;
@@ -38,7 +37,6 @@ import static org.junit.Assert.assertNull;
import static org.junit.Assert.assertTrue;
import static org.mockito.ArgumentMatchers.any;
-import android.graphics.Rect;
import android.os.IBinder;
import android.os.RemoteException;
import android.platform.test.annotations.Presubmit;
@@ -70,7 +68,7 @@ public class AppTransitionTests extends WindowTestsBase {
@Before
public void setUp() throws Exception {
- doNothing().when(mWm.mRoot).performSurfacePlacement(anyBoolean());
+ doNothing().when(mWm.mRoot).performSurfacePlacement();
mDc = mWm.getDefaultDisplayContentLocked();
}
diff --git a/services/tests/wmtests/src/com/android/server/wm/AppWindowTokenTests.java b/services/tests/wmtests/src/com/android/server/wm/AppWindowTokenTests.java
index 6cc57f4dbf8c..cf3cfecbf65e 100644
--- a/services/tests/wmtests/src/com/android/server/wm/AppWindowTokenTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/AppWindowTokenTests.java
@@ -174,7 +174,7 @@ public class AppWindowTokenTests extends WindowTestsBase {
null /* freezeThisOneIfNeeded */, false /* forceUpdate */);
// In this test, DC will not get config update. Set the waiting flag to false.
mDisplayContent.mWaitingForConfig = false;
- mWm.mRoot.performSurfacePlacement(false /* recoveringMemory */);
+ mWm.mRoot.performSurfacePlacement();
assertEquals(SCREEN_ORIENTATION_REVERSE_LANDSCAPE, mDisplayContent.getLastOrientation());
assertTrue(appWindow.mResizeReported);
appWindow.removeImmediately();
diff --git a/services/tests/wmtests/src/com/android/server/wm/RecentTasksTest.java b/services/tests/wmtests/src/com/android/server/wm/RecentTasksTest.java
index 66566bc5dff5..da3ee3990137 100644
--- a/services/tests/wmtests/src/com/android/server/wm/RecentTasksTest.java
+++ b/services/tests/wmtests/src/com/android/server/wm/RecentTasksTest.java
@@ -21,6 +21,7 @@ import static android.app.WindowConfiguration.ACTIVITY_TYPE_HOME;
import static android.app.WindowConfiguration.ACTIVITY_TYPE_STANDARD;
import static android.app.WindowConfiguration.ACTIVITY_TYPE_UNDEFINED;
import static android.app.WindowConfiguration.WINDOWING_MODE_FULLSCREEN;
+import static android.app.WindowConfiguration.WINDOWING_MODE_MULTI_WINDOW;
import static android.app.WindowConfiguration.WINDOWING_MODE_PINNED;
import static android.app.WindowConfiguration.WINDOWING_MODE_UNDEFINED;
import static android.content.Intent.FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS;
@@ -28,6 +29,7 @@ import static android.content.Intent.FLAG_ACTIVITY_MULTIPLE_TASK;
import static android.content.Intent.FLAG_ACTIVITY_NEW_DOCUMENT;
import static android.content.Intent.FLAG_ACTIVITY_NEW_TASK;
import static android.view.Display.DEFAULT_DISPLAY;
+import static android.view.Display.TYPE_VIRTUAL;
import static com.android.dx.mockito.inline.extended.ExtendedMockito.doNothing;
import static com.android.dx.mockito.inline.extended.ExtendedMockito.doReturn;
@@ -54,6 +56,7 @@ import static java.lang.Integer.MAX_VALUE;
import android.app.ActivityManager.RecentTaskInfo;
import android.app.ActivityManager.RunningTaskInfo;
+import android.app.ActivityOptions;
import android.app.ActivityTaskManager;
import android.app.WindowConfiguration;
import android.content.ComponentName;
@@ -681,24 +684,19 @@ public class RecentTasksTest extends ActivityTestsBase {
* Tests that tasks on singleTaskDisplay are not visible and not trimmed/removed.
*/
@Test
- public void testVisibleTasks_singleTaskDisplay() {
+ public void testVisibleTasks_alwaysOnTop() {
mRecentTasks.setOnlyTestVisibleRange();
mRecentTasks.setParameters(-1 /* min */, 3 /* max */, -1 /* ms */);
- final DisplayContent singleTaskDisplay =
- addNewDisplayContentAt(DisplayContent.POSITION_TOP);
- singleTaskDisplay.setDisplayToSingleTaskInstance();
- ActivityStack singleTaskStack = singleTaskDisplay.createStack(
- WINDOWING_MODE_FULLSCREEN, ACTIVITY_TYPE_STANDARD, true /* onTop */);
+ final DisplayContent display = mRootWindowContainer.getDefaultDisplay();
+ final Task alwaysOnTopTask = display.createStack(WINDOWING_MODE_MULTI_WINDOW,
+ ACTIVITY_TYPE_STANDARD, true /* onTop */);
+ alwaysOnTopTask.setAlwaysOnTop(true);
- Task excludedTask1 = createTaskBuilder(".ExcludedTask1")
- .setStack(singleTaskStack)
- .build();
+ assertFalse("Always on top tasks should not be visible recents",
+ mRecentTasks.isVisibleRecentTask(alwaysOnTopTask));
- assertFalse("Tasks on singleTaskDisplay should not be visible recents",
- mRecentTasks.isVisibleRecentTask(excludedTask1));
-
- mRecentTasks.add(excludedTask1);
+ mRecentTasks.add(alwaysOnTopTask);
// Add N+1 visible tasks.
mRecentTasks.add(mTasks.get(0));
@@ -1366,12 +1364,12 @@ public class RecentTasksTest extends ActivityTestsBase {
public boolean mLastAllowed;
@Override
- void getTasks(int maxNum, List<RunningTaskInfo> list, int ignoreActivityType,
- int ignoreWindowingMode, RootWindowContainer root,
- int callingUid, boolean allowed, boolean crossUser, ArraySet<Integer> profileIds) {
+ void getTasks(int maxNum, List<RunningTaskInfo> list, boolean filterOnlyVisibleRecents,
+ RootWindowContainer root, int callingUid, boolean allowed, boolean crossUser,
+ ArraySet<Integer> profileIds) {
mLastAllowed = allowed;
- super.getTasks(maxNum, list, ignoreActivityType, ignoreWindowingMode, root,
- callingUid, allowed, crossUser, profileIds);
+ super.getTasks(maxNum, list, filterOnlyVisibleRecents, root, callingUid, allowed,
+ crossUser, profileIds);
}
}
}
diff --git a/services/tests/wmtests/src/com/android/server/wm/RecentsAnimationControllerTest.java b/services/tests/wmtests/src/com/android/server/wm/RecentsAnimationControllerTest.java
index 406affc27b0a..da07baca3ce1 100644
--- a/services/tests/wmtests/src/com/android/server/wm/RecentsAnimationControllerTest.java
+++ b/services/tests/wmtests/src/com/android/server/wm/RecentsAnimationControllerTest.java
@@ -100,7 +100,7 @@ public class RecentsAnimationControllerTest extends WindowTestsBase {
@Before
public void setUp() throws Exception {
MockitoAnnotations.initMocks(this);
- doNothing().when(mWm.mRoot).performSurfacePlacement(anyBoolean());
+ doNothing().when(mWm.mRoot).performSurfacePlacement();
when(mMockRunner.asBinder()).thenReturn(new Binder());
mDefaultDisplay = mWm.mRoot.getDefaultDisplay();
mController = spy(new RecentsAnimationController(mWm, mMockRunner, mAnimationCallbacks,
@@ -403,11 +403,11 @@ public class RecentsAnimationControllerTest extends WindowTestsBase {
wallpapers.get(0).getConfiguration().orientation);
// Wallpaper's transform state is controlled by home, so the invocation should be no-op.
- wallpaperWindowToken.clearFixedRotationTransform();
+ wallpaperWindowToken.finishFixedRotationTransform();
assertTrue(wallpaperWindowToken.hasFixedRotationTransform());
// Wallpaper's transform state should be cleared with home.
- homeActivity.clearFixedRotationTransform();
+ homeActivity.finishFixedRotationTransform();
assertFalse(wallpaperWindowToken.hasFixedRotationTransform());
}
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 0ef25824df2a..e841e434ea82 100644
--- a/services/tests/wmtests/src/com/android/server/wm/RootActivityContainerTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/RootActivityContainerTests.java
@@ -788,6 +788,22 @@ public class RootActivityContainerTests extends ActivityTestsBase {
}
@Test
+ public void testGetValidLaunchStackOnDisplayWithCandidateRootTask() {
+ // Create a root task with an activity on secondary display.
+ final TestDisplayContent secondaryDisplay = new TestDisplayContent.Builder(mService, 300,
+ 600).build();
+ final Task task = new ActivityTestsBase.StackBuilder(mRootWindowContainer).setDisplay(
+ secondaryDisplay).build();
+ final ActivityRecord activity = new ActivityTestsBase.ActivityBuilder(mService)
+ .setTask(task).build();
+
+ // Make sure the root task is valid and can be reused on default display.
+ final ActivityStack stack = mRootWindowContainer.getValidLaunchStackOnDisplay(
+ DEFAULT_DISPLAY, activity, task, null, null);
+ assertEquals(task, stack);
+ }
+
+ @Test
public void testSwitchUser_missingHomeRootTask() {
doReturn(mFullscreenStack).when(mRootWindowContainer).getTopDisplayFocusedStack();
diff --git a/services/tests/wmtests/src/com/android/server/wm/RunningTasksTest.java b/services/tests/wmtests/src/com/android/server/wm/RunningTasksTest.java
index 0d5565428bf2..d6a67abc9e76 100644
--- a/services/tests/wmtests/src/com/android/server/wm/RunningTasksTest.java
+++ b/services/tests/wmtests/src/com/android/server/wm/RunningTasksTest.java
@@ -16,9 +16,6 @@
package com.android.server.wm;
-import static android.app.WindowConfiguration.ACTIVITY_TYPE_UNDEFINED;
-import static android.app.WindowConfiguration.WINDOWING_MODE_UNDEFINED;
-
import static com.google.common.truth.Truth.assertThat;
import static org.junit.Assert.assertEquals;
@@ -82,9 +79,8 @@ public class RunningTasksTest extends ActivityTestsBase {
// collected from all tasks across all the stacks
final int numFetchTasks = 5;
ArrayList<RunningTaskInfo> tasks = new ArrayList<>();
- mRunningTasks.getTasks(5, tasks, ACTIVITY_TYPE_UNDEFINED, WINDOWING_MODE_UNDEFINED,
- mRootWindowContainer, -1 /* callingUid */, true /* allowed */,
- true /*crossUser */, PROFILE_IDS);
+ mRunningTasks.getTasks(5, tasks, false /* filterOnlyVisibleRecents */, mRootWindowContainer,
+ -1 /* callingUid */, true /* allowed */, true /*crossUser */, PROFILE_IDS);
assertThat(tasks).hasSize(numFetchTasks);
for (int i = 0; i < numFetchTasks; i++) {
assertEquals(numTasks - i - 1, tasks.get(i).id);
@@ -93,9 +89,9 @@ public class RunningTasksTest extends ActivityTestsBase {
// Ensure that requesting more than the total number of tasks only returns the subset
// and does not crash
tasks.clear();
- mRunningTasks.getTasks(100, tasks, ACTIVITY_TYPE_UNDEFINED, WINDOWING_MODE_UNDEFINED,
- mRootWindowContainer, -1 /* callingUid */, true /* allowed */,
- true /* crossUser */, PROFILE_IDS);
+ mRunningTasks.getTasks(100, tasks, false /* filterOnlyVisibleRecents */,
+ mRootWindowContainer, -1 /* callingUid */, true /* allowed */, true /* crossUser */,
+ PROFILE_IDS);
assertThat(tasks).hasSize(numTasks);
for (int i = 0; i < numTasks; i++) {
assertEquals(numTasks - i - 1, tasks.get(i).id);
@@ -119,9 +115,9 @@ public class RunningTasksTest extends ActivityTestsBase {
final int numFetchTasks = 5;
final ArrayList<RunningTaskInfo> tasks = new ArrayList<>();
- mRunningTasks.getTasks(numFetchTasks, tasks, ACTIVITY_TYPE_UNDEFINED,
- WINDOWING_MODE_UNDEFINED, mRootWindowContainer, -1 /* callingUid */,
- true /* allowed */, true /*crossUser */, PROFILE_IDS);
+ mRunningTasks.getTasks(numFetchTasks, tasks, false /* filterOnlyVisibleRecents */,
+ mRootWindowContainer, -1 /* callingUid */, true /* allowed */, true /*crossUser */,
+ PROFILE_IDS);
assertThat(tasks).hasSize(numFetchTasks);
for (int i = 0; i < tasks.size(); i++) {
final Bundle extras = tasks.get(i).baseIntent.getExtras();
diff --git a/services/tests/wmtests/src/com/android/server/wm/SizeCompatTests.java b/services/tests/wmtests/src/com/android/server/wm/SizeCompatTests.java
index edf81ea32ad3..893a14541c48 100644
--- a/services/tests/wmtests/src/com/android/server/wm/SizeCompatTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/SizeCompatTests.java
@@ -481,7 +481,7 @@ public class SizeCompatTests extends ActivityTestsBase {
// The letterbox needs a main window to layout.
addWindowToActivity(mActivity);
// Compute the frames of the window and invoke {@link ActivityRecord#layoutLetterbox}.
- mActivity.mRootWindowContainer.performSurfacePlacement(false /* recoveringMemory */);
+ mActivity.mRootWindowContainer.performSurfacePlacement();
// The letterbox insets should be [350, 0 - 350, 0].
assertEquals(new Rect(mActivity.getBounds().left, 0, dh - mActivity.getBounds().right, 0),
mActivity.getLetterboxInsets());
diff --git a/telecomm/java/android/telecom/ConnectionService.java b/telecomm/java/android/telecom/ConnectionService.java
index 0dca006f37c0..ffd25c08a8ba 100755
--- a/telecomm/java/android/telecom/ConnectionService.java
+++ b/telecomm/java/android/telecom/ConnectionService.java
@@ -2633,6 +2633,7 @@ public abstract class ConnectionService extends Service {
* @param request Details about the incoming call.
* @return The {@code Connection} object to satisfy this call, or {@code null} to
* not handle the call.
+ * @hide
*/
public @Nullable Conference onCreateIncomingConference(
@Nullable PhoneAccountHandle connectionManagerPhoneAccount,
@@ -2717,6 +2718,7 @@ public abstract class ConnectionService extends Service {
* @param connectionManagerPhoneAccount See description at
* {@link #onCreateOutgoingConnection(PhoneAccountHandle, ConnectionRequest)}.
* @param request The incoming connection request.
+ * @hide
*/
public void onCreateIncomingConferenceFailed(
@Nullable PhoneAccountHandle connectionManagerPhoneAccount,
@@ -2737,6 +2739,7 @@ public abstract class ConnectionService extends Service {
* @param connectionManagerPhoneAccount See description at
* {@link #onCreateOutgoingConnection(PhoneAccountHandle, ConnectionRequest)}.
* @param request The outgoing connection request.
+ * @hide
*/
public void onCreateOutgoingConferenceFailed(
@Nullable PhoneAccountHandle connectionManagerPhoneAccount,
@@ -2805,6 +2808,7 @@ public abstract class ConnectionService extends Service {
* @param request Details about the outgoing call.
* @return The {@code Conference} object to satisfy this call, or the result of an invocation
* of {@link Connection#createFailedConnection(DisconnectCause)} to not handle the call.
+ * @hide
*/
public @Nullable Conference onCreateOutgoingConference(
@Nullable PhoneAccountHandle connectionManagerPhoneAccount,
diff --git a/telephony/common/com/android/internal/telephony/TelephonyPermissions.java b/telephony/common/com/android/internal/telephony/TelephonyPermissions.java
index 0b331744d922..7e02966779a2 100644
--- a/telephony/common/com/android/internal/telephony/TelephonyPermissions.java
+++ b/telephony/common/com/android/internal/telephony/TelephonyPermissions.java
@@ -442,16 +442,40 @@ public final class TelephonyPermissions {
// NOTE(b/73308711): If an app has one of the following AppOps bits explicitly revoked, they
// will be denied access, even if they have another permission and AppOps bit if needed.
- // First, check if we can read the phone state and the SDK version is below R.
+ // First, check if the SDK version is below R
+ boolean preR = false;
try {
ApplicationInfo info = context.getPackageManager().getApplicationInfoAsUser(
callingPackage, 0, UserHandle.getUserHandleForUid(Binder.getCallingUid()));
- if (info.targetSdkVersion <= Build.VERSION_CODES.Q) {
+ preR = info.targetSdkVersion <= Build.VERSION_CODES.Q;
+ } catch (PackageManager.NameNotFoundException nameNotFoundException) {
+ }
+ if (preR) {
+ // SDK < R allows READ_PHONE_STATE, READ_PRIVILEGED_PHONE_STATE, or carrier privilege
+ try {
return checkReadPhoneState(
context, subId, pid, uid, callingPackage, callingFeatureId, message);
+ } catch (SecurityException readPhoneStateException) {
+ }
+ } else {
+ // SDK >= R allows READ_PRIVILEGED_PHONE_STATE or carrier privilege
+ try {
+ context.enforcePermission(
+ android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE, pid, uid, message);
+ // Skip checking for runtime permission since caller has privileged permission
+ return true;
+ } catch (SecurityException readPrivilegedPhoneStateException) {
+ if (SubscriptionManager.isValidSubscriptionId(subId)) {
+ try {
+ enforceCarrierPrivilege(context, subId, uid, message);
+ // Skip checking for runtime permission since caller has carrier privilege
+ return true;
+ } catch (SecurityException carrierPrivilegeException) {
+ }
+ }
}
- } catch (SecurityException | PackageManager.NameNotFoundException e) {
}
+
// Can be read with READ_SMS too.
try {
context.enforcePermission(android.Manifest.permission.READ_SMS, pid, uid, message);
diff --git a/telephony/java/android/telephony/AccessNetworkConstants.java b/telephony/java/android/telephony/AccessNetworkConstants.java
index 558f4cd24471..39a754389254 100644
--- a/telephony/java/android/telephony/AccessNetworkConstants.java
+++ b/telephony/java/android/telephony/AccessNetworkConstants.java
@@ -19,9 +19,9 @@ package android.telephony;
import android.annotation.IntDef;
import android.annotation.SystemApi;
import android.annotation.TestApi;
-import android.hardware.radio.V1_1.EutranBands;
import android.hardware.radio.V1_1.GeranBands;
import android.hardware.radio.V1_5.AccessNetwork;
+import android.hardware.radio.V1_5.EutranBands;
import android.hardware.radio.V1_5.UtranBands;
import java.lang.annotation.Retention;
@@ -212,7 +212,8 @@ public final class AccessNetworkConstants {
/**
* Frequency bands for EUTRAN.
- * http://www.etsi.org/deliver/etsi_ts/136100_136199/136101/14.03.00_60/ts_136101v140p.pdf
+ * 3GPP TS 36.101, Version 16.4.0, Table 5.5: Operating bands
+ * https://www.etsi.org/deliver/etsi_ts/136100_136199/136101/15.09.00_60/ts_136101v150900p.pdf
*/
public static final class EutranBand {
public static final int BAND_1 = EutranBands.BAND_1;
@@ -259,10 +260,22 @@ public final class AccessNetworkConstants {
public static final int BAND_46 = EutranBands.BAND_46;
public static final int BAND_47 = EutranBands.BAND_47;
public static final int BAND_48 = EutranBands.BAND_48;
+ public static final int BAND_49 = EutranBands.BAND_49;
+ public static final int BAND_50 = EutranBands.BAND_50;
+ public static final int BAND_51 = EutranBands.BAND_51;
+ public static final int BAND_52 = EutranBands.BAND_52;
+ public static final int BAND_53 = EutranBands.BAND_53;
public static final int BAND_65 = EutranBands.BAND_65;
public static final int BAND_66 = EutranBands.BAND_66;
public static final int BAND_68 = EutranBands.BAND_68;
public static final int BAND_70 = EutranBands.BAND_70;
+ public static final int BAND_71 = EutranBands.BAND_71;
+ public static final int BAND_72 = EutranBands.BAND_72;
+ public static final int BAND_73 = EutranBands.BAND_73;
+ public static final int BAND_74 = EutranBands.BAND_74;
+ public static final int BAND_85 = EutranBands.BAND_85;
+ public static final int BAND_87 = EutranBands.BAND_87;
+ public static final int BAND_88 = EutranBands.BAND_88;
/** @hide */
private EutranBand() {};
@@ -305,9 +318,11 @@ public final class AccessNetworkConstants {
/**
* Frequency bands for NGRAN
+ * https://www.etsi.org/deliver/etsi_ts/138100_138199/13810101/15.08.02_60/ts_13810101v150802p.pdf
+ * https://www.etsi.org/deliver/etsi_ts/138100_138199/13810102/15.08.00_60/ts_13810102v150800p.pdf
*/
public static final class NgranBands {
- /** FR1 bands */
+ /** 3GPP TS 38.101-1, Version 16.2.0, Table 5.2-1: FR1 bands */
public static final int BAND_1 = android.hardware.radio.V1_5.NgranBands.BAND_1;
public static final int BAND_2 = android.hardware.radio.V1_5.NgranBands.BAND_2;
public static final int BAND_3 = android.hardware.radio.V1_5.NgranBands.BAND_3;
@@ -346,9 +361,15 @@ public final class AccessNetworkConstants {
public static final int BAND_83 = android.hardware.radio.V1_5.NgranBands.BAND_83;
public static final int BAND_84 = android.hardware.radio.V1_5.NgranBands.BAND_84;
public static final int BAND_86 = android.hardware.radio.V1_5.NgranBands.BAND_86;
+ public static final int BAND_89 = android.hardware.radio.V1_5.NgranBands.BAND_89;
public static final int BAND_90 = android.hardware.radio.V1_5.NgranBands.BAND_90;
+ public static final int BAND_91 = android.hardware.radio.V1_5.NgranBands.BAND_91;
+ public static final int BAND_92 = android.hardware.radio.V1_5.NgranBands.BAND_92;
+ public static final int BAND_93 = android.hardware.radio.V1_5.NgranBands.BAND_93;
+ public static final int BAND_94 = android.hardware.radio.V1_5.NgranBands.BAND_94;
+ public static final int BAND_95 = android.hardware.radio.V1_5.NgranBands.BAND_95;
- /** FR2 bands */
+ /** 3GPP TS 38.101-2, Version 16.2.0, Table 5.2-1: FR2 bands */
public static final int BAND_257 = android.hardware.radio.V1_5.NgranBands.BAND_257;
public static final int BAND_258 = android.hardware.radio.V1_5.NgranBands.BAND_258;
public static final int BAND_260 = android.hardware.radio.V1_5.NgranBands.BAND_260;
@@ -398,7 +419,13 @@ public final class AccessNetworkConstants {
BAND_83,
BAND_84,
BAND_86,
+ BAND_89,
BAND_90,
+ BAND_91,
+ BAND_92,
+ BAND_93,
+ BAND_94,
+ BAND_95,
BAND_257,
BAND_258,
BAND_260,
@@ -495,7 +522,13 @@ public final class AccessNetworkConstants {
case BAND_83:
case BAND_84:
case BAND_86:
+ case BAND_89:
case BAND_90:
+ case BAND_91:
+ case BAND_92:
+ case BAND_93:
+ case BAND_94:
+ case BAND_95:
return FREQUENCY_RANGE_GROUP_1;
case BAND_257:
case BAND_258:
diff --git a/telephony/java/android/telephony/AccessNetworkUtils.java b/telephony/java/android/telephony/AccessNetworkUtils.java
index 5d2c225f28ec..981ed450004a 100644
--- a/telephony/java/android/telephony/AccessNetworkUtils.java
+++ b/telephony/java/android/telephony/AccessNetworkUtils.java
@@ -34,12 +34,10 @@ public class AccessNetworkUtils {
return DUPLEX_MODE_UNKNOWN;
}
- if (band >= EutranBand.BAND_68) {
+ if (band > EutranBand.BAND_88) {
return DUPLEX_MODE_UNKNOWN;
} else if (band >= EutranBand.BAND_65) {
return DUPLEX_MODE_FDD;
- } else if (band >= EutranBand.BAND_47) {
- return DUPLEX_MODE_UNKNOWN;
} else if (band >= EutranBand.BAND_33) {
return DUPLEX_MODE_TDD;
} else if (band >= EutranBand.BAND_1) {
@@ -58,17 +56,53 @@ public class AccessNetworkUtils {
* @return Operating band number, or {@link #INVALID_BAND} if no corresponding band exists
*/
public static int getOperatingBandForEarfcn(int earfcn) {
- if (earfcn > 67535) {
+ if (earfcn > 70645) {
+ return INVALID_BAND;
+ } else if (earfcn >= 70596) {
+ return EutranBand.BAND_88;
+ } else if (earfcn >= 70546) {
+ return EutranBand.BAND_87;
+ } else if (earfcn >= 70366) {
+ return EutranBand.BAND_85;
+ } else if (earfcn > 69465) {
+ return INVALID_BAND;
+ } else if (earfcn >= 69036) {
+ return EutranBand.BAND_74;
+ } else if (earfcn >= 68986) {
+ return EutranBand.BAND_73;
+ } else if (earfcn >= 68936) {
+ return EutranBand.BAND_72;
+ } else if (earfcn >= 68586) {
+ return EutranBand.BAND_71;
+ } else if (earfcn >= 68336) {
+ return EutranBand.BAND_70;
+ } else if (earfcn > 67835) {
return INVALID_BAND;
+ } else if (earfcn >= 67536) {
+ return EutranBand.BAND_68;
} else if (earfcn >= 67366) {
return INVALID_BAND; // band 67 only for CarrierAgg
} else if (earfcn >= 66436) {
return EutranBand.BAND_66;
} else if (earfcn >= 65536) {
return EutranBand.BAND_65;
- } else if (earfcn > 54339) {
+ } else if (earfcn > 60254) {
return INVALID_BAND;
- } else if (earfcn >= 46790 /* inferred from the end range of BAND_45 */) {
+ } else if (earfcn >= 60140) {
+ return EutranBand.BAND_53;
+ } else if (earfcn >= 59140) {
+ return EutranBand.BAND_52;
+ } else if (earfcn >= 59090) {
+ return EutranBand.BAND_51;
+ } else if (earfcn >= 58240) {
+ return EutranBand.BAND_50;
+ } else if (earfcn >= 56740) {
+ return EutranBand.BAND_49;
+ } else if (earfcn >= 55240) {
+ return EutranBand.BAND_48;
+ } else if (earfcn >= 54540) {
+ return EutranBand.BAND_47;
+ } else if (earfcn >= 46790) {
return EutranBand.BAND_46;
} else if (earfcn >= 46590) {
return EutranBand.BAND_45;
diff --git a/telephony/java/android/telephony/CellSignalStrengthCdma.java b/telephony/java/android/telephony/CellSignalStrengthCdma.java
index 1c92705b9422..d00049c1ebe5 100644
--- a/telephony/java/android/telephony/CellSignalStrengthCdma.java
+++ b/telephony/java/android/telephony/CellSignalStrengthCdma.java
@@ -314,6 +314,8 @@ public final class CellSignalStrengthCdma extends CellSignalStrength implements
/**
* Get the signal strength as dBm
+ *
+ * @return min(CDMA RSSI, EVDO RSSI) of the measured cell.
*/
@Override
public int getDbm() {
diff --git a/telephony/java/android/telephony/CellSignalStrengthGsm.java b/telephony/java/android/telephony/CellSignalStrengthGsm.java
index 76d2df918423..9d55f109f751 100644
--- a/telephony/java/android/telephony/CellSignalStrengthGsm.java
+++ b/telephony/java/android/telephony/CellSignalStrengthGsm.java
@@ -145,6 +145,8 @@ public final class CellSignalStrengthGsm extends CellSignalStrength implements P
/**
* Get the signal strength as dBm.
+ *
+ * @return the RSSI of the measured cell.
*/
@Override
public int getDbm() {
diff --git a/telephony/java/android/telephony/SmsManager.java b/telephony/java/android/telephony/SmsManager.java
index c1447465f53f..991375c5bc73 100644
--- a/telephony/java/android/telephony/SmsManager.java
+++ b/telephony/java/android/telephony/SmsManager.java
@@ -2520,7 +2520,6 @@ public final class SmsManager {
* @param sentIntent if not NULL this <code>PendingIntent</code> is
* broadcast when the message is successfully sent, or failed
* @throws IllegalArgumentException if contentUri is empty
- * @deprecated use {@link MmsManager#sendMultimediaMessage} instead.
*/
public void sendMultimediaMessage(Context context, Uri contentUri, String locationUrl,
Bundle configOverrides, PendingIntent sentIntent) {
@@ -2555,7 +2554,6 @@ public final class SmsManager {
* @param downloadedIntent if not NULL this <code>PendingIntent</code> is
* broadcast when the message is downloaded, or the download is failed
* @throws IllegalArgumentException if locationUrl or contentUri is empty
- * @deprecated use {@link MmsManager#downloadMultimediaMessage} instead.
*/
public void downloadMultimediaMessage(Context context, String locationUrl, Uri contentUri,
Bundle configOverrides, PendingIntent downloadedIntent) {
diff --git a/telephony/java/android/telephony/SubscriptionManager.java b/telephony/java/android/telephony/SubscriptionManager.java
index 5d3cc44ac68c..2facd5a16bc8 100644
--- a/telephony/java/android/telephony/SubscriptionManager.java
+++ b/telephony/java/android/telephony/SubscriptionManager.java
@@ -944,6 +944,18 @@ public class SubscriptionManager {
if (DBG) log("onSubscriptionsChanged: NOT OVERRIDDEN");
}
+ /**
+ * Callback invoked when {@link SubscriptionManager#addOnSubscriptionsChangedListener(
+ * Executor, OnSubscriptionsChangedListener)} or
+ * {@link SubscriptionManager#addOnSubscriptionsChangedListener(
+ * OnSubscriptionsChangedListener)} fails to complete due to the
+ * {@link Context#TELEPHONY_REGISTRY_SERVICE} being unavailable.
+ * @hide
+ */
+ public void onAddListenerFailed() {
+ Rlog.w(LOG_TAG, "onAddListenerFailed not overridden");
+ }
+
private void log(String s) {
Rlog.d(LOG_TAG, s);
}
@@ -1012,6 +1024,12 @@ public class SubscriptionManager {
if (telephonyRegistryManager != null) {
telephonyRegistryManager.addOnSubscriptionsChangedListener(listener,
executor);
+ } else {
+ // If the telephony registry isn't available, we will inform the caller on their
+ // listener that it failed so they can try to re-register.
+ loge("addOnSubscriptionsChangedListener: pkgname=" + pkgName + " failed to be added "
+ + " due to TELEPHONY_REGISTRY_SERVICE being unavailable.");
+ executor.execute(() -> listener.onAddListenerFailed());
}
}
diff --git a/test-runner/src/android/test/TouchUtils.java b/test-runner/src/android/test/TouchUtils.java
index bb4e00ba1ef9..f2f0be73c010 100644
--- a/test-runner/src/android/test/TouchUtils.java
+++ b/test-runner/src/android/test/TouchUtils.java
@@ -223,7 +223,7 @@ public class TouchUtils {
public static void dragViewToBottom(InstrumentationTestCase test, Activity activity, View v,
int stepCount) {
int screenHeight =
- activity.getWindowManager().getCurrentWindowMetrics().getSize().getHeight();
+ activity.getWindowManager().getCurrentWindowMetrics().getBounds().height();
int[] xy = new int[2];
v.getLocationOnScreen(xy);
diff --git a/tests/AppLaunch/src/com/android/tests/applaunch/AppLaunch.java b/tests/AppLaunch/src/com/android/tests/applaunch/AppLaunch.java
index 9be97b505a3f..0ad30391d1a8 100644
--- a/tests/AppLaunch/src/com/android/tests/applaunch/AppLaunch.java
+++ b/tests/AppLaunch/src/com/android/tests/applaunch/AppLaunch.java
@@ -46,6 +46,7 @@ import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.OutputStreamWriter;
import java.util.ArrayList;
+import java.util.Arrays;
import java.util.HashMap;
import java.util.HashSet;
import java.util.LinkedHashMap;
@@ -72,6 +73,7 @@ public class AppLaunch extends InstrumentationTestCase {
private static final String KEY_REQUIRED_ACCOUNTS = "required_accounts";
private static final String KEY_APPS = "apps";
private static final String KEY_IORAP_TRIAL_LAUNCH = "iorap_trial_launch";
+ private static final String KEY_IORAP_COMPILER_FILTERS = "iorap_compiler_filters";
private static final String KEY_TRIAL_LAUNCH = "trial_launch";
private static final String KEY_LAUNCH_ITERATIONS = "launch_iterations";
private static final String KEY_LAUNCH_ORDER = "launch_order";
@@ -153,6 +155,7 @@ public class AppLaunch extends InstrumentationTestCase {
private BufferedWriter mBufferedWriter = null;
private boolean mSimplePerfAppOnly = false;
private String[] mCompilerFilters = null;
+ private List<String> mIorapCompilerFilters = null;
private String mLastAppName = "";
private boolean mCycleCleanUp = false;
private boolean mTraceAll = false;
@@ -618,6 +621,24 @@ public class AppLaunch extends InstrumentationTestCase {
return reason;
}
+ private boolean shouldIncludeIorap(String compilerFilter) {
+ if (!mIorapTrialLaunch) {
+ return false;
+ }
+
+ // No iorap compiler filters specified: treat all compiler filters as ok.
+ if (mIorapCompilerFilters == null) {
+ return true;
+ }
+
+ // iorap compiler filters specified: the compilerFilter must be in the whitelist.
+ if (mIorapCompilerFilters.indexOf(compilerFilter) != -1) {
+ return true;
+ }
+
+ return false;
+ }
+
/**
* If launch order is "cyclic" then apps will be launched one after the
* other for each iteration count.
@@ -632,7 +653,7 @@ public class AppLaunch extends InstrumentationTestCase {
mLaunchOrderList.add(new LaunchOrder(app, compilerFilter, TRIAL_LAUNCH, /*iorapEnabled*/false));
}
}
- if (mIorapTrialLaunch) {
+ if (shouldIncludeIorap(compilerFilter)) {
for (int launchCount = 0; launchCount < IORAP_TRIAL_LAUNCH_ITERATIONS; ++launchCount) {
for (String app : mNameToResultKey.keySet()) {
String reason = makeReasonForIorapTrialLaunch(launchCount);
@@ -646,14 +667,16 @@ public class AppLaunch extends InstrumentationTestCase {
for (int launchCount = 0; launchCount < mLaunchIterations; launchCount++) {
for (String app : mNameToResultKey.keySet()) {
mLaunchOrderList.add(new LaunchOrder(app, compilerFilter,
- String.format(LAUNCH_ITERATION, launchCount), mIorapTrialLaunch));
+ String.format(LAUNCH_ITERATION, launchCount),
+ shouldIncludeIorap(compilerFilter)));
}
}
if (mTraceDirectoryStr != null && !mTraceDirectoryStr.isEmpty()) {
for (int traceCount = 0; traceCount < mTraceLaunchCount; traceCount++) {
for (String app : mNameToResultKey.keySet()) {
mLaunchOrderList.add(new LaunchOrder(app, compilerFilter,
- String.format(TRACE_ITERATION, traceCount), mIorapTrialLaunch));
+ String.format(TRACE_ITERATION, traceCount),
+ shouldIncludeIorap(compilerFilter)));
}
}
}
@@ -664,7 +687,7 @@ public class AppLaunch extends InstrumentationTestCase {
if (mTrialLaunch) {
mLaunchOrderList.add(new LaunchOrder(app, compilerFilter, TRIAL_LAUNCH, /*iorapEnabled*/false));
}
- if (mIorapTrialLaunch) {
+ if (shouldIncludeIorap(compilerFilter)) {
for (int launchCount = 0; launchCount < IORAP_TRIAL_LAUNCH_ITERATIONS; ++launchCount) {
String reason = makeReasonForIorapTrialLaunch(launchCount);
mLaunchOrderList.add(
@@ -675,12 +698,14 @@ public class AppLaunch extends InstrumentationTestCase {
}
for (int launchCount = 0; launchCount < mLaunchIterations; launchCount++) {
mLaunchOrderList.add(new LaunchOrder(app, compilerFilter,
- String.format(LAUNCH_ITERATION, launchCount), mIorapTrialLaunch));
+ String.format(LAUNCH_ITERATION, launchCount),
+ shouldIncludeIorap(compilerFilter)));
}
if (mTraceDirectoryStr != null && !mTraceDirectoryStr.isEmpty()) {
for (int traceCount = 0; traceCount < mTraceLaunchCount; traceCount++) {
mLaunchOrderList.add(new LaunchOrder(app, compilerFilter,
- String.format(TRACE_ITERATION, traceCount), mIorapTrialLaunch));
+ String.format(TRACE_ITERATION, traceCount),
+ shouldIncludeIorap(compilerFilter)));
}
}
}
@@ -767,7 +792,7 @@ public class AppLaunch extends InstrumentationTestCase {
.executeShellCommand(String.format("setprop iorapd.readahead.enable %b", enable));
getInstrumentation().getUiAutomation()
.executeShellCommand("start iorapd");
- sleep(2000); // give enough time for iorapd to start back up.
+ sleep(3000); // give enough time for iorapd to start back up.
if (enable) {
mIorapStatus = IorapStatus.ENABLED;
@@ -822,6 +847,13 @@ public class AppLaunch extends InstrumentationTestCase {
mCompilerFilters = new String[1];
}
+ String iorapCompilerFilterList = args.getString(KEY_IORAP_COMPILER_FILTERS);
+ if (iorapCompilerFilterList != null) {
+ // Passing in iorap compiler filters implies an iorap trial launch.
+ mIorapTrialLaunch = true;
+ mIorapCompilerFilters = Arrays.asList(iorapCompilerFilterList.split("\\|"));
+ }
+
// Pre-populate the results map to avoid null checks.
for (String app : mNameToLaunchTime.keySet()) {
HashMap<String, List<AppLaunchResult>> map = new HashMap<>();
diff --git a/tests/BlobStoreTestUtils/src/com/android/utils/blob/DummyBlobData.java b/tests/BlobStoreTestUtils/src/com/android/utils/blob/DummyBlobData.java
index 42908bef6178..35a6c26ec73f 100644
--- a/tests/BlobStoreTestUtils/src/com/android/utils/blob/DummyBlobData.java
+++ b/tests/BlobStoreTestUtils/src/com/android/utils/blob/DummyBlobData.java
@@ -167,7 +167,7 @@ public class DummyBlobData {
final byte[] actualBytes = new byte[lengthBytes];
try (FileInputStream in = new ParcelFileDescriptor.AutoCloseInputStream(
- session.openWrite(0L, 0L))) {
+ session.openRead())) {
read(in, actualBytes, offsetBytes, lengthBytes);
}
@@ -190,7 +190,7 @@ public class DummyBlobData {
long offsetBytes, long lengthBytes) throws Exception {
final byte[] actualDigest;
try (FileInputStream in = new ParcelFileDescriptor.AutoCloseInputStream(
- session.openWrite(0L, 0L))) {
+ session.openRead())) {
actualDigest = createSha256Digest(in, offsetBytes, lengthBytes);
}
diff --git a/tests/MirrorSurfaceTest/src/com/google/android/test/mirrorsurface/MirrorSurfaceActivity.java b/tests/MirrorSurfaceTest/src/com/google/android/test/mirrorsurface/MirrorSurfaceActivity.java
index e255ce234c65..31532a226800 100644
--- a/tests/MirrorSurfaceTest/src/com/google/android/test/mirrorsurface/MirrorSurfaceActivity.java
+++ b/tests/MirrorSurfaceTest/src/com/google/android/test/mirrorsurface/MirrorSurfaceActivity.java
@@ -27,7 +27,6 @@ import android.graphics.Rect;
import android.os.Bundle;
import android.os.Handler;
import android.os.RemoteException;
-import android.util.Size;
import android.view.Gravity;
import android.view.IWindowManager;
import android.view.MotionEvent;
@@ -90,8 +89,8 @@ public class MirrorSurfaceActivity extends Activity implements View.OnClickListe
.getSystemService(WindowManager.class);
mIWm = WindowManagerGlobal.getWindowManagerService();
- Size windowSize = mWm.getCurrentWindowMetrics().getSize();
- mWindowBounds.set(0, 0, windowSize.getWidth(), windowSize.getHeight());
+ Rect windowBounds = mWm.getCurrentWindowMetrics().getBounds();
+ mWindowBounds.set(0, 0, windowBounds.width(), windowBounds.height());
mScaleText = findViewById(R.id.scale);
mDisplayFrameText = findViewById(R.id.displayFrame);
diff --git a/wifi/java/android/net/wifi/SoftApConfiguration.java b/wifi/java/android/net/wifi/SoftApConfiguration.java
index a269e17a8cff..457e0db9dc54 100644
--- a/wifi/java/android/net/wifi/SoftApConfiguration.java
+++ b/wifi/java/android/net/wifi/SoftApConfiguration.java
@@ -516,9 +516,6 @@ public final class SoftApConfiguration implements Parcelable {
public WifiConfiguration toWifiConfiguration() {
WifiConfiguration wifiConfig = new WifiConfiguration();
wifiConfig.SSID = mSsid;
- if (mBssid != null) {
- wifiConfig.BSSID = mBssid.toString();
- }
wifiConfig.preSharedKey = mPassphrase;
wifiConfig.hiddenSSID = mHiddenSsid;
wifiConfig.apChannel = mChannel;
@@ -662,8 +659,6 @@ public final class SoftApConfiguration implements Parcelable {
/**
* Specifies a BSSID for the AP.
* <p>
- * Only supported when configuring a local-only hotspot.
- * <p>
* <li>If not set, defaults to null.</li>
* @param bssid BSSID, or null to have the BSSID chosen by the framework. The caller is
* responsible for avoiding collisions.