1/* 2 * Copyright (C) 2010 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 17package com.android.internal.telephony; 18 19import android.telephony.SmsMessage; 20import android.telephony.TelephonyManager; 21import android.test.AndroidTestCase; 22import android.test.suitebuilder.annotation.LargeTest; 23import android.test.suitebuilder.annotation.MediumTest; 24import android.test.suitebuilder.annotation.SmallTest; 25import android.util.Log; 26 27import java.util.Random; 28 29import static android.telephony.SmsMessage.MAX_USER_DATA_BYTES; 30import static android.telephony.SmsMessage.MAX_USER_DATA_BYTES_WITH_HEADER; 31import static android.telephony.SmsMessage.MAX_USER_DATA_SEPTETS; 32import static android.telephony.SmsMessage.MAX_USER_DATA_SEPTETS_WITH_HEADER; 33 34/** 35 * Test cases to verify selection of the optimal 7 bit encoding tables 36 * (for all combinations of enabled national language tables) for messages 37 * containing Turkish, Spanish, Portuguese, Greek, and other symbols 38 * present in the GSM default and national language tables defined in 39 * 3GPP TS 23.038. Also verifies correct SMS encoding for CDMA, which only 40 * supports the GSM 7 bit default alphabet, ASCII 8 bit, and UCS-2. 41 * Tests both encoding variations: unsupported characters mapped to space, 42 * and unsupported characters force entire message to UCS-2. 43 */ 44public class SmsMessageBodyTest extends AndroidTestCase { 45 private static final String TAG = "SmsMessageBodyTest"; 46 47 // ASCII chars in the GSM 7 bit default alphabet 48 private static final String sAsciiChars = "@$_ !\"#%&'()*+,-./0123456789" + 49 ":;<=>?ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz\n\r"; 50 51 // Unicode chars in the GSM 7 bit default alphabet and both locking shift tables 52 private static final String sGsmDefaultChars = "\u00a3\u00a5\u00e9\u00c7\u0394\u00c9" + 53 "\u00dc\u00a7\u00fc\u00e0"; 54 55 // Unicode chars in the GSM 7 bit default table and Turkish locking shift tables 56 private static final String sGsmDefaultAndTurkishTables = "\u00f9\u00f2\u00c5\u00e5\u00df" + 57 "\u00a4\u00c4\u00d6\u00d1\u00e4\u00f6\u00f1"; 58 59 // Unicode chars in the GSM 7 bit default table but not the locking shift tables 60 private static final String sGsmDefaultTableOnly = "\u00e8\u00ec\u00d8\u00f8\u00c6\u00e6" + 61 "\u00a1\u00bf"; 62 63 // ASCII chars in the GSM default extension table 64 private static final String sGsmExtendedAsciiChars = "{}[]\f"; 65 66 // chars in GSM default extension table and Portuguese locking shift table 67 private static final String sGsmExtendedPortugueseLocking = "^\\|~"; 68 69 // Euro currency symbol 70 private static final String sGsmExtendedEuroSymbol = "\u20ac"; 71 72 // CJK ideographs, Hiragana, Katakana, full width letters, Cyrillic, etc. 73 private static final String sUnicodeChars = "\u4e00\u4e01\u4e02\u4e03" + 74 "\u4e04\u4e05\u4e06\u4e07\u4e08\u4e09\u4e0a\u4e0b\u4e0c\u4e0d" + 75 "\u4e0e\u4e0f\u3041\u3042\u3043\u3044\u3045\u3046\u3047\u3048" + 76 "\u30a1\u30a2\u30a3\u30a4\u30a5\u30a6\u30a7\u30a8" + 77 "\uff10\uff11\uff12\uff13\uff14\uff15\uff16\uff17\uff18" + 78 "\uff70\uff71\uff72\uff73\uff74\uff75\uff76\uff77\uff78" + 79 "\u0400\u0401\u0402\u0403\u0404\u0405\u0406\u0407\u0408" + 80 "\u00a2\u00a9\u00ae\u2122"; 81 82 // chars in Turkish single shift and locking shift tables 83 private static final String sTurkishChars = "\u0131\u011e\u011f\u015e\u015f\u0130"; 84 85 // chars in Spanish single shift table and Portuguese single and locking shift tables 86 private static final String sPortugueseAndSpanishChars = "\u00c1\u00e1\u00cd\u00ed" 87 + "\u00d3\u00f3\u00da\u00fa"; 88 89 // chars in all national language tables but not in the standard GSM alphabets 90 private static final String sNationalLanguageTablesOnly = "\u00e7"; 91 92 // chars in Portuguese single shift and locking shift tables 93 private static final String sPortugueseChars = "\u00ea\u00d4\u00f4\u00c0\u00c2\u00e2" 94 + "\u00ca\u00c3\u00d5\u00e3\u00f5"; 95 96 // chars in Portuguese locking shift table only 97 private static final String sPortugueseLockingShiftChars = "\u00aa\u221e\u00ba`"; 98 99 // Greek letters in GSM alphabet missing from Portuguese locking and single shift tables 100 private static final String sGreekLettersNotInPortugueseTables = "\u039b\u039e"; 101 102 // Greek letters in GSM alphabet and Portuguese single shift (but not locking shift) table 103 private static final String sGreekLettersInPortugueseShiftTable = 104 "\u03a6\u0393\u03a9\u03a0\u03a8\u03a3\u0398"; 105 106 // List of classes of characters in SMS tables 107 private static final String[] sCharacterClasses = { 108 sGsmExtendedAsciiChars, 109 sGsmExtendedPortugueseLocking, 110 sGsmDefaultChars, 111 sGsmDefaultAndTurkishTables, 112 sGsmDefaultTableOnly, 113 sGsmExtendedEuroSymbol, 114 sUnicodeChars, 115 sTurkishChars, 116 sPortugueseChars, 117 sPortugueseLockingShiftChars, 118 sPortugueseAndSpanishChars, 119 sGreekLettersNotInPortugueseTables, 120 sGreekLettersInPortugueseShiftTable, 121 sNationalLanguageTablesOnly, 122 sAsciiChars 123 }; 124 125 private static final int sNumCharacterClasses = sCharacterClasses.length; 126 127 // For each character class, whether it is present in a particular char table. 128 // First three entries are locking shift tables, followed by four single shift tables 129 private static final boolean[][] sCharClassPresenceInTables = { 130 // ASCII chars in all GSM extension tables 131 {false, false, false, true, true, true, true}, 132 // ASCII chars in all GSM extension tables and Portuguese locking shift table 133 {false, false, true, true, true, true, true}, 134 // non-ASCII chars in GSM default alphabet and all locking tables 135 {true, true, true, false, false, false, false}, 136 // non-ASCII chars in GSM default alphabet and Turkish locking shift table 137 {true, true, false, false, false, false, false}, 138 // non-ASCII chars in GSM default alphabet table only 139 {true, false, false, false, false, false, false}, 140 // Euro symbol is present in several tables 141 {false, true, true, true, true, true, true}, 142 // Unicode characters not present in any 7 bit tables 143 {false, false, false, false, false, false, false}, 144 // Characters specific to Turkish language 145 {false, true, false, false, true, false, false}, 146 // Characters in Portuguese single shift and locking shift tables 147 {false, false, true, false, false, false, true}, 148 // Characters in Portuguese locking shift table only 149 {false, false, true, false, false, false, false}, 150 // Chars in Spanish single shift and Portuguese single and locking shift tables 151 {false, false, true, false, false, true, true}, 152 // Greek letters in GSM default alphabet missing from Portuguese tables 153 {true, true, false, false, false, false, false}, 154 // Greek letters in GSM alphabet and Portuguese single shift table 155 {true, true, false, false, false, false, true}, 156 // Chars in all national language tables but not the standard GSM tables 157 {false, true, true, false, true, true, true}, 158 // ASCII chars in GSM default alphabet 159 {true, true, true, false, false, false, false} 160 }; 161 162 private static final int sTestLengthCount = 12; 163 164 private static final int[] sSeptetTestLengths = 165 { 0, 1, 2, 80, 159, 160, 161, 240, 305, 306, 307, 320}; 166 167 private static final int[] sUnicodeTestLengths = 168 { 0, 1, 2, 35, 69, 70, 71, 100, 133, 134, 135, 160}; 169 170 private static final int[] sTestMsgCounts = 171 { 1, 1, 1, 1, 1, 1, 2, 2, 2, 2, 3, 3}; 172 173 private static final int[] sSeptetUnitsRemaining = 174 {160, 159, 158, 80, 1, 0, 145, 66, 1, 0, 152, 139}; 175 176 private static final int[] sUnicodeUnitsRemaining = 177 { 70, 69, 68, 35, 1, 0, 63, 34, 1, 0, 66, 41}; 178 179 // Combinations of enabled GSM national language single shift tables 180 private static final int[][] sEnabledSingleShiftTables = { 181 {}, // GSM default alphabet only 182 {1}, // Turkish (single shift only) 183 {1}, // Turkish (single and locking shift) 184 {2}, // Spanish 185 {3}, // Portuguese (single shift only) 186 {3}, // Portuguese (single and locking shift) 187 {1, 2}, // Turkish + Spanish (single shift only) 188 {1, 2}, // Turkish + Spanish (single and locking shift) 189 {1, 3}, // Turkish + Portuguese (single shift only) 190 {1, 3}, // Turkish + Portuguese (single and locking shift) 191 {2, 3}, // Spanish + Portuguese (single shift only) 192 {2, 3}, // Spanish + Portuguese (single and locking shift) 193 {1, 2, 3}, // Turkish, Spanish, Portuguese (single shift only) 194 {1, 2, 3}, // Turkish, Spanish, Portuguese (single and locking shift) 195 {1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13} // all language tables 196 }; 197 198 // Combinations of enabled GSM national language locking shift tables 199 private static final int[][] sEnabledLockingShiftTables = { 200 {}, // GSM default alphabet only 201 {}, // Turkish (single shift only) 202 {1}, // Turkish (single and locking shift) 203 {}, // Spanish (no locking shift table) 204 {}, // Portuguese (single shift only) 205 {3}, // Portuguese (single and locking shift) 206 {}, // Turkish + Spanish (single shift only) 207 {1}, // Turkish + Spanish (single and locking shift) 208 {}, // Turkish + Portuguese (single shift only) 209 {1, 3}, // Turkish + Portuguese (single and locking shift) 210 {}, // Spanish + Portuguese (single shift only) 211 {3}, // Spanish + Portuguese (single and locking shift) 212 {}, // Turkish, Spanish, Portuguese (single shift only) 213 {1, 3}, // Turkish, Spanish, Portuguese (single and locking shift) 214 {1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13} // all language tables 215 }; 216 217 // LanguagePair counter indexes to check for each entry above 218 private static final int[][] sLanguagePairIndexesByEnabledIndex = { 219 {0}, // default tables only 220 {0, 1}, // Turkish (single shift only) 221 {0, 1, 4, 5}, // Turkish (single and locking shift) 222 {0, 2}, // Spanish 223 {0, 3}, // Portuguese (single shift only) 224 {0, 3, 8, 11}, // Portuguese (single and locking shift) 225 {0, 1, 2}, // Turkish + Spanish (single shift only) 226 {0, 1, 2, 4, 5, 6}, // Turkish + Spanish (single and locking shift) 227 {0, 1, 3}, // Turkish + Portuguese (single shift only) 228 {0, 1, 3, 4, 5, 7, 8, 9, 11}, // Turkish + Portuguese (single and locking shift) 229 {0, 2, 3}, // Spanish + Portuguese (single shift only) 230 {0, 2, 3, 8, 10, 11}, // Spanish + Portuguese (single and locking shift) 231 {0, 1, 2, 3}, // all languages (single shift only) 232 {0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11}, // all languages (single and locking shift) 233 {0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11} // all languages (no Indic chars in test) 234 }; 235 236 /** 237 * User data header requires one octet for length. Count as one septet, because 238 * all combinations of header elements below will have at least one free bit 239 * when padding to the nearest septet boundary. 240 */ 241 private static final int UDH_SEPTET_COST_LENGTH = 1; 242 243 /** 244 * Using a non-default language locking shift table OR single shift table 245 * requires a user data header of 3 octets, or 4 septets, plus UDH length. 246 */ 247 private static final int UDH_SEPTET_COST_ONE_SHIFT_TABLE = 4; 248 249 /** 250 * Using a non-default language locking shift table AND single shift table 251 * requires a user data header of 6 octets, or 7 septets, plus UDH length. 252 */ 253 private static final int UDH_SEPTET_COST_TWO_SHIFT_TABLES = 7; 254 255 /** 256 * Multi-part messages require a user data header of 5 octets, or 6 septets, 257 * plus UDH length. 258 */ 259 private static final int UDH_SEPTET_COST_CONCATENATED_MESSAGE = 6; 260 261 @SmallTest 262 public void testCalcLengthAscii() throws Exception { 263 StringBuilder sb = new StringBuilder(320); 264 int[] values = {0, 0, 0, SmsMessage.ENCODING_7BIT, 0, 0}; 265 int startPos = 0; 266 int asciiCharsLen = sAsciiChars.length(); 267 268 for (int i = 0; i < sTestLengthCount; i++) { 269 int len = sSeptetTestLengths[i]; 270 assertTrue(sb.length() <= len); 271 272 while (sb.length() < len) { 273 int addCount = len - sb.length(); 274 int endPos = (asciiCharsLen - startPos > addCount) ? 275 (startPos + addCount) : asciiCharsLen; 276 sb.append(sAsciiChars, startPos, endPos); 277 startPos = (endPos == asciiCharsLen) ? 0 : endPos; 278 } 279 assertEquals(len, sb.length()); 280 281 String testStr = sb.toString(); 282 values[0] = sTestMsgCounts[i]; 283 values[1] = len; 284 values[2] = sSeptetUnitsRemaining[i]; 285 286 callGsmLengthMethods(testStr, false, values); 287 callGsmLengthMethods(testStr, true, values); 288 callCdmaLengthMethods(testStr, false, values); 289 callCdmaLengthMethods(testStr, true, values); 290 } 291 } 292 293 @SmallTest 294 public void testCalcLengthUnicode() throws Exception { 295 StringBuilder sb = new StringBuilder(160); 296 int[] values = {0, 0, 0, SmsMessage.ENCODING_16BIT, 0, 0}; 297 int[] values7bit = {1, 0, 0, SmsMessage.ENCODING_7BIT, 0, 0}; 298 int startPos = 0; 299 int unicodeCharsLen = sUnicodeChars.length(); 300 301 // start with length 1: empty string uses ENCODING_7BIT 302 for (int i = 1; i < sTestLengthCount; i++) { 303 int len = sUnicodeTestLengths[i]; 304 assertTrue(sb.length() <= len); 305 306 while (sb.length() < len) { 307 int addCount = len - sb.length(); 308 int endPos = (unicodeCharsLen - startPos > addCount) ? 309 (startPos + addCount) : unicodeCharsLen; 310 sb.append(sUnicodeChars, startPos, endPos); 311 startPos = (endPos == unicodeCharsLen) ? 0 : endPos; 312 } 313 assertEquals(len, sb.length()); 314 315 String testStr = sb.toString(); 316 values[0] = sTestMsgCounts[i]; 317 values[1] = len; 318 values[2] = sUnicodeUnitsRemaining[i]; 319 values7bit[1] = len; 320 values7bit[2] = MAX_USER_DATA_SEPTETS - len; 321 322 callGsmLengthMethods(testStr, false, values); 323 callCdmaLengthMethods(testStr, false, values); 324 callGsmLengthMethods(testStr, true, values7bit); 325 callCdmaLengthMethods(testStr, true, values7bit); 326 } 327 } 328 329 private static class LanguagePair { 330 // index is 2 for Portuguese locking shift because there is no Spanish locking shift table 331 private final int langTableIndex; 332 private final int langShiftTableIndex; 333 int length; 334 int missingChars7bit; 335 336 LanguagePair(int langTable, int langShiftTable) { 337 langTableIndex = langTable; 338 langShiftTableIndex = langShiftTable; 339 } 340 341 void clear() { 342 length = 0; 343 missingChars7bit = 0; 344 } 345 346 void addChar(boolean[] charClassTableRow) { 347 if (charClassTableRow[langTableIndex]) { 348 length++; 349 } else if (charClassTableRow[3 + langShiftTableIndex]) { 350 length += 2; 351 } else { 352 length++; // use ' ' for unmapped char in 7 bit only mode 353 missingChars7bit++; 354 } 355 } 356 } 357 358 private static class CounterHelper { 359 LanguagePair[] mCounters; 360 int[] mStatsCounters; 361 int mUnicodeCounter; 362 363 CounterHelper() { 364 mCounters = new LanguagePair[12]; 365 mStatsCounters = new int[12]; 366 for (int i = 0; i < 12; i++) { 367 mCounters[i] = new LanguagePair(i/4, i%4); 368 } 369 } 370 371 void clear() { 372 // Note: don't clear stats counters 373 for (int i = 0; i < 12; i++) { 374 mCounters[i].clear(); 375 } 376 } 377 378 void addChar(int charClass) { 379 boolean[] charClassTableRow = sCharClassPresenceInTables[charClass]; 380 for (int i = 0; i < 12; i++) { 381 mCounters[i].addChar(charClassTableRow); 382 } 383 } 384 385 void fillData(int enabledLangsIndex, boolean use7bitOnly, int[] values, int length) { 386 int[] languagePairs = sLanguagePairIndexesByEnabledIndex[enabledLangsIndex]; 387 int minNumSeptets = Integer.MAX_VALUE; 388 int minNumSeptetsWithHeader = Integer.MAX_VALUE; 389 int minNumMissingChars = Integer.MAX_VALUE; 390 int langIndex = -1; 391 int langShiftIndex = -1; 392 for (int i : languagePairs) { 393 LanguagePair pair = mCounters[i]; 394 int udhLength = 0; 395 if (i != 0) { 396 udhLength = UDH_SEPTET_COST_LENGTH; 397 if (i < 4 || i % 4 == 0) { 398 udhLength += UDH_SEPTET_COST_ONE_SHIFT_TABLE; 399 } else { 400 udhLength += UDH_SEPTET_COST_TWO_SHIFT_TABLES; 401 } 402 } 403 int numSeptetsWithHeader; 404 if (pair.length > (MAX_USER_DATA_SEPTETS - udhLength)) { 405 if (udhLength == 0) { 406 udhLength = UDH_SEPTET_COST_LENGTH; 407 } 408 udhLength += UDH_SEPTET_COST_CONCATENATED_MESSAGE; 409 int septetsPerPart = MAX_USER_DATA_SEPTETS - udhLength; 410 int msgCount = (pair.length + septetsPerPart - 1) / septetsPerPart; 411 numSeptetsWithHeader = udhLength * msgCount + pair.length; 412 } else { 413 numSeptetsWithHeader = udhLength + pair.length; 414 } 415 416 if (use7bitOnly) { 417 if (pair.missingChars7bit < minNumMissingChars || (pair.missingChars7bit == 418 minNumMissingChars && numSeptetsWithHeader < minNumSeptetsWithHeader)) { 419 minNumSeptets = pair.length; 420 minNumSeptetsWithHeader = numSeptetsWithHeader; 421 minNumMissingChars = pair.missingChars7bit; 422 langIndex = pair.langTableIndex; 423 langShiftIndex = pair.langShiftTableIndex; 424 } 425 } else { 426 if (pair.missingChars7bit == 0 && numSeptetsWithHeader < minNumSeptetsWithHeader) { 427 minNumSeptets = pair.length; 428 minNumSeptetsWithHeader = numSeptetsWithHeader; 429 langIndex = pair.langTableIndex; 430 langShiftIndex = pair.langShiftTableIndex; 431 } 432 } 433 } 434 if (langIndex == -1) { 435 // nothing matches, use values for Unicode 436 int byteCount = length * 2; 437 if (byteCount > MAX_USER_DATA_BYTES) { 438 values[0] = (byteCount + MAX_USER_DATA_BYTES_WITH_HEADER - 1) / 439 MAX_USER_DATA_BYTES_WITH_HEADER; 440 values[2] = ((values[0] * MAX_USER_DATA_BYTES_WITH_HEADER) - byteCount) / 2; 441 } else { 442 values[0] = 1; 443 values[2] = (MAX_USER_DATA_BYTES - byteCount) / 2; 444 } 445 values[1] = length; 446 values[3] = SmsMessage.ENCODING_16BIT; 447 values[4] = 0; 448 values[5] = 0; 449 mUnicodeCounter++; 450 } else { 451 int udhLength = 0; 452 if (langIndex != 0 || langShiftIndex != 0) { 453 udhLength = UDH_SEPTET_COST_LENGTH; 454 if (langIndex == 0 || langShiftIndex == 0) { 455 udhLength += UDH_SEPTET_COST_ONE_SHIFT_TABLE; 456 } else { 457 udhLength += UDH_SEPTET_COST_TWO_SHIFT_TABLES; 458 } 459 } 460 int msgCount; 461 if (minNumSeptets > (MAX_USER_DATA_SEPTETS - udhLength)) { 462 if (udhLength == 0) { 463 udhLength = UDH_SEPTET_COST_LENGTH; 464 } 465 udhLength += UDH_SEPTET_COST_CONCATENATED_MESSAGE; 466 int septetsPerPart = MAX_USER_DATA_SEPTETS - udhLength; 467 msgCount = (minNumSeptets + septetsPerPart - 1) / septetsPerPart; 468 } else { 469 msgCount = 1; 470 } 471 values[0] = msgCount; 472 values[1] = minNumSeptets; 473 values[2] = (values[0] * (MAX_USER_DATA_SEPTETS - udhLength)) - minNumSeptets; 474 values[3] = SmsMessage.ENCODING_7BIT; 475 values[4] = (langIndex == 2 ? 3 : langIndex); // Portuguese is code 3, index 2 476 values[5] = langShiftIndex; 477 assertEquals("minNumSeptetsWithHeader", minNumSeptetsWithHeader, 478 udhLength * msgCount + minNumSeptets); 479 mStatsCounters[langIndex * 4 + langShiftIndex]++; 480 } 481 } 482 483 void printStats() { 484 Log.d(TAG, "Unicode selection count: " + mUnicodeCounter); 485 for (int i = 0; i < 12; i++) { 486 Log.d(TAG, "Language pair index " + i + " count: " + mStatsCounters[i]); 487 } 488 } 489 } 490 491 @LargeTest 492 public void testCalcLengthMixed7bit() throws Exception { 493 StringBuilder sb = new StringBuilder(320); 494 CounterHelper ch = new CounterHelper(); 495 Random r = new Random(0x4321); // use the same seed for reproducibility 496 int[] expectedValues = new int[6]; 497 int[] origLockingShiftTables = GsmAlphabet.getEnabledLockingShiftTables(); 498 int[] origSingleShiftTables = GsmAlphabet.getEnabledSingleShiftTables(); 499 int enabledLanguagesTestCases = sEnabledSingleShiftTables.length; 500 long startTime = System.currentTimeMillis(); 501 502 // Repeat for 10 test runs 503 for (int run = 0; run < 10; run++) { 504 sb.setLength(0); 505 ch.clear(); 506 int unicodeOnlyCount = 0; 507 508 // Test incrementally from 1 to 320 character random messages 509 for (int i = 1; i < 320; i++) { 510 // 1% chance to add from each special character class, else add an ASCII char 511 int charClass = r.nextInt(100); 512 if (charClass >= sNumCharacterClasses) { 513 charClass = sNumCharacterClasses - 1; // last class is ASCII 514 } 515 int classLength = sCharacterClasses[charClass].length(); 516 char nextChar = sCharacterClasses[charClass].charAt(r.nextInt(classLength)); 517 sb.append(nextChar); 518 ch.addChar(charClass); 519 520// if (i % 20 == 0) { 521// Log.d(TAG, "test string: " + sb); 522// } 523 524 // Test string against all combinations of enabled languages 525 boolean unicodeOnly = true; 526 for (int j = 0; j < enabledLanguagesTestCases; j++) { 527 GsmAlphabet.setEnabledSingleShiftTables(sEnabledSingleShiftTables[j]); 528 GsmAlphabet.setEnabledLockingShiftTables(sEnabledLockingShiftTables[j]); 529 ch.fillData(j, false, expectedValues, i); 530 if (expectedValues[3] == SmsMessage.ENCODING_7BIT) { 531 unicodeOnly = false; 532 } 533 callGsmLengthMethods(sb, false, expectedValues); 534 // test 7 bit only mode 535 ch.fillData(j, true, expectedValues, i); 536 callGsmLengthMethods(sb, true, expectedValues); 537 } 538 // after 10 iterations with a Unicode-only string, skip to next test string 539 // so we can spend more time testing strings that do encode into 7 bits. 540 if (unicodeOnly && ++unicodeOnlyCount == 10) { 541// Log.d(TAG, "Unicode only: skipping to next test string"); 542 break; 543 } 544 } 545 } 546 ch.printStats(); 547 Log.d(TAG, "Completed in " + (System.currentTimeMillis() - startTime) + " ms"); 548 GsmAlphabet.setEnabledLockingShiftTables(origLockingShiftTables); 549 GsmAlphabet.setEnabledSingleShiftTables(origSingleShiftTables); 550 } 551 552 private void callGsmLengthMethods(CharSequence msgBody, boolean use7bitOnly, 553 int[] expectedValues) 554 { 555 // deprecated GSM-specific method 556 int[] values = android.telephony.gsm.SmsMessage.calculateLength(msgBody, use7bitOnly); 557 assertEquals("msgCount", expectedValues[0], values[0]); 558 assertEquals("codeUnitCount", expectedValues[1], values[1]); 559 assertEquals("codeUnitsRemaining", expectedValues[2], values[2]); 560 assertEquals("codeUnitSize", expectedValues[3], values[3]); 561 562 int activePhone = TelephonyManager.getDefault().getPhoneType(); 563 if (TelephonyManager.PHONE_TYPE_GSM == activePhone) { 564 values = android.telephony.SmsMessage.calculateLength(msgBody, use7bitOnly); 565 assertEquals("msgCount", expectedValues[0], values[0]); 566 assertEquals("codeUnitCount", expectedValues[1], values[1]); 567 assertEquals("codeUnitsRemaining", expectedValues[2], values[2]); 568 assertEquals("codeUnitSize", expectedValues[3], values[3]); 569 } 570 571 SmsMessageBase.TextEncodingDetails ted = 572 com.android.internal.telephony.gsm.SmsMessage.calculateLength(msgBody, use7bitOnly); 573 assertEquals("msgCount", expectedValues[0], ted.msgCount); 574 assertEquals("codeUnitCount", expectedValues[1], ted.codeUnitCount); 575 assertEquals("codeUnitsRemaining", expectedValues[2], ted.codeUnitsRemaining); 576 assertEquals("codeUnitSize", expectedValues[3], ted.codeUnitSize); 577 assertEquals("languageTable", expectedValues[4], ted.languageTable); 578 assertEquals("languageShiftTable", expectedValues[5], ted.languageShiftTable); 579 } 580 581 private void callCdmaLengthMethods(CharSequence msgBody, boolean use7bitOnly, 582 int[] expectedValues) 583 { 584 int activePhone = TelephonyManager.getDefault().getPhoneType(); 585 if (TelephonyManager.PHONE_TYPE_CDMA == activePhone) { 586 int[] values = android.telephony.SmsMessage.calculateLength(msgBody, use7bitOnly); 587 assertEquals("msgCount", expectedValues[0], values[0]); 588 assertEquals("codeUnitCount", expectedValues[1], values[1]); 589 assertEquals("codeUnitsRemaining", expectedValues[2], values[2]); 590 assertEquals("codeUnitSize", expectedValues[3], values[3]); 591 } 592 593 SmsMessageBase.TextEncodingDetails ted = 594 com.android.internal.telephony.cdma.SmsMessage.calculateLength(msgBody, use7bitOnly); 595 assertEquals("msgCount", expectedValues[0], ted.msgCount); 596 assertEquals("codeUnitCount", expectedValues[1], ted.codeUnitCount); 597 assertEquals("codeUnitsRemaining", expectedValues[2], ted.codeUnitsRemaining); 598 assertEquals("codeUnitSize", expectedValues[3], ted.codeUnitSize); 599 600 ted = com.android.internal.telephony.cdma.sms.BearerData.calcTextEncodingDetails(msgBody, use7bitOnly); 601 assertEquals("msgCount", expectedValues[0], ted.msgCount); 602 assertEquals("codeUnitCount", expectedValues[1], ted.codeUnitCount); 603 assertEquals("codeUnitsRemaining", expectedValues[2], ted.codeUnitsRemaining); 604 assertEquals("codeUnitSize", expectedValues[3], ted.codeUnitSize); 605 } 606} 607