Add ISIM application support for LTE devices.

- Add methods to TelephonyManager to provide access to IMS records on
  the ISIM application of the UICC, as well as access to the ISIM
  AKA authentication algorithm.

- Add support for the new IMS methods to CDMALTEPhone, using the helper class
  ImsUiccRecords to load the IMS records from the ISIM. The same approach
  can be used to implement IMS support for UMTS/LTE devices.

- There is a new RIL request, RIL_REQUEST_ISIM_AUTHENTICATION, which is
  used to perform IMS AKA authentication using the algorithm on the ISIM
  application of the UICC. The challenge nonce and response are both encoded
  as Base64 strings.

Change-Id: I73367c7d9bc573d0d883d68adf09891de1319129
diff --git a/core/res/AndroidManifest.xml b/core/res/AndroidManifest.xml
index 2dbb0b2..540c65a 100644
--- a/core/res/AndroidManifest.xml
+++ b/core/res/AndroidManifest.xml
@@ -582,6 +582,12 @@
         android:label="@string/permlab_readPhoneState"
         android:description="@string/permdesc_readPhoneState" />
 
+    <!-- Allows read access to privileged phone state.
+         @hide Used internally. -->
+    <permission android:name="android.permission.READ_PRIVILEGED_PHONE_STATE"
+        android:permissionGroup="android.permission-group.PHONE_CALLS"
+        android:protectionLevel="signatureOrSystem" />
+
     <!-- ================================== -->
     <!-- Permissions for sdcard interaction -->
     <!-- ================================== -->
diff --git a/telephony/java/android/telephony/TelephonyManager.java b/telephony/java/android/telephony/TelephonyManager.java
index f7e0c66..1954172 100644
--- a/telephony/java/android/telephony/TelephonyManager.java
+++ b/telephony/java/android/telephony/TelephonyManager.java
@@ -832,6 +832,55 @@
         }
     }
 
+    /**
+     * Returns the IMS private user identity (IMPI) that was loaded from the ISIM.
+     * @return the IMPI, or null if not present or not loaded
+     * @hide
+     */
+    public String getIsimImpi() {
+        try {
+            return getSubscriberInfo().getIsimImpi();
+        } catch (RemoteException ex) {
+            return null;
+        } catch (NullPointerException ex) {
+            // This could happen before phone restarts due to crashing
+            return null;
+        }
+    }
+
+    /**
+     * Returns the IMS home network domain name that was loaded from the ISIM.
+     * @return the IMS domain name, or null if not present or not loaded
+     * @hide
+     */
+    public String getIsimDomain() {
+        try {
+            return getSubscriberInfo().getIsimDomain();
+        } catch (RemoteException ex) {
+            return null;
+        } catch (NullPointerException ex) {
+            // This could happen before phone restarts due to crashing
+            return null;
+        }
+    }
+
+    /**
+     * Returns the IMS public user identities (IMPU) that were loaded from the ISIM.
+     * @return an array of IMPU strings, with one IMPU per string, or null if
+     *      not present or not loaded
+     * @hide
+     */
+    public String[] getIsimImpu() {
+        try {
+            return getSubscriberInfo().getIsimImpu();
+        } catch (RemoteException ex) {
+            return null;
+        } catch (NullPointerException ex) {
+            // This could happen before phone restarts due to crashing
+            return null;
+        }
+    }
+
     private IPhoneSubInfo getSubscriberInfo() {
         // get it each time because that process crashes a lot
         return IPhoneSubInfo.Stub.asInterface(ServiceManager.getService("iphonesubinfo"));
diff --git a/telephony/java/com/android/internal/telephony/CommandsInterface.java b/telephony/java/com/android/internal/telephony/CommandsInterface.java
index b68cbe9..1caea70 100644
--- a/telephony/java/com/android/internal/telephony/CommandsInterface.java
+++ b/telephony/java/com/android/internal/telephony/CommandsInterface.java
@@ -1489,11 +1489,8 @@
 
     /**
      * Setup a packet data connection On successful completion, the result
-     * message will return the following: [0] indicating PDP CID, which is
-     * generated by RIL. This Connection ID is used in both GSM/UMTS and CDMA
-     * modes [1] indicating the network interface name for GSM/UMTS or CDMA [2]
-     * indicating the IP address for this interface for GSM/UMTS and NULL in the
-     * case of CDMA
+     * message will return a {@link DataCallState} object containing the connection
+     * information.
      *
      * @param radioTechnology
      *            indicates whether to setup connection on radio technology CDMA
@@ -1569,7 +1566,7 @@
     /**
      * Request the status of the ICC and UICC cards.
      *
-     * @param response
+     * @param result
      *          Callback message containing {@link IccCardStatus} structure for the card.
      */
     public void getIccCardStatus(Message result);
@@ -1583,4 +1580,14 @@
      * or {@link Phone#LTE_ON_CDMA_TRUE}
      */
     public int getLteOnCdmaMode();
+
+    /**
+     * Request the ISIM application on the UICC to perform the AKA
+     * challenge/response algorithm for IMS authentication. The nonce string
+     * and challenge response are Base64 encoded Strings.
+     *
+     * @param nonce the nonce string to pass with the ISIM authentication request
+     * @param response a callback message with the String response in the obj field
+     */
+    public void requestIsimAuthentication(String nonce, Message response);
 }
diff --git a/telephony/java/com/android/internal/telephony/IPhoneSubInfo.aidl b/telephony/java/com/android/internal/telephony/IPhoneSubInfo.aidl
index 5cba2e1..def770f 100644
--- a/telephony/java/com/android/internal/telephony/IPhoneSubInfo.aidl
+++ b/telephony/java/com/android/internal/telephony/IPhoneSubInfo.aidl
@@ -67,4 +67,23 @@
      * Retrieves the alpha identifier associated with the voice mail number.
      */
     String getVoiceMailAlphaTag();
+
+    /**
+     * Returns the IMS private user identity (IMPI) that was loaded from the ISIM.
+     * @return the IMPI, or null if not present or not loaded
+     */
+    String getIsimImpi();
+
+    /**
+     * Returns the IMS home network domain name that was loaded from the ISIM.
+     * @return the IMS domain name, or null if not present or not loaded
+     */
+    String getIsimDomain();
+
+    /**
+     * Returns the IMS public user identities (IMPU) that were loaded from the ISIM.
+     * @return an array of IMPU strings, with one IMPU per string, or null if
+     *      not present or not loaded
+     */
+    String[] getIsimImpu();
 }
diff --git a/telephony/java/com/android/internal/telephony/IccRecords.java b/telephony/java/com/android/internal/telephony/IccRecords.java
index 3a27901..84bfc40 100644
--- a/telephony/java/com/android/internal/telephony/IccRecords.java
+++ b/telephony/java/com/android/internal/telephony/IccRecords.java
@@ -22,6 +22,8 @@
 import android.os.Registrant;
 import android.os.RegistrantList;
 
+import com.android.internal.telephony.ims.IsimRecords;
+
 /**
  * {@hide}
  */
@@ -70,6 +72,24 @@
     // ***** Event Constants
     protected static final int EVENT_SET_MSISDN_DONE = 30;
 
+    public static final int EVENT_GET_ICC_RECORD_DONE = 100;
+
+    /**
+     * Generic ICC record loaded callback. Subclasses can call EF load methods on
+     * {@link IccFileHandler} passing a Message for onLoaded with the what field set to
+     * {@link #EVENT_GET_ICC_RECORD_DONE} and the obj field set to an instance
+     * of this interface. The {@link #handleMessage} method in this class will print a
+     * log message using {@link #getEfName()} and decrement {@link #recordsToLoad}.
+     *
+     * If the record load was successful, {@link #onRecordLoaded} will be called with the result.
+     * Otherwise, an error log message will be output by {@link #handleMessage} and
+     * {@link #onRecordLoaded} will not be called.
+     */
+    public interface IccRecordLoaded {
+        String getEfName();
+        void onRecordLoaded(AsyncResult ar);
+    }
+
     // ***** Constructor
 
     public IccRecords(PhoneBase p) {
@@ -234,7 +254,32 @@
 
     //***** Overridden from Handler
     @Override
-    public abstract void handleMessage(Message msg);
+    public void handleMessage(Message msg) {
+        switch (msg.what) {
+            case EVENT_GET_ICC_RECORD_DONE:
+                try {
+                    AsyncResult ar = (AsyncResult) msg.obj;
+                    IccRecordLoaded recordLoaded = (IccRecordLoaded) ar.userObj;
+                    if (DBG) log(recordLoaded.getEfName() + " LOADED");
+
+                    if (ar.exception != null) {
+                        loge("Record Load Exception: " + ar.exception);
+                    } else {
+                        recordLoaded.onRecordLoaded(ar);
+                    }
+                }catch (RuntimeException exc) {
+                    // I don't want these exceptions to be fatal
+                    loge("Exception parsing SIM record: " + exc);
+                } finally {
+                    // Count up record load responses even if they are fails
+                    onRecordLoaded();
+                }
+                break;
+
+            default:
+                super.handleMessage(msg);
+        }
+    }
 
     protected abstract void onRecordLoaded();
 
@@ -303,4 +348,19 @@
      * @param s is the string to write
      */
     protected abstract void log(String s);
+
+    /**
+     * Write error string to log file.
+     *
+     * @param s is the string to write
+     */
+    protected abstract void loge(String s);
+
+    /**
+     * Return an interface to retrieve the ISIM records for IMS, if available.
+     * @return the interface to retrieve the ISIM records, or null if not supported
+     */
+    public IsimRecords getIsimRecords() {
+        return null;
+    }
 }
diff --git a/telephony/java/com/android/internal/telephony/Phone.java b/telephony/java/com/android/internal/telephony/Phone.java
index 4b02e8e..6347f37 100644
--- a/telephony/java/com/android/internal/telephony/Phone.java
+++ b/telephony/java/com/android/internal/telephony/Phone.java
@@ -28,6 +28,7 @@
 import android.telephony.SignalStrength;
 
 import com.android.internal.telephony.DataConnection;
+import com.android.internal.telephony.ims.IsimRecords;
 import com.android.internal.telephony.test.SimulatedRadioControl;
 
 import java.util.List;
@@ -1730,4 +1731,20 @@
      * false otherwise
      */
     boolean isCspPlmnEnabled();
+
+    /**
+     * Return an interface to retrieve the ISIM records for IMS, if available.
+     * @return the interface to retrieve the ISIM records, or null if not supported
+     */
+    IsimRecords getIsimRecords();
+
+    /**
+     * Request the ISIM application on the UICC to perform the AKA
+     * challenge/response algorithm for IMS authentication. The nonce string
+     * and challenge response are Base64 encoded Strings.
+     *
+     * @param nonce the nonce string to pass with the ISIM authentication request
+     * @param response a callback message with the String response in the obj field
+     */
+    void requestIsimAuthentication(String nonce, Message response);
 }
diff --git a/telephony/java/com/android/internal/telephony/PhoneBase.java b/telephony/java/com/android/internal/telephony/PhoneBase.java
index a0961ca..4f86ea8 100644
--- a/telephony/java/com/android/internal/telephony/PhoneBase.java
+++ b/telephony/java/com/android/internal/telephony/PhoneBase.java
@@ -37,6 +37,7 @@
 import android.util.Log;
 
 import com.android.internal.R;
+import com.android.internal.telephony.ims.IsimRecords;
 import com.android.internal.telephony.test.SimulatedRadioControl;
 import com.android.internal.telephony.gsm.SIMRecords;
 import com.android.internal.telephony.gsm.SimCard;
@@ -1114,6 +1115,15 @@
         return false;
     }
 
+    public IsimRecords getIsimRecords() {
+        Log.e(LOG_TAG, "getIsimRecords() is only supported on LTE devices");
+        return null;
+    }
+
+    public void requestIsimAuthentication(String nonce, Message result) {
+        Log.e(LOG_TAG, "requestIsimAuthentication() is only supported on LTE devices");
+    }
+
     /**
      * Common error logger method for unexpected calls to CDMA-only methods.
      */
diff --git a/telephony/java/com/android/internal/telephony/PhoneProxy.java b/telephony/java/com/android/internal/telephony/PhoneProxy.java
index b5bfc76f..3678017 100644
--- a/telephony/java/com/android/internal/telephony/PhoneProxy.java
+++ b/telephony/java/com/android/internal/telephony/PhoneProxy.java
@@ -32,6 +32,7 @@
 
 import com.android.internal.telephony.cdma.CDMAPhone;
 import com.android.internal.telephony.gsm.GSMPhone;
+import com.android.internal.telephony.ims.IsimRecords;
 import com.android.internal.telephony.test.SimulatedRadioControl;
 
 import java.util.List;
@@ -841,6 +842,14 @@
         return mActivePhone.isCspPlmnEnabled();
     }
 
+    public IsimRecords getIsimRecords() {
+        return mActivePhone.getIsimRecords();
+    }
+
+    public void requestIsimAuthentication(String nonce, Message response) {
+        mActivePhone.requestIsimAuthentication(nonce, response);
+    }
+
     /**
      * {@inheritDoc}
      */
diff --git a/telephony/java/com/android/internal/telephony/PhoneSubInfo.java b/telephony/java/com/android/internal/telephony/PhoneSubInfo.java
index a45cad1..de18d0a 100644
--- a/telephony/java/com/android/internal/telephony/PhoneSubInfo.java
+++ b/telephony/java/com/android/internal/telephony/PhoneSubInfo.java
@@ -24,15 +24,19 @@
 import android.telephony.PhoneNumberUtils;
 import android.util.Log;
 
+import com.android.internal.telephony.ims.IsimRecords;
+
 public class PhoneSubInfo extends IPhoneSubInfo.Stub {
     static final String LOG_TAG = "PHONE";
     private Phone mPhone;
     private Context mContext;
     private static final String READ_PHONE_STATE =
         android.Manifest.permission.READ_PHONE_STATE;
+    // TODO: change getCompleteVoiceMailNumber() to require READ_PRIVILEGED_PHONE_STATE
     private static final String CALL_PRIVILEGED =
-        // TODO Add core/res/AndriodManifest.xml#READ_PRIVILEGED_PHONE_STATE
         android.Manifest.permission.CALL_PRIVILEGED;
+    private static final String READ_PRIVILEGED_PHONE_STATE =
+        android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE;
 
     public PhoneSubInfo(Phone phone) {
         mPhone = phone;
@@ -131,6 +135,52 @@
         return (String) mPhone.getVoiceMailAlphaTag();
     }
 
+    /**
+     * Returns the IMS private user identity (IMPI) that was loaded from the ISIM.
+     * @return the IMPI, or null if not present or not loaded
+     */
+    public String getIsimImpi() {
+        mContext.enforceCallingOrSelfPermission(READ_PRIVILEGED_PHONE_STATE,
+                "Requires READ_PRIVILEGED_PHONE_STATE");
+        IsimRecords isim = mPhone.getIsimRecords();
+        if (isim != null) {
+            return isim.getIsimImpi();
+        } else {
+            return null;
+        }
+    }
+
+    /**
+     * Returns the IMS home network domain name that was loaded from the ISIM.
+     * @return the IMS domain name, or null if not present or not loaded
+     */
+    public String getIsimDomain() {
+        mContext.enforceCallingOrSelfPermission(READ_PRIVILEGED_PHONE_STATE,
+                "Requires READ_PRIVILEGED_PHONE_STATE");
+        IsimRecords isim = mPhone.getIsimRecords();
+        if (isim != null) {
+            return isim.getIsimDomain();
+        } else {
+            return null;
+        }
+    }
+
+    /**
+     * Returns the IMS public user identities (IMPU) that were loaded from the ISIM.
+     * @return an array of IMPU strings, with one IMPU per string, or null if
+     *      not present or not loaded
+     */
+    public String[] getIsimImpu() {
+        mContext.enforceCallingOrSelfPermission(READ_PRIVILEGED_PHONE_STATE,
+                "Requires READ_PRIVILEGED_PHONE_STATE");
+        IsimRecords isim = mPhone.getIsimRecords();
+        if (isim != null) {
+            return isim.getIsimImpu();
+        } else {
+            return null;
+        }
+    }
+
     protected void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
         if (mContext.checkCallingOrSelfPermission(android.Manifest.permission.DUMP)
                 != PackageManager.PERMISSION_GRANTED) {
diff --git a/telephony/java/com/android/internal/telephony/PhoneSubInfoProxy.java b/telephony/java/com/android/internal/telephony/PhoneSubInfoProxy.java
index 7009893..a287b2e 100644
--- a/telephony/java/com/android/internal/telephony/PhoneSubInfoProxy.java
+++ b/telephony/java/com/android/internal/telephony/PhoneSubInfoProxy.java
@@ -95,6 +95,31 @@
         return mPhoneSubInfo.getVoiceMailAlphaTag();
     }
 
+    /**
+     * Returns the IMS private user identity (IMPI) that was loaded from the ISIM.
+     * @return the IMPI, or null if not present or not loaded
+     */
+    public String getIsimImpi() {
+        return mPhoneSubInfo.getIsimImpi();
+    }
+
+    /**
+     * Returns the IMS home network domain name that was loaded from the ISIM.
+     * @return the IMS domain name, or null if not present or not loaded
+     */
+    public String getIsimDomain() {
+        return mPhoneSubInfo.getIsimDomain();
+    }
+
+    /**
+     * Returns the IMS public user identities (IMPU) that were loaded from the ISIM.
+     * @return an array of IMPU strings, with one IMPU per string, or null if
+     *      not present or not loaded
+     */
+    public String[] getIsimImpu() {
+        return mPhoneSubInfo.getIsimImpu();
+    }
+
     protected void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
         mPhoneSubInfo.dump(fd, pw, args);
     }
diff --git a/telephony/java/com/android/internal/telephony/RIL.java b/telephony/java/com/android/internal/telephony/RIL.java
index c6ed405..3e13a86 100644
--- a/telephony/java/com/android/internal/telephony/RIL.java
+++ b/telephony/java/com/android/internal/telephony/RIL.java
@@ -47,17 +47,8 @@
 import android.text.TextUtils;
 import android.util.Log;
 
-import com.android.internal.telephony.CallForwardInfo;
-import com.android.internal.telephony.CommandException;
-import com.android.internal.telephony.DataCallState;
 import com.android.internal.telephony.gsm.SmsBroadcastConfigInfo;
 import com.android.internal.telephony.gsm.SuppServiceNotification;
-import com.android.internal.telephony.IccCardApplication;
-import com.android.internal.telephony.IccCardStatus;
-import com.android.internal.telephony.IccUtils;
-import com.android.internal.telephony.OperatorInfo;
-import com.android.internal.telephony.RILConstants;
-import com.android.internal.telephony.SmsResponse;
 import com.android.internal.telephony.cdma.CdmaCallWaitingNotification;
 import com.android.internal.telephony.cdma.CdmaInformationRecords;
 
@@ -2255,6 +2246,7 @@
             case RIL_REQUEST_REPORT_SMS_MEMORY_STATUS: ret = responseVoid(p); break;
             case RIL_REQUEST_REPORT_STK_SERVICE_IS_RUNNING: ret = responseVoid(p); break;
             case RIL_REQUEST_CDMA_GET_SUBSCRIPTION_SOURCE: ret =  responseInts(p); break;
+            case RIL_REQUEST_ISIM_AUTHENTICATION: ret =  responseString(p); break;
             default:
                 throw new RuntimeException("Unrecognized solicited response: " + rr.mRequest);
             //break;
@@ -3461,6 +3453,7 @@
             case RIL_REQUEST_REPORT_SMS_MEMORY_STATUS: return "RIL_REQUEST_REPORT_SMS_MEMORY_STATUS";
             case RIL_REQUEST_REPORT_STK_SERVICE_IS_RUNNING: return "RIL_REQUEST_REPORT_STK_SERVICE_IS_RUNNING";
             case RIL_REQUEST_CDMA_GET_SUBSCRIPTION_SOURCE: return "RIL_REQUEST_CDMA_GET_SUBSCRIPTION_SOURCE";
+            case RIL_REQUEST_ISIM_AUTHENTICATION: return "RIL_REQUEST_ISIM_AUTHENTICATION";
             default: return "<unknown request>";
         }
     }
@@ -3704,4 +3697,13 @@
         send(rr);
     }
 
+    public void requestIsimAuthentication(String nonce, Message response) {
+        RILRequest rr = RILRequest.obtain(RIL_REQUEST_ISIM_AUTHENTICATION, response);
+
+        rr.mp.writeString(nonce);
+
+        if (RILJ_LOGD) riljLog(rr.serialString() + "> " + requestToString(rr.mRequest));
+
+        send(rr);
+    }
 }
diff --git a/telephony/java/com/android/internal/telephony/RILConstants.java b/telephony/java/com/android/internal/telephony/RILConstants.java
index facee5f..7fb7f41 100644
--- a/telephony/java/com/android/internal/telephony/RILConstants.java
+++ b/telephony/java/com/android/internal/telephony/RILConstants.java
@@ -261,6 +261,7 @@
     int RIL_REQUEST_REPORT_SMS_MEMORY_STATUS = 102;
     int RIL_REQUEST_REPORT_STK_SERVICE_IS_RUNNING = 103;
     int RIL_REQUEST_CDMA_GET_SUBSCRIPTION_SOURCE = 104;
+    int RIL_REQUEST_ISIM_AUTHENTICATION = 105;
     int RIL_UNSOL_RESPONSE_BASE = 1000;
     int RIL_UNSOL_RESPONSE_RADIO_STATE_CHANGED = 1000;
     int RIL_UNSOL_RESPONSE_CALL_STATE_CHANGED = 1001;
diff --git a/telephony/java/com/android/internal/telephony/cdma/CDMALTEPhone.java b/telephony/java/com/android/internal/telephony/cdma/CDMALTEPhone.java
index ac66b48..f4ed91d 100644
--- a/telephony/java/com/android/internal/telephony/cdma/CDMALTEPhone.java
+++ b/telephony/java/com/android/internal/telephony/cdma/CDMALTEPhone.java
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2006 The Android Open Source Project
+ * 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.
@@ -16,29 +16,19 @@
 
 package com.android.internal.telephony.cdma;
 
-import android.os.SystemProperties;
-import android.content.Context;
-import android.net.Uri;
-import android.content.Context;
-import android.provider.Telephony;
 import android.content.ContentValues;
+import android.content.Context;
 import android.database.SQLException;
-import android.telephony.ServiceState;
-import android.telephony.SignalStrength;
+import android.net.Uri;
+import android.os.Message;
+import android.provider.Telephony;
+import android.util.Log;
 
-import com.android.internal.telephony.gsm.SIMRecords;
-import com.android.internal.telephony.gsm.SimCard;
-import com.android.internal.telephony.ServiceStateTracker;
-import com.android.internal.telephony.DataConnectionTracker;
 import com.android.internal.telephony.CommandsInterface;
 import com.android.internal.telephony.Phone;
-import com.android.internal.telephony.PhoneBase;
 import com.android.internal.telephony.PhoneNotifier;
-import com.android.internal.telephony.PhoneProxy;
-import com.android.internal.telephony.IccCard;
-import com.android.internal.telephony.gsm.GsmDataConnectionTracker;
-
-import android.util.Log;
+import com.android.internal.telephony.gsm.SimCard;
+import com.android.internal.telephony.ims.IsimRecords;
 
 public class CDMALTEPhone extends CDMAPhone {
     static final String LOG_TAG = "CDMA";
@@ -68,7 +58,7 @@
         DataState ret = DataState.DISCONNECTED;
 
         if (mSST == null) {
-            // Radio Technology Change is ongoning, dispose() and
+            // Radio Technology Change is ongoing, dispose() and
             // removeReferences() have already been called
 
             ret = DataState.DISCONNECTED;
@@ -146,6 +136,16 @@
     }
 
     @Override
+    public IsimRecords getIsimRecords() {
+        return mIccRecords.getIsimRecords();
+    }
+
+    @Override
+    public void requestIsimAuthentication(String nonce, Message result) {
+        mCM.requestIsimAuthentication(nonce, result);
+    }
+
+    @Override
     protected void log(String s) {
         if (DBG)
             Log.d(LOG_TAG, "[CDMALTEPhone] " + s);
diff --git a/telephony/java/com/android/internal/telephony/cdma/CdmaLteUiccFileHandler.java b/telephony/java/com/android/internal/telephony/cdma/CdmaLteUiccFileHandler.java
index b9d7c46..b57af0e 100644
--- a/telephony/java/com/android/internal/telephony/cdma/CdmaLteUiccFileHandler.java
+++ b/telephony/java/com/android/internal/telephony/cdma/CdmaLteUiccFileHandler.java
@@ -42,6 +42,10 @@
             return MF_SIM + DF_CDMA;
         case EF_AD:
             return MF_SIM + DF_GSM;
+        case EF_IMPI:
+        case EF_DOMAIN:
+        case EF_IMPU:
+            return MF_SIM + DF_ADFISIM;
         }
         return getCommonIccEFPath(efid);
     }
diff --git a/telephony/java/com/android/internal/telephony/cdma/CdmaLteUiccRecords.java b/telephony/java/com/android/internal/telephony/cdma/CdmaLteUiccRecords.java
index fc6abad..c4fa6f6 100755
--- a/telephony/java/com/android/internal/telephony/cdma/CdmaLteUiccRecords.java
+++ b/telephony/java/com/android/internal/telephony/cdma/CdmaLteUiccRecords.java
@@ -15,8 +15,10 @@
  */
 package com.android.internal.telephony.cdma;
 
-import static com.android.internal.telephony.TelephonyProperties.PROPERTY_ICC_OPERATOR_ALPHA;
-import static com.android.internal.telephony.TelephonyProperties.PROPERTY_TEST_CSIM;
+import android.os.AsyncResult;
+import android.os.SystemProperties;
+import android.util.Log;
+
 import com.android.internal.telephony.GsmAlphabet;
 import com.android.internal.telephony.IccCardApplication.AppType;
 import com.android.internal.telephony.IccFileHandler;
@@ -25,12 +27,14 @@
 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;
-import java.util.Locale;
+import com.android.internal.telephony.ims.IsimRecords;
+import com.android.internal.telephony.ims.IsimUiccRecords;
+
 import java.util.ArrayList;
+import java.util.Locale;
+
+import static com.android.internal.telephony.TelephonyProperties.PROPERTY_ICC_OPERATOR_ALPHA;
+import static com.android.internal.telephony.TelephonyProperties.PROPERTY_TEST_CSIM;
 
 /**
  * {@hide}
@@ -46,130 +50,191 @@
     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;
+    private final IsimUiccRecords mIsimUiccRecords = new IsimUiccRecords();
 
     public CdmaLteUiccRecords(PhoneBase p) {
         super(p);
     }
 
-    @Override
-    public void handleMessage(Message msg) {
-        AsyncResult ar;
-        byte data[];
+    // Refer to ETSI TS 102.221
+    private class EfPlLoaded implements IccRecordLoaded {
+        public String getEfName() {
+            return "EF_PL";
+        }
 
-        boolean isCsimRecordLoadResponse = false;
+        public void onRecordLoaded(AsyncResult ar) {
+            mEFpl = (byte[]) ar.result;
+            if (DBG) log("EF_PL=" + IccUtils.bytesToHexString(mEFpl));
+        }
+    }
 
-        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;
+    // Refer to C.S0065 5.2.26
+    private class EfCsimLiLoaded implements IccRecordLoaded {
+        public String getEfName() {
+            return "EF_CSIM_LI";
+        }
 
-                ar = (AsyncResult) msg.obj;
-
-                if (ar.exception != null) {
-                    Log.e(LOG_TAG, "ar.exception = " + ar.exception);
-                    break;
+        public void onRecordLoaded(AsyncResult ar) {
+            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] = ' ';
                 }
-
-                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;
-            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) {
-            Log.w(LOG_TAG, "Exception parsing SIM record", exc);
-        } finally {
-            if (isCsimRecordLoadResponse) {
-                onRecordLoaded();
             }
+
+            if (DBG) log("EF_LI=" + IccUtils.bytesToHexString(mEFli));
+        }
+    }
+
+    // Refer to C.S0065 5.2.32
+    private class EfCsimSpnLoaded implements IccRecordLoaded {
+        public String getEfName() {
+            return "EF_CSIM_SPN";
+        }
+
+        public void onRecordLoaded(AsyncResult ar) {
+            byte[] data = (byte[]) ar.result;
+            if (DBG) log("CSIM_SPN=" +
+                         IccUtils.bytesToHexString(data));
+
+            // C.S0065 for EF_SPN decoding
+            mCsimSpnDisplayCondition = ((0x01 & data[0]) != 0);
+
+            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=" + mCsimSpnDisplayCondition);
+            phone.setSystemProperty(PROPERTY_ICC_OPERATOR_ALPHA, spn);
+        }
+    }
+
+    private class EfCsimMdnLoaded implements IccRecordLoaded {
+        public String getEfName() {
+            return "EF_CSIM_MDN";
+        }
+
+        public void onRecordLoaded(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 class EfCsimImsimLoaded implements IccRecordLoaded {
+        public String getEfName() {
+            return "EF_CSIM_IMSIM";
+        }
+
+        public void onRecordLoaded(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));
+                mMin = builder.toString();
+                if (DBG) log("min present=" + mMin);
+            } else {
+                if (DBG) log("min not present");
+            }
+        }
+    }
+
+    private class EfCsimCdmaHomeLoaded implements IccRecordLoaded {
+        public String getEfName() {
+            return "EF_CSIM_CDMAHOME";
+        }
+
+        public void onRecordLoaded(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 class EfCsimEprlLoaded implements IccRecordLoaded {
+        public String getEfName() {
+            return "EF_CSIM_EPRL";
+        }
+        public void onRecordLoaded(AsyncResult ar) {
+            onGetCSimEprlDone(ar);
         }
     }
 
@@ -189,8 +254,8 @@
 
     @Override
     protected void onAllRecordsLoaded() {
-        super.onAllRecordsLoaded();
         setLocaleFromCsim();
+        super.onAllRecordsLoaded();     // broadcasts ICC state change to "LOADED"
     }
 
     @Override
@@ -207,112 +272,36 @@
         iccFh.loadEFTransparent(EF_AD, obtainMessage(EVENT_GET_AD_DONE));
         recordsToLoad++;
 
-        iccFh.loadEFTransparent(EF_PL, obtainMessage(EVENT_GET_PL_DONE));
+        iccFh.loadEFTransparent(EF_PL,
+                obtainMessage(EVENT_GET_ICC_RECORD_DONE, new EfPlLoaded()));
         recordsToLoad++;
 
-        iccFh.loadEFTransparent(EF_CSIM_LI, obtainMessage(EVENT_GET_CSIM_LI_DONE));
+        iccFh.loadEFTransparent(EF_CSIM_LI,
+                obtainMessage(EVENT_GET_ICC_RECORD_DONE, new EfCsimLiLoaded()));
         recordsToLoad++;
 
-        iccFh.loadEFTransparent(EF_CSIM_SPN, obtainMessage(EVENT_GET_CSIM_SPN_DONE));
+        iccFh.loadEFTransparent(EF_CSIM_SPN,
+                obtainMessage(EVENT_GET_ICC_RECORD_DONE, new EfCsimSpnLoaded()));
         recordsToLoad++;
 
-        iccFh.loadEFLinearFixed(EF_CSIM_MDN, 1, obtainMessage(EVENT_GET_CSIM_MDN_DONE));
+        iccFh.loadEFLinearFixed(EF_CSIM_MDN, 1,
+                obtainMessage(EVENT_GET_ICC_RECORD_DONE, new EfCsimMdnLoaded()));
         recordsToLoad++;
 
-        iccFh.loadEFTransparent(EF_CSIM_IMSIM, obtainMessage(EVENT_GET_CSIM_IMSIM_DONE));
+        iccFh.loadEFTransparent(EF_CSIM_IMSIM,
+                obtainMessage(EVENT_GET_ICC_RECORD_DONE, new EfCsimImsimLoaded()));
         recordsToLoad++;
 
         iccFh.loadEFLinearFixedAll(EF_CSIM_CDMAHOME,
-                                   obtainMessage(EVENT_GET_CSIM_CDMAHOME_DONE));
+                obtainMessage(EVENT_GET_ICC_RECORD_DONE, new EfCsimCdmaHomeLoaded()));
         recordsToLoad++;
 
-        iccFh.loadEFTransparent(EF_CSIM_EPRL, obtainMessage(EVENT_GET_CSIM_EPRL_DONE));
+        iccFh.loadEFTransparent(EF_CSIM_EPRL,
+                obtainMessage(EVENT_GET_ICC_RECORD_DONE, new EfCsimEprlLoaded()));
         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
-        mCsimSpnDisplayCondition = ((0x01 & 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=" + mCsimSpnDisplayCondition);
-        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");
-        }
+        // load ISIM records
+        recordsToLoad += mIsimUiccRecords.fetchIsimRecords(iccFh, this);
     }
 
     private int adjstMinDigits (int digits) {
@@ -324,32 +313,6 @@
         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.
@@ -418,6 +381,11 @@
         if (DBG) Log.d(LOG_TAG, "[CSIM] " + s);
     }
 
+    @Override
+    protected void loge(String s) {
+        if (DBG) Log.e(LOG_TAG, "[CSIM] " + s);
+    }
+
     public String getMdn() {
         return mMdn;
     }
@@ -443,6 +411,11 @@
     }
 
     @Override
+    public IsimRecords getIsimRecords() {
+        return mIsimUiccRecords;
+    }
+
+    @Override
     public boolean isProvisioned() {
         // If UICC card has CSIM app, look for MDN and MIN field
         // to determine if the SIM is provisioned.  Otherwise,
diff --git a/telephony/java/com/android/internal/telephony/cdma/RuimRecords.java b/telephony/java/com/android/internal/telephony/cdma/RuimRecords.java
index 9af2d26..9850b9f 100755
--- a/telephony/java/com/android/internal/telephony/cdma/RuimRecords.java
+++ b/telephony/java/com/android/internal/telephony/cdma/RuimRecords.java
@@ -443,4 +443,8 @@
         Log.d(LOG_TAG, "[RuimRecords] " + s);
     }
 
+    @Override
+    protected void loge(String s) {
+        Log.e(LOG_TAG, "[RuimRecords] " + s);
+    }
 }
diff --git a/telephony/java/com/android/internal/telephony/gsm/SIMRecords.java b/telephony/java/com/android/internal/telephony/gsm/SIMRecords.java
index b0bad56..28034cc 100755
--- a/telephony/java/com/android/internal/telephony/gsm/SIMRecords.java
+++ b/telephony/java/com/android/internal/telephony/gsm/SIMRecords.java
@@ -147,8 +147,6 @@
     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 = {
@@ -1089,6 +1087,9 @@
                 handleEfCspData(data);
                 break;
 
+            default:
+                super.handleMessage(msg);   // IccRecords handles generic record load responses
+
         }}catch (RuntimeException exc) {
             // I don't want these exceptions to be fatal
             Log.w(LOG_TAG, "Exception parsing SIM record", exc);
@@ -1573,6 +1574,10 @@
         Log.d(LOG_TAG, "[SIMRecords] " + s);
     }
 
+    protected void loge(String s) {
+        Log.e(LOG_TAG, "[SIMRecords] " + s);
+    }
+
     /**
      * Return true if "Restriction of menu options for manual PLMN selection"
      * bit is set or EF_CSP data is unavailable, return false otherwise.
diff --git a/telephony/java/com/android/internal/telephony/ims/IsimRecords.java b/telephony/java/com/android/internal/telephony/ims/IsimRecords.java
new file mode 100644
index 0000000..b8b98b9
--- /dev/null
+++ b/telephony/java/com/android/internal/telephony/ims/IsimRecords.java
@@ -0,0 +1,44 @@
+/*
+ * 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.ims;
+
+/**
+ * {@hide}
+ */
+public interface IsimRecords {
+
+    /**
+     * Return the IMS private user identity (IMPI).
+     * Returns null if the IMPI hasn't been loaded or isn't present on the ISIM.
+     * @return the IMS private user identity string, or null if not available
+     */
+    String getIsimImpi();
+
+    /**
+     * Return the IMS home network domain name.
+     * Returns null if the IMS domain hasn't been loaded or isn't present on the ISIM.
+     * @return the IMS home network domain name, or null if not available
+     */
+    String getIsimDomain();
+
+    /**
+     * Return an array of IMS public user identities (IMPU).
+     * Returns null if the IMPU hasn't been loaded or isn't present on the ISIM.
+     * @return an array of IMS public user identity strings, or null if not available
+     */
+    String[] getIsimImpu();
+}
diff --git a/telephony/java/com/android/internal/telephony/ims/IsimUiccRecords.java b/telephony/java/com/android/internal/telephony/ims/IsimUiccRecords.java
new file mode 100644
index 0000000..ee1a42d
--- /dev/null
+++ b/telephony/java/com/android/internal/telephony/ims/IsimUiccRecords.java
@@ -0,0 +1,157 @@
+/*
+ * 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.ims;
+
+import android.os.AsyncResult;
+import android.os.Handler;
+import android.util.Log;
+
+import com.android.internal.telephony.IccFileHandler;
+import com.android.internal.telephony.IccRecords;
+import com.android.internal.telephony.gsm.SimTlv;
+
+import java.nio.charset.Charset;
+import java.util.ArrayList;
+
+import static com.android.internal.telephony.IccConstants.EF_DOMAIN;
+import static com.android.internal.telephony.IccConstants.EF_IMPI;
+import static com.android.internal.telephony.IccConstants.EF_IMPU;
+
+/**
+ * {@hide}
+ */
+public final class IsimUiccRecords implements IsimRecords {
+    protected static final String LOG_TAG = "GSM";
+
+    private static final boolean DBG = true;
+    private static final boolean DUMP_RECORDS = false;   // Note: PII is logged when this is true
+
+    // ISIM EF records (see 3GPP TS 31.103)
+    private String mIsimImpi;               // IMS private user identity
+    private String mIsimDomain;             // IMS home network domain name
+    private String[] mIsimImpu;             // IMS public user identity(s)
+
+    private static final int TAG_ISIM_VALUE = 0x80;     // From 3GPP TS 31.103
+
+    private class EfIsimImpiLoaded implements IccRecords.IccRecordLoaded {
+        public String getEfName() {
+            return "EF_ISIM_IMPI";
+        }
+        public void onRecordLoaded(AsyncResult ar) {
+            byte[] data = (byte[]) ar.result;
+            mIsimImpi = isimTlvToString(data);
+            if (DUMP_RECORDS) log("EF_IMPI=" + mIsimImpi);
+        }
+    }
+
+    private class EfIsimImpuLoaded implements IccRecords.IccRecordLoaded {
+        public String getEfName() {
+            return "EF_ISIM_IMPU";
+        }
+        public void onRecordLoaded(AsyncResult ar) {
+            ArrayList<byte[]> impuList = (ArrayList<byte[]>) ar.result;
+            if (DBG) log("EF_IMPU record count: " + impuList.size());
+            mIsimImpu = new String[impuList.size()];
+            int i = 0;
+            for (byte[] identity : impuList) {
+                String impu = isimTlvToString(identity);
+                if (DUMP_RECORDS) log("EF_IMPU[" + i + "]=" + impu);
+                mIsimImpu[i++] = impu;
+            }
+        }
+    }
+
+    private class EfIsimDomainLoaded implements IccRecords.IccRecordLoaded {
+        public String getEfName() {
+            return "EF_ISIM_DOMAIN";
+        }
+        public void onRecordLoaded(AsyncResult ar) {
+            byte[] data = (byte[]) ar.result;
+            mIsimDomain = isimTlvToString(data);
+            if (DUMP_RECORDS) log("EF_DOMAIN=" + mIsimDomain);
+        }
+    }
+
+    /**
+     * Request the ISIM records to load.
+     * @param iccFh the IccFileHandler to load the records from
+     * @param h the Handler to which the response message will be sent
+     * @return the number of EF record requests that were added
+     */
+    public int fetchIsimRecords(IccFileHandler iccFh, Handler h) {
+        iccFh.loadEFTransparent(EF_IMPI, h.obtainMessage(
+                IccRecords.EVENT_GET_ICC_RECORD_DONE, new EfIsimImpiLoaded()));
+        iccFh.loadEFLinearFixedAll(EF_IMPU, h.obtainMessage(
+                IccRecords.EVENT_GET_ICC_RECORD_DONE, new EfIsimImpuLoaded()));
+        iccFh.loadEFTransparent(EF_DOMAIN, h.obtainMessage(
+                IccRecords.EVENT_GET_ICC_RECORD_DONE, new EfIsimDomainLoaded()));
+        return 3;   // number of EF record load requests
+    }
+
+    /**
+     * ISIM records for IMS are stored inside a Tag-Length-Value record as a UTF-8 string
+     * with tag value 0x80.
+     * @param record the byte array containing the IMS data string
+     * @return the decoded String value, or null if the record can't be decoded
+     */
+    private static String isimTlvToString(byte[] record) {
+        SimTlv tlv = new SimTlv(record, 0, record.length);
+        do {
+            if (tlv.getTag() == TAG_ISIM_VALUE) {
+                return new String(tlv.getData(), Charset.forName("UTF-8"));
+            }
+        } while (tlv.nextObject());
+
+        Log.e(LOG_TAG, "[ISIM] can't find TLV tag in ISIM record, returning null");
+        return null;
+    }
+
+    void log(String s) {
+        if (DBG) Log.d(LOG_TAG, "[ISIM] " + s);
+    }
+
+    void loge(String s) {
+        if (DBG) Log.e(LOG_TAG, "[ISIM] " + s);
+    }
+
+    /**
+     * Return the IMS private user identity (IMPI).
+     * Returns null if the IMPI hasn't been loaded or isn't present on the ISIM.
+     * @return the IMS private user identity string, or null if not available
+     */
+    public String getIsimImpi() {
+        return mIsimImpi;
+    }
+
+    /**
+     * Return the IMS home network domain name.
+     * Returns null if the IMS domain hasn't been loaded or isn't present on the ISIM.
+     * @return the IMS home network domain name, or null if not available
+     */
+    public String getIsimDomain() {
+        return mIsimDomain;
+    }
+
+    /**
+     * Return an array of IMS public user identities (IMPU).
+     * Returns null if the IMPU hasn't been loaded or isn't present on the ISIM.
+     * @return an array of IMS public user identity strings, or null if not available
+     */
+    public String[] getIsimImpu() {
+        return (mIsimImpu != null) ? mIsimImpu.clone() : null;
+    }
+}
diff --git a/telephony/java/com/android/internal/telephony/sip/SipCommandInterface.java b/telephony/java/com/android/internal/telephony/sip/SipCommandInterface.java
index 5208ccd..85ce6e0 100644
--- a/telephony/java/com/android/internal/telephony/sip/SipCommandInterface.java
+++ b/telephony/java/com/android/internal/telephony/sip/SipCommandInterface.java
@@ -186,7 +186,7 @@
 
     public void setupDataCall(String radioTechnology, String profile,
             String apn, String user, String password, String authType,
-            String protcol, Message result) {
+            String protocol, Message result) {
     }
 
     public void deactivateDataCall(int cid, int reason, Message result) {
@@ -403,4 +403,7 @@
     public void changeIccPin2ForApp(String oldPin2, String newPin2, String aidPtr,
             Message response) {
     }
+
+    public void requestIsimAuthentication(String nonce, Message response) {
+    }
 }
diff --git a/telephony/java/com/android/internal/telephony/test/SimulatedCommands.java b/telephony/java/com/android/internal/telephony/test/SimulatedCommands.java
index 80de9f3..a2a344f 100644
--- a/telephony/java/com/android/internal/telephony/test/SimulatedCommands.java
+++ b/telephony/java/com/android/internal/telephony/test/SimulatedCommands.java
@@ -1501,4 +1501,8 @@
             Message response) {
         unimplemented(response);
     }
+
+    public void requestIsimAuthentication(String nonce, Message response) {
+        unimplemented(response);
+    }
 }