Improve SatelliteAccessControllerTest (unit test) isolation

Also, improve incomplete environment handling in SatelliteAccessController

Bug: 365800992
Test: com.android.phone.satellite.accesscontrol.SatelliteAccessControllerTest
Test: com.android.phone.satellite.entitlement.SatelliteEntitlementControllerTest
Flag: EXEMPT bugfix
Change-Id: Ibe257752ef3c0a174e9455042082d0369ac864fb
diff --git a/src/com/android/phone/satellite/accesscontrol/SatelliteAccessController.java b/src/com/android/phone/satellite/accesscontrol/SatelliteAccessController.java
index 5f60291..c48e016 100644
--- a/src/com/android/phone/satellite/accesscontrol/SatelliteAccessController.java
+++ b/src/com/android/phone/satellite/accesscontrol/SatelliteAccessController.java
@@ -756,15 +756,22 @@
         Path targetDir = ctsFile.toPath();
         Path targetSatS2FilePath = targetDir.resolve(sourceFileName);
         try {
-            InputStream inputStream = phoneGlobals.getAssets().open(sourceFileName);
+            var assetManager = phoneGlobals.getAssets();
+            if (assetManager == null) {
+                loge("copyTestSatS2FileToPhoneDirectory: no assets");
+                return null;
+            }
+            InputStream inputStream = assetManager.open(sourceFileName);
             if (inputStream == null) {
                 loge("copyTestSatS2FileToPhoneDirectory: Resource=" + sourceFileName
                         + " not found");
+                return null;
             } else {
                 Files.copy(inputStream, targetSatS2FilePath, StandardCopyOption.REPLACE_EXISTING);
             }
         } catch (IOException ex) {
             loge("copyTestSatS2FileToPhoneDirectory: ex=" + ex);
+            return null;
         }
         return targetSatS2FilePath;
     }
diff --git a/tests/src/com/android/TelephonyTestBase.java b/tests/src/com/android/TelephonyTestBase.java
index 3e74eb7..94e91d3 100644
--- a/tests/src/com/android/TelephonyTestBase.java
+++ b/tests/src/com/android/TelephonyTestBase.java
@@ -35,6 +35,8 @@
 import com.android.internal.telephony.PhoneFactory;
 import com.android.internal.telephony.data.DataConfigManager;
 import com.android.internal.telephony.data.DataNetworkController;
+import com.android.internal.telephony.metrics.MetricsCollector;
+import com.android.internal.telephony.metrics.PersistAtomsStorage;
 import com.android.phone.PhoneGlobals;
 import com.android.phone.PhoneInterfaceManager;
 
@@ -65,6 +67,7 @@
     @Mock protected PhoneGlobals mPhoneGlobals;
     @Mock protected GsmCdmaPhone mPhone;
     @Mock protected DataNetworkController mDataNetworkController;
+    @Mock private MetricsCollector mMetricsCollector;
 
     private final HashMap<InstanceKey, Object> mOldInstances = new HashMap<>();
     private final LinkedList<InstanceKey> mInstanceKeys = new LinkedList<>();
@@ -92,6 +95,9 @@
         replaceInstance(PhoneFactory.class, "sPhone", null, mPhone);
         replaceInstance(PhoneFactory.class, "sPhones", null, new Phone[] {mPhone});
         replaceInstance(PhoneGlobals.class, "sMe", null, mPhoneGlobals);
+        replaceInstance(PhoneFactory.class, "sMetricsCollector", null, mMetricsCollector);
+
+        doReturn(Mockito.mock(PersistAtomsStorage.class)).when(mMetricsCollector).getAtomsStorage();
 
         doReturn(mDataNetworkController).when(mPhone).getDataNetworkController();
         doReturn(Collections.emptyList()).when(mDataNetworkController)
diff --git a/tests/src/com/android/TestContext.java b/tests/src/com/android/TestContext.java
index a684ef5..fe88ae6 100644
--- a/tests/src/com/android/TestContext.java
+++ b/tests/src/com/android/TestContext.java
@@ -21,6 +21,8 @@
 import static org.mockito.Mockito.doAnswer;
 import static org.mockito.Mockito.when;
 
+import android.annotation.NonNull;
+import android.annotation.Nullable;
 import android.content.AttributionSource;
 import android.content.BroadcastReceiver;
 import android.content.ContentResolver;
@@ -28,6 +30,8 @@
 import android.content.Intent;
 import android.content.IntentFilter;
 import android.content.pm.PackageManager;
+import android.content.res.AssetManager;
+import android.content.res.Resources;
 import android.os.Binder;
 import android.os.Handler;
 import android.os.Looper;
@@ -44,7 +48,10 @@
 import android.util.Log;
 import android.util.SparseArray;
 
+import androidx.test.InstrumentationRegistry;
+
 import org.mockito.Mock;
+import org.mockito.Mockito;
 import org.mockito.MockitoAnnotations;
 import org.mockito.stubbing.Answer;
 
@@ -87,6 +94,11 @@
     }
 
     @Override
+    public AssetManager getAssets() {
+        return Mockito.mock(AssetManager.class);
+    }
+
+    @Override
     public Executor getMainExecutor() {
         // Just run on current thread
         return Runnable::run;
@@ -98,6 +110,11 @@
     }
 
     @Override
+    public @NonNull Context createAttributionContext(@Nullable String attributionTag) {
+        return this;
+    }
+
+    @Override
     public String getPackageName() {
         return "com.android.phone.tests";
     }
@@ -226,6 +243,11 @@
         return new Handler(Looper.getMainLooper());
     }
 
+    @Override
+    public Resources.Theme getTheme() {
+        return InstrumentationRegistry.getTargetContext().getTheme();
+    }
+
     /**
      * @return CarrierConfig PersistableBundle for the subscription specified.
      */
diff --git a/tests/src/com/android/phone/satellite/accesscontrol/SatelliteAccessControllerTest.java b/tests/src/com/android/phone/satellite/accesscontrol/SatelliteAccessControllerTest.java
index 5c18cc5..b388954 100644
--- a/tests/src/com/android/phone/satellite/accesscontrol/SatelliteAccessControllerTest.java
+++ b/tests/src/com/android/phone/satellite/accesscontrol/SatelliteAccessControllerTest.java
@@ -49,6 +49,7 @@
 import static org.junit.Assert.assertSame;
 import static org.junit.Assert.assertTrue;
 import static org.junit.Assert.fail;
+import static org.junit.Assume.assumeTrue;
 import static org.mockito.ArgumentMatchers.any;
 import static org.mockito.ArgumentMatchers.anyBoolean;
 import static org.mockito.ArgumentMatchers.anyInt;
@@ -87,7 +88,6 @@
 import android.os.CancellationSignal;
 import android.os.DropBoxManager;
 import android.os.Handler;
-import android.os.HandlerThread;
 import android.os.IBinder;
 import android.os.Looper;
 import android.os.Message;
@@ -101,12 +101,14 @@
 import android.telephony.satellite.SatelliteAccessConfiguration;
 import android.telephony.satellite.SatelliteInfo;
 import android.telephony.satellite.SatelliteManager;
+import android.testing.AndroidTestingRunner;
 import android.testing.TestableLooper;
 import android.util.Log;
 import android.util.Pair;
 
-import androidx.test.ext.junit.runners.AndroidJUnit4;
+import androidx.test.InstrumentationRegistry;
 
+import com.android.TelephonyTestBase;
 import com.android.internal.telephony.Phone;
 import com.android.internal.telephony.PhoneFactory;
 import com.android.internal.telephony.TelephonyCountryDetector;
@@ -115,6 +117,7 @@
 import com.android.internal.telephony.satellite.SatelliteConfigParser;
 import com.android.internal.telephony.satellite.SatelliteController;
 import com.android.internal.telephony.satellite.SatelliteModemInterface;
+import com.android.internal.telephony.satellite.metrics.ControllerMetricsStats;
 
 import org.junit.After;
 import org.junit.Before;
@@ -123,10 +126,8 @@
 import org.mockito.ArgumentCaptor;
 import org.mockito.Captor;
 import org.mockito.Mock;
-import org.mockito.MockitoAnnotations;
 
 import java.io.File;
-import java.lang.reflect.Field;
 import java.util.ArrayList;
 import java.util.Arrays;
 import java.util.HashMap;
@@ -141,8 +142,9 @@
 import java.util.function.Consumer;
 
 /** Unit test for {@link SatelliteAccessController} */
-@RunWith(AndroidJUnit4.class)
-public class SatelliteAccessControllerTest {
+@RunWith(AndroidTestingRunner.class)
+@TestableLooper.RunWithLooper
+public class SatelliteAccessControllerTest extends TelephonyTestBase {
     private static final String TAG = "SatelliteAccessControllerTest";
     private static final String[] TEST_SATELLITE_COUNTRY_CODES = {"US", "CA", "UK"};
     private static final String[] TEST_SATELLITE_COUNTRY_CODES_EMPTY = {""};
@@ -176,8 +178,7 @@
     private SatelliteModemInterface mMockSatelliteModemInterface;
     @Mock
     private DropBoxManager mMockDropBoxManager;
-    @Mock
-    private Context mMockContext;
+    private Context mMockContext;  // alias of mContext
     @Mock
     private Phone mMockPhone;
     @Mock
@@ -224,7 +225,6 @@
     private ConcurrentHashMap<IBinder, ISatelliteCommunicationAllowedStateCallback>
             mSatelliteCommunicationAllowedStateCallbackMap;
 
-    private Looper mLooper;
     private TestableLooper mTestableLooper;
     private Phone[] mPhones;
     private TestSatelliteAccessController mSatelliteAccessControllerUT;
@@ -289,17 +289,10 @@
 
     @Before
     public void setUp() throws Exception {
-        logd("setUp");
-        MockitoAnnotations.initMocks(this);
+        super.setUp();
 
-        if (Looper.myLooper() == null) {
-            Looper.prepare();
-        }
-
-        HandlerThread handlerThread = new HandlerThread("SatelliteAccessControllerTest");
-        handlerThread.start();
-        mLooper = handlerThread.getLooper();
-        mTestableLooper = new TestableLooper(mLooper);
+        mMockContext = mContext;
+        mTestableLooper = TestableLooper.get(this);
         when(mMockContext.getSystemServiceName(LocationManager.class)).thenReturn(
                 Context.LOCATION_SERVICE);
         when(mMockContext.getSystemServiceName(TelecomManager.class)).thenReturn(
@@ -312,6 +305,11 @@
                 mMockTelecomManager);
         when(mMockContext.getSystemService(DropBoxManager.class)).thenReturn(
                 mMockDropBoxManager);
+        doAnswer(inv -> {
+            var args = inv.getArguments();
+            return InstrumentationRegistry.getTargetContext()
+                    .getDir((String) args[0], (Integer) args[1]);
+        }).when(mPhoneGlobals).getDir(anyString(), anyInt());
         mPhones = new Phone[]{mMockPhone, mMockPhone2};
         replaceInstance(PhoneFactory.class, "sPhones", null, mPhones);
         replaceInstance(SatelliteController.class, "sInstance", null,
@@ -320,6 +318,8 @@
                 mMockSatelliteModemInterface);
         replaceInstance(TelephonyCountryDetector.class, "sInstance", null,
                 mMockCountryDetector);
+        replaceInstance(ControllerMetricsStats.class, "sInstance", null,
+                mock(ControllerMetricsStats.class));
         when(mMockSatelliteController.getSatellitePhone()).thenReturn(mMockPhone);
         when(mMockPhone.getSubId()).thenReturn(SubscriptionManager.getDefaultSubscriptionId());
 
@@ -361,8 +361,8 @@
                 any(SatelliteOnDeviceAccessController.LocationToken.class)))
                 .thenReturn(DEFAULT_REGIONAL_SATELLITE_CONFIG_ID);
 
-        when(mMockContext.getSharedPreferences(anyString(), anyInt())).thenReturn(
-                mMockSharedPreferences);
+        doReturn(mMockSharedPreferences).when(mMockContext)
+                .getSharedPreferences(anyString(), anyInt());
         when(mMockSharedPreferences.getBoolean(anyString(), anyBoolean())).thenReturn(true);
         when(mMockSharedPreferences.getStringSet(anyString(), any()))
                 .thenReturn(Set.of(TEST_SATELLITE_COUNTRY_CODES));
@@ -392,28 +392,19 @@
                 NotificationManager.class)).thenReturn(Context.NOTIFICATION_SERVICE);
         when(mMockContext.getSystemService(Context.NOTIFICATION_SERVICE))
                 .thenReturn(mMockNotificationManager);
-        when(mMockContext.getApplicationInfo()).thenReturn(mMockApplicationInfo);
+        doReturn(mMockApplicationInfo).when(mMockContext).getApplicationInfo();
         mMockApplicationInfo.targetSdkVersion = Build.VERSION_CODES.UPSIDE_DOWN_CAKE;
         when(mMockPackageManager.getApplicationInfo(anyString(), anyInt()))
                 .thenReturn(mMockApplicationInfo);
         mSatelliteAccessControllerUT = new TestSatelliteAccessController(mMockContext,
-                mMockFeatureFlags, mLooper, mMockLocationManager, mMockTelecomManager,
-                mMockSatelliteOnDeviceAccessController, mMockSatS2File);
+                mMockFeatureFlags, mTestableLooper.getLooper(), mMockLocationManager,
+                mMockTelecomManager, mMockSatelliteOnDeviceAccessController, mMockSatS2File);
         mTestableLooper.processAllMessages();
     }
 
     @After
     public void tearDown() throws Exception {
-        logd("tearDown");
-        if (mTestableLooper != null) {
-            mTestableLooper.destroy();
-            mTestableLooper = null;
-        }
-
-        if (mLooper != null) {
-            mLooper.quit();
-            mLooper = null;
-        }
+        super.tearDown();
     }
 
     @Test
@@ -1480,6 +1471,7 @@
         doReturn(mockConfig).when(mMockSatelliteController).getSatelliteConfig();
         File testS2File = mSatelliteAccessControllerUT
                 .getTestSatelliteS2File(GOOGLE_US_SAN_SAT_S2_FILE_NAME);
+        assumeTrue("Satellite not supported", testS2File != null && testS2File.exists());
         doReturn(List.of(TEST_SATELLITE_COUNTRY_CODES))
                 .when(mockConfig).getDeviceSatelliteCountryCodes();
         doReturn(true).when(mockConfig).isSatelliteDataForAllowedRegion();
@@ -1800,13 +1792,6 @@
         Log.d(TAG, message);
     }
 
-    private static void replaceInstance(final Class c,
-            final String instanceName, final Object obj, final Object newValue) throws Exception {
-        Field field = c.getDeclaredField(instanceName);
-        field.setAccessible(true);
-        field.set(obj, newValue);
-    }
-
     private static class TestSatelliteAccessController extends SatelliteAccessController {
         public long elapsedRealtimeNanos = 0;
 
diff --git a/tests/src/com/android/phone/satellite/entitlement/SatelliteEntitlementControllerTest.java b/tests/src/com/android/phone/satellite/entitlement/SatelliteEntitlementControllerTest.java
index 9f8a733..f41f861 100644
--- a/tests/src/com/android/phone/satellite/entitlement/SatelliteEntitlementControllerTest.java
+++ b/tests/src/com/android/phone/satellite/entitlement/SatelliteEntitlementControllerTest.java
@@ -60,9 +60,6 @@
 
 import com.android.TelephonyTestBase;
 import com.android.internal.telephony.ExponentialBackoff;
-import com.android.internal.telephony.PhoneFactory;
-import com.android.internal.telephony.metrics.MetricsCollector;
-import com.android.internal.telephony.metrics.PersistAtomsStorage;
 import com.android.internal.telephony.satellite.SatelliteController;
 import com.android.internal.telephony.subscription.SubscriptionManagerService;
 import com.android.libraries.entitlement.ServiceEntitlementException;
@@ -72,7 +69,6 @@
 import org.junit.Test;
 import org.junit.runner.RunWith;
 import org.mockito.Mock;
-import org.mockito.Mockito;
 import org.mockito.invocation.InvocationOnMock;
 import org.mockito.stubbing.Answer;
 
@@ -105,7 +101,6 @@
     @Mock Network mNetwork;
     @Mock TelephonyManager mTelephonyManager;
     @Mock SubscriptionManagerService mMockSubscriptionManagerService;
-    @Mock private MetricsCollector mMetricsCollector;
     @Mock SatelliteEntitlementApi mSatelliteEntitlementApi;
     @Mock SatelliteEntitlementResult mSatelliteEntitlementResult;
     @Mock SatelliteController mSatelliteController;
@@ -123,8 +118,6 @@
         replaceInstance(SubscriptionManagerService.class, "sInstance", null,
                 mMockSubscriptionManagerService);
         replaceInstance(SatelliteController.class, "sInstance", null, mSatelliteController);
-        replaceInstance(PhoneFactory.class, "sMetricsCollector", null, mMetricsCollector);
-        doReturn(Mockito.mock(PersistAtomsStorage.class)).when(mMetricsCollector).getAtomsStorage();
 
         mTestableLooper = TestableLooper.get(this);
         mHandler = new Handler(mTestableLooper.getLooper());