Fix unable to erase eSIM
Before this change, - eSIM will be erased twice, one with result callback and one without result callback. - During reset, ResetNetworkConfirm could interrupted by subscription invalid event, which happens during reset. After this change, - eSIM will be erased only once, result callback is registered separately. - Explicit exit the page when reset finish, and ignore the subscription invalid event after reset started. Bug: 328293508 Flag: EXEMPT bug fix Test: manual - dry run the reset Test: ResetNetworkConfirmTest Change-Id: I51395a556b1c8775192d5897a87f13046c042578
This commit is contained in:
@@ -52,6 +52,7 @@ import com.android.settings.network.SubscriptionUtil;
|
|||||||
import com.android.settings.network.telephony.EuiccRacConnectivityDialogActivity;
|
import com.android.settings.network.telephony.EuiccRacConnectivityDialogActivity;
|
||||||
import com.android.settings.password.ChooseLockSettingsHelper;
|
import com.android.settings.password.ChooseLockSettingsHelper;
|
||||||
import com.android.settings.password.ConfirmLockPattern;
|
import com.android.settings.password.ConfirmLockPattern;
|
||||||
|
import com.android.settings.system.reset.ResetNetworkConfirm;
|
||||||
import com.android.settingslib.development.DevelopmentSettingsEnabler;
|
import com.android.settingslib.development.DevelopmentSettingsEnabler;
|
||||||
|
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
|
@@ -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<Void, Void, Boolean> {
|
|
||||||
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;
|
|
||||||
}
|
|
||||||
}
|
|
@@ -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;
|
|
||||||
}
|
|
||||||
}
|
|
@@ -65,6 +65,8 @@ public class ResetNetworkOperationBuilder {
|
|||||||
|
|
||||||
private Context mContext;
|
private Context mContext;
|
||||||
private List<Runnable> mResetSequence = new ArrayList<Runnable>();
|
private List<Runnable> mResetSequence = new ArrayList<Runnable>();
|
||||||
|
@Nullable
|
||||||
|
private Consumer<Boolean> mResetEsimResultCallback = null;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Constructor of builder.
|
* Constructor of builder.
|
||||||
@@ -129,31 +131,32 @@ public class ResetNetworkOperationBuilder {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Append a step of resetting E-SIM.
|
* Append a result callback of resetting E-SIM.
|
||||||
* @param callerPackage package name of caller
|
* @param resultCallback a callback dealing with result of resetting eSIM
|
||||||
* @return this
|
* @return this
|
||||||
*/
|
*/
|
||||||
public ResetNetworkOperationBuilder resetEsim(String callerPackage) {
|
public ResetNetworkOperationBuilder resetEsimResultCallback(Consumer<Boolean> resultCallback) {
|
||||||
resetEsim(callerPackage, null);
|
mResetEsimResultCallback = resultCallback;
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Append a step of resetting E-SIM.
|
* Append a step of resetting E-SIM.
|
||||||
* @param callerPackage package name of caller
|
* @param callerPackage package name of caller
|
||||||
* @param resultCallback a Consumer<Boolean> dealing with result of resetting eSIM
|
|
||||||
* @return this
|
* @return this
|
||||||
*/
|
*/
|
||||||
public ResetNetworkOperationBuilder resetEsim(String callerPackage,
|
public ResetNetworkOperationBuilder resetEsim(String callerPackage) {
|
||||||
Consumer<Boolean> resultCallback) {
|
|
||||||
Runnable runnable = () -> {
|
Runnable runnable = () -> {
|
||||||
long startTime = SystemClock.elapsedRealtime();
|
long startTime = SystemClock.elapsedRealtime();
|
||||||
|
|
||||||
if (!DRY_RUN) {
|
boolean wipped;
|
||||||
Boolean wipped = RecoverySystem.wipeEuiccData(mContext, callerPackage);
|
if (DRY_RUN) {
|
||||||
if (resultCallback != null) {
|
wipped = true;
|
||||||
resultCallback.accept(wipped);
|
} else {
|
||||||
|
wipped = RecoverySystem.wipeEuiccData(mContext, callerPackage);
|
||||||
}
|
}
|
||||||
|
if (mResetEsimResultCallback != null) {
|
||||||
|
mResetEsimResultCallback.accept(wipped);
|
||||||
}
|
}
|
||||||
|
|
||||||
long endTime = SystemClock.elapsedRealtime();
|
long endTime = SystemClock.elapsedRealtime();
|
||||||
|
217
src/com/android/settings/system/reset/ResetNetworkConfirm.kt
Normal file
217
src/com/android/settings/system/reset/ResetNetworkConfirm.kt
Normal file
@@ -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<View>(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<TextView>(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<Int> {
|
||||||
|
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"
|
||||||
|
}
|
||||||
|
}
|
@@ -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));
|
|
||||||
}
|
|
||||||
}
|
|
@@ -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<ResetNetworkConfirm>()
|
||||||
|
|
||||||
|
@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<TextView>(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<TextView>(R.id.reset_network_confirm).text)
|
||||||
|
.isEqualTo(context.getString(R.string.reset_network_final_desc))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@@ -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));
|
|
||||||
}
|
|
||||||
}
|
|
Reference in New Issue
Block a user