diff options
author | destradaa <destradaa@google.com> | 2013-08-13 23:56:31 +0000 |
---|---|---|
committer | Android (Google) Code Review <android-gerrit@google.com> | 2013-08-13 23:56:31 +0000 |
commit | 5c7e64609c4de93cd70c2cbe238a5fc3ff3c6078 (patch) | |
tree | 5601c7e6ce5320f7bd197ef1bcb9833ee8a632e4 | |
parent | 7a8d9d6fecb31124ad1ec349944659a2f5672776 (diff) | |
parent | 0682809ad08db284d7110aab44108d5e9c310e6b (diff) | |
download | frameworks_base-5c7e64609c4de93cd70c2cbe238a5fc3ff3c6078.zip frameworks_base-5c7e64609c4de93cd70c2cbe238a5fc3ff3c6078.tar.gz frameworks_base-5c7e64609c4de93cd70c2cbe238a5fc3ff3c6078.tar.bz2 |
Merge "Add support in the platform for Flp Geofencing." into klp-dev
13 files changed, 731 insertions, 237 deletions
@@ -355,6 +355,7 @@ aidl_files := \ frameworks/base/core/java/android/content/SyncStats.aidl \ frameworks/base/core/java/android/content/res/Configuration.aidl \ frameworks/base/core/java/android/database/CursorWindow.aidl \ + frameworks/base/core/java/android/hardware/location/GeofenceHardwareRequestParcelable.aidl \ frameworks/base/core/java/android/net/Uri.aidl \ frameworks/base/core/java/android/nfc/NdefMessage.aidl \ frameworks/base/core/java/android/nfc/NdefRecord.aidl \ diff --git a/core/java/android/hardware/location/GeofenceHardware.java b/core/java/android/hardware/location/GeofenceHardware.java index e67d0d7..21de9f5 100644 --- a/core/java/android/hardware/location/GeofenceHardware.java +++ b/core/java/android/hardware/location/GeofenceHardware.java @@ -15,16 +15,11 @@ */ package android.hardware.location; -import android.content.Context; import android.location.Location; import android.os.RemoteException; -import android.util.Log; import java.lang.ref.WeakReference; import java.util.HashMap; -import java.util.Map; -import java.util.Set; - /** * This class handles geofences managed by various hardware subsystems. It contains @@ -52,7 +47,7 @@ public final class GeofenceHardware { private IGeofenceHardware mService; // Hardware systems that do geofence monitoring. - static final int NUM_MONITORS = 1; + static final int NUM_MONITORS = 2; /** * Constant for geofence monitoring done by the GPS hardware. @@ -60,6 +55,13 @@ public final class GeofenceHardware { public static final int MONITORING_TYPE_GPS_HARDWARE = 0; /** + * Constant for geofence monitoring done by the Fused hardware. + * + * @hide + */ + public static final int MONITORING_TYPE_FUSED_HARDWARE = 1; + + /** * Constant to indiciate that the monitoring system is currently * available for monitoring geofences. */ @@ -124,8 +126,12 @@ public final class GeofenceHardware { */ public static final int GEOFENCE_FAILURE = 5; - static final int GPS_GEOFENCE_UNAVAILABLE = 1<<0L; - static final int GPS_GEOFENCE_AVAILABLE = 1<<1L; + /** + * The constant used to indicate that the operation failed due to insufficient memory. + * + * @hide + */ + public static final int GEOFENCE_ERROR_INSUFFICIENT_MEMORY = 6; private HashMap<GeofenceHardwareCallback, GeofenceHardwareCallbackWrapper> mCallbacks = new HashMap<GeofenceHardwareCallback, GeofenceHardwareCallbackWrapper>(); diff --git a/core/java/android/hardware/location/GeofenceHardwareImpl.java b/core/java/android/hardware/location/GeofenceHardwareImpl.java index 77e3143..eac6620 100644 --- a/core/java/android/hardware/location/GeofenceHardwareImpl.java +++ b/core/java/android/hardware/location/GeofenceHardwareImpl.java @@ -18,23 +18,21 @@ package android.hardware.location; import android.content.Context; import android.content.pm.PackageManager; +import android.location.FusedBatchOptions; +import android.location.IFusedGeofenceHardware; 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; -import android.os.ServiceManager; import android.os.SystemClock; import android.util.Log; import android.util.SparseArray; import java.util.ArrayList; -import java.util.HashMap; /** * This class manages the geofences which are handled by hardware. @@ -54,6 +52,7 @@ public final class GeofenceHardwareImpl { new ArrayList[GeofenceHardware.NUM_MONITORS]; private final ArrayList<Reaper> mReapers = new ArrayList<Reaper>(); + private IFusedGeofenceHardware mFusedService; private IGpsGeofenceHardware mGpsService; private int[] mSupportedMonitorTypes = new int[GeofenceHardware.NUM_MONITORS]; @@ -67,7 +66,7 @@ public final class GeofenceHardwareImpl { private static final int GEOFENCE_CALLBACK_BINDER_DIED = 6; // mCallbacksHandler message types - private static final int GPS_GEOFENCE_STATUS = 1; + private static final int 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; @@ -91,16 +90,6 @@ public final class GeofenceHardwareImpl { private static final int RESOLUTION_LEVEL_COARSE = 2; private static final int RESOLUTION_LEVEL_FINE = 3; - // GPS Geofence errors. Should match gps.h constants. - private static final int GPS_GEOFENCE_OPERATION_SUCCESS = 0; - private static final int GPS_GEOFENCE_ERROR_TOO_MANY_GEOFENCES = 100; - private static final int GPS_GEOFENCE_ERROR_ID_EXISTS = -101; - private static final int GPS_GEOFENCE_ERROR_ID_UNKNOWN = -102; - private static final int GPS_GEOFENCE_ERROR_INVALID_TRANSITION = -103; - private static final int GPS_GEOFENCE_ERROR_GENERIC = -149; - - - public synchronized static GeofenceHardwareImpl getInstance(Context context) { if (sInstance == null) { sInstance = new GeofenceHardwareImpl(context); @@ -113,6 +102,9 @@ public final class GeofenceHardwareImpl { // Init everything to unsupported. setMonitorAvailability(GeofenceHardware.MONITORING_TYPE_GPS_HARDWARE, GeofenceHardware.MONITOR_UNSUPPORTED); + setMonitorAvailability( + GeofenceHardware.MONITORING_TYPE_FUSED_HARDWARE, + GeofenceHardware.MONITOR_UNSUPPORTED); } @@ -147,6 +139,22 @@ public final class GeofenceHardwareImpl { } } + private void updateFusedHardwareAvailability() { + boolean fusedSupported; + try { + fusedSupported = mFusedService.isSupported(); + } catch(RemoteException e) { + Log.e(TAG, "RemoteException calling LocationManagerService"); + fusedSupported = false; + } + + if(fusedSupported) { + setMonitorAvailability( + GeofenceHardware.MONITORING_TYPE_FUSED_HARDWARE, + GeofenceHardware.MONITOR_CURRENTLY_AVAILABLE); + } + } + public void setGpsHardwareGeofence(IGpsGeofenceHardware service) { if (mGpsService == null) { mGpsService = service; @@ -159,12 +167,39 @@ public final class GeofenceHardwareImpl { } } + public void setFusedGeofenceHardware(IFusedGeofenceHardware service) { + if(mFusedService == null) { + mFusedService = service; + updateFusedHardwareAvailability(); + } else if(service == null) { + mFusedService = null; + Log.w(TAG, "Fused Geofence Hardware service seems to have crashed"); + } else { + Log.e(TAG, "Error: FusedService being set again"); + } + } + public int[] getMonitoringTypes() { + boolean gpsSupported; + boolean fusedSupported; synchronized (mSupportedMonitorTypes) { - if (mSupportedMonitorTypes[GeofenceHardware.MONITORING_TYPE_GPS_HARDWARE] != - GeofenceHardware.MONITOR_UNSUPPORTED) { - return new int[] {GeofenceHardware.MONITORING_TYPE_GPS_HARDWARE}; + gpsSupported = mSupportedMonitorTypes[GeofenceHardware.MONITORING_TYPE_GPS_HARDWARE] + != GeofenceHardware.MONITOR_UNSUPPORTED; + fusedSupported = mSupportedMonitorTypes[GeofenceHardware.MONITORING_TYPE_FUSED_HARDWARE] + != GeofenceHardware.MONITOR_UNSUPPORTED; + } + + if(gpsSupported) { + if(fusedSupported) { + return new int[] { + GeofenceHardware.MONITORING_TYPE_GPS_HARDWARE, + GeofenceHardware.MONITORING_TYPE_FUSED_HARDWARE }; + } else { + return new int[] { GeofenceHardware.MONITORING_TYPE_GPS_HARDWARE }; } + } else if (fusedSupported) { + return new int[] { GeofenceHardware.MONITORING_TYPE_FUSED_HARDWARE }; + } else { return new int[0]; } } @@ -213,6 +248,30 @@ public final class GeofenceHardwareImpl { result = false; } break; + case GeofenceHardware.MONITORING_TYPE_FUSED_HARDWARE: + if(mFusedService == null) { + return false; + } + GeofenceHardwareRequest request = GeofenceHardwareRequest.createCircularGeofence( + latitude, + longitude, + radius); + request.setUnknownTimer(unknownTimer); + request.setNotificationResponsiveness(notificationResponsivenes); + request.setMonitorTransitions(monitorTransitions); + request.setLastTransition(lastTransition); + + GeofenceHardwareRequestParcelable parcelableRequest = + new GeofenceHardwareRequestParcelable(geofenceId, request); + try { + mFusedService.addGeofences( + new GeofenceHardwareRequestParcelable[] { parcelableRequest }); + result = true; + } catch(RemoteException e) { + Log.e(TAG, "AddGeofence: RemoteException calling LocationManagerService"); + result = false; + } + break; default: result = false; } @@ -251,6 +310,18 @@ public final class GeofenceHardwareImpl { result = false; } break; + case GeofenceHardware.MONITORING_TYPE_FUSED_HARDWARE: + if(mFusedService == null) { + return false; + } + try { + mFusedService.removeGeofences(new int[] { geofenceId }); + result = true; + } catch(RemoteException e) { + Log.e(TAG, "RemoveGeofence: RemoteException calling LocationManagerService"); + result = false; + } + break; default: result = false; } @@ -278,6 +349,18 @@ public final class GeofenceHardwareImpl { result = false; } break; + case GeofenceHardware.MONITORING_TYPE_FUSED_HARDWARE: + if(mFusedService == null) { + return false; + } + try { + mFusedService.pauseMonitoringGeofence(geofenceId); + result = true; + } catch(RemoteException e) { + Log.e(TAG, "PauseGeofence: RemoteException calling LocationManagerService"); + result = false; + } + break; default: result = false; } @@ -306,6 +389,18 @@ public final class GeofenceHardwareImpl { result = false; } break; + case GeofenceHardware.MONITORING_TYPE_FUSED_HARDWARE: + if(mFusedService == null) { + return false; + } + try { + mFusedService.resumeMonitoringGeofence(geofenceId, monitorTransition); + result = true; + } catch(RemoteException e) { + Log.e(TAG, "ResumeGeofence: RemoteException calling LocationManagerService"); + result = false; + } + break; default: result = false; } @@ -334,127 +429,106 @@ public final class GeofenceHardwareImpl { return true; } - private Location getLocation(int flags, double latitude, - double longitude, double altitude, float speed, float bearing, float accuracy, - long timestamp) { - if (DEBUG) Log.d(TAG, "GetLocation: " + flags + ":" + latitude); - Location location = new Location(LocationManager.GPS_PROVIDER); - if ((flags & LOCATION_HAS_LAT_LONG) == LOCATION_HAS_LAT_LONG) { - location.setLatitude(latitude); - location.setLongitude(longitude); - location.setTime(timestamp); - // It would be nice to push the elapsed real-time timestamp - // further down the stack, but this is still useful - location.setElapsedRealtimeNanos(SystemClock.elapsedRealtimeNanos()); - } - if ((flags & LOCATION_HAS_ALTITUDE) == LOCATION_HAS_ALTITUDE) { - location.setAltitude(altitude); - } else { - location.removeAltitude(); - } - if ((flags & LOCATION_HAS_SPEED) == LOCATION_HAS_SPEED) { - location.setSpeed(speed); - } else { - location.removeSpeed(); - } - if ((flags & LOCATION_HAS_BEARING) == LOCATION_HAS_BEARING) { - location.setBearing(bearing); - } else { - location.removeBearing(); - } - if ((flags & LOCATION_HAS_ACCURACY) == LOCATION_HAS_ACCURACY) { - location.setAccuracy(accuracy); - } else { - location.removeAccuracy(); - } - return location; + /** + * Used to report geofence transitions + */ + public void reportGeofenceTransition( + int geofenceId, + Location location, + int transition, + long transitionTimestamp, + int monitoringType, + int sourcesUsed) { + if(location == null) { + Log.e(TAG, String.format("Invalid Geofence Transition: location=%p", location)); + return; + } + if(DEBUG) { + Log.d( + TAG, + "GeofenceTransition| " + location + ", transition:" + transition + + ", transitionTimestamp:" + transitionTimestamp + ", monitoringType:" + + monitoringType + ", sourcesUsed:" + sourcesUsed); + } + + GeofenceTransition geofenceTransition = new GeofenceTransition( + geofenceId, + transition, + transitionTimestamp, + location, + monitoringType, + sourcesUsed); + acquireWakeLock(); + + Message message = mGeofenceHandler.obtainMessage( + GEOFENCE_TRANSITION_CALLBACK, + geofenceTransition); + message.sendToTarget(); } /** - * called from GpsLocationProvider to report geofence transition + * Used to report Monitor status changes. */ - public void reportGpsGeofenceTransition(int geofenceId, int flags, double latitude, - double longitude, double altitude, float speed, float bearing, float accuracy, - long timestamp, int transition, long transitionTimestamp) { - if (DEBUG) Log.d(TAG, "GeofenceTransition: Flags: " + flags + " Lat: " + latitude + - " Long: " + longitude + " Altitude: " + altitude + " Speed: " + speed + " Bearing: " + - bearing + " Accuracy: " + accuracy + " Timestamp: " + timestamp + " Transition: " + - transition + " TransitionTimestamp: " + transitionTimestamp); - Location location = getLocation(flags, latitude, longitude, altitude, speed, bearing, - accuracy, timestamp); - GeofenceTransition t = new GeofenceTransition(geofenceId, transition, timestamp, location); + public void reportGeofenceMonitorStatus( + int monitoringType, + int monitoringStatus, + Location location, + int source) { + // TODO: use the source if needed in the future + setMonitorAvailability(monitoringType, monitoringStatus); acquireWakeLock(); - Message m = mGeofenceHandler.obtainMessage(GEOFENCE_TRANSITION_CALLBACK, t); - mGeofenceHandler.sendMessage(m); + Message message = mCallbacksHandler.obtainMessage(GEOFENCE_STATUS, location); + message.arg1 = monitoringStatus; + message.arg2 = monitoringType; + message.sendToTarget(); } /** - * called from GpsLocationProvider to report GPS status change. + * Internal generic status report function for Geofence operations. + * + * @param operation The operation to be reported as defined internally. + * @param geofenceId The id of the geofence the operation is related to. + * @param operationStatus The status of the operation as defined in GeofenceHardware class. This + * status is independent of the statuses reported by different HALs. */ - public void reportGpsGeofenceStatus(int status, int flags, double latitude, - double longitude, double altitude, float speed, float bearing, float accuracy, - long timestamp) { - Location location = getLocation(flags, latitude, longitude, altitude, speed, bearing, - accuracy, timestamp); - boolean available = false; - if (status == GeofenceHardware.GPS_GEOFENCE_AVAILABLE) available = true; - - int val = (available ? GeofenceHardware.MONITOR_CURRENTLY_AVAILABLE : - GeofenceHardware.MONITOR_CURRENTLY_UNAVAILABLE); - setMonitorAvailability(GeofenceHardware.MONITORING_TYPE_GPS_HARDWARE, val); - + private void reportGeofenceOperationStatus(int operation, int geofenceId, int operationStatus) { acquireWakeLock(); - Message m = mCallbacksHandler.obtainMessage(GPS_GEOFENCE_STATUS, location); - m.arg1 = val; - mCallbacksHandler.sendMessage(m); + Message message = mGeofenceHandler.obtainMessage(operation); + message.arg1 = geofenceId; + message.arg2 = operationStatus; + message.sendToTarget(); } /** - * called from GpsLocationProvider add geofence callback. + * Used to report the status of a Geofence Add operation. */ - public void reportGpsGeofenceAddStatus(int geofenceId, int status) { - if (DEBUG) Log.d(TAG, "Add Callback: GPS : Id: " + geofenceId + " Status: " + status); - acquireWakeLock(); - Message m = mGeofenceHandler.obtainMessage(ADD_GEOFENCE_CALLBACK); - m.arg1 = geofenceId; - m.arg2 = getGeofenceStatus(status); - mGeofenceHandler.sendMessage(m); + public void reportGeofenceAddStatus(int geofenceId, int status) { + if(DEBUG) Log.d(TAG, "AddCallback| id:" + geofenceId + ", status:" + status); + reportGeofenceOperationStatus(ADD_GEOFENCE_CALLBACK, geofenceId, status); } /** - * called from GpsLocationProvider remove geofence callback. + * Used to report the status of a Geofence Remove operation. */ - public void reportGpsGeofenceRemoveStatus(int geofenceId, int status) { - if (DEBUG) Log.d(TAG, "Remove Callback: GPS : Id: " + geofenceId + " Status: " + status); - acquireWakeLock(); - Message m = mGeofenceHandler.obtainMessage(REMOVE_GEOFENCE_CALLBACK); - m.arg1 = geofenceId; - m.arg2 = getGeofenceStatus(status); - mGeofenceHandler.sendMessage(m); + public void reportGeofenceRemoveStatus(int geofenceId, int status) { + if(DEBUG) Log.d(TAG, "RemoveCallback| id:" + geofenceId + ", status:" + status); + reportGeofenceOperationStatus(REMOVE_GEOFENCE_CALLBACK, geofenceId, status); } /** - * called from GpsLocationProvider pause geofence callback. + * Used to report the status of a Geofence Pause operation. */ - public void reportGpsGeofencePauseStatus(int geofenceId, int status) { - if (DEBUG) Log.d(TAG, "Pause Callback: GPS : Id: " + geofenceId + " Status: " + status); - acquireWakeLock(); - Message m = mGeofenceHandler.obtainMessage(PAUSE_GEOFENCE_CALLBACK); - m.arg1 = geofenceId; - m.arg2 = getGeofenceStatus(status); - mGeofenceHandler.sendMessage(m); + public void reportGeofencePauseStatus(int geofenceId, int status) { + if(DEBUG) Log.d(TAG, "PauseCallbac| id:" + geofenceId + ", status" + status); + reportGeofenceOperationStatus(PAUSE_GEOFENCE_CALLBACK, geofenceId, status); } /** - * called from GpsLocationProvider resume geofence callback. + * Used to report the status of a Geofence Resume operation. */ - public void reportGpsGeofenceResumeStatus(int geofenceId, int status) { - if (DEBUG) Log.d(TAG, "Resume Callback: GPS : Id: " + geofenceId + " Status: " + status); - acquireWakeLock(); - Message m = mGeofenceHandler.obtainMessage(RESUME_GEOFENCE_CALLBACK); - m.arg1 = geofenceId; - m.arg2 = getGeofenceStatus(status); - mGeofenceHandler.sendMessage(m); + public void reportGeofenceResumeStatus(int geofenceId, int status) { + if(DEBUG) Log.d(TAG, "ResumeCallback| id:" + geofenceId + ", status:" + status); + reportGeofenceOperationStatus(RESUME_GEOFENCE_CALLBACK, geofenceId, status); } // All operations on mGeofences @@ -539,7 +613,7 @@ public final class GeofenceHardwareImpl { callback.onGeofenceTransition( geofenceTransition.mGeofenceId, geofenceTransition.mTransition, geofenceTransition.mLocation, geofenceTransition.mTimestamp, - GeofenceHardware.MONITORING_TYPE_GPS_HARDWARE); + geofenceTransition.mMonitoringType); } catch (RemoteException e) {} } releaseWakeLock(); @@ -571,21 +645,20 @@ public final class GeofenceHardwareImpl { IGeofenceHardwareMonitorCallback callback; switch (msg.what) { - case GPS_GEOFENCE_STATUS: + case GEOFENCE_STATUS: Location location = (Location) msg.obj; int val = msg.arg1; + monitoringType = msg.arg2; boolean available; available = (val == GeofenceHardware.MONITOR_CURRENTLY_AVAILABLE ? true : false); - callbackList = mCallbacks[GeofenceHardware.MONITORING_TYPE_GPS_HARDWARE]; + callbackList = mCallbacks[monitoringType]; if (callbackList != null) { if (DEBUG) Log.d(TAG, "MonitoringSystemChangeCallback: GPS : " + available); for (IGeofenceHardwareMonitorCallback c: callbackList) { try { - c.onMonitoringSystemChange( - GeofenceHardware.MONITORING_TYPE_GPS_HARDWARE, available, - location); + c.onMonitoringSystemChange(monitoringType, available, location); } catch (RemoteException e) {} } } @@ -666,12 +739,22 @@ public final class GeofenceHardwareImpl { private int mGeofenceId, mTransition; private long mTimestamp; private Location mLocation; - - GeofenceTransition(int geofenceId, int transition, long timestamp, Location location) { + private int mMonitoringType; + private int mSourcesUsed; + + GeofenceTransition( + int geofenceId, + int transition, + long timestamp, + Location location, + int monitoringType, + int sourcesUsed) { mGeofenceId = geofenceId; mTransition = transition; mTimestamp = timestamp; mLocation = location; + mMonitoringType = monitoringType; + mSourcesUsed = sourcesUsed; } } @@ -686,6 +769,8 @@ public final class GeofenceHardwareImpl { switch (monitoringType) { case GeofenceHardware.MONITORING_TYPE_GPS_HARDWARE: return RESOLUTION_LEVEL_FINE; + case GeofenceHardware.MONITORING_TYPE_FUSED_HARDWARE: + return RESOLUTION_LEVEL_FINE; } return RESOLUTION_LEVEL_NONE; } @@ -752,22 +837,4 @@ public final class GeofenceHardwareImpl { return RESOLUTION_LEVEL_NONE; } } - - private int getGeofenceStatus(int status) { - switch (status) { - case GPS_GEOFENCE_OPERATION_SUCCESS: - return GeofenceHardware.GEOFENCE_SUCCESS; - case GPS_GEOFENCE_ERROR_GENERIC: - return GeofenceHardware.GEOFENCE_FAILURE; - case GPS_GEOFENCE_ERROR_ID_EXISTS: - return GeofenceHardware.GEOFENCE_ERROR_ID_EXISTS; - case GPS_GEOFENCE_ERROR_INVALID_TRANSITION: - return GeofenceHardware.GEOFENCE_ERROR_INVALID_TRANSITION; - case GPS_GEOFENCE_ERROR_TOO_MANY_GEOFENCES: - return GeofenceHardware.GEOFENCE_ERROR_TOO_MANY_GEOFENCES; - case GPS_GEOFENCE_ERROR_ID_UNKNOWN: - return GeofenceHardware.GEOFENCE_ERROR_ID_UNKNOWN; - } - return -1; - } } diff --git a/core/java/android/hardware/location/GeofenceHardwareRequestParcelable.aidl b/core/java/android/hardware/location/GeofenceHardwareRequestParcelable.aidl new file mode 100644 index 0000000..b599d44 --- /dev/null +++ b/core/java/android/hardware/location/GeofenceHardwareRequestParcelable.aidl @@ -0,0 +1,19 @@ +/* + * 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; + +parcelable GeofenceHardwareRequestParcelable; diff --git a/core/java/android/hardware/location/GeofenceHardwareRequestParcelable.java b/core/java/android/hardware/location/GeofenceHardwareRequestParcelable.java new file mode 100644 index 0000000..40e7fc4 --- /dev/null +++ b/core/java/android/hardware/location/GeofenceHardwareRequestParcelable.java @@ -0,0 +1,151 @@ +/* + * 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.os.Parcel; +import android.os.Parcelable; +import android.util.Log; + +/** + * Geofence Hardware Request used for internal location services communication. + * + * @hide + */ +public final class GeofenceHardwareRequestParcelable implements Parcelable { + private GeofenceHardwareRequest mRequest; + private int mId; + + public GeofenceHardwareRequestParcelable(int id, GeofenceHardwareRequest request) { + mId = id; + mRequest = request; + } + + /** + * Returns the id of this request. + */ + public int getId() { + return mId; + } + + /** + * Returns the latitude of this geofence. + */ + public double getLatitude() { + return mRequest.getLatitude(); + } + + /** + * Returns the longitude of this geofence. + */ + public double getLongitude() { + return mRequest.getLongitude(); + } + + /** + * Returns the radius of this geofence. + */ + public double getRadius() { + return mRequest.getRadius(); + } + + /** + * Returns transitions monitored for this geofence. + */ + public int getMonitorTransitions() { + return mRequest.getMonitorTransitions(); + } + + /** + * Returns the unknownTimer of this geofence. + */ + public int getUnknownTimer() { + return mRequest.getUnknownTimer(); + } + + /** + * Returns the notification responsiveness of this geofence. + */ + public int getNotificationResponsiveness() { + return mRequest.getNotificationResponsiveness(); + } + + /** + * Returns the last transition of this geofence. + */ + public int getLastTransition() { + return mRequest.getLastTransition(); + } + + /** + * Returns the type of the geofence for the current request. + */ + int getType() { + return mRequest.getType(); + } + + /** + * Method definitions to support Parcelable operations. + */ + public static final Parcelable.Creator<GeofenceHardwareRequestParcelable> CREATOR = + new Parcelable.Creator<GeofenceHardwareRequestParcelable>() { + @Override + public GeofenceHardwareRequestParcelable createFromParcel(Parcel parcel) { + int geofenceType = parcel.readInt(); + if(geofenceType != GeofenceHardwareRequest.GEOFENCE_TYPE_CIRCLE) { + Log.e( + "GeofenceHardwareRequest", + String.format("Invalid Geofence type: %d", geofenceType)); + return null; + } + + GeofenceHardwareRequest request = GeofenceHardwareRequest.createCircularGeofence( + parcel.readDouble(), + parcel.readDouble(), + parcel.readDouble()); + request.setLastTransition(parcel.readInt()); + request.setMonitorTransitions(parcel.readInt()); + request.setUnknownTimer(parcel.readInt()); + request.setNotificationResponsiveness(parcel.readInt()); + + int id = parcel.readInt(); + return new GeofenceHardwareRequestParcelable(id, request); + } + + @Override + public GeofenceHardwareRequestParcelable[] newArray(int size) { + return new GeofenceHardwareRequestParcelable[size]; + } + }; + + @Override + public int describeContents() { + return 0; + } + + @Override + public void writeToParcel(Parcel parcel, int flags) { + parcel.writeInt(getType()); + parcel.writeDouble(getLatitude()); + parcel.writeDouble(getLongitude()); + parcel.writeDouble(getRadius()); + parcel.writeInt(getLastTransition()); + parcel.writeInt(getMonitorTransitions()); + parcel.writeInt(getUnknownTimer()); + parcel.writeInt(getNotificationResponsiveness()); + parcel.writeInt(getId()); + } +} diff --git a/core/java/android/hardware/location/GeofenceHardwareService.java b/core/java/android/hardware/location/GeofenceHardwareService.java index 3bc70ee..fb238bd 100644 --- a/core/java/android/hardware/location/GeofenceHardwareService.java +++ b/core/java/android/hardware/location/GeofenceHardwareService.java @@ -20,6 +20,7 @@ import android.Manifest; import android.app.Service; import android.content.Context; import android.content.Intent; +import android.location.IFusedGeofenceHardware; import android.location.IGpsGeofenceHardware; import android.os.Binder; import android.os.IBinder; @@ -68,6 +69,10 @@ public class GeofenceHardwareService extends Service { mGeofenceHardwareImpl.setGpsHardwareGeofence(service); } + public void setFusedGeofenceHardware(IFusedGeofenceHardware service) { + mGeofenceHardwareImpl.setFusedGeofenceHardware(service); + } + public int[] getMonitoringTypes() { 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 6900070..8900166 100644 --- a/core/java/android/hardware/location/IGeofenceHardware.aidl +++ b/core/java/android/hardware/location/IGeofenceHardware.aidl @@ -16,6 +16,7 @@ package android.hardware.location; +import android.location.IFusedGeofenceHardware; import android.location.IGpsGeofenceHardware; import android.hardware.location.IGeofenceHardwareCallback; import android.hardware.location.IGeofenceHardwareMonitorCallback; @@ -23,6 +24,7 @@ import android.hardware.location.IGeofenceHardwareMonitorCallback; /** @hide */ interface IGeofenceHardware { void setGpsGeofenceHardware(in IGpsGeofenceHardware service); + void setFusedGeofenceHardware(in IFusedGeofenceHardware service); int[] getMonitoringTypes(); int getStatusOfMonitoringType(int monitoringType); boolean addCircularFence(int id, int monitoringType, double lat, double longitude, diff --git a/location/java/android/location/IFusedGeofenceHardware.aidl b/location/java/android/location/IFusedGeofenceHardware.aidl index 9dbf1f4..d8c3585 100644 --- a/location/java/android/location/IFusedGeofenceHardware.aidl +++ b/location/java/android/location/IFusedGeofenceHardware.aidl @@ -16,8 +16,8 @@ package android.location; -import android.location.Geofence; - +import android.hardware.location.GeofenceHardwareRequestParcelable; + /** * Fused Geofence Hardware interface. * @@ -39,11 +39,9 @@ interface IFusedGeofenceHardware { /** * Adds a given list of geofences to the system. * - * @param geofenceIdsArray The list of geofence Ids to add. - * @param geofencesArray the list of geofences to add. + * @param geofenceRequestsArray The list of geofences to add. */ - // TODO: [GeofenceIntegration] GeofenceHardwareRequest is not a parcelable class exposed in aidl - void addGeofences(in int[] geofenceIdsArray, in Geofence[] geofencesArray); + void addGeofences(in GeofenceHardwareRequestParcelable[] geofenceRequestsArray); /** * Removes a give list of geofences from the system. @@ -79,7 +77,8 @@ interface IFusedGeofenceHardware { * the geofence. * @param monitorTransitions The set of transitions to monitor. * @param notificationResponsiveness The notification responsivness needed. - * @param unknownTimer The time span associated with the + * @param unknownTimer The time span associated with the. + * @param sourcesToUse The source technologies to use. * * Remarks: keep the options as separate fields to be able to leverage the class * GeofenceHardwareRequest without any changes @@ -89,5 +88,6 @@ interface IFusedGeofenceHardware { in int lastTransition, in int monitorTransitions, in int notificationResponsiveness, - in int unknownTimer); + in int unknownTimer, + in int sourcesToUse); } diff --git a/services/java/com/android/server/LocationManagerService.java b/services/java/com/android/server/LocationManagerService.java index a32699a..d039a5e 100644 --- a/services/java/com/android/server/LocationManagerService.java +++ b/services/java/com/android/server/LocationManagerService.java @@ -420,19 +420,7 @@ public class LocationManagerService extends ILocationManager.Stub { Slog.e(TAG, "no geocoder provider found"); } - // bind to geofence provider - GeofenceProxy provider = GeofenceProxy.createAndBind(mContext, - com.android.internal.R.bool.config_enableGeofenceOverlay, - com.android.internal.R.string.config_geofenceProviderPackageName, - com.android.internal.R.array.config_locationProviderPackageNames, - mLocationHandler, - gpsProvider.getGpsGeofenceProxy()); - if (provider == null) { - Slog.e(TAG, "no geofence provider found"); - } - // bind to fused provider - // TODO: [GeofenceIntegration] bind #getGeofenceHardware() with the GeofenceProxy FlpHardwareProvider flpHardwareProvider = FlpHardwareProvider.getInstance(mContext); FusedProxy fusedProxy = FusedProxy.createAndBind( mContext, @@ -441,10 +429,21 @@ public class LocationManagerService extends ILocationManager.Stub { com.android.internal.R.bool.config_enableFusedLocationOverlay, com.android.internal.R.string.config_fusedLocationProviderPackageName, com.android.internal.R.array.config_locationProviderPackageNames); - if(fusedProxy == null) { Slog.e(TAG, "No FusedProvider found."); } + + // bind to geofence provider + GeofenceProxy provider = GeofenceProxy.createAndBind(mContext, + com.android.internal.R.bool.config_enableGeofenceOverlay, + com.android.internal.R.string.config_geofenceProviderPackageName, + com.android.internal.R.array.config_locationProviderPackageNames, + mLocationHandler, + gpsProvider.getGpsGeofenceProxy(), + flpHardwareProvider.getGeofenceHardware()); + if (provider == null) { + Slog.e(TAG, "no geofence provider found"); + } } /** diff --git a/services/java/com/android/server/location/FlpHardwareProvider.java b/services/java/com/android/server/location/FlpHardwareProvider.java index 226c18c..ebeccfb 100644 --- a/services/java/com/android/server/location/FlpHardwareProvider.java +++ b/services/java/com/android/server/location/FlpHardwareProvider.java @@ -16,12 +16,13 @@ package com.android.server.location; +import android.hardware.location.GeofenceHardware; import android.hardware.location.GeofenceHardwareImpl; +import android.hardware.location.GeofenceHardwareRequestParcelable; import android.hardware.location.IFusedLocationHardware; import android.hardware.location.IFusedLocationHardwareSink; import android.location.IFusedGeofenceHardware; import android.location.FusedBatchOptions; -import android.location.Geofence; import android.location.Location; import android.location.LocationListener; import android.location.LocationManager; @@ -49,6 +50,15 @@ public class FlpHardwareProvider { private final Context mContext; private final Object mLocationSinkLock = new Object(); + // FlpHal result codes, they must be equal to the ones in fused_location.h + private static final int FLP_RESULT_SUCCESS = 0; + private static final int FLP_RESULT_ERROR = -1; + private static final int FLP_RESULT_INSUFFICIENT_MEMORY = -2; + private static final int FLP_RESULT_TOO_MANY_GEOFENCES = -3; + private static final int FLP_RESULT_ID_EXISTS = -4; + private static final int FLP_RESULT_ID_UNKNOWN = -5; + private static final int FLP_RESULT_INVALID_GEOFENCE_TRANSITION = -6; + public static FlpHardwareProvider getInstance(Context context) { if (sSingletonInstance == null) { sSingletonInstance = new FlpHardwareProvider(context); @@ -120,29 +130,46 @@ public class FlpHardwareProvider { Location location, int transition, long timestamp, - int sourcesUsed - ) { - // TODO: [GeofenceIntegration] change GeofenceHardwareImpl to accept a location object + int sourcesUsed) { + getGeofenceHardwareSink().reportGeofenceTransition( + geofenceId, + updateLocationInformation(location), + transition, + timestamp, + GeofenceHardware.MONITORING_TYPE_FUSED_HARDWARE, + sourcesUsed); } private void onGeofenceMonitorStatus(int status, int source, Location location) { - // TODO: [GeofenceIntegration] + getGeofenceHardwareSink().reportGeofenceMonitorStatus( + GeofenceHardware.MONITORING_TYPE_FUSED_HARDWARE, + status, + updateLocationInformation(location), + source); } private void onGeofenceAdd(int geofenceId, int result) { - // TODO: [GeofenceIntegration] map between GPS and FLP results to pass a consistent status + getGeofenceHardwareSink().reportGeofenceAddStatus( + geofenceId, + translateToGeofenceHardwareStatus(result)); } private void onGeofenceRemove(int geofenceId, int result) { - // TODO: [GeofenceIntegration] map between GPS and FLP results to pass a consistent status + getGeofenceHardwareSink().reportGeofenceRemoveStatus( + geofenceId, + translateToGeofenceHardwareStatus(result)); } private void onGeofencePause(int geofenceId, int result) { - // TODO; [GeofenceIntegration] map between GPS and FLP results + getGeofenceHardwareSink().reportGeofencePauseStatus( + geofenceId, + translateToGeofenceHardwareStatus(result)); } private void onGeofenceResume(int geofenceId, int result) { - // TODO: [GeofenceIntegration] map between GPS and FLP results + getGeofenceHardwareSink().reportGeofenceResumeStatus( + geofenceId, + translateToGeofenceHardwareStatus(result)); } /** @@ -175,7 +202,8 @@ public class FlpHardwareProvider { // FlpGeofencingInterface members private native boolean nativeIsGeofencingSupported(); - private native void nativeAddGeofences(int[] geofenceIdsArray, Geofence[] geofencesArray); + private native void nativeAddGeofences( + GeofenceHardwareRequestParcelable[] geofenceRequestsArray); private native void nativePauseGeofence(int geofenceId); private native void nativeResumeGeofence(int geofenceId, int monitorTransitions); private native void nativeModifyGeofenceOption( @@ -281,8 +309,8 @@ public class FlpHardwareProvider { } @Override - public void addGeofences(int[] geofenceIdsArray, Geofence[] geofencesArray) { - nativeAddGeofences(geofenceIdsArray, geofencesArray); + public void addGeofences(GeofenceHardwareRequestParcelable[] geofenceRequestsArray) { + nativeAddGeofences(geofenceRequestsArray); } @Override @@ -305,17 +333,15 @@ public class FlpHardwareProvider { int lastTransition, int monitorTransitions, int notificationResponsiveness, - int unknownTimer - ) { - // TODO: [GeofenceIntegration] set sourcesToUse to the right value - // TODO: expose sourcesToUse externally when needed + int unknownTimer, + int sourcesToUse) { nativeModifyGeofenceOption( geofenceId, lastTransition, monitorTransitions, notificationResponsiveness, unknownTimer, - /* sourcesToUse */ 0xFFFF); + sourcesToUse); } }; @@ -347,10 +373,39 @@ public class FlpHardwareProvider { private GeofenceHardwareImpl getGeofenceHardwareSink() { if (mGeofenceHardwareSink == null) { - // TODO: [GeofenceIntegration] we need to register ourselves with GeofenceHardwareImpl mGeofenceHardwareSink = GeofenceHardwareImpl.getInstance(mContext); } return mGeofenceHardwareSink; } -}
\ No newline at end of file + + private static int translateToGeofenceHardwareStatus(int flpHalResult) { + switch(flpHalResult) { + case FLP_RESULT_SUCCESS: + return GeofenceHardware.GEOFENCE_SUCCESS; + case FLP_RESULT_ERROR: + return GeofenceHardware.GEOFENCE_FAILURE; + // TODO: uncomment this once the ERROR definition is marked public + //case FLP_RESULT_INSUFFICIENT_MEMORY: + // return GeofenceHardware.GEOFENCE_ERROR_INSUFFICIENT_MEMORY; + case FLP_RESULT_TOO_MANY_GEOFENCES: + return GeofenceHardware.GEOFENCE_ERROR_TOO_MANY_GEOFENCES; + case FLP_RESULT_ID_EXISTS: + return GeofenceHardware.GEOFENCE_ERROR_ID_EXISTS; + case FLP_RESULT_ID_UNKNOWN: + return GeofenceHardware.GEOFENCE_ERROR_ID_UNKNOWN; + case FLP_RESULT_INVALID_GEOFENCE_TRANSITION: + return GeofenceHardware.GEOFENCE_ERROR_INVALID_TRANSITION; + default: + Log.e(TAG, String.format("Invalid FlpHal result code: %d", flpHalResult)); + return GeofenceHardware.GEOFENCE_FAILURE; + } + } + + private Location updateLocationInformation(Location location) { + location.setProvider(LocationManager.FUSED_PROVIDER); + // set the elapsed time-stamp just as GPS provider does + location.setElapsedRealtimeNanos(SystemClock.elapsedRealtimeNanos()); + return location; + } +} diff --git a/services/java/com/android/server/location/GeofenceProxy.java b/services/java/com/android/server/location/GeofenceProxy.java index f6be27b..a86c923 100644 --- a/services/java/com/android/server/location/GeofenceProxy.java +++ b/services/java/com/android/server/location/GeofenceProxy.java @@ -22,6 +22,7 @@ import android.hardware.location.GeofenceHardwareService; import android.hardware.location.IGeofenceHardware; import android.location.IGeofenceProvider; import android.location.IGpsGeofenceHardware; +import android.location.IFusedGeofenceHardware; import android.content.Context; import android.os.Handler; import android.os.IBinder; @@ -44,6 +45,7 @@ public final class GeofenceProxy { private Context mContext; private IGeofenceHardware mGeofenceHardware; private IGpsGeofenceHardware mGpsGeofenceHardware; + private IFusedGeofenceHardware mFusedGeofenceHardware; private static final int GEOFENCE_PROVIDER_CONNECTED = 1; private static final int GEOFENCE_HARDWARE_CONNECTED = 2; @@ -60,9 +62,11 @@ public final class GeofenceProxy { public static GeofenceProxy createAndBind(Context context, int overlaySwitchResId, int defaultServicePackageNameResId, - int initialPackageNamesResId, Handler handler, IGpsGeofenceHardware gpsGeofence) { + int initialPackageNamesResId, Handler handler, IGpsGeofenceHardware gpsGeofence, + IFusedGeofenceHardware fusedGeofenceHardware) { GeofenceProxy proxy = new GeofenceProxy(context, overlaySwitchResId, - defaultServicePackageNameResId, initialPackageNamesResId, handler, gpsGeofence); + defaultServicePackageNameResId, initialPackageNamesResId, handler, gpsGeofence, + fusedGeofenceHardware); if (proxy.bindGeofenceProvider()) { return proxy; } else { @@ -72,11 +76,13 @@ public final class GeofenceProxy { private GeofenceProxy(Context context, int overlaySwitchResId, int defaultServicePackageNameResId, - int initialPackageNamesResId, Handler handler, IGpsGeofenceHardware gpsGeofence) { + int initialPackageNamesResId, Handler handler, IGpsGeofenceHardware gpsGeofence, + IFusedGeofenceHardware fusedGeofenceHardware) { mContext = context; mServiceWatcher = new ServiceWatcher(context, TAG, SERVICE_ACTION, overlaySwitchResId, defaultServicePackageNameResId, initialPackageNamesResId, mRunnable, handler); mGpsGeofenceHardware = gpsGeofence; + mFusedGeofenceHardware = fusedGeofenceHardware; bindHardwareGeofence(); } @@ -123,6 +129,13 @@ public final class GeofenceProxy { } } + private void setFusedGeofence() { + try { + mGeofenceHardware.setFusedGeofenceHardware(mFusedGeofenceHardware); + } catch(RemoteException e) { + Log.e(TAG, "Error while connecting to GeofenceHardwareService"); + } + } // This needs to be reworked, when more services get added, // Might need a state machine or add a framework utility class, @@ -142,6 +155,7 @@ public final class GeofenceProxy { break; case GEOFENCE_HARDWARE_CONNECTED: setGpsGeofence(); + setFusedGeofence(); mGeofenceHardwareConnected = true; if (mGeofenceProviderConnected) { setGeofenceHardwareInProvider(); diff --git a/services/java/com/android/server/location/GpsLocationProvider.java b/services/java/com/android/server/location/GpsLocationProvider.java index 38453c8..6053c61 100644 --- a/services/java/com/android/server/location/GpsLocationProvider.java +++ b/services/java/com/android/server/location/GpsLocationProvider.java @@ -24,9 +24,10 @@ import android.content.Context; import android.content.Intent; import android.content.IntentFilter; import android.database.Cursor; +import android.hardware.location.GeofenceHardware; import android.hardware.location.GeofenceHardwareImpl; -import android.hardware.location.IGeofenceHardware; import android.location.Criteria; +import android.location.FusedBatchOptions; import android.location.IGpsGeofenceHardware; import android.location.IGpsStatusListener; import android.location.IGpsStatusProvider; @@ -195,6 +196,17 @@ public class GpsLocationProvider implements LocationProviderInterface { private static final String PROPERTIES_FILE = "/etc/gps.conf"; + private static final int GPS_GEOFENCE_UNAVAILABLE = 1<<0L; + private static final int GPS_GEOFENCE_AVAILABLE = 1<<1L; + + // GPS Geofence errors. Should match gps.h constants. + private static final int GPS_GEOFENCE_OPERATION_SUCCESS = 0; + private static final int GPS_GEOFENCE_ERROR_TOO_MANY_GEOFENCES = 100; + private static final int GPS_GEOFENCE_ERROR_ID_EXISTS = -101; + private static final int GPS_GEOFENCE_ERROR_ID_UNKNOWN = -102; + private static final int GPS_GEOFENCE_ERROR_INVALID_TRANSITION = -103; + private static final int GPS_GEOFENCE_ERROR_GENERIC = -149; + /** simpler wrapper for ProviderRequest + Worksource */ private static class GpsRequest { public ProviderRequest request; @@ -501,7 +513,7 @@ public class GpsLocationProvider implements LocationProviderInterface { LocationManager locManager = (LocationManager) mContext.getSystemService(Context.LOCATION_SERVICE); locManager.requestLocationUpdates(LocationManager.PASSIVE_PROVIDER, - 0, 0, new NetworkLocationListener(), mHandler.getLooper()); + 0, 0, new NetworkLocationListener(), mHandler.getLooper()); } }); } @@ -1405,6 +1417,62 @@ public class GpsLocationProvider implements LocationProviderInterface { } /** + * Helper method to construct a location object. + */ + private Location buildLocation( + int flags, + double latitude, + double longitude, + double altitude, + float speed, + float bearing, + float accuracy, + long timestamp) { + Location location = new Location(LocationManager.GPS_PROVIDER); + if((flags & LOCATION_HAS_LAT_LONG) == LOCATION_HAS_LAT_LONG) { + location.setLatitude(latitude); + location.setLongitude(longitude); + location.setTime(timestamp); + location.setElapsedRealtimeNanos(SystemClock.elapsedRealtimeNanos()); + } + if((flags & LOCATION_HAS_ALTITUDE) == LOCATION_HAS_ALTITUDE) { + location.setAltitude(altitude); + } + if((flags & LOCATION_HAS_SPEED) == LOCATION_HAS_SPEED) { + location.setSpeed(speed); + } + if((flags & LOCATION_HAS_BEARING) == LOCATION_HAS_BEARING) { + location.setBearing(bearing); + } + if((flags & LOCATION_HAS_ACCURACY) == LOCATION_HAS_ACCURACY) { + location.setAccuracy(accuracy); + } + return location; + } + + /** + * Converts the GPS HAL status to the internal Geofence Hardware status. + */ + private int getGeofenceStatus(int status) { + switch(status) { + case GPS_GEOFENCE_OPERATION_SUCCESS: + return GeofenceHardware.GEOFENCE_SUCCESS; + case GPS_GEOFENCE_ERROR_GENERIC: + return GeofenceHardware.GEOFENCE_FAILURE; + case GPS_GEOFENCE_ERROR_ID_EXISTS: + return GeofenceHardware.GEOFENCE_ERROR_ID_EXISTS; + case GPS_GEOFENCE_ERROR_INVALID_TRANSITION: + return GeofenceHardware.GEOFENCE_ERROR_INVALID_TRANSITION; + case GPS_GEOFENCE_ERROR_TOO_MANY_GEOFENCES: + return GeofenceHardware.GEOFENCE_ERROR_TOO_MANY_GEOFENCES; + case GPS_GEOFENCE_ERROR_ID_UNKNOWN: + return GeofenceHardware.GEOFENCE_ERROR_ID_UNKNOWN; + default: + return -1; + } + } + + /** * Called from native to report GPS Geofence transition * All geofence callbacks are called on the same thread */ @@ -1414,8 +1482,22 @@ public class GpsLocationProvider implements LocationProviderInterface { if (mGeofenceHardwareImpl == null) { mGeofenceHardwareImpl = GeofenceHardwareImpl.getInstance(mContext); } - mGeofenceHardwareImpl.reportGpsGeofenceTransition(geofenceId, flags, latitude, longitude, - altitude, speed, bearing, accuracy, timestamp, transition, transitionTimestamp); + Location location = buildLocation( + flags, + latitude, + longitude, + altitude, + speed, + bearing, + accuracy, + timestamp); + mGeofenceHardwareImpl.reportGeofenceTransition( + geofenceId, + location, + transition, + transitionTimestamp, + GeofenceHardware.MONITORING_TYPE_GPS_HARDWARE, + FusedBatchOptions.SourceTechnologies.GNSS); } /** @@ -1427,8 +1509,24 @@ public class GpsLocationProvider implements LocationProviderInterface { if (mGeofenceHardwareImpl == null) { mGeofenceHardwareImpl = GeofenceHardwareImpl.getInstance(mContext); } - mGeofenceHardwareImpl.reportGpsGeofenceStatus(status, flags, latitude, longitude, altitude, - speed, bearing, accuracy, timestamp); + Location location = buildLocation( + flags, + latitude, + longitude, + altitude, + speed, + bearing, + accuracy, + timestamp); + int monitorStatus = GeofenceHardware.MONITOR_CURRENTLY_UNAVAILABLE; + if(status == GPS_GEOFENCE_AVAILABLE) { + monitorStatus = GeofenceHardware.MONITOR_CURRENTLY_AVAILABLE; + } + mGeofenceHardwareImpl.reportGeofenceMonitorStatus( + GeofenceHardware.MONITORING_TYPE_GPS_HARDWARE, + monitorStatus, + location, + FusedBatchOptions.SourceTechnologies.GNSS); } /** @@ -1438,7 +1536,7 @@ public class GpsLocationProvider implements LocationProviderInterface { if (mGeofenceHardwareImpl == null) { mGeofenceHardwareImpl = GeofenceHardwareImpl.getInstance(mContext); } - mGeofenceHardwareImpl.reportGpsGeofenceAddStatus(geofenceId, status); + mGeofenceHardwareImpl.reportGeofenceAddStatus(geofenceId, getGeofenceStatus(status)); } /** @@ -1448,7 +1546,7 @@ public class GpsLocationProvider implements LocationProviderInterface { if (mGeofenceHardwareImpl == null) { mGeofenceHardwareImpl = GeofenceHardwareImpl.getInstance(mContext); } - mGeofenceHardwareImpl.reportGpsGeofenceRemoveStatus(geofenceId, status); + mGeofenceHardwareImpl.reportGeofenceRemoveStatus(geofenceId, getGeofenceStatus(status)); } /** @@ -1458,7 +1556,7 @@ public class GpsLocationProvider implements LocationProviderInterface { if (mGeofenceHardwareImpl == null) { mGeofenceHardwareImpl = GeofenceHardwareImpl.getInstance(mContext); } - mGeofenceHardwareImpl.reportGpsGeofencePauseStatus(geofenceId, status); + mGeofenceHardwareImpl.reportGeofencePauseStatus(geofenceId, getGeofenceStatus(status)); } /** @@ -1468,7 +1566,7 @@ public class GpsLocationProvider implements LocationProviderInterface { if (mGeofenceHardwareImpl == null) { mGeofenceHardwareImpl = GeofenceHardwareImpl.getInstance(mContext); } - mGeofenceHardwareImpl.reportGpsGeofenceResumeStatus(geofenceId, status); + mGeofenceHardwareImpl.reportGeofenceResumeStatus(geofenceId, getGeofenceStatus(status)); } //============================================================= diff --git a/services/jni/com_android_server_location_FlpHardwareProvider.cpp b/services/jni/com_android_server_location_FlpHardwareProvider.cpp index 48b86db..c871828 100644 --- a/services/jni/com_android_server_location_FlpHardwareProvider.cpp +++ b/services/jni/com_android_server_location_FlpHardwareProvider.cpp @@ -261,6 +261,75 @@ static void TranslateFromObject( } /* + * Helper function to unwrap Geofence structures from the Java Runtime calls. + */ +static void TranslateGeofenceFromGeofenceHardwareRequestParcelable( + JNIEnv* env, + jobject geofenceRequestObject, + Geofence& geofence) { + jclass geofenceRequestClass = env->GetObjectClass(geofenceRequestObject); + + jmethodID getId = env->GetMethodID(geofenceRequestClass, "getId", "()I"); + geofence.geofence_id = env->CallIntMethod(geofenceRequestObject, getId); + + jmethodID getType = env->GetMethodID(geofenceRequestClass, "getType", "()I"); + // this works because GeofenceHardwareRequest.java and fused_location.h have + // the same notion of geofence types + GeofenceType type = (GeofenceType)env->CallIntMethod(geofenceRequestObject, getType); + if(type != TYPE_CIRCLE) { + ThrowOnError(env, FLP_RESULT_ERROR, __FUNCTION__); + } + geofence.data->type = type; + GeofenceCircle& circle = geofence.data->geofence.circle; + + jmethodID getLatitude = env->GetMethodID( + geofenceRequestClass, + "getLatitude", + "()D"); + circle.latitude = env->CallDoubleMethod(geofenceRequestObject, getLatitude); + + jmethodID getLongitude = env->GetMethodID( + geofenceRequestClass, + "getLongitude", + "()D"); + circle.longitude = env->CallDoubleMethod(geofenceRequestObject, getLongitude); + + jmethodID getRadius = env->GetMethodID(geofenceRequestClass, "getRadius", "()D"); + circle.radius_m = env->CallDoubleMethod(geofenceRequestObject, getRadius); + + GeofenceOptions* options = geofence.options; + jmethodID getMonitorTransitions = env->GetMethodID( + geofenceRequestClass, + "getMonitorTransitions", + "()I"); + options->monitor_transitions = env->CallIntMethod( + geofenceRequestObject, + getMonitorTransitions); + + jmethodID getUnknownTimer = env->GetMethodID( + geofenceRequestClass, + "getUnknownTimer", + "()I"); + options->unknown_timer_ms = env->CallIntMethod(geofenceRequestObject, getUnknownTimer); + + jmethodID getNotificationResponsiveness = env->GetMethodID( + geofenceRequestClass, + "getNotificationResponsiveness", + "()D"); + options->notification_responsivenes_ms = env->CallIntMethod( + geofenceRequestObject, + getNotificationResponsiveness); + + jmethodID getLastTransition = env->GetMethodID( + geofenceRequestClass, + "getLastTransition", + "()I"); + options->last_transition = env->CallIntMethod(geofenceRequestObject, getLastTransition); + + // TODO: set data.sources_to_use when available +} + +/* * Helper function to transform FlpLocation into a java object. */ static void TranslateToObject(const FlpLocation* location, jobject& locationObject) { @@ -559,7 +628,7 @@ static void Init(JNIEnv* env, jobject obj) { } err = module->methods->open( - module, + module, FUSED_LOCATION_HARDWARE_MODULE_ID, &sHardwareDevice); if(err != 0) { ALOGE("Error opening device '%s': %d", FUSED_LOCATION_HARDWARE_MODULE_ID, err); @@ -749,10 +818,9 @@ static jboolean IsGeofencingSupported() { static void AddGeofences( JNIEnv* env, jobject object, - jintArray geofenceIdsArray, - jobjectArray geofencesArray) { - if(geofencesArray == NULL) { - ALOGE("Invalid Geofences to add: %p", geofencesArray); + jobjectArray geofenceRequestsArray) { + if(geofenceRequestsArray == NULL) { + ALOGE("Invalid Geofences to add: %p", geofenceRequestsArray); ThrowOnError(env, FLP_RESULT_ERROR, __FUNCTION__); } @@ -760,23 +828,32 @@ static void AddGeofences( ThrowOnError(env, FLP_RESULT_ERROR, __FUNCTION__); } - jint geofencesCount = env->GetArrayLength(geofenceIdsArray); - Geofence* geofences = new Geofence[geofencesCount]; + jint geofenceRequestsCount = env->GetArrayLength(geofenceRequestsArray); + if(geofenceRequestsCount == 0) { + return; + } + + Geofence* geofences = new Geofence[geofenceRequestsCount]; if (geofences == NULL) { ThrowOnError(env, FLP_RESULT_INSUFFICIENT_MEMORY, __FUNCTION__); } - jint* ids = env->GetIntArrayElements(geofenceIdsArray, /* isCopy */ NULL); - for (int i = 0; i < geofencesCount; ++i) { - geofences[i].geofence_id = ids[i]; + for (int i = 0; i < geofenceRequestsCount; ++i) { + geofences[i].data = new GeofenceData(); + geofences[i].options = new GeofenceOptions(); + jobject geofenceObject = env->GetObjectArrayElement(geofenceRequestsArray, i); - // TODO: fill in the GeofenceData - - // TODO: fill in the GeofenceOptions + TranslateGeofenceFromGeofenceHardwareRequestParcelable(env, geofenceObject, geofences[i]); } - sFlpGeofencingInterface->add_geofences(geofencesCount, &geofences); - if (geofences != NULL) delete[] geofences; + sFlpGeofencingInterface->add_geofences(geofenceRequestsCount, &geofences); + if (geofences != NULL) { + for(int i = 0; i < geofenceRequestsCount; ++i) { + delete geofences[i].data; + delete geofences[i].options; + } + delete[] geofences; + } } static void PauseGeofence(JNIEnv* env, jobject object, jint geofenceId) { @@ -847,41 +924,41 @@ static JNINativeMethod sMethods[] = { {"nativeCleanup", "()V", reinterpret_cast<void*>(Cleanup)}, {"nativeIsSupported", "()Z", reinterpret_cast<void*>(IsSupported)}, {"nativeGetBatchSize", "()I", reinterpret_cast<void*>(GetBatchSize)}, - {"nativeStartBatching", - "(ILandroid/location/FusedBatchOptions;)V", + {"nativeStartBatching", + "(ILandroid/location/FusedBatchOptions;)V", reinterpret_cast<void*>(StartBatching)}, - {"nativeUpdateBatchingOptions", - "(ILandroid/location/FusedBatchOptions;)V", + {"nativeUpdateBatchingOptions", + "(ILandroid/location/FusedBatchOptions;)V", reinterpret_cast<void*>(UpdateBatchingOptions)}, {"nativeStopBatching", "(I)V", reinterpret_cast<void*>(StopBatching)}, - {"nativeRequestBatchedLocation", - "(I)V", + {"nativeRequestBatchedLocation", + "(I)V", reinterpret_cast<void*>(GetBatchedLocation)}, - {"nativeInjectLocation", - "(Landroid/location/Location;)V", + {"nativeInjectLocation", + "(Landroid/location/Location;)V", reinterpret_cast<void*>(InjectLocation)}, - {"nativeIsDiagnosticSupported", - "()Z", + {"nativeIsDiagnosticSupported", + "()Z", reinterpret_cast<void*>(IsDiagnosticSupported)}, - {"nativeInjectDiagnosticData", - "(Ljava/lang/String;)V", + {"nativeInjectDiagnosticData", + "(Ljava/lang/String;)V", reinterpret_cast<void*>(InjectDiagnosticData)}, - {"nativeIsDeviceContextSupported", - "()Z", + {"nativeIsDeviceContextSupported", + "()Z", reinterpret_cast<void*>(IsDeviceContextSupported)}, - {"nativeInjectDeviceContext", - "(I)V", + {"nativeInjectDeviceContext", + "(I)V", reinterpret_cast<void*>(InjectDeviceContext)}, - {"nativeIsGeofencingSupported", - "()Z", + {"nativeIsGeofencingSupported", + "()Z", reinterpret_cast<void*>(IsGeofencingSupported)}, - {"nativeAddGeofences", - "([I[Landroid/location/Geofence;)V", + {"nativeAddGeofences", + "([Landroid/hardware/location/GeofenceHardwareRequestParcelable;)V", reinterpret_cast<void*>(AddGeofences)}, {"nativePauseGeofence", "(I)V", reinterpret_cast<void*>(PauseGeofence)}, {"nativeResumeGeofence", "(II)V", reinterpret_cast<void*>(ResumeGeofence)}, - {"nativeModifyGeofenceOption", - "(IIIIII)V", + {"nativeModifyGeofenceOption", + "(IIIIII)V", reinterpret_cast<void*>(ModifyGeofenceOption)}, {"nativeRemoveGeofences", "([I)V", reinterpret_cast<void*>(RemoveGeofences)} }; |