Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 141da403 authored by bi4004.lee's avatar bi4004.lee Committed by Jake Hamby
Browse files

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
parent 7311bd4b
Loading
Loading
Loading
Loading
+24 −5
Original line number Diff line number Diff line
@@ -291,12 +291,31 @@ public class SmsMessage {
        // flexibly...

        int limit;
        if (ted.codeUnitSize == ENCODING_7BIT) {
            int udhLength;
            if (ted.languageTable != 0 && ted.languageShiftTable != 0) {
                udhLength = GsmAlphabet.UDH_SEPTET_COST_TWO_SHIFT_TABLES;
            } else if (ted.languageTable != 0 || ted.languageShiftTable != 0) {
                udhLength = GsmAlphabet.UDH_SEPTET_COST_ONE_SHIFT_TABLE;
            } else {
                udhLength = 0;
            }

            if (ted.msgCount > 1) {
            limit = (ted.codeUnitSize == ENCODING_7BIT) ?
                MAX_USER_DATA_SEPTETS_WITH_HEADER : MAX_USER_DATA_BYTES_WITH_HEADER;
                udhLength += GsmAlphabet.UDH_SEPTET_COST_CONCATENATED_MESSAGE;
            }

            if (udhLength != 0) {
                udhLength += GsmAlphabet.UDH_SEPTET_COST_LENGTH;
            }

            limit = MAX_USER_DATA_SEPTETS - udhLength;
        } else {
            limit = (ted.codeUnitSize == ENCODING_7BIT) ?
                MAX_USER_DATA_SEPTETS : MAX_USER_DATA_BYTES;
            if (ted.msgCount > 1) {
                limit = MAX_USER_DATA_BYTES_WITH_HEADER;
            } else {
                limit = MAX_USER_DATA_BYTES;
            }
        }

        int pos = 0;  // Index in code units.
+4 −4
Original line number Diff line number Diff line
@@ -60,25 +60,25 @@ public class GsmAlphabet {
     * all combinations of header elements below will have at least one free bit
     * when padding to the nearest septet boundary.
     */
    private static final int UDH_SEPTET_COST_LENGTH = 1;
    public static final int UDH_SEPTET_COST_LENGTH = 1;

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

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

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

    /**
     * Converts a char to a GSM 7 bit table index.
+109 −2
Original line number Diff line number Diff line
@@ -16,11 +16,14 @@

package com.android.internal.telephony;

import android.telephony.TelephonyManager;
import android.test.AndroidTestCase;
import android.test.suitebuilder.annotation.SmallTest;

import com.android.internal.telephony.gsm.SmsMessage;
import com.android.internal.util.HexDump;

import android.test.AndroidTestCase;
import android.test.suitebuilder.annotation.SmallTest;
import java.util.ArrayList;

public class GsmSmsTest extends AndroidTestCase {

@@ -231,6 +234,110 @@ public class GsmSmsTest extends AndroidTestCase {
            + "\u00a7~abcdefghijklmnopqrstuvwxyz\u00e3\u00f5`\u00fc\u00e0"
    };

    @SmallTest
    public void testFragmentText() throws Exception {
        boolean isGsmPhone = (TelephonyManager.getDefault().getPhoneType() ==
                TelephonyManager.PHONE_TYPE_GSM);

        // Valid 160 character 7-bit text.
        String text = "123456789012345678901234567890123456789012345678901234567890" +
                "1234567890123456789012345678901234567890123456789012345678901234567890" +
                "123456789012345678901234567890";
        SmsMessageBase.TextEncodingDetails ted = SmsMessage.calculateLength(text, false);
        assertEquals(1, ted.msgCount);
        assertEquals(160, ted.codeUnitCount);
        assertEquals(1, ted.codeUnitSize);
        assertEquals(0, ted.languageTable);
        assertEquals(0, ted.languageShiftTable);
        if (isGsmPhone) {
            ArrayList<String> fragments = android.telephony.SmsMessage.fragmentText(text);
            assertEquals(1, fragments.size());
        }

        // Valid 161 character 7-bit text.
        text = "123456789012345678901234567890123456789012345678901234567890" +
                "1234567890123456789012345678901234567890123456789012345678901234567890" +
                "1234567890123456789012345678901";
        ted = SmsMessage.calculateLength(text, false);
        assertEquals(2, ted.msgCount);
        assertEquals(161, ted.codeUnitCount);
        assertEquals(1, ted.codeUnitSize);
        assertEquals(0, ted.languageTable);
        assertEquals(0, ted.languageShiftTable);
        if (isGsmPhone) {
            ArrayList<String> fragments = android.telephony.SmsMessage.fragmentText(text);
            assertEquals(2, fragments.size());
            assertEquals(text, fragments.get(0) + fragments.get(1));
            assertEquals(153, fragments.get(0).length());
            assertEquals(8, fragments.get(1).length());
        }
    }

    @SmallTest
    public void testFragmentTurkishText() throws Exception {
        boolean isGsmPhone = (TelephonyManager.getDefault().getPhoneType() ==
                TelephonyManager.PHONE_TYPE_GSM);

        int[] oldTables = GsmAlphabet.getEnabledSingleShiftTables();
        int[] turkishTable = { 1 };
        GsmAlphabet.setEnabledSingleShiftTables(turkishTable);

        // Valid 77 character text with Turkish characters.
        String text = "ĞŞİğşıĞŞİğşıĞŞİğşıĞŞİğşıĞŞİğşıĞŞİğşıĞŞİğşıĞŞİğşıĞŞİğşıĞŞİğşı" +
                "ĞŞİğşıĞŞİğşıĞŞİğş";
        SmsMessageBase.TextEncodingDetails ted = SmsMessage.calculateLength(text, false);
        assertEquals(1, ted.msgCount);
        assertEquals(154, ted.codeUnitCount);
        assertEquals(1, ted.codeUnitSize);
        assertEquals(0, ted.languageTable);
        assertEquals(1, ted.languageShiftTable);
        if (isGsmPhone) {
            ArrayList<String> fragments = android.telephony.SmsMessage.fragmentText(text);
            assertEquals(1, fragments.size());
            assertEquals(text, fragments.get(0));
            assertEquals(77, fragments.get(0).length());
        }

        // Valid 78 character text with Turkish characters.
        text = "ĞŞİğşıĞŞİğşıĞŞİğşıĞŞİğşıĞŞİğşıĞŞİğşıĞŞİğşıĞŞİğşıĞŞİğşıĞŞİğşı" +
                "ĞŞİğşıĞŞİğşıĞŞİğşı";
        ted = SmsMessage.calculateLength(text, false);
        assertEquals(2, ted.msgCount);
        assertEquals(156, ted.codeUnitCount);
        assertEquals(1, ted.codeUnitSize);
        assertEquals(0, ted.languageTable);
        assertEquals(1, ted.languageShiftTable);
        if (isGsmPhone) {
            ArrayList<String> fragments = android.telephony.SmsMessage.fragmentText(text);
            assertEquals(2, fragments.size());
            assertEquals(text, fragments.get(0) + fragments.get(1));
            assertEquals(74, fragments.get(0).length());
            assertEquals(4, fragments.get(1).length());
        }

        // Valid 160 character text with Turkish characters.
        text = "ĞŞİğşıĞŞİğşıĞŞİğşıĞŞİğşıĞŞİğşıĞŞİğşıĞŞİğşıĞŞİğşıĞŞİğşıĞŞİğşı" +
                "ĞŞİğşıĞŞİğşıĞŞİğşıĞŞİğşıĞŞİğşıĞŞİğşıĞŞİğşıĞŞİğşıĞŞİğşıĞŞİğşıĞŞİğşıĞŞİğ" +
                "ĞŞİğşıĞŞİğşıĞŞİğşıĞŞİğşıĞŞİğşı";
        ted = SmsMessage.calculateLength(text, false);
        assertEquals(3, ted.msgCount);
        assertEquals(320, ted.codeUnitCount);
        assertEquals(1, ted.codeUnitSize);
        assertEquals(0, ted.languageTable);
        assertEquals(1, ted.languageShiftTable);
        if (isGsmPhone) {
            ArrayList<String> fragments = android.telephony.SmsMessage.fragmentText(text);
            assertEquals(3, fragments.size());
            assertEquals(text, fragments.get(0) + fragments.get(1) + fragments.get(2));
            assertEquals(74, fragments.get(0).length());
            assertEquals(74, fragments.get(1).length());
            assertEquals(12, fragments.get(2).length());
        }

        GsmAlphabet.setEnabledSingleShiftTables(oldTables);
    }


    @SmallTest
    public void testDecode() throws Exception {
        decodeSingle(0);    // default table