10825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville/*
20825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville * Copyright (C) 2006 The Android Open Source Project
30825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville *
40825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville * Licensed under the Apache License, Version 2.0 (the "License");
50825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville * you may not use this file except in compliance with the License.
60825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville * You may obtain a copy of the License at
70825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville *
80825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville *      http://www.apache.org/licenses/LICENSE-2.0
90825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville *
100825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville * Unless required by applicable law or agreed to in writing, software
110825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville * distributed under the License is distributed on an "AS IS" BASIS,
120825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
130825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville * See the License for the specific language governing permissions and
140825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville * limitations under the License.
150825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville */
160825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville
170825495a331bb44df395a0cdb79fab85e68db5d5Wink Savillepackage com.android.internal.telephony;
180825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville
190825495a331bb44df395a0cdb79fab85e68db5d5Wink Savilleimport android.telephony.TelephonyManager;
200825495a331bb44df395a0cdb79fab85e68db5d5Wink Savilleimport android.test.AndroidTestCase;
210825495a331bb44df395a0cdb79fab85e68db5d5Wink Savilleimport android.test.suitebuilder.annotation.SmallTest;
220825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville
230825495a331bb44df395a0cdb79fab85e68db5d5Wink Savilleimport com.android.internal.telephony.gsm.SmsMessage;
240825495a331bb44df395a0cdb79fab85e68db5d5Wink Savilleimport com.android.internal.util.HexDump;
250825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville
260825495a331bb44df395a0cdb79fab85e68db5d5Wink Savilleimport java.util.ArrayList;
270825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville
280825495a331bb44df395a0cdb79fab85e68db5d5Wink Savillepublic class GsmSmsTest extends AndroidTestCase {
290825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville
300825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville    @SmallTest
310825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville    public void testAddressing() throws Exception {
320825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        String pdu = "07914151551512f2040B916105551511f100006060605130308A04D4F29C0E";
330825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        SmsMessage sms = SmsMessage.createFromPdu(HexDump.hexStringToByteArray(pdu));
340825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        assertEquals("+14155551212", sms.getServiceCenterAddress());
350825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        assertEquals("+16505551111", sms.getOriginatingAddress());
360825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        assertEquals("Test", sms.getMessageBody());
370825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville
380825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        pdu = "07914151551512f2040B916105551511f100036060924180008A0DA"
390825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville                + "8695DAC2E8FE9296A794E07";
400825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        sms = SmsMessage.createFromPdu(HexDump.hexStringToByteArray(pdu));
410825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        assertEquals("+14155551212", sms.getServiceCenterAddress());
420825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        assertEquals("+16505551111", sms.getOriginatingAddress());
430825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        assertEquals("(Subject)Test", sms.getMessageBody());
440825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville    }
450825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville
460825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville    @SmallTest
470825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville    public void testUdh() throws Exception {
480825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        String pdu = "07914140279510F6440A8111110301003BF56080207130138A8C0B05040B8423F"
490825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville                + "000032A02010106276170706C69636174696F6E2F766E642E7761702E6D6D732D"
500825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville                + "6D65737361676500AF848D0185B4848C8298524E453955304A6D7135514141426"
510825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville                + "66C414141414D7741414236514141414141008D908918802B3135313232393737"
520825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville                + "3638332F545950453D504C4D4E008A808E022B918805810306977F83687474703"
530825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville                + "A2F2F36";
540825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        SmsMessage sms = SmsMessage.createFromPdu(HexDump.hexStringToByteArray(pdu));
550825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        SmsHeader header = sms.getUserDataHeader();
560825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        assertNotNull(header);
570825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        assertNotNull(header.concatRef);
580825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        assertEquals(header.concatRef.refNumber, 42);
590825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        assertEquals(header.concatRef.msgCount, 2);
600825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        assertEquals(header.concatRef.seqNumber, 1);
610825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        assertEquals(header.concatRef.isEightBits, true);
620825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        assertNotNull(header.portAddrs);
630825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        assertEquals(header.portAddrs.destPort, 2948);
640825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        assertEquals(header.portAddrs.origPort, 9200);
650825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        assertEquals(header.portAddrs.areEightBits, false);
660825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville
670825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        pdu = "07914140279510F6440A8111110301003BF56080207130238A3B0B05040B8423F"
680825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville                + "000032A0202362E3130322E3137312E3135302F524E453955304A6D7135514141"
690825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville                + "42666C414141414D774141423651414141414100";
700825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        sms = SmsMessage.createFromPdu(HexDump.hexStringToByteArray(pdu));
710825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        header = sms.getUserDataHeader();
720825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        assertNotNull(header);
730825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        assertNotNull(header.concatRef);
740825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        assertEquals(header.concatRef.refNumber, 42);
750825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        assertEquals(header.concatRef.msgCount, 2);
760825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        assertEquals(header.concatRef.seqNumber, 2);
770825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        assertEquals(header.concatRef.isEightBits, true);
780825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        assertNotNull(header.portAddrs);
790825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        assertEquals(header.portAddrs.destPort, 2948);
800825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        assertEquals(header.portAddrs.origPort, 9200);
810825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        assertEquals(header.portAddrs.areEightBits, false);
820825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville    }
830825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville
840825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville    @SmallTest
850825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville    public void testUcs2() throws Exception {
860825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        String pdu = "07912160130300F4040B914151245584F600087010807121352B1021220"
870825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville                + "0A900AE00680065006C006C006F";
880825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        SmsMessage sms = SmsMessage.createFromPdu(HexDump.hexStringToByteArray(pdu));
890825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        assertEquals("\u2122\u00a9\u00aehello", sms.getMessageBody());
900825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville    }
910825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville
920825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville    @SmallTest
930825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville    public void testMultipart() throws Exception {
940825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        /*
950825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville         * Multi-part text SMS with septet data.
960825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville         */
970825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        String pdu = "07916163838408F6440B816105224431F700007060217175830AA0050003"
980825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville                + "00020162B1582C168BC562B1582C168BC562B1582C168BC562B1582C"
990825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville                + "168BC562B1582C168BC562B1582C168BC562B1582C168BC562B1582C"
1000825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville                + "168BC562B1582C168BC562B1582C168BC562B1582C168BC562B1582C"
1010825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville                + "168BC562B1582C168BC562B1582C168BC562B1582C168BC562B1582C"
1020825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville                + "168BC562B1582C168BC562B1582C168BC562B1582C168BC562";
1030825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        SmsMessage sms = SmsMessage.createFromPdu(HexDump.hexStringToByteArray(pdu));
1040825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        assertEquals(sms.getMessageBody(),
1050825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville                "1111111111111111111111111111111111111111"
1060825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville                + "1111111111111111111111111111111111111111"
1070825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville                + "1111111111111111111111111111111111111111"
1080825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville                + "111111111111111111111111111111111");
1090825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville
1100825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        pdu = "07916163838408F6440B816105224431F700007060217185000A23050003"
1110825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville                + "00020262B1582C168BC96432994C2693C96432994C2693C96432990C";
1120825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        sms = SmsMessage.createFromPdu(HexDump.hexStringToByteArray(pdu));
1130825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        assertEquals("1111111222222222222222222222", sms.getMessageBody());
1140825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville    }
1150825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville
1160825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville    @SmallTest
1170825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville    public void testCPHSVoiceMail() throws Exception {
1180825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        // "set MWI flag"
1190825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville
1200825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        String pdu = "07912160130310F20404D0110041006060627171118A0120";
1210825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville
1220825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        SmsMessage sms = SmsMessage.createFromPdu(HexDump.hexStringToByteArray(pdu));
1230825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville
1240825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        assertTrue(sms.isReplace());
1250825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        assertEquals("_@", sms.getOriginatingAddress());
1260825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        assertEquals(" ", sms.getMessageBody());
1270825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        assertTrue(sms.isMWISetMessage());
1280825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville
1290825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        // "clear mwi flag"
1300825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville
1310825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        pdu = "07912160130310F20404D0100041006021924193352B0120";
1320825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville
1330825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        sms = SmsMessage.createFromPdu(HexDump.hexStringToByteArray(pdu));
1340825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville
1350825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        assertTrue(sms.isMWIClearMessage());
1360825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville
1370825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        // "clear MWI flag"
1380825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville
1390825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        pdu = "07912160130310F20404D0100041006060627161058A0120";
1400825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville
1410825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        sms = SmsMessage.createFromPdu(HexDump.hexStringToByteArray(pdu));
1420825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville
1430825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        assertTrue(sms.isReplace());
1440825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        assertEquals("\u0394@", sms.getOriginatingAddress());
1450825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        assertEquals(" ", sms.getMessageBody());
1460825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        assertTrue(sms.isMWIClearMessage());
1470825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville    }
1480825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville
1490825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville    @SmallTest
1500825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville    public void testCingularVoiceMail() throws Exception {
1510825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        // "set MWI flag"
1520825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville
1530825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        String pdu = "07912180958750F84401800500C87020026195702B06040102000200";
1540825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        SmsMessage sms = SmsMessage.createFromPdu(HexDump.hexStringToByteArray(pdu));
1550825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville
1560825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        assertTrue(sms.isMWISetMessage());
1570825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        assertTrue(sms.isMwiDontStore());
1580825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville
1590825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        // "clear mwi flag"
1600825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville
1610825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        pdu = "07912180958750F84401800500C07020027160112B06040102000000";
1620825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        sms = SmsMessage.createFromPdu(HexDump.hexStringToByteArray(pdu));
1630825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville
1640825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        assertTrue(sms.isMWIClearMessage());
1650825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        assertTrue(sms.isMwiDontStore());
1660825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville    }
1670825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville
1680825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville    @SmallTest
1690825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville    public void testEmailGateway() throws Exception {
1700825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        String pdu = "07914151551512f204038105f300007011103164638a28e6f71b50c687db" +
1710825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville                "7076d9357eb7412f7a794e07cdeb6275794c07bde8e5391d247e93f3";
1720825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville
1730825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        SmsMessage sms = SmsMessage.createFromPdu(HexDump.hexStringToByteArray(pdu));
1740825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville
1750825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        assertEquals("+14155551212", sms.getServiceCenterAddress());
1760825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        assertTrue(sms.isEmail());
1770825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        assertEquals("foo@example.com", sms.getEmailFrom());
1780825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        assertEquals("foo@example.com", sms.getDisplayOriginatingAddress());
1790825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        // As of https://android-git.corp.google.com/g/#change,9324
1800825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        // getPseudoSubject will always be empty, and any subject is not extracted.
1810825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        assertEquals("", sms.getPseudoSubject());
1820825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        assertEquals("test subject /test body", sms.getDisplayMessageBody());
1830825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        assertEquals("test subject /test body", sms.getEmailBody());
1840825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville
1850825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        // email gateway sms test, including gsm extended character set.
1860825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        pdu = "07914151551512f204038105f400007011103105458a29e6f71b50c687db" +
1870825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville                "7076d9357eb741af0d0a442fcfe9c23739bfe16d289bdee6b5f1813629";
1880825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville
1890825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        sms = SmsMessage.createFromPdu(HexDump.hexStringToByteArray(pdu));
1900825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville
1910825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        assertEquals("+14155551212", sms.getServiceCenterAddress());
1920825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        assertTrue(sms.isEmail());
1930825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        assertEquals("foo@example.com", sms.getDisplayOriginatingAddress());
1940825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        assertEquals("foo@example.com", sms.getEmailFrom());
1950825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        assertEquals("{ testBody[^~\\] }", sms.getDisplayMessageBody());
1960825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        assertEquals("{ testBody[^~\\] }", sms.getEmailBody());
1970825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville    }
1980825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville
1990825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville    @SmallTest
2000825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville    public void testExtendedCharacterTable() throws Exception {
2010825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        String pdu = "07914151551512f2040B916105551511f100006080615131728A44D4F29C0E2" +
2020825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville                "AE3E96537B94C068DD16179784C2FCB41F4B0985D06B958ADD00FB0E94536AF9749" +
2030825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville                "74DA6D281BA00E95E26D509B946FC3DBF87A25D56A04";
2040825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville
2050825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        SmsMessage sms = SmsMessage.createFromPdu(HexDump.hexStringToByteArray(pdu));
2060825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville
2070825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        assertEquals("+14155551212", sms.getServiceCenterAddress());
2080825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        assertEquals("+16505551111", sms.getOriginatingAddress());
2090825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        assertEquals("Test extended character table .,-!?@~_\\/&\"';^|:()<{}>[]=%*+#",
2100825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville                sms.getMessageBody());
2110825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville    }
2120825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville
2130825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville    // GSM 7 bit tables in String form, Escape (0x1B) replaced with '@'
2140825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville    private static final String[] sBasicTables = {
2150825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        // GSM 7 bit default alphabet
2160825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        "@\u00a3$\u00a5\u00e8\u00e9\u00f9\u00ec\u00f2\u00c7\n\u00d8\u00f8\r\u00c5\u00e5\u0394_"
2170825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville            + "\u03a6\u0393\u039b\u03a9\u03a0\u03a8\u03a3\u0398\u039e@\u00c6\u00e6\u00df\u00c9"
2180825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville            + " !\"#\u00a4%&'()*+,-./0123456789:;<=>?\u00a1ABCDEFGHIJKLMNOPQRSTUVWXYZ\u00c4\u00d6"
2190825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville            + "\u00d1\u00dc\u00a7\u00bfabcdefghijklmnopqrstuvwxyz\u00e4\u00f6\u00f1\u00fc\u00e0",
2200825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville
2210825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        // Turkish locking shift table
2220825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        "@\u00a3$\u00a5\u20ac\u00e9\u00f9\u0131\u00f2\u00c7\n\u011e\u011f\r\u00c5\u00e5\u0394_"
2230825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville            + "\u03a6\u0393\u039b\u03a9\u03a0\u03a8\u03a3\u0398\u039e@\u015e\u015f\u00df\u00c9"
2240825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville            + " !\"#\u00a4%&'()*+,-./0123456789:;<=>?\u0130ABCDEFGHIJKLMNOPQRSTUVWXYZ\u00c4\u00d6"
2250825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville            + "\u00d1\u00dc\u00a7\u00e7abcdefghijklmnopqrstuvwxyz\u00e4\u00f6\u00f1\u00fc\u00e0",
2260825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville
2270825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        // no locking shift table defined for Spanish
2280825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        "",
2290825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville
2300825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        // Portuguese locking shift table
2310825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        "@\u00a3$\u00a5\u00ea\u00e9\u00fa\u00ed\u00f3\u00e7\n\u00d4\u00f4\r\u00c1\u00e1\u0394_"
2320825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville            + "\u00aa\u00c7\u00c0\u221e^\\\u20ac\u00d3|@\u00c2\u00e2\u00ca\u00c9 !\"#\u00ba%&'()"
2330825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville            + "*+,-./0123456789:;<=>?\u00cdABCDEFGHIJKLMNOPQRSTUVWXYZ\u00c3\u00d5\u00da\u00dc"
2340825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville            + "\u00a7~abcdefghijklmnopqrstuvwxyz\u00e3\u00f5`\u00fc\u00e0"
2350825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville    };
2360825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville
2370825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville    @SmallTest
2380825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville    public void testFragmentText() throws Exception {
2390825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        boolean isGsmPhone = (TelephonyManager.getDefault().getPhoneType() ==
2400825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville                TelephonyManager.PHONE_TYPE_GSM);
2410825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville
2420825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        // Valid 160 character 7-bit text.
2430825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        String text = "123456789012345678901234567890123456789012345678901234567890" +
2440825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville                "1234567890123456789012345678901234567890123456789012345678901234567890" +
2450825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville                "123456789012345678901234567890";
2460825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        GsmAlphabet.TextEncodingDetails ted = SmsMessage.calculateLength(text, false);
2470825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        assertEquals(1, ted.msgCount);
2480825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        assertEquals(160, ted.codeUnitCount);
2490825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        assertEquals(1, ted.codeUnitSize);
2500825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        assertEquals(0, ted.languageTable);
2510825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        assertEquals(0, ted.languageShiftTable);
2520825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        if (isGsmPhone) {
2530825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville            ArrayList<String> fragments = android.telephony.SmsMessage.fragmentText(text);
2540825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville            assertEquals(1, fragments.size());
2550825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        }
2560825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville
2570825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        // Valid 161 character 7-bit text.
2580825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        text = "123456789012345678901234567890123456789012345678901234567890" +
2590825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville                "1234567890123456789012345678901234567890123456789012345678901234567890" +
2600825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville                "1234567890123456789012345678901";
2610825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        ted = SmsMessage.calculateLength(text, false);
2620825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        assertEquals(2, ted.msgCount);
2630825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        assertEquals(161, ted.codeUnitCount);
2640825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        assertEquals(1, ted.codeUnitSize);
2650825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        assertEquals(0, ted.languageTable);
2660825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        assertEquals(0, ted.languageShiftTable);
2670825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        if (isGsmPhone) {
2680825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville            ArrayList<String> fragments = android.telephony.SmsMessage.fragmentText(text);
2690825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville            assertEquals(2, fragments.size());
2700825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville            assertEquals(text, fragments.get(0) + fragments.get(1));
2710825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville            assertEquals(153, fragments.get(0).length());
2720825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville            assertEquals(8, fragments.get(1).length());
2730825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        }
2740825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville    }
2750825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville
2760825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville    @SmallTest
2770825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville    public void testFragmentTurkishText() throws Exception {
2780825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        boolean isGsmPhone = (TelephonyManager.getDefault().getPhoneType() ==
2790825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville                TelephonyManager.PHONE_TYPE_GSM);
2800825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville
2810825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        int[] oldTables = GsmAlphabet.getEnabledSingleShiftTables();
2820825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        int[] turkishTable = { 1 };
2830825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        GsmAlphabet.setEnabledSingleShiftTables(turkishTable);
2840825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville
2850825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        // Valid 77 character text with Turkish characters.
2860825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        String text = "ĞŞİğşıĞŞİğşıĞŞİğşıĞŞİğşıĞŞİğşıĞŞİğşıĞŞİğşıĞŞİğşıĞŞİğşıĞŞİğşı" +
2870825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville                "ĞŞİğşıĞŞİğşıĞŞİğş";
2880825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        GsmAlphabet.TextEncodingDetails ted = SmsMessage.calculateLength(text, false);
2890825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        assertEquals(1, ted.msgCount);
2900825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        assertEquals(154, ted.codeUnitCount);
2910825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        assertEquals(1, ted.codeUnitSize);
2920825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        assertEquals(0, ted.languageTable);
2930825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        assertEquals(1, ted.languageShiftTable);
2940825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        if (isGsmPhone) {
2950825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville            ArrayList<String> fragments = android.telephony.SmsMessage.fragmentText(text);
2960825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville            assertEquals(1, fragments.size());
2970825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville            assertEquals(text, fragments.get(0));
2980825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville            assertEquals(77, fragments.get(0).length());
2990825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        }
3000825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville
3010825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        // Valid 78 character text with Turkish characters.
3020825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        text = "ĞŞİğşıĞŞİğşıĞŞİğşıĞŞİğşıĞŞİğşıĞŞİğşıĞŞİğşıĞŞİğşıĞŞİğşıĞŞİğşı" +
3030825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville                "ĞŞİğşıĞŞİğşıĞŞİğşı";
3040825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        ted = SmsMessage.calculateLength(text, false);
3050825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        assertEquals(2, ted.msgCount);
3060825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        assertEquals(156, ted.codeUnitCount);
3070825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        assertEquals(1, ted.codeUnitSize);
3080825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        assertEquals(0, ted.languageTable);
3090825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        assertEquals(1, ted.languageShiftTable);
3100825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        if (isGsmPhone) {
3110825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville            ArrayList<String> fragments = android.telephony.SmsMessage.fragmentText(text);
3120825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville            assertEquals(2, fragments.size());
3130825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville            assertEquals(text, fragments.get(0) + fragments.get(1));
3140825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville            assertEquals(74, fragments.get(0).length());
3150825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville            assertEquals(4, fragments.get(1).length());
3160825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        }
3170825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville
3180825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        // Valid 160 character text with Turkish characters.
3190825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        text = "ĞŞİğşıĞŞİğşıĞŞİğşıĞŞİğşıĞŞİğşıĞŞİğşıĞŞİğşıĞŞİğşıĞŞİğşıĞŞİğşı" +
3200825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville                "ĞŞİğşıĞŞİğşıĞŞİğşıĞŞİğşıĞŞİğşıĞŞİğşıĞŞİğşıĞŞİğşıĞŞİğşıĞŞİğşıĞŞİğşıĞŞİğ" +
3210825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville                "ĞŞİğşıĞŞİğşıĞŞİğşıĞŞİğşıĞŞİğşı";
3220825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        ted = SmsMessage.calculateLength(text, false);
3230825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        assertEquals(3, ted.msgCount);
3240825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        assertEquals(320, ted.codeUnitCount);
3250825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        assertEquals(1, ted.codeUnitSize);
3260825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        assertEquals(0, ted.languageTable);
3270825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        assertEquals(1, ted.languageShiftTable);
3280825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        if (isGsmPhone) {
3290825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville            ArrayList<String> fragments = android.telephony.SmsMessage.fragmentText(text);
3300825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville            assertEquals(3, fragments.size());
3310825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville            assertEquals(text, fragments.get(0) + fragments.get(1) + fragments.get(2));
3320825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville            assertEquals(74, fragments.get(0).length());
3330825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville            assertEquals(74, fragments.get(1).length());
3340825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville            assertEquals(12, fragments.get(2).length());
3350825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        }
3360825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville
3370825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        GsmAlphabet.setEnabledSingleShiftTables(oldTables);
3380825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville    }
3390825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville
3400825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville
3410825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville    @SmallTest
3420825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville    public void testDecode() throws Exception {
3430825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        decodeSingle(0);    // default table
3440825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        decodeSingle(1);    // Turkish locking shift table
3450825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        decodeSingle(3);    // Portuguese locking shift table
3460825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville    }
3470825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville
3480825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville    private void decodeSingle(int language) throws Exception {
3490825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        byte[] septets = new byte[(7 * 128 + 7) / 8];
3500825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville
3510825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        int bitOffset = 0;
3520825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville
3530825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        for (int i = 0; i < 128; i++) {
3540825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville            int v;
3550825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville            if (i == 0x1b) {
3560825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville                // extended escape char
3570825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville                v = 0;
3580825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville            } else {
3590825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville                v = i;
3600825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville            }
3610825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville
3620825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville            int byteOffset = bitOffset / 8;
3630825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville            int shift = bitOffset % 8;
3640825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville
3650825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville            septets[byteOffset] |= v << shift;
3660825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville
3670825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville            if (shift > 1) {
3680825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville                septets[byteOffset + 1] = (byte) (v >> (8 - shift));
3690825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville            }
3700825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville
3710825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville            bitOffset += 7;
3720825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        }
3730825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville
3740825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        String decoded = GsmAlphabet.gsm7BitPackedToString(septets, 0, 128, 0, language, 0);
3750825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        byte[] reEncoded = GsmAlphabet.stringToGsm7BitPacked(decoded, language, 0);
3760825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville
3770825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        assertEquals(sBasicTables[language], decoded);
3780825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville
3790825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        // reEncoded has the count septets byte at the front
3800825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        assertEquals(septets.length + 1, reEncoded.length);
3810825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville
3820825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        for (int i = 0; i < septets.length; i++) {
3830825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville            assertEquals(septets[i], reEncoded[i + 1]);
3840825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        }
3850825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville    }
3860825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville
3870825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville    private static final int GSM_ESCAPE_CHARACTER = 0x1b;
3880825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville
3890825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville    private static final String[] sExtendedTables = {
3900825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        // GSM 7 bit default alphabet extension table
3910825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        "\f^{}\\[~]|\u20ac",
3920825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville
3930825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        // Turkish single shift extension table
3940825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        "\f^{}\\[~]|\u011e\u0130\u015e\u00e7\u20ac\u011f\u0131\u015f",
3950825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville
3960825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        // Spanish single shift extension table
3970825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        "\u00e7\f^{}\\[~]|\u00c1\u00cd\u00d3\u00da\u00e1\u20ac\u00ed\u00f3\u00fa",
3980825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville
3990825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        // Portuguese single shift extension table
4000825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        "\u00ea\u00e7\f\u00d4\u00f4\u00c1\u00e1\u03a6\u0393^\u03a9\u03a0\u03a8\u03a3\u0398\u00ca"
4010825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville            + "{}\\[~]|\u00c0\u00cd\u00d3\u00da\u00c3\u00d5\u00c2\u20ac\u00ed\u00f3\u00fa\u00e3"
4020825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville            + "\u00f5\u00e2"
4030825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville    };
4040825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville
4050825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville    private static final int[][] sExtendedTableIndexes = {
4060825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        {0x0a, 0x14, 0x28, 0x29, 0x2f, 0x3c, 0x3d, 0x3e, 0x40, 0x65},
4070825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        {0x0a, 0x14, 0x28, 0x29, 0x2f, 0x3c, 0x3d, 0x3e, 0x40, 0x47, 0x49, 0x53, 0x63,
4080825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville                0x65, 0x67, 0x69, 0x73},
4090825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        {0x09, 0x0a, 0x14, 0x28, 0x29, 0x2f, 0x3c, 0x3d, 0x3e, 0x40, 0x41, 0x49, 0x4f,
4100825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville                0x55, 0x61, 0x65, 0x69, 0x6f, 0x75},
4110825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        {0x05, 0x09, 0x0a, 0x0b, 0x0c, 0x0e, 0x0f, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17,
4120825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville                0x18, 0x19, 0x1f, 0x28, 0x29, 0x2f, 0x3c, 0x3d, 0x3e, 0x40, 0x41, 0x49,
4130825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville                0x4f, 0x55, 0x5b, 0x5c, 0x61, 0x65, 0x69, 0x6f, 0x75, 0x7b, 0x7c, 0x7f}
4140825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville    };
4150825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville
4160825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville    @SmallTest
4170825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville    public void testDecodeExtended() throws Exception {
4180825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        for (int language = 0; language < 3; language++) {
4190825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville            int[] tableIndex = sExtendedTableIndexes[language];
4200825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville            int numSeptets = tableIndex.length * 2;  // two septets per extended char
4210825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville            byte[] septets = new byte[(7 * numSeptets + 7) / 8];
4220825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville
4230825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville            int bitOffset = 0;
4240825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville
4250825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville            for (int v : tableIndex) {
4260825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville                // escape character
4270825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville                int byteOffset = bitOffset / 8;
4280825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville                int shift = bitOffset % 8;
4290825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville
4300825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville                septets[byteOffset] |= GSM_ESCAPE_CHARACTER << shift;
4310825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville
4320825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville                if (shift > 1) {
4330825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville                    septets[byteOffset + 1] = (byte) (GSM_ESCAPE_CHARACTER >> (8 - shift));
4340825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville                }
4350825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville
4360825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville                bitOffset += 7;
4370825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville
4380825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville                // extended table index
4390825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville                byteOffset = bitOffset / 8;
4400825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville                shift = bitOffset % 8;
4410825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville
4420825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville                septets[byteOffset] |= v << shift;
4430825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville
4440825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville                if (shift > 1) {
4450825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville                    septets[byteOffset + 1] = (byte) (v >> (8 - shift));
4460825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville                }
4470825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville
4480825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville                bitOffset += 7;
4490825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville            }
4500825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville
4510825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville            String decoded = GsmAlphabet.gsm7BitPackedToString(septets, 0, numSeptets, 0,
4520825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville                    0, language);
4530825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville            byte[] reEncoded = GsmAlphabet.stringToGsm7BitPacked(decoded, 0, language);
4540825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville
4550825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville            assertEquals(sExtendedTables[language], decoded);
4560825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville
4570825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville            // reEncoded has the count septets byte at the front
4580825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville            assertEquals(septets.length + 1, reEncoded.length);
4590825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville
4600825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville            for (int i = 0; i < septets.length; i++) {
4610825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville                assertEquals(septets[i], reEncoded[i + 1]);
4620825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville            }
4630825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        }
4640825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville    }
4650825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville
4660825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville    @SmallTest
4670825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville    public void testDecodeExtendedFallback() throws Exception {
4680825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        // verify that unmapped characters in extension table fall back to locking shift table
4690825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        for (int language = 0; language < 3; language++) {
4700825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville            int[] tableIndex = sExtendedTableIndexes[language];
4710825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville            int numChars = 128 - tableIndex.length;
4720825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville            int numSeptets = numChars * 2;  // two septets per extended char
4730825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville            byte[] septets = new byte[(7 * numSeptets + 7) / 8];
4740825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville
4750825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville            int tableOffset = 0;
4760825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville            int bitOffset = 0;
4770825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville
4780825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville            StringBuilder defaultTable = new StringBuilder(128);
4790825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville            StringBuilder turkishTable = new StringBuilder(128);
4800825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville            StringBuilder portugueseTable = new StringBuilder(128);
4810825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville
4820825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville            for (char c = 0; c < 128; c++) {
4830825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville                // skip characters that are present in the current extension table
4840825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville                if (tableOffset < tableIndex.length && tableIndex[tableOffset] == c) {
4850825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville                    tableOffset++;
4860825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville                    continue;
4870825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville                }
4880825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville
4890825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville                // escape character
4900825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville                int byteOffset = bitOffset / 8;
4910825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville                int shift = bitOffset % 8;
4920825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville
4930825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville                septets[byteOffset] |= GSM_ESCAPE_CHARACTER << shift;
4940825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville
4950825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville                if (shift > 1) {
4960825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville                    septets[byteOffset + 1] = (byte) (GSM_ESCAPE_CHARACTER >> (8 - shift));
4970825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville                }
4980825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville
4990825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville                bitOffset += 7;
5000825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville
5010825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville                // extended table index
5020825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville                byteOffset = bitOffset / 8;
5030825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville                shift = bitOffset % 8;
5040825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville
5050825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville                septets[byteOffset] |= c << shift;
5060825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville
5070825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville                if (shift > 1) {
5080825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville                    septets[byteOffset + 1] = (byte) (c >> (8 - shift));
5090825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville                }
5100825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville
5110825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville                bitOffset += 7;
5120825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville
5130825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville                if (c == GsmAlphabet.GSM_EXTENDED_ESCAPE) {
5140825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville                    // double Escape maps to space character
5150825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville                    defaultTable.append(' ');
5160825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville                    turkishTable.append(' ');
5170825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville                    portugueseTable.append(' ');
5180825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville                } else {
5190825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville                    // other unmapped chars map to the default or locking shift table
5200825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville                    defaultTable.append(sBasicTables[0].charAt(c));
5210825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville                    turkishTable.append(sBasicTables[1].charAt(c));
5220825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville                    portugueseTable.append(sBasicTables[3].charAt(c));
5230825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville                }
5240825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville            }
5250825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville
5260825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville            String decoded = GsmAlphabet.gsm7BitPackedToString(septets, 0, numSeptets, 0,
5270825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville                    0, language);
5280825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville
5290825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville            assertEquals(defaultTable.toString(), decoded);
5300825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville
5310825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville            decoded = GsmAlphabet.gsm7BitPackedToString(septets, 0, numSeptets, 0, 1, language);
5320825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville            assertEquals(turkishTable.toString(), decoded);
5330825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville
5340825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville            decoded = GsmAlphabet.gsm7BitPackedToString(septets, 0, numSeptets, 0, 3, language);
5350825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville            assertEquals(portugueseTable.toString(), decoded);
5360825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        }
5370825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville    }
5380825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville}
539