Fix sim status details not updated after sim hotswap
Telephony callback may be removed in onPause during sim hotswap, but they are not re-registered in onResume for sub info still null.
Listen sub info change and re-register telephony callback when need.
Test: function test pass and SimStatusDialogControllerTest unit test pass.
Change-Id: I17e60c9e3441fc593107048494f830408c37ae61
Bug: 384643359
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/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);
+ }
}