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