KeyguardPasswordView.java revision 6fb841fa219eaae3e87f2fdc05e105d7a1813c42
1/*
2 * Copyright (C) 2012 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.internal.policy.impl.keyguard;
18
19import android.content.Context;
20import android.util.AttributeSet;
21import android.view.View;
22
23import com.android.internal.R;
24import com.android.internal.widget.LockPatternUtils;
25import java.util.List;
26
27import android.app.admin.DevicePolicyManager;
28import android.content.res.Configuration;
29import android.graphics.Rect;
30
31import com.android.internal.widget.PasswordEntryKeyboardView;
32
33import android.os.CountDownTimer;
34import android.os.SystemClock;
35import android.text.Editable;
36import android.text.InputType;
37import android.text.TextWatcher;
38import android.text.method.DigitsKeyListener;
39import android.text.method.TextKeyListener;
40import android.view.KeyEvent;
41import android.view.inputmethod.EditorInfo;
42import android.view.inputmethod.InputMethodInfo;
43import android.view.inputmethod.InputMethodManager;
44import android.view.inputmethod.InputMethodSubtype;
45import android.widget.EditText;
46import android.widget.LinearLayout;
47import android.widget.TextView;
48import android.widget.TextView.OnEditorActionListener;
49
50import com.android.internal.widget.PasswordEntryKeyboardHelper;
51/**
52 * Displays a dialer-like interface or alphanumeric (latin-1) key entry for the user to enter
53 * an unlock password
54 */
55
56public class KeyguardPasswordView extends KeyguardAbsKeyInputView
57        implements KeyguardSecurityView, OnEditorActionListener, TextWatcher {
58
59    private PasswordEntryKeyboardView mKeyboardView;
60    private PasswordEntryKeyboardHelper mKeyboardHelper;
61    private boolean mIsAlpha;
62
63    public KeyguardPasswordView(Context context) {
64        super(context);
65    }
66
67    public KeyguardPasswordView(Context context, AttributeSet attrs) {
68        super(context, attrs);
69    }
70
71    protected void resetState() {
72        mSecurityMessageDisplay.setMessage(
73                mIsAlpha ? R.string.kg_password_instructions : R.string.kg_pin_instructions, false);
74        mPasswordEntry.setEnabled(true);
75        mKeyboardView.setEnabled(true);
76    }
77
78    @Override
79    protected void onFinishInflate() {
80        super.onFinishInflate();
81
82        final int quality = mLockPatternUtils.getKeyguardStoredPasswordQuality();
83        mIsAlpha = DevicePolicyManager.PASSWORD_QUALITY_ALPHABETIC == quality
84                || DevicePolicyManager.PASSWORD_QUALITY_ALPHANUMERIC == quality
85                || DevicePolicyManager.PASSWORD_QUALITY_COMPLEX == quality;
86
87        mKeyboardView = (PasswordEntryKeyboardView) findViewById(R.id.keyboard);
88
89        mKeyboardHelper = new PasswordEntryKeyboardHelper(mContext, mKeyboardView, this, false,
90                new int[] {
91                    R.xml.kg_password_kbd_numeric,
92                    com.android.internal.R.xml.password_kbd_qwerty,
93                    com.android.internal.R.xml.password_kbd_qwerty_shifted,
94                    com.android.internal.R.xml.password_kbd_symbols,
95                    com.android.internal.R.xml.password_kbd_symbols_shift
96                    }
97        );
98        mKeyboardHelper.setEnableHaptics(mLockPatternUtils.isTactileFeedbackEnabled());
99
100        boolean imeOrDeleteButtonVisible = false;
101        if (mIsAlpha) {
102            // We always use the system IME for alpha keyboard, so hide lockscreen's soft keyboard
103            mKeyboardHelper.setKeyboardMode(PasswordEntryKeyboardHelper.KEYBOARD_MODE_ALPHA);
104            mKeyboardView.setVisibility(View.GONE);
105        } else {
106            mKeyboardHelper.setKeyboardMode(PasswordEntryKeyboardHelper.KEYBOARD_MODE_NUMERIC);
107
108            // Use lockscreen's numeric keyboard if the physical keyboard isn't showing
109            boolean hardKeyboardVisible = getResources().getConfiguration().hardKeyboardHidden
110                    == Configuration.HARDKEYBOARDHIDDEN_NO;
111            mKeyboardView.setVisibility(
112                    (ENABLE_HIDE_KEYBOARD && hardKeyboardVisible) ? View.INVISIBLE : View.VISIBLE);
113
114            // The delete button is of the PIN keyboard itself in some (e.g. tablet) layouts,
115            // not a separate view
116            View pinDelete = findViewById(R.id.delete_button);
117            if (pinDelete != null) {
118                pinDelete.setVisibility(View.VISIBLE);
119                imeOrDeleteButtonVisible = true;
120                pinDelete.setOnClickListener(new OnClickListener() {
121                    public void onClick(View v) {
122                        mKeyboardHelper.handleBackspace();
123                    }
124                });
125            }
126        }
127
128        // This allows keyboards with overlapping qwerty/numeric keys to choose just numeric keys.
129        if (mIsAlpha) {
130            mPasswordEntry.setKeyListener(TextKeyListener.getInstance());
131            mPasswordEntry.setInputType(InputType.TYPE_CLASS_TEXT
132                    | InputType.TYPE_TEXT_VARIATION_PASSWORD);
133        } else {
134            mPasswordEntry.setKeyListener(DigitsKeyListener.getInstance());
135            mPasswordEntry.setInputType(InputType.TYPE_CLASS_NUMBER
136                    | InputType.TYPE_NUMBER_VARIATION_PASSWORD);
137        }
138
139        // Poke the wakelock any time the text is selected or modified
140        mPasswordEntry.setOnClickListener(new OnClickListener() {
141            public void onClick(View v) {
142                mCallback.userActivity(0); // TODO: customize timeout for text?
143            }
144        });
145
146        mPasswordEntry.addTextChangedListener(new TextWatcher() {
147            public void onTextChanged(CharSequence s, int start, int before, int count) {
148            }
149
150            public void beforeTextChanged(CharSequence s, int start, int count, int after) {
151            }
152
153            public void afterTextChanged(Editable s) {
154                if (mCallback != null) {
155                    mCallback.userActivity(0);
156                }
157            }
158        });
159
160        mPasswordEntry.requestFocus();
161
162        // If there's more than one IME, enable the IME switcher button
163        View switchImeButton = findViewById(R.id.switch_ime_button);
164        final InputMethodManager imm = (InputMethodManager) getContext().getSystemService(
165                Context.INPUT_METHOD_SERVICE);
166        if (mIsAlpha && switchImeButton != null && hasMultipleEnabledIMEsOrSubtypes(imm, false)) {
167            switchImeButton.setVisibility(View.VISIBLE);
168            imeOrDeleteButtonVisible = true;
169            switchImeButton.setOnClickListener(new OnClickListener() {
170                public void onClick(View v) {
171                    mCallback.userActivity(0); // Leave the screen on a bit longer
172                    imm.showInputMethodPicker();
173                }
174            });
175        }
176
177        // If no icon is visible, reset the start margin on the password field so the text is
178        // still centered.
179        if (!imeOrDeleteButtonVisible) {
180            android.view.ViewGroup.LayoutParams params = mPasswordEntry.getLayoutParams();
181            if (params instanceof MarginLayoutParams) {
182                final MarginLayoutParams mlp = (MarginLayoutParams) params;
183                mlp.setMarginStart(0);
184                mPasswordEntry.setLayoutParams(params);
185            }
186        }
187    }
188
189    /**
190     * Method adapted from com.android.inputmethod.latin.Utils
191     *
192     * @param imm The input method manager
193     * @param shouldIncludeAuxiliarySubtypes
194     * @return true if we have multiple IMEs to choose from
195     */
196    private boolean hasMultipleEnabledIMEsOrSubtypes(InputMethodManager imm,
197            final boolean shouldIncludeAuxiliarySubtypes) {
198        final List<InputMethodInfo> enabledImis = imm.getEnabledInputMethodList();
199
200        // Number of the filtered IMEs
201        int filteredImisCount = 0;
202
203        for (InputMethodInfo imi : enabledImis) {
204            // We can return true immediately after we find two or more filtered IMEs.
205            if (filteredImisCount > 1) return true;
206            final List<InputMethodSubtype> subtypes =
207                    imm.getEnabledInputMethodSubtypeList(imi, true);
208            // IMEs that have no subtypes should be counted.
209            if (subtypes.isEmpty()) {
210                ++filteredImisCount;
211                continue;
212            }
213
214            int auxCount = 0;
215            for (InputMethodSubtype subtype : subtypes) {
216                if (subtype.isAuxiliary()) {
217                    ++auxCount;
218                }
219            }
220            final int nonAuxCount = subtypes.size() - auxCount;
221
222            // IMEs that have one or more non-auxiliary subtypes should be counted.
223            // If shouldIncludeAuxiliarySubtypes is true, IMEs that have two or more auxiliary
224            // subtypes should be counted as well.
225            if (nonAuxCount > 0 || (shouldIncludeAuxiliarySubtypes && auxCount > 1)) {
226                ++filteredImisCount;
227                continue;
228            }
229        }
230
231        return filteredImisCount > 1
232        // imm.getEnabledInputMethodSubtypeList(null, false) will return the current IME's enabled
233        // input method subtype (The current IME should be LatinIME.)
234                || imm.getEnabledInputMethodSubtypeList(null, false).size() > 1;
235    }
236
237    @Override
238    public void showUsabilityHint() {
239    }
240}
241
242