Mark DDS PhoneAccount as CAPABILITY_EMERGENCY_PREFERRED

On MSIM devices where GNSS SUPL is not supported for
emergency calls on the non-DDS subscription, mark the
DDS subscription as CAPABILITY_EMERGENCY_PREFERRED so
that Telecom will override the user's choice of
PhoneAccount and always try to place the emergency call
over the DDS subscription.

Note: We do not set this preference if the subscription is
marked as opportunistic. If the DDS is a data only SIM, we
will dial on the non-DDS when Telephony receives the
outgoing call request.

Bug: 131203278
Test: Manual Testing; atest FrameworkTelephonyTests
Change-Id: I6beb1955bb0aa4140e1ce5b17d51d249c4b85106
diff --git a/res/values/config.xml b/res/values/config.xml
index 6b6bf04..adabe6c 100644
--- a/res/values/config.xml
+++ b/res/values/config.xml
@@ -257,4 +257,11 @@
     <!-- The country list that shortcut view can be enabled. -->
     <string-array name="config_countries_to_enable_shortcut_view" translatable="false">
     </string-array>
+
+    <!-- When an emergency call is placed and the carrier supports network initiated SUPL requests
+         for location, this configuration dictates whether or not the modem supports SUPL requests
+         being handled on the logical slot that is not currently configured as the default data
+         slot. If true, telephony will always try to place the emergency call on the subscription
+         associated with default data first, instead of using the default voice configuration.-->
+    <bool name="config_gnss_supl_requires_default_data_for_emergency">false</bool>
 </resources>
diff --git a/src/com/android/services/telephony/TelecomAccountRegistry.java b/src/com/android/services/telephony/TelecomAccountRegistry.java
index 21685a3..177d669 100644
--- a/src/com/android/services/telephony/TelecomAccountRegistry.java
+++ b/src/com/android/services/telephony/TelecomAccountRegistry.java
@@ -56,6 +56,7 @@
 import com.android.ims.ImsManager;
 import com.android.internal.telephony.Phone;
 import com.android.internal.telephony.PhoneFactory;
+import com.android.internal.telephony.SubscriptionController;
 import com.android.phone.PhoneGlobals;
 import com.android.phone.PhoneUtils;
 import com.android.phone.R;
@@ -84,6 +85,7 @@
         private final PstnPhoneCapabilitiesNotifier mPhoneCapabilitiesNotifier;
         private boolean mIsEmergency;
         private boolean mIsRttCapable;
+        private boolean mIsEmergencyPreferred;
         private MmTelFeature.MmTelCapabilities mMmTelCapabilities;
         private ImsMmTelManager.CapabilityCallback mMmtelCapabilityCallback;
         private ImsMmTelManager mMmTelManager;
@@ -271,6 +273,11 @@
                 capabilities |= PhoneAccount.CAPABILITY_PLACE_EMERGENCY_CALLS;
             }
 
+            mIsEmergencyPreferred = isEmergencyPreferredAccount(subId);
+            if (mIsEmergencyPreferred) {
+                capabilities |= PhoneAccount.CAPABILITY_EMERGENCY_PREFERRED;
+            }
+
             if (isRttCurrentlySupported()) {
                 capabilities |= PhoneAccount.CAPABILITY_RTT;
                 mIsRttCapable = true;
@@ -410,6 +417,36 @@
         }
 
         /**
+         * In some cases, we need to try sending the emergency call over this PhoneAccount due to
+         * restrictions and limitations in MSIM configured devices. This includes the following:
+         * 1) The device does not support GNSS SUPL requests on the non-DDS subscription due to
+         *   modem limitations. If the device does not support SUPL on non-DDS, we need to try the
+         *   emergency call on the DDS subscription first to allow for SUPL to be completed.
+         *
+         * @return true if Telecom should prefer this PhoneAccount, false if there is no preference
+         * needed.
+         */
+        private boolean isEmergencyPreferredAccount(int subId) {
+            final boolean gnssSuplRequiresDefaultData = mContext.getResources().getBoolean(
+                    R.bool.config_gnss_supl_requires_default_data_for_emergency);
+            if (!gnssSuplRequiresDefaultData) {
+                // No preference is necessary.
+                return false;
+            }
+
+            // Only set a preference on MSIM devices
+            if (mTelephonyManager.getPhoneCount() <= 1) {
+                return false;
+            }
+            // Check to see if this PhoneAccount is associated with the default Data subscription.
+            if (!SubscriptionManager.isValidSubscriptionId(subId)) {
+                return false;
+            }
+            SubscriptionController controller = SubscriptionController.getInstance();
+            return controller != null && (controller.getDefaultDataSubId() == subId);
+        }
+
+        /**
          * Determines from carrier configuration whether pausing of IMS video calls is supported.
          *
          * @return {@code true} if pausing IMS video calls is supported.
@@ -596,6 +633,14 @@
             }
         }
 
+        public void updateDefaultDataSubId() {
+            boolean isEmergencyPreferred = isEmergencyPreferredAccount(mPhone.getSubId());
+            if (isEmergencyPreferred != mIsEmergencyPreferred) {
+                Log.i(this, "updateDefaultDataSubId - changed, new value: " + isEmergencyPreferred);
+                mAccount = registerPstnPhoneAccount(mIsEmergency, mIsDummy);
+            }
+        }
+
         /**
          * Determines whether RTT is supported given the current state of the
          * device.
@@ -743,6 +788,15 @@
             }
             mServiceState = newState;
         }
+
+        @Override
+        public void onActiveDataSubscriptionIdChanged(int subId) {
+            synchronized (mAccountsLock) {
+                for (AccountEntry account : mAccounts) {
+                    account.updateDefaultDataSubId();
+                }
+            }
+        }
     };
 
     private static TelecomAccountRegistry sInstance;
@@ -951,7 +1005,8 @@
 
         // We also need to listen for changes to the service state (e.g. emergency -> in service)
         // because this could signal a removal or addition of a SIM in a single SIM phone.
-        mTelephonyManager.listen(mPhoneStateListener, PhoneStateListener.LISTEN_SERVICE_STATE);
+        mTelephonyManager.listen(mPhoneStateListener, PhoneStateListener.LISTEN_SERVICE_STATE
+                | PhoneStateListener.LISTEN_ACTIVE_DATA_SUBSCRIPTION_ID_CHANGE);
 
         // Listen for user switches.  When the user switches, we need to ensure that if the current
         // use is not the primary user we disable video calling.