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