Update location framework to accept raw data from GPS HAL.

Change-Id: Ib4feca004b53fa89dcece4299974ab08913455a0
diff --git a/services/core/java/com/android/server/LocationManagerService.java b/services/core/java/com/android/server/LocationManagerService.java
index 10382ba..67e58a6 100644
--- a/services/core/java/com/android/server/LocationManagerService.java
+++ b/services/core/java/com/android/server/LocationManagerService.java
@@ -16,6 +16,27 @@
 
 package com.android.server;
 
+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.GeofenceManager;
+import com.android.server.location.GeofenceProxy;
+import com.android.server.location.GpsLocationProvider;
+import com.android.server.location.GpsMeasurementsProvider;
+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 android.app.AppOpsManager;
 import android.app.PendingIntent;
 import android.content.BroadcastReceiver;
@@ -36,6 +57,7 @@
 import android.location.Criteria;
 import android.location.GeocoderParams;
 import android.location.Geofence;
+import android.location.IGpsMeasurementsListener;
 import android.location.IGpsStatusListener;
 import android.location.IGpsStatusProvider;
 import android.location.ILocationListener;
@@ -62,26 +84,6 @@
 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.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;
@@ -154,6 +156,7 @@
     private LocationWorkerHandler mLocationHandler;
     private PassiveProvider mPassiveProvider;  // track passive provider for special cases
     private LocationBlacklist mBlacklist;
+    private GpsMeasurementsProvider mGpsMeasurementsProvider;
 
     // --- fields below are protected by mLock ---
     // Set of providers that are explicitly enabled
@@ -403,6 +406,7 @@
             addProviderLocked(gpsProvider);
             mRealProviders.put(LocationManager.GPS_PROVIDER, gpsProvider);
         }
+        mGpsMeasurementsProvider = gpsProvider.getGpsMeasurementsProvider();
 
         /*
         Load package name(s) containing location provider support.
@@ -1804,6 +1808,36 @@
     }
 
     @Override
+    public boolean addGpsMeasurementsListener(
+            IGpsMeasurementsListener listener,
+            String packageName) {
+        int allowedResolutionLevel = getCallerAllowedResolutionLevel();
+        checkResolutionLevelIsSufficientForProviderUse(
+                allowedResolutionLevel,
+                LocationManager.GPS_PROVIDER);
+
+        int uid = Binder.getCallingUid();
+        long identity = Binder.clearCallingIdentity();
+        boolean hasLocationAccess;
+        try {
+            hasLocationAccess = checkLocationAccess(uid, packageName, allowedResolutionLevel);
+        } finally {
+            Binder.restoreCallingIdentity(identity);
+        }
+
+        if (!hasLocationAccess) {
+            return false;
+        }
+
+        return mGpsMeasurementsProvider.addListener(listener);
+    }
+
+    @Override
+    public boolean removeGpsMeasurementsListener(IGpsMeasurementsListener listener) {
+        return mGpsMeasurementsProvider.removeListener(listener);
+    }
+
+    @Override
     public boolean sendExtraCommand(String provider, String command, Bundle extras) {
         if (provider == null) {
             // throw NullPointerException to remain compatible with previous implementation
diff --git a/services/core/java/com/android/server/location/GpsLocationProvider.java b/services/core/java/com/android/server/location/GpsLocationProvider.java
index c5b6c7b..8222155 100644
--- a/services/core/java/com/android/server/location/GpsLocationProvider.java
+++ b/services/core/java/com/android/server/location/GpsLocationProvider.java
@@ -16,6 +16,15 @@
 
 package com.android.server.location;
 
+import com.android.internal.app.IAppOpsService;
+import com.android.internal.app.IBatteryStats;
+import com.android.internal.location.GpsNetInitiatedHandler;
+import com.android.internal.location.GpsNetInitiatedHandler.GpsNiNotification;
+import com.android.internal.location.ProviderProperties;
+import com.android.internal.location.ProviderRequest;
+import com.android.internal.telephony.Phone;
+import com.android.internal.telephony.PhoneConstants;
+
 import android.app.AlarmManager;
 import android.app.AppOpsManager;
 import android.app.PendingIntent;
@@ -28,6 +37,7 @@
 import android.hardware.location.GeofenceHardwareImpl;
 import android.location.Criteria;
 import android.location.FusedBatchOptions;
+import android.location.GpsMeasurementsEvent;
 import android.location.IGpsGeofenceHardware;
 import android.location.IGpsStatusListener;
 import android.location.IGpsStatusProvider;
@@ -46,7 +56,6 @@
 import android.os.Binder;
 import android.os.Bundle;
 import android.os.Handler;
-import android.os.IBinder;
 import android.os.Looper;
 import android.os.Message;
 import android.os.PowerManager;
@@ -64,27 +73,17 @@
 import android.util.Log;
 import android.util.NtpTrustedTime;
 
-import com.android.internal.app.IAppOpsService;
-import com.android.internal.app.IBatteryStats;
-import com.android.internal.location.GpsNetInitiatedHandler;
-import com.android.internal.location.ProviderProperties;
-import com.android.internal.location.ProviderRequest;
-import com.android.internal.location.GpsNetInitiatedHandler.GpsNiNotification;
-import com.android.internal.telephony.Phone;
-import com.android.internal.telephony.PhoneConstants;
-
 import java.io.File;
 import java.io.FileDescriptor;
 import java.io.FileInputStream;
 import java.io.IOException;
 import java.io.PrintWriter;
 import java.io.StringReader;
-import java.util.ArrayList;
+import java.net.InetAddress;
+import java.net.UnknownHostException;
 import java.util.Date;
 import java.util.Map.Entry;
 import java.util.Properties;
-import java.net.InetAddress;
-import java.net.UnknownHostException;
 
 /**
  * A GPS implementation of LocationProvider used by LocationManager.
@@ -314,7 +313,12 @@
     private final ILocationManager mILocationManager;
     private Location mLocation = new Location(LocationManager.GPS_PROVIDER);
     private Bundle mLocationExtras = new Bundle();
-    private ArrayList<Listener> mListeners = new ArrayList<Listener>();
+    private GpsStatusListenerHelper mListenerHelper = new GpsStatusListenerHelper() {
+        @Override
+        protected boolean isSupported() {
+            return native_is_measurement_supported();
+        }
+    };
 
     // Handler for processing events
     private Handler mHandler;
@@ -348,49 +352,29 @@
     private final IGpsStatusProvider mGpsStatusProvider = new IGpsStatusProvider.Stub() {
         @Override
         public void addGpsStatusListener(IGpsStatusListener listener) throws RemoteException {
-            if (listener == null) {
-                throw new NullPointerException("listener is null in addGpsStatusListener");
-            }
-
-            synchronized (mListeners) {
-                IBinder binder = listener.asBinder();
-                int size = mListeners.size();
-                for (int i = 0; i < size; i++) {
-                    Listener test = mListeners.get(i);
-                    if (binder.equals(test.mListener.asBinder())) {
-                        // listener already added
-                        return;
-                    }
-                }
-
-                Listener l = new Listener(listener);
-                binder.linkToDeath(l, 0);
-                mListeners.add(l);
-            }
+            mListenerHelper.addListener(listener);
         }
 
         @Override
         public void removeGpsStatusListener(IGpsStatusListener listener) {
-            if (listener == null) {
-                throw new NullPointerException("listener is null in addGpsStatusListener");
-            }
+            mListenerHelper.removeListener(listener);
+        }
+    };
 
-            synchronized (mListeners) {
-                IBinder binder = listener.asBinder();
-                Listener l = null;
-                int size = mListeners.size();
-                for (int i = 0; i < size && l == null; i++) {
-                    Listener test = mListeners.get(i);
-                    if (binder.equals(test.mListener.asBinder())) {
-                        l = test;
-                    }
-                }
+    private final GpsMeasurementsProvider mGpsMeasurementsProvider = new GpsMeasurementsProvider() {
+        @Override
+        public boolean isSupported() {
+            return native_is_measurement_supported();
+        }
 
-                if (l != null) {
-                    mListeners.remove(l);
-                    binder.unlinkToDeath(l, 0);
-                }
-            }
+        @Override
+        protected void onFirstListenerAdded() {
+            native_start_measurement_collection();
+        }
+
+        @Override
+        protected void onLastListenerRemoved() {
+            native_stop_measurement_collection();
         }
     };
 
@@ -402,6 +386,10 @@
         return mGpsGeofenceBinder;
     }
 
+    public GpsMeasurementsProvider getGpsMeasurementsProvider() {
+        return mGpsMeasurementsProvider;
+    }
+
     private final BroadcastReceiver mBroadcastReciever = new BroadcastReceiver() {
         @Override public void onReceive(Context context, Intent intent) {
             String action = intent.getAction();
@@ -892,26 +880,6 @@
         }
     }
 
-    private final class Listener implements IBinder.DeathRecipient {
-        final IGpsStatusListener mListener;
-
-        Listener(IGpsStatusListener listener) {
-            mListener = listener;
-        }
-
-        @Override
-        public void binderDied() {
-            if (DEBUG) Log.d(TAG, "GPS status listener died");
-
-            synchronized (mListeners) {
-                mListeners.remove(this);
-            }
-            if (mListener != null) {
-                mListener.asBinder().unlinkToDeath(this, 0);
-            }
-        }
-    }
-
     private void updateClientUids(WorkSource source) {
         // Update work source.
         WorkSource[] changes = mClientSource.setReturningDiffs(source);
@@ -1185,20 +1153,7 @@
             if (DEBUG) Log.d(TAG, "TTFF: " + mTimeToFirstFix);
 
             // notify status listeners
-            synchronized (mListeners) {
-                int size = mListeners.size();
-                for (int i = 0; i < size; i++) {
-                    Listener listener = mListeners.get(i);
-                    try {
-                        listener.mListener.onFirstFix(mTimeToFirstFix);
-                    } catch (RemoteException e) {
-                        Log.w(TAG, "RemoteException in stopNavigating");
-                        mListeners.remove(listener);
-                        // adjust for size of list changing
-                        size--;
-                    }
-                }
-            }
+            mListenerHelper.onFirstFix(mTimeToFirstFix);
         }
 
         if (mSingleShot) {
@@ -1232,49 +1187,31 @@
     private void reportStatus(int status) {
         if (DEBUG) Log.v(TAG, "reportStatus status: " + status);
 
-        synchronized (mListeners) {
-            boolean wasNavigating = mNavigating;
+        boolean wasNavigating = mNavigating;
+        switch (status) {
+            case GPS_STATUS_SESSION_BEGIN:
+                mNavigating = true;
+                mEngineOn = true;
+                break;
+            case GPS_STATUS_SESSION_END:
+                mNavigating = false;
+                break;
+            case GPS_STATUS_ENGINE_ON:
+                mEngineOn = true;
+                break;
+            case GPS_STATUS_ENGINE_OFF:
+                mEngineOn = false;
+                mNavigating = false;
+                break;
+        }
 
-            switch (status) {
-                case GPS_STATUS_SESSION_BEGIN:
-                    mNavigating = true;
-                    mEngineOn = true;
-                    break;
-                case GPS_STATUS_SESSION_END:
-                    mNavigating = false;
-                    break;
-                case GPS_STATUS_ENGINE_ON:
-                    mEngineOn = true;
-                    break;
-                case GPS_STATUS_ENGINE_OFF:
-                    mEngineOn = false;
-                    mNavigating = false;
-                    break;
-            }
+        if (wasNavigating != mNavigating) {
+            mListenerHelper.onStatusChanged(mNavigating);
 
-            if (wasNavigating != mNavigating) {
-                int size = mListeners.size();
-                for (int i = 0; i < size; i++) {
-                    Listener listener = mListeners.get(i);
-                    try {
-                        if (mNavigating) {
-                            listener.mListener.onGpsStarted();
-                        } else {
-                            listener.mListener.onGpsStopped();
-                        }
-                    } catch (RemoteException e) {
-                        Log.w(TAG, "RemoteException in reportStatus");
-                        mListeners.remove(listener);
-                        // adjust for size of list changing
-                        size--;
-                    }
-                }
-
-                // send an intent to notify that the GPS has been enabled or disabled.
-                Intent intent = new Intent(LocationManager.GPS_ENABLED_CHANGE_ACTION);
-                intent.putExtra(LocationManager.EXTRA_GPS_ENABLED, mNavigating);
-                mContext.sendBroadcastAsUser(intent, UserHandle.ALL);
-            }
+            // send an intent to notify that the GPS has been enabled or disabled
+            Intent intent = new Intent(LocationManager.GPS_ENABLED_CHANGE_ACTION);
+            intent.putExtra(LocationManager.EXTRA_GPS_ENABLED, mNavigating);
+            mContext.sendBroadcastAsUser(intent, UserHandle.ALL);
         }
     }
 
@@ -1282,25 +1219,16 @@
      * called from native code to update SV info
      */
     private void reportSvStatus() {
-
         int svCount = native_read_sv_status(mSvs, mSnrs, mSvElevations, mSvAzimuths, mSvMasks);
-
-        synchronized (mListeners) {
-            int size = mListeners.size();
-            for (int i = 0; i < size; i++) {
-                Listener listener = mListeners.get(i);
-                try {
-                    listener.mListener.onSvStatusChanged(svCount, mSvs, mSnrs,
-                            mSvElevations, mSvAzimuths, mSvMasks[EPHEMERIS_MASK],
-                            mSvMasks[ALMANAC_MASK], mSvMasks[USED_FOR_FIX_MASK]);
-                } catch (RemoteException e) {
-                    Log.w(TAG, "RemoteException in reportSvInfo");
-                    mListeners.remove(listener);
-                    // adjust for size of list changing
-                    size--;
-                }
-            }
-        }
+        mListenerHelper.onSvStatusChanged(
+                svCount,
+                mSvs,
+                mSnrs,
+                mSvElevations,
+                mSvAzimuths,
+                mSvMasks[EPHEMERIS_MASK],
+                mSvMasks[ALMANAC_MASK],
+                mSvMasks[USED_FOR_FIX_MASK]);
 
         if (VERBOSE) {
             Log.v(TAG, "SV count: " + svCount +
@@ -1398,26 +1326,16 @@
      * called from native code to report NMEA data received
      */
     private void reportNmea(long timestamp) {
-        synchronized (mListeners) {
-            int size = mListeners.size();
-            if (size > 0) {
-                // don't bother creating the String if we have no listeners
-                int length = native_read_nmea(mNmeaBuffer, mNmeaBuffer.length);
-                String nmea = new String(mNmeaBuffer, 0, length);
+        int length = native_read_nmea(mNmeaBuffer, mNmeaBuffer.length);
+        String nmea = new String(mNmeaBuffer, 0 /* offset */, length);
+        mListenerHelper.onNmeaReceived(timestamp, nmea);
+    }
 
-                for (int i = 0; i < size; i++) {
-                    Listener listener = mListeners.get(i);
-                    try {
-                        listener.mListener.onNmeaReceived(timestamp, nmea);
-                    } catch (RemoteException e) {
-                        Log.w(TAG, "RemoteException in reportNmea");
-                        mListeners.remove(listener);
-                        // adjust for size of list changing
-                        size--;
-                    }
-                }
-            }
-        }
+    /**
+     * called from native code - Gps Data callback
+     */
+    private void reportMeasurementData(GpsMeasurementsEvent event) {
+        mGpsMeasurementsProvider.onMeasurementsAvailable(event);
     }
 
     /**
@@ -1845,7 +1763,7 @@
                 Log.e(TAG, "No APN found to select.");
             }
         } catch (Exception e) {
-            Log.e(TAG, "Error encountered on selectiong the APN.", e);
+            Log.e(TAG, "Error encountered on selecting the APN.", e);
         } finally {
             if (cursor != null) {
                 cursor.close();
@@ -2008,4 +1926,9 @@
     private static native boolean native_remove_geofence(int geofenceId);
     private static native boolean native_resume_geofence(int geofenceId, int transitions);
     private static native boolean native_pause_geofence(int geofenceId);
+
+    // Gps Hal measurements support.
+    private static native boolean native_is_measurement_supported();
+    private static native boolean native_start_measurement_collection();
+    private static native boolean native_stop_measurement_collection();
 }
diff --git a/services/core/java/com/android/server/location/GpsMeasurementsProvider.java b/services/core/java/com/android/server/location/GpsMeasurementsProvider.java
new file mode 100644
index 0000000..001f638
--- /dev/null
+++ b/services/core/java/com/android/server/location/GpsMeasurementsProvider.java
@@ -0,0 +1,44 @@
+/*
+ * Copyright (C) 2014 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.location.GpsMeasurementsEvent;
+import android.location.IGpsMeasurementsListener;
+import android.os.RemoteException;
+
+/**
+ * An base implementation for GPS measurements provider.
+ * It abstracts out the responsibility of handling listeners, while still allowing technology
+ * specific implementations to be built.
+ *
+ * @hide
+ */
+public abstract class GpsMeasurementsProvider
+        extends RemoteListenerHelper<IGpsMeasurementsListener> {
+
+    public void onMeasurementsAvailable(final GpsMeasurementsEvent event) {
+        ListenerOperation<IGpsMeasurementsListener> operation =
+                new ListenerOperation<IGpsMeasurementsListener>() {
+            @Override
+            public void execute(IGpsMeasurementsListener listener) throws RemoteException {
+                listener.onGpsMeasurementsReceived(event);
+            }
+        };
+
+        foreach(operation);
+    }
+}
diff --git a/services/core/java/com/android/server/location/GpsStatusListenerHelper.java b/services/core/java/com/android/server/location/GpsStatusListenerHelper.java
new file mode 100644
index 0000000..b741e75
--- /dev/null
+++ b/services/core/java/com/android/server/location/GpsStatusListenerHelper.java
@@ -0,0 +1,91 @@
+/*
+ * Copyright (C) 2014 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.location.IGpsStatusListener;
+import android.os.RemoteException;
+
+/**
+ * Implementation of a handler for {@link IGpsStatusListener}.
+ */
+abstract class GpsStatusListenerHelper extends RemoteListenerHelper<IGpsStatusListener> {
+    public void onFirstFix(final int timeToFirstFix) {
+        Operation operation = new Operation() {
+            @Override
+            public void execute(IGpsStatusListener listener) throws RemoteException {
+                listener.onFirstFix(timeToFirstFix);
+            }
+        };
+
+        foreach(operation);
+    }
+
+    public void onStatusChanged(final boolean isNavigating) {
+        Operation operation = new Operation() {
+            @Override
+            public void execute(IGpsStatusListener listener) throws RemoteException {
+                if (isNavigating) {
+                    listener.onGpsStarted();
+                } else {
+                    listener.onGpsStopped();
+                }
+            }
+        };
+
+        foreach(operation);
+    }
+
+    public void onSvStatusChanged(
+            final int svCount,
+            final int[] prns,
+            final float[] snrs,
+            final float[] elevations,
+            final float[] azimuths,
+            final int ephemerisMask,
+            final int almanacMask,
+            final int usedInFixMask) {
+        Operation operation = new Operation() {
+            @Override
+            public void execute(IGpsStatusListener listener) throws RemoteException {
+                listener.onSvStatusChanged(
+                        svCount,
+                        prns,
+                        snrs,
+                        elevations,
+                        azimuths,
+                        ephemerisMask,
+                        almanacMask,
+                        usedInFixMask);
+            }
+        };
+
+        foreach(operation);
+    }
+
+    public void onNmeaReceived(final long timestamp, final String nmea) {
+        Operation operation = new Operation() {
+            @Override
+            public void execute(IGpsStatusListener listener) throws RemoteException {
+                listener.onNmeaReceived(timestamp, nmea);
+            }
+        };
+
+        foreach(operation);
+    }
+
+    private abstract class Operation implements ListenerOperation<IGpsStatusListener> { }
+}
diff --git a/services/core/java/com/android/server/location/RemoteListenerHelper.java b/services/core/java/com/android/server/location/RemoteListenerHelper.java
new file mode 100644
index 0000000..79335f7
--- /dev/null
+++ b/services/core/java/com/android/server/location/RemoteListenerHelper.java
@@ -0,0 +1,148 @@
+/*
+ * Copyright (C) 2014 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 com.android.internal.util.Preconditions;
+
+import android.annotation.NonNull;
+import android.os.IBinder;
+import android.os.IInterface;
+import android.os.RemoteException;
+import android.util.Log;
+
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.HashMap;
+
+/**
+ * A helper class, that handles operations in remote listeners, and tracks for remote process death.
+ */
+abstract class RemoteListenerHelper<TListener extends IInterface> {
+    private static final String TAG = "RemoteListenerHelper";
+
+    private final HashMap<IBinder, LinkedListener> mListenerMap =
+            new HashMap<IBinder, LinkedListener>();
+
+    public boolean addListener(@NonNull TListener listener) {
+        Preconditions.checkNotNull(listener, "Attempted to register a 'null' listener.");
+
+        if (!isSupported()) {
+            Log.e(TAG, "Refused to add listener, the feature is not supported.");
+            return false;
+        }
+
+        IBinder binder = listener.asBinder();
+        LinkedListener deathListener = new LinkedListener(listener);
+        synchronized (mListenerMap) {
+            if (mListenerMap.containsKey(binder)) {
+                // listener already added
+                return true;
+            }
+
+            try {
+                binder.linkToDeath(deathListener, 0 /* flags */);
+            } catch (RemoteException e) {
+                // if the remote process registering the listener is already death, just swallow the
+                // exception and continue
+                Log.e(TAG, "Remote listener already died.", e);
+                return false;
+            }
+
+            mListenerMap.put(binder, deathListener);
+            if (mListenerMap.size() == 1) {
+                onFirstListenerAdded();
+            }
+        }
+
+        return true;
+    }
+
+    public boolean removeListener(@NonNull TListener listener) {
+        Preconditions.checkNotNull(listener, "Attempted to remove a 'null' listener.");
+
+        if (!isSupported()) {
+            Log.e(TAG, "Refused to remove listener, the feature is not supported.");
+            return false;
+        }
+
+        IBinder binder = listener.asBinder();
+        LinkedListener linkedListener;
+        synchronized (mListenerMap) {
+            linkedListener = mListenerMap.remove(binder);
+            if (mListenerMap.isEmpty() && linkedListener != null) {
+                onLastListenerRemoved();
+            }
+        }
+
+        if (linkedListener != null) {
+            binder.unlinkToDeath(linkedListener, 0 /* flags */);
+        }
+
+        return true;
+    }
+
+    protected abstract boolean isSupported();
+
+    protected void onFirstListenerAdded() {
+        // event triggered when the first listener has been added
+    }
+
+    protected void onLastListenerRemoved() {
+        // event triggered when the last listener has bee removed
+    }
+
+    protected interface ListenerOperation<TListener extends IInterface> {
+        void execute(TListener listener) throws RemoteException;
+    }
+
+    protected void foreach(ListenerOperation operation) {
+        Collection<LinkedListener> linkedListeners;
+        synchronized (mListenerMap) {
+            Collection<LinkedListener> values = mListenerMap.values();
+            linkedListeners = new ArrayList<LinkedListener>(values);
+        }
+
+        for (LinkedListener linkedListener : linkedListeners) {
+            TListener listener = linkedListener.getUnderlyingListener();
+            try {
+                operation.execute(listener);
+            } catch (RemoteException e) {
+                Log.e(TAG, "Error in monitored listener.", e);
+                removeListener(listener);
+            }
+        }
+    }
+
+    private class LinkedListener implements IBinder.DeathRecipient {
+        private final TListener mListener;
+
+        public LinkedListener(@NonNull TListener listener) {
+            mListener = listener;
+        }
+
+        @NonNull
+        public TListener getUnderlyingListener() {
+            return mListener;
+        }
+
+        @Override
+        public void binderDied() {
+            Log.d(TAG, "Remote Listener died: " + mListener);
+            removeListener(mListener);
+        }
+    }
+}
diff --git a/services/core/jni/com_android_server_location_GpsLocationProvider.cpp b/services/core/jni/com_android_server_location_GpsLocationProvider.cpp
index 5bafb52..87626d0 100644
--- a/services/core/jni/com_android_server_location_GpsLocationProvider.cpp
+++ b/services/core/jni/com_android_server_location_GpsLocationProvider.cpp
@@ -52,6 +52,7 @@
 static jmethodID method_reportGeofenceRemoveStatus;
 static jmethodID method_reportGeofencePauseStatus;
 static jmethodID method_reportGeofenceResumeStatus;
+static jmethodID method_reportMeasurementData;
 
 static const GpsInterface* sGpsInterface = NULL;
 static const GpsXtraInterface* sGpsXtraInterface = NULL;
@@ -60,6 +61,7 @@
 static const GpsDebugInterface* sGpsDebugInterface = NULL;
 static const AGpsRilInterface* sAGpsRilInterface = NULL;
 static const GpsGeofencingInterface* sGpsGeofencingInterface = NULL;
+static const GpsMeasurementInterface* sGpsMeasurementInterface = NULL;
 
 // temporary storage for GPS callbacks
 static GpsSvStatus  sGpsSvStatus;
@@ -441,6 +443,10 @@
             "(II)V");
     method_reportGeofencePauseStatus = env->GetMethodID(clazz,"reportGeofencePauseStatus",
             "(II)V");
+    method_reportMeasurementData = env->GetMethodID(
+            clazz,
+            "reportMeasurementData",
+            "(Landroid/location/GpsMeasurementsEvent;)V");
 
     err = hw_get_module(GPS_HARDWARE_MODULE_ID, (hw_module_t const**)&module);
     if (err == 0) {
@@ -464,6 +470,8 @@
             (const AGpsRilInterface*)sGpsInterface->get_extension(AGPS_RIL_INTERFACE);
         sGpsGeofencingInterface =
             (const GpsGeofencingInterface*)sGpsInterface->get_extension(GPS_GEOFENCING_INTERFACE);
+        sGpsMeasurementInterface =
+            (const GpsMeasurementInterface*)sGpsInterface->get_extension(GPS_MEASUREMENT_INTERFACE);
     }
 }
 
@@ -851,42 +859,500 @@
     return JNI_FALSE;
 }
 
+static jobject translate_gps_clock(JNIEnv* env, GpsClock* clock) {
+    const char* doubleSignature = "(D)V";
+
+    jclass gpsClockClass = env->FindClass("android/location/GpsClock");
+    jmethodID gpsClockCtor = env->GetMethodID(gpsClockClass, "<init>", "()V");
+
+    jobject gpsClockObject = env->NewObject(gpsClockClass, gpsClockCtor);
+    GpsClockFlags flags = clock->flags;
+
+    if (flags & GPS_CLOCK_HAS_LEAP_SECOND) {
+        jmethodID setterMethod = env->GetMethodID(gpsClockClass, "setLeapSecond", "(S)V");
+        env->CallObjectMethod(gpsClockObject, setterMethod, clock->leap_second);
+   }
+
+    jmethodID setterMethod = env->GetMethodID(gpsClockClass, "setTimeInNs", "(J)V");
+    env->CallObjectMethod(gpsClockObject, setterMethod, clock->time_ns);
+
+    if (flags & GPS_CLOCK_HAS_TIME_UNCERTAINTY) {
+        jmethodID setterMethod = env->GetMethodID(
+                gpsClockClass,
+                "setTimeUncertaintyInNs",
+                doubleSignature);
+        env->CallObjectMethod(gpsClockObject, setterMethod, clock->time_uncertainty_ns);
+    }
+
+    if (flags & GPS_CLOCK_HAS_BIAS) {
+        jmethodID setterMethod = env->GetMethodID(gpsClockClass, "setBiasInNs", doubleSignature);
+        env->CallObjectMethod(gpsClockObject, setterMethod, clock->bias_ns);
+    }
+
+    if (flags & GPS_CLOCK_HAS_BIAS_UNCERTAINTY) {
+        jmethodID setterMethod = env->GetMethodID(
+                gpsClockClass,
+                "setBiasUncertaintyInNs",
+                doubleSignature);
+        env->CallObjectMethod(gpsClockObject, setterMethod, clock->bias_uncertainty_ns);
+    }
+
+    if (flags & GPS_CLOCK_HAS_DRIFT) {
+        jmethodID setterMethod = env->GetMethodID(
+                gpsClockClass,
+                "setDriftInNsPerSec",
+                doubleSignature);
+        env->CallObjectMethod(gpsClockObject, setterMethod, clock->drift_nsps);
+    }
+
+    if (flags & GPS_CLOCK_HAS_DRIFT_UNCERTAINTY) {
+        jmethodID setterMethod = env->GetMethodID(
+                gpsClockClass,
+                "setDriftUncertaintyInNsPerSec",
+                doubleSignature);
+        env->CallObjectMethod(gpsClockObject, setterMethod, clock->drift_uncertainty_nsps);
+    }
+
+    return gpsClockObject;
+}
+
+static jobject translate_gps_measurement(
+        JNIEnv* env,
+        GpsMeasurement* measurement,
+        uint32_t time_ns) {
+    const char* shortSignature = "(S)V";
+    const char* longSignature = "(J)V";
+    const char* floatSignature = "(F)V";
+    const char* doubleSignature = "(D)V";
+
+    jclass gpsMeasurementClass = env->FindClass("android/location/GpsMeasurement");
+    jmethodID gpsMeasurementCtor = env->GetMethodID(gpsMeasurementClass, "<init>", "()V");
+
+    jobject gpsMeasurementObject = env->NewObject(gpsMeasurementClass, gpsMeasurementCtor);
+    GpsMeasurementFlags flags = measurement->flags;
+
+
+    jmethodID prnSetterMethod = env->GetMethodID(gpsMeasurementClass, "setPrn", "(B)V");
+    env->CallObjectMethod(gpsMeasurementObject, prnSetterMethod, measurement->prn);
+
+    jmethodID localTimeSetterMethod =
+            env->GetMethodID(gpsMeasurementClass, "setLocalTimeInNs", longSignature);
+    env->CallObjectMethod(
+            gpsMeasurementObject,
+            localTimeSetterMethod,
+            time_ns + measurement->time_offset_ns);
+
+    jmethodID receivedGpsTowSetterMethod =
+            env->GetMethodID(gpsMeasurementClass, "setReceivedGpsTowInNs", longSignature);
+    env->CallObjectMethod(
+            gpsMeasurementObject,
+            receivedGpsTowSetterMethod,
+            measurement->received_gps_tow_ns);
+
+    jmethodID cn0SetterMethod = env->GetMethodID(
+            gpsMeasurementClass,
+            "setCn0InDbHz",
+            doubleSignature);
+    env->CallObjectMethod(gpsMeasurementObject, cn0SetterMethod, measurement->c_n0_dbhz);
+
+    jmethodID pseudorangeRateSetterMethod = env->GetMethodID(
+            gpsMeasurementClass,
+            "setPseudorangeRateInMetersPerSec",
+            doubleSignature);
+    env->CallObjectMethod(
+            gpsMeasurementObject,
+            pseudorangeRateSetterMethod,
+            measurement->pseudorange_rate_mpersec);
+
+    jmethodID pseudorangeRateUncertaintySetterMethod = env->GetMethodID(
+            gpsMeasurementClass,
+            "setPseudorangeRateUncertaintyInMetersPerSec",
+            doubleSignature);
+    env->CallObjectMethod(
+            gpsMeasurementObject,
+            pseudorangeRateUncertaintySetterMethod,
+            measurement->pseudorange_rate_uncertainty_mpersec);
+
+    jmethodID accumulatedDeltaRangeSetterMethod = env->GetMethodID(
+            gpsMeasurementClass,
+            "setAccumulatedDeltaRangeInMeters",
+            doubleSignature);
+    env->CallVoidMethod(
+            gpsMeasurementObject,
+            accumulatedDeltaRangeSetterMethod,
+            measurement->accumulated_delta_range_m);
+
+    jmethodID accumulatedDeltaRangeUncertaintySetterMethod = env->GetMethodID(
+            gpsMeasurementClass,
+            "setAccumulatedDeltaRangeUncertaintyInMeters",
+            doubleSignature);
+    env->CallVoidMethod(
+            gpsMeasurementObject,
+            accumulatedDeltaRangeUncertaintySetterMethod,
+            measurement->accumulated_delta_range_uncertainty_m);
+
+
+    if (flags & GPS_MEASUREMENT_HAS_PSEUDORANGE) {
+        jmethodID setterMethod = env->GetMethodID(
+                gpsMeasurementClass,
+                "setPseudorangeInMeters",
+                doubleSignature);
+        env->CallObjectMethod(gpsMeasurementObject, setterMethod, measurement->pseudorange_m);
+    }
+
+    if (flags & GPS_MEASUREMENT_HAS_PSEUDORANGE_UNCERTAINTY) {
+        jmethodID setterMethod = env->GetMethodID(
+                gpsMeasurementClass,
+                "setPseudorangeUncertaintyInMeters",
+                doubleSignature);
+        env->CallObjectMethod(
+                gpsMeasurementObject,
+                setterMethod,
+                measurement->pseudorange_uncertainty_m);
+    }
+
+    if (flags & GPS_MEASUREMENT_HAS_CODE_PHASE) {
+        jmethodID setterMethod = env->GetMethodID(
+                gpsMeasurementClass,
+                "setCodePhaseInChips",
+                doubleSignature);
+        env->CallObjectMethod(gpsMeasurementObject, setterMethod, measurement->code_phase_chips);
+    }
+
+    if (flags & GPS_MEASUREMENT_HAS_CODE_PHASE_UNCERTAINTY) {
+        jmethodID setterMethod = env->GetMethodID(
+                gpsMeasurementClass,
+                "setCodePhaseUncertaintyInChips",
+                doubleSignature);
+        env->CallObjectMethod(
+                gpsMeasurementObject,
+                setterMethod,
+                measurement->code_phase_uncertainty_chips);
+    }
+
+    if (flags & GPS_MEASUREMENT_HAS_CARRIER_FREQUENCY) {
+        jmethodID setterMethod = env->GetMethodID(
+                gpsMeasurementClass,
+                "setCarrierFrequencyInHz",
+                 floatSignature);
+        env->CallObjectMethod(
+                gpsMeasurementObject,
+                setterMethod,
+                measurement->carrier_frequency_hz);
+    }
+
+    if (flags & GPS_MEASUREMENT_HAS_CARRIER_CYCLES) {
+        jmethodID setterMethod =
+                env->GetMethodID(gpsMeasurementClass, "setCarrierCycles", longSignature);
+        env->CallObjectMethod(gpsMeasurementObject, setterMethod, measurement->carrier_cycles);
+    }
+
+    if (flags & GPS_MEASUREMENT_HAS_CARRIER_PHASE) {
+        jmethodID setterMethod =
+                env->GetMethodID(gpsMeasurementClass, "setCarrierPhase", doubleSignature);
+        env->CallObjectMethod(gpsMeasurementObject, setterMethod, measurement->carrier_phase);
+    }
+
+    if (flags & GPS_MEASUREMENT_HAS_CARRIER_PHASE_UNCERTAINTY) {
+        jmethodID setterMethod = env->GetMethodID(
+                gpsMeasurementClass,
+                "setCarrierPhaseUncertainty",
+                doubleSignature);
+        env->CallObjectMethod(
+                gpsMeasurementObject,
+                setterMethod,
+                measurement->carrier_phase_uncertainty);
+    }
+
+    jmethodID lossOfLockSetterMethod =
+            env->GetMethodID(gpsMeasurementClass, "setLossOfLock", shortSignature);
+    env->CallObjectMethod(gpsMeasurementObject, lossOfLockSetterMethod, measurement->loss_of_lock);
+
+    if (flags & GPS_MEASUREMENT_HAS_BIT_NUMBER) {
+        jmethodID setterMethod = env->GetMethodID(
+                gpsMeasurementClass,
+                "setBitNumber",
+                shortSignature);
+        env->CallObjectMethod(gpsMeasurementObject, setterMethod, measurement->bit_number);
+    }
+
+    if (flags & GPS_MEASUREMENT_HAS_TIME_FROM_LAST_BIT) {
+        jmethodID setterMethod = env->GetMethodID(
+                gpsMeasurementClass,
+                "setTimeFromLastBitInNs",
+                longSignature);
+        env->CallObjectMethod(
+                gpsMeasurementObject,
+                setterMethod,
+                measurement->time_from_last_bit_ns);
+    }
+
+    if (flags & GPS_MEASUREMENT_HAS_DOPPLER_SHIFT) {
+        jmethodID setterMethod = env->GetMethodID(
+                gpsMeasurementClass,
+                "setDopplerShiftInHz",
+                doubleSignature);
+        env->CallObjectMethod(gpsMeasurementObject, setterMethod, measurement->doppler_shift_hz);
+    }
+
+    if (flags & GPS_MEASUREMENT_HAS_DOPPLER_SHIFT_UNCERTAINTY) {
+        jmethodID setterMethod = env->GetMethodID(
+                gpsMeasurementClass,
+                "setDopplerShiftUncertaintyInHz",
+                doubleSignature);
+        env->CallObjectMethod(
+                gpsMeasurementObject,
+                setterMethod,
+                measurement->doppler_shift_uncertainty_hz);
+    }
+
+    jmethodID multipathIndicatorSetterMethod = env->GetMethodID(
+            gpsMeasurementClass,
+            "setMultipathIndicator",
+            shortSignature);
+    env->CallObjectMethod(
+            gpsMeasurementObject,
+            multipathIndicatorSetterMethod,
+            measurement->multipath_indicator);
+
+    if (flags & GPS_MEASUREMENT_HAS_SNR) {
+        jmethodID setterMethod =
+                env->GetMethodID(gpsMeasurementClass, "setSnrInDb", doubleSignature);
+        env->CallObjectMethod(gpsMeasurementObject, setterMethod, measurement->snr_db);
+    }
+
+    if (flags & GPS_MEASUREMENT_HAS_ELEVATION) {
+        jmethodID setterMethod = env->GetMethodID(
+                gpsMeasurementClass,
+                "setElevationInDeg",
+                doubleSignature);
+        env->CallObjectMethod(gpsMeasurementObject, setterMethod, measurement->elevation_deg);
+    }
+
+    if (flags & GPS_MEASUREMENT_HAS_ELEVATION_UNCERTAINTY) {
+        jmethodID setterMethod = env->GetMethodID(
+                gpsMeasurementClass,
+                "setElevationUncertaintyInDeg",
+                doubleSignature);
+        env->CallObjectMethod(
+                gpsMeasurementObject,
+                setterMethod,
+                measurement->elevation_uncertainty_deg);
+    }
+
+    if (flags & GPS_MEASUREMENT_HAS_AZIMUTH) {
+        jmethodID setterMethod =
+                env->GetMethodID(gpsMeasurementClass, "setAzimuthInDeg", doubleSignature);
+        env->CallObjectMethod(gpsMeasurementObject, setterMethod, measurement->azimuth_deg);
+    }
+
+    if (flags & GPS_MEASUREMENT_HAS_AZIMUTH_UNCERTAINTY) {
+        jmethodID setterMethod = env->GetMethodID(
+                gpsMeasurementClass,
+                "setAzimuthUncertaintyInDeg",
+                doubleSignature);
+        env->CallObjectMethod(
+                gpsMeasurementObject,
+                setterMethod,
+                measurement->azimuth_uncertainty_deg);
+    }
+
+    jmethodID usedInFixSetterMethod = env->GetMethodID(gpsMeasurementClass, "setUsedInFix", "(Z)V");
+    env->CallObjectMethod(
+            gpsMeasurementObject,
+            usedInFixSetterMethod,
+            (flags & GPS_MEASUREMENT_HAS_USED_IN_FIX) && measurement->used_in_fix);
+
+    return gpsMeasurementObject;
+}
+
+static jobjectArray translate_gps_measurements(JNIEnv* env, GpsData* data) {
+    size_t measurementCount = data->measurement_count;
+    if (measurementCount == 0) {
+        return NULL;
+    }
+
+    jclass gpsMeasurementClass = env->FindClass("android/location/GpsMeasurement");
+    jobjectArray gpsMeasurementArray = env->NewObjectArray(
+            measurementCount,
+            gpsMeasurementClass,
+            NULL /* initialElement */);
+
+    GpsMeasurement* gpsMeasurements = data->measurements;
+    for (uint16_t i = 0; i < measurementCount; ++i) {
+        jobject gpsMeasurement = translate_gps_measurement(
+                env,
+                &gpsMeasurements[i],
+                data->clock.time_ns);
+        env->SetObjectArrayElement(gpsMeasurementArray, i, gpsMeasurement);
+        env->DeleteLocalRef(gpsMeasurement);
+    }
+
+    env->DeleteLocalRef(gpsMeasurementClass);
+    return gpsMeasurementArray;
+}
+
+static void measurement_callback(GpsData* data) {
+    JNIEnv* env = AndroidRuntime::getJNIEnv();
+    if (data == NULL) {
+        ALOGE("Invalid data provided to gps_measurement_callback");
+        return;
+    }
+
+    if (data->size == sizeof(GpsData)) {
+        jobject gpsClock = translate_gps_clock(env, &data->clock);
+        jobjectArray measurementArray = translate_gps_measurements(env, data);
+
+        jclass gpsMeasurementsEventClass = env->FindClass("android/location/GpsMeasurementsEvent");
+        jmethodID gpsMeasurementsEventCtor = env->GetMethodID(
+                gpsMeasurementsEventClass,
+                "<init>",
+                "(Landroid/location/GpsClock;[Landroid/location/GpsMeasurement;)V");
+
+        jobject gpsMeasurementsEvent = env->NewObject(
+                gpsMeasurementsEventClass,
+                gpsMeasurementsEventCtor,
+                gpsClock,
+                measurementArray);
+
+        env->CallVoidMethod(mCallbacksObj, method_reportMeasurementData, gpsMeasurementsEvent);
+        checkAndClearExceptionFromCallback(env, __FUNCTION__);
+    } else {
+        ALOGE("Invalid GpsData size found in gps_measurement_callback, size=%d", data->size);
+        return;
+    }
+}
+
+GpsMeasurementCallbacks sGpsMeasurementCallbacks = {
+    sizeof(GpsMeasurementCallbacks),
+    measurement_callback,
+};
+
+static jboolean android_location_GpsLocationProvider_is_measurement_supported(
+        JNIEnv* env,
+        jobject obj) {
+    if (sGpsMeasurementInterface != NULL) {
+        return JNI_TRUE;
+    }
+    return JNI_FALSE;
+}
+
+static jboolean android_location_GpsLocationProvider_start_measurement_collection(
+        JNIEnv* env,
+        jobject obj) {
+    if (sGpsMeasurementInterface == NULL) {
+        ALOGE("Measurement interface is not available.");
+        return JNI_FALSE;
+    }
+
+    int result = sGpsMeasurementInterface->init(&sGpsMeasurementCallbacks);
+    if (result != GPS_GEOFENCE_OPERATION_SUCCESS) {
+        ALOGE("An error has been found on GpsMeasurementInterface::init, status=%d", result);
+        return JNI_FALSE;
+    }
+
+    return JNI_TRUE;
+}
+
+static jboolean android_location_GpsLocationProvider_stop_measurement_collection(
+        JNIEnv* env,
+        jobject obj) {
+    if (sGpsMeasurementInterface == NULL) {
+        ALOGE("Measurement interface not available");
+        return JNI_FALSE;
+    }
+
+    sGpsMeasurementInterface->close();
+    return JNI_TRUE;
+}
+
 static JNINativeMethod sMethods[] = {
      /* name, signature, funcPtr */
     {"class_init_native", "()V", (void *)android_location_GpsLocationProvider_class_init_native},
     {"native_is_supported", "()Z", (void*)android_location_GpsLocationProvider_is_supported},
     {"native_init", "()Z", (void*)android_location_GpsLocationProvider_init},
     {"native_cleanup", "()V", (void*)android_location_GpsLocationProvider_cleanup},
-    {"native_set_position_mode", "(IIIII)Z", (void*)android_location_GpsLocationProvider_set_position_mode},
+    {"native_set_position_mode",
+            "(IIIII)Z",
+            (void*)android_location_GpsLocationProvider_set_position_mode},
     {"native_start", "()Z", (void*)android_location_GpsLocationProvider_start},
     {"native_stop", "()Z", (void*)android_location_GpsLocationProvider_stop},
-    {"native_delete_aiding_data", "(I)V", (void*)android_location_GpsLocationProvider_delete_aiding_data},
-    {"native_read_sv_status", "([I[F[F[F[I)I", (void*)android_location_GpsLocationProvider_read_sv_status},
+    {"native_delete_aiding_data",
+            "(I)V",
+            (void*)android_location_GpsLocationProvider_delete_aiding_data},
+    {"native_read_sv_status",
+            "([I[F[F[F[I)I",
+            (void*)android_location_GpsLocationProvider_read_sv_status},
     {"native_read_nmea", "([BI)I", (void*)android_location_GpsLocationProvider_read_nmea},
     {"native_inject_time", "(JJI)V", (void*)android_location_GpsLocationProvider_inject_time},
-    {"native_inject_location", "(DDF)V", (void*)android_location_GpsLocationProvider_inject_location},
+    {"native_inject_location",
+            "(DDF)V",
+            (void*)android_location_GpsLocationProvider_inject_location},
     {"native_supports_xtra", "()Z", (void*)android_location_GpsLocationProvider_supports_xtra},
-    {"native_inject_xtra_data", "([BI)V", (void*)android_location_GpsLocationProvider_inject_xtra_data},
-    {"native_agps_data_conn_open", "(Ljava/lang/String;I)V", (void*)android_location_GpsLocationProvider_agps_data_conn_open},
-    {"native_agps_data_conn_closed", "()V", (void*)android_location_GpsLocationProvider_agps_data_conn_closed},
-    {"native_agps_data_conn_failed", "()V", (void*)android_location_GpsLocationProvider_agps_data_conn_failed},
-    {"native_agps_set_id","(ILjava/lang/String;)V",(void*)android_location_GpsLocationProvider_agps_set_id},
-    {"native_agps_set_ref_location_cellid","(IIIII)V",(void*)android_location_GpsLocationProvider_agps_set_reference_location_cellid},
-    {"native_set_agps_server", "(ILjava/lang/String;I)V", (void*)android_location_GpsLocationProvider_set_agps_server},
-    {"native_send_ni_response", "(II)V", (void*)android_location_GpsLocationProvider_send_ni_response},
-    {"native_agps_ni_message", "([BI)V", (void *)android_location_GpsLocationProvider_agps_send_ni_message},
-    {"native_get_internal_state", "()Ljava/lang/String;", (void*)android_location_GpsLocationProvider_get_internal_state},
-    {"native_update_network_state", "(ZIZZLjava/lang/String;Ljava/lang/String;)V", (void*)android_location_GpsLocationProvider_update_network_state },
-    {"native_is_geofence_supported", "()Z", (void*) android_location_GpsLocationProvider_is_geofence_supported},
-    {"native_add_geofence", "(IDDDIIII)Z", (void *)android_location_GpsLocationProvider_add_geofence},
-    {"native_remove_geofence", "(I)Z", (void *)android_location_GpsLocationProvider_remove_geofence},
+    {"native_inject_xtra_data",
+            "([BI)V",
+            (void*)android_location_GpsLocationProvider_inject_xtra_data},
+    {"native_agps_data_conn_open",
+            "(Ljava/lang/String;I)V",
+            (void*)android_location_GpsLocationProvider_agps_data_conn_open},
+    {"native_agps_data_conn_closed",
+            "()V",
+            (void*)android_location_GpsLocationProvider_agps_data_conn_closed},
+    {"native_agps_data_conn_failed",
+            "()V",
+            (void*)android_location_GpsLocationProvider_agps_data_conn_failed},
+    {"native_agps_set_id",
+            "(ILjava/lang/String;)V",
+            (void*)android_location_GpsLocationProvider_agps_set_id},
+    {"native_agps_set_ref_location_cellid",
+            "(IIIII)V",
+            (void*)android_location_GpsLocationProvider_agps_set_reference_location_cellid},
+    {"native_set_agps_server",
+            "(ILjava/lang/String;I)V",
+            (void*)android_location_GpsLocationProvider_set_agps_server},
+    {"native_send_ni_response",
+            "(II)V",
+            (void*)android_location_GpsLocationProvider_send_ni_response},
+    {"native_agps_ni_message",
+            "([BI)V",
+            (void *)android_location_GpsLocationProvider_agps_send_ni_message},
+    {"native_get_internal_state",
+            "()Ljava/lang/String;",
+            (void*)android_location_GpsLocationProvider_get_internal_state},
+    {"native_update_network_state",
+            "(ZIZZLjava/lang/String;Ljava/lang/String;)V",
+            (void*)android_location_GpsLocationProvider_update_network_state },
+    {"native_is_geofence_supported",
+            "()Z",
+            (void*) android_location_GpsLocationProvider_is_geofence_supported},
+    {"native_add_geofence",
+            "(IDDDIIII)Z",
+            (void *)android_location_GpsLocationProvider_add_geofence},
+    {"native_remove_geofence",
+            "(I)Z",
+            (void *)android_location_GpsLocationProvider_remove_geofence},
     {"native_pause_geofence", "(I)Z", (void *)android_location_GpsLocationProvider_pause_geofence},
-    {"native_resume_geofence", "(II)Z", (void *)android_location_GpsLocationProvider_resume_geofence}
+    {"native_resume_geofence",
+            "(II)Z",
+            (void *)android_location_GpsLocationProvider_resume_geofence},
+    {"native_is_measurement_supported",
+            "()Z",
+            (void*) android_location_GpsLocationProvider_is_measurement_supported},
+    {"native_start_measurement_collection",
+            "()Z",
+            (void*) android_location_GpsLocationProvider_start_measurement_collection},
+    {"native_stop_measurement_collection",
+            "()Z",
+            (void*) android_location_GpsLocationProvider_stop_measurement_collection}
 };
 
 int register_android_server_location_GpsLocationProvider(JNIEnv* env)
 {
-    return jniRegisterNativeMethods(env, "com/android/server/location/GpsLocationProvider", sMethods, NELEM(sMethods));
+    return jniRegisterNativeMethods(
+            env,
+            "com/android/server/location/GpsLocationProvider",
+            sMethods,
+            NELEM(sMethods));
 }
 
 } /* namespace android */