diff options
-rw-r--r-- | Android.mk | 2 | ||||
-rwxr-xr-x | core/res/res/values/config.xml | 2 | ||||
-rwxr-xr-x | core/res/res/values/symbols.xml | 1 | ||||
-rw-r--r-- | location/java/android/location/GeoFenceParams.aidl | 23 | ||||
-rw-r--r-- | location/java/android/location/GeoFenceParams.java | 132 | ||||
-rw-r--r-- | location/java/android/location/IGeoFenceListener.aidl | 30 | ||||
-rw-r--r-- | location/java/android/location/IGeoFencer.aidl | 33 | ||||
-rw-r--r-- | services/core/java/com/android/server/LocationManagerService.java | 70 | ||||
-rw-r--r-- | services/core/java/com/android/server/location/GeoFencerBase.java | 147 | ||||
-rw-r--r-- | services/core/java/com/android/server/location/GeoFencerProxy.java | 148 |
10 files changed, 582 insertions, 6 deletions
@@ -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); + } +} |