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