diff options
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 Binary files differnew file mode 100644 index 000000000000..f9777c3f5ca5 --- /dev/null +++ b/core/tests/coretests/assets/SourceStampVerifierTest/stamp-lineage-invalid.apk diff --git a/core/tests/coretests/assets/SourceStampVerifierTest/stamp-lineage-valid.apk b/core/tests/coretests/assets/SourceStampVerifierTest/stamp-lineage-valid.apk Binary files differnew file mode 100644 index 000000000000..955652e387b8 --- /dev/null +++ b/core/tests/coretests/assets/SourceStampVerifierTest/stamp-lineage-valid.apk 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 { } |