Add passive location provider.

The passive location provider allows receiving location updates without
actually triggering them.  This allows an application to receive location
updates that are being generated due to other clients of the location manager.

Change-Id: Ibf7a96b089c56875d4f62d3210252ae8d9f32768
Signed-off-by: Mike Lockwood <lockwood@android.com>
diff --git a/services/java/com/android/server/LocationManagerService.java b/services/java/com/android/server/LocationManagerService.java
index e12f2e1..9068966 100644
--- a/services/java/com/android/server/LocationManagerService.java
+++ b/services/java/com/android/server/LocationManagerService.java
@@ -71,6 +71,7 @@
 import com.android.internal.location.GpsNetInitiatedHandler;
 import com.android.internal.location.LocationProviderProxy;
 import com.android.internal.location.MockProvider;
+import com.android.internal.location.PassiveProvider;
 
 /**
  * The service class that manages LocationProviders and issues location
@@ -452,6 +453,11 @@
             mGpsLocationProvider = gpsProvider;
         }
 
+        // create a passive location provider, which is always enabled
+        PassiveProvider passiveProvider = new PassiveProvider(this);
+        addProvider(passiveProvider);
+        mEnabledProviders.add(passiveProvider.getName());
+
         // initialize external network location and geocoder services
         Resources resources = mContext.getResources();
         String serviceName = resources.getString(
@@ -538,7 +544,8 @@
     }
 
     private void checkPermissionsSafe(String provider) {
-        if (LocationManager.GPS_PROVIDER.equals(provider)
+        if ((LocationManager.GPS_PROVIDER.equals(provider)
+                 || LocationManager.PASSIVE_PROVIDER.equals(provider))
             && (mContext.checkCallingOrSelfPermission(ACCESS_FINE_LOCATION)
                 != PackageManager.PERMISSION_GRANTED)) {
             throw new SecurityException("Requires ACCESS_FINE_LOCATION permission");
@@ -1343,7 +1350,7 @@
         }
     }
 
-    public void reportLocation(Location location) {
+    public void reportLocation(Location location, boolean passive) {
         if (mContext.checkCallingOrSelfPermission(INSTALL_LOCATION_PROVIDER)
                 != PackageManager.PERMISSION_GRANTED) {
             throw new SecurityException("Requires INSTALL_LOCATION_PROVIDER permission");
@@ -1351,6 +1358,7 @@
 
         mLocationHandler.removeMessages(MESSAGE_LOCATION_CHANGED, location);
         Message m = Message.obtain(mLocationHandler, MESSAGE_LOCATION_CHANGED, location);
+        m.arg1 = (passive ? 1 : 0);
         mLocationHandler.sendMessageAtFrontOfQueue(m);
     }
 
@@ -1415,8 +1423,8 @@
         return true;
     }
 
-    private void handleLocationChangedLocked(Location location) {
-        String provider = location.getProvider();
+    private void handleLocationChangedLocked(Location location, boolean passive) {
+        String provider = (passive ? LocationManager.PASSIVE_PROVIDER : location.getProvider());
         ArrayList<UpdateRecord> records = mRecordsByProvider.get(provider);
         if (records == null || records.size() == 0) {
             return;
@@ -1502,17 +1510,20 @@
                     synchronized (mLock) {
                         Location location = (Location) msg.obj;
                         String provider = location.getProvider();
+                        boolean passive = (msg.arg1 == 1);
 
-                        // notify other providers of the new location
-                        for (int i = mProviders.size() - 1; i >= 0; i--) {
-                            LocationProviderInterface p = mProviders.get(i);
-                            if (!provider.equals(p.getName())) {
-                                p.updateLocation(location);
+                        if (!passive) {
+                            // notify other providers of the new location
+                            for (int i = mProviders.size() - 1; i >= 0; i--) {
+                                LocationProviderInterface p = mProviders.get(i);
+                                if (!provider.equals(p.getName())) {
+                                    p.updateLocation(location);
+                                }
                             }
                         }
 
                         if (isAllowedBySettingsLocked(provider)) {
-                            handleLocationChangedLocked(location);
+                            handleLocationChangedLocked(location, passive);
                         }
                     }
                 }
@@ -1687,6 +1698,10 @@
         boolean supportsSpeed, boolean supportsBearing, int powerRequirement, int accuracy) {
         checkMockPermissionsSafe();
 
+        if (LocationManager.PASSIVE_PROVIDER.equals(name)) {
+            throw new IllegalArgumentException("Cannot mock the passive location provider");
+        }
+
         long identity = Binder.clearCallingIdentity();
         synchronized (mLock) {
             MockProvider provider = new MockProvider(name, this,