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