Merge "Read CSIM records in LTE on CDMA mode" into honeycomb-LTE
diff --git a/telephony/java/com/android/internal/telephony/IccConstants.java b/telephony/java/com/android/internal/telephony/IccConstants.java
index b40f945..cafc79b 100644
--- a/telephony/java/com/android/internal/telephony/IccConstants.java
+++ b/telephony/java/com/android/internal/telephony/IccConstants.java
@@ -58,6 +58,12 @@
     static final int EF_CST = 0x6f32;
     static final int EF_RUIM_SPN =0x6F41;
 
+    // ETSI TS.102.221
+    static final int EF_PL = 0x2F05;
+    // 3GPP2 C.S0065
+    static final int EF_CSIM_LI = 0x6F3A;
+    static final int EF_CSIM_SPN =0x6F41;
+
     //ISIM access
     static final int EF_IMPU = 0x6f04;
     static final int EF_IMPI = 0x6f02;
diff --git a/telephony/java/com/android/internal/telephony/IccFileHandler.java b/telephony/java/com/android/internal/telephony/IccFileHandler.java
index 92ddd2c..93b9b79 100644
--- a/telephony/java/com/android/internal/telephony/IccFileHandler.java
+++ b/telephony/java/com/android/internal/telephony/IccFileHandler.java
@@ -529,6 +529,7 @@
             return MF_SIM + DF_TELECOM;
 
         case EF_ICCID:
+        case EF_PL:
             return MF_SIM;
         case EF_IMG:
             return MF_SIM + DF_TELECOM + DF_GRAPHICS;
diff --git a/telephony/java/com/android/internal/telephony/cdma/CDMALTEPhone.java b/telephony/java/com/android/internal/telephony/cdma/CDMALTEPhone.java
index 5733164..fe2fcb2 100644
--- a/telephony/java/com/android/internal/telephony/cdma/CDMALTEPhone.java
+++ b/telephony/java/com/android/internal/telephony/cdma/CDMALTEPhone.java
@@ -58,8 +58,9 @@
     @Override
     protected void initSstIcc() {
         mSST = new CdmaLteServiceStateTracker(this);
-        mIccRecords = new SIMRecords(this);
+        mIccRecords = new CdmaLteUiccRecords(this);
         mIccCard = new SimCard(this, LOG_TAG, DBG);
+        mIccFileHandler = new CdmaLteUiccFileHandler(this);
     }
 
     @Override
diff --git a/telephony/java/com/android/internal/telephony/cdma/CDMAPhone.java b/telephony/java/com/android/internal/telephony/cdma/CDMAPhone.java
index c85f7d8..a283062 100755
--- a/telephony/java/com/android/internal/telephony/cdma/CDMAPhone.java
+++ b/telephony/java/com/android/internal/telephony/cdma/CDMAPhone.java
@@ -156,13 +156,13 @@
         mSST = new CdmaServiceStateTracker(this);
         mIccRecords = new RuimRecords(this);
         mIccCard = new RuimCard(this, LOG_TAG, DBG);
+        mIccFileHandler = new RuimFileHandler(this);
     }
 
     protected void init(Context context, PhoneNotifier notifier) {
         mCM.setPhoneType(Phone.PHONE_TYPE_CDMA);
         mCT = new CdmaCallTracker(this);
         mSMS = new CdmaSMSDispatcher(this);
-        mIccFileHandler = new RuimFileHandler(this);
         mDataConnectionTracker = new CdmaDataConnectionTracker (this);
         mRuimPhoneBookInterfaceManager = new RuimPhoneBookInterfaceManager(this);
         mRuimSmsInterfaceManager = new RuimSmsInterfaceManager(this, mSMS);
diff --git a/telephony/java/com/android/internal/telephony/cdma/CdmaLteUiccFileHandler.java b/telephony/java/com/android/internal/telephony/cdma/CdmaLteUiccFileHandler.java
new file mode 100644
index 0000000..2aede29
--- /dev/null
+++ b/telephony/java/com/android/internal/telephony/cdma/CdmaLteUiccFileHandler.java
@@ -0,0 +1,52 @@
+/*
+ * Copyright (C) 2011 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.cdma;
+
+import android.util.Log;
+import com.android.internal.telephony.IccConstants;
+import com.android.internal.telephony.IccFileHandler;
+
+/**
+ * {@hide}
+ */
+public final class CdmaLteUiccFileHandler extends IccFileHandler {
+    static final String LOG_TAG = "CDMA";
+
+    CdmaLteUiccFileHandler(CDMALTEPhone phone) {
+        super(phone);
+    }
+
+    protected String getEFPath(int efid) {
+        switch(efid) {
+        case EF_CSIM_SPN:
+        case EF_CSIM_LI:
+            return MF_SIM + DF_CDMA;
+        case EF_AD:
+            return MF_SIM + DF_GSM;
+        }
+        return getCommonIccEFPath(efid);
+    }
+
+    protected void logd(String msg) {
+        Log.d(LOG_TAG, "[CdmaLteUiccFileHandler] " + msg);
+    }
+
+    protected void loge(String msg) {
+        Log.e(LOG_TAG, "[CdmaLteUiccFileHandler] " + msg);
+    }
+
+}
diff --git a/telephony/java/com/android/internal/telephony/cdma/CdmaLteUiccRecords.java b/telephony/java/com/android/internal/telephony/cdma/CdmaLteUiccRecords.java
new file mode 100755
index 0000000..78879d6
--- /dev/null
+++ b/telephony/java/com/android/internal/telephony/cdma/CdmaLteUiccRecords.java
@@ -0,0 +1,215 @@
+/*
+ * Copyright (C) 2011 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.cdma;
+
+import static com.android.internal.telephony.TelephonyProperties.PROPERTY_ICC_OPERATOR_ALPHA;
+import com.android.internal.telephony.GsmAlphabet;
+import com.android.internal.telephony.IccFileHandler;
+import com.android.internal.telephony.IccUtils;
+import com.android.internal.telephony.PhoneBase;
+import com.android.internal.telephony.cdma.sms.UserData;
+import com.android.internal.telephony.gsm.SIMRecords;
+import android.os.AsyncResult;
+import android.os.Message;
+import android.os.SystemProperties;
+import android.util.Log;
+
+
+/**
+ * {@hide}
+ */
+public final class CdmaLteUiccRecords extends SIMRecords {
+    // From CSIM application
+    private byte[] mEFpl = null;
+    private byte[] mEFli = null;
+    boolean csimSpnDisplayCondition = false;
+
+    private static final int EVENT_GET_PL_DONE = CSIM_EVENT_BASE;
+    private static final int EVENT_GET_CSIM_LI_DONE = CSIM_EVENT_BASE + 1;
+    private static final int EVENT_GET_CSIM_SPN_DONE = CSIM_EVENT_BASE + 2;
+
+    public CdmaLteUiccRecords(PhoneBase p) {
+        super(p);
+    }
+
+    @Override
+    public void handleMessage(Message msg) {
+        AsyncResult ar;
+        byte data[];
+
+        boolean isCsimRecordLoadResponse = false;
+
+        try { switch (msg.what) {
+            case EVENT_GET_PL_DONE:
+                // Refer to ETSI TS.102.221
+                if (DBG) log("EF_GET_EF_PL_DONE");
+                isCsimRecordLoadResponse = true;
+
+                ar = (AsyncResult) msg.obj;
+
+                if (ar.exception != null) {
+                    Log.e(LOG_TAG, "ar.exception = " + ar.exception);
+                    break;
+                }
+
+                mEFpl = (byte[]) ar.result;
+                if (DBG) log("EF_PL=" + IccUtils.bytesToHexString(mEFpl));
+                break;
+
+            case EVENT_GET_CSIM_LI_DONE:
+                // Refer to C.S0065 5.2.26
+                if (DBG) log("EVENT_GET_CSIM_LI_DONE");
+                isCsimRecordLoadResponse = true;
+
+                ar = (AsyncResult) msg.obj;
+                if (ar.exception != null) {
+                    Log.e(LOG_TAG, "ar.exception = " + ar.exception);
+                    break;
+                }
+
+                mEFli = (byte[]) ar.result;
+                // convert csim efli data to iso 639 format
+                for (int i = 0; i < mEFli.length; i+=2) {
+                    switch(mEFli[i+1]) {
+                    case 0x01: mEFli[i] = 'e'; mEFli[i+1] = 'n';break;
+                    case 0x02: mEFli[i] = 'f'; mEFli[i+1] = 'r';break;
+                    case 0x03: mEFli[i] = 'e'; mEFli[i+1] = 's';break;
+                    case 0x04: mEFli[i] = 'j'; mEFli[i+1] = 'a';break;
+                    case 0x05: mEFli[i] = 'k'; mEFli[i+1] = 'o';break;
+                    case 0x06: mEFli[i] = 'z'; mEFli[i+1] = 'h';break;
+                    case 0x07: mEFli[i] = 'h'; mEFli[i+1] = 'e';break;
+                    default: mEFli[i] = ' '; mEFli[i+1] = ' ';
+                    }
+                }
+
+                if (DBG) log("EF_LI=" + IccUtils.bytesToHexString(mEFli));
+                break;
+            case EVENT_GET_CSIM_SPN_DONE:
+                // Refer to C.S0065 5.2.32
+                if (DBG) log("EVENT_GET_CSIM_SPN_DONE");
+                isCsimRecordLoadResponse = true;
+                ar = (AsyncResult) msg.obj;
+
+                if (ar.exception != null) {
+                    Log.e(LOG_TAG, "ar.exception=" + ar.exception);
+                    break;
+                }
+                onGetCSimSpnDone(ar);
+                break;
+            default:
+                super.handleMessage(msg);
+        }}catch (RuntimeException exc) {
+            Log.w(LOG_TAG, "Exception parsing SIM record", exc);
+        } finally {
+            if (isCsimRecordLoadResponse) {
+                onRecordLoaded();
+            }
+        }
+    }
+
+    @Override
+    protected void onRecordLoaded() {
+        // One record loaded successfully or failed, In either case
+        // we need to update the recordsToLoad count
+        recordsToLoad -= 1;
+
+        if (recordsToLoad == 0 && recordsRequested == true) {
+            onAllRecordsLoaded();
+        } else if (recordsToLoad < 0) {
+            Log.e(LOG_TAG, "SIMRecords: recordsToLoad <0, programmer error suspected");
+            recordsToLoad = 0;
+        }
+    }
+
+    @Override
+    protected void fetchSimRecords() {
+        IccFileHandler iccFh = phone.getIccFileHandler();
+        recordsRequested = true;
+
+        phone.mCM.getIMSI(obtainMessage(EVENT_GET_IMSI_DONE));
+        recordsToLoad++;
+
+        iccFh.loadEFTransparent(EF_ICCID, obtainMessage(EVENT_GET_ICCID_DONE));
+        recordsToLoad++;
+
+        iccFh.loadEFTransparent(EF_AD, obtainMessage(EVENT_GET_AD_DONE));
+        recordsToLoad++;
+
+        iccFh.loadEFTransparent(EF_PL, obtainMessage(EVENT_GET_PL_DONE));
+        recordsToLoad++;
+
+        iccFh.loadEFTransparent(EF_CSIM_LI, obtainMessage(EVENT_GET_CSIM_LI_DONE));
+        recordsToLoad++;
+
+        iccFh.loadEFTransparent(EF_CSIM_SPN, obtainMessage(EVENT_GET_CSIM_SPN_DONE));
+        recordsToLoad++;
+    }
+
+    private void onGetCSimSpnDone(AsyncResult ar) {
+        byte[] data = (byte[]) ar.result;
+        if (DBG) log("CSIM_SPN=" +
+                     IccUtils.bytesToHexString(data));
+
+        // C.S0065 for EF_SPN decoding
+        csimSpnDisplayCondition = ((0x02 & data[0]) > 0)?true:false;
+
+        int encoding = data[1];
+        int language = data[2];
+        byte[] spnData = new byte[32];
+        System.arraycopy(data, 3, spnData, 0, (data.length < 32)?data.length:32);
+
+        int numBytes;
+        for (numBytes = 0; numBytes < spnData.length; numBytes++) {
+            if ((spnData[numBytes] & 0xFF) == 0xFF) break;
+        }
+
+        if (numBytes == 0) {
+            spn = "";
+            return;
+        }
+        try {
+            switch (encoding) {
+            case UserData.ENCODING_OCTET:
+            case UserData.ENCODING_LATIN:
+                spn = new String(spnData, 0, numBytes, "ISO-8859-1");
+                break;
+            case UserData.ENCODING_IA5:
+            case UserData.ENCODING_GSM_7BIT_ALPHABET:
+            case UserData.ENCODING_7BIT_ASCII:
+                spn = GsmAlphabet.gsm7BitPackedToString(spnData, 0, (numBytes*8)/7);
+                break;
+            case UserData.ENCODING_UNICODE_16:
+                spn =  new String(spnData, 0, numBytes, "utf-16");
+                break;
+            default:
+                log("SPN encoding not supported");
+            }
+        } catch(Exception e) {
+            log("spn decode error: " + e);
+        }
+        if (DBG) log("spn=" + spn);
+        if (DBG) log("spnCondition=" + csimSpnDisplayCondition);
+        phone.setSystemProperty(PROPERTY_ICC_OPERATOR_ALPHA, spn);
+    }
+
+    public byte[] getPreferredLanguage() {
+        return mEFpl;
+    }
+
+    public byte[] getLanguageIndication() {
+        return mEFli;
+    }
+}
diff --git a/telephony/java/com/android/internal/telephony/gsm/SIMRecords.java b/telephony/java/com/android/internal/telephony/gsm/SIMRecords.java
index 4cd9440..b0bad56 100755
--- a/telephony/java/com/android/internal/telephony/gsm/SIMRecords.java
+++ b/telephony/java/com/android/internal/telephony/gsm/SIMRecords.java
@@ -45,12 +45,12 @@
 /**
  * {@hide}
  */
-public final class SIMRecords extends IccRecords {
-    static final String LOG_TAG = "GSM";
+public class SIMRecords extends IccRecords {
+    protected static final String LOG_TAG = "GSM";
 
     private static final boolean CRASH_RIL = false;
 
-    private static final boolean DBG = true;
+    protected static final boolean DBG = true;
 
     // ***** Instance Variables
 
@@ -120,13 +120,13 @@
 
     private static final int EVENT_SIM_READY = 1;
     private static final int EVENT_RADIO_OFF_OR_NOT_AVAILABLE = 2;
-    private static final int EVENT_GET_IMSI_DONE = 3;
-    private static final int EVENT_GET_ICCID_DONE = 4;
+    protected static final int EVENT_GET_IMSI_DONE = 3;
+    protected static final int EVENT_GET_ICCID_DONE = 4;
     private static final int EVENT_GET_MBI_DONE = 5;
     private static final int EVENT_GET_MBDN_DONE = 6;
     private static final int EVENT_GET_MWIS_DONE = 7;
     private static final int EVENT_GET_VOICE_MAIL_INDICATOR_CPHS_DONE = 8;
-    private static final int EVENT_GET_AD_DONE = 9; // Admin data on SIM
+    protected static final int EVENT_GET_AD_DONE = 9; // Admin data on SIM
     private static final int EVENT_GET_MSISDN_DONE = 10;
     private static final int EVENT_GET_CPHS_MAILBOX_DONE = 11;
     private static final int EVENT_GET_SPN_DONE = 12;
@@ -147,6 +147,8 @@
     private static final int EVENT_GET_CFIS_DONE = 32;
     private static final int EVENT_GET_CSP_CPHS_DONE = 33;
 
+    protected static final int CSIM_EVENT_BASE = 100;
+
     // Lookup table for carriers known to produce SIMs which incorrectly indicate MNC length.
 
     private static final String[] MCCMNC_CODES_HAVING_3DIGITS_MNC = {
@@ -1285,7 +1287,7 @@
         fetchSimRecords();
     }
 
-    private void fetchSimRecords() {
+    protected void fetchSimRecords() {
         recordsRequested = true;
         IccFileHandler iccFh = phone.getIccFileHandler();