Add Executor APIs to LocationManager
Add executor support for all LM APIs and consolidate various GNSS listeners. Also fixes some edge cases around multithreaded listener callback delivery. Bug: 136212299 Test: Manual Change-Id: I2e863e41de846e739654362e859b58a5ed45c673
This commit is contained in:
@@ -23089,8 +23089,9 @@ package android.location {
|
||||
|
||||
public class LocationManager {
|
||||
method @Deprecated @RequiresPermission(android.Manifest.permission.ACCESS_FINE_LOCATION) public boolean addGpsStatusListener(android.location.GpsStatus.Listener);
|
||||
method @RequiresPermission(android.Manifest.permission.ACCESS_FINE_LOCATION) public boolean addNmeaListener(@NonNull android.location.OnNmeaMessageListener);
|
||||
method @Deprecated @RequiresPermission(android.Manifest.permission.ACCESS_FINE_LOCATION) public boolean addNmeaListener(@NonNull android.location.OnNmeaMessageListener);
|
||||
method @RequiresPermission(android.Manifest.permission.ACCESS_FINE_LOCATION) public boolean addNmeaListener(@NonNull android.location.OnNmeaMessageListener, @Nullable android.os.Handler);
|
||||
method @RequiresPermission(android.Manifest.permission.ACCESS_FINE_LOCATION) public boolean addNmeaListener(@NonNull java.util.concurrent.Executor, @NonNull android.location.OnNmeaMessageListener);
|
||||
method @RequiresPermission(anyOf={android.Manifest.permission.ACCESS_COARSE_LOCATION, android.Manifest.permission.ACCESS_FINE_LOCATION}) public void addProximityAlert(double, double, float, long, @NonNull android.app.PendingIntent);
|
||||
method public void addTestProvider(@NonNull String, boolean, boolean, boolean, boolean, boolean, boolean, boolean, int, int);
|
||||
method @Deprecated public void clearTestProviderEnabled(@NonNull String);
|
||||
@@ -23107,12 +23108,15 @@ package android.location {
|
||||
method @NonNull public java.util.List<java.lang.String> getProviders(@NonNull android.location.Criteria, boolean);
|
||||
method public boolean isLocationEnabled();
|
||||
method public boolean isProviderEnabled(@NonNull String);
|
||||
method @RequiresPermission(android.Manifest.permission.ACCESS_FINE_LOCATION) public boolean registerGnssMeasurementsCallback(@NonNull android.location.GnssMeasurementsEvent.Callback);
|
||||
method @Deprecated @RequiresPermission(android.Manifest.permission.ACCESS_FINE_LOCATION) public boolean registerGnssMeasurementsCallback(@NonNull android.location.GnssMeasurementsEvent.Callback);
|
||||
method @RequiresPermission(android.Manifest.permission.ACCESS_FINE_LOCATION) public boolean registerGnssMeasurementsCallback(@NonNull android.location.GnssMeasurementsEvent.Callback, @Nullable android.os.Handler);
|
||||
method public boolean registerGnssNavigationMessageCallback(@NonNull android.location.GnssNavigationMessage.Callback);
|
||||
method @RequiresPermission(android.Manifest.permission.ACCESS_FINE_LOCATION) public boolean registerGnssMeasurementsCallback(@NonNull java.util.concurrent.Executor, @NonNull android.location.GnssMeasurementsEvent.Callback);
|
||||
method @Deprecated public boolean registerGnssNavigationMessageCallback(@NonNull android.location.GnssNavigationMessage.Callback);
|
||||
method @RequiresPermission(android.Manifest.permission.ACCESS_FINE_LOCATION) public boolean registerGnssNavigationMessageCallback(@NonNull android.location.GnssNavigationMessage.Callback, @Nullable android.os.Handler);
|
||||
method @RequiresPermission(android.Manifest.permission.ACCESS_FINE_LOCATION) public boolean registerGnssStatusCallback(@NonNull android.location.GnssStatus.Callback);
|
||||
method @RequiresPermission(android.Manifest.permission.ACCESS_FINE_LOCATION) public boolean registerGnssNavigationMessageCallback(@NonNull java.util.concurrent.Executor, @NonNull android.location.GnssNavigationMessage.Callback);
|
||||
method @Deprecated @RequiresPermission(android.Manifest.permission.ACCESS_FINE_LOCATION) public boolean registerGnssStatusCallback(@NonNull android.location.GnssStatus.Callback);
|
||||
method @RequiresPermission(android.Manifest.permission.ACCESS_FINE_LOCATION) public boolean registerGnssStatusCallback(@NonNull android.location.GnssStatus.Callback, @Nullable android.os.Handler);
|
||||
method @RequiresPermission(android.Manifest.permission.ACCESS_FINE_LOCATION) public boolean registerGnssStatusCallback(@NonNull java.util.concurrent.Executor, @NonNull android.location.GnssStatus.Callback);
|
||||
method @Deprecated public void removeGpsStatusListener(android.location.GpsStatus.Listener);
|
||||
method public void removeNmeaListener(@NonNull android.location.OnNmeaMessageListener);
|
||||
method @RequiresPermission(anyOf={"android.permission.ACCESS_COARSE_LOCATION", "android.permission.ACCESS_FINE_LOCATION"}, apis="..22") public void removeProximityAlert(@NonNull android.app.PendingIntent);
|
||||
@@ -23121,7 +23125,9 @@ package android.location {
|
||||
method public void removeUpdates(@NonNull android.app.PendingIntent);
|
||||
method @RequiresPermission(anyOf={android.Manifest.permission.ACCESS_COARSE_LOCATION, android.Manifest.permission.ACCESS_FINE_LOCATION}) public void requestLocationUpdates(@NonNull String, long, float, @NonNull android.location.LocationListener);
|
||||
method @RequiresPermission(anyOf={android.Manifest.permission.ACCESS_COARSE_LOCATION, android.Manifest.permission.ACCESS_FINE_LOCATION}) public void requestLocationUpdates(@NonNull String, long, float, @NonNull android.location.LocationListener, @Nullable android.os.Looper);
|
||||
method @RequiresPermission(anyOf={android.Manifest.permission.ACCESS_COARSE_LOCATION, android.Manifest.permission.ACCESS_FINE_LOCATION}) public void requestLocationUpdates(@NonNull String, long, float, @NonNull java.util.concurrent.Executor, @NonNull android.location.LocationListener);
|
||||
method @RequiresPermission(anyOf={android.Manifest.permission.ACCESS_COARSE_LOCATION, android.Manifest.permission.ACCESS_FINE_LOCATION}) public void requestLocationUpdates(long, float, @NonNull android.location.Criteria, @NonNull android.location.LocationListener, @Nullable android.os.Looper);
|
||||
method @RequiresPermission(anyOf={android.Manifest.permission.ACCESS_COARSE_LOCATION, android.Manifest.permission.ACCESS_FINE_LOCATION}) public void requestLocationUpdates(long, float, @NonNull android.location.Criteria, @NonNull java.util.concurrent.Executor, @NonNull android.location.LocationListener);
|
||||
method @RequiresPermission(anyOf={android.Manifest.permission.ACCESS_COARSE_LOCATION, android.Manifest.permission.ACCESS_FINE_LOCATION}) public void requestLocationUpdates(@NonNull String, long, float, @NonNull android.app.PendingIntent);
|
||||
method @RequiresPermission(anyOf={android.Manifest.permission.ACCESS_COARSE_LOCATION, android.Manifest.permission.ACCESS_FINE_LOCATION}) public void requestLocationUpdates(long, float, @NonNull android.location.Criteria, @NonNull android.app.PendingIntent);
|
||||
method @RequiresPermission(anyOf={android.Manifest.permission.ACCESS_COARSE_LOCATION, android.Manifest.permission.ACCESS_FINE_LOCATION}) public void requestSingleUpdate(@NonNull String, @NonNull android.location.LocationListener, @Nullable android.os.Looper);
|
||||
|
||||
@@ -3430,6 +3430,7 @@ package android.location {
|
||||
method @RequiresPermission(android.Manifest.permission.READ_DEVICE_CONFIG) public boolean isProviderPackage(@NonNull String);
|
||||
method @RequiresPermission(android.Manifest.permission.LOCATION_HARDWARE) public boolean registerGnssBatchedLocationCallback(long, boolean, @NonNull android.location.BatchedLocationCallback, @Nullable android.os.Handler);
|
||||
method @RequiresPermission(anyOf={android.Manifest.permission.ACCESS_COARSE_LOCATION, android.Manifest.permission.ACCESS_FINE_LOCATION}) public void requestLocationUpdates(@NonNull android.location.LocationRequest, @NonNull android.location.LocationListener, @Nullable android.os.Looper);
|
||||
method @RequiresPermission(anyOf={android.Manifest.permission.ACCESS_COARSE_LOCATION, android.Manifest.permission.ACCESS_FINE_LOCATION}) public void requestLocationUpdates(@NonNull android.location.LocationRequest, @NonNull java.util.concurrent.Executor, @NonNull android.location.LocationListener);
|
||||
method @RequiresPermission(anyOf={android.Manifest.permission.ACCESS_COARSE_LOCATION, android.Manifest.permission.ACCESS_FINE_LOCATION}) public void requestLocationUpdates(@NonNull android.location.LocationRequest, @NonNull android.app.PendingIntent);
|
||||
method @RequiresPermission(android.Manifest.permission.LOCATION_HARDWARE) public void setExtraLocationControllerPackage(@Nullable String);
|
||||
method @RequiresPermission(android.Manifest.permission.LOCATION_HARDWARE) public void setExtraLocationControllerPackageEnabled(boolean);
|
||||
|
||||
@@ -1085,6 +1085,7 @@ package android.location {
|
||||
method @NonNull public String[] getIgnoreSettingsWhitelist();
|
||||
method @NonNull public java.util.List<android.location.LocationRequest> getTestProviderCurrentRequests(String);
|
||||
method @RequiresPermission(anyOf={android.Manifest.permission.ACCESS_COARSE_LOCATION, android.Manifest.permission.ACCESS_FINE_LOCATION}) public void requestLocationUpdates(@NonNull android.location.LocationRequest, @NonNull android.location.LocationListener, @Nullable android.os.Looper);
|
||||
method @RequiresPermission(anyOf={android.Manifest.permission.ACCESS_COARSE_LOCATION, android.Manifest.permission.ACCESS_FINE_LOCATION}) public void requestLocationUpdates(@NonNull android.location.LocationRequest, @NonNull java.util.concurrent.Executor, @NonNull android.location.LocationListener);
|
||||
method @RequiresPermission(anyOf={android.Manifest.permission.ACCESS_COARSE_LOCATION, android.Manifest.permission.ACCESS_FINE_LOCATION}) public void requestLocationUpdates(@NonNull android.location.LocationRequest, @NonNull android.app.PendingIntent);
|
||||
method @RequiresPermission(android.Manifest.permission.WRITE_SECURE_SETTINGS) public void setLocationEnabledForUser(boolean, @NonNull android.os.UserHandle);
|
||||
}
|
||||
|
||||
@@ -218,7 +218,6 @@ Landroid/location/ILocationManager$Stub$Proxy;-><init>(Landroid/os/IBinder;)V
|
||||
Landroid/location/ILocationManager$Stub;->asInterface(Landroid/os/IBinder;)Landroid/location/ILocationManager;
|
||||
Landroid/location/ILocationManager$Stub;->TRANSACTION_getAllProviders:I
|
||||
Landroid/location/INetInitiatedListener$Stub;-><init>()V
|
||||
Landroid/location/LocationManager$ListenerTransport;-><init>(Landroid/location/LocationManager;Landroid/location/LocationListener;Landroid/os/Looper;)V
|
||||
Landroid/Manifest$permission;->CAPTURE_SECURE_VIDEO_OUTPUT:Ljava/lang/String;
|
||||
Landroid/Manifest$permission;->CAPTURE_VIDEO_OUTPUT:Ljava/lang/String;
|
||||
Landroid/Manifest$permission;->READ_FRAME_BUFFER:Ljava/lang/String;
|
||||
|
||||
139
location/java/android/location/AbstractListenerManager.java
Normal file
139
location/java/android/location/AbstractListenerManager.java
Normal file
@@ -0,0 +1,139 @@
|
||||
/*
|
||||
* Copyright (C) 2014 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;
|
||||
|
||||
import android.annotation.NonNull;
|
||||
import android.annotation.Nullable;
|
||||
import android.os.Binder;
|
||||
import android.os.Handler;
|
||||
import android.os.HandlerExecutor;
|
||||
import android.os.RemoteException;
|
||||
import android.util.ArrayMap;
|
||||
|
||||
import com.android.internal.annotations.GuardedBy;
|
||||
import com.android.internal.util.Preconditions;
|
||||
|
||||
import java.util.concurrent.Executor;
|
||||
import java.util.function.Consumer;
|
||||
|
||||
/**
|
||||
* A base class to manage listeners that have a 1:N -> source:listener relationship.
|
||||
*
|
||||
* @hide
|
||||
*/
|
||||
abstract class AbstractListenerManager<T> {
|
||||
|
||||
private static class Registration<T> {
|
||||
private final Executor mExecutor;
|
||||
@Nullable private volatile T mListener;
|
||||
|
||||
private Registration(Executor executor, T listener) {
|
||||
Preconditions.checkArgument(listener != null);
|
||||
Preconditions.checkArgument(executor != null);
|
||||
mExecutor = executor;
|
||||
mListener = listener;
|
||||
}
|
||||
|
||||
private void unregister() {
|
||||
mListener = null;
|
||||
}
|
||||
|
||||
private void execute(Consumer<T> operation) {
|
||||
mExecutor.execute(() -> {
|
||||
T listener = mListener;
|
||||
if (listener == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
// we may be under the binder identity if a direct executor is used
|
||||
long identity = Binder.clearCallingIdentity();
|
||||
try {
|
||||
operation.accept(listener);
|
||||
} finally {
|
||||
Binder.restoreCallingIdentity(identity);
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
@GuardedBy("mListeners")
|
||||
private final ArrayMap<Object, Registration<T>> mListeners = new ArrayMap<>();
|
||||
|
||||
public boolean addListener(@NonNull T listener, @NonNull Handler handler)
|
||||
throws RemoteException {
|
||||
return addInternal(listener, handler);
|
||||
}
|
||||
|
||||
public boolean addListener(@NonNull T listener, @NonNull Executor executor)
|
||||
throws RemoteException {
|
||||
return addInternal(listener, executor);
|
||||
}
|
||||
|
||||
protected final boolean addInternal(Object listener, Handler handler) throws RemoteException {
|
||||
return addInternal(listener, new HandlerExecutor(handler));
|
||||
}
|
||||
|
||||
protected final boolean addInternal(Object listener, Executor executor) throws RemoteException {
|
||||
return addInternal(listener, new Registration<>(executor, convertKey(listener)));
|
||||
}
|
||||
|
||||
private boolean addInternal(Object key, Registration<T> registration) throws RemoteException {
|
||||
Preconditions.checkNotNull(key);
|
||||
Preconditions.checkNotNull(registration);
|
||||
|
||||
synchronized (mListeners) {
|
||||
if (mListeners.isEmpty() && !registerService()) {
|
||||
return false;
|
||||
}
|
||||
Registration<T> oldRegistration = mListeners.put(key, registration);
|
||||
if (oldRegistration != null) {
|
||||
oldRegistration.unregister();
|
||||
}
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
public void removeListener(Object listener) throws RemoteException {
|
||||
synchronized (mListeners) {
|
||||
Registration<T> oldRegistration = mListeners.remove(listener);
|
||||
if (oldRegistration == null) {
|
||||
return;
|
||||
}
|
||||
oldRegistration.unregister();
|
||||
|
||||
if (mListeners.isEmpty()) {
|
||||
unregisterService();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
protected T convertKey(@NonNull Object listener) {
|
||||
return (T) listener;
|
||||
}
|
||||
|
||||
protected abstract boolean registerService() throws RemoteException;
|
||||
protected abstract void unregisterService() throws RemoteException;
|
||||
|
||||
protected void execute(Consumer<T> operation) {
|
||||
synchronized (mListeners) {
|
||||
for (Registration<T> registration : mListeners.values()) {
|
||||
registration.execute(operation);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,66 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) 2017 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;
|
||||
|
||||
import android.content.Context;
|
||||
import android.os.RemoteException;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* A handler class to manage transport callbacks for {@link BatchedLocationCallback}.
|
||||
*
|
||||
* @hide
|
||||
*/
|
||||
class BatchedLocationCallbackTransport
|
||||
extends LocalListenerHelper<BatchedLocationCallback> {
|
||||
private final ILocationManager mLocationManager;
|
||||
|
||||
private final IBatchedLocationCallback mCallbackTransport = new CallbackTransport();
|
||||
|
||||
public BatchedLocationCallbackTransport(Context context, ILocationManager locationManager) {
|
||||
super(context, "BatchedLocationCallbackTransport");
|
||||
mLocationManager = locationManager;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected boolean registerWithServer() throws RemoteException {
|
||||
return mLocationManager.addGnssBatchingCallback(
|
||||
mCallbackTransport,
|
||||
getContext().getPackageName());
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void unregisterFromServer() throws RemoteException {
|
||||
mLocationManager.removeGnssBatchingCallback();
|
||||
}
|
||||
|
||||
private class CallbackTransport extends IBatchedLocationCallback.Stub {
|
||||
@Override
|
||||
public void onLocationBatch(final List<Location> locations) {
|
||||
ListenerOperation<BatchedLocationCallback> operation =
|
||||
new ListenerOperation<BatchedLocationCallback>() {
|
||||
@Override
|
||||
public void execute(BatchedLocationCallback callback)
|
||||
throws RemoteException {
|
||||
callback.onLocationBatch(locations);
|
||||
}
|
||||
};
|
||||
foreach(operation);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,97 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) 2014 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;
|
||||
|
||||
import android.content.Context;
|
||||
import android.os.RemoteException;
|
||||
|
||||
import com.android.internal.util.Preconditions;
|
||||
|
||||
/**
|
||||
* A handler class to manage transport callbacks for {@link GnssMeasurementsEvent.Callback}.
|
||||
*
|
||||
* @hide
|
||||
*/
|
||||
class GnssMeasurementCallbackTransport
|
||||
extends LocalListenerHelper<GnssMeasurementsEvent.Callback> {
|
||||
private static final String TAG = "GnssMeasCbTransport";
|
||||
private final ILocationManager mLocationManager;
|
||||
|
||||
private final IGnssMeasurementsListener mListenerTransport = new ListenerTransport();
|
||||
|
||||
public GnssMeasurementCallbackTransport(Context context, ILocationManager locationManager) {
|
||||
super(context, TAG);
|
||||
mLocationManager = locationManager;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected boolean registerWithServer() throws RemoteException {
|
||||
return mLocationManager.addGnssMeasurementsListener(
|
||||
mListenerTransport,
|
||||
getContext().getPackageName());
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void unregisterFromServer() throws RemoteException {
|
||||
mLocationManager.removeGnssMeasurementsListener(mListenerTransport);
|
||||
}
|
||||
|
||||
/**
|
||||
* Injects GNSS measurement corrections into the GNSS chipset.
|
||||
*
|
||||
* @param measurementCorrections a {@link GnssMeasurementCorrections} object with the GNSS
|
||||
* measurement corrections to be injected into the GNSS chipset.
|
||||
*/
|
||||
protected void injectGnssMeasurementCorrections(
|
||||
GnssMeasurementCorrections measurementCorrections) throws RemoteException {
|
||||
Preconditions.checkNotNull(measurementCorrections);
|
||||
mLocationManager.injectGnssMeasurementCorrections(
|
||||
measurementCorrections, getContext().getPackageName());
|
||||
}
|
||||
|
||||
protected long getGnssCapabilities() throws RemoteException {
|
||||
return mLocationManager.getGnssCapabilities(getContext().getPackageName());
|
||||
}
|
||||
|
||||
private class ListenerTransport extends IGnssMeasurementsListener.Stub {
|
||||
@Override
|
||||
public void onGnssMeasurementsReceived(final GnssMeasurementsEvent event) {
|
||||
ListenerOperation<GnssMeasurementsEvent.Callback> operation =
|
||||
new ListenerOperation<GnssMeasurementsEvent.Callback>() {
|
||||
@Override
|
||||
public void execute(GnssMeasurementsEvent.Callback callback)
|
||||
throws RemoteException {
|
||||
callback.onGnssMeasurementsReceived(event);
|
||||
}
|
||||
};
|
||||
foreach(operation);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onStatusChanged(final int status) {
|
||||
ListenerOperation<GnssMeasurementsEvent.Callback> operation =
|
||||
new ListenerOperation<GnssMeasurementsEvent.Callback>() {
|
||||
@Override
|
||||
public void execute(GnssMeasurementsEvent.Callback callback)
|
||||
throws RemoteException {
|
||||
callback.onStatusChanged(status);
|
||||
}
|
||||
};
|
||||
foreach(operation);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,79 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) 2014 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;
|
||||
|
||||
import android.content.Context;
|
||||
import android.os.RemoteException;
|
||||
|
||||
/**
|
||||
* A handler class to manage transport callback for {@link GnssNavigationMessage.Callback}.
|
||||
*
|
||||
* @hide
|
||||
*/
|
||||
class GnssNavigationMessageCallbackTransport
|
||||
extends LocalListenerHelper<GnssNavigationMessage.Callback> {
|
||||
private final ILocationManager mLocationManager;
|
||||
|
||||
private final IGnssNavigationMessageListener mListenerTransport = new ListenerTransport();
|
||||
|
||||
public GnssNavigationMessageCallbackTransport(
|
||||
Context context,
|
||||
ILocationManager locationManager) {
|
||||
super(context, "GnssNavigationMessageCallbackTransport");
|
||||
mLocationManager = locationManager;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected boolean registerWithServer() throws RemoteException {
|
||||
return mLocationManager.addGnssNavigationMessageListener(
|
||||
mListenerTransport,
|
||||
getContext().getPackageName());
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void unregisterFromServer() throws RemoteException {
|
||||
mLocationManager.removeGnssNavigationMessageListener(mListenerTransport);
|
||||
}
|
||||
|
||||
private class ListenerTransport extends IGnssNavigationMessageListener.Stub {
|
||||
@Override
|
||||
public void onGnssNavigationMessageReceived(final GnssNavigationMessage event) {
|
||||
ListenerOperation<GnssNavigationMessage.Callback> operation =
|
||||
new ListenerOperation<GnssNavigationMessage.Callback>() {
|
||||
@Override
|
||||
public void execute(GnssNavigationMessage.Callback callback)
|
||||
throws RemoteException {
|
||||
callback.onGnssNavigationMessageReceived(event);
|
||||
}
|
||||
};
|
||||
foreach(operation);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onStatusChanged(final int status) {
|
||||
ListenerOperation<GnssNavigationMessage.Callback> operation =
|
||||
new ListenerOperation<GnssNavigationMessage.Callback>() {
|
||||
@Override
|
||||
public void execute(GnssNavigationMessage.Callback callback)
|
||||
throws RemoteException {
|
||||
callback.onStatusChanged(status);
|
||||
}
|
||||
};
|
||||
foreach(operation);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,134 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) 2014 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;
|
||||
|
||||
import android.annotation.NonNull;
|
||||
import android.content.Context;
|
||||
import android.os.Handler;
|
||||
import android.os.RemoteException;
|
||||
import android.util.Log;
|
||||
|
||||
import com.android.internal.util.Preconditions;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collection;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* A base handler class to manage transport and local listeners.
|
||||
*
|
||||
* @hide
|
||||
*/
|
||||
abstract class LocalListenerHelper<TListener> {
|
||||
private final HashMap<TListener, Handler> mListeners = new HashMap<>();
|
||||
|
||||
private final String mTag;
|
||||
private final Context mContext;
|
||||
|
||||
protected LocalListenerHelper(Context context, String name) {
|
||||
Preconditions.checkNotNull(name);
|
||||
mContext = context;
|
||||
mTag = name;
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds a {@param listener} to the list of listeners on which callbacks will be executed. The
|
||||
* execution will happen on the {@param handler} thread or alternatively in the callback thread
|
||||
* if a {@code null} handler value is passed.
|
||||
*/
|
||||
public boolean add(@NonNull TListener listener, Handler handler) {
|
||||
Preconditions.checkNotNull(listener);
|
||||
synchronized (mListeners) {
|
||||
// we need to register with the service first, because we need to find out if the
|
||||
// service will actually support the request before we attempt anything
|
||||
if (mListeners.isEmpty()) {
|
||||
boolean registeredWithService;
|
||||
try {
|
||||
registeredWithService = registerWithServer();
|
||||
} catch (RemoteException e) {
|
||||
Log.e(mTag, "Error handling first listener.", e);
|
||||
return false;
|
||||
}
|
||||
if (!registeredWithService) {
|
||||
Log.e(mTag, "Unable to register listener transport.");
|
||||
return false;
|
||||
}
|
||||
}
|
||||
if (mListeners.containsKey(listener)) {
|
||||
return true;
|
||||
}
|
||||
mListeners.put(listener, handler);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
public void remove(@NonNull TListener listener) {
|
||||
Preconditions.checkNotNull(listener);
|
||||
synchronized (mListeners) {
|
||||
boolean removed = mListeners.containsKey(listener);
|
||||
mListeners.remove(listener);
|
||||
boolean isLastRemoved = removed && mListeners.isEmpty();
|
||||
if (isLastRemoved) {
|
||||
try {
|
||||
unregisterFromServer();
|
||||
} catch (RemoteException e) {
|
||||
Log.v(mTag, "Error handling last listener removal", e);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
protected abstract boolean registerWithServer() throws RemoteException;
|
||||
protected abstract void unregisterFromServer() throws RemoteException;
|
||||
|
||||
protected interface ListenerOperation<TListener> {
|
||||
void execute(TListener listener) throws RemoteException;
|
||||
}
|
||||
|
||||
protected Context getContext() {
|
||||
return mContext;
|
||||
}
|
||||
|
||||
private void executeOperation(ListenerOperation<TListener> operation, TListener listener) {
|
||||
try {
|
||||
operation.execute(listener);
|
||||
} catch (RemoteException e) {
|
||||
Log.e(mTag, "Error in monitored listener.", e);
|
||||
// don't return, give a fair chance to all listeners to receive the event
|
||||
}
|
||||
}
|
||||
|
||||
protected void foreach(final ListenerOperation<TListener> operation) {
|
||||
Collection<Map.Entry<TListener, Handler>> listeners;
|
||||
synchronized (mListeners) {
|
||||
listeners = new ArrayList<>(mListeners.entrySet());
|
||||
}
|
||||
for (final Map.Entry<TListener, Handler> listener : listeners) {
|
||||
if (listener.getValue() == null) {
|
||||
executeOperation(operation, listener.getKey());
|
||||
} else {
|
||||
listener.getValue().post(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
executeOperation(operation, listener.getKey());
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
File diff suppressed because it is too large
Load Diff
Reference in New Issue
Block a user