com.brq.wallet.activity.receive.ReceiveCoinsActivity.java Source code

Java tutorial

Introduction

Here is the source code for com.brq.wallet.activity.receive.ReceiveCoinsActivity.java

Source

/*
 * Copyright 2013, 2014 Megion Research and Development GmbH
 *
 * Licensed under the Microsoft Reference Source License (MS-RSL)
 *
 * This license governs use of the accompanying software. If you use the software, you accept this license.
 * If you do not accept the license, do not use the software.
 *
 * 1. Definitions
 * The terms "reproduce," "reproduction," and "distribution" have the same meaning here as under U.S. copyright law.
 * "You" means the licensee of the software.
 * "Your company" means the company you worked for when you downloaded the software.
 * "Reference use" means use of the software within your company as a reference, in read only form, for the sole purposes
 * of debugging your products, maintaining your products, or enhancing the interoperability of your products with the
 * software, and specifically excludes the right to distribute the software outside of your company.
 * "Licensed patents" means any Licensor patent claims which read directly on the software as distributed by the Licensor
 * under this license.
 *
 * 2. Grant of Rights
 * (A) Copyright Grant- Subject to the terms of this license, the Licensor grants you a non-transferable, non-exclusive,
 * worldwide, royalty-free copyright license to reproduce the software for reference use.
 * (B) Patent Grant- Subject to the terms of this license, the Licensor grants you a non-transferable, non-exclusive,
 * worldwide, royalty-free patent license under licensed patents for reference use.
 *
 * 3. Limitations
 * (A) No Trademark License- This license does not grant you any rights to use the Licensors name, logo, or trademarks.
 * (B) If you begin patent litigation against the Licensor over patents that you think may apply to the software
 * (including a cross-claim or counterclaim in a lawsuit), your license to the software ends automatically.
 * (C) The software is licensed "as-is." You bear the risk of using it. The Licensor gives no express warranties,
 * guarantees or conditions. You may have additional consumer rights under your local laws which this license cannot
 * change. To the extent permitted under your local laws, the Licensor excludes the implied warranties of merchantability,
 * fitness for a particular purpose and non-infringement.
 */

package com.brq.wallet.activity.receive;

import android.annotation.TargetApi;
import android.app.Activity;
import android.app.NotificationManager;
import android.content.Context;
import android.content.Intent;
import android.media.AudioManager;
import android.media.RingtoneManager;
import android.net.Uri;
import android.nfc.NdefMessage;
import android.nfc.NdefRecord;
import android.nfc.NfcAdapter;
import android.nfc.NfcEvent;
import android.os.Build;
import android.os.Bundle;
import android.support.v4.app.NotificationCompat;
import android.view.View;
import android.view.View.OnClickListener;
import android.view.Window;
import android.view.WindowManager;
import android.widget.Button;
import android.widget.ImageView;
import android.widget.TextView;
import android.widget.Toast;

import butterknife.BindView;

import com.brq.wallet.Utils;
import com.brq.wallet.activity.util.QrImageView;
import com.google.common.base.Preconditions;
import com.mrd.bitlib.model.Address;
import com.mrd.bitlib.util.CoinUtil;
import com.brq.wallet.MbwManager;
import com.brq.wallet.R;
import com.brq.wallet.activity.GetAmountActivity;
import com.brq.wallet.event.SyncFailed;
import com.brq.wallet.event.SyncStopped;
import com.mycelium.wapi.model.TransactionSummary;
import com.mycelium.wapi.wallet.WalletAccount;
import com.mycelium.wapi.wallet.currency.BitcoinValue;
import com.mycelium.wapi.wallet.currency.CurrencyValue;
import com.mycelium.wapi.wallet.currency.ExactBitcoinValue;
import com.mycelium.wapi.wallet.currency.ExchangeBasedBitcoinValue;
import com.squareup.otto.Subscribe;

import java.util.ArrayList;
import java.util.Date;
import java.util.List;

import butterknife.ButterKnife;
import butterknife.OnClick;

public class ReceiveCoinsActivity extends Activity {

    private static final int GET_AMOUNT_RESULT_CODE = 1;
    private static final String LAST_ADDRESS_BALANCE = "lastAddressBalance";
    private static final String RECEIVING_SINCE = "receivingSince";
    private static final String AMOUNT = "amount";
    public static final String SYNC_ERRORS = "syncErrors";
    private static final int MAX_SYNC_ERRORS = 8;

    @BindView(R.id.tvAmountLabel)
    TextView tvAmountLabel;
    @BindView(R.id.tvAmount)
    TextView tvAmount;
    @BindView(R.id.tvWarning)
    TextView tvWarning;
    @BindView(R.id.tvTitle)
    TextView tvTitle;
    @BindView(R.id.tvAddress1)
    TextView tvAddress1;
    @BindView(R.id.tvAddress2)
    TextView tvAddress2;
    @BindView(R.id.tvAddress3)
    TextView tvAddress3;
    @BindView(R.id.ivNfc)
    ImageView ivNfc;
    @BindView(R.id.ivQrCode)
    QrImageView ivQrCode;
    @BindView(R.id.btShare)
    Button btShare;

    private MbwManager _mbwManager;
    private Address _address;
    private boolean _havePrivateKey;
    private CurrencyValue _amount;
    private Long _receivingSince;
    private CurrencyValue _lastAddressBalance;
    private int _syncErrors = 0;
    private boolean _showIncomingUtxo;

    public static void callMe(Activity currentActivity, Address address, boolean havePrivateKey) {
        Intent intent = new Intent(currentActivity, ReceiveCoinsActivity.class);
        intent.putExtra("address", address);
        intent.putExtra("havePrivateKey", havePrivateKey);
        intent.putExtra("showIncomingUtxo", false);
        currentActivity.startActivity(intent);
    }

    public static void callMe(Activity currentActivity, Address address, boolean havePrivateKey,
            boolean showIncomingUtxo) {
        Intent intent = new Intent(currentActivity, ReceiveCoinsActivity.class);
        intent.putExtra("address", address);
        intent.putExtra("havePrivateKey", havePrivateKey);
        intent.putExtra("showIncomingUtxo", showIncomingUtxo);
        currentActivity.startActivity(intent);
    }

    /**
     * Called when the activity is first created.
     */
    @Override
    public void onCreate(Bundle savedInstanceState) {
        this.requestWindowFeature(Window.FEATURE_NO_TITLE);
        this.getWindow().setFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN,
                WindowManager.LayoutParams.FLAG_FULLSCREEN);
        super.onCreate(savedInstanceState);
        setContentView(R.layout.receive_coins_activity);
        ButterKnife.bind(this);

        _mbwManager = MbwManager.getInstance(getApplication());

        // Get intent parameters
        _address = Preconditions.checkNotNull((Address) getIntent().getSerializableExtra("address"));
        _havePrivateKey = getIntent().getBooleanExtra("havePrivateKey", false);
        _showIncomingUtxo = getIntent().getBooleanExtra("showIncomingUtxo", false);

        // Load saved state
        if (savedInstanceState != null) {
            _amount = (CurrencyValue) savedInstanceState.getSerializable(AMOUNT);
            _receivingSince = savedInstanceState.getLong(RECEIVING_SINCE);
            _lastAddressBalance = (CurrencyValue) savedInstanceState.getSerializable(LAST_ADDRESS_BALANCE);
            _syncErrors = savedInstanceState.getInt(SYNC_ERRORS);
        } else {
            _receivingSince = new Date().getTime();
        }

        // Amount Hint
        tvAmount.setHint(getResources().getString(R.string.amount_hint_denomination,
                _mbwManager.getBitcoinDenomination().toString()));
        shareByNfc();
    }

    @TargetApi(16)
    protected void shareByNfc() {
        if (Build.VERSION.SDK_INT < 16) {
            // the function isNdefPushEnabled is only available for SdkVersion >= 16
            // We would be theoretically able to push the message over Ndef, but it is not
            // possible to check if Ndef/NFC is available or not - so dont try it at all, if
            // SdkVersion is too low
            return;
        }

        NfcAdapter nfc = NfcAdapter.getDefaultAdapter(this);
        if (nfc != null && nfc.isNdefPushEnabled()) {
            nfc.setNdefPushMessageCallback(new NfcAdapter.CreateNdefMessageCallback() {
                @Override
                public NdefMessage createNdefMessage(NfcEvent event) {
                    NdefRecord uriRecord = NdefRecord.createUri(getPaymentUri());
                    return new NdefMessage(new NdefRecord[] { uriRecord });
                }
            }, this);
            ivNfc.setVisibility(View.VISIBLE);
            ivNfc.setOnClickListener(new OnClickListener() {
                @Override
                public void onClick(View v) {
                    Utils.showSimpleMessageDialog(ReceiveCoinsActivity.this,
                            getString(R.string.nfc_payment_request_hint));
                }
            });
        } else {
            ivNfc.setVisibility(View.GONE);
        }
    }

    @Override
    protected void onSaveInstanceState(Bundle outState) {
        if (!CurrencyValue.isNullOrZero(_amount)) {
            outState.putSerializable(AMOUNT, _amount);
        }
        outState.putLong(RECEIVING_SINCE, _receivingSince);
        outState.putInt(SYNC_ERRORS, _syncErrors);
        outState.putSerializable(LAST_ADDRESS_BALANCE, _lastAddressBalance);
        super.onSaveInstanceState(outState);
    }

    @Override
    protected void onPause() {
        _mbwManager.stopWatchingAddress();
        _mbwManager.getEventBus().unregister(this);
        super.onPause();
    }

    @Override
    protected void onResume() {
        super.onResume();
        _mbwManager.getEventBus().register(this);
        if (_showIncomingUtxo && _syncErrors < MAX_SYNC_ERRORS) {
            _mbwManager.watchAddress(_address);
        }
        updateUi();
    }

    BitcoinValue getBitcoinAmount() {
        if (CurrencyValue.isNullOrZero(_amount)) {
            return null;
        }

        if (!_amount.isBtc()) {
            // convert the amount to btc, but only once and stay within btc for all next calls
            _amount = ExchangeBasedBitcoinValue.fromValue(_amount, _mbwManager.getExchangeRateManager());
        }

        return (BitcoinValue) _amount;
    }

    private void updateUi() {
        final String qrText = getPaymentUri();

        if (CurrencyValue.isNullOrZero(_amount)) {
            tvTitle.setText(R.string.bitcoin_address_title);
            btShare.setText(R.string.share_bitcoin_address);
            tvAmountLabel.setText(R.string.optional_amount);
            tvAmount.setText("");
        } else {
            tvTitle.setText(R.string.payment_request);
            btShare.setText(R.string.share_payment_request);
            tvAmountLabel.setText(R.string.amount_title);
            tvAmount.setText(
                    Utils.getFormattedValueWithUnit(getBitcoinAmount(), _mbwManager.getBitcoinDenomination()));
        }

        // QR code
        ivQrCode.setQrCode(qrText);

        // Show warning if the record has no private key
        if (_havePrivateKey) {
            tvWarning.setVisibility(View.GONE);
        } else {
            tvWarning.setVisibility(View.VISIBLE);
        }

        String[] addressStrings = Utils.stringChopper(getBitcoinAddress(), 12);
        tvAddress1.setText(addressStrings[0]);
        tvAddress2.setText(addressStrings[1]);
        tvAddress3.setText(addressStrings[2]);

        updateAmount();
    }

    private void updateAmount() {
        if (CurrencyValue.isNullOrZero(_amount)) {
            // No amount to show
            tvAmount.setText("");
        } else {
            // Set Amount
            tvAmount.setText(
                    Utils.getFormattedValueWithUnit(getBitcoinAmount(), _mbwManager.getBitcoinDenomination()));
        }
    }

    private String getPaymentUri() {
        final StringBuilder uri = new StringBuilder("bitcoin:");
        uri.append(getBitcoinAddress());
        if (!CurrencyValue.isNullOrZero(_amount)) {
            uri.append("?amount=").append(CoinUtil.valueString(getBitcoinAmount().getLongValue(), false));
        }
        return uri.toString();
    }

    private String getBitcoinAddress() {
        return _address.toString();
    }

    public void shareRequest(View view) {
        Intent s = new Intent(android.content.Intent.ACTION_SEND);
        s.setType("text/plain");
        if (CurrencyValue.isNullOrZero(_amount)) {
            s.putExtra(Intent.EXTRA_SUBJECT, getResources().getString(R.string.bitcoin_address_title));
            s.putExtra(Intent.EXTRA_TEXT, getBitcoinAddress());
            startActivity(Intent.createChooser(s, getResources().getString(R.string.share_bitcoin_address)));
        } else {
            s.putExtra(Intent.EXTRA_SUBJECT, getResources().getString(R.string.payment_request));
            s.putExtra(Intent.EXTRA_TEXT, getPaymentUri());
            startActivity(Intent.createChooser(s, getResources().getString(R.string.share_payment_request)));
        }
    }

    public void copyToClipboard(View view) {
        String text;
        if (CurrencyValue.isNullOrZero(_amount)) {
            text = getBitcoinAddress();
        } else {
            text = getPaymentUri();
        }
        Utils.setClipboardString(text, this);
        Toast.makeText(this, R.string.copied_to_clipboard, Toast.LENGTH_SHORT).show();
    }

    public void onActivityResult(final int requestCode, final int resultCode, final Intent intent) {
        if (requestCode == GET_AMOUNT_RESULT_CODE && resultCode == RESULT_OK) {
            // Get result from address chooser (may be null)
            _amount = (CurrencyValue) intent.getSerializableExtra(GetAmountActivity.AMOUNT);
        } else {
            super.onActivityResult(requestCode, resultCode, intent);
        }
    }

    @OnClick(R.id.btEnterAmount)
    public void onEnterClick() {
        if (CurrencyValue.isNullOrZero(_amount)) {
            GetAmountActivity.callMe(ReceiveCoinsActivity.this, null, GET_AMOUNT_RESULT_CODE);
        } else {
            // call the amount activity with the exact amount, so that the user sees the same amount he had entered
            // it in non-BTC
            GetAmountActivity.callMe(ReceiveCoinsActivity.this, _amount.getExactValueIfPossible(),
                    GET_AMOUNT_RESULT_CODE);
        }
    }

    @Subscribe
    public void syncError(SyncFailed event) {
        _syncErrors++;
        // stop syncing after a certain amount of errors (no network available)
        if (_syncErrors > MAX_SYNC_ERRORS) {
            _mbwManager.stopWatchingAddress();
        }
    }

    @Subscribe
    public void syncStopped(SyncStopped event) {
        TextView tvRecv = (TextView) findViewById(R.id.tvReceived);
        TextView tvRecvWarning = (TextView) findViewById(R.id.tvReceivedWarningAmount);
        final WalletAccount selectedAccount = _mbwManager.getSelectedAccount();
        final List<TransactionSummary> transactionsSince = selectedAccount.getTransactionsSince(_receivingSince);
        final ArrayList<TransactionSummary> interesting = new ArrayList<TransactionSummary>();
        CurrencyValue sum = ExactBitcoinValue.ZERO;
        for (TransactionSummary item : transactionsSince) {
            if (item.toAddresses.contains(_address)) {
                interesting.add(item);
                sum = item.value;
            }
        }

        if (interesting.size() > 0) {
            tvRecv.setText(getString(R.string.incoming_payment)
                    + Utils.getFormattedValueWithUnit(sum, _mbwManager.getBitcoinDenomination()));
            // if the user specified an amount, also check it if it matches up...
            if (!CurrencyValue.isNullOrZero(_amount)) {
                tvRecvWarning.setVisibility(sum.equals(_amount) ? View.GONE : View.VISIBLE);
            } else {
                tvRecvWarning.setVisibility(View.GONE);
            }
            tvRecv.setVisibility(View.VISIBLE);
            if (!sum.equals(_lastAddressBalance)) {
                NotificationManager notificationManager = (NotificationManager) this
                        .getSystemService(Context.NOTIFICATION_SERVICE);
                Uri soundUri = RingtoneManager.getDefaultUri(RingtoneManager.TYPE_NOTIFICATION);

                NotificationCompat.Builder mBuilder = new NotificationCompat.Builder(getApplicationContext())
                        .setSound(soundUri, AudioManager.STREAM_NOTIFICATION); //This sets the sound to play
                notificationManager.notify(0, mBuilder.build());

                _lastAddressBalance = sum;
            }
        } else {
            tvRecv.setVisibility(View.GONE);
        }
    }
}