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