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