Home | History | Annotate | Download | only in keyguard
      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