OSDN Git Service

Use CSIM to get provision information
authorKazuhiro Ondo <kazuhiro.ondo@motorola.com>
Wed, 1 Jun 2011 05:38:42 +0000 (00:38 -0500)
committerWink Saville <wink@google.com>
Wed, 8 Jun 2011 19:59:22 +0000 (12:59 -0700)
In case of LTE & CDMA hybrid system, provision information will be
read from CSIM records.

Also CSIM records can be updated over the air. No data connection
attempt should be made until CSIM provisioning is notified
via SIM_REFRESH event.

Change-Id: I001db48d07d90af22104cb958df638e15e0d494a

telephony/java/com/android/internal/telephony/IccConstants.java
telephony/java/com/android/internal/telephony/IccRecords.java
telephony/java/com/android/internal/telephony/IccUtils.java
telephony/java/com/android/internal/telephony/cdma/CdmaLteServiceStateTracker.java
telephony/java/com/android/internal/telephony/cdma/CdmaLteUiccFileHandler.java
telephony/java/com/android/internal/telephony/cdma/CdmaLteUiccRecords.java
telephony/java/com/android/internal/telephony/cdma/CdmaServiceStateTracker.java
telephony/java/com/android/internal/telephony/gsm/GsmDataConnectionTracker.java

index cafc79b..1ba6dfe 100644 (file)
@@ -63,6 +63,10 @@ public interface IccConstants {
     // 3GPP2 C.S0065
     static final int EF_CSIM_LI = 0x6F3A;
     static final int EF_CSIM_SPN =0x6F41;
+    static final int EF_CSIM_MDN = 0x6F44;
+    static final int EF_CSIM_IMSIM = 0x6F22;
+    static final int EF_CSIM_CDMAHOME = 0x6F28;
+    static final int EF_CSIM_EPRL = 0x6F5A;
 
     //ISIM access
     static final int EF_IMPU = 0x6f04;
index 10a3b69..3a27901 100644 (file)
@@ -288,6 +288,16 @@ public abstract class IccRecords extends Handler implements IccConstants {
     }
 
     /**
+     * Indicates wether SIM is in provisioned state or not.
+     * Overridden only if SIM can be dynamically provisioned via OTA.
+     *
+     * @return true if provisioned
+     */
+    public boolean isProvisioned () {
+        return true;
+    }
+
+    /**
      * Write string to log file
      *
      * @param s is the string to write
index df579b0..8e60e6e 100644 (file)
@@ -63,6 +63,29 @@ public class IccUtils {
         return ret.toString();
     }
 
+    /**
+     * Decode cdma byte into String.
+     */
+    public static String
+    cdmaBcdToString(byte[] data, int offset, int length) {
+        StringBuilder ret = new StringBuilder(length);
+
+        int count = 0;
+        for (int i = offset; count < length; i++) {
+            int v;
+            v = data[i] & 0xf;
+            if (v > 9)  v = 0;
+            ret.append((char)('0' + v));
+
+            if (++count == length) break;
+
+            v = (data[i] >> 4) & 0xf;
+            if (v > 9)  v = 0;
+            ret.append((char)('0' + v));
+            ++count;
+        }
+        return ret.toString();
+    }
 
     /**
      * Decodes a GSM-style BCD byte, returning an int ranging from 0-99.
index faae622..318cf37 100644 (file)
@@ -67,11 +67,24 @@ public class CdmaLteServiceStateTracker extends CdmaServiceStateTracker {
         case EVENT_SIM_READY:
             if (DBG) log("handleMessage EVENT_SIM_READY");
             isSubscriptionFromRuim = false;
-            cm.getCDMASubscription( obtainMessage(EVENT_POLL_STATE_CDMA_SUBSCRIPTION));
+            // Register SIM_RECORDS_LOADED dynamically.
+            // This is to avoid confilct with RUIM_READY scenario)
+            phone.mIccRecords.registerForRecordsLoaded(this, EVENT_SIM_RECORDS_LOADED, null);
             pollState();
             // Signal strength polling stops when radio is off.
             queueNextSignalStrengthPoll();
             break;
+        case EVENT_SIM_RECORDS_LOADED:
+            CdmaLteUiccRecords sim = (CdmaLteUiccRecords)phone.mIccRecords;
+            if ((sim != null) && sim.isProvisioned()) {
+                mMdn = sim.getMdn();
+                mMin = sim.getMin();
+                parseSidNid(sim.getSid(), sim.getNid());
+                mPrlVersion = sim.getPrlVersion();;
+                mIsMinInfoReady = true;
+                updateOtaspState();
+            }
+            break;
         default:
             super.handleMessage(msg);
         }
index 2aede29..b9d7c46 100644 (file)
@@ -19,6 +19,7 @@ package com.android.internal.telephony.cdma;
 import android.util.Log;
 import com.android.internal.telephony.IccConstants;
 import com.android.internal.telephony.IccFileHandler;
+import android.os.Message;
 
 /**
  * {@hide}
@@ -34,6 +35,10 @@ public final class CdmaLteUiccFileHandler extends IccFileHandler {
         switch(efid) {
         case EF_CSIM_SPN:
         case EF_CSIM_LI:
+        case EF_CSIM_MDN:
+        case EF_CSIM_IMSIM:
+        case EF_CSIM_CDMAHOME:
+        case EF_CSIM_EPRL:
             return MF_SIM + DF_CDMA;
         case EF_AD:
             return MF_SIM + DF_GSM;
@@ -41,6 +46,21 @@ public final class CdmaLteUiccFileHandler extends IccFileHandler {
         return getCommonIccEFPath(efid);
     }
 
+    @Override
+    public void loadEFTransparent(int fileid, Message onLoaded) {
+        if (fileid == EF_CSIM_EPRL) {
+            // Entire PRL could be huge. We are only interested in
+            // the first 4 bytes of the record.
+            phone.mCM.iccIO(COMMAND_READ_BINARY, fileid, getEFPath(fileid),
+                            0, 0, 4, null, null,
+                            obtainMessage(EVENT_READ_BINARY_DONE,
+                                          fileid, 0, onLoaded));
+        } else {
+            super.loadEFTransparent(fileid, onLoaded);
+        }
+    }
+
+
     protected void logd(String msg) {
         Log.d(LOG_TAG, "[CdmaLteUiccFileHandler] " + msg);
     }
index 78879d6..ac77f9a 100755 (executable)
@@ -26,7 +26,8 @@ import android.os.AsyncResult;
 import android.os.Message;
 import android.os.SystemProperties;
 import android.util.Log;
-
+import java.util.Locale;
+import java.util.ArrayList;
 
 /**
  * {@hide}
@@ -36,10 +37,19 @@ public final class CdmaLteUiccRecords extends SIMRecords {
     private byte[] mEFpl = null;
     private byte[] mEFli = null;
     boolean csimSpnDisplayCondition = false;
+    private String mMdn;
+    private String mMin;
+    private String mPrlVersion;
+    private String mHomeSystemId;
+    private String mHomeNetworkId;
 
     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;
+    private static final int EVENT_GET_CSIM_MDN_DONE = CSIM_EVENT_BASE + 3;
+    private static final int EVENT_GET_CSIM_IMSIM_DONE = CSIM_EVENT_BASE + 4;
+    private static final int EVENT_GET_CSIM_CDMAHOME_DONE = CSIM_EVENT_BASE + 5;
+    private static final int EVENT_GET_CSIM_EPRL_DONE = CSIM_EVENT_BASE + 6;
 
     public CdmaLteUiccRecords(PhoneBase p) {
         super(p);
@@ -109,6 +119,46 @@ public final class CdmaLteUiccRecords extends SIMRecords {
                 }
                 onGetCSimSpnDone(ar);
                 break;
+            case EVENT_GET_CSIM_MDN_DONE:
+                if (DBG) log("EVENT_GET_CSIM_MDN_DONE");
+                isCsimRecordLoadResponse = true;
+                ar = (AsyncResult) msg.obj;
+                if (ar.exception != null) {
+                    Log.e(LOG_TAG, "ar.exception=" + ar.exception);
+                    break;
+                }
+                onGetCSimMdnDone(ar);
+                break;
+            case EVENT_GET_CSIM_IMSIM_DONE:
+                if (DBG) log("EVENT_GET_CSIM_IMSIM_DONE");
+                isCsimRecordLoadResponse = true;
+                ar = (AsyncResult) msg.obj;
+                if (ar.exception != null) {
+                    Log.e(LOG_TAG, "ar.exception=" + ar.exception);
+                    break;
+                }
+                onGetCSimImsimDone(ar);
+                break;
+            case EVENT_GET_CSIM_CDMAHOME_DONE:
+                if (DBG) log("EVENT_GET_CSIM_CDMAHOME_DONE");
+                isCsimRecordLoadResponse = true;
+                ar = (AsyncResult) msg.obj;
+                if (ar.exception != null) {
+                    Log.e(LOG_TAG, "ar.exception=" + ar.exception);
+                    break;
+                }
+                onGetCSimCdmaHomeDone(ar);
+                break;
+            case EVENT_GET_CSIM_EPRL_DONE:
+                if (DBG) log("EVENT_GET_CSIM_EPRL_DONE");
+                isCsimRecordLoadResponse = true;
+                ar = (AsyncResult) msg.obj;
+                if (ar.exception != null) {
+                    Log.e(LOG_TAG, "ar.exception=" + ar.exception);
+                    break;
+                }
+                onGetCSimEprlDone(ar);
+                break;
             default:
                 super.handleMessage(msg);
         }}catch (RuntimeException exc) {
@@ -156,6 +206,19 @@ public final class CdmaLteUiccRecords extends SIMRecords {
 
         iccFh.loadEFTransparent(EF_CSIM_SPN, obtainMessage(EVENT_GET_CSIM_SPN_DONE));
         recordsToLoad++;
+
+        iccFh.loadEFLinearFixed(EF_CSIM_MDN, 1, obtainMessage(EVENT_GET_CSIM_MDN_DONE));
+        recordsToLoad++;
+
+        iccFh.loadEFTransparent(EF_CSIM_IMSIM, obtainMessage(EVENT_GET_CSIM_IMSIM_DONE));
+        recordsToLoad++;
+
+        iccFh.loadEFLinearFixedAll(EF_CSIM_CDMAHOME,
+                                   obtainMessage(EVENT_GET_CSIM_CDMAHOME_DONE));
+        recordsToLoad++;
+
+        iccFh.loadEFTransparent(EF_CSIM_EPRL, obtainMessage(EVENT_GET_CSIM_EPRL_DONE));
+        recordsToLoad++;
     }
 
     private void onGetCSimSpnDone(AsyncResult ar) {
@@ -205,6 +268,93 @@ public final class CdmaLteUiccRecords extends SIMRecords {
         phone.setSystemProperty(PROPERTY_ICC_OPERATOR_ALPHA, spn);
     }
 
+    private void onGetCSimMdnDone(AsyncResult ar) {
+        byte[] data = (byte[]) ar.result;
+        if (DBG) log("CSIM_MDN=" + IccUtils.bytesToHexString(data));
+        int mdnDigitsNum = 0x0F & data[0];
+        mMdn = IccUtils.cdmaBcdToString(data, 1, mdnDigitsNum);
+        if (DBG) log("CSIM MDN=" + mMdn);
+    }
+
+    private void onGetCSimImsimDone(AsyncResult ar) {
+        byte[] data = (byte[]) ar.result;
+        if (DBG) log("CSIM_IMSIM=" + IccUtils.bytesToHexString(data));
+        // C.S0065 section 5.2.2 for IMSI_M encoding
+        // C.S0005 section 2.3.1 for MIN encoding in IMSI_M.
+        boolean provisioned = ((data[7] & 0x80) == 0x80);
+
+        if (provisioned) {
+            int first3digits = ((0x03 & data[2]) << 8) + (0xFF & data[1]);
+            int second3digits = (((0xFF & data[5]) << 8) | (0xFF & data[4])) >> 6;
+            int digit7 = 0x0F & (data[4] >> 2);
+            if (digit7 > 0x09) digit7 = 0;
+            int last3digits = ((0x03 & data[4]) << 8) | (0xFF & data[3]);
+            first3digits = adjstMinDigits(first3digits);
+            second3digits = adjstMinDigits(second3digits);
+            last3digits = adjstMinDigits(last3digits);
+
+            StringBuilder builder = new StringBuilder();
+            builder.append(String.format(Locale.US, "%03d", first3digits));
+            builder.append(String.format(Locale.US, "%03d", second3digits));
+            builder.append(String.format(Locale.US, "%d", digit7));
+            builder.append(String.format(Locale.US, "%03d", last3digits));
+            if (DBG) log("min present=" + builder.toString());
+
+            mMin = builder.toString();
+        } else {
+            if (DBG) log("min not present");
+        }
+    }
+
+    private int adjstMinDigits (int digits) {
+        // Per C.S0005 section 2.3.1.
+        digits += 111;
+        digits = (digits % 10 == 0)?(digits - 10):digits;
+        digits = ((digits / 10) % 10 == 0)?(digits - 100):digits;
+        digits = ((digits / 100) % 10 == 0)?(digits - 1000):digits;
+        return digits;
+    }
+
+    private void onGetCSimCdmaHomeDone(AsyncResult ar) {
+        // Per C.S0065 section 5.2.8
+        ArrayList<byte[]> dataList = (ArrayList<byte[]>) ar.result;
+        if (DBG) log("CSIM_CDMAHOME data size=" + dataList.size());
+        if (dataList.isEmpty()) {
+            return;
+        }
+        StringBuilder sidBuf = new StringBuilder();
+        StringBuilder nidBuf = new StringBuilder();
+
+        for (byte[] data : dataList) {
+            if (data.length == 5) {
+                int sid = ((data[1] & 0xFF) << 8) | (data[0] & 0xFF);
+                int nid = ((data[3] & 0xFF) << 8) | (data[2] & 0xFF);
+                sidBuf.append(sid).append(",");
+                nidBuf.append(nid).append(",");
+            }
+        }
+        // remove trailing ","
+        sidBuf.setLength(sidBuf.length()-1);
+        nidBuf.setLength(nidBuf.length()-1);
+
+        mHomeSystemId = sidBuf.toString();
+        mHomeNetworkId = nidBuf.toString();
+    }
+
+    private void onGetCSimEprlDone(AsyncResult ar) {
+        // C.S0065 section 5.2.57 for EFeprl encoding
+        // C.S0016 section 3.5.5 for PRL format.
+        byte[] data = (byte[]) ar.result;
+        if (DBG) log("CSIM_EPRL=" + IccUtils.bytesToHexString(data));
+
+        // Only need the first 4 bytes of record
+        if (data.length > 3) {
+            int prlId = ((data[2] & 0xFF) << 8) | (data[3] & 0xFF);
+            mPrlVersion = Integer.toString(prlId);
+        }
+        if (DBG) log("CSIM PRL version=" + mPrlVersion);
+    }
+
     public byte[] getPreferredLanguage() {
         return mEFpl;
     }
@@ -212,4 +362,32 @@ public final class CdmaLteUiccRecords extends SIMRecords {
     public byte[] getLanguageIndication() {
         return mEFli;
     }
+
+    public String getMdn() {
+        return mMdn;
+    }
+
+    public String getMin() {
+        return mMin;
+    }
+
+    public String getSid() {
+        return mHomeSystemId;
+    }
+
+    public String getNid() {
+        return mHomeNetworkId;
+    }
+
+    public String getPrlVersion() {
+        return mPrlVersion;
+    }
+
+    @Override
+    public boolean isProvisioned() {
+        // Look for MDN and MIN field to determine if the SIM is provisioned.
+        if ((mMdn != null) && (mMin != null)) return true;
+
+        return false;
+    }
 }
index 805ee49..5ebdd22 100755 (executable)
@@ -129,12 +129,12 @@ public class CdmaServiceStateTracker extends ServiceStateTracker {
     /** Contains the name of the registered network in CDMA (either ONS or ERI text). */
     private String curPlmn = null;
 
-    private String mMdn;
+    protected String mMdn;
     private int mHomeSystemId[] = null;
     private int mHomeNetworkId[] = null;
-    private String mMin;
-    private String mPrlVersion;
-    private boolean mIsMinInfoReady = false;
+    protected String mMin;
+    protected String mPrlVersion;
+    protected boolean mIsMinInfoReady = false;
 
     private boolean isEriTextLoaded = false;
     protected boolean isSubscriptionFromRuim = false;
@@ -373,53 +373,15 @@ public class CdmaServiceStateTracker extends ServiceStateTracker {
                 String cdmaSubscription[] = (String[])ar.result;
                 if (cdmaSubscription != null && cdmaSubscription.length >= 5) {
                     mMdn = cdmaSubscription[0];
-                    if (cdmaSubscription[1] != null) {
-                        String[] sid = cdmaSubscription[1].split(",");
-                        mHomeSystemId = new int[sid.length];
-                        for (int i = 0; i < sid.length; i++) {
-                            try {
-                                mHomeSystemId[i] = Integer.parseInt(sid[i]);
-                            } catch (NumberFormatException ex) {
-                                loge("error parsing system id: " + ex);
-                            }
-                        }
-                    }
-                    if (DBG) log("GET_CDMA_SUBSCRIPTION: SID=" + cdmaSubscription[1] );
-
-                    if (cdmaSubscription[2] != null) {
-                        String[] nid = cdmaSubscription[2].split(",");
-                        mHomeNetworkId = new int[nid.length];
-                        for (int i = 0; i < nid.length; i++) {
-                            try {
-                                mHomeNetworkId[i] = Integer.parseInt(nid[i]);
-                            } catch (NumberFormatException ex) {
-                                loge("GET_CDMA_SUBSCRIPTION: error parsing network id: " + ex);
-                            }
-                        }
-                    }
-                    if (DBG) log("GET_CDMA_SUBSCRIPTION: NID=" + cdmaSubscription[2]);
+                    parseSidNid(cdmaSubscription[1], cdmaSubscription[2]);
+
                     mMin = cdmaSubscription[3];
                     mPrlVersion = cdmaSubscription[4];
                     if (DBG) log("GET_CDMA_SUBSCRIPTION: MDN=" + mMdn);
 
                     mIsMinInfoReady = true;
 
-                    int otaspMode = getOtasp();
-                    int oldOtaspMode = mCurrentOtaspMode;
-                    mCurrentOtaspMode = otaspMode;
-
-                    // Notify apps subscription info is ready
-                    if (cdmaForSubscriptionInfoReadyRegistrants != null) {
-                        if (DBG) log("GET_CDMA_SUBSCRIPTION: call notifyRegistrants()");
-                        cdmaForSubscriptionInfoReadyRegistrants.notifyRegistrants();
-                    }
-                    if (oldOtaspMode != mCurrentOtaspMode) {
-                        if (DBG) {
-                            log("GET_CDMA_SUBSCRIPTION: call notifyOtaspChanged old otaspMode=" +
-                                oldOtaspMode + " new otaspMode=" + mCurrentOtaspMode);
-                        }
-                        phone.notifyOtaspChanged(mCurrentOtaspMode);
-                    }
+                    updateOtaspState();
                     phone.getIccCard().broadcastIccStateChangedIntent(IccCard.INTENT_VALUE_ICC_IMSI,
                             null);
                 } else {
@@ -1622,6 +1584,53 @@ public class CdmaServiceStateTracker extends ServiceStateTracker {
         cm.setRadioPower(false, null);
     }
 
+    protected void parseSidNid (String sidStr, String nidStr) {
+        if (sidStr != null) {
+            String[] sid = sidStr.split(",");
+            mHomeSystemId = new int[sid.length];
+            for (int i = 0; i < sid.length; i++) {
+                try {
+                    mHomeSystemId[i] = Integer.parseInt(sid[i]);
+                } catch (NumberFormatException ex) {
+                    loge("error parsing system id: " + ex);
+                }
+            }
+        }
+        if (DBG) log("CDMA_SUBSCRIPTION: SID=" + sidStr);
+
+        if (nidStr != null) {
+            String[] nid = nidStr.split(",");
+            mHomeNetworkId = new int[nid.length];
+            for (int i = 0; i < nid.length; i++) {
+                try {
+                    mHomeNetworkId[i] = Integer.parseInt(nid[i]);
+                } catch (NumberFormatException ex) {
+                    loge("CDMA_SUBSCRIPTION: error parsing network id: " + ex);
+                }
+            }
+        }
+        if (DBG) log("CDMA_SUBSCRIPTION: NID=" + nidStr);
+    }
+
+    protected void updateOtaspState() {
+        int otaspMode = getOtasp();
+        int oldOtaspMode = mCurrentOtaspMode;
+        mCurrentOtaspMode = otaspMode;
+
+        // Notify apps subscription info is ready
+        if (cdmaForSubscriptionInfoReadyRegistrants != null) {
+            if (DBG) log("CDMA_SUBSCRIPTION: call notifyRegistrants()");
+            cdmaForSubscriptionInfoReadyRegistrants.notifyRegistrants();
+        }
+        if (oldOtaspMode != mCurrentOtaspMode) {
+            if (DBG) {
+                log("CDMA_SUBSCRIPTION: call notifyOtaspChanged old otaspMode=" +
+                    oldOtaspMode + " new otaspMode=" + mCurrentOtaspMode);
+            }
+            phone.notifyOtaspChanged(mCurrentOtaspMode);
+        }
+    }
+
     @Override
     protected void log(String s) {
         Log.d(LOG_TAG, "[CdmaSST] " + s);
index db2b490..dcde71a 100644 (file)
@@ -561,6 +561,7 @@ public final class GsmDataConnectionTracker extends DataConnectionTracker {
         boolean allowed =
                     (gprsState == ServiceState.STATE_IN_SERVICE || mAutoAttachOnCreation) &&
                     mPhone.mIccRecords.getRecordsLoaded() &&
+                    mPhone.mIccRecords.isProvisioned() &&
                     mPhone.getState() == Phone.State.IDLE &&
                     mInternalDataEnabled &&
                     (!mPhone.getServiceState().getRoaming() || getDataOnRoamingEnabled()) &&
@@ -572,6 +573,7 @@ public final class GsmDataConnectionTracker extends DataConnectionTracker {
                 reason += " - gprs= " + gprsState;
             }
             if (!mPhone.mIccRecords.getRecordsLoaded()) reason += " - SIM not loaded";
+            if (!mPhone.mIccRecords.isProvisioned()) reason += " - SIM not provisioned";
             if (mPhone.getState() != Phone.State.IDLE) {
                 reason += " - PhoneState= " + mPhone.getState();
             }