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