summaryrefslogtreecommitdiffstats
path: root/services
diff options
context:
space:
mode:
Diffstat (limited to 'services')
-rw-r--r--services/core/java/com/android/server/LocationManagerService.java10
-rw-r--r--services/core/java/com/android/server/location/GpsLocationProvider.java120
-rw-r--r--services/core/java/com/android/server/location/GpsMeasurementsProvider.java59
-rw-r--r--services/core/java/com/android/server/location/GpsNavigationMessageProvider.java60
-rw-r--r--services/core/java/com/android/server/location/GpsStatusListenerHelper.java57
-rw-r--r--services/core/java/com/android/server/location/RemoteListenerHelper.java164
6 files changed, 349 insertions, 121 deletions
diff --git a/services/core/java/com/android/server/LocationManagerService.java b/services/core/java/com/android/server/LocationManagerService.java
index d9c96e4..be83b9b 100644
--- a/services/core/java/com/android/server/LocationManagerService.java
+++ b/services/core/java/com/android/server/LocationManagerService.java
@@ -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
diff --git a/services/core/java/com/android/server/location/GpsLocationProvider.java b/services/core/java/com/android/server/location/GpsLocationProvider.java
index 46c8221..7354137 100644
--- a/services/core/java/com/android/server/location/GpsLocationProvider.java
+++ b/services/core/java/com/android/server/location/GpsLocationProvider.java
@@ -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);
}
/**
diff --git a/services/core/java/com/android/server/location/GpsMeasurementsProvider.java b/services/core/java/com/android/server/location/GpsMeasurementsProvider.java
index 1c48257..0514e0c 100644
--- a/services/core/java/com/android/server/location/GpsMeasurementsProvider.java
+++ b/services/core/java/com/android/server/location/GpsMeasurementsProvider.java
@@ -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);
+ }
+ }
}
diff --git a/services/core/java/com/android/server/location/GpsNavigationMessageProvider.java b/services/core/java/com/android/server/location/GpsNavigationMessageProvider.java
index fca7378..13d22fc 100644
--- a/services/core/java/com/android/server/location/GpsNavigationMessageProvider.java
+++ b/services/core/java/com/android/server/location/GpsNavigationMessageProvider.java
@@ -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);
+ }
+ }
}
diff --git a/services/core/java/com/android/server/location/GpsStatusListenerHelper.java b/services/core/java/com/android/server/location/GpsStatusListenerHelper.java
index 27cf3d8..376b4a5 100644
--- a/services/core/java/com/android/server/location/GpsStatusListenerHelper.java
+++ b/services/core/java/com/android/server/location/GpsStatusListenerHelper.java
@@ -17,39 +17,64 @@
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");
- public void onFirstFix(final int timeToFirstFix) {
- Operation operation = new Operation() {
+ Operation nullOperation = new Operation() {
@Override
- public void execute(IGpsStatusListener listener) throws RemoteException {
- listener.onFirstFix(timeToFirstFix);
- }
+ 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 onStatusChanged(final boolean isNavigating) {
+ public void onFirstFix(final int timeToFirstFix) {
Operation operation = new Operation() {
@Override
public void execute(IGpsStatusListener listener) throws RemoteException {
- if (isNavigating) {
- listener.onGpsStarted();
- } else {
- listener.onGpsStopped();
- }
+ listener.onFirstFix(timeToFirstFix);
}
};
-
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);
}
diff --git a/services/core/java/com/android/server/location/RemoteListenerHelper.java b/services/core/java/com/android/server/location/RemoteListenerHelper.java
index 451af18..402b601 100644
--- a/services/core/java/com/android/server/location/RemoteListenerHelper.java
+++ b/services/core/java/com/android/server/location/RemoteListenerHelper.java
@@ -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> {
+ 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;
+
+ private final Handler mHandler;
private final String mTag;
- private final HashMap<IBinder, LinkedListener> mListenerMap =
- new HashMap<IBinder, LinkedListener>();
- protected RemoteListenerHelper(String name) {
+ 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,75 +61,126 @@ 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 {
@@ -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);
+ }
+ }
+ }
}