• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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.annotation.Nullable;
20 import android.app.Activity;
21 import android.app.settings.SettingsEnums;
22 import android.content.ContentResolver;
23 import android.content.Context;
24 import android.content.Intent;
25 import android.content.res.Resources;
26 import android.os.Bundle;
27 import android.provider.Settings;
28 import android.provider.Settings.Global;
29 import android.telephony.SubscriptionInfo;
30 import android.telephony.SubscriptionManager;
31 import android.telephony.euicc.EuiccManager;
32 import android.text.TextUtils;
33 import android.util.Log;
34 import android.view.LayoutInflater;
35 import android.view.View;
36 import android.view.View.OnClickListener;
37 import android.view.ViewGroup;
38 import android.widget.ArrayAdapter;
39 import android.widget.Button;
40 import android.widget.CheckBox;
41 import android.widget.Spinner;
42 
43 import androidx.activity.result.ActivityResult;
44 import androidx.activity.result.ActivityResultLauncher;
45 import androidx.activity.result.contract.ActivityResultContracts;
46 import androidx.annotation.VisibleForTesting;
47 
48 import com.android.settings.core.InstrumentedFragment;
49 import com.android.settings.core.SubSettingLauncher;
50 import com.android.settings.network.ResetNetworkRestrictionViewBuilder;
51 import com.android.settings.network.SubscriptionUtil;
52 import com.android.settings.password.ChooseLockSettingsHelper;
53 import com.android.settings.password.ConfirmLockPattern;
54 import com.android.settingslib.development.DevelopmentSettingsEnabler;
55 
56 import java.util.ArrayList;
57 import java.util.Collections;
58 import java.util.List;
59 import java.util.Optional;
60 
61 /**
62  * Confirm and execute a reset of the device's network settings to a clean "just out of the box"
63  * state.  Multiple confirmations are required: first, a general "are you sure you want to do this?"
64  * prompt, followed by a keyguard pattern trace if the user has defined one, followed by a final
65  * strongly-worded "THIS WILL RESET EVERYTHING" prompt.  If at any time the phone is allowed to go
66  * to sleep, is locked, et cetera, then the confirmation sequence is abandoned.
67  *
68  * This is the initial screen.
69  */
70 public class ResetNetwork extends InstrumentedFragment {
71     private static final String TAG = "ResetNetwork";
72 
73     // Arbitrary to avoid conficts
74     private static final int KEYGUARD_REQUEST = 55;
75 
76     private ActivityResultLauncher mActivityResultLauncher;
77     private List<SubscriptionInfo> mSubscriptions;
78 
79     private View mContentView;
80     private Spinner mSubscriptionSpinner;
81     private Button mInitiateButton;
82     @VisibleForTesting View mEsimContainer;
83     @VisibleForTesting CheckBox mEsimCheckbox;
84 
85     @Override
onCreate(@ullable Bundle savedInstanceState)86     public void onCreate(@Nullable Bundle savedInstanceState) {
87         super.onCreate(savedInstanceState);
88         getActivity().setTitle(R.string.reset_mobile_network_settings_title);
89 
90         mActivityResultLauncher = registerForActivityResult(
91                 new ActivityResultContracts.StartActivityForResult(),
92                 result -> onActivityLauncherResult(result));
93     }
94 
95     /**
96      * Keyguard validation is run using the standard {@link ConfirmLockPattern}
97      * component as a subactivity
98      * @param request the request code to be returned once confirmation finishes
99      * @return true if confirmation launched
100      */
runKeyguardConfirmation(int request)101     private boolean runKeyguardConfirmation(int request) {
102         Resources res = getActivity().getResources();
103         final ChooseLockSettingsHelper.Builder builder =
104                 new ChooseLockSettingsHelper.Builder(getActivity(), this);
105         return builder.setRequestCode(request)
106                 .setTitle(res.getText(R.string.reset_mobile_network_settings_title))
107                 .setActivityResultLauncher(mActivityResultLauncher)
108                 .show();
109     }
110 
onActivityLauncherResult(ActivityResult result)111     public void onActivityLauncherResult(ActivityResult result) {
112         // If the user entered a valid keyguard trace, present the final
113         // confirmation prompt; otherwise, go back to the initial state.
114         if (result.getResultCode() == Activity.RESULT_OK) {
115             showFinalConfirmation();
116         } else if (mContentView != null) {
117             establishInitialState(getActiveSubscriptionInfoList());
118         }
119     }
120 
121     @VisibleForTesting
showFinalConfirmation()122     void showFinalConfirmation() {
123         Bundle args = new Bundle();
124 
125         ResetNetworkRequest request = new ResetNetworkRequest(
126                 ResetNetworkRequest.RESET_CONNECTIVITY_MANAGER |
127                 ResetNetworkRequest.RESET_VPN_MANAGER
128         );
129         if (mSubscriptions != null && mSubscriptions.size() > 0) {
130             int selectedIndex = mSubscriptionSpinner.getSelectedItemPosition();
131             SubscriptionInfo subscription = mSubscriptions.get(selectedIndex);
132             int subId = subscription.getSubscriptionId();
133             request.setResetTelephonyAndNetworkPolicyManager(subId)
134                    .setResetApn(subId);
135         }
136         if (mEsimContainer.getVisibility() == View.VISIBLE && mEsimCheckbox.isChecked()) {
137             request.setResetEsim(getContext().getPackageName())
138                    .writeIntoBundle(args);
139         } else {
140             request.writeIntoBundle(args);
141         }
142 
143         new SubSettingLauncher(getContext())
144                 .setDestination(ResetNetworkConfirm.class.getName())
145                 .setArguments(args)
146                 .setTitleRes(R.string.reset_mobile_network_settings_confirm_title)
147                 .setSourceMetricsCategory(getMetricsCategory())
148                 .launch();
149     }
150 
151     /**
152      * If the user clicks to begin the reset sequence, we next require a
153      * keyguard confirmation if the user has currently enabled one.  If there
154      * is no keyguard available, we simply go to the final confirmation prompt.
155      */
156     private final Button.OnClickListener mInitiateListener = new Button.OnClickListener() {
157 
158         @Override
159         public void onClick(View v) {
160             if (!runKeyguardConfirmation(KEYGUARD_REQUEST)) {
161                 showFinalConfirmation();
162             }
163         }
164     };
165 
166     /**
167      * In its initial state, the activity presents a button for the user to
168      * click in order to initiate a confirmation sequence.  This method is
169      * called from various other points in the code to reset the activity to
170      * this base state.
171      *
172      * <p>Reinflating views from resources is expensive and prevents us from
173      * caching widget pointers, so we use a single-inflate pattern:  we lazy-
174      * inflate each view, caching all of the widget pointers we'll need at the
175      * time, then simply reuse the inflated views directly whenever we need
176      * to change contents.
177      *
178      * @param subscriptionsList is a list of SubscriptionInfo(s) which allow user to select from
179      */
establishInitialState(List<SubscriptionInfo> subscriptionsList)180     private void establishInitialState(List<SubscriptionInfo> subscriptionsList) {
181         mSubscriptionSpinner = (Spinner) mContentView.findViewById(R.id.reset_network_subscription);
182         mEsimContainer = mContentView.findViewById(R.id.erase_esim_container);
183         mEsimCheckbox = mContentView.findViewById(R.id.erase_esim);
184 
185         mSubscriptions = subscriptionsList;
186         if (mSubscriptions != null && mSubscriptions.size() > 0) {
187             // Get the default subscription in the order of data, voice, sms, first up.
188             int defaultSubscription = SubscriptionManager.getDefaultDataSubscriptionId();
189             if (!SubscriptionManager.isUsableSubscriptionId(defaultSubscription)) {
190                 defaultSubscription = SubscriptionManager.getDefaultVoiceSubscriptionId();
191             }
192             if (!SubscriptionManager.isUsableSubscriptionId(defaultSubscription)) {
193                 defaultSubscription = SubscriptionManager.getDefaultSmsSubscriptionId();
194             }
195             if (!SubscriptionManager.isUsableSubscriptionId(defaultSubscription)) {
196                 defaultSubscription = SubscriptionManager.getDefaultSubscriptionId();
197             }
198 
199             int selectedIndex = 0;
200             int size = mSubscriptions.size();
201             List<String> subscriptionNames = new ArrayList<>();
202             for (SubscriptionInfo record : mSubscriptions) {
203                 if (record.getSubscriptionId() == defaultSubscription) {
204                     // Set the first selected value to the default
205                     selectedIndex = subscriptionNames.size();
206                 }
207                 String name = SubscriptionUtil.getUniqueSubscriptionDisplayName(
208                         record, getContext()).toString();
209                 if (TextUtils.isEmpty(name)) {
210                     name = record.getNumber();
211                 }
212                 if (TextUtils.isEmpty(name)) {
213                     CharSequence carrierName = record.getCarrierName();
214                     name = TextUtils.isEmpty(carrierName) ? "" : carrierName.toString();
215                 }
216                 if (TextUtils.isEmpty(name)) {
217                     name = String.format("MCC:%s MNC:%s Slot:%s Id:%s", record.getMcc(),
218                             record.getMnc(), record.getSimSlotIndex(), record.getSubscriptionId());
219                 }
220                 subscriptionNames.add(name);
221             }
222             ArrayAdapter<String> adapter = new ArrayAdapter<String>(getActivity(),
223                     android.R.layout.simple_spinner_item, subscriptionNames);
224             adapter.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item);
225             mSubscriptionSpinner.setAdapter(adapter);
226             mSubscriptionSpinner.setSelection(selectedIndex);
227             if (mSubscriptions.size() > 1) {
228                 mSubscriptionSpinner.setVisibility(View.VISIBLE);
229             } else {
230                 mSubscriptionSpinner.setVisibility(View.INVISIBLE);
231             }
232         } else {
233             mSubscriptionSpinner.setVisibility(View.INVISIBLE);
234         }
235         mInitiateButton = (Button) mContentView.findViewById(R.id.initiate_reset_network);
236         mInitiateButton.setOnClickListener(mInitiateListener);
237         if (showEuiccSettings(getContext())) {
238             mEsimContainer.setVisibility(View.VISIBLE);
239             mEsimContainer.setOnClickListener(new OnClickListener() {
240                 @Override
241                 public void onClick(View v) {
242                     mEsimCheckbox.toggle();
243                 }
244             });
245         } else {
246             mEsimCheckbox.setChecked(false /* checked */);
247         }
248     }
249 
getActiveSubscriptionInfoList()250     private List<SubscriptionInfo> getActiveSubscriptionInfoList() {
251         if (!SubscriptionUtil.isSimHardwareVisible(getActivity())) {
252             return Collections.emptyList();
253         }
254         SubscriptionManager mgr = getActivity().getSystemService(SubscriptionManager.class);
255         if (mgr == null) {
256             Log.w(TAG, "No SubscriptionManager");
257             return Collections.emptyList();
258         }
259         return Optional.ofNullable(mgr.getActiveSubscriptionInfoList())
260                 .orElse(Collections.emptyList());
261     }
262 
263     @Override
onResume()264     public void onResume() {
265         super.onResume();
266 
267         if (mContentView == null) {
268             return;
269         }
270 
271         // update options if subcription has been changed
272         List<SubscriptionInfo> updatedSubscriptions = getActiveSubscriptionInfoList();
273         if ((mSubscriptions != null)
274                 && (mSubscriptions.size() == updatedSubscriptions.size())
275                 && mSubscriptions.containsAll(updatedSubscriptions)) {
276             return;
277         }
278         Log.d(TAG, "subcription list changed");
279         establishInitialState(updatedSubscriptions);
280     }
281 
showEuiccSettings(Context context)282     private boolean showEuiccSettings(Context context) {
283         if (!SubscriptionUtil.isSimHardwareVisible(context)) {
284             return false;
285         }
286         EuiccManager euiccManager =
287                 (EuiccManager) context.getSystemService(Context.EUICC_SERVICE);
288         if (!euiccManager.isEnabled()) {
289             return false;
290         }
291         ContentResolver resolver = context.getContentResolver();
292         return Settings.Global.getInt(resolver, Global.EUICC_PROVISIONED, 0) != 0
293                 || DevelopmentSettingsEnabler.isDevelopmentSettingsEnabled(context);
294     }
295 
296     @Override
onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState)297     public View onCreateView(LayoutInflater inflater, ViewGroup container,
298             Bundle savedInstanceState) {
299         View view = (new ResetNetworkRestrictionViewBuilder(getActivity())).build();
300         if (view != null) {
301             Log.w(TAG, "Access deny.");
302             return view;
303         }
304 
305         mContentView = inflater.inflate(R.layout.reset_mobile_network_settings, null);
306 
307         establishInitialState(getActiveSubscriptionInfoList());
308         return mContentView;
309     }
310 
311     @Override
getMetricsCategory()312     public int getMetricsCategory() {
313         return SettingsEnums.RESET_NETWORK;
314     }
315 }
316