blob: ee7b5b1de024a8a8070222b9013ba03974173913 [file] [log] [blame]
/*
* Copyright (C) 2018 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.car.settings.security;
import android.content.Context;
import android.content.res.ColorStateList;
import android.content.res.TypedArray;
import android.util.AttributeSet;
import android.view.LayoutInflater;
import android.view.MotionEvent;
import android.view.View;
import android.widget.GridLayout;
import android.widget.ImageButton;
import android.widget.TextView;
import androidx.annotation.DrawableRes;
import androidx.annotation.Nullable;
import androidx.annotation.VisibleForTesting;
import com.android.car.settings.R;
import java.util.ArrayList;
import java.util.List;
/**
* A custom view for the PIN pad.
*/
public class PinPadView extends GridLayout {
// Number of keys in the pin pad, 0-9 plus backspace and enter keys.
@VisibleForTesting
static final int NUM_KEYS = 12;
@VisibleForTesting
static final int[] PIN_PAD_DIGIT_KEYS = {R.id.key0, R.id.key1, R.id.key2, R.id.key3,
R.id.key4, R.id.key5, R.id.key6, R.id.key7, R.id.key8, R.id.key9};
/**
* The delay in milliseconds between character deletion when the user continuously holds the
* backspace key.
*/
private static final int LONG_CLICK_DELAY_MILLS = 100;
private final List<View> mPinKeys = new ArrayList<>(NUM_KEYS);
private final Runnable mOnBackspaceLongClick = new Runnable() {
public void run() {
if (mOnClickListener != null) {
mOnClickListener.onBackspaceClick();
getHandler().postDelayed(this, LONG_CLICK_DELAY_MILLS);
}
}
};
private PinPadClickListener mOnClickListener;
private ImageButton mEnterKey;
public PinPadView(Context context) {
super(context);
init(null, 0, 0);
}
public PinPadView(Context context, AttributeSet attrs) {
super(context, attrs);
init(attrs, 0, 0);
}
public PinPadView(Context context, @Nullable AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
init(attrs, defStyleAttr, 0);
}
public PinPadView(Context context, @Nullable AttributeSet attrs, int defStyleAttr,
int defStyleRes) {
super(context, attrs, defStyleAttr, defStyleRes);
init(attrs, defStyleAttr, defStyleRes);
}
/**
* Set the call back for key click.
*
* @param pinPadClickListener The call back.
*/
public void setPinPadClickListener(PinPadClickListener pinPadClickListener) {
mOnClickListener = pinPadClickListener;
}
@Override
public void setEnabled(boolean enabled) {
super.setEnabled(enabled);
for (View key : mPinKeys) {
key.setEnabled(enabled);
}
}
/**
* Set the resource Id of the enter key icon.
*
* @param drawableId The resource Id of the drawable.
*/
public void setEnterKeyIcon(@DrawableRes int drawableId) {
mEnterKey.setImageResource(drawableId);
}
/**
* Override the default tint of the enter key icon.
*
* @param tint A ColorStateList.
*/
public void setEnterKeyImageTint(ColorStateList tint) {
mEnterKey.setImageTintList(tint);
}
/**
* Sets if the enter key for submitting a PIN is enabled or disabled.
*/
public void setEnterKeyEnabled(boolean enabled) {
mEnterKey.setEnabled(enabled);
}
private void init(AttributeSet attrs, int defStyleAttr, int defStyleRes) {
LayoutInflater inflater = LayoutInflater.from(getContext());
TypedArray typedArray = getContext().obtainStyledAttributes(
attrs, R.styleable.PinPadView, defStyleAttr, defStyleRes);
inflater.inflate(
typedArray.getResourceId(R.styleable.PinPadView_layout, R.layout.pin_pad_view),
this, true);
typedArray.recycle();
for (int keyId : PIN_PAD_DIGIT_KEYS) {
TextView key = findViewById(keyId);
String digit = key.getTag().toString();
key.setOnClickListener(v -> mOnClickListener.onDigitKeyClick(digit));
mPinKeys.add(key);
}
ImageButton backspace = findViewById(R.id.key_backspace);
backspace.setOnTouchListener((v, event) -> {
switch (event.getAction()) {
case MotionEvent.ACTION_DOWN:
getHandler().post(mOnBackspaceLongClick);
// Must return false so that ripple can show
return false;
case MotionEvent.ACTION_UP:
getHandler().removeCallbacks(mOnBackspaceLongClick);
// Must return false so that ripple can show
return false;
default:
return false;
}
});
mPinKeys.add(backspace);
mEnterKey = findViewById(R.id.key_enter);
mEnterKey.setOnClickListener(v -> mOnClickListener.onEnterKeyClick());
mPinKeys.add(mEnterKey);
}
/**
* The call back interface for onClick event in the view.
*/
public interface PinPadClickListener {
/**
* One of the digit key has been clicked.
*
* @param digit A String representing a digit between 0 and 9.
*/
void onDigitKeyClick(String digit);
/**
* The backspace key has been clicked.
*/
void onBackspaceClick();
/**
* The enter key has been clicked.
*/
void onEnterKeyClick();
}
}