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