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 android.app.Activity;
20 import android.app.ProgressDialog;
21 import android.app.settings.SettingsEnums;
22 import android.content.Context;
23 import android.os.AsyncTask;
24 import android.os.Bundle;
25 import android.os.Looper;
26 import android.telephony.SubscriptionManager;
27 import android.telephony.SubscriptionManager.OnSubscriptionsChangedListener;
28 import android.util.Log;
29 import android.view.LayoutInflater;
30 import android.view.View;
31 import android.view.ViewGroup;
32 import android.widget.Button;
33 import android.widget.TextView;
34 import android.widget.Toast;
35 
36 import androidx.annotation.VisibleForTesting;
37 import androidx.appcompat.app.AlertDialog;
38 
39 import com.android.settings.core.InstrumentedFragment;
40 import com.android.settings.network.ResetNetworkOperationBuilder;
41 import com.android.settings.network.ResetNetworkRestrictionViewBuilder;
42 
43 import java.util.concurrent.atomic.AtomicBoolean;
44 
45 /**
46  * Confirm and execute a reset of the network settings to a clean "just out of the box"
47  * state.  Multiple confirmations are required: first, a general "are you sure
48  * you want to do this?" prompt, followed by a keyguard pattern trace if the user
49  * has defined one, followed by a final strongly-worded "THIS WILL RESET EVERYTHING"
50  * prompt.  If at any time the phone is allowed to go to sleep, is
51  * locked, et cetera, then the confirmation sequence is abandoned.
52  *
53  * This is the confirmation screen.
54  */
55 public class ResetNetworkConfirm extends InstrumentedFragment {
56     private static final String TAG = "ResetNetworkConfirm";
57 
58     @VisibleForTesting View mContentView;
59     @VisibleForTesting ResetNetworkTask mResetNetworkTask;
60     @VisibleForTesting Activity mActivity;
61     @VisibleForTesting ResetNetworkRequest mResetNetworkRequest;
62     private ProgressDialog mProgressDialog;
63     private AlertDialog mAlertDialog;
64     @VisibleForTesting ResetSubscriptionContract mResetSubscriptionContract;
65     private OnSubscriptionsChangedListener mSubscriptionsChangedListener;
66 
67     /**
68      * Async task used to do all reset task. If error happens during
69      * erasing eSIM profiles or timeout, an error msg is shown.
70      */
71     private class ResetNetworkTask extends AsyncTask<Void, Void, Boolean> {
72         private static final String TAG = "ResetNetworkTask";
73 
74         private final Context mContext;
75 
ResetNetworkTask(Context context)76         ResetNetworkTask(Context context) {
77             mContext = context;
78         }
79 
80         @Override
doInBackground(Void... params)81         protected Boolean doInBackground(Void... params) {
82             final AtomicBoolean resetEsimSuccess = new AtomicBoolean(true);
83 
84             String resetEsimPackageName = mResetNetworkRequest.getResetEsimPackageName();
85             ResetNetworkOperationBuilder builder = mResetNetworkRequest
86                     .toResetNetworkOperationBuilder(mContext, Looper.getMainLooper());
87             if (resetEsimPackageName != null) {
88                 // Override reset eSIM option for the result of reset operation
89                 builder = builder.resetEsim(resetEsimPackageName,
90                         success -> { resetEsimSuccess.set(success); }
91                         );
92             }
93             builder.build().run();
94 
95             boolean isResetSucceed = resetEsimSuccess.get();
96             Log.d(TAG, "network factoryReset complete. succeeded: "
97                     + String.valueOf(isResetSucceed));
98             return isResetSucceed;
99         }
100 
101         @Override
onPostExecute(Boolean succeeded)102         protected void onPostExecute(Boolean succeeded) {
103             if (mProgressDialog != null && mProgressDialog.isShowing()) {
104                 mProgressDialog.dismiss();
105             }
106 
107             if (succeeded) {
108                 Toast.makeText(mContext, R.string.reset_network_complete_toast, Toast.LENGTH_SHORT)
109                         .show();
110             } else {
111                 mAlertDialog = new AlertDialog.Builder(mContext)
112                         .setTitle(R.string.reset_esim_error_title)
113                         .setMessage(R.string.reset_esim_error_msg)
114                         .setPositiveButton(android.R.string.ok, null /* listener */)
115                         .show();
116             }
117         }
118     }
119 
120     /**
121      * The user has gone through the multiple confirmation, so now we go ahead
122      * and reset the network settings to its factory-default state.
123      */
124     @VisibleForTesting
125     Button.OnClickListener mFinalClickListener = new Button.OnClickListener() {
126 
127         @Override
128         public void onClick(View v) {
129             if (Utils.isMonkeyRunning()) {
130                 return;
131             }
132 
133             // abandon execution if subscription no longer active
134             Integer subId = mResetSubscriptionContract.getAnyMissingSubscriptionId();
135             if (subId != null) {
136                 Log.w(TAG, "subId " + subId + " no longer active");
137                 getActivity().onBackPressed();
138                 return;
139             }
140 
141             // Should dismiss the progress dialog firstly if it is showing
142             // Or not the progress dialog maybe not dismissed in fast clicking.
143             if (mProgressDialog != null && mProgressDialog.isShowing()) {
144                 mProgressDialog.dismiss();
145             }
146 
147             mProgressDialog = getProgressDialog(mActivity);
148             mProgressDialog.show();
149 
150             mResetNetworkTask = new ResetNetworkTask(mActivity);
151             mResetNetworkTask.execute();
152         }
153     };
154 
getProgressDialog(Context context)155     private ProgressDialog getProgressDialog(Context context) {
156         final ProgressDialog progressDialog = new ProgressDialog(context);
157         progressDialog.setIndeterminate(true);
158         progressDialog.setCancelable(false);
159         progressDialog.setMessage(
160                 context.getString(R.string.main_clear_progress_text));
161         return progressDialog;
162     }
163 
164     /**
165      * Configure the UI for the final confirmation interaction
166      */
establishFinalConfirmationState()167     private void establishFinalConfirmationState() {
168         mContentView.findViewById(R.id.execute_reset_network)
169                 .setOnClickListener(mFinalClickListener);
170     }
171 
172     @VisibleForTesting
setSubtitle()173     void setSubtitle() {
174         if (mResetNetworkRequest.getResetEsimPackageName() != null) {
175             ((TextView) mContentView.findViewById(R.id.reset_network_confirm))
176                     .setText(R.string.reset_network_final_desc_esim);
177         }
178     }
179 
180     @Override
onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState)181     public View onCreateView(LayoutInflater inflater, ViewGroup container,
182             Bundle savedInstanceState) {
183         View view = (new ResetNetworkRestrictionViewBuilder(mActivity)).build();
184         if (view != null) {
185             mResetSubscriptionContract.close();
186             Log.w(TAG, "Access deny.");
187             return view;
188         }
189         mContentView = inflater.inflate(R.layout.reset_network_confirm, null);
190         establishFinalConfirmationState();
191         setSubtitle();
192         return mContentView;
193     }
194 
195     @Override
onCreate(Bundle savedInstanceState)196     public void onCreate(Bundle savedInstanceState) {
197         super.onCreate(savedInstanceState);
198 
199         Bundle args = getArguments();
200         if (args == null) {
201             args = savedInstanceState;
202         }
203         mResetNetworkRequest = new ResetNetworkRequest(args);
204 
205         mActivity = getActivity();
206 
207         mResetSubscriptionContract = new ResetSubscriptionContract(getContext(),
208                 mResetNetworkRequest) {
209             @Override
210             public void onSubscriptionInactive(int subscriptionId) {
211                 // close UI if subscription no longer active
212                 Log.w(TAG, "subId " + subscriptionId + " no longer active.");
213                 getActivity().onBackPressed();
214             }
215         };
216     }
217 
218     @Override
onSaveInstanceState(Bundle outState)219     public void onSaveInstanceState(Bundle outState) {
220         super.onSaveInstanceState(outState);
221         mResetNetworkRequest.writeIntoBundle(outState);
222     }
223 
224     @Override
onDestroy()225     public void onDestroy() {
226         if (mResetNetworkTask != null) {
227             mResetNetworkTask.cancel(true /* mayInterruptIfRunning */);
228             mResetNetworkTask = null;
229         }
230         if (mResetSubscriptionContract != null) {
231             mResetSubscriptionContract.close();
232             mResetSubscriptionContract = null;
233         }
234         if (mProgressDialog != null) {
235             mProgressDialog.dismiss();
236         }
237         if (mAlertDialog != null) {
238             mAlertDialog.dismiss();
239         }
240         super.onDestroy();
241     }
242 
243     @Override
getMetricsCategory()244     public int getMetricsCategory() {
245         return SettingsEnums.RESET_NETWORK_CONFIRM;
246     }
247 }
248