CryptKeeper.java revision 00046d6e176eb05c3e3b0d13d38a8da7491bba5e
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;
238fd5bc9e6ff0d02012df670a6bf4bcdaf903c09dJason parksimport android.app.StatusBarManager;
248fd5bc9e6ff0d02012df670a6bf4bcdaf903c09dJason parksimport android.content.ComponentName;
258fd5bc9e6ff0d02012df670a6bf4bcdaf903c09dJason parksimport android.content.Context;
26ec5a45e79cb7161adfabf475342c1e1b25994276Jason parksimport android.content.Intent;
278fd5bc9e6ff0d02012df670a6bf4bcdaf903c09dJason parksimport android.content.pm.PackageManager;
2875c085ee890744cdd4b90c72f8b50e6aeeb31e88Jason parksimport android.graphics.Rect;
298fd5bc9e6ff0d02012df670a6bf4bcdaf903c09dJason parksimport android.inputmethodservice.KeyboardView;
3006c5ff4a46686d3f599e40df0768177d3d88913cJason parksimport android.os.AsyncTask;
318fd5bc9e6ff0d02012df670a6bf4bcdaf903c09dJason parksimport android.os.Bundle;
32ec5a45e79cb7161adfabf475342c1e1b25994276Jason parksimport android.os.Handler;
338fd5bc9e6ff0d02012df670a6bf4bcdaf903c09dJason parksimport android.os.IBinder;
34ec5a45e79cb7161adfabf475342c1e1b25994276Jason parksimport android.os.Message;
3535933812b16f0b4221280bbcc3c32f6540996bf2Jason parksimport android.os.PowerManager;
368fd5bc9e6ff0d02012df670a6bf4bcdaf903c09dJason parksimport android.os.ServiceManager;
378fd5bc9e6ff0d02012df670a6bf4bcdaf903c09dJason parksimport android.os.SystemProperties;
388fd5bc9e6ff0d02012df670a6bf4bcdaf903c09dJason parksimport android.os.storage.IMountService;
39ec5a45e79cb7161adfabf475342c1e1b25994276Jason parksimport android.text.TextUtils;
4075c085ee890744cdd4b90c72f8b50e6aeeb31e88Jason parksimport android.util.AttributeSet;
418fd5bc9e6ff0d02012df670a6bf4bcdaf903c09dJason parksimport android.util.Log;
428fd5bc9e6ff0d02012df670a6bf4bcdaf903c09dJason parksimport android.view.KeyEvent;
4375c085ee890744cdd4b90c72f8b50e6aeeb31e88Jason parksimport android.view.MotionEvent;
4413d62049f7c96c47356f23eaee7f0997612fdf9fAndy Stadlerimport android.view.View;
4513d62049f7c96c47356f23eaee7f0997612fdf9fAndy Stadlerimport android.view.View.OnClickListener;
468fd5bc9e6ff0d02012df670a6bf4bcdaf903c09dJason parksimport android.view.inputmethod.EditorInfo;
4775c085ee890744cdd4b90c72f8b50e6aeeb31e88Jason parksimport android.view.inputmethod.InputMethodManager;
4813d62049f7c96c47356f23eaee7f0997612fdf9fAndy Stadlerimport android.widget.Button;
49ec5a45e79cb7161adfabf475342c1e1b25994276Jason parksimport android.widget.EditText;
50ec5a45e79cb7161adfabf475342c1e1b25994276Jason parksimport android.widget.ProgressBar;
518fd5bc9e6ff0d02012df670a6bf4bcdaf903c09dJason parksimport android.widget.TextView;
528fd5bc9e6ff0d02012df670a6bf4bcdaf903c09dJason parks
538fd5bc9e6ff0d02012df670a6bf4bcdaf903c09dJason parkspublic class CryptKeeper extends Activity implements TextView.OnEditorActionListener {
54ec5a45e79cb7161adfabf475342c1e1b25994276Jason parks    private static final String TAG = "CryptKeeper";
5535933812b16f0b4221280bbcc3c32f6540996bf2Jason parks
568fd5bc9e6ff0d02012df670a6bf4bcdaf903c09dJason parks    private static final String DECRYPT_STATE = "trigger_restart_framework";
57ec5a45e79cb7161adfabf475342c1e1b25994276Jason parks
58ec5a45e79cb7161adfabf475342c1e1b25994276Jason parks    private static final int UPDATE_PROGRESS = 1;
59ec5a45e79cb7161adfabf475342c1e1b25994276Jason parks    private static final int COOLDOWN = 2;
60ec5a45e79cb7161adfabf475342c1e1b25994276Jason parks
61ec5a45e79cb7161adfabf475342c1e1b25994276Jason parks    private static final int MAX_FAILED_ATTEMPTS = 30;
62ec5a45e79cb7161adfabf475342c1e1b25994276Jason parks    private static final int COOL_DOWN_ATTEMPTS = 10;
63ec5a45e79cb7161adfabf475342c1e1b25994276Jason parks    private static final int COOL_DOWN_INTERVAL = 30; // 30 seconds
64ec5a45e79cb7161adfabf475342c1e1b25994276Jason parks
651499740c13af5fbd5766a87825c3e789b37bab24Andy Stadler    private int mCooldown;
661499740c13af5fbd5766a87825c3e789b37bab24Andy Stadler    PowerManager.WakeLock mWakeLock;
6706c5ff4a46686d3f599e40df0768177d3d88913cJason parks    private EditText mPasswordEntry;
681499740c13af5fbd5766a87825c3e789b37bab24Andy Stadler
691499740c13af5fbd5766a87825c3e789b37bab24Andy Stadler    /**
701499740c13af5fbd5766a87825c3e789b37bab24Andy Stadler     * Used to propagate state through configuration changes (e.g. screen rotation)
711499740c13af5fbd5766a87825c3e789b37bab24Andy Stadler     */
721499740c13af5fbd5766a87825c3e789b37bab24Andy Stadler    private static class NonConfigurationInstanceState {
731499740c13af5fbd5766a87825c3e789b37bab24Andy Stadler        final PowerManager.WakeLock wakelock;
741499740c13af5fbd5766a87825c3e789b37bab24Andy Stadler
751499740c13af5fbd5766a87825c3e789b37bab24Andy Stadler        NonConfigurationInstanceState(PowerManager.WakeLock _wakelock) {
761499740c13af5fbd5766a87825c3e789b37bab24Andy Stadler            wakelock = _wakelock;
771499740c13af5fbd5766a87825c3e789b37bab24Andy Stadler        }
781499740c13af5fbd5766a87825c3e789b37bab24Andy Stadler    }
791499740c13af5fbd5766a87825c3e789b37bab24Andy Stadler
80f1dbf55819e01f6cf1a99d38a292b15de1262a29Jason parks    // This activity is used to fade the screen to black after the password is entered.
81f1dbf55819e01f6cf1a99d38a292b15de1262a29Jason parks    public static class Blank extends Activity {
8213d62049f7c96c47356f23eaee7f0997612fdf9fAndy Stadler        @Override
8313d62049f7c96c47356f23eaee7f0997612fdf9fAndy Stadler        public void onCreate(Bundle savedInstanceState) {
8413d62049f7c96c47356f23eaee7f0997612fdf9fAndy Stadler            super.onCreate(savedInstanceState);
8513d62049f7c96c47356f23eaee7f0997612fdf9fAndy Stadler            setContentView(R.layout.crypt_keeper_blank);
8613d62049f7c96c47356f23eaee7f0997612fdf9fAndy Stadler        }
87f1dbf55819e01f6cf1a99d38a292b15de1262a29Jason parks    }
88ec5a45e79cb7161adfabf475342c1e1b25994276Jason parks
8975c085ee890744cdd4b90c72f8b50e6aeeb31e88Jason parks    // Use a custom EditText to prevent the input method from showing.
9075c085ee890744cdd4b90c72f8b50e6aeeb31e88Jason parks    public static class CryptEditText extends EditText {
9175c085ee890744cdd4b90c72f8b50e6aeeb31e88Jason parks        InputMethodManager imm;
9275c085ee890744cdd4b90c72f8b50e6aeeb31e88Jason parks
9375c085ee890744cdd4b90c72f8b50e6aeeb31e88Jason parks        public CryptEditText(Context context, AttributeSet attrs) {
9475c085ee890744cdd4b90c72f8b50e6aeeb31e88Jason parks            super(context, attrs);
9575c085ee890744cdd4b90c72f8b50e6aeeb31e88Jason parks            imm = ((InputMethodManager) getContext().
9675c085ee890744cdd4b90c72f8b50e6aeeb31e88Jason parks                    getSystemService(Context.INPUT_METHOD_SERVICE));
9775c085ee890744cdd4b90c72f8b50e6aeeb31e88Jason parks        }
9875c085ee890744cdd4b90c72f8b50e6aeeb31e88Jason parks
9975c085ee890744cdd4b90c72f8b50e6aeeb31e88Jason parks        @Override
10075c085ee890744cdd4b90c72f8b50e6aeeb31e88Jason parks        protected void onFocusChanged(boolean focused, int direction, Rect previouslyFocusedRect) {
10175c085ee890744cdd4b90c72f8b50e6aeeb31e88Jason parks            super.onFocusChanged(focused, direction, previouslyFocusedRect);
10275c085ee890744cdd4b90c72f8b50e6aeeb31e88Jason parks
10375c085ee890744cdd4b90c72f8b50e6aeeb31e88Jason parks            if (focused && imm != null && imm.isActive(this)) {
10475c085ee890744cdd4b90c72f8b50e6aeeb31e88Jason parks                imm.hideSoftInputFromWindow(getApplicationWindowToken(), 0);
10575c085ee890744cdd4b90c72f8b50e6aeeb31e88Jason parks            }
10675c085ee890744cdd4b90c72f8b50e6aeeb31e88Jason parks        }
10775c085ee890744cdd4b90c72f8b50e6aeeb31e88Jason parks
10875c085ee890744cdd4b90c72f8b50e6aeeb31e88Jason parks        @Override
10975c085ee890744cdd4b90c72f8b50e6aeeb31e88Jason parks        public boolean onTouchEvent(MotionEvent event) {
11075c085ee890744cdd4b90c72f8b50e6aeeb31e88Jason parks            boolean handled = super.onTouchEvent(event);
11175c085ee890744cdd4b90c72f8b50e6aeeb31e88Jason parks
11275c085ee890744cdd4b90c72f8b50e6aeeb31e88Jason parks            if (imm != null && imm.isActive(this)) {
11375c085ee890744cdd4b90c72f8b50e6aeeb31e88Jason parks                imm.hideSoftInputFromWindow(getApplicationWindowToken(), 0);
11475c085ee890744cdd4b90c72f8b50e6aeeb31e88Jason parks            }
11575c085ee890744cdd4b90c72f8b50e6aeeb31e88Jason parks
11675c085ee890744cdd4b90c72f8b50e6aeeb31e88Jason parks            return handled;
11775c085ee890744cdd4b90c72f8b50e6aeeb31e88Jason parks        }
11875c085ee890744cdd4b90c72f8b50e6aeeb31e88Jason parks    }
11975c085ee890744cdd4b90c72f8b50e6aeeb31e88Jason parks
12006c5ff4a46686d3f599e40df0768177d3d88913cJason parks    private class DecryptTask extends AsyncTask<String, Void, Integer> {
12106c5ff4a46686d3f599e40df0768177d3d88913cJason parks        @Override
12206c5ff4a46686d3f599e40df0768177d3d88913cJason parks        protected Integer doInBackground(String... params) {
12306c5ff4a46686d3f599e40df0768177d3d88913cJason parks            IMountService service = getMountService();
12406c5ff4a46686d3f599e40df0768177d3d88913cJason parks            try {
12506c5ff4a46686d3f599e40df0768177d3d88913cJason parks                return service.decryptStorage(params[0]);
12606c5ff4a46686d3f599e40df0768177d3d88913cJason parks            } catch (Exception e) {
12706c5ff4a46686d3f599e40df0768177d3d88913cJason parks                Log.e(TAG, "Error while decrypting...", e);
12806c5ff4a46686d3f599e40df0768177d3d88913cJason parks                return -1;
12906c5ff4a46686d3f599e40df0768177d3d88913cJason parks            }
13006c5ff4a46686d3f599e40df0768177d3d88913cJason parks        }
13106c5ff4a46686d3f599e40df0768177d3d88913cJason parks
13206c5ff4a46686d3f599e40df0768177d3d88913cJason 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
13606c5ff4a46686d3f599e40df0768177d3d88913cJason parks                // 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);
15206c5ff4a46686d3f599e40df0768177d3d88913cJason parks
15306c5ff4a46686d3f599e40df0768177d3d88913cJason parks                // Reenable the password entry
15406c5ff4a46686d3f599e40df0768177d3d88913cJason parks                mPasswordEntry.setEnabled(true);
15506c5ff4a46686d3f599e40df0768177d3d88913cJason parks            }
15606c5ff4a46686d3f599e40df0768177d3d88913cJason parks        }
15706c5ff4a46686d3f599e40df0768177d3d88913cJason parks    }
15875c085ee890744cdd4b90c72f8b50e6aeeb31e88Jason parks
159ec5a45e79cb7161adfabf475342c1e1b25994276Jason parks    private Handler mHandler = new Handler() {
160ec5a45e79cb7161adfabf475342c1e1b25994276Jason parks        @Override
161ec5a45e79cb7161adfabf475342c1e1b25994276Jason parks        public void handleMessage(Message msg) {
162ec5a45e79cb7161adfabf475342c1e1b25994276Jason parks            switch (msg.what) {
163ec5a45e79cb7161adfabf475342c1e1b25994276Jason parks            case UPDATE_PROGRESS:
164f8217304073b5cd13823a0602568394be93bf310Jason parks                updateProgress();
165ec5a45e79cb7161adfabf475342c1e1b25994276Jason parks                break;
16635933812b16f0b4221280bbcc3c32f6540996bf2Jason parks
167ec5a45e79cb7161adfabf475342c1e1b25994276Jason parks            case COOLDOWN:
168f8217304073b5cd13823a0602568394be93bf310Jason parks                cooldown();
169ec5a45e79cb7161adfabf475342c1e1b25994276Jason parks                break;
170ec5a45e79cb7161adfabf475342c1e1b25994276Jason parks            }
171ec5a45e79cb7161adfabf475342c1e1b25994276Jason parks        }
172ec5a45e79cb7161adfabf475342c1e1b25994276Jason parks    };
17335933812b16f0b4221280bbcc3c32f6540996bf2Jason parks
1748fd5bc9e6ff0d02012df670a6bf4bcdaf903c09dJason parks    @Override
1758fd5bc9e6ff0d02012df670a6bf4bcdaf903c09dJason parks    public void onCreate(Bundle savedInstanceState) {
1768fd5bc9e6ff0d02012df670a6bf4bcdaf903c09dJason parks        super.onCreate(savedInstanceState);
17735933812b16f0b4221280bbcc3c32f6540996bf2Jason parks
1789597406aa1b83867b03a47d1a5162969b924f2fcAndy Stadler        // If we are not encrypted or encrypting, get out quickly.
1798fd5bc9e6ff0d02012df670a6bf4bcdaf903c09dJason parks        String state = SystemProperties.get("vold.decrypt");
1808fd5bc9e6ff0d02012df670a6bf4bcdaf903c09dJason parks        if ("".equals(state) || DECRYPT_STATE.equals(state)) {
18135933812b16f0b4221280bbcc3c32f6540996bf2Jason parks            // Disable the crypt keeper.
1828fd5bc9e6ff0d02012df670a6bf4bcdaf903c09dJason parks            PackageManager pm = getPackageManager();
1838fd5bc9e6ff0d02012df670a6bf4bcdaf903c09dJason parks            ComponentName name = new ComponentName(this, CryptKeeper.class);
1848fd5bc9e6ff0d02012df670a6bf4bcdaf903c09dJason parks            pm.setComponentEnabledSetting(name, PackageManager.COMPONENT_ENABLED_STATE_DISABLED, 0);
1858fd5bc9e6ff0d02012df670a6bf4bcdaf903c09dJason parks            return;
1868fd5bc9e6ff0d02012df670a6bf4bcdaf903c09dJason parks        }
18735933812b16f0b4221280bbcc3c32f6540996bf2Jason parks
18839f1e04079976d3d10fdd8e5dd36c833bab8a371Jason parks        // Disable the status bar
18939f1e04079976d3d10fdd8e5dd36c833bab8a371Jason parks        StatusBarManager sbm = (StatusBarManager) getSystemService(Context.STATUS_BAR_SERVICE);
19013d62049f7c96c47356f23eaee7f0997612fdf9fAndy Stadler        sbm.disable(StatusBarManager.DISABLE_EXPAND
19113d62049f7c96c47356f23eaee7f0997612fdf9fAndy Stadler                | StatusBarManager.DISABLE_NOTIFICATION_ICONS
19239f1e04079976d3d10fdd8e5dd36c833bab8a371Jason parks                | StatusBarManager.DISABLE_NOTIFICATION_ALERTS
19313d62049f7c96c47356f23eaee7f0997612fdf9fAndy Stadler                | StatusBarManager.DISABLE_SYSTEM_INFO
19413d62049f7c96c47356f23eaee7f0997612fdf9fAndy Stadler                | StatusBarManager.DISABLE_NAVIGATION
19513d62049f7c96c47356f23eaee7f0997612fdf9fAndy Stadler                | StatusBarManager.DISABLE_BACK);
1961499740c13af5fbd5766a87825c3e789b37bab24Andy Stadler
1971499740c13af5fbd5766a87825c3e789b37bab24Andy Stadler        // Check for (and recover) retained instance data
1981499740c13af5fbd5766a87825c3e789b37bab24Andy Stadler        Object lastInstance = getLastNonConfigurationInstance();
1991499740c13af5fbd5766a87825c3e789b37bab24Andy Stadler        if (lastInstance instanceof NonConfigurationInstanceState) {
2001499740c13af5fbd5766a87825c3e789b37bab24Andy Stadler            NonConfigurationInstanceState retained = (NonConfigurationInstanceState) lastInstance;
2011499740c13af5fbd5766a87825c3e789b37bab24Andy Stadler            mWakeLock = retained.wakelock;
2021499740c13af5fbd5766a87825c3e789b37bab24Andy Stadler        }
203ec5a45e79cb7161adfabf475342c1e1b25994276Jason parks    }
20435933812b16f0b4221280bbcc3c32f6540996bf2Jason parks
2059597406aa1b83867b03a47d1a5162969b924f2fcAndy Stadler    /**
2069597406aa1b83867b03a47d1a5162969b924f2fcAndy Stadler     * Note, we defer the state check and screen setup to onStart() because this will be
2079597406aa1b83867b03a47d1a5162969b924f2fcAndy Stadler     * re-run if the user clicks the power button (sleeping/waking the screen), and this is
2089597406aa1b83867b03a47d1a5162969b924f2fcAndy Stadler     * especially important if we were to lose the wakelock for any reason.
2099597406aa1b83867b03a47d1a5162969b924f2fcAndy Stadler     */
2109597406aa1b83867b03a47d1a5162969b924f2fcAndy Stadler    @Override
2119597406aa1b83867b03a47d1a5162969b924f2fcAndy Stadler    public void onStart() {
2129597406aa1b83867b03a47d1a5162969b924f2fcAndy Stadler        super.onStart();
2139597406aa1b83867b03a47d1a5162969b924f2fcAndy Stadler
2149597406aa1b83867b03a47d1a5162969b924f2fcAndy Stadler        // Check to see why we were started.
2159597406aa1b83867b03a47d1a5162969b924f2fcAndy Stadler        String progress = SystemProperties.get("vold.encrypt_progress");
2169597406aa1b83867b03a47d1a5162969b924f2fcAndy Stadler        if (!"".equals(progress)) {
2179597406aa1b83867b03a47d1a5162969b924f2fcAndy Stadler            setContentView(R.layout.crypt_keeper_progress);
2189597406aa1b83867b03a47d1a5162969b924f2fcAndy Stadler            encryptionProgressInit();
2199597406aa1b83867b03a47d1a5162969b924f2fcAndy Stadler        } else {
2209597406aa1b83867b03a47d1a5162969b924f2fcAndy Stadler            setContentView(R.layout.crypt_keeper_password_entry);
2219597406aa1b83867b03a47d1a5162969b924f2fcAndy Stadler            passwordEntryInit();
2229597406aa1b83867b03a47d1a5162969b924f2fcAndy Stadler        }
2239597406aa1b83867b03a47d1a5162969b924f2fcAndy Stadler    }
2249597406aa1b83867b03a47d1a5162969b924f2fcAndy Stadler
225f8217304073b5cd13823a0602568394be93bf310Jason parks    @Override
226f8217304073b5cd13823a0602568394be93bf310Jason parks    public void onStop() {
227f8217304073b5cd13823a0602568394be93bf310Jason parks        super.onStop();
228f8217304073b5cd13823a0602568394be93bf310Jason parks
229f8217304073b5cd13823a0602568394be93bf310Jason parks        mHandler.removeMessages(COOLDOWN);
230f8217304073b5cd13823a0602568394be93bf310Jason parks        mHandler.removeMessages(UPDATE_PROGRESS);
2311499740c13af5fbd5766a87825c3e789b37bab24Andy Stadler    }
2321499740c13af5fbd5766a87825c3e789b37bab24Andy Stadler
2331499740c13af5fbd5766a87825c3e789b37bab24Andy Stadler    /**
2341499740c13af5fbd5766a87825c3e789b37bab24Andy Stadler     * Reconfiguring, so propagate the wakelock to the next instance.  This runs between onStop()
2351499740c13af5fbd5766a87825c3e789b37bab24Andy Stadler     * and onDestroy() and only if we are changing configuration (e.g. rotation).  Also clears
2361499740c13af5fbd5766a87825c3e789b37bab24Andy Stadler     * mWakeLock so the subsequent call to onDestroy does not release it.
2371499740c13af5fbd5766a87825c3e789b37bab24Andy Stadler     */
2381499740c13af5fbd5766a87825c3e789b37bab24Andy Stadler    @Override
2391499740c13af5fbd5766a87825c3e789b37bab24Andy Stadler    public Object onRetainNonConfigurationInstance() {
2401499740c13af5fbd5766a87825c3e789b37bab24Andy Stadler        NonConfigurationInstanceState state = new NonConfigurationInstanceState(mWakeLock);
2411499740c13af5fbd5766a87825c3e789b37bab24Andy Stadler        mWakeLock = null;
2421499740c13af5fbd5766a87825c3e789b37bab24Andy Stadler        return state;
2431499740c13af5fbd5766a87825c3e789b37bab24Andy Stadler    }
2441499740c13af5fbd5766a87825c3e789b37bab24Andy Stadler
2451499740c13af5fbd5766a87825c3e789b37bab24Andy Stadler    @Override
2461499740c13af5fbd5766a87825c3e789b37bab24Andy Stadler    public void onDestroy() {
2471499740c13af5fbd5766a87825c3e789b37bab24Andy Stadler        super.onDestroy();
248f8217304073b5cd13823a0602568394be93bf310Jason parks
249f8217304073b5cd13823a0602568394be93bf310Jason parks        if (mWakeLock != null) {
250f8217304073b5cd13823a0602568394be93bf310Jason parks            mWakeLock.release();
251f8217304073b5cd13823a0602568394be93bf310Jason parks            mWakeLock = null;
252f8217304073b5cd13823a0602568394be93bf310Jason parks        }
253f8217304073b5cd13823a0602568394be93bf310Jason parks    }
254f8217304073b5cd13823a0602568394be93bf310Jason parks
255ec5a45e79cb7161adfabf475342c1e1b25994276Jason parks    private void encryptionProgressInit() {
25635933812b16f0b4221280bbcc3c32f6540996bf2Jason parks        // Accquire a partial wakelock to prevent the device from sleeping. Note
25735933812b16f0b4221280bbcc3c32f6540996bf2Jason parks        // we never release this wakelock as we will be restarted after the device
25835933812b16f0b4221280bbcc3c32f6540996bf2Jason parks        // is encrypted.
25935933812b16f0b4221280bbcc3c32f6540996bf2Jason parks
26035933812b16f0b4221280bbcc3c32f6540996bf2Jason parks        PowerManager pm = (PowerManager) getSystemService(Context.POWER_SERVICE);
261f8217304073b5cd13823a0602568394be93bf310Jason parks        mWakeLock = pm.newWakeLock(PowerManager.FULL_WAKE_LOCK, TAG);
262f8217304073b5cd13823a0602568394be93bf310Jason parks
263f8217304073b5cd13823a0602568394be93bf310Jason parks        mWakeLock.acquire();
264f8217304073b5cd13823a0602568394be93bf310Jason parks
265f8217304073b5cd13823a0602568394be93bf310Jason parks        ProgressBar progressBar = (ProgressBar) findViewById(R.id.progress_bar);
266f8217304073b5cd13823a0602568394be93bf310Jason parks        progressBar.setIndeterminate(true);
26735933812b16f0b4221280bbcc3c32f6540996bf2Jason parks
268f8217304073b5cd13823a0602568394be93bf310Jason parks        updateProgress();
269f8217304073b5cd13823a0602568394be93bf310Jason parks    }
270f8217304073b5cd13823a0602568394be93bf310Jason parks
27113d62049f7c96c47356f23eaee7f0997612fdf9fAndy Stadler    private void showFactoryReset() {
27213d62049f7c96c47356f23eaee7f0997612fdf9fAndy Stadler        // Hide the encryption-bot to make room for the "factory reset" button
27313d62049f7c96c47356f23eaee7f0997612fdf9fAndy Stadler        findViewById(R.id.encroid).setVisibility(View.GONE);
27413d62049f7c96c47356f23eaee7f0997612fdf9fAndy Stadler
27513d62049f7c96c47356f23eaee7f0997612fdf9fAndy Stadler        // Show the reset button, failure text, and a divider
27613d62049f7c96c47356f23eaee7f0997612fdf9fAndy Stadler        Button button = (Button) findViewById(R.id.factory_reset);
27713d62049f7c96c47356f23eaee7f0997612fdf9fAndy Stadler        button.setVisibility(View.VISIBLE);
27813d62049f7c96c47356f23eaee7f0997612fdf9fAndy Stadler        button.setOnClickListener(new OnClickListener() {
27913d62049f7c96c47356f23eaee7f0997612fdf9fAndy Stadler            public void onClick(View v) {
28013d62049f7c96c47356f23eaee7f0997612fdf9fAndy Stadler                // Factory reset the device.
28113d62049f7c96c47356f23eaee7f0997612fdf9fAndy Stadler                sendBroadcast(new Intent("android.intent.action.MASTER_CLEAR"));
28213d62049f7c96c47356f23eaee7f0997612fdf9fAndy Stadler            }
28313d62049f7c96c47356f23eaee7f0997612fdf9fAndy Stadler        });
28413d62049f7c96c47356f23eaee7f0997612fdf9fAndy Stadler
28513d62049f7c96c47356f23eaee7f0997612fdf9fAndy Stadler        TextView tv = (TextView) findViewById(R.id.title);
28613d62049f7c96c47356f23eaee7f0997612fdf9fAndy Stadler        tv.setText(R.string.crypt_keeper_failed_title);
28713d62049f7c96c47356f23eaee7f0997612fdf9fAndy Stadler
28813d62049f7c96c47356f23eaee7f0997612fdf9fAndy Stadler        tv = (TextView) findViewById(R.id.status);
28913d62049f7c96c47356f23eaee7f0997612fdf9fAndy Stadler        tv.setText(R.string.crypt_keeper_failed_summary);
29013d62049f7c96c47356f23eaee7f0997612fdf9fAndy Stadler
29113d62049f7c96c47356f23eaee7f0997612fdf9fAndy Stadler        View view = findViewById(R.id.bottom_divider);
29213d62049f7c96c47356f23eaee7f0997612fdf9fAndy Stadler        view.setVisibility(View.VISIBLE);
29313d62049f7c96c47356f23eaee7f0997612fdf9fAndy Stadler    }
29413d62049f7c96c47356f23eaee7f0997612fdf9fAndy Stadler
295f8217304073b5cd13823a0602568394be93bf310Jason parks    private void updateProgress() {
296f8217304073b5cd13823a0602568394be93bf310Jason parks        String state = SystemProperties.get("vold.encrypt_progress");
297f8217304073b5cd13823a0602568394be93bf310Jason parks
29813d62049f7c96c47356f23eaee7f0997612fdf9fAndy Stadler        if ("error_partially_encrypted".equals(state)) {
29913d62049f7c96c47356f23eaee7f0997612fdf9fAndy Stadler            showFactoryReset();
30013d62049f7c96c47356f23eaee7f0997612fdf9fAndy Stadler            return;
30113d62049f7c96c47356f23eaee7f0997612fdf9fAndy Stadler        }
30213d62049f7c96c47356f23eaee7f0997612fdf9fAndy Stadler
303f8217304073b5cd13823a0602568394be93bf310Jason parks        int progress = 0;
304f8217304073b5cd13823a0602568394be93bf310Jason parks        try {
305f8217304073b5cd13823a0602568394be93bf310Jason parks            progress = Integer.parseInt(state);
306f8217304073b5cd13823a0602568394be93bf310Jason parks        } catch (Exception e) {
307f8217304073b5cd13823a0602568394be93bf310Jason parks            Log.w(TAG, "Error parsing progress: " + e.toString());
308f8217304073b5cd13823a0602568394be93bf310Jason parks        }
30935933812b16f0b4221280bbcc3c32f6540996bf2Jason parks
310f8217304073b5cd13823a0602568394be93bf310Jason parks        CharSequence status = getText(R.string.crypt_keeper_setup_description);
311f8217304073b5cd13823a0602568394be93bf310Jason parks        TextView tv = (TextView) findViewById(R.id.status);
312f8217304073b5cd13823a0602568394be93bf310Jason parks        tv.setText(TextUtils.expandTemplate(status, Integer.toString(progress)));
313f8217304073b5cd13823a0602568394be93bf310Jason parks
314f8217304073b5cd13823a0602568394be93bf310Jason parks        // Check the progress every 5 seconds
315f8217304073b5cd13823a0602568394be93bf310Jason parks        mHandler.removeMessages(UPDATE_PROGRESS);
316f8217304073b5cd13823a0602568394be93bf310Jason parks        mHandler.sendEmptyMessageDelayed(UPDATE_PROGRESS, 5000);
317f8217304073b5cd13823a0602568394be93bf310Jason parks    }
318f8217304073b5cd13823a0602568394be93bf310Jason parks
319f8217304073b5cd13823a0602568394be93bf310Jason parks    private void cooldown() {
320f8217304073b5cd13823a0602568394be93bf310Jason parks        TextView tv = (TextView) findViewById(R.id.status);
32113d62049f7c96c47356f23eaee7f0997612fdf9fAndy Stadler
322f8217304073b5cd13823a0602568394be93bf310Jason parks        if (mCooldown <= 0) {
323f8217304073b5cd13823a0602568394be93bf310Jason parks            // Re-enable the password entry
32406c5ff4a46686d3f599e40df0768177d3d88913cJason parks            mPasswordEntry.setEnabled(true);
325f8217304073b5cd13823a0602568394be93bf310Jason parks
32613d62049f7c96c47356f23eaee7f0997612fdf9fAndy Stadler            tv.setVisibility(View.GONE);
327f8217304073b5cd13823a0602568394be93bf310Jason parks        } else {
32813d62049f7c96c47356f23eaee7f0997612fdf9fAndy Stadler            CharSequence template = getText(R.string.crypt_keeper_cooldown);
32913d62049f7c96c47356f23eaee7f0997612fdf9fAndy Stadler            tv.setText(TextUtils.expandTemplate(template, Integer.toString(mCooldown)));
33013d62049f7c96c47356f23eaee7f0997612fdf9fAndy Stadler
33113d62049f7c96c47356f23eaee7f0997612fdf9fAndy Stadler            tv.setVisibility(View.VISIBLE);
332f8217304073b5cd13823a0602568394be93bf310Jason parks
333f8217304073b5cd13823a0602568394be93bf310Jason parks            mCooldown--;
334f8217304073b5cd13823a0602568394be93bf310Jason parks            mHandler.removeMessages(COOLDOWN);
335f8217304073b5cd13823a0602568394be93bf310Jason parks            mHandler.sendEmptyMessageDelayed(COOLDOWN, 1000); // Tick every second
336f8217304073b5cd13823a0602568394be93bf310Jason parks        }
337ec5a45e79cb7161adfabf475342c1e1b25994276Jason parks    }
33835933812b16f0b4221280bbcc3c32f6540996bf2Jason parks
339ec5a45e79cb7161adfabf475342c1e1b25994276Jason parks    private void passwordEntryInit() {
34006c5ff4a46686d3f599e40df0768177d3d88913cJason parks        mPasswordEntry = (EditText) findViewById(R.id.passwordEntry);
34106c5ff4a46686d3f599e40df0768177d3d88913cJason parks        mPasswordEntry.setOnEditorActionListener(this);
34235933812b16f0b4221280bbcc3c32f6540996bf2Jason parks
3438fd5bc9e6ff0d02012df670a6bf4bcdaf903c09dJason parks        KeyboardView keyboardView = (PasswordEntryKeyboardView) findViewById(R.id.keyboard);
34435933812b16f0b4221280bbcc3c32f6540996bf2Jason parks
34500046d6e176eb05c3e3b0d13d38a8da7491bba5eJason parks        if (keyboardView != null) {
34600046d6e176eb05c3e3b0d13d38a8da7491bba5eJason parks            PasswordEntryKeyboardHelper keyboardHelper = new PasswordEntryKeyboardHelper(this,
34700046d6e176eb05c3e3b0d13d38a8da7491bba5eJason parks                    keyboardView, mPasswordEntry, false);
34800046d6e176eb05c3e3b0d13d38a8da7491bba5eJason parks            keyboardHelper.setKeyboardMode(PasswordEntryKeyboardHelper.KEYBOARD_MODE_ALPHA);
34900046d6e176eb05c3e3b0d13d38a8da7491bba5eJason parks        }
3508fd5bc9e6ff0d02012df670a6bf4bcdaf903c09dJason parks    }
3518fd5bc9e6ff0d02012df670a6bf4bcdaf903c09dJason parks
3528fd5bc9e6ff0d02012df670a6bf4bcdaf903c09dJason parks    private IMountService getMountService() {
3538fd5bc9e6ff0d02012df670a6bf4bcdaf903c09dJason parks        IBinder service = ServiceManager.getService("mount");
3548fd5bc9e6ff0d02012df670a6bf4bcdaf903c09dJason parks        if (service != null) {
3558fd5bc9e6ff0d02012df670a6bf4bcdaf903c09dJason parks            return IMountService.Stub.asInterface(service);
3568fd5bc9e6ff0d02012df670a6bf4bcdaf903c09dJason parks        }
3578fd5bc9e6ff0d02012df670a6bf4bcdaf903c09dJason parks        return null;
3588fd5bc9e6ff0d02012df670a6bf4bcdaf903c09dJason parks    }
3598fd5bc9e6ff0d02012df670a6bf4bcdaf903c09dJason parks
3608fd5bc9e6ff0d02012df670a6bf4bcdaf903c09dJason parks    @Override
3618fd5bc9e6ff0d02012df670a6bf4bcdaf903c09dJason parks    public boolean onEditorAction(TextView v, int actionId, KeyEvent event) {
36200046d6e176eb05c3e3b0d13d38a8da7491bba5eJason parks        if (actionId == EditorInfo.IME_NULL || actionId == EditorInfo.IME_ACTION_DONE) {
3638fd5bc9e6ff0d02012df670a6bf4bcdaf903c09dJason parks            // Get the password
3648fd5bc9e6ff0d02012df670a6bf4bcdaf903c09dJason parks            String password = v.getText().toString();
3658fd5bc9e6ff0d02012df670a6bf4bcdaf903c09dJason parks
366ec5a45e79cb7161adfabf475342c1e1b25994276Jason parks            if (TextUtils.isEmpty(password)) {
367ec5a45e79cb7161adfabf475342c1e1b25994276Jason parks                return true;
368ec5a45e79cb7161adfabf475342c1e1b25994276Jason parks            }
36935933812b16f0b4221280bbcc3c32f6540996bf2Jason parks
3708fd5bc9e6ff0d02012df670a6bf4bcdaf903c09dJason parks            // Now that we have the password clear the password field.
3718fd5bc9e6ff0d02012df670a6bf4bcdaf903c09dJason parks            v.setText(null);
3728fd5bc9e6ff0d02012df670a6bf4bcdaf903c09dJason parks
37306c5ff4a46686d3f599e40df0768177d3d88913cJason parks            // Disable the password entry while checking the password. This
37406c5ff4a46686d3f599e40df0768177d3d88913cJason parks            // we either be reenabled if the password was wrong or after the
37506c5ff4a46686d3f599e40df0768177d3d88913cJason parks            // cooldown period.
37606c5ff4a46686d3f599e40df0768177d3d88913cJason parks            mPasswordEntry.setEnabled(false);
37706c5ff4a46686d3f599e40df0768177d3d88913cJason parks
37806c5ff4a46686d3f599e40df0768177d3d88913cJason parks            new DecryptTask().execute(password);
37935933812b16f0b4221280bbcc3c32f6540996bf2Jason parks
3808fd5bc9e6ff0d02012df670a6bf4bcdaf903c09dJason parks            return true;
3818fd5bc9e6ff0d02012df670a6bf4bcdaf903c09dJason parks        }
3828fd5bc9e6ff0d02012df670a6bf4bcdaf903c09dJason parks        return false;
3838fd5bc9e6ff0d02012df670a6bf4bcdaf903c09dJason parks    }
3848fd5bc9e6ff0d02012df670a6bf4bcdaf903c09dJason parks}