Merge "[view compiler] Add test coverage for layouts compiled from APK"
diff --git a/api/system-current.txt b/api/system-current.txt
index eb7ed6e..09737e8 100644
--- a/api/system-current.txt
+++ b/api/system-current.txt
@@ -9238,7 +9238,7 @@
     field public static final int STATE_UNAVAILABLE = 0; // 0x0
   }
 
-  public static class ImsFeature.Capabilities {
+  @Deprecated public static class ImsFeature.Capabilities {
     field @Deprecated protected int mCapabilities;
   }
 
@@ -9272,7 +9272,7 @@
   public static class MmTelFeature.MmTelCapabilities extends android.telephony.ims.feature.ImsFeature.Capabilities {
     ctor public MmTelFeature.MmTelCapabilities();
     ctor @Deprecated public MmTelFeature.MmTelCapabilities(android.telephony.ims.feature.ImsFeature.Capabilities);
-    ctor public MmTelFeature.MmTelCapabilities(int);
+    ctor public MmTelFeature.MmTelCapabilities(@android.telephony.ims.feature.MmTelFeature.MmTelCapabilities.MmTelCapability int);
     method public final void addCapabilities(@android.telephony.ims.feature.MmTelFeature.MmTelCapabilities.MmTelCapability int);
     method public final boolean isCapable(@android.telephony.ims.feature.MmTelFeature.MmTelCapabilities.MmTelCapability int);
     method public final void removeCapabilities(@android.telephony.ims.feature.MmTelFeature.MmTelCapabilities.MmTelCapability int);
diff --git a/telephony/java/android/provider/Telephony.java b/telephony/java/android/provider/Telephony.java
index 3e4cd4d..ddda010 100644
--- a/telephony/java/android/provider/Telephony.java
+++ b/telephony/java/android/provider/Telephony.java
@@ -3963,6 +3963,13 @@
         public static final Uri CONTENT_URI = Uri.parse("content://cellbroadcasts");
 
         /**
+         * The id of the subscription which received this cell broadcast message.
+         * <P>Type: INTEGER</P>
+         * @hide
+         */
+        public static final String SUB_ID = "sub_id";
+
+        /**
          * Message geographical scope. Valid values are:
          * <ul>
          * <li>{@link android.telephony.SmsCbMessage#GEOGRAPHICAL_SCOPE_CELL_WIDE}. meaning the
@@ -4184,6 +4191,18 @@
         public static final String GEOMETRIES = "geometries";
 
         /**
+         * Geo-Fencing Maximum Wait Time in second. The range of the time is [0, 255]. A device
+         * shall allow to determine its position meeting operator policy. If the device is unable to
+         * determine its position meeting operator policy within the GeoFencing Maximum Wait Time,
+         * it shall present the alert to the user and discontinue further positioning determination
+         * for the alert.
+         *
+         * <P>Type: INTEGER</P>
+         * @hide
+         */
+        public static final String MAXIMUM_WAIT_TIME = "maximum_wait_time";
+
+        /**
          * Query columns for instantiating {@link android.telephony.CellBroadcastMessage} objects.
          * @hide
          */
@@ -4236,7 +4255,8 @@
                 CMAS_CERTAINTY,
                 RECEIVED_TIME,
                 MESSAGE_BROADCASTED,
-                GEOMETRIES
+                GEOMETRIES,
+                MAXIMUM_WAIT_TIME
         };
     }
 
diff --git a/telephony/java/android/telephony/SmsCbMessage.java b/telephony/java/android/telephony/SmsCbMessage.java
index 77231d1..c078764 100644
--- a/telephony/java/android/telephony/SmsCbMessage.java
+++ b/telephony/java/android/telephony/SmsCbMessage.java
@@ -139,6 +139,12 @@
     @Retention(RetentionPolicy.SOURCE)
     public @interface MessagePriority {}
 
+    /**
+     * ATIS-0700041 Section 5.2.8 WAC Geo-Fencing Maximum Wait Time Table 12.
+     * @hide
+     */
+    public static final int MAXIMUM_WAIT_TIME_NOT_SET = 255;
+
     /** Format of this message (for interpretation of service category values). */
     private final int mMessageFormat;
 
@@ -187,6 +193,14 @@
     @Nullable
     private final SmsCbCmasInfo mCmasWarningInfo;
 
+    /**
+     * Geo-Fencing Maximum Wait Time in second, a device shall allow to determine its position
+     * meeting operator policy. If the device is unable to determine its position meeting operator
+     * policy within the GeoFencing Maximum Wait Time, it shall present the alert to the user and
+     * discontinue further positioning determination for the alert.
+     */
+    private final int mMaximumWaitTimeSec;
+
     /** UNIX timestamp of when the message was received. */
     private final long mReceivedTimeMillis;
 
@@ -202,8 +216,8 @@
             @Nullable SmsCbCmasInfo cmasWarningInfo) {
 
         this(messageFormat, geographicalScope, serialNumber, location, serviceCategory, language,
-                body, priority, etwsWarningInfo, cmasWarningInfo, null /* geometries */,
-                System.currentTimeMillis());
+                body, priority, etwsWarningInfo, cmasWarningInfo, 0 /* maximumWaitingTime */,
+                null /* geometries */, System.currentTimeMillis());
     }
 
     /**
@@ -213,7 +227,7 @@
     public SmsCbMessage(int messageFormat, int geographicalScope, int serialNumber,
             SmsCbLocation location, int serviceCategory, String language, String body,
             int priority, SmsCbEtwsInfo etwsWarningInfo, SmsCbCmasInfo cmasWarningInfo,
-            List<Geometry> geometries, long receivedTimeMillis) {
+            int maximumWaitTimeSec, List<Geometry> geometries, long receivedTimeMillis) {
         mMessageFormat = messageFormat;
         mGeographicalScope = geographicalScope;
         mSerialNumber = serialNumber;
@@ -226,6 +240,7 @@
         mCmasWarningInfo = cmasWarningInfo;
         mReceivedTimeMillis = receivedTimeMillis;
         mGeometries = geometries;
+        mMaximumWaitTimeSec = maximumWaitTimeSec;
     }
 
     /**
@@ -262,6 +277,7 @@
         mReceivedTimeMillis = in.readLong();
         String geoStr = in.readString();
         mGeometries = geoStr != null ? CbGeoUtils.parseGeometriesFromString(geoStr) : null;
+        mMaximumWaitTimeSec = in.readInt();
     }
 
     /**
@@ -295,6 +311,7 @@
         dest.writeLong(mReceivedTimeMillis);
         dest.writeString(
                 mGeometries != null ? CbGeoUtils.encodeGeometriesToString(mGeometries) : null);
+        dest.writeInt(mMaximumWaitTimeSec);
     }
 
     @NonNull
@@ -389,6 +406,15 @@
     }
 
     /**
+     * Get the Geo-Fencing Maximum Wait Time.
+     * @return the time in second.
+     * @hide
+     */
+    public int getMaximumWaitingTime() {
+        return mMaximumWaitTimeSec;
+    }
+
+    /**
      * Get the time when this message was received.
      * @return the time in millisecond
      */
@@ -475,6 +501,7 @@
                 + ", priority=" + mPriority
                 + (mEtwsWarningInfo != null ? (", " + mEtwsWarningInfo.toString()) : "")
                 + (mCmasWarningInfo != null ? (", " + mCmasWarningInfo.toString()) : "")
+                + ", maximumWaitingTime = " + mMaximumWaitTimeSec
                 + ", geo=" + (mGeometries != null
                 ? CbGeoUtils.encodeGeometriesToString(mGeometries) : "null")
                 + '}';
@@ -535,6 +562,8 @@
             cv.put(CellBroadcasts.GEOMETRIES, (String) null);
         }
 
+        cv.put(CellBroadcasts.MAXIMUM_WAIT_TIME, mMaximumWaitTimeSec);
+
         return cv;
     }
 
@@ -644,17 +673,21 @@
         List<Geometry> geometries =
                 geoStr != null ? CbGeoUtils.parseGeometriesFromString(geoStr) : null;
 
-        long receivedTimeSec = cursor.getLong(
+        long receivedTimeMillis = cursor.getLong(
                 cursor.getColumnIndexOrThrow(CellBroadcasts.RECEIVED_TIME));
 
+        int maximumWaitTimeSec = cursor.getInt(
+                cursor.getColumnIndexOrThrow(CellBroadcasts.MAXIMUM_WAIT_TIME));
+
         return new SmsCbMessage(format, geoScope, serialNum, location, category,
-                language, body, priority, etwsInfo, cmasInfo, geometries, receivedTimeSec);
+                language, body, priority, etwsInfo, cmasInfo, maximumWaitTimeSec, geometries,
+                receivedTimeMillis);
     }
 
     /**
      * @return {@code True} if this message needs geo-fencing check.
      */
     public boolean needGeoFencingCheck() {
-        return mGeometries != null;
+        return mMaximumWaitTimeSec > 0 && mGeometries != null;
     }
 }
diff --git a/telephony/java/android/telephony/ims/feature/ImsFeature.java b/telephony/java/android/telephony/ims/feature/ImsFeature.java
index 3a9979d..3562880 100644
--- a/telephony/java/android/telephony/ims/feature/ImsFeature.java
+++ b/telephony/java/android/telephony/ims/feature/ImsFeature.java
@@ -201,15 +201,20 @@
     }
 
     /**
-     * Contains the capabilities defined and supported by an ImsFeature in the form of a bit mask.
-     * <p>
-     * Typically this class is not used directly, but rather extended in subclasses of
+     * Contains the IMS capabilities defined and supported by an ImsFeature in the form of a
+     * bit-mask.
+     *
+     * @deprecated This class is not used directly, but rather extended in subclasses of
      * {@link ImsFeature} to provide service specific capabilities.
+     * @see MmTelFeature.MmTelCapabilities
      * @hide
      */
-    @SystemApi
+    // Not Actually deprecated, but we need to remove it from the @SystemApi surface.
+    @Deprecated
+    @SystemApi // SystemApi only because it was leaked through type usage in a previous release.
     public static class Capabilities {
         /** @deprecated Use getters and accessors instead. */
+        // Not actually deprecated, but we need to remove it from the @SystemApi surface eventually.
         protected int mCapabilities = 0;
 
         /**
diff --git a/telephony/java/android/telephony/ims/feature/MmTelFeature.java b/telephony/java/android/telephony/ims/feature/MmTelFeature.java
index 20c191d..ceb4704 100644
--- a/telephony/java/android/telephony/ims/feature/MmTelFeature.java
+++ b/telephony/java/android/telephony/ims/feature/MmTelFeature.java
@@ -242,8 +242,8 @@
          * @param capabilities The capabilities that are supported for MmTel in the form of a
          *                     bitfield.
          */
-        public MmTelCapabilities(int capabilities) {
-            mCapabilities = capabilities;
+        public MmTelCapabilities(@MmTelCapability int capabilities) {
+            super(capabilities);
         }
 
         @IntDef(flag = true,
diff --git a/telephony/java/com/android/internal/telephony/CbGeoUtils.java b/telephony/java/com/android/internal/telephony/CbGeoUtils.java
index 73dd822..0b73252 100644
--- a/telephony/java/com/android/internal/telephony/CbGeoUtils.java
+++ b/telephony/java/com/android/internal/telephony/CbGeoUtils.java
@@ -299,7 +299,8 @@
      * @return the encoded string.
      */
     @NonNull
-    public static String encodeGeometriesToString(@NonNull List<Geometry> geometries) {
+    public static String encodeGeometriesToString(List<Geometry> geometries) {
+        if (geometries == null || geometries.isEmpty()) return "";
         return geometries.stream()
                 .map(geometry -> encodeGeometryToString(geometry))
                 .filter(encodedStr -> !TextUtils.isEmpty(encodedStr))
diff --git a/telephony/java/com/android/internal/telephony/gsm/GsmSmsCbMessage.java b/telephony/java/com/android/internal/telephony/gsm/GsmSmsCbMessage.java
index dca4e6b..6eea118 100644
--- a/telephony/java/com/android/internal/telephony/gsm/GsmSmsCbMessage.java
+++ b/telephony/java/com/android/internal/telephony/gsm/GsmSmsCbMessage.java
@@ -104,7 +104,7 @@
                     header.getSerialNumber(), location, header.getServiceCategory(), null,
                     getEtwsPrimaryMessage(context, header.getEtwsInfo().getWarningType()),
                     SmsCbMessage.MESSAGE_PRIORITY_EMERGENCY, header.getEtwsInfo(),
-                    header.getCmasInfo(), null /* geometries */, receivedTimeMillis);
+                    header.getCmasInfo(), 0, null /* geometries */, receivedTimeMillis);
         } else if (header.isUmtsFormat()) {
             // UMTS format has only 1 PDU
             byte[] pdu = pdus[0];
@@ -120,9 +120,13 @@
 
             // Has Warning Area Coordinates information
             List<Geometry> geometries = null;
+            int maximumWaitingTimeSec = 255;
             if (pdu.length > wacDataOffset) {
                 try {
-                    geometries = parseWarningAreaCoordinates(pdu, wacDataOffset);
+                    Pair<Integer, List<Geometry>> wac = parseWarningAreaCoordinates(pdu,
+                            wacDataOffset);
+                    maximumWaitingTimeSec = wac.first;
+                    geometries = wac.second;
                 } catch (Exception ex) {
                     // Catch the exception here, the message will be considered as having no WAC
                     // information which means the message will be broadcasted directly.
@@ -133,7 +137,8 @@
             return new SmsCbMessage(SmsCbMessage.MESSAGE_FORMAT_3GPP,
                     header.getGeographicalScope(), header.getSerialNumber(), location,
                     header.getServiceCategory(), language, body, priority,
-                    header.getEtwsInfo(), header.getCmasInfo(), geometries, receivedTimeMillis);
+                    header.getEtwsInfo(), header.getCmasInfo(), maximumWaitingTimeSec, geometries,
+                    receivedTimeMillis);
         } else {
             String language = null;
             StringBuilder sb = new StringBuilder();
@@ -148,7 +153,7 @@
             return new SmsCbMessage(SmsCbMessage.MESSAGE_FORMAT_3GPP,
                     header.getGeographicalScope(), header.getSerialNumber(), location,
                     header.getServiceCategory(), language, sb.toString(), priority,
-                    header.getEtwsInfo(), header.getCmasInfo(), null /* geometries */,
+                    header.getEtwsInfo(), header.getCmasInfo(), 0, null /* geometries */,
                     receivedTimeMillis);
         }
     }
@@ -197,7 +202,17 @@
         }
     }
 
-    private static List<Geometry> parseWarningAreaCoordinates(byte[] pdu, int wacOffset) {
+    /**
+     * Parse the broadcast area and maximum wait time from the Warning Area Coordinates TLV.
+     *
+     * @param pdu Warning Area Coordinates TLV.
+     * @param wacOffset the offset of Warning Area Coordinates TLV.
+     * @return a pair with the first element is maximum wait time and the second is the broadcast
+     * area. The default value of the maximum wait time is 255 which means use the device default
+     * value.
+     */
+    private static Pair<Integer, List<Geometry>> parseWarningAreaCoordinates(
+            byte[] pdu, int wacOffset) {
         // little-endian
         int wacDataLength = (pdu[wacOffset + 1] << 8) | pdu[wacOffset];
         int offset = wacOffset + 2;
@@ -209,6 +224,8 @@
 
         BitStreamReader bitReader = new BitStreamReader(pdu, offset);
 
+        int maximumWaitTimeSec = SmsCbMessage.MAXIMUM_WAIT_TIME_NOT_SET;
+
         List<Geometry> geo = new ArrayList<>();
         int remainedBytes = wacDataLength;
         while (remainedBytes > 0) {
@@ -220,8 +237,7 @@
 
             switch (type) {
                 case CbGeoUtils.GEO_FENCING_MAXIMUM_WAIT_TIME:
-                    // TODO: handle the maximum wait time in cell broadcast provider.
-                    int maximumWaitTimeSec = bitReader.read(8);
+                    maximumWaitTimeSec = bitReader.read(8);
                     break;
                 case CbGeoUtils.GEOMETRY_TYPE_POLYGON:
                     List<LatLng> latLngs = new ArrayList<>();
@@ -247,7 +263,7 @@
                     throw new IllegalArgumentException("Unsupported geoType = " + type);
             }
         }
-        return geo;
+        return new Pair(maximumWaitTimeSec, geo);
     }
 
     /**