Merge "Change the way to determine the availability of emergency over VoWi-Fi"
diff --git a/src/com/android/phone/PhoneInterfaceManager.java b/src/com/android/phone/PhoneInterfaceManager.java
index f661a92..8942d8a 100644
--- a/src/com/android/phone/PhoneInterfaceManager.java
+++ b/src/com/android/phone/PhoneInterfaceManager.java
@@ -2466,6 +2466,20 @@
                 ? getDefaultPhone() : getPhone(subId);
     }
 
+    /**
+     * Get phone object associated with a subscription.
+     * Return default phone if phone object associated with subscription is null
+     * @param subId - subscriptionId
+     * @return phone object associated with a subscription or default phone if null.
+     */
+    private Phone getPhoneFromSubIdOrDefault(int subId) {
+        Phone phone = getPhoneFromSubId(subId);
+        if (phone == null) {
+            phone = getDefaultPhone();
+        }
+        return phone;
+    }
+
     @Nullable
     private UiccPort getUiccPortFromRequest(@NonNull MainThreadRequest request) {
         Phone phone = getPhoneFromRequest(request);
@@ -6729,11 +6743,10 @@
             throw new SecurityException(
                     "setAllowedNetworkTypesForReason cannot be called with carrier privileges for"
                             + " reason "
-                            + TelephonyManager.allowedNetworkTypesReasonToString(reason));
+                            + reason);
         }
         if (!TelephonyManager.isValidAllowedNetworkTypesReason(reason)) {
-            loge("setAllowedNetworkTypesForReason: Invalid allowed network type reason: "
-                    + TelephonyManager.allowedNetworkTypesReasonToString(reason));
+            loge("setAllowedNetworkTypesForReason: Invalid allowed network type reason: " + reason);
             return false;
         }
         if (!SubscriptionManager.isUsableSubscriptionId(subId)) {
@@ -6741,10 +6754,8 @@
             return false;
         }
 
-        log("setAllowedNetworkTypesForReason: subId=" + subId + ", reason="
-                + TelephonyManager.allowedNetworkTypesReasonToString(reason) + ", network types: "
-                + TelephonyManager.convertNetworkTypeBitmaskToString(allowedNetworkTypes)
-                + ", callingPackage=" + getCurrentPackageName());
+        log("setAllowedNetworkTypesForReason: subId=" + subId + ", reason=" + reason + " value: "
+                + TelephonyManager.convertNetworkTypeBitmaskToString(allowedNetworkTypes));
 
         Phone phone = getPhone(subId);
         if (phone == null) {
@@ -6752,9 +6763,7 @@
         }
 
         if (allowedNetworkTypes == phone.getAllowedNetworkTypes(reason)) {
-            log("setAllowedNetworkTypesForReason: "
-                    + TelephonyManager.allowedNetworkTypesReasonToString(reason)
-                    + " already has the specified network types.");
+            log("setAllowedNetworkTypesForReason: " + reason + "does not change value");
             return true;
         }
 
@@ -11745,7 +11754,8 @@
             boolean updateIfNeeded) {
         enforceInteractAcrossUsersPermission("getDefaultRespondViaMessageApplication");
 
-        Context context = getPhone(subId).getContext();
+        Context context = getPhoneFromSubIdOrDefault(subId).getContext();
+
         UserHandle userHandle = null;
         final long identity = Binder.clearCallingIdentity();
         try {
diff --git a/src/com/android/services/telephony/TelephonyConnectionService.java b/src/com/android/services/telephony/TelephonyConnectionService.java
index 7d7d949..68956bd 100644
--- a/src/com/android/services/telephony/TelephonyConnectionService.java
+++ b/src/com/android/services/telephony/TelephonyConnectionService.java
@@ -557,13 +557,22 @@
                         Connection connection, @Connection.ConnectionState int state) {
                     TelephonyConnection c = (TelephonyConnection) connection;
                     if (c != null) {
-                        if (c.getState() == Connection.STATE_ACTIVE) {
-                            Log.d(LOG_TAG, "Call State->ACTIVE."
-                                    + "Clearing DomainSelectionConnection");
-                            c.removeTelephonyConnectionListener(mNormalCallConnectionListener);
-                            mDomainSelectionConnection.finishSelection();
-                            mDomainSelectionConnection = null;
-                            mNormalCallConnection = null;
+                        switch(c.getState()) {
+                            case Connection.STATE_ACTIVE: {
+                                Log.d(LOG_TAG, "Call State->ACTIVE."
+                                        + "Clearing DomainSelectionConnection");
+                                if (mDomainSelectionConnection != null) {
+                                    mDomainSelectionConnection.finishSelection();
+                                    mDomainSelectionConnection = null;
+                                }
+                                mNormalCallConnection = null;
+                            }
+                            break;
+
+                            case Connection.STATE_DISCONNECTED: {
+                                c.removeTelephonyConnectionListener(mNormalCallConnectionListener);
+                            }
+                            break;
                         }
                     }
                 }
@@ -598,7 +607,6 @@
                             if (mDomainSelectionConnection != null) {
                                 mDomainSelectionConnection = null;
                             }
-
                             if (mNormalCallConnection != null) {
                                 // TODO: To support ShowPreciseFailedCause, TelephonyConnection
                                 //  .getShowPreciseFailedCause API should be added.
@@ -2048,8 +2056,10 @@
                             e.getMessage(), phone.getPhoneId()));
             mNormalCallConnection.close();
         }
-        mDomainSelectionConnection.finishSelection();
-        mDomainSelectionConnection = null;
+        if (mDomainSelectionConnection != null) {
+            mDomainSelectionConnection.finishSelection();
+            mDomainSelectionConnection = null;
+        }
         mNormalCallConnection = null;
     }
 
@@ -2060,6 +2070,10 @@
             return false;
         }
 
+        if (phone == null) {
+            return false;
+        }
+
         String dialPart = PhoneNumberUtils.extractNetworkPortionAlt(
                 PhoneNumberUtils.stripSeparators(number));
         boolean isMmiCode = (dialPart.startsWith("*") || dialPart.startsWith("#"))
@@ -2072,6 +2086,16 @@
             return false;
         }
 
+        // Check and select same domain as ongoing call on the same subscription (if exists)
+        int activeCallDomain = getActiveCallDomain(phone.getSubId());
+        if (activeCallDomain != NetworkRegistrationInfo.DOMAIN_UNKNOWN) {
+            Log.d(LOG_TAG, "Selecting same domain as ongoing call on same subId");
+            mNormalCallConnection = connection;
+            handleOutgoingCallConnectionByCallDomainSelection(
+                    activeCallDomain, phone, number, videoState);
+            return true;
+        }
+
         mDomainSelectionConnection = mDomainSelectionResolver
                 .getDomainSelectionConnection(phone, SELECTOR_TYPE_CALLING, false);
         if (mDomainSelectionConnection == null) {
@@ -2313,6 +2337,7 @@
                             callFailCause, reasonInfo);
 
             Log.d(LOG_TAG, "Reselecting the domain for call");
+            mNormalCallConnection = c;
             CompletableFuture<Integer> future = mDomainSelectionConnection
                     .reselectDomain(selectionAttributes);
             if (future != null) {
@@ -2329,7 +2354,7 @@
             mDomainSelectionConnection = null;
         }
         mNormalCallConnection = null;
-        Log.d(LOG_TAG, "Reselecting the domain for call failed");
+        Log.d(LOG_TAG, "Reselect call domain not triggered.");
         return false;
     }
 
@@ -3459,4 +3484,25 @@
                     }
                 });
     }
+
+    private @NetworkRegistrationInfo.Domain int getActiveCallDomain(int subId) {
+        for (Connection c: getAllConnections()) {
+            if ((c instanceof TelephonyConnection)) {
+                TelephonyConnection connection = (TelephonyConnection) c;
+                Phone phone = connection.getPhone();
+                if (phone == null) {
+                    continue;
+                }
+
+                if (phone.getSubId() == subId) {
+                    if (phone instanceof GsmCdmaPhone) {
+                        return NetworkRegistrationInfo.DOMAIN_CS;
+                    } else if (phone instanceof ImsPhone) {
+                        return NetworkRegistrationInfo.DOMAIN_PS;
+                    }
+                }
+            }
+        }
+        return NetworkRegistrationInfo.DOMAIN_UNKNOWN;
+    }
 }
diff --git a/src/com/android/services/telephony/domainselection/ImsStateTracker.java b/src/com/android/services/telephony/domainselection/ImsStateTracker.java
index 51792ff..fc3f811 100644
--- a/src/com/android/services/telephony/domainselection/ImsStateTracker.java
+++ b/src/com/android/services/telephony/domainselection/ImsStateTracker.java
@@ -565,6 +565,8 @@
             setImsStateAsUnavailable();
             unregisterImsRegistrationCallback();
             unregisterMmTelCapabilityCallback();
+            // ImsStateCallback has already been removed after calling onUnavailable.
+            mImsStateCallback = null;
             notifyImsMmTelFeatureAvailableChanged();
         } else {
             logw("onMmTelFeatureUnavailable: unexpected reason=" + reason);
diff --git a/tests/src/com/android/services/telephony/domainselection/ImsStateTrackerTest.java b/tests/src/com/android/services/telephony/domainselection/ImsStateTrackerTest.java
index fc483ee..430adea 100644
--- a/tests/src/com/android/services/telephony/domainselection/ImsStateTrackerTest.java
+++ b/tests/src/com/android/services/telephony/domainselection/ImsStateTrackerTest.java
@@ -210,6 +210,23 @@
 
     @Test
     @SmallTest
+    public void testStartAfterUnavailableWithReasonSubscriptionInactive() throws ImsException {
+        ImsStateCallback callback = setUpImsStateCallback();
+        callback.onUnavailable(ImsStateCallback.REASON_SUBSCRIPTION_INACTIVE);
+
+        mImsStateTracker.start(SUB_1);
+
+        assertTrue(isImsStateInit());
+        // One is invoked in setUpImsStateCallback and the other is invoked in start(int).
+        verify(mMmTelManager, times(2)).registerImsStateCallback(
+                any(Executor.class), any(ImsStateCallback.class));
+        // ImsStateCallback has already been set to null when onUnavailable is called.
+        verify(mMmTelManager, never()).unregisterImsStateCallback(
+                any(ImsStateCallback.class));
+    }
+
+    @Test
+    @SmallTest
     public void testUpdateServiceStateBeforeAddingListener() {
         mImsStateTracker.updateServiceState(mServiceState);
         mImsStateTracker.addServiceStateListener(mServiceStateListener);