blob: d366efe0d9796a1f2b9d04f51faf5de1d99aa5d2 [file] [log] [blame]
Dan Willemsen4980bf42017-02-14 14:17:12 -08001/*
2 * Copyright (C) 2010 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17package android.telephony;
18
Jordan Liu657ef5a2019-08-16 14:07:03 -070019import android.annotation.IntDef;
20import android.annotation.NonNull;
Pengquan Menge3f37272019-08-12 23:09:34 -070021import android.annotation.Nullable;
Jordan Liu657ef5a2019-08-16 14:07:03 -070022import android.annotation.SystemApi;
Pengquan Menge3f37272019-08-12 23:09:34 -070023import android.content.ContentValues;
24import android.database.Cursor;
Dan Willemsen4980bf42017-02-14 14:17:12 -080025import android.os.Parcel;
26import android.os.Parcelable;
Pengquan Menge3f37272019-08-12 23:09:34 -070027import android.provider.Telephony.CellBroadcasts;
Jordan Liua8ec03e2019-10-21 12:31:59 -070028import android.telephony.CbGeoUtils.Geometry;
Pengquan Menge3f37272019-08-12 23:09:34 -070029
Jordan Liu657ef5a2019-08-16 14:07:03 -070030import java.lang.annotation.Retention;
31import java.lang.annotation.RetentionPolicy;
Jordan Liu15a72742019-11-20 13:55:18 -080032import java.util.ArrayList;
Pengquan Menge3f37272019-08-12 23:09:34 -070033import java.util.List;
Dan Willemsen4980bf42017-02-14 14:17:12 -080034
35/**
36 * Parcelable object containing a received cell broadcast message. There are four different types
37 * of Cell Broadcast messages:
38 *
39 * <ul>
40 * <li>opt-in informational broadcasts, e.g. news, weather, stock quotes, sports scores</li>
41 * <li>cell information messages, broadcast on channel 50, indicating the current cell name for
42 * roaming purposes (required to display on the idle screen in Brazil)</li>
43 * <li>emergency broadcasts for the Japanese Earthquake and Tsunami Warning System (ETWS)</li>
44 * <li>emergency broadcasts for the American Commercial Mobile Alert Service (CMAS)</li>
45 * </ul>
46 *
47 * <p>There are also four different CB message formats: GSM, ETWS Primary Notification (GSM only),
48 * UMTS, and CDMA. Some fields are only applicable for some message formats. Other fields were
49 * unified under a common name, avoiding some names, such as "Message Identifier", that refer to
50 * two completely different concepts in 3GPP and CDMA.
51 *
52 * <p>The GSM/UMTS Message Identifier field is available via {@link #getServiceCategory}, the name
53 * of the equivalent field in CDMA. In both cases the service category is a 16-bit value, but 3GPP
54 * and 3GPP2 have completely different meanings for the respective values. For ETWS and CMAS, the
55 * application should
56 *
57 * <p>The CDMA Message Identifier field is available via {@link #getSerialNumber}, which is used
58 * to detect the receipt of a duplicate message to be discarded. In CDMA, the message ID is
59 * unique to the current PLMN. In GSM/UMTS, there is a 16-bit serial number containing a 2-bit
60 * Geographical Scope field which indicates whether the 10-bit message code and 4-bit update number
61 * are considered unique to the PLMN, to the current cell, or to the current Location Area (or
62 * Service Area in UMTS). The relevant values are concatenated into a single String which will be
63 * unique if the messages are not duplicates.
64 *
65 * <p>The SMS dispatcher does not detect duplicate messages. However, it does concatenate the
66 * pages of a GSM multi-page cell broadcast into a single SmsCbMessage object.
67 *
68 * <p>Interested applications with {@code RECEIVE_SMS_PERMISSION} can register to receive
69 * {@code SMS_CB_RECEIVED_ACTION} broadcast intents for incoming non-emergency broadcasts.
70 * Only system applications such as the CellBroadcastReceiver may receive notifications for
71 * emergency broadcasts (ETWS and CMAS). This is intended to prevent any potential for delays or
72 * interference with the immediate display of the alert message and playing of the alert sound and
73 * vibration pattern, which could be caused by poorly written or malicious non-system code.
74 *
75 * @hide
76 */
Jordan Liu657ef5a2019-08-16 14:07:03 -070077@SystemApi
78public final class SmsCbMessage implements Parcelable {
Dan Willemsen4980bf42017-02-14 14:17:12 -080079
Jordan Liu657ef5a2019-08-16 14:07:03 -070080 /** @hide */
81 public static final String LOG_TAG = "SMSCB";
Dan Willemsen4980bf42017-02-14 14:17:12 -080082
83 /** Cell wide geographical scope with immediate display (GSM/UMTS only). */
84 public static final int GEOGRAPHICAL_SCOPE_CELL_WIDE_IMMEDIATE = 0;
85
86 /** PLMN wide geographical scope (GSM/UMTS and all CDMA broadcasts). */
87 public static final int GEOGRAPHICAL_SCOPE_PLMN_WIDE = 1;
88
89 /** Location / service area wide geographical scope (GSM/UMTS only). */
Jordan Liu657ef5a2019-08-16 14:07:03 -070090 public static final int GEOGRAPHICAL_SCOPE_LOCATION_AREA_WIDE = 2;
Dan Willemsen4980bf42017-02-14 14:17:12 -080091
92 /** Cell wide geographical scope (GSM/UMTS only). */
93 public static final int GEOGRAPHICAL_SCOPE_CELL_WIDE = 3;
94
Jordan Liu657ef5a2019-08-16 14:07:03 -070095 /** @hide */
96 @IntDef(prefix = { "GEOGRAPHICAL_SCOPE_" }, value = {
97 GEOGRAPHICAL_SCOPE_CELL_WIDE_IMMEDIATE,
98 GEOGRAPHICAL_SCOPE_PLMN_WIDE,
99 GEOGRAPHICAL_SCOPE_LOCATION_AREA_WIDE,
100 GEOGRAPHICAL_SCOPE_CELL_WIDE,
101 })
102 @Retention(RetentionPolicy.SOURCE)
103 public @interface GeographicalScope {}
104
Dan Willemsen4980bf42017-02-14 14:17:12 -0800105 /** GSM or UMTS format cell broadcast. */
106 public static final int MESSAGE_FORMAT_3GPP = 1;
107
108 /** CDMA format cell broadcast. */
109 public static final int MESSAGE_FORMAT_3GPP2 = 2;
110
Jordan Liu657ef5a2019-08-16 14:07:03 -0700111 /** @hide */
112 @IntDef(prefix = { "MESSAGE_FORMAT_" }, value = {
113 MESSAGE_FORMAT_3GPP,
114 MESSAGE_FORMAT_3GPP2
115 })
116 @Retention(RetentionPolicy.SOURCE)
117 public @interface MessageFormat {}
118
Dan Willemsen4980bf42017-02-14 14:17:12 -0800119 /** Normal message priority. */
120 public static final int MESSAGE_PRIORITY_NORMAL = 0;
121
122 /** Interactive message priority. */
123 public static final int MESSAGE_PRIORITY_INTERACTIVE = 1;
124
125 /** Urgent message priority. */
126 public static final int MESSAGE_PRIORITY_URGENT = 2;
127
128 /** Emergency message priority. */
129 public static final int MESSAGE_PRIORITY_EMERGENCY = 3;
130
Jordan Liu657ef5a2019-08-16 14:07:03 -0700131 /** @hide */
132 @IntDef(prefix = { "MESSAGE_PRIORITY_" }, value = {
133 MESSAGE_PRIORITY_NORMAL,
134 MESSAGE_PRIORITY_INTERACTIVE,
135 MESSAGE_PRIORITY_URGENT,
136 MESSAGE_PRIORITY_EMERGENCY,
137 })
138 @Retention(RetentionPolicy.SOURCE)
139 public @interface MessagePriority {}
140
Pengquan Meng02d6ac02019-08-27 11:20:17 -0700141 /**
Jordan Liu0d76fbd2019-11-06 12:48:51 -0800142 * Integer indicating that the maximum wait time is not set.
143 * Based on ATIS-0700041 Section 5.2.8 WAC Geo-Fencing Maximum Wait Time Table 12.
Pengquan Meng02d6ac02019-08-27 11:20:17 -0700144 */
145 public static final int MAXIMUM_WAIT_TIME_NOT_SET = 255;
146
Dan Willemsen4980bf42017-02-14 14:17:12 -0800147 /** Format of this message (for interpretation of service category values). */
148 private final int mMessageFormat;
149
150 /** Geographical scope of broadcast. */
151 private final int mGeographicalScope;
152
153 /**
154 * Serial number of broadcast (message identifier for CDMA, geographical scope + message code +
155 * update number for GSM/UMTS). The serial number plus the location code uniquely identify
156 * a cell broadcast for duplicate detection.
157 */
158 private final int mSerialNumber;
159
160 /**
161 * Location identifier for this message. It consists of the current operator MCC/MNC as a
162 * 5 or 6-digit decimal string. In addition, for GSM/UMTS, if the Geographical Scope of the
163 * message is not binary 01, the Location Area is included for comparison. If the GS is
164 * 00 or 11, the Cell ID is also included. LAC and Cell ID are -1 if not specified.
165 */
Jordan Liu657ef5a2019-08-16 14:07:03 -0700166 @NonNull
Dan Willemsen4980bf42017-02-14 14:17:12 -0800167 private final SmsCbLocation mLocation;
168
169 /**
170 * 16-bit CDMA service category or GSM/UMTS message identifier. For ETWS and CMAS warnings,
171 * the information provided by the category is also available via {@link #getEtwsWarningInfo()}
172 * or {@link #getCmasWarningInfo()}.
173 */
174 private final int mServiceCategory;
175
176 /** Message language, as a two-character string, e.g. "en". */
Jordan Liu657ef5a2019-08-16 14:07:03 -0700177 @Nullable
Dan Willemsen4980bf42017-02-14 14:17:12 -0800178 private final String mLanguage;
179
Jack Yu641db9a2020-01-24 13:24:41 -0800180 /** The 8-bit data coding scheme defined in 3GPP TS 23.038 section 4. */
181 private final int mDataCodingScheme;
182
Dan Willemsen4980bf42017-02-14 14:17:12 -0800183 /** Message body, as a String. */
Jordan Liu657ef5a2019-08-16 14:07:03 -0700184 @Nullable
Dan Willemsen4980bf42017-02-14 14:17:12 -0800185 private final String mBody;
186
187 /** Message priority (including emergency priority). */
188 private final int mPriority;
189
190 /** ETWS warning notification information (ETWS warnings only). */
Jordan Liu657ef5a2019-08-16 14:07:03 -0700191 @Nullable
Dan Willemsen4980bf42017-02-14 14:17:12 -0800192 private final SmsCbEtwsInfo mEtwsWarningInfo;
193
194 /** CMAS warning notification information (CMAS warnings only). */
Jordan Liu657ef5a2019-08-16 14:07:03 -0700195 @Nullable
Dan Willemsen4980bf42017-02-14 14:17:12 -0800196 private final SmsCbCmasInfo mCmasWarningInfo;
197
Pengquan Meng02d6ac02019-08-27 11:20:17 -0700198 /**
199 * Geo-Fencing Maximum Wait Time in second, a device shall allow to determine its position
200 * meeting operator policy. If the device is unable to determine its position meeting operator
201 * policy within the GeoFencing Maximum Wait Time, it shall present the alert to the user and
202 * discontinue further positioning determination for the alert.
203 */
204 private final int mMaximumWaitTimeSec;
205
Pengquan Menge3f37272019-08-12 23:09:34 -0700206 /** UNIX timestamp of when the message was received. */
207 private final long mReceivedTimeMillis;
208
209 /** CMAS warning area coordinates. */
210 private final List<Geometry> mGeometries;
211
Jack Yu750b8b12019-11-20 23:18:29 -0800212 private final int mSlotIndex;
213
214 private final int mSubId;
Chen Xu515285b2019-10-03 16:48:56 -0700215
Dan Willemsen4980bf42017-02-14 14:17:12 -0800216 /**
217 * Create a new SmsCbMessage with the specified data.
Jordan Liu0d76fbd2019-11-06 12:48:51 -0800218 * @hide
Dan Willemsen4980bf42017-02-14 14:17:12 -0800219 */
220 public SmsCbMessage(int messageFormat, int geographicalScope, int serialNumber,
Jordan Liu657ef5a2019-08-16 14:07:03 -0700221 @NonNull SmsCbLocation location, int serviceCategory, @Nullable String language,
222 @Nullable String body, int priority, @Nullable SmsCbEtwsInfo etwsWarningInfo,
Jack Yu750b8b12019-11-20 23:18:29 -0800223 @Nullable SmsCbCmasInfo cmasWarningInfo, int slotIndex, int subId) {
Pengquan Menge3f37272019-08-12 23:09:34 -0700224
225 this(messageFormat, geographicalScope, serialNumber, location, serviceCategory, language,
Jack Yu641db9a2020-01-24 13:24:41 -0800226 0, body, priority, etwsWarningInfo, cmasWarningInfo, 0 /* maximumWaitingTime */,
Jack Yu750b8b12019-11-20 23:18:29 -0800227 null /* geometries */, System.currentTimeMillis(), slotIndex, subId);
Pengquan Menge3f37272019-08-12 23:09:34 -0700228 }
229
230 /**
Jordan Liu0d76fbd2019-11-06 12:48:51 -0800231 * Create a new {@link SmsCbMessage} with the specified data, including warning area
232 * coordinates information.
Pengquan Menge3f37272019-08-12 23:09:34 -0700233 */
234 public SmsCbMessage(int messageFormat, int geographicalScope, int serialNumber,
Jack Yu750b8b12019-11-20 23:18:29 -0800235 @NonNull SmsCbLocation location, int serviceCategory,
Jack Yu641db9a2020-01-24 13:24:41 -0800236 @Nullable String language, int dataCodingScheme, @Nullable String body,
237 int priority, @Nullable SmsCbEtwsInfo etwsWarningInfo,
Jack Yu750b8b12019-11-20 23:18:29 -0800238 @Nullable SmsCbCmasInfo cmasWarningInfo, int maximumWaitTimeSec,
239 @Nullable List<Geometry> geometries, long receivedTimeMillis, int slotIndex,
240 int subId) {
Dan Willemsen4980bf42017-02-14 14:17:12 -0800241 mMessageFormat = messageFormat;
242 mGeographicalScope = geographicalScope;
243 mSerialNumber = serialNumber;
244 mLocation = location;
245 mServiceCategory = serviceCategory;
246 mLanguage = language;
Jack Yu641db9a2020-01-24 13:24:41 -0800247 mDataCodingScheme = dataCodingScheme;
Dan Willemsen4980bf42017-02-14 14:17:12 -0800248 mBody = body;
249 mPriority = priority;
250 mEtwsWarningInfo = etwsWarningInfo;
251 mCmasWarningInfo = cmasWarningInfo;
Pengquan Menge3f37272019-08-12 23:09:34 -0700252 mReceivedTimeMillis = receivedTimeMillis;
253 mGeometries = geometries;
Pengquan Meng02d6ac02019-08-27 11:20:17 -0700254 mMaximumWaitTimeSec = maximumWaitTimeSec;
Chen Xu515285b2019-10-03 16:48:56 -0700255 mSlotIndex = slotIndex;
Jack Yu750b8b12019-11-20 23:18:29 -0800256 mSubId = subId;
Dan Willemsen4980bf42017-02-14 14:17:12 -0800257 }
258
Jordan Liu657ef5a2019-08-16 14:07:03 -0700259 /**
260 * Create a new SmsCbMessage object from a Parcel.
261 * @hide
262 */
263 public SmsCbMessage(@NonNull Parcel in) {
Dan Willemsen4980bf42017-02-14 14:17:12 -0800264 mMessageFormat = in.readInt();
265 mGeographicalScope = in.readInt();
266 mSerialNumber = in.readInt();
267 mLocation = new SmsCbLocation(in);
268 mServiceCategory = in.readInt();
269 mLanguage = in.readString();
Jack Yu641db9a2020-01-24 13:24:41 -0800270 mDataCodingScheme = in.readInt();
Dan Willemsen4980bf42017-02-14 14:17:12 -0800271 mBody = in.readString();
272 mPriority = in.readInt();
273 int type = in.readInt();
274 switch (type) {
275 case 'E':
276 // unparcel ETWS warning information
277 mEtwsWarningInfo = new SmsCbEtwsInfo(in);
278 mCmasWarningInfo = null;
279 break;
280
281 case 'C':
282 // unparcel CMAS warning information
283 mEtwsWarningInfo = null;
284 mCmasWarningInfo = new SmsCbCmasInfo(in);
285 break;
286
287 default:
288 mEtwsWarningInfo = null;
289 mCmasWarningInfo = null;
290 }
Pengquan Menge3f37272019-08-12 23:09:34 -0700291 mReceivedTimeMillis = in.readLong();
292 String geoStr = in.readString();
293 mGeometries = geoStr != null ? CbGeoUtils.parseGeometriesFromString(geoStr) : null;
Pengquan Meng02d6ac02019-08-27 11:20:17 -0700294 mMaximumWaitTimeSec = in.readInt();
Chen Xu515285b2019-10-03 16:48:56 -0700295 mSlotIndex = in.readInt();
Jack Yu750b8b12019-11-20 23:18:29 -0800296 mSubId = in.readInt();
Dan Willemsen4980bf42017-02-14 14:17:12 -0800297 }
298
299 /**
300 * Flatten this object into a Parcel.
301 *
302 * @param dest The Parcel in which the object should be written.
303 * @param flags Additional flags about how the object should be written (ignored).
304 */
305 @Override
306 public void writeToParcel(Parcel dest, int flags) {
307 dest.writeInt(mMessageFormat);
308 dest.writeInt(mGeographicalScope);
309 dest.writeInt(mSerialNumber);
310 mLocation.writeToParcel(dest, flags);
311 dest.writeInt(mServiceCategory);
312 dest.writeString(mLanguage);
Jack Yu641db9a2020-01-24 13:24:41 -0800313 dest.writeInt(mDataCodingScheme);
Dan Willemsen4980bf42017-02-14 14:17:12 -0800314 dest.writeString(mBody);
315 dest.writeInt(mPriority);
316 if (mEtwsWarningInfo != null) {
317 // parcel ETWS warning information
318 dest.writeInt('E');
319 mEtwsWarningInfo.writeToParcel(dest, flags);
320 } else if (mCmasWarningInfo != null) {
321 // parcel CMAS warning information
322 dest.writeInt('C');
323 mCmasWarningInfo.writeToParcel(dest, flags);
324 } else {
325 // no ETWS or CMAS warning information
326 dest.writeInt('0');
327 }
Pengquan Menge3f37272019-08-12 23:09:34 -0700328 dest.writeLong(mReceivedTimeMillis);
329 dest.writeString(
330 mGeometries != null ? CbGeoUtils.encodeGeometriesToString(mGeometries) : null);
Pengquan Meng02d6ac02019-08-27 11:20:17 -0700331 dest.writeInt(mMaximumWaitTimeSec);
Chen Xu515285b2019-10-03 16:48:56 -0700332 dest.writeInt(mSlotIndex);
Jack Yu750b8b12019-11-20 23:18:29 -0800333 dest.writeInt(mSubId);
Dan Willemsen4980bf42017-02-14 14:17:12 -0800334 }
335
Jordan Liu657ef5a2019-08-16 14:07:03 -0700336 @NonNull
337 public static final Parcelable.Creator<SmsCbMessage> CREATOR =
338 new Parcelable.Creator<SmsCbMessage>() {
Dan Willemsen4980bf42017-02-14 14:17:12 -0800339 @Override
340 public SmsCbMessage createFromParcel(Parcel in) {
341 return new SmsCbMessage(in);
342 }
343
344 @Override
345 public SmsCbMessage[] newArray(int size) {
346 return new SmsCbMessage[size];
347 }
348 };
349
350 /**
351 * Return the geographical scope of this message (GSM/UMTS only).
352 *
353 * @return Geographical scope
354 */
Jordan Liu657ef5a2019-08-16 14:07:03 -0700355 public @GeographicalScope int getGeographicalScope() {
Dan Willemsen4980bf42017-02-14 14:17:12 -0800356 return mGeographicalScope;
357 }
358
359 /**
360 * Return the broadcast serial number of broadcast (message identifier for CDMA, or
361 * geographical scope + message code + update number for GSM/UMTS). The serial number plus
362 * the location code uniquely identify a cell broadcast for duplicate detection.
363 *
364 * @return the 16-bit CDMA message identifier or GSM/UMTS serial number
365 */
366 public int getSerialNumber() {
367 return mSerialNumber;
368 }
369
370 /**
371 * Return the location identifier for this message, consisting of the MCC/MNC as a
372 * 5 or 6-digit decimal string. In addition, for GSM/UMTS, if the Geographical Scope of the
373 * message is not binary 01, the Location Area is included. If the GS is 00 or 11, the
374 * cell ID is also included. The {@link SmsCbLocation} object includes a method to test
375 * if the location is included within another location area or within a PLMN and CellLocation.
376 *
377 * @return the geographical location code for duplicate message detection
378 */
Jordan Liu657ef5a2019-08-16 14:07:03 -0700379 @NonNull
380 public android.telephony.SmsCbLocation getLocation() {
Dan Willemsen4980bf42017-02-14 14:17:12 -0800381 return mLocation;
382 }
383
384 /**
385 * Return the 16-bit CDMA service category or GSM/UMTS message identifier. The interpretation
386 * of the category is radio technology specific. For ETWS and CMAS warnings, the information
387 * provided by the category is available via {@link #getEtwsWarningInfo()} or
388 * {@link #getCmasWarningInfo()} in a radio technology independent format.
389 *
390 * @return the radio technology specific service category
391 */
392 public int getServiceCategory() {
393 return mServiceCategory;
394 }
395
396 /**
397 * Get the ISO-639-1 language code for this message, or null if unspecified
398 *
399 * @return Language code
400 */
Jordan Liu657ef5a2019-08-16 14:07:03 -0700401 @Nullable
Dan Willemsen4980bf42017-02-14 14:17:12 -0800402 public String getLanguageCode() {
403 return mLanguage;
404 }
405
406 /**
Jack Yu641db9a2020-01-24 13:24:41 -0800407 * Get data coding scheme of the message
408 *
409 * @return The 8-bit data coding scheme defined in 3GPP TS 23.038 section 4.
410 */
411 public int getDataCodingScheme() {
412 return mDataCodingScheme;
413 }
414
415 /**
Dan Willemsen4980bf42017-02-14 14:17:12 -0800416 * Get the body of this message, or null if no body available
417 *
418 * @return Body, or null
419 */
Jordan Liu657ef5a2019-08-16 14:07:03 -0700420 @Nullable
Dan Willemsen4980bf42017-02-14 14:17:12 -0800421 public String getMessageBody() {
422 return mBody;
423 }
424
425 /**
Jordan Liu15a72742019-11-20 13:55:18 -0800426 * Get the warning area coordinates information represented by polygons and circles.
427 * @return a list of geometries, or an empty list if there is no coordinate information
428 * associated with this message.
Jordan Liu657ef5a2019-08-16 14:07:03 -0700429 * @hide
Pengquan Menge3f37272019-08-12 23:09:34 -0700430 */
Jordan Liu15a72742019-11-20 13:55:18 -0800431 @SystemApi
432 @NonNull
Pengquan Menge3f37272019-08-12 23:09:34 -0700433 public List<Geometry> getGeometries() {
Jordan Liu15a72742019-11-20 13:55:18 -0800434 if (mGeometries == null) {
435 return new ArrayList<>();
436 }
Pengquan Menge3f37272019-08-12 23:09:34 -0700437 return mGeometries;
438 }
439
440 /**
Pengquan Meng02d6ac02019-08-27 11:20:17 -0700441 * Get the Geo-Fencing Maximum Wait Time.
442 * @return the time in second.
Pengquan Meng02d6ac02019-08-27 11:20:17 -0700443 */
Jordan Liua8ec03e2019-10-21 12:31:59 -0700444 public int getMaximumWaitingDuration() {
Pengquan Meng02d6ac02019-08-27 11:20:17 -0700445 return mMaximumWaitTimeSec;
446 }
447
448 /**
Pengquan Menge3f37272019-08-12 23:09:34 -0700449 * Get the time when this message was received.
450 * @return the time in millisecond
451 */
452 public long getReceivedTime() {
453 return mReceivedTimeMillis;
454 }
455
456 /**
Jack Yu750b8b12019-11-20 23:18:29 -0800457 * Get the slot index associated with this message.
458 * @return the slot index associated with this message
Chen Xu515285b2019-10-03 16:48:56 -0700459 */
460 public int getSlotIndex() {
461 return mSlotIndex;
462 }
463
464 /**
Jack Yu750b8b12019-11-20 23:18:29 -0800465 * Get the subscription id associated with this message.
466 * @return the subscription id associated with this message
467 */
468 public int getSubscriptionId() {
469 return mSubId;
470 }
471
472 /**
Dan Willemsen4980bf42017-02-14 14:17:12 -0800473 * Get the message format ({@link #MESSAGE_FORMAT_3GPP} or {@link #MESSAGE_FORMAT_3GPP2}).
474 * @return an integer representing 3GPP or 3GPP2 message format
475 */
Jordan Liu657ef5a2019-08-16 14:07:03 -0700476 public @MessageFormat int getMessageFormat() {
Dan Willemsen4980bf42017-02-14 14:17:12 -0800477 return mMessageFormat;
478 }
479
480 /**
481 * Get the message priority. Normal broadcasts return {@link #MESSAGE_PRIORITY_NORMAL}
482 * and emergency broadcasts return {@link #MESSAGE_PRIORITY_EMERGENCY}. CDMA also may return
483 * {@link #MESSAGE_PRIORITY_INTERACTIVE} or {@link #MESSAGE_PRIORITY_URGENT}.
484 * @return an integer representing the message priority
485 */
Jordan Liu657ef5a2019-08-16 14:07:03 -0700486 public @MessagePriority int getMessagePriority() {
Dan Willemsen4980bf42017-02-14 14:17:12 -0800487 return mPriority;
488 }
489
490 /**
491 * If this is an ETWS warning notification then this method will return an object containing
492 * the ETWS warning type, the emergency user alert flag, and the popup flag. If this is an
493 * ETWS primary notification (GSM only), there will also be a 7-byte timestamp and 43-byte
494 * digital signature. As of Release 10, 3GPP TS 23.041 states that the UE shall ignore the
495 * ETWS primary notification timestamp and digital signature if received.
496 *
497 * @return an SmsCbEtwsInfo object, or null if this is not an ETWS warning notification
498 */
Jordan Liu657ef5a2019-08-16 14:07:03 -0700499 @Nullable
Dan Willemsen4980bf42017-02-14 14:17:12 -0800500 public SmsCbEtwsInfo getEtwsWarningInfo() {
501 return mEtwsWarningInfo;
502 }
503
504 /**
505 * If this is a CMAS warning notification then this method will return an object containing
506 * the CMAS message class, category, response type, severity, urgency and certainty.
507 * The message class is always present. Severity, urgency and certainty are present for CDMA
508 * warning notifications containing a type 1 elements record and for GSM and UMTS warnings
509 * except for the Presidential-level alert category. Category and response type are only
510 * available for CDMA notifications containing a type 1 elements record.
511 *
512 * @return an SmsCbCmasInfo object, or null if this is not a CMAS warning notification
513 */
Jordan Liu657ef5a2019-08-16 14:07:03 -0700514 @Nullable
Dan Willemsen4980bf42017-02-14 14:17:12 -0800515 public SmsCbCmasInfo getCmasWarningInfo() {
516 return mCmasWarningInfo;
517 }
518
519 /**
520 * Return whether this message is an emergency (PWS) message type.
Jordan Liu657ef5a2019-08-16 14:07:03 -0700521 * @return true if the message is an emergency notification; false otherwise
Dan Willemsen4980bf42017-02-14 14:17:12 -0800522 */
523 public boolean isEmergencyMessage() {
524 return mPriority == MESSAGE_PRIORITY_EMERGENCY;
525 }
526
527 /**
528 * Return whether this message is an ETWS warning alert.
529 * @return true if the message is an ETWS warning notification; false otherwise
530 */
531 public boolean isEtwsMessage() {
532 return mEtwsWarningInfo != null;
533 }
534
535 /**
536 * Return whether this message is a CMAS warning alert.
537 * @return true if the message is a CMAS warning notification; false otherwise
538 */
539 public boolean isCmasMessage() {
540 return mCmasWarningInfo != null;
541 }
542
543 @Override
544 public String toString() {
545 return "SmsCbMessage{geographicalScope=" + mGeographicalScope + ", serialNumber="
546 + mSerialNumber + ", location=" + mLocation + ", serviceCategory="
547 + mServiceCategory + ", language=" + mLanguage + ", body=" + mBody
548 + ", priority=" + mPriority
549 + (mEtwsWarningInfo != null ? (", " + mEtwsWarningInfo.toString()) : "")
Pengquan Menge3f37272019-08-12 23:09:34 -0700550 + (mCmasWarningInfo != null ? (", " + mCmasWarningInfo.toString()) : "")
Jack Yu21effc82019-11-21 20:10:15 -0800551 + ", maximumWaitingTime=" + mMaximumWaitTimeSec
552 + ", received time=" + mReceivedTimeMillis
Chen Xu515285b2019-10-03 16:48:56 -0700553 + ", slotIndex = " + mSlotIndex
Pengquan Menge3f37272019-08-12 23:09:34 -0700554 + ", geo=" + (mGeometries != null
555 ? CbGeoUtils.encodeGeometriesToString(mGeometries) : "null")
556 + '}';
Dan Willemsen4980bf42017-02-14 14:17:12 -0800557 }
558
559 /**
560 * Describe the kinds of special objects contained in the marshalled representation.
561 * @return a bitmask indicating this Parcelable contains no special objects
562 */
563 @Override
564 public int describeContents() {
565 return 0;
566 }
Pengquan Menge3f37272019-08-12 23:09:34 -0700567
568 /**
569 * @return the {@link ContentValues} instance that includes the cell broadcast data.
570 */
Jordan Liu657ef5a2019-08-16 14:07:03 -0700571 @NonNull
Pengquan Menge3f37272019-08-12 23:09:34 -0700572 public ContentValues getContentValues() {
573 ContentValues cv = new ContentValues(16);
Chen Xu515285b2019-10-03 16:48:56 -0700574 cv.put(CellBroadcasts.SLOT_INDEX, mSlotIndex);
Jack Yue94a7a42019-12-19 14:13:43 -0800575 cv.put(CellBroadcasts.SUBSCRIPTION_ID, mSubId);
Pengquan Menge3f37272019-08-12 23:09:34 -0700576 cv.put(CellBroadcasts.GEOGRAPHICAL_SCOPE, mGeographicalScope);
577 if (mLocation.getPlmn() != null) {
578 cv.put(CellBroadcasts.PLMN, mLocation.getPlmn());
579 }
580 if (mLocation.getLac() != -1) {
581 cv.put(CellBroadcasts.LAC, mLocation.getLac());
582 }
583 if (mLocation.getCid() != -1) {
584 cv.put(CellBroadcasts.CID, mLocation.getCid());
585 }
586 cv.put(CellBroadcasts.SERIAL_NUMBER, getSerialNumber());
587 cv.put(CellBroadcasts.SERVICE_CATEGORY, getServiceCategory());
588 cv.put(CellBroadcasts.LANGUAGE_CODE, getLanguageCode());
Jack Yub670fbd2020-02-03 13:58:28 -0800589 cv.put(CellBroadcasts.DATA_CODING_SCHEME, getDataCodingScheme());
Pengquan Menge3f37272019-08-12 23:09:34 -0700590 cv.put(CellBroadcasts.MESSAGE_BODY, getMessageBody());
591 cv.put(CellBroadcasts.MESSAGE_FORMAT, getMessageFormat());
592 cv.put(CellBroadcasts.MESSAGE_PRIORITY, getMessagePriority());
593
594 SmsCbEtwsInfo etwsInfo = getEtwsWarningInfo();
595 if (etwsInfo != null) {
596 cv.put(CellBroadcasts.ETWS_WARNING_TYPE, etwsInfo.getWarningType());
Jack Yu059be242020-06-02 22:23:45 -0700597 cv.put(CellBroadcasts.ETWS_IS_PRIMARY, etwsInfo.isPrimary());
Pengquan Menge3f37272019-08-12 23:09:34 -0700598 }
599
600 SmsCbCmasInfo cmasInfo = getCmasWarningInfo();
601 if (cmasInfo != null) {
602 cv.put(CellBroadcasts.CMAS_MESSAGE_CLASS, cmasInfo.getMessageClass());
603 cv.put(CellBroadcasts.CMAS_CATEGORY, cmasInfo.getCategory());
604 cv.put(CellBroadcasts.CMAS_RESPONSE_TYPE, cmasInfo.getResponseType());
605 cv.put(CellBroadcasts.CMAS_SEVERITY, cmasInfo.getSeverity());
606 cv.put(CellBroadcasts.CMAS_URGENCY, cmasInfo.getUrgency());
607 cv.put(CellBroadcasts.CMAS_CERTAINTY, cmasInfo.getCertainty());
608 }
609
610 cv.put(CellBroadcasts.RECEIVED_TIME, mReceivedTimeMillis);
611
612 if (mGeometries != null) {
613 cv.put(CellBroadcasts.GEOMETRIES, CbGeoUtils.encodeGeometriesToString(mGeometries));
614 } else {
615 cv.put(CellBroadcasts.GEOMETRIES, (String) null);
616 }
617
Pengquan Meng02d6ac02019-08-27 11:20:17 -0700618 cv.put(CellBroadcasts.MAXIMUM_WAIT_TIME, mMaximumWaitTimeSec);
619
Pengquan Menge3f37272019-08-12 23:09:34 -0700620 return cv;
621 }
622
623 /**
624 * Create a {@link SmsCbMessage} instance from a row in the cell broadcast database.
625 * @param cursor an open SQLite cursor pointing to the row to read
626 * @return a {@link SmsCbMessage} instance.
627 * @throws IllegalArgumentException if one of the required columns is missing
628 */
Jordan Liu657ef5a2019-08-16 14:07:03 -0700629 @NonNull
630 public static SmsCbMessage createFromCursor(@NonNull Cursor cursor) {
Pengquan Menge3f37272019-08-12 23:09:34 -0700631 int geoScope = cursor.getInt(
632 cursor.getColumnIndexOrThrow(CellBroadcasts.GEOGRAPHICAL_SCOPE));
633 int serialNum = cursor.getInt(cursor.getColumnIndexOrThrow(CellBroadcasts.SERIAL_NUMBER));
634 int category = cursor.getInt(cursor.getColumnIndexOrThrow(CellBroadcasts.SERVICE_CATEGORY));
635 String language = cursor.getString(
636 cursor.getColumnIndexOrThrow(CellBroadcasts.LANGUAGE_CODE));
637 String body = cursor.getString(cursor.getColumnIndexOrThrow(CellBroadcasts.MESSAGE_BODY));
638 int format = cursor.getInt(cursor.getColumnIndexOrThrow(CellBroadcasts.MESSAGE_FORMAT));
639 int priority = cursor.getInt(cursor.getColumnIndexOrThrow(CellBroadcasts.MESSAGE_PRIORITY));
Chen Xu515285b2019-10-03 16:48:56 -0700640 int slotIndex = cursor.getInt(cursor.getColumnIndexOrThrow(CellBroadcasts.SLOT_INDEX));
Jack Yue94a7a42019-12-19 14:13:43 -0800641 int subId = cursor.getInt(cursor.getColumnIndexOrThrow(CellBroadcasts.SUBSCRIPTION_ID));
Pengquan Menge3f37272019-08-12 23:09:34 -0700642
643 String plmn;
644 int plmnColumn = cursor.getColumnIndex(CellBroadcasts.PLMN);
645 if (plmnColumn != -1 && !cursor.isNull(plmnColumn)) {
646 plmn = cursor.getString(plmnColumn);
647 } else {
648 plmn = null;
649 }
650
651 int lac;
652 int lacColumn = cursor.getColumnIndex(CellBroadcasts.LAC);
653 if (lacColumn != -1 && !cursor.isNull(lacColumn)) {
654 lac = cursor.getInt(lacColumn);
655 } else {
656 lac = -1;
657 }
658
659 int cid;
660 int cidColumn = cursor.getColumnIndex(CellBroadcasts.CID);
661 if (cidColumn != -1 && !cursor.isNull(cidColumn)) {
662 cid = cursor.getInt(cidColumn);
663 } else {
664 cid = -1;
665 }
666
667 SmsCbLocation location = new SmsCbLocation(plmn, lac, cid);
668
669 SmsCbEtwsInfo etwsInfo;
670 int etwsWarningTypeColumn = cursor.getColumnIndex(CellBroadcasts.ETWS_WARNING_TYPE);
Jack Yu059be242020-06-02 22:23:45 -0700671 int etwsIsPrimaryColumn = cursor.getColumnIndex(CellBroadcasts.ETWS_IS_PRIMARY);
672 if (etwsWarningTypeColumn != -1 && !cursor.isNull(etwsWarningTypeColumn)
673 && etwsIsPrimaryColumn != -1 && !cursor.isNull(etwsIsPrimaryColumn)) {
Pengquan Menge3f37272019-08-12 23:09:34 -0700674 int warningType = cursor.getInt(etwsWarningTypeColumn);
Jack Yu059be242020-06-02 22:23:45 -0700675 boolean isPrimary = cursor.getInt(etwsIsPrimaryColumn) != 0;
676 etwsInfo = new SmsCbEtwsInfo(warningType, false, false, isPrimary, null);
Pengquan Menge3f37272019-08-12 23:09:34 -0700677 } else {
678 etwsInfo = null;
679 }
680
681 SmsCbCmasInfo cmasInfo = null;
682 int cmasMessageClassColumn = cursor.getColumnIndex(CellBroadcasts.CMAS_MESSAGE_CLASS);
683 if (cmasMessageClassColumn != -1 && !cursor.isNull(cmasMessageClassColumn)) {
684 int messageClass = cursor.getInt(cmasMessageClassColumn);
685
686 int cmasCategory;
687 int cmasCategoryColumn = cursor.getColumnIndex(CellBroadcasts.CMAS_CATEGORY);
688 if (cmasCategoryColumn != -1 && !cursor.isNull(cmasCategoryColumn)) {
689 cmasCategory = cursor.getInt(cmasCategoryColumn);
690 } else {
691 cmasCategory = SmsCbCmasInfo.CMAS_CATEGORY_UNKNOWN;
692 }
693
694 int responseType;
695 int cmasResponseTypeColumn = cursor.getColumnIndex(CellBroadcasts.CMAS_RESPONSE_TYPE);
696 if (cmasResponseTypeColumn != -1 && !cursor.isNull(cmasResponseTypeColumn)) {
697 responseType = cursor.getInt(cmasResponseTypeColumn);
698 } else {
699 responseType = SmsCbCmasInfo.CMAS_RESPONSE_TYPE_UNKNOWN;
700 }
701
702 int severity;
703 int cmasSeverityColumn = cursor.getColumnIndex(CellBroadcasts.CMAS_SEVERITY);
704 if (cmasSeverityColumn != -1 && !cursor.isNull(cmasSeverityColumn)) {
705 severity = cursor.getInt(cmasSeverityColumn);
706 } else {
707 severity = SmsCbCmasInfo.CMAS_SEVERITY_UNKNOWN;
708 }
709
710 int urgency;
711 int cmasUrgencyColumn = cursor.getColumnIndex(CellBroadcasts.CMAS_URGENCY);
712 if (cmasUrgencyColumn != -1 && !cursor.isNull(cmasUrgencyColumn)) {
713 urgency = cursor.getInt(cmasUrgencyColumn);
714 } else {
715 urgency = SmsCbCmasInfo.CMAS_URGENCY_UNKNOWN;
716 }
717
718 int certainty;
719 int cmasCertaintyColumn = cursor.getColumnIndex(CellBroadcasts.CMAS_CERTAINTY);
720 if (cmasCertaintyColumn != -1 && !cursor.isNull(cmasCertaintyColumn)) {
721 certainty = cursor.getInt(cmasCertaintyColumn);
722 } else {
723 certainty = SmsCbCmasInfo.CMAS_CERTAINTY_UNKNOWN;
724 }
725
726 cmasInfo = new SmsCbCmasInfo(messageClass, cmasCategory, responseType, severity,
727 urgency, certainty);
728 }
729
730 String geoStr = cursor.getString(cursor.getColumnIndex(CellBroadcasts.GEOMETRIES));
731 List<Geometry> geometries =
732 geoStr != null ? CbGeoUtils.parseGeometriesFromString(geoStr) : null;
733
Pengquan Meng02d6ac02019-08-27 11:20:17 -0700734 long receivedTimeMillis = cursor.getLong(
Pengquan Menge3f37272019-08-12 23:09:34 -0700735 cursor.getColumnIndexOrThrow(CellBroadcasts.RECEIVED_TIME));
736
Pengquan Meng02d6ac02019-08-27 11:20:17 -0700737 int maximumWaitTimeSec = cursor.getInt(
738 cursor.getColumnIndexOrThrow(CellBroadcasts.MAXIMUM_WAIT_TIME));
739
Pengquan Menge3f37272019-08-12 23:09:34 -0700740 return new SmsCbMessage(format, geoScope, serialNum, location, category,
Jack Yu641db9a2020-01-24 13:24:41 -0800741 language, 0, body, priority, etwsInfo, cmasInfo, maximumWaitTimeSec, geometries,
Jack Yu750b8b12019-11-20 23:18:29 -0800742 receivedTimeMillis, slotIndex, subId);
Pengquan Menge3f37272019-08-12 23:09:34 -0700743 }
744
745 /**
746 * @return {@code True} if this message needs geo-fencing check.
747 */
748 public boolean needGeoFencingCheck() {
Jordan Liu15a72742019-11-20 13:55:18 -0800749 return mMaximumWaitTimeSec > 0 && mGeometries != null && !mGeometries.isEmpty();
Pengquan Menge3f37272019-08-12 23:09:34 -0700750 }
Dan Willemsen4980bf42017-02-14 14:17:12 -0800751}