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
17package android.telephony;
18
19import android.os.Parcel;
20import 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 */
64public 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     */
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. */
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
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     */
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     */
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     */
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     */
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     */
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     */
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     */
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     */
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     */
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     */
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     */
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     */
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     */
360    public boolean isCmasMessage() {
361        return mCmasWarningInfo != null;
362    }
363
364    @Override
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
379    public int describeContents() {
380        return 0;
381    }
382}
383