diff --git a/src/com/android/settings/network/telephony/AutoDataSwitchPreferenceController.java b/src/com/android/settings/network/telephony/AutoDataSwitchPreferenceController.java index f4543f5004d..ea2a9ece14b 100644 --- a/src/com/android/settings/network/telephony/AutoDataSwitchPreferenceController.java +++ b/src/com/android/settings/network/telephony/AutoDataSwitchPreferenceController.java @@ -22,8 +22,10 @@ import static androidx.lifecycle.Lifecycle.Event.ON_RESUME; import android.content.Context; import android.os.Handler; import android.os.Looper; +import android.telephony.SubscriptionInfo; import android.telephony.SubscriptionManager; import android.telephony.TelephonyManager; +import android.util.Log; import androidx.lifecycle.LifecycleObserver; import androidx.lifecycle.OnLifecycleEvent; @@ -36,6 +38,8 @@ import com.android.settings.datausage.DataUsageUtils; import com.android.settings.network.MobileDataContentObserver; import com.android.settings.network.SubscriptionsChangeListener; +import java.util.List; + /** * Controls whether switch mobile data to the non-default SIM if the non-default SIM has better * availability. @@ -45,39 +49,88 @@ import com.android.settings.network.SubscriptionsChangeListener; * signal/connectivity. * If this feature is enabled, data will be temporarily enabled on the non-default data SIM, * including during any voice calls. + * + * Showing this preference in the default data sim UI. */ public class AutoDataSwitchPreferenceController extends TelephonyTogglePreferenceController implements LifecycleObserver, SubscriptionsChangeListener.SubscriptionsChangeListenerClient { + private static final String TAG = "AutoDataSwitchPreferenceController"; private SwitchPreference mPreference; private SubscriptionsChangeListener mChangeListener; private TelephonyManager mManager; private MobileDataContentObserver mMobileDataContentObserver; private PreferenceScreen mScreen; + private SubscriptionManager mSubscriptionManager; + private List mSubInfoList; public AutoDataSwitchPreferenceController(Context context, String preferenceKey) { super(context, preferenceKey); + mSubscriptionManager = mContext.getSystemService(SubscriptionManager.class); } void init(int subId) { this.mSubId = subId; - mManager = mContext.getSystemService(TelephonyManager.class).createForSubscriptionId(subId); + if (renewSubscriptionInfoList()) { + // If the subscriptionInfos are changed, then + mManager = mContext.getSystemService(TelephonyManager.class) + .createForSubscriptionId(getNonDdsSubId()); + } + if (mMobileDataContentObserver == null) { + mMobileDataContentObserver = new MobileDataContentObserver( + new Handler(Looper.getMainLooper())); + mMobileDataContentObserver.setOnMobileDataChangedListener(() -> { + mManager = mContext.getSystemService(TelephonyManager.class) + .createForSubscriptionId(getNonDdsSubId()); + refreshPreference(); + }); + } + } + + private void renewTelephonyComponent() { + if (renewSubscriptionInfoList()) { + // If the subscriptionInfos are changed, then + if (mMobileDataContentObserver != null) { + mMobileDataContentObserver.unRegister(mContext); + } + } + if (mSubInfoList == null) { + Log.d(TAG, "mSubInfoList is null. Stop to register the listener"); + return; + } + if (mMobileDataContentObserver != null) { + for (SubscriptionInfo subInfo : mSubInfoList) { + mMobileDataContentObserver.register(mContext, subInfo.getSubscriptionId()); + } + } + mManager = mContext.getSystemService(TelephonyManager.class) + .createForSubscriptionId(getNonDdsSubId()); + } + + /** + * Renew the subscriptionInfoList if the subscriptionInfos are changed. + * @return true if the subscriptionInfos are changed. Otherwise, return false. + */ + private boolean renewSubscriptionInfoList() { + final List newSubInfoList = + mSubscriptionManager.getActiveSubscriptionInfoList(); + if ((newSubInfoList == null && mSubInfoList == null) + || (mSubInfoList != null && mSubInfoList.equals(newSubInfoList))) { + return false; + } + mSubInfoList = newSubInfoList; + return true; } @OnLifecycleEvent(ON_RESUME) public void onResume() { + renewTelephonyComponent(); if (mChangeListener == null) { mChangeListener = new SubscriptionsChangeListener(mContext, this); } mChangeListener.start(); - if (mMobileDataContentObserver == null) { - mMobileDataContentObserver = new MobileDataContentObserver( - new Handler(Looper.getMainLooper())); - mMobileDataContentObserver.setOnMobileDataChangedListener(() -> refreshPreference()); - } - mMobileDataContentObserver.register(mContext, mSubId); } @OnLifecycleEvent(ON_PAUSE) @@ -105,6 +158,10 @@ public class AutoDataSwitchPreferenceController extends TelephonyTogglePreferenc @Override public boolean setChecked(boolean isChecked) { + if (mManager == null) { + Log.d(TAG, "mManager is null."); + return false; + } mManager.setMobileDataPolicyEnabled( TelephonyManager.MOBILE_DATA_POLICY_AUTO_DATA_SWITCH, isChecked); @@ -119,7 +176,8 @@ public class AutoDataSwitchPreferenceController extends TelephonyTogglePreferenc @Override public int getAvailabilityStatus(int subId) { if (!SubscriptionManager.isValidSubscriptionId(subId) - || SubscriptionManager.getDefaultDataSubscriptionId() == subId + || SubscriptionManager.getDefaultDataSubscriptionId() != subId + || !SubscriptionManager.isValidSubscriptionId(getNonDdsSubId()) || (!hasMobileData())) { return CONDITIONALLY_UNAVAILABLE; } @@ -136,10 +194,12 @@ public class AutoDataSwitchPreferenceController extends TelephonyTogglePreferenc } @Override - public void onAirplaneModeChanged(boolean airplaneModeEnabled) {} + public void onAirplaneModeChanged(boolean airplaneModeEnabled) { + } @Override public void onSubscriptionsChanged() { + renewTelephonyComponent(); updateState(mPreference); } @@ -152,4 +212,23 @@ public class AutoDataSwitchPreferenceController extends TelephonyTogglePreferenc super.displayPreference(mScreen); } } + + private int getNonDdsSubId() { + int ddsSubId = SubscriptionManager.getDefaultDataSubscriptionId(); + Log.d(TAG, "DDS SubId: " + ddsSubId); + + if (ddsSubId == SubscriptionManager.INVALID_SUBSCRIPTION_ID) { + return SubscriptionManager.INVALID_SUBSCRIPTION_ID; + } + + if (mSubInfoList == null) { + return SubscriptionManager.INVALID_SUBSCRIPTION_ID; + } + + return mSubInfoList.stream() + .mapToInt(subInfo -> subInfo.getSubscriptionId()) + .filter(subId -> subId != ddsSubId) + .findFirst() + .orElse(SubscriptionManager.INVALID_SUBSCRIPTION_ID); + } } diff --git a/tests/robotests/src/com/android/settings/network/telephony/AutoDataSwitchPreferenceControllerTest.java b/tests/robotests/src/com/android/settings/network/telephony/AutoDataSwitchPreferenceControllerTest.java index 758d6b09b99..32657a4a12f 100644 --- a/tests/robotests/src/com/android/settings/network/telephony/AutoDataSwitchPreferenceControllerTest.java +++ b/tests/robotests/src/com/android/settings/network/telephony/AutoDataSwitchPreferenceControllerTest.java @@ -28,13 +28,18 @@ import static org.mockito.ArgumentMatchers.eq; import static org.mockito.Mockito.doReturn; import static org.mockito.Mockito.spy; import static org.mockito.Mockito.when; +import static org.robolectric.Shadows.shadowOf; import android.content.Context; +import android.telephony.SubscriptionInfo; +import android.telephony.SubscriptionManager; import android.telephony.TelephonyManager; import androidx.preference.PreferenceScreen; import androidx.preference.SwitchPreference; +import com.google.common.collect.ImmutableList; + import org.junit.Before; import org.junit.Test; import org.junit.runner.RunWith; @@ -56,10 +61,15 @@ public class AutoDataSwitchPreferenceControllerTest { private TelephonyManager mTelephonyManager; @Mock private PreferenceScreen mPreferenceScreen; + @Mock + private SubscriptionInfo mSubscriptionInfo1; + @Mock + private SubscriptionInfo mSubscriptionInfo2; private Context mContext; private SwitchPreference mSwitchPreference; private AutoDataSwitchPreferenceController mController; + private ShadowSubscriptionManager mShadowSubscriptionManager; @Before public void setUp() { @@ -69,6 +79,11 @@ public class AutoDataSwitchPreferenceControllerTest { when(mTelephonyManager.createForSubscriptionId(anyInt())).thenReturn(mTelephonyManager); mSwitchPreference = new SwitchPreference(mContext); when(mPreferenceScreen.findPreference(PREF_KEY)).thenReturn(mSwitchPreference); + when(mSubscriptionInfo1.getSubscriptionId()).thenReturn(SUB_ID_1); + when(mSubscriptionInfo2.getSubscriptionId()).thenReturn(SUB_ID_2); + mShadowSubscriptionManager = shadowOf(mContext.getSystemService(SubscriptionManager.class)); + mShadowSubscriptionManager.setActiveSubscriptionInfoList(ImmutableList.of( + mSubscriptionInfo1, mSubscriptionInfo2)); mController = new AutoDataSwitchPreferenceController(mContext, PREF_KEY) { @Override protected boolean hasMobileData() { @@ -90,18 +105,9 @@ public class AutoDataSwitchPreferenceControllerTest { } @Test - public void displayPreference_defaultForData_notAvailable() { + public void displayPreference_defaultForData_available() { ShadowSubscriptionManager.setDefaultDataSubscriptionId(SUB_ID_1); - - mController.displayPreference(mPreferenceScreen); - - assertThat(mController.isAvailable()).isFalse(); - assertThat(mSwitchPreference.isVisible()).isFalse(); - } - - @Test - public void displayPreference_notDefaultForData_available() { - ShadowSubscriptionManager.setDefaultDataSubscriptionId(SUB_ID_2); + mController.init(SUB_ID_1); mController.displayPreference(mPreferenceScreen); @@ -110,23 +116,22 @@ public class AutoDataSwitchPreferenceControllerTest { } @Test - public void onSubscriptionsChanged_becomesDefaultForData_notAvailable() { + public void displayPreference_notDefaultForData_notAvailable() { ShadowSubscriptionManager.setDefaultDataSubscriptionId(SUB_ID_2); mController.displayPreference(mPreferenceScreen); - ShadowSubscriptionManager.setDefaultDataSubscriptionId(SUB_ID_1); - mController.onSubscriptionsChanged(); assertThat(mController.isAvailable()).isFalse(); assertThat(mSwitchPreference.isVisible()).isFalse(); } @Test - public void onSubscriptionsChanged_noLongerDefaultForData_available() { - ShadowSubscriptionManager.setDefaultDataSubscriptionId(SUB_ID_1); + public void onSubscriptionsChanged_becomesDefaultForData_available() { + ShadowSubscriptionManager.setDefaultDataSubscriptionId(SUB_ID_2); + mController.init(SUB_ID_1); mController.displayPreference(mPreferenceScreen); - ShadowSubscriptionManager.setDefaultDataSubscriptionId(SUB_ID_2); + ShadowSubscriptionManager.setDefaultDataSubscriptionId(SUB_ID_1); mController.onSubscriptionsChanged(); assertThat(mController.isAvailable()).isTrue(); @@ -134,22 +139,38 @@ public class AutoDataSwitchPreferenceControllerTest { } @Test - public void getAvailabilityStatus_mobileDataChangWithDefaultDataSubId_returnUnavailable() { + public void onSubscriptionsChanged_noLongerDefaultForData_notAvailable() { ShadowSubscriptionManager.setDefaultDataSubscriptionId(SUB_ID_1); + mController.init(SUB_ID_1); + + mController.displayPreference(mPreferenceScreen); + ShadowSubscriptionManager.setDefaultDataSubscriptionId(SUB_ID_2); + mController.onSubscriptionsChanged(); + + assertThat(mController.isAvailable()).isFalse(); + assertThat(mSwitchPreference.isVisible()).isFalse(); + } + + @Test + public void getAvailabilityStatus_mobileDataChangWithDefaultDataSubId_returnAvailable() { + ShadowSubscriptionManager.setDefaultDataSubscriptionId(SUB_ID_1); + mController.init(SUB_ID_1); mController.refreshPreference(); assertThat(mController.getAvailabilityStatus(SUB_ID_1)) - .isEqualTo(CONDITIONALLY_UNAVAILABLE); + .isEqualTo(AVAILABLE); } @Test - public void getAvailabilityStatus_mobileDataChangWithoutDefaultDataSubId_returnAvailable() { + public void getAvailabilityStatus_mobileDataChangWithoutDefaultDataSubId_returnUnavailable() { ShadowSubscriptionManager.setDefaultDataSubscriptionId(SUB_ID_1); + mController.init(SUB_ID_1); mController.displayPreference(mPreferenceScreen); mController.refreshPreference(); - assertThat(mController.getAvailabilityStatus(SUB_ID_2)).isEqualTo(AVAILABLE); + assertThat(mController.getAvailabilityStatus(SUB_ID_2)).isEqualTo( + CONDITIONALLY_UNAVAILABLE); } }