• 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 com.android.internal.widget.LockPatternUtils;
20 
21 import android.app.Activity;
22 import android.app.AlertDialog;
23 import android.app.Fragment;
24 import android.app.admin.DevicePolicyManager;
25 import android.content.BroadcastReceiver;
26 import android.content.Context;
27 import android.content.Intent;
28 import android.content.IntentFilter;
29 import android.content.res.Resources;
30 import android.os.BatteryManager;
31 import android.os.Bundle;
32 import android.preference.Preference;
33 import android.preference.PreferenceActivity;
34 import android.text.TextUtils;
35 import android.view.LayoutInflater;
36 import android.view.View;
37 import android.view.ViewGroup;
38 import android.widget.Button;
39 
40 public class CryptKeeperSettings extends Fragment {
41     private static final String TAG = "CryptKeeper";
42 
43     private static final int KEYGUARD_REQUEST = 55;
44 
45     // This is the minimum acceptable password quality.  If the current password quality is
46     // lower than this, encryption should not be activated.
47     static final int MIN_PASSWORD_QUALITY = DevicePolicyManager.PASSWORD_QUALITY_NUMERIC;
48 
49     // Minimum battery charge level (in percent) to launch encryption.  If the battery charge is
50     // lower than this, encryption should not be activated.
51     private static final int MIN_BATTERY_LEVEL = 80;
52 
53     private View mContentView;
54     private Button mInitiateButton;
55     private View mPowerWarning;
56     private View mBatteryWarning;
57     private IntentFilter mIntentFilter;
58 
59     private BroadcastReceiver mIntentReceiver = new BroadcastReceiver() {
60         @Override
61         public void onReceive(Context context, Intent intent) {
62             String action = intent.getAction();
63             if (action.equals(Intent.ACTION_BATTERY_CHANGED)) {
64                 int level = intent.getIntExtra(BatteryManager.EXTRA_LEVEL, 0);
65                 int plugged = intent.getIntExtra(BatteryManager.EXTRA_PLUGGED, 0);
66                 int invalidCharger = intent.getIntExtra(BatteryManager.EXTRA_INVALID_CHARGER, 0);
67 
68                 boolean levelOk = level >= MIN_BATTERY_LEVEL;
69                 boolean pluggedOk =
70                     (plugged == BatteryManager.BATTERY_PLUGGED_AC ||
71                      plugged == BatteryManager.BATTERY_PLUGGED_USB) &&
72                      invalidCharger == 0;
73 
74                 // Update UI elements based on power/battery status
75                 mInitiateButton.setEnabled(levelOk && pluggedOk);
76                 mPowerWarning.setVisibility(pluggedOk ? View.GONE : View.VISIBLE );
77                 mBatteryWarning.setVisibility(levelOk ? View.GONE : View.VISIBLE);
78             }
79         }
80     };
81 
82     /**
83      * If the user clicks to begin the reset sequence, we next require a
84      * keyguard confirmation if the user has currently enabled one.  If there
85      * is no keyguard available, we prompt the user to set a password.
86      */
87     private Button.OnClickListener mInitiateListener = new Button.OnClickListener() {
88 
89         public void onClick(View v) {
90             if (!runKeyguardConfirmation(KEYGUARD_REQUEST)) {
91                 // TODO replace (or follow) this dialog with an explicit launch into password UI
92                 new AlertDialog.Builder(getActivity())
93                     .setTitle(R.string.crypt_keeper_dialog_need_password_title)
94                     .setIcon(android.R.drawable.ic_dialog_alert)
95                     .setMessage(R.string.crypt_keeper_dialog_need_password_message)
96                     .setPositiveButton(android.R.string.ok, null)
97                     .create()
98                     .show();
99             }
100         }
101     };
102 
103     @Override
onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedState)104     public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedState) {
105         mContentView = inflater.inflate(R.layout.crypt_keeper_settings, null);
106 
107         mIntentFilter = new IntentFilter();
108         mIntentFilter.addAction(Intent.ACTION_BATTERY_CHANGED);
109 
110         mInitiateButton = (Button) mContentView.findViewById(R.id.initiate_encrypt);
111         mInitiateButton.setOnClickListener(mInitiateListener);
112         mInitiateButton.setEnabled(false);
113 
114         mPowerWarning = mContentView.findViewById(R.id.warning_unplugged);
115         mBatteryWarning = mContentView.findViewById(R.id.warning_low_charge);
116 
117         return mContentView;
118     }
119 
120     @Override
onResume()121     public void onResume() {
122         super.onResume();
123         getActivity().registerReceiver(mIntentReceiver, mIntentFilter);
124     }
125 
126     @Override
onPause()127     public void onPause() {
128         super.onPause();
129         getActivity().unregisterReceiver(mIntentReceiver);
130     }
131 
132     /**
133      * If encryption is already started, and this launched via a "start encryption" intent,
134      * then exit immediately - it's already up and running, so there's no point in "starting" it.
135      */
136     @Override
onActivityCreated(Bundle savedInstanceState)137     public void onActivityCreated(Bundle savedInstanceState) {
138         super.onActivityCreated(savedInstanceState);
139         Activity activity = getActivity();
140         Intent intent = activity.getIntent();
141         if (DevicePolicyManager.ACTION_START_ENCRYPTION.equals(intent.getAction())) {
142             DevicePolicyManager dpm = (DevicePolicyManager)
143                     activity.getSystemService(Context.DEVICE_POLICY_SERVICE);
144             if (dpm != null) {
145                 int status = dpm.getStorageEncryptionStatus();
146                 if (status != DevicePolicyManager.ENCRYPTION_STATUS_INACTIVE) {
147                     // There is nothing to do here, so simply finish() (which returns to caller)
148                     activity.finish();
149                 }
150             }
151         }
152     }
153 
154     /**
155      * Keyguard validation is run using the standard {@link ConfirmLockPattern}
156      * component as a subactivity
157      * @param request the request code to be returned once confirmation finishes
158      * @return true if confirmation launched
159      */
runKeyguardConfirmation(int request)160     private boolean runKeyguardConfirmation(int request) {
161         // 1.  Confirm that we have a sufficient PIN/Password to continue
162         LockPatternUtils lockPatternUtils = new LockPatternUtils(getActivity());
163         int quality = lockPatternUtils.getActivePasswordQuality();
164         if (quality == DevicePolicyManager.PASSWORD_QUALITY_BIOMETRIC_WEAK
165             && lockPatternUtils.isLockPasswordEnabled()) {
166             // Use the alternate as the quality. We expect this to be
167             // PASSWORD_QUALITY_SOMETHING(pattern) or PASSWORD_QUALITY_NUMERIC(PIN).
168             quality = lockPatternUtils.getKeyguardStoredPasswordQuality();
169         }
170         if (quality < MIN_PASSWORD_QUALITY) {
171             return false;
172         }
173         // 2.  Ask the user to confirm the current PIN/Password
174         Resources res = getActivity().getResources();
175         return new ChooseLockSettingsHelper(getActivity(), this)
176                 .launchConfirmationActivity(request,
177                         res.getText(R.string.master_clear_gesture_prompt),
178                         res.getText(R.string.master_clear_gesture_explanation));
179     }
180 
181     @Override
onActivityResult(int requestCode, int resultCode, Intent data)182     public void onActivityResult(int requestCode, int resultCode, Intent data) {
183         super.onActivityResult(requestCode, resultCode, data);
184 
185         if (requestCode != KEYGUARD_REQUEST) {
186             return;
187         }
188 
189         // If the user entered a valid keyguard trace, present the final
190         // confirmation prompt; otherwise, go back to the initial state.
191         if (resultCode == Activity.RESULT_OK && data != null) {
192             String password = data.getStringExtra(ChooseLockSettingsHelper.EXTRA_KEY_PASSWORD);
193             if (!TextUtils.isEmpty(password)) {
194                 showFinalConfirmation(password);
195             }
196         }
197     }
198 
showFinalConfirmation(String password)199     private void showFinalConfirmation(String password) {
200         Preference preference = new Preference(getActivity());
201         preference.setFragment(CryptKeeperConfirm.class.getName());
202         preference.setTitle(R.string.crypt_keeper_confirm_title);
203         preference.getExtras().putString("password", password);
204         ((PreferenceActivity) getActivity()).onPreferenceStartFragment(null, preference);
205     }
206 }
207 
208