Skip to content

Commit 141da40

Browse files
bi4004.leeJake Hamby
authored andcommitted
Fix exception when sending multi-page SMS with Turkish characters.
- Precondition: config_sms_enabled_single_shift_tables is configured as 1 (Turkish) in frameworks/base/core/res/res/values/config.xml - Cause: There is no consideration for National Language Shift Tables in SmsMessage::fragmentText function. - Solution: The header length is calculated properly according to National Language Shift Table - modified to add test cases and fix calculation bug (jhamby@google.com) Bug: 5553544 Change-Id: I9eaefbbd6b3d75f8c41cbf9d0cb03a701cfa1cb3
1 parent 7311bd4 commit 141da40

File tree

3 files changed

+137
-11
lines changed

3 files changed

+137
-11
lines changed

telephony/java/android/telephony/SmsMessage.java

Lines changed: 24 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -291,12 +291,31 @@ public static ArrayList<String> fragmentText(String text) {
291291
// flexibly...
292292

293293
int limit;
294-
if (ted.msgCount > 1) {
295-
limit = (ted.codeUnitSize == ENCODING_7BIT) ?
296-
MAX_USER_DATA_SEPTETS_WITH_HEADER : MAX_USER_DATA_BYTES_WITH_HEADER;
294+
if (ted.codeUnitSize == ENCODING_7BIT) {
295+
int udhLength;
296+
if (ted.languageTable != 0 && ted.languageShiftTable != 0) {
297+
udhLength = GsmAlphabet.UDH_SEPTET_COST_TWO_SHIFT_TABLES;
298+
} else if (ted.languageTable != 0 || ted.languageShiftTable != 0) {
299+
udhLength = GsmAlphabet.UDH_SEPTET_COST_ONE_SHIFT_TABLE;
300+
} else {
301+
udhLength = 0;
302+
}
303+
304+
if (ted.msgCount > 1) {
305+
udhLength += GsmAlphabet.UDH_SEPTET_COST_CONCATENATED_MESSAGE;
306+
}
307+
308+
if (udhLength != 0) {
309+
udhLength += GsmAlphabet.UDH_SEPTET_COST_LENGTH;
310+
}
311+
312+
limit = MAX_USER_DATA_SEPTETS - udhLength;
297313
} else {
298-
limit = (ted.codeUnitSize == ENCODING_7BIT) ?
299-
MAX_USER_DATA_SEPTETS : MAX_USER_DATA_BYTES;
314+
if (ted.msgCount > 1) {
315+
limit = MAX_USER_DATA_BYTES_WITH_HEADER;
316+
} else {
317+
limit = MAX_USER_DATA_BYTES;
318+
}
300319
}
301320

302321
int pos = 0; // Index in code units.

telephony/java/com/android/internal/telephony/GsmAlphabet.java

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -60,25 +60,25 @@ private GsmAlphabet() { }
6060
* all combinations of header elements below will have at least one free bit
6161
* when padding to the nearest septet boundary.
6262
*/
63-
private static final int UDH_SEPTET_COST_LENGTH = 1;
63+
public static final int UDH_SEPTET_COST_LENGTH = 1;
6464

6565
/**
6666
* Using a non-default language locking shift table OR single shift table
6767
* requires a user data header of 3 octets, or 4 septets, plus UDH length.
6868
*/
69-
private static final int UDH_SEPTET_COST_ONE_SHIFT_TABLE = 4;
69+
public static final int UDH_SEPTET_COST_ONE_SHIFT_TABLE = 4;
7070

7171
/**
7272
* Using a non-default language locking shift table AND single shift table
7373
* requires a user data header of 6 octets, or 7 septets, plus UDH length.
7474
*/
75-
private static final int UDH_SEPTET_COST_TWO_SHIFT_TABLES = 7;
75+
public static final int UDH_SEPTET_COST_TWO_SHIFT_TABLES = 7;
7676

7777
/**
7878
* Multi-part messages require a user data header of 5 octets, or 6 septets,
7979
* plus UDH length.
8080
*/
81-
private static final int UDH_SEPTET_COST_CONCATENATED_MESSAGE = 6;
81+
public static final int UDH_SEPTET_COST_CONCATENATED_MESSAGE = 6;
8282

8383
/**
8484
* Converts a char to a GSM 7 bit table index.

telephony/tests/telephonytests/src/com/android/internal/telephony/GsmSmsTest.java

Lines changed: 109 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -16,11 +16,14 @@
1616

1717
package com.android.internal.telephony;
1818

19+
import android.telephony.TelephonyManager;
20+
import android.test.AndroidTestCase;
21+
import android.test.suitebuilder.annotation.SmallTest;
22+
1923
import com.android.internal.telephony.gsm.SmsMessage;
2024
import com.android.internal.util.HexDump;
2125

22-
import android.test.AndroidTestCase;
23-
import android.test.suitebuilder.annotation.SmallTest;
26+
import java.util.ArrayList;
2427

2528
public class GsmSmsTest extends AndroidTestCase {
2629

@@ -231,6 +234,110 @@ public void testExtendedCharacterTable() throws Exception {
231234
+ "\u00a7~abcdefghijklmnopqrstuvwxyz\u00e3\u00f5`\u00fc\u00e0"
232235
};
233236

237+
@SmallTest
238+
public void testFragmentText() throws Exception {
239+
boolean isGsmPhone = (TelephonyManager.getDefault().getPhoneType() ==
240+
TelephonyManager.PHONE_TYPE_GSM);
241+
242+
// Valid 160 character 7-bit text.
243+
String text = "123456789012345678901234567890123456789012345678901234567890" +
244+
"1234567890123456789012345678901234567890123456789012345678901234567890" +
245+
"123456789012345678901234567890";
246+
SmsMessageBase.TextEncodingDetails ted = SmsMessage.calculateLength(text, false);
247+
assertEquals(1, ted.msgCount);
248+
assertEquals(160, ted.codeUnitCount);
249+
assertEquals(1, ted.codeUnitSize);
250+
assertEquals(0, ted.languageTable);
251+
assertEquals(0, ted.languageShiftTable);
252+
if (isGsmPhone) {
253+
ArrayList<String> fragments = android.telephony.SmsMessage.fragmentText(text);
254+
assertEquals(1, fragments.size());
255+
}
256+
257+
// Valid 161 character 7-bit text.
258+
text = "123456789012345678901234567890123456789012345678901234567890" +
259+
"1234567890123456789012345678901234567890123456789012345678901234567890" +
260+
"1234567890123456789012345678901";
261+
ted = SmsMessage.calculateLength(text, false);
262+
assertEquals(2, ted.msgCount);
263+
assertEquals(161, ted.codeUnitCount);
264+
assertEquals(1, ted.codeUnitSize);
265+
assertEquals(0, ted.languageTable);
266+
assertEquals(0, ted.languageShiftTable);
267+
if (isGsmPhone) {
268+
ArrayList<String> fragments = android.telephony.SmsMessage.fragmentText(text);
269+
assertEquals(2, fragments.size());
270+
assertEquals(text, fragments.get(0) + fragments.get(1));
271+
assertEquals(153, fragments.get(0).length());
272+
assertEquals(8, fragments.get(1).length());
273+
}
274+
}
275+
276+
@SmallTest
277+
public void testFragmentTurkishText() throws Exception {
278+
boolean isGsmPhone = (TelephonyManager.getDefault().getPhoneType() ==
279+
TelephonyManager.PHONE_TYPE_GSM);
280+
281+
int[] oldTables = GsmAlphabet.getEnabledSingleShiftTables();
282+
int[] turkishTable = { 1 };
283+
GsmAlphabet.setEnabledSingleShiftTables(turkishTable);
284+
285+
// Valid 77 character text with Turkish characters.
286+
String text = "ĞŞİğşıĞŞİğşıĞŞİğşıĞŞİğşıĞŞİğşıĞŞİğşıĞŞİğşıĞŞİğşıĞŞİğşıĞŞİğşı" +
287+
"ĞŞİğşıĞŞİğşıĞŞİğş";
288+
SmsMessageBase.TextEncodingDetails ted = SmsMessage.calculateLength(text, false);
289+
assertEquals(1, ted.msgCount);
290+
assertEquals(154, ted.codeUnitCount);
291+
assertEquals(1, ted.codeUnitSize);
292+
assertEquals(0, ted.languageTable);
293+
assertEquals(1, ted.languageShiftTable);
294+
if (isGsmPhone) {
295+
ArrayList<String> fragments = android.telephony.SmsMessage.fragmentText(text);
296+
assertEquals(1, fragments.size());
297+
assertEquals(text, fragments.get(0));
298+
assertEquals(77, fragments.get(0).length());
299+
}
300+
301+
// Valid 78 character text with Turkish characters.
302+
text = "ĞŞİğşıĞŞİğşıĞŞİğşıĞŞİğşıĞŞİğşıĞŞİğşıĞŞİğşıĞŞİğşıĞŞİğşıĞŞİğşı" +
303+
"ĞŞİğşıĞŞİğşıĞŞİğşı";
304+
ted = SmsMessage.calculateLength(text, false);
305+
assertEquals(2, ted.msgCount);
306+
assertEquals(156, ted.codeUnitCount);
307+
assertEquals(1, ted.codeUnitSize);
308+
assertEquals(0, ted.languageTable);
309+
assertEquals(1, ted.languageShiftTable);
310+
if (isGsmPhone) {
311+
ArrayList<String> fragments = android.telephony.SmsMessage.fragmentText(text);
312+
assertEquals(2, fragments.size());
313+
assertEquals(text, fragments.get(0) + fragments.get(1));
314+
assertEquals(74, fragments.get(0).length());
315+
assertEquals(4, fragments.get(1).length());
316+
}
317+
318+
// Valid 160 character text with Turkish characters.
319+
text = "ĞŞİğşıĞŞİğşıĞŞİğşıĞŞİğşıĞŞİğşıĞŞİğşıĞŞİğşıĞŞİğşıĞŞİğşıĞŞİğşı" +
320+
"ĞŞİğşıĞŞİğşıĞŞİğşıĞŞİğşıĞŞİğşıĞŞİğşıĞŞİğşıĞŞİğşıĞŞİğşıĞŞİğşıĞŞİğşıĞŞİğ" +
321+
"ĞŞİğşıĞŞİğşıĞŞİğşıĞŞİğşıĞŞİğşı";
322+
ted = SmsMessage.calculateLength(text, false);
323+
assertEquals(3, ted.msgCount);
324+
assertEquals(320, ted.codeUnitCount);
325+
assertEquals(1, ted.codeUnitSize);
326+
assertEquals(0, ted.languageTable);
327+
assertEquals(1, ted.languageShiftTable);
328+
if (isGsmPhone) {
329+
ArrayList<String> fragments = android.telephony.SmsMessage.fragmentText(text);
330+
assertEquals(3, fragments.size());
331+
assertEquals(text, fragments.get(0) + fragments.get(1) + fragments.get(2));
332+
assertEquals(74, fragments.get(0).length());
333+
assertEquals(74, fragments.get(1).length());
334+
assertEquals(12, fragments.get(2).length());
335+
}
336+
337+
GsmAlphabet.setEnabledSingleShiftTables(oldTables);
338+
}
339+
340+
234341
@SmallTest
235342
public void testDecode() throws Exception {
236343
decodeSingle(0); // default table

0 commit comments

Comments
 (0)