Merge "Update batching APIs" into sc-dev
This commit is contained in:
committed by
Android (Google) Code Review
commit
df079b7943
@@ -19457,7 +19457,7 @@ package android.location {
|
||||
public interface LocationListener {
|
||||
method public default void onFlushComplete(int);
|
||||
method public void onLocationChanged(@NonNull android.location.Location);
|
||||
method public default void onLocationChanged(@NonNull android.location.LocationResult);
|
||||
method public default void onLocationChanged(@NonNull java.util.List<android.location.Location>);
|
||||
method public default void onProviderDisabled(@NonNull String);
|
||||
method public default void onProviderEnabled(@NonNull String);
|
||||
method @Deprecated public default void onStatusChanged(String, int, android.os.Bundle);
|
||||
@@ -19543,8 +19543,8 @@ package android.location {
|
||||
field public static final String FUSED_PROVIDER = "fused";
|
||||
field public static final String GPS_PROVIDER = "gps";
|
||||
field public static final String KEY_FLUSH_COMPLETE = "flushComplete";
|
||||
field public static final String KEY_LOCATIONS = "locations";
|
||||
field public static final String KEY_LOCATION_CHANGED = "location";
|
||||
field public static final String KEY_LOCATION_RESULT = "locationResult";
|
||||
field public static final String KEY_PROVIDER_ENABLED = "providerEnabled";
|
||||
field public static final String KEY_PROXIMITY_ENTERING = "entering";
|
||||
field @Deprecated public static final String KEY_STATUS_CHANGED = "status";
|
||||
@@ -19602,18 +19602,6 @@ package android.location {
|
||||
method @NonNull public android.location.LocationRequest.Builder setQuality(int);
|
||||
}
|
||||
|
||||
public final class LocationResult implements android.os.Parcelable {
|
||||
method @NonNull public java.util.List<android.location.Location> asList();
|
||||
method @NonNull public static android.location.LocationResult create(@NonNull android.location.Location);
|
||||
method @NonNull public static android.location.LocationResult create(@NonNull java.util.List<android.location.Location>);
|
||||
method public int describeContents();
|
||||
method @NonNull public android.location.Location get(@IntRange(from=0) int);
|
||||
method @NonNull public android.location.Location getLastLocation();
|
||||
method @IntRange(from=1) public int size();
|
||||
method public void writeToParcel(@NonNull android.os.Parcel, int);
|
||||
field @NonNull public static final android.os.Parcelable.Creator<android.location.LocationResult> CREATOR;
|
||||
}
|
||||
|
||||
public interface OnNmeaMessageListener {
|
||||
method public void onNmeaMessage(String, long);
|
||||
}
|
||||
|
||||
@@ -4718,10 +4718,6 @@ package android.location {
|
||||
method @NonNull @RequiresPermission(android.Manifest.permission.UPDATE_DEVICE_STATS) public android.location.LocationRequest.Builder setWorkSource(@Nullable android.os.WorkSource);
|
||||
}
|
||||
|
||||
public final class LocationResult implements android.os.Parcelable {
|
||||
method @NonNull public static android.location.LocationResult wrap(@NonNull android.location.Location);
|
||||
}
|
||||
|
||||
public final class SatellitePvt implements android.os.Parcelable {
|
||||
method public int describeContents();
|
||||
method @NonNull public android.location.SatellitePvt.ClockInfo getClockInfo();
|
||||
@@ -4788,7 +4784,7 @@ package android.location.provider {
|
||||
method public abstract void onSendExtraCommand(@NonNull String, @Nullable android.os.Bundle);
|
||||
method public abstract void onSetRequest(@NonNull android.location.provider.ProviderRequest);
|
||||
method public void reportLocation(@NonNull android.location.Location);
|
||||
method public void reportLocation(@NonNull android.location.LocationResult);
|
||||
method public void reportLocations(@NonNull java.util.List<android.location.Location>);
|
||||
method public void setAllowed(boolean);
|
||||
method public void setProperties(@NonNull android.location.provider.ProviderProperties);
|
||||
field public static final String ACTION_FUSED_PROVIDER = "com.android.location.service.FusedLocationProvider";
|
||||
|
||||
@@ -16,7 +16,7 @@
|
||||
|
||||
package android.location;
|
||||
|
||||
import android.location.LocationResult;
|
||||
import android.location.Location;
|
||||
import android.os.IRemoteCallback;
|
||||
|
||||
/**
|
||||
@@ -24,7 +24,7 @@ import android.os.IRemoteCallback;
|
||||
*/
|
||||
oneway interface ILocationListener
|
||||
{
|
||||
void onLocationChanged(in LocationResult locationResult, in @nullable IRemoteCallback onCompleteCallback);
|
||||
void onLocationChanged(in List<Location> locations, in @nullable IRemoteCallback onCompleteCallback);
|
||||
void onProviderEnabledChanged(String provider, boolean enabled);
|
||||
void onFlushComplete(int requestCode);
|
||||
}
|
||||
|
||||
@@ -19,6 +19,7 @@ package android.location;
|
||||
import android.annotation.NonNull;
|
||||
import android.os.Bundle;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.concurrent.Executor;
|
||||
|
||||
/**
|
||||
@@ -48,15 +49,18 @@ public interface LocationListener {
|
||||
/**
|
||||
* Called when the location has changed and locations are being delivered in batches. The
|
||||
* default implementation calls through to ({@link #onLocationChanged(Location)} with all
|
||||
* locations in the batch, from earliest to latest.
|
||||
* locations in the batch. The list of locations is always guaranteed to be non-empty, and is
|
||||
* always guaranteed to be ordered from earliest location to latest location (so that the
|
||||
* earliest location in the batch is at index 0 in the list, and the latest location in the
|
||||
* batch is at index size-1 in the list).
|
||||
*
|
||||
* @see LocationRequest#getMaxUpdateDelayMillis()
|
||||
* @param locationResult the location result list
|
||||
* @param locations the location list
|
||||
*/
|
||||
default void onLocationChanged(@NonNull LocationResult locationResult) {
|
||||
final int size = locationResult.size();
|
||||
for (int i = 0; i < size; ++i) {
|
||||
onLocationChanged(locationResult.get(i));
|
||||
default void onLocationChanged(@NonNull List<Location> locations) {
|
||||
final int size = locations.size();
|
||||
for (int i = 0; i < size; i++) {
|
||||
onLocationChanged(locations.get(i));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -232,19 +232,26 @@ public class LocationManager {
|
||||
|
||||
/**
|
||||
* Key used for an extra holding a {@link Location} value when a location change is sent using
|
||||
* a PendingIntent.
|
||||
* a PendingIntent. If the location change includes a list of batched locations via
|
||||
* {@link #KEY_LOCATIONS} then this key will still be present, and will hold the last location
|
||||
* in the batch. Use {@link Intent#getParcelableExtra(String)} to retrieve the location.
|
||||
*
|
||||
* @see #requestLocationUpdates(String, LocationRequest, PendingIntent)
|
||||
*/
|
||||
public static final String KEY_LOCATION_CHANGED = "location";
|
||||
|
||||
/**
|
||||
* Key used for an extra holding a {@link LocationResult} value when a location change is sent
|
||||
* using a PendingIntent.
|
||||
* Key used for an extra holding a array of {@link Location}s when a location change is sent
|
||||
* using a PendingIntent. This key will only be present if the location change includes
|
||||
* multiple (ie, batched) locations, otherwise only {@link #KEY_LOCATION_CHANGED} will be
|
||||
* present. Use {@link Intent#getParcelableArrayExtra(String)} to retrieve the locations.
|
||||
*
|
||||
* <p>The array of locations will never be empty, and will ordered from earliest location to
|
||||
* latest location, the same as with {@link LocationListener#onLocationChanged(List)}.
|
||||
*
|
||||
* @see #requestLocationUpdates(String, LocationRequest, PendingIntent)
|
||||
*/
|
||||
public static final String KEY_LOCATION_RESULT = "locationResult";
|
||||
public static final String KEY_LOCATIONS = "locations";
|
||||
|
||||
/**
|
||||
* Key used for an extra holding an integer request code when location flush completion is sent
|
||||
@@ -3018,12 +3025,12 @@ public class LocationManager {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onLocationChanged(LocationResult locationResult,
|
||||
public void onLocationChanged(List<Location> locations,
|
||||
@Nullable IRemoteCallback onCompleteCallback) {
|
||||
executeSafely(mExecutor, () -> mListener, new ListenerOperation<LocationListener>() {
|
||||
@Override
|
||||
public void operate(LocationListener listener) {
|
||||
listener.onLocationChanged(locationResult);
|
||||
listener.onLocationChanged(locations);
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -3366,8 +3373,8 @@ public class LocationManager {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onLocationChanged(@NonNull LocationResult locationResult) {
|
||||
mCallback.onLocationBatch(locationResult.asList());
|
||||
public void onLocationChanged(@NonNull List<Location> locations) {
|
||||
mCallback.onLocationBatch(locations);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -605,7 +605,7 @@ public final class LocationRequest implements Parcelable {
|
||||
* When available, batching can provide substantial power savings to the device, and clients are
|
||||
* encouraged to take advantage where appropriate for the use case.
|
||||
*
|
||||
* @see LocationListener#onLocationChanged(LocationResult)
|
||||
* @see LocationListener#onLocationChanged(java.util.List)
|
||||
* @return the maximum time by which a location update may be delayed
|
||||
*/
|
||||
public @IntRange(from = 0) long getMaxUpdateDelayMillis() {
|
||||
|
||||
@@ -19,7 +19,6 @@ package android.location;
|
||||
import android.annotation.IntRange;
|
||||
import android.annotation.NonNull;
|
||||
import android.annotation.Nullable;
|
||||
import android.annotation.SystemApi;
|
||||
import android.os.Parcel;
|
||||
import android.os.Parcelable;
|
||||
|
||||
@@ -34,21 +33,14 @@ import java.util.function.Predicate;
|
||||
|
||||
/**
|
||||
* A location result representing a list of locations, ordered from earliest to latest.
|
||||
*
|
||||
* @hide
|
||||
*/
|
||||
public final class LocationResult implements Parcelable {
|
||||
|
||||
/**
|
||||
* Creates a new LocationResult from the given location.
|
||||
*/
|
||||
public static @NonNull LocationResult create(@NonNull Location location) {
|
||||
ArrayList<Location> locations = new ArrayList<>(1);
|
||||
locations.add(new Location(Objects.requireNonNull(location)));
|
||||
return new LocationResult(locations);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a new LocationResult from the given locations. Locations must be ordered in the same
|
||||
* order they were derived (earliest to latest).
|
||||
* Creates a new LocationResult from the given locations, making a copy of each location.
|
||||
* Locations must be ordered in the same order they were derived (earliest to latest).
|
||||
*/
|
||||
public static @NonNull LocationResult create(@NonNull List<Location> locations) {
|
||||
Preconditions.checkArgument(!locations.isEmpty());
|
||||
@@ -60,16 +52,40 @@ public final class LocationResult implements Parcelable {
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a new LocationResult that takes ownership of the given location without copying it.
|
||||
* Callers must ensure the given location is never mutated after this method is called.
|
||||
*
|
||||
* @hide
|
||||
* Creates a new LocationResult from the given locations, making a copy of each location.
|
||||
* Locations must be ordered in the same order they were derived (earliest to latest).
|
||||
*/
|
||||
@SystemApi
|
||||
public static @NonNull LocationResult wrap(@NonNull Location location) {
|
||||
ArrayList<Location> locations = new ArrayList<>(1);
|
||||
locations.add(Objects.requireNonNull(location));
|
||||
return new LocationResult(locations);
|
||||
public static @NonNull LocationResult create(@NonNull Location... locations) {
|
||||
Preconditions.checkArgument(locations.length > 0);
|
||||
ArrayList<Location> locationsCopy = new ArrayList<>(locations.length);
|
||||
for (Location location : locations) {
|
||||
locationsCopy.add(new Location(Objects.requireNonNull(location)));
|
||||
}
|
||||
return new LocationResult(locationsCopy);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a new LocationResult that takes ownership of the given locations without copying
|
||||
* them. Callers must ensure the given locations are never mutated after this method is called.
|
||||
* Locations must be ordered in the same order they were derived (earliest to latest).
|
||||
*/
|
||||
public static @NonNull LocationResult wrap(@NonNull List<Location> locations) {
|
||||
Preconditions.checkArgument(!locations.isEmpty());
|
||||
return new LocationResult(new ArrayList<>(locations));
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a new LocationResult that takes ownership of the given locations without copying
|
||||
* them. Callers must ensure the given locations are never mutated after this method is called.
|
||||
* Locations must be ordered in the same order they were derived (earliest to latest).
|
||||
*/
|
||||
public static @NonNull LocationResult wrap(@NonNull Location... locations) {
|
||||
Preconditions.checkArgument(locations.length > 0);
|
||||
ArrayList<Location> newLocations = new ArrayList<>(locations.length);
|
||||
for (Location location : locations) {
|
||||
newLocations.add(Objects.requireNonNull(location));
|
||||
}
|
||||
return new LocationResult(newLocations);
|
||||
}
|
||||
|
||||
private final ArrayList<Location> mLocations;
|
||||
@@ -112,7 +128,7 @@ public final class LocationResult implements Parcelable {
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the numer of locations in this location result.
|
||||
* Returns the number of locations in this location result.
|
||||
*/
|
||||
public @IntRange(from = 1) int size() {
|
||||
return mLocations.size();
|
||||
@@ -139,9 +155,9 @@ public final class LocationResult implements Parcelable {
|
||||
* @hide
|
||||
*/
|
||||
public @NonNull LocationResult deepCopy() {
|
||||
ArrayList<Location> copy = new ArrayList<>(mLocations.size());
|
||||
final int size = mLocations.size();
|
||||
for (int i = 0; i < size; ++i) {
|
||||
ArrayList<Location> copy = new ArrayList<>(size);
|
||||
for (int i = 0; i < size; i++) {
|
||||
copy.add(new Location(mLocations.get(i)));
|
||||
}
|
||||
return new LocationResult(copy);
|
||||
@@ -164,7 +180,7 @@ public final class LocationResult implements Parcelable {
|
||||
* Returns a LocationResult with only locations that pass the given predicate. This
|
||||
* implementation will avoid allocations when no locations are filtered out. The predicate is
|
||||
* guaranteed to be invoked once per location, in order from earliest to latest. If all
|
||||
* locations are filtered out a null value is returned instead of an empty LocationResult.
|
||||
* locations are filtered out a null value is returned.
|
||||
*
|
||||
* @hide
|
||||
*/
|
||||
|
||||
@@ -16,7 +16,7 @@
|
||||
|
||||
package android.location.provider;
|
||||
|
||||
import android.location.LocationResult;
|
||||
import android.location.Location;
|
||||
import android.location.provider.ProviderProperties;
|
||||
|
||||
/**
|
||||
@@ -28,6 +28,7 @@ interface ILocationProviderManager {
|
||||
void onSetAllowed(boolean allowed);
|
||||
void onSetProperties(in ProviderProperties properties);
|
||||
|
||||
void onReportLocation(in LocationResult locationResult);
|
||||
void onReportLocation(in Location location);
|
||||
void onReportLocations(in List<Location> locations);
|
||||
void onFlushComplete();
|
||||
}
|
||||
|
||||
@@ -25,12 +25,13 @@ import android.annotation.SystemApi;
|
||||
import android.content.Context;
|
||||
import android.content.Intent;
|
||||
import android.location.Location;
|
||||
import android.location.LocationResult;
|
||||
import android.os.Bundle;
|
||||
import android.os.IBinder;
|
||||
import android.os.RemoteException;
|
||||
import android.util.Log;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.Objects;
|
||||
|
||||
/**
|
||||
@@ -200,35 +201,29 @@ public abstract class LocationProviderBase {
|
||||
* Reports a new location from this provider.
|
||||
*/
|
||||
public void reportLocation(@NonNull Location location) {
|
||||
reportLocation(LocationResult.create(location));
|
||||
ILocationProviderManager manager = mManager;
|
||||
if (manager != null) {
|
||||
try {
|
||||
manager.onReportLocation(stripExtras(location));
|
||||
} catch (RemoteException e) {
|
||||
throw e.rethrowFromSystemServer();
|
||||
} catch (RuntimeException e) {
|
||||
Log.w(mTag, e);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Reports a new location result from this provider.
|
||||
*
|
||||
* <p>May only be used from Android S onwards.
|
||||
* Reports a new batch of locations from this provider. Locations must be ordered in the list
|
||||
* from earliest first to latest last.
|
||||
*/
|
||||
public void reportLocation(@NonNull LocationResult locationResult) {
|
||||
public void reportLocations(@NonNull List<Location> locations) {
|
||||
ILocationProviderManager manager = mManager;
|
||||
if (manager != null) {
|
||||
locationResult = locationResult.map(location -> {
|
||||
// remove deprecated extras to save on serialization costs
|
||||
Bundle extras = location.getExtras();
|
||||
if (extras != null && (extras.containsKey(EXTRA_NO_GPS_LOCATION)
|
||||
|| extras.containsKey("coarseLocation"))) {
|
||||
location = new Location(location);
|
||||
extras = location.getExtras();
|
||||
extras.remove(EXTRA_NO_GPS_LOCATION);
|
||||
extras.remove("coarseLocation");
|
||||
if (extras.isEmpty()) {
|
||||
location.setExtras(null);
|
||||
}
|
||||
}
|
||||
return location;
|
||||
});
|
||||
|
||||
|
||||
try {
|
||||
manager.onReportLocation(locationResult);
|
||||
manager.onReportLocations(stripExtras(locations));
|
||||
} catch (RemoteException e) {
|
||||
throw e.rethrowFromSystemServer();
|
||||
} catch (RuntimeException e) {
|
||||
@@ -246,9 +241,9 @@ public abstract class LocationProviderBase {
|
||||
|
||||
/**
|
||||
* Requests a flush of any pending batched locations. The callback must always be invoked once
|
||||
* per invocation, and should be invoked after {@link #reportLocation(LocationResult)} has been
|
||||
* invoked with any flushed locations. The callback may be invoked immediately if no locations
|
||||
* are flushed.
|
||||
* per invocation, and should be invoked after {@link #reportLocation(Location)} or
|
||||
* {@link #reportLocations(List)} has been invoked with any flushed locations. The callback may
|
||||
* be invoked immediately if no locations are flushed.
|
||||
*/
|
||||
public abstract void onFlush(@NonNull OnFlushCompleteCallback callback);
|
||||
|
||||
@@ -259,6 +254,49 @@ public abstract class LocationProviderBase {
|
||||
@SuppressLint("NullableCollection")
|
||||
@Nullable Bundle extras);
|
||||
|
||||
private static Location stripExtras(Location location) {
|
||||
Bundle extras = location.getExtras();
|
||||
if (extras != null && (extras.containsKey(EXTRA_NO_GPS_LOCATION)
|
||||
|| extras.containsKey("indoorProbability")
|
||||
|| extras.containsKey("coarseLocation"))) {
|
||||
location = new Location(location);
|
||||
extras = location.getExtras();
|
||||
extras.remove(EXTRA_NO_GPS_LOCATION);
|
||||
extras.remove("indoorProbability");
|
||||
extras.remove("coarseLocation");
|
||||
if (extras.isEmpty()) {
|
||||
location.setExtras(null);
|
||||
}
|
||||
}
|
||||
return location;
|
||||
}
|
||||
|
||||
private static List<Location> stripExtras(List<Location> locations) {
|
||||
List<Location> mapped = locations;
|
||||
final int size = locations.size();
|
||||
int i = 0;
|
||||
for (Location location : locations) {
|
||||
Location newLocation = stripExtras(location);
|
||||
if (mapped != locations) {
|
||||
mapped.add(newLocation);
|
||||
} else if (newLocation != location) {
|
||||
mapped = new ArrayList<>(size);
|
||||
int j = 0;
|
||||
for (Location copiedLocation : locations) {
|
||||
if (j >= i) {
|
||||
break;
|
||||
}
|
||||
mapped.add(copiedLocation);
|
||||
j++;
|
||||
}
|
||||
mapped.add(newLocation);
|
||||
}
|
||||
i++;
|
||||
}
|
||||
|
||||
return mapped;
|
||||
}
|
||||
|
||||
private final class Service extends ILocationProvider.Stub {
|
||||
|
||||
Service() {}
|
||||
|
||||
@@ -21,8 +21,8 @@ package com.android.location.provider {
|
||||
method @Deprecated protected void onInit();
|
||||
method @Deprecated protected boolean onSendExtraCommand(@Nullable String, @Nullable android.os.Bundle);
|
||||
method @Deprecated protected abstract void onSetRequest(com.android.location.provider.ProviderRequestUnbundled, android.os.WorkSource);
|
||||
method @Deprecated public void reportLocation(android.location.Location);
|
||||
method @Deprecated public void reportLocation(android.location.LocationResult);
|
||||
method @Deprecated public void reportLocation(@NonNull android.location.Location);
|
||||
method @Deprecated public void reportLocations(@NonNull java.util.List<android.location.Location>);
|
||||
method @Deprecated @RequiresApi(android.os.Build.VERSION_CODES.Q) public void setAdditionalProviderPackages(java.util.List<java.lang.String>);
|
||||
method @Deprecated @RequiresApi(android.os.Build.VERSION_CODES.R) public void setAllowed(boolean);
|
||||
method @Deprecated @RequiresApi(android.os.Build.VERSION_CODES.Q) public void setEnabled(boolean);
|
||||
|
||||
@@ -16,13 +16,13 @@
|
||||
|
||||
package com.android.location.provider;
|
||||
|
||||
import android.annotation.NonNull;
|
||||
import android.annotation.Nullable;
|
||||
import android.content.Context;
|
||||
import android.location.ILocationManager;
|
||||
import android.location.Location;
|
||||
import android.location.LocationManager;
|
||||
import android.location.LocationProvider;
|
||||
import android.location.LocationResult;
|
||||
import android.location.provider.ILocationProvider;
|
||||
import android.location.provider.ILocationProviderManager;
|
||||
import android.location.provider.ProviderProperties;
|
||||
@@ -39,6 +39,7 @@ import androidx.annotation.RequiresApi;
|
||||
|
||||
import java.io.FileDescriptor;
|
||||
import java.io.PrintWriter;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
@@ -94,10 +95,6 @@ public abstract class LocationProviderBase {
|
||||
*/
|
||||
public static final String FUSED_PROVIDER = LocationManager.FUSED_PROVIDER;
|
||||
|
||||
private static final String EXTRA_KEY_COARSE_LOCATION = "coarseLocation";
|
||||
private static final String EXTRA_KEY_NO_GPS_LOCATION = "noGPSLocation";
|
||||
private static final String EXTRA_KEY_INDOOR_PROB = "indoorProbability";
|
||||
|
||||
final String mTag;
|
||||
@Nullable final String mPackageName;
|
||||
@Nullable final String mAttributionTag;
|
||||
@@ -254,20 +251,11 @@ public abstract class LocationProviderBase {
|
||||
/**
|
||||
* Reports a new location from this provider.
|
||||
*/
|
||||
public void reportLocation(Location location) {
|
||||
reportLocation(LocationResult.create(location));
|
||||
}
|
||||
|
||||
/**
|
||||
* Reports a new location from this provider.
|
||||
*/
|
||||
public void reportLocation(LocationResult locationResult) {
|
||||
public void reportLocation(@NonNull Location location) {
|
||||
ILocationProviderManager manager = mManager;
|
||||
if (manager != null) {
|
||||
locationResult = locationResult.map(this::cleanUpExtras);
|
||||
|
||||
try {
|
||||
manager.onReportLocation(locationResult);
|
||||
manager.onReportLocation(stripExtras(location));
|
||||
} catch (RemoteException e) {
|
||||
throw e.rethrowFromSystemServer();
|
||||
} catch (RuntimeException e) {
|
||||
@@ -277,30 +265,20 @@ public abstract class LocationProviderBase {
|
||||
}
|
||||
|
||||
/**
|
||||
* Remove deprecated/unnecessary extras to save on serialization costs.
|
||||
*
|
||||
* {@link #EXTRA_KEY_NO_GPS_LOCATION} and {@link #EXTRA_KEY_COARSE_LOCATION} are deprecated.
|
||||
*
|
||||
* {@link #EXTRA_KEY_INDOOR_PROB} should only be used in the framework.
|
||||
* Reports a new batch of locations from this provider. Locations must be ordered in the list
|
||||
* from earliest first to latest last.
|
||||
*/
|
||||
private Location cleanUpExtras(Location location) {
|
||||
Bundle extras = location.getExtras();
|
||||
if (extras == null) {
|
||||
return location;
|
||||
}
|
||||
if (extras.containsKey(EXTRA_KEY_NO_GPS_LOCATION)
|
||||
|| extras.containsKey(EXTRA_KEY_COARSE_LOCATION)
|
||||
|| extras.containsKey(EXTRA_KEY_INDOOR_PROB)) {
|
||||
location = new Location(location);
|
||||
extras = location.getExtras();
|
||||
extras.remove(EXTRA_KEY_NO_GPS_LOCATION);
|
||||
extras.remove(EXTRA_KEY_COARSE_LOCATION);
|
||||
extras.remove(EXTRA_KEY_INDOOR_PROB);
|
||||
if (extras.isEmpty()) {
|
||||
location.setExtras(null);
|
||||
public void reportLocations(@NonNull List<Location> locations) {
|
||||
ILocationProviderManager manager = mManager;
|
||||
if (manager != null) {
|
||||
try {
|
||||
manager.onReportLocations(stripExtras(locations));
|
||||
} catch (RemoteException e) {
|
||||
throw e.rethrowFromSystemServer();
|
||||
} catch (RuntimeException e) {
|
||||
Log.w(mTag, e);
|
||||
}
|
||||
}
|
||||
return location;
|
||||
}
|
||||
|
||||
protected void onInit() {
|
||||
@@ -336,9 +314,9 @@ public abstract class LocationProviderBase {
|
||||
|
||||
/**
|
||||
* Requests a flush of any pending batched locations. The callback must always be invoked once
|
||||
* per invocation, and should be invoked after {@link #reportLocation(LocationResult)} has been
|
||||
* invoked with any flushed locations. The callback may be invoked immediately if no locations
|
||||
* are flushed.
|
||||
* per invocation, and should be invoked after {@link #reportLocation(Location)} or
|
||||
* {@link #reportLocations(List)} has been invoked with any flushed locations. The callback may
|
||||
* be invoked immediately if no locations are flushed.
|
||||
*/
|
||||
protected void onFlush(OnFlushCompleteCallback callback) {
|
||||
callback.onFlushComplete();
|
||||
@@ -433,4 +411,47 @@ public abstract class LocationProviderBase {
|
||||
onSendExtraCommand(command, extras);
|
||||
}
|
||||
}
|
||||
|
||||
private static Location stripExtras(Location location) {
|
||||
Bundle extras = location.getExtras();
|
||||
if (extras != null && (extras.containsKey(EXTRA_NO_GPS_LOCATION)
|
||||
|| extras.containsKey("indoorProbability")
|
||||
|| extras.containsKey("coarseLocation"))) {
|
||||
location = new Location(location);
|
||||
extras = location.getExtras();
|
||||
extras.remove(EXTRA_NO_GPS_LOCATION);
|
||||
extras.remove("indoorProbability");
|
||||
extras.remove("coarseLocation");
|
||||
if (extras.isEmpty()) {
|
||||
location.setExtras(null);
|
||||
}
|
||||
}
|
||||
return location;
|
||||
}
|
||||
|
||||
private static List<Location> stripExtras(List<Location> locations) {
|
||||
List<Location> mapped = locations;
|
||||
final int size = locations.size();
|
||||
int i = 0;
|
||||
for (Location location : locations) {
|
||||
Location newLocation = stripExtras(location);
|
||||
if (mapped != locations) {
|
||||
mapped.add(newLocation);
|
||||
} else if (newLocation != location) {
|
||||
mapped = new ArrayList<>(size);
|
||||
int j = 0;
|
||||
for (Location copiedLocation : locations) {
|
||||
if (j >= i) {
|
||||
break;
|
||||
}
|
||||
mapped.add(copiedLocation);
|
||||
j++;
|
||||
}
|
||||
mapped.add(newLocation);
|
||||
}
|
||||
i++;
|
||||
}
|
||||
|
||||
return mapped;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -26,7 +26,6 @@ import android.location.Criteria;
|
||||
import android.location.Location;
|
||||
import android.location.LocationManager;
|
||||
import android.location.LocationRequest;
|
||||
import android.location.LocationResult;
|
||||
import android.location.provider.ILocationProvider;
|
||||
import android.location.provider.ILocationProviderManager;
|
||||
import android.location.provider.ProviderProperties;
|
||||
@@ -49,6 +48,7 @@ import org.junit.runner.RunWith;
|
||||
import java.io.ByteArrayOutputStream;
|
||||
import java.io.FileInputStream;
|
||||
import java.io.IOException;
|
||||
import java.util.List;
|
||||
import java.util.Random;
|
||||
import java.util.concurrent.LinkedBlockingQueue;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
@@ -167,10 +167,13 @@ public class FusedLocationServiceTest {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onReportLocation(LocationResult locationResult) {
|
||||
for (int i = 0; i < locationResult.size(); i++) {
|
||||
mLocations.add(locationResult.get(i));
|
||||
}
|
||||
public void onReportLocation(Location location) {
|
||||
mLocations.add(location);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onReportLocations(List<Location> locations) {
|
||||
mLocations.addAll(locations);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
@@ -103,7 +103,6 @@ import com.android.server.location.provider.AbstractLocationProvider;
|
||||
import java.io.FileDescriptor;
|
||||
import java.io.PrintWriter;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
import java.util.Objects;
|
||||
@@ -1489,7 +1488,7 @@ public class GnssLocationProvider extends AbstractLocationProvider implements
|
||||
}
|
||||
|
||||
if (locations.length > 0) {
|
||||
reportLocation(LocationResult.create(Arrays.asList(locations)).validate());
|
||||
reportLocation(LocationResult.wrap(locations).validate());
|
||||
}
|
||||
|
||||
for (Runnable listener : listeners) {
|
||||
|
||||
@@ -20,8 +20,8 @@ import static android.app.compat.CompatChanges.isChangeEnabled;
|
||||
import static android.location.LocationManager.DELIVER_HISTORICAL_LOCATIONS;
|
||||
import static android.location.LocationManager.GPS_PROVIDER;
|
||||
import static android.location.LocationManager.KEY_FLUSH_COMPLETE;
|
||||
import static android.location.LocationManager.KEY_LOCATIONS;
|
||||
import static android.location.LocationManager.KEY_LOCATION_CHANGED;
|
||||
import static android.location.LocationManager.KEY_LOCATION_RESULT;
|
||||
import static android.location.LocationManager.KEY_PROVIDER_ENABLED;
|
||||
import static android.location.LocationManager.PASSIVE_PROVIDER;
|
||||
import static android.os.IPowerManager.LOCATION_MODE_NO_CHANGE;
|
||||
@@ -187,7 +187,8 @@ public class LocationProviderManager extends
|
||||
@Override
|
||||
public void deliverOnLocationChanged(LocationResult locationResult,
|
||||
@Nullable Runnable onCompleteCallback) throws RemoteException {
|
||||
mListener.onLocationChanged(locationResult, SingleUseCallback.wrap(onCompleteCallback));
|
||||
mListener.onLocationChanged(locationResult.asList(),
|
||||
SingleUseCallback.wrap(onCompleteCallback));
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -222,12 +223,16 @@ public class LocationProviderManager extends
|
||||
// allows apps to start a fg service in response to a location PI
|
||||
options.setTemporaryAppWhitelistDuration(TEMPORARY_APP_ALLOWLIST_DURATION_MS);
|
||||
|
||||
Intent intent = new Intent().putExtra(KEY_LOCATION_CHANGED,
|
||||
locationResult.getLastLocation());
|
||||
if (locationResult.size() > 1) {
|
||||
intent.putExtra(KEY_LOCATIONS, locationResult.asList().toArray(new Location[0]));
|
||||
}
|
||||
|
||||
mPendingIntent.send(
|
||||
mContext,
|
||||
0,
|
||||
new Intent()
|
||||
.putExtra(KEY_LOCATION_CHANGED, locationResult.getLastLocation())
|
||||
.putExtra(KEY_LOCATION_RESULT, locationResult),
|
||||
intent,
|
||||
onCompleteCallback != null ? (pI, i, rC, rD, rE) -> onCompleteCallback.run()
|
||||
: null,
|
||||
null,
|
||||
|
||||
@@ -53,7 +53,7 @@ public class MockLocationProvider extends AbstractLocationProvider {
|
||||
Location location = new Location(l);
|
||||
location.setIsFromMockProvider(true);
|
||||
mLocation = location;
|
||||
reportLocation(LocationResult.wrap(location));
|
||||
reportLocation(LocationResult.wrap(location).validate());
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
@@ -21,6 +21,7 @@ import static com.android.internal.util.ConcurrentUtils.DIRECT_EXECUTOR;
|
||||
import android.annotation.Nullable;
|
||||
import android.content.ComponentName;
|
||||
import android.content.Context;
|
||||
import android.location.Location;
|
||||
import android.location.LocationResult;
|
||||
import android.location.provider.ILocationProvider;
|
||||
import android.location.provider.ILocationProviderManager;
|
||||
@@ -40,6 +41,7 @@ import com.android.server.location.provider.AbstractLocationProvider;
|
||||
import java.io.FileDescriptor;
|
||||
import java.io.PrintWriter;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.Objects;
|
||||
|
||||
/**
|
||||
@@ -260,13 +262,25 @@ public class ProxyLocationProvider extends AbstractLocationProvider {
|
||||
|
||||
// executed on binder thread
|
||||
@Override
|
||||
public void onReportLocation(LocationResult locationResult) {
|
||||
public void onReportLocation(Location location) {
|
||||
synchronized (mLock) {
|
||||
if (mProxy != this) {
|
||||
return;
|
||||
}
|
||||
|
||||
reportLocation(locationResult.validate());
|
||||
reportLocation(LocationResult.wrap(location).validate());
|
||||
}
|
||||
}
|
||||
|
||||
// executed on binder thread
|
||||
@Override
|
||||
public void onReportLocations(List<Location> locations) {
|
||||
synchronized (mLock) {
|
||||
if (mProxy != this) {
|
||||
return;
|
||||
}
|
||||
|
||||
reportLocation(LocationResult.wrap(locations).validate());
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -96,6 +96,7 @@ import java.io.FileDescriptor;
|
||||
import java.io.PrintWriter;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
import java.util.Random;
|
||||
import java.util.concurrent.CountDownLatch;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
@@ -383,7 +384,7 @@ public class LocationProviderManagerTest {
|
||||
|
||||
LocationResult loc = createLocationResult(NAME, mRandom);
|
||||
mProvider.setProviderLocation(loc);
|
||||
verify(listener).onLocationChanged(eq(loc), nullable(IRemoteCallback.class));
|
||||
verify(listener).onLocationChanged(eq(loc.asList()), nullable(IRemoteCallback.class));
|
||||
}
|
||||
|
||||
@Test
|
||||
@@ -406,13 +407,13 @@ public class LocationProviderManagerTest {
|
||||
|
||||
LocationResult loc = createLocationResult(NAME, mRandom);
|
||||
mProvider.setProviderLocation(loc);
|
||||
verify(listener).onLocationChanged(eq(loc), nullable(IRemoteCallback.class));
|
||||
verify(listener).onLocationChanged(eq(loc.asList()), nullable(IRemoteCallback.class));
|
||||
|
||||
mInjector.getSettingsHelper().setLocationEnabled(false, CURRENT_USER);
|
||||
verify(listener, timeout(TIMEOUT_MS).times(1)).onProviderEnabledChanged(NAME, false);
|
||||
loc = createLocationResult(NAME, mRandom);
|
||||
mProvider.setProviderLocation(loc);
|
||||
verify(listener, times(1)).onLocationChanged(any(LocationResult.class),
|
||||
verify(listener, times(1)).onLocationChanged(any(List.class),
|
||||
nullable(IRemoteCallback.class));
|
||||
|
||||
mInjector.getSettingsHelper().setLocationEnabled(true, CURRENT_USER);
|
||||
@@ -422,7 +423,7 @@ public class LocationProviderManagerTest {
|
||||
verify(listener, timeout(TIMEOUT_MS).times(2)).onProviderEnabledChanged(NAME, false);
|
||||
loc = createLocationResult(NAME, mRandom);
|
||||
mProvider.setProviderLocation(loc);
|
||||
verify(listener, times(1)).onLocationChanged(any(LocationResult.class),
|
||||
verify(listener, times(1)).onLocationChanged(any(List.class),
|
||||
nullable(IRemoteCallback.class));
|
||||
|
||||
mProvider.setAllowed(true);
|
||||
@@ -430,7 +431,7 @@ public class LocationProviderManagerTest {
|
||||
|
||||
loc = createLocationResult(NAME, mRandom);
|
||||
mProvider.setProviderLocation(loc);
|
||||
verify(listener).onLocationChanged(eq(loc), nullable(IRemoteCallback.class));
|
||||
verify(listener).onLocationChanged(eq(loc.asList()), nullable(IRemoteCallback.class));
|
||||
}
|
||||
|
||||
@Test
|
||||
@@ -447,7 +448,7 @@ public class LocationProviderManagerTest {
|
||||
|
||||
LocationResult loc = createLocationResult(NAME, mRandom);
|
||||
mProvider.setProviderLocation(loc);
|
||||
verify(listener, timeout(TIMEOUT_MS).times(1)).onLocationChanged(eq(loc),
|
||||
verify(listener, timeout(TIMEOUT_MS).times(1)).onLocationChanged(eq(loc.asList()),
|
||||
nullable(IRemoteCallback.class));
|
||||
}
|
||||
|
||||
@@ -462,7 +463,7 @@ public class LocationProviderManagerTest {
|
||||
mManager.unregisterLocationRequest(listener);
|
||||
|
||||
mProvider.setProviderLocation(createLocation(NAME, mRandom));
|
||||
verify(listener, never()).onLocationChanged(any(LocationResult.class),
|
||||
verify(listener, never()).onLocationChanged(any(List.class),
|
||||
nullable(IRemoteCallback.class));
|
||||
|
||||
mInjector.getSettingsHelper().setLocationEnabled(false, CURRENT_USER);
|
||||
@@ -493,7 +494,7 @@ public class LocationProviderManagerTest {
|
||||
mProvider.setProviderLocation(createLocation(NAME, mRandom));
|
||||
mManager.unregisterLocationRequest(listener);
|
||||
blocker.countDown();
|
||||
verify(listener, after(TIMEOUT_MS).never()).onLocationChanged(any(LocationResult.class),
|
||||
verify(listener, after(TIMEOUT_MS).never()).onLocationChanged(any(List.class),
|
||||
nullable(IRemoteCallback.class));
|
||||
}
|
||||
|
||||
@@ -513,7 +514,7 @@ public class LocationProviderManagerTest {
|
||||
mProvider.setProviderLocation(createLocation(NAME, mRandom));
|
||||
mProvider.setProviderLocation(createLocation(NAME, mRandom));
|
||||
|
||||
verify(listener, times(5)).onLocationChanged(any(LocationResult.class),
|
||||
verify(listener, times(5)).onLocationChanged(any(List.class),
|
||||
nullable(IRemoteCallback.class));
|
||||
}
|
||||
|
||||
@@ -528,7 +529,7 @@ public class LocationProviderManagerTest {
|
||||
|
||||
mInjector.getAlarmHelper().incrementAlarmTime(5000);
|
||||
mProvider.setProviderLocation(createLocation(NAME, mRandom));
|
||||
verify(listener, never()).onLocationChanged(any(LocationResult.class),
|
||||
verify(listener, never()).onLocationChanged(any(List.class),
|
||||
nullable(IRemoteCallback.class));
|
||||
}
|
||||
|
||||
@@ -544,7 +545,7 @@ public class LocationProviderManagerTest {
|
||||
Thread.sleep(25);
|
||||
|
||||
mProvider.setProviderLocation(createLocation(NAME, mRandom));
|
||||
verify(listener, never()).onLocationChanged(any(LocationResult.class),
|
||||
verify(listener, never()).onLocationChanged(any(List.class),
|
||||
nullable(IRemoteCallback.class));
|
||||
}
|
||||
|
||||
@@ -561,7 +562,7 @@ public class LocationProviderManagerTest {
|
||||
mProvider.setProviderLocation(createLocation(NAME, mRandom));
|
||||
|
||||
verify(listener, times(1)).onLocationChanged(
|
||||
any(LocationResult.class), nullable(IRemoteCallback.class));
|
||||
any(List.class), nullable(IRemoteCallback.class));
|
||||
}
|
||||
|
||||
@Test
|
||||
@@ -578,7 +579,7 @@ public class LocationProviderManagerTest {
|
||||
mProvider.setProviderLocation(loc);
|
||||
|
||||
verify(listener, times(1)).onLocationChanged(
|
||||
any(LocationResult.class), nullable(IRemoteCallback.class));
|
||||
any(List.class), nullable(IRemoteCallback.class));
|
||||
}
|
||||
|
||||
@Test
|
||||
@@ -592,7 +593,7 @@ public class LocationProviderManagerTest {
|
||||
|
||||
mProvider.setProviderLocation(createLocation(NAME, mRandom));
|
||||
|
||||
verify(listener, never()).onLocationChanged(any(LocationResult.class),
|
||||
verify(listener, never()).onLocationChanged(any(List.class),
|
||||
nullable(IRemoteCallback.class));
|
||||
}
|
||||
|
||||
@@ -622,7 +623,7 @@ public class LocationProviderManagerTest {
|
||||
verify(mWakeLock, never()).release();
|
||||
|
||||
blocker.countDown();
|
||||
verify(listener, timeout(TIMEOUT_MS)).onLocationChanged(any(LocationResult.class),
|
||||
verify(listener, timeout(TIMEOUT_MS)).onLocationChanged(any(List.class),
|
||||
nullable(IRemoteCallback.class));
|
||||
verify(mWakeLock).acquire(anyLong());
|
||||
verify(mWakeLock, timeout(TIMEOUT_MS)).release();
|
||||
@@ -640,7 +641,7 @@ public class LocationProviderManagerTest {
|
||||
mProvider.setProviderLocation(createLocation(NAME, mRandom));
|
||||
mProvider.setProviderLocation(createLocation(NAME, mRandom));
|
||||
verify(listener, times(1))
|
||||
.onLocationChanged(any(LocationResult.class), nullable(IRemoteCallback.class));
|
||||
.onLocationChanged(any(List.class), nullable(IRemoteCallback.class));
|
||||
}
|
||||
|
||||
@Test
|
||||
@@ -657,7 +658,7 @@ public class LocationProviderManagerTest {
|
||||
mProvider.setProviderLocation(createLocation(NAME, mRandom));
|
||||
mProvider.setProviderLocation(createLocation(NAME, mRandom));
|
||||
verify(listener, times(1))
|
||||
.onLocationChanged(any(LocationResult.class), nullable(IRemoteCallback.class));
|
||||
.onLocationChanged(any(List.class), nullable(IRemoteCallback.class));
|
||||
}
|
||||
|
||||
@Test
|
||||
@@ -746,7 +747,7 @@ public class LocationProviderManagerTest {
|
||||
mProvider.completeFlushes();
|
||||
|
||||
InOrder inOrder = inOrder(listener);
|
||||
inOrder.verify(listener).onLocationChanged(eq(loc), any(IRemoteCallback.class));
|
||||
inOrder.verify(listener).onLocationChanged(eq(loc.asList()), any(IRemoteCallback.class));
|
||||
inOrder.verify(listener).onFlushComplete(99);
|
||||
}
|
||||
|
||||
@@ -838,7 +839,7 @@ public class LocationProviderManagerTest {
|
||||
.build();
|
||||
mManager.registerLocationRequest(request1, IDENTITY, PERMISSION_FINE, listener1);
|
||||
|
||||
verify(listener1).onLocationChanged(any(LocationResult.class),
|
||||
verify(listener1).onLocationChanged(any(List.class),
|
||||
nullable(IRemoteCallback.class));
|
||||
|
||||
assertThat(mProvider.getRequest().isActive()).isFalse();
|
||||
@@ -989,7 +990,7 @@ public class LocationProviderManagerTest {
|
||||
private ILocationListener createMockLocationListener() {
|
||||
return spy(new ILocationListener.Stub() {
|
||||
@Override
|
||||
public void onLocationChanged(LocationResult location,
|
||||
public void onLocationChanged(List<Location> locations,
|
||||
IRemoteCallback onCompleteCallback) {
|
||||
if (onCompleteCallback != null) {
|
||||
try {
|
||||
|
||||
@@ -185,8 +185,8 @@ public class MockableLocationProviderTest {
|
||||
|
||||
@Test
|
||||
public void testReportLocation() {
|
||||
LocationResult realLocation = LocationResult.create(new Location("real"));
|
||||
LocationResult mockLocation = LocationResult.create(new Location("mock"));
|
||||
LocationResult realLocation = LocationResult.wrap(new Location("real"));
|
||||
LocationResult mockLocation = LocationResult.wrap(new Location("mock"));
|
||||
|
||||
mRealProvider.reportLocation(realLocation);
|
||||
assertThat(mListener.getNextLocationResult()).isEqualTo(realLocation);
|
||||
|
||||
Reference in New Issue
Block a user