Stuart Scott | be90341 | 2014-07-24 19:22:06 -0700 | [diff] [blame] | 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 | |
Doris Ling | ed4685f | 2017-10-25 14:08:57 -0700 | [diff] [blame] | 19 | import android.annotation.Nullable; |
Stuart Scott | be90341 | 2014-07-24 19:22:06 -0700 | [diff] [blame] | 20 | import android.app.Activity; |
Fan Zhang | 31b2100 | 2019-01-16 13:49:47 -0800 | [diff] [blame] | 21 | import android.app.settings.SettingsEnums; |
Qingxi Li | 0caad2f | 2018-01-05 10:52:42 -0800 | [diff] [blame] | 22 | import android.content.ContentResolver; |
| 23 | import android.content.Context; |
Stuart Scott | be90341 | 2014-07-24 19:22:06 -0700 | [diff] [blame] | 24 | import android.content.Intent; |
Stuart Scott | be90341 | 2014-07-24 19:22:06 -0700 | [diff] [blame] | 25 | import android.content.res.Resources; |
Stuart Scott | be90341 | 2014-07-24 19:22:06 -0700 | [diff] [blame] | 26 | import android.os.Bundle; |
Sudheer Shanka | 7dbbe13 | 2016-02-16 14:19:32 +0000 | [diff] [blame] | 27 | import android.os.UserHandle; |
Stuart Scott | be90341 | 2014-07-24 19:22:06 -0700 | [diff] [blame] | 28 | import android.os.UserManager; |
Qingxi Li | 0caad2f | 2018-01-05 10:52:42 -0800 | [diff] [blame] | 29 | import android.provider.Settings; |
| 30 | import android.provider.Settings.Global; |
Stuart Scott | be90341 | 2014-07-24 19:22:06 -0700 | [diff] [blame] | 31 | import android.telephony.SubscriptionInfo; |
| 32 | import android.telephony.SubscriptionManager; |
Qingxi Li | 0caad2f | 2018-01-05 10:52:42 -0800 | [diff] [blame] | 33 | import android.telephony.euicc.EuiccManager; |
Stuart Scott | be90341 | 2014-07-24 19:22:06 -0700 | [diff] [blame] | 34 | import android.text.TextUtils; |
Stuart Scott | be90341 | 2014-07-24 19:22:06 -0700 | [diff] [blame] | 35 | import android.view.LayoutInflater; |
| 36 | import android.view.View; |
Qingxi Li | 0caad2f | 2018-01-05 10:52:42 -0800 | [diff] [blame] | 37 | import android.view.View.OnClickListener; |
Stuart Scott | be90341 | 2014-07-24 19:22:06 -0700 | [diff] [blame] | 38 | import android.view.ViewGroup; |
| 39 | import android.widget.ArrayAdapter; |
| 40 | import android.widget.Button; |
Qingxi Li | 0caad2f | 2018-01-05 10:52:42 -0800 | [diff] [blame] | 41 | import android.widget.CheckBox; |
Stuart Scott | be90341 | 2014-07-24 19:22:06 -0700 | [diff] [blame] | 42 | import android.widget.Spinner; |
Stuart Scott | be90341 | 2014-07-24 19:22:06 -0700 | [diff] [blame] | 43 | |
Andrew Sapperstein | 88930e3 | 2019-03-07 14:18:15 -0800 | [diff] [blame] | 44 | import androidx.annotation.VisibleForTesting; |
| 45 | |
Doris Ling | 7248972 | 2017-11-16 11:03:40 -0800 | [diff] [blame] | 46 | import com.android.settings.core.InstrumentedFragment; |
Fan Zhang | 7cf99f5 | 2018-02-16 10:37:37 -0800 | [diff] [blame] | 47 | import com.android.settings.core.SubSettingLauncher; |
arangelov | 9308154 | 2017-10-27 13:51:28 +0100 | [diff] [blame] | 48 | import com.android.settings.enterprise.ActionDisabledByAdminDialogHelper; |
Maurice Lam | 2eb170c | 2017-04-28 16:18:47 -0700 | [diff] [blame] | 49 | import com.android.settings.password.ChooseLockSettingsHelper; |
| 50 | import com.android.settings.password.ConfirmLockPattern; |
Maurice Lam | 2eb170c | 2017-04-28 16:18:47 -0700 | [diff] [blame] | 51 | import com.android.settingslib.RestrictedLockUtils.EnforcedAdmin; |
Philip P. Moltmann | e3f7211 | 2018-08-28 15:01:43 -0700 | [diff] [blame] | 52 | import com.android.settingslib.RestrictedLockUtilsInternal; |
Taesu Lee | 39e4fbb | 2019-07-22 19:20:05 +0900 | [diff] [blame] | 53 | import com.android.settingslib.development.DevelopmentSettingsEnabler; |
Stuart Scott | be90341 | 2014-07-24 19:22:06 -0700 | [diff] [blame] | 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 | */ |
Doris Ling | 7248972 | 2017-11-16 11:03:40 -0800 | [diff] [blame] | 67 | public class ResetNetwork extends InstrumentedFragment { |
Stuart Scott | be90341 | 2014-07-24 19:22:06 -0700 | [diff] [blame] | 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; |
Andrew Sapperstein | 88930e3 | 2019-03-07 14:18:15 -0800 | [diff] [blame] | 78 | @VisibleForTesting View mEsimContainer; |
| 79 | @VisibleForTesting CheckBox mEsimCheckbox; |
Stuart Scott | be90341 | 2014-07-24 19:22:06 -0700 | [diff] [blame] | 80 | |
Doris Ling | 03a3b51 | 2017-10-18 14:25:01 -0700 | [diff] [blame] | 81 | @Override |
Doris Ling | ed4685f | 2017-10-25 14:08:57 -0700 | [diff] [blame] | 82 | public void onCreate(@Nullable Bundle savedInstanceState) { |
| 83 | super.onCreate(savedInstanceState); |
Doris Ling | 4a01283 | 2017-11-13 17:58:13 -0800 | [diff] [blame] | 84 | getActivity().setTitle(R.string.reset_network_title); |
Doris Ling | 03a3b51 | 2017-10-18 14:25:01 -0700 | [diff] [blame] | 85 | } |
| 86 | |
Stuart Scott | be90341 | 2014-07-24 19:22:06 -0700 | [diff] [blame] | 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 | */ |
| 93 | private boolean runKeyguardConfirmation(int request) { |
| 94 | Resources res = getActivity().getResources(); |
Jorim Jaggi | 8a09b61 | 2015-04-06 17:47:18 -0700 | [diff] [blame] | 95 | return new ChooseLockSettingsHelper(getActivity(), this).launchConfirmationActivity( |
| 96 | request, res.getText(R.string.reset_network_title)); |
Stuart Scott | be90341 | 2014-07-24 19:22:06 -0700 | [diff] [blame] | 97 | } |
| 98 | |
| 99 | @Override |
| 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 | |
Andrew Sapperstein | 88930e3 | 2019-03-07 14:18:15 -0800 | [diff] [blame] | 116 | @VisibleForTesting |
| 117 | void showFinalConfirmation() { |
Stuart Scott | be90341 | 2014-07-24 19:22:06 -0700 | [diff] [blame] | 118 | Bundle args = new Bundle(); |
Stuart Scott | 754b566 | 2015-03-19 16:02:09 -0700 | [diff] [blame] | 119 | if (mSubscriptions != null && mSubscriptions.size() > 0) { |
Stuart Scott | be90341 | 2014-07-24 19:22:06 -0700 | [diff] [blame] | 120 | int selectedIndex = mSubscriptionSpinner.getSelectedItemPosition(); |
| 121 | SubscriptionInfo subscription = mSubscriptions.get(selectedIndex); |
tom hsu | a381196 | 2020-01-14 14:46:09 +0800 | [diff] [blame] | 122 | args.putInt(SubscriptionManager.EXTRA_SUBSCRIPTION_INDEX, |
| 123 | subscription.getSubscriptionId()); |
Stuart Scott | be90341 | 2014-07-24 19:22:06 -0700 | [diff] [blame] | 124 | } |
Andrew Sapperstein | 88930e3 | 2019-03-07 14:18:15 -0800 | [diff] [blame] | 125 | args.putBoolean(MasterClear.ERASE_ESIMS_EXTRA, |
tom hsu | a381196 | 2020-01-14 14:46:09 +0800 | [diff] [blame] | 126 | mEsimContainer.getVisibility() == View.VISIBLE && mEsimCheckbox.isChecked()); |
Fan Zhang | 7cf99f5 | 2018-02-16 10:37:37 -0800 | [diff] [blame] | 127 | new SubSettingLauncher(getContext()) |
| 128 | .setDestination(ResetNetworkConfirm.class.getName()) |
| 129 | .setArguments(args) |
hjchangliao | e86eec0 | 2018-05-02 13:01:07 +0800 | [diff] [blame] | 130 | .setTitleRes(R.string.reset_network_confirm_title) |
Fan Zhang | 7cf99f5 | 2018-02-16 10:37:37 -0800 | [diff] [blame] | 131 | .setSourceMetricsCategory(getMetricsCategory()) |
| 132 | .launch(); |
Stuart Scott | be90341 | 2014-07-24 19:22:06 -0700 | [diff] [blame] | 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 | */ |
| 162 | private void establishInitialState() { |
| 163 | mSubscriptionSpinner = (Spinner) mContentView.findViewById(R.id.reset_network_subscription); |
Qingxi Li | 0caad2f | 2018-01-05 10:52:42 -0800 | [diff] [blame] | 164 | mEsimContainer = mContentView.findViewById(R.id.erase_esim_container); |
| 165 | mEsimCheckbox = mContentView.findViewById(R.id.erase_esim); |
Stuart Scott | be90341 | 2014-07-24 19:22:06 -0700 | [diff] [blame] | 166 | |
Malcolm Chen | 14dde50 | 2019-01-14 15:13:10 -0800 | [diff] [blame] | 167 | mSubscriptions = SubscriptionManager.from(getActivity()) |
Bonian Chen | 1247771 | 2019-12-16 13:55:54 +0800 | [diff] [blame] | 168 | .getActiveSubscriptionInfoList(); |
Stuart Scott | 9302830 | 2015-03-19 14:48:37 -0700 | [diff] [blame] | 169 | if (mSubscriptions != null && mSubscriptions.size() > 0) { |
Stuart Scott | be90341 | 2014-07-24 19:22:06 -0700 | [diff] [blame] | 170 | // Get the default subscription in the order of data, voice, sms, first up. |
Shishir Agrawal | d2b0fc0 | 2016-01-25 14:05:32 -0800 | [diff] [blame] | 171 | int defaultSubscription = SubscriptionManager.getDefaultDataSubscriptionId(); |
changbetty | ebe36cf | 2020-01-08 22:06:26 +0800 | [diff] [blame] | 172 | if (!SubscriptionManager.isUsableSubscriptionId(defaultSubscription)) { |
Shishir Agrawal | d2b0fc0 | 2016-01-25 14:05:32 -0800 | [diff] [blame] | 173 | defaultSubscription = SubscriptionManager.getDefaultVoiceSubscriptionId(); |
Stuart Scott | be90341 | 2014-07-24 19:22:06 -0700 | [diff] [blame] | 174 | } |
changbetty | ebe36cf | 2020-01-08 22:06:26 +0800 | [diff] [blame] | 175 | if (!SubscriptionManager.isUsableSubscriptionId(defaultSubscription)) { |
Shishir Agrawal | d2b0fc0 | 2016-01-25 14:05:32 -0800 | [diff] [blame] | 176 | defaultSubscription = SubscriptionManager.getDefaultSmsSubscriptionId(); |
Stuart Scott | be90341 | 2014-07-24 19:22:06 -0700 | [diff] [blame] | 177 | } |
changbetty | ebe36cf | 2020-01-08 22:06:26 +0800 | [diff] [blame] | 178 | if (!SubscriptionManager.isUsableSubscriptionId(defaultSubscription)) { |
Shishir Agrawal | d2b0fc0 | 2016-01-25 14:05:32 -0800 | [diff] [blame] | 179 | defaultSubscription = SubscriptionManager.getDefaultSubscriptionId(); |
Stuart Scott | be90341 | 2014-07-24 19:22:06 -0700 | [diff] [blame] | 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); |
Meng Wang | dfba923 | 2016-08-01 10:19:15 -0700 | [diff] [blame] | 208 | if (mSubscriptions.size() > 1) { |
| 209 | mSubscriptionSpinner.setVisibility(View.VISIBLE); |
| 210 | } else { |
| 211 | mSubscriptionSpinner.setVisibility(View.INVISIBLE); |
| 212 | } |
Stuart Scott | be90341 | 2014-07-24 19:22:06 -0700 | [diff] [blame] | 213 | } else { |
| 214 | mSubscriptionSpinner.setVisibility(View.INVISIBLE); |
| 215 | } |
| 216 | mInitiateButton = (Button) mContentView.findViewById(R.id.initiate_reset_network); |
| 217 | mInitiateButton.setOnClickListener(mInitiateListener); |
Qingxi Li | 0caad2f | 2018-01-05 10:52:42 -0800 | [diff] [blame] | 218 | if (showEuiccSettings(getContext())) { |
| 219 | mEsimContainer.setVisibility(View.VISIBLE); |
Qingxi Li | 0caad2f | 2018-01-05 10:52:42 -0800 | [diff] [blame] | 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 | |
| 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 |
Taesu Lee | 39e4fbb | 2019-07-22 19:20:05 +0900 | [diff] [blame] | 239 | || DevelopmentSettingsEnabler.isDevelopmentSettingsEnabled(context); |
Stuart Scott | be90341 | 2014-07-24 19:22:06 -0700 | [diff] [blame] | 240 | } |
| 241 | |
| 242 | @Override |
| 243 | public View onCreateView(LayoutInflater inflater, ViewGroup container, |
| 244 | Bundle savedInstanceState) { |
Xiaohui Chen | 44879a3 | 2015-07-22 13:53:22 -0700 | [diff] [blame] | 245 | final UserManager um = UserManager.get(getActivity()); |
Philip P. Moltmann | e3f7211 | 2018-08-28 15:01:43 -0700 | [diff] [blame] | 246 | final EnforcedAdmin admin = RestrictedLockUtilsInternal.checkIfRestrictionEnforced( |
Sudheer Shanka | 7dbbe13 | 2016-02-16 14:19:32 +0000 | [diff] [blame] | 247 | getActivity(), UserManager.DISALLOW_NETWORK_RESET, UserHandle.myUserId()); |
Philip P. Moltmann | e3f7211 | 2018-08-28 15:01:43 -0700 | [diff] [blame] | 248 | if (!um.isAdminUser() || RestrictedLockUtilsInternal.hasBaseUserRestriction(getActivity(), |
Sudheer Shanka | 7dbbe13 | 2016-02-16 14:19:32 +0000 | [diff] [blame] | 249 | UserManager.DISALLOW_NETWORK_RESET, UserHandle.myUserId())) { |
Stuart Scott | 176f512 | 2015-04-20 11:05:43 -0700 | [diff] [blame] | 250 | return inflater.inflate(R.layout.network_reset_disallowed_screen, null); |
Sudheer Shanka | 7dbbe13 | 2016-02-16 14:19:32 +0000 | [diff] [blame] | 251 | } else if (admin != null) { |
arangelov | 9308154 | 2017-10-27 13:51:28 +0100 | [diff] [blame] | 252 | new ActionDisabledByAdminDialogHelper(getActivity()) |
| 253 | .prepareDialogBuilder(UserManager.DISALLOW_NETWORK_RESET, admin) |
| 254 | .setOnDismissListener(__ -> getActivity().finish()) |
| 255 | .show(); |
| 256 | return new View(getContext()); |
Stuart Scott | 176f512 | 2015-04-20 11:05:43 -0700 | [diff] [blame] | 257 | } |
| 258 | |
Stuart Scott | be90341 | 2014-07-24 19:22:06 -0700 | [diff] [blame] | 259 | mContentView = inflater.inflate(R.layout.reset_network, null); |
| 260 | |
| 261 | establishInitialState(); |
| 262 | return mContentView; |
| 263 | } |
Chris Wren | 8a963ba | 2015-03-20 10:29:14 -0400 | [diff] [blame] | 264 | |
| 265 | @Override |
Fan Zhang | 6507613 | 2016-08-08 10:25:13 -0700 | [diff] [blame] | 266 | public int getMetricsCategory() { |
Fan Zhang | 31b2100 | 2019-01-16 13:49:47 -0800 | [diff] [blame] | 267 | return SettingsEnums.RESET_NETWORK; |
Chris Wren | 8a963ba | 2015-03-20 10:29:14 -0400 | [diff] [blame] | 268 | } |
Stuart Scott | be90341 | 2014-07-24 19:22:06 -0700 | [diff] [blame] | 269 | } |