/*
|
* 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
|
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);
|
if (enabled && !mPasswordEntry.hasFocus()) {
|
mPasswordEntry.requestFocus();
|
}
|
}
|
|
@Override
|
protected void setPasswordEntryInputEnabled(boolean enabled) {
|
mPasswordEntry.setEnabled(enabled);
|
mOkButton.setEnabled(enabled);
|
if (enabled && !mPasswordEntry.hasFocus()) {
|
mPasswordEntry.requestFocus();
|
}
|
}
|
|
@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 getPromptReasonStringRes(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 byte[] getPasswordText() {
|
return charSequenceToByteArray(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 void onResume(int reason) {
|
super.onResume(reason);
|
mPasswordEntry.requestFocus();
|
}
|
|
@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;
|
}
|
|
@Override
|
public CharSequence getTitle() {
|
return getContext().getString(
|
com.android.internal.R.string.keyguard_accessibility_pin_unlock);
|
}
|
|
/*
|
* This method avoids creating a new string when getting a byte array from EditView#getText().
|
*/
|
private static byte[] charSequenceToByteArray(CharSequence chars) {
|
if (chars == null) {
|
return null;
|
}
|
byte[] bytes = new byte[chars.length()];
|
for (int i = 0; i < chars.length(); i++) {
|
bytes[i] = (byte) chars.charAt(i);
|
}
|
return bytes;
|
}
|
}
|