blob: 88b344e9906728bf9f822a229af2378cb4f4ad42 [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 parks8fd5bc92011-01-12 16:03:31 -060033import android.os.ServiceManager;
34import android.os.SystemProperties;
35import android.os.storage.IMountService;
Jason parksec5a45e2011-01-18 15:28:36 -060036import android.text.TextUtils;
Jason parks8fd5bc92011-01-12 16:03:31 -060037import android.text.format.DateFormat;
38import android.util.Log;
39import android.view.KeyEvent;
40import android.view.inputmethod.EditorInfo;
Jason parksec5a45e2011-01-18 15:28:36 -060041import android.widget.EditText;
42import android.widget.ProgressBar;
Jason parks8fd5bc92011-01-12 16:03:31 -060043import android.widget.TextView;
44
45import java.util.Date;
46
47public class CryptKeeper extends Activity implements TextView.OnEditorActionListener {
Jason parksec5a45e2011-01-18 15:28:36 -060048 private static final String TAG = "CryptKeeper";
49
Jason parks8fd5bc92011-01-12 16:03:31 -060050 private static final String DECRYPT_STATE = "trigger_restart_framework";
Jason parksec5a45e2011-01-18 15:28:36 -060051
52 private static final int UPDATE_PROGRESS = 1;
53 private static final int COOLDOWN = 2;
54
55 private static final int MAX_FAILED_ATTEMPTS = 30;
56 private static final int COOL_DOWN_ATTEMPTS = 10;
57 private static final int COOL_DOWN_INTERVAL = 30; // 30 seconds
58
59
60 private Handler mHandler = new Handler() {
61 @Override
62 public void handleMessage(Message msg) {
63
64 switch (msg.what) {
65
66 case UPDATE_PROGRESS:
67 String state = SystemProperties.get("vold.encrypt_progress");
68
69 ProgressBar progressBar = (ProgressBar) findViewById(R.id.progress_bar);
70 progressBar.setProgress(0);
71
72 try {
73 int progress = Integer.parseInt(state);
74 progressBar.setProgress(progress);
75 } catch (Exception e) {
76 Log.w(TAG, "Error parsing progress: " + e.toString());
77 }
78
79 // Check the status every 1 second
80 sendEmptyMessageDelayed(0, 1000);
81 break;
82
83 case COOLDOWN:
84 TextView tv = (TextView) findViewById(R.id.status);
85 if (mCooldown <= 0) {
86 // Re-enable the password entry
87 EditText passwordEntry = (EditText) findViewById(R.id.passwordEntry);
88 passwordEntry.setEnabled(true);
89
90 tv.setText(R.string.try_again);
91
92 } else {
93
94 CharSequence tempalte = getText(R.string.crypt_keeper_cooldown);
95 tv.setText(TextUtils.expandTemplate(tempalte, Integer.toString(mCooldown)));
96
97 mCooldown--;
98 mHandler.sendEmptyMessageDelayed(COOLDOWN, 1000); // Tick every second
99 }
100 break;
101 }
102 }
103 };
104
105 private int mFailedAttempts = 0;
106 private int mCooldown;
Jason parks8fd5bc92011-01-12 16:03:31 -0600107
108 @Override
109 public void onCreate(Bundle savedInstanceState) {
110 super.onCreate(savedInstanceState);
Jason parks8fd5bc92011-01-12 16:03:31 -0600111
112 String state = SystemProperties.get("vold.decrypt");
113 if ("".equals(state) || DECRYPT_STATE.equals(state)) {
Jason parksec5a45e2011-01-18 15:28:36 -0600114 // Disable the crypt keeper.
Jason parks8fd5bc92011-01-12 16:03:31 -0600115 PackageManager pm = getPackageManager();
116 ComponentName name = new ComponentName(this, CryptKeeper.class);
117 pm.setComponentEnabledSetting(name, PackageManager.COMPONENT_ENABLED_STATE_DISABLED, 0);
118 return;
119 }
120
Jason parksec5a45e2011-01-18 15:28:36 -0600121 // Check to see why we were started.
122 String progress = SystemProperties.get("vold.encrypt_progress");
123 if ("startup".equals(progress)) {
124 setContentView(R.layout.crypt_keeper_progress);
125 encryptionProgressInit();
126 } else {
127 setContentView(R.layout.crypt_keeper_password_entry);
128 passwordEntryInit();
129 }
130 }
131
132 private void encryptionProgressInit() {
133 mHandler.sendEmptyMessage(UPDATE_PROGRESS);
134 }
135
136 private void passwordEntryInit() {
Jason parks8fd5bc92011-01-12 16:03:31 -0600137 TextView passwordEntry = (TextView) findViewById(R.id.passwordEntry);
138 passwordEntry.setOnEditorActionListener(this);
139
140 KeyboardView keyboardView = (PasswordEntryKeyboardView) findViewById(R.id.keyboard);
141
142 PasswordEntryKeyboardHelper keyboardHelper = new PasswordEntryKeyboardHelper(this,
143 keyboardView, passwordEntry, false);
144 keyboardHelper.setKeyboardMode(PasswordEntryKeyboardHelper.KEYBOARD_MODE_ALPHA);
145
146
147 passwordEntry.setCompoundDrawablesWithIntrinsicBounds(android.R.drawable.ic_lock_idle_lock,
148 0, 0, 0);
149
150 String dateFormatString = getString(com.android.internal.R.string.full_wday_month_day_no_year);
151 TextView date = (TextView) findViewById(R.id.date);
152 date.setText(DateFormat.format(dateFormatString, new Date()));
153
154 // Disable the status bar
155 StatusBarManager sbm = (StatusBarManager) getSystemService(Context.STATUS_BAR_SERVICE);
156 sbm.disable(StatusBarManager.DISABLE_EXPAND | StatusBarManager.DISABLE_NOTIFICATION_ICONS
157 | StatusBarManager.DISABLE_NOTIFICATION_ALERTS
158 | StatusBarManager.DISABLE_SYSTEM_INFO | StatusBarManager.DISABLE_NAVIGATION);
159 }
160
161 private IMountService getMountService() {
162 IBinder service = ServiceManager.getService("mount");
163 if (service != null) {
164 return IMountService.Stub.asInterface(service);
165 }
166 return null;
167 }
168
169 @Override
170 public boolean onEditorAction(TextView v, int actionId, KeyEvent event) {
171 if (actionId == EditorInfo.IME_NULL) {
172 // Get the password
173 String password = v.getText().toString();
174
Jason parksec5a45e2011-01-18 15:28:36 -0600175 if (TextUtils.isEmpty(password)) {
176 return true;
177 }
178
Jason parks8fd5bc92011-01-12 16:03:31 -0600179 // Now that we have the password clear the password field.
180 v.setText(null);
181
182 IMountService service = getMountService();
183 try {
184 service.decryptStorage(password);
185
186 // For now the only way to get here is for the password to be
187 // wrong.
188
Jason parksec5a45e2011-01-18 15:28:36 -0600189 mFailedAttempts++;
190
191 if (mFailedAttempts == MAX_FAILED_ATTEMPTS) {
192 // Factory reset the device.
193 sendBroadcast(new Intent("android.intent.action.MASTER_CLEAR"));
194 } else if ((mFailedAttempts % COOL_DOWN_ATTEMPTS) == 0) {
195 mCooldown = COOL_DOWN_INTERVAL;
196 EditText passwordEntry = (EditText) findViewById(R.id.passwordEntry);
197 passwordEntry.setEnabled(false);
198 mHandler.sendEmptyMessage(COOLDOWN);
199 } else {
200 TextView tv = (TextView) findViewById(R.id.status);
201 tv.setText(R.string.try_again);
202 }
Jason parks8fd5bc92011-01-12 16:03:31 -0600203 } catch (Exception e) {
Jason parksec5a45e2011-01-18 15:28:36 -0600204 Log.e(TAG, "Error while decrypting...", e);
Jason parks8fd5bc92011-01-12 16:03:31 -0600205 }
206
207 return true;
208 }
209 return false;
210 }
211}