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
This commit is contained in:
Erik Zivkovic
2010-06-16 11:00:29 +02:00
committed by Jean-Baptiste Queru
parent e78a000955
commit aad6f806c5
7 changed files with 192 additions and 1 deletions

View File

@@ -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;

View File

@@ -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);
}

View File

@@ -0,0 +1,51 @@
/*
* 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;
}
}

View File

@@ -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 + "'");