diff --git a/src/com/android/settings/ResetNetwork.java b/src/com/android/settings/ResetNetwork.java index c91ef5cdb93..c1e3494d621 100644 --- a/src/com/android/settings/ResetNetwork.java +++ b/src/com/android/settings/ResetNetwork.java @@ -52,6 +52,7 @@ 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.settings.system.reset.ResetNetworkConfirm; import com.android.settingslib.development.DevelopmentSettingsEnabler; import java.util.ArrayList; diff --git a/src/com/android/settings/ResetNetworkConfirm.java b/src/com/android/settings/ResetNetworkConfirm.java deleted file mode 100644 index c707b96a328..00000000000 --- a/src/com/android/settings/ResetNetworkConfirm.java +++ /dev/null @@ -1,247 +0,0 @@ -/* - * Copyright (C) 2015 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; - -import android.app.Activity; -import android.app.ProgressDialog; -import android.app.settings.SettingsEnums; -import android.content.Context; -import android.os.AsyncTask; -import android.os.Bundle; -import android.os.Looper; -import android.telephony.SubscriptionManager; -import android.telephony.SubscriptionManager.OnSubscriptionsChangedListener; -import android.util.Log; -import android.view.LayoutInflater; -import android.view.View; -import android.view.ViewGroup; -import android.widget.Button; -import android.widget.TextView; -import android.widget.Toast; - -import androidx.annotation.VisibleForTesting; -import androidx.appcompat.app.AlertDialog; - -import com.android.settings.core.InstrumentedFragment; -import com.android.settings.network.ResetNetworkOperationBuilder; -import com.android.settings.network.ResetNetworkRestrictionViewBuilder; - -import java.util.concurrent.atomic.AtomicBoolean; - -/** - * Confirm and execute a reset of the network settings to a clean "just out of the box" - * state. Multiple confirmations are required: first, a general "are you sure - * you want to do this?" prompt, followed by a keyguard pattern trace if the user - * has defined one, followed by a final strongly-worded "THIS WILL RESET EVERYTHING" - * prompt. If at any time the phone is allowed to go to sleep, is - * locked, et cetera, then the confirmation sequence is abandoned. - * - * This is the confirmation screen. - */ -public class ResetNetworkConfirm extends InstrumentedFragment { - private static final String TAG = "ResetNetworkConfirm"; - - @VisibleForTesting View mContentView; - @VisibleForTesting ResetNetworkTask mResetNetworkTask; - @VisibleForTesting Activity mActivity; - @VisibleForTesting ResetNetworkRequest mResetNetworkRequest; - private ProgressDialog mProgressDialog; - private AlertDialog mAlertDialog; - @VisibleForTesting ResetSubscriptionContract mResetSubscriptionContract; - private OnSubscriptionsChangedListener mSubscriptionsChangedListener; - - /** - * Async task used to do all reset task. If error happens during - * erasing eSIM profiles or timeout, an error msg is shown. - */ - private class ResetNetworkTask extends AsyncTask { - private static final String TAG = "ResetNetworkTask"; - - private final Context mContext; - - ResetNetworkTask(Context context) { - mContext = context; - } - - @Override - protected Boolean doInBackground(Void... params) { - final AtomicBoolean resetEsimSuccess = new AtomicBoolean(true); - - String resetEsimPackageName = mResetNetworkRequest.getResetEsimPackageName(); - ResetNetworkOperationBuilder builder = mResetNetworkRequest - .toResetNetworkOperationBuilder(mContext, Looper.getMainLooper()); - if (resetEsimPackageName != null) { - // Override reset eSIM option for the result of reset operation - builder = builder.resetEsim(resetEsimPackageName, - success -> { resetEsimSuccess.set(success); } - ); - } - builder.build().run(); - - boolean isResetSucceed = resetEsimSuccess.get(); - Log.d(TAG, "network factoryReset complete. succeeded: " - + String.valueOf(isResetSucceed)); - return isResetSucceed; - } - - @Override - protected void onPostExecute(Boolean succeeded) { - if (mProgressDialog != null && mProgressDialog.isShowing()) { - mProgressDialog.dismiss(); - } - - if (succeeded) { - Toast.makeText(mContext, R.string.reset_network_complete_toast, Toast.LENGTH_SHORT) - .show(); - } else { - mAlertDialog = new AlertDialog.Builder(mContext) - .setTitle(R.string.reset_esim_error_title) - .setMessage(R.string.reset_esim_error_msg) - .setPositiveButton(android.R.string.ok, null /* listener */) - .show(); - } - } - } - - /** - * The user has gone through the multiple confirmation, so now we go ahead - * and reset the network settings to its factory-default state. - */ - @VisibleForTesting - Button.OnClickListener mFinalClickListener = new Button.OnClickListener() { - - @Override - public void onClick(View v) { - if (Utils.isMonkeyRunning()) { - return; - } - - // abandon execution if subscription no longer active - Integer subId = mResetSubscriptionContract.getAnyMissingSubscriptionId(); - if (subId != null) { - Log.w(TAG, "subId " + subId + " no longer active"); - getActivity().onBackPressed(); - return; - } - - // Should dismiss the progress dialog firstly if it is showing - // Or not the progress dialog maybe not dismissed in fast clicking. - if (mProgressDialog != null && mProgressDialog.isShowing()) { - mProgressDialog.dismiss(); - } - - mProgressDialog = getProgressDialog(mActivity); - mProgressDialog.show(); - - mResetNetworkTask = new ResetNetworkTask(mActivity); - mResetNetworkTask.execute(); - } - }; - - private ProgressDialog getProgressDialog(Context context) { - final ProgressDialog progressDialog = new ProgressDialog(context); - progressDialog.setIndeterminate(true); - progressDialog.setCancelable(false); - progressDialog.setMessage( - context.getString(R.string.main_clear_progress_text)); - return progressDialog; - } - - /** - * Configure the UI for the final confirmation interaction - */ - private void establishFinalConfirmationState() { - mContentView.findViewById(R.id.execute_reset_network) - .setOnClickListener(mFinalClickListener); - } - - @VisibleForTesting - void setSubtitle() { - if (mResetNetworkRequest.getResetEsimPackageName() != null) { - ((TextView) mContentView.findViewById(R.id.reset_network_confirm)) - .setText(R.string.reset_network_final_desc_esim); - } - } - - @Override - public View onCreateView(LayoutInflater inflater, ViewGroup container, - Bundle savedInstanceState) { - View view = (new ResetNetworkRestrictionViewBuilder(mActivity)).build(); - if (view != null) { - mResetSubscriptionContract.close(); - Log.w(TAG, "Access deny."); - return view; - } - mContentView = inflater.inflate(R.layout.reset_network_confirm, null); - establishFinalConfirmationState(); - setSubtitle(); - return mContentView; - } - - @Override - public void onCreate(Bundle savedInstanceState) { - super.onCreate(savedInstanceState); - - Bundle args = getArguments(); - if (args == null) { - args = savedInstanceState; - } - mResetNetworkRequest = new ResetNetworkRequest(args); - - mActivity = getActivity(); - - mResetSubscriptionContract = new ResetSubscriptionContract(getContext(), - mResetNetworkRequest) { - @Override - public void onSubscriptionInactive(int subscriptionId) { - // close UI if subscription no longer active - Log.w(TAG, "subId " + subscriptionId + " no longer active."); - getActivity().onBackPressed(); - } - }; - } - - @Override - public void onSaveInstanceState(Bundle outState) { - super.onSaveInstanceState(outState); - mResetNetworkRequest.writeIntoBundle(outState); - } - - @Override - public void onDestroy() { - if (mResetNetworkTask != null) { - mResetNetworkTask.cancel(true /* mayInterruptIfRunning */); - mResetNetworkTask = null; - } - if (mResetSubscriptionContract != null) { - mResetSubscriptionContract.close(); - mResetSubscriptionContract = null; - } - if (mProgressDialog != null) { - mProgressDialog.dismiss(); - } - if (mAlertDialog != null) { - mAlertDialog.dismiss(); - } - super.onDestroy(); - } - - @Override - public int getMetricsCategory() { - return SettingsEnums.RESET_NETWORK_CONFIRM; - } -} diff --git a/src/com/android/settings/ResetSubscriptionContract.java b/src/com/android/settings/ResetSubscriptionContract.java deleted file mode 100644 index 528a16def5a..00000000000 --- a/src/com/android/settings/ResetSubscriptionContract.java +++ /dev/null @@ -1,157 +0,0 @@ -/* - * Copyright (C) 2022 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; - -import android.content.Context; -import android.telephony.SubscriptionManager; -import android.telephony.SubscriptionManager.OnSubscriptionsChangedListener; -import android.util.Log; - -import androidx.annotation.VisibleForTesting; - -import java.util.concurrent.ExecutorService; -import java.util.concurrent.Executors; -import java.util.concurrent.atomic.AtomicBoolean; -import java.util.stream.IntStream; - -/** - * A Class monitoring the availability of subscription IDs provided within reset request. - * - * This is to detect the situation when user changing SIM card during the presenting of - * confirmation UI. - */ -public class ResetSubscriptionContract implements AutoCloseable { - private static final String TAG = "ResetSubscriptionContract"; - - private final Context mContext; - private ExecutorService mExecutorService; - private final int [] mResetSubscriptionIds; - @VisibleForTesting - protected OnSubscriptionsChangedListener mSubscriptionsChangedListener; - private AtomicBoolean mSubscriptionsUpdateNotify = new AtomicBoolean(); - - /** - * Constructor - * @param context Context - * @param resetRequest the request object for perform network reset operation. - */ - public ResetSubscriptionContract(Context context, ResetNetworkRequest resetRequest) { - mContext = context; - // Only keeps specific subscription ID required to perform reset operation - IntStream subIdStream = IntStream.of( - resetRequest.getResetTelephonyAndNetworkPolicyManager(), - resetRequest.getResetApnSubId(), resetRequest.getResetImsSubId()); - mResetSubscriptionIds = subIdStream.sorted().distinct() - .filter(id -> SubscriptionManager.isUsableSubscriptionId(id)) - .toArray(); - - if (mResetSubscriptionIds.length <= 0) { - return; - } - - // Monitoring callback through background thread - mExecutorService = Executors.newSingleThreadExecutor(); - startMonitorSubscriptionChange(); - } - - /** - * A method for detecting if there's any subscription under monitor no longer active. - * @return subscription ID which is no longer active. - */ - public Integer getAnyMissingSubscriptionId() { - if (mResetSubscriptionIds.length <= 0) { - return null; - } - SubscriptionManager mgr = getSubscriptionManager(); - if (mgr == null) { - Log.w(TAG, "Fail to access subscription manager"); - return mResetSubscriptionIds[0]; - } - for (int idx = 0; idx < mResetSubscriptionIds.length; idx++) { - int subId = mResetSubscriptionIds[idx]; - if (mgr.getActiveSubscriptionInfo(subId) == null) { - Log.w(TAG, "SubId " + subId + " no longer active."); - return subId; - } - } - return null; - } - - /** - * Async callback when detecting if there's any subscription under monitor no longer active. - * @param subscriptionId subscription ID which is no longer active. - */ - public void onSubscriptionInactive(int subscriptionId) {} - - @VisibleForTesting - protected SubscriptionManager getSubscriptionManager() { - return mContext.getSystemService(SubscriptionManager.class); - } - - @VisibleForTesting - protected OnSubscriptionsChangedListener getChangeListener() { - return new OnSubscriptionsChangedListener() { - @Override - public void onSubscriptionsChanged() { - /** - * Reducing the processing time on main UI thread through a flag. - * Once flag get into false, which means latest callback has been - * processed. - */ - mSubscriptionsUpdateNotify.set(true); - - // Back to main UI thread - mContext.getMainExecutor().execute(() -> { - // Remove notifications and perform checking. - if (mSubscriptionsUpdateNotify.getAndSet(false)) { - Integer subId = getAnyMissingSubscriptionId(); - if (subId != null) { - onSubscriptionInactive(subId); - } - } - }); - } - }; - } - - private void startMonitorSubscriptionChange() { - SubscriptionManager mgr = getSubscriptionManager(); - if (mgr == null) { - return; - } - // update monitor listener - mSubscriptionsChangedListener = getChangeListener(); - - mgr.addOnSubscriptionsChangedListener( - mExecutorService, mSubscriptionsChangedListener); - } - - // Implementation of AutoCloseable - public void close() { - if (mExecutorService == null) { - return; - } - // Stop monitoring subscription change - SubscriptionManager mgr = getSubscriptionManager(); - if (mgr != null) { - mgr.removeOnSubscriptionsChangedListener(mSubscriptionsChangedListener); - } - // Release Executor - mExecutorService.shutdownNow(); - mExecutorService = null; - } -} diff --git a/src/com/android/settings/network/ResetNetworkOperationBuilder.java b/src/com/android/settings/network/ResetNetworkOperationBuilder.java index 47c06d4480d..dfcca520255 100644 --- a/src/com/android/settings/network/ResetNetworkOperationBuilder.java +++ b/src/com/android/settings/network/ResetNetworkOperationBuilder.java @@ -65,6 +65,8 @@ public class ResetNetworkOperationBuilder { private Context mContext; private List mResetSequence = new ArrayList(); + @Nullable + private Consumer mResetEsimResultCallback = null; /** * Constructor of builder. @@ -129,31 +131,32 @@ public class ResetNetworkOperationBuilder { } /** - * Append a step of resetting E-SIM. - * @param callerPackage package name of caller + * Append a result callback of resetting E-SIM. + * @param resultCallback a callback dealing with result of resetting eSIM * @return this */ - public ResetNetworkOperationBuilder resetEsim(String callerPackage) { - resetEsim(callerPackage, null); + public ResetNetworkOperationBuilder resetEsimResultCallback(Consumer resultCallback) { + mResetEsimResultCallback = resultCallback; return this; } /** * Append a step of resetting E-SIM. * @param callerPackage package name of caller - * @param resultCallback a Consumer dealing with result of resetting eSIM * @return this */ - public ResetNetworkOperationBuilder resetEsim(String callerPackage, - Consumer resultCallback) { + public ResetNetworkOperationBuilder resetEsim(String callerPackage) { Runnable runnable = () -> { long startTime = SystemClock.elapsedRealtime(); - if (!DRY_RUN) { - Boolean wipped = RecoverySystem.wipeEuiccData(mContext, callerPackage); - if (resultCallback != null) { - resultCallback.accept(wipped); - } + boolean wipped; + if (DRY_RUN) { + wipped = true; + } else { + wipped = RecoverySystem.wipeEuiccData(mContext, callerPackage); + } + if (mResetEsimResultCallback != null) { + mResetEsimResultCallback.accept(wipped); } long endTime = SystemClock.elapsedRealtime(); diff --git a/src/com/android/settings/system/reset/ResetNetworkConfirm.kt b/src/com/android/settings/system/reset/ResetNetworkConfirm.kt new file mode 100644 index 00000000000..34b9909e55e --- /dev/null +++ b/src/com/android/settings/system/reset/ResetNetworkConfirm.kt @@ -0,0 +1,217 @@ +/* + * Copyright (C) 2024 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.system.reset + +import android.app.ProgressDialog +import android.app.settings.SettingsEnums +import android.os.Bundle +import android.os.Looper +import android.telephony.SubscriptionManager +import android.util.Log +import android.view.LayoutInflater +import android.view.View +import android.view.ViewGroup +import android.widget.TextView +import android.widget.Toast +import androidx.annotation.VisibleForTesting +import androidx.appcompat.app.AlertDialog +import androidx.lifecycle.lifecycleScope +import com.android.settings.R +import com.android.settings.ResetNetworkRequest +import com.android.settings.Utils +import com.android.settings.core.InstrumentedFragment +import com.android.settings.network.ResetNetworkRestrictionViewBuilder +import com.android.settings.network.telephony.SubscriptionRepository +import com.android.settingslib.spa.framework.util.collectLatestWithLifecycle +import kotlinx.coroutines.Dispatchers +import kotlinx.coroutines.flow.Flow +import kotlinx.coroutines.flow.conflate +import kotlinx.coroutines.flow.emptyFlow +import kotlinx.coroutines.flow.flowOn +import kotlinx.coroutines.flow.mapNotNull +import kotlinx.coroutines.launch +import kotlinx.coroutines.withContext + +/** + * Confirm and execute a reset of the network settings to a clean "just out of the box" state. + * Multiple confirmations are required: first, a general "are you sure you want to do this?" prompt, + * followed by a keyguard pattern trace if the user has defined one, followed by a final + * strongly-worded "THIS WILL RESET EVERYTHING" prompt. If at any time the phone is allowed to go to + * sleep, is locked, et cetera, then the confirmation sequence is abandoned. + * + * This is the confirmation screen. + */ +class ResetNetworkConfirm : InstrumentedFragment() { + @VisibleForTesting lateinit var resetNetworkRequest: ResetNetworkRequest + private var progressDialog: ProgressDialog? = null + private var alertDialog: AlertDialog? = null + private var resetStarted = false + + override fun onCreate(savedInstanceState: Bundle?) { + super.onCreate(savedInstanceState) + + Log.d(TAG, "onCreate: $arguments") + resetNetworkRequest = ResetNetworkRequest(arguments) + } + + override fun onCreateView( + inflater: LayoutInflater, + container: ViewGroup?, + savedInstanceState: Bundle? + ): View { + val view = ResetNetworkRestrictionViewBuilder(requireActivity()).build() + if (view != null) { + Log.w(TAG, "Access deny.") + return view + } + return inflater.inflate(R.layout.reset_network_confirm, null).apply { + establishFinalConfirmationState() + setSubtitle() + } + } + + /** Configure the UI for the final confirmation interaction */ + private fun View.establishFinalConfirmationState() { + requireViewById(R.id.execute_reset_network).setOnClickListener { + if (!Utils.isMonkeyRunning() && !resetStarted) { + resetStarted = true + viewLifecycleOwner.lifecycleScope.launch { onResetClicked() } + } + } + } + + private fun View.setSubtitle() { + if (resetNetworkRequest.resetEsimPackageName != null) { + requireViewById(R.id.reset_network_confirm) + .setText(R.string.reset_network_final_desc_esim) + } + } + + override fun onViewCreated(view: View, savedInstanceState: Bundle?) { + super.onViewCreated(view, savedInstanceState) + invalidSubIdFlow().collectLatestWithLifecycle(viewLifecycleOwner) { invalidSubId -> + // Reset process could triage this callback, so if reset has started, ignore the event. + if (!resetStarted) { + Log.w(TAG, "subId $invalidSubId no longer active.") + requireActivity().finish() + } + } + } + + /** + * Monitor the sub ids in the request, if any sub id becomes inactive, the request is abandoned. + */ + private fun invalidSubIdFlow(): Flow { + val subIdsInRequest = + listOf( + resetNetworkRequest.resetTelephonyAndNetworkPolicyManager, + resetNetworkRequest.resetApnSubId, + resetNetworkRequest.resetImsSubId, + ) + .distinct() + .filter(SubscriptionManager::isUsableSubscriptionId) + + if (subIdsInRequest.isEmpty()) return emptyFlow() + + return SubscriptionRepository(requireContext()) + .activeSubscriptionIdListFlow() + .mapNotNull { activeSubIds -> subIdsInRequest.firstOrNull { it !in activeSubIds } } + .conflate() + .flowOn(Dispatchers.Default) + } + + /** + * The user has gone through the multiple confirmation, so now we go ahead and reset the network + * settings to its factory-default state. + */ + @VisibleForTesting + suspend fun onResetClicked() { + showProgressDialog() + resetNetwork() + } + + private fun showProgressDialog() { + progressDialog = + ProgressDialog(requireContext()).apply { + isIndeterminate = true + setCancelable(false) + setMessage(requireContext().getString(R.string.main_clear_progress_text)) + show() + } + } + + private fun dismissProgressDialog() { + progressDialog?.let { progressDialog -> + if (progressDialog.isShowing) { + progressDialog.dismiss() + } + } + } + + /** + * Do all reset task. + * + * If error happens during erasing eSIM profiles or timeout, an error msg is shown. + */ + private suspend fun resetNetwork() { + var resetEsimSuccess = true + + withContext(Dispatchers.Default) { + val builder = + resetNetworkRequest.toResetNetworkOperationBuilder( + requireContext(), Looper.getMainLooper()) + resetNetworkRequest.resetEsimPackageName?.let { resetEsimPackageName -> + builder.resetEsim(resetEsimPackageName) + builder.resetEsimResultCallback { resetEsimSuccess = it } + } + builder.build().run() + } + + Log.d(TAG, "network factoryReset complete. succeeded: $resetEsimSuccess") + onResetFinished(resetEsimSuccess) + } + + private fun onResetFinished(resetEsimSuccess: Boolean) { + dismissProgressDialog() + val activity = requireActivity() + + if (!resetEsimSuccess) { + alertDialog = + AlertDialog.Builder(activity) + .setTitle(R.string.reset_esim_error_title) + .setMessage(R.string.reset_esim_error_msg) + .setPositiveButton(android.R.string.ok, /* listener= */ null) + .show() + } else { + Toast.makeText(activity, R.string.reset_network_complete_toast, Toast.LENGTH_SHORT) + .show() + } + activity.finish() + } + + override fun onDestroy() { + progressDialog?.dismiss() + alertDialog?.dismiss() + super.onDestroy() + } + + override fun getMetricsCategory() = SettingsEnums.RESET_NETWORK_CONFIRM + + private companion object { + const val TAG = "ResetNetworkConfirm" + } +} diff --git a/tests/robotests/src/com/android/settings/ResetNetworkConfirmTest.java b/tests/robotests/src/com/android/settings/ResetNetworkConfirmTest.java deleted file mode 100644 index ea6559c7416..00000000000 --- a/tests/robotests/src/com/android/settings/ResetNetworkConfirmTest.java +++ /dev/null @@ -1,124 +0,0 @@ -/* - * Copyright (C) 2018 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; - -import static com.google.common.truth.Truth.assertThat; - -import static org.mockito.Mockito.spy; - -import android.view.LayoutInflater; -import android.widget.TextView; - -import androidx.fragment.app.FragmentActivity; - -import com.android.settings.testutils.shadow.ShadowBluetoothAdapter; -import com.android.settings.testutils.shadow.ShadowRecoverySystem; - -import org.junit.After; -import org.junit.Before; -import org.junit.Rule; -import org.junit.Test; -import org.junit.runner.RunWith; -import org.mockito.Mock; -import org.mockito.junit.MockitoJUnit; -import org.mockito.junit.MockitoRule; -import org.robolectric.Robolectric; -import org.robolectric.RobolectricTestRunner; -import org.robolectric.android.util.concurrent.PausedExecutorService; -import org.robolectric.annotation.Config; -import org.robolectric.shadows.ShadowLooper; -import org.robolectric.shadows.ShadowPausedAsyncTask; - -@RunWith(RobolectricTestRunner.class) -@Config(shadows = {ShadowRecoverySystem.class, ShadowBluetoothAdapter.class}) -public class ResetNetworkConfirmTest { - @Rule - public final MockitoRule mMockitoRule = MockitoJUnit.rule(); - - private static final String TEST_PACKAGE = "com.android.settings"; - - private FragmentActivity mActivity; - - @Mock - private ResetNetworkConfirm mResetNetworkConfirm; - private PausedExecutorService mExecutorService; - - @Before - public void setUp() { - mExecutorService = new PausedExecutorService(); - ShadowPausedAsyncTask.overrideExecutor(mExecutorService); - mResetNetworkConfirm = new ResetNetworkConfirm(); - mActivity = spy(Robolectric.setupActivity(FragmentActivity.class)); - mResetNetworkConfirm.mActivity = mActivity; - } - - @After - public void tearDown() { - ShadowRecoverySystem.reset(); - } - - @Test - public void testResetNetworkData_notResetEsim() { - mResetNetworkConfirm.mResetNetworkRequest = - new ResetNetworkRequest(ResetNetworkRequest.RESET_NONE); - mResetNetworkConfirm.mResetSubscriptionContract = - new ResetSubscriptionContract(mActivity, - mResetNetworkConfirm.mResetNetworkRequest) { - @Override - public void onSubscriptionInactive(int subscriptionId) { - mActivity.onBackPressed(); - } - }; - - mResetNetworkConfirm.mFinalClickListener.onClick(null /* View */); - mExecutorService.runAll(); - ShadowLooper.idleMainLooper(); - - assertThat(ShadowRecoverySystem.getWipeEuiccCalledCount()).isEqualTo(0); - } - - @Test - public void setSubtitle_eraseEsim() { - mResetNetworkConfirm.mResetNetworkRequest = - new ResetNetworkRequest(ResetNetworkRequest.RESET_NONE); - mResetNetworkConfirm.mResetNetworkRequest.setResetEsim(TEST_PACKAGE); - - mResetNetworkConfirm.mContentView = - LayoutInflater.from(mActivity).inflate(R.layout.reset_network_confirm, null); - - mResetNetworkConfirm.setSubtitle(); - - assertThat(((TextView) mResetNetworkConfirm.mContentView - .findViewById(R.id.reset_network_confirm)).getText()) - .isEqualTo(mActivity.getString(R.string.reset_network_final_desc_esim)); - } - - @Test - public void setSubtitle_notEraseEsim() { - mResetNetworkConfirm.mResetNetworkRequest = - new ResetNetworkRequest(ResetNetworkRequest.RESET_NONE); - - mResetNetworkConfirm.mContentView = - LayoutInflater.from(mActivity).inflate(R.layout.reset_network_confirm, null); - - mResetNetworkConfirm.setSubtitle(); - - assertThat(((TextView) mResetNetworkConfirm.mContentView - .findViewById(R.id.reset_network_confirm)).getText()) - .isEqualTo(mActivity.getString(R.string.reset_network_final_desc)); - } -} diff --git a/tests/spa_unit/src/com/android/settings/system/reset/ResetNetworkConfirmTest.kt b/tests/spa_unit/src/com/android/settings/system/reset/ResetNetworkConfirmTest.kt new file mode 100644 index 00000000000..4812cfb1545 --- /dev/null +++ b/tests/spa_unit/src/com/android/settings/system/reset/ResetNetworkConfirmTest.kt @@ -0,0 +1,79 @@ +/* + * Copyright (C) 2024 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.system.reset + +import android.content.Context +import android.view.LayoutInflater +import android.widget.TextView +import androidx.fragment.app.testing.launchFragment +import androidx.test.core.app.ApplicationProvider +import androidx.test.ext.junit.runners.AndroidJUnit4 +import com.android.settings.R +import com.android.settings.ResetNetworkRequest +import com.google.common.truth.Truth.assertThat +import kotlinx.coroutines.runBlocking +import org.junit.Test +import org.junit.runner.RunWith +import org.mockito.kotlin.any +import org.mockito.kotlin.never +import org.mockito.kotlin.spy +import org.mockito.kotlin.verify + +@RunWith(AndroidJUnit4::class) +class ResetNetworkConfirmTest { + private val context: Context = spy(ApplicationProvider.getApplicationContext()) {} + + private val scenario = launchFragment() + + @Test + fun resetNetworkData_notResetEsim() { + scenario.recreate().onFragment { fragment -> + fragment.resetNetworkRequest = ResetNetworkRequest(ResetNetworkRequest.RESET_NONE) + + runBlocking { fragment.onResetClicked() } + + verify(context, never()).getSystemService(any()) + } + } + + @Test + fun setSubtitle_eraseEsim() { + scenario.onFragment { fragment -> + fragment.resetNetworkRequest = + ResetNetworkRequest(ResetNetworkRequest.RESET_NONE).apply { + setResetEsim(context.packageName) + } + + val view = fragment.onCreateView(LayoutInflater.from(context), null, null) + + assertThat(view.requireViewById(R.id.reset_network_confirm).text) + .isEqualTo(context.getString(R.string.reset_network_final_desc_esim)) + } + } + + @Test + fun setSubtitle_notEraseEsim() { + scenario.onFragment { fragment -> + fragment.resetNetworkRequest = ResetNetworkRequest(ResetNetworkRequest.RESET_NONE) + + val view = fragment.onCreateView(LayoutInflater.from(context), null, null) + + assertThat(view.requireViewById(R.id.reset_network_confirm).text) + .isEqualTo(context.getString(R.string.reset_network_final_desc)) + } + } +} diff --git a/tests/unit/src/com/android/settings/ResetSubscriptionContractTest.java b/tests/unit/src/com/android/settings/ResetSubscriptionContractTest.java deleted file mode 100644 index 4443304d696..00000000000 --- a/tests/unit/src/com/android/settings/ResetSubscriptionContractTest.java +++ /dev/null @@ -1,109 +0,0 @@ -/* - * Copyright (C) 2022 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; - -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertNull; -import static org.mockito.ArgumentMatchers.any; -import static org.mockito.Mockito.doReturn; -import static org.mockito.Mockito.spy; -import static org.mockito.Mockito.verify; - -import android.content.Context; -import android.os.Bundle; -import android.telephony.SubscriptionInfo; -import android.telephony.SubscriptionManager; -import android.telephony.SubscriptionManager.OnSubscriptionsChangedListener; -import androidx.test.core.app.ApplicationProvider; -import androidx.test.ext.junit.runners.AndroidJUnit4; -import org.junit.Before; -import org.junit.Test; -import org.junit.runner.RunWith; -import org.mockito.Mock; -import org.mockito.MockitoAnnotations; - -@RunWith(AndroidJUnit4.class) -public class ResetSubscriptionContractTest { - - private static final int SUB_ID_1 = 3; - private static final int SUB_ID_2 = 8; - - @Mock - private SubscriptionManager mSubscriptionManager; - @Mock - private OnSubscriptionsChangedListener mOnSubscriptionsChangedListener; - @Mock - private SubscriptionInfo mSubscriptionInfo1; - @Mock - private SubscriptionInfo mSubscriptionInfo2; - - private Context mContext; - private ResetNetworkRequest mRequestArgs; - - @Before - public void setUp() { - MockitoAnnotations.initMocks(this); - - mContext = spy(ApplicationProvider.getApplicationContext()); - mRequestArgs = new ResetNetworkRequest(new Bundle()); - } - - private ResetSubscriptionContract createTestObject() { - return new ResetSubscriptionContract(mContext, mRequestArgs) { - @Override - protected SubscriptionManager getSubscriptionManager() { - return mSubscriptionManager; - } - @Override - protected OnSubscriptionsChangedListener getChangeListener() { - return mOnSubscriptionsChangedListener; - } - }; - } - - @Test - public void getAnyMissingSubscriptionId_returnNull_whenNoSubscriptionChange() { - mRequestArgs.setResetTelephonyAndNetworkPolicyManager(SUB_ID_1); - doReturn(mSubscriptionInfo1).when(mSubscriptionManager) - .getActiveSubscriptionInfo(SUB_ID_1); - mRequestArgs.setResetApn(SUB_ID_2); - doReturn(mSubscriptionInfo2).when(mSubscriptionManager) - .getActiveSubscriptionInfo(SUB_ID_2); - - ResetSubscriptionContract target = createTestObject(); - - verify(mSubscriptionManager).addOnSubscriptionsChangedListener(any(), any()); - - assertNull(target.getAnyMissingSubscriptionId()); - } - - @Test - public void getAnyMissingSubscriptionId_returnSubId_whenSubscriptionNotActive() { - mRequestArgs.setResetTelephonyAndNetworkPolicyManager(SUB_ID_1); - doReturn(mSubscriptionInfo1).when(mSubscriptionManager) - .getActiveSubscriptionInfo(SUB_ID_1); - mRequestArgs.setResetApn(SUB_ID_2); - doReturn(null).when(mSubscriptionManager) - .getActiveSubscriptionInfo(SUB_ID_2); - - ResetSubscriptionContract target = createTestObject(); - - verify(mSubscriptionManager).addOnSubscriptionsChangedListener(any(), any()); - - assertEquals(target.getAnyMissingSubscriptionId(), new Integer(SUB_ID_2)); - } -}