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

Commit f1c01bd6 authored by Erik Zivkovic's avatar Erik Zivkovic Committed by Steve Kondik
Browse files

Support for KSC5601 on SIM.

Korean phones write to the ADN record of the SIM in a non-standard way.
When UCS2 is not used, the alphaTag will be written in the KSC5601
encoding. This contribution adds support for reading that format when
a Korean SIM card is used.

Also adds support for KSC5601 in SMS.

Change-Id: I81a4a6949359b4d23a937ac2d813bafed2b85ff6
parent 8d4ba365
Loading
Loading
Loading
Loading
+1 −1
Original line number Diff line number Diff line
@@ -283,7 +283,7 @@ public class AdnRecord implements Parcelable {
    private void
    parseRecord(byte[] record) {
        try {
            alphaTag = IccUtils.adnStringFieldToString(
            alphaTag = IccUtils.adnStringFieldToStringKsc5601Support(
                            record, 0, record.length - FOOTER_SIZE_BYTES);

            int footerOffset = record.length - FOOTER_SIZE_BYTES;
+46 −0
Original line number Diff line number Diff line
@@ -150,6 +150,47 @@ public class IccUtils {
     */
    public static String
    adnStringFieldToString(byte[] data, int offset, int length) {
        String s = adnStringFieldToStringUcs2Helper(data, offset, length);
        if (s == null) {
            s = adnStringFieldToStringGsm8BitHelper(data, offset, length);
        }
        return s;
    }

    /**
     * Almost identical to the method {@link #adnStringFieldToString}.
     *
     * Exception:
     * If the SIM is Korean (MCC equals "450"), KSC5601 encoding will be
     * assumed (instead of GSM8Bit). This could lead to unintended consequences,
     * if the ADN alphaTag was saved with GSM8Bit. This is considered an
     * acceptable risk.
     */
    public static String
    adnStringFieldToStringKsc5601Support(byte[] data, int offset, int length) {
        String s = adnStringFieldToStringUcs2Helper(data, offset, length);

        if (s == null) {
            if (SimRegionCache.getRegion() == SimRegionCache.MCC_KOREAN) {
                try {
                    int len = offset;
                    byte stop = (byte)0xFF;
                    while (len < length && data[len] != stop) {
                        len++;
                    }
                    return new String(data, offset, len, "KSC5601");
                } catch (UnsupportedEncodingException e) {
                    Log.e(LOG_TAG, "implausible UnsupportedEncodingException", e);
                }
            }

            return adnStringFieldToStringGsm8BitHelper(data, offset, length);
        }
        return s;
    }

    private static String
    adnStringFieldToStringUcs2Helper(byte[] data, int offset, int length) {
        if (length >= 1) {
            if (data[offset] == (byte) 0x80) {
                int ucslen = (length - 1) / 2;
@@ -225,6 +266,11 @@ public class IccUtils {
            return ret.toString();
        }

        return null;
    }

    private static String
    adnStringFieldToStringGsm8BitHelper(byte[] data, int offset, int length) {
        return GsmAlphabet.gsm8BitUnpackedToString(data, offset, length);
    }

+51 −0
Original line number Diff line number Diff line
/*
 * Copyright (C) 2010 The Android Open Source Project
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package com.android.internal.telephony;

import android.os.SystemProperties;

public class SimRegionCache {
    public static final int MCC_UNSET  = Integer.MIN_VALUE;
    public static final int MCC_KOREAN = 450;

    private static int regionFromMcc = MCC_UNSET;

    /**
     * Returns the region as read from the MCC of the SIM card.
     * If the property {@link TelephonyProperties#
     * PROPERTY_ICC_OPERATOR_NUMERIC}
     * returns null or an empty String, the value is {@link #MCC_UNSET}
     *
     * @return the cached region, if set.
     */
    public static int getRegion() {
        if (regionFromMcc == MCC_UNSET) {
            String plmn = SystemProperties.get(
                    TelephonyProperties.PROPERTY_ICC_OPERATOR_NUMERIC,
                    null);

            if (plmn != null && plmn.length() >= 3) {
                try {
                    regionFromMcc = Integer.parseInt(plmn.substring(0, 3));
                } catch(Exception e) {
                    // Nothing that can be done here.
                }
            }
        }
        return regionFromMcc;
    }
}
+37 −0
Original line number Diff line number Diff line
@@ -24,6 +24,7 @@ import android.util.Log;
import com.android.internal.telephony.IccUtils;
import com.android.internal.telephony.EncodeException;
import com.android.internal.telephony.GsmAlphabet;
import com.android.internal.telephony.SimRegionCache;
import com.android.internal.telephony.SmsHeader;
import com.android.internal.telephony.SmsMessageBase;
import com.android.internal.telephony.SmsMessageBase.TextEncodingDetails;
@@ -48,6 +49,12 @@ import static android.telephony.SmsMessage.MessageClass;
public class SmsMessage extends SmsMessageBase{
    static final String LOG_TAG = "GSM";

    /**
     * Used with the ENCODING_ constants from {@link android.telephony.SmsMessage}
     * Not a part of the public API, therefore not in order with those constants.
     */
    private static final int ENCODING_KSC5601 = 4000;

    private MessageClass messageClass;

    /**
@@ -781,6 +788,28 @@ public class SmsMessage extends SmsMessageBase{
            return ret;
        }

        /**
         * Interprets the user data payload as KSC5601 characters, and
         * decodes them into a String
         *
         * @param byteCount the number of bytes in the user data payload
         * @return a String with the decoded characters
         */
        String getUserDataKSC5601(int byteCount) {
            String ret;

            try {
                ret = new String(pdu, cur, byteCount, "KSC5601");
            } catch (UnsupportedEncodingException ex) {
                // Should return same as ENCODING_UNKNOWN on error.
                ret = null;
                Log.e(LOG_TAG, "implausible UnsupportedEncodingException", ex);
            }

            cur += byteCount;
            return ret;
        }

        boolean moreDataPresent() {
            return (pdu.length > cur);
        }
@@ -1110,6 +1139,10 @@ public class SmsMessage extends SmsMessageBase{
        } else {
            Log.w(LOG_TAG, "3 - Unsupported SMS data coding scheme "
                    + (dataCodingScheme & 0xff));
            if (SimRegionCache.getRegion() == SimRegionCache.MCC_KOREAN) {
                Log.w(LOG_TAG, "Korean SIM, using KSC5601 for decoding.");
                encodingType = ENCODING_KSC5601;
            }
        }

        // set both the user data and the user data header.
@@ -1131,6 +1164,10 @@ public class SmsMessage extends SmsMessageBase{
        case ENCODING_16BIT:
            messageBody = p.getUserDataUCS2(count);
            break;

        case ENCODING_KSC5601:
            messageBody = p.getUserDataKSC5601(count);
            break;
        }

        if (Config.LOGV) Log.v(LOG_TAG, "SMS message body (raw): '" + messageBody + "'");
+12 −0
Original line number Diff line number Diff line
@@ -170,6 +170,18 @@ public class AdnRecordTest extends TestCase {
        assertEquals("Adgjm", adn.getAlphaTag());
        assertEquals("+18885551212,12345678", adn.getNumber());
        assertFalse(adn.isEmpty());

        //
        // Test that a ADN record with KSC5601 will get converted correctly
        // This test will only be run when using a Korean SIM
        //
        if (SimRegionCache.getRegion() == SimRegionCache.MCC_KOREAN) {
            adn = new AdnRecord(IccUtils.hexStringToBytes(
                  "3030312C20C8AB41B1E6FFFFFFFFFFFF07811010325476F8FFFFFFFFFFFF"));
            assertEquals("001, \uD64DA\uAE38", adn.getAlphaTag());
            assertEquals("01012345678", adn.getNumber());
            assertFalse(adn.isEmpty());
        }
    }
}

Loading