package com.greenaddress.greenbits.ui; import android.annotation.SuppressLint; import android.app.Dialog; import android.app.PendingIntent; import android.content.Intent; import android.content.IntentFilter; import android.graphics.drawable.BitmapDrawable; import android.nfc.NdefMessage; import android.nfc.NdefRecord; import android.nfc.NfcAdapter; import android.nfc.Tag; import android.nfc.tech.Ndef; import android.nfc.tech.NdefFormatable; import android.os.Build; import android.os.Bundle; import android.text.method.LinkMovementMethod; import android.view.Menu; import android.view.MenuItem; import android.view.View; import android.view.Window; import android.widget.CheckBox; import android.widget.ImageView; import android.widget.TextView; import com.afollestad.materialdialogs.MaterialDialog; import com.afollestad.materialdialogs.Theme; import com.dd.CircularProgressButton; import com.google.common.util.concurrent.FutureCallback; import com.google.common.util.concurrent.Futures; import com.google.common.util.concurrent.ListenableFuture; import com.greenaddress.greenapi.CryptoHelper; import com.greenaddress.greenapi.LoginData; import java.io.IOException; public class SignUpActivity extends LoginActivity { private static final String TAG = SignUpActivity.class.getSimpleName(); private static final int PINSAVE = 1337; private boolean mWriteMode; private Dialog mMnemonicDialog; private Dialog mNfcDialog; private NfcAdapter mNfcAdapter; private PendingIntent mNfcPendingIntent; private TextView mNfcTagsWrittenText; private ImageView mSignupNfcIcon; private TextView mMnemonicText; private CheckBox mAcceptCheckBox; private CircularProgressButton mContinueButton; private ListenableFuture<LoginData> mOnSignUp; private final Runnable mDialogCB = new Runnable() { public void run() { mWriteMode = false; } }; @Override protected int getMainViewId() { return R.layout.activity_sign_up; } @Override protected void onCreateWithService(final Bundle savedInstanceState) { final View nfcView = getLayoutInflater().inflate(R.layout.dialog_nfc_write, null, false); mNfcTagsWrittenText = UI.find(nfcView, R.id.nfcTagsWrittenText); mNfcAdapter = NfcAdapter.getDefaultAdapter(this); mNfcPendingIntent = PendingIntent.getActivity(this, 0, new Intent(this, SignUpActivity.class).addFlags(Intent.FLAG_ACTIVITY_SINGLE_TOP), 0); mMnemonicText = UI.find(this, R.id.signupMnemonicText); mMnemonicText.setText(mService.getSignUpMnemonic()); mAcceptCheckBox = UI.find(this, R.id.signupAcceptCheckBox); mContinueButton = UI.find(this, R.id.signupContinueButton); if (mOnSignUp != null) { mAcceptCheckBox.setEnabled(false); mAcceptCheckBox.setChecked(true); UI.enable(mContinueButton); } final TextView termsText = UI.find(this, R.id.textTosLink); termsText.setMovementMethod(LinkMovementMethod.getInstance()); final View qrView = getLayoutInflater().inflate(R.layout.dialog_qrcode, null, false); final ImageView qrCodeMnemonic = UI.find(qrView, R.id.qrInDialogImageView); final TextView qrCodeIcon = UI.find(this, R.id.signupQrCodeIcon); qrCodeIcon.setOnClickListener(new View.OnClickListener() { public void onClick(final View v) { qrCodeIcon.clearAnimation(); if (mMnemonicDialog == null) { qrCodeMnemonic.setLayoutParams(UI.getScreenLayout(SignUpActivity.this, 0.8)); mMnemonicDialog = new Dialog(SignUpActivity.this); mMnemonicDialog.getWindow().requestFeature(Window.FEATURE_NO_TITLE); mMnemonicDialog.setContentView(qrView); } mMnemonicDialog.show(); final BitmapDrawable bd = new BitmapDrawable(getResources(), mService.getSignUpQRCode()); bd.setFilterBitmap(false); qrCodeMnemonic.setImageDrawable(bd); } }); mContinueButton.setOnClickListener(new View.OnClickListener() { @Override public void onClick(final View v) { int errorId = 0; if (!mService.isConnected()) errorId = R.string.notConnected; else if (!mAcceptCheckBox.isChecked()) errorId = R.string.securePassphraseMsg; else if (mOnSignUp != null) errorId = R.string.signupInProgress; if (errorId != 0) { toast(errorId); return; } mContinueButton.setIndeterminateProgressMode(true); mContinueButton.setProgress(50); mOnSignUp = mService.signup(UI.getText(mMnemonicText)); Futures.addCallback(mOnSignUp, new FutureCallback<LoginData>() { @Override public void onSuccess(final LoginData result) { setComplete(true); mService.resetSignUp(); mOnSignUp = null; final Intent savePin = PinSaveActivity.createIntent(SignUpActivity.this, mService.getMnemonics()); startActivityForResult(savePin, PINSAVE); } @Override public void onFailure(final Throwable t) { setComplete(false); mOnSignUp = null; t.printStackTrace(); toast(t.getMessage()); } }, mService.getExecutor()); } }); mSignupNfcIcon = UI.find(this, R.id.signupNfcIcon); if (Build.VERSION.SDK_INT < 16) { UI.hide(mSignupNfcIcon); return; } mNfcDialog = new MaterialDialog.Builder(SignUpActivity.this) .title(R.string.nfcDialogMessage) .customView(nfcView, true) .titleColorRes(R.color.white) .contentColorRes(android.R.color.white) .theme(Theme.DARK).build(); mSignupNfcIcon.setOnClickListener(new View.OnClickListener() { @Override public void onClick(final View v) { mWriteMode = true; mNfcDialog.show(); } }); UI.setDialogCloseHandler(mNfcDialog, mDialogCB, true /* cancelOnly */); } private void setComplete(final boolean isComplete) { runOnUiThread(new Runnable() { public void run() { mContinueButton.setProgress(isComplete ? 100 : 0); } }); } private void incrementTagsWritten() { final Integer written = Integer.parseInt(UI.getText(mNfcTagsWrittenText)); mNfcTagsWrittenText.setText(String.valueOf(written + 1)); } @Override public void onResumeWithService() { if (mNfcAdapter != null) { final IntentFilter filter = new IntentFilter(NfcAdapter.ACTION_TAG_DISCOVERED); final IntentFilter[] filters = new IntentFilter[]{filter}; mNfcAdapter.enableForegroundDispatch(this, mNfcPendingIntent, filters, null); } UI.showIf(mNfcAdapter != null && mNfcAdapter.isEnabled(), mSignupNfcIcon); } @Override public void onPauseWithService() { if (mNfcAdapter != null) mNfcAdapter.disableForegroundDispatch(this); } @Override @SuppressLint("NewApi") // mSignupNfcIcon is hidden for API < 16 protected void onNewIntent(final Intent intent) { super.onNewIntent(intent); if (!mWriteMode || !NfcAdapter.ACTION_TAG_DISCOVERED.equals(intent.getAction())) return; final Tag detectedTag = intent.getParcelableExtra(NfcAdapter.EXTRA_TAG); final byte[] seed = CryptoHelper.mnemonic_to_bytes(UI.getText(mMnemonicText)); final NdefRecord[] record = new NdefRecord[1]; record[0] = NdefRecord.createMime("x-gait/mnc", seed); final NdefMessage message = new NdefMessage(record); final int size = message.toByteArray().length; try { final Ndef ndef = Ndef.get(detectedTag); if (ndef != null) { ndef.connect(); if (!ndef.isWritable()) shortToast(R.string.err_sign_up_nfc_not_writable); if (ndef.getMaxSize() < size) shortToast(R.string.err_sign_up_nfc_too_small); ndef.writeNdefMessage(message); incrementTagsWritten(); } else { final NdefFormatable format = NdefFormatable.get(detectedTag); if (format != null) try { format.connect(); format.format(message); incrementTagsWritten(); } catch (final IOException e) { } } } catch (final Exception e) { } } @Override public void onDestroy() { super.onDestroy(); if (mMnemonicDialog != null) mMnemonicDialog.dismiss(); if (mNfcDialog != null) mNfcDialog.dismiss(); } @Override public void onBackPressed() { if (mOnSignUp != null) { mService.resetSignUp(); mOnSignUp = null; mService.disconnect(true); } super.onBackPressed(); } @Override public boolean onCreateOptionsMenu(final Menu menu) { // Inflate the menu; this adds items to the action bar if it is present. getMenuInflater().inflate(R.menu.common_menu, menu); return true; } @Override public boolean onOptionsItemSelected(final MenuItem item) { // Handle action bar item clicks here. The action bar will // automatically handle clicks on the Home/Up button, so long // as you specify a parent activity in AndroidManifest.xml. return item.getItemId() == R.id.action_settings || super.onOptionsItemSelected(item); } @Override protected void onActivityResult(final int requestCode, final int resultCode, final Intent data) { super.onActivityResult(requestCode, resultCode, data); switch (requestCode) { case PINSAVE: onLoginSuccess(); break; } } }