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