• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2010 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 
20 import static android.content.Context.MODE_PRIVATE;
21 
22 import static com.android.settingslib.RestrictedLockUtils.EnforcedAdmin;
23 
24 import android.app.ProgressDialog;
25 import android.app.admin.DevicePolicyManager;
26 import android.app.admin.FactoryResetProtectionPolicy;
27 import android.app.settings.SettingsEnums;
28 import android.content.Context;
29 import android.content.Intent;
30 import android.content.SharedPreferences;
31 import android.content.pm.ActivityInfo;
32 import android.os.AsyncTask;
33 import android.os.Bundle;
34 import android.os.SystemProperties;
35 import android.os.UserHandle;
36 import android.os.UserManager;
37 import android.service.oemlock.OemLockManager;
38 import android.service.persistentdata.PersistentDataBlockManager;
39 import android.util.Log;
40 import android.view.LayoutInflater;
41 import android.view.View;
42 import android.view.ViewGroup;
43 import android.widget.Button;
44 
45 import androidx.annotation.VisibleForTesting;
46 
47 import com.android.settings.core.InstrumentedFragment;
48 import com.android.settings.enterprise.ActionDisabledByAdminDialogHelper;
49 import com.android.settings.network.telephony.SubscriptionActionDialogActivity;
50 import com.android.settingslib.RestrictedLockUtilsInternal;
51 
52 import com.google.android.setupcompat.template.FooterBarMixin;
53 import com.google.android.setupcompat.template.FooterButton;
54 import com.google.android.setupcompat.template.FooterButton.ButtonType;
55 import com.google.android.setupcompat.util.WizardManagerHelper;
56 import com.google.android.setupdesign.GlifLayout;
57 
58 /**
59  * Confirm and execute a reset of the device to a clean "just out of the box"
60  * state.  Multiple confirmations are required: first, a general "are you sure
61  * you want to do this?" prompt, followed by a keyguard pattern trace if the user
62  * has defined one, followed by a final strongly-worded "THIS WILL ERASE EVERYTHING
63  * ON THE PHONE" prompt.  If at any time the phone is allowed to go to sleep, is
64  * locked, et cetera, then the confirmation sequence is abandoned.
65  * <p>
66  * This is the confirmation screen.
67  */
68 public class MainClearConfirm extends InstrumentedFragment {
69     private static final String TAG = "MainClearConfirm";
70 
71     private static final String PERSISTENT_DATA_BLOCK_PROP = "ro.frp.pst";
72 
73     @VisibleForTesting
74     GlifLayout mContentView;
75     private boolean mEraseSdCard;
76     @VisibleForTesting
77     boolean mEraseEsims;
78 
79     /**
80      * The user has gone through the multiple confirmation, so now we go ahead
81      * and invoke the Checkin Service to reset the device to its factory-default
82      * state (rebooting in the process).
83      */
84     private Button.OnClickListener mFinalClickListener = new Button.OnClickListener() {
85 
86         public void onClick(View v) {
87             if (Utils.isMonkeyRunning()) {
88                 return;
89             }
90 
91             final PersistentDataBlockManager pdbManager;
92             // pre-flight check hardware support PersistentDataBlockManager
93             if (!SystemProperties.get(PERSISTENT_DATA_BLOCK_PROP).equals("")) {
94                 pdbManager = getActivity().getSystemService(PersistentDataBlockManager.class);
95             } else {
96                 pdbManager = null;
97             }
98             setSimDialogProgressState();
99             if (shouldWipePersistentDataBlock(pdbManager)) {
100 
101                 new AsyncTask<Void, Void, Void>() {
102                     int mOldOrientation;
103                     ProgressDialog mProgressDialog;
104 
105                     @Override
106                     protected Void doInBackground(Void... params) {
107                         pdbManager.wipe();
108                         return null;
109                     }
110 
111                     @Override
112                     protected void onPostExecute(Void aVoid) {
113                         mProgressDialog.hide();
114                         if (getActivity() != null) {
115                             getActivity().setRequestedOrientation(mOldOrientation);
116                             doMainClear();
117                         }
118                     }
119 
120                     @Override
121                     protected void onPreExecute() {
122                         mProgressDialog = getProgressDialog();
123                         mProgressDialog.show();
124 
125                         // need to prevent orientation changes as we're about to go into
126                         // a long IO request, so we won't be able to access inflate resources on
127                         // flash
128                         mOldOrientation = getActivity().getRequestedOrientation();
129                         getActivity().setRequestedOrientation(
130                                 ActivityInfo.SCREEN_ORIENTATION_LOCKED);
131                     }
132                 }.execute();
133             } else {
134                 doMainClear();
135             }
136 
137         }
138 
139         private void setSimDialogProgressState() {
140             if (getActivity() != null) {
141                 final SharedPreferences prefs = getActivity().getSharedPreferences(
142                         SubscriptionActionDialogActivity.SIM_ACTION_DIALOG_PREFS, MODE_PRIVATE);
143                 prefs.edit().putInt(SubscriptionActionDialogActivity.KEY_PROGRESS_STATE,
144                         SubscriptionActionDialogActivity.PROGRESS_IS_SHOWING).apply();
145                 Log.d(TAG, "SIM dialog setProgressState: 1");
146             }
147         }
148 
149         private ProgressDialog getProgressDialog() {
150             final ProgressDialog progressDialog = new ProgressDialog(getActivity());
151             progressDialog.setIndeterminate(true);
152             progressDialog.setCancelable(false);
153             progressDialog.setTitle(
154                     getActivity().getString(R.string.main_clear_progress_title));
155             progressDialog.setMessage(
156                     getActivity().getString(R.string.main_clear_progress_text));
157             return progressDialog;
158         }
159     };
160 
161     @VisibleForTesting
shouldWipePersistentDataBlock(PersistentDataBlockManager pdbManager)162     boolean shouldWipePersistentDataBlock(PersistentDataBlockManager pdbManager) {
163         if (pdbManager == null) {
164             return false;
165         }
166 
167         // Do not try to erase factory reset protection data if the protection is alive.
168         if (pdbManager.isFactoryResetProtectionActive()) {
169             return false;
170         }
171 
172         // The persistent data block will persist if the device is still being provisioned.
173         if (isDeviceStillBeingProvisioned()) {
174             return false;
175         }
176 
177         // If OEM unlock is allowed, the persistent data block will be wiped during the FR
178         // process on devices without FRP Hardening. If disabled, it will be wiped here instead.
179         // On devices with FRP Hardening, the persistent data block should always be wiped,
180         // regardless of the OEM Unlocking state.
181         if (!android.security.Flags.frpEnforcement() && isOemUnlockedAllowed()) {
182             return false;
183         }
184 
185         final DevicePolicyManager dpm = (DevicePolicyManager) getActivity()
186                 .getSystemService(Context.DEVICE_POLICY_SERVICE);
187         // Do not erase the factory reset protection data (from Settings) if factory reset
188         // protection policy is not supported on the device.
189         if (!dpm.isFactoryResetProtectionPolicySupported()) {
190             return false;
191         }
192 
193         // Do not erase the factory reset protection data (from Settings) if the
194         // device is an organization-owned managed profile device and a factory
195         // reset protection policy has been set.
196         FactoryResetProtectionPolicy frpPolicy = dpm.getFactoryResetProtectionPolicy(null);
197         if (dpm.isOrganizationOwnedDeviceWithManagedProfile() && frpPolicy != null
198                 && frpPolicy.isNotEmpty()) {
199             return false;
200         }
201 
202         return true;
203     }
204 
205     @VisibleForTesting
isOemUnlockedAllowed()206     boolean isOemUnlockedAllowed() {
207         return ((OemLockManager) getActivity().getSystemService(
208                 Context.OEM_LOCK_SERVICE)).isOemUnlockAllowed();
209     }
210 
211     @VisibleForTesting
isDeviceStillBeingProvisioned()212     boolean isDeviceStillBeingProvisioned() {
213         return !WizardManagerHelper.isDeviceProvisioned(getActivity());
214     }
215 
doMainClear()216     private void doMainClear() {
217         Intent intent = new Intent(Intent.ACTION_FACTORY_RESET);
218         intent.setPackage("android");
219         intent.addFlags(Intent.FLAG_RECEIVER_FOREGROUND);
220         intent.putExtra(Intent.EXTRA_REASON, "MainClearConfirm");
221         intent.putExtra(Intent.EXTRA_WIPE_EXTERNAL_STORAGE, mEraseSdCard);
222         intent.putExtra(Intent.EXTRA_WIPE_ESIMS, mEraseEsims);
223         getActivity().sendBroadcast(intent);
224         // Intent handling is asynchronous -- assume it will happen soon.
225     }
226 
227     /**
228      * Configure the UI for the final confirmation interaction
229      */
establishFinalConfirmationState()230     private void establishFinalConfirmationState() {
231         final FooterBarMixin mixin = mContentView.getMixin(FooterBarMixin.class);
232         mixin.setPrimaryButton(
233                 new FooterButton.Builder(getActivity())
234                         .setText(R.string.main_clear_button_text)
235                         .setListener(mFinalClickListener)
236                         .setButtonType(ButtonType.OTHER)
237                         .setTheme(com.google.android.setupdesign.R.style.SudGlifButton_Primary)
238                         .build()
239         );
240     }
241 
242     @Override
onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState)243     public View onCreateView(LayoutInflater inflater, ViewGroup container,
244             Bundle savedInstanceState) {
245         final EnforcedAdmin admin = RestrictedLockUtilsInternal.checkIfRestrictionEnforced(
246                 getActivity(), UserManager.DISALLOW_FACTORY_RESET, UserHandle.myUserId());
247         if (RestrictedLockUtilsInternal.hasBaseUserRestriction(getActivity(),
248                 UserManager.DISALLOW_FACTORY_RESET, UserHandle.myUserId())) {
249             return inflater.inflate(R.layout.main_clear_disallowed_screen, null);
250         } else if (admin != null) {
251             new ActionDisabledByAdminDialogHelper(getActivity())
252                     .prepareDialogBuilder(UserManager.DISALLOW_FACTORY_RESET, admin)
253                     .setOnDismissListener(__ -> getActivity().finish())
254                     .show();
255             return new View(getActivity());
256         }
257         mContentView = (GlifLayout) inflater.inflate(R.layout.main_clear_confirm, null);
258         establishFinalConfirmationState();
259         setSubtitle();
260         setAccessibilityTitle();
261         return mContentView;
262     }
263 
setAccessibilityTitle()264     private void setAccessibilityTitle() {
265         CharSequence currentTitle = getActivity().getTitle();
266         CharSequence confirmationMessage = mContentView.getDescriptionText();
267         if (confirmationMessage != null) {
268             String accessibleText = currentTitle + "," + confirmationMessage;
269             getActivity().setTitle(Utils.createAccessibleSequence(currentTitle, accessibleText));
270         }
271     }
272 
273     @VisibleForTesting
setSubtitle()274     void setSubtitle() {
275         mContentView.setDescriptionText(
276                 mEraseEsims ? R.string.main_clear_final_desc_esim : R.string.main_clear_final_desc);
277     }
278 
279     @Override
onCreate(Bundle savedInstanceState)280     public void onCreate(Bundle savedInstanceState) {
281         super.onCreate(savedInstanceState);
282 
283         Bundle args = getArguments();
284         mEraseSdCard = args != null
285                 && args.getBoolean(MainClear.ERASE_EXTERNAL_EXTRA);
286         mEraseEsims = args != null
287                 && args.getBoolean(MainClear.ERASE_ESIMS_EXTRA);
288     }
289 
290     @Override
getMetricsCategory()291     public int getMetricsCategory() {
292         return SettingsEnums.MASTER_CLEAR_CONFIRM;
293     }
294 }
295