• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2008 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.accounts.Account;
20 import android.accounts.AccountManager;
21 import android.accounts.AuthenticatorDescription;
22 import android.app.Activity;
23 import android.app.Fragment;
24 import android.content.Context;
25 import android.content.Intent;
26 import android.content.pm.PackageManager;
27 import android.content.res.Resources;
28 import android.graphics.drawable.Drawable;
29 import android.os.Bundle;
30 import android.os.Environment;
31 import android.os.SystemProperties;
32 import android.preference.Preference;
33 import android.preference.PreferenceActivity;
34 import android.util.Log;
35 import android.view.LayoutInflater;
36 import android.view.View;
37 import android.view.ViewGroup;
38 import android.widget.Button;
39 import android.widget.CheckBox;
40 import android.widget.LinearLayout;
41 import android.widget.TextView;
42 
43 /**
44  * Confirm and execute a reset of the device to a clean "just out of the box"
45  * state.  Multiple confirmations are required: first, a general "are you sure
46  * you want to do this?" prompt, followed by a keyguard pattern trace if the user
47  * has defined one, followed by a final strongly-worded "THIS WILL ERASE EVERYTHING
48  * ON THE PHONE" prompt.  If at any time the phone is allowed to go to sleep, is
49  * locked, et cetera, then the confirmation sequence is abandoned.
50  *
51  * This is the initial screen.
52  */
53 public class MasterClear extends Fragment {
54     private static final String TAG = "MasterClear";
55 
56     private static final int KEYGUARD_REQUEST = 55;
57 
58     static final String ERASE_EXTERNAL_EXTRA = "erase_sd";
59 
60     private View mContentView;
61     private Button mInitiateButton;
62     private View mExternalStorageContainer;
63     private CheckBox mExternalStorage;
64 
65     /**
66      * Keyguard validation is run using the standard {@link ConfirmLockPattern}
67      * component as a subactivity
68      * @param request the request code to be returned once confirmation finishes
69      * @return true if confirmation launched
70      */
runKeyguardConfirmation(int request)71     private boolean runKeyguardConfirmation(int request) {
72         Resources res = getActivity().getResources();
73         return new ChooseLockSettingsHelper(getActivity(), this)
74                 .launchConfirmationActivity(request,
75                         res.getText(R.string.master_clear_gesture_prompt),
76                         res.getText(R.string.master_clear_gesture_explanation));
77     }
78 
79     @Override
onActivityResult(int requestCode, int resultCode, Intent data)80     public void onActivityResult(int requestCode, int resultCode, Intent data) {
81         super.onActivityResult(requestCode, resultCode, data);
82 
83         if (requestCode != KEYGUARD_REQUEST) {
84             return;
85         }
86 
87         // If the user entered a valid keyguard trace, present the final
88         // confirmation prompt; otherwise, go back to the initial state.
89         if (resultCode == Activity.RESULT_OK) {
90             showFinalConfirmation();
91         } else {
92             establishInitialState();
93         }
94     }
95 
showFinalConfirmation()96     private void showFinalConfirmation() {
97         Preference preference = new Preference(getActivity());
98         preference.setFragment(MasterClearConfirm.class.getName());
99         preference.setTitle(R.string.master_clear_confirm_title);
100         preference.getExtras().putBoolean(ERASE_EXTERNAL_EXTRA, mExternalStorage.isChecked());
101         ((PreferenceActivity) getActivity()).onPreferenceStartFragment(null, preference);
102     }
103 
104     /**
105      * If the user clicks to begin the reset sequence, we next require a
106      * keyguard confirmation if the user has currently enabled one.  If there
107      * is no keyguard available, we simply go to the final confirmation prompt.
108      */
109     private final Button.OnClickListener mInitiateListener = new Button.OnClickListener() {
110 
111         public void onClick(View v) {
112             if (!runKeyguardConfirmation(KEYGUARD_REQUEST)) {
113                 showFinalConfirmation();
114             }
115         }
116     };
117 
118     /**
119      * In its initial state, the activity presents a button for the user to
120      * click in order to initiate a confirmation sequence.  This method is
121      * called from various other points in the code to reset the activity to
122      * this base state.
123      *
124      * <p>Reinflating views from resources is expensive and prevents us from
125      * caching widget pointers, so we use a single-inflate pattern:  we lazy-
126      * inflate each view, caching all of the widget pointers we'll need at the
127      * time, then simply reuse the inflated views directly whenever we need
128      * to change contents.
129      */
establishInitialState()130     private void establishInitialState() {
131         mInitiateButton = (Button) mContentView.findViewById(R.id.initiate_master_clear);
132         mInitiateButton.setOnClickListener(mInitiateListener);
133         mExternalStorageContainer = mContentView.findViewById(R.id.erase_external_container);
134         mExternalStorage = (CheckBox) mContentView.findViewById(R.id.erase_external);
135 
136         /*
137          * If the external storage is emulated, it will be erased with a factory
138          * reset at any rate. There is no need to have a separate option until
139          * we have a factory reset that only erases some directories and not
140          * others. Likewise, if it's non-removable storage, it could potentially have been
141          * encrypted, and will also need to be wiped.
142          */
143         boolean isExtStorageEmulated = Environment.isExternalStorageEmulated();
144         if (isExtStorageEmulated
145                 || (!Environment.isExternalStorageRemovable() && isExtStorageEncrypted())) {
146             mExternalStorageContainer.setVisibility(View.GONE);
147 
148             final View externalOption = mContentView.findViewById(R.id.erase_external_option_text);
149             externalOption.setVisibility(View.GONE);
150 
151             final View externalAlsoErased = mContentView.findViewById(R.id.also_erases_external);
152             externalAlsoErased.setVisibility(View.VISIBLE);
153 
154             // If it's not emulated, it is on a separate partition but it means we're doing
155             // a force wipe due to encryption.
156             mExternalStorage.setChecked(!isExtStorageEmulated);
157         } else {
158             mExternalStorageContainer.setOnClickListener(new View.OnClickListener() {
159 
160                 @Override
161                 public void onClick(View v) {
162                     mExternalStorage.toggle();
163                 }
164             });
165         }
166 
167         loadAccountList();
168     }
169 
isExtStorageEncrypted()170     private boolean isExtStorageEncrypted() {
171         String state = SystemProperties.get("vold.decrypt");
172         return !"".equals(state);
173     }
174 
loadAccountList()175     private void loadAccountList() {
176         View accountsLabel = mContentView.findViewById(R.id.accounts_label);
177         LinearLayout contents = (LinearLayout)mContentView.findViewById(R.id.accounts);
178         contents.removeAllViews();
179 
180         Context context = getActivity();
181 
182         AccountManager mgr = AccountManager.get(context);
183         Account[] accounts = mgr.getAccounts();
184         final int N = accounts.length;
185         if (N == 0) {
186             accountsLabel.setVisibility(View.GONE);
187             contents.setVisibility(View.GONE);
188             return;
189         }
190 
191         LayoutInflater inflater = (LayoutInflater)context.getSystemService(
192                 Context.LAYOUT_INFLATER_SERVICE);
193 
194         AuthenticatorDescription[] descs = AccountManager.get(context).getAuthenticatorTypes();
195         final int M = descs.length;
196 
197         for (int i=0; i<N; i++) {
198             Account account = accounts[i];
199             AuthenticatorDescription desc = null;
200             for (int j=0; j<M; j++) {
201                 if (account.type.equals(descs[j].type)) {
202                     desc = descs[j];
203                     break;
204                 }
205             }
206             if (desc == null) {
207                 Log.w(TAG, "No descriptor for account name=" + account.name
208                         + " type=" + account.type);
209                 continue;
210             }
211             Drawable icon = null;
212             try {
213                 if (desc.iconId != 0) {
214                     Context authContext = context.createPackageContext(desc.packageName, 0);
215                     icon = authContext.getResources().getDrawable(desc.iconId);
216                 }
217             } catch (PackageManager.NameNotFoundException e) {
218                 Log.w(TAG, "No icon for account type " + desc.type);
219             }
220 
221             TextView child = (TextView)inflater.inflate(R.layout.master_clear_account,
222                     contents, false);
223             child.setText(account.name);
224             if (icon != null) {
225                 child.setCompoundDrawablesWithIntrinsicBounds(icon, null, null, null);
226             }
227             contents.addView(child);
228         }
229 
230         accountsLabel.setVisibility(View.VISIBLE);
231         contents.setVisibility(View.VISIBLE);
232     }
233 
234     @Override
onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState)235     public View onCreateView(LayoutInflater inflater, ViewGroup container,
236             Bundle savedInstanceState) {
237         mContentView = inflater.inflate(R.layout.master_clear, null);
238 
239         establishInitialState();
240         return mContentView;
241     }
242 }
243