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