• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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