1 /* 2 * Copyright (C) 2015 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17 package com.android.settings; 18 19 import static com.android.settingslib.RestrictedLockUtils.EnforcedAdmin; 20 21 import android.app.Activity; 22 import android.app.ProgressDialog; 23 import android.app.settings.SettingsEnums; 24 import android.bluetooth.BluetoothAdapter; 25 import android.bluetooth.BluetoothManager; 26 import android.content.ContentResolver; 27 import android.content.Context; 28 import android.net.ConnectivityManager; 29 import android.net.NetworkPolicyManager; 30 import android.net.Uri; 31 import android.net.VpnManager; 32 import android.net.wifi.WifiManager; 33 import android.net.wifi.p2p.WifiP2pManager; 34 import android.os.AsyncTask; 35 import android.os.Bundle; 36 import android.os.Looper; 37 import android.os.RecoverySystem; 38 import android.os.UserHandle; 39 import android.os.UserManager; 40 import android.telephony.SubscriptionManager; 41 import android.telephony.SubscriptionManager.OnSubscriptionsChangedListener; 42 import android.telephony.TelephonyManager; 43 import android.util.Log; 44 import android.view.LayoutInflater; 45 import android.view.View; 46 import android.view.ViewGroup; 47 import android.widget.Button; 48 import android.widget.TextView; 49 import android.widget.Toast; 50 51 import androidx.annotation.VisibleForTesting; 52 import androidx.appcompat.app.AlertDialog; 53 54 import com.android.settings.core.InstrumentedFragment; 55 import com.android.settings.enterprise.ActionDisabledByAdminDialogHelper; 56 import com.android.settings.network.apn.ApnSettings; 57 import com.android.settingslib.RestrictedLockUtilsInternal; 58 59 /** 60 * Confirm and execute a reset of the network settings to a clean "just out of the box" 61 * state. Multiple confirmations are required: first, a general "are you sure 62 * you want to do this?" prompt, followed by a keyguard pattern trace if the user 63 * has defined one, followed by a final strongly-worded "THIS WILL RESET EVERYTHING" 64 * prompt. If at any time the phone is allowed to go to sleep, is 65 * locked, et cetera, then the confirmation sequence is abandoned. 66 * 67 * This is the confirmation screen. 68 */ 69 public class ResetNetworkConfirm extends InstrumentedFragment { 70 private static final String TAG = "ResetNetworkConfirm"; 71 72 @VisibleForTesting View mContentView; 73 @VisibleForTesting boolean mEraseEsim; 74 @VisibleForTesting ResetNetworkTask mResetNetworkTask; 75 @VisibleForTesting Activity mActivity; 76 private int mSubId = SubscriptionManager.INVALID_SUBSCRIPTION_ID; 77 private ProgressDialog mProgressDialog; 78 private AlertDialog mAlertDialog; 79 private OnSubscriptionsChangedListener mSubscriptionsChangedListener; 80 81 /** 82 * Async task used to do all reset task. If error happens during 83 * erasing eSIM profiles or timeout, an error msg is shown. 84 */ 85 private class ResetNetworkTask extends AsyncTask<Void, Void, Boolean> { 86 private static final String TAG = "ResetNetworkTask"; 87 88 private final Context mContext; 89 private final String mPackageName; 90 ResetNetworkTask(Context context)91 ResetNetworkTask(Context context) { 92 mContext = context; 93 mPackageName = context.getPackageName(); 94 } 95 96 @Override doInBackground(Void... params)97 protected Boolean doInBackground(Void... params) { 98 boolean isResetSucceed = true; 99 ConnectivityManager connectivityManager = (ConnectivityManager) 100 mContext.getSystemService(Context.CONNECTIVITY_SERVICE); 101 if (connectivityManager != null) { 102 connectivityManager.factoryReset(); 103 } 104 105 VpnManager vpnManager = mContext.getSystemService(VpnManager.class); 106 if (vpnManager != null) { 107 vpnManager.factoryReset(); 108 } 109 110 WifiManager wifiManager = (WifiManager) 111 mContext.getSystemService(Context.WIFI_SERVICE); 112 if (wifiManager != null) { 113 wifiManager.factoryReset(); 114 } 115 116 p2pFactoryReset(mContext); 117 118 if (mEraseEsim) { 119 isResetSucceed = RecoverySystem.wipeEuiccData(mContext, mPackageName); 120 } 121 122 TelephonyManager telephonyManager = (TelephonyManager) 123 mContext.getSystemService(TelephonyManager.class) 124 .createForSubscriptionId(mSubId); 125 if (telephonyManager != null) { 126 telephonyManager.resetSettings(); 127 } 128 129 NetworkPolicyManager policyManager = (NetworkPolicyManager) 130 mContext.getSystemService(Context.NETWORK_POLICY_SERVICE); 131 if (policyManager != null) { 132 String subscriberId = telephonyManager.getSubscriberId(); 133 policyManager.factoryReset(subscriberId); 134 } 135 136 BluetoothManager btManager = (BluetoothManager) 137 mContext.getSystemService(Context.BLUETOOTH_SERVICE); 138 if (btManager != null) { 139 BluetoothAdapter btAdapter = btManager.getAdapter(); 140 if (btAdapter != null) { 141 btAdapter.factoryReset(); 142 } 143 } 144 145 restoreDefaultApn(mContext); 146 Log.d(TAG, "network factoryReset complete. succeeded: " 147 + String.valueOf(isResetSucceed)); 148 return isResetSucceed; 149 } 150 151 @Override onPostExecute(Boolean succeeded)152 protected void onPostExecute(Boolean succeeded) { 153 mProgressDialog.dismiss(); 154 if (succeeded) { 155 Toast.makeText(mContext, R.string.reset_network_complete_toast, Toast.LENGTH_SHORT) 156 .show(); 157 } else { 158 mAlertDialog = new AlertDialog.Builder(mContext) 159 .setTitle(R.string.reset_esim_error_title) 160 .setMessage(R.string.reset_esim_error_msg) 161 .setPositiveButton(android.R.string.ok, null /* listener */) 162 .show(); 163 } 164 } 165 } 166 167 /** 168 * The user has gone through the multiple confirmation, so now we go ahead 169 * and reset the network settings to its factory-default state. 170 */ 171 @VisibleForTesting 172 Button.OnClickListener mFinalClickListener = new Button.OnClickListener() { 173 174 @Override 175 public void onClick(View v) { 176 if (Utils.isMonkeyRunning()) { 177 return; 178 } 179 180 // abandon execution if subscription no longer active 181 if (mSubId != SubscriptionManager.INVALID_SUBSCRIPTION_ID) { 182 SubscriptionManager mgr = getSubscriptionManager(); 183 // always remove listener 184 stopMonitorSubscriptionChange(mgr); 185 if (!isSubscriptionRemainActive(mgr, mSubId)) { 186 Log.w(TAG, "subId " + mSubId + " disappear when confirm"); 187 mActivity.finish(); 188 return; 189 } 190 } 191 192 mProgressDialog = getProgressDialog(mActivity); 193 mProgressDialog.show(); 194 195 mResetNetworkTask = new ResetNetworkTask(mActivity); 196 mResetNetworkTask.execute(); 197 } 198 }; 199 200 @VisibleForTesting p2pFactoryReset(Context context)201 void p2pFactoryReset(Context context) { 202 WifiP2pManager wifiP2pManager = (WifiP2pManager) 203 context.getSystemService(Context.WIFI_P2P_SERVICE); 204 if (wifiP2pManager != null) { 205 WifiP2pManager.Channel channel = wifiP2pManager.initialize( 206 context.getApplicationContext(), context.getMainLooper(), 207 null /* listener */); 208 if (channel != null) { 209 wifiP2pManager.factoryReset(channel, null /* listener */); 210 } 211 } 212 } 213 getProgressDialog(Context context)214 private ProgressDialog getProgressDialog(Context context) { 215 final ProgressDialog progressDialog = new ProgressDialog(context); 216 progressDialog.setIndeterminate(true); 217 progressDialog.setCancelable(false); 218 progressDialog.setMessage( 219 context.getString(R.string.main_clear_progress_text)); 220 return progressDialog; 221 } 222 223 /** 224 * Restore APN settings to default. 225 */ restoreDefaultApn(Context context)226 private void restoreDefaultApn(Context context) { 227 Uri uri = Uri.parse(ApnSettings.RESTORE_CARRIERS_URI); 228 229 if (SubscriptionManager.isUsableSubscriptionId(mSubId)) { 230 uri = Uri.withAppendedPath(uri, "subId/" + String.valueOf(mSubId)); 231 } 232 233 ContentResolver resolver = context.getContentResolver(); 234 resolver.delete(uri, null, null); 235 } 236 237 /** 238 * Configure the UI for the final confirmation interaction 239 */ establishFinalConfirmationState()240 private void establishFinalConfirmationState() { 241 mContentView.findViewById(R.id.execute_reset_network) 242 .setOnClickListener(mFinalClickListener); 243 } 244 245 @VisibleForTesting setSubtitle()246 void setSubtitle() { 247 if (mEraseEsim) { 248 ((TextView) mContentView.findViewById(R.id.reset_network_confirm)) 249 .setText(R.string.reset_network_final_desc_esim); 250 } 251 } 252 253 @Override onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState)254 public View onCreateView(LayoutInflater inflater, ViewGroup container, 255 Bundle savedInstanceState) { 256 final EnforcedAdmin admin = RestrictedLockUtilsInternal.checkIfRestrictionEnforced( 257 mActivity, UserManager.DISALLOW_NETWORK_RESET, UserHandle.myUserId()); 258 if (RestrictedLockUtilsInternal.hasBaseUserRestriction(mActivity, 259 UserManager.DISALLOW_NETWORK_RESET, UserHandle.myUserId())) { 260 return inflater.inflate(R.layout.network_reset_disallowed_screen, null); 261 } else if (admin != null) { 262 new ActionDisabledByAdminDialogHelper(mActivity) 263 .prepareDialogBuilder(UserManager.DISALLOW_NETWORK_RESET, admin) 264 .setOnDismissListener(__ -> mActivity.finish()) 265 .show(); 266 return new View(mActivity); 267 } 268 mContentView = inflater.inflate(R.layout.reset_network_confirm, null); 269 establishFinalConfirmationState(); 270 setSubtitle(); 271 return mContentView; 272 } 273 274 @Override onCreate(Bundle savedInstanceState)275 public void onCreate(Bundle savedInstanceState) { 276 super.onCreate(savedInstanceState); 277 278 Bundle args = getArguments(); 279 if (args != null) { 280 mSubId = args.getInt(SubscriptionManager.EXTRA_SUBSCRIPTION_INDEX, 281 SubscriptionManager.INVALID_SUBSCRIPTION_ID); 282 mEraseEsim = args.getBoolean(MainClear.ERASE_ESIMS_EXTRA); 283 } 284 285 mActivity = getActivity(); 286 287 if (mSubId == SubscriptionManager.INVALID_SUBSCRIPTION_ID) { 288 return; 289 } 290 // close confirmation dialog when reset specific subscription 291 // but removed priori to the confirmation button been pressed 292 startMonitorSubscriptionChange(getSubscriptionManager()); 293 } 294 getSubscriptionManager()295 private SubscriptionManager getSubscriptionManager() { 296 SubscriptionManager mgr = mActivity.getSystemService(SubscriptionManager.class); 297 if (mgr == null) { 298 Log.w(TAG, "No SubscriptionManager"); 299 } 300 return mgr; 301 } 302 startMonitorSubscriptionChange(SubscriptionManager mgr)303 private void startMonitorSubscriptionChange(SubscriptionManager mgr) { 304 if (mgr == null) { 305 return; 306 } 307 // update monitor listener 308 mSubscriptionsChangedListener = new OnSubscriptionsChangedListener( 309 Looper.getMainLooper()) { 310 @Override 311 public void onSubscriptionsChanged() { 312 SubscriptionManager mgr = getSubscriptionManager(); 313 if (isSubscriptionRemainActive(mgr, mSubId)) { 314 return; 315 } 316 // close UI if subscription no longer active 317 Log.w(TAG, "subId " + mSubId + " no longer active."); 318 stopMonitorSubscriptionChange(mgr); 319 mActivity.finish(); 320 } 321 }; 322 mgr.addOnSubscriptionsChangedListener( 323 mActivity.getMainExecutor(), mSubscriptionsChangedListener); 324 } 325 isSubscriptionRemainActive(SubscriptionManager mgr, int subscriptionId)326 private boolean isSubscriptionRemainActive(SubscriptionManager mgr, int subscriptionId) { 327 return (mgr == null) ? false : (mgr.getActiveSubscriptionInfo(subscriptionId) != null); 328 } 329 stopMonitorSubscriptionChange(SubscriptionManager mgr)330 private void stopMonitorSubscriptionChange(SubscriptionManager mgr) { 331 if ((mgr == null) || (mSubscriptionsChangedListener == null)) { 332 return; 333 } 334 mgr.removeOnSubscriptionsChangedListener(mSubscriptionsChangedListener); 335 mSubscriptionsChangedListener = null; 336 } 337 338 @Override onDestroy()339 public void onDestroy() { 340 if (mResetNetworkTask != null) { 341 mResetNetworkTask.cancel(true /* mayInterruptIfRunning */); 342 mResetNetworkTask = null; 343 } 344 if (mProgressDialog != null) { 345 mProgressDialog.dismiss(); 346 } 347 if (mAlertDialog != null) { 348 mAlertDialog.dismiss(); 349 } 350 stopMonitorSubscriptionChange(getSubscriptionManager()); 351 super.onDestroy(); 352 } 353 354 @Override getMetricsCategory()355 public int getMetricsCategory() { 356 return SettingsEnums.RESET_NETWORK_CONFIRM; 357 } 358 } 359