summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--apex/jobscheduler/service/java/com/android/server/DeviceIdleController.java7
-rw-r--r--apex/media/framework/java/android/media/MediaController2.java1
-rw-r--r--api/current.txt75
-rw-r--r--api/module-lib-current.txt2
-rw-r--r--api/system-current.txt67
-rw-r--r--api/test-current.txt39
-rw-r--r--cmds/statsd/src/atoms.proto26
-rw-r--r--core/java/android/app/ActivityOptions.java88
-rw-r--r--core/java/android/app/ApplicationPackageManager.java11
-rw-r--r--core/java/android/content/pm/ApkChecksum.aidl (renamed from core/java/android/content/pm/FileChecksum.aidl)2
-rw-r--r--core/java/android/content/pm/ApkChecksum.java (renamed from core/java/android/content/pm/FileChecksum.java)123
-rw-r--r--core/java/android/content/pm/Checksum.aidl20
-rw-r--r--core/java/android/content/pm/Checksum.java228
-rw-r--r--core/java/android/content/pm/IPackageInstallerSession.aidl3
-rw-r--r--core/java/android/content/pm/PackageInstaller.java25
-rw-r--r--core/java/android/content/pm/PackageManager.java72
-rw-r--r--core/java/android/content/pm/UserInfo.java10
-rw-r--r--core/java/android/util/FeatureFlagUtils.java1
-rw-r--r--core/java/android/util/apk/ApkSignatureSchemeV3Verifier.java168
-rw-r--r--core/java/android/util/apk/ApkSigningBlockUtils.java127
-rw-r--r--core/java/android/util/apk/SourceStampVerificationResult.java25
-rw-r--r--core/java/android/util/apk/SourceStampVerifier.java104
-rw-r--r--core/java/android/view/ViewDebug.java2
-rw-r--r--core/java/com/android/internal/config/sysui/SystemUiDeviceConfigFlags.java5
-rw-r--r--core/java/com/android/internal/util/Preconditions.java2
-rw-r--r--core/res/res/values-gl/strings.xml2
-rw-r--r--core/res/res/values-sv/strings.xml2
-rw-r--r--core/res/res/values-sw/strings.xml2
-rw-r--r--core/tests/coretests/assets/SourceStampVerifierTest/stamp-lineage-invalid.apkbin0 -> 16854 bytes
-rw-r--r--core/tests/coretests/assets/SourceStampVerifierTest/stamp-lineage-valid.apkbin0 -> 16854 bytes
-rw-r--r--core/tests/coretests/src/android/util/apk/SourceStampVerifierTest.java33
-rw-r--r--graphics/java/android/graphics/ImageDecoder.java6
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/FullscreenTaskListener.java6
-rw-r--r--libs/hwui/jni/ImageDecoder.cpp13
-rw-r--r--location/java/android/location/ILocationManager.aidl8
-rw-r--r--location/java/android/location/LocationManager.java424
-rw-r--r--location/java/android/location/LocationRequest.java1251
-rw-r--r--location/lib/java/com/android/location/provider/LocationRequestUnbundled.java18
-rw-r--r--media/java/android/media/MicrophoneInfo.java7
-rw-r--r--media/java/android/media/browse/MediaBrowser.java2
-rw-r--r--media/java/android/media/session/MediaSessionManager.java7
-rw-r--r--non-updatable-api/current.txt75
-rw-r--r--non-updatable-api/module-lib-current.txt2
-rw-r--r--non-updatable-api/system-current.txt67
-rw-r--r--packages/FusedLocation/src/com/android/location/fused/FusedLocationProvider.java16
-rw-r--r--packages/FusedLocation/test/src/com/android/location/fused/tests/FusedLocationServiceTest.java9
-rw-r--r--packages/InputDevices/res/values-af/strings.xml2
-rw-r--r--packages/InputDevices/res/values-am/strings.xml2
-rw-r--r--packages/InputDevices/res/values-ar/strings.xml2
-rw-r--r--packages/InputDevices/res/values-as/strings.xml2
-rw-r--r--packages/InputDevices/res/values-az/strings.xml2
-rw-r--r--packages/InputDevices/res/values-b+sr+Latn/strings.xml2
-rw-r--r--packages/InputDevices/res/values-be/strings.xml2
-rw-r--r--packages/InputDevices/res/values-bg/strings.xml2
-rw-r--r--packages/InputDevices/res/values-bn/strings.xml2
-rw-r--r--packages/InputDevices/res/values-bs/strings.xml2
-rw-r--r--packages/InputDevices/res/values-ca/strings.xml2
-rw-r--r--packages/InputDevices/res/values-cs/strings.xml2
-rw-r--r--packages/InputDevices/res/values-da/strings.xml2
-rw-r--r--packages/InputDevices/res/values-de/strings.xml2
-rw-r--r--packages/InputDevices/res/values-el/strings.xml2
-rw-r--r--packages/InputDevices/res/values-en-rAU/strings.xml2
-rw-r--r--packages/InputDevices/res/values-en-rCA/strings.xml2
-rw-r--r--packages/InputDevices/res/values-en-rGB/strings.xml2
-rw-r--r--packages/InputDevices/res/values-en-rIN/strings.xml2
-rw-r--r--packages/InputDevices/res/values-en-rXC/strings.xml2
-rw-r--r--packages/InputDevices/res/values-es-rUS/strings.xml2
-rw-r--r--packages/InputDevices/res/values-es/strings.xml2
-rw-r--r--packages/InputDevices/res/values-et/strings.xml2
-rw-r--r--packages/InputDevices/res/values-eu/strings.xml2
-rw-r--r--packages/InputDevices/res/values-fa/strings.xml2
-rw-r--r--packages/InputDevices/res/values-fi/strings.xml2
-rw-r--r--packages/InputDevices/res/values-fr-rCA/strings.xml2
-rw-r--r--packages/InputDevices/res/values-fr/strings.xml2
-rw-r--r--packages/InputDevices/res/values-gl/strings.xml2
-rw-r--r--packages/InputDevices/res/values-gu/strings.xml2
-rw-r--r--packages/InputDevices/res/values-hi/strings.xml2
-rw-r--r--packages/InputDevices/res/values-hr/strings.xml2
-rw-r--r--packages/InputDevices/res/values-hu/strings.xml2
-rw-r--r--packages/InputDevices/res/values-hy/strings.xml2
-rw-r--r--packages/InputDevices/res/values-in/strings.xml2
-rw-r--r--packages/InputDevices/res/values-is/strings.xml2
-rw-r--r--packages/InputDevices/res/values-it/strings.xml2
-rw-r--r--packages/InputDevices/res/values-iw/strings.xml2
-rw-r--r--packages/InputDevices/res/values-ja/strings.xml2
-rw-r--r--packages/InputDevices/res/values-ka/strings.xml2
-rw-r--r--packages/InputDevices/res/values-kk/strings.xml2
-rw-r--r--packages/InputDevices/res/values-km/strings.xml2
-rw-r--r--packages/InputDevices/res/values-kn/strings.xml2
-rw-r--r--packages/InputDevices/res/values-ko/strings.xml2
-rw-r--r--packages/InputDevices/res/values-ky/strings.xml2
-rw-r--r--packages/InputDevices/res/values-lo/strings.xml2
-rw-r--r--packages/InputDevices/res/values-lt/strings.xml2
-rw-r--r--packages/InputDevices/res/values-lv/strings.xml2
-rw-r--r--packages/InputDevices/res/values-mk/strings.xml2
-rw-r--r--packages/InputDevices/res/values-ml/strings.xml2
-rw-r--r--packages/InputDevices/res/values-mn/strings.xml2
-rw-r--r--packages/InputDevices/res/values-mr/strings.xml2
-rw-r--r--packages/InputDevices/res/values-ms/strings.xml2
-rw-r--r--packages/InputDevices/res/values-my/strings.xml2
-rw-r--r--packages/InputDevices/res/values-nb/strings.xml2
-rw-r--r--packages/InputDevices/res/values-ne/strings.xml2
-rw-r--r--packages/InputDevices/res/values-nl/strings.xml2
-rw-r--r--packages/InputDevices/res/values-or/strings.xml2
-rw-r--r--packages/InputDevices/res/values-pa/strings.xml2
-rw-r--r--packages/InputDevices/res/values-pl/strings.xml2
-rw-r--r--packages/InputDevices/res/values-pt-rBR/strings.xml2
-rw-r--r--packages/InputDevices/res/values-pt-rPT/strings.xml2
-rw-r--r--packages/InputDevices/res/values-pt/strings.xml2
-rw-r--r--packages/InputDevices/res/values-ro/strings.xml2
-rw-r--r--packages/InputDevices/res/values-ru/strings.xml2
-rw-r--r--packages/InputDevices/res/values-si/strings.xml2
-rw-r--r--packages/InputDevices/res/values-sk/strings.xml2
-rw-r--r--packages/InputDevices/res/values-sl/strings.xml2
-rw-r--r--packages/InputDevices/res/values-sq/strings.xml2
-rw-r--r--packages/InputDevices/res/values-sr/strings.xml2
-rw-r--r--packages/InputDevices/res/values-sv/strings.xml2
-rw-r--r--packages/InputDevices/res/values-sw/strings.xml2
-rw-r--r--packages/InputDevices/res/values-ta/strings.xml2
-rw-r--r--packages/InputDevices/res/values-te/strings.xml2
-rw-r--r--packages/InputDevices/res/values-th/strings.xml2
-rw-r--r--packages/InputDevices/res/values-tl/strings.xml2
-rw-r--r--packages/InputDevices/res/values-tr/strings.xml2
-rw-r--r--packages/InputDevices/res/values-uk/strings.xml2
-rw-r--r--packages/InputDevices/res/values-ur/strings.xml2
-rw-r--r--packages/InputDevices/res/values-uz/strings.xml2
-rw-r--r--packages/InputDevices/res/values-vi/strings.xml2
-rw-r--r--packages/InputDevices/res/values-zh-rCN/strings.xml2
-rw-r--r--packages/InputDevices/res/values-zh-rHK/strings.xml2
-rw-r--r--packages/InputDevices/res/values-zh-rTW/strings.xml2
-rw-r--r--packages/InputDevices/res/values-zu/strings.xml2
-rw-r--r--packages/PrintSpooler/src/com/android/printspooler/ui/FusedPrintersProvider.java11
-rw-r--r--packages/SettingsLib/res/values-ar/strings.xml6
-rw-r--r--packages/SettingsLib/src/com/android/settingslib/wifi/WifiEntryPreference.java7
-rw-r--r--packages/SettingsLib/tests/robotests/src/com/android/settingslib/wifi/WifiEntryPreferenceTest.java40
-rw-r--r--packages/SystemUI/res/values-af/strings.xml2
-rw-r--r--packages/SystemUI/res/values-am/strings.xml2
-rw-r--r--packages/SystemUI/res/values-ar/strings.xml2
-rw-r--r--packages/SystemUI/res/values-as/strings.xml2
-rw-r--r--packages/SystemUI/res/values-az/strings.xml2
-rw-r--r--packages/SystemUI/res/values-b+sr+Latn/strings.xml2
-rw-r--r--packages/SystemUI/res/values-be/strings.xml2
-rw-r--r--packages/SystemUI/res/values-bg/strings.xml2
-rw-r--r--packages/SystemUI/res/values-bn/strings.xml2
-rw-r--r--packages/SystemUI/res/values-bs/strings.xml2
-rw-r--r--packages/SystemUI/res/values-ca/strings.xml2
-rw-r--r--packages/SystemUI/res/values-cs/strings.xml2
-rw-r--r--packages/SystemUI/res/values-da/strings.xml2
-rw-r--r--packages/SystemUI/res/values-de/strings.xml2
-rw-r--r--packages/SystemUI/res/values-el/strings.xml2
-rw-r--r--packages/SystemUI/res/values-en-rAU/strings.xml2
-rw-r--r--packages/SystemUI/res/values-en-rCA/strings.xml2
-rw-r--r--packages/SystemUI/res/values-en-rGB/strings.xml2
-rw-r--r--packages/SystemUI/res/values-en-rIN/strings.xml2
-rw-r--r--packages/SystemUI/res/values-en-rXC/strings.xml4
-rw-r--r--packages/SystemUI/res/values-es-rUS/strings.xml2
-rw-r--r--packages/SystemUI/res/values-es/strings.xml2
-rw-r--r--packages/SystemUI/res/values-et/strings.xml2
-rw-r--r--packages/SystemUI/res/values-eu/strings.xml2
-rw-r--r--packages/SystemUI/res/values-fa/strings.xml2
-rw-r--r--packages/SystemUI/res/values-fi/strings.xml2
-rw-r--r--packages/SystemUI/res/values-fr-rCA/strings.xml2
-rw-r--r--packages/SystemUI/res/values-fr/strings.xml2
-rw-r--r--packages/SystemUI/res/values-gl/strings.xml4
-rw-r--r--packages/SystemUI/res/values-gu/strings.xml2
-rw-r--r--packages/SystemUI/res/values-hi/strings.xml2
-rw-r--r--packages/SystemUI/res/values-hr/strings.xml2
-rw-r--r--packages/SystemUI/res/values-hu/strings.xml2
-rw-r--r--packages/SystemUI/res/values-hy/strings.xml2
-rw-r--r--packages/SystemUI/res/values-in/strings.xml2
-rw-r--r--packages/SystemUI/res/values-is/strings.xml2
-rw-r--r--packages/SystemUI/res/values-it/strings.xml2
-rw-r--r--packages/SystemUI/res/values-iw/strings.xml2
-rw-r--r--packages/SystemUI/res/values-ja/strings.xml2
-rw-r--r--packages/SystemUI/res/values-ka/strings.xml2
-rw-r--r--packages/SystemUI/res/values-kk/strings.xml2
-rw-r--r--packages/SystemUI/res/values-km/strings.xml2
-rw-r--r--packages/SystemUI/res/values-kn/strings.xml2
-rw-r--r--packages/SystemUI/res/values-ko/strings.xml2
-rw-r--r--packages/SystemUI/res/values-ky/strings.xml2
-rw-r--r--packages/SystemUI/res/values-lo/strings.xml2
-rw-r--r--packages/SystemUI/res/values-lt/strings.xml2
-rw-r--r--packages/SystemUI/res/values-lv/strings.xml2
-rw-r--r--packages/SystemUI/res/values-mk/strings.xml2
-rw-r--r--packages/SystemUI/res/values-ml/strings.xml2
-rw-r--r--packages/SystemUI/res/values-mn/strings.xml2
-rw-r--r--packages/SystemUI/res/values-mr/strings.xml2
-rw-r--r--packages/SystemUI/res/values-ms/strings.xml2
-rw-r--r--packages/SystemUI/res/values-my/strings.xml2
-rw-r--r--packages/SystemUI/res/values-nb/strings.xml2
-rw-r--r--packages/SystemUI/res/values-ne/strings.xml2
-rw-r--r--packages/SystemUI/res/values-nl/strings.xml2
-rw-r--r--packages/SystemUI/res/values-or/strings.xml2
-rw-r--r--packages/SystemUI/res/values-pa/strings.xml2
-rw-r--r--packages/SystemUI/res/values-pl/strings.xml2
-rw-r--r--packages/SystemUI/res/values-pt-rBR/strings.xml2
-rw-r--r--packages/SystemUI/res/values-pt-rPT/strings.xml2
-rw-r--r--packages/SystemUI/res/values-pt/strings.xml2
-rw-r--r--packages/SystemUI/res/values-ro/strings.xml2
-rw-r--r--packages/SystemUI/res/values-ru/strings.xml2
-rw-r--r--packages/SystemUI/res/values-si/strings.xml2
-rw-r--r--packages/SystemUI/res/values-sk/strings.xml2
-rw-r--r--packages/SystemUI/res/values-sl/strings.xml2
-rw-r--r--packages/SystemUI/res/values-sq/strings.xml2
-rw-r--r--packages/SystemUI/res/values-sr/strings.xml2
-rw-r--r--packages/SystemUI/res/values-sv/strings.xml2
-rw-r--r--packages/SystemUI/res/values-sw/strings.xml2
-rw-r--r--packages/SystemUI/res/values-ta/strings.xml2
-rw-r--r--packages/SystemUI/res/values-te/strings.xml2
-rw-r--r--packages/SystemUI/res/values-th/strings.xml2
-rw-r--r--packages/SystemUI/res/values-tl/strings.xml2
-rw-r--r--packages/SystemUI/res/values-tr/strings.xml2
-rw-r--r--packages/SystemUI/res/values-uk/strings.xml2
-rw-r--r--packages/SystemUI/res/values-ur/strings.xml2
-rw-r--r--packages/SystemUI/res/values-uz/strings.xml2
-rw-r--r--packages/SystemUI/res/values-vi/strings.xml2
-rw-r--r--packages/SystemUI/res/values-zh-rCN/strings.xml2
-rw-r--r--packages/SystemUI/res/values-zh-rHK/strings.xml2
-rw-r--r--packages/SystemUI/res/values-zh-rTW/strings.xml2
-rw-r--r--packages/SystemUI/res/values-zu/strings.xml2
-rw-r--r--packages/SystemUI/res/values/strings.xml2
-rw-r--r--packages/SystemUI/src/com/android/systemui/ScreenDecorations.java7
-rw-r--r--packages/SystemUI/src/com/android/systemui/bubbles/Bubble.java16
-rw-r--r--packages/SystemUI/src/com/android/systemui/bubbles/BubbleController.java2
-rw-r--r--packages/SystemUI/src/com/android/systemui/bubbles/BubbleOverflow.kt9
-rw-r--r--packages/SystemUI/src/com/android/systemui/bubbles/BubbleStackView.java16
-rw-r--r--packages/SystemUI/src/com/android/systemui/pip/phone/PipMotionHelper.java31
-rw-r--r--packages/SystemUI/src/com/android/systemui/pip/phone/PipTouchHandler.java42
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationConversationInfo.java13
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBar.java7
-rw-r--r--packages/SystemUI/src/com/android/systemui/volume/VolumeDialogControllerImpl.java3
-rw-r--r--packages/SystemUI/src/com/android/systemui/wmshell/WMShell.java13
-rw-r--r--services/accessibility/java/com/android/server/accessibility/magnification/WindowMagnificationManager.java16
-rw-r--r--services/core/java/com/android/server/ConnectivityService.java21
-rw-r--r--services/core/java/com/android/server/appop/AppOpsService.java15
-rw-r--r--services/core/java/com/android/server/hdmi/Constants.java24
-rw-r--r--services/core/java/com/android/server/hdmi/HdmiUtils.java56
-rw-r--r--services/core/java/com/android/server/location/LocationManagerService.java64
-rw-r--r--services/core/java/com/android/server/location/LocationProviderManager.java68
-rw-r--r--services/core/java/com/android/server/location/PassiveLocationProviderManager.java21
-rw-r--r--services/core/java/com/android/server/location/geofence/GeofenceManager.java24
-rw-r--r--services/core/java/com/android/server/location/gnss/GnssLocationProvider.java31
-rw-r--r--services/core/java/com/android/server/location/gnss/GnssMeasurementsProvider.java20
-rw-r--r--services/core/java/com/android/server/location/gnss/GnssPsdsDownloader.java17
-rw-r--r--services/core/java/com/android/server/location/gnss/GnssStatusProvider.java19
-rw-r--r--services/core/java/com/android/server/location/listeners/ListenerMultiplexer.java2
-rw-r--r--services/core/java/com/android/server/location/util/LocationUsageLogger.java12
-rw-r--r--services/core/java/com/android/server/media/MediaSessionStack.java2
-rw-r--r--services/core/java/com/android/server/net/LockdownVpnTracker.java22
-rw-r--r--services/core/java/com/android/server/pm/ApkChecksums.java250
-rw-r--r--services/core/java/com/android/server/pm/PackageInstallerService.java6
-rw-r--r--services/core/java/com/android/server/pm/PackageInstallerSession.java278
-rw-r--r--services/core/java/com/android/server/pm/PackageManagerService.java9
-rw-r--r--services/core/java/com/android/server/pm/Settings.java4
-rw-r--r--services/core/java/com/android/server/pm/UserManagerService.java15
-rw-r--r--services/core/java/com/android/server/timezonedetector/TimeZoneDetectorCallbackImpl.java13
-rw-r--r--services/core/java/com/android/server/wm/ActivityMetricsLogger.java46
-rw-r--r--services/core/java/com/android/server/wm/ActivityStackSupervisor.java2
-rw-r--r--services/core/java/com/android/server/wm/ActivityStarter.java4
-rw-r--r--services/core/java/com/android/server/wm/InputMonitor.java3
-rw-r--r--services/core/java/com/android/server/wm/RecentsAnimation.java2
-rw-r--r--services/core/java/com/android/server/wm/Task.java31
-rw-r--r--services/core/java/com/android/server/wm/TaskTapPointerEventListener.java12
-rw-r--r--services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java1495
-rw-r--r--services/tests/mockingservicestests/src/com/android/server/am/ApplicationExitInfoTest.java2
-rw-r--r--services/tests/mockingservicestests/src/com/android/server/location/LocationProviderManagerTest.java99
-rw-r--r--services/tests/mockingservicestests/src/com/android/server/location/listeners/ListenerMultiplexerTest.java5
-rw-r--r--services/tests/servicestests/src/com/android/server/devicepolicy/DevicePolicyManagerTest.java80
-rw-r--r--services/tests/servicestests/src/com/android/server/hdmi/HdmiUtilsTest.java90
-rw-r--r--services/tests/servicestests/src/com/android/server/pm/PackageInstallerSessionTest.java1
-rw-r--r--services/tests/servicestests/src/com/android/server/pm/UserManagerServiceUserInfoTest.java32
-rw-r--r--services/tests/wmtests/src/com/android/server/wm/ActivityMetricsLaunchObserverTests.java17
-rwxr-xr-xtelephony/java/android/telephony/CarrierConfigManager.java5
-rw-r--r--wifi/java/android/net/wifi/WifiScanner.java2
-rw-r--r--wifi/java/android/net/wifi/nl80211/NativeScanResult.java4
275 files changed, 4114 insertions, 2579 deletions
diff --git a/apex/jobscheduler/service/java/com/android/server/DeviceIdleController.java b/apex/jobscheduler/service/java/com/android/server/DeviceIdleController.java
index d8386b5f1153..59915e145c49 100644
--- a/apex/jobscheduler/service/java/com/android/server/DeviceIdleController.java
+++ b/apex/jobscheduler/service/java/com/android/server/DeviceIdleController.java
@@ -2178,11 +2178,10 @@ public class DeviceIdleController extends SystemService
if (getContext().getResources().getBoolean(
com.android.internal.R.bool.config_autoPowerModePrefetchLocation)) {
- mLocationRequest = LocationRequest.create()
+ mLocationRequest = new LocationRequest.Builder(/*intervalMillis=*/ 0)
.setQuality(LocationRequest.ACCURACY_FINE)
- .setInterval(0)
- .setFastestInterval(0)
- .setNumUpdates(1);
+ .setMaxUpdates(1)
+ .build();
}
mConstraintController = mInjector.getConstraintController(
diff --git a/apex/media/framework/java/android/media/MediaController2.java b/apex/media/framework/java/android/media/MediaController2.java
index d059c670ccb6..159e8e551d11 100644
--- a/apex/media/framework/java/android/media/MediaController2.java
+++ b/apex/media/framework/java/android/media/MediaController2.java
@@ -594,7 +594,6 @@ public class MediaController2 implements AutoCloseable {
if (DEBUG) {
Log.d(TAG, "onServiceConnected " + name + " " + this);
}
- // Sanity check
if (!mSessionToken.getPackageName().equals(name.getPackageName())) {
Log.wtf(TAG, "Expected connection to " + mSessionToken.getPackageName()
+ " but is connected to " + name);
diff --git a/api/current.txt b/api/current.txt
index 723ffec5916b..afd93c363e60 100644
--- a/api/current.txt
+++ b/api/current.txt
@@ -11447,6 +11447,16 @@ package android.content.pm {
field public final float widthFraction;
}
+ public final class ApkChecksum implements android.os.Parcelable {
+ method public int describeContents();
+ method public int getKind();
+ method @Nullable public java.security.cert.Certificate getSourceCertificate() throws java.security.cert.CertificateException;
+ method @Nullable public String getSplitName();
+ method @NonNull public byte[] getValue();
+ method public void writeToParcel(@NonNull android.os.Parcel, int);
+ field @NonNull public static final android.os.Parcelable.Creator<android.content.pm.ApkChecksum> CREATOR;
+ }
+
public class ApplicationInfo extends android.content.pm.PackageItemInfo implements android.os.Parcelable {
ctor public ApplicationInfo();
ctor public ApplicationInfo(android.content.pm.ApplicationInfo);
@@ -11548,6 +11558,21 @@ package android.content.pm {
field @NonNull public static final android.os.Parcelable.Creator<android.content.pm.ChangedPackages> CREATOR;
}
+ public final class Checksum implements android.os.Parcelable {
+ method public int describeContents();
+ method public int getKind();
+ method @NonNull public byte[] getValue();
+ method public void writeToParcel(@NonNull android.os.Parcel, int);
+ field @NonNull public static final android.os.Parcelable.Creator<android.content.pm.Checksum> CREATOR;
+ field public static final int PARTIAL_MERKLE_ROOT_1M_SHA256 = 32; // 0x20
+ field public static final int PARTIAL_MERKLE_ROOT_1M_SHA512 = 64; // 0x40
+ field public static final int WHOLE_MD5 = 2; // 0x2
+ field public static final int WHOLE_MERKLE_ROOT_4K_SHA256 = 1; // 0x1
+ field public static final int WHOLE_SHA1 = 4; // 0x4
+ field public static final int WHOLE_SHA256 = 8; // 0x8
+ field public static final int WHOLE_SHA512 = 16; // 0x10
+ }
+
public class ComponentInfo extends android.content.pm.PackageItemInfo {
ctor public ComponentInfo();
ctor public ComponentInfo(android.content.pm.ComponentInfo);
@@ -11619,16 +11644,6 @@ package android.content.pm {
field public int version;
}
- public final class FileChecksum implements android.os.Parcelable {
- method public int describeContents();
- method public int getKind();
- method @Nullable public java.security.cert.Certificate getSourceCertificate() throws java.security.cert.CertificateException;
- method @Nullable public String getSplitName();
- method @NonNull public byte[] getValue();
- method public void writeToParcel(@NonNull android.os.Parcel, int);
- field @NonNull public static final android.os.Parcelable.Creator<android.content.pm.FileChecksum> CREATOR;
- }
-
public final class InstallSourceInfo implements android.os.Parcelable {
method public int describeContents();
method @Nullable public String getInitiatingPackageName();
@@ -11849,6 +11864,7 @@ package android.content.pm {
public static class PackageInstaller.Session implements java.io.Closeable {
method public void abandon();
+ method public void addChecksums(@NonNull String, @NonNull java.util.List<android.content.pm.Checksum>) throws java.io.IOException;
method public void addChildSessionId(int);
method public void close();
method public void commit(@NonNull android.content.IntentSender);
@@ -12250,8 +12266,6 @@ package android.content.pm {
field public static final int MATCH_SYSTEM_ONLY = 1048576; // 0x100000
field public static final int MATCH_UNINSTALLED_PACKAGES = 8192; // 0x2000
field public static final long MAXIMUM_VERIFICATION_TIMEOUT = 3600000L; // 0x36ee80L
- field public static final int PARTIAL_MERKLE_ROOT_1M_SHA256 = 32; // 0x20
- field public static final int PARTIAL_MERKLE_ROOT_1M_SHA512 = 64; // 0x40
field public static final int PERMISSION_DENIED = -1; // 0xffffffff
field public static final int PERMISSION_GRANTED = 0; // 0x0
field public static final int SIGNATURE_FIRST_NOT_SIGNED = -1; // 0xffffffff
@@ -12266,11 +12280,6 @@ package android.content.pm {
field public static final int VERIFICATION_ALLOW = 1; // 0x1
field public static final int VERIFICATION_REJECT = -1; // 0xffffffff
field public static final int VERSION_CODE_HIGHEST = -1; // 0xffffffff
- field public static final int WHOLE_MD5 = 2; // 0x2
- field public static final int WHOLE_MERKLE_ROOT_4K_SHA256 = 1; // 0x1
- field public static final int WHOLE_SHA1 = 4; // 0x4
- field public static final int WHOLE_SHA256 = 8; // 0x8
- field public static final int WHOLE_SHA512 = 16; // 0x10
}
public static class PackageManager.NameNotFoundException extends android.util.AndroidException {
@@ -23916,6 +23925,7 @@ package android.location {
method @NonNull public java.util.List<java.lang.String> getAllProviders();
method @Nullable public String getBestProvider(@NonNull android.location.Criteria, boolean);
method @RequiresPermission(anyOf={android.Manifest.permission.ACCESS_COARSE_LOCATION, android.Manifest.permission.ACCESS_FINE_LOCATION}) public void getCurrentLocation(@NonNull String, @Nullable android.os.CancellationSignal, @NonNull java.util.concurrent.Executor, @NonNull java.util.function.Consumer<android.location.Location>);
+ method @RequiresPermission(anyOf={android.Manifest.permission.ACCESS_COARSE_LOCATION, android.Manifest.permission.ACCESS_FINE_LOCATION}) public void getCurrentLocation(@NonNull String, @NonNull android.location.LocationRequest, @Nullable android.os.CancellationSignal, @NonNull java.util.concurrent.Executor, @NonNull java.util.function.Consumer<android.location.Location>);
method @NonNull public android.location.GnssCapabilities getGnssCapabilities();
method @Nullable public String getGnssHardwareModelName();
method public int getGnssYearOfHardware();
@@ -23950,6 +23960,8 @@ package android.location {
method @RequiresPermission(anyOf={android.Manifest.permission.ACCESS_COARSE_LOCATION, android.Manifest.permission.ACCESS_FINE_LOCATION}) public void requestLocationUpdates(long, float, @NonNull android.location.Criteria, @NonNull java.util.concurrent.Executor, @NonNull android.location.LocationListener);
method @RequiresPermission(anyOf={android.Manifest.permission.ACCESS_COARSE_LOCATION, android.Manifest.permission.ACCESS_FINE_LOCATION}) public void requestLocationUpdates(@NonNull String, long, float, @NonNull android.app.PendingIntent);
method @RequiresPermission(anyOf={android.Manifest.permission.ACCESS_COARSE_LOCATION, android.Manifest.permission.ACCESS_FINE_LOCATION}) public void requestLocationUpdates(long, float, @NonNull android.location.Criteria, @NonNull android.app.PendingIntent);
+ method @RequiresPermission(anyOf={android.Manifest.permission.ACCESS_COARSE_LOCATION, android.Manifest.permission.ACCESS_FINE_LOCATION}) public void requestLocationUpdates(@NonNull String, @NonNull android.location.LocationRequest, @NonNull java.util.concurrent.Executor, @NonNull android.location.LocationListener);
+ method @RequiresPermission(anyOf={android.Manifest.permission.ACCESS_COARSE_LOCATION, android.Manifest.permission.ACCESS_FINE_LOCATION}) public void requestLocationUpdates(@NonNull String, @NonNull android.location.LocationRequest, @NonNull android.app.PendingIntent);
method @Deprecated @RequiresPermission(anyOf={android.Manifest.permission.ACCESS_COARSE_LOCATION, android.Manifest.permission.ACCESS_FINE_LOCATION}) public void requestSingleUpdate(@NonNull String, @NonNull android.location.LocationListener, @Nullable android.os.Looper);
method @Deprecated @RequiresPermission(anyOf={android.Manifest.permission.ACCESS_COARSE_LOCATION, android.Manifest.permission.ACCESS_FINE_LOCATION}) public void requestSingleUpdate(@NonNull android.location.Criteria, @NonNull android.location.LocationListener, @Nullable android.os.Looper);
method @Deprecated @RequiresPermission(anyOf={android.Manifest.permission.ACCESS_COARSE_LOCATION, android.Manifest.permission.ACCESS_FINE_LOCATION}) public void requestSingleUpdate(@NonNull String, @NonNull android.app.PendingIntent);
@@ -23993,6 +24005,30 @@ package android.location {
field @Deprecated public static final int TEMPORARILY_UNAVAILABLE = 1; // 0x1
}
+ public final class LocationRequest implements android.os.Parcelable {
+ method public int describeContents();
+ method public long getDurationMillis();
+ method public long getIntervalMillis();
+ method public int getMaxUpdates();
+ method public float getMinUpdateDistanceMeters();
+ method public long getMinUpdateIntervalMillis();
+ method public void writeToParcel(@NonNull android.os.Parcel, int);
+ field @NonNull public static final android.os.Parcelable.Creator<android.location.LocationRequest> CREATOR;
+ field public static final long PASSIVE_INTERVAL = 9223372036854775807L; // 0x7fffffffffffffffL
+ }
+
+ public static final class LocationRequest.Builder {
+ ctor public LocationRequest.Builder(long);
+ ctor public LocationRequest.Builder(@NonNull android.location.LocationRequest);
+ method @NonNull public android.location.LocationRequest build();
+ method @NonNull public android.location.LocationRequest.Builder clearMinUpdateIntervalMillis();
+ method @NonNull public android.location.LocationRequest.Builder setDurationMillis(@IntRange(from=1) long);
+ method @NonNull public android.location.LocationRequest.Builder setIntervalMillis(@IntRange(from=0) long);
+ method @NonNull public android.location.LocationRequest.Builder setMaxUpdates(@IntRange(from=1, to=java.lang.Integer.MAX_VALUE) int);
+ method @NonNull public android.location.LocationRequest.Builder setMinUpdateDistanceMeters(@FloatRange(from=0, to=java.lang.Float.MAX_VALUE) float);
+ method @NonNull public android.location.LocationRequest.Builder setMinUpdateIntervalMillis(@IntRange(from=0) long);
+ }
+
public interface OnNmeaMessageListener {
method public void onNmeaMessage(String, long);
}
@@ -46824,6 +46860,7 @@ package android.telephony {
field public static final String KEY_HIDE_PREFERRED_NETWORK_TYPE_BOOL = "hide_preferred_network_type_bool";
field public static final String KEY_HIDE_PRESET_APN_DETAILS_BOOL = "hide_preset_apn_details_bool";
field public static final String KEY_HIDE_SIM_LOCK_SETTINGS_BOOL = "hide_sim_lock_settings_bool";
+ field public static final String KEY_HIDE_TTY_HCO_VCO_WITH_RTT_BOOL = "hide_tty_hco_vco_with_rtt";
field public static final String KEY_IGNORE_DATA_ENABLED_CHANGED_FOR_VIDEO_CALLS = "ignore_data_enabled_changed_for_video_calls";
field public static final String KEY_IGNORE_RTT_MODE_SETTING_BOOL = "ignore_rtt_mode_setting_bool";
field public static final String KEY_IGNORE_SIM_NETWORK_LOCKED_EVENTS_BOOL = "ignore_sim_network_locked_events_bool";
@@ -46890,7 +46927,11 @@ package android.telephony {
field public static final String KEY_READ_ONLY_APN_TYPES_STRING_ARRAY = "read_only_apn_types_string_array";
field public static final String KEY_REQUIRE_ENTITLEMENT_CHECKS_BOOL = "require_entitlement_checks_bool";
field @Deprecated public static final String KEY_RESTART_RADIO_ON_PDP_FAIL_REGULAR_DEACTIVATION_BOOL = "restart_radio_on_pdp_fail_regular_deactivation_bool";
+ field public static final String KEY_RTT_AUTO_UPGRADE_BOOL = "rtt_auto_upgrade_bool";
+ field public static final String KEY_RTT_DOWNGRADE_SUPPORTED_BOOL = "rtt_downgrade_supported_bool";
field public static final String KEY_RTT_SUPPORTED_BOOL = "rtt_supported_bool";
+ field public static final String KEY_RTT_SUPPORTED_FOR_VT_BOOL = "rtt_supported_for_vt_bool";
+ field public static final String KEY_RTT_UPGRADE_SUPPORTED_BOOL = "rtt_upgrade_supported_bool";
field public static final String KEY_SHOW_4G_FOR_3G_DATA_ICON_BOOL = "show_4g_for_3g_data_icon_bool";
field public static final String KEY_SHOW_4G_FOR_LTE_DATA_ICON_BOOL = "show_4g_for_lte_data_icon_bool";
field public static final String KEY_SHOW_APN_SETTING_CDMA_BOOL = "show_apn_setting_cdma_bool";
diff --git a/api/module-lib-current.txt b/api/module-lib-current.txt
index c12d897b9d72..4f0e2cd3c768 100644
--- a/api/module-lib-current.txt
+++ b/api/module-lib-current.txt
@@ -66,6 +66,8 @@ package android.media.session {
method public boolean dispatchMediaKeyEventAsSystemService(@NonNull android.media.session.MediaSession.Token, @NonNull android.view.KeyEvent);
method public void dispatchVolumeKeyEventAsSystemService(@NonNull android.view.KeyEvent, int);
method public void dispatchVolumeKeyEventAsSystemService(@NonNull android.media.session.MediaSession.Token, @NonNull android.view.KeyEvent);
+ field public static final int RESULT_MEDIA_KEY_HANDLED = 1; // 0x1
+ field public static final int RESULT_MEDIA_KEY_NOT_HANDLED = 0; // 0x0
}
}
diff --git a/api/system-current.txt b/api/system-current.txt
index 4134711035e5..84a8a1d5c7a6 100644
--- a/api/system-current.txt
+++ b/api/system-current.txt
@@ -4075,7 +4075,7 @@ package android.location {
public class LocationManager {
method @RequiresPermission(android.Manifest.permission.LOCATION_HARDWARE) public void flushGnssBatch();
- method @RequiresPermission(anyOf={android.Manifest.permission.ACCESS_COARSE_LOCATION, android.Manifest.permission.ACCESS_FINE_LOCATION}) public void getCurrentLocation(@NonNull android.location.LocationRequest, @Nullable android.os.CancellationSignal, @NonNull java.util.concurrent.Executor, @NonNull java.util.function.Consumer<android.location.Location>);
+ method @Deprecated @RequiresPermission(anyOf={android.Manifest.permission.ACCESS_COARSE_LOCATION, android.Manifest.permission.ACCESS_FINE_LOCATION}) public void getCurrentLocation(@NonNull android.location.LocationRequest, @Nullable android.os.CancellationSignal, @NonNull java.util.concurrent.Executor, @NonNull java.util.function.Consumer<android.location.Location>);
method @Nullable public String getExtraLocationControllerPackage();
method @RequiresPermission(android.Manifest.permission.LOCATION_HARDWARE) public int getGnssBatchSize();
method @RequiresPermission(android.Manifest.permission.ACCESS_FINE_LOCATION) public void injectGnssMeasurementCorrections(@NonNull android.location.GnssMeasurementCorrections);
@@ -4086,9 +4086,9 @@ package android.location {
method @RequiresPermission(android.Manifest.permission.READ_DEVICE_CONFIG) public boolean isProviderPackage(@Nullable String, @NonNull String);
method @RequiresPermission(android.Manifest.permission.LOCATION_HARDWARE) public boolean registerGnssBatchedLocationCallback(long, boolean, @NonNull android.location.BatchedLocationCallback, @Nullable android.os.Handler);
method @RequiresPermission(allOf={android.Manifest.permission.ACCESS_FINE_LOCATION, android.Manifest.permission.LOCATION_HARDWARE}) public boolean registerGnssMeasurementsCallback(@NonNull android.location.GnssRequest, @NonNull java.util.concurrent.Executor, @NonNull android.location.GnssMeasurementsEvent.Callback);
- method @RequiresPermission(anyOf={android.Manifest.permission.ACCESS_COARSE_LOCATION, android.Manifest.permission.ACCESS_FINE_LOCATION}) public void requestLocationUpdates(@Nullable android.location.LocationRequest, @NonNull android.location.LocationListener, @Nullable android.os.Looper);
- method @RequiresPermission(anyOf={android.Manifest.permission.ACCESS_COARSE_LOCATION, android.Manifest.permission.ACCESS_FINE_LOCATION}) public void requestLocationUpdates(@Nullable android.location.LocationRequest, @NonNull java.util.concurrent.Executor, @NonNull android.location.LocationListener);
- method @RequiresPermission(anyOf={android.Manifest.permission.ACCESS_COARSE_LOCATION, android.Manifest.permission.ACCESS_FINE_LOCATION}) public void requestLocationUpdates(@Nullable android.location.LocationRequest, @NonNull android.app.PendingIntent);
+ method @Deprecated @RequiresPermission(anyOf={android.Manifest.permission.ACCESS_COARSE_LOCATION, android.Manifest.permission.ACCESS_FINE_LOCATION}) public void requestLocationUpdates(@Nullable android.location.LocationRequest, @NonNull android.location.LocationListener, @Nullable android.os.Looper);
+ method @Deprecated @RequiresPermission(anyOf={android.Manifest.permission.ACCESS_COARSE_LOCATION, android.Manifest.permission.ACCESS_FINE_LOCATION}) public void requestLocationUpdates(@Nullable android.location.LocationRequest, @NonNull java.util.concurrent.Executor, @NonNull android.location.LocationListener);
+ method @Deprecated @RequiresPermission(anyOf={android.Manifest.permission.ACCESS_COARSE_LOCATION, android.Manifest.permission.ACCESS_FINE_LOCATION}) public void requestLocationUpdates(@Nullable android.location.LocationRequest, @NonNull android.app.PendingIntent);
method @RequiresPermission(android.Manifest.permission.LOCATION_HARDWARE) public void setExtraLocationControllerPackage(@Nullable String);
method @RequiresPermission(android.Manifest.permission.LOCATION_HARDWARE) public void setExtraLocationControllerPackageEnabled(boolean);
method @RequiresPermission(android.Manifest.permission.WRITE_SECURE_SETTINGS) public void setLocationEnabledForUser(boolean, @NonNull android.os.UserHandle);
@@ -4097,42 +4097,49 @@ package android.location {
}
public final class LocationRequest implements android.os.Parcelable {
- method @NonNull public static android.location.LocationRequest create();
- method @NonNull public static android.location.LocationRequest createFromDeprecatedCriteria(@NonNull android.location.Criteria, long, float, boolean);
- method @NonNull public static android.location.LocationRequest createFromDeprecatedProvider(@NonNull String, long, float, boolean);
- method public int describeContents();
+ method @Deprecated @NonNull public static android.location.LocationRequest create();
+ method @Deprecated @NonNull public static android.location.LocationRequest createFromDeprecatedCriteria(@NonNull android.location.Criteria, long, float, boolean);
+ method @Deprecated @NonNull public static android.location.LocationRequest createFromDeprecatedProvider(@NonNull String, long, float, boolean);
method @Deprecated public long getExpireAt();
- method public long getExpireIn();
- method public long getFastestInterval();
- method public boolean getHideFromAppOps();
- method public long getInterval();
- method public int getNumUpdates();
- method @NonNull public String getProvider();
+ method @Deprecated public long getExpireIn();
+ method @Deprecated public long getFastestInterval();
+ method @Deprecated public boolean getHideFromAppOps();
+ method @Deprecated public long getInterval();
+ method @Deprecated public int getNumUpdates();
+ method @Deprecated @NonNull public String getProvider();
method public int getQuality();
- method public float getSmallestDisplacement();
+ method @Deprecated public float getSmallestDisplacement();
method @Nullable public android.os.WorkSource getWorkSource();
+ method public boolean isHiddenFromAppOps();
method public boolean isLocationSettingsIgnored();
- method public boolean isLowPowerMode();
+ method public boolean isLowPower();
+ method @Deprecated public boolean isLowPowerMode();
method @Deprecated @NonNull public android.location.LocationRequest setExpireAt(long);
- method @NonNull public android.location.LocationRequest setExpireIn(long);
- method @NonNull public android.location.LocationRequest setFastestInterval(long);
- method public void setHideFromAppOps(boolean);
- method @NonNull public android.location.LocationRequest setInterval(long);
- method @NonNull @RequiresPermission(android.Manifest.permission.WRITE_SECURE_SETTINGS) public android.location.LocationRequest setLocationSettingsIgnored(boolean);
- method @NonNull public android.location.LocationRequest setLowPowerMode(boolean);
- method @NonNull public android.location.LocationRequest setNumUpdates(int);
- method @NonNull public android.location.LocationRequest setProvider(@NonNull String);
- method @NonNull public android.location.LocationRequest setQuality(int);
- method @NonNull public android.location.LocationRequest setSmallestDisplacement(float);
- method public void setWorkSource(@Nullable android.os.WorkSource);
- method public void writeToParcel(android.os.Parcel, int);
+ method @Deprecated @NonNull public android.location.LocationRequest setExpireIn(long);
+ method @Deprecated @NonNull public android.location.LocationRequest setFastestInterval(long);
+ method @Deprecated public void setHideFromAppOps(boolean);
+ method @Deprecated @NonNull public android.location.LocationRequest setInterval(long);
+ method @Deprecated @NonNull @RequiresPermission(android.Manifest.permission.WRITE_SECURE_SETTINGS) public android.location.LocationRequest setLocationSettingsIgnored(boolean);
+ method @Deprecated @NonNull public android.location.LocationRequest setLowPowerMode(boolean);
+ method @Deprecated @NonNull public android.location.LocationRequest setNumUpdates(int);
+ method @Deprecated @NonNull public android.location.LocationRequest setProvider(@NonNull String);
+ method @Deprecated @NonNull public android.location.LocationRequest setQuality(int);
+ method @Deprecated @NonNull public android.location.LocationRequest setSmallestDisplacement(float);
+ method @Deprecated public void setWorkSource(@Nullable android.os.WorkSource);
field public static final int ACCURACY_BLOCK = 102; // 0x66
field public static final int ACCURACY_CITY = 104; // 0x68
field public static final int ACCURACY_FINE = 100; // 0x64
- field @NonNull public static final android.os.Parcelable.Creator<android.location.LocationRequest> CREATOR;
field public static final int POWER_HIGH = 203; // 0xcb
field public static final int POWER_LOW = 201; // 0xc9
- field public static final int POWER_NONE = 200; // 0xc8
+ field @Deprecated public static final int POWER_NONE = 200; // 0xc8
+ }
+
+ public static final class LocationRequest.Builder {
+ method @NonNull @RequiresPermission(android.Manifest.permission.UPDATE_APP_OPS_STATS) public android.location.LocationRequest.Builder setHiddenFromAppOps(boolean);
+ method @NonNull @RequiresPermission(android.Manifest.permission.WRITE_SECURE_SETTINGS) public android.location.LocationRequest.Builder setLocationSettingsIgnored(boolean);
+ method @NonNull @RequiresPermission(android.Manifest.permission.LOCATION_HARDWARE) public android.location.LocationRequest.Builder setLowPower(boolean);
+ method @NonNull public android.location.LocationRequest.Builder setQuality(int);
+ method @NonNull @RequiresPermission(android.Manifest.permission.UPDATE_DEVICE_STATS) public android.location.LocationRequest.Builder setWorkSource(@Nullable android.os.WorkSource);
}
}
diff --git a/api/test-current.txt b/api/test-current.txt
index de2919b8936a..30972b65a1fd 100644
--- a/api/test-current.txt
+++ b/api/test-current.txt
@@ -1686,45 +1686,34 @@ package android.location {
public class LocationManager {
method @NonNull public String[] getBackgroundThrottlingWhitelist();
- method @RequiresPermission(anyOf={android.Manifest.permission.ACCESS_COARSE_LOCATION, android.Manifest.permission.ACCESS_FINE_LOCATION}) public void getCurrentLocation(@NonNull android.location.LocationRequest, @Nullable android.os.CancellationSignal, @NonNull java.util.concurrent.Executor, @NonNull java.util.function.Consumer<android.location.Location>);
+ method @Deprecated @RequiresPermission(anyOf={android.Manifest.permission.ACCESS_COARSE_LOCATION, android.Manifest.permission.ACCESS_FINE_LOCATION}) public void getCurrentLocation(@NonNull android.location.LocationRequest, @Nullable android.os.CancellationSignal, @NonNull java.util.concurrent.Executor, @NonNull java.util.function.Consumer<android.location.Location>);
method @NonNull public String[] getIgnoreSettingsWhitelist();
method @Deprecated @Nullable @RequiresPermission("android.permission.READ_DEVICE_CONFIG") public java.util.List<java.lang.String> getProviderPackages(@NonNull String);
method @NonNull public java.util.List<android.location.LocationRequest> getTestProviderCurrentRequests(String);
- method @RequiresPermission(anyOf={android.Manifest.permission.ACCESS_COARSE_LOCATION, android.Manifest.permission.ACCESS_FINE_LOCATION}) public void requestLocationUpdates(@Nullable android.location.LocationRequest, @NonNull android.location.LocationListener, @Nullable android.os.Looper);
- method @RequiresPermission(anyOf={android.Manifest.permission.ACCESS_COARSE_LOCATION, android.Manifest.permission.ACCESS_FINE_LOCATION}) public void requestLocationUpdates(@Nullable android.location.LocationRequest, @NonNull java.util.concurrent.Executor, @NonNull android.location.LocationListener);
- method @RequiresPermission(anyOf={android.Manifest.permission.ACCESS_COARSE_LOCATION, android.Manifest.permission.ACCESS_FINE_LOCATION}) public void requestLocationUpdates(@Nullable android.location.LocationRequest, @NonNull android.app.PendingIntent);
+ method @Deprecated @RequiresPermission(anyOf={android.Manifest.permission.ACCESS_COARSE_LOCATION, android.Manifest.permission.ACCESS_FINE_LOCATION}) public void requestLocationUpdates(@Nullable android.location.LocationRequest, @NonNull android.location.LocationListener, @Nullable android.os.Looper);
+ method @Deprecated @RequiresPermission(anyOf={android.Manifest.permission.ACCESS_COARSE_LOCATION, android.Manifest.permission.ACCESS_FINE_LOCATION}) public void requestLocationUpdates(@Nullable android.location.LocationRequest, @NonNull java.util.concurrent.Executor, @NonNull android.location.LocationListener);
+ method @Deprecated @RequiresPermission(anyOf={android.Manifest.permission.ACCESS_COARSE_LOCATION, android.Manifest.permission.ACCESS_FINE_LOCATION}) public void requestLocationUpdates(@Nullable android.location.LocationRequest, @NonNull android.app.PendingIntent);
method @RequiresPermission(android.Manifest.permission.WRITE_SECURE_SETTINGS) public void setLocationEnabledForUser(boolean, @NonNull android.os.UserHandle);
field public static final String FUSED_PROVIDER = "fused";
}
public final class LocationRequest implements android.os.Parcelable {
- method @NonNull public static android.location.LocationRequest create();
- method public int describeContents();
- method @Deprecated public long getExpireAt();
- method public long getExpireIn();
- method public long getFastestInterval();
- method public long getInterval();
- method public int getNumUpdates();
- method public int getQuality();
+ method @Nullable public android.os.WorkSource getWorkSource();
+ method public boolean isHiddenFromAppOps();
method public boolean isLocationSettingsIgnored();
- method public boolean isLowPowerMode();
- method @Deprecated @NonNull public android.location.LocationRequest setExpireAt(long);
- method @NonNull public android.location.LocationRequest setExpireIn(long);
- method @NonNull public android.location.LocationRequest setFastestInterval(long);
- method @NonNull public android.location.LocationRequest setInterval(long);
- method @NonNull @RequiresPermission(android.Manifest.permission.WRITE_SECURE_SETTINGS) public android.location.LocationRequest setLocationSettingsIgnored(boolean);
- method @NonNull public android.location.LocationRequest setLowPowerMode(boolean);
- method @NonNull public android.location.LocationRequest setNumUpdates(int);
- method @NonNull public android.location.LocationRequest setProvider(@NonNull String);
- method @NonNull public android.location.LocationRequest setQuality(int);
- method public void writeToParcel(android.os.Parcel, int);
+ method public boolean isLowPower();
field public static final int ACCURACY_BLOCK = 102; // 0x66
field public static final int ACCURACY_CITY = 104; // 0x68
field public static final int ACCURACY_FINE = 100; // 0x64
- field @NonNull public static final android.os.Parcelable.Creator<android.location.LocationRequest> CREATOR;
field public static final int POWER_HIGH = 203; // 0xcb
field public static final int POWER_LOW = 201; // 0xc9
- field public static final int POWER_NONE = 200; // 0xc8
+ }
+
+ public static final class LocationRequest.Builder {
+ method @NonNull @RequiresPermission("android.permission.UPDATE_APP_OPS_STATS") public android.location.LocationRequest.Builder setHiddenFromAppOps(boolean);
+ method @NonNull @RequiresPermission(android.Manifest.permission.WRITE_SECURE_SETTINGS) public android.location.LocationRequest.Builder setLocationSettingsIgnored(boolean);
+ method @NonNull @RequiresPermission(android.Manifest.permission.LOCATION_HARDWARE) public android.location.LocationRequest.Builder setLowPower(boolean);
+ method @NonNull @RequiresPermission(android.Manifest.permission.UPDATE_DEVICE_STATS) public android.location.LocationRequest.Builder setWorkSource(@Nullable android.os.WorkSource);
}
}
diff --git a/cmds/statsd/src/atoms.proto b/cmds/statsd/src/atoms.proto
index 94c2305e36f6..038f4c35bab6 100644
--- a/cmds/statsd/src/atoms.proto
+++ b/cmds/statsd/src/atoms.proto
@@ -3764,6 +3764,19 @@ message AppStartOccurred {
// The reason why the package was optimized.
optional int32 package_optimization_compilation_reason = 15;
+
+ enum SourceType {
+ UNAVAILABLE = 0;
+ LAUNCHER = 1;
+ NOTIFICATION = 2;
+ LOCKSCREEN = 3;
+ }
+ // The type of the startup source.
+ optional SourceType source_type = 16;
+
+ // The time from the startup source to the beginning of handling the startup event.
+ // -1 means not available.
+ optional int32 source_event_delay_millis = 17;
}
message AppStartCanceled {
@@ -3808,6 +3821,19 @@ message AppStartFullyDrawn {
// App startup time (until call to Activity#reportFullyDrawn()).
optional int64 app_startup_time_millis = 6;
+
+ enum SourceType {
+ UNAVAILABLE = 0;
+ LAUNCHER = 1;
+ NOTIFICATION = 2;
+ LOCKSCREEN = 3;
+ }
+ // The type of the startup source.
+ optional SourceType source_type = 7;
+
+ // The time from the startup source to the beginning of handling the startup event.
+ // -1 means not available.
+ optional int32 source_event_delay_millis = 8;
}
/**
diff --git a/core/java/android/app/ActivityOptions.java b/core/java/android/app/ActivityOptions.java
index 84a6b43e7175..a61159a23c2c 100644
--- a/core/java/android/app/ActivityOptions.java
+++ b/core/java/android/app/ActivityOptions.java
@@ -22,6 +22,7 @@ import static android.app.WindowConfiguration.ACTIVITY_TYPE_UNDEFINED;
import static android.app.WindowConfiguration.WINDOWING_MODE_UNDEFINED;
import static android.view.Display.INVALID_DISPLAY;
+import android.annotation.IntDef;
import android.annotation.NonNull;
import android.annotation.Nullable;
import android.annotation.RequiresPermission;
@@ -37,6 +38,7 @@ import android.hardware.HardwareBuffer;
import android.os.Bundle;
import android.os.Handler;
import android.os.IRemoteCallback;
+import android.os.Parcel;
import android.os.Parcelable;
import android.os.RemoteException;
import android.os.ResultReceiver;
@@ -54,6 +56,8 @@ import android.view.ViewGroup;
import android.view.Window;
import android.window.WindowContainerToken;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
import java.util.ArrayList;
/**
@@ -290,6 +294,9 @@ public class ActivityOptions {
private static final String KEY_EXIT_COORDINATOR_INDEX
= "android:activity.exitCoordinatorIndex";
+ /** See {@link SourceInfo}. */
+ private static final String KEY_SOURCE_INFO = "android.activity.sourceInfo";
+
private static final String KEY_USAGE_TIME_REPORT = "android:activity.usageTimeReport";
private static final String KEY_ROTATION_ANIMATION_HINT = "android:activity.rotationAnimationHint";
@@ -369,6 +376,7 @@ public class ActivityOptions {
private boolean mAvoidMoveToFront;
private boolean mFreezeRecentTasksReordering;
private AppTransitionAnimationSpec mAnimSpecs[];
+ private SourceInfo mSourceInfo;
private int mRotationAnimationHint = -1;
private Bundle mAppVerificationBundle;
private IAppTransitionAnimationSpecsFuture mSpecsFuture;
@@ -1055,6 +1063,7 @@ public class ActivityOptions {
mAnimationFinishedListener = IRemoteCallback.Stub.asInterface(
opts.getBinder(KEY_ANIMATION_FINISHED_LISTENER));
}
+ mSourceInfo = opts.getParcelable(KEY_SOURCE_INFO);
mRotationAnimationHint = opts.getInt(KEY_ROTATION_ANIMATION_HINT, -1);
mAppVerificationBundle = opts.getBundle(KEY_INSTANT_APP_VERIFICATION_BUNDLE);
if (opts.containsKey(KEY_SPECS_FUTURE)) {
@@ -1696,6 +1705,9 @@ public class ActivityOptions {
if (mSpecsFuture != null) {
b.putBinder(KEY_SPECS_FUTURE, mSpecsFuture.asBinder());
}
+ if (mSourceInfo != null) {
+ b.putParcelable(KEY_SOURCE_INFO, mSourceInfo);
+ }
if (mRotationAnimationHint != -1) {
b.putInt(KEY_ROTATION_ANIMATION_HINT, mRotationAnimationHint);
}
@@ -1737,6 +1749,28 @@ public class ActivityOptions {
}
/**
+ * Returns the launch source information set by {@link #setSourceInfo}.
+ * @hide
+ */
+ public @Nullable SourceInfo getSourceInfo() {
+ return mSourceInfo;
+ }
+
+ /**
+ * Sets the source information of the launch event.
+ *
+ * @param type The type of the startup source.
+ * @param uptimeMillis The event time of startup source in milliseconds since boot, not
+ * including sleep (e.g. from {@link android.view.MotionEvent#getEventTime}
+ * or {@link android.os.SystemClock#uptimeMillis}).
+ * @see SourceInfo
+ * @hide
+ */
+ public void setSourceInfo(@SourceInfo.SourceType int type, long uptimeMillis) {
+ mSourceInfo = new SourceInfo(type, uptimeMillis);
+ }
+
+ /**
* Return the filtered options only meant to be seen by the target activity itself
* @hide
*/
@@ -1863,4 +1897,58 @@ public class ActivityOptions {
}
}
}
+
+ /**
+ * The information about the source of activity launch. E.g. describe an activity is launched
+ * from launcher by receiving a motion event with a timestamp.
+ * @hide
+ */
+ public static class SourceInfo implements Parcelable {
+ /** Launched from launcher. */
+ public static final int TYPE_LAUNCHER = 1;
+ /** Launched from notification. */
+ public static final int TYPE_NOTIFICATION = 2;
+ /** Launched from lockscreen, including notification while the device is locked. */
+ public static final int TYPE_LOCKSCREEN = 3;
+
+ @IntDef(flag = true, prefix = { "TYPE_" }, value = {
+ TYPE_LAUNCHER,
+ TYPE_NOTIFICATION,
+ TYPE_LOCKSCREEN,
+ })
+ @Retention(RetentionPolicy.SOURCE)
+ public @interface SourceType {}
+
+ /** The type of the startup source. */
+ public final @SourceType int type;
+
+ /** The timestamp (uptime based) of the source to launch activity. */
+ public final long eventTimeMs;
+
+ SourceInfo(@SourceType int srcType, long uptimeMillis) {
+ type = srcType;
+ eventTimeMs = uptimeMillis;
+ }
+
+ @Override
+ public void writeToParcel(Parcel dest, int flags) {
+ dest.writeInt(type);
+ dest.writeLong(eventTimeMs);
+ }
+
+ @Override
+ public int describeContents() {
+ return 0;
+ }
+
+ public static final Creator<SourceInfo> CREATOR = new Creator<SourceInfo>() {
+ public SourceInfo createFromParcel(Parcel in) {
+ return new SourceInfo(in.readInt(), in.readLong());
+ }
+
+ public SourceInfo[] newArray(int size) {
+ return new SourceInfo[size];
+ }
+ };
+ }
}
diff --git a/core/java/android/app/ApplicationPackageManager.java b/core/java/android/app/ApplicationPackageManager.java
index 2780036d8102..066a00732965 100644
--- a/core/java/android/app/ApplicationPackageManager.java
+++ b/core/java/android/app/ApplicationPackageManager.java
@@ -16,6 +16,14 @@
package android.app;
+import static android.content.pm.Checksum.PARTIAL_MERKLE_ROOT_1M_SHA256;
+import static android.content.pm.Checksum.PARTIAL_MERKLE_ROOT_1M_SHA512;
+import static android.content.pm.Checksum.WHOLE_MD5;
+import static android.content.pm.Checksum.WHOLE_MERKLE_ROOT_4K_SHA256;
+import static android.content.pm.Checksum.WHOLE_SHA1;
+import static android.content.pm.Checksum.WHOLE_SHA256;
+import static android.content.pm.Checksum.WHOLE_SHA512;
+
import android.annotation.DrawableRes;
import android.annotation.NonNull;
import android.annotation.Nullable;
@@ -32,6 +40,7 @@ import android.content.IntentSender;
import android.content.pm.ActivityInfo;
import android.content.pm.ApplicationInfo;
import android.content.pm.ChangedPackages;
+import android.content.pm.Checksum;
import android.content.pm.ComponentInfo;
import android.content.pm.FeatureInfo;
import android.content.pm.IPackageDataObserver;
@@ -973,7 +982,7 @@ public class ApplicationPackageManager extends PackageManager {
@Override
public void getChecksums(@NonNull String packageName, boolean includeSplits,
- @FileChecksumKind int required, @Nullable List<Certificate> trustedInstallers,
+ @Checksum.Kind int required, @Nullable List<Certificate> trustedInstallers,
@NonNull IntentSender statusReceiver)
throws CertificateEncodingException, IOException, NameNotFoundException {
Objects.requireNonNull(packageName);
diff --git a/core/java/android/content/pm/FileChecksum.aidl b/core/java/android/content/pm/ApkChecksum.aidl
index 109f211033c1..46781fe26677 100644
--- a/core/java/android/content/pm/FileChecksum.aidl
+++ b/core/java/android/content/pm/ApkChecksum.aidl
@@ -16,5 +16,5 @@
package android.content.pm;
-parcelable FileChecksum;
+parcelable ApkChecksum;
diff --git a/core/java/android/content/pm/FileChecksum.java b/core/java/android/content/pm/ApkChecksum.java
index 55430c2b877b..e087c44d1ed1 100644
--- a/core/java/android/content/pm/FileChecksum.java
+++ b/core/java/android/content/pm/ApkChecksum.java
@@ -34,51 +34,71 @@ import java.security.cert.X509Certificate;
import java.util.List;
/**
- * A typed checksum.
+ * A typed checksum of an APK.
*
* @see PackageManager#getChecksums(String, boolean, int, List, IntentSender)
*/
@DataClass(genHiddenConstructor = true)
-public final class FileChecksum implements Parcelable {
+@DataClass.Suppress({"getChecksum"})
+public final class ApkChecksum implements Parcelable {
/**
* Checksum for which split. Null indicates base.apk.
*/
private final @Nullable String mSplitName;
/**
- * Checksum kind.
+ * Checksum.
*/
- private final @PackageManager.FileChecksumKind int mKind;
- /**
- * Checksum value.
- */
- private final @NonNull byte[] mValue;
+ private final @NonNull Checksum mChecksum;
/**
* For Installer-provided checksums, certificate of the Installer/AppStore.
*/
private final @Nullable byte[] mSourceCertificate;
/**
- * Constructor, internal use only
+ * Constructor, internal use only.
*
* @hide
*/
- public FileChecksum(@Nullable String splitName, @PackageManager.FileChecksumKind int kind,
+ public ApkChecksum(@Nullable String splitName, @Checksum.Kind int kind,
@NonNull byte[] value) {
- this(splitName, kind, value, (byte[]) null);
+ this(splitName, new Checksum(kind, value), (byte[]) null);
}
/**
- * Constructor, internal use only
+ * Constructor, internal use only.
*
* @hide
*/
- public FileChecksum(@Nullable String splitName, @PackageManager.FileChecksumKind int kind,
+ public ApkChecksum(@Nullable String splitName, @Checksum.Kind int kind,
@NonNull byte[] value, @Nullable Certificate sourceCertificate)
throws CertificateEncodingException {
- this(splitName, kind, value,
+ this(splitName, new Checksum(kind, value),
(sourceCertificate != null) ? sourceCertificate.getEncoded() : null);
}
+
+ /**
+ * Checksum kind.
+ */
+ public @Checksum.Kind int getKind() {
+ return mChecksum.getKind();
+ }
+
+ /**
+ * Checksum value.
+ */
+ public @NonNull byte[] getValue() {
+ return mChecksum.getValue();
+ }
+
+ /**
+ * Returns raw bytes representing encoded certificate of the source of this checksum.
+ * @hide
+ */
+ public @Nullable byte[] getSourceCertificateBytes() {
+ return mSourceCertificate;
+ }
+
/**
* Certificate of the source of this checksum.
* @throws CertificateException in case when certificate can't be re-created from serialized
@@ -102,7 +122,7 @@ public final class FileChecksum implements Parcelable {
// CHECKSTYLE:OFF Generated code
//
// To regenerate run:
- // $ codegen $ANDROID_BUILD_TOP/frameworks/base/core/java/android/content/pm/FileChecksum.java
+ // $ codegen $ANDROID_BUILD_TOP/frameworks/base/core/java/android/content/pm/ApkChecksum.java
//
// To exclude the generated code from IntelliJ auto-formatting enable (one-time):
// Settings > Editor > Code Style > Formatter Control
@@ -110,31 +130,25 @@ public final class FileChecksum implements Parcelable {
/**
- * Creates a new FileChecksum.
+ * Creates a new ApkChecksum.
*
* @param splitName
* Checksum for which split. Null indicates base.apk.
- * @param kind
- * Checksum kind.
- * @param value
- * Checksum value.
+ * @param checksum
+ * Checksum.
* @param sourceCertificate
* For Installer-provided checksums, certificate of the Installer/AppStore.
* @hide
*/
@DataClass.Generated.Member
- public FileChecksum(
+ public ApkChecksum(
@Nullable String splitName,
- @PackageManager.FileChecksumKind int kind,
- @NonNull byte[] value,
+ @NonNull Checksum checksum,
@Nullable byte[] sourceCertificate) {
this.mSplitName = splitName;
- this.mKind = kind;
+ this.mChecksum = checksum;
com.android.internal.util.AnnotationValidations.validate(
- PackageManager.FileChecksumKind.class, null, mKind);
- this.mValue = value;
- com.android.internal.util.AnnotationValidations.validate(
- NonNull.class, null, mValue);
+ NonNull.class, null, mChecksum);
this.mSourceCertificate = sourceCertificate;
// onConstructed(); // You can define this method to get a callback
@@ -148,22 +162,6 @@ public final class FileChecksum implements Parcelable {
return mSplitName;
}
- /**
- * Checksum kind.
- */
- @DataClass.Generated.Member
- public @PackageManager.FileChecksumKind int getKind() {
- return mKind;
- }
-
- /**
- * Checksum value.
- */
- @DataClass.Generated.Member
- public @NonNull byte[] getValue() {
- return mValue;
- }
-
@Override
@DataClass.Generated.Member
public void writeToParcel(@NonNull Parcel dest, int flags) {
@@ -172,11 +170,10 @@ public final class FileChecksum implements Parcelable {
byte flg = 0;
if (mSplitName != null) flg |= 0x1;
- if (mSourceCertificate != null) flg |= 0x8;
+ if (mSourceCertificate != null) flg |= 0x4;
dest.writeByte(flg);
if (mSplitName != null) dest.writeString(mSplitName);
- dest.writeInt(mKind);
- dest.writeByteArray(mValue);
+ dest.writeTypedObject(mChecksum, flags);
if (mSourceCertificate != null) dest.writeByteArray(mSourceCertificate);
}
@@ -187,47 +184,43 @@ public final class FileChecksum implements Parcelable {
/** @hide */
@SuppressWarnings({"unchecked", "RedundantCast"})
@DataClass.Generated.Member
- /* package-private */ FileChecksum(@NonNull Parcel in) {
+ /* package-private */ ApkChecksum(@NonNull Parcel in) {
// You can override field unparcelling by defining methods like:
// static FieldType unparcelFieldName(Parcel in) { ... }
byte flg = in.readByte();
String splitName = (flg & 0x1) == 0 ? null : in.readString();
- int kind = in.readInt();
- byte[] value = in.createByteArray();
- byte[] sourceCertificate = (flg & 0x8) == 0 ? null : in.createByteArray();
+ Checksum checksum = (Checksum) in.readTypedObject(Checksum.CREATOR);
+ byte[] sourceCertificate = (flg & 0x4) == 0 ? null : in.createByteArray();
this.mSplitName = splitName;
- this.mKind = kind;
- com.android.internal.util.AnnotationValidations.validate(
- PackageManager.FileChecksumKind.class, null, mKind);
- this.mValue = value;
+ this.mChecksum = checksum;
com.android.internal.util.AnnotationValidations.validate(
- NonNull.class, null, mValue);
+ NonNull.class, null, mChecksum);
this.mSourceCertificate = sourceCertificate;
// onConstructed(); // You can define this method to get a callback
}
@DataClass.Generated.Member
- public static final @NonNull Parcelable.Creator<FileChecksum> CREATOR
- = new Parcelable.Creator<FileChecksum>() {
+ public static final @NonNull Parcelable.Creator<ApkChecksum> CREATOR
+ = new Parcelable.Creator<ApkChecksum>() {
@Override
- public FileChecksum[] newArray(int size) {
- return new FileChecksum[size];
+ public ApkChecksum[] newArray(int size) {
+ return new ApkChecksum[size];
}
@Override
- public FileChecksum createFromParcel(@NonNull Parcel in) {
- return new FileChecksum(in);
+ public ApkChecksum createFromParcel(@NonNull Parcel in) {
+ return new ApkChecksum(in);
}
};
@DataClass.Generated(
- time = 1598322801861L,
+ time = 1599845645160L,
codegenVersion = "1.0.15",
- sourceFile = "frameworks/base/core/java/android/content/pm/FileChecksum.java",
- inputSignatures = "private final @android.annotation.Nullable java.lang.String mSplitName\nprivate final @android.content.pm.PackageManager.FileChecksumKind int mKind\nprivate final @android.annotation.NonNull byte[] mValue\nprivate final @android.annotation.Nullable byte[] mSourceCertificate\npublic @android.annotation.Nullable java.security.cert.Certificate getSourceCertificate()\nclass FileChecksum extends java.lang.Object implements [android.os.Parcelable]\n@com.android.internal.util.DataClass(genHiddenConstructor=true)")
+ sourceFile = "frameworks/base/core/java/android/content/pm/ApkChecksum.java",
+ inputSignatures = "private final @android.annotation.Nullable java.lang.String mSplitName\nprivate final @android.annotation.NonNull android.content.pm.Checksum mChecksum\nprivate final @android.annotation.Nullable byte[] mSourceCertificate\npublic @android.content.pm.Checksum.Kind int getKind()\npublic @android.annotation.NonNull byte[] getValue()\npublic @android.annotation.Nullable byte[] getSourceCertificateBytes()\npublic @android.annotation.Nullable java.security.cert.Certificate getSourceCertificate()\nclass ApkChecksum extends java.lang.Object implements [android.os.Parcelable]\n@com.android.internal.util.DataClass(genHiddenConstructor=true)")
@Deprecated
private void __metadata() {}
diff --git a/core/java/android/content/pm/Checksum.aidl b/core/java/android/content/pm/Checksum.aidl
new file mode 100644
index 000000000000..f0ca206fad58
--- /dev/null
+++ b/core/java/android/content/pm/Checksum.aidl
@@ -0,0 +1,20 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.content.pm;
+
+parcelable Checksum;
+
diff --git a/core/java/android/content/pm/Checksum.java b/core/java/android/content/pm/Checksum.java
new file mode 100644
index 000000000000..123aaddda7ce
--- /dev/null
+++ b/core/java/android/content/pm/Checksum.java
@@ -0,0 +1,228 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.content.pm;
+
+import android.annotation.IntDef;
+import android.annotation.NonNull;
+import android.os.Parcel;
+import android.os.Parcelable;
+
+import com.android.internal.util.DataClass;
+
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.util.List;
+
+/**
+ * A typed checksum.
+ *
+ * @see PackageInstaller.Session#addChecksums(String, List)
+ */
+@DataClass(genHiddenConstructor = true, genConstDefs = false)
+public final class Checksum implements Parcelable {
+ /**
+ * Root SHA256 hash of a 4K Merkle tree computed over all file bytes.
+ * <a href="https://source.android.com/security/apksigning/v4">See APK Signature Scheme V4</a>.
+ * <a href="https://git.kernel.org/pub/scm/fs/fscrypt/fscrypt.git/tree/Documentation/filesystems/fsverity.rst">See fs-verity</a>.
+ *
+ * @see PackageManager#getChecksums
+ */
+ public static final int WHOLE_MERKLE_ROOT_4K_SHA256 = 0x00000001;
+
+ /**
+ * MD5 hash computed over all file bytes.
+ *
+ * @see PackageManager#getChecksums
+ */
+ public static final int WHOLE_MD5 = 0x00000002;
+
+ /**
+ * SHA1 hash computed over all file bytes.
+ *
+ * @see PackageManager#getChecksums
+ */
+ public static final int WHOLE_SHA1 = 0x00000004;
+
+ /**
+ * SHA256 hash computed over all file bytes.
+ *
+ * @see PackageManager#getChecksums
+ */
+ public static final int WHOLE_SHA256 = 0x00000008;
+
+ /**
+ * SHA512 hash computed over all file bytes.
+ *
+ * @see PackageManager#getChecksums
+ */
+ public static final int WHOLE_SHA512 = 0x00000010;
+
+ /**
+ * Root SHA256 hash of a 1M Merkle tree computed over protected content.
+ * Excludes signing block.
+ * <a href="https://source.android.com/security/apksigning/v2">See APK Signature Scheme V2</a>.
+ *
+ * @see PackageManager#getChecksums
+ */
+ public static final int PARTIAL_MERKLE_ROOT_1M_SHA256 = 0x00000020;
+
+ /**
+ * Root SHA512 hash of a 1M Merkle tree computed over protected content.
+ * Excludes signing block.
+ * <a href="https://source.android.com/security/apksigning/v2">See APK Signature Scheme V2</a>.
+ *
+ * @see PackageManager#getChecksums
+ */
+ public static final int PARTIAL_MERKLE_ROOT_1M_SHA512 = 0x00000040;
+
+ /** @hide */
+ @IntDef(flag = true, prefix = {"WHOLE_", "PARTIAL_"}, value = {
+ WHOLE_MERKLE_ROOT_4K_SHA256,
+ WHOLE_MD5,
+ WHOLE_SHA1,
+ WHOLE_SHA256,
+ WHOLE_SHA512,
+ PARTIAL_MERKLE_ROOT_1M_SHA256,
+ PARTIAL_MERKLE_ROOT_1M_SHA512,
+ })
+ @Retention(RetentionPolicy.SOURCE)
+ public @interface Kind {}
+
+ /**
+ * Checksum kind.
+ */
+ private final @Checksum.Kind int mKind;
+ /**
+ * Checksum value.
+ */
+ private final @NonNull byte[] mValue;
+
+
+
+ // Code below generated by codegen v1.0.15.
+ //
+ // DO NOT MODIFY!
+ // CHECKSTYLE:OFF Generated code
+ //
+ // To regenerate run:
+ // $ codegen $ANDROID_BUILD_TOP/frameworks/base/core/java/android/content/pm/Checksum.java
+ //
+ // To exclude the generated code from IntelliJ auto-formatting enable (one-time):
+ // Settings > Editor > Code Style > Formatter Control
+ //@formatter:off
+
+
+ /**
+ * Creates a new Checksum.
+ *
+ * @param kind
+ * Checksum kind.
+ * @param value
+ * Checksum value.
+ * @hide
+ */
+ @DataClass.Generated.Member
+ public Checksum(
+ @Checksum.Kind int kind,
+ @NonNull byte[] value) {
+ this.mKind = kind;
+ com.android.internal.util.AnnotationValidations.validate(
+ Checksum.Kind.class, null, mKind);
+ this.mValue = value;
+ com.android.internal.util.AnnotationValidations.validate(
+ NonNull.class, null, mValue);
+
+ // onConstructed(); // You can define this method to get a callback
+ }
+
+ /**
+ * Checksum kind.
+ */
+ @DataClass.Generated.Member
+ public @Checksum.Kind int getKind() {
+ return mKind;
+ }
+
+ /**
+ * Checksum value.
+ */
+ @DataClass.Generated.Member
+ public @NonNull byte[] getValue() {
+ return mValue;
+ }
+
+ @Override
+ @DataClass.Generated.Member
+ public void writeToParcel(@NonNull Parcel dest, int flags) {
+ // You can override field parcelling by defining methods like:
+ // void parcelFieldName(Parcel dest, int flags) { ... }
+
+ dest.writeInt(mKind);
+ dest.writeByteArray(mValue);
+ }
+
+ @Override
+ @DataClass.Generated.Member
+ public int describeContents() { return 0; }
+
+ /** @hide */
+ @SuppressWarnings({"unchecked", "RedundantCast"})
+ @DataClass.Generated.Member
+ /* package-private */ Checksum(@NonNull Parcel in) {
+ // You can override field unparcelling by defining methods like:
+ // static FieldType unparcelFieldName(Parcel in) { ... }
+
+ int kind = in.readInt();
+ byte[] value = in.createByteArray();
+
+ this.mKind = kind;
+ com.android.internal.util.AnnotationValidations.validate(
+ Checksum.Kind.class, null, mKind);
+ this.mValue = value;
+ com.android.internal.util.AnnotationValidations.validate(
+ NonNull.class, null, mValue);
+
+ // onConstructed(); // You can define this method to get a callback
+ }
+
+ @DataClass.Generated.Member
+ public static final @NonNull Parcelable.Creator<Checksum> CREATOR
+ = new Parcelable.Creator<Checksum>() {
+ @Override
+ public Checksum[] newArray(int size) {
+ return new Checksum[size];
+ }
+
+ @Override
+ public Checksum createFromParcel(@NonNull Parcel in) {
+ return new Checksum(in);
+ }
+ };
+
+ @DataClass.Generated(
+ time = 1599845646883L,
+ codegenVersion = "1.0.15",
+ sourceFile = "frameworks/base/core/java/android/content/pm/Checksum.java",
+ inputSignatures = "public static final int WHOLE_MERKLE_ROOT_4K_SHA256\npublic static final int WHOLE_MD5\npublic static final int WHOLE_SHA1\npublic static final int WHOLE_SHA256\npublic static final int WHOLE_SHA512\npublic static final int PARTIAL_MERKLE_ROOT_1M_SHA256\npublic static final int PARTIAL_MERKLE_ROOT_1M_SHA512\nprivate final @android.content.pm.Checksum.Kind int mKind\nprivate final @android.annotation.NonNull byte[] mValue\nclass Checksum extends java.lang.Object implements [android.os.Parcelable]\n@com.android.internal.util.DataClass(genHiddenConstructor=true, genConstDefs=false)")
+ @Deprecated
+ private void __metadata() {}
+
+
+ //@formatter:on
+ // End of generated code
+
+}
diff --git a/core/java/android/content/pm/IPackageInstallerSession.aidl b/core/java/android/content/pm/IPackageInstallerSession.aidl
index fc20263fe00a..6ccbc36e26f6 100644
--- a/core/java/android/content/pm/IPackageInstallerSession.aidl
+++ b/core/java/android/content/pm/IPackageInstallerSession.aidl
@@ -16,6 +16,7 @@
package android.content.pm;
+import android.content.pm.Checksum;
import android.content.pm.DataLoaderParamsParcel;
import android.content.pm.IPackageInstallObserver2;
import android.content.IntentSender;
@@ -33,6 +34,8 @@ interface IPackageInstallerSession {
void write(String name, long offsetBytes, long lengthBytes, in ParcelFileDescriptor fd);
+ void addChecksums(String name, in Checksum[] checksums);
+
void removeSplit(String splitName);
void close();
diff --git a/core/java/android/content/pm/PackageInstaller.java b/core/java/android/content/pm/PackageInstaller.java
index e6ea04433114..9eb95a3f6707 100644
--- a/core/java/android/content/pm/PackageInstaller.java
+++ b/core/java/android/content/pm/PackageInstaller.java
@@ -1219,6 +1219,31 @@ public class PackageInstaller {
}
/**
+ * Adds installer-provided checksums for the APK file in session.
+ *
+ * @param name previously written as part of this session.
+ * @param checksums installer intends to make available via
+ * {@link PackageManager#getChecksums(String, boolean, int, List,
+ * IntentSender)}.
+ * @throws SecurityException if called after the session has been
+ * committed or abandoned.
+ */
+ public void addChecksums(@NonNull String name, @NonNull List<Checksum> checksums)
+ throws IOException {
+ Objects.requireNonNull(name);
+ Objects.requireNonNull(checksums);
+
+ try {
+ mSession.addChecksums(name, checksums.toArray(new Checksum[checksums.size()]));
+ } catch (RuntimeException e) {
+ ExceptionUtils.maybeUnwrapIOException(e);
+ throw e;
+ } catch (RemoteException e) {
+ throw e.rethrowFromSystemServer();
+ }
+ }
+
+ /**
* Attempt to commit everything staged in this session. This may require
* user intervention, and so it may not happen immediately. The final
* result of the commit will be reported through the given callback.
diff --git a/core/java/android/content/pm/PackageManager.java b/core/java/android/content/pm/PackageManager.java
index d2395ec9f69f..e68df3383642 100644
--- a/core/java/android/content/pm/PackageManager.java
+++ b/core/java/android/content/pm/PackageManager.java
@@ -7844,74 +7844,6 @@ public abstract class PackageManager {
}
/**
- * Root SHA256 hash of a 4K Merkle tree computed over all file bytes.
- * <a href="https://source.android.com/security/apksigning/v4">See APK Signature Scheme V4</a>.
- * <a href="https://git.kernel.org/pub/scm/fs/fscrypt/fscrypt.git/tree/Documentation/filesystems/fsverity.rst">See fs-verity</a>.
- *
- * @see #getChecksums
- */
- public static final int WHOLE_MERKLE_ROOT_4K_SHA256 = 0x00000001;
-
- /**
- * MD5 hash computed over all file bytes.
- *
- * @see #getChecksums
- */
- public static final int WHOLE_MD5 = 0x00000002;
-
- /**
- * SHA1 hash computed over all file bytes.
- *
- * @see #getChecksums
- */
- public static final int WHOLE_SHA1 = 0x00000004;
-
- /**
- * SHA256 hash computed over all file bytes.
- *
- * @see #getChecksums
- */
- public static final int WHOLE_SHA256 = 0x00000008;
-
- /**
- * SHA512 hash computed over all file bytes.
- *
- * @see #getChecksums
- */
- public static final int WHOLE_SHA512 = 0x00000010;
-
- /**
- * Root SHA256 hash of a 1M Merkle tree computed over protected content.
- * Excludes signing block.
- * <a href="https://source.android.com/security/apksigning/v2">See APK Signature Scheme V2</a>.
- *
- * @see #getChecksums
- */
- public static final int PARTIAL_MERKLE_ROOT_1M_SHA256 = 0x00000020;
-
- /**
- * Root SHA512 hash of a 1M Merkle tree computed over protected content.
- * Excludes signing block.
- * <a href="https://source.android.com/security/apksigning/v2">See APK Signature Scheme V2</a>.
- *
- * @see #getChecksums
- */
- public static final int PARTIAL_MERKLE_ROOT_1M_SHA512 = 0x00000040;
-
- /** @hide */
- @IntDef(flag = true, prefix = {"WHOLE_", "PARTIAL_"}, value = {
- WHOLE_MERKLE_ROOT_4K_SHA256,
- WHOLE_MD5,
- WHOLE_SHA1,
- WHOLE_SHA256,
- WHOLE_SHA512,
- PARTIAL_MERKLE_ROOT_1M_SHA256,
- PARTIAL_MERKLE_ROOT_1M_SHA512,
- })
- @Retention(RetentionPolicy.SOURCE)
- public @interface FileChecksumKind {}
-
- /**
* Trust any Installer to provide checksums for the package.
* @see #getChecksums
*/
@@ -7940,12 +7872,12 @@ public abstract class PackageManager {
* {@link #TRUST_ALL} will return checksums from any Installer,
* {@link #TRUST_NONE} disables optimized Installer-enforced checksums.
* @param statusReceiver called once when the results are available as
- * {@link #EXTRA_CHECKSUMS} of type FileChecksum[].
+ * {@link #EXTRA_CHECKSUMS} of type ApkChecksum[].
* @throws CertificateEncodingException if an encoding error occurs for trustedInstallers.
* @throws NameNotFoundException if a package with the given name cannot be found on the system.
*/
public void getChecksums(@NonNull String packageName, boolean includeSplits,
- @FileChecksumKind int required, @Nullable List<Certificate> trustedInstallers,
+ @Checksum.Kind int required, @Nullable List<Certificate> trustedInstallers,
@NonNull IntentSender statusReceiver)
throws CertificateEncodingException, IOException, NameNotFoundException {
throw new UnsupportedOperationException("getChecksums not implemented in subclass");
diff --git a/core/java/android/content/pm/UserInfo.java b/core/java/android/content/pm/UserInfo.java
index aca5b458a2d6..08b23b04f2ae 100644
--- a/core/java/android/content/pm/UserInfo.java
+++ b/core/java/android/content/pm/UserInfo.java
@@ -221,6 +221,14 @@ public class UserInfo implements Parcelable {
public boolean preCreated;
/**
+ * When {@code true}, it indicates this user was created by converting a {@link #preCreated}
+ * user.
+ *
+ * <p><b>NOTE: </b>only used for debugging purposes, it's not set when marshalled to a parcel.
+ */
+ public boolean convertedFromPreCreated;
+
+ /**
* Creates a UserInfo whose user type is determined automatically by the flags according to
* {@link #getDefaultUserType}; can only be used for user types handled there.
*/
@@ -413,6 +421,7 @@ public class UserInfo implements Parcelable {
lastLoggedInFingerprint = orig.lastLoggedInFingerprint;
partial = orig.partial;
preCreated = orig.preCreated;
+ convertedFromPreCreated = orig.convertedFromPreCreated;
profileGroupId = orig.profileGroupId;
restrictedProfileParentId = orig.restrictedProfileParentId;
guestToRemove = orig.guestToRemove;
@@ -440,6 +449,7 @@ public class UserInfo implements Parcelable {
+ ", type=" + userType
+ ", flags=" + flagsToString(flags)
+ (preCreated ? " (pre-created)" : "")
+ + (convertedFromPreCreated ? " (converted)" : "")
+ (partial ? " (partial)" : "")
+ "]";
}
diff --git a/core/java/android/util/FeatureFlagUtils.java b/core/java/android/util/FeatureFlagUtils.java
index 09736085954c..9cc6b9f83ede 100644
--- a/core/java/android/util/FeatureFlagUtils.java
+++ b/core/java/android/util/FeatureFlagUtils.java
@@ -66,6 +66,7 @@ public class FeatureFlagUtils {
DEFAULT_FLAGS.put("settings_tether_all_in_one", "false");
DEFAULT_FLAGS.put("settings_silky_home", "false");
+ DEFAULT_FLAGS.put("settings_contextual_home", "false");
}
/**
diff --git a/core/java/android/util/apk/ApkSignatureSchemeV3Verifier.java b/core/java/android/util/apk/ApkSignatureSchemeV3Verifier.java
index 5f963b019335..4d1402a0d6d6 100644
--- a/core/java/android/util/apk/ApkSignatureSchemeV3Verifier.java
+++ b/core/java/android/util/apk/ApkSignatureSchemeV3Verifier.java
@@ -25,6 +25,7 @@ import static android.util.apk.ApkSigningBlockUtils.getSignatureAlgorithmJcaKeyA
import static android.util.apk.ApkSigningBlockUtils.getSignatureAlgorithmJcaSignatureAlgorithm;
import static android.util.apk.ApkSigningBlockUtils.isSupportedSignatureAlgorithm;
import static android.util.apk.ApkSigningBlockUtils.readLengthPrefixedByteArray;
+import static android.util.apk.ApkSigningBlockUtils.verifyProofOfRotationStruct;
import android.os.Build;
import android.util.ArrayMap;
@@ -53,7 +54,6 @@ import java.security.spec.InvalidKeySpecException;
import java.security.spec.X509EncodedKeySpec;
import java.util.ArrayList;
import java.util.Arrays;
-import java.util.HashSet;
import java.util.List;
import java.util.Map;
@@ -90,9 +90,10 @@ public class ApkSignatureSchemeV3Verifier {
* associated with each signer.
*
* @throws SignatureNotFoundException if the APK is not signed using APK Signature Scheme v3.
- * @throws SecurityException if the APK Signature Scheme v3 signature of this APK does not
- * verify.
- * @throws IOException if an I/O error occurs while reading the APK file.
+ * @throws SecurityException if the APK Signature Scheme v3 signature of this APK does
+ * not
+ * verify.
+ * @throws IOException if an I/O error occurs while reading the APK file.
*/
public static VerifiedSigner verify(String apkFile)
throws SignatureNotFoundException, SecurityException, IOException {
@@ -106,7 +107,7 @@ public class ApkSignatureSchemeV3Verifier {
* Block while gathering signer information. The APK contents are not verified.
*
* @throws SignatureNotFoundException if the APK is not signed using APK Signature Scheme v3.
- * @throws IOException if an I/O error occurs while reading the APK file.
+ * @throws IOException if an I/O error occurs while reading the APK file.
*/
public static VerifiedSigner unsafeGetCertsWithoutVerification(String apkFile)
throws SignatureNotFoundException, SecurityException, IOException {
@@ -125,9 +126,10 @@ public class ApkSignatureSchemeV3Verifier {
* associated with each signer.
*
* @throws SignatureNotFoundException if the APK is not signed using APK Signature Scheme v3.
- * @throws SecurityException if an APK Signature Scheme v3 signature of this APK does not
- * verify.
- * @throws IOException if an I/O error occurs while reading the APK file.
+ * @throws SecurityException if an APK Signature Scheme v3 signature of this APK does
+ * not
+ * verify.
+ * @throws IOException if an I/O error occurs while reading the APK file.
*/
private static VerifiedSigner verify(RandomAccessFile apk, boolean verifyIntegrity)
throws SignatureNotFoundException, SecurityException, IOException {
@@ -140,7 +142,7 @@ public class ApkSignatureSchemeV3Verifier {
* additional information relevant for verifying the block against the file.
*
* @throws SignatureNotFoundException if the APK is not signed using APK Signature Scheme v3.
- * @throws IOException if an I/O error occurs while reading the APK file.
+ * @throws IOException if an I/O error occurs while reading the APK file.
*/
public static SignatureInfo findSignature(RandomAccessFile apk)
throws IOException, SignatureNotFoundException {
@@ -152,7 +154,7 @@ public class ApkSignatureSchemeV3Verifier {
* Block.
*
* @param signatureInfo APK Signature Scheme v3 Block and information relevant for verifying it
- * against the APK file.
+ * against the APK file.
*/
private static VerifiedSigner verify(
RandomAccessFile apk,
@@ -160,7 +162,7 @@ public class ApkSignatureSchemeV3Verifier {
boolean doVerifyIntegrity) throws SecurityException, IOException {
int signerCount = 0;
Map<Integer, byte[]> contentDigests = new ArrayMap<>();
- Pair<X509Certificate[], VerifiedProofOfRotation> result = null;
+ Pair<X509Certificate[], ApkSigningBlockUtils.VerifiedProofOfRotation> result = null;
CertificateFactory certFactory;
try {
certFactory = CertificateFactory.getInstance("X.509");
@@ -215,10 +217,11 @@ public class ApkSignatureSchemeV3Verifier {
return new VerifiedSigner(result.first, result.second, verityRootHash, contentDigests);
}
- private static Pair<X509Certificate[], VerifiedProofOfRotation> verifySigner(
- ByteBuffer signerBlock,
- Map<Integer, byte[]> contentDigests,
- CertificateFactory certFactory)
+ private static Pair<X509Certificate[], ApkSigningBlockUtils.VerifiedProofOfRotation>
+ verifySigner(
+ ByteBuffer signerBlock,
+ Map<Integer, byte[]> contentDigests,
+ CertificateFactory certFactory)
throws SecurityException, IOException, PlatformNotSupportedException {
ByteBuffer signedData = getLengthPrefixedSlice(signerBlock);
int minSdkVersion = signerBlock.getInt();
@@ -228,9 +231,9 @@ public class ApkSignatureSchemeV3Verifier {
// this signature isn't meant to be used with this platform, skip it.
throw new PlatformNotSupportedException(
"Signer not supported by this platform "
- + "version. This platform: " + Build.VERSION.SDK_INT
- + ", signer minSdkVersion: " + minSdkVersion
- + ", maxSdkVersion: " + maxSdkVersion);
+ + "version. This platform: " + Build.VERSION.SDK_INT
+ + ", signer minSdkVersion: " + minSdkVersion
+ + ", maxSdkVersion: " + maxSdkVersion);
}
ByteBuffer signatures = getLengthPrefixedSlice(signerBlock);
@@ -331,7 +334,8 @@ public class ApkSignatureSchemeV3Verifier {
&& (!MessageDigest.isEqual(previousSignerDigest, contentDigest))) {
throw new SecurityException(
getContentDigestAlgorithmJcaDigestAlgorithm(digestAlgorithm)
- + " contents digest does not match the digest specified by a preceding signer");
+ + " contents digest does not match the digest specified by a "
+ + "preceding signer");
}
ByteBuffer certificates = getLengthPrefixedSlice(signedData);
@@ -379,11 +383,11 @@ public class ApkSignatureSchemeV3Verifier {
private static final int PROOF_OF_ROTATION_ATTR_ID = 0x3ba06f8c;
- private static Pair<X509Certificate[], VerifiedProofOfRotation> verifyAdditionalAttributes(
- ByteBuffer attrs, List<X509Certificate> certs, CertificateFactory certFactory)
- throws IOException {
+ private static Pair<X509Certificate[], ApkSigningBlockUtils.VerifiedProofOfRotation>
+ verifyAdditionalAttributes(ByteBuffer attrs, List<X509Certificate> certs,
+ CertificateFactory certFactory) throws IOException {
X509Certificate[] certChain = certs.toArray(new X509Certificate[certs.size()]);
- VerifiedProofOfRotation por = null;
+ ApkSigningBlockUtils.VerifiedProofOfRotation por = null;
while (attrs.hasRemaining()) {
ByteBuffer attr = getLengthPrefixedSlice(attrs);
@@ -392,7 +396,7 @@ public class ApkSignatureSchemeV3Verifier {
+ "ID. Remaining: " + attr.remaining());
}
int id = attr.getInt();
- switch(id) {
+ switch (id) {
case PROOF_OF_ROTATION_ATTR_ID:
if (por != null) {
throw new SecurityException("Encountered multiple Proof-of-rotation records"
@@ -404,7 +408,7 @@ public class ApkSignatureSchemeV3Verifier {
try {
if (por.certs.size() > 0
&& !Arrays.equals(por.certs.get(por.certs.size() - 1).getEncoded(),
- certChain[0].getEncoded())) {
+ certChain[0].getEncoded())) {
throw new SecurityException("Terminal certificate in Proof-of-rotation"
+ " record does not match APK signing certificate");
}
@@ -422,96 +426,6 @@ public class ApkSignatureSchemeV3Verifier {
return Pair.create(certChain, por);
}
- private static VerifiedProofOfRotation verifyProofOfRotationStruct(
- ByteBuffer porBuf,
- CertificateFactory certFactory)
- throws SecurityException, IOException {
- int levelCount = 0;
- int lastSigAlgorithm = -1;
- X509Certificate lastCert = null;
- List<X509Certificate> certs = new ArrayList<>();
- List<Integer> flagsList = new ArrayList<>();
-
- // Proof-of-rotation struct:
- // A uint32 version code followed by basically a singly linked list of nodes, called levels
- // here, each of which have the following structure:
- // * length-prefix for the entire level
- // - length-prefixed signed data (if previous level exists)
- // * length-prefixed X509 Certificate
- // * uint32 signature algorithm ID describing how this signed data was signed
- // - uint32 flags describing how to treat the cert contained in this level
- // - uint32 signature algorithm ID to use to verify the signature of the next level. The
- // algorithm here must match the one in the signed data section of the next level.
- // - length-prefixed signature over the signed data in this level. The signature here
- // is verified using the certificate from the previous level.
- // The linking is provided by the certificate of each level signing the one of the next.
-
- try {
-
- // get the version code, but don't do anything with it: creator knew about all our flags
- porBuf.getInt();
- HashSet<X509Certificate> certHistorySet = new HashSet<>();
- while (porBuf.hasRemaining()) {
- levelCount++;
- ByteBuffer level = getLengthPrefixedSlice(porBuf);
- ByteBuffer signedData = getLengthPrefixedSlice(level);
- int flags = level.getInt();
- int sigAlgorithm = level.getInt();
- byte[] signature = readLengthPrefixedByteArray(level);
-
- if (lastCert != null) {
- // Use previous level cert to verify current level
- Pair<String, ? extends AlgorithmParameterSpec> sigAlgParams =
- getSignatureAlgorithmJcaSignatureAlgorithm(lastSigAlgorithm);
- PublicKey publicKey = lastCert.getPublicKey();
- Signature sig = Signature.getInstance(sigAlgParams.first);
- sig.initVerify(publicKey);
- if (sigAlgParams.second != null) {
- sig.setParameter(sigAlgParams.second);
- }
- sig.update(signedData);
- if (!sig.verify(signature)) {
- throw new SecurityException("Unable to verify signature of certificate #"
- + levelCount + " using " + sigAlgParams.first + " when verifying"
- + " Proof-of-rotation record");
- }
- }
-
- signedData.rewind();
- byte[] encodedCert = readLengthPrefixedByteArray(signedData);
- int signedSigAlgorithm = signedData.getInt();
- if (lastCert != null && lastSigAlgorithm != signedSigAlgorithm) {
- throw new SecurityException("Signing algorithm ID mismatch for certificate #"
- + levelCount + " when verifying Proof-of-rotation record");
- }
- lastCert = (X509Certificate)
- certFactory.generateCertificate(new ByteArrayInputStream(encodedCert));
- lastCert = new VerbatimX509Certificate(lastCert, encodedCert);
-
- lastSigAlgorithm = sigAlgorithm;
- if (certHistorySet.contains(lastCert)) {
- throw new SecurityException("Encountered duplicate entries in "
- + "Proof-of-rotation record at certificate #" + levelCount + ". All "
- + "signing certificates should be unique");
- }
- certHistorySet.add(lastCert);
- certs.add(lastCert);
- flagsList.add(flags);
- }
- } catch (IOException | BufferUnderflowException e) {
- throw new IOException("Failed to parse Proof-of-rotation record", e);
- } catch (NoSuchAlgorithmException | InvalidKeyException
- | InvalidAlgorithmParameterException | SignatureException e) {
- throw new SecurityException(
- "Failed to verify signature over signed data for certificate #"
- + levelCount + " when verifying Proof-of-rotation record", e);
- } catch (CertificateException e) {
- throw new SecurityException("Failed to decode certificate #" + levelCount
- + " when verifying Proof-of-rotation record", e);
- }
- return new VerifiedProofOfRotation(certs, flagsList);
- }
-
static byte[] getVerityRootHash(String apkPath)
throws IOException, SignatureNotFoundException, SecurityException {
try (RandomAccessFile apk = new RandomAccessFile(apkPath, "r")) {
@@ -523,7 +437,7 @@ public class ApkSignatureSchemeV3Verifier {
static byte[] generateApkVerity(String apkPath, ByteBufferFactory bufferFactory)
throws IOException, SignatureNotFoundException, SecurityException, DigestException,
- NoSuchAlgorithmException {
+ NoSuchAlgorithmException {
try (RandomAccessFile apk = new RandomAccessFile(apkPath, "r")) {
SignatureInfo signatureInfo = findSignature(apk);
return VerityBuilder.generateApkVerity(apkPath, bufferFactory, signatureInfo);
@@ -532,7 +446,7 @@ public class ApkSignatureSchemeV3Verifier {
static byte[] generateApkVerityRootHash(String apkPath)
throws NoSuchAlgorithmException, DigestException, IOException,
- SignatureNotFoundException {
+ SignatureNotFoundException {
try (RandomAccessFile apk = new RandomAccessFile(apkPath, "r")) {
SignatureInfo signatureInfo = findSignature(apk);
VerifiedSigner vSigner = verify(apk, false);
@@ -545,35 +459,21 @@ public class ApkSignatureSchemeV3Verifier {
}
/**
- * Verified processed proof of rotation.
- *
- * @hide for internal use only.
- */
- public static class VerifiedProofOfRotation {
- public final List<X509Certificate> certs;
- public final List<Integer> flagsList;
-
- public VerifiedProofOfRotation(List<X509Certificate> certs, List<Integer> flagsList) {
- this.certs = certs;
- this.flagsList = flagsList;
- }
- }
-
- /**
* Verified APK Signature Scheme v3 signer, including the proof of rotation structure.
*
* @hide for internal use only.
*/
public static class VerifiedSigner {
public final X509Certificate[] certs;
- public final VerifiedProofOfRotation por;
+ public final ApkSigningBlockUtils.VerifiedProofOfRotation por;
public final byte[] verityRootHash;
// Algorithm -> digest map of signed digests in the signature.
// All these are verified if requested.
public final Map<Integer, byte[]> contentDigests;
- public VerifiedSigner(X509Certificate[] certs, VerifiedProofOfRotation por,
+ public VerifiedSigner(X509Certificate[] certs,
+ ApkSigningBlockUtils.VerifiedProofOfRotation por,
byte[] verityRootHash, Map<Integer, byte[]> contentDigests) {
this.certs = certs;
this.por = por;
diff --git a/core/java/android/util/apk/ApkSigningBlockUtils.java b/core/java/android/util/apk/ApkSigningBlockUtils.java
index 021f232979ef..c97c995641d1 100644
--- a/core/java/android/util/apk/ApkSigningBlockUtils.java
+++ b/core/java/android/util/apk/ApkSigningBlockUtils.java
@@ -19,6 +19,7 @@ package android.util.apk;
import android.util.ArrayMap;
import android.util.Pair;
+import java.io.ByteArrayInputStream;
import java.io.FileDescriptor;
import java.io.IOException;
import java.io.RandomAccessFile;
@@ -26,12 +27,23 @@ import java.nio.BufferUnderflowException;
import java.nio.ByteBuffer;
import java.nio.ByteOrder;
import java.security.DigestException;
+import java.security.InvalidAlgorithmParameterException;
+import java.security.InvalidKeyException;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
+import java.security.PublicKey;
+import java.security.Signature;
+import java.security.SignatureException;
+import java.security.cert.CertificateException;
+import java.security.cert.CertificateFactory;
+import java.security.cert.X509Certificate;
import java.security.spec.AlgorithmParameterSpec;
import java.security.spec.MGF1ParameterSpec;
import java.security.spec.PSSParameterSpec;
+import java.util.ArrayList;
import java.util.Arrays;
+import java.util.HashSet;
+import java.util.List;
import java.util.Map;
/**
@@ -51,9 +63,8 @@ public final class ApkSigningBlockUtils {
* @param blockId the ID value in the APK Signing Block's sequence of ID-value pairs
* identifying the appropriate block to find, e.g. the APK Signature Scheme v2
* block ID.
- *
* @throws SignatureNotFoundException if the APK is not signed using this scheme.
- * @throws IOException if an I/O error occurs while reading the APK file.
+ * @throws IOException if an I/O error occurs while reading the APK file.
*/
static SignatureInfo findSignature(RandomAccessFile apk, int blockId)
throws IOException, SignatureNotFoundException {
@@ -377,7 +388,7 @@ public final class ApkSigningBlockUtils {
/**
* Returns the ZIP End of Central Directory (EoCD) and its offset in the file.
*
- * @throws IOException if an I/O error occurs while reading the file.
+ * @throws IOException if an I/O error occurs while reading the file.
* @throws SignatureNotFoundException if the EoCD could not be found.
*/
static Pair<ByteBuffer, Long> getEocd(RandomAccessFile apk)
@@ -398,13 +409,13 @@ public final class ApkSigningBlockUtils {
if (centralDirOffset > eocdOffset) {
throw new SignatureNotFoundException(
"ZIP Central Directory offset out of range: " + centralDirOffset
- + ". ZIP End of Central Directory offset: " + eocdOffset);
+ + ". ZIP End of Central Directory offset: " + eocdOffset);
}
long centralDirSize = ZipUtils.getZipEocdCentralDirectorySizeBytes(eocd);
if (centralDirOffset + centralDirSize != eocdOffset) {
throw new SignatureNotFoundException(
"ZIP Central Directory is not immediately followed by End of Central"
- + " Directory");
+ + " Directory");
}
return centralDirOffset;
}
@@ -687,7 +698,7 @@ public final class ApkSigningBlockUtils {
static Pair<ByteBuffer, Long> findApkSigningBlock(
RandomAccessFile apk, long centralDirOffset)
- throws IOException, SignatureNotFoundException {
+ throws IOException, SignatureNotFoundException {
// FORMAT:
// OFFSET DATA TYPE DESCRIPTION
// * @+0 bytes uint64: size in bytes (excluding this field)
@@ -806,4 +817,108 @@ public final class ApkSigningBlockUtils {
}
}
+ static VerifiedProofOfRotation verifyProofOfRotationStruct(
+ ByteBuffer porBuf,
+ CertificateFactory certFactory)
+ throws SecurityException, IOException {
+ int levelCount = 0;
+ int lastSigAlgorithm = -1;
+ X509Certificate lastCert = null;
+ List<X509Certificate> certs = new ArrayList<>();
+ List<Integer> flagsList = new ArrayList<>();
+
+ // Proof-of-rotation struct:
+ // A uint32 version code followed by basically a singly linked list of nodes, called levels
+ // here, each of which have the following structure:
+ // * length-prefix for the entire level
+ // - length-prefixed signed data (if previous level exists)
+ // * length-prefixed X509 Certificate
+ // * uint32 signature algorithm ID describing how this signed data was signed
+ // - uint32 flags describing how to treat the cert contained in this level
+ // - uint32 signature algorithm ID to use to verify the signature of the next level. The
+ // algorithm here must match the one in the signed data section of the next level.
+ // - length-prefixed signature over the signed data in this level. The signature here
+ // is verified using the certificate from the previous level.
+ // The linking is provided by the certificate of each level signing the one of the next.
+
+ try {
+
+ // get the version code, but don't do anything with it: creator knew about all our flags
+ porBuf.getInt();
+ HashSet<X509Certificate> certHistorySet = new HashSet<>();
+ while (porBuf.hasRemaining()) {
+ levelCount++;
+ ByteBuffer level = getLengthPrefixedSlice(porBuf);
+ ByteBuffer signedData = getLengthPrefixedSlice(level);
+ int flags = level.getInt();
+ int sigAlgorithm = level.getInt();
+ byte[] signature = readLengthPrefixedByteArray(level);
+
+ if (lastCert != null) {
+ // Use previous level cert to verify current level
+ Pair<String, ? extends AlgorithmParameterSpec> sigAlgParams =
+ getSignatureAlgorithmJcaSignatureAlgorithm(lastSigAlgorithm);
+ PublicKey publicKey = lastCert.getPublicKey();
+ Signature sig = Signature.getInstance(sigAlgParams.first);
+ sig.initVerify(publicKey);
+ if (sigAlgParams.second != null) {
+ sig.setParameter(sigAlgParams.second);
+ }
+ sig.update(signedData);
+ if (!sig.verify(signature)) {
+ throw new SecurityException("Unable to verify signature of certificate #"
+ + levelCount + " using " + sigAlgParams.first + " when verifying"
+ + " Proof-of-rotation record");
+ }
+ }
+
+ signedData.rewind();
+ byte[] encodedCert = readLengthPrefixedByteArray(signedData);
+ int signedSigAlgorithm = signedData.getInt();
+ if (lastCert != null && lastSigAlgorithm != signedSigAlgorithm) {
+ throw new SecurityException("Signing algorithm ID mismatch for certificate #"
+ + levelCount + " when verifying Proof-of-rotation record");
+ }
+ lastCert = (X509Certificate)
+ certFactory.generateCertificate(new ByteArrayInputStream(encodedCert));
+ lastCert = new VerbatimX509Certificate(lastCert, encodedCert);
+
+ lastSigAlgorithm = sigAlgorithm;
+ if (certHistorySet.contains(lastCert)) {
+ throw new SecurityException("Encountered duplicate entries in "
+ + "Proof-of-rotation record at certificate #" + levelCount + ". All "
+ + "signing certificates should be unique");
+ }
+ certHistorySet.add(lastCert);
+ certs.add(lastCert);
+ flagsList.add(flags);
+ }
+ } catch (IOException | BufferUnderflowException e) {
+ throw new IOException("Failed to parse Proof-of-rotation record", e);
+ } catch (NoSuchAlgorithmException | InvalidKeyException
+ | InvalidAlgorithmParameterException | SignatureException e) {
+ throw new SecurityException(
+ "Failed to verify signature over signed data for certificate #"
+ + levelCount + " when verifying Proof-of-rotation record", e);
+ } catch (CertificateException e) {
+ throw new SecurityException("Failed to decode certificate #" + levelCount
+ + " when verifying Proof-of-rotation record", e);
+ }
+ return new VerifiedProofOfRotation(certs, flagsList);
+ }
+
+ /**
+ * Verified processed proof of rotation.
+ *
+ * @hide for internal use only.
+ */
+ public static class VerifiedProofOfRotation {
+ public final List<X509Certificate> certs;
+ public final List<Integer> flagsList;
+
+ public VerifiedProofOfRotation(List<X509Certificate> certs, List<Integer> flagsList) {
+ this.certs = certs;
+ this.flagsList = flagsList;
+ }
+ }
}
diff --git a/core/java/android/util/apk/SourceStampVerificationResult.java b/core/java/android/util/apk/SourceStampVerificationResult.java
index 2edaf623fb94..8b9eee2f796e 100644
--- a/core/java/android/util/apk/SourceStampVerificationResult.java
+++ b/core/java/android/util/apk/SourceStampVerificationResult.java
@@ -19,6 +19,8 @@ package android.util.apk;
import android.annotation.Nullable;
import java.security.cert.Certificate;
+import java.util.Collections;
+import java.util.List;
/**
* A class encapsulating the result from the source stamp verifier
@@ -32,12 +34,15 @@ public final class SourceStampVerificationResult {
private final boolean mPresent;
private final boolean mVerified;
private final Certificate mCertificate;
+ private final List<? extends Certificate> mCertificateLineage;
private SourceStampVerificationResult(
- boolean present, boolean verified, @Nullable Certificate certificate) {
+ boolean present, boolean verified, @Nullable Certificate certificate,
+ List<? extends Certificate> certificateLineage) {
this.mPresent = present;
this.mVerified = verified;
this.mCertificate = certificate;
+ this.mCertificateLineage = certificateLineage;
}
public boolean isPresent() {
@@ -52,6 +57,10 @@ public final class SourceStampVerificationResult {
return mCertificate;
}
+ public List<? extends Certificate> getCertificateLineage() {
+ return mCertificateLineage;
+ }
+
/**
* Create a non-present source stamp outcome.
*
@@ -59,18 +68,21 @@ public final class SourceStampVerificationResult {
*/
public static SourceStampVerificationResult notPresent() {
return new SourceStampVerificationResult(
- /* present= */ false, /* verified= */ false, /* certificate= */ null);
+ /* present= */ false, /* verified= */ false, /* certificate= */
+ null, /* certificateLineage= */ Collections.emptyList());
}
/**
* Create a verified source stamp outcome.
*
- * @param certificate The source stamp certificate.
+ * @param certificate The source stamp certificate.
+ * @param certificateLineage The proof-of-rotation lineage for the source stamp.
* @return A verified source stamp result, and the source stamp certificate.
*/
- public static SourceStampVerificationResult verified(Certificate certificate) {
+ public static SourceStampVerificationResult verified(Certificate certificate,
+ List<? extends Certificate> certificateLineage) {
return new SourceStampVerificationResult(
- /* present= */ true, /* verified= */ true, certificate);
+ /* present= */ true, /* verified= */ true, certificate, certificateLineage);
}
/**
@@ -80,6 +92,7 @@ public final class SourceStampVerificationResult {
*/
public static SourceStampVerificationResult notVerified() {
return new SourceStampVerificationResult(
- /* present= */ true, /* verified= */ false, /* certificate= */ null);
+ /* present= */ true, /* verified= */ false, /* certificate= */
+ null, /* certificateLineage= */ Collections.emptyList());
}
}
diff --git a/core/java/android/util/apk/SourceStampVerifier.java b/core/java/android/util/apk/SourceStampVerifier.java
index 5fc242353d51..f9e312146ccf 100644
--- a/core/java/android/util/apk/SourceStampVerifier.java
+++ b/core/java/android/util/apk/SourceStampVerifier.java
@@ -23,6 +23,7 @@ import static android.util.apk.ApkSigningBlockUtils.getSignatureAlgorithmContent
import static android.util.apk.ApkSigningBlockUtils.getSignatureAlgorithmJcaSignatureAlgorithm;
import static android.util.apk.ApkSigningBlockUtils.isSupportedSignatureAlgorithm;
import static android.util.apk.ApkSigningBlockUtils.readLengthPrefixedByteArray;
+import static android.util.apk.ApkSigningBlockUtils.verifyProofOfRotationStruct;
import android.util.Pair;
import android.util.Slog;
@@ -44,12 +45,14 @@ import java.security.PublicKey;
import java.security.Signature;
import java.security.SignatureException;
import java.security.cert.Certificate;
+import java.security.cert.CertificateEncodingException;
import java.security.cert.CertificateException;
import java.security.cert.CertificateFactory;
import java.security.cert.X509Certificate;
import java.security.spec.AlgorithmParameterSpec;
import java.util.ArrayList;
import java.util.Arrays;
+import java.util.Collections;
import java.util.Comparator;
import java.util.HashMap;
import java.util.List;
@@ -76,6 +79,7 @@ public abstract class SourceStampVerifier {
private static final int APK_SIGNATURE_SCHEME_V2_BLOCK_ID = 0x7109871a;
private static final int APK_SIGNATURE_SCHEME_V3_BLOCK_ID = 0xf05368c0;
private static final int SOURCE_STAMP_BLOCK_ID = 0x6dff800d;
+ private static final int PROOF_OF_ROTATION_ATTR_ID = 0x9d6303f7;
private static final int VERSION_JAR_SIGNATURE_SCHEME = 1;
private static final int VERSION_APK_SIGNATURE_SCHEME_V2 = 2;
@@ -85,11 +89,13 @@ public abstract class SourceStampVerifier {
private static final String SOURCE_STAMP_CERTIFICATE_HASH_ZIP_ENTRY_NAME = "stamp-cert-sha256";
/** Hidden constructor to prevent instantiation. */
- private SourceStampVerifier() {}
+ private SourceStampVerifier() {
+ }
- /** Verifies SourceStamp present in a list of APKs. */
+ /** Verifies SourceStamp present in a list of (split) APKs for the same app. */
public static SourceStampVerificationResult verify(List<String> apkFiles) {
Certificate stampCertificate = null;
+ List<? extends Certificate> stampCertificateLineage = Collections.emptyList();
for (String apkFile : apkFiles) {
SourceStampVerificationResult sourceStampVerificationResult = verify(apkFile);
if (!sourceStampVerificationResult.isPresent()
@@ -97,12 +103,15 @@ public abstract class SourceStampVerifier {
return sourceStampVerificationResult;
}
if (stampCertificate != null
- && !stampCertificate.equals(sourceStampVerificationResult.getCertificate())) {
+ && (!stampCertificate.equals(sourceStampVerificationResult.getCertificate())
+ || !stampCertificateLineage.equals(
+ sourceStampVerificationResult.getCertificateLineage()))) {
return SourceStampVerificationResult.notVerified();
}
stampCertificate = sourceStampVerificationResult.getCertificate();
+ stampCertificateLineage = sourceStampVerificationResult.getCertificateLineage();
}
- return SourceStampVerificationResult.verified(stampCertificate);
+ return SourceStampVerificationResult.verified(stampCertificate, stampCertificateLineage);
}
/** Verifies SourceStamp present in the provided APK. */
@@ -177,21 +186,44 @@ public abstract class SourceStampVerifier {
"No signatures found for signature scheme %d",
signatureSchemeDigest.getKey()));
}
+ ByteBuffer signatures = ApkSigningBlockUtils.getLengthPrefixedSlice(
+ signedSignatureSchemeData.get(signatureSchemeDigest.getKey()));
verifySourceStampSignature(
- signedSignatureSchemeData.get(signatureSchemeDigest.getKey()),
+ signatureSchemeDigest.getValue(),
sourceStampCertificate,
- signatureSchemeDigest.getValue());
+ signatures);
}
- return SourceStampVerificationResult.verified(sourceStampCertificate);
+ List<? extends Certificate> sourceStampCertificateLineage = Collections.emptyList();
+ if (sourceStampBlockData.hasRemaining()) {
+ // The stamp block contains some additional attributes.
+ ByteBuffer stampAttributeData = getLengthPrefixedSlice(sourceStampBlockData);
+ ByteBuffer stampAttributeDataSignatures = getLengthPrefixedSlice(sourceStampBlockData);
+
+ byte[] stampAttributeBytes = new byte[stampAttributeData.remaining()];
+ stampAttributeData.get(stampAttributeBytes);
+ stampAttributeData.flip();
+
+ verifySourceStampSignature(stampAttributeBytes, sourceStampCertificate,
+ stampAttributeDataSignatures);
+ ApkSigningBlockUtils.VerifiedProofOfRotation verifiedProofOfRotation =
+ verifySourceStampAttributes(stampAttributeData, sourceStampCertificate);
+ if (verifiedProofOfRotation != null) {
+ sourceStampCertificateLineage = verifiedProofOfRotation.certs;
+ }
+ }
+
+ return SourceStampVerificationResult.verified(sourceStampCertificate,
+ sourceStampCertificateLineage);
}
/**
* Verify the SourceStamp certificate found in the signing block is the same as the SourceStamp
* certificate found in the APK. It returns the verified certificate.
*
- * @param sourceStampBlockData the source stamp block in the APK signing block which contains
- * the certificate used to sign the stamp digests.
+ * @param sourceStampBlockData the source stamp block in the APK signing block which
+ * contains
+ * the certificate used to sign the stamp digests.
* @param sourceStampCertificateDigest the source stamp certificate digest found in the APK.
*/
private static X509Certificate verifySourceStampCertificate(
@@ -230,16 +262,16 @@ public abstract class SourceStampVerifier {
* Verify the SourceStamp signature found in the signing block is signed by the SourceStamp
* certificate found in the APK.
*
- * @param signedBlockData the source stamp block in the APK signing block which contains the
- * stamp signed digests.
+ * @param data the digest to be verified being signed by the source stamp
+ * certificate.
* @param sourceStampCertificate the source stamp certificate used to sign the stamp digests.
- * @param digest the digest to be verified being signed by the source stamp certificate.
+ * @param signatures the source stamp block in the APK signing block which contains
+ * the stamp signed digests.
*/
- private static void verifySourceStampSignature(
- ByteBuffer signedBlockData, X509Certificate sourceStampCertificate, byte[] digest)
+ private static void verifySourceStampSignature(byte[] data,
+ X509Certificate sourceStampCertificate, ByteBuffer signatures)
throws IOException {
// Parse the signatures block and identify supported signatures
- ByteBuffer signatures = ApkSigningBlockUtils.getLengthPrefixedSlice(signedBlockData);
int signatureCount = 0;
int bestSigAlgorithm = -1;
byte[] bestSigAlgorithmSignatureBytes = null;
@@ -285,7 +317,7 @@ public abstract class SourceStampVerifier {
if (jcaSignatureAlgorithmParams != null) {
sig.setParameter(jcaSignatureAlgorithmParams);
}
- sig.update(digest);
+ sig.update(data);
sigVerified = sig.verify(bestSigAlgorithmSignatureBytes);
} catch (InvalidKeyException
| InvalidAlgorithmParameterException
@@ -414,6 +446,46 @@ public abstract class SourceStampVerifier {
return result.array();
}
+ private static ApkSigningBlockUtils.VerifiedProofOfRotation verifySourceStampAttributes(
+ ByteBuffer stampAttributeData,
+ X509Certificate sourceStampCertificate)
+ throws IOException {
+ CertificateFactory certFactory;
+ try {
+ certFactory = CertificateFactory.getInstance("X.509");
+ } catch (CertificateException e) {
+ throw new RuntimeException("Failed to obtain X.509 CertificateFactory", e);
+ }
+ ByteBuffer stampAttributes = getLengthPrefixedSlice(stampAttributeData);
+ ApkSigningBlockUtils.VerifiedProofOfRotation verifiedProofOfRotation = null;
+ while (stampAttributes.hasRemaining()) {
+ ByteBuffer attribute = getLengthPrefixedSlice(stampAttributes);
+ int id = attribute.getInt();
+ if (id == PROOF_OF_ROTATION_ATTR_ID) {
+ if (verifiedProofOfRotation != null) {
+ throw new SecurityException("Encountered multiple Proof-of-rotation records"
+ + " when verifying source stamp signature");
+ }
+ verifiedProofOfRotation = verifyProofOfRotationStruct(attribute, certFactory);
+ // Make sure that the last certificate in the Proof-of-rotation record matches
+ // the one used to sign this APK.
+ try {
+ if (verifiedProofOfRotation.certs.size() > 0
+ && !Arrays.equals(verifiedProofOfRotation.certs.get(
+ verifiedProofOfRotation.certs.size() - 1).getEncoded(),
+ sourceStampCertificate.getEncoded())) {
+ throw new SecurityException("Terminal certificate in Proof-of-rotation"
+ + " record does not match source stamp certificate");
+ }
+ } catch (CertificateEncodingException e) {
+ throw new SecurityException("Failed to encode certificate when comparing"
+ + " Proof-of-rotation record and source stamp certificate", e);
+ }
+ }
+ }
+ return verifiedProofOfRotation;
+ }
+
private static byte[] computeSha256Digest(byte[] input) {
try {
MessageDigest messageDigest = MessageDigest.getInstance("SHA-256");
diff --git a/core/java/android/view/ViewDebug.java b/core/java/android/view/ViewDebug.java
index 4303d705f945..100b4fdbf446 100644
--- a/core/java/android/view/ViewDebug.java
+++ b/core/java/android/view/ViewDebug.java
@@ -531,7 +531,7 @@ public class ViewDebug {
@UnsupportedAppUsage
static void dispatchCommand(View view, String command, String parameters,
OutputStream clientStream) throws IOException {
- // Paranoid but safe...
+ // Just being cautious...
view = view.getRootView();
if (REMOTE_COMMAND_DUMP.equalsIgnoreCase(command)) {
diff --git a/core/java/com/android/internal/config/sysui/SystemUiDeviceConfigFlags.java b/core/java/com/android/internal/config/sysui/SystemUiDeviceConfigFlags.java
index 8b4fddbec03c..6314fcbde333 100644
--- a/core/java/com/android/internal/config/sysui/SystemUiDeviceConfigFlags.java
+++ b/core/java/com/android/internal/config/sysui/SystemUiDeviceConfigFlags.java
@@ -395,6 +395,11 @@ public final class SystemUiDeviceConfigFlags {
public static final String PIP_PINCH_RESIZE = "pip_pinch_resize";
/**
+ * (boolean) Whether to enable stashing for PIP.
+ */
+ public static final String PIP_STASHING = "pip_stashing";
+
+ /**
* (float) Bottom height in DP for Back Gesture.
*/
public static final String BACK_GESTURE_BOTTOM_HEIGHT = "back_gesture_bottom_height";
diff --git a/core/java/com/android/internal/util/Preconditions.java b/core/java/com/android/internal/util/Preconditions.java
index 937b9426476a..dae649a903d5 100644
--- a/core/java/com/android/internal/util/Preconditions.java
+++ b/core/java/com/android/internal/util/Preconditions.java
@@ -207,7 +207,7 @@ public class Preconditions {
* @param message the message of the security exception to be thrown
* @throws SecurityException if {@code expression} is false
*/
- public static void checkSecurity(final boolean expression, final String message) {
+ public static void checkCallAuthorization(final boolean expression, final String message) {
if (!expression) {
throw new SecurityException(message);
}
diff --git a/core/res/res/values-gl/strings.xml b/core/res/res/values-gl/strings.xml
index b3a4542614ac..0f281469bbf1 100644
--- a/core/res/res/values-gl/strings.xml
+++ b/core/res/res/values-gl/strings.xml
@@ -852,7 +852,7 @@
<string name="lockscreen_transport_pause_description" msgid="6705284702135372494">"Pausar"</string>
<string name="lockscreen_transport_play_description" msgid="106868788691652733">"Reproducir"</string>
<string name="lockscreen_transport_stop_description" msgid="1449552232598355348">"Deter"</string>
- <string name="lockscreen_transport_rew_description" msgid="7680106856221622779">"Rebobinar"</string>
+ <string name="lockscreen_transport_rew_description" msgid="7680106856221622779">"Retroceder"</string>
<string name="lockscreen_transport_ffw_description" msgid="4763794746640196772">"Avance rápido"</string>
<string name="emergency_calls_only" msgid="3057351206678279851">"Só chamadas de emerxencia"</string>
<string name="lockscreen_network_locked_message" msgid="2814046965899249635">"Bloqueada pola rede"</string>
diff --git a/core/res/res/values-sv/strings.xml b/core/res/res/values-sv/strings.xml
index e1442437df77..3711e2bf0530 100644
--- a/core/res/res/values-sv/strings.xml
+++ b/core/res/res/values-sv/strings.xml
@@ -1829,7 +1829,7 @@
<item quantity="other">I %d tim</item>
<item quantity="one">I en 1 tim</item>
</plurals>
- <string name="zen_mode_until" msgid="2250286190237669079">"Till kl. <xliff:g id="FORMATTEDTIME">%1$s</xliff:g>"</string>
+ <string name="zen_mode_until" msgid="2250286190237669079">"Till <xliff:g id="FORMATTEDTIME">%1$s</xliff:g>"</string>
<string name="zen_mode_alarm" msgid="7046911727540499275">"Till <xliff:g id="FORMATTEDTIME">%1$s</xliff:g> (nästa alarm)"</string>
<string name="zen_mode_forever" msgid="740585666364912448">"Tills du stänger av"</string>
<string name="zen_mode_forever_dnd" msgid="3423201955704180067">"Tills du inaktiverar Stör ej"</string>
diff --git a/core/res/res/values-sw/strings.xml b/core/res/res/values-sw/strings.xml
index 22736d8bca87..23b6c3b5a029 100644
--- a/core/res/res/values-sw/strings.xml
+++ b/core/res/res/values-sw/strings.xml
@@ -305,7 +305,7 @@
<string name="permgroupdesc_sms" msgid="5726462398070064542">"itume na iangalie SMS"</string>
<string name="permgrouplab_storage" msgid="1938416135375282333">"Faili na maudhui"</string>
<string name="permgroupdesc_storage" msgid="6351503740613026600">"ifikie picha, maudhui na faili kwenye kifaa chako"</string>
- <string name="permgrouplab_microphone" msgid="2480597427667420076">"Kipokea sauti"</string>
+ <string name="permgrouplab_microphone" msgid="2480597427667420076">"Maikrofoni"</string>
<string name="permgroupdesc_microphone" msgid="1047786732792487722">"irekodi sauti"</string>
<string name="permgrouplab_activityRecognition" msgid="3324466667921775766">"Shughuli za kimwili"</string>
<string name="permgroupdesc_activityRecognition" msgid="4725624819457670704">"ifikie shughuli zako za kimwili"</string>
diff --git a/core/tests/coretests/assets/SourceStampVerifierTest/stamp-lineage-invalid.apk b/core/tests/coretests/assets/SourceStampVerifierTest/stamp-lineage-invalid.apk
new file mode 100644
index 000000000000..f9777c3f5ca5
--- /dev/null
+++ b/core/tests/coretests/assets/SourceStampVerifierTest/stamp-lineage-invalid.apk
Binary files differ
diff --git a/core/tests/coretests/assets/SourceStampVerifierTest/stamp-lineage-valid.apk b/core/tests/coretests/assets/SourceStampVerifierTest/stamp-lineage-valid.apk
new file mode 100644
index 000000000000..955652e387b8
--- /dev/null
+++ b/core/tests/coretests/assets/SourceStampVerifierTest/stamp-lineage-valid.apk
Binary files differ
diff --git a/core/tests/coretests/src/android/util/apk/SourceStampVerifierTest.java b/core/tests/coretests/src/android/util/apk/SourceStampVerifierTest.java
index 81d54b57486c..bc0bddba2f20 100644
--- a/core/tests/coretests/src/android/util/apk/SourceStampVerifierTest.java
+++ b/core/tests/coretests/src/android/util/apk/SourceStampVerifierTest.java
@@ -17,6 +17,7 @@
package android.util.apk;
import static org.junit.Assert.assertArrayEquals;
+import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertNull;
@@ -198,6 +199,38 @@ public class SourceStampVerifierTest {
assertNull(result.getCertificate());
}
+ @Test
+ public void testSourceStamp_validStampLineage() throws Exception {
+ mPrimaryApk = getApk("SourceStampVerifierTest/stamp-lineage-valid.apk");
+ byte[] expectedStampCertHash = getSourceStampCertificateHashFromApk(mPrimaryApk);
+
+ SourceStampVerificationResult result =
+ SourceStampVerifier.verify(mPrimaryApk.getAbsolutePath());
+
+ assertTrue(result.isPresent());
+ assertTrue(result.isVerified());
+ assertNotNull(result.getCertificate());
+ byte[] actualStampCertHash =
+ MessageDigest.getInstance("SHA-256").digest(result.getCertificate().getEncoded());
+ assertArrayEquals(expectedStampCertHash, actualStampCertHash);
+ assertEquals(2, result.getCertificateLineage().size());
+ assertEquals(result.getCertificate(),
+ result.getCertificateLineage().get(result.getCertificateLineage().size() - 1));
+ }
+
+ @Test
+ public void testSourceStamp_invalidStampLineage() throws Exception {
+ mPrimaryApk = getApk("SourceStampVerifierTest/stamp-lineage-invalid.apk");
+
+ SourceStampVerificationResult result =
+ SourceStampVerifier.verify(mPrimaryApk.getAbsolutePath());
+
+ assertTrue(result.isPresent());
+ assertFalse(result.isVerified());
+ assertNull(result.getCertificate());
+ assertTrue(result.getCertificateLineage().isEmpty());
+ }
+
private File getApk(String apkPath) throws IOException {
File apk = File.createTempFile("SourceStampApk", ".apk");
try (InputStream inputStream = mContext.getAssets().open(apkPath)) {
diff --git a/graphics/java/android/graphics/ImageDecoder.java b/graphics/java/android/graphics/ImageDecoder.java
index ca37917f437f..4cac7fbb023b 100644
--- a/graphics/java/android/graphics/ImageDecoder.java
+++ b/graphics/java/android/graphics/ImageDecoder.java
@@ -301,7 +301,7 @@ public final class ImageDecoder implements AutoCloseable {
ImageDecoder decoder = null;
try {
- decoder = nCreate(fd, preferAnimation, source);
+ decoder = nCreate(fd, AssetFileDescriptor.UNKNOWN_LENGTH, preferAnimation, source);
} finally {
if (decoder == null) {
IoUtils.closeQuietly(stream);
@@ -349,7 +349,7 @@ public final class ImageDecoder implements AutoCloseable {
try {
try {
Os.lseek(fd, offset, SEEK_SET);
- decoder = nCreate(fd, preferAnimation, source);
+ decoder = nCreate(fd, assetFd.getDeclaredLength(), preferAnimation, source);
} catch (ErrnoException e) {
decoder = createFromStream(new FileInputStream(fd), true, preferAnimation, source);
}
@@ -2008,7 +2008,7 @@ public final class ImageDecoder implements AutoCloseable {
private static native ImageDecoder nCreate(InputStream is, byte[] storage,
boolean preferAnimation, Source src) throws IOException;
// The fd must be seekable.
- private static native ImageDecoder nCreate(FileDescriptor fd,
+ private static native ImageDecoder nCreate(FileDescriptor fd, long length,
boolean preferAnimation, Source src) throws IOException;
@NonNull
private static native Bitmap nDecodeBitmap(long nativePtr,
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/FullscreenTaskListener.java b/libs/WindowManager/Shell/src/com/android/wm/shell/FullscreenTaskListener.java
index d0051db9e9fc..9047b71253da 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/FullscreenTaskListener.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/FullscreenTaskListener.java
@@ -46,6 +46,12 @@ class FullscreenTaskListener implements ShellTaskOrganizer.TaskListener {
final SurfaceControl.Transaction t = mTransactionPool.acquire();
ProtoLog.v(ShellProtoLogGroup.WM_SHELL_TASK_ORG, "Fullscreen Task Appeared: #%d",
taskInfo.taskId);
+ // Reset several properties back to fullscreen (PiP, for example, leaves all these
+ // properties in a bad state).
+ t.setPosition(leash, 0, 0);
+ t.setWindowCrop(leash, null);
+ t.setAlpha(leash, 1f);
+ t.setMatrix(leash, 1, 0, 0, 1);
t.show(leash);
t.apply();
}
diff --git a/libs/hwui/jni/ImageDecoder.cpp b/libs/hwui/jni/ImageDecoder.cpp
index 1f4fd230e55e..da91d46b0738 100644
--- a/libs/hwui/jni/ImageDecoder.cpp
+++ b/libs/hwui/jni/ImageDecoder.cpp
@@ -152,7 +152,7 @@ static jobject native_create(JNIEnv* env, std::unique_ptr<SkStream> stream,
}
static jobject ImageDecoder_nCreateFd(JNIEnv* env, jobject /*clazz*/,
- jobject fileDescriptor, jboolean preferAnimation, jobject source) {
+ jobject fileDescriptor, jlong length, jboolean preferAnimation, jobject source) {
#ifndef __ANDROID__ // LayoutLib for Windows does not support F_DUPFD_CLOEXEC
return throw_exception(env, kSourceException, "Only supported on Android", nullptr, source);
#else
@@ -172,7 +172,14 @@ static jobject ImageDecoder_nCreateFd(JNIEnv* env, jobject /*clazz*/,
nullptr, source);
}
- std::unique_ptr<SkFILEStream> fileStream(new SkFILEStream(file));
+ std::unique_ptr<SkFILEStream> fileStream;
+ if (length == -1) {
+ // -1 corresponds to AssetFileDescriptor.UNKNOWN_LENGTH. Pass no length
+ // so SkFILEStream will figure out the size of the file on its own.
+ fileStream.reset(new SkFILEStream(file));
+ } else {
+ fileStream.reset(new SkFILEStream(file, length));
+ }
return native_create(env, std::move(fileStream), source, preferAnimation);
#endif
}
@@ -493,7 +500,7 @@ static const JNINativeMethod gImageDecoderMethods[] = {
{ "nCreate", "(Ljava/nio/ByteBuffer;IIZLandroid/graphics/ImageDecoder$Source;)Landroid/graphics/ImageDecoder;", (void*) ImageDecoder_nCreateByteBuffer },
{ "nCreate", "([BIIZLandroid/graphics/ImageDecoder$Source;)Landroid/graphics/ImageDecoder;", (void*) ImageDecoder_nCreateByteArray },
{ "nCreate", "(Ljava/io/InputStream;[BZLandroid/graphics/ImageDecoder$Source;)Landroid/graphics/ImageDecoder;", (void*) ImageDecoder_nCreateInputStream },
- { "nCreate", "(Ljava/io/FileDescriptor;ZLandroid/graphics/ImageDecoder$Source;)Landroid/graphics/ImageDecoder;", (void*) ImageDecoder_nCreateFd },
+ { "nCreate", "(Ljava/io/FileDescriptor;JZLandroid/graphics/ImageDecoder$Source;)Landroid/graphics/ImageDecoder;", (void*) ImageDecoder_nCreateFd },
{ "nDecodeBitmap", "(JLandroid/graphics/ImageDecoder;ZIILandroid/graphics/Rect;ZIZZZJZ)Landroid/graphics/Bitmap;",
(void*) ImageDecoder_nDecodeBitmap },
{ "nGetSampledSize","(JI)Landroid/util/Size;", (void*) ImageDecoder_nGetSampledSize },
diff --git a/location/java/android/location/ILocationManager.aidl b/location/java/android/location/ILocationManager.aidl
index 0e7eaa21888e..c1a98eabb2b7 100644
--- a/location/java/android/location/ILocationManager.aidl
+++ b/location/java/android/location/ILocationManager.aidl
@@ -46,13 +46,13 @@ import com.android.internal.location.ProviderProperties;
*/
interface ILocationManager
{
- Location getLastLocation(in LocationRequest request, String packageName, String attributionTag);
- void getCurrentLocation(in LocationRequest request, in ICancellationSignal cancellationSignal, in ILocationCallback callback, String packageName, String attributionTag, String listenerId);
+ Location getLastLocation(String provider, String packageName, String attributionTag);
+ void getCurrentLocation(String provider, in LocationRequest request, in ICancellationSignal cancellationSignal, in ILocationCallback callback, String packageName, String attributionTag, String listenerId);
- void registerLocationListener(in LocationRequest request, in ILocationListener listener, String packageName, String attributionTag, String listenerId);
+ void registerLocationListener(String provider, in LocationRequest request, in ILocationListener listener, String packageName, String attributionTag, String listenerId);
void unregisterLocationListener(in ILocationListener listener);
- void registerLocationPendingIntent(in LocationRequest request, in PendingIntent intent, String packageName, String attributionTag);
+ void registerLocationPendingIntent(String provider, in LocationRequest request, in PendingIntent intent, String packageName, String attributionTag);
void unregisterLocationPendingIntent(in PendingIntent intent);
void requestGeofence(in Geofence geofence, in PendingIntent intent, String packageName, String attributionTag);
diff --git a/location/java/android/location/LocationManager.java b/location/java/android/location/LocationManager.java
index 04bcbfc5f6b8..d7ef24170c24 100644
--- a/location/java/android/location/LocationManager.java
+++ b/location/java/android/location/LocationManager.java
@@ -670,11 +670,8 @@ public class LocationManager {
public Location getLastKnownLocation(@NonNull String provider) {
Preconditions.checkArgument(provider != null, "invalid null provider");
- LocationRequest request = LocationRequest.createFromDeprecatedProvider(
- provider, 0, 0, true);
-
try {
- return mService.getLastLocation(request, mContext.getPackageName(),
+ return mService.getLastLocation(provider, mContext.getPackageName(),
mContext.getAttributionTag());
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
@@ -682,23 +679,11 @@ public class LocationManager {
}
/**
- * Asynchronously returns a single current location fix. This may activate sensors in order to
- * compute a new location, unlike {@link #getLastKnownLocation(String)}, which will only return
- * a cached fix if available. The given callback will be invoked once and only once, either with
- * a valid location fix or with a null location fix if the provider was unable to generate a
- * valid location.
- *
- * <p>A client may supply an optional {@link CancellationSignal}. If this is used to cancel the
- * operation, no callback should be expected after the cancellation.
- *
- * <p>This method may return locations from the very recent past (on the order of several
- * seconds), but will never return older locations (for example, several minutes old or older).
- * Clients may rely upon the guarantee that if this method returns a location, it will represent
- * the best estimation of the location of the device in the present moment.
+ * Asynchronously returns a single current location fix from the given provider.
*
- * <p>Clients calling this method from the background may notice that the method fails to
- * determine a valid location fix more often than while in the foreground. Background
- * applications may be throttled in their location accesses to some degree.
+ * <p>See
+ * {@link #getCurrentLocation(String, LocationRequest, CancellationSignal, Executor, Consumer)}
+ * for more information.
*
* @param provider a provider listed by {@link #getAllProviders()}
* @param cancellationSignal an optional signal that allows for cancelling this call
@@ -714,16 +699,19 @@ public class LocationManager {
public void getCurrentLocation(@NonNull String provider,
@Nullable CancellationSignal cancellationSignal,
@NonNull @CallbackExecutor Executor executor, @NonNull Consumer<Location> consumer) {
- getCurrentLocation(LocationRequest.createFromDeprecatedProvider(provider, 0, 0, true),
+ getCurrentLocation(
+ provider,
+ new LocationRequest.Builder(0).build(),
cancellationSignal, executor, consumer);
}
/**
- * Asynchronously returns a single current location fix based on the given
- * {@link LocationRequest}.
+ * Asynchronously returns a single current location fix from the given provider based on the
+ * given {@link LocationRequest}.
*
- * <p>See {@link #getCurrentLocation(String, CancellationSignal, Executor, Consumer)} for more
- * information.
+ * <p>See
+ * {@link #getCurrentLocation(String, LocationRequest, CancellationSignal, Executor, Consumer)}
+ * for more information.
*
* @param locationRequest the location request containing location parameters
* @param cancellationSignal an optional signal that allows for cancelling this call
@@ -735,13 +723,66 @@ public class LocationManager {
* @throws IllegalArgumentException if consumer is null
* @throws SecurityException if no suitable permission is present
* @hide
+ * @deprecated Use
+ * {@link #getCurrentLocation(String, LocationRequest, CancellationSignal, Executor, Consumer)}
+ * instead.
*/
+ @Deprecated
@SystemApi
@TestApi
@RequiresPermission(anyOf = {ACCESS_COARSE_LOCATION, ACCESS_FINE_LOCATION})
public void getCurrentLocation(@NonNull LocationRequest locationRequest,
@Nullable CancellationSignal cancellationSignal,
@NonNull @CallbackExecutor Executor executor, @NonNull Consumer<Location> consumer) {
+ Preconditions.checkArgument(locationRequest.getProvider() != null);
+ getCurrentLocation(locationRequest.getProvider(), locationRequest, cancellationSignal,
+ executor, consumer);
+ }
+
+ /**
+ * Asynchronously returns a single current location fix from the given provider based on the
+ * given {@link LocationRequest}. This may activate sensors in order to compute a new location,
+ * unlike {@link #getLastKnownLocation(String)}, which will only return a cached fix if
+ * available. The given callback will be invoked once and only once, either with a valid
+ * location or with a null location if the provider was unable to generate a valid location.
+ *
+ * <p>A client may supply an optional {@link CancellationSignal}. If this is used to cancel the
+ * operation, no callback should be expected after the cancellation.
+ *
+ * <p>This method may return locations from the very recent past (on the order of several
+ * seconds), but will never return older locations (for example, several minutes old or older).
+ * Clients may rely upon the guarantee that if this method returns a location, it will represent
+ * the best estimation of the location of the device in the present moment.
+ *
+ * <p>Clients calling this method from the background may notice that the method fails to
+ * determine a valid location fix more often than while in the foreground. Background
+ * applications may be throttled in their location accesses to some degree.
+ *
+ * The given location request may be used to provide hints on how a fresh location is computed
+ * if necessary. In particular {@link LocationRequest#getDurationMillis()} can be used to
+ * provide maximum duration allowed before failing. The system will always cap the maximum
+ * amount of time a request for current location may run to some reasonable value (less than a
+ * minute for example) before the request is failed.
+ *
+ * @param provider a provider listed by {@link #getAllProviders()}
+ * @param locationRequest the location request containing location parameters
+ * @param cancellationSignal an optional signal that allows for cancelling this call
+ * @param executor the callback will take place on this {@link Executor}
+ * @param consumer the callback invoked with either a {@link Location} or null
+ *
+ * @throws IllegalArgumentException if provider is null or doesn't exist
+ * @throws IllegalArgumentException if executor is null
+ * @throws IllegalArgumentException if consumer is null
+ * @throws SecurityException if no suitable permission is present
+ */
+ @RequiresPermission(anyOf = {ACCESS_COARSE_LOCATION, ACCESS_FINE_LOCATION})
+ public void getCurrentLocation(@NonNull String provider,
+ @NonNull LocationRequest locationRequest,
+ @Nullable CancellationSignal cancellationSignal,
+ @NonNull @CallbackExecutor Executor executor, @NonNull Consumer<Location> consumer) {
+ Preconditions.checkArgument(provider != null, "invalid null provider");
+ Preconditions.checkArgument(locationRequest != null, "invalid null location request");
+
ICancellationSignal remoteCancellationSignal = CancellationSignal.createTransport();
GetCurrentLocationTransport transport = new GetCurrentLocationTransport(executor, consumer,
remoteCancellationSignal);
@@ -752,7 +793,7 @@ public class LocationManager {
}
try {
- mService.getCurrentLocation(locationRequest, remoteCancellationSignal,
+ mService.getCurrentLocation(provider, locationRequest, remoteCancellationSignal,
transport, mContext.getPackageName(), mContext.getAttributionTag(),
AppOpsManager.toReceiverId(consumer));
} catch (RemoteException e) {
@@ -782,12 +823,16 @@ public class LocationManager {
public void requestSingleUpdate(
@NonNull String provider, @NonNull LocationListener listener, @Nullable Looper looper) {
Preconditions.checkArgument(provider != null, "invalid null provider");
- Preconditions.checkArgument(listener != null, "invalid null listener");
- LocationRequest request = LocationRequest.createFromDeprecatedProvider(
- provider, 0, 0, true);
- request.setExpireIn(MAX_SINGLE_LOCATION_TIMEOUT_MS);
- requestLocationUpdates(request, listener, looper);
+ Handler handler = looper == null ? new Handler() : new Handler(looper);
+ requestLocationUpdates(
+ provider,
+ new LocationRequest.Builder(0)
+ .setMaxUpdates(1)
+ .setDurationMillis(MAX_SINGLE_LOCATION_TIMEOUT_MS)
+ .build(),
+ new HandlerExecutor(handler),
+ listener);
}
/**
@@ -814,12 +859,17 @@ public class LocationManager {
@NonNull LocationListener listener,
@Nullable Looper looper) {
Preconditions.checkArgument(criteria != null, "invalid null criteria");
- Preconditions.checkArgument(listener != null, "invalid null listener");
- LocationRequest request = LocationRequest.createFromDeprecatedCriteria(
- criteria, 0, 0, true);
- request.setExpireIn(MAX_SINGLE_LOCATION_TIMEOUT_MS);
- requestLocationUpdates(request, listener, looper);
+ Handler handler = looper == null ? new Handler() : new Handler(looper);
+ requestLocationUpdates(
+ FUSED_PROVIDER,
+ new LocationRequest.Builder(0)
+ .setQuality(criteria)
+ .setMaxUpdates(1)
+ .setDurationMillis(MAX_SINGLE_LOCATION_TIMEOUT_MS)
+ .build(),
+ new HandlerExecutor(handler),
+ listener);
}
/**
@@ -843,10 +893,13 @@ public class LocationManager {
@NonNull PendingIntent pendingIntent) {
Preconditions.checkArgument(provider != null, "invalid null provider");
- LocationRequest request = LocationRequest.createFromDeprecatedProvider(
- provider, 0, 0, true);
- request.setExpireIn(MAX_SINGLE_LOCATION_TIMEOUT_MS);
- requestLocationUpdates(request, pendingIntent);
+ requestLocationUpdates(
+ provider,
+ new LocationRequest.Builder(0)
+ .setMaxUpdates(1)
+ .setDurationMillis(MAX_SINGLE_LOCATION_TIMEOUT_MS)
+ .build(),
+ pendingIntent);
}
/**
@@ -871,61 +924,27 @@ public class LocationManager {
@NonNull PendingIntent pendingIntent) {
Preconditions.checkArgument(criteria != null, "invalid null criteria");
- LocationRequest request = LocationRequest.createFromDeprecatedCriteria(
- criteria, 0, 0, true);
- request.setExpireIn(MAX_SINGLE_LOCATION_TIMEOUT_MS);
- requestLocationUpdates(request, pendingIntent);
+ requestLocationUpdates(
+ FUSED_PROVIDER,
+ new LocationRequest.Builder(0)
+ .setQuality(criteria)
+ .setMaxUpdates(1)
+ .setDurationMillis(MAX_SINGLE_LOCATION_TIMEOUT_MS)
+ .build(),
+ pendingIntent);
}
/**
- * Register for location updates from the given provider with the given arguments. {@link
- * LocationListener} callbacks will take place on the given {@link Looper} or {@link Executor}.
- * If a null {@link Looper} is supplied, the Looper of the calling thread will be used instead.
- * Only one request can be registered for each unique listener, so any subsequent requests with
- * the same listener will overwrite all associated arguments.
+ * Register for location updates from the given provider with the given arguments, and a
+ * callback on the {@link Looper} of the calling thread.
*
- * <p> It may take a while to receive the first location update. If an immediate location is
- * required, applications may use the {@link #getLastKnownLocation(String)} method.
- *
- * <p> The location update interval can be controlled using the minimum time parameter. The
- * elapsed time between location updates will never be less than this parameter, although it may
- * be more depending on location availability and other factors. Choosing a sensible value for
- * the minimum time parameter is important to conserve battery life. Every location update
- * requires power from a variety of sensors. Select a minimum time parameter as high as possible
- * while still providing a reasonable user experience. If your application is not in the
- * foreground and showing location to the user then your application should consider switching
- * to the {@link #PASSIVE_PROVIDER} instead.
- *
- * <p> The minimum distance parameter can also be used to control the frequency of location
- * updates. If it is greater than 0 then the location provider will only send your application
- * an update when the location has changed by at least minDistance meters, AND when the minimum
- * time has elapsed. However it is more difficult for location providers to save power using the
- * minimum distance parameter, so the minimum time parameter should be the primary tool for
- * conserving battery life.
- *
- * <p> If your application wants to passively observe location updates triggered by other
- * applications, but not consume any additional power otherwise, then use the {@link
- * #PASSIVE_PROVIDER}. This provider does not turn on or modify active location providers, so
- * you do not need to be as careful about minimum time and minimum distance parameters. However,
- * if your application performs heavy work on a location update (such as network activity) then
- * you should select non-zero values for the parameters to rate-limit your update frequency in
- * the case another application enables a location provider with extremely fast updates.
- *
- * <p>In case the provider you have selected is disabled, location updates will cease, and a
- * provider availability update will be sent. As soon as the provider is enabled again, another
- * provider availability update will be sent and location updates will immediately resume.
- *
- * <p> When location callbacks are invoked, the system will hold a wakelock on your
- * application's behalf for some period of time, but not indefinitely. If your application
- * requires a long running wakelock within the location callback, you should acquire it
- * yourself.
+ * <p>See {@link #requestLocationUpdates(String, LocationRequest, Executor, LocationListener)}
+ * for more detail on how this method works.
*
* <p class="note"> Prior to Jellybean, the minTime parameter was only a hint, and some location
* provider implementations ignored it. For Jellybean and onwards however, it is mandatory for
* Android compatible devices to observe both the minTime and minDistance parameters.
*
- * <p>To unregister for location updates, use {@link #removeUpdates(LocationListener)}.
- *
* @param provider a provider listed by {@link #getAllProviders()}
* @param minTimeMs minimum time interval between location updates in milliseconds
* @param minDistanceM minimum distance between location updates in meters
@@ -939,21 +958,20 @@ public class LocationManager {
@RequiresPermission(anyOf = {ACCESS_COARSE_LOCATION, ACCESS_FINE_LOCATION})
public void requestLocationUpdates(@NonNull String provider, long minTimeMs, float minDistanceM,
@NonNull LocationListener listener) {
- Preconditions.checkArgument(provider != null, "invalid null provider");
- Preconditions.checkArgument(listener != null, "invalid null listener");
-
- LocationRequest request = LocationRequest.createFromDeprecatedProvider(
- provider, minTimeMs, minDistanceM, false);
- requestLocationUpdates(request, listener, null);
+ requestLocationUpdates(provider, minTimeMs, minDistanceM, listener, null);
}
/**
- * Register for location updates using the named provider, and a callback on
- * the specified {@link Looper}.
+ * Register for location updates from the given provider with the given arguments, and a
+ * callback on the specified {@link Looper}.
*
- * <p>See {@link #requestLocationUpdates(String, long, float, LocationListener)}
+ * <p>See {@link #requestLocationUpdates(String, LocationRequest, Executor, LocationListener)}
* for more detail on how this method works.
*
+ * <p class="note">Prior to Jellybean, the minTime parameter was only a hint, and some location
+ * provider implementations ignored it. For Jellybean and onwards however, it is mandatory for
+ * Android compatible devices to observe both the minTime and minDistance parameters.
+ *
* @param provider a provider listed by {@link #getAllProviders()}
* @param minTimeMs minimum time interval between location updates in milliseconds
* @param minDistanceM minimum distance between location updates in meters
@@ -968,21 +986,22 @@ public class LocationManager {
@RequiresPermission(anyOf = {ACCESS_COARSE_LOCATION, ACCESS_FINE_LOCATION})
public void requestLocationUpdates(@NonNull String provider, long minTimeMs, float minDistanceM,
@NonNull LocationListener listener, @Nullable Looper looper) {
- Preconditions.checkArgument(provider != null, "invalid null provider");
- Preconditions.checkArgument(listener != null, "invalid null listener");
-
- LocationRequest request = LocationRequest.createFromDeprecatedProvider(
- provider, minTimeMs, minDistanceM, false);
- requestLocationUpdates(request, listener, looper);
+ Handler handler = looper == null ? new Handler() : new Handler(looper);
+ requestLocationUpdates(provider, minTimeMs, minDistanceM, new HandlerExecutor(handler),
+ listener);
}
/**
* Register for location updates using the named provider, and a callback on
* the specified {@link Executor}.
*
- * <p>See {@link #requestLocationUpdates(String, long, float, LocationListener)}
+ * <p>See {@link #requestLocationUpdates(String, LocationRequest, Executor, LocationListener)}
* for more detail on how this method works.
*
+ * <p class="note">Prior to Jellybean, the minTime parameter was only a hint, and some location
+ * provider implementations ignored it. For Jellybean and onwards however, it is mandatory for
+ * Android compatible devices to observe both the minTime and minDistance parameters.
+ *
* @param provider a provider listed by {@link #getAllProviders()}
* @param minTimeMs minimum time interval between location updates in milliseconds
* @param minDistanceM minimum distance between location updates in meters
@@ -1001,16 +1020,22 @@ public class LocationManager {
float minDistanceM,
@NonNull @CallbackExecutor Executor executor,
@NonNull LocationListener listener) {
- LocationRequest request = LocationRequest.createFromDeprecatedProvider(
- provider, minTimeMs, minDistanceM, false);
- requestLocationUpdates(request, executor, listener);
+ Preconditions.checkArgument(provider != null, "invalid null provider");
+
+ requestLocationUpdates(
+ provider,
+ new LocationRequest.Builder(minTimeMs)
+ .setMinUpdateDistanceMeters(minDistanceM)
+ .build(),
+ executor,
+ listener);
}
/**
* Register for location updates using a provider selected through the given Criteria, and a
* callback on the specified {@link Looper}.
*
- * <p>See {@link #requestLocationUpdates(String, long, float, LocationListener)}
+ * <p>See {@link #requestLocationUpdates(String, LocationRequest, Executor, LocationListener)}
* for more detail on how this method works.
*
* @param minTimeMs minimum time interval between location updates in milliseconds
@@ -1026,19 +1051,16 @@ public class LocationManager {
public void requestLocationUpdates(long minTimeMs, float minDistanceM,
@NonNull Criteria criteria, @NonNull LocationListener listener,
@Nullable Looper looper) {
- Preconditions.checkArgument(criteria != null, "invalid null criteria");
- Preconditions.checkArgument(listener != null, "invalid null listener");
-
- LocationRequest request = LocationRequest.createFromDeprecatedCriteria(
- criteria, minTimeMs, minDistanceM, false);
- requestLocationUpdates(request, listener, looper);
+ Handler handler = looper == null ? new Handler() : new Handler(looper);
+ requestLocationUpdates(minTimeMs, minDistanceM, criteria, new HandlerExecutor(handler),
+ listener);
}
/**
* Register for location updates using a provider selected through the given Criteria, and a
* callback on the specified {@link Executor}.
*
- * <p>See {@link #requestLocationUpdates(String, long, float, LocationListener)}
+ * <p>See {@link #requestLocationUpdates(String, LocationRequest, Executor, LocationListener)}
* for more detail on how this method works.
*
* @param minTimeMs minimum time interval between location updates in milliseconds
@@ -1059,23 +1081,24 @@ public class LocationManager {
@NonNull Criteria criteria,
@NonNull @CallbackExecutor Executor executor,
@NonNull LocationListener listener) {
- LocationRequest request = LocationRequest.createFromDeprecatedCriteria(
- criteria, minTimeMs, minDistanceM, false);
- requestLocationUpdates(request, executor, listener);
+ Preconditions.checkArgument(criteria != null, "invalid null criteria");
+
+ requestLocationUpdates(
+ FUSED_PROVIDER,
+ new LocationRequest.Builder(minTimeMs)
+ .setQuality(criteria)
+ .setMinUpdateDistanceMeters(minDistanceM)
+ .build(),
+ executor,
+ listener);
}
/**
* Register for location updates using the named provider, and callbacks delivered via the
* provided {@link PendingIntent}.
*
- * <p>The delivered pending intents will contain extras with the callback information. The keys
- * used for the extras are {@link #KEY_LOCATION_CHANGED} and {@link #KEY_PROVIDER_ENABLED}. See
- * the documentation for each respective extra key for information on the values.
- *
- * <p>To unregister for location updates, use {@link #removeUpdates(PendingIntent)}.
- *
- * <p>See {@link #requestLocationUpdates(String, long, float, LocationListener)}
- * for more detail on how this method works.
+ * <p>See {@link #requestLocationUpdates(String, LocationRequest, PendingIntent)} for more
+ * detail on how this method works.
*
* @param provider a provider listed by {@link #getAllProviders()}
* @param minTimeMs minimum time interval between location updates in milliseconds
@@ -1091,9 +1114,12 @@ public class LocationManager {
@NonNull PendingIntent pendingIntent) {
Preconditions.checkArgument(provider != null, "invalid null provider");
- LocationRequest request = LocationRequest.createFromDeprecatedProvider(
- provider, minTimeMs, minDistanceM, false);
- requestLocationUpdates(request, pendingIntent);
+ requestLocationUpdates(
+ provider,
+ new LocationRequest.Builder(minTimeMs)
+ .setMinUpdateDistanceMeters(minDistanceM)
+ .build(),
+ pendingIntent);
}
/**
@@ -1116,10 +1142,13 @@ public class LocationManager {
public void requestLocationUpdates(long minTimeMs, float minDistanceM,
@NonNull Criteria criteria, @NonNull PendingIntent pendingIntent) {
Preconditions.checkArgument(criteria != null, "invalid null criteria");
-
- LocationRequest request = LocationRequest.createFromDeprecatedCriteria(
- criteria, minTimeMs, minDistanceM, false);
- requestLocationUpdates(request, pendingIntent);
+ requestLocationUpdates(
+ FUSED_PROVIDER,
+ new LocationRequest.Builder(minTimeMs)
+ .setQuality(criteria)
+ .setMinUpdateDistanceMeters(minDistanceM)
+ .build(),
+ pendingIntent);
}
/**
@@ -1131,7 +1160,7 @@ public class LocationManager {
* choose default low power parameters for location updates, but this is heavily discouraged,
* and an explicit LocationRequest should always be provided.
*
- * <p>See {@link #requestLocationUpdates(String, long, float, LocationListener)}
+ * <p>See {@link #requestLocationUpdates(String, LocationRequest, Executor, LocationListener)}
* for more detail on how this method works.
*
* @param locationRequest the location request containing location parameters
@@ -1143,7 +1172,10 @@ public class LocationManager {
* @throws SecurityException if no suitable permission is present
*
* @hide
+ * @deprecated Use
+ * {@link #requestLocationUpdates(String, LocationRequest, Executor, LocationListener)} instead.
*/
+ @Deprecated
@SystemApi
@TestApi
@RequiresPermission(anyOf = {ACCESS_COARSE_LOCATION, ACCESS_FINE_LOCATION})
@@ -1159,8 +1191,8 @@ public class LocationManager {
* Register for location updates using a {@link LocationRequest}, and a callback on the
* specified {@link Executor}.
*
- * <p>See {@link #requestLocationUpdates(LocationRequest, LocationListener, Looper)} for more
- * detail on how this method works.
+ * <p>See {@link #requestLocationUpdates(String, LocationRequest, Executor, LocationListener)}
+ * for more detail on how this method works.
*
* @param locationRequest the location request containing location parameters
* @param executor the executor handling listener callbacks
@@ -1171,7 +1203,10 @@ public class LocationManager {
* @throws SecurityException if no suitable permission is present
*
* @hide
+ * @deprecated Use
+ * {@link #requestLocationUpdates(String, LocationRequest, Executor, LocationListener)} instead.
*/
+ @Deprecated
@SystemApi
@TestApi
@RequiresPermission(anyOf = {ACCESS_COARSE_LOCATION, ACCESS_FINE_LOCATION})
@@ -1180,8 +1215,93 @@ public class LocationManager {
@NonNull @CallbackExecutor Executor executor,
@NonNull LocationListener listener) {
if (locationRequest == null) {
- locationRequest = new LocationRequest();
+ locationRequest = LocationRequest.create();
}
+ Preconditions.checkArgument(locationRequest.getProvider() != null);
+ requestLocationUpdates(locationRequest.getProvider(), locationRequest, executor, listener);
+ }
+
+ /**
+ * Register for location updates using a {@link LocationRequest}, and callbacks delivered via
+ * the provided {@link PendingIntent}.
+ *
+ * <p>See {@link #requestLocationUpdates(String, LocationRequest, PendingIntent)} for more
+ * detail on how this method works.
+ *
+ * @param locationRequest the location request containing location parameters
+ * @param pendingIntent the pending intent to send location updates
+ *
+ * @throws IllegalArgumentException if pendingIntent is null
+ * @throws SecurityException if no suitable permission is present
+ *
+ * @hide
+ * @deprecated Use {@link #requestLocationUpdates(String, LocationRequest, PendingIntent)}
+ * instead.
+ */
+ @Deprecated
+ @SystemApi
+ @TestApi
+ @RequiresPermission(anyOf = {ACCESS_COARSE_LOCATION, ACCESS_FINE_LOCATION})
+ public void requestLocationUpdates(
+ @Nullable LocationRequest locationRequest,
+ @NonNull PendingIntent pendingIntent) {
+ if (locationRequest == null) {
+ locationRequest = LocationRequest.create();
+ }
+ Preconditions.checkArgument(locationRequest.getProvider() != null);
+ requestLocationUpdates(locationRequest.getProvider(), locationRequest, pendingIntent);
+ }
+
+ /**
+ * Register for location updates from the specified provider, using a {@link LocationRequest},
+ * and a callback on the specified {@link Executor}.
+ *
+ * <p>Only one request can be registered for each unique listener/provider pair, so any
+ * subsequent requests with the same provider and listener will overwrite all associated
+ * arguments. The same listener may be used across multiple providers with different requests
+ * for each provider.
+ *
+ * <p>It may take a while to receive the first location update. If an immediate location is
+ * required, applications may use the {@link #getLastKnownLocation(String)} method.
+ *
+ * <p>See {@link LocationRequest} documentation for an explanation of various request parameters
+ * and how they can affect the received locations.
+ *
+ * <p> If your application wants to passively observe location updates from any provider, then
+ * use the {@link #PASSIVE_PROVIDER}. This provider does not turn on or modify active location
+ * providers, so you do not need to be as careful about minimum time and minimum distance
+ * parameters. However, if your application performs heavy work on a location update (such as
+ * network activity) then you should set an explicit fastest interval on your location request
+ * in case another application enables a location provider with extremely fast updates.
+ *
+ * <p>In case the provider you have selected is disabled, location updates will cease, and a
+ * provider availability update will be sent. As soon as the provider is enabled again, another
+ * provider availability update will be sent and location updates will immediately resume.
+ *
+ * <p> When location callbacks are invoked, the system will hold a wakelock on your
+ * application's behalf for some period of time, but not indefinitely. If your application
+ * requires a long running wakelock within the location callback, you should acquire it
+ * yourself.
+ *
+ * <p>To unregister for location updates, use {@link #removeUpdates(LocationListener)}.
+ *
+ * @param provider a provider listed by {@link #getAllProviders()}
+ * @param locationRequest the location request containing location parameters
+ * @param executor the executor handling listener callbacks
+ * @param listener the listener to receive location updates
+ *
+ * @throws IllegalArgumentException if provider is null or doesn't exist
+ * @throws IllegalArgumentException if locationRequest is null
+ * @throws IllegalArgumentException if listener is null
+ * @throws SecurityException if no suitable permission is present
+ */
+ @RequiresPermission(anyOf = {ACCESS_COARSE_LOCATION, ACCESS_FINE_LOCATION})
+ public void requestLocationUpdates(@NonNull String provider,
+ @NonNull LocationRequest locationRequest,
+ @NonNull @CallbackExecutor Executor executor,
+ @NonNull LocationListener listener) {
+ Preconditions.checkArgument(provider != null, "invalid null provider");
+ Preconditions.checkArgument(locationRequest != null, "invalid null location request");
synchronized (sLocationListeners) {
WeakReference<LocationListenerTransport> reference = sLocationListeners.get(listener);
@@ -1198,7 +1318,7 @@ public class LocationManager {
// make sure that callbacks are not made on the same thread - however it is the
// easiest way to guarantee that clients will not receive callbacks after
// unregistration is complete.
- mService.registerLocationListener(locationRequest, transport,
+ mService.registerLocationListener(provider, locationRequest, transport,
mContext.getPackageName(), mContext.getAttributionTag(),
AppOpsManager.toReceiverId(listener));
} catch (RemoteException e) {
@@ -1208,39 +1328,39 @@ public class LocationManager {
}
/**
- * Register for location updates using a {@link LocationRequest}, and callbacks delivered via
- * the provided {@link PendingIntent}.
+ * Register for location updates from the specified provider, using a {@link LocationRequest},
+ * and callbacks delivered via the provided {@link PendingIntent}.
*
- * <p>See {@link #requestLocationUpdates(LocationRequest, LocationListener, Looper)} and
- * {@link #requestLocationUpdates(String, long, float, PendingIntent)} for more detail on how
- * this method works.
+ * <p>The delivered pending intents will contain extras with the callback information. The keys
+ * used for the extras are {@link #KEY_LOCATION_CHANGED} and {@link #KEY_PROVIDER_ENABLED}. See
+ * the documentation for each respective extra key for information on the values.
+ *
+ * <p>To unregister for location updates, use {@link #removeUpdates(PendingIntent)}.
*
+ * @param provider a provider listed by {@link #getAllProviders()}
* @param locationRequest the location request containing location parameters
* @param pendingIntent the pending intent to send location updates
*
+ * @throws IllegalArgumentException if provider is null or doesn't exist
+ * @throws IllegalArgumentException if locationRequest is null
* @throws IllegalArgumentException if pendingIntent is null
* @throws SecurityException if no suitable permission is present
- *
- * @hide
*/
- @SystemApi
- @TestApi
@RequiresPermission(anyOf = {ACCESS_COARSE_LOCATION, ACCESS_FINE_LOCATION})
- public void requestLocationUpdates(
- @Nullable LocationRequest locationRequest,
+ public void requestLocationUpdates(@NonNull String provider,
+ @NonNull LocationRequest locationRequest,
@NonNull PendingIntent pendingIntent) {
+ Preconditions.checkArgument(provider != null, "invalid null provider");
+ Preconditions.checkArgument(locationRequest != null, "invalid null location request");
Preconditions.checkArgument(pendingIntent != null, "invalid null pending intent");
+
if (Compatibility.isChangeEnabled(TARGETED_PENDING_INTENT)) {
Preconditions.checkArgument(pendingIntent.isTargetedToPackage(),
"pending intent must be targeted to a package");
}
- if (locationRequest == null) {
- locationRequest = new LocationRequest();
- }
-
try {
- mService.registerLocationPendingIntent(locationRequest, pendingIntent,
+ mService.registerLocationPendingIntent(provider, locationRequest, pendingIntent,
mContext.getPackageName(), mContext.getAttributionTag());
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
diff --git a/location/java/android/location/LocationRequest.java b/location/java/android/location/LocationRequest.java
index 280bd058ef0f..c53d08bdcd16 100644
--- a/location/java/android/location/LocationRequest.java
+++ b/location/java/android/location/LocationRequest.java
@@ -16,7 +16,12 @@
package android.location;
+import static java.lang.Math.max;
+import static java.lang.Math.min;
+
import android.Manifest;
+import android.annotation.FloatRange;
+import android.annotation.IntRange;
import android.annotation.NonNull;
import android.annotation.Nullable;
import android.annotation.RequiresPermission;
@@ -26,7 +31,6 @@ import android.compat.annotation.UnsupportedAppUsage;
import android.os.Build;
import android.os.Parcel;
import android.os.Parcelable;
-import android.os.SystemClock;
import android.os.WorkSource;
import android.util.TimeUtils;
@@ -36,73 +40,25 @@ import java.util.Objects;
/**
- * A data object that contains quality of service parameters for requests
- * to the {@link LocationManager}.
- *
- * <p>LocationRequest objects are used to request a quality of service
- * for location updates from the Location Manager.
- *
- * <p>For example, if your application wants high accuracy location
- * it should create a location request with {@link #setQuality} set to
- * {@link #ACCURACY_FINE} or {@link #POWER_HIGH}, and it should set
- * {@link #setInterval} to less than one second. This would be
- * appropriate for mapping applications that are showing your location
- * in real-time.
- *
- * <p>At the other extreme, if you want negligible power
- * impact, but to still receive location updates when available, then use
- * {@link #setQuality} with {@link #POWER_NONE}. With this request your
- * application will not trigger (and therefore will not receive any
- * power blame) any location updates, but will receive locations
- * triggered by other applications. This would be appropriate for
- * applications that have no firm requirement for location, but can
- * take advantage when available.
- *
- * <p>In between these two extremes is a very common use-case, where
- * applications definitely want to receive
- * updates at a specified interval, and can receive them faster when
- * available, but still want a low power impact. These applications
- * should consider {@link #POWER_LOW} combined with a faster
- * {@link #setFastestInterval} (such as 1 minute) and a slower
- * {@link #setInterval} (such as 60 minutes). They will only be assigned
- * power blame for the interval set by {@link #setInterval}, but can
- * still receive locations triggered by other applications at a rate up
- * to {@link #setFastestInterval}. This style of request is appropriate for
- * many location aware applications, including background usage. Do be
- * careful to also throttle {@link #setFastestInterval} if you perform
- * heavy-weight work after receiving an update - such as using the network.
- *
- * <p>Activities should strongly consider removing all location
- * request when entering the background, or
- * at least swap the request to a larger interval and lower quality.
- * Future version of the location manager may automatically perform background
- * throttling on behalf of applications.
- *
- * <p>Applications cannot specify the exact location sources that are
- * used by Android's <em>Fusion Engine</em>. In fact, the system
- * may have multiple location sources (providers) running and may
- * fuse the results from several sources into a single Location object.
- *
- * <p>Location requests from applications with
- * {@link android.Manifest.permission#ACCESS_COARSE_LOCATION} and not
- * {@link android.Manifest.permission#ACCESS_FINE_LOCATION} will
- * be automatically throttled to a slower interval, and the location
- * object will be obfuscated to only show a coarse level of accuracy.
- *
- * <p>All location requests are considered hints, and you may receive
- * locations that are more accurate, less accurate, and slower
- * than requested.
- *
- * @hide
+ * An encapsulation of various parameters for requesting location via {@link LocationManager}.
*/
-@SystemApi
-@TestApi
public final class LocationRequest implements Parcelable {
+
+ /**
+ * Represents a passive only request. Such a request will not trigger any active locations or
+ * power usage itself, but may receive locations generated in response to other requests.
+ */
+ public static final long PASSIVE_INTERVAL = Long.MAX_VALUE;
+
/**
* Used with {@link #setQuality} to request the most accurate locations available.
*
* <p>This may be up to 1 meter accuracy, although this is implementation dependent.
+ *
+ * @hide
*/
+ @SystemApi
+ @TestApi
public static final int ACCURACY_FINE = 100;
/**
@@ -111,7 +67,11 @@ public final class LocationRequest implements Parcelable {
* <p>Block level accuracy is considered to be about 100 meter accuracy,
* although this is implementation dependent. Using a coarse accuracy
* such as this often consumes less power.
+ *
+ * @hide
*/
+ @SystemApi
+ @TestApi
public static final int ACCURACY_BLOCK = 102;
/**
@@ -120,7 +80,11 @@ public final class LocationRequest implements Parcelable {
* <p>City level accuracy is considered to be about 10km accuracy,
* although this is implementation dependent. Using a coarse accuracy
* such as this often consumes less power.
+ *
+ * @hide
*/
+ @SystemApi
+ @TestApi
public static final int ACCURACY_CITY = 104;
/**
@@ -129,7 +93,12 @@ public final class LocationRequest implements Parcelable {
* <p>This location request will not trigger any active location requests,
* but will receive locations triggered by other applications. Your application
* will not receive any direct power blame for location work.
+ *
+ * @hide
+ * @deprecated Use {@link #PASSIVE_INTERVAL} instead.
*/
+ @SystemApi
+ @Deprecated
public static final int POWER_NONE = 200;
/**
@@ -137,66 +106,76 @@ public final class LocationRequest implements Parcelable {
*
* <p>This location request will avoid high power location work where
* possible.
+ *
+ * @hide
*/
+ @SystemApi
+ @TestApi
public static final int POWER_LOW = 201;
/**
* Used with {@link #setQuality} to allow high power consumption for location.
*
* <p>This location request will allow high power location work.
+ *
+ * @hide
*/
+ @SystemApi
+ @TestApi
public static final int POWER_HIGH = 203;
- private static final long DEFAULT_INTERVAL_MS = 60 * 60 * 1000; // 1 hour
- private static final double FASTEST_INTERVAL_FACTOR = 6.0; // 6x
+ private static final long IMPLICIT_MIN_UPDATE_INTERVAL = -1;
- @UnsupportedAppUsage
- private String mProvider;
- @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 115609023)
+ @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, publicAlternatives = "Use {@link "
+ + "LocationManager} methods to provide the provider explicitly.")
+ @Nullable private String mProvider;
private int mQuality;
- @UnsupportedAppUsage
+ @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, publicAlternatives = "Use {@link "
+ + "LocationRequest} instead.")
private long mInterval;
- @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 115609023)
- private long mFastestInterval;
- @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 115609023)
- private boolean mExplicitFastestInterval;
- @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 115609023)
- private long mExpireAt;
- private long mExpireIn;
- @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 115609023)
- private int mNumUpdates;
- @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 115609023)
- private float mSmallestDisplacement;
- @UnsupportedAppUsage
+ private long mMinUpdateIntervalMillis;
+ private long mExpireAtRealtimeMillis;
+ private long mDurationMillis;
+ private int mMaxUpdates;
+ private float mMinUpdateDistanceMeters;
private boolean mHideFromAppOps;
private boolean mLocationSettingsIgnored;
- private boolean mLowPowerMode;
- @UnsupportedAppUsage
+ private boolean mLowPower;
private @Nullable WorkSource mWorkSource;
/**
- * Create a location request with default parameters.
- *
- * <p>Default parameters are for a low power, slowly updated location.
- * It can then be adjusted as required by the applications before passing
- * to the {@link LocationManager}
- *
- * @return a new location request
+ * @hide
+ * @deprecated Use the Builder to construct new LocationRequests.
*/
+ @SystemApi
+ @Deprecated
@NonNull
public static LocationRequest create() {
- return new LocationRequest();
+ // 60 minutes is the default legacy interval
+ return new LocationRequest.Builder(60 * 60 * 1000)
+ .setQuality(POWER_LOW)
+ .build();
}
- /** @hide */
+ /**
+ * @hide
+ * @deprecated Use the Builder to construct new LocationRequests.
+ */
@SystemApi
+ @Deprecated
@NonNull
- public static LocationRequest createFromDeprecatedProvider(
- @NonNull String provider, long minTime, float minDistance, boolean singleShot) {
+ public static LocationRequest createFromDeprecatedProvider(@NonNull String provider,
+ long intervalMillis, float minUpdateDistanceMeters, boolean singleShot) {
Preconditions.checkArgument(provider != null, "invalid null provider");
- if (minTime < 0) minTime = 0;
- if (minDistance < 0) minDistance = 0;
+ if (intervalMillis < 0) {
+ intervalMillis = 0;
+ } else if (intervalMillis == PASSIVE_INTERVAL) {
+ intervalMillis = Long.MAX_VALUE - 1;
+ }
+ if (minUpdateDistanceMeters < 0) {
+ minUpdateDistanceMeters = 0;
+ }
int quality;
if (LocationManager.PASSIVE_PROVIDER.equals(provider)) {
@@ -207,512 +186,484 @@ public final class LocationRequest implements Parcelable {
quality = POWER_LOW;
}
- LocationRequest request = new LocationRequest()
+ return new LocationRequest.Builder(intervalMillis)
+ .setMinUpdateIntervalMillis(intervalMillis)
+ .setMinUpdateDistanceMeters(minUpdateDistanceMeters)
+ .setMaxUpdates(singleShot ? 1 : Integer.MAX_VALUE)
+ .build()
.setProvider(provider)
- .setQuality(quality)
- .setInterval(minTime)
- .setFastestInterval(minTime)
- .setSmallestDisplacement(minDistance);
- if (singleShot) request.setNumUpdates(1);
- return request;
+ .setQuality(quality);
}
- /** @hide */
+ /**
+ * @hide
+ * @deprecated Use the Builder to construct new LocationRequests.
+ */
@SystemApi
+ @Deprecated
@NonNull
- public static LocationRequest createFromDeprecatedCriteria(
- @NonNull Criteria criteria, long minTime, float minDistance, boolean singleShot) {
+ public static LocationRequest createFromDeprecatedCriteria(@NonNull Criteria criteria,
+ long intervalMillis, float minUpdateDistanceMeters, boolean singleShot) {
Preconditions.checkArgument(criteria != null, "invalid null criteria");
- if (minTime < 0) minTime = 0;
- if (minDistance < 0) minDistance = 0;
-
- int quality;
- switch (criteria.getAccuracy()) {
- case Criteria.ACCURACY_COARSE:
- quality = ACCURACY_BLOCK;
- break;
- case Criteria.ACCURACY_FINE:
- quality = ACCURACY_FINE;
- break;
- default: {
- if (criteria.getPowerRequirement() == Criteria.POWER_HIGH) {
- quality = POWER_HIGH;
- } else {
- quality = POWER_LOW;
- }
- }
+ if (intervalMillis < 0) {
+ intervalMillis = 0;
+ } else if (intervalMillis == PASSIVE_INTERVAL) {
+ intervalMillis = Long.MAX_VALUE - 1;
+ }
+ if (minUpdateDistanceMeters < 0) {
+ minUpdateDistanceMeters = 0;
}
- LocationRequest request = new LocationRequest()
- .setQuality(quality)
- .setInterval(minTime)
- .setFastestInterval(minTime)
- .setSmallestDisplacement(minDistance);
- if (singleShot) request.setNumUpdates(1);
- return request;
- }
-
- /** @hide */
- public LocationRequest() {
- this(
- /* provider= */ LocationManager.FUSED_PROVIDER,
- /* quality= */ POWER_LOW,
- /* interval= */ DEFAULT_INTERVAL_MS,
- /* fastestInterval= */ (long) (DEFAULT_INTERVAL_MS / FASTEST_INTERVAL_FACTOR),
- /* explicitFastestInterval= */ false,
- /* expireAt= */ Long.MAX_VALUE,
- /* expireIn= */ Long.MAX_VALUE,
- /* numUpdates= */ Integer.MAX_VALUE,
- /* smallestDisplacement= */ 0,
- /* hideFromAppOps= */ false,
- /* locationSettingsIgnored= */ false,
- /* lowPowerMode= */ false,
- /* workSource= */ null);
- }
-
- /** @hide */
- public LocationRequest(LocationRequest src) {
- this(
- src.mProvider,
- src.mQuality,
- src.mInterval,
- src.mFastestInterval,
- src.mExplicitFastestInterval,
- src.mExpireAt,
- src.mExpireIn,
- src.mNumUpdates,
- src.mSmallestDisplacement,
- src.mHideFromAppOps,
- src.mLocationSettingsIgnored,
- src.mLowPowerMode,
- src.mWorkSource);
+ return new LocationRequest.Builder(intervalMillis)
+ .setQuality(criteria)
+ .setMinUpdateIntervalMillis(intervalMillis)
+ .setMinUpdateDistanceMeters(minUpdateDistanceMeters)
+ .setMaxUpdates(singleShot ? 1 : Integer.MAX_VALUE)
+ .build();
}
private LocationRequest(
- @NonNull String provider,
+ @Nullable String provider,
+ long intervalMillis,
int quality,
- long intervalMs,
- long fastestIntervalMs,
- boolean explicitFastestInterval,
- long expireAt,
- long expireInMs,
- int numUpdates,
- float smallestDisplacementM,
- boolean hideFromAppOps,
+ long expireAtRealtimeMillis,
+ long durationMillis,
+ int maxUpdates,
+ long minUpdateIntervalMillis,
+ float minUpdateDistanceMeters,
+ boolean hiddenFromAppOps,
boolean locationSettingsIgnored,
- boolean lowPowerMode,
- WorkSource workSource) {
- Preconditions.checkArgument(provider != null, "invalid provider: null");
- checkQuality(quality);
+ boolean lowPower,
+ @Nullable WorkSource workSource) {
+ Preconditions.checkArgument(intervalMillis != PASSIVE_INTERVAL || quality == POWER_NONE);
+ Preconditions.checkArgument(minUpdateIntervalMillis <= intervalMillis);
mProvider = provider;
+ mInterval = intervalMillis;
mQuality = quality;
- mInterval = intervalMs;
- mFastestInterval = fastestIntervalMs;
- mExplicitFastestInterval = explicitFastestInterval;
- mExpireAt = expireAt;
- mExpireIn = expireInMs;
- mNumUpdates = numUpdates;
- mSmallestDisplacement = Preconditions.checkArgumentInRange(smallestDisplacementM, 0,
- Float.MAX_VALUE, "smallestDisplacementM");
- mHideFromAppOps = hideFromAppOps;
- mLowPowerMode = lowPowerMode;
+ mMinUpdateIntervalMillis = minUpdateIntervalMillis;
+ mExpireAtRealtimeMillis = expireAtRealtimeMillis;
+ mDurationMillis = durationMillis;
+ mMaxUpdates = maxUpdates;
+ mMinUpdateDistanceMeters = minUpdateDistanceMeters;
+ mHideFromAppOps = hiddenFromAppOps;
+ mLowPower = lowPower;
mLocationSettingsIgnored = locationSettingsIgnored;
mWorkSource = workSource;
}
/**
- * Set the quality of the request.
- *
- * <p>Use with a accuracy constant such as {@link #ACCURACY_FINE}, or a power
- * constant such as {@link #POWER_LOW}. You cannot request both accuracy and
- * power, only one or the other can be specified. The system will then
- * maximize accuracy or minimize power as appropriate.
- *
- * <p>The quality of the request is a strong hint to the system for which
- * location sources to use. For example, {@link #ACCURACY_FINE} is more likely
- * to use GPS, and {@link #POWER_LOW} is more likely to use WIFI & Cell tower
- * positioning, but it also depends on many other factors (such as which sources
- * are available) and is implementation dependent.
- *
- * <p>{@link #setQuality} and {@link #setInterval} are the most important parameters
- * on a location request.
- *
- * @param quality an accuracy or power constant
- * @return the same object, so that setters can be chained
- * @throws IllegalArgumentException if the quality constant is not valid
+ * @hide
+ * @deprecated LocationRequests should be treated as immutable.
*/
- public @NonNull LocationRequest setQuality(int quality) {
- checkQuality(quality);
- mQuality = quality;
+ @SystemApi
+ @Deprecated
+ public @NonNull LocationRequest setProvider(@NonNull String provider) {
+ Preconditions.checkArgument(provider != null);
+ mProvider = provider;
return this;
}
/**
- * Get the quality of the request.
- *
- * @return an accuracy or power constant
+ * @hide
+ * @deprecated Providers are no longer an explicit part of a location request.
*/
- public int getQuality() {
- return mQuality;
+ @SystemApi
+ @Deprecated
+ public @NonNull String getProvider() {
+ return mProvider != null ? mProvider : LocationManager.FUSED_PROVIDER;
}
/**
- * Set the desired interval for active location updates, in milliseconds.
- *
- * <p>The location manager will actively try to obtain location updates
- * for your application at this interval, so it has a
- * direct influence on the amount of power used by your application.
- * Choose your interval wisely.
- *
- * <p>This interval is inexact. You may not receive updates at all (if
- * no location sources are available), or you may receive them
- * slower than requested. You may also receive them faster than
- * requested (if other applications are requesting location at a
- * faster interval). The fastest rate that you will receive
- * updates can be controlled with {@link #setFastestInterval}.
- *
- * <p>Applications with only the coarse location permission may have their
- * interval silently throttled.
- *
- * <p>An interval of 0 is allowed, but not recommended, since
- * location updates may be extremely fast on future implementations.
- *
- * <p>{@link #setQuality} and {@link #setInterval} are the most important parameters
- * on a location request.
- *
- * @param millis desired interval in millisecond, inexact
- * @return the same object, so that setters can be chained
- * @throws IllegalArgumentException if the interval is less than zero
+ * @hide
+ * @deprecated LocationRequests should be treated as immutable.
*/
- public @NonNull LocationRequest setInterval(long millis) {
- Preconditions.checkArgument(millis >= 0, "invalid interval: + millis");
- mInterval = millis;
- if (!mExplicitFastestInterval) {
- mFastestInterval = (long) (mInterval / FASTEST_INTERVAL_FACTOR);
- }
+ @SystemApi
+ @Deprecated
+ public @NonNull LocationRequest setQuality(int quality) {
+ mQuality = Builder.checkQuality(quality, true);
return this;
}
/**
- * Get the desired interval of this request, in milliseconds.
+ * Returns the quality of the location request.
+ *
+ * @return the quality of the location request
*
- * @return desired interval in milliseconds, inexact
+ * @hide
*/
- public long getInterval() {
- return mInterval;
+ @SystemApi
+ public int getQuality() {
+ if (mInterval == PASSIVE_INTERVAL) {
+ return POWER_NONE;
+ } else {
+ return mQuality;
+ }
}
-
/**
- * Requests the GNSS chipset to run in a low power mode and make strong tradeoffs to
- * substantially restrict power.
- *
- * <p>In this mode, the GNSS chipset will not, on average, run power hungry operations like RF &
- * signal searches for more than one second per interval (specified by
- * {@link #setInterval(long)}).
- *
- * @param enabled Enable or disable low power mode
- * @return the same object, so that setters can be chained
+ * @hide
+ * @deprecated LocationRequests should be treated as immutable.
*/
- public @NonNull LocationRequest setLowPowerMode(boolean enabled) {
- mLowPowerMode = enabled;
+ @SystemApi
+ @Deprecated
+ public @NonNull LocationRequest setInterval(long millis) {
+ Preconditions.checkArgument(millis >= 0);
+
+ // legacy clients don't know about the passive interval
+ if (millis == PASSIVE_INTERVAL) {
+ millis = Long.MAX_VALUE - 1;
+ }
+
+ mInterval = millis;
+ if (mMinUpdateIntervalMillis > mInterval) {
+ mMinUpdateIntervalMillis = mInterval;
+ }
return this;
}
/**
- * Returns true if low power mode is enabled.
+ * @hide
+ * @deprecated Use {@link #getIntervalMillis()} instead.
*/
- public boolean isLowPowerMode() {
- return mLowPowerMode;
+ @SystemApi
+ @Deprecated
+ public long getInterval() {
+ return getIntervalMillis();
}
/**
- * Requests that user location settings be ignored in order to satisfy this request. This API
- * is only for use in extremely rare scenarios where it is appropriate to ignore user location
- * settings, such as a user initiated emergency (dialing 911 for instance).
+ * Returns the desired interval of location updates, or {@link #PASSIVE_INTERVAL} if this is a
+ * passive, no power request. A passive request will not actively generate location updates
+ * (and thus will not be power blamed for location), but may receive location updates generated
+ * as a result of other location requests. A passive request must always have an explicit
+ * minimum update interval set.
*
- * @param locationSettingsIgnored Whether to ignore location settings
- * @return the same object, so that setters can be chained
- */
- @RequiresPermission(Manifest.permission.WRITE_SECURE_SETTINGS)
- public @NonNull LocationRequest setLocationSettingsIgnored(boolean locationSettingsIgnored) {
- mLocationSettingsIgnored = locationSettingsIgnored;
- return this;
- }
-
- /**
- * Returns true if location settings will be ignored in order to satisfy this request.
+ * <p>Locations may be available at a faster interval than specified here, see
+ * {@link #getMinUpdateIntervalMillis()} for the behavior in that case.
+ *
+ * @return the desired interval of location updates
*/
- public boolean isLocationSettingsIgnored() {
- return mLocationSettingsIgnored;
+ public long getIntervalMillis() {
+ return mInterval;
}
/**
- * Explicitly set the fastest interval for location updates, in
- * milliseconds.
- *
- * <p>This controls the fastest rate at which your application will
- * receive location updates, which might be faster than
- * {@link #setInterval} in some situations (for example, if other
- * applications are triggering location updates).
- *
- * <p>This allows your application to passively acquire locations
- * at a rate faster than it actively acquires locations, saving power.
- *
- * <p>Unlike {@link #setInterval}, this parameter is exact. Your
- * application will never receive updates faster than this value.
- *
- * <p>If you don't call this method, a fastest interval
- * will be selected for you. It will be a value faster than your
- * active interval ({@link #setInterval}).
- *
- * <p>An interval of 0 is allowed, but not recommended, since
- * location updates may be extremely fast on future implementations.
- *
- * <p>If the fastest interval set is slower than {@link #setInterval},
- * then your effective fastest interval is {@link #setInterval}.
- *
- * @param millis fastest interval for updates in milliseconds
- * @return the same object, so that setters can be chained
- * @throws IllegalArgumentException if the interval is less than zero
+ * @hide
+ * @deprecated LocationRequests should be treated as immutable.
*/
+ @SystemApi
+ @Deprecated
public @NonNull LocationRequest setFastestInterval(long millis) {
- Preconditions.checkArgument(millis >= 0, "invalid interval: + millis");
- mExplicitFastestInterval = true;
- mFastestInterval = millis;
+ Preconditions.checkArgument(millis >= 0);
+ mMinUpdateIntervalMillis = millis;
return this;
}
/**
- * Get the fastest interval of this request in milliseconds. The system will never provide
- * location updates faster than the minimum of the fastest interval and {@link #getInterval}.
- *
- * @return fastest interval in milliseconds
+ * @hide
+ * @deprecated Use {@link #getMinUpdateIntervalMillis()} instead.
*/
+ @SystemApi
+ @Deprecated
public long getFastestInterval() {
- return mFastestInterval;
+ return getMinUpdateIntervalMillis();
}
/**
- * Set the expiration time of this request in milliseconds of realtime since boot. Values in the
- * past are allowed, but indicate that the request has already expired. The location manager
- * will automatically stop updates after the request expires.
- *
- * @param millis expiration time of request in milliseconds since boot
- * @return the same object, so that setters can be chained
- * @see SystemClock#elapsedRealtime()
- * @deprecated Prefer {@link #setExpireIn(long)}.
+ * @hide
+ * @deprecated LocationRequests should be treated as immutable.
*/
+ @SystemApi
@Deprecated
public @NonNull LocationRequest setExpireAt(long millis) {
- mExpireAt = Math.max(millis, 0);
+ mExpireAtRealtimeMillis = max(millis, 0);
return this;
}
/**
- * Get the request expiration time in milliseconds of realtime since boot.
- *
- * @return request expiration time in milliseconds since boot
- * @see SystemClock#elapsedRealtime()
- * @deprecated Prefer {@link #getExpireIn()}.
+ * @hide
+ * @deprecated Prefer {@link #getDurationMillis()} where possible.
*/
+ @SystemApi
@Deprecated
public long getExpireAt() {
- return mExpireAt;
+ return mExpireAtRealtimeMillis;
}
/**
- * Set the duration of this request in milliseconds of realtime. Values less than 0 are allowed,
- * but indicate that the request has already expired. The location manager will automatically
- * stop updates after the request expires.
- *
- * @param millis duration of request in milliseconds
- * @return the same object, so that setters can be chained
- * @see SystemClock#elapsedRealtime()
+ * @hide
+ * @deprecated LocationRequests should be treated as immutable.
*/
+ @SystemApi
+ @Deprecated
public @NonNull LocationRequest setExpireIn(long millis) {
- mExpireIn = millis;
+ mDurationMillis = millis;
return this;
}
/**
- * Get the request expiration duration in milliseconds of realtime.
- *
- * @return request expiration duration in milliseconds
- * @see SystemClock#elapsedRealtime()
+ * @hide
+ * @deprecated Use {@link #getDurationMillis()} instead.
*/
+ @SystemApi
+ @Deprecated
public long getExpireIn() {
- return mExpireIn;
+ return getDurationMillis();
}
/**
- * Returns the realtime at which this request expires, taking into account both
- * {@link #setExpireAt(long)} and {@link #setExpireIn(long)} relative to the given realtime.
+ * Returns the duration for which location will be provided before the request is automatically
+ * removed. A duration of <code>Long.MAX_VALUE</code> represents an unlimited duration.
*
+ * @return the duration for which location will be provided
+ */
+ public long getDurationMillis() {
+ return mDurationMillis;
+ }
+
+ /**
* @hide
*/
public long getExpirationRealtimeMs(long startRealtimeMs) {
long expirationRealtimeMs;
// Check for > Long.MAX_VALUE overflow (elapsedRealtime > 0):
- if (mExpireIn > Long.MAX_VALUE - startRealtimeMs) {
+ if (mDurationMillis > Long.MAX_VALUE - startRealtimeMs) {
expirationRealtimeMs = Long.MAX_VALUE;
} else {
- expirationRealtimeMs = startRealtimeMs + mExpireIn;
+ expirationRealtimeMs = startRealtimeMs + mDurationMillis;
}
- return Math.min(expirationRealtimeMs, mExpireAt);
+ return min(expirationRealtimeMs, mExpireAtRealtimeMillis);
}
/**
- * Set the number of location updates.
- *
- * <p>By default locations are continuously updated until the request is explicitly
- * removed, however you can optionally request a set number of updates.
- * For example, if your application only needs a single fresh location,
- * then call this method with a value of 1 before passing the request
- * to the location manager.
- *
- * @param numUpdates the number of location updates requested
- * @return the same object, so that setters can be chained
- * @throws IllegalArgumentException if numUpdates is 0 or less
+ * @hide
+ * @deprecated LocationRequests should be treated as immutable.
*/
+ @SystemApi
+ @Deprecated
public @NonNull LocationRequest setNumUpdates(int numUpdates) {
if (numUpdates <= 0) {
throw new IllegalArgumentException(
"invalid numUpdates: " + numUpdates);
}
- mNumUpdates = numUpdates;
+ mMaxUpdates = numUpdates;
return this;
}
/**
- * Get the number of updates requested.
- *
- * <p>By default this is {@link Integer#MAX_VALUE}, which indicates that
- * locations are updated until the request is explicitly removed.
- *
- * @return number of updates
+ * @hide
+ * @deprecated Use {@link #getMaxUpdates()} instead.
*/
+ @SystemApi
+ @Deprecated
public int getNumUpdates() {
- return mNumUpdates;
+ return getMaxUpdates();
}
- /** @hide */
- public void decrementNumUpdates() {
- if (mNumUpdates != Integer.MAX_VALUE) {
- mNumUpdates--;
- }
- if (mNumUpdates < 0) {
- mNumUpdates = 0;
+ /**
+ * Returns the maximum number of location updates for this request before the request is
+ * automatically removed. A max updates value of <code>Integer.MAX_VALUE</code> represents an
+ * unlimited number of updates.
+ */
+ public int getMaxUpdates() {
+ return mMaxUpdates;
+ }
+
+ /**
+ * Returns the minimum update interval. If location updates are available faster than the
+ * request interval then locations will only be delivered if the minimum update interval has
+ * expired since the last location update.
+ *
+ * <p class=note><strong>Note:</strong> Some allowance for jitter is already built into the
+ * minimum update interval, so you need not worry about updates blocked simply because they
+ * arrived a fraction of a second earlier than expected.
+ *
+ * @return the minimum update interval
+ */
+ public long getMinUpdateIntervalMillis() {
+ if (mMinUpdateIntervalMillis == IMPLICIT_MIN_UPDATE_INTERVAL) {
+ return mInterval;
+ } else {
+ // the min is only necessary in case someone use a deprecated function to mess with the
+ // interval or min update interval
+ return min(mMinUpdateIntervalMillis, mInterval);
}
}
- /** Sets the provider to use for this location request. */
- public @NonNull LocationRequest setProvider(@NonNull String provider) {
- Preconditions.checkArgument(provider != null, "invalid provider: null");
- mProvider = provider;
+ /**
+ * @hide
+ * @deprecated LocationRequests should be treated as immutable.
+ */
+ @SystemApi
+ @Deprecated
+ public @NonNull LocationRequest setSmallestDisplacement(float minDisplacementMeters) {
+ mMinUpdateDistanceMeters = Preconditions.checkArgumentInRange(minDisplacementMeters, 0,
+ Float.MAX_VALUE, "minDisplacementMeters");
return this;
}
- /** @hide */
+ /**
+ * @hide
+ * @deprecated Use {@link #getMinUpdateDistanceMeters()} instead.
+ */
@SystemApi
- public @NonNull String getProvider() {
- return mProvider;
+ @Deprecated
+ public float getSmallestDisplacement() {
+ return getMinUpdateDistanceMeters();
+ }
+
+ /**
+ * Returns the minimum distance between location updates. If a potential location update is
+ * closer to the last location update than the minimum update distance, then the potential
+ * location update will not occur. A value of 0 meters implies that no location update will ever
+ * be rejected due to failing this constraint.
+ *
+ * @return the minimum distance between location updates
+ */
+ public float getMinUpdateDistanceMeters() {
+ return mMinUpdateDistanceMeters;
}
- /** @hide */
+ /**
+ * @hide
+ * @deprecated LocationRequests should be treated as immutable.
+ */
@SystemApi
- public @NonNull LocationRequest setSmallestDisplacement(float smallestDisplacementM) {
- mSmallestDisplacement = Preconditions.checkArgumentInRange(smallestDisplacementM, 0,
- Float.MAX_VALUE, "smallestDisplacementM");
- return this;
+ @Deprecated
+ public void setHideFromAppOps(boolean hiddenFromAppOps) {
+ mHideFromAppOps = hiddenFromAppOps;
}
- /** @hide */
+ /**
+ * @hide
+ * @deprecated Use {@link #isHiddenFromAppOps()} instead.
+ */
@SystemApi
- public float getSmallestDisplacement() {
- return mSmallestDisplacement;
+ @Deprecated
+ public boolean getHideFromAppOps() {
+ return isHiddenFromAppOps();
}
/**
- * Sets the WorkSource to use for power blaming of this location request.
+ * Returns true if this request should be ignored while updating app ops with location usage.
+ * This implies that someone else (usually the creator of the location request) is responsible
+ * for updating app ops.
*
- * <p>No permissions are required to make this call, however the LocationManager
- * will throw a SecurityException when requesting location updates if the caller
- * doesn't have the {@link android.Manifest.permission#UPDATE_DEVICE_STATS} permission.
+ * @return true if this request should be ignored while updating app ops with location usage
*
- * @param workSource WorkSource defining power blame for this location request.
* @hide
*/
+ @TestApi
@SystemApi
- public void setWorkSource(@Nullable WorkSource workSource) {
- mWorkSource = workSource;
+ public boolean isHiddenFromAppOps() {
+ return mHideFromAppOps;
}
- /** @hide */
+ /**
+ * @hide
+ * @deprecated LocationRequests should be treated as immutable.
+ */
@SystemApi
- public @Nullable WorkSource getWorkSource() {
- return mWorkSource;
+ @Deprecated
+ @RequiresPermission(Manifest.permission.WRITE_SECURE_SETTINGS)
+ public @NonNull LocationRequest setLocationSettingsIgnored(boolean locationSettingsIgnored) {
+ mLocationSettingsIgnored = locationSettingsIgnored;
+ return this;
}
/**
- * Sets whether or not this location request should be hidden from AppOps.
+ * Returns true if location settings, throttling, background location limits, and any other
+ * possible limiting factors will be ignored in order to satisfy this request.
+ *
+ * @return true if all limiting factors will be ignored to satisfy this request
*
- * <p>Hiding a location request from AppOps will remove user visibility in the UI as to this
- * request's existence. It does not affect power blaming in the Battery page.
+ * @hide
+ */
+ @TestApi
+ @SystemApi
+ public boolean isLocationSettingsIgnored() {
+ return mLocationSettingsIgnored;
+ }
+
+ /**
+ * @hide
+ * @deprecated LocationRequests should be treated as immutable.
+ */
+ @SystemApi
+ @Deprecated
+ public @NonNull LocationRequest setLowPowerMode(boolean enabled) {
+ mLowPower = enabled;
+ return this;
+ }
+
+ /**
+ * @hide
+ * @deprecated Use {@link #isLowPower()} instead.
+ */
+ @Deprecated
+ @SystemApi
+ public boolean isLowPowerMode() {
+ return isLowPower();
+ }
+
+ /**
+ * Returns true if extreme trade-offs should be made to save power for this request. This
+ * usually involves specialized hardware modes which can greatly affect the quality of
+ * locations.
*
- * <p>No permissions are required to make this call, however the LocationManager
- * will throw a SecurityException when requesting location updates if the caller
- * doesn't have the {@link android.Manifest.permission#UPDATE_APP_OPS_STATS} permission.
+ * @return true if extreme trade-offs should be made to save power for this request
*
- * @param hideFromAppOps If true AppOps won't keep track of this location request.
* @hide
- * @see android.app.AppOpsManager
*/
+ @TestApi
@SystemApi
- public void setHideFromAppOps(boolean hideFromAppOps) {
- mHideFromAppOps = hideFromAppOps;
+ public boolean isLowPower() {
+ return mLowPower;
}
- /** @hide */
+ /**
+ * @hide
+ * @deprecated LocationRequests should be treated as immutable.
+ */
@SystemApi
- public boolean getHideFromAppOps() {
- return mHideFromAppOps;
+ @Deprecated
+ public void setWorkSource(@Nullable WorkSource workSource) {
+ mWorkSource = workSource;
}
- @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 115609023)
- private static void checkQuality(int quality) {
- switch (quality) {
- case ACCURACY_FINE:
- case ACCURACY_BLOCK:
- case ACCURACY_CITY:
- case POWER_NONE:
- case POWER_LOW:
- case POWER_HIGH:
- break;
- default:
- throw new IllegalArgumentException("invalid quality: " + quality);
- }
+ /**
+ * Returns the work source used for power blame for this request. If null, the system is free to
+ * assign power blame as it deems most appropriate.
+ *
+ * @return the work source used for power blame for this request
+ *
+ * @hide
+ */
+ @TestApi
+ @SystemApi
+ public @Nullable WorkSource getWorkSource() {
+ return mWorkSource;
}
+
public static final @NonNull Parcelable.Creator<LocationRequest> CREATOR =
new Parcelable.Creator<LocationRequest>() {
@Override
public LocationRequest createFromParcel(Parcel in) {
return new LocationRequest(
/* provider= */ in.readString(),
+ /* intervalMillis= */ in.readLong(),
/* quality= */ in.readInt(),
- /* interval= */ in.readLong(),
- /* fastestInterval= */ in.readLong(),
- /* explicitFastestInterval= */ in.readBoolean(),
- /* expireAt= */ in.readLong(),
- /* expireIn= */ in.readLong(),
- /* numUpdates= */ in.readInt(),
- /* smallestDisplacement= */ in.readFloat(),
- /* hideFromAppOps= */ in.readBoolean(),
+ /* expireAtRealtimeMillis= */ in.readLong(),
+ /* durationMillis= */ in.readLong(),
+ /* maxUpdates= */ in.readInt(),
+ /* minUpdateIntervalMillis= */ in.readLong(),
+ /* minUpdateDistanceMeters= */ in.readFloat(),
+ /* hiddenFromAppOps= */ in.readBoolean(),
/* locationSettingsIgnored= */ in.readBoolean(),
- /* lowPowerMode= */ in.readBoolean(),
+ /* lowPower= */ in.readBoolean(),
/* workSource= */ in.readTypedObject(WorkSource.CREATOR));
}
@@ -728,42 +679,21 @@ public final class LocationRequest implements Parcelable {
}
@Override
- public void writeToParcel(Parcel parcel, int flags) {
+ public void writeToParcel(@NonNull Parcel parcel, int flags) {
parcel.writeString(mProvider);
- parcel.writeInt(mQuality);
parcel.writeLong(mInterval);
- parcel.writeLong(mFastestInterval);
- parcel.writeBoolean(mExplicitFastestInterval);
- parcel.writeLong(mExpireAt);
- parcel.writeLong(mExpireIn);
- parcel.writeInt(mNumUpdates);
- parcel.writeFloat(mSmallestDisplacement);
+ parcel.writeInt(mQuality);
+ parcel.writeLong(mExpireAtRealtimeMillis);
+ parcel.writeLong(mDurationMillis);
+ parcel.writeInt(mMaxUpdates);
+ parcel.writeLong(mMinUpdateIntervalMillis);
+ parcel.writeFloat(mMinUpdateDistanceMeters);
parcel.writeBoolean(mHideFromAppOps);
parcel.writeBoolean(mLocationSettingsIgnored);
- parcel.writeBoolean(mLowPowerMode);
+ parcel.writeBoolean(mLowPower);
parcel.writeTypedObject(mWorkSource, 0);
}
- /** @hide */
- public static String qualityToString(int quality) {
- switch (quality) {
- case ACCURACY_FINE:
- return "ACCURACY_FINE";
- case ACCURACY_BLOCK:
- return "ACCURACY_BLOCK";
- case ACCURACY_CITY:
- return "ACCURACY_CITY";
- case POWER_NONE:
- return "POWER_NONE";
- case POWER_LOW:
- return "POWER_LOW";
- case POWER_HIGH:
- return "POWER_HIGH";
- default:
- return "???";
- }
- }
-
@Override
public boolean equals(Object o) {
if (this == o) {
@@ -774,18 +704,17 @@ public final class LocationRequest implements Parcelable {
}
LocationRequest that = (LocationRequest) o;
- return mQuality == that.mQuality
- && mInterval == that.mInterval
- && mFastestInterval == that.mFastestInterval
- && mExplicitFastestInterval == that.mExplicitFastestInterval
- && mExpireAt == that.mExpireAt
- && mExpireIn == that.mExpireIn
- && mNumUpdates == that.mNumUpdates
- && Float.compare(that.mSmallestDisplacement, mSmallestDisplacement) == 0
+ return mInterval == that.mInterval
+ && mQuality == that.mQuality
+ && mExpireAtRealtimeMillis == that.mExpireAtRealtimeMillis
+ && mDurationMillis == that.mDurationMillis
+ && mMaxUpdates == that.mMaxUpdates
+ && mMinUpdateIntervalMillis == that.mMinUpdateIntervalMillis
+ && Float.compare(that.mMinUpdateDistanceMeters, mMinUpdateDistanceMeters) == 0
&& mHideFromAppOps == that.mHideFromAppOps
&& mLocationSettingsIgnored == that.mLocationSettingsIgnored
- && mLowPowerMode == that.mLowPowerMode
- && mProvider.equals(that.mProvider)
+ && mLowPower == that.mLowPower
+ && Objects.equals(mProvider, that.mProvider)
&& Objects.equals(mWorkSource, that.mWorkSource);
}
@@ -799,33 +728,371 @@ public final class LocationRequest implements Parcelable {
public String toString() {
StringBuilder s = new StringBuilder();
s.append("Request[");
- s.append(qualityToString(mQuality));
- s.append(" ").append(mProvider);
- if (mQuality != POWER_NONE) {
- s.append(" interval=");
+ if (mProvider != null) {
+ s.append(mProvider).append(" ");
+ }
+ if (mQuality != POWER_NONE && mQuality != ACCURACY_BLOCK) {
+ s.append(qualityToString(mQuality)).append(" ");
+ }
+ if (mInterval != PASSIVE_INTERVAL) {
+ s.append("interval=");
TimeUtils.formatDuration(mInterval, s);
- if (mExplicitFastestInterval && mFastestInterval != mInterval) {
- s.append(" fastestInterval=");
- TimeUtils.formatDuration(mFastestInterval, s);
- }
+ } else {
+ s.append("PASSIVE");
+ }
+ if (mExpireAtRealtimeMillis != Long.MAX_VALUE) {
+ s.append(" expireAt=").append(TimeUtils.formatRealtime(mExpireAtRealtimeMillis));
}
- if (mExpireAt != Long.MAX_VALUE) {
- s.append(" expireAt=").append(TimeUtils.formatRealtime(mExpireAt));
+ if (mDurationMillis != Long.MAX_VALUE) {
+ s.append(" duration=");
+ TimeUtils.formatDuration(mDurationMillis, s);
}
- if (mExpireIn != Long.MAX_VALUE) {
- s.append(" expireIn=");
- TimeUtils.formatDuration(mExpireIn, s);
+ if (mMaxUpdates != Integer.MAX_VALUE) {
+ s.append(" maxUpdates=").append(mMaxUpdates);
}
- if (mNumUpdates != Integer.MAX_VALUE) {
- s.append(" num=").append(mNumUpdates);
+ if (mMinUpdateIntervalMillis < mInterval) {
+ s.append(" minUpdateInterval=");
+ TimeUtils.formatDuration(mMinUpdateIntervalMillis, s);
}
- if (mLowPowerMode) {
- s.append(" lowPowerMode");
+ if (mMinUpdateDistanceMeters > 0.0) {
+ s.append(" minUpdateDistance=").append(mMinUpdateDistanceMeters);
+ }
+ if (mLowPower) {
+ s.append(" lowPower");
+ }
+ if (mHideFromAppOps) {
+ s.append(" hiddenFromAppOps");
}
if (mLocationSettingsIgnored) {
s.append(" locationSettingsIgnored");
}
+ if (mWorkSource != null) {
+ s.append(" ").append(mWorkSource);
+ }
s.append(']');
return s.toString();
}
+
+ private static String qualityToString(int quality) {
+ switch (quality) {
+ case ACCURACY_FINE:
+ return "ACCURACY_FINE";
+ case ACCURACY_BLOCK:
+ return "ACCURACY_BLOCK";
+ case ACCURACY_CITY:
+ return "ACCURACY_CITY";
+ case POWER_NONE:
+ return "POWER_NONE";
+ case POWER_LOW:
+ return "POWER_LOW";
+ case POWER_HIGH:
+ return "POWER_HIGH";
+ default:
+ return "???";
+ }
+ }
+
+ /**
+ * A builder class for {@link LocationRequest}.
+ */
+ public static final class Builder {
+
+ private static int checkQuality(int quality, boolean allowDeprecated) {
+ switch (quality) {
+ case ACCURACY_FINE:
+ // fall through
+ case ACCURACY_BLOCK:
+ // fall through
+ case ACCURACY_CITY:
+ // fall through
+ case POWER_LOW:
+ // fall through
+ case POWER_HIGH:
+ return quality;
+ case POWER_NONE:
+ if (allowDeprecated) {
+ return quality;
+ }
+ // fall through
+ default:
+ throw new IllegalArgumentException("invalid quality: " + quality);
+ }
+ }
+
+ private long mIntervalMillis;
+ private int mQuality;
+ private long mDurationMillis;
+ private int mMaxUpdates;
+ private long mMinUpdateIntervalMillis;
+ private float mMinUpdateDistanceMeters;
+ private boolean mHiddenFromAppOps;
+ private boolean mLocationSettingsIgnored;
+ private boolean mLowPower;
+ @Nullable private WorkSource mWorkSource;
+
+ /**
+ * Creates a new Builder with the given interval. See {@link #setIntervalMillis(long)} for
+ * more information on the interval.
+ */
+ public Builder(long intervalMillis) {
+ // gives us a range check
+ setIntervalMillis(intervalMillis);
+
+ mQuality = ACCURACY_BLOCK;
+ mDurationMillis = Long.MAX_VALUE;
+ mMaxUpdates = Integer.MAX_VALUE;
+ mMinUpdateIntervalMillis = IMPLICIT_MIN_UPDATE_INTERVAL;
+ mMinUpdateDistanceMeters = 0;
+ mHiddenFromAppOps = false;
+ mLocationSettingsIgnored = false;
+ mLowPower = false;
+ mWorkSource = null;
+ }
+
+ /**
+ * Creates a new Builder with all parameters copied from the given location request.
+ */
+ public Builder(@NonNull LocationRequest locationRequest) {
+ mIntervalMillis = locationRequest.mInterval;
+ mQuality = locationRequest.mQuality;
+ mDurationMillis = locationRequest.mDurationMillis;
+ mMaxUpdates = locationRequest.mMaxUpdates;
+ mMinUpdateIntervalMillis = locationRequest.mMinUpdateIntervalMillis;
+ mMinUpdateDistanceMeters = locationRequest.mMinUpdateDistanceMeters;
+ mHiddenFromAppOps = locationRequest.mHideFromAppOps;
+ mLocationSettingsIgnored = locationRequest.mLocationSettingsIgnored;
+ mLowPower = locationRequest.mLowPower;
+ mWorkSource = locationRequest.mWorkSource;
+
+ // handle edge cases that can only happen with location request that has been modified
+ // by deprecated SystemApi methods
+ if (mQuality == POWER_NONE) {
+ mIntervalMillis = PASSIVE_INTERVAL;
+ }
+ if (mIntervalMillis == PASSIVE_INTERVAL
+ && mMinUpdateIntervalMillis == IMPLICIT_MIN_UPDATE_INTERVAL) {
+ // this is the legacy default minimum update interval, so if we're forced to
+ // change the value, at least this should be unsuprising to legacy clients (which
+ // should be the only clients capable of getting in this weird state).
+ mMinUpdateIntervalMillis = 10 * 60 * 1000;
+ }
+ }
+
+ /**
+ * Sets the request interval. The request interval may be set to {@link #PASSIVE_INTERVAL}
+ * which indicates this request will not actively generate location updates (and thus will
+ * not be power blamed for location), but may receive location updates generated as a result
+ * of other location requests. A passive request must always have an explicit minimum
+ * update interval set.
+ *
+ * <p>Locations may be available at a faster interval than specified here, see
+ * {@link #setMinUpdateIntervalMillis(long)} for the behavior in that case.
+ */
+ public @NonNull Builder setIntervalMillis(@IntRange(from = 0) long intervalMillis) {
+ mIntervalMillis = Preconditions.checkArgumentInRange(intervalMillis, 0, Long.MAX_VALUE,
+ "intervalMillis");
+ return this;
+ }
+
+ /**
+ * @hide
+ */
+ @SystemApi
+ public @NonNull Builder setQuality(int quality) {
+ mQuality = checkQuality(quality, false);
+ return this;
+ }
+
+ /**
+ * @hide
+ */
+ public @NonNull Builder setQuality(@NonNull Criteria criteria) {
+ switch (criteria.getAccuracy()) {
+ case Criteria.ACCURACY_COARSE:
+ mQuality = ACCURACY_BLOCK;
+ break;
+ case Criteria.ACCURACY_FINE:
+ mQuality = ACCURACY_FINE;
+ break;
+ default: {
+ if (criteria.getPowerRequirement() == Criteria.POWER_HIGH) {
+ mQuality = POWER_HIGH;
+ } else {
+ mQuality = POWER_LOW;
+ }
+ }
+ }
+ return this;
+ }
+
+ /**
+ * Sets the duration this request will continue before being automatically removed. Defaults
+ * to <code>Long.MAX_VALUE</code>, which represents an unlimited duration.
+ */
+ public @NonNull Builder setDurationMillis(@IntRange(from = 1) long durationMillis) {
+ mDurationMillis = Preconditions.checkArgumentInRange(durationMillis, 1, Long.MAX_VALUE,
+ "durationMillis");
+ return this;
+ }
+
+ /**
+ * Sets the maximum number of location updates for this request before this request is
+ * automatically removed. Defaults to <code>Integer.MAX_VALUE</code>, which represents an
+ * unlimited number of updates.
+ */
+ public @NonNull Builder setMaxUpdates(
+ @IntRange(from = 1, to = Integer.MAX_VALUE) int maxUpdates) {
+ mMaxUpdates = Preconditions.checkArgumentInRange(maxUpdates, 1, Integer.MAX_VALUE,
+ "maxUpdates");
+ return this;
+ }
+
+ /**
+ * Sets an explicit minimum update interval. If location updates are available faster than
+ * the request interval then locations will only be delivered if the minimum update interval
+ * has expired since the last location update. Defaults to no explicit minimum update
+ * interval set, which means the minimum update interval is the same as the interval.
+ *
+ * <p class=note><strong>Note:</strong> Some allowance for jitter is already built into the
+ * minimum update interval, so you need not worry about updates blocked simply because they
+ * arrived a fraction of a second earlier than expected.
+ *
+ * <p class="note"><strong>Note:</strong> When {@link #build()} is invoked, the minimum of
+ * the interval and the minimum update interval will be used as the minimum update interval
+ * of the built request.
+ */
+ public @NonNull Builder setMinUpdateIntervalMillis(
+ @IntRange(from = 0) long minUpdateIntervalMillis) {
+ mMinUpdateIntervalMillis = Preconditions.checkArgumentInRange(minUpdateIntervalMillis,
+ 0, Long.MAX_VALUE, "minUpdateIntervalMillis");
+ return this;
+ }
+
+ /**
+ * Clears an explicitly set minimum update interval and reverts to an implicit minimum
+ * update interval which is the same as the interval.
+ */
+ public @NonNull Builder clearMinUpdateIntervalMillis() {
+ mMinUpdateIntervalMillis = IMPLICIT_MIN_UPDATE_INTERVAL;
+ return this;
+ }
+
+ /**
+ * Sets the minimum update distance between delivered locations. If a potential location
+ * update is closer to the last delivered location than the minimum update distance, then
+ * the potential location update will not occur. Defaults to 0, which represents no minimum
+ * update distance.
+ */
+ public @NonNull Builder setMinUpdateDistanceMeters(
+ @FloatRange(from = 0, to = Float.MAX_VALUE) float minUpdateDistanceMeters) {
+ mMinUpdateDistanceMeters = Preconditions.checkArgumentInRange(minUpdateDistanceMeters,
+ 0, Float.MAX_VALUE, "minUpdateDistanceMeters");
+ return this;
+ }
+
+ /**
+ * If set to true, indicates that app ops should not be updated with location usage due to
+ * this request. This implies that someone else (usually the creator of the location
+ * request) is responsible for updating app ops as appropriate. Defaults to false.
+ *
+ * <p>Permissions enforcement occurs when resulting location request is actually used, not
+ * when this method is invoked.
+ *
+ * @hide
+ */
+ @TestApi
+ @SystemApi
+ @RequiresPermission(Manifest.permission.UPDATE_APP_OPS_STATS)
+ public @NonNull Builder setHiddenFromAppOps(boolean hiddenFromAppOps) {
+ mHiddenFromAppOps = hiddenFromAppOps;
+ return this;
+ }
+
+ /**
+ * If set to true, indicates that location settings, throttling, background location limits,
+ * and any other possible limiting factors should be ignored in order to satisfy this
+ * request. This is only intended for use in user initiated emergency situations, and
+ * should be used extremely cautiously. Defaults to false.
+ *
+ * <p>Permissions enforcement occurs when resulting location request is actually used, not
+ * when this method is invoked.
+ *
+ * @hide
+ */
+ @TestApi
+ @SystemApi
+ @RequiresPermission(Manifest.permission.WRITE_SECURE_SETTINGS)
+ public @NonNull Builder setLocationSettingsIgnored(boolean locationSettingsIgnored) {
+ mLocationSettingsIgnored = locationSettingsIgnored;
+ return this;
+ }
+
+ /**
+ * It set to true, indicates that extreme trade-offs should be made if possible to save
+ * power for this request. This usually involves specialized hardware modes which can
+ * greatly affect the quality of locations. Defaults to false.
+ *
+ * <p>Permissions enforcement occurs when resulting location request is actually used, not
+ * when this method is invoked.
+ *
+ * @hide
+ */
+ @TestApi
+ @SystemApi
+ @RequiresPermission(Manifest.permission.LOCATION_HARDWARE)
+ public @NonNull Builder setLowPower(boolean lowPower) {
+ mLowPower = lowPower;
+ return this;
+ }
+
+ /**
+ * Sets the work source to use for power blame for this location request. Defaults to null,
+ * which implies the system is free to assign power blame as it determines best for this
+ * request (which usually means blaming the owner of the location listener).
+ *
+ * <p>Permissions enforcement occurs when resulting location request is actually used, not
+ * when this method is invoked.
+ *
+ * @hide
+ */
+ @TestApi
+ @SystemApi
+ @RequiresPermission(Manifest.permission.UPDATE_DEVICE_STATS)
+ public @NonNull Builder setWorkSource(@Nullable WorkSource workSource) {
+ mWorkSource = workSource;
+ return this;
+ }
+
+ /**
+ * Builds a location request from this builder. If an explicit minimum update interval is
+ * set, the minimum update interval of the location request will be the minimum of the
+ * interval and minimum update interval.
+ *
+ * <p>If building a passive request then you must have set an explicit minimum update
+ * interval.
+ *
+ * @throws IllegalStateException if building a passive request with no explicit minimum
+ * update interval set
+ * @return a new location request
+ */
+ public @NonNull LocationRequest build() {
+ Preconditions.checkState(mIntervalMillis != PASSIVE_INTERVAL
+ || mMinUpdateIntervalMillis != IMPLICIT_MIN_UPDATE_INTERVAL,
+ "passive location requests must have an explicit minimum update interval");
+
+ return new LocationRequest(
+ null,
+ mIntervalMillis,
+ mIntervalMillis != PASSIVE_INTERVAL ? mQuality : POWER_NONE,
+ Long.MAX_VALUE,
+ mDurationMillis,
+ mMaxUpdates,
+ min(mMinUpdateIntervalMillis, mIntervalMillis),
+ mMinUpdateDistanceMeters,
+ mHiddenFromAppOps,
+ mLocationSettingsIgnored,
+ mLowPower,
+ mWorkSource);
+ }
+ }
}
diff --git a/location/lib/java/com/android/location/provider/LocationRequestUnbundled.java b/location/lib/java/com/android/location/provider/LocationRequestUnbundled.java
index 2511c39caf5c..92e05ef68e3b 100644
--- a/location/lib/java/com/android/location/provider/LocationRequestUnbundled.java
+++ b/location/lib/java/com/android/location/provider/LocationRequestUnbundled.java
@@ -82,25 +82,21 @@ public final class LocationRequestUnbundled {
}
/**
- * Get the desired interval of this request, in milliseconds.
+ * Get the location update interval.
*
- * @return desired interval in milliseconds, inexact
+ * @return location update interval
*/
public long getInterval() {
- return delegate.getInterval();
+ return delegate.getIntervalMillis();
}
/**
- * Get the fastest interval of this request, in milliseconds.
+ * Get the minimum delivery interval.
*
- * <p>The system will never provide location updates faster
- * than the minimum of {@link #getFastestInterval} and
- * {@link #getInterval}.
- *
- * @return fastest interval in milliseconds, exact
+ * @return minimum delivery interval
*/
public long getFastestInterval() {
- return delegate.getFastestInterval();
+ return delegate.getMinUpdateIntervalMillis();
}
/**
@@ -118,7 +114,7 @@ public final class LocationRequestUnbundled {
* @return minimum distance between location updates in meters
*/
public float getSmallestDisplacement() {
- return delegate.getSmallestDisplacement();
+ return delegate.getMinUpdateDistanceMeters();
}
/**
diff --git a/media/java/android/media/MicrophoneInfo.java b/media/java/android/media/MicrophoneInfo.java
index 876628fefff4..acd284f3fad9 100644
--- a/media/java/android/media/MicrophoneInfo.java
+++ b/media/java/android/media/MicrophoneInfo.java
@@ -268,8 +268,11 @@ public final class MicrophoneInfo {
/**
* Returns A {@link Coordinate3F} object that represents the geometric location of microphone
- * in meters, from bottom-left-back corner of appliance. X-axis, Y-axis and Z-axis show
- * as the x, y, z values.
+ * in meters. X-axis, Y-axis and Z-axis show as the x, y, z values. For mobile devices, the axes
+ * originate from the bottom-left-back corner of the appliance. In devices with
+ * {@link android.content.pm.PackageManager#FEATURE_AUTOMOTIVE}, axes are defined with respect
+ * to the vehicle body frame, originating from the center of the vehicle's rear axle.
+ * @see <a href="https://source.android.com/devices/sensors/sensor-types#auto_axes">auto axes</a>
*
* @return the geometric location of the microphone or {@link #POSITION_UNKNOWN} if the
* geometric location is unknown
diff --git a/media/java/android/media/browse/MediaBrowser.java b/media/java/android/media/browse/MediaBrowser.java
index 029e61492b6d..011e835e02ec 100644
--- a/media/java/android/media/browse/MediaBrowser.java
+++ b/media/java/android/media/browse/MediaBrowser.java
@@ -210,7 +210,7 @@ public final class MediaBrowser {
public void disconnect() {
// It's ok to call this any state, because allowing this lets apps not have
// to check isConnected() unnecessarily. They won't appreciate the extra
- // assertions for this. We do everything we can here to go back to a sane state.
+ // assertions for this. We do everything we can here to go back to a valid state.
mState = CONNECT_STATE_DISCONNECTING;
mHandler.post(new Runnable() {
@Override
diff --git a/media/java/android/media/session/MediaSessionManager.java b/media/java/android/media/session/MediaSessionManager.java
index 20006934ee46..9494295e4bd9 100644
--- a/media/java/android/media/session/MediaSessionManager.java
+++ b/media/java/android/media/session/MediaSessionManager.java
@@ -68,16 +68,19 @@ public final class MediaSessionManager {
private static final String TAG = "SessionManager";
/**
- * Used by IOnMediaKeyListener to indicate that the media key event isn't handled.
+ * Used to indicate that the media key event isn't handled.
* @hide
*/
+ @SystemApi(client = SystemApi.Client.MODULE_LIBRARIES)
public static final int RESULT_MEDIA_KEY_NOT_HANDLED = 0;
/**
- * Used by IOnMediaKeyListener to indicate that the media key event is handled.
+ * Used to indicate that the media key event is handled.
* @hide
*/
+ @SystemApi(client = SystemApi.Client.MODULE_LIBRARIES)
public static final int RESULT_MEDIA_KEY_HANDLED = 1;
+
private final ISessionManager mService;
private final OnMediaKeyEventDispatchedListenerStub mOnMediaKeyEventDispatchedListenerStub =
new OnMediaKeyEventDispatchedListenerStub();
diff --git a/non-updatable-api/current.txt b/non-updatable-api/current.txt
index 26a0ad917c99..4dd3f008f97a 100644
--- a/non-updatable-api/current.txt
+++ b/non-updatable-api/current.txt
@@ -11447,6 +11447,16 @@ package android.content.pm {
field public final float widthFraction;
}
+ public final class ApkChecksum implements android.os.Parcelable {
+ method public int describeContents();
+ method public int getKind();
+ method @Nullable public java.security.cert.Certificate getSourceCertificate() throws java.security.cert.CertificateException;
+ method @Nullable public String getSplitName();
+ method @NonNull public byte[] getValue();
+ method public void writeToParcel(@NonNull android.os.Parcel, int);
+ field @NonNull public static final android.os.Parcelable.Creator<android.content.pm.ApkChecksum> CREATOR;
+ }
+
public class ApplicationInfo extends android.content.pm.PackageItemInfo implements android.os.Parcelable {
ctor public ApplicationInfo();
ctor public ApplicationInfo(android.content.pm.ApplicationInfo);
@@ -11548,6 +11558,21 @@ package android.content.pm {
field @NonNull public static final android.os.Parcelable.Creator<android.content.pm.ChangedPackages> CREATOR;
}
+ public final class Checksum implements android.os.Parcelable {
+ method public int describeContents();
+ method public int getKind();
+ method @NonNull public byte[] getValue();
+ method public void writeToParcel(@NonNull android.os.Parcel, int);
+ field @NonNull public static final android.os.Parcelable.Creator<android.content.pm.Checksum> CREATOR;
+ field public static final int PARTIAL_MERKLE_ROOT_1M_SHA256 = 32; // 0x20
+ field public static final int PARTIAL_MERKLE_ROOT_1M_SHA512 = 64; // 0x40
+ field public static final int WHOLE_MD5 = 2; // 0x2
+ field public static final int WHOLE_MERKLE_ROOT_4K_SHA256 = 1; // 0x1
+ field public static final int WHOLE_SHA1 = 4; // 0x4
+ field public static final int WHOLE_SHA256 = 8; // 0x8
+ field public static final int WHOLE_SHA512 = 16; // 0x10
+ }
+
public class ComponentInfo extends android.content.pm.PackageItemInfo {
ctor public ComponentInfo();
ctor public ComponentInfo(android.content.pm.ComponentInfo);
@@ -11619,16 +11644,6 @@ package android.content.pm {
field public int version;
}
- public final class FileChecksum implements android.os.Parcelable {
- method public int describeContents();
- method public int getKind();
- method @Nullable public java.security.cert.Certificate getSourceCertificate() throws java.security.cert.CertificateException;
- method @Nullable public String getSplitName();
- method @NonNull public byte[] getValue();
- method public void writeToParcel(@NonNull android.os.Parcel, int);
- field @NonNull public static final android.os.Parcelable.Creator<android.content.pm.FileChecksum> CREATOR;
- }
-
public final class InstallSourceInfo implements android.os.Parcelable {
method public int describeContents();
method @Nullable public String getInitiatingPackageName();
@@ -11849,6 +11864,7 @@ package android.content.pm {
public static class PackageInstaller.Session implements java.io.Closeable {
method public void abandon();
+ method public void addChecksums(@NonNull String, @NonNull java.util.List<android.content.pm.Checksum>) throws java.io.IOException;
method public void addChildSessionId(int);
method public void close();
method public void commit(@NonNull android.content.IntentSender);
@@ -12250,8 +12266,6 @@ package android.content.pm {
field public static final int MATCH_SYSTEM_ONLY = 1048576; // 0x100000
field public static final int MATCH_UNINSTALLED_PACKAGES = 8192; // 0x2000
field public static final long MAXIMUM_VERIFICATION_TIMEOUT = 3600000L; // 0x36ee80L
- field public static final int PARTIAL_MERKLE_ROOT_1M_SHA256 = 32; // 0x20
- field public static final int PARTIAL_MERKLE_ROOT_1M_SHA512 = 64; // 0x40
field public static final int PERMISSION_DENIED = -1; // 0xffffffff
field public static final int PERMISSION_GRANTED = 0; // 0x0
field public static final int SIGNATURE_FIRST_NOT_SIGNED = -1; // 0xffffffff
@@ -12266,11 +12280,6 @@ package android.content.pm {
field public static final int VERIFICATION_ALLOW = 1; // 0x1
field public static final int VERIFICATION_REJECT = -1; // 0xffffffff
field public static final int VERSION_CODE_HIGHEST = -1; // 0xffffffff
- field public static final int WHOLE_MD5 = 2; // 0x2
- field public static final int WHOLE_MERKLE_ROOT_4K_SHA256 = 1; // 0x1
- field public static final int WHOLE_SHA1 = 4; // 0x4
- field public static final int WHOLE_SHA256 = 8; // 0x8
- field public static final int WHOLE_SHA512 = 16; // 0x10
}
public static class PackageManager.NameNotFoundException extends android.util.AndroidException {
@@ -23898,6 +23907,7 @@ package android.location {
method @NonNull public java.util.List<java.lang.String> getAllProviders();
method @Nullable public String getBestProvider(@NonNull android.location.Criteria, boolean);
method @RequiresPermission(anyOf={android.Manifest.permission.ACCESS_COARSE_LOCATION, android.Manifest.permission.ACCESS_FINE_LOCATION}) public void getCurrentLocation(@NonNull String, @Nullable android.os.CancellationSignal, @NonNull java.util.concurrent.Executor, @NonNull java.util.function.Consumer<android.location.Location>);
+ method @RequiresPermission(anyOf={android.Manifest.permission.ACCESS_COARSE_LOCATION, android.Manifest.permission.ACCESS_FINE_LOCATION}) public void getCurrentLocation(@NonNull String, @NonNull android.location.LocationRequest, @Nullable android.os.CancellationSignal, @NonNull java.util.concurrent.Executor, @NonNull java.util.function.Consumer<android.location.Location>);
method @NonNull public android.location.GnssCapabilities getGnssCapabilities();
method @Nullable public String getGnssHardwareModelName();
method public int getGnssYearOfHardware();
@@ -23932,6 +23942,8 @@ package android.location {
method @RequiresPermission(anyOf={android.Manifest.permission.ACCESS_COARSE_LOCATION, android.Manifest.permission.ACCESS_FINE_LOCATION}) public void requestLocationUpdates(long, float, @NonNull android.location.Criteria, @NonNull java.util.concurrent.Executor, @NonNull android.location.LocationListener);
method @RequiresPermission(anyOf={android.Manifest.permission.ACCESS_COARSE_LOCATION, android.Manifest.permission.ACCESS_FINE_LOCATION}) public void requestLocationUpdates(@NonNull String, long, float, @NonNull android.app.PendingIntent);
method @RequiresPermission(anyOf={android.Manifest.permission.ACCESS_COARSE_LOCATION, android.Manifest.permission.ACCESS_FINE_LOCATION}) public void requestLocationUpdates(long, float, @NonNull android.location.Criteria, @NonNull android.app.PendingIntent);
+ method @RequiresPermission(anyOf={android.Manifest.permission.ACCESS_COARSE_LOCATION, android.Manifest.permission.ACCESS_FINE_LOCATION}) public void requestLocationUpdates(@NonNull String, @NonNull android.location.LocationRequest, @NonNull java.util.concurrent.Executor, @NonNull android.location.LocationListener);
+ method @RequiresPermission(anyOf={android.Manifest.permission.ACCESS_COARSE_LOCATION, android.Manifest.permission.ACCESS_FINE_LOCATION}) public void requestLocationUpdates(@NonNull String, @NonNull android.location.LocationRequest, @NonNull android.app.PendingIntent);
method @Deprecated @RequiresPermission(anyOf={android.Manifest.permission.ACCESS_COARSE_LOCATION, android.Manifest.permission.ACCESS_FINE_LOCATION}) public void requestSingleUpdate(@NonNull String, @NonNull android.location.LocationListener, @Nullable android.os.Looper);
method @Deprecated @RequiresPermission(anyOf={android.Manifest.permission.ACCESS_COARSE_LOCATION, android.Manifest.permission.ACCESS_FINE_LOCATION}) public void requestSingleUpdate(@NonNull android.location.Criteria, @NonNull android.location.LocationListener, @Nullable android.os.Looper);
method @Deprecated @RequiresPermission(anyOf={android.Manifest.permission.ACCESS_COARSE_LOCATION, android.Manifest.permission.ACCESS_FINE_LOCATION}) public void requestSingleUpdate(@NonNull String, @NonNull android.app.PendingIntent);
@@ -23975,6 +23987,30 @@ package android.location {
field @Deprecated public static final int TEMPORARILY_UNAVAILABLE = 1; // 0x1
}
+ public final class LocationRequest implements android.os.Parcelable {
+ method public int describeContents();
+ method public long getDurationMillis();
+ method public long getIntervalMillis();
+ method public int getMaxUpdates();
+ method public float getMinUpdateDistanceMeters();
+ method public long getMinUpdateIntervalMillis();
+ method public void writeToParcel(@NonNull android.os.Parcel, int);
+ field @NonNull public static final android.os.Parcelable.Creator<android.location.LocationRequest> CREATOR;
+ field public static final long PASSIVE_INTERVAL = 9223372036854775807L; // 0x7fffffffffffffffL
+ }
+
+ public static final class LocationRequest.Builder {
+ ctor public LocationRequest.Builder(long);
+ ctor public LocationRequest.Builder(@NonNull android.location.LocationRequest);
+ method @NonNull public android.location.LocationRequest build();
+ method @NonNull public android.location.LocationRequest.Builder clearMinUpdateIntervalMillis();
+ method @NonNull public android.location.LocationRequest.Builder setDurationMillis(@IntRange(from=1) long);
+ method @NonNull public android.location.LocationRequest.Builder setIntervalMillis(@IntRange(from=0) long);
+ method @NonNull public android.location.LocationRequest.Builder setMaxUpdates(@IntRange(from=1, to=java.lang.Integer.MAX_VALUE) int);
+ method @NonNull public android.location.LocationRequest.Builder setMinUpdateDistanceMeters(@FloatRange(from=0, to=java.lang.Float.MAX_VALUE) float);
+ method @NonNull public android.location.LocationRequest.Builder setMinUpdateIntervalMillis(@IntRange(from=0) long);
+ }
+
public interface OnNmeaMessageListener {
method public void onNmeaMessage(String, long);
}
@@ -44967,6 +45003,7 @@ package android.telephony {
field public static final String KEY_HIDE_PREFERRED_NETWORK_TYPE_BOOL = "hide_preferred_network_type_bool";
field public static final String KEY_HIDE_PRESET_APN_DETAILS_BOOL = "hide_preset_apn_details_bool";
field public static final String KEY_HIDE_SIM_LOCK_SETTINGS_BOOL = "hide_sim_lock_settings_bool";
+ field public static final String KEY_HIDE_TTY_HCO_VCO_WITH_RTT_BOOL = "hide_tty_hco_vco_with_rtt";
field public static final String KEY_IGNORE_DATA_ENABLED_CHANGED_FOR_VIDEO_CALLS = "ignore_data_enabled_changed_for_video_calls";
field public static final String KEY_IGNORE_RTT_MODE_SETTING_BOOL = "ignore_rtt_mode_setting_bool";
field public static final String KEY_IGNORE_SIM_NETWORK_LOCKED_EVENTS_BOOL = "ignore_sim_network_locked_events_bool";
@@ -45033,7 +45070,11 @@ package android.telephony {
field public static final String KEY_READ_ONLY_APN_TYPES_STRING_ARRAY = "read_only_apn_types_string_array";
field public static final String KEY_REQUIRE_ENTITLEMENT_CHECKS_BOOL = "require_entitlement_checks_bool";
field @Deprecated public static final String KEY_RESTART_RADIO_ON_PDP_FAIL_REGULAR_DEACTIVATION_BOOL = "restart_radio_on_pdp_fail_regular_deactivation_bool";
+ field public static final String KEY_RTT_AUTO_UPGRADE_BOOL = "rtt_auto_upgrade_bool";
+ field public static final String KEY_RTT_DOWNGRADE_SUPPORTED_BOOL = "rtt_downgrade_supported_bool";
field public static final String KEY_RTT_SUPPORTED_BOOL = "rtt_supported_bool";
+ field public static final String KEY_RTT_SUPPORTED_FOR_VT_BOOL = "rtt_supported_for_vt_bool";
+ field public static final String KEY_RTT_UPGRADE_SUPPORTED_BOOL = "rtt_upgrade_supported_bool";
field public static final String KEY_SHOW_4G_FOR_3G_DATA_ICON_BOOL = "show_4g_for_3g_data_icon_bool";
field public static final String KEY_SHOW_4G_FOR_LTE_DATA_ICON_BOOL = "show_4g_for_lte_data_icon_bool";
field public static final String KEY_SHOW_APN_SETTING_CDMA_BOOL = "show_apn_setting_cdma_bool";
diff --git a/non-updatable-api/module-lib-current.txt b/non-updatable-api/module-lib-current.txt
index f7f42d0a5956..63b98cb5bd6a 100644
--- a/non-updatable-api/module-lib-current.txt
+++ b/non-updatable-api/module-lib-current.txt
@@ -66,6 +66,8 @@ package android.media.session {
method public boolean dispatchMediaKeyEventAsSystemService(@NonNull android.media.session.MediaSession.Token, @NonNull android.view.KeyEvent);
method public void dispatchVolumeKeyEventAsSystemService(@NonNull android.view.KeyEvent, int);
method public void dispatchVolumeKeyEventAsSystemService(@NonNull android.media.session.MediaSession.Token, @NonNull android.view.KeyEvent);
+ field public static final int RESULT_MEDIA_KEY_HANDLED = 1; // 0x1
+ field public static final int RESULT_MEDIA_KEY_NOT_HANDLED = 0; // 0x0
}
}
diff --git a/non-updatable-api/system-current.txt b/non-updatable-api/system-current.txt
index 8fae240a95b4..a403f4521aa0 100644
--- a/non-updatable-api/system-current.txt
+++ b/non-updatable-api/system-current.txt
@@ -4015,7 +4015,7 @@ package android.location {
public class LocationManager {
method @RequiresPermission(android.Manifest.permission.LOCATION_HARDWARE) public void flushGnssBatch();
- method @RequiresPermission(anyOf={android.Manifest.permission.ACCESS_COARSE_LOCATION, android.Manifest.permission.ACCESS_FINE_LOCATION}) public void getCurrentLocation(@NonNull android.location.LocationRequest, @Nullable android.os.CancellationSignal, @NonNull java.util.concurrent.Executor, @NonNull java.util.function.Consumer<android.location.Location>);
+ method @Deprecated @RequiresPermission(anyOf={android.Manifest.permission.ACCESS_COARSE_LOCATION, android.Manifest.permission.ACCESS_FINE_LOCATION}) public void getCurrentLocation(@NonNull android.location.LocationRequest, @Nullable android.os.CancellationSignal, @NonNull java.util.concurrent.Executor, @NonNull java.util.function.Consumer<android.location.Location>);
method @Nullable public String getExtraLocationControllerPackage();
method @RequiresPermission(android.Manifest.permission.LOCATION_HARDWARE) public int getGnssBatchSize();
method @RequiresPermission(android.Manifest.permission.ACCESS_FINE_LOCATION) public void injectGnssMeasurementCorrections(@NonNull android.location.GnssMeasurementCorrections);
@@ -4026,9 +4026,9 @@ package android.location {
method @RequiresPermission(android.Manifest.permission.READ_DEVICE_CONFIG) public boolean isProviderPackage(@Nullable String, @NonNull String);
method @RequiresPermission(android.Manifest.permission.LOCATION_HARDWARE) public boolean registerGnssBatchedLocationCallback(long, boolean, @NonNull android.location.BatchedLocationCallback, @Nullable android.os.Handler);
method @RequiresPermission(allOf={android.Manifest.permission.ACCESS_FINE_LOCATION, android.Manifest.permission.LOCATION_HARDWARE}) public boolean registerGnssMeasurementsCallback(@NonNull android.location.GnssRequest, @NonNull java.util.concurrent.Executor, @NonNull android.location.GnssMeasurementsEvent.Callback);
- method @RequiresPermission(anyOf={android.Manifest.permission.ACCESS_COARSE_LOCATION, android.Manifest.permission.ACCESS_FINE_LOCATION}) public void requestLocationUpdates(@Nullable android.location.LocationRequest, @NonNull android.location.LocationListener, @Nullable android.os.Looper);
- method @RequiresPermission(anyOf={android.Manifest.permission.ACCESS_COARSE_LOCATION, android.Manifest.permission.ACCESS_FINE_LOCATION}) public void requestLocationUpdates(@Nullable android.location.LocationRequest, @NonNull java.util.concurrent.Executor, @NonNull android.location.LocationListener);
- method @RequiresPermission(anyOf={android.Manifest.permission.ACCESS_COARSE_LOCATION, android.Manifest.permission.ACCESS_FINE_LOCATION}) public void requestLocationUpdates(@Nullable android.location.LocationRequest, @NonNull android.app.PendingIntent);
+ method @Deprecated @RequiresPermission(anyOf={android.Manifest.permission.ACCESS_COARSE_LOCATION, android.Manifest.permission.ACCESS_FINE_LOCATION}) public void requestLocationUpdates(@Nullable android.location.LocationRequest, @NonNull android.location.LocationListener, @Nullable android.os.Looper);
+ method @Deprecated @RequiresPermission(anyOf={android.Manifest.permission.ACCESS_COARSE_LOCATION, android.Manifest.permission.ACCESS_FINE_LOCATION}) public void requestLocationUpdates(@Nullable android.location.LocationRequest, @NonNull java.util.concurrent.Executor, @NonNull android.location.LocationListener);
+ method @Deprecated @RequiresPermission(anyOf={android.Manifest.permission.ACCESS_COARSE_LOCATION, android.Manifest.permission.ACCESS_FINE_LOCATION}) public void requestLocationUpdates(@Nullable android.location.LocationRequest, @NonNull android.app.PendingIntent);
method @RequiresPermission(android.Manifest.permission.LOCATION_HARDWARE) public void setExtraLocationControllerPackage(@Nullable String);
method @RequiresPermission(android.Manifest.permission.LOCATION_HARDWARE) public void setExtraLocationControllerPackageEnabled(boolean);
method @RequiresPermission(android.Manifest.permission.WRITE_SECURE_SETTINGS) public void setLocationEnabledForUser(boolean, @NonNull android.os.UserHandle);
@@ -4037,42 +4037,49 @@ package android.location {
}
public final class LocationRequest implements android.os.Parcelable {
- method @NonNull public static android.location.LocationRequest create();
- method @NonNull public static android.location.LocationRequest createFromDeprecatedCriteria(@NonNull android.location.Criteria, long, float, boolean);
- method @NonNull public static android.location.LocationRequest createFromDeprecatedProvider(@NonNull String, long, float, boolean);
- method public int describeContents();
+ method @Deprecated @NonNull public static android.location.LocationRequest create();
+ method @Deprecated @NonNull public static android.location.LocationRequest createFromDeprecatedCriteria(@NonNull android.location.Criteria, long, float, boolean);
+ method @Deprecated @NonNull public static android.location.LocationRequest createFromDeprecatedProvider(@NonNull String, long, float, boolean);
method @Deprecated public long getExpireAt();
- method public long getExpireIn();
- method public long getFastestInterval();
- method public boolean getHideFromAppOps();
- method public long getInterval();
- method public int getNumUpdates();
- method @NonNull public String getProvider();
+ method @Deprecated public long getExpireIn();
+ method @Deprecated public long getFastestInterval();
+ method @Deprecated public boolean getHideFromAppOps();
+ method @Deprecated public long getInterval();
+ method @Deprecated public int getNumUpdates();
+ method @Deprecated @NonNull public String getProvider();
method public int getQuality();
- method public float getSmallestDisplacement();
+ method @Deprecated public float getSmallestDisplacement();
method @Nullable public android.os.WorkSource getWorkSource();
+ method public boolean isHiddenFromAppOps();
method public boolean isLocationSettingsIgnored();
- method public boolean isLowPowerMode();
+ method public boolean isLowPower();
+ method @Deprecated public boolean isLowPowerMode();
method @Deprecated @NonNull public android.location.LocationRequest setExpireAt(long);
- method @NonNull public android.location.LocationRequest setExpireIn(long);
- method @NonNull public android.location.LocationRequest setFastestInterval(long);
- method public void setHideFromAppOps(boolean);
- method @NonNull public android.location.LocationRequest setInterval(long);
- method @NonNull @RequiresPermission(android.Manifest.permission.WRITE_SECURE_SETTINGS) public android.location.LocationRequest setLocationSettingsIgnored(boolean);
- method @NonNull public android.location.LocationRequest setLowPowerMode(boolean);
- method @NonNull public android.location.LocationRequest setNumUpdates(int);
- method @NonNull public android.location.LocationRequest setProvider(@NonNull String);
- method @NonNull public android.location.LocationRequest setQuality(int);
- method @NonNull public android.location.LocationRequest setSmallestDisplacement(float);
- method public void setWorkSource(@Nullable android.os.WorkSource);
- method public void writeToParcel(android.os.Parcel, int);
+ method @Deprecated @NonNull public android.location.LocationRequest setExpireIn(long);
+ method @Deprecated @NonNull public android.location.LocationRequest setFastestInterval(long);
+ method @Deprecated public void setHideFromAppOps(boolean);
+ method @Deprecated @NonNull public android.location.LocationRequest setInterval(long);
+ method @Deprecated @NonNull @RequiresPermission(android.Manifest.permission.WRITE_SECURE_SETTINGS) public android.location.LocationRequest setLocationSettingsIgnored(boolean);
+ method @Deprecated @NonNull public android.location.LocationRequest setLowPowerMode(boolean);
+ method @Deprecated @NonNull public android.location.LocationRequest setNumUpdates(int);
+ method @Deprecated @NonNull public android.location.LocationRequest setProvider(@NonNull String);
+ method @Deprecated @NonNull public android.location.LocationRequest setQuality(int);
+ method @Deprecated @NonNull public android.location.LocationRequest setSmallestDisplacement(float);
+ method @Deprecated public void setWorkSource(@Nullable android.os.WorkSource);
field public static final int ACCURACY_BLOCK = 102; // 0x66
field public static final int ACCURACY_CITY = 104; // 0x68
field public static final int ACCURACY_FINE = 100; // 0x64
- field @NonNull public static final android.os.Parcelable.Creator<android.location.LocationRequest> CREATOR;
field public static final int POWER_HIGH = 203; // 0xcb
field public static final int POWER_LOW = 201; // 0xc9
- field public static final int POWER_NONE = 200; // 0xc8
+ field @Deprecated public static final int POWER_NONE = 200; // 0xc8
+ }
+
+ public static final class LocationRequest.Builder {
+ method @NonNull @RequiresPermission(android.Manifest.permission.UPDATE_APP_OPS_STATS) public android.location.LocationRequest.Builder setHiddenFromAppOps(boolean);
+ method @NonNull @RequiresPermission(android.Manifest.permission.WRITE_SECURE_SETTINGS) public android.location.LocationRequest.Builder setLocationSettingsIgnored(boolean);
+ method @NonNull @RequiresPermission(android.Manifest.permission.LOCATION_HARDWARE) public android.location.LocationRequest.Builder setLowPower(boolean);
+ method @NonNull public android.location.LocationRequest.Builder setQuality(int);
+ method @NonNull @RequiresPermission(android.Manifest.permission.UPDATE_DEVICE_STATS) public android.location.LocationRequest.Builder setWorkSource(@Nullable android.os.WorkSource);
}
}
diff --git a/packages/FusedLocation/src/com/android/location/fused/FusedLocationProvider.java b/packages/FusedLocation/src/com/android/location/fused/FusedLocationProvider.java
index 781efc118429..900e68d36c32 100644
--- a/packages/FusedLocation/src/com/android/location/fused/FusedLocationProvider.java
+++ b/packages/FusedLocation/src/com/android/location/fused/FusedLocationProvider.java
@@ -30,7 +30,6 @@ import android.location.Location;
import android.location.LocationListener;
import android.location.LocationManager;
import android.location.LocationRequest;
-import android.os.Looper;
import android.os.WorkSource;
import com.android.internal.annotations.GuardedBy;
@@ -182,6 +181,7 @@ public class FusedLocationProvider extends LocationProviderBase {
for (LocationRequestUnbundled request : mRequest.getLocationRequests()) {
switch (request.getQuality()) {
case LocationRequestUnbundled.ACCURACY_FINE:
+ case LocationRequestUnbundled.ACCURACY_BLOCK:
case LocationRequestUnbundled.POWER_HIGH:
if (request.getInterval() < gpsInterval) {
gpsInterval = request.getInterval();
@@ -190,7 +190,6 @@ public class FusedLocationProvider extends LocationProviderBase {
networkInterval = request.getInterval();
}
break;
- case LocationRequestUnbundled.ACCURACY_BLOCK:
case LocationRequestUnbundled.ACCURACY_CITY:
case LocationRequestUnbundled.POWER_LOW:
if (request.getInterval() < networkInterval) {
@@ -219,13 +218,12 @@ public class FusedLocationProvider extends LocationProviderBase {
mLocationManager.removeUpdates(listener);
}
if (newInterval != Long.MAX_VALUE) {
- LocationRequest request = LocationRequest.createFromDeprecatedProvider(
- provider, newInterval, 0, false);
- if (mRequest.isLocationSettingsIgnored()) {
- request.setLocationSettingsIgnored(true);
- }
- request.setWorkSource(mWorkSource);
- mLocationManager.requestLocationUpdates(request, listener, Looper.getMainLooper());
+ LocationRequest request = new LocationRequest.Builder(newInterval)
+ .setLocationSettingsIgnored(mRequest.isLocationSettingsIgnored())
+ .setWorkSource(mWorkSource)
+ .build();
+ mLocationManager.requestLocationUpdates(provider, request, mContext.getMainExecutor(),
+ listener);
}
}
diff --git a/packages/FusedLocation/test/src/com/android/location/fused/tests/FusedLocationServiceTest.java b/packages/FusedLocation/test/src/com/android/location/fused/tests/FusedLocationServiceTest.java
index 2c4545e7b265..687dd13f8732 100644
--- a/packages/FusedLocation/test/src/com/android/location/fused/tests/FusedLocationServiceTest.java
+++ b/packages/FusedLocation/test/src/com/android/location/fused/tests/FusedLocationServiceTest.java
@@ -16,7 +16,6 @@
package com.android.location.fused.tests;
-import static android.location.LocationManager.FUSED_PROVIDER;
import static android.location.LocationManager.GPS_PROVIDER;
import static android.location.LocationManager.NETWORK_PROVIDER;
@@ -121,8 +120,7 @@ public class FusedLocationServiceTest {
@Test
public void testNetworkRequest() throws Exception {
- LocationRequest request = LocationRequest.createFromDeprecatedProvider(FUSED_PROVIDER, 1000,
- 0, false);
+ LocationRequest request = new LocationRequest.Builder(1000).build();
mProvider.setRequest(
new ProviderRequest.Builder()
@@ -139,8 +137,9 @@ public class FusedLocationServiceTest {
@Test
public void testGpsRequest() throws Exception {
- LocationRequest request = LocationRequest.createFromDeprecatedProvider(FUSED_PROVIDER, 1000,
- 0, false).setQuality(LocationRequest.POWER_HIGH);
+ LocationRequest request = new LocationRequest.Builder(1000)
+ .setQuality(LocationRequest.POWER_HIGH)
+ .build();
mProvider.setRequest(
new ProviderRequest.Builder()
diff --git a/packages/InputDevices/res/values-af/strings.xml b/packages/InputDevices/res/values-af/strings.xml
index 22436052b6e6..f3e11fb923fe 100644
--- a/packages/InputDevices/res/values-af/strings.xml
+++ b/packages/InputDevices/res/values-af/strings.xml
@@ -26,6 +26,8 @@
<string name="keyboard_layout_finnish" msgid="5585659438924315466">"Fins"</string>
<string name="keyboard_layout_croatian" msgid="4172229471079281138">"Kroaties"</string>
<string name="keyboard_layout_czech" msgid="1349256901452975343">"Tsjeggies"</string>
+ <!-- no translation found for keyboard_layout_czech_qwerty (3331402534128515501) -->
+ <skip />
<string name="keyboard_layout_estonian" msgid="8775830985185665274">"Estnies"</string>
<string name="keyboard_layout_hungarian" msgid="4154963661406035109">"Hongaars"</string>
<string name="keyboard_layout_icelandic" msgid="5836645650912489642">"Yslands"</string>
diff --git a/packages/InputDevices/res/values-am/strings.xml b/packages/InputDevices/res/values-am/strings.xml
index 3257e9852a7a..1729f2903f48 100644
--- a/packages/InputDevices/res/values-am/strings.xml
+++ b/packages/InputDevices/res/values-am/strings.xml
@@ -26,6 +26,8 @@
<string name="keyboard_layout_finnish" msgid="5585659438924315466">"ፊኒሽ"</string>
<string name="keyboard_layout_croatian" msgid="4172229471079281138">"ክሮሽያ"</string>
<string name="keyboard_layout_czech" msgid="1349256901452975343">"ቼክ"</string>
+ <!-- no translation found for keyboard_layout_czech_qwerty (3331402534128515501) -->
+ <skip />
<string name="keyboard_layout_estonian" msgid="8775830985185665274">"ኤስቶኒያ"</string>
<string name="keyboard_layout_hungarian" msgid="4154963661406035109">"ሀንጋሪ"</string>
<string name="keyboard_layout_icelandic" msgid="5836645650912489642">"አይስላንድ"</string>
diff --git a/packages/InputDevices/res/values-ar/strings.xml b/packages/InputDevices/res/values-ar/strings.xml
index dc1c89fce99b..12751dbceb5b 100644
--- a/packages/InputDevices/res/values-ar/strings.xml
+++ b/packages/InputDevices/res/values-ar/strings.xml
@@ -26,6 +26,8 @@
<string name="keyboard_layout_finnish" msgid="5585659438924315466">"الفنلندية"</string>
<string name="keyboard_layout_croatian" msgid="4172229471079281138">"الكرواتية"</string>
<string name="keyboard_layout_czech" msgid="1349256901452975343">"التشيكية"</string>
+ <!-- no translation found for keyboard_layout_czech_qwerty (3331402534128515501) -->
+ <skip />
<string name="keyboard_layout_estonian" msgid="8775830985185665274">"الإستونية"</string>
<string name="keyboard_layout_hungarian" msgid="4154963661406035109">"المجرية"</string>
<string name="keyboard_layout_icelandic" msgid="5836645650912489642">"الأيسلندية"</string>
diff --git a/packages/InputDevices/res/values-as/strings.xml b/packages/InputDevices/res/values-as/strings.xml
index c572df90417e..a2df66cb1995 100644
--- a/packages/InputDevices/res/values-as/strings.xml
+++ b/packages/InputDevices/res/values-as/strings.xml
@@ -26,6 +26,8 @@
<string name="keyboard_layout_finnish" msgid="5585659438924315466">"ফিনিশ্ব"</string>
<string name="keyboard_layout_croatian" msgid="4172229471079281138">"ক্ৰ\'ৱেশ্বিয়ান"</string>
<string name="keyboard_layout_czech" msgid="1349256901452975343">"চ্চেক"</string>
+ <!-- no translation found for keyboard_layout_czech_qwerty (3331402534128515501) -->
+ <skip />
<string name="keyboard_layout_estonian" msgid="8775830985185665274">"ইষ্ট\'নিয়া"</string>
<string name="keyboard_layout_hungarian" msgid="4154963661406035109">"হাংগেৰিয়ান"</string>
<string name="keyboard_layout_icelandic" msgid="5836645650912489642">"আইচলেণ্ডিক"</string>
diff --git a/packages/InputDevices/res/values-az/strings.xml b/packages/InputDevices/res/values-az/strings.xml
index 51ca6fbe100d..1d9eb0687c7d 100644
--- a/packages/InputDevices/res/values-az/strings.xml
+++ b/packages/InputDevices/res/values-az/strings.xml
@@ -26,6 +26,8 @@
<string name="keyboard_layout_finnish" msgid="5585659438924315466">"Fin"</string>
<string name="keyboard_layout_croatian" msgid="4172229471079281138">"Xorvat"</string>
<string name="keyboard_layout_czech" msgid="1349256901452975343">"Çex"</string>
+ <!-- no translation found for keyboard_layout_czech_qwerty (3331402534128515501) -->
+ <skip />
<string name="keyboard_layout_estonian" msgid="8775830985185665274">"Eston"</string>
<string name="keyboard_layout_hungarian" msgid="4154963661406035109">"Macar"</string>
<string name="keyboard_layout_icelandic" msgid="5836645650912489642">"İslandiyalı"</string>
diff --git a/packages/InputDevices/res/values-b+sr+Latn/strings.xml b/packages/InputDevices/res/values-b+sr+Latn/strings.xml
index aa071f338404..7952c22caa67 100644
--- a/packages/InputDevices/res/values-b+sr+Latn/strings.xml
+++ b/packages/InputDevices/res/values-b+sr+Latn/strings.xml
@@ -26,6 +26,8 @@
<string name="keyboard_layout_finnish" msgid="5585659438924315466">"finska"</string>
<string name="keyboard_layout_croatian" msgid="4172229471079281138">"hrvatska"</string>
<string name="keyboard_layout_czech" msgid="1349256901452975343">"češka"</string>
+ <!-- no translation found for keyboard_layout_czech_qwerty (3331402534128515501) -->
+ <skip />
<string name="keyboard_layout_estonian" msgid="8775830985185665274">"estonska"</string>
<string name="keyboard_layout_hungarian" msgid="4154963661406035109">"mađarska"</string>
<string name="keyboard_layout_icelandic" msgid="5836645650912489642">"islandska"</string>
diff --git a/packages/InputDevices/res/values-be/strings.xml b/packages/InputDevices/res/values-be/strings.xml
index 7acffe3f480f..4e2d5ba9216f 100644
--- a/packages/InputDevices/res/values-be/strings.xml
+++ b/packages/InputDevices/res/values-be/strings.xml
@@ -26,6 +26,8 @@
<string name="keyboard_layout_finnish" msgid="5585659438924315466">"Фінская"</string>
<string name="keyboard_layout_croatian" msgid="4172229471079281138">"Харвацкая"</string>
<string name="keyboard_layout_czech" msgid="1349256901452975343">"Чэшская"</string>
+ <!-- no translation found for keyboard_layout_czech_qwerty (3331402534128515501) -->
+ <skip />
<string name="keyboard_layout_estonian" msgid="8775830985185665274">"Эстонская"</string>
<string name="keyboard_layout_hungarian" msgid="4154963661406035109">"Венгерская"</string>
<string name="keyboard_layout_icelandic" msgid="5836645650912489642">"Ісландская"</string>
diff --git a/packages/InputDevices/res/values-bg/strings.xml b/packages/InputDevices/res/values-bg/strings.xml
index 9d4479164988..01feb95a127d 100644
--- a/packages/InputDevices/res/values-bg/strings.xml
+++ b/packages/InputDevices/res/values-bg/strings.xml
@@ -26,6 +26,8 @@
<string name="keyboard_layout_finnish" msgid="5585659438924315466">"финландски"</string>
<string name="keyboard_layout_croatian" msgid="4172229471079281138">"хърватски"</string>
<string name="keyboard_layout_czech" msgid="1349256901452975343">"чешки"</string>
+ <!-- no translation found for keyboard_layout_czech_qwerty (3331402534128515501) -->
+ <skip />
<string name="keyboard_layout_estonian" msgid="8775830985185665274">"естонски"</string>
<string name="keyboard_layout_hungarian" msgid="4154963661406035109">"унгарски"</string>
<string name="keyboard_layout_icelandic" msgid="5836645650912489642">"исландски"</string>
diff --git a/packages/InputDevices/res/values-bn/strings.xml b/packages/InputDevices/res/values-bn/strings.xml
index 20ddf15efbef..d3b47bc3c76b 100644
--- a/packages/InputDevices/res/values-bn/strings.xml
+++ b/packages/InputDevices/res/values-bn/strings.xml
@@ -26,6 +26,8 @@
<string name="keyboard_layout_finnish" msgid="5585659438924315466">"ফিনিশ"</string>
<string name="keyboard_layout_croatian" msgid="4172229471079281138">"ক্রোয়েশিয়"</string>
<string name="keyboard_layout_czech" msgid="1349256901452975343">"চেক"</string>
+ <!-- no translation found for keyboard_layout_czech_qwerty (3331402534128515501) -->
+ <skip />
<string name="keyboard_layout_estonian" msgid="8775830985185665274">"এস্তোনীয়"</string>
<string name="keyboard_layout_hungarian" msgid="4154963661406035109">"হাঙ্গেরিয়"</string>
<string name="keyboard_layout_icelandic" msgid="5836645650912489642">"আইসল্যান্ডিক"</string>
diff --git a/packages/InputDevices/res/values-bs/strings.xml b/packages/InputDevices/res/values-bs/strings.xml
index 6b26b3734b0f..893d45376796 100644
--- a/packages/InputDevices/res/values-bs/strings.xml
+++ b/packages/InputDevices/res/values-bs/strings.xml
@@ -26,6 +26,8 @@
<string name="keyboard_layout_finnish" msgid="5585659438924315466">"finski"</string>
<string name="keyboard_layout_croatian" msgid="4172229471079281138">"hrvatski"</string>
<string name="keyboard_layout_czech" msgid="1349256901452975343">"češki"</string>
+ <!-- no translation found for keyboard_layout_czech_qwerty (3331402534128515501) -->
+ <skip />
<string name="keyboard_layout_estonian" msgid="8775830985185665274">"estonski"</string>
<string name="keyboard_layout_hungarian" msgid="4154963661406035109">"mađarski"</string>
<string name="keyboard_layout_icelandic" msgid="5836645650912489642">"islandski"</string>
diff --git a/packages/InputDevices/res/values-ca/strings.xml b/packages/InputDevices/res/values-ca/strings.xml
index 9f53d35e0050..9da74e14e140 100644
--- a/packages/InputDevices/res/values-ca/strings.xml
+++ b/packages/InputDevices/res/values-ca/strings.xml
@@ -26,6 +26,8 @@
<string name="keyboard_layout_finnish" msgid="5585659438924315466">"Finès"</string>
<string name="keyboard_layout_croatian" msgid="4172229471079281138">"Croat"</string>
<string name="keyboard_layout_czech" msgid="1349256901452975343">"Txec"</string>
+ <!-- no translation found for keyboard_layout_czech_qwerty (3331402534128515501) -->
+ <skip />
<string name="keyboard_layout_estonian" msgid="8775830985185665274">"Estonià"</string>
<string name="keyboard_layout_hungarian" msgid="4154963661406035109">"Hongarès"</string>
<string name="keyboard_layout_icelandic" msgid="5836645650912489642">"Islandès"</string>
diff --git a/packages/InputDevices/res/values-cs/strings.xml b/packages/InputDevices/res/values-cs/strings.xml
index 1dbe4abf989a..041fcbbe8960 100644
--- a/packages/InputDevices/res/values-cs/strings.xml
+++ b/packages/InputDevices/res/values-cs/strings.xml
@@ -26,6 +26,8 @@
<string name="keyboard_layout_finnish" msgid="5585659438924315466">"finské"</string>
<string name="keyboard_layout_croatian" msgid="4172229471079281138">"chorvatské"</string>
<string name="keyboard_layout_czech" msgid="1349256901452975343">"české"</string>
+ <!-- no translation found for keyboard_layout_czech_qwerty (3331402534128515501) -->
+ <skip />
<string name="keyboard_layout_estonian" msgid="8775830985185665274">"estonské"</string>
<string name="keyboard_layout_hungarian" msgid="4154963661406035109">"maďarské"</string>
<string name="keyboard_layout_icelandic" msgid="5836645650912489642">"islandské"</string>
diff --git a/packages/InputDevices/res/values-da/strings.xml b/packages/InputDevices/res/values-da/strings.xml
index 4b2ba1f57824..bde1fd2c9d9e 100644
--- a/packages/InputDevices/res/values-da/strings.xml
+++ b/packages/InputDevices/res/values-da/strings.xml
@@ -26,6 +26,8 @@
<string name="keyboard_layout_finnish" msgid="5585659438924315466">"Finsk"</string>
<string name="keyboard_layout_croatian" msgid="4172229471079281138">"Kroatisk"</string>
<string name="keyboard_layout_czech" msgid="1349256901452975343">"Tjekkisk"</string>
+ <!-- no translation found for keyboard_layout_czech_qwerty (3331402534128515501) -->
+ <skip />
<string name="keyboard_layout_estonian" msgid="8775830985185665274">"Estisk"</string>
<string name="keyboard_layout_hungarian" msgid="4154963661406035109">"Ungarsk"</string>
<string name="keyboard_layout_icelandic" msgid="5836645650912489642">"Islandsk"</string>
diff --git a/packages/InputDevices/res/values-de/strings.xml b/packages/InputDevices/res/values-de/strings.xml
index 5d3f42c3235d..975308f4ffda 100644
--- a/packages/InputDevices/res/values-de/strings.xml
+++ b/packages/InputDevices/res/values-de/strings.xml
@@ -26,6 +26,8 @@
<string name="keyboard_layout_finnish" msgid="5585659438924315466">"Finnisch"</string>
<string name="keyboard_layout_croatian" msgid="4172229471079281138">"Kroatisch"</string>
<string name="keyboard_layout_czech" msgid="1349256901452975343">"Tschechisch"</string>
+ <!-- no translation found for keyboard_layout_czech_qwerty (3331402534128515501) -->
+ <skip />
<string name="keyboard_layout_estonian" msgid="8775830985185665274">"Estnisch"</string>
<string name="keyboard_layout_hungarian" msgid="4154963661406035109">"Ungarisch"</string>
<string name="keyboard_layout_icelandic" msgid="5836645650912489642">"Isländisch"</string>
diff --git a/packages/InputDevices/res/values-el/strings.xml b/packages/InputDevices/res/values-el/strings.xml
index b6366ea38317..52088f6199d0 100644
--- a/packages/InputDevices/res/values-el/strings.xml
+++ b/packages/InputDevices/res/values-el/strings.xml
@@ -26,6 +26,8 @@
<string name="keyboard_layout_finnish" msgid="5585659438924315466">"Φινλανδικά"</string>
<string name="keyboard_layout_croatian" msgid="4172229471079281138">"Κροατικά"</string>
<string name="keyboard_layout_czech" msgid="1349256901452975343">"Τσεχικά"</string>
+ <!-- no translation found for keyboard_layout_czech_qwerty (3331402534128515501) -->
+ <skip />
<string name="keyboard_layout_estonian" msgid="8775830985185665274">"Εσθονικά"</string>
<string name="keyboard_layout_hungarian" msgid="4154963661406035109">"Ουγγρικά"</string>
<string name="keyboard_layout_icelandic" msgid="5836645650912489642">"Ισλανδικά"</string>
diff --git a/packages/InputDevices/res/values-en-rAU/strings.xml b/packages/InputDevices/res/values-en-rAU/strings.xml
index 0b41ccc9bf33..17a1fb754cad 100644
--- a/packages/InputDevices/res/values-en-rAU/strings.xml
+++ b/packages/InputDevices/res/values-en-rAU/strings.xml
@@ -26,6 +26,8 @@
<string name="keyboard_layout_finnish" msgid="5585659438924315466">"Finnish"</string>
<string name="keyboard_layout_croatian" msgid="4172229471079281138">"Croatian"</string>
<string name="keyboard_layout_czech" msgid="1349256901452975343">"Czech"</string>
+ <!-- no translation found for keyboard_layout_czech_qwerty (3331402534128515501) -->
+ <skip />
<string name="keyboard_layout_estonian" msgid="8775830985185665274">"Estonian"</string>
<string name="keyboard_layout_hungarian" msgid="4154963661406035109">"Hungarian"</string>
<string name="keyboard_layout_icelandic" msgid="5836645650912489642">"Icelandic"</string>
diff --git a/packages/InputDevices/res/values-en-rCA/strings.xml b/packages/InputDevices/res/values-en-rCA/strings.xml
index 0b41ccc9bf33..17a1fb754cad 100644
--- a/packages/InputDevices/res/values-en-rCA/strings.xml
+++ b/packages/InputDevices/res/values-en-rCA/strings.xml
@@ -26,6 +26,8 @@
<string name="keyboard_layout_finnish" msgid="5585659438924315466">"Finnish"</string>
<string name="keyboard_layout_croatian" msgid="4172229471079281138">"Croatian"</string>
<string name="keyboard_layout_czech" msgid="1349256901452975343">"Czech"</string>
+ <!-- no translation found for keyboard_layout_czech_qwerty (3331402534128515501) -->
+ <skip />
<string name="keyboard_layout_estonian" msgid="8775830985185665274">"Estonian"</string>
<string name="keyboard_layout_hungarian" msgid="4154963661406035109">"Hungarian"</string>
<string name="keyboard_layout_icelandic" msgid="5836645650912489642">"Icelandic"</string>
diff --git a/packages/InputDevices/res/values-en-rGB/strings.xml b/packages/InputDevices/res/values-en-rGB/strings.xml
index 0b41ccc9bf33..17a1fb754cad 100644
--- a/packages/InputDevices/res/values-en-rGB/strings.xml
+++ b/packages/InputDevices/res/values-en-rGB/strings.xml
@@ -26,6 +26,8 @@
<string name="keyboard_layout_finnish" msgid="5585659438924315466">"Finnish"</string>
<string name="keyboard_layout_croatian" msgid="4172229471079281138">"Croatian"</string>
<string name="keyboard_layout_czech" msgid="1349256901452975343">"Czech"</string>
+ <!-- no translation found for keyboard_layout_czech_qwerty (3331402534128515501) -->
+ <skip />
<string name="keyboard_layout_estonian" msgid="8775830985185665274">"Estonian"</string>
<string name="keyboard_layout_hungarian" msgid="4154963661406035109">"Hungarian"</string>
<string name="keyboard_layout_icelandic" msgid="5836645650912489642">"Icelandic"</string>
diff --git a/packages/InputDevices/res/values-en-rIN/strings.xml b/packages/InputDevices/res/values-en-rIN/strings.xml
index 0b41ccc9bf33..17a1fb754cad 100644
--- a/packages/InputDevices/res/values-en-rIN/strings.xml
+++ b/packages/InputDevices/res/values-en-rIN/strings.xml
@@ -26,6 +26,8 @@
<string name="keyboard_layout_finnish" msgid="5585659438924315466">"Finnish"</string>
<string name="keyboard_layout_croatian" msgid="4172229471079281138">"Croatian"</string>
<string name="keyboard_layout_czech" msgid="1349256901452975343">"Czech"</string>
+ <!-- no translation found for keyboard_layout_czech_qwerty (3331402534128515501) -->
+ <skip />
<string name="keyboard_layout_estonian" msgid="8775830985185665274">"Estonian"</string>
<string name="keyboard_layout_hungarian" msgid="4154963661406035109">"Hungarian"</string>
<string name="keyboard_layout_icelandic" msgid="5836645650912489642">"Icelandic"</string>
diff --git a/packages/InputDevices/res/values-en-rXC/strings.xml b/packages/InputDevices/res/values-en-rXC/strings.xml
index 85c2b2849199..8603c54c6b46 100644
--- a/packages/InputDevices/res/values-en-rXC/strings.xml
+++ b/packages/InputDevices/res/values-en-rXC/strings.xml
@@ -26,6 +26,8 @@
<string name="keyboard_layout_finnish" msgid="5585659438924315466">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‎‎‏‏‎‏‏‎‎‎‎‏‎‎‎‎‏‏‏‏‏‏‏‎‏‎‏‎‏‎‎‏‏‎‎‏‎‏‎‏‏‎‎‏‎‎‎‎‏‏‏‎‏‏‎‏‎‎‏‎‏‎‎Finnish‎‏‎‎‏‎"</string>
<string name="keyboard_layout_croatian" msgid="4172229471079281138">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‎‏‏‏‎‎‏‏‏‏‎‎‏‏‎‏‎‏‏‏‏‎‎‏‎‎‏‏‎‎‏‎‎‏‏‏‎‎‏‎‎‎‏‏‎‎‎‏‎‏‏‎‎‎‏‏‏‏‏‎‎‏‎‎Croatian‎‏‎‎‏‎"</string>
<string name="keyboard_layout_czech" msgid="1349256901452975343">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‎‏‏‎‎‏‎‏‎‏‏‏‎‎‏‏‎‎‎‎‏‏‎‎‎‎‎‎‎‎‎‏‏‎‏‎‎‎‏‏‏‎‏‏‎‎‏‎‏‎‎‏‏‎‎‏‏‏‎‏‏‏‏‎Czech‎‏‎‎‏‎"</string>
+ <!-- no translation found for keyboard_layout_czech_qwerty (3331402534128515501) -->
+ <skip />
<string name="keyboard_layout_estonian" msgid="8775830985185665274">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‏‏‏‎‎‏‏‏‎‎‏‎‏‎‎‎‎‎‎‎‏‏‏‏‎‎‏‎‎‎‏‏‏‎‎‎‎‎‏‏‎‏‏‎‏‏‏‎‏‎‎‎‎‎‏‏‏‏‏‎‏‎‎Estonian‎‏‎‎‏‎"</string>
<string name="keyboard_layout_hungarian" msgid="4154963661406035109">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‎‏‏‏‎‎‏‏‎‏‎‏‎‎‏‎‏‏‎‎‏‎‏‎‏‏‎‏‏‏‏‏‎‏‎‎‏‎‎‏‏‎‎‎‎‏‏‎‏‎‏‏‏‎‎‏‎‏‎‎‏‎‏‎Hungarian‎‏‎‎‏‎"</string>
<string name="keyboard_layout_icelandic" msgid="5836645650912489642">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‎‏‎‎‎‎‏‏‏‏‏‏‏‏‏‏‏‎‏‏‏‎‎‏‎‎‏‎‏‏‏‎‏‎‏‏‏‎‎‏‏‏‎‏‏‏‏‎‏‏‎‎‎‎‏‎‏‎‏‎‏‎‎Icelandic‎‏‎‎‏‎"</string>
diff --git a/packages/InputDevices/res/values-es-rUS/strings.xml b/packages/InputDevices/res/values-es-rUS/strings.xml
index 11b9a4662bf1..fc5e3d88228b 100644
--- a/packages/InputDevices/res/values-es-rUS/strings.xml
+++ b/packages/InputDevices/res/values-es-rUS/strings.xml
@@ -26,6 +26,8 @@
<string name="keyboard_layout_finnish" msgid="5585659438924315466">"Finlandés"</string>
<string name="keyboard_layout_croatian" msgid="4172229471079281138">"Croata"</string>
<string name="keyboard_layout_czech" msgid="1349256901452975343">"Checo"</string>
+ <!-- no translation found for keyboard_layout_czech_qwerty (3331402534128515501) -->
+ <skip />
<string name="keyboard_layout_estonian" msgid="8775830985185665274">"Estonio"</string>
<string name="keyboard_layout_hungarian" msgid="4154963661406035109">"Húngaro"</string>
<string name="keyboard_layout_icelandic" msgid="5836645650912489642">"Islandés"</string>
diff --git a/packages/InputDevices/res/values-es/strings.xml b/packages/InputDevices/res/values-es/strings.xml
index 096526746844..773cdf9a4459 100644
--- a/packages/InputDevices/res/values-es/strings.xml
+++ b/packages/InputDevices/res/values-es/strings.xml
@@ -26,6 +26,8 @@
<string name="keyboard_layout_finnish" msgid="5585659438924315466">"Finlandés"</string>
<string name="keyboard_layout_croatian" msgid="4172229471079281138">"Croata"</string>
<string name="keyboard_layout_czech" msgid="1349256901452975343">"Checo"</string>
+ <!-- no translation found for keyboard_layout_czech_qwerty (3331402534128515501) -->
+ <skip />
<string name="keyboard_layout_estonian" msgid="8775830985185665274">"Estonio"</string>
<string name="keyboard_layout_hungarian" msgid="4154963661406035109">"Húngaro"</string>
<string name="keyboard_layout_icelandic" msgid="5836645650912489642">"Islandés"</string>
diff --git a/packages/InputDevices/res/values-et/strings.xml b/packages/InputDevices/res/values-et/strings.xml
index d84be12c05a9..dbe5865aeadb 100644
--- a/packages/InputDevices/res/values-et/strings.xml
+++ b/packages/InputDevices/res/values-et/strings.xml
@@ -26,6 +26,8 @@
<string name="keyboard_layout_finnish" msgid="5585659438924315466">"Soome"</string>
<string name="keyboard_layout_croatian" msgid="4172229471079281138">"Horvaatia"</string>
<string name="keyboard_layout_czech" msgid="1349256901452975343">"Tšehhi"</string>
+ <!-- no translation found for keyboard_layout_czech_qwerty (3331402534128515501) -->
+ <skip />
<string name="keyboard_layout_estonian" msgid="8775830985185665274">"Eesti"</string>
<string name="keyboard_layout_hungarian" msgid="4154963661406035109">"Ungari"</string>
<string name="keyboard_layout_icelandic" msgid="5836645650912489642">"Islandi"</string>
diff --git a/packages/InputDevices/res/values-eu/strings.xml b/packages/InputDevices/res/values-eu/strings.xml
index c4252491d287..e89ffa8b6c68 100644
--- a/packages/InputDevices/res/values-eu/strings.xml
+++ b/packages/InputDevices/res/values-eu/strings.xml
@@ -26,6 +26,8 @@
<string name="keyboard_layout_finnish" msgid="5585659438924315466">"Finlandiarra"</string>
<string name="keyboard_layout_croatian" msgid="4172229471079281138">"Kroaziarra"</string>
<string name="keyboard_layout_czech" msgid="1349256901452975343">"Txekiarra"</string>
+ <!-- no translation found for keyboard_layout_czech_qwerty (3331402534128515501) -->
+ <skip />
<string name="keyboard_layout_estonian" msgid="8775830985185665274">"Estoniarra"</string>
<string name="keyboard_layout_hungarian" msgid="4154963661406035109">"Hungariarra"</string>
<string name="keyboard_layout_icelandic" msgid="5836645650912489642">"Islandiarra"</string>
diff --git a/packages/InputDevices/res/values-fa/strings.xml b/packages/InputDevices/res/values-fa/strings.xml
index 153c3c5ad85c..2d5f81d06d21 100644
--- a/packages/InputDevices/res/values-fa/strings.xml
+++ b/packages/InputDevices/res/values-fa/strings.xml
@@ -26,6 +26,8 @@
<string name="keyboard_layout_finnish" msgid="5585659438924315466">"فنلاندی"</string>
<string name="keyboard_layout_croatian" msgid="4172229471079281138">"کرواسی"</string>
<string name="keyboard_layout_czech" msgid="1349256901452975343">"چک"</string>
+ <!-- no translation found for keyboard_layout_czech_qwerty (3331402534128515501) -->
+ <skip />
<string name="keyboard_layout_estonian" msgid="8775830985185665274">"استونیایی"</string>
<string name="keyboard_layout_hungarian" msgid="4154963661406035109">"مجارستانی"</string>
<string name="keyboard_layout_icelandic" msgid="5836645650912489642">"ایسلندی"</string>
diff --git a/packages/InputDevices/res/values-fi/strings.xml b/packages/InputDevices/res/values-fi/strings.xml
index dddb23dc1163..d4b0580dac69 100644
--- a/packages/InputDevices/res/values-fi/strings.xml
+++ b/packages/InputDevices/res/values-fi/strings.xml
@@ -26,6 +26,8 @@
<string name="keyboard_layout_finnish" msgid="5585659438924315466">"suomi"</string>
<string name="keyboard_layout_croatian" msgid="4172229471079281138">"kroaatti"</string>
<string name="keyboard_layout_czech" msgid="1349256901452975343">"tšekki"</string>
+ <!-- no translation found for keyboard_layout_czech_qwerty (3331402534128515501) -->
+ <skip />
<string name="keyboard_layout_estonian" msgid="8775830985185665274">"viro"</string>
<string name="keyboard_layout_hungarian" msgid="4154963661406035109">"unkari"</string>
<string name="keyboard_layout_icelandic" msgid="5836645650912489642">"islanti"</string>
diff --git a/packages/InputDevices/res/values-fr-rCA/strings.xml b/packages/InputDevices/res/values-fr-rCA/strings.xml
index 40b9280bc4db..beb0e07bc751 100644
--- a/packages/InputDevices/res/values-fr-rCA/strings.xml
+++ b/packages/InputDevices/res/values-fr-rCA/strings.xml
@@ -26,6 +26,8 @@
<string name="keyboard_layout_finnish" msgid="5585659438924315466">"Finnois"</string>
<string name="keyboard_layout_croatian" msgid="4172229471079281138">"Croate"</string>
<string name="keyboard_layout_czech" msgid="1349256901452975343">"Tchèque"</string>
+ <!-- no translation found for keyboard_layout_czech_qwerty (3331402534128515501) -->
+ <skip />
<string name="keyboard_layout_estonian" msgid="8775830985185665274">"Estonien"</string>
<string name="keyboard_layout_hungarian" msgid="4154963661406035109">"Hongrois"</string>
<string name="keyboard_layout_icelandic" msgid="5836645650912489642">"Islandais"</string>
diff --git a/packages/InputDevices/res/values-fr/strings.xml b/packages/InputDevices/res/values-fr/strings.xml
index be7489fadd4e..223ed3c78a9e 100644
--- a/packages/InputDevices/res/values-fr/strings.xml
+++ b/packages/InputDevices/res/values-fr/strings.xml
@@ -26,6 +26,8 @@
<string name="keyboard_layout_finnish" msgid="5585659438924315466">"Finnois"</string>
<string name="keyboard_layout_croatian" msgid="4172229471079281138">"Croate"</string>
<string name="keyboard_layout_czech" msgid="1349256901452975343">"Tchèque"</string>
+ <!-- no translation found for keyboard_layout_czech_qwerty (3331402534128515501) -->
+ <skip />
<string name="keyboard_layout_estonian" msgid="8775830985185665274">"Estonien"</string>
<string name="keyboard_layout_hungarian" msgid="4154963661406035109">"Hongrois"</string>
<string name="keyboard_layout_icelandic" msgid="5836645650912489642">"Islandais"</string>
diff --git a/packages/InputDevices/res/values-gl/strings.xml b/packages/InputDevices/res/values-gl/strings.xml
index e03946546051..7d3e1d6fb903 100644
--- a/packages/InputDevices/res/values-gl/strings.xml
+++ b/packages/InputDevices/res/values-gl/strings.xml
@@ -26,6 +26,8 @@
<string name="keyboard_layout_finnish" msgid="5585659438924315466">"Finés"</string>
<string name="keyboard_layout_croatian" msgid="4172229471079281138">"Croata"</string>
<string name="keyboard_layout_czech" msgid="1349256901452975343">"Checo"</string>
+ <!-- no translation found for keyboard_layout_czech_qwerty (3331402534128515501) -->
+ <skip />
<string name="keyboard_layout_estonian" msgid="8775830985185665274">"Estoniano"</string>
<string name="keyboard_layout_hungarian" msgid="4154963661406035109">"Húngaro"</string>
<string name="keyboard_layout_icelandic" msgid="5836645650912489642">"Islandés"</string>
diff --git a/packages/InputDevices/res/values-gu/strings.xml b/packages/InputDevices/res/values-gu/strings.xml
index f60eaf39155f..0f7863a11aaa 100644
--- a/packages/InputDevices/res/values-gu/strings.xml
+++ b/packages/InputDevices/res/values-gu/strings.xml
@@ -26,6 +26,8 @@
<string name="keyboard_layout_finnish" msgid="5585659438924315466">"ફિનિશ"</string>
<string name="keyboard_layout_croatian" msgid="4172229471079281138">"ક્રોએશિયન"</string>
<string name="keyboard_layout_czech" msgid="1349256901452975343">"ચેક"</string>
+ <!-- no translation found for keyboard_layout_czech_qwerty (3331402534128515501) -->
+ <skip />
<string name="keyboard_layout_estonian" msgid="8775830985185665274">"એસ્ટોનિયન"</string>
<string name="keyboard_layout_hungarian" msgid="4154963661406035109">"હંગેરિયન"</string>
<string name="keyboard_layout_icelandic" msgid="5836645650912489642">"આઇસલેન્ડિક"</string>
diff --git a/packages/InputDevices/res/values-hi/strings.xml b/packages/InputDevices/res/values-hi/strings.xml
index d7fce5288e62..37a5e582b34c 100644
--- a/packages/InputDevices/res/values-hi/strings.xml
+++ b/packages/InputDevices/res/values-hi/strings.xml
@@ -26,6 +26,8 @@
<string name="keyboard_layout_finnish" msgid="5585659438924315466">"फ़िनिश"</string>
<string name="keyboard_layout_croatian" msgid="4172229471079281138">"क्रोएशियन"</string>
<string name="keyboard_layout_czech" msgid="1349256901452975343">"चेक"</string>
+ <!-- no translation found for keyboard_layout_czech_qwerty (3331402534128515501) -->
+ <skip />
<string name="keyboard_layout_estonian" msgid="8775830985185665274">"एस्टोनियाई"</string>
<string name="keyboard_layout_hungarian" msgid="4154963661406035109">"हंगेरियाई"</string>
<string name="keyboard_layout_icelandic" msgid="5836645650912489642">"आइसलैंडिक"</string>
diff --git a/packages/InputDevices/res/values-hr/strings.xml b/packages/InputDevices/res/values-hr/strings.xml
index c155dd368487..83c2fc1f6b7b 100644
--- a/packages/InputDevices/res/values-hr/strings.xml
+++ b/packages/InputDevices/res/values-hr/strings.xml
@@ -26,6 +26,8 @@
<string name="keyboard_layout_finnish" msgid="5585659438924315466">"finska"</string>
<string name="keyboard_layout_croatian" msgid="4172229471079281138">"hrvatska"</string>
<string name="keyboard_layout_czech" msgid="1349256901452975343">"češka"</string>
+ <!-- no translation found for keyboard_layout_czech_qwerty (3331402534128515501) -->
+ <skip />
<string name="keyboard_layout_estonian" msgid="8775830985185665274">"estonska"</string>
<string name="keyboard_layout_hungarian" msgid="4154963661406035109">"mađarska"</string>
<string name="keyboard_layout_icelandic" msgid="5836645650912489642">"islandska"</string>
diff --git a/packages/InputDevices/res/values-hu/strings.xml b/packages/InputDevices/res/values-hu/strings.xml
index 998a68c14cf8..cd11cb423e8d 100644
--- a/packages/InputDevices/res/values-hu/strings.xml
+++ b/packages/InputDevices/res/values-hu/strings.xml
@@ -26,6 +26,8 @@
<string name="keyboard_layout_finnish" msgid="5585659438924315466">"finn"</string>
<string name="keyboard_layout_croatian" msgid="4172229471079281138">"horvát"</string>
<string name="keyboard_layout_czech" msgid="1349256901452975343">"cseh"</string>
+ <!-- no translation found for keyboard_layout_czech_qwerty (3331402534128515501) -->
+ <skip />
<string name="keyboard_layout_estonian" msgid="8775830985185665274">"észt"</string>
<string name="keyboard_layout_hungarian" msgid="4154963661406035109">"magyar"</string>
<string name="keyboard_layout_icelandic" msgid="5836645650912489642">"izlandi"</string>
diff --git a/packages/InputDevices/res/values-hy/strings.xml b/packages/InputDevices/res/values-hy/strings.xml
index 0672387a42a0..4528377695c6 100644
--- a/packages/InputDevices/res/values-hy/strings.xml
+++ b/packages/InputDevices/res/values-hy/strings.xml
@@ -26,6 +26,8 @@
<string name="keyboard_layout_finnish" msgid="5585659438924315466">"Ֆիններեն"</string>
<string name="keyboard_layout_croatian" msgid="4172229471079281138">"Խորվաթերեն"</string>
<string name="keyboard_layout_czech" msgid="1349256901452975343">"Չեխերեն"</string>
+ <!-- no translation found for keyboard_layout_czech_qwerty (3331402534128515501) -->
+ <skip />
<string name="keyboard_layout_estonian" msgid="8775830985185665274">"Էստոներեն"</string>
<string name="keyboard_layout_hungarian" msgid="4154963661406035109">"Հունգարերեն"</string>
<string name="keyboard_layout_icelandic" msgid="5836645650912489642">"Իսլանդերեն"</string>
diff --git a/packages/InputDevices/res/values-in/strings.xml b/packages/InputDevices/res/values-in/strings.xml
index 9b09bdeb6622..cd14c31cd89d 100644
--- a/packages/InputDevices/res/values-in/strings.xml
+++ b/packages/InputDevices/res/values-in/strings.xml
@@ -26,6 +26,8 @@
<string name="keyboard_layout_finnish" msgid="5585659438924315466">"Finlandia"</string>
<string name="keyboard_layout_croatian" msgid="4172229471079281138">"Kroasia"</string>
<string name="keyboard_layout_czech" msgid="1349256901452975343">"Ceko"</string>
+ <!-- no translation found for keyboard_layout_czech_qwerty (3331402534128515501) -->
+ <skip />
<string name="keyboard_layout_estonian" msgid="8775830985185665274">"Estonia"</string>
<string name="keyboard_layout_hungarian" msgid="4154963661406035109">"Hungaria"</string>
<string name="keyboard_layout_icelandic" msgid="5836645650912489642">"Islandia"</string>
diff --git a/packages/InputDevices/res/values-is/strings.xml b/packages/InputDevices/res/values-is/strings.xml
index a23e41bf6a83..deb1f1c84e88 100644
--- a/packages/InputDevices/res/values-is/strings.xml
+++ b/packages/InputDevices/res/values-is/strings.xml
@@ -26,6 +26,8 @@
<string name="keyboard_layout_finnish" msgid="5585659438924315466">"Finnskt"</string>
<string name="keyboard_layout_croatian" msgid="4172229471079281138">"Króatískt"</string>
<string name="keyboard_layout_czech" msgid="1349256901452975343">"Tékkneskt"</string>
+ <!-- no translation found for keyboard_layout_czech_qwerty (3331402534128515501) -->
+ <skip />
<string name="keyboard_layout_estonian" msgid="8775830985185665274">"Eistneskt"</string>
<string name="keyboard_layout_hungarian" msgid="4154963661406035109">"Ungverskt"</string>
<string name="keyboard_layout_icelandic" msgid="5836645650912489642">"Íslenskt"</string>
diff --git a/packages/InputDevices/res/values-it/strings.xml b/packages/InputDevices/res/values-it/strings.xml
index 49baaf93b429..6c4adb816264 100644
--- a/packages/InputDevices/res/values-it/strings.xml
+++ b/packages/InputDevices/res/values-it/strings.xml
@@ -26,6 +26,8 @@
<string name="keyboard_layout_finnish" msgid="5585659438924315466">"Finlandese"</string>
<string name="keyboard_layout_croatian" msgid="4172229471079281138">"Croato"</string>
<string name="keyboard_layout_czech" msgid="1349256901452975343">"Ceco"</string>
+ <!-- no translation found for keyboard_layout_czech_qwerty (3331402534128515501) -->
+ <skip />
<string name="keyboard_layout_estonian" msgid="8775830985185665274">"Estone"</string>
<string name="keyboard_layout_hungarian" msgid="4154963661406035109">"Ungherese"</string>
<string name="keyboard_layout_icelandic" msgid="5836645650912489642">"Islandese"</string>
diff --git a/packages/InputDevices/res/values-iw/strings.xml b/packages/InputDevices/res/values-iw/strings.xml
index 8eae0375b5f6..3e9ffa8c1b44 100644
--- a/packages/InputDevices/res/values-iw/strings.xml
+++ b/packages/InputDevices/res/values-iw/strings.xml
@@ -26,6 +26,8 @@
<string name="keyboard_layout_finnish" msgid="5585659438924315466">"פינית"</string>
<string name="keyboard_layout_croatian" msgid="4172229471079281138">"קרואטית"</string>
<string name="keyboard_layout_czech" msgid="1349256901452975343">"צ\'כית"</string>
+ <!-- no translation found for keyboard_layout_czech_qwerty (3331402534128515501) -->
+ <skip />
<string name="keyboard_layout_estonian" msgid="8775830985185665274">"אסטונית"</string>
<string name="keyboard_layout_hungarian" msgid="4154963661406035109">"הונגרית"</string>
<string name="keyboard_layout_icelandic" msgid="5836645650912489642">"איסלנדית"</string>
diff --git a/packages/InputDevices/res/values-ja/strings.xml b/packages/InputDevices/res/values-ja/strings.xml
index 31ae22732fde..e60b50cfa964 100644
--- a/packages/InputDevices/res/values-ja/strings.xml
+++ b/packages/InputDevices/res/values-ja/strings.xml
@@ -26,6 +26,8 @@
<string name="keyboard_layout_finnish" msgid="5585659438924315466">"フィンランド語"</string>
<string name="keyboard_layout_croatian" msgid="4172229471079281138">"クロアチア語"</string>
<string name="keyboard_layout_czech" msgid="1349256901452975343">"チェコ語"</string>
+ <!-- no translation found for keyboard_layout_czech_qwerty (3331402534128515501) -->
+ <skip />
<string name="keyboard_layout_estonian" msgid="8775830985185665274">"エストニア語"</string>
<string name="keyboard_layout_hungarian" msgid="4154963661406035109">"ハンガリー語"</string>
<string name="keyboard_layout_icelandic" msgid="5836645650912489642">"アイスランド語"</string>
diff --git a/packages/InputDevices/res/values-ka/strings.xml b/packages/InputDevices/res/values-ka/strings.xml
index 328432922501..3e02764c5593 100644
--- a/packages/InputDevices/res/values-ka/strings.xml
+++ b/packages/InputDevices/res/values-ka/strings.xml
@@ -26,6 +26,8 @@
<string name="keyboard_layout_finnish" msgid="5585659438924315466">"ფინური"</string>
<string name="keyboard_layout_croatian" msgid="4172229471079281138">"ხორვატიული"</string>
<string name="keyboard_layout_czech" msgid="1349256901452975343">"ჩეხური"</string>
+ <!-- no translation found for keyboard_layout_czech_qwerty (3331402534128515501) -->
+ <skip />
<string name="keyboard_layout_estonian" msgid="8775830985185665274">"ესტონური"</string>
<string name="keyboard_layout_hungarian" msgid="4154963661406035109">"უნგრული"</string>
<string name="keyboard_layout_icelandic" msgid="5836645650912489642">"ისლანდიური"</string>
diff --git a/packages/InputDevices/res/values-kk/strings.xml b/packages/InputDevices/res/values-kk/strings.xml
index 634eaf9d675c..e4ad73e2efd4 100644
--- a/packages/InputDevices/res/values-kk/strings.xml
+++ b/packages/InputDevices/res/values-kk/strings.xml
@@ -26,6 +26,8 @@
<string name="keyboard_layout_finnish" msgid="5585659438924315466">"Фин"</string>
<string name="keyboard_layout_croatian" msgid="4172229471079281138">"Хорват"</string>
<string name="keyboard_layout_czech" msgid="1349256901452975343">"Чех"</string>
+ <!-- no translation found for keyboard_layout_czech_qwerty (3331402534128515501) -->
+ <skip />
<string name="keyboard_layout_estonian" msgid="8775830985185665274">"Эстон"</string>
<string name="keyboard_layout_hungarian" msgid="4154963661406035109">"Мадияр"</string>
<string name="keyboard_layout_icelandic" msgid="5836645650912489642">"Исланд"</string>
diff --git a/packages/InputDevices/res/values-km/strings.xml b/packages/InputDevices/res/values-km/strings.xml
index a4946ab80f98..8be590e3cd89 100644
--- a/packages/InputDevices/res/values-km/strings.xml
+++ b/packages/InputDevices/res/values-km/strings.xml
@@ -26,6 +26,8 @@
<string name="keyboard_layout_finnish" msgid="5585659438924315466">"ហ្វាំងឡង់"</string>
<string name="keyboard_layout_croatian" msgid="4172229471079281138">"ក្រូអាត"</string>
<string name="keyboard_layout_czech" msgid="1349256901452975343">"ឆេក"</string>
+ <!-- no translation found for keyboard_layout_czech_qwerty (3331402534128515501) -->
+ <skip />
<string name="keyboard_layout_estonian" msgid="8775830985185665274">"អេស្តូនី"</string>
<string name="keyboard_layout_hungarian" msgid="4154963661406035109">"ហុងគ្រី"</string>
<string name="keyboard_layout_icelandic" msgid="5836645650912489642">"អ៊ីស្លង់"</string>
diff --git a/packages/InputDevices/res/values-kn/strings.xml b/packages/InputDevices/res/values-kn/strings.xml
index 073ce98892d7..846101c57c4a 100644
--- a/packages/InputDevices/res/values-kn/strings.xml
+++ b/packages/InputDevices/res/values-kn/strings.xml
@@ -26,6 +26,8 @@
<string name="keyboard_layout_finnish" msgid="5585659438924315466">"ಫಿನ್ನಿಷ್"</string>
<string name="keyboard_layout_croatian" msgid="4172229471079281138">"ಕ್ರೊಯೇಶಿಯನ್"</string>
<string name="keyboard_layout_czech" msgid="1349256901452975343">"ಜೆಕ್"</string>
+ <!-- no translation found for keyboard_layout_czech_qwerty (3331402534128515501) -->
+ <skip />
<string name="keyboard_layout_estonian" msgid="8775830985185665274">"ಎಸ್ಟೋನಿಯನ್"</string>
<string name="keyboard_layout_hungarian" msgid="4154963661406035109">"ಹಂಗೇರಿಯನ್"</string>
<string name="keyboard_layout_icelandic" msgid="5836645650912489642">"ಐಸ್‌ಲ್ಯಾಂಡಿಕ್"</string>
diff --git a/packages/InputDevices/res/values-ko/strings.xml b/packages/InputDevices/res/values-ko/strings.xml
index 97ed6a03be88..2677432970da 100644
--- a/packages/InputDevices/res/values-ko/strings.xml
+++ b/packages/InputDevices/res/values-ko/strings.xml
@@ -26,6 +26,8 @@
<string name="keyboard_layout_finnish" msgid="5585659438924315466">"핀란드어"</string>
<string name="keyboard_layout_croatian" msgid="4172229471079281138">"크로아티아어"</string>
<string name="keyboard_layout_czech" msgid="1349256901452975343">"체코어"</string>
+ <!-- no translation found for keyboard_layout_czech_qwerty (3331402534128515501) -->
+ <skip />
<string name="keyboard_layout_estonian" msgid="8775830985185665274">"에스토니아어"</string>
<string name="keyboard_layout_hungarian" msgid="4154963661406035109">"헝가리어"</string>
<string name="keyboard_layout_icelandic" msgid="5836645650912489642">"아이슬란드어"</string>
diff --git a/packages/InputDevices/res/values-ky/strings.xml b/packages/InputDevices/res/values-ky/strings.xml
index ab775ffce31e..15a504ea4f59 100644
--- a/packages/InputDevices/res/values-ky/strings.xml
+++ b/packages/InputDevices/res/values-ky/strings.xml
@@ -26,6 +26,8 @@
<string name="keyboard_layout_finnish" msgid="5585659438924315466">"Фин"</string>
<string name="keyboard_layout_croatian" msgid="4172229471079281138">"Хорват"</string>
<string name="keyboard_layout_czech" msgid="1349256901452975343">"Чех"</string>
+ <!-- no translation found for keyboard_layout_czech_qwerty (3331402534128515501) -->
+ <skip />
<string name="keyboard_layout_estonian" msgid="8775830985185665274">"Эстон"</string>
<string name="keyboard_layout_hungarian" msgid="4154963661406035109">"Венгр"</string>
<string name="keyboard_layout_icelandic" msgid="5836645650912489642">"Исландия"</string>
diff --git a/packages/InputDevices/res/values-lo/strings.xml b/packages/InputDevices/res/values-lo/strings.xml
index 392430f07752..b999498e9414 100644
--- a/packages/InputDevices/res/values-lo/strings.xml
+++ b/packages/InputDevices/res/values-lo/strings.xml
@@ -26,6 +26,8 @@
<string name="keyboard_layout_finnish" msgid="5585659438924315466">"ຟິນນິຊ"</string>
<string name="keyboard_layout_croatian" msgid="4172229471079281138">"ໂຄຣເອທຽນ"</string>
<string name="keyboard_layout_czech" msgid="1349256901452975343">"ເຊກ"</string>
+ <!-- no translation found for keyboard_layout_czech_qwerty (3331402534128515501) -->
+ <skip />
<string name="keyboard_layout_estonian" msgid="8775830985185665274">"ເອສໂຕນຽນ"</string>
<string name="keyboard_layout_hungarian" msgid="4154963661406035109">"ຮັງກາຣຽນ"</string>
<string name="keyboard_layout_icelandic" msgid="5836645650912489642">"ໄອສແລນດິກ"</string>
diff --git a/packages/InputDevices/res/values-lt/strings.xml b/packages/InputDevices/res/values-lt/strings.xml
index 18e33e916da5..df2e376b7520 100644
--- a/packages/InputDevices/res/values-lt/strings.xml
+++ b/packages/InputDevices/res/values-lt/strings.xml
@@ -26,6 +26,8 @@
<string name="keyboard_layout_finnish" msgid="5585659438924315466">"Suomių k."</string>
<string name="keyboard_layout_croatian" msgid="4172229471079281138">"Kroatų k."</string>
<string name="keyboard_layout_czech" msgid="1349256901452975343">"Čekų k."</string>
+ <!-- no translation found for keyboard_layout_czech_qwerty (3331402534128515501) -->
+ <skip />
<string name="keyboard_layout_estonian" msgid="8775830985185665274">"Estų k."</string>
<string name="keyboard_layout_hungarian" msgid="4154963661406035109">"Vengrų k."</string>
<string name="keyboard_layout_icelandic" msgid="5836645650912489642">"Islandų k."</string>
diff --git a/packages/InputDevices/res/values-lv/strings.xml b/packages/InputDevices/res/values-lv/strings.xml
index 96ab62f64e46..f3758390380d 100644
--- a/packages/InputDevices/res/values-lv/strings.xml
+++ b/packages/InputDevices/res/values-lv/strings.xml
@@ -26,6 +26,8 @@
<string name="keyboard_layout_finnish" msgid="5585659438924315466">"Somu"</string>
<string name="keyboard_layout_croatian" msgid="4172229471079281138">"Horvātu"</string>
<string name="keyboard_layout_czech" msgid="1349256901452975343">"Čehu"</string>
+ <!-- no translation found for keyboard_layout_czech_qwerty (3331402534128515501) -->
+ <skip />
<string name="keyboard_layout_estonian" msgid="8775830985185665274">"Igauņu"</string>
<string name="keyboard_layout_hungarian" msgid="4154963661406035109">"Ungāru"</string>
<string name="keyboard_layout_icelandic" msgid="5836645650912489642">"Īslandiešu"</string>
diff --git a/packages/InputDevices/res/values-mk/strings.xml b/packages/InputDevices/res/values-mk/strings.xml
index 33d9723dddef..b65db16c8dd5 100644
--- a/packages/InputDevices/res/values-mk/strings.xml
+++ b/packages/InputDevices/res/values-mk/strings.xml
@@ -26,6 +26,8 @@
<string name="keyboard_layout_finnish" msgid="5585659438924315466">"Фински"</string>
<string name="keyboard_layout_croatian" msgid="4172229471079281138">"Хрватски"</string>
<string name="keyboard_layout_czech" msgid="1349256901452975343">"Чешки"</string>
+ <!-- no translation found for keyboard_layout_czech_qwerty (3331402534128515501) -->
+ <skip />
<string name="keyboard_layout_estonian" msgid="8775830985185665274">"Естонски"</string>
<string name="keyboard_layout_hungarian" msgid="4154963661406035109">"Унгарски"</string>
<string name="keyboard_layout_icelandic" msgid="5836645650912489642">"Исландски"</string>
diff --git a/packages/InputDevices/res/values-ml/strings.xml b/packages/InputDevices/res/values-ml/strings.xml
index 3b29f3c1df9f..cb65e9c40822 100644
--- a/packages/InputDevices/res/values-ml/strings.xml
+++ b/packages/InputDevices/res/values-ml/strings.xml
@@ -26,6 +26,8 @@
<string name="keyboard_layout_finnish" msgid="5585659438924315466">"ഫിന്നിഷ്"</string>
<string name="keyboard_layout_croatian" msgid="4172229471079281138">"ക്രൊയേഷ്യൻ"</string>
<string name="keyboard_layout_czech" msgid="1349256901452975343">"ചെക്ക്"</string>
+ <!-- no translation found for keyboard_layout_czech_qwerty (3331402534128515501) -->
+ <skip />
<string name="keyboard_layout_estonian" msgid="8775830985185665274">"എസ്റ്റോണിയൻ"</string>
<string name="keyboard_layout_hungarian" msgid="4154963661406035109">"ഹംഗേറിയൻ"</string>
<string name="keyboard_layout_icelandic" msgid="5836645650912489642">"ഐസ്‌ലാന്‍ഡിക്"</string>
diff --git a/packages/InputDevices/res/values-mn/strings.xml b/packages/InputDevices/res/values-mn/strings.xml
index 01e8c967bfa4..f405750e941d 100644
--- a/packages/InputDevices/res/values-mn/strings.xml
+++ b/packages/InputDevices/res/values-mn/strings.xml
@@ -26,6 +26,8 @@
<string name="keyboard_layout_finnish" msgid="5585659438924315466">"Финлянд"</string>
<string name="keyboard_layout_croatian" msgid="4172229471079281138">"Хорват"</string>
<string name="keyboard_layout_czech" msgid="1349256901452975343">"Чех"</string>
+ <!-- no translation found for keyboard_layout_czech_qwerty (3331402534128515501) -->
+ <skip />
<string name="keyboard_layout_estonian" msgid="8775830985185665274">"Эстон"</string>
<string name="keyboard_layout_hungarian" msgid="4154963661406035109">"Унгар"</string>
<string name="keyboard_layout_icelandic" msgid="5836645650912489642">"Исланд"</string>
diff --git a/packages/InputDevices/res/values-mr/strings.xml b/packages/InputDevices/res/values-mr/strings.xml
index b4ebf76302eb..ba31233e0006 100644
--- a/packages/InputDevices/res/values-mr/strings.xml
+++ b/packages/InputDevices/res/values-mr/strings.xml
@@ -26,6 +26,8 @@
<string name="keyboard_layout_finnish" msgid="5585659438924315466">"फिन्निश"</string>
<string name="keyboard_layout_croatian" msgid="4172229471079281138">"क्रोएशियन"</string>
<string name="keyboard_layout_czech" msgid="1349256901452975343">"झेक"</string>
+ <!-- no translation found for keyboard_layout_czech_qwerty (3331402534128515501) -->
+ <skip />
<string name="keyboard_layout_estonian" msgid="8775830985185665274">"एस्टोनियन"</string>
<string name="keyboard_layout_hungarian" msgid="4154963661406035109">"हंगेरियन"</string>
<string name="keyboard_layout_icelandic" msgid="5836645650912489642">"आइसलँडिक"</string>
diff --git a/packages/InputDevices/res/values-ms/strings.xml b/packages/InputDevices/res/values-ms/strings.xml
index 3e716aef7571..09afb200773f 100644
--- a/packages/InputDevices/res/values-ms/strings.xml
+++ b/packages/InputDevices/res/values-ms/strings.xml
@@ -26,6 +26,8 @@
<string name="keyboard_layout_finnish" msgid="5585659438924315466">"Bahasa Finland"</string>
<string name="keyboard_layout_croatian" msgid="4172229471079281138">"Bahasa Croatia"</string>
<string name="keyboard_layout_czech" msgid="1349256901452975343">"Bahasa Czech"</string>
+ <!-- no translation found for keyboard_layout_czech_qwerty (3331402534128515501) -->
+ <skip />
<string name="keyboard_layout_estonian" msgid="8775830985185665274">"Bahasa Estonia"</string>
<string name="keyboard_layout_hungarian" msgid="4154963661406035109">"Bahasa Hungary"</string>
<string name="keyboard_layout_icelandic" msgid="5836645650912489642">"Bahasa Iceland"</string>
diff --git a/packages/InputDevices/res/values-my/strings.xml b/packages/InputDevices/res/values-my/strings.xml
index 35c52d318481..6eaeeea341ad 100644
--- a/packages/InputDevices/res/values-my/strings.xml
+++ b/packages/InputDevices/res/values-my/strings.xml
@@ -26,6 +26,8 @@
<string name="keyboard_layout_finnish" msgid="5585659438924315466">"ဖင်လန်"</string>
<string name="keyboard_layout_croatian" msgid="4172229471079281138">"ခရိုအေးရှန်း"</string>
<string name="keyboard_layout_czech" msgid="1349256901452975343">"ချက်"</string>
+ <!-- no translation found for keyboard_layout_czech_qwerty (3331402534128515501) -->
+ <skip />
<string name="keyboard_layout_estonian" msgid="8775830985185665274">"အက်စ်စတိုးနီးယန်း"</string>
<string name="keyboard_layout_hungarian" msgid="4154963661406035109">"ဟန်ဂေရီယန်း"</string>
<string name="keyboard_layout_icelandic" msgid="5836645650912489642">"အိုက်စလန်"</string>
diff --git a/packages/InputDevices/res/values-nb/strings.xml b/packages/InputDevices/res/values-nb/strings.xml
index fe0a92a0f5b5..9a0ac843cae2 100644
--- a/packages/InputDevices/res/values-nb/strings.xml
+++ b/packages/InputDevices/res/values-nb/strings.xml
@@ -26,6 +26,8 @@
<string name="keyboard_layout_finnish" msgid="5585659438924315466">"Finsk"</string>
<string name="keyboard_layout_croatian" msgid="4172229471079281138">"Kroatisk"</string>
<string name="keyboard_layout_czech" msgid="1349256901452975343">"Tsjekkisk"</string>
+ <!-- no translation found for keyboard_layout_czech_qwerty (3331402534128515501) -->
+ <skip />
<string name="keyboard_layout_estonian" msgid="8775830985185665274">"Estisk"</string>
<string name="keyboard_layout_hungarian" msgid="4154963661406035109">"Ungarsk"</string>
<string name="keyboard_layout_icelandic" msgid="5836645650912489642">"Islandsk"</string>
diff --git a/packages/InputDevices/res/values-ne/strings.xml b/packages/InputDevices/res/values-ne/strings.xml
index c847058e6692..731c88fe4077 100644
--- a/packages/InputDevices/res/values-ne/strings.xml
+++ b/packages/InputDevices/res/values-ne/strings.xml
@@ -26,6 +26,8 @@
<string name="keyboard_layout_finnish" msgid="5585659438924315466">"फिनिश"</string>
<string name="keyboard_layout_croatian" msgid="4172229471079281138">"क्रोशीयाली"</string>
<string name="keyboard_layout_czech" msgid="1349256901452975343">"चेक"</string>
+ <!-- no translation found for keyboard_layout_czech_qwerty (3331402534128515501) -->
+ <skip />
<string name="keyboard_layout_estonian" msgid="8775830985185665274">"एस्तोनीयाली"</string>
<string name="keyboard_layout_hungarian" msgid="4154963661406035109">"हंगेरियन"</string>
<string name="keyboard_layout_icelandic" msgid="5836645650912489642">"आइसल्याण्डिक"</string>
diff --git a/packages/InputDevices/res/values-nl/strings.xml b/packages/InputDevices/res/values-nl/strings.xml
index 483e821de209..578b2aa4d137 100644
--- a/packages/InputDevices/res/values-nl/strings.xml
+++ b/packages/InputDevices/res/values-nl/strings.xml
@@ -26,6 +26,8 @@
<string name="keyboard_layout_finnish" msgid="5585659438924315466">"Fins"</string>
<string name="keyboard_layout_croatian" msgid="4172229471079281138">"Kroatisch"</string>
<string name="keyboard_layout_czech" msgid="1349256901452975343">"Tsjechisch"</string>
+ <!-- no translation found for keyboard_layout_czech_qwerty (3331402534128515501) -->
+ <skip />
<string name="keyboard_layout_estonian" msgid="8775830985185665274">"Estlands"</string>
<string name="keyboard_layout_hungarian" msgid="4154963661406035109">"Hongaars"</string>
<string name="keyboard_layout_icelandic" msgid="5836645650912489642">"IJslands"</string>
diff --git a/packages/InputDevices/res/values-or/strings.xml b/packages/InputDevices/res/values-or/strings.xml
index 57df24ec8660..04d44dcac860 100644
--- a/packages/InputDevices/res/values-or/strings.xml
+++ b/packages/InputDevices/res/values-or/strings.xml
@@ -26,6 +26,8 @@
<string name="keyboard_layout_finnish" msgid="5585659438924315466">"ଫିନ୍ନିଶ୍‍"</string>
<string name="keyboard_layout_croatian" msgid="4172229471079281138">"କ୍ରୋଆଶିଆନ୍"</string>
<string name="keyboard_layout_czech" msgid="1349256901452975343">"ଚେକ୍"</string>
+ <!-- no translation found for keyboard_layout_czech_qwerty (3331402534128515501) -->
+ <skip />
<string name="keyboard_layout_estonian" msgid="8775830985185665274">"ଇଷ୍ଟୋନିଆନ୍"</string>
<string name="keyboard_layout_hungarian" msgid="4154963661406035109">"ହଙ୍ଗେରିଆନ୍"</string>
<string name="keyboard_layout_icelandic" msgid="5836645650912489642">"ଆଇସଲାଣ୍ଡିକ୍"</string>
diff --git a/packages/InputDevices/res/values-pa/strings.xml b/packages/InputDevices/res/values-pa/strings.xml
index 90203a7377ff..2eb30c90dd42 100644
--- a/packages/InputDevices/res/values-pa/strings.xml
+++ b/packages/InputDevices/res/values-pa/strings.xml
@@ -26,6 +26,8 @@
<string name="keyboard_layout_finnish" msgid="5585659438924315466">"ਫਿਨਿਸ਼"</string>
<string name="keyboard_layout_croatian" msgid="4172229471079281138">"ਕਰੋਆਟੀਆਈ"</string>
<string name="keyboard_layout_czech" msgid="1349256901452975343">"ਚੈਕ"</string>
+ <!-- no translation found for keyboard_layout_czech_qwerty (3331402534128515501) -->
+ <skip />
<string name="keyboard_layout_estonian" msgid="8775830985185665274">"ਇਸਟੋਨੀਅਨ"</string>
<string name="keyboard_layout_hungarian" msgid="4154963661406035109">"ਹੰਗੇਰੀਅਨ"</string>
<string name="keyboard_layout_icelandic" msgid="5836645650912489642">"ਆਈਸਲੈਂਡੀ"</string>
diff --git a/packages/InputDevices/res/values-pl/strings.xml b/packages/InputDevices/res/values-pl/strings.xml
index c10596a19e76..44f9e3f61c27 100644
--- a/packages/InputDevices/res/values-pl/strings.xml
+++ b/packages/InputDevices/res/values-pl/strings.xml
@@ -26,6 +26,8 @@
<string name="keyboard_layout_finnish" msgid="5585659438924315466">"Fiński"</string>
<string name="keyboard_layout_croatian" msgid="4172229471079281138">"Chorwacki"</string>
<string name="keyboard_layout_czech" msgid="1349256901452975343">"Czeski"</string>
+ <!-- no translation found for keyboard_layout_czech_qwerty (3331402534128515501) -->
+ <skip />
<string name="keyboard_layout_estonian" msgid="8775830985185665274">"Estoński"</string>
<string name="keyboard_layout_hungarian" msgid="4154963661406035109">"Węgierski"</string>
<string name="keyboard_layout_icelandic" msgid="5836645650912489642">"Islandzki"</string>
diff --git a/packages/InputDevices/res/values-pt-rBR/strings.xml b/packages/InputDevices/res/values-pt-rBR/strings.xml
index b956a01eadcb..d282f2c64860 100644
--- a/packages/InputDevices/res/values-pt-rBR/strings.xml
+++ b/packages/InputDevices/res/values-pt-rBR/strings.xml
@@ -26,6 +26,8 @@
<string name="keyboard_layout_finnish" msgid="5585659438924315466">"Finlandês"</string>
<string name="keyboard_layout_croatian" msgid="4172229471079281138">"Croata"</string>
<string name="keyboard_layout_czech" msgid="1349256901452975343">"Tcheco"</string>
+ <!-- no translation found for keyboard_layout_czech_qwerty (3331402534128515501) -->
+ <skip />
<string name="keyboard_layout_estonian" msgid="8775830985185665274">"Estoniano"</string>
<string name="keyboard_layout_hungarian" msgid="4154963661406035109">"Húngaro"</string>
<string name="keyboard_layout_icelandic" msgid="5836645650912489642">"Islandês"</string>
diff --git a/packages/InputDevices/res/values-pt-rPT/strings.xml b/packages/InputDevices/res/values-pt-rPT/strings.xml
index d9aa91d34c8b..052e2ad160bb 100644
--- a/packages/InputDevices/res/values-pt-rPT/strings.xml
+++ b/packages/InputDevices/res/values-pt-rPT/strings.xml
@@ -26,6 +26,8 @@
<string name="keyboard_layout_finnish" msgid="5585659438924315466">"Finlandês"</string>
<string name="keyboard_layout_croatian" msgid="4172229471079281138">"Croata"</string>
<string name="keyboard_layout_czech" msgid="1349256901452975343">"Checo"</string>
+ <!-- no translation found for keyboard_layout_czech_qwerty (3331402534128515501) -->
+ <skip />
<string name="keyboard_layout_estonian" msgid="8775830985185665274">"Estónio"</string>
<string name="keyboard_layout_hungarian" msgid="4154963661406035109">"Húngaro"</string>
<string name="keyboard_layout_icelandic" msgid="5836645650912489642">"Islandês"</string>
diff --git a/packages/InputDevices/res/values-pt/strings.xml b/packages/InputDevices/res/values-pt/strings.xml
index b956a01eadcb..d282f2c64860 100644
--- a/packages/InputDevices/res/values-pt/strings.xml
+++ b/packages/InputDevices/res/values-pt/strings.xml
@@ -26,6 +26,8 @@
<string name="keyboard_layout_finnish" msgid="5585659438924315466">"Finlandês"</string>
<string name="keyboard_layout_croatian" msgid="4172229471079281138">"Croata"</string>
<string name="keyboard_layout_czech" msgid="1349256901452975343">"Tcheco"</string>
+ <!-- no translation found for keyboard_layout_czech_qwerty (3331402534128515501) -->
+ <skip />
<string name="keyboard_layout_estonian" msgid="8775830985185665274">"Estoniano"</string>
<string name="keyboard_layout_hungarian" msgid="4154963661406035109">"Húngaro"</string>
<string name="keyboard_layout_icelandic" msgid="5836645650912489642">"Islandês"</string>
diff --git a/packages/InputDevices/res/values-ro/strings.xml b/packages/InputDevices/res/values-ro/strings.xml
index 9deaa452042c..7d85df0ff637 100644
--- a/packages/InputDevices/res/values-ro/strings.xml
+++ b/packages/InputDevices/res/values-ro/strings.xml
@@ -26,6 +26,8 @@
<string name="keyboard_layout_finnish" msgid="5585659438924315466">"Finlandeză"</string>
<string name="keyboard_layout_croatian" msgid="4172229471079281138">"Croată"</string>
<string name="keyboard_layout_czech" msgid="1349256901452975343">"Cehă"</string>
+ <!-- no translation found for keyboard_layout_czech_qwerty (3331402534128515501) -->
+ <skip />
<string name="keyboard_layout_estonian" msgid="8775830985185665274">"Estoniană"</string>
<string name="keyboard_layout_hungarian" msgid="4154963661406035109">"Maghiară"</string>
<string name="keyboard_layout_icelandic" msgid="5836645650912489642">"Islandeză"</string>
diff --git a/packages/InputDevices/res/values-ru/strings.xml b/packages/InputDevices/res/values-ru/strings.xml
index 888c8f57fd32..a1d3185a6397 100644
--- a/packages/InputDevices/res/values-ru/strings.xml
+++ b/packages/InputDevices/res/values-ru/strings.xml
@@ -26,6 +26,8 @@
<string name="keyboard_layout_finnish" msgid="5585659438924315466">"финский"</string>
<string name="keyboard_layout_croatian" msgid="4172229471079281138">"хорватский"</string>
<string name="keyboard_layout_czech" msgid="1349256901452975343">"чешский"</string>
+ <!-- no translation found for keyboard_layout_czech_qwerty (3331402534128515501) -->
+ <skip />
<string name="keyboard_layout_estonian" msgid="8775830985185665274">"эстонский"</string>
<string name="keyboard_layout_hungarian" msgid="4154963661406035109">"венгерский"</string>
<string name="keyboard_layout_icelandic" msgid="5836645650912489642">"исландский"</string>
diff --git a/packages/InputDevices/res/values-si/strings.xml b/packages/InputDevices/res/values-si/strings.xml
index 895e7b5065d5..49b990751d5d 100644
--- a/packages/InputDevices/res/values-si/strings.xml
+++ b/packages/InputDevices/res/values-si/strings.xml
@@ -26,6 +26,8 @@
<string name="keyboard_layout_finnish" msgid="5585659438924315466">"ෆින්ලන්ත"</string>
<string name="keyboard_layout_croatian" msgid="4172229471079281138">"ක්‍රොඒෂියානු"</string>
<string name="keyboard_layout_czech" msgid="1349256901452975343">"චෙක්"</string>
+ <!-- no translation found for keyboard_layout_czech_qwerty (3331402534128515501) -->
+ <skip />
<string name="keyboard_layout_estonian" msgid="8775830985185665274">"එස්තෝනියානු"</string>
<string name="keyboard_layout_hungarian" msgid="4154963661406035109">"හංගේරියානු"</string>
<string name="keyboard_layout_icelandic" msgid="5836645650912489642">"අයිස්ලන්ත"</string>
diff --git a/packages/InputDevices/res/values-sk/strings.xml b/packages/InputDevices/res/values-sk/strings.xml
index 70843d28f90e..260a43258818 100644
--- a/packages/InputDevices/res/values-sk/strings.xml
+++ b/packages/InputDevices/res/values-sk/strings.xml
@@ -26,6 +26,8 @@
<string name="keyboard_layout_finnish" msgid="5585659438924315466">"fínske"</string>
<string name="keyboard_layout_croatian" msgid="4172229471079281138">"chorvátske"</string>
<string name="keyboard_layout_czech" msgid="1349256901452975343">"české"</string>
+ <!-- no translation found for keyboard_layout_czech_qwerty (3331402534128515501) -->
+ <skip />
<string name="keyboard_layout_estonian" msgid="8775830985185665274">"estónske"</string>
<string name="keyboard_layout_hungarian" msgid="4154963661406035109">"maďarské"</string>
<string name="keyboard_layout_icelandic" msgid="5836645650912489642">"islandské"</string>
diff --git a/packages/InputDevices/res/values-sl/strings.xml b/packages/InputDevices/res/values-sl/strings.xml
index 410be33fa2ad..613dda057d4a 100644
--- a/packages/InputDevices/res/values-sl/strings.xml
+++ b/packages/InputDevices/res/values-sl/strings.xml
@@ -26,6 +26,8 @@
<string name="keyboard_layout_finnish" msgid="5585659438924315466">"finska"</string>
<string name="keyboard_layout_croatian" msgid="4172229471079281138">"hrvaška"</string>
<string name="keyboard_layout_czech" msgid="1349256901452975343">"češka"</string>
+ <!-- no translation found for keyboard_layout_czech_qwerty (3331402534128515501) -->
+ <skip />
<string name="keyboard_layout_estonian" msgid="8775830985185665274">"estonska"</string>
<string name="keyboard_layout_hungarian" msgid="4154963661406035109">"madžarska"</string>
<string name="keyboard_layout_icelandic" msgid="5836645650912489642">"islandska"</string>
diff --git a/packages/InputDevices/res/values-sq/strings.xml b/packages/InputDevices/res/values-sq/strings.xml
index b620067d2233..29e22786d2c4 100644
--- a/packages/InputDevices/res/values-sq/strings.xml
+++ b/packages/InputDevices/res/values-sq/strings.xml
@@ -26,6 +26,8 @@
<string name="keyboard_layout_finnish" msgid="5585659438924315466">"finlandisht"</string>
<string name="keyboard_layout_croatian" msgid="4172229471079281138">"kroatisht"</string>
<string name="keyboard_layout_czech" msgid="1349256901452975343">"çekisht"</string>
+ <!-- no translation found for keyboard_layout_czech_qwerty (3331402534128515501) -->
+ <skip />
<string name="keyboard_layout_estonian" msgid="8775830985185665274">"estonisht"</string>
<string name="keyboard_layout_hungarian" msgid="4154963661406035109">"hungarisht"</string>
<string name="keyboard_layout_icelandic" msgid="5836645650912489642">"islandisht"</string>
diff --git a/packages/InputDevices/res/values-sr/strings.xml b/packages/InputDevices/res/values-sr/strings.xml
index 543af8a66399..686f6aea8ce1 100644
--- a/packages/InputDevices/res/values-sr/strings.xml
+++ b/packages/InputDevices/res/values-sr/strings.xml
@@ -26,6 +26,8 @@
<string name="keyboard_layout_finnish" msgid="5585659438924315466">"финска"</string>
<string name="keyboard_layout_croatian" msgid="4172229471079281138">"хрватска"</string>
<string name="keyboard_layout_czech" msgid="1349256901452975343">"чешка"</string>
+ <!-- no translation found for keyboard_layout_czech_qwerty (3331402534128515501) -->
+ <skip />
<string name="keyboard_layout_estonian" msgid="8775830985185665274">"естонска"</string>
<string name="keyboard_layout_hungarian" msgid="4154963661406035109">"мађарска"</string>
<string name="keyboard_layout_icelandic" msgid="5836645650912489642">"исландска"</string>
diff --git a/packages/InputDevices/res/values-sv/strings.xml b/packages/InputDevices/res/values-sv/strings.xml
index f776a43db81a..7b7076732ad1 100644
--- a/packages/InputDevices/res/values-sv/strings.xml
+++ b/packages/InputDevices/res/values-sv/strings.xml
@@ -26,6 +26,8 @@
<string name="keyboard_layout_finnish" msgid="5585659438924315466">"Finskt"</string>
<string name="keyboard_layout_croatian" msgid="4172229471079281138">"Kroatiskt"</string>
<string name="keyboard_layout_czech" msgid="1349256901452975343">"Tjeckiskt"</string>
+ <!-- no translation found for keyboard_layout_czech_qwerty (3331402534128515501) -->
+ <skip />
<string name="keyboard_layout_estonian" msgid="8775830985185665274">"Estniskt"</string>
<string name="keyboard_layout_hungarian" msgid="4154963661406035109">"Ungerskt"</string>
<string name="keyboard_layout_icelandic" msgid="5836645650912489642">"Isländskt"</string>
diff --git a/packages/InputDevices/res/values-sw/strings.xml b/packages/InputDevices/res/values-sw/strings.xml
index 3d25dadab70c..d82959a60f78 100644
--- a/packages/InputDevices/res/values-sw/strings.xml
+++ b/packages/InputDevices/res/values-sw/strings.xml
@@ -26,6 +26,8 @@
<string name="keyboard_layout_finnish" msgid="5585659438924315466">"Kifinlandi"</string>
<string name="keyboard_layout_croatian" msgid="4172229471079281138">"Kikroeshia"</string>
<string name="keyboard_layout_czech" msgid="1349256901452975343">"Kicheki"</string>
+ <!-- no translation found for keyboard_layout_czech_qwerty (3331402534128515501) -->
+ <skip />
<string name="keyboard_layout_estonian" msgid="8775830985185665274">"Kiestonia"</string>
<string name="keyboard_layout_hungarian" msgid="4154963661406035109">"Kihungari"</string>
<string name="keyboard_layout_icelandic" msgid="5836645650912489642">"Kiaislandi"</string>
diff --git a/packages/InputDevices/res/values-ta/strings.xml b/packages/InputDevices/res/values-ta/strings.xml
index ff8e474cf504..e25e5edfda40 100644
--- a/packages/InputDevices/res/values-ta/strings.xml
+++ b/packages/InputDevices/res/values-ta/strings.xml
@@ -26,6 +26,8 @@
<string name="keyboard_layout_finnish" msgid="5585659438924315466">"ஃபின்னிஷ்"</string>
<string name="keyboard_layout_croatian" msgid="4172229471079281138">"குரோஷியன்"</string>
<string name="keyboard_layout_czech" msgid="1349256901452975343">"செக்"</string>
+ <!-- no translation found for keyboard_layout_czech_qwerty (3331402534128515501) -->
+ <skip />
<string name="keyboard_layout_estonian" msgid="8775830985185665274">"எஸ்தோனியன்"</string>
<string name="keyboard_layout_hungarian" msgid="4154963661406035109">"ஹங்கேரியன்"</string>
<string name="keyboard_layout_icelandic" msgid="5836645650912489642">"ஐஸ்லாண்டிக்"</string>
diff --git a/packages/InputDevices/res/values-te/strings.xml b/packages/InputDevices/res/values-te/strings.xml
index c22ab22c56d0..e07b2b521614 100644
--- a/packages/InputDevices/res/values-te/strings.xml
+++ b/packages/InputDevices/res/values-te/strings.xml
@@ -26,6 +26,8 @@
<string name="keyboard_layout_finnish" msgid="5585659438924315466">"ఫిన్నిష్"</string>
<string name="keyboard_layout_croatian" msgid="4172229471079281138">"క్రొయేషియన్"</string>
<string name="keyboard_layout_czech" msgid="1349256901452975343">"చెక్"</string>
+ <!-- no translation found for keyboard_layout_czech_qwerty (3331402534128515501) -->
+ <skip />
<string name="keyboard_layout_estonian" msgid="8775830985185665274">"ఎస్టోనియన్"</string>
<string name="keyboard_layout_hungarian" msgid="4154963661406035109">"హంగేరియన్"</string>
<string name="keyboard_layout_icelandic" msgid="5836645650912489642">"ఐస్‌లాండిక్"</string>
diff --git a/packages/InputDevices/res/values-th/strings.xml b/packages/InputDevices/res/values-th/strings.xml
index 5dfc0f92eabf..926c127aea38 100644
--- a/packages/InputDevices/res/values-th/strings.xml
+++ b/packages/InputDevices/res/values-th/strings.xml
@@ -26,6 +26,8 @@
<string name="keyboard_layout_finnish" msgid="5585659438924315466">"ฟินแลนด์"</string>
<string name="keyboard_layout_croatian" msgid="4172229471079281138">"โครเอเชีย"</string>
<string name="keyboard_layout_czech" msgid="1349256901452975343">"เช็ก"</string>
+ <!-- no translation found for keyboard_layout_czech_qwerty (3331402534128515501) -->
+ <skip />
<string name="keyboard_layout_estonian" msgid="8775830985185665274">"เอสโตเนีย"</string>
<string name="keyboard_layout_hungarian" msgid="4154963661406035109">"ฮังการี"</string>
<string name="keyboard_layout_icelandic" msgid="5836645650912489642">"ไอซ์แลนดิก"</string>
diff --git a/packages/InputDevices/res/values-tl/strings.xml b/packages/InputDevices/res/values-tl/strings.xml
index 5441b0634643..41d6a18ce6d2 100644
--- a/packages/InputDevices/res/values-tl/strings.xml
+++ b/packages/InputDevices/res/values-tl/strings.xml
@@ -26,6 +26,8 @@
<string name="keyboard_layout_finnish" msgid="5585659438924315466">"Finnish"</string>
<string name="keyboard_layout_croatian" msgid="4172229471079281138">"Croatian"</string>
<string name="keyboard_layout_czech" msgid="1349256901452975343">"Czech"</string>
+ <!-- no translation found for keyboard_layout_czech_qwerty (3331402534128515501) -->
+ <skip />
<string name="keyboard_layout_estonian" msgid="8775830985185665274">"Estonian"</string>
<string name="keyboard_layout_hungarian" msgid="4154963661406035109">"Hungarian"</string>
<string name="keyboard_layout_icelandic" msgid="5836645650912489642">"Icelandic"</string>
diff --git a/packages/InputDevices/res/values-tr/strings.xml b/packages/InputDevices/res/values-tr/strings.xml
index 4b8a728f0ae9..9249930ee978 100644
--- a/packages/InputDevices/res/values-tr/strings.xml
+++ b/packages/InputDevices/res/values-tr/strings.xml
@@ -26,6 +26,8 @@
<string name="keyboard_layout_finnish" msgid="5585659438924315466">"Fince"</string>
<string name="keyboard_layout_croatian" msgid="4172229471079281138">"Hırvatça"</string>
<string name="keyboard_layout_czech" msgid="1349256901452975343">"Çekçe"</string>
+ <!-- no translation found for keyboard_layout_czech_qwerty (3331402534128515501) -->
+ <skip />
<string name="keyboard_layout_estonian" msgid="8775830985185665274">"Estonca"</string>
<string name="keyboard_layout_hungarian" msgid="4154963661406035109">"Macarca"</string>
<string name="keyboard_layout_icelandic" msgid="5836645650912489642">"İzlandaca"</string>
diff --git a/packages/InputDevices/res/values-uk/strings.xml b/packages/InputDevices/res/values-uk/strings.xml
index 6c0934f6e340..20f60461af1c 100644
--- a/packages/InputDevices/res/values-uk/strings.xml
+++ b/packages/InputDevices/res/values-uk/strings.xml
@@ -26,6 +26,8 @@
<string name="keyboard_layout_finnish" msgid="5585659438924315466">"фінська"</string>
<string name="keyboard_layout_croatian" msgid="4172229471079281138">"хорватська"</string>
<string name="keyboard_layout_czech" msgid="1349256901452975343">"чеська"</string>
+ <!-- no translation found for keyboard_layout_czech_qwerty (3331402534128515501) -->
+ <skip />
<string name="keyboard_layout_estonian" msgid="8775830985185665274">"естонська"</string>
<string name="keyboard_layout_hungarian" msgid="4154963661406035109">"угорська"</string>
<string name="keyboard_layout_icelandic" msgid="5836645650912489642">"ісландська"</string>
diff --git a/packages/InputDevices/res/values-ur/strings.xml b/packages/InputDevices/res/values-ur/strings.xml
index 80c67f5032b5..7e474302125b 100644
--- a/packages/InputDevices/res/values-ur/strings.xml
+++ b/packages/InputDevices/res/values-ur/strings.xml
@@ -26,6 +26,8 @@
<string name="keyboard_layout_finnish" msgid="5585659438924315466">"فنش"</string>
<string name="keyboard_layout_croatian" msgid="4172229471079281138">"کروشیائی"</string>
<string name="keyboard_layout_czech" msgid="1349256901452975343">"چیک"</string>
+ <!-- no translation found for keyboard_layout_czech_qwerty (3331402534128515501) -->
+ <skip />
<string name="keyboard_layout_estonian" msgid="8775830985185665274">"اسٹونیائی"</string>
<string name="keyboard_layout_hungarian" msgid="4154963661406035109">"ہنگریائی"</string>
<string name="keyboard_layout_icelandic" msgid="5836645650912489642">"آئس لینڈک"</string>
diff --git a/packages/InputDevices/res/values-uz/strings.xml b/packages/InputDevices/res/values-uz/strings.xml
index d205a560be8f..9d7f1e43e93f 100644
--- a/packages/InputDevices/res/values-uz/strings.xml
+++ b/packages/InputDevices/res/values-uz/strings.xml
@@ -26,6 +26,8 @@
<string name="keyboard_layout_finnish" msgid="5585659438924315466">"Fincha"</string>
<string name="keyboard_layout_croatian" msgid="4172229471079281138">"Xorvatcha"</string>
<string name="keyboard_layout_czech" msgid="1349256901452975343">"Chexcha"</string>
+ <!-- no translation found for keyboard_layout_czech_qwerty (3331402534128515501) -->
+ <skip />
<string name="keyboard_layout_estonian" msgid="8775830985185665274">"Estoncha"</string>
<string name="keyboard_layout_hungarian" msgid="4154963661406035109">"Vengercha"</string>
<string name="keyboard_layout_icelandic" msgid="5836645650912489642">"Islandcha"</string>
diff --git a/packages/InputDevices/res/values-vi/strings.xml b/packages/InputDevices/res/values-vi/strings.xml
index 4e446946cc50..62e59520e6eb 100644
--- a/packages/InputDevices/res/values-vi/strings.xml
+++ b/packages/InputDevices/res/values-vi/strings.xml
@@ -26,6 +26,8 @@
<string name="keyboard_layout_finnish" msgid="5585659438924315466">"Tiếng Phần Lan"</string>
<string name="keyboard_layout_croatian" msgid="4172229471079281138">"Tiếng Croatia"</string>
<string name="keyboard_layout_czech" msgid="1349256901452975343">"Tiếng Séc"</string>
+ <!-- no translation found for keyboard_layout_czech_qwerty (3331402534128515501) -->
+ <skip />
<string name="keyboard_layout_estonian" msgid="8775830985185665274">"Tiếng Estonia"</string>
<string name="keyboard_layout_hungarian" msgid="4154963661406035109">"Tiếng Hungary"</string>
<string name="keyboard_layout_icelandic" msgid="5836645650912489642">"Tiếng Ai-xơ-len"</string>
diff --git a/packages/InputDevices/res/values-zh-rCN/strings.xml b/packages/InputDevices/res/values-zh-rCN/strings.xml
index fecaca8644ca..0b6ec0f6f7c4 100644
--- a/packages/InputDevices/res/values-zh-rCN/strings.xml
+++ b/packages/InputDevices/res/values-zh-rCN/strings.xml
@@ -26,6 +26,8 @@
<string name="keyboard_layout_finnish" msgid="5585659438924315466">"芬兰语"</string>
<string name="keyboard_layout_croatian" msgid="4172229471079281138">"克罗地亚语"</string>
<string name="keyboard_layout_czech" msgid="1349256901452975343">"捷克语"</string>
+ <!-- no translation found for keyboard_layout_czech_qwerty (3331402534128515501) -->
+ <skip />
<string name="keyboard_layout_estonian" msgid="8775830985185665274">"爱沙尼亚语"</string>
<string name="keyboard_layout_hungarian" msgid="4154963661406035109">"匈牙利语"</string>
<string name="keyboard_layout_icelandic" msgid="5836645650912489642">"冰岛语"</string>
diff --git a/packages/InputDevices/res/values-zh-rHK/strings.xml b/packages/InputDevices/res/values-zh-rHK/strings.xml
index f87b7f8c4919..22b46ca4a3cc 100644
--- a/packages/InputDevices/res/values-zh-rHK/strings.xml
+++ b/packages/InputDevices/res/values-zh-rHK/strings.xml
@@ -26,6 +26,8 @@
<string name="keyboard_layout_finnish" msgid="5585659438924315466">"芬蘭文"</string>
<string name="keyboard_layout_croatian" msgid="4172229471079281138">"克羅地亞文"</string>
<string name="keyboard_layout_czech" msgid="1349256901452975343">"捷克文"</string>
+ <!-- no translation found for keyboard_layout_czech_qwerty (3331402534128515501) -->
+ <skip />
<string name="keyboard_layout_estonian" msgid="8775830985185665274">"愛沙尼亞文"</string>
<string name="keyboard_layout_hungarian" msgid="4154963661406035109">"匈牙利文"</string>
<string name="keyboard_layout_icelandic" msgid="5836645650912489642">"冰島文"</string>
diff --git a/packages/InputDevices/res/values-zh-rTW/strings.xml b/packages/InputDevices/res/values-zh-rTW/strings.xml
index 13514dffea9f..abe16f360f1f 100644
--- a/packages/InputDevices/res/values-zh-rTW/strings.xml
+++ b/packages/InputDevices/res/values-zh-rTW/strings.xml
@@ -26,6 +26,8 @@
<string name="keyboard_layout_finnish" msgid="5585659438924315466">"芬蘭文"</string>
<string name="keyboard_layout_croatian" msgid="4172229471079281138">"克羅埃西亞文"</string>
<string name="keyboard_layout_czech" msgid="1349256901452975343">"捷克文"</string>
+ <!-- no translation found for keyboard_layout_czech_qwerty (3331402534128515501) -->
+ <skip />
<string name="keyboard_layout_estonian" msgid="8775830985185665274">"愛沙尼亞文"</string>
<string name="keyboard_layout_hungarian" msgid="4154963661406035109">"匈牙利文"</string>
<string name="keyboard_layout_icelandic" msgid="5836645650912489642">"冰島文"</string>
diff --git a/packages/InputDevices/res/values-zu/strings.xml b/packages/InputDevices/res/values-zu/strings.xml
index 36e2001068c2..c94225126580 100644
--- a/packages/InputDevices/res/values-zu/strings.xml
+++ b/packages/InputDevices/res/values-zu/strings.xml
@@ -26,6 +26,8 @@
<string name="keyboard_layout_finnish" msgid="5585659438924315466">"Isi-Finnish"</string>
<string name="keyboard_layout_croatian" msgid="4172229471079281138">"Isi-Croatian"</string>
<string name="keyboard_layout_czech" msgid="1349256901452975343">"Isi-Czech"</string>
+ <!-- no translation found for keyboard_layout_czech_qwerty (3331402534128515501) -->
+ <skip />
<string name="keyboard_layout_estonian" msgid="8775830985185665274">"Isi-Estonian"</string>
<string name="keyboard_layout_hungarian" msgid="4154963661406035109">"Isi-Hungarian"</string>
<string name="keyboard_layout_icelandic" msgid="5836645650912489642">"Isi-Icelandic"</string>
diff --git a/packages/PrintSpooler/src/com/android/printspooler/ui/FusedPrintersProvider.java b/packages/PrintSpooler/src/com/android/printspooler/ui/FusedPrintersProvider.java
index 467a60e62e14..8e140ca27971 100644
--- a/packages/PrintSpooler/src/com/android/printspooler/ui/FusedPrintersProvider.java
+++ b/packages/PrintSpooler/src/com/android/printspooler/ui/FusedPrintersProvider.java
@@ -31,6 +31,7 @@ import android.location.LocationRequest;
import android.os.AsyncTask;
import android.os.Bundle;
import android.os.Handler;
+import android.os.HandlerExecutor;
import android.os.Looper;
import android.os.SystemClock;
import android.print.PrintManager;
@@ -250,9 +251,13 @@ public final class FusedPrintersProvider extends Loader<List<PrinterInfo>>
Log.i(LOG_TAG, "onStartLoading() " + FusedPrintersProvider.this.hashCode());
}
- mLocationManager.requestLocationUpdates(LocationRequest.create()
- .setQuality(LocationRequest.POWER_LOW).setInterval(LOCATION_UPDATE_MS), this,
- Looper.getMainLooper());
+ mLocationManager.requestLocationUpdates(
+ LocationManager.FUSED_PROVIDER,
+ new LocationRequest.Builder(LOCATION_UPDATE_MS)
+ .setQuality(LocationRequest.POWER_LOW)
+ .build(),
+ new HandlerExecutor(new Handler(Looper.getMainLooper())),
+ this);
Location lastLocation = mLocationManager.getLastLocation();
if (lastLocation != null) {
diff --git a/packages/SettingsLib/res/values-ar/strings.xml b/packages/SettingsLib/res/values-ar/strings.xml
index 9acfa0da7747..9ca1814783b5 100644
--- a/packages/SettingsLib/res/values-ar/strings.xml
+++ b/packages/SettingsLib/res/values-ar/strings.xml
@@ -25,7 +25,7 @@
<string name="wifi_remembered" msgid="3266709779723179188">"تم الحفظ"</string>
<string name="wifi_disconnected" msgid="7054450256284661757">"غير متصلة"</string>
<string name="wifi_disabled_generic" msgid="2651916945380294607">"غير مفعّلة"</string>
- <string name="wifi_disabled_network_failure" msgid="2660396183242399585">"‏تعذّرت تهيئة عنوان IP"</string>
+ <string name="wifi_disabled_network_failure" msgid="2660396183242399585">"‏تعذّر إعداد عنوان IP"</string>
<string name="wifi_disabled_by_recommendation_provider" msgid="1302938248432705534">"الجهاز غير متصل بسبب انخفاض جودة الشبكة"</string>
<string name="wifi_disabled_wifi_failure" msgid="8819554899148331100">"‏تعذّر اتصال WiFi"</string>
<string name="wifi_disabled_password_failure" msgid="6892387079613226738">"حدثت مشكلة في المصادقة"</string>
@@ -292,8 +292,8 @@
<string name="dev_logpersist_clear_warning_message" msgid="6447590867594287413">"عندما نتوقف عن رصد أي أخطاء باستخدام المسجِّل الدائم مرة أخرى، يتعين علينا محو بيانات المسجِّل الموجودة على جهازك."</string>
<string name="select_logpersist_title" msgid="447071974007104196">"تخزين بيانات المسجِّل باستمرار على الجهاز"</string>
<string name="select_logpersist_dialog_title" msgid="7745193591195485594">"تحديد مخازن السجلات المؤقتة المراد تخزينها باستمرار على الجهاز"</string>
- <string name="select_usb_configuration_title" msgid="6339801314922294586">"‏حدد تهيئة USB"</string>
- <string name="select_usb_configuration_dialog_title" msgid="3579567144722589237">"‏حدد تهيئة USB"</string>
+ <string name="select_usb_configuration_title" msgid="6339801314922294586">"‏حدد إعداد USB"</string>
+ <string name="select_usb_configuration_dialog_title" msgid="3579567144722589237">"‏حدد إعداد USB"</string>
<string name="allow_mock_location" msgid="2102650981552527884">"السماح بمواقع وهمية"</string>
<string name="allow_mock_location_summary" msgid="179780881081354579">"السماح بمواقع وهمية"</string>
<string name="debug_view_attributes" msgid="3539609843984208216">"تفعيل فحص سمة العرض"</string>
diff --git a/packages/SettingsLib/src/com/android/settingslib/wifi/WifiEntryPreference.java b/packages/SettingsLib/src/com/android/settingslib/wifi/WifiEntryPreference.java
index bba69f29a290..aad0d3af6626 100644
--- a/packages/SettingsLib/src/com/android/settingslib/wifi/WifiEntryPreference.java
+++ b/packages/SettingsLib/src/com/android/settingslib/wifi/WifiEntryPreference.java
@@ -35,7 +35,6 @@ import androidx.preference.PreferenceViewHolder;
import com.android.settingslib.R;
import com.android.settingslib.Utils;
import com.android.wifitrackerlib.WifiEntry;
-import com.android.wifitrackerlib.WifiEntry.ConnectedInfo;
/**
* Preference to display a WifiEntry in a wifi picker.
@@ -138,11 +137,7 @@ public class WifiEntryPreference extends Preference implements WifiEntry.WifiEnt
public void refresh() {
setTitle(mWifiEntry.getTitle());
final int level = mWifiEntry.getLevel();
- final ConnectedInfo connectedInfo = mWifiEntry.getConnectedInfo();
- boolean showX = false;
- if (connectedInfo != null) {
- showX = !connectedInfo.isDefaultNetwork || !connectedInfo.isValidated;
- }
+ final boolean showX = mWifiEntry.shouldShowXLevelIcon();
if (level != mLevel || showX != mShowX) {
mLevel = level;
mShowX = showX;
diff --git a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/wifi/WifiEntryPreferenceTest.java b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/wifi/WifiEntryPreferenceTest.java
index 40af7dc797b3..c21830b28e3a 100644
--- a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/wifi/WifiEntryPreferenceTest.java
+++ b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/wifi/WifiEntryPreferenceTest.java
@@ -17,7 +17,6 @@ package com.android.settingslib.wifi;
import static com.google.common.truth.Truth.assertThat;
-import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.when;
import android.content.Context;
@@ -30,7 +29,6 @@ import androidx.preference.PreferenceViewHolder;
import com.android.settingslib.R;
import com.android.wifitrackerlib.WifiEntry;
-import com.android.wifitrackerlib.WifiEntry.ConnectedInfo;
import org.junit.Before;
import org.junit.Test;
@@ -179,43 +177,9 @@ public class WifiEntryPreferenceTest {
}
@Test
- public void levelChanged_notDefaultWifiRefresh_shouldUpdateLevelIcon() {
+ public void levelChanged_showXWifiRefresh_shouldUpdateLevelIcon() {
final List<Drawable> iconList = new ArrayList<>();
- final ConnectedInfo mockConnectedInfo = mock(ConnectedInfo.class);
- mockConnectedInfo.isDefaultNetwork = false;
- when(mMockWifiEntry.getConnectedInfo()).thenReturn(mockConnectedInfo);
- final WifiEntryPreference pref =
- new WifiEntryPreference(mContext, mMockWifiEntry, mMockIconInjector);
-
- when(mMockWifiEntry.getLevel()).thenReturn(0);
- pref.refresh();
- iconList.add(pref.getIcon());
- when(mMockWifiEntry.getLevel()).thenReturn(1);
- pref.refresh();
- iconList.add(pref.getIcon());
- when(mMockWifiEntry.getLevel()).thenReturn(2);
- pref.refresh();
- iconList.add(pref.getIcon());
- when(mMockWifiEntry.getLevel()).thenReturn(3);
- pref.refresh();
- iconList.add(pref.getIcon());
- when(mMockWifiEntry.getLevel()).thenReturn(4);
- pref.refresh();
- iconList.add(pref.getIcon());
- when(mMockWifiEntry.getLevel()).thenReturn(-1);
- pref.refresh();
- iconList.add(pref.getIcon());
-
- assertThat(iconList).containsExactly(mMockShowXDrawable0, mMockShowXDrawable1,
- mMockShowXDrawable2, mMockShowXDrawable3, mMockShowXDrawable4, null);
- }
-
- @Test
- public void levelChanged_notValidatedWifiRefresh_shouldUpdateLevelIcon() {
- final List<Drawable> iconList = new ArrayList<>();
- final ConnectedInfo mockConnectedInfo = mock(ConnectedInfo.class);
- mockConnectedInfo.isValidated = false;
- when(mMockWifiEntry.getConnectedInfo()).thenReturn(mockConnectedInfo);
+ when(mMockWifiEntry.shouldShowXLevelIcon()).thenReturn(true);
final WifiEntryPreference pref =
new WifiEntryPreference(mContext, mMockWifiEntry, mMockIconInjector);
diff --git a/packages/SystemUI/res/values-af/strings.xml b/packages/SystemUI/res/values-af/strings.xml
index eae2cbb332df..4a55ce3f077b 100644
--- a/packages/SystemUI/res/values-af/strings.xml
+++ b/packages/SystemUI/res/values-af/strings.xml
@@ -1067,6 +1067,4 @@
<string name="controls_added_tooltip" msgid="4842812921719153085">"Hou aan/af-skakelaar in om nuwe kontroles te sien"</string>
<string name="controls_menu_add" msgid="4447246119229920050">"Voeg kontroles by"</string>
<string name="controls_menu_edit" msgid="890623986951347062">"Wysig kontroles"</string>
- <string name="one_handed_tutorial_title" msgid="6312198435090726656">"Gebruik eenhandmodus"</string>
- <string name="one_handed_tutorial_description" msgid="7674850272340517174">"Swiep van die onderkant van die skerm af op of tik enige plek bo die program om uit te gaan"</string>
</resources>
diff --git a/packages/SystemUI/res/values-am/strings.xml b/packages/SystemUI/res/values-am/strings.xml
index e8326a7b3293..7de4f443240c 100644
--- a/packages/SystemUI/res/values-am/strings.xml
+++ b/packages/SystemUI/res/values-am/strings.xml
@@ -1067,6 +1067,4 @@
<string name="controls_added_tooltip" msgid="4842812921719153085">"አዲስ መቆጣጠሪያዎችን ለማየት የኃይል አዝራር ይያዙ"</string>
<string name="controls_menu_add" msgid="4447246119229920050">"መቆጣጠሪያዎችን አክል"</string>
<string name="controls_menu_edit" msgid="890623986951347062">"መቆጣጠሪያዎችን ያርትዑ"</string>
- <string name="one_handed_tutorial_title" msgid="6312198435090726656">"ባለአንድ እጅ ሁነታን በመጠቀም ላይ"</string>
- <string name="one_handed_tutorial_description" msgid="7674850272340517174">"ለመውጣት ከማያው ግርጌ ወደ ላይ ይጥረጉ ወይም ከመተግበሪያው በላይ ማንኛውም ቦታ ላይ መታ ያድርጉ"</string>
</resources>
diff --git a/packages/SystemUI/res/values-ar/strings.xml b/packages/SystemUI/res/values-ar/strings.xml
index b020f17dc612..9874d70a87dc 100644
--- a/packages/SystemUI/res/values-ar/strings.xml
+++ b/packages/SystemUI/res/values-ar/strings.xml
@@ -1091,6 +1091,4 @@
<string name="controls_added_tooltip" msgid="4842812921719153085">"اضغط مع الاستمرار على زر التشغيل لعرض عناصر التحكّم الجديدة."</string>
<string name="controls_menu_add" msgid="4447246119229920050">"إضافة عناصر تحكّم"</string>
<string name="controls_menu_edit" msgid="890623986951347062">"تعديل عناصر التحكّم"</string>
- <string name="one_handed_tutorial_title" msgid="6312198435090726656">"استخدام وضع \"التصفح بيد واحدة\""</string>
- <string name="one_handed_tutorial_description" msgid="7674850272340517174">"للخروج، مرِّر سريعًا من أسفل الشاشة إلى أعلاها أو انقر في أي مكان فوق التطبيق."</string>
</resources>
diff --git a/packages/SystemUI/res/values-as/strings.xml b/packages/SystemUI/res/values-as/strings.xml
index 31077dac8c41..55799a86089a 100644
--- a/packages/SystemUI/res/values-as/strings.xml
+++ b/packages/SystemUI/res/values-as/strings.xml
@@ -1067,6 +1067,4 @@
<string name="controls_added_tooltip" msgid="4842812921719153085">"নতুন নিয়ন্ত্ৰণসমূহ চাবলৈ পাৱাৰৰ বুটামটো ধৰি ৰাখক"</string>
<string name="controls_menu_add" msgid="4447246119229920050">"নিয়ন্ত্ৰণসমূহ যোগ দিয়ক"</string>
<string name="controls_menu_edit" msgid="890623986951347062">"নিয়ন্ত্ৰণসমূহ সম্পাদনা কৰক"</string>
- <string name="one_handed_tutorial_title" msgid="6312198435090726656">"এখন হাতেৰে ব্যৱহাৰ কৰা ম’ড ব্যৱহাৰ কৰিবলৈ"</string>
- <string name="one_handed_tutorial_description" msgid="7674850272340517174">"বাহিৰ হ’বলৈ স্ক্রীনখনৰ একেবাৰে তলৰ পৰা ওপৰলৈ ছোৱাইপ কৰক অথবা এপ্‌টোৰ ওপৰত যিকোনো ঠাইত টিপক"</string>
</resources>
diff --git a/packages/SystemUI/res/values-az/strings.xml b/packages/SystemUI/res/values-az/strings.xml
index b5960668e8fe..83af4623b54c 100644
--- a/packages/SystemUI/res/values-az/strings.xml
+++ b/packages/SystemUI/res/values-az/strings.xml
@@ -1067,6 +1067,4 @@
<string name="controls_added_tooltip" msgid="4842812921719153085">"Yeni nizamlayıcıları görmək üçün yandırıb-söndürmə düyməsinə basıb saxlayın"</string>
<string name="controls_menu_add" msgid="4447246119229920050">"Nizamlayıcılar əlavə edin"</string>
<string name="controls_menu_edit" msgid="890623986951347062">"Nizamlayıcıları redaktə edin"</string>
- <string name="one_handed_tutorial_title" msgid="6312198435090726656">"Bir əlli rejimdən istifadə edilir"</string>
- <string name="one_handed_tutorial_description" msgid="7674850272340517174">"Çıxmaq üçün ekranın aşağısından yuxarıya doğru sürüşdürün və ya tətbiqin yuxarısında istənilən yerə toxunun"</string>
</resources>
diff --git a/packages/SystemUI/res/values-b+sr+Latn/strings.xml b/packages/SystemUI/res/values-b+sr+Latn/strings.xml
index aa141e637932..ce7b6077129f 100644
--- a/packages/SystemUI/res/values-b+sr+Latn/strings.xml
+++ b/packages/SystemUI/res/values-b+sr+Latn/strings.xml
@@ -1073,6 +1073,4 @@
<string name="controls_added_tooltip" msgid="4842812921719153085">"Zadržite dugme za uključivanje da biste videli nove kontrole"</string>
<string name="controls_menu_add" msgid="4447246119229920050">"Dodaj kontrole"</string>
<string name="controls_menu_edit" msgid="890623986951347062">"Izmeni kontrole"</string>
- <string name="one_handed_tutorial_title" msgid="6312198435090726656">"Korišćenje režima jednom rukom"</string>
- <string name="one_handed_tutorial_description" msgid="7674850272340517174">"Da biste izašli, prevucite nagore od dna ekrana ili dodirnite bilo gde iznad aplikacije"</string>
</resources>
diff --git a/packages/SystemUI/res/values-be/strings.xml b/packages/SystemUI/res/values-be/strings.xml
index 194f92b633e4..f1fc8f565a3b 100644
--- a/packages/SystemUI/res/values-be/strings.xml
+++ b/packages/SystemUI/res/values-be/strings.xml
@@ -1079,6 +1079,4 @@
<string name="controls_added_tooltip" msgid="4842812921719153085">"Каб убачыць новыя элементы кіравання, утрымлівайце кнопку сілкавання націснутай"</string>
<string name="controls_menu_add" msgid="4447246119229920050">"Дадаць элементы кіравання"</string>
<string name="controls_menu_edit" msgid="890623986951347062">"Змяніць элементы кіравання"</string>
- <string name="one_handed_tutorial_title" msgid="6312198435090726656">"Выкарыстоўваецца рэжым кіравання адной рукой"</string>
- <string name="one_handed_tutorial_description" msgid="7674850272340517174">"Каб выйсці, правядзіце па экране пальцам знізу ўверх або націсніце ў любым месцы над праграмай"</string>
</resources>
diff --git a/packages/SystemUI/res/values-bg/strings.xml b/packages/SystemUI/res/values-bg/strings.xml
index 02eea8abe4dd..1678abadfeff 100644
--- a/packages/SystemUI/res/values-bg/strings.xml
+++ b/packages/SystemUI/res/values-bg/strings.xml
@@ -1067,6 +1067,4 @@
<string name="controls_added_tooltip" msgid="4842812921719153085">"Задръжте бутона за захранване, за да видите новите контроли"</string>
<string name="controls_menu_add" msgid="4447246119229920050">"Добавяне на контроли"</string>
<string name="controls_menu_edit" msgid="890623986951347062">"Редактиране на контролите"</string>
- <string name="one_handed_tutorial_title" msgid="6312198435090726656">"Използване на режима за работа с една ръка"</string>
- <string name="one_handed_tutorial_description" msgid="7674850272340517174">"За изход прекарайте пръст нагоре от долната част на екрана или докоснете произволно място над приложението"</string>
</resources>
diff --git a/packages/SystemUI/res/values-bn/strings.xml b/packages/SystemUI/res/values-bn/strings.xml
index 96a7368b1dfd..9d5415fe5af1 100644
--- a/packages/SystemUI/res/values-bn/strings.xml
+++ b/packages/SystemUI/res/values-bn/strings.xml
@@ -1067,6 +1067,4 @@
<string name="controls_added_tooltip" msgid="4842812921719153085">"নতুন কন্ট্রোল দেখতে পাওয়ার বোতাম টিপে ধরে থাকুন"</string>
<string name="controls_menu_add" msgid="4447246119229920050">"কন্ট্রোল যোগ করুন"</string>
<string name="controls_menu_edit" msgid="890623986951347062">"কন্ট্রোল এডিট করুন"</string>
- <string name="one_handed_tutorial_title" msgid="6312198435090726656">"\'এক হাতে ব্যবহার করার মোড\'-এর ব্যবহার"</string>
- <string name="one_handed_tutorial_description" msgid="7674850272340517174">"বেরিয়ে আসার জন্য, স্ক্রিনের নিচ থেকে উপরের দিকে সোয়াইপ করুন অথবা অ্যাপের আইকনের উপরে যেকোনও জায়গায় ট্যাপ করুন"</string>
</resources>
diff --git a/packages/SystemUI/res/values-bs/strings.xml b/packages/SystemUI/res/values-bs/strings.xml
index 0a091aae70b9..819bfcf58674 100644
--- a/packages/SystemUI/res/values-bs/strings.xml
+++ b/packages/SystemUI/res/values-bs/strings.xml
@@ -1073,6 +1073,4 @@
<string name="controls_added_tooltip" msgid="4842812921719153085">"Zadržite dugme za uključivanje da vidite nove kontrole"</string>
<string name="controls_menu_add" msgid="4447246119229920050">"Dodaj kontrole"</string>
<string name="controls_menu_edit" msgid="890623986951347062">"Uredi kontrole"</string>
- <string name="one_handed_tutorial_title" msgid="6312198435090726656">"Korištenje načina rada jednom rukom"</string>
- <string name="one_handed_tutorial_description" msgid="7674850272340517174">"Da izađete, prevucite s dna ekrana prema gore ili dodirnite bilo gdje iznad aplikacije"</string>
</resources>
diff --git a/packages/SystemUI/res/values-ca/strings.xml b/packages/SystemUI/res/values-ca/strings.xml
index d4e8befe3f4d..a7aff9850a6b 100644
--- a/packages/SystemUI/res/values-ca/strings.xml
+++ b/packages/SystemUI/res/values-ca/strings.xml
@@ -1067,6 +1067,4 @@
<string name="controls_added_tooltip" msgid="4842812921719153085">"Mantén premut el botó d\'engegada per veure controls nous"</string>
<string name="controls_menu_add" msgid="4447246119229920050">"Afegeix controls"</string>
<string name="controls_menu_edit" msgid="890623986951347062">"Edita els controls"</string>
- <string name="one_handed_tutorial_title" msgid="6312198435090726656">"S\'està utilitzant el mode d\'una mà"</string>
- <string name="one_handed_tutorial_description" msgid="7674850272340517174">"Per sortir, llisca cap amunt des de la part inferior de la pantalla o toca qualsevol lloc a sobre de l\'aplicació"</string>
</resources>
diff --git a/packages/SystemUI/res/values-cs/strings.xml b/packages/SystemUI/res/values-cs/strings.xml
index 239a0f6b3d53..44864f0e8141 100644
--- a/packages/SystemUI/res/values-cs/strings.xml
+++ b/packages/SystemUI/res/values-cs/strings.xml
@@ -1079,6 +1079,4 @@
<string name="controls_added_tooltip" msgid="4842812921719153085">"Nové ovládací prvky zobrazíte podržením vypínače"</string>
<string name="controls_menu_add" msgid="4447246119229920050">"Přidat ovládací prvky"</string>
<string name="controls_menu_edit" msgid="890623986951347062">"Upravit ovládací prvky"</string>
- <string name="one_handed_tutorial_title" msgid="6312198435090726656">"Používáte režim jedné ruky"</string>
- <string name="one_handed_tutorial_description" msgid="7674850272340517174">"Režim ukončíte, když přejedete prstem z dolní části obrazovky nahoru nebo klepnete kamkoli nad aplikaci"</string>
</resources>
diff --git a/packages/SystemUI/res/values-da/strings.xml b/packages/SystemUI/res/values-da/strings.xml
index 7ce60ea1536a..b6702126323d 100644
--- a/packages/SystemUI/res/values-da/strings.xml
+++ b/packages/SystemUI/res/values-da/strings.xml
@@ -1067,6 +1067,4 @@
<string name="controls_added_tooltip" msgid="4842812921719153085">"Hold afbryderknappen nede for at se nye betjeningselementer"</string>
<string name="controls_menu_add" msgid="4447246119229920050">"Tilføj styring"</string>
<string name="controls_menu_edit" msgid="890623986951347062">"Rediger styring"</string>
- <string name="one_handed_tutorial_title" msgid="6312198435090726656">"Brug af enhåndstilstand"</string>
- <string name="one_handed_tutorial_description" msgid="7674850272340517174">"Du kan afslutte ved at stryge opad fra bunden af skærmen eller trykke et vilkårligt sted over appen"</string>
</resources>
diff --git a/packages/SystemUI/res/values-de/strings.xml b/packages/SystemUI/res/values-de/strings.xml
index 093e1a20ca97..af8d22ea4cd0 100644
--- a/packages/SystemUI/res/values-de/strings.xml
+++ b/packages/SystemUI/res/values-de/strings.xml
@@ -1067,6 +1067,4 @@
<string name="controls_added_tooltip" msgid="4842812921719153085">"Zum Anzeigen der Karten für neue Geräte Ein-/Aus-Taste gedrückt halten"</string>
<string name="controls_menu_add" msgid="4447246119229920050">"Steuerelemente hinzufügen"</string>
<string name="controls_menu_edit" msgid="890623986951347062">"Steuerelemente bearbeiten"</string>
- <string name="one_handed_tutorial_title" msgid="6312198435090726656">"Einhandmodus verwenden"</string>
- <string name="one_handed_tutorial_description" msgid="7674850272340517174">"Wenn du die App schließen möchtest, wische vom unteren Rand des Displays nach oben oder tippe auf eine beliebige Stelle oberhalb der App"</string>
</resources>
diff --git a/packages/SystemUI/res/values-el/strings.xml b/packages/SystemUI/res/values-el/strings.xml
index ac1a3ee4601e..951f01d54bdf 100644
--- a/packages/SystemUI/res/values-el/strings.xml
+++ b/packages/SystemUI/res/values-el/strings.xml
@@ -1067,6 +1067,4 @@
<string name="controls_added_tooltip" msgid="4842812921719153085">"Πατήστε το κουμπί λειτουργίας για να δείτε νέα στοιχεία ελέγχου."</string>
<string name="controls_menu_add" msgid="4447246119229920050">"Προσθήκη στοιχείων ελέγχου"</string>
<string name="controls_menu_edit" msgid="890623986951347062">"Επεξεργασία στοιχείων ελέγχου"</string>
- <string name="one_handed_tutorial_title" msgid="6312198435090726656">"Χρήση λειτουργίας ενός χεριού"</string>
- <string name="one_handed_tutorial_description" msgid="7674850272340517174">"Για έξοδο, σύρετε προς τα πάνω από το κάτω μέρος της οθόνης ή πατήστε οπουδήποτε πάνω από την εφαρμογή."</string>
</resources>
diff --git a/packages/SystemUI/res/values-en-rAU/strings.xml b/packages/SystemUI/res/values-en-rAU/strings.xml
index 3a76d75ac043..debbd834f98d 100644
--- a/packages/SystemUI/res/values-en-rAU/strings.xml
+++ b/packages/SystemUI/res/values-en-rAU/strings.xml
@@ -1067,6 +1067,4 @@
<string name="controls_added_tooltip" msgid="4842812921719153085">"Hold Power button to see new controls"</string>
<string name="controls_menu_add" msgid="4447246119229920050">"Add controls"</string>
<string name="controls_menu_edit" msgid="890623986951347062">"Edit controls"</string>
- <string name="one_handed_tutorial_title" msgid="6312198435090726656">"Using one-handed mode"</string>
- <string name="one_handed_tutorial_description" msgid="7674850272340517174">"To exit, swipe up from the bottom of the screen or tap anywhere above the app"</string>
</resources>
diff --git a/packages/SystemUI/res/values-en-rCA/strings.xml b/packages/SystemUI/res/values-en-rCA/strings.xml
index ac6519394268..b7ad5977e78f 100644
--- a/packages/SystemUI/res/values-en-rCA/strings.xml
+++ b/packages/SystemUI/res/values-en-rCA/strings.xml
@@ -1067,6 +1067,4 @@
<string name="controls_added_tooltip" msgid="4842812921719153085">"Hold Power button to see new controls"</string>
<string name="controls_menu_add" msgid="4447246119229920050">"Add controls"</string>
<string name="controls_menu_edit" msgid="890623986951347062">"Edit controls"</string>
- <string name="one_handed_tutorial_title" msgid="6312198435090726656">"Using one-handed mode"</string>
- <string name="one_handed_tutorial_description" msgid="7674850272340517174">"To exit, swipe up from the bottom of the screen or tap anywhere above the app"</string>
</resources>
diff --git a/packages/SystemUI/res/values-en-rGB/strings.xml b/packages/SystemUI/res/values-en-rGB/strings.xml
index 3a76d75ac043..debbd834f98d 100644
--- a/packages/SystemUI/res/values-en-rGB/strings.xml
+++ b/packages/SystemUI/res/values-en-rGB/strings.xml
@@ -1067,6 +1067,4 @@
<string name="controls_added_tooltip" msgid="4842812921719153085">"Hold Power button to see new controls"</string>
<string name="controls_menu_add" msgid="4447246119229920050">"Add controls"</string>
<string name="controls_menu_edit" msgid="890623986951347062">"Edit controls"</string>
- <string name="one_handed_tutorial_title" msgid="6312198435090726656">"Using one-handed mode"</string>
- <string name="one_handed_tutorial_description" msgid="7674850272340517174">"To exit, swipe up from the bottom of the screen or tap anywhere above the app"</string>
</resources>
diff --git a/packages/SystemUI/res/values-en-rIN/strings.xml b/packages/SystemUI/res/values-en-rIN/strings.xml
index 3a76d75ac043..debbd834f98d 100644
--- a/packages/SystemUI/res/values-en-rIN/strings.xml
+++ b/packages/SystemUI/res/values-en-rIN/strings.xml
@@ -1067,6 +1067,4 @@
<string name="controls_added_tooltip" msgid="4842812921719153085">"Hold Power button to see new controls"</string>
<string name="controls_menu_add" msgid="4447246119229920050">"Add controls"</string>
<string name="controls_menu_edit" msgid="890623986951347062">"Edit controls"</string>
- <string name="one_handed_tutorial_title" msgid="6312198435090726656">"Using one-handed mode"</string>
- <string name="one_handed_tutorial_description" msgid="7674850272340517174">"To exit, swipe up from the bottom of the screen or tap anywhere above the app"</string>
</resources>
diff --git a/packages/SystemUI/res/values-en-rXC/strings.xml b/packages/SystemUI/res/values-en-rXC/strings.xml
index 0a36daef1603..c76dc72714de 100644
--- a/packages/SystemUI/res/values-en-rXC/strings.xml
+++ b/packages/SystemUI/res/values-en-rXC/strings.xml
@@ -1067,8 +1067,4 @@
<string name="controls_added_tooltip" msgid="4842812921719153085">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‎‎‎‎‏‏‎‎‏‏‎‏‎‏‎‎‏‎‎‎‎‎‏‎‏‏‎‎‎‏‏‎‏‎‏‎‎‎‏‎‏‏‏‏‎‏‏‏‏‎‎‎‎‏‏‎‏‏‏‏‎‏‎Hold Power button to see new controls‎‏‎‎‏‎"</string>
<string name="controls_menu_add" msgid="4447246119229920050">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‎‏‏‏‏‎‏‏‎‏‏‎‏‏‏‏‏‎‎‏‎‏‎‏‏‎‎‏‎‎‎‎‏‏‎‏‏‎‏‎‏‏‎‏‏‏‏‎‎‎‏‎‎‏‏‎‎‏‏‎‎‏‎‎Add controls‎‏‎‎‏‎"</string>
<string name="controls_menu_edit" msgid="890623986951347062">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‎‎‏‏‎‎‎‏‎‏‏‏‎‎‎‎‏‎‎‎‎‏‏‏‎‎‏‏‎‎‎‎‏‎‎‎‏‎‏‎‏‎‏‏‎‏‎‏‎‏‏‎‏‏‎‏‏‏‎‏‏‎‎Edit controls‎‏‎‎‏‎"</string>
- <!-- no translation found for one_handed_tutorial_title (6312198435090726656) -->
- <skip />
- <!-- no translation found for one_handed_tutorial_description (7674850272340517174) -->
- <skip />
</resources>
diff --git a/packages/SystemUI/res/values-es-rUS/strings.xml b/packages/SystemUI/res/values-es-rUS/strings.xml
index ccc46266f7fe..1ef965d22748 100644
--- a/packages/SystemUI/res/values-es-rUS/strings.xml
+++ b/packages/SystemUI/res/values-es-rUS/strings.xml
@@ -1067,6 +1067,4 @@
<string name="controls_added_tooltip" msgid="4842812921719153085">"Mantén presionado el botón de encendido para ver los nuevos controles"</string>
<string name="controls_menu_add" msgid="4447246119229920050">"Agregar controles"</string>
<string name="controls_menu_edit" msgid="890623986951347062">"Editar controles"</string>
- <string name="one_handed_tutorial_title" msgid="6312198435090726656">"Cómo usar el Modo de una mano"</string>
- <string name="one_handed_tutorial_description" msgid="7674850272340517174">"Para salir, desliza el dedo hacia arriba desde la parte inferior de la pantalla o presiona cualquier parte arriba de la app"</string>
</resources>
diff --git a/packages/SystemUI/res/values-es/strings.xml b/packages/SystemUI/res/values-es/strings.xml
index 79c2fbd357ae..e483c0e1ac6d 100644
--- a/packages/SystemUI/res/values-es/strings.xml
+++ b/packages/SystemUI/res/values-es/strings.xml
@@ -1067,6 +1067,4 @@
<string name="controls_added_tooltip" msgid="4842812921719153085">"Mantén pulsado el botón de encendido para ver los controles nuevos"</string>
<string name="controls_menu_add" msgid="4447246119229920050">"Añadir controles"</string>
<string name="controls_menu_edit" msgid="890623986951347062">"Editar controles"</string>
- <string name="one_handed_tutorial_title" msgid="6312198435090726656">"Utilizar el modo una mano"</string>
- <string name="one_handed_tutorial_description" msgid="7674850272340517174">"Para salir, desliza dos dedos hacia arriba desde la parte inferior de la pantalla o toca cualquier zona que haya encima de la aplicación."</string>
</resources>
diff --git a/packages/SystemUI/res/values-et/strings.xml b/packages/SystemUI/res/values-et/strings.xml
index 21189f1ea5f6..fea0df62e625 100644
--- a/packages/SystemUI/res/values-et/strings.xml
+++ b/packages/SystemUI/res/values-et/strings.xml
@@ -1067,6 +1067,4 @@
<string name="controls_added_tooltip" msgid="4842812921719153085">"Uute juhtelementide vaatamiseks hoidke all toitenuppu"</string>
<string name="controls_menu_add" msgid="4447246119229920050">"Lisa juhtelemente"</string>
<string name="controls_menu_edit" msgid="890623986951347062">"Muuda juhtelemente"</string>
- <string name="one_handed_tutorial_title" msgid="6312198435090726656">"Ühekäerežiimi kasutamine"</string>
- <string name="one_handed_tutorial_description" msgid="7674850272340517174">"Väljumiseks pühkige ekraani alaosast üles või puudutage ekraani rakenduse kohal"</string>
</resources>
diff --git a/packages/SystemUI/res/values-eu/strings.xml b/packages/SystemUI/res/values-eu/strings.xml
index 8a372361daac..297472a66325 100644
--- a/packages/SystemUI/res/values-eu/strings.xml
+++ b/packages/SystemUI/res/values-eu/strings.xml
@@ -1067,6 +1067,4 @@
<string name="controls_added_tooltip" msgid="4842812921719153085">"Eduki sakatuta etengailua kontrolatzeko aukera berriak ikusteko"</string>
<string name="controls_menu_add" msgid="4447246119229920050">"Gehitu aukerak"</string>
<string name="controls_menu_edit" msgid="890623986951347062">"Editatu aukerak"</string>
- <string name="one_handed_tutorial_title" msgid="6312198435090726656">"Esku bakarreko modua erabiltzea"</string>
- <string name="one_handed_tutorial_description" msgid="7674850272340517174">"Ateratzeko, pasatu hatza pantailaren behealdetik gora edo sakatu aplikazioaren gainaldea"</string>
</resources>
diff --git a/packages/SystemUI/res/values-fa/strings.xml b/packages/SystemUI/res/values-fa/strings.xml
index 7f85959af7aa..2c32225d5ec2 100644
--- a/packages/SystemUI/res/values-fa/strings.xml
+++ b/packages/SystemUI/res/values-fa/strings.xml
@@ -1067,6 +1067,4 @@
<string name="controls_added_tooltip" msgid="4842812921719153085">"برای دیدن کنترل‌های جدید، دکمه روشن/خاموش را پایین نگه دارید"</string>
<string name="controls_menu_add" msgid="4447246119229920050">"افزودن کنترل‌ها"</string>
<string name="controls_menu_edit" msgid="890623986951347062">"ویرایش کنترل‌ها"</string>
- <string name="one_handed_tutorial_title" msgid="6312198435090726656">"استفاده از «حالت تک حرکت»"</string>
- <string name="one_handed_tutorial_description" msgid="7674850272340517174">"برای خارج شدن، از پایین صفحه‌نمایش تند به‌طرف بالا بکشید یا در هر جایی از بالای برنامه که می‌خواهید ضربه بزنید"</string>
</resources>
diff --git a/packages/SystemUI/res/values-fi/strings.xml b/packages/SystemUI/res/values-fi/strings.xml
index fd9bbd94625c..b6c4ba0c2578 100644
--- a/packages/SystemUI/res/values-fi/strings.xml
+++ b/packages/SystemUI/res/values-fi/strings.xml
@@ -1067,6 +1067,4 @@
<string name="controls_added_tooltip" msgid="4842812921719153085">"Paina virtapainiketta pitkään nähdäksesi uudet säätimet"</string>
<string name="controls_menu_add" msgid="4447246119229920050">"Lisää säätimiä"</string>
<string name="controls_menu_edit" msgid="890623986951347062">"Muokkaa säätimiä"</string>
- <string name="one_handed_tutorial_title" msgid="6312198435090726656">"Yhden käden moodin käyttö"</string>
- <string name="one_handed_tutorial_description" msgid="7674850272340517174">"Poistu pyyhkäisemällä ylös näytön alareunasta tai napauttamalla sovelluksen yllä"</string>
</resources>
diff --git a/packages/SystemUI/res/values-fr-rCA/strings.xml b/packages/SystemUI/res/values-fr-rCA/strings.xml
index 8817cebdcf4d..34391efe460d 100644
--- a/packages/SystemUI/res/values-fr-rCA/strings.xml
+++ b/packages/SystemUI/res/values-fr-rCA/strings.xml
@@ -1067,6 +1067,4 @@
<string name="controls_added_tooltip" msgid="4842812921719153085">"Maintenez enfoncé l\'interrupteur pour afficher les nouvelles commandes"</string>
<string name="controls_menu_add" msgid="4447246119229920050">"Ajouter des commandes"</string>
<string name="controls_menu_edit" msgid="890623986951347062">"Modifier des commandes"</string>
- <string name="one_handed_tutorial_title" msgid="6312198435090726656">"Utiliser le mode Une main"</string>
- <string name="one_handed_tutorial_description" msgid="7674850272340517174">"Pour quitter, balayez l\'écran du bas vers le haut, ou touchez n\'importe où sur l\'écran en haut de l\'application"</string>
</resources>
diff --git a/packages/SystemUI/res/values-fr/strings.xml b/packages/SystemUI/res/values-fr/strings.xml
index 35176c79f987..ebd9b9b9f40c 100644
--- a/packages/SystemUI/res/values-fr/strings.xml
+++ b/packages/SystemUI/res/values-fr/strings.xml
@@ -1067,6 +1067,4 @@
<string name="controls_added_tooltip" msgid="4842812921719153085">"Appuyez de manière prolongée sur le bouton Marche/Arrêt pour afficher les nouvelles commandes"</string>
<string name="controls_menu_add" msgid="4447246119229920050">"Ajouter des commandes"</string>
<string name="controls_menu_edit" msgid="890623986951347062">"Modifier des commandes"</string>
- <string name="one_handed_tutorial_title" msgid="6312198435090726656">"Utiliser le mode une main"</string>
- <string name="one_handed_tutorial_description" msgid="7674850272340517174">"Pour quitter, balayez l\'écran de bas en haut ou appuyez n\'importe où au-dessus de l\'application"</string>
</resources>
diff --git a/packages/SystemUI/res/values-gl/strings.xml b/packages/SystemUI/res/values-gl/strings.xml
index 7c6279894069..79795927c1af 100644
--- a/packages/SystemUI/res/values-gl/strings.xml
+++ b/packages/SystemUI/res/values-gl/strings.xml
@@ -792,7 +792,7 @@
<string name="keyboard_key_media_stop" msgid="1509943745250377699">"Deter"</string>
<string name="keyboard_key_media_next" msgid="8502476691227914952">"Seguinte"</string>
<string name="keyboard_key_media_previous" msgid="5637875709190955351">"Anterior"</string>
- <string name="keyboard_key_media_rewind" msgid="3450387734224327577">"Rebobinar"</string>
+ <string name="keyboard_key_media_rewind" msgid="3450387734224327577">"Retroceder"</string>
<string name="keyboard_key_media_fast_forward" msgid="3572444327046911822">"Avance rápido"</string>
<string name="keyboard_key_page_up" msgid="173914303254199845">"Re Páx"</string>
<string name="keyboard_key_page_down" msgid="9035902490071829731">"Av Páx"</string>
@@ -1067,6 +1067,4 @@
<string name="controls_added_tooltip" msgid="4842812921719153085">"Mantén premido o botón de acendido para ver os novos controis"</string>
<string name="controls_menu_add" msgid="4447246119229920050">"Engadir controis"</string>
<string name="controls_menu_edit" msgid="890623986951347062">"Editar controis"</string>
- <string name="one_handed_tutorial_title" msgid="6312198435090726656">"Como se usa o modo dunha soa man?"</string>
- <string name="one_handed_tutorial_description" msgid="7674850272340517174">"Para saír, pasa o dedo cara arriba desde a parte inferior da pantalla ou toca calquera lugar da zona situada encima da aplicación"</string>
</resources>
diff --git a/packages/SystemUI/res/values-gu/strings.xml b/packages/SystemUI/res/values-gu/strings.xml
index af0d7d3e1b10..9599ca868365 100644
--- a/packages/SystemUI/res/values-gu/strings.xml
+++ b/packages/SystemUI/res/values-gu/strings.xml
@@ -1067,6 +1067,4 @@
<string name="controls_added_tooltip" msgid="4842812921719153085">"નવા નિયંત્રણ જોવા માટે પાવર બટનને દબાવી રાખો"</string>
<string name="controls_menu_add" msgid="4447246119229920050">"નિયંત્રણો ઉમેરો"</string>
<string name="controls_menu_edit" msgid="890623986951347062">"નિયંત્રણોમાં ફેરફાર કરો"</string>
- <string name="one_handed_tutorial_title" msgid="6312198435090726656">"એક-હાથે વાપરો મોડનો ઉપયોગ કરી રહ્યાં છીએ"</string>
- <string name="one_handed_tutorial_description" msgid="7674850272340517174">"બહાર નીકળવા માટે, સ્ક્રીનની નીચેના ભાગથી ઉપરની તરફ સ્વાઇપ કરો અથવા ઍપના આઇકન પર ગમે ત્યાં ટૅપ કરો"</string>
</resources>
diff --git a/packages/SystemUI/res/values-hi/strings.xml b/packages/SystemUI/res/values-hi/strings.xml
index 0a7515d03a65..f3a7ec1c0cca 100644
--- a/packages/SystemUI/res/values-hi/strings.xml
+++ b/packages/SystemUI/res/values-hi/strings.xml
@@ -1069,6 +1069,4 @@
<string name="controls_added_tooltip" msgid="4842812921719153085">"नए कंट्रोल देखने के लिए पावर बटन दबाकर रखें"</string>
<string name="controls_menu_add" msgid="4447246119229920050">"कंट्राेल जोड़ें"</string>
<string name="controls_menu_edit" msgid="890623986951347062">"कंट्रोल मेन्यू में बदलाव करें"</string>
- <string name="one_handed_tutorial_title" msgid="6312198435090726656">"वन-हैंडेड मोड का इस्तेमाल करना"</string>
- <string name="one_handed_tutorial_description" msgid="7674850272340517174">"इसे बंद करने के लिए, स्क्रीन के सबसे निचले हिस्से से ऊपर की ओर स्वाइप करें या ऐप्लिकेशन के आइकॉन के ऊपर कहीं भी टैप करें"</string>
</resources>
diff --git a/packages/SystemUI/res/values-hr/strings.xml b/packages/SystemUI/res/values-hr/strings.xml
index 27b6909159aa..870ca49add60 100644
--- a/packages/SystemUI/res/values-hr/strings.xml
+++ b/packages/SystemUI/res/values-hr/strings.xml
@@ -1073,6 +1073,4 @@
<string name="controls_added_tooltip" msgid="4842812921719153085">"Zadržite tipku za uključivanje/isključivanje za prikaz novih kontrola"</string>
<string name="controls_menu_add" msgid="4447246119229920050">"Dodaj kontrole"</string>
<string name="controls_menu_edit" msgid="890623986951347062">"Uredi kontrole"</string>
- <string name="one_handed_tutorial_title" msgid="6312198435090726656">"Korištenje načina rada jednom rukom"</string>
- <string name="one_handed_tutorial_description" msgid="7674850272340517174">"Za izlaz prijeđite prstom od dna zaslona prema gore ili dodirnite bio gdje iznad aplikacije"</string>
</resources>
diff --git a/packages/SystemUI/res/values-hu/strings.xml b/packages/SystemUI/res/values-hu/strings.xml
index 1f52b2cbe78b..f88076f54b22 100644
--- a/packages/SystemUI/res/values-hu/strings.xml
+++ b/packages/SystemUI/res/values-hu/strings.xml
@@ -1067,6 +1067,4 @@
<string name="controls_added_tooltip" msgid="4842812921719153085">"Az új vezérlők megtekintéséhez tartsa nyomva a bekapcsológombot"</string>
<string name="controls_menu_add" msgid="4447246119229920050">"Vezérlők hozzáadása"</string>
<string name="controls_menu_edit" msgid="890623986951347062">"Vezérlők szerkesztése"</string>
- <string name="one_handed_tutorial_title" msgid="6312198435090726656">"Egykezes mód használata"</string>
- <string name="one_handed_tutorial_description" msgid="7674850272340517174">"A kilépéshez csúsztasson felfelé a képernyő aljáról, vagy koppintson az alkalmazás felett a képernyő bármelyik részére"</string>
</resources>
diff --git a/packages/SystemUI/res/values-hy/strings.xml b/packages/SystemUI/res/values-hy/strings.xml
index d4a093f78659..04c2bb1a5237 100644
--- a/packages/SystemUI/res/values-hy/strings.xml
+++ b/packages/SystemUI/res/values-hy/strings.xml
@@ -1067,6 +1067,4 @@
<string name="controls_added_tooltip" msgid="4842812921719153085">"Սեղմած պահեք սնուցման կոճակը՝ կառավարման նոր տարրերը տեսնելու համար։"</string>
<string name="controls_menu_add" msgid="4447246119229920050">"Ավելացնել կառավարման տարրեր"</string>
<string name="controls_menu_edit" msgid="890623986951347062">"Փոփոխել կառավարման տարրերը"</string>
- <string name="one_handed_tutorial_title" msgid="6312198435090726656">"Ինչպես օգտվել մեկ ձեռքի ռեժիմից"</string>
- <string name="one_handed_tutorial_description" msgid="7674850272340517174">"Դուրս գալու համար մատը սահեցրեք էկրանի ներքևից վերև կամ հպեք հավելվածի վերևում որևէ տեղ։"</string>
</resources>
diff --git a/packages/SystemUI/res/values-in/strings.xml b/packages/SystemUI/res/values-in/strings.xml
index 3b89b3d5e9fc..403af01642dd 100644
--- a/packages/SystemUI/res/values-in/strings.xml
+++ b/packages/SystemUI/res/values-in/strings.xml
@@ -1067,6 +1067,4 @@
<string name="controls_added_tooltip" msgid="4842812921719153085">"Tahan Tombol daya untuk melihat kontrol baru"</string>
<string name="controls_menu_add" msgid="4447246119229920050">"Tambahkan kontrol"</string>
<string name="controls_menu_edit" msgid="890623986951347062">"Edit kontrol"</string>
- <string name="one_handed_tutorial_title" msgid="6312198435090726656">"Menggunakan mode satu tangan"</string>
- <string name="one_handed_tutorial_description" msgid="7674850272340517174">"Untuk keluar, geser layar dari bawah ke atas atau ketuk di mana saja di atas aplikasi"</string>
</resources>
diff --git a/packages/SystemUI/res/values-is/strings.xml b/packages/SystemUI/res/values-is/strings.xml
index da8a092bcc47..a1c4a7f651c7 100644
--- a/packages/SystemUI/res/values-is/strings.xml
+++ b/packages/SystemUI/res/values-is/strings.xml
@@ -1067,6 +1067,4 @@
<string name="controls_added_tooltip" msgid="4842812921719153085">"Haltu aflrofanum inni til að sjá nýjar stýringar"</string>
<string name="controls_menu_add" msgid="4447246119229920050">"Bæta við stýringum"</string>
<string name="controls_menu_edit" msgid="890623986951347062">"Breyta stýringum"</string>
- <string name="one_handed_tutorial_title" msgid="6312198435090726656">"Notkun stillingar fyrir eina hönd"</string>
- <string name="one_handed_tutorial_description" msgid="7674850272340517174">"Til að loka skaltu strjúka upp frá neðri hluta skjásins eða ýta hvar sem er fyrir ofan forritið"</string>
</resources>
diff --git a/packages/SystemUI/res/values-it/strings.xml b/packages/SystemUI/res/values-it/strings.xml
index 0ec9c236f761..be017e11330a 100644
--- a/packages/SystemUI/res/values-it/strings.xml
+++ b/packages/SystemUI/res/values-it/strings.xml
@@ -1067,6 +1067,4 @@
<string name="controls_added_tooltip" msgid="4842812921719153085">"Tieni premuto il tasto di accensione per visualizzare i nuovi controlli"</string>
<string name="controls_menu_add" msgid="4447246119229920050">"Aggiungi controlli"</string>
<string name="controls_menu_edit" msgid="890623986951347062">"Modifica controlli"</string>
- <string name="one_handed_tutorial_title" msgid="6312198435090726656">"Usare la modalità one-hand"</string>
- <string name="one_handed_tutorial_description" msgid="7674850272340517174">"Per uscire, scorri verso l\'alto dalla parte inferiore dello schermo oppure tocca un punto qualsiasi sopra l\'app"</string>
</resources>
diff --git a/packages/SystemUI/res/values-iw/strings.xml b/packages/SystemUI/res/values-iw/strings.xml
index 193c5f61fe3e..1baa627c5a7d 100644
--- a/packages/SystemUI/res/values-iw/strings.xml
+++ b/packages/SystemUI/res/values-iw/strings.xml
@@ -1079,6 +1079,4 @@
<string name="controls_added_tooltip" msgid="4842812921719153085">"ניתן ללחוץ על לחצן ההפעלה כדי להציג פקדים חדשים"</string>
<string name="controls_menu_add" msgid="4447246119229920050">"הוספת פקדים"</string>
<string name="controls_menu_edit" msgid="890623986951347062">"עריכת פקדים"</string>
- <string name="one_handed_tutorial_title" msgid="6312198435090726656">"איך להשתמש במצב שימוש ביד אחת"</string>
- <string name="one_handed_tutorial_description" msgid="7674850272340517174">"כדי לצאת, יש להחליק למעלה מתחתית המסך או להקיש במקום כלשהו במסך מעל האפליקציה"</string>
</resources>
diff --git a/packages/SystemUI/res/values-ja/strings.xml b/packages/SystemUI/res/values-ja/strings.xml
index 9aa9e76c1597..fd1aa57f39d9 100644
--- a/packages/SystemUI/res/values-ja/strings.xml
+++ b/packages/SystemUI/res/values-ja/strings.xml
@@ -1067,6 +1067,4 @@
<string name="controls_added_tooltip" msgid="4842812921719153085">"電源ボタンを長押しすると、新しいコントロールが表示されます"</string>
<string name="controls_menu_add" msgid="4447246119229920050">"コントロールを追加"</string>
<string name="controls_menu_edit" msgid="890623986951347062">"コントロールを編集"</string>
- <string name="one_handed_tutorial_title" msgid="6312198435090726656">"片手モードの使用"</string>
- <string name="one_handed_tutorial_description" msgid="7674850272340517174">"終了するには、画面を下から上にスワイプするか、アプリの任意の場所をタップします"</string>
</resources>
diff --git a/packages/SystemUI/res/values-ka/strings.xml b/packages/SystemUI/res/values-ka/strings.xml
index aa6f35d00826..86451b8da7a5 100644
--- a/packages/SystemUI/res/values-ka/strings.xml
+++ b/packages/SystemUI/res/values-ka/strings.xml
@@ -1067,6 +1067,4 @@
<string name="controls_added_tooltip" msgid="4842812921719153085">"ხანგრძლივად დააჭირეთ ჩართვის ღილაკს მართვის ახალი საშუალებების სანახავად"</string>
<string name="controls_menu_add" msgid="4447246119229920050">"მართვის საშუალებების დამატება"</string>
<string name="controls_menu_edit" msgid="890623986951347062">"მართვის საშუალებათა რედაქტირება"</string>
- <string name="one_handed_tutorial_title" msgid="6312198435090726656">"ცალი ხელის რეჟიმის გამოყენება"</string>
- <string name="one_handed_tutorial_description" msgid="7674850272340517174">"გასასვლელად გადაფურცლეთ ეკრანის ქვედა კიდიდან ზემოთ ან შეეხეთ ნებისმიერ ადგილას აპის ზემოთ"</string>
</resources>
diff --git a/packages/SystemUI/res/values-kk/strings.xml b/packages/SystemUI/res/values-kk/strings.xml
index cafbc2b56732..ed6c05d60bb6 100644
--- a/packages/SystemUI/res/values-kk/strings.xml
+++ b/packages/SystemUI/res/values-kk/strings.xml
@@ -1067,6 +1067,4 @@
<string name="controls_added_tooltip" msgid="4842812921719153085">"Жаңа басқару элементтерін көру үшін \"Қуат\" түймесін басып тұрыңыз."</string>
<string name="controls_menu_add" msgid="4447246119229920050">"Басқару элементтерін енгізу"</string>
<string name="controls_menu_edit" msgid="890623986951347062">"Басқару элементтерін өзгерту"</string>
- <string name="one_handed_tutorial_title" msgid="6312198435090726656">"Бір қолмен енгізу режимін пайдалану"</string>
- <string name="one_handed_tutorial_description" msgid="7674850272340517174">"Шығу үшін экранның төменгі жағынан жоғары қарай сипаңыз немесе қолданбаның үстінен кез келген жерден түртіңіз."</string>
</resources>
diff --git a/packages/SystemUI/res/values-km/strings.xml b/packages/SystemUI/res/values-km/strings.xml
index 5f16c7645511..7636fdd6d8c2 100644
--- a/packages/SystemUI/res/values-km/strings.xml
+++ b/packages/SystemUI/res/values-km/strings.xml
@@ -1067,6 +1067,4 @@
<string name="controls_added_tooltip" msgid="4842812921719153085">"សង្កត់​ប៊ូតុង​ថាមពល ដើម្បី​មើលឃើញ​ការគ្រប់គ្រង​ថ្មីៗ"</string>
<string name="controls_menu_add" msgid="4447246119229920050">"បញ្ចូល​ផ្ទាំងគ្រប់គ្រង"</string>
<string name="controls_menu_edit" msgid="890623986951347062">"កែ​ផ្ទាំងគ្រប់គ្រង"</string>
- <string name="one_handed_tutorial_title" msgid="6312198435090726656">"កំពុងប្រើ​មុខងារប្រើដៃម្ខាង"</string>
- <string name="one_handed_tutorial_description" msgid="7674850272340517174">"ដើម្បីចាកចេញ សូមអូសឡើងលើ​ពីផ្នែកខាងក្រោមអេក្រង់ ឬចុចផ្នែកណាមួយ​នៅខាងលើកម្មវិធី"</string>
</resources>
diff --git a/packages/SystemUI/res/values-kn/strings.xml b/packages/SystemUI/res/values-kn/strings.xml
index dff9ebd1a072..7980790c3feb 100644
--- a/packages/SystemUI/res/values-kn/strings.xml
+++ b/packages/SystemUI/res/values-kn/strings.xml
@@ -1067,6 +1067,4 @@
<string name="controls_added_tooltip" msgid="4842812921719153085">"ಹೊಸ ನಿಯಂತ್ರಣಗಳನ್ನು ನೋಡಲು ಪವರ್ ಬಟನ್ ಹಿಡಿದುಕೊಳ್ಳಿ"</string>
<string name="controls_menu_add" msgid="4447246119229920050">"ನಿಯಂತ್ರಣಗಳನ್ನು ಸೇರಿಸಿ"</string>
<string name="controls_menu_edit" msgid="890623986951347062">"ನಿಯಂತ್ರಣಗಳನ್ನು ಎಡಿಟ್ ಮಾಡಿ"</string>
- <string name="one_handed_tutorial_title" msgid="6312198435090726656">"ಒಂದು ಕೈ ಮೋಡ್ ಅನ್ನು ಬಳಸಲಾಗುತ್ತಿದೆ"</string>
- <string name="one_handed_tutorial_description" msgid="7674850272340517174">"ನಿರ್ಗಮಿಸಲು, ಸ್ಕ್ರೀನ್‌ನ ಕೆಳಗಿನಿಂದ ಮೇಲಕ್ಕೆ ಸ್ವೈಪ್ ಮಾಡಿ ಅಥವಾ ಆ್ಯಪ್‌ನ ಮೇಲೆ ಎಲ್ಲಿಯಾದರೂ ಟ್ಯಾಪ್ ಮಾಡಿ"</string>
</resources>
diff --git a/packages/SystemUI/res/values-ko/strings.xml b/packages/SystemUI/res/values-ko/strings.xml
index 181888f29161..ce59c6f796c5 100644
--- a/packages/SystemUI/res/values-ko/strings.xml
+++ b/packages/SystemUI/res/values-ko/strings.xml
@@ -1067,6 +1067,4 @@
<string name="controls_added_tooltip" msgid="4842812921719153085">"새 컨트롤을 보려면 전원 버튼을 길게 누르세요."</string>
<string name="controls_menu_add" msgid="4447246119229920050">"컨트롤 추가"</string>
<string name="controls_menu_edit" msgid="890623986951347062">"컨트롤 수정"</string>
- <string name="one_handed_tutorial_title" msgid="6312198435090726656">"한 손 사용 모드 사용하기"</string>
- <string name="one_handed_tutorial_description" msgid="7674850272340517174">"화면 하단에서 위로 스와이프하거나 앱 상단을 탭하여 종료합니다."</string>
</resources>
diff --git a/packages/SystemUI/res/values-ky/strings.xml b/packages/SystemUI/res/values-ky/strings.xml
index 47fc3a8fbf31..57132e43dae9 100644
--- a/packages/SystemUI/res/values-ky/strings.xml
+++ b/packages/SystemUI/res/values-ky/strings.xml
@@ -1067,6 +1067,4 @@
<string name="controls_added_tooltip" msgid="4842812921719153085">"Башкаруу элементтерин көрүү үчүн күйгүзүү/өчүрүү баскычын коё бербей басып туруңуз"</string>
<string name="controls_menu_add" msgid="4447246119229920050">"Башкаруу элементтерин кошуу"</string>
<string name="controls_menu_edit" msgid="890623986951347062">"Башкаруу элементтерин түзөтүү"</string>
- <string name="one_handed_tutorial_title" msgid="6312198435090726656">"Бир кол режимин колдонуу"</string>
- <string name="one_handed_tutorial_description" msgid="7674850272340517174">"Чыгуу үчүн экранды ылдый жагынан өйдө көздөй сүрүңүз же колдонмонун өйдө жагын басыңыз"</string>
</resources>
diff --git a/packages/SystemUI/res/values-lo/strings.xml b/packages/SystemUI/res/values-lo/strings.xml
index cb875559011d..0ff4509891b0 100644
--- a/packages/SystemUI/res/values-lo/strings.xml
+++ b/packages/SystemUI/res/values-lo/strings.xml
@@ -1067,6 +1067,4 @@
<string name="controls_added_tooltip" msgid="4842812921719153085">"ກົດປຸ່ມເປີດປິດຄ້າງໄວ້ເພື່ອເບິ່ງການຄວບຄຸມໃໝ່"</string>
<string name="controls_menu_add" msgid="4447246119229920050">"ເພີ່ມການຄວບຄຸມ"</string>
<string name="controls_menu_edit" msgid="890623986951347062">"ແກ້ໄຂການຄວບຄຸມ"</string>
- <string name="one_handed_tutorial_title" msgid="6312198435090726656">"ກຳລັງໃຊ້ໂໝດມືດຽວ"</string>
- <string name="one_handed_tutorial_description" msgid="7674850272340517174">"ເພື່ອອອກ, ໃຫ້ປັດຂຶ້ນຈາກລຸ່ມສຸດຂອງໜ້າຈໍ ຫຼື ແຕະບ່ອນໃດກໍໄດ້ຢູ່ເທິງແອັບ"</string>
</resources>
diff --git a/packages/SystemUI/res/values-lt/strings.xml b/packages/SystemUI/res/values-lt/strings.xml
index ac90c0f58e68..239151ac5be4 100644
--- a/packages/SystemUI/res/values-lt/strings.xml
+++ b/packages/SystemUI/res/values-lt/strings.xml
@@ -1079,6 +1079,4 @@
<string name="controls_added_tooltip" msgid="4842812921719153085">"Jei norite peržiūrėti naujus valdiklius, laikykite paspaudę maitinimo mygtuką"</string>
<string name="controls_menu_add" msgid="4447246119229920050">"Pridėti valdiklių"</string>
<string name="controls_menu_edit" msgid="890623986951347062">"Redaguoti valdiklius"</string>
- <string name="one_handed_tutorial_title" msgid="6312198435090726656">"Vienos rankos režimo naudojimas"</string>
- <string name="one_handed_tutorial_description" msgid="7674850272340517174">"Jei norite išeiti, perbraukite aukštyn nuo ekrano apačios arba palieskite bet kur virš programos"</string>
</resources>
diff --git a/packages/SystemUI/res/values-lv/strings.xml b/packages/SystemUI/res/values-lv/strings.xml
index 2f5edd3f0d9f..1552a9e68363 100644
--- a/packages/SystemUI/res/values-lv/strings.xml
+++ b/packages/SystemUI/res/values-lv/strings.xml
@@ -1073,6 +1073,4 @@
<string name="controls_added_tooltip" msgid="4842812921719153085">"Nospiediet barošanas pogu un turiet to, lai skatītu jaunas vadīklas"</string>
<string name="controls_menu_add" msgid="4447246119229920050">"Pievienot vadīklas"</string>
<string name="controls_menu_edit" msgid="890623986951347062">"Rediģēt vadīklas"</string>
- <string name="one_handed_tutorial_title" msgid="6312198435090726656">"Vienas rokas režīma izmantošana"</string>
- <string name="one_handed_tutorial_description" msgid="7674850272340517174">"Lai izietu, velciet augšup no ekrāna apakšdaļas vai pieskarieties jebkurā vietā virs lietotnes"</string>
</resources>
diff --git a/packages/SystemUI/res/values-mk/strings.xml b/packages/SystemUI/res/values-mk/strings.xml
index de9cf0fb57bf..42b758fd518b 100644
--- a/packages/SystemUI/res/values-mk/strings.xml
+++ b/packages/SystemUI/res/values-mk/strings.xml
@@ -1067,6 +1067,4 @@
<string name="controls_added_tooltip" msgid="4842812921719153085">"Задржете го копчето за вклучување за да ги видите новите контроли"</string>
<string name="controls_menu_add" msgid="4447246119229920050">"Додајте контроли"</string>
<string name="controls_menu_edit" msgid="890623986951347062">"Изменете ги контролите"</string>
- <string name="one_handed_tutorial_title" msgid="6312198435090726656">"Користење на режимот со една рака"</string>
- <string name="one_handed_tutorial_description" msgid="7674850272340517174">"За да излезете, повлечете нагоре од дното на екранот или допрете каде било над апликацијата"</string>
</resources>
diff --git a/packages/SystemUI/res/values-ml/strings.xml b/packages/SystemUI/res/values-ml/strings.xml
index bd5187456574..2e68d3b8717d 100644
--- a/packages/SystemUI/res/values-ml/strings.xml
+++ b/packages/SystemUI/res/values-ml/strings.xml
@@ -1067,6 +1067,4 @@
<string name="controls_added_tooltip" msgid="4842812921719153085">"പുതിയ നിയന്ത്രണങ്ങൾ കാണാൻ പവർ ബട്ടൺ പിടിക്കുക"</string>
<string name="controls_menu_add" msgid="4447246119229920050">"നിയന്ത്രണങ്ങൾ ചേർക്കുക"</string>
<string name="controls_menu_edit" msgid="890623986951347062">"നിയന്ത്രണങ്ങൾ എഡിറ്റ് ചെയ്യുക"</string>
- <string name="one_handed_tutorial_title" msgid="6312198435090726656">"ഒറ്റക്കൈ മോഡ് എങ്ങനെ ഉപയോഗിക്കാം"</string>
- <string name="one_handed_tutorial_description" msgid="7674850272340517174">"പുറത്ത് കടക്കാൻ, സ്ക്രീനിന്റെ ചുവടെ നിന്ന് മുകളിലേക്ക് സ്വൈപ്പ് ചെയ്യുക അല്ലെങ്കിൽ ആപ്പിന് മുകളിലായി എവിടെയെങ്കിലും ടാപ്പ് ചെയ്യുക"</string>
</resources>
diff --git a/packages/SystemUI/res/values-mn/strings.xml b/packages/SystemUI/res/values-mn/strings.xml
index 14401030fb21..fab7a5531ca1 100644
--- a/packages/SystemUI/res/values-mn/strings.xml
+++ b/packages/SystemUI/res/values-mn/strings.xml
@@ -1067,6 +1067,4 @@
<string name="controls_added_tooltip" msgid="4842812921719153085">"Шинэ хяналтыг харахын тулд асаах товчийг удаан дарна уу"</string>
<string name="controls_menu_add" msgid="4447246119229920050">"Хяналт нэмэх"</string>
<string name="controls_menu_edit" msgid="890623986951347062">"Хяналтыг өөрчлөх"</string>
- <string name="one_handed_tutorial_title" msgid="6312198435090726656">"Нэг гарын горимыг ашиглаж байна"</string>
- <string name="one_handed_tutorial_description" msgid="7674850272340517174">"Гарахын тулд дэлгэцийн доод хэсгээс дээш шудрах эсвэл аппын дээд хэсэгт хүссэн газраа товшино уу"</string>
</resources>
diff --git a/packages/SystemUI/res/values-mr/strings.xml b/packages/SystemUI/res/values-mr/strings.xml
index 32fe7bdecb42..31a0a7a8da31 100644
--- a/packages/SystemUI/res/values-mr/strings.xml
+++ b/packages/SystemUI/res/values-mr/strings.xml
@@ -1067,6 +1067,4 @@
<string name="controls_added_tooltip" msgid="4842812921719153085">"नवीन नियंत्रणे पाहण्यासाठी पॉवर बटण धरून ठेवा"</string>
<string name="controls_menu_add" msgid="4447246119229920050">"नियंत्रणे जोडा"</string>
<string name="controls_menu_edit" msgid="890623986951347062">"नियंत्रणे व्यवस्थापित करा"</string>
- <string name="one_handed_tutorial_title" msgid="6312198435090726656">"एकहाती मोड वापरणे"</string>
- <string name="one_handed_tutorial_description" msgid="7674850272340517174">"बाहेर पडण्यासाठी स्क्रीनच्या खालून वरच्या दिशेने स्वाइप करा किंवा ॲप आयकनच्या वर कोठेही टॅप करा"</string>
</resources>
diff --git a/packages/SystemUI/res/values-ms/strings.xml b/packages/SystemUI/res/values-ms/strings.xml
index fe246d1a6129..b147b6e7a023 100644
--- a/packages/SystemUI/res/values-ms/strings.xml
+++ b/packages/SystemUI/res/values-ms/strings.xml
@@ -1067,6 +1067,4 @@
<string name="controls_added_tooltip" msgid="4842812921719153085">"Tahan butang Kuasa untuk melihat kawalan baharu"</string>
<string name="controls_menu_add" msgid="4447246119229920050">"Tambah kawalan"</string>
<string name="controls_menu_edit" msgid="890623986951347062">"Edit kawalan"</string>
- <string name="one_handed_tutorial_title" msgid="6312198435090726656">"Menggunakan mod sebelah tangan"</string>
- <string name="one_handed_tutorial_description" msgid="7674850272340517174">"Untuk keluar, leret ke atas daripada bahagian bawah skrin atau ketik pada mana-mana di bahagian atas apl"</string>
</resources>
diff --git a/packages/SystemUI/res/values-my/strings.xml b/packages/SystemUI/res/values-my/strings.xml
index 53c02a54ef7c..636e83643ee6 100644
--- a/packages/SystemUI/res/values-my/strings.xml
+++ b/packages/SystemUI/res/values-my/strings.xml
@@ -1067,6 +1067,4 @@
<string name="controls_added_tooltip" msgid="4842812921719153085">"ထိန်းချုပ်မှုအသစ်များ ကြည့်ရန် ဖွင့်ပိတ်ခလုတ်ကို ဖိထားပါ"</string>
<string name="controls_menu_add" msgid="4447246119229920050">"ထိန်းချုပ်မှုများ ထည့်ရန်"</string>
<string name="controls_menu_edit" msgid="890623986951347062">"ထိန်းချုပ်မှုများ တည်းဖြတ်ရန်"</string>
- <string name="one_handed_tutorial_title" msgid="6312198435090726656">"လက်တစ်ဖက်သုံးမုဒ် အသုံးပြုခြင်း"</string>
- <string name="one_handed_tutorial_description" msgid="7674850272340517174">"ထွက်ရန် ဖန်သားပြင်၏အောက်ခြေမှ အပေါ်သို့ပွတ်ဆွဲပါ သို့မဟုတ် အက်ပ်အပေါ်ဘက် မည်သည့်နေရာတွင်မဆို တို့ပါ"</string>
</resources>
diff --git a/packages/SystemUI/res/values-nb/strings.xml b/packages/SystemUI/res/values-nb/strings.xml
index 5c9f63f3a797..93ef3af9b037 100644
--- a/packages/SystemUI/res/values-nb/strings.xml
+++ b/packages/SystemUI/res/values-nb/strings.xml
@@ -1067,6 +1067,4 @@
<string name="controls_added_tooltip" msgid="4842812921719153085">"Hold inne av/på-knappen for å se kontroller"</string>
<string name="controls_menu_add" msgid="4447246119229920050">"Legg til kontroller"</string>
<string name="controls_menu_edit" msgid="890623986951347062">"Endre kontroller"</string>
- <string name="one_handed_tutorial_title" msgid="6312198435090726656">"Bruk av enhåndsmodus"</string>
- <string name="one_handed_tutorial_description" msgid="7674850272340517174">"For å avslutte, sveip opp fra bunnen av skjermen eller trykk hvor som helst over appen"</string>
</resources>
diff --git a/packages/SystemUI/res/values-ne/strings.xml b/packages/SystemUI/res/values-ne/strings.xml
index 791e4d3d3f20..d218e3939304 100644
--- a/packages/SystemUI/res/values-ne/strings.xml
+++ b/packages/SystemUI/res/values-ne/strings.xml
@@ -1067,6 +1067,4 @@
<string name="controls_added_tooltip" msgid="4842812921719153085">"नयाँ नियन्त्रण सुविधाहरू हेर्न पावर बटन थिचिराख्नुहोस्"</string>
<string name="controls_menu_add" msgid="4447246119229920050">"नियन्त्रण सुविधाहरू थप्नुहोस्"</string>
<string name="controls_menu_edit" msgid="890623986951347062">"नियन्त्रण सुविधाहरू सम्पादन गर्नु…"</string>
- <string name="one_handed_tutorial_title" msgid="6312198435090726656">"एक हाते मोड प्रयोग गरिँदै छ"</string>
- <string name="one_handed_tutorial_description" msgid="7674850272340517174">"बाहिर निस्कन, स्क्रिनको पुछारबाट माथितिर स्वाइप गर्नुहोस् वा एपभन्दा माथि जुनसुकै ठाउँमा ट्याप गर्नुहोस्"</string>
</resources>
diff --git a/packages/SystemUI/res/values-nl/strings.xml b/packages/SystemUI/res/values-nl/strings.xml
index 01d3fecd3323..3d61ee4adaf7 100644
--- a/packages/SystemUI/res/values-nl/strings.xml
+++ b/packages/SystemUI/res/values-nl/strings.xml
@@ -1067,6 +1067,4 @@
<string name="controls_added_tooltip" msgid="4842812921719153085">"Houd de aan/uit-knop ingedrukt om nieuwe bedieningselementen te bekijken"</string>
<string name="controls_menu_add" msgid="4447246119229920050">"Bedieningselementen toevoegen"</string>
<string name="controls_menu_edit" msgid="890623986951347062">"Bedieningselementen bewerken"</string>
- <string name="one_handed_tutorial_title" msgid="6312198435090726656">"Bediening met één hand gebruiken"</string>
- <string name="one_handed_tutorial_description" msgid="7674850272340517174">"Als je wilt afsluiten, swipe je omhoog vanaf de onderkant van het scherm of tik je ergens boven de app"</string>
</resources>
diff --git a/packages/SystemUI/res/values-or/strings.xml b/packages/SystemUI/res/values-or/strings.xml
index c7de8ca38cb2..dc38e39e054c 100644
--- a/packages/SystemUI/res/values-or/strings.xml
+++ b/packages/SystemUI/res/values-or/strings.xml
@@ -1067,6 +1067,4 @@
<string name="controls_added_tooltip" msgid="4842812921719153085">"ନୂଆ ନିୟନ୍ତ୍ରଣଗୁଡ଼ିକୁ ଦେଖିବା ପାଇଁ ପାୱାର ବଟନକୁ ଧରି ରଖନ୍ତୁ"</string>
<string name="controls_menu_add" msgid="4447246119229920050">"ନିୟନ୍ତ୍ରଣଗୁଡ଼ିକ ଯୋଗ କରନ୍ତୁ"</string>
<string name="controls_menu_edit" msgid="890623986951347062">"ନିୟନ୍ତ୍ରଣଗୁଡ଼ିକ ସମ୍ପାଦନ କରନ୍ତୁ"</string>
- <string name="one_handed_tutorial_title" msgid="6312198435090726656">"ଏକ-ହାତ ମୋଡ୍ ବ୍ୟବହାର କରି"</string>
- <string name="one_handed_tutorial_description" msgid="7674850272340517174">"ବାହାରି ଯିବା ପାଇଁ, ତଳୁ ଉପରକୁ ସ୍ୱାଇପ୍ କରନ୍ତୁ କିମ୍ବା ଆପ୍ ଆଇକନର ଉପରେ ଯେ କୌଣସି ସ୍ଥାନରେ ଟାପ୍ କରନ୍ତୁ"</string>
</resources>
diff --git a/packages/SystemUI/res/values-pa/strings.xml b/packages/SystemUI/res/values-pa/strings.xml
index 66333b9e09fe..8d15d176ead4 100644
--- a/packages/SystemUI/res/values-pa/strings.xml
+++ b/packages/SystemUI/res/values-pa/strings.xml
@@ -1067,6 +1067,4 @@
<string name="controls_added_tooltip" msgid="4842812921719153085">"ਨਵੇਂ ਕੰਟਰੋਲ ਦੇਖਣ ਲਈ ਪਾਵਰ ਬਟਨ ਦਬਾਈ ਰੱਖੋ"</string>
<string name="controls_menu_add" msgid="4447246119229920050">"ਕੰਟਰੋਲ ਸ਼ਾਮਲ ਕਰੋ"</string>
<string name="controls_menu_edit" msgid="890623986951347062">"ਕੰਟਰੋਲਾਂ ਦਾ ਸੰਪਾਦਨ ਕਰੋ"</string>
- <string name="one_handed_tutorial_title" msgid="6312198435090726656">"ਇੱਕ ਹੱਥ ਮੋਡ ਵਰਤਣਾ"</string>
- <string name="one_handed_tutorial_description" msgid="7674850272340517174">"ਬਾਹਰ ਜਾਣ ਲਈ, ਸਕ੍ਰੀਨ ਦੇ ਹੇਠਾਂ ਤੋਂ ਉੱਪਰ ਵੱਲ ਸਵਾਈਪ ਕਰੋ ਜਾਂ ਐਪ \'ਤੇ ਕਿਤੇ ਵੀ ਟੈਪ ਕਰੋ"</string>
</resources>
diff --git a/packages/SystemUI/res/values-pl/strings.xml b/packages/SystemUI/res/values-pl/strings.xml
index c68e3ac46932..b531be0ff724 100644
--- a/packages/SystemUI/res/values-pl/strings.xml
+++ b/packages/SystemUI/res/values-pl/strings.xml
@@ -1079,6 +1079,4 @@
<string name="controls_added_tooltip" msgid="4842812921719153085">"Przytrzymaj przycisk zasilania, by zobaczyć nowe elementy sterujące"</string>
<string name="controls_menu_add" msgid="4447246119229920050">"Dodaj elementy sterujące"</string>
<string name="controls_menu_edit" msgid="890623986951347062">"Edytuj elementy sterujące"</string>
- <string name="one_handed_tutorial_title" msgid="6312198435090726656">"Korzystanie z trybu jednej ręki"</string>
- <string name="one_handed_tutorial_description" msgid="7674850272340517174">"Aby zamknąć, przesuń palcem z dołu ekranu w górę lub kliknij dowolne miejsce nad aplikacją"</string>
</resources>
diff --git a/packages/SystemUI/res/values-pt-rBR/strings.xml b/packages/SystemUI/res/values-pt-rBR/strings.xml
index ff2ecd38547f..67f161151d47 100644
--- a/packages/SystemUI/res/values-pt-rBR/strings.xml
+++ b/packages/SystemUI/res/values-pt-rBR/strings.xml
@@ -1067,6 +1067,4 @@
<string name="controls_added_tooltip" msgid="4842812921719153085">"Mantenha o botão liga/desliga pressionado para ver os novos controles"</string>
<string name="controls_menu_add" msgid="4447246119229920050">"Adicionar controles"</string>
<string name="controls_menu_edit" msgid="890623986951347062">"Editar controles"</string>
- <string name="one_handed_tutorial_title" msgid="6312198435090726656">"Como usar o modo para uma mão"</string>
- <string name="one_handed_tutorial_description" msgid="7674850272340517174">"Para sair, deslize de baixo para cima na tela ou toque em qualquer lugar acima do app"</string>
</resources>
diff --git a/packages/SystemUI/res/values-pt-rPT/strings.xml b/packages/SystemUI/res/values-pt-rPT/strings.xml
index c39a5eb54868..6e32ca4b940b 100644
--- a/packages/SystemUI/res/values-pt-rPT/strings.xml
+++ b/packages/SystemUI/res/values-pt-rPT/strings.xml
@@ -1067,6 +1067,4 @@
<string name="controls_added_tooltip" msgid="4842812921719153085">"Mantenha premido o botão ligar/desligar para ver os novos controlos."</string>
<string name="controls_menu_add" msgid="4447246119229920050">"Adicionar controlos"</string>
<string name="controls_menu_edit" msgid="890623986951347062">"Editar controlos"</string>
- <string name="one_handed_tutorial_title" msgid="6312198435090726656">"Utilizar o modo para uma mão"</string>
- <string name="one_handed_tutorial_description" msgid="7674850272340517174">"Para sair, deslize rapidamente para cima a partir da parte inferior do ecrã ou toque em qualquer ponto acima da app."</string>
</resources>
diff --git a/packages/SystemUI/res/values-pt/strings.xml b/packages/SystemUI/res/values-pt/strings.xml
index ff2ecd38547f..67f161151d47 100644
--- a/packages/SystemUI/res/values-pt/strings.xml
+++ b/packages/SystemUI/res/values-pt/strings.xml
@@ -1067,6 +1067,4 @@
<string name="controls_added_tooltip" msgid="4842812921719153085">"Mantenha o botão liga/desliga pressionado para ver os novos controles"</string>
<string name="controls_menu_add" msgid="4447246119229920050">"Adicionar controles"</string>
<string name="controls_menu_edit" msgid="890623986951347062">"Editar controles"</string>
- <string name="one_handed_tutorial_title" msgid="6312198435090726656">"Como usar o modo para uma mão"</string>
- <string name="one_handed_tutorial_description" msgid="7674850272340517174">"Para sair, deslize de baixo para cima na tela ou toque em qualquer lugar acima do app"</string>
</resources>
diff --git a/packages/SystemUI/res/values-ro/strings.xml b/packages/SystemUI/res/values-ro/strings.xml
index b793bcd33e4c..691fd835b563 100644
--- a/packages/SystemUI/res/values-ro/strings.xml
+++ b/packages/SystemUI/res/values-ro/strings.xml
@@ -1073,6 +1073,4 @@
<string name="controls_added_tooltip" msgid="4842812921719153085">"Apăsați butonul de alimentare pentru a vedea noile comenzi"</string>
<string name="controls_menu_add" msgid="4447246119229920050">"Adăugați comenzi"</string>
<string name="controls_menu_edit" msgid="890623986951347062">"Editați comenzile"</string>
- <string name="one_handed_tutorial_title" msgid="6312198435090726656">"Folosirea modului cu o mână"</string>
- <string name="one_handed_tutorial_description" msgid="7674850272340517174">"Pentru a ieși, glisați în sus din partea de jos a ecranului sau atingeți oriunde deasupra ferestrei aplicației"</string>
</resources>
diff --git a/packages/SystemUI/res/values-ru/strings.xml b/packages/SystemUI/res/values-ru/strings.xml
index 7560f5309824..3ccafda2bbfe 100644
--- a/packages/SystemUI/res/values-ru/strings.xml
+++ b/packages/SystemUI/res/values-ru/strings.xml
@@ -1079,6 +1079,4 @@
<string name="controls_added_tooltip" msgid="4842812921719153085">"Удерживайте кнопку питания, чтобы увидеть новые элементы управления"</string>
<string name="controls_menu_add" msgid="4447246119229920050">"Добавить виджеты"</string>
<string name="controls_menu_edit" msgid="890623986951347062">"Изменить виджеты"</string>
- <string name="one_handed_tutorial_title" msgid="6312198435090726656">"Использование режима управления одной рукой"</string>
- <string name="one_handed_tutorial_description" msgid="7674850272340517174">"Чтобы выйти, проведите по экрану снизу вверх или нажмите в любой области над значком приложения."</string>
</resources>
diff --git a/packages/SystemUI/res/values-si/strings.xml b/packages/SystemUI/res/values-si/strings.xml
index 02f9c23cecf9..14528c078a33 100644
--- a/packages/SystemUI/res/values-si/strings.xml
+++ b/packages/SystemUI/res/values-si/strings.xml
@@ -1067,6 +1067,4 @@
<string name="controls_added_tooltip" msgid="4842812921719153085">"නව පාලන බැලීමට බල බොත්තම අල්ලාගෙන සිටින්න"</string>
<string name="controls_menu_add" msgid="4447246119229920050">"පාලන එක් කරන්න"</string>
<string name="controls_menu_edit" msgid="890623986951347062">"පාලන සංස්කරණය කරන්න"</string>
- <string name="one_handed_tutorial_title" msgid="6312198435090726656">"තනි-අත් ප්‍රකාරය භාවිත කරමින්"</string>
- <string name="one_handed_tutorial_description" msgid="7674850272340517174">"පිටවීමට, තිරයේ පහළ සිට ඉහළට ස්වයිප් කරන්න හෝ යෙදුමට ඉහළින් ඕනෑම තැනක තට්ටු කරන්න"</string>
</resources>
diff --git a/packages/SystemUI/res/values-sk/strings.xml b/packages/SystemUI/res/values-sk/strings.xml
index 54a32ddd1cbf..3c405128788a 100644
--- a/packages/SystemUI/res/values-sk/strings.xml
+++ b/packages/SystemUI/res/values-sk/strings.xml
@@ -1079,6 +1079,4 @@
<string name="controls_added_tooltip" msgid="4842812921719153085">"Pridržaním vypínača zobrazíte nové ovládacie prvky"</string>
<string name="controls_menu_add" msgid="4447246119229920050">"Pridať ovládače"</string>
<string name="controls_menu_edit" msgid="890623986951347062">"Upraviť ovládače"</string>
- <string name="one_handed_tutorial_title" msgid="6312198435090726656">"Používanie režimu jednej ruky"</string>
- <string name="one_handed_tutorial_description" msgid="7674850272340517174">"Ukončíte potiahnutím z dolnej časti obrazovky nahor alebo klepnutím kdekoľvek nad aplikáciu"</string>
</resources>
diff --git a/packages/SystemUI/res/values-sl/strings.xml b/packages/SystemUI/res/values-sl/strings.xml
index 32fce7d58c9c..4c68eeb15800 100644
--- a/packages/SystemUI/res/values-sl/strings.xml
+++ b/packages/SystemUI/res/values-sl/strings.xml
@@ -1079,6 +1079,4 @@
<string name="controls_added_tooltip" msgid="4842812921719153085">"Za ogled novih kontrolnikov pridržite gumb za vklop"</string>
<string name="controls_menu_add" msgid="4447246119229920050">"Dodaj kontrolnike"</string>
<string name="controls_menu_edit" msgid="890623986951347062">"Uredi kontrolnike"</string>
- <string name="one_handed_tutorial_title" msgid="6312198435090726656">"Uporaba enoročnega načina"</string>
- <string name="one_handed_tutorial_description" msgid="7674850272340517174">"Za izhod povlecite z dna zaslona navzgor ali se dotaknite na poljubnem mestu nad aplikacijo"</string>
</resources>
diff --git a/packages/SystemUI/res/values-sq/strings.xml b/packages/SystemUI/res/values-sq/strings.xml
index c907bc23cf32..681fa3fbeaf1 100644
--- a/packages/SystemUI/res/values-sq/strings.xml
+++ b/packages/SystemUI/res/values-sq/strings.xml
@@ -1067,6 +1067,4 @@
<string name="controls_added_tooltip" msgid="4842812921719153085">"Mbaj shtypur butonin e energjisë për të parë kontrollet e reja"</string>
<string name="controls_menu_add" msgid="4447246119229920050">"Shto kontrollet"</string>
<string name="controls_menu_edit" msgid="890623986951347062">"Modifiko kontrollet"</string>
- <string name="one_handed_tutorial_title" msgid="6312198435090726656">"Po përdor modalitetin e përdorimit me një dorë"</string>
- <string name="one_handed_tutorial_description" msgid="7674850272340517174">"Për të dalë, rrëshqit lart nga fundi i ekranit ose trokit diku mbi aplikacion"</string>
</resources>
diff --git a/packages/SystemUI/res/values-sr/strings.xml b/packages/SystemUI/res/values-sr/strings.xml
index 8b7ce1f35cb3..15190d4860bf 100644
--- a/packages/SystemUI/res/values-sr/strings.xml
+++ b/packages/SystemUI/res/values-sr/strings.xml
@@ -1073,6 +1073,4 @@
<string name="controls_added_tooltip" msgid="4842812921719153085">"Задржите дугме за укључивање да бисте видели нове контроле"</string>
<string name="controls_menu_add" msgid="4447246119229920050">"Додај контроле"</string>
<string name="controls_menu_edit" msgid="890623986951347062">"Измени контроле"</string>
- <string name="one_handed_tutorial_title" msgid="6312198435090726656">"Коришћење режима једном руком"</string>
- <string name="one_handed_tutorial_description" msgid="7674850272340517174">"Да бисте изашли, превуците нагоре од дна екрана или додирните било где изнад апликације"</string>
</resources>
diff --git a/packages/SystemUI/res/values-sv/strings.xml b/packages/SystemUI/res/values-sv/strings.xml
index c4b7977ae5a6..6fc976ea9d36 100644
--- a/packages/SystemUI/res/values-sv/strings.xml
+++ b/packages/SystemUI/res/values-sv/strings.xml
@@ -1067,6 +1067,4 @@
<string name="controls_added_tooltip" msgid="4842812921719153085">"De nya snabbkontrollerna visas om du håller strömbrytaren nedtryckt"</string>
<string name="controls_menu_add" msgid="4447246119229920050">"Lägg till snabbkontroller"</string>
<string name="controls_menu_edit" msgid="890623986951347062">"Redigera snabbkontroller"</string>
- <string name="one_handed_tutorial_title" msgid="6312198435090726656">"Använda enhandsläge"</string>
- <string name="one_handed_tutorial_description" msgid="7674850272340517174">"Avsluta genom att svepa uppåt från skärmens nederkant eller trycka ovanför appen"</string>
</resources>
diff --git a/packages/SystemUI/res/values-sw/strings.xml b/packages/SystemUI/res/values-sw/strings.xml
index b483fa8f0791..67d5f3404269 100644
--- a/packages/SystemUI/res/values-sw/strings.xml
+++ b/packages/SystemUI/res/values-sw/strings.xml
@@ -1067,6 +1067,4 @@
<string name="controls_added_tooltip" msgid="4842812921719153085">"Shikilia kitufe cha kuwasha/kuzima ili uone vidhibiti vipya"</string>
<string name="controls_menu_add" msgid="4447246119229920050">"Weka vidhibiti"</string>
<string name="controls_menu_edit" msgid="890623986951347062">"Badilisha vidhibiti"</string>
- <string name="one_handed_tutorial_title" msgid="6312198435090726656">"Kutumia hali ya kutumia kwa mkono mmoja"</string>
- <string name="one_handed_tutorial_description" msgid="7674850272340517174">"Ili ufunge, telezesha kidole juu kutoka sehemu ya chini ya skrini au uguse mahali popote juu ya programu"</string>
</resources>
diff --git a/packages/SystemUI/res/values-ta/strings.xml b/packages/SystemUI/res/values-ta/strings.xml
index 2c025e72cdf4..8f2e296301d7 100644
--- a/packages/SystemUI/res/values-ta/strings.xml
+++ b/packages/SystemUI/res/values-ta/strings.xml
@@ -1067,6 +1067,4 @@
<string name="controls_added_tooltip" msgid="4842812921719153085">"புதிய கட்டுப்பாடுகளைப் பார்க்க பவர் பட்டனைப் பிடித்திருக்கவும்"</string>
<string name="controls_menu_add" msgid="4447246119229920050">"கட்டுப்பாடுகளைச் சேர்த்தல்"</string>
<string name="controls_menu_edit" msgid="890623986951347062">"கட்டுப்பாடுகளை மாற்றுதல்"</string>
- <string name="one_handed_tutorial_title" msgid="6312198435090726656">"ஒற்றைக் கைப் பயன்முறையைப் பயன்படுத்துதல்"</string>
- <string name="one_handed_tutorial_description" msgid="7674850272340517174">"வெளியேற, திரையின் கீழிருந்து மேல்நோக்கி ஸ்வைப் செய்யவும் அல்லது ஆப்ஸுக்கு மேலே எங்காவது தட்டவும்"</string>
</resources>
diff --git a/packages/SystemUI/res/values-te/strings.xml b/packages/SystemUI/res/values-te/strings.xml
index a49bb9b46512..8a15d7615140 100644
--- a/packages/SystemUI/res/values-te/strings.xml
+++ b/packages/SystemUI/res/values-te/strings.xml
@@ -1067,6 +1067,4 @@
<string name="controls_added_tooltip" msgid="4842812921719153085">"కొత్త నియంత్రణలను చూడడానికి పవర్ బటన్‌ని నొక్కి పట్టుకోండి"</string>
<string name="controls_menu_add" msgid="4447246119229920050">"నియంత్రణలను జోడించండి"</string>
<string name="controls_menu_edit" msgid="890623986951347062">"నియంత్రణలను ఎడిట్ చేయండి"</string>
- <string name="one_handed_tutorial_title" msgid="6312198435090726656">"వన్-హ్యాండెడ్ మోడ్‌ను ఉపయోగించడం"</string>
- <string name="one_handed_tutorial_description" msgid="7674850272340517174">"నిష్క్రమించడానికి, స్క్రీన్ కింది భాగం నుండి పైకి స్వైప్ చేయండి లేదా యాప్ పైన ఎక్కడైనా ట్యాప్ చేయండి"</string>
</resources>
diff --git a/packages/SystemUI/res/values-th/strings.xml b/packages/SystemUI/res/values-th/strings.xml
index 8fd844203d9f..16593b4c245f 100644
--- a/packages/SystemUI/res/values-th/strings.xml
+++ b/packages/SystemUI/res/values-th/strings.xml
@@ -1067,6 +1067,4 @@
<string name="controls_added_tooltip" msgid="4842812921719153085">"กดปุ่มเปิด/ปิดค้างไว้เพื่อดูตัวควบคุมใหม่ๆ"</string>
<string name="controls_menu_add" msgid="4447246119229920050">"เพิ่มตัวควบคุม"</string>
<string name="controls_menu_edit" msgid="890623986951347062">"แก้ไขตัวควบคุม"</string>
- <string name="one_handed_tutorial_title" msgid="6312198435090726656">"การใช้โหมดมือเดียว"</string>
- <string name="one_handed_tutorial_description" msgid="7674850272340517174">"หากต้องการออก ให้เลื่อนขึ้นจากด้านล่างของหน้าจอหรือแตะที่ใดก็ได้เหนือแอป"</string>
</resources>
diff --git a/packages/SystemUI/res/values-tl/strings.xml b/packages/SystemUI/res/values-tl/strings.xml
index 5951ba223c5d..283a6d54ef0f 100644
--- a/packages/SystemUI/res/values-tl/strings.xml
+++ b/packages/SystemUI/res/values-tl/strings.xml
@@ -1067,6 +1067,4 @@
<string name="controls_added_tooltip" msgid="4842812921719153085">"Pindutin nang matagal ang Power button para makita ang mga bagong kontrol"</string>
<string name="controls_menu_add" msgid="4447246119229920050">"Magdagdag ng mga kontrol"</string>
<string name="controls_menu_edit" msgid="890623986951347062">"Mag-edit ng mga kontrol"</string>
- <string name="one_handed_tutorial_title" msgid="6312198435090726656">"Gamit ang one-hand mode"</string>
- <string name="one_handed_tutorial_description" msgid="7674850272340517174">"Para lumabas, mag-swipe pataas mula sa ibaba ng screen o mag-tap kahit saan sa itaas ng app"</string>
</resources>
diff --git a/packages/SystemUI/res/values-tr/strings.xml b/packages/SystemUI/res/values-tr/strings.xml
index 2d2ccadd65d8..514f4ee57ce3 100644
--- a/packages/SystemUI/res/values-tr/strings.xml
+++ b/packages/SystemUI/res/values-tr/strings.xml
@@ -1067,6 +1067,4 @@
<string name="controls_added_tooltip" msgid="4842812921719153085">"Yeni kontrolleri görmek için Güç düğmesini basılı tutun"</string>
<string name="controls_menu_add" msgid="4447246119229920050">"Denetim ekle"</string>
<string name="controls_menu_edit" msgid="890623986951347062">"Denetimleri düzenle"</string>
- <string name="one_handed_tutorial_title" msgid="6312198435090726656">"Tek el modunu kullanma"</string>
- <string name="one_handed_tutorial_description" msgid="7674850272340517174">"Çıkmak için ekranın alt kısmından yukarı kaydırın veya uygulamanın üzerinde herhangi bir yere dokunun"</string>
</resources>
diff --git a/packages/SystemUI/res/values-uk/strings.xml b/packages/SystemUI/res/values-uk/strings.xml
index 1a8ce7b6ad76..565907ce9106 100644
--- a/packages/SystemUI/res/values-uk/strings.xml
+++ b/packages/SystemUI/res/values-uk/strings.xml
@@ -1079,6 +1079,4 @@
<string name="controls_added_tooltip" msgid="4842812921719153085">"Утримуйте кнопку живлення, щоб переглянути нові елементи керування"</string>
<string name="controls_menu_add" msgid="4447246119229920050">"Додати елементи керування"</string>
<string name="controls_menu_edit" msgid="890623986951347062">"Змінити елементи керування"</string>
- <string name="one_handed_tutorial_title" msgid="6312198435090726656">"Як користуватись режимом керування однією рукою"</string>
- <string name="one_handed_tutorial_description" msgid="7674850272340517174">"Щоб вийти, проведіть пальцем вверх від низу екрана або торкніться екрана над додатком"</string>
</resources>
diff --git a/packages/SystemUI/res/values-ur/strings.xml b/packages/SystemUI/res/values-ur/strings.xml
index 4f091d6bde09..d5f90195a4d9 100644
--- a/packages/SystemUI/res/values-ur/strings.xml
+++ b/packages/SystemUI/res/values-ur/strings.xml
@@ -1067,6 +1067,4 @@
<string name="controls_added_tooltip" msgid="4842812921719153085">"نئے کنٹرولز دیکھنے کے لیے پاور بٹن کو دبائے رکھیں"</string>
<string name="controls_menu_add" msgid="4447246119229920050">"کنٹرولز شامل کریں"</string>
<string name="controls_menu_edit" msgid="890623986951347062">"کنٹرولز میں ترمیم کریں"</string>
- <string name="one_handed_tutorial_title" msgid="6312198435090726656">"ایک ہاتھ کی وضع کا استعمال کرنا"</string>
- <string name="one_handed_tutorial_description" msgid="7674850272340517174">"باہر نکلنے کے لئے، اسکرین کے نیچے سے اوپر کی طرف سوائپ کریں یا ایپ کے اوپر کہیں بھی تھپتھپائیں"</string>
</resources>
diff --git a/packages/SystemUI/res/values-uz/strings.xml b/packages/SystemUI/res/values-uz/strings.xml
index 26a691a147ce..71703e05ea29 100644
--- a/packages/SystemUI/res/values-uz/strings.xml
+++ b/packages/SystemUI/res/values-uz/strings.xml
@@ -1067,6 +1067,4 @@
<string name="controls_added_tooltip" msgid="4842812921719153085">"Yangi boshqaruv elementlari bilan tanishish uchun quvvat tugmasini bosib turing"</string>
<string name="controls_menu_add" msgid="4447246119229920050">"Element kiritish"</string>
<string name="controls_menu_edit" msgid="890623986951347062">"Elementlarni tahrirlash"</string>
- <string name="one_handed_tutorial_title" msgid="6312198435090726656">"Ixcham rejimdan foydalaning"</string>
- <string name="one_handed_tutorial_description" msgid="7674850272340517174">"Chiqish uchun ekran pastidan tepaga suring yoki ilovaning tepasidagi istalgan joyga bosing."</string>
</resources>
diff --git a/packages/SystemUI/res/values-vi/strings.xml b/packages/SystemUI/res/values-vi/strings.xml
index bea99a9aa82e..12eb5e12f2a6 100644
--- a/packages/SystemUI/res/values-vi/strings.xml
+++ b/packages/SystemUI/res/values-vi/strings.xml
@@ -1067,6 +1067,4 @@
<string name="controls_added_tooltip" msgid="4842812921719153085">"Giữ nút Nguồn để xem các tùy chọn điều khiển mới"</string>
<string name="controls_menu_add" msgid="4447246119229920050">"Thêm các tùy chọn điều khiển"</string>
<string name="controls_menu_edit" msgid="890623986951347062">"Chỉnh sửa tùy chọn điều khiển"</string>
- <string name="one_handed_tutorial_title" msgid="6312198435090726656">"Cách dùng chế độ một tay"</string>
- <string name="one_handed_tutorial_description" msgid="7674850272340517174">"Để thoát, hãy vuốt lên từ cuối màn hình hoặc nhấn vào vị trí bất kỳ phía trên ứng dụng"</string>
</resources>
diff --git a/packages/SystemUI/res/values-zh-rCN/strings.xml b/packages/SystemUI/res/values-zh-rCN/strings.xml
index 8e73f36a74d3..f886ecb6cf39 100644
--- a/packages/SystemUI/res/values-zh-rCN/strings.xml
+++ b/packages/SystemUI/res/values-zh-rCN/strings.xml
@@ -1067,6 +1067,4 @@
<string name="controls_added_tooltip" msgid="4842812921719153085">"按住电源按钮即可查看新控件"</string>
<string name="controls_menu_add" msgid="4447246119229920050">"添加控件"</string>
<string name="controls_menu_edit" msgid="890623986951347062">"修改控件"</string>
- <string name="one_handed_tutorial_title" msgid="6312198435090726656">"使用单手模式"</string>
- <string name="one_handed_tutorial_description" msgid="7674850272340517174">"如需退出,请从屏幕底部向上滑动,或点按应用上方的任意位置"</string>
</resources>
diff --git a/packages/SystemUI/res/values-zh-rHK/strings.xml b/packages/SystemUI/res/values-zh-rHK/strings.xml
index 08bf63b116cc..744d341deb08 100644
--- a/packages/SystemUI/res/values-zh-rHK/strings.xml
+++ b/packages/SystemUI/res/values-zh-rHK/strings.xml
@@ -1067,6 +1067,4 @@
<string name="controls_added_tooltip" msgid="4842812921719153085">"按住「開關」按鈕以查看新控制項"</string>
<string name="controls_menu_add" msgid="4447246119229920050">"新增控制項"</string>
<string name="controls_menu_edit" msgid="890623986951347062">"編輯控制項"</string>
- <string name="one_handed_tutorial_title" msgid="6312198435090726656">"使用單手模式"</string>
- <string name="one_handed_tutorial_description" msgid="7674850272340517174">"如要退出,請從螢幕底部向上滑動,或輕按應用程式上方的任何位置"</string>
</resources>
diff --git a/packages/SystemUI/res/values-zh-rTW/strings.xml b/packages/SystemUI/res/values-zh-rTW/strings.xml
index 3e7d2e481630..49d530f0a7af 100644
--- a/packages/SystemUI/res/values-zh-rTW/strings.xml
+++ b/packages/SystemUI/res/values-zh-rTW/strings.xml
@@ -1067,6 +1067,4 @@
<string name="controls_added_tooltip" msgid="4842812921719153085">"按住電源按鈕即可查看新的控制項"</string>
<string name="controls_menu_add" msgid="4447246119229920050">"新增控制項"</string>
<string name="controls_menu_edit" msgid="890623986951347062">"編輯控制項"</string>
- <string name="one_handed_tutorial_title" msgid="6312198435090726656">"使用單手模式"</string>
- <string name="one_handed_tutorial_description" msgid="7674850272340517174">"如要退出,請從螢幕底部向上滑動,或輕觸應用程式上方的任何位置"</string>
</resources>
diff --git a/packages/SystemUI/res/values-zu/strings.xml b/packages/SystemUI/res/values-zu/strings.xml
index f93ff1d85db8..abc45c84ccd0 100644
--- a/packages/SystemUI/res/values-zu/strings.xml
+++ b/packages/SystemUI/res/values-zu/strings.xml
@@ -1067,6 +1067,4 @@
<string name="controls_added_tooltip" msgid="4842812921719153085">"Bamba Inkinobho yamandla ukuze ubone izilawuli ezintsha"</string>
<string name="controls_menu_add" msgid="4447246119229920050">"Engeza Izilawuli"</string>
<string name="controls_menu_edit" msgid="890623986951347062">"Hlela izilawuli"</string>
- <string name="one_handed_tutorial_title" msgid="6312198435090726656">"Ukusebenzisa imodi yesandla esisodwa"</string>
- <string name="one_handed_tutorial_description" msgid="7674850272340517174">"Ukuze uphume, swayipha ngaphezulu kusuka ngezansi kwesikrini noma thepha noma kuphi ngenhla kohlelo lokusebenza"</string>
</resources>
diff --git a/packages/SystemUI/res/values/strings.xml b/packages/SystemUI/res/values/strings.xml
index cca70f9aa518..e577b967a85e 100644
--- a/packages/SystemUI/res/values/strings.xml
+++ b/packages/SystemUI/res/values/strings.xml
@@ -107,7 +107,7 @@
<string name="status_bar_settings_notifications">Notifications</string>
<!-- Separator for PLMN and SPN in network name. -->
- <string name="status_bar_network_name_separator" translatable="false">|</string>
+ <string name="status_bar_network_name_separator" translatable="false"> - </string>
<!-- Network connection string for Bluetooth Reverse Tethering -->
<string name="bluetooth_tethered">Bluetooth tethered</string>
diff --git a/packages/SystemUI/src/com/android/systemui/ScreenDecorations.java b/packages/SystemUI/src/com/android/systemui/ScreenDecorations.java
index f663d1a0d77c..1ebe64860a98 100644
--- a/packages/SystemUI/src/com/android/systemui/ScreenDecorations.java
+++ b/packages/SystemUI/src/com/android/systemui/ScreenDecorations.java
@@ -105,6 +105,9 @@ public class ScreenDecorations extends SystemUI implements Tunable {
public static final String SIZE = "sysui_rounded_size";
public static final String PADDING = "sysui_rounded_content_padding";
+ // Provide a way for factory to disable ScreenDecorations to run the Display tests.
+ private static final boolean DEBUG_DISABLE_SCREEN_DECORATIONS =
+ SystemProperties.getBoolean("debug.disable_screen_decorations", false);
private static final boolean DEBUG_SCREENSHOT_ROUNDED_CORNERS =
SystemProperties.getBoolean("debug.screenshot_rounded_corners", false);
private static final boolean VERBOSE = false;
@@ -204,6 +207,10 @@ public class ScreenDecorations extends SystemUI implements Tunable {
@Override
public void start() {
+ if (DEBUG_DISABLE_SCREEN_DECORATIONS) {
+ Log.i(TAG, "ScreenDecorations is disabled");
+ return;
+ }
mHandler = startHandlerThread();
mHandler.post(this::startOnScreenDecorationsThread);
}
diff --git a/packages/SystemUI/src/com/android/systemui/bubbles/Bubble.java b/packages/SystemUI/src/com/android/systemui/bubbles/Bubble.java
index e6c1bc3d4c6c..fbb47e2086b3 100644
--- a/packages/SystemUI/src/com/android/systemui/bubbles/Bubble.java
+++ b/packages/SystemUI/src/com/android/systemui/bubbles/Bubble.java
@@ -254,21 +254,28 @@ class Bubble implements BubbleViewProvider {
}
/**
- * Call when the views should be removed, ensure this is called to clean up ActivityView
- * content.
+ * Cleanup expanded view for bubbles going into overflow.
*/
- void cleanupViews() {
+ void cleanupExpandedView() {
if (mExpandedView != null) {
mExpandedView.cleanUpExpandedState();
mExpandedView = null;
}
- mIconView = null;
if (mIntent != null) {
mIntent.unregisterCancelListener(mIntentCancelListener);
}
mIntentActive = false;
}
+ /**
+ * Call when the views should be removed, ensure this is called to clean up ActivityView
+ * content.
+ */
+ void cleanupViews() {
+ cleanupExpandedView();
+ mIconView = null;
+ }
+
void setPendingIntentCanceled() {
mPendingIntentCanceled = true;
}
@@ -328,7 +335,6 @@ class Bubble implements BubbleViewProvider {
return;
}
mInflationTask.cancel(true /* mayInterruptIfRunning */);
- cleanupViews();
}
void setViewInfo(BubbleViewInfoTask.BubbleViewInfo info) {
diff --git a/packages/SystemUI/src/com/android/systemui/bubbles/BubbleController.java b/packages/SystemUI/src/com/android/systemui/bubbles/BubbleController.java
index 4b4e275e5cbd..99875f8675d8 100644
--- a/packages/SystemUI/src/com/android/systemui/bubbles/BubbleController.java
+++ b/packages/SystemUI/src/com/android/systemui/bubbles/BubbleController.java
@@ -1328,6 +1328,8 @@ public class BubbleController implements ConfigurationController.ConfigurationLi
// Lazy load overflow bubbles from disk
loadOverflowBubblesFromDisk();
+ mStackView.updateOverflowButtonDot();
+
// Update bubbles in overflow.
if (mOverflowListener != null) {
mOverflowListener.applyUpdate(update);
diff --git a/packages/SystemUI/src/com/android/systemui/bubbles/BubbleOverflow.kt b/packages/SystemUI/src/com/android/systemui/bubbles/BubbleOverflow.kt
index 6d3c2a68e6c7..bf7c860132bf 100644
--- a/packages/SystemUI/src/com/android/systemui/bubbles/BubbleOverflow.kt
+++ b/packages/SystemUI/src/com/android/systemui/bubbles/BubbleOverflow.kt
@@ -43,6 +43,7 @@ class BubbleOverflow(
private var bitmapSize = 0
private var iconBitmapSize = 0
private var dotColor = 0
+ private var showDot = false
private val inflater: LayoutInflater = LayoutInflater.from(context)
private val expandedView: BubbleExpandedView = inflater
@@ -118,12 +119,18 @@ class BubbleOverflow(
// Attach BubbleOverflow to BadgedImageView
overflowBtn.setRenderedBubble(this)
+ overflowBtn.removeDotSuppressionFlag(BadgedImageView.SuppressionFlag.FLYOUT_VISIBLE)
}
fun setVisible(visible: Int) {
overflowBtn.visibility = visible
}
+ fun setShowDot(show: Boolean) {
+ showDot = show
+ overflowBtn.updateDotVisibility(true /* animate */)
+ }
+
override fun getExpandedView(): BubbleExpandedView? {
return expandedView
}
@@ -141,7 +148,7 @@ class BubbleOverflow(
}
override fun showDot(): Boolean {
- return false
+ return showDot
}
override fun getDotPath(): Path? {
diff --git a/packages/SystemUI/src/com/android/systemui/bubbles/BubbleStackView.java b/packages/SystemUI/src/com/android/systemui/bubbles/BubbleStackView.java
index 55f96312d8a2..f2fba23564da 100644
--- a/packages/SystemUI/src/com/android/systemui/bubbles/BubbleStackView.java
+++ b/packages/SystemUI/src/com/android/systemui/bubbles/BubbleStackView.java
@@ -1162,6 +1162,16 @@ public class BubbleStackView extends FrameLayout
updateOverflowVisibility();
}
+ void updateOverflowButtonDot() {
+ for (Bubble b : mBubbleData.getOverflowBubbles()) {
+ if (b.showDot()) {
+ mBubbleOverflow.setShowDot(true);
+ return;
+ }
+ }
+ mBubbleOverflow.setShowDot(false);
+ }
+
/**
* Handle theme changes.
*/
@@ -1487,7 +1497,11 @@ public class BubbleStackView extends FrameLayout
if (v instanceof BadgedImageView
&& ((BadgedImageView) v).getKey().equals(bubble.getKey())) {
mBubbleContainer.removeViewAt(i);
- bubble.cleanupViews();
+ if (mBubbleData.hasOverflowBubbleWithKey(bubble.getKey())) {
+ bubble.cleanupExpandedView();
+ } else {
+ bubble.cleanupViews();
+ }
updatePointerPosition();
logBubbleEvent(bubble, SysUiStatsLog.BUBBLE_UICHANGED__ACTION__DISMISSED);
return;
diff --git a/packages/SystemUI/src/com/android/systemui/pip/phone/PipMotionHelper.java b/packages/SystemUI/src/com/android/systemui/pip/phone/PipMotionHelper.java
index dcee2a5b4b20..e24121928808 100644
--- a/packages/SystemUI/src/com/android/systemui/pip/phone/PipMotionHelper.java
+++ b/packages/SystemUI/src/com/android/systemui/pip/phone/PipMotionHelper.java
@@ -58,6 +58,7 @@ public class PipMotionHelper implements PipAppOpsListener.Callback,
private static final int EXPAND_STACK_TO_MENU_DURATION = 250;
private static final int LEAVE_PIP_DURATION = 300;
private static final int SHIFT_DURATION = 300;
+ private static final float STASH_RATIO = 0.25f;
/** Friction to use for PIP when it moves via physics fling animations. */
private static final float DEFAULT_FRICTION = 2f;
@@ -120,6 +121,8 @@ public class PipMotionHelper implements PipAppOpsListener.Callback,
/** FlingConfig instances provided to PhysicsAnimator for fling gestures. */
private PhysicsAnimator.FlingConfig mFlingConfigX;
private PhysicsAnimator.FlingConfig mFlingConfigY;
+ /** FlingConfig instances proviced to PhysicsAnimator for stashing. */
+ private PhysicsAnimator.FlingConfig mStashConfigX;
/** SpringConfig to use for fling-then-spring animations. */
private final PhysicsAnimator.SpringConfig mSpringConfig =
@@ -383,6 +386,21 @@ public class PipMotionHelper implements PipAppOpsListener.Callback,
void flingToSnapTarget(
float velocityX, float velocityY,
@Nullable Runnable updateAction, @Nullable Runnable endAction) {
+ movetoTarget(velocityX, velocityY, updateAction, endAction, false /* isStash */);
+ }
+
+ /**
+ * Stash PiP to the closest edge.
+ */
+ void stashToEdge(
+ float velocityX, float velocityY,
+ @Nullable Runnable updateAction, @Nullable Runnable endAction) {
+ movetoTarget(velocityX, velocityY, updateAction, endAction, true /* isStash */);
+ }
+
+ private void movetoTarget(
+ float velocityX, float velocityY,
+ @Nullable Runnable updateAction, @Nullable Runnable endAction, boolean isStash) {
// If we're flinging to a snap target now, we're not springing to catch up to the touch
// location now.
mSpringingToTouch = false;
@@ -391,8 +409,8 @@ public class PipMotionHelper implements PipAppOpsListener.Callback,
.spring(FloatProperties.RECT_WIDTH, mBounds.width(), mSpringConfig)
.spring(FloatProperties.RECT_HEIGHT, mBounds.height(), mSpringConfig)
.flingThenSpring(
- FloatProperties.RECT_X, velocityX, mFlingConfigX, mSpringConfig,
- true /* flingMustReachMinOrMax */)
+ FloatProperties.RECT_X, velocityX, isStash ? mStashConfigX : mFlingConfigX,
+ mSpringConfig, true /* flingMustReachMinOrMax */)
.flingThenSpring(
FloatProperties.RECT_Y, velocityY, mFlingConfigY, mSpringConfig)
.withEndActions(endAction);
@@ -402,7 +420,11 @@ public class PipMotionHelper implements PipAppOpsListener.Callback,
(target, values) -> updateAction.run());
}
- final float xEndValue = velocityX < 0 ? mMovementBounds.left : mMovementBounds.right;
+ final float offset = ((float) mBounds.width()) * (1.0f - STASH_RATIO);
+ final float leftEdge = isStash ? mMovementBounds.left - offset : mMovementBounds.left;
+ final float rightEdge = isStash ? mMovementBounds.right + offset : mMovementBounds.right;
+
+ final float xEndValue = velocityX < 0 ? leftEdge : rightEdge;
final float estimatedFlingYEndValue =
PhysicsAnimator.estimateFlingEndValue(
mTemporaryBounds.top, velocityY, mFlingConfigY);
@@ -506,6 +528,9 @@ public class PipMotionHelper implements PipAppOpsListener.Callback,
DEFAULT_FRICTION, mMovementBounds.left, mMovementBounds.right);
mFlingConfigY = new PhysicsAnimator.FlingConfig(
DEFAULT_FRICTION, mMovementBounds.top, mMovementBounds.bottom);
+ final float offset = ((float) mBounds.width()) * (1.0f - STASH_RATIO);
+ mStashConfigX = new PhysicsAnimator.FlingConfig(
+ DEFAULT_FRICTION, mMovementBounds.left - offset, mMovementBounds.right + offset);
}
/**
diff --git a/packages/SystemUI/src/com/android/systemui/pip/phone/PipTouchHandler.java b/packages/SystemUI/src/com/android/systemui/pip/phone/PipTouchHandler.java
index 97b3484292c6..858683c4e2d4 100644
--- a/packages/SystemUI/src/com/android/systemui/pip/phone/PipTouchHandler.java
+++ b/packages/SystemUI/src/com/android/systemui/pip/phone/PipTouchHandler.java
@@ -16,6 +16,7 @@
package com.android.systemui.pip.phone;
+import static com.android.internal.config.sysui.SystemUiDeviceConfigFlags.PIP_STASHING;
import static com.android.systemui.pip.PipAnimationController.TRANSITION_DIRECTION_TO_PIP;
import static com.android.systemui.pip.phone.PipMenuActivityController.MENU_STATE_CLOSE;
import static com.android.systemui.pip.phone.PipMenuActivityController.MENU_STATE_FULL;
@@ -33,6 +34,7 @@ import android.graphics.Rect;
import android.graphics.drawable.TransitionDrawable;
import android.os.Handler;
import android.os.RemoteException;
+import android.provider.DeviceConfig;
import android.util.Log;
import android.util.Size;
import android.view.Gravity;
@@ -102,6 +104,13 @@ public class PipTouchHandler {
private boolean mShowPipMenuOnAnimationEnd = false;
/**
+ * Whether PIP stash is enabled or not. When enabled, if at the time of fling-release the
+ * PIP bounds is outside the left/right edge of the screen, it will be shown in "stashed" mode,
+ * where PIP will only show partially.
+ */
+ private boolean mEnableStash = false;
+
+ /**
* MagnetizedObject wrapper for PIP. This allows the magnetic target library to locate and move
* PIP.
*/
@@ -306,6 +315,22 @@ public class PipTouchHandler {
});
mMagneticTargetAnimator = PhysicsAnimator.getInstance(mTargetView);
+
+ mEnableStash = DeviceConfig.getBoolean(
+ DeviceConfig.NAMESPACE_SYSTEMUI,
+ PIP_STASHING,
+ /* defaultValue = */ false);
+ deviceConfig.addOnPropertiesChangedListener(DeviceConfig.NAMESPACE_SYSTEMUI,
+ context.getMainExecutor(),
+ new DeviceConfig.OnPropertiesChangedListener() {
+ @Override
+ public void onPropertiesChanged(DeviceConfig.Properties properties) {
+ if (properties.getKeyset().contains(PIP_STASHING)) {
+ mEnableStash = properties.getBoolean(
+ PIP_STASHING, /* defaultValue = */ false);
+ }
+ }
+ });
}
private void reloadResources() {
@@ -986,9 +1011,20 @@ public class PipTouchHandler {
// Reset the touch state on up before the fling settles
mTouchState.reset();
- mMotionHelper.flingToSnapTarget(vel.x, vel.y,
- PipTouchHandler.this::updateDismissFraction /* updateAction */,
- this::flingEndAction /* endAction */);
+ final Rect animatingBounds = mMotionHelper.getPossiblyAnimatingBounds();
+ // If User releases the PIP window while it's out of the display bounds, put
+ // PIP into stashed mode.
+ if (mEnableStash
+ && (animatingBounds.right > mPipBoundsHandler.getDisplayBounds().right
+ || animatingBounds.left < mPipBoundsHandler.getDisplayBounds().left)) {
+ mMotionHelper.stashToEdge(vel.x, vel.y,
+ PipTouchHandler.this::updateDismissFraction /* updateAction */,
+ this::flingEndAction /* endAction */);
+ } else {
+ mMotionHelper.flingToSnapTarget(vel.x, vel.y,
+ PipTouchHandler.this::updateDismissFraction /* updateAction */,
+ this::flingEndAction /* endAction */);
+ }
} else if (mTouchState.isDoubleTap()) {
// Expand to fullscreen if this is a double tap
// the PiP should be frozen until the transition ends
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationConversationInfo.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationConversationInfo.java
index 7c7bb5c83762..b19997d15664 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationConversationInfo.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationConversationInfo.java
@@ -42,6 +42,8 @@ import android.content.pm.ApplicationInfo;
import android.content.pm.PackageManager;
import android.content.pm.ShortcutInfo;
import android.content.pm.ShortcutManager;
+import android.content.res.TypedArray;
+import android.graphics.drawable.Drawable;
import android.os.Handler;
import android.os.RemoteException;
import android.os.UserHandle;
@@ -538,12 +540,21 @@ public class NotificationConversationInfo extends LinearLayout implements
&& Settings.Global.getInt(mContext.getContentResolver(),
NOTIFICATION_BUBBLES, 0) == 1;
+ Drawable person = mIconFactory.getBaseIconDrawable(mShortcutInfo);
+ if (person == null) {
+ person = mContext.getDrawable(R.drawable.ic_person).mutate();
+ TypedArray ta = mContext.obtainStyledAttributes(new int[]{android.R.attr.colorAccent});
+ int colorAccent = ta.getColor(0, 0);
+ ta.recycle();
+ person.setTint(colorAccent);
+ }
+
PriorityOnboardingDialogController controller = mBuilderProvider.get()
.setContext(mUserContext)
.setView(onboardingView)
.setIgnoresDnd(ignoreDnd)
.setShowsAsBubble(showAsBubble)
- .setIcon(mIconFactory.getBaseIconDrawable(mShortcutInfo))
+ .setIcon(person)
.setBadge(mIconFactory.getAppBadge(
mPackageName, UserHandle.getUserId(mSbn.getUid())))
.setOnSettingsClick(mOnConversationSettingsClickListener)
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBar.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBar.java
index 31c1a5e5a9aa..8254b7f5b32a 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBar.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBar.java
@@ -1848,7 +1848,7 @@ public class StatusBar extends SystemUI implements DemoMode,
mStatusBarStateController.setPanelExpanded(isExpanded);
if (isExpanded && mStatusBarStateController.getState() != StatusBarState.KEYGUARD) {
if (DEBUG) {
- Log.v(TAG, "clearing notification effects from setExpandedHeight");
+ Log.v(TAG, "clearing notification effects from Height");
}
clearNotificationEffects();
}
@@ -2809,6 +2809,7 @@ public class StatusBar extends SystemUI implements DemoMode,
private final BroadcastReceiver mBroadcastReceiver = new BroadcastReceiver() {
@Override
public void onReceive(Context context, Intent intent) {
+ Trace.beginSection("StatusBar#onReceive");
if (DEBUG) Log.v(TAG, "onReceive: " + intent);
String action = intent.getAction();
if (Intent.ACTION_CLOSE_SYSTEM_DIALOGS.equals(action)) {
@@ -2833,7 +2834,8 @@ public class StatusBar extends SystemUI implements DemoMode,
mNotificationShadeWindowController.setNotTouchable(false);
}
if (mBubbleController.isStackExpanded()) {
- mBubbleController.collapseStack();
+ // Post to main thread handler, since updating the UI.
+ mMainThreadHandler.post(() -> mBubbleController.collapseStack());
}
finishBarAnimations();
resetUserExpandedStates();
@@ -2841,6 +2843,7 @@ public class StatusBar extends SystemUI implements DemoMode,
else if (DevicePolicyManager.ACTION_SHOW_DEVICE_MONITORING_DIALOG.equals(action)) {
mQSPanel.showDeviceMonitoringDialog();
}
+ Trace.endSection();
}
};
diff --git a/packages/SystemUI/src/com/android/systemui/volume/VolumeDialogControllerImpl.java b/packages/SystemUI/src/com/android/systemui/volume/VolumeDialogControllerImpl.java
index d8eecef024ce..3aba7ca1ad7c 100644
--- a/packages/SystemUI/src/com/android/systemui/volume/VolumeDialogControllerImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/volume/VolumeDialogControllerImpl.java
@@ -76,6 +76,7 @@ import java.util.HashMap;
import java.util.Map;
import java.util.Objects;
import java.util.Optional;
+import java.util.concurrent.ConcurrentHashMap;
import javax.inject.Inject;
@@ -829,7 +830,7 @@ public class VolumeDialogControllerImpl implements VolumeDialogController, Dumpa
}
class C implements Callbacks {
- private final HashMap<Callbacks, Handler> mCallbackMap = new HashMap<>();
+ private final Map<Callbacks, Handler> mCallbackMap = new ConcurrentHashMap<>();
public void add(Callbacks callback, Handler handler) {
if (callback == null || handler == null) throw new IllegalArgumentException();
diff --git a/packages/SystemUI/src/com/android/systemui/wmshell/WMShell.java b/packages/SystemUI/src/com/android/systemui/wmshell/WMShell.java
index 6f681e8cc6c7..da7713acfc32 100644
--- a/packages/SystemUI/src/com/android/systemui/wmshell/WMShell.java
+++ b/packages/SystemUI/src/com/android/systemui/wmshell/WMShell.java
@@ -82,6 +82,9 @@ public final class WMShell extends SystemUI implements ProtoTraceable<SystemUiTr
private final ShellTaskOrganizer mShellTaskOrganizer;
private final ProtoTracer mProtoTracer;
+ private KeyguardUpdateMonitorCallback mSplitScreenKeyguardCallback;
+ private KeyguardUpdateMonitorCallback mOneHandedKeyguardCallback;
+
@Inject
public WMShell(Context context, CommandQueue commandQueue,
KeyguardUpdateMonitor keyguardUpdateMonitor,
@@ -134,7 +137,7 @@ public final class WMShell extends SystemUI implements ProtoTraceable<SystemUiTr
@VisibleForTesting
void initSplitScreen(SplitScreen splitScreen) {
- mKeyguardUpdateMonitor.registerCallback(new KeyguardUpdateMonitorCallback() {
+ mSplitScreenKeyguardCallback = new KeyguardUpdateMonitorCallback() {
@Override
public void onKeyguardVisibilityChanged(boolean showing) {
// Hide the divider when keyguard is showing. Even though keyguard/statusbar is
@@ -143,7 +146,8 @@ public final class WMShell extends SystemUI implements ProtoTraceable<SystemUiTr
// TODO(b/148906453): Figure out keyguard dismiss animation for divider view.
splitScreen.onKeyguardVisibilityChanged(showing);
}
- });
+ };
+ mKeyguardUpdateMonitor.registerCallback(mSplitScreenKeyguardCallback);
mActivityManagerWrapper.registerTaskStackListener(
new TaskStackChangeListener() {
@@ -223,7 +227,7 @@ public final class WMShell extends SystemUI implements ProtoTraceable<SystemUiTr
}
});
- mKeyguardUpdateMonitor.registerCallback(new KeyguardUpdateMonitorCallback() {
+ mOneHandedKeyguardCallback = new KeyguardUpdateMonitorCallback() {
@Override
public void onKeyguardBouncerChanged(boolean bouncer) {
if (bouncer) {
@@ -235,7 +239,8 @@ public final class WMShell extends SystemUI implements ProtoTraceable<SystemUiTr
public void onKeyguardVisibilityChanged(boolean showing) {
oneHanded.stopOneHanded();
}
- });
+ };
+ mKeyguardUpdateMonitor.registerCallback(mOneHandedKeyguardCallback);
mScreenLifecycle.addObserver(new ScreenLifecycle.Observer() {
@Override
diff --git a/services/accessibility/java/com/android/server/accessibility/magnification/WindowMagnificationManager.java b/services/accessibility/java/com/android/server/accessibility/magnification/WindowMagnificationManager.java
index d3d56d7f857d..9cbd78bf4482 100644
--- a/services/accessibility/java/com/android/server/accessibility/magnification/WindowMagnificationManager.java
+++ b/services/accessibility/java/com/android/server/accessibility/magnification/WindowMagnificationManager.java
@@ -68,6 +68,7 @@ public class WindowMagnificationManager implements
private SparseArray<WindowMagnifier> mWindowMagnifiers = new SparseArray<>();
private int mUserId;
+ private boolean mReceiverRegistered = false;
@VisibleForTesting
protected final BroadcastReceiver mScreenStateReceiver = new BroadcastReceiver() {
@Override
@@ -150,10 +151,16 @@ public class WindowMagnificationManager implements
}
if (connect) {
final IntentFilter intentFilter = new IntentFilter(Intent.ACTION_SCREEN_OFF);
- mContext.registerReceiver(mScreenStateReceiver, intentFilter);
+ if (!mReceiverRegistered) {
+ mContext.registerReceiver(mScreenStateReceiver, intentFilter);
+ mReceiverRegistered = true;
+ }
} else {
disableAllWindowMagnifiers();
- mContext.unregisterReceiver(mScreenStateReceiver);
+ if (mReceiverRegistered) {
+ mContext.unregisterReceiver(mScreenStateReceiver);
+ mReceiverRegistered = false;
+ }
}
}
@@ -240,6 +247,9 @@ public class WindowMagnificationManager implements
void enableWindowMagnification(int displayId, float scale, float centerX, float centerY,
@Nullable Runnable endCallback) {
synchronized (mLock) {
+ if (mConnectionWrapper == null) {
+ return;
+ }
WindowMagnifier magnifier = mWindowMagnifiers.get(displayId);
if (magnifier == null) {
magnifier = createWindowMagnifier(displayId);
@@ -269,7 +279,7 @@ public class WindowMagnificationManager implements
void disableWindowMagnification(int displayId, boolean clear, Runnable endCallback) {
synchronized (mLock) {
WindowMagnifier magnifier = mWindowMagnifiers.get(displayId);
- if (magnifier == null) {
+ if (magnifier == null || mConnectionWrapper == null) {
return;
}
magnifier.disableWindowMagnificationInternal(endCallback);
diff --git a/services/core/java/com/android/server/ConnectivityService.java b/services/core/java/com/android/server/ConnectivityService.java
index bd590d317910..bc79a6a5817b 100644
--- a/services/core/java/com/android/server/ConnectivityService.java
+++ b/services/core/java/com/android/server/ConnectivityService.java
@@ -16,6 +16,7 @@
package com.android.server;
+import static android.Manifest.permission.NETWORK_STACK;
import static android.Manifest.permission.RECEIVE_DATA_ACTIVITY_CHANGE;
import static android.content.pm.PackageManager.PERMISSION_GRANTED;
import static android.net.ConnectivityDiagnosticsManager.ConnectivityReport.KEY_NETWORK_PROBES_ATTEMPTED_BITMASK;
@@ -1136,6 +1137,12 @@ public class ConnectivityService extends IConnectivityManager.Stub
null /* broadcastPermission */,
mHandler);
+ // Listen to lockdown VPN reset.
+ intentFilter = new IntentFilter();
+ intentFilter.addAction(LockdownVpnTracker.ACTION_LOCKDOWN_RESET);
+ mContext.registerReceiverAsUser(
+ mIntentReceiver, UserHandle.ALL, intentFilter, NETWORK_STACK, mHandler);
+
try {
mNMS.registerObserver(mDataActivityObserver);
} catch (RemoteException e) {
@@ -5204,6 +5211,12 @@ public class ConnectivityService extends IConnectivityManager.Stub
}
}
+ private void onVpnLockdownReset() {
+ synchronized (mVpns) {
+ if (mLockdownTracker != null) mLockdownTracker.reset();
+ }
+ }
+
private BroadcastReceiver mIntentReceiver = new BroadcastReceiver() {
@Override
public void onReceive(Context context, Intent intent) {
@@ -5214,6 +5227,12 @@ public class ConnectivityService extends IConnectivityManager.Stub
final Uri packageData = intent.getData();
final String packageName =
packageData != null ? packageData.getSchemeSpecificPart() : null;
+
+ if (LockdownVpnTracker.ACTION_LOCKDOWN_RESET.equals(action)) {
+ onVpnLockdownReset();
+ }
+
+ // UserId should be filled for below intents, check the existence.
if (userId == UserHandle.USER_NULL) return;
if (Intent.ACTION_USER_STARTED.equals(action)) {
@@ -5232,6 +5251,8 @@ public class ConnectivityService extends IConnectivityManager.Stub
final boolean isReplacing = intent.getBooleanExtra(
Intent.EXTRA_REPLACING, false);
onPackageRemoved(packageName, uid, isReplacing);
+ } else {
+ Log.wtf(TAG, "received unexpected intent: " + action);
}
}
};
diff --git a/services/core/java/com/android/server/appop/AppOpsService.java b/services/core/java/com/android/server/appop/AppOpsService.java
index b56b09d707af..06f44b1bd388 100644
--- a/services/core/java/com/android/server/appop/AppOpsService.java
+++ b/services/core/java/com/android/server/appop/AppOpsService.java
@@ -39,6 +39,7 @@ import static android.app.AppOpsManager.OP_FLAG_TRUSTED_PROXIED;
import static android.app.AppOpsManager.OP_NONE;
import static android.app.AppOpsManager.OP_PLAY_AUDIO;
import static android.app.AppOpsManager.OP_RECORD_AUDIO;
+import static android.app.AppOpsManager.OP_RECORD_AUDIO_HOTWORD;
import static android.app.AppOpsManager.OpEventProxyInfo;
import static android.app.AppOpsManager.RestrictionBypass;
import static android.app.AppOpsManager.SAMPLING_STRATEGY_BOOT_TIME_SAMPLING;
@@ -3428,7 +3429,19 @@ public class AppOpsService extends IAppOpsService.Stub {
String resolvedPackageName = resolvePackageName(uid, packageName);
if (resolvedPackageName == null) {
- return AppOpsManager.MODE_IGNORED;
+ return AppOpsManager.MODE_IGNORED;
+ }
+
+ // As a special case for OP_RECORD_AUDIO_HOTWORD, which we use only for attribution
+ // purposes and not as a check, also make sure that the caller is allowed to access
+ // the data gated by OP_RECORD_AUDIO.
+ //
+ // TODO: Revert this change before Android 12.
+ if (code == OP_RECORD_AUDIO_HOTWORD) {
+ int result = checkOperation(OP_RECORD_AUDIO, uid, packageName);
+ if (result != AppOpsManager.MODE_ALLOWED) {
+ return result;
+ }
}
RestrictionBypass bypass;
diff --git a/services/core/java/com/android/server/hdmi/Constants.java b/services/core/java/com/android/server/hdmi/Constants.java
index 713f8008e313..425fbc5687ec 100644
--- a/services/core/java/com/android/server/hdmi/Constants.java
+++ b/services/core/java/com/android/server/hdmi/Constants.java
@@ -329,6 +329,30 @@ final class Constants {
static final int INVALID_PHYSICAL_ADDRESS = HdmiDeviceInfo.PATH_INVALID;
static final int PATH_INTERNAL = HdmiDeviceInfo.PATH_INTERNAL;
+ // The relationship from one path (physical address) to another.
+ @IntDef({
+ PATH_RELATIONSHIP_UNKNOWN,
+ PATH_RELATIONSHIP_DIFFERENT_BRANCH,
+ PATH_RELATIONSHIP_ANCESTOR,
+ PATH_RELATIONSHIP_DESCENDANT,
+ PATH_RELATIONSHIP_SIBLING,
+ PATH_RELATIONSHIP_SAME
+ })
+ @interface PathRelationship {}
+
+ // One or both of the paths is invalid
+ static final int PATH_RELATIONSHIP_UNKNOWN = 0;
+ // None of the relationships below holds
+ static final int PATH_RELATIONSHIP_DIFFERENT_BRANCH = 1;
+ // A path is either the TV, or between the TV and another path
+ static final int PATH_RELATIONSHIP_ANCESTOR = 2;
+ // A path is located somewhere below another path
+ static final int PATH_RELATIONSHIP_DESCENDANT = 3;
+ // A path has the same parent as another path
+ static final int PATH_RELATIONSHIP_SIBLING = 4;
+ // A path is equal to another path
+ static final int PATH_RELATIONSHIP_SAME = 5;
+
// Strategy for device polling.
// Should use "OR(|) operation of POLL_STRATEGY_XXX and POLL_ITERATION_XXX.
static final int POLL_STRATEGY_MASK = 0x3; // first and second bit.
diff --git a/services/core/java/com/android/server/hdmi/HdmiUtils.java b/services/core/java/com/android/server/hdmi/HdmiUtils.java
index cd65db6055af..a6951ef1958f 100644
--- a/services/core/java/com/android/server/hdmi/HdmiUtils.java
+++ b/services/core/java/com/android/server/hdmi/HdmiUtils.java
@@ -24,10 +24,11 @@ import android.util.Xml;
import com.android.internal.util.HexDump;
import com.android.internal.util.IndentingPrintWriter;
-
import com.android.server.hdmi.Constants.AbortReason;
import com.android.server.hdmi.Constants.AudioCodec;
import com.android.server.hdmi.Constants.FeatureOpcode;
+import com.android.server.hdmi.Constants.PathRelationship;
+
import org.xmlpull.v1.XmlPullParser;
import org.xmlpull.v1.XmlPullParserException;
@@ -311,26 +312,43 @@ final class HdmiUtils {
* @return true if the new path in the active routing path
*/
static boolean isInActiveRoutingPath(int activePath, int newPath) {
- // Check each nibble of the currently active path and the new path till the position
- // where the active nibble is not zero. For (activePath, newPath),
- // (1.1.0.0, 1.0.0.0) -> true, new path is a parent
- // (1.2.1.0, 1.2.1.2) -> true, new path is a descendant
- // (1.1.0.0, 1.2.0.0) -> false, new path is a sibling
- // (1.0.0.0, 2.0.0.0) -> false, in a completely different path
- for (int i = 12; i >= 0; i -= 4) {
- int nibbleActive = (activePath >> i) & 0xF;
- if (nibbleActive == 0) {
- break;
- }
- int nibbleNew = (newPath >> i) & 0xF;
- if (nibbleNew == 0) {
- break;
- }
- if (nibbleActive != nibbleNew) {
- return false;
+ @PathRelationship int pathRelationship = pathRelationship(newPath, activePath);
+ return (pathRelationship == Constants.PATH_RELATIONSHIP_ANCESTOR
+ || pathRelationship == Constants.PATH_RELATIONSHIP_DESCENDANT
+ || pathRelationship == Constants.PATH_RELATIONSHIP_SAME);
+ }
+
+ /**
+ * Computes the relationship from the first path to the second path.
+ */
+ static @PathRelationship int pathRelationship(int firstPath, int secondPath) {
+ if (firstPath == Constants.INVALID_PHYSICAL_ADDRESS
+ || secondPath == Constants.INVALID_PHYSICAL_ADDRESS) {
+ return Constants.PATH_RELATIONSHIP_UNKNOWN;
+ }
+ // Loop forwards through both paths, looking for the first nibble where the paths differ.
+ // Checking this nibble and the next one distinguishes between most possible relationships.
+ for (int nibbleIndex = 0; nibbleIndex <= 3; nibbleIndex++) {
+ int shift = 12 - nibbleIndex * 4;
+ int firstPathNibble = (firstPath >> shift) & 0xF;
+ int secondPathNibble = (secondPath >> shift) & 0xF;
+ // Found the first nibble where the paths differ.
+ if (firstPathNibble != secondPathNibble) {
+ int firstPathNextNibble = (firstPath >> (shift - 4)) & 0xF;
+ int secondPathNextNibble = (secondPath >> (shift - 4)) & 0xF;
+ if (firstPathNibble == 0) {
+ return Constants.PATH_RELATIONSHIP_ANCESTOR;
+ } else if (secondPathNibble == 0) {
+ return Constants.PATH_RELATIONSHIP_DESCENDANT;
+ } else if (nibbleIndex == 3
+ || (firstPathNextNibble == 0 && secondPathNextNibble == 0)) {
+ return Constants.PATH_RELATIONSHIP_SIBLING;
+ } else {
+ return Constants.PATH_RELATIONSHIP_DIFFERENT_BRANCH;
+ }
}
}
- return true;
+ return Constants.PATH_RELATIONSHIP_SAME;
}
/**
diff --git a/services/core/java/com/android/server/location/LocationManagerService.java b/services/core/java/com/android/server/location/LocationManagerService.java
index f4d0a6254318..807784dde505 100644
--- a/services/core/java/com/android/server/location/LocationManagerService.java
+++ b/services/core/java/com/android/server/location/LocationManagerService.java
@@ -553,8 +553,9 @@ public class LocationManagerService extends ILocationManager.Stub {
}
@Override
- public void registerLocationListener(LocationRequest request, ILocationListener listener,
- String packageName, String attributionTag, String listenerId) {
+ public void registerLocationListener(String provider, LocationRequest request,
+ ILocationListener listener, String packageName, String attributionTag,
+ String listenerId) {
CallerIdentity identity = CallerIdentity.fromBinder(mContext, packageName, attributionTag,
listenerId);
int permissionLevel = LocationPermissions.getPermissionLevel(mContext, identity.getUid(),
@@ -570,16 +571,16 @@ public class LocationManagerService extends ILocationManager.Stub {
request = validateAndSanitizeLocationRequest(request, permissionLevel);
- LocationProviderManager manager = getLocationProviderManager(request.getProvider());
+ LocationProviderManager manager = getLocationProviderManager(provider);
Preconditions.checkArgument(manager != null,
- "provider \"" + request.getProvider() + "\" does not exist");
+ "provider \"" + provider + "\" does not exist");
manager.registerLocationRequest(request, identity, permissionLevel, listener);
}
@Override
- public void registerLocationPendingIntent(LocationRequest request, PendingIntent pendingIntent,
- String packageName, String attributionTag) {
+ public void registerLocationPendingIntent(String provider, LocationRequest request,
+ PendingIntent pendingIntent, String packageName, String attributionTag) {
CallerIdentity identity = CallerIdentity.fromBinder(mContext, packageName, attributionTag,
AppOpsManager.toReceiverId(pendingIntent));
int permissionLevel = LocationPermissions.getPermissionLevel(mContext, identity.getUid(),
@@ -592,24 +593,22 @@ public class LocationManagerService extends ILocationManager.Stub {
request = validateAndSanitizeLocationRequest(request, permissionLevel);
- LocationProviderManager manager = getLocationProviderManager(request.getProvider());
+ LocationProviderManager manager = getLocationProviderManager(provider);
Preconditions.checkArgument(manager != null,
- "provider \"" + request.getProvider() + "\" does not exist");
+ "provider \"" + provider + "\" does not exist");
manager.registerLocationRequest(request, identity, permissionLevel, pendingIntent);
}
private LocationRequest validateAndSanitizeLocationRequest(LocationRequest request,
@PermissionLevel int permissionLevel) {
- Objects.requireNonNull(request.getProvider());
-
WorkSource workSource = request.getWorkSource();
if (workSource != null && !workSource.isEmpty()) {
mContext.enforceCallingOrSelfPermission(
permission.UPDATE_DEVICE_STATS,
"setting a work source requires " + permission.UPDATE_DEVICE_STATS);
}
- if (request.getHideFromAppOps()) {
+ if (request.isHiddenFromAppOps()) {
mContext.enforceCallingOrSelfPermission(
permission.UPDATE_APP_OPS_STATS,
"hiding from app ops requires " + permission.UPDATE_APP_OPS_STATS);
@@ -620,12 +619,12 @@ public class LocationManagerService extends ILocationManager.Stub {
"ignoring location settings requires " + permission.WRITE_SECURE_SETTINGS);
}
- LocationRequest sanitized = new LocationRequest(request);
+ LocationRequest.Builder sanitized = new LocationRequest.Builder(request);
if (mContext.checkCallingPermission(permission.LOCATION_HARDWARE) != PERMISSION_GRANTED) {
- sanitized.setLowPowerMode(false);
+ sanitized.setLowPower(false);
}
if (permissionLevel < PERMISSION_FINE) {
- switch (sanitized.getQuality()) {
+ switch (request.getQuality()) {
case LocationRequest.ACCURACY_FINE:
sanitized.setQuality(LocationRequest.ACCURACY_BLOCK);
break;
@@ -634,24 +633,21 @@ public class LocationManagerService extends ILocationManager.Stub {
break;
}
- if (sanitized.getInterval() < FASTEST_COARSE_INTERVAL_MS) {
- sanitized.setInterval(FASTEST_COARSE_INTERVAL_MS);
+ if (request.getIntervalMillis() < FASTEST_COARSE_INTERVAL_MS) {
+ sanitized.setIntervalMillis(FASTEST_COARSE_INTERVAL_MS);
}
- if (sanitized.getFastestInterval() < FASTEST_COARSE_INTERVAL_MS) {
- sanitized.setFastestInterval(FASTEST_COARSE_INTERVAL_MS);
+ if (request.getMinUpdateIntervalMillis() < FASTEST_COARSE_INTERVAL_MS) {
+ sanitized.clearMinUpdateIntervalMillis();
}
}
- if (sanitized.getFastestInterval() > sanitized.getInterval()) {
- sanitized.setFastestInterval(request.getInterval());
- }
- if (sanitized.getWorkSource() != null) {
- if (sanitized.getWorkSource().isEmpty()) {
+ if (request.getWorkSource() != null) {
+ if (request.getWorkSource().isEmpty()) {
sanitized.setWorkSource(null);
- } else if (sanitized.getWorkSource().getPackageName(0) == null) {
+ } else if (request.getWorkSource().getPackageName(0) == null) {
Log.w(TAG, "received (and ignoring) illegal worksource with no package name");
sanitized.setWorkSource(null);
} else {
- List<WorkChain> workChains = sanitized.getWorkSource().getWorkChains();
+ List<WorkChain> workChains = request.getWorkSource().getWorkChains();
if (workChains != null && !workChains.isEmpty() && workChains.get(
0).getAttributionTag() == null) {
Log.w(TAG,
@@ -661,7 +657,7 @@ public class LocationManagerService extends ILocationManager.Stub {
}
}
- return sanitized;
+ return sanitized.build();
}
@Override
@@ -679,8 +675,7 @@ public class LocationManagerService extends ILocationManager.Stub {
}
@Override
- public Location getLastLocation(LocationRequest request, String packageName,
- String attributionTag) {
+ public Location getLastLocation(String provider, String packageName, String attributionTag) {
CallerIdentity identity = CallerIdentity.fromBinder(mContext, packageName, attributionTag);
int permissionLevel = LocationPermissions.getPermissionLevel(mContext, identity.getUid(),
identity.getPid());
@@ -690,15 +685,12 @@ public class LocationManagerService extends ILocationManager.Stub {
// clients in the system process must have an attribution tag set
Preconditions.checkArgument(identity.getPid() != Process.myPid() || attributionTag != null);
- request = validateAndSanitizeLocationRequest(request, permissionLevel);
-
- LocationProviderManager manager = getLocationProviderManager(request.getProvider());
+ LocationProviderManager manager = getLocationProviderManager(provider);
if (manager == null) {
return null;
}
- Location location = manager.getLastLocation(identity, permissionLevel,
- request.isLocationSettingsIgnored());
+ Location location = manager.getLastLocation(identity, permissionLevel, false);
// lastly - note app ops
if (!mInjector.getAppOpsHelper().noteOpNoThrow(LocationPermissions.asAppOp(permissionLevel),
@@ -710,7 +702,7 @@ public class LocationManagerService extends ILocationManager.Stub {
}
@Override
- public void getCurrentLocation(LocationRequest request,
+ public void getCurrentLocation(String provider, LocationRequest request,
ICancellationSignal cancellationTransport, ILocationCallback consumer,
String packageName, String attributionTag, String listenerId) {
CallerIdentity identity = CallerIdentity.fromBinder(mContext, packageName, attributionTag,
@@ -725,9 +717,9 @@ public class LocationManagerService extends ILocationManager.Stub {
request = validateAndSanitizeLocationRequest(request, permissionLevel);
- LocationProviderManager manager = getLocationProviderManager(request.getProvider());
+ LocationProviderManager manager = getLocationProviderManager(provider);
Preconditions.checkArgument(manager != null,
- "provider \"" + request.getProvider() + "\" does not exist");
+ "provider \"" + provider + "\" does not exist");
manager.getCurrentLocation(request, identity, permissionLevel, cancellationTransport,
consumer);
diff --git a/services/core/java/com/android/server/location/LocationProviderManager.java b/services/core/java/com/android/server/location/LocationProviderManager.java
index 1815a8554705..830548b044a6 100644
--- a/services/core/java/com/android/server/location/LocationProviderManager.java
+++ b/services/core/java/com/android/server/location/LocationProviderManager.java
@@ -291,7 +291,7 @@ class LocationProviderManager extends
@Override
protected final ListenerOperation<LocationTransport> onActive() {
- if (!getRequest().getHideFromAppOps()) {
+ if (!getRequest().isHiddenFromAppOps()) {
mLocationAttributionHelper.reportLocationStart(getIdentity(), getName(), getKey());
}
onHighPowerUsageChanged();
@@ -301,7 +301,7 @@ class LocationProviderManager extends
@Override
protected final ListenerOperation<LocationTransport> onInactive() {
onHighPowerUsageChanged();
- if (!getRequest().getHideFromAppOps()) {
+ if (!getRequest().isHiddenFromAppOps()) {
mLocationAttributionHelper.reportLocationStop(getIdentity(), getName(), getKey());
}
return null;
@@ -343,7 +343,7 @@ class LocationProviderManager extends
if (isUsingHighPower != mIsUsingHighPower) {
mIsUsingHighPower = isUsingHighPower;
- if (!getRequest().getHideFromAppOps()) {
+ if (!getRequest().isHiddenFromAppOps()) {
if (mIsUsingHighPower) {
mLocationAttributionHelper.reportHighPowerLocationStart(
getIdentity(), getName(), getKey());
@@ -362,7 +362,7 @@ class LocationProviderManager extends
}
return isActive()
- && getRequest().getInterval() < MAX_HIGH_POWER_INTERVAL_MS
+ && getRequest().getIntervalMillis() < MAX_HIGH_POWER_INTERVAL_MS
&& getProperties().mPowerRequirement == Criteria.POWER_HIGH;
}
@@ -448,26 +448,26 @@ class LocationProviderManager extends
}
private LocationRequest calculateProviderLocationRequest() {
- LocationRequest newRequest = new LocationRequest(super.getRequest());
+ LocationRequest.Builder builder = new LocationRequest.Builder(super.getRequest());
- if (newRequest.isLocationSettingsIgnored()) {
+ if (super.getRequest().isLocationSettingsIgnored()) {
// if we are not currently allowed use location settings ignored, disable it
if (!mSettingsHelper.getIgnoreSettingsPackageWhitelist().contains(
getIdentity().getPackageName()) && !mLocationManagerInternal.isProvider(
null, getIdentity())) {
- newRequest.setLocationSettingsIgnored(false);
+ builder.setLocationSettingsIgnored(false);
}
}
- if (!newRequest.isLocationSettingsIgnored() && !isThrottlingExempt()) {
+ if (!super.getRequest().isLocationSettingsIgnored() && !isThrottlingExempt()) {
// throttle in the background
if (!mForeground) {
- newRequest.setInterval(Math.max(newRequest.getInterval(),
+ builder.setIntervalMillis(Math.max(super.getRequest().getIntervalMillis(),
mSettingsHelper.getBackgroundThrottleIntervalMs()));
}
}
- return newRequest;
+ return builder.build();
}
private boolean isThrottlingExempt() {
@@ -635,14 +635,15 @@ class LocationProviderManager extends
long deltaMs = NANOSECONDS.toMillis(
location.getElapsedRealtimeNanos()
- mLastLocation.getElapsedRealtimeNanos());
- if (deltaMs < getRequest().getFastestInterval() - MAX_FASTEST_INTERVAL_JITTER_MS) {
+ if (deltaMs < getRequest().getMinUpdateIntervalMillis()
+ - MAX_FASTEST_INTERVAL_JITTER_MS) {
return null;
}
// check smallest displacement
- double smallestDisplacement = getRequest().getSmallestDisplacement();
- if (smallestDisplacement > 0.0 && location.distanceTo(mLastLocation)
- <= smallestDisplacement) {
+ double smallestDisplacementM = getRequest().getMinUpdateDistanceMeters();
+ if (smallestDisplacementM > 0.0 && location.distanceTo(mLastLocation)
+ <= smallestDisplacementM) {
return null;
}
}
@@ -692,7 +693,7 @@ class LocationProviderManager extends
if (success) {
// check num updates - if successful then this function will always be run
// from the same thread, and no additional synchronization is necessary
- boolean remove = ++mNumLocationsDelivered >= getRequest().getNumUpdates();
+ boolean remove = ++mNumLocationsDelivered >= getRequest().getMaxUpdates();
if (remove) {
if (D) {
Log.d(TAG, "removing " + getIdentity() + " from " + mName
@@ -1326,10 +1327,10 @@ class LocationProviderManager extends
public void getCurrentLocation(LocationRequest request, CallerIdentity callerIdentity,
int permissionLevel, ICancellationSignal cancellationTransport,
ILocationCallback callback) {
- Preconditions.checkArgument(mName.equals(request.getProvider()));
-
- if (request.getExpireIn() > GET_CURRENT_LOCATION_MAX_TIMEOUT_MS) {
- request.setExpireIn(GET_CURRENT_LOCATION_MAX_TIMEOUT_MS);
+ if (request.getDurationMillis() > GET_CURRENT_LOCATION_MAX_TIMEOUT_MS) {
+ request = new LocationRequest.Builder(request)
+ .setDurationMillis(GET_CURRENT_LOCATION_MAX_TIMEOUT_MS)
+ .build();
}
GetCurrentLocationListenerRegistration registration =
@@ -1404,8 +1405,6 @@ class LocationProviderManager extends
public void registerLocationRequest(LocationRequest request, CallerIdentity callerIdentity,
@PermissionLevel int permissionLevel, ILocationListener listener) {
- Preconditions.checkArgument(mName.equals(request.getProvider()));
-
synchronized (mLock) {
long identity = Binder.clearCallingIdentity();
try {
@@ -1424,8 +1423,6 @@ class LocationProviderManager extends
public void registerLocationRequest(LocationRequest request, CallerIdentity callerIdentity,
@PermissionLevel int permissionLevel, PendingIntent pendingIntent) {
- Preconditions.checkArgument(mName.equals(request.getProvider()));
-
synchronized (mLock) {
long identity = Binder.clearCallingIdentity();
try {
@@ -1517,17 +1514,17 @@ class LocationProviderManager extends
LocationStatsEnums.USAGE_STARTED,
LocationStatsEnums.API_REQUEST_LOCATION_UPDATES,
registration.getIdentity().getPackageName(),
+ mName,
registration.getRequest(),
key instanceof PendingIntent,
- key instanceof IBinder,
- /* geofence= */ null,
- registration.isForeground());
+ /* geofence= */ key instanceof IBinder,
+ null, registration.isForeground());
mLocationRequestStatistics.startRequesting(
registration.getIdentity().getPackageName(),
registration.getIdentity().getAttributionTag(),
mName,
- registration.getRequest().getInterval(),
+ registration.getRequest().getIntervalMillis(),
registration.isForeground());
}
@@ -1547,11 +1544,11 @@ class LocationProviderManager extends
LocationStatsEnums.USAGE_ENDED,
LocationStatsEnums.API_REQUEST_LOCATION_UPDATES,
registration.getIdentity().getPackageName(),
+ mName,
registration.getRequest(),
key instanceof PendingIntent,
- key instanceof IBinder,
- /* geofence= */ null,
- registration.isForeground());
+ /* geofence= */ key instanceof IBinder,
+ null, registration.isForeground());
}
@GuardedBy("mLock")
@@ -1643,15 +1640,20 @@ class LocationProviderManager extends
for (Registration registration : registrations) {
LocationRequest locationRequest = registration.getRequest();
+ // passive requests do not contribute to the provider
+ if (locationRequest.getIntervalMillis() == LocationRequest.PASSIVE_INTERVAL) {
+ continue;
+ }
+
if (locationRequest.isLocationSettingsIgnored()) {
providerRequest.setLocationSettingsIgnored(true);
}
- if (!locationRequest.isLowPowerMode()) {
+ if (!locationRequest.isLowPower()) {
providerRequest.setLowPowerMode(false);
}
providerRequest.setInterval(
- Math.min(locationRequest.getInterval(), providerRequest.getInterval()));
+ Math.min(locationRequest.getIntervalMillis(), providerRequest.getInterval()));
providerRegistrations.add(registration);
}
@@ -1674,7 +1676,7 @@ class LocationProviderManager extends
}
for (int i = 0; i < registrationsSize; i++) {
LocationRequest request = providerRegistrations.get(i).getRequest();
- if (request.getInterval() <= thresholdIntervalMs) {
+ if (request.getIntervalMillis() <= thresholdIntervalMs) {
providerRequest.getWorkSource().add(providerRegistrations.get(i).getWorkSource());
}
}
diff --git a/services/core/java/com/android/server/location/PassiveLocationProviderManager.java b/services/core/java/com/android/server/location/PassiveLocationProviderManager.java
index d4999ab8be0a..92ef5b7c73a8 100644
--- a/services/core/java/com/android/server/location/PassiveLocationProviderManager.java
+++ b/services/core/java/com/android/server/location/PassiveLocationProviderManager.java
@@ -20,11 +20,16 @@ import android.annotation.Nullable;
import android.content.Context;
import android.location.Location;
import android.location.LocationManager;
+import android.location.LocationRequest;
import android.os.Binder;
+import com.android.internal.location.ProviderRequest;
import com.android.internal.util.Preconditions;
import com.android.server.location.util.Injector;
+import java.util.ArrayList;
+import java.util.Collection;
+
class PassiveLocationProviderManager extends LocationProviderManager {
PassiveLocationProviderManager(Context context, Injector injector) {
@@ -57,4 +62,20 @@ class PassiveLocationProviderManager extends LocationProviderManager {
}
}
}
+
+ @Override
+ protected ProviderRequest mergeRequests(Collection<Registration> registrations) {
+ ProviderRequest.Builder providerRequest = new ProviderRequest.Builder()
+ .setInterval(0);
+
+ ArrayList<LocationRequest> requests = new ArrayList<>(registrations.size());
+ for (Registration registration : registrations) {
+ requests.add(registration.getRequest());
+ if (registration.getRequest().isLocationSettingsIgnored()) {
+ providerRequest.setLocationSettingsIgnored(true);
+ }
+ }
+
+ return providerRequest.setLocationRequests(requests).build();
+ }
}
diff --git a/services/core/java/com/android/server/location/geofence/GeofenceManager.java b/services/core/java/com/android/server/location/geofence/GeofenceManager.java
index 2d7f02873b8f..7f02b2a807c3 100644
--- a/services/core/java/com/android/server/location/geofence/GeofenceManager.java
+++ b/services/core/java/com/android/server/location/geofence/GeofenceManager.java
@@ -16,6 +16,7 @@
package com.android.server.location.geofence;
+import static android.location.LocationManager.FUSED_PROVIDER;
import static android.location.LocationManager.KEY_PROXIMITY_ENTERING;
import static com.android.internal.util.ConcurrentUtils.DIRECT_EXECUTOR;
@@ -350,11 +351,11 @@ public class GeofenceManager extends
LocationStatsEnums.USAGE_ENDED,
LocationStatsEnums.API_REQUEST_GEOFENCE,
registration.getIdentity().getPackageName(),
+ null,
/* LocationRequest= */ null,
/* hasListener= */ false,
true,
- registration.getRequest(),
- true);
+ registration.getRequest(), true);
}
@Override
@@ -363,16 +364,17 @@ public class GeofenceManager extends
LocationStatsEnums.USAGE_ENDED,
LocationStatsEnums.API_REQUEST_GEOFENCE,
registration.getIdentity().getPackageName(),
+ null,
/* LocationRequest= */ null,
/* hasListener= */ false,
true,
- registration.getRequest(),
- true);
+ registration.getRequest(), true);
}
@Override
protected boolean registerWithService(LocationRequest locationRequest) {
- getLocationManager().requestLocationUpdates(locationRequest, DIRECT_EXECUTOR, this);
+ getLocationManager().requestLocationUpdates(FUSED_PROVIDER, locationRequest,
+ DIRECT_EXECUTOR, this);
return true;
}
@@ -417,13 +419,11 @@ public class GeofenceManager extends
intervalMs = mSettingsHelper.getBackgroundThrottleProximityAlertIntervalMs();
}
- LocationRequest request = LocationRequest.createFromDeprecatedProvider(
- LocationManager.FUSED_PROVIDER, intervalMs, 0, false);
- request.setFastestInterval(0);
- request.setHideFromAppOps(true);
- request.setWorkSource(workSource);
-
- return request;
+ return new LocationRequest.Builder(intervalMs)
+ .setMinUpdateIntervalMillis(0)
+ .setHiddenFromAppOps(true)
+ .setWorkSource(workSource)
+ .build();
}
diff --git a/services/core/java/com/android/server/location/gnss/GnssLocationProvider.java b/services/core/java/com/android/server/location/gnss/GnssLocationProvider.java
index a4486d7b5898..bd4fc135d2bb 100644
--- a/services/core/java/com/android/server/location/gnss/GnssLocationProvider.java
+++ b/services/core/java/com/android/server/location/gnss/GnssLocationProvider.java
@@ -45,6 +45,7 @@ import android.os.BatteryStats;
import android.os.Binder;
import android.os.Bundle;
import android.os.Handler;
+import android.os.HandlerExecutor;
import android.os.Looper;
import android.os.Message;
import android.os.PersistableBundle;
@@ -700,9 +701,8 @@ public class GnssLocationProvider extends AbstractLocationProvider implements
Context.LOCATION_SERVICE);
String provider;
LocationChangeListener locationListener;
- LocationRequest locationRequest = new LocationRequest()
- .setInterval(LOCATION_UPDATE_MIN_TIME_INTERVAL_MILLIS)
- .setFastestInterval(LOCATION_UPDATE_MIN_TIME_INTERVAL_MILLIS);
+ LocationRequest.Builder locationRequest = new LocationRequest.Builder(
+ LOCATION_UPDATE_MIN_TIME_INTERVAL_MILLIS);
if (independentFromGnss) {
// For fast GNSS TTFF
@@ -716,8 +716,6 @@ public class GnssLocationProvider extends AbstractLocationProvider implements
locationRequest.setQuality(LocationRequest.ACCURACY_FINE);
}
- locationRequest.setProvider(provider);
-
// Ignore location settings if in emergency mode. This is only allowed for
// isUserEmergency request (introduced in HAL v2.0), or HAL v1.1.
if (mNIHandler.getInEmergency()) {
@@ -735,8 +733,8 @@ public class GnssLocationProvider extends AbstractLocationProvider implements
provider, durationMillis));
try {
- locationManager.requestLocationUpdates(locationRequest,
- locationListener, mHandler.getLooper());
+ locationManager.requestLocationUpdates(provider, locationRequest.build(),
+ new HandlerExecutor(mHandler), locationListener);
locationListener.mNumLocationUpdateRequest++;
mHandler.postDelayed(() -> {
if (--locationListener.mNumLocationUpdateRequest == 0) {
@@ -1952,20 +1950,13 @@ public class GnssLocationProvider extends AbstractLocationProvider implements
// listen for PASSIVE_PROVIDER updates
LocationManager locManager =
(LocationManager) mContext.getSystemService(Context.LOCATION_SERVICE);
- long minTime = 0;
- float minDistance = 0;
- LocationRequest request = LocationRequest.createFromDeprecatedProvider(
- LocationManager.PASSIVE_PROVIDER,
- minTime,
- minDistance,
- false);
- // Don't keep track of this request since it's done on behalf of other clients
- // (which are kept track of separately).
- request.setHideFromAppOps(true);
locManager.requestLocationUpdates(
- request,
- new NetworkLocationListener(),
- getLooper());
+ LocationManager.PASSIVE_PROVIDER,
+ new LocationRequest.Builder(0)
+ .setHiddenFromAppOps(true)
+ .build(),
+ new HandlerExecutor(this),
+ new NetworkLocationListener());
updateEnabled();
}
diff --git a/services/core/java/com/android/server/location/gnss/GnssMeasurementsProvider.java b/services/core/java/com/android/server/location/gnss/GnssMeasurementsProvider.java
index 0815d46a735d..37db02337a2f 100644
--- a/services/core/java/com/android/server/location/gnss/GnssMeasurementsProvider.java
+++ b/services/core/java/com/android/server/location/gnss/GnssMeasurementsProvider.java
@@ -141,11 +141,11 @@ public class GnssMeasurementsProvider extends
LocationStatsEnums.USAGE_STARTED,
LocationStatsEnums.API_ADD_GNSS_MEASUREMENTS_LISTENER,
registration.getIdentity().getPackageName(),
- /* LocationRequest= */ null,
- /* hasListener= */ true,
- /* hasIntent= */ false,
- /* geofence= */ null,
- registration.isForeground());
+ null,
+ null,
+ true,
+ false,
+ null, registration.isForeground());
}
@Override
@@ -154,11 +154,11 @@ public class GnssMeasurementsProvider extends
LocationStatsEnums.USAGE_ENDED,
LocationStatsEnums.API_ADD_GNSS_MEASUREMENTS_LISTENER,
registration.getIdentity().getPackageName(),
- /* LocationRequest= */ null,
- /* hasListener= */ true,
- /* hasIntent= */ false,
- /* geofence= */ null,
- registration.isForeground());
+ null,
+ null,
+ true,
+ false,
+ null, registration.isForeground());
}
/**
diff --git a/services/core/java/com/android/server/location/gnss/GnssPsdsDownloader.java b/services/core/java/com/android/server/location/gnss/GnssPsdsDownloader.java
index 4a062d81d3b7..443a6c0a5a92 100644
--- a/services/core/java/com/android/server/location/gnss/GnssPsdsDownloader.java
+++ b/services/core/java/com/android/server/location/gnss/GnssPsdsDownloader.java
@@ -18,7 +18,6 @@ package com.android.server.location.gnss;
import android.annotation.Nullable;
import android.net.TrafficStats;
-import android.text.TextUtils;
import android.util.Log;
import com.android.internal.util.TrafficStatsConstants;
@@ -42,7 +41,6 @@ class GnssPsdsDownloader {
private static final String TAG = "GnssPsdsDownloader";
private static final boolean DEBUG = Log.isLoggable(TAG, Log.DEBUG);
private static final long MAXIMUM_CONTENT_LENGTH_BYTES = 1000000; // 1MB.
- private static final String DEFAULT_USER_AGENT = "Android";
private static final int CONNECTION_TIMEOUT_MS = (int) TimeUnit.SECONDS.toMillis(30);
private static final int READ_TIMEOUT_MS = (int) TimeUnit.SECONDS.toMillis(60);
@@ -55,26 +53,17 @@ class GnssPsdsDownloader {
private final String[] mPsdsServers;
// to load balance our server requests
private int mNextServerIndex;
- private final String mUserAgent;
GnssPsdsDownloader(Properties properties) {
// read PSDS servers from the Properties object
int count = 0;
- String longTermPsdsServer1 = properties.getProperty("XTRA_SERVER_1");
- String longTermPsdsServer2 = properties.getProperty("XTRA_SERVER_2");
- String longTermPsdsServer3 = properties.getProperty("XTRA_SERVER_3");
+ String longTermPsdsServer1 = properties.getProperty("LONGTERM_PSDS_SERVER_1");
+ String longTermPsdsServer2 = properties.getProperty("LONGTERM_PSDS_SERVER_2");
+ String longTermPsdsServer3 = properties.getProperty("LONGTERM_PSDS_SERVER_3");
if (longTermPsdsServer1 != null) count++;
if (longTermPsdsServer2 != null) count++;
if (longTermPsdsServer3 != null) count++;
- // Set User Agent from properties, if possible.
- String agent = properties.getProperty("XTRA_USER_AGENT");
- if (TextUtils.isEmpty(agent)) {
- mUserAgent = DEFAULT_USER_AGENT;
- } else {
- mUserAgent = agent;
- }
-
if (count == 0) {
Log.e(TAG, "No Long-Term PSDS servers were specified in the GnssConfiguration");
mLongTermPsdsServers = null;
diff --git a/services/core/java/com/android/server/location/gnss/GnssStatusProvider.java b/services/core/java/com/android/server/location/gnss/GnssStatusProvider.java
index 19f79273c992..68813b3e0777 100644
--- a/services/core/java/com/android/server/location/gnss/GnssStatusProvider.java
+++ b/services/core/java/com/android/server/location/gnss/GnssStatusProvider.java
@@ -71,11 +71,11 @@ public class GnssStatusProvider extends GnssListenerMultiplexer<Void, IGnssStatu
LocationStatsEnums.USAGE_STARTED,
LocationStatsEnums.API_REGISTER_GNSS_STATUS_CALLBACK,
registration.getIdentity().getPackageName(),
- /* LocationRequest= */ null,
- /* hasListener= */ true,
- /* hasIntent= */ false,
- /* geofence= */ null,
- registration.isForeground());
+ null,
+ null,
+ true,
+ false,
+ null, registration.isForeground());
}
@Override
@@ -84,10 +84,11 @@ public class GnssStatusProvider extends GnssListenerMultiplexer<Void, IGnssStatu
LocationStatsEnums.USAGE_ENDED,
LocationStatsEnums.API_REGISTER_GNSS_STATUS_CALLBACK,
registration.getIdentity().getPackageName(),
- /* LocationRequest= */ null,
- /* hasListener= */ true,
- /* hasIntent= */ false,
- /* geofence= */ null,
+ null,
+ null,
+ true,
+ false,
+ null,
registration.isForeground());
}
diff --git a/services/core/java/com/android/server/location/listeners/ListenerMultiplexer.java b/services/core/java/com/android/server/location/listeners/ListenerMultiplexer.java
index 8a6b8aa1e463..feb4fbd1de31 100644
--- a/services/core/java/com/android/server/location/listeners/ListenerMultiplexer.java
+++ b/services/core/java/com/android/server/location/listeners/ListenerMultiplexer.java
@@ -88,7 +88,7 @@ public abstract class ListenerMultiplexer<TKey, TRequest, TListener,
private boolean mServiceRegistered = false;
@GuardedBy("mRegistrations")
- private TMergedRequest mCurrentRequest;
+ @Nullable private TMergedRequest mCurrentRequest;
/**
* Should be implemented to register with the backing service with the given merged request, and
diff --git a/services/core/java/com/android/server/location/util/LocationUsageLogger.java b/services/core/java/com/android/server/location/util/LocationUsageLogger.java
index 2e50d4fecf15..a229964d8701 100644
--- a/services/core/java/com/android/server/location/util/LocationUsageLogger.java
+++ b/services/core/java/com/android/server/location/util/LocationUsageLogger.java
@@ -49,7 +49,7 @@ public class LocationUsageLogger {
* Log a location API usage event.
*/
public void logLocationApiUsage(int usageType, int apiInUse,
- String packageName, LocationRequest locationRequest,
+ String packageName, String provider, LocationRequest locationRequest,
boolean hasListener, boolean hasIntent,
Geofence geofence, boolean foreground) {
try {
@@ -64,22 +64,22 @@ public class LocationUsageLogger {
usageType, apiInUse, packageName,
isLocationRequestNull
? LocationStatsEnums.PROVIDER_UNKNOWN
- : bucketizeProvider(locationRequest.getProvider()),
+ : bucketizeProvider(provider),
isLocationRequestNull
? LocationStatsEnums.QUALITY_UNKNOWN
: locationRequest.getQuality(),
isLocationRequestNull
? LocationStatsEnums.INTERVAL_UNKNOWN
- : bucketizeInterval(locationRequest.getInterval()),
+ : bucketizeInterval(locationRequest.getIntervalMillis()),
isLocationRequestNull
? LocationStatsEnums.DISTANCE_UNKNOWN
: bucketizeDistance(
- locationRequest.getSmallestDisplacement()),
- isLocationRequestNull ? 0 : locationRequest.getNumUpdates(),
+ locationRequest.getMinUpdateDistanceMeters()),
+ isLocationRequestNull ? 0 : locationRequest.getMaxUpdates(),
// only log expireIn for USAGE_STARTED
isLocationRequestNull || usageType == LocationStatsEnums.USAGE_ENDED
? LocationStatsEnums.EXPIRATION_UNKNOWN
- : bucketizeExpireIn(locationRequest.getExpireIn()),
+ : bucketizeExpireIn(locationRequest.getDurationMillis()),
getCallbackType(apiInUse, hasListener, hasIntent),
isGeofenceNull
? LocationStatsEnums.RADIUS_UNKNOWN
diff --git a/services/core/java/com/android/server/media/MediaSessionStack.java b/services/core/java/com/android/server/media/MediaSessionStack.java
index d9b5b6d41c11..f15e22f92cad 100644
--- a/services/core/java/com/android/server/media/MediaSessionStack.java
+++ b/services/core/java/com/android/server/media/MediaSessionStack.java
@@ -101,7 +101,7 @@ class MediaSessionStack {
if (mMediaButtonSession == record) {
// When the media button session is removed, nullify the media button session and do not
// search for the alternative media session within the app. It's because the alternative
- // media session might be a dummy which isn't able to handle the media key events.
+ // media session might be a fake which isn't able to handle the media key events.
// TODO(b/154456172): Make this decision unaltered by non-media app's playback.
updateMediaButtonSession(null);
}
diff --git a/services/core/java/com/android/server/net/LockdownVpnTracker.java b/services/core/java/com/android/server/net/LockdownVpnTracker.java
index 3cafafffc62a..05f280884432 100644
--- a/services/core/java/com/android/server/net/LockdownVpnTracker.java
+++ b/services/core/java/com/android/server/net/LockdownVpnTracker.java
@@ -16,7 +16,6 @@
package com.android.server.net;
-import static android.Manifest.permission.NETWORK_STACK;
import static android.provider.Settings.ACTION_VPN_SETTINGS;
import android.annotation.NonNull;
@@ -24,10 +23,8 @@ import android.annotation.Nullable;
import android.app.Notification;
import android.app.NotificationManager;
import android.app.PendingIntent;
-import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
-import android.content.IntentFilter;
import android.net.ConnectivityManager;
import android.net.LinkAddress;
import android.net.LinkProperties;
@@ -41,6 +38,7 @@ import android.text.TextUtils;
import android.util.Slog;
import com.android.internal.R;
+import com.android.internal.annotations.GuardedBy;
import com.android.internal.messages.nano.SystemMessageProto.SystemMessage;
import com.android.internal.net.VpnConfig;
import com.android.internal.net.VpnProfile;
@@ -63,7 +61,7 @@ public class LockdownVpnTracker {
/** Number of VPN attempts before waiting for user intervention. */
private static final int MAX_ERROR_COUNT = 4;
- private static final String ACTION_LOCKDOWN_RESET = "com.android.server.action.LOCKDOWN_RESET";
+ public static final String ACTION_LOCKDOWN_RESET = "com.android.server.action.LOCKDOWN_RESET";
@NonNull private final Context mContext;
@NonNull private final ConnectivityService mConnService;
@@ -104,13 +102,6 @@ public class LockdownVpnTracker {
mResetIntent = PendingIntent.getBroadcast(mContext, 0, resetIntent, 0);
}
- private BroadcastReceiver mResetReceiver = new BroadcastReceiver() {
- @Override
- public void onReceive(Context context, Intent intent) {
- reset();
- }
- };
-
/**
* Watch for state changes to both active egress network, kicking off a VPN
* connection when ready, or setting firewall rules once VPN is connected.
@@ -200,9 +191,6 @@ public class LockdownVpnTracker {
mVpn.setEnableTeardown(false);
mVpn.setLockdown(true);
-
- final IntentFilter resetFilter = new IntentFilter(ACTION_LOCKDOWN_RESET);
- mContext.registerReceiver(mResetReceiver, resetFilter, NETWORK_STACK, mHandler);
handleStateChangedLocked();
}
@@ -222,10 +210,14 @@ public class LockdownVpnTracker {
mVpn.setLockdown(false);
hideNotification();
- mContext.unregisterReceiver(mResetReceiver);
mVpn.setEnableTeardown(true);
}
+ /**
+ * Reset VPN lockdown tracker. Called by ConnectivityService when receiving
+ * {@link #ACTION_LOCKDOWN_RESET} pending intent.
+ */
+ @GuardedBy("mConnService.mVpns")
public void reset() {
Slog.d(TAG, "reset()");
synchronized (mStateLock) {
diff --git a/services/core/java/com/android/server/pm/ApkChecksums.java b/services/core/java/com/android/server/pm/ApkChecksums.java
index 0338ed802436..c6c80aef4432 100644
--- a/services/core/java/com/android/server/pm/ApkChecksums.java
+++ b/services/core/java/com/android/server/pm/ApkChecksums.java
@@ -16,14 +16,15 @@
package com.android.server.pm;
+import static android.content.pm.Checksum.PARTIAL_MERKLE_ROOT_1M_SHA256;
+import static android.content.pm.Checksum.PARTIAL_MERKLE_ROOT_1M_SHA512;
+import static android.content.pm.Checksum.WHOLE_MD5;
+import static android.content.pm.Checksum.WHOLE_MERKLE_ROOT_4K_SHA256;
+import static android.content.pm.Checksum.WHOLE_SHA1;
+import static android.content.pm.Checksum.WHOLE_SHA256;
+import static android.content.pm.Checksum.WHOLE_SHA512;
import static android.content.pm.PackageManager.EXTRA_CHECKSUMS;
-import static android.content.pm.PackageManager.PARTIAL_MERKLE_ROOT_1M_SHA256;
-import static android.content.pm.PackageManager.PARTIAL_MERKLE_ROOT_1M_SHA512;
-import static android.content.pm.PackageManager.WHOLE_MD5;
-import static android.content.pm.PackageManager.WHOLE_MERKLE_ROOT_4K_SHA256;
-import static android.content.pm.PackageManager.WHOLE_SHA1;
-import static android.content.pm.PackageManager.WHOLE_SHA256;
-import static android.content.pm.PackageManager.WHOLE_SHA512;
+import static android.content.pm.PackageParser.APK_FILE_EXTENSION;
import static android.util.apk.ApkSigningBlockUtils.CONTENT_DIGEST_CHUNKED_SHA256;
import static android.util.apk.ApkSigningBlockUtils.CONTENT_DIGEST_CHUNKED_SHA512;
import static android.util.apk.ApkSigningBlockUtils.CONTENT_DIGEST_VERITY_CHUNKED_SHA256;
@@ -33,14 +34,16 @@ import android.annotation.Nullable;
import android.content.Context;
import android.content.Intent;
import android.content.IntentSender;
-import android.content.pm.FileChecksum;
-import android.content.pm.PackageManager;
+import android.content.pm.ApkChecksum;
+import android.content.pm.Checksum;
import android.content.pm.PackageParser;
+import android.content.pm.Signature;
import android.os.Handler;
import android.os.SystemClock;
import android.os.incremental.IncrementalManager;
import android.os.incremental.IncrementalStorage;
import android.util.ArrayMap;
+import android.util.ArraySet;
import android.util.Pair;
import android.util.Slog;
import android.util.apk.ApkSignatureSchemeV2Verifier;
@@ -57,18 +60,26 @@ import com.android.internal.annotations.VisibleForTesting;
import com.android.server.security.VerityUtils;
import java.io.BufferedInputStream;
+import java.io.DataInputStream;
+import java.io.DataOutputStream;
import java.io.File;
import java.io.FileInputStream;
+import java.io.FileOutputStream;
import java.io.IOException;
+import java.io.InputStream;
+import java.io.OutputStream;
import java.io.RandomAccessFile;
import java.nio.ByteBuffer;
import java.security.DigestException;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.security.cert.Certificate;
+import java.security.cert.CertificateEncodingException;
+import java.security.cert.CertificateException;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
+import java.util.Set;
/**
* Provides checksums for APK.
@@ -76,6 +87,8 @@ import java.util.Map;
public class ApkChecksums {
static final String TAG = "ApkChecksums";
+ private static final String DIGESTS_FILE_EXTENSION = ".digests";
+
// MessageDigest algorithms.
static final String ALGO_MD5 = "MD5";
static final String ALGO_SHA1 = "SHA1";
@@ -131,6 +144,100 @@ public class ApkChecksums {
}
/**
+ * Return the digests path associated with the given code path
+ * (replaces '.apk' extension with '.digests')
+ *
+ * @throws IllegalArgumentException if the code path is not an .apk.
+ */
+ public static String buildDigestsPathForApk(String codePath) {
+ if (!PackageParser.isApkPath(codePath)) {
+ throw new IllegalStateException("Code path is not an apk " + codePath);
+ }
+ return codePath.substring(0, codePath.length() - APK_FILE_EXTENSION.length())
+ + DIGESTS_FILE_EXTENSION;
+ }
+
+ /**
+ * Search for the digests file associated with the given target file.
+ * If it exists, the method returns the digests file; otherwise it returns null.
+ */
+ public static File findDigestsForFile(File targetFile) {
+ String digestsPath = buildDigestsPathForApk(targetFile.getAbsolutePath());
+ File digestsFile = new File(digestsPath);
+ return digestsFile.exists() ? digestsFile : null;
+ }
+
+ /**
+ * Serialize checksums to file in binary format.
+ */
+ public static void writeChecksums(File file, ApkChecksum[] checksums)
+ throws IOException, CertificateException {
+ try (OutputStream os = new FileOutputStream(file);
+ DataOutputStream dos = new DataOutputStream(os)) {
+ dos.writeInt(checksums.length);
+ for (ApkChecksum checksum : checksums) {
+ final String splitName = checksum.getSplitName();
+ if (splitName == null) {
+ dos.writeInt(-1);
+ } else {
+ dos.writeInt(splitName.length());
+ dos.writeUTF(splitName);
+ }
+
+ dos.writeInt(checksum.getKind());
+
+ final byte[] valueBytes = checksum.getValue();
+ dos.writeInt(valueBytes.length);
+ dos.write(valueBytes);
+
+ final Certificate cert = checksum.getSourceCertificate();
+ final byte[] certBytes = (cert == null) ? null : cert.getEncoded();
+ if (certBytes == null) {
+ dos.writeInt(-1);
+ } else {
+ dos.writeInt(certBytes.length);
+ dos.write(certBytes);
+ }
+ }
+ }
+ }
+
+ /**
+ * Deserialize array of checksums previously stored in
+ * {@link #writeChecksums(File, ApkChecksum[])}.
+ */
+ private static ApkChecksum[] readChecksums(File file) throws IOException {
+ try (InputStream is = new FileInputStream(file);
+ DataInputStream dis = new DataInputStream(is)) {
+ final int size = dis.readInt();
+ ApkChecksum[] checksums = new ApkChecksum[size];
+ for (int i = 0; i < size; ++i) {
+ final String splitName;
+ if (dis.readInt() < 0) {
+ splitName = null;
+ } else {
+ splitName = dis.readUTF();
+ }
+ final int kind = dis.readInt();
+ final byte[] valueBytes = new byte[dis.readInt()];
+ dis.read(valueBytes);
+ final byte[] certBytes;
+ final int certBytesLength = dis.readInt();
+ if (certBytesLength < 0) {
+ certBytes = null;
+ } else {
+ certBytes = new byte[certBytesLength];
+ dis.read(certBytes);
+ }
+ checksums[i] = new ApkChecksum(splitName, new Checksum(kind, valueBytes),
+ certBytes);
+ }
+ return checksums;
+ }
+ }
+
+
+ /**
* Fetch or calculate checksums for the collection of files.
*
* @param filesToChecksum split name, null for base and File to fetch checksums for
@@ -142,20 +249,20 @@ public class ApkChecksums {
* @param statusReceiver to receive the resulting checksums
*/
public static void getChecksums(List<Pair<String, File>> filesToChecksum,
- @PackageManager.FileChecksumKind int optional,
- @PackageManager.FileChecksumKind int required,
+ @Checksum.Kind int optional,
+ @Checksum.Kind int required,
@Nullable Certificate[] trustedInstallers,
@NonNull IntentSender statusReceiver,
@NonNull Injector injector) {
- List<Map<Integer, FileChecksum>> result = new ArrayList<>(filesToChecksum.size());
+ List<Map<Integer, ApkChecksum>> result = new ArrayList<>(filesToChecksum.size());
for (int i = 0, size = filesToChecksum.size(); i < size; ++i) {
final String split = filesToChecksum.get(i).first;
final File file = filesToChecksum.get(i).second;
- Map<Integer, FileChecksum> checksums = new ArrayMap<>();
+ Map<Integer, ApkChecksum> checksums = new ArrayMap<>();
result.add(checksums);
try {
- getAvailableFileChecksums(split, file, optional | required, trustedInstallers,
+ getAvailableApkChecksums(split, file, optional | required, trustedInstallers,
checksums);
} catch (Throwable e) {
Slog.e(TAG, "Preferred checksum calculation error", e);
@@ -168,18 +275,18 @@ public class ApkChecksums {
}
private static void processRequiredChecksums(List<Pair<String, File>> filesToChecksum,
- List<Map<Integer, FileChecksum>> result,
- @PackageManager.FileChecksumKind int required,
+ List<Map<Integer, ApkChecksum>> result,
+ @Checksum.Kind int required,
@NonNull IntentSender statusReceiver,
@NonNull Injector injector,
long startTime) {
final boolean timeout =
SystemClock.uptimeMillis() - startTime >= PROCESS_REQUIRED_CHECKSUMS_TIMEOUT_MILLIS;
- List<FileChecksum> allChecksums = new ArrayList<>();
+ List<ApkChecksum> allChecksums = new ArrayList<>();
for (int i = 0, size = filesToChecksum.size(); i < size; ++i) {
final String split = filesToChecksum.get(i).first;
final File file = filesToChecksum.get(i).second;
- Map<Integer, FileChecksum> checksums = result.get(i);
+ Map<Integer, ApkChecksum> checksums = result.get(i);
try {
if (!timeout || required != 0) {
@@ -192,7 +299,7 @@ public class ApkChecksums {
return;
}
- getRequiredFileChecksums(split, file, required, checksums);
+ getRequiredApkChecksums(split, file, required, checksums);
}
allChecksums.addAll(checksums.values());
} catch (Throwable e) {
@@ -202,7 +309,7 @@ public class ApkChecksums {
final Intent intent = new Intent();
intent.putExtra(EXTRA_CHECKSUMS,
- allChecksums.toArray(new FileChecksum[allChecksums.size()]));
+ allChecksums.toArray(new ApkChecksum[allChecksums.size()]));
try {
statusReceiver.sendIntent(injector.getContext(), 1, intent, null, null);
@@ -222,16 +329,16 @@ public class ApkChecksums {
* [] - trust nobody.
* @param checksums resulting checksums
*/
- private static void getAvailableFileChecksums(String split, File file,
- @PackageManager.FileChecksumKind int kinds,
+ private static void getAvailableApkChecksums(String split, File file,
+ @Checksum.Kind int kinds,
@Nullable Certificate[] trustedInstallers,
- Map<Integer, FileChecksum> checksums) {
+ Map<Integer, ApkChecksum> checksums) {
final String filePath = file.getAbsolutePath();
// Always available: FSI or IncFs.
if (isRequired(WHOLE_MERKLE_ROOT_4K_SHA256, kinds, checksums)) {
// Hashes in fs-verity and IncFS are always verified.
- FileChecksum checksum = extractHashFromFS(split, filePath);
+ ApkChecksum checksum = extractHashFromFS(split, filePath);
if (checksum != null) {
checksums.put(checksum.getKind(), checksum);
}
@@ -240,22 +347,40 @@ public class ApkChecksums {
// System enforced: v2/v3.
if (isRequired(PARTIAL_MERKLE_ROOT_1M_SHA256, kinds, checksums) || isRequired(
PARTIAL_MERKLE_ROOT_1M_SHA512, kinds, checksums)) {
- Map<Integer, FileChecksum> v2v3checksums = extractHashFromV2V3Signature(
+ Map<Integer, ApkChecksum> v2v3checksums = extractHashFromV2V3Signature(
split, filePath, kinds);
if (v2v3checksums != null) {
checksums.putAll(v2v3checksums);
}
}
- // TODO(b/160605420): Installer provided.
+ if (trustedInstallers == null || trustedInstallers.length > 0) {
+ final File digestsFile = new File(buildDigestsPathForApk(filePath));
+ if (digestsFile.exists()) {
+ try {
+ final ApkChecksum[] digests = readChecksums(digestsFile);
+ final Set<Signature> trusted = convertToSet(trustedInstallers);
+ for (ApkChecksum digest : digests) {
+ if (isRequired(digest.getKind(), kinds, checksums) && isTrusted(digest,
+ trusted)) {
+ checksums.put(digest.getKind(), digest);
+ }
+ }
+ } catch (IOException e) {
+ Slog.e(TAG, "Error reading .digests", e);
+ } catch (CertificateEncodingException e) {
+ Slog.e(TAG, "Error encoding trustedInstallers", e);
+ }
+ }
+ }
}
/**
* Whether the file is available for checksumming or we need to wait.
*/
private static boolean needToWait(File file,
- @PackageManager.FileChecksumKind int kinds,
- Map<Integer, FileChecksum> checksums,
+ @Checksum.Kind int kinds,
+ Map<Integer, ApkChecksum> checksums,
@NonNull Injector injector) throws IOException {
if (!isRequired(WHOLE_MERKLE_ROOT_4K_SHA256, kinds, checksums)
&& !isRequired(WHOLE_MD5, kinds, checksums)
@@ -274,12 +399,13 @@ public class ApkChecksums {
IncrementalManager manager = injector.getIncrementalManager();
if (manager == null) {
- throw new IllegalStateException("IncrementalManager is missing.");
+ Slog.e(TAG, "IncrementalManager is missing.");
+ return false;
}
IncrementalStorage storage = manager.openStorage(filePath);
if (storage == null) {
- throw new IllegalStateException(
- "IncrementalStorage is missing for a path on IncFs: " + filePath);
+ Slog.e(TAG, "IncrementalStorage is missing for a path on IncFs: " + filePath);
+ return false;
}
return !storage.isFileFullyLoaded(filePath);
@@ -293,9 +419,9 @@ public class ApkChecksums {
* @param kinds mask to forcefully calculate if not available
* @param checksums resulting checksums
*/
- private static void getRequiredFileChecksums(String split, File file,
- @PackageManager.FileChecksumKind int kinds,
- Map<Integer, FileChecksum> checksums) {
+ private static void getRequiredApkChecksums(String split, File file,
+ @Checksum.Kind int kinds,
+ Map<Integer, ApkChecksum> checksums) {
final String filePath = file.getAbsolutePath();
// Manually calculating required checksums if not readily available.
@@ -310,7 +436,7 @@ public class ApkChecksums {
}
});
checksums.put(WHOLE_MERKLE_ROOT_4K_SHA256,
- new FileChecksum(split, WHOLE_MERKLE_ROOT_4K_SHA256, generatedRootHash));
+ new ApkChecksum(split, WHOLE_MERKLE_ROOT_4K_SHA256, generatedRootHash));
} catch (IOException | NoSuchAlgorithmException | DigestException e) {
Slog.e(TAG, "Error calculating WHOLE_MERKLE_ROOT_4K_SHA256", e);
}
@@ -324,8 +450,8 @@ public class ApkChecksums {
calculatePartialChecksumsIfRequested(checksums, split, file, kinds);
}
- private static boolean isRequired(@PackageManager.FileChecksumKind int kind,
- @PackageManager.FileChecksumKind int kinds, Map<Integer, FileChecksum> checksums) {
+ private static boolean isRequired(@Checksum.Kind int kind,
+ @Checksum.Kind int kinds, Map<Integer, ApkChecksum> checksums) {
if ((kinds & kind) == 0) {
return false;
}
@@ -335,12 +461,36 @@ public class ApkChecksums {
return true;
}
- private static FileChecksum extractHashFromFS(String split, String filePath) {
+ /**
+ * Signature class provides a fast way to compare certificates using their hashes.
+ * The hash is exactly the same as in X509/Certificate.
+ */
+ private static Set<Signature> convertToSet(@Nullable Certificate[] array) throws
+ CertificateEncodingException {
+ if (array == null) {
+ return null;
+ }
+ final Set<Signature> set = new ArraySet<>(array.length);
+ for (Certificate item : array) {
+ set.add(new Signature(item.getEncoded()));
+ }
+ return set;
+ }
+
+ private static boolean isTrusted(ApkChecksum checksum, Set<Signature> trusted) {
+ if (trusted == null) {
+ return true;
+ }
+ final Signature signature = new Signature(checksum.getSourceCertificateBytes());
+ return trusted.contains(signature);
+ }
+
+ private static ApkChecksum extractHashFromFS(String split, String filePath) {
// verity first
{
byte[] hash = VerityUtils.getFsverityRootHash(filePath);
if (hash != null) {
- return new FileChecksum(split, WHOLE_MERKLE_ROOT_4K_SHA256, hash);
+ return new ApkChecksum(split, WHOLE_MERKLE_ROOT_4K_SHA256, hash);
}
}
// v4 next
@@ -350,7 +500,7 @@ public class ApkChecksums {
byte[] hash = signer.contentDigests.getOrDefault(CONTENT_DIGEST_VERITY_CHUNKED_SHA256,
null);
if (hash != null) {
- return new FileChecksum(split, WHOLE_MERKLE_ROOT_4K_SHA256, hash);
+ return new ApkChecksum(split, WHOLE_MERKLE_ROOT_4K_SHA256, hash);
}
} catch (SignatureNotFoundException e) {
// Nothing
@@ -360,7 +510,7 @@ public class ApkChecksums {
return null;
}
- private static Map<Integer, FileChecksum> extractHashFromV2V3Signature(
+ private static Map<Integer, ApkChecksum> extractHashFromV2V3Signature(
String split, String filePath, int kinds) {
Map<Integer, byte[]> contentDigests = null;
try {
@@ -377,19 +527,19 @@ public class ApkChecksums {
return null;
}
- Map<Integer, FileChecksum> checksums = new ArrayMap<>();
+ Map<Integer, ApkChecksum> checksums = new ArrayMap<>();
if ((kinds & PARTIAL_MERKLE_ROOT_1M_SHA256) != 0) {
byte[] hash = contentDigests.getOrDefault(CONTENT_DIGEST_CHUNKED_SHA256, null);
if (hash != null) {
checksums.put(PARTIAL_MERKLE_ROOT_1M_SHA256,
- new FileChecksum(split, PARTIAL_MERKLE_ROOT_1M_SHA256, hash));
+ new ApkChecksum(split, PARTIAL_MERKLE_ROOT_1M_SHA256, hash));
}
}
if ((kinds & PARTIAL_MERKLE_ROOT_1M_SHA512) != 0) {
byte[] hash = contentDigests.getOrDefault(CONTENT_DIGEST_CHUNKED_SHA512, null);
if (hash != null) {
checksums.put(PARTIAL_MERKLE_ROOT_1M_SHA512,
- new FileChecksum(split, PARTIAL_MERKLE_ROOT_1M_SHA512, hash));
+ new ApkChecksum(split, PARTIAL_MERKLE_ROOT_1M_SHA512, hash));
}
}
return checksums;
@@ -411,17 +561,17 @@ public class ApkChecksums {
}
}
- private static void calculateChecksumIfRequested(Map<Integer, FileChecksum> checksums,
+ private static void calculateChecksumIfRequested(Map<Integer, ApkChecksum> checksums,
String split, File file, int required, int kind) {
if ((required & kind) != 0 && !checksums.containsKey(kind)) {
- final byte[] checksum = getFileChecksum(file, kind);
+ final byte[] checksum = getApkChecksum(file, kind);
if (checksum != null) {
- checksums.put(kind, new FileChecksum(split, kind, checksum));
+ checksums.put(kind, new ApkChecksum(split, kind, checksum));
}
}
}
- private static byte[] getFileChecksum(File file, int kind) {
+ private static byte[] getApkChecksum(File file, int kind) {
try (FileInputStream fis = new FileInputStream(file);
BufferedInputStream bis = new BufferedInputStream(fis)) {
byte[] dataBytes = new byte[512 * 1024];
@@ -466,7 +616,7 @@ public class ApkChecksums {
}
}
- private static void calculatePartialChecksumsIfRequested(Map<Integer, FileChecksum> checksums,
+ private static void calculatePartialChecksumsIfRequested(Map<Integer, ApkChecksum> checksums,
String split, File file, int required) {
boolean needSignatureSha256 =
(required & PARTIAL_MERKLE_ROOT_1M_SHA256) != 0 && !checksums.containsKey(
@@ -500,7 +650,7 @@ public class ApkChecksums {
for (int i = 0, size = digestAlgos.length; i < size; ++i) {
int checksumKind = getChecksumKindForContentDigestAlgo(digestAlgos[i]);
if (checksumKind != -1) {
- checksums.put(checksumKind, new FileChecksum(split, checksumKind, digests[i]));
+ checksums.put(checksumKind, new ApkChecksum(split, checksumKind, digests[i]));
}
}
} catch (IOException | DigestException e) {
diff --git a/services/core/java/com/android/server/pm/PackageInstallerService.java b/services/core/java/com/android/server/pm/PackageInstallerService.java
index 155af82289d4..f52db5fb5f2f 100644
--- a/services/core/java/com/android/server/pm/PackageInstallerService.java
+++ b/services/core/java/com/android/server/pm/PackageInstallerService.java
@@ -732,9 +732,9 @@ public class PackageInstallerService extends IPackageInstaller.Stub implements
installerAttributionTag);
session = new PackageInstallerSession(mInternalCallback, mContext, mPm, this,
mInstallThread.getLooper(), mStagingManager, sessionId, userId, callingUid,
- installSource, params, createdMillis,
- stageDir, stageCid, null, false, false, false, false, null, SessionInfo.INVALID_ID,
- false, false, false, SessionInfo.STAGED_SESSION_NO_ERROR, "");
+ installSource, params, createdMillis, stageDir, stageCid, null, null, false, false,
+ false, false, null, SessionInfo.INVALID_ID, false, false, false,
+ SessionInfo.STAGED_SESSION_NO_ERROR, "");
synchronized (mSessions) {
mSessions.put(sessionId, session);
diff --git a/services/core/java/com/android/server/pm/PackageInstallerSession.java b/services/core/java/com/android/server/pm/PackageInstallerSession.java
index 17cd8f58c3a3..bcb5fdba7a3b 100644
--- a/services/core/java/com/android/server/pm/PackageInstallerSession.java
+++ b/services/core/java/com/android/server/pm/PackageInstallerSession.java
@@ -27,6 +27,7 @@ import static android.content.pm.PackageManager.INSTALL_FAILED_INTERNAL_ERROR;
import static android.content.pm.PackageManager.INSTALL_FAILED_INVALID_APK;
import static android.content.pm.PackageManager.INSTALL_FAILED_MEDIA_UNAVAILABLE;
import static android.content.pm.PackageManager.INSTALL_FAILED_MISSING_SPLIT;
+import static android.content.pm.PackageManager.INSTALL_PARSE_FAILED_CERTIFICATE_ENCODING;
import static android.content.pm.PackageParser.APEX_FILE_EXTENSION;
import static android.content.pm.PackageParser.APK_FILE_EXTENSION;
import static android.system.OsConstants.O_CREAT;
@@ -61,7 +62,9 @@ import android.content.IIntentReceiver;
import android.content.IIntentSender;
import android.content.Intent;
import android.content.IntentSender;
+import android.content.pm.ApkChecksum;
import android.content.pm.ApplicationInfo;
+import android.content.pm.Checksum;
import android.content.pm.DataLoaderManager;
import android.content.pm.DataLoaderParams;
import android.content.pm.DataLoaderParamsParcel;
@@ -84,6 +87,7 @@ import android.content.pm.PackageParser;
import android.content.pm.PackageParser.ApkLite;
import android.content.pm.PackageParser.PackageLite;
import android.content.pm.PackageParser.PackageParserException;
+import android.content.pm.Signature;
import android.content.pm.dex.DexMetadataHelper;
import android.content.pm.parsing.ApkLiteParseUtils;
import android.content.pm.parsing.result.ParseResult;
@@ -118,6 +122,7 @@ import android.system.Os;
import android.system.OsConstants;
import android.system.StructStat;
import android.text.TextUtils;
+import android.util.ArrayMap;
import android.util.ArraySet;
import android.util.ExceptionUtils;
import android.util.MathUtils;
@@ -153,6 +158,7 @@ import java.io.FileDescriptor;
import java.io.FileFilter;
import java.io.FileOutputStream;
import java.io.IOException;
+import java.security.cert.CertificateException;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
@@ -176,6 +182,7 @@ public class PackageInstallerSession extends IPackageInstallerSession.Stub {
static final String TAG_SESSION = "session";
static final String TAG_CHILD_SESSION = "childSession";
static final String TAG_SESSION_FILE = "sessionFile";
+ static final String TAG_SESSION_CHECKSUM = "sessionChecksum";
private static final String TAG_GRANTED_RUNTIME_PERMISSION = "granted-runtime-permission";
private static final String TAG_WHITELISTED_RESTRICTED_PERMISSION =
"whitelisted-restricted-permission";
@@ -230,10 +237,14 @@ public class PackageInstallerSession extends IPackageInstallerSession.Stub {
private static final String ATTR_LENGTH_BYTES = "lengthBytes";
private static final String ATTR_METADATA = "metadata";
private static final String ATTR_SIGNATURE = "signature";
+ private static final String ATTR_CHECKSUM_KIND = "checksumKind";
+ private static final String ATTR_CHECKSUM_VALUE = "checksumValue";
+ private static final String ATTR_CHECKSUM_CERTIFICATE = "checksumCertificate";
private static final String PROPERTY_NAME_INHERIT_NATIVE = "pi.inherit_native_on_dont_kill";
private static final int[] EMPTY_CHILD_SESSION_ARRAY = EmptyArray.INT;
private static final InstallationFile[] EMPTY_INSTALLATION_FILE_ARRAY = {};
+ private static final ApkChecksum[] EMPTY_FILE_CHECKSUM_ARRAY = {};
private static final String SYSTEM_DATA_LOADER_PACKAGE = "android";
@@ -380,6 +391,27 @@ public class PackageInstallerSession extends IPackageInstallerSession.Stub {
@GuardedBy("mLock")
private ArraySet<FileEntry> mFiles = new ArraySet<>();
+ static class CertifiedChecksum {
+ final @NonNull Checksum mChecksum;
+ final @NonNull byte[] mCertificate;
+
+ CertifiedChecksum(@NonNull Checksum checksum, @NonNull byte[] certificate) {
+ mChecksum = checksum;
+ mCertificate = certificate;
+ }
+
+ Checksum getChecksum() {
+ return mChecksum;
+ }
+
+ byte[] getCertificate() {
+ return mCertificate;
+ }
+ }
+
+ @GuardedBy("mLock")
+ private ArrayMap<String, List<CertifiedChecksum>> mChecksums = new ArrayMap<>();
+
@GuardedBy("mLock")
private boolean mStagedSessionApplied;
@GuardedBy("mLock")
@@ -581,8 +613,9 @@ public class PackageInstallerSession extends IPackageInstallerSession.Stub {
PackageSessionProvider sessionProvider, Looper looper, StagingManager stagingManager,
int sessionId, int userId, int installerUid, @NonNull InstallSource installSource,
SessionParams params, long createdMillis,
- File stageDir, String stageCid, InstallationFile[] files, boolean prepared,
- boolean committed, boolean destroyed, boolean sealed,
+ File stageDir, String stageCid, InstallationFile[] files,
+ ArrayMap<String, List<CertifiedChecksum>> checksums,
+ boolean prepared, boolean committed, boolean destroyed, boolean sealed,
@Nullable int[] childSessionIds, int parentSessionId, boolean isReady,
boolean isFailed, boolean isApplied, int stagedSessionErrorCode,
String stagedSessionErrorMessage) {
@@ -615,6 +648,7 @@ public class PackageInstallerSession extends IPackageInstallerSession.Stub {
this.mParentSessionId = parentSessionId;
if (files != null) {
+ mFiles.ensureCapacity(files.length);
for (int i = 0, size = files.length; i < size; ++i) {
InstallationFile file = files[i];
if (!mFiles.add(new FileEntry(i, file))) {
@@ -624,6 +658,10 @@ public class PackageInstallerSession extends IPackageInstallerSession.Stub {
}
}
+ if (checksums != null) {
+ mChecksums.putAll(checksums);
+ }
+
if (!params.isMultiPackage && (stageDir == null) == (stageCid == null)) {
throw new IllegalArgumentException(
"Exactly one of stageDir or stageCid stage must be set");
@@ -907,6 +945,45 @@ public class PackageInstallerSession extends IPackageInstallerSession.Stub {
}
@Override
+ public void addChecksums(String name, @NonNull Checksum[] checksums) {
+ if (checksums.length == 0) {
+ return;
+ }
+
+ final PackageManagerInternal pmi = LocalServices.getService(
+ PackageManagerInternal.class);
+ final AndroidPackage callingInstaller = pmi.getPackage(Binder.getCallingUid());
+
+ if (callingInstaller == null) {
+ throw new IllegalStateException("Can't obtain calling installer's package.");
+ }
+
+ // Obtaining array of certificates used for signing the installer package.
+ // According to V2/V3 signing schema, the first certificate corresponds to public key
+ // in the signing block.
+ Signature[] certs = callingInstaller.getSigningDetails().signatures;
+ if (certs == null || certs.length == 0 || certs[0] == null) {
+ throw new IllegalStateException(
+ "Can't obtain calling installer package's certificates.");
+ }
+ byte[] mainCertificateBytes = certs[0].toByteArray();
+
+ synchronized (mLock) {
+ assertCallerIsOwnerOrRootLocked();
+ assertPreparedAndNotCommittedOrDestroyedLocked("addChecksums");
+
+ for (Checksum checksum : checksums) {
+ List<CertifiedChecksum> fileChecksums = mChecksums.get(name);
+ if (fileChecksums == null) {
+ fileChecksums = new ArrayList<>();
+ mChecksums.put(name, fileChecksums);
+ }
+ fileChecksums.add(new CertifiedChecksum(checksum, mainCertificateBytes));
+ }
+ }
+ }
+
+ @Override
public void removeSplit(String splitName) {
if (isDataLoaderInstallation()) {
throw new IllegalStateException(
@@ -2155,7 +2232,7 @@ public class PackageInstallerSession extends IPackageInstallerSession.Stub {
}
final File targetFile = new File(stageDir, targetName);
- resolveAndStageFileLocked(addedFile, targetFile);
+ resolveAndStageFileLocked(addedFile, targetFile, null);
mResolvedBaseFile = targetFile;
// Populate package name of the apex session
@@ -2174,6 +2251,13 @@ public class PackageInstallerSession extends IPackageInstallerSession.Stub {
}
}
+ private static String splitNameToFileName(String splitName) {
+ if (splitName == null) {
+ return "base";
+ }
+ return "split_" + splitName;
+ }
+
/**
* Validate install by confirming that all application packages are have
* consistent package name, version code, and signing certificates.
@@ -2259,37 +2343,21 @@ public class PackageInstallerSession extends IPackageInstallerSession.Stub {
assertApkConsistentLocked(String.valueOf(addedFile), apk);
// Take this opportunity to enforce uniform naming
- final String targetName;
- if (apk.splitName == null) {
- targetName = "base" + APK_FILE_EXTENSION;
- } else {
- targetName = "split_" + apk.splitName + APK_FILE_EXTENSION;
- }
+ final String fileName = splitNameToFileName(apk.splitName);
+ final String targetName = fileName + APK_FILE_EXTENSION;
if (!FileUtils.isValidExtFilename(targetName)) {
throw new PackageManagerException(INSTALL_FAILED_INVALID_APK,
"Invalid filename: " + targetName);
}
final File targetFile = new File(stageDir, targetName);
- resolveAndStageFileLocked(addedFile, targetFile);
+ resolveAndStageFileLocked(addedFile, targetFile, apk.splitName);
// Base is coming from session
if (apk.splitName == null) {
mResolvedBaseFile = targetFile;
baseApk = apk;
}
-
- // Validate and add Dex Metadata (.dm).
- final File dexMetadataFile = DexMetadataHelper.findDexMetadataForFile(addedFile);
- if (dexMetadataFile != null) {
- if (!FileUtils.isValidExtFilename(dexMetadataFile.getName())) {
- throw new PackageManagerException(INSTALL_FAILED_INVALID_APK,
- "Invalid filename: " + dexMetadataFile);
- }
- final File targetDexMetadataFile = new File(stageDir,
- DexMetadataHelper.buildDexMetadataPathForApk(targetName));
- resolveAndStageFileLocked(dexMetadataFile, targetDexMetadataFile);
- }
}
if (removeSplitList.size() > 0) {
@@ -2338,15 +2406,20 @@ public class PackageInstallerSession extends IPackageInstallerSession.Stub {
}
}
+ if (!mChecksums.isEmpty()) {
+ throw new PackageManagerException(
+ PackageManager.INSTALL_FAILED_SESSION_INVALID,
+ "Invalid checksum name(s): " + String.join(",", mChecksums.keySet()));
+ }
+
if (params.mode == SessionParams.MODE_FULL_INSTALL) {
// Full installs must include a base package
if (!stagedSplits.contains(null)) {
throw new PackageManagerException(INSTALL_FAILED_INVALID_APK,
"Full install must include a base package");
}
-
} else {
- ApplicationInfo appInfo = pkgInfo.applicationInfo;
+ final ApplicationInfo appInfo = pkgInfo.applicationInfo;
ParseResult<PackageLite> pkgLiteResult = ApkLiteParseUtils.parsePackageLite(
input.reset(), new File(appInfo.getCodePath()), 0);
if (pkgLiteResult.isError()) {
@@ -2365,33 +2438,21 @@ public class PackageInstallerSession extends IPackageInstallerSession.Stub {
assertApkConsistentLocked("Existing base", existingBase);
- // Inherit base if not overridden
+ // Inherit base if not overridden.
if (mResolvedBaseFile == null) {
mResolvedBaseFile = new File(appInfo.getBaseCodePath());
- resolveInheritedFileLocked(mResolvedBaseFile);
- // Inherit the dex metadata if present.
- final File baseDexMetadataFile =
- DexMetadataHelper.findDexMetadataForFile(mResolvedBaseFile);
- if (baseDexMetadataFile != null) {
- resolveInheritedFileLocked(baseDexMetadataFile);
- }
+ inheritFileLocked(mResolvedBaseFile);
baseApk = existingBase;
}
- // Inherit splits if not overridden
+ // Inherit splits if not overridden.
if (!ArrayUtils.isEmpty(existing.splitNames)) {
for (int i = 0; i < existing.splitNames.length; i++) {
final String splitName = existing.splitNames[i];
final File splitFile = new File(existing.splitCodePaths[i]);
final boolean splitRemoved = removeSplitList.contains(splitName);
if (!stagedSplits.contains(splitName) && !splitRemoved) {
- resolveInheritedFileLocked(splitFile);
- // Inherit the dex metadata if present.
- final File splitDexMetadataFile =
- DexMetadataHelper.findDexMetadataForFile(splitFile);
- if (splitDexMetadataFile != null) {
- resolveInheritedFileLocked(splitDexMetadataFile);
- }
+ inheritFileLocked(splitFile);
}
}
}
@@ -2492,11 +2553,15 @@ public class PackageInstallerSession extends IPackageInstallerSession.Stub {
}
@GuardedBy("mLock")
- private void resolveAndStageFileLocked(File origFile, File targetFile)
+ private void stageFileLocked(File origFile, File targetFile)
throws PackageManagerException {
mResolvedStagedFiles.add(targetFile);
maybeRenameFile(origFile, targetFile);
+ }
+ @GuardedBy("mLock")
+ private void maybeStageFsveritySignatureLocked(File origFile, File targetFile)
+ throws PackageManagerException {
final File originalSignature = new File(
VerityUtils.getFsveritySignatureFilePath(origFile.getPath()));
// Make sure .fsv_sig exists when it should, then resolve and stage it.
@@ -2521,14 +2586,84 @@ public class PackageInstallerSession extends IPackageInstallerSession.Stub {
final File stagedSignature = new File(
VerityUtils.getFsveritySignatureFilePath(targetFile.getPath()));
- maybeRenameFile(originalSignature, stagedSignature);
- mResolvedStagedFiles.add(stagedSignature);
+
+ stageFileLocked(originalSignature, stagedSignature);
}
@GuardedBy("mLock")
- private void resolveInheritedFileLocked(File origFile) {
- mResolvedInheritedFiles.add(origFile);
+ private void maybeStageDexMetadataLocked(File origFile, File targetFile)
+ throws PackageManagerException {
+ final File dexMetadataFile = DexMetadataHelper.findDexMetadataForFile(origFile);
+ if (dexMetadataFile == null) {
+ return;
+ }
+
+ if (!FileUtils.isValidExtFilename(dexMetadataFile.getName())) {
+ throw new PackageManagerException(INSTALL_FAILED_INVALID_APK,
+ "Invalid filename: " + dexMetadataFile);
+ }
+ final File targetDexMetadataFile = new File(stageDir,
+ DexMetadataHelper.buildDexMetadataPathForApk(targetFile.getName()));
+
+ stageFileLocked(dexMetadataFile, targetDexMetadataFile);
+ maybeStageFsveritySignatureLocked(dexMetadataFile, targetDexMetadataFile);
+ }
+
+ private static ApkChecksum[] createApkChecksums(String splitName,
+ List<CertifiedChecksum> checksums) {
+ ApkChecksum[] result = new ApkChecksum[checksums.size()];
+ for (int i = 0, size = checksums.size(); i < size; ++i) {
+ CertifiedChecksum checksum = checksums.get(i);
+ result[i] = new ApkChecksum(splitName, checksum.getChecksum(),
+ checksum.getCertificate());
+ }
+ return result;
+ }
+
+ @GuardedBy("mLock")
+ private void maybeStageDigestsLocked(File origFile, File targetFile, String splitName)
+ throws PackageManagerException {
+ final List<CertifiedChecksum> checksums = mChecksums.get(origFile.getName());
+ if (checksums == null) {
+ return;
+ }
+ mChecksums.remove(origFile.getName());
+
+ if (checksums.isEmpty()) {
+ return;
+ }
+
+ final File targetDigestsFile = new File(stageDir,
+ ApkChecksums.buildDigestsPathForApk(targetFile.getName()));
+ try {
+ ApkChecksums.writeChecksums(targetDigestsFile,
+ createApkChecksums(splitName, checksums));
+ } catch (CertificateException e) {
+ throw new PackageManagerException(INSTALL_PARSE_FAILED_CERTIFICATE_ENCODING,
+ "Failed to encode certificate for " + mPackageName, e);
+ } catch (IOException e) {
+ throw new PackageManagerException(INSTALL_FAILED_INSUFFICIENT_STORAGE,
+ "Failed to store digests for " + mPackageName, e);
+ }
+
+ stageFileLocked(targetDigestsFile, targetDigestsFile);
+ }
+
+ @GuardedBy("mLock")
+ private void resolveAndStageFileLocked(File origFile, File targetFile, String splitName)
+ throws PackageManagerException {
+ stageFileLocked(origFile, targetFile);
+
+ // Stage fsverity signature if present.
+ maybeStageFsveritySignatureLocked(origFile, targetFile);
+ // Stage dex metadata (.dm) if present.
+ maybeStageDexMetadataLocked(origFile, targetFile);
+ // Stage checksums (.digests) if present.
+ maybeStageDigestsLocked(origFile, targetFile, splitName);
+ }
+ @GuardedBy("mLock")
+ private void maybeInheritFsveritySignatureLocked(File origFile) {
// Inherit the fsverity signature file if present.
final File fsveritySignatureFile = new File(
VerityUtils.getFsveritySignatureFilePath(origFile.getPath()));
@@ -2538,6 +2673,26 @@ public class PackageInstallerSession extends IPackageInstallerSession.Stub {
}
@GuardedBy("mLock")
+ private void inheritFileLocked(File origFile) {
+ mResolvedInheritedFiles.add(origFile);
+
+ maybeInheritFsveritySignatureLocked(origFile);
+
+ // Inherit the dex metadata if present.
+ final File dexMetadataFile =
+ DexMetadataHelper.findDexMetadataForFile(origFile);
+ if (dexMetadataFile != null) {
+ mResolvedInheritedFiles.add(dexMetadataFile);
+ maybeInheritFsveritySignatureLocked(dexMetadataFile);
+ }
+ // Inherit the digests if present.
+ final File digestsFile = ApkChecksums.findDigestsForFile(origFile);
+ if (digestsFile != null) {
+ mResolvedInheritedFiles.add(digestsFile);
+ }
+ }
+
+ @GuardedBy("mLock")
private void assertApkConsistentLocked(String tag, ApkLite apk)
throws PackageManagerException {
if (!mPackageName.equals(apk.packageName)) {
@@ -3791,6 +3946,22 @@ public class PackageInstallerSession extends IPackageInstallerSession.Stub {
writeByteArrayAttribute(out, ATTR_SIGNATURE, file.getSignature());
out.endTag(null, TAG_SESSION_FILE);
}
+
+ for (int i = 0, isize = mChecksums.size(); i < isize; ++i) {
+ String fileName = mChecksums.keyAt(i);
+ List<CertifiedChecksum> checksums = mChecksums.valueAt(i);
+ for (int j = 0, jsize = checksums.size(); j < jsize; ++j) {
+ CertifiedChecksum checksum = checksums.get(j);
+ out.startTag(null, TAG_SESSION_CHECKSUM);
+ writeStringAttribute(out, ATTR_NAME, fileName);
+ writeIntAttribute(out, ATTR_CHECKSUM_KIND, checksum.getChecksum().getKind());
+ writeByteArrayAttribute(out, ATTR_CHECKSUM_VALUE,
+ checksum.getChecksum().getValue());
+ writeByteArrayAttribute(out, ATTR_CHECKSUM_CERTIFICATE,
+ checksum.getCertificate());
+ out.endTag(null, TAG_SESSION_CHECKSUM);
+ }
+ }
}
out.endTag(null, TAG_SESSION);
@@ -3904,6 +4075,7 @@ public class PackageInstallerSession extends IPackageInstallerSession.Stub {
int autoRevokePermissionsMode = MODE_DEFAULT;
List<Integer> childSessionIds = new ArrayList<>();
List<InstallationFile> files = new ArrayList<>();
+ ArrayMap<String, List<CertifiedChecksum>> checksums = new ArrayMap<>();
int outerDepth = in.getDepth();
int type;
while ((type = in.next()) != XmlPullParser.END_DOCUMENT
@@ -3932,6 +4104,20 @@ public class PackageInstallerSession extends IPackageInstallerSession.Stub {
readByteArrayAttribute(in, ATTR_METADATA),
readByteArrayAttribute(in, ATTR_SIGNATURE)));
}
+ if (TAG_SESSION_CHECKSUM.equals(in.getName())) {
+ final String fileName = readStringAttribute(in, ATTR_NAME);
+ final CertifiedChecksum certifiedChecksum = new CertifiedChecksum(
+ new Checksum(readIntAttribute(in, ATTR_CHECKSUM_KIND, 0),
+ readByteArrayAttribute(in, ATTR_CHECKSUM_VALUE)),
+ readByteArrayAttribute(in, ATTR_CHECKSUM_CERTIFICATE));
+
+ List<CertifiedChecksum> certifiedChecksums = checksums.get(fileName);
+ if (certifiedChecksums == null) {
+ certifiedChecksums = new ArrayList<>();
+ checksums.put(fileName, certifiedChecksums);
+ }
+ certifiedChecksums.add(certifiedChecksum);
+ }
}
if (grantedRuntimePermissions.size() > 0) {
@@ -3964,7 +4150,7 @@ public class PackageInstallerSession extends IPackageInstallerSession.Stub {
installOriginatingPackageName, installerPackageName, installerAttributionTag);
return new PackageInstallerSession(callback, context, pm, sessionProvider,
installerThread, stagingManager, sessionId, userId, installerUid,
- installSource, params, createdMillis, stageDir, stageCid, fileArray,
+ installSource, params, createdMillis, stageDir, stageCid, fileArray, checksums,
prepared, committed, destroyed, sealed, childSessionIdsArray, parentSessionId,
isReady, isFailed, isApplied, stagedSessionErrorCode, stagedSessionErrorMessage);
}
diff --git a/services/core/java/com/android/server/pm/PackageManagerService.java b/services/core/java/com/android/server/pm/PackageManagerService.java
index fcf5d9691d99..5850dc012226 100644
--- a/services/core/java/com/android/server/pm/PackageManagerService.java
+++ b/services/core/java/com/android/server/pm/PackageManagerService.java
@@ -164,6 +164,7 @@ import android.content.pm.ActivityInfo;
import android.content.pm.ApplicationInfo;
import android.content.pm.AuxiliaryResolveInfo;
import android.content.pm.ChangedPackages;
+import android.content.pm.Checksum;
import android.content.pm.ComponentInfo;
import android.content.pm.DataLoaderType;
import android.content.pm.FallbackCategoryProvider;
@@ -2459,8 +2460,8 @@ public class PackageManagerService extends IPackageManager.Stub
@Override
public void getChecksums(@NonNull String packageName, boolean includeSplits,
- @PackageManager.FileChecksumKind int optional,
- @PackageManager.FileChecksumKind int required, @Nullable List trustedInstallers,
+ @Checksum.Kind int optional,
+ @Checksum.Kind int required, @Nullable List trustedInstallers,
@NonNull IntentSender statusReceiver, int userId) {
Objects.requireNonNull(packageName);
Objects.requireNonNull(statusReceiver);
@@ -19862,7 +19863,7 @@ public class PackageManagerService extends IPackageManager.Stub
final PreferredIntentResolver pir = mSettings.editPreferredActivitiesLPw(userId);
final ArrayList<PreferredActivity> existing = pir.findFilters(filter);
if (removeExisting && existing != null) {
- mSettings.removeFiltersLPw(pir, filter, existing);
+ Settings.removeFilters(pir, filter, existing);
}
pir.addFilter(new PreferredActivity(filter, match, set, activity, always));
scheduleWritePackageRestrictionsLocked(userId);
@@ -19963,7 +19964,7 @@ public class PackageManagerService extends IPackageManager.Stub
}
}
if (existing != null) {
- mSettings.removeFiltersLPw(pir, filter, existing);
+ Settings.removeFilters(pir, filter, existing);
}
}
}
diff --git a/services/core/java/com/android/server/pm/Settings.java b/services/core/java/com/android/server/pm/Settings.java
index 74bc49dd9108..f801702f7ddd 100644
--- a/services/core/java/com/android/server/pm/Settings.java
+++ b/services/core/java/com/android/server/pm/Settings.java
@@ -3183,7 +3183,7 @@ public final class Settings {
}
}
- void removeFiltersLPw(@NonNull PreferredIntentResolver pir,
+ static void removeFilters(@NonNull PreferredIntentResolver pir,
@NonNull IntentFilter filter, @NonNull List<PreferredActivity> existing) {
if (PackageManagerService.DEBUG_PREFERRED) {
Slog.i(TAG, existing.size() + " preferred matches for:");
@@ -3405,7 +3405,7 @@ public final class Settings {
final PreferredIntentResolver pir = editPreferredActivitiesLPw(userId);
final List<PreferredActivity> existing = pir.findFilters(filter);
if (existing != null) {
- removeFiltersLPw(pir, filter, existing);
+ removeFilters(pir, filter, existing);
}
PreferredActivity pa = new PreferredActivity(filter, systemMatch, set, cn, true);
pir.addFilter(pa);
diff --git a/services/core/java/com/android/server/pm/UserManagerService.java b/services/core/java/com/android/server/pm/UserManagerService.java
index 6ecaab6692a2..4aaa8a5abcf5 100644
--- a/services/core/java/com/android/server/pm/UserManagerService.java
+++ b/services/core/java/com/android/server/pm/UserManagerService.java
@@ -175,6 +175,7 @@ public class UserManagerService extends IUserManager.Stub {
private static final String ATTR_NEXT_SERIAL_NO = "nextSerialNumber";
private static final String ATTR_PARTIAL = "partial";
private static final String ATTR_PRE_CREATED = "preCreated";
+ private static final String ATTR_CONVERTED_FROM_PRE_CREATED = "convertedFromPreCreated";
private static final String ATTR_GUEST_TO_REMOVE = "guestToRemove";
private static final String ATTR_USER_VERSION = "version";
private static final String ATTR_PROFILE_GROUP_ID = "profileGroupId";
@@ -2912,6 +2913,9 @@ public class UserManagerService extends IUserManager.Stub {
if (userInfo.preCreated) {
serializer.attribute(null, ATTR_PRE_CREATED, "true");
}
+ if (userInfo.convertedFromPreCreated) {
+ serializer.attribute(null, ATTR_CONVERTED_FROM_PRE_CREATED, "true");
+ }
if (userInfo.guestToRemove) {
serializer.attribute(null, ATTR_GUEST_TO_REMOVE, "true");
}
@@ -3069,6 +3073,7 @@ public class UserManagerService extends IUserManager.Stub {
int restrictedProfileParentId = UserInfo.NO_PROFILE_GROUP_ID;
boolean partial = false;
boolean preCreated = false;
+ boolean converted = false;
boolean guestToRemove = false;
boolean persistSeedData = false;
String seedAccountName = null;
@@ -3120,6 +3125,10 @@ public class UserManagerService extends IUserManager.Stub {
if ("true".equals(valueString)) {
preCreated = true;
}
+ valueString = parser.getAttributeValue(null, ATTR_CONVERTED_FROM_PRE_CREATED);
+ if ("true".equals(valueString)) {
+ converted = true;
+ }
valueString = parser.getAttributeValue(null, ATTR_GUEST_TO_REMOVE);
if ("true".equals(valueString)) {
guestToRemove = true;
@@ -3177,6 +3186,7 @@ public class UserManagerService extends IUserManager.Stub {
userInfo.lastLoggedInFingerprint = lastLoggedInFingerprint;
userInfo.partial = partial;
userInfo.preCreated = preCreated;
+ userInfo.convertedFromPreCreated = converted;
userInfo.guestToRemove = guestToRemove;
userInfo.profileGroupId = profileGroupId;
userInfo.profileBadge = profileBadge;
@@ -3610,6 +3620,7 @@ public class UserManagerService extends IUserManager.Stub {
preCreatedUser.name = name;
preCreatedUser.flags = newFlags;
preCreatedUser.preCreated = false;
+ preCreatedUser.convertedFromPreCreated = true;
preCreatedUser.creationTime = getCreationTime();
synchronized (mPackagesLock) {
@@ -4703,6 +4714,7 @@ public class UserManagerService extends IUserManager.Stub {
running ? " (running)" : "",
user.partial ? " (partial)" : "",
user.preCreated ? " (pre-created)" : "",
+ user.convertedFromPreCreated ? " (converted)" : "",
current ? " (current)" : "");
} else {
// NOTE: the standard "list users" command is used by integration tests and
@@ -4788,6 +4800,9 @@ public class UserManagerService extends IUserManager.Stub {
if (userInfo.preCreated) {
pw.print(" <pre-created>");
}
+ if (userInfo.convertedFromPreCreated) {
+ pw.print(" <converted>");
+ }
pw.println();
pw.print(" Type: "); pw.println(userInfo.userType);
pw.print(" Flags: "); pw.print(userInfo.flags); pw.print(" (");
diff --git a/services/core/java/com/android/server/timezonedetector/TimeZoneDetectorCallbackImpl.java b/services/core/java/com/android/server/timezonedetector/TimeZoneDetectorCallbackImpl.java
index d64032325539..6a12b7c8f9a5 100644
--- a/services/core/java/com/android/server/timezonedetector/TimeZoneDetectorCallbackImpl.java
+++ b/services/core/java/com/android/server/timezonedetector/TimeZoneDetectorCallbackImpl.java
@@ -117,12 +117,13 @@ public final class TimeZoneDetectorCallbackImpl implements TimeZoneDetectorStrat
@Override
public ConfigurationInternal getConfigurationInternal(@UserIdInt int userId) {
+ boolean geoDetectionEnabled = mGeoDetectionFeatureEnabled && isGeoDetectionEnabled(userId);
return new ConfigurationInternal.Builder(userId)
.setUserConfigAllowed(isUserConfigAllowed(userId))
.setAutoDetectionSupported(isAutoDetectionSupported())
.setAutoDetectionEnabled(isAutoDetectionEnabled())
.setLocationEnabled(isLocationEnabled(userId))
- .setGeoDetectionEnabled(isGeoDetectionEnabled(userId))
+ .setGeoDetectionEnabled(geoDetectionEnabled)
.build();
}
@@ -167,9 +168,11 @@ public final class TimeZoneDetectorCallbackImpl implements TimeZoneDetectorStrat
final boolean autoDetectionEnabled = configuration.isAutoDetectionEnabled();
setAutoDetectionEnabled(autoDetectionEnabled);
- final int userId = configuration.getUserId();
- final boolean geoTzDetectionEnabled = configuration.isGeoDetectionEnabled();
- setGeoDetectionEnabled(userId, geoTzDetectionEnabled);
+ if (mGeoDetectionFeatureEnabled) {
+ final int userId = configuration.getUserId();
+ final boolean geoTzDetectionEnabled = configuration.isGeoDetectionEnabled();
+ setGeoDetectionEnabled(userId, geoTzDetectionEnabled);
+ }
}
}
@@ -211,4 +214,4 @@ public final class TimeZoneDetectorCallbackImpl implements TimeZoneDetectorStrat
return mContext.getSystemService(ConnectivityManager.class)
.isNetworkSupported(ConnectivityManager.TYPE_MOBILE);
}
-} \ No newline at end of file
+}
diff --git a/services/core/java/com/android/server/wm/ActivityMetricsLogger.java b/services/core/java/com/android/server/wm/ActivityMetricsLogger.java
index 6e9526afa962..fb06a9cb5887 100644
--- a/services/core/java/com/android/server/wm/ActivityMetricsLogger.java
+++ b/services/core/java/com/android/server/wm/ActivityMetricsLogger.java
@@ -67,6 +67,8 @@ import static com.android.server.wm.EventLogTags.WM_ACTIVITY_LAUNCH_TIME;
import android.annotation.NonNull;
import android.annotation.Nullable;
+import android.app.ActivityOptions;
+import android.app.ActivityOptions.SourceInfo;
import android.app.WaitResult;
import android.app.WindowConfiguration.WindowingMode;
import android.content.ComponentName;
@@ -161,6 +163,8 @@ class ActivityMetricsLogger {
* launched successfully.
*/
static final class LaunchingState {
+ /** The device uptime of {@link #notifyActivityLaunching}. */
+ private final long mCurrentUpTimeMs = SystemClock.uptimeMillis();
/** The timestamp of {@link #notifyActivityLaunching}. */
private long mCurrentTransitionStartTimeNs;
/** Non-null when a {@link TransitionInfo} is created for this state. */
@@ -199,6 +203,10 @@ class ActivityMetricsLogger {
/** The latest activity to have been launched. */
@NonNull ActivityRecord mLastLaunchedActivity;
+ /** The type of the source that triggers the launch event. */
+ @SourceInfo.SourceType int mSourceType;
+ /** The time from the source event (e.g. touch) to {@link #notifyActivityLaunching}. */
+ int mSourceEventDelayMs = INVALID_DELAY;
/** The time from {@link #mTransitionStartTimeNs} to {@link #notifyTransitionStarting}. */
int mCurrentTransitionDelayMs;
/** The time from {@link #mTransitionStartTimeNs} to {@link #notifyStartingWindowDrawn}. */
@@ -222,8 +230,8 @@ class ActivityMetricsLogger {
/** @return Non-null if there will be a window drawn event for the launch. */
@Nullable
static TransitionInfo create(@NonNull ActivityRecord r,
- @NonNull LaunchingState launchingState, boolean processRunning,
- boolean processSwitch, int startResult) {
+ @NonNull LaunchingState launchingState, @Nullable ActivityOptions options,
+ boolean processRunning, boolean processSwitch, int startResult) {
int transitionType = INVALID_TRANSITION_TYPE;
if (processRunning) {
if (startResult == START_SUCCESS) {
@@ -240,22 +248,31 @@ class ActivityMetricsLogger {
// That means the startResult is neither START_SUCCESS nor START_TASK_TO_FRONT.
return null;
}
- return new TransitionInfo(r, launchingState, transitionType, processRunning,
+ return new TransitionInfo(r, launchingState, options, transitionType, processRunning,
processSwitch);
}
/** Use {@link TransitionInfo#create} instead to ensure the transition type is valid. */
- private TransitionInfo(ActivityRecord r, LaunchingState launchingState, int transitionType,
- boolean processRunning, boolean processSwitch) {
+ private TransitionInfo(ActivityRecord r, LaunchingState launchingState,
+ ActivityOptions options, int transitionType, boolean processRunning,
+ boolean processSwitch) {
mLaunchingState = launchingState;
mTransitionStartTimeNs = launchingState.mCurrentTransitionStartTimeNs;
mTransitionType = transitionType;
mProcessRunning = processRunning;
mProcessSwitch = processSwitch;
mCurrentTransitionDeviceUptime =
- (int) TimeUnit.MILLISECONDS.toSeconds(SystemClock.uptimeMillis());
+ (int) TimeUnit.MILLISECONDS.toSeconds(launchingState.mCurrentUpTimeMs);
setLatestLaunchedActivity(r);
launchingState.mAssociatedTransitionInfo = this;
+ if (options != null) {
+ final SourceInfo sourceInfo = options.getSourceInfo();
+ if (sourceInfo != null) {
+ mSourceType = sourceInfo.type;
+ mSourceEventDelayMs =
+ (int) (launchingState.mCurrentUpTimeMs - sourceInfo.eventTimeMs);
+ }
+ }
}
/**
@@ -324,6 +341,8 @@ class ActivityMetricsLogger {
final private String launchedActivityAppRecordRequiredAbi;
final String launchedActivityShortComponentName;
final private String processName;
+ @VisibleForTesting final @SourceInfo.SourceType int sourceType;
+ @VisibleForTesting final int sourceEventDelayMs;
final private int reason;
final private int startingWindowDelayMs;
final private int bindApplicationDelayMs;
@@ -352,12 +371,14 @@ class ActivityMetricsLogger {
? null
: launchedActivity.app.getRequiredAbi();
reason = info.mReason;
+ sourceEventDelayMs = info.mSourceEventDelayMs;
startingWindowDelayMs = info.mStartingWindowDelayMs;
bindApplicationDelayMs = info.mBindApplicationDelayMs;
windowsDrawnDelayMs = info.mWindowsDrawnDelayMs;
type = info.mTransitionType;
processRecord = launchedActivity.app;
processName = launchedActivity.processName;
+ sourceType = info.mSourceType;
userId = launchedActivity.mUserId;
launchedActivityShortComponentName = launchedActivity.shortComponentName;
activityRecordIdHashCode = System.identityHashCode(launchedActivity);
@@ -513,9 +534,10 @@ class ActivityMetricsLogger {
* @param resultCode One of the {@link android.app.ActivityManager}.START_* flags, indicating
* the result of the launch.
* @param launchedActivity The activity that is being launched
+ * @param options The given options of the launching activity.
*/
void notifyActivityLaunched(@NonNull LaunchingState launchingState, int resultCode,
- @Nullable ActivityRecord launchedActivity) {
+ @Nullable ActivityRecord launchedActivity, @Nullable ActivityOptions options) {
if (launchedActivity == null) {
// The launch is aborted, e.g. intent not resolved, class not found.
abort(null /* info */, "nothing launched");
@@ -560,7 +582,7 @@ class ActivityMetricsLogger {
}
final TransitionInfo newInfo = TransitionInfo.create(launchedActivity, launchingState,
- processRunning, processSwitch, resultCode);
+ options, processRunning, processSwitch, resultCode);
if (newInfo == null) {
abort(info, "unrecognized launch");
return;
@@ -864,7 +886,9 @@ class ActivityMetricsLogger {
info.windowsDrawnDelayMs,
launchToken,
packageOptimizationInfo.getCompilationReason(),
- packageOptimizationInfo.getCompilationFilter());
+ packageOptimizationInfo.getCompilationFilter(),
+ info.sourceType,
+ info.sourceEventDelayMs);
if (DEBUG_METRICS) {
Slog.i(TAG, String.format("APP_START_OCCURRED(%s, %s, %s, %s, %s)",
@@ -970,7 +994,9 @@ class ActivityMetricsLogger {
: FrameworkStatsLog.APP_START_FULLY_DRAWN__TYPE__WITHOUT_BUNDLE,
info.mLastLaunchedActivity.info.name,
info.mProcessRunning,
- startupTimeMs);
+ startupTimeMs,
+ info.mSourceType,
+ info.mSourceEventDelayMs);
// Ends the trace started at the beginning of this function. This is located here to allow
// the trace slice to have a noticable duration.
diff --git a/services/core/java/com/android/server/wm/ActivityStackSupervisor.java b/services/core/java/com/android/server/wm/ActivityStackSupervisor.java
index 5196416e2cd3..ab464501193c 100644
--- a/services/core/java/com/android/server/wm/ActivityStackSupervisor.java
+++ b/services/core/java/com/android/server/wm/ActivityStackSupervisor.java
@@ -2515,7 +2515,7 @@ public class ActivityStackSupervisor implements RecentTasks.Callbacks {
targetActivity.applyOptionsLocked();
} finally {
mActivityMetricsLogger.notifyActivityLaunched(launchingState,
- START_TASK_TO_FRONT, targetActivity);
+ START_TASK_TO_FRONT, targetActivity, activityOptions);
}
mService.getActivityStartController().postStartActivityProcessingForLastStarter(
diff --git a/services/core/java/com/android/server/wm/ActivityStarter.java b/services/core/java/com/android/server/wm/ActivityStarter.java
index 19755f29043e..e8e4059af324 100644
--- a/services/core/java/com/android/server/wm/ActivityStarter.java
+++ b/services/core/java/com/android/server/wm/ActivityStarter.java
@@ -616,7 +616,7 @@ class ActivityStarter {
voiceInteractor, startFlags, doResume, options, inTask,
false /* restrictedBgActivity */, intentGrants);
mSupervisor.getActivityMetricsLogger().notifyActivityLaunched(launchingState,
- mLastStartActivityResult, mLastStartActivityRecord);
+ mLastStartActivityResult, mLastStartActivityRecord, options);
} finally {
onExecutionComplete();
}
@@ -704,7 +704,7 @@ class ActivityStarter {
// ActivityMetricsLogger will then wait for the windows to be drawn and populate
// WaitResult.
mSupervisor.getActivityMetricsLogger().notifyActivityLaunched(launchingState, res,
- mLastStartActivityRecord);
+ mLastStartActivityRecord, mOptions);
return getExternalResult(mRequest.waitResult == null ? res
: waitForResult(res, mLastStartActivityRecord));
}
diff --git a/services/core/java/com/android/server/wm/InputMonitor.java b/services/core/java/com/android/server/wm/InputMonitor.java
index 714591a831bd..acf5f75f7e23 100644
--- a/services/core/java/com/android/server/wm/InputMonitor.java
+++ b/services/core/java/com/android/server/wm/InputMonitor.java
@@ -562,7 +562,8 @@ final class InputMonitor {
}
if (mAddNavInputConsumerHandle) {
- mNavInputConsumer.show(mInputTransaction, w);
+ // We set the layer to z=MAX-1 so that it's always on top.
+ mNavInputConsumer.show(mInputTransaction, Integer.MAX_VALUE - 1);
mAddNavInputConsumerHandle = false;
}
diff --git a/services/core/java/com/android/server/wm/RecentsAnimation.java b/services/core/java/com/android/server/wm/RecentsAnimation.java
index 6c416830b59e..35338bb67469 100644
--- a/services/core/java/com/android/server/wm/RecentsAnimation.java
+++ b/services/core/java/com/android/server/wm/RecentsAnimation.java
@@ -250,7 +250,7 @@ class RecentsAnimation implements RecentsAnimationCallbacks,
mService.mRootWindowContainer.ensureActivitiesVisible(null, 0, PRESERVE_WINDOWS);
mStackSupervisor.getActivityMetricsLogger().notifyActivityLaunched(launchingState,
- START_TASK_TO_FRONT, targetActivity);
+ START_TASK_TO_FRONT, targetActivity, null /* options */);
// Register for stack order changes
mDefaultTaskDisplayArea.registerStackOrderChangedListener(this);
diff --git a/services/core/java/com/android/server/wm/Task.java b/services/core/java/com/android/server/wm/Task.java
index 15a44e8ab2f8..9172897b4869 100644
--- a/services/core/java/com/android/server/wm/Task.java
+++ b/services/core/java/com/android/server/wm/Task.java
@@ -5938,31 +5938,12 @@ class Task extends WindowContainer<WindowContainer> {
if (shouldSleepOrShutDownActivities()
&& mLastPausedActivity == next
&& mRootWindowContainer.allPausedActivitiesComplete()) {
- // If the current top activity may be able to occlude keyguard but the occluded state
- // has not been set, update visibility and check again if we should continue to resume.
- boolean nothingToResume = true;
- if (!mAtmService.mShuttingDown) {
- final boolean canShowWhenLocked = !mTopActivityOccludesKeyguard
- && next.canShowWhenLocked();
- final boolean mayDismissKeyguard = mTopDismissingKeyguardActivity != next
- && next.containsDismissKeyguardWindow();
-
- if (canShowWhenLocked || mayDismissKeyguard) {
- ensureActivitiesVisible(null /* starting */, 0 /* configChanges */,
- !PRESERVE_WINDOWS);
- nothingToResume = shouldSleepActivities();
- } else if (next.currentLaunchCanTurnScreenOn() && next.canTurnScreenOn()) {
- nothingToResume = false;
- }
- }
- if (nothingToResume) {
- // Make sure we have executed any pending transitions, since there
- // should be nothing left to do at this point.
- executeAppTransition(options);
- if (DEBUG_STATES) Slog.d(TAG_STATES,
- "resumeTopActivityLocked: Going to sleep and all paused");
- return false;
- }
+ // Make sure we have executed any pending transitions, since there
+ // should be nothing left to do at this point.
+ executeAppTransition(options);
+ if (DEBUG_STATES) Slog.d(TAG_STATES,
+ "resumeTopActivityLocked: Going to sleep and all paused");
+ return false;
}
// Make sure that the user who owns this activity is started. If not,
diff --git a/services/core/java/com/android/server/wm/TaskTapPointerEventListener.java b/services/core/java/com/android/server/wm/TaskTapPointerEventListener.java
index 06c2b1687fa4..523b484269c0 100644
--- a/services/core/java/com/android/server/wm/TaskTapPointerEventListener.java
+++ b/services/core/java/com/android/server/wm/TaskTapPointerEventListener.java
@@ -25,6 +25,7 @@ import static android.view.PointerIcon.TYPE_VERTICAL_DOUBLE_ARROW;
import android.graphics.Rect;
import android.graphics.Region;
import android.hardware.input.InputManager;
+import android.view.InputDevice;
import android.view.MotionEvent;
import android.view.WindowManagerPolicyConstants.PointerEventListener;
@@ -62,8 +63,15 @@ public class TaskTapPointerEventListener implements PointerEventListener {
public void onPointerEvent(MotionEvent motionEvent) {
switch (motionEvent.getActionMasked()) {
case MotionEvent.ACTION_DOWN: {
- final int x = (int) motionEvent.getX();
- final int y = (int) motionEvent.getY();
+ final int x;
+ final int y;
+ if (motionEvent.getSource() == InputDevice.SOURCE_MOUSE) {
+ x = (int) motionEvent.getXCursorPosition();
+ y = (int) motionEvent.getYCursorPosition();
+ } else {
+ x = (int) motionEvent.getX();
+ y = (int) motionEvent.getY();
+ }
synchronized (this) {
if (!mTouchExcludeRegion.contains(x, y)) {
diff --git a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
index e85bbd958898..183a1495b075 100644
--- a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
+++ b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
@@ -1536,9 +1536,21 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager {
/**
* Creates a new {@link CallerIdentity} object to represent the caller's identity.
+ */
+ @VisibleForTesting
+ protected CallerIdentity getCallerIdentity(@Nullable ComponentName adminComponent,
+ @NonNull String callerPackage) {
+ return adminComponent == null
+ ? getCallerIdentity(callerPackage)
+ : getCallerIdentity(adminComponent);
+ }
+
+ /**
+ * Creates a new {@link CallerIdentity} object to represent the caller's identity.
* The component name should be an active admin for the calling user.
*/
- private CallerIdentity getCallerIdentity(@NonNull ComponentName adminComponent) {
+ @VisibleForTesting
+ protected CallerIdentity getCallerIdentity(@NonNull ComponentName adminComponent) {
final int callerUid = mInjector.binderGetCallingUid();
final DevicePolicyData policy = getUserData(UserHandle.getUserId(callerUid));
ActiveAdmin admin = policy.mAdminMap.get(adminComponent);
@@ -2097,12 +2109,13 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager {
String.format("Device owner %s for user %d not found", doComponent,
caller.getUid()));
- Preconditions.checkSecurity(doAdmin.getUid() == caller.getUid(),
+ Preconditions.checkCallAuthorization(doAdmin.getUid() == caller.getUid(),
String.format("Admin %s is not owned by uid %d, but uid %d", doComponent,
caller.getUid(), doAdmin.getUid()));
- Preconditions.checkSecurity(doAdmin.info.getComponent().equals(caller.getComponentName()),
- String.format("Caller component %s is not device owner",
+ Preconditions.checkCallAuthorization(
+ doAdmin.info.getComponent().equals(caller.getComponentName()),
+ String.format("Caller component %s is not device owner",
caller.getComponentName()));
return doAdmin;
@@ -2119,12 +2132,13 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager {
Preconditions.checkState(poAdmin != null,
String.format("No device profile owner for caller %d", caller.getUid()));
- Preconditions.checkSecurity(poAdmin.getUid() == caller.getUid(),
+ Preconditions.checkCallAuthorization(poAdmin.getUid() == caller.getUid(),
String.format("Admin %s is not owned by uid %d", poAdminComponent,
caller.getUid()));
- Preconditions.checkSecurity(poAdmin.info.getComponent().equals(caller.getComponentName()),
- String.format("Caller component %s is not profile owner",
+ Preconditions.checkCallAuthorization(
+ poAdmin.info.getComponent().equals(caller.getComponentName()),
+ String.format("Caller component %s is not profile owner",
caller.getComponentName()));
return poAdmin;
@@ -2133,7 +2147,7 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager {
@NonNull ActiveAdmin getOrganizationOwnedProfileOwnerLocked(final CallerIdentity caller) {
final ActiveAdmin profileOwner = getProfileOwnerOfCallerLocked(caller);
- Preconditions.checkSecurity(
+ Preconditions.checkCallAuthorization(
mOwners.isProfileOwnerOfOrganizationOwnedDevice(caller.getUserId()),
String.format("Admin %s is not of an org-owned device",
profileOwner.info.getComponent()));
@@ -2881,10 +2895,10 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager {
Bundle onEnableData) {
Preconditions.checkArgumentNonnegative(userHandle, "Invalid userId");
- final CallerIdentity identity = getCallerIdentity();
+ final CallerIdentity caller = getCallerIdentity();
Preconditions.checkCallAuthorization(
hasCallingOrSelfPermission(permission.MANAGE_DEVICE_ADMINS));
- Preconditions.checkCallAuthorization(hasFullCrossUsersPermission(identity, userHandle));
+ Preconditions.checkCallAuthorization(hasFullCrossUsersPermission(caller, userHandle));
DevicePolicyData policy = getUserData(userHandle);
DeviceAdminInfo info = findAdmin(adminReceiver, userHandle,
@@ -3026,8 +3040,8 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager {
}
Preconditions.checkArgumentNonnegative(userHandle, "Invalid userId");
- final CallerIdentity identity = getCallerIdentity();
- Preconditions.checkCallAuthorization(hasFullCrossUsersPermission(identity, userHandle));
+ final CallerIdentity caller = getCallerIdentity();
+ Preconditions.checkCallAuthorization(hasFullCrossUsersPermission(caller, userHandle));
synchronized (getLockObject()) {
return getActiveAdminUncheckedLocked(adminReceiver, userHandle) != null;
@@ -3041,8 +3055,8 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager {
}
Preconditions.checkArgumentNonnegative(userHandle, "Invalid userId");
- final CallerIdentity identity = getCallerIdentity();
- Preconditions.checkCallAuthorization(hasFullCrossUsersPermission(identity, userHandle));
+ final CallerIdentity caller = getCallerIdentity();
+ Preconditions.checkCallAuthorization(hasFullCrossUsersPermission(caller, userHandle));
synchronized (getLockObject()) {
DevicePolicyData policyData = getUserData(userHandle);
@@ -3057,8 +3071,8 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager {
}
Preconditions.checkArgumentNonnegative(userHandle, "Invalid userId");
- final CallerIdentity identity = getCallerIdentity(adminReceiver);
- Preconditions.checkCallAuthorization(hasFullCrossUsersPermission(identity, userHandle));
+ final CallerIdentity caller = getCallerIdentity(adminReceiver);
+ Preconditions.checkCallAuthorization(hasFullCrossUsersPermission(caller, userHandle));
synchronized (getLockObject()) {
ActiveAdmin administrator = getActiveAdminUncheckedLocked(adminReceiver, userHandle);
@@ -3077,8 +3091,8 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager {
}
Preconditions.checkArgumentNonnegative(userHandle, "Invalid userId");
- final CallerIdentity identity = getCallerIdentity();
- Preconditions.checkCallAuthorization(hasFullCrossUsersPermission(identity, userHandle));
+ final CallerIdentity caller = getCallerIdentity();
+ Preconditions.checkCallAuthorization(hasFullCrossUsersPermission(caller, userHandle));
synchronized (getLockObject()) {
DevicePolicyData policy = getUserData(userHandle);
@@ -3101,8 +3115,8 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager {
}
Preconditions.checkArgumentNonnegative(userHandle, "Invalid userId");
- final CallerIdentity identity = getCallerIdentity();
- Preconditions.checkCallAuthorization(hasFullCrossUsersPermission(identity, userHandle));
+ final CallerIdentity caller = getCallerIdentity();
+ Preconditions.checkCallAuthorization(hasFullCrossUsersPermission(caller, userHandle));
synchronized (getLockObject()) {
DevicePolicyData policy = getUserData(userHandle);
@@ -3215,8 +3229,8 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager {
}
Preconditions.checkArgumentNonnegative(userHandle, "Invalid userId");
- final CallerIdentity identity = getCallerIdentity();
- Preconditions.checkCallAuthorization(hasFullCrossUsersPermission(identity, userHandle));
+ final CallerIdentity caller = getCallerIdentity();
+ Preconditions.checkCallAuthorization(hasFullCrossUsersPermission(caller, userHandle));
enforceUserUnlocked(userHandle);
synchronized (getLockObject()) {
@@ -3372,8 +3386,8 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager {
}
Preconditions.checkArgumentNonnegative(userHandle, "Invalid userId");
- final CallerIdentity identity = getCallerIdentity();
- Preconditions.checkCallAuthorization(hasFullCrossUsersPermission(identity, userHandle));
+ final CallerIdentity caller = getCallerIdentity();
+ Preconditions.checkCallAuthorization(hasFullCrossUsersPermission(caller, userHandle));
synchronized (getLockObject()) {
int mode = PASSWORD_QUALITY_UNSPECIFIED;
@@ -3588,8 +3602,8 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager {
}
Preconditions.checkArgumentNonnegative(userHandle, "Invalid userId");
- final CallerIdentity identity = getCallerIdentity();
- Preconditions.checkCallAuthorization(hasFullCrossUsersPermission(identity, userHandle));
+ final CallerIdentity caller = getCallerIdentity();
+ Preconditions.checkCallAuthorization(hasFullCrossUsersPermission(caller, userHandle));
synchronized (getLockObject()) {
long timeout = 0L;
@@ -3616,12 +3630,12 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager {
@Override
public boolean addCrossProfileWidgetProvider(ComponentName admin, String packageName) {
- final CallerIdentity identity = getCallerIdentity(admin);
- Preconditions.checkCallAuthorization(isProfileOwner(identity) || isDeviceOwner(identity));
+ final CallerIdentity caller = getCallerIdentity(admin);
+ Preconditions.checkCallAuthorization(isProfileOwner(caller) || isDeviceOwner(caller));
List<String> changedProviders = null;
synchronized (getLockObject()) {
- ActiveAdmin activeAdmin = getProfileOwnerOrDeviceOwnerLocked(identity);
+ ActiveAdmin activeAdmin = getProfileOwnerOrDeviceOwnerLocked(caller);
if (activeAdmin.crossProfileWidgetProviders == null) {
activeAdmin.crossProfileWidgetProviders = new ArrayList<>();
}
@@ -3629,7 +3643,7 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager {
if (!providers.contains(packageName)) {
providers.add(packageName);
changedProviders = new ArrayList<>(providers);
- saveSettingsLocked(identity.getUserId());
+ saveSettingsLocked(caller.getUserId());
}
}
@@ -3639,7 +3653,7 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager {
.write();
if (changedProviders != null) {
- mLocalService.notifyCrossProfileProvidersChanged(identity.getUserId(),
+ mLocalService.notifyCrossProfileProvidersChanged(caller.getUserId(),
changedProviders);
return true;
}
@@ -3649,12 +3663,12 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager {
@Override
public boolean removeCrossProfileWidgetProvider(ComponentName admin, String packageName) {
- final CallerIdentity identity = getCallerIdentity(admin);
- Preconditions.checkCallAuthorization(isProfileOwner(identity) || isDeviceOwner(identity));
+ final CallerIdentity caller = getCallerIdentity(admin);
+ Preconditions.checkCallAuthorization(isProfileOwner(caller) || isDeviceOwner(caller));
List<String> changedProviders = null;
synchronized (getLockObject()) {
- ActiveAdmin activeAdmin = getProfileOwnerOrDeviceOwnerLocked(identity);
+ ActiveAdmin activeAdmin = getProfileOwnerOrDeviceOwnerLocked(caller);
if (activeAdmin.crossProfileWidgetProviders == null
|| activeAdmin.crossProfileWidgetProviders.isEmpty()) {
return false;
@@ -3662,7 +3676,7 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager {
List<String> providers = activeAdmin.crossProfileWidgetProviders;
if (providers.remove(packageName)) {
changedProviders = new ArrayList<>(providers);
- saveSettingsLocked(identity.getUserId());
+ saveSettingsLocked(caller.getUserId());
}
}
@@ -3672,7 +3686,7 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager {
.write();
if (changedProviders != null) {
- mLocalService.notifyCrossProfileProvidersChanged(identity.getUserId(),
+ mLocalService.notifyCrossProfileProvidersChanged(caller.getUserId(),
changedProviders);
return true;
}
@@ -3682,11 +3696,11 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager {
@Override
public List<String> getCrossProfileWidgetProviders(ComponentName admin) {
- final CallerIdentity identity = getCallerIdentity(admin);
- Preconditions.checkCallAuthorization(isProfileOwner(identity) || isDeviceOwner(identity));
+ final CallerIdentity caller = getCallerIdentity(admin);
+ Preconditions.checkCallAuthorization(isProfileOwner(caller) || isDeviceOwner(caller));
synchronized (getLockObject()) {
- ActiveAdmin activeAdmin = getProfileOwnerOrDeviceOwnerLocked(identity);
+ ActiveAdmin activeAdmin = getProfileOwnerOrDeviceOwnerLocked(caller);
if (activeAdmin.crossProfileWidgetProviders == null
|| activeAdmin.crossProfileWidgetProviders.isEmpty()) {
return null;
@@ -3731,8 +3745,8 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager {
}
Preconditions.checkArgumentNonnegative(userHandle, "Invalid userId");
- final CallerIdentity identity = getCallerIdentity();
- Preconditions.checkCallAuthorization(hasFullCrossUsersPermission(identity, userHandle));
+ final CallerIdentity caller = getCallerIdentity();
+ Preconditions.checkCallAuthorization(hasFullCrossUsersPermission(caller, userHandle));
synchronized (getLockObject()) {
return getPasswordExpirationLocked(who, userHandle, parent);
@@ -3941,8 +3955,8 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager {
}
Preconditions.checkArgumentNonnegative(userHandle, "Invalid userId");
- final CallerIdentity identity = getCallerIdentity();
- Preconditions.checkCallAuthorization(hasFullCrossUsersPermission(identity, userHandle));
+ final CallerIdentity caller = getCallerIdentity();
+ Preconditions.checkCallAuthorization(hasFullCrossUsersPermission(caller, userHandle));
synchronized (getLockObject()) {
if (who != null) {
@@ -3985,8 +3999,8 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager {
}
Preconditions.checkArgumentNonnegative(userHandle, "Invalid userId");
- final CallerIdentity identity = getCallerIdentity();
- Preconditions.checkCallAuthorization(hasFullCrossUsersPermission(identity, userHandle));
+ final CallerIdentity caller = getCallerIdentity();
+ Preconditions.checkCallAuthorization(hasFullCrossUsersPermission(caller, userHandle));
ArrayList<PasswordMetrics> adminMetrics = new ArrayList<>();
synchronized (getLockObject()) {
@@ -4006,8 +4020,8 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager {
}
Preconditions.checkArgumentNonnegative(userHandle, "Invalid userId");
- final CallerIdentity identity = getCallerIdentity();
- Preconditions.checkCallAuthorization(hasFullCrossUsersPermission(identity, userHandle));
+ final CallerIdentity caller = getCallerIdentity();
+ Preconditions.checkCallAuthorization(hasFullCrossUsersPermission(caller, userHandle));
enforceUserUnlocked(userHandle, parent);
synchronized (getLockObject()) {
@@ -4041,8 +4055,8 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager {
}
Preconditions.checkArgumentNonnegative(userHandle, "Invalid userId");
- final CallerIdentity identity = getCallerIdentity();
- Preconditions.checkCallAuthorization(hasFullCrossUsersPermission(identity, userHandle));
+ final CallerIdentity caller = getCallerIdentity();
+ Preconditions.checkCallAuthorization(hasFullCrossUsersPermission(caller, userHandle));
enforceManagedProfile(userHandle, "call APIs refering to the parent profile");
synchronized (getLockObject()) {
@@ -4063,8 +4077,8 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager {
}
Preconditions.checkArgumentNonnegative(userHandle, "Invalid userId");
- final CallerIdentity identity = getCallerIdentity();
- Preconditions.checkCallAuthorization(hasFullCrossUsersPermission(identity, userHandle));
+ final CallerIdentity caller = getCallerIdentity();
+ Preconditions.checkCallAuthorization(hasFullCrossUsersPermission(caller, userHandle));
enforceNotManagedProfile(userHandle, "check password sufficiency");
enforceUserUnlocked(userHandle);
@@ -4154,11 +4168,11 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager {
}
Preconditions.checkArgumentNonnegative(userHandle, "Invalid userId");
- final CallerIdentity identity = getCallerIdentity();
- Preconditions.checkCallAuthorization(hasFullCrossUsersPermission(identity, userHandle));
+ final CallerIdentity caller = getCallerIdentity();
+ Preconditions.checkCallAuthorization(hasFullCrossUsersPermission(caller, userHandle));
synchronized (getLockObject()) {
- if (!isSystemUid(identity)) {
+ if (!isSystemUid(caller)) {
// This API can be called by an active device admin or by keyguard code.
if (!hasCallingPermission(permission.ACCESS_KEYGUARD_SECURE_STORAGE)) {
getActiveAdminForCallerLocked(
@@ -4205,8 +4219,8 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager {
}
Preconditions.checkArgumentNonnegative(userHandle, "Invalid userId");
- final CallerIdentity identity = getCallerIdentity();
- Preconditions.checkCallAuthorization(hasFullCrossUsersPermission(identity, userHandle));
+ final CallerIdentity caller = getCallerIdentity();
+ Preconditions.checkCallAuthorization(hasFullCrossUsersPermission(caller, userHandle));
synchronized (getLockObject()) {
ActiveAdmin admin = (who != null)
@@ -4223,8 +4237,8 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager {
}
Preconditions.checkArgumentNonnegative(userHandle, "Invalid userId");
- final CallerIdentity identity = getCallerIdentity();
- Preconditions.checkCallAuthorization(hasFullCrossUsersPermission(identity, userHandle));
+ final CallerIdentity caller = getCallerIdentity();
+ Preconditions.checkCallAuthorization(hasFullCrossUsersPermission(caller, userHandle));
synchronized (getLockObject()) {
ActiveAdmin admin = getAdminWithMinimumFailedPasswordsForWipeLocked(
@@ -4498,8 +4512,8 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager {
}
Preconditions.checkArgumentNonnegative(userHandle, "Invalid userId");
- final CallerIdentity identity = getCallerIdentity();
- Preconditions.checkCallAuthorization(hasFullCrossUsersPermission(identity, userHandle));
+ final CallerIdentity caller = getCallerIdentity();
+ Preconditions.checkCallAuthorization(hasFullCrossUsersPermission(caller, userHandle));
synchronized (getLockObject()) {
if (who != null) {
@@ -4577,8 +4591,8 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager {
}
Preconditions.checkArgumentNonnegative(userId, "Invalid userId");
- final CallerIdentity identity = getCallerIdentity();
- Preconditions.checkCallAuthorization(hasFullCrossUsersPermission(identity, userId));
+ final CallerIdentity caller = getCallerIdentity();
+ Preconditions.checkCallAuthorization(hasFullCrossUsersPermission(caller, userId));
if (!mLockPatternUtils.hasSecureLockScreen()) {
// No strong auth timeout on devices not supporting the
@@ -4716,20 +4730,6 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager {
enforceProfileOrDeviceOwner(who);
}
- private void enforceDeviceOwnerOrProfileOwnerOnOrganizationOwnedDevice(ComponentName who) {
- synchronized (getLockObject()) {
- getActiveAdminForCallerLocked(
- who, DeviceAdminInfo.USES_POLICY_ORGANIZATION_OWNED_PROFILE_OWNER);
- }
- }
-
- private void enforceProfileOwnerOfOrganizationOwnedDevice(ActiveAdmin admin) {
- if (!isProfileOwnerOfOrganizationOwnedDevice(admin)) {
- throw new SecurityException(String.format("Provided admin %s is either not a profile "
- + "owner or not on a corporate-owned device.", admin));
- }
- }
-
@Override
public boolean approveCaCert(String alias, int userId, boolean approval) {
enforceManageUsers();
@@ -4832,29 +4832,27 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager {
public boolean installKeyPair(ComponentName who, String callerPackage, byte[] privKey,
byte[] cert, byte[] chain, String alias, boolean requestAccess,
boolean isUserSelectable) {
- enforceCanManageScope(who, callerPackage, DeviceAdminInfo.USES_POLICY_PROFILE_OWNER,
- DELEGATION_CERT_INSTALL);
-
+ final CallerIdentity caller = getCallerIdentity(who, callerPackage);
+ Preconditions.checkCallAuthorization(isDeviceOwner(caller)
+ || isProfileOwner(caller) || isCallerDelegate(caller, DELEGATION_CERT_INSTALL));
- final int callingUid = mInjector.binderGetCallingUid();
final long id = mInjector.binderClearCallingIdentity();
try {
final KeyChainConnection keyChainConnection =
- KeyChain.bindAsUser(mContext, UserHandle.getUserHandleForUid(callingUid));
+ KeyChain.bindAsUser(mContext, caller.getUserHandle());
try {
IKeyChainService keyChain = keyChainConnection.getService();
if (!keyChain.installKeyPair(privKey, cert, chain, alias, KeyStore.UID_SELF)) {
return false;
}
if (requestAccess) {
- keyChain.setGrant(callingUid, alias, true);
+ keyChain.setGrant(caller.getUid(), alias, true);
}
keyChain.setUserSelectable(alias, isUserSelectable);
- final boolean isDelegate = (who == null);
DevicePolicyEventLogger
.createEvent(DevicePolicyEnums.INSTALL_KEY_PAIR)
- .setAdmin(callerPackage)
- .setBoolean(isDelegate)
+ .setAdmin(caller.getPackageName())
+ .setBoolean(/* isDelegate */ who == null)
.write();
return true;
} catch (RemoteException e) {
@@ -4873,23 +4871,22 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager {
@Override
public boolean removeKeyPair(ComponentName who, String callerPackage, String alias) {
- enforceCanManageScope(who, callerPackage, DeviceAdminInfo.USES_POLICY_PROFILE_OWNER,
- DELEGATION_CERT_INSTALL);
+ final CallerIdentity caller = getCallerIdentity(who, callerPackage);
+ Preconditions.checkCallAuthorization(isDeviceOwner(caller)
+ || isProfileOwner(caller) || isCallerDelegate(caller, DELEGATION_CERT_INSTALL));
- final UserHandle userHandle = new UserHandle(UserHandle.getCallingUserId());
final long id = Binder.clearCallingIdentity();
try {
- final KeyChainConnection keyChainConnection = KeyChain.bindAsUser(mContext, userHandle);
+ final KeyChainConnection keyChainConnection =
+ KeyChain.bindAsUser(mContext, caller.getUserHandle());
try {
IKeyChainService keyChain = keyChainConnection.getService();
- final boolean result = keyChain.removeKeyPair(alias);
- final boolean isDelegate = (who == null);
DevicePolicyEventLogger
.createEvent(DevicePolicyEnums.REMOVE_KEY_PAIR)
- .setAdmin(callerPackage)
- .setBoolean(isDelegate)
+ .setAdmin(caller.getPackageName())
+ .setBoolean(/* isDelegate */ who == null)
.write();
- return result;
+ return keyChain.removeKeyPair(alias);
} catch (RemoteException e) {
Log.e(LOG_TAG, "Removing keypair", e);
} finally {
@@ -4905,39 +4902,30 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager {
}
@Override
- public boolean setKeyGrantForApp(
- ComponentName who, String callerPackage, String alias, String packageName,
- boolean hasGrant) {
- enforceCanManageScope(who, callerPackage, DeviceAdminInfo.USES_POLICY_PROFILE_OWNER,
- DELEGATION_CERT_SELECTION);
+ public boolean setKeyGrantForApp(ComponentName who, String callerPackage, String alias,
+ String packageName, boolean hasGrant) {
+ Preconditions.checkStringNotEmpty(alias, "Alias to grant cannot be empty");
+ Preconditions.checkStringNotEmpty(packageName, "Package to grant to cannot be empty");
- if (TextUtils.isEmpty(alias)) {
- throw new IllegalArgumentException("Alias to grant cannot be empty.");
- }
+ final CallerIdentity caller = getCallerIdentity(who, callerPackage);
+ Preconditions.checkCallAuthorization(isDeviceOwner(caller)
+ || isProfileOwner(caller) || isCallerDelegate(caller, DELEGATION_CERT_INSTALL));
- if (TextUtils.isEmpty(packageName)) {
- throw new IllegalArgumentException("Package to grant to cannot be empty.");
- }
-
- final int userId = mInjector.userHandleGetCallingUserId();
final int granteeUid;
try {
ApplicationInfo ai = mInjector.getIPackageManager().getApplicationInfo(
- packageName, 0, userId);
- if (ai == null) {
- throw new IllegalArgumentException(
- String.format("Provided package %s is not installed", packageName));
- }
+ packageName, 0, caller.getUserId());
+ Preconditions.checkArgument(ai != null,
+ String.format("Provided package %s is not installed", packageName));
granteeUid = ai.uid;
} catch (RemoteException e) {
throw new IllegalStateException("Failure getting grantee uid", e);
}
- final int callingUid = mInjector.binderGetCallingUid();
final long id = mInjector.binderClearCallingIdentity();
try {
final KeyChainConnection keyChainConnection =
- KeyChain.bindAsUser(mContext, UserHandle.getUserHandleForUid(callingUid));
+ KeyChain.bindAsUser(mContext, caller.getUserHandle());
try {
IKeyChainService keyChain = keyChainConnection.getService();
keyChain.setGrant(granteeUid, alias, hasGrant);
@@ -4980,23 +4968,22 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager {
* access to device identifiers in this case as part of the delegation.
*/
@VisibleForTesting
- public void enforceCallerCanRequestDeviceIdAttestation(
- ComponentName who, String callerPackage, int callerUid) throws SecurityException {
- final int userId = UserHandle.getUserId(callerUid);
-
+ public void enforceCallerCanRequestDeviceIdAttestation(CallerIdentity caller)
+ throws SecurityException {
/**
* First check if there's a profile owner because the device could be in COMP mode (where
* there's a device owner and profile owner on the same device).
* If the caller is from the work profile, then it must be the PO or the delegate, and
* it must have the right permission to access device identifiers.
*/
- if (hasProfileOwner(userId)) {
+ if (hasProfileOwner(caller.getUserId())) {
// Make sure that the caller is the profile owner or delegate.
- enforceCanManageScope(who, callerPackage, DeviceAdminInfo.USES_POLICY_PROFILE_OWNER,
- DELEGATION_CERT_INSTALL);
+ Preconditions.checkCallAuthorization(
+ isDeviceOwner(caller) || isProfileOwner(caller) || isCallerDelegate(
+ caller, DELEGATION_CERT_INSTALL));
// Verify that the managed profile is on an organization-owned device and as such
// the profile owner can access Device IDs.
- if (isProfileOwnerOfOrganizationOwnedDevice(userId)) {
+ if (isProfileOwnerOfOrganizationOwnedDevice(caller.getUserId())) {
return;
}
throw new SecurityException(
@@ -5004,8 +4991,8 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager {
}
// If not, fall back to the device owner check.
- enforceCanManageScope(who, callerPackage, DeviceAdminInfo.USES_POLICY_DEVICE_OWNER,
- DELEGATION_CERT_INSTALL);
+ Preconditions.checkCallAuthorization(
+ isDeviceOwner(caller) || isCallerDelegate(caller, DELEGATION_CERT_INSTALL));
}
@VisibleForTesting
@@ -5046,26 +5033,29 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager {
@Override
public boolean generateKeyPair(ComponentName who, String callerPackage, String algorithm,
- ParcelableKeyGenParameterSpec parcelableKeySpec,
- int idAttestationFlags,
+ ParcelableKeyGenParameterSpec parcelableKeySpec, int idAttestationFlags,
KeymasterCertificateChain attestationChain) {
// Get attestation flags, if any.
final int[] attestationUtilsFlags = translateIdAttestationFlags(idAttestationFlags);
final boolean deviceIdAttestationRequired = attestationUtilsFlags != null;
- final int callingUid = mInjector.binderGetCallingUid();
+ final KeyGenParameterSpec keySpec = parcelableKeySpec.getSpec();
+ final String alias = keySpec.getKeystoreAlias();
+
+ Preconditions.checkStringNotEmpty(alias, "Empty alias provided");
+ Preconditions.checkArgument(
+ !deviceIdAttestationRequired || keySpec.getAttestationChallenge() != null,
+ "Requested Device ID attestation but challenge is empty");
+ final CallerIdentity caller = getCallerIdentity(who, callerPackage);
if (deviceIdAttestationRequired && attestationUtilsFlags.length > 0) {
- enforceCallerCanRequestDeviceIdAttestation(who, callerPackage, callingUid);
+ // TODO: replace enforce methods
+ enforceCallerCanRequestDeviceIdAttestation(caller);
enforceIndividualAttestationSupportedIfRequested(attestationUtilsFlags);
} else {
- enforceCanManageScope(who, callerPackage, DeviceAdminInfo.USES_POLICY_PROFILE_OWNER,
- DELEGATION_CERT_INSTALL);
- }
- final KeyGenParameterSpec keySpec = parcelableKeySpec.getSpec();
- final String alias = keySpec.getKeystoreAlias();
- if (TextUtils.isEmpty(alias)) {
- throw new IllegalArgumentException("Empty alias provided.");
+ Preconditions.checkCallAuthorization(isDeviceOwner(caller) || isProfileOwner(caller)
+ || isCallerDelegate(caller, DELEGATION_CERT_INSTALL));
}
+
// As the caller will be granted access to the key, ensure no UID was specified, as
// it will not have the desired effect.
if (keySpec.getUid() != KeyStore.UID_SELF) {
@@ -5073,24 +5063,16 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager {
return false;
}
- if (deviceIdAttestationRequired && (keySpec.getAttestationChallenge() == null)) {
- throw new IllegalArgumentException(
- "Requested Device ID attestation but challenge is empty.");
- }
-
- final UserHandle userHandle = mInjector.binderGetCallingUserHandle();
final long id = mInjector.binderClearCallingIdentity();
try {
try (KeyChainConnection keyChainConnection =
- KeyChain.bindAsUser(mContext, userHandle)) {
+ KeyChain.bindAsUser(mContext, caller.getUserHandle())) {
IKeyChainService keyChain = keyChainConnection.getService();
// Copy the provided keySpec, excluding the attestation challenge, which will be
// used later for requesting key attestation record.
- final KeyGenParameterSpec noAttestationSpec =
- new KeyGenParameterSpec.Builder(keySpec)
- .setAttestationChallenge(null)
- .build();
+ final KeyGenParameterSpec noAttestationSpec = new KeyGenParameterSpec.Builder(
+ keySpec).setAttestationChallenge(null).build();
final int generationResult = keyChain.generateKeyPair(algorithm,
new ParcelableKeyGenParameterSpec(noAttestationSpec));
@@ -5112,7 +5094,7 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager {
// Note the use of the calling UID, since the request for the private
// key will come from the client's process, so the grant has to be for
// that UID.
- keyChain.setGrant(callingUid, alias, true);
+ keyChain.setGrant(caller.getUid(), alias, true);
final byte[] attestationChallenge = keySpec.getAttestationChallenge();
if (attestationChallenge != null) {
@@ -5130,11 +5112,10 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager {
return false;
}
}
- final boolean isDelegate = (who == null);
DevicePolicyEventLogger
.createEvent(DevicePolicyEnums.GENERATE_KEY_PAIR)
- .setAdmin(callerPackage)
- .setBoolean(isDelegate)
+ .setAdmin(caller.getPackageName())
+ .setBoolean(/* isDelegate */ who == null)
.setInt(idAttestationFlags)
.setStrings(algorithm)
.write();
@@ -5165,23 +5146,22 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager {
@Override
public boolean setKeyPairCertificate(ComponentName who, String callerPackage, String alias,
byte[] cert, byte[] chain, boolean isUserSelectable) {
- enforceCanManageScope(who, callerPackage, DeviceAdminInfo.USES_POLICY_PROFILE_OWNER,
- DELEGATION_CERT_INSTALL);
+ final CallerIdentity caller = getCallerIdentity(who, callerPackage);
+ Preconditions.checkCallAuthorization(isDeviceOwner(caller)
+ || isProfileOwner(caller) || isCallerDelegate(caller, DELEGATION_CERT_INSTALL));
- final int callingUid = mInjector.binderGetCallingUid();
final long id = mInjector.binderClearCallingIdentity();
try (final KeyChainConnection keyChainConnection =
- KeyChain.bindAsUser(mContext, UserHandle.getUserHandleForUid(callingUid))) {
+ KeyChain.bindAsUser(mContext, caller.getUserHandle())) {
IKeyChainService keyChain = keyChainConnection.getService();
if (!keyChain.setKeyPairCertificate(alias, cert, chain)) {
return false;
}
keyChain.setUserSelectable(alias, isUserSelectable);
- final boolean isDelegate = (who == null);
DevicePolicyEventLogger
.createEvent(DevicePolicyEnums.SET_KEY_PAIR_CERTIFICATE)
- .setAdmin(callerPackage)
- .setBoolean(isDelegate)
+ .setAdmin(caller.getPackageName())
+ .setBoolean(/* isDelegate */ who == null)
.write();
return true;
} catch (InterruptedException e) {
@@ -5301,7 +5281,7 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager {
Objects.requireNonNull(who, "ComponentName is null");
Preconditions.checkStringNotEmpty(delegatePackage, "Delegate package is null or empty");
Preconditions.checkCollectionElementsNotNull(scopeList, "Scopes");
- final CallerIdentity identity = getCallerIdentity(who);
+ final CallerIdentity caller = getCallerIdentity(who);
// Remove possible duplicates.
final ArrayList<String> scopes = new ArrayList(new ArraySet(scopeList));
@@ -5310,12 +5290,12 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager {
throw new IllegalArgumentException("Unexpected delegation scopes");
}
// Retrieve the user ID of the calling process.
- final int userId = identity.getUserId();
+ final int userId = caller.getUserId();
final boolean hasDoDelegation = !Collections.disjoint(scopes, DEVICE_OWNER_DELEGATIONS);
synchronized (getLockObject()) {
// Ensure calling process is device/profile owner.
if (hasDoDelegation) {
- Preconditions.checkCallAuthorization(isDeviceOwner(identity));
+ Preconditions.checkCallAuthorization(isDeviceOwner(caller));
} else {
// TODO move whole condition out of synchronized block
getActiveAdminForCallerLocked(who, DeviceAdminInfo.USES_POLICY_PROFILE_OWNER);
@@ -5538,49 +5518,30 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager {
}
/**
- * Throw a security exception if a ComponentName is given and it is not a device/profile owner
- * or if the calling process is not a delegate of the given scope.
+ * Check whether a caller application has been delegated a given scope via
+ * {@link #setDelegatedScopes} to access privileged APIs on the behalf of a profile owner or
+ * device owner.
+ * <p>
+ * This is done by checking that the calling package was granted {@code scope} delegation and
+ * then comparing the calling UID with the UID of the calling package as reported by
+ * {@link PackageManager#getPackageUidAsUser}.
*
- * @param who the device owner of profile owner, or null if {@code callerPackage} is a
- * {@code scope} delegate.
- * @param callerPackage the name of the calling package. Required if {@code who} is
- * {@code null}.
- * @param reqPolicy the policy used in the API whose access permission is being checked.
- * @param scope the delegation scope corresponding to the API being checked.
- * @throws SecurityException if {@code who} is given and is not an owner for {@code reqPolicy};
- * or when {@code who} is {@code null} and {@code callerPackage} is not a delegate
- * of {@code scope}.
+ * @param caller the calling identity
+ * @param scope the delegation scope to be checked.
+ * @return {@code true} if the calling process is a delegate of {@code scope}.
*/
- private void enforceCanManageScope(ComponentName who, String callerPackage, int reqPolicy,
- String scope) {
- enforceCanManageScopeOrCheckPermission(who, callerPackage, reqPolicy, scope, null);
- }
+ private boolean isCallerDelegate(CallerIdentity caller, String scope) {
+ Objects.requireNonNull(caller.getPackageName(), "callerPackage is null");
+ Preconditions.checkArgument(Arrays.asList(DELEGATIONS).contains(scope),
+ String.format("Unexpected delegation scope: %s", scope));
- /**
- * Throw a security exception if a ComponentName is given and it is not a device/profile owner
- * OR if the calling process is not a delegate of the given scope and does not hold the
- * required permission.
- */
- private void enforceCanManageScopeOrCheckPermission(@Nullable ComponentName who,
- @NonNull String callerPackage, int reqPolicy, @NonNull String scope,
- @Nullable String permission) {
- // If a ComponentName is given ensure it is a device or profile owner according to policy.
- if (who != null) {
- synchronized (getLockObject()) {
- getActiveAdminForCallerLocked(who, reqPolicy);
- }
- } else {
- // If no ComponentName is given ensure calling process has scope delegation or required
- // permission
- if (isCallerDelegate(callerPackage, mInjector.binderGetCallingUid(), scope)) {
- return;
- }
- if (permission == null) {
- throw new SecurityException("Caller with uid " + mInjector.binderGetCallingUid()
- + " is not a delegate of scope " + scope + ".");
- } else {
- mContext.enforceCallingOrSelfPermission(permission, null);
- }
+ synchronized (getLockObject()) {
+ // Retrieve user policy data.
+ final DevicePolicyData policy = getUserData(caller.getUserId());
+ // Retrieve the list of delegation scopes granted to callerPackage.
+ final List<String> scopes = policy.mDelegationMap.get(caller.getPackageName());
+ // Check callingUid only if callerPackage has the required scope delegation.
+ return scopes != null && scopes.contains(scope);
}
}
@@ -5789,32 +5750,27 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager {
if (!mHasFeature) {
return;
}
+ final CallerIdentity caller = getCallerIdentity();
+ boolean calledByProfileOwnerOnOrgOwnedDevice =
+ isProfileOwnerOfOrganizationOwnedDevice(caller);
+ if (calledOnParentInstance) {
+ Preconditions.checkCallAuthorization(calledByProfileOwnerOnOrgOwnedDevice,
+ "Wiping the entire device can only be done by a profile owner on "
+ + "organization-owned device.");
+ }
+ if ((flags & WIPE_RESET_PROTECTION_DATA) != 0) {
+ Preconditions.checkCallAuthorization(
+ isDeviceOwner(caller) || calledByProfileOwnerOnOrgOwnedDevice,
+ "Only device owners or proflie owners of organization-owned device can set "
+ + "WIPE_RESET_PROTECTION_DATA");
+ }
final ActiveAdmin admin;
synchronized (getLockObject()) {
admin = getActiveAdminForCallerLocked(null, DeviceAdminInfo.USES_POLICY_WIPE_DATA);
}
-
- if (admin == null) {
- throw new SecurityException(String.format("No active admin for user %d",
- mInjector.userHandleGetCallingUserId()));
- }
-
- boolean calledByProfileOwnerOnOrgOwnedDevice =
- isProfileOwnerOfOrganizationOwnedDevice(admin);
-
- if (calledOnParentInstance && !calledByProfileOwnerOnOrgOwnedDevice) {
- throw new SecurityException("Wiping the entire device can only be done by a profile"
- + "owner on organization-owned device.");
- }
-
- if ((flags & WIPE_RESET_PROTECTION_DATA) != 0) {
- if (!isDeviceOwner(admin) && !calledByProfileOwnerOnOrgOwnedDevice) {
- throw new SecurityException(
- "Only device owners or proflie owners of organization-owned device"
- + " can set WIPE_RESET_PROTECTION_DATA");
- }
- }
+ Preconditions.checkCallAuthorization(admin != null,
+ String.format("No active admin for user %d", caller.getUserId()));
if (TextUtils.isEmpty(wipeReasonForUser)) {
if (calledByProfileOwnerOnOrgOwnedDevice && !calledOnParentInstance) {
@@ -6004,10 +5960,10 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager {
}
Preconditions.checkArgumentNonnegative(userHandle, "Invalid userId");
- final CallerIdentity identity = comp != null
+ final CallerIdentity caller = comp != null
? getCallerIdentity(comp)
: getCallerIdentity();
- Preconditions.checkCallAuthorization(hasFullCrossUsersPermission(identity, userHandle));
+ Preconditions.checkCallAuthorization(hasFullCrossUsersPermission(caller, userHandle));
Preconditions.checkCallAuthorization(hasCallingOrSelfPermission(BIND_DEVICE_ADMIN));
synchronized (getLockObject()) {
@@ -6087,8 +6043,8 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager {
public void reportFailedPasswordAttempt(int userHandle) {
Preconditions.checkArgumentNonnegative(userHandle, "Invalid userId");
- final CallerIdentity identity = getCallerIdentity();
- Preconditions.checkCallAuthorization(hasFullCrossUsersPermission(identity, userHandle));
+ final CallerIdentity caller = getCallerIdentity();
+ Preconditions.checkCallAuthorization(hasFullCrossUsersPermission(caller, userHandle));
Preconditions.checkCallAuthorization(hasCallingOrSelfPermission(BIND_DEVICE_ADMIN));
if (!isSeparateProfileChallengeEnabled(userHandle)) {
enforceNotManagedProfile(userHandle,
@@ -6168,8 +6124,8 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager {
public void reportSuccessfulPasswordAttempt(int userHandle) {
Preconditions.checkArgumentNonnegative(userHandle, "Invalid userId");
- final CallerIdentity identity = getCallerIdentity();
- Preconditions.checkCallAuthorization(hasFullCrossUsersPermission(identity, userHandle));
+ final CallerIdentity caller = getCallerIdentity();
+ Preconditions.checkCallAuthorization(hasFullCrossUsersPermission(caller, userHandle));
Preconditions.checkCallAuthorization(hasCallingOrSelfPermission(BIND_DEVICE_ADMIN));
synchronized (getLockObject()) {
@@ -6198,8 +6154,8 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager {
public void reportFailedBiometricAttempt(int userHandle) {
Preconditions.checkArgumentNonnegative(userHandle, "Invalid userId");
- final CallerIdentity identity = getCallerIdentity();
- Preconditions.checkCallAuthorization(hasFullCrossUsersPermission(identity, userHandle));
+ final CallerIdentity caller = getCallerIdentity();
+ Preconditions.checkCallAuthorization(hasFullCrossUsersPermission(caller, userHandle));
Preconditions.checkCallAuthorization(hasCallingOrSelfPermission(BIND_DEVICE_ADMIN));
if (mInjector.securityLogIsLoggingEnabled()) {
@@ -6212,8 +6168,8 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager {
public void reportSuccessfulBiometricAttempt(int userHandle) {
Preconditions.checkArgumentNonnegative(userHandle, "Invalid userId");
- final CallerIdentity identity = getCallerIdentity();
- Preconditions.checkCallAuthorization(hasFullCrossUsersPermission(identity, userHandle));
+ final CallerIdentity caller = getCallerIdentity();
+ Preconditions.checkCallAuthorization(hasFullCrossUsersPermission(caller, userHandle));
Preconditions.checkCallAuthorization(hasCallingOrSelfPermission(BIND_DEVICE_ADMIN));
if (mInjector.securityLogIsLoggingEnabled()) {
@@ -6226,8 +6182,8 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager {
public void reportKeyguardDismissed(int userHandle) {
Preconditions.checkArgumentNonnegative(userHandle, "Invalid userId");
- final CallerIdentity identity = getCallerIdentity();
- Preconditions.checkCallAuthorization(hasFullCrossUsersPermission(identity, userHandle));
+ final CallerIdentity caller = getCallerIdentity();
+ Preconditions.checkCallAuthorization(hasFullCrossUsersPermission(caller, userHandle));
Preconditions.checkCallAuthorization(hasCallingOrSelfPermission(BIND_DEVICE_ADMIN));
if (mInjector.securityLogIsLoggingEnabled()) {
@@ -6239,8 +6195,8 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager {
public void reportKeyguardSecured(int userHandle) {
Preconditions.checkArgumentNonnegative(userHandle, "Invalid userId");
- final CallerIdentity identity = getCallerIdentity();
- Preconditions.checkCallAuthorization(hasFullCrossUsersPermission(identity, userHandle));
+ final CallerIdentity caller = getCallerIdentity();
+ Preconditions.checkCallAuthorization(hasFullCrossUsersPermission(caller, userHandle));
Preconditions.checkCallAuthorization(hasCallingOrSelfPermission(BIND_DEVICE_ADMIN));
if (mInjector.securityLogIsLoggingEnabled()) {
@@ -6305,8 +6261,8 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager {
}
Preconditions.checkArgumentNonnegative(userHandle, "Invalid userId");
- final CallerIdentity identity = getCallerIdentity();
- Preconditions.checkCallAuthorization(hasFullCrossUsersPermission(identity, userHandle));
+ final CallerIdentity caller = getCallerIdentity();
+ Preconditions.checkCallAuthorization(hasFullCrossUsersPermission(caller, userHandle));
synchronized (getLockObject()) {
DevicePolicyData policy = getUserData(UserHandle.USER_SYSTEM);
@@ -6329,8 +6285,8 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager {
@Override
public void setRecommendedGlobalProxy(ComponentName who, ProxyInfo proxyInfo) {
Objects.requireNonNull(who, "ComponentName is null");
- final CallerIdentity identity = getCallerIdentity(who);
- Preconditions.checkCallAuthorization(isDeviceOwner(identity));
+ final CallerIdentity caller = getCallerIdentity(who);
+ Preconditions.checkCallAuthorization(isDeviceOwner(caller));
mInjector.binderWithCleanCallingIdentity(
() -> mInjector.getConnectivityManager().setGlobalProxy(proxyInfo));
}
@@ -6443,10 +6399,10 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager {
}
Preconditions.checkArgumentNonnegative(userHandle, "Invalid userId");
- final CallerIdentity identity = who != null
+ final CallerIdentity caller = who != null
? getCallerIdentity(who)
: getCallerIdentity();
- Preconditions.checkCallAuthorization(hasFullCrossUsersPermission(identity, userHandle));
+ Preconditions.checkCallAuthorization(hasFullCrossUsersPermission(caller, userHandle));
synchronized (getLockObject()) {
// Check for permissions if a particular caller is specified
@@ -6479,10 +6435,10 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager {
}
Preconditions.checkArgumentNonnegative(userHandle, "Invalid userId");
- final CallerIdentity identity = callerPackage != null
+ final CallerIdentity caller = callerPackage != null
? getCallerIdentity(callerPackage)
: getCallerIdentity();
- Preconditions.checkCallAuthorization(hasFullCrossUsersPermission(identity, userHandle));
+ Preconditions.checkCallAuthorization(hasFullCrossUsersPermission(caller, userHandle));
// It's not critical here, but let's make sure the package name is correct, in case
// we start using it for different purposes.
@@ -6555,23 +6511,27 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager {
return;
}
Objects.requireNonNull(who, "ComponentName is null");
- final int userHandle = UserHandle.getCallingUserId();
+
+ final CallerIdentity caller = getCallerIdentity(who);
+ if (parent) {
+ Preconditions.checkCallAuthorization(isProfileOwnerOfOrganizationOwnedDevice(caller));
+ }
+
synchronized (getLockObject()) {
ActiveAdmin ap = getActiveAdminForCallerLocked(who,
DeviceAdminInfo.USES_POLICY_PROFILE_OWNER, parent);
- if (parent) {
- enforceProfileOwnerOfOrganizationOwnedDevice(ap);
- }
if (ap.disableScreenCapture != disabled) {
ap.disableScreenCapture = disabled;
- saveSettingsLocked(userHandle);
- final int affectedUserId = parent ? getProfileParentId(userHandle) : userHandle;
+ saveSettingsLocked(caller.getUserId());
+ final int affectedUserId = parent
+ ? getProfileParentId(caller.getUserId())
+ : caller.getUserId();
updateScreenCaptureDisabled(affectedUserId, disabled);
}
}
DevicePolicyEventLogger
.createEvent(DevicePolicyEnums.SET_SCREEN_CAPTURE_DISABLED)
- .setAdmin(who)
+ .setAdmin(caller.getComponentName())
.setBoolean(disabled)
.write();
}
@@ -6585,12 +6545,13 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager {
if (!mHasFeature) {
return false;
}
+ if (parent) {
+ Objects.requireNonNull(who, "ComponentName is null");
+ Preconditions.checkCallAuthorization(
+ isProfileOwnerOfOrganizationOwnedDevice(getCallerIdentity(who)));
+ }
+
synchronized (getLockObject()) {
- if (parent) {
- final ActiveAdmin ap = getActiveAdminForCallerLocked(who,
- DeviceAdminInfo.USES_POLICY_ORGANIZATION_OWNED_PROFILE_OWNER, parent);
- enforceProfileOwnerOfOrganizationOwnedDevice(ap);
- }
if (who != null) {
ActiveAdmin admin = getActiveAdminUncheckedLocked(who, userHandle, parent);
return (admin != null) && admin.disableScreenCapture;
@@ -6627,23 +6588,23 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager {
return;
}
Objects.requireNonNull(who, "ComponentName is null");
- final CallerIdentity identity = getCallerIdentity(who);
+ final CallerIdentity caller = getCallerIdentity(who);
boolean requireAutoTimeChanged = false;
synchronized (getLockObject()) {
- Preconditions.checkSecurity(!isManagedProfile(identity.getUserId()),
+ Preconditions.checkCallAuthorization(!isManagedProfile(caller.getUserId()),
"Managed profile cannot set auto time required");
- ActiveAdmin admin = getProfileOwnerOrDeviceOwnerLocked(identity);
+ ActiveAdmin admin = getProfileOwnerOrDeviceOwnerLocked(caller);
if (admin.requireAutoTime != required) {
admin.requireAutoTime = required;
- saveSettingsLocked(identity.getUserId());
+ saveSettingsLocked(caller.getUserId());
requireAutoTimeChanged = true;
}
}
// requireAutoTime is now backed by DISALLOW_CONFIG_DATE_TIME restriction, so propagate
// updated restrictions to the framework.
if (requireAutoTimeChanged) {
- pushUserRestrictions(identity.getUserId());
+ pushUserRestrictions(caller.getUserId());
}
// Turn AUTO_TIME on in settings if it is required
if (required) {
@@ -6694,14 +6655,17 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager {
return;
}
Objects.requireNonNull(who, "ComponentName is null");
- enforceProfileOwnerOnUser0OrProfileOwnerOrganizationOwned();
+
+ final CallerIdentity caller = getCallerIdentity(who);
+ Preconditions.checkCallAuthorization(isProfileOwnerOnUser0(caller)
+ || isProfileOwnerOfOrganizationOwnedDevice(caller) || isDeviceOwner(caller));
mInjector.binderWithCleanCallingIdentity(() ->
mInjector.settingsGlobalPutInt(Settings.Global.AUTO_TIME, enabled ? 1 : 0));
DevicePolicyEventLogger
.createEvent(DevicePolicyEnums.SET_AUTO_TIME)
- .setAdmin(who)
+ .setAdmin(caller.getComponentName())
.setBoolean(enabled)
.write();
}
@@ -6715,7 +6679,10 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager {
return false;
}
Objects.requireNonNull(who, "ComponentName is null");
- enforceProfileOwnerOnUser0OrProfileOwnerOrganizationOwned();
+
+ final CallerIdentity caller = getCallerIdentity(who);
+ Preconditions.checkCallAuthorization(isProfileOwnerOnUser0(caller)
+ || isProfileOwnerOfOrganizationOwnedDevice(caller) || isDeviceOwner(caller));
return mInjector.settingsGlobalGetInt(Global.AUTO_TIME, 0) > 0;
}
@@ -6729,14 +6696,17 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager {
return;
}
Objects.requireNonNull(who, "ComponentName is null");
- enforceProfileOwnerOnUser0OrProfileOwnerOrganizationOwned();
+
+ final CallerIdentity caller = getCallerIdentity(who);
+ Preconditions.checkCallAuthorization(isProfileOwnerOnUser0(caller)
+ || isProfileOwnerOfOrganizationOwnedDevice(caller) || isDeviceOwner(caller));
mInjector.binderWithCleanCallingIdentity(() ->
mInjector.settingsGlobalPutInt(Global.AUTO_TIME_ZONE, enabled ? 1 : 0));
DevicePolicyEventLogger
.createEvent(DevicePolicyEnums.SET_AUTO_TIME_ZONE)
- .setAdmin(who)
+ .setAdmin(caller.getComponentName())
.setBoolean(enabled)
.write();
}
@@ -6750,7 +6720,10 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager {
return false;
}
Objects.requireNonNull(who, "ComponentName is null");
- enforceProfileOwnerOnUser0OrProfileOwnerOrganizationOwned();
+
+ final CallerIdentity caller = getCallerIdentity(who);
+ Preconditions.checkCallAuthorization(isProfileOwnerOnUser0(caller)
+ || isProfileOwnerOfOrganizationOwnedDevice(caller) || isDeviceOwner(caller));
return mInjector.settingsGlobalGetInt(Global.AUTO_TIME_ZONE, 0) > 0;
}
@@ -6761,8 +6734,8 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager {
return;
}
Objects.requireNonNull(who, "ComponentName is null");
- final CallerIdentity identity = getCallerIdentity(who);
- Preconditions.checkCallAuthorization(isDeviceOwner(identity));
+ final CallerIdentity caller = getCallerIdentity(who);
+ Preconditions.checkCallAuthorization(isDeviceOwner(caller));
// Allow setting this policy to true only if there is a split system user.
if (forceEphemeralUsers && !mInjector.userManagerIsSplitSystemUser()) {
@@ -6774,7 +6747,7 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager {
final ActiveAdmin deviceOwner = getDeviceOwnerAdminLocked();
if (deviceOwner.forceEphemeralUsers != forceEphemeralUsers) {
deviceOwner.forceEphemeralUsers = forceEphemeralUsers;
- saveSettingsLocked(identity.getUserId());
+ saveSettingsLocked(caller.getUserId());
mUserManagerInternal.setForceEphemeralUsers(forceEphemeralUsers);
removeAllUsers = forceEphemeralUsers;
}
@@ -6790,8 +6763,8 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager {
return false;
}
Objects.requireNonNull(who, "ComponentName is null");
- final CallerIdentity identity = getCallerIdentity(who);
- Preconditions.checkCallAuthorization(isDeviceOwner(identity));
+ final CallerIdentity caller = getCallerIdentity(who);
+ Preconditions.checkCallAuthorization(isDeviceOwner(caller));
synchronized (getLockObject()) {
final ActiveAdmin deviceOwner = getDeviceOwnerAdminLocked();
@@ -6799,14 +6772,6 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager {
}
}
- private void ensureAllUsersAffiliated() throws SecurityException {
- synchronized (getLockObject()) {
- if (!areAllUsersAffiliatedWithDeviceLocked()) {
- throw new SecurityException("Not all users are affiliated.");
- }
- }
- }
-
@Override
public boolean requestBugreport(ComponentName who) {
if (!mHasFeature) {
@@ -6816,9 +6781,9 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager {
// TODO: If an unaffiliated user is removed, the admin will be able to request a bugreport
// which could still contain data related to that user. Should we disallow that, e.g. until
// next boot? Might not be needed given that this still requires user consent.
- final CallerIdentity identity = getCallerIdentity(who);
- Preconditions.checkCallAuthorization(isDeviceOwner(identity));
- ensureAllUsersAffiliated();
+ final CallerIdentity caller = getCallerIdentity(who);
+ Preconditions.checkCallAuthorization(isDeviceOwner(caller));
+ Preconditions.checkCallAuthorization(areAllUsersAffiliatedWithDeviceLocked());
if (mBugreportCollectionManager.requestBugreport()) {
DevicePolicyEventLogger
@@ -6923,13 +6888,16 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager {
return;
}
Objects.requireNonNull(who, "ComponentName is null");
- int userHandle = mInjector.userHandleGetCallingUserId();
+
+ final CallerIdentity caller = getCallerIdentity(who);
+ if (parent) {
+ Preconditions.checkCallAuthorization(isProfileOwnerOfOrganizationOwnedDevice(caller));
+ }
+
+ final int userHandle = caller.getUserId();
synchronized (getLockObject()) {
ActiveAdmin ap = getActiveAdminForCallerLocked(who,
DeviceAdminInfo.USES_POLICY_DISABLE_CAMERA, parent);
- if (parent) {
- enforceProfileOwnerOfOrganizationOwnedDevice(ap);
- }
if (ap.disableCamera != disabled) {
ap.disableCamera = disabled;
saveSettingsLocked(userHandle);
@@ -6945,7 +6913,7 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager {
}
DevicePolicyEventLogger
.createEvent(DevicePolicyEnums.SET_CAMERA_DISABLED)
- .setAdmin(who)
+ .setAdmin(caller.getComponentName())
.setBoolean(disabled)
.setStrings(parent ? CALLED_FROM_PARENT : NOT_CALLED_FROM_PARENT)
.write();
@@ -6965,15 +6933,16 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager {
if (!mHasFeature) {
return false;
}
+ if (parent) {
+ Objects.requireNonNull(who, "ComponentName is null");
+ Preconditions.checkCallAuthorization(
+ isProfileOwnerOfOrganizationOwnedDevice(getCallerIdentity(who)));
+ }
+
synchronized (getLockObject()) {
- if (parent) {
- final ActiveAdmin ap = getActiveAdminForCallerLocked(who,
- DeviceAdminInfo.USES_POLICY_DISABLE_CAMERA, parent);
- enforceProfileOwnerOfOrganizationOwnedDevice(ap);
- }
if (who != null) {
ActiveAdmin admin = getActiveAdminUncheckedLocked(who, userHandle, parent);
- return (admin != null) ? admin.disableCamera : false;
+ return (admin != null) && admin.disableCamera;
}
// First, see if DO has set it. If so, it's device-wide.
if (mergeDeviceOwnerRestriction) {
@@ -7001,13 +6970,16 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager {
return;
}
Objects.requireNonNull(who, "ComponentName is null");
- final int userHandle = mInjector.userHandleGetCallingUserId();
+
+ final CallerIdentity caller = getCallerIdentity(who);
+
+ final int userHandle = caller.getUserId();
synchronized (getLockObject()) {
ActiveAdmin ap = getActiveAdminForCallerLocked(
who, DeviceAdminInfo.USES_POLICY_DISABLE_KEYGUARD_FEATURES, parent);
if (isManagedProfile(userHandle)) {
if (parent) {
- if (isProfileOwnerOfOrganizationOwnedDevice(ap)) {
+ if (isProfileOwnerOfOrganizationOwnedDevice(caller)) {
which = which & PROFILE_KEYGUARD_FEATURES_AFFECT_OWNER;
} else {
which = which & NON_ORG_OWNED_PROFILE_KEYGUARD_FEATURES_AFFECT_OWNER;
@@ -7028,7 +7000,7 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager {
}
DevicePolicyEventLogger
.createEvent(DevicePolicyEnums.SET_KEYGUARD_DISABLED_FEATURES)
- .setAdmin(who)
+ .setAdmin(caller.getComponentName())
.setInt(which)
.setStrings(parent ? CALLED_FROM_PARENT : NOT_CALLED_FROM_PARENT)
.write();
@@ -7045,8 +7017,8 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager {
}
Preconditions.checkArgumentNonnegative(userHandle, "Invalid userId");
- final CallerIdentity identity = getCallerIdentity();
- Preconditions.checkCallAuthorization(hasFullCrossUsersPermission(identity, userHandle));
+ final CallerIdentity caller = getCallerIdentity();
+ Preconditions.checkCallAuthorization(hasFullCrossUsersPermission(caller, userHandle));
final long ident = mInjector.binderClearCallingIdentity();
try {
@@ -7097,25 +7069,24 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager {
return;
}
Objects.requireNonNull(packageList, "packageList is null");
- final int userHandle = UserHandle.getCallingUserId();
+ final CallerIdentity caller = getCallerIdentity(who, callerPackage);
+ Preconditions.checkCallAuthorization(isDeviceOwner(caller)
+ || isCallerDelegate(caller, DELEGATION_KEEP_UNINSTALLED_PACKAGES));
+
synchronized (getLockObject()) {
- // Ensure the caller is a DO or a keep uninstalled packages delegate.
- enforceCanManageScope(who, callerPackage, DeviceAdminInfo.USES_POLICY_DEVICE_OWNER,
- DELEGATION_KEEP_UNINSTALLED_PACKAGES);
// Get the device owner
ActiveAdmin deviceOwner = getDeviceOwnerAdminLocked();
// Set list of packages to be kept even if uninstalled.
deviceOwner.keepUninstalledPackages = packageList;
// Save settings.
- saveSettingsLocked(userHandle);
+ saveSettingsLocked(caller.getUserId());
// Notify package manager.
mInjector.getPackageManagerInternal().setKeepUninstalledPackages(packageList);
}
- final boolean isDelegate = (who == null);
DevicePolicyEventLogger
.createEvent(DevicePolicyEnums.SET_KEEP_UNINSTALLED_PACKAGES)
- .setAdmin(callerPackage)
- .setBoolean(isDelegate)
+ .setAdmin(caller.getPackageName())
+ .setBoolean(/* isDelegate */ who == null)
.setStrings(packageList.toArray(new String[0]))
.write();
}
@@ -7125,11 +7096,12 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager {
if (!mHasFeature) {
return null;
}
+ final CallerIdentity caller = getCallerIdentity(who, callerPackage);
+ Preconditions.checkCallAuthorization(isDeviceOwner(caller)
+ || isCallerDelegate(caller, DELEGATION_KEEP_UNINSTALLED_PACKAGES));
+
// TODO In split system user mode, allow apps on user 0 to query the list
synchronized (getLockObject()) {
- // Ensure the caller is a DO or a keep uninstalled packages delegate.
- enforceCanManageScope(who, callerPackage, DeviceAdminInfo.USES_POLICY_DEVICE_OWNER,
- DELEGATION_KEEP_UNINSTALLED_PACKAGES);
return getKeepUninstalledPackagesLocked();
}
}
@@ -7228,11 +7200,11 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager {
}
}
- private boolean isDeviceOwner(CallerIdentity identity) {
+ private boolean isDeviceOwner(CallerIdentity caller) {
synchronized (getLockObject()) {
return mOwners.hasDeviceOwner()
- && mOwners.getDeviceOwnerUserId() == identity.getUserId()
- && mOwners.getDeviceOwnerComponent().equals(identity.getComponentName());
+ && mOwners.getDeviceOwnerUserId() == caller.getUserId()
+ && mOwners.getDeviceOwnerComponent().equals(caller.getComponentName());
}
}
@@ -7258,12 +7230,12 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager {
/**
* Returns {@code true} if the provided caller identity is of a profile owner.
- * @param identity identity of caller.
+ * @param caller identity of caller.
* @return true if {@code identity} is a profile owner, false otherwise.
*/
- public boolean isProfileOwner(CallerIdentity identity) {
- final ComponentName profileOwner = getProfileOwner(identity.getUserId());
- return profileOwner != null && profileOwner.equals(identity.getComponentName());
+ public boolean isProfileOwner(CallerIdentity caller) {
+ final ComponentName profileOwner = getProfileOwner(caller.getUserId());
+ return profileOwner != null && profileOwner.equals(caller.getComponentName());
}
private boolean hasProfileOwner(int userId) {
@@ -7272,32 +7244,33 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager {
}
}
+ /**
+ * Returns {@code true} if the provided caller identity is of a profile owner of an organization
+ * owned device.
+ *
+ * @param caller identity of caller
+ * @return true if {@code identity} is a profile owner of an organization owned device, false
+ * otherwise.
+ */
+ private boolean isProfileOwnerOfOrganizationOwnedDevice(CallerIdentity caller) {
+ return isProfileOwner(caller) && isProfileOwnerOfOrganizationOwnedDevice(
+ caller.getUserId());
+ }
+
private boolean isProfileOwnerOfOrganizationOwnedDevice(int userId) {
synchronized (getLockObject()) {
return mOwners.isProfileOwnerOfOrganizationOwnedDevice(userId);
}
}
- /**
- * Returns true if the provided {@code admin} is a profile owner and the profile is marked
- * as organization-owned.
- * The {@code admin} parameter must be obtained by the service by calling
- * {@code getActiveAdminForCallerLocked} or one of the similar variants, not caller-supplied
- * input.
- */
- private boolean isProfileOwnerOfOrganizationOwnedDevice(@Nullable ActiveAdmin admin) {
- if (admin == null) {
- return false;
- }
-
- return isProfileOwnerOfOrganizationOwnedDevice(
- admin.info.getComponent(), admin.getUserHandle().getIdentifier());
- }
-
private boolean isProfileOwnerOfOrganizationOwnedDevice(ComponentName who, int userId) {
return isProfileOwner(who, userId) && isProfileOwnerOfOrganizationOwnedDevice(userId);
}
+ private boolean isProfileOwnerOnUser0(CallerIdentity caller) {
+ return isProfileOwner(caller) && caller.getUserHandle().isSystem();
+ }
+
@Override
public ComponentName getDeviceOwnerComponent(boolean callingUserOnly) {
if (!mHasFeature) {
@@ -7604,26 +7577,21 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager {
@Override
public void setDeviceOwnerLockScreenInfo(ComponentName who, CharSequence info) {
- Objects.requireNonNull(who, "ComponentName is null");
if (!mHasFeature) {
return;
}
+ Objects.requireNonNull(who, "ComponentName is null");
- synchronized (getLockObject()) {
- ActiveAdmin admin = getActiveAdminForCallerLocked(who,
- DeviceAdminInfo.USES_POLICY_PROFILE_OWNER);
- if (!isProfileOwnerOfOrganizationOwnedDevice(admin) && !isDeviceOwner(admin)) {
- throw new SecurityException("Only Device Owner or Profile Owner of"
- + " organization-owned device can set screen lock info.");
- }
- }
+ final CallerIdentity caller = getCallerIdentity(who);
+ Preconditions.checkCallAuthorization(isDeviceOwner(caller)
+ || isProfileOwnerOfOrganizationOwnedDevice(caller));
mInjector.binderWithCleanCallingIdentity(() ->
mLockPatternUtils.setDeviceOwnerInfo(info != null ? info.toString() : null));
DevicePolicyEventLogger
.createEvent(DevicePolicyEnums.SET_DEVICE_OWNER_LOCK_SCREEN_INFO)
- .setAdmin(who)
+ .setAdmin(caller.getComponentName())
.write();
}
@@ -7828,8 +7796,8 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager {
public ComponentName getProfileOwnerAsUser(int userHandle) {
Preconditions.checkArgumentNonnegative(userHandle, "Invalid userId");
- final CallerIdentity identity = getCallerIdentity();
- Preconditions.checkCallAuthorization(hasCrossUsersPermission(identity, userHandle));
+ final CallerIdentity caller = getCallerIdentity();
+ Preconditions.checkCallAuthorization(hasCrossUsersPermission(caller, userHandle));
return getProfileOwner(userHandle);
}
@@ -7899,15 +7867,21 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager {
return null;
}
synchronized (getLockObject()) {
+ final ComponentName doComponent = mOwners.getDeviceOwnerComponent();
+ final ComponentName poComponent =
+ mOwners.getProfileOwnerComponent(userHandle.getIdentifier());
+ // Return test only admin by default.
+ if (isAdminTestOnlyLocked(doComponent, userHandle.getIdentifier())) {
+ return doComponent;
+ } else if (isAdminTestOnlyLocked(poComponent, userHandle.getIdentifier())) {
+ return poComponent;
+ }
final String supervisor = mContext.getResources().getString(
com.android.internal.R.string.config_defaultSupervisionProfileOwnerComponent);
if (supervisor == null) {
return null;
}
final ComponentName supervisorComponent = ComponentName.unflattenFromString(supervisor);
- final ComponentName doComponent = mOwners.getDeviceOwnerComponent();
- final ComponentName poComponent =
- mOwners.getProfileOwnerComponent(userHandle.getIdentifier());
if (supervisorComponent.equals(doComponent) || supervisorComponent.equals(
poComponent)) {
return supervisorComponent;
@@ -8200,21 +8174,21 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager {
== PackageManager.PERMISSION_GRANTED;
}
- private boolean hasPermissionForPreflight(CallerIdentity identity, String permission) {
+ private boolean hasPermissionForPreflight(CallerIdentity caller, String permission) {
final int callingPid = mInjector.binderGetCallingPid();
final String packageName = mContext.getPackageName();
return PermissionChecker.checkPermissionForPreflight(mContext, permission, callingPid,
- identity.getUid(), packageName) == PermissionChecker.PERMISSION_GRANTED;
+ caller.getUid(), packageName) == PermissionChecker.PERMISSION_GRANTED;
}
- private boolean hasFullCrossUsersPermission(CallerIdentity identity, int userHandle) {
- return (userHandle == identity.getUserId()) || isSystemUid(identity) || isRootUid(identity)
+ private boolean hasFullCrossUsersPermission(CallerIdentity caller, int userHandle) {
+ return (userHandle == caller.getUserId()) || isSystemUid(caller) || isRootUid(caller)
|| hasCallingOrSelfPermission(permission.INTERACT_ACROSS_USERS_FULL);
}
- private boolean hasCrossUsersPermission(CallerIdentity identity, int userHandle) {
- return (userHandle == identity.getUserId()) || isSystemUid(identity) || isRootUid(identity)
+ private boolean hasCrossUsersPermission(CallerIdentity caller, int userHandle) {
+ return (userHandle == caller.getUserId()) || isSystemUid(caller) || isRootUid(caller)
|| hasCallingOrSelfPermission(permission.INTERACT_ACROSS_USERS);
}
@@ -8254,39 +8228,18 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager {
"Only profile owner, device owner and system may call this method.");
}
- private void enforceProfileOwnerOnUser0OrProfileOwnerOrganizationOwned() {
- synchronized (getLockObject()) {
- // Check if there is a device owner or profile owner of an organization-owned device
- ActiveAdmin owner = getActiveAdminWithPolicyForUidLocked(null,
- DeviceAdminInfo.USES_POLICY_ORGANIZATION_OWNED_PROFILE_OWNER,
- mInjector.binderGetCallingUid());
- if (owner != null) {
- return;
- }
-
- // Checks whether the caller is a profile owner on user 0 rather than
- // checking whether the active admin is on user 0
- owner = getActiveAdminWithPolicyForUidLocked(null,
- DeviceAdminInfo.USES_POLICY_PROFILE_OWNER, mInjector.binderGetCallingUid());
- if (owner != null && owner.getUserHandle().isSystem()) {
- return;
- }
- }
- throw new SecurityException("No active admin found");
- }
-
- private void enforceProfileOwnerOrFullCrossUsersPermission(CallerIdentity identity,
+ private void enforceProfileOwnerOrFullCrossUsersPermission(CallerIdentity caller,
int userId) {
- if (userId == identity.getUserId()) {
+ if (userId == caller.getUserId()) {
synchronized (getLockObject()) {
if (getActiveAdminWithPolicyForUidLocked(null,
- DeviceAdminInfo.USES_POLICY_PROFILE_OWNER, identity.getUid()) != null) {
+ DeviceAdminInfo.USES_POLICY_PROFILE_OWNER, caller.getUid()) != null) {
// Device Owner/Profile Owner may access the user it runs on.
return;
}
}
}
- Preconditions.checkCallAuthorization(hasFullCrossUsersPermission(identity, userId));
+ Preconditions.checkCallAuthorization(hasFullCrossUsersPermission(caller, userId));
}
private boolean canUserUseLockTaskLocked(int userId) {
@@ -8340,16 +8293,16 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager {
return UserHandle.isSameApp(mInjector.binderGetCallingUid(), Process.SYSTEM_UID);
}
- private boolean isSystemUid(CallerIdentity identity) {
- return UserHandle.isSameApp(identity.getUid(), Process.SYSTEM_UID);
+ private boolean isSystemUid(CallerIdentity caller) {
+ return UserHandle.isSameApp(caller.getUid(), Process.SYSTEM_UID);
}
- private boolean isRootUid(CallerIdentity identity) {
- return UserHandle.isSameApp(identity.getUid(), Process.ROOT_UID);
+ private boolean isRootUid(CallerIdentity caller) {
+ return UserHandle.isSameApp(caller.getUid(), Process.ROOT_UID);
}
- private boolean isShellUid(CallerIdentity identity) {
- return UserHandle.isSameApp(identity.getUid(), Process.SHELL_UID);
+ private boolean isShellUid(CallerIdentity caller) {
+ return UserHandle.isSameApp(caller.getUid(), Process.SHELL_UID);
}
protected int getProfileParentId(int userHandle) {
@@ -8523,16 +8476,13 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager {
@Override
public void setDefaultSmsApplication(ComponentName admin, String packageName, boolean parent) {
Objects.requireNonNull(admin, "ComponentName is null");
- final CallerIdentity identity = getCallerIdentity(admin);
+ final CallerIdentity caller = getCallerIdentity(admin);
+ Preconditions.checkCallAuthorization(isDeviceOwner(caller)
+ || (parent && isProfileOwnerOfOrganizationOwnedDevice(caller)));
if (parent) {
- ActiveAdmin ap = getActiveAdminForCallerLocked(admin,
- DeviceAdminInfo.USES_POLICY_ORGANIZATION_OWNED_PROFILE_OWNER, parent);
- enforceProfileOwnerOfOrganizationOwnedDevice(ap);
mInjector.binderWithCleanCallingIdentity(() -> enforcePackageIsSystemPackage(
packageName, getProfileParentId(mInjector.userHandleGetCallingUserId())));
- } else {
- Preconditions.checkCallAuthorization(isDeviceOwner(identity));
}
mInjector.binderWithCleanCallingIdentity(() ->
@@ -8566,17 +8516,17 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager {
@Override
public void setApplicationRestrictions(ComponentName who, String callerPackage,
String packageName, Bundle settings) {
- enforceCanManageScope(who, callerPackage, DeviceAdminInfo.USES_POLICY_PROFILE_OWNER,
- DELEGATION_APP_RESTRICTIONS);
+ final CallerIdentity caller = getCallerIdentity(who, callerPackage);
+ Preconditions.checkCallAuthorization(isDeviceOwner(caller) || isProfileOwner(caller)
+ || isCallerDelegate(caller, DELEGATION_APP_RESTRICTIONS));
- final UserHandle userHandle = mInjector.binderGetCallingUserHandle();
mInjector.binderWithCleanCallingIdentity(() -> {
- mUserManager.setApplicationRestrictions(packageName, settings, userHandle);
- final boolean isDelegate = (who == null);
+ mUserManager.setApplicationRestrictions(packageName, settings,
+ caller.getUserHandle());
DevicePolicyEventLogger
.createEvent(DevicePolicyEnums.SET_APPLICATION_RESTRICTIONS)
- .setAdmin(callerPackage)
- .setBoolean(isDelegate)
+ .setAdmin(caller.getPackageName())
+ .setBoolean(/* isDelegate */ who == null)
.setStrings(packageName)
.write();
});
@@ -8608,10 +8558,10 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager {
Objects.requireNonNull(agent, "agent null");
Preconditions.checkArgumentNonnegative(userHandle, "Invalid userId");
- final CallerIdentity identity = admin != null
+ final CallerIdentity caller = admin != null
? getCallerIdentity(admin)
: getCallerIdentity();
- Preconditions.checkCallAuthorization(hasFullCrossUsersPermission(identity, userHandle));
+ Preconditions.checkCallAuthorization(hasFullCrossUsersPermission(caller, userHandle));
synchronized (getLockObject()) {
final String componentName = agent.flattenToString();
@@ -8811,10 +8761,10 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager {
return false;
}
Objects.requireNonNull(who, "ComponentName is null");
- final CallerIdentity identity = getCallerIdentity(who);
+ final CallerIdentity caller = getCallerIdentity(who);
if (packageList != null) {
- int userId = identity.getUserId();
+ int userId = caller.getUserId();
List<AccessibilityServiceInfo> enabledServices = null;
long id = mInjector.binderClearCallingIdentity();
try {
@@ -8844,7 +8794,7 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager {
}
synchronized (getLockObject()) {
- ActiveAdmin admin = getProfileOwnerOrDeviceOwnerLocked(identity);
+ ActiveAdmin admin = getProfileOwnerOrDeviceOwnerLocked(caller);
admin.permittedAccessiblityServices = packageList;
saveSettingsLocked(UserHandle.getCallingUserId());
}
@@ -8864,11 +8814,11 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager {
return null;
}
Objects.requireNonNull(who, "ComponentName is null");
- final CallerIdentity identity = getCallerIdentity(who);
- Preconditions.checkCallAuthorization(isDeviceOwner(identity) || isProfileOwner(identity));
+ final CallerIdentity caller = getCallerIdentity(who);
+ Preconditions.checkCallAuthorization(isDeviceOwner(caller) || isProfileOwner(caller));
synchronized (getLockObject()) {
- ActiveAdmin admin = getProfileOwnerOrDeviceOwnerLocked(identity);
+ ActiveAdmin admin = getProfileOwnerOrDeviceOwnerLocked(caller);
return admin.permittedAccessiblityServices;
}
}
@@ -8963,19 +8913,19 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager {
return false;
}
Objects.requireNonNull(who, "ComponentName is null");
- final CallerIdentity identity = getCallerIdentity(who);
- Preconditions.checkCallAuthorization(isDeviceOwner(identity) || isProfileOwner(identity));
+ final CallerIdentity caller = getCallerIdentity(who);
+ Preconditions.checkCallAuthorization(isDeviceOwner(caller) || isProfileOwner(caller));
if (packageList != null) {
List<InputMethodInfo> enabledImes = InputMethodManagerInternal.get()
- .getEnabledInputMethodListAsUser(identity.getUserId());
+ .getEnabledInputMethodListAsUser(caller.getUserId());
if (enabledImes != null) {
List<String> enabledPackages = new ArrayList<String>();
for (InputMethodInfo ime : enabledImes) {
enabledPackages.add(ime.getPackageName());
}
if (!checkPackagesInPermittedListOrSystem(enabledPackages, packageList,
- identity.getUserId())) {
+ caller.getUserId())) {
Slog.e(LOG_TAG, "Cannot set permitted input methods, "
+ "because it contains already enabled input method.");
return false;
@@ -8984,9 +8934,9 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager {
}
synchronized (getLockObject()) {
- ActiveAdmin admin = getProfileOwnerOrDeviceOwnerLocked(identity);
+ ActiveAdmin admin = getProfileOwnerOrDeviceOwnerLocked(caller);
admin.permittedInputMethods = packageList;
- saveSettingsLocked(identity.getUserId());
+ saveSettingsLocked(caller.getUserId());
}
final String[] packageArray =
packageList != null ? ((List<String>) packageList).toArray(new String[0]) : null;
@@ -9004,11 +8954,11 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager {
return null;
}
Objects.requireNonNull(who, "ComponentName is null");
- final CallerIdentity identity = getCallerIdentity(who);
- Preconditions.checkCallAuthorization(isDeviceOwner(identity) || isProfileOwner(identity));
+ final CallerIdentity caller = getCallerIdentity(who);
+ Preconditions.checkCallAuthorization(isDeviceOwner(caller) || isProfileOwner(caller));
synchronized (getLockObject()) {
- ActiveAdmin admin = getProfileOwnerOrDeviceOwnerLocked(identity);
+ ActiveAdmin admin = getProfileOwnerOrDeviceOwnerLocked(caller);
return admin.permittedInputMethods;
}
}
@@ -9082,16 +9032,16 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager {
return false;
}
Objects.requireNonNull(who, "ComponentName is null");
- final CallerIdentity identity = getCallerIdentity(who);
+ final CallerIdentity caller = getCallerIdentity(who);
- if (!isManagedProfile(identity.getUserId())) {
+ if (!isManagedProfile(caller.getUserId())) {
return false;
}
synchronized (getLockObject()) {
- ActiveAdmin admin = getProfileOwnerOrDeviceOwnerLocked(identity);
+ ActiveAdmin admin = getProfileOwnerOrDeviceOwnerLocked(caller);
admin.permittedNotificationListeners = packageList;
- saveSettingsLocked(identity.getUserId());
+ saveSettingsLocked(caller.getUserId());
}
return true;
}
@@ -9102,12 +9052,12 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager {
return null;
}
Objects.requireNonNull(who, "ComponentName is null");
- final CallerIdentity identity = getCallerIdentity(who);
+ final CallerIdentity caller = getCallerIdentity(who);
synchronized (getLockObject()) {
// API contract is to return null if there are no permitted cross-profile notification
// listeners, including in Device Owner mode.
- ActiveAdmin admin = getProfileOwnerOrDeviceOwnerLocked(identity);
+ ActiveAdmin admin = getProfileOwnerOrDeviceOwnerLocked(caller);
return admin.permittedNotificationListeners;
}
}
@@ -9303,14 +9253,14 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager {
public boolean removeUser(ComponentName who, UserHandle userHandle) {
Objects.requireNonNull(who, "ComponentName is null");
Objects.requireNonNull(userHandle, "UserHandle is null");
- final CallerIdentity identity = getCallerIdentity(who);
- Preconditions.checkCallAuthorization(isDeviceOwner(identity));
+ final CallerIdentity caller = getCallerIdentity(who);
+ Preconditions.checkCallAuthorization(isDeviceOwner(caller));
return mInjector.binderWithCleanCallingIdentity(() -> {
String restriction = isManagedProfile(userHandle.getIdentifier())
? UserManager.DISALLOW_REMOVE_MANAGED_PROFILE
: UserManager.DISALLOW_REMOVE_USER;
- if (isAdminAffectedByRestriction(who, restriction, identity.getUserId())) {
+ if (isAdminAffectedByRestriction(who, restriction, caller.getUserId())) {
Log.w(LOG_TAG, "The device owner cannot remove a user because "
+ restriction + " is enabled, and was not set by the device owner");
return false;
@@ -9336,8 +9286,8 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager {
@Override
public boolean switchUser(ComponentName who, UserHandle userHandle) {
Objects.requireNonNull(who, "ComponentName is null");
- final CallerIdentity identity = getCallerIdentity(who);
- Preconditions.checkCallAuthorization(isDeviceOwner(identity));
+ final CallerIdentity caller = getCallerIdentity(who);
+ Preconditions.checkCallAuthorization(isDeviceOwner(caller));
synchronized (getLockObject()) {
long id = mInjector.binderClearCallingIdentity();
@@ -9360,8 +9310,8 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager {
public int startUserInBackground(ComponentName who, UserHandle userHandle) {
Objects.requireNonNull(who, "ComponentName is null");
Objects.requireNonNull(userHandle, "UserHandle is null");
- final CallerIdentity identity = getCallerIdentity(who);
- Preconditions.checkCallAuthorization(isDeviceOwner(identity));
+ final CallerIdentity caller = getCallerIdentity(who);
+ Preconditions.checkCallAuthorization(isDeviceOwner(caller));
final int userId = userHandle.getIdentifier();
if (isManagedProfile(userId)) {
@@ -9393,8 +9343,8 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager {
public int stopUser(ComponentName who, UserHandle userHandle) {
Objects.requireNonNull(who, "ComponentName is null");
Objects.requireNonNull(userHandle, "UserHandle is null");
- final CallerIdentity identity = getCallerIdentity(who);
- Preconditions.checkCallAuthorization(isDeviceOwner(identity));
+ final CallerIdentity caller = getCallerIdentity(who);
+ Preconditions.checkCallAuthorization(isDeviceOwner(caller));
final int userId = userHandle.getIdentifier();
if (isManagedProfile(userId)) {
@@ -9462,8 +9412,8 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager {
@Override
public List<UserHandle> getSecondaryUsers(ComponentName who) {
Objects.requireNonNull(who, "ComponentName is null");
- final CallerIdentity identity = getCallerIdentity(who);
- Preconditions.checkCallAuthorization(isDeviceOwner(identity));
+ final CallerIdentity caller = getCallerIdentity(who);
+ Preconditions.checkCallAuthorization(isDeviceOwner(caller));
return mInjector.binderWithCleanCallingIdentity(() -> {
final List<UserInfo> userInfos = mInjector.getUserManager().getAliveUsers();
@@ -9491,12 +9441,13 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager {
@Override
public Bundle getApplicationRestrictions(ComponentName who, String callerPackage,
String packageName) {
- enforceCanManageScope(who, callerPackage, DeviceAdminInfo.USES_POLICY_PROFILE_OWNER,
- DELEGATION_APP_RESTRICTIONS);
+ final CallerIdentity caller = getCallerIdentity(who, callerPackage);
+ Preconditions.checkCallAuthorization(isDeviceOwner(caller) || isProfileOwner(caller)
+ || isCallerDelegate(caller, DELEGATION_APP_RESTRICTIONS));
- final UserHandle userHandle = mInjector.binderGetCallingUserHandle();
return mInjector.binderWithCleanCallingIdentity(() -> {
- Bundle bundle = mUserManager.getApplicationRestrictions(packageName, userHandle);
+ Bundle bundle = mUserManager.getApplicationRestrictions(packageName,
+ caller.getUserHandle());
// if no restrictions were saved, mUserManager.getApplicationRestrictions
// returns null, but DPM method should return an empty Bundle as per JavaDoc
return bundle != null ? bundle : Bundle.EMPTY;
@@ -9506,18 +9457,16 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager {
@Override
public String[] setPackagesSuspended(ComponentName who, String callerPackage,
String[] packageNames, boolean suspended) {
- int callingUserId = UserHandle.getCallingUserId();
+ final CallerIdentity caller = getCallerIdentity(who, callerPackage);
+ Preconditions.checkCallAuthorization(isDeviceOwner(caller) || isProfileOwner(caller)
+ || isCallerDelegate(caller, DELEGATION_PACKAGE_ACCESS));
+
String[] result = null;
synchronized (getLockObject()) {
- // Ensure the caller is a DO/PO or a package access delegate.
- enforceCanManageScope(who, callerPackage, DeviceAdminInfo.USES_POLICY_PROFILE_OWNER,
- DELEGATION_PACKAGE_ACCESS);
-
long id = mInjector.binderClearCallingIdentity();
try {
- result = mIPackageManager
- .setPackagesSuspendedAsUser(packageNames, suspended,
- null, null, null, PLATFORM_PACKAGE_NAME, callingUserId);
+ result = mIPackageManager.setPackagesSuspendedAsUser(packageNames, suspended, null,
+ null, null, PLATFORM_PACKAGE_NAME, caller.getUserId());
} catch (RemoteException re) {
// Shouldn't happen.
Slog.e(LOG_TAG, "Failed talking to the package manager", re);
@@ -9525,11 +9474,10 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager {
mInjector.binderRestoreCallingIdentity(id);
}
}
- final boolean isDelegate = (who == null);
DevicePolicyEventLogger
.createEvent(DevicePolicyEnums.SET_PACKAGES_SUSPENDED)
- .setAdmin(callerPackage)
- .setBoolean(isDelegate)
+ .setAdmin(caller.getPackageName())
+ .setBoolean(/* isDelegate */ who == null)
.setStrings(packageNames)
.write();
if (result != null) {
@@ -9540,15 +9488,14 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager {
@Override
public boolean isPackageSuspended(ComponentName who, String callerPackage, String packageName) {
- int callingUserId = UserHandle.getCallingUserId();
- synchronized (getLockObject()) {
- // Ensure the caller is a DO/PO or a package access delegate.
- enforceCanManageScope(who, callerPackage, DeviceAdminInfo.USES_POLICY_PROFILE_OWNER,
- DELEGATION_PACKAGE_ACCESS);
+ final CallerIdentity caller = getCallerIdentity(who, callerPackage);
+ Preconditions.checkCallAuthorization(isDeviceOwner(caller) || isProfileOwner(caller)
+ || isCallerDelegate(caller, DELEGATION_PACKAGE_ACCESS));
+ synchronized (getLockObject()) {
long id = mInjector.binderClearCallingIdentity();
try {
- return mIPackageManager.isPackageSuspendedForUser(packageName, callingUserId);
+ return mIPackageManager.isPackageSuspendedForUser(packageName, caller.getUserId());
} catch (RemoteException re) {
// Shouldn't happen.
Slog.e(LOG_TAG, "Failed talking to the package manager", re);
@@ -9563,32 +9510,32 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager {
public void setUserRestriction(ComponentName who, String key, boolean enabledFromThisOwner,
boolean parent) {
Objects.requireNonNull(who, "ComponentName is null");
+
+ final CallerIdentity caller = getCallerIdentity(who);
+
if (!UserRestrictionsUtils.isValidRestriction(key)) {
return;
}
- int userHandle = mInjector.userHandleGetCallingUserId();
+ int userHandle = caller.getUserId();
synchronized (getLockObject()) {
final ActiveAdmin activeAdmin =
getActiveAdminForCallerLocked(who,
DeviceAdminInfo.USES_POLICY_PROFILE_OWNER, parent);
- final boolean isDeviceOwner = isDeviceOwner(who, userHandle);
- if (isDeviceOwner) {
+ if (isDeviceOwner(caller)) {
if (!UserRestrictionsUtils.canDeviceOwnerChange(key)) {
throw new SecurityException("Device owner cannot set user restriction " + key);
}
- if (parent) {
- throw new IllegalArgumentException(
- "Cannot use the parent instance in Device Owner mode");
- }
+ Preconditions.checkArgument(!parent,
+ "Cannot use the parent instance in Device Owner mode");
} else {
boolean profileOwnerCanChangeOnItself = !parent
&& UserRestrictionsUtils.canProfileOwnerChange(key, userHandle);
boolean orgOwnedProfileOwnerCanChangesGlobally = parent
- && isProfileOwnerOfOrganizationOwnedDevice(activeAdmin)
- && UserRestrictionsUtils
- .canProfileOwnerOfOrganizationOwnedDeviceChange(key);
+ && isProfileOwnerOfOrganizationOwnedDevice(caller)
+ && UserRestrictionsUtils.canProfileOwnerOfOrganizationOwnedDeviceChange(
+ key);
if (!profileOwnerCanChangeOnItself && !orgOwnedProfileOwnerCanChangesGlobally) {
throw new SecurityException("Profile owner cannot set user restriction " + key);
@@ -9609,7 +9556,7 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager {
: DevicePolicyEnums.REMOVE_USER_RESTRICTION;
DevicePolicyEventLogger
.createEvent(eventId)
- .setAdmin(who)
+ .setAdmin(caller.getComponentName())
.setStrings(key, parent ? CALLED_FROM_PARENT : NOT_CALLED_FROM_PARENT)
.write();
if (SecurityLog.isLoggingEnabled()) {
@@ -9687,14 +9634,14 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager {
return null;
}
Objects.requireNonNull(who, "ComponentName is null");
+
final CallerIdentity caller = getCallerIdentity(who);
+ Preconditions.checkCallAuthorization(isDeviceOwner(caller) || isProfileOwner(caller)
+ || (parent && isProfileOwnerOfOrganizationOwnedDevice(caller)));
synchronized (getLockObject()) {
final ActiveAdmin activeAdmin = getParentOfAdminIfRequired(
getProfileOwnerOrDeviceOwnerLocked(caller), parent);
- if (parent) {
- enforceProfileOwnerOfOrganizationOwnedDevice(activeAdmin);
- }
return activeAdmin.userRestrictions;
}
}
@@ -9702,15 +9649,13 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager {
@Override
public boolean setApplicationHidden(ComponentName who, String callerPackage, String packageName,
boolean hidden, boolean parent) {
- final int userId = parent ? getProfileParentId(UserHandle.getCallingUserId())
- : UserHandle.getCallingUserId();
- boolean result;
+ final CallerIdentity caller = getCallerIdentity(who, callerPackage);
+ Preconditions.checkCallAuthorization(isDeviceOwner(caller) || isProfileOwner(caller)
+ || isCallerDelegate(caller, DELEGATION_PACKAGE_ACCESS));
+ final int userId = parent ? getProfileParentId(caller.getUserId()) : caller.getUserId();
+ boolean result;
synchronized (getLockObject()) {
- // Ensure the caller is a DO/PO or a package access delegate.
- enforceCanManageScope(who, callerPackage, DeviceAdminInfo.USES_POLICY_PROFILE_OWNER,
- DELEGATION_PACKAGE_ACCESS);
-
if (parent) {
getActiveAdminForCallerLocked(who,
DeviceAdminInfo.USES_POLICY_ORGANIZATION_OWNED_PROFILE_OWNER, parent);
@@ -9720,15 +9665,13 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager {
mInjector.binderWithCleanCallingIdentity(() ->
enforcePackageIsSystemPackage(packageName, userId));
}
-
result = mInjector.binderWithCleanCallingIdentity(() -> mIPackageManager
.setApplicationHiddenSettingAsUser(packageName, hidden, userId));
}
- final boolean isDelegate = (who == null);
DevicePolicyEventLogger
.createEvent(DevicePolicyEnums.SET_APPLICATION_HIDDEN)
- .setAdmin(callerPackage)
- .setBoolean(isDelegate)
+ .setAdmin(caller.getPackageName())
+ .setBoolean(/* isDelegate */ who == null)
.setStrings(packageName, hidden ? "hidden" : "not_hidden",
parent ? CALLED_FROM_PARENT : NOT_CALLED_FROM_PARENT)
.write();
@@ -9738,14 +9681,12 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager {
@Override
public boolean isApplicationHidden(ComponentName who, String callerPackage,
String packageName, boolean parent) {
- final int userId = parent ? getProfileParentId(UserHandle.getCallingUserId())
- : UserHandle.getCallingUserId();
+ final CallerIdentity caller = getCallerIdentity(who, callerPackage);
+ Preconditions.checkCallAuthorization(isDeviceOwner(caller) || isProfileOwner(caller)
+ || isCallerDelegate(caller, DELEGATION_PACKAGE_ACCESS));
+ final int userId = parent ? getProfileParentId(caller.getUserId()) : caller.getUserId();
synchronized (getLockObject()) {
- // Ensure the caller is a DO/PO or a package access delegate.
- enforceCanManageScope(who, callerPackage, DeviceAdminInfo.USES_POLICY_PROFILE_OWNER,
- DELEGATION_PACKAGE_ACCESS);
-
if (parent) {
getActiveAdminForCallerLocked(who,
DeviceAdminInfo.USES_POLICY_ORGANIZATION_OWNED_PROFILE_OWNER, parent);
@@ -9774,26 +9715,21 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager {
@Override
public void enableSystemApp(ComponentName who, String callerPackage, String packageName) {
- synchronized (getLockObject()) {
- // Ensure the caller is a DO/PO or an enable system app delegate.
- enforceCanManageScope(who, callerPackage, DeviceAdminInfo.USES_POLICY_PROFILE_OWNER,
- DELEGATION_ENABLE_SYSTEM_APP);
+ final CallerIdentity caller = getCallerIdentity(who, callerPackage);
+ Preconditions.checkCallAuthorization(isDeviceOwner(caller) || isProfileOwner(caller)
+ || isCallerDelegate(caller, DELEGATION_ENABLE_SYSTEM_APP));
+ synchronized (getLockObject()) {
final boolean isDemo = isCurrentUserDemo();
-
- int userId = UserHandle.getCallingUserId();
+ int userId = caller.getUserId();
long id = mInjector.binderClearCallingIdentity();
-
try {
if (VERBOSE_LOG) {
- Slog.v(LOG_TAG, "installing " + packageName + " for "
- + userId);
+ Slog.v(LOG_TAG, "installing " + packageName + " for " + userId);
}
- int parentUserId = getProfileParentId(userId);
- if (!isDemo && !isSystemApp(mIPackageManager, packageName, parentUserId)) {
- throw new IllegalArgumentException("Only system apps can be enabled this way.");
- }
+ Preconditions.checkArgument(isDemo || isSystemApp(mIPackageManager, packageName,
+ getProfileParentId(userId)), "Only system apps can be enabled this way");
// Install the app.
mIPackageManager.installExistingPackageAsUser(packageName, userId,
@@ -9812,28 +9748,25 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager {
mInjector.binderRestoreCallingIdentity(id);
}
}
- final boolean isDelegate = (who == null);
DevicePolicyEventLogger
.createEvent(DevicePolicyEnums.ENABLE_SYSTEM_APP)
- .setAdmin(callerPackage)
- .setBoolean(isDelegate)
+ .setAdmin(caller.getPackageName())
+ .setBoolean(/* isDelegate */ who == null)
.setStrings(packageName)
.write();
}
@Override
public int enableSystemAppWithIntent(ComponentName who, String callerPackage, Intent intent) {
+ final CallerIdentity caller = getCallerIdentity(who, callerPackage);
+ Preconditions.checkCallAuthorization(isDeviceOwner(caller) || isProfileOwner(caller)
+ || isCallerDelegate(caller, DELEGATION_ENABLE_SYSTEM_APP));
+
int numberOfAppsInstalled = 0;
synchronized (getLockObject()) {
- // Ensure the caller is a DO/PO or an enable system app delegate.
- enforceCanManageScope(who, callerPackage, DeviceAdminInfo.USES_POLICY_PROFILE_OWNER,
- DELEGATION_ENABLE_SYSTEM_APP);
-
- int userId = UserHandle.getCallingUserId();
long id = mInjector.binderClearCallingIdentity();
-
try {
- int parentUserId = getProfileParentId(userId);
+ final int parentUserId = getProfileParentId(caller.getUserId());
List<ResolveInfo> activitiesToEnable = mIPackageManager
.queryIntentActivities(intent,
intent.resolveTypeIfNeeded(mContext.getContentResolver()),
@@ -9851,7 +9784,8 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager {
String packageName = info.activityInfo.packageName;
if (isSystemApp(mIPackageManager, packageName, parentUserId)) {
numberOfAppsInstalled++;
- mIPackageManager.installExistingPackageAsUser(packageName, userId,
+ mIPackageManager.installExistingPackageAsUser(packageName,
+ caller.getUserId(),
PackageManager.INSTALL_ALL_WHITELIST_RESTRICTED_PERMISSIONS,
PackageManager.INSTALL_REASON_POLICY, null);
} else {
@@ -9869,11 +9803,10 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager {
mInjector.binderRestoreCallingIdentity(id);
}
}
- final boolean isDelegate = (who == null);
DevicePolicyEventLogger
.createEvent(DevicePolicyEnums.ENABLE_SYSTEM_APP_WITH_INTENT)
- .setAdmin(callerPackage)
- .setBoolean(isDelegate)
+ .setAdmin(caller.getPackageName())
+ .setBoolean(/* isDelegate */ who == null)
.setStrings(intent.getAction())
.write();
return numberOfAppsInstalled;
@@ -9893,26 +9826,25 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager {
@Override
public boolean installExistingPackage(ComponentName who, String callerPackage,
String packageName) {
+ final CallerIdentity caller = getCallerIdentity(who, callerPackage);
+ Preconditions.checkCallAuthorization(isDeviceOwner(caller) || isProfileOwner(caller)
+ || isCallerDelegate(caller, DELEGATION_INSTALL_EXISTING_PACKAGE));
+
boolean result;
synchronized (getLockObject()) {
- // Ensure the caller is a PO or an install existing package delegate
- enforceCanManageScope(who, callerPackage, DeviceAdminInfo.USES_POLICY_PROFILE_OWNER,
- DELEGATION_INSTALL_EXISTING_PACKAGE);
- final int callingUserId = mInjector.userHandleGetCallingUserId();
- if (!isUserAffiliatedWithDeviceLocked(callingUserId)) {
- throw new SecurityException("Admin " + who +
- " is neither the device owner or affiliated user's profile owner.");
- }
-
+ Preconditions.checkCallAuthorization(
+ isUserAffiliatedWithDeviceLocked(caller.getUserId()), String.format(
+ "Admin %s is neither the device owner or "
+ + "affiliated user's profile owner.", who));
final long id = mInjector.binderClearCallingIdentity();
try {
if (VERBOSE_LOG) {
- Slog.v(LOG_TAG, "installing " + packageName + " for "
- + callingUserId);
+ Slog.v(LOG_TAG, "installing " + packageName + " for " + caller.getUserId());
}
// Install the package.
- result = mIPackageManager.installExistingPackageAsUser(packageName, callingUserId,
+ result = mIPackageManager.installExistingPackageAsUser(packageName,
+ caller.getUserId(),
PackageManager.INSTALL_ALL_WHITELIST_RESTRICTED_PERMISSIONS,
PackageManager.INSTALL_REASON_POLICY, null)
== PackageManager.INSTALL_SUCCEEDED;
@@ -9924,11 +9856,10 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager {
}
}
if (result) {
- final boolean isDelegate = (who == null);
DevicePolicyEventLogger
.createEvent(DevicePolicyEnums.INSTALL_EXISTING_PACKAGE)
- .setAdmin(callerPackage)
- .setBoolean(isDelegate)
+ .setAdmin(caller.getPackageName())
+ .setBoolean(/* isDelegate */ who == null)
.setStrings(packageName)
.write();
}
@@ -9979,8 +9910,8 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager {
}
Preconditions.checkArgumentNonnegative(userId, "Invalid userId");
- final CallerIdentity identity = getCallerIdentity();
- Preconditions.checkCallAuthorization(hasFullCrossUsersPermission(identity, userId));
+ final CallerIdentity caller = getCallerIdentity();
+ Preconditions.checkCallAuthorization(hasFullCrossUsersPermission(caller, userId));
synchronized (getLockObject()) {
final ArraySet<String> resultSet = new ArraySet<>();
@@ -10009,12 +9940,12 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager {
@Override
public void setUninstallBlocked(ComponentName who, String callerPackage, String packageName,
boolean uninstallBlocked) {
- final int userId = UserHandle.getCallingUserId();
- synchronized (getLockObject()) {
- // Ensure the caller is a DO/PO or a block uninstall delegate
- enforceCanManageScope(who, callerPackage, DeviceAdminInfo.USES_POLICY_PROFILE_OWNER,
- DELEGATION_BLOCK_UNINSTALL);
+ final CallerIdentity caller = getCallerIdentity(who, callerPackage);
+ Preconditions.checkCallAuthorization(isDeviceOwner(caller) || isProfileOwner(caller)
+ || isCallerDelegate(caller, DELEGATION_BLOCK_UNINSTALL));
+ final int userId = caller.getUserId();
+ synchronized (getLockObject()) {
long id = mInjector.binderClearCallingIdentity();
try {
mIPackageManager.setBlockUninstallForUser(packageName, uninstallBlocked, userId);
@@ -10031,11 +9962,10 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager {
pmi.removeDistractingPackageRestrictions(packageName, userId);
pmi.flushPackageRestrictions(userId);
}
- final boolean isDelegate = (who == null);
DevicePolicyEventLogger
.createEvent(DevicePolicyEnums.SET_UNINSTALL_BLOCKED)
- .setAdmin(callerPackage)
- .setBoolean(isDelegate)
+ .setAdmin(caller.getPackageName())
+ .setBoolean(/* isDelegate */ who == null)
.setStrings(packageName)
.write();
}
@@ -10073,14 +10003,14 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager {
return;
}
Objects.requireNonNull(who, "ComponentName is null");
- final CallerIdentity identity = getCallerIdentity(who);
- Preconditions.checkCallAuthorization(isProfileOwner(identity) || isDeviceOwner(identity));
+ final CallerIdentity caller = getCallerIdentity(who);
+ Preconditions.checkCallAuthorization(isProfileOwner(caller) || isDeviceOwner(caller));
synchronized (getLockObject()) {
- ActiveAdmin admin = getProfileOwnerOrDeviceOwnerLocked(identity);
+ ActiveAdmin admin = getProfileOwnerOrDeviceOwnerLocked(caller);
if (admin.disableCallerId != disabled) {
admin.disableCallerId = disabled;
- saveSettingsLocked(identity.getUserId());
+ saveSettingsLocked(caller.getUserId());
}
}
DevicePolicyEventLogger
@@ -10096,11 +10026,11 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager {
return false;
}
Objects.requireNonNull(who, "ComponentName is null");
- final CallerIdentity identity = getCallerIdentity(who);
- Preconditions.checkCallAuthorization(isProfileOwner(identity) || isDeviceOwner(identity));
+ final CallerIdentity caller = getCallerIdentity(who);
+ Preconditions.checkCallAuthorization(isProfileOwner(caller) || isDeviceOwner(caller));
synchronized (getLockObject()) {
- ActiveAdmin admin = getProfileOwnerOrDeviceOwnerLocked(identity);
+ ActiveAdmin admin = getProfileOwnerOrDeviceOwnerLocked(caller);
return admin.disableCallerId;
}
}
@@ -10109,8 +10039,8 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager {
public boolean getCrossProfileCallerIdDisabledForUser(int userId) {
Preconditions.checkArgumentNonnegative(userId, "Invalid userId");
- final CallerIdentity identity = getCallerIdentity();
- Preconditions.checkCallAuthorization(hasCrossUsersPermission(identity, userId));
+ final CallerIdentity caller = getCallerIdentity();
+ Preconditions.checkCallAuthorization(hasCrossUsersPermission(caller, userId));
synchronized (getLockObject()) {
ActiveAdmin admin = getProfileOwnerAdminLocked(userId);
@@ -10124,14 +10054,14 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager {
return;
}
Objects.requireNonNull(who, "ComponentName is null");
- final CallerIdentity identity = getCallerIdentity(who);
- Preconditions.checkCallAuthorization(isProfileOwner(identity) || isDeviceOwner(identity));
+ final CallerIdentity caller = getCallerIdentity(who);
+ Preconditions.checkCallAuthorization(isProfileOwner(caller) || isDeviceOwner(caller));
synchronized (getLockObject()) {
- ActiveAdmin admin = getProfileOwnerOrDeviceOwnerLocked(identity);
+ ActiveAdmin admin = getProfileOwnerOrDeviceOwnerLocked(caller);
if (admin.disableContactsSearch != disabled) {
admin.disableContactsSearch = disabled;
- saveSettingsLocked(identity.getUserId());
+ saveSettingsLocked(caller.getUserId());
}
}
DevicePolicyEventLogger
@@ -10147,11 +10077,11 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager {
return false;
}
Objects.requireNonNull(who, "ComponentName is null");
- final CallerIdentity identity = getCallerIdentity(who);
- Preconditions.checkCallAuthorization(isProfileOwner(identity) || isDeviceOwner(identity));
+ final CallerIdentity caller = getCallerIdentity(who);
+ Preconditions.checkCallAuthorization(isProfileOwner(caller) || isDeviceOwner(caller));
synchronized (getLockObject()) {
- ActiveAdmin admin = getProfileOwnerOrDeviceOwnerLocked(identity);
+ ActiveAdmin admin = getProfileOwnerOrDeviceOwnerLocked(caller);
return admin.disableContactsSearch;
}
}
@@ -10160,8 +10090,8 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager {
public boolean getCrossProfileContactsSearchDisabledForUser(int userId) {
Preconditions.checkArgumentNonnegative(userId, "Invalid userId");
- final CallerIdentity identity = getCallerIdentity();
- Preconditions.checkCallAuthorization(hasCrossUsersPermission(identity, userId));
+ final CallerIdentity caller = getCallerIdentity();
+ Preconditions.checkCallAuthorization(hasCrossUsersPermission(caller, userId));
synchronized (getLockObject()) {
ActiveAdmin admin = getProfileOwnerAdminLocked(userId);
@@ -10233,14 +10163,14 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager {
return;
}
Objects.requireNonNull(who, "ComponentName is null");
- final CallerIdentity identity = getCallerIdentity(who);
- Preconditions.checkCallAuthorization(isDeviceOwner(identity) || isProfileOwner(identity));
+ final CallerIdentity caller = getCallerIdentity(who);
+ Preconditions.checkCallAuthorization(isDeviceOwner(caller) || isProfileOwner(caller));
synchronized (getLockObject()) {
- ActiveAdmin admin = getProfileOwnerOrDeviceOwnerLocked(identity);
+ ActiveAdmin admin = getProfileOwnerOrDeviceOwnerLocked(caller);
if (admin.disableBluetoothContactSharing != disabled) {
admin.disableBluetoothContactSharing = disabled;
- saveSettingsLocked(identity.getUserId());
+ saveSettingsLocked(caller.getUserId());
}
}
DevicePolicyEventLogger
@@ -10256,11 +10186,11 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager {
return false;
}
Objects.requireNonNull(who, "ComponentName is null");
- final CallerIdentity identity = getCallerIdentity(who);
- Preconditions.checkCallAuthorization(isDeviceOwner(identity) || isProfileOwner(identity));
+ final CallerIdentity caller = getCallerIdentity(who);
+ Preconditions.checkCallAuthorization(isDeviceOwner(caller) || isProfileOwner(caller));
synchronized (getLockObject()) {
- ActiveAdmin admin = getProfileOwnerOrDeviceOwnerLocked(identity);
+ ActiveAdmin admin = getProfileOwnerOrDeviceOwnerLocked(caller);
return admin.disableBluetoothContactSharing;
}
}
@@ -10301,6 +10231,12 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager {
throw new SecurityException(
"User " + userId + " is not allowed to call setSecondaryLockscreenEnabled");
}
+ synchronized (getLockObject()) {
+ if (isAdminTestOnlyLocked(who, userId)) {
+ // Allow testOnly admins to bypass supervision config requirement.
+ return;
+ }
+ }
// Only the default supervision app can use this API.
final String supervisor = mContext.getResources().getString(
com.android.internal.R.string.config_defaultSupervisionProfileOwnerComponent);
@@ -10457,8 +10393,8 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager {
@Override
public void setGlobalSetting(ComponentName who, String setting, String value) {
Objects.requireNonNull(who, "ComponentName is null");
- final CallerIdentity identity = getCallerIdentity(who);
- Preconditions.checkCallAuthorization(isDeviceOwner(identity));
+ final CallerIdentity caller = getCallerIdentity(who);
+ Preconditions.checkCallAuthorization(isDeviceOwner(caller));
DevicePolicyEventLogger
.createEvent(DevicePolicyEnums.SET_GLOBAL_SETTING)
@@ -10520,7 +10456,10 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager {
return;
}
Preconditions.checkNotNull(who, "ComponentName is null");
- enforceDeviceOwnerOrProfileOwnerOnOrganizationOwnedDevice(who);
+
+ final CallerIdentity caller = getCallerIdentity(who);
+ Preconditions.checkCallAuthorization(isDeviceOwner(caller)
+ || isProfileOwnerOfOrganizationOwnedDevice(caller));
mInjector.binderWithCleanCallingIdentity(() ->
mInjector.settingsGlobalPutInt(Global.WIFI_DEVICE_OWNER_CONFIGS_LOCKDOWN,
@@ -10528,7 +10467,7 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager {
DevicePolicyEventLogger
.createEvent(DevicePolicyEnums.ALLOW_MODIFICATION_OF_ADMIN_CONFIGURED_NETWORKS)
- .setAdmin(who)
+ .setAdmin(caller.getComponentName())
.setBoolean(lockdown)
.write();
}
@@ -10539,7 +10478,10 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager {
return false;
}
Preconditions.checkNotNull(who, "ComponentName is null");
- enforceDeviceOwnerOrProfileOwnerOnOrganizationOwnedDevice(who);
+
+ final CallerIdentity caller = getCallerIdentity(who);
+ Preconditions.checkCallAuthorization(isDeviceOwner(caller)
+ || isProfileOwnerOfOrganizationOwnedDevice(caller));
return mInjector.binderWithCleanCallingIdentity(() ->
mInjector.settingsGlobalGetInt(Global.WIFI_DEVICE_OWNER_CONFIGS_LOCKDOWN, 0) > 0);
@@ -10547,20 +10489,20 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager {
@Override
public void setLocationEnabled(ComponentName who, boolean locationEnabled) {
- final CallerIdentity identity = getCallerIdentity(who);
- Preconditions.checkCallAuthorization(isDeviceOwner(identity));
+ final CallerIdentity caller = getCallerIdentity(who);
+ Preconditions.checkCallAuthorization(isDeviceOwner(caller));
mInjector.binderWithCleanCallingIdentity(() -> {
boolean wasLocationEnabled = mInjector.getLocationManager().isLocationEnabledForUser(
- identity.getUserHandle());
+ caller.getUserHandle());
mInjector.getLocationManager().setLocationEnabledForUser(locationEnabled,
- identity.getUserHandle());
+ caller.getUserHandle());
// make a best effort to only show the notification if the admin is actually enabling
// location. this is subject to race conditions with settings changes, but those are
// unlikely to realistically interfere
if (locationEnabled && !wasLocationEnabled) {
- showLocationSettingsEnabledNotification(identity.getUserHandle());
+ showLocationSettingsEnabledNotification(caller.getUserHandle());
}
});
@@ -10605,15 +10547,19 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager {
@Override
public boolean setTime(ComponentName who, long millis) {
- Objects.requireNonNull(who, "ComponentName is null in setTime");
- enforceDeviceOwnerOrProfileOwnerOnOrganizationOwnedDevice(who);
+ Objects.requireNonNull(who, "ComponentName is null");
+
+ final CallerIdentity caller = getCallerIdentity(who);
+ Preconditions.checkCallAuthorization(isDeviceOwner(caller)
+ || isProfileOwnerOfOrganizationOwnedDevice(caller));
+
// Don't allow set time when auto time is on.
if (mInjector.settingsGlobalGetInt(Global.AUTO_TIME, 0) == 1) {
return false;
}
DevicePolicyEventLogger
.createEvent(DevicePolicyEnums.SET_TIME)
- .setAdmin(who)
+ .setAdmin(caller.getComponentName())
.write();
mInjector.binderWithCleanCallingIdentity(() -> mInjector.getAlarmManager().setTime(millis));
return true;
@@ -10621,8 +10567,12 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager {
@Override
public boolean setTimeZone(ComponentName who, String timeZone) {
- Objects.requireNonNull(who, "ComponentName is null in setTimeZone");
- enforceDeviceOwnerOrProfileOwnerOnOrganizationOwnedDevice(who);
+ Objects.requireNonNull(who, "ComponentName is null");
+
+ final CallerIdentity caller = getCallerIdentity(who);
+ Preconditions.checkCallAuthorization(isDeviceOwner(caller)
+ || isProfileOwnerOfOrganizationOwnedDevice(caller));
+
// Don't allow set timezone when auto timezone is on.
if (mInjector.settingsGlobalGetInt(Global.AUTO_TIME_ZONE, 0) == 1) {
return false;
@@ -10632,7 +10582,7 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager {
DevicePolicyEventLogger
.createEvent(DevicePolicyEnums.SET_TIME_ZONE)
- .setAdmin(who)
+ .setAdmin(caller.getComponentName())
.write();
return true;
}
@@ -11644,25 +11594,23 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager {
}
@Override
- public void setPermissionPolicy(ComponentName admin, String callerPackage, int policy)
- throws RemoteException {
- int userId = UserHandle.getCallingUserId();
+ public void setPermissionPolicy(ComponentName admin, String callerPackage, int policy) {
+ final CallerIdentity caller = getCallerIdentity(admin, callerPackage);
+ Preconditions.checkCallAuthorization(isDeviceOwner(caller) || isProfileOwner(caller)
+ || isCallerDelegate(caller, DELEGATION_PERMISSION_GRANT));
+
synchronized (getLockObject()) {
- // Ensure the caller is a DO/PO or a permission grant state delegate.
- enforceCanManageScope(admin, callerPackage, DeviceAdminInfo.USES_POLICY_PROFILE_OWNER,
- DELEGATION_PERMISSION_GRANT);
- DevicePolicyData userPolicy = getUserData(userId);
+ DevicePolicyData userPolicy = getUserData(caller.getUserId());
if (userPolicy.mPermissionPolicy != policy) {
userPolicy.mPermissionPolicy = policy;
- saveSettingsLocked(userId);
+ saveSettingsLocked(caller.getUserId());
}
}
- final boolean isDelegate = (admin == null);
DevicePolicyEventLogger
.createEvent(DevicePolicyEnums.SET_PERMISSION_POLICY)
- .setAdmin(callerPackage)
+ .setAdmin(caller.getPackageName())
.setInt(policy)
- .setBoolean(isDelegate)
+ .setBoolean(/* isDelegate */ admin == null)
.write();
}
@@ -11681,18 +11629,18 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager {
throws RemoteException {
Objects.requireNonNull(callback);
- UserHandle user = mInjector.binderGetCallingUserHandle();
+ final CallerIdentity caller = getCallerIdentity(admin, callerPackage);
+ Preconditions.checkCallAuthorization(isDeviceOwner(caller) || isProfileOwner(caller)
+ || isCallerDelegate(caller, DELEGATION_PERMISSION_GRANT));
+
synchronized (getLockObject()) {
- // Ensure the caller is a DO/PO or a permission grant state delegate.
- enforceCanManageScope(admin, callerPackage, DeviceAdminInfo.USES_POLICY_PROFILE_OWNER,
- DELEGATION_PERMISSION_GRANT);
long ident = mInjector.binderClearCallingIdentity();
try {
- boolean isPostQAdmin = getTargetSdk(callerPackage, user.getIdentifier())
+ boolean isPostQAdmin = getTargetSdk(caller.getPackageName(), caller.getUserId())
>= android.os.Build.VERSION_CODES.Q;
if (!isPostQAdmin) {
// Legacy admins assume that they cannot control pre-M apps
- if (getTargetSdk(packageName, user.getIdentifier())
+ if (getTargetSdk(packageName, caller.getUserId())
< android.os.Build.VERSION_CODES.M) {
callback.sendResult(null);
return;
@@ -11704,16 +11652,15 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager {
return;
}
} catch (NameNotFoundException e) {
- throw new RemoteException(
- "Cannot check if " + permission + "is a runtime permission", e, false,
- true);
+ throw new RemoteException("Cannot check if " + permission
+ + "is a runtime permission", e, false, true);
}
if (grantState == DevicePolicyManager.PERMISSION_GRANT_STATE_GRANTED
|| grantState == DevicePolicyManager.PERMISSION_GRANT_STATE_DENIED
|| grantState == DevicePolicyManager.PERMISSION_GRANT_STATE_DEFAULT) {
- mInjector.getPermissionControllerManager(user)
- .setRuntimePermissionGrantStateByDeviceAdmin(callerPackage,
+ mInjector.getPermissionControllerManager(caller.getUserHandle())
+ .setRuntimePermissionGrantStateByDeviceAdmin(caller.getPackageName(),
packageName, permission, grantState, mContext.getMainExecutor(),
(permissionWasSet) -> {
if (isPostQAdmin && !permissionWasSet) {
@@ -11721,14 +11668,13 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager {
return;
}
- final boolean isDelegate = (admin == null);
DevicePolicyEventLogger
.createEvent(DevicePolicyEnums
.SET_PERMISSION_GRANT_STATE)
- .setAdmin(callerPackage)
+ .setAdmin(caller.getPackageName())
.setStrings(permission)
.setInt(grantState)
- .setBoolean(isDelegate)
+ .setBoolean(/* isDelegate */ admin == null)
.write();
callback.sendResult(Bundle.EMPTY);
@@ -11747,26 +11693,23 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager {
@Override
public int getPermissionGrantState(ComponentName admin, String callerPackage,
String packageName, String permission) throws RemoteException {
- PackageManager packageManager = mInjector.getPackageManager();
+ final CallerIdentity caller = getCallerIdentity(admin, callerPackage);
+ Preconditions.checkCallAuthorization(
+ isSystemUid(caller) || isDeviceOwner(caller) || isProfileOwner(caller)
+ || isCallerDelegate(caller, DELEGATION_PERMISSION_GRANT));
- UserHandle user = mInjector.binderGetCallingUserHandle();
- if (!isCallerWithSystemUid()) {
- // Ensure the caller is a DO/PO or a permission grant state delegate.
- enforceCanManageScope(admin, callerPackage,
- DeviceAdminInfo.USES_POLICY_PROFILE_OWNER, DELEGATION_PERMISSION_GRANT);
- }
synchronized (getLockObject()) {
return mInjector.binderWithCleanCallingIdentity(() -> {
int granted;
- if (getTargetSdk(callerPackage, user.getIdentifier())
+ if (getTargetSdk(caller.getPackageName(), caller.getUserId())
< android.os.Build.VERSION_CODES.Q) {
// The per-Q behavior was to not check the app-ops state.
granted = mIPackageManager.checkPermission(permission, packageName,
- user.getIdentifier());
+ caller.getUserId());
} else {
try {
- int uid = packageManager.getPackageUidAsUser(packageName,
- user.getIdentifier());
+ int uid = mInjector.getPackageManager().getPackageUidAsUser(packageName,
+ caller.getUserId());
if (PermissionChecker.checkPermissionForPreflight(mContext, permission,
PermissionChecker.PID_UNKNOWN, uid, packageName)
!= PermissionChecker.PERMISSION_GRANTED) {
@@ -11775,12 +11718,12 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager {
granted = PackageManager.PERMISSION_GRANTED;
}
} catch (NameNotFoundException e) {
- throw new RemoteException(
- "Cannot check if " + permission + "is a runtime permission", e,
- false, true);
+ throw new RemoteException("Cannot check if " + permission
+ + "is a runtime permission", e, false, true);
}
}
- int permFlags = packageManager.getPermissionFlags(permission, packageName, user);
+ int permFlags = mInjector.getPackageManager().getPermissionFlags(
+ permission, packageName, caller.getUserHandle());
if ((permFlags & PackageManager.FLAG_PERMISSION_POLICY_FIXED)
!= PackageManager.FLAG_PERMISSION_POLICY_FIXED) {
// Not controlled by policy
@@ -12062,8 +12005,11 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager {
@Override
public String getWifiMacAddress(ComponentName admin) {
- // Make sure caller has DO.
- enforceDeviceOwnerOrProfileOwnerOnOrganizationOwnedDevice(admin);
+ Objects.requireNonNull(admin, "ComponentName is null");
+
+ final CallerIdentity caller = getCallerIdentity(admin);
+ Preconditions.checkCallAuthorization(isDeviceOwner(caller)
+ || isProfileOwnerOfOrganizationOwnedDevice(caller));
return mInjector.binderWithCleanCallingIdentity(() -> {
String[] macAddresses = mInjector.getWifiManager().getFactoryMacAddresses();
@@ -12072,7 +12018,7 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager {
}
DevicePolicyEventLogger
.createEvent(DevicePolicyEnums.GET_WIFI_MAC_ADDRESS)
- .setAdmin(admin)
+ .setAdmin(caller.getComponentName())
.write();
return macAddresses.length > 0 ? macAddresses[0] : null;
});
@@ -12102,8 +12048,8 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager {
@Override
public void reboot(ComponentName admin) {
Objects.requireNonNull(admin, "ComponentName is null");
- final CallerIdentity identity = getCallerIdentity(admin);
- Preconditions.checkCallAuthorization(isDeviceOwner(identity));
+ final CallerIdentity caller = getCallerIdentity(admin);
+ Preconditions.checkCallAuthorization(isDeviceOwner(caller));
mInjector.binderWithCleanCallingIdentity(() -> {
// Make sure there are no ongoing calls on the device.
@@ -12222,12 +12168,12 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager {
return;
}
Objects.requireNonNull(who, "ComponentName is null");
- final CallerIdentity identity = getCallerIdentity(who);
- enforceManagedProfile(identity.getUserId(), "set organization color");
+ final CallerIdentity caller = getCallerIdentity(who);
+ enforceManagedProfile(caller.getUserId(), "set organization color");
synchronized (getLockObject()) {
- ActiveAdmin admin = getProfileOwnerOrDeviceOwnerLocked(identity);
+ ActiveAdmin admin = getProfileOwnerOrDeviceOwnerLocked(caller);
admin.organizationColor = color;
- saveSettingsLocked(identity.getUserId());
+ saveSettingsLocked(caller.getUserId());
}
DevicePolicyEventLogger
.createEvent(DevicePolicyEnums.SET_ORGANIZATION_COLOR)
@@ -12242,8 +12188,8 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager {
}
Preconditions.checkArgumentNonnegative(userId, "Invalid userId");
- final CallerIdentity identity = getCallerIdentity();
- Preconditions.checkCallAuthorization(hasFullCrossUsersPermission(identity, userId));
+ final CallerIdentity caller = getCallerIdentity();
+ Preconditions.checkCallAuthorization(hasFullCrossUsersPermission(caller, userId));
enforceManageUsers();
enforceManagedProfile(userId, "set organization color");
@@ -12260,10 +12206,10 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager {
return ActiveAdmin.DEF_ORGANIZATION_COLOR;
}
Objects.requireNonNull(who, "ComponentName is null");
- final CallerIdentity identity = getCallerIdentity(who);
- enforceManagedProfile(identity.getUserId(), "get organization color");
+ final CallerIdentity caller = getCallerIdentity(who);
+ enforceManagedProfile(caller.getUserId(), "get organization color");
synchronized (getLockObject()) {
- ActiveAdmin admin = getProfileOwnerOrDeviceOwnerLocked(identity);
+ ActiveAdmin admin = getProfileOwnerOrDeviceOwnerLocked(caller);
return admin.organizationColor;
}
}
@@ -12275,8 +12221,8 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager {
}
Preconditions.checkArgumentNonnegative(userHandle, "Invalid userId");
- final CallerIdentity identity = getCallerIdentity();
- Preconditions.checkCallAuthorization(hasFullCrossUsersPermission(identity, userHandle));
+ final CallerIdentity caller = getCallerIdentity();
+ Preconditions.checkCallAuthorization(hasFullCrossUsersPermission(caller, userHandle));
enforceManagedProfile(userHandle, "get organization color");
synchronized (getLockObject()) {
@@ -12293,14 +12239,14 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager {
return;
}
Objects.requireNonNull(who, "ComponentName is null");
- final CallerIdentity identity = getCallerIdentity(who);
+ final CallerIdentity caller = getCallerIdentity(who);
synchronized (getLockObject()) {
- ActiveAdmin admin = getProfileOwnerOrDeviceOwnerLocked(identity);
+ ActiveAdmin admin = getProfileOwnerOrDeviceOwnerLocked(caller);
if (!TextUtils.equals(admin.organizationName, text)) {
admin.organizationName = (text == null || text.length() == 0)
? null : text.toString();
- saveSettingsLocked(identity.getUserId());
+ saveSettingsLocked(caller.getUserId());
}
}
}
@@ -12311,10 +12257,10 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager {
return null;
}
Objects.requireNonNull(who, "ComponentName is null");
- final CallerIdentity identity = getCallerIdentity(who);
- enforceManagedProfile(identity.getUserId(), "get organization name");
+ final CallerIdentity caller = getCallerIdentity(who);
+ enforceManagedProfile(caller.getUserId(), "get organization name");
synchronized (getLockObject()) {
- ActiveAdmin admin = getProfileOwnerOrDeviceOwnerLocked(identity);
+ ActiveAdmin admin = getProfileOwnerOrDeviceOwnerLocked(caller);
return admin.organizationName;
}
}
@@ -12338,8 +12284,8 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager {
}
Preconditions.checkArgumentNonnegative(userHandle, "Invalid userId");
- final CallerIdentity identity = getCallerIdentity();
- Preconditions.checkCallAuthorization(hasFullCrossUsersPermission(identity, userHandle));
+ final CallerIdentity caller = getCallerIdentity();
+ Preconditions.checkCallAuthorization(hasFullCrossUsersPermission(caller, userHandle));
enforceManagedProfile(userHandle, "get organization name");
synchronized (getLockObject()) {
@@ -12354,21 +12300,21 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager {
public List<String> setMeteredDataDisabledPackages(ComponentName who, List<String> packageNames) {
Objects.requireNonNull(who);
Objects.requireNonNull(packageNames);
- final CallerIdentity identity = getCallerIdentity(who);
- Preconditions.checkSecurity(isDeviceOwner(identity) || isProfileOwner(identity),
- String.format("Admin %s does not own the profile", identity.getComponentName()));
+ final CallerIdentity caller = getCallerIdentity(who);
+ Preconditions.checkCallAuthorization(isDeviceOwner(caller) || isProfileOwner(caller),
+ String.format("Admin %s does not own the profile", caller.getComponentName()));
if (!mHasFeature) {
return packageNames;
}
synchronized (getLockObject()) {
- final ActiveAdmin admin = getProfileOwnerOrDeviceOwnerLocked(identity);
+ final ActiveAdmin admin = getProfileOwnerOrDeviceOwnerLocked(caller);
return mInjector.binderWithCleanCallingIdentity(() -> {
final List<String> excludedPkgs = removeInvalidPkgsForMeteredDataRestriction(
- identity.getUserId(), packageNames);
+ caller.getUserId(), packageNames);
admin.meteredDisabledPackages = packageNames;
- pushMeteredDisabledPackagesLocked(identity.getUserId());
- saveSettingsLocked(identity.getUserId());
+ pushMeteredDisabledPackagesLocked(caller.getUserId());
+ saveSettingsLocked(caller.getUserId());
return excludedPkgs;
});
}
@@ -12405,12 +12351,12 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager {
if (!mHasFeature) {
return new ArrayList<>();
}
- final CallerIdentity identity = getCallerIdentity(who);
- Preconditions.checkSecurity(isDeviceOwner(identity) || isProfileOwner(identity),
- String.format("Admin %s does not own the profile", identity.getComponentName()));
+ final CallerIdentity caller = getCallerIdentity(who);
+ Preconditions.checkCallAuthorization(isDeviceOwner(caller) || isProfileOwner(caller),
+ String.format("Admin %s does not own the profile", caller.getComponentName()));
synchronized (getLockObject()) {
- final ActiveAdmin admin = getProfileOwnerOrDeviceOwnerLocked(identity);
+ final ActiveAdmin admin = getProfileOwnerOrDeviceOwnerLocked(caller);
return admin.meteredDisabledPackages == null
? new ArrayList<>() : admin.meteredDisabledPackages;
}
@@ -12707,16 +12653,17 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager {
if (!mHasFeature) {
return null;
}
+ Objects.requireNonNull(admin, "ComponentName is null");
- Objects.requireNonNull(admin);
- enforceDeviceOwnerOrProfileOwnerOnOrganizationOwnedDevice(admin);
- if (!isOrganizationOwnedDeviceWithManagedProfile()) {
- ensureAllUsersAffiliated();
- }
+ final CallerIdentity caller = getCallerIdentity(admin);
+ Preconditions.checkCallAuthorization(isDeviceOwner(caller)
+ || isProfileOwnerOfOrganizationOwnedDevice(caller));
+ Preconditions.checkCallAuthorization(isOrganizationOwnedDeviceWithManagedProfile()
+ || areAllUsersAffiliatedWithDeviceLocked());
DevicePolicyEventLogger
.createEvent(DevicePolicyEnums.RETRIEVE_PRE_REBOOT_SECURITY_LOGS)
- .setAdmin(admin)
+ .setAdmin(caller.getComponentName())
.write();
if (!mContext.getResources().getBoolean(R.bool.config_supportPreRebootSecurityLogs)
@@ -12744,12 +12691,13 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager {
if (!mHasFeature) {
return null;
}
+ Objects.requireNonNull(admin, "ComponentName is null");
- Objects.requireNonNull(admin);
- enforceDeviceOwnerOrProfileOwnerOnOrganizationOwnedDevice(admin);
- if (!isOrganizationOwnedDeviceWithManagedProfile()) {
- ensureAllUsersAffiliated();
- }
+ final CallerIdentity caller = getCallerIdentity(admin);
+ Preconditions.checkCallAuthorization(isDeviceOwner(caller)
+ || isProfileOwnerOfOrganizationOwnedDevice(caller));
+ Preconditions.checkCallAuthorization(isOrganizationOwnedDeviceWithManagedProfile()
+ || areAllUsersAffiliatedWithDeviceLocked());
if (!mInjector.securityLogGetLoggingEnabledProperty()) {
return null;
@@ -12760,7 +12708,7 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager {
List<SecurityEvent> logs = mSecurityLogMonitor.retrieveLogs();
DevicePolicyEventLogger
.createEvent(DevicePolicyEnums.RETRIEVE_SECURITY_LOGS)
- .setAdmin(admin)
+ .setAdmin(caller.getComponentName())
.write();
return logs != null ? new ParceledListSlice<SecurityEvent>(logs) : null;
}
@@ -13200,10 +13148,11 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager {
if (!mHasFeature) {
return;
}
- synchronized (getLockObject()) {
- enforceCanManageScope(admin, packageName, DeviceAdminInfo.USES_POLICY_DEVICE_OWNER,
- DELEGATION_NETWORK_LOGGING);
+ final CallerIdentity caller = getCallerIdentity(admin, packageName);
+ Preconditions.checkCallAuthorization(isDeviceOwner(caller)
+ || isCallerDelegate(caller, DELEGATION_NETWORK_LOGGING));
+ synchronized (getLockObject()) {
if (enabled == isNetworkLoggingEnabledInternalLocked()) {
// already in the requested state
return;
@@ -13214,15 +13163,13 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager {
deviceOwner.numNetworkLoggingNotifications = 0;
deviceOwner.lastNetworkLoggingNotificationTimeMs = 0;
}
- saveSettingsLocked(mInjector.userHandleGetCallingUserId());
-
+ saveSettingsLocked(caller.getUserId());
setNetworkLoggingActiveInternal(enabled);
- final boolean isDelegate = (admin == null);
DevicePolicyEventLogger
.createEvent(DevicePolicyEnums.SET_NETWORK_LOGGING_ENABLED)
- .setAdmin(packageName)
- .setBoolean(isDelegate)
+ .setAdmin(caller.getPackageName())
+ .setBoolean(/* isDelegate */ admin == null)
.setInt(enabled ? 1 : 0)
.write();
}
@@ -13319,10 +13266,12 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager {
if (!mHasFeature) {
return false;
}
+ final CallerIdentity caller = getCallerIdentity(admin, packageName);
+ Preconditions.checkCallAuthorization(
+ isDeviceOwner(caller) || isCallerDelegate(caller, DELEGATION_NETWORK_LOGGING)
+ || hasCallingOrSelfPermission(permission.MANAGE_USERS));
+
synchronized (getLockObject()) {
- enforceCanManageScopeOrCheckPermission(admin, packageName,
- DeviceAdminInfo.USES_POLICY_DEVICE_OWNER, DELEGATION_NETWORK_LOGGING,
- android.Manifest.permission.MANAGE_USERS);
return isNetworkLoggingEnabledInternalLocked();
}
}
@@ -13345,20 +13294,19 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager {
if (!mHasFeature) {
return null;
}
- enforceCanManageScope(admin, packageName, DeviceAdminInfo.USES_POLICY_DEVICE_OWNER,
- DELEGATION_NETWORK_LOGGING);
- ensureAllUsersAffiliated();
+ final CallerIdentity caller = getCallerIdentity(admin, packageName);
+ Preconditions.checkCallAuthorization(isDeviceOwner(caller)
+ || isCallerDelegate(caller, DELEGATION_NETWORK_LOGGING));
+ Preconditions.checkCallAuthorization(areAllUsersAffiliatedWithDeviceLocked());
synchronized (getLockObject()) {
- if (mNetworkLogger == null
- || !isNetworkLoggingEnabledInternalLocked()) {
+ if (mNetworkLogger == null || !isNetworkLoggingEnabledInternalLocked()) {
return null;
}
- final boolean isDelegate = (admin == null);
DevicePolicyEventLogger
.createEvent(DevicePolicyEnums.RETRIEVE_NETWORK_LOGS)
- .setAdmin(packageName)
- .setBoolean(isDelegate)
+ .setAdmin(caller.getPackageName())
+ .setBoolean(/* isDelegate */ admin == null)
.write();
final long currentTime = System.currentTimeMillis();
@@ -13575,8 +13523,8 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager {
@Override
public StringParceledListSlice getOwnerInstalledCaCerts(@NonNull UserHandle user) {
final int userId = user.getIdentifier();
- final CallerIdentity identity = getCallerIdentity();
- enforceProfileOwnerOrFullCrossUsersPermission(identity, userId);
+ final CallerIdentity caller = getCallerIdentity();
+ enforceProfileOwnerOrFullCrossUsersPermission(caller, userId);
synchronized (getLockObject()) {
return new StringParceledListSlice(
new ArrayList<>(getUserData(userId).mOwnerInstalledCaCerts));
@@ -13620,8 +13568,8 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager {
return;
}
Objects.requireNonNull(admin, "ComponentName is null");
- final CallerIdentity identity = getCallerIdentity(admin);
- Preconditions.checkCallAuthorization(isDeviceOwner(identity));
+ final CallerIdentity caller = getCallerIdentity(admin);
+ Preconditions.checkCallAuthorization(isDeviceOwner(caller));
synchronized (getLockObject()) {
ActiveAdmin deviceOwner = getDeviceOwnerAdminLocked();
@@ -13630,7 +13578,7 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager {
return;
}
deviceOwner.isLogoutEnabled = enabled;
- saveSettingsLocked(identity.getUserId());
+ saveSettingsLocked(caller.getUserId());
}
}
@@ -13797,8 +13745,8 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager {
return;
}
Objects.requireNonNull(admin, "ComponentName is null");
- final CallerIdentity identity = getCallerIdentity(admin);
- Preconditions.checkCallAuthorization(isDeviceOwner(identity));
+ final CallerIdentity caller = getCallerIdentity(admin);
+ Preconditions.checkCallAuthorization(isDeviceOwner(caller));
final String startUserSessionMessageString =
startUserSessionMessage != null ? startUserSessionMessage.toString() : null;
@@ -13809,7 +13757,7 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager {
return;
}
deviceOwner.startUserSessionMessage = startUserSessionMessageString;
- saveSettingsLocked(identity.getUserId());
+ saveSettingsLocked(caller.getUserId());
}
mInjector.getActivityManagerInternal()
@@ -13822,8 +13770,8 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager {
return;
}
Objects.requireNonNull(admin, "ComponentName is null");
- final CallerIdentity identity = getCallerIdentity(admin);
- Preconditions.checkCallAuthorization(isDeviceOwner(identity));
+ final CallerIdentity caller = getCallerIdentity(admin);
+ Preconditions.checkCallAuthorization(isDeviceOwner(caller));
final String endUserSessionMessageString =
endUserSessionMessage != null ? endUserSessionMessage.toString() : null;
@@ -13834,7 +13782,7 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager {
return;
}
deviceOwner.endUserSessionMessage = endUserSessionMessageString;
- saveSettingsLocked(identity.getUserId());
+ saveSettingsLocked(caller.getUserId());
}
mInjector.getActivityManagerInternal()
@@ -13847,8 +13795,8 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager {
return null;
}
Objects.requireNonNull(admin, "ComponentName is null");
- final CallerIdentity identity = getCallerIdentity(admin);
- Preconditions.checkCallAuthorization(isDeviceOwner(identity));
+ final CallerIdentity caller = getCallerIdentity(admin);
+ Preconditions.checkCallAuthorization(isDeviceOwner(caller));
synchronized (getLockObject()) {
final ActiveAdmin deviceOwner = getDeviceOwnerAdminLocked();
@@ -13862,8 +13810,8 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager {
return null;
}
Objects.requireNonNull(admin, "ComponentName is null");
- final CallerIdentity identity = getCallerIdentity(admin);
- Preconditions.checkCallAuthorization(isDeviceOwner(identity));
+ final CallerIdentity caller = getCallerIdentity(admin);
+ Preconditions.checkCallAuthorization(isDeviceOwner(caller));
synchronized (getLockObject()) {
final ActiveAdmin deviceOwner = getDeviceOwnerAdminLocked();
@@ -13907,8 +13855,8 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager {
}
Objects.requireNonNull(who, "ComponentName is null");
Objects.requireNonNull(apnSetting, "ApnSetting is null in addOverrideApn");
- final CallerIdentity identity = getCallerIdentity(who);
- Preconditions.checkCallAuthorization(isDeviceOwner(identity));
+ final CallerIdentity caller = getCallerIdentity(who);
+ Preconditions.checkCallAuthorization(isDeviceOwner(caller));
TelephonyManager tm = mContext.getSystemService(TelephonyManager.class);
if (tm != null) {
@@ -13928,8 +13876,8 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager {
}
Objects.requireNonNull(who, "ComponentName is null");
Objects.requireNonNull(apnSetting, "ApnSetting is null in updateOverrideApn");
- final CallerIdentity identity = getCallerIdentity(who);
- Preconditions.checkCallAuthorization(isDeviceOwner(identity));
+ final CallerIdentity caller = getCallerIdentity(who);
+ Preconditions.checkCallAuthorization(isDeviceOwner(caller));
if (apnId < 0) {
return false;
@@ -13950,8 +13898,8 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager {
return false;
}
Objects.requireNonNull(who, "ComponentName is null");
- final CallerIdentity identity = getCallerIdentity(who);
- Preconditions.checkCallAuthorization(isDeviceOwner(identity));
+ final CallerIdentity caller = getCallerIdentity(who);
+ Preconditions.checkCallAuthorization(isDeviceOwner(caller));
return removeOverrideApnUnchecked(apnId);
}
@@ -13971,8 +13919,8 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager {
return Collections.emptyList();
}
Objects.requireNonNull(who, "ComponentName is null");
- final CallerIdentity identity = getCallerIdentity(who);
- Preconditions.checkCallAuthorization(isDeviceOwner(identity));
+ final CallerIdentity caller = getCallerIdentity(who);
+ Preconditions.checkCallAuthorization(isDeviceOwner(caller));
return getOverrideApnsUnchecked();
}
@@ -13992,8 +13940,8 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager {
return;
}
Objects.requireNonNull(who, "ComponentName is null");
- final CallerIdentity identity = getCallerIdentity(who);
- Preconditions.checkCallAuthorization(isDeviceOwner(identity));
+ final CallerIdentity caller = getCallerIdentity(who);
+ Preconditions.checkCallAuthorization(isDeviceOwner(caller));
setOverrideApnsEnabledUnchecked(enabled);
}
@@ -14010,8 +13958,8 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager {
return false;
}
Objects.requireNonNull(who, "ComponentName is null");
- final CallerIdentity identity = getCallerIdentity(who);
- Preconditions.checkCallAuthorization(isDeviceOwner(identity));
+ final CallerIdentity caller = getCallerIdentity(who);
+ Preconditions.checkCallAuthorization(isDeviceOwner(caller));
Cursor enforceCursor = mInjector.binderWithCleanCallingIdentity(
() -> mContext.getContentResolver().query(
@@ -14094,8 +14042,8 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager {
return PRIVATE_DNS_SET_ERROR_FAILURE_SETTING;
}
Objects.requireNonNull(who, "ComponentName is null");
- final CallerIdentity identity = getCallerIdentity(who);
- Preconditions.checkCallAuthorization(isDeviceOwner(identity));
+ final CallerIdentity caller = getCallerIdentity(who);
+ Preconditions.checkCallAuthorization(isDeviceOwner(caller));
switch (mode) {
case PRIVATE_DNS_MODE_OPPORTUNISTIC:
@@ -14130,8 +14078,8 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager {
return PRIVATE_DNS_MODE_UNKNOWN;
}
Objects.requireNonNull(who, "ComponentName is null");
- final CallerIdentity identity = getCallerIdentity(who);
- Preconditions.checkCallAuthorization(isDeviceOwner(identity));
+ final CallerIdentity caller = getCallerIdentity(who);
+ Preconditions.checkCallAuthorization(isDeviceOwner(caller));
String currentMode = mInjector.settingsGlobalGetString(PRIVATE_DNS_MODE);
if (currentMode == null) {
@@ -14155,20 +14103,26 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager {
return null;
}
Objects.requireNonNull(who, "ComponentName is null");
- final CallerIdentity identity = getCallerIdentity(who);
- Preconditions.checkCallAuthorization(isDeviceOwner(identity));
+ final CallerIdentity caller = getCallerIdentity(who);
+ Preconditions.checkCallAuthorization(isDeviceOwner(caller));
return mInjector.settingsGlobalGetString(PRIVATE_DNS_SPECIFIER);
}
@Override
public void installUpdateFromFile(ComponentName admin,
ParcelFileDescriptor updateFileDescriptor, StartInstallingUpdateCallback callback) {
+ Objects.requireNonNull(admin, "ComponentName is null");
+
+ final CallerIdentity caller = getCallerIdentity(admin);
+ Preconditions.checkCallAuthorization(isDeviceOwner(caller)
+ || isProfileOwnerOfOrganizationOwnedDevice(caller));
+
DevicePolicyEventLogger
.createEvent(DevicePolicyEnums.INSTALL_SYSTEM_UPDATE)
- .setAdmin(admin)
+ .setAdmin(caller.getComponentName())
.setBoolean(isDeviceAB())
.write();
- enforceDeviceOwnerOrProfileOwnerOnOrganizationOwnedDevice(admin);
+
mInjector.binderWithCleanCallingIdentity(() -> {
UpdateInstaller updateInstaller;
if (isDeviceAB()) {
@@ -14193,12 +14147,12 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager {
return;
}
Objects.requireNonNull(who, "ComponentName is null");
- final CallerIdentity identity = getCallerIdentity(who);
+ final CallerIdentity caller = getCallerIdentity(who);
synchronized (getLockObject()) {
- final ActiveAdmin admin = getProfileOwnerOrDeviceOwnerLocked(identity);
+ final ActiveAdmin admin = getProfileOwnerOrDeviceOwnerLocked(caller);
admin.mCrossProfileCalendarPackages = packageNames;
- saveSettingsLocked(identity.getUserId());
+ saveSettingsLocked(caller.getUserId());
}
DevicePolicyEventLogger
.createEvent(DevicePolicyEnums.SET_CROSS_PROFILE_CALENDAR_PACKAGES)
@@ -14214,10 +14168,10 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager {
return Collections.emptyList();
}
Objects.requireNonNull(who, "ComponentName is null");
- final CallerIdentity identity = getCallerIdentity(who);
+ final CallerIdentity caller = getCallerIdentity(who);
synchronized (getLockObject()) {
- final ActiveAdmin admin = getProfileOwnerOrDeviceOwnerLocked(identity);
+ final ActiveAdmin admin = getProfileOwnerOrDeviceOwnerLocked(caller);
return admin.mCrossProfileCalendarPackages;
}
}
@@ -14231,8 +14185,8 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager {
Preconditions.checkStringNotEmpty(packageName, "Package name is null or empty");
Preconditions.checkArgumentNonnegative(userHandle, "Invalid userId");
- final CallerIdentity identity = getCallerIdentity();
- Preconditions.checkCallAuthorization(hasCrossUsersPermission(identity, userHandle));
+ final CallerIdentity caller = getCallerIdentity();
+ Preconditions.checkCallAuthorization(hasCrossUsersPermission(caller, userHandle));
synchronized (getLockObject()) {
if (mInjector.settingsSecureGetIntForUser(
@@ -14257,8 +14211,8 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager {
}
Preconditions.checkArgumentNonnegative(userHandle, "Invalid userId");
- final CallerIdentity identity = getCallerIdentity();
- Preconditions.checkCallAuthorization(hasCrossUsersPermission(identity, userHandle));
+ final CallerIdentity caller = getCallerIdentity();
+ Preconditions.checkCallAuthorization(hasCrossUsersPermission(caller, userHandle));
synchronized (getLockObject()) {
final ActiveAdmin admin = getProfileOwnerAdminLocked(userHandle);
@@ -14276,17 +14230,17 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager {
}
Objects.requireNonNull(who, "ComponentName is null");
Objects.requireNonNull(packageNames, "Package names is null");
- final CallerIdentity identity = getCallerIdentity(who);
+ final CallerIdentity caller = getCallerIdentity(who);
final List<String> previousCrossProfilePackages;
synchronized (getLockObject()) {
- final ActiveAdmin admin = getProfileOwnerOrDeviceOwnerLocked(identity);
+ final ActiveAdmin admin = getProfileOwnerOrDeviceOwnerLocked(caller);
previousCrossProfilePackages = admin.mCrossProfilePackages;
if (packageNames.equals(previousCrossProfilePackages)) {
return;
}
admin.mCrossProfilePackages = packageNames;
- saveSettingsLocked(identity.getUserId());
+ saveSettingsLocked(caller.getUserId());
}
logSetCrossProfilePackages(who, packageNames);
final CrossProfileApps crossProfileApps = mContext.getSystemService(CrossProfileApps.class);
@@ -14309,10 +14263,10 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager {
return Collections.emptyList();
}
Objects.requireNonNull(who, "ComponentName is null");
- final CallerIdentity identity = getCallerIdentity(who);
+ final CallerIdentity caller = getCallerIdentity(who);
synchronized (getLockObject()) {
- final ActiveAdmin admin = getProfileOwnerOrDeviceOwnerLocked(identity);
+ final ActiveAdmin admin = getProfileOwnerOrDeviceOwnerLocked(caller);
return admin.mCrossProfilePackages;
}
}
@@ -14322,12 +14276,12 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager {
if (!mHasFeature) {
return Collections.emptyList();
}
- final CallerIdentity identity = getCallerIdentity();
+ final CallerIdentity caller = getCallerIdentity();
Preconditions.checkCallAuthorization(
- isSystemUid(identity) || isRootUid(identity) || hasCallingPermission(
+ isSystemUid(caller) || isRootUid(caller) || hasCallingPermission(
permission.INTERACT_ACROSS_USERS) || hasCallingPermission(
permission.INTERACT_ACROSS_USERS_FULL) || hasPermissionForPreflight(
- identity, permission.INTERACT_ACROSS_PROFILES));
+ caller, permission.INTERACT_ACROSS_PROFILES));
synchronized (getLockObject()) {
final List<ActiveAdmin> admins = getProfileOwnerAdminsForCurrentProfileGroup();
@@ -14516,11 +14470,11 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager {
public void setUserControlDisabledPackages(ComponentName who, List<String> packages) {
Objects.requireNonNull(who, "ComponentName is null");
Preconditions.checkNotNull(packages, "packages is null");
- final CallerIdentity identity = getCallerIdentity(who);
- Preconditions.checkCallAuthorization(isDeviceOwner(identity));
+ final CallerIdentity caller = getCallerIdentity(who);
+ Preconditions.checkCallAuthorization(isDeviceOwner(caller));
synchronized (getLockObject()) {
- setUserControlDisabledPackagesLocked(identity.getUserId(), packages);
+ setUserControlDisabledPackagesLocked(caller.getUserId(), packages);
DevicePolicyEventLogger
.createEvent(DevicePolicyEnums.SET_USER_CONTROL_DISABLED_PACKAGES)
.setAdmin(who)
@@ -14540,12 +14494,12 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager {
@Override
public List<String> getUserControlDisabledPackages(ComponentName who) {
- final CallerIdentity identity = getCallerIdentity(who);
- Preconditions.checkCallAuthorization(isDeviceOwner(identity));
+ final CallerIdentity caller = getCallerIdentity(who);
+ Preconditions.checkCallAuthorization(isDeviceOwner(caller));
synchronized (getLockObject()) {
final List<String> packages =
- getUserData(identity.getUserId()).mUserControlDisabledPackages;
+ getUserData(caller.getUserId()).mUserControlDisabledPackages;
return packages == null ? Collections.EMPTY_LIST : packages;
}
}
@@ -14587,12 +14541,16 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager {
@Override
public @PersonalAppsSuspensionReason int getPersonalAppsSuspendedReasons(ComponentName who) {
+ Objects.requireNonNull(who, "ComponentName is null");
+
+ final CallerIdentity caller = getCallerIdentity(who);
+ // DO shouldn't be able to use this method.
+ Preconditions.checkCallAuthorization(isProfileOwnerOfOrganizationOwnedDevice(caller));
+
synchronized (getLockObject()) {
final ActiveAdmin admin = getActiveAdminForCallerLocked(who,
DeviceAdminInfo.USES_POLICY_ORGANIZATION_OWNED_PROFILE_OWNER,
false /* parent */);
- // DO shouldn't be able to use this method.
- enforceProfileOwnerOfOrganizationOwnedDevice(admin);
final long deadline = admin.mProfileOffDeadline;
final int result = makeSuspensionReasons(admin.mSuspendPersonalApps,
deadline != 0 && mInjector.systemCurrentTimeMillis() > deadline);
@@ -14616,14 +14574,18 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager {
@Override
public void setPersonalAppsSuspended(ComponentName who, boolean suspended) {
- final int callingUserId = mInjector.userHandleGetCallingUserId();
+ Objects.requireNonNull(who, "ComponentName is null");
+
+ final CallerIdentity caller = getCallerIdentity(who);
+ // DO shouldn't be able to use this method.
+ Preconditions.checkCallAuthorization(isProfileOwnerOfOrganizationOwnedDevice(caller));
+ Preconditions.checkState(canHandleCheckPolicyComplianceIntent(caller));
+
+ final int callingUserId = caller.getUserId();
synchronized (getLockObject()) {
final ActiveAdmin admin = getActiveAdminForCallerLocked(who,
DeviceAdminInfo.USES_POLICY_ORGANIZATION_OWNED_PROFILE_OWNER,
false /* parent */);
- // DO shouldn't be able to use this method.
- enforceProfileOwnerOfOrganizationOwnedDevice(admin);
- enforceHandlesCheckPolicyComplianceIntent(callingUserId, admin.info.getPackageName());
boolean shouldSaveSettings = false;
if (admin.mSuspendPersonalApps != suspended) {
admin.mSuspendPersonalApps = suspended;
@@ -14643,7 +14605,7 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager {
DevicePolicyEventLogger
.createEvent(DevicePolicyEnums.SET_PERSONAL_APPS_SUSPENDED)
- .setAdmin(who)
+ .setAdmin(caller.getComponentName())
.setBoolean(suspended)
.write();
}
@@ -14874,15 +14836,20 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager {
@Override
public void setManagedProfileMaximumTimeOff(ComponentName who, long timeoutMillis) {
- final int userId = mInjector.userHandleGetCallingUserId();
+ Objects.requireNonNull(who, "ComponentName is null");
+ Preconditions.checkArgumentNonnegative(timeoutMillis, "Timeout must be non-negative.");
+
+ final CallerIdentity caller = getCallerIdentity(who);
+ // DO shouldn't be able to use this method.
+ Preconditions.checkCallAuthorization(isProfileOwnerOfOrganizationOwnedDevice(caller));
+ Preconditions.checkState(canHandleCheckPolicyComplianceIntent(caller));
+
+ final int userId = caller.getUserId();
synchronized (getLockObject()) {
final ActiveAdmin admin = getActiveAdminForCallerLocked(who,
DeviceAdminInfo.USES_POLICY_ORGANIZATION_OWNED_PROFILE_OWNER,
false /* parent */);
- // DO shouldn't be able to use this method.
- enforceProfileOwnerOfOrganizationOwnedDevice(admin);
- enforceHandlesCheckPolicyComplianceIntent(userId, admin.info.getPackageName());
- Preconditions.checkArgument(timeoutMillis >= 0, "Timeout must be non-negative.");
+
// Ensure the timeout is long enough to avoid having bad user experience.
if (timeoutMillis > 0 && timeoutMillis < MANAGED_PROFILE_MAXIMUM_TIME_OFF_THRESHOLD
&& !isAdminTestOnlyLocked(who, userId)) {
@@ -14900,31 +14867,35 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager {
DevicePolicyEventLogger
.createEvent(DevicePolicyEnums.SET_MANAGED_PROFILE_MAXIMUM_TIME_OFF)
- .setAdmin(who)
+ .setAdmin(caller.getComponentName())
.setTimePeriod(timeoutMillis)
.write();
}
- private void enforceHandlesCheckPolicyComplianceIntent(
- @UserIdInt int userId, String packageName) {
+ private boolean canHandleCheckPolicyComplianceIntent(CallerIdentity caller) {
mInjector.binderWithCleanCallingIdentity(() -> {
final Intent intent = new Intent(DevicePolicyManager.ACTION_CHECK_POLICY_COMPLIANCE);
- intent.setPackage(packageName);
- final List<ResolveInfo> handlers = mInjector.getPackageManager()
- .queryIntentActivitiesAsUser(intent, /* flags= */ 0, userId);
- Preconditions.checkState(!handlers.isEmpty(),
- "Admin doesn't handle " + DevicePolicyManager.ACTION_CHECK_POLICY_COMPLIANCE);
+ intent.setPackage(caller.getPackageName());
+ final List<ResolveInfo> handlers =
+ mInjector.getPackageManager().queryIntentActivitiesAsUser(intent, /* flags= */
+ 0, caller.getUserId());
+ return !handlers.isEmpty();
});
+ return true;
}
@Override
public long getManagedProfileMaximumTimeOff(ComponentName who) {
+ Objects.requireNonNull(who, "ComponentName is null");
+
+ final CallerIdentity caller = getCallerIdentity(who);
+ // DO shouldn't be able to use this method.
+ Preconditions.checkCallAuthorization(isProfileOwnerOfOrganizationOwnedDevice(caller));
+
synchronized (getLockObject()) {
final ActiveAdmin admin = getActiveAdminForCallerLocked(who,
DeviceAdminInfo.USES_POLICY_ORGANIZATION_OWNED_PROFILE_OWNER,
false /* parent */);
- // DO shouldn't be able to use this method.
- enforceProfileOwnerOfOrganizationOwnedDevice(admin);
return admin.mProfileMaximumTimeOffMillis;
}
}
diff --git a/services/tests/mockingservicestests/src/com/android/server/am/ApplicationExitInfoTest.java b/services/tests/mockingservicestests/src/com/android/server/am/ApplicationExitInfoTest.java
index 8db09b4f156c..e9a50b36693a 100644
--- a/services/tests/mockingservicestests/src/com/android/server/am/ApplicationExitInfoTest.java
+++ b/services/tests/mockingservicestests/src/com/android/server/am/ApplicationExitInfoTest.java
@@ -120,6 +120,7 @@ public class ApplicationExitInfoTest {
mHandlerThread.start();
mHandler = new Handler(mHandlerThread.getLooper());
mProcessList = spy(new ProcessList());
+ ProcessList.sKillHandler = null;
mAppExitInfoTracker = spy(new AppExitInfoTracker());
setFieldValue(AppExitInfoTracker.class, mAppExitInfoTracker, "mIsolatedUidRecords",
spy(mAppExitInfoTracker.new IsolatedUidRecords()));
@@ -147,6 +148,7 @@ public class ApplicationExitInfoTest {
public void tearDown() {
LocalServices.removeServiceForTest(PackageManagerInternal.class);
mHandlerThread.quit();
+ ProcessList.sKillHandler = null;
}
private static <T> void setFieldValue(Class clazz, Object obj, String fieldName, T val) {
diff --git a/services/tests/mockingservicestests/src/com/android/server/location/LocationProviderManagerTest.java b/services/tests/mockingservicestests/src/com/android/server/location/LocationProviderManagerTest.java
index 80ad0a838bbb..c36cdeb582bd 100644
--- a/services/tests/mockingservicestests/src/com/android/server/location/LocationProviderManagerTest.java
+++ b/services/tests/mockingservicestests/src/com/android/server/location/LocationProviderManagerTest.java
@@ -24,7 +24,6 @@ import static android.app.AppOpsManager.OP_MONITOR_LOCATION;
import static android.location.Criteria.ACCURACY_COARSE;
import static android.location.Criteria.ACCURACY_FINE;
import static android.location.Criteria.POWER_HIGH;
-import static android.location.LocationManager.PASSIVE_PROVIDER;
import static android.os.PowerManager.LOCATION_MODE_THROTTLE_REQUESTS_WHEN_SCREEN_OFF;
import static androidx.test.ext.truth.location.LocationSubject.assertThat;
@@ -356,8 +355,7 @@ public class LocationProviderManagerTest {
@Test
public void testPassive_Listener() throws Exception {
ILocationListener listener = createMockLocationListener();
- LocationRequest request = LocationRequest.createFromDeprecatedProvider(PASSIVE_PROVIDER, 0,
- 0, false);
+ LocationRequest request = new LocationRequest.Builder(0).build();
mPassive.registerLocationRequest(request, IDENTITY, PERMISSION_FINE, listener);
Location loc = createLocation(NAME, mRandom);
@@ -382,8 +380,7 @@ public class LocationProviderManagerTest {
ArgumentCaptor<Location> locationCaptor = ArgumentCaptor.forClass(Location.class);
ILocationListener listener = createMockLocationListener();
- mManager.registerLocationRequest(
- LocationRequest.createFromDeprecatedProvider(NAME, 0, 0, false), IDENTITY,
+ mManager.registerLocationRequest(new LocationRequest.Builder(0).build(), IDENTITY,
PERMISSION_FINE, listener);
Location loc = createLocation(NAME, mRandom);
@@ -437,8 +434,7 @@ public class LocationProviderManagerTest {
"attribution");
ILocationListener listener = createMockLocationListener();
- mManager.registerLocationRequest(
- LocationRequest.createFromDeprecatedProvider(NAME, 0, 0, false), identity,
+ mManager.registerLocationRequest(new LocationRequest.Builder(0).build(), identity,
PERMISSION_FINE, listener);
Location loc = createLocation(NAME, mRandom);
@@ -451,8 +447,7 @@ public class LocationProviderManagerTest {
@Test
public void testRegisterListener_Unregister() throws Exception {
ILocationListener listener = createMockLocationListener();
- mManager.registerLocationRequest(
- LocationRequest.createFromDeprecatedProvider(NAME, 0, 0, false), IDENTITY,
+ mManager.registerLocationRequest(new LocationRequest.Builder(0).build(), IDENTITY,
PERMISSION_FINE, listener);
mManager.unregisterLocationRequest(listener);
@@ -470,8 +465,7 @@ public class LocationProviderManagerTest {
"attribution");
ILocationListener listener = createMockLocationListener();
- mManager.registerLocationRequest(
- LocationRequest.createFromDeprecatedProvider(NAME, 0, 0, false), identity,
+ mManager.registerLocationRequest(new LocationRequest.Builder(0).build(), identity,
PERMISSION_FINE, listener);
CountDownLatch blocker = new CountDownLatch(1);
@@ -493,8 +487,7 @@ public class LocationProviderManagerTest {
@Test
public void testRegisterListener_NumUpdates() throws Exception {
ILocationListener listener = createMockLocationListener();
- LocationRequest request = LocationRequest.createFromDeprecatedProvider(NAME, 0, 0,
- false).setNumUpdates(5);
+ LocationRequest request = new LocationRequest.Builder(0).setMaxUpdates(5).build();
mManager.registerLocationRequest(request, IDENTITY, PERMISSION_FINE, listener);
mProvider.setProviderLocation(createLocation(NAME, mRandom));
@@ -511,8 +504,7 @@ public class LocationProviderManagerTest {
@Test
public void testRegisterListener_ExpiringAlarm() throws Exception {
ILocationListener listener = createMockLocationListener();
- LocationRequest request = LocationRequest.createFromDeprecatedProvider(NAME, 0, 0,
- false).setExpireIn(5000);
+ LocationRequest request = new LocationRequest.Builder(0).setDurationMillis(5000).build();
mManager.registerLocationRequest(request, IDENTITY, PERMISSION_FINE, listener);
long baseTimeMs = SystemClock.elapsedRealtime();
@@ -535,8 +527,7 @@ public class LocationProviderManagerTest {
@Test
public void testRegisterListener_ExpiringNoAlarm() throws Exception {
ILocationListener listener = createMockLocationListener();
- LocationRequest request = LocationRequest.createFromDeprecatedProvider(NAME, 0, 0,
- false).setExpireIn(25);
+ LocationRequest request = new LocationRequest.Builder(0).setDurationMillis(25).build();
mManager.registerLocationRequest(request, IDENTITY, PERMISSION_FINE, listener);
Thread.sleep(25);
@@ -547,22 +538,10 @@ public class LocationProviderManagerTest {
}
@Test
- public void testRegisterListener_AlreadyExpired() throws Exception {
- ILocationListener listener = createMockLocationListener();
- LocationRequest request = LocationRequest.createFromDeprecatedProvider(NAME, 0, 0,
- false).setExpireIn(-1);
- mManager.registerLocationRequest(request, IDENTITY, PERMISSION_FINE, listener);
-
- mProvider.setProviderLocation(createLocation(NAME, mRandom));
- verify(listener, never()).onLocationChanged(any(Location.class),
- nullable(IRemoteCallback.class));
- }
-
- @Test
public void testRegisterListener_FastestInterval() throws Exception {
ILocationListener listener = createMockLocationListener();
- LocationRequest request = LocationRequest.createFromDeprecatedProvider(NAME, 5000, 0,
- false).setFastestInterval(5000);
+ LocationRequest request = new LocationRequest.Builder(5000).setMinUpdateIntervalMillis(
+ 5000).build();
mManager.registerLocationRequest(request, IDENTITY, PERMISSION_FINE, listener);
mProvider.setProviderLocation(createLocation(NAME, mRandom));
@@ -575,8 +554,8 @@ public class LocationProviderManagerTest {
@Test
public void testRegisterListener_SmallestDisplacement() throws Exception {
ILocationListener listener = createMockLocationListener();
- LocationRequest request = LocationRequest.createFromDeprecatedProvider(NAME, 5000, 0,
- false).setSmallestDisplacement(1f);
+ LocationRequest request = new LocationRequest.Builder(5000).setMinUpdateDistanceMeters(
+ 1f).build();
mManager.registerLocationRequest(request, IDENTITY, PERMISSION_FINE, listener);
Location loc = createLocation(NAME, mRandom);
@@ -590,7 +569,7 @@ public class LocationProviderManagerTest {
@Test
public void testRegisterListener_NoteOpFailure() throws Exception {
ILocationListener listener = createMockLocationListener();
- LocationRequest request = LocationRequest.createFromDeprecatedProvider(NAME, 0, 0, false);
+ LocationRequest request = new LocationRequest.Builder(0).build();
mManager.registerLocationRequest(request, IDENTITY, PERMISSION_FINE, listener);
mInjector.getAppOpsHelper().setAppOpAllowed(OP_FINE_LOCATION, IDENTITY.getPackageName(),
@@ -608,8 +587,7 @@ public class LocationProviderManagerTest {
"attribution");
ILocationListener listener = createMockLocationListener();
- mManager.registerLocationRequest(
- LocationRequest.createFromDeprecatedProvider(NAME, 0, 0, false), identity,
+ mManager.registerLocationRequest(new LocationRequest.Builder(0).build(), identity,
PERMISSION_FINE, listener);
CountDownLatch blocker = new CountDownLatch(1);
@@ -637,8 +615,7 @@ public class LocationProviderManagerTest {
ArgumentCaptor<Location> locationCaptor = ArgumentCaptor.forClass(Location.class);
ILocationCallback listener = createMockGetCurrentLocationListener();
- LocationRequest locationRequest = LocationRequest.createFromDeprecatedProvider(NAME, 0, 0,
- false);
+ LocationRequest locationRequest = new LocationRequest.Builder(0).build();
ICancellationSignal cancellationSignal = CancellationSignal.createTransport();
mManager.getCurrentLocation(locationRequest, IDENTITY,
PERMISSION_FINE, cancellationSignal, listener);
@@ -654,8 +631,7 @@ public class LocationProviderManagerTest {
@Test
public void testGetCurrentLocation_Cancel() throws Exception {
ILocationCallback listener = createMockGetCurrentLocationListener();
- LocationRequest locationRequest = LocationRequest.createFromDeprecatedProvider(NAME, 0, 0,
- false);
+ LocationRequest locationRequest = new LocationRequest.Builder(0).build();
ICancellationSignal cancellationSignal = CancellationSignal.createTransport();
mManager.getCurrentLocation(locationRequest, IDENTITY,
PERMISSION_FINE, cancellationSignal, listener);
@@ -669,8 +645,7 @@ public class LocationProviderManagerTest {
@Test
public void testGetCurrentLocation_ProviderDisabled() throws Exception {
ILocationCallback listener = createMockGetCurrentLocationListener();
- LocationRequest locationRequest = LocationRequest.createFromDeprecatedProvider(NAME, 0, 0,
- false);
+ LocationRequest locationRequest = new LocationRequest.Builder(0).build();
ICancellationSignal cancellationSignal = CancellationSignal.createTransport();
mManager.getCurrentLocation(locationRequest, IDENTITY,
PERMISSION_FINE, cancellationSignal, listener);
@@ -686,8 +661,7 @@ public class LocationProviderManagerTest {
mProvider.setProviderAllowed(false);
ILocationCallback listener = createMockGetCurrentLocationListener();
- LocationRequest locationRequest = LocationRequest.createFromDeprecatedProvider(NAME, 0, 0,
- false);
+ LocationRequest locationRequest = new LocationRequest.Builder(0).build();
ICancellationSignal cancellationSignal = CancellationSignal.createTransport();
mManager.getCurrentLocation(locationRequest, IDENTITY,
PERMISSION_FINE, cancellationSignal, listener);
@@ -705,8 +679,7 @@ public class LocationProviderManagerTest {
mProvider.setProviderLocation(loc);
ILocationCallback listener = createMockGetCurrentLocationListener();
- LocationRequest locationRequest = LocationRequest.createFromDeprecatedProvider(NAME, 0, 0,
- false);
+ LocationRequest locationRequest = new LocationRequest.Builder(0).build();
ICancellationSignal cancellationSignal = CancellationSignal.createTransport();
mManager.getCurrentLocation(locationRequest, IDENTITY,
PERMISSION_FINE, cancellationSignal, listener);
@@ -718,8 +691,7 @@ public class LocationProviderManagerTest {
@Test
public void testGetCurrentLocation_Timeout() throws Exception {
ILocationCallback listener = createMockGetCurrentLocationListener();
- LocationRequest locationRequest = LocationRequest.createFromDeprecatedProvider(NAME, 0, 0,
- false);
+ LocationRequest locationRequest = new LocationRequest.Builder(0).build();
ICancellationSignal cancellationSignal = CancellationSignal.createTransport();
mManager.getCurrentLocation(locationRequest, IDENTITY,
PERMISSION_FINE, cancellationSignal, listener);
@@ -742,7 +714,7 @@ public class LocationProviderManagerTest {
IDENTITY.getPackageName())).isFalse();
ILocationListener listener = createMockLocationListener();
- LocationRequest request = LocationRequest.createFromDeprecatedProvider(NAME, 0, 0, false);
+ LocationRequest request = new LocationRequest.Builder(0).build();
mManager.registerLocationRequest(request, IDENTITY, PERMISSION_FINE, listener);
assertThat(mInjector.getAppOpsHelper().isAppOpStarted(OP_MONITOR_LOCATION,
@@ -771,7 +743,7 @@ public class LocationProviderManagerTest {
assertThat(mProvider.getRequest().locationRequests).isEmpty();
ILocationListener listener1 = createMockLocationListener();
- LocationRequest request1 = LocationRequest.createFromDeprecatedProvider(NAME, 5, 0, false);
+ LocationRequest request1 = new LocationRequest.Builder(5).build();
mManager.registerLocationRequest(request1, IDENTITY, PERMISSION_FINE, listener1);
assertThat(mProvider.getRequest().reportLocation).isTrue();
@@ -782,8 +754,7 @@ public class LocationProviderManagerTest {
assertThat(mProvider.getRequest().workSource).isNotNull();
ILocationListener listener2 = createMockLocationListener();
- LocationRequest request2 = LocationRequest.createFromDeprecatedProvider(NAME, 1, 0,
- false).setLowPowerMode(true);
+ LocationRequest request2 = new LocationRequest.Builder(1).setLowPower(true).build();
mManager.registerLocationRequest(request2, IDENTITY, PERMISSION_FINE, listener2);
assertThat(mProvider.getRequest().reportLocation).isTrue();
@@ -811,7 +782,7 @@ public class LocationProviderManagerTest {
@Test
public void testProviderRequest_BackgroundThrottle() {
ILocationListener listener1 = createMockLocationListener();
- LocationRequest request1 = LocationRequest.createFromDeprecatedProvider(NAME, 5, 0, false);
+ LocationRequest request1 = new LocationRequest.Builder(5).build();
mManager.registerLocationRequest(request1, IDENTITY, PERMISSION_FINE, listener1);
assertThat(mProvider.getRequest().interval).isEqualTo(5);
@@ -827,7 +798,7 @@ public class LocationProviderManagerTest {
Collections.singleton(IDENTITY.getPackageName()));
ILocationListener listener1 = createMockLocationListener();
- LocationRequest request1 = LocationRequest.createFromDeprecatedProvider(NAME, 5, 0, false);
+ LocationRequest request1 = new LocationRequest.Builder(5).build();
mManager.registerLocationRequest(request1, IDENTITY, PERMISSION_FINE, listener1);
assertThat(mProvider.getRequest().reportLocation).isTrue();
@@ -835,8 +806,8 @@ public class LocationProviderManagerTest {
assertThat(mProvider.getRequest().locationSettingsIgnored).isFalse();
ILocationListener listener2 = createMockLocationListener();
- LocationRequest request2 = LocationRequest.createFromDeprecatedProvider(NAME, 1, 0,
- false).setLocationSettingsIgnored(true);
+ LocationRequest request2 = new LocationRequest.Builder(1).setLocationSettingsIgnored(
+ true).build();
mManager.registerLocationRequest(request2, IDENTITY, PERMISSION_FINE, listener2);
assertThat(mProvider.getRequest().reportLocation).isTrue();
@@ -850,12 +821,12 @@ public class LocationProviderManagerTest {
Collections.singleton(IDENTITY.getPackageName()));
ILocationListener listener1 = createMockLocationListener();
- LocationRequest request1 = LocationRequest.createFromDeprecatedProvider(NAME, 1, 0, false);
+ LocationRequest request1 = new LocationRequest.Builder(1).build();
mManager.registerLocationRequest(request1, IDENTITY, PERMISSION_FINE, listener1);
ILocationListener listener2 = createMockLocationListener();
- LocationRequest request2 = LocationRequest.createFromDeprecatedProvider(NAME, 5, 0,
- false).setLocationSettingsIgnored(true);
+ LocationRequest request2 = new LocationRequest.Builder(5).setLocationSettingsIgnored(
+ true).build();
mManager.registerLocationRequest(request2, IDENTITY, PERMISSION_FINE, listener2);
mInjector.getSettingsHelper().setLocationEnabled(false, IDENTITY.getUserId());
@@ -872,8 +843,8 @@ public class LocationProviderManagerTest {
Collections.singleton(IDENTITY.getPackageName()));
ILocationListener listener = createMockLocationListener();
- LocationRequest request = LocationRequest.createFromDeprecatedProvider(NAME, 1, 0,
- false).setLocationSettingsIgnored(true);
+ LocationRequest request = new LocationRequest.Builder(1).setLocationSettingsIgnored(
+ true).build();
mManager.registerLocationRequest(request, IDENTITY, PERMISSION_FINE, listener);
mInjector.getSettingsHelper().setIgnoreSettingsPackageWhitelist(Collections.emptySet());
@@ -889,8 +860,8 @@ public class LocationProviderManagerTest {
Collections.singleton(IDENTITY.getPackageName()));
ILocationListener listener1 = createMockLocationListener();
- LocationRequest request1 = LocationRequest.createFromDeprecatedProvider(NAME, 5, 0,
- false).setLocationSettingsIgnored(true);
+ LocationRequest request1 = new LocationRequest.Builder(5).setLocationSettingsIgnored(
+ true).build();
mManager.registerLocationRequest(request1, IDENTITY, PERMISSION_FINE, listener1);
assertThat(mProvider.getRequest().interval).isEqualTo(5);
@@ -905,7 +876,7 @@ public class LocationProviderManagerTest {
LOCATION_MODE_THROTTLE_REQUESTS_WHEN_SCREEN_OFF);
ILocationListener listener = createMockLocationListener();
- LocationRequest request = LocationRequest.createFromDeprecatedProvider(NAME, 5, 0, false);
+ LocationRequest request = new LocationRequest.Builder(5).build();
mManager.registerLocationRequest(request, IDENTITY, PERMISSION_FINE, listener);
assertThat(mProvider.getRequest().reportLocation).isTrue();
diff --git a/services/tests/mockingservicestests/src/com/android/server/location/listeners/ListenerMultiplexerTest.java b/services/tests/mockingservicestests/src/com/android/server/location/listeners/ListenerMultiplexerTest.java
index 69a9f4415fe7..0b5a6998cd0d 100644
--- a/services/tests/mockingservicestests/src/com/android/server/location/listeners/ListenerMultiplexerTest.java
+++ b/services/tests/mockingservicestests/src/com/android/server/location/listeners/ListenerMultiplexerTest.java
@@ -43,7 +43,6 @@ import org.mockito.InOrder;
import java.util.Collection;
import java.util.function.Consumer;
-import java.util.function.Predicate;
@SuppressWarnings("unchecked")
@Presubmit
@@ -355,10 +354,6 @@ public class ListenerMultiplexerTest {
removeRegistration(consumer, registration);
}
- public void removeListenerIf(Predicate<Consumer<TestListenerRegistration>> predicate) {
- removeRegistrationIf(predicate);
- }
-
public void setActive(Integer request, boolean active) {
updateRegistrations(testRegistration -> {
if (testRegistration.getRequest().equals(request)) {
diff --git a/services/tests/servicestests/src/com/android/server/devicepolicy/DevicePolicyManagerTest.java b/services/tests/servicestests/src/com/android/server/devicepolicy/DevicePolicyManagerTest.java
index e6fc792c6a9d..3a8d9c3e9ff5 100644
--- a/services/tests/servicestests/src/com/android/server/devicepolicy/DevicePolicyManagerTest.java
+++ b/services/tests/servicestests/src/com/android/server/devicepolicy/DevicePolicyManagerTest.java
@@ -1664,7 +1664,7 @@ public class DevicePolicyManagerTest extends DpmTestBase {
final String nonExistAppRestrictionsManagerPackage = "com.google.app.restrictions.manager2";
final String appRestrictionsManagerPackage = "com.google.app.restrictions.manager";
final String nonDelegateExceptionMessageRegex =
- "Caller with uid \\d+ is not a delegate of scope delegation-app-restrictions.";
+ "Caller with uid \\d+ is not com.google.app.restrictions.manager";
final int appRestrictionsManagerAppId = 20987;
final int appRestrictionsManagerUid = setupPackageInPackageManager(
appRestrictionsManagerPackage, appRestrictionsManagerAppId);
@@ -1676,7 +1676,7 @@ public class DevicePolicyManagerTest extends DpmTestBase {
assertFalse(dpm.isCallerApplicationRestrictionsManagingPackage());
final Bundle rest = new Bundle();
rest.putString("KEY_STRING", "Foo1");
- assertExpectException(SecurityException.class, nonDelegateExceptionMessageRegex,
+ assertExpectException(SecurityException.class, INVALID_CALLING_IDENTITY_MSG,
() -> dpm.setApplicationRestrictions(null, "pkg1", rest));
// Check via the profile owner that no restrictions were set.
@@ -1725,7 +1725,7 @@ public class DevicePolicyManagerTest extends DpmTestBase {
mContext.binder.callingUid = appRestrictionsManagerUid;
mContext.packageName = appRestrictionsManagerPackage;
assertFalse(dpm.isCallerApplicationRestrictionsManagingPackage());
- assertExpectException(SecurityException.class, nonDelegateExceptionMessageRegex,
+ assertExpectException(SecurityException.class, INVALID_CALLING_IDENTITY_MSG,
() -> dpm.setApplicationRestrictions(null, "pkg1", null));
}
@@ -2355,13 +2355,13 @@ public class DevicePolicyManagerTest extends DpmTestBase {
// Test 2. Caller has DA, but not DO.
assertExpectException(SecurityException.class,
- /* messageRegex= */ NOT_ORG_OWNED_PROFILE_OWNER_MSG,
+ /* messageRegex= */ INVALID_CALLING_IDENTITY_MSG,
() -> dpm.getWifiMacAddress(admin1));
// Test 3. Caller has PO, but not DO.
assertTrue(dpm.setProfileOwner(admin1, null, UserHandle.USER_SYSTEM));
assertExpectException(SecurityException.class,
- /* messageRegex= */ NOT_ORG_OWNED_PROFILE_OWNER_MSG,
+ /* messageRegex= */ INVALID_CALLING_IDENTITY_MSG,
() -> dpm.getWifiMacAddress(admin1));
// Remove PO.
@@ -2878,7 +2878,7 @@ public class DevicePolicyManagerTest extends DpmTestBase {
private void setupProfileOwnerOnUser0() throws Exception {
mContext.callerPermissions.addAll(OWNER_SETUP_PERMISSIONS);
- setUpPackageManagerForAdmin(admin1, DpmMockContext.CALLER_SYSTEM_USER_UID);
+ setUpPackageManagerForAdmin(admin1, DpmMockContext.SYSTEM_UID);
dpm.setActiveAdmin(admin1, false);
assertTrue(dpm.setProfileOwner(admin1, null, UserHandle.USER_SYSTEM));
@@ -3929,7 +3929,7 @@ public class DevicePolicyManagerTest extends DpmTestBase {
}
public void testSetAutoTimeEnabledWithPOOnUser0() throws Exception {
- mContext.binder.callingUid = DpmMockContext.CALLER_SYSTEM_USER_UID;
+ mContext.binder.callingUid = DpmMockContext.SYSTEM_UID;
setupProfileOwnerOnUser0();
dpm.setAutoTimeEnabled(admin1, true);
verify(getServices().settings).settingsGlobalPutInt(Settings.Global.AUTO_TIME, 1);
@@ -3967,7 +3967,7 @@ public class DevicePolicyManagerTest extends DpmTestBase {
}
public void testSetAutoTimeZoneEnabledWithPOOnUser0() throws Exception {
- mContext.binder.callingUid = DpmMockContext.CALLER_SYSTEM_USER_UID;
+ mContext.binder.callingUid = DpmMockContext.SYSTEM_UID;
setupProfileOwnerOnUser0();
dpm.setAutoTimeZoneEnabled(admin1, true);
verify(getServices().settings).settingsGlobalPutInt(Settings.Global.AUTO_TIME_ZONE, 1);
@@ -4392,6 +4392,16 @@ public class DevicePolicyManagerTest extends DpmTestBase {
public void testSecondaryLockscreen_nonSupervisionApp() throws Exception {
mContext.binder.callingUid = DpmMockContext.CALLER_UID;
+ // Ensure packages are *not* flagged as test_only.
+ doReturn(new ApplicationInfo()).when(getServices().ipackageManager).getApplicationInfo(
+ eq(admin1.getPackageName()),
+ anyInt(),
+ eq(CALLER_USER_HANDLE));
+ doReturn(new ApplicationInfo()).when(getServices().ipackageManager).getApplicationInfo(
+ eq(admin2.getPackageName()),
+ anyInt(),
+ eq(CALLER_USER_HANDLE));
+
// Initial state is disabled.
assertFalse(dpm.isSecondaryLockscreenEnabled(UserHandle.of(CALLER_USER_HANDLE)));
@@ -4755,7 +4765,7 @@ public class DevicePolicyManagerTest extends DpmTestBase {
// System can retrieve permission grant state.
mContext.binder.callingUid = DpmMockContext.SYSTEM_UID;
- mContext.packageName = "com.example.system";
+ mContext.packageName = "android";
assertEquals(DevicePolicyManager.PERMISSION_GRANT_STATE_GRANTED,
dpm.getPermissionGrantState(null, app1, permission));
assertEquals(DevicePolicyManager.PERMISSION_GRANT_STATE_DEFAULT,
@@ -5716,18 +5726,18 @@ public class DevicePolicyManagerTest extends DpmTestBase {
configureContextForAccess(mContext, false);
// Device owner should be allowed to request Device ID attestation.
- dpms.enforceCallerCanRequestDeviceIdAttestation(admin1, admin1.getPackageName(),
- DpmMockContext.CALLER_SYSTEM_USER_UID);
+ dpms.enforceCallerCanRequestDeviceIdAttestation(dpms.getCallerIdentity(admin1));
// Another package must not be allowed to request Device ID attestation.
assertExpectException(SecurityException.class, null,
- () -> dpms.enforceCallerCanRequestDeviceIdAttestation(null,
- admin2.getPackageName(), DpmMockContext.CALLER_UID));
+ () -> dpms.enforceCallerCanRequestDeviceIdAttestation(
+ dpms.getCallerIdentity(null, admin2.getPackageName())));
+
// Another component that is not the admin must not be allowed to request Device ID
// attestation.
assertExpectException(SecurityException.class, null,
- () -> dpms.enforceCallerCanRequestDeviceIdAttestation(admin2,
- admin1.getPackageName(), DpmMockContext.CALLER_UID));
+ () -> dpms.enforceCallerCanRequestDeviceIdAttestation(
+ dpms.getCallerIdentity(admin2)));
}
public void testEnforceCallerCanRequestDeviceIdAttestation_profileOwnerCaller()
@@ -5736,24 +5746,25 @@ public class DevicePolicyManagerTest extends DpmTestBase {
// Make sure a security exception is thrown if the device has no profile owner.
assertExpectException(SecurityException.class, null,
- () -> dpms.enforceCallerCanRequestDeviceIdAttestation(admin1,
- admin1.getPackageName(), DpmMockContext.CALLER_SYSTEM_USER_UID));
+ () -> dpms.enforceCallerCanRequestDeviceIdAttestation(
+ dpms.getCallerIdentity(admin1)));
setupProfileOwner();
configureProfileOwnerOfOrgOwnedDevice(admin1, CALLER_USER_HANDLE);
// The profile owner is allowed to request Device ID attestation.
mServiceContext.binder.callingUid = DpmMockContext.CALLER_UID;
- dpms.enforceCallerCanRequestDeviceIdAttestation(admin1, admin1.getPackageName(),
- DpmMockContext.CALLER_UID);
+ dpms.enforceCallerCanRequestDeviceIdAttestation(dpms.getCallerIdentity(admin1));
+
// But not another package.
assertExpectException(SecurityException.class, null,
- () -> dpms.enforceCallerCanRequestDeviceIdAttestation(null,
- admin2.getPackageName(), DpmMockContext.CALLER_UID));
+ () -> dpms.enforceCallerCanRequestDeviceIdAttestation(
+ dpms.getCallerIdentity(null, admin2.getPackageName())));
+
// Or another component which is not the admin.
assertExpectException(SecurityException.class, null,
- () -> dpms.enforceCallerCanRequestDeviceIdAttestation(admin2,
- admin2.getPackageName(), DpmMockContext.CALLER_UID));
+ () -> dpms.enforceCallerCanRequestDeviceIdAttestation(
+ dpms.getCallerIdentity(admin2, admin2.getPackageName())));
}
public void runAsDelegatedCertInstaller(DpmRunnable action) throws Exception {
@@ -5781,15 +5792,10 @@ public class DevicePolicyManagerTest extends DpmTestBase {
// Make sure that the profile owner can still request Device ID attestation.
mServiceContext.binder.callingUid = DpmMockContext.CALLER_UID;
- dpms.enforceCallerCanRequestDeviceIdAttestation(admin1, admin1.getPackageName(),
- DpmMockContext.CALLER_UID);
+ dpms.enforceCallerCanRequestDeviceIdAttestation(dpms.getCallerIdentity(admin1));
- runAsDelegatedCertInstaller(dpm -> {
- dpms.enforceCallerCanRequestDeviceIdAttestation(null,
- DpmMockContext.DELEGATE_PACKAGE_NAME,
- UserHandle.getUid(CALLER_USER_HANDLE,
- DpmMockContext.DELEGATE_CERT_INSTALLER_UID));
- });
+ runAsDelegatedCertInstaller(dpm -> dpms.enforceCallerCanRequestDeviceIdAttestation(
+ dpms.getCallerIdentity(null, DpmMockContext.DELEGATE_PACKAGE_NAME)));
}
public void testEnforceCallerCanRequestDeviceIdAttestation_delegateCallerWithoutPermissions()
@@ -5802,18 +5808,14 @@ public class DevicePolicyManagerTest extends DpmTestBase {
dpm -> dpm.setDelegatedScopes(admin1, DpmMockContext.DELEGATE_PACKAGE_NAME,
Arrays.asList(DELEGATION_CERT_INSTALL)));
-
assertExpectException(SecurityException.class, null,
- () -> dpms.enforceCallerCanRequestDeviceIdAttestation(admin1,
- admin1.getPackageName(),
- DpmMockContext.CALLER_UID));
+ () -> dpms.enforceCallerCanRequestDeviceIdAttestation(
+ dpms.getCallerIdentity(admin1)));
runAsDelegatedCertInstaller(dpm -> {
assertExpectException(SecurityException.class, /* messageRegex= */ null,
- () -> dpms.enforceCallerCanRequestDeviceIdAttestation(null,
- DpmMockContext.DELEGATE_PACKAGE_NAME,
- UserHandle.getUid(CALLER_USER_HANDLE,
- DpmMockContext.DELEGATE_CERT_INSTALLER_UID)));
+ () -> dpms.enforceCallerCanRequestDeviceIdAttestation(
+ dpms.getCallerIdentity(null, DpmMockContext.DELEGATE_PACKAGE_NAME)));
});
}
diff --git a/services/tests/servicestests/src/com/android/server/hdmi/HdmiUtilsTest.java b/services/tests/servicestests/src/com/android/server/hdmi/HdmiUtilsTest.java
index f72dbf6ed0b0..d8f5c4c8f58c 100644
--- a/services/tests/servicestests/src/com/android/server/hdmi/HdmiUtilsTest.java
+++ b/services/tests/servicestests/src/com/android/server/hdmi/HdmiUtilsTest.java
@@ -17,6 +17,9 @@ package com.android.server.hdmi;
import static com.google.common.truth.Truth.assertThat;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertTrue;
+
import android.platform.test.annotations.Presubmit;
import android.util.Slog;
@@ -145,4 +148,91 @@ public class HdmiUtilsTest {
assertThat(config).isEqualTo(expectedConfig);
}
+
+ @Test
+ public void isAffectingActiveRoutingPath() {
+ // New path alters the parent
+ assertTrue(HdmiUtils.isAffectingActiveRoutingPath(0x1100, 0x2000));
+ // New path is a sibling
+ assertTrue(HdmiUtils.isAffectingActiveRoutingPath(0x1100, 0x1200));
+ // New path is the descendant of a sibling
+ assertFalse(HdmiUtils.isAffectingActiveRoutingPath(0x1100, 0x1210));
+ // In a completely different path
+ assertFalse(HdmiUtils.isAffectingActiveRoutingPath(0x1000, 0x3200));
+ }
+
+ @Test
+ public void isInActiveRoutingPath() {
+ // New path is a parent
+ assertTrue(HdmiUtils.isInActiveRoutingPath(0x1100, 0x1000));
+ // New path is a descendant
+ assertTrue(HdmiUtils.isInActiveRoutingPath(0x1210, 0x1212));
+ // New path is a sibling
+ assertFalse(HdmiUtils.isInActiveRoutingPath(0x1100, 0x1200));
+ // In a completely different path
+ assertFalse(HdmiUtils.isInActiveRoutingPath(0x1000, 0x2000));
+ }
+
+ @Test
+ public void pathRelationship_unknown() {
+ assertThat(HdmiUtils.pathRelationship(0x1234, Constants.INVALID_PHYSICAL_ADDRESS))
+ .isEqualTo(Constants.PATH_RELATIONSHIP_UNKNOWN);
+ assertThat(HdmiUtils.pathRelationship(Constants.INVALID_PHYSICAL_ADDRESS, 0x1234))
+ .isEqualTo(Constants.PATH_RELATIONSHIP_UNKNOWN);
+ assertThat(HdmiUtils.pathRelationship(Constants.INVALID_PHYSICAL_ADDRESS,
+ Constants.INVALID_PHYSICAL_ADDRESS))
+ .isEqualTo(Constants.PATH_RELATIONSHIP_UNKNOWN);
+ }
+
+ @Test
+ public void pathRelationship_differentBranch() {
+ assertThat(HdmiUtils.pathRelationship(0x1200, 0x2000))
+ .isEqualTo(Constants.PATH_RELATIONSHIP_DIFFERENT_BRANCH);
+ assertThat(HdmiUtils.pathRelationship(0x1234, 0x1224))
+ .isEqualTo(Constants.PATH_RELATIONSHIP_DIFFERENT_BRANCH);
+ assertThat(HdmiUtils.pathRelationship(0x1234, 0x1134))
+ .isEqualTo(Constants.PATH_RELATIONSHIP_DIFFERENT_BRANCH);
+ assertThat(HdmiUtils.pathRelationship(0x1234, 0x2234))
+ .isEqualTo(Constants.PATH_RELATIONSHIP_DIFFERENT_BRANCH);
+ }
+
+ @Test
+ public void pathRelationship_ancestor() {
+ assertThat(HdmiUtils.pathRelationship(0x0000, 0x1230))
+ .isEqualTo(Constants.PATH_RELATIONSHIP_ANCESTOR);
+ assertThat(HdmiUtils.pathRelationship(0x1000, 0x1230))
+ .isEqualTo(Constants.PATH_RELATIONSHIP_ANCESTOR);
+ assertThat(HdmiUtils.pathRelationship(0x1200, 0x1230))
+ .isEqualTo(Constants.PATH_RELATIONSHIP_ANCESTOR);
+ }
+
+ @Test
+ public void pathRelationship_descendant() {
+ assertThat(HdmiUtils.pathRelationship(0x1230, 0x0000))
+ .isEqualTo(Constants.PATH_RELATIONSHIP_DESCENDANT);
+ assertThat(HdmiUtils.pathRelationship(0x1230, 0x1000))
+ .isEqualTo(Constants.PATH_RELATIONSHIP_DESCENDANT);
+ assertThat(HdmiUtils.pathRelationship(0x1230, 0x1200))
+ .isEqualTo(Constants.PATH_RELATIONSHIP_DESCENDANT);
+ }
+
+ @Test
+ public void pathRelationship_sibling() {
+ assertThat(HdmiUtils.pathRelationship(0x1000, 0x2000))
+ .isEqualTo(Constants.PATH_RELATIONSHIP_SIBLING);
+ assertThat(HdmiUtils.pathRelationship(0x1200, 0x1100))
+ .isEqualTo(Constants.PATH_RELATIONSHIP_SIBLING);
+ assertThat(HdmiUtils.pathRelationship(0x1230, 0x1220))
+ .isEqualTo(Constants.PATH_RELATIONSHIP_SIBLING);
+ assertThat(HdmiUtils.pathRelationship(0x1234, 0x1233))
+ .isEqualTo(Constants.PATH_RELATIONSHIP_SIBLING);
+ }
+
+ @Test
+ public void pathRelationship_same() {
+ assertThat(HdmiUtils.pathRelationship(0x0000, 0x0000))
+ .isEqualTo(Constants.PATH_RELATIONSHIP_SAME);
+ assertThat(HdmiUtils.pathRelationship(0x1234, 0x1234))
+ .isEqualTo(Constants.PATH_RELATIONSHIP_SAME);
+ }
}
diff --git a/services/tests/servicestests/src/com/android/server/pm/PackageInstallerSessionTest.java b/services/tests/servicestests/src/com/android/server/pm/PackageInstallerSessionTest.java
index fe429c8823f8..4a6e11bca613 100644
--- a/services/tests/servicestests/src/com/android/server/pm/PackageInstallerSessionTest.java
+++ b/services/tests/servicestests/src/com/android/server/pm/PackageInstallerSessionTest.java
@@ -176,6 +176,7 @@ public class PackageInstallerSessionTest {
/* stageDir */ mTmpDir,
/* stageCid */ null,
/* files */ null,
+ /* checksums */ null,
/* prepared */ true,
/* committed */ true,
/* destroyed */ staged ? true : false,
diff --git a/services/tests/servicestests/src/com/android/server/pm/UserManagerServiceUserInfoTest.java b/services/tests/servicestests/src/com/android/server/pm/UserManagerServiceUserInfoTest.java
index 66ca839081bc..0ccc02663dc5 100644
--- a/services/tests/servicestests/src/com/android/server/pm/UserManagerServiceUserInfoTest.java
+++ b/services/tests/servicestests/src/com/android/server/pm/UserManagerServiceUserInfoTest.java
@@ -105,7 +105,7 @@ public class UserManagerServiceUserInfoTest {
UserData read = mUserManagerService.readUserLP(
data.info.id, new ByteArrayInputStream(bytes));
- assertUserInfoEquals(data.info, read.info);
+ assertUserInfoEquals(data.info, read.info, /* parcelCopy= */ false);
}
@Test
@@ -123,7 +123,16 @@ public class UserManagerServiceUserInfoTest {
UserInfo read = UserInfo.CREATOR.createFromParcel(in);
in.recycle();
- assertUserInfoEquals(info, read);
+ assertUserInfoEquals(info, read, /* parcelCopy= */ true);
+ }
+
+ @Test
+ public void testCopyConstructor() throws Exception {
+ UserInfo info = createUser();
+
+ UserInfo copy = new UserInfo(info);
+
+ assertUserInfoEquals(info, copy, /* parcelCopy= */ false);
}
@Test
@@ -227,10 +236,11 @@ public class UserManagerServiceUserInfoTest {
user.partial = true;
user.guestToRemove = true;
user.preCreated = true;
+ user.convertedFromPreCreated = true;
return user;
}
- private void assertUserInfoEquals(UserInfo one, UserInfo two) {
+ private void assertUserInfoEquals(UserInfo one, UserInfo two, boolean parcelCopy) {
assertEquals("Id not preserved", one.id, two.id);
assertEquals("Name not preserved", one.name, two.name);
assertEquals("Icon path not preserved", one.iconPath, two.iconPath);
@@ -238,11 +248,17 @@ public class UserManagerServiceUserInfoTest {
assertEquals("UserType not preserved", one.userType, two.userType);
assertEquals("profile group not preserved", one.profileGroupId,
two.profileGroupId);
- assertEquals("restricted profile parent not preseved", one.restrictedProfileParentId,
+ assertEquals("restricted profile parent not preserved", one.restrictedProfileParentId,
two.restrictedProfileParentId);
- assertEquals("profile badge not preseved", one.profileBadge, two.profileBadge);
- assertEquals("partial not preseved", one.partial, two.partial);
- assertEquals("guestToRemove not preseved", one.guestToRemove, two.guestToRemove);
- assertEquals("preCreated not preseved", one.preCreated, two.preCreated);
+ assertEquals("profile badge not preserved", one.profileBadge, two.profileBadge);
+ assertEquals("partial not preserved", one.partial, two.partial);
+ assertEquals("guestToRemove not preserved", one.guestToRemove, two.guestToRemove);
+ assertEquals("preCreated not preserved", one.preCreated, two.preCreated);
+ if (parcelCopy) {
+ assertFalse("convertedFromPreCreated should not be set", two.convertedFromPreCreated);
+ } else {
+ assertEquals("convertedFromPreCreated not preserved", one.convertedFromPreCreated,
+ two.convertedFromPreCreated);
+ }
}
}
diff --git a/services/tests/wmtests/src/com/android/server/wm/ActivityMetricsLaunchObserverTests.java b/services/tests/wmtests/src/com/android/server/wm/ActivityMetricsLaunchObserverTests.java
index e860f2508983..9be31647cf73 100644
--- a/services/tests/wmtests/src/com/android/server/wm/ActivityMetricsLaunchObserverTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/ActivityMetricsLaunchObserverTests.java
@@ -33,6 +33,8 @@ import static org.mockito.ArgumentMatchers.argThat;
import static org.mockito.ArgumentMatchers.eq;
import static org.mockito.Mockito.timeout;
+import android.app.ActivityOptions;
+import android.app.ActivityOptions.SourceInfo;
import android.content.Intent;
import android.os.SystemClock;
import android.platform.test.annotations.Presubmit;
@@ -68,6 +70,7 @@ public class ActivityMetricsLaunchObserverTests extends WindowTestsBase {
private ActivityRecord mTrampolineActivity;
private ActivityRecord mTopActivity;
+ private ActivityOptions mActivityOptions;
private boolean mLaunchTopByTrampoline;
@Before
@@ -209,6 +212,8 @@ public class ActivityMetricsLaunchObserverTests extends WindowTestsBase {
@Test
public void testOnReportFullyDrawn() {
+ mActivityOptions = ActivityOptions.makeBasic();
+ mActivityOptions.setSourceInfo(SourceInfo.TYPE_LAUNCHER, SystemClock.uptimeMillis() - 10);
onActivityLaunched(mTopActivity);
// The activity reports fully drawn before windows drawn, then the fully drawn event will
@@ -216,7 +221,10 @@ public class ActivityMetricsLaunchObserverTests extends WindowTestsBase {
mActivityMetricsLogger.logAppTransitionReportedDrawn(mTopActivity, false);
notifyTransitionStarting(mTopActivity);
// The pending fully drawn event should send when the actual windows drawn event occurs.
- notifyWindowsDrawn(mTopActivity);
+ final ActivityMetricsLogger.TransitionInfoSnapshot info = notifyWindowsDrawn(mTopActivity);
+ assertWithMessage("Record start source").that(info.sourceType)
+ .isEqualTo(SourceInfo.TYPE_LAUNCHER);
+ assertWithMessage("Record event time").that(info.sourceEventDelayMs).isAtLeast(10);
verifyAsync(mLaunchObserver).onReportFullyDrawn(eqProto(mTopActivity), anyLong());
verifyOnActivityLaunchFinished(mTopActivity);
@@ -251,7 +259,8 @@ public class ActivityMetricsLaunchObserverTests extends WindowTestsBase {
}
private void notifyActivityLaunched(int resultCode, ActivityRecord activity) {
- mActivityMetricsLogger.notifyActivityLaunched(mLaunchingState, resultCode, activity);
+ mActivityMetricsLogger.notifyActivityLaunched(mLaunchingState, resultCode, activity,
+ mActivityOptions);
}
private void notifyTransitionStarting(ActivityRecord activity) {
@@ -260,8 +269,8 @@ public class ActivityMetricsLaunchObserverTests extends WindowTestsBase {
mActivityMetricsLogger.notifyTransitionStarting(reasons);
}
- private void notifyWindowsDrawn(ActivityRecord r) {
- mActivityMetricsLogger.notifyWindowsDrawn(r, SystemClock.elapsedRealtimeNanos());
+ private ActivityMetricsLogger.TransitionInfoSnapshot notifyWindowsDrawn(ActivityRecord r) {
+ return mActivityMetricsLogger.notifyWindowsDrawn(r, SystemClock.elapsedRealtimeNanos());
}
@Test
diff --git a/telephony/java/android/telephony/CarrierConfigManager.java b/telephony/java/android/telephony/CarrierConfigManager.java
index 470d4bec4c38..4de1abfee7fc 100755
--- a/telephony/java/android/telephony/CarrierConfigManager.java
+++ b/telephony/java/android/telephony/CarrierConfigManager.java
@@ -2743,32 +2743,27 @@ public class CarrierConfigManager {
/**
* Indicates if the carrier supports auto-upgrading a call to RTT when receiving a call from a
* RTT-supported device.
- * @hide
*/
public static final String KEY_RTT_AUTO_UPGRADE_BOOL = "rtt_auto_upgrade_bool";
/**
* Indicates if the carrier supports RTT during a video call.
- * @hide
*/
public static final String KEY_RTT_SUPPORTED_FOR_VT_BOOL = "rtt_supported_for_vt_bool";
/**
* Indicates if the carrier supports upgrading a voice call to an RTT call during the call.
- * @hide
*/
public static final String KEY_RTT_UPGRADE_SUPPORTED_BOOL = "rtt_upgrade_supported_bool";
/**
* Indicates if the carrier supports downgrading a RTT call to a voice call during the call.
- * @hide
*/
public static final String KEY_RTT_DOWNGRADE_SUPPORTED_BOOL = "rtt_downgrade_supported_bool";
/**
* Indicates if the TTY HCO and VCO options should be hidden in the accessibility menu
* if the device is capable of RTT.
- * @hide
*/
public static final String KEY_HIDE_TTY_HCO_VCO_WITH_RTT_BOOL = "hide_tty_hco_vco_with_rtt";
diff --git a/wifi/java/android/net/wifi/WifiScanner.java b/wifi/java/android/net/wifi/WifiScanner.java
index a68d7e260b6a..41d0857214f3 100644
--- a/wifi/java/android/net/wifi/WifiScanner.java
+++ b/wifi/java/android/net/wifi/WifiScanner.java
@@ -193,8 +193,6 @@ public class WifiScanner {
* @hide
*/
public static boolean isFullBandScan(@WifiBand int bandScanned, boolean excludeDfs) {
- // 5GHz DFS channel is part of 5GHz, mark 5GHz scanned as well.
- if ((bandScanned & WIFI_BAND_5_GHZ_DFS_ONLY) != 0) bandScanned |= WIFI_BAND_5_GHZ;
return (bandScanned | WIFI_BAND_6_GHZ | WIFI_BAND_60_GHZ
| (excludeDfs ? WIFI_BAND_5_GHZ_DFS_ONLY : 0))
== WIFI_BAND_ALL;
diff --git a/wifi/java/android/net/wifi/nl80211/NativeScanResult.java b/wifi/java/android/net/wifi/nl80211/NativeScanResult.java
index 35cf45fe36ed..7a9b34b16058 100644
--- a/wifi/java/android/net/wifi/nl80211/NativeScanResult.java
+++ b/wifi/java/android/net/wifi/nl80211/NativeScanResult.java
@@ -157,7 +157,9 @@ public final class NativeScanResult implements Parcelable {
BSS_CAPABILITY_RADIO_MANAGEMENT,
BSS_CAPABILITY_DSSS_OFDM,
BSS_CAPABILITY_DELAYED_BLOCK_ACK,
- BSS_CAPABILITY_IMMEDIATE_BLOCK_ACK
+ BSS_CAPABILITY_IMMEDIATE_BLOCK_ACK,
+ BSS_CAPABILITY_DMG_ESS,
+ BSS_CAPABILITY_DMG_IBSS
})
public @interface BssCapabilityBits { }