Add telephony country code to Thread country code sources am: a00bb3fad9

Original change: https://android-review.googlesource.com/c/platform/packages/modules/Connectivity/+/2884948

Change-Id: Ib5bb374826b5f23a452843c17775fa7700822e78
Signed-off-by: Automerger Merge Worker <android-build-automerger-merge-worker@system.gserviceaccount.com>
diff --git a/thread/service/java/com/android/server/thread/ThreadNetworkCountryCode.java b/thread/service/java/com/android/server/thread/ThreadNetworkCountryCode.java
index 7845209..b7b6233 100644
--- a/thread/service/java/com/android/server/thread/ThreadNetworkCountryCode.java
+++ b/thread/service/java/com/android/server/thread/ThreadNetworkCountryCode.java
@@ -19,6 +19,10 @@
 import android.annotation.Nullable;
 import android.annotation.StringDef;
 import android.annotation.TargetApi;
+import android.content.BroadcastReceiver;
+import android.content.Context;
+import android.content.Intent;
+import android.content.IntentFilter;
 import android.location.Address;
 import android.location.Geocoder;
 import android.location.Location;
@@ -27,6 +31,10 @@
 import android.net.wifi.WifiManager;
 import android.net.wifi.WifiManager.ActiveCountryCodeChangedCallback;
 import android.os.Build;
+import android.telephony.SubscriptionInfo;
+import android.telephony.SubscriptionManager;
+import android.telephony.TelephonyManager;
+import android.util.ArrayMap;
 import android.util.Log;
 
 import com.android.connectivity.resources.R;
@@ -40,11 +48,13 @@
 import java.time.Instant;
 import java.util.List;
 import java.util.Locale;
+import java.util.Map;
 import java.util.Objects;
 
 /**
  * Provide functions for making changes to Thread Network country code. This Country Code is from
- * location or WiFi configuration. This class sends Country Code to Thread Network native layer.
+ * location, WiFi or telephony configuration. This class sends Country Code to Thread Network native
+ * layer.
  *
  * <p>This class is thread-safe.
  */
@@ -68,6 +78,8 @@
                 COUNTRY_CODE_SOURCE_DEFAULT,
                 COUNTRY_CODE_SOURCE_LOCATION,
                 COUNTRY_CODE_SOURCE_OVERRIDE,
+                COUNTRY_CODE_SOURCE_TELEPHONY,
+                COUNTRY_CODE_SOURCE_TELEPHONY_LAST,
                 COUNTRY_CODE_SOURCE_WIFI,
             })
     private @interface CountryCodeSource {}
@@ -75,20 +87,30 @@
     private static final String COUNTRY_CODE_SOURCE_DEFAULT = "Default";
     private static final String COUNTRY_CODE_SOURCE_LOCATION = "Location";
     private static final String COUNTRY_CODE_SOURCE_OVERRIDE = "Override";
+    private static final String COUNTRY_CODE_SOURCE_TELEPHONY = "Telephony";
+    private static final String COUNTRY_CODE_SOURCE_TELEPHONY_LAST = "TelephonyLast";
     private static final String COUNTRY_CODE_SOURCE_WIFI = "Wifi";
+
     private static final CountryCodeInfo DEFAULT_COUNTRY_CODE_INFO =
             new CountryCodeInfo(DEFAULT_COUNTRY_CODE, COUNTRY_CODE_SOURCE_DEFAULT);
 
     private final ConnectivityResources mResources;
+    private final Context mContext;
     private final LocationManager mLocationManager;
     @Nullable private final Geocoder mGeocoder;
     private final ThreadNetworkControllerService mThreadNetworkControllerService;
     private final WifiManager mWifiManager;
+    private final TelephonyManager mTelephonyManager;
+    private final SubscriptionManager mSubscriptionManager;
+    private final Map<Integer, TelephonyCountryCodeSlotInfo> mTelephonyCountryCodeSlotInfoMap =
+            new ArrayMap();
 
     @Nullable private CountryCodeInfo mCurrentCountryCodeInfo;
     @Nullable private CountryCodeInfo mLocationCountryCodeInfo;
     @Nullable private CountryCodeInfo mOverrideCountryCodeInfo;
     @Nullable private CountryCodeInfo mWifiCountryCodeInfo;
+    @Nullable private CountryCodeInfo mTelephonyCountryCodeInfo;
+    @Nullable private CountryCodeInfo mTelephonyLastCountryCodeInfo;
 
     /** Container class to store Thread country code information. */
     private static final class CountryCodeInfo {
@@ -131,6 +153,27 @@
         }
     }
 
+    /** Container class to store country code per SIM slot. */
+    private static final class TelephonyCountryCodeSlotInfo {
+        public int slotIndex;
+        public String countryCode;
+        public String lastKnownCountryCode;
+        public Instant timestamp;
+
+        @Override
+        public String toString() {
+            return "TelephonyCountryCodeSlotInfo{ slotIndex: "
+                    + slotIndex
+                    + ", countryCode: "
+                    + countryCode
+                    + ", lastKnownCountryCode: "
+                    + lastKnownCountryCode
+                    + ", timestamp: "
+                    + timestamp
+                    + "}";
+        }
+    }
+
     private boolean isLocationUseForCountryCodeEnabled() {
         return mResources
                 .get()
@@ -142,18 +185,39 @@
             ThreadNetworkControllerService threadNetworkControllerService,
             @Nullable Geocoder geocoder,
             ConnectivityResources resources,
-            WifiManager wifiManager) {
+            WifiManager wifiManager,
+            Context context,
+            TelephonyManager telephonyManager,
+            SubscriptionManager subscriptionManager) {
         mLocationManager = locationManager;
         mThreadNetworkControllerService = threadNetworkControllerService;
         mGeocoder = geocoder;
         mResources = resources;
         mWifiManager = wifiManager;
+        mContext = context;
+        mTelephonyManager = telephonyManager;
+        mSubscriptionManager = subscriptionManager;
+    }
+
+    public static ThreadNetworkCountryCode newInstance(
+            Context context, ThreadNetworkControllerService controllerService) {
+        return new ThreadNetworkCountryCode(
+                context.getSystemService(LocationManager.class),
+                controllerService,
+                Geocoder.isPresent() ? new Geocoder(context) : null,
+                new ConnectivityResources(context),
+                context.getSystemService(WifiManager.class),
+                context,
+                context.getSystemService(TelephonyManager.class),
+                context.getSystemService(SubscriptionManager.class));
     }
 
     /** Sets up this country code module to listen to location country code changes. */
     public synchronized void initialize() {
         registerGeocoderCountryCodeCallback();
         registerWifiCountryCodeCallback();
+        registerTelephonyCountryCodeCallback();
+        updateTelephonyCountryCodeFromSimCard();
         updateCountryCode(false /* forceUpdate */);
     }
 
@@ -229,14 +293,130 @@
         }
     }
 
+    private synchronized void registerTelephonyCountryCodeCallback() {
+        if (Build.VERSION.SDK_INT < Build.VERSION_CODES.TIRAMISU) {
+            Log.wtf(
+                    TAG,
+                    "Unexpected call to register the telephony country code changed callback, "
+                            + "Thread code never runs under T or lower.");
+            return;
+        }
+
+        BroadcastReceiver broadcastReceiver =
+                new BroadcastReceiver() {
+                    @Override
+                    public void onReceive(Context context, Intent intent) {
+                        int slotIndex =
+                                intent.getIntExtra(
+                                        SubscriptionManager.EXTRA_SLOT_INDEX,
+                                        SubscriptionManager.INVALID_SIM_SLOT_INDEX);
+                        String lastKnownCountryCode = null;
+                        String countryCode =
+                                intent.getStringExtra(TelephonyManager.EXTRA_NETWORK_COUNTRY);
+
+                        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.UPSIDE_DOWN_CAKE) {
+                            lastKnownCountryCode =
+                                    intent.getStringExtra(
+                                            TelephonyManager.EXTRA_LAST_KNOWN_NETWORK_COUNTRY);
+                        }
+
+                        setTelephonyCountryCodeAndLastKnownCountryCode(
+                                slotIndex, countryCode, lastKnownCountryCode);
+                    }
+                };
+
+        mContext.registerReceiver(
+                broadcastReceiver,
+                new IntentFilter(TelephonyManager.ACTION_NETWORK_COUNTRY_CHANGED),
+                Context.RECEIVER_EXPORTED);
+    }
+
+    private synchronized void updateTelephonyCountryCodeFromSimCard() {
+        List<SubscriptionInfo> subscriptionInfoList =
+                mSubscriptionManager.getActiveSubscriptionInfoList();
+
+        if (subscriptionInfoList == null) {
+            Log.d(TAG, "No SIM card is found");
+            return;
+        }
+
+        for (SubscriptionInfo subscriptionInfo : subscriptionInfoList) {
+            String countryCode;
+            int slotIndex;
+
+            slotIndex = subscriptionInfo.getSimSlotIndex();
+            try {
+                countryCode = mTelephonyManager.getNetworkCountryIso(slotIndex);
+            } catch (IllegalArgumentException e) {
+                Log.e(TAG, "Failed to get country code for slot index:" + slotIndex, e);
+                continue;
+            }
+
+            Log.d(TAG, "Telephony slot " + slotIndex + " country code is " + countryCode);
+            setTelephonyCountryCodeAndLastKnownCountryCode(
+                    slotIndex, countryCode, null /* lastKnownCountryCode */);
+        }
+    }
+
+    private synchronized void setTelephonyCountryCodeAndLastKnownCountryCode(
+            int slotIndex, String countryCode, String lastKnownCountryCode) {
+        Log.d(
+                TAG,
+                "Set telephony country code to: "
+                        + countryCode
+                        + ", last country code to: "
+                        + lastKnownCountryCode
+                        + " for slotIndex: "
+                        + slotIndex);
+
+        TelephonyCountryCodeSlotInfo telephonyCountryCodeInfoSlot =
+                mTelephonyCountryCodeSlotInfoMap.computeIfAbsent(
+                        slotIndex, k -> new TelephonyCountryCodeSlotInfo());
+        telephonyCountryCodeInfoSlot.slotIndex = slotIndex;
+        telephonyCountryCodeInfoSlot.timestamp = Instant.now();
+        telephonyCountryCodeInfoSlot.countryCode = countryCode;
+        telephonyCountryCodeInfoSlot.lastKnownCountryCode = lastKnownCountryCode;
+
+        mTelephonyCountryCodeInfo = null;
+        mTelephonyLastCountryCodeInfo = null;
+
+        for (TelephonyCountryCodeSlotInfo slotInfo : mTelephonyCountryCodeSlotInfoMap.values()) {
+            if ((mTelephonyCountryCodeInfo == null) && isValidCountryCode(slotInfo.countryCode)) {
+                mTelephonyCountryCodeInfo =
+                        new CountryCodeInfo(
+                                slotInfo.countryCode,
+                                COUNTRY_CODE_SOURCE_TELEPHONY,
+                                slotInfo.timestamp);
+            }
+
+            if ((mTelephonyLastCountryCodeInfo == null)
+                    && isValidCountryCode(slotInfo.lastKnownCountryCode)) {
+                mTelephonyLastCountryCodeInfo =
+                        new CountryCodeInfo(
+                                slotInfo.lastKnownCountryCode,
+                                COUNTRY_CODE_SOURCE_TELEPHONY_LAST,
+                                slotInfo.timestamp);
+            }
+        }
+
+        updateCountryCode(false /* forceUpdate */);
+    }
+
     /**
      * Priority order of country code sources (we stop at the first known country code source):
      *
      * <ul>
      *   <li>1. Override country code - Country code forced via shell command (local/automated
      *       testing)
-     *   <li>2. Wifi country code - Current country code retrieved via wifi (via 80211.ad).
-     *   <li>3. Location Country code - Country code retrieved from LocationManager passive location
+     *   <li>2. Telephony country code - Current country code retrieved via cellular. If there are
+     *       multiple SIM's, the country code chosen is non-deterministic if they return different
+     *       codes. The first valid country code with the lowest slot number will be used.
+     *   <li>3. Wifi country code - Current country code retrieved via wifi (via 80211.ad).
+     *   <li>4. Last known telephony country code - Last known country code retrieved via cellular.
+     *       If there are multiple SIM's, the country code chosen is non-deterministic if they
+     *       return different codes. The first valid last known country code with the lowest slot
+     *       number will be used.
+     *   <li>5. Location country code - Country code retrieved from LocationManager passive location
      *       provider.
      * </ul>
      *
@@ -247,10 +427,18 @@
             return mOverrideCountryCodeInfo;
         }
 
+        if (mTelephonyCountryCodeInfo != null) {
+            return mTelephonyCountryCodeInfo;
+        }
+
         if (mWifiCountryCodeInfo != null) {
             return mWifiCountryCodeInfo;
         }
 
+        if (mTelephonyLastCountryCodeInfo != null) {
+            return mTelephonyLastCountryCodeInfo;
+        }
+
         if (mLocationCountryCodeInfo != null) {
             return mLocationCountryCodeInfo;
         }
@@ -344,7 +532,10 @@
     public synchronized void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
         pw.println("---- Dump of ThreadNetworkCountryCode begin ----");
         pw.println("mOverrideCountryCodeInfo: " + mOverrideCountryCodeInfo);
+        pw.println("mTelephonyCountryCodeSlotInfoMap: " + mTelephonyCountryCodeSlotInfoMap);
+        pw.println("mTelephonyCountryCodeInfo: " + mTelephonyCountryCodeInfo);
         pw.println("mWifiCountryCodeInfo: " + mWifiCountryCodeInfo);
+        pw.println("mTelephonyLastCountryCodeInfo: " + mTelephonyLastCountryCodeInfo);
         pw.println("mLocationCountryCodeInfo: " + mLocationCountryCodeInfo);
         pw.println("mCurrentCountryCodeInfo: " + mCurrentCountryCodeInfo);
         pw.println("---- Dump of ThreadNetworkCountryCode end ------");
diff --git a/thread/service/java/com/android/server/thread/ThreadNetworkService.java b/thread/service/java/com/android/server/thread/ThreadNetworkService.java
index 80b8842..a3cf278 100644
--- a/thread/service/java/com/android/server/thread/ThreadNetworkService.java
+++ b/thread/service/java/com/android/server/thread/ThreadNetworkService.java
@@ -21,16 +21,12 @@
 import android.annotation.NonNull;
 import android.annotation.Nullable;
 import android.content.Context;
-import android.location.Geocoder;
-import android.location.LocationManager;
 import android.net.thread.IThreadNetworkController;
 import android.net.thread.IThreadNetworkManager;
-import android.net.wifi.WifiManager;
 import android.os.Binder;
 import android.os.ParcelFileDescriptor;
 
 import com.android.server.SystemService;
-import com.android.server.connectivity.ConnectivityResources;
 
 import java.io.FileDescriptor;
 import java.io.PrintWriter;
@@ -60,13 +56,7 @@
         if (phase == SystemService.PHASE_BOOT_COMPLETED) {
             mControllerService = ThreadNetworkControllerService.newInstance(mContext);
             mControllerService.initialize();
-            mCountryCode =
-                    new ThreadNetworkCountryCode(
-                            mContext.getSystemService(LocationManager.class),
-                            mControllerService,
-                            Geocoder.isPresent() ? new Geocoder(mContext) : null,
-                            new ConnectivityResources(mContext),
-                            mContext.getSystemService(WifiManager.class));
+            mCountryCode = ThreadNetworkCountryCode.newInstance(mContext, mControllerService);
             mCountryCode.initialize();
 
             mShellCommand = new ThreadNetworkShellCommand(mCountryCode);
diff --git a/thread/tests/unit/src/com/android/server/thread/ThreadNetworkCountryCodeTest.java b/thread/tests/unit/src/com/android/server/thread/ThreadNetworkCountryCodeTest.java
index d7082fe..17cdd01 100644
--- a/thread/tests/unit/src/com/android/server/thread/ThreadNetworkCountryCodeTest.java
+++ b/thread/tests/unit/src/com/android/server/thread/ThreadNetworkCountryCodeTest.java
@@ -38,6 +38,9 @@
 import static org.mockito.Mockito.verifyNoMoreInteractions;
 import static org.mockito.Mockito.when;
 
+import android.content.BroadcastReceiver;
+import android.content.Context;
+import android.content.Intent;
 import android.content.pm.PackageManager;
 import android.content.res.Resources;
 import android.location.Address;
@@ -48,6 +51,9 @@
 import android.net.thread.IOperationReceiver;
 import android.net.wifi.WifiManager;
 import android.net.wifi.WifiManager.ActiveCountryCodeChangedCallback;
+import android.telephony.SubscriptionInfo;
+import android.telephony.SubscriptionManager;
+import android.telephony.TelephonyManager;
 
 import androidx.test.filters.SmallTest;
 import androidx.test.runner.AndroidJUnit4;
@@ -64,6 +70,7 @@
 import org.mockito.MockitoAnnotations;
 import org.mockito.stubbing.Answer;
 
+import java.util.Iterator;
 import java.util.List;
 import java.util.Locale;
 
@@ -73,7 +80,10 @@
 public class ThreadNetworkCountryCodeTest {
     private static final String TEST_COUNTRY_CODE_US = "US";
     private static final String TEST_COUNTRY_CODE_CN = "CN";
+    private static final int TEST_SIM_SLOT_INDEX_0 = 0;
+    private static final int TEST_SIM_SLOT_INDEX_1 = 1;
 
+    @Mock Context mContext;
     @Mock LocationManager mLocationManager;
     @Mock Geocoder mGeocoder;
     @Mock ThreadNetworkControllerService mThreadNetworkControllerService;
@@ -82,6 +92,11 @@
     @Mock Resources mResources;
     @Mock ConnectivityResources mConnectivityResources;
     @Mock WifiManager mWifiManager;
+    @Mock SubscriptionManager mSubscriptionManager;
+    @Mock TelephonyManager mTelephonyManager;
+    @Mock List<SubscriptionInfo> mSubscriptionInfoList;
+    @Mock SubscriptionInfo mSubscriptionInfo0;
+    @Mock SubscriptionInfo mSubscriptionInfo1;
 
     private ThreadNetworkCountryCode mThreadNetworkCountryCode;
     private boolean mErrorSetCountryCode;
@@ -90,6 +105,7 @@
     @Captor private ArgumentCaptor<Geocoder.GeocodeListener> mGeocodeListenerCaptor;
     @Captor private ArgumentCaptor<IOperationReceiver> mOperationReceiverCaptor;
     @Captor private ArgumentCaptor<ActiveCountryCodeChangedCallback> mWifiCountryCodeReceiverCaptor;
+    @Captor private ArgumentCaptor<BroadcastReceiver> mTelephonyCountryCodeReceiverCaptor;
 
     @Before
     public void setUp() throws Exception {
@@ -98,6 +114,16 @@
         when(mConnectivityResources.get()).thenReturn(mResources);
         when(mResources.getBoolean(anyInt())).thenReturn(true);
 
+        when(mSubscriptionManager.getActiveSubscriptionInfoList())
+                .thenReturn(mSubscriptionInfoList);
+        Iterator<SubscriptionInfo> iteratorMock = mock(Iterator.class);
+        when(mSubscriptionInfoList.size()).thenReturn(2);
+        when(mSubscriptionInfoList.iterator()).thenReturn(iteratorMock);
+        when(iteratorMock.hasNext()).thenReturn(true).thenReturn(true).thenReturn(false);
+        when(iteratorMock.next()).thenReturn(mSubscriptionInfo0).thenReturn(mSubscriptionInfo1);
+        when(mSubscriptionInfo0.getSimSlotIndex()).thenReturn(TEST_SIM_SLOT_INDEX_0);
+        when(mSubscriptionInfo1.getSimSlotIndex()).thenReturn(TEST_SIM_SLOT_INDEX_1);
+
         when(mLocation.getLatitude()).thenReturn(0.0);
         when(mLocation.getLongitude()).thenReturn(0.0);
 
@@ -124,7 +150,10 @@
                         mThreadNetworkControllerService,
                         mGeocoder,
                         mConnectivityResources,
-                        mWifiManager);
+                        mWifiManager,
+                        mContext,
+                        mTelephonyManager,
+                        mSubscriptionManager);
     }
 
     private static Address newAddress(String countryCode) {
@@ -177,6 +206,7 @@
         verify(mGeocoder)
                 .getFromLocation(
                         anyDouble(), anyDouble(), anyInt(), mGeocodeListenerCaptor.capture());
+
         Address mockAddress = mock(Address.class);
         when(mockAddress.getCountryCode()).thenReturn(TEST_COUNTRY_CODE_US);
         List<Address> addresses = List.of(mockAddress);
@@ -217,6 +247,115 @@
     }
 
     @Test
+    public void telephonyCountryCode_bothTelephonyAndLocationAvailable_telephonyCodeIsUsed() {
+        mThreadNetworkCountryCode.initialize();
+        verify(mLocationManager)
+                .requestLocationUpdates(
+                        anyString(), anyLong(), anyFloat(), mLocationListenerCaptor.capture());
+        mLocationListenerCaptor.getValue().onLocationChanged(mLocation);
+        verify(mGeocoder)
+                .getFromLocation(
+                        anyDouble(), anyDouble(), anyInt(), mGeocodeListenerCaptor.capture());
+        mGeocodeListenerCaptor.getValue().onGeocode(List.of(newAddress(TEST_COUNTRY_CODE_US)));
+
+        verify(mContext)
+                .registerReceiver(
+                        mTelephonyCountryCodeReceiverCaptor.capture(),
+                        any(),
+                        eq(Context.RECEIVER_EXPORTED));
+        Intent intent =
+                new Intent(TelephonyManager.ACTION_NETWORK_COUNTRY_CHANGED)
+                        .putExtra(TelephonyManager.EXTRA_NETWORK_COUNTRY, TEST_COUNTRY_CODE_CN)
+                        .putExtra(SubscriptionManager.EXTRA_SLOT_INDEX, TEST_SIM_SLOT_INDEX_0);
+        mTelephonyCountryCodeReceiverCaptor.getValue().onReceive(mContext, intent);
+
+        assertThat(mThreadNetworkCountryCode.getCountryCode()).isEqualTo(TEST_COUNTRY_CODE_CN);
+    }
+
+    @Test
+    public void telephonyCountryCode_locationIsAvailable_lastKnownTelephonyCodeIsUsed() {
+        mThreadNetworkCountryCode.initialize();
+        verify(mLocationManager)
+                .requestLocationUpdates(
+                        anyString(), anyLong(), anyFloat(), mLocationListenerCaptor.capture());
+        mLocationListenerCaptor.getValue().onLocationChanged(mLocation);
+        verify(mGeocoder)
+                .getFromLocation(
+                        anyDouble(), anyDouble(), anyInt(), mGeocodeListenerCaptor.capture());
+        mGeocodeListenerCaptor.getValue().onGeocode(List.of(newAddress(TEST_COUNTRY_CODE_US)));
+
+        verify(mContext)
+                .registerReceiver(
+                        mTelephonyCountryCodeReceiverCaptor.capture(),
+                        any(),
+                        eq(Context.RECEIVER_EXPORTED));
+        Intent intent =
+                new Intent(TelephonyManager.ACTION_NETWORK_COUNTRY_CHANGED)
+                        .putExtra(TelephonyManager.EXTRA_NETWORK_COUNTRY, "")
+                        .putExtra(
+                                TelephonyManager.EXTRA_LAST_KNOWN_NETWORK_COUNTRY,
+                                TEST_COUNTRY_CODE_US)
+                        .putExtra(SubscriptionManager.EXTRA_SLOT_INDEX, TEST_SIM_SLOT_INDEX_0);
+        mTelephonyCountryCodeReceiverCaptor.getValue().onReceive(mContext, intent);
+
+        assertThat(mThreadNetworkCountryCode.getCountryCode()).isEqualTo(TEST_COUNTRY_CODE_US);
+    }
+
+    @Test
+    public void telephonyCountryCode_lastKnownCountryCodeAvailable_telephonyCodeIsUsed() {
+        mThreadNetworkCountryCode.initialize();
+        verify(mContext)
+                .registerReceiver(
+                        mTelephonyCountryCodeReceiverCaptor.capture(),
+                        any(),
+                        eq(Context.RECEIVER_EXPORTED));
+        Intent intent0 =
+                new Intent(TelephonyManager.ACTION_NETWORK_COUNTRY_CHANGED)
+                        .putExtra(TelephonyManager.EXTRA_NETWORK_COUNTRY, "")
+                        .putExtra(
+                                TelephonyManager.EXTRA_LAST_KNOWN_NETWORK_COUNTRY,
+                                TEST_COUNTRY_CODE_US)
+                        .putExtra(SubscriptionManager.EXTRA_SLOT_INDEX, TEST_SIM_SLOT_INDEX_0);
+        mTelephonyCountryCodeReceiverCaptor.getValue().onReceive(mContext, intent0);
+
+        verify(mContext)
+                .registerReceiver(
+                        mTelephonyCountryCodeReceiverCaptor.capture(),
+                        any(),
+                        eq(Context.RECEIVER_EXPORTED));
+        Intent intent1 =
+                new Intent(TelephonyManager.ACTION_NETWORK_COUNTRY_CHANGED)
+                        .putExtra(TelephonyManager.EXTRA_NETWORK_COUNTRY, TEST_COUNTRY_CODE_CN)
+                        .putExtra(SubscriptionManager.EXTRA_SLOT_INDEX, TEST_SIM_SLOT_INDEX_1);
+        mTelephonyCountryCodeReceiverCaptor.getValue().onReceive(mContext, intent1);
+
+        assertThat(mThreadNetworkCountryCode.getCountryCode()).isEqualTo(TEST_COUNTRY_CODE_CN);
+    }
+
+    @Test
+    public void telephonyCountryCode_multipleSims_firstSimIsUsed() {
+        mThreadNetworkCountryCode.initialize();
+        verify(mContext)
+                .registerReceiver(
+                        mTelephonyCountryCodeReceiverCaptor.capture(),
+                        any(),
+                        eq(Context.RECEIVER_EXPORTED));
+        Intent intent1 =
+                new Intent(TelephonyManager.ACTION_NETWORK_COUNTRY_CHANGED)
+                        .putExtra(TelephonyManager.EXTRA_NETWORK_COUNTRY, TEST_COUNTRY_CODE_CN)
+                        .putExtra(SubscriptionManager.EXTRA_SLOT_INDEX, TEST_SIM_SLOT_INDEX_1);
+        mTelephonyCountryCodeReceiverCaptor.getValue().onReceive(mContext, intent1);
+
+        Intent intent0 =
+                new Intent(TelephonyManager.ACTION_NETWORK_COUNTRY_CHANGED)
+                        .putExtra(TelephonyManager.EXTRA_NETWORK_COUNTRY, TEST_COUNTRY_CODE_CN)
+                        .putExtra(SubscriptionManager.EXTRA_SLOT_INDEX, TEST_SIM_SLOT_INDEX_0);
+        mTelephonyCountryCodeReceiverCaptor.getValue().onReceive(mContext, intent0);
+
+        assertThat(mThreadNetworkCountryCode.getCountryCode()).isEqualTo(TEST_COUNTRY_CODE_CN);
+    }
+
+    @Test
     public void updateCountryCode_noForceUpdateDefaultCountryCode_noCountryCodeIsUpdated() {
         mThreadNetworkCountryCode.initialize();
         clearInvocations(mThreadNetworkControllerService);