10825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville/*
20825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville * Copyright (C) 2008 The Android Open Source Project
30825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville *
40825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville * Licensed under the Apache License, Version 2.0 (the "License");
50825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville * you may not use this file except in compliance with the License.
60825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville * You may obtain a copy of the License at
70825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville *
80825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville *      http://www.apache.org/licenses/LICENSE-2.0
90825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville *
100825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville * Unless required by applicable law or agreed to in writing, software
110825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville * distributed under the License is distributed on an "AS IS" BASIS,
120825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
130825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville * See the License for the specific language governing permissions and
140825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville * limitations under the License.
150825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville */
160825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville
170825495a331bb44df395a0cdb79fab85e68db5d5Wink Savillepackage com.android.internal.telephony.cdma.sms;
180825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville
190825495a331bb44df395a0cdb79fab85e68db5d5Wink Savilleimport android.content.res.Resources;
200825495a331bb44df395a0cdb79fab85e68db5d5Wink Savilleimport android.telephony.SmsCbCmasInfo;
210825495a331bb44df395a0cdb79fab85e68db5d5Wink Savilleimport android.telephony.cdma.CdmaSmsCbProgramData;
22b8a13d300b245e0080aa01275e232f54d5d0e09cJake Hambyimport android.telephony.cdma.CdmaSmsCbProgramResults;
230825495a331bb44df395a0cdb79fab85e68db5d5Wink Savilleimport android.text.format.Time;
24ded9c0af7fa49504c047275ed34c2d3b22bf0c3aWink Savilleimport android.telephony.Rlog;
250825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville
260825495a331bb44df395a0cdb79fab85e68db5d5Wink Savilleimport com.android.internal.telephony.GsmAlphabet;
270825495a331bb44df395a0cdb79fab85e68db5d5Wink Savilleimport com.android.internal.telephony.SmsConstants;
280825495a331bb44df395a0cdb79fab85e68db5d5Wink Savilleimport com.android.internal.telephony.SmsHeader;
290825495a331bb44df395a0cdb79fab85e68db5d5Wink Savilleimport com.android.internal.telephony.GsmAlphabet.TextEncodingDetails;
30d720945f2be5ea5fe0faf67e67d9ea0e184eba67Alex Yakavenkaimport com.android.internal.telephony.uicc.IccUtils;
310825495a331bb44df395a0cdb79fab85e68db5d5Wink Savilleimport com.android.internal.util.BitwiseInputStream;
320825495a331bb44df395a0cdb79fab85e68db5d5Wink Savilleimport com.android.internal.util.BitwiseOutputStream;
330825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville
340825495a331bb44df395a0cdb79fab85e68db5d5Wink Savilleimport java.util.ArrayList;
350825495a331bb44df395a0cdb79fab85e68db5d5Wink Savilleimport java.util.TimeZone;
360825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville
370825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville/**
380825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville * An object to encode and decode CDMA SMS bearer data.
390825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville */
400825495a331bb44df395a0cdb79fab85e68db5d5Wink Savillepublic final class BearerData {
41cbaa45bbf2cab852b6c9c3a887e9f803d4e857eaWink Saville    private final static String LOG_TAG = "BearerData";
420825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville
430825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville    /**
440825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville     * Bearer Data Subparameter Identifiers
450825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville     * (See 3GPP2 C.S0015-B, v2.0, table 4.5-1)
460825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville     * NOTE: Commented subparameter types are not implemented.
470825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville     */
480825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville    private final static byte SUBPARAM_MESSAGE_IDENTIFIER               = 0x00;
490825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville    private final static byte SUBPARAM_USER_DATA                        = 0x01;
500825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville    private final static byte SUBPARAM_USER_RESPONSE_CODE               = 0x02;
510825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville    private final static byte SUBPARAM_MESSAGE_CENTER_TIME_STAMP        = 0x03;
520825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville    private final static byte SUBPARAM_VALIDITY_PERIOD_ABSOLUTE         = 0x04;
530825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville    private final static byte SUBPARAM_VALIDITY_PERIOD_RELATIVE         = 0x05;
540825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville    private final static byte SUBPARAM_DEFERRED_DELIVERY_TIME_ABSOLUTE  = 0x06;
550825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville    private final static byte SUBPARAM_DEFERRED_DELIVERY_TIME_RELATIVE  = 0x07;
560825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville    private final static byte SUBPARAM_PRIORITY_INDICATOR               = 0x08;
570825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville    private final static byte SUBPARAM_PRIVACY_INDICATOR                = 0x09;
580825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville    private final static byte SUBPARAM_REPLY_OPTION                     = 0x0A;
590825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville    private final static byte SUBPARAM_NUMBER_OF_MESSAGES               = 0x0B;
600825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville    private final static byte SUBPARAM_ALERT_ON_MESSAGE_DELIVERY        = 0x0C;
610825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville    private final static byte SUBPARAM_LANGUAGE_INDICATOR               = 0x0D;
620825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville    private final static byte SUBPARAM_CALLBACK_NUMBER                  = 0x0E;
630825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville    private final static byte SUBPARAM_MESSAGE_DISPLAY_MODE             = 0x0F;
640825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville    //private final static byte SUBPARAM_MULTIPLE_ENCODING_USER_DATA      = 0x10;
650825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville    private final static byte SUBPARAM_MESSAGE_DEPOSIT_INDEX            = 0x11;
660825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville    private final static byte SUBPARAM_SERVICE_CATEGORY_PROGRAM_DATA    = 0x12;
670825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville    private final static byte SUBPARAM_SERVICE_CATEGORY_PROGRAM_RESULTS = 0x13;
680825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville    private final static byte SUBPARAM_MESSAGE_STATUS                   = 0x14;
690825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville    //private final static byte SUBPARAM_TP_FAILURE_CAUSE                 = 0x15;
700825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville    //private final static byte SUBPARAM_ENHANCED_VMN                     = 0x16;
710825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville    //private final static byte SUBPARAM_ENHANCED_VMN_ACK                 = 0x17;
720825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville
733de1a7e5535f36e86d82da12df2b17aeeafabdc6Rika Brooks    // All other values after this are reserved.
743de1a7e5535f36e86d82da12df2b17aeeafabdc6Rika Brooks    private final static byte SUBPARAM_ID_LAST_DEFINED                    = 0x17;
753de1a7e5535f36e86d82da12df2b17aeeafabdc6Rika Brooks
760825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville    /**
770825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville     * Supported message types for CDMA SMS messages
780825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville     * (See 3GPP2 C.S0015-B, v2.0, table 4.5.1-1)
790825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville     */
800825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville    public static final int MESSAGE_TYPE_DELIVER        = 0x01;
810825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville    public static final int MESSAGE_TYPE_SUBMIT         = 0x02;
820825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville    public static final int MESSAGE_TYPE_CANCELLATION   = 0x03;
830825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville    public static final int MESSAGE_TYPE_DELIVERY_ACK   = 0x04;
840825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville    public static final int MESSAGE_TYPE_USER_ACK       = 0x05;
850825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville    public static final int MESSAGE_TYPE_READ_ACK       = 0x06;
860825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville    public static final int MESSAGE_TYPE_DELIVER_REPORT = 0x07;
870825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville    public static final int MESSAGE_TYPE_SUBMIT_REPORT  = 0x08;
880825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville
890825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville    public int messageType;
900825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville
910825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville    /**
920825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville     * 16-bit value indicating the message ID, which increments modulo 65536.
930825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville     * (Special rules apply for WAP-messages.)
940825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville     * (See 3GPP2 C.S0015-B, v2, 4.5.1)
950825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville     */
960825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville    public int messageId;
970825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville
980825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville    /**
990825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville     * Supported priority modes for CDMA SMS messages
1000825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville     * (See 3GPP2 C.S0015-B, v2.0, table 4.5.9-1)
1010825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville     */
1020825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville    public static final int PRIORITY_NORMAL        = 0x0;
1030825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville    public static final int PRIORITY_INTERACTIVE   = 0x1;
1040825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville    public static final int PRIORITY_URGENT        = 0x2;
1050825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville    public static final int PRIORITY_EMERGENCY     = 0x3;
1060825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville
1070825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville    public boolean priorityIndicatorSet = false;
1080825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville    public int priority = PRIORITY_NORMAL;
1090825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville
1100825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville    /**
1110825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville     * Supported privacy modes for CDMA SMS messages
1120825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville     * (See 3GPP2 C.S0015-B, v2.0, table 4.5.10-1)
1130825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville     */
1140825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville    public static final int PRIVACY_NOT_RESTRICTED = 0x0;
1150825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville    public static final int PRIVACY_RESTRICTED     = 0x1;
1160825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville    public static final int PRIVACY_CONFIDENTIAL   = 0x2;
1170825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville    public static final int PRIVACY_SECRET         = 0x3;
1180825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville
1190825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville    public boolean privacyIndicatorSet = false;
1200825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville    public int privacy = PRIVACY_NOT_RESTRICTED;
1210825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville
1220825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville    /**
1230825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville     * Supported alert priority modes for CDMA SMS messages
1240825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville     * (See 3GPP2 C.S0015-B, v2.0, table 4.5.13-1)
1250825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville     */
1260825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville    public static final int ALERT_DEFAULT          = 0x0;
1270825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville    public static final int ALERT_LOW_PRIO         = 0x1;
1280825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville    public static final int ALERT_MEDIUM_PRIO      = 0x2;
1290825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville    public static final int ALERT_HIGH_PRIO        = 0x3;
1300825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville
1310825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville    public boolean alertIndicatorSet = false;
1320825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville    public int alert = ALERT_DEFAULT;
1330825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville
1340825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville    /**
1350825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville     * Supported display modes for CDMA SMS messages.  Display mode is
1360825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville     * a 2-bit value used to indicate to the mobile station when to
1370825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville     * display the received message.  (See 3GPP2 C.S0015-B, v2,
1380825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville     * 4.5.16)
1390825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville     */
1400825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville    public static final int DISPLAY_MODE_IMMEDIATE      = 0x0;
1410825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville    public static final int DISPLAY_MODE_DEFAULT        = 0x1;
1420825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville    public static final int DISPLAY_MODE_USER           = 0x2;
1430825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville
1440825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville    public boolean displayModeSet = false;
1450825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville    public int displayMode = DISPLAY_MODE_DEFAULT;
1460825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville
1470825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville    /**
1480825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville     * Language Indicator values.  NOTE: the spec (3GPP2 C.S0015-B,
1490825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville     * v2, 4.5.14) is ambiguous as to the meaning of this field, as it
1500825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville     * refers to C.R1001-D but that reference has been crossed out.
1510825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville     * It would seem reasonable to assume the values from C.R1001-F
1520825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville     * (table 9.2-1) are to be used instead.
1530825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville     */
1540825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville    public static final int LANGUAGE_UNKNOWN  = 0x00;
1550825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville    public static final int LANGUAGE_ENGLISH  = 0x01;
1560825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville    public static final int LANGUAGE_FRENCH   = 0x02;
1570825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville    public static final int LANGUAGE_SPANISH  = 0x03;
1580825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville    public static final int LANGUAGE_JAPANESE = 0x04;
1590825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville    public static final int LANGUAGE_KOREAN   = 0x05;
1600825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville    public static final int LANGUAGE_CHINESE  = 0x06;
1610825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville    public static final int LANGUAGE_HEBREW   = 0x07;
1620825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville
1630825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville    public boolean languageIndicatorSet = false;
1640825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville    public int language = LANGUAGE_UNKNOWN;
1650825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville
1660825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville    /**
1670825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville     * SMS Message Status Codes.  The first component of the Message
1680825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville     * status indicates if an error has occurred and whether the error
1690825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville     * is considered permanent or temporary.  The second component of
1700825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville     * the Message status indicates the cause of the error (if any).
1710825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville     * (See 3GPP2 C.S0015-B, v2.0, 4.5.21)
1720825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville     */
1730825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville    /* no-error codes */
1740825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville    public static final int ERROR_NONE                   = 0x00;
1750825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville    public static final int STATUS_ACCEPTED              = 0x00;
1760825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville    public static final int STATUS_DEPOSITED_TO_INTERNET = 0x01;
1770825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville    public static final int STATUS_DELIVERED             = 0x02;
1780825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville    public static final int STATUS_CANCELLED             = 0x03;
1790825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville    /* temporary-error and permanent-error codes */
1800825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville    public static final int ERROR_TEMPORARY              = 0x02;
1810825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville    public static final int STATUS_NETWORK_CONGESTION    = 0x04;
1820825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville    public static final int STATUS_NETWORK_ERROR         = 0x05;
1830825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville    public static final int STATUS_UNKNOWN_ERROR         = 0x1F;
1840825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville    /* permanent-error codes */
1850825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville    public static final int ERROR_PERMANENT              = 0x03;
1860825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville    public static final int STATUS_CANCEL_FAILED         = 0x06;
1870825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville    public static final int STATUS_BLOCKED_DESTINATION   = 0x07;
1880825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville    public static final int STATUS_TEXT_TOO_LONG         = 0x08;
1890825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville    public static final int STATUS_DUPLICATE_MESSAGE     = 0x09;
1900825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville    public static final int STATUS_INVALID_DESTINATION   = 0x0A;
1910825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville    public static final int STATUS_MESSAGE_EXPIRED       = 0x0D;
1920825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville    /* undefined-status codes */
1930825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville    public static final int ERROR_UNDEFINED              = 0xFF;
1940825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville    public static final int STATUS_UNDEFINED             = 0xFF;
1950825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville
1960825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville    public boolean messageStatusSet = false;
1970825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville    public int errorClass = ERROR_UNDEFINED;
1980825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville    public int messageStatus = STATUS_UNDEFINED;
1990825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville
2000825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville    /**
2010825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville     * 1-bit value that indicates whether a User Data Header (UDH) is present.
2020825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville     * (See 3GPP2 C.S0015-B, v2, 4.5.1)
2030825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville     *
2040825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville     * NOTE: during encoding, this value will be set based on the
2050825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville     * presence of a UDH in the structured data, any existing setting
2060825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville     * will be overwritten.
2070825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville     */
2080825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville    public boolean hasUserDataHeader;
2090825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville
2100825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville    /**
2110825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville     * provides the information for the user data
2120825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville     * (e.g. padding bits, user data, user data header, etc)
2130825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville     * (See 3GPP2 C.S.0015-B, v2, 4.5.2)
2140825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville     */
2150825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville    public UserData userData;
2160825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville
2170825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville    /**
2180825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville     * The User Response Code subparameter is used in the SMS User
2190825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville     * Acknowledgment Message to respond to previously received short
2200825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville     * messages. This message center-specific element carries the
2210825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville     * identifier of a predefined response. (See 3GPP2 C.S.0015-B, v2,
2220825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville     * 4.5.3)
2230825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville     */
2240825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville    public boolean userResponseCodeSet = false;
2250825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville    public int userResponseCode;
2260825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville
2270825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville    /**
2280825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville     * 6-byte-field, see 3GPP2 C.S0015-B, v2, 4.5.4
2290825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville     */
2300825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville    public static class TimeStamp extends Time {
2310825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville
2320825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        public TimeStamp() {
2330825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville            super(TimeZone.getDefault().getID());   // 3GPP2 timestamps use the local timezone
2340825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        }
2350825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville
2360825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        public static TimeStamp fromByteArray(byte[] data) {
2370825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville            TimeStamp ts = new TimeStamp();
2380825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville            // C.S0015-B v2.0, 4.5.4: range is 1996-2095
2390825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville            int year = IccUtils.cdmaBcdByteToInt(data[0]);
2400825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville            if (year > 99 || year < 0) return null;
2410825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville            ts.year = year >= 96 ? year + 1900 : year + 2000;
2420825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville            int month = IccUtils.cdmaBcdByteToInt(data[1]);
2430825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville            if (month < 1 || month > 12) return null;
2440825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville            ts.month = month - 1;
2450825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville            int day = IccUtils.cdmaBcdByteToInt(data[2]);
2460825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville            if (day < 1 || day > 31) return null;
2470825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville            ts.monthDay = day;
2480825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville            int hour = IccUtils.cdmaBcdByteToInt(data[3]);
2490825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville            if (hour < 0 || hour > 23) return null;
2500825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville            ts.hour = hour;
2510825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville            int minute = IccUtils.cdmaBcdByteToInt(data[4]);
2520825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville            if (minute < 0 || minute > 59) return null;
2530825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville            ts.minute = minute;
2540825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville            int second = IccUtils.cdmaBcdByteToInt(data[5]);
2550825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville            if (second < 0 || second > 59) return null;
2560825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville            ts.second = second;
2570825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville            return ts;
2580825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        }
2590825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville
2600825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        @Override
2610825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        public String toString() {
2620825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville            StringBuilder builder = new StringBuilder();
2630825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville            builder.append("TimeStamp ");
2640825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville            builder.append("{ year=" + year);
2650825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville            builder.append(", month=" + month);
2660825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville            builder.append(", day=" + monthDay);
2670825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville            builder.append(", hour=" + hour);
2680825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville            builder.append(", minute=" + minute);
2690825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville            builder.append(", second=" + second);
2700825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville            builder.append(" }");
2710825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville            return builder.toString();
2720825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        }
2730825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville    }
2740825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville
2750825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville    public TimeStamp msgCenterTimeStamp;
2760825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville    public TimeStamp validityPeriodAbsolute;
2770825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville    public TimeStamp deferredDeliveryTimeAbsolute;
2780825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville
2790825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville    /**
2800825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville     * Relative time is specified as one byte, the value of which
2810825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville     * falls into a series of ranges, as specified below.  The idea is
2820825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville     * that shorter time intervals allow greater precision -- the
2830825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville     * value means minutes from zero until the MINS_LIMIT (inclusive),
2840825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville     * upon which it means hours until the HOURS_LIMIT, and so
2850825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville     * forth. (See 3GPP2 C.S0015-B, v2, 4.5.6-1)
2860825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville     */
2870825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville    public static final int RELATIVE_TIME_MINS_LIMIT      = 143;
2880825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville    public static final int RELATIVE_TIME_HOURS_LIMIT     = 167;
2890825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville    public static final int RELATIVE_TIME_DAYS_LIMIT      = 196;
2900825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville    public static final int RELATIVE_TIME_WEEKS_LIMIT     = 244;
2910825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville    public static final int RELATIVE_TIME_INDEFINITE      = 245;
2920825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville    public static final int RELATIVE_TIME_NOW             = 246;
2930825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville    public static final int RELATIVE_TIME_MOBILE_INACTIVE = 247;
2940825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville    public static final int RELATIVE_TIME_RESERVED        = 248;
2950825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville
2960825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville    public boolean validityPeriodRelativeSet;
2970825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville    public int validityPeriodRelative;
2980825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville    public boolean deferredDeliveryTimeRelativeSet;
2990825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville    public int deferredDeliveryTimeRelative;
3000825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville
3010825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville    /**
3020825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville     * The Reply Option subparameter contains 1-bit values which
3030825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville     * indicate whether SMS acknowledgment is requested or not.  (See
3040825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville     * 3GPP2 C.S0015-B, v2, 4.5.11)
3050825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville     */
3060825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville    public boolean userAckReq;
3070825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville    public boolean deliveryAckReq;
3080825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville    public boolean readAckReq;
3090825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville    public boolean reportReq;
3100825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville
3110825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville    /**
3120825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville     * The Number of Messages subparameter (8-bit value) is a decimal
3130825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville     * number in the 0 to 99 range representing the number of messages
3140825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville     * stored at the Voice Mail System. This element is used by the
3150825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville     * Voice Mail Notification service.  (See 3GPP2 C.S0015-B, v2,
3160825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville     * 4.5.12)
3170825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville     */
3180825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville    public int numberOfMessages;
3190825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville
3200825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville    /**
3210825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville     * The Message Deposit Index subparameter is assigned by the
3220825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville     * message center as a unique index to the contents of the User
3230825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville     * Data subparameter in each message sent to a particular mobile
3240825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville     * station. The mobile station, when replying to a previously
3250825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville     * received short message which included a Message Deposit Index
3260825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville     * subparameter, may include the Message Deposit Index of the
3270825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville     * received message to indicate to the message center that the
3280825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville     * original contents of the message are to be included in the
3290825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville     * reply.  (See 3GPP2 C.S0015-B, v2, 4.5.18)
3300825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville     */
3310825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville    public int depositIndex;
3320825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville
3330825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville    /**
3340825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville     * 4-bit or 8-bit value that indicates the number to be dialed in reply to a
3350825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville     * received SMS message.
3360825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville     * (See 3GPP2 C.S0015-B, v2, 4.5.15)
3370825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville     */
3380825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville    public CdmaSmsAddress callbackNumber;
3390825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville
3400825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville    /**
3410825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville     * CMAS warning notification information.
3420825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville     * @see #decodeCmasUserData(BearerData, int)
3430825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville     */
3440825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville    public SmsCbCmasInfo cmasWarningInfo;
3450825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville
3460825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville    /**
3470825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville     * The Service Category Program Data subparameter is used to enable and disable
3480825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville     * SMS broadcast service categories to display. If this subparameter is present,
3490825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville     * this field will contain a list of one or more
3500825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville     * {@link android.telephony.cdma.CdmaSmsCbProgramData} objects containing the
3510825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville     * operation(s) to perform.
3520825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville     */
353b8a13d300b245e0080aa01275e232f54d5d0e09cJake Hamby    public ArrayList<CdmaSmsCbProgramData> serviceCategoryProgramData;
354b8a13d300b245e0080aa01275e232f54d5d0e09cJake Hamby
355b8a13d300b245e0080aa01275e232f54d5d0e09cJake Hamby    /**
356b8a13d300b245e0080aa01275e232f54d5d0e09cJake Hamby     * The Service Category Program Results subparameter informs the message center
357b8a13d300b245e0080aa01275e232f54d5d0e09cJake Hamby     * of the results of a Service Category Program Data request.
358b8a13d300b245e0080aa01275e232f54d5d0e09cJake Hamby     */
359b8a13d300b245e0080aa01275e232f54d5d0e09cJake Hamby    public ArrayList<CdmaSmsCbProgramResults> serviceCategoryProgramResults;
360b8a13d300b245e0080aa01275e232f54d5d0e09cJake Hamby
3610825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville
3620825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville    private static class CodingException extends Exception {
3630825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        public CodingException(String s) {
3640825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville            super(s);
3650825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        }
3660825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville    }
3670825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville
3680825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville    /**
3690825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville     * Returns the language indicator as a two-character ISO 639 string.
3700825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville     * @return a two character ISO 639 language code
3710825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville     */
3720825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville    public String getLanguage() {
3730825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        return getLanguageCodeForValue(language);
3740825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville    }
3750825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville
3760825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville    /**
3770825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville     * Converts a CDMA language indicator value to an ISO 639 two character language code.
3780825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville     * @param languageValue the CDMA language value to convert
3790825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville     * @return the two character ISO 639 language code for the specified value, or null if unknown
3800825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville     */
3810825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville    private static String getLanguageCodeForValue(int languageValue) {
3820825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        switch (languageValue) {
3830825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville            case LANGUAGE_ENGLISH:
3840825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville                return "en";
3850825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville
3860825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville            case LANGUAGE_FRENCH:
3870825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville                return "fr";
3880825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville
3890825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville            case LANGUAGE_SPANISH:
3900825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville                return "es";
3910825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville
3920825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville            case LANGUAGE_JAPANESE:
3930825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville                return "ja";
3940825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville
3950825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville            case LANGUAGE_KOREAN:
3960825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville                return "ko";
3970825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville
3980825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville            case LANGUAGE_CHINESE:
3990825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville                return "zh";
4000825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville
4010825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville            case LANGUAGE_HEBREW:
4020825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville                return "he";
4030825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville
4040825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville            default:
4050825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville                return null;
4060825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        }
4070825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville    }
4080825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville
4090825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville    @Override
4100825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville    public String toString() {
4110825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        StringBuilder builder = new StringBuilder();
4120825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        builder.append("BearerData ");
4130825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        builder.append("{ messageType=" + messageType);
414cbaa45bbf2cab852b6c9c3a887e9f803d4e857eaWink Saville        builder.append(", messageId=" + messageId);
4150825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        builder.append(", priority=" + (priorityIndicatorSet ? priority : "unset"));
4160825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        builder.append(", privacy=" + (privacyIndicatorSet ? privacy : "unset"));
4170825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        builder.append(", alert=" + (alertIndicatorSet ? alert : "unset"));
4180825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        builder.append(", displayMode=" + (displayModeSet ? displayMode : "unset"));
4190825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        builder.append(", language=" + (languageIndicatorSet ? language : "unset"));
4200825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        builder.append(", errorClass=" + (messageStatusSet ? errorClass : "unset"));
4210825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        builder.append(", msgStatus=" + (messageStatusSet ? messageStatus : "unset"));
4220825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        builder.append(", msgCenterTimeStamp=" +
4230825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville                ((msgCenterTimeStamp != null) ? msgCenterTimeStamp : "unset"));
4240825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        builder.append(", validityPeriodAbsolute=" +
4250825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville                ((validityPeriodAbsolute != null) ? validityPeriodAbsolute : "unset"));
4260825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        builder.append(", validityPeriodRelative=" +
4270825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville                ((validityPeriodRelativeSet) ? validityPeriodRelative : "unset"));
4280825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        builder.append(", deferredDeliveryTimeAbsolute=" +
4290825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville                ((deferredDeliveryTimeAbsolute != null) ? deferredDeliveryTimeAbsolute : "unset"));
4300825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        builder.append(", deferredDeliveryTimeRelative=" +
4310825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville                ((deferredDeliveryTimeRelativeSet) ? deferredDeliveryTimeRelative : "unset"));
4320825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        builder.append(", userAckReq=" + userAckReq);
4330825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        builder.append(", deliveryAckReq=" + deliveryAckReq);
4340825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        builder.append(", readAckReq=" + readAckReq);
4350825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        builder.append(", reportReq=" + reportReq);
4360825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        builder.append(", numberOfMessages=" + numberOfMessages);
4370825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        builder.append(", callbackNumber=" + callbackNumber);
4380825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        builder.append(", depositIndex=" + depositIndex);
4390825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        builder.append(", hasUserDataHeader=" + hasUserDataHeader);
4400825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        builder.append(", userData=" + userData);
4410825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        builder.append(" }");
4420825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        return builder.toString();
4430825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville    }
4440825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville
4450825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville    private static void encodeMessageId(BearerData bData, BitwiseOutputStream outStream)
4460825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        throws BitwiseOutputStream.AccessException
4470825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville    {
4480825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        outStream.write(8, 3);
4490825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        outStream.write(4, bData.messageType);
4500825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        outStream.write(8, bData.messageId >> 8);
4510825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        outStream.write(8, bData.messageId);
4520825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        outStream.write(1, bData.hasUserDataHeader ? 1 : 0);
4530825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        outStream.skip(3);
4540825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville    }
4550825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville
4560825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville    private static int countAsciiSeptets(CharSequence msg, boolean force) {
4570825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        int msgLen = msg.length();
4580825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        if (force) return msgLen;
4590825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        for (int i = 0; i < msgLen; i++) {
4600825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville            if (UserData.charToAscii.get(msg.charAt(i), -1) == -1) {
4610825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville                return -1;
4620825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville            }
4630825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        }
4640825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        return msgLen;
4650825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville    }
4660825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville
4670825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville    /**
4680825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville     * Calculate the message text encoding length, fragmentation, and other details.
4690825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville     *
4700825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville     * @param msg message text
4710825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville     * @param force7BitEncoding ignore (but still count) illegal characters if true
4720825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville     * @return septet count, or -1 on failure
4730825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville     */
4740825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville    public static TextEncodingDetails calcTextEncodingDetails(CharSequence msg,
4750825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville            boolean force7BitEncoding) {
4760825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        TextEncodingDetails ted;
4770825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        int septets = countAsciiSeptets(msg, force7BitEncoding);
4780825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        if (septets != -1 && septets <= SmsConstants.MAX_USER_DATA_SEPTETS) {
4790825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville            ted = new TextEncodingDetails();
4800825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville            ted.msgCount = 1;
4810825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville            ted.codeUnitCount = septets;
4820825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville            ted.codeUnitsRemaining = SmsConstants.MAX_USER_DATA_SEPTETS - septets;
4830825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville            ted.codeUnitSize = SmsConstants.ENCODING_7BIT;
4840825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        } else {
4850825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville            ted = com.android.internal.telephony.gsm.SmsMessage.calculateLength(
4860825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville                    msg, force7BitEncoding);
4870825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville            if (ted.msgCount == 1 && ted.codeUnitSize == SmsConstants.ENCODING_7BIT) {
4880825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville                // We don't support single-segment EMS, so calculate for 16-bit
4890825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville                // TODO: Consider supporting single-segment EMS
4900825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville                ted.codeUnitCount = msg.length();
4910825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville                int octets = ted.codeUnitCount * 2;
4920825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville                if (octets > SmsConstants.MAX_USER_DATA_BYTES) {
4930825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville                    ted.msgCount = (octets + (SmsConstants.MAX_USER_DATA_BYTES_WITH_HEADER - 1)) /
4940825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville                            SmsConstants.MAX_USER_DATA_BYTES_WITH_HEADER;
4950825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville                    ted.codeUnitsRemaining = ((ted.msgCount *
4960825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville                            SmsConstants.MAX_USER_DATA_BYTES_WITH_HEADER) - octets) / 2;
4970825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville                } else {
4980825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville                    ted.msgCount = 1;
4990825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville                    ted.codeUnitsRemaining = (SmsConstants.MAX_USER_DATA_BYTES - octets)/2;
5000825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville                }
5010825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville                ted.codeUnitSize = SmsConstants.ENCODING_16BIT;
5020825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville            }
5030825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        }
5040825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        return ted;
5050825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville    }
5060825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville
5070825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville    private static byte[] encode7bitAscii(String msg, boolean force)
5080825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        throws CodingException
5090825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville    {
5100825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        try {
5110825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville            BitwiseOutputStream outStream = new BitwiseOutputStream(msg.length());
5120825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville            int msgLen = msg.length();
5130825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville            for (int i = 0; i < msgLen; i++) {
5140825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville                int charCode = UserData.charToAscii.get(msg.charAt(i), -1);
5150825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville                if (charCode == -1) {
5160825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville                    if (force) {
5170825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville                        outStream.write(7, UserData.UNENCODABLE_7_BIT_CHAR);
5180825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville                    } else {
5190825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville                        throw new CodingException("cannot ASCII encode (" + msg.charAt(i) + ")");
5200825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville                    }
5210825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville                } else {
5220825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville                    outStream.write(7, charCode);
5230825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville                }
5240825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville            }
5250825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville            return outStream.toByteArray();
5260825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        } catch (BitwiseOutputStream.AccessException ex) {
5270825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville            throw new CodingException("7bit ASCII encode failed: " + ex);
5280825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        }
5290825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville    }
5300825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville
5310825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville    private static byte[] encodeUtf16(String msg)
5320825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        throws CodingException
5330825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville    {
5340825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        try {
5350825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville            return msg.getBytes("utf-16be");
5360825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        } catch (java.io.UnsupportedEncodingException ex) {
5370825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville            throw new CodingException("UTF-16 encode failed: " + ex);
5380825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        }
5390825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville    }
5400825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville
5410825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville    private static class Gsm7bitCodingResult {
5420825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        int septets;
5430825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        byte[] data;
5440825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville    }
5450825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville
5460825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville    private static Gsm7bitCodingResult encode7bitGsm(String msg, int septetOffset, boolean force)
5470825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        throws CodingException
5480825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville    {
5490825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        try {
5500825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville            /*
5510825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville             * TODO(cleanup): It would be nice if GsmAlphabet provided
5520825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville             * an option to produce just the data without prepending
5530825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville             * the septet count, as this function is really just a
5540825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville             * wrapper to strip that off.  Not to mention that the
5550825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville             * septet count is generally known prior to invocation of
5560825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville             * the encoder.  Note that it cannot be derived from the
5570825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville             * resulting array length, since that cannot distinguish
5580825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville             * if the last contains either 1 or 8 valid bits.
5590825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville             *
5600825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville             * TODO(cleanup): The BitwiseXStreams could also be
5610825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville             * extended with byte-wise reversed endianness read/write
5620825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville             * routines to allow a corresponding implementation of
5630825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville             * stringToGsm7BitPacked, and potentially directly support
5640825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville             * access to the main bitwise stream from encode/decode.
5650825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville             */
5660825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville            byte[] fullData = GsmAlphabet.stringToGsm7BitPacked(msg, septetOffset, !force, 0, 0);
5670825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville            Gsm7bitCodingResult result = new Gsm7bitCodingResult();
5680825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville            result.data = new byte[fullData.length - 1];
5690825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville            System.arraycopy(fullData, 1, result.data, 0, fullData.length - 1);
5700825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville            result.septets = fullData[0] & 0x00FF;
5710825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville            return result;
5720825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        } catch (com.android.internal.telephony.EncodeException ex) {
5730825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville            throw new CodingException("7bit GSM encode failed: " + ex);
5740825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        }
5750825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville    }
5760825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville
5770825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville    private static void encode7bitEms(UserData uData, byte[] udhData, boolean force)
5780825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        throws CodingException
5790825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville    {
5800825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        int udhBytes = udhData.length + 1;  // Add length octet.
5810825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        int udhSeptets = ((udhBytes * 8) + 6) / 7;
5820825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        Gsm7bitCodingResult gcr = encode7bitGsm(uData.payloadStr, udhSeptets, force);
5830825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        uData.msgEncoding = UserData.ENCODING_GSM_7BIT_ALPHABET;
5840825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        uData.msgEncodingSet = true;
5850825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        uData.numFields = gcr.septets;
5860825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        uData.payload = gcr.data;
5870825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        uData.payload[0] = (byte)udhData.length;
5880825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        System.arraycopy(udhData, 0, uData.payload, 1, udhData.length);
5890825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville    }
5900825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville
5910825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville    private static void encode16bitEms(UserData uData, byte[] udhData)
5920825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        throws CodingException
5930825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville    {
5940825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        byte[] payload = encodeUtf16(uData.payloadStr);
5950825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        int udhBytes = udhData.length + 1;  // Add length octet.
5960825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        int udhCodeUnits = (udhBytes + 1) / 2;
5970825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        int payloadCodeUnits = payload.length / 2;
5980825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        uData.msgEncoding = UserData.ENCODING_UNICODE_16;
5990825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        uData.msgEncodingSet = true;
6000825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        uData.numFields = udhCodeUnits + payloadCodeUnits;
6010825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        uData.payload = new byte[uData.numFields * 2];
6020825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        uData.payload[0] = (byte)udhData.length;
6030825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        System.arraycopy(udhData, 0, uData.payload, 1, udhData.length);
604115632cc56f813bd21543f8532c763d7d2968046Jake Hamby        System.arraycopy(payload, 0, uData.payload, udhBytes, payload.length);
6050825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville    }
6060825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville
6070825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville    private static void encodeEmsUserDataPayload(UserData uData)
6080825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        throws CodingException
6090825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville    {
6100825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        byte[] headerData = SmsHeader.toByteArray(uData.userDataHeader);
6110825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        if (uData.msgEncodingSet) {
6120825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville            if (uData.msgEncoding == UserData.ENCODING_GSM_7BIT_ALPHABET) {
6130825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville                encode7bitEms(uData, headerData, true);
6140825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville            } else if (uData.msgEncoding == UserData.ENCODING_UNICODE_16) {
6150825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville                encode16bitEms(uData, headerData);
6160825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville            } else {
6170825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville                throw new CodingException("unsupported EMS user data encoding (" +
6180825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville                                          uData.msgEncoding + ")");
6190825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville            }
6200825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        } else {
6210825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville            try {
6220825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville                encode7bitEms(uData, headerData, false);
6230825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville            } catch (CodingException ex) {
6240825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville                encode16bitEms(uData, headerData);
6250825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville            }
6260825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        }
6270825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville    }
6280825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville
6293de1a7e5535f36e86d82da12df2b17aeeafabdc6Rika Brooks    private static byte[] encodeShiftJis(String msg) throws CodingException {
6303de1a7e5535f36e86d82da12df2b17aeeafabdc6Rika Brooks        try {
6313de1a7e5535f36e86d82da12df2b17aeeafabdc6Rika Brooks            return msg.getBytes("Shift_JIS");
6323de1a7e5535f36e86d82da12df2b17aeeafabdc6Rika Brooks        } catch (java.io.UnsupportedEncodingException ex) {
6333de1a7e5535f36e86d82da12df2b17aeeafabdc6Rika Brooks            throw new CodingException("Shift-JIS encode failed: " + ex);
6343de1a7e5535f36e86d82da12df2b17aeeafabdc6Rika Brooks        }
6353de1a7e5535f36e86d82da12df2b17aeeafabdc6Rika Brooks    }
6363de1a7e5535f36e86d82da12df2b17aeeafabdc6Rika Brooks
6370825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville    private static void encodeUserDataPayload(UserData uData)
6380825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        throws CodingException
6390825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville    {
6400825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        if ((uData.payloadStr == null) && (uData.msgEncoding != UserData.ENCODING_OCTET)) {
641ded9c0af7fa49504c047275ed34c2d3b22bf0c3aWink Saville            Rlog.e(LOG_TAG, "user data with null payloadStr");
6420825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville            uData.payloadStr = "";
6430825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        }
6440825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville
6450825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        if (uData.userDataHeader != null) {
6460825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville            encodeEmsUserDataPayload(uData);
6470825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville            return;
6480825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        }
6490825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville
6500825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        if (uData.msgEncodingSet) {
6510825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville            if (uData.msgEncoding == UserData.ENCODING_OCTET) {
6520825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville                if (uData.payload == null) {
653ded9c0af7fa49504c047275ed34c2d3b22bf0c3aWink Saville                    Rlog.e(LOG_TAG, "user data with octet encoding but null payload");
6540825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville                    uData.payload = new byte[0];
6550825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville                    uData.numFields = 0;
6560825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville                } else {
6570825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville                    uData.numFields = uData.payload.length;
6580825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville                }
6590825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville            } else {
6600825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville                if (uData.payloadStr == null) {
661ded9c0af7fa49504c047275ed34c2d3b22bf0c3aWink Saville                    Rlog.e(LOG_TAG, "non-octet user data with null payloadStr");
6620825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville                    uData.payloadStr = "";
6630825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville                }
6640825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville                if (uData.msgEncoding == UserData.ENCODING_GSM_7BIT_ALPHABET) {
6650825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville                    Gsm7bitCodingResult gcr = encode7bitGsm(uData.payloadStr, 0, true);
6660825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville                    uData.payload = gcr.data;
6670825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville                    uData.numFields = gcr.septets;
6680825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville                } else if (uData.msgEncoding == UserData.ENCODING_7BIT_ASCII) {
6690825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville                    uData.payload = encode7bitAscii(uData.payloadStr, true);
6700825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville                    uData.numFields = uData.payloadStr.length();
6710825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville                } else if (uData.msgEncoding == UserData.ENCODING_UNICODE_16) {
6720825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville                    uData.payload = encodeUtf16(uData.payloadStr);
6730825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville                    uData.numFields = uData.payloadStr.length();
6743de1a7e5535f36e86d82da12df2b17aeeafabdc6Rika Brooks                } else if (uData.msgEncoding == UserData.ENCODING_SHIFT_JIS) {
6753de1a7e5535f36e86d82da12df2b17aeeafabdc6Rika Brooks                    uData.payload = encodeShiftJis(uData.payloadStr);
6763de1a7e5535f36e86d82da12df2b17aeeafabdc6Rika Brooks                    uData.numFields = uData.payload.length;
6770825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville                } else {
6780825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville                    throw new CodingException("unsupported user data encoding (" +
6790825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville                                              uData.msgEncoding + ")");
6800825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville                }
6810825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville            }
6820825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        } else {
6830825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville            try {
6840825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville                uData.payload = encode7bitAscii(uData.payloadStr, false);
6850825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville                uData.msgEncoding = UserData.ENCODING_7BIT_ASCII;
6860825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville            } catch (CodingException ex) {
6870825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville                uData.payload = encodeUtf16(uData.payloadStr);
6880825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville                uData.msgEncoding = UserData.ENCODING_UNICODE_16;
6890825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville            }
6900825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville            uData.numFields = uData.payloadStr.length();
6910825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville            uData.msgEncodingSet = true;
6920825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        }
6930825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville    }
6940825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville
6950825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville    private static void encodeUserData(BearerData bData, BitwiseOutputStream outStream)
6960825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        throws BitwiseOutputStream.AccessException, CodingException
6970825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville    {
6980825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        /*
6990825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville         * TODO(cleanup): Do we really need to set userData.payload as
7000825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville         * a side effect of encoding?  If not, we could avoid data
7010825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville         * copies by passing outStream directly.
7020825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville         */
7030825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        encodeUserDataPayload(bData.userData);
7040825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        bData.hasUserDataHeader = bData.userData.userDataHeader != null;
7050825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville
7060825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        if (bData.userData.payload.length > SmsConstants.MAX_USER_DATA_BYTES) {
7070825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville            throw new CodingException("encoded user data too large (" +
7080825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville                                      bData.userData.payload.length +
7090825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville                                      " > " + SmsConstants.MAX_USER_DATA_BYTES + " bytes)");
7100825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        }
7110825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville
7120825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        /*
7130825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville         * TODO(cleanup): figure out what the right answer is WRT paddingBits field
7140825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville         *
7150825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville         *   userData.paddingBits = (userData.payload.length * 8) - (userData.numFields * 7);
7160825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville         *   userData.paddingBits = 0; // XXX this seems better, but why?
7170825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville         *
7180825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville         */
7190825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        int dataBits = (bData.userData.payload.length * 8) - bData.userData.paddingBits;
7200825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        int paramBits = dataBits + 13;
7210825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        if ((bData.userData.msgEncoding == UserData.ENCODING_IS91_EXTENDED_PROTOCOL) ||
7220825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville            (bData.userData.msgEncoding == UserData.ENCODING_GSM_DCS)) {
7230825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville            paramBits += 8;
7240825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        }
7250825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        int paramBytes = (paramBits / 8) + ((paramBits % 8) > 0 ? 1 : 0);
7260825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        int paddingBits = (paramBytes * 8) - paramBits;
7270825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        outStream.write(8, paramBytes);
7280825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        outStream.write(5, bData.userData.msgEncoding);
7290825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        if ((bData.userData.msgEncoding == UserData.ENCODING_IS91_EXTENDED_PROTOCOL) ||
7300825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville            (bData.userData.msgEncoding == UserData.ENCODING_GSM_DCS)) {
7310825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville            outStream.write(8, bData.userData.msgType);
7320825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        }
7330825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        outStream.write(8, bData.userData.numFields);
7340825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        outStream.writeByteArray(dataBits, bData.userData.payload);
7350825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        if (paddingBits > 0) outStream.write(paddingBits, 0);
7360825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville    }
7370825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville
7380825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville    private static void encodeReplyOption(BearerData bData, BitwiseOutputStream outStream)
7390825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        throws BitwiseOutputStream.AccessException
7400825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville    {
7410825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        outStream.write(8, 1);
7420825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        outStream.write(1, bData.userAckReq     ? 1 : 0);
7430825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        outStream.write(1, bData.deliveryAckReq ? 1 : 0);
7440825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        outStream.write(1, bData.readAckReq     ? 1 : 0);
7450825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        outStream.write(1, bData.reportReq      ? 1 : 0);
7460825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        outStream.write(4, 0);
7470825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville    }
7480825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville
7490825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville    private static byte[] encodeDtmfSmsAddress(String address) {
7500825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        int digits = address.length();
7510825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        int dataBits = digits * 4;
7520825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        int dataBytes = (dataBits / 8);
7530825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        dataBytes += (dataBits % 8) > 0 ? 1 : 0;
7540825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        byte[] rawData = new byte[dataBytes];
7550825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        for (int i = 0; i < digits; i++) {
7560825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville            char c = address.charAt(i);
7570825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville            int val = 0;
7580825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville            if ((c >= '1') && (c <= '9')) val = c - '0';
7590825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville            else if (c == '0') val = 10;
7600825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville            else if (c == '*') val = 11;
7610825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville            else if (c == '#') val = 12;
7620825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville            else return null;
7630825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville            rawData[i / 2] |= val << (4 - ((i % 2) * 4));
7640825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        }
7650825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        return rawData;
7660825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville    }
7670825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville
7680825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville    /*
7690825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville     * TODO(cleanup): CdmaSmsAddress encoding should make use of
7700825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville     * CdmaSmsAddress.parse provided that DTMF encoding is unified,
7710825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville     * and the difference in 4-bit vs. 8-bit is resolved.
7720825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville     */
7730825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville
7740825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville    private static void encodeCdmaSmsAddress(CdmaSmsAddress addr) throws CodingException {
7750825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        if (addr.digitMode == CdmaSmsAddress.DIGIT_MODE_8BIT_CHAR) {
7760825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville            try {
7770825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville                addr.origBytes = addr.address.getBytes("US-ASCII");
7780825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville            } catch (java.io.UnsupportedEncodingException ex) {
7790825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville                throw new CodingException("invalid SMS address, cannot convert to ASCII");
7800825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville            }
7810825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        } else {
7820825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville            addr.origBytes = encodeDtmfSmsAddress(addr.address);
7830825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        }
7840825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville    }
7850825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville
7860825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville    private static void encodeCallbackNumber(BearerData bData, BitwiseOutputStream outStream)
7870825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        throws BitwiseOutputStream.AccessException, CodingException
7880825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville    {
7890825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        CdmaSmsAddress addr = bData.callbackNumber;
7900825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        encodeCdmaSmsAddress(addr);
7910825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        int paramBits = 9;
7920825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        int dataBits = 0;
7930825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        if (addr.digitMode == CdmaSmsAddress.DIGIT_MODE_8BIT_CHAR) {
7940825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville            paramBits += 7;
7950825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville            dataBits = addr.numberOfDigits * 8;
7960825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        } else {
7970825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville            dataBits = addr.numberOfDigits * 4;
7980825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        }
7990825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        paramBits += dataBits;
8000825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        int paramBytes = (paramBits / 8) + ((paramBits % 8) > 0 ? 1 : 0);
8010825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        int paddingBits = (paramBytes * 8) - paramBits;
8020825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        outStream.write(8, paramBytes);
8030825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        outStream.write(1, addr.digitMode);
8040825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        if (addr.digitMode == CdmaSmsAddress.DIGIT_MODE_8BIT_CHAR) {
8050825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville            outStream.write(3, addr.ton);
8060825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville            outStream.write(4, addr.numberPlan);
8070825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        }
8080825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        outStream.write(8, addr.numberOfDigits);
8090825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        outStream.writeByteArray(dataBits, addr.origBytes);
8100825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        if (paddingBits > 0) outStream.write(paddingBits, 0);
8110825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville    }
8120825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville
8130825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville    private static void encodeMsgStatus(BearerData bData, BitwiseOutputStream outStream)
8140825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        throws BitwiseOutputStream.AccessException
8150825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville    {
8160825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        outStream.write(8, 1);
8170825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        outStream.write(2, bData.errorClass);
8180825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        outStream.write(6, bData.messageStatus);
8190825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville    }
8200825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville
8210825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville    private static void encodeMsgCount(BearerData bData, BitwiseOutputStream outStream)
8220825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        throws BitwiseOutputStream.AccessException
8230825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville    {
8240825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        outStream.write(8, 1);
8250825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        outStream.write(8, bData.numberOfMessages);
8260825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville    }
8270825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville
8280825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville    private static void encodeValidityPeriodRel(BearerData bData, BitwiseOutputStream outStream)
8290825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        throws BitwiseOutputStream.AccessException
8300825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville    {
8310825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        outStream.write(8, 1);
8320825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        outStream.write(8, bData.validityPeriodRelative);
8330825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville    }
8340825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville
8350825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville    private static void encodePrivacyIndicator(BearerData bData, BitwiseOutputStream outStream)
8360825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        throws BitwiseOutputStream.AccessException
8370825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville    {
8380825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        outStream.write(8, 1);
8390825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        outStream.write(2, bData.privacy);
8400825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        outStream.skip(6);
8410825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville    }
8420825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville
8430825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville    private static void encodeLanguageIndicator(BearerData bData, BitwiseOutputStream outStream)
8440825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        throws BitwiseOutputStream.AccessException
8450825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville    {
8460825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        outStream.write(8, 1);
8470825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        outStream.write(8, bData.language);
8480825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville    }
8490825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville
8500825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville    private static void encodeDisplayMode(BearerData bData, BitwiseOutputStream outStream)
8510825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        throws BitwiseOutputStream.AccessException
8520825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville    {
8530825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        outStream.write(8, 1);
8540825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        outStream.write(2, bData.displayMode);
8550825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        outStream.skip(6);
8560825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville    }
8570825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville
8580825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville    private static void encodePriorityIndicator(BearerData bData, BitwiseOutputStream outStream)
8590825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        throws BitwiseOutputStream.AccessException
8600825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville    {
8610825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        outStream.write(8, 1);
8620825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        outStream.write(2, bData.priority);
8630825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        outStream.skip(6);
8640825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville    }
8650825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville
8660825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville    private static void encodeMsgDeliveryAlert(BearerData bData, BitwiseOutputStream outStream)
8670825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        throws BitwiseOutputStream.AccessException
8680825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville    {
8690825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        outStream.write(8, 1);
8700825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        outStream.write(2, bData.alert);
8710825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        outStream.skip(6);
8720825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville    }
8730825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville
874b8a13d300b245e0080aa01275e232f54d5d0e09cJake Hamby    private static void encodeScpResults(BearerData bData, BitwiseOutputStream outStream)
875b8a13d300b245e0080aa01275e232f54d5d0e09cJake Hamby        throws BitwiseOutputStream.AccessException
876b8a13d300b245e0080aa01275e232f54d5d0e09cJake Hamby    {
877b8a13d300b245e0080aa01275e232f54d5d0e09cJake Hamby        ArrayList<CdmaSmsCbProgramResults> results = bData.serviceCategoryProgramResults;
878b8a13d300b245e0080aa01275e232f54d5d0e09cJake Hamby        outStream.write(8, (results.size() * 4));   // 4 octets per program result
879b8a13d300b245e0080aa01275e232f54d5d0e09cJake Hamby        for (CdmaSmsCbProgramResults result : results) {
880b8a13d300b245e0080aa01275e232f54d5d0e09cJake Hamby            int category = result.getCategory();
881b8a13d300b245e0080aa01275e232f54d5d0e09cJake Hamby            outStream.write(8, category >> 8);
882b8a13d300b245e0080aa01275e232f54d5d0e09cJake Hamby            outStream.write(8, category);
883b8a13d300b245e0080aa01275e232f54d5d0e09cJake Hamby            outStream.write(8, result.getLanguage());
884b8a13d300b245e0080aa01275e232f54d5d0e09cJake Hamby            outStream.write(4, result.getCategoryResult());
885b8a13d300b245e0080aa01275e232f54d5d0e09cJake Hamby            outStream.skip(4);
886b8a13d300b245e0080aa01275e232f54d5d0e09cJake Hamby        }
887b8a13d300b245e0080aa01275e232f54d5d0e09cJake Hamby    }
888b8a13d300b245e0080aa01275e232f54d5d0e09cJake Hamby
8890825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville    /**
8900825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville     * Create serialized representation for BearerData object.
8910825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville     * (See 3GPP2 C.R1001-F, v1.0, section 4.5 for layout details)
8920825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville     *
8930825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville     * @param bData an instance of BearerData.
8940825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville     *
8950825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville     * @return byte array of raw encoded SMS bearer data.
8960825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville     */
8970825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville    public static byte[] encode(BearerData bData) {
8980825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        bData.hasUserDataHeader = ((bData.userData != null) &&
8990825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville                (bData.userData.userDataHeader != null));
9000825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        try {
9010825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville            BitwiseOutputStream outStream = new BitwiseOutputStream(200);
9020825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville            outStream.write(8, SUBPARAM_MESSAGE_IDENTIFIER);
9030825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville            encodeMessageId(bData, outStream);
9040825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville            if (bData.userData != null) {
9050825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville                outStream.write(8, SUBPARAM_USER_DATA);
9060825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville                encodeUserData(bData, outStream);
9070825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville            }
9080825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville            if (bData.callbackNumber != null) {
9090825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville                outStream.write(8, SUBPARAM_CALLBACK_NUMBER);
9100825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville                encodeCallbackNumber(bData, outStream);
9110825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville            }
9120825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville            if (bData.userAckReq || bData.deliveryAckReq || bData.readAckReq || bData.reportReq) {
9130825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville                outStream.write(8, SUBPARAM_REPLY_OPTION);
9140825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville                encodeReplyOption(bData, outStream);
9150825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville            }
9160825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville            if (bData.numberOfMessages != 0) {
9170825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville                outStream.write(8, SUBPARAM_NUMBER_OF_MESSAGES);
9180825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville                encodeMsgCount(bData, outStream);
9190825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville            }
9200825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville            if (bData.validityPeriodRelativeSet) {
9210825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville                outStream.write(8, SUBPARAM_VALIDITY_PERIOD_RELATIVE);
9220825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville                encodeValidityPeriodRel(bData, outStream);
9230825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville            }
9240825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville            if (bData.privacyIndicatorSet) {
9250825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville                outStream.write(8, SUBPARAM_PRIVACY_INDICATOR);
9260825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville                encodePrivacyIndicator(bData, outStream);
9270825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville            }
9280825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville            if (bData.languageIndicatorSet) {
9290825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville                outStream.write(8, SUBPARAM_LANGUAGE_INDICATOR);
9300825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville                encodeLanguageIndicator(bData, outStream);
9310825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville            }
9320825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville            if (bData.displayModeSet) {
9330825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville                outStream.write(8, SUBPARAM_MESSAGE_DISPLAY_MODE);
9340825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville                encodeDisplayMode(bData, outStream);
9350825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville            }
9360825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville            if (bData.priorityIndicatorSet) {
9370825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville                outStream.write(8, SUBPARAM_PRIORITY_INDICATOR);
9380825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville                encodePriorityIndicator(bData, outStream);
9390825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville            }
9400825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville            if (bData.alertIndicatorSet) {
9410825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville                outStream.write(8, SUBPARAM_ALERT_ON_MESSAGE_DELIVERY);
9420825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville                encodeMsgDeliveryAlert(bData, outStream);
9430825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville            }
9440825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville            if (bData.messageStatusSet) {
9450825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville                outStream.write(8, SUBPARAM_MESSAGE_STATUS);
9460825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville                encodeMsgStatus(bData, outStream);
9470825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville            }
948b8a13d300b245e0080aa01275e232f54d5d0e09cJake Hamby            if (bData.serviceCategoryProgramResults != null) {
949b8a13d300b245e0080aa01275e232f54d5d0e09cJake Hamby                outStream.write(8, SUBPARAM_SERVICE_CATEGORY_PROGRAM_RESULTS);
950b8a13d300b245e0080aa01275e232f54d5d0e09cJake Hamby                encodeScpResults(bData, outStream);
951b8a13d300b245e0080aa01275e232f54d5d0e09cJake Hamby            }
9520825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville            return outStream.toByteArray();
9530825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        } catch (BitwiseOutputStream.AccessException ex) {
954ded9c0af7fa49504c047275ed34c2d3b22bf0c3aWink Saville            Rlog.e(LOG_TAG, "BearerData encode failed: " + ex);
9550825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        } catch (CodingException ex) {
956ded9c0af7fa49504c047275ed34c2d3b22bf0c3aWink Saville            Rlog.e(LOG_TAG, "BearerData encode failed: " + ex);
9570825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        }
9580825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        return null;
9590825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville   }
9600825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville
9610825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville    private static boolean decodeMessageId(BearerData bData, BitwiseInputStream inStream)
962cbaa45bbf2cab852b6c9c3a887e9f803d4e857eaWink Saville        throws BitwiseInputStream.AccessException {
9630825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        final int EXPECTED_PARAM_SIZE = 3 * 8;
9640825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        boolean decodeSuccess = false;
9650825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        int paramBits = inStream.read(8) * 8;
9660825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        if (paramBits >= EXPECTED_PARAM_SIZE) {
9670825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville            paramBits -= EXPECTED_PARAM_SIZE;
9680825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville            decodeSuccess = true;
9690825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville            bData.messageType = inStream.read(4);
9700825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville            bData.messageId = inStream.read(8) << 8;
9710825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville            bData.messageId |= inStream.read(8);
9720825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville            bData.hasUserDataHeader = (inStream.read(1) == 1);
9730825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville            inStream.skip(3);
9740825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        }
9750825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        if ((! decodeSuccess) || (paramBits > 0)) {
976ded9c0af7fa49504c047275ed34c2d3b22bf0c3aWink Saville            Rlog.d(LOG_TAG, "MESSAGE_IDENTIFIER decode " +
9770825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville                      (decodeSuccess ? "succeeded" : "failed") +
9780825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville                      " (extra bits = " + paramBits + ")");
9790825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        }
9800825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        inStream.skip(paramBits);
9810825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        return decodeSuccess;
9820825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville    }
9830825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville
9843de1a7e5535f36e86d82da12df2b17aeeafabdc6Rika Brooks    private static boolean decodeReserved(
9853de1a7e5535f36e86d82da12df2b17aeeafabdc6Rika Brooks            BearerData bData, BitwiseInputStream inStream, int subparamId)
9863de1a7e5535f36e86d82da12df2b17aeeafabdc6Rika Brooks        throws BitwiseInputStream.AccessException, CodingException
9873de1a7e5535f36e86d82da12df2b17aeeafabdc6Rika Brooks    {
9883de1a7e5535f36e86d82da12df2b17aeeafabdc6Rika Brooks        boolean decodeSuccess = false;
9893de1a7e5535f36e86d82da12df2b17aeeafabdc6Rika Brooks        int subparamLen = inStream.read(8); // SUBPARAM_LEN
9903de1a7e5535f36e86d82da12df2b17aeeafabdc6Rika Brooks        int paramBits = subparamLen * 8;
9913de1a7e5535f36e86d82da12df2b17aeeafabdc6Rika Brooks        if (paramBits <= inStream.available()) {
9923de1a7e5535f36e86d82da12df2b17aeeafabdc6Rika Brooks            decodeSuccess = true;
9933de1a7e5535f36e86d82da12df2b17aeeafabdc6Rika Brooks            inStream.skip(paramBits);
9943de1a7e5535f36e86d82da12df2b17aeeafabdc6Rika Brooks        }
9953de1a7e5535f36e86d82da12df2b17aeeafabdc6Rika Brooks        Rlog.d(LOG_TAG, "RESERVED bearer data subparameter " + subparamId + " decode "
9963de1a7e5535f36e86d82da12df2b17aeeafabdc6Rika Brooks                + (decodeSuccess ? "succeeded" : "failed") + " (param bits = " + paramBits + ")");
9973de1a7e5535f36e86d82da12df2b17aeeafabdc6Rika Brooks        if (!decodeSuccess) {
9983de1a7e5535f36e86d82da12df2b17aeeafabdc6Rika Brooks            throw new CodingException("RESERVED bearer data subparameter " + subparamId
9993de1a7e5535f36e86d82da12df2b17aeeafabdc6Rika Brooks                    + " had invalid SUBPARAM_LEN " + subparamLen);
10003de1a7e5535f36e86d82da12df2b17aeeafabdc6Rika Brooks        }
10013de1a7e5535f36e86d82da12df2b17aeeafabdc6Rika Brooks
10023de1a7e5535f36e86d82da12df2b17aeeafabdc6Rika Brooks        return decodeSuccess;
10033de1a7e5535f36e86d82da12df2b17aeeafabdc6Rika Brooks    }
10043de1a7e5535f36e86d82da12df2b17aeeafabdc6Rika Brooks
10050825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville    private static boolean decodeUserData(BearerData bData, BitwiseInputStream inStream)
10060825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        throws BitwiseInputStream.AccessException
10070825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville    {
10080825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        int paramBits = inStream.read(8) * 8;
10090825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        bData.userData = new UserData();
10100825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        bData.userData.msgEncoding = inStream.read(5);
10110825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        bData.userData.msgEncodingSet = true;
10120825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        bData.userData.msgType = 0;
10130825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        int consumedBits = 5;
10140825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        if ((bData.userData.msgEncoding == UserData.ENCODING_IS91_EXTENDED_PROTOCOL) ||
10150825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville            (bData.userData.msgEncoding == UserData.ENCODING_GSM_DCS)) {
10160825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville            bData.userData.msgType = inStream.read(8);
10170825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville            consumedBits += 8;
10180825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        }
10190825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        bData.userData.numFields = inStream.read(8);
10200825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        consumedBits += 8;
10210825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        int dataBits = paramBits - consumedBits;
10220825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        bData.userData.payload = inStream.readByteArray(dataBits);
10230825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        return true;
10240825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville    }
10250825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville
10260825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville    private static String decodeUtf8(byte[] data, int offset, int numFields)
10270825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        throws CodingException
10280825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville    {
1029115632cc56f813bd21543f8532c763d7d2968046Jake Hamby        return decodeCharset(data, offset, numFields, 1, "UTF-8");
10300825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville    }
10310825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville
10320825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville    private static String decodeUtf16(byte[] data, int offset, int numFields)
10330825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        throws CodingException
10340825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville    {
1035115632cc56f813bd21543f8532c763d7d2968046Jake Hamby        // Subtract header and possible padding byte (at end) from num fields.
1036115632cc56f813bd21543f8532c763d7d2968046Jake Hamby        int padding = offset % 2;
1037115632cc56f813bd21543f8532c763d7d2968046Jake Hamby        numFields -= (offset + padding) / 2;
1038115632cc56f813bd21543f8532c763d7d2968046Jake Hamby        return decodeCharset(data, offset, numFields, 2, "utf-16be");
1039115632cc56f813bd21543f8532c763d7d2968046Jake Hamby    }
1040115632cc56f813bd21543f8532c763d7d2968046Jake Hamby
1041115632cc56f813bd21543f8532c763d7d2968046Jake Hamby    private static String decodeCharset(byte[] data, int offset, int numFields, int width,
1042115632cc56f813bd21543f8532c763d7d2968046Jake Hamby            String charset) throws CodingException
1043115632cc56f813bd21543f8532c763d7d2968046Jake Hamby    {
1044115632cc56f813bd21543f8532c763d7d2968046Jake Hamby        if (numFields < 0 || (numFields * width + offset) > data.length) {
1045115632cc56f813bd21543f8532c763d7d2968046Jake Hamby            // Try to decode the max number of characters in payload
1046115632cc56f813bd21543f8532c763d7d2968046Jake Hamby            int padding = offset % width;
1047115632cc56f813bd21543f8532c763d7d2968046Jake Hamby            int maxNumFields = (data.length - offset - padding) / width;
1048115632cc56f813bd21543f8532c763d7d2968046Jake Hamby            if (maxNumFields < 0) {
1049115632cc56f813bd21543f8532c763d7d2968046Jake Hamby                throw new CodingException(charset + " decode failed: offset out of range");
1050115632cc56f813bd21543f8532c763d7d2968046Jake Hamby            }
1051ded9c0af7fa49504c047275ed34c2d3b22bf0c3aWink Saville            Rlog.e(LOG_TAG, charset + " decode error: offset = " + offset + " numFields = "
1052115632cc56f813bd21543f8532c763d7d2968046Jake Hamby                    + numFields + " data.length = " + data.length + " maxNumFields = "
1053115632cc56f813bd21543f8532c763d7d2968046Jake Hamby                    + maxNumFields);
1054115632cc56f813bd21543f8532c763d7d2968046Jake Hamby            numFields = maxNumFields;
10550825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        }
10560825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        try {
1057115632cc56f813bd21543f8532c763d7d2968046Jake Hamby            return new String(data, offset, numFields * width, charset);
10580825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        } catch (java.io.UnsupportedEncodingException ex) {
1059115632cc56f813bd21543f8532c763d7d2968046Jake Hamby            throw new CodingException(charset + " decode failed: " + ex);
10600825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        }
10610825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville    }
10620825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville
10630825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville    private static String decode7bitAscii(byte[] data, int offset, int numFields)
10640825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        throws CodingException
10650825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville    {
10660825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        try {
10670825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville            offset *= 8;
10680825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville            StringBuffer strBuf = new StringBuffer(numFields);
10690825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville            BitwiseInputStream inStream = new BitwiseInputStream(data);
10700825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville            int wantedBits = (offset * 8) + (numFields * 7);
10710825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville            if (inStream.available() < wantedBits) {
10720825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville                throw new CodingException("insufficient data (wanted " + wantedBits +
10730825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville                                          " bits, but only have " + inStream.available() + ")");
10740825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville            }
10750825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville            inStream.skip(offset);
10760825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville            for (int i = 0; i < numFields; i++) {
10770825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville                int charCode = inStream.read(7);
10780825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville                if ((charCode >= UserData.ASCII_MAP_BASE_INDEX) &&
10790825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville                        (charCode <= UserData.ASCII_MAP_MAX_INDEX)) {
10800825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville                    strBuf.append(UserData.ASCII_MAP[charCode - UserData.ASCII_MAP_BASE_INDEX]);
10810825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville                } else if (charCode == UserData.ASCII_NL_INDEX) {
10820825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville                    strBuf.append('\n');
10830825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville                } else if (charCode == UserData.ASCII_CR_INDEX) {
10840825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville                    strBuf.append('\r');
10850825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville                } else {
10860825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville                    /* For other charCodes, they are unprintable, and so simply use SPACE. */
10870825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville                    strBuf.append(' ');
10880825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville                }
10890825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville            }
10900825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville            return strBuf.toString();
10910825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        } catch (BitwiseInputStream.AccessException ex) {
10920825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville            throw new CodingException("7bit ASCII decode failed: " + ex);
10930825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        }
10940825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville    }
10950825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville
10960825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville    private static String decode7bitGsm(byte[] data, int offset, int numFields)
10970825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        throws CodingException
10980825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville    {
10990825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        // Start reading from the next 7-bit aligned boundary after offset.
11000825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        int offsetBits = offset * 8;
11010825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        int offsetSeptets = (offsetBits + 6) / 7;
11020825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        numFields -= offsetSeptets;
11030825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        int paddingBits = (offsetSeptets * 7) - offsetBits;
11040825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        String result = GsmAlphabet.gsm7BitPackedToString(data, offset, numFields, paddingBits,
11050825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville                0, 0);
11060825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        if (result == null) {
11070825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville            throw new CodingException("7bit GSM decoding failed");
11080825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        }
11090825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        return result;
11100825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville    }
11110825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville
11120825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville    private static String decodeLatin(byte[] data, int offset, int numFields)
11130825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        throws CodingException
11140825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville    {
1115115632cc56f813bd21543f8532c763d7d2968046Jake Hamby        return decodeCharset(data, offset, numFields, 1, "ISO-8859-1");
11160825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville    }
11170825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville
11183de1a7e5535f36e86d82da12df2b17aeeafabdc6Rika Brooks    private static String decodeShiftJis(byte[] data, int offset, int numFields)
11193de1a7e5535f36e86d82da12df2b17aeeafabdc6Rika Brooks        throws CodingException
11203de1a7e5535f36e86d82da12df2b17aeeafabdc6Rika Brooks    {
1121a2ccc4f16ec2f3e26b308d6f25cd4aa6a394a008Jake Hamby        return decodeCharset(data, offset, numFields, 1, "Shift_JIS");
11223de1a7e5535f36e86d82da12df2b17aeeafabdc6Rika Brooks    }
11233de1a7e5535f36e86d82da12df2b17aeeafabdc6Rika Brooks
11240825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville    private static void decodeUserDataPayload(UserData userData, boolean hasUserDataHeader)
11250825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        throws CodingException
11260825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville    {
11270825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        int offset = 0;
11280825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        if (hasUserDataHeader) {
11290825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville            int udhLen = userData.payload[0] & 0x00FF;
11300825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville            offset += udhLen + 1;
11310825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville            byte[] headerData = new byte[udhLen];
11320825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville            System.arraycopy(userData.payload, 1, headerData, 0, udhLen);
11330825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville            userData.userDataHeader = SmsHeader.fromByteArray(headerData);
11340825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        }
11350825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        switch (userData.msgEncoding) {
11360825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        case UserData.ENCODING_OCTET:
11370825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville            /*
11380825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville            *  Octet decoding depends on the carrier service.
11390825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville            */
11400825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville            boolean decodingtypeUTF8 = Resources.getSystem()
11410825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville                    .getBoolean(com.android.internal.R.bool.config_sms_utf8_support);
11420825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville
11430825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville            // Strip off any padding bytes, meaning any differences between the length of the
11440825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville            // array and the target length specified by numFields.  This is to avoid any
11450825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville            // confusion by code elsewhere that only considers the payload array length.
11460825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville            byte[] payload = new byte[userData.numFields];
11470825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville            int copyLen = userData.numFields < userData.payload.length
11480825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville                    ? userData.numFields : userData.payload.length;
11490825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville
11500825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville            System.arraycopy(userData.payload, 0, payload, 0, copyLen);
11510825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville            userData.payload = payload;
11520825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville
11530825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville            if (!decodingtypeUTF8) {
11540825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville                // There are many devices in the market that send 8bit text sms (latin encoded) as
11550825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville                // octet encoded.
11560825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville                userData.payloadStr = decodeLatin(userData.payload, offset, userData.numFields);
11570825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville            } else {
11580825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville                userData.payloadStr = decodeUtf8(userData.payload, offset, userData.numFields);
11590825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville            }
11600825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville            break;
11610825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville
11620825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        case UserData.ENCODING_IA5:
11630825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        case UserData.ENCODING_7BIT_ASCII:
11640825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville            userData.payloadStr = decode7bitAscii(userData.payload, offset, userData.numFields);
11650825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville            break;
11660825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        case UserData.ENCODING_UNICODE_16:
11670825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville            userData.payloadStr = decodeUtf16(userData.payload, offset, userData.numFields);
11680825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville            break;
11690825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        case UserData.ENCODING_GSM_7BIT_ALPHABET:
11700825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville            userData.payloadStr = decode7bitGsm(userData.payload, offset, userData.numFields);
11710825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville            break;
11720825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        case UserData.ENCODING_LATIN:
11730825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville            userData.payloadStr = decodeLatin(userData.payload, offset, userData.numFields);
11740825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville            break;
11753de1a7e5535f36e86d82da12df2b17aeeafabdc6Rika Brooks        case UserData.ENCODING_SHIFT_JIS:
11763de1a7e5535f36e86d82da12df2b17aeeafabdc6Rika Brooks            userData.payloadStr = decodeShiftJis(userData.payload, offset, userData.numFields);
11773de1a7e5535f36e86d82da12df2b17aeeafabdc6Rika Brooks            break;
11780825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        default:
11790825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville            throw new CodingException("unsupported user data encoding ("
11800825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville                                      + userData.msgEncoding + ")");
11810825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        }
11820825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville    }
11830825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville
11840825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville    /**
11850825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville     * IS-91 Voice Mail message decoding
11860825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville     * (See 3GPP2 C.S0015-A, Table 4.3.1.4.1-1)
11870825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville     * (For character encodings, see TIA/EIA/IS-91, Annex B)
11880825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville     *
11890825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville     * Protocol Summary: The user data payload may contain 3-14
11900825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville     * characters.  The first two characters are parsed as a number
11910825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville     * and indicate the number of voicemails.  The third character is
11920825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville     * either a SPACE or '!' to indicate normal or urgent priority,
11930825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville     * respectively.  Any following characters are treated as normal
11940825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville     * text user data payload.
11950825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville     *
11960825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville     * Note that the characters encoding is 6-bit packed.
11970825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville     */
11980825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville    private static void decodeIs91VoicemailStatus(BearerData bData)
11990825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        throws BitwiseInputStream.AccessException, CodingException
12000825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville    {
12010825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        BitwiseInputStream inStream = new BitwiseInputStream(bData.userData.payload);
12020825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        int dataLen = inStream.available() / 6;  // 6-bit packed character encoding.
12030825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        int numFields = bData.userData.numFields;
12040825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        if ((dataLen > 14) || (dataLen < 3) || (dataLen < numFields)) {
12050825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville            throw new CodingException("IS-91 voicemail status decoding failed");
12060825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        }
12070825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        try {
12080825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville            StringBuffer strbuf = new StringBuffer(dataLen);
12090825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville            while (inStream.available() >= 6) {
12100825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville                strbuf.append(UserData.ASCII_MAP[inStream.read(6)]);
12110825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville            }
12120825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville            String data = strbuf.toString();
12130825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville            bData.numberOfMessages = Integer.parseInt(data.substring(0, 2));
12140825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville            char prioCode = data.charAt(2);
12150825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville            if (prioCode == ' ') {
12160825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville                bData.priority = PRIORITY_NORMAL;
12170825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville            } else if (prioCode == '!') {
12180825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville                bData.priority = PRIORITY_URGENT;
12190825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville            } else {
12200825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville                throw new CodingException("IS-91 voicemail status decoding failed: " +
12210825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville                        "illegal priority setting (" + prioCode + ")");
12220825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville            }
12230825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville            bData.priorityIndicatorSet = true;
12240825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville            bData.userData.payloadStr = data.substring(3, numFields - 3);
12250825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville       } catch (java.lang.NumberFormatException ex) {
12260825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville            throw new CodingException("IS-91 voicemail status decoding failed: " + ex);
12270825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        } catch (java.lang.IndexOutOfBoundsException ex) {
12280825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville            throw new CodingException("IS-91 voicemail status decoding failed: " + ex);
12290825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        }
12300825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville    }
12310825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville
12320825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville    /**
12330825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville     * IS-91 Short Message decoding
12340825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville     * (See 3GPP2 C.S0015-A, Table 4.3.1.4.1-1)
12350825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville     * (For character encodings, see TIA/EIA/IS-91, Annex B)
12360825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville     *
12370825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville     * Protocol Summary: The user data payload may contain 1-14
12380825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville     * characters, which are treated as normal text user data payload.
12390825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville     * Note that the characters encoding is 6-bit packed.
12400825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville     */
12410825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville    private static void decodeIs91ShortMessage(BearerData bData)
12420825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        throws BitwiseInputStream.AccessException, CodingException
12430825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville    {
12440825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        BitwiseInputStream inStream = new BitwiseInputStream(bData.userData.payload);
12450825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        int dataLen = inStream.available() / 6;  // 6-bit packed character encoding.
12460825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        int numFields = bData.userData.numFields;
12470825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        // dataLen may be > 14 characters due to octet padding
12480825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        if ((numFields > 14) || (dataLen < numFields)) {
12490825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville            throw new CodingException("IS-91 short message decoding failed");
12500825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        }
12510825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        StringBuffer strbuf = new StringBuffer(dataLen);
12520825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        for (int i = 0; i < numFields; i++) {
12530825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville            strbuf.append(UserData.ASCII_MAP[inStream.read(6)]);
12540825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        }
12550825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        bData.userData.payloadStr = strbuf.toString();
12560825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville    }
12570825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville
12580825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville    /**
12590825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville     * IS-91 CLI message (callback number) decoding
12600825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville     * (See 3GPP2 C.S0015-A, Table 4.3.1.4.1-1)
12610825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville     *
12620825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville     * Protocol Summary: The data payload may contain 1-32 digits,
12630825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville     * encoded using standard 4-bit DTMF, which are treated as a
12640825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville     * callback number.
12650825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville     */
12660825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville    private static void decodeIs91Cli(BearerData bData) throws CodingException {
12670825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        BitwiseInputStream inStream = new BitwiseInputStream(bData.userData.payload);
12680825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        int dataLen = inStream.available() / 4;  // 4-bit packed DTMF digit encoding.
12690825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        int numFields = bData.userData.numFields;
12700825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        if ((dataLen > 14) || (dataLen < 3) || (dataLen < numFields)) {
12710825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville            throw new CodingException("IS-91 voicemail status decoding failed");
12720825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        }
12730825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        CdmaSmsAddress addr = new CdmaSmsAddress();
12740825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        addr.digitMode = CdmaSmsAddress.DIGIT_MODE_4BIT_DTMF;
12750825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        addr.origBytes = bData.userData.payload;
12760825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        addr.numberOfDigits = (byte)numFields;
12770825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        decodeSmsAddress(addr);
12780825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        bData.callbackNumber = addr;
12790825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville    }
12800825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville
12810825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville    private static void decodeIs91(BearerData bData)
12820825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        throws BitwiseInputStream.AccessException, CodingException
12830825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville    {
12840825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        switch (bData.userData.msgType) {
12850825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        case UserData.IS91_MSG_TYPE_VOICEMAIL_STATUS:
12860825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville            decodeIs91VoicemailStatus(bData);
12870825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville            break;
12880825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        case UserData.IS91_MSG_TYPE_CLI:
12890825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville            decodeIs91Cli(bData);
12900825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville            break;
12910825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        case UserData.IS91_MSG_TYPE_SHORT_MESSAGE_FULL:
12920825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        case UserData.IS91_MSG_TYPE_SHORT_MESSAGE:
12930825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville            decodeIs91ShortMessage(bData);
12940825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville            break;
12950825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        default:
12960825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville            throw new CodingException("unsupported IS-91 message type (" +
12970825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville                    bData.userData.msgType + ")");
12980825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        }
12990825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville    }
13000825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville
13010825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville    private static boolean decodeReplyOption(BearerData bData, BitwiseInputStream inStream)
1302cbaa45bbf2cab852b6c9c3a887e9f803d4e857eaWink Saville        throws BitwiseInputStream.AccessException {
13030825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        final int EXPECTED_PARAM_SIZE = 1 * 8;
13040825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        boolean decodeSuccess = false;
13050825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        int paramBits = inStream.read(8) * 8;
13060825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        if (paramBits >= EXPECTED_PARAM_SIZE) {
13070825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville            paramBits -= EXPECTED_PARAM_SIZE;
13080825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville            decodeSuccess = true;
13090825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville            bData.userAckReq     = (inStream.read(1) == 1);
13100825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville            bData.deliveryAckReq = (inStream.read(1) == 1);
13110825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville            bData.readAckReq     = (inStream.read(1) == 1);
13120825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville            bData.reportReq      = (inStream.read(1) == 1);
13130825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville            inStream.skip(4);
13140825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        }
13150825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        if ((! decodeSuccess) || (paramBits > 0)) {
1316ded9c0af7fa49504c047275ed34c2d3b22bf0c3aWink Saville            Rlog.d(LOG_TAG, "REPLY_OPTION decode " +
13170825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville                      (decodeSuccess ? "succeeded" : "failed") +
13180825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville                      " (extra bits = " + paramBits + ")");
13190825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        }
13200825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        inStream.skip(paramBits);
13210825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        return decodeSuccess;
13220825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville    }
13230825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville
13240825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville    private static boolean decodeMsgCount(BearerData bData, BitwiseInputStream inStream)
1325cbaa45bbf2cab852b6c9c3a887e9f803d4e857eaWink Saville        throws BitwiseInputStream.AccessException {
13260825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        final int EXPECTED_PARAM_SIZE = 1 * 8;
13270825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        boolean decodeSuccess = false;
13280825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        int paramBits = inStream.read(8) * 8;
13290825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        if (paramBits >= EXPECTED_PARAM_SIZE) {
13300825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville            paramBits -= EXPECTED_PARAM_SIZE;
13310825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville            decodeSuccess = true;
13320825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville            bData.numberOfMessages = IccUtils.cdmaBcdByteToInt((byte)inStream.read(8));
13330825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        }
13340825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        if ((! decodeSuccess) || (paramBits > 0)) {
1335ded9c0af7fa49504c047275ed34c2d3b22bf0c3aWink Saville            Rlog.d(LOG_TAG, "NUMBER_OF_MESSAGES decode " +
13360825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville                      (decodeSuccess ? "succeeded" : "failed") +
13370825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville                      " (extra bits = " + paramBits + ")");
13380825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        }
13390825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        inStream.skip(paramBits);
13400825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        return decodeSuccess;
13410825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville    }
13420825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville
13430825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville    private static boolean decodeDepositIndex(BearerData bData, BitwiseInputStream inStream)
1344cbaa45bbf2cab852b6c9c3a887e9f803d4e857eaWink Saville        throws BitwiseInputStream.AccessException {
13450825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        final int EXPECTED_PARAM_SIZE = 2 * 8;
13460825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        boolean decodeSuccess = false;
13470825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        int paramBits = inStream.read(8) * 8;
13480825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        if (paramBits >= EXPECTED_PARAM_SIZE) {
13490825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville            paramBits -= EXPECTED_PARAM_SIZE;
13500825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville            decodeSuccess = true;
13510825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville            bData.depositIndex = (inStream.read(8) << 8) | inStream.read(8);
13520825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        }
13530825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        if ((! decodeSuccess) || (paramBits > 0)) {
1354ded9c0af7fa49504c047275ed34c2d3b22bf0c3aWink Saville            Rlog.d(LOG_TAG, "MESSAGE_DEPOSIT_INDEX decode " +
13550825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville                      (decodeSuccess ? "succeeded" : "failed") +
13560825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville                      " (extra bits = " + paramBits + ")");
13570825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        }
13580825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        inStream.skip(paramBits);
13590825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        return decodeSuccess;
13600825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville    }
13610825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville
13620825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville    private static String decodeDtmfSmsAddress(byte[] rawData, int numFields)
13630825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        throws CodingException
13640825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville    {
13650825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        /* DTMF 4-bit digit encoding, defined in at
13660825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville         * 3GPP2 C.S005-D, v2.0, table 2.7.1.3.2.4-4 */
13670825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        StringBuffer strBuf = new StringBuffer(numFields);
13680825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        for (int i = 0; i < numFields; i++) {
13690825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville            int val = 0x0F & (rawData[i / 2] >>> (4 - ((i % 2) * 4)));
13700825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville            if ((val >= 1) && (val <= 9)) strBuf.append(Integer.toString(val, 10));
13710825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville            else if (val == 10) strBuf.append('0');
13720825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville            else if (val == 11) strBuf.append('*');
13730825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville            else if (val == 12) strBuf.append('#');
13740825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville            else throw new CodingException("invalid SMS address DTMF code (" + val + ")");
13750825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        }
13760825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        return strBuf.toString();
13770825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville    }
13780825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville
13790825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville    private static void decodeSmsAddress(CdmaSmsAddress addr) throws CodingException {
13800825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        if (addr.digitMode == CdmaSmsAddress.DIGIT_MODE_8BIT_CHAR) {
13810825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville            try {
13820825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville                /* As specified in 3GPP2 C.S0015-B, v2, 4.5.15 -- actually
13830825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville                 * just 7-bit ASCII encoding, with the MSB being zero. */
13840825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville                addr.address = new String(addr.origBytes, 0, addr.origBytes.length, "US-ASCII");
13850825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville            } catch (java.io.UnsupportedEncodingException ex) {
13860825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville                throw new CodingException("invalid SMS address ASCII code");
13870825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville            }
13880825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        } else {
13890825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville            addr.address = decodeDtmfSmsAddress(addr.origBytes, addr.numberOfDigits);
13900825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        }
13910825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville    }
13920825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville
13930825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville    private static boolean decodeCallbackNumber(BearerData bData, BitwiseInputStream inStream)
13940825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        throws BitwiseInputStream.AccessException, CodingException
13950825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville    {
1396dbb088ab146d2fcb435e75e4ca70f2ff7d00d2c7Alex Yakavenka        final int EXPECTED_PARAM_SIZE = 1 * 8; //at least
13970825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        int paramBits = inStream.read(8) * 8;
1398dbb088ab146d2fcb435e75e4ca70f2ff7d00d2c7Alex Yakavenka        if (paramBits < EXPECTED_PARAM_SIZE) {
1399dbb088ab146d2fcb435e75e4ca70f2ff7d00d2c7Alex Yakavenka            inStream.skip(paramBits);
1400dbb088ab146d2fcb435e75e4ca70f2ff7d00d2c7Alex Yakavenka            return false;
1401dbb088ab146d2fcb435e75e4ca70f2ff7d00d2c7Alex Yakavenka        }
14020825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        CdmaSmsAddress addr = new CdmaSmsAddress();
14030825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        addr.digitMode = inStream.read(1);
14040825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        byte fieldBits = 4;
14050825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        byte consumedBits = 1;
14060825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        if (addr.digitMode == CdmaSmsAddress.DIGIT_MODE_8BIT_CHAR) {
14070825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville            addr.ton = inStream.read(3);
14080825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville            addr.numberPlan = inStream.read(4);
14090825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville            fieldBits = 8;
14100825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville            consumedBits += 7;
14110825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        }
14120825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        addr.numberOfDigits = inStream.read(8);
14130825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        consumedBits += 8;
14140825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        int remainingBits = paramBits - consumedBits;
14150825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        int dataBits = addr.numberOfDigits * fieldBits;
14160825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        int paddingBits = remainingBits - dataBits;
14170825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        if (remainingBits < dataBits) {
14180825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville            throw new CodingException("CALLBACK_NUMBER subparam encoding size error (" +
14190825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville                                      "remainingBits + " + remainingBits + ", dataBits + " +
14200825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville                                      dataBits + ", paddingBits + " + paddingBits + ")");
14210825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        }
14220825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        addr.origBytes = inStream.readByteArray(dataBits);
14230825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        inStream.skip(paddingBits);
14240825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        decodeSmsAddress(addr);
14250825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        bData.callbackNumber = addr;
14260825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        return true;
14270825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville    }
14280825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville
14290825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville    private static boolean decodeMsgStatus(BearerData bData, BitwiseInputStream inStream)
1430cbaa45bbf2cab852b6c9c3a887e9f803d4e857eaWink Saville        throws BitwiseInputStream.AccessException {
14310825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        final int EXPECTED_PARAM_SIZE = 1 * 8;
14320825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        boolean decodeSuccess = false;
14330825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        int paramBits = inStream.read(8) * 8;
14340825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        if (paramBits >= EXPECTED_PARAM_SIZE) {
14350825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville            paramBits -= EXPECTED_PARAM_SIZE;
14360825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville            decodeSuccess = true;
14370825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville            bData.errorClass = inStream.read(2);
14380825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville            bData.messageStatus = inStream.read(6);
14390825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        }
14400825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        if ((! decodeSuccess) || (paramBits > 0)) {
1441ded9c0af7fa49504c047275ed34c2d3b22bf0c3aWink Saville            Rlog.d(LOG_TAG, "MESSAGE_STATUS decode " +
14420825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville                      (decodeSuccess ? "succeeded" : "failed") +
14430825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville                      " (extra bits = " + paramBits + ")");
14440825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        }
14450825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        inStream.skip(paramBits);
14460825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        bData.messageStatusSet = decodeSuccess;
14470825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        return decodeSuccess;
14480825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville    }
14490825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville
14500825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville    private static boolean decodeMsgCenterTimeStamp(BearerData bData, BitwiseInputStream inStream)
1451cbaa45bbf2cab852b6c9c3a887e9f803d4e857eaWink Saville        throws BitwiseInputStream.AccessException {
14520825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        final int EXPECTED_PARAM_SIZE = 6 * 8;
14530825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        boolean decodeSuccess = false;
14540825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        int paramBits = inStream.read(8) * 8;
14550825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        if (paramBits >= EXPECTED_PARAM_SIZE) {
14560825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville            paramBits -= EXPECTED_PARAM_SIZE;
14570825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville            decodeSuccess = true;
14580825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville            bData.msgCenterTimeStamp = TimeStamp.fromByteArray(inStream.readByteArray(6 * 8));
14590825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        }
14600825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        if ((! decodeSuccess) || (paramBits > 0)) {
1461ded9c0af7fa49504c047275ed34c2d3b22bf0c3aWink Saville            Rlog.d(LOG_TAG, "MESSAGE_CENTER_TIME_STAMP decode " +
14620825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville                      (decodeSuccess ? "succeeded" : "failed") +
14630825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville                      " (extra bits = " + paramBits + ")");
14640825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        }
14650825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        inStream.skip(paramBits);
14660825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        return decodeSuccess;
14670825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville    }
14680825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville
14690825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville    private static boolean decodeValidityAbs(BearerData bData, BitwiseInputStream inStream)
1470cbaa45bbf2cab852b6c9c3a887e9f803d4e857eaWink Saville        throws BitwiseInputStream.AccessException {
14710825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        final int EXPECTED_PARAM_SIZE = 6 * 8;
14720825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        boolean decodeSuccess = false;
14730825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        int paramBits = inStream.read(8) * 8;
14740825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        if (paramBits >= EXPECTED_PARAM_SIZE) {
14750825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville            paramBits -= EXPECTED_PARAM_SIZE;
14760825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville            decodeSuccess = true;
14770825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville            bData.validityPeriodAbsolute = TimeStamp.fromByteArray(inStream.readByteArray(6 * 8));
14780825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        }
14790825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        if ((! decodeSuccess) || (paramBits > 0)) {
1480ded9c0af7fa49504c047275ed34c2d3b22bf0c3aWink Saville            Rlog.d(LOG_TAG, "VALIDITY_PERIOD_ABSOLUTE decode " +
14810825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville                      (decodeSuccess ? "succeeded" : "failed") +
14820825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville                      " (extra bits = " + paramBits + ")");
14830825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        }
14840825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        inStream.skip(paramBits);
14850825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        return decodeSuccess;
14860825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville    }
14870825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville
14880825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville    private static boolean decodeDeferredDeliveryAbs(BearerData bData, BitwiseInputStream inStream)
1489cbaa45bbf2cab852b6c9c3a887e9f803d4e857eaWink Saville        throws BitwiseInputStream.AccessException {
14900825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        final int EXPECTED_PARAM_SIZE = 6 * 8;
14910825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        boolean decodeSuccess = false;
14920825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        int paramBits = inStream.read(8) * 8;
14930825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        if (paramBits >= EXPECTED_PARAM_SIZE) {
14940825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville            paramBits -= EXPECTED_PARAM_SIZE;
14950825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville            decodeSuccess = true;
14960825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville            bData.deferredDeliveryTimeAbsolute = TimeStamp.fromByteArray(
14970825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville                    inStream.readByteArray(6 * 8));
14980825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        }
14990825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        if ((! decodeSuccess) || (paramBits > 0)) {
1500ded9c0af7fa49504c047275ed34c2d3b22bf0c3aWink Saville            Rlog.d(LOG_TAG, "DEFERRED_DELIVERY_TIME_ABSOLUTE decode " +
15010825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville                      (decodeSuccess ? "succeeded" : "failed") +
15020825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville                      " (extra bits = " + paramBits + ")");
15030825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        }
15040825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        inStream.skip(paramBits);
15050825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        return decodeSuccess;
15060825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville    }
15070825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville
15080825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville    private static boolean decodeValidityRel(BearerData bData, BitwiseInputStream inStream)
1509cbaa45bbf2cab852b6c9c3a887e9f803d4e857eaWink Saville        throws BitwiseInputStream.AccessException {
15100825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        final int EXPECTED_PARAM_SIZE = 1 * 8;
15110825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        boolean decodeSuccess = false;
15120825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        int paramBits = inStream.read(8) * 8;
15130825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        if (paramBits >= EXPECTED_PARAM_SIZE) {
15140825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville            paramBits -= EXPECTED_PARAM_SIZE;
15150825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville            decodeSuccess = true;
15160825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville            bData.deferredDeliveryTimeRelative = inStream.read(8);
15170825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        }
15180825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        if ((! decodeSuccess) || (paramBits > 0)) {
1519ded9c0af7fa49504c047275ed34c2d3b22bf0c3aWink Saville            Rlog.d(LOG_TAG, "VALIDITY_PERIOD_RELATIVE decode " +
15200825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville                      (decodeSuccess ? "succeeded" : "failed") +
15210825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville                      " (extra bits = " + paramBits + ")");
15220825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        }
15230825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        inStream.skip(paramBits);
15240825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        bData.deferredDeliveryTimeRelativeSet = decodeSuccess;
15250825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        return decodeSuccess;
15260825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville    }
15270825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville
15280825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville    private static boolean decodeDeferredDeliveryRel(BearerData bData, BitwiseInputStream inStream)
1529cbaa45bbf2cab852b6c9c3a887e9f803d4e857eaWink Saville        throws BitwiseInputStream.AccessException {
15300825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        final int EXPECTED_PARAM_SIZE = 1 * 8;
15310825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        boolean decodeSuccess = false;
15320825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        int paramBits = inStream.read(8) * 8;
15330825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        if (paramBits >= EXPECTED_PARAM_SIZE) {
15340825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville            paramBits -= EXPECTED_PARAM_SIZE;
15350825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville            decodeSuccess = true;
15360825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville            bData.validityPeriodRelative = inStream.read(8);
15370825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        }
15380825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        if ((! decodeSuccess) || (paramBits > 0)) {
1539ded9c0af7fa49504c047275ed34c2d3b22bf0c3aWink Saville            Rlog.d(LOG_TAG, "DEFERRED_DELIVERY_TIME_RELATIVE decode " +
15400825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville                      (decodeSuccess ? "succeeded" : "failed") +
15410825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville                      " (extra bits = " + paramBits + ")");
15420825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        }
15430825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        inStream.skip(paramBits);
15440825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        bData.validityPeriodRelativeSet = decodeSuccess;
15450825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        return decodeSuccess;
15460825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville    }
15470825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville
15480825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville    private static boolean decodePrivacyIndicator(BearerData bData, BitwiseInputStream inStream)
1549cbaa45bbf2cab852b6c9c3a887e9f803d4e857eaWink Saville        throws BitwiseInputStream.AccessException {
15500825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        final int EXPECTED_PARAM_SIZE = 1 * 8;
15510825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        boolean decodeSuccess = false;
15520825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        int paramBits = inStream.read(8) * 8;
15530825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        if (paramBits >= EXPECTED_PARAM_SIZE) {
15540825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville            paramBits -= EXPECTED_PARAM_SIZE;
15550825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville            decodeSuccess = true;
15560825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville            bData.privacy = inStream.read(2);
15570825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville            inStream.skip(6);
15580825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        }
15590825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        if ((! decodeSuccess) || (paramBits > 0)) {
1560ded9c0af7fa49504c047275ed34c2d3b22bf0c3aWink Saville            Rlog.d(LOG_TAG, "PRIVACY_INDICATOR decode " +
15610825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville                      (decodeSuccess ? "succeeded" : "failed") +
15620825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville                      " (extra bits = " + paramBits + ")");
15630825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        }
15640825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        inStream.skip(paramBits);
15650825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        bData.privacyIndicatorSet = decodeSuccess;
15660825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        return decodeSuccess;
15670825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville    }
15680825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville
15690825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville    private static boolean decodeLanguageIndicator(BearerData bData, BitwiseInputStream inStream)
1570cbaa45bbf2cab852b6c9c3a887e9f803d4e857eaWink Saville        throws BitwiseInputStream.AccessException {
15710825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        final int EXPECTED_PARAM_SIZE = 1 * 8;
15720825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        boolean decodeSuccess = false;
15730825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        int paramBits = inStream.read(8) * 8;
15740825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        if (paramBits >= EXPECTED_PARAM_SIZE) {
15750825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville            paramBits -= EXPECTED_PARAM_SIZE;
15760825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville            decodeSuccess = true;
15770825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville            bData.language = inStream.read(8);
15780825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        }
15790825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        if ((! decodeSuccess) || (paramBits > 0)) {
1580ded9c0af7fa49504c047275ed34c2d3b22bf0c3aWink Saville            Rlog.d(LOG_TAG, "LANGUAGE_INDICATOR decode " +
15810825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville                      (decodeSuccess ? "succeeded" : "failed") +
15820825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville                      " (extra bits = " + paramBits + ")");
15830825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        }
15840825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        inStream.skip(paramBits);
15850825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        bData.languageIndicatorSet = decodeSuccess;
15860825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        return decodeSuccess;
15870825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville    }
15880825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville
15890825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville    private static boolean decodeDisplayMode(BearerData bData, BitwiseInputStream inStream)
1590cbaa45bbf2cab852b6c9c3a887e9f803d4e857eaWink Saville        throws BitwiseInputStream.AccessException {
15910825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        final int EXPECTED_PARAM_SIZE = 1 * 8;
15920825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        boolean decodeSuccess = false;
15930825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        int paramBits = inStream.read(8) * 8;
15940825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        if (paramBits >= EXPECTED_PARAM_SIZE) {
15950825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville            paramBits -= EXPECTED_PARAM_SIZE;
15960825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville            decodeSuccess = true;
15970825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville            bData.displayMode = inStream.read(2);
15980825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville            inStream.skip(6);
15990825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        }
16000825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        if ((! decodeSuccess) || (paramBits > 0)) {
1601ded9c0af7fa49504c047275ed34c2d3b22bf0c3aWink Saville            Rlog.d(LOG_TAG, "DISPLAY_MODE decode " +
16020825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville                      (decodeSuccess ? "succeeded" : "failed") +
16030825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville                      " (extra bits = " + paramBits + ")");
16040825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        }
16050825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        inStream.skip(paramBits);
16060825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        bData.displayModeSet = decodeSuccess;
16070825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        return decodeSuccess;
16080825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville    }
16090825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville
16100825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville    private static boolean decodePriorityIndicator(BearerData bData, BitwiseInputStream inStream)
1611cbaa45bbf2cab852b6c9c3a887e9f803d4e857eaWink Saville        throws BitwiseInputStream.AccessException {
16120825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        final int EXPECTED_PARAM_SIZE = 1 * 8;
16130825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        boolean decodeSuccess = false;
16140825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        int paramBits = inStream.read(8) * 8;
16150825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        if (paramBits >= EXPECTED_PARAM_SIZE) {
16160825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville            paramBits -= EXPECTED_PARAM_SIZE;
16170825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville            decodeSuccess = true;
16180825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville            bData.priority = inStream.read(2);
16190825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville            inStream.skip(6);
16200825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        }
16210825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        if ((! decodeSuccess) || (paramBits > 0)) {
1622ded9c0af7fa49504c047275ed34c2d3b22bf0c3aWink Saville            Rlog.d(LOG_TAG, "PRIORITY_INDICATOR decode " +
16230825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville                      (decodeSuccess ? "succeeded" : "failed") +
16240825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville                      " (extra bits = " + paramBits + ")");
16250825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        }
16260825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        inStream.skip(paramBits);
16270825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        bData.priorityIndicatorSet = decodeSuccess;
16280825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        return decodeSuccess;
16290825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville    }
16300825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville
16310825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville    private static boolean decodeMsgDeliveryAlert(BearerData bData, BitwiseInputStream inStream)
1632cbaa45bbf2cab852b6c9c3a887e9f803d4e857eaWink Saville        throws BitwiseInputStream.AccessException {
16330825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        final int EXPECTED_PARAM_SIZE = 1 * 8;
16340825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        boolean decodeSuccess = false;
16350825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        int paramBits = inStream.read(8) * 8;
16360825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        if (paramBits >= EXPECTED_PARAM_SIZE) {
16370825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville            paramBits -= EXPECTED_PARAM_SIZE;
16380825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville            decodeSuccess = true;
16390825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville            bData.alert = inStream.read(2);
16400825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville            inStream.skip(6);
16410825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        }
16420825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        if ((! decodeSuccess) || (paramBits > 0)) {
1643ded9c0af7fa49504c047275ed34c2d3b22bf0c3aWink Saville            Rlog.d(LOG_TAG, "ALERT_ON_MESSAGE_DELIVERY decode " +
16440825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville                      (decodeSuccess ? "succeeded" : "failed") +
16450825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville                      " (extra bits = " + paramBits + ")");
16460825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        }
16470825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        inStream.skip(paramBits);
16480825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        bData.alertIndicatorSet = decodeSuccess;
16490825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        return decodeSuccess;
16500825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville    }
16510825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville
16520825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville    private static boolean decodeUserResponseCode(BearerData bData, BitwiseInputStream inStream)
1653cbaa45bbf2cab852b6c9c3a887e9f803d4e857eaWink Saville        throws BitwiseInputStream.AccessException {
16540825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        final int EXPECTED_PARAM_SIZE = 1 * 8;
16550825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        boolean decodeSuccess = false;
16560825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        int paramBits = inStream.read(8) * 8;
16570825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        if (paramBits >= EXPECTED_PARAM_SIZE) {
16580825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville            paramBits -= EXPECTED_PARAM_SIZE;
16590825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville            decodeSuccess = true;
16600825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville            bData.userResponseCode = inStream.read(8);
16610825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        }
16620825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        if ((! decodeSuccess) || (paramBits > 0)) {
1663ded9c0af7fa49504c047275ed34c2d3b22bf0c3aWink Saville            Rlog.d(LOG_TAG, "USER_RESPONSE_CODE decode " +
16640825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville                      (decodeSuccess ? "succeeded" : "failed") +
16650825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville                      " (extra bits = " + paramBits + ")");
16660825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        }
16670825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        inStream.skip(paramBits);
16680825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        bData.userResponseCodeSet = decodeSuccess;
16690825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        return decodeSuccess;
16700825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville    }
16710825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville
16720825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville    private static boolean decodeServiceCategoryProgramData(BearerData bData,
16730825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville            BitwiseInputStream inStream) throws BitwiseInputStream.AccessException, CodingException
16740825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville    {
16750825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        if (inStream.available() < 13) {
16760825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville            throw new CodingException("SERVICE_CATEGORY_PROGRAM_DATA decode failed: only "
16770825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville                    + inStream.available() + " bits available");
16780825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        }
16790825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville
16800825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        int paramBits = inStream.read(8) * 8;
16810825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        int msgEncoding = inStream.read(5);
16820825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        paramBits -= 5;
16830825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville
16840825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        if (inStream.available() < paramBits) {
16850825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville            throw new CodingException("SERVICE_CATEGORY_PROGRAM_DATA decode failed: only "
16860825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville                    + inStream.available() + " bits available (" + paramBits + " bits expected)");
16870825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        }
16880825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville
16890825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        ArrayList<CdmaSmsCbProgramData> programDataList = new ArrayList<CdmaSmsCbProgramData>();
16900825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville
16910825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        final int CATEGORY_FIELD_MIN_SIZE = 6 * 8;
16920825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        boolean decodeSuccess = false;
16930825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        while (paramBits >= CATEGORY_FIELD_MIN_SIZE) {
16940825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville            int operation = inStream.read(4);
16950825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville            int category = (inStream.read(8) << 8) | inStream.read(8);
1696b8a13d300b245e0080aa01275e232f54d5d0e09cJake Hamby            int language = inStream.read(8);
16970825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville            int maxMessages = inStream.read(8);
16980825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville            int alertOption = inStream.read(4);
16990825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville            int numFields = inStream.read(8);
17000825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville            paramBits -= CATEGORY_FIELD_MIN_SIZE;
17010825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville
17020825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville            int textBits = getBitsForNumFields(msgEncoding, numFields);
17030825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville            if (paramBits < textBits) {
17040825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville                throw new CodingException("category name is " + textBits + " bits in length,"
17050825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville                        + " but there are only " + paramBits + " bits available");
17060825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville            }
17070825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville
17080825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville            UserData userData = new UserData();
17090825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville            userData.msgEncoding = msgEncoding;
17100825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville            userData.msgEncodingSet = true;
17110825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville            userData.numFields = numFields;
17120825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville            userData.payload = inStream.readByteArray(textBits);
17130825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville            paramBits -= textBits;
17140825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville
17150825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville            decodeUserDataPayload(userData, false);
17160825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville            String categoryName = userData.payloadStr;
17170825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville            CdmaSmsCbProgramData programData = new CdmaSmsCbProgramData(operation, category,
17180825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville                    language, maxMessages, alertOption, categoryName);
17190825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville            programDataList.add(programData);
17200825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville
17210825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville            decodeSuccess = true;
17220825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        }
17230825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville
17240825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        if ((! decodeSuccess) || (paramBits > 0)) {
1725ded9c0af7fa49504c047275ed34c2d3b22bf0c3aWink Saville            Rlog.d(LOG_TAG, "SERVICE_CATEGORY_PROGRAM_DATA decode " +
17260825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville                      (decodeSuccess ? "succeeded" : "failed") +
17270825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville                      " (extra bits = " + paramBits + ')');
17280825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        }
17290825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville
17300825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        inStream.skip(paramBits);
17310825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        bData.serviceCategoryProgramData = programDataList;
17320825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        return decodeSuccess;
17330825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville    }
17340825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville
17350825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville    private static int serviceCategoryToCmasMessageClass(int serviceCategory) {
17360825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        switch (serviceCategory) {
17370825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville            case SmsEnvelope.SERVICE_CATEGORY_CMAS_PRESIDENTIAL_LEVEL_ALERT:
17380825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville                return SmsCbCmasInfo.CMAS_CLASS_PRESIDENTIAL_LEVEL_ALERT;
17390825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville
17400825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville            case SmsEnvelope.SERVICE_CATEGORY_CMAS_EXTREME_THREAT:
17410825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville                return SmsCbCmasInfo.CMAS_CLASS_EXTREME_THREAT;
17420825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville
17430825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville            case SmsEnvelope.SERVICE_CATEGORY_CMAS_SEVERE_THREAT:
17440825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville                return SmsCbCmasInfo.CMAS_CLASS_SEVERE_THREAT;
17450825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville
17460825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville            case SmsEnvelope.SERVICE_CATEGORY_CMAS_CHILD_ABDUCTION_EMERGENCY:
17470825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville                return SmsCbCmasInfo.CMAS_CLASS_CHILD_ABDUCTION_EMERGENCY;
17480825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville
17490825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville            case SmsEnvelope.SERVICE_CATEGORY_CMAS_TEST_MESSAGE:
17500825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville                return SmsCbCmasInfo.CMAS_CLASS_REQUIRED_MONTHLY_TEST;
17510825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville
17520825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville            default:
17530825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville                return SmsCbCmasInfo.CMAS_CLASS_UNKNOWN;
17540825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        }
17550825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville    }
17560825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville
17570825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville    /**
17580825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville     * Calculates the number of bits to read for the specified number of encoded characters.
17590825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville     * @param msgEncoding the message encoding to use
17600825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville     * @param numFields the number of characters to read. For Shift-JIS and Korean encodings,
17610825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville     *  this is the number of bytes to read.
17620825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville     * @return the number of bits to read from the stream
17630825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville     * @throws CodingException if the specified encoding is not supported
17640825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville     */
17650825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville    private static int getBitsForNumFields(int msgEncoding, int numFields)
17660825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville            throws CodingException {
17670825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        switch (msgEncoding) {
17680825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville            case UserData.ENCODING_OCTET:
17690825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville            case UserData.ENCODING_SHIFT_JIS:
17700825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville            case UserData.ENCODING_KOREAN:
17710825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville            case UserData.ENCODING_LATIN:
17720825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville            case UserData.ENCODING_LATIN_HEBREW:
17730825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville                return numFields * 8;
17740825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville
17750825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville            case UserData.ENCODING_IA5:
17760825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville            case UserData.ENCODING_7BIT_ASCII:
17770825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville            case UserData.ENCODING_GSM_7BIT_ALPHABET:
17780825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville                return numFields * 7;
17790825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville
17800825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville            case UserData.ENCODING_UNICODE_16:
17810825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville                return numFields * 16;
17820825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville
17830825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville            default:
17840825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville                throw new CodingException("unsupported message encoding (" + msgEncoding + ')');
17850825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        }
17860825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville    }
17870825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville
17880825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville    /**
17890825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville     * CMAS message decoding.
17900825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville     * (See TIA-1149-0-1, CMAS over CDMA)
17910825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville     *
17920825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville     * @param serviceCategory is the service category from the SMS envelope
17930825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville     */
17940825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville    private static void decodeCmasUserData(BearerData bData, int serviceCategory)
17950825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville            throws BitwiseInputStream.AccessException, CodingException {
17960825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        BitwiseInputStream inStream = new BitwiseInputStream(bData.userData.payload);
17970825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        if (inStream.available() < 8) {
17980825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville            throw new CodingException("emergency CB with no CMAE_protocol_version");
17990825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        }
18000825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        int protocolVersion = inStream.read(8);
18010825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        if (protocolVersion != 0) {
18020825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville            throw new CodingException("unsupported CMAE_protocol_version " + protocolVersion);
18030825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        }
18040825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville
18050825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        int messageClass = serviceCategoryToCmasMessageClass(serviceCategory);
18060825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        int category = SmsCbCmasInfo.CMAS_CATEGORY_UNKNOWN;
18070825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        int responseType = SmsCbCmasInfo.CMAS_RESPONSE_TYPE_UNKNOWN;
18080825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        int severity = SmsCbCmasInfo.CMAS_SEVERITY_UNKNOWN;
18090825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        int urgency = SmsCbCmasInfo.CMAS_URGENCY_UNKNOWN;
18100825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        int certainty = SmsCbCmasInfo.CMAS_CERTAINTY_UNKNOWN;
18110825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville
18120825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        while (inStream.available() >= 16) {
18130825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville            int recordType = inStream.read(8);
18140825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville            int recordLen = inStream.read(8);
18150825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville            switch (recordType) {
18160825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville                case 0:     // Type 0 elements (Alert text)
18170825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville                    UserData alertUserData = new UserData();
18180825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville                    alertUserData.msgEncoding = inStream.read(5);
18190825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville                    alertUserData.msgEncodingSet = true;
18200825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville                    alertUserData.msgType = 0;
18210825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville
18220825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville                    int numFields;                          // number of chars to decode
18230825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville                    switch (alertUserData.msgEncoding) {
18240825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville                        case UserData.ENCODING_OCTET:
18250825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville                        case UserData.ENCODING_LATIN:
18260825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville                            numFields = recordLen - 1;      // subtract 1 byte for encoding
18270825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville                            break;
18280825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville
18290825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville                        case UserData.ENCODING_IA5:
18300825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville                        case UserData.ENCODING_7BIT_ASCII:
18310825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville                        case UserData.ENCODING_GSM_7BIT_ALPHABET:
18320825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville                            numFields = ((recordLen * 8) - 5) / 7;  // subtract 5 bits for encoding
18330825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville                            break;
18340825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville
18350825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville                        case UserData.ENCODING_UNICODE_16:
18360825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville                            numFields = (recordLen - 1) / 2;
18370825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville                            break;
18380825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville
18390825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville                        default:
18400825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville                            numFields = 0;      // unsupported encoding
18410825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville                    }
18420825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville
18430825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville                    alertUserData.numFields = numFields;
18440825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville                    alertUserData.payload = inStream.readByteArray(recordLen * 8 - 5);
18450825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville                    decodeUserDataPayload(alertUserData, false);
18460825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville                    bData.userData = alertUserData;
18470825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville                    break;
18480825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville
18490825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville                case 1:     // Type 1 elements
18500825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville                    category = inStream.read(8);
18510825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville                    responseType = inStream.read(8);
18520825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville                    severity = inStream.read(4);
18530825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville                    urgency = inStream.read(4);
18540825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville                    certainty = inStream.read(4);
18550825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville                    inStream.skip(recordLen * 8 - 28);
18560825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville                    break;
18570825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville
18580825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville                default:
1859ded9c0af7fa49504c047275ed34c2d3b22bf0c3aWink Saville                    Rlog.w(LOG_TAG, "skipping unsupported CMAS record type " + recordType);
18600825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville                    inStream.skip(recordLen * 8);
18610825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville                    break;
18620825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville            }
18630825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        }
18640825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville
18650825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        bData.cmasWarningInfo = new SmsCbCmasInfo(messageClass, category, responseType, severity,
18660825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville                urgency, certainty);
18670825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville    }
18680825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville
18690825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville    /**
18700825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville     * Create BearerData object from serialized representation.
18710825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville     * (See 3GPP2 C.R1001-F, v1.0, section 4.5 for layout details)
18720825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville     *
18730825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville     * @param smsData byte array of raw encoded SMS bearer data.
18740825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville     * @return an instance of BearerData.
18750825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville     */
18760825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville    public static BearerData decode(byte[] smsData) {
18770825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        return decode(smsData, 0);
18780825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville    }
18790825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville
18800825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville    private static boolean isCmasAlertCategory(int category) {
18810825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        return category >= SmsEnvelope.SERVICE_CATEGORY_CMAS_PRESIDENTIAL_LEVEL_ALERT
18820825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville                && category <= SmsEnvelope.SERVICE_CATEGORY_CMAS_LAST_RESERVED_VALUE;
18830825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville    }
18840825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville
18850825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville    /**
18860825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville     * Create BearerData object from serialized representation.
18870825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville     * (See 3GPP2 C.R1001-F, v1.0, section 4.5 for layout details)
18880825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville     *
18890825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville     * @param smsData byte array of raw encoded SMS bearer data.
18900825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville     * @param serviceCategory the envelope service category (for CMAS alert handling)
18910825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville     * @return an instance of BearerData.
18920825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville     */
18930825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville    public static BearerData decode(byte[] smsData, int serviceCategory) {
18940825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        try {
18950825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville            BitwiseInputStream inStream = new BitwiseInputStream(smsData);
18960825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville            BearerData bData = new BearerData();
18970825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville            int foundSubparamMask = 0;
18980825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville            while (inStream.available() > 0) {
18990825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville                int subparamId = inStream.read(8);
19000825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville                int subparamIdBit = 1 << subparamId;
19013de1a7e5535f36e86d82da12df2b17aeeafabdc6Rika Brooks                // int is 4 bytes. This duplicate check has a limit to Id number up to 32 (4*8)
19023de1a7e5535f36e86d82da12df2b17aeeafabdc6Rika Brooks                // as 32th bit is the max bit in int.
19033de1a7e5535f36e86d82da12df2b17aeeafabdc6Rika Brooks                // Per 3GPP2 C.S0015-B Table 4.5-1 Bearer Data Subparameter Identifiers:
19043de1a7e5535f36e86d82da12df2b17aeeafabdc6Rika Brooks                // last defined subparam ID is 23 (00010111 = 0x17 = 23).
19053de1a7e5535f36e86d82da12df2b17aeeafabdc6Rika Brooks                // Only do duplicate subparam ID check if subparam is within defined value as
19063de1a7e5535f36e86d82da12df2b17aeeafabdc6Rika Brooks                // reserved subparams are just skipped.
19073de1a7e5535f36e86d82da12df2b17aeeafabdc6Rika Brooks                if ((foundSubparamMask & subparamIdBit) != 0 &&
19083de1a7e5535f36e86d82da12df2b17aeeafabdc6Rika Brooks                        (subparamId >= SUBPARAM_MESSAGE_IDENTIFIER &&
19093de1a7e5535f36e86d82da12df2b17aeeafabdc6Rika Brooks                        subparamId <= SUBPARAM_ID_LAST_DEFINED)) {
19100825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville                    throw new CodingException("illegal duplicate subparameter (" +
19110825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville                                              subparamId + ")");
19120825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville                }
19130825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville                boolean decodeSuccess;
19140825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville                switch (subparamId) {
19150825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville                case SUBPARAM_MESSAGE_IDENTIFIER:
19160825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville                    decodeSuccess = decodeMessageId(bData, inStream);
19170825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville                    break;
19180825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville                case SUBPARAM_USER_DATA:
19190825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville                    decodeSuccess = decodeUserData(bData, inStream);
19200825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville                    break;
19210825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville                case SUBPARAM_USER_RESPONSE_CODE:
19220825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville                    decodeSuccess = decodeUserResponseCode(bData, inStream);
19230825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville                    break;
19240825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville                case SUBPARAM_REPLY_OPTION:
19250825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville                    decodeSuccess = decodeReplyOption(bData, inStream);
19260825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville                    break;
19270825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville                case SUBPARAM_NUMBER_OF_MESSAGES:
19280825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville                    decodeSuccess = decodeMsgCount(bData, inStream);
19290825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville                    break;
19300825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville                case SUBPARAM_CALLBACK_NUMBER:
19310825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville                    decodeSuccess = decodeCallbackNumber(bData, inStream);
19320825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville                    break;
19330825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville                case SUBPARAM_MESSAGE_STATUS:
19340825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville                    decodeSuccess = decodeMsgStatus(bData, inStream);
19350825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville                    break;
19360825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville                case SUBPARAM_MESSAGE_CENTER_TIME_STAMP:
19370825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville                    decodeSuccess = decodeMsgCenterTimeStamp(bData, inStream);
19380825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville                    break;
19390825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville                case SUBPARAM_VALIDITY_PERIOD_ABSOLUTE:
19400825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville                    decodeSuccess = decodeValidityAbs(bData, inStream);
19410825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville                    break;
19420825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville                case SUBPARAM_VALIDITY_PERIOD_RELATIVE:
19430825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville                    decodeSuccess = decodeValidityRel(bData, inStream);
19440825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville                    break;
19450825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville                case SUBPARAM_DEFERRED_DELIVERY_TIME_ABSOLUTE:
19460825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville                    decodeSuccess = decodeDeferredDeliveryAbs(bData, inStream);
19470825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville                    break;
19480825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville                case SUBPARAM_DEFERRED_DELIVERY_TIME_RELATIVE:
19490825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville                    decodeSuccess = decodeDeferredDeliveryRel(bData, inStream);
19500825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville                    break;
19510825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville                case SUBPARAM_PRIVACY_INDICATOR:
19520825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville                    decodeSuccess = decodePrivacyIndicator(bData, inStream);
19530825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville                    break;
19540825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville                case SUBPARAM_LANGUAGE_INDICATOR:
19550825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville                    decodeSuccess = decodeLanguageIndicator(bData, inStream);
19560825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville                    break;
19570825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville                case SUBPARAM_MESSAGE_DISPLAY_MODE:
19580825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville                    decodeSuccess = decodeDisplayMode(bData, inStream);
19590825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville                    break;
19600825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville                case SUBPARAM_PRIORITY_INDICATOR:
19610825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville                    decodeSuccess = decodePriorityIndicator(bData, inStream);
19620825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville                    break;
19630825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville                case SUBPARAM_ALERT_ON_MESSAGE_DELIVERY:
19640825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville                    decodeSuccess = decodeMsgDeliveryAlert(bData, inStream);
19650825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville                    break;
19660825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville                case SUBPARAM_MESSAGE_DEPOSIT_INDEX:
19670825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville                    decodeSuccess = decodeDepositIndex(bData, inStream);
19680825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville                    break;
19690825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville                case SUBPARAM_SERVICE_CATEGORY_PROGRAM_DATA:
19700825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville                    decodeSuccess = decodeServiceCategoryProgramData(bData, inStream);
19710825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville                    break;
19720825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville                default:
19733de1a7e5535f36e86d82da12df2b17aeeafabdc6Rika Brooks                    decodeSuccess = decodeReserved(bData, inStream, subparamId);
19743de1a7e5535f36e86d82da12df2b17aeeafabdc6Rika Brooks                }
19753de1a7e5535f36e86d82da12df2b17aeeafabdc6Rika Brooks                if (decodeSuccess &&
19763de1a7e5535f36e86d82da12df2b17aeeafabdc6Rika Brooks                        (subparamId >= SUBPARAM_MESSAGE_IDENTIFIER &&
19773de1a7e5535f36e86d82da12df2b17aeeafabdc6Rika Brooks                        subparamId <= SUBPARAM_ID_LAST_DEFINED)) {
19783de1a7e5535f36e86d82da12df2b17aeeafabdc6Rika Brooks                    foundSubparamMask |= subparamIdBit;
19790825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville                }
19800825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville            }
19810825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville            if ((foundSubparamMask & (1 << SUBPARAM_MESSAGE_IDENTIFIER)) == 0) {
19820825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville                throw new CodingException("missing MESSAGE_IDENTIFIER subparam");
19830825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville            }
19840825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville            if (bData.userData != null) {
19850825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville                if (isCmasAlertCategory(serviceCategory)) {
19860825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville                    decodeCmasUserData(bData, serviceCategory);
19870825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville                } else if (bData.userData.msgEncoding == UserData.ENCODING_IS91_EXTENDED_PROTOCOL) {
19880825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville                    if ((foundSubparamMask ^
19890825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville                             (1 << SUBPARAM_MESSAGE_IDENTIFIER) ^
19900825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville                             (1 << SUBPARAM_USER_DATA))
19910825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville                            != 0) {
1992ded9c0af7fa49504c047275ed34c2d3b22bf0c3aWink Saville                        Rlog.e(LOG_TAG, "IS-91 must occur without extra subparams (" +
19930825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville                              foundSubparamMask + ")");
19940825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville                    }
19950825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville                    decodeIs91(bData);
19960825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville                } else {
19970825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville                    decodeUserDataPayload(bData.userData, bData.hasUserDataHeader);
19980825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville                }
19990825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville            }
20000825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville            return bData;
20010825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        } catch (BitwiseInputStream.AccessException ex) {
2002ded9c0af7fa49504c047275ed34c2d3b22bf0c3aWink Saville            Rlog.e(LOG_TAG, "BearerData decode failed: " + ex);
20030825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        } catch (CodingException ex) {
2004ded9c0af7fa49504c047275ed34c2d3b22bf0c3aWink Saville            Rlog.e(LOG_TAG, "BearerData decode failed: " + ex);
20050825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        }
20060825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        return null;
20070825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville    }
20080825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville}
2009