|
|
|
@@ -0,0 +1,645 @@
|
|
|
|
|
package com.goodiebag.pinview;
|
|
|
|
|
import android.content.Context;
|
|
|
|
|
import android.content.res.TypedArray;
|
|
|
|
|
import android.graphics.Rect;
|
|
|
|
|
import androidx.annotation.ColorInt;
|
|
|
|
|
import androidx.annotation.DrawableRes;
|
|
|
|
|
import androidx.annotation.NonNull;
|
|
|
|
|
import android.text.Editable;
|
|
|
|
|
import android.text.InputFilter;
|
|
|
|
|
import android.text.TextWatcher;
|
|
|
|
|
import android.text.method.TransformationMethod;
|
|
|
|
|
import android.util.AttributeSet;
|
|
|
|
|
import android.view.Gravity;
|
|
|
|
|
import android.view.KeyEvent;
|
|
|
|
|
import android.view.MotionEvent;
|
|
|
|
|
import android.view.View;
|
|
|
|
|
import android.view.inputmethod.InputMethodManager;
|
|
|
|
|
import android.widget.EditText;
|
|
|
|
|
import android.widget.LinearLayout;
|
|
|
|
|
import java.util.ArrayList;
|
|
|
|
|
import java.util.List;
|
|
|
|
|
|
|
|
|
|
import static android.text.InputType.TYPE_CLASS_NUMBER;
|
|
|
|
|
import static android.text.InputType.TYPE_CLASS_TEXT;
|
|
|
|
|
import static android.text.InputType.TYPE_NUMBER_VARIATION_PASSWORD;
|
|
|
|
|
public class Pinview extends LinearLayout implements TextWatcher, View.OnFocusChangeListener, View.OnKeyListener {
|
|
|
|
|
private final float DENSITY = getContext().getResources().getDisplayMetrics().density;
|
|
|
|
|
/**
|
|
|
|
|
* Attributes
|
|
|
|
|
*/
|
|
|
|
|
private int mPinLength = 4;
|
|
|
|
|
private List<EditText> editTextList = new ArrayList<>();
|
|
|
|
|
private int mPinWidth = 50;
|
|
|
|
|
private int mTextSize = 12;
|
|
|
|
|
private int mPinHeight = 50;
|
|
|
|
|
private int mSplitWidth = 20;
|
|
|
|
|
private boolean mCursorVisible = false;
|
|
|
|
|
private boolean mDelPressed = false;
|
|
|
|
|
@DrawableRes
|
|
|
|
|
private int mPinBackground = R.drawable.sample_background;
|
|
|
|
|
private boolean mPassword = false;
|
|
|
|
|
private String mHint = "";
|
|
|
|
|
private InputType inputType = InputType.TEXT;
|
|
|
|
|
private boolean finalNumberPin = false;
|
|
|
|
|
private PinViewEventListener mListener;
|
|
|
|
|
private boolean fromSetValue = false;
|
|
|
|
|
private boolean mForceKeyboard = true;
|
|
|
|
|
|
|
|
|
|
public enum InputType {
|
|
|
|
|
TEXT, NUMBER
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Interface for onDataEntered event.
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
public interface PinViewEventListener {
|
|
|
|
|
void onDataEntered(Pinview pinview, boolean fromUser);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
OnClickListener mClickListener;
|
|
|
|
|
|
|
|
|
|
View currentFocus = null;
|
|
|
|
|
|
|
|
|
|
InputFilter[] filters = new InputFilter[1];
|
|
|
|
|
LinearLayout.LayoutParams params;
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
public Pinview(Context context) {
|
|
|
|
|
this(context, null);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public Pinview(Context context, AttributeSet attrs) {
|
|
|
|
|
this(context, attrs, 0);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public Pinview(Context context, AttributeSet attrs, int defStyleAttr) {
|
|
|
|
|
super(context, attrs, defStyleAttr);
|
|
|
|
|
setGravity(Gravity.CENTER);
|
|
|
|
|
init(context, attrs, defStyleAttr);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* A method to take care of all the initialisations.
|
|
|
|
|
*
|
|
|
|
|
* @param context
|
|
|
|
|
* @param attrs
|
|
|
|
|
* @param defStyleAttr
|
|
|
|
|
*/
|
|
|
|
|
private void init(Context context, AttributeSet attrs, int defStyleAttr) {
|
|
|
|
|
this.removeAllViews();
|
|
|
|
|
mPinHeight *= DENSITY;
|
|
|
|
|
mPinWidth *= DENSITY;
|
|
|
|
|
mSplitWidth *= DENSITY;
|
|
|
|
|
setWillNotDraw(false);
|
|
|
|
|
initAttributes(context, attrs, defStyleAttr);
|
|
|
|
|
params = new LayoutParams(mPinWidth, mPinHeight);
|
|
|
|
|
setOrientation(HORIZONTAL);
|
|
|
|
|
createEditTexts();
|
|
|
|
|
super.setOnClickListener(new OnClickListener() {
|
|
|
|
|
@Override
|
|
|
|
|
public void onClick(View view) {
|
|
|
|
|
boolean focused = false;
|
|
|
|
|
for (EditText editText : editTextList) {
|
|
|
|
|
if (editText.length() == 0) {
|
|
|
|
|
editText.requestFocus();
|
|
|
|
|
openKeyboard();
|
|
|
|
|
focused = true;
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
if (!focused && editTextList.size() > 0) { // Focus the last view
|
|
|
|
|
editTextList.get(editTextList.size() - 1).requestFocus();
|
|
|
|
|
}
|
|
|
|
|
if (mClickListener != null) {
|
|
|
|
|
mClickListener.onClick(Pinview.this);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
});
|
|
|
|
|
// Bring up the keyboard
|
|
|
|
|
final View firstEditText = editTextList.get(0);
|
|
|
|
|
if (firstEditText != null)
|
|
|
|
|
firstEditText.postDelayed(new Runnable() {
|
|
|
|
|
@Override
|
|
|
|
|
public void run() {
|
|
|
|
|
openKeyboard();
|
|
|
|
|
}
|
|
|
|
|
}, 200);
|
|
|
|
|
updateEnabledState();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Creates editTexts and adds it to the pinview based on the pinLength specified.
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
private void createEditTexts() {
|
|
|
|
|
removeAllViews();
|
|
|
|
|
editTextList.clear();
|
|
|
|
|
EditText editText;
|
|
|
|
|
for (int i = 0; i < mPinLength; i++) {
|
|
|
|
|
editText = new EditText(getContext());
|
|
|
|
|
editText.setTextSize(mTextSize);
|
|
|
|
|
editTextList.add(i, editText);
|
|
|
|
|
this.addView(editText);
|
|
|
|
|
generateOneEditText(editText, "" + i);
|
|
|
|
|
}
|
|
|
|
|
setTransformation();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* This method gets the attribute values from the XML, if not found it takes the default values.
|
|
|
|
|
*
|
|
|
|
|
* @param context
|
|
|
|
|
* @param attrs
|
|
|
|
|
* @param defStyleAttr
|
|
|
|
|
*/
|
|
|
|
|
private void initAttributes(Context context, AttributeSet attrs, int defStyleAttr) {
|
|
|
|
|
if (attrs != null) {
|
|
|
|
|
final TypedArray array = context.obtainStyledAttributes(attrs, R.styleable.Pinview, defStyleAttr, 0);
|
|
|
|
|
mPinBackground = array.getResourceId(R.styleable.Pinview_pinBackground, mPinBackground);
|
|
|
|
|
mPinLength = array.getInt(R.styleable.Pinview_pinLength, mPinLength);
|
|
|
|
|
mPinHeight = (int) array.getDimension(R.styleable.Pinview_pinHeight, mPinHeight);
|
|
|
|
|
mPinWidth = (int) array.getDimension(R.styleable.Pinview_pinWidth, mPinWidth);
|
|
|
|
|
mSplitWidth = (int) array.getDimension(R.styleable.Pinview_splitWidth, mSplitWidth);
|
|
|
|
|
mTextSize = (int) array.getDimension(R.styleable.Pinview_textSize, mTextSize);
|
|
|
|
|
mCursorVisible = array.getBoolean(R.styleable.Pinview_cursorVisible, mCursorVisible);
|
|
|
|
|
mPassword = array.getBoolean(R.styleable.Pinview_password, mPassword);
|
|
|
|
|
mForceKeyboard = array.getBoolean(R.styleable.Pinview_forceKeyboard, mForceKeyboard);
|
|
|
|
|
mHint = array.getString(R.styleable.Pinview_hint);
|
|
|
|
|
InputType[] its = InputType.values();
|
|
|
|
|
inputType = its[array.getInt(R.styleable.Pinview_inputType, 0)];
|
|
|
|
|
array.recycle();
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Takes care of styling the editText passed in the param.
|
|
|
|
|
* tag is the index of the editText.
|
|
|
|
|
*
|
|
|
|
|
* @param styleEditText
|
|
|
|
|
* @param tag
|
|
|
|
|
*/
|
|
|
|
|
private void generateOneEditText(EditText styleEditText, String tag) {
|
|
|
|
|
params.setMargins(mSplitWidth / 2, mSplitWidth / 2, mSplitWidth / 2, mSplitWidth / 2);
|
|
|
|
|
filters[0] = new InputFilter.LengthFilter(1);
|
|
|
|
|
styleEditText.setFilters(filters);
|
|
|
|
|
styleEditText.setLayoutParams(params);
|
|
|
|
|
styleEditText.setGravity(Gravity.CENTER);
|
|
|
|
|
styleEditText.setCursorVisible(mCursorVisible);
|
|
|
|
|
|
|
|
|
|
if (!mCursorVisible) {
|
|
|
|
|
styleEditText.setClickable(false);
|
|
|
|
|
styleEditText.setHint(mHint);
|
|
|
|
|
|
|
|
|
|
styleEditText.setOnTouchListener((view, motionEvent) -> {
|
|
|
|
|
// When back space is pressed it goes to delete mode and when u click on an edit Text it should get out of the delete mode
|
|
|
|
|
mDelPressed = false;
|
|
|
|
|
return false;
|
|
|
|
|
});
|
|
|
|
|
}
|
|
|
|
|
styleEditText.setBackgroundResource(mPinBackground);
|
|
|
|
|
styleEditText.setPadding(0, 0, 0, 0);
|
|
|
|
|
styleEditText.setTag(tag);
|
|
|
|
|
styleEditText.setInputType(getKeyboardInputType());
|
|
|
|
|
styleEditText.addTextChangedListener(this);
|
|
|
|
|
styleEditText.setOnFocusChangeListener(this);
|
|
|
|
|
styleEditText.setOnKeyListener(this);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private int getKeyboardInputType() {
|
|
|
|
|
int it;
|
|
|
|
|
switch (inputType) {
|
|
|
|
|
case NUMBER:
|
|
|
|
|
it = TYPE_CLASS_NUMBER | TYPE_NUMBER_VARIATION_PASSWORD;
|
|
|
|
|
break;
|
|
|
|
|
case TEXT:
|
|
|
|
|
it = TYPE_CLASS_TEXT;
|
|
|
|
|
break;
|
|
|
|
|
default:
|
|
|
|
|
it = TYPE_CLASS_TEXT;
|
|
|
|
|
}
|
|
|
|
|
return it;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Returns the value of the Pinview
|
|
|
|
|
*
|
|
|
|
|
* @return
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
public String getValue() {
|
|
|
|
|
StringBuilder sb = new StringBuilder();
|
|
|
|
|
for (EditText et : editTextList) {
|
|
|
|
|
sb.append(et.getText().toString());
|
|
|
|
|
}
|
|
|
|
|
return sb.toString();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Requsets focus on current pin view and opens keyboard if forceKeyboard is enabled.
|
|
|
|
|
*
|
|
|
|
|
* @return the current focused pin view. It can be used to open softkeyboard manually.
|
|
|
|
|
*/
|
|
|
|
|
public View requestPinEntryFocus() {
|
|
|
|
|
int currentTag = Math.max(0, getIndexOfCurrentFocus());
|
|
|
|
|
EditText currentEditText = editTextList.get(currentTag);
|
|
|
|
|
if (currentEditText != null) {
|
|
|
|
|
currentEditText.requestFocus();
|
|
|
|
|
}
|
|
|
|
|
openKeyboard();
|
|
|
|
|
return currentEditText;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private void openKeyboard() {
|
|
|
|
|
if (mForceKeyboard) {
|
|
|
|
|
InputMethodManager inputMethodManager = (InputMethodManager) getContext().getSystemService(Context.INPUT_METHOD_SERVICE);
|
|
|
|
|
inputMethodManager.toggleSoftInput(InputMethodManager.SHOW_FORCED, InputMethodManager.HIDE_IMPLICIT_ONLY);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Clears the values in the Pinview
|
|
|
|
|
*/
|
|
|
|
|
public void clearValue() {
|
|
|
|
|
setValue("");
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Sets the value of the Pinview
|
|
|
|
|
*
|
|
|
|
|
* @param value
|
|
|
|
|
*/
|
|
|
|
|
public void setValue(@NonNull String value) {
|
|
|
|
|
String regex = "[0-9]*"; // Allow empty string to clear the fields
|
|
|
|
|
fromSetValue = true;
|
|
|
|
|
if (inputType == InputType.NUMBER && !value.matches(regex))
|
|
|
|
|
return;
|
|
|
|
|
int lastTagHavingValue = -1;
|
|
|
|
|
for (int i = 0; i < editTextList.size(); i++) {
|
|
|
|
|
if (value.length() > i) {
|
|
|
|
|
lastTagHavingValue = i;
|
|
|
|
|
editTextList.get(i).setText(((Character) value.charAt(i)).toString());
|
|
|
|
|
} else {
|
|
|
|
|
editTextList.get(i).setText("");
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
if (mPinLength > 0) {
|
|
|
|
|
if (lastTagHavingValue < mPinLength - 1) {
|
|
|
|
|
currentFocus = editTextList.get(lastTagHavingValue + 1);
|
|
|
|
|
} else {
|
|
|
|
|
currentFocus = editTextList.get(mPinLength - 1);
|
|
|
|
|
if (inputType == InputType.NUMBER || mPassword)
|
|
|
|
|
finalNumberPin = true;
|
|
|
|
|
if (mListener != null)
|
|
|
|
|
mListener.onDataEntered(this, false);
|
|
|
|
|
}
|
|
|
|
|
currentFocus.requestFocus();
|
|
|
|
|
}
|
|
|
|
|
fromSetValue = false;
|
|
|
|
|
updateEnabledState();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
@Override
|
|
|
|
|
public void onFocusChange(View view, boolean isFocused) {
|
|
|
|
|
if (isFocused && !mCursorVisible) {
|
|
|
|
|
if (mDelPressed) {
|
|
|
|
|
currentFocus = view;
|
|
|
|
|
mDelPressed = false;
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
for (final EditText editText : editTextList) {
|
|
|
|
|
if (editText.length() == 0) {
|
|
|
|
|
if (editText != view) {
|
|
|
|
|
editText.requestFocus();
|
|
|
|
|
} else {
|
|
|
|
|
currentFocus = view;
|
|
|
|
|
}
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
if (editTextList.get(editTextList.size() - 1) != view) {
|
|
|
|
|
editTextList.get(editTextList.size() - 1).requestFocus();
|
|
|
|
|
} else {
|
|
|
|
|
currentFocus = view;
|
|
|
|
|
}
|
|
|
|
|
} else if (isFocused && mCursorVisible) {
|
|
|
|
|
currentFocus = view;
|
|
|
|
|
} else {
|
|
|
|
|
view.clearFocus();
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Handles the character transformation for password inputs.
|
|
|
|
|
*/
|
|
|
|
|
private void setTransformation() {
|
|
|
|
|
if (mPassword) {
|
|
|
|
|
for (EditText editText : editTextList) {
|
|
|
|
|
editText.removeTextChangedListener(this);
|
|
|
|
|
editText.setTransformationMethod(new PinTransformationMethod());
|
|
|
|
|
editText.addTextChangedListener(this);
|
|
|
|
|
}
|
|
|
|
|
} else {
|
|
|
|
|
for (EditText editText : editTextList) {
|
|
|
|
|
editText.removeTextChangedListener(this);
|
|
|
|
|
editText.setTransformationMethod(null);
|
|
|
|
|
editText.addTextChangedListener(this);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
@Override
|
|
|
|
|
public void beforeTextChanged(CharSequence charSequence, int i, int i1, int i2) {
|
|
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Fired when text changes in the editTexts.
|
|
|
|
|
* Backspace is also identified here.
|
|
|
|
|
*
|
|
|
|
|
* @param charSequence
|
|
|
|
|
* @param start
|
|
|
|
|
* @param i1
|
|
|
|
|
* @param count
|
|
|
|
|
*/
|
|
|
|
|
@Override
|
|
|
|
|
public void onTextChanged(CharSequence charSequence, int start, int i1, int count) {
|
|
|
|
|
if (charSequence.length() == 1 && currentFocus != null) {
|
|
|
|
|
final int currentTag = getIndexOfCurrentFocus();
|
|
|
|
|
if (currentTag < mPinLength - 1) {
|
|
|
|
|
long delay = 1;
|
|
|
|
|
if (mPassword)
|
|
|
|
|
delay = 25;
|
|
|
|
|
this.postDelayed(new Runnable() {
|
|
|
|
|
@Override
|
|
|
|
|
public void run() {
|
|
|
|
|
EditText nextEditText = editTextList.get(currentTag + 1);
|
|
|
|
|
nextEditText.setEnabled(true);
|
|
|
|
|
nextEditText.requestFocus();
|
|
|
|
|
}
|
|
|
|
|
}, delay);
|
|
|
|
|
} else {
|
|
|
|
|
//Last Pin box has been reached.
|
|
|
|
|
}
|
|
|
|
|
if (currentTag == mPinLength - 1 && inputType == InputType.NUMBER || currentTag == mPinLength - 1 && mPassword) {
|
|
|
|
|
finalNumberPin = true;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
} else if (charSequence.length() == 0) {
|
|
|
|
|
int currentTag = getIndexOfCurrentFocus();
|
|
|
|
|
mDelPressed = true;
|
|
|
|
|
//For the last cell of the non password text fields. Clear the text without changing the focus.
|
|
|
|
|
if (editTextList.get(currentTag).getText().length() > 0)
|
|
|
|
|
editTextList.get(currentTag).setText("");
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
for (int index = 0; index < mPinLength; index++) {
|
|
|
|
|
if (editTextList.get(index).getText().length() < 1)
|
|
|
|
|
break;
|
|
|
|
|
if (!fromSetValue && index + 1 == mPinLength && mListener != null)
|
|
|
|
|
mListener.onDataEntered(this, true);
|
|
|
|
|
}
|
|
|
|
|
updateEnabledState();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Disable views ahead of current focus, so a selector can change the drawing of those views.
|
|
|
|
|
*/
|
|
|
|
|
private void updateEnabledState() {
|
|
|
|
|
int currentTag = Math.max(0, getIndexOfCurrentFocus());
|
|
|
|
|
for (int index = 0; index < editTextList.size(); index++) {
|
|
|
|
|
EditText editText = editTextList.get(index);
|
|
|
|
|
editText.setEnabled(index <= currentTag);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
@Override
|
|
|
|
|
public void afterTextChanged(Editable editable) {
|
|
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Monitors keyEvent.
|
|
|
|
|
*
|
|
|
|
|
* @param view
|
|
|
|
|
* @param i
|
|
|
|
|
* @param keyEvent
|
|
|
|
|
* @return
|
|
|
|
|
*/
|
|
|
|
|
@Override
|
|
|
|
|
public boolean onKey(View view, int i, KeyEvent keyEvent) {
|
|
|
|
|
|
|
|
|
|
if ((keyEvent.getAction() == KeyEvent.ACTION_UP) && (i == KeyEvent.KEYCODE_DEL)) {
|
|
|
|
|
// Perform action on Del press
|
|
|
|
|
int currentTag = getIndexOfCurrentFocus();
|
|
|
|
|
//Last tile of the number pad. Clear the edit text without changing the focus.
|
|
|
|
|
if (inputType == InputType.NUMBER && currentTag == mPinLength - 1 && finalNumberPin ||
|
|
|
|
|
(mPassword && currentTag == mPinLength - 1 && finalNumberPin)) {
|
|
|
|
|
if (editTextList.get(currentTag).length() > 0) {
|
|
|
|
|
editTextList.get(currentTag).setText("");
|
|
|
|
|
}
|
|
|
|
|
finalNumberPin = false;
|
|
|
|
|
} else if (currentTag > 0) {
|
|
|
|
|
mDelPressed = true;
|
|
|
|
|
if (editTextList.get(currentTag).length() == 0) {
|
|
|
|
|
//Takes it back one tile
|
|
|
|
|
editTextList.get(currentTag - 1).requestFocus();
|
|
|
|
|
//Clears the tile it just got to
|
|
|
|
|
editTextList.get(currentTag).setText("");
|
|
|
|
|
} else {
|
|
|
|
|
//If it has some content clear it first
|
|
|
|
|
editTextList.get(currentTag).setText("");
|
|
|
|
|
}
|
|
|
|
|
} else {
|
|
|
|
|
//For the first cell
|
|
|
|
|
if (editTextList.get(currentTag).getText().length() > 0)
|
|
|
|
|
editTextList.get(currentTag).setText("");
|
|
|
|
|
}
|
|
|
|
|
return true;
|
|
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* A class to implement the transformation mechanism
|
|
|
|
|
*/
|
|
|
|
|
private class PinTransformationMethod implements TransformationMethod {
|
|
|
|
|
|
|
|
|
|
private char BULLET = '\u2022';
|
|
|
|
|
|
|
|
|
|
@Override
|
|
|
|
|
public CharSequence getTransformation(CharSequence source, final View view) {
|
|
|
|
|
return new PasswordCharSequence(source);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
@Override
|
|
|
|
|
public void onFocusChanged(final View view, final CharSequence sourceText, final boolean focused, final int direction, final Rect previouslyFocusedRect) {
|
|
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private class PasswordCharSequence implements CharSequence {
|
|
|
|
|
private final CharSequence source;
|
|
|
|
|
|
|
|
|
|
public PasswordCharSequence(@NonNull CharSequence source) {
|
|
|
|
|
this.source = source;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
@Override
|
|
|
|
|
public int length() {
|
|
|
|
|
return source.length();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
@Override
|
|
|
|
|
public char charAt(int index) {
|
|
|
|
|
return BULLET;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
@Override
|
|
|
|
|
public CharSequence subSequence(int start, int end) {
|
|
|
|
|
return new PasswordCharSequence(this.source.subSequence(start, end));
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Getters and Setters
|
|
|
|
|
*/
|
|
|
|
|
private int getIndexOfCurrentFocus() {
|
|
|
|
|
return editTextList.indexOf(currentFocus);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
public int getSplitWidth() {
|
|
|
|
|
return mSplitWidth;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public void setSplitWidth(int splitWidth) {
|
|
|
|
|
this.mSplitWidth = splitWidth;
|
|
|
|
|
int margin = splitWidth / 2;
|
|
|
|
|
params.setMargins(margin, margin, margin, margin);
|
|
|
|
|
|
|
|
|
|
for (EditText editText : editTextList) {
|
|
|
|
|
editText.setLayoutParams(params);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public int getPinHeight() {
|
|
|
|
|
return mPinHeight;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public void setPinHeight(int pinHeight) {
|
|
|
|
|
this.mPinHeight = pinHeight;
|
|
|
|
|
params.height = pinHeight;
|
|
|
|
|
for (EditText editText : editTextList) {
|
|
|
|
|
editText.setLayoutParams(params);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public int getPinWidth() {
|
|
|
|
|
return mPinWidth;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public void setPinWidth(int pinWidth) {
|
|
|
|
|
this.mPinWidth = pinWidth;
|
|
|
|
|
params.width = pinWidth;
|
|
|
|
|
for (EditText editText : editTextList) {
|
|
|
|
|
editText.setLayoutParams(params);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public int getPinLength() {
|
|
|
|
|
return mPinLength;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public void setPinLength(int pinLength) {
|
|
|
|
|
this.mPinLength = pinLength;
|
|
|
|
|
createEditTexts();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public boolean isPassword() {
|
|
|
|
|
return mPassword;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public void setPassword(boolean password) {
|
|
|
|
|
this.mPassword = password;
|
|
|
|
|
setTransformation();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public String getHint() {
|
|
|
|
|
return mHint;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public void setHint(String mHint) {
|
|
|
|
|
this.mHint = mHint;
|
|
|
|
|
for (EditText editText : editTextList)
|
|
|
|
|
editText.setHint(mHint);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public
|
|
|
|
|
@DrawableRes
|
|
|
|
|
int getPinBackground() {
|
|
|
|
|
return mPinBackground;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public void setPinBackgroundRes(@DrawableRes int res) {
|
|
|
|
|
this.mPinBackground = res;
|
|
|
|
|
for (EditText editText : editTextList)
|
|
|
|
|
editText.setBackgroundResource(res);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
@Override
|
|
|
|
|
public void setOnClickListener(OnClickListener l) {
|
|
|
|
|
mClickListener = l;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public InputType getInputType() {
|
|
|
|
|
return inputType;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public void setInputType(InputType inputType) {
|
|
|
|
|
this.inputType = inputType;
|
|
|
|
|
int it = getKeyboardInputType();
|
|
|
|
|
for (EditText editText : editTextList) {
|
|
|
|
|
editText.setInputType(it);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public void setPinViewEventListener(PinViewEventListener listener) {
|
|
|
|
|
this.mListener = listener;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public void showCursor(boolean status) {
|
|
|
|
|
mCursorVisible = status;
|
|
|
|
|
if (editTextList == null || editTextList.isEmpty()) {
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
for (EditText edt : editTextList) {
|
|
|
|
|
edt.setCursorVisible(status);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public void setTextSize(int textSize) {
|
|
|
|
|
mTextSize = textSize;
|
|
|
|
|
if (editTextList == null || editTextList.isEmpty()) {
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
for (EditText edt : editTextList) {
|
|
|
|
|
edt.setTextSize(mTextSize);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public void setTextColor(@ColorInt int color) {
|
|
|
|
|
|
|
|
|
|
if (editTextList == null || editTextList.isEmpty()) {
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
for (EditText edt : editTextList) {
|
|
|
|
|
edt.setTextColor(color);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
}
|