Merge "Revert "Unbind ConnectionService if connection creation timed out."" into main
diff --git a/src/com/android/server/telecom/CallLogManager.java b/src/com/android/server/telecom/CallLogManager.java
index fc4e05d..6a9977d 100644
--- a/src/com/android/server/telecom/CallLogManager.java
+++ b/src/com/android/server/telecom/CallLogManager.java
@@ -31,6 +31,8 @@
 import android.location.Location;
 import android.net.Uri;
 import android.os.AsyncTask;
+import android.os.Handler;
+import android.os.HandlerExecutor;
 import android.os.Looper;
 import android.os.UserHandle;
 import android.os.PersistableBundle;
@@ -57,6 +59,8 @@
 import java.util.Locale;
 import java.util.Objects;
 import java.util.UUID;
+import java.util.concurrent.Executor;
+import java.util.concurrent.Executors;
 import java.util.stream.Stream;
 
 /**
@@ -116,8 +120,10 @@
     private static final String CALL_TYPE = "callType";
     private static final String CALL_DURATION = "duration";
 
-    private Object mLock;
+    private final Object mLock = new Object();
+    private Country mCurrentCountry;
     private String mCurrentCountryIso;
+    private HandlerExecutor mCountryCodeExecutor;
 
     private final FeatureFlags mFeatureFlags;
 
@@ -130,7 +136,7 @@
         mPhoneAccountRegistrar = phoneAccountRegistrar;
         mMissedCallNotifier = missedCallNotifier;
         mAnomalyReporterAdapter = anomalyReporterAdapter;
-        mLock = new Object();
+        mCountryCodeExecutor = new HandlerExecutor(new Handler(Looper.getMainLooper()));
         mFeatureFlags = featureFlags;
     }
 
@@ -620,7 +626,7 @@
             return Locale.getDefault().getCountry();
         }
 
-        return country.getCountryIso();
+        return country.getCountryCode();
     }
 
     /**
@@ -631,31 +637,35 @@
     public String getCountryIso() {
         synchronized (mLock) {
             if (mCurrentCountryIso == null) {
-                Log.i(TAG, "Country cache is null. Detecting Country and Setting Cache...");
+                // Moving this into the constructor will pose issues if the service is not yet set
+                // up, causing a RemoteException to be thrown. Note that the callback is only
+                // registered if the country iso cache is null (so in an ideal setting, this should
+                // only require a one-time configuration).
                 final CountryDetector countryDetector =
                         (CountryDetector) mContext.getSystemService(Context.COUNTRY_DETECTOR);
-                Country country = null;
                 if (countryDetector != null) {
-                    country = countryDetector.detectCountry();
-
-                    countryDetector.addCountryListener((newCountry) -> {
-                        Log.startSession("CLM.oCD");
-                        try {
-                            synchronized (mLock) {
-                                Log.i(TAG, "Country ISO changed. Retrieving new ISO...");
-                                mCurrentCountryIso = getCountryIsoFromCountry(newCountry);
-                            }
-                        } finally {
-                            Log.endSession();
-                        }
-                    }, Looper.getMainLooper());
+                    countryDetector.registerCountryDetectorCallback(
+                            mCountryCodeExecutor, this::countryCodeConsumer);
                 }
-                mCurrentCountryIso = getCountryIsoFromCountry(country);
+                mCurrentCountryIso = getCountryIsoFromCountry(mCurrentCountry);
             }
             return mCurrentCountryIso;
         }
     }
 
+    /** Consumer to receive the country code if it changes. */
+    private void countryCodeConsumer(Country newCountry) {
+        Log.startSession("CLM.cCC");
+        try {
+            Log.i(TAG, "Country ISO changed. Retrieving new ISO...");
+            synchronized (mLock) {
+                mCurrentCountry = newCountry;
+                mCurrentCountryIso = getCountryIsoFromCountry(newCountry);
+            }
+        } finally {
+            Log.endSession();
+        }
+    }
 
     /**
      * Returns a pair containing the number of rows in the call log, as well as the maximum call log
diff --git a/tests/src/com/android/server/telecom/tests/CallLogManagerTest.java b/tests/src/com/android/server/telecom/tests/CallLogManagerTest.java
index 8a32fbd..fa35f25 100644
--- a/tests/src/com/android/server/telecom/tests/CallLogManagerTest.java
+++ b/tests/src/com/android/server/telecom/tests/CallLogManagerTest.java
@@ -16,6 +16,8 @@
 
 package com.android.server.telecom.tests;
 
+import static com.android.server.telecom.tests.TelecomSystemTest.TEST_TIMEOUT;
+
 import static org.junit.Assert.assertEquals;
 import static org.junit.Assert.assertFalse;
 import static org.junit.Assert.assertNotNull;
@@ -45,6 +47,7 @@
 import android.location.Location;
 import android.net.Uri;
 import android.os.Bundle;
+import android.os.Handler;
 import android.os.Looper;
 import android.os.PersistableBundle;
 import android.os.SystemClock;
@@ -88,6 +91,9 @@
 import org.mockito.stubbing.Answer;
 
 import java.util.Arrays;
+import java.util.Locale;
+import java.util.concurrent.Executor;
+import java.util.function.Consumer;
 
 @RunWith(JUnit4.class)
 public class CallLogManagerTest extends TelecomTestCase {
@@ -863,35 +869,33 @@
 
     @SmallTest
     @Test
-    public void testCountryIso_setCache() {
-        Country testCountry = new Country(TEST_ISO, Country.COUNTRY_SOURCE_LOCALE);
-        CountryDetector mockDetector = (CountryDetector) mContext.getSystemService(
-                Context.COUNTRY_DETECTOR);
-        when(mockDetector.detectCountry()).thenReturn(testCountry);
-
-        String resultIso = mCallLogManager.getCountryIso();
-
-        verifyCountryIso(mockDetector, resultIso);
-    }
-
-    @SmallTest
-    @Test
     public void testCountryIso_newCountryDetected() {
         Country testCountry = new Country(TEST_ISO, Country.COUNTRY_SOURCE_LOCALE);
         Country testCountry2 = new Country(TEST_ISO_2, Country.COUNTRY_SOURCE_LOCALE);
         CountryDetector mockDetector = (CountryDetector) mContext.getSystemService(
                 Context.COUNTRY_DETECTOR);
-        when(mockDetector.detectCountry()).thenReturn(testCountry);
-        // Put TEST_ISO in the Cache
+        Handler handler = new Handler(Looper.getMainLooper());
+
+        String initialIso = mCallLogManager.getCountryIso();
+        assertEquals(Locale.getDefault().getCountry(), initialIso);
+
+        ArgumentCaptor<Consumer<Country>> capture = ArgumentCaptor.forClass(Consumer.class);
+        verify(mockDetector).registerCountryDetectorCallback(
+                any(Executor.class), capture.capture());
+        Consumer<Country> countryConsumer = capture.getValue();
+
+        countryConsumer.accept(testCountry);
+        waitForHandlerAction(handler, TEST_TIMEOUT);
         String resultIso = mCallLogManager.getCountryIso();
-        ArgumentCaptor<CountryListener> captor = verifyCountryIso(mockDetector, resultIso);
+        assertEquals(TEST_ISO, resultIso);
 
-        // Change ISO to TEST_ISO_2
-        CountryListener listener = captor.getValue();
-        listener.onCountryDetected(testCountry2);
-
-        String resultIso2 = mCallLogManager.getCountryIso();
-        assertEquals(TEST_ISO_2, resultIso2);
+        // If default locale is equal to TEST_ISO, test another ISO to assure working functionality.
+        if (initialIso.equals(TEST_ISO)) {
+            countryConsumer.accept(testCountry2);
+            waitForHandlerAction(handler, TEST_TIMEOUT);
+            resultIso = mCallLogManager.getCountryIso();
+            assertEquals(TEST_ISO_2, resultIso);
+        }
     }
 
     @SmallTest