From da6508954a492f3dd4397e70e4fa08ee54bd2741 Mon Sep 17 00:00:00 2001 From: Jaikumar Ganesh Date: Wed, 17 Apr 2013 12:19:10 -0700 Subject: Hardware geofence API changes. b/8631678 1.GeofenceRequest object created. 2.MonitorState moved to a new callback 3.getTypeAndStatus separated to 2 calls. 4.Binder death implemented 5.geofenceChange callback name changed. 6.Parameters rearranged in some calls. Change-Id: I8fe9621186aeb49efeb0eef1821a2556afe03cfc --- .../hardware/location/GeofenceHardware.java | 178 ++++++++++++++------- .../location/GeofenceHardwareCallback.java | 15 +- .../hardware/location/GeofenceHardwareImpl.java | 178 +++++++++++++++++++-- .../location/GeofenceHardwareMonitorCallback.java | 37 +++++ .../hardware/location/GeofenceHardwareRequest.java | 158 ++++++++++++++++++ .../hardware/location/GeofenceHardwareService.java | 31 ++-- .../hardware/location/IGeofenceHardware.aidl | 16 +- .../location/IGeofenceHardwareCallback.aidl | 3 +- .../location/IGeofenceHardwareMonitorCallback.aidl | 24 +++ 9 files changed, 529 insertions(+), 111 deletions(-) create mode 100644 core/java/android/hardware/location/GeofenceHardwareMonitorCallback.java create mode 100644 core/java/android/hardware/location/GeofenceHardwareRequest.java create mode 100644 core/java/android/hardware/location/IGeofenceHardwareMonitorCallback.aidl (limited to 'core/java/android/hardware/location') diff --git a/core/java/android/hardware/location/GeofenceHardware.java b/core/java/android/hardware/location/GeofenceHardware.java index 35bbb9c..e67d0d7 100644 --- a/core/java/android/hardware/location/GeofenceHardware.java +++ b/core/java/android/hardware/location/GeofenceHardware.java @@ -129,6 +129,9 @@ public final class GeofenceHardware { private HashMap mCallbacks = new HashMap(); + private HashMap + mMonitorCallbacks = new HashMap(); /** * @hide */ @@ -137,8 +140,29 @@ public final class GeofenceHardware { } /** - * Returns all the hardware geofence monitoring systems and their status. - * Status can be one of {@link #MONITOR_CURRENTLY_AVAILABLE}, + * Returns all the hardware geofence monitoring systems which are supported + * + *

Call {@link #getStatusOfMonitoringType(int)} to know the current state + * of a monitoring system. + * + *

Requires {@link android.Manifest.permission#LOCATION_HARDWARE} permission to access + * geofencing in hardware. + * + * @return An array of all the monitoring types. + * An array of length 0 is returned in case of errors. + */ + public int[] getMonitoringTypes() { + try { + return mService.getMonitoringTypes(); + } catch (RemoteException e) { + } + return new int[0]; + } + + /** + * Returns current status of a hardware geofence monitoring system. + * + *

Status can be one of {@link #MONITOR_CURRENTLY_AVAILABLE}, * {@link #MONITOR_CURRENTLY_UNAVAILABLE} or {@link #MONITOR_UNSUPPORTED} * *

Some supported hardware monitoring systems might not be available @@ -147,18 +171,15 @@ public final class GeofenceHardware { * geofences and will change from {@link #MONITOR_CURRENTLY_AVAILABLE} to * {@link #MONITOR_CURRENTLY_UNAVAILABLE}. * - *

Requires {@link android.Manifest.permission#LOCATION_HARDWARE} permission to access - * geofencing in hardware. - * - * @return An array indexed by the various monitoring types and their status. - * An array of length 0 is returned in case of errors. + * @param monitoringType + * @return Current status of the monitoring type. */ - public int[] getMonitoringTypesAndStatus() { + public int getStatusOfMonitoringType(int monitoringType) { try { - return mService.getMonitoringTypesAndStatus(); + return mService.getStatusOfMonitoringType(monitoringType); } catch (RemoteException e) { + return MONITOR_UNSUPPORTED; } - return new int[0]; } /** @@ -167,8 +188,10 @@ public final class GeofenceHardware { *

When the device detects that is has entered, exited or is uncertain * about the area specified by the geofence, the given callback will be called. * - *

The {@link GeofenceHardwareCallback#onGeofenceChange} callback will be called, - * with the following parameters + *

If this call returns true, it means that the geofence has been sent to the hardware. + * {@link GeofenceHardwareCallback#onGeofenceAdd} will be called with the result of the + * add call from the hardware. The {@link GeofenceHardwareCallback#onGeofenceAdd} will be + * called with the following parameters when a transition event occurs. *

    *
  • The geofence Id *
  • The location object indicating the last known location. @@ -195,43 +218,46 @@ public final class GeofenceHardware { * which abstracts the hardware should be used instead. All the checks are done by the higher * level public API. Any needed locking should be handled by the higher level API. * - * @param latitude Latitude of the area to be monitored. - * @param longitude Longitude of the area to be monitored. - * @param radius Radius (in meters) of the area to be monitored. - * @param lastTransition The current state of the geofence. Can be one of - * {@link #GEOFENCE_ENTERED}, {@link #GEOFENCE_EXITED}, - * {@link #GEOFENCE_UNCERTAIN}. - * @param monitorTransitions Bitwise OR of {@link #GEOFENCE_ENTERED}, - * {@link #GEOFENCE_EXITED}, {@link #GEOFENCE_UNCERTAIN} - * @param notificationResponsivenes Defines the best-effort description - * of how soon should the callback be called when the transition - * associated with the Geofence is triggered. For instance, if - * set to 1000 millseconds with {@link #GEOFENCE_ENTERED}, - * the callback will be called 1000 milliseconds within entering - * the geofence. This parameter is defined in milliseconds. - * @param unknownTimer The time limit after which the - * {@link #GEOFENCE_UNCERTAIN} transition - * should be triggered. This paramter is defined in milliseconds. + *

    Create a geofence request object using the methods in {@link GeofenceHardwareRequest} to + * set all the characteristics of the geofence. Use the created GeofenceHardwareRequest object + * in this call. + * + * @param geofenceId The id associated with the geofence. * @param monitoringType The type of the hardware subsystem that should be used * to monitor the geofence. + * @param geofenceRequest The {@link GeofenceHardwareRequest} object associated with the + * geofence. * @param callback {@link GeofenceHardwareCallback} that will be use to notify the * transition. - * @return true on success. + * @return true when the geofence is successfully sent to the hardware for addition. + * @throws IllegalArgumentException when the geofence request type is not supported. */ - public boolean addCircularFence(int geofenceId, double latitude, double longitude, - double radius, int lastTransition,int monitorTransitions, int notificationResponsivenes, - int unknownTimer, int monitoringType, GeofenceHardwareCallback callback) { + public boolean addGeofence(int geofenceId, int monitoringType, GeofenceHardwareRequest + geofenceRequest, GeofenceHardwareCallback callback) { try { - return mService.addCircularFence(geofenceId, latitude, longitude, radius, - lastTransition, monitorTransitions, notificationResponsivenes, unknownTimer, - monitoringType, getCallbackWrapper(callback)); + if (geofenceRequest.getType() == GeofenceHardwareRequest.GEOFENCE_TYPE_CIRCLE) { + return mService.addCircularFence(geofenceId, monitoringType, + geofenceRequest.getLatitude(), + geofenceRequest.getLongitude(), geofenceRequest.getRadius(), + geofenceRequest.getLastTransition(), + geofenceRequest.getMonitorTransitions(), + geofenceRequest.getNotificationResponsiveness(), + geofenceRequest.getUnknownTimer(), + getCallbackWrapper(callback)); + } else { + throw new IllegalArgumentException("Geofence Request type not supported"); + } } catch (RemoteException e) { } return false; } /** - * Removes a geofence added by {@link #addCircularFence} call. + * Removes a geofence added by {@link #addGeofence} call. + * + *

    If this call returns true, it means that the geofence has been sent to the hardware. + * {@link GeofenceHardwareCallback#onGeofenceRemove} will be called with the result of the + * remove call from the hardware. * *

    Requires {@link android.Manifest.permission#ACCESS_FINE_LOCATION} permission when * {@link #MONITORING_TYPE_GPS_HARDWARE} is used. @@ -246,7 +272,7 @@ public final class GeofenceHardware { * @param geofenceId The id of the geofence. * @param monitoringType The type of the hardware subsystem that should be used * to monitor the geofence. - * @return true on success. + * @return true when the geofence is successfully sent to the hardware for removal. . */ public boolean removeGeofence(int geofenceId, int monitoringType) { try { @@ -257,7 +283,11 @@ public final class GeofenceHardware { } /** - * Pauses the monitoring of a geofence added by {@link #addCircularFence} call. + * Pauses the monitoring of a geofence added by {@link #addGeofence} call. + * + *

    If this call returns true, it means that the geofence has been sent to the hardware. + * {@link GeofenceHardwareCallback#onGeofencePause} will be called with the result of the + * pause call from the hardware. * *

    Requires {@link android.Manifest.permission#ACCESS_FINE_LOCATION} permission when * {@link #MONITORING_TYPE_GPS_HARDWARE} is used. @@ -272,7 +302,7 @@ public final class GeofenceHardware { * @param geofenceId The id of the geofence. * @param monitoringType The type of the hardware subsystem that should be used * to monitor the geofence. - * @return true on success. + * @return true when the geofence is successfully sent to the hardware for pausing. */ public boolean pauseGeofence(int geofenceId, int monitoringType) { try { @@ -285,6 +315,10 @@ public final class GeofenceHardware { /** * Resumes the monitoring of a geofence added by {@link #pauseGeofence} call. * + *

    If this call returns true, it means that the geofence has been sent to the hardware. + * {@link GeofenceHardwareCallback#onGeofenceResume} will be called with the result of the + * resume call from the hardware. + * *

    Requires {@link android.Manifest.permission#ACCESS_FINE_LOCATION} permission when * {@link #MONITORING_TYPE_GPS_HARDWARE} is used. * @@ -296,15 +330,15 @@ public final class GeofenceHardware { * level public API. Any needed locking should be handled by the higher level API. * * @param geofenceId The id of the geofence. - * @param monitorTransition Bitwise OR of {@link #GEOFENCE_ENTERED}, - * {@link #GEOFENCE_EXITED}, {@link #GEOFENCE_UNCERTAIN} * @param monitoringType The type of the hardware subsystem that should be used * to monitor the geofence. - * @return true on success. + * @param monitorTransition Bitwise OR of {@link #GEOFENCE_ENTERED}, + * {@link #GEOFENCE_EXITED}, {@link #GEOFENCE_UNCERTAIN} + * @return true when the geofence is successfully sent to the hardware for resumption. */ - public boolean resumeGeofence(int geofenceId, int monitorTransition, int monitoringType) { + public boolean resumeGeofence(int geofenceId, int monitoringType, int monitorTransition) { try { - return mService.resumeGeofence(geofenceId, monitorTransition, monitoringType); + return mService.resumeGeofence(geofenceId, monitoringType, monitorTransition); } catch (RemoteException e) { } return false; @@ -333,10 +367,10 @@ public final class GeofenceHardware { * @return true on success */ public boolean registerForMonitorStateChangeCallback(int monitoringType, - GeofenceHardwareCallback callback) { + GeofenceHardwareMonitorCallback callback) { try { return mService.registerForMonitorStateChangeCallback(monitoringType, - getCallbackWrapper(callback)); + getMonitorCallbackWrapper(callback)); } catch (RemoteException e) { } return false; @@ -361,12 +395,12 @@ public final class GeofenceHardware { * @return true on success */ public boolean unregisterForMonitorStateChangeCallback(int monitoringType, - GeofenceHardwareCallback callback) { + GeofenceHardwareMonitorCallback callback) { boolean result = false; try { result = mService.unregisterForMonitorStateChangeCallback(monitoringType, - getCallbackWrapper(callback)); - if (result) removeCallback(callback); + getMonitorCallbackWrapper(callback)); + if (result) removeMonitorCallback(callback); } catch (RemoteException e) { } @@ -391,24 +425,50 @@ public final class GeofenceHardware { } } - class GeofenceHardwareCallbackWrapper extends IGeofenceHardwareCallback.Stub { - private WeakReference mCallback; + private void removeMonitorCallback(GeofenceHardwareMonitorCallback callback) { + synchronized (mMonitorCallbacks) { + mMonitorCallbacks.remove(callback); + } + } - GeofenceHardwareCallbackWrapper(GeofenceHardwareCallback c) { - mCallback = new WeakReference(c); + private GeofenceHardwareMonitorCallbackWrapper getMonitorCallbackWrapper( + GeofenceHardwareMonitorCallback callback) { + synchronized (mMonitorCallbacks) { + GeofenceHardwareMonitorCallbackWrapper wrapper = mMonitorCallbacks.get(callback); + if (wrapper == null) { + wrapper = new GeofenceHardwareMonitorCallbackWrapper(callback); + mMonitorCallbacks.put(callback, wrapper); + } + return wrapper; + } + } + + class GeofenceHardwareMonitorCallbackWrapper extends IGeofenceHardwareMonitorCallback.Stub { + private WeakReference mCallback; + + GeofenceHardwareMonitorCallbackWrapper(GeofenceHardwareMonitorCallback c) { + mCallback = new WeakReference(c); } public void onMonitoringSystemChange(int monitoringType, boolean available, Location location) { - GeofenceHardwareCallback c = mCallback.get(); + GeofenceHardwareMonitorCallback c = mCallback.get(); if (c != null) c.onMonitoringSystemChange(monitoringType, available, location); } + } + + class GeofenceHardwareCallbackWrapper extends IGeofenceHardwareCallback.Stub { + private WeakReference mCallback; - public void onGeofenceChange(int geofenceId, int transition, Location location, + GeofenceHardwareCallbackWrapper(GeofenceHardwareCallback c) { + mCallback = new WeakReference(c); + } + + public void onGeofenceTransition(int geofenceId, int transition, Location location, long timestamp, int monitoringType) { GeofenceHardwareCallback c = mCallback.get(); if (c != null) { - c.onGeofenceChange(geofenceId, transition, location, timestamp, + c.onGeofenceTransition(geofenceId, transition, location, timestamp, monitoringType); } } @@ -428,7 +488,9 @@ public final class GeofenceHardware { public void onGeofencePause(int geofenceId, int status) { GeofenceHardwareCallback c = mCallback.get(); - if (c != null) c.onGeofencePause(geofenceId, status); + if (c != null) { + c.onGeofencePause(geofenceId, status); + } } public void onGeofenceResume(int geofenceId, int status) { diff --git a/core/java/android/hardware/location/GeofenceHardwareCallback.java b/core/java/android/hardware/location/GeofenceHardwareCallback.java index 8ab582a..6cad3da 100644 --- a/core/java/android/hardware/location/GeofenceHardwareCallback.java +++ b/core/java/android/hardware/location/GeofenceHardwareCallback.java @@ -22,19 +22,6 @@ import android.location.Location; * The callback class associated with the APIs in {@link GeofenceHardware} */ public abstract class GeofenceHardwareCallback { - - /** - * The callback called when the state of a monitoring system changes. - * {@link GeofenceHardware#MONITORING_TYPE_GPS_HARDWARE} is an example of a - * monitoring system. - * - * @param monitoringType The type of the monitoring system. - * @param available Indicates whether the system is currently available or not. - * @param location The last known location according to the monitoring system. - */ - public void onMonitoringSystemChange(int monitoringType, boolean available, Location location) { - } - /** * The callback called when there is a transition to report for the specific * geofence. @@ -47,7 +34,7 @@ public abstract class GeofenceHardwareCallback { * detected * @param monitoringType Type of the monitoring system. */ - public void onGeofenceChange(int geofenceId, int transition, Location location, + public void onGeofenceTransition(int geofenceId, int transition, Location location, long timestamp, int monitoringType) { } diff --git a/core/java/android/hardware/location/GeofenceHardwareImpl.java b/core/java/android/hardware/location/GeofenceHardwareImpl.java index 21f1ea6..a62b660 100644 --- a/core/java/android/hardware/location/GeofenceHardwareImpl.java +++ b/core/java/android/hardware/location/GeofenceHardwareImpl.java @@ -21,8 +21,10 @@ import android.content.pm.PackageManager; import android.location.IGpsGeofenceHardware; import android.location.Location; import android.location.LocationManager; +import android.os.Binder; import android.os.Bundle; import android.os.Handler; +import android.os.IBinder; import android.os.Message; import android.os.PowerManager; import android.os.RemoteException; @@ -48,8 +50,9 @@ public final class GeofenceHardwareImpl { private PowerManager.WakeLock mWakeLock; private SparseArray mGeofences = new SparseArray(); - private ArrayList[] mCallbacks = + private ArrayList[] mCallbacks = new ArrayList[GeofenceHardware.NUM_MONITORS]; + private ArrayList mReapers = new ArrayList(); private IGpsGeofenceHardware mGpsService; @@ -63,11 +66,18 @@ public final class GeofenceHardwareImpl { private static final int RESUME_GEOFENCE_CALLBACK = 5; private static final int ADD_GEOFENCE = 6; private static final int REMOVE_GEOFENCE = 7; + private static final int GEOFENCE_CALLBACK_BINDER_DIED = 8; // mCallbacksHandler message types private static final int GPS_GEOFENCE_STATUS = 1; private static final int CALLBACK_ADD = 2; private static final int CALLBACK_REMOVE = 3; + private static final int MONITOR_CALLBACK_BINDER_DIED = 4; + + // mReaperHandler message types + private static final int REAPER_GEOFENCE_ADDED = 1; + private static final int REAPER_MONITOR_CALLBACK_ADDED = 2; + private static final int REAPER_REMOVED = 3; // The following constants need to match GpsLocationFlags enum in gps.h private static final int LOCATION_INVALID = 0; @@ -151,15 +161,28 @@ public final class GeofenceHardwareImpl { } } - public int[] getMonitoringTypesAndStatus() { + public int[] getMonitoringTypes() { synchronized (mSupportedMonitorTypes) { - return mSupportedMonitorTypes; + if (mSupportedMonitorTypes[GeofenceHardware.MONITORING_TYPE_GPS_HARDWARE] != + GeofenceHardware.MONITOR_UNSUPPORTED) { + return new int[] {GeofenceHardware.MONITORING_TYPE_GPS_HARDWARE}; + } + return new int[0]; + } + } + + public int getStatusOfMonitoringType(int monitoringType) { + synchronized (mSupportedMonitorTypes) { + if (monitoringType >= mSupportedMonitorTypes.length || monitoringType < 0) { + throw new IllegalArgumentException("Unknown monitoring type"); + } + return mSupportedMonitorTypes[monitoringType]; } } - public boolean addCircularFence(int geofenceId, double latitude, double longitude, - double radius, int lastTransition,int monitorTransitions, int notificationResponsivenes, - int unknownTimer, int monitoringType, IGeofenceHardwareCallback callback) { + public boolean addCircularFence(int geofenceId, int monitoringType, double latitude, + double longitude, double radius, int lastTransition,int monitorTransitions, + int notificationResponsivenes, int unknownTimer, IGeofenceHardwareCallback callback) { // This API is not thread safe. Operations on the same geofence need to be serialized // by upper layers if (DEBUG) { @@ -190,7 +213,11 @@ public final class GeofenceHardwareImpl { default: result = false; } - if (!result) { + if (result) { + m = mReaperHandler.obtainMessage(REAPER_GEOFENCE_ADDED, callback); + m.arg1 = monitoringType; + mReaperHandler.sendMessage(m); + } else { m = mGeofenceHandler.obtainMessage(REMOVE_GEOFENCE); m.arg1 = geofenceId; mGeofenceHandler.sendMessage(m); @@ -245,7 +272,7 @@ public final class GeofenceHardwareImpl { } - public boolean resumeGeofence(int geofenceId, int monitorTransition, int monitoringType) { + public boolean resumeGeofence(int geofenceId, int monitoringType, int monitorTransition) { // This API is not thread safe. Operations on the same geofence need to be serialized // by upper layers if (DEBUG) Log.d(TAG, "Resume Geofence: GeofenceId: " + geofenceId); @@ -268,7 +295,12 @@ public final class GeofenceHardwareImpl { } public boolean registerForMonitorStateChangeCallback(int monitoringType, - IGeofenceHardwareCallback callback) { + IGeofenceHardwareMonitorCallback callback) { + Message reaperMessage = + mReaperHandler.obtainMessage(REAPER_MONITOR_CALLBACK_ADDED, callback); + reaperMessage.arg1 = monitoringType; + mReaperHandler.sendMessage(reaperMessage); + Message m = mCallbacksHandler.obtainMessage(CALLBACK_ADD, callback); m.arg1 = monitoringType; mCallbacksHandler.sendMessage(m); @@ -276,7 +308,7 @@ public final class GeofenceHardwareImpl { } public boolean unregisterForMonitorStateChangeCallback(int monitoringType, - IGeofenceHardwareCallback callback) { + IGeofenceHardwareMonitorCallback callback) { Message m = mCallbacksHandler.obtainMessage(CALLBACK_REMOVE, callback); m.arg1 = monitoringType; mCallbacksHandler.sendMessage(m); @@ -477,13 +509,25 @@ public final class GeofenceHardwareImpl { "Location: " + geofenceTransition.mLocation + ":" + mGeofences); try { - callback.onGeofenceChange( + callback.onGeofenceTransition( geofenceTransition.mGeofenceId, geofenceTransition.mTransition, geofenceTransition.mLocation, geofenceTransition.mTimestamp, GeofenceHardware.MONITORING_TYPE_GPS_HARDWARE); } catch (RemoteException e) {} releaseWakeLock(); break; + case GEOFENCE_CALLBACK_BINDER_DIED: + // Find all geofences associated with this callback and remove them. + callback = (IGeofenceHardwareCallback) (msg.obj); + if (DEBUG) Log.d(TAG, "Geofence callback reaped:" + callback); + int monitoringType = msg.arg1; + for (int i = 0; i < mGeofences.size(); i++) { + if (mGeofences.valueAt(i).equals(callback)) { + geofenceId = mGeofences.keyAt(i); + removeGeofence(mGeofences.keyAt(i), monitoringType); + mGeofences.remove(geofenceId); + } + } } } }; @@ -493,8 +537,8 @@ public final class GeofenceHardwareImpl { @Override public void handleMessage(Message msg) { int monitoringType; - ArrayList callbackList; - IGeofenceHardwareCallback callback; + ArrayList callbackList; + IGeofenceHardwareMonitorCallback callback; switch (msg.what) { case GPS_GEOFENCE_STATUS: @@ -508,7 +552,7 @@ public final class GeofenceHardwareImpl { if (DEBUG) Log.d(TAG, "MonitoringSystemChangeCallback: GPS : " + available); - for (IGeofenceHardwareCallback c: callbackList) { + for (IGeofenceHardwareMonitorCallback c: callbackList) { try { c.onMonitoringSystemChange( GeofenceHardware.MONITORING_TYPE_GPS_HARDWARE, available, @@ -519,22 +563,71 @@ public final class GeofenceHardwareImpl { break; case CALLBACK_ADD: monitoringType = msg.arg1; - callback = (IGeofenceHardwareCallback) msg.obj; + callback = (IGeofenceHardwareMonitorCallback) msg.obj; callbackList = mCallbacks[monitoringType]; if (callbackList == null) { - callbackList = new ArrayList(); + callbackList = new ArrayList(); mCallbacks[monitoringType] = callbackList; } if (!callbackList.contains(callback)) callbackList.add(callback); break; case CALLBACK_REMOVE: monitoringType = msg.arg1; - callback = (IGeofenceHardwareCallback) msg.obj; + callback = (IGeofenceHardwareMonitorCallback) msg.obj; callbackList = mCallbacks[monitoringType]; if (callbackList != null) { callbackList.remove(callback); } break; + case MONITOR_CALLBACK_BINDER_DIED: + callback = (IGeofenceHardwareMonitorCallback) msg.obj; + if (DEBUG) Log.d(TAG, "Monitor callback reaped:" + callback); + callbackList = mCallbacks[msg.arg1]; + if (callbackList != null && callbackList.contains(callback)) { + callbackList.remove(callback); + } + } + } + }; + + // All operations on mReaper + private Handler mReaperHandler = new Handler() { + @Override + public void handleMessage(Message msg) { + Reaper r; + IGeofenceHardwareCallback callback; + IGeofenceHardwareMonitorCallback monitorCallback; + int monitoringType; + + switch (msg.what) { + case REAPER_GEOFENCE_ADDED: + callback = (IGeofenceHardwareCallback) msg.obj; + monitoringType = msg.arg1; + r = new Reaper(callback, monitoringType); + if (!mReapers.contains(r)) { + mReapers.add(r); + IBinder b = callback.asBinder(); + try { + b.linkToDeath(r, 0); + } catch (RemoteException e) {} + } + break; + case REAPER_MONITOR_CALLBACK_ADDED: + monitorCallback = (IGeofenceHardwareMonitorCallback) msg.obj; + monitoringType = msg.arg1; + + r = new Reaper(monitorCallback, monitoringType); + if (!mReapers.contains(r)) { + mReapers.add(r); + IBinder b = monitorCallback.asBinder(); + try { + b.linkToDeath(r, 0); + } catch (RemoteException e) {} + } + break; + case REAPER_REMOVED: + r = (Reaper) msg.obj; + mReapers.remove(r); } } }; @@ -567,6 +660,57 @@ public final class GeofenceHardwareImpl { return RESOLUTION_LEVEL_NONE; } + class Reaper implements IBinder.DeathRecipient { + private IGeofenceHardwareMonitorCallback mMonitorCallback; + private IGeofenceHardwareCallback mCallback; + private int mMonitoringType; + + Reaper(IGeofenceHardwareCallback c, int monitoringType) { + mCallback = c; + mMonitoringType = monitoringType; + } + + Reaper(IGeofenceHardwareMonitorCallback c, int monitoringType) { + mMonitorCallback = c; + mMonitoringType = monitoringType; + } + + @Override + public void binderDied() { + Message m; + if (mCallback != null) { + m = mGeofenceHandler.obtainMessage(GEOFENCE_CALLBACK_BINDER_DIED, mCallback); + m.arg1 = mMonitoringType; + mGeofenceHandler.sendMessage(m); + } else if (mMonitorCallback != null) { + m = mCallbacksHandler.obtainMessage(MONITOR_CALLBACK_BINDER_DIED, mMonitorCallback); + m.arg1 = mMonitoringType; + mCallbacksHandler.sendMessage(m); + } + Message reaperMessage = mReaperHandler.obtainMessage(REAPER_REMOVED, this); + mReaperHandler.sendMessage(reaperMessage); + } + + @Override + public int hashCode() { + int result = 17; + result = 31 * result + (mCallback != null ? mCallback.hashCode() : 0); + result = 31 * result + (mMonitorCallback != null ? mMonitorCallback.hashCode() : 0); + result = 31 * result + mMonitoringType; + return result; + } + + @Override + public boolean equals(Object obj) { + if (obj == null) return false; + if (obj == this) return true; + + Reaper rhs = (Reaper) obj; + return rhs.mCallback == mCallback && rhs.mMonitorCallback == mMonitorCallback && + rhs.mMonitoringType == mMonitoringType; + } + } + int getAllowedResolutionLevel(int pid, int uid) { if (mContext.checkPermission(android.Manifest.permission.ACCESS_FINE_LOCATION, pid, uid) == PackageManager.PERMISSION_GRANTED) { diff --git a/core/java/android/hardware/location/GeofenceHardwareMonitorCallback.java b/core/java/android/hardware/location/GeofenceHardwareMonitorCallback.java new file mode 100644 index 0000000..b8e927e --- /dev/null +++ b/core/java/android/hardware/location/GeofenceHardwareMonitorCallback.java @@ -0,0 +1,37 @@ +/* + * Copyright (C) 2013 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.hardware.location; + +import android.location.Location; + +/** + * The callback class associated with the status change of hardware montiors + * in {@link GeofenceHardware} + */ +public abstract class GeofenceHardwareMonitorCallback { + /** + * The callback called when the state of a monitoring system changes. + * {@link GeofenceHardware#MONITORING_TYPE_GPS_HARDWARE} is an example of a + * monitoring system + * + * @param monitoringType The type of the monitoring system. + * @param available Indicates whether the system is currenty available or not. + * @param location The last known location according to the monitoring system. + */ + public void onMonitoringSystemChange(int monitoringType, boolean available, Location location) { + } +} diff --git a/core/java/android/hardware/location/GeofenceHardwareRequest.java b/core/java/android/hardware/location/GeofenceHardwareRequest.java new file mode 100644 index 0000000..6e7b592 --- /dev/null +++ b/core/java/android/hardware/location/GeofenceHardwareRequest.java @@ -0,0 +1,158 @@ +/* + * Copyright (C) 2013 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.hardware.location; + +import android.location.Location; + +/** + * This class represents the characteristics of the geofence. + * + *

    Use this in conjunction with {@link GeofenceHardware} APIs. + */ + +public final class GeofenceHardwareRequest { + static final int GEOFENCE_TYPE_CIRCLE = 0; + private int mType; + private double mLatitude; + private double mLongitude; + private double mRadius; + private int mLastTransition = GeofenceHardware.GEOFENCE_UNCERTAIN; + private int mUnknownTimer = 30000; // 30 secs + private int mMonitorTransitions = GeofenceHardware.GEOFENCE_UNCERTAIN | + GeofenceHardware.GEOFENCE_ENTERED | GeofenceHardware.GEOFENCE_EXITED; + private int mNotificationResponsiveness = 5000; // 5 secs + + private void setCircularGeofence(double latitude, double longitude, double radius) { + mLatitude = latitude; + mLongitude = longitude; + mRadius = radius; + mType = GEOFENCE_TYPE_CIRCLE; + } + + /** + * Create a circular geofence. + * + * @param latitude Latitude of the geofence + * @param longitude Longitude of the geofence + * @param radius Radius of the geofence (in meters) + */ + public static GeofenceHardwareRequest createCircularGeofence(double latitude, + double longitude, double radius) { + GeofenceHardwareRequest geofenceRequest = new GeofenceHardwareRequest(); + geofenceRequest.setCircularGeofence(latitude, longitude, radius); + return geofenceRequest; + } + + /** + * Set the last known transition of the geofence. + * + * @param lastTransition The current state of the geofence. Can be one of + * {@link GeofenceHardware#GEOFENCE_ENTERED}, {@link GeofenceHardware#GEOFENCE_EXITED}, + * {@link GeofenceHardware#GEOFENCE_UNCERTAIN}. + */ + public void setLastTransition(int lastTransition) { + mLastTransition = lastTransition; + } + + /** + * Set the unknown timer for this geofence. + * + * @param unknownTimer The time limit after which the + * {@link GeofenceHardware#GEOFENCE_UNCERTAIN} transition + * should be triggered. This paramter is defined in milliseconds. + */ + public void setUnknownTimer(int unknownTimer) { + mUnknownTimer = unknownTimer; + } + + /** + * Set the transitions to be monitored. + * + * @param monitorTransitions Bitwise OR of {@link GeofenceHardware#GEOFENCE_ENTERED}, + * {@link GeofenceHardware#GEOFENCE_EXITED}, {@link GeofenceHardware#GEOFENCE_UNCERTAIN} + */ + public void setMonitorTransitions(int monitorTransitions) { + mMonitorTransitions = monitorTransitions; + } + + /** + * Set the notification responsiveness of the geofence. + * + * @param notificationResponsiveness (milliseconds) Defines the best-effort description + * of how soon should the callback be called when the transition + * associated with the Geofence is triggered. For instance, if + * set to 1000 millseconds with {@link GeofenceHardware#GEOFENCE_ENTERED}, + * the callback will be called 1000 milliseconds within entering + * the geofence. + */ + public void setNotificationResponsiveness(int notificationResponsiveness) { + mNotificationResponsiveness = notificationResponsiveness; + } + + /** + * Returns the latitude of this geofence. + */ + public double getLatitude() { + return mLatitude; + } + + /** + * Returns the longitude of this geofence. + */ + public double getLongitude() { + return mLongitude; + } + + /** + * Returns the radius of this geofence. + */ + public double getRadius() { + return mRadius; + } + + /** + * Returns transitions monitored for this geofence. + */ + public int getMonitorTransitions() { + return mMonitorTransitions; + } + + /** + * Returns the unknownTimer of this geofence. + */ + public int getUnknownTimer() { + return mUnknownTimer; + } + + /** + * Returns the notification responsiveness of this geofence. + */ + public int getNotificationResponsiveness() { + return mNotificationResponsiveness; + } + + /** + * Returns the last transition of this geofence. + */ + public int getLastTransition() { + return mLastTransition; + } + + int getType() { + return mType; + } +} diff --git a/core/java/android/hardware/location/GeofenceHardwareService.java b/core/java/android/hardware/location/GeofenceHardwareService.java index 0eccee6..3bc70ee 100644 --- a/core/java/android/hardware/location/GeofenceHardwareService.java +++ b/core/java/android/hardware/location/GeofenceHardwareService.java @@ -68,23 +68,28 @@ public class GeofenceHardwareService extends Service { mGeofenceHardwareImpl.setGpsHardwareGeofence(service); } - public int[] getMonitoringTypesAndStatus() { + public int[] getMonitoringTypes() { mContext.enforceCallingPermission(Manifest.permission.LOCATION_HARDWARE, "Location Hardware permission not granted to access hardware geofence"); - return mGeofenceHardwareImpl.getMonitoringTypesAndStatus(); + return mGeofenceHardwareImpl.getMonitoringTypes(); } - public boolean addCircularFence(int id, double lat, double longitude, double radius, - int lastTransition, int monitorTransitions, int - notificationResponsiveness, int unknownTimer, int monitoringType, - IGeofenceHardwareCallback callback) { + public int getStatusOfMonitoringType(int monitoringType) { + mContext.enforceCallingPermission(Manifest.permission.LOCATION_HARDWARE, + "Location Hardware permission not granted to access hardware geofence"); + + return mGeofenceHardwareImpl.getStatusOfMonitoringType(monitoringType); + } + public boolean addCircularFence(int id, int monitoringType, double lat, double longitude, + double radius, int lastTransition, int monitorTransitions, int + notificationResponsiveness, int unknownTimer, IGeofenceHardwareCallback callback) { mContext.enforceCallingPermission(Manifest.permission.LOCATION_HARDWARE, "Location Hardware permission not granted to access hardware geofence"); checkPermission(Binder.getCallingPid(), Binder.getCallingUid(), monitoringType); - return mGeofenceHardwareImpl.addCircularFence(id, lat, longitude, radius, - lastTransition, monitorTransitions, notificationResponsiveness, unknownTimer, - monitoringType, callback); + return mGeofenceHardwareImpl.addCircularFence(id, monitoringType, lat, longitude, + radius, lastTransition, monitorTransitions, notificationResponsiveness, + unknownTimer, callback); } public boolean removeGeofence(int id, int monitoringType) { @@ -103,16 +108,16 @@ public class GeofenceHardwareService extends Service { return mGeofenceHardwareImpl.pauseGeofence(id, monitoringType); } - public boolean resumeGeofence(int id, int monitorTransitions, int monitoringType) { + public boolean resumeGeofence(int id, int monitoringType, int monitorTransitions) { mContext.enforceCallingPermission(Manifest.permission.LOCATION_HARDWARE, "Location Hardware permission not granted to access hardware geofence"); checkPermission(Binder.getCallingPid(), Binder.getCallingUid(), monitoringType); - return mGeofenceHardwareImpl.resumeGeofence(id, monitorTransitions, monitoringType); + return mGeofenceHardwareImpl.resumeGeofence(id, monitoringType, monitorTransitions); } public boolean registerForMonitorStateChangeCallback(int monitoringType, - IGeofenceHardwareCallback callback) { + IGeofenceHardwareMonitorCallback callback) { mContext.enforceCallingPermission(Manifest.permission.LOCATION_HARDWARE, "Location Hardware permission not granted to access hardware geofence"); @@ -122,7 +127,7 @@ public class GeofenceHardwareService extends Service { } public boolean unregisterForMonitorStateChangeCallback(int monitoringType, - IGeofenceHardwareCallback callback) { + IGeofenceHardwareMonitorCallback callback) { mContext.enforceCallingPermission(Manifest.permission.LOCATION_HARDWARE, "Location Hardware permission not granted to access hardware geofence"); diff --git a/core/java/android/hardware/location/IGeofenceHardware.aidl b/core/java/android/hardware/location/IGeofenceHardware.aidl index 4ba02b8..6900070 100644 --- a/core/java/android/hardware/location/IGeofenceHardware.aidl +++ b/core/java/android/hardware/location/IGeofenceHardware.aidl @@ -18,19 +18,21 @@ package android.hardware.location; import android.location.IGpsGeofenceHardware; import android.hardware.location.IGeofenceHardwareCallback; +import android.hardware.location.IGeofenceHardwareMonitorCallback; /** @hide */ interface IGeofenceHardware { void setGpsGeofenceHardware(in IGpsGeofenceHardware service); - int[] getMonitoringTypesAndStatus(); - boolean addCircularFence(int id, double lat, double longitude, double radius, - int lastTransition, int monitorTransitions, int notificationResponsiveness, - int unknownTimer, int monitoringType, in IGeofenceHardwareCallback callback); + int[] getMonitoringTypes(); + int getStatusOfMonitoringType(int monitoringType); + boolean addCircularFence(int id, int monitoringType, double lat, double longitude, + double radius, int lastTransition, int monitorTransitions, + int notificationResponsiveness, int unknownTimer,in IGeofenceHardwareCallback callback); boolean removeGeofence(int id, int monitoringType); boolean pauseGeofence(int id, int monitoringType); - boolean resumeGeofence(int id, int monitorTransitions, int monitoringType); + boolean resumeGeofence(int id, int monitoringType, int monitorTransitions); boolean registerForMonitorStateChangeCallback(int monitoringType, - IGeofenceHardwareCallback callback); + IGeofenceHardwareMonitorCallback callback); boolean unregisterForMonitorStateChangeCallback(int monitoringType, - IGeofenceHardwareCallback callback); + IGeofenceHardwareMonitorCallback callback); } diff --git a/core/java/android/hardware/location/IGeofenceHardwareCallback.aidl b/core/java/android/hardware/location/IGeofenceHardwareCallback.aidl index 678fc49..3a8f430 100644 --- a/core/java/android/hardware/location/IGeofenceHardwareCallback.aidl +++ b/core/java/android/hardware/location/IGeofenceHardwareCallback.aidl @@ -20,8 +20,7 @@ import android.location.Location; /** @hide */ oneway interface IGeofenceHardwareCallback { - void onMonitoringSystemChange(int monitoringType, boolean available, in Location location); - void onGeofenceChange(int geofenceId, int transition, in Location location, + void onGeofenceTransition(int geofenceId, int transition, in Location location, long timestamp, int monitoringType); void onGeofenceAdd(int geofenceId, int status); void onGeofenceRemove(int geofenceId, int status); diff --git a/core/java/android/hardware/location/IGeofenceHardwareMonitorCallback.aidl b/core/java/android/hardware/location/IGeofenceHardwareMonitorCallback.aidl new file mode 100644 index 0000000..0b6e04b --- /dev/null +++ b/core/java/android/hardware/location/IGeofenceHardwareMonitorCallback.aidl @@ -0,0 +1,24 @@ +/* + * Copyright (C) 2013 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.hardware.location; + +import android.location.Location; + +/** @hide */ +oneway interface IGeofenceHardwareMonitorCallback { + void onMonitoringSystemChange(int monitoringType, boolean available, in Location location); +} -- cgit v1.1