CryptKeeper.java revision 06c5ff4a46686d3f599e40df0768177d3d88913c
18fd5bc9e6ff0d02012df670a6bf4bcdaf903c09dJason parks/*
28fd5bc9e6ff0d02012df670a6bf4bcdaf903c09dJason parks * Copyright (C) 2011 The Android Open Source Project
38fd5bc9e6ff0d02012df670a6bf4bcdaf903c09dJason parks *
48fd5bc9e6ff0d02012df670a6bf4bcdaf903c09dJason parks * Licensed under the Apache License, Version 2.0 (the "License");
58fd5bc9e6ff0d02012df670a6bf4bcdaf903c09dJason parks * you may not use this file except in compliance with the License.
68fd5bc9e6ff0d02012df670a6bf4bcdaf903c09dJason parks * You may obtain a copy of the License at
78fd5bc9e6ff0d02012df670a6bf4bcdaf903c09dJason parks *
88fd5bc9e6ff0d02012df670a6bf4bcdaf903c09dJason parks *      http://www.apache.org/licenses/LICENSE-2.0
98fd5bc9e6ff0d02012df670a6bf4bcdaf903c09dJason parks *
108fd5bc9e6ff0d02012df670a6bf4bcdaf903c09dJason parks * Unless required by applicable law or agreed to in writing, software
118fd5bc9e6ff0d02012df670a6bf4bcdaf903c09dJason parks * distributed under the License is distributed on an "AS IS" BASIS,
128fd5bc9e6ff0d02012df670a6bf4bcdaf903c09dJason parks * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
138fd5bc9e6ff0d02012df670a6bf4bcdaf903c09dJason parks * See the License for the specific language governing permissions and
148fd5bc9e6ff0d02012df670a6bf4bcdaf903c09dJason parks * limitations under the License.
158fd5bc9e6ff0d02012df670a6bf4bcdaf903c09dJason parks */
168fd5bc9e6ff0d02012df670a6bf4bcdaf903c09dJason parks
178fd5bc9e6ff0d02012df670a6bf4bcdaf903c09dJason parkspackage com.android.settings;
188fd5bc9e6ff0d02012df670a6bf4bcdaf903c09dJason parks
198fd5bc9e6ff0d02012df670a6bf4bcdaf903c09dJason parksimport com.android.internal.widget.PasswordEntryKeyboardHelper;
208fd5bc9e6ff0d02012df670a6bf4bcdaf903c09dJason parksimport com.android.internal.widget.PasswordEntryKeyboardView;
218fd5bc9e6ff0d02012df670a6bf4bcdaf903c09dJason parks
228fd5bc9e6ff0d02012df670a6bf4bcdaf903c09dJason parksimport android.app.Activity;
23ec5a45e79cb7161adfabf475342c1e1b25994276Jason parksimport android.app.StatusBarManager;
248fd5bc9e6ff0d02012df670a6bf4bcdaf903c09dJason parksimport android.content.ComponentName;
25de3c9cb412688eb841993ad971d06039d8a952c3Vikram Aggarwalimport android.content.Context;
2606c5ff4a46686d3f599e40df0768177d3d88913cJason parksimport android.content.Intent;
278fd5bc9e6ff0d02012df670a6bf4bcdaf903c09dJason parksimport android.content.pm.PackageManager;
28ec5a45e79cb7161adfabf475342c1e1b25994276Jason parksimport android.graphics.Rect;
298fd5bc9e6ff0d02012df670a6bf4bcdaf903c09dJason parksimport android.inputmethodservice.KeyboardView;
30ec5a45e79cb7161adfabf475342c1e1b25994276Jason parksimport android.os.AsyncTask;
3135933812b16f0b4221280bbcc3c32f6540996bf2Jason parksimport android.os.Bundle;
328373b451692a39abdfd12444241c016831e1a4a4David Brownimport android.os.Handler;
338fd5bc9e6ff0d02012df670a6bf4bcdaf903c09dJason parksimport android.os.IBinder;
348fd5bc9e6ff0d02012df670a6bf4bcdaf903c09dJason parksimport android.os.Message;
358fd5bc9e6ff0d02012df670a6bf4bcdaf903c09dJason parksimport android.os.PowerManager;
368373b451692a39abdfd12444241c016831e1a4a4David Brownimport android.os.ServiceManager;
37ec5a45e79cb7161adfabf475342c1e1b25994276Jason parksimport android.os.SystemProperties;
388fd5bc9e6ff0d02012df670a6bf4bcdaf903c09dJason parksimport android.os.storage.IMountService;
398fd5bc9e6ff0d02012df670a6bf4bcdaf903c09dJason parksimport android.text.TextUtils;
4013d62049f7c96c47356f23eaee7f0997612fdf9fAndy Stadlerimport android.util.AttributeSet;
4113d62049f7c96c47356f23eaee7f0997612fdf9fAndy Stadlerimport android.util.Log;
428fd5bc9e6ff0d02012df670a6bf4bcdaf903c09dJason parksimport android.view.KeyEvent;
439fcb6a7fac02aef85085c2db616556257e1642f5Ben Komaloimport android.view.MotionEvent;
4475c085ee890744cdd4b90c72f8b50e6aeeb31e88Jason parksimport android.view.View;
459fcb6a7fac02aef85085c2db616556257e1642f5Ben Komaloimport android.view.View.OnClickListener;
4613d62049f7c96c47356f23eaee7f0997612fdf9fAndy Stadlerimport android.view.inputmethod.EditorInfo;
47ec5a45e79cb7161adfabf475342c1e1b25994276Jason parksimport android.view.inputmethod.InputMethodManager;
48ec5a45e79cb7161adfabf475342c1e1b25994276Jason parksimport android.widget.Button;
498fd5bc9e6ff0d02012df670a6bf4bcdaf903c09dJason parksimport android.widget.EditText;
508fd5bc9e6ff0d02012df670a6bf4bcdaf903c09dJason parksimport android.widget.ProgressBar;
5191a2f0566afb91549cbda9289b516154a6467624Ben Komaloimport android.widget.TextView;
529fcb6a7fac02aef85085c2db616556257e1642f5Ben Komalo
539fcb6a7fac02aef85085c2db616556257e1642f5Ben Komalopublic class CryptKeeper extends Activity implements TextView.OnEditorActionListener {
5491a2f0566afb91549cbda9289b516154a6467624Ben Komalo    private static final String TAG = "CryptKeeper";
5591a2f0566afb91549cbda9289b516154a6467624Ben Komalo
5691a2f0566afb91549cbda9289b516154a6467624Ben Komalo    private static final String DECRYPT_STATE = "trigger_restart_framework";
5791a2f0566afb91549cbda9289b516154a6467624Ben Komalo
5891a2f0566afb91549cbda9289b516154a6467624Ben Komalo    private static final int UPDATE_PROGRESS = 1;
5991a2f0566afb91549cbda9289b516154a6467624Ben Komalo    private static final int COOLDOWN = 2;
6091a2f0566afb91549cbda9289b516154a6467624Ben Komalo
6191a2f0566afb91549cbda9289b516154a6467624Ben Komalo    private static final int MAX_FAILED_ATTEMPTS = 30;
6291a2f0566afb91549cbda9289b516154a6467624Ben Komalo    private static final int COOL_DOWN_ATTEMPTS = 10;
6391a2f0566afb91549cbda9289b516154a6467624Ben Komalo    private static final int COOL_DOWN_INTERVAL = 30; // 30 seconds
6491a2f0566afb91549cbda9289b516154a6467624Ben Komalo
6591a2f0566afb91549cbda9289b516154a6467624Ben Komalo    private int mCooldown;
6691a2f0566afb91549cbda9289b516154a6467624Ben Komalo    PowerManager.WakeLock mWakeLock;
6791a2f0566afb91549cbda9289b516154a6467624Ben Komalo    private EditText mPasswordEntry;
688fd5bc9e6ff0d02012df670a6bf4bcdaf903c09dJason parks
69ec5a45e79cb7161adfabf475342c1e1b25994276Jason parks    /**
7035933812b16f0b4221280bbcc3c32f6540996bf2Jason parks     * Used to propagate state through configuration changes (e.g. screen rotation)
718fd5bc9e6ff0d02012df670a6bf4bcdaf903c09dJason parks     */
72de3c9cb412688eb841993ad971d06039d8a952c3Vikram Aggarwal    private static class NonConfigurationInstanceState {
73de3c9cb412688eb841993ad971d06039d8a952c3Vikram Aggarwal        final PowerManager.WakeLock wakelock;
74de3c9cb412688eb841993ad971d06039d8a952c3Vikram Aggarwal
75de3c9cb412688eb841993ad971d06039d8a952c3Vikram Aggarwal        NonConfigurationInstanceState(PowerManager.WakeLock _wakelock) {
76de3c9cb412688eb841993ad971d06039d8a952c3Vikram Aggarwal            wakelock = _wakelock;
77de3c9cb412688eb841993ad971d06039d8a952c3Vikram Aggarwal        }
78de3c9cb412688eb841993ad971d06039d8a952c3Vikram Aggarwal    }
79de3c9cb412688eb841993ad971d06039d8a952c3Vikram Aggarwal
80ec5a45e79cb7161adfabf475342c1e1b25994276Jason parks    // This activity is used to fade the screen to black after the password is entered.
81ec5a45e79cb7161adfabf475342c1e1b25994276Jason parks    public static class Blank extends Activity {
82ec5a45e79cb7161adfabf475342c1e1b25994276Jason parks        @Override
83ec5a45e79cb7161adfabf475342c1e1b25994276Jason parks        public void onCreate(Bundle savedInstanceState) {
848373b451692a39abdfd12444241c016831e1a4a4David Brown            super.onCreate(savedInstanceState);
858373b451692a39abdfd12444241c016831e1a4a4David Brown            setContentView(R.layout.crypt_keeper_blank);
868373b451692a39abdfd12444241c016831e1a4a4David Brown        }
8791a2f0566afb91549cbda9289b516154a6467624Ben Komalo    }
8891a2f0566afb91549cbda9289b516154a6467624Ben Komalo
8991a2f0566afb91549cbda9289b516154a6467624Ben Komalo    // Use a custom EditText to prevent the input method from showing.
9091a2f0566afb91549cbda9289b516154a6467624Ben Komalo    public static class CryptEditText extends EditText {
9191a2f0566afb91549cbda9289b516154a6467624Ben Komalo        InputMethodManager imm;
92de3c9cb412688eb841993ad971d06039d8a952c3Vikram Aggarwal
9391a2f0566afb91549cbda9289b516154a6467624Ben Komalo        public CryptEditText(Context context, AttributeSet attrs) {
94bfa3a64310162c8f29eae208220988380ffeea6eVikram Aggarwal            super(context, attrs);
950e66609c95047ba7e5c0408bdc88af4315fd35b1Ben Komalo            imm = ((InputMethodManager) getContext().
96d4758efef6d6564d7b4b0b747d0a9ae9b44a38c7Ben Komalo                    getSystemService(Context.INPUT_METHOD_SERVICE));
970e66609c95047ba7e5c0408bdc88af4315fd35b1Ben Komalo        }
980e66609c95047ba7e5c0408bdc88af4315fd35b1Ben Komalo
99de3c9cb412688eb841993ad971d06039d8a952c3Vikram Aggarwal        @Override
100de3c9cb412688eb841993ad971d06039d8a952c3Vikram Aggarwal        protected void onFocusChanged(boolean focused, int direction, Rect previouslyFocusedRect) {
1010e66609c95047ba7e5c0408bdc88af4315fd35b1Ben Komalo            super.onFocusChanged(focused, direction, previouslyFocusedRect);
1021499740c13af5fbd5766a87825c3e789b37bab24Andy Stadler
1031499740c13af5fbd5766a87825c3e789b37bab24Andy Stadler            if (focused && imm != null && imm.isActive(this)) {
10406c5ff4a46686d3f599e40df0768177d3d88913cJason parks                imm.hideSoftInputFromWindow(getApplicationWindowToken(), 0);
1051499740c13af5fbd5766a87825c3e789b37bab24Andy Stadler            }
1061499740c13af5fbd5766a87825c3e789b37bab24Andy Stadler        }
1071499740c13af5fbd5766a87825c3e789b37bab24Andy Stadler
1081499740c13af5fbd5766a87825c3e789b37bab24Andy Stadler        @Override
1091499740c13af5fbd5766a87825c3e789b37bab24Andy Stadler        public boolean onTouchEvent(MotionEvent event) {
1101499740c13af5fbd5766a87825c3e789b37bab24Andy Stadler            boolean handled = super.onTouchEvent(event);
1111499740c13af5fbd5766a87825c3e789b37bab24Andy Stadler
1121499740c13af5fbd5766a87825c3e789b37bab24Andy Stadler            if (imm != null && imm.isActive(this)) {
1131499740c13af5fbd5766a87825c3e789b37bab24Andy Stadler                imm.hideSoftInputFromWindow(getApplicationWindowToken(), 0);
1141499740c13af5fbd5766a87825c3e789b37bab24Andy Stadler            }
1151499740c13af5fbd5766a87825c3e789b37bab24Andy Stadler
1161499740c13af5fbd5766a87825c3e789b37bab24Andy Stadler            return handled;
117bfa3a64310162c8f29eae208220988380ffeea6eVikram Aggarwal        }
118bfa3a64310162c8f29eae208220988380ffeea6eVikram Aggarwal    }
119bfa3a64310162c8f29eae208220988380ffeea6eVikram Aggarwal
1209f55ae28789754dafeed5c68468d45135d46199eVikram Aggarwal    private class DecryptTask extends AsyncTask<String, Void, Integer> {
12113d62049f7c96c47356f23eaee7f0997612fdf9fAndy Stadler        @Override
12213d62049f7c96c47356f23eaee7f0997612fdf9fAndy Stadler        protected Integer doInBackground(String... params) {
12313d62049f7c96c47356f23eaee7f0997612fdf9fAndy Stadler            IMountService service = getMountService();
12413d62049f7c96c47356f23eaee7f0997612fdf9fAndy Stadler            try {
12513d62049f7c96c47356f23eaee7f0997612fdf9fAndy Stadler                return service.decryptStorage(params[0]);
126de3c9cb412688eb841993ad971d06039d8a952c3Vikram Aggarwal            } catch (Exception e) {
127de3c9cb412688eb841993ad971d06039d8a952c3Vikram Aggarwal                Log.e(TAG, "Error while decrypting...", e);
128de3c9cb412688eb841993ad971d06039d8a952c3Vikram Aggarwal                return -1;
129de3c9cb412688eb841993ad971d06039d8a952c3Vikram Aggarwal            }
130de3c9cb412688eb841993ad971d06039d8a952c3Vikram Aggarwal        }
131f1dbf55819e01f6cf1a99d38a292b15de1262a29Jason parks
132ec5a45e79cb7161adfabf475342c1e1b25994276Jason parks        @Override
13306c5ff4a46686d3f599e40df0768177d3d88913cJason parks        protected void onPostExecute(Integer failedAttempts) {
13406c5ff4a46686d3f599e40df0768177d3d88913cJason parks            if (failedAttempts == 0) {
13506c5ff4a46686d3f599e40df0768177d3d88913cJason parks                // The password was entered successfully. Start the Blank activity
136de3c9cb412688eb841993ad971d06039d8a952c3Vikram Aggarwal                // so this activity animates to black before the devices starts. Note
13706c5ff4a46686d3f599e40df0768177d3d88913cJason parks                // It has 1 second to complete the animation or it will be frozen
13806c5ff4a46686d3f599e40df0768177d3d88913cJason parks                // until the boot animation comes back up.
13906c5ff4a46686d3f599e40df0768177d3d88913cJason parks                Intent intent = new Intent(CryptKeeper.this, Blank.class);
14006c5ff4a46686d3f599e40df0768177d3d88913cJason parks                finish();
14106c5ff4a46686d3f599e40df0768177d3d88913cJason parks                startActivity(intent);
14206c5ff4a46686d3f599e40df0768177d3d88913cJason parks            } else if (failedAttempts == MAX_FAILED_ATTEMPTS) {
14306c5ff4a46686d3f599e40df0768177d3d88913cJason parks                // Factory reset the device.
14406c5ff4a46686d3f599e40df0768177d3d88913cJason parks                sendBroadcast(new Intent("android.intent.action.MASTER_CLEAR"));
14506c5ff4a46686d3f599e40df0768177d3d88913cJason parks            } else if ((failedAttempts % COOL_DOWN_ATTEMPTS) == 0) {
14606c5ff4a46686d3f599e40df0768177d3d88913cJason parks                mCooldown = COOL_DOWN_INTERVAL;
14706c5ff4a46686d3f599e40df0768177d3d88913cJason parks                cooldown();
14806c5ff4a46686d3f599e40df0768177d3d88913cJason parks            } else {
14906c5ff4a46686d3f599e40df0768177d3d88913cJason parks                TextView tv = (TextView) findViewById(R.id.status);
15006c5ff4a46686d3f599e40df0768177d3d88913cJason parks                tv.setText(R.string.try_again);
15106c5ff4a46686d3f599e40df0768177d3d88913cJason parks                tv.setVisibility(View.VISIBLE);
152bfa3a64310162c8f29eae208220988380ffeea6eVikram Aggarwal
15306c5ff4a46686d3f599e40df0768177d3d88913cJason parks                // Reenable the password entry
15406c5ff4a46686d3f599e40df0768177d3d88913cJason parks                mPasswordEntry.setEnabled(true);
15506c5ff4a46686d3f599e40df0768177d3d88913cJason parks            }
15606c5ff4a46686d3f599e40df0768177d3d88913cJason parks        }
15706c5ff4a46686d3f599e40df0768177d3d88913cJason parks    }
15806c5ff4a46686d3f599e40df0768177d3d88913cJason parks
15906c5ff4a46686d3f599e40df0768177d3d88913cJason parks    private Handler mHandler = new Handler() {
16006c5ff4a46686d3f599e40df0768177d3d88913cJason parks        @Override
16106c5ff4a46686d3f599e40df0768177d3d88913cJason parks        public void handleMessage(Message msg) {
162bfa3a64310162c8f29eae208220988380ffeea6eVikram Aggarwal            switch (msg.what) {
163bfa3a64310162c8f29eae208220988380ffeea6eVikram Aggarwal            case UPDATE_PROGRESS:
164bfa3a64310162c8f29eae208220988380ffeea6eVikram Aggarwal                updateProgress();
16506c5ff4a46686d3f599e40df0768177d3d88913cJason parks                break;
16606c5ff4a46686d3f599e40df0768177d3d88913cJason parks
16706c5ff4a46686d3f599e40df0768177d3d88913cJason parks            case COOLDOWN:
16806c5ff4a46686d3f599e40df0768177d3d88913cJason parks                cooldown();
16906c5ff4a46686d3f599e40df0768177d3d88913cJason parks                break;
17006c5ff4a46686d3f599e40df0768177d3d88913cJason parks            }
17175c085ee890744cdd4b90c72f8b50e6aeeb31e88Jason parks        }
1720e66609c95047ba7e5c0408bdc88af4315fd35b1Ben Komalo    };
1730e66609c95047ba7e5c0408bdc88af4315fd35b1Ben Komalo
1740e66609c95047ba7e5c0408bdc88af4315fd35b1Ben Komalo    @Override
175de3c9cb412688eb841993ad971d06039d8a952c3Vikram Aggarwal    public void onCreate(Bundle savedInstanceState) {
1760e66609c95047ba7e5c0408bdc88af4315fd35b1Ben Komalo        super.onCreate(savedInstanceState);
177d4758efef6d6564d7b4b0b747d0a9ae9b44a38c7Ben Komalo
1780e66609c95047ba7e5c0408bdc88af4315fd35b1Ben Komalo        // If we are not encrypted or encrypting, get out quickly.
1790e66609c95047ba7e5c0408bdc88af4315fd35b1Ben Komalo        String state = SystemProperties.get("vold.decrypt");
1800e66609c95047ba7e5c0408bdc88af4315fd35b1Ben Komalo        if ("".equals(state) || DECRYPT_STATE.equals(state)) {
1810e66609c95047ba7e5c0408bdc88af4315fd35b1Ben Komalo            // Disable the crypt keeper.
1820e66609c95047ba7e5c0408bdc88af4315fd35b1Ben Komalo            PackageManager pm = getPackageManager();
1830e66609c95047ba7e5c0408bdc88af4315fd35b1Ben Komalo            ComponentName name = new ComponentName(this, CryptKeeper.class);
1840e66609c95047ba7e5c0408bdc88af4315fd35b1Ben Komalo            pm.setComponentEnabledSetting(name, PackageManager.COMPONENT_ENABLED_STATE_DISABLED, 0);
1850e66609c95047ba7e5c0408bdc88af4315fd35b1Ben Komalo            return;
1860e66609c95047ba7e5c0408bdc88af4315fd35b1Ben Komalo        }
1870e66609c95047ba7e5c0408bdc88af4315fd35b1Ben Komalo
1880e66609c95047ba7e5c0408bdc88af4315fd35b1Ben Komalo        // Disable the status bar
1890e66609c95047ba7e5c0408bdc88af4315fd35b1Ben Komalo        StatusBarManager sbm = (StatusBarManager) getSystemService(Context.STATUS_BAR_SERVICE);
1900e66609c95047ba7e5c0408bdc88af4315fd35b1Ben Komalo        sbm.disable(StatusBarManager.DISABLE_EXPAND
1910e66609c95047ba7e5c0408bdc88af4315fd35b1Ben Komalo                | StatusBarManager.DISABLE_NOTIFICATION_ICONS
1920e66609c95047ba7e5c0408bdc88af4315fd35b1Ben Komalo                | StatusBarManager.DISABLE_NOTIFICATION_ALERTS
1930e66609c95047ba7e5c0408bdc88af4315fd35b1Ben Komalo                | StatusBarManager.DISABLE_SYSTEM_INFO
1940e66609c95047ba7e5c0408bdc88af4315fd35b1Ben Komalo                | StatusBarManager.DISABLE_NAVIGATION
1950e66609c95047ba7e5c0408bdc88af4315fd35b1Ben Komalo                | StatusBarManager.DISABLE_BACK);
196d4758efef6d6564d7b4b0b747d0a9ae9b44a38c7Ben Komalo
197d4758efef6d6564d7b4b0b747d0a9ae9b44a38c7Ben Komalo        // Check for (and recover) retained instance data
1980e66609c95047ba7e5c0408bdc88af4315fd35b1Ben Komalo        Object lastInstance = getLastNonConfigurationInstance();
1990e66609c95047ba7e5c0408bdc88af4315fd35b1Ben Komalo        if (lastInstance instanceof NonConfigurationInstanceState) {
2000e66609c95047ba7e5c0408bdc88af4315fd35b1Ben Komalo            NonConfigurationInstanceState retained = (NonConfigurationInstanceState) lastInstance;
2010e66609c95047ba7e5c0408bdc88af4315fd35b1Ben Komalo            mWakeLock = retained.wakelock;
2020e66609c95047ba7e5c0408bdc88af4315fd35b1Ben Komalo        }
20391a2f0566afb91549cbda9289b516154a6467624Ben Komalo    }
204ec5a45e79cb7161adfabf475342c1e1b25994276Jason parks
205ec5a45e79cb7161adfabf475342c1e1b25994276Jason parks    /**
206ec5a45e79cb7161adfabf475342c1e1b25994276Jason parks     * Note, we defer the state check and screen setup to onStart() because this will be
207de3c9cb412688eb841993ad971d06039d8a952c3Vikram Aggarwal     * re-run if the user clicks the power button (sleeping/waking the screen), and this is
208f8217304073b5cd13823a0602568394be93bf310Jason parks     * especially important if we were to lose the wakelock for any reason.
209ec5a45e79cb7161adfabf475342c1e1b25994276Jason parks     */
21035933812b16f0b4221280bbcc3c32f6540996bf2Jason parks    @Override
211de3c9cb412688eb841993ad971d06039d8a952c3Vikram Aggarwal    public void onStart() {
212f8217304073b5cd13823a0602568394be93bf310Jason parks        super.onStart();
213ec5a45e79cb7161adfabf475342c1e1b25994276Jason parks
214de3c9cb412688eb841993ad971d06039d8a952c3Vikram Aggarwal        // Check to see why we were started.
215de3c9cb412688eb841993ad971d06039d8a952c3Vikram Aggarwal        String progress = SystemProperties.get("vold.encrypt_progress");
216de3c9cb412688eb841993ad971d06039d8a952c3Vikram Aggarwal        if (!"".equals(progress)) {
217de3c9cb412688eb841993ad971d06039d8a952c3Vikram Aggarwal            setContentView(R.layout.crypt_keeper_progress);
218ec5a45e79cb7161adfabf475342c1e1b25994276Jason parks            encryptionProgressInit();
219ec5a45e79cb7161adfabf475342c1e1b25994276Jason parks        } else {
220ec5a45e79cb7161adfabf475342c1e1b25994276Jason parks            setContentView(R.layout.crypt_keeper_password_entry);
22135933812b16f0b4221280bbcc3c32f6540996bf2Jason parks            passwordEntryInit();
222de3c9cb412688eb841993ad971d06039d8a952c3Vikram Aggarwal        }
223de3c9cb412688eb841993ad971d06039d8a952c3Vikram Aggarwal    }
22491a2f0566afb91549cbda9289b516154a6467624Ben Komalo
22591a2f0566afb91549cbda9289b516154a6467624Ben Komalo    @Override
22691a2f0566afb91549cbda9289b516154a6467624Ben Komalo    public void onStop() {
22791a2f0566afb91549cbda9289b516154a6467624Ben Komalo        super.onStop();
22891a2f0566afb91549cbda9289b516154a6467624Ben Komalo
22991a2f0566afb91549cbda9289b516154a6467624Ben Komalo        mHandler.removeMessages(COOLDOWN);
23091a2f0566afb91549cbda9289b516154a6467624Ben Komalo        mHandler.removeMessages(UPDATE_PROGRESS);
23191a2f0566afb91549cbda9289b516154a6467624Ben Komalo    }
23291a2f0566afb91549cbda9289b516154a6467624Ben Komalo
23391a2f0566afb91549cbda9289b516154a6467624Ben Komalo    /**
234de3c9cb412688eb841993ad971d06039d8a952c3Vikram Aggarwal     * Reconfiguring, so propagate the wakelock to the next instance.  This runs between onStop()
235de3c9cb412688eb841993ad971d06039d8a952c3Vikram Aggarwal     * and onDestroy() and only if we are changing configuration (e.g. rotation).  Also clears
236de3c9cb412688eb841993ad971d06039d8a952c3Vikram Aggarwal     * mWakeLock so the subsequent call to onDestroy does not release it.
237de3c9cb412688eb841993ad971d06039d8a952c3Vikram Aggarwal     */
238de3c9cb412688eb841993ad971d06039d8a952c3Vikram Aggarwal    @Override
239de3c9cb412688eb841993ad971d06039d8a952c3Vikram Aggarwal    public Object onRetainNonConfigurationInstance() {
240de3c9cb412688eb841993ad971d06039d8a952c3Vikram Aggarwal        NonConfigurationInstanceState state = new NonConfigurationInstanceState(mWakeLock);
241de3c9cb412688eb841993ad971d06039d8a952c3Vikram Aggarwal        mWakeLock = null;
242de3c9cb412688eb841993ad971d06039d8a952c3Vikram Aggarwal        return state;
243de3c9cb412688eb841993ad971d06039d8a952c3Vikram Aggarwal    }
244de3c9cb412688eb841993ad971d06039d8a952c3Vikram Aggarwal
245de3c9cb412688eb841993ad971d06039d8a952c3Vikram Aggarwal    @Override
246de3c9cb412688eb841993ad971d06039d8a952c3Vikram Aggarwal    public void onDestroy() {
247de3c9cb412688eb841993ad971d06039d8a952c3Vikram Aggarwal        super.onDestroy();
248de3c9cb412688eb841993ad971d06039d8a952c3Vikram Aggarwal
249de3c9cb412688eb841993ad971d06039d8a952c3Vikram Aggarwal        if (mWakeLock != null) {
250de3c9cb412688eb841993ad971d06039d8a952c3Vikram Aggarwal            mWakeLock.release();
251de3c9cb412688eb841993ad971d06039d8a952c3Vikram Aggarwal            mWakeLock = null;
252de3c9cb412688eb841993ad971d06039d8a952c3Vikram Aggarwal        }
253de3c9cb412688eb841993ad971d06039d8a952c3Vikram Aggarwal    }
254de3c9cb412688eb841993ad971d06039d8a952c3Vikram Aggarwal
255de3c9cb412688eb841993ad971d06039d8a952c3Vikram Aggarwal    private void encryptionProgressInit() {
256de3c9cb412688eb841993ad971d06039d8a952c3Vikram Aggarwal        // Accquire a partial wakelock to prevent the device from sleeping. Note
257de3c9cb412688eb841993ad971d06039d8a952c3Vikram Aggarwal        // we never release this wakelock as we will be restarted after the device
258de3c9cb412688eb841993ad971d06039d8a952c3Vikram Aggarwal        // is encrypted.
259de3c9cb412688eb841993ad971d06039d8a952c3Vikram Aggarwal
260de3c9cb412688eb841993ad971d06039d8a952c3Vikram Aggarwal        PowerManager pm = (PowerManager) getSystemService(Context.POWER_SERVICE);
261de3c9cb412688eb841993ad971d06039d8a952c3Vikram Aggarwal        mWakeLock = pm.newWakeLock(PowerManager.FULL_WAKE_LOCK, TAG);
262de3c9cb412688eb841993ad971d06039d8a952c3Vikram Aggarwal
263de3c9cb412688eb841993ad971d06039d8a952c3Vikram Aggarwal        mWakeLock.acquire();
264de3c9cb412688eb841993ad971d06039d8a952c3Vikram Aggarwal
265de3c9cb412688eb841993ad971d06039d8a952c3Vikram Aggarwal        ProgressBar progressBar = (ProgressBar) findViewById(R.id.progress_bar);
266de3c9cb412688eb841993ad971d06039d8a952c3Vikram Aggarwal        progressBar.setIndeterminate(true);
2678fd5bc9e6ff0d02012df670a6bf4bcdaf903c09dJason parks
2688fd5bc9e6ff0d02012df670a6bf4bcdaf903c09dJason parks        updateProgress();
2698fd5bc9e6ff0d02012df670a6bf4bcdaf903c09dJason parks    }
27035933812b16f0b4221280bbcc3c32f6540996bf2Jason parks
2719597406aa1b83867b03a47d1a5162969b924f2fcAndy Stadler    private void showFactoryReset() {
272de3c9cb412688eb841993ad971d06039d8a952c3Vikram Aggarwal        // Hide the encryption-bot to make room for the "factory reset" button
27391a2f0566afb91549cbda9289b516154a6467624Ben Komalo        findViewById(R.id.encroid).setVisibility(View.GONE);
27435933812b16f0b4221280bbcc3c32f6540996bf2Jason parks
2758fd5bc9e6ff0d02012df670a6bf4bcdaf903c09dJason parks        // Show the reset button, failure text, and a divider
2768fd5bc9e6ff0d02012df670a6bf4bcdaf903c09dJason parks        Button button = (Button) findViewById(R.id.factory_reset);
277140f6c6cf705f020c0ee6a2843cf1691cc68e729Dianne Hackborn        button.setVisibility(View.VISIBLE);
278140f6c6cf705f020c0ee6a2843cf1691cc68e729Dianne Hackborn        button.setOnClickListener(new OnClickListener() {
279140f6c6cf705f020c0ee6a2843cf1691cc68e729Dianne Hackborn            public void onClick(View v) {
280644fa4243b4c288c85845b3f86aab25135635729Dianne Hackborn                // Factory reset the device.
281644fa4243b4c288c85845b3f86aab25135635729Dianne Hackborn                sendBroadcast(new Intent("android.intent.action.MASTER_CLEAR"));
282644fa4243b4c288c85845b3f86aab25135635729Dianne Hackborn            }
283140f6c6cf705f020c0ee6a2843cf1691cc68e729Dianne Hackborn        });
284140f6c6cf705f020c0ee6a2843cf1691cc68e729Dianne Hackborn
285140f6c6cf705f020c0ee6a2843cf1691cc68e729Dianne Hackborn        TextView tv = (TextView) findViewById(R.id.title);
286140f6c6cf705f020c0ee6a2843cf1691cc68e729Dianne Hackborn        tv.setText(R.string.crypt_keeper_failed_title);
2878fd5bc9e6ff0d02012df670a6bf4bcdaf903c09dJason parks
2888fd5bc9e6ff0d02012df670a6bf4bcdaf903c09dJason parks        tv = (TextView) findViewById(R.id.status);
28935933812b16f0b4221280bbcc3c32f6540996bf2Jason parks        tv.setText(R.string.crypt_keeper_failed_summary);
290b96b35a62b1f092b6322643c3568f3e712543e53Vikram Aggarwal
291b96b35a62b1f092b6322643c3568f3e712543e53Vikram Aggarwal        View view = findViewById(R.id.bottom_divider);
29239f1e04079976d3d10fdd8e5dd36c833bab8a371Jason parks        view.setVisibility(View.VISIBLE);
29313d62049f7c96c47356f23eaee7f0997612fdf9fAndy Stadler    }
29413d62049f7c96c47356f23eaee7f0997612fdf9fAndy Stadler
29539f1e04079976d3d10fdd8e5dd36c833bab8a371Jason parks    private void updateProgress() {
29613d62049f7c96c47356f23eaee7f0997612fdf9fAndy Stadler        String state = SystemProperties.get("vold.encrypt_progress");
2974d2bfd149118c8b82827d76d1d110fd5c65294c8Daniel Sandler
298b96b35a62b1f092b6322643c3568f3e712543e53Vikram Aggarwal        if ("error_partially_encrypted".equals(state)) {
2991499740c13af5fbd5766a87825c3e789b37bab24Andy Stadler            showFactoryReset();
300de3c9cb412688eb841993ad971d06039d8a952c3Vikram Aggarwal            return;
3011499740c13af5fbd5766a87825c3e789b37bab24Andy Stadler        }
302de3c9cb412688eb841993ad971d06039d8a952c3Vikram Aggarwal
3031499740c13af5fbd5766a87825c3e789b37bab24Andy Stadler        int progress = 0;
3041499740c13af5fbd5766a87825c3e789b37bab24Andy Stadler        try {
3051499740c13af5fbd5766a87825c3e789b37bab24Andy Stadler            progress = Integer.parseInt(state);
3060460675b7c0d5a9b02dae01578c64ff0453e4fb7Ben Komalo        } catch (Exception e) {
3071499740c13af5fbd5766a87825c3e789b37bab24Andy Stadler            Log.w(TAG, "Error parsing progress: " + e.toString());
308ec5a45e79cb7161adfabf475342c1e1b25994276Jason parks        }
30935933812b16f0b4221280bbcc3c32f6540996bf2Jason parks
3109597406aa1b83867b03a47d1a5162969b924f2fcAndy Stadler        CharSequence status = getText(R.string.crypt_keeper_setup_description);
3119597406aa1b83867b03a47d1a5162969b924f2fcAndy Stadler        TextView tv = (TextView) findViewById(R.id.status);
3129597406aa1b83867b03a47d1a5162969b924f2fcAndy Stadler        tv.setText(TextUtils.expandTemplate(status, Integer.toString(progress)));
3139597406aa1b83867b03a47d1a5162969b924f2fcAndy Stadler
3149597406aa1b83867b03a47d1a5162969b924f2fcAndy Stadler        // Check the progress every 5 seconds
3159597406aa1b83867b03a47d1a5162969b924f2fcAndy Stadler        mHandler.removeMessages(UPDATE_PROGRESS);
3169597406aa1b83867b03a47d1a5162969b924f2fcAndy Stadler        mHandler.sendEmptyMessageDelayed(UPDATE_PROGRESS, 5000);
3179597406aa1b83867b03a47d1a5162969b924f2fcAndy Stadler    }
318d4758efef6d6564d7b4b0b747d0a9ae9b44a38c7Ben Komalo
3190e66609c95047ba7e5c0408bdc88af4315fd35b1Ben Komalo    private void cooldown() {
3200e66609c95047ba7e5c0408bdc88af4315fd35b1Ben Komalo        TextView tv = (TextView) findViewById(R.id.status);
3210e66609c95047ba7e5c0408bdc88af4315fd35b1Ben Komalo
3220e66609c95047ba7e5c0408bdc88af4315fd35b1Ben Komalo        if (mCooldown <= 0) {
3230e66609c95047ba7e5c0408bdc88af4315fd35b1Ben Komalo            // Re-enable the password entry
3240e66609c95047ba7e5c0408bdc88af4315fd35b1Ben Komalo            mPasswordEntry.setEnabled(true);
3250e66609c95047ba7e5c0408bdc88af4315fd35b1Ben Komalo
3260e66609c95047ba7e5c0408bdc88af4315fd35b1Ben Komalo            tv.setVisibility(View.GONE);
3270e66609c95047ba7e5c0408bdc88af4315fd35b1Ben Komalo        } else {
3280e66609c95047ba7e5c0408bdc88af4315fd35b1Ben Komalo            CharSequence template = getText(R.string.crypt_keeper_cooldown);
3290e66609c95047ba7e5c0408bdc88af4315fd35b1Ben Komalo            tv.setText(TextUtils.expandTemplate(template, Integer.toString(mCooldown)));
3300e66609c95047ba7e5c0408bdc88af4315fd35b1Ben Komalo
3310e66609c95047ba7e5c0408bdc88af4315fd35b1Ben Komalo            tv.setVisibility(View.VISIBLE);
332de3c9cb412688eb841993ad971d06039d8a952c3Vikram Aggarwal
3330e66609c95047ba7e5c0408bdc88af4315fd35b1Ben Komalo            mCooldown--;
3349597406aa1b83867b03a47d1a5162969b924f2fcAndy Stadler            mHandler.removeMessages(COOLDOWN);
3359597406aa1b83867b03a47d1a5162969b924f2fcAndy Stadler            mHandler.sendEmptyMessageDelayed(COOLDOWN, 1000); // Tick every second
336de3c9cb412688eb841993ad971d06039d8a952c3Vikram Aggarwal        }
3379597406aa1b83867b03a47d1a5162969b924f2fcAndy Stadler    }
3389597406aa1b83867b03a47d1a5162969b924f2fcAndy Stadler
339d4758efef6d6564d7b4b0b747d0a9ae9b44a38c7Ben Komalo    private void passwordEntryInit() {
340d4758efef6d6564d7b4b0b747d0a9ae9b44a38c7Ben Komalo        mPasswordEntry = (EditText) findViewById(R.id.passwordEntry);
341d4758efef6d6564d7b4b0b747d0a9ae9b44a38c7Ben Komalo        mPasswordEntry.setOnEditorActionListener(this);
342d4758efef6d6564d7b4b0b747d0a9ae9b44a38c7Ben Komalo
3439597406aa1b83867b03a47d1a5162969b924f2fcAndy Stadler        KeyboardView keyboardView = (PasswordEntryKeyboardView) findViewById(R.id.keyboard);
3449597406aa1b83867b03a47d1a5162969b924f2fcAndy Stadler
3459597406aa1b83867b03a47d1a5162969b924f2fcAndy Stadler        PasswordEntryKeyboardHelper keyboardHelper = new PasswordEntryKeyboardHelper(this,
346f8217304073b5cd13823a0602568394be93bf310Jason parks                keyboardView, mPasswordEntry, false);
347f8217304073b5cd13823a0602568394be93bf310Jason parks        keyboardHelper.setKeyboardMode(PasswordEntryKeyboardHelper.KEYBOARD_MODE_ALPHA);
348f8217304073b5cd13823a0602568394be93bf310Jason parks    }
349de3c9cb412688eb841993ad971d06039d8a952c3Vikram Aggarwal
350de3c9cb412688eb841993ad971d06039d8a952c3Vikram Aggarwal    private IMountService getMountService() {
351de3c9cb412688eb841993ad971d06039d8a952c3Vikram Aggarwal        IBinder service = ServiceManager.getService("mount");
3521499740c13af5fbd5766a87825c3e789b37bab24Andy Stadler        if (service != null) {
3531499740c13af5fbd5766a87825c3e789b37bab24Andy Stadler            return IMountService.Stub.asInterface(service);
3541499740c13af5fbd5766a87825c3e789b37bab24Andy Stadler        }
3551499740c13af5fbd5766a87825c3e789b37bab24Andy Stadler        return null;
3561499740c13af5fbd5766a87825c3e789b37bab24Andy Stadler    }
3571499740c13af5fbd5766a87825c3e789b37bab24Andy Stadler
3581499740c13af5fbd5766a87825c3e789b37bab24Andy Stadler    @Override
3591499740c13af5fbd5766a87825c3e789b37bab24Andy Stadler    public boolean onEditorAction(TextView v, int actionId, KeyEvent event) {
3601499740c13af5fbd5766a87825c3e789b37bab24Andy Stadler        if (actionId == EditorInfo.IME_NULL) {
3611499740c13af5fbd5766a87825c3e789b37bab24Andy Stadler            // Get the password
3620460675b7c0d5a9b02dae01578c64ff0453e4fb7Ben Komalo            String password = v.getText().toString();
3631499740c13af5fbd5766a87825c3e789b37bab24Andy Stadler
3641499740c13af5fbd5766a87825c3e789b37bab24Andy Stadler            if (TextUtils.isEmpty(password)) {
3651499740c13af5fbd5766a87825c3e789b37bab24Andy Stadler                return true;
3661499740c13af5fbd5766a87825c3e789b37bab24Andy Stadler            }
3671499740c13af5fbd5766a87825c3e789b37bab24Andy Stadler
3681499740c13af5fbd5766a87825c3e789b37bab24Andy Stadler            // Now that we have the password clear the password field.
3691499740c13af5fbd5766a87825c3e789b37bab24Andy Stadler            v.setText(null);
370f8217304073b5cd13823a0602568394be93bf310Jason parks
371f8217304073b5cd13823a0602568394be93bf310Jason parks            // Disable the password entry while checking the password. This
3720460675b7c0d5a9b02dae01578c64ff0453e4fb7Ben Komalo            // we either be reenabled if the password was wrong or after the
373f8217304073b5cd13823a0602568394be93bf310Jason parks            // cooldown period.
374f8217304073b5cd13823a0602568394be93bf310Jason parks            mPasswordEntry.setEnabled(false);
375f8217304073b5cd13823a0602568394be93bf310Jason parks
376f8217304073b5cd13823a0602568394be93bf310Jason parks            new DecryptTask().execute(password);
377f8217304073b5cd13823a0602568394be93bf310Jason parks
378de3c9cb412688eb841993ad971d06039d8a952c3Vikram Aggarwal            return true;
379de3c9cb412688eb841993ad971d06039d8a952c3Vikram Aggarwal        }
380de3c9cb412688eb841993ad971d06039d8a952c3Vikram Aggarwal        return false;
381ec5a45e79cb7161adfabf475342c1e1b25994276Jason parks    }
38235933812b16f0b4221280bbcc3c32f6540996bf2Jason parks}