/* * Copyright (C) 2014 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.graphics.Rect; import android.util.AttributeSet; import android.view.KeyEvent; import android.view.MotionEvent; import android.view.View; /** * A Pin based Keyguard input view */ public abstract class KeyguardPinBasedInputView extends KeyguardAbsKeyInputView implements View.OnKeyListener, View.OnTouchListener { protected PasswordTextView mPasswordEntry; private View mOkButton; private View mDeleteButton; private View mButton0; private View mButton1; private View mButton2; private View mButton3; private View mButton4; private View mButton5; private View mButton6; private View mButton7; private View mButton8; private View mButton9; public KeyguardPinBasedInputView(Context context) { this(context, null); } public KeyguardPinBasedInputView(Context context, AttributeSet attrs) { super(context, attrs); } @Override public void reset() { mPasswordEntry.requestFocus(); super.reset(); } @Override protected boolean onRequestFocusInDescendants(int direction, Rect previouslyFocusedRect) { // send focus to the password field return mPasswordEntry.requestFocus(direction, previouslyFocusedRect); } @Override protected void resetState() { setPasswordEntryEnabled(true); } @Override protected void setPasswordEntryEnabled(boolean enabled) { mPasswordEntry.setEnabled(enabled); mOkButton.setEnabled(enabled); } @Override protected void setPasswordEntryInputEnabled(boolean enabled) { mPasswordEntry.setEnabled(enabled); mOkButton.setEnabled(enabled); } @Override public boolean onKeyDown(int keyCode, KeyEvent event) { if (KeyEvent.isConfirmKey(keyCode)) { performClick(mOkButton); return true; } else if (keyCode == KeyEvent.KEYCODE_DEL) { performClick(mDeleteButton); return true; } if (keyCode >= KeyEvent.KEYCODE_0 && keyCode <= KeyEvent.KEYCODE_9) { int number = keyCode - KeyEvent.KEYCODE_0; performNumberClick(number); return true; } if (keyCode >= KeyEvent.KEYCODE_NUMPAD_0 && keyCode <= KeyEvent.KEYCODE_NUMPAD_9) { int number = keyCode - KeyEvent.KEYCODE_NUMPAD_0; performNumberClick(number); return true; } return super.onKeyDown(keyCode, event); } @Override protected int getPromtReasonStringRes(int reason) { switch (reason) { case PROMPT_REASON_RESTART: return R.string.kg_prompt_reason_restart_pin; case PROMPT_REASON_TIMEOUT: return R.string.kg_prompt_reason_timeout_pin; case PROMPT_REASON_DEVICE_ADMIN: return R.string.kg_prompt_reason_device_admin; case PROMPT_REASON_USER_REQUEST: return R.string.kg_prompt_reason_user_request; case PROMPT_REASON_NONE: return 0; default: return R.string.kg_prompt_reason_timeout_pin; } } private void performClick(View view) { view.performClick(); } private void performNumberClick(int number) { switch (number) { case 0: performClick(mButton0); break; case 1: performClick(mButton1); break; case 2: performClick(mButton2); break; case 3: performClick(mButton3); break; case 4: performClick(mButton4); break; case 5: performClick(mButton5); break; case 6: performClick(mButton6); break; case 7: performClick(mButton7); break; case 8: performClick(mButton8); break; case 9: performClick(mButton9); break; } } @Override protected void resetPasswordText(boolean animate, boolean announce) { mPasswordEntry.reset(animate, announce); } @Override protected String getPasswordText() { return mPasswordEntry.getText(); } @Override protected void onFinishInflate() { mPasswordEntry = findViewById(getPasswordTextViewId()); mPasswordEntry.setOnKeyListener(this); // Set selected property on so the view can send accessibility events. mPasswordEntry.setSelected(true); mPasswordEntry.setUserActivityListener(new PasswordTextView.UserActivityListener() { @Override public void onUserActivity() { onUserInput(); } }); mOkButton = findViewById(R.id.key_enter); if (mOkButton != null) { mOkButton.setOnTouchListener(this); mOkButton.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { if (mPasswordEntry.isEnabled()) { verifyPasswordAndUnlock(); } } }); mOkButton.setOnHoverListener(new LiftToActivateListener(getContext())); } mDeleteButton = findViewById(R.id.delete_button); mDeleteButton.setVisibility(View.VISIBLE); mDeleteButton.setOnTouchListener(this); mDeleteButton.setOnClickListener(new OnClickListener() { @Override public void onClick(View v) { // check for time-based lockouts if (mPasswordEntry.isEnabled()) { mPasswordEntry.deleteLastChar(); } } }); mDeleteButton.setOnLongClickListener(new View.OnLongClickListener() { @Override public boolean onLongClick(View v) { // check for time-based lockouts if (mPasswordEntry.isEnabled()) { resetPasswordText(true /* animate */, true /* announce */); } doHapticKeyClick(); return true; } }); mButton0 = findViewById(R.id.key0); mButton1 = findViewById(R.id.key1); mButton2 = findViewById(R.id.key2); mButton3 = findViewById(R.id.key3); mButton4 = findViewById(R.id.key4); mButton5 = findViewById(R.id.key5); mButton6 = findViewById(R.id.key6); mButton7 = findViewById(R.id.key7); mButton8 = findViewById(R.id.key8); mButton9 = findViewById(R.id.key9); mPasswordEntry.requestFocus(); super.onFinishInflate(); } @Override public boolean onTouch(View v, MotionEvent event) { if (event.getActionMasked() == MotionEvent.ACTION_DOWN) { doHapticKeyClick(); } return false; } @Override public boolean onKey(View v, int keyCode, KeyEvent event) { if (event.getAction() == KeyEvent.ACTION_DOWN) { return onKeyDown(keyCode, event); } return false; } }