SmsCbHeader.java revision 4980bf4aff8d49ac4e05444a6ef40ea1536f1afb
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 com.android.internal.telephony.gsm;
18
19import android.telephony.SmsCbCmasInfo;
20import android.telephony.SmsCbEtwsInfo;
21
22import java.util.Arrays;
23
24/**
25 * Parses a 3GPP TS 23.041 cell broadcast message header. This class is public for use by
26 * CellBroadcastReceiver test cases, but should not be used by applications.
27 *
28 * All relevant header information is now sent as a Parcelable
29 * {@link android.telephony.SmsCbMessage} object in the "message" extra of the
30 * {@link android.provider.Telephony.Sms.Intents#SMS_CB_RECEIVED_ACTION} or
31 * {@link android.provider.Telephony.Sms.Intents#SMS_EMERGENCY_CB_RECEIVED_ACTION} intent.
32 * The raw PDU is no longer sent to SMS CB applications.
33 */
34public class SmsCbHeader {
35
36    /**
37     * Length of SMS-CB header
38     */
39    static final int PDU_HEADER_LENGTH = 6;
40
41    /**
42     * GSM pdu format, as defined in 3gpp TS 23.041, section 9.4.1
43     */
44    static final int FORMAT_GSM = 1;
45
46    /**
47     * UMTS pdu format, as defined in 3gpp TS 23.041, section 9.4.2
48     */
49    static final int FORMAT_UMTS = 2;
50
51    /**
52     * GSM pdu format, as defined in 3gpp TS 23.041, section 9.4.1.3
53     */
54    static final int FORMAT_ETWS_PRIMARY = 3;
55
56    /**
57     * Message type value as defined in 3gpp TS 25.324, section 11.1.
58     */
59    private static final int MESSAGE_TYPE_CBS_MESSAGE = 1;
60
61    /**
62     * Length of GSM pdus
63     */
64    private static final int PDU_LENGTH_GSM = 88;
65
66    /**
67     * Maximum length of ETWS primary message GSM pdus
68     */
69    private static final int PDU_LENGTH_ETWS = 56;
70
71    private final int mGeographicalScope;
72
73    /** The serial number combines geographical scope, message code, and update number. */
74    private final int mSerialNumber;
75
76    /** The Message Identifier in 3GPP is the same as the Service Category in CDMA. */
77    private final int mMessageIdentifier;
78
79    private final int mDataCodingScheme;
80
81    private final int mPageIndex;
82
83    private final int mNrOfPages;
84
85    private final int mFormat;
86
87    /** ETWS warning notification info. */
88    private final SmsCbEtwsInfo mEtwsInfo;
89
90    /** CMAS warning notification info. */
91    private final SmsCbCmasInfo mCmasInfo;
92
93    public SmsCbHeader(byte[] pdu) throws IllegalArgumentException {
94        if (pdu == null || pdu.length < PDU_HEADER_LENGTH) {
95            throw new IllegalArgumentException("Illegal PDU");
96        }
97
98        if (pdu.length <= PDU_LENGTH_GSM) {
99            // can be ETWS or GSM format.
100            // Per TS23.041 9.4.1.2 and 9.4.1.3.2, GSM and ETWS format both
101            // contain serial number which contains GS, Message Code, and Update Number
102            // per 9.4.1.2.1, and message identifier in same octets
103            mGeographicalScope = (pdu[0] & 0xc0) >>> 6;
104            mSerialNumber = ((pdu[0] & 0xff) << 8) | (pdu[1] & 0xff);
105            mMessageIdentifier = ((pdu[2] & 0xff) << 8) | (pdu[3] & 0xff);
106            if (isEtwsMessage() && pdu.length <= PDU_LENGTH_ETWS) {
107                mFormat = FORMAT_ETWS_PRIMARY;
108                mDataCodingScheme = -1;
109                mPageIndex = -1;
110                mNrOfPages = -1;
111                boolean emergencyUserAlert = (pdu[4] & 0x1) != 0;
112                boolean activatePopup = (pdu[5] & 0x80) != 0;
113                int warningType = (pdu[4] & 0xfe) >>> 1;
114                byte[] warningSecurityInfo;
115                // copy the Warning-Security-Information, if present
116                if (pdu.length > PDU_HEADER_LENGTH) {
117                    warningSecurityInfo = Arrays.copyOfRange(pdu, 6, pdu.length);
118                } else {
119                    warningSecurityInfo = null;
120                }
121                mEtwsInfo = new SmsCbEtwsInfo(warningType, emergencyUserAlert, activatePopup,
122                        true, warningSecurityInfo);
123                mCmasInfo = null;
124                return;     // skip the ETWS/CMAS initialization code for regular notifications
125            } else {
126                // GSM pdus are no more than 88 bytes
127                mFormat = FORMAT_GSM;
128                mDataCodingScheme = pdu[4] & 0xff;
129
130                // Check for invalid page parameter
131                int pageIndex = (pdu[5] & 0xf0) >>> 4;
132                int nrOfPages = pdu[5] & 0x0f;
133
134                if (pageIndex == 0 || nrOfPages == 0 || pageIndex > nrOfPages) {
135                    pageIndex = 1;
136                    nrOfPages = 1;
137                }
138
139                mPageIndex = pageIndex;
140                mNrOfPages = nrOfPages;
141            }
142        } else {
143            // UMTS pdus are always at least 90 bytes since the payload includes
144            // a number-of-pages octet and also one length octet per page
145            mFormat = FORMAT_UMTS;
146
147            int messageType = pdu[0];
148
149            if (messageType != MESSAGE_TYPE_CBS_MESSAGE) {
150                throw new IllegalArgumentException("Unsupported message type " + messageType);
151            }
152
153            mMessageIdentifier = ((pdu[1] & 0xff) << 8) | pdu[2] & 0xff;
154            mGeographicalScope = (pdu[3] & 0xc0) >>> 6;
155            mSerialNumber = ((pdu[3] & 0xff) << 8) | (pdu[4] & 0xff);
156            mDataCodingScheme = pdu[5] & 0xff;
157
158            // We will always consider a UMTS message as having one single page
159            // since there's only one instance of the header, even though the
160            // actual payload may contain several pages.
161            mPageIndex = 1;
162            mNrOfPages = 1;
163        }
164
165        if (isEtwsMessage()) {
166            boolean emergencyUserAlert = isEtwsEmergencyUserAlert();
167            boolean activatePopup = isEtwsPopupAlert();
168            int warningType = getEtwsWarningType();
169            mEtwsInfo = new SmsCbEtwsInfo(warningType, emergencyUserAlert, activatePopup,
170                    false, null);
171            mCmasInfo = null;
172        } else if (isCmasMessage()) {
173            int messageClass = getCmasMessageClass();
174            int severity = getCmasSeverity();
175            int urgency = getCmasUrgency();
176            int certainty = getCmasCertainty();
177            mEtwsInfo = null;
178            mCmasInfo = new SmsCbCmasInfo(messageClass, SmsCbCmasInfo.CMAS_CATEGORY_UNKNOWN,
179                    SmsCbCmasInfo.CMAS_RESPONSE_TYPE_UNKNOWN, severity, urgency, certainty);
180        } else {
181            mEtwsInfo = null;
182            mCmasInfo = null;
183        }
184    }
185
186    int getGeographicalScope() {
187        return mGeographicalScope;
188    }
189
190    int getSerialNumber() {
191        return mSerialNumber;
192    }
193
194    int getServiceCategory() {
195        return mMessageIdentifier;
196    }
197
198    int getDataCodingScheme() {
199        return mDataCodingScheme;
200    }
201
202    int getPageIndex() {
203        return mPageIndex;
204    }
205
206    int getNumberOfPages() {
207        return mNrOfPages;
208    }
209
210    SmsCbEtwsInfo getEtwsInfo() {
211        return mEtwsInfo;
212    }
213
214    SmsCbCmasInfo getCmasInfo() {
215        return mCmasInfo;
216    }
217
218    /**
219     * Return whether this broadcast is an emergency (PWS) message type.
220     * @return true if this message is emergency type; false otherwise
221     */
222    boolean isEmergencyMessage() {
223        return mMessageIdentifier >= SmsCbConstants.MESSAGE_ID_PWS_FIRST_IDENTIFIER
224                && mMessageIdentifier <= SmsCbConstants.MESSAGE_ID_PWS_LAST_IDENTIFIER;
225    }
226
227    /**
228     * Return whether this broadcast is an ETWS emergency message type.
229     * @return true if this message is ETWS emergency type; false otherwise
230     */
231    private boolean isEtwsMessage() {
232        return (mMessageIdentifier & SmsCbConstants.MESSAGE_ID_ETWS_TYPE_MASK)
233                == SmsCbConstants.MESSAGE_ID_ETWS_TYPE;
234    }
235
236    /**
237     * Return whether this broadcast is an ETWS primary notification.
238     * @return true if this message is an ETWS primary notification; false otherwise
239     */
240    boolean isEtwsPrimaryNotification() {
241        return mFormat == FORMAT_ETWS_PRIMARY;
242    }
243
244    /**
245     * Return whether this broadcast is in UMTS format.
246     * @return true if this message is in UMTS format; false otherwise
247     */
248    boolean isUmtsFormat() {
249        return mFormat == FORMAT_UMTS;
250    }
251
252    /**
253     * Return whether this message is a CMAS emergency message type.
254     * @return true if this message is CMAS emergency type; false otherwise
255     */
256    private boolean isCmasMessage() {
257        return mMessageIdentifier >= SmsCbConstants.MESSAGE_ID_CMAS_FIRST_IDENTIFIER
258                && mMessageIdentifier <= SmsCbConstants.MESSAGE_ID_CMAS_LAST_IDENTIFIER;
259    }
260
261    /**
262     * Return whether the popup alert flag is set for an ETWS warning notification.
263     * This method assumes that the message ID has already been checked for ETWS type.
264     *
265     * @return true if the message code indicates a popup alert should be displayed
266     */
267    private boolean isEtwsPopupAlert() {
268        return (mSerialNumber & SmsCbConstants.SERIAL_NUMBER_ETWS_ACTIVATE_POPUP) != 0;
269    }
270
271    /**
272     * Return whether the emergency user alert flag is set for an ETWS warning notification.
273     * This method assumes that the message ID has already been checked for ETWS type.
274     *
275     * @return true if the message code indicates an emergency user alert
276     */
277    private boolean isEtwsEmergencyUserAlert() {
278        return (mSerialNumber & SmsCbConstants.SERIAL_NUMBER_ETWS_EMERGENCY_USER_ALERT) != 0;
279    }
280
281    /**
282     * Returns the warning type for an ETWS warning notification.
283     * This method assumes that the message ID has already been checked for ETWS type.
284     *
285     * @return the ETWS warning type defined in 3GPP TS 23.041 section 9.3.24
286     */
287    private int getEtwsWarningType() {
288        return mMessageIdentifier - SmsCbConstants.MESSAGE_ID_ETWS_EARTHQUAKE_WARNING;
289    }
290
291    /**
292     * Returns the message class for a CMAS warning notification.
293     * This method assumes that the message ID has already been checked for CMAS type.
294     * @return the CMAS message class as defined in {@link SmsCbCmasInfo}
295     */
296    private int getCmasMessageClass() {
297        switch (mMessageIdentifier) {
298            case SmsCbConstants.MESSAGE_ID_CMAS_ALERT_PRESIDENTIAL_LEVEL:
299            case SmsCbConstants.MESSAGE_ID_CMAS_ALERT_PRESIDENTIAL_LEVEL_LANGUAGE:
300                return SmsCbCmasInfo.CMAS_CLASS_PRESIDENTIAL_LEVEL_ALERT;
301
302            case SmsCbConstants.MESSAGE_ID_CMAS_ALERT_EXTREME_IMMEDIATE_OBSERVED:
303            case SmsCbConstants.MESSAGE_ID_CMAS_ALERT_EXTREME_IMMEDIATE_OBSERVED_LANGUAGE:
304            case SmsCbConstants.MESSAGE_ID_CMAS_ALERT_EXTREME_IMMEDIATE_LIKELY:
305            case SmsCbConstants.MESSAGE_ID_CMAS_ALERT_EXTREME_IMMEDIATE_LIKELY_LANGUAGE:
306                return SmsCbCmasInfo.CMAS_CLASS_EXTREME_THREAT;
307
308            case SmsCbConstants.MESSAGE_ID_CMAS_ALERT_EXTREME_EXPECTED_OBSERVED:
309            case SmsCbConstants.MESSAGE_ID_CMAS_ALERT_EXTREME_EXPECTED_OBSERVED_LANGUAGE:
310            case SmsCbConstants.MESSAGE_ID_CMAS_ALERT_EXTREME_EXPECTED_LIKELY:
311            case SmsCbConstants.MESSAGE_ID_CMAS_ALERT_EXTREME_EXPECTED_LIKELY_LANGUAGE:
312            case SmsCbConstants.MESSAGE_ID_CMAS_ALERT_SEVERE_IMMEDIATE_OBSERVED:
313            case SmsCbConstants.MESSAGE_ID_CMAS_ALERT_SEVERE_IMMEDIATE_OBSERVED_LANGUAGE:
314            case SmsCbConstants.MESSAGE_ID_CMAS_ALERT_SEVERE_IMMEDIATE_LIKELY:
315            case SmsCbConstants.MESSAGE_ID_CMAS_ALERT_SEVERE_IMMEDIATE_LIKELY_LANGUAGE:
316            case SmsCbConstants.MESSAGE_ID_CMAS_ALERT_SEVERE_EXPECTED_OBSERVED:
317            case SmsCbConstants.MESSAGE_ID_CMAS_ALERT_SEVERE_EXPECTED_OBSERVED_LANGUAGE:
318            case SmsCbConstants.MESSAGE_ID_CMAS_ALERT_SEVERE_EXPECTED_LIKELY:
319            case SmsCbConstants.MESSAGE_ID_CMAS_ALERT_SEVERE_EXPECTED_LIKELY_LANGUAGE:
320                return SmsCbCmasInfo.CMAS_CLASS_SEVERE_THREAT;
321
322            case SmsCbConstants.MESSAGE_ID_CMAS_ALERT_CHILD_ABDUCTION_EMERGENCY:
323            case SmsCbConstants.MESSAGE_ID_CMAS_ALERT_CHILD_ABDUCTION_EMERGENCY_LANGUAGE:
324                return SmsCbCmasInfo.CMAS_CLASS_CHILD_ABDUCTION_EMERGENCY;
325
326            case SmsCbConstants.MESSAGE_ID_CMAS_ALERT_REQUIRED_MONTHLY_TEST:
327            case SmsCbConstants.MESSAGE_ID_CMAS_ALERT_REQUIRED_MONTHLY_TEST_LANGUAGE:
328                return SmsCbCmasInfo.CMAS_CLASS_REQUIRED_MONTHLY_TEST;
329
330            case SmsCbConstants.MESSAGE_ID_CMAS_ALERT_EXERCISE:
331            case SmsCbConstants.MESSAGE_ID_CMAS_ALERT_EXERCISE_LANGUAGE:
332                return SmsCbCmasInfo.CMAS_CLASS_CMAS_EXERCISE;
333
334            case SmsCbConstants.MESSAGE_ID_CMAS_ALERT_OPERATOR_DEFINED_USE:
335            case SmsCbConstants.MESSAGE_ID_CMAS_ALERT_OPERATOR_DEFINED_USE_LANGUAGE:
336                return SmsCbCmasInfo.CMAS_CLASS_OPERATOR_DEFINED_USE;
337
338            default:
339                return SmsCbCmasInfo.CMAS_CLASS_UNKNOWN;
340        }
341    }
342
343    /**
344     * Returns the severity for a CMAS warning notification. This is only available for extreme
345     * and severe alerts, not for other types such as Presidential Level and AMBER alerts.
346     * This method assumes that the message ID has already been checked for CMAS type.
347     * @return the CMAS severity as defined in {@link SmsCbCmasInfo}
348     */
349    private int getCmasSeverity() {
350        switch (mMessageIdentifier) {
351            case SmsCbConstants.MESSAGE_ID_CMAS_ALERT_EXTREME_IMMEDIATE_OBSERVED:
352            case SmsCbConstants.MESSAGE_ID_CMAS_ALERT_EXTREME_IMMEDIATE_OBSERVED_LANGUAGE:
353            case SmsCbConstants.MESSAGE_ID_CMAS_ALERT_EXTREME_IMMEDIATE_LIKELY:
354            case SmsCbConstants.MESSAGE_ID_CMAS_ALERT_EXTREME_IMMEDIATE_LIKELY_LANGUAGE:
355            case SmsCbConstants.MESSAGE_ID_CMAS_ALERT_EXTREME_EXPECTED_OBSERVED:
356            case SmsCbConstants.MESSAGE_ID_CMAS_ALERT_EXTREME_EXPECTED_OBSERVED_LANGUAGE:
357            case SmsCbConstants.MESSAGE_ID_CMAS_ALERT_EXTREME_EXPECTED_LIKELY:
358            case SmsCbConstants.MESSAGE_ID_CMAS_ALERT_EXTREME_EXPECTED_LIKELY_LANGUAGE:
359                return SmsCbCmasInfo.CMAS_SEVERITY_EXTREME;
360
361            case SmsCbConstants.MESSAGE_ID_CMAS_ALERT_SEVERE_IMMEDIATE_OBSERVED:
362            case SmsCbConstants.MESSAGE_ID_CMAS_ALERT_SEVERE_IMMEDIATE_OBSERVED_LANGUAGE:
363            case SmsCbConstants.MESSAGE_ID_CMAS_ALERT_SEVERE_IMMEDIATE_LIKELY:
364            case SmsCbConstants.MESSAGE_ID_CMAS_ALERT_SEVERE_IMMEDIATE_LIKELY_LANGUAGE:
365            case SmsCbConstants.MESSAGE_ID_CMAS_ALERT_SEVERE_EXPECTED_OBSERVED:
366            case SmsCbConstants.MESSAGE_ID_CMAS_ALERT_SEVERE_EXPECTED_OBSERVED_LANGUAGE:
367            case SmsCbConstants.MESSAGE_ID_CMAS_ALERT_SEVERE_EXPECTED_LIKELY:
368            case SmsCbConstants.MESSAGE_ID_CMAS_ALERT_SEVERE_EXPECTED_LIKELY_LANGUAGE:
369                return SmsCbCmasInfo.CMAS_SEVERITY_SEVERE;
370
371            default:
372                return SmsCbCmasInfo.CMAS_SEVERITY_UNKNOWN;
373        }
374    }
375
376    /**
377     * Returns the urgency for a CMAS warning notification. This is only available for extreme
378     * and severe alerts, not for other types such as Presidential Level and AMBER alerts.
379     * This method assumes that the message ID has already been checked for CMAS type.
380     * @return the CMAS urgency as defined in {@link SmsCbCmasInfo}
381     */
382    private int getCmasUrgency() {
383        switch (mMessageIdentifier) {
384            case SmsCbConstants.MESSAGE_ID_CMAS_ALERT_EXTREME_IMMEDIATE_OBSERVED:
385            case SmsCbConstants.MESSAGE_ID_CMAS_ALERT_EXTREME_IMMEDIATE_OBSERVED_LANGUAGE:
386            case SmsCbConstants.MESSAGE_ID_CMAS_ALERT_EXTREME_IMMEDIATE_LIKELY:
387            case SmsCbConstants.MESSAGE_ID_CMAS_ALERT_EXTREME_IMMEDIATE_LIKELY_LANGUAGE:
388            case SmsCbConstants.MESSAGE_ID_CMAS_ALERT_SEVERE_IMMEDIATE_OBSERVED:
389            case SmsCbConstants.MESSAGE_ID_CMAS_ALERT_SEVERE_IMMEDIATE_OBSERVED_LANGUAGE:
390            case SmsCbConstants.MESSAGE_ID_CMAS_ALERT_SEVERE_IMMEDIATE_LIKELY:
391            case SmsCbConstants.MESSAGE_ID_CMAS_ALERT_SEVERE_IMMEDIATE_LIKELY_LANGUAGE:
392                return SmsCbCmasInfo.CMAS_URGENCY_IMMEDIATE;
393
394            case SmsCbConstants.MESSAGE_ID_CMAS_ALERT_EXTREME_EXPECTED_OBSERVED:
395            case SmsCbConstants.MESSAGE_ID_CMAS_ALERT_EXTREME_EXPECTED_OBSERVED_LANGUAGE:
396            case SmsCbConstants.MESSAGE_ID_CMAS_ALERT_EXTREME_EXPECTED_LIKELY:
397            case SmsCbConstants.MESSAGE_ID_CMAS_ALERT_EXTREME_EXPECTED_LIKELY_LANGUAGE:
398            case SmsCbConstants.MESSAGE_ID_CMAS_ALERT_SEVERE_EXPECTED_OBSERVED:
399            case SmsCbConstants.MESSAGE_ID_CMAS_ALERT_SEVERE_EXPECTED_OBSERVED_LANGUAGE:
400            case SmsCbConstants.MESSAGE_ID_CMAS_ALERT_SEVERE_EXPECTED_LIKELY:
401            case SmsCbConstants.MESSAGE_ID_CMAS_ALERT_SEVERE_EXPECTED_LIKELY_LANGUAGE:
402                return SmsCbCmasInfo.CMAS_URGENCY_EXPECTED;
403
404            default:
405                return SmsCbCmasInfo.CMAS_URGENCY_UNKNOWN;
406        }
407    }
408
409    /**
410     * Returns the certainty for a CMAS warning notification. This is only available for extreme
411     * and severe alerts, not for other types such as Presidential Level and AMBER alerts.
412     * This method assumes that the message ID has already been checked for CMAS type.
413     * @return the CMAS certainty as defined in {@link SmsCbCmasInfo}
414     */
415    private int getCmasCertainty() {
416        switch (mMessageIdentifier) {
417            case SmsCbConstants.MESSAGE_ID_CMAS_ALERT_EXTREME_IMMEDIATE_OBSERVED:
418            case SmsCbConstants.MESSAGE_ID_CMAS_ALERT_EXTREME_IMMEDIATE_OBSERVED_LANGUAGE:
419            case SmsCbConstants.MESSAGE_ID_CMAS_ALERT_EXTREME_EXPECTED_OBSERVED:
420            case SmsCbConstants.MESSAGE_ID_CMAS_ALERT_EXTREME_EXPECTED_OBSERVED_LANGUAGE:
421            case SmsCbConstants.MESSAGE_ID_CMAS_ALERT_SEVERE_IMMEDIATE_OBSERVED:
422            case SmsCbConstants.MESSAGE_ID_CMAS_ALERT_SEVERE_IMMEDIATE_OBSERVED_LANGUAGE:
423            case SmsCbConstants.MESSAGE_ID_CMAS_ALERT_SEVERE_EXPECTED_OBSERVED:
424            case SmsCbConstants.MESSAGE_ID_CMAS_ALERT_SEVERE_EXPECTED_OBSERVED_LANGUAGE:
425                return SmsCbCmasInfo.CMAS_CERTAINTY_OBSERVED;
426
427            case SmsCbConstants.MESSAGE_ID_CMAS_ALERT_EXTREME_IMMEDIATE_LIKELY:
428            case SmsCbConstants.MESSAGE_ID_CMAS_ALERT_EXTREME_IMMEDIATE_LIKELY_LANGUAGE:
429            case SmsCbConstants.MESSAGE_ID_CMAS_ALERT_EXTREME_EXPECTED_LIKELY:
430            case SmsCbConstants.MESSAGE_ID_CMAS_ALERT_EXTREME_EXPECTED_LIKELY_LANGUAGE:
431            case SmsCbConstants.MESSAGE_ID_CMAS_ALERT_SEVERE_IMMEDIATE_LIKELY:
432            case SmsCbConstants.MESSAGE_ID_CMAS_ALERT_SEVERE_IMMEDIATE_LIKELY_LANGUAGE:
433            case SmsCbConstants.MESSAGE_ID_CMAS_ALERT_SEVERE_EXPECTED_LIKELY:
434            case SmsCbConstants.MESSAGE_ID_CMAS_ALERT_SEVERE_EXPECTED_LIKELY_LANGUAGE:
435                return SmsCbCmasInfo.CMAS_CERTAINTY_LIKELY;
436
437            default:
438                return SmsCbCmasInfo.CMAS_CERTAINTY_UNKNOWN;
439        }
440    }
441
442    @Override
443    public String toString() {
444        return "SmsCbHeader{GS=" + mGeographicalScope + ", serialNumber=0x" +
445                Integer.toHexString(mSerialNumber) +
446                ", messageIdentifier=0x" + Integer.toHexString(mMessageIdentifier) +
447                ", DCS=0x" + Integer.toHexString(mDataCodingScheme) +
448                ", page " + mPageIndex + " of " + mNrOfPages + '}';
449    }
450}