15e0f7ba8fa8045aab98664b5103d8620e9ac7f06Jim Miller/*
2dcb3d84b82cc2448d04e73359a716581bfb657dbJim Miller * Copyright (C) 2012 The Android Open Source Project
35e0f7ba8fa8045aab98664b5103d8620e9ac7f06Jim Miller *
45e0f7ba8fa8045aab98664b5103d8620e9ac7f06Jim Miller * Licensed under the Apache License, Version 2.0 (the "License");
55e0f7ba8fa8045aab98664b5103d8620e9ac7f06Jim Miller * you may not use this file except in compliance with the License.
65e0f7ba8fa8045aab98664b5103d8620e9ac7f06Jim Miller * You may obtain a copy of the License at
75e0f7ba8fa8045aab98664b5103d8620e9ac7f06Jim Miller *
85e0f7ba8fa8045aab98664b5103d8620e9ac7f06Jim Miller *      http://www.apache.org/licenses/LICENSE-2.0
95e0f7ba8fa8045aab98664b5103d8620e9ac7f06Jim Miller *
105e0f7ba8fa8045aab98664b5103d8620e9ac7f06Jim Miller * Unless required by applicable law or agreed to in writing, software
115e0f7ba8fa8045aab98664b5103d8620e9ac7f06Jim Miller * distributed under the License is distributed on an "AS IS" BASIS,
125e0f7ba8fa8045aab98664b5103d8620e9ac7f06Jim Miller * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
135e0f7ba8fa8045aab98664b5103d8620e9ac7f06Jim Miller * See the License for the specific language governing permissions and
145e0f7ba8fa8045aab98664b5103d8620e9ac7f06Jim Miller * limitations under the License.
155e0f7ba8fa8045aab98664b5103d8620e9ac7f06Jim Miller */
165e0f7ba8fa8045aab98664b5103d8620e9ac7f06Jim Miller
175ecd81154fa039961f65bb4e36d18ac555b0d1d6Jim Millerpackage com.android.keyguard;
185e0f7ba8fa8045aab98664b5103d8620e9ac7f06Jim Miller
19f7c5d0e46ced3ec3edb6f656acd82900b9ac988cJim Millerimport android.app.admin.DevicePolicyManager;
201254f2f42f7173ef51d0034975ab5cb7d44f8209Michael Jurkaimport android.content.Context;
215475906f53e2d79807548932dfabbf9945143740Jim Millerimport android.content.res.Configuration;
228ecfac1d8c2988c3d5031e78f9edefff6e663fd1Jim Millerimport android.text.Editable;
23da3ae8fba865e4b02016bcb65b87a1fbfa000158Jim Millerimport android.text.InputType;
248ecfac1d8c2988c3d5031e78f9edefff6e663fd1Jim Millerimport android.text.TextWatcher;
258b9dda28c9850b4a68b6958b8d4f751dd64157adJim Millerimport android.text.method.DigitsKeyListener;
268b9dda28c9850b4a68b6958b8d4f751dd64157adJim Millerimport android.text.method.TextKeyListener;
271254f2f42f7173ef51d0034975ab5cb7d44f8209Michael Jurkaimport android.util.AttributeSet;
281254f2f42f7173ef51d0034975ab5cb7d44f8209Michael Jurkaimport android.view.View;
29858f8eaac75bcd1b296b41837caf3dae82d1d72aJim Millerimport android.view.inputmethod.InputMethodInfo;
30858f8eaac75bcd1b296b41837caf3dae82d1d72aJim Millerimport android.view.inputmethod.InputMethodManager;
31858f8eaac75bcd1b296b41837caf3dae82d1d72aJim Millerimport android.view.inputmethod.InputMethodSubtype;
32a781d016108d64b2735740d42b5a7c57eb420406Jim Millerimport android.widget.TextView.OnEditorActionListener;
33a781d016108d64b2735740d42b5a7c57eb420406Jim Miller
34a781d016108d64b2735740d42b5a7c57eb420406Jim Millerimport com.android.internal.widget.PasswordEntryKeyboardHelper;
351254f2f42f7173ef51d0034975ab5cb7d44f8209Michael Jurkaimport com.android.internal.widget.PasswordEntryKeyboardView;
361254f2f42f7173ef51d0034975ab5cb7d44f8209Michael Jurka
371254f2f42f7173ef51d0034975ab5cb7d44f8209Michael Jurkaimport java.util.List;
385e0f7ba8fa8045aab98664b5103d8620e9ac7f06Jim Miller/**
392c1ce0564fbd329e9e9ccfca100c69cfc1fd2645Daniel Sandler * Displays an alphanumeric (latin-1) key entry for the user to enter
405e0f7ba8fa8045aab98664b5103d8620e9ac7f06Jim Miller * an unlock password
415e0f7ba8fa8045aab98664b5103d8620e9ac7f06Jim Miller */
425e0f7ba8fa8045aab98664b5103d8620e9ac7f06Jim Miller
4369bdee7c873c4a2295651efda2d0e79c515acc17Daniel Sandlerpublic class KeyguardPasswordView extends KeyguardAbsKeyInputView
449cf2c523d82ec14632fd0db920dcc8909c0f44a5Jim Miller        implements KeyguardSecurityView, OnEditorActionListener, TextWatcher {
4569bdee7c873c4a2295651efda2d0e79c515acc17Daniel Sandler
46a042ac90640c0c3fd3c5349083b86bbfd6319b64Chris Wren    private final boolean mShowImeAtScreenOn;
47a042ac90640c0c3fd3c5349083b86bbfd6319b64Chris Wren
482c1ce0564fbd329e9e9ccfca100c69cfc1fd2645Daniel Sandler    InputMethodManager mImm;
49ac8f5751f52fa445af641604e476703dd5e89504Jim Miller
50dcb3d84b82cc2448d04e73359a716581bfb657dbJim Miller    public KeyguardPasswordView(Context context) {
51a042ac90640c0c3fd3c5349083b86bbfd6319b64Chris Wren        this(context, null);
52dcb3d84b82cc2448d04e73359a716581bfb657dbJim Miller    }
53dcb3d84b82cc2448d04e73359a716581bfb657dbJim Miller
54dcb3d84b82cc2448d04e73359a716581bfb657dbJim Miller    public KeyguardPasswordView(Context context, AttributeSet attrs) {
55dcb3d84b82cc2448d04e73359a716581bfb657dbJim Miller        super(context, attrs);
56a042ac90640c0c3fd3c5349083b86bbfd6319b64Chris Wren        mShowImeAtScreenOn = context.getResources().
57a042ac90640c0c3fd3c5349083b86bbfd6319b64Chris Wren                getBoolean(R.bool.kg_show_ime_at_screen_on);
58dcb3d84b82cc2448d04e73359a716581bfb657dbJim Miller    }
595475906f53e2d79807548932dfabbf9945143740Jim Miller
6069bdee7c873c4a2295651efda2d0e79c515acc17Daniel Sandler    protected void resetState() {
612c1ce0564fbd329e9e9ccfca100c69cfc1fd2645Daniel Sandler        mSecurityMessageDisplay.setMessage(R.string.kg_password_instructions, false);
6208b2b6bfe2550b65c68ad7b4bef8283f1ff17561Jim Miller        mPasswordEntry.setEnabled(true);
6308b2b6bfe2550b65c68ad7b4bef8283f1ff17561Jim Miller    }
6408b2b6bfe2550b65c68ad7b4bef8283f1ff17561Jim Miller
65dcb3d84b82cc2448d04e73359a716581bfb657dbJim Miller    @Override
668a26bf5aea45650a14215d398c7d0909fcf80c43Daniel Sandler    protected int getPasswordTextViewId() {
678a26bf5aea45650a14215d398c7d0909fcf80c43Daniel Sandler        return R.id.passwordEntry;
688a26bf5aea45650a14215d398c7d0909fcf80c43Daniel Sandler    }
698a26bf5aea45650a14215d398c7d0909fcf80c43Daniel Sandler
708a26bf5aea45650a14215d398c7d0909fcf80c43Daniel Sandler    @Override
7186f9637d7bfdc33ab826cc3bbd740f4bf01be280Jim Miller    public boolean needsInput() {
7286f9637d7bfdc33ab826cc3bbd740f4bf01be280Jim Miller        return true;
7386f9637d7bfdc33ab826cc3bbd740f4bf01be280Jim Miller    }
7486f9637d7bfdc33ab826cc3bbd740f4bf01be280Jim Miller
7586f9637d7bfdc33ab826cc3bbd740f4bf01be280Jim Miller    @Override
76a042ac90640c0c3fd3c5349083b86bbfd6319b64Chris Wren    public void onResume(int reason) {
77a042ac90640c0c3fd3c5349083b86bbfd6319b64Chris Wren        super.onResume(reason);
78fba4d4a7678862a21d5cf7770ca8bfcc79831bf6Daniel Sandler        mPasswordEntry.requestFocus();
79a042ac90640c0c3fd3c5349083b86bbfd6319b64Chris Wren        if (reason != KeyguardSecurityView.SCREEN_ON || mShowImeAtScreenOn) {
80a042ac90640c0c3fd3c5349083b86bbfd6319b64Chris Wren            mImm.showSoftInput(mPasswordEntry, InputMethodManager.SHOW_IMPLICIT);
81a042ac90640c0c3fd3c5349083b86bbfd6319b64Chris Wren        }
822c1ce0564fbd329e9e9ccfca100c69cfc1fd2645Daniel Sandler    }
83f7c5d0e46ced3ec3edb6f656acd82900b9ac988cJim Miller
842c1ce0564fbd329e9e9ccfca100c69cfc1fd2645Daniel Sandler    @Override
852c1ce0564fbd329e9e9ccfca100c69cfc1fd2645Daniel Sandler    public void onPause() {
862c1ce0564fbd329e9e9ccfca100c69cfc1fd2645Daniel Sandler        super.onPause();
872c1ce0564fbd329e9e9ccfca100c69cfc1fd2645Daniel Sandler        mImm.hideSoftInputFromWindow(getWindowToken(), 0);
882c1ce0564fbd329e9e9ccfca100c69cfc1fd2645Daniel Sandler    }
895e0f7ba8fa8045aab98664b5103d8620e9ac7f06Jim Miller
902c1ce0564fbd329e9e9ccfca100c69cfc1fd2645Daniel Sandler    @Override
912c1ce0564fbd329e9e9ccfca100c69cfc1fd2645Daniel Sandler    protected void onFinishInflate() {
922c1ce0564fbd329e9e9ccfca100c69cfc1fd2645Daniel Sandler        super.onFinishInflate();
93dcb3d84b82cc2448d04e73359a716581bfb657dbJim Miller
94d9d09451ccec7c551d5f9c2f1417c9c1de2952a6Jim Miller        boolean imeOrDeleteButtonVisible = false;
955e0f7ba8fa8045aab98664b5103d8620e9ac7f06Jim Miller
962c1ce0564fbd329e9e9ccfca100c69cfc1fd2645Daniel Sandler        mImm = (InputMethodManager) getContext().getSystemService(
972c1ce0564fbd329e9e9ccfca100c69cfc1fd2645Daniel Sandler                Context.INPUT_METHOD_SERVICE);
982c1ce0564fbd329e9e9ccfca100c69cfc1fd2645Daniel Sandler
992c1ce0564fbd329e9e9ccfca100c69cfc1fd2645Daniel Sandler        mPasswordEntry.setKeyListener(TextKeyListener.getInstance());
1002c1ce0564fbd329e9e9ccfca100c69cfc1fd2645Daniel Sandler        mPasswordEntry.setInputType(InputType.TYPE_CLASS_TEXT
1012c1ce0564fbd329e9e9ccfca100c69cfc1fd2645Daniel Sandler                | InputType.TYPE_TEXT_VARIATION_PASSWORD);
1028b9dda28c9850b4a68b6958b8d4f751dd64157adJim Miller
1036b05d58018c2806459c121e507c005639b74aee9Jim Miller        // Poke the wakelock any time the text is selected or modified
1046b05d58018c2806459c121e507c005639b74aee9Jim Miller        mPasswordEntry.setOnClickListener(new OnClickListener() {
1056b05d58018c2806459c121e507c005639b74aee9Jim Miller            public void onClick(View v) {
106dcb3d84b82cc2448d04e73359a716581bfb657dbJim Miller                mCallback.userActivity(0); // TODO: customize timeout for text?
1076b05d58018c2806459c121e507c005639b74aee9Jim Miller            }
1086b05d58018c2806459c121e507c005639b74aee9Jim Miller        });
109dcb3d84b82cc2448d04e73359a716581bfb657dbJim Miller
1108ecfac1d8c2988c3d5031e78f9edefff6e663fd1Jim Miller        mPasswordEntry.addTextChangedListener(new TextWatcher() {
1118ecfac1d8c2988c3d5031e78f9edefff6e663fd1Jim Miller            public void onTextChanged(CharSequence s, int start, int before, int count) {
1128ecfac1d8c2988c3d5031e78f9edefff6e663fd1Jim Miller            }
1138ecfac1d8c2988c3d5031e78f9edefff6e663fd1Jim Miller
1148ecfac1d8c2988c3d5031e78f9edefff6e663fd1Jim Miller            public void beforeTextChanged(CharSequence s, int start, int count, int after) {
1158ecfac1d8c2988c3d5031e78f9edefff6e663fd1Jim Miller            }
1168ecfac1d8c2988c3d5031e78f9edefff6e663fd1Jim Miller
1178ecfac1d8c2988c3d5031e78f9edefff6e663fd1Jim Miller            public void afterTextChanged(Editable s) {
118ac8a59d3d3a6ddb32a293e4dfc74fb55a0ea6e82Adam Cohen                if (mCallback != null) {
119ac8a59d3d3a6ddb32a293e4dfc74fb55a0ea6e82Adam Cohen                    mCallback.userActivity(0);
120ac8a59d3d3a6ddb32a293e4dfc74fb55a0ea6e82Adam Cohen                }
1218ecfac1d8c2988c3d5031e78f9edefff6e663fd1Jim Miller            }
1228ecfac1d8c2988c3d5031e78f9edefff6e663fd1Jim Miller        });
123858f8eaac75bcd1b296b41837caf3dae82d1d72aJim Miller
12469bdee7c873c4a2295651efda2d0e79c515acc17Daniel Sandler        mPasswordEntry.requestFocus();
12569bdee7c873c4a2295651efda2d0e79c515acc17Daniel Sandler
126858f8eaac75bcd1b296b41837caf3dae82d1d72aJim Miller        // If there's more than one IME, enable the IME switcher button
127858f8eaac75bcd1b296b41837caf3dae82d1d72aJim Miller        View switchImeButton = findViewById(R.id.switch_ime_button);
1282c1ce0564fbd329e9e9ccfca100c69cfc1fd2645Daniel Sandler        if (switchImeButton != null && hasMultipleEnabledIMEsOrSubtypes(mImm, false)) {
129858f8eaac75bcd1b296b41837caf3dae82d1d72aJim Miller            switchImeButton.setVisibility(View.VISIBLE);
130d9d09451ccec7c551d5f9c2f1417c9c1de2952a6Jim Miller            imeOrDeleteButtonVisible = true;
131858f8eaac75bcd1b296b41837caf3dae82d1d72aJim Miller            switchImeButton.setOnClickListener(new OnClickListener() {
132858f8eaac75bcd1b296b41837caf3dae82d1d72aJim Miller                public void onClick(View v) {
133dcb3d84b82cc2448d04e73359a716581bfb657dbJim Miller                    mCallback.userActivity(0); // Leave the screen on a bit longer
1342c1ce0564fbd329e9e9ccfca100c69cfc1fd2645Daniel Sandler                    mImm.showInputMethodPicker();
135858f8eaac75bcd1b296b41837caf3dae82d1d72aJim Miller                }
136858f8eaac75bcd1b296b41837caf3dae82d1d72aJim Miller            });
137858f8eaac75bcd1b296b41837caf3dae82d1d72aJim Miller        }
138d9d09451ccec7c551d5f9c2f1417c9c1de2952a6Jim Miller
13970bc9f24ce6098a8c82245ac1ce7721d354ecd3dAdam Powell        // If no icon is visible, reset the start margin on the password field so the text is
140d9d09451ccec7c551d5f9c2f1417c9c1de2952a6Jim Miller        // still centered.
141d9d09451ccec7c551d5f9c2f1417c9c1de2952a6Jim Miller        if (!imeOrDeleteButtonVisible) {
142d9d09451ccec7c551d5f9c2f1417c9c1de2952a6Jim Miller            android.view.ViewGroup.LayoutParams params = mPasswordEntry.getLayoutParams();
143d9d09451ccec7c551d5f9c2f1417c9c1de2952a6Jim Miller            if (params instanceof MarginLayoutParams) {
14470bc9f24ce6098a8c82245ac1ce7721d354ecd3dAdam Powell                final MarginLayoutParams mlp = (MarginLayoutParams) params;
14570bc9f24ce6098a8c82245ac1ce7721d354ecd3dAdam Powell                mlp.setMarginStart(0);
146d9d09451ccec7c551d5f9c2f1417c9c1de2952a6Jim Miller                mPasswordEntry.setLayoutParams(params);
147d9d09451ccec7c551d5f9c2f1417c9c1de2952a6Jim Miller            }
148d9d09451ccec7c551d5f9c2f1417c9c1de2952a6Jim Miller        }
149858f8eaac75bcd1b296b41837caf3dae82d1d72aJim Miller    }
150858f8eaac75bcd1b296b41837caf3dae82d1d72aJim Miller
151858f8eaac75bcd1b296b41837caf3dae82d1d72aJim Miller    /**
152858f8eaac75bcd1b296b41837caf3dae82d1d72aJim Miller     * Method adapted from com.android.inputmethod.latin.Utils
153858f8eaac75bcd1b296b41837caf3dae82d1d72aJim Miller     *
154858f8eaac75bcd1b296b41837caf3dae82d1d72aJim Miller     * @param imm The input method manager
155858f8eaac75bcd1b296b41837caf3dae82d1d72aJim Miller     * @param shouldIncludeAuxiliarySubtypes
156858f8eaac75bcd1b296b41837caf3dae82d1d72aJim Miller     * @return true if we have multiple IMEs to choose from
157858f8eaac75bcd1b296b41837caf3dae82d1d72aJim Miller     */
158858f8eaac75bcd1b296b41837caf3dae82d1d72aJim Miller    private boolean hasMultipleEnabledIMEsOrSubtypes(InputMethodManager imm,
159858f8eaac75bcd1b296b41837caf3dae82d1d72aJim Miller            final boolean shouldIncludeAuxiliarySubtypes) {
160858f8eaac75bcd1b296b41837caf3dae82d1d72aJim Miller        final List<InputMethodInfo> enabledImis = imm.getEnabledInputMethodList();
161858f8eaac75bcd1b296b41837caf3dae82d1d72aJim Miller
162858f8eaac75bcd1b296b41837caf3dae82d1d72aJim Miller        // Number of the filtered IMEs
163858f8eaac75bcd1b296b41837caf3dae82d1d72aJim Miller        int filteredImisCount = 0;
164858f8eaac75bcd1b296b41837caf3dae82d1d72aJim Miller
165858f8eaac75bcd1b296b41837caf3dae82d1d72aJim Miller        for (InputMethodInfo imi : enabledImis) {
166858f8eaac75bcd1b296b41837caf3dae82d1d72aJim Miller            // We can return true immediately after we find two or more filtered IMEs.
167858f8eaac75bcd1b296b41837caf3dae82d1d72aJim Miller            if (filteredImisCount > 1) return true;
168858f8eaac75bcd1b296b41837caf3dae82d1d72aJim Miller            final List<InputMethodSubtype> subtypes =
169858f8eaac75bcd1b296b41837caf3dae82d1d72aJim Miller                    imm.getEnabledInputMethodSubtypeList(imi, true);
170858f8eaac75bcd1b296b41837caf3dae82d1d72aJim Miller            // IMEs that have no subtypes should be counted.
171858f8eaac75bcd1b296b41837caf3dae82d1d72aJim Miller            if (subtypes.isEmpty()) {
172858f8eaac75bcd1b296b41837caf3dae82d1d72aJim Miller                ++filteredImisCount;
173858f8eaac75bcd1b296b41837caf3dae82d1d72aJim Miller                continue;
174858f8eaac75bcd1b296b41837caf3dae82d1d72aJim Miller            }
175858f8eaac75bcd1b296b41837caf3dae82d1d72aJim Miller
176858f8eaac75bcd1b296b41837caf3dae82d1d72aJim Miller            int auxCount = 0;
177858f8eaac75bcd1b296b41837caf3dae82d1d72aJim Miller            for (InputMethodSubtype subtype : subtypes) {
178858f8eaac75bcd1b296b41837caf3dae82d1d72aJim Miller                if (subtype.isAuxiliary()) {
179858f8eaac75bcd1b296b41837caf3dae82d1d72aJim Miller                    ++auxCount;
180858f8eaac75bcd1b296b41837caf3dae82d1d72aJim Miller                }
181858f8eaac75bcd1b296b41837caf3dae82d1d72aJim Miller            }
182858f8eaac75bcd1b296b41837caf3dae82d1d72aJim Miller            final int nonAuxCount = subtypes.size() - auxCount;
183858f8eaac75bcd1b296b41837caf3dae82d1d72aJim Miller
184858f8eaac75bcd1b296b41837caf3dae82d1d72aJim Miller            // IMEs that have one or more non-auxiliary subtypes should be counted.
185858f8eaac75bcd1b296b41837caf3dae82d1d72aJim Miller            // If shouldIncludeAuxiliarySubtypes is true, IMEs that have two or more auxiliary
186858f8eaac75bcd1b296b41837caf3dae82d1d72aJim Miller            // subtypes should be counted as well.
187858f8eaac75bcd1b296b41837caf3dae82d1d72aJim Miller            if (nonAuxCount > 0 || (shouldIncludeAuxiliarySubtypes && auxCount > 1)) {
188858f8eaac75bcd1b296b41837caf3dae82d1d72aJim Miller                ++filteredImisCount;
189858f8eaac75bcd1b296b41837caf3dae82d1d72aJim Miller                continue;
190858f8eaac75bcd1b296b41837caf3dae82d1d72aJim Miller            }
191858f8eaac75bcd1b296b41837caf3dae82d1d72aJim Miller        }
192858f8eaac75bcd1b296b41837caf3dae82d1d72aJim Miller
193858f8eaac75bcd1b296b41837caf3dae82d1d72aJim Miller        return filteredImisCount > 1
194858f8eaac75bcd1b296b41837caf3dae82d1d72aJim Miller        // imm.getEnabledInputMethodSubtypeList(null, false) will return the current IME's enabled
195858f8eaac75bcd1b296b41837caf3dae82d1d72aJim Miller        // input method subtype (The current IME should be LatinIME.)
196858f8eaac75bcd1b296b41837caf3dae82d1d72aJim Miller                || imm.getEnabledInputMethodSubtypeList(null, false).size() > 1;
1975e0f7ba8fa8045aab98664b5103d8620e9ac7f06Jim Miller    }
1986fb841fa219eaae3e87f2fdc05e105d7a1813c42Adam Cohen
1996fb841fa219eaae3e87f2fdc05e105d7a1813c42Adam Cohen    @Override
2006fb841fa219eaae3e87f2fdc05e105d7a1813c42Adam Cohen    public void showUsabilityHint() {
2016fb841fa219eaae3e87f2fdc05e105d7a1813c42Adam Cohen    }
20216d90923149435cc7f565f684d42ecd074712ce5Daniel Sandler
20316d90923149435cc7f565f684d42ecd074712ce5Daniel Sandler    @Override
20416d90923149435cc7f565f684d42ecd074712ce5Daniel Sandler    public int getWrongPasswordStringId() {
20516d90923149435cc7f565f684d42ecd074712ce5Daniel Sandler        return R.string.kg_wrong_password;
20616d90923149435cc7f565f684d42ecd074712ce5Daniel Sandler    }
2075e0f7ba8fa8045aab98664b5103d8620e9ac7f06Jim Miller}
208