1 /* 2 * Copyright 2018 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17 package androidx.leanback.widget.picker; 18 19 import android.annotation.SuppressLint; 20 import android.content.Context; 21 import android.content.res.TypedArray; 22 import android.util.AttributeSet; 23 import android.view.KeyEvent; 24 25 import androidx.core.view.ViewCompat; 26 import androidx.leanback.R; 27 28 import java.util.ArrayList; 29 import java.util.List; 30 31 /** 32 * {@link Picker} subclass for allowing the user to enter a numerical PIN. The column count can be 33 * customized, and defaults to 4. 34 * 35 * {@link R.attr#columnCount} 36 */ 37 public class PinPicker extends Picker { 38 39 private static final int DEFAULT_COLUMN_COUNT = 4; 40 PinPicker(Context context, AttributeSet attrs)41 public PinPicker(Context context, AttributeSet attrs) { 42 this(context, attrs, R.attr.pinPickerStyle); 43 } 44 45 @SuppressLint("CustomViewStyleable") PinPicker(Context context, AttributeSet attrs, int defStyleAttr)46 public PinPicker(Context context, AttributeSet attrs, int defStyleAttr) { 47 super(context, attrs, defStyleAttr); 48 final TypedArray a = context.obtainStyledAttributes( 49 attrs, R.styleable.lbPinPicker, defStyleAttr, 0); 50 ViewCompat.saveAttributeDataForStyleable( 51 this, context, R.styleable.lbPinPicker, attrs, a, defStyleAttr, 0); 52 try { 53 setSeparator(" "); 54 setNumberOfColumns(a.getInt(R.styleable.lbPinPicker_columnCount, DEFAULT_COLUMN_COUNT)); 55 } finally { 56 a.recycle(); 57 } 58 } 59 60 /** 61 * Sets the number of columns for entering the PIN. 62 * 63 * @param count how many columns to display. 64 */ setNumberOfColumns(int count)65 public void setNumberOfColumns(int count) { 66 final List<PickerColumn> columns = new ArrayList<>(count); 67 for (int i = 0; i < count; i++) { 68 final PickerColumn column = new PickerColumn(); 69 column.setMinValue(0); 70 column.setMaxValue(9); 71 column.setLabelFormat("%d"); 72 columns.add(column); 73 } 74 setColumns(columns); 75 } 76 77 @Override performClick()78 public boolean performClick() { 79 final int column = getSelectedColumn(); 80 if (column == getColumnsCount() - 1) { 81 return super.performClick(); 82 } else { 83 setSelectedColumn(column + 1); 84 return false; 85 } 86 } 87 88 @Override dispatchKeyEvent(KeyEvent event)89 public boolean dispatchKeyEvent(KeyEvent event) { 90 final int keyCode = event.getKeyCode(); 91 if (event.getAction() == KeyEvent.ACTION_UP 92 && keyCode >= KeyEvent.KEYCODE_0 && keyCode <= KeyEvent.KEYCODE_9) { 93 final int selectedColumn = getSelectedColumn(); 94 setColumnValue(selectedColumn, keyCode - KeyEvent.KEYCODE_0, false /* animate */); 95 performClick(); 96 return true; 97 } 98 return super.dispatchKeyEvent(event); 99 } 100 101 /** 102 * Returns the PIN that the user has entered. 103 * 104 * @return Currently entered PIN 105 */ getPin()106 public String getPin() { 107 final StringBuilder pin = new StringBuilder(); 108 final int columnsCount = getColumnsCount(); 109 for (int i = 0; i < columnsCount; i++) { 110 pin.append(Integer.toString(getColumnAt(i).getCurrentValue())); 111 } 112 return pin.toString(); 113 } 114 115 /** 116 * Resets all columns and selects the first one. 117 */ resetPin()118 public void resetPin() { 119 final int columnsCount = getColumnsCount(); 120 for (int i = 0; i < columnsCount; i++) { 121 setColumnValue(i, 0, false /* animate */); 122 } 123 setSelectedColumn(0); 124 } 125 } 126