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.content.ContentResolver; 22 import android.content.Context; 23 import android.content.Intent; 24 import android.content.res.Resources; 25 import android.os.Bundle; 26 import android.os.UserHandle; 27 import android.os.UserManager; 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.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 import android.widget.TextView; 43 44 import com.android.internal.logging.nano.MetricsProto.MetricsEvent; 45 import com.android.internal.telephony.PhoneConstants; 46 import com.android.settings.core.InstrumentedFragment; 47 import com.android.settings.core.SubSettingLauncher; 48 import com.android.settings.enterprise.ActionDisabledByAdminDialogHelper; 49 import com.android.settings.password.ChooseLockSettingsHelper; 50 import com.android.settings.password.ConfirmLockPattern; 51 import com.android.settingslib.RestrictedLockUtils; 52 import com.android.settingslib.RestrictedLockUtils.EnforcedAdmin; 53 54 import java.util.ArrayList; 55 import java.util.List; 56 57 /** 58 * Confirm and execute a reset of the device's network settings to a clean "just out of the box" 59 * state. Multiple confirmations are required: first, a general "are you sure you want to do this?" 60 * prompt, followed by a keyguard pattern trace if the user has defined one, followed by a final 61 * strongly-worded "THIS WILL RESET EVERYTHING" prompt. If at any time the phone is allowed to go 62 * to sleep, is locked, et cetera, then the confirmation sequence is abandoned. 63 * 64 * This is the initial screen. 65 */ 66 public class ResetNetwork extends InstrumentedFragment { 67 private static final String TAG = "ResetNetwork"; 68 69 // Arbitrary to avoid conficts 70 private static final int KEYGUARD_REQUEST = 55; 71 72 private List<SubscriptionInfo> mSubscriptions; 73 74 private View mContentView; 75 private Spinner mSubscriptionSpinner; 76 private Button mInitiateButton; 77 private View mEsimContainer; 78 private CheckBox mEsimCheckbox; 79 80 @Override 81 public void onCreate(@Nullable Bundle savedInstanceState) { 82 super.onCreate(savedInstanceState); 83 getActivity().setTitle(R.string.reset_network_title); 84 } 85 86 /** 87 * Keyguard validation is run using the standard {@link ConfirmLockPattern} 88 * component as a subactivity 89 * @param request the request code to be returned once confirmation finishes 90 * @return true if confirmation launched 91 */ 92 private boolean runKeyguardConfirmation(int request) { 93 Resources res = getActivity().getResources(); 94 return new ChooseLockSettingsHelper(getActivity(), this).launchConfirmationActivity( 95 request, res.getText(R.string.reset_network_title)); 96 } 97 98 @Override 99 public void onActivityResult(int requestCode, int resultCode, Intent data) { 100 super.onActivityResult(requestCode, resultCode, data); 101 102 if (requestCode != KEYGUARD_REQUEST) { 103 return; 104 } 105 106 // If the user entered a valid keyguard trace, present the final 107 // confirmation prompt; otherwise, go back to the initial state. 108 if (resultCode == Activity.RESULT_OK) { 109 showFinalConfirmation(); 110 } else { 111 establishInitialState(); 112 } 113 } 114 115 private void showFinalConfirmation() { 116 Bundle args = new Bundle(); 117 if (mSubscriptions != null && mSubscriptions.size() > 0) { 118 int selectedIndex = mSubscriptionSpinner.getSelectedItemPosition(); 119 SubscriptionInfo subscription = mSubscriptions.get(selectedIndex); 120 args.putInt(PhoneConstants.SUBSCRIPTION_KEY, subscription.getSubscriptionId()); 121 } 122 args.putBoolean(MasterClear.ERASE_ESIMS_EXTRA, mEsimCheckbox.isChecked()); 123 new SubSettingLauncher(getContext()) 124 .setDestination(ResetNetworkConfirm.class.getName()) 125 .setArguments(args) 126 .setTitle(R.string.reset_network_confirm_title) 127 .setSourceMetricsCategory(getMetricsCategory()) 128 .launch(); 129 } 130 131 /** 132 * If the user clicks to begin the reset sequence, we next require a 133 * keyguard confirmation if the user has currently enabled one. If there 134 * is no keyguard available, we simply go to the final confirmation prompt. 135 */ 136 private final Button.OnClickListener mInitiateListener = new Button.OnClickListener() { 137 138 @Override 139 public void onClick(View v) { 140 if (!runKeyguardConfirmation(KEYGUARD_REQUEST)) { 141 showFinalConfirmation(); 142 } 143 } 144 }; 145 146 /** 147 * In its initial state, the activity presents a button for the user to 148 * click in order to initiate a confirmation sequence. This method is 149 * called from various other points in the code to reset the activity to 150 * this base state. 151 * 152 * <p>Reinflating views from resources is expensive and prevents us from 153 * caching widget pointers, so we use a single-inflate pattern: we lazy- 154 * inflate each view, caching all of the widget pointers we'll need at the 155 * time, then simply reuse the inflated views directly whenever we need 156 * to change contents. 157 */ 158 private void establishInitialState() { 159 mSubscriptionSpinner = (Spinner) mContentView.findViewById(R.id.reset_network_subscription); 160 mEsimContainer = mContentView.findViewById(R.id.erase_esim_container); 161 mEsimCheckbox = mContentView.findViewById(R.id.erase_esim); 162 163 mSubscriptions = SubscriptionManager.from(getActivity()).getActiveSubscriptionInfoList(); 164 if (mSubscriptions != null && mSubscriptions.size() > 0) { 165 // Get the default subscription in the order of data, voice, sms, first up. 166 int defaultSubscription = SubscriptionManager.getDefaultDataSubscriptionId(); 167 if (!SubscriptionManager.isUsableSubIdValue(defaultSubscription)) { 168 defaultSubscription = SubscriptionManager.getDefaultVoiceSubscriptionId(); 169 } 170 if (!SubscriptionManager.isUsableSubIdValue(defaultSubscription)) { 171 defaultSubscription = SubscriptionManager.getDefaultSmsSubscriptionId(); 172 } 173 if (!SubscriptionManager.isUsableSubIdValue(defaultSubscription)) { 174 defaultSubscription = SubscriptionManager.getDefaultSubscriptionId(); 175 } 176 177 int selectedIndex = 0; 178 int size = mSubscriptions.size(); 179 List<String> subscriptionNames = new ArrayList<>(); 180 for (SubscriptionInfo record : mSubscriptions) { 181 if (record.getSubscriptionId() == defaultSubscription) { 182 // Set the first selected value to the default 183 selectedIndex = subscriptionNames.size(); 184 } 185 String name = record.getDisplayName().toString(); 186 if (TextUtils.isEmpty(name)) { 187 name = record.getNumber(); 188 } 189 if (TextUtils.isEmpty(name)) { 190 name = record.getCarrierName().toString(); 191 } 192 if (TextUtils.isEmpty(name)) { 193 name = String.format("MCC:%s MNC:%s Slot:%s Id:%s", record.getMcc(), 194 record.getMnc(), record.getSimSlotIndex(), record.getSubscriptionId()); 195 } 196 subscriptionNames.add(name); 197 } 198 ArrayAdapter<String> adapter = new ArrayAdapter<String>(getActivity(), 199 android.R.layout.simple_spinner_item, subscriptionNames); 200 adapter.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item); 201 mSubscriptionSpinner.setAdapter(adapter); 202 mSubscriptionSpinner.setSelection(selectedIndex); 203 if (mSubscriptions.size() > 1) { 204 mSubscriptionSpinner.setVisibility(View.VISIBLE); 205 } else { 206 mSubscriptionSpinner.setVisibility(View.INVISIBLE); 207 } 208 } else { 209 mSubscriptionSpinner.setVisibility(View.INVISIBLE); 210 } 211 mInitiateButton = (Button) mContentView.findViewById(R.id.initiate_reset_network); 212 mInitiateButton.setOnClickListener(mInitiateListener); 213 if (showEuiccSettings(getContext())) { 214 mEsimContainer.setVisibility(View.VISIBLE); 215 TextView title = mContentView.findViewById(R.id.erase_esim_title); 216 title.setText(R.string.reset_esim_title); 217 mEsimContainer.setOnClickListener(new OnClickListener() { 218 @Override 219 public void onClick(View v) { 220 mEsimCheckbox.toggle(); 221 } 222 }); 223 } else { 224 mEsimCheckbox.setChecked(false /* checked */); 225 } 226 } 227 228 private boolean showEuiccSettings(Context context) { 229 EuiccManager euiccManager = 230 (EuiccManager) context.getSystemService(Context.EUICC_SERVICE); 231 if (!euiccManager.isEnabled()) { 232 return false; 233 } 234 ContentResolver resolver = context.getContentResolver(); 235 return Settings.Global.getInt(resolver, Global.EUICC_PROVISIONED, 0) != 0 236 || Settings.Global.getInt(resolver, Global.DEVELOPMENT_SETTINGS_ENABLED, 0) != 0; 237 } 238 239 @Override 240 public View onCreateView(LayoutInflater inflater, ViewGroup container, 241 Bundle savedInstanceState) { 242 final UserManager um = UserManager.get(getActivity()); 243 final EnforcedAdmin admin = RestrictedLockUtils.checkIfRestrictionEnforced( 244 getActivity(), UserManager.DISALLOW_NETWORK_RESET, UserHandle.myUserId()); 245 if (!um.isAdminUser() || RestrictedLockUtils.hasBaseUserRestriction(getActivity(), 246 UserManager.DISALLOW_NETWORK_RESET, UserHandle.myUserId())) { 247 return inflater.inflate(R.layout.network_reset_disallowed_screen, null); 248 } else if (admin != null) { 249 new ActionDisabledByAdminDialogHelper(getActivity()) 250 .prepareDialogBuilder(UserManager.DISALLOW_NETWORK_RESET, admin) 251 .setOnDismissListener(__ -> getActivity().finish()) 252 .show(); 253 return new View(getContext()); 254 } 255 256 mContentView = inflater.inflate(R.layout.reset_network, null); 257 258 establishInitialState(); 259 return mContentView; 260 } 261 262 @Override 263 public int getMetricsCategory() { 264 return MetricsEvent.RESET_NETWORK; 265 } 266 } 267