diff options
| author | 2021-02-08 21:01:41 +0000 | |
|---|---|---|
| committer | 2021-02-08 21:01:41 +0000 | |
| commit | 15c8bf6793f3ca582cbb5b285f3fbdaf86e2cc76 (patch) | |
| tree | 45060823652c20a224ee9d7d8023a954e9f42e5e | |
| parent | b610667bfd88681a2c089150315f8e4eedd3691e (diff) | |
| parent | 72a25122677dda9145ce6b42108933d1e72ebcf6 (diff) | |
Merge "Add LocationManager#registerProviderRequestListener" into sc-dev
8 files changed, 198 insertions, 6 deletions
diff --git a/core/api/system-current.txt b/core/api/system-current.txt index 6fec3095ed16..1192d1fa59af 100644 --- a/core/api/system-current.txt +++ b/core/api/system-current.txt @@ -4666,6 +4666,7 @@ package android.location { method @RequiresPermission(android.Manifest.permission.READ_DEVICE_CONFIG) public boolean isProviderPackage(@Nullable String, @NonNull String, @Nullable String); method @Deprecated @RequiresPermission(allOf={android.Manifest.permission.LOCATION_HARDWARE, android.Manifest.permission.UPDATE_APP_OPS_STATS}) public boolean registerGnssBatchedLocationCallback(long, boolean, @NonNull android.location.BatchedLocationCallback, @Nullable android.os.Handler); method @Deprecated @RequiresPermission(android.Manifest.permission.ACCESS_FINE_LOCATION) public boolean registerGnssMeasurementsCallback(@NonNull android.location.GnssRequest, @NonNull java.util.concurrent.Executor, @NonNull android.location.GnssMeasurementsEvent.Callback); + method @RequiresPermission(android.Manifest.permission.LOCATION_HARDWARE) public boolean registerProviderRequestListener(@NonNull java.util.concurrent.Executor, @NonNull android.location.provider.ProviderRequest.Listener); method @Deprecated @RequiresPermission(anyOf={android.Manifest.permission.ACCESS_COARSE_LOCATION, android.Manifest.permission.ACCESS_FINE_LOCATION}) public void requestLocationUpdates(@Nullable android.location.LocationRequest, @NonNull android.location.LocationListener, @Nullable android.os.Looper); method @Deprecated @RequiresPermission(anyOf={android.Manifest.permission.ACCESS_COARSE_LOCATION, android.Manifest.permission.ACCESS_FINE_LOCATION}) public void requestLocationUpdates(@Nullable android.location.LocationRequest, @NonNull java.util.concurrent.Executor, @NonNull android.location.LocationListener); method @Deprecated @RequiresPermission(anyOf={android.Manifest.permission.ACCESS_COARSE_LOCATION, android.Manifest.permission.ACCESS_FINE_LOCATION}) public void requestLocationUpdates(@Nullable android.location.LocationRequest, @NonNull android.app.PendingIntent); @@ -4674,6 +4675,7 @@ package android.location { method @RequiresPermission(android.Manifest.permission.WRITE_SECURE_SETTINGS) public void setLocationEnabledForUser(boolean, @NonNull android.os.UserHandle); method @Deprecated @RequiresPermission(android.Manifest.permission.WRITE_SECURE_SETTINGS) public boolean setProviderEnabledForUser(@NonNull String, boolean, @NonNull android.os.UserHandle); method @Deprecated @RequiresPermission(android.Manifest.permission.LOCATION_HARDWARE) public boolean unregisterGnssBatchedLocationCallback(@NonNull android.location.BatchedLocationCallback); + method @RequiresPermission(android.Manifest.permission.LOCATION_HARDWARE) public void unregisterProviderRequestListener(@NonNull android.location.provider.ProviderRequest.Listener); } public final class LocationRequest implements android.os.Parcelable { @@ -4823,6 +4825,10 @@ package android.location.provider { method @NonNull public android.location.provider.ProviderRequest.Builder setWorkSource(@NonNull android.os.WorkSource); } + public static interface ProviderRequest.Listener { + method public void onProviderRequestChanged(@NonNull String, @NonNull android.location.provider.ProviderRequest); + } + } package android.media { diff --git a/location/java/android/location/ILocationManager.aidl b/location/java/android/location/ILocationManager.aidl index 65721cc33aed..adf58da6a072 100644 --- a/location/java/android/location/ILocationManager.aidl +++ b/location/java/android/location/ILocationManager.aidl @@ -36,6 +36,7 @@ import android.location.LastLocationRequest; import android.location.Location; import android.location.LocationRequest; import android.location.LocationTime; +import android.location.provider.IProviderRequestListener; import android.location.provider.ProviderProperties; import android.os.Bundle; import android.os.ICancellationSignal; @@ -91,6 +92,9 @@ interface ILocationManager void addGnssNavigationMessageListener(in IGnssNavigationMessageListener listener, String packageName, @nullable String attributionTag); void removeGnssNavigationMessageListener(in IGnssNavigationMessageListener listener); + void addProviderRequestListener(in IProviderRequestListener listener); + void removeProviderRequestListener(in IProviderRequestListener listener); + int getGnssBatchSize(); void startGnssBatch(long periodNanos, in ILocationListener listener, String packageName, @nullable String attributionTag, @nullable String listenerId); void flushGnssBatch(); diff --git a/location/java/android/location/LocationManager.java b/location/java/android/location/LocationManager.java index d56948222797..088b789ea690 100644 --- a/location/java/android/location/LocationManager.java +++ b/location/java/android/location/LocationManager.java @@ -49,7 +49,10 @@ import android.content.Context; import android.content.Intent; import android.content.IntentFilter; import android.content.pm.PackageManager; +import android.location.provider.IProviderRequestListener; import android.location.provider.ProviderProperties; +import android.location.provider.ProviderRequest; +import android.location.provider.ProviderRequest.Listener; import android.os.Build; import android.os.Bundle; import android.os.CancellationSignal; @@ -436,6 +439,9 @@ public class LocationManager { new GnssNavigationTransportManager(); } + private static final ProviderRequestTransportManager sProviderRequestListeners = + new ProviderRequestTransportManager(); + private final Context mContext; private final ILocationManager mService; @@ -2772,6 +2778,37 @@ public class LocationManager { } /** + * Registers a {@link ProviderRequest.Listener} to all providers. + * + * @param executor the executor that the callback runs on + * @param listener the listener to register + * @return {@code true} always + * @hide + */ + @SystemApi + @RequiresPermission(Manifest.permission.LOCATION_HARDWARE) + public boolean registerProviderRequestListener( + @NonNull @CallbackExecutor Executor executor, + @NonNull Listener listener) { + sProviderRequestListeners.addListener(listener, + new ProviderRequestTransport(executor, listener)); + return true; + } + + /** + * Unregisters a {@link ProviderRequest.Listener}. + * + * @param listener the listener to remove. + * @hide + */ + @SystemApi + @RequiresPermission(Manifest.permission.LOCATION_HARDWARE) + public void unregisterProviderRequestListener( + @NonNull Listener listener) { + sProviderRequestListeners.removeListener(listener); + } + + /** * Returns the batch size (in number of Location objects) that are supported by the batching * interface. * @@ -2960,6 +2997,22 @@ public class LocationManager { } } + private static class ProviderRequestTransportManager extends + ListenerTransportManager<ProviderRequestTransport> { + + @Override + protected void registerTransport(ProviderRequestTransport transport) + throws RemoteException { + getService().addProviderRequestListener(transport); + } + + @Override + protected void unregisterTransport(ProviderRequestTransport transport) + throws RemoteException { + getService().removeProviderRequestListener(transport); + } + } + private static class GetCurrentLocationTransport extends ILocationCallback.Stub implements ListenerExecutor, CancellationSignal.OnCancelListener { @@ -3359,6 +3412,36 @@ public class LocationManager { } } + private static class ProviderRequestTransport extends IProviderRequestListener.Stub + implements ListenerTransport<ProviderRequest.Listener> { + + private final Executor mExecutor; + + private volatile @Nullable ProviderRequest.Listener mListener; + + ProviderRequestTransport(Executor executor, ProviderRequest.Listener listener) { + Preconditions.checkArgument(executor != null, "invalid null executor"); + Preconditions.checkArgument(listener != null, "invalid null callback"); + mExecutor = executor; + mListener = listener; + } + + @Override + public void unregister() { + mListener = null; + } + + @Override + public @Nullable ProviderRequest.Listener getListener() { + return mListener; + } + + @Override + public void onProviderRequestChanged(String provider, ProviderRequest request) { + execute(mExecutor, listener -> listener.onProviderRequestChanged(provider, request)); + } + } + private static class BatchedLocationCallbackWrapper implements LocationListener { private final BatchedLocationCallback mCallback; diff --git a/location/java/android/location/provider/IProviderRequestListener.aidl b/location/java/android/location/provider/IProviderRequestListener.aidl new file mode 100644 index 000000000000..89d454aafe2c --- /dev/null +++ b/location/java/android/location/provider/IProviderRequestListener.aidl @@ -0,0 +1,26 @@ +/* + * Copyright (C) 2021, The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package android.location.provider; + +import android.location.provider.ProviderRequest; + +/** + * {@hide} + */ +oneway interface IProviderRequestListener { + void onProviderRequestChanged(String provider, in ProviderRequest request); +} diff --git a/location/java/android/location/provider/ProviderRequest.java b/location/java/android/location/provider/ProviderRequest.java index e543b040a2d4..b6ec32309b08 100644 --- a/location/java/android/location/provider/ProviderRequest.java +++ b/location/java/android/location/provider/ProviderRequest.java @@ -53,6 +53,17 @@ public final class ProviderRequest implements Parcelable { private final boolean mLocationSettingsIgnored; private final WorkSource mWorkSource; + /** + * Listener to be invoked when a new request is set to the provider. + */ + public interface Listener { + + /** + * Invoked when a new request is set. + */ + void onProviderRequestChanged(@NonNull String provider, @NonNull ProviderRequest request); + } + private ProviderRequest( long intervalMillis, @Quality int quality, diff --git a/services/core/java/com/android/server/location/LocationManagerService.java b/services/core/java/com/android/server/location/LocationManagerService.java index 142f64f0a510..ea759bf500dd 100644 --- a/services/core/java/com/android/server/location/LocationManagerService.java +++ b/services/core/java/com/android/server/location/LocationManagerService.java @@ -66,6 +66,7 @@ import android.location.LocationManagerInternal; import android.location.LocationProvider; import android.location.LocationRequest; import android.location.LocationTime; +import android.location.provider.IProviderRequestListener; import android.location.provider.ProviderProperties; import android.location.util.identity.CallerIdentity; import android.os.Binder; @@ -882,6 +883,20 @@ public class LocationManagerService extends ILocationManager.Stub { } @Override + public void addProviderRequestListener(IProviderRequestListener listener) { + for (LocationProviderManager manager : mProviderManagers) { + manager.addProviderRequestListener(listener); + } + } + + @Override + public void removeProviderRequestListener(IProviderRequestListener listener) { + for (LocationProviderManager manager : mProviderManagers) { + manager.removeProviderRequestListener(listener); + } + } + + @Override public void injectGnssMeasurementCorrections(GnssMeasurementCorrections corrections) { if (mGnssManagerService != null) { mGnssManagerService.injectGnssMeasurementCorrections(corrections); diff --git a/services/core/java/com/android/server/location/provider/LocationProviderManager.java b/services/core/java/com/android/server/location/provider/LocationProviderManager.java index 221d4fb40ef9..48a012e57a02 100644 --- a/services/core/java/com/android/server/location/provider/LocationProviderManager.java +++ b/services/core/java/com/android/server/location/provider/LocationProviderManager.java @@ -55,6 +55,7 @@ import android.location.LocationManagerInternal; import android.location.LocationManagerInternal.ProviderEnabledListener; import android.location.LocationRequest; import android.location.LocationResult; +import android.location.provider.IProviderRequestListener; import android.location.provider.ProviderProperties; import android.location.provider.ProviderRequest; import android.location.util.identity.CallerIdentity; @@ -117,6 +118,7 @@ import java.lang.annotation.RetentionPolicy; import java.util.ArrayList; import java.util.Collection; import java.util.Objects; +import java.util.concurrent.CopyOnWriteArrayList; import java.util.function.Predicate; /** @@ -1219,6 +1221,8 @@ public class LocationProviderManager extends @GuardedBy("mLock") private final ArrayList<ProviderEnabledListener> mEnabledListeners; + private final CopyOnWriteArrayList<IProviderRequestListener> mProviderRequestListeners; + protected final LocationManagerInternal mLocationManagerInternal; protected final SettingsHelper mSettingsHelper; protected final UserInfoHelper mUserHelper; @@ -1279,6 +1283,7 @@ public class LocationProviderManager extends mLastLocations = new SparseArray<>(2); mEnabledListeners = new ArrayList<>(); + mProviderRequestListeners = new CopyOnWriteArrayList<>(); mLocationManagerInternal = Objects.requireNonNull( LocalServices.getService(LocationManagerInternal.class)); @@ -1344,6 +1349,7 @@ public class LocationProviderManager extends // if external entities are registering listeners it's their responsibility to // unregister them before stopManager() is called Preconditions.checkState(mEnabledListeners.isEmpty()); + mProviderRequestListeners.clear(); mEnabled.clear(); mLastLocations.clear(); @@ -1404,6 +1410,16 @@ public class LocationProviderManager extends } } + /** Add a {@link IProviderRequestListener}. */ + public void addProviderRequestListener(IProviderRequestListener listener) { + mProviderRequestListeners.add(listener); + } + + /** Remove a {@link IProviderRequestListener}. */ + public void removeProviderRequestListener(IProviderRequestListener listener) { + mProviderRequestListeners.remove(listener); + } + public void setRealProvider(@Nullable AbstractLocationProvider provider) { synchronized (mLock) { Preconditions.checkState(mState != STATE_STOPPED); @@ -1873,8 +1889,7 @@ public class LocationProviderManager extends Preconditions.checkState(delayMs >= 0 && delayMs <= newRequest.getIntervalMillis()); if (delayMs < MIN_REQUEST_DELAY_MS) { - mLocationEventLog.logProviderUpdateRequest(mName, newRequest); - mProvider.getController().setRequest(newRequest); + setProviderRequest(newRequest); } else { if (D) { Log.d(TAG, mName + " provider delaying request update " + newRequest + " by " @@ -1886,8 +1901,7 @@ public class LocationProviderManager extends public void onAlarm() { synchronized (mLock) { if (mDelayedRegister == this) { - mLocationEventLog.logProviderUpdateRequest(mName, newRequest); - mProvider.getController().setRequest(newRequest); + setProviderRequest(newRequest); mDelayedRegister = null; } } @@ -1906,8 +1920,23 @@ public class LocationProviderManager extends Preconditions.checkState(Thread.holdsLock(mLock)); } - mLocationEventLog.logProviderUpdateRequest(mName, ProviderRequest.EMPTY_REQUEST); - mProvider.getController().setRequest(ProviderRequest.EMPTY_REQUEST); + setProviderRequest(ProviderRequest.EMPTY_REQUEST); + } + + @GuardedBy("mLock") + private void setProviderRequest(ProviderRequest request) { + mLocationEventLog.logProviderUpdateRequest(mName, request); + mProvider.getController().setRequest(request); + + FgThread.getHandler().post(() -> { + for (IProviderRequestListener listener : mProviderRequestListeners) { + try { + listener.onProviderRequestChanged(mName, request); + } catch (RemoteException e) { + mProviderRequestListeners.remove(listener); + } + } + }); } @GuardedBy("mLock") diff --git a/services/tests/mockingservicestests/src/com/android/server/location/provider/LocationProviderManagerTest.java b/services/tests/mockingservicestests/src/com/android/server/location/provider/LocationProviderManagerTest.java index 3b5cc887c798..54fa89a1e24b 100644 --- a/services/tests/mockingservicestests/src/com/android/server/location/provider/LocationProviderManagerTest.java +++ b/services/tests/mockingservicestests/src/com/android/server/location/provider/LocationProviderManagerTest.java @@ -64,6 +64,7 @@ import android.location.LocationManagerInternal; import android.location.LocationManagerInternal.ProviderEnabledListener; import android.location.LocationRequest; import android.location.LocationResult; +import android.location.provider.IProviderRequestListener; import android.location.provider.ProviderProperties; import android.location.provider.ProviderRequest; import android.location.util.identity.CallerIdentity; @@ -662,6 +663,23 @@ public class LocationProviderManagerTest { } @Test + public void testProviderRequestListener() throws Exception { + IProviderRequestListener requestListener = mock(IProviderRequestListener.class); + mManager.addProviderRequestListener(requestListener); + + ILocationListener locationListener = createMockLocationListener(); + LocationRequest request = new LocationRequest.Builder(1).setWorkSource( + WORK_SOURCE).build(); + mManager.registerLocationRequest(request, IDENTITY, PERMISSION_FINE, locationListener); + + verify(requestListener, timeout(TIMEOUT_MS).times(1)).onProviderRequestChanged(anyString(), + any(ProviderRequest.class)); + + mManager.unregisterLocationRequest(locationListener); + mManager.removeProviderRequestListener(requestListener); + } + + @Test public void testGetCurrentLocation() throws Exception { ILocationCallback listener = createMockGetCurrentLocationListener(); LocationRequest request = new LocationRequest.Builder(0).setWorkSource(WORK_SOURCE).build(); |