summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorDante Russo <drusso@codeaurora.org>2014-04-10 15:11:45 -0700
committerSteve Kondik <shade@chemlab.org>2015-10-16 19:35:53 -0700
commitd8729538a3dd1e3947278b9b048d254e66ca05d3 (patch)
tree4429b0e60e1b0d9de8fa682a07a46fad22aefa4e
parentd25fef5357480af5bee11ed00baa7e2b27616f18 (diff)
downloadframeworks_base-d8729538a3dd1e3947278b9b048d254e66ca05d3.zip
frameworks_base-d8729538a3dd1e3947278b9b048d254e66ca05d3.tar.gz
frameworks_base-d8729538a3dd1e3947278b9b048d254e66ca05d3.tar.bz2
geofence: Low power geofence HW implementation
HW implemntation overwrites the SW implementation Change-Id: Id738f2808691c35e5507e1d557bc5351456953ad
-rw-r--r--Android.mk2
-rwxr-xr-xcore/res/res/values/config.xml2
-rwxr-xr-xcore/res/res/values/symbols.xml1
-rw-r--r--location/java/android/location/GeoFenceParams.aidl23
-rw-r--r--location/java/android/location/GeoFenceParams.java132
-rw-r--r--location/java/android/location/IGeoFenceListener.aidl30
-rw-r--r--location/java/android/location/IGeoFencer.aidl33
-rw-r--r--services/core/java/com/android/server/LocationManagerService.java70
-rw-r--r--services/core/java/com/android/server/location/GeoFencerBase.java147
-rw-r--r--services/core/java/com/android/server/location/GeoFencerProxy.java148
10 files changed, 582 insertions, 6 deletions
diff --git a/Android.mk b/Android.mk
index 1beb3b2..efc0962 100644
--- a/Android.mk
+++ b/Android.mk
@@ -321,6 +321,8 @@ LOCAL_SRC_FILES += \
location/java/android/location/IGeofenceProvider.aidl \
location/java/android/location/IGpsMeasurementsListener.aidl \
location/java/android/location/IGpsNavigationMessageListener.aidl \
+ location/java/android/location/IGeoFencer.aidl \
+ location/java/android/location/IGeoFenceListener.aidl \
location/java/android/location/IGpsStatusListener.aidl \
location/java/android/location/IGpsStatusProvider.aidl \
location/java/android/location/ILocationListener.aidl \
diff --git a/core/res/res/values/config.xml b/core/res/res/values/config.xml
index 1e5db81..877419d 100755
--- a/core/res/res/values/config.xml
+++ b/core/res/res/values/config.xml
@@ -1177,6 +1177,8 @@
<!-- Component name of the combo network location provider. -->
<string name="config_comboNetworkLocationProvider" translatable="false">com.qualcomm.location</string>
+ <!-- Component name of the service providing geofence API support. -->
+ <string name="config_geofenceProvider" translatable="false">com.qualcomm.location</string>
<!-- Boolean indicating if current platform supports bluetooth SCO for off call
use cases -->
diff --git a/core/res/res/values/symbols.xml b/core/res/res/values/symbols.xml
index db5b46f..6cadd53 100755
--- a/core/res/res/values/symbols.xml
+++ b/core/res/res/values/symbols.xml
@@ -1743,6 +1743,7 @@
<java-symbol type="string" name="config_geofenceProviderPackageName" />
<java-symbol type="string" name="config_networkLocationProviderPackageName" />
<java-symbol type="string" name="config_comboNetworkLocationProvider" />
+ <java-symbol type="string" name="config_geofenceProvider" />
<java-symbol type="string" name="config_wimaxManagerClassname" />
<java-symbol type="string" name="config_wimaxNativeLibLocation" />
<java-symbol type="string" name="config_wimaxServiceClassname" />
diff --git a/location/java/android/location/GeoFenceParams.aidl b/location/java/android/location/GeoFenceParams.aidl
new file mode 100644
index 0000000..3e9be4c
--- /dev/null
+++ b/location/java/android/location/GeoFenceParams.aidl
@@ -0,0 +1,23 @@
+/* Copyright (c) 2012-2013, The Linux Foundation. All rights reserved.
+ *
+ * Not a Contribution, Apache license notifications and license are retained
+ * for attribution purposes only.
+ *
+ * Copyright (C) 2007 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.location;
+
+parcelable GeoFenceParams;
diff --git a/location/java/android/location/GeoFenceParams.java b/location/java/android/location/GeoFenceParams.java
new file mode 100644
index 0000000..aa6e245
--- /dev/null
+++ b/location/java/android/location/GeoFenceParams.java
@@ -0,0 +1,132 @@
+/* Copyright (c) 2012-2013, The Linux Foundation. All rights reserved.
+ *
+ * Not a Contribution, Apache license notifications and license are retained
+ * for attribution purposes only.
+ *
+ * Copyright (C) 2007 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.location;
+
+import android.app.PendingIntent;
+import android.os.Binder;
+import android.os.Parcel;
+import android.os.Parcelable;
+import java.io.PrintWriter;
+
+/**
+ * GeoFenceParams for internal use
+ * {@hide}
+ */
+public class GeoFenceParams implements Parcelable {
+ public static final int ENTERING = 1;
+ public static final int LEAVING = 2;
+ public final int mUid;
+ public final double mLatitude;
+ public final double mLongitude;
+ public final float mRadius;
+ public final long mExpiration;
+ public final PendingIntent mIntent;
+ public final String mPackageName;
+
+ public static final Parcelable.Creator<GeoFenceParams> CREATOR = new Parcelable.Creator<GeoFenceParams>() {
+ public GeoFenceParams createFromParcel(Parcel in) {
+ return new GeoFenceParams(in);
+ }
+
+ @Override
+ public GeoFenceParams[] newArray(int size) {
+ return new GeoFenceParams[size];
+ }
+ };
+
+ public GeoFenceParams(double lat, double lon, float r,
+ long expire, PendingIntent intent, String packageName) {
+ this(Binder.getCallingUid(), lat, lon, r, expire, intent, packageName);
+ }
+
+ public GeoFenceParams(int uid, double lat, double lon, float r,
+ long expire, PendingIntent intent, String packageName) {
+ mUid = uid;
+ mLatitude = lat;
+ mLongitude = lon;
+ mRadius = r;
+ mExpiration = expire;
+ mIntent = intent;
+ mPackageName = packageName;
+ }
+
+ private GeoFenceParams(Parcel in) {
+ mUid = in.readInt();
+ mLatitude = in.readDouble();
+ mLongitude = in.readDouble();
+ mRadius = in.readFloat();
+ mExpiration = in.readLong();
+ mIntent = in.readParcelable(null);
+ mPackageName = in.readString();
+ }
+
+ @Override
+ public int describeContents() {
+ return 0;
+ }
+
+ @Override
+ public void writeToParcel(Parcel dest, int flags) {
+ dest.writeInt(mUid);
+ dest.writeDouble(mLatitude);
+ dest.writeDouble(mLongitude);
+ dest.writeFloat(mRadius);
+ dest.writeLong(mExpiration);
+ dest.writeParcelable(mIntent, 0);
+ dest.writeString(mPackageName);
+ }
+
+ @Override
+ public String toString() {
+ StringBuilder sb = new StringBuilder();
+ sb.append("GeoFenceParams:\n\tmUid - ");
+ sb.append(mUid);
+ sb.append("\n\tmLatitide - ");
+ sb.append(mLatitude);
+ sb.append("\n\tmLongitude - ");
+ sb.append(mLongitude);
+ sb.append("\n\tmRadius - ");
+ sb.append(mRadius);
+ sb.append("\n\tmExpiration - ");
+ sb.append(mExpiration);
+ sb.append("\n\tmIntent - ");
+ sb.append(mIntent);
+ return sb.toString();
+ }
+
+ public long getExpiration() {
+ return mExpiration;
+ }
+
+ public PendingIntent getIntent() {
+ return mIntent;
+ }
+
+ public int getCallerUid() {
+ return mUid;
+ }
+
+ public void dump(PrintWriter pw, String prefix) {
+ pw.println(prefix + this);
+ pw.println(prefix + "mLatitude=" + mLatitude + " mLongitude=" + mLongitude);
+ pw.println(prefix + "mRadius=" + mRadius + " mExpiration=" + mExpiration);
+ }
+}
diff --git a/location/java/android/location/IGeoFenceListener.aidl b/location/java/android/location/IGeoFenceListener.aidl
new file mode 100644
index 0000000..ccec143
--- /dev/null
+++ b/location/java/android/location/IGeoFenceListener.aidl
@@ -0,0 +1,30 @@
+/* Copyright (c) 2012-2013, The Linux Foundation. All rights reserved.
+ *
+ * Not a Contribution, Apache license notifications and license are retained
+ * for attribution purposes only.
+ *
+ * Copyright (C) 2007 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.location;
+
+import android.app.PendingIntent;
+
+/**
+ * {@hide}
+ */
+oneway interface IGeoFenceListener {
+ void geoFenceExpired(in PendingIntent intent);
+}
diff --git a/location/java/android/location/IGeoFencer.aidl b/location/java/android/location/IGeoFencer.aidl
new file mode 100644
index 0000000..d576c6e
--- /dev/null
+++ b/location/java/android/location/IGeoFencer.aidl
@@ -0,0 +1,33 @@
+/* Copyright (c) 2012-2013, The Linux Foundation. All rights reserved.
+ *
+ * Not a Contribution, Apache license notifications and license are retained
+ * for attribution purposes only.
+ *
+ * Copyright (C) 2007 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.location;
+
+import android.location.GeoFenceParams;
+import android.app.PendingIntent;
+
+/**
+ * {@hide}
+ */
+interface IGeoFencer {
+ boolean setGeoFence(in IBinder who, in GeoFenceParams params);
+ void clearGeoFence(in IBinder who, in PendingIntent fence);
+ void clearGeoFenceUser(int uid);
+}
diff --git a/services/core/java/com/android/server/LocationManagerService.java b/services/core/java/com/android/server/LocationManagerService.java
index bc1383c..00e86de 100644
--- a/services/core/java/com/android/server/LocationManagerService.java
+++ b/services/core/java/com/android/server/LocationManagerService.java
@@ -64,6 +64,7 @@ import android.location.Geofence;
import android.location.IGpsGeofenceHardware;
import android.location.IGpsMeasurementsListener;
import android.location.IGpsNavigationMessageListener;
+import android.location.GeoFenceParams;
import android.location.IGpsStatusListener;
import android.location.IGpsStatusProvider;
import android.location.ILocationListener;
@@ -90,6 +91,28 @@ import android.provider.Settings;
import android.util.Log;
import android.util.Slog;
+import com.android.internal.content.PackageMonitor;
+import com.android.internal.location.ProviderProperties;
+import com.android.internal.location.ProviderRequest;
+import com.android.internal.os.BackgroundThread;
+import com.android.server.location.FlpHardwareProvider;
+import com.android.server.location.FusedProxy;
+import com.android.server.location.GeocoderProxy;
+import com.android.server.location.GeofenceProxy;
+import com.android.server.location.GeofenceManager;
+import com.android.server.location.GeoFencerBase;
+import com.android.server.location.GeoFencerProxy;
+import com.android.server.location.GpsLocationProvider;
+import com.android.server.location.LocationBlacklist;
+import com.android.server.location.LocationFudger;
+import com.android.server.location.LocationProviderInterface;
+import com.android.server.location.LocationProviderProxy;
+import com.android.server.location.LocationRequestStatistics;
+import com.android.server.location.LocationRequestStatistics.PackageProviderKey;
+import com.android.server.location.LocationRequestStatistics.PackageStatistics;
+import com.android.server.location.MockProvider;
+import com.android.server.location.PassiveProvider;
+
import java.io.FileDescriptor;
import java.io.PrintWriter;
import java.util.ArrayList;
@@ -157,6 +180,8 @@ public class LocationManagerService extends ILocationManager.Stub {
private String mComboNlpPackageName;
private String mComboNlpReadyMarker;
private String mComboNlpScreenMarker;
+ private String mGeoFencerPackageName;
+ private GeoFencerBase mGeoFencer;
private PowerManager mPowerManager;
private UserManager mUserManager;
private GeocoderProxy mGeocodeProvider;
@@ -512,6 +537,15 @@ public class LocationManagerService extends ILocationManager.Stub {
Slog.e(TAG, "no geocoder provider found");
}
+ mGeoFencerPackageName = resources.getString(
+ com.android.internal.R.string.config_geofenceProvider);
+ if (mGeoFencerPackageName != null &&
+ mPackageManager.resolveService(new Intent(mGeoFencerPackageName), 0) != null){
+ mGeoFencer = GeoFencerProxy.getGeoFencerProxy(mContext, mGeoFencerPackageName);
+ } else {
+ mGeoFencer = null;
+ }
+
// bind to fused hardware provider if supported
// in devices without support, requesting an instance of FlpHardwareProvider will raise an
// exception, so make sure we only do that when supported
@@ -1622,9 +1656,11 @@ public class LocationManagerService extends ILocationManager.Stub {
checkLocationAccess(pid, uid, packageName, allowedResolutionLevel);
synchronized (mLock) {
- Receiver recevier = checkListenerOrIntentLocked(listener, intent, pid, uid,
+ Receiver receiver = checkListenerOrIntentLocked(listener, intent, pid, uid,
packageName, workSource, hideFromAppOps);
- requestLocationUpdatesLocked(sanitizedRequest, recevier, pid, uid, packageName);
+ if (receiver != null) {
+ requestLocationUpdatesLocked(sanitizedRequest, receiver, pid, uid, packageName);
+ }
}
} finally {
Binder.restoreCallingIdentity(identity);
@@ -1683,7 +1719,9 @@ public class LocationManagerService extends ILocationManager.Stub {
// providers may use public location API's, need to clear identity
long identity = Binder.clearCallingIdentity();
try {
- removeUpdatesLocked(receiver);
+ if (receiver != null) {
+ removeUpdatesLocked(receiver);
+ }
} finally {
Binder.restoreCallingIdentity(identity);
}
@@ -1822,8 +1860,20 @@ public class LocationManagerService extends ILocationManager.Stub {
}
long identity = Binder.clearCallingIdentity();
try {
- mGeofenceManager.addFence(sanitizedRequest, geofence, intent, allowedResolutionLevel,
- uid, packageName);
+ if (mGeoFencer != null) {
+ long expiration;
+ if (sanitizedRequest.getExpireAt() == Long.MAX_VALUE) {
+ expiration = -1; // -1 means forever
+ } else {
+ expiration = sanitizedRequest.getExpireAt() - SystemClock.elapsedRealtime();
+ }
+ mGeoFencer.add(new GeoFenceParams(uid, geofence.getLatitude(),
+ geofence.getLongitude(), geofence.getRadius(),
+ expiration, intent, packageName));
+ } else {
+ mGeofenceManager.addFence(sanitizedRequest, geofence, intent,
+ allowedResolutionLevel, uid, packageName);
+ }
} finally {
Binder.restoreCallingIdentity(identity);
}
@@ -1839,7 +1889,11 @@ public class LocationManagerService extends ILocationManager.Stub {
// geo-fence manager uses the public location API, need to clear identity
long identity = Binder.clearCallingIdentity();
try {
- mGeofenceManager.removeFence(geofence, intent);
+ if (mGeoFencer != null) {
+ mGeoFencer.remove(intent);
+ } else {
+ mGeofenceManager.removeFence(geofence, intent);
+ }
} finally {
Binder.restoreCallingIdentity(identity);
}
@@ -2731,6 +2785,10 @@ public class LocationManagerService extends ILocationManager.Stub {
mGeofenceManager.dump(pw);
+ if (mGeoFencer != null) {
+ mGeoFencer.dump(pw, "");
+ }
+
if (mEnabledProviders.size() > 0) {
pw.println(" Enabled Providers:");
for (String i : mEnabledProviders) {
diff --git a/services/core/java/com/android/server/location/GeoFencerBase.java b/services/core/java/com/android/server/location/GeoFencerBase.java
new file mode 100644
index 0000000..eec07ab
--- /dev/null
+++ b/services/core/java/com/android/server/location/GeoFencerBase.java
@@ -0,0 +1,147 @@
+/* Copyright (c) 2012-2013, The Linux Foundation. All rights reserved.
+ *
+ * Not a Contribution, Apache license notifications and license are retained
+ * for attribution purposes only.
+ *
+ * Copyright (C) 2007 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 com.android.server.location;
+
+import android.os.Binder;
+import android.os.Parcelable;
+import android.util.Log;
+import android.app.PendingIntent;
+import android.content.BroadcastReceiver;
+import android.location.GeoFenceParams;
+import android.location.ILocationListener;
+import java.io.PrintWriter;
+import java.util.Map;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.Collection;
+import java.util.ArrayList;
+
+/**
+ * This class defines a base class for GeoFencers
+ *
+ * @hide
+ */
+public abstract class GeoFencerBase {
+ private static final String TAG = "GeoFencerBase";
+ private HashMap<PendingIntent,GeoFenceParams> mGeoFences;
+
+ public GeoFencerBase() {
+ mGeoFences = new HashMap<PendingIntent,GeoFenceParams>();
+ }
+
+ public void add(double latitude, double longitude,
+ float radius, long expiration, PendingIntent intent,
+ String packageName) {
+ add(new GeoFenceParams(latitude, longitude, radius,
+ expiration, intent, packageName));
+ }
+
+ public void add(GeoFenceParams geoFence) {
+ synchronized(mGeoFences) {
+ mGeoFences.put(geoFence.mIntent, geoFence);
+ }
+ if (!start(geoFence)) {
+ synchronized(mGeoFences) {
+ mGeoFences.remove(geoFence.mIntent);
+ }
+ }
+ }
+
+ public void remove(PendingIntent intent) {
+ remove(intent, false);
+ }
+
+ public void remove(PendingIntent intent, boolean localOnly) {
+ GeoFenceParams geoFence = null;
+
+ synchronized(mGeoFences) {
+ geoFence = mGeoFences.remove(intent);
+ }
+
+ if (geoFence != null) {
+ if (!localOnly && !stop(intent)) {
+ synchronized(mGeoFences) {
+ mGeoFences.put(geoFence.mIntent, geoFence);
+ }
+ }
+ }
+ }
+
+ public int getNumbOfGeoFences() {
+ return mGeoFences.size();
+ }
+
+ public Collection<GeoFenceParams> getAllGeoFences() {
+ return mGeoFences.values();
+ }
+
+ public GeoFenceParams getGeoFence(PendingIntent intent) {
+ return mGeoFences.get(intent);
+ }
+
+ public boolean hasCaller(int uid) {
+ for (GeoFenceParams alert : mGeoFences.values()) {
+ if (alert.mUid == uid) {
+ return true;
+ }
+ }
+ return false;
+ }
+
+ public void removeCaller(int uid) {
+ ArrayList<PendingIntent> removedFences = null;
+ for (GeoFenceParams alert : mGeoFences.values()) {
+ if (alert.mUid == uid) {
+ if (removedFences == null) {
+ removedFences = new ArrayList<PendingIntent>();
+ }
+ removedFences.add(alert.mIntent);
+ }
+ }
+ if (removedFences != null) {
+ for (int i = removedFences.size()-1; i>=0; i--) {
+ mGeoFences.remove(removedFences.get(i));
+ }
+ }
+ }
+
+ public void transferService(GeoFencerBase geofencer) {
+ for (GeoFenceParams alert : geofencer.mGeoFences.values()) {
+ geofencer.stop(alert.mIntent);
+ add(alert);
+ }
+ }
+
+ public void dump(PrintWriter pw, String prefix) {
+ if (mGeoFences.size() > 0) {
+ pw.println(prefix + " GeoFences:");
+ prefix += " ";
+ for (Map.Entry<PendingIntent, GeoFenceParams> i
+ : mGeoFences.entrySet()) {
+ pw.println(prefix + i.getKey() + ":");
+ i.getValue().dump(pw, prefix);
+ }
+ }
+ }
+
+ abstract protected boolean start(GeoFenceParams geoFence);
+ abstract protected boolean stop(PendingIntent intent);
+}
diff --git a/services/core/java/com/android/server/location/GeoFencerProxy.java b/services/core/java/com/android/server/location/GeoFencerProxy.java
new file mode 100644
index 0000000..2459080
--- /dev/null
+++ b/services/core/java/com/android/server/location/GeoFencerProxy.java
@@ -0,0 +1,148 @@
+/* Copyright (c) 2012-2013, The Linux Foundation. All rights reserved.
+ *
+ * Not a Contribution, Apache license notifications and license are retained
+ * for attribution purposes only.
+ *
+ * Copyright (C) 2007 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 com.android.server.location;
+
+import android.content.ComponentName;
+import android.content.Context;
+import android.content.Intent;
+import android.content.ServiceConnection;
+import android.os.IBinder;
+import android.os.RemoteException;
+import android.os.UserHandle;
+import android.util.Log;
+import android.app.PendingIntent;
+import android.location.IGeoFencer;
+import android.location.IGeoFenceListener;
+import android.location.GeoFenceParams;
+
+/**
+ * A class for proxying IGeoFenceProvider implementations.
+ *
+ * {@hide}
+ */
+public class GeoFencerProxy extends GeoFencerBase {
+
+ private static final String TAG = "GeoFencerProxy";
+ private static final boolean LOGV_ENABLED = true;
+
+ private final Context mContext;
+ private final Intent mIntent;
+ private IGeoFencer mGeoFencer;
+
+ private final ServiceConnection mServiceConnection = new ServiceConnection() {
+ public void onServiceConnected(ComponentName className, IBinder service) {
+ synchronized (this) {
+ mGeoFencer = IGeoFencer.Stub.asInterface(service);
+ notifyAll();
+ }
+ Log.v(TAG, "onServiceConnected: mGeoFencer - "+mGeoFencer);
+ }
+ public void onServiceDisconnected(ComponentName className) {
+ synchronized (this) {
+ mGeoFencer = null;
+ }
+ Log.v(TAG, "onServiceDisconnected");
+ }
+ };
+
+ private final IGeoFenceListener.Stub mListener = new IGeoFenceListener.Stub() {
+ @Override
+ public void geoFenceExpired(PendingIntent intent) throws RemoteException {
+ logv("geoFenceExpired - "+intent);
+ remove(intent, true);
+ }
+ };
+
+ private static GeoFencerProxy mGeoFencerProxy;
+ public static GeoFencerProxy getGeoFencerProxy(Context context, String serviceName) {
+ if (mGeoFencerProxy == null) {
+ mGeoFencerProxy = new GeoFencerProxy(context, serviceName);
+ }
+ return mGeoFencerProxy;
+ }
+
+ private GeoFencerProxy(Context context, String serviceName) {
+ mContext = context;
+ mIntent = new Intent(serviceName);
+ mContext.bindService(mIntent, mServiceConnection,
+ Context.BIND_AUTO_CREATE | Context.BIND_NOT_FOREGROUND
+ | Context.BIND_ALLOW_OOM_MANAGEMENT);
+ }
+
+ public void removeCaller(int uid) {
+ super.removeCaller(uid);
+ if(mGeoFencer != null) {
+ try {
+ mGeoFencer.clearGeoFenceUser(uid);
+ } catch (RemoteException re) {
+ }
+ }
+ else
+ Log.e(TAG, "removeCaller - mGeoFencer is null");
+ }
+
+ private boolean ensureGeoFencer() {
+ if (mGeoFencer == null) {
+ try {
+ synchronized(mServiceConnection) {
+ logv("waiting...");
+ mServiceConnection.wait(60000);
+ logv("woke up!!!");
+ }
+ } catch (InterruptedException ie) {
+ Log.w(TAG, "Interrupted while waiting for GeoFencer");
+ return false;
+ }
+
+ if (mGeoFencer == null) {
+ Log.w(TAG, "Timed out. No GeoFencer connection");
+ return false;
+ }
+ }
+
+ return true;
+ }
+
+ protected boolean start(GeoFenceParams geofence) {
+ if (ensureGeoFencer()) {
+ try {
+ return mGeoFencer.setGeoFence(mListener, geofence);
+ } catch (RemoteException re) {
+ }
+ }
+ return false;
+ }
+
+ protected boolean stop(PendingIntent intent) {
+ if (ensureGeoFencer()) {
+ try {
+ mGeoFencer.clearGeoFence(mListener, intent);
+ return true;
+ } catch (RemoteException re) {
+ }
+ }
+ return false;
+ }
+
+ private void logv(String s) {
+ if (LOGV_ENABLED) Log.v(TAG, s);
+ }
+}