Merge "Create new API for MNO carrier id"
diff --git a/AndroidManifest.xml b/AndroidManifest.xml
index 72e3cc3..30760dc 100644
--- a/AndroidManifest.xml
+++ b/AndroidManifest.xml
@@ -38,7 +38,6 @@
     <protected-broadcast android:name="android.intent.action.ANY_DATA_STATE" />
     <protected-broadcast android:name="android.intent.action.DATA_CONNECTION_FAILED" />
     <protected-broadcast android:name="android.intent.action.DATA_STALL_DETECTED" />
-    <protected-broadcast android:name="android.intent.action.MMSSMS_DATABASE_LOST" />
     <protected-broadcast android:name="android.intent.action.SIM_STATE_CHANGED" />
     <protected-broadcast android:name="android.intent.action.NETWORK_SET_TIME" />
     <protected-broadcast android:name="android.intent.action.NETWORK_SET_TIMEZONE" />
diff --git a/res/values-fr-rCA/strings.xml b/res/values-fr-rCA/strings.xml
index 3a310f8..ceb83c5 100644
--- a/res/values-fr-rCA/strings.xml
+++ b/res/values-fr-rCA/strings.xml
@@ -16,7 +16,7 @@
 
 <resources xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
-    <string name="phoneAppLabel" product="tablet" msgid="8576272342240415145">"Données mobiles"</string>
+    <string name="phoneAppLabel" product="tablet" msgid="8576272342240415145">"Données cellulaires"</string>
     <string name="phoneAppLabel" product="default" msgid="6790717591729922998">"Services téléphoniques"</string>
     <string name="emergencyDialerIconLabel" msgid="7812140032168171053">"Appels d\'urgence"</string>
     <string name="phoneIconLabel" msgid="2331230813161304895">"Téléphone"</string>
@@ -245,7 +245,7 @@
     <string name="roaming_enable" msgid="7331106985174381987">"Se connecter aux services de données lors de l\'itinérance"</string>
     <string name="roaming_disable" msgid="1843417228755568110">"Se connecter aux services de données lors de l\'itinérance"</string>
     <string name="roaming_reenable_message" msgid="6843814381576397939">"L\'itinérance des données est désactivée. Touchez pour l\'activer."</string>
-    <string name="roaming_notification_title" msgid="4749053220884743110">"Connexion de données mobiles perdue"</string>
+    <string name="roaming_notification_title" msgid="4749053220884743110">"Connexion de données cellulaires perdue"</string>
     <string name="roaming_warning" msgid="1603164667540144353">"Des frais importants peuvent s\'appliquer."</string>
     <string name="roaming_check_price_warning" msgid="7497570906830902550">"Communiquez avec votre fournisseur réseau pour connaître les tarifs."</string>
     <string name="roaming_alert_title" msgid="3654815360303826008">"Autoriser les données en itinérance?"</string>
@@ -260,7 +260,7 @@
     <string name="data_usage_disable_mobile" msgid="3577275288809667615">"Désactiver les données mobiles?"</string>
     <string name="sim_selection_required_pref" msgid="7049424902961844236">"Sélection requise"</string>
     <string name="sim_change_data_title" msgid="5332425991853799280">"Changer de SIM pour les données?"</string>
-    <string name="sim_change_data_message" msgid="2163963581444907496">"Utiliser la carte SIM <xliff:g id="NEW_SIM">%1$s</xliff:g> au lieu de la carte <xliff:g id="OLD_SIM">%2$s</xliff:g> pour les données mobiles?"</string>
+    <string name="sim_change_data_message" msgid="2163963581444907496">"Utiliser la carte SIM <xliff:g id="NEW_SIM">%1$s</xliff:g> au lieu de la carte <xliff:g id="OLD_SIM">%2$s</xliff:g> pour les données cellulaires?"</string>
     <string name="wifi_calling_settings_title" msgid="7741961465416430470">"Appels Wi-Fi"</string>
     <string name="video_calling_settings_title" msgid="539714564273795574">"Appels vidéo par l\'entremise du fournisseur de services"</string>
     <string name="gsm_umts_options" msgid="6538311689850981686">"Options GSM/UMTS"</string>
@@ -569,7 +569,7 @@
     <string name="ota_hfa_activation_title" msgid="2234246934160473981">"Activation en cours…"</string>
     <string name="ota_hfa_activation_dialog_message" msgid="8092479227918463415">"Le téléphone est en train d\'activer votre service de données cellulaires.\n\nCela peut prendre jusqu\'à cinq minutes."</string>
     <string name="ota_skip_activation_dialog_title" msgid="2943366608272261306">"Ignorer l\'activation?"</string>
-    <string name="ota_skip_activation_dialog_message" msgid="2440770373498870550">"Si vous poursuivez sans activer votre mobile, vous ne pourrez ni téléphoner, ni vous connecter à des réseaux de données mobiles. La connexion à un réseau Wi-Fi reste possible. Vous serez invité à effectuer l\'activation à chaque démarrage du téléphone."</string>
+    <string name="ota_skip_activation_dialog_message" msgid="2440770373498870550">"Si vous poursuivez sans activer votre appareil mobile, vous ne pourrez ni téléphoner, ni vous connecter à des réseaux de données cellulaires. La connexion à un réseau Wi-Fi reste possible. Vous serez invité à effectuer l\'activation à chaque démarrage du téléphone."</string>
     <string name="ota_skip_activation_dialog_skip_label" msgid="3458532775091563208">"Passer"</string>
     <string name="ota_activate" msgid="1368528132525626264">"Activer"</string>
     <string name="ota_title_activate_success" msgid="6570240212263372046">"Votre téléphone est activé"</string>
@@ -653,12 +653,12 @@
     <string name="mobile_data_status_roaming_turned_on_subtext" msgid="1335176927083781041">"L\'itinérance de données est activée"</string>
     <string name="mobile_data_status_roaming_without_plan_subtext" msgid="3568412513831673037">"En itinérance. Un forfait de données est requis"</string>
     <string name="mobile_data_status_roaming_with_plan_subtext" msgid="8721998948811064377">"En itinérance. Le forfait de données est actif"</string>
-    <string name="mobile_data_status_no_plan_subtext" msgid="4887747337017565725">"Il ne reste plus de données mobiles"</string>
-    <string name="mobile_data_activate_prepaid" msgid="7447025165850512683">"Il ne reste plus de données mobiles"</string>
-    <string name="mobile_data_activate_prepaid_summary" msgid="5705389791791637666">"Ajouter des données mobiles par l\'intermédiaire de <xliff:g id="PROVIDER_NAME">%s</xliff:g>"</string>
+    <string name="mobile_data_status_no_plan_subtext" msgid="4887747337017565725">"Il ne reste plus de données cellulaires"</string>
+    <string name="mobile_data_activate_prepaid" msgid="7447025165850512683">"Il ne reste plus de données cellulaires"</string>
+    <string name="mobile_data_activate_prepaid_summary" msgid="5705389791791637666">"Ajouter des données cellulaires par l\'intermédiaire de <xliff:g id="PROVIDER_NAME">%s</xliff:g>"</string>
     <string name="mobile_data_activate_roaming_plan" msgid="5998161536947086264">"Aucun forfait d\'itinérance"</string>
     <string name="mobile_data_activate_roaming_plan_summary" msgid="511202908883425459">"Ajouter un forfait d\'itinérance par l\'intermédiaire de <xliff:g id="PROVIDER_NAME">%s</xliff:g>"</string>
-    <string name="mobile_data_activate_footer" msgid="5979019929980140594">"Vous pouvez ajouter des données mobiles ou un forfait d\'itinérance par l\'intermédiaire de votre fournisseur de services, <xliff:g id="PROVIDER_NAME">%s</xliff:g>."</string>
+    <string name="mobile_data_activate_footer" msgid="5979019929980140594">"Vous pouvez ajouter des données cellulaires ou un forfait d\'itinérance par l\'intermédiaire de votre fournisseur de services, <xliff:g id="PROVIDER_NAME">%s</xliff:g>."</string>
     <string name="mobile_data_activate_diag_title" msgid="9044252207707864493">"Ajouter des données?"</string>
     <string name="mobile_data_activate_diag_message" msgid="8216154678758451453">"Vous devrez peut-être ajouter des données par l\'intermédiaire de <xliff:g id="PROVIDER_NAME">%s</xliff:g>"</string>
     <string name="mobile_data_activate_button" msgid="3682400969184405446">"AJOUTER DES DONNÉES"</string>
@@ -770,9 +770,9 @@
     <string name="callFailed_already_ringing" msgid="7747655701540586943">"Impossible de passer un appel, car il y a un appel entrant sans réponse. Répondez à l\'appel entrant ou refusez-le avant de passer un nouvel appel."</string>
     <string name="callFailed_calling_disabled" msgid="7257184079619449933">"Impossible de passer un appel, car la fonction d\'appel a été désactivée à l\'aide de la propriété système ro.telephony.disable-call."</string>
     <string name="callFailed_too_many_calls" msgid="3023051919216926990">"Impossible de passer un appel, car deux appels sont déjà en cours. Déconnectez-en un ou fusionnez-les en conférence téléphonique avant de passer un nouvel appel."</string>
-    <string name="supp_service_over_ut_precautions" msgid="2565837355815074278">"Avant d\'utiliser <xliff:g id="SUPP_SERVICE">%s</xliff:g>, assurez-vous que les données mobiles sont activées. Vous pouvez modifier cette option dans les paramètres du réseau cellulaire."</string>
-    <string name="supp_service_over_ut_precautions_roaming" msgid="1597142936802114092">"Avant d\'utiliser <xliff:g id="SUPP_SERVICE">%s</xliff:g>, assurez-vous que les données mobiles et l\'itinérance des données sont activées. Vous pouvez modifier ces options dans les paramètres du réseau cellulaire."</string>
-    <string name="supp_service_over_ut_precautions_dual_sim" msgid="1682814794340311300">"Avant d\'utiliser <xliff:g id="SUPP_SERVICE">%1$s</xliff:g>, assurez-vous que les données mobiles sont activées pour la carte SIM <xliff:g id="SIM_NUMBER">%2$d</xliff:g>. Vous pouvez modifier cette option dans les paramètres du réseau cellulaire."</string>
-    <string name="supp_service_over_ut_precautions_roaming_dual_sim" msgid="8062345092837168385">"Avant d\'utiliser <xliff:g id="SUPP_SERVICE">%1$s</xliff:g>, assurez-vous que les données mobiles et l\'itinérance des données sont activées pour la carte SIM <xliff:g id="SIM_NUMBER">%2$d</xliff:g>. Vous pouvez modifier ces options dans les paramètres du réseau cellulaire."</string>
+    <string name="supp_service_over_ut_precautions" msgid="2565837355815074278">"Avant d\'utiliser <xliff:g id="SUPP_SERVICE">%s</xliff:g>, assurez-vous que les données cellulaires sont activées. Vous pouvez modifier cette option dans les paramètres du réseau cellulaire."</string>
+    <string name="supp_service_over_ut_precautions_roaming" msgid="1597142936802114092">"Avant d\'utiliser <xliff:g id="SUPP_SERVICE">%s</xliff:g>, assurez-vous que les données cellulaires et l\'itinérance des données sont activées. Vous pouvez modifier ces options dans les paramètres du réseau cellulaire."</string>
+    <string name="supp_service_over_ut_precautions_dual_sim" msgid="1682814794340311300">"Avant d\'utiliser <xliff:g id="SUPP_SERVICE">%1$s</xliff:g>, assurez-vous que les données cellulaires sont activées pour la carte SIM <xliff:g id="SIM_NUMBER">%2$d</xliff:g>. Vous pouvez modifier cette option dans les paramètres du réseau cellulaire."</string>
+    <string name="supp_service_over_ut_precautions_roaming_dual_sim" msgid="8062345092837168385">"Avant d\'utiliser <xliff:g id="SUPP_SERVICE">%1$s</xliff:g>, assurez-vous que les données cellulaires et l\'itinérance des données sont activées pour la carte SIM <xliff:g id="SIM_NUMBER">%2$d</xliff:g>. Vous pouvez modifier ces options dans les paramètres du réseau cellulaire."</string>
     <string name="supp_service_over_ut_precautions_dialog_dismiss" msgid="5061044213859557398">"Ignorer"</string>
 </resources>
diff --git a/res/values/strings.xml b/res/values/strings.xml
index db8d16a..f206322 100644
--- a/res/values/strings.xml
+++ b/res/values/strings.xml
@@ -1804,7 +1804,11 @@
     <!-- Message displayed to the user to indicate that a held call has been released /
          disconnected. -->
     <string name="supp_service_held_call_released">Held call has been released.</string>
-
+    <!-- In-call screen: error message shown when the user attempts to place a call, but the device
+         is currently in the process of being provisioned for service.  Provisioning is the process
+         by which a device confirms which services are available to the user by contacting the
+         mobile service provider. -->
+    <string name="callFailed_otasp_provisioning_in_process">Cannot place a call as the device is currently being provisioned.</string>
     <!-- In-call screen: error message shown when the user has attempted to place a new outgoing
          call, but there is already a call in dialing state. -->
     <string name="callFailed_already_dialing">Cannot place a call as another outgoing call is already dialing.</string>
diff --git a/src/com/android/phone/EmergencyDialer.java b/src/com/android/phone/EmergencyDialer.java
index 1fbbd33..1619aa1 100644
--- a/src/com/android/phone/EmergencyDialer.java
+++ b/src/com/android/phone/EmergencyDialer.java
@@ -62,7 +62,6 @@
 import android.text.TextWatcher;
 import android.text.method.DialerKeyListener;
 import android.text.style.TtsSpan;
-import android.util.FeatureFlagUtils;
 import android.util.Log;
 import android.util.TypedValue;
 import android.view.HapticFeedbackConstants;
@@ -348,8 +347,21 @@
         // Allow turning screen on
         setTurnScreenOn(true);
 
-        mAreEmergencyDialerShortcutsEnabled = FeatureFlagUtils
-                .isEnabled(this, FeatureFlagUtils.EMERGENCY_DIAL_SHORTCUTS);
+        CarrierConfigManager configMgr = getSystemService(CarrierConfigManager.class);
+        PersistableBundle carrierConfig =
+                configMgr.getConfigForSubId(SubscriptionManager.getDefaultVoiceSubscriptionId());
+
+        // Disable emergency dialer shortcut when can't get the location information or inserting
+        // the SIM of the blacklisted carrier.
+        boolean isSupport = carrierConfig.getBoolean(
+                CarrierConfigManager.KEY_SUPPORT_EMERGENCY_DIALER_SHORTCUT_BOOL);
+        Log.d(LOG_TAG, "Is the carrier supported: " + isSupport);
+        TelephonyManager tm = getSystemService(TelephonyManager.class);
+        if (isSupport && !TextUtils.isEmpty(tm.getNetworkCountryIso())) {
+            mAreEmergencyDialerShortcutsEnabled = true;
+        } else {
+            mAreEmergencyDialerShortcutsEnabled = false;
+        }
         Log.d(LOG_TAG, "Enable emergency dialer shortcut: "
                 + mAreEmergencyDialerShortcutsEnabled);
 
@@ -400,11 +412,6 @@
         // Check whether we should show the onscreen "Dial" button and co.
         // Read carrier config through the public API because PhoneGlobals is not available when we
         // run as a secondary user.
-        CarrierConfigManager configMgr =
-                (CarrierConfigManager) getSystemService(Context.CARRIER_CONFIG_SERVICE);
-        PersistableBundle carrierConfig =
-                configMgr.getConfigForSubId(SubscriptionManager.getDefaultVoiceSubscriptionId());
-
         if (carrierConfig.getBoolean(CarrierConfigManager.KEY_SHOW_ONSCREEN_DIAL_BUTTON_BOOL)) {
             mDialButton.setOnClickListener(this);
         } else {
diff --git a/src/com/android/phone/NetworkSelectSetting.java b/src/com/android/phone/NetworkSelectSetting.java
index 371a3a6..d9731be 100644
--- a/src/com/android/phone/NetworkSelectSetting.java
+++ b/src/com/android/phone/NetworkSelectSetting.java
@@ -418,7 +418,6 @@
 
                 mConnectedNetworkOperatorsPreference.addPreference(pref);
             } else {
-                loge("Invalid CellIfno: " + cellInfo.toString());
                 // Remove the connected network operators category
                 removeConnectedNetworkOperatorPreference();
             }
diff --git a/src/com/android/phone/NotificationMgr.java b/src/com/android/phone/NotificationMgr.java
index 5aa87d0..de3fffc 100644
--- a/src/com/android/phone/NotificationMgr.java
+++ b/src/com/android/phone/NotificationMgr.java
@@ -30,7 +30,10 @@
 import android.content.pm.UserInfo;
 import android.content.res.Resources;
 import android.net.Uri;
+import android.os.Handler;
+import android.os.Message;
 import android.os.PersistableBundle;
+import android.os.SystemClock;
 import android.os.SystemProperties;
 import android.os.UserHandle;
 import android.os.UserManager;
@@ -50,6 +53,7 @@
 import android.text.TextUtils;
 import android.util.ArrayMap;
 import android.util.Log;
+import android.util.SparseArray;
 import android.widget.Toast;
 
 import com.android.internal.telephony.Phone;
@@ -89,6 +93,14 @@
     static final int DATA_DISCONNECTED_ROAMING_NOTIFICATION = 5;
     static final int SELECTED_OPERATOR_FAIL_NOTIFICATION = 6;
 
+    // Event for network selection notification.
+    private static final int EVENT_PENDING_NETWORK_SELECTION_NOTIFICATION = 1;
+
+    private static final long NETWORK_SELECTION_NOTIFICATION_MAX_PENDING_TIME_IN_MS = 10000L;
+    private static final int NETWORK_SELECTION_NOTIFICATION_MAX_PENDING_TIMES = 10;
+
+    private static final int STATE_UNKNOWN_SERVICE = -1;
+
     /** The singleton NotificationMgr instance. */
     private static NotificationMgr sInstance;
 
@@ -103,12 +115,36 @@
     private TelecomManager mTelecomManager;
     private TelephonyManager mTelephonyManager;
 
-    // used to track the notification of selected network unavailable
-    private boolean mSelectedUnavailableNotify = false;
+    // used to track the notification of selected network unavailable, per subscription id.
+    private SparseArray<Boolean> mSelectedUnavailableNotify = new SparseArray<>();
 
     // used to track whether the message waiting indicator is visible, per subscription id.
     private ArrayMap<Integer, Boolean> mMwiVisible = new ArrayMap<Integer, Boolean>();
 
+    // those flags are used to track whether to show network selection notification or not.
+    private SparseArray<Integer> mPreviousServiceState = new SparseArray<>();
+    private SparseArray<Long> mOOSTimestamp = new SparseArray<>();
+    private SparseArray<Integer> mPendingEventCounter = new SparseArray<>();
+    // maps each subId to selected network operator name.
+    private SparseArray<String> mSelectedNetworkOperatorName = new SparseArray<>();
+
+    private final Handler mHandler = new Handler() {
+        @Override
+        public void handleMessage(Message msg) {
+            switch (msg.what) {
+                case EVENT_PENDING_NETWORK_SELECTION_NOTIFICATION:
+                    int subId = (int) msg.obj;
+                    TelephonyManager telephonyManager =
+                            mTelephonyManager.createForSubscriptionId(subId);
+                    if (telephonyManager.getServiceState() != null) {
+                        shouldShowNotification(telephonyManager.getServiceState().getState(),
+                                subId);
+                    }
+                    break;
+            }
+        }
+    };
+
     /**
      * Private constructor (this is a singleton).
      * @see #init(PhoneGlobals)
@@ -592,19 +628,21 @@
         intent.putExtra(GsmUmtsOptions.EXTRA_SUB_ID, subId);
         builder.setContentIntent(PendingIntent.getActivity(mContext, 0, intent, 0));
         mNotificationManager.notifyAsUser(
-                null /* tag */,
+                Integer.toString(subId) /* tag */,
                 SELECTED_OPERATOR_FAIL_NOTIFICATION,
                 builder.build(),
                 UserHandle.ALL);
+        mSelectedUnavailableNotify.put(subId, true);
     }
 
     /**
      * Turn off the network selection "no service" notification
      */
-    private void cancelNetworkSelection() {
+    private void cancelNetworkSelection(int subId) {
         if (DBG) log("cancelNetworkSelection()...");
         mNotificationManager.cancelAsUser(
-                null /* tag */, SELECTED_OPERATOR_FAIL_NOTIFICATION, UserHandle.ALL);
+                Integer.toString(subId) /* tag */, SELECTED_OPERATOR_FAIL_NOTIFICATION,
+                UserHandle.ALL);
     }
 
     /**
@@ -645,18 +683,34 @@
                             + (isManualSelection ? selectedNetworkOperatorName : ""));
                 }
 
-                if (serviceState == ServiceState.STATE_OUT_OF_SERVICE && isManualSelection) {
-                    showNetworkSelection(selectedNetworkOperatorName, subId);
-                    mSelectedUnavailableNotify = true;
+                if (isManualSelection) {
+                    mSelectedNetworkOperatorName.put(subId, selectedNetworkOperatorName);
+                    shouldShowNotification(serviceState, subId);
                 } else {
-                    if (mSelectedUnavailableNotify) {
-                        cancelNetworkSelection();
-                        mSelectedUnavailableNotify = false;
-                    }
+                    dismissNetworkSelectionNotification(subId);
+                    clearUpNetworkSelectionNotificationParam(subId);
                 }
             } else {
                 if (DBG) log("updateNetworkSelection()..." + "state = " +
                         serviceState + " not updating network due to invalid subId " + subId);
+                dismissNetworkSelectionNotificationForInactiveSubId();
+            }
+        }
+    }
+
+    private void dismissNetworkSelectionNotification(int subId) {
+        if (mSelectedUnavailableNotify.get(subId, false)) {
+            cancelNetworkSelection(subId);
+            mSelectedUnavailableNotify.remove(subId);
+        }
+    }
+
+    private void dismissNetworkSelectionNotificationForInactiveSubId() {
+        for (int i = 0; i < mSelectedUnavailableNotify.size(); i++) {
+            int subId = mSelectedUnavailableNotify.keyAt(i);
+            if (!mSubscriptionManager.isActiveSubId(subId)) {
+                dismissNetworkSelectionNotification(subId);
+                clearUpNetworkSelectionNotificationParam(subId);
             }
         }
     }
@@ -677,4 +731,65 @@
     private void logi(String msg) {
         Log.i(LOG_TAG, msg);
     }
+
+    /**
+     * In case network selection notification shows up repeatedly under
+     * unstable network condition. The logic is to check whether or not
+     * the service state keeps in no service condition for at least
+     * {@link #NETWORK_SELECTION_NOTIFICATION_MAX_PENDING_TIME_IN_MS}.
+     * And checking {@link #NETWORK_SELECTION_NOTIFICATION_MAX_PENDING_TIMES} times.
+     * To avoid the notification showing up for the momentary state.
+     */
+    private void shouldShowNotification(int serviceState, int subId) {
+        if (serviceState == ServiceState.STATE_OUT_OF_SERVICE) {
+            if (mPreviousServiceState.get(subId, STATE_UNKNOWN_SERVICE)
+                    != ServiceState.STATE_OUT_OF_SERVICE) {
+                mOOSTimestamp.put(subId, getTimeStamp());
+            }
+            if ((getTimeStamp() - mOOSTimestamp.get(subId, 0L)
+                    >= NETWORK_SELECTION_NOTIFICATION_MAX_PENDING_TIME_IN_MS)
+                    || mPendingEventCounter.get(subId, 0)
+                    > NETWORK_SELECTION_NOTIFICATION_MAX_PENDING_TIMES) {
+                showNetworkSelection(mSelectedNetworkOperatorName.get(subId), subId);
+                clearUpNetworkSelectionNotificationParam(subId);
+            } else {
+                startPendingNetworkSelectionNotification(subId);
+            }
+        } else {
+            dismissNetworkSelectionNotification(subId);
+        }
+        mPreviousServiceState.put(subId, serviceState);
+        if (DBG) {
+            log("shouldShowNotification()..." + " subId = " + subId
+                    + " serviceState = " + serviceState
+                    + " mOOSTimestamp = " + mOOSTimestamp
+                    + " mPendingEventCounter = " + mPendingEventCounter);
+        }
+    }
+
+    private void startPendingNetworkSelectionNotification(int subId) {
+        if (!mHandler.hasMessages(EVENT_PENDING_NETWORK_SELECTION_NOTIFICATION, subId)) {
+            if (DBG) {
+                log("startPendingNetworkSelectionNotification: subId = " + subId);
+            }
+            mHandler.sendMessageDelayed(
+                    mHandler.obtainMessage(EVENT_PENDING_NETWORK_SELECTION_NOTIFICATION, subId),
+                    NETWORK_SELECTION_NOTIFICATION_MAX_PENDING_TIME_IN_MS);
+            mPendingEventCounter.put(subId, mPendingEventCounter.get(subId, 0) + 1);
+        }
+    }
+
+    private void clearUpNetworkSelectionNotificationParam(int subId) {
+        if (mHandler.hasMessages(EVENT_PENDING_NETWORK_SELECTION_NOTIFICATION, subId)) {
+            mHandler.removeMessages(EVENT_PENDING_NETWORK_SELECTION_NOTIFICATION, subId);
+        }
+        mPreviousServiceState.remove(subId);
+        mOOSTimestamp.remove(subId);
+        mPendingEventCounter.remove(subId);
+        mSelectedNetworkOperatorName.remove(subId);
+    }
+
+    private static long getTimeStamp() {
+        return SystemClock.elapsedRealtime();
+    }
 }
diff --git a/src/com/android/phone/PhoneInterfaceManager.java b/src/com/android/phone/PhoneInterfaceManager.java
index 6090d89..8cdb4b9 100755
--- a/src/com/android/phone/PhoneInterfaceManager.java
+++ b/src/com/android/phone/PhoneInterfaceManager.java
@@ -54,6 +54,7 @@
 import android.telecom.PhoneAccount;
 import android.telecom.PhoneAccountHandle;
 import android.telecom.TelecomManager;
+import android.telephony.emergency.EmergencyNumber;
 import android.telephony.CarrierConfigManager;
 import android.telephony.CellInfo;
 import android.telephony.CellInfoGsm;
@@ -169,8 +170,8 @@
     private static final int EVENT_NV_WRITE_ITEM_DONE = 16;
     private static final int CMD_NV_WRITE_CDMA_PRL = 17;
     private static final int EVENT_NV_WRITE_CDMA_PRL_DONE = 18;
-    private static final int CMD_NV_RESET_CONFIG = 19;
-    private static final int EVENT_NV_RESET_CONFIG_DONE = 20;
+    private static final int CMD_RESET_MODEM_CONFIG = 19;
+    private static final int EVENT_RESET_MODEM_CONFIG_DONE = 20;
     private static final int CMD_GET_PREFERRED_NETWORK_TYPE = 21;
     private static final int EVENT_GET_PREFERRED_NETWORK_TYPE_DONE = 22;
     private static final int CMD_SET_PREFERRED_NETWORK_TYPE = 23;
@@ -214,6 +215,8 @@
     private static final int EVENT_GET_ALL_CELL_INFO_DONE = 61;
     private static final int CMD_GET_CELL_LOCATION = 62;
     private static final int EVENT_GET_CELL_LOCATION_DONE = 63;
+    private static final int CMD_MODEM_REBOOT = 64;
+    private static final int EVENT_CMD_MODEM_REBOOT_DONE = 65;
 
     // Parameters of select command.
     private static final int SELECT_COMMAND = 0xA4;
@@ -652,14 +655,14 @@
                     handleNullReturnEvent(msg, "nvWriteCdmaPrl");
                     break;
 
-                case CMD_NV_RESET_CONFIG:
+                case CMD_RESET_MODEM_CONFIG:
                     request = (MainThreadRequest) msg.obj;
-                    onCompleted = obtainMessage(EVENT_NV_RESET_CONFIG_DONE, request);
-                    mPhone.nvResetConfig((Integer) request.argument, onCompleted);
+                    onCompleted = obtainMessage(EVENT_RESET_MODEM_CONFIG_DONE, request);
+                    mPhone.resetModemConfig(onCompleted);
                     break;
 
-                case EVENT_NV_RESET_CONFIG_DONE:
-                    handleNullReturnEvent(msg, "nvResetConfig");
+                case EVENT_RESET_MODEM_CONFIG_DONE:
+                    handleNullReturnEvent(msg, "resetModemConfig");
                     break;
 
                 case CMD_GET_PREFERRED_NETWORK_TYPE:
@@ -1040,6 +1043,16 @@
                     break;
                 }
 
+                case CMD_MODEM_REBOOT:
+                    request = (MainThreadRequest) msg.obj;
+                    onCompleted = obtainMessage(EVENT_RESET_MODEM_CONFIG_DONE, request);
+                    mPhone.rebootModem(onCompleted);
+                    break;
+
+                case EVENT_CMD_MODEM_REBOOT_DONE:
+                    handleNullReturnEvent(msg, "rebootModem");
+                    break;
+
                 default:
                     Log.w(LOG_TAG, "MainThreadHandler: unexpected message code: " + msg.what);
                     break;
@@ -3367,26 +3380,56 @@
     }
 
     /**
-     * Perform the specified type of NV config reset.
+     * Rollback modem configurations to factory default except some config which are in whitelist.
      * Used for device configuration by some CDMA operators.
      *
-     * @param resetType the type of reset to perform (1 == factory reset; 2 == NV-only reset)
+     * @param slotIndex - device slot.
+     *
      * @return true on success; false on any failure
      */
     @Override
-    public boolean nvResetConfig(int resetType) {
-        TelephonyPermissions.enforceCallingOrSelfModifyPermissionOrCarrierPrivilege(
-                mApp, getDefaultSubscription(), "nvResetConfig");
+    public boolean resetModemConfig(int slotIndex) {
+        Phone phone = PhoneFactory.getPhone(slotIndex);
+        if (phone != null) {
+            TelephonyPermissions.enforceCallingOrSelfModifyPermissionOrCarrierPrivilege(
+                    mApp, phone.getSubId(), "resetModemConfig");
 
-        final long identity = Binder.clearCallingIdentity();
-        try {
-            if (DBG) log("nvResetConfig: type " + resetType);
-            Boolean success = (Boolean) sendRequest(CMD_NV_RESET_CONFIG, resetType);
-            if (DBG) log("nvResetConfig: type " + resetType + ' ' + (success ? "ok" : "fail"));
-            return success;
-        } finally {
-            Binder.restoreCallingIdentity(identity);
+            final long identity = Binder.clearCallingIdentity();
+            try {
+                Boolean success = (Boolean) sendRequest(CMD_RESET_MODEM_CONFIG, null);
+                if (DBG) log("resetModemConfig:" + ' ' + (success ? "ok" : "fail"));
+                return success;
+            } finally {
+                Binder.restoreCallingIdentity(identity);
+            }
         }
+        return false;
+    }
+
+    /**
+     * Generate a radio modem reset. Used for device configuration by some CDMA operators.
+     *
+     * @param slotIndex - device slot.
+     *
+     * @return true on success; false on any failure
+     */
+    @Override
+    public boolean rebootModem(int slotIndex) {
+        Phone phone = PhoneFactory.getPhone(slotIndex);
+        if (phone != null) {
+            TelephonyPermissions.enforceCallingOrSelfModifyPermissionOrCarrierPrivilege(
+                    mApp, phone.getSubId(), "rebootModem");
+
+            final long identity = Binder.clearCallingIdentity();
+            try {
+                Boolean success = (Boolean) sendRequest(CMD_MODEM_REBOOT, null);
+                if (DBG) log("rebootModem:" + ' ' + (success ? "ok" : "fail"));
+                return success;
+            } finally {
+                Binder.restoreCallingIdentity(identity);
+            }
+        }
+        return false;
     }
 
     public String[] getPcscfAddress(String apnType, String callingPackage) {
@@ -3750,7 +3793,7 @@
 
     /**
      * Check TETHER_DUN_REQUIRED and TETHER_DUN_APN settings, net.tethering.noprovisioning
-     * SystemProperty, and config_tether_apndata to decide whether DUN APN is required for
+     * SystemProperty to decide whether DUN APN is required for
      * tethering.
      *
      * @return 0: Not required. 1: required. 2: Not set.
@@ -3764,8 +3807,7 @@
         try {
             int dunRequired = Settings.Global.getInt(mPhone.getContext().getContentResolver(),
                     Settings.Global.TETHER_DUN_REQUIRED, 2);
-            // If not set, check net.tethering.noprovisioning, TETHER_DUN_APN setting and
-            // config_tether_apndata.
+            // If not set, check net.tethering.noprovisioning, TETHER_DUN_APN setting
             if (dunRequired == 2 && mPhone.hasMatchedTetherApnSetting()) {
                 dunRequired = 1;
             }
@@ -4383,7 +4425,14 @@
         }
     }
 
-    public boolean isRttSupported() {
+    /**
+     * Determines whether the device currently supports RTT (Real-time text). Based both on carrier
+     * support for the feature and device firmware support.
+     *
+     * @return {@code true} if the device and carrier both support RTT, {@code false} otherwise.
+     */
+    @Override
+    public boolean isRttSupported(int subscriptionId) {
         final long identity = Binder.clearCallingIdentity();
         try {
             boolean isCarrierSupported = mApp.getCarrierConfigForSubId(
@@ -4397,10 +4446,14 @@
         }
     }
 
-    public boolean isRttEnabled() {
+    /**
+     * Determines whether the user has turned on RTT. Only returns true if the device and carrier
+     * both also support RTT.
+     */
+    public boolean isRttEnabled(int subscriptionId) {
         final long identity = Binder.clearCallingIdentity();
         try {
-            return isRttSupported() && Settings.Secure.getInt(
+            return isRttSupported(subscriptionId) && Settings.Secure.getInt(
                     mPhone.getContext().getContentResolver(),
                     Settings.Secure.RTT_CALLING_MODE, 0) != 0;
         } finally {
@@ -5703,4 +5756,37 @@
 
         SmsApplication.setDefaultApplicationAsUser(packageName, mApp, userId);
     }
+
+    @Override
+    public Map<Integer, List<EmergencyNumber>> getCurrentEmergencyNumberList(
+            String callingPackage) {
+        // TODO connect with internal content
+        return null;
+    }
+
+    @Override
+    public boolean isCurrentEmergencyNumber(String number) {
+        // TODO connect with internal content
+        return false;
+    }
+
+    @Override
+    public List<String> getCertsFromCarrierPrivilegeAccessRules(int subId) {
+        enforceReadPrivilegedPermission("getCertsFromCarrierPrivilegeAccessRules");
+        Phone phone = getPhone(subId);
+        if (phone == null) {
+            return null;
+        }
+        final long identity = Binder.clearCallingIdentity();
+        try {
+            UiccProfile profile = UiccController.getInstance()
+                    .getUiccProfileForPhone(phone.getPhoneId());
+            if (profile != null) {
+                return profile.getCertsFromCarrierPrivilegeAccessRules();
+            }
+        } finally {
+            Binder.restoreCallingIdentity(identity);
+        }
+        return null;
+    }
 }
diff --git a/src/com/android/phone/PhoneUtils.java b/src/com/android/phone/PhoneUtils.java
index c1bd1b6..3306d4b 100644
--- a/src/com/android/phone/PhoneUtils.java
+++ b/src/com/android/phone/PhoneUtils.java
@@ -429,6 +429,12 @@
             // been assigned for the PUK unlock / SIM READY process.
             app.setPukEntryProgressDialog(pd);
 
+        } else if ((app.getPUKEntryActivity() != null) && (state == MmiCode.State.FAILED)) {
+            createUssdDialog(app, context, text,
+                    WindowManager.LayoutParams.TYPE_KEYGUARD_DIALOG);
+            // In case of failure to unlock, we'll need to reset the
+            // PUK unlock activity, so that the user may try again.
+            app.setPukEntryActivity(null);
         } else {
             // In case of failure to unlock, we'll need to reset the
             // PUK unlock activity, so that the user may try again.
@@ -439,42 +445,8 @@
             // A USSD in a pending state means that it is still
             // interacting with the user.
             if (state != MmiCode.State.PENDING) {
-                log("displayMMIComplete: MMI code has finished running.");
-
-                log("displayMMIComplete: Extended NW displayMMIInitiate (" + text + ")");
-                if (text == null || text.length() == 0)
-                    return;
-
-                // displaying system alert dialog on the screen instead of
-                // using another activity to display the message.  This
-                // places the message at the forefront of the UI.
-
-                if (sUssdDialog == null) {
-                    sUssdDialog = new AlertDialog.Builder(context, THEME)
-                            .setPositiveButton(R.string.ok, null)
-                            .setCancelable(true)
-                            .setOnDismissListener(new DialogInterface.OnDismissListener() {
-                                @Override
-                                public void onDismiss(DialogInterface dialog) {
-                                    sUssdMsg.setLength(0);
-                                }
-                            })
-                            .create();
-
-                    sUssdDialog.getWindow().setType(
-                            WindowManager.LayoutParams.TYPE_SYSTEM_ALERT);
-                    sUssdDialog.getWindow().addFlags(
-                            WindowManager.LayoutParams.FLAG_DIM_BEHIND);
-                }
-                if (sUssdMsg.length() != 0) {
-                    sUssdMsg
-                            .insert(0, "\n")
-                            .insert(0, app.getResources().getString(R.string.ussd_dialog_sep))
-                            .insert(0, "\n");
-                }
-                sUssdMsg.insert(0, text);
-                sUssdDialog.setMessage(sUssdMsg.toString());
-                sUssdDialog.show();
+                createUssdDialog(app, context, text,
+                        WindowManager.LayoutParams.TYPE_SYSTEM_ALERT);
             } else {
                 log("displayMMIComplete: USSD code has requested user input. Constructing input "
                         + "dialog.");
@@ -588,6 +560,46 @@
         }
     }
 
+    private static void createUssdDialog(PhoneGlobals app, Context context, CharSequence text,
+            int windowType) {
+        log("displayMMIComplete: MMI code has finished running.");
+
+        log("displayMMIComplete: Extended NW displayMMIInitiate (" + text + ")");
+        if (text == null || text.length() == 0) {
+            return;
+        }
+
+        // displaying system alert dialog on the screen instead of
+        // using another activity to display the message.  This
+        // places the message at the forefront of the UI.
+
+        if (sUssdDialog == null) {
+            sUssdDialog = new AlertDialog.Builder(context, THEME)
+                    .setPositiveButton(R.string.ok, null)
+                    .setCancelable(true)
+                    .setOnDismissListener(new DialogInterface.OnDismissListener() {
+                        @Override
+                        public void onDismiss(DialogInterface dialog) {
+                            sUssdMsg.setLength(0);
+                        }
+                    })
+                    .create();
+
+            sUssdDialog.getWindow().setType(windowType);
+            sUssdDialog.getWindow().addFlags(
+                    WindowManager.LayoutParams.FLAG_DIM_BEHIND);
+        }
+        if (sUssdMsg.length() != 0) {
+            sUssdMsg
+                    .insert(0, "\n")
+                    .insert(0, app.getResources().getString(R.string.ussd_dialog_sep))
+                    .insert(0, "\n");
+        }
+        sUssdMsg.insert(0, text);
+        sUssdDialog.setMessage(sUssdMsg.toString());
+        sUssdDialog.show();
+    }
+
     /**
      * Cancels the current pending MMI operation, if applicable.
      * @return true if we canceled an MMI operation, or false
diff --git a/src/com/android/phone/otasp/OtaspActivationService.java b/src/com/android/phone/otasp/OtaspActivationService.java
index c41640c..7490880 100644
--- a/src/com/android/phone/otasp/OtaspActivationService.java
+++ b/src/com/android/phone/otasp/OtaspActivationService.java
@@ -28,6 +28,7 @@
 import android.telephony.SubscriptionManager;
 import android.telephony.TelephonyManager;
 
+import com.android.internal.telephony.GsmCdmaConnection;
 import com.android.internal.telephony.Phone;
 import com.android.internal.telephony.PhoneConstants;
 import com.android.phone.PhoneGlobals;
@@ -45,8 +46,10 @@
 public class OtaspActivationService extends Service {
     private static final String TAG = OtaspActivationService.class.getSimpleName();
     private static final boolean DBG = true;
-    /* non-interactive otasp number */
-    private static final String OTASP_NUMBER = "*22899";
+    /**
+     * non-interactive otasp number
+     */
+    private static final String OTASP_NUMBER = GsmCdmaConnection.OTASP_NUMBER;
 
     /**
      * Otasp call follows with SIM reloading which might triggers a retry loop on activation
diff --git a/src/com/android/phone/settings/AccessibilitySettingsFragment.java b/src/com/android/phone/settings/AccessibilitySettingsFragment.java
index 0eb3845..5c614d9 100644
--- a/src/com/android/phone/settings/AccessibilitySettingsFragment.java
+++ b/src/com/android/phone/settings/AccessibilitySettingsFragment.java
@@ -109,7 +109,8 @@
             mButtonHac = null;
         }
 
-        if (PhoneGlobals.getInstance().phoneMgr.isRttSupported()) {
+        if (PhoneGlobals.getInstance().phoneMgr
+                .isRttSupported(SubscriptionManager.getDefaultVoiceSubscriptionId())) {
             // TODO: this is going to be a on/off switch for now. Ask UX about how to integrate
             // this settings with TTY
             boolean rttOn = Settings.Secure.getInt(
diff --git a/src/com/android/services/telephony/DisconnectCauseUtil.java b/src/com/android/services/telephony/DisconnectCauseUtil.java
index 611d147..9ed34e7 100644
--- a/src/com/android/services/telephony/DisconnectCauseUtil.java
+++ b/src/com/android/services/telephony/DisconnectCauseUtil.java
@@ -173,6 +173,7 @@
             case android.telephony.DisconnectCause.CANT_CALL_WHILE_RINGING:
             case android.telephony.DisconnectCause.CALLING_DISABLED:
             case android.telephony.DisconnectCause.TOO_MANY_ONGOING_CALLS:
+            case android.telephony.DisconnectCause.OTASP_PROVISIONING_IN_PROCESS:
             case android.telephony.DisconnectCause.UNOBTAINABLE_NUMBER:
             case android.telephony.DisconnectCause.VOICEMAIL_NUMBER_MISSING:
             case android.telephony.DisconnectCause.DIAL_MODIFIED_TO_USSD:
@@ -337,11 +338,12 @@
             case android.telephony.DisconnectCause.TOO_MANY_ONGOING_CALLS:
                 resourceId = R.string.callFailed_too_many_calls;
                 break;
-
             case android.telephony.DisconnectCause.IMS_SIP_ALTERNATE_EMERGENCY_CALL:
                 resourceId = R.string.incall_error_power_off;
                 break;
-
+            case android.telephony.DisconnectCause.OTASP_PROVISIONING_IN_PROCESS:
+                resourceId = R.string.callFailed_otasp_provisioning_in_process;
+                break;
             default:
                 break;
         }
@@ -717,11 +719,12 @@
             case android.telephony.DisconnectCause.TOO_MANY_ONGOING_CALLS:
                 resourceId = R.string.callFailed_too_many_calls;
                 break;
-
             case android.telephony.DisconnectCause.IMS_SIP_ALTERNATE_EMERGENCY_CALL:
                 resourceId = R.string.incall_error_power_off;
                 break;
-
+            case android.telephony.DisconnectCause.OTASP_PROVISIONING_IN_PROCESS:
+                resourceId = R.string.callFailed_otasp_provisioning_in_process;
+                break;
             default:
                 break;
         }
diff --git a/src/com/android/services/telephony/TelecomAccountRegistry.java b/src/com/android/services/telephony/TelecomAccountRegistry.java
index 6b7a002..a0e5530 100644
--- a/src/com/android/services/telephony/TelecomAccountRegistry.java
+++ b/src/com/android/services/telephony/TelecomAccountRegistry.java
@@ -260,7 +260,7 @@
                 extras.putBoolean(PhoneAccount.EXTRA_PLAY_CALL_RECORDING_TONE, true);
             }
 
-            if (PhoneGlobals.getInstance().phoneMgr.isRttEnabled()) {
+            if (PhoneGlobals.getInstance().phoneMgr.isRttEnabled(subId)) {
                 capabilities |= PhoneAccount.CAPABILITY_RTT;
             }
 
@@ -525,7 +525,8 @@
         }
 
         public void updateRttCapability() {
-            boolean isRttEnabled = PhoneGlobals.getInstance().phoneMgr.isRttEnabled();
+            boolean isRttEnabled = PhoneGlobals.getInstance().phoneMgr
+                    .isRttEnabled(mPhone.getSubId());
             boolean oldRttEnabled = mAccount.hasCapabilities(PhoneAccount.CAPABILITY_RTT);
             if (isRttEnabled != oldRttEnabled) {
                 mAccount = registerPstnPhoneAccount(mIsEmergency, mIsDummy);
diff --git a/src/com/android/services/telephony/TelephonyConnectionService.java b/src/com/android/services/telephony/TelephonyConnectionService.java
index 07754c6..f986994 100644
--- a/src/com/android/services/telephony/TelephonyConnectionService.java
+++ b/src/com/android/services/telephony/TelephonyConnectionService.java
@@ -1140,6 +1140,9 @@
                 case CallStateException.ERROR_TOO_MANY_CALLS:
                     cause = android.telephony.DisconnectCause.TOO_MANY_ONGOING_CALLS;
                     break;
+                case CallStateException.ERROR_OTASP_PROVISIONING_IN_PROCESS:
+                    cause = android.telephony.DisconnectCause.OTASP_PROVISIONING_IN_PROCESS;
+                    break;
             }
             connection.setDisconnected(DisconnectCauseUtil.toTelecomDisconnectCause(
                     cause, e.getMessage(), phone.getPhoneId()));