summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authordestradaa <destradaa@google.com>2013-08-12 18:50:30 -0700
committerdestradaa <destradaa@google.com>2013-08-13 16:00:04 -0700
commit0682809ad08db284d7110aab44108d5e9c310e6b (patch)
tree2aa38602adac05aa16f829f995b21d239ba2494c
parentf464511a7be2e381f508b5b2b937f19c98d800c2 (diff)
downloadframeworks_base-0682809ad08db284d7110aab44108d5e9c310e6b.zip
frameworks_base-0682809ad08db284d7110aab44108d5e9c310e6b.tar.gz
frameworks_base-0682809ad08db284d7110aab44108d5e9c310e6b.tar.bz2
Add support in the platform for Flp Geofencing.
Change-Id: I0fb0e276d3a06322697bb5d46323779aca1f78c5
-rw-r--r--Android.mk1
-rw-r--r--core/java/android/hardware/location/GeofenceHardware.java22
-rw-r--r--core/java/android/hardware/location/GeofenceHardwareImpl.java345
-rw-r--r--core/java/android/hardware/location/GeofenceHardwareRequestParcelable.aidl19
-rw-r--r--core/java/android/hardware/location/GeofenceHardwareRequestParcelable.java151
-rw-r--r--core/java/android/hardware/location/GeofenceHardwareService.java5
-rw-r--r--core/java/android/hardware/location/IGeofenceHardware.aidl2
-rw-r--r--location/java/android/location/IFusedGeofenceHardware.aidl16
-rw-r--r--services/java/com/android/server/LocationManagerService.java25
-rw-r--r--services/java/com/android/server/location/FlpHardwareProvider.java93
-rw-r--r--services/java/com/android/server/location/GeofenceProxy.java20
-rw-r--r--services/java/com/android/server/location/GpsLocationProvider.java118
-rw-r--r--services/jni/com_android_server_location_FlpHardwareProvider.cpp151
13 files changed, 731 insertions, 237 deletions
diff --git a/Android.mk b/Android.mk
index 22ee3a6..bdc83cf 100644
--- a/Android.mk
+++ b/Android.mk
@@ -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)}
};