From 363535192ddddadf5036936058ab523e4f037ad2 Mon Sep 17 00:00:00 2001 From: Rafael Higuera Silva Date: Wed, 13 Mar 2024 23:18:47 +0000 Subject: [PATCH] Add new warning dialogue when user is Resetting mobile network settings. If the user is reseting mobile network settings and have all these conditions: - No Wi-fi - Has check to delete all eSIMs - Has a least one RAC sim carrier Then show the warning dialogue. Test: make, manually test, atest SubSettingLauncherTest, atest ResetNetworkTest, atest SubscriptionUtilTest Bug: 328649510 Merged-In: I47d9b868b649b259d5e4008ec742317d2cb7cf51 Change-Id: I47d9b868b649b259d5e4008ec742317d2cb7cf51 (cherry picked from commit 147cc19b532fd52f918afd644140327d3d3d8904) --- src/com/android/settings/ResetNetwork.java | 26 +++++++++---- .../settings/core/SubSettingLauncher.java | 36 ++++++++++++++++- .../network/EraseEuiccDataController.java | 3 +- .../settings/network/SubscriptionUtil.java | 19 +++++++++ .../EuiccRacConnectivityDialogActivity.java | 37 ++++++++++++++++-- .../android/settings/ResetNetworkTest.java | 19 +++++++++ .../settings/core/SubSettingLauncherTest.java | 39 ++++++++++++++++++- .../network/SubscriptionUtilTest.java | 33 ++++++++++++++++ 8 files changed, 195 insertions(+), 17 deletions(-) diff --git a/src/com/android/settings/ResetNetwork.java b/src/com/android/settings/ResetNetwork.java index c33a4f826a0..05c85986d83 100644 --- a/src/com/android/settings/ResetNetwork.java +++ b/src/com/android/settings/ResetNetwork.java @@ -49,6 +49,7 @@ import com.android.settings.core.InstrumentedFragment; import com.android.settings.core.SubSettingLauncher; import com.android.settings.network.ResetNetworkRestrictionViewBuilder; import com.android.settings.network.SubscriptionUtil; +import com.android.settings.network.telephony.EuiccRacConnectivityDialogActivity; import com.android.settings.password.ChooseLockSettingsHelper; import com.android.settings.password.ConfirmLockPattern; import com.android.settingslib.development.DevelopmentSettingsEnabler; @@ -121,6 +122,8 @@ public class ResetNetwork extends InstrumentedFragment { @VisibleForTesting void showFinalConfirmation() { Bundle args = new Bundle(); + Context context = getContext(); + boolean resetSims = false; // TODO(b/317276437) Simplify the logic once flag is released int resetOptions = ResetNetworkRequest.RESET_CONNECTIVITY_MANAGER @@ -142,18 +145,25 @@ public class ResetNetwork extends InstrumentedFragment { } } if (mEsimContainer.getVisibility() == View.VISIBLE && mEsimCheckbox.isChecked()) { - request.setResetEsim(getContext().getPackageName()) - .writeIntoBundle(args); + resetSims = true; + request.setResetEsim(context.getPackageName()).writeIntoBundle(args); } else { request.writeIntoBundle(args); } - new SubSettingLauncher(getContext()) - .setDestination(ResetNetworkConfirm.class.getName()) - .setArguments(args) - .setTitleRes(R.string.reset_mobile_network_settings_confirm_title) - .setSourceMetricsCategory(getMetricsCategory()) - .launch(); + SubSettingLauncher launcher = + new SubSettingLauncher(context) + .setDestination(ResetNetworkConfirm.class.getName()) + .setArguments(args) + .setTitleRes(R.string.reset_mobile_network_settings_confirm_title) + .setSourceMetricsCategory(getMetricsCategory()); + + if (resetSims && SubscriptionUtil.shouldShowRacDialog(context)) { + context.startActivity( + EuiccRacConnectivityDialogActivity.getIntent(context, launcher.toIntent())); + } else { + launcher.launch(); + } } /** diff --git a/src/com/android/settings/core/SubSettingLauncher.java b/src/com/android/settings/core/SubSettingLauncher.java index e8c42197607..2f1f7d298e6 100644 --- a/src/com/android/settings/core/SubSettingLauncher.java +++ b/src/com/android/settings/core/SubSettingLauncher.java @@ -17,12 +17,14 @@ package com.android.settings.core; import android.annotation.StringRes; +import android.content.ComponentName; import android.content.Context; import android.content.Intent; import android.os.Bundle; import android.os.UserHandle; import android.text.TextUtils; +import androidx.annotation.NonNull; import androidx.annotation.VisibleForTesting; import androidx.fragment.app.Fragment; @@ -129,14 +131,22 @@ public class SubSettingLauncher { } public void launch() { + launchWithIntent(toIntent()); + } + + /** + * Launch sub settings activity with an intent. + * + * @param intent the settings intent we want to launch + */ + public void launchWithIntent(@NonNull Intent intent) { + verifyIntent(intent); if (mLaunched) { throw new IllegalStateException( "This launcher has already been executed. Do not reuse"); } mLaunched = true; - final Intent intent = toIntent(); - boolean launchAsUser = mLaunchRequest.mUserHandle != null && mLaunchRequest.mUserHandle.getIdentifier() != UserHandle.myUserId(); boolean launchForResult = mLaunchRequest.mResultListener != null; @@ -152,6 +162,28 @@ public class SubSettingLauncher { } } + /** + * Verify intent is correctly constructed. + * + * @param intent the intent to verify + */ + @VisibleForTesting + public void verifyIntent(@NonNull Intent intent) { + String className = SubSettings.class.getName(); + ComponentName componentName = intent.getComponent(); + String destinationName = intent.getStringExtra(SettingsActivity.EXTRA_SHOW_FRAGMENT); + int sourceMetricsCategory = + intent.getIntExtra(MetricsFeatureProvider.EXTRA_SOURCE_METRICS_CATEGORY, -1); + + if (componentName != null && !TextUtils.equals(className, componentName.getClassName())) { + throw new IllegalArgumentException(String.format("Class must be: %s", className)); + } else if (TextUtils.isEmpty(destinationName)) { + throw new IllegalArgumentException("Destination fragment must be set"); + } else if (sourceMetricsCategory < 0) { + throw new IllegalArgumentException("Source metrics category must be set"); + } + } + public Intent toIntent() { final Intent intent = new Intent(Intent.ACTION_MAIN); copyExtras(intent); diff --git a/src/com/android/settings/network/EraseEuiccDataController.java b/src/com/android/settings/network/EraseEuiccDataController.java index 782ab7d8158..4e89da0a292 100644 --- a/src/com/android/settings/network/EraseEuiccDataController.java +++ b/src/com/android/settings/network/EraseEuiccDataController.java @@ -50,8 +50,7 @@ public class EraseEuiccDataController extends BasePreferenceController { if (!TextUtils.equals(preference.getKey(), getPreferenceKey())) { return false; } - if (SubscriptionUtil.hasSubscriptionWithRacCarrier(mContext) - && !SubscriptionUtil.isConnectedToWifi(mContext)) { + if (SubscriptionUtil.shouldShowRacDialog(mContext)) { EuiccRacConnectivityDialogFragment.show(mHostFragment); } else { EraseEuiccDataDialogFragment.show(mHostFragment); diff --git a/src/com/android/settings/network/SubscriptionUtil.java b/src/com/android/settings/network/SubscriptionUtil.java index fbe6c1f649e..3632ca323c9 100644 --- a/src/com/android/settings/network/SubscriptionUtil.java +++ b/src/com/android/settings/network/SubscriptionUtil.java @@ -80,6 +80,7 @@ public class SubscriptionUtil { private static List sAvailableResultsForTesting; private static List sActiveResultsForTesting; + @Nullable private static Boolean sEnableRacDialogForTesting; @VisibleForTesting public static void setAvailableSubscriptionsForTesting(List results) { @@ -91,6 +92,11 @@ public class SubscriptionUtil { sActiveResultsForTesting = results; } + @VisibleForTesting + public static void setEnableRacDialogForTesting(boolean enableRacDialog) { + sEnableRacDialogForTesting = enableRacDialog; + } + public static List getActiveSubscriptions(SubscriptionManager manager) { //TODO (b/315499317) : Refactor the subscription utils. @@ -908,6 +914,19 @@ public class SubscriptionUtil { return Arrays.stream(carriersThatUseRAC).anyMatch(cid -> cid == carrierId); } + /** + * Check if warning dialog should be presented when erasing all eSIMS. + * + * @param context Context to check if any sim carrier use RAC and device Wi-Fi connection. + * @return {@code true} if dialog should be presented to the user. + */ + public static boolean shouldShowRacDialog(@NonNull Context context) { + if (sEnableRacDialogForTesting != null) { + return sEnableRacDialogForTesting; + } + return !isConnectedToWifi(context) && hasSubscriptionWithRacCarrier(context); + } + /** * Retrieves NetworkCapabilities for the active network. * diff --git a/src/com/android/settings/network/telephony/EuiccRacConnectivityDialogActivity.java b/src/com/android/settings/network/telephony/EuiccRacConnectivityDialogActivity.java index cb4ab18dc67..d439d4f6c27 100644 --- a/src/com/android/settings/network/telephony/EuiccRacConnectivityDialogActivity.java +++ b/src/com/android/settings/network/telephony/EuiccRacConnectivityDialogActivity.java @@ -23,21 +23,28 @@ import android.telephony.SubscriptionManager; import android.util.Log; import androidx.annotation.NonNull; +import androidx.annotation.Nullable; +import androidx.fragment.app.FragmentActivity; import com.android.settings.R; +import com.android.settings.core.SubSettingLauncher; /** This dialog activity advise the user to have connectivity if the eSIM uses a RAC. */ -public class EuiccRacConnectivityDialogActivity extends SubscriptionActionDialogActivity +public class EuiccRacConnectivityDialogActivity extends FragmentActivity implements WarningDialogFragment.OnConfirmListener { private static final String TAG = "EuiccRacConnectivityDialogActivity"; // Dialog tags private static final int DIALOG_TAG_ERASE_ANYWAY_CONFIRMATION = 1; + private static final String ARG_SUB_ID = "sub_id"; + private static final String ARG_RESET_MOBILE_NETWORK_ID = "reset_mobile_netword_id"; private int mSubId; + @Nullable + private Intent mResetMobileNetworkIntent; /** - * Returns an intent of EuiccRacConnectivityDialogActivity. + * Returns an intent of EuiccRacConnectivityDialogActivity for Settings: erase eSIM. * * @param context The context used to start the EuiccRacConnectivityDialogActivity. * @param subId The subscription ID of the subscription needs to be deleted. If the subscription @@ -50,12 +57,29 @@ public class EuiccRacConnectivityDialogActivity extends SubscriptionActionDialog return intent; } + /** + * Returns an intent of EuiccRacConnectivityDialogActivity for Reset: Mobile network settings. + * + * @param context The context used to start the EuiccRacConnectivityDialogActivity. + * @param resetMobileNetworkIntent The intent that will continue the reset of mobile network + * settings. + */ + @NonNull + public static Intent getIntent(@NonNull Context context, + @NonNull Intent resetMobileNetworkIntent) { + Intent intent = new Intent(context, EuiccRacConnectivityDialogActivity.class); + intent.putExtra(ARG_RESET_MOBILE_NETWORK_ID, resetMobileNetworkIntent); + return intent; + } + @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); Intent intent = getIntent(); mSubId = intent.getIntExtra(ARG_SUB_ID, SubscriptionManager.INVALID_SUBSCRIPTION_ID); + mResetMobileNetworkIntent = + intent.getParcelableExtra(ARG_RESET_MOBILE_NETWORK_ID, Intent.class); if (savedInstanceState == null) { showConnectivityWarningDialog(); @@ -72,8 +96,13 @@ public class EuiccRacConnectivityDialogActivity extends SubscriptionActionDialog switch (tag) { case DIALOG_TAG_ERASE_ANYWAY_CONFIRMATION: finish(); - Log.i(TAG, "Show dialogue activity that handles deleting eSIM profiles"); - startActivity(DeleteEuiccSubscriptionDialogActivity.getIntent(this, mSubId)); + if (mResetMobileNetworkIntent != null) { + Log.i(TAG, "Show fragment activity that handles mobile network settings reset"); + new SubSettingLauncher(this).launchWithIntent(mResetMobileNetworkIntent); + } else { + Log.i(TAG, "Show dialogue activity that handles deleting eSIM profiles"); + startActivity(DeleteEuiccSubscriptionDialogActivity.getIntent(this, mSubId)); + } break; default: Log.e(TAG, "Unrecognized confirmation dialog tag: " + tag); diff --git a/tests/robotests/src/com/android/settings/ResetNetworkTest.java b/tests/robotests/src/com/android/settings/ResetNetworkTest.java index 0c2c7e8a5f7..db724c49ed8 100644 --- a/tests/robotests/src/com/android/settings/ResetNetworkTest.java +++ b/tests/robotests/src/com/android/settings/ResetNetworkTest.java @@ -27,6 +27,9 @@ import android.content.Intent; import android.view.View; import android.widget.CheckBox; +import com.android.settings.network.SubscriptionUtil; +import com.android.settings.network.telephony.EuiccRacConnectivityDialogActivity; + import org.junit.Before; import org.junit.Ignore; import org.junit.Test; @@ -51,6 +54,7 @@ public class ResetNetworkTest { @Test @Ignore public void showFinalConfirmation_checkboxVisible_eraseEsimChecked() { + SubscriptionUtil.setEnableRacDialogForTesting(true); mResetNetwork.mEsimContainer.setVisibility(View.VISIBLE); mResetNetwork.mEsimCheckbox.setChecked(true); @@ -61,6 +65,21 @@ public class ResetNetworkTest { .isNotNull(); } + @Test + public void showFinalConfirmation_checkboxVisible_eraseEsimChecked_showRacWarningDialog() { + SubscriptionUtil.setEnableRacDialogForTesting(true); + mResetNetwork.mEsimContainer.setVisibility(View.VISIBLE); + mResetNetwork.mEsimCheckbox.setChecked(true); + + mResetNetwork.showFinalConfirmation(); + + Intent intent = shadowOf(mActivity).getNextStartedActivity(); + + assertThat(intent).isNotNull(); + assertThat(intent.getComponent().getClassName()).isEqualTo( + EuiccRacConnectivityDialogActivity.class.getName()); + } + @Test public void showFinalConfirmation_checkboxVisible_eraseEsimUnchecked() { mResetNetwork.mEsimContainer.setVisibility(View.VISIBLE); diff --git a/tests/robotests/src/com/android/settings/core/SubSettingLauncherTest.java b/tests/robotests/src/com/android/settings/core/SubSettingLauncherTest.java index bfc8ea62ad4..e7051d26fc3 100644 --- a/tests/robotests/src/com/android/settings/core/SubSettingLauncherTest.java +++ b/tests/robotests/src/com/android/settings/core/SubSettingLauncherTest.java @@ -67,7 +67,7 @@ public class SubSettingLauncherTest { } @Test(expected = IllegalStateException.class) - public void cannotReuseLauncher() { + public void cannotReuseLauncher_launchMethod() { final SubSettingLauncher launcher = spy(new SubSettingLauncher(mContext)) .setDestination(SubSettingLauncherTest.class.getName()) .setSourceMetricsCategory(123); @@ -76,6 +76,43 @@ public class SubSettingLauncherTest { launcher.launch(); } + @Test(expected = IllegalArgumentException.class) + public void verifyIntent_noDestination() { + final SubSettingLauncher launcher = + spy(new SubSettingLauncher(mContext)) + .setSourceMetricsCategory(123); + doNothing().when(launcher).launch(any(Intent.class)); + launcher.launchWithIntent(launcher.toIntent()); + } + + @Test(expected = IllegalArgumentException.class) + public void verifyIntent_noMetricsCategory() { + final SubSettingLauncher launcher = spy(new SubSettingLauncher(mContext)) + .setDestination(SubSettingLauncherTest.class.getName()); + doNothing().when(launcher).launch(any(Intent.class)); + launcher.launchWithIntent(launcher.toIntent()); + } + + @Test(expected = IllegalArgumentException.class) + public void verifyIntent_notTheCorrectClass() { + final SubSettingLauncher launcher = spy(new SubSettingLauncher(mContext)) + .setDestination(SubSettingLauncherTest.class.getName()) + .setSourceMetricsCategory(123); + doNothing().when(launcher).launch(any(Intent.class)); + launcher.launchWithIntent(new Intent(Intent.ACTION_MAIN)); + } + + @Test(expected = IllegalStateException.class) + public void cannotReuseLauncher_launchAndLaunchWithIntentMethod() { + final SubSettingLauncher launcher = + spy(new SubSettingLauncher(mContext)) + .setDestination(SubSettingLauncherTest.class.getName()) + .setSourceMetricsCategory(123); + doNothing().when(launcher).launch(any(Intent.class)); + launcher.launchWithIntent(launcher.toIntent()); + launcher.launch(); + } + @Test(expected = IllegalArgumentException.class) public void launch_noSourceMetricsCategory_shouldCrash() { final SubSettingLauncher launcher = spy(new SubSettingLauncher(mContext)) diff --git a/tests/unit/src/com/android/settings/network/SubscriptionUtilTest.java b/tests/unit/src/com/android/settings/network/SubscriptionUtilTest.java index 6c946e55c1d..6df281a5db2 100644 --- a/tests/unit/src/com/android/settings/network/SubscriptionUtilTest.java +++ b/tests/unit/src/com/android/settings/network/SubscriptionUtilTest.java @@ -649,6 +649,39 @@ public class SubscriptionUtilTest { assertFalse(SubscriptionUtil.isConnectedToWifi(mContext)); } + @Test + public void hasSubscriptionWithRacCarrier_hasNoWifi_showRacDialog_returnTrue() { + when(mResources.getIntArray(anyInt())).thenReturn(CARRIERS_THAT_USE_RAC); + final SubscriptionInfo info = mock(SubscriptionInfo.class); + when(info.getCarrierId()).thenReturn(RAC_CARRIER_ID); + when(mSubMgr.getAvailableSubscriptionInfoList()).thenReturn(Arrays.asList(info)); + addNetworkTransportType(NetworkCapabilities.TRANSPORT_BLUETOOTH); + + assertTrue(SubscriptionUtil.shouldShowRacDialog(mContext)); + } + + @Test + public void hasSubscriptionWithRacCarrier_hasWifi_showRacDialog_returnFalse() { + when(mResources.getIntArray(anyInt())).thenReturn(CARRIERS_THAT_USE_RAC); + final SubscriptionInfo info = mock(SubscriptionInfo.class); + when(info.getCarrierId()).thenReturn(RAC_CARRIER_ID); + when(mSubMgr.getAvailableSubscriptionInfoList()).thenReturn(Arrays.asList(info)); + addNetworkTransportType(NetworkCapabilities.TRANSPORT_WIFI); + + assertFalse(SubscriptionUtil.shouldShowRacDialog(mContext)); + } + + @Test + public void hasNoSubscriptionWithRacCarrier_hasNoWifi_showRacDialog_returnFalse() { + when(mResources.getIntArray(anyInt())).thenReturn(CARRIERS_THAT_USE_RAC); + final SubscriptionInfo info = mock(SubscriptionInfo.class); + when(info.getCarrierId()).thenReturn(NO_RAC_CARRIER_ID); + when(mSubMgr.getAvailableSubscriptionInfoList()).thenReturn(Arrays.asList(info)); + addNetworkTransportType(NetworkCapabilities.TRANSPORT_WIFI); + + assertFalse(SubscriptionUtil.shouldShowRacDialog(mContext)); + } + private void addNetworkTransportType(int networkType) { mNetworkCapabilities = new NetworkCapabilities.Builder().addTransportType(networkType).build();