/* * Copyright (C) 2012 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package com.android.keyguard; import android.content.Context; import android.text.InputType; import android.text.TextWatcher; import android.text.method.DigitsKeyListener; import android.util.AttributeSet; import android.view.View; import android.view.ViewGroup; import android.widget.TextView.OnEditorActionListener; /** * Displays a PIN pad for unlocking. */ public class KeyguardPINView extends KeyguardAbsKeyInputView implements KeyguardSecurityView, OnEditorActionListener, TextWatcher { private final AppearAnimationUtils mAppearAnimationUtils; private ViewGroup mKeyguardBouncerFrame; private ViewGroup mRow0; private ViewGroup mRow1; private ViewGroup mRow2; private ViewGroup mRow3; private View mDivider; public KeyguardPINView(Context context) { this(context, null); } public KeyguardPINView(Context context, AttributeSet attrs) { super(context, attrs); mAppearAnimationUtils = new AppearAnimationUtils(context); } protected void resetState() { if (KeyguardUpdateMonitor.getInstance(mContext).getMaxBiometricUnlockAttemptsReached()) { mSecurityMessageDisplay.setMessage(R.string.faceunlock_multiple_failures, true); } else { mSecurityMessageDisplay.setMessage(R.string.kg_pin_instructions, false); } mPasswordEntry.setEnabled(true); } @Override protected int getPasswordTextViewId() { return R.id.pinEntry; } @Override protected void onFinishInflate() { super.onFinishInflate(); mKeyguardBouncerFrame = (ViewGroup) findViewById(R.id.keyguard_bouncer_frame); mRow0 = (ViewGroup) findViewById(R.id.row0); mRow1 = (ViewGroup) findViewById(R.id.row1); mRow2 = (ViewGroup) findViewById(R.id.row2); mRow3 = (ViewGroup) findViewById(R.id.row3); mDivider = findViewById(R.id.divider); final View ok = findViewById(R.id.key_enter); if (ok != null) { ok.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { doHapticKeyClick(); if (mPasswordEntry.isEnabled()) { verifyPasswordAndUnlock(); } } }); ok.setOnHoverListener(new LiftToActivateListener(getContext())); } // The delete button is of the PIN keyboard itself in some (e.g. tablet) layouts, // not a separate view View pinDelete = findViewById(R.id.delete_button); if (pinDelete != null) { pinDelete.setVisibility(View.VISIBLE); pinDelete.setOnClickListener(new OnClickListener() { public void onClick(View v) { // check for time-based lockouts if (mPasswordEntry.isEnabled()) { CharSequence str = mPasswordEntry.getText(); if (str.length() > 0) { mPasswordEntry.setText(str.subSequence(0, str.length()-1)); } } doHapticKeyClick(); } }); pinDelete.setOnLongClickListener(new View.OnLongClickListener() { public boolean onLongClick(View v) { // check for time-based lockouts if (mPasswordEntry.isEnabled()) { mPasswordEntry.setText(""); } doHapticKeyClick(); return true; } }); } mPasswordEntry.setKeyListener(DigitsKeyListener.getInstance()); mPasswordEntry.setInputType(InputType.TYPE_CLASS_NUMBER | InputType.TYPE_NUMBER_VARIATION_PASSWORD); mPasswordEntry.requestFocus(); } @Override public void showUsabilityHint() { } @Override public int getWrongPasswordStringId() { return R.string.kg_wrong_pin; } @Override public void startAppearAnimation() { enableClipping(false); setTranslationY(mAppearAnimationUtils.getStartTranslation()); animate() .setDuration(500) .setInterpolator(mAppearAnimationUtils.getInterpolator()) .translationY(0); mAppearAnimationUtils.startAppearAnimation(new View[][] { new View[] { mRow0, null, null }, new View[] { findViewById(R.id.key1), findViewById(R.id.key2), findViewById(R.id.key3) }, new View[] { findViewById(R.id.key4), findViewById(R.id.key5), findViewById(R.id.key6) }, new View[] { findViewById(R.id.key7), findViewById(R.id.key8), findViewById(R.id.key9) }, new View[] { null, findViewById(R.id.key0), findViewById(R.id.key_enter) }, new View[] { null, mEcaView, null }}, new Runnable() { @Override public void run() { enableClipping(true); } }); } private void enableClipping(boolean enable) { mKeyguardBouncerFrame.setClipToPadding(enable); mKeyguardBouncerFrame.setClipChildren(enable); mRow1.setClipToPadding(enable); mRow2.setClipToPadding(enable); mRow3.setClipToPadding(enable); setClipChildren(enable); } }