Merge tag 'android-9.0.0_r37' of https://android.googlesource.com/platform//frameworks/opt/telephony into HEAD

Android 9.0.0 Release 37 (PQ3A.190505.002)

Change-Id: I78816ee5aa17ed42fe2afe633d8e2e3d87fe9bb3
Signed-off-by: Jackeagle <jackeagle102@gmail.com>
diff --git a/.gitreview b/.gitreview
new file mode 100644
index 0000000..a8a330a
--- /dev/null
+++ b/.gitreview
@@ -0,0 +1,5 @@
+[gerrit]
+host=review.blissroms.com
+port=29418
+project=platform_frameworks_opt_telephony.git
+defaultbranch=p9.0
diff --git a/Android.mk b/Android.mk
index 561aed0..24f9128 100644
--- a/Android.mk
+++ b/Android.mk
@@ -24,7 +24,7 @@
 	$(call all-Iaidl-files-under, src/java) \
 	$(call all-logtags-files-under, src/java)
 
-LOCAL_JAVA_LIBRARIES := voip-common ims-common services bouncycastle
+LOCAL_JAVA_LIBRARIES := voip-common ims-common telephony-ext services bouncycastle
 LOCAL_STATIC_JAVA_LIBRARIES := \
     telephony-protos \
     android.hardware.radio-V1.0-java \
@@ -32,7 +32,8 @@
     android.hardware.radio-V1.2-java \
     android.hardware.radio.config-V1.0-java \
     android.hardware.radio.deprecated-V1.0-java \
-    android.hidl.base-V1.0-java
+    android.hidl.base-V1.0-java \
+    ims-ext-common
 
 LOCAL_MODULE_TAGS := optional
 LOCAL_MODULE := telephony-common
diff --git a/src/java/com/android/internal/telephony/BaseCommands.java b/src/java/com/android/internal/telephony/BaseCommands.java
index c8cea5a..7b61364 100644
--- a/src/java/com/android/internal/telephony/BaseCommands.java
+++ b/src/java/com/android/internal/telephony/BaseCommands.java
@@ -879,8 +879,7 @@
         return mRilVersion;
     }
 
-    public void setUiccSubscription(int slotId, int appIndex, int subId, int subStatus,
-            Message response) {
+    public void setUiccSubscription(int appIndex, boolean activate, Message response) {
     }
 
     public void setDataAllowed(boolean allowed, Message response) {
diff --git a/src/java/com/android/internal/telephony/CommandsInterface.java b/src/java/com/android/internal/telephony/CommandsInterface.java
index 9f6ce5e..c9ce5b4 100644
--- a/src/java/com/android/internal/telephony/CommandsInterface.java
+++ b/src/java/com/android/internal/telephony/CommandsInterface.java
@@ -1952,20 +1952,15 @@
    /**
      * Sets user selected subscription at Modem.
      *
-     * @param slotId
-     *          Slot.
      * @param appIndex
      *          Application index in the card.
-     * @param subId
-     *          Indicates subscription 0 or subscription 1.
-     * @param subStatus
-     *          Activation status, 1 = activate and 0 = deactivate.
+     * @param activate
+     *          Whether to activate or deactivate the subscription.
      * @param result
      *          Callback message contains the information of SUCCESS/FAILURE.
      */
     // FIXME Update the doc and consider modifying the request to make more generic.
-    public void setUiccSubscription(int slotId, int appIndex, int subId, int subStatus,
-            Message result);
+    public void setUiccSubscription(int appIndex, boolean activate, Message result);
 
     /**
      * Tells the modem if data is allowed or not.
diff --git a/src/java/com/android/internal/telephony/GsmCdmaPhone.java b/src/java/com/android/internal/telephony/GsmCdmaPhone.java
index 13f8b0b..fa8cbe2 100644
--- a/src/java/com/android/internal/telephony/GsmCdmaPhone.java
+++ b/src/java/com/android/internal/telephony/GsmCdmaPhone.java
@@ -2164,7 +2164,11 @@
             // Complete pending USSD
 
             if (isUssdRelease) {
-                found.onUssdRelease();
+                if (SystemProperties.getBoolean("ro.telephony.isHisiRIL", false)) {
+                    found.onUssdFinished(ussdMessage, isUssdRequest);
+                } else {
+                    found.onUssdRelease();
+                }
             } else if (isUssdError) {
                 found.onUssdFinishedError();
             } else {
@@ -2668,6 +2672,7 @@
                 }
                 mUiccApplication.set(newUiccApplication);
                 mIccRecords.set(newUiccApplication.getIccRecords());
+                logd("mIccRecords = " + mIccRecords);
                 registerForIccRecordEvents();
                 mIccPhoneBookIntManager.updateIccRecords(mIccRecords.get());
             }
@@ -3282,7 +3287,7 @@
         }
     }
 
-    private void phoneObjectUpdater(int newVoiceRadioTech) {
+    protected void phoneObjectUpdater(int newVoiceRadioTech) {
         logd("phoneObjectUpdater: newVoiceRadioTech=" + newVoiceRadioTech);
 
         // Check for a voice over lte replacement
@@ -3467,6 +3472,8 @@
         pw.println("GsmCdmaPhone extends:");
         super.dump(fd, pw, args);
         pw.println(" mPrecisePhoneType=" + mPrecisePhoneType);
+        pw.println(" mSimRecords=" + mSimRecords);
+        pw.println(" mIsimUiccRecords=" + mIsimUiccRecords);
         pw.println(" mCT=" + mCT);
         pw.println(" mSST=" + mSST);
         pw.println(" mPendingMMIs=" + mPendingMMIs);
@@ -3522,7 +3529,8 @@
     /**
      * @return operator numeric.
      */
-    private String getOperatorNumeric() {
+    @Override
+    public String getOperatorNumeric() {
         String operatorNumeric = null;
         if (isPhoneTypeGsm()) {
             IccRecords r = mIccRecords.get();
diff --git a/src/java/com/android/internal/telephony/IIccPhoneBook.aidl b/src/java/com/android/internal/telephony/IIccPhoneBook.aidl
index 5090d1a..3dc3ba3 100644
--- a/src/java/com/android/internal/telephony/IIccPhoneBook.aidl
+++ b/src/java/com/android/internal/telephony/IIccPhoneBook.aidl
@@ -16,6 +16,8 @@
 
 package com.android.internal.telephony;
 
+import android.content.ContentValues;
+
 import com.android.internal.telephony.uicc.AdnRecord;
 
 
@@ -103,6 +105,22 @@
             String oldTag, String oldPhoneNumber,
             String newTag, String newPhoneNumber,
             String pin2);
+
+    /**
+     * Replace oldAdn with newAdn in ADN-like record in EF
+     *
+     * getAdnRecordsInEf must be called at least once before this function,
+     * otherwise an error will be returned
+     *
+     * @param subId user preferred subId
+     * @param efid must be one among EF_ADN, EF_FDN, and EF_SDN
+     * @param values including ADN,EMAIL,ANR to be updated
+     * @param pin2 required to update EF_FDN, otherwise must be null
+     * @return true for success
+     */
+    boolean updateAdnRecordsWithContentValuesInEfBySearchUsingSubId(int subId,
+            int efid, in ContentValues values, String pin2);
+
     /**
      * Update an ADN-like EF record by record index
      *
@@ -165,4 +183,39 @@
      */
     int[] getAdnRecordsSizeForSubscriber(int subId, int efid);
 
+    /**
+     * Get the capacity of ADN records
+     *
+     * @return  int[10] array
+     *            capacity[0]  is the max count of ADN
+     *            capacity[1]  is the used count of ADN
+     *            capacity[2]  is the max count of EMAIL
+     *            capacity[3]  is the used count of EMAIL
+     *            capacity[4]  is the max count of ANR
+     *            capacity[5]  is the used count of ANR
+     *            capacity[6]  is the max length of name
+     *            capacity[7]  is the max length of number
+     *            capacity[8]  is the max length of email
+     *            capacity[9]  is the max length of anr
+     */
+    int[] getAdnRecordsCapacity();
+
+    /**
+     * Get the capacity of ADN records
+     *
+     * @param subId user preferred subId
+     * @return  int[10] array
+     *            capacity[0]  is the max count of ADN
+     *            capacity[1]  is the used count of ADN
+     *            capacity[2]  is the max count of EMAIL
+     *            capacity[3]  is the used count of EMAIL
+     *            capacity[4]  is the max count of ANR
+     *            capacity[5]  is the used count of ANR
+     *            capacity[6]  is the max length of name
+     *            capacity[7]  is the max length of number
+     *            capacity[8]  is the max length of email
+     *            capacity[9]  is the max length of anr
+     */
+    int[] getAdnRecordsCapacityForSubscriber(int subId);
+
 }
diff --git a/src/java/com/android/internal/telephony/IccPhoneBookInterfaceManager.java b/src/java/com/android/internal/telephony/IccPhoneBookInterfaceManager.java
index 2a35370..40e8ba4 100644
--- a/src/java/com/android/internal/telephony/IccPhoneBookInterfaceManager.java
+++ b/src/java/com/android/internal/telephony/IccPhoneBookInterfaceManager.java
@@ -16,12 +16,15 @@
 
 package com.android.internal.telephony;
 
+import android.content.ContentValues;
 import android.content.pm.PackageManager;
 import android.os.AsyncResult;
 import android.os.Handler;
+import android.os.HandlerThread;
 import android.os.Looper;
 import android.os.Message;
 import android.telephony.Rlog;
+import android.text.TextUtils;
 
 import com.android.internal.telephony.uicc.AdnRecord;
 import com.android.internal.telephony.uicc.AdnRecordCache;
@@ -58,7 +61,18 @@
     protected static final int EVENT_LOAD_DONE = 2;
     protected static final int EVENT_UPDATE_DONE = 3;
 
-    protected Handler mBaseHandler = new Handler() {
+    protected final IccPbHandler mBaseHandler;
+
+    private static final HandlerThread  mHandlerThread  = new HandlerThread("IccPbHandlerLoader");
+    static {
+        mHandlerThread.start();
+    }
+
+    protected class IccPbHandler extends Handler {
+        public IccPbHandler(Looper looper) {
+            super(looper);
+        }
+
         @Override
         public void handleMessage(Message msg) {
             AsyncResult ar;
@@ -81,6 +95,9 @@
                     break;
                 case EVENT_UPDATE_DONE:
                     ar = (AsyncResult) msg.obj;
+                    if (ar.exception != null) {
+                        if(DBG) logd("exception of EVENT_UPDATE_DONE is" + ar.exception);
+                    }
                     synchronized (mLock) {
                         mSuccess = (ar.exception == null);
                         notifyPending(ar);
@@ -90,6 +107,7 @@
                     ar = (AsyncResult)msg.obj;
                     synchronized (mLock) {
                         if (ar.exception == null) {
+                            if(DBG) logd("Load ADN records done");
                             mRecords = (List<AdnRecord>) ar.result;
                         } else {
                             if(DBG) logd("Cannot load ADN records");
@@ -116,6 +134,7 @@
         if (r != null) {
             mAdnCache = r.getAdnCache();
         }
+        mBaseHandler = new IccPbHandler(mHandlerThread.getLooper());
     }
 
     public void dispose() {
@@ -196,6 +215,66 @@
     }
 
     /**
+     * Replace oldAdn with newAdn in ADN-like record in EF
+     *
+     * getAdnRecordsInEf must be called at least once before this function,
+     * otherwise an error will be returned.
+     * throws SecurityException if no WRITE_CONTACTS permission
+     *
+     * @param efid must be one among EF_ADN, EF_FDN, and EF_SDN
+     * @param values old adn tag,  phone number, email and anr to be replaced
+     *        new adn tag,  phone number, email and anr to be stored
+     * @param newPhoneNumber adn number ot be stored
+     * @param oldPhoneNumber adn number to be replaced
+     *        Set both oldTag, oldPhoneNubmer, oldEmail and oldAnr to ""
+     *        means to replace an empty record, aka, insert new record
+     *        Set both newTag, newPhoneNubmer, newEmail and newAnr ""
+     *        means to replace the old record with empty one, aka, delete old record
+     * @param pin2 required to update EF_FDN, otherwise must be null
+     * @return true for success
+     */
+    public boolean updateAdnRecordsWithContentValuesInEfBySearch(int efid, ContentValues values,
+            String pin2) {
+
+        if (mPhone.getContext().checkCallingOrSelfPermission(
+                android.Manifest.permission.WRITE_CONTACTS) != PackageManager.PERMISSION_GRANTED) {
+            throw new SecurityException("Requires android.permission.WRITE_CONTACTS permission");
+        }
+
+        String oldTag = values.getAsString(IccProvider.STR_TAG);
+        String newTag = values.getAsString(IccProvider.STR_NEW_TAG);
+        String oldPhoneNumber = values.getAsString(IccProvider.STR_NUMBER);
+        String newPhoneNumber = values.getAsString(IccProvider.STR_NEW_NUMBER);
+        String oldEmail = values.getAsString(IccProvider.STR_EMAILS);
+        String newEmail = values.getAsString(IccProvider.STR_NEW_EMAILS);
+        String oldAnr = values.getAsString(IccProvider.STR_ANRS);
+        String newAnr = values.getAsString(IccProvider.STR_NEW_ANRS);
+        String[] oldEmailArray = TextUtils.isEmpty(oldEmail) ? null : getStringArray(oldEmail);
+        String[] newEmailArray = TextUtils.isEmpty(newEmail) ? null : getStringArray(newEmail);
+        String[] oldAnrArray = TextUtils.isEmpty(oldAnr) ? null : getAnrStringArray(oldAnr);
+        String[] newAnrArray = TextUtils.isEmpty(newAnr) ? null : getAnrStringArray(newAnr);
+        efid = updateEfForIccType(efid);
+
+        if (DBG) logd("updateAdnRecordsWithContentValuesInEfBySearch: efid=" + efid +
+                ", values = " + values + ", pin2=" + pin2);
+        synchronized (mLock) {
+            checkThread();
+            mSuccess = false;
+            AtomicBoolean status = new AtomicBoolean(false);
+            Message response = mBaseHandler.obtainMessage(EVENT_UPDATE_DONE, status);
+            AdnRecord oldAdn = new AdnRecord(oldTag, oldPhoneNumber, oldEmailArray, oldAnrArray);
+            AdnRecord newAdn = new AdnRecord(newTag, newPhoneNumber, newEmailArray, newAnrArray);
+            if (mAdnCache != null) {
+                mAdnCache.updateAdnBySearch(efid, oldAdn, newAdn, pin2, response);
+                waitForResult(status);
+            } else {
+                loge("Failure while trying to update by search due to uninitialised adncache");
+            }
+        }
+        return mSuccess;
+    }
+
+    /**
      * Update an ADN-like EF record by record index
      *
      * This is useful for iteration the whole ADN file, such as write the whole
@@ -311,7 +390,7 @@
     protected void checkThread() {
         if (!ALLOW_SIM_OP_IN_UI_THREAD) {
             // Make sure this isn't the UI thread, since it will block
-            if (mBaseHandler.getLooper().equals(Looper.myLooper())) {
+            if (Looper.getMainLooper().equals(Looper.myLooper())) {
                 loge("query() called on the main UI thread!");
                 throw new IllegalStateException(
                         "You cannot call query on this provder from the main UI thread.");
@@ -329,7 +408,7 @@
         }
     }
 
-    private int updateEfForIccType(int efid) {
+    protected int updateEfForIccType(int efid) {
         // Check if we are trying to read ADN records
         if (efid == IccConstants.EF_ADN) {
             if (mPhone.getCurrentUiccAppType() == AppType.APPTYPE_USIM) {
@@ -338,5 +417,41 @@
         }
         return efid;
     }
+
+    protected String[] getStringArray(String str) {
+        if (str != null) {
+            return str.split(",");
+        }
+        return null;
+    }
+
+    protected String[] getAnrStringArray(String str) {
+        if (str != null) {
+            return str.split(":");
+        }
+        return null;
+    }
+
+    /**
+     * Get the capacity of ADN records
+     *
+     * @return  int[6] array
+     *            capacity[0]  is the max count of ADN
+     *            capacity[1]  is the used count of ADN
+     *            capacity[2]  is the max count of EMAIL
+     *            capacity[3]  is the used count of EMAIL
+     *            capacity[4]  is the max count of ANR
+     *            capacity[5]  is the used count of ANR
+     *            capacity[6]  is the max length of name
+     *            capacity[7]  is the max length of number
+     *            capacity[8]  is the max length of email
+     *            capacity[9]  is the max length of anr
+     */
+    public int[] getAdnRecordsCapacity() {
+        if (DBG) logd("getAdnRecordsCapacity");
+        int capacity[] = new int[10];
+
+        return capacity;
+    }
 }
 
diff --git a/src/java/com/android/internal/telephony/IccProvider.java b/src/java/com/android/internal/telephony/IccProvider.java
index 8feec94..a1ada42 100644
--- a/src/java/com/android/internal/telephony/IccProvider.java
+++ b/src/java/com/android/internal/telephony/IccProvider.java
@@ -48,6 +48,7 @@
         "name",
         "number",
         "emails",
+        "anrs",
         "_id"
     };
 
@@ -59,10 +60,15 @@
     protected static final int SDN_SUB = 6;
     protected static final int ADN_ALL = 7;
 
-    protected static final String STR_TAG = "tag";
-    protected static final String STR_NUMBER = "number";
-    protected static final String STR_EMAILS = "emails";
-    protected static final String STR_PIN2 = "pin2";
+    public static final String STR_TAG = "tag";
+    public static final String STR_NUMBER = "number";
+    public static final String STR_EMAILS = "emails";
+    public static final String STR_ANRS = "anrs";
+    public static final String STR_NEW_TAG = "newTag";
+    public static final String STR_NEW_NUMBER = "newNumber";
+    public static final String STR_NEW_EMAILS = "newEmails";
+    public static final String STR_NEW_ANRS = "newAnrs";
+    public static final String STR_PIN2 = "pin2";
 
     private static final UriMatcher URL_MATCHER =
                             new UriMatcher(UriMatcher.NO_MATCH);
@@ -197,8 +203,19 @@
 
         String tag = initialValues.getAsString("tag");
         String number = initialValues.getAsString("number");
-        // TODO(): Read email instead of sending null.
-        boolean success = addIccRecordToEf(efType, tag, number, null, pin2, subId);
+        String emails = initialValues.getAsString("emails");
+        String anrs = initialValues.getAsString("anrs");
+
+        ContentValues values = new ContentValues();
+        values.put(STR_TAG,"");
+        values.put(STR_NUMBER,"");
+        values.put(STR_EMAILS,"");
+        values.put(STR_ANRS,"");
+        values.put(STR_NEW_TAG,tag);
+        values.put(STR_NEW_NUMBER,number);
+        values.put(STR_NEW_EMAILS,emails);
+        values.put(STR_NEW_ANRS,anrs);
+        boolean success = updateIccRecordInEf(efType, values, pin2, subId);
 
         if (!success) {
             return null;
@@ -291,10 +308,11 @@
         // parse where clause
         String tag = null;
         String number = null;
-        String[] emails = null;
+        String emails = null;
+        String anrs = null;
         String pin2 = null;
 
-        String[] tokens = where.split("AND");
+        String[] tokens = where.split(" AND ");
         int n = tokens.length;
 
         while (--n >= 0) {
@@ -315,18 +333,29 @@
             } else if (STR_NUMBER.equals(key)) {
                 number = normalizeValue(val);
             } else if (STR_EMAILS.equals(key)) {
-                //TODO(): Email is null.
-                emails = null;
+                emails = normalizeValue(val);
+            } else if (STR_ANRS.equals(key)) {
+                anrs = normalizeValue(val);
             } else if (STR_PIN2.equals(key)) {
                 pin2 = normalizeValue(val);
             }
         }
 
+        ContentValues values = new ContentValues();
+        values.put(STR_TAG,tag);
+        values.put(STR_NUMBER,number);
+        values.put(STR_EMAILS,emails);
+        values.put(STR_ANRS,anrs);
+        values.put(STR_NEW_TAG,"");
+        values.put(STR_NEW_NUMBER,"");
+        values.put(STR_NEW_EMAILS,"");
+        values.put(STR_NEW_ANRS,"");
         if (efType == FDN && TextUtils.isEmpty(pin2)) {
             return 0;
         }
 
-        boolean success = deleteIccRecordFromEf(efType, tag, number, emails, pin2, subId);
+        if (DBG) log("delete mvalues= " + values);
+        boolean success = updateIccRecordInEf(efType, values, pin2, subId);
         if (!success) {
             return 0;
         }
@@ -379,8 +408,7 @@
         String newNumber = values.getAsString("newNumber");
         String[] newEmails = null;
         // TODO(): Update for email.
-        boolean success = updateIccRecordInEf(efType, tag, number,
-                newTag, newNumber, pin2, subId);
+        boolean success = updateIccRecordInEf(efType, values, pin2, subId);
 
         if (!success) {
             return 0;
@@ -454,21 +482,17 @@
     }
 
     private boolean
-    updateIccRecordInEf(int efType, String oldName, String oldNumber,
-            String newName, String newNumber, String pin2, int subId) {
-        if (DBG) log("updateIccRecordInEf: efType=0x" + Integer.toHexString(efType).toUpperCase() +
-                ", oldname=" + Rlog.pii(TAG, oldName) + ", oldnumber=" + Rlog.pii(TAG, oldNumber) +
-                ", newname=" + Rlog.pii(TAG, newName) + ", newnumber=" + Rlog.pii(TAG, newName) +
-                ", subscription=" + subId);
-
+    updateIccRecordInEf(int efType, ContentValues values, String pin2, int subId) {
         boolean success = false;
 
+        if (DBG) log("updateIccRecordInEf: efType=" + efType +
+                    ", values: [ "+ values + " ], subId:" + subId);
         try {
             IIccPhoneBook iccIpb = IIccPhoneBook.Stub.asInterface(
                     ServiceManager.getService("simphonebook"));
             if (iccIpb != null) {
-                success = iccIpb.updateAdnRecordsInEfBySearchForSubscriber(subId, efType, oldName,
-                        oldNumber, newName, newNumber, pin2);
+                success = iccIpb.updateAdnRecordsWithContentValuesInEfBySearchUsingSubId(subId,
+                        efType, values, pin2);
             }
         } catch (RemoteException ex) {
             // ignore it
@@ -479,7 +503,6 @@
         return success;
     }
 
-
     private boolean deleteIccRecordFromEf(int efType, String name, String number, String[] emails,
             String pin2, int subId) {
         if (DBG) log("deleteIccRecordFromEf: efType=0x" +
@@ -513,9 +536,10 @@
      */
     private void loadRecord(AdnRecord record, MatrixCursor cursor, int id) {
         if (!record.isEmpty()) {
-            Object[] contact = new Object[4];
+            Object[] contact = new Object[5];
             String alphaTag = record.getAlphaTag();
             String number = record.getNumber();
+            String[] anrs = record.getAdditionalNumbers();
 
             if (DBG) log("loadRecord: " + alphaTag + ", " + Rlog.pii(TAG, number));
             contact[0] = alphaTag;
@@ -531,7 +555,18 @@
                 }
                 contact[2] = emailString.toString();
             }
-            contact[3] = id;
+
+            if (anrs != null) {
+                StringBuilder anrString = new StringBuilder();
+                for (String anr : anrs) {
+                    if (DBG) log("Adding anr:" + anr);
+                    anrString.append(anr);
+                    anrString.append(":");
+                }
+                contact[3] = anrString.toString();
+            }
+
+            contact[4] = id;
             cursor.addRow(contact);
         }
     }
diff --git a/src/java/com/android/internal/telephony/LocaleTracker.java b/src/java/com/android/internal/telephony/LocaleTracker.java
index 996e288..9d730d4 100644
--- a/src/java/com/android/internal/telephony/LocaleTracker.java
+++ b/src/java/com/android/internal/telephony/LocaleTracker.java
@@ -408,8 +408,9 @@
             // Set the country code for wifi. This sets allowed wifi channels based on the
             // country of the carrier we see. If we can't see any, reset to 0 so we don't
             // broadcast on forbidden channels.
-            ((WifiManager) mPhone.getContext().getSystemService(Context.WIFI_SERVICE))
-                    .setCountryCode(countryIso);
+            if (mPhone.getContext().getSystemService(Context.WIFI_SERVICE) != null)
+                ((WifiManager) mPhone.getContext().getSystemService(Context.WIFI_SERVICE))
+                        .setCountryCode(countryIso);
         }
     }
 
diff --git a/src/java/com/android/internal/telephony/Phone.java b/src/java/com/android/internal/telephony/Phone.java
index c2446e4..3e18b92 100644
--- a/src/java/com/android/internal/telephony/Phone.java
+++ b/src/java/com/android/internal/telephony/Phone.java
@@ -285,7 +285,7 @@
     private boolean mImsServiceReady = false;
     protected Phone mImsPhone = null;
 
-    private final AtomicReference<RadioCapability> mRadioCapability =
+    protected final AtomicReference<RadioCapability> mRadioCapability =
             new AtomicReference<RadioCapability>();
 
     private static final int DEFAULT_REPORT_INTERVAL_MS = 200;
@@ -1289,7 +1289,7 @@
 
     private void updateSavedNetworkOperator(NetworkSelectMessage nsm) {
         int subId = getSubId();
-        if (SubscriptionManager.isValidSubscriptionId(subId)) {
+        if (SubscriptionController.getInstance().isActiveSubId(subId)) {
             // open the shared preferences editor, and write the value.
             // nsm.operatorNumeric is "" if we're in automatic.selection.
             SharedPreferences sp = PreferenceManager.getDefaultSharedPreferences(getContext());
@@ -1762,7 +1762,7 @@
     private int getCallForwardingIndicatorFromSharedPref() {
         int status = IccRecords.CALL_FORWARDING_STATUS_DISABLED;
         int subId = getSubId();
-        if (SubscriptionManager.isValidSubscriptionId(subId)) {
+        if (SubscriptionController.getInstance().isActiveSubId(subId)) {
             SharedPreferences sp = PreferenceManager.getDefaultSharedPreferences(mContext);
             status = sp.getInt(CF_STATUS + subId, IccRecords.CALL_FORWARDING_STATUS_UNKNOWN);
             Rlog.d(LOG_TAG, "getCallForwardingIndicatorFromSharedPref: for subId " + subId + "= " +
@@ -2292,7 +2292,7 @@
     public void setVoiceMessageCount(int countWaiting) {
         mVmCount = countWaiting;
         int subId = getSubId();
-        if (SubscriptionManager.isValidSubscriptionId(subId)) {
+        if (SubscriptionController.getInstance().isActiveSubId(subId)) {
 
             Rlog.d(LOG_TAG, "setVoiceMessageCount: Storing Voice Mail Count = " + countWaiting +
                     " for mVmCountKey = " + VM_COUNT + subId + " in preferences.");
@@ -2312,7 +2312,7 @@
     protected int getStoredVoiceMessageCount() {
         int countVoiceMessages = 0;
         int subId = getSubId();
-        if (SubscriptionManager.isValidSubscriptionId(subId)) {
+        if (SubscriptionController.getInstance().isActiveSubId(subId)) {
             int invalidCount = -2;  //-1 is not really invalid. It is used for unknown number of vm
             SharedPreferences sp = PreferenceManager.getDefaultSharedPreferences(mContext);
             int countFromSP = sp.getInt(VM_COUNT + subId, invalidCount);
@@ -3395,7 +3395,7 @@
 
     protected void setPreferredNetworkTypeIfSimLoaded() {
         int subId = getSubId();
-        if (SubscriptionManager.isValidSubscriptionId(subId)) {
+        if (SubscriptionManager.from(mContext).isActiveSubId(subId)) {
             int type = PhoneFactory.calculatePreferredNetworkType(mContext, getSubId());
             setPreferredNetworkType(type, null);
         }
@@ -3589,6 +3589,10 @@
     public void cancelUSSD() {
     }
 
+    public String getOperatorNumeric() {
+        return "";
+    }
+
     /**
      * Set boolean broadcastEmergencyCallStateChanges
      */
diff --git a/src/java/com/android/internal/telephony/PhoneFactory.java b/src/java/com/android/internal/telephony/PhoneFactory.java
index ba77747..50627fe 100644
--- a/src/java/com/android/internal/telephony/PhoneFactory.java
+++ b/src/java/com/android/internal/telephony/PhoneFactory.java
@@ -136,6 +136,8 @@
                 }
 
                 sPhoneNotifier = new DefaultPhoneNotifier();
+                TelephonyComponentFactory telephonyComponentFactory
+                        = TelephonyComponentFactory.getInstance();
 
                 int cdmaSubscription = CdmaSubscriptionSourceManager.getDefault(context);
                 Rlog.i(LOG_TAG, "Cdma Subscription set to " + cdmaSubscription);
@@ -168,11 +170,11 @@
                     networkModes[i] = RILConstants.PREFERRED_NETWORK_MODE;
 
                     Rlog.i(LOG_TAG, "Network Mode set to " + Integer.toString(networkModes[i]));
-                    sCommandsInterfaces[i] = new RIL(context, networkModes[i],
-                            cdmaSubscription, i);
+                    sCommandsInterfaces[i] = telephonyComponentFactory.makeRIL(context,
+                            networkModes[i], cdmaSubscription, i);
                 }
                 Rlog.i(LOG_TAG, "Creating SubscriptionController");
-                SubscriptionController.init(context, sCommandsInterfaces);
+                telephonyComponentFactory.initSubscriptionController(context, sCommandsInterfaces);
 
                 // Instantiate UiccController so that all other classes can just
                 // call getInstance()
@@ -188,15 +190,15 @@
                     Phone phone = null;
                     int phoneType = TelephonyManager.getPhoneType(networkModes[i]);
                     if (phoneType == PhoneConstants.PHONE_TYPE_GSM) {
-                        phone = new GsmCdmaPhone(context,
+                        phone = telephonyComponentFactory.makePhone(context,
                                 sCommandsInterfaces[i], sPhoneNotifier, i,
                                 PhoneConstants.PHONE_TYPE_GSM,
-                                TelephonyComponentFactory.getInstance());
+                                telephonyComponentFactory);
                     } else if (phoneType == PhoneConstants.PHONE_TYPE_CDMA) {
-                        phone = new GsmCdmaPhone(context,
+                        phone = telephonyComponentFactory.makePhone(context,
                                 sCommandsInterfaces[i], sPhoneNotifier, i,
-                                PhoneConstants.PHONE_TYPE_CDMA_LTE,
-                                TelephonyComponentFactory.getInstance());
+                                PhoneConstants.PHONE_TYPE_CDMA,
+                                telephonyComponentFactory);
                     }
                     Rlog.i(LOG_TAG, "Creating Phone with type = " + phoneType + " sub = " + i);
 
@@ -225,8 +227,11 @@
                 sMadeDefaults = true;
 
                 Rlog.i(LOG_TAG, "Creating SubInfoRecordUpdater ");
-                sSubInfoRecordUpdater = new SubscriptionInfoUpdater(
-                        BackgroundThread.get().getLooper(), context, sPhones, sCommandsInterfaces);
+                sSubInfoRecordUpdater = sContext.getResources().getBoolean(com.android.internal.R.bool.config_oldQtiTelephony)
+                        ? telephonyComponentFactory.makeSubscriptionInfoUpdater(
+                                context, sPhones, sCommandsInterfaces)
+                        : telephonyComponentFactory.makeSubscriptionInfoUpdater(
+                                BackgroundThread.get().getLooper(), context, sPhones, sCommandsInterfaces);
                 SubscriptionController.getInstance().updatePhonesAvailability(sPhones);
 
                 // Start monitoring after defaults have been made.
@@ -243,7 +248,8 @@
 
                 sSubscriptionMonitor = new SubscriptionMonitor(tr, sContext, sc, numPhones);
 
-                sPhoneSwitcher = new PhoneSwitcher(MAX_ACTIVE_PHONES, numPhones,
+                sPhoneSwitcher = telephonyComponentFactory.
+                        makePhoneSwitcher(MAX_ACTIVE_PHONES, numPhones,
                         sContext, sc, Looper.myLooper(), tr, sCommandsInterfaces,
                         sPhones);
 
@@ -260,6 +266,8 @@
                             sPhoneSwitcher, sc, sSubscriptionMonitor, Looper.myLooper(),
                             sContext, i, sPhones[i].mDcTracker);
                 }
+                telephonyComponentFactory.makeExtTelephonyClasses(
+                        context, sPhones, sCommandsInterfaces);
             }
         }
     }
diff --git a/src/java/com/android/internal/telephony/PhoneSwitcher.java b/src/java/com/android/internal/telephony/PhoneSwitcher.java
index cd28b2b..be122bb 100644
--- a/src/java/com/android/internal/telephony/PhoneSwitcher.java
+++ b/src/java/com/android/internal/telephony/PhoneSwitcher.java
@@ -57,29 +57,32 @@
  * the active phones.  Note we don't wait for data attach (which may not happen anyway).
  */
 public class PhoneSwitcher extends Handler {
-    private final static String LOG_TAG = "PhoneSwitcher";
-    private final static boolean VDBG = false;
+    protected final static String LOG_TAG = "PhoneSwitcher";
+    protected final static boolean VDBG = false;
 
-    private final int mMaxActivePhones;
-    private final List<DcRequest> mPrioritizedDcRequests = new ArrayList<DcRequest>();
-    private final RegistrantList[] mActivePhoneRegistrants;
-    private final SubscriptionController mSubscriptionController;
-    private final int[] mPhoneSubscriptions;
-    private final CommandsInterface[] mCommandsInterfaces;
-    private final Context mContext;
-    private final PhoneState[] mPhoneStates;
-    private final int mNumPhones;
+    protected int mMaxActivePhones;
+    protected final List<DcRequest> mPrioritizedDcRequests = new ArrayList<DcRequest>();
+    protected final RegistrantList[] mActivePhoneRegistrants;
+    protected final SubscriptionController mSubscriptionController;
+    protected final int[] mPhoneSubscriptions;
+    protected final CommandsInterface[] mCommandsInterfaces;
+    protected final Context mContext;
+    protected final PhoneState[] mPhoneStates;
+    protected final int mNumPhones;
     private final Phone[] mPhones;
     private final LocalLog mLocalLog;
 
-    private int mDefaultDataSubscription;
+    protected int mDefaultDataSubscription;
 
-    private final static int EVENT_DEFAULT_SUBSCRIPTION_CHANGED = 101;
-    private final static int EVENT_SUBSCRIPTION_CHANGED         = 102;
+    protected final static int EVENT_DEFAULT_SUBSCRIPTION_CHANGED = 101;
+    protected final static int EVENT_SUBSCRIPTION_CHANGED         = 102;
     private final static int EVENT_REQUEST_NETWORK              = 103;
     private final static int EVENT_RELEASE_NETWORK              = 104;
     private final static int EVENT_EMERGENCY_TOGGLE             = 105;
     private final static int EVENT_RESEND_DATA_ALLOWED          = 106;
+    protected final static int EVENT_VOICE_CALL_ENDED           = 107;
+    protected static final int EVENT_UNSOL_MAX_DATA_ALLOWED_CHANGED = 108;
+    protected static final int EVENT_OEM_HOOK_SERVICE_READY     = 109;
 
     private final static int MAX_LOCAL_LOG_LINES = 30;
 
@@ -204,7 +207,7 @@
         }
     }
 
-    private boolean isEmergency() {
+    protected boolean isEmergency() {
         for (Phone p : mPhones) {
             if (p == null) continue;
             if (p.isInEcm() || p.isInEmergencyCall()) return true;
@@ -255,7 +258,7 @@
     }
 
     private static final boolean REQUESTS_CHANGED   = true;
-    private static final boolean REQUESTS_UNCHANGED = false;
+    protected static final boolean REQUESTS_UNCHANGED = false;
     /**
      * Re-evaluate things.
      * Do nothing if nothing's changed.
@@ -265,7 +268,7 @@
      * phones that aren't in the active phone list.  Finally, activate all
      * phones in the active phone list.
      */
-    private void onEvaluate(boolean requestsChanged, String reason) {
+    protected void onEvaluate(boolean requestsChanged, String reason) {
         StringBuilder sb = new StringBuilder(reason);
         if (isEmergency()) {
             log("onEvalute aborted due to Emergency");
@@ -326,12 +329,12 @@
         }
     }
 
-    private static class PhoneState {
+    protected static class PhoneState {
         public volatile boolean active = false;
         public long lastRequested = 0;
     }
 
-    private void deactivate(int phoneId) {
+    protected void deactivate(int phoneId) {
         PhoneState state = mPhoneStates[phoneId];
         if (state.active == false) return;
         state.active = false;
@@ -344,7 +347,7 @@
         mActivePhoneRegistrants[phoneId].notifyRegistrants();
     }
 
-    private void activate(int phoneId) {
+    protected void activate(int phoneId) {
         PhoneState state = mPhoneStates[phoneId];
         if (state.active == true) return;
         state.active = true;
@@ -366,7 +369,7 @@
         msg.sendToTarget();
     }
 
-    private void onResendDataAllowed(Message msg) {
+    protected void onResendDataAllowed(Message msg) {
         final int phoneId = msg.arg1;
         // Skip ALLOW_DATA for single SIM device
         if (mNumPhones > 1) {
@@ -374,7 +377,7 @@
         }
     }
 
-    private int phoneIdForRequest(NetworkRequest netRequest) {
+    protected int phoneIdForRequest(NetworkRequest netRequest) {
         NetworkSpecifier specifier = netRequest.networkCapabilities.getNetworkSpecifier();
         int subId;
 
@@ -427,7 +430,7 @@
         }
     }
 
-    private void log(String l) {
+    protected void log(String l) {
         Rlog.d(LOG_TAG, l);
         mLocalLog.log(l);
     }
diff --git a/src/java/com/android/internal/telephony/RIL.java b/src/java/com/android/internal/telephony/RIL.java
index 9e74ee2..eeeb3c4 100644
--- a/src/java/com/android/internal/telephony/RIL.java
+++ b/src/java/com/android/internal/telephony/RIL.java
@@ -20,6 +20,7 @@
 import static com.android.internal.util.Preconditions.checkNotNull;
 
 import android.content.Context;
+import android.content.res.Resources;
 import android.hardware.radio.V1_0.Carrier;
 import android.hardware.radio.V1_0.CarrierRestrictions;
 import android.hardware.radio.V1_0.CdmaBroadcastSmsConfigInfo;
@@ -71,6 +72,7 @@
 import android.os.WorkSource;
 import android.service.carrier.CarrierIdentifier;
 import android.telephony.AccessNetworkConstants.AccessNetworkType;
+import android.telephony.CarrierConfigManager;
 import android.telephony.CellIdentity;
 import android.telephony.CellIdentityCdma;
 import android.telephony.CellInfo;
@@ -119,6 +121,18 @@
 import java.util.concurrent.atomic.AtomicBoolean;
 import java.util.concurrent.atomic.AtomicLong;
 
+import static android.telephony.TelephonyManager.NETWORK_TYPE_UNKNOWN;
+import static android.telephony.TelephonyManager.NETWORK_TYPE_GPRS;
+import static android.telephony.TelephonyManager.NETWORK_TYPE_EDGE;
+import static android.telephony.TelephonyManager.NETWORK_TYPE_UMTS;
+import static android.telephony.TelephonyManager.NETWORK_TYPE_HSDPA;
+import static android.telephony.TelephonyManager.NETWORK_TYPE_HSUPA;
+import static android.telephony.TelephonyManager.NETWORK_TYPE_HSPA;
+import static android.telephony.TelephonyManager.NETWORK_TYPE_LTE;
+import static android.telephony.TelephonyManager.NETWORK_TYPE_HSPAP;
+import static android.telephony.TelephonyManager.NETWORK_TYPE_GSM;
+import static android.telephony.TelephonyManager.NETWORK_TYPE_LTE_CA;
+
 /**
  * RIL implementation of the CommandsInterface.
  *
@@ -174,9 +188,10 @@
     AtomicBoolean mTestingEmergencyCall = new AtomicBoolean(false);
 
     final Integer mPhoneId;
+    private List<String> mOldRilFeatures;
 
     /* default work source which will blame phone process */
-    private WorkSource mRILDefaultWorkSource;
+    protected WorkSource mRILDefaultWorkSource;
 
     /* Worksource containing all applications causing wakelock to be held */
     private WorkSource mActiveWakelockWorkSource;
@@ -184,7 +199,7 @@
     /** Telephony metrics instance for logging metrics event */
     private TelephonyMetrics mMetrics = TelephonyMetrics.getInstance();
 
-    boolean mIsMobileNetworkSupported;
+    protected boolean mIsMobileNetworkSupported;
     RadioResponse mRadioResponse;
     RadioIndication mRadioIndication;
     volatile IRadio mRadioProxy = null;
@@ -195,6 +210,9 @@
     final RadioProxyDeathRecipient mRadioProxyDeathRecipient;
     final RilHandler mRilHandler;
 
+    private static RIL sRil;
+    private static int[][] sSignalCust;
+
     //***** Events
     static final int EVENT_WAKE_LOCK_TIMEOUT    = 2;
     static final int EVENT_ACK_WAKE_LOCK_TIMEOUT    = 4;
@@ -331,7 +349,7 @@
         }
     }
 
-    private void resetProxyAndRequestList() {
+    protected void resetProxyAndRequestList() {
         mRadioProxy = null;
         mOemHookProxy = null;
 
@@ -456,6 +474,9 @@
         mPhoneType = RILConstants.NO_PHONE;
         mPhoneId = instanceId;
 
+        final String oldRilFeatures = SystemProperties.get("ro.telephony.ril.config", "");
+        mOldRilFeatures = Arrays.asList(oldRilFeatures.split(","));
+
         ConnectivityManager cm = (ConnectivityManager)context.getSystemService(
                 Context.CONNECTIVITY_SERVICE);
         mIsMobileNetworkSupported = cm.isNetworkSupported(ConnectivityManager.TYPE_MOBILE);
@@ -467,6 +488,49 @@
         mRilHandler = new RilHandler();
         mRadioProxyDeathRecipient = new RadioProxyDeathRecipient();
 
+        sRil = this;
+
+        // Create custom signal strength thresholds based on Huawei's
+        if (sSignalCust == null) {
+            final int THRESHOLDS = 4;
+            final int STEPS = THRESHOLDS - 1;
+            sSignalCust = new int[3][THRESHOLDS];
+            String[][] hwSignalCust = {
+                   SystemProperties.get("gsm.sigcust.gsm",
+                           "5,false,-109,-103,-97,-91,-85").split(","),
+                   SystemProperties.get("gsm.sigcust.lte",
+                           "5,false,-120,-115,-110,-105,-97").split(","),
+                   SystemProperties.get("gsm.sigcust.umts",
+                           "5,false,-112,-105,-99,-93,-87").split(",")
+            };
+            for (int i = 0; i < sSignalCust.length; i++) {
+                // Get the highest and the lowest dBm values
+                int max = Integer.parseInt(hwSignalCust[i][hwSignalCust[i].length - 1]);
+                int min = Integer.parseInt(hwSignalCust[i][hwSignalCust[i].length -
+                        Integer.parseInt(hwSignalCust[i][0])]);
+                // Default distance between thresholds
+                int step = (max - min) / STEPS;
+                // Extra distance that needs to be accounted for
+                int rem = (max - min) % STEPS;
+
+                // Fill the array with the basic step distance
+                for (int j = 0; j < sSignalCust[i].length; j++) {
+                    sSignalCust[i][j] = min + step * j;
+                }
+
+                // Make the max line up
+                sSignalCust[i][sSignalCust[i].length - 1] += rem;
+
+                // Distribute the remainder
+                int j = sSignalCust[i].length - 2;
+                while (rem > 0 && j > 0) {
+                    sSignalCust[i][j]++;
+                    j--;
+                    rem--;
+                }
+            }
+        }
+
         PowerManager pm = (PowerManager)context.getSystemService(Context.POWER_SERVICE);
         mWakeLock = pm.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, RILJ_WAKELOCK_TAG);
         mWakeLock.setReferenceCounted(false);
@@ -515,6 +579,12 @@
         return rr;
     }
 
+    protected int obtainRequestSerial(int request, Message result, WorkSource workSource) {
+        RILRequest rr = RILRequest.obtain(request, result, workSource);
+        addRequest(rr);
+        return rr.mSerial;
+    }
+
     private void handleRadioProxyExceptionForRR(RILRequest rr, String caller, Exception e) {
         riljLoge(caller + ": " + e);
         resetProxyAndRequestList();
@@ -3315,8 +3385,7 @@
     }
 
     @Override
-    public void setUiccSubscription(int slotId, int appIndex, int subId,
-                                    int subStatus, Message result) {
+    public void setUiccSubscription(int appIndex, boolean activate, Message result) {
         IRadio radioProxy = getRadioProxy(result);
         if (radioProxy != null) {
             RILRequest rr = obtainRequest(RIL_REQUEST_SET_UICC_SUBSCRIPTION, result,
@@ -3324,15 +3393,14 @@
 
             if (RILJ_LOGD) {
                 riljLog(rr.serialString() + "> " + requestToString(rr.mRequest)
-                        + " slot = " + slotId + " appIndex = " + appIndex
-                        + " subId = " + subId + " subStatus = " + subStatus);
+                        + " appIndex: " + appIndex + " activate: " + activate);
             }
 
             SelectUiccSub info = new SelectUiccSub();
-            info.slot = slotId;
+            info.slot = mPhoneId;
             info.appIndex = appIndex;
-            info.subType = subId;
-            info.actStatus = subStatus;
+            info.subType = mPhoneId;
+            info.actStatus = activate ? 1 : 0;
 
             try {
                 radioProxy.setUiccSubscription(rr.mSerial, info);
@@ -4196,6 +4264,15 @@
         return rr;
     }
 
+    protected Message getMessageFromRequest(Object request) {
+        RILRequest rr = (RILRequest)request;
+        Message result = null;
+        if (rr != null) {
+                result = rr.mResult;
+        }
+        return result;
+    }
+
     /**
      * This is a helper function to be called at the end of all RadioResponse callbacks.
      * It takes care of sending error response, logging, decrementing wakelock if needed, and
@@ -4228,6 +4305,11 @@
         }
     }
 
+    protected void processResponseDone(Object request, RadioResponseInfo responseInfo, Object ret) {
+        RILRequest rr = (RILRequest)request;
+        processResponseDone(rr, responseInfo, ret);
+    }
+
     /**
      * Function to send ack and acquire related wakelock
      */
@@ -5502,10 +5584,159 @@
         return response;
     }
 
+    static SignalStrength convertHalSignalStrengthHuawei(
+            android.hardware.radio.V1_0.SignalStrength signalStrength, int phoneId) {
+        int gsmSignalStrength = signalStrength.gw.signalStrength;
+        int gsmBitErrorRate = signalStrength.gw.bitErrorRate;
+        int cdmaDbm = signalStrength.cdma.dbm;
+        int cdmaEcio = signalStrength.cdma.ecio;
+        int evdoDbm = signalStrength.evdo.dbm;
+        int evdoEcio = signalStrength.evdo.ecio;
+        int evdoSnr = signalStrength.evdo.signalNoiseRatio;
+        int lteSignalStrength = signalStrength.lte.signalStrength;
+        int lteRsrp = signalStrength.lte.rsrp;
+        int lteRsrq = signalStrength.lte.rsrq;
+        int lteRssnr = signalStrength.lte.rssnr;
+        int lteCqi = signalStrength.lte.cqi;
+
+        int tdscdmaRscp_1_2 = 255; // 255 is the value for unknown/unreported ASU.
+        // The HAL 1.0 range is 25..120; the ASU/ HAL 1.2 range is 0..96;
+        // yes, this means the range in 1.0 cannot express -24dBm = 96
+        if (signalStrength.tdScdma.rscp >= 25 && signalStrength.tdScdma.rscp <= 120) {
+            // First we flip the sign to convert from the HALs -rscp to the actual RSCP value.
+            int rscpDbm = -signalStrength.tdScdma.rscp;
+            // Then to convert from RSCP to ASU, we apply the offset which aligns 0 ASU to -120dBm.
+            tdscdmaRscp_1_2 = rscpDbm + 120;
+        }
+
+        TelephonyManager tm = (TelephonyManager)
+                sRil.mContext.getSystemService(Context.TELEPHONY_SERVICE);
+        int radioTech = tm.getDataNetworkType(phoneId);
+
+        if (radioTech == NETWORK_TYPE_UNKNOWN) {
+            radioTech = tm.getVoiceNetworkType(phoneId);
+        }
+
+        int[] threshRsrp = CarrierConfigManager.getDefaultConfig().getIntArray(
+                CarrierConfigManager.KEY_LTE_RSRP_THRESHOLDS_INT_ARRAY);
+
+         if (sSignalCust != null && threshRsrp.length == 4) {
+            switch (radioTech) {
+                case NETWORK_TYPE_LTE_CA:
+                case NETWORK_TYPE_LTE:
+                    if (lteRsrp > -44) { // None or Unknown
+                        lteRsrp = -43;
+                        lteRssnr = 301;
+                        lteSignalStrength = 99;
+                    } else if (lteRsrp >= sSignalCust[1][3]) { // Great
+                        lteRsrp = threshRsrp[3];
+                        lteRssnr = 130;
+                        lteSignalStrength = 12;
+                    } else if (lteRsrp >= sSignalCust[1][2]) { // Good
+                        lteRsrp = threshRsrp[2];
+                        lteRssnr = 45;
+                        lteSignalStrength = 8;
+                    } else if (lteRsrp >= sSignalCust[1][1]) { // Moderate
+                        lteRsrp = threshRsrp[1];
+                        lteRssnr = 10;
+                        lteSignalStrength = 5;
+                    } else if (lteRsrp >= sSignalCust[1][0]) { // Poor
+                        lteRsrp = threshRsrp[0];
+                        lteRssnr = -30;
+                        lteSignalStrength = 0;
+                    } else { // None or Unknown
+                        lteRsrp = -140;
+                        lteRssnr = -200;
+                        lteSignalStrength = 99;
+                    }
+                    break;
+                case NETWORK_TYPE_HSPAP:
+                case NETWORK_TYPE_HSPA:
+                case NETWORK_TYPE_HSUPA:
+                case NETWORK_TYPE_HSDPA:
+                case NETWORK_TYPE_UMTS:
+                    lteRsrp = (gsmSignalStrength & 0xFF) - 256;
+                    if (lteRsrp > -20) { // None or Unknown
+                        lteRsrp = -43;
+                        lteRssnr = 301;
+                        lteSignalStrength = 99;
+                    } else if (lteRsrp >= sSignalCust[2][3]) { // Great
+                        lteRsrp = threshRsrp[3];
+                        lteRssnr = 130;
+                        lteSignalStrength = 12;
+                    } else if (lteRsrp >= sSignalCust[2][2]) { // Good
+                        lteRsrp = threshRsrp[2];
+                        lteRssnr = 45;
+                        lteSignalStrength = 8;
+                    } else if (lteRsrp >= sSignalCust[2][1]) { // Moderate
+                        lteRsrp = threshRsrp[1];
+                        lteRssnr = 10;
+                        lteSignalStrength = 5;
+                    } else if (lteRsrp >= sSignalCust[2][0]) { // Poor
+                        lteRsrp = threshRsrp[0];
+                        lteRssnr = -30;
+                        lteSignalStrength = 0;
+                    } else { // None or Unknown
+                        lteRsrp = -140;
+                        lteRssnr = -200;
+                        lteSignalStrength = 99;
+                    }
+                    break;
+                default:
+                    lteRsrp = (gsmSignalStrength & 0xFF) - 256;
+                    if (lteRsrp > -20) { // None or Unknown
+                        lteRsrp = -43;
+                        lteRssnr = 301;
+                        lteSignalStrength = 99;
+                    } else if (lteRsrp >= sSignalCust[0][3]) { // Great
+                        lteRsrp = threshRsrp[3];
+                        lteRssnr = 130;
+                        lteSignalStrength = 12;
+                    } else if (lteRsrp >= sSignalCust[0][2]) { // Good
+                        lteRsrp = threshRsrp[2];
+                        lteRssnr = 45;
+                        lteSignalStrength = 8;
+                    } else if (lteRsrp >= sSignalCust[0][1]) { // Moderate
+                        lteRsrp = threshRsrp[1];
+                        lteRssnr = 10;
+                        lteSignalStrength = 5;
+                    } else if (lteRsrp >= sSignalCust[0][0]) { // Poor
+                        lteRsrp = threshRsrp[0];
+                        lteRssnr = -30;
+                        lteSignalStrength = 0;
+                    } else { // None or Unknown
+                        lteRsrp = -140;
+                        lteRssnr = -200;
+                        lteSignalStrength = 99;
+                    }
+            }
+        }
+
+        return new SignalStrength(gsmSignalStrength,
+                gsmSignalStrength,
+                cdmaDbm,
+                cdmaEcio,
+                evdoDbm,
+                evdoEcio,
+                evdoSnr,
+                lteSignalStrength,
+                lteRsrp,
+                lteRsrq,
+                lteRssnr,
+                lteCqi,
+                tdscdmaRscp_1_2);
+    }
+
     /** Convert HAL 1.0 Signal Strength to android SignalStrength */
     @VisibleForTesting
     public static SignalStrength convertHalSignalStrength(
-            android.hardware.radio.V1_0.SignalStrength signalStrength) {
+            android.hardware.radio.V1_0.SignalStrength signalStrength, int phoneId) {
+ 	Boolean prop = android.os.SystemProperties.getBoolean("ro.telephony.isHisiRIL", false);
+
+        if (prop && phoneId >= 0) {
+            return convertHalSignalStrengthHuawei(signalStrength, phoneId);
+        }
+
         int tdscdmaRscp_1_2 = 255; // 255 is the value for unknown/unreported ASU.
         // The HAL 1.0 range is 25..120; the ASU/ HAL 1.2 range is 0..96;
         // yes, this means the range in 1.0 cannot express -24dBm = 96
@@ -5531,6 +5762,11 @@
                 tdscdmaRscp_1_2);
     }
 
+    static SignalStrength convertHalSignalStrength(
+            android.hardware.radio.V1_0.SignalStrength signalStrength) {
+        return convertHalSignalStrength(signalStrength, -1);
+    }
+
     /** Convert HAL 1.2 Signal Strength to android SignalStrength */
     @VisibleForTesting
     public static SignalStrength convertHalSignalStrength_1_2(
@@ -5552,4 +5788,8 @@
                 signalStrength.wcdma.base.signalStrength,
                 signalStrength.wcdma.rscp);
     }
+
+    public boolean needsOldRilFeature(String feature) {
+        return mOldRilFeatures.contains(feature);
+    }
 }
diff --git a/src/java/com/android/internal/telephony/RadioIndication.java b/src/java/com/android/internal/telephony/RadioIndication.java
index f7a7943..49b526c 100644
--- a/src/java/com/android/internal/telephony/RadioIndication.java
+++ b/src/java/com/android/internal/telephony/RadioIndication.java
@@ -228,7 +228,7 @@
                                       android.hardware.radio.V1_0.SignalStrength signalStrength) {
         mRil.processIndication(indicationType);
 
-        SignalStrength ss = RIL.convertHalSignalStrength(signalStrength);
+        SignalStrength ss = RIL.convertHalSignalStrength(signalStrength, mRil.mPhoneId);
         // Note this is set to "verbose" because it happens frequently
         if (RIL.RILJ_LOGV) mRil.unsljLogvRet(RIL_UNSOL_SIGNAL_STRENGTH, ss);
 
diff --git a/src/java/com/android/internal/telephony/RadioResponse.java b/src/java/com/android/internal/telephony/RadioResponse.java
index e790ab6..5201f8b 100644
--- a/src/java/com/android/internal/telephony/RadioResponse.java
+++ b/src/java/com/android/internal/telephony/RadioResponse.java
@@ -1694,7 +1694,7 @@
         RILRequest rr = mRil.processResponse(responseInfo);
 
         if (rr != null) {
-            SignalStrength ret = RIL.convertHalSignalStrength(signalStrength);
+            SignalStrength ret = RIL.convertHalSignalStrength(signalStrength, mRil.mPhoneId);
             if (responseInfo.error == RadioError.NONE) {
                 sendMessageResponse(rr.mResult, ret);
             }
diff --git a/src/java/com/android/internal/telephony/ServiceStateTracker.java b/src/java/com/android/internal/telephony/ServiceStateTracker.java
index 04241c8..6355627 100644
--- a/src/java/com/android/internal/telephony/ServiceStateTracker.java
+++ b/src/java/com/android/internal/telephony/ServiceStateTracker.java
@@ -146,7 +146,7 @@
      * expected responses in this pollingContext.
      */
     @VisibleForTesting
-    public int[] mPollingContext;
+    protected int[] mPollingContext;
     private boolean mDesiredPowerState;
 
     /**
@@ -287,7 +287,7 @@
             int subId = mPhone.getSubId();
             ServiceStateTracker.this.mPrevSubId = mPreviousSubId.get();
             if (mPreviousSubId.getAndSet(subId) != subId) {
-                if (SubscriptionManager.isValidSubscriptionId(subId)) {
+                if (mSubscriptionController.isActiveSubId(subId)) {
                     Context context = mPhone.getContext();
 
                     mPhone.notifyPhoneStateChanged();
@@ -346,7 +346,7 @@
     };
 
     //Common
-    private final GsmCdmaPhone mPhone;
+    protected final GsmCdmaPhone mPhone;
 
     public CellLocation mCellLoc;
     private CellLocation mNewCellLoc;
@@ -1792,7 +1792,7 @@
         return cdmaRoaming && !isSameOperatorNameFromSimAndSS(s);
     }
 
-    void handlePollStateResultMessage(int what, AsyncResult ar) {
+    protected void handlePollStateResultMessage(int what, AsyncResult ar) {
         int ints[];
         switch (what) {
             case EVENT_POLL_STATE_REGISTRATION: {
diff --git a/src/java/com/android/internal/telephony/SubscriptionController.java b/src/java/com/android/internal/telephony/SubscriptionController.java
index fd12273..2437a8d 100644
--- a/src/java/com/android/internal/telephony/SubscriptionController.java
+++ b/src/java/com/android/internal/telephony/SubscriptionController.java
@@ -85,8 +85,8 @@
  */
 public class SubscriptionController extends ISub.Stub {
     static final String LOG_TAG = "SubscriptionController";
-    static final boolean DBG = true;
-    static final boolean VDBG = false;
+    protected static final boolean DBG = true;
+    protected static final boolean VDBG = false;
     static final boolean DBG_CACHE = false;
     static final int MAX_LOCAL_LOG_LINES = 500; // TODO: Reduce to 100 when 17678050 is fixed
     private static final int DEPRECATED_SETTING = -1;
@@ -147,7 +147,7 @@
     protected final Object mLock = new Object();
 
     /** The singleton instance. */
-    private static SubscriptionController sInstance = null;
+    protected static SubscriptionController sInstance = null;
     protected static Phone[] sPhones;
     protected Context mContext;
     protected TelephonyManager mTelephonyManager;
@@ -158,8 +158,8 @@
     // FIXME: Does not allow for multiple subs in a slot and change to SparseArray
     private static Map<Integer, Integer> sSlotIndexToSubId =
             new ConcurrentHashMap<Integer, Integer>();
-    private static int mDefaultFallbackSubId = SubscriptionManager.INVALID_SUBSCRIPTION_ID;
-    private static int mDefaultPhoneId = SubscriptionManager.DEFAULT_PHONE_INDEX;
+    protected static int mDefaultFallbackSubId = SubscriptionManager.INVALID_SUBSCRIPTION_ID;
+    protected static int mDefaultPhoneId = SubscriptionManager.DEFAULT_PHONE_INDEX;
 
     private int[] colorArr;
     private long mLastISubServiceRegTime;
@@ -233,7 +233,7 @@
         if (DBG) logdl("[SubscriptionController] init by Phone");
     }
 
-    private void enforceModifyPhoneState(String message) {
+    protected void enforceModifyPhoneState(String message) {
         mContext.enforceCallingOrSelfPermission(
                 android.Manifest.permission.MODIFY_PHONE_STATE, message);
     }
@@ -895,6 +895,19 @@
      */
     @Override
     public int addSubInfoRecord(String iccId, int slotIndex) {
+        String fullIccId;
+        Phone phone = PhoneFactory.getPhone(slotIndex);
+        UiccCard uiccCard = UiccController.getInstance().getUiccCardForSlot(slotIndex);
+        if (phone != null && uiccCard != null) {
+            fullIccId = phone.getFullIccSerialNumber();
+            if (TextUtils.isEmpty(fullIccId)) {
+                fullIccId = iccId;
+            }
+        } else {
+            if (DBG) logdl("[addSubInfoRecord]- null fullIccId");
+            return -1;
+        }
+
         if (DBG) logdl("[addSubInfoRecord]+ iccId:" + SubscriptionInfo.givePrintableIccid(iccId) +
                 " slotIndex:" + slotIndex);
 
@@ -913,8 +926,10 @@
                     new String[]{SubscriptionManager.UNIQUE_KEY_SUBSCRIPTION_ID,
                             SubscriptionManager.SIM_SLOT_INDEX, SubscriptionManager.NAME_SOURCE,
                             SubscriptionManager.ICC_ID, SubscriptionManager.CARD_ID},
-                    SubscriptionManager.ICC_ID + "=?" + " OR " + SubscriptionManager.ICC_ID + "=?",
-                            new String[]{iccId, IccUtils.getDecimalSubstring(iccId)}, null);
+                    SubscriptionManager.ICC_ID + "=?" + " OR " + SubscriptionManager.ICC_ID + "=?"
+                             + " OR " + SubscriptionManager.ICC_ID + "=?" + " collate nocase",
+                            new String[]{iccId, IccUtils.getDecimalSubstring(iccId), fullIccId},
+                            null);
 
             boolean setDisplayName = false;
             try {
@@ -938,8 +953,9 @@
                         setDisplayName = true;
                     }
 
-                    if (oldIccId != null && oldIccId.length() < iccId.length()
-                            && (oldIccId.equals(IccUtils.getDecimalSubstring(iccId)))) {
+                    if (oldIccId != null && oldIccId.length() != iccId.length()
+                           && (oldIccId.equals(IccUtils.getDecimalSubstring(iccId))
+                           || iccId.equalsIgnoreCase(IccUtils.stripTrailingFs(oldIccId)))) {
                         value.put(SubscriptionManager.ICC_ID, iccId);
                     }
 
@@ -955,9 +971,6 @@
                         resolver.update(SubscriptionManager.CONTENT_URI, value,
                                 SubscriptionManager.UNIQUE_KEY_SUBSCRIPTION_ID +
                                         "=" + Long.toString(subId), null);
-
-                        // Refresh the Cache of Active Subscription Info List
-                        refreshCachedActiveSubscriptionInfoList();
                     }
 
                     if (DBG) logdl("[addSubInfoRecord] Record already exists");
@@ -1000,7 +1013,7 @@
 
                             // Set the default sub if not set or if single sim device
                             if (!SubscriptionManager.isValidSubscriptionId(defaultSubId)
-                                    || subIdCountMax == 1) {
+                                    || (subIdCountMax == 1) || (!isActiveSubId(defaultSubId))) {
                                 setDefaultFallbackSubId(subId);
                             }
                             // If single sim device, set this subscription as the default for everything
@@ -1051,12 +1064,12 @@
                         SubscriptionManager.UNIQUE_KEY_SUBSCRIPTION_ID +
                                 "=" + Long.toString(subId), null);
 
-                // Refresh the Cache of Active Subscription Info List
-                refreshCachedActiveSubscriptionInfoList();
-
                 if (DBG) logdl("[addSubInfoRecord] sim name = " + nameToSet);
             }
 
+            // Refresh the Cache of Active Subscription Info List
+            refreshCachedActiveSubscriptionInfoList();
+
             // Once the records are loaded, notify DcTracker
             sPhones[slotIndex].updateDataConnectionTracker();
 
@@ -1100,9 +1113,6 @@
 
         Uri uri = resolver.insert(SubscriptionManager.CONTENT_URI, value);
 
-        // Refresh the Cache of Active Subscription Info List
-        refreshCachedActiveSubscriptionInfoList();
-
         return uri;
     }
 
@@ -1536,7 +1546,7 @@
 
     }
 
-    private int[] getDummySubIds(int slotIndex) {
+    protected int[] getDummySubIds(int slotIndex) {
         // FIXME: Remove notion of Dummy SUBSCRIPTION_ID.
         // I tested this returning null as no one appears to care,
         // but no connection came up on sprout with two sims.
@@ -1582,21 +1592,21 @@
         }
     }
 
-    private void logvl(String msg) {
+    protected void logvl(String msg) {
         logv(msg);
         mLocalLog.log(msg);
     }
 
-    private void logv(String msg) {
+    protected void logv(String msg) {
         Rlog.v(LOG_TAG, msg);
     }
 
-    private void logdl(String msg) {
+    protected void logdl(String msg) {
         logd(msg);
         mLocalLog.log(msg);
     }
 
-    private static void slogd(String msg) {
+    protected static void slogd(String msg) {
         Rlog.d(LOG_TAG, msg);
     }
 
@@ -1604,7 +1614,7 @@
         Rlog.d(LOG_TAG, msg);
     }
 
-    private void logel(String msg) {
+    protected void logel(String msg) {
         loge(msg);
         mLocalLog.log(msg);
     }
@@ -1758,7 +1768,7 @@
         broadcastDefaultDataSubIdChanged(subId);
     }
 
-    private void updateAllDataConnectionTrackers() {
+    protected void updateAllDataConnectionTrackers() {
         // Tell Phone Proxies to update data connection tracker
         int len = sPhones.length;
         if (DBG) logdl("[updateAllDataConnectionTrackers] sPhones.length=" + len);
@@ -1768,7 +1778,7 @@
         }
     }
 
-    private void broadcastDefaultDataSubIdChanged(int subId) {
+    protected void broadcastDefaultDataSubIdChanged(int subId) {
         // Broadcast an Intent for default data sub change
         if (DBG) logdl("[broadcastDefaultDataSubIdChanged] subId=" + subId);
         Intent intent = new Intent(TelephonyIntents.ACTION_DEFAULT_DATA_SUBSCRIPTION_CHANGED);
@@ -1782,7 +1792,7 @@
      * sub is set as default subId. If two or more  sub's are active
      * the first sub is set as default subscription
      */
-    private void setDefaultFallbackSubId(int subId) {
+    protected void setDefaultFallbackSubId(int subId) {
         if (subId == SubscriptionManager.DEFAULT_SUBSCRIPTION_ID) {
             throw new RuntimeException("setDefaultSubId called with DEFAULT_SUB_ID");
         }
@@ -1843,7 +1853,7 @@
         }
     }
 
-    private boolean shouldDefaultBeCleared(List<SubscriptionInfo> records, int subId) {
+    protected boolean shouldDefaultBeCleared(List<SubscriptionInfo> records, int subId) {
         if (DBG) logdl("[shouldDefaultBeCleared: subId] " + subId);
         if (records == null) {
             if (DBG) logdl("[shouldDefaultBeCleared] return true no records subId=" + subId);
@@ -2116,7 +2126,7 @@
         return resultValue;
     }
 
-    private static void printStackTrace(String msg) {
+    protected static void printStackTrace(String msg) {
         RuntimeException re = new RuntimeException();
         slogd("StackTrace - " + msg);
         StackTraceElement[] st = re.getStackTrace();
diff --git a/src/java/com/android/internal/telephony/SubscriptionInfoUpdater.java b/src/java/com/android/internal/telephony/SubscriptionInfoUpdater.java
index 1a4ed5b..4a40a9a 100644
--- a/src/java/com/android/internal/telephony/SubscriptionInfoUpdater.java
+++ b/src/java/com/android/internal/telephony/SubscriptionInfoUpdater.java
@@ -53,6 +53,7 @@
 import com.android.internal.telephony.euicc.EuiccController;
 import com.android.internal.telephony.uicc.IccRecords;
 import com.android.internal.telephony.uicc.IccUtils;
+import com.android.internal.os.BackgroundThread;
 
 import java.io.FileDescriptor;
 import java.io.PrintWriter;
@@ -108,7 +109,7 @@
 
     private static Phone[] mPhone;
     private static Context mContext = null;
-    private static String mIccId[] = new String[PROJECT_SIM_NUM];
+    protected static String mIccId[] = new String[PROJECT_SIM_NUM];
     private static int[] mInsertSimState = new int[PROJECT_SIM_NUM];
     private static int[] sSimCardState = new int[PROJECT_SIM_NUM];
     private static int[] sSimApplicationState = new int[PROJECT_SIM_NUM];
@@ -142,6 +143,11 @@
         initializeCarrierApps();
     }
 
+    public SubscriptionInfoUpdater(Context context, Phone[] phone, CommandsInterface[] ci) {
+        this(BackgroundThread.get().getLooper(), context, phone, ci);
+
+    }
+
     private void initializeCarrierApps() {
         // Initialize carrier apps:
         // -Now (on system startup)
@@ -201,7 +207,7 @@
         }
     }
 
-    private boolean isAllIccIdQueryDone() {
+    protected boolean isAllIccIdQueryDone() {
         for (int i = 0; i < PROJECT_SIM_NUM; i++) {
             if (mIccId[i] == null) {
                 logd("Wait for SIM" + (i + 1) + " IccId");
@@ -302,7 +308,7 @@
         sendMessage(obtainMessage(EVENT_REFRESH_EMBEDDED_SUBSCRIPTIONS, callback));
     }
 
-    private void handleSimLocked(int slotId, String reason) {
+    protected void handleSimLocked(int slotId, String reason) {
         if (mIccId[slotId] != null && mIccId[slotId].equals(ICCID_STRING_FOR_NO_SIM)) {
             logd("SIM" + (slotId + 1) + " hot plug in");
             mIccId[slotId] = null;
@@ -355,7 +361,7 @@
         }
     }
 
-    private void handleSimLoaded(int slotId) {
+    protected void handleSimLoaded(int slotId) {
         logd("handleSimLoaded: slotId: " + slotId);
 
         // The SIM should be loaded at this state, but it is possible in cases such as SIM being
@@ -382,12 +388,10 @@
             updateSubscriptionInfoByIccId();
             int[] subIds = mSubscriptionManager.getActiveSubscriptionIdList();
             for (int subId : subIds) {
-                TelephonyManager tm = TelephonyManager.getDefault();
-
-                String operator = tm.getSimOperatorNumeric(subId);
                 slotId = SubscriptionController.getInstance().getPhoneId(subId);
+                String operator = mPhone[slotId].getOperatorNumeric();
 
-                if (!TextUtils.isEmpty(operator)) {
+                if (operator != null && !TextUtils.isEmpty(operator)) {
                     if (subId == SubscriptionController.getInstance().getDefaultSubId()) {
                         MccTable.updateMccMncConfiguration(mContext, operator, false);
                     }
@@ -396,6 +400,7 @@
                     logd("EVENT_RECORDS_LOADED Operator name is null");
                 }
 
+                TelephonyManager tm = TelephonyManager.getDefault();
                 String msisdn = tm.getLine1Number(subId);
                 ContentResolver contentResolver = mContext.getContentResolver();
 
@@ -480,9 +485,9 @@
         mCarrierServiceBindHelper.updateForPhoneId(slotId, simState);
     }
 
-    private void handleSimAbsent(int slotId) {
+    protected void handleSimAbsent(int slotId) {
         if (mIccId[slotId] != null && !mIccId[slotId].equals(ICCID_STRING_FOR_NO_SIM)) {
-            logd("SIM" + (slotId + 1) + " hot plug out");
+            logd("SIM" + (slotId + 1) + " hot plug out or error.");
         }
         mIccId[slotId] = ICCID_STRING_FOR_NO_SIM;
         if (isAllIccIdQueryDone()) {
@@ -494,7 +499,7 @@
         broadcastSimApplicationStateChanged(slotId, TelephonyManager.SIM_STATE_NOT_READY);
     }
 
-    private void handleSimError(int slotId) {
+    protected void handleSimError(int slotId) {
         if (mIccId[slotId] != null && !mIccId[slotId].equals(ICCID_STRING_FOR_NO_SIM)) {
             logd("SIM" + (slotId + 1) + " Error ");
         }
@@ -513,7 +518,7 @@
      * TODO: Simplify more, as no one is interested in what happened
      * only what the current list contains.
      */
-    synchronized private void updateSubscriptionInfoByIccId() {
+    synchronized protected void updateSubscriptionInfoByIccId() {
         logd("updateSubscriptionInfoByIccId:+ Start");
 
         for (int i = 0; i < PROJECT_SIM_NUM; i++) {
diff --git a/src/java/com/android/internal/telephony/TelephonyComponentFactory.java b/src/java/com/android/internal/telephony/TelephonyComponentFactory.java
index 8ad5720..4fc5ea8 100644
--- a/src/java/com/android/internal/telephony/TelephonyComponentFactory.java
+++ b/src/java/com/android/internal/telephony/TelephonyComponentFactory.java
@@ -23,6 +23,7 @@
 import android.os.Looper;
 import android.os.ServiceManager;
 import android.telephony.AccessNetworkConstants.TransportType;
+import android.telephony.Rlog;
 
 import com.android.internal.telephony.cdma.CdmaSubscriptionSourceManager;
 import com.android.internal.telephony.cdma.EriManager;
@@ -30,9 +31,16 @@
 import com.android.internal.telephony.imsphone.ImsExternalCallTracker;
 import com.android.internal.telephony.imsphone.ImsPhone;
 import com.android.internal.telephony.imsphone.ImsPhoneCallTracker;
+import com.android.internal.telephony.SubscriptionController;
 import com.android.internal.telephony.uicc.IccCardStatus;
 import com.android.internal.telephony.uicc.UiccCard;
 import com.android.internal.telephony.uicc.UiccProfile;
+import com.android.internal.os.BackgroundThread;
+
+
+import dalvik.system.PathClassLoader;
+
+import java.lang.reflect.Constructor;
 
 /**
  * This class has one-line methods to instantiate objects only. The purpose is to make code
@@ -40,28 +48,49 @@
  * this way makes it easier to mock them in tests.
  */
 public class TelephonyComponentFactory {
+    protected static String LOG_TAG = "TelephonyComponentFactory";
     private static TelephonyComponentFactory sInstance;
 
     public static TelephonyComponentFactory getInstance() {
         if (sInstance == null) {
-            sInstance = new TelephonyComponentFactory();
+            String fullClsName = "com.qualcomm.qti.internal.telephony.QtiTelephonyComponentFactory";
+            String libPath = "/system/framework/qti-telephony-common.jar";
+
+            try {
+                PathClassLoader classLoader = new PathClassLoader(libPath,
+                        ClassLoader.getSystemClassLoader());
+                Class<?> cls = Class.forName(fullClsName, false, classLoader);
+                Constructor custMethod = cls.getConstructor();
+                sInstance = (TelephonyComponentFactory) custMethod.newInstance();
+                Rlog.i(LOG_TAG, "Using QtiTelephonyComponentFactory");
+            } catch (NoClassDefFoundError | ClassNotFoundException e) {
+                Rlog.e(LOG_TAG, "QtiTelephonyComponentFactory not used - fallback to default");
+                sInstance = new TelephonyComponentFactory();
+            } catch (Exception e) {
+                Rlog.e(LOG_TAG, "Error loading QtiTelephonyComponentFactory - fallback to default");
+                sInstance = new TelephonyComponentFactory();
+            }
         }
         return sInstance;
     }
 
     public GsmCdmaCallTracker makeGsmCdmaCallTracker(GsmCdmaPhone phone) {
+        Rlog.d(LOG_TAG, "makeGsmCdmaCallTracker");
         return new GsmCdmaCallTracker(phone);
     }
 
     public SmsStorageMonitor makeSmsStorageMonitor(Phone phone) {
+        Rlog.d(LOG_TAG, "makeSmsStorageMonitor");
         return new SmsStorageMonitor(phone);
     }
 
     public SmsUsageMonitor makeSmsUsageMonitor(Context context) {
+        Rlog.d(LOG_TAG, "makeSmsUsageMonitor");
         return new SmsUsageMonitor(context);
     }
 
     public ServiceStateTracker makeServiceStateTracker(GsmCdmaPhone phone, CommandsInterface ci) {
+        Rlog.d(LOG_TAG, "makeServiceStateTracker");
         return new ServiceStateTracker(phone, ci);
     }
 
@@ -77,6 +106,7 @@
     }
 
     public DcTracker makeDcTracker(Phone phone) {
+        Rlog.d(LOG_TAG, "makeDcTracker");
         return new DcTracker(phone, TransportType.WWAN);
     }
 
@@ -93,10 +123,12 @@
     }
 
     public IccPhoneBookInterfaceManager makeIccPhoneBookInterfaceManager(Phone phone) {
+        Rlog.d(LOG_TAG, "makeIccPhoneBookInterfaceManager");
         return new IccPhoneBookInterfaceManager(phone);
     }
 
     public IccSmsInterfaceManager makeIccSmsInterfaceManager(Phone phone) {
+        Rlog.d(LOG_TAG, "makeIccSmsInterfaceManager");
         return new IccSmsInterfaceManager(phone);
     }
 
@@ -109,10 +141,12 @@
     }
 
     public EriManager makeEriManager(Phone phone, Context context, int eriFileSource) {
+        Rlog.d(LOG_TAG, "makeEriManager");
         return new EriManager(phone, context, eriFileSource);
     }
 
     public WspTypeDecoder makeWspTypeDecoder(byte[] pdu) {
+        Rlog.d(LOG_TAG, "makeWspTypeDecoder");
         return new WspTypeDecoder(pdu);
     }
 
@@ -122,6 +156,7 @@
     public InboundSmsTracker makeInboundSmsTracker(byte[] pdu, long timestamp, int destPort,
             boolean is3gpp2, boolean is3gpp2WapPdu, String address, String displayAddr,
             String messageBody) {
+        Rlog.d(LOG_TAG, "makeInboundSmsTracker");
         return new InboundSmsTracker(pdu, timestamp, destPort, is3gpp2, is3gpp2WapPdu, address,
                 displayAddr, messageBody);
     }
@@ -132,6 +167,7 @@
     public InboundSmsTracker makeInboundSmsTracker(byte[] pdu, long timestamp, int destPort,
             boolean is3gpp2, String address, String displayAddr, int referenceNumber, int sequenceNumber,
             int messageCount, boolean is3gpp2WapPdu, String messageBody) {
+        Rlog.d(LOG_TAG, "makeInboundSmsTracker");
         return new InboundSmsTracker(pdu, timestamp, destPort, is3gpp2, address, displayAddr,
                 referenceNumber, sequenceNumber, messageCount, is3gpp2WapPdu, messageBody);
     }
@@ -140,10 +176,12 @@
      * Create a tracker from a row of raw table
      */
     public InboundSmsTracker makeInboundSmsTracker(Cursor cursor, boolean isCurrentFormat3gpp2) {
+        Rlog.d(LOG_TAG, "makeInboundSmsTracker");
         return new InboundSmsTracker(cursor, isCurrentFormat3gpp2);
     }
 
     public ImsPhoneCallTracker makeImsPhoneCallTracker(ImsPhone imsPhone) {
+        Rlog.d(LOG_TAG, "makeImsPhoneCallTracker");
         return new ImsPhoneCallTracker(imsPhone);
     }
 
@@ -166,14 +204,61 @@
     public CdmaSubscriptionSourceManager
     getCdmaSubscriptionSourceManagerInstance(Context context, CommandsInterface ci, Handler h,
                                              int what, Object obj) {
+        Rlog.d(LOG_TAG, "getCdmaSubscriptionSourceManagerInstance");
         return CdmaSubscriptionSourceManager.getInstance(context, ci, h, what, obj);
     }
 
     public IDeviceIdleController getIDeviceIdleController() {
+        Rlog.d(LOG_TAG, "getIDeviceIdleController");
         return IDeviceIdleController.Stub.asInterface(
                 ServiceManager.getService(Context.DEVICE_IDLE_CONTROLLER));
     }
 
+    public Phone makePhone(Context context, CommandsInterface ci, PhoneNotifier notifier,
+            int phoneId, int precisePhoneType,
+            TelephonyComponentFactory telephonyComponentFactory) {
+        Rlog.d(LOG_TAG, "makePhone");
+        return new GsmCdmaPhone(context, ci, notifier, phoneId, precisePhoneType,
+                telephonyComponentFactory);
+    }
+
+    public SubscriptionController initSubscriptionController(Context c, CommandsInterface[] ci) {
+        Rlog.d(LOG_TAG, "initSubscriptionController");
+        return SubscriptionController.init(c, ci);
+    }
+
+    public SubscriptionInfoUpdater makeSubscriptionInfoUpdater(Context context,
+            Phone[] phones, CommandsInterface[] ci) {
+        Rlog.d(LOG_TAG, "makeSubscriptionInfoUpdater");
+        return new SubscriptionInfoUpdater(BackgroundThread.get().getLooper(), context, phones, ci);
+    }
+
+    public SubscriptionInfoUpdater makeSubscriptionInfoUpdater(Looper looper, Context context,
+            Phone[] phones, CommandsInterface[] ci) {
+        Rlog.d(LOG_TAG, "makeSubscriptionInfoUpdater");
+        return new SubscriptionInfoUpdater(looper, context, phones, ci);
+    }
+
+    public void makeExtTelephonyClasses(Context context,
+            Phone[] phones, CommandsInterface[] commandsInterfaces) {
+        Rlog.d(LOG_TAG, "makeExtTelephonyClasses");
+    }
+
+    public PhoneSwitcher makePhoneSwitcher(int maxActivePhones, int numPhones, Context context,
+            SubscriptionController subscriptionController, Looper looper, ITelephonyRegistry tr,
+            CommandsInterface[] cis, Phone[] phones) {
+        Rlog.d(LOG_TAG, "makePhoneSwitcher");
+        return new PhoneSwitcher(maxActivePhones,numPhones,
+                context, subscriptionController, looper, tr, cis,
+                phones);
+    }
+
+    public RIL makeRIL(Context context, int preferredNetworkType,
+            int cdmaSubscription, Integer instanceId) {
+        Rlog.d(LOG_TAG, "makeRIL");
+        return new RIL(context, preferredNetworkType, cdmaSubscription, instanceId);
+    }
+
     public LocaleTracker makeLocaleTracker(Phone phone, Looper looper) {
         return new LocaleTracker(phone, looper);
     }
diff --git a/src/java/com/android/internal/telephony/UiccPhoneBookController.java b/src/java/com/android/internal/telephony/UiccPhoneBookController.java
index f3019f0..40a2f49 100644
--- a/src/java/com/android/internal/telephony/UiccPhoneBookController.java
+++ b/src/java/com/android/internal/telephony/UiccPhoneBookController.java
@@ -18,6 +18,7 @@
 
 package com.android.internal.telephony;
 
+import android.content.ContentValues;
 import android.os.ServiceManager;
 import android.telephony.Rlog;
 
@@ -53,14 +54,13 @@
     updateAdnRecordsInEfBySearchForSubscriber(int subId, int efid, String oldTag,
             String oldPhoneNumber, String newTag, String newPhoneNumber,
             String pin2) throws android.os.RemoteException {
-        IccPhoneBookInterfaceManager iccPbkIntMgr =
-                             getIccPhoneBookInterfaceManager(subId);
+        IccPhoneBookInterfaceManager iccPbkIntMgr = getIccPhoneBookInterfaceManager(subId);
         if (iccPbkIntMgr != null) {
             return iccPbkIntMgr.updateAdnRecordsInEfBySearch(efid, oldTag,
                     oldPhoneNumber, newTag, newPhoneNumber, pin2);
         } else {
             Rlog.e(TAG,"updateAdnRecordsInEfBySearch iccPbkIntMgr is" +
-                      " null for Subscription:"+subId);
+                    " null for Subscription:" + subId);
             return false;
         }
     }
@@ -77,14 +77,13 @@
     public boolean
     updateAdnRecordsInEfByIndexForSubscriber(int subId, int efid, String newTag,
             String newPhoneNumber, int index, String pin2) throws android.os.RemoteException {
-        IccPhoneBookInterfaceManager iccPbkIntMgr =
-                             getIccPhoneBookInterfaceManager(subId);
+        IccPhoneBookInterfaceManager iccPbkIntMgr = getIccPhoneBookInterfaceManager(subId);
         if (iccPbkIntMgr != null) {
             return iccPbkIntMgr.updateAdnRecordsInEfByIndex(efid, newTag,
                     newPhoneNumber, index, pin2);
         } else {
             Rlog.e(TAG,"updateAdnRecordsInEfByIndex iccPbkIntMgr is" +
-                      " null for Subscription:"+subId);
+                    " null for Subscription:" + subId);
             return false;
         }
     }
@@ -127,6 +126,48 @@
         }
     }
 
+    @Override
+    public int[] getAdnRecordsCapacity() throws android.os.RemoteException {
+        return getAdnRecordsCapacityForSubscriber(getDefaultSubscription());
+    }
+
+    @Override
+    public int[] getAdnRecordsCapacityForSubscriber(int subId)
+           throws android.os.RemoteException {
+        IccPhoneBookInterfaceManager iccPbkIntMgr =
+                             getIccPhoneBookInterfaceManager(subId);
+        if (iccPbkIntMgr != null) {
+            return iccPbkIntMgr.getAdnRecordsCapacity();
+        } else {
+            Rlog.e(TAG,"getAdnRecordsCapacity iccPbkIntMgr is" +
+                      " null for Subscription:"+subId);
+            return null;
+        }
+    }
+
+    public boolean
+    updateAdnRecordsWithContentValuesInEfBySearch(int efid, ContentValues values,
+        String pin2) throws android.os.RemoteException {
+            return updateAdnRecordsWithContentValuesInEfBySearchUsingSubId(
+                getDefaultSubscription(), efid, values, pin2);
+    }
+
+    public boolean
+    updateAdnRecordsWithContentValuesInEfBySearchUsingSubId(int subId, int efid,
+        ContentValues values, String pin2)
+        throws android.os.RemoteException {
+        IccPhoneBookInterfaceManager iccPbkIntMgr =
+                             getIccPhoneBookInterfaceManager(subId);
+        if (iccPbkIntMgr != null) {
+            return iccPbkIntMgr.updateAdnRecordsWithContentValuesInEfBySearch(
+                efid, values, pin2);
+        } else {
+            Rlog.e(TAG,"updateAdnRecordsWithContentValuesInEfBySearchUsingSubId " +
+                "iccPbkIntMgr is null for Subscription:"+subId);
+            return false;
+        }
+    }
+
     /**
      * get phone book interface manager object based on subscription.
      **/
diff --git a/src/java/com/android/internal/telephony/dataconnection/DcTracker.java b/src/java/com/android/internal/telephony/dataconnection/DcTracker.java
index ea6fa81..4b7fb49 100644
--- a/src/java/com/android/internal/telephony/dataconnection/DcTracker.java
+++ b/src/java/com/android/internal/telephony/dataconnection/DcTracker.java
@@ -75,7 +75,8 @@
 import android.util.Pair;
 import android.util.SparseArray;
 import android.view.WindowManager;
-
+import com.android.internal.R;
+import com.android.internal.telephony.cdma.CdmaSubscriptionSourceManager;
 import com.android.internal.annotations.VisibleForTesting;
 import com.android.internal.telephony.CarrierActionAgent;
 import com.android.internal.telephony.DctConstants;
@@ -113,8 +114,8 @@
  * {@hide}
  */
 public class DcTracker extends Handler {
-    private static final String LOG_TAG = "DCT";
-    private static final boolean DBG = true;
+    protected String LOG_TAG = "DCT";
+    protected static final boolean DBG = true;
     private static final boolean VDBG = false; // STOPSHIP if true
     private static final boolean VDBG_STALL = false; // STOPSHIP if true
     private static final boolean RADIO_TESTS = false;
@@ -174,10 +175,10 @@
             } );
 
     /** allApns holds all apns */
-    private ArrayList<ApnSetting> mAllApnSettings = null;
+    protected ArrayList<ApnSetting> mAllApnSettings = null;
 
     /** preferred apn */
-    private ApnSetting mPreferredApn = null;
+    protected ApnSetting mPreferredApn = null;
 
     /** Is packet service restricted by network */
     private boolean mIsPsRestricted = false;
@@ -186,7 +187,7 @@
     private ApnSetting mEmergencyApn = null;
 
     /* Once disposed dont handle any messages */
-    private boolean mIsDisposed = false;
+    protected boolean mIsDisposed = false;
 
     private ContentResolver mResolver;
 
@@ -292,11 +293,11 @@
                     if (DBG) log("SubscriptionListener.onSubscriptionInfoChanged");
                     // Set the network type, in case the radio does not restore it.
                     int subId = mPhone.getSubId();
-                    if (SubscriptionManager.isValidSubscriptionId(subId)) {
+                    if (mSubscriptionManager.isActiveSubId(subId)) {
                         registerSettingsObserver();
                     }
                     if (mPreviousSubId.getAndSet(subId) != subId &&
-                            SubscriptionManager.isValidSubscriptionId(subId)) {
+                            mSubscriptionManager.isActiveSubId(subId)) {
                         onRecordsLoadedOrSubIdChanged();
                     }
                 }
@@ -390,7 +391,7 @@
 
         // Stop reconnect if not current subId is not correct.
         // FIXME STOPSHIP - phoneSubId is coming up as -1 way after boot and failing this?
-        if (!SubscriptionManager.isValidSubscriptionId(currSubId) || (currSubId != phoneSubId)) {
+        if (!mSubscriptionManager.isActiveSubId(currSubId) || (currSubId != phoneSubId)) {
             log("receive ReconnectAlarm but subId incorrect, ignore");
             return;
         }
@@ -452,11 +453,11 @@
     private RegistrantList mAllDataDisconnectedRegistrants = new RegistrantList();
 
     // member variables
-    private final Phone mPhone;
+    protected final Phone mPhone;
     private final UiccController mUiccController;
-    private final AtomicReference<IccRecords> mIccRecords = new AtomicReference<IccRecords>();
+    protected final AtomicReference<IccRecords> mIccRecords = new AtomicReference<IccRecords>();
     private DctConstants.Activity mActivity = DctConstants.Activity.NONE;
-    private DctConstants.State mState = DctConstants.State.IDLE;
+    protected DctConstants.State mState = DctConstants.State.IDLE;
     private final Handler mDataConnectionTracker;
 
     private long mTxPkts;
@@ -487,8 +488,8 @@
     private PendingIntent mReconnectIntent = null;
 
     // When false we will not auto attach and manually attaching is required.
-    private boolean mAutoAttachOnCreationConfig = false;
-    private AtomicBoolean mAutoAttachOnCreation = new AtomicBoolean(false);
+    protected boolean mAutoAttachOnCreationConfig = false;
+    protected AtomicBoolean mAutoAttachOnCreation = new AtomicBoolean(false);
 
     // State of screen
     // (TODO: Reconsider tying directly to screen, maybe this is
@@ -497,7 +498,7 @@
 
     // Indicates if we found mvno-specific APNs in the full APN list.
     // used to determine if we can accept mno-specific APN for tethering.
-    private boolean mMvnoMatched = false;
+    protected boolean mMvnoMatched = false;
 
     /** Allows the generation of unique Id's for DataConnection objects */
     private AtomicInteger mUniqueIdGenerator = new AtomicInteger(0);
@@ -582,6 +583,10 @@
 
     private final int mTransportType;
 
+    public DcTracker(Phone phone) { 
+      this(phone, TransportType.WWAN);
+    }
+
     //***** Constructor
     public DcTracker(Phone phone, int transportType) {
         super();
@@ -1230,6 +1235,15 @@
         setupDataOnConnectableApns(Phone.REASON_DATA_ATTACHED);
     }
 
+    protected boolean getAttachedStatus() {
+        return mAttached.get();
+    }
+
+    protected boolean isNvSubscription() {
+        int cdmaSubscriptionSource = CdmaSubscriptionSourceManager.getDefault(mPhone.getContext());
+        return cdmaSubscriptionSource == CdmaSubscriptionSourceManager.SUBSCRIPTION_FROM_NV;
+    }
+
     /**
      * Check if it is allowed to make a data connection (without checking APN context specific
      * conditions).
@@ -1263,7 +1277,7 @@
 
         // Step 1: Get all environment conditions.
         final boolean internalDataEnabled = mDataEnabledSettings.isInternalDataEnabled();
-        boolean attachedState = mAttached.get();
+        boolean attachedState = getAttachedStatus();
         boolean desiredPowerState = mPhone.getServiceStateTracker().getDesiredPowerState();
         boolean radioStateFromCarrier = mPhone.getServiceStateTracker().getPowerStateFromCarrier();
         // TODO: Remove this hack added by ag/641832.
@@ -1326,7 +1340,7 @@
         if (!(attachedState || mAutoAttachOnCreation.get())) {
             reasons.add(DataDisallowedReasonType.NOT_ATTACHED);
         }
-        if (!recordsLoaded) {
+        if (!(recordsLoaded || isNvSubscription())) {
             reasons.add(DataDisallowedReasonType.RECORD_NOT_LOADED);
         }
         if (phoneState != PhoneConstants.State.IDLE
@@ -1406,11 +1420,11 @@
         ONLY_ON_CHANGE
     };
 
-    private void setupDataOnConnectableApns(String reason) {
+    protected void setupDataOnConnectableApns(String reason) {
         setupDataOnConnectableApns(reason, RetryFailures.ALWAYS);
     }
 
-    private void setupDataOnConnectableApns(String reason, RetryFailures retryFailures) {
+    protected void setupDataOnConnectableApns(String reason, RetryFailures retryFailures) {
         if (VDBG) log("setupDataOnConnectableApns: " + reason);
 
         if (DBG && !VDBG) {
@@ -1538,7 +1552,7 @@
     }
 
     // Disabled apn's still need avail/unavail notifications - send them out
-    private void notifyOffApnsOfAvailability(String reason) {
+    protected void notifyOffApnsOfAvailability(String reason) {
         for (ApnContext apnContext : mApnContexts.values()) {
             if (!mAttached.get() || !apnContext.isReady()) {
                 if (VDBG) log("notifyOffApnOfAvailability type:" + apnContext.getApnType());
@@ -1565,7 +1579,7 @@
      * @return boolean - true if we did cleanup any connections, false if they
      *                   were already all disconnected.
      */
-    private boolean cleanUpAllConnections(boolean tearDown, String reason) {
+    protected boolean cleanUpAllConnections(boolean tearDown, String reason) {
         if (DBG) log("cleanUpAllConnections: tearDown=" + tearDown + " reason=" + reason);
         boolean didDisconnect = false;
         boolean disableMeteredOnly = false;
@@ -1639,7 +1653,7 @@
         sendMessage(msg);
     }
 
-    private void cleanUpConnection(boolean tearDown, ApnContext apnContext) {
+    protected void cleanUpConnection(boolean tearDown, ApnContext apnContext) {
         if (apnContext == null) {
             if (DBG) log("cleanUpConnection: apn context is null");
             return;
@@ -1739,7 +1753,7 @@
         }
         int bearer = mPhone.getServiceState().getRilDataRadioTechnology();
         IccRecords r = mIccRecords.get();
-        String operator = (r != null) ? r.getOperatorNumeric() : "";
+        String operator = mPhone.getOperatorNumeric();
         ArrayList<ApnSetting> dunCandidates = new ArrayList<ApnSetting>();
         ArrayList<ApnSetting> retDunSettings = new ArrayList<ApnSetting>();
 
@@ -1900,7 +1914,7 @@
         return apn;
     }
 
-    private ArrayList<ApnSetting> createApnList(Cursor cursor) {
+    protected ArrayList<ApnSetting> createApnList(Cursor cursor) {
         ArrayList<ApnSetting> mnoApns = new ArrayList<ApnSetting>();
         ArrayList<ApnSetting> mvnoApns = new ArrayList<ApnSetting>();
         IccRecords r = mIccRecords.get();
@@ -2065,7 +2079,7 @@
         return true;
     }
 
-    private void setInitialAttachApn() {
+    protected  void setInitialAttachApn() {
         ApnSetting iaApnSetting = null;
         ApnSetting defaultApnSetting = null;
         ApnSetting firstApnSetting = null;
@@ -2094,6 +2108,11 @@
             }
         }
 
+        if ((iaApnSetting == null) && (defaultApnSetting == null) &&
+                !allowInitialAttachForOperator()) {
+            log("Abort Initial attach");
+            return;
+        }
         // The priority of apn candidates from highest to lowest is:
         //   1) APN_TYPE_IA (Initial Attach)
         //   2) mPreferredApn, i.e. the current preferred apn
@@ -2125,6 +2144,10 @@
         }
     }
 
+    protected boolean allowInitialAttachForOperator() {
+        return true;
+    }
+
     /**
      * Handles changes to the APN database.
      */
@@ -2305,7 +2328,7 @@
         return mAutoAttachOnCreation.get();
     }
 
-    private void onRecordsLoadedOrSubIdChanged() {
+    protected void onRecordsLoadedOrSubIdChanged() {
         if (DBG) log("onRecordsLoadedOrSubIdChanged: createAllApnList");
         mAutoAttachOnCreationConfig = mPhone.getContext().getResources()
                 .getBoolean(com.android.internal.R.bool.config_auto_attach_data_on_creation);
@@ -3307,7 +3330,7 @@
         notifyOffApnsOfAvailability(reason);
     }
 
-    private void setDataProfilesAsNeeded() {
+    protected void setDataProfilesAsNeeded() {
         if (DBG) log("setDataProfilesAsNeeded");
         if (mAllApnSettings != null && !mAllApnSettings.isEmpty()) {
             ArrayList<DataProfile> dps = new ArrayList<DataProfile>();
@@ -3330,11 +3353,11 @@
      * Based on the sim operator numeric, create a list for all possible
      * Data Connections and setup the preferredApn.
      */
-    private void createAllApnList() {
+    protected void createAllApnList() {
         mMvnoMatched = false;
         mAllApnSettings = new ArrayList<>();
         IccRecords r = mIccRecords.get();
-        String operator = (r != null) ? r.getOperatorNumeric() : "";
+        String operator = mPhone.getOperatorNumeric();
         if (operator != null) {
             String selection = Telephony.Carriers.NUMERIC + " = '" + operator + "'";
             // query only enabled apn.
@@ -3377,7 +3400,7 @@
         setDataProfilesAsNeeded();
     }
 
-    private void dedupeApnSettings() {
+    protected void dedupeApnSettings() {
         ArrayList<ApnSetting> resultApns = new ArrayList<ApnSetting>();
 
         // coalesce APNs if they are similar enough to prevent
@@ -3486,8 +3509,7 @@
             }
         }
 
-        IccRecords r = mIccRecords.get();
-        String operator = (r != null) ? r.getOperatorNumeric() : "";
+        String operator = mPhone.getOperatorNumeric();
 
         // This is a workaround for a bug (7305641) where we don't failover to other
         // suitable APNs if our preferred APN fails.  On prepaid ATT sims we need to
@@ -3510,7 +3532,7 @@
                     + " canSetPreferApn=" + mCanSetPreferApn
                     + " mPreferredApn=" + mPreferredApn
                     + " operator=" + operator + " radioTech=" + radioTech
-                    + " IccRecords r=" + r);
+                    + " IccRecords r=" + mIccRecords);
         }
 
         if (usePreferred && mCanSetPreferApn && mPreferredApn != null &&
@@ -3605,7 +3627,7 @@
         return result.toString();
     }
 
-    private void setPreferredApn(int pos) {
+    protected void setPreferredApn(int pos) {
         if (!mCanSetPreferApn) {
             log("setPreferredApn: X !canSEtPreferApn");
             return;
@@ -3625,7 +3647,7 @@
         }
     }
 
-    private ApnSetting getPreferredApn() {
+    protected ApnSetting getPreferredApn() {
         if (mAllApnSettings == null || mAllApnSettings.isEmpty()) {
             log("getPreferredApn: mAllApnSettings is " + ((mAllApnSettings == null)?"null":"empty"));
             return null;
@@ -3676,7 +3698,7 @@
                 // If onRecordsLoadedOrSubIdChanged() is not called here, it should be called on
                 // onSubscriptionsChanged() when a valid subId is available.
                 int subId = mPhone.getSubId();
-                if (SubscriptionManager.isValidSubscriptionId(subId)) {
+                if (mSubscriptionManager.isActiveSubId(subId)) {
                     onRecordsLoadedOrSubIdChanged();
                 } else {
                     log("Ignoring EVENT_RECORDS_LOADED as subId is not valid: " + subId);
@@ -4063,7 +4085,7 @@
             return;
         }
 
-        IccRecords newIccRecords = getUiccRecords(UiccController.APP_FAM_3GPP);
+        IccRecords newIccRecords = mPhone.getIccRecords();
 
         IccRecords r = mIccRecords.get();
         if (r != newIccRecords) {
@@ -4073,7 +4095,7 @@
                 mIccRecords.set(null);
             }
             if (newIccRecords != null) {
-                if (SubscriptionManager.isValidSubscriptionId(mPhone.getSubId())) {
+                if (mSubscriptionManager.isActiveSubId(mPhone.getSubId())) {
                     log("New records found.");
                     mIccRecords.set(newIccRecords);
                     newIccRecords.registerForRecordsLoaded(
@@ -4184,7 +4206,7 @@
         return true;
     }
 
-    private void log(String s) {
+    protected void log(String s) {
         Rlog.d(LOG_TAG, "[" + mPhone.getPhoneId() + "]" + s);
     }
 
@@ -4355,7 +4377,7 @@
     /**
      * Add the Emergency APN settings to APN settings list
      */
-    private void addEmergencyApnSetting() {
+    protected void addEmergencyApnSetting() {
         if(mEmergencyApn != null) {
             if(mAllApnSettings == null) {
                 mAllApnSettings = new ArrayList<ApnSetting>();
@@ -4394,7 +4416,7 @@
         return true;
     }
 
-    private void cleanUpConnectionsOnUpdatedApns(boolean tearDown, String reason) {
+    protected void cleanUpConnectionsOnUpdatedApns(boolean tearDown, String reason) {
         if (DBG) log("cleanUpConnectionsOnUpdatedApns: tearDown=" + tearDown);
         if (mAllApnSettings != null && mAllApnSettings.isEmpty()) {
             cleanUpAllConnections(tearDown, Phone.REASON_APN_CHANGED);
diff --git a/src/java/com/android/internal/telephony/imsphone/ImsPhone.java b/src/java/com/android/internal/telephony/imsphone/ImsPhone.java
index 3333697..f789bf2 100644
--- a/src/java/com/android/internal/telephony/imsphone/ImsPhone.java
+++ b/src/java/com/android/internal/telephony/imsphone/ImsPhone.java
@@ -45,6 +45,7 @@
 import android.content.BroadcastReceiver;
 import android.content.Context;
 import android.content.Intent;
+import android.content.IntentFilter;
 import android.net.NetworkStats;
 import android.net.Uri;
 import android.os.AsyncResult;
@@ -70,8 +71,10 @@
 import android.telephony.ims.ImsCallProfile;
 import android.telephony.ims.ImsReasonInfo;
 import android.telephony.ims.ImsSsInfo;
+import android.telephony.ims.ImsStreamMediaProfile;
 import android.text.TextUtils;
 
+import com.android.ims.ImsCall;
 import com.android.ims.ImsEcbm;
 import com.android.ims.ImsEcbmStateListener;
 import com.android.ims.ImsException;
@@ -98,6 +101,9 @@
 import com.android.internal.telephony.uicc.IccRecords;
 import com.android.internal.telephony.util.NotificationChannelController;
 
+import org.codeaurora.ims.QtiCallConstants;
+import org.codeaurora.ims.utils.QtiImsExtUtils;
+
 import java.io.FileDescriptor;
 import java.io.PrintWriter;
 import java.util.ArrayList;
@@ -282,6 +288,14 @@
         mDefaultPhone.registerForServiceStateChanged(this, EVENT_SERVICE_STATE_CHANGED, null);
         // Force initial roaming state update later, on EVENT_CARRIER_CONFIG_CHANGED.
         // Settings provider or CarrierConfig may not be loaded now.
+
+        // Register receiver for sending RTT text message and
+        // for receving RTT Operation
+        // .i.e.Upgrade Initiate, Upgrade accept, Upgrade reject
+        IntentFilter filter = new IntentFilter();
+        filter.addAction(QtiCallConstants.ACTION_SEND_RTT_TEXT);
+        filter.addAction(QtiCallConstants.ACTION_RTT_OPERATION);
+        mDefaultPhone.getContext().registerReceiver(mRttReceiver, filter);
     }
 
     //todo: get rid of this function. It is not needed since parentPhone obj never changes
@@ -301,6 +315,7 @@
             mDefaultPhone.getServiceStateTracker().
                     unregisterForDataRegStateOrRatChanged(this);
             mDefaultPhone.unregisterForServiceStateChanged(this);
+            mDefaultPhone.getContext().unregisterReceiver(mRttReceiver);
         }
     }
 
@@ -1829,6 +1844,198 @@
         return tm.isNetworkRoaming();
     }
 
+    private BroadcastReceiver mRttReceiver = new BroadcastReceiver() {
+        @Override
+        public void onReceive(Context context, Intent intent) {
+            if (QtiCallConstants.ACTION_SEND_RTT_TEXT.equals(intent.getAction())) {
+                Rlog.d(LOG_TAG, "RTT: Received ACTION_SEND_RTT_TEXT");
+                String data = intent.getStringExtra(QtiCallConstants.RTT_TEXT_VALUE);
+                sendRttMessage(data);
+            } else if (QtiCallConstants.ACTION_RTT_OPERATION.equals(intent.getAction())) {
+                Rlog.d(LOG_TAG, "RTT: Received ACTION_RTT_OPERATION");
+                int data = intent.getIntExtra(QtiCallConstants.RTT_OPERATION_TYPE, 0);
+                checkIfModifyRequestOrResponse(data);
+            } else {
+                Rlog.d(LOG_TAG, "RTT: unknown intent");
+            }
+        }
+    };
+
+    /**
+     * Sends Rtt message
+     * Rtt Message can be sent only when -
+     * operating mode is RTT_FULL and for non-VT calls only based on config
+     *
+     * @param data The Rtt text to be sent
+     */
+    public void sendRttMessage(String data) {
+        if (!canProcessRttRequest() || !isFgCallActive()) {
+            return;
+        }
+
+        // Check for empty message
+        if (TextUtils.isEmpty(data)) {
+            Rlog.d(LOG_TAG, "RTT: Text null");
+            return;
+        }
+
+        ImsCall imsCall = getForegroundCall().getImsCall();
+        if (imsCall == null) {
+            Rlog.d(LOG_TAG, "RTT: imsCall null");
+            return;
+        }
+
+        if (!isRttVtCallAllowed(imsCall)) {
+            Rlog.d(LOG_TAG, "RTT: InCorrect mode");
+            return;
+        }
+
+        Rlog.d(LOG_TAG, "RTT: sendRttMessage");
+        imsCall.sendRttMessage(data);
+    }
+
+    /**
+     * Sends RTT Upgrade request
+     *
+     * @param to: expected profile
+     */
+    public void sendRttModifyRequest(ImsCallProfile to) {
+        Rlog.d(LOG_TAG, "RTT: sendRttModifyRequest");
+        ImsCall imsCall = getForegroundCall().getImsCall();
+        if (imsCall == null) {
+            Rlog.d(LOG_TAG, "RTT: imsCall null");
+            return;
+        }
+
+        imsCall.sendRttModifyRequest();
+    }
+
+    /**
+     * Sends RTT Upgrade response
+     *
+     * @param data : response for upgrade
+     */
+    public void sendRttModifyResponse(int response) {
+        ImsCall imsCall = getForegroundCall().getImsCall();
+        if (imsCall == null) {
+            Rlog.d(LOG_TAG, "RTT: imsCall null");
+            return;
+        }
+
+        if (!isRttVtCallAllowed(imsCall)) {
+            Rlog.d(LOG_TAG, "RTT: Not allowed for VT");
+            return;
+        }
+
+        Rlog.d(LOG_TAG, "RTT: sendRttModifyResponse");
+        imsCall.sendRttModifyResponse(mapRequestToResponse(response));
+    }
+
+    // Utility to check if the value coming in intent is for upgrade initiate or upgrade response
+    private void checkIfModifyRequestOrResponse(int data) {
+        if (!canProcessRttRequest() || !isFgCallActive()) {
+            return;
+        }
+
+        Rlog.d(LOG_TAG, "RTT: checkIfModifyRequestOrResponse data =  " + data);
+        switch (data) {
+            case QtiCallConstants.RTT_UPGRADE_INITIATE:
+                // Rtt Upgrade means enable Rtt
+                packRttModifyRequestToProfile(ImsStreamMediaProfile.RTT_MODE_FULL);
+                break;
+            case QtiCallConstants.RTT_DOWNGRADE_INITIATE:
+                // Rtt downrade means disable Rtt
+                packRttModifyRequestToProfile(ImsStreamMediaProfile.RTT_MODE_DISABLED);
+                break;
+            case QtiCallConstants.RTT_UPGRADE_CONFIRM:
+            case QtiCallConstants.RTT_UPGRADE_REJECT:
+                sendRttModifyResponse(data);
+                break;
+        }
+    }
+
+    private void packRttModifyRequestToProfile(int data) {
+        if (!canSendRttModifyRequest()) {
+            Rlog.d(LOG_TAG, "RTT: cannot send rtt modify request");
+            return;
+        }
+
+        ImsCallProfile fromProfile = getForegroundCall().getImsCall().getCallProfile();
+        ImsCallProfile toProfile = fromProfile;
+        toProfile.mMediaProfile = new ImsStreamMediaProfile(data);
+
+        Rlog.d(LOG_TAG, "RTT: packRttModifyRequestToProfile");
+        sendRttModifyRequest(toProfile);
+    }
+
+    private boolean canSendRttModifyRequest() {
+        ImsCall imsCall = getForegroundCall().getImsCall();
+        if (imsCall == null) {
+            Rlog.d(LOG_TAG, "RTT: imsCall null");
+            return false;
+        }
+
+        return true;
+    }
+
+    private boolean mapRequestToResponse(int response) {
+        switch (response) {
+            case QtiCallConstants.RTT_UPGRADE_CONFIRM:
+                return true;
+            case QtiCallConstants.RTT_UPGRADE_REJECT:
+                return false;
+            default:
+                return false;
+        }
+    }
+
+    /*
+     * Returns true if Mode is RTT_FULL, false otherwise
+     */
+    private boolean isInFullRttMode() {
+        int mode = QtiImsExtUtils.getRttOperatingMode(mContext);
+        Rlog.d(LOG_TAG, "RTT: isInFullRttMode mode = " + mode);
+        return (mode == QtiCallConstants.RTT_MODE_FULL);
+    }
+
+    /*
+     * Rtt for VT calls is not supported for certain operators
+     * Check the config and process the request
+     */
+    public boolean isRttVtCallAllowed(ImsCall call) {
+        int mode = QtiImsExtUtils.getRttOperatingMode(mContext);
+        Rlog.d(LOG_TAG, "RTT: isRttVtCallAllowed mode = " + mode);
+
+        if (call.getCallProfile().isVideoCall() &&
+                !QtiImsExtUtils.isRttSupportedOnVtCalls(mPhoneId, mContext)) {
+            return false;
+        }
+        return true;
+    }
+
+    public boolean canProcessRttRequest() {
+        // Process only if Carrier supports RTT and RTT is on
+        if (!(QtiImsExtUtils.isRttSupported(mPhoneId, mContext) &&
+                    QtiImsExtUtils.isRttOn(mContext))) {
+            Rlog.d(LOG_TAG, "RTT: canProcessRttRequest RTT is not supported/off");
+            return false;
+        }
+        Rlog.d(LOG_TAG, "RTT: canProcessRttRequest rtt supported = " +
+                QtiImsExtUtils.isRttSupported(mPhoneId, mContext) + ", is Rtt on = " +
+                QtiImsExtUtils.isRttOn(mContext) + ", Rtt mode = " +
+                QtiImsExtUtils.getRttOperatingMode(mContext));
+        return true;
+    }
+
+    public boolean isFgCallActive() {
+        // process the request only if foreground is active
+        if (ImsPhoneCall.State.ACTIVE != getForegroundCall().getState()) {
+            Rlog.d(LOG_TAG, "RTT: isFgCallActive fg call not active");
+            return false;
+        }
+        return true;
+    }
+
     @Override
     public void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
         pw.println("ImsPhone extends:");
diff --git a/src/java/com/android/internal/telephony/imsphone/ImsPhoneCallTracker.java b/src/java/com/android/internal/telephony/imsphone/ImsPhoneCallTracker.java
index a776816..725edfb 100644
--- a/src/java/com/android/internal/telephony/imsphone/ImsPhoneCallTracker.java
+++ b/src/java/com/android/internal/telephony/imsphone/ImsPhoneCallTracker.java
@@ -101,6 +101,9 @@
 import com.android.internal.telephony.nano.TelephonyProto.TelephonyCallSession.Event.ImsCommand;
 import com.android.server.net.NetworkStatsService;
 
+import org.codeaurora.ims.QtiCallConstants;
+import org.codeaurora.ims.utils.QtiImsExtUtils;
+
 import java.io.FileDescriptor;
 import java.io.PrintWriter;
 import java.util.ArrayList;
@@ -1213,6 +1216,7 @@
                 // being sent to the lower layers/to the network.
             }
 
+            profile = setRttModeBasedOnOperator(profile);
             ImsCall imsCall = mImsManager.makeCall(profile, callees, mImsCallListener);
             conn.setImsCall(imsCall);
 
@@ -1245,6 +1249,7 @@
             throw new CallStateException("cannot accept call");
         }
 
+        ImsStreamMediaProfile mediaProfile = new ImsStreamMediaProfile();
         if ((mRingingCall.getState() == ImsPhoneCall.State.WAITING)
                 && mForegroundCall.getState().isAlive()) {
             setMute(false);
@@ -1264,7 +1269,9 @@
                 // We need to disconnect the foreground call before answering the background call.
                 mForegroundCall.hangup();
                 try {
-                    ringingCall.accept(ImsCallProfile.getCallTypeFromVideoState(videoState));
+                    mediaProfile = addRttAttributeIfRequired(ringingCall, mediaProfile);
+                    ringingCall.accept(ImsCallProfile.getCallTypeFromVideoState(videoState),
+                            mediaProfile);
                 } catch (ImsException e) {
                     throw new CallStateException("cannot accept call");
                 }
@@ -1278,7 +1285,9 @@
             try {
                 ImsCall imsCall = mRingingCall.getImsCall();
                 if (imsCall != null) {
-                    imsCall.accept(ImsCallProfile.getCallTypeFromVideoState(videoState));
+                    mediaProfile = addRttAttributeIfRequired(imsCall, mediaProfile);
+                    imsCall.accept(ImsCallProfile.getCallTypeFromVideoState(videoState),
+                            mediaProfile);
                     mMetrics.writeOnImsCommand(mPhone.getPhoneId(), imsCall.getSession(),
                             ImsCommand.IMS_CMD_ACCEPT);
                 } else {
@@ -1746,8 +1755,12 @@
                 //accept waiting call after holding background call
                 ImsCall imsCall = mRingingCall.getImsCall();
                 if (imsCall != null) {
+                    ImsStreamMediaProfile mediaProfile = new ImsStreamMediaProfile();
+                    mediaProfile = addRttAttributeIfRequired(imsCall, mediaProfile);
+
                     imsCall.accept(
-                        ImsCallProfile.getCallTypeFromVideoState(mPendingCallVideoState));
+                            ImsCallProfile.getCallTypeFromVideoState(mPendingCallVideoState),
+                            mediaProfile);
                     mMetrics.writeOnImsCommand(mPhone.getPhoneId(), imsCall.getSession(),
                             ImsCommand.IMS_CMD_ACCEPT);
                 }
@@ -3951,4 +3964,42 @@
     public void setAlwaysPlayRemoteHoldTone(boolean shouldPlayRemoteHoldTone) {
         mAlwaysPlayRemoteHoldTone = shouldPlayRemoteHoldTone;
     }
+
+    // Update the Rtt attribute
+    private ImsCallProfile setRttModeBasedOnOperator(ImsCallProfile profile) {
+        if (!mPhone.canProcessRttRequest()) {
+            return profile;
+        }
+
+        int mode = QtiImsExtUtils.getRttOperatingMode(mPhone.getContext());
+
+        if (DBG) log("RTT: setRttModeBasedOnOperator mode = " + mode);
+
+        if (!QtiImsExtUtils.isRttSupportedOnVtCalls(mPhone.getPhoneId(), mPhone.getContext()) &&
+                profile.isVideoCall()) {
+            return profile;
+        }
+
+        profile.mMediaProfile.setRttMode(mode);
+        return profile;
+    }
+
+    // Accept the call as RTT if incoming call as RTT attribute set
+    private ImsStreamMediaProfile addRttAttributeIfRequired(ImsCall call,
+            ImsStreamMediaProfile mediaProfile) {
+
+        if (!mPhone.canProcessRttRequest()) {
+            return mediaProfile;
+        }
+
+        ImsCallProfile profile = call.getCallProfile();
+        if (profile.mMediaProfile != null && profile.mMediaProfile.isRttCall() &&
+                (mPhone.isRttVtCallAllowed(call))) {
+            if (DBG) log("RTT: addRttAttributeIfRequired = " + profile.mMediaProfile.isRttCall());
+            // If RTT UI option is on, then incoming RTT call should always be accepted
+            // as RTT, irrespective of Modes
+            mediaProfile.setRttMode(ImsStreamMediaProfile.RTT_MODE_FULL);
+        }
+        return mediaProfile;
+    }
 }
diff --git a/src/java/com/android/internal/telephony/imsphone/ImsRttTextHandler.java b/src/java/com/android/internal/telephony/imsphone/ImsRttTextHandler.java
index eff2499..b8dc76e 100644
--- a/src/java/com/android/internal/telephony/imsphone/ImsRttTextHandler.java
+++ b/src/java/com/android/internal/telephony/imsphone/ImsRttTextHandler.java
@@ -124,11 +124,19 @@
                     return;
                 }
                 mRttTextStream = (Connection.RttTextStream) msg.obj;
+                if (mRttTextStream == null) {
+                    Rlog.e(LOG_TAG, "RTT text stream is null");
+                    return;
+                }
                 mReaderThread = new InCallReaderThread(mRttTextStream);
                 mReaderThread.start();
                 break;
             case SEND_TO_INCALL:
                 String messageToIncall = (String) msg.obj;
+                if (mRttTextStream == null) {
+                    Rlog.e(LOG_TAG, "RTT text stream is null");
+                    return;
+                }
                 try {
                     mRttTextStream.write(messageToIncall);
                 } catch (IOException e) {
diff --git a/src/java/com/android/internal/telephony/test/SimulatedCommandsVerifier.java b/src/java/com/android/internal/telephony/test/SimulatedCommandsVerifier.java
index f43cee0..2d7e814 100644
--- a/src/java/com/android/internal/telephony/test/SimulatedCommandsVerifier.java
+++ b/src/java/com/android/internal/telephony/test/SimulatedCommandsVerifier.java
@@ -1308,8 +1308,7 @@
     }
 
     @Override
-    public void setUiccSubscription(int slotId, int appIndex, int subId, int subStatus,
-                                    Message result) {
+    public void setUiccSubscription(int appIndex, boolean activate, Message result) {
 
     }
 
diff --git a/src/java/com/android/internal/telephony/uicc/AdnRecord.java b/src/java/com/android/internal/telephony/uicc/AdnRecord.java
index 4414caf..acda8bd 100644
--- a/src/java/com/android/internal/telephony/uicc/AdnRecord.java
+++ b/src/java/com/android/internal/telephony/uicc/AdnRecord.java
@@ -42,6 +42,7 @@
     String mAlphaTag = null;
     String mNumber = null;
     String[] mEmails;
+    String[] mAdditionalNumbers = null;
     int mExtRecord = 0xff;
     int mEfid;                   // or 0 if none
     int mRecordNumber;           // or 0 if none
@@ -80,14 +81,16 @@
             String alphaTag;
             String number;
             String[] emails;
+            String[] additionalNumbers;
 
             efid = source.readInt();
             recordNumber = source.readInt();
             alphaTag = source.readString();
             number = source.readString();
             emails = source.readStringArray();
+            additionalNumbers = source.readStringArray();
 
-            return new AdnRecord(efid, recordNumber, alphaTag, number, emails);
+            return new AdnRecord(efid, recordNumber, alphaTag, number, emails, additionalNumbers);
         }
 
         @Override
@@ -116,12 +119,27 @@
         this(0, 0, alphaTag, number, emails);
     }
 
+    public AdnRecord(String alphaTag, String number, String[] emails, String[] additionalNumbers) {
+        this(0, 0, alphaTag, number, emails, additionalNumbers);
+    }
+
     public AdnRecord (int efid, int recordNumber, String alphaTag, String number, String[] emails) {
         this.mEfid = efid;
         this.mRecordNumber = recordNumber;
         this.mAlphaTag = alphaTag;
         this.mNumber = number;
         this.mEmails = emails;
+        this.mAdditionalNumbers = null;
+    }
+
+    public AdnRecord(int efid, int recordNumber, String alphaTag, String number, String[] emails,
+            String[] additionalNumbers) {
+        this.mEfid = efid;
+        this.mRecordNumber = recordNumber;
+        this.mAlphaTag = alphaTag;
+        this.mNumber = number;
+        this.mEmails = emails;
+        this.mAdditionalNumbers = additionalNumbers;
     }
 
     public AdnRecord(int efid, int recordNumber, String alphaTag, String number) {
@@ -130,6 +148,7 @@
         this.mAlphaTag = alphaTag;
         this.mNumber = number;
         this.mEmails = null;
+        this.mAdditionalNumbers = null;
     }
 
     //***** Instance Methods
@@ -162,14 +181,32 @@
         this.mEmails = emails;
     }
 
+    public String[] getAdditionalNumbers() {
+        return mAdditionalNumbers;
+    }
+
+    public void setAdditionalNumbers(String[] additionalNumbers) {
+        this.mAdditionalNumbers = additionalNumbers;
+    }
+
+    public int getRecordNumber() {
+        return mRecordNumber;
+    }
+
+    public void setRecordNumber(int recNumber) {
+        mRecordNumber = recNumber;
+    }
+
     @Override
     public String toString() {
         return "ADN Record '" + mAlphaTag + "' '" + Rlog.pii(LOG_TAG, mNumber) + " "
-                + Rlog.pii(LOG_TAG, mEmails) + "'";
+                + Rlog.pii(LOG_TAG, mEmails) + " "
+                + Rlog.pii(LOG_TAG, mAdditionalNumbers) + "'";
     }
 
     public boolean isEmpty() {
-        return TextUtils.isEmpty(mAlphaTag) && TextUtils.isEmpty(mNumber) && mEmails == null;
+        return TextUtils.isEmpty(mAlphaTag) && TextUtils.isEmpty(mNumber) && mEmails == null &&
+                mAdditionalNumbers == null;
     }
 
     public boolean hasExtendedRecord() {
@@ -190,11 +227,56 @@
         return (s1.equals(s2));
     }
 
+    /** Help function for ANR/EMAIL array compare. */
+    private static boolean arrayCompareNullEqualsEmpty(String s1[], String s2[]) {
+        if (s1 == s2) {
+            return true;
+        }
+
+        if (s1 == null) {
+            s1 = new String[1];
+            s1[0] = "";
+        }
+
+        if (s2 == null) {
+            s2 = new String[1];
+            s2[0] = "";
+        }
+
+        for (String str:s1) {
+            if (TextUtils.isEmpty(str)) {
+                continue;
+            } else {
+                if (Arrays.asList(s2).contains(str)) {
+                    continue;
+                } else {
+                    return false;
+                }
+            }
+        }
+
+        for (String str:s2) {
+            if (TextUtils.isEmpty(str)) {
+                continue;
+            } else {
+                if (Arrays.asList(s1).contains(str)) {
+                    continue;
+                } else {
+                    return false;
+                }
+            }
+        }
+
+        return true;
+    }
+
     public boolean isEqual(AdnRecord adn) {
         return ( stringCompareNullEqualsEmpty(mAlphaTag, adn.mAlphaTag) &&
                 stringCompareNullEqualsEmpty(mNumber, adn.mNumber) &&
-                Arrays.equals(mEmails, adn.mEmails));
+                arrayCompareNullEqualsEmpty(mEmails, adn.mEmails) &&
+                arrayCompareNullEqualsEmpty(mAdditionalNumbers, adn.mAdditionalNumbers));
     }
+
     //***** Parcelable Implementation
 
     @Override
@@ -209,6 +291,7 @@
         dest.writeString(mAlphaTag);
         dest.writeString(mNumber);
         dest.writeStringArray(mEmails);
+        dest.writeStringArray(mAdditionalNumbers);
     }
 
     /**
@@ -231,11 +314,11 @@
             adnString[i] = (byte) 0xFF;
         }
 
-        if (TextUtils.isEmpty(mNumber)) {
+        if (TextUtils.isEmpty(mNumber) && TextUtils.isEmpty(mAlphaTag)) {
             Rlog.w(LOG_TAG, "[buildAdnString] Empty dialing number");
             return adnString;   // return the empty record (for delete)
-        } else if (mNumber.length()
-                > (ADN_DIALING_NUMBER_END - ADN_DIALING_NUMBER_START + 1) * 2) {
+        } else if (mNumber != null &&
+                mNumber.length() > (ADN_DIALING_NUMBER_END - ADN_DIALING_NUMBER_START + 1) * 2) {
             Rlog.w(LOG_TAG,
                     "[buildAdnString] Max length of dialing number is 20");
             return null;
@@ -248,14 +331,16 @@
             Rlog.w(LOG_TAG, "[buildAdnString] Max length of tag is " + footerOffset);
             return null;
         } else {
-            bcdNumber = PhoneNumberUtils.numberToCalledPartyBCD(
-                    mNumber, PhoneNumberUtils.BCD_EXTENDED_TYPE_EF_ADN);
+            if (!TextUtils.isEmpty(mNumber)) {
+                bcdNumber = PhoneNumberUtils.numberToCalledPartyBCD(
+                        mNumber, PhoneNumberUtils.BCD_EXTENDED_TYPE_EF_ADN);
 
-            System.arraycopy(bcdNumber, 0, adnString,
-                    footerOffset + ADN_TON_AND_NPI, bcdNumber.length);
+                System.arraycopy(bcdNumber, 0, adnString,
+                        footerOffset + ADN_TON_AND_NPI, bcdNumber.length);
 
-            adnString[footerOffset + ADN_BCD_NUMBER_LENGTH]
-                    = (byte) (bcdNumber.length);
+                adnString[footerOffset + ADN_BCD_NUMBER_LENGTH]
+                        = (byte) (bcdNumber.length);
+            }
             adnString[footerOffset + ADN_CAPABILITY_ID]
                     = (byte) 0xFF; // Capability Id
             adnString[footerOffset + ADN_EXTENSION_ID]
@@ -340,12 +425,14 @@
             mExtRecord = 0xff & record[record.length - 1];
 
             mEmails = null;
+            mAdditionalNumbers = null;
 
         } catch (RuntimeException ex) {
             Rlog.w(LOG_TAG, "Error parsing AdnRecord", ex);
             mNumber = "";
             mAlphaTag = "";
             mEmails = null;
+            mAdditionalNumbers = null;
         }
     }
 }
diff --git a/src/java/com/android/internal/telephony/uicc/RuimRecords.java b/src/java/com/android/internal/telephony/uicc/RuimRecords.java
index 88ac071..9a9435a 100644
--- a/src/java/com/android/internal/telephony/uicc/RuimRecords.java
+++ b/src/java/com/android/internal/telephony/uicc/RuimRecords.java
@@ -84,8 +84,11 @@
                 + " mHomeNetworkId=" + mHomeNetworkId;
     }
 
+    // Constants
+    // MNC length in case of CSIM/RUIM IMSI is 2 as per spec C.S0065 section 5.2.2
+    private static final int CSIM_IMSI_MNC_LENGTH = 2;
+
     // ***** Event Constants
-    private static final int EVENT_GET_IMSI_DONE = 3;
     private static final int EVENT_GET_DEVICE_IDENTITY_DONE = 4;
     private static final int EVENT_GET_ICCID_DONE = 5;
     private static final int EVENT_GET_CDMA_SUBSCRIPTION_DONE = 10;
@@ -203,16 +206,67 @@
         }
     }
 
-    private int adjstMinDigits (int digits) {
+    private int decodeImsiDigits(int digits, int length) {
         // 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;
+        int constant = 0;
+        for (int i = 0; i < length; i++) {
+            constant = (constant * 10) + 1;
+        }
+
+        digits += constant;
+
+        for (int i = 0, denominator = 1; i < length; i++) {
+            digits = ((digits / denominator) % 10 == 0) ? (digits - (10 * denominator)) : digits;
+            denominator *= 10;
+        }
         return digits;
     }
 
     /**
+     * Decode utility to decode IMSI from data read from EF_IMSIM
+     * Please refer to
+     *       // C.S0065 section 5.2.2 for IMSI_M encoding
+     *       // C.S0005 section 2.3.1 for MIN encoding in IMSI_M.
+     */
+    private String decodeImsi(byte[] data) {
+        // Retrieve the MCC and digits 11 and 12
+        int mcc_data = ((0x03 & data[9]) << 8) | (0xFF & data[8]);
+        int mcc = decodeImsiDigits(mcc_data, 3);
+        int digits_11_12_data = data[6] & 0x7f;
+        int digits_11_12 = decodeImsiDigits(digits_11_12_data, 2);
+
+        // Retrieve 10 MIN digits
+        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 = decodeImsiDigits(first3digits, 3);
+        second3digits = decodeImsiDigits(second3digits, 3);
+        last3digits = decodeImsiDigits(last3digits, 3);
+
+        StringBuilder builder = new StringBuilder();
+        builder.append(String.format(Locale.US, "%03d", mcc));
+        builder.append(String.format(Locale.US, "%02d", digits_11_12));
+        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));
+        return  builder.toString();
+    }
+
+     /**
+     * Introduce Generic API returns the 5 or 6 digit MCC/MNC
+     * of the operator that provided the RUIM card.
+     * Returns null of RUIM is not yet ready
+     */
+    @Override
+    public String getOperatorNumeric() {
+        return getRUIMOperatorNumeric();
+    }
+
+    /**
      * Returns the 5 or 6 digit MCC/MNC of the operator that
      *  provided the RUIM card. Returns null of RUIM is not yet ready
      */
@@ -229,11 +283,7 @@
             return imsi.substring(0, 3 + mMncLength);
         }
 
-        // Guess the MNC length based on the MCC if we don't
-        // have a valid value in ef[ad]
-
-        int mcc = Integer.parseInt(imsi.substring(0, 3));
-        return imsi.substring(0, 3 + MccTable.smallestDigitsMccForMnc(mcc));
+        return mImsi.substring(0, 3 + CSIM_IMSI_MNC_LENGTH);
     }
 
     // Refer to ETSI TS 102.221
@@ -378,31 +428,39 @@
         @Override
         public void onRecordLoaded(AsyncResult ar) {
             byte[] data = (byte[]) ar.result;
+
+            if (data == null || data.length < 10) {
+                log("Invalid IMSI from EF_CSIM_IMSIM " + IccUtils.bytesToHexString(data));
+                mImsi = null;
+                mMin = null;
+                return;
+            }
             if (VDBG) 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);
+                mImsi = decodeImsi(data);
+                if (null != mImsi) {
+                    mMin = mImsi.substring(5, 15);
+                }
+                if (DBG) log("IMSI: " + mImsi.substring(0, 5) + "xxxxxxxxx");
 
-                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");
+                if (DBG) log("IMSI not provisioned in card");
             }
+
+            // Update MccTable with the retrieved IMSI
+            String operatorNumeric = getOperatorNumeric();
+            if (operatorNumeric != null) {
+                if (operatorNumeric.length() <= 6) {
+                    MccTable.updateMccMncConfiguration(mContext, operatorNumeric, false);
+                }
+            }
+
+            mImsiReadyRegistrants.notifyRegistrants();
         }
     }
 
@@ -618,43 +676,6 @@
                 log("Event EVENT_GET_DEVICE_IDENTITY_DONE Received");
             break;
 
-            /* IO events */
-            case EVENT_GET_IMSI_DONE:
-                isRecordLoadResponse = true;
-
-                ar = (AsyncResult)msg.obj;
-                if (ar.exception != null) {
-                    loge("Exception querying IMSI, Exception:" + ar.exception);
-                    break;
-                }
-
-                mImsi = (String) ar.result;
-
-                // IMSI (MCC+MNC+MSIN) is at least 6 digits, but not more
-                // than 15 (and usually 15).
-                if (mImsi != null && (mImsi.length() < 6 || mImsi.length() > 15)) {
-                    loge("invalid IMSI " + mImsi);
-                    mImsi = null;
-                }
-
-                // FIXME: CSIM IMSI may not contain the MNC.
-                if (false) {
-                    log("IMSI: " + mImsi.substring(0, 6) + "xxxxxxxxx");
-
-                    String operatorNumeric = getRUIMOperatorNumeric();
-                    if (operatorNumeric != null) {
-                        if (operatorNumeric.length() <= 6) {
-                            log("update mccmnc=" + operatorNumeric);
-                            MccTable.updateMccMncConfiguration(mContext, operatorNumeric, false);
-                        }
-                    }
-                } else {
-                    String operatorNumeric = getRUIMOperatorNumeric();
-                    log("NO update mccmnc=" + operatorNumeric);
-                }
-
-            break;
-
             case EVENT_GET_CDMA_SUBSCRIPTION_DONE:
                 ar = (AsyncResult)msg.obj;
                 String localTemp[] = (String[])ar.result;
@@ -844,9 +865,6 @@
 
         if (DBG) log("fetchRuimRecords " + mRecordsToLoad);
 
-        mCi.getIMSIForApp(mParentApp.getAid(), obtainMessage(EVENT_GET_IMSI_DONE));
-        mRecordsToLoad++;
-
         mFh.loadEFTransparent(EF_ICCID,
                 obtainMessage(EVENT_GET_ICCID_DONE));
         mRecordsToLoad++;
diff --git a/src/java/com/android/internal/telephony/uicc/UiccProfile.java b/src/java/com/android/internal/telephony/uicc/UiccProfile.java
index 2910ff7..80248ea 100644
--- a/src/java/com/android/internal/telephony/uicc/UiccProfile.java
+++ b/src/java/com/android/internal/telephony/uicc/UiccProfile.java
@@ -55,6 +55,7 @@
 import com.android.internal.telephony.Phone;
 import com.android.internal.telephony.PhoneConstants;
 import com.android.internal.telephony.PhoneFactory;
+import com.android.internal.telephony.RIL;
 import com.android.internal.telephony.SubscriptionController;
 import com.android.internal.telephony.cat.CatService;
 import com.android.internal.telephony.uicc.IccCardApplicationStatus.AppType;
@@ -103,6 +104,7 @@
     private final UiccCard mUiccCard; //parent
     private CatService mCatService;
     private UiccCarrierPrivilegeRules mCarrierPrivilegeRules;
+    private boolean mDefaultAppsActivated;
     private boolean mDisposed = false;
 
     private RegistrantList mCarrierPrivilegeRegistrants = new RegistrantList();
@@ -920,10 +922,59 @@
             }
 
             sanitizeApplicationIndexesLocked();
+
+            if (needsSimActivation()) {
+                if (ics.mCardState == CardState.CARDSTATE_PRESENT) {
+                    if (!mDefaultAppsActivated) {
+                        activateDefaultApps();
+                        mDefaultAppsActivated = true;
+                    }
+                } else {
+                    // SIM removed, reset activation flag to make sure
+                    // to re-run the activation at the next insertion
+                    mDefaultAppsActivated = false;
+                }
+            }
+
             updateIccAvailability(true);
         }
     }
 
+    private boolean needsSimActivation() {
+        if (mCi instanceof RIL) {
+            return ((RIL) mCi).needsOldRilFeature("simactivation");
+        }
+        return false;
+    }
+
+    private void activateDefaultApps() {
+        int gsmIndex = mGsmUmtsSubscriptionAppIndex;
+        int cdmaIndex = mCdmaSubscriptionAppIndex;
+
+        if (gsmIndex < 0 || cdmaIndex < 0) {
+            for (int i = 0; i < mUiccApplications.length; i++) {
+                if (mUiccApplications[i] == null) {
+                    continue;
+                }
+
+                AppType appType = mUiccApplications[i].getType();
+                if (gsmIndex < 0 &&
+                        (appType == AppType.APPTYPE_USIM || appType == AppType.APPTYPE_SIM)) {
+                    gsmIndex = i;
+                } else if (cdmaIndex < 0 &&
+                        (appType == AppType.APPTYPE_CSIM || appType == AppType.APPTYPE_RUIM)) {
+                    cdmaIndex = i;
+                }
+            }
+        }
+        if (gsmIndex >= 0) {
+            mCi.setUiccSubscription(gsmIndex, true, null);
+        }
+        if (cdmaIndex >= 0) {
+            mCi.setUiccSubscription(cdmaIndex, true, null);
+        }
+    }
+
     private void createAndUpdateCatServiceLocked() {
         if (mUiccApplications.length > 0 && mUiccApplications[0] != null) {
             // Initialize or Reinitialize CatService
diff --git a/src/java/com/android/internal/telephony/util/TelephonyExtUtils.java b/src/java/com/android/internal/telephony/util/TelephonyExtUtils.java
new file mode 100644
index 0000000..b4cd601
--- /dev/null
+++ b/src/java/com/android/internal/telephony/util/TelephonyExtUtils.java
@@ -0,0 +1,247 @@
+/*

+ * Copyright (C) 2018 The LineageOS 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.util;

+

+import android.content.BroadcastReceiver;

+import android.content.Context;

+import android.content.Intent;

+import android.content.IntentFilter;

+import android.os.RemoteException;

+import android.os.ServiceManager;

+import android.telephony.SubscriptionManager;

+import android.util.Log;

+

+import com.android.internal.telephony.PhoneConstants;

+

+import org.codeaurora.internal.IExtTelephony;

+

+import java.util.ArrayList;

+import java.util.List;

+

+public final class TelephonyExtUtils {

+    private static final boolean DEBUG = false;

+    private static final String TAG = "TelephonyExtUtils";

+

+    public static final String ACTION_UICC_MANUAL_PROVISION_STATUS_CHANGED =

+            "org.codeaurora.intent.action.ACTION_UICC_MANUAL_PROVISION_STATUS_CHANGED";

+

+    public static final String EXTRA_NEW_PROVISION_STATE = "newProvisionState";

+

+    // This is the list of possible values that

+    // IExtTelephony.getCurrentUiccCardProvisioningStatus() can return

+    public static final int CARD_NOT_PRESENT = -2;

+    public static final int INVALID_STATE = -1;

+    public static final int NOT_PROVISIONED = 0;

+    public static final int PROVISIONED = 1;

+

+    private boolean mNoServiceAvailable = false;

+    private IExtTelephony mExtTelephony;

+

+    private static TelephonyExtUtils sInstance;

+

+    private final List<ProvisioningChangedListener> mListeners = new ArrayList<>();

+

+    private final BroadcastReceiver mReceiver = new BroadcastReceiver() {

+        @Override

+        public void onReceive(Context context, Intent intent) {

+            final String action = intent.getAction();

+            if (Intent.ACTION_BOOT_COMPLETED.equals(action)) {

+                if (DEBUG) Log.d(TAG, "Boot completed, registering service");

+                mNoServiceAvailable = getService() == null;

+            } else if (ACTION_UICC_MANUAL_PROVISION_STATUS_CHANGED.equals(action)) {

+                int slotId = intent.getIntExtra(PhoneConstants.PHONE_KEY,

+                        SubscriptionManager.INVALID_SIM_SLOT_INDEX);

+                boolean provisioned = intent.getIntExtra(EXTRA_NEW_PROVISION_STATE,

+                        NOT_PROVISIONED) == PROVISIONED;

+                if (DEBUG) Log.d(TAG, "Received ACTION_UICC_MANUAL_PROVISION_STATUS_CHANGED"

+                        + " on slotId: " + slotId + ", sub provisioned: " + provisioned);

+                notifyListeners(slotId, provisioned);

+            }

+        }

+    };

+

+    // This class is not supposed to be instantiated externally

+    private TelephonyExtUtils(Context context) {

+        if (DEBUG) Log.d(TAG, "Registering listeners!");

+

+        IntentFilter intentFilter = new IntentFilter();

+        intentFilter.addAction(ACTION_UICC_MANUAL_PROVISION_STATUS_CHANGED);

+        intentFilter.addAction(Intent.ACTION_BOOT_COMPLETED);

+        context.registerReceiver(mReceiver, intentFilter);

+    }

+

+    /**

+     * Get an existing instance of the utils or create a new one if not existant

+     *

+     * @return An instance of this class

+     */

+    public static TelephonyExtUtils getInstance(Context context) {

+        if (sInstance == null) {

+            sInstance = new TelephonyExtUtils(context.getApplicationContext());

+        }

+        return sInstance;

+    }

+

+    /**

+     * Determines whether the ITelephonyExt service is available on the device

+     * Any result of the methods in this class are only valid if this method returns true

+     *

+     * @return true on success

+     */

+    public boolean hasService() {

+        return getService() != null;

+    }

+

+    /**

+     * Determines whether the SIM associated with the given SubscriptionId is provisioned

+     *

+     * @return true if the SIM associated with the given subId is provisioned

+     */

+    public boolean isSubProvisioned(int subId) {

+        return isSlotProvisioned(SubscriptionManager.getSlotIndex(subId));

+    }

+

+    /**

+     * Determines whether the given SIM is provisioned

+     *

+     * @return true if the SIM is provisioned

+     */

+    public boolean isSlotProvisioned(int slotId) {

+        return getCurrentUiccCardProvisioningStatus(slotId) == PROVISIONED;

+    }

+

+    /**

+     * Get the current provisioning status for a given SIM slot

+     *

+     * @return The provisioning status from the extension or INVALID_STATE if not possible

+     */

+    public int getCurrentUiccCardProvisioningStatus(int slotId) {

+        IExtTelephony service = getService();

+        if (service != null && slotId != SubscriptionManager.INVALID_SIM_SLOT_INDEX) {

+            try {

+                return mExtTelephony.getCurrentUiccCardProvisioningStatus(slotId);

+            } catch (RemoteException ex) {

+                Log.e(TAG, "Failed to get provisioning status for slotId: " + slotId, ex);

+            }

+        }

+        return INVALID_STATE;

+    }

+

+    /**

+     * Activate the SIM card with the given slotId

+     *

+     * @return The result of the activation or -1

+     */

+    public int activateUiccCard(int slotId) {

+        IExtTelephony service = getService();

+        if (service != null) {

+            try {

+                return mExtTelephony.activateUiccCard(slotId);

+            } catch (RemoteException ex) {

+                Log.e(TAG, "Activating sub failed for slotId: " + slotId);

+            }

+        }

+        return -1;

+    }

+

+    /**

+     * Deactivate the SIM card with the given slotId

+     *

+     * @return The result of the deactivation or -1

+     */

+    public int deactivateUiccCard(int slotId) {

+        IExtTelephony service = getService();

+        if (service != null) {

+            try {

+                return mExtTelephony.deactivateUiccCard(slotId);

+            } catch (RemoteException ex) {

+                Log.e(TAG, "Deactivating sub failed for slotId: " + slotId);

+            }

+        }

+        return -1;

+    }

+

+    /**

+     * Add a ProvisioningChangedListener to get notified in case of provisioning changes

+     */

+    public void addListener(ProvisioningChangedListener listener) {

+        if (listener != null) {

+            mListeners.remove(listener);

+            mListeners.add(listener);

+        }

+    }

+

+    /**

+     * Remove a ProvisioningChangedListener to not get notified of provisioning changes anymore

+     */

+    public void removeListener(ProvisioningChangedListener listener) {

+        if (listener != null) {

+            mListeners.remove(listener);

+        }

+    }

+

+    /**

+     * Notify all registered listeners about provisioning changes

+     */

+    private void notifyListeners(int slotId, boolean provisioned) {

+        for (ProvisioningChangedListener listener : mListeners) {

+            listener.onProvisioningChanged(slotId, provisioned);

+        }

+    }

+

+    /**

+     * Helper method to get an already instantiated service or instantiate it

+     *

+     * @return a valid service instance or null

+     */

+    private IExtTelephony getService() {

+        // We already tried to get the service but weren't successful, so just return null here

+        if (mNoServiceAvailable) {

+            if (DEBUG) Log.v(TAG, "Already tried to get a service without success, returning!");

+            return null;

+        }

+

+        if (DEBUG) Log.d(TAG, "Retrieving the service");

+

+        // Instead of getting a new service instance, return an already existing one here

+        if (mExtTelephony != null) {

+            if (DEBUG) Log.d(TAG, "Returning cached service instance");

+            return mExtTelephony;

+        }

+

+        synchronized(TelephonyExtUtils.class) {

+            try {

+                mExtTelephony =

+                        IExtTelephony.Stub.asInterface(ServiceManager.getService("extphone"));

+            } catch (NoClassDefFoundError ex) {

+                // Ignore, device does not ship with telephony-ext

+                Log.d(TAG, "Failed to get telephony extension service!");

+                mNoServiceAvailable = true;

+            }

+        }

+

+        return mExtTelephony;

+    }

+

+    /**

+     * Interface definition so we can register callbacks to get the provisioning status

+     *  whenever it changes

+     */

+    public interface ProvisioningChangedListener {

+        public void onProvisioningChanged(int slotId, boolean isProvisioned);

+    }

+}
\ No newline at end of file
diff --git a/tests/telephonytests/src/com/android/internal/telephony/uicc/IccPhoneBookInterfaceManagerTest.java b/tests/telephonytests/src/com/android/internal/telephony/uicc/IccPhoneBookInterfaceManagerTest.java
index 9510619..df9a436 100644
--- a/tests/telephonytests/src/com/android/internal/telephony/uicc/IccPhoneBookInterfaceManagerTest.java
+++ b/tests/telephonytests/src/com/android/internal/telephony/uicc/IccPhoneBookInterfaceManagerTest.java
@@ -15,6 +15,7 @@
  */
 package com.android.internal.telephony.uicc;
 
+import android.content.ContentValues;
 import android.os.HandlerThread;
 import android.os.Message;
 import android.os.AsyncResult;
@@ -36,7 +37,9 @@
 
 import static org.junit.Assert.assertEquals;
 import static org.junit.Assert.assertNull;
+import static org.junit.Assert.assertTrue;
 import static org.mockito.Mockito.anyInt;
+import static org.mockito.Mockito.anyString;
 
 import java.util.Arrays;
 import java.util.List;
@@ -115,4 +118,36 @@
         //verify the previous read is not got affected
         assertEquals(mAdnList, adnListResult);
     }
+
+    @Test
+    @SmallTest
+    public void testUpdateAdnRecord() {
+        doAnswer(new Answer<Void>() {
+            @Override
+            public Void answer(InvocationOnMock invocation) throws Throwable {
+                Message response = (Message) invocation.getArguments()[4];
+                //set result for update ADN EF
+                AsyncResult.forMessage(response).exception = null;
+                response.sendToTarget();
+                return null;
+            }
+        }).when(mAdnRecordCache).updateAdnBySearch(anyInt(),
+                (AdnRecord) anyObject(), (AdnRecord) anyObject(),
+                anyString(), (Message) anyObject());
+
+        ContentValues values = new ContentValues();
+        values.put("tag", "");
+        values.put("number", "");
+        values.put("emails", "");
+        values.put("anrs", "");
+        values.put("newTag", "test");
+        values.put("newNumber", "123456");
+        values.put("newEmails", "");
+        values.put("newAnrs", "");
+
+        boolean result = mIccPhoneBookInterfaceMgr.updateAdnRecordsWithContentValuesInEfBySearch(
+                IccConstants.EF_ADN, values , null);
+
+        assertTrue(result);
+    }
 }