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