Merge "Add getCurrentLocation API to LocationManager"
This commit is contained in:
committed by
Android (Google) Code Review
commit
8eb590bdc7
@@ -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);
|
||||
|
||||
@@ -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();
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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);
|
||||
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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
|
||||
|
||||
Reference in New Issue
Block a user