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