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