Merge "Add support in the platform for Flp Geofencing." into klp-dev

This commit is contained in:
destradaa
2013-08-13 23:56:31 +00:00
committed by Android (Google) Code Review
13 changed files with 728 additions and 234 deletions

View File

@@ -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 \

View File

@@ -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,13 +47,20 @@ 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.
*/
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>();

View File

@@ -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());
/**
* 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 ((flags & LOCATION_HAS_ALTITUDE) == LOCATION_HAS_ALTITUDE) {
location.setAltitude(altitude);
} else {
location.removeAltitude();
if(DEBUG) {
Log.d(
TAG,
"GeofenceTransition| " + location + ", transition:" + transition +
", transitionTimestamp:" + transitionTimestamp + ", monitoringType:" +
monitoringType + ", sourcesUsed:" + sourcesUsed);
}
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;
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;
private int mMonitoringType;
private int mSourcesUsed;
GeofenceTransition(int geofenceId, int transition, long timestamp, Location location) {
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;
}
}

View File

@@ -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;

View File

@@ -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());
}
}

View File

@@ -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");

View File

@@ -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,

View File

@@ -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);
}

View File

@@ -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");
}
}
/**

View File

@@ -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;
}
}
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;
}
}

View File

@@ -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();

View File

@@ -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());
}
});
}
@@ -1404,6 +1416,62 @@ public class GpsLocationProvider implements LocationProviderInterface {
sendMessage(DOWNLOAD_XTRA_DATA, 0, null);
}
/**
* 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));
}
//=============================================================

View File

@@ -260,6 +260,75 @@ static void TranslateFromObject(
batchOptions.flags = env->CallIntMethod(batchOptionsObject, getFlags);
}
/*
* 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.
*/
@@ -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)}
};