Skip to content

Commit 749c627

Browse files
Jean-Baptiste QueruAndroid Code Review
authored andcommitted
Merge "Support for KSC5601 on SIM."
2 parents e78a000 + aad6f80 commit 749c627

File tree

7 files changed

+192
-1
lines changed

7 files changed

+192
-1
lines changed

telephony/java/com/android/internal/telephony/AdnRecord.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -283,7 +283,7 @@ public byte[] buildAdnString(int recordSize) {
283283
private void
284284
parseRecord(byte[] record) {
285285
try {
286-
alphaTag = IccUtils.adnStringFieldToString(
286+
alphaTag = IccUtils.adnStringFieldToStringKsc5601Support(
287287
record, 0, record.length - FOOTER_SIZE_BYTES);
288288

289289
int footerOffset = record.length - FOOTER_SIZE_BYTES;

telephony/java/com/android/internal/telephony/IccUtils.java

Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -150,6 +150,47 @@ public class IccUtils {
150150
*/
151151
public static String
152152
adnStringFieldToString(byte[] data, int offset, int length) {
153+
String s = adnStringFieldToStringUcs2Helper(data, offset, length);
154+
if (s == null) {
155+
s = adnStringFieldToStringGsm8BitHelper(data, offset, length);
156+
}
157+
return s;
158+
}
159+
160+
/**
161+
* Almost identical to the method {@link #adnStringFieldToString}.
162+
*
163+
* Exception:
164+
* If the SIM is Korean (MCC equals "450"), KSC5601 encoding will be
165+
* assumed (instead of GSM8Bit). This could lead to unintended consequences,
166+
* if the ADN alphaTag was saved with GSM8Bit. This is considered an
167+
* acceptable risk.
168+
*/
169+
public static String
170+
adnStringFieldToStringKsc5601Support(byte[] data, int offset, int length) {
171+
String s = adnStringFieldToStringUcs2Helper(data, offset, length);
172+
173+
if (s == null) {
174+
if (SimRegionCache.getRegion() == SimRegionCache.MCC_KOREAN) {
175+
try {
176+
int len = offset;
177+
byte stop = (byte)0xFF;
178+
while (len < length && data[len] != stop) {
179+
len++;
180+
}
181+
return new String(data, offset, len, "KSC5601");
182+
} catch (UnsupportedEncodingException e) {
183+
Log.e(LOG_TAG, "implausible UnsupportedEncodingException", e);
184+
}
185+
}
186+
187+
return adnStringFieldToStringGsm8BitHelper(data, offset, length);
188+
}
189+
return s;
190+
}
191+
192+
private static String
193+
adnStringFieldToStringUcs2Helper(byte[] data, int offset, int length) {
153194
if (length >= 1) {
154195
if (data[offset] == (byte) 0x80) {
155196
int ucslen = (length - 1) / 2;
@@ -225,6 +266,11 @@ public class IccUtils {
225266
return ret.toString();
226267
}
227268

269+
return null;
270+
}
271+
272+
private static String
273+
adnStringFieldToStringGsm8BitHelper(byte[] data, int offset, int length) {
228274
return GsmAlphabet.gsm8BitUnpackedToString(data, offset, length);
229275
}
230276

Lines changed: 51 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,51 @@
1+
/*
2+
* Copyright (C) 2010 The Android Open Source Project
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* http://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
17+
package com.android.internal.telephony;
18+
19+
import android.os.SystemProperties;
20+
21+
public class SimRegionCache {
22+
public static final int MCC_UNSET = Integer.MIN_VALUE;
23+
public static final int MCC_KOREAN = 450;
24+
25+
private static int regionFromMcc = MCC_UNSET;
26+
27+
/**
28+
* Returns the region as read from the MCC of the SIM card.
29+
* If the property {@link TelephonyProperties#
30+
* PROPERTY_ICC_OPERATOR_NUMERIC}
31+
* returns null or an empty String, the value is {@link #MCC_UNSET}
32+
*
33+
* @return the cached region, if set.
34+
*/
35+
public static int getRegion() {
36+
if (regionFromMcc == MCC_UNSET) {
37+
String plmn = SystemProperties.get(
38+
TelephonyProperties.PROPERTY_ICC_OPERATOR_NUMERIC,
39+
null);
40+
41+
if (plmn != null && plmn.length() >= 3) {
42+
try {
43+
regionFromMcc = Integer.parseInt(plmn.substring(0, 3));
44+
} catch(Exception e) {
45+
// Nothing that can be done here.
46+
}
47+
}
48+
}
49+
return regionFromMcc;
50+
}
51+
}

telephony/java/com/android/internal/telephony/gsm/SmsMessage.java

Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@
2424
import com.android.internal.telephony.IccUtils;
2525
import com.android.internal.telephony.EncodeException;
2626
import com.android.internal.telephony.GsmAlphabet;
27+
import com.android.internal.telephony.SimRegionCache;
2728
import com.android.internal.telephony.SmsHeader;
2829
import com.android.internal.telephony.SmsMessageBase;
2930
import com.android.internal.telephony.SmsMessageBase.TextEncodingDetails;
@@ -48,6 +49,12 @@
4849
public class SmsMessage extends SmsMessageBase{
4950
static final String LOG_TAG = "GSM";
5051

52+
/**
53+
* Used with the ENCODING_ constants from {@link android.telephony.SmsMessage}
54+
* Not a part of the public API, therefore not in order with those constants.
55+
*/
56+
private static final int ENCODING_KSC5601 = 4000;
57+
5158
private MessageClass messageClass;
5259

5360
/**
@@ -781,6 +788,28 @@ String getUserDataUCS2(int byteCount) {
781788
return ret;
782789
}
783790

791+
/**
792+
* Interprets the user data payload as KSC5601 characters, and
793+
* decodes them into a String
794+
*
795+
* @param byteCount the number of bytes in the user data payload
796+
* @return a String with the decoded characters
797+
*/
798+
String getUserDataKSC5601(int byteCount) {
799+
String ret;
800+
801+
try {
802+
ret = new String(pdu, cur, byteCount, "KSC5601");
803+
} catch (UnsupportedEncodingException ex) {
804+
// Should return same as ENCODING_UNKNOWN on error.
805+
ret = null;
806+
Log.e(LOG_TAG, "implausible UnsupportedEncodingException", ex);
807+
}
808+
809+
cur += byteCount;
810+
return ret;
811+
}
812+
784813
boolean moreDataPresent() {
785814
return (pdu.length > cur);
786815
}
@@ -1110,6 +1139,10 @@ private void parseUserData(PduParser p, boolean hasUserDataHeader) {
11101139
} else {
11111140
Log.w(LOG_TAG, "3 - Unsupported SMS data coding scheme "
11121141
+ (dataCodingScheme & 0xff));
1142+
if (SimRegionCache.getRegion() == SimRegionCache.MCC_KOREAN) {
1143+
Log.w(LOG_TAG, "Korean SIM, using KSC5601 for decoding.");
1144+
encodingType = ENCODING_KSC5601;
1145+
}
11131146
}
11141147

11151148
// set both the user data and the user data header.
@@ -1131,6 +1164,10 @@ private void parseUserData(PduParser p, boolean hasUserDataHeader) {
11311164
case ENCODING_16BIT:
11321165
messageBody = p.getUserDataUCS2(count);
11331166
break;
1167+
1168+
case ENCODING_KSC5601:
1169+
messageBody = p.getUserDataKSC5601(count);
1170+
break;
11341171
}
11351172

11361173
if (Config.LOGV) Log.v(LOG_TAG, "SMS message body (raw): '" + messageBody + "'");

telephony/tests/telephonytests/src/com/android/internal/telephony/AdnRecordTest.java

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -170,6 +170,18 @@ public void testBasic() throws Exception {
170170
assertEquals("Adgjm", adn.getAlphaTag());
171171
assertEquals("+18885551212,12345678", adn.getNumber());
172172
assertFalse(adn.isEmpty());
173+
174+
//
175+
// Test that a ADN record with KSC5601 will get converted correctly
176+
// This test will only be run when using a Korean SIM
177+
//
178+
if (SimRegionCache.getRegion() == SimRegionCache.MCC_KOREAN) {
179+
adn = new AdnRecord(IccUtils.hexStringToBytes(
180+
"3030312C20C8AB41B1E6FFFFFFFFFFFF07811010325476F8FFFFFFFFFFFF"));
181+
assertEquals("001, \uD64DA\uAE38", adn.getAlphaTag());
182+
assertEquals("01012345678", adn.getNumber());
183+
assertFalse(adn.isEmpty());
184+
}
173185
}
174186
}
175187

telephony/tests/telephonytests/src/com/android/internal/telephony/SMSDispatcherTest.java

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -102,4 +102,25 @@ public void testEfRecord() throws Exception {
102102
sms = SmsMessage.createFromEfRecord(1, data);
103103
assertNotNull(sms.getMessageBody());
104104
}
105+
106+
@MediumTest
107+
public void testEfRecordKorean() throws Exception {
108+
if (SimRegionCache.getRegion() == SimRegionCache.MCC_KOREAN) {
109+
SmsMessage sms;
110+
111+
String s = "01089128010099010259040ba11000000000f00095013091900563008c4142"
112+
+ "434445b0a1b3aab4d9b6f3b8b631323334354142434445b0a1b3aab4d9b6f3"
113+
+ "b8b631323334354142434445b0a1b3aab4d9b6f3b8b6313233343541424344"
114+
+ "45b0a1b3aab4d9b6f3b8b63132333435000000000000000000000000000000"
115+
+ "00000000000000000000000000000000000000000000000000000000000000"
116+
+ "0000000000000000000000000000ffffffffffffff";
117+
118+
119+
byte[] data = IccUtils.hexStringToBytes(s);
120+
121+
sms = SmsMessage.createFromEfRecord(1, data);
122+
assertNotNull(sms.getMessageBody());
123+
assertTrue(sms.getMessageBody().startsWith("ABCDE\uAC00\uB098\uB2E4\uB77C\uB9C812345ABCDE"));
124+
}
125+
}
105126
}

telephony/tests/telephonytests/src/com/android/internal/telephony/SimUtilsTest.java

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -82,6 +82,30 @@ public void testBasic() throws Exception {
8282
data = IccUtils.hexStringToBytes("820505302D82d32d31");
8383
// Example from 3GPP TS 11.11 V18.1.3.0 annex B
8484
assertEquals("-\u0532\u0583-1", IccUtils.adnStringFieldToString(data, 0, data.length));
85+
86+
/*
87+
* adnStringFieldToStringKsc5601Support()
88+
* Tests equal the ones above, and will only be run if the SIM is NOT korean.
89+
*/
90+
91+
if (SimRegionCache.getRegion() != SimRegionCache.MCC_KOREAN) {
92+
data = IccUtils.hexStringToBytes("00566f696365204d61696c07918150367742f3ffffffffffff");
93+
// Again, skip prepended 0
94+
// (this is an EF[ADN] record)
95+
assertEquals("Voice Mail", IccUtils.adnStringFieldToStringKsc5601Support(data, 1, data.length - 15));
96+
97+
data = IccUtils.hexStringToBytes("809673539A5764002F004DFFFFFFFFFF");
98+
// (this is from an EF[ADN] record)
99+
assertEquals("\u9673\u539A\u5764/M", IccUtils.adnStringFieldToStringKsc5601Support(data, 0, data.length));
100+
101+
data = IccUtils.hexStringToBytes("810A01566fec6365204de0696cFFFFFF");
102+
// (this is made up to test since I don't have a real one)
103+
assertEquals("Vo\u00ECce M\u00E0il", IccUtils.adnStringFieldToStringKsc5601Support(data, 0, data.length));
104+
105+
data = IccUtils.hexStringToBytes("820505302D82d32d31");
106+
// Example from 3GPP TS 11.11 V18.1.3.0 annex B
107+
assertEquals("-\u0532\u0583-1", IccUtils.adnStringFieldToStringKsc5601Support(data, 0, data.length));
108+
}
85109
}
86110

87111
}

0 commit comments

Comments
 (0)