Merge "Add getCurrentLocation API to LocationManager"

This commit is contained in:
Soonil Nagarkar
2019-10-18 16:22:25 +00:00
committed by Android (Google) Code Review
6 changed files with 364 additions and 96 deletions

View File

@@ -23148,6 +23148,7 @@ package android.location {
method @Deprecated public void clearTestProviderStatus(@NonNull String);
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 @Nullable public String getGnssHardwareModelName();
method public int getGnssYearOfHardware();
method @Deprecated @Nullable @RequiresPermission(android.Manifest.permission.ACCESS_FINE_LOCATION) public android.location.GpsStatus getGpsStatus(@Nullable android.location.GpsStatus);

View File

@@ -3453,6 +3453,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 @Nullable public String getExtraLocationControllerPackage();
method @RequiresPermission(android.Manifest.permission.LOCATION_HARDWARE) public int getGnssBatchSize();
method @NonNull @RequiresPermission(android.Manifest.permission.ACCESS_FINE_LOCATION) public android.location.GnssCapabilities getGnssCapabilities();

View File

@@ -1123,6 +1123,7 @@ 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 @NonNull public String[] getIgnoreSettingsWhitelist();
method @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);

View File

@@ -31,6 +31,7 @@ import android.location.Location;
import android.location.LocationRequest;
import android.location.LocationTime;
import android.os.Bundle;
import android.os.ICancellationSignal;
import com.android.internal.location.ProviderProperties;
@@ -41,6 +42,11 @@ import com.android.internal.location.ProviderProperties;
*/
interface ILocationManager
{
Location getLastLocation(in LocationRequest request, String packageName);
boolean getCurrentLocation(in LocationRequest request,
in ICancellationSignal cancellationSignal, in ILocationListener listener,
String packageName, String listenerIdentifier);
void requestLocationUpdates(in LocationRequest request, in ILocationListener listener,
in PendingIntent intent, String packageName, String listenerIdentifier);
void removeUpdates(in ILocationListener listener, in PendingIntent intent, String packageName);
@@ -49,8 +55,6 @@ interface ILocationManager
in PendingIntent intent, String packageName, String listenerIdentifier);
void removeGeofence(in Geofence fence, in PendingIntent intent, String packageName);
Location getLastLocation(in LocationRequest request, String packageName);
boolean registerGnssStatusCallback(IGnssStatusListener callback, String packageName);
void unregisterGnssStatusCallback(IGnssStatusListener callback);

View File

@@ -20,6 +20,7 @@ import static android.Manifest.permission.ACCESS_COARSE_LOCATION;
import static android.Manifest.permission.ACCESS_FINE_LOCATION;
import static android.Manifest.permission.LOCATION_HARDWARE;
import static android.Manifest.permission.WRITE_SECURE_SETTINGS;
import static android.app.AlarmManager.ELAPSED_REALTIME;
import android.Manifest;
import android.annotation.CallbackExecutor;
@@ -31,17 +32,21 @@ import android.annotation.SystemApi;
import android.annotation.SystemService;
import android.annotation.TestApi;
import android.annotation.UnsupportedAppUsage;
import android.app.AlarmManager;
import android.app.PendingIntent;
import android.content.Context;
import android.content.pm.PackageManager;
import android.os.Binder;
import android.os.Build;
import android.os.Bundle;
import android.os.CancellationSignal;
import android.os.Handler;
import android.os.HandlerExecutor;
import android.os.ICancellationSignal;
import android.os.Looper;
import android.os.Process;
import android.os.RemoteException;
import android.os.SystemClock;
import android.os.UserHandle;
import android.provider.Settings;
import android.util.ArrayMap;
@@ -55,6 +60,7 @@ import java.util.Collections;
import java.util.List;
import java.util.concurrent.Executor;
import java.util.concurrent.RejectedExecutionException;
import java.util.function.Consumer;
/**
* This class provides access to the system location services. These services allow applications to
@@ -77,22 +83,20 @@ public class LocationManager {
/**
* Name of the network location provider.
* <p>This provider determines location based on
* availability of cell tower and WiFi access points. Results are retrieved
* by means of a network lookup.
*
* <p>This provider determines location based on nearby of cell tower and WiFi access points.
* Results are retrieved by means of a network lookup.
*/
public static final String NETWORK_PROVIDER = "network";
/**
* Name of the GPS location provider.
* Name of the GNSS location provider.
*
* <p>This provider determines location using
* satellites. Depending on conditions, this provider may take a while to return
* a location fix. Requires the permission
* {@link android.Manifest.permission#ACCESS_FINE_LOCATION}.
* <p>This provider determines location using GNSS satellites. Depending on conditions, this
* provider may take a while to return a location fix. Requires the
* {@link android.Manifest.permission#ACCESS_FINE_LOCATION} permission.
*
* <p> The extras Bundle for the GPS location provider can contain the
* following key/value pairs:
* <p>The extras Bundle for the GPS location provider can contain the following key/value pairs:
* <ul>
* <li> satellites - the number of satellites used to derive the fix
* </ul>
@@ -100,26 +104,24 @@ public class LocationManager {
public static final String GPS_PROVIDER = "gps";
/**
* A special location provider for receiving locations without actually initiating
* a location fix.
* A special location provider for receiving locations without actually initiating a location
* fix.
*
* <p>This provider can be used to passively receive location updates
* when other applications or services request them without actually requesting
* the locations yourself. This provider will return locations generated by other
* providers. You can query the {@link Location#getProvider()} method to determine
* the origin of the location update. Requires the permission
* {@link android.Manifest.permission#ACCESS_FINE_LOCATION}, although if the GPS is
* not enabled this provider might only return coarse fixes.
* <p>This provider can be used to passively receive location updates when other applications or
* services request them without actually requesting the locations yourself. This provider will
* only return locations generated by other providers. You can query the
* {@link Location#getProvider()} method to determine the actual provider that supplied the
* location update. Requires the {@link android.Manifest.permission#ACCESS_FINE_LOCATION}
* permission, although there is no guarantee of fine locations.
*/
public static final String PASSIVE_PROVIDER = "passive";
/**
* Name of the Fused location provider.
* The fused location provider.
*
* <p>This provider combines inputs for all possible location sources
* to provide the best possible Location fix. It is implicitly
* used for all API's that involve the {@link LocationRequest}
* object.
* <p>This provider combines may combine inputs from several location sources to provide the
* best possible location fix. It is implicitly used for all API's that involve the
* {@link LocationRequest} object.
*
* @hide
*/
@@ -228,6 +230,8 @@ public class LocationManager {
public static final String METADATA_SETTINGS_FOOTER_STRING =
"com.android.settings.location.FOOTER_STRING";
private static final long GET_CURRENT_LOCATION_TIMEOUT_MS = 30 * 1000;
private final Context mContext;
@UnsupportedAppUsage
@@ -522,6 +526,13 @@ public class LocationManager {
* location. The returned location may be quite old in some circumstances, so the age of the
* location should always be checked.
*
* <p>This will never activate sensors to compute a new location, and will only ever return a
* cached location.
*
* <p>See also {@link #getCurrentLocation(String, CancellationSignal, Executor, Consumer)} which
* will always attempt to return a current location, but will potentially use additional power
* in the course of the attempt as compared to this method.
*
* @param provider the name of the provider
* @return the last known location for the given provider, or null if not available
* @throws SecurityException if no suitable permission is present
@@ -550,36 +561,117 @@ public class LocationManager {
* @return A identifying string
*/
private static String getListenerIdentifier(@NonNull Object listener) {
StringBuilder sb = new StringBuilder();
sb.append(listener.getClass().getName());
sb.append('@');
sb.append(Integer.toHexString(System.identityHashCode(listener)));
return sb.toString();
return listener.getClass().getName()
+ '@'
+ Integer.toHexString(System.identityHashCode(listener));
}
/**
* Register for a single location update using the named provider and
* a callback.
* 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>See {@link #requestLocationUpdates(String, long, float, LocationListener, Looper)}
* for more detail on how to use this method.
* <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.
*
* @param provider the name of the provider with which to register
* @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,
@Nullable CancellationSignal cancellationSignal,
@NonNull @CallbackExecutor Executor executor, @NonNull Consumer<Location> consumer) {
getCurrentLocation(LocationRequest.createFromDeprecatedProvider(provider, 0, 0, true),
cancellationSignal, executor, consumer);
}
/**
* Asynchronously returns a single current location fix based on the given
* {@link LocationRequest}.
*
* <p>See {@link #getCurrentLocation(String, 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
* @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
* @hide
*/
@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) {
LocationRequest currentLocationRequest = new LocationRequest(locationRequest)
.setNumUpdates(1).setExpireIn(GET_CURRENT_LOCATION_TIMEOUT_MS);
GetCurrentLocationTransport listenerTransport = new GetCurrentLocationTransport(executor,
consumer);
if (cancellationSignal != null) {
cancellationSignal.throwIfCanceled();
}
ICancellationSignal remoteCancellationSignal = CancellationSignal.createTransport();
try {
if (mService.getCurrentLocation(currentLocationRequest, remoteCancellationSignal,
listenerTransport, mContext.getPackageName(),
getListenerIdentifier(consumer))) {
listenerTransport.register(mContext.getSystemService(AlarmManager.class),
remoteCancellationSignal);
if (cancellationSignal != null) {
cancellationSignal.setOnCancelListener(listenerTransport::cancel);
}
} else {
listenerTransport.fail();
}
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
}
}
/**
* Register for a single location update using the named provider and a callback.
*
* <p>See {@link #requestLocationUpdates(String, long, float, LocationListener, Looper)} for
* more detail on how to use this method.
*
* @param provider the name of the provider with which to register
* @param listener a {@link LocationListener} whose
* {@link LocationListener#onLocationChanged} method will be called when
* the location update is available
* @param looper a Looper object whose message queue will be used to
* implement the callback mechanism, or null to make callbacks on the calling
* thread
* @param listener the listener to receive location updates
* @param looper the looper handling listener callbacks, or null to use the looper of the
* calling thread
*
* @throws IllegalArgumentException if provider is null or doesn't exist
* @throws IllegalArgumentException if listener is null
* @throws SecurityException if no suitable permission is present
* @deprecated This method can drain much more battery than expected if it is not possible to
* calculate location. Prefer any of the requestLocationUpdates() methods which require explicit
* removal.
* @throws SecurityException if no suitable permission is present
* @deprecated Use {@link #getCurrentLocation(String, CancellationSignal, Executor, Consumer)}
* instead as it does not carry a risk of extreme battery drain.
*/
@Deprecated
@RequiresPermission(anyOf = {ACCESS_COARSE_LOCATION, ACCESS_FINE_LOCATION})
@@ -594,27 +686,21 @@ public class LocationManager {
}
/**
* Register for a single location update using a Criteria and
* a callback.
* Register for a single location update using a Criteria and a callback.
*
* <p>See {@link #requestLocationUpdates(long, float, Criteria, PendingIntent)}
* for more detail on how to use this method.
* <p>See {@link #requestLocationUpdates(long, float, Criteria, PendingIntent)} for more detail
* on how to use this method.
*
* @param criteria contains parameters for the location manager to choose the
* appropriate provider and parameters to compute the location
* @param listener a {@link LocationListener} whose
* {@link LocationListener#onLocationChanged} method will be called when
* the location update is available
* @param looper a Looper object whose message queue will be used to
* implement the callback mechanism, or null to make callbacks on the calling
* thread
* @param criteria contains parameters to choose the appropriate provider for location updates
* @param listener the listener to receive location updates
* @param looper the looper handling listener callbacks, or null to use the looper of the
* calling thread
*
* @throws IllegalArgumentException if criteria is null
* @throws IllegalArgumentException if listener is null
* @throws SecurityException if no suitable permission is present
* @deprecated This method can drain much more battery than expected if it is not possible to
* calculate location. Prefer any of the requestLocationUpdates() methods which require explicit
* removal.
* @throws SecurityException if no suitable permission is present
* @deprecated Use {@link #getCurrentLocation(String, CancellationSignal, Executor, Consumer)}
* instead as it does not carry a risk of extreme battery drain.
*/
@RequiresPermission(anyOf = {ACCESS_COARSE_LOCATION, ACCESS_FINE_LOCATION})
public void requestSingleUpdate(
@@ -632,54 +718,54 @@ public class LocationManager {
/**
* Register for a single location update using a named provider and pending intent.
*
* <p>See {@link #requestLocationUpdates(long, float, Criteria, PendingIntent)}
* for more detail on how to use this method.
* <p>See {@link #requestLocationUpdates(long, float, Criteria, PendingIntent)} for more detail
* on how to use this method.
*
* @param provider the name of the provider with which to register
* @param intent a {@link PendingIntent} to be sent for the location update
* @param provider the name of the provider with which to register
* @param pendingIntent the pending intent to send location updates
*
* @throws IllegalArgumentException if provider is null or doesn't exist
* @throws IllegalArgumentException if intent is null
* @throws SecurityException if no suitable permission is present
* @deprecated This method can drain much more battery than expected if it is not possible to
* calculate location. Prefer any of the requestLocationUpdates() methods which require explicit
* removal.
* @throws SecurityException if no suitable permission is present
* @deprecated Use {@link #getCurrentLocation(String, CancellationSignal, Executor, Consumer)}
* instead as it does not carry a risk of extreme battery drain.
*/
@RequiresPermission(anyOf = {ACCESS_COARSE_LOCATION, ACCESS_FINE_LOCATION})
public void requestSingleUpdate(@NonNull String provider, @NonNull PendingIntent intent) {
public void requestSingleUpdate(@NonNull String provider,
@NonNull PendingIntent pendingIntent) {
Preconditions.checkArgument(provider != null, "invalid null provider");
checkPendingIntent(intent);
checkPendingIntent(pendingIntent);
LocationRequest request = LocationRequest.createFromDeprecatedProvider(
provider, 0, 0, true);
requestLocationUpdates(request, intent);
requestLocationUpdates(request, pendingIntent);
}
/**
* Register for a single location update using a Criteria and pending intent.
*
* <p>See {@link #requestLocationUpdates(long, float, Criteria, PendingIntent)}
* for more detail on how to use this method.
* <p>See {@link #requestLocationUpdates(long, float, Criteria, PendingIntent)} for more detail
* on how to use this method.
*
* @param criteria contains parameters for the location manager to choose the
* appropriate provider and parameters to compute the location
* @param intent a {@link PendingIntent} to be sent for the location update
* @param criteria contains parameters to choose the appropriate provider for location
* updates
* @param pendingIntent the pending intent to send location updates
*
* @throws IllegalArgumentException if provider is null or doesn't exist
* @throws IllegalArgumentException if intent is null
* @throws SecurityException if no suitable permission is present
* @deprecated This method can drain much more battery than expected if it is not possible to
* calculate location. Prefer any of the requestLocationUpdates() methods which require explicit
* removal.
* @throws SecurityException if no suitable permission is present
* @deprecated Use {@link #getCurrentLocation(String, CancellationSignal, Executor, Consumer)}
* instead as it does not carry a risk of extreme battery drain.
*/
@RequiresPermission(anyOf = {ACCESS_COARSE_LOCATION, ACCESS_FINE_LOCATION})
public void requestSingleUpdate(@NonNull Criteria criteria, @NonNull PendingIntent intent) {
public void requestSingleUpdate(@NonNull Criteria criteria,
@NonNull PendingIntent pendingIntent) {
Preconditions.checkArgument(criteria != null, "invalid null criteria");
checkPendingIntent(intent);
checkPendingIntent(pendingIntent);
LocationRequest request = LocationRequest.createFromDeprecatedCriteria(
criteria, 0, 0, true);
requestLocationUpdates(request, intent);
requestLocationUpdates(request, pendingIntent);
}
/**
@@ -2295,6 +2381,127 @@ public class LocationManager {
}
}
private static class GetCurrentLocationTransport extends ILocationListener.Stub implements
AlarmManager.OnAlarmListener {
@GuardedBy("this")
@Nullable
private Executor mExecutor;
@GuardedBy("this")
@Nullable
private Consumer<Location> mConsumer;
@GuardedBy("this")
@Nullable
private AlarmManager mAlarmManager;
@GuardedBy("this")
@Nullable
private ICancellationSignal mRemoteCancellationSignal;
private GetCurrentLocationTransport(Executor executor, Consumer<Location> consumer) {
Preconditions.checkArgument(executor != null, "illegal null executor");
Preconditions.checkArgument(consumer != null, "illegal null consumer");
mExecutor = executor;
mConsumer = consumer;
mAlarmManager = null;
mRemoteCancellationSignal = null;
}
public synchronized void register(AlarmManager alarmManager,
ICancellationSignal remoteCancellationSignal) {
if (mConsumer == null) {
return;
}
mAlarmManager = alarmManager;
mAlarmManager.set(
ELAPSED_REALTIME,
SystemClock.elapsedRealtime() + GET_CURRENT_LOCATION_TIMEOUT_MS,
"GetCurrentLocation",
this,
null);
mRemoteCancellationSignal = remoteCancellationSignal;
}
public synchronized void cancel() {
mExecutor = null;
mConsumer = null;
if (mAlarmManager != null) {
mAlarmManager.cancel(this);
mAlarmManager = null;
}
if (mRemoteCancellationSignal != null) {
try {
mRemoteCancellationSignal.cancel();
} catch (RemoteException e) {
// ignore
}
mRemoteCancellationSignal = null;
}
}
public void fail() {
deliverResult(null);
}
@Override
public void onAlarm() {
synchronized (this) {
// save ourselves a pointless x-process call to cancel the alarm
mAlarmManager = null;
}
deliverResult(null);
}
@Override
public void onLocationChanged(Location location) {
synchronized (this) {
// save ourselves a pointless x-process call to cancel the location request
mRemoteCancellationSignal = null;
}
deliverResult(location);
}
@Override
public void onStatusChanged(String provider, int status, Bundle extras) {}
@Override
public void onProviderEnabled(String provider) {}
@Override
public void onProviderDisabled(String provider) {
// in the event of the provider being disabled it is unlikely that we will get further
// locations, so fail early so the client isn't left waiting hopelessly
deliverResult(null);
}
private synchronized void deliverResult(@Nullable Location location) {
if (mExecutor == null) {
return;
}
mExecutor.execute(() -> {
Consumer<Location> consumer;
synchronized (GetCurrentLocationTransport.this) {
if (mConsumer == null) {
return;
}
consumer = mConsumer;
cancel();
}
consumer.accept(location);
});
}
}
private class LocationListenerTransport extends ILocationListener.Stub {
private final LocationListener mListener;

View File

@@ -62,8 +62,10 @@ import android.location.LocationRequest;
import android.location.LocationTime;
import android.os.Binder;
import android.os.Bundle;
import android.os.CancellationSignal;
import android.os.Handler;
import android.os.IBinder;
import android.os.ICancellationSignal;
import android.os.PowerManager;
import android.os.PowerManager.ServiceType;
import android.os.PowerManagerInternal;
@@ -119,6 +121,7 @@ import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import java.util.concurrent.TimeUnit;
/**
* The service class that manages LocationProviders and issues location
@@ -145,11 +148,12 @@ public class LocationManagerService extends ILocationManager.Stub {
private static final String FUSED_LOCATION_SERVICE_ACTION =
"com.android.location.service.FusedLocationProvider";
private static final long NANOS_PER_MILLI = 1000000L;
// The maximum interval a location request can have and still be considered "high power".
private static final long HIGH_POWER_INTERVAL_MS = 5 * 60 * 1000;
// maximum age of a location before it is no longer considered "current"
private static final long MAX_CURRENT_LOCATION_AGE_MS = 10 * 1000;
private static final int FOREGROUND_IMPORTANCE_CUTOFF
= ActivityManager.RunningAppProcessInfo.IMPORTANCE_FOREGROUND_SERVICE;
@@ -2450,8 +2454,8 @@ public class LocationManagerService extends ILocationManager.Stub {
// Don't return stale location to apps with foreground-only location permission.
String op = resolutionLevelToOpStr(allowedResolutionLevel);
long locationAgeMs = SystemClock.elapsedRealtime()
- location.getElapsedRealtimeNanos() / NANOS_PER_MILLI;
long locationAgeMs = TimeUnit.NANOSECONDS.toMillis(
SystemClock.elapsedRealtime() - location.getElapsedRealtimeNanos());
if ((locationAgeMs > Settings.Global.getLong(
mContext.getContentResolver(),
Settings.Global.LOCATION_LAST_LOCATION_MAX_AGE_MILLIS,
@@ -2488,6 +2492,56 @@ public class LocationManagerService extends ILocationManager.Stub {
}
}
@Override
public boolean getCurrentLocation(LocationRequest locationRequest,
ICancellationSignal remoteCancellationSignal, ILocationListener listener,
String packageName, String listenerIdentifier) {
// side effect of validating locationRequest and packageName
Location lastLocation = getLastLocation(locationRequest, packageName);
if (lastLocation != null) {
long locationAgeMs = TimeUnit.NANOSECONDS.toMillis(
SystemClock.elapsedRealtimeNanos() - lastLocation.getElapsedRealtimeNanos());
long identity = Binder.clearCallingIdentity();
try {
if (locationAgeMs < MAX_CURRENT_LOCATION_AGE_MS) {
try {
listener.onLocationChanged(lastLocation);
return true;
} catch (RemoteException e) {
Log.w(TAG, e);
return false;
}
}
// packageName already validated by getLastLocation() call above
boolean foreground = LocationManagerServiceUtils.isImportanceForeground(
mActivityManager.getPackageImportance(packageName));
if (!foreground) {
long backgroundThrottleIntervalMs = Settings.Global.getLong(
mContext.getContentResolver(),
Settings.Global.LOCATION_BACKGROUND_THROTTLE_INTERVAL_MS,
DEFAULT_BACKGROUND_THROTTLE_INTERVAL_MS);
if (locationAgeMs < backgroundThrottleIntervalMs) {
// not allowed to request new locations, so we can't return anything
return false;
}
}
} finally {
Binder.restoreCallingIdentity(identity);
}
}
requestLocationUpdates(locationRequest, listener, null, packageName, listenerIdentifier);
CancellationSignal cancellationSignal = CancellationSignal.fromTransport(
remoteCancellationSignal);
if (cancellationSignal != null) {
cancellationSignal.setOnCancelListener(
() -> removeUpdates(listener, null, packageName));
}
return true;
}
@Override
public LocationTime getGnssTimeMillis() {
synchronized (mLock) {
@@ -2836,9 +2890,9 @@ public class LocationManagerService extends ILocationManager.Stub {
// Check whether sufficient time has passed
long minTime = record.mRealRequest.getFastestInterval();
long delta = (loc.getElapsedRealtimeNanos() - lastLoc.getElapsedRealtimeNanos())
/ NANOS_PER_MILLI;
if (delta < minTime - MAX_PROVIDER_SCHEDULING_JITTER_MS) {
long deltaMs = TimeUnit.NANOSECONDS.toMillis(
loc.getElapsedRealtimeNanos() - lastLoc.getElapsedRealtimeNanos());
if (deltaMs < minTime - MAX_PROVIDER_SCHEDULING_JITTER_MS) {
return false;
}
@@ -2893,9 +2947,9 @@ public class LocationManagerService extends ILocationManager.Stub {
mLastLocationCoarseInterval.put(provider.getName(), lastLocationCoarseInterval);
}
}
long timeDiffNanos = location.getElapsedRealtimeNanos()
- lastLocationCoarseInterval.getElapsedRealtimeNanos();
if (timeDiffNanos > LocationFudger.FASTEST_INTERVAL_MS * NANOS_PER_MILLI) {
long timeDeltaMs = TimeUnit.NANOSECONDS.toMillis(location.getElapsedRealtimeNanos()
- lastLocationCoarseInterval.getElapsedRealtimeNanos());
if (timeDeltaMs > LocationFudger.FASTEST_INTERVAL_MS) {
lastLocationCoarseInterval.set(location);
}
// Don't ever return a coarse location that is more recent than the allowed update