Merge "Update getGnssCapabilities() in LMS to include sub-HAL capabilities"
diff --git a/api/system-current.txt b/api/system-current.txt
index 0b50b0c..583dd76 100644
--- a/api/system-current.txt
+++ b/api/system-current.txt
@@ -3068,6 +3068,19 @@
     method public void onLocationBatch(java.util.List<android.location.Location>);
   }
 
+  public final class GnssCapabilities {
+    method public boolean hasCapability(int);
+    field public static final int GEOFENCING = 2; // 0x2
+    field public static final int LOW_POWER_MODE = 0; // 0x0
+    field public static final int MEASUREMENTS = 3; // 0x3
+    field public static final int MEASUREMENT_CORRECTIONS = 5; // 0x5
+    field public static final int MEASUREMENT_CORRECTIONS_EXCESS_PATH_LENGTH = 7; // 0x7
+    field public static final int MEASUREMENT_CORRECTIONS_LOS_SATS = 6; // 0x6
+    field public static final int MEASUREMENT_CORRECTIONS_REFLECTING_PLANE = 8; // 0x8
+    field public static final int NAV_MESSAGES = 4; // 0x4
+    field public static final int SATELLITE_BLACKLIST = 1; // 0x1
+  }
+
   public final class GnssMeasurementCorrections implements android.os.Parcelable {
     method public int describeContents();
     method @FloatRange(from=-1000.0F, to=10000.0f) public double getAltitudeMeters();
@@ -3375,7 +3388,7 @@
   public class LocationManager {
     method @RequiresPermission(android.Manifest.permission.LOCATION_HARDWARE) public void flushGnssBatch();
     method @RequiresPermission(android.Manifest.permission.LOCATION_HARDWARE) public int getGnssBatchSize();
-    method public int getGnssCapabilities();
+    method @Nullable public android.location.GnssCapabilities getGnssCapabilities();
     method @Nullable public String getLocationControllerExtraPackage();
     method @RequiresPermission(android.Manifest.permission.ACCESS_FINE_LOCATION) public void injectGnssMeasurementCorrections(@NonNull android.location.GnssMeasurementCorrections);
     method public boolean isLocationControllerExtraPackageEnabled();
diff --git a/location/java/android/location/GnssCapabilities.java b/location/java/android/location/GnssCapabilities.java
new file mode 100644
index 0000000..6a35920
--- /dev/null
+++ b/location/java/android/location/GnssCapabilities.java
@@ -0,0 +1,153 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.location;
+
+import android.annotation.IntDef;
+import android.annotation.SystemApi;
+
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+
+/**
+ * A container of supported GNSS chipset capabilities.
+ *
+ * @hide
+ */
+@SystemApi
+public final class GnssCapabilities {
+    /** The GNSS chipset supports low power mode. */
+    public static final int LOW_POWER_MODE                                              = 0;
+
+    /** The GNSS chipset supports blacklisting satellites. */
+    public static final int SATELLITE_BLACKLIST                                         = 1;
+
+    /** The GNSS chipset supports geofencing. */
+    public static final int GEOFENCING                                                  = 2;
+
+    /** The GNSS chipset supports measurements.*/
+    public static final int MEASUREMENTS                                                = 3;
+
+    /** The GNSS chipset supports navigation messages. */
+    public static final int NAV_MESSAGES                                                = 4;
+
+    /** The GNSS chipset supports measurement corrections. */
+    public static final int MEASUREMENT_CORRECTIONS                                     = 5;
+
+    /** The GNSS chipset supports line-of-sight satellite identification measurement corrections. */
+    public static final int MEASUREMENT_CORRECTIONS_LOS_SATS                            = 6;
+
+    /** The GNSS chipset supports per satellite excess-path-length measurement corrections. */
+    public static final int MEASUREMENT_CORRECTIONS_EXCESS_PATH_LENGTH                  = 7;
+
+    /** The GNSS chipset supports reflecting planes measurement corrections. */
+    public static final int MEASUREMENT_CORRECTIONS_REFLECTING_PLANE                    = 8;
+
+    private static final int MIN_CAPABILITY = 0;
+    private static final int MAX_CAPABILITY = MEASUREMENT_CORRECTIONS_REFLECTING_PLANE;
+
+    /**
+     * GNSS capability.
+     * @hide
+     */
+    @Retention(RetentionPolicy.SOURCE)
+    @IntDef({
+            LOW_POWER_MODE,
+            SATELLITE_BLACKLIST,
+            GEOFENCING,
+            MEASUREMENTS,
+            NAV_MESSAGES,
+            MEASUREMENT_CORRECTIONS,
+            MEASUREMENT_CORRECTIONS_LOS_SATS,
+            MEASUREMENT_CORRECTIONS_EXCESS_PATH_LENGTH,
+            MEASUREMENT_CORRECTIONS_REFLECTING_PLANE
+    })
+    public @interface Capability {}
+
+    /**
+     * @hide
+     */
+    public static final long INVALID_CAPABILITIES = -1;
+
+    /** A bitmask of supported GNSS capabilities. */
+    private final long mGnssCapabilities;
+
+    static GnssCapabilities of(long gnssCapabilities) {
+        return new GnssCapabilities(gnssCapabilities);
+    }
+
+    private GnssCapabilities(long gnssCapabilities) {
+        mGnssCapabilities = gnssCapabilities;
+    }
+
+    /**
+     * Returns {@code true} if the {@code capability} is supported by the GNSS implementation.
+     */
+    public boolean hasCapability(@Capability int capability) {
+        return isValidCapability(capability) && (mGnssCapabilities & (1 << capability)) != 0;
+    }
+
+    @Override
+    public String toString() {
+        StringBuilder sb = new StringBuilder("GnssCapabilities: (");
+        int capability = 0;
+        boolean addSeparator = false;
+        long gnssCapabilities = mGnssCapabilities;
+        while (gnssCapabilities != 0) {
+            if ((gnssCapabilities & 1) != 0) {
+                if (addSeparator) {
+                    sb.append(' ');
+                } else {
+                    addSeparator = true;
+                }
+                sb.append(toStringCapability(capability));
+            }
+            gnssCapabilities >>= 1;
+            ++capability;
+        }
+        sb.append(")");
+        return sb.toString();
+    }
+
+    private boolean isValidCapability(@Capability int capability) {
+        return capability >= MIN_CAPABILITY && capability <= MAX_CAPABILITY;
+    }
+
+    private static String toStringCapability(@Capability int capability) {
+        switch (capability) {
+            case LOW_POWER_MODE:
+                return "LOW_POWER_MODE";
+            case SATELLITE_BLACKLIST:
+                return "SATELLITE_BLACKLIST";
+            case GEOFENCING:
+                return "GEOFENCING";
+            case MEASUREMENTS:
+                return "MEASUREMENTS";
+            case NAV_MESSAGES:
+                return "NAV_MESSAGES";
+            case MEASUREMENT_CORRECTIONS:
+                return "MEASUREMENT_CORRECTIONS";
+            case MEASUREMENT_CORRECTIONS_LOS_SATS:
+                return "MEASUREMENT_CORRECTIONS_LOS_SATS";
+            case MEASUREMENT_CORRECTIONS_EXCESS_PATH_LENGTH:
+                return "MEASUREMENT_CORRECTIONS_EXCESS_PATH_LENGTH";
+            case MEASUREMENT_CORRECTIONS_REFLECTING_PLANE:
+                return "MEASUREMENT_CORRECTIONS_REFLECTING_PLANE";
+            default:
+                return "Unknown(" + capability + ")";
+        }
+    }
+}
diff --git a/location/java/android/location/GnssMeasurementCallbackTransport.java b/location/java/android/location/GnssMeasurementCallbackTransport.java
index 1188b13b..8cb8c0b 100644
--- a/location/java/android/location/GnssMeasurementCallbackTransport.java
+++ b/location/java/android/location/GnssMeasurementCallbackTransport.java
@@ -63,7 +63,7 @@
                 measurementCorrections, getContext().getPackageName());
     }
 
-    protected int getGnssCapabilities() throws RemoteException {
+    protected long getGnssCapabilities() throws RemoteException {
         return mLocationManager.getGnssCapabilities(getContext().getPackageName());
     }
 
diff --git a/location/java/android/location/ILocationManager.aidl b/location/java/android/location/ILocationManager.aidl
index c371c5f..a4582b7 100644
--- a/location/java/android/location/ILocationManager.aidl
+++ b/location/java/android/location/ILocationManager.aidl
@@ -66,7 +66,7 @@
     boolean addGnssMeasurementsListener(in IGnssMeasurementsListener listener, in String packageName);
     void injectGnssMeasurementCorrections(in GnssMeasurementCorrections corrections,
             in String packageName);
-    int getGnssCapabilities(in String packageName);
+    long getGnssCapabilities(in String packageName);
     void removeGnssMeasurementsListener(in IGnssMeasurementsListener listener);
 
     boolean addGnssNavigationMessageListener(
diff --git a/location/java/android/location/LocationManager.java b/location/java/android/location/LocationManager.java
index 01f1798..edf304c 100644
--- a/location/java/android/location/LocationManager.java
+++ b/location/java/android/location/LocationManager.java
@@ -1986,15 +1986,19 @@
     }
 
     /**
-     * Returns the integer capability flags of the GNSS chipset as defined in {@code
-     * IGnssCallback.hal}
+     * Returns the supported capabilities of the GNSS chipset or {@code null} if there is an error
+     * in obtaining the capabilities.
      *
      * @hide
      */
     @SystemApi
-    public int getGnssCapabilities() {
+    public @Nullable GnssCapabilities getGnssCapabilities() {
         try {
-            return mGnssMeasurementCallbackTransport.getGnssCapabilities();
+            long gnssCapabilities = mGnssMeasurementCallbackTransport.getGnssCapabilities();
+            if (gnssCapabilities == GnssCapabilities.INVALID_CAPABILITIES) {
+                return null;
+            }
+            return GnssCapabilities.of(gnssCapabilities);
         } catch (RemoteException e) {
             throw e.rethrowFromSystemServer();
         }
diff --git a/services/core/java/com/android/server/LocationManagerService.java b/services/core/java/com/android/server/LocationManagerService.java
index 6ef5b54..ceeb539 100644
--- a/services/core/java/com/android/server/LocationManagerService.java
+++ b/services/core/java/com/android/server/LocationManagerService.java
@@ -2943,7 +2943,7 @@
     }
 
     @Override
-    public int getGnssCapabilities(String packageName) {
+    public long getGnssCapabilities(String packageName) {
         mContext.enforceCallingPermission(
                 android.Manifest.permission.LOCATION_HARDWARE,
                 "Location Hardware permission not granted to obtain GNSS chipset capabilities.");