1 /*
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 
17 package android.telephony;
18 
19 import android.os.Parcel;
20 import android.os.Parcelable;
21 
22 /**
23  * Parcelable object containing a received cell broadcast message. There are four different types
24  * of Cell Broadcast messages:
25  *
26  * <ul>
27  * <li>opt-in informational broadcasts, e.g. news, weather, stock quotes, sports scores</li>
28  * <li>cell information messages, broadcast on channel 50, indicating the current cell name for
29  *  roaming purposes (required to display on the idle screen in Brazil)</li>
30  * <li>emergency broadcasts for the Japanese Earthquake and Tsunami Warning System (ETWS)</li>
31  * <li>emergency broadcasts for the American Commercial Mobile Alert Service (CMAS)</li>
32  * </ul>
33  *
34  * <p>There are also four different CB message formats: GSM, ETWS Primary Notification (GSM only),
35  * UMTS, and CDMA. Some fields are only applicable for some message formats. Other fields were
36  * unified under a common name, avoiding some names, such as "Message Identifier", that refer to
37  * two completely different concepts in 3GPP and CDMA.
38  *
39  * <p>The GSM/UMTS Message Identifier field is available via {@link #getServiceCategory}, the name
40  * of the equivalent field in CDMA. In both cases the service category is a 16-bit value, but 3GPP
41  * and 3GPP2 have completely different meanings for the respective values. For ETWS and CMAS, the
42  * application should
43  *
44  * <p>The CDMA Message Identifier field is available via {@link #getSerialNumber}, which is used
45  * to detect the receipt of a duplicate message to be discarded. In CDMA, the message ID is
46  * unique to the current PLMN. In GSM/UMTS, there is a 16-bit serial number containing a 2-bit
47  * Geographical Scope field which indicates whether the 10-bit message code and 4-bit update number
48  * are considered unique to the PLMN, to the current cell, or to the current Location Area (or
49  * Service Area in UMTS). The relevant values are concatenated into a single String which will be
50  * unique if the messages are not duplicates.
51  *
52  * <p>The SMS dispatcher does not detect duplicate messages. However, it does concatenate the
53  * pages of a GSM multi-page cell broadcast into a single SmsCbMessage object.
54  *
55  * <p>Interested applications with {@code RECEIVE_SMS_PERMISSION} can register to receive
56  * {@code SMS_CB_RECEIVED_ACTION} broadcast intents for incoming non-emergency broadcasts.
57  * Only system applications such as the CellBroadcastReceiver may receive notifications for
58  * emergency broadcasts (ETWS and CMAS). This is intended to prevent any potential for delays or
59  * interference with the immediate display of the alert message and playing of the alert sound and
60  * vibration pattern, which could be caused by poorly written or malicious non-system code.
61  *
62  * @hide
63  */
64 public class SmsCbMessage implements Parcelable {
65 
66     protected static final String LOG_TAG = "SMSCB";
67 
68     /** Cell wide geographical scope with immediate display (GSM/UMTS only). */
69     public static final int GEOGRAPHICAL_SCOPE_CELL_WIDE_IMMEDIATE = 0;
70 
71     /** PLMN wide geographical scope (GSM/UMTS and all CDMA broadcasts). */
72     public static final int GEOGRAPHICAL_SCOPE_PLMN_WIDE = 1;
73 
74     /** Location / service area wide geographical scope (GSM/UMTS only). */
75     public static final int GEOGRAPHICAL_SCOPE_LA_WIDE = 2;
76 
77     /** Cell wide geographical scope (GSM/UMTS only). */
78     public static final int GEOGRAPHICAL_SCOPE_CELL_WIDE = 3;
79 
80     /** GSM or UMTS format cell broadcast. */
81     public static final int MESSAGE_FORMAT_3GPP = 1;
82 
83     /** CDMA format cell broadcast. */
84     public static final int MESSAGE_FORMAT_3GPP2 = 2;
85 
86     /** Normal message priority. */
87     public static final int MESSAGE_PRIORITY_NORMAL = 0;
88 
89     /** Interactive message priority. */
90     public static final int MESSAGE_PRIORITY_INTERACTIVE = 1;
91 
92     /** Urgent message priority. */
93     public static final int MESSAGE_PRIORITY_URGENT = 2;
94 
95     /** Emergency message priority. */
96     public static final int MESSAGE_PRIORITY_EMERGENCY = 3;
97 
98     /** Format of this message (for interpretation of service category values). */
99     private final int mMessageFormat;
100 
101     /** Geographical scope of broadcast. */
102     private final int mGeographicalScope;
103 
104     /**
105      * Serial number of broadcast (message identifier for CDMA, geographical scope + message code +
106      * update number for GSM/UMTS). The serial number plus the location code uniquely identify
107      * a cell broadcast for duplicate detection.
108      */
109     private final int mSerialNumber;
110 
111     /**
112      * Location identifier for this message. It consists of the current operator MCC/MNC as a
113      * 5 or 6-digit decimal string. In addition, for GSM/UMTS, if the Geographical Scope of the
114      * message is not binary 01, the Location Area is included for comparison. If the GS is
115      * 00 or 11, the Cell ID is also included. LAC and Cell ID are -1 if not specified.
116      */
117     private final SmsCbLocation mLocation;
118 
119     /**
120      * 16-bit CDMA service category or GSM/UMTS message identifier. For ETWS and CMAS warnings,
121      * the information provided by the category is also available via {@link #getEtwsWarningInfo()}
122      * or {@link #getCmasWarningInfo()}.
123      */
124     private final int mServiceCategory;
125 
126     /** Message language, as a two-character string, e.g. "en". */
127     private final String mLanguage;
128 
129     /** Message body, as a String. */
130     private final String mBody;
131 
132     /** Message priority (including emergency priority). */
133     private final int mPriority;
134 
135     /** ETWS warning notification information (ETWS warnings only). */
136     private final SmsCbEtwsInfo mEtwsWarningInfo;
137 
138     /** CMAS warning notification information (CMAS warnings only). */
139     private final SmsCbCmasInfo mCmasWarningInfo;
140 
141     /**
142      * Create a new SmsCbMessage with the specified data.
143      */
SmsCbMessage(int messageFormat, int geographicalScope, int serialNumber, SmsCbLocation location, int serviceCategory, String language, String body, int priority, SmsCbEtwsInfo etwsWarningInfo, SmsCbCmasInfo cmasWarningInfo)144     public SmsCbMessage(int messageFormat, int geographicalScope, int serialNumber,
145             SmsCbLocation location, int serviceCategory, String language, String body,
146             int priority, SmsCbEtwsInfo etwsWarningInfo, SmsCbCmasInfo cmasWarningInfo) {
147         mMessageFormat = messageFormat;
148         mGeographicalScope = geographicalScope;
149         mSerialNumber = serialNumber;
150         mLocation = location;
151         mServiceCategory = serviceCategory;
152         mLanguage = language;
153         mBody = body;
154         mPriority = priority;
155         mEtwsWarningInfo = etwsWarningInfo;
156         mCmasWarningInfo = cmasWarningInfo;
157     }
158 
159     /** Create a new SmsCbMessage object from a Parcel. */
SmsCbMessage(Parcel in)160     public SmsCbMessage(Parcel in) {
161         mMessageFormat = in.readInt();
162         mGeographicalScope = in.readInt();
163         mSerialNumber = in.readInt();
164         mLocation = new SmsCbLocation(in);
165         mServiceCategory = in.readInt();
166         mLanguage = in.readString();
167         mBody = in.readString();
168         mPriority = in.readInt();
169         int type = in.readInt();
170         switch (type) {
171             case 'E':
172                 // unparcel ETWS warning information
173                 mEtwsWarningInfo = new SmsCbEtwsInfo(in);
174                 mCmasWarningInfo = null;
175                 break;
176 
177             case 'C':
178                 // unparcel CMAS warning information
179                 mEtwsWarningInfo = null;
180                 mCmasWarningInfo = new SmsCbCmasInfo(in);
181                 break;
182 
183             default:
184                 mEtwsWarningInfo = null;
185                 mCmasWarningInfo = null;
186         }
187     }
188 
189     /**
190      * Flatten this object into a Parcel.
191      *
192      * @param dest  The Parcel in which the object should be written.
193      * @param flags Additional flags about how the object should be written (ignored).
194      */
195     @Override
writeToParcel(Parcel dest, int flags)196     public void writeToParcel(Parcel dest, int flags) {
197         dest.writeInt(mMessageFormat);
198         dest.writeInt(mGeographicalScope);
199         dest.writeInt(mSerialNumber);
200         mLocation.writeToParcel(dest, flags);
201         dest.writeInt(mServiceCategory);
202         dest.writeString(mLanguage);
203         dest.writeString(mBody);
204         dest.writeInt(mPriority);
205         if (mEtwsWarningInfo != null) {
206             // parcel ETWS warning information
207             dest.writeInt('E');
208             mEtwsWarningInfo.writeToParcel(dest, flags);
209         } else if (mCmasWarningInfo != null) {
210             // parcel CMAS warning information
211             dest.writeInt('C');
212             mCmasWarningInfo.writeToParcel(dest, flags);
213         } else {
214             // no ETWS or CMAS warning information
215             dest.writeInt('0');
216         }
217     }
218 
219     public static final Parcelable.Creator<SmsCbMessage> CREATOR
220             = new Parcelable.Creator<SmsCbMessage>() {
221         @Override
222         public SmsCbMessage createFromParcel(Parcel in) {
223             return new SmsCbMessage(in);
224         }
225 
226         @Override
227         public SmsCbMessage[] newArray(int size) {
228             return new SmsCbMessage[size];
229         }
230     };
231 
232     /**
233      * Return the geographical scope of this message (GSM/UMTS only).
234      *
235      * @return Geographical scope
236      */
getGeographicalScope()237     public int getGeographicalScope() {
238         return mGeographicalScope;
239     }
240 
241     /**
242      * Return the broadcast serial number of broadcast (message identifier for CDMA, or
243      * geographical scope + message code + update number for GSM/UMTS). The serial number plus
244      * the location code uniquely identify a cell broadcast for duplicate detection.
245      *
246      * @return the 16-bit CDMA message identifier or GSM/UMTS serial number
247      */
getSerialNumber()248     public int getSerialNumber() {
249         return mSerialNumber;
250     }
251 
252     /**
253      * Return the location identifier for this message, consisting of the MCC/MNC as a
254      * 5 or 6-digit decimal string. In addition, for GSM/UMTS, if the Geographical Scope of the
255      * message is not binary 01, the Location Area is included. If the GS is 00 or 11, the
256      * cell ID is also included. The {@link SmsCbLocation} object includes a method to test
257      * if the location is included within another location area or within a PLMN and CellLocation.
258      *
259      * @return the geographical location code for duplicate message detection
260      */
getLocation()261     public SmsCbLocation getLocation() {
262         return mLocation;
263     }
264 
265     /**
266      * Return the 16-bit CDMA service category or GSM/UMTS message identifier. The interpretation
267      * of the category is radio technology specific. For ETWS and CMAS warnings, the information
268      * provided by the category is available via {@link #getEtwsWarningInfo()} or
269      * {@link #getCmasWarningInfo()} in a radio technology independent format.
270      *
271      * @return the radio technology specific service category
272      */
getServiceCategory()273     public int getServiceCategory() {
274         return mServiceCategory;
275     }
276 
277     /**
278      * Get the ISO-639-1 language code for this message, or null if unspecified
279      *
280      * @return Language code
281      */
getLanguageCode()282     public String getLanguageCode() {
283         return mLanguage;
284     }
285 
286     /**
287      * Get the body of this message, or null if no body available
288      *
289      * @return Body, or null
290      */
getMessageBody()291     public String getMessageBody() {
292         return mBody;
293     }
294 
295     /**
296      * Get the message format ({@link #MESSAGE_FORMAT_3GPP} or {@link #MESSAGE_FORMAT_3GPP2}).
297      * @return an integer representing 3GPP or 3GPP2 message format
298      */
getMessageFormat()299     public int getMessageFormat() {
300         return mMessageFormat;
301     }
302 
303     /**
304      * Get the message priority. Normal broadcasts return {@link #MESSAGE_PRIORITY_NORMAL}
305      * and emergency broadcasts return {@link #MESSAGE_PRIORITY_EMERGENCY}. CDMA also may return
306      * {@link #MESSAGE_PRIORITY_INTERACTIVE} or {@link #MESSAGE_PRIORITY_URGENT}.
307      * @return an integer representing the message priority
308      */
getMessagePriority()309     public int getMessagePriority() {
310         return mPriority;
311     }
312 
313     /**
314      * If this is an ETWS warning notification then this method will return an object containing
315      * the ETWS warning type, the emergency user alert flag, and the popup flag. If this is an
316      * ETWS primary notification (GSM only), there will also be a 7-byte timestamp and 43-byte
317      * digital signature. As of Release 10, 3GPP TS 23.041 states that the UE shall ignore the
318      * ETWS primary notification timestamp and digital signature if received.
319      *
320      * @return an SmsCbEtwsInfo object, or null if this is not an ETWS warning notification
321      */
getEtwsWarningInfo()322     public SmsCbEtwsInfo getEtwsWarningInfo() {
323         return mEtwsWarningInfo;
324     }
325 
326     /**
327      * If this is a CMAS warning notification then this method will return an object containing
328      * the CMAS message class, category, response type, severity, urgency and certainty.
329      * The message class is always present. Severity, urgency and certainty are present for CDMA
330      * warning notifications containing a type 1 elements record and for GSM and UMTS warnings
331      * except for the Presidential-level alert category. Category and response type are only
332      * available for CDMA notifications containing a type 1 elements record.
333      *
334      * @return an SmsCbCmasInfo object, or null if this is not a CMAS warning notification
335      */
getCmasWarningInfo()336     public SmsCbCmasInfo getCmasWarningInfo() {
337         return mCmasWarningInfo;
338     }
339 
340     /**
341      * Return whether this message is an emergency (PWS) message type.
342      * @return true if the message is a public warning notification; false otherwise
343      */
isEmergencyMessage()344     public boolean isEmergencyMessage() {
345         return mPriority == MESSAGE_PRIORITY_EMERGENCY;
346     }
347 
348     /**
349      * Return whether this message is an ETWS warning alert.
350      * @return true if the message is an ETWS warning notification; false otherwise
351      */
isEtwsMessage()352     public boolean isEtwsMessage() {
353         return mEtwsWarningInfo != null;
354     }
355 
356     /**
357      * Return whether this message is a CMAS warning alert.
358      * @return true if the message is a CMAS warning notification; false otherwise
359      */
isCmasMessage()360     public boolean isCmasMessage() {
361         return mCmasWarningInfo != null;
362     }
363 
364     @Override
toString()365     public String toString() {
366         return "SmsCbMessage{geographicalScope=" + mGeographicalScope + ", serialNumber="
367                 + mSerialNumber + ", location=" + mLocation + ", serviceCategory="
368                 + mServiceCategory + ", language=" + mLanguage + ", body=" + mBody
369                 + ", priority=" + mPriority
370                 + (mEtwsWarningInfo != null ? (", " + mEtwsWarningInfo.toString()) : "")
371                 + (mCmasWarningInfo != null ? (", " + mCmasWarningInfo.toString()) : "") + '}';
372     }
373 
374     /**
375      * Describe the kinds of special objects contained in the marshalled representation.
376      * @return a bitmask indicating this Parcelable contains no special objects
377      */
378     @Override
describeContents()379     public int describeContents() {
380         return 0;
381     }
382 }
383