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