diff --git a/res/xml/mobile_network_settings_v2.xml b/res/xml/mobile_network_settings_v2.xml index 20ed1c75a22..506b354ba42 100644 --- a/res/xml/mobile_network_settings_v2.xml +++ b/res/xml/mobile_network_settings_v2.xml @@ -203,4 +203,14 @@ android:title="@string/mobile_network_erase_sim" settings:controller="com.android.settings.network.telephony.DeleteSimProfilePreferenceController" /> + + + + diff --git a/src/com/android/settings/network/MobileNetworkListController.java b/src/com/android/settings/network/MobileNetworkListController.java index d0e14ce2168..ab41fad6236 100644 --- a/src/com/android/settings/network/MobileNetworkListController.java +++ b/src/com/android/settings/network/MobileNetworkListController.java @@ -118,14 +118,19 @@ public class MobileNetworkListController extends AbstractPreferenceController im if (mSubscriptionManager.isActiveSubscriptionId(subId)) { pref.setSummary(R.string.mobile_network_active_sim); } else { - pref.setSummary(R.string.mobile_network_inactive_sim); + pref.setSummary(mContext.getString(R.string.mobile_network_tap_to_activate, + SubscriptionUtil.getDisplayName(info))); } } pref.setOnPreferenceClickListener(clickedPref -> { - final Intent intent = new Intent(mContext, MobileNetworkActivity.class); - intent.putExtra(Settings.EXTRA_SUB_ID, info.getSubscriptionId()); - mContext.startActivity(intent); + if (!info.isEmbedded() && !mSubscriptionManager.isActiveSubscriptionId(subId)) { + mSubscriptionManager.setSubscriptionEnabled(subId, true); + } else { + final Intent intent = new Intent(mContext, MobileNetworkActivity.class); + intent.putExtra(Settings.EXTRA_SUB_ID, info.getSubscriptionId()); + mContext.startActivity(intent); + } return true; }); mPreferences.put(subId, pref); diff --git a/src/com/android/settings/network/MobileNetworkSummaryController.java b/src/com/android/settings/network/MobileNetworkSummaryController.java index 9498c4e61e0..0f76f24de56 100644 --- a/src/com/android/settings/network/MobileNetworkSummaryController.java +++ b/src/com/android/settings/network/MobileNetworkSummaryController.java @@ -108,7 +108,14 @@ public class MobileNetworkSummaryController extends AbstractPreferenceController } return null; } else if (subs.size() == 1) { - return subs.get(0).getDisplayName(); + final SubscriptionInfo info = subs.get(0); + final int subId = info.getSubscriptionId(); + if (!info.isEmbedded() && !mSubscriptionManager.isActiveSubscriptionId(subId)) { + return mContext.getString(R.string.mobile_network_tap_to_activate, + SubscriptionUtil.getDisplayName(info)); + } else { + return subs.get(0).getDisplayName(); + } } else { final int count = subs.size(); return mContext.getResources().getQuantityString(R.plurals.mobile_network_summary_count, @@ -154,9 +161,15 @@ public class MobileNetworkSummaryController extends AbstractPreferenceController if (subs.size() == 1) { mPreference.setOnPreferenceClickListener((Preference pref) -> { - final Intent intent = new Intent(mContext, MobileNetworkActivity.class); - intent.putExtra(Settings.EXTRA_SUB_ID, subs.get(0).getSubscriptionId()); - mContext.startActivity(intent); + final SubscriptionInfo info = subs.get(0); + final int subId = info.getSubscriptionId(); + if (!info.isEmbedded() && !mSubscriptionManager.isActiveSubscriptionId(subId)) { + mSubscriptionManager.setSubscriptionEnabled(subId, true); + } else { + final Intent intent = new Intent(mContext, MobileNetworkActivity.class); + intent.putExtra(Settings.EXTRA_SUB_ID, subs.get(0).getSubscriptionId()); + mContext.startActivity(intent); + } return true; }); } else { diff --git a/src/com/android/settings/network/SubscriptionUtil.java b/src/com/android/settings/network/SubscriptionUtil.java index ebac51f3f67..f7235754f6c 100644 --- a/src/com/android/settings/network/SubscriptionUtil.java +++ b/src/com/android/settings/network/SubscriptionUtil.java @@ -25,12 +25,10 @@ import android.telephony.SubscriptionInfo; import android.telephony.SubscriptionManager; import android.telephony.TelephonyManager; import android.telephony.UiccSlotInfo; -import android.text.TextUtils; import androidx.annotation.VisibleForTesting; import java.util.ArrayList; -import java.util.Iterator; import java.util.List; public class SubscriptionUtil { @@ -107,4 +105,12 @@ public class SubscriptionUtil { } return subscriptions; } + + public static String getDisplayName(SubscriptionInfo info) { + final CharSequence name = info.getDisplayName(); + if (name != null) { + return name.toString(); + } + return ""; + } } diff --git a/src/com/android/settings/network/telephony/DisableSimFooterPreferenceController.java b/src/com/android/settings/network/telephony/DisableSimFooterPreferenceController.java new file mode 100644 index 00000000000..ab01b9d5a86 --- /dev/null +++ b/src/com/android/settings/network/telephony/DisableSimFooterPreferenceController.java @@ -0,0 +1,54 @@ +/* + * Copyright (C) 2019 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.settings.network.telephony; + +import android.content.Context; +import android.telephony.SubscriptionInfo; +import android.telephony.SubscriptionManager; +import android.telephony.TelephonyManager; + +import com.android.settings.core.BasePreferenceController; +import com.android.settings.network.SubscriptionUtil; + +public class DisableSimFooterPreferenceController extends BasePreferenceController { + private int mSubId; + + public DisableSimFooterPreferenceController(Context context, String preferenceKey) { + super(context, preferenceKey); + mSubId = SubscriptionManager.INVALID_SUBSCRIPTION_ID; + } + + public void init(int subId) { + mSubId = subId; + } + + @Override + public int getAvailabilityStatus() { + if (mSubId == SubscriptionManager.INVALID_SUBSCRIPTION_ID) { + return CONDITIONALLY_UNAVAILABLE; + } + for (SubscriptionInfo info : SubscriptionUtil.getAvailableSubscriptions(mContext)) { + if (info.getSubscriptionId() == mSubId) { + if (info.isEmbedded()) { + return CONDITIONALLY_UNAVAILABLE; + } + break; + } + } + return AVAILABLE; + } +} diff --git a/src/com/android/settings/network/telephony/MobileNetworkSettings.java b/src/com/android/settings/network/telephony/MobileNetworkSettings.java index aa63b747ad9..c8e2247db15 100644 --- a/src/com/android/settings/network/telephony/MobileNetworkSettings.java +++ b/src/com/android/settings/network/telephony/MobileNetworkSettings.java @@ -142,6 +142,7 @@ public class MobileNetworkSettings extends RestrictedDashboardFragment { use(DisabledSubscriptionController.class).init(getLifecycle(), mSubId); use(DeleteSimProfilePreferenceController.class).init(mSubId, this, REQUEST_CODE_DELETE_SUBSCRIPTION); + use(DisableSimFooterPreferenceController.class).init(mSubId); } use(MobileDataPreferenceController.class).init(getFragmentManager(), mSubId); use(RoamingPreferenceController.class).init(getFragmentManager(), mSubId); diff --git a/src/com/android/settings/network/telephony/MobileNetworkSwitchController.java b/src/com/android/settings/network/telephony/MobileNetworkSwitchController.java index 2037adce4b5..e6422f00d60 100644 --- a/src/com/android/settings/network/telephony/MobileNetworkSwitchController.java +++ b/src/com/android/settings/network/telephony/MobileNetworkSwitchController.java @@ -93,23 +93,23 @@ public class MobileNetworkSwitchController extends BasePreferenceController impl if (mSwitchBar == null) { return; } - final List subs = SubscriptionUtil.getAvailableSubscriptions( - mContext); - if (mSubId == SubscriptionManager.INVALID_SUBSCRIPTION_ID || - mSubscriptionManager.isSubscriptionEnabled(mSubId) && subs.size() < 2) { - mSwitchBar.hide(); - return; - } - for (SubscriptionInfo info : subs) { + SubscriptionInfo subInfo = null; + for (SubscriptionInfo info : SubscriptionUtil.getAvailableSubscriptions(mContext)) { if (info.getSubscriptionId() == mSubId) { - mSwitchBar.show(); - mSwitchBar.setChecked(mSubscriptionManager.isSubscriptionEnabled(mSubId)); - return; + subInfo = info; + break; } } - // This subscription was not found in the available list. - mSwitchBar.hide(); + + // For eSIM, we always want the toggle. The telephony stack doesn't currently support + // disabling a pSIM directly (b/133379187), so we for now we don't include this on pSIM. + if (subInfo == null || !subInfo.isEmbedded()) { + mSwitchBar.hide(); + } else { + mSwitchBar.show(); + mSwitchBar.setChecked(mSubscriptionManager.isSubscriptionEnabled(mSubId)); + } } @Override diff --git a/tests/robotests/src/com/android/settings/network/MobileNetworkListControllerTest.java b/tests/robotests/src/com/android/settings/network/MobileNetworkListControllerTest.java index 342fed50f15..4a98753e2b0 100644 --- a/tests/robotests/src/com/android/settings/network/MobileNetworkListControllerTest.java +++ b/tests/robotests/src/com/android/settings/network/MobileNetworkListControllerTest.java @@ -21,6 +21,8 @@ import static android.telephony.SubscriptionManager.INVALID_SUBSCRIPTION_ID; import static com.google.common.truth.Truth.assertThat; +import static org.mockito.ArgumentMatchers.eq; +import static org.mockito.Mockito.doReturn; import static org.mockito.Mockito.mock; import static org.mockito.Mockito.spy; import static org.mockito.Mockito.times; @@ -32,6 +34,7 @@ import android.content.Context; import android.content.Intent; import android.provider.Settings; import android.telephony.SubscriptionInfo; +import android.telephony.SubscriptionManager; import android.telephony.TelephonyManager; import android.telephony.euicc.EuiccManager; @@ -54,9 +57,11 @@ import androidx.preference.PreferenceScreen; @RunWith(RobolectricTestRunner.class) public class MobileNetworkListControllerTest { @Mock - TelephonyManager mTelephonyManager; + private TelephonyManager mTelephonyManager; @Mock - EuiccManager mEuiccManager; + private EuiccManager mEuiccManager; + @Mock + private SubscriptionManager mSubscriptionManager; @Mock private Lifecycle mLifecycle; @@ -74,6 +79,7 @@ public class MobileNetworkListControllerTest { mContext = spy(Robolectric.setupActivity(Activity.class)); when(mContext.getSystemService(TelephonyManager.class)).thenReturn(mTelephonyManager); when(mContext.getSystemService(EuiccManager.class)).thenReturn(mEuiccManager); + when(mContext.getSystemService(SubscriptionManager.class)).thenReturn(mSubscriptionManager); Settings.Global.putInt(mContext.getContentResolver(), Settings.Global.EUICC_PROVISIONED, 1); when(mPreferenceScreen.getContext()).thenReturn(mContext); mAddMorePreference = new Preference(mContext); @@ -114,6 +120,8 @@ public class MobileNetworkListControllerTest { public void displayPreference_twoSubscriptions_correctlySetup() { final SubscriptionInfo sub1 = createMockSubscription(1, "sub1"); final SubscriptionInfo sub2 = createMockSubscription(2, "sub2"); + doReturn(true).when(mSubscriptionManager).isActiveSubscriptionId(eq(1)); + doReturn(true).when(mSubscriptionManager).isActiveSubscriptionId(eq(2)); SubscriptionUtil.setAvailableSubscriptionsForTesting(Arrays.asList(sub1, sub2)); mController.displayPreference(mPreferenceScreen); mController.onResume(); @@ -138,6 +146,33 @@ public class MobileNetworkListControllerTest { assertThat(intent2.getIntExtra(EXTRA_SUB_ID, INVALID_SUBSCRIPTION_ID)).isEqualTo(2); } + @Test + public void displayPreference_oneActiveESimOneInactivePSim_correctlySetup() { + final SubscriptionInfo sub1 = createMockSubscription(1, "sub1"); + final SubscriptionInfo sub2 = createMockSubscription(2, "sub2"); + when(sub1.isEmbedded()).thenReturn(true); + doReturn(true).when(mSubscriptionManager).isActiveSubscriptionId(eq(1)); + doReturn(false).when(mSubscriptionManager).isActiveSubscriptionId(eq(2)); + + when(sub2.isEmbedded()).thenReturn(false); + SubscriptionUtil.setAvailableSubscriptionsForTesting(Arrays.asList(sub1, sub2)); + + mController.displayPreference(mPreferenceScreen); + mController.onResume(); + + // Check that the preferences get created with the correct summaries. + final ArgumentCaptor preferenceCaptor = ArgumentCaptor.forClass( + Preference.class); + verify(mPreferenceScreen, times(2)).addPreference(preferenceCaptor.capture()); + final Preference pref1 = preferenceCaptor.getAllValues().get(0); + final Preference pref2 = preferenceCaptor.getAllValues().get(1); + assertThat(pref1.getSummary()).isEqualTo("Active / Downloaded SIM"); + assertThat(pref2.getSummary()).isEqualTo("Tap to activate sub2"); + + pref2.getOnPreferenceClickListener().onPreferenceClick(pref2); + verify(mSubscriptionManager).setSubscriptionEnabled(eq(2), eq(true)); + } + @Test public void onSubscriptionsChanged_twoSubscriptionsOneChangesName_preferenceUpdated() { final SubscriptionInfo sub1 = createMockSubscription(1, "sub1"); diff --git a/tests/robotests/src/com/android/settings/network/MobileNetworkSummaryControllerTest.java b/tests/robotests/src/com/android/settings/network/MobileNetworkSummaryControllerTest.java index a6238505756..99c9134c77d 100644 --- a/tests/robotests/src/com/android/settings/network/MobileNetworkSummaryControllerTest.java +++ b/tests/robotests/src/com/android/settings/network/MobileNetworkSummaryControllerTest.java @@ -18,6 +18,7 @@ package com.android.settings.network; import static com.google.common.truth.Truth.assertThat; +import static org.mockito.ArgumentMatchers.anyInt; import static org.mockito.ArgumentMatchers.eq; import static org.mockito.ArgumentMatchers.notNull; import static org.mockito.Mockito.atLeastOnce; @@ -64,6 +65,8 @@ public class MobileNetworkSummaryControllerTest { @Mock private TelephonyManager mTelephonyManager; @Mock + private SubscriptionManager mSubscriptionManager; + @Mock private EuiccManager mEuiccManager; @Mock private PreferenceScreen mPreferenceScreen; @@ -79,9 +82,11 @@ public class MobileNetworkSummaryControllerTest { MockitoAnnotations.initMocks(this); mContext = spy(Robolectric.setupActivity(Activity.class)); when(mContext.getSystemService(TelephonyManager.class)).thenReturn(mTelephonyManager); + when(mContext.getSystemService(SubscriptionManager.class)).thenReturn(mSubscriptionManager); when(mContext.getSystemService(EuiccManager.class)).thenReturn(mEuiccManager); when(mContext.getSystemService(UserManager.class)).thenReturn(mUserManager); when(mTelephonyManager.getNetworkCountryIso()).thenReturn(""); + when(mSubscriptionManager.isActiveSubscriptionId(anyInt())).thenReturn(true); when(mEuiccManager.isEnabled()).thenReturn(true); Settings.Global.putInt(mContext.getContentResolver(), Settings.Global.EUICC_PROVISIONED, 1); @@ -159,6 +164,24 @@ public class MobileNetworkSummaryControllerTest { SubscriptionManager.INVALID_SUBSCRIPTION_ID)).isEqualTo(sub1.getSubscriptionId()); } + @Test + public void getSummary_oneInactivePSim_correctSummaryAndClickHandler() { + final SubscriptionInfo sub1 = mock(SubscriptionInfo.class); + when(sub1.getSubscriptionId()).thenReturn(1); + when(sub1.getDisplayName()).thenReturn("sub1"); + SubscriptionUtil.setAvailableSubscriptionsForTesting(Arrays.asList(sub1)); + when(mSubscriptionManager.isActiveSubscriptionId(eq(1))).thenReturn(false); + + mController.displayPreference(mPreferenceScreen); + mController.onResume(); + + assertThat(mController.getSummary()).isEqualTo("Tap to activate sub1"); + + assertThat(mPreference.getFragment()).isNull(); + mPreference.getOnPreferenceClickListener().onPreferenceClick(mPreference); + verify(mSubscriptionManager).setSubscriptionEnabled(eq(sub1.getSubscriptionId()), eq(true)); + } + @Test public void getSummary_twoSubscriptions_correctSummaryAndFragment() { final SubscriptionInfo sub1 = mock(SubscriptionInfo.class); diff --git a/tests/robotests/src/com/android/settings/network/telephony/DisableSimFooterPreferenceControllerTest.java b/tests/robotests/src/com/android/settings/network/telephony/DisableSimFooterPreferenceControllerTest.java new file mode 100644 index 00000000000..a0a4f009832 --- /dev/null +++ b/tests/robotests/src/com/android/settings/network/telephony/DisableSimFooterPreferenceControllerTest.java @@ -0,0 +1,77 @@ +/* + * Copyright (C) 2019 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.settings.network.telephony; + +import static com.google.common.truth.Truth.assertThat; + +import static org.mockito.Mockito.spy; +import static org.mockito.Mockito.when; + +import android.content.Context; +import android.telephony.SubscriptionInfo; + +import com.android.settings.network.SubscriptionUtil; + +import org.junit.Before; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.mockito.Mock; +import org.mockito.MockitoAnnotations; +import org.robolectric.RobolectricTestRunner; +import org.robolectric.RuntimeEnvironment; + +import java.util.Arrays; + +@RunWith(RobolectricTestRunner.class) +public class DisableSimFooterPreferenceControllerTest { + private static final String PREF_KEY = "pref_key"; + private static final int SUB_ID = 111; + + @Mock + private SubscriptionInfo mInfo; + + private Context mContext; + private DisableSimFooterPreferenceController mController; + + @Before + public void setUp() { + MockitoAnnotations.initMocks(this); + mContext = RuntimeEnvironment.application; + when(mInfo.getSubscriptionId()).thenReturn(SUB_ID); + SubscriptionUtil.setAvailableSubscriptionsForTesting(Arrays.asList(mInfo)); + mController = new DisableSimFooterPreferenceController(mContext, PREF_KEY); + } + + @Test + public void isAvailable_noInit_notAvailable() { + assertThat(mController.isAvailable()).isFalse(); + } + + @Test + public void isAvailable_eSIM_notAvailable() { + when(mInfo.isEmbedded()).thenReturn(true); + mController.init(SUB_ID); + assertThat(mController.isAvailable()).isFalse(); + } + + @Test + public void isAvailable_pSIM_available() { + when(mInfo.isEmbedded()).thenReturn(false); + mController.init(SUB_ID); + assertThat(mController.isAvailable()).isTrue(); + } +} diff --git a/tests/robotests/src/com/android/settings/network/telephony/MobileNetworkSwitchControllerTest.java b/tests/robotests/src/com/android/settings/network/telephony/MobileNetworkSwitchControllerTest.java index a10227f5924..86c380e006b 100644 --- a/tests/robotests/src/com/android/settings/network/telephony/MobileNetworkSwitchControllerTest.java +++ b/tests/robotests/src/com/android/settings/network/telephony/MobileNetworkSwitchControllerTest.java @@ -79,13 +79,14 @@ public class MobileNetworkSwitchControllerTest { mLifecycleOwner = () -> mLifecycle; mLifecycle = new Lifecycle(mLifecycleOwner); + when(mSubscription.isEmbedded()).thenReturn(true); when(mSubscription.getSubscriptionId()).thenReturn(mSubId); // Most tests want to have 2 available subscriptions so that the switch bar will show. - SubscriptionInfo sub2 = mock(SubscriptionInfo.class); + final SubscriptionInfo sub2 = mock(SubscriptionInfo.class); when(sub2.getSubscriptionId()).thenReturn(456); SubscriptionUtil.setAvailableSubscriptionsForTesting(Arrays.asList(mSubscription, sub2)); - String key = "prefKey"; + final String key = "prefKey"; mController = new MobileNetworkSwitchController(mContext, key); mController.init(mLifecycle, mSubscription.getSubscriptionId()); @@ -100,11 +101,18 @@ public class MobileNetworkSwitchControllerTest { } @Test - public void displayPreference_oneEnabledSubscription_switchBarHidden() { + public void isAvailable_pSIM_isNotAvailable() { + when(mSubscription.isEmbedded()).thenReturn(false); + mController.displayPreference(mScreen); + assertThat(mSwitchBar.isShowing()).isFalse(); + } + + @Test + public void displayPreference_oneEnabledSubscription_switchBarNotHidden() { doReturn(true).when(mSubscriptionManager).isSubscriptionEnabled(mSubId); SubscriptionUtil.setAvailableSubscriptionsForTesting(Arrays.asList(mSubscription)); mController.displayPreference(mScreen); - assertThat(mSwitchBar.isShowing()).isFalse(); + assertThat(mSwitchBar.isShowing()).isTrue(); } @Test