/******************************************************************************* * Copyright (c) 2010 Denis Solonenko. * All rights reserved. This program and the accompanying materials * are made available under the terms of the GNU Public License v2.0 * which accompanies this distribution, and is available at * http://www.gnu.org/licenses/old-licenses/gpl-2.0.html * * Contributors: * Denis Solonenko - initial API and implementation ******************************************************************************/ package ru.orangesoftware.financisto2.view; import java.security.MessageDigest; import java.security.NoSuchAlgorithmException; import android.os.Vibrator; import ru.orangesoftware.financisto2.R; import ru.orangesoftware.financisto2.utils.Base64Coder; import android.content.Context; import android.view.LayoutInflater; import android.view.View; import android.view.View.OnClickListener; import android.view.animation.AccelerateInterpolator; import android.view.animation.Animation; import android.view.animation.CycleInterpolator; import android.view.animation.TranslateAnimation; import android.widget.Button; import android.widget.TextView; import android.widget.ViewSwitcher; import ru.orangesoftware.financisto2.utils.MyPreferences; public class PinView implements OnClickListener { private static final int[] buttons = { R.id.b0, R.id.b1, R.id.b2, R.id.b3, R.id.b4, R.id.b5, R.id.b6, R.id.b7, R.id.b8, R.id.b9, R.id.bHelp, R.id.bClear}; public static interface PinListener { void onConfirm(String pinBase64); void onSuccess(String pinBase64); } private final Context context; private final PinListener listener; private final View v; private final ViewSwitcher switcher; private final MessageDigest digest; private final Vibrator vibrator; private TextView result; private String pin1; private String pin2; private boolean confirmPin; public PinView(Context context, PinListener listener, int layoutId) { this(context, listener, null, layoutId); } public PinView(Context context, PinListener listener, String pin, int layoutId) { this.context = context; this.listener = listener; this.confirmPin = pin == null; this.pin1 = pin; LayoutInflater layoutInflater = (LayoutInflater)context.getSystemService(Context.LAYOUT_INFLATER_SERVICE); v = layoutInflater.inflate(layoutId, null); for (int id : buttons) { v.findViewById(id).setOnClickListener(this); } result = (TextView)v.findViewById(R.id.result1); switcher = (ViewSwitcher)v.findViewById(R.id.switcher); switcher.setInAnimation(inFromRightAnimation()); switcher.setOutAnimation(outToLeftAnimation()); try { digest = MessageDigest.getInstance("SHA-1"); } catch (NoSuchAlgorithmException e) { throw new RuntimeException(e); } this.vibrator = (Vibrator) context.getSystemService(Context.VIBRATOR_SERVICE); } public View getView() { return v; } @Override public void onClick(View v) { Button b = (Button)v; char c = b.getText().charAt(0); if (vibrator != null && MyPreferences.isPinHapticFeedbackEnabled(context)) { vibrator.vibrate(20); } switch (c) { case 'O': nextStep(); break; case 'C': result.setText(""); break; default: String text = result.getText().toString(); if (text.length() < 7) { result.setText(text+String.valueOf(c)); } break; } } private void nextStep() { if (confirmPin) { pin1 = pinBase64(result.getText().toString()); result = (TextView)v.findViewById(R.id.result2); confirmPin = false; switcher.showNext(); listener.onConfirm(pin1); } else { pin2 = pinBase64(result.getText().toString()); if (pin1.equals(pin2)) { listener.onSuccess(pin2); } else { result.startAnimation(shakeAnimation()); } } } private String pinBase64(String pin) { byte[] a = digest.digest(pin.getBytes()); return new String(Base64Coder.encode(a)); } private Animation inFromRightAnimation() { Animation inFromRight = new TranslateAnimation( Animation.RELATIVE_TO_PARENT, +1.0f, Animation.RELATIVE_TO_PARENT, 0.0f, Animation.RELATIVE_TO_PARENT, 0.0f, Animation.RELATIVE_TO_PARENT, 0.0f); inFromRight.setDuration(300); inFromRight.setInterpolator(new AccelerateInterpolator()); return inFromRight; } private Animation outToLeftAnimation() { Animation outtoLeft = new TranslateAnimation( Animation.RELATIVE_TO_PARENT, 0.0f, Animation.RELATIVE_TO_PARENT, -1.0f, Animation.RELATIVE_TO_PARENT, 0.0f, Animation.RELATIVE_TO_PARENT, 0.0f); outtoLeft.setDuration(300); outtoLeft.setInterpolator(new AccelerateInterpolator()); return outtoLeft; } private Animation shakeAnimation() { Animation anim = new TranslateAnimation(0.0f, 10.0f, 0.0f, 0.0f); anim.setDuration(300); anim.setInterpolator(new CycleInterpolator(5)); return anim; } }