Support maximum wait time for Cell broadcast
Geo-Fencing Maximum Wait Time a device shall allow to determines it
location 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.
Bug: 139022202
Test: manual
Change-Id: If3d8d7915f2d86da20c63e99bee01f30e3ea89c0
diff --git a/telephony/java/android/provider/Telephony.java b/telephony/java/android/provider/Telephony.java
index c1b8479..67b252e 100644
--- a/telephony/java/android/provider/Telephony.java
+++ b/telephony/java/android/provider/Telephony.java
@@ -3962,6 +3962,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
@@ -4183,6 +4190,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
*/
@@ -4235,7 +4254,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/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);
}
/**