1 /* 2 * Copyright (C) 2012 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17 package com.android.cellbroadcastservice.tests; 18 19 import android.content.Context; 20 import android.hardware.radio.V1_0.CdmaSmsMessage; 21 import android.telephony.SmsCbCmasInfo; 22 import android.telephony.SmsCbMessage; 23 import android.telephony.cdma.CdmaSmsCbProgramData; 24 import android.testing.AndroidTestingRunner; 25 import android.testing.TestableLooper; 26 import android.util.Log; 27 28 import com.android.cellbroadcastservice.BearerData; 29 import com.android.cellbroadcastservice.DefaultCellBroadcastService; 30 import com.android.internal.telephony.GsmAlphabet; 31 import com.android.internal.telephony.cdma.SmsMessage; 32 import com.android.internal.telephony.cdma.sms.CdmaSmsAddress; 33 import com.android.internal.telephony.cdma.sms.CdmaSmsSubaddress; 34 import com.android.internal.telephony.cdma.sms.SmsEnvelope; 35 import com.android.internal.util.BitwiseOutputStream; 36 37 import org.junit.After; 38 import org.junit.Before; 39 import org.junit.Ignore; 40 import org.junit.Test; 41 import org.junit.runner.RunWith; 42 43 import java.util.Arrays; 44 import java.util.List; 45 import java.util.Random; 46 47 /** 48 * Test cases to verify that our parseCdmaBroadcastSms function correctly works with the 49 * CdmaSmsMessage class. 50 */ 51 @RunWith(AndroidTestingRunner.class) 52 @TestableLooper.RunWithLooper 53 public class CdmaSmsMessageTest extends CellBroadcastServiceTestBase { 54 55 private static final String TAG = "CdmaSmsMessageTest"; 56 57 /* Copy of private subparameter identifier constants from BearerData class. */ 58 private static final byte SUBPARAM_MESSAGE_IDENTIFIER = (byte) 0x00; 59 private static final byte SUBPARAM_USER_DATA = (byte) 0x01; 60 private static final byte SUBPARAM_PRIORITY_INDICATOR = (byte) 0x08; 61 private static final byte SUBPARAM_LANGUAGE_INDICATOR = (byte) 0x0D; 62 private static final byte SUBPARAM_SERVICE_CATEGORY_PROGRAM_DATA = 0x12; 63 64 private static final int TELESERVICE_NOT_SET = 0x0000; 65 private static final int TELESERVICE_SCPT = 0x1006; 66 67 /** 68 * Digit Mode Indicator is a 1-bit value that indicates whether 69 * the address digits are 4-bit DTMF codes or 8-bit codes. (See 70 * 3GPP2 C.S0015-B, v2, 3.4.3.3) 71 */ 72 private static final int DIGIT_MODE_4BIT_DTMF = 0x00; 73 private static final int DIGIT_MODE_8BIT_CHAR = 0x01; 74 75 /** 76 * Number Mode Indicator is 1-bit value that indicates whether the 77 * address type is a data network address or not. (See 3GPP2 78 * C.S0015-B, v2, 3.4.3.3) 79 */ 80 private static final int NUMBER_MODE_NOT_DATA_NETWORK = 0x00; 81 private static final int NUMBER_MODE_DATA_NETWORK = 0x01; 82 83 /** 84 * Number Types for data networks. 85 * (See 3GPP2 C.S005-D, table2.7.1.3.2.4-2 for complete table) 86 * (See 3GPP2 C.S0015-B, v2, 3.4.3.3 for data network subset) 87 * NOTE: value is stored in the parent class ton field. 88 */ 89 private static final int TON_UNKNOWN = 0x00; 90 91 /** 92 * Numbering Plan identification is a 0 or 4-bit value that 93 * indicates which numbering plan identification is set. (See 94 * 3GPP2, C.S0015-B, v2, 3.4.3.3 and C.S005-D, table2.7.1.3.2.4-3) 95 */ 96 private static final int NUMBERING_PLAN_ISDN_TELEPHONY = 0x1; 97 98 /** 99 * User data encoding types. 100 * (See 3GPP2 C.R1001-F, v1.0, table 9.1-1) 101 */ 102 public static final int ENCODING_OCTET = 0x00; 103 public static final int ENCODING_IS91_EXTENDED_PROTOCOL = 0x01; 104 public static final int ENCODING_7BIT_ASCII = 0x02; 105 public static final int ENCODING_IA5 = 0x03; 106 public static final int ENCODING_UNICODE_16 = 0x04; 107 public static final int ENCODING_SHIFT_JIS = 0x05; 108 public static final int ENCODING_KOREAN = 0x06; 109 public static final int ENCODING_LATIN_HEBREW = 0x07; 110 public static final int ENCODING_LATIN = 0x08; 111 public static final int ENCODING_GSM_7BIT_ALPHABET = 0x09; 112 public static final int ENCODING_GSM_DCS = 0x0A; 113 114 /** 115 * IS-91 message types. 116 * (See TIA/EIS/IS-91-A-ENGL 1999, table 3.7.1.1-3) 117 */ 118 public static final int IS91_MSG_TYPE_VOICEMAIL_STATUS = 0x82; 119 public static final int IS91_MSG_TYPE_SHORT_MESSAGE_FULL = 0x83; 120 public static final int IS91_MSG_TYPE_CLI = 0x84; 121 public static final int IS91_MSG_TYPE_SHORT_MESSAGE = 0x85; 122 123 /** 124 * Supported message types for CDMA SMS messages 125 * (See 3GPP2 C.S0015-B, v2.0, table 4.5.1-1) 126 */ 127 public static final int MESSAGE_TYPE_DELIVER = 0x01; 128 public static final int MESSAGE_TYPE_SUBMIT = 0x02; 129 public static final int MESSAGE_TYPE_CANCELLATION = 0x03; 130 public static final int MESSAGE_TYPE_DELIVERY_ACK = 0x04; 131 132 @Before setUp()133 public void setUp() throws Exception { 134 super.setUp(); 135 putResources(com.android.cellbroadcastservice.R.bool.config_sms_utf8_support, false); 136 } 137 138 @After tearDown()139 public void tearDown() throws Exception { 140 super.tearDown(); 141 } 142 143 /** 144 * Initialize a Parcel for an incoming CDMA cell broadcast. The caller will write the 145 * bearer data and then convert it to an SmsMessage. 146 * 147 * @param serviceCategory the CDMA service category 148 * @return the initialized Parcel 149 */ createBroadcastParcel(int serviceCategory)150 private static CdmaSmsMessage createBroadcastParcel(int serviceCategory) { 151 CdmaSmsMessage msg = new CdmaSmsMessage(); 152 153 msg.teleserviceId = TELESERVICE_NOT_SET; 154 msg.isServicePresent = true; 155 msg.serviceCategory = serviceCategory; 156 157 // dummy address (RIL may generate a different dummy address for broadcasts) 158 msg.address.digitMode = DIGIT_MODE_4BIT_DTMF; 159 msg.address.numberMode = NUMBER_MODE_NOT_DATA_NETWORK; 160 msg.address.numberType = TON_UNKNOWN; 161 msg.address.numberPlan = NUMBERING_PLAN_ISDN_TELEPHONY; 162 msg.subAddress.subaddressType = 0; 163 msg.subAddress.odd = false; 164 return msg; 165 } 166 167 /** 168 * Initialize a BitwiseOutputStream with the CDMA bearer data subparameters except for 169 * user data. The caller will append the user data and add it to the parcel. 170 * 171 * @param messageId the 16-bit message identifier 172 * @param priority message priority 173 * @param language message language code 174 * @return the initialized BitwiseOutputStream 175 */ createBearerDataStream(int messageId, int priority, int language)176 private static BitwiseOutputStream createBearerDataStream(int messageId, int priority, 177 int language) throws BitwiseOutputStream.AccessException { 178 BitwiseOutputStream bos = new BitwiseOutputStream(10); 179 bos.write(8, SUBPARAM_MESSAGE_IDENTIFIER); 180 bos.write(8, 3); // length: 3 bytes 181 bos.write(4, BearerData.MESSAGE_TYPE_DELIVER); 182 bos.write(8, ((messageId >>> 8) & 0xff)); 183 bos.write(8, (messageId & 0xff)); 184 bos.write(1, 0); // no User Data Header 185 bos.write(3, 0); // reserved 186 187 if (priority != -1) { 188 bos.write(8, SUBPARAM_PRIORITY_INDICATOR); 189 bos.write(8, 1); // length: 1 byte 190 bos.write(2, (priority & 0x03)); 191 bos.write(6, 0); // reserved 192 } 193 194 if (language != -1) { 195 bos.write(8, SUBPARAM_LANGUAGE_INDICATOR); 196 bos.write(8, 1); // length: 1 byte 197 bos.write(8, (language & 0xff)); 198 } 199 200 return bos; 201 } 202 203 /** 204 * Convert CdmaSmsMessage defined in radio/1.0/types.hal to SmsMessage 205 * Note only primitive fields are set 206 * @param cdmaSmsMessage CdmaSmsMessage defined in radio/1.0/types.hal 207 * @return A converted SmsMessage 208 * TODO: remove this method and use the one in RILUtils 209 */ convertHalCdmaSmsMessage( android.hardware.radio.V1_0.CdmaSmsMessage cdmaSmsMessage)210 private static SmsMessage convertHalCdmaSmsMessage( 211 android.hardware.radio.V1_0.CdmaSmsMessage cdmaSmsMessage) { 212 // Note: Parcel.readByte actually reads one Int and masks to byte 213 SmsEnvelope env = new SmsEnvelope(); 214 CdmaSmsAddress addr = new CdmaSmsAddress(); 215 CdmaSmsSubaddress subaddr = new CdmaSmsSubaddress(); 216 byte[] data; 217 byte count; 218 int countInt; 219 int addressDigitMode; 220 221 //currently not supported by the modem-lib: env.mMessageType 222 env.teleService = cdmaSmsMessage.teleserviceId; 223 224 if (cdmaSmsMessage.isServicePresent) { 225 env.messageType = SmsEnvelope.MESSAGE_TYPE_BROADCAST; 226 } else { 227 if (SmsEnvelope.TELESERVICE_NOT_SET == env.teleService) { 228 // assume type ACK 229 env.messageType = SmsEnvelope.MESSAGE_TYPE_ACKNOWLEDGE; 230 } else { 231 env.messageType = SmsEnvelope.MESSAGE_TYPE_POINT_TO_POINT; 232 } 233 } 234 env.serviceCategory = cdmaSmsMessage.serviceCategory; 235 236 // address 237 addressDigitMode = cdmaSmsMessage.address.digitMode; 238 addr.digitMode = (byte) (0xFF & addressDigitMode); 239 addr.numberMode = (byte) (0xFF & cdmaSmsMessage.address.numberMode); 240 addr.ton = cdmaSmsMessage.address.numberType; 241 addr.numberPlan = (byte) (0xFF & cdmaSmsMessage.address.numberPlan); 242 count = (byte) cdmaSmsMessage.address.digits.size(); 243 addr.numberOfDigits = count; 244 data = new byte[count]; 245 for (int index = 0; index < count; index++) { 246 data[index] = cdmaSmsMessage.address.digits.get(index); 247 248 // convert the value if it is 4-bit DTMF to 8 bit 249 if (addressDigitMode == CdmaSmsAddress.DIGIT_MODE_4BIT_DTMF) { 250 data[index] = SmsMessage.convertDtmfToAscii(data[index]); 251 } 252 } 253 254 addr.origBytes = data; 255 256 subaddr.type = cdmaSmsMessage.subAddress.subaddressType; 257 subaddr.odd = (byte) (cdmaSmsMessage.subAddress.odd ? 1 : 0); 258 count = (byte) cdmaSmsMessage.subAddress.digits.size(); 259 260 if (count < 0) { 261 count = 0; 262 } 263 264 // p_cur->sSubAddress.digits[digitCount] : 265 266 data = new byte[count]; 267 268 for (int index = 0; index < count; ++index) { 269 data[index] = cdmaSmsMessage.subAddress.digits.get(index); 270 } 271 272 subaddr.origBytes = data; 273 274 /* currently not supported by the modem-lib: 275 env.bearerReply 276 env.replySeqNo 277 env.errorClass 278 env.causeCode 279 */ 280 281 // bearer data 282 countInt = cdmaSmsMessage.bearerData.size(); 283 if (countInt < 0) { 284 countInt = 0; 285 } 286 287 data = new byte[countInt]; 288 for (int index = 0; index < countInt; index++) { 289 data[index] = cdmaSmsMessage.bearerData.get(index); 290 } 291 // BD gets further decoded when accessed in SMSDispatcher 292 env.bearerData = data; 293 294 // link the filled objects to the SMS 295 env.origAddress = addr; 296 env.origSubaddress = subaddr; 297 298 SmsMessage msg = new SmsMessage(addr, env); 299 300 return msg; 301 } 302 303 /** 304 * Write the bearer data array to the parcel, then return a new SmsMessage from the parcel. 305 * 306 * @param msg CdmaSmsMessage containing the CDMA SMS headers 307 * @param bearerData the bearer data byte array to append to the parcel 308 * @return the new SmsMessage created from the parcel 309 */ createMessageFromParcel(CdmaSmsMessage msg, byte[] bearerData)310 private static SmsMessage createMessageFromParcel(CdmaSmsMessage msg, byte[] bearerData) { 311 for (byte b : bearerData) { 312 msg.bearerData.add(b); 313 } 314 SmsMessage message = convertHalCdmaSmsMessage(msg); 315 return message; 316 } 317 318 /** 319 * Create a parcel for an incoming CMAS broadcast, then return a new SmsMessage created 320 * from the parcel. 321 * 322 * @param serviceCategory the CDMA service category 323 * @param messageId the 16-bit message identifier 324 * @param priority message priority 325 * @param language message language code 326 * @param body message body 327 * @param cmasCategory CMAS category (or -1 to skip adding CMAS type 1 elements record) 328 * @param responseType CMAS response type 329 * @param severity CMAS severity 330 * @param urgency CMAS urgency 331 * @param certainty CMAS certainty 332 * @return the newly created SmsMessage object 333 */ createCmasSmsMessage(int serviceCategory, int messageId, int priority, int language, int encoding, String body, int cmasCategory, int responseType, int severity, int urgency, int certainty)334 private static SmsMessage createCmasSmsMessage(int serviceCategory, int messageId, int priority, 335 int language, int encoding, String body, int cmasCategory, int responseType, 336 int severity, int urgency, int certainty) throws Exception { 337 BitwiseOutputStream cmasBos = new BitwiseOutputStream(10); 338 cmasBos.write(8, 0); // CMAE protocol version 0 339 340 if (body != null) { 341 cmasBos.write(8, 0); // Type 0 elements (alert text) 342 encodeBody(encoding, body, true, cmasBos); 343 } 344 345 if (cmasCategory != SmsCbCmasInfo.CMAS_CATEGORY_UNKNOWN) { 346 cmasBos.write(8, 1); // Type 1 elements 347 cmasBos.write(8, 4); // length: 4 bytes 348 cmasBos.write(8, (cmasCategory & 0xff)); 349 cmasBos.write(8, (responseType & 0xff)); 350 cmasBos.write(4, (severity & 0x0f)); 351 cmasBos.write(4, (urgency & 0x0f)); 352 cmasBos.write(4, (certainty & 0x0f)); 353 cmasBos.write(4, 0); // pad to octet boundary 354 } 355 356 byte[] cmasUserData = cmasBos.toByteArray(); 357 358 CdmaSmsMessage msg = createBroadcastParcel(serviceCategory); 359 BitwiseOutputStream bos = createBearerDataStream(messageId, priority, language); 360 361 bos.write(8, SUBPARAM_USER_DATA); 362 bos.write(8, cmasUserData.length + 2); // add 2 bytes for msg_encoding and num_fields 363 bos.write(5, ENCODING_OCTET); 364 bos.write(8, cmasUserData.length); 365 bos.writeByteArray(cmasUserData.length * 8, cmasUserData); 366 bos.write(3, 0); // pad to byte boundary 367 368 return createMessageFromParcel(msg, bos.toByteArray()); 369 } 370 371 /** 372 * Create a parcel for an incoming CDMA cell broadcast, then return a new SmsMessage created 373 * from the parcel. 374 * 375 * @param serviceCategory the CDMA service category 376 * @param messageId the 16-bit message identifier 377 * @param priority message priority 378 * @param language message language code 379 * @param encoding user data encoding method 380 * @param body the message body 381 * @return the newly created SmsMessage object 382 */ createBroadcastSmsMessage(int serviceCategory, int messageId, int priority, int language, int encoding, String body)383 private static SmsMessage createBroadcastSmsMessage(int serviceCategory, int messageId, 384 int priority, int language, int encoding, String body) throws Exception { 385 CdmaSmsMessage msg = createBroadcastParcel(serviceCategory); 386 BitwiseOutputStream bos = createBearerDataStream(messageId, priority, language); 387 388 bos.write(8, SUBPARAM_USER_DATA); 389 encodeBody(encoding, body, false, bos); 390 391 return createMessageFromParcel(msg, bos.toByteArray()); 392 } 393 394 /** 395 * Append the message length, encoding, and body to the BearerData output stream. 396 * This is used for writing the User Data subparameter for non-CMAS broadcasts and for 397 * writing the alert text for CMAS broadcasts. 398 * 399 * @param encoding one of the CDMA UserData encoding values 400 * @param body the message body 401 * @param isCmasRecord true if this is a CMAS type 0 elements record; false for user data 402 * @param bos the BitwiseOutputStream to write to 403 * @throws Exception on any encoding error 404 */ encodeBody(int encoding, String body, boolean isCmasRecord, BitwiseOutputStream bos)405 private static void encodeBody(int encoding, String body, boolean isCmasRecord, 406 BitwiseOutputStream bos) throws Exception { 407 if (encoding == ENCODING_7BIT_ASCII || encoding == ENCODING_IA5) { 408 int charCount = body.length(); 409 int recordBits = (charCount * 7) + 5; // add 5 bits for char set field 410 int recordOctets = (recordBits + 7) / 8; // round up to octet boundary 411 int padBits = (recordOctets * 8) - recordBits; 412 413 if (!isCmasRecord) { 414 recordOctets++; // add 8 bits for num_fields 415 } 416 417 bos.write(8, recordOctets); 418 bos.write(5, (encoding & 0x1f)); 419 420 if (!isCmasRecord) { 421 bos.write(8, charCount); 422 } 423 424 for (int i = 0; i < charCount; i++) { 425 bos.write(7, body.charAt(i)); 426 } 427 428 bos.write(padBits, 0); // pad to octet boundary 429 } else if (encoding == ENCODING_GSM_7BIT_ALPHABET 430 || encoding == ENCODING_GSM_DCS) { 431 // convert to 7-bit packed encoding with septet count in index 0 of byte array 432 byte[] encodedBody = GsmAlphabet.stringToGsm7BitPacked(body); 433 434 int charCount = encodedBody[0]; // septet count 435 int recordBits = (charCount * 7) + 5; // add 5 bits for char set field 436 int recordOctets = (recordBits + 7) / 8; // round up to octet boundary 437 int padBits = (recordOctets * 8) - recordBits; 438 439 if (!isCmasRecord) { 440 recordOctets++; // add 8 bits for num_fields 441 if (encoding == ENCODING_GSM_DCS) { 442 recordOctets++; // add 8 bits for DCS (message type) 443 } 444 } 445 446 bos.write(8, recordOctets); 447 bos.write(5, (encoding & 0x1f)); 448 449 if (!isCmasRecord && encoding == ENCODING_GSM_DCS) { 450 bos.write(8, 0); // GSM DCS: 7 bit default alphabet, no msg class 451 } 452 453 if (!isCmasRecord) { 454 bos.write(8, charCount); 455 } 456 byte[] bodySeptets = Arrays.copyOfRange(encodedBody, 1, encodedBody.length); 457 bos.writeByteArray(charCount * 7, bodySeptets); 458 bos.write(padBits, 0); // pad to octet boundary 459 } else if (encoding == ENCODING_IS91_EXTENDED_PROTOCOL) { 460 // 6 bit packed encoding with 0x20 offset (ASCII 0x20 - 0x60) 461 int charCount = body.length(); 462 int recordBits = (charCount * 6) + 21; // add 21 bits for header fields 463 int recordOctets = (recordBits + 7) / 8; // round up to octet boundary 464 int padBits = (recordOctets * 8) - recordBits; 465 466 bos.write(8, recordOctets); 467 468 bos.write(5, (encoding & 0x1f)); 469 bos.write(8, IS91_MSG_TYPE_SHORT_MESSAGE); 470 bos.write(8, charCount); 471 472 for (int i = 0; i < charCount; i++) { 473 bos.write(6, ((int) body.charAt(i) - 0x20)); 474 } 475 476 bos.write(padBits, 0); // pad to octet boundary 477 } else { 478 byte[] encodedBody; 479 switch (encoding) { 480 case ENCODING_UNICODE_16: 481 encodedBody = body.getBytes("UTF-16BE"); 482 break; 483 484 case ENCODING_SHIFT_JIS: 485 encodedBody = body.getBytes("Shift_JIS"); 486 break; 487 488 case ENCODING_KOREAN: 489 encodedBody = body.getBytes("KSC5601"); 490 break; 491 492 case ENCODING_LATIN_HEBREW: 493 encodedBody = body.getBytes("ISO-8859-8"); 494 break; 495 496 case ENCODING_LATIN: 497 default: 498 encodedBody = body.getBytes("ISO-8859-1"); 499 break; 500 } 501 int charCount = body.length(); // use actual char count for num fields 502 int recordOctets = encodedBody.length + 1; // add 1 byte for encoding and pad bits 503 if (!isCmasRecord) { 504 recordOctets++; // add 8 bits for num_fields 505 } 506 bos.write(8, recordOctets); 507 bos.write(5, (encoding & 0x1f)); 508 if (!isCmasRecord) { 509 bos.write(8, charCount); 510 } 511 bos.writeByteArray(encodedBody.length * 8, encodedBody); 512 bos.write(3, 0); // pad to octet boundary 513 } 514 } 515 516 private static final String TEST_TEXT = "This is a test CDMA cell broadcast message..." 517 + "678901234567890123456789012345678901234567890"; 518 519 private static final String PRES_ALERT = 520 "THE PRESIDENT HAS ISSUED AN EMERGENCY ALERT. CHECK LOCAL MEDIA FOR MORE DETAILS"; 521 522 private static final String EXTREME_ALERT = "FLASH FLOOD WARNING FOR SOUTH COCONINO COUNTY" 523 + " - NORTH CENTRAL ARIZONA UNTIL 415 PM MST"; 524 525 private static final String SEVERE_ALERT = "SEVERE WEATHER WARNING FOR SOMERSET COUNTY" 526 + " - NEW JERSEY UNTIL 415 PM MST"; 527 528 private static final String AMBER_ALERT = 529 "AMBER ALERT:Mountain View,CA VEH'07 Blue Honda Civic CA LIC 5ABC123"; 530 531 private static final String MONTHLY_TEST_ALERT = "This is a test of the emergency alert system." 532 + " This is only a test. 89012345678901234567890"; 533 534 private static final String IS91_TEXT = "IS91 SHORT MSG"; // max length 14 chars 535 536 /** 537 * Verify that the SmsCbMessage has the correct values for CDMA. 538 * 539 * @param cbMessage the message to test 540 */ verifyCbValues(SmsCbMessage cbMessage)541 private static void verifyCbValues(SmsCbMessage cbMessage) { 542 assertEquals(SmsCbMessage.MESSAGE_FORMAT_3GPP2, cbMessage.getMessageFormat()); 543 assertEquals(SmsCbMessage.GEOGRAPHICAL_SCOPE_PLMN_WIDE, cbMessage.getGeographicalScope()); 544 assertEquals(false, cbMessage.isEtwsMessage()); // ETWS on CDMA not currently supported 545 } 546 doTestNonEmergencyBroadcast(Context context, int encoding)547 private static void doTestNonEmergencyBroadcast(Context context, int encoding) 548 throws Exception { 549 SmsMessage msg = createBroadcastSmsMessage(123, 456, BearerData.PRIORITY_NORMAL, 550 BearerData.LANGUAGE_ENGLISH, encoding, TEST_TEXT); 551 552 SmsCbMessage cbMessage = 553 DefaultCellBroadcastService.parseCdmaBroadcastSms(context, 554 0, "", msg.getEnvelopeBearerData(), msg.getEnvelopeServiceCategory()); 555 //SmsCbMessage cbMessage = msg.parseCdmaBroadcastSms("", 0); 556 verifyCbValues(cbMessage); 557 assertEquals(123, cbMessage.getServiceCategory()); 558 assertEquals(456, cbMessage.getSerialNumber()); 559 assertEquals(SmsCbMessage.MESSAGE_PRIORITY_NORMAL, cbMessage.getMessagePriority()); 560 assertEquals("en", cbMessage.getLanguageCode()); 561 assertEquals(TEST_TEXT, cbMessage.getMessageBody()); 562 assertEquals(false, cbMessage.isEmergencyMessage()); 563 assertEquals(false, cbMessage.isCmasMessage()); 564 } 565 566 @Test testNonEmergencyBroadcast7bitAscii()567 public void testNonEmergencyBroadcast7bitAscii() throws Exception { 568 doTestNonEmergencyBroadcast(mMockedContext, ENCODING_7BIT_ASCII); 569 } 570 571 @Test testNonEmergencyBroadcast7bitGsm()572 public void testNonEmergencyBroadcast7bitGsm() throws Exception { 573 doTestNonEmergencyBroadcast(mMockedContext, ENCODING_GSM_7BIT_ALPHABET); 574 } 575 576 @Test testNonEmergencyBroadcast16bitUnicode()577 public void testNonEmergencyBroadcast16bitUnicode() throws Exception { 578 doTestNonEmergencyBroadcast(mMockedContext, ENCODING_UNICODE_16); 579 } 580 doTestCmasBroadcast(Context context, int serviceCategory, int messageClass, String body)581 private static void doTestCmasBroadcast(Context context, int serviceCategory, int messageClass, 582 String body) throws Exception { 583 SmsMessage msg = createCmasSmsMessage( 584 serviceCategory, 1234, BearerData.PRIORITY_EMERGENCY, BearerData.LANGUAGE_ENGLISH, 585 ENCODING_7BIT_ASCII, body, -1, -1, -1, -1, -1); 586 587 SmsCbMessage cbMessage = 588 DefaultCellBroadcastService.parseCdmaBroadcastSms(context, 589 0, "", msg.getEnvelopeBearerData(), msg.getEnvelopeServiceCategory()); 590 //SmsCbMessage cbMessage = msg.parseCdmaBroadcastSms("", 0); 591 verifyCbValues(cbMessage); 592 assertEquals(serviceCategory, cbMessage.getServiceCategory()); 593 assertEquals(1234, cbMessage.getSerialNumber()); 594 assertEquals(SmsCbMessage.MESSAGE_PRIORITY_EMERGENCY, cbMessage.getMessagePriority()); 595 assertEquals("en", cbMessage.getLanguageCode()); 596 assertEquals(body, cbMessage.getMessageBody()); 597 assertEquals(true, cbMessage.isEmergencyMessage()); 598 assertEquals(true, cbMessage.isCmasMessage()); 599 SmsCbCmasInfo cmasInfo = cbMessage.getCmasWarningInfo(); 600 assertEquals(messageClass, cmasInfo.getMessageClass()); 601 assertEquals(SmsCbCmasInfo.CMAS_CATEGORY_UNKNOWN, cmasInfo.getCategory()); 602 assertEquals(SmsCbCmasInfo.CMAS_RESPONSE_TYPE_UNKNOWN, cmasInfo.getResponseType()); 603 assertEquals(SmsCbCmasInfo.CMAS_SEVERITY_UNKNOWN, cmasInfo.getSeverity()); 604 assertEquals(SmsCbCmasInfo.CMAS_URGENCY_UNKNOWN, cmasInfo.getUrgency()); 605 assertEquals(SmsCbCmasInfo.CMAS_CERTAINTY_UNKNOWN, cmasInfo.getCertainty()); 606 } 607 608 @Test testCmasPresidentialAlert()609 public void testCmasPresidentialAlert() throws Exception { 610 doTestCmasBroadcast(mMockedContext, 611 CdmaSmsCbProgramData.CATEGORY_CMAS_PRESIDENTIAL_LEVEL_ALERT, 612 SmsCbCmasInfo.CMAS_CLASS_PRESIDENTIAL_LEVEL_ALERT, PRES_ALERT); 613 } 614 615 @Test testCmasExtremeAlert()616 public void testCmasExtremeAlert() throws Exception { 617 doTestCmasBroadcast(mMockedContext, CdmaSmsCbProgramData.CATEGORY_CMAS_EXTREME_THREAT, 618 SmsCbCmasInfo.CMAS_CLASS_EXTREME_THREAT, EXTREME_ALERT); 619 } 620 621 @Test testCmasSevereAlert()622 public void testCmasSevereAlert() throws Exception { 623 doTestCmasBroadcast(mMockedContext, CdmaSmsCbProgramData.CATEGORY_CMAS_SEVERE_THREAT, 624 SmsCbCmasInfo.CMAS_CLASS_SEVERE_THREAT, SEVERE_ALERT); 625 } 626 627 @Test testCmasAmberAlert()628 public void testCmasAmberAlert() throws Exception { 629 doTestCmasBroadcast(mMockedContext, 630 CdmaSmsCbProgramData.CATEGORY_CMAS_CHILD_ABDUCTION_EMERGENCY, 631 SmsCbCmasInfo.CMAS_CLASS_CHILD_ABDUCTION_EMERGENCY, AMBER_ALERT); 632 } 633 634 @Test testCmasTestMessage()635 public void testCmasTestMessage() throws Exception { 636 doTestCmasBroadcast(mMockedContext, CdmaSmsCbProgramData.CATEGORY_CMAS_TEST_MESSAGE, 637 SmsCbCmasInfo.CMAS_CLASS_REQUIRED_MONTHLY_TEST, MONTHLY_TEST_ALERT); 638 } 639 640 @Test testCmasExtremeAlertType1Elements()641 public void testCmasExtremeAlertType1Elements() throws Exception { 642 SmsMessage msg = createCmasSmsMessage(CdmaSmsCbProgramData.CATEGORY_CMAS_EXTREME_THREAT, 643 5678, BearerData.PRIORITY_EMERGENCY, BearerData.LANGUAGE_ENGLISH, 644 ENCODING_7BIT_ASCII, EXTREME_ALERT, SmsCbCmasInfo.CMAS_CATEGORY_ENV, 645 SmsCbCmasInfo.CMAS_RESPONSE_TYPE_MONITOR, SmsCbCmasInfo.CMAS_SEVERITY_SEVERE, 646 SmsCbCmasInfo.CMAS_URGENCY_EXPECTED, SmsCbCmasInfo.CMAS_CERTAINTY_LIKELY); 647 648 SmsCbMessage cbMessage = 649 DefaultCellBroadcastService.parseCdmaBroadcastSms(mMockedContext, 650 0, "", msg.getEnvelopeBearerData(), msg.getEnvelopeServiceCategory()); 651 //SmsCbMessage cbMessage = msg.parseCdmaBroadcastSms("", 0); 652 verifyCbValues(cbMessage); 653 assertEquals(CdmaSmsCbProgramData.CATEGORY_CMAS_EXTREME_THREAT, 654 cbMessage.getServiceCategory()); 655 assertEquals(5678, cbMessage.getSerialNumber()); 656 assertEquals(SmsCbMessage.MESSAGE_PRIORITY_EMERGENCY, cbMessage.getMessagePriority()); 657 assertEquals("en", cbMessage.getLanguageCode()); 658 assertEquals(EXTREME_ALERT, cbMessage.getMessageBody()); 659 assertEquals(true, cbMessage.isEmergencyMessage()); 660 assertEquals(true, cbMessage.isCmasMessage()); 661 SmsCbCmasInfo cmasInfo = cbMessage.getCmasWarningInfo(); 662 assertEquals(SmsCbCmasInfo.CMAS_CLASS_EXTREME_THREAT, cmasInfo.getMessageClass()); 663 assertEquals(SmsCbCmasInfo.CMAS_CATEGORY_ENV, cmasInfo.getCategory()); 664 assertEquals(SmsCbCmasInfo.CMAS_RESPONSE_TYPE_MONITOR, cmasInfo.getResponseType()); 665 assertEquals(SmsCbCmasInfo.CMAS_SEVERITY_SEVERE, cmasInfo.getSeverity()); 666 assertEquals(SmsCbCmasInfo.CMAS_URGENCY_EXPECTED, cmasInfo.getUrgency()); 667 assertEquals(SmsCbCmasInfo.CMAS_CERTAINTY_LIKELY, cmasInfo.getCertainty()); 668 } 669 670 // VZW requirement is to discard message with unsupported charset. Verify that we return null 671 // for this unsupported character set. 672 @Ignore 673 @Test testCmasUnsupportedCharSet()674 public void testCmasUnsupportedCharSet() throws Exception { 675 SmsMessage msg = createCmasSmsMessage(CdmaSmsCbProgramData.CATEGORY_CMAS_EXTREME_THREAT, 676 12345, BearerData.PRIORITY_EMERGENCY, BearerData.LANGUAGE_ENGLISH, 677 0x1F, EXTREME_ALERT, -1, -1, -1, -1, -1); 678 679 SmsCbMessage cbMessage = 680 DefaultCellBroadcastService.parseCdmaBroadcastSms(mMockedContext, 681 0, "", msg.getEnvelopeBearerData(), msg.getEnvelopeServiceCategory()); 682 //SmsCbMessage cbMessage = msg.parseCdmaBroadcastSms("", 0); 683 assertNull("expected null for unsupported charset", cbMessage); 684 } 685 686 // VZW requirement is to discard message with unsupported charset. Verify that we return null 687 // for this unsupported character set. 688 @Test testCmasUnsupportedCharSet2()689 public void testCmasUnsupportedCharSet2() throws Exception { 690 SmsMessage msg = createCmasSmsMessage(CdmaSmsCbProgramData.CATEGORY_CMAS_EXTREME_THREAT, 691 67890, BearerData.PRIORITY_EMERGENCY, BearerData.LANGUAGE_ENGLISH, 692 ENCODING_KOREAN, EXTREME_ALERT, -1, -1, -1, -1, -1); 693 694 SmsCbMessage cbMessage = 695 DefaultCellBroadcastService.parseCdmaBroadcastSms(mMockedContext, 696 0, "", msg.getEnvelopeBearerData(), msg.getEnvelopeServiceCategory()); 697 //SmsCbMessage cbMessage = msg.parseCdmaBroadcastSms("", 0); 698 assertNull("expected null for unsupported charset", cbMessage); 699 } 700 701 // VZW requirement is to discard message without record type 0. The framework will decode it 702 // and the app will discard it. 703 @Test testCmasNoRecordType0()704 public void testCmasNoRecordType0() throws Exception { 705 SmsMessage msg = createCmasSmsMessage( 706 CdmaSmsCbProgramData.CATEGORY_CMAS_PRESIDENTIAL_LEVEL_ALERT, 1234, 707 BearerData.PRIORITY_EMERGENCY, BearerData.LANGUAGE_ENGLISH, 708 ENCODING_7BIT_ASCII, null, -1, -1, -1, -1, -1); 709 710 SmsCbMessage cbMessage = 711 DefaultCellBroadcastService.parseCdmaBroadcastSms(mMockedContext, 712 0, "", msg.getEnvelopeBearerData(), msg.getEnvelopeServiceCategory()); 713 //SmsCbMessage cbMessage = msg.parseCdmaBroadcastSms("", 0); 714 verifyCbValues(cbMessage); 715 assertEquals(CdmaSmsCbProgramData.CATEGORY_CMAS_PRESIDENTIAL_LEVEL_ALERT, 716 cbMessage.getServiceCategory()); 717 assertEquals(1234, cbMessage.getSerialNumber()); 718 assertEquals(SmsCbMessage.MESSAGE_PRIORITY_EMERGENCY, cbMessage.getMessagePriority()); 719 assertEquals("en", cbMessage.getLanguageCode()); 720 assertEquals(null, cbMessage.getMessageBody()); 721 assertEquals(true, cbMessage.isEmergencyMessage()); 722 assertEquals(true, cbMessage.isCmasMessage()); 723 SmsCbCmasInfo cmasInfo = cbMessage.getCmasWarningInfo(); 724 assertEquals(SmsCbCmasInfo.CMAS_CLASS_PRESIDENTIAL_LEVEL_ALERT, cmasInfo.getMessageClass()); 725 assertEquals(SmsCbCmasInfo.CMAS_CATEGORY_UNKNOWN, cmasInfo.getCategory()); 726 assertEquals(SmsCbCmasInfo.CMAS_RESPONSE_TYPE_UNKNOWN, cmasInfo.getResponseType()); 727 assertEquals(SmsCbCmasInfo.CMAS_SEVERITY_UNKNOWN, cmasInfo.getSeverity()); 728 assertEquals(SmsCbCmasInfo.CMAS_URGENCY_UNKNOWN, cmasInfo.getUrgency()); 729 assertEquals(SmsCbCmasInfo.CMAS_CERTAINTY_UNKNOWN, cmasInfo.getCertainty()); 730 } 731 732 // Make sure we don't throw an exception if we feed completely random data to BearerStream. 733 @Test testRandomBearerStreamData()734 public void testRandomBearerStreamData() { 735 Random r = new Random(54321); 736 for (int run = 0; run < 1000; run++) { 737 int len = r.nextInt(140); 738 byte[] data = new byte[len]; 739 for (int i = 0; i < len; i++) { 740 data[i] = (byte) r.nextInt(256); 741 } 742 // Log.d(TAG, "trying random bearer data run " + run + " length " + len); 743 try { 744 int category = 0x0ff0 + r.nextInt(32); // half CMAS, half non-CMAS 745 CdmaSmsMessage cdmaSmsMessage = createBroadcastParcel(category); 746 SmsMessage msg = createMessageFromParcel(cdmaSmsMessage, data); 747 SmsCbMessage cbMessage = 748 DefaultCellBroadcastService.parseCdmaBroadcastSms( 749 mMockedContext, 750 0, "", msg.getEnvelopeBearerData(), 751 msg.getEnvelopeServiceCategory()); 752 //SmsCbMessage cbMessage = msg.parseCdmaBroadcastSms("", 0); 753 // with random input, cbMessage will almost always be null (log when it isn't) 754 if (cbMessage != null) { 755 Log.d(TAG, "success: " + cbMessage); 756 } 757 } catch (Exception e) { 758 Log.d(TAG, "exception thrown", e); 759 fail("Exception in decoder at run " + run + " length " + len + ": " + e); 760 } 761 } 762 } 763 764 // Make sure we don't throw an exception if we put random data in the UserData subparam. 765 @Test testRandomUserData()766 public void testRandomUserData() { 767 Random r = new Random(94040); 768 for (int run = 0; run < 1000; run++) { 769 int category = 0x0ff0 + r.nextInt(32); // half CMAS, half non-CMAS 770 CdmaSmsMessage cdmaSmsMessage = createBroadcastParcel(category); 771 int len = r.nextInt(140); 772 // Log.d(TAG, "trying random user data run " + run + " length " + len); 773 774 try { 775 BitwiseOutputStream bos = createBearerDataStream(r.nextInt(65536), r.nextInt(4), 776 r.nextInt(256)); 777 778 bos.write(8, SUBPARAM_USER_DATA); 779 bos.write(8, len); 780 781 for (int i = 0; i < len; i++) { 782 bos.write(8, r.nextInt(256)); 783 } 784 785 SmsMessage msg = createMessageFromParcel(cdmaSmsMessage, bos.toByteArray()); 786 SmsCbMessage cbMessage = 787 DefaultCellBroadcastService.parseCdmaBroadcastSms(mMockedContext, 0, "", 788 msg.getEnvelopeBearerData(), msg.getEnvelopeServiceCategory()); 789 //SmsCbMessage cbMessage = msg.parseCdmaBroadcastSms("", 0); 790 } catch (Exception e) { 791 Log.d(TAG, "exception thrown", e); 792 fail("Exception in decoder at run " + run + " length " + len + ": " + e); 793 } 794 } 795 } 796 797 /** 798 * Initialize a Parcel for incoming Service Category Program Data teleservice. The caller will 799 * write the bearer data and then convert it to an SmsMessage. 800 * 801 * @return the initialized Parcel 802 */ createServiceCategoryProgramDataParcel()803 private static CdmaSmsMessage createServiceCategoryProgramDataParcel() { 804 CdmaSmsMessage msg = new CdmaSmsMessage(); 805 806 msg.teleserviceId = TELESERVICE_SCPT; 807 msg.isServicePresent = false; 808 msg.serviceCategory = 0; 809 810 // dummy address (RIL may generate a different dummy address for broadcasts) 811 msg.address.digitMode = DIGIT_MODE_4BIT_DTMF; 812 msg.address.numberMode = NUMBER_MODE_NOT_DATA_NETWORK; 813 msg.address.numberType = TON_UNKNOWN; 814 msg.address.numberPlan = NUMBERING_PLAN_ISDN_TELEPHONY; 815 msg.subAddress.subaddressType = 0; 816 msg.subAddress.odd = false; 817 return msg; 818 } 819 820 private static final String CAT_EXTREME_THREAT = "Extreme Threat to Life and Property"; 821 private static final String CAT_SEVERE_THREAT = "Severe Threat to Life and Property"; 822 private static final String CAT_AMBER_ALERTS = "AMBER Alerts"; 823 824 @Test testServiceCategoryProgramDataAddCategory()825 public void testServiceCategoryProgramDataAddCategory() throws Exception { 826 CdmaSmsMessage cdmaSmsMessage = createServiceCategoryProgramDataParcel(); 827 BitwiseOutputStream bos = createBearerDataStream(123, -1, -1); 828 829 int categoryNameLength = CAT_EXTREME_THREAT.length(); 830 int subparamLengthBits = (53 + (categoryNameLength * 7)); 831 int subparamLengthBytes = (subparamLengthBits + 7) / 8; 832 int subparamPadBits = (subparamLengthBytes * 8) - subparamLengthBits; 833 834 bos.write(8, SUBPARAM_SERVICE_CATEGORY_PROGRAM_DATA); 835 bos.write(8, subparamLengthBytes); 836 bos.write(5, ENCODING_7BIT_ASCII); 837 838 bos.write(4, CdmaSmsCbProgramData.OPERATION_ADD_CATEGORY); 839 bos.write(8, (CdmaSmsCbProgramData.CATEGORY_CMAS_EXTREME_THREAT >>> 8)); 840 bos.write(8, (CdmaSmsCbProgramData.CATEGORY_CMAS_EXTREME_THREAT & 0xff)); 841 bos.write(8, BearerData.LANGUAGE_ENGLISH); 842 bos.write(8, 100); // max messages 843 bos.write(4, CdmaSmsCbProgramData.ALERT_OPTION_DEFAULT_ALERT); 844 845 bos.write(8, categoryNameLength); 846 for (int i = 0; i < categoryNameLength; i++) { 847 bos.write(7, CAT_EXTREME_THREAT.charAt(i)); 848 } 849 bos.write(subparamPadBits, 0); 850 851 SmsMessage msg = createMessageFromParcel(cdmaSmsMessage, bos.toByteArray()); 852 assertNotNull(msg); 853 msg.parseSms(); 854 List<CdmaSmsCbProgramData> programDataList = msg.getSmsCbProgramData(); 855 assertNotNull(programDataList); 856 assertEquals(1, programDataList.size()); 857 CdmaSmsCbProgramData programData = programDataList.get(0); 858 assertEquals(CdmaSmsCbProgramData.OPERATION_ADD_CATEGORY, programData.getOperation()); 859 assertEquals(CdmaSmsCbProgramData.CATEGORY_CMAS_EXTREME_THREAT, 860 programData.getCategory()); 861 assertEquals(CAT_EXTREME_THREAT, programData.getCategoryName()); 862 assertEquals(BearerData.LANGUAGE_ENGLISH, programData.getLanguage()); 863 assertEquals(100, programData.getMaxMessages()); 864 assertEquals(CdmaSmsCbProgramData.ALERT_OPTION_DEFAULT_ALERT, programData.getAlertOption()); 865 } 866 867 @Test testServiceCategoryProgramDataDeleteTwoCategories()868 public void testServiceCategoryProgramDataDeleteTwoCategories() throws Exception { 869 CdmaSmsMessage cdmaSmsMessage = createServiceCategoryProgramDataParcel(); 870 BitwiseOutputStream bos = createBearerDataStream(456, -1, -1); 871 872 int category1NameLength = CAT_SEVERE_THREAT.length(); 873 int category2NameLength = CAT_AMBER_ALERTS.length(); 874 875 int subparamLengthBits = (101 + (category1NameLength * 7) + (category2NameLength * 7)); 876 int subparamLengthBytes = (subparamLengthBits + 7) / 8; 877 int subparamPadBits = (subparamLengthBytes * 8) - subparamLengthBits; 878 879 bos.write(8, SUBPARAM_SERVICE_CATEGORY_PROGRAM_DATA); 880 bos.write(8, subparamLengthBytes); 881 bos.write(5, ENCODING_7BIT_ASCII); 882 883 bos.write(4, CdmaSmsCbProgramData.OPERATION_DELETE_CATEGORY); 884 bos.write(8, (CdmaSmsCbProgramData.CATEGORY_CMAS_SEVERE_THREAT >>> 8)); 885 bos.write(8, (CdmaSmsCbProgramData.CATEGORY_CMAS_SEVERE_THREAT & 0xff)); 886 bos.write(8, BearerData.LANGUAGE_ENGLISH); 887 bos.write(8, 0); // max messages 888 bos.write(4, CdmaSmsCbProgramData.ALERT_OPTION_NO_ALERT); 889 890 bos.write(8, category1NameLength); 891 for (int i = 0; i < category1NameLength; i++) { 892 bos.write(7, CAT_SEVERE_THREAT.charAt(i)); 893 } 894 895 bos.write(4, CdmaSmsCbProgramData.OPERATION_DELETE_CATEGORY); 896 bos.write(8, (CdmaSmsCbProgramData.CATEGORY_CMAS_CHILD_ABDUCTION_EMERGENCY >>> 8)); 897 bos.write(8, (CdmaSmsCbProgramData.CATEGORY_CMAS_CHILD_ABDUCTION_EMERGENCY & 0xff)); 898 bos.write(8, BearerData.LANGUAGE_ENGLISH); 899 bos.write(8, 0); // max messages 900 bos.write(4, CdmaSmsCbProgramData.ALERT_OPTION_NO_ALERT); 901 902 bos.write(8, category2NameLength); 903 for (int i = 0; i < category2NameLength; i++) { 904 bos.write(7, CAT_AMBER_ALERTS.charAt(i)); 905 } 906 907 bos.write(subparamPadBits, 0); 908 909 SmsMessage msg = createMessageFromParcel(cdmaSmsMessage, bos.toByteArray()); 910 assertNotNull(msg); 911 msg.parseSms(); 912 List<CdmaSmsCbProgramData> programDataList = msg.getSmsCbProgramData(); 913 assertNotNull(programDataList); 914 assertEquals(2, programDataList.size()); 915 916 CdmaSmsCbProgramData programData = programDataList.get(0); 917 assertEquals(CdmaSmsCbProgramData.OPERATION_DELETE_CATEGORY, programData.getOperation()); 918 assertEquals(CdmaSmsCbProgramData.CATEGORY_CMAS_SEVERE_THREAT, 919 programData.getCategory()); 920 assertEquals(CAT_SEVERE_THREAT, programData.getCategoryName()); 921 assertEquals(BearerData.LANGUAGE_ENGLISH, programData.getLanguage()); 922 assertEquals(0, programData.getMaxMessages()); 923 assertEquals(CdmaSmsCbProgramData.ALERT_OPTION_NO_ALERT, programData.getAlertOption()); 924 925 programData = programDataList.get(1); 926 assertEquals(CdmaSmsCbProgramData.OPERATION_DELETE_CATEGORY, programData.getOperation()); 927 assertEquals(CdmaSmsCbProgramData.CATEGORY_CMAS_CHILD_ABDUCTION_EMERGENCY, 928 programData.getCategory()); 929 assertEquals(CAT_AMBER_ALERTS, programData.getCategoryName()); 930 assertEquals(BearerData.LANGUAGE_ENGLISH, programData.getLanguage()); 931 assertEquals(0, programData.getMaxMessages()); 932 assertEquals(CdmaSmsCbProgramData.ALERT_OPTION_NO_ALERT, programData.getAlertOption()); 933 } 934 935 private static final byte[] CMAS_TEST_BEARER_DATA = { 936 0x00, 0x03, 0x1C, 0x78, 0x00, 0x01, 0x59, 0x02, (byte) 0xB8, 0x00, 0x02, 0x10, 937 (byte) 0xAA, 938 0x68, (byte) 0xD3, (byte) 0xCD, 0x06, (byte) 0x9E, 0x68, 0x30, (byte) 0xA0, (byte) 0xE9, 939 (byte) 0x97, (byte) 0x9F, 0x44, 0x1B, (byte) 0xF3, 0x20, (byte) 0xE9, (byte) 0xA3, 940 0x2A, 0x08, 0x7B, (byte) 0xF6, (byte) 0xED, (byte) 0xCB, (byte) 0xCB, 0x1E, (byte) 0x9C, 941 0x3B, 0x10, 0x4D, (byte) 0xDF, (byte) 0x8B, 0x4E, 942 (byte) 0xCC, (byte) 0xA8, 0x20, (byte) 0xEC, (byte) 0xCB, (byte) 0xCB, (byte) 0xA2, 943 0x0A, 944 0x7E, 0x79, (byte) 0xF4, (byte) 0xCB, (byte) 0xB5, 0x72, 0x0A, (byte) 0x9A, 0x34, 945 (byte) 0xF3, 0x41, (byte) 0xA7, (byte) 0x9A, 0x0D, (byte) 0xFB, (byte) 0xB6, 0x79, 0x41, 946 (byte) 0x85, 0x07, 0x4C, (byte) 0xBC, (byte) 0xFA, 0x2E, 0x00, 0x08, 0x20, 0x58, 0x38, 947 (byte) 0x88, (byte) 0x80, 0x10, 0x54, 0x06, 0x38, 0x20, 0x60, 948 0x30, (byte) 0xA8, (byte) 0x81, (byte) 0x90, 0x20, 0x08 949 }; 950 951 // Test case for CMAS test message received on the Sprint network. 952 @Test testDecodeRawBearerData()953 public void testDecodeRawBearerData() { 954 CdmaSmsMessage cdmaSmsMessage = 955 createBroadcastParcel(CdmaSmsCbProgramData.CATEGORY_CMAS_TEST_MESSAGE); 956 SmsMessage msg = createMessageFromParcel(cdmaSmsMessage, CMAS_TEST_BEARER_DATA); 957 958 SmsCbMessage cbMessage = 959 DefaultCellBroadcastService.parseCdmaBroadcastSms(mMockedContext, 960 0, "", msg.getEnvelopeBearerData(), msg.getEnvelopeServiceCategory()); 961 //SmsCbMessage cbMessage = msg.parseCdmaBroadcastSms("", 0); 962 assertNotNull("expected non-null for bearer data", cbMessage); 963 assertEquals("geoScope", cbMessage.getGeographicalScope(), 1); 964 assertEquals("serialNumber", cbMessage.getSerialNumber(), 51072); 965 assertEquals("serviceCategory", cbMessage.getServiceCategory(), 966 CdmaSmsCbProgramData.CATEGORY_CMAS_TEST_MESSAGE); 967 assertEquals("payload", cbMessage.getMessageBody(), 968 "This is a test of the Commercial Mobile Alert System. This is only a test."); 969 970 SmsCbCmasInfo cmasInfo = cbMessage.getCmasWarningInfo(); 971 assertNotNull("expected non-null for CMAS info", cmasInfo); 972 assertEquals("category", cmasInfo.getCategory(), SmsCbCmasInfo.CMAS_CATEGORY_OTHER); 973 assertEquals("responseType", cmasInfo.getResponseType(), 974 SmsCbCmasInfo.CMAS_RESPONSE_TYPE_NONE); 975 assertEquals("severity", cmasInfo.getSeverity(), SmsCbCmasInfo.CMAS_SEVERITY_SEVERE); 976 assertEquals("urgency", cmasInfo.getUrgency(), SmsCbCmasInfo.CMAS_URGENCY_EXPECTED); 977 assertEquals("certainty", cmasInfo.getCertainty(), SmsCbCmasInfo.CMAS_CERTAINTY_LIKELY); 978 } 979 } 980