Merge "create TM for each subId to register phonestatelistner"
diff --git a/AndroidManifest.xml b/AndroidManifest.xml
index b0c4158..f8d8ca0 100644
--- a/AndroidManifest.xml
+++ b/AndroidManifest.xml
@@ -89,6 +89,7 @@
     <protected-broadcast android:name= "android.telephony.action.SUBSCRIPTION_CARRIER_IDENTITY_CHANGED" />
     <protected-broadcast android:name= "android.telephony.action.SUBSCRIPTION_SPECIFIC_CARRIER_IDENTITY_CHANGED" />
     <protected-broadcast android:name= "android.telephony.action.NETWORK_COUNTRY_CHANGED" />
+    <protected-broadcast android:name= "android.telephony.action.PRIMARY_SUBSCRIPTION_LIST_CHANGED" />
 
     <!-- For Vendor Debugging in Telephony -->
     <protected-broadcast android:name="android.telephony.action.ANOMALY_REPORTED" />
diff --git a/res/values/strings.xml b/res/values/strings.xml
index 8e7d087..f15138e 100644
--- a/res/values/strings.xml
+++ b/res/values/strings.xml
@@ -175,6 +175,13 @@
     <!-- DO NOT TRANSLATE. Internal key for a voicemail notification preference. -->
     <string name="voicemail_notifications_key" translatable="false">voicemail_notification_key</string>
 
+    <!-- Title for Make and receive calls category. -->
+    <string name="make_and_receive_calls">Make &amp; receive calls</string>
+    <!-- Title for the button to launch smart forwarding which will configure call forwarding on both SIMs to forward the call to the other SIM number when its not reachable. -->
+    <string name="smart_forwarding_settings_menu">Smart Forwarding</string>
+    <!-- Description of smart forwarding setting. -->
+    <string name="smart_forwarding_settings_menu_summary">When one number isn\'t reachable, always forward calls to your other number</string>
+
     <!-- Voicemail notifications title. The user clicks on this preference navigate to the system settings screen for that channel
     .[CHAR LIMIT=30] -->
     <string name="voicemail_notifications_preference_title">Notifications</string>
diff --git a/src/com/android/phone/CarrierConfigLoader.java b/src/com/android/phone/CarrierConfigLoader.java
index 137d3d1..6a3e928 100644
--- a/src/com/android/phone/CarrierConfigLoader.java
+++ b/src/com/android/phone/CarrierConfigLoader.java
@@ -324,7 +324,7 @@
                     final String carrierPackageName = getCarrierPackageForPhoneId(phoneId);
                     if (carrierPackageName != null) {
                         log("Found carrier config app: " + carrierPackageName);
-                        sendMessage(obtainMessage(EVENT_DO_FETCH_CARRIER, phoneId));
+                        sendMessage(obtainMessage(EVENT_DO_FETCH_CARRIER, phoneId, -1));
                     } else {
                         broadcastConfigChangedIntent(phoneId);
                     }
diff --git a/src/com/android/phone/PhoneInterfaceManager.java b/src/com/android/phone/PhoneInterfaceManager.java
index 6f02ae2..25abf24 100755
--- a/src/com/android/phone/PhoneInterfaceManager.java
+++ b/src/com/android/phone/PhoneInterfaceManager.java
@@ -2797,6 +2797,22 @@
     }
 
     @Override
+    public boolean isInEmergencySmsMode() {
+        enforceReadPrivilegedPermission("isInEmergencySmsMode");
+        final long identity = Binder.clearCallingIdentity();
+        try {
+            for (Phone phone : PhoneFactory.getPhones()) {
+                if (phone.isInEmergencySmsMode()) {
+                    return true;
+                }
+            }
+        } finally {
+            Binder.restoreCallingIdentity(identity);
+        }
+        return false;
+    }
+
+    @Override
     public void registerImsRegistrationCallback(int subId, IImsRegistrationCallback c)
             throws RemoteException {
         enforceReadPrivilegedPermission("registerImsRegistrationCallback");
@@ -6726,13 +6742,13 @@
     }
 
     @Override
-    public void setMultisimCarrierRestriction(boolean isMultisimCarrierRestricted) {
+    public void setMultiSimCarrierRestriction(boolean isMultiSimCarrierRestricted) {
         enforceModifyPermission();
 
         final long identity = Binder.clearCallingIdentity();
         try {
             mTelephonySharedPreferences.edit()
-                    .putBoolean(PREF_MULTI_SIM_RESTRICTED, isMultisimCarrierRestricted)
+                    .putBoolean(PREF_MULTI_SIM_RESTRICTED, isMultiSimCarrierRestricted)
                     .commit();
         } finally {
             Binder.restoreCallingIdentity(identity);
@@ -6740,45 +6756,47 @@
     }
 
     @Override
-    public boolean isMultisimSupported(String callingPackage) {
+    @TelephonyManager.IsMultiSimSupportedResult
+    public int isMultiSimSupported(String callingPackage) {
         if (!TelephonyPermissions.checkCallingOrSelfReadPhoneState(mApp,
-                getDefaultPhone().getSubId(), callingPackage, "isMultisimSupported")) {
-            return false;
+                getDefaultPhone().getSubId(), callingPackage, "isMultiSimSupported")) {
+            return TelephonyManager.MULTISIM_NOT_SUPPORTED_BY_HARDWARE;
         }
 
         final long identity = Binder.clearCallingIdentity();
         try {
-            return isMultisimSupportedInternal();
+            return isMultiSimSupportedInternal();
         } finally {
             Binder.restoreCallingIdentity(identity);
         }
     }
 
-    private boolean isMultisimSupportedInternal() {
+    @TelephonyManager.IsMultiSimSupportedResult
+    private int isMultiSimSupportedInternal() {
         // If the device has less than 2 SIM cards, indicate that multisim is restricted.
         int numPhysicalSlots = UiccController.getInstance().getUiccSlots().length;
         if (numPhysicalSlots < 2) {
-            loge("isMultisimSupportedInternal: requires at least 2 cards");
-            return false;
+            loge("isMultiSimSupportedInternal: requires at least 2 cards");
+            return TelephonyManager.MULTISIM_NOT_SUPPORTED_BY_HARDWARE;
         }
         // Check if the hardware supports multisim functionality. If usage of multisim is not
         // supported by the modem, indicate that it is restricted.
         PhoneCapability staticCapability =
                 mPhoneConfigurationManager.getStaticPhoneCapability();
         if (staticCapability == null) {
-            loge("isMultisimSupportedInternal: no static configuration available");
-            return false;
+            loge("isMultiSimSupportedInternal: no static configuration available");
+            return TelephonyManager.MULTISIM_NOT_SUPPORTED_BY_HARDWARE;
         }
         if (staticCapability.logicalModemList.size() < 2) {
-            loge("isMultisimSupportedInternal: maximum number of modem is < 2");
-            return false;
+            loge("isMultiSimSupportedInternal: maximum number of modem is < 2");
+            return TelephonyManager.MULTISIM_NOT_SUPPORTED_BY_HARDWARE;
         }
         // Check if support of multiple SIMs is restricted by carrier
         if (mTelephonySharedPreferences.getBoolean(PREF_MULTI_SIM_RESTRICTED, false)) {
-            return false;
+            return TelephonyManager.MULTISIM_NOT_SUPPORTED_BY_CARRIER;
         }
 
-        return true;
+        return TelephonyManager.MULTISIM_ALLOWED;
     }
 
     /**
@@ -6800,7 +6818,7 @@
 
         try {
             //only proceed if multi-sim is not restricted
-            if (!isMultisimSupportedInternal()) {
+            if (isMultiSimSupportedInternal() != TelephonyManager.MULTISIM_ALLOWED) {
                 loge("switchMultiSimConfig not possible. It is restricted or not supported.");
                 return;
             }
diff --git a/src/com/android/phone/SpecialCharSequenceMgr.java b/src/com/android/phone/SpecialCharSequenceMgr.java
index 5a5d488..514b2c9 100644
--- a/src/com/android/phone/SpecialCharSequenceMgr.java
+++ b/src/com/android/phone/SpecialCharSequenceMgr.java
@@ -23,12 +23,19 @@
 import android.content.Intent;
 import android.provider.Settings;
 import android.telephony.PhoneNumberUtils;
+import android.telephony.SubscriptionInfo;
+import android.telephony.SubscriptionManager;
+import android.telephony.TelephonyManager;
 import android.util.Log;
 import android.view.WindowManager;
 
+import com.android.internal.telephony.IccCardConstants;
 import com.android.internal.telephony.Phone;
 import com.android.internal.telephony.TelephonyCapabilities;
 
+import java.util.ArrayList;
+import java.util.List;
+
 /**
  * Helper class to listen for some magic dialpad character sequences
  * that are handled specially by the Phone app.
@@ -185,6 +192,40 @@
         return false;
     }
 
+    private static IccCardConstants.State getSimState(int slotId, Context context) {
+        final TelephonyManager tele = TelephonyManager.from(context);
+        int simState =  tele.getSimState(slotId);
+        IccCardConstants.State state;
+        try {
+            state = IccCardConstants.State.intToState(simState);
+        } catch (IllegalArgumentException ex) {
+            Log.w(TAG, "Unknown sim state: " + simState);
+            state = IccCardConstants.State.UNKNOWN;
+        }
+        return state;
+    }
+
+    private static int getNextSubIdForState(IccCardConstants.State state, Context context) {
+        SubscriptionManager subscriptionManager = SubscriptionManager.from(context);
+        List<SubscriptionInfo> list = subscriptionManager.getActiveSubscriptionInfoList();
+        if (list == null) {
+            // getActiveSubscriptionInfoList was null callers expect an empty list.
+            list = new ArrayList<>();
+        }
+        int resultId = SubscriptionManager.INVALID_SUBSCRIPTION_ID;
+        int bestSlotId = Integer.MAX_VALUE; // Favor lowest slot first
+        for (int i = 0; i < list.size(); i++) {
+            final SubscriptionInfo info = list.get(i);
+            final int id = info.getSubscriptionId();
+            if (state == getSimState(info.getSimSlotIndex(), context)
+                    && bestSlotId > info.getSimSlotIndex()) {
+                resultId = id;
+                bestSlotId = info.getSimSlotIndex();
+            }
+        }
+        return resultId;
+    }
+
     static private boolean handlePinEntry(Context context, String input,
                                           Activity pukInputActivity) {
         // TODO: The string constants here should be removed in favor
@@ -193,7 +234,20 @@
         if ((input.startsWith("**04") || input.startsWith("**05"))
                 && input.endsWith("#")) {
             PhoneGlobals app = PhoneGlobals.getInstance();
-            Phone phone = PhoneGlobals.getPhone();
+            Phone phone;
+            int subId;
+            if (input.startsWith("**04")) {
+                subId = getNextSubIdForState(IccCardConstants.State.PIN_REQUIRED, context);
+            } else {
+                subId = getNextSubIdForState(IccCardConstants.State.PUK_REQUIRED, context);
+            }
+            if (SubscriptionManager.isValidSubscriptionId(subId)) {
+                log("get phone with subId: " + subId);
+                phone = PhoneGlobals.getPhone(subId);
+            } else {
+                log("get default phone");
+                phone = PhoneGlobals.getPhone();
+            }
             boolean isMMIHandled = phone.handlePinMmi(input);
 
             // if the PUK code is recognized then indicate to the
diff --git a/src/com/android/services/telephony/TelephonyConnectionService.java b/src/com/android/services/telephony/TelephonyConnectionService.java
index 2cd62ff..fd7eeb2 100644
--- a/src/com/android/services/telephony/TelephonyConnectionService.java
+++ b/src/com/android/services/telephony/TelephonyConnectionService.java
@@ -518,6 +518,7 @@
     }
 
     private boolean isEmergencyNumberTestNumber(String number) {
+        number = PhoneNumberUtils.stripSeparators(number);
         Map<Integer, List<EmergencyNumber>> list =
                 mTelephonyManagerProxy.getCurrentEmergencyNumberList();
         // Do not worry about which subscription the test emergency call is on yet, only detect that