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 17 package com.android.keyguard; 18 19 import android.app.admin.DevicePolicyManager; 20 import android.content.Context; 21 import android.content.res.Configuration; 22 import android.text.Editable; 23 import android.text.InputType; 24 import android.text.TextWatcher; 25 import android.text.method.DigitsKeyListener; 26 import android.text.method.TextKeyListener; 27 import android.util.AttributeSet; 28 import android.view.View; 29 import android.view.inputmethod.InputMethodInfo; 30 import android.view.inputmethod.InputMethodManager; 31 import android.view.inputmethod.InputMethodSubtype; 32 import android.widget.TextView.OnEditorActionListener; 33 34 import com.android.internal.widget.PasswordEntryKeyboardHelper; 35 import com.android.internal.widget.PasswordEntryKeyboardView; 36 37 import java.util.List; 38 /** 39 * Displays an alphanumeric (latin-1) key entry for the user to enter 40 * an unlock password 41 */ 42 43 public class KeyguardPasswordView extends KeyguardAbsKeyInputView 44 implements KeyguardSecurityView, OnEditorActionListener, TextWatcher { 45 46 private final boolean mShowImeAtScreenOn; 47 48 InputMethodManager mImm; 49 50 public KeyguardPasswordView(Context context) { 51 this(context, null); 52 } 53 54 public KeyguardPasswordView(Context context, AttributeSet attrs) { 55 super(context, attrs); 56 mShowImeAtScreenOn = context.getResources(). 57 getBoolean(R.bool.kg_show_ime_at_screen_on); 58 } 59 60 protected void resetState() { 61 mSecurityMessageDisplay.setMessage(R.string.kg_password_instructions, false); 62 mPasswordEntry.setEnabled(true); 63 } 64 65 @Override 66 protected int getPasswordTextViewId() { 67 return R.id.passwordEntry; 68 } 69 70 @Override 71 public boolean needsInput() { 72 return true; 73 } 74 75 @Override 76 public void onResume(int reason) { 77 super.onResume(reason); 78 mPasswordEntry.requestFocus(); 79 if (reason != KeyguardSecurityView.SCREEN_ON || mShowImeAtScreenOn) { 80 mImm.showSoftInput(mPasswordEntry, InputMethodManager.SHOW_IMPLICIT); 81 } 82 } 83 84 @Override 85 public void onPause() { 86 super.onPause(); 87 mImm.hideSoftInputFromWindow(getWindowToken(), 0); 88 } 89 90 @Override 91 protected void onFinishInflate() { 92 super.onFinishInflate(); 93 94 boolean imeOrDeleteButtonVisible = false; 95 96 mImm = (InputMethodManager) getContext().getSystemService( 97 Context.INPUT_METHOD_SERVICE); 98 99 mPasswordEntry.setKeyListener(TextKeyListener.getInstance()); 100 mPasswordEntry.setInputType(InputType.TYPE_CLASS_TEXT 101 | InputType.TYPE_TEXT_VARIATION_PASSWORD); 102 103 // Poke the wakelock any time the text is selected or modified 104 mPasswordEntry.setOnClickListener(new OnClickListener() { 105 public void onClick(View v) { 106 mCallback.userActivity(0); // TODO: customize timeout for text? 107 } 108 }); 109 110 mPasswordEntry.addTextChangedListener(new TextWatcher() { 111 public void onTextChanged(CharSequence s, int start, int before, int count) { 112 } 113 114 public void beforeTextChanged(CharSequence s, int start, int count, int after) { 115 } 116 117 public void afterTextChanged(Editable s) { 118 if (mCallback != null) { 119 mCallback.userActivity(0); 120 } 121 } 122 }); 123 124 mPasswordEntry.requestFocus(); 125 126 // If there's more than one IME, enable the IME switcher button 127 View switchImeButton = findViewById(R.id.switch_ime_button); 128 if (switchImeButton != null && hasMultipleEnabledIMEsOrSubtypes(mImm, false)) { 129 switchImeButton.setVisibility(View.VISIBLE); 130 imeOrDeleteButtonVisible = true; 131 switchImeButton.setOnClickListener(new OnClickListener() { 132 public void onClick(View v) { 133 mCallback.userActivity(0); // Leave the screen on a bit longer 134 mImm.showInputMethodPicker(); 135 } 136 }); 137 } 138 139 // If no icon is visible, reset the start margin on the password field so the text is 140 // still centered. 141 if (!imeOrDeleteButtonVisible) { 142 android.view.ViewGroup.LayoutParams params = mPasswordEntry.getLayoutParams(); 143 if (params instanceof MarginLayoutParams) { 144 final MarginLayoutParams mlp = (MarginLayoutParams) params; 145 mlp.setMarginStart(0); 146 mPasswordEntry.setLayoutParams(params); 147 } 148 } 149 } 150 151 /** 152 * Method adapted from com.android.inputmethod.latin.Utils 153 * 154 * @param imm The input method manager 155 * @param shouldIncludeAuxiliarySubtypes 156 * @return true if we have multiple IMEs to choose from 157 */ 158 private boolean hasMultipleEnabledIMEsOrSubtypes(InputMethodManager imm, 159 final boolean shouldIncludeAuxiliarySubtypes) { 160 final List<InputMethodInfo> enabledImis = imm.getEnabledInputMethodList(); 161 162 // Number of the filtered IMEs 163 int filteredImisCount = 0; 164 165 for (InputMethodInfo imi : enabledImis) { 166 // We can return true immediately after we find two or more filtered IMEs. 167 if (filteredImisCount > 1) return true; 168 final List<InputMethodSubtype> subtypes = 169 imm.getEnabledInputMethodSubtypeList(imi, true); 170 // IMEs that have no subtypes should be counted. 171 if (subtypes.isEmpty()) { 172 ++filteredImisCount; 173 continue; 174 } 175 176 int auxCount = 0; 177 for (InputMethodSubtype subtype : subtypes) { 178 if (subtype.isAuxiliary()) { 179 ++auxCount; 180 } 181 } 182 final int nonAuxCount = subtypes.size() - auxCount; 183 184 // IMEs that have one or more non-auxiliary subtypes should be counted. 185 // If shouldIncludeAuxiliarySubtypes is true, IMEs that have two or more auxiliary 186 // subtypes should be counted as well. 187 if (nonAuxCount > 0 || (shouldIncludeAuxiliarySubtypes && auxCount > 1)) { 188 ++filteredImisCount; 189 continue; 190 } 191 } 192 193 return filteredImisCount > 1 194 // imm.getEnabledInputMethodSubtypeList(null, false) will return the current IME's enabled 195 // input method subtype (The current IME should be LatinIME.) 196 || imm.getEnabledInputMethodSubtypeList(null, false).size() > 1; 197 } 198 199 @Override 200 public void showUsabilityHint() { 201 } 202 203 @Override 204 public int getWrongPasswordStringId() { 205 return R.string.kg_wrong_password; 206 } 207 } 208