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
Merged-In: If3d8d7915f2d86da20c63e99bee01f30e3ea89c0
Change-Id: If3d8d7915f2d86da20c63e99bee01f30e3ea89c0
(cherry picked from commit 02d6ac0f20)
This commit is contained in:
@@ -3890,6 +3890,13 @@ public final class Telephony {
|
|||||||
@NonNull
|
@NonNull
|
||||||
public static final Uri CONTENT_URI = Uri.parse("content://cellbroadcasts");
|
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:
|
* Message geographical scope. Valid values are:
|
||||||
* <ul>
|
* <ul>
|
||||||
@@ -4111,6 +4118,18 @@ public final class Telephony {
|
|||||||
*/
|
*/
|
||||||
public static final String GEOMETRIES = "geometries";
|
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.
|
* Query columns for instantiating {@link android.telephony.CellBroadcastMessage} objects.
|
||||||
* @hide
|
* @hide
|
||||||
@@ -4164,7 +4183,8 @@ public final class Telephony {
|
|||||||
CMAS_CERTAINTY,
|
CMAS_CERTAINTY,
|
||||||
RECEIVED_TIME,
|
RECEIVED_TIME,
|
||||||
MESSAGE_BROADCASTED,
|
MESSAGE_BROADCASTED,
|
||||||
GEOMETRIES
|
GEOMETRIES,
|
||||||
|
MAXIMUM_WAIT_TIME
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -139,6 +139,12 @@ public final class SmsCbMessage implements Parcelable {
|
|||||||
@Retention(RetentionPolicy.SOURCE)
|
@Retention(RetentionPolicy.SOURCE)
|
||||||
public @interface MessagePriority {}
|
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). */
|
/** Format of this message (for interpretation of service category values). */
|
||||||
private final int mMessageFormat;
|
private final int mMessageFormat;
|
||||||
|
|
||||||
@@ -187,6 +193,14 @@ public final class SmsCbMessage implements Parcelable {
|
|||||||
@Nullable
|
@Nullable
|
||||||
private final SmsCbCmasInfo mCmasWarningInfo;
|
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. */
|
/** UNIX timestamp of when the message was received. */
|
||||||
private final long mReceivedTimeMillis;
|
private final long mReceivedTimeMillis;
|
||||||
|
|
||||||
@@ -202,8 +216,8 @@ public final class SmsCbMessage implements Parcelable {
|
|||||||
@Nullable SmsCbCmasInfo cmasWarningInfo) {
|
@Nullable SmsCbCmasInfo cmasWarningInfo) {
|
||||||
|
|
||||||
this(messageFormat, geographicalScope, serialNumber, location, serviceCategory, language,
|
this(messageFormat, geographicalScope, serialNumber, location, serviceCategory, language,
|
||||||
body, priority, etwsWarningInfo, cmasWarningInfo, null /* geometries */,
|
body, priority, etwsWarningInfo, cmasWarningInfo, 0 /* maximumWaitingTime */,
|
||||||
System.currentTimeMillis());
|
null /* geometries */, System.currentTimeMillis());
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -213,7 +227,7 @@ public final class SmsCbMessage implements Parcelable {
|
|||||||
public SmsCbMessage(int messageFormat, int geographicalScope, int serialNumber,
|
public SmsCbMessage(int messageFormat, int geographicalScope, int serialNumber,
|
||||||
SmsCbLocation location, int serviceCategory, String language, String body,
|
SmsCbLocation location, int serviceCategory, String language, String body,
|
||||||
int priority, SmsCbEtwsInfo etwsWarningInfo, SmsCbCmasInfo cmasWarningInfo,
|
int priority, SmsCbEtwsInfo etwsWarningInfo, SmsCbCmasInfo cmasWarningInfo,
|
||||||
List<Geometry> geometries, long receivedTimeMillis) {
|
int maximumWaitTimeSec, List<Geometry> geometries, long receivedTimeMillis) {
|
||||||
mMessageFormat = messageFormat;
|
mMessageFormat = messageFormat;
|
||||||
mGeographicalScope = geographicalScope;
|
mGeographicalScope = geographicalScope;
|
||||||
mSerialNumber = serialNumber;
|
mSerialNumber = serialNumber;
|
||||||
@@ -226,6 +240,7 @@ public final class SmsCbMessage implements Parcelable {
|
|||||||
mCmasWarningInfo = cmasWarningInfo;
|
mCmasWarningInfo = cmasWarningInfo;
|
||||||
mReceivedTimeMillis = receivedTimeMillis;
|
mReceivedTimeMillis = receivedTimeMillis;
|
||||||
mGeometries = geometries;
|
mGeometries = geometries;
|
||||||
|
mMaximumWaitTimeSec = maximumWaitTimeSec;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -262,6 +277,7 @@ public final class SmsCbMessage implements Parcelable {
|
|||||||
mReceivedTimeMillis = in.readLong();
|
mReceivedTimeMillis = in.readLong();
|
||||||
String geoStr = in.readString();
|
String geoStr = in.readString();
|
||||||
mGeometries = geoStr != null ? CbGeoUtils.parseGeometriesFromString(geoStr) : null;
|
mGeometries = geoStr != null ? CbGeoUtils.parseGeometriesFromString(geoStr) : null;
|
||||||
|
mMaximumWaitTimeSec = in.readInt();
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -295,6 +311,7 @@ public final class SmsCbMessage implements Parcelable {
|
|||||||
dest.writeLong(mReceivedTimeMillis);
|
dest.writeLong(mReceivedTimeMillis);
|
||||||
dest.writeString(
|
dest.writeString(
|
||||||
mGeometries != null ? CbGeoUtils.encodeGeometriesToString(mGeometries) : null);
|
mGeometries != null ? CbGeoUtils.encodeGeometriesToString(mGeometries) : null);
|
||||||
|
dest.writeInt(mMaximumWaitTimeSec);
|
||||||
}
|
}
|
||||||
|
|
||||||
@NonNull
|
@NonNull
|
||||||
@@ -388,6 +405,15 @@ public final class SmsCbMessage implements Parcelable {
|
|||||||
return mGeometries;
|
return mGeometries;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 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.
|
* Get the time when this message was received.
|
||||||
* @return the time in millisecond
|
* @return the time in millisecond
|
||||||
@@ -475,6 +501,7 @@ public final class SmsCbMessage implements Parcelable {
|
|||||||
+ ", priority=" + mPriority
|
+ ", priority=" + mPriority
|
||||||
+ (mEtwsWarningInfo != null ? (", " + mEtwsWarningInfo.toString()) : "")
|
+ (mEtwsWarningInfo != null ? (", " + mEtwsWarningInfo.toString()) : "")
|
||||||
+ (mCmasWarningInfo != null ? (", " + mCmasWarningInfo.toString()) : "")
|
+ (mCmasWarningInfo != null ? (", " + mCmasWarningInfo.toString()) : "")
|
||||||
|
+ ", maximumWaitingTime = " + mMaximumWaitTimeSec
|
||||||
+ ", geo=" + (mGeometries != null
|
+ ", geo=" + (mGeometries != null
|
||||||
? CbGeoUtils.encodeGeometriesToString(mGeometries) : "null")
|
? CbGeoUtils.encodeGeometriesToString(mGeometries) : "null")
|
||||||
+ '}';
|
+ '}';
|
||||||
@@ -535,6 +562,8 @@ public final class SmsCbMessage implements Parcelable {
|
|||||||
cv.put(CellBroadcasts.GEOMETRIES, (String) null);
|
cv.put(CellBroadcasts.GEOMETRIES, (String) null);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
cv.put(CellBroadcasts.MAXIMUM_WAIT_TIME, mMaximumWaitTimeSec);
|
||||||
|
|
||||||
return cv;
|
return cv;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -644,17 +673,21 @@ public final class SmsCbMessage implements Parcelable {
|
|||||||
List<Geometry> geometries =
|
List<Geometry> geometries =
|
||||||
geoStr != null ? CbGeoUtils.parseGeometriesFromString(geoStr) : null;
|
geoStr != null ? CbGeoUtils.parseGeometriesFromString(geoStr) : null;
|
||||||
|
|
||||||
long receivedTimeSec = cursor.getLong(
|
long receivedTimeMillis = cursor.getLong(
|
||||||
cursor.getColumnIndexOrThrow(CellBroadcasts.RECEIVED_TIME));
|
cursor.getColumnIndexOrThrow(CellBroadcasts.RECEIVED_TIME));
|
||||||
|
|
||||||
|
int maximumWaitTimeSec = cursor.getInt(
|
||||||
|
cursor.getColumnIndexOrThrow(CellBroadcasts.MAXIMUM_WAIT_TIME));
|
||||||
|
|
||||||
return new SmsCbMessage(format, geoScope, serialNum, location, category,
|
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.
|
* @return {@code True} if this message needs geo-fencing check.
|
||||||
*/
|
*/
|
||||||
public boolean needGeoFencingCheck() {
|
public boolean needGeoFencingCheck() {
|
||||||
return mGeometries != null;
|
return mMaximumWaitTimeSec > 0 && mGeometries != null;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -299,7 +299,8 @@ public class CbGeoUtils {
|
|||||||
* @return the encoded string.
|
* @return the encoded string.
|
||||||
*/
|
*/
|
||||||
@NonNull
|
@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()
|
return geometries.stream()
|
||||||
.map(geometry -> encodeGeometryToString(geometry))
|
.map(geometry -> encodeGeometryToString(geometry))
|
||||||
.filter(encodedStr -> !TextUtils.isEmpty(encodedStr))
|
.filter(encodedStr -> !TextUtils.isEmpty(encodedStr))
|
||||||
|
|||||||
@@ -104,7 +104,7 @@ public class GsmSmsCbMessage {
|
|||||||
header.getSerialNumber(), location, header.getServiceCategory(), null,
|
header.getSerialNumber(), location, header.getServiceCategory(), null,
|
||||||
getEtwsPrimaryMessage(context, header.getEtwsInfo().getWarningType()),
|
getEtwsPrimaryMessage(context, header.getEtwsInfo().getWarningType()),
|
||||||
SmsCbMessage.MESSAGE_PRIORITY_EMERGENCY, header.getEtwsInfo(),
|
SmsCbMessage.MESSAGE_PRIORITY_EMERGENCY, header.getEtwsInfo(),
|
||||||
header.getCmasInfo(), null /* geometries */, receivedTimeMillis);
|
header.getCmasInfo(), 0, null /* geometries */, receivedTimeMillis);
|
||||||
} else if (header.isUmtsFormat()) {
|
} else if (header.isUmtsFormat()) {
|
||||||
// UMTS format has only 1 PDU
|
// UMTS format has only 1 PDU
|
||||||
byte[] pdu = pdus[0];
|
byte[] pdu = pdus[0];
|
||||||
@@ -120,9 +120,13 @@ public class GsmSmsCbMessage {
|
|||||||
|
|
||||||
// Has Warning Area Coordinates information
|
// Has Warning Area Coordinates information
|
||||||
List<Geometry> geometries = null;
|
List<Geometry> geometries = null;
|
||||||
|
int maximumWaitingTimeSec = 255;
|
||||||
if (pdu.length > wacDataOffset) {
|
if (pdu.length > wacDataOffset) {
|
||||||
try {
|
try {
|
||||||
geometries = parseWarningAreaCoordinates(pdu, wacDataOffset);
|
Pair<Integer, List<Geometry>> wac = parseWarningAreaCoordinates(pdu,
|
||||||
|
wacDataOffset);
|
||||||
|
maximumWaitingTimeSec = wac.first;
|
||||||
|
geometries = wac.second;
|
||||||
} catch (Exception ex) {
|
} catch (Exception ex) {
|
||||||
// Catch the exception here, the message will be considered as having no WAC
|
// Catch the exception here, the message will be considered as having no WAC
|
||||||
// information which means the message will be broadcasted directly.
|
// information which means the message will be broadcasted directly.
|
||||||
@@ -133,7 +137,8 @@ public class GsmSmsCbMessage {
|
|||||||
return new SmsCbMessage(SmsCbMessage.MESSAGE_FORMAT_3GPP,
|
return new SmsCbMessage(SmsCbMessage.MESSAGE_FORMAT_3GPP,
|
||||||
header.getGeographicalScope(), header.getSerialNumber(), location,
|
header.getGeographicalScope(), header.getSerialNumber(), location,
|
||||||
header.getServiceCategory(), language, body, priority,
|
header.getServiceCategory(), language, body, priority,
|
||||||
header.getEtwsInfo(), header.getCmasInfo(), geometries, receivedTimeMillis);
|
header.getEtwsInfo(), header.getCmasInfo(), maximumWaitingTimeSec, geometries,
|
||||||
|
receivedTimeMillis);
|
||||||
} else {
|
} else {
|
||||||
String language = null;
|
String language = null;
|
||||||
StringBuilder sb = new StringBuilder();
|
StringBuilder sb = new StringBuilder();
|
||||||
@@ -148,7 +153,7 @@ public class GsmSmsCbMessage {
|
|||||||
return new SmsCbMessage(SmsCbMessage.MESSAGE_FORMAT_3GPP,
|
return new SmsCbMessage(SmsCbMessage.MESSAGE_FORMAT_3GPP,
|
||||||
header.getGeographicalScope(), header.getSerialNumber(), location,
|
header.getGeographicalScope(), header.getSerialNumber(), location,
|
||||||
header.getServiceCategory(), language, sb.toString(), priority,
|
header.getServiceCategory(), language, sb.toString(), priority,
|
||||||
header.getEtwsInfo(), header.getCmasInfo(), null /* geometries */,
|
header.getEtwsInfo(), header.getCmasInfo(), 0, null /* geometries */,
|
||||||
receivedTimeMillis);
|
receivedTimeMillis);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -197,7 +202,17 @@ public class GsmSmsCbMessage {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
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
|
// little-endian
|
||||||
int wacDataLength = (pdu[wacOffset + 1] << 8) | pdu[wacOffset];
|
int wacDataLength = (pdu[wacOffset + 1] << 8) | pdu[wacOffset];
|
||||||
int offset = wacOffset + 2;
|
int offset = wacOffset + 2;
|
||||||
@@ -209,6 +224,8 @@ public class GsmSmsCbMessage {
|
|||||||
|
|
||||||
BitStreamReader bitReader = new BitStreamReader(pdu, offset);
|
BitStreamReader bitReader = new BitStreamReader(pdu, offset);
|
||||||
|
|
||||||
|
int maximumWaitTimeSec = SmsCbMessage.MAXIMUM_WAIT_TIME_NOT_SET;
|
||||||
|
|
||||||
List<Geometry> geo = new ArrayList<>();
|
List<Geometry> geo = new ArrayList<>();
|
||||||
int remainedBytes = wacDataLength;
|
int remainedBytes = wacDataLength;
|
||||||
while (remainedBytes > 0) {
|
while (remainedBytes > 0) {
|
||||||
@@ -220,8 +237,7 @@ public class GsmSmsCbMessage {
|
|||||||
|
|
||||||
switch (type) {
|
switch (type) {
|
||||||
case CbGeoUtils.GEO_FENCING_MAXIMUM_WAIT_TIME:
|
case CbGeoUtils.GEO_FENCING_MAXIMUM_WAIT_TIME:
|
||||||
// TODO: handle the maximum wait time in cell broadcast provider.
|
maximumWaitTimeSec = bitReader.read(8);
|
||||||
int maximumWaitTimeSec = bitReader.read(8);
|
|
||||||
break;
|
break;
|
||||||
case CbGeoUtils.GEOMETRY_TYPE_POLYGON:
|
case CbGeoUtils.GEOMETRY_TYPE_POLYGON:
|
||||||
List<LatLng> latLngs = new ArrayList<>();
|
List<LatLng> latLngs = new ArrayList<>();
|
||||||
@@ -247,7 +263,7 @@ public class GsmSmsCbMessage {
|
|||||||
throw new IllegalArgumentException("Unsupported geoType = " + type);
|
throw new IllegalArgumentException("Unsupported geoType = " + type);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return geo;
|
return new Pair(maximumWaitTimeSec, geo);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
Reference in New Issue
Block a user