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