PinDialogFragment.java revision 3150b12e5df05eec2c3ebb85360661f1d034c188
165a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane/* 265a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane * Copyright (C) 2014 The Android Open Source Project 365a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane * 465a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane * Licensed under the Apache License, Version 2.0 (the "License"); 565a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane * you may not use this file except in compliance with the License. 665a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane * You may obtain a copy of the License at 765a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane * 865a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane * http://www.apache.org/licenses/LICENSE-2.0 965a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane * 1065a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane * Unless required by applicable law or agreed to in writing, software 1165a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane * distributed under the License is distributed on an "AS IS" BASIS, 1265a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 1365a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane * See the License for the specific language governing permissions and 1465a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane * limitations under the License. 1565a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane */ 1665a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane 17a10ccbdf6a7bdf626ee6e58574d9f8d800d124f5Tony Mantlerpackage com.android.tv.settings.dialog; 1865a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane 1965a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Laneimport android.animation.Animator; 2065a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Laneimport android.animation.AnimatorInflater; 21c03836a4b5c65e59fc5abc73cc42d0b56176d5e6Tony Mantlerimport android.app.Activity; 2265a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Laneimport android.app.Dialog; 233150b12e5df05eec2c3ebb85360661f1d034c188Andrew Wilsonimport android.app.Fragment; 2465a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Laneimport android.content.Context; 2565a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Laneimport android.content.DialogInterface; 2665a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Laneimport android.content.res.Resources; 2765a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Laneimport android.os.Bundle; 2865a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Laneimport android.os.Handler; 2965a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Laneimport android.text.TextUtils; 3065a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Laneimport android.text.format.DateUtils; 3165a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Laneimport android.util.AttributeSet; 3265a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Laneimport android.util.Log; 3365a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Laneimport android.util.TypedValue; 3465a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Laneimport android.view.KeyEvent; 3565a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Laneimport android.view.LayoutInflater; 3665a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Laneimport android.view.View; 3765a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Laneimport android.view.ViewGroup; 3865a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Laneimport android.widget.FrameLayout; 3965a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Laneimport android.widget.OverScroller; 4065a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Laneimport android.widget.TextView; 4165a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Laneimport android.widget.Toast; 4265a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane 4365a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Laneimport com.android.tv.settings.R; 4465a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane 4565a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lanepublic abstract class PinDialogFragment extends SafeDismissDialogFragment { 4665a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane private static final String TAG = "PinDialogFragment"; 476e995161147d9110d77ae1fe38b697e52891d3f2Tony Mantler private static final boolean DEBUG = false; 4865a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane 49c03836a4b5c65e59fc5abc73cc42d0b56176d5e6Tony Mantler protected static final String ARG_TYPE = "type"; 50c03836a4b5c65e59fc5abc73cc42d0b56176d5e6Tony Mantler 5165a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane /** 5265a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane * PIN code dialog for unlock channel 5365a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane */ 5465a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane public static final int PIN_DIALOG_TYPE_UNLOCK_CHANNEL = 0; 5565a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane 5665a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane /** 5765a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane * PIN code dialog for unlock content. 5865a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane * Only difference between {@code PIN_DIALOG_TYPE_UNLOCK_CHANNEL} is it's title. 5965a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane */ 6065a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane public static final int PIN_DIALOG_TYPE_UNLOCK_PROGRAM = 1; 6165a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane 6265a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane /** 6365a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane * PIN code dialog for change parental control settings 6465a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane */ 6565a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane public static final int PIN_DIALOG_TYPE_ENTER_PIN = 2; 6665a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane 6765a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane /** 6865a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane * PIN code dialog for set new PIN 6965a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane */ 7065a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane public static final int PIN_DIALOG_TYPE_NEW_PIN = 3; 7165a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane 7265a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane // PIN code dialog for checking old PIN. This is intenal only. 7365a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane private static final int PIN_DIALOG_TYPE_OLD_PIN = 4; 7465a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane 7565a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane private static final int PIN_DIALOG_RESULT_SUCCESS = 0; 7665a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane private static final int PIN_DIALOG_RESULT_FAIL = 1; 7765a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane 7865a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane private static final int MAX_WRONG_PIN_COUNT = 5; 7965a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane private static final int DISABLE_PIN_DURATION_MILLIS = 60 * 1000; // 1 minute 8065a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane 8165a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane public interface ResultListener { 82c03836a4b5c65e59fc5abc73cc42d0b56176d5e6Tony Mantler void pinFragmentDone(boolean success); 8365a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane } 8465a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane 8565a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane public static final String DIALOG_TAG = PinDialogFragment.class.getName(); 8665a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane 8765a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane private static final int NUMBER_PICKERS_RES_ID[] = { 8865a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane R.id.first, R.id.second, R.id.third, R.id.fourth }; 8965a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane 9065a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane private int mType; 9165a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane private int mRetCode; 9265a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane 9365a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane private TextView mWrongPinView; 9465a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane private View mEnterPinView; 9565a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane private TextView mTitleView; 9665a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane private PinNumberPicker[] mPickers; 9765a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane private String mPrevPin; 9865a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane private int mWrongPinCount; 9965a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane private long mDisablePinUntil; 10065a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane private final Handler mHandler = new Handler(); 10165a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane 10265a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane public abstract long getPinDisabledUntil(); 10365a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane public abstract void setPinDisabledUntil(long retryDisableTimeout); 10465a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane public abstract void setPin(String pin); 10565a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane public abstract boolean isPinCorrect(String pin); 10665a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane public abstract boolean isPinSet(); 10765a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane 108c03836a4b5c65e59fc5abc73cc42d0b56176d5e6Tony Mantler public PinDialogFragment() { 10965a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane mRetCode = PIN_DIALOG_RESULT_FAIL; 11065a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane } 11165a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane 11265a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane @Override 11365a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane public void onCreate(Bundle savedInstanceState) { 11465a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane super.onCreate(savedInstanceState); 11565a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane setStyle(STYLE_NO_TITLE, 0); 11665a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane mDisablePinUntil = getPinDisabledUntil(); 117c03836a4b5c65e59fc5abc73cc42d0b56176d5e6Tony Mantler final Bundle args = getArguments(); 118c03836a4b5c65e59fc5abc73cc42d0b56176d5e6Tony Mantler if (!args.containsKey(ARG_TYPE)) { 119c03836a4b5c65e59fc5abc73cc42d0b56176d5e6Tony Mantler throw new IllegalStateException("Fragment arguments must specify type"); 120c03836a4b5c65e59fc5abc73cc42d0b56176d5e6Tony Mantler } 121c03836a4b5c65e59fc5abc73cc42d0b56176d5e6Tony Mantler mType = getArguments().getInt(ARG_TYPE); 12265a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane } 12365a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane 12465a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane @Override 12565a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane public Dialog onCreateDialog(Bundle savedInstanceState) { 12665a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane Dialog dlg = super.onCreateDialog(savedInstanceState); 12765a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane dlg.getWindow().getAttributes().windowAnimations = R.style.pin_dialog_animation; 12865a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane PinNumberPicker.loadResources(dlg.getContext()); 12965a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane return dlg; 13065a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane } 13165a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane 13265a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane @Override 13365a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane public View onCreateView(LayoutInflater inflater, ViewGroup container, 13465a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane Bundle savedInstanceState) { 13565a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane final View v = inflater.inflate(R.layout.pin_dialog, container, false); 13665a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane 13765a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane mWrongPinView = (TextView) v.findViewById(R.id.wrong_pin); 13865a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane mEnterPinView = v.findViewById(R.id.enter_pin); 13965a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane mTitleView = (TextView) mEnterPinView.findViewById(R.id.title); 14065a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane if (!isPinSet()) { 14165a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane // If PIN isn't set, user should set a PIN. 14265a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane // Successfully setting a new set is considered as entering correct PIN. 14365a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane mType = PIN_DIALOG_TYPE_NEW_PIN; 14465a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane } 14565a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane switch (mType) { 14665a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane case PIN_DIALOG_TYPE_UNLOCK_CHANNEL: 14765a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane mTitleView.setText(R.string.pin_enter_unlock_channel); 14865a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane break; 14965a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane case PIN_DIALOG_TYPE_UNLOCK_PROGRAM: 15065a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane mTitleView.setText(R.string.pin_enter_unlock_program); 15165a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane break; 15265a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane case PIN_DIALOG_TYPE_ENTER_PIN: 15365a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane mTitleView.setText(R.string.pin_enter_pin); 15465a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane break; 15565a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane case PIN_DIALOG_TYPE_NEW_PIN: 15665a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane if (!isPinSet()) { 15765a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane mTitleView.setText(R.string.pin_enter_new_pin); 15865a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane } else { 15965a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane mTitleView.setText(R.string.pin_enter_old_pin); 16065a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane mType = PIN_DIALOG_TYPE_OLD_PIN; 16165a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane } 16265a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane } 16365a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane 16465a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane mPickers = new PinNumberPicker[NUMBER_PICKERS_RES_ID.length]; 16565a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane for (int i = 0; i < NUMBER_PICKERS_RES_ID.length; i++) { 16665a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane mPickers[i] = (PinNumberPicker) v.findViewById(NUMBER_PICKERS_RES_ID[i]); 16765a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane mPickers[i].setValueRange(0, 9); 16865a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane mPickers[i].setPinDialogFragment(this); 16965a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane mPickers[i].updateFocus(); 17065a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane } 17165a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane for (int i = 0; i < NUMBER_PICKERS_RES_ID.length - 1; i++) { 17265a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane mPickers[i].setNextNumberPicker(mPickers[i + 1]); 17365a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane } 17465a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane 17565a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane if (mType != PIN_DIALOG_TYPE_NEW_PIN) { 17665a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane updateWrongPin(); 17765a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane } 17865a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane return v; 17965a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane } 18065a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane 18165a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane private final Runnable mUpdateEnterPinRunnable = new Runnable() { 18265a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane @Override 18365a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane public void run() { 18465a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane updateWrongPin(); 18565a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane } 18665a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane }; 18765a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane 18865a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane private void updateWrongPin() { 18965a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane if (getActivity() == null) { 19065a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane // The activity is already detached. No need to update. 19165a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane mHandler.removeCallbacks(null); 19265a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane return; 19365a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane } 19465a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane 19565a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane boolean enabled = (mDisablePinUntil - System.currentTimeMillis()) / 1000 < 1; 19665a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane if (enabled) { 19765a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane mWrongPinView.setVisibility(View.INVISIBLE); 19865a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane mEnterPinView.setVisibility(View.VISIBLE); 19965a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane mWrongPinCount = 0; 20065a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane } else { 20165a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane mEnterPinView.setVisibility(View.INVISIBLE); 20265a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane mWrongPinView.setVisibility(View.VISIBLE); 20365a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane mWrongPinView.setText(getResources().getString(R.string.pin_enter_wrong, 20465a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane DateUtils.getRelativeTimeSpanString(mDisablePinUntil, 20565a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane System.currentTimeMillis(), DateUtils.SECOND_IN_MILLIS))); 20665a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane mHandler.postDelayed(mUpdateEnterPinRunnable, 1000); 20765a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane } 20865a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane } 20965a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane 21065a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane private void exit(int retCode) { 21165a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane mRetCode = retCode; 21265a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane dismiss(); 21365a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane } 21465a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane 21565a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane @Override 21665a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane public void onDismiss(DialogInterface dialog) { 21765a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane super.onDismiss(dialog); 21865a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane if (DEBUG) Log.d(TAG, "onDismiss: mRetCode=" + mRetCode); 2193150b12e5df05eec2c3ebb85360661f1d034c188Andrew Wilson 2203150b12e5df05eec2c3ebb85360661f1d034c188Andrew Wilson boolean result = mRetCode == PIN_DIALOG_RESULT_SUCCESS; 2213150b12e5df05eec2c3ebb85360661f1d034c188Andrew Wilson Fragment f = getTargetFragment(); 2223150b12e5df05eec2c3ebb85360661f1d034c188Andrew Wilson if (f instanceof ResultListener) { 2233150b12e5df05eec2c3ebb85360661f1d034c188Andrew Wilson ((ResultListener) f).pinFragmentDone(result); 2243150b12e5df05eec2c3ebb85360661f1d034c188Andrew Wilson } else if (getActivity() instanceof ResultListener) { 2253150b12e5df05eec2c3ebb85360661f1d034c188Andrew Wilson final ResultListener listener = (ResultListener) getActivity(); 2263150b12e5df05eec2c3ebb85360661f1d034c188Andrew Wilson listener.pinFragmentDone(result); 22765a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane } 22865a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane } 22965a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane 23065a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane private void handleWrongPin() { 23165a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane if (++mWrongPinCount >= MAX_WRONG_PIN_COUNT) { 23265a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane mDisablePinUntil = System.currentTimeMillis() + DISABLE_PIN_DURATION_MILLIS; 23365a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane setPinDisabledUntil(mDisablePinUntil); 23465a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane updateWrongPin(); 23565a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane } else { 23665a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane showToast(R.string.pin_toast_wrong); 23765a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane } 23865a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane } 23965a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane 24065a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane private void showToast(int resId) { 24165a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane Toast.makeText(getActivity(), resId, Toast.LENGTH_SHORT).show(); 24265a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane } 24365a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane 24465a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane private void done(String pin) { 24565a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane if (DEBUG) Log.d(TAG, "done: mType=" + mType + " pin=" + pin); 24665a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane switch (mType) { 24765a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane case PIN_DIALOG_TYPE_UNLOCK_CHANNEL: 24865a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane case PIN_DIALOG_TYPE_UNLOCK_PROGRAM: 24965a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane case PIN_DIALOG_TYPE_ENTER_PIN: 25065a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane // TODO: Implement limited number of retrials and timeout logic. 25165a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane if (!isPinSet() || isPinCorrect(pin)) { 25265a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane exit(PIN_DIALOG_RESULT_SUCCESS); 25365a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane } else { 25465a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane resetPinInput(); 25565a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane handleWrongPin(); 25665a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane } 25765a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane break; 25865a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane case PIN_DIALOG_TYPE_NEW_PIN: 25965a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane resetPinInput(); 26065a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane if (mPrevPin == null) { 26165a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane mPrevPin = pin; 26265a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane mTitleView.setText(R.string.pin_enter_again); 26365a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane } else { 26465a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane if (pin.equals(mPrevPin)) { 26565a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane setPin(pin); 26665a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane exit(PIN_DIALOG_RESULT_SUCCESS); 26765a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane } else { 26865a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane mTitleView.setText(R.string.pin_enter_new_pin); 26965a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane mPrevPin = null; 27065a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane showToast(R.string.pin_toast_not_match); 27165a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane } 27265a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane } 27365a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane break; 27465a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane case PIN_DIALOG_TYPE_OLD_PIN: 27565a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane if (isPinCorrect(pin)) { 27665a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane mType = PIN_DIALOG_TYPE_NEW_PIN; 27765a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane resetPinInput(); 27865a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane mTitleView.setText(R.string.pin_enter_new_pin); 27965a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane } else { 28065a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane handleWrongPin(); 28165a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane } 28265a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane break; 28365a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane } 28465a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane } 28565a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane 28665a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane public int getType() { 28765a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane return mType; 28865a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane } 28965a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane 29065a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane private String getPinInput() { 29165a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane String result = ""; 29265a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane try { 29365a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane for (PinNumberPicker pnp : mPickers) { 29465a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane pnp.updateText(); 29565a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane result += pnp.getValue(); 29665a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane } 29765a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane } catch (IllegalStateException e) { 29865a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane result = ""; 29965a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane } 30065a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane return result; 30165a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane } 30265a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane 30365a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane private void resetPinInput() { 30465a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane for (PinNumberPicker pnp : mPickers) { 30565a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane pnp.setValueRange(0, 9); 30665a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane } 30765a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane mPickers[0].requestFocus(); 30865a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane } 30965a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane 31065a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane public static final class PinNumberPicker extends FrameLayout { 31165a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane private static final int NUMBER_VIEWS_RES_ID[] = { 31265a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane R.id.previous2_number, 31365a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane R.id.previous_number, 31465a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane R.id.current_number, 31565a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane R.id.next_number, 31665a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane R.id.next2_number }; 31765a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane private static final int CURRENT_NUMBER_VIEW_INDEX = 2; 31865a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane 31965a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane private static Animator sFocusedNumberEnterAnimator; 32065a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane private static Animator sFocusedNumberExitAnimator; 32165a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane private static Animator sAdjacentNumberEnterAnimator; 32265a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane private static Animator sAdjacentNumberExitAnimator; 32365a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane 32465a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane private static float sAlphaForFocusedNumber; 32565a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane private static float sAlphaForAdjacentNumber; 32665a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane 32765a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane private int mMinValue; 32865a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane private int mMaxValue; 32965a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane private int mCurrentValue; 33065a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane private int mNextValue; 3316e995161147d9110d77ae1fe38b697e52891d3f2Tony Mantler private final int mNumberViewHeight; 33265a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane private PinDialogFragment mDialog; 33365a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane private PinNumberPicker mNextNumberPicker; 33465a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane private boolean mCancelAnimation; 33565a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane 33665a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane private final View mNumberViewHolder; 33765a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane private final View mBackgroundView; 33865a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane private final TextView[] mNumberViews; 33965a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane private final OverScroller mScroller; 34065a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane 34165a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane public PinNumberPicker(Context context) { 34265a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane this(context, null); 34365a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane } 34465a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane 34565a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane public PinNumberPicker(Context context, AttributeSet attrs) { 34665a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane this(context, attrs, 0); 34765a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane } 34865a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane 34965a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane public PinNumberPicker(Context context, AttributeSet attrs, int defStyleAttr) { 35065a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane this(context, attrs, defStyleAttr, 0); 35165a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane } 35265a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane 35365a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane public PinNumberPicker(Context context, AttributeSet attrs, int defStyleAttr, 35465a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane int defStyleRes) { 35565a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane super(context, attrs, defStyleAttr, defStyleRes); 35665a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane View view = inflate(context, R.layout.pin_number_picker, this); 35765a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane mNumberViewHolder = view.findViewById(R.id.number_view_holder); 35865a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane mBackgroundView = view.findViewById(R.id.focused_background); 35965a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane mNumberViews = new TextView[NUMBER_VIEWS_RES_ID.length]; 36065a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane for (int i = 0; i < NUMBER_VIEWS_RES_ID.length; ++i) { 36165a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane mNumberViews[i] = (TextView) view.findViewById(NUMBER_VIEWS_RES_ID[i]); 36265a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane } 36365a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane Resources resources = context.getResources(); 36465a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane mNumberViewHeight = resources.getDimensionPixelOffset( 36565a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane R.dimen.pin_number_picker_text_view_height); 36665a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane 36765a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane mScroller = new OverScroller(context); 36865a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane 36965a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane mNumberViewHolder.setOnFocusChangeListener(new OnFocusChangeListener() { 37065a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane @Override 37165a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane public void onFocusChange(View v, boolean hasFocus) { 37265a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane updateFocus(); 37365a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane } 37465a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane }); 37565a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane 37665a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane mNumberViewHolder.setOnKeyListener(new OnKeyListener() { 37765a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane @Override 37865a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane public boolean onKey(View v, int keyCode, KeyEvent event) { 37965a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane if (event.getAction() == KeyEvent.ACTION_DOWN) { 38065a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane switch (keyCode) { 38165a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane case KeyEvent.KEYCODE_DPAD_UP: 38265a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane case KeyEvent.KEYCODE_DPAD_DOWN: { 38365a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane if (!mScroller.isFinished() || mCancelAnimation) { 38465a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane endScrollAnimation(); 38565a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane } 38665a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane if (mScroller.isFinished() || mCancelAnimation) { 38765a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane mCancelAnimation = false; 38865a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane if (keyCode == KeyEvent.KEYCODE_DPAD_DOWN) { 38965a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane mNextValue = adjustValueInValidRange(mCurrentValue + 1); 39065a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane startScrollAnimation(true); 39165a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane mScroller.startScroll(0, 0, 0, mNumberViewHeight, 39265a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane getResources().getInteger( 39365a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane R.integer.pin_number_scroll_duration)); 39465a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane } else { 39565a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane mNextValue = adjustValueInValidRange(mCurrentValue - 1); 39665a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane startScrollAnimation(false); 39765a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane mScroller.startScroll(0, 0, 0, -mNumberViewHeight, 39865a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane getResources().getInteger( 39965a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane R.integer.pin_number_scroll_duration)); 40065a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane } 40165a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane updateText(); 40265a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane invalidate(); 40365a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane } 40465a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane return true; 40565a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane } 40665a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane } 40765a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane } else if (event.getAction() == KeyEvent.ACTION_UP) { 40865a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane switch (keyCode) { 40965a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane case KeyEvent.KEYCODE_DPAD_UP: 41065a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane case KeyEvent.KEYCODE_DPAD_DOWN: { 41165a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane mCancelAnimation = true; 41265a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane return true; 41365a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane } 41465a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane } 41565a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane } 41665a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane return false; 41765a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane } 41865a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane }); 41965a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane mNumberViewHolder.setScrollY(mNumberViewHeight); 42065a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane } 42165a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane 42265a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane static void loadResources(Context context) { 42365a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane if (sFocusedNumberEnterAnimator == null) { 42465a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane TypedValue outValue = new TypedValue(); 42565a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane context.getResources().getValue( 42665a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane R.float_type.pin_alpha_for_focused_number, outValue, true); 42765a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane sAlphaForFocusedNumber = outValue.getFloat(); 42865a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane context.getResources().getValue( 42965a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane R.float_type.pin_alpha_for_adjacent_number, outValue, true); 43065a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane sAlphaForAdjacentNumber = outValue.getFloat(); 43165a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane 43265a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane sFocusedNumberEnterAnimator = AnimatorInflater.loadAnimator(context, 43365a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane R.animator.pin_focused_number_enter); 43465a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane sFocusedNumberExitAnimator = AnimatorInflater.loadAnimator(context, 43565a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane R.animator.pin_focused_number_exit); 43665a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane sAdjacentNumberEnterAnimator = AnimatorInflater.loadAnimator(context, 43765a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane R.animator.pin_adjacent_number_enter); 43865a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane sAdjacentNumberExitAnimator = AnimatorInflater.loadAnimator(context, 43965a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane R.animator.pin_adjacent_number_exit); 44065a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane } 44165a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane } 44265a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane 44365a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane @Override 44465a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane public void computeScroll() { 44565a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane super.computeScroll(); 44665a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane if (mScroller.computeScrollOffset()) { 44765a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane mNumberViewHolder.setScrollY(mScroller.getCurrY() + mNumberViewHeight); 44865a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane updateText(); 44965a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane invalidate(); 45065a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane } else if (mCurrentValue != mNextValue) { 45165a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane mCurrentValue = mNextValue; 45265a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane } 45365a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane } 45465a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane 45565a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane @Override 45665a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane public boolean dispatchKeyEvent(KeyEvent event) { 45765a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane if (event.getAction() == KeyEvent.ACTION_UP) { 45865a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane int keyCode = event.getKeyCode(); 45965a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane if (keyCode >= KeyEvent.KEYCODE_0 && keyCode <= KeyEvent.KEYCODE_9) { 46065a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane setNextValue(keyCode - KeyEvent.KEYCODE_0); 46165a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane } else if (keyCode != KeyEvent.KEYCODE_DPAD_CENTER 46265a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane && keyCode != KeyEvent.KEYCODE_ENTER) { 46365a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane return super.dispatchKeyEvent(event); 46465a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane } 46565a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane if (mNextNumberPicker == null) { 46665a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane String pin = mDialog.getPinInput(); 46765a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane if (!TextUtils.isEmpty(pin)) { 46865a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane mDialog.done(pin); 46965a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane } 47065a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane } else { 47165a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane mNextNumberPicker.requestFocus(); 47265a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane } 47365a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane return true; 47465a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane } 47565a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane return super.dispatchKeyEvent(event); 47665a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane } 47765a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane 47865a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane @Override 47965a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane public void setEnabled(boolean enabled) { 48065a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane super.setEnabled(enabled); 48165a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane mNumberViewHolder.setFocusable(enabled); 48265a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane for (int i = 0; i < NUMBER_VIEWS_RES_ID.length; ++i) { 48365a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane mNumberViews[i].setEnabled(enabled); 48465a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane } 48565a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane } 48665a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane 48765a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane void startScrollAnimation(boolean scrollUp) { 48865a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane if (scrollUp) { 48965a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane sAdjacentNumberExitAnimator.setTarget(mNumberViews[1]); 49065a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane sFocusedNumberExitAnimator.setTarget(mNumberViews[2]); 49165a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane sFocusedNumberEnterAnimator.setTarget(mNumberViews[3]); 49265a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane sAdjacentNumberEnterAnimator.setTarget(mNumberViews[4]); 49365a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane } else { 49465a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane sAdjacentNumberEnterAnimator.setTarget(mNumberViews[0]); 49565a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane sFocusedNumberEnterAnimator.setTarget(mNumberViews[1]); 49665a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane sFocusedNumberExitAnimator.setTarget(mNumberViews[2]); 49765a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane sAdjacentNumberExitAnimator.setTarget(mNumberViews[3]); 49865a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane } 49965a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane sAdjacentNumberExitAnimator.start(); 50065a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane sFocusedNumberExitAnimator.start(); 50165a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane sFocusedNumberEnterAnimator.start(); 50265a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane sAdjacentNumberEnterAnimator.start(); 50365a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane } 50465a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane 50565a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane void endScrollAnimation() { 50665a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane sAdjacentNumberExitAnimator.end(); 50765a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane sFocusedNumberExitAnimator.end(); 50865a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane sFocusedNumberEnterAnimator.end(); 50965a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane sAdjacentNumberEnterAnimator.end(); 51065a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane mCurrentValue = mNextValue; 51165a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane mNumberViews[1].setAlpha(sAlphaForAdjacentNumber); 51265a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane mNumberViews[2].setAlpha(sAlphaForFocusedNumber); 51365a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane mNumberViews[3].setAlpha(sAlphaForAdjacentNumber); 51465a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane } 51565a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane 51665a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane void setValueRange(int min, int max) { 51765a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane if (min > max) { 51865a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane throw new IllegalArgumentException( 51965a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane "The min value should be greater than or equal to the max value"); 52065a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane } 52165a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane mMinValue = min; 52265a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane mMaxValue = max; 52365a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane mNextValue = mCurrentValue = mMinValue - 1; 52465a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane clearText(); 52565a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane mNumberViews[CURRENT_NUMBER_VIEW_INDEX].setText("—"); 52665a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane } 52765a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane 52865a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane void setPinDialogFragment(PinDialogFragment dlg) { 52965a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane mDialog = dlg; 53065a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane } 53165a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane 53265a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane void setNextNumberPicker(PinNumberPicker picker) { 53365a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane mNextNumberPicker = picker; 53465a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane } 53565a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane 53665a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane int getValue() { 53765a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane if (mCurrentValue < mMinValue || mCurrentValue > mMaxValue) { 53865a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane throw new IllegalStateException("Value is not set"); 53965a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane } 54065a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane return mCurrentValue; 54165a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane } 54265a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane 54365a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane // Will take effect when the focus is updated. 54465a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane void setNextValue(int value) { 54565a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane if (value < mMinValue || value > mMaxValue) { 54665a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane throw new IllegalStateException("Value is not set"); 54765a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane } 54865a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane mNextValue = adjustValueInValidRange(value); 54965a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane } 55065a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane 55165a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane void updateFocus() { 55265a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane endScrollAnimation(); 55365a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane if (mNumberViewHolder.isFocused()) { 55465a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane mBackgroundView.setVisibility(View.VISIBLE); 55565a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane updateText(); 55665a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane } else { 55765a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane mBackgroundView.setVisibility(View.GONE); 55865a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane if (!mScroller.isFinished()) { 55965a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane mCurrentValue = mNextValue; 56065a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane mScroller.abortAnimation(); 56165a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane } 56265a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane clearText(); 56365a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane mNumberViewHolder.setScrollY(mNumberViewHeight); 56465a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane } 56565a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane } 56665a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane 56765a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane private void clearText() { 56865a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane for (int i = 0; i < NUMBER_VIEWS_RES_ID.length; ++i) { 56965a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane if (i != CURRENT_NUMBER_VIEW_INDEX) { 57065a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane mNumberViews[i].setText(""); 57165a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane } else if (mCurrentValue >= mMinValue && mCurrentValue <= mMaxValue) { 57265a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane mNumberViews[i].setText(String.valueOf(mCurrentValue)); 57365a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane } 57465a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane } 57565a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane } 57665a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane 57765a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane private void updateText() { 57865a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane if (mNumberViewHolder.isFocused()) { 57965a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane if (mCurrentValue < mMinValue || mCurrentValue > mMaxValue) { 58065a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane mNextValue = mCurrentValue = mMinValue; 58165a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane } 58265a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane int value = adjustValueInValidRange(mCurrentValue - CURRENT_NUMBER_VIEW_INDEX); 58365a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane for (int i = 0; i < NUMBER_VIEWS_RES_ID.length; ++i) { 58465a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane mNumberViews[i].setText(String.valueOf(adjustValueInValidRange(value))); 58565a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane value = adjustValueInValidRange(value + 1); 58665a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane } 58765a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane } 58865a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane } 58965a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane 59065a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane private int adjustValueInValidRange(int value) { 59165a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane int interval = mMaxValue - mMinValue + 1; 59265a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane if (value < mMinValue - interval || value > mMaxValue + interval) { 59365a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane throw new IllegalArgumentException("The value( " + value 59465a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane + ") is too small or too big to adjust"); 59565a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane } 59665a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane return (value < mMinValue) ? value + interval 59765a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane : (value > mMaxValue) ? value - interval : value; 59865a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane } 59965a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane } 60065a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane} 601