diff options
author | 2020-08-26 19:08:21 -0700 | |
---|---|---|
committer | 2020-09-11 12:29:50 -0700 | |
commit | 757380517baed7274a55a2fa4ef7bfe1cc774fc1 (patch) | |
tree | ca054c428b6b07ce71b8ad52246cb6d961a03da9 | |
parent | 9de9f13ef26dd1f0305040493a396c5a54a8f600 (diff) |
Make LocationRequest a public API
LocationRequest and associated APIs have historically always been
SystemApi, for no real reason. In keeping with the Android-wide push to
clean up API surfaces like this, we make LocationRequest a public API.
Bug: 166692379
Test: manual + presubmits
Change-Id: I6a93fca1a5613c96bf35da158bc542e47864dbff
24 files changed, 1375 insertions, 961 deletions
diff --git a/apex/jobscheduler/service/java/com/android/server/DeviceIdleController.java b/apex/jobscheduler/service/java/com/android/server/DeviceIdleController.java index 6c3398f91db1..17b76a414b46 100644 --- a/apex/jobscheduler/service/java/com/android/server/DeviceIdleController.java +++ b/apex/jobscheduler/service/java/com/android/server/DeviceIdleController.java @@ -2076,11 +2076,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/api/current.txt b/api/current.txt index a1629f1a937e..5c5657b60e86 100644 --- a/api/current.txt +++ b/api/current.txt @@ -23914,6 +23914,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(); @@ -23948,6 +23949,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); @@ -23991,6 +23994,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); } diff --git a/api/system-current.txt b/api/system-current.txt index 62503d73defa..e0fd50ea11b6 100755 --- a/api/system-current.txt +++ b/api/system-current.txt @@ -4074,7 +4074,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); @@ -4085,9 +4085,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); @@ -4096,42 +4096,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 2dd740924275..84eded69048a 100644 --- a/api/test-current.txt +++ b/api/test-current.txt @@ -1687,45 +1687,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/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 6fc702e4a068..c0d17c1fa824 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/non-updatable-api/current.txt b/non-updatable-api/current.txt index e1b3151acd5b..71d9e8d45404 100644 --- a/non-updatable-api/current.txt +++ b/non-updatable-api/current.txt @@ -23896,6 +23896,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(); @@ -23930,6 +23931,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); @@ -23973,6 +23976,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); } diff --git a/non-updatable-api/system-current.txt b/non-updatable-api/system-current.txt index 39ba60c23e7a..e44c4ad064b2 100644 --- a/non-updatable-api/system-current.txt +++ b/non-updatable-api/system-current.txt @@ -4014,7 +4014,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); @@ -4025,9 +4025,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); @@ -4036,42 +4036,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/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/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 3e5b6e3f462f..d2d75d0e3cd0 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; @@ -699,9 +700,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 @@ -715,8 +715,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()) { @@ -734,8 +732,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) { @@ -1954,20 +1952,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/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/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)) { |