Merge "Add support for GPS measurement/navigation message capabilities. b/16727892 b/16815124" into lmp-mr1-dev
This commit is contained in:
@@ -26,14 +26,12 @@ import android.os.RemoteException;
|
||||
*/
|
||||
class GpsMeasurementListenerTransport
|
||||
extends LocalListenerHelper<GpsMeasurementsEvent.Listener> {
|
||||
private final Context mContext;
|
||||
private final ILocationManager mLocationManager;
|
||||
|
||||
private final IGpsMeasurementsListener mListenerTransport = new ListenerTransport();
|
||||
|
||||
public GpsMeasurementListenerTransport(Context context, ILocationManager locationManager) {
|
||||
super("GpsMeasurementListenerTransport");
|
||||
mContext = context;
|
||||
super(context, "GpsMeasurementListenerTransport");
|
||||
mLocationManager = locationManager;
|
||||
}
|
||||
|
||||
@@ -41,7 +39,7 @@ class GpsMeasurementListenerTransport
|
||||
protected boolean registerWithServer() throws RemoteException {
|
||||
return mLocationManager.addGpsMeasurementsListener(
|
||||
mListenerTransport,
|
||||
mContext.getPackageName());
|
||||
getContext().getPackageName());
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -59,7 +57,18 @@ class GpsMeasurementListenerTransport
|
||||
listener.onGpsMeasurementsReceived(event);
|
||||
}
|
||||
};
|
||||
foreach(operation);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onStatusChanged(final int status) {
|
||||
ListenerOperation<GpsMeasurementsEvent.Listener> operation =
|
||||
new ListenerOperation<GpsMeasurementsEvent.Listener>() {
|
||||
@Override
|
||||
public void execute(GpsMeasurementsEvent.Listener listener) throws RemoteException {
|
||||
listener.onStatusChanged(status);
|
||||
}
|
||||
};
|
||||
foreach(operation);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -32,6 +32,24 @@ import java.util.Collections;
|
||||
* @hide
|
||||
*/
|
||||
public class GpsMeasurementsEvent implements Parcelable {
|
||||
|
||||
/**
|
||||
* The system does not support tracking of GPS Measurements. This status will not change in the
|
||||
* future.
|
||||
*/
|
||||
public static final int STATUS_NOT_SUPPORTED = 0;
|
||||
|
||||
/**
|
||||
* GPS Measurements are successfully being tracked, it will receive updates once they are
|
||||
* available.
|
||||
*/
|
||||
public static final int STATUS_READY = 1;
|
||||
|
||||
/**
|
||||
* GPS provider or Location is disabled, updates will not be received until they are enabled.
|
||||
*/
|
||||
public static final int STATUS_GPS_LOCATION_DISABLED = 2;
|
||||
|
||||
private final GpsClock mClock;
|
||||
private final Collection<GpsMeasurement> mReadOnlyMeasurements;
|
||||
|
||||
@@ -43,7 +61,16 @@ public class GpsMeasurementsEvent implements Parcelable {
|
||||
* @hide
|
||||
*/
|
||||
public interface Listener {
|
||||
|
||||
/**
|
||||
* Returns the latest collected GPS Measurements.
|
||||
*/
|
||||
void onGpsMeasurementsReceived(GpsMeasurementsEvent eventArgs);
|
||||
|
||||
/**
|
||||
* Returns the latest status of the GPS Measurements sub-system.
|
||||
*/
|
||||
void onStatusChanged(int status);
|
||||
}
|
||||
|
||||
public GpsMeasurementsEvent(GpsClock clock, GpsMeasurement[] measurements) {
|
||||
@@ -103,7 +130,9 @@ public class GpsMeasurementsEvent implements Parcelable {
|
||||
public void writeToParcel(Parcel parcel, int flags) {
|
||||
parcel.writeParcelable(mClock, flags);
|
||||
|
||||
GpsMeasurement[] measurementsArray = mReadOnlyMeasurements.toArray(new GpsMeasurement[0]);
|
||||
int measurementsCount = mReadOnlyMeasurements.size();
|
||||
GpsMeasurement[] measurementsArray =
|
||||
mReadOnlyMeasurements.toArray(new GpsMeasurement[measurementsCount]);
|
||||
parcel.writeInt(measurementsArray.length);
|
||||
parcel.writeTypedArray(measurementsArray, flags);
|
||||
}
|
||||
|
||||
@@ -21,9 +21,6 @@ import android.os.Parcel;
|
||||
import android.os.Parcelable;
|
||||
|
||||
import java.security.InvalidParameterException;
|
||||
import java.util.Arrays;
|
||||
import java.util.Collection;
|
||||
import java.util.Collections;
|
||||
|
||||
/**
|
||||
* A class implementing a container for data associated with a navigation message event.
|
||||
@@ -32,6 +29,24 @@ import java.util.Collections;
|
||||
* @hide
|
||||
*/
|
||||
public class GpsNavigationMessageEvent implements Parcelable {
|
||||
|
||||
/**
|
||||
* The system does not support tracking of GPS Navigation Messages. This status will not change
|
||||
* in the future.
|
||||
*/
|
||||
public static int STATUS_NOT_SUPPORTED = 0;
|
||||
|
||||
/**
|
||||
* GPS Navigation Messages are successfully being tracked, it will receive updates once they are
|
||||
* available.
|
||||
*/
|
||||
public static int STATUS_READY = 1;
|
||||
|
||||
/**
|
||||
* GPS provider or Location is disabled, updated will not be received until they are enabled.
|
||||
*/
|
||||
public static int STATUS_GPS_LOCATION_DISABLED = 2;
|
||||
|
||||
private final GpsNavigationMessage mNavigationMessage;
|
||||
|
||||
/**
|
||||
@@ -42,7 +57,16 @@ public class GpsNavigationMessageEvent implements Parcelable {
|
||||
* @hide
|
||||
*/
|
||||
public interface Listener {
|
||||
|
||||
/**
|
||||
* Returns the latest collected GPS Navigation Message.
|
||||
*/
|
||||
void onGpsNavigationMessageReceived(GpsNavigationMessageEvent event);
|
||||
|
||||
/**
|
||||
* Returns the latest status of the GPS Navigation Messages sub-system.
|
||||
*/
|
||||
void onStatusChanged(int status);
|
||||
}
|
||||
|
||||
public GpsNavigationMessageEvent(GpsNavigationMessage message) {
|
||||
|
||||
@@ -26,7 +26,6 @@ import android.os.RemoteException;
|
||||
*/
|
||||
class GpsNavigationMessageListenerTransport
|
||||
extends LocalListenerHelper<GpsNavigationMessageEvent.Listener> {
|
||||
private final Context mContext;
|
||||
private final ILocationManager mLocationManager;
|
||||
|
||||
private final IGpsNavigationMessageListener mListenerTransport = new ListenerTransport();
|
||||
@@ -34,8 +33,7 @@ class GpsNavigationMessageListenerTransport
|
||||
public GpsNavigationMessageListenerTransport(
|
||||
Context context,
|
||||
ILocationManager locationManager) {
|
||||
super("GpsNavigationMessageListenerTransport");
|
||||
mContext = context;
|
||||
super(context, "GpsNavigationMessageListenerTransport");
|
||||
mLocationManager = locationManager;
|
||||
}
|
||||
|
||||
@@ -43,7 +41,7 @@ class GpsNavigationMessageListenerTransport
|
||||
protected boolean registerWithServer() throws RemoteException {
|
||||
return mLocationManager.addGpsNavigationMessageListener(
|
||||
mListenerTransport,
|
||||
mContext.getPackageName());
|
||||
getContext().getPackageName());
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -62,7 +60,19 @@ class GpsNavigationMessageListenerTransport
|
||||
listener.onGpsNavigationMessageReceived(event);
|
||||
}
|
||||
};
|
||||
foreach(operation);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onStatusChanged(final int status) {
|
||||
ListenerOperation<GpsNavigationMessageEvent.Listener> operation =
|
||||
new ListenerOperation<GpsNavigationMessageEvent.Listener>() {
|
||||
@Override
|
||||
public void execute(GpsNavigationMessageEvent.Listener listener)
|
||||
throws RemoteException {
|
||||
listener.onStatusChanged(status);
|
||||
}
|
||||
};
|
||||
foreach(operation);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -23,4 +23,5 @@ import android.location.GpsMeasurementsEvent;
|
||||
*/
|
||||
oneway interface IGpsMeasurementsListener {
|
||||
void onGpsMeasurementsReceived(in GpsMeasurementsEvent event);
|
||||
void onStatusChanged(in int status);
|
||||
}
|
||||
|
||||
@@ -23,4 +23,5 @@ import android.location.GpsNavigationMessageEvent;
|
||||
*/
|
||||
oneway interface IGpsNavigationMessageListener {
|
||||
void onGpsNavigationMessageReceived(in GpsNavigationMessageEvent event);
|
||||
void onStatusChanged(in int status);
|
||||
}
|
||||
|
||||
@@ -62,12 +62,12 @@ interface ILocationManager
|
||||
boolean sendNiResponse(int notifId, int userResponse);
|
||||
|
||||
boolean addGpsMeasurementsListener(in IGpsMeasurementsListener listener, in String packageName);
|
||||
boolean removeGpsMeasurementsListener(in IGpsMeasurementsListener listener);
|
||||
void removeGpsMeasurementsListener(in IGpsMeasurementsListener listener);
|
||||
|
||||
boolean addGpsNavigationMessageListener(
|
||||
in IGpsNavigationMessageListener listener,
|
||||
in String packageName);
|
||||
boolean removeGpsNavigationMessageListener(in IGpsNavigationMessageListener listener);
|
||||
void removeGpsNavigationMessageListener(in IGpsNavigationMessageListener listener);
|
||||
|
||||
// --- deprecated ---
|
||||
List<String> getAllProviders();
|
||||
|
||||
@@ -19,6 +19,7 @@ package android.location;
|
||||
import com.android.internal.util.Preconditions;
|
||||
|
||||
import android.annotation.NonNull;
|
||||
import android.content.Context;
|
||||
import android.os.RemoteException;
|
||||
import android.util.Log;
|
||||
|
||||
@@ -32,17 +33,19 @@ import java.util.HashSet;
|
||||
* @hide
|
||||
*/
|
||||
abstract class LocalListenerHelper<TListener> {
|
||||
private final HashSet<TListener> mListeners = new HashSet<TListener>();
|
||||
private final String mTag;
|
||||
private final HashSet<TListener> mListeners = new HashSet<>();
|
||||
|
||||
protected LocalListenerHelper(String name) {
|
||||
private final String mTag;
|
||||
private final Context mContext;
|
||||
|
||||
protected LocalListenerHelper(Context context, String name) {
|
||||
Preconditions.checkNotNull(name);
|
||||
mContext = context;
|
||||
mTag = name;
|
||||
}
|
||||
|
||||
public boolean add(@NonNull TListener listener) {
|
||||
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
|
||||
@@ -59,18 +62,15 @@ abstract class LocalListenerHelper<TListener> {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
if (mListeners.contains(listener)) {
|
||||
return true;
|
||||
}
|
||||
mListeners.add(listener);
|
||||
return mListeners.add(listener);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
public void remove(@NonNull TListener listener) {
|
||||
Preconditions.checkNotNull(listener);
|
||||
|
||||
synchronized (mListeners) {
|
||||
boolean removed = mListeners.remove(listener);
|
||||
boolean isLastRemoved = removed && mListeners.isEmpty();
|
||||
@@ -78,7 +78,7 @@ abstract class LocalListenerHelper<TListener> {
|
||||
try {
|
||||
unregisterFromServer();
|
||||
} catch (RemoteException e) {
|
||||
|
||||
Log.v(mTag, "Error handling last listener removal", e);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -91,12 +91,15 @@ abstract class LocalListenerHelper<TListener> {
|
||||
void execute(TListener listener) throws RemoteException;
|
||||
}
|
||||
|
||||
protected void foreach(ListenerOperation operation) {
|
||||
protected Context getContext() {
|
||||
return mContext;
|
||||
}
|
||||
|
||||
protected void foreach(ListenerOperation<TListener> operation) {
|
||||
Collection<TListener> listeners;
|
||||
synchronized (mListeners) {
|
||||
listeners = new ArrayList<TListener>(mListeners);
|
||||
listeners = new ArrayList<>(mListeners);
|
||||
}
|
||||
|
||||
for (TListener listener : listeners) {
|
||||
try {
|
||||
operation.execute(listener);
|
||||
|
||||
@@ -1579,7 +1579,7 @@ public class LocationManager {
|
||||
* Adds a GPS Measurement listener.
|
||||
*
|
||||
* @param listener a {@link GpsMeasurementsEvent.Listener} object to register.
|
||||
* @return {@code true} if the listener was successfully registered, {@code false} otherwise.
|
||||
* @return {@code true} if the listener was added successfully, {@code false} otherwise.
|
||||
*
|
||||
* @hide
|
||||
*/
|
||||
@@ -1602,7 +1602,7 @@ public class LocationManager {
|
||||
* Adds a GPS Navigation Message listener.
|
||||
*
|
||||
* @param listener a {@link GpsNavigationMessageEvent.Listener} object to register.
|
||||
* @return {@code true} if the listener was successfully registered, {@code false} otherwise.
|
||||
* @return {@code true} if the listener was added successfully, {@code false} otherwise.
|
||||
*
|
||||
* @hide
|
||||
*/
|
||||
|
||||
@@ -60,6 +60,8 @@ import android.location.Address;
|
||||
import android.location.Criteria;
|
||||
import android.location.GeocoderParams;
|
||||
import android.location.Geofence;
|
||||
import android.location.GpsMeasurementsEvent;
|
||||
import android.location.GpsNavigationMessageEvent;
|
||||
import android.location.IGpsMeasurementsListener;
|
||||
import android.location.IGpsNavigationMessageListener;
|
||||
import android.location.IGpsStatusListener;
|
||||
@@ -1859,8 +1861,8 @@ public class LocationManagerService extends ILocationManager.Stub {
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean removeGpsMeasurementsListener(IGpsMeasurementsListener listener) {
|
||||
return mGpsMeasurementsProvider.removeListener(listener);
|
||||
public void removeGpsMeasurementsListener(IGpsMeasurementsListener listener) {
|
||||
mGpsMeasurementsProvider.removeListener(listener);
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -1888,8 +1890,8 @@ public class LocationManagerService extends ILocationManager.Stub {
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean removeGpsNavigationMessageListener(IGpsNavigationMessageListener listener) {
|
||||
return mGpsNavigationMessageProvider.removeListener(listener);
|
||||
public void removeGpsNavigationMessageListener(IGpsNavigationMessageListener listener) {
|
||||
mGpsNavigationMessageProvider.removeListener(listener);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
@@ -162,6 +162,9 @@ public class GpsLocationProvider implements LocationProviderInterface {
|
||||
private static final int GPS_CAPABILITY_MSA = 0x0000004;
|
||||
private static final int GPS_CAPABILITY_SINGLE_SHOT = 0x0000008;
|
||||
private static final int GPS_CAPABILITY_ON_DEMAND_TIME = 0x0000010;
|
||||
private static final int GPS_CAPABILITY_GEOFENCING = 0x0000020;
|
||||
private static final int GPS_CAPABILITY_MEASUREMENTS = 0x0000040;
|
||||
private static final int GPS_CAPABILITY_NAV_MESSAGES = 0x0000080;
|
||||
|
||||
// The AGPS SUPL mode
|
||||
private static final int AGPS_SUPL_MODE_MSA = 0x02;
|
||||
@@ -348,20 +351,9 @@ public class GpsLocationProvider implements LocationProviderInterface {
|
||||
private final ILocationManager mILocationManager;
|
||||
private Location mLocation = new Location(LocationManager.GPS_PROVIDER);
|
||||
private Bundle mLocationExtras = new Bundle();
|
||||
private GpsStatusListenerHelper mListenerHelper = new GpsStatusListenerHelper() {
|
||||
@Override
|
||||
protected boolean isSupported() {
|
||||
return GpsLocationProvider.isSupported();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected boolean registerWithService() {
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void unregisterFromService() {}
|
||||
};
|
||||
private final GpsStatusListenerHelper mListenerHelper;
|
||||
private final GpsMeasurementsProvider mGpsMeasurementsProvider;
|
||||
private final GpsNavigationMessageProvider mGpsNavigationMessageProvider;
|
||||
|
||||
// Handler for processing events
|
||||
private Handler mHandler;
|
||||
@@ -409,41 +401,6 @@ public class GpsLocationProvider implements LocationProviderInterface {
|
||||
}
|
||||
};
|
||||
|
||||
private final GpsMeasurementsProvider mGpsMeasurementsProvider = new GpsMeasurementsProvider() {
|
||||
@Override
|
||||
public boolean isSupported() {
|
||||
return native_is_measurement_supported();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected boolean registerWithService() {
|
||||
return native_start_measurement_collection();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void unregisterFromService() {
|
||||
native_stop_measurement_collection();
|
||||
}
|
||||
};
|
||||
|
||||
private final GpsNavigationMessageProvider mGpsNavigationMessageProvider =
|
||||
new GpsNavigationMessageProvider() {
|
||||
@Override
|
||||
protected boolean isSupported() {
|
||||
return native_is_navigation_message_supported();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected boolean registerWithService() {
|
||||
return native_start_navigation_message_collection();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void unregisterFromService() {
|
||||
native_stop_navigation_message_collection();
|
||||
}
|
||||
};
|
||||
|
||||
public IGpsStatusProvider getGpsStatusProvider() {
|
||||
return mGpsStatusProvider;
|
||||
}
|
||||
@@ -696,6 +653,62 @@ public class GpsLocationProvider implements LocationProviderInterface {
|
||||
mHandler.getLooper());
|
||||
}
|
||||
});
|
||||
|
||||
mListenerHelper = new GpsStatusListenerHelper(mHandler) {
|
||||
@Override
|
||||
protected boolean isAvailableInPlatform() {
|
||||
return GpsLocationProvider.isSupported();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected boolean isGpsEnabled() {
|
||||
return isEnabled();
|
||||
}
|
||||
};
|
||||
|
||||
mGpsMeasurementsProvider = new GpsMeasurementsProvider(mHandler) {
|
||||
@Override
|
||||
public boolean isAvailableInPlatform() {
|
||||
return native_is_measurement_supported();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected boolean registerWithService() {
|
||||
return native_start_measurement_collection();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void unregisterFromService() {
|
||||
native_stop_measurement_collection();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected boolean isGpsEnabled() {
|
||||
return isEnabled();
|
||||
}
|
||||
};
|
||||
|
||||
mGpsNavigationMessageProvider = new GpsNavigationMessageProvider(mHandler) {
|
||||
@Override
|
||||
protected boolean isAvailableInPlatform() {
|
||||
return native_is_navigation_message_supported();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected boolean registerWithService() {
|
||||
return native_start_navigation_message_collection();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void unregisterFromService() {
|
||||
native_stop_navigation_message_collection();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected boolean isGpsEnabled() {
|
||||
return isEnabled();
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
private void listenForBroadcasts() {
|
||||
@@ -1445,7 +1458,9 @@ public class GpsLocationProvider implements LocationProviderInterface {
|
||||
}
|
||||
|
||||
if (wasNavigating != mNavigating) {
|
||||
mListenerHelper.onStatusChanged(mNavigating);
|
||||
mListenerHelper.onGpsEnabledChanged(mNavigating);
|
||||
mGpsMeasurementsProvider.onGpsEnabledChanged(mNavigating);
|
||||
mGpsNavigationMessageProvider.onGpsEnabledChanged(mNavigating);
|
||||
|
||||
// send an intent to notify that the GPS has been enabled or disabled
|
||||
Intent intent = new Intent(LocationManager.GPS_ENABLED_CHANGE_ACTION);
|
||||
@@ -1598,6 +1613,11 @@ public class GpsLocationProvider implements LocationProviderInterface {
|
||||
mPeriodicTimeInjection = true;
|
||||
requestUtcTime();
|
||||
}
|
||||
|
||||
mGpsMeasurementsProvider.onCapabilitiesUpdated(
|
||||
(capabilities & GPS_CAPABILITY_MEASUREMENTS) == GPS_CAPABILITY_MEASUREMENTS);
|
||||
mGpsNavigationMessageProvider.onCapabilitiesUpdated(
|
||||
(capabilities & GPS_CAPABILITY_NAV_MESSAGES) == GPS_CAPABILITY_NAV_MESSAGES);
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -18,7 +18,9 @@ package com.android.server.location;
|
||||
|
||||
import android.location.GpsMeasurementsEvent;
|
||||
import android.location.IGpsMeasurementsListener;
|
||||
import android.os.Handler;
|
||||
import android.os.RemoteException;
|
||||
import android.util.Log;
|
||||
|
||||
/**
|
||||
* An base implementation for GPS measurements provider.
|
||||
@@ -29,8 +31,10 @@ import android.os.RemoteException;
|
||||
*/
|
||||
public abstract class GpsMeasurementsProvider
|
||||
extends RemoteListenerHelper<IGpsMeasurementsListener> {
|
||||
public GpsMeasurementsProvider() {
|
||||
super("GpsMeasurementsProvider");
|
||||
private static final String TAG = "GpsMeasurementsProvider";
|
||||
|
||||
public GpsMeasurementsProvider(Handler handler) {
|
||||
super(handler, TAG);
|
||||
}
|
||||
|
||||
public void onMeasurementsAvailable(final GpsMeasurementsEvent event) {
|
||||
@@ -41,7 +45,56 @@ public abstract class GpsMeasurementsProvider
|
||||
listener.onGpsMeasurementsReceived(event);
|
||||
}
|
||||
};
|
||||
|
||||
foreach(operation);
|
||||
}
|
||||
|
||||
public void onCapabilitiesUpdated(boolean isGpsMeasurementsSupported) {
|
||||
int status = isGpsMeasurementsSupported ?
|
||||
GpsMeasurementsEvent.STATUS_READY :
|
||||
GpsMeasurementsEvent.STATUS_NOT_SUPPORTED;
|
||||
setSupported(isGpsMeasurementsSupported, new StatusChangedOperation(status));
|
||||
}
|
||||
|
||||
@Override
|
||||
protected ListenerOperation<IGpsMeasurementsListener> getHandlerOperation(int result) {
|
||||
final int status;
|
||||
switch (result) {
|
||||
case RESULT_SUCCESS:
|
||||
status = GpsMeasurementsEvent.STATUS_READY;
|
||||
break;
|
||||
case RESULT_NOT_AVAILABLE:
|
||||
case RESULT_NOT_SUPPORTED:
|
||||
case RESULT_INTERNAL_ERROR:
|
||||
status = GpsMeasurementsEvent.STATUS_NOT_SUPPORTED;
|
||||
break;
|
||||
case RESULT_GPS_LOCATION_DISABLED:
|
||||
status = GpsMeasurementsEvent.STATUS_GPS_LOCATION_DISABLED;
|
||||
break;
|
||||
default:
|
||||
Log.v(TAG, "Unhandled addListener result: " + result);
|
||||
return null;
|
||||
}
|
||||
return new StatusChangedOperation(status);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void handleGpsEnabledChanged(boolean enabled) {
|
||||
int status = enabled ?
|
||||
GpsMeasurementsEvent.STATUS_READY :
|
||||
GpsMeasurementsEvent.STATUS_GPS_LOCATION_DISABLED;
|
||||
foreach(new StatusChangedOperation(status));
|
||||
}
|
||||
|
||||
private class StatusChangedOperation implements ListenerOperation<IGpsMeasurementsListener> {
|
||||
private final int mStatus;
|
||||
|
||||
public StatusChangedOperation(int status) {
|
||||
mStatus = status;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void execute(IGpsMeasurementsListener listener) throws RemoteException {
|
||||
listener.onStatusChanged(mStatus);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -18,7 +18,9 @@ package com.android.server.location;
|
||||
|
||||
import android.location.GpsNavigationMessageEvent;
|
||||
import android.location.IGpsNavigationMessageListener;
|
||||
import android.os.Handler;
|
||||
import android.os.RemoteException;
|
||||
import android.util.Log;
|
||||
|
||||
/**
|
||||
* An base implementation for GPS navigation messages provider.
|
||||
@@ -29,8 +31,10 @@ import android.os.RemoteException;
|
||||
*/
|
||||
public abstract class GpsNavigationMessageProvider
|
||||
extends RemoteListenerHelper<IGpsNavigationMessageListener> {
|
||||
public GpsNavigationMessageProvider() {
|
||||
super("GpsNavigationMessageProvider");
|
||||
private static final String TAG = "GpsNavigationMessageProvider";
|
||||
|
||||
public GpsNavigationMessageProvider(Handler handler) {
|
||||
super(handler, TAG);
|
||||
}
|
||||
|
||||
public void onNavigationMessageAvailable(final GpsNavigationMessageEvent event) {
|
||||
@@ -42,7 +46,57 @@ public abstract class GpsNavigationMessageProvider
|
||||
listener.onGpsNavigationMessageReceived(event);
|
||||
}
|
||||
};
|
||||
|
||||
foreach(operation);
|
||||
}
|
||||
|
||||
public void onCapabilitiesUpdated(boolean isGpsNavigationMessageSupported) {
|
||||
int status = isGpsNavigationMessageSupported ?
|
||||
GpsNavigationMessageEvent.STATUS_READY :
|
||||
GpsNavigationMessageEvent.STATUS_NOT_SUPPORTED;
|
||||
setSupported(isGpsNavigationMessageSupported, new StatusChangedOperation(status));
|
||||
}
|
||||
|
||||
@Override
|
||||
protected ListenerOperation<IGpsNavigationMessageListener> getHandlerOperation(int result) {
|
||||
final int status;
|
||||
switch (result) {
|
||||
case RESULT_SUCCESS:
|
||||
status = GpsNavigationMessageEvent.STATUS_READY;
|
||||
break;
|
||||
case RESULT_NOT_AVAILABLE:
|
||||
case RESULT_NOT_SUPPORTED:
|
||||
case RESULT_INTERNAL_ERROR:
|
||||
status = GpsNavigationMessageEvent.STATUS_NOT_SUPPORTED;
|
||||
break;
|
||||
case RESULT_GPS_LOCATION_DISABLED:
|
||||
status = GpsNavigationMessageEvent.STATUS_GPS_LOCATION_DISABLED;
|
||||
break;
|
||||
default:
|
||||
Log.v(TAG, "Unhandled addListener result: " + result);
|
||||
return null;
|
||||
}
|
||||
return new StatusChangedOperation(status);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void handleGpsEnabledChanged(boolean enabled) {
|
||||
int status = enabled ?
|
||||
GpsNavigationMessageEvent.STATUS_READY :
|
||||
GpsNavigationMessageEvent.STATUS_GPS_LOCATION_DISABLED;
|
||||
foreach(new StatusChangedOperation(status));
|
||||
}
|
||||
|
||||
private class StatusChangedOperation
|
||||
implements ListenerOperation<IGpsNavigationMessageListener> {
|
||||
private final int mStatus;
|
||||
|
||||
public StatusChangedOperation(int status) {
|
||||
mStatus = status;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void execute(IGpsNavigationMessageListener listener) throws RemoteException {
|
||||
listener.onStatusChanged(mStatus);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -17,14 +17,55 @@
|
||||
package com.android.server.location;
|
||||
|
||||
import android.location.IGpsStatusListener;
|
||||
import android.os.Handler;
|
||||
import android.os.RemoteException;
|
||||
|
||||
/**
|
||||
* Implementation of a handler for {@link IGpsStatusListener}.
|
||||
*/
|
||||
abstract class GpsStatusListenerHelper extends RemoteListenerHelper<IGpsStatusListener> {
|
||||
public GpsStatusListenerHelper() {
|
||||
super("GpsStatusListenerHelper");
|
||||
public GpsStatusListenerHelper(Handler handler) {
|
||||
super(handler, "GpsStatusListenerHelper");
|
||||
|
||||
Operation nullOperation = new Operation() {
|
||||
@Override
|
||||
public void execute(IGpsStatusListener iGpsStatusListener) throws RemoteException {}
|
||||
};
|
||||
setSupported(GpsLocationProvider.isSupported(), nullOperation);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected boolean registerWithService() {
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void unregisterFromService() {}
|
||||
|
||||
@Override
|
||||
protected ListenerOperation<IGpsStatusListener> getHandlerOperation(int result) {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void handleGpsEnabledChanged(boolean enabled) {
|
||||
Operation operation;
|
||||
if (enabled) {
|
||||
operation = new Operation() {
|
||||
@Override
|
||||
public void execute(IGpsStatusListener listener) throws RemoteException {
|
||||
listener.onGpsStarted();
|
||||
}
|
||||
};
|
||||
} else {
|
||||
operation = new Operation() {
|
||||
@Override
|
||||
public void execute(IGpsStatusListener listener) throws RemoteException {
|
||||
listener.onGpsStopped();
|
||||
}
|
||||
};
|
||||
}
|
||||
foreach(operation);
|
||||
}
|
||||
|
||||
public void onFirstFix(final int timeToFirstFix) {
|
||||
@@ -34,22 +75,6 @@ abstract class GpsStatusListenerHelper extends RemoteListenerHelper<IGpsStatusLi
|
||||
listener.onFirstFix(timeToFirstFix);
|
||||
}
|
||||
};
|
||||
|
||||
foreach(operation);
|
||||
}
|
||||
|
||||
public void onStatusChanged(final boolean isNavigating) {
|
||||
Operation operation = new Operation() {
|
||||
@Override
|
||||
public void execute(IGpsStatusListener listener) throws RemoteException {
|
||||
if (isNavigating) {
|
||||
listener.onGpsStarted();
|
||||
} else {
|
||||
listener.onGpsStopped();
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
foreach(operation);
|
||||
}
|
||||
|
||||
@@ -76,7 +101,6 @@ abstract class GpsStatusListenerHelper extends RemoteListenerHelper<IGpsStatusLi
|
||||
usedInFixMask);
|
||||
}
|
||||
};
|
||||
|
||||
foreach(operation);
|
||||
}
|
||||
|
||||
@@ -87,7 +111,6 @@ abstract class GpsStatusListenerHelper extends RemoteListenerHelper<IGpsStatusLi
|
||||
listener.onNmeaReceived(timestamp, nmea);
|
||||
}
|
||||
};
|
||||
|
||||
foreach(operation);
|
||||
}
|
||||
|
||||
|
||||
@@ -19,35 +19,41 @@ package com.android.server.location;
|
||||
import com.android.internal.util.Preconditions;
|
||||
|
||||
import android.annotation.NonNull;
|
||||
import android.os.Handler;
|
||||
import android.os.IBinder;
|
||||
import android.os.IInterface;
|
||||
import android.os.RemoteException;
|
||||
import android.util.Log;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collection;
|
||||
import java.util.HashMap;
|
||||
|
||||
/**
|
||||
* A helper class, that handles operations in remote listeners, and tracks for remote process death.
|
||||
*/
|
||||
abstract class RemoteListenerHelper<TListener extends IInterface> {
|
||||
private final String mTag;
|
||||
private final HashMap<IBinder, LinkedListener> mListenerMap =
|
||||
new HashMap<IBinder, LinkedListener>();
|
||||
protected static final int RESULT_SUCCESS = 0;
|
||||
protected static final int RESULT_NOT_AVAILABLE = 1;
|
||||
protected static final int RESULT_NOT_SUPPORTED = 2;
|
||||
protected static final int RESULT_GPS_LOCATION_DISABLED = 3;
|
||||
protected static final int RESULT_INTERNAL_ERROR = 4;
|
||||
|
||||
protected RemoteListenerHelper(String name) {
|
||||
private final Handler mHandler;
|
||||
private final String mTag;
|
||||
|
||||
private final HashMap<IBinder, LinkedListener> mListenerMap = new HashMap<>();
|
||||
|
||||
private boolean mIsRegistered;
|
||||
private boolean mHasIsSupported;
|
||||
private boolean mIsSupported;
|
||||
|
||||
protected RemoteListenerHelper(Handler handler, String name) {
|
||||
Preconditions.checkNotNull(name);
|
||||
mHandler = handler;
|
||||
mTag = name;
|
||||
}
|
||||
|
||||
public boolean addListener(@NonNull TListener listener) {
|
||||
Preconditions.checkNotNull(listener, "Attempted to register a 'null' listener.");
|
||||
if (!isSupported()) {
|
||||
Log.e(mTag, "Refused to add listener, the feature is not supported.");
|
||||
return false;
|
||||
}
|
||||
|
||||
IBinder binder = listener.asBinder();
|
||||
LinkedListener deathListener = new LinkedListener(listener);
|
||||
synchronized (mListenerMap) {
|
||||
@@ -55,77 +61,128 @@ abstract class RemoteListenerHelper<TListener extends IInterface> {
|
||||
// listener already added
|
||||
return true;
|
||||
}
|
||||
|
||||
try {
|
||||
binder.linkToDeath(deathListener, 0 /* flags */);
|
||||
} catch (RemoteException e) {
|
||||
// if the remote process registering the listener is already death, just swallow the
|
||||
// exception and continue
|
||||
Log.e(mTag, "Remote listener already died.", e);
|
||||
// exception and return
|
||||
Log.v(mTag, "Remote listener already died.", e);
|
||||
return false;
|
||||
}
|
||||
|
||||
mListenerMap.put(binder, deathListener);
|
||||
if (mListenerMap.size() == 1) {
|
||||
if (!registerWithService()) {
|
||||
Log.e(mTag, "RegisterWithService failed, listener will be removed.");
|
||||
removeListener(listener);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// update statuses we already know about, starting from the ones that will never change
|
||||
int result;
|
||||
if (!isAvailableInPlatform()) {
|
||||
result = RESULT_NOT_AVAILABLE;
|
||||
} else if (mHasIsSupported && !mIsSupported) {
|
||||
result = RESULT_NOT_SUPPORTED;
|
||||
} else if (!isGpsEnabled()) {
|
||||
result = RESULT_GPS_LOCATION_DISABLED;
|
||||
} else if (!tryRegister()) {
|
||||
// only attempt to register if GPS is enabled, otherwise we will register once GPS
|
||||
// becomes available
|
||||
result = RESULT_INTERNAL_ERROR;
|
||||
} else if (mHasIsSupported && mIsSupported) {
|
||||
result = RESULT_SUCCESS;
|
||||
} else {
|
||||
// at this point if the supported flag is not set, the notification will be sent
|
||||
// asynchronously in the future
|
||||
return true;
|
||||
}
|
||||
post(listener, getHandlerOperation(result));
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
public boolean removeListener(@NonNull TListener listener) {
|
||||
public void removeListener(@NonNull TListener listener) {
|
||||
Preconditions.checkNotNull(listener, "Attempted to remove a 'null' listener.");
|
||||
if (!isSupported()) {
|
||||
Log.e(mTag, "Refused to remove listener, the feature is not supported.");
|
||||
return false;
|
||||
}
|
||||
|
||||
IBinder binder = listener.asBinder();
|
||||
LinkedListener linkedListener;
|
||||
synchronized (mListenerMap) {
|
||||
linkedListener = mListenerMap.remove(binder);
|
||||
if (mListenerMap.isEmpty() && linkedListener != null) {
|
||||
unregisterFromService();
|
||||
if (mListenerMap.isEmpty()) {
|
||||
tryUnregister();
|
||||
}
|
||||
}
|
||||
|
||||
if (linkedListener != null) {
|
||||
binder.unlinkToDeath(linkedListener, 0 /* flags */);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
protected abstract boolean isSupported();
|
||||
public void onGpsEnabledChanged(boolean enabled) {
|
||||
// handle first the sub-class implementation, so any error in registration can take
|
||||
// precedence
|
||||
handleGpsEnabledChanged(enabled);
|
||||
synchronized (mListenerMap) {
|
||||
if (!enabled) {
|
||||
tryUnregister();
|
||||
return;
|
||||
}
|
||||
if (mListenerMap.isEmpty()) {
|
||||
return;
|
||||
}
|
||||
if (tryRegister()) {
|
||||
// registration was successful, there is no need to update the state
|
||||
return;
|
||||
}
|
||||
ListenerOperation<TListener> operation = getHandlerOperation(RESULT_INTERNAL_ERROR);
|
||||
foreachUnsafe(operation);
|
||||
}
|
||||
}
|
||||
|
||||
protected abstract boolean isAvailableInPlatform();
|
||||
protected abstract boolean isGpsEnabled();
|
||||
protected abstract boolean registerWithService();
|
||||
protected abstract void unregisterFromService();
|
||||
protected abstract ListenerOperation<TListener> getHandlerOperation(int result);
|
||||
protected abstract void handleGpsEnabledChanged(boolean enabled);
|
||||
|
||||
protected interface ListenerOperation<TListener extends IInterface> {
|
||||
void execute(TListener listener) throws RemoteException;
|
||||
}
|
||||
|
||||
protected void foreach(ListenerOperation operation) {
|
||||
Collection<LinkedListener> linkedListeners;
|
||||
protected void foreach(ListenerOperation<TListener> operation) {
|
||||
synchronized (mListenerMap) {
|
||||
Collection<LinkedListener> values = mListenerMap.values();
|
||||
linkedListeners = new ArrayList<LinkedListener>(values);
|
||||
foreachUnsafe(operation);
|
||||
}
|
||||
}
|
||||
|
||||
for (LinkedListener linkedListener : linkedListeners) {
|
||||
TListener listener = linkedListener.getUnderlyingListener();
|
||||
try {
|
||||
operation.execute(listener);
|
||||
} catch (RemoteException e) {
|
||||
Log.e(mTag, "Error in monitored listener.", e);
|
||||
removeListener(listener);
|
||||
}
|
||||
protected void setSupported(boolean value, ListenerOperation<TListener> notifier) {
|
||||
synchronized (mListenerMap) {
|
||||
mHasIsSupported = true;
|
||||
mIsSupported = value;
|
||||
foreachUnsafe(notifier);
|
||||
}
|
||||
}
|
||||
|
||||
private void foreachUnsafe(ListenerOperation<TListener> operation) {
|
||||
for (LinkedListener linkedListener : mListenerMap.values()) {
|
||||
post(linkedListener.getUnderlyingListener(), operation);
|
||||
}
|
||||
}
|
||||
|
||||
private void post(TListener listener, ListenerOperation<TListener> operation) {
|
||||
if (operation != null) {
|
||||
mHandler.post(new HandlerRunnable(listener, operation));
|
||||
}
|
||||
}
|
||||
|
||||
private boolean tryRegister() {
|
||||
if (!mIsRegistered) {
|
||||
mIsRegistered = registerWithService();
|
||||
}
|
||||
return mIsRegistered;
|
||||
}
|
||||
|
||||
private void tryUnregister() {
|
||||
if (!mIsRegistered) {
|
||||
return;
|
||||
}
|
||||
unregisterFromService();
|
||||
mIsRegistered = false;
|
||||
}
|
||||
|
||||
private class LinkedListener implements IBinder.DeathRecipient {
|
||||
private final TListener mListener;
|
||||
|
||||
@@ -144,4 +201,23 @@ abstract class RemoteListenerHelper<TListener extends IInterface> {
|
||||
removeListener(mListener);
|
||||
}
|
||||
}
|
||||
|
||||
private class HandlerRunnable implements Runnable {
|
||||
private final TListener mListener;
|
||||
private final ListenerOperation<TListener> mOperation;
|
||||
|
||||
public HandlerRunnable(TListener listener, ListenerOperation<TListener> operation) {
|
||||
mListener = listener;
|
||||
mOperation = operation;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void run() {
|
||||
try {
|
||||
mOperation.execute(mListener);
|
||||
} catch (RemoteException e) {
|
||||
Log.v(mTag, "Error in monitored listener.", e);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user