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