Share the emergency country iso from other sub

In multi-sim, some vendor may only notify the emergency network
info only through one of the IRadio slots, so that the emergency country
info of the other IRadio slots are missing and the emergency number list
from the database cannot be cached based on the country. To solve this,
we need the share the emergency network country to other slots if those
slots are not registrated with the emergency network. We also need to
notify other subs the changed emergency network country iso if the changed
emergency network country iso can be shared.

Test: unit test;
Bug: 137236159
Bug: 137235431
Change-Id: Ie86527eab753e2b3bb8e95120ca8b51904b8bd00
diff --git a/src/java/com/android/internal/telephony/emergency/EmergencyNumberTracker.java b/src/java/com/android/internal/telephony/emergency/EmergencyNumberTracker.java
index 2c822ba..a1a7aea 100644
--- a/src/java/com/android/internal/telephony/emergency/EmergencyNumberTracker.java
+++ b/src/java/com/android/internal/telephony/emergency/EmergencyNumberTracker.java
@@ -41,6 +41,7 @@
 import com.android.internal.telephony.LocaleTracker;
 import com.android.internal.telephony.Phone;
 import com.android.internal.telephony.PhoneConstants;
+import com.android.internal.telephony.PhoneFactory;
 import com.android.internal.telephony.ServiceStateTracker;
 import com.android.internal.telephony.SubscriptionController;
 import com.android.internal.telephony.metrics.TelephonyMetrics;
@@ -80,6 +81,11 @@
     private final CommandsInterface mCi;
     private final Phone mPhone;
     private String mCountryIso;
+    /**
+     * Indicates if the country iso is set by another subscription.
+     * @hide
+     */
+    public boolean mIsCountrySetByAnotherSub = false;
     private String[] mEmergencyNumberPrefix = new String[0];
 
     private static final String EMERGENCY_NUMBER_DB_ASSETS_FILE = "eccdata";
@@ -131,7 +137,9 @@
                     if (TextUtils.isEmpty(countryIso)) {
                         return;
                     }
-                    updateEmergencyNumberDatabaseCountryChange(countryIso);
+
+                    // Update country iso change for available Phones
+                    updateEmergencyCountryIsoAllPhones(countryIso);
                 }
                 return;
             }
@@ -222,11 +230,40 @@
         // If country iso has been cached when listener is set, don't need to cache the initial
         // country iso and initial database.
         if (mCountryIso == null) {
-            mCountryIso = getInitialCountryIso().toLowerCase();
+            updateEmergencyCountryIso(getInitialCountryIso().toLowerCase());
             cacheEmergencyDatabaseByCountry(mCountryIso);
         }
     }
 
+    /**
+     * Update Emergency country iso for all the Phones
+     */
+    @VisibleForTesting
+    public void updateEmergencyCountryIsoAllPhones(String countryIso) {
+        // Notify country iso change for current Phone
+        mIsCountrySetByAnotherSub = false;
+        updateEmergencyNumberDatabaseCountryChange(countryIso);
+
+        // Share and notify country iso change for other Phones if the country
+        // iso in their emergency number tracker is not available or the country
+        // iso there is set by another active subscription.
+        for (Phone phone: PhoneFactory.getPhones()) {
+            if (phone.getPhoneId() == mPhone.getPhoneId()) {
+                continue;
+            }
+            EmergencyNumberTracker emergencyNumberTracker;
+            if (phone != null && phone.getEmergencyNumberTracker() != null) {
+                emergencyNumberTracker = phone.getEmergencyNumberTracker();
+                if (TextUtils.isEmpty(emergencyNumberTracker.getEmergencyCountryIso())
+                        || emergencyNumberTracker.mIsCountrySetByAnotherSub) {
+                    emergencyNumberTracker.mIsCountrySetByAnotherSub = true;
+                    emergencyNumberTracker.updateEmergencyNumberDatabaseCountryChange(
+                            countryIso);
+                }
+            }
+        }
+    }
+
     private void onCarrierConfigChanged() {
         if (mPhone != null) {
             CarrierConfigManager configMgr = (CarrierConfigManager)
@@ -381,8 +418,7 @@
     private void updateEmergencyNumberListDatabaseAndNotify(String countryIso) {
         logd("updateEmergencyNumberListDatabaseAndNotify(): receiving countryIso: "
                 + countryIso);
-
-        mCountryIso = countryIso.toLowerCase();
+        updateEmergencyCountryIso(countryIso.toLowerCase());
         cacheEmergencyDatabaseByCountry(countryIso);
         writeUpdatedEmergencyNumberListMetrics(mEmergencyNumberListFromDatabase);
         if (!DBG) {
@@ -560,6 +596,14 @@
         return EmergencyNumber.EMERGENCY_CALL_ROUTING_UNKNOWN;
     }
 
+    public String getEmergencyCountryIso() {
+        return mCountryIso;
+    }
+
+    private synchronized void updateEmergencyCountryIso(String countryIso) {
+        mCountryIso = countryIso;
+    }
+
     /**
      * Get Emergency number list based on EccList. This util is used for solving backward
      * compatibility if device does not support the 1.4 IRadioIndication HAL that reports
diff --git a/tests/telephonytests/src/com/android/internal/telephony/emergency/EmergencyNumberTrackerTest.java b/tests/telephonytests/src/com/android/internal/telephony/emergency/EmergencyNumberTrackerTest.java
index 4c80685..290c535 100644
--- a/tests/telephonytests/src/com/android/internal/telephony/emergency/EmergencyNumberTrackerTest.java
+++ b/tests/telephonytests/src/com/android/internal/telephony/emergency/EmergencyNumberTrackerTest.java
@@ -17,17 +17,21 @@
 package com.android.internal.telephony.emergency;
 
 import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertTrue;
 import static org.mockito.Mockito.doReturn;
 
 import android.os.AsyncResult;
 import android.os.HandlerThread;
 import android.telephony.emergency.EmergencyNumber;
 
+import com.android.internal.telephony.Phone;
+import com.android.internal.telephony.PhoneFactory;
 import com.android.internal.telephony.TelephonyTest;
 
 import org.junit.After;
 import org.junit.Before;
 import org.junit.Test;
+import org.mockito.Mock;
 
 import java.util.ArrayList;
 import java.util.Collections;
@@ -38,8 +42,16 @@
  */
 public class EmergencyNumberTrackerTest extends TelephonyTest {
 
+    @Mock
+    private Phone mPhone2; // mPhone as phone 1 is already defined in TelephonyTest.
+
+    // mEmergencyNumberTrackerMock for mPhone
     private EmergencyNumberTracker mEmergencyNumberTrackerMock;
+    // mEmergencyNumberTrackerMock2 for mPhone2
+    private EmergencyNumberTracker mEmergencyNumberTrackerMock2;
+
     private List<EmergencyNumber> mEmergencyNumberListTestSample = new ArrayList<>();
+    private EmergencyNumber mUsEmergencyNumber;
     private String[] mEmergencyNumberPrefixTestSample = {"123", "456"};
     private static final long TIMEOUT_MS = 500;
 
@@ -50,6 +62,8 @@
         @Override
         public void onLooperPrepared() {
             mEmergencyNumberTrackerMock = new EmergencyNumberTracker(mPhone, mSimulatedCommands);
+            mEmergencyNumberTrackerMock2 = new EmergencyNumberTracker(mPhone2, mSimulatedCommands);
+            doReturn(mEmergencyNumberTrackerMock2).when(mPhone2).getEmergencyNumberTracker();
             mEmergencyNumberTrackerMock.DBG = true;
             setReady(true);
         }
@@ -62,6 +76,11 @@
         logd("EmergencyNumberTrackerTest +Setup!");
         super.setUp("EmergencyNumberTrackerTest");
         doReturn(mContext).when(mPhone).getContext();
+        doReturn(0).when(mPhone).getPhoneId();
+
+        doReturn(mContext).when(mPhone2).getContext();
+        doReturn(1).when(mPhone2).getPhoneId();
+
         initializeEmergencyNumberListTestSamples();
         mHandlerThread = new EmergencyNumberTrackerTestHandler("EmergencyNumberTrackerTestHandler");
         mHandlerThread.start();
@@ -71,6 +90,9 @@
 
     @After
     public void tearDown() throws Exception {
+        // Set back to single sim mode
+        setSinglePhone();
+
         mHandlerThread.quit();
         mHandlerThread.join();
         super.tearDown();
@@ -82,6 +104,12 @@
                 new ArrayList<String>(),
                 EmergencyNumber.EMERGENCY_NUMBER_SOURCE_NETWORK_SIGNALING,
                 EmergencyNumber.EMERGENCY_CALL_ROUTING_UNKNOWN);
+        mUsEmergencyNumber = new EmergencyNumber("911", "us", "",
+            EmergencyNumber.EMERGENCY_SERVICE_CATEGORY_POLICE
+                | EmergencyNumber.EMERGENCY_SERVICE_CATEGORY_AMBULANCE
+                | EmergencyNumber.EMERGENCY_SERVICE_CATEGORY_FIRE_BRIGADE, new ArrayList<String>(),
+            EmergencyNumber.EMERGENCY_NUMBER_SOURCE_DATABASE,
+            EmergencyNumber.EMERGENCY_CALL_ROUTING_UNKNOWN);
         mEmergencyNumberListTestSample.add(emergencyNumberForTest);
     }
 
@@ -93,11 +121,26 @@
         waitForHandlerAction(mEmergencyNumberTrackerMock, TIMEOUT_MS);
     }
 
-    private void sendEmergencyNumberPrefix() {
-        mEmergencyNumberTrackerMock.obtainMessage(
+    private void cacheEmergencyNumberListFromDatabaseByCountry(String countryIso) {
+        mEmergencyNumberTrackerMock.updateEmergencyNumberDatabaseCountryChange(countryIso);
+        waitForHandlerAction(mEmergencyNumberTrackerMock, TIMEOUT_MS);
+    }
+
+    private void sendEmergencyNumberPrefix(EmergencyNumberTracker emergencyNumberTrackerMock) {
+        emergencyNumberTrackerMock.obtainMessage(
         	4 /* EVENT_UPDATE_EMERGENCY_NUMBER_PREFIX */,
                 mEmergencyNumberPrefixTestSample).sendToTarget();
-        waitForHandlerAction(mEmergencyNumberTrackerMock, TIMEOUT_MS);
+        waitForHandlerAction(emergencyNumberTrackerMock, TIMEOUT_MS);
+    }
+
+    private void setDsdsPhones() throws Exception {
+        mPhones = new Phone[] {mPhone, mPhone2};
+        replaceInstance(PhoneFactory.class, "sPhones", null, mPhones);
+    }
+
+    private void setSinglePhone() throws Exception {
+        mPhones = new Phone[] {mPhone};
+        replaceInstance(PhoneFactory.class, "sPhones", null, mPhones);
     }
 
     @Test
@@ -108,9 +151,66 @@
     }
 
     @Test
+    public void testUpdateEmergencyCountryIso() throws Exception {
+        sendEmergencyNumberPrefix(mEmergencyNumberTrackerMock);
+        mEmergencyNumberTrackerMock.updateEmergencyNumberDatabaseCountryChange("us");
+        waitForHandlerAction(mEmergencyNumberTrackerMock, TIMEOUT_MS);
+
+        assertTrue(mEmergencyNumberTrackerMock.getEmergencyCountryIso().equals("us"));
+    }
+
+    @Test
+    public void testUpdateEmergencyCountryIsoMultiSim() throws Exception {
+        setDsdsPhones();
+        sendEmergencyNumberPrefix(mEmergencyNumberTrackerMock);
+        sendEmergencyNumberPrefix(mEmergencyNumberTrackerMock2);
+        mEmergencyNumberTrackerMock.updateEmergencyCountryIsoAllPhones("jp");
+        waitForHandlerAction(mEmergencyNumberTrackerMock, TIMEOUT_MS);
+        waitForHandlerAction(mEmergencyNumberTrackerMock2, TIMEOUT_MS);
+
+        assertTrue(mEmergencyNumberTrackerMock.getEmergencyCountryIso().equals("jp"));
+        assertTrue(mEmergencyNumberTrackerMock2.getEmergencyCountryIso().equals("jp"));
+    }
+
+    @Test
+    public void testUpdateEmergencyCountryIsoFromAnotherSimOrNot() throws Exception {
+        setDsdsPhones();
+        sendEmergencyNumberPrefix(mEmergencyNumberTrackerMock);
+        sendEmergencyNumberPrefix(mEmergencyNumberTrackerMock2);
+
+        // First, both slots have empty country iso, trigger a country change to "jp".
+        // We should expect both sims have "jp" country iso.
+        mEmergencyNumberTrackerMock.updateEmergencyCountryIsoAllPhones("jp");
+        waitForHandlerAction(mEmergencyNumberTrackerMock, TIMEOUT_MS);
+        waitForHandlerAction(mEmergencyNumberTrackerMock2, TIMEOUT_MS);
+        assertTrue(mEmergencyNumberTrackerMock.getEmergencyCountryIso().equals("jp"));
+        assertTrue(mEmergencyNumberTrackerMock2.getEmergencyCountryIso().equals("jp"));
+
+        // Second, both slots now have "jp" country iso, trigger a country change to "us".
+        // We should expect both sims have "us" country iso.
+        mEmergencyNumberTrackerMock.updateEmergencyCountryIsoAllPhones("us");
+        waitForHandlerAction(mEmergencyNumberTrackerMock, TIMEOUT_MS);
+        waitForHandlerAction(mEmergencyNumberTrackerMock2, TIMEOUT_MS);
+        assertTrue(mEmergencyNumberTrackerMock.getEmergencyCountryIso().equals("us"));
+        assertTrue(mEmergencyNumberTrackerMock2.getEmergencyCountryIso().equals("us"));
+
+        // Third, both slots now have "us" country iso, manually configure
+        // "mIsCountrySetByAnotherSub" flag in "mPhone2" as false, and trigger a country
+        // change to "ca". We should expect the current phone to change the country iso
+        // to "ca", and should expect the other phone *not* to change their country iso
+        // to "ca".
+        mEmergencyNumberTrackerMock2.mIsCountrySetByAnotherSub = false;
+        mEmergencyNumberTrackerMock.updateEmergencyCountryIsoAllPhones("ca");
+        waitForHandlerAction(mEmergencyNumberTrackerMock, TIMEOUT_MS);
+        waitForHandlerAction(mEmergencyNumberTrackerMock2, TIMEOUT_MS);
+        assertTrue(mEmergencyNumberTrackerMock.getEmergencyCountryIso().equals("ca"));
+        assertTrue(mEmergencyNumberTrackerMock2.getEmergencyCountryIso().equals("us"));
+    }
+
+    @Test
     public void testEmergencyNumberListPrefix() throws Exception {
         sendEmergencyNumberListFromRadio();
-        sendEmergencyNumberPrefix();
+        sendEmergencyNumberPrefix(mEmergencyNumberTrackerMock);
         List<EmergencyNumber> resultToVerify = mEmergencyNumberListTestSample;
         resultToVerify.add(new EmergencyNumber("123119", "jp", "30",
                 EmergencyNumber.EMERGENCY_SERVICE_CATEGORY_FIRE_BRIGADE,