Merge "Removing Dead Flag Test: CI Bug: 386652866" into main
diff --git a/Android.bp b/Android.bp
index 0a58ee8..827f431 100644
--- a/Android.bp
+++ b/Android.bp
@@ -126,6 +126,7 @@
     },
 
     libs: [
+        "framework-virtualization.stubs.system",
         "telephony-common",
         "ims-common",
     ],
diff --git a/res/values/strings.xml b/res/values/strings.xml
index 7e363e6..2366f3b 100644
--- a/res/values/strings.xml
+++ b/res/values/strings.xml
@@ -13046,7 +13046,7 @@
     <string name="thread_network_settings_learn_more">Learn more about Thread</string>
 
     <!-- URL for Thread network settings learn more link [CHAR_LIMIT=NONE] -->
-    <string name="thread_network_settings_learn_more_link" translatable="false">https://developers.home.google.com</string>
+    <string name="thread_network_settings_learn_more_link" translatable="false">https://support.google.com/android?p=thread_toggle</string>
 
     <!-- Label for the camera use toggle [CHAR LIMIT=40] -->
     <string name="camera_toggle_title">Camera access</string>
diff --git a/src/com/android/settings/development/linuxterminal/LinuxTerminalPreferenceController.java b/src/com/android/settings/development/linuxterminal/LinuxTerminalPreferenceController.java
index cbb9181..3bd9587 100644
--- a/src/com/android/settings/development/linuxterminal/LinuxTerminalPreferenceController.java
+++ b/src/com/android/settings/development/linuxterminal/LinuxTerminalPreferenceController.java
@@ -16,10 +16,13 @@
 
 package com.android.settings.development.linuxterminal;
 
+import static android.system.virtualmachine.VirtualMachineManager.CAPABILITY_NON_PROTECTED_VM;
+
 import android.content.Context;
 import android.content.pm.PackageManager;
 import android.os.Process;
 import android.os.storage.StorageManager;
+import android.system.virtualmachine.VirtualMachineManager;
 import android.text.TextUtils;
 import android.util.DataUnit;
 
@@ -58,9 +61,13 @@
 
         StorageManager storageManager =
                 Objects.requireNonNull(context.getSystemService(StorageManager.class));
+        VirtualMachineManager virtualMachineManager =
+                Objects.requireNonNull(context.getSystemService(VirtualMachineManager.class));
         mIsDeviceCapable =
                 getTotalMemory() >= MEMORY_MIN_BYTES
-                        && storageManager.getPrimaryStorageSize() >= STORAGE_MIN_BYTES;
+                        && storageManager.getPrimaryStorageSize() >= STORAGE_MIN_BYTES
+                        && ((virtualMachineManager.getCapabilities() & CAPABILITY_NON_PROTECTED_VM)
+                                != 0);
     }
 
     // Avoid lazy initialization because this may be called before displayPreference().
diff --git a/src/com/android/settings/deviceinfo/simstatus/SimStatusDialogController.java b/src/com/android/settings/deviceinfo/simstatus/SimStatusDialogController.java
index b5ee1d8..89f286c 100644
--- a/src/com/android/settings/deviceinfo/simstatus/SimStatusDialogController.java
+++ b/src/com/android/settings/deviceinfo/simstatus/SimStatusDialogController.java
@@ -100,11 +100,17 @@
     @VisibleForTesting
     static final int MAX_PHONE_COUNT_SINGLE_SIM = 1;
 
-    private final OnSubscriptionsChangedListener mOnSubscriptionsChangedListener =
+    @VisibleForTesting
+    final OnSubscriptionsChangedListener mOnSubscriptionsChangedListener =
             new OnSubscriptionsChangedListener() {
                 @Override
                 public void onSubscriptionsChanged() {
+                    SubscriptionInfo oldSubInfo = mSubscriptionInfo;
                     mSubscriptionInfo = getPhoneSubscriptionInfo(mSlotIndex);
+                    if (getSubId(oldSubInfo) != getSubId(mSubscriptionInfo)) {
+                      unregisterTelephonyCallback(oldSubInfo);
+                      registerTelephonyCallback(mSubscriptionInfo);
+                    }
                     updateSubscriptionStatus();
                 }
             };
@@ -123,7 +129,6 @@
     private final Context mContext;
 
     private boolean mShowLatestAreaInfo;
-    private boolean mIsRegisteredListener = false;
 
     private final BroadcastReceiver mAreaInfoReceiver = new BroadcastReceiver() {
         @Override
@@ -137,7 +142,8 @@
     };
 
     @VisibleForTesting
-    protected SimStatusDialogTelephonyCallback mTelephonyCallback;
+    protected final SimStatusDialogTelephonyCallback mTelephonyCallback =
+            new SimStatusDialogTelephonyCallback();
 
     private CellBroadcastServiceConnection mCellBroadcastServiceConnection;
 
@@ -181,8 +187,6 @@
         mContext = dialog.getContext();
         mSlotIndex = slotId;
         mSubscriptionInfo = getPhoneSubscriptionInfo(slotId);
-
-        mTelephonyManager = mContext.getSystemService(TelephonyManager.class);
         mCarrierConfigManager = mContext.getSystemService(CarrierConfigManager.class);
         mEuiccManager = mContext.getSystemService(EuiccManager.class);
         mSubscriptionManager = mContext.getSystemService(SubscriptionManager.class);
@@ -201,11 +205,13 @@
 
     public void initialize() {
         if (mSubscriptionInfo == null) {
-            return;
+            // Should not depend on default sub TelephonyManager, but lots of code already uses it
+            mTelephonyManager = mContext.getSystemService(TelephonyManager.class);
+        } else {
+            mTelephonyManager = mContext.getSystemService(TelephonyManager.class)
+                .createForSubscriptionId(mSubscriptionInfo.getSubscriptionId());
         }
-        mTelephonyManager =
-            getTelephonyManager().createForSubscriptionId(mSubscriptionInfo.getSubscriptionId());
-        mTelephonyCallback = new SimStatusDialogTelephonyCallback();
+
         updateLatestAreaInfo();
         updateSubscriptionStatus();
     }
@@ -222,6 +228,10 @@
         updateNetworkType();
         updateRoamingStatus(serviceState);
         updateIccidNumber();
+
+        if (mSubscriptionInfo == null) {
+            updateDataState(TelephonyManager.DATA_UNKNOWN);
+        }
     }
 
     /**
@@ -242,13 +252,9 @@
      */
     @Override
     public void onResume(@NonNull LifecycleOwner owner) {
-        if (mSubscriptionInfo == null) {
-            return;
-        }
-        mTelephonyManager = getTelephonyManager().createForSubscriptionId(
-                mSubscriptionInfo.getSubscriptionId());
-        getTelephonyManager()
-                .registerTelephonyCallback(mContext.getMainExecutor(), mTelephonyCallback);
+        // get the latest sub info for it may be updated in onPause/onStop status.
+        mSubscriptionInfo = getPhoneSubscriptionInfo(mSlotIndex);
+        registerTelephonyCallback(mSubscriptionInfo);
         mSubscriptionManager.addOnSubscriptionsChangedListener(
                 mContext.getMainExecutor(), mOnSubscriptionsChangedListener);
         collectSimStatusDialogInfo(owner);
@@ -259,8 +265,6 @@
                     new IntentFilter(CellBroadcastIntents.ACTION_AREA_INFO_UPDATED),
                     Context.RECEIVER_EXPORTED/*UNAUDITED*/);
         }
-
-        mIsRegisteredListener = true;
     }
 
     /**
@@ -268,22 +272,9 @@
      */
     @Override
     public void onPause(@NonNull LifecycleOwner owner) {
-        if (mSubscriptionInfo == null) {
-            if (mIsRegisteredListener) {
-                mSubscriptionManager.removeOnSubscriptionsChangedListener(
-                        mOnSubscriptionsChangedListener);
-                getTelephonyManager().unregisterTelephonyCallback(mTelephonyCallback);
-                if (mShowLatestAreaInfo) {
-                    mContext.unregisterReceiver(mAreaInfoReceiver);
-                }
-                mIsRegisteredListener = false;
-            }
-            return;
-        }
-
-        mSubscriptionManager.removeOnSubscriptionsChangedListener(mOnSubscriptionsChangedListener);
-        getTelephonyManager().unregisterTelephonyCallback(mTelephonyCallback);
-
+        mSubscriptionManager.removeOnSubscriptionsChangedListener(
+                mOnSubscriptionsChangedListener);
+        unregisterTelephonyCallback(mSubscriptionInfo);
         if (mShowLatestAreaInfo) {
             mContext.unregisterReceiver(mAreaInfoReceiver);
         }
@@ -555,6 +546,34 @@
         return SubscriptionManager.from(mContext).getActiveSubscriptionInfoForSimSlotIndex(slotId);
     }
 
+    private void registerTelephonyCallback(SubscriptionInfo subInfo) {
+        if (subInfo == null) {
+            return;
+        }
+
+        // No need to have a member to hold mTelephonyManager, leaving it as lots of code
+        // depending on it
+        mTelephonyManager = mContext.getSystemService(TelephonyManager.class)
+                .createForSubscriptionId(subInfo.getSubscriptionId());
+        mTelephonyManager.registerTelephonyCallback(
+                mContext.getMainExecutor(), mTelephonyCallback);
+    }
+
+    private void unregisterTelephonyCallback(SubscriptionInfo subInfo) {
+        if (subInfo == null) {
+          return;
+        }
+
+        mContext.getSystemService(TelephonyManager.class)
+                .createForSubscriptionId(subInfo.getSubscriptionId())
+                .unregisterTelephonyCallback(mTelephonyCallback);
+    }
+
+    private int getSubId(SubscriptionInfo subInfo) {
+        return subInfo == null ? SubscriptionManager.INVALID_SUBSCRIPTION_ID :
+                subInfo.getSubscriptionId();
+    }
+
     @VisibleForTesting
     class SimStatusDialogTelephonyCallback extends TelephonyCallback implements
             TelephonyCallback.DataConnectionStateListener,
diff --git a/tests/robotests/Android.bp b/tests/robotests/Android.bp
index 8622ec5..552e8cc 100644
--- a/tests/robotests/Android.bp
+++ b/tests/robotests/Android.bp
@@ -80,6 +80,7 @@
 
     libs: [
         "android.test.mock.impl",
+        "framework-virtualization.stubs.system",
         "ims-common",
     ],
 
diff --git a/tests/robotests/src/com/android/settings/development/linuxterminal/LinuxTerminalPreferenceControllerTest.java b/tests/robotests/src/com/android/settings/development/linuxterminal/LinuxTerminalPreferenceControllerTest.java
index fffe6b1..d17b49b 100644
--- a/tests/robotests/src/com/android/settings/development/linuxterminal/LinuxTerminalPreferenceControllerTest.java
+++ b/tests/robotests/src/com/android/settings/development/linuxterminal/LinuxTerminalPreferenceControllerTest.java
@@ -16,6 +16,8 @@
 
 package com.android.settings.development.linuxterminal;
 
+import static android.system.virtualmachine.VirtualMachineManager.CAPABILITY_NON_PROTECTED_VM;
+
 import static com.android.settings.development.linuxterminal.LinuxTerminalPreferenceController.MEMORY_MIN_BYTES;
 import static com.android.settings.development.linuxterminal.LinuxTerminalPreferenceController.STORAGE_MIN_BYTES;
 import static com.android.settings.development.linuxterminal.LinuxTerminalPreferenceController.TERMINAL_PACKAGE_NAME_RESID;
@@ -32,6 +34,7 @@
 import android.content.pm.PackageManager;
 import android.content.pm.PackageManager.NameNotFoundException;
 import android.os.storage.StorageManager;
+import android.system.virtualmachine.VirtualMachineManager;
 
 import org.junit.Before;
 import org.junit.Test;
@@ -43,27 +46,33 @@
 /** Tests {@link LinuxTerminalPreferenceController} */
 @RunWith(RobolectricTestRunner.class)
 public class LinuxTerminalPreferenceControllerTest {
+    private static final String TERMINAL_PACKAGE_NAME = "com.android.virtualization.terminal";
 
     @Mock private Context mContext;
     @Mock private PackageManager mPackageManager;
     @Mock private StorageManager mStorageManager;
+    @Mock private VirtualMachineManager mVirtualMachineManager;
     @Mock private PackageInfo mPackageInfo;
 
-    private String mTerminalPackageName = "com.android.virtualization.terminal";
     private LinuxTerminalPreferenceController mController;
 
     @Before
     public void setup() throws Exception {
         MockitoAnnotations.initMocks(this);
-        doReturn(mTerminalPackageName).when(mContext).getString(TERMINAL_PACKAGE_NAME_RESID);
+        doReturn(TERMINAL_PACKAGE_NAME).when(mContext).getString(TERMINAL_PACKAGE_NAME_RESID);
 
         doReturn(mPackageManager).when(mContext).getPackageManager();
         doReturn(mPackageInfo)
                 .when(mPackageManager)
-                .getPackageInfo(eq(mTerminalPackageName), anyInt());
+                .getPackageInfo(eq(TERMINAL_PACKAGE_NAME), anyInt());
 
         doReturn(mStorageManager).when(mContext).getSystemService(StorageManager.class);
         doReturn(STORAGE_MIN_BYTES).when(mStorageManager).getPrimaryStorageSize();
+
+        doReturn(mVirtualMachineManager)
+                .when(mContext)
+                .getSystemService(VirtualMachineManager.class);
+        doReturn(CAPABILITY_NON_PROTECTED_VM).when(mVirtualMachineManager).getCapabilities();
     }
 
     @Test
@@ -83,6 +92,15 @@
     }
 
     @Test
+    public void isAvailable_whenVmNotSupported_returnFalse() {
+        doReturn(0).when(mVirtualMachineManager).getCapabilities();
+
+        mController = createController(mContext);
+
+        assertThat(mController.isAvailable()).isFalse();
+    }
+
+    @Test
     public void isAvailable_whenPackageExists_returnsTrue() {
         mController = createController(mContext);
 
@@ -102,7 +120,7 @@
     public void isAvailable_whenAppDoesNotExist_returnsFalse() throws Exception {
         doThrow(new NameNotFoundException())
                 .when(mPackageManager)
-                .getPackageInfo(eq(mTerminalPackageName), anyInt());
+                .getPackageInfo(eq(TERMINAL_PACKAGE_NAME), anyInt());
 
         mController = createController(mContext);
 
diff --git a/tests/unit/src/com/android/settings/deviceinfo/simstatus/SimStatusDialogControllerTest.java b/tests/unit/src/com/android/settings/deviceinfo/simstatus/SimStatusDialogControllerTest.java
index 3fa3808..d68ffa8 100644
--- a/tests/unit/src/com/android/settings/deviceinfo/simstatus/SimStatusDialogControllerTest.java
+++ b/tests/unit/src/com/android/settings/deviceinfo/simstatus/SimStatusDialogControllerTest.java
@@ -17,6 +17,7 @@
 package com.android.settings.deviceinfo.simstatus;
 
 import static com.android.settings.deviceinfo.simstatus.SimStatusDialogController.CELL_DATA_NETWORK_TYPE_VALUE_ID;
+import static com.android.settings.deviceinfo.simstatus.SimStatusDialogController.CELLULAR_NETWORK_STATE;
 import static com.android.settings.deviceinfo.simstatus.SimStatusDialogController.CELL_VOICE_NETWORK_TYPE_VALUE_ID;
 import static com.android.settings.deviceinfo.simstatus.SimStatusDialogController.ICCID_INFO_LABEL_ID;
 import static com.android.settings.deviceinfo.simstatus.SimStatusDialogController.ICCID_INFO_VALUE_ID;
@@ -30,8 +31,10 @@
 import static com.android.settings.deviceinfo.simstatus.SimStatusDialogController.SERVICE_STATE_VALUE_ID;
 
 import static org.junit.Assert.assertTrue;
+import static org.mockito.ArgumentMatchers.any;
 import static org.mockito.ArgumentMatchers.anyInt;
 import static org.mockito.Mockito.doReturn;
+import static org.mockito.Mockito.mock;
 import static org.mockito.Mockito.spy;
 import static org.mockito.Mockito.verify;
 import static org.mockito.Mockito.when;
@@ -42,6 +45,7 @@
 import android.telephony.ServiceState;
 import android.telephony.SubscriptionInfo;
 import android.telephony.SubscriptionManager;
+import android.telephony.TelephonyCallback;
 import android.telephony.TelephonyManager;
 import android.telephony.UiccCardInfo;
 import android.telephony.euicc.EuiccManager;
@@ -65,6 +69,7 @@
 import java.util.HashMap;
 import java.util.concurrent.atomic.AtomicBoolean;
 import java.util.concurrent.atomic.AtomicInteger;
+import java.util.concurrent.Executor;
 
 @RunWith(AndroidJUnit4.class)
 public class SimStatusDialogControllerTest {
@@ -74,6 +79,10 @@
     @Mock
     private TelephonyManager mTelephonyManager;
     @Mock
+    private TelephonyManager mTelephonyManagerForSub1;
+    @Mock
+    private TelephonyManager mTelephonyManagerForSub2;
+    @Mock
     private SubscriptionInfo mSubscriptionInfo;
     @Mock
     private ServiceState mServiceState;
@@ -94,6 +103,9 @@
 
     private static final int MAX_PHONE_COUNT_DUAL_SIM = 2;
 
+    private static final int TEST_SUB_ID_1 = 1;
+    private static final int TEST_SUB_ID_2 = 2;
+
     @Before
     @UiThreadTest
     public void setup() {
@@ -106,6 +118,7 @@
         mSubscriptionManager = spy(mContext.getSystemService(SubscriptionManager.class));
         doReturn(mSubscriptionInfo).when(mSubscriptionManager)
                 .getActiveSubscriptionInfoForSimSlotIndex(anyInt());
+        doReturn(TEST_SUB_ID_1).when(mSubscriptionInfo).getSubscriptionId();
 
         when(mContext.getSystemService(TelephonyManager.class)).thenReturn(mTelephonyManager);
         when(mContext.getSystemService(CarrierConfigManager.class)).thenReturn(
@@ -113,8 +126,10 @@
         when(mContext.getSystemService(EuiccManager.class)).thenReturn(mEuiccManager);
         when(mContext.getSystemService(SubscriptionManager.class)).thenReturn(mSubscriptionManager);
 
-        doReturn(mTelephonyManager).when(mTelephonyManager).createForSubscriptionId(
-                anyInt());
+        doReturn(mTelephonyManagerForSub1).when(mTelephonyManager).createForSubscriptionId(
+                TEST_SUB_ID_1);
+        doReturn(mTelephonyManagerForSub2).when(mTelephonyManager).createForSubscriptionId(
+                TEST_SUB_ID_2);
         doReturn(2).when(mTelephonyManager).getCardIdForDefaultEuicc();
         doReturn(TelephonyManager.NETWORK_TYPE_LTE).when(mTelephonyManager).getDataNetworkType();
 
@@ -340,4 +355,45 @@
         verify(mDialog).setSettingVisibility(IMS_REGISTRATION_STATE_LABEL_ID, false);
         verify(mDialog).setSettingVisibility(IMS_REGISTRATION_STATE_VALUE_ID, false);
     }
+
+    @Test
+    public void onSubscriptionsChanged_updateSubInfoToNewSub_testTelephonyCallbackUnregRereg() {
+        // sub id changed from 1 to 2
+        SubscriptionInfo subInfo2 = mock(SubscriptionInfo.class);
+        doReturn(TEST_SUB_ID_2).when(subInfo2).getSubscriptionId();
+        doReturn(subInfo2).when(mSubscriptionManager)
+                .getActiveSubscriptionInfoForSimSlotIndex(anyInt());
+        mController.mOnSubscriptionsChangedListener.onSubscriptionsChanged();
+        verify(mTelephonyManagerForSub2).registerTelephonyCallback(any(Executor.class),
+                any(TelephonyCallback.class));
+
+        // sub id changed from 2 to 1
+        SubscriptionInfo subInfo1 = mock(SubscriptionInfo.class);
+        doReturn(TEST_SUB_ID_1).when(subInfo1).getSubscriptionId();
+        doReturn(subInfo1).when(mSubscriptionManager)
+                .getActiveSubscriptionInfoForSimSlotIndex(anyInt());
+        mController.mOnSubscriptionsChangedListener.onSubscriptionsChanged();
+        verify(mTelephonyManagerForSub2).unregisterTelephonyCallback(
+                mController.mTelephonyCallback);
+        verify(mTelephonyManagerForSub1).registerTelephonyCallback(any(Executor.class),
+                any(TelephonyCallback.class));
+    }
+
+    @Test
+    public void onSubscriptionsChanged_updateSubInfoToNull_testTelephonyCallbackUnreg() {
+        doReturn(null).when(mSubscriptionManager).getActiveSubscriptionInfoForSimSlotIndex(
+                anyInt());
+        mController.mOnSubscriptionsChangedListener.onSubscriptionsChanged();
+        verify(mTelephonyManagerForSub1).unregisterTelephonyCallback(
+                mController.mTelephonyCallback);
+    }
+
+    @Test
+    public void onSubscriptionsChanged_updateSubInfoToNull_shouldUpdateDataStatusToUnknown() {
+        doReturn(null).when(mSubscriptionManager).getActiveSubscriptionInfoForSimSlotIndex(
+                anyInt());
+        mController.mOnSubscriptionsChangedListener.onSubscriptionsChanged();
+        final String unknownText = ResourcesUtils.getResourcesString(mContext, "radioInfo_unknown");
+        verify(mDialog).setText(CELLULAR_NETWORK_STATE, unknownText);
+    }
 }
diff --git a/tests/unit/src/com/android/settings/network/telephony/MobileNetworkUtilsTest.java b/tests/unit/src/com/android/settings/network/telephony/MobileNetworkUtilsTest.java
index 5f887de..1c51d1d 100644
--- a/tests/unit/src/com/android/settings/network/telephony/MobileNetworkUtilsTest.java
+++ b/tests/unit/src/com/android/settings/network/telephony/MobileNetworkUtilsTest.java
@@ -60,6 +60,7 @@
 import com.android.settings.network.ims.MockWfcQueryImsState;
 
 import org.junit.Before;
+import org.junit.Ignore;
 import org.junit.Test;
 import org.junit.runner.RunWith;
 import org.mockito.Mock;
@@ -396,6 +397,7 @@
     }
 
     @Test
+    @Ignore
     public void getCurrentCarrierNameForDisplay_withoutSubId_returnNotNull() {
         assertThat(MobileNetworkUtils.getCurrentCarrierNameForDisplay(
                 mContext)).isNotNull();