Support MBCS characters in contacts and SMS messages that are stored in SIM cards.

Change-Id: I0438c5748a47512fc2a0e4b89ac85e30e3f5c6de
This commit is contained in:
Sang-il, Lee
2010-08-05 17:07:01 +09:00
committed by Jake Hamby
parent 3e2d81cb73
commit b55df4471e
7 changed files with 144 additions and 3 deletions

View File

@@ -0,0 +1,21 @@
<?xml version="1.0" encoding="utf-8"?>
<!--
/*
** Copyright 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.
*/
-->
<resources>
<string name="gsm_alphabet_default_charset">euc-kr</string>
</resources>

View File

@@ -405,4 +405,8 @@
<!-- IP address of the dns server to use if nobody else suggests one -->
<string name="config_default_dns_server">8.8.8.8</string>
<!-- The default character set for GsmAlphabet -->
<!-- Empty string means MBCS is not considered -->
<string name="gsm_alphabet_default_charset"></string>
</resources>

View File

@@ -53,6 +53,10 @@ public class SmsMessage {
public static final int ENCODING_7BIT = 1;
public static final int ENCODING_8BIT = 2;
public static final int ENCODING_16BIT = 3;
/**
* @hide This value is not defined in global standard. Only in Korea, this is used.
*/
public static final int ENCODING_KSC5601 = 4;
/** The maximum number of payload bytes per message */
public static final int MAX_USER_DATA_BYTES = 140;

View File

@@ -16,10 +16,14 @@
package com.android.internal.telephony;
import android.text.TextUtils;
import android.util.SparseIntArray;
import android.util.Log;
import java.nio.ByteBuffer;
import java.nio.charset.Charset;
/**
* This class implements the character set mapping between
* the GSM SMS 7-bit alphabet specified in TS 23.038 6.2.1
@@ -354,6 +358,32 @@ public class GsmAlphabet {
*/
public static String
gsm8BitUnpackedToString(byte[] data, int offset, int length) {
return gsm8BitUnpackedToString(data, offset, length, "");
}
/**
* Convert a GSM alphabet string that's stored in 8-bit unpacked
* format (as it often appears in SIM records) into a String
*
* Field may be padded with trailing 0xff's. The decode stops
* at the first 0xff encountered.
*
* Additionally, in some country(ex. Korea), there are non-ASCII or MBCS characters.
* If a character set is given, characters in data are treat as MBCS.
*/
public static String
gsm8BitUnpackedToString(byte[] data, int offset, int length, String characterset) {
boolean isMbcs = false;
Charset charset = null;
ByteBuffer mbcsBuffer = null;
if (!TextUtils.isEmpty(characterset)
&& !characterset.equalsIgnoreCase("us-ascii")
&& Charset.isSupported(characterset)) {
isMbcs = true;
charset = Charset.forName(characterset);
mbcsBuffer = ByteBuffer.allocate(2);
}
boolean prevWasEscape;
StringBuilder ret = new StringBuilder(length);
@@ -379,7 +409,15 @@ public class GsmAlphabet {
if (prevWasEscape) {
ret.append((char)gsmExtendedToChar.get(c, ' '));
} else {
ret.append((char)gsmToChar.get(c, ' '));
if (!isMbcs || c < 0x80 || i + 1 >= offset + length) {
ret.append((char)gsmToChar.get(c, ' '));
} else {
// isMbcs must be true. So both mbcsBuffer and charset are initialized.
mbcsBuffer.clear();
mbcsBuffer.put(data, i++, 2);
mbcsBuffer.flip();
ret.append(charset.decode(mbcsBuffer).toString());
}
}
prevWasEscape = false;
}

View File

@@ -16,13 +16,16 @@
package com.android.internal.telephony;
import android.content.res.Resources;
import android.content.res.Resources.NotFoundException;
import android.graphics.Bitmap;
import android.graphics.Color;
import android.util.Log;
import com.android.internal.telephony.GsmAlphabet;
import java.io.UnsupportedEncodingException;
import java.nio.ByteBuffer;
import java.nio.charset.Charset;
/**
* Various methods, useful for dealing with SIM data.
@@ -150,6 +153,9 @@ public class IccUtils {
*/
public static String
adnStringFieldToString(byte[] data, int offset, int length) {
if (length == 0) {
return "";
}
if (length >= 1) {
if (data[offset] == (byte) 0x80) {
int ucslen = (length - 1) / 2;
@@ -225,7 +231,15 @@ public class IccUtils {
return ret.toString();
}
return GsmAlphabet.gsm8BitUnpackedToString(data, offset, length);
Resources resource = Resources.getSystem();
String defaultCharset = "";
try {
defaultCharset =
resource.getString(com.android.internal.R.string.gsm_alphabet_default_charset);
} catch (NotFoundException e) {
// Ignore Exception and defaultCharset is set to a empty string.
}
return GsmAlphabet.gsm8BitUnpackedToString(data, offset, length, defaultCharset.trim());
}
static int

View File

@@ -33,6 +33,7 @@ import java.io.UnsupportedEncodingException;
import static android.telephony.SmsMessage.ENCODING_7BIT;
import static android.telephony.SmsMessage.ENCODING_8BIT;
import static android.telephony.SmsMessage.ENCODING_16BIT;
import static android.telephony.SmsMessage.ENCODING_KSC5601;
import static android.telephony.SmsMessage.ENCODING_UNKNOWN;
import static android.telephony.SmsMessage.MAX_USER_DATA_BYTES;
import static android.telephony.SmsMessage.MAX_USER_DATA_BYTES_WITH_HEADER;
@@ -776,6 +777,27 @@ public class SmsMessage extends SmsMessageBase {
return ret;
}
/**
* Interprets the user data payload as KSC-5601 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) {
ret = "";
Log.e(LOG_TAG, "implausible UnsupportedEncodingException", ex);
}
cur += byteCount;
return ret;
}
boolean moreDataPresent() {
return (pdu.length > cur);
}
@@ -1111,6 +1133,16 @@ public class SmsMessage extends SmsMessageBase {
Log.w(LOG_TAG, "MWI for fax, email, or other "
+ (dataCodingScheme & 0xff));
}
} else if ((dataCodingScheme & 0xC0) == 0x80) {
// 3GPP TS 23.038 V7.0.0 (2006-03) section 4
// 0x80..0xBF == Reserved coding groups
if (dataCodingScheme == 0x84) {
// This value used for KSC5601 by carriers in Korea.
encodingType = ENCODING_KSC5601;
} else {
Log.w(LOG_TAG, "5 - Unsupported SMS data coding scheme "
+ (dataCodingScheme & 0xff));
}
} else {
Log.w(LOG_TAG, "3 - Unsupported SMS data coding scheme "
+ (dataCodingScheme & 0xff));
@@ -1135,6 +1167,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 + "'");

View File

@@ -16,6 +16,8 @@
package com.android.internal.telephony;
import com.android.internal.telephony.GsmAlphabet;
import junit.framework.TestCase;
import android.test.suitebuilder.annotation.LargeTest;
@@ -307,4 +309,26 @@ public class GsmAlphabetTest extends TestCase {
assertEquals("a",
GsmAlphabet.gsm8BitUnpackedToString(unpacked, 1, unpacked.length - 1));
}
@SmallTest
public void testGsm8BitUpackedWithEuckr() throws Exception {
// Some feature phones in Korea store contacts as euc-kr.
// Test this situations.
byte unpacked[];
// Test general alphabet strings.
unpacked = IccUtils.hexStringToBytes("61626320646566FF");
assertEquals("abc def",
GsmAlphabet.gsm8BitUnpackedToString(unpacked, 0, unpacked.length, "euc-kr"));
// Test korean strings.
unpacked = IccUtils.hexStringToBytes("C5D7BDBAC6AEFF");
assertEquals("\uD14C\uC2A4\uD2B8",
GsmAlphabet.gsm8BitUnpackedToString(unpacked, 0, unpacked.length, "euc-kr"));
// Test gsm Extented Characters.
unpacked = GsmAlphabet.stringToGsm8BitPacked(sGsmExtendedChars);
assertEquals(sGsmExtendedChars,
GsmAlphabet.gsm8BitUnpackedToString(unpacked, 0, unpacked.length, "euc-kr"));
}
}