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

Commit 1424fe00 authored by Tammo Spalink's avatar Tammo Spalink
Browse files

added non-numeric cdma sms address support

parent c0ecdf15
Loading
Loading
Loading
Loading
+7 −33
Original line number Diff line number Diff line
@@ -584,38 +584,6 @@ public class SmsMessage extends SmsMessageBase {
        }
    }

    private static CdmaSmsAddress parseCdmaSmsAddr(String addrStr) {
        // see C.S0015-B, v2.0, 3.4.3.3
        CdmaSmsAddress addr = new CdmaSmsAddress();
        addr.digitMode = CdmaSmsAddress.DIGIT_MODE_4BIT_DTMF;
        try {
            addr.origBytes = addrStr.getBytes("UTF-8");
            for (int index = 0; index < addr.origBytes.length; index++) {
                if (addr.origBytes[index] >= '0' && addr.origBytes[index] <= '9') {
                    if (addr.origBytes[index] == '0') {
                        addr.origBytes[index] = 10;
                    } else {
                        addr.origBytes[index] -= '0';
                    }
                } else if (addr.origBytes[index] == '*') {
                    addr.origBytes[index] = 11;
                } else if (addr.origBytes[index] == '#') {
                    addr.origBytes[index] = 12;
                } else {
                    return null;
                }
            }
        } catch  (java.io.UnsupportedEncodingException ex) {
            Log.e(LOG_TAG, "CDMA address parsing failed: " + ex);
            return null;
        }
        addr.numberOfDigits = (byte)addr.origBytes.length;
        addr.numberMode = CdmaSmsAddress.NUMBER_MODE_NOT_DATA_NETWORK;
        addr.numberPlan = CdmaSmsAddress.NUMBERING_PLAN_ISDN_TELEPHONY;
        addr.ton = CdmaSmsAddress.TON_UNKNOWN;
        return addr;
    }

    /**
     * Set the nextMessageId to a random value between 0 and 65536
     * See C.S0015-B, v2.0, 4.3.1.5
@@ -642,7 +610,13 @@ public class SmsMessage extends SmsMessageBase {
         * TODO(cleanup): give this function a more meaningful name.
         */

        CdmaSmsAddress destAddr = parseCdmaSmsAddr(destAddrStr);
        /**
         * TODO(cleanup): Make returning null from the getSubmitPdu
         * variations meaningful -- clean up the error feedback
         * mechanism, and avoid null pointer exceptions.
         */

        CdmaSmsAddress destAddr = CdmaSmsAddress.parse(destAddrStr);
        if (destAddr == null) return null;

        BearerData bearerData = new BearerData();
+6 −0
Original line number Diff line number Diff line
@@ -624,6 +624,12 @@ public final class BearerData {
        return rawData;
    }

    /*
     * TODO(cleanup): CdmaSmsAddress encoding should make use of
     * CdmaSmsAddress.parse provided that DTMF encoding is unified,
     * and the difference in 4bit vs 8bit is resolved.
     */

    private static void encodeCdmaSmsAddress(CdmaSmsAddress addr) throws CodingException {
        if (addr.digitMode == CdmaSmsAddress.DIGIT_MODE_8BIT_CHAR) {
            try {
+123 −2
Original line number Diff line number Diff line
@@ -16,7 +16,10 @@

package com.android.internal.telephony.cdma.sms;

import android.util.SparseBooleanArray;

import com.android.internal.telephony.SmsAddress;
import com.android.internal.telephony.cdma.sms.UserData;
import com.android.internal.util.HexDump;

public class CdmaSmsAddress extends SmsAddress {
@@ -43,7 +46,8 @@ public class CdmaSmsAddress extends SmsAddress {

    /**
     * Number Types for data networks.
     * (See 3GPP2 C.S0015-B, v2, 3.4.3.3)
     * (See 3GPP2 C.S005-D, table2.7.1.3.2.4-2 for complete table)
     * (See 3GPP2 C.S0015-B, v2, 3.4.3.3 for data network subset)
     * NOTE: value is stored in the parent class ton field.
     */
    static public final int TON_UNKNOWN                   = 0x00;
@@ -98,10 +102,127 @@ public class CdmaSmsAddress extends SmsAddress {
        builder.append(", numberPlan=" + numberPlan);
        builder.append(", numberOfDigits=" + numberOfDigits);
        builder.append(", ton=" + ton);
        builder.append(", address=" + address);
        builder.append(", address=\"" + address + "\"");
        builder.append(", origBytes=" + HexDump.toHexString(origBytes));
        builder.append(" }");
        return builder.toString();
    }

    /*
     * TODO(cleanup): Refactor the parsing for addresses to better
     * share code and logic with GSM.  Also, gather all DTMF/BCD
     * processing code in one place.
     */

    private static byte[] parseToDtmf(String address) {
        int digits = address.length();
        byte[] result = new byte[digits];
        for (int i = 0; i < digits; i++) {
            char c = address.charAt(i);
            int val = 0;
            if ((c >= '1') && (c <= '9')) val = c - '0';
            else if (c == '0') val = 10;
            else if (c == '*') val = 11;
            else if (c == '#') val = 12;
            else return null;
            result[i] = (byte)val;
        }
        return result;
    }

    private static final char[] numericCharsDialable = {
        '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', '*', '#'
    };

    private static final char[] numericCharsSugar = {
        '(', ')', ' ', '-', '+'
    };

    private static final SparseBooleanArray numericCharDialableMap = new SparseBooleanArray (
            numericCharsDialable.length + numericCharsSugar.length);
    static {
        for (int i = 0; i < numericCharsDialable.length; i++) {
            numericCharDialableMap.put(numericCharsDialable[i], true);
        }
        for (int i = 0; i < numericCharsSugar.length; i++) {
            numericCharDialableMap.put(numericCharsSugar[i], false);
        }
    }

    /**
     * Given a numeric address string, return the string without
     * syntactic sugar, meaning parens, spaces, hyphens/minuses, or
     * plus signs.  If the input string contains non-numeric
     * non-punctuation characters, return null.
     */
    private static String filterNumericSugar(String address) {
        StringBuilder builder = new StringBuilder();
        int len = address.length();
        for (int i = 0; i < len; i++) {
            char c = address.charAt(i);
            int mapIndex = numericCharDialableMap.indexOfKey(c);
            if (mapIndex < 0) return null;
            if (! numericCharDialableMap.valueAt(mapIndex)) continue;
            builder.append(c);
        }
        return builder.toString();
    }

    /**
     * Given a string, return the string without whitespace,
     * including CR/LF.
     */
    private static String filterWhitespace(String address) {
        StringBuilder builder = new StringBuilder();
        int len = address.length();
        for (int i = 0; i < len; i++) {
            char c = address.charAt(i);
            if ((c == ' ') || (c == '\r') || (c == '\n') || (c == '\t')) continue;
            builder.append(c);
        }
        return builder.toString();
    }

    /**
     * Given a string, create a corresponding CdmaSmsAddress object.
     *
     * The result will be null if the input string is not
     * representable using printable ASCII.
     *
     * For numeric addresses, the string is cleaned up by removing
     * common punctuation.  For alpha addresses, the string is cleaned
     * up by removing whitespace.
     */
    public static CdmaSmsAddress parse(String address) {
        CdmaSmsAddress addr = new CdmaSmsAddress();
        addr.address = address;
        addr.ton = CdmaSmsAddress.TON_UNKNOWN;
        byte[] origBytes = null;
        String filteredAddr = filterNumericSugar(address);
        if (filteredAddr != null) {
            origBytes = parseToDtmf(filteredAddr);
        }
        if (origBytes != null) {
            addr.digitMode = DIGIT_MODE_4BIT_DTMF;
            addr.numberMode = NUMBER_MODE_NOT_DATA_NETWORK;
            if (address.indexOf('+') != -1) {
                addr.ton = TON_INTERNATIONAL_OR_IP;
            }
        } else {
            filteredAddr = filterWhitespace(address);
            origBytes = UserData.stringToAscii(filteredAddr);
            if (origBytes == null) {
                return null;
            }
            addr.digitMode = DIGIT_MODE_8BIT_CHAR;
            addr.numberMode = NUMBER_MODE_DATA_NETWORK;
            if (address.indexOf('@') != -1) {
                addr.ton = TON_NATIONAL_OR_EMAIL;
            }
        }
        addr.origBytes = origBytes;
        addr.numberOfDigits = origBytes.length;
        return addr;
    }

}
+20 −0
Original line number Diff line number Diff line
@@ -92,6 +92,26 @@ public class UserData {
        charToAscii.put('\n', ASCII_CR_INDEX);
    }

    /*
     * TODO(cleanup): Move this very generic functionality somewhere
     * more general.
     */
    /**
     * Given a string generate a corresponding ASCII-encoded byte
     * array, but limited to printable characters.  If the input
     * contains unprintable characters, return null.
     */
    public static byte[] stringToAscii(String str) {
        int len = str.length();
        byte[] result = new byte[len];
        for (int i = 0; i < len; i++) {
            int charCode = charToAscii.get(str.charAt(i), -1);
            if (charCode == -1) return null;
            result[i] = (byte)charCode;
        }
        return result;
    }

    /**
     * Mapping for IA5 values less than 32 are flow control signals
     * and not used here.
+61 −0
Original line number Diff line number Diff line
@@ -37,6 +37,67 @@ import android.util.Log;
public class CdmaSmsTest extends AndroidTestCase {
    private final static String LOG_TAG = "CDMA";

    @SmallTest
    public void testCdmaSmsAddrParsing() throws Exception {
        CdmaSmsAddress addr = CdmaSmsAddress.parse("6502531000");
        assertEquals(addr.ton, CdmaSmsAddress.TON_UNKNOWN);
        assertEquals(addr.digitMode, CdmaSmsAddress.DIGIT_MODE_4BIT_DTMF);
        assertEquals(addr.numberMode, CdmaSmsAddress.NUMBER_MODE_NOT_DATA_NETWORK);
        assertEquals(addr.numberOfDigits, 10);
        assertEquals(addr.origBytes.length, 10);
        byte[] data = {6, 5, 10, 2, 5, 3, 1, 10, 10, 10};
        for (int i = 0; i < data.length; i++) {
            assertEquals(addr.origBytes[i], data[i]);
        }
        addr = CdmaSmsAddress.parse("(650) 253-1000");
        assertEquals(addr.ton, CdmaSmsAddress.TON_UNKNOWN);
        assertEquals(addr.digitMode, CdmaSmsAddress.DIGIT_MODE_4BIT_DTMF);
        assertEquals(addr.numberMode, CdmaSmsAddress.NUMBER_MODE_NOT_DATA_NETWORK);
        assertEquals(addr.numberOfDigits, 10);
        assertEquals(addr.origBytes.length, 10);
        byte[] data2 = {6, 5, 10, 2, 5, 3, 1, 10, 10, 10};
        for (int i = 0; i < data2.length; i++) {
            assertEquals(addr.origBytes[i], data2[i]);
        }
        addr = CdmaSmsAddress.parse("(+886) 917 222 555");
        assertEquals(addr.ton, CdmaSmsAddress.TON_INTERNATIONAL_OR_IP);
        assertEquals(addr.digitMode, CdmaSmsAddress.DIGIT_MODE_4BIT_DTMF);
        assertEquals(addr.numberMode, CdmaSmsAddress.NUMBER_MODE_NOT_DATA_NETWORK);
        assertEquals(addr.numberOfDigits, 12);
        assertEquals(addr.origBytes.length, 12);
        byte[] data3 = {8, 8, 6, 9, 1, 7, 2, 2, 2, 5, 5, 5};
        for (int i = 0; i < data3.length; i++) {
            assertEquals(addr.origBytes[i], data3[i]);
        }
        addr = CdmaSmsAddress.parse("(650) *253-1000 #600");
        byte[] data4 = {6, 5, 10, 11, 2, 5, 3, 1, 10, 10, 10, 12, 6, 10, 10};
        for (int i = 0; i < data4.length; i++) {
            assertEquals(addr.origBytes[i], data4[i]);
        }
        String input = "x@y.com,a@b.com";
        addr = CdmaSmsAddress.parse(input);
        assertEquals(addr.ton, CdmaSmsAddress.TON_NATIONAL_OR_EMAIL);
        assertEquals(addr.digitMode, CdmaSmsAddress.DIGIT_MODE_8BIT_CHAR);
        assertEquals(addr.numberMode, CdmaSmsAddress.NUMBER_MODE_DATA_NETWORK);
        assertEquals(addr.numberOfDigits, 15);
        assertEquals(addr.origBytes.length, 15);
        assertEquals(new String(addr.origBytes), input);
        addr = CdmaSmsAddress.parse("foo bar");
        assertEquals(addr.ton, CdmaSmsAddress.TON_UNKNOWN);
        assertEquals(addr.digitMode, CdmaSmsAddress.DIGIT_MODE_8BIT_CHAR);
        assertEquals(addr.numberMode, CdmaSmsAddress.NUMBER_MODE_DATA_NETWORK);
        assertEquals(addr.numberOfDigits, 6);
        assertEquals(addr.origBytes.length, 6);
        assertEquals(new String(addr.origBytes), "foobar");
        addr = CdmaSmsAddress.parse("f\noo\tb   a\rr");
        assertEquals(new String(addr.origBytes), "foobar");
        assertEquals(CdmaSmsAddress.parse("f\u0000oo bar"), null);
        assertEquals(CdmaSmsAddress.parse("f\u0007oo bar"), null);
        assertEquals(CdmaSmsAddress.parse("f\u0080oo bar"), null);
        assertEquals(CdmaSmsAddress.parse("f\u1ECFboo\u001fbar"), null);
        assertEquals(CdmaSmsAddress.parse("f\u0080oo bar"), null);
    }

    @SmallTest
    public void testUserData7bitGsm() throws Exception {
        String pdu = "00031040900112488ea794e074d69e1b7392c270326cde9e98";