blob: 6f847f3d53555ebdefc03bc51807461b132bd285 [file] [log] [blame]
Jason parks8fd5bc92011-01-12 16:03:31 -06001/*
2 * Copyright (C) 2011 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
17package com.android.settings;
18
19import com.android.internal.widget.PasswordEntryKeyboardHelper;
20import com.android.internal.widget.PasswordEntryKeyboardView;
21
22import android.app.Activity;
23import android.app.StatusBarManager;
24import android.content.ComponentName;
25import android.content.Context;
Jason parksec5a45e2011-01-18 15:28:36 -060026import android.content.Intent;
Jason parks8fd5bc92011-01-12 16:03:31 -060027import android.content.pm.PackageManager;
28import android.inputmethodservice.KeyboardView;
29import android.os.Bundle;
Jason parksec5a45e2011-01-18 15:28:36 -060030import android.os.Handler;
Jason parks8fd5bc92011-01-12 16:03:31 -060031import android.os.IBinder;
Jason parksec5a45e2011-01-18 15:28:36 -060032import android.os.Message;
Jason parks35933812011-01-21 15:48:20 -060033import android.os.PowerManager;
Jason parks8fd5bc92011-01-12 16:03:31 -060034import android.os.ServiceManager;
35import android.os.SystemProperties;
36import android.os.storage.IMountService;
Jason parksec5a45e2011-01-18 15:28:36 -060037import android.text.TextUtils;
Jason parks8fd5bc92011-01-12 16:03:31 -060038import android.text.format.DateFormat;
39import android.util.Log;
40import android.view.KeyEvent;
41import android.view.inputmethod.EditorInfo;
Jason parksec5a45e2011-01-18 15:28:36 -060042import android.widget.EditText;
43import android.widget.ProgressBar;
Jason parks8fd5bc92011-01-12 16:03:31 -060044import android.widget.TextView;
45
46import java.util.Date;
47
48public class CryptKeeper extends Activity implements TextView.OnEditorActionListener {
Jason parksec5a45e2011-01-18 15:28:36 -060049 private static final String TAG = "CryptKeeper";
Jason parks35933812011-01-21 15:48:20 -060050
Jason parks8fd5bc92011-01-12 16:03:31 -060051 private static final String DECRYPT_STATE = "trigger_restart_framework";
Jason parksec5a45e2011-01-18 15:28:36 -060052
53 private static final int UPDATE_PROGRESS = 1;
54 private static final int COOLDOWN = 2;
55
56 private static final int MAX_FAILED_ATTEMPTS = 30;
57 private static final int COOL_DOWN_ATTEMPTS = 10;
58 private static final int COOL_DOWN_INTERVAL = 30; // 30 seconds
59
Jason parksf1dbf552011-01-24 16:19:28 -060060 // This activity is used to fade the screen to black after the password is entered.
61 public static class Blank extends Activity {
62 }
Jason parksec5a45e2011-01-18 15:28:36 -060063
64 private Handler mHandler = new Handler() {
65 @Override
66 public void handleMessage(Message msg) {
Jason parksec5a45e2011-01-18 15:28:36 -060067 switch (msg.what) {
Jason parksec5a45e2011-01-18 15:28:36 -060068 case UPDATE_PROGRESS:
Jason parksf8217302011-01-26 13:11:42 -060069 updateProgress();
Jason parksec5a45e2011-01-18 15:28:36 -060070 break;
Jason parks35933812011-01-21 15:48:20 -060071
Jason parksec5a45e2011-01-18 15:28:36 -060072 case COOLDOWN:
Jason parksf8217302011-01-26 13:11:42 -060073 cooldown();
Jason parksec5a45e2011-01-18 15:28:36 -060074 break;
75 }
76 }
77 };
Jason parks35933812011-01-21 15:48:20 -060078
Jason parksec5a45e2011-01-18 15:28:36 -060079 private int mCooldown;
Jason parksf8217302011-01-26 13:11:42 -060080 PowerManager.WakeLock mWakeLock;
Jason parks35933812011-01-21 15:48:20 -060081
Jason parks8fd5bc92011-01-12 16:03:31 -060082 @Override
83 public void onCreate(Bundle savedInstanceState) {
84 super.onCreate(savedInstanceState);
Jason parks35933812011-01-21 15:48:20 -060085
Jason parks8fd5bc92011-01-12 16:03:31 -060086 String state = SystemProperties.get("vold.decrypt");
87 if ("".equals(state) || DECRYPT_STATE.equals(state)) {
Jason parks35933812011-01-21 15:48:20 -060088 // Disable the crypt keeper.
Jason parks8fd5bc92011-01-12 16:03:31 -060089 PackageManager pm = getPackageManager();
90 ComponentName name = new ComponentName(this, CryptKeeper.class);
91 pm.setComponentEnabledSetting(name, PackageManager.COMPONENT_ENABLED_STATE_DISABLED, 0);
92 return;
93 }
Jason parks35933812011-01-21 15:48:20 -060094
Jason parksec5a45e2011-01-18 15:28:36 -060095 // Check to see why we were started.
96 String progress = SystemProperties.get("vold.encrypt_progress");
Jason parksdbf43222011-01-20 18:49:58 -060097
98 if (!"".equals(progress)) {
Jason parksec5a45e2011-01-18 15:28:36 -060099 setContentView(R.layout.crypt_keeper_progress);
100 encryptionProgressInit();
101 } else {
102 setContentView(R.layout.crypt_keeper_password_entry);
103 passwordEntryInit();
104 }
Jason parks39f1e042011-01-20 23:29:28 -0600105
106 // Disable the status bar
107 StatusBarManager sbm = (StatusBarManager) getSystemService(Context.STATUS_BAR_SERVICE);
108 sbm.disable(StatusBarManager.DISABLE_EXPAND | StatusBarManager.DISABLE_NOTIFICATION_ICONS
109 | StatusBarManager.DISABLE_NOTIFICATION_ALERTS
110 | StatusBarManager.DISABLE_SYSTEM_INFO | StatusBarManager.DISABLE_NAVIGATION);
Jason parksec5a45e2011-01-18 15:28:36 -0600111 }
Jason parks35933812011-01-21 15:48:20 -0600112
Jason parksf8217302011-01-26 13:11:42 -0600113 @Override
114 public void onStop() {
115 super.onStop();
116
117 mHandler.removeMessages(COOLDOWN);
118 mHandler.removeMessages(UPDATE_PROGRESS);
119
120 if (mWakeLock != null) {
121 mWakeLock.release();
122 mWakeLock = null;
123 }
124 }
125
Jason parksec5a45e2011-01-18 15:28:36 -0600126 private void encryptionProgressInit() {
Jason parks35933812011-01-21 15:48:20 -0600127 // Accquire a partial wakelock to prevent the device from sleeping. Note
128 // we never release this wakelock as we will be restarted after the device
129 // is encrypted.
130
131 PowerManager pm = (PowerManager) getSystemService(Context.POWER_SERVICE);
Jason parksf8217302011-01-26 13:11:42 -0600132 mWakeLock = pm.newWakeLock(PowerManager.FULL_WAKE_LOCK, TAG);
Jason parks35933812011-01-21 15:48:20 -0600133
Jason parksf8217302011-01-26 13:11:42 -0600134 mWakeLock.acquire();
Jason parks35933812011-01-21 15:48:20 -0600135
Jason parksf8217302011-01-26 13:11:42 -0600136 ProgressBar progressBar = (ProgressBar) findViewById(R.id.progress_bar);
137 progressBar.setIndeterminate(true);
138
139 updateProgress();
140 }
141
142 private void updateProgress() {
143 String state = SystemProperties.get("vold.encrypt_progress");
144
145 int progress = 0;
146 try {
147 progress = Integer.parseInt(state);
148 } catch (Exception e) {
149 Log.w(TAG, "Error parsing progress: " + e.toString());
150 }
151
152 CharSequence status = getText(R.string.crypt_keeper_setup_description);
153 TextView tv = (TextView) findViewById(R.id.status);
154 tv.setText(TextUtils.expandTemplate(status, Integer.toString(progress)));
155
156 // Check the progress every 5 seconds
157 mHandler.removeMessages(UPDATE_PROGRESS);
158 mHandler.sendEmptyMessageDelayed(UPDATE_PROGRESS, 5000);
159 }
160
161 private void cooldown() {
162 TextView tv = (TextView) findViewById(R.id.status);
163 if (mCooldown <= 0) {
164 // Re-enable the password entry
165 EditText passwordEntry = (EditText) findViewById(R.id.passwordEntry);
166 passwordEntry.setEnabled(true);
167
168 tv.setText(R.string.try_again);
169
170 } else {
171 CharSequence tempalte = getText(R.string.crypt_keeper_cooldown);
172 tv.setText(TextUtils.expandTemplate(tempalte, Integer.toString(mCooldown)));
173
174 mCooldown--;
175 mHandler.removeMessages(COOLDOWN);
176 mHandler.sendEmptyMessageDelayed(COOLDOWN, 1000); // Tick every second
177 }
Jason parksec5a45e2011-01-18 15:28:36 -0600178 }
Jason parks35933812011-01-21 15:48:20 -0600179
Jason parksec5a45e2011-01-18 15:28:36 -0600180 private void passwordEntryInit() {
Jason parks8fd5bc92011-01-12 16:03:31 -0600181 TextView passwordEntry = (TextView) findViewById(R.id.passwordEntry);
182 passwordEntry.setOnEditorActionListener(this);
Jason parks35933812011-01-21 15:48:20 -0600183
Jason parks8fd5bc92011-01-12 16:03:31 -0600184 KeyboardView keyboardView = (PasswordEntryKeyboardView) findViewById(R.id.keyboard);
Jason parks35933812011-01-21 15:48:20 -0600185
Jason parks8fd5bc92011-01-12 16:03:31 -0600186 PasswordEntryKeyboardHelper keyboardHelper = new PasswordEntryKeyboardHelper(this,
187 keyboardView, passwordEntry, false);
188 keyboardHelper.setKeyboardMode(PasswordEntryKeyboardHelper.KEYBOARD_MODE_ALPHA);
189
190
191 passwordEntry.setCompoundDrawablesWithIntrinsicBounds(android.R.drawable.ic_lock_idle_lock,
192 0, 0, 0);
193
194 String dateFormatString = getString(com.android.internal.R.string.full_wday_month_day_no_year);
195 TextView date = (TextView) findViewById(R.id.date);
196 date.setText(DateFormat.format(dateFormatString, new Date()));
Jason parks8fd5bc92011-01-12 16:03:31 -0600197 }
198
199 private IMountService getMountService() {
200 IBinder service = ServiceManager.getService("mount");
201 if (service != null) {
202 return IMountService.Stub.asInterface(service);
203 }
204 return null;
205 }
206
207 @Override
208 public boolean onEditorAction(TextView v, int actionId, KeyEvent event) {
209 if (actionId == EditorInfo.IME_NULL) {
210 // Get the password
211 String password = v.getText().toString();
212
Jason parksec5a45e2011-01-18 15:28:36 -0600213 if (TextUtils.isEmpty(password)) {
214 return true;
215 }
Jason parks35933812011-01-21 15:48:20 -0600216
Jason parks8fd5bc92011-01-12 16:03:31 -0600217 // Now that we have the password clear the password field.
218 v.setText(null);
219
220 IMountService service = getMountService();
221 try {
Jason parksf1dbf552011-01-24 16:19:28 -0600222 int failedAttempts = service.decryptStorage(password);
Jason parks8fd5bc92011-01-12 16:03:31 -0600223
Jason parksf1dbf552011-01-24 16:19:28 -0600224 if (failedAttempts == 0) {
225 // The password was entered successfully. Start the Blank activity
226 // so this activity animates to black before the devices starts. Note
227 // It has 1 second to complete the animation or it will be frozen
228 // until the boot animation comes back up.
229 Intent intent = new Intent(this, Blank.class);
230 finish();
231 startActivity(intent);
232 } else if (failedAttempts == MAX_FAILED_ATTEMPTS) {
Jason parksec5a45e2011-01-18 15:28:36 -0600233 // Factory reset the device.
234 sendBroadcast(new Intent("android.intent.action.MASTER_CLEAR"));
Jason parksf1dbf552011-01-24 16:19:28 -0600235 } else if ((failedAttempts % COOL_DOWN_ATTEMPTS) == 0) {
Jason parksec5a45e2011-01-18 15:28:36 -0600236 mCooldown = COOL_DOWN_INTERVAL;
237 EditText passwordEntry = (EditText) findViewById(R.id.passwordEntry);
238 passwordEntry.setEnabled(false);
Jason parksf8217302011-01-26 13:11:42 -0600239 cooldown();
Jason parksec5a45e2011-01-18 15:28:36 -0600240 } else {
241 TextView tv = (TextView) findViewById(R.id.status);
242 tv.setText(R.string.try_again);
243 }
Jason parks8fd5bc92011-01-12 16:03:31 -0600244 } catch (Exception e) {
Jason parksec5a45e2011-01-18 15:28:36 -0600245 Log.e(TAG, "Error while decrypting...", e);
Jason parks8fd5bc92011-01-12 16:03:31 -0600246 }
Jason parks35933812011-01-21 15:48:20 -0600247
Jason parks8fd5bc92011-01-12 16:03:31 -0600248 return true;
249 }
250 return false;
251 }
252}