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