package org.fedorahosted.freeotp; import android.content.Context; import android.util.AttributeSet; import android.view.View; import android.view.animation.Animation; import android.view.animation.AnimationUtils; import android.widget.FrameLayout; import android.widget.ImageView; import android.widget.PopupMenu; import android.widget.TextView; import com.squareup.picasso.Picasso; import org.fedorahosted.freeotp.edit.DeleteActivity; import org.fedorahosted.freeotp.edit.EditActivity; public class TokenLayout extends FrameLayout implements View.OnClickListener, Runnable { private ProgressCircle mProgressInner; private ProgressCircle mProgressOuter; private ImageView mImage; private TextView mCode; private TextView mIssuer; private TextView mLabel; private ImageView mMenu; private PopupMenu mPopupMenu; private TokenCode mCodes; private Token.TokenType mType; private String mPlaceholder; private long mStartTime; public TokenLayout(Context context) { super(context); } public TokenLayout(Context context, AttributeSet attrs) { super(context, attrs); } public TokenLayout(Context context, AttributeSet attrs, int defStyle) { super(context, attrs, defStyle); } @Override protected void onFinishInflate() { super.onFinishInflate(); mProgressInner = (ProgressCircle) findViewById(R.id.progressInner); mProgressOuter = (ProgressCircle) findViewById(R.id.progressOuter); mImage = (ImageView) findViewById(R.id.image); mCode = (TextView) findViewById(R.id.code); mIssuer = (TextView) findViewById(R.id.issuer); mLabel = (TextView) findViewById(R.id.label); mMenu = (ImageView) findViewById(R.id.menu); mPopupMenu = new PopupMenu(getContext(), mMenu); mMenu.setOnClickListener(this); } public void bind(Token token, int menu, PopupMenu.OnMenuItemClickListener micl) { mCodes = null; // Setup menu. mPopupMenu.getMenu().clear(); mPopupMenu.getMenuInflater().inflate(menu, mPopupMenu.getMenu()); mPopupMenu.setOnMenuItemClickListener(micl); // Cancel all active animations. setEnabled(true); removeCallbacks(this); mImage.clearAnimation(); mProgressInner.clearAnimation(); mProgressOuter.clearAnimation(); mProgressInner.setVisibility(View.GONE); mProgressOuter.setVisibility(View.GONE); // Get the code placeholder. char[] placeholder = new char[token.getDigits()]; for (int i = 0; i < placeholder.length; i++) placeholder[i] = '-'; mPlaceholder = new String(placeholder); // Show the image. Picasso.with(getContext()) .load(token.getImage()) .placeholder(R.drawable.logo) .into(mImage); // Set the labels. mLabel.setText(token.getLabel()); mIssuer.setText(token.getIssuer()); mCode.setText(mPlaceholder); if (mIssuer.getText().length() == 0) { mIssuer.setText(token.getLabel()); mLabel.setVisibility(View.GONE); } else { mLabel.setVisibility(View.VISIBLE); } } private void animate(View view, int anim, boolean animate) { Animation a = AnimationUtils.loadAnimation(view.getContext(), anim); if (!animate) a.setDuration(0); view.startAnimation(a); } public void start(Token.TokenType type, TokenCode codes, boolean animate) { mCodes = codes; mType = type; // Start animations. mProgressInner.setVisibility(View.VISIBLE); animate(mProgressInner, R.anim.fadein, animate); animate(mImage, R.anim.token_image_fadeout, animate); // Handle type-specific UI. switch (type) { case HOTP: setEnabled(false); break; case TOTP: mProgressOuter.setVisibility(View.VISIBLE); animate(mProgressOuter, R.anim.fadein, animate); break; } mStartTime = System.currentTimeMillis(); post(this); } @Override public void onClick(View v) { mPopupMenu.show(); } @Override public void run() { // Get the current data String code = mCodes == null ? null : mCodes.getCurrentCode(); if (code != null) { // Determine whether to enable/disable the view. if (!isEnabled()) setEnabled(System.currentTimeMillis() - mStartTime > 5000); // Update the fields mCode.setText(code); mProgressInner.setProgress(mCodes.getCurrentProgress()); if (mType != Token.TokenType.HOTP) mProgressOuter.setProgress(mCodes.getTotalProgress()); postDelayed(this, 100); return; } mCode.setText(mPlaceholder); mProgressInner.setVisibility(View.GONE); mProgressOuter.setVisibility(View.GONE); animate(mImage, R.anim.token_image_fadein, true); } }