OSDN Git Service

Duty Cycling and Low Power Mode GNSS feature implementations
authorgomo <gomo@google.com>
Sat, 11 Nov 2017 04:35:46 +0000 (20:35 -0800)
committergomo <gomo@google.com>
Wed, 13 Dec 2017 21:38:31 +0000 (13:38 -0800)
Implementaion of 2 GNSS Android-P features:
- The Duty Cycling API to enable high accuracy applications development
- The Low Power Mode GNSS API to save power when indoor

Bug: 64009176
Test: Existing unit tests still pass.
Change-Id: I3ba3b86a635a54927c694fdd66a038757e843937

16 files changed:
api/current.txt
api/system-current.txt
core/java/android/provider/Settings.java
core/proto/android/providers/settings.proto
core/tests/coretests/src/android/provider/SettingsBackupTest.java
location/java/android/location/GnssMeasurementsEvent.java
location/java/android/location/LocalListenerHelper.java
location/java/android/location/LocationRequest.java
location/java/com/android/internal/location/ProviderRequest.java
packages/SettingsProvider/src/com/android/providers/settings/SettingsProtoDumpUtil.java
services/core/java/com/android/server/LocationManagerService.java
services/core/java/com/android/server/location/GnssLocationProvider.java
services/core/java/com/android/server/location/GnssMeasurementsProvider.java
services/core/java/com/android/server/location/GnssStatusListenerHelper.java
services/core/java/com/android/server/location/RemoteListenerHelper.java
services/core/jni/com_android_server_location_GnssLocationProvider.cpp

index eec7b53..447d9bf 100644 (file)
@@ -20981,6 +20981,7 @@ package android.location {
     method public void onGnssMeasurementsReceived(android.location.GnssMeasurementsEvent);
     method public void onStatusChanged(int);
     field public static final int STATUS_LOCATION_DISABLED = 2; // 0x2
+    field public static final int STATUS_NOT_ALLOWED = 3; // 0x3
     field public static final int STATUS_NOT_SUPPORTED = 0; // 0x0
     field public static final int STATUS_READY = 1; // 0x1
   }
index 33fa246..3c7aeda 100644 (file)
@@ -2104,11 +2104,13 @@ package android.location {
     method public int getQuality();
     method public float getSmallestDisplacement();
     method public android.os.WorkSource getWorkSource();
+    method public boolean isLowPowerMode();
     method public android.location.LocationRequest setExpireAt(long);
     method public android.location.LocationRequest setExpireIn(long);
     method public android.location.LocationRequest setFastestInterval(long);
     method public void setHideFromAppOps(boolean);
     method public android.location.LocationRequest setInterval(long);
+    method public android.location.LocationRequest setLowPowerMode(boolean);
     method public android.location.LocationRequest setNumUpdates(int);
     method public android.location.LocationRequest setProvider(java.lang.String);
     method public android.location.LocationRequest setQuality(int);
index 6b1632a..94ac052 100644 (file)
@@ -11143,6 +11143,15 @@ public final class Settings {
          */
         public static final String NOTIFICATION_SNOOZE_OPTIONS =
                 "notification_snooze_options";
+
+        /**
+         * Enable GNSS Raw Measurements Full Tracking?
+         * 0 = no
+         * 1 = yes
+         * @hide
+         */
+        public static final String ENABLE_GNSS_RAW_MEAS_FULL_TRACKING =
+                "enable_gnss_raw_meas_full_tracking";
     }
 
     /**
index 8d091ab..fb0ebed 100644 (file)
@@ -387,8 +387,9 @@ message GlobalSettingsProto {
     optional SettingProto enable_cache_quota_calculation = 339;
     optional SettingProto enable_deletion_helper_no_threshold_toggle = 340;
     optional SettingProto notification_snooze_options = 341;
+    optional SettingProto enable_gnss_raw_meas_full_tracking = 346;
 
-    // Next tag = 346;
+    // Next tag = 347;
 }
 
 message SecureSettingsProto {
index 0982a4b..b03f054 100644 (file)
@@ -367,6 +367,7 @@ public class SettingsBackupTest {
                     Settings.Global.ENABLE_GPU_DEBUG_LAYERS,
                     Settings.Global.GPU_DEBUG_APP,
                     Settings.Global.GPU_DEBUG_LAYERS,
+                    Settings.Global.ENABLE_GNSS_RAW_MEAS_FULL_TRACKING,
                     Settings.Global.NETWORK_ACCESS_TIMEOUT_MS,
                     Settings.Global.WARNING_TEMPERATURE,
                     Settings.Global.WEBVIEW_DATA_REDUCTION_PROXY_KEY,
index d66fd9c..072a7fe 100644 (file)
@@ -49,7 +49,7 @@ public final class GnssMeasurementsEvent implements Parcelable {
          * @hide
          */
         @Retention(RetentionPolicy.SOURCE)
-        @IntDef({STATUS_NOT_SUPPORTED, STATUS_READY, STATUS_LOCATION_DISABLED})
+        @IntDef({STATUS_NOT_SUPPORTED, STATUS_READY, STATUS_LOCATION_DISABLED, STATUS_NOT_ALLOWED})
         public @interface GnssMeasurementsStatus {}
 
         /**
@@ -72,6 +72,12 @@ public final class GnssMeasurementsEvent implements Parcelable {
         public static final int STATUS_LOCATION_DISABLED = 2;
 
         /**
+         * The client is not allowed to register for GNSS Measurements in general or in the
+         * requested mode.
+         */
+        public static final int STATUS_NOT_ALLOWED = 3;
+
+        /**
          * Reports the latest collected GNSS Measurements.
          */
         public void onGnssMeasurementsReceived(GnssMeasurementsEvent eventArgs) {}
index d7d2c51..592d01d 100644 (file)
 
 package android.location;
 
-import com.android.internal.util.Preconditions;
-
 import android.annotation.NonNull;
 import android.content.Context;
 import android.os.Handler;
 import android.os.RemoteException;
 import android.util.Log;
 
+import com.android.internal.util.Preconditions;
+
 import java.util.ArrayList;
 import java.util.Collection;
 import java.util.HashMap;
@@ -46,6 +46,11 @@ abstract class LocalListenerHelper<TListener> {
         mTag = name;
     }
 
+    /**
+     * Adds a {@param listener} to the list of listeners on which callbacks will be executed. The
+     * execution will happen on the {@param handler} thread or alternatively in the callback thread
+     * if a  {@code null} handler value is passed.
+     */
     public boolean add(@NonNull TListener listener, Handler handler) {
         Preconditions.checkNotNull(listener);
         synchronized (mListeners) {
index 65e7ced..6abba95 100644 (file)
@@ -143,7 +143,7 @@ public final class LocationRequest implements Parcelable {
 
     private int mQuality = POWER_LOW;
     private long mInterval = 60 * 60 * 1000;   // 60 minutes
-    private long mFastestInterval = (long)(mInterval / FASTEST_INTERVAL_FACTOR);  // 10 minutes
+    private long mFastestInterval = (long) (mInterval / FASTEST_INTERVAL_FACTOR);  // 10 minutes
     private boolean mExplicitFastestInterval = false;
     private long mExpireAt = Long.MAX_VALUE;  // no expiry
     private int mNumUpdates = Integer.MAX_VALUE;  // no expiry
@@ -151,7 +151,11 @@ public final class LocationRequest implements Parcelable {
     private WorkSource mWorkSource = null;
     private boolean mHideFromAppOps = false; // True if this request shouldn't be counted by AppOps
 
-    private String mProvider = LocationManager.FUSED_PROVIDER;  // for deprecated APIs that explicitly request a provider
+    private String mProvider = LocationManager.FUSED_PROVIDER;
+            // for deprecated APIs that explicitly request a provider
+
+    /** If true, GNSS chipset will make strong tradeoffs to substantially restrict power use */
+    private boolean mLowPowerMode = false;
 
     /**
      * Create a location request with default parameters.
@@ -184,11 +188,11 @@ public final class LocationRequest implements Parcelable {
         }
 
         LocationRequest request = new LocationRequest()
-            .setProvider(provider)
-            .setQuality(quality)
-            .setInterval(minTime)
-            .setFastestInterval(minTime)
-            .setSmallestDisplacement(minDistance);
+                .setProvider(provider)
+                .setQuality(quality)
+                .setInterval(minTime)
+                .setFastestInterval(minTime)
+                .setSmallestDisplacement(minDistance);
         if (singleShot) request.setNumUpdates(1);
         return request;
     }
@@ -220,16 +224,17 @@ public final class LocationRequest implements Parcelable {
         }
 
         LocationRequest request = new LocationRequest()
-            .setQuality(quality)
-            .setInterval(minTime)
-            .setFastestInterval(minTime)
-            .setSmallestDisplacement(minDistance);
+                .setQuality(quality)
+                .setInterval(minTime)
+                .setFastestInterval(minTime)
+                .setSmallestDisplacement(minDistance);
         if (singleShot) request.setNumUpdates(1);
         return request;
     }
 
     /** @hide */
-    public LocationRequest() { }
+    public LocationRequest() {
+    }
 
     /** @hide */
     public LocationRequest(LocationRequest src) {
@@ -243,6 +248,7 @@ public final class LocationRequest implements Parcelable {
         mProvider = src.mProvider;
         mWorkSource = src.mWorkSource;
         mHideFromAppOps = src.mHideFromAppOps;
+        mLowPowerMode = src.mLowPowerMode;
     }
 
     /**
@@ -263,8 +269,8 @@ public final class LocationRequest implements Parcelable {
      * on a location request.
      *
      * @param quality an accuracy or power constant
-     * @throws InvalidArgumentException if the quality constant is not valid
      * @return the same object, so that setters can be chained
+     * @throws InvalidArgumentException if the quality constant is not valid
      */
     public LocationRequest setQuality(int quality) {
         checkQuality(quality);
@@ -306,14 +312,14 @@ public final class LocationRequest implements Parcelable {
      * on a location request.
      *
      * @param millis desired interval in millisecond, inexact
-     * @throws InvalidArgumentException if the interval is less than zero
      * @return the same object, so that setters can be chained
+     * @throws InvalidArgumentException if the interval is less than zero
      */
     public LocationRequest setInterval(long millis) {
         checkInterval(millis);
         mInterval = millis;
         if (!mExplicitFastestInterval) {
-            mFastestInterval = (long)(mInterval / FASTEST_INTERVAL_FACTOR);
+            mFastestInterval = (long) (mInterval / FASTEST_INTERVAL_FACTOR);
         }
         return this;
     }
@@ -327,6 +333,34 @@ public final class LocationRequest implements Parcelable {
         return mInterval;
     }
 
+
+    /**
+     * Requests the GNSS chipset to run in a low power mode and make strong tradeoffs to
+     * substantially restrict power.
+     *
+     * <p>In this mode, the GNSS chipset will not, on average, run power hungry operations like RF &
+     * signal searches for more than one second per interval {@link #mInterval}
+     *
+     * @param enabled Enable or disable low power mode
+     * @return the same object, so that setters can be chained
+     * @hide
+     */
+    @SystemApi
+    public LocationRequest setLowPowerMode(boolean enabled) {
+        mLowPowerMode = enabled;
+        return this;
+    }
+
+    /**
+     * Returns true if low power mode is enabled.
+     *
+     * @hide
+     */
+    @SystemApi
+    public boolean isLowPowerMode() {
+        return mLowPowerMode;
+    }
+
     /**
      * Explicitly set the fastest interval for location updates, in
      * milliseconds.
@@ -353,8 +387,8 @@ public final class LocationRequest implements Parcelable {
      * then your effective fastest interval is {@link #setInterval}.
      *
      * @param millis fastest interval for updates in milliseconds, exact
-     * @throws InvalidArgumentException if the interval is less than zero
      * @return the same object, so that setters can be chained
+     * @throws InvalidArgumentException if the interval is less than zero
      */
     public LocationRequest setFastestInterval(long millis) {
         checkInterval(millis);
@@ -397,9 +431,9 @@ public final class LocationRequest implements Parcelable {
 
         // Check for > Long.MAX_VALUE overflow (elapsedRealtime > 0):
         if (millis > Long.MAX_VALUE - elapsedRealtime) {
-          mExpireAt = Long.MAX_VALUE;
+            mExpireAt = Long.MAX_VALUE;
         } else {
-          mExpireAt = millis + elapsedRealtime;
+            mExpireAt = millis + elapsedRealtime;
         }
 
         if (mExpireAt < 0) mExpireAt = 0;
@@ -448,11 +482,14 @@ public final class LocationRequest implements Parcelable {
      * to the location manager.
      *
      * @param numUpdates the number of location updates requested
-     * @throws InvalidArgumentException if numUpdates is 0 or less
      * @return the same object, so that setters can be chained
+     * @throws InvalidArgumentException if numUpdates is 0 or less
      */
     public LocationRequest setNumUpdates(int numUpdates) {
-        if (numUpdates <= 0) throw new IllegalArgumentException("invalid numUpdates: " + numUpdates);
+        if (numUpdates <= 0) {
+            throw new IllegalArgumentException(
+                    "invalid numUpdates: " + numUpdates);
+        }
         mNumUpdates = numUpdates;
         return this;
     }
@@ -462,6 +499,7 @@ public final class LocationRequest implements Parcelable {
      *
      * <p>By default this is {@link Integer#MAX_VALUE}, which indicates that
      * locations are updated until the request is explicitly removed.
+     *
      * @return number of updates
      */
     public int getNumUpdates() {
@@ -539,8 +577,8 @@ public final class LocationRequest implements Parcelable {
      * doesn't have the {@link android.Manifest.permission#UPDATE_APP_OPS_STATS} permission.
      *
      * @param hideFromAppOps If true AppOps won't keep track of this location request.
-     * @see android.app.AppOpsManager
      * @hide
+     * @see android.app.AppOpsManager
      */
     @SystemApi
     public void setHideFromAppOps(boolean hideFromAppOps) {
@@ -587,27 +625,29 @@ public final class LocationRequest implements Parcelable {
 
     public static final Parcelable.Creator<LocationRequest> CREATOR =
             new Parcelable.Creator<LocationRequest>() {
-        @Override
-        public LocationRequest createFromParcel(Parcel in) {
-            LocationRequest request = new LocationRequest();
-            request.setQuality(in.readInt());
-            request.setFastestInterval(in.readLong());
-            request.setInterval(in.readLong());
-            request.setExpireAt(in.readLong());
-            request.setNumUpdates(in.readInt());
-            request.setSmallestDisplacement(in.readFloat());
-            request.setHideFromAppOps(in.readInt() != 0);
-            String provider = in.readString();
-            if (provider != null) request.setProvider(provider);
-            WorkSource workSource = in.readParcelable(null);
-            if (workSource != null) request.setWorkSource(workSource);
-            return request;
-        }
-        @Override
-        public LocationRequest[] newArray(int size) {
-            return new LocationRequest[size];
-        }
-    };
+                @Override
+                public LocationRequest createFromParcel(Parcel in) {
+                    LocationRequest request = new LocationRequest();
+                    request.setQuality(in.readInt());
+                    request.setFastestInterval(in.readLong());
+                    request.setInterval(in.readLong());
+                    request.setExpireAt(in.readLong());
+                    request.setNumUpdates(in.readInt());
+                    request.setSmallestDisplacement(in.readFloat());
+                    request.setHideFromAppOps(in.readInt() != 0);
+                    request.setLowPowerMode(in.readInt() != 0);
+                    String provider = in.readString();
+                    if (provider != null) request.setProvider(provider);
+                    WorkSource workSource = in.readParcelable(null);
+                    if (workSource != null) request.setWorkSource(workSource);
+                    return request;
+                }
+
+                @Override
+                public LocationRequest[] newArray(int size) {
+                    return new LocationRequest[size];
+                }
+            };
 
     @Override
     public int describeContents() {
@@ -623,6 +663,7 @@ public final class LocationRequest implements Parcelable {
         parcel.writeInt(mNumUpdates);
         parcel.writeFloat(mSmallestDisplacement);
         parcel.writeInt(mHideFromAppOps ? 1 : 0);
+        parcel.writeInt(mLowPowerMode ? 1 : 0);
         parcel.writeString(mProvider);
         parcel.writeParcelable(mWorkSource, 0);
     }
@@ -663,9 +704,10 @@ public final class LocationRequest implements Parcelable {
             s.append(" expireIn=");
             TimeUtils.formatDuration(expireIn, s);
         }
-        if (mNumUpdates != Integer.MAX_VALUE){
+        if (mNumUpdates != Integer.MAX_VALUE) {
             s.append(" num=").append(mNumUpdates);
         }
+        s.append(" lowPowerMode=").append(mLowPowerMode);
         s.append(']');
         return s.toString();
     }
index 26243e7..45fdb76 100644 (file)
@@ -33,6 +33,12 @@ public final class ProviderRequest implements Parcelable {
     public long interval = Long.MAX_VALUE;
 
     /**
+     * Whether provider shall make stronger than normal tradeoffs to substantially restrict power
+     * use.
+     */
+    public boolean lowPowerMode = false;
+
+    /**
      * A more detailed set of requests.
      * <p>Location Providers can optionally use this to
      * fine tune location updates, for example when there
@@ -41,26 +47,29 @@ public final class ProviderRequest implements Parcelable {
      */
     public List<LocationRequest> locationRequests = new ArrayList<LocationRequest>();
 
-    public ProviderRequest() { }
+    public ProviderRequest() {
+    }
 
     public static final Parcelable.Creator<ProviderRequest> CREATOR =
             new Parcelable.Creator<ProviderRequest>() {
-        @Override
-        public ProviderRequest createFromParcel(Parcel in) {
-            ProviderRequest request = new ProviderRequest();
-            request.reportLocation = in.readInt() == 1;
-            request.interval = in.readLong();
-            int count = in.readInt();
-            for (int i = 0; i < count; i++) {
-                request.locationRequests.add(LocationRequest.CREATOR.createFromParcel(in));
-            }
-            return request;
-        }
-        @Override
-        public ProviderRequest[] newArray(int size) {
-            return new ProviderRequest[size];
-        }
-    };
+                @Override
+                public ProviderRequest createFromParcel(Parcel in) {
+                    ProviderRequest request = new ProviderRequest();
+                    request.reportLocation = in.readInt() == 1;
+                    request.interval = in.readLong();
+                    request.lowPowerMode = in.readBoolean();
+                    int count = in.readInt();
+                    for (int i = 0; i < count; i++) {
+                        request.locationRequests.add(LocationRequest.CREATOR.createFromParcel(in));
+                    }
+                    return request;
+                }
+
+                @Override
+                public ProviderRequest[] newArray(int size) {
+                    return new ProviderRequest[size];
+                }
+            };
 
     @Override
     public int describeContents() {
@@ -71,6 +80,7 @@ public final class ProviderRequest implements Parcelable {
     public void writeToParcel(Parcel parcel, int flags) {
         parcel.writeInt(reportLocation ? 1 : 0);
         parcel.writeLong(interval);
+        parcel.writeBoolean(lowPowerMode);
         parcel.writeInt(locationRequests.size());
         for (LocationRequest request : locationRequests) {
             request.writeToParcel(parcel, flags);
@@ -85,6 +95,7 @@ public final class ProviderRequest implements Parcelable {
             s.append("ON");
             s.append(" interval=");
             TimeUtils.formatDuration(interval, s);
+            s.append(" lowPowerMode=" + lowPowerMode);
         } else {
             s.append("OFF");
         }
index fabdbd4..1d3f26e 100644 (file)
@@ -881,6 +881,9 @@ class SettingsProtoDumpUtil {
         dumpSetting(s, p,
                 Settings.Global.GPU_DEBUG_LAYERS,
                 GlobalSettingsProto.GPU_DEBUG_LAYERS);
+        dumpSetting(s, p,
+                Settings.Global.ENABLE_GNSS_RAW_MEAS_FULL_TRACKING,
+                GlobalSettingsProto.ENABLE_GNSS_RAW_MEAS_FULL_TRACKING);
         // Settings.Global.SHOW_PROCESSES intentionally excluded since it's deprecated.
         dumpSetting(s, p,
                 Settings.Global.LOW_POWER_MODE,
index bdfccd6..0a86281 100644 (file)
@@ -20,6 +20,7 @@ import android.app.ActivityManager;
 import android.annotation.NonNull;
 import android.util.ArrayMap;
 import android.util.ArraySet;
+
 import com.android.internal.content.PackageMonitor;
 import com.android.internal.location.ProviderProperties;
 import com.android.internal.location.ProviderRequest;
@@ -147,7 +148,7 @@ public class LocationManagerService extends ILocationManager.Stub {
     private static final long HIGH_POWER_INTERVAL_MS = 5 * 60 * 1000;
 
     private static final int FOREGROUND_IMPORTANCE_CUTOFF
-        = ActivityManager.RunningAppProcessInfo.IMPORTANCE_FOREGROUND_SERVICE;
+            = ActivityManager.RunningAppProcessInfo.IMPORTANCE_FOREGROUND_SERVICE;
 
     // default background throttling interval if not overriden in settings
     private static final long DEFAULT_BACKGROUND_THROTTLE_INTERVAL_MS = 30 * 60 * 1000;
@@ -239,7 +240,7 @@ public class LocationManagerService extends ILocationManager.Stub {
 
     // current active user on the device - other users are denied location data
     private int mCurrentUserId = UserHandle.USER_SYSTEM;
-    private int[] mCurrentUserProfiles = new int[] { UserHandle.USER_SYSTEM };
+    private int[] mCurrentUserProfiles = new int[]{UserHandle.USER_SYSTEM};
 
     private GnssLocationProvider.GnssSystemInfoProvider mGnssSystemInfoProvider;
 
@@ -253,7 +254,7 @@ public class LocationManagerService extends ILocationManager.Stub {
     public LocationManagerService(Context context) {
         super();
         mContext = context;
-        mAppOps = (AppOpsManager)context.getSystemService(Context.APP_OPS_SERVICE);
+        mAppOps = (AppOpsManager) context.getSystemService(Context.APP_OPS_SERVICE);
 
         // Let the package manager query which are the default location
         // providers as they get certain permissions granted by default.
@@ -370,18 +371,18 @@ public class LocationManagerService extends ILocationManager.Stub {
                     }
                 }, UserHandle.USER_ALL);
         mContext.getContentResolver().registerContentObserver(
-            Settings.Global.getUriFor(
-                Settings.Global.LOCATION_BACKGROUND_THROTTLE_PACKAGE_WHITELIST),
-            true,
-            new ContentObserver(mLocationHandler) {
-                @Override
-                public void onChange(boolean selfChange) {
-                    synchronized (mLock) {
-                        updateBackgroundThrottlingWhitelistLocked();
-                        updateProvidersLocked();
+                Settings.Global.getUriFor(
+                        Settings.Global.LOCATION_BACKGROUND_THROTTLE_PACKAGE_WHITELIST),
+                true,
+                new ContentObserver(mLocationHandler) {
+                    @Override
+                    public void onChange(boolean selfChange) {
+                        synchronized (mLock) {
+                            updateBackgroundThrottlingWhitelistLocked();
+                            updateProvidersLocked();
+                        }
                     }
-                }
-            }, UserHandle.USER_ALL);
+                }, UserHandle.USER_ALL);
         mPackageMonitor.register(mContext, mLocationHandler.getLooper(), true);
 
         // listen for user change
@@ -402,7 +403,7 @@ public class LocationManagerService extends ILocationManager.Stub {
                     updateUserProfiles(mCurrentUserId);
                 } else if (Intent.ACTION_SHUTDOWN.equals(action)) {
                     // shutdown only if UserId indicates whole system, not just one user
-                    if(D) Log.d(TAG, "Shutdown received with UserId: " + getSendingUserId());
+                    if (D) Log.d(TAG, "Shutdown received with UserId: " + getSendingUserId());
                     if (getSendingUserId() == UserHandle.USER_ALL) {
                         shutdownComponents();
                     }
@@ -416,13 +417,15 @@ public class LocationManagerService extends ILocationManager.Stub {
         HashSet<String> affectedProviders = new HashSet<>(mRecordsByProvider.size());
         synchronized (mLock) {
             for (Entry<String, ArrayList<UpdateRecord>> entry
-                : mRecordsByProvider.entrySet()) {
+                    : mRecordsByProvider.entrySet()) {
                 String provider = entry.getKey();
                 for (UpdateRecord record : entry.getValue()) {
                     if (record.mReceiver.mIdentity.mUid == uid
-                        && record.mIsForegroundUid != foreground) {
-                        if (D) Log.d(TAG, "request from uid " + uid + " is now "
-                            + (foreground ? "foreground" : "background)"));
+                            && record.mIsForegroundUid != foreground) {
+                        if (D) {
+                            Log.d(TAG, "request from uid " + uid + " is now "
+                                    + (foreground ? "foreground" : "background)"));
+                        }
                         record.mIsForegroundUid = foreground;
 
                         if (!isThrottlingExemptLocked(record.mReceiver.mIdentity)) {
@@ -436,10 +439,12 @@ public class LocationManagerService extends ILocationManager.Stub {
             }
 
             for (Entry<IGnssMeasurementsListener, Identity> entry
-                : mGnssMeasurementsListeners.entrySet()) {
+                    : mGnssMeasurementsListeners.entrySet()) {
                 if (entry.getValue().mUid == uid) {
-                    if (D) Log.d(TAG, "gnss measurements listener from uid " + uid
-                        + " is now " + (foreground ? "foreground" : "background)"));
+                    if (D) {
+                        Log.d(TAG, "gnss measurements listener from uid " + uid
+                                + " is now " + (foreground ? "foreground" : "background)"));
+                    }
                     if (foreground || isThrottlingExemptLocked(entry.getValue())) {
                         mGnssMeasurementsProvider.addListener(entry.getKey());
                     } else {
@@ -449,11 +454,13 @@ public class LocationManagerService extends ILocationManager.Stub {
             }
 
             for (Entry<IGnssNavigationMessageListener, Identity> entry
-                : mGnssNavigationMessageListeners.entrySet()) {
+                    : mGnssNavigationMessageListeners.entrySet()) {
                 if (entry.getValue().mUid == uid) {
-                    if (D) Log.d(TAG, "gnss navigation message listener from uid "
-                        + uid + " is now "
-                        + (foreground ? "foreground" : "background)"));
+                    if (D) {
+                        Log.d(TAG, "gnss navigation message listener from uid "
+                                + uid + " is now "
+                                + (foreground ? "foreground" : "background)"));
+                    }
                     if (foreground || isThrottlingExemptLocked(entry.getValue())) {
                         mGnssNavigationMessageProvider.addListener(entry.getKey());
                     } else {
@@ -477,7 +484,7 @@ public class LocationManagerService extends ILocationManager.Stub {
      * support for components that do not wish to handle such event.
      */
     private void shutdownComponents() {
-        if(D) Log.d(TAG, "Shutting down components...");
+        if (D) Log.d(TAG, "Shutting down components...");
 
         LocationProviderInterface gpsProvider = mProvidersByName.get(LocationManager.GPS_PROVIDER);
         if (gpsProvider != null && gpsProvider.isEnabled()) {
@@ -563,8 +570,10 @@ public class LocationManagerService extends ILocationManager.Stub {
                 // as a proxy for coreApp="true"
                 if (pm.checkSignatures(systemPackageName, packageName)
                         != PackageManager.SIGNATURE_MATCH) {
-                    if (D) Log.d(TAG, "Fallback candidate not signed the same as system: "
-                            + packageName);
+                    if (D) {
+                        Log.d(TAG, "Fallback candidate not signed the same as system: "
+                                + packageName);
+                    }
                     continue;
                 }
 
@@ -622,8 +631,10 @@ public class LocationManagerService extends ILocationManager.Stub {
         ArrayList<String> providerPackageNames = new ArrayList<>();
         String[] pkgs = resources.getStringArray(
                 com.android.internal.R.array.config_locationProviderPackageNames);
-        if (D) Log.d(TAG, "certificates for location providers pulled from: " +
-                Arrays.toString(pkgs));
+        if (D) {
+            Log.d(TAG, "certificates for location providers pulled from: " +
+                    Arrays.toString(pkgs));
+        }
         if (pkgs != null) providerPackageNames.addAll(Arrays.asList(pkgs));
 
         ensureFallbackFusedProviderPresentLocked(providerPackageNames);
@@ -642,7 +653,7 @@ public class LocationManagerService extends ILocationManager.Stub {
             mProxyProviders.add(networkProvider);
             addProviderLocked(networkProvider);
         } else {
-            Slog.w(TAG,  "no network location provider found");
+            Slog.w(TAG, "no network location provider found");
         }
 
         // bind to fused provider
@@ -671,7 +682,7 @@ public class LocationManagerService extends ILocationManager.Stub {
                 com.android.internal.R.array.config_locationProviderPackageNames,
                 mLocationHandler);
         if (mGeocodeProvider == null) {
-            Slog.e(TAG,  "no geocoder provider found");
+            Slog.e(TAG, "no geocoder provider found");
         }
 
         // bind to fused hardware provider if supported
@@ -697,14 +708,14 @@ public class LocationManagerService extends ILocationManager.Stub {
 
         // bind to geofence provider
         GeofenceProxy provider = GeofenceProxy.createAndBind(
-                mContext,com.android.internal.R.bool.config_enableGeofenceOverlay,
+                mContext, com.android.internal.R.bool.config_enableGeofenceOverlay,
                 com.android.internal.R.string.config_geofenceProviderPackageName,
                 com.android.internal.R.array.config_locationProviderPackageNames,
                 mLocationHandler,
                 mGpsGeofenceProxy,
                 flpHardwareProvider != null ? flpHardwareProvider.getGeofenceHardware() : null);
         if (provider == null) {
-            Slog.d(TAG,  "Unable to bind FLP Geofence proxy.");
+            Slog.d(TAG, "Unable to bind FLP Geofence proxy.");
         }
 
         // bind to hardware activity recognition
@@ -751,6 +762,7 @@ public class LocationManagerService extends ILocationManager.Stub {
 
     /**
      * Called when the device's active user changes.
+     *
      * @param userId the new active user's UserId
      */
     private void switchUser(int userId) {
@@ -797,7 +809,7 @@ public class LocationManagerService extends ILocationManager.Stub {
         final boolean mHideFromAppOps; // True if AppOps should not monitor this receiver.
         final Object mKey;
 
-        final HashMap<String,UpdateRecord> mUpdateRecords = new HashMap<>();
+        final HashMap<String, UpdateRecord> mUpdateRecords = new HashMap<>();
 
         // True if app ops has started monitoring this receiver for locations.
         boolean mOpMonitoring;
@@ -914,9 +926,9 @@ public class LocationManagerService extends ILocationManager.Stub {
         /**
          * Update AppOps monitoring for a single location request and op type.
          *
-         * @param allowMonitoring True if monitoring is allowed for this request/op.
+         * @param allowMonitoring     True if monitoring is allowed for this request/op.
          * @param currentlyMonitoring True if AppOps is currently monitoring this request/op.
-         * @param op AppOps code for the op to update.
+         * @param op                  AppOps code for the op to update.
          * @return True if monitoring is on for this request/op after updating.
          */
         private boolean updateMonitoring(boolean allowMonitoring, boolean currentlyMonitoring,
@@ -1004,7 +1016,8 @@ public class LocationManagerService extends ILocationManager.Stub {
                 }
             } else {
                 Intent locationChanged = new Intent();
-                locationChanged.putExtra(LocationManager.KEY_LOCATION_CHANGED, new Location(location));
+                locationChanged.putExtra(LocationManager.KEY_LOCATION_CHANGED,
+                        new Location(location));
                 try {
                     synchronized (this) {
                         // synchronize to ensure incrementPendingBroadcastsLocked()
@@ -1286,7 +1299,7 @@ public class LocationManagerService extends ILocationManager.Stub {
         }
 
         if (mGnssBatchingProvider != null) {
-             mGnssBatchingProvider.flush();
+            mGnssBatchingProvider.flush();
         }
     }
 
@@ -1301,7 +1314,7 @@ public class LocationManagerService extends ILocationManager.Stub {
         if (mGnssBatchingProvider != null) {
             mGnssBatchingInProgress = false;
             return mGnssBatchingProvider.stop();
-        } else  {
+        } else {
             return false;
         }
     }
@@ -1363,7 +1376,7 @@ public class LocationManagerService extends ILocationManager.Stub {
      * processes belonging to background users.
      *
      * @param provider the name of the location provider
-     * @param uid the requestor's UID
+     * @param uid      the requestor's UID
      */
     private boolean isAllowedByUserSettingsLocked(String provider, int uid) {
         if (!isCurrentProfile(UserHandle.getUserId(uid)) && !isUidALocationProvider(uid)) {
@@ -1467,7 +1480,7 @@ public class LocationManagerService extends ILocationManager.Stub {
      * location provider.
      *
      * @param allowedResolutionLevel resolution level allowed to caller
-     * @param providerName the name of the location provider
+     * @param providerName           the name of the location provider
      */
     private void checkResolutionLevelIsSufficientForProviderUse(int allowedResolutionLevel,
             String providerName) {
@@ -1718,7 +1731,9 @@ public class LocationManagerService extends ILocationManager.Stub {
                 resolver,
                 Settings.Global.LOCATION_BACKGROUND_THROTTLE_INTERVAL_MS,
                 DEFAULT_BACKGROUND_THROTTLE_INTERVAL_MS);
+        // initialize the low power mode to true and set to false if any of the records requires
 
+        providerRequest.lowPowerMode = true;
         if (records != null) {
             for (UpdateRecord record : records) {
                 if (isCurrentProfile(UserHandle.getUserId(record.mReceiver.mIdentity.mUid))) {
@@ -1742,6 +1757,9 @@ public class LocationManagerService extends ILocationManager.Stub {
 
                         record.mRequest = locationRequest;
                         providerRequest.locationRequests.add(locationRequest);
+                        if (!locationRequest.isLowPowerMode()) {
+                            providerRequest.lowPowerMode = false;
+                        }
                         if (interval < providerRequest.interval) {
                             providerRequest.reportLocation = true;
                             providerRequest.interval = interval;
@@ -1794,23 +1812,23 @@ public class LocationManagerService extends ILocationManager.Stub {
     public String[] getBackgroundThrottlingWhitelist() {
         synchronized (mLock) {
             return mBackgroundThrottlePackageWhitelist.toArray(
-                new String[mBackgroundThrottlePackageWhitelist.size()]);
+                    new String[mBackgroundThrottlePackageWhitelist.size()]);
         }
     }
 
     private void updateBackgroundThrottlingWhitelistLocked() {
         String setting = Settings.Global.getString(
-            mContext.getContentResolver(),
-            Settings.Global.LOCATION_BACKGROUND_THROTTLE_PACKAGE_WHITELIST);
+                mContext.getContentResolver(),
+                Settings.Global.LOCATION_BACKGROUND_THROTTLE_PACKAGE_WHITELIST);
         if (setting == null) {
             setting = "";
         }
 
         mBackgroundThrottlePackageWhitelist.clear();
         mBackgroundThrottlePackageWhitelist.addAll(
-            SystemConfig.getInstance().getAllowUnthrottledLocation());
+                SystemConfig.getInstance().getAllowUnthrottledLocation());
         mBackgroundThrottlePackageWhitelist.addAll(
-            Arrays.asList(setting.split(",")));
+                Arrays.asList(setting.split(",")));
     }
 
     private boolean isThrottlingExemptLocked(Identity identity) {
@@ -1894,7 +1912,8 @@ public class LocationManagerService extends ILocationManager.Stub {
         @Override
         public String toString() {
             return "UpdateRecord[" + mProvider + " " + mReceiver.mIdentity.mPackageName
-                    + "(" + mReceiver.mIdentity.mUid + (mIsForegroundUid ? " foreground" : " background")
+                    + "(" + mReceiver.mIdentity.mUid + (mIsForegroundUid ? " foreground"
+                    : " background")
                     + ")" + " " + mRealRequest + "]";
         }
     }
@@ -1936,8 +1955,13 @@ public class LocationManagerService extends ILocationManager.Stub {
      * @return a version of request that meets the given resolution and consistency requirements
      * @hide
      */
-    private LocationRequest createSanitizedRequest(LocationRequest request, int resolutionLevel) {
+    private LocationRequest createSanitizedRequest(LocationRequest request, int resolutionLevel,
+            boolean callerHasLocationHardwarePermission) {
         LocationRequest sanitizedRequest = new LocationRequest(request);
+        if (!callerHasLocationHardwarePermission) {
+            // allow setting low power mode only for callers with location hardware permission
+            sanitizedRequest.setLowPowerMode(false);
+        }
         if (resolutionLevel < RESOLUTION_LEVEL_FINE) {
             switch (sanitizedRequest.getQuality()) {
                 case LocationRequest.ACCURACY_FINE:
@@ -2013,7 +2037,11 @@ public class LocationManagerService extends ILocationManager.Stub {
         if (hideFromAppOps) {
             checkUpdateAppOpsAllowed();
         }
-        LocationRequest sanitizedRequest = createSanitizedRequest(request, allowedResolutionLevel);
+        boolean callerHasLocationHardwarePermission =
+                mContext.checkCallingPermission(android.Manifest.permission.LOCATION_HARDWARE)
+                        == PackageManager.PERMISSION_GRANTED;
+        LocationRequest sanitizedRequest = createSanitizedRequest(request, allowedResolutionLevel,
+                callerHasLocationHardwarePermission);
 
         final int pid = Binder.getCallingPid();
         final int uid = Binder.getCallingUid();
@@ -2050,11 +2078,13 @@ public class LocationManagerService extends ILocationManager.Stub {
         }
 
         UpdateRecord record = new UpdateRecord(name, request, receiver);
-        if (D) Log.d(TAG, "request " + Integer.toHexString(System.identityHashCode(receiver))
-                + " " + name + " " + request + " from " + packageName + "(" + uid + " "
-                + (record.mIsForegroundUid ? "foreground" : "background")
-                + (isThrottlingExemptLocked(receiver.mIdentity)
+        if (D) {
+            Log.d(TAG, "request " + Integer.toHexString(System.identityHashCode(receiver))
+                    + " " + name + " " + request + " from " + packageName + "(" + uid + " "
+                    + (record.mIsForegroundUid ? "foreground" : "background")
+                    + (isThrottlingExemptLocked(receiver.mIdentity)
                     ? " [whitelisted]" : "") + ")");
+        }
 
         UpdateRecord oldRecord = receiver.mUpdateRecords.put(name, record);
         if (oldRecord != null) {
@@ -2159,14 +2189,18 @@ public class LocationManagerService extends ILocationManager.Stub {
         final long identity = Binder.clearCallingIdentity();
         try {
             if (mBlacklist.isBlacklisted(packageName)) {
-                if (D) Log.d(TAG, "not returning last loc for blacklisted app: " +
-                        packageName);
+                if (D) {
+                    Log.d(TAG, "not returning last loc for blacklisted app: " +
+                            packageName);
+                }
                 return null;
             }
 
             if (!reportLocationAccessNoThrow(pid, uid, packageName, allowedResolutionLevel)) {
-                if (D) Log.d(TAG, "not returning last loc for no op app: " +
-                        packageName);
+                if (D) {
+                    Log.d(TAG, "not returning last loc for no op app: " +
+                            packageName);
+                }
                 return null;
             }
 
@@ -2192,7 +2226,8 @@ public class LocationManagerService extends ILocationManager.Stub {
                     return null;
                 }
                 if (allowedResolutionLevel < RESOLUTION_LEVEL_FINE) {
-                    Location noGPSLocation = location.getExtraLocation(Location.EXTRA_NO_GPS_LOCATION);
+                    Location noGPSLocation = location.getExtraLocation(
+                            Location.EXTRA_NO_GPS_LOCATION);
                     if (noGPSLocation != null) {
                         return new Location(mLocationFudger.getOrCreate(noGPSLocation));
                     }
@@ -2216,7 +2251,12 @@ public class LocationManagerService extends ILocationManager.Stub {
         checkPackageName(packageName);
         checkResolutionLevelIsSufficientForProviderUse(allowedResolutionLevel,
                 request.getProvider());
-        LocationRequest sanitizedRequest = createSanitizedRequest(request, allowedResolutionLevel);
+        // Require that caller can manage given document
+        boolean callerHasLocationHardwarePermission =
+                mContext.checkCallingPermission(android.Manifest.permission.LOCATION_HARDWARE)
+                        == PackageManager.PERMISSION_GRANTED;
+        LocationRequest sanitizedRequest = createSanitizedRequest(request, allowedResolutionLevel,
+                callerHasLocationHardwarePermission);
 
         if (D) Log.d(TAG, "requestGeofence: " + sanitizedRequest + " " + geofence + " " + intent);
 
@@ -2282,8 +2322,7 @@ public class LocationManagerService extends ILocationManager.Stub {
 
     @Override
     public boolean addGnssMeasurementsListener(
-            IGnssMeasurementsListener listener,
-            String packageName) {
+            IGnssMeasurementsListener listener, String packageName) {
         if (!hasGnssPermissions(packageName) || mGnssMeasurementsProvider == null) {
             return false;
         }
@@ -2296,7 +2335,7 @@ public class LocationManagerService extends ILocationManager.Stub {
             try {
                 if (isThrottlingExemptLocked(callerIdentity)
                         || isImportanceForeground(
-                                mActivityManager.getPackageImportance(packageName))) {
+                        mActivityManager.getPackageImportance(packageName))) {
                     return mGnssMeasurementsProvider.addListener(listener);
                 }
             } finally {
@@ -2327,13 +2366,13 @@ public class LocationManagerService extends ILocationManager.Stub {
 
         synchronized (mLock) {
             Identity callerIdentity
-                = new Identity(Binder.getCallingUid(), Binder.getCallingPid(), packageName);
+                    = new Identity(Binder.getCallingUid(), Binder.getCallingPid(), packageName);
             mGnssNavigationMessageListeners.put(listener, callerIdentity);
             long identity = Binder.clearCallingIdentity();
             try {
                 if (isThrottlingExemptLocked(callerIdentity)
                         || isImportanceForeground(
-                                mActivityManager.getPackageImportance(packageName))) {
+                        mActivityManager.getPackageImportance(packageName))) {
                     return mGnssNavigationMessageProvider.addListener(listener);
                 }
             } finally {
@@ -2394,7 +2433,7 @@ public class LocationManagerService extends ILocationManager.Stub {
     /**
      * @return null if the provider does not exist
      * @throws SecurityException if the provider is not allowed to be
-     * accessed by the caller
+     *                           accessed by the caller
      */
     @Override
     public ProviderProperties getProviderProperties(String provider) {
@@ -2417,7 +2456,7 @@ public class LocationManagerService extends ILocationManager.Stub {
     /**
      * @return null if the provider does not exist
      * @throws SecurityException if the provider is not allowed to be
-     * accessed by the caller
+     *                           accessed by the caller
      */
     @Override
     public String getNetworkProviderPackage() {
@@ -2641,8 +2680,10 @@ public class LocationManagerService extends ILocationManager.Stub {
             }
 
             if (mBlacklist.isBlacklisted(receiver.mIdentity.mPackageName)) {
-                if (D) Log.d(TAG, "skipping loc update for blacklisted app: " +
-                        receiver.mIdentity.mPackageName);
+                if (D) {
+                    Log.d(TAG, "skipping loc update for blacklisted app: " +
+                            receiver.mIdentity.mPackageName);
+                }
                 continue;
             }
 
@@ -2651,8 +2692,10 @@ public class LocationManagerService extends ILocationManager.Stub {
                     receiver.mIdentity.mUid,
                     receiver.mIdentity.mPackageName,
                     receiver.mAllowedResolutionLevel)) {
-                if (D) Log.d(TAG, "skipping loc update for no op app: " +
-                        receiver.mIdentity.mPackageName);
+                if (D) {
+                    Log.d(TAG, "skipping loc update for no op app: " +
+                            receiver.mIdentity.mPackageName);
+                }
                 continue;
             }
 
@@ -3114,12 +3157,12 @@ public class LocationManagerService extends ILocationManager.Stub {
             }
 
             pw.append("  fudger: ");
-            mLocationFudger.dump(fd, pw,  args);
+            mLocationFudger.dump(fd, pw, args);
 
             if (args.length > 0 && "short".equals(args[0])) {
                 return;
             }
-            for (LocationProviderInterface provider: mProviders) {
+            for (LocationProviderInterface provider : mProviders) {
                 pw.print(provider.getName() + " Internal State");
                 if (provider instanceof LocationProviderProxy) {
                     LocationProviderProxy proxy = (LocationProviderProxy) provider;
index 0b511f2..b324002 100644 (file)
@@ -233,13 +233,13 @@ public class GnssLocationProvider implements LocationProviderInterface {
     private static final int AGPS_SETID_TYPE_IMSI = 1;
     private static final int AGPS_SETID_TYPE_MSISDN = 2;
 
-    private static final int GPS_GEOFENCE_UNAVAILABLE = 1<<0L;
-    private static final int GPS_GEOFENCE_AVAILABLE = 1<<1L;
+    private static final int GPS_GEOFENCE_UNAVAILABLE = 1 << 0L;
+    private static final int GPS_GEOFENCE_AVAILABLE = 1 << 1L;
 
     // GPS Geofence errors. Should match GeofenceStatus enum in IGnssGeofenceCallback.hal.
     private static final int GPS_GEOFENCE_OPERATION_SUCCESS = 0;
     private static final int GPS_GEOFENCE_ERROR_TOO_MANY_GEOFENCES = 100;
-    private static final int GPS_GEOFENCE_ERROR_ID_EXISTS  = -101;
+    private static final int GPS_GEOFENCE_ERROR_ID_EXISTS = -101;
     private static final int GPS_GEOFENCE_ERROR_ID_UNKNOWN = -102;
     private static final int GPS_GEOFENCE_ERROR_INVALID_TRANSITION = -103;
     private static final int GPS_GEOFENCE_ERROR_GENERIC = -149;
@@ -253,6 +253,7 @@ public class GnssLocationProvider implements LocationProviderInterface {
     private static class GpsRequest {
         public ProviderRequest request;
         public WorkSource source;
+
         public GpsRequest(ProviderRequest request, WorkSource source) {
             this.request = request;
             this.source = source;
@@ -280,15 +281,15 @@ public class GnssLocationProvider implements LocationProviderInterface {
 
     // how often to request NTP time, in milliseconds
     // current setting 24 hours
-    private static final long NTP_INTERVAL = 24*60*60*1000;
+    private static final long NTP_INTERVAL = 24 * 60 * 60 * 1000;
     // how long to wait if we have a network error in NTP or XTRA downloading
     // the initial value of the exponential backoff
     // current setting - 5 minutes
-    private static final long RETRY_INTERVAL = 5*60*1000;
+    private static final long RETRY_INTERVAL = 5 * 60 * 1000;
     // how long to wait if we have a network error in NTP or XTRA downloading
     // the max value of the exponential backoff
     // current setting - 4 hours
-    private static final long MAX_RETRY_INTERVAL = 4*60*60*1000;
+    private static final long MAX_RETRY_INTERVAL = 4 * 60 * 60 * 1000;
 
     // Timeout when holding wakelocks for downloading XTRA data.
     private static final long DOWNLOAD_XTRA_DATA_TIMEOUT_MS = 60 * 1000;
@@ -321,6 +322,9 @@ public class GnssLocationProvider implements LocationProviderInterface {
     // requested frequency of fixes, in milliseconds
     private int mFixInterval = 1000;
 
+    // true if low power mode for the GNSS chipset is part of the latest request.
+    private boolean mLowPowerMode = false;
+
     // true if we started navigation
     private boolean mStarted;
 
@@ -398,7 +402,6 @@ public class GnssLocationProvider implements LocationProviderInterface {
     private final static String LPP_PROFILE = "persist.sys.gps.lpp";
 
 
-
     private final PowerManager mPowerManager;
     private final AlarmManager mAlarmManager;
     private final PendingIntent mWakeupIntent;
@@ -459,26 +462,27 @@ public class GnssLocationProvider implements LocationProviderInterface {
      */
     private final ConnectivityManager.NetworkCallback mNetworkConnectivityCallback =
             new ConnectivityManager.NetworkCallback() {
-        @Override
-        public void onAvailable(Network network) {
-            if (mInjectNtpTimePending == STATE_PENDING_NETWORK) {
-                requestUtcTime();
-            }
-            if (mDownloadXtraDataPending == STATE_PENDING_NETWORK) {
-                if (mSupportsXtra) {
-                    // Download only if supported, (prevents an unneccesary on-boot download)
-                    xtraDownloadRequest();
+                @Override
+                public void onAvailable(Network network) {
+                    if (mInjectNtpTimePending == STATE_PENDING_NETWORK) {
+                        requestUtcTime();
+                    }
+                    if (mDownloadXtraDataPending == STATE_PENDING_NETWORK) {
+                        if (mSupportsXtra) {
+                            // Download only if supported, (prevents an unneccesary on-boot
+                            // download)
+                            xtraDownloadRequest();
+                        }
+                    }
+                    // Always on, notify HAL so it can get data it needs
+                    sendMessage(UPDATE_NETWORK_STATE, 0 /*arg*/, network);
                 }
-            }
-            // Always on, notify HAL so it can get data it needs
-            sendMessage(UPDATE_NETWORK_STATE, 0 /*arg*/, network);
-        }
 
-        @Override
-        public void onLost(Network network) {
-            sendMessage(UPDATE_NETWORK_STATE, 0 /*arg*/, network);
-        }
-    };
+                @Override
+                public void onLost(Network network) {
+                    sendMessage(UPDATE_NETWORK_STATE, 0 /*arg*/, network);
+                }
+            };
 
     /**
      * Callback used to listen for availability of a requested SUPL connection.
@@ -487,20 +491,21 @@ public class GnssLocationProvider implements LocationProviderInterface {
      */
     private final ConnectivityManager.NetworkCallback mSuplConnectivityCallback =
             new ConnectivityManager.NetworkCallback() {
-        @Override
-        public void onAvailable(Network network) {
-            // Specific to a change to a SUPL enabled network becoming ready
-            sendMessage(UPDATE_NETWORK_STATE, 0 /*arg*/, network);
-        }
+                @Override
+                public void onAvailable(Network network) {
+                    // Specific to a change to a SUPL enabled network becoming ready
+                    sendMessage(UPDATE_NETWORK_STATE, 0 /*arg*/, network);
+                }
 
-        @Override
-        public void onLost(Network network) {
-            releaseSuplConnection(GPS_RELEASE_AGPS_DATA_CONN);
-        }
-    };
+                @Override
+                public void onLost(Network network) {
+                    releaseSuplConnection(GPS_RELEASE_AGPS_DATA_CONN);
+                }
+            };
 
     private final BroadcastReceiver mBroadcastReceiver = new BroadcastReceiver() {
-        @Override public void onReceive(Context context, Intent intent) {
+        @Override
+        public void onReceive(Context context, Intent intent) {
             String action = intent.getAction();
             if (DEBUG) Log.d(TAG, "receive broadcast intent, action: " + action);
             if (action == null) {
@@ -524,11 +529,11 @@ public class GnssLocationProvider implements LocationProviderInterface {
 
     private final OnSubscriptionsChangedListener mOnSubscriptionsChangedListener =
             new OnSubscriptionsChangedListener() {
-        @Override
-        public void onSubscriptionsChanged() {
-            sendMessage(SUBSCRIPTION_OR_SIM_CHANGED, 0, null);
-        }
-    };
+                @Override
+                public void onSubscriptionsChanged() {
+                    sendMessage(SUBSCRIPTION_OR_SIM_CHANGED, 0, null);
+                }
+            };
 
     private void subscriptionOrSimChanged(Context context) {
         if (DEBUG) Log.d(TAG, "received SIM related action: ");
@@ -599,8 +604,8 @@ public class GnssLocationProvider implements LocationProviderInterface {
 
         String lpp_prof = SystemProperties.get(LPP_PROFILE);
         if (!TextUtils.isEmpty(lpp_prof)) {
-                // override default value of this if lpp_prof is not empty
-                properties.setProperty("LPP_PROFILE", lpp_prof);
+            // override default value of this if lpp_prof is not empty
+            properties.setProperty("LPP_PROFILE", lpp_prof);
         }
         /*
          * Overlay carrier properties from a debug configuration file.
@@ -608,7 +613,7 @@ public class GnssLocationProvider implements LocationProviderInterface {
         loadPropertiesFromFile(DEBUG_PROPERTIES_FILE, properties);
         // TODO: we should get rid of C2K specific setting.
         setSuplHostPort(properties.getProperty("SUPL_HOST"),
-                        properties.getProperty("SUPL_PORT"));
+                properties.getProperty("SUPL_PORT"));
         mC2KServerHost = properties.getProperty("C2K_HOST");
         String portString = properties.getProperty("C2K_PORT");
         if (mC2KServerHost != null && portString != null) {
@@ -625,24 +630,26 @@ public class GnssLocationProvider implements LocationProviderInterface {
                     put("SUPL_MODE", (val) -> native_set_supl_mode(val));
                     put("SUPL_ES", (val) -> native_set_supl_es(val));
                     put("LPP_PROFILE", (val) -> native_set_lpp_profile(val));
-                    put("A_GLONASS_POS_PROTOCOL_SELECT", (val) -> native_set_gnss_pos_protocol_select(val));
-                    put("USE_EMERGENCY_PDN_FOR_EMERGENCY_SUPL", (val) -> native_set_emergency_supl_pdn(val));
+                    put("A_GLONASS_POS_PROTOCOL_SELECT",
+                            (val) -> native_set_gnss_pos_protocol_select(val));
+                    put("USE_EMERGENCY_PDN_FOR_EMERGENCY_SUPL",
+                            (val) -> native_set_emergency_supl_pdn(val));
                     put("GPS_LOCK", (val) -> native_set_gps_lock(val));
                 }
             };
 
-            for(Entry<String, SetCarrierProperty> entry : map.entrySet()) {
+            for (Entry<String, SetCarrierProperty> entry : map.entrySet()) {
                 String propertyName = entry.getKey();
                 String propertyValueString = properties.getProperty(propertyName);
                 if (propertyValueString != null) {
                     try {
-                          int propertyValueInt = Integer.decode(propertyValueString);
-                          boolean result = entry.getValue().set(propertyValueInt);
-                          if (result == false) {
-                              Log.e(TAG, "Unable to set " + propertyName);
-                          }
+                        int propertyValueInt = Integer.decode(propertyValueString);
+                        boolean result = entry.getValue().set(propertyValueInt);
+                        if (result == false) {
+                            Log.e(TAG, "Unable to set " + propertyName);
+                        }
                     } catch (NumberFormatException e) {
-                          Log.e(TAG, "unable to parse propertyName: " + propertyValueString);
+                        Log.e(TAG, "unable to parse propertyName: " + propertyValueString);
                     }
                 }
             }
@@ -663,7 +670,7 @@ public class GnssLocationProvider implements LocationProviderInterface {
     }
 
     private void loadPropertiesFromResource(Context context,
-                                            Properties properties) {
+            Properties properties) {
         String[] configValues = context.getResources().getStringArray(
                 com.android.internal.R.array.config_gpsParameters);
         for (String item : configValues) {
@@ -681,7 +688,7 @@ public class GnssLocationProvider implements LocationProviderInterface {
     }
 
     private boolean loadPropertiesFromFile(String filename,
-                                           Properties properties) {
+            Properties properties) {
         try {
             File file = new File(filename);
             FileInputStream stream = null;
@@ -717,11 +724,11 @@ public class GnssLocationProvider implements LocationProviderInterface {
                 PowerManager.PARTIAL_WAKE_LOCK, DOWNLOAD_EXTRA_WAKELOCK_KEY);
         mDownloadXtraWakeLock.setReferenceCounted(true);
 
-        mAlarmManager = (AlarmManager)mContext.getSystemService(Context.ALARM_SERVICE);
+        mAlarmManager = (AlarmManager) mContext.getSystemService(Context.ALARM_SERVICE);
         mWakeupIntent = PendingIntent.getBroadcast(mContext, 0, new Intent(ALARM_WAKEUP), 0);
         mTimeoutIntent = PendingIntent.getBroadcast(mContext, 0, new Intent(ALARM_TIMEOUT), 0);
 
-        mConnMgr = (ConnectivityManager)context.getSystemService(Context.CONNECTIVITY_SERVICE);
+        mConnMgr = (ConnectivityManager) context.getSystemService(Context.CONNECTIVITY_SERVICE);
 
         // App ops service to keep track of who is accessing the GPS
         mAppOpsService = IAppOpsService.Stub.asInterface(ServiceManager.getService(
@@ -744,8 +751,8 @@ public class GnssLocationProvider implements LocationProviderInterface {
 
         // Create a GPS net-initiated handler.
         mNIHandler = new GpsNetInitiatedHandler(context,
-                                                mNetInitiatedListener,
-                                                mSuplEsEnabled);
+                mNetInitiatedListener,
+                mSuplEsEnabled);
 
         mListenerHelper = new GnssStatusListenerHelper(mHandler) {
             @Override
@@ -766,8 +773,23 @@ public class GnssLocationProvider implements LocationProviderInterface {
             }
 
             @Override
-            protected boolean registerWithService() {
-                return native_start_measurement_collection();
+            protected int registerWithService() {
+                int devOptions = Settings.Secure.getInt(mContext.getContentResolver(),
+                        Settings.Global.DEVELOPMENT_SETTINGS_ENABLED , 0);
+                int fullTrackingToggled = Settings.Global.getInt(mContext.getContentResolver(),
+                        Settings.Global.ENABLE_GNSS_RAW_MEAS_FULL_TRACKING , 0);
+                boolean result = false;
+                if (devOptions == 1 /* Developer Mode enabled */
+                        && fullTrackingToggled == 1 /* Raw Measurements Full Tracking enabled */) {
+                    result =  native_start_measurement_collection(true /* enableFullTracking */);
+                } else {
+                    result =  native_start_measurement_collection(false /* enableFullTracking */);
+                }
+                if (result) {
+                    return RemoteListenerHelper.RESULT_SUCCESS;
+                } else {
+                    return RemoteListenerHelper.RESULT_INTERNAL_ERROR;
+                }
             }
 
             @Override
@@ -788,8 +810,13 @@ public class GnssLocationProvider implements LocationProviderInterface {
             }
 
             @Override
-            protected boolean registerWithService() {
-                return native_start_navigation_message_collection();
+            protected int registerWithService() {
+                boolean result = native_start_navigation_message_collection();
+                if (result) {
+                    return RemoteListenerHelper.RESULT_SUCCESS;
+                } else {
+                    return RemoteListenerHelper.RESULT_INTERNAL_ERROR;
+                }
             }
 
             @Override
@@ -1116,9 +1143,9 @@ public class GnssLocationProvider implements LocationProviderInterface {
      * Checks what SUPL mode to use, according to the AGPS mode as well as the
      * allowed mode from properties.
      *
-     * @param properties GPS properties
+     * @param properties  GPS properties
      * @param agpsEnabled whether AGPS is enabled by settings value
-     * @param singleShot whether "singleshot" is needed
+     * @param singleShot  whether "singleshot" is needed
      * @return SUPL mode (MSA vs MSB vs STANDALONE)
      */
     private int getSuplMode(Properties properties, boolean agpsEnabled, boolean singleShot) {
@@ -1222,7 +1249,7 @@ public class GnssLocationProvider implements LocationProviderInterface {
     }
 
     private void updateStatus(int status, int svCount, int meanCn0, int maxCn0) {
-        if (status != mStatus || svCount != mSvCount || meanCn0 != mMeanCn0 || maxCn0 != mMaxCn0 ) {
+        if (status != mStatus || svCount != mSvCount || meanCn0 != mMeanCn0 || maxCn0 != mMaxCn0) {
             mStatus = status;
             mSvCount = svCount;
             mMeanCn0 = meanCn0;
@@ -1284,7 +1311,7 @@ public class GnssLocationProvider implements LocationProviderInterface {
             updateClientUids(mWorkSource);
 
             mFixInterval = (int) mProviderRequest.interval;
-
+            mLowPowerMode = (boolean) mProviderRequest.lowPowerMode;
             // check for overflow
             if (mFixInterval != mProviderRequest.interval) {
                 Log.w(TAG, "interval overflow: " + mProviderRequest.interval);
@@ -1293,10 +1320,10 @@ public class GnssLocationProvider implements LocationProviderInterface {
 
             // apply request to GPS engine
             if (mStarted && hasCapability(GPS_CAPABILITY_SCHEDULING)) {
-                // change period
+                // change period and/or lowPowerMode
                 if (!native_set_position_mode(mPositionMode, GPS_POSITION_RECURRENCE_PERIODIC,
-                        mFixInterval, 0, 0)) {
-                    Log.e(TAG, "set_position_mode failed in setMinTime()");
+                        mFixInterval, 0, 0, mLowPowerMode)) {
+                    Log.e(TAG, "set_position_mode failed in updateRequirements");
                 }
             } else if (!mStarted) {
                 // start GPS
@@ -1323,7 +1350,7 @@ public class GnssLocationProvider implements LocationProviderInterface {
         // Update sources that were not previously tracked.
         if (newWork != null) {
             int lastuid = -1;
-            for (int i=0; i<newWork.size(); i++) {
+            for (int i = 0; i < newWork.size(); i++) {
                 try {
                     int uid = newWork.get(i);
                     mAppOpsService.startOperation(AppOpsManager.getToken(mAppOpsService),
@@ -1341,7 +1368,7 @@ public class GnssLocationProvider implements LocationProviderInterface {
         // Update sources that are no longer tracked.
         if (goneWork != null) {
             int lastuid = -1;
-            for (int i=0; i<goneWork.size(); i++) {
+            for (int i = 0; i < goneWork.size(); i++) {
                 try {
                     int uid = goneWork.get(i);
                     mAppOpsService.finishOperation(AppOpsManager.getToken(mAppOpsService),
@@ -1455,13 +1482,13 @@ public class GnssLocationProvider implements LocationProviderInterface {
 
             boolean agpsEnabled =
                     (Settings.Global.getInt(mContext.getContentResolver(),
-                                            Settings.Global.ASSISTED_GPS_ENABLED, 1) != 0);
+                            Settings.Global.ASSISTED_GPS_ENABLED, 1) != 0);
             mPositionMode = getSuplMode(mProperties, agpsEnabled, singleShot);
 
             if (DEBUG) {
                 String mode;
 
-                switch(mPositionMode) {
+                switch (mPositionMode) {
                     case GPS_POSITION_MODE_STANDALONE:
                         mode = "standalone";
                         break;
@@ -1479,8 +1506,9 @@ public class GnssLocationProvider implements LocationProviderInterface {
             }
 
             int interval = (hasCapability(GPS_CAPABILITY_SCHEDULING) ? mFixInterval : 1000);
+            mLowPowerMode = (boolean) mProviderRequest.lowPowerMode;
             if (!native_set_position_mode(mPositionMode, GPS_POSITION_RECURRENCE_PERIODIC,
-                    interval, 0, 0)) {
+                    interval, 0, 0, mLowPowerMode)) {
                 mStarted = false;
                 Log.e(TAG, "set_position_mode failed in startNavigating()");
                 return;
@@ -1578,7 +1606,7 @@ public class GnssLocationProvider implements LocationProviderInterface {
         mLastFixTime = SystemClock.elapsedRealtime();
         // report time to first fix
         if (mTimeToFirstFix == 0 && hasLatLong) {
-            mTimeToFirstFix = (int)(mLastFixTime - mFixRequestTime);
+            mTimeToFirstFix = (int) (mLastFixTime - mFixRequestTime);
             if (DEBUG) Log.d(TAG, "TTFF: " + mTimeToFirstFix);
             mGnssMetrics.logTimeToFirstFixMilliSecs(mTimeToFirstFix);
 
@@ -1604,12 +1632,12 @@ public class GnssLocationProvider implements LocationProviderInterface {
             updateStatus(LocationProvider.AVAILABLE, mSvCount, mMeanCn0, mMaxCn0);
         }
 
-       if (!hasCapability(GPS_CAPABILITY_SCHEDULING) && mStarted &&
-               mFixInterval > GPS_POLLING_THRESHOLD_INTERVAL) {
+        if (!hasCapability(GPS_CAPABILITY_SCHEDULING) && mStarted &&
+                mFixInterval > GPS_POLLING_THRESHOLD_INTERVAL) {
             if (DEBUG) Log.d(TAG, "got fix, hibernating");
             hibernate();
         }
-   }
+    }
 
     /**
      * called from native code to update our status
@@ -1650,10 +1678,10 @@ public class GnssLocationProvider implements LocationProviderInterface {
      */
     private void reportSvStatus() {
         int svCount = native_read_sv_status(mSvidWithFlags,
-            mCn0s,
-            mSvElevations,
-            mSvAzimuths,
-            mSvCarrierFreqs);
+                mCn0s,
+                mSvElevations,
+                mSvAzimuths,
+                mSvCarrierFreqs);
         mListenerHelper.onSvStatusChanged(
                 svCount,
                 mSvidWithFlags,
@@ -1676,7 +1704,7 @@ public class GnssLocationProvider implements LocationProviderInterface {
             if ((mSvidWithFlags[i] & GnssStatus.GNSS_SV_FLAGS_USED_IN_FIX) != 0) {
                 ++usedInFixCount;
                 if (mCn0s[i] > maxCn0) {
-                    maxCn0 = (int)mCn0s[i];
+                    maxCn0 = (int) mCn0s[i];
                 }
                 meanCn0 += mCn0s[i];
             }
@@ -1693,7 +1721,7 @@ public class GnssLocationProvider implements LocationProviderInterface {
                         ((mSvidWithFlags[i] & GnssStatus.GNSS_SV_FLAGS_USED_IN_FIX) == 0
                                 ? "" : "U") +
                         ((mSvidWithFlags[i] & GnssStatus.GNSS_SV_FLAGS_HAS_CARRIER_FREQUENCY) == 0
-                        ? "" : "F"));
+                                ? "" : "F"));
             }
         }
         if (usedInFixCount > 0) {
@@ -1703,7 +1731,7 @@ public class GnssLocationProvider implements LocationProviderInterface {
         updateStatus(mStatus, usedInFixCount, meanCn0, maxCn0);
 
         if (mNavigating && mStatus == LocationProvider.AVAILABLE && mLastFixTime > 0 &&
-            SystemClock.elapsedRealtime() - mLastFixTime > RECENT_FIX_TIMEOUT) {
+                SystemClock.elapsedRealtime() - mLastFixTime > RECENT_FIX_TIMEOUT) {
             // send an intent to notify that the GPS is no longer receiving fixes.
             Intent intent = new Intent(LocationManager.GPS_FIX_CHANGE_ACTION);
             intent.putExtra(LocationManager.EXTRA_GPS_ENABLED, false);
@@ -1843,14 +1871,17 @@ public class GnssLocationProvider implements LocationProviderInterface {
          * Returns the GNSS batching size
          */
         int getSize();
+
         /**
          * Starts the hardware batching operation
          */
         boolean start(long periodNanos, boolean wakeOnFifoFull);
+
         /**
          * Forces a flush of existing locations from the hardware batching
          */
         void flush();
+
         /**
          * Stops the batching operation
          */
@@ -1866,6 +1897,7 @@ public class GnssLocationProvider implements LocationProviderInterface {
             public int getSize() {
                 return native_get_batch_size();
             }
+
             @Override
             public boolean start(long periodNanos, boolean wakeOnFifoFull) {
                 if (periodNanos <= 0) {
@@ -1875,10 +1907,12 @@ public class GnssLocationProvider implements LocationProviderInterface {
                 }
                 return native_start_batch(periodNanos, wakeOnFifoFull);
             }
+
             @Override
             public void flush() {
                 native_flush_batch();
             }
+
             @Override
             public boolean stop() {
                 return native_stop_batch();
@@ -1911,7 +1945,7 @@ public class GnssLocationProvider implements LocationProviderInterface {
     private void enableBatching() {
         if (!native_init_batching()) {
             Log.e(TAG, "Failed to initialize GNSS batching");
-        };
+        }
     }
 
     /**
@@ -1927,7 +1961,9 @@ public class GnssLocationProvider implements LocationProviderInterface {
      */
     private void reportLocationBatch(Location[] locationArray) {
         List<Location> locations = new ArrayList<>(Arrays.asList(locationArray));
-        if(DEBUG) { Log.d(TAG, "Location batch of size " + locationArray.length + "reported"); }
+        if (DEBUG) {
+            Log.d(TAG, "Location batch of size " + locationArray.length + " reported");
+        }
         try {
             mILocationManager.reportLocationBatch(locations);
         } catch (RemoteException e) {
@@ -1947,7 +1983,7 @@ public class GnssLocationProvider implements LocationProviderInterface {
      * Converts the GPS HAL status to the internal Geofence Hardware status.
      */
     private int getGeofenceStatus(int status) {
-        switch(status) {
+        switch (status) {
             case GPS_GEOFENCE_OPERATION_SUCCESS:
                 return GeofenceHardware.GEOFENCE_SUCCESS;
             case GPS_GEOFENCE_ERROR_GENERIC:
@@ -1970,7 +2006,7 @@ public class GnssLocationProvider implements LocationProviderInterface {
      * All geofence callbacks are called on the same thread
      */
     private void reportGeofenceTransition(int geofenceId, Location location, int transition,
-                                          long transitionTimestamp) {
+            long transitionTimestamp) {
         if (mGeofenceHardwareImpl == null) {
             mGeofenceHardwareImpl = GeofenceHardwareImpl.getInstance(mContext);
         }
@@ -1992,7 +2028,7 @@ public class GnssLocationProvider implements LocationProviderInterface {
             mGeofenceHardwareImpl = GeofenceHardwareImpl.getInstance(mContext);
         }
         int monitorStatus = GeofenceHardware.MONITOR_CURRENTLY_UNAVAILABLE;
-        if(status == GPS_GEOFENCE_AVAILABLE) {
+        if (status == GPS_GEOFENCE_AVAILABLE) {
             monitorStatus = GeofenceHardware.MONITOR_CURRENTLY_AVAILABLE;
         }
         mGeofenceHardwareImpl.reportGeofenceMonitorStatus(
@@ -2048,12 +2084,13 @@ public class GnssLocationProvider implements LocationProviderInterface {
     private final INetInitiatedListener mNetInitiatedListener = new INetInitiatedListener.Stub() {
         // Sends a response for an NI request to HAL.
         @Override
-        public boolean sendNiResponse(int notificationId, int userResponse)
-        {
+        public boolean sendNiResponse(int notificationId, int userResponse) {
             // TODO Add Permission check
 
-            if (DEBUG) Log.d(TAG, "sendNiResponse, notifId: " + notificationId +
-                    ", response: " + userResponse);
+            if (DEBUG) {
+                Log.d(TAG, "sendNiResponse, notifId: " + notificationId +
+                        ", response: " + userResponse);
+            }
             native_send_ni_response(notificationId, userResponse);
             return true;
         }
@@ -2074,8 +2111,7 @@ public class GnssLocationProvider implements LocationProviderInterface {
             String text,
             int requestorIdEncoding,
             int textEncoding
-        )
-    {
+    ) {
         Log.i(TAG, "reportNiNotification: entered");
         Log.i(TAG, "notificationId: " + notificationId +
                 ", niType: " + niType +
@@ -2094,7 +2130,8 @@ public class GnssLocationProvider implements LocationProviderInterface {
         notification.niType = niType;
         notification.needNotify = (notifyFlags & GpsNetInitiatedHandler.GPS_NI_NEED_NOTIFY) != 0;
         notification.needVerify = (notifyFlags & GpsNetInitiatedHandler.GPS_NI_NEED_VERIFY) != 0;
-        notification.privacyOverride = (notifyFlags & GpsNetInitiatedHandler.GPS_NI_PRIVACY_OVERRIDE) != 0;
+        notification.privacyOverride =
+                (notifyFlags & GpsNetInitiatedHandler.GPS_NI_PRIVACY_OVERRIDE) != 0;
         notification.timeout = timeout;
         notification.defaultResponse = defaultResponse;
         notification.requestorId = requestorId;
@@ -2126,8 +2163,7 @@ public class GnssLocationProvider implements LocationProviderInterface {
                 data = data_temp;
                 type = AGPS_SETID_TYPE_IMSI;
             }
-        }
-        else if ((flags & AGPS_RIL_REQUEST_SETID_MSISDN) == AGPS_RIL_REQUEST_SETID_MSISDN) {
+        } else if ((flags & AGPS_RIL_REQUEST_SETID_MSISDN) == AGPS_RIL_REQUEST_SETID_MSISDN) {
             String data_temp = phone.getLine1Number();
             if (data_temp == null) {
                 // This means the framework does not have the SIM card ready.
@@ -2161,14 +2197,14 @@ public class GnssLocationProvider implements LocationProviderInterface {
             if ((gsm_cell != null) && (phone.getNetworkOperator() != null)
                     && (phone.getNetworkOperator().length() > 3)) {
                 int type;
-                int mcc = Integer.parseInt(phone.getNetworkOperator().substring(0,3));
+                int mcc = Integer.parseInt(phone.getNetworkOperator().substring(0, 3));
                 int mnc = Integer.parseInt(phone.getNetworkOperator().substring(3));
                 int networkType = phone.getNetworkType();
                 if (networkType == TelephonyManager.NETWORK_TYPE_UMTS
-                    || networkType == TelephonyManager.NETWORK_TYPE_HSDPA
-                    || networkType == TelephonyManager.NETWORK_TYPE_HSUPA
-                    || networkType == TelephonyManager.NETWORK_TYPE_HSPA
-                    || networkType == TelephonyManager.NETWORK_TYPE_HSPAP) {
+                        || networkType == TelephonyManager.NETWORK_TYPE_HSDPA
+                        || networkType == TelephonyManager.NETWORK_TYPE_HSUPA
+                        || networkType == TelephonyManager.NETWORK_TYPE_HSPA
+                        || networkType == TelephonyManager.NETWORK_TYPE_HSPAP) {
                     type = AGPS_REF_LOCATION_TYPE_UMTS_CELLID;
                 } else {
                     type = AGPS_REF_LOCATION_TYPE_GSM_CELLID;
@@ -2176,7 +2212,7 @@ public class GnssLocationProvider implements LocationProviderInterface {
                 native_agps_set_ref_location_cellid(type, mcc, mnc,
                         gsm_cell.getLac(), gsm_cell.getCid());
             } else {
-                Log.e(TAG,"Error getting cell location info.");
+                Log.e(TAG, "Error getting cell location info.");
             }
         } else if (phoneType == TelephonyManager.PHONE_TYPE_CDMA) {
             Log.e(TAG, "CDMA not supported.");
@@ -2269,7 +2305,7 @@ public class GnssLocationProvider implements LocationProviderInterface {
              * restart.
              */
             boolean isInitialized = native_init();
-            if(!isInitialized) {
+            if (!isInitialized) {
                 Log.w(TAG, "Native initialization failed at bootup");
             } else {
                 native_cleanup();
@@ -2280,7 +2316,8 @@ public class GnssLocationProvider implements LocationProviderInterface {
             reloadGpsProperties(mContext, mProperties);
 
             // TODO: When this object "finishes" we should unregister by invoking
-            // SubscriptionManager.getInstance(mContext).unregister(mOnSubscriptionsChangedListener);
+            // SubscriptionManager.getInstance(mContext).unregister
+            // (mOnSubscriptionsChangedListener);
             // This is not strictly necessary because it will be unregistered if the
             // notification fails but it is good form.
 
@@ -2359,12 +2396,18 @@ public class GnssLocationProvider implements LocationProviderInterface {
                 handleUpdateLocation(location);
             }
         }
+
         @Override
-        public void onStatusChanged(String provider, int status, Bundle extras) { }
+        public void onStatusChanged(String provider, int status, Bundle extras) {
+        }
+
         @Override
-        public void onProviderEnabled(String provider) { }
+        public void onProviderEnabled(String provider) {
+        }
+
         @Override
-        public void onProviderDisabled(String provider) { }
+        public void onProviderDisabled(String provider) {
+        }
     }
 
     private String getSelectedApn() {
@@ -2373,7 +2416,7 @@ public class GnssLocationProvider implements LocationProviderInterface {
         try {
             cursor = mContext.getContentResolver().query(
                     uri,
-                    new String[] { "apn" },
+                    new String[]{"apn"},
                     null /* selection */,
                     null /* selectionArgs */,
                     Carriers.DEFAULT_SORT_ORDER);
@@ -2404,7 +2447,7 @@ public class GnssLocationProvider implements LocationProviderInterface {
         try {
             cursor = mContext.getContentResolver().query(
                     Carriers.CONTENT_URI,
-                    new String[] { Carriers.PROTOCOL },
+                    new String[]{Carriers.PROTOCOL},
                     selection,
                     null,
                     Carriers.DEFAULT_SORT_ORDER);
@@ -2461,7 +2504,7 @@ public class GnssLocationProvider implements LocationProviderInterface {
 
     /**
      * @return {@code true} if there is a data network available for outgoing connections,
-     *         {@code false} otherwise.
+     * {@code false} otherwise.
      */
     private boolean isDataNetworkConnected() {
         NetworkInfo activeNetworkInfo = mConnMgr.getActiveNetworkInfo();
@@ -2482,7 +2525,7 @@ public class GnssLocationProvider implements LocationProviderInterface {
      * @return A string representing the current state stored in {@link #mAGpsDataConnectionState}.
      */
     private String agpsDataConnStateAsString() {
-        switch(mAGpsDataConnectionState) {
+        switch (mAGpsDataConnectionState) {
             case AGPS_DATA_CONNECTION_CLOSED:
                 return "CLOSED";
             case AGPS_DATA_CONNECTION_OPEN:
@@ -2549,12 +2592,12 @@ public class GnssLocationProvider implements LocationProviderInterface {
     }
 
 
-
     @Override
     public void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
         StringBuilder s = new StringBuilder();
         s.append("  mStarted=").append(mStarted).append('\n');
         s.append("  mFixInterval=").append(mFixInterval).append('\n');
+        s.append("  mLowPowerMode=").append(mLowPowerMode).append('\n');
         s.append("  mDisableGps (battery saver mode)=").append(mDisableGps).append('\n');
         s.append("  mEngineCapabilities=0x").append(Integer.toHexString(mEngineCapabilities));
         s.append(" ( ");
@@ -2618,29 +2661,45 @@ public class GnssLocationProvider implements LocationProviderInterface {
     // preallocated to avoid memory allocation in reportNmea()
     private byte[] mNmeaBuffer = new byte[120];
 
-    static { class_init_native(); }
+    static {
+        class_init_native();
+    }
+
     private static native void class_init_native();
+
     private static native boolean native_is_supported();
+
     private static native boolean native_is_agps_ril_supported();
+
     private static native boolean native_is_gnss_configuration_supported();
 
     private native boolean native_init();
+
     private native void native_cleanup();
+
     private native boolean native_set_position_mode(int mode, int recurrence, int min_interval,
-            int preferred_accuracy, int preferred_time);
+            int preferred_accuracy, int preferred_time, boolean lowPowerMode);
+
     private native boolean native_start();
+
     private native boolean native_stop();
+
     private native void native_delete_aiding_data(int flags);
+
     // returns number of SVs
     // mask[0] is ephemeris mask and mask[1] is almanac mask
     private native int native_read_sv_status(int[] prnWithFlags, float[] cn0s, float[] elevations,
             float[] azimuths, float[] carrierFrequencies);
+
     private native int native_read_nmea(byte[] buffer, int bufferSize);
+
     private native void native_inject_location(double latitude, double longitude, float accuracy);
 
     // XTRA Support
     private native void native_inject_time(long time, long timeReference, int uncertainty);
+
     private native boolean native_supports_xtra();
+
     private native void native_inject_xtra_data(byte[] data, int length);
 
     // DEBUG Support
@@ -2648,9 +2707,13 @@ public class GnssLocationProvider implements LocationProviderInterface {
 
     // AGPS Support
     private native void native_agps_data_conn_open(String apn, int apnIpType);
+
     private native void native_agps_data_conn_closed();
+
     private native void native_agps_data_conn_failed();
-    private native void native_agps_ni_message(byte [] msg, int length);
+
+    private native void native_agps_ni_message(byte[] msg, int length);
+
     private native void native_set_agps_server(int type, String hostname, int port);
 
     // Network-initiated (NI) Support
@@ -2659,6 +2722,7 @@ public class GnssLocationProvider implements LocationProviderInterface {
     // AGPS ril suport
     private native void native_agps_set_ref_location_cellid(int type, int mcc, int mnc,
             int lac, int cid);
+
     private native void native_agps_set_id(int type, String setid);
 
     private native void native_update_network_state(boolean connected, int type,
@@ -2666,38 +2730,57 @@ public class GnssLocationProvider implements LocationProviderInterface {
 
     // Hardware Geofence support.
     private static native boolean native_is_geofence_supported();
+
     private static native boolean native_add_geofence(int geofenceId, double latitude,
-            double longitude, double radius, int lastTransition,int monitorTransitions,
+            double longitude, double radius, int lastTransition, int monitorTransitions,
             int notificationResponsivenes, int unknownTimer);
+
     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 native boolean native_start_measurement_collection();
+
+    private native boolean native_start_measurement_collection(boolean enableFullTracking);
+
     private native boolean native_stop_measurement_collection();
 
     // Gps Navigation message support.
     private static native boolean native_is_navigation_message_supported();
+
     private native boolean native_start_navigation_message_collection();
+
     private native boolean native_stop_navigation_message_collection();
 
     // GNSS Configuration
     private static native boolean native_set_supl_version(int version);
+
     private static native boolean native_set_supl_mode(int mode);
+
     private static native boolean native_set_supl_es(int es);
+
     private static native boolean native_set_lpp_profile(int lppProfile);
+
     private static native boolean native_set_gnss_pos_protocol_select(int gnssPosProtocolSelect);
+
     private static native boolean native_set_gps_lock(int gpsLock);
+
     private static native boolean native_set_emergency_supl_pdn(int emergencySuplPdn);
 
     // GNSS Batching
     private static native int native_get_batch_size();
+
     private static native boolean native_start_batch(long periodNanos, boolean wakeOnFifoFull);
+
     private static native void native_flush_batch();
+
     private static native boolean native_stop_batch();
+
     private static native boolean native_init_batching();
+
     private static native void native_cleanup_batching();
 
 }
index 924520b..477dae6 100644 (file)
@@ -40,11 +40,11 @@ public abstract class GnssMeasurementsProvider
     public void onMeasurementsAvailable(final GnssMeasurementsEvent event) {
         ListenerOperation<IGnssMeasurementsListener> operation =
                 new ListenerOperation<IGnssMeasurementsListener>() {
-            @Override
-            public void execute(IGnssMeasurementsListener listener) throws RemoteException {
-                listener.onGnssMeasurementsReceived(event);
-            }
-        };
+                    @Override
+                    public void execute(IGnssMeasurementsListener listener) throws RemoteException {
+                        listener.onGnssMeasurementsReceived(event);
+                    }
+                };
         foreach(operation);
     }
 
@@ -70,6 +70,9 @@ public abstract class GnssMeasurementsProvider
             case RESULT_INTERNAL_ERROR:
                 status = GnssMeasurementsEvent.Callback.STATUS_NOT_SUPPORTED;
                 break;
+            case RESULT_NOT_ALLOWED:
+                status = GnssMeasurementsEvent.Callback.STATUS_NOT_ALLOWED;
+                break;
             case RESULT_GPS_LOCATION_DISABLED:
                 status = GnssMeasurementsEvent.Callback.STATUS_LOCATION_DISABLED;
                 break;
index fe2bb38..124220f 100644 (file)
@@ -30,8 +30,8 @@ abstract class GnssStatusListenerHelper extends RemoteListenerHelper<IGnssStatus
     }
 
     @Override
-    protected boolean registerWithService() {
-        return true;
+    protected int registerWithService() {
+        return RemoteListenerHelper.RESULT_SUCCESS;
     }
 
     @Override
index f51bc87..58a9516 100644 (file)
@@ -16,8 +16,6 @@
 
 package com.android.server.location;
 
-import com.android.internal.util.Preconditions;
-
 import android.annotation.NonNull;
 import android.os.Handler;
 import android.os.IBinder;
@@ -25,7 +23,8 @@ import android.os.IInterface;
 import android.os.RemoteException;
 import android.util.Log;
 
-import java.lang.Runnable;
+import com.android.internal.util.Preconditions;
+
 import java.util.HashMap;
 import java.util.Map;
 
@@ -40,6 +39,7 @@ abstract class RemoteListenerHelper<TListener extends IInterface> {
     protected static final int RESULT_GPS_LOCATION_DISABLED = 3;
     protected static final int RESULT_INTERNAL_ERROR = 4;
     protected static final int RESULT_UNKNOWN = 5;
+    protected static final int RESULT_NOT_ALLOWED = 6;
 
     private final Handler mHandler;
     private final String mTag;
@@ -118,7 +118,8 @@ abstract class RemoteListenerHelper<TListener extends IInterface> {
 
     protected abstract boolean isAvailableInPlatform();
     protected abstract boolean isGpsEnabled();
-    protected abstract boolean registerWithService(); // must access only on handler thread
+    // must access only on handler thread
+    protected abstract int registerWithService();
     protected abstract void unregisterFromService(); // must access only on handler thread
     protected abstract ListenerOperation<TListener> getHandlerOperation(int result);
 
@@ -177,10 +178,12 @@ abstract class RemoteListenerHelper<TListener extends IInterface> {
 
     private void tryRegister() {
         mHandler.post(new Runnable() {
+            int registrationState = RESULT_INTERNAL_ERROR;
             @Override
             public void run() {
                 if (!mIsRegistered) {
-                    mIsRegistered = registerWithService();
+                    registrationState = registerWithService();
+                    mIsRegistered = registrationState == RESULT_SUCCESS;
                 }
                 if (!mIsRegistered) {
                     // post back a failure
@@ -188,7 +191,7 @@ abstract class RemoteListenerHelper<TListener extends IInterface> {
                         @Override
                         public void run() {
                             synchronized (mListenerMap) {
-                                ListenerOperation<TListener> operation = getHandlerOperation(RESULT_INTERNAL_ERROR);
+                                ListenerOperation<TListener> operation = getHandlerOperation(registrationState);
                                 foreachUnsafe(operation);
                             }
                         }
index 4cbe64d..246bd42 100644 (file)
 
 #define LOG_NDEBUG 0
 
+#include <android/hardware/gnss/1.0/IGnss.h>
 #include <android/hardware/gnss/1.1/IGnss.h>
 
+#include <android/hardware/gnss/1.0/IGnssMeasurement.h>
+#include <android/hardware/gnss/1.1/IGnssMeasurement.h>
 #include <nativehelper/JNIHelp.h>
 #include "jni.h"
 #include "hardware_legacy/power.h"
@@ -77,23 +80,23 @@ using android::hardware::Void;
 using android::hardware::hidl_vec;
 using android::hardware::hidl_death_recipient;
 using android::hidl::base::V1_0::IBase;
-
 using android::hardware::gnss::V1_0::GnssLocation;
 using android::hardware::gnss::V1_0::GnssLocationFlags;
-
+using IGnss_V1_1 = android::hardware::gnss::V1_1::IGnss;
+using IGnssMeasurement_V1_0 = android::hardware::gnss::V1_0::IGnssMeasurement;
+using IGnssMeasurement_V1_1 = android::hardware::gnss::V1_1::IGnssMeasurement;
+using android::hardware::gnss::V1_0::IGnss;
 using android::hardware::gnss::V1_0::IAGnss;
 using android::hardware::gnss::V1_0::IAGnssCallback;
 using android::hardware::gnss::V1_0::IAGnssCallback;
 using android::hardware::gnss::V1_0::IAGnssRil;
 using android::hardware::gnss::V1_0::IAGnssRilCallback;
-using android::hardware::gnss::V1_0::IGnss;
 using android::hardware::gnss::V1_0::IGnssBatching;
 using android::hardware::gnss::V1_0::IGnssBatchingCallback;
 using android::hardware::gnss::V1_0::IGnssConfiguration;
 using android::hardware::gnss::V1_0::IGnssDebug;
 using android::hardware::gnss::V1_0::IGnssGeofenceCallback;
 using android::hardware::gnss::V1_0::IGnssGeofencing;
-using android::hardware::gnss::V1_0::IGnssMeasurement;
 using android::hardware::gnss::V1_0::IGnssMeasurementCallback;
 using android::hardware::gnss::V1_0::IGnssNavigationMessage;
 using android::hardware::gnss::V1_0::IGnssNavigationMessageCallback;
@@ -101,8 +104,6 @@ using android::hardware::gnss::V1_0::IGnssNi;
 using android::hardware::gnss::V1_0::IGnssNiCallback;
 using android::hardware::gnss::V1_0::IGnssXtra;
 using android::hardware::gnss::V1_0::IGnssXtraCallback;
-
-using IGnssV1_1 = android::hardware::gnss::V1_1::IGnss;
 using android::hardware::gnss::V1_1::IGnssCallback;
 
 struct GnssDeathRecipient : virtual public hidl_death_recipient
@@ -118,7 +119,7 @@ struct GnssDeathRecipient : virtual public hidl_death_recipient
 
 sp<GnssDeathRecipient> gnssHalDeathRecipient = nullptr;
 sp<IGnss> gnssHal = nullptr;
-sp<IGnssV1_1> gnssHalV1_1 = nullptr;
+sp<IGnss_V1_1> gnssHal_V1_1 = nullptr;
 sp<IGnssXtra> gnssXtraIface = nullptr;
 sp<IAGnssRil> agnssRilIface = nullptr;
 sp<IGnssGeofencing> gnssGeofencingIface = nullptr;
@@ -127,7 +128,8 @@ sp<IGnssBatching> gnssBatchingIface = nullptr;
 sp<IGnssDebug> gnssDebugIface = nullptr;
 sp<IGnssConfiguration> gnssConfigurationIface = nullptr;
 sp<IGnssNi> gnssNiIface = nullptr;
-sp<IGnssMeasurement> gnssMeasurementIface = nullptr;
+sp<IGnssMeasurement_V1_0> gnssMeasurementIface = nullptr;
+sp<IGnssMeasurement_V1_1> gnssMeasurementIface_V1_1 = nullptr;
 sp<IGnssNavigationMessage> gnssNavigationMessageIface = nullptr;
 
 #define WAKE_LOCK_NAME  "GPS"
@@ -1068,11 +1070,13 @@ static void android_location_GnssLocationProvider_class_init_native(JNIEnv* env,
         LOG_ALWAYS_FATAL("Unable to get Java VM. Error: %d", jvmStatus);
     }
 
-    gnssHal = gnssHalV1_1 = IGnssV1_1::getService();
-
-    if (gnssHal == nullptr) {
+    // TODO(b/31632518)
+    gnssHal_V1_1 = IGnss_V1_1::getService();
+    if (gnssHal_V1_1 == nullptr) {
         ALOGD("gnssHal 1.1 was null, trying 1.0");
         gnssHal = IGnss::getService();
+    } else {
+        gnssHal = gnssHal_V1_1;
     }
 
     if (gnssHal != nullptr) {
@@ -1116,11 +1120,21 @@ static void android_location_GnssLocationProvider_class_init_native(JNIEnv* env,
             gnssNavigationMessageIface = gnssNavigationMessage;
         }
 
-        auto gnssMeasurement = gnssHal->getExtensionGnssMeasurement();
-        if (!gnssMeasurement.isOk()) {
-            ALOGD("Unable to get a handle to GnssMeasurement");
+        if (gnssHal_V1_1 != nullptr) {
+             auto gnssMeasurement = gnssHal_V1_1->getExtensionGnssMeasurement_1_1();
+             if (!gnssMeasurement.isOk()) {
+                 ALOGD("Unable to get a handle to GnssMeasurement");
+             } else {
+                 gnssMeasurementIface_V1_1 = gnssMeasurement;
+                 gnssMeasurementIface = gnssMeasurementIface_V1_1;
+             }
         } else {
-            gnssMeasurementIface = gnssMeasurement;
+             auto gnssMeasurement_V1_0 = gnssHal->getExtensionGnssMeasurement();
+             if (!gnssMeasurement_V1_0.isOk()) {
+                 ALOGD("Unable to get a handle to GnssMeasurement");
+             } else {
+                 gnssMeasurementIface = gnssMeasurement_V1_0;
+             }
         }
 
         auto gnssDebug = gnssHal->getExtensionGnssDebug();
@@ -1195,8 +1209,8 @@ static jboolean android_location_GnssLocationProvider_init(JNIEnv* env, jobject
     sp<IGnssCallback> gnssCbIface = new GnssCallback();
 
     Return<bool> result = false;
-    if (gnssHalV1_1 != nullptr) {
-        result = gnssHalV1_1->setCallback_1_1(gnssCbIface);
+    if (gnssHal_V1_1 != nullptr) {
+        result = gnssHal_V1_1->setCallback_1_1(gnssCbIface);
     } else {
         result = gnssHal->setCallback(gnssCbIface);
     }
@@ -1255,21 +1269,27 @@ static void android_location_GnssLocationProvider_cleanup(JNIEnv* /* env */, job
 
 static jboolean android_location_GnssLocationProvider_set_position_mode(JNIEnv* /* env */,
         jobject /* obj */, jint mode, jint recurrence, jint min_interval, jint preferred_accuracy,
-        jint preferred_time) {
-    if (gnssHal != nullptr) {
-        auto result = gnssHal->setPositionMode(static_cast<IGnss::GnssPositionMode>(mode),
-                                     static_cast<IGnss::GnssPositionRecurrence>(recurrence),
-                                     min_interval,
-                                     preferred_accuracy,
-                                     preferred_time);
-        if (!result.isOk()) {
-            ALOGE("%s: GNSS setPositionMode failed\n", __func__);
-            return JNI_FALSE;
-        } else {
-            return result;
-        }
+        jint preferred_time, jboolean low_power_mode) {
+    Return<bool> result = false;
+    if (gnssHal_V1_1 != nullptr) {
+         result = gnssHal_V1_1->setPositionMode_1_1(static_cast<IGnss::GnssPositionMode>(mode),
+                                                             static_cast<IGnss::GnssPositionRecurrence>(recurrence),
+                                                             min_interval,
+                                                             preferred_accuracy,
+                                                             preferred_time,
+                                                             low_power_mode);
+     } else if (gnssHal != nullptr) {
+         result = gnssHal->setPositionMode(static_cast<IGnss::GnssPositionMode>(mode),
+                                                                      static_cast<IGnss::GnssPositionRecurrence>(recurrence),
+                                                                      min_interval,
+                                                                      preferred_accuracy,
+                                                                      preferred_time);
+    }
+    if (!result.isOk()) {
+       ALOGE("%s: GNSS setPositionMode failed\n", __func__);
+       return JNI_FALSE;
     } else {
-        return JNI_FALSE;
+       return result;
     }
 }
 
@@ -1679,16 +1699,29 @@ static jboolean android_location_GnssLocationProvider_is_measurement_supported(
 }
 
 static jboolean android_location_GnssLocationProvider_start_measurement_collection(
-        JNIEnv* env,
-        jobject obj) {
+        JNIEnv* /* env */,
+        jobject /* obj */,
+        jboolean enableFullTracking) {
     if (gnssMeasurementIface == nullptr) {
         ALOGE("GNSS Measurement interface is not available.");
         return JNI_FALSE;
     }
 
     sp<GnssMeasurementCallback> cbIface = new GnssMeasurementCallback();
-    IGnssMeasurement::GnssMeasurementStatus result = gnssMeasurementIface->setCallback(cbIface);
-    if (result != IGnssMeasurement::GnssMeasurementStatus::SUCCESS) {
+    IGnssMeasurement_V1_0::GnssMeasurementStatus result =
+                    IGnssMeasurement_V1_0::GnssMeasurementStatus::ERROR_GENERIC;;
+    if (gnssMeasurementIface_V1_1 != nullptr) {
+         result = gnssMeasurementIface_V1_1->setCallback_1_1(cbIface,
+                        enableFullTracking);
+    } else {
+        if (enableFullTracking == JNI_TRUE) {
+            // full tracking mode not supported in 1.0 HAL
+            return JNI_FALSE;
+        }
+        result = gnssMeasurementIface->setCallback(cbIface);
+    }
+
+    if (result != IGnssMeasurement_V1_0::GnssMeasurementStatus::SUCCESS) {
         ALOGE("An error has been found on GnssMeasurementInterface::init, status=%d",
               static_cast<int32_t>(result));
         return JNI_FALSE;
@@ -1941,8 +1974,8 @@ static const JNINativeMethod sMethods[] = {
     {"native_cleanup", "()V", reinterpret_cast<void *>(
             android_location_GnssLocationProvider_cleanup)},
     {"native_set_position_mode",
-            "(IIIII)Z",
-            reinterpret_cast<void*>(android_location_GnssLocationProvider_set_position_mode)},
+                "(IIIIIZ)Z",
+                reinterpret_cast<void*>(android_location_GnssLocationProvider_set_position_mode)},
     {"native_start", "()Z", reinterpret_cast<void*>(android_location_GnssLocationProvider_start)},
     {"native_stop", "()Z", reinterpret_cast<void*>(android_location_GnssLocationProvider_stop)},
     {"native_delete_aiding_data",
@@ -2010,7 +2043,7 @@ static const JNINativeMethod sMethods[] = {
             reinterpret_cast<void *>(
                     android_location_GnssLocationProvider_is_measurement_supported)},
     {"native_start_measurement_collection",
-            "()Z",
+             "(Z)Z",
             reinterpret_cast<void *>(
                     android_location_GnssLocationProvider_start_measurement_collection)},
     {"native_stop_measurement_collection",