Android Open Source - android-sdk Invoice Activity






From Project

Back to project page android-sdk.

License

The source code is released under:

MIT License

If you think the Android project android-sdk listed in this page is inappropriate, such as containing malicious code/tools or violating the copyright, please email info at java2s dot com, thanks.

Java Source Code

package com.bitpay.sdk.android;
//from  w ww. j a v a 2 s  .  c o  m
import android.app.Activity;
import android.content.ActivityNotFoundException;
import android.content.ClipData;
import android.content.ClipboardManager;
import android.content.Context;
import android.content.Intent;
import android.graphics.Bitmap;
import android.graphics.Color;
import android.graphics.Paint;
import android.graphics.Point;
import android.net.Uri;
import android.nfc.NdefMessage;
import android.nfc.NdefRecord;
import android.nfc.NfcAdapter;
import android.nfc.NfcEvent;
import android.os.AsyncTask;
import android.os.Bundle;
import android.util.Log;
import android.view.Display;
import android.view.View;
import android.widget.Button;
import android.widget.ImageView;
import android.widget.ProgressBar;
import android.widget.TextView;
import android.widget.Toast;

import com.bitpay.sdk.model.Invoice;
import com.google.zxing.BarcodeFormat;
import com.google.zxing.EncodeHintType;
import com.google.zxing.MultiFormatWriter;
import com.google.zxing.WriterException;
import com.google.zxing.common.BitMatrix;
import com.google.zxing.qrcode.decoder.ErrorCorrectionLevel;

import java.io.File;
import java.util.Date;
import java.util.Hashtable;
import java.util.concurrent.Executor;
import java.util.concurrent.Executors;

public class InvoiceActivity extends Activity implements NfcAdapter.CreateNdefMessageCallback, NfcAdapter.OnNdefPushCompleteCallback {

    public static final int RESULT_USER_CANCELED = 10;
    public static final int RESULT_STATE_INVALID = 11;
    public static final int RESULT_EXPIRED = 12;
    public static final int RESULT_COMPLETE = 13;
    public static final int RESULT_CONFIRMED = 14;
    public static final int RESULT_PAID = 15;
    public static final int RESULT_OVERPAID = 16;
    public static final int RESULT_PARTIALLY_PAID = 17;

    public static final Executor executor = Executors.newCachedThreadPool();

    public static final String INVOICE = "invoice";
    public static final String CLIENT = "bitpay";
    private static final String TRIGGERED_WALLET = "triggered";
    private static final long PAID_INTERVAL_MILLIS = 2000;

    private boolean triggeredWallet;

    private NfcAdapter mNfcAdapter;
    private Invoice mInvoice = null;
    private BitPayAndroid client;
    private AsyncTask<String, Invoice, Void> followInvoiceTask;
    private AsyncTask<Void, Void, Void> updateTimerTask;

    private ProgressBar progressBar;
    private ProgressBar loadingQr;
    private TextView status;
    private TextView price;

    private Button launchWallet;
    private Button refund;
    private TextView showQR;
    private ImageView qrView;

    private TextView address;
    private TextView timeRemaining;
    private TextView conversion;

    public static int getResourseIdByName(String packageName, String className, String name) {
        Class r = null;
        int id = 0;
        try {
            r = Class.forName(packageName + ".R");

            Class[] classes = r.getClasses();
            Class desireClass = null;

            for (int i = 0; i < classes.length; i++) {
                if (classes[i].getName().split("\\$")[1].equals(className)) {
                    desireClass = classes[i];

                    break;
                }
            }

            if (desireClass != null)
                id = desireClass.getField(name).getInt(desireClass);
        } catch (ClassNotFoundException e) {
            e.printStackTrace();
        } catch (IllegalArgumentException e) {
            e.printStackTrace();
        } catch (SecurityException e) {
            e.printStackTrace();
        } catch (IllegalAccessException e) {
            e.printStackTrace();
        } catch (NoSuchFieldException e) {
            e.printStackTrace();
        }

        return id;

    }

    @Override
    protected void onSaveInstanceState(Bundle outState) {
        super.onSaveInstanceState(outState);
        outState.putParcelable(INVOICE, mInvoice);
        outState.putBoolean(TRIGGERED_WALLET, triggeredWallet);
    }

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setResult(RESULT_USER_CANCELED);
        setContentView(getResourseIdByName(getPackageName(), "layout", "activity_invoice"));

        status = (TextView) findViewById(getResourseIdByName(getPackageName(), "id", "status"));
        price = (TextView) findViewById(getResourseIdByName(getPackageName(), "id", "price"));
        refund = (Button) findViewById(getResourseIdByName(getPackageName(), "id", "refund"));

        launchWallet = (Button) findViewById(getResourseIdByName(getPackageName(), "id", "launchWallet"));
        progressBar = (ProgressBar) findViewById(getResourseIdByName(getPackageName(), "id", "progressBar"));
        loadingQr = (ProgressBar) findViewById(getResourseIdByName(getPackageName(), "id", "loadingQr"));
        qrView = (ImageView) findViewById(getResourseIdByName(getPackageName(), "id", "qr"));

        showQR = (TextView) findViewById(getResourseIdByName(getPackageName(), "id", "showQr"));
        address = (TextView) findViewById(getResourseIdByName(getPackageName(), "id", "address"));
        timeRemaining = (TextView) findViewById(getResourseIdByName(getPackageName(), "id", "timeRemaining"));
        conversion = (TextView) findViewById(getResourseIdByName(getPackageName(), "id", "conversion"));

        if (savedInstanceState != null) {
            mInvoice = savedInstanceState.getParcelable(INVOICE);
            client = savedInstanceState.getParcelable(CLIENT);
            triggeredWallet = savedInstanceState.getBoolean(TRIGGERED_WALLET);
        } else {
            mInvoice = getIntent().getParcelableExtra(INVOICE);
            client = getIntent().getParcelableExtra(CLIENT);
            triggeredWallet = getIntent().getBooleanExtra(TRIGGERED_WALLET, false);
        }

        progressBar.setRotation(180);
        price.setText(mInvoice.getBtcPrice() + " BTC");
        timeRemaining.setText(getRemainingTimeAsString());
        conversion.setText(mInvoice.getBtcPrice() + " BTC = " + mInvoice.getPrice() + mInvoice.getCurrency());
        address.setText(getAddress());
        address.setPaintFlags(address.getPaintFlags() | Paint.UNDERLINE_TEXT_FLAG);
        address.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                ClipboardManager ClipMan = (ClipboardManager) getSystemService(Context.CLIPBOARD_SERVICE);
                ClipMan.setPrimaryClip(ClipData.newPlainText("label", mInvoice.getPaymentUrls().getBIP73()));
                Toast toast = Toast.makeText(getApplicationContext(), "Copied payment address to clipboard", Toast.LENGTH_LONG);
                toast.show();
            }
        });
        showQR.setPaintFlags(showQR.getPaintFlags() | Paint.UNDERLINE_TEXT_FLAG);
        showQR.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                triggerQrLoad();
            }
        });
        launchWallet.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                Intent bitcoinIntent = new Intent(Intent.ACTION_VIEW);
                bitcoinIntent.setData(Uri.parse(mInvoice.getBIP21due()));
                startActivity(bitcoinIntent);
            }
        });

        mNfcAdapter = NfcAdapter.getDefaultAdapter(this);
        if (mNfcAdapter != null) {
            // Register callback to set NDEF message
            mNfcAdapter.setNdefPushMessageCallback(this, this);

            // Register callback to listen for message-sent success
            mNfcAdapter.setOnNdefPushCompleteCallback(this, this);
        } else {
            Log.i("InvoiceActivity", "NFC is not available on this device");
        }
        if (!triggeredWallet) {
            if (BitPayAndroid.isWalletAvailable(this)) {
                Intent bitcoinIntent = new Intent(Intent.ACTION_VIEW);
                bitcoinIntent.setData(Uri.parse(mInvoice.getBIP21due()));
                triggeredWallet = true;
                startActivity(bitcoinIntent);
            } else {
                Toast.makeText(getApplicationContext(), "You don't have any bitcoin wallets installed.", Toast.LENGTH_LONG).show();
                triggerQrLoad();
            }
        } else {
            triggerStatusCheck();
        }
    }

    private void setupUpdateTimer() {
        updateTimerTask = new AsyncTask<Void, Void, Void>() {
            @Override
            protected Void doInBackground(Void... params) {
                while (true) {
                    publishProgress(null, null);
                    try {
                        Thread.sleep(1000);
                    } catch (InterruptedException e) {
                    }
                }
            }

            @Override
            protected void onProgressUpdate(Void... values) {
                super.onProgressUpdate(values);

                int remainingSeconds = getRemainingSeconds();
                if (remainingSeconds < 0) {
                    timeRemaining.setText("-");
                    progressBar.setProgress(0);
                } else {
                    timeRemaining.setText(getRemainingTimeAsString());
                    progressBar.setProgress((getRemainingSeconds() * 100) / (15 * 60));
                }
            }
        }.executeOnExecutor(executor, null, null);
    }

    private void triggerStatusCheck() {
        if (followInvoiceTask != null) {
            followInvoiceTask.cancel(true);
        }
        if (client == null) {
            return;
        }
        followInvoiceTask = new BitPayAndroid.FollowInvoiceStatusTask(client) {
            @Override
            protected void onProgressUpdate(Invoice... values) {
                Invoice invoice = values[0];
                Invoice prev = mInvoice;
                if (invoice != null) {
                    mInvoice = invoice;
                } else {
                    return;
                }
                if (invoice.getExceptionStatus().equals("paidPartial") && !prev.getBtcDue().equals(invoice.getBtcDue())) {
                    status.setText("Partial payment received. Due amount:");
                    price.setText(invoice.getBtcDue() + " BTC");
                    InvoiceActivity.this.setResult(RESULT_PARTIALLY_PAID);
                    if (qrView.getVisibility() == View.VISIBLE) {
                        triggerQrLoad();
                    }
                    return;
                }
                if (invoice.getExceptionStatus().equals("paidOver")) {
                    InvoiceActivity.this.setResult(RESULT_OVERPAID);
                    status.setText("This invoice was overpaid.");
                    hidePaymentButtons();
                    showRefund();
                    this.cancel(true);
                    return;
                }
                super.onProgressUpdate(values);
            }

            @Override
            public void onStatePaid() {
                InvoiceActivity.this.setResult(RESULT_PAID);
                checkExceptionAndFinish();
            }

            private void checkExceptionAndFinish() {
                if (mInvoice.getExceptionStatus().equals("false")) {
                    hidePaymentButtons();
                    showReceipt();
                    new AsyncTask<Void, Void, Void>() {

                        @Override
                        protected Void doInBackground(Void... params) {
                            try {
                                Thread.sleep(PAID_INTERVAL_MILLIS);
                            } catch (InterruptedException e) {
                                e.printStackTrace();
                            }
                            return null;
                        }

                        @Override
                        protected void onPostExecute(Void aVoid) {
                            super.onPostExecute(aVoid);

                            InvoiceActivity.this.finish();
                        }
                    }.executeOnExecutor(executor, null, null);

                    this.cancel(true);
                }
            }

            @Override
            public void onStateConfirmed() {
                InvoiceActivity.this.setResult(RESULT_CONFIRMED);
                checkExceptionAndFinish();
            }

            @Override
            public void onStateComplete() {
                InvoiceActivity.this.setResult(RESULT_COMPLETE);
                checkExceptionAndFinish();
            }

            @Override
            public void onStateExpired() {
                InvoiceActivity.this.setResult(RESULT_EXPIRED);
                checkExceptionAndFinish();
            }

            @Override
            public void onStateInvalid() {
                InvoiceActivity.this.setResult(RESULT_STATE_INVALID);
                checkExceptionAndFinish();
            }
        }.executeOnExecutor(executor, mInvoice.getId());
    }

    private void showRefund() {
        refund = (Button) findViewById(getResourseIdByName(getPackageName(), "id", "refund"));
        refund.setVisibility(View.VISIBLE);
        refund.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                Intent intent = new Intent(Intent.ACTION_SEND);
                intent.setType("message/rfc822");
                intent.putExtra(Intent.EXTRA_EMAIL, new String[]{"support@bitpay.com"});
                intent.putExtra(Intent.EXTRA_SUBJECT, "Refund Request");
                intent.putExtra(Intent.EXTRA_TEXT, "Invoice: " + mInvoice.getUrl() +
                        ((mInvoice.getRefundAddresses() != null && mInvoice.getRefundAddresses().size() > 0)
                                ? "\nRefund Address:" + mInvoice.getRefundAddresses() : "")
                        + "\nReason: Overpaid invoice");

                startActivity(Intent.createChooser(intent, "Send Email"));
            }
        });
    }

    private void showReceipt() {

        price.setVisibility(View.VISIBLE);
        price.setText(mInvoice.getBtcPrice() + " BTC paid");
        status.setText("Your payment was received successfully");
    }

    private void hidePaymentButtons() {

        progressBar.setVisibility(View.GONE);
        loadingQr.setVisibility(View.GONE);
        price.setVisibility(View.GONE);

        launchWallet.setVisibility(View.GONE);
        showQR.setVisibility(View.GONE);
        qrView.setVisibility(View.GONE);

        address.setVisibility(View.GONE);
        timeRemaining.setVisibility(View.GONE);
        conversion.setVisibility(View.GONE);
    }

    @Override
    protected void onPause() {
        super.onPause();
        if (followInvoiceTask != null) {
            followInvoiceTask.cancel(true);
        }
        if (updateTimerTask != null) {
            updateTimerTask.cancel(true);
        }
    }

    @Override
    protected void onResume() {
        super.onResume();
        triggerStatusCheck();
        setupUpdateTimer();
    }

    @Override
    public NdefMessage createNdefMessage(NfcEvent event) {

        if (mInvoice != null && mInvoice.getPaymentUrls() != null && mInvoice.getPaymentUrls().getBIP72b() != null) {
            return new NdefMessage(new NdefRecord[]{
                    NdefRecord.createUri(mInvoice.getPaymentUrls().getBIP72())
            });
        }
        return null;
    }

    @Override
    public void onNdefPushComplete(NfcEvent event) {
        // Pass
    }

    public int getRemainingSeconds() {
        Date now = new Date();
        int millis = (int) (Math.abs(now.getTime() - Long.parseLong(mInvoice.getExpirationTime())));
        return millis / 1000;
    }

    public String getRemainingTimeAsString() {
        int seconds = getRemainingSeconds();
        return String.format("%02d:%02d", seconds / 60, seconds % 60);
    }

    public String getAddress() {
        String bip21 = mInvoice.getPaymentUrls().getBIP21();
        return bip21.substring(bip21.indexOf(":") + 1, bip21.indexOf("?"));
    }

    public Bitmap generateQR(String text) {
        Display display = getWindowManager().getDefaultDisplay();
        Point size = new Point();
        display.getSize(size);
        int width = size.x * 3 / 4;
        int height = width;
        MultiFormatWriter writer = new MultiFormatWriter();
        Hashtable hints = new Hashtable();
        hints.put(EncodeHintType.ERROR_CORRECTION, ErrorCorrectionLevel.Q);
        BitMatrix matrix = null;
        Bitmap bmp = Bitmap.createBitmap(width, height, Bitmap.Config.RGB_565);
        try {
            matrix = writer.encode(text, BarcodeFormat.QR_CODE, width, height, hints);
        } catch (WriterException e) {
            return bmp;
        }
        for (int x = 0; x < width; x++){
            for (int y = 0; y < height; y++){
                bmp.setPixel(x, y, matrix.get(x,y) ? Color.BLACK : Color.WHITE);
            }
        }
        return bmp;
    }

    private void triggerQrLoad() {
        new AsyncTask<Void, Void, Bitmap>() {

            @Override
            protected void onPreExecute() {
                super.onPreExecute();
                qrView.setVisibility(View.GONE);
                showQR.setVisibility(View.GONE);
                loadingQr.setVisibility(View.VISIBLE);
            }

            @Override
            protected Bitmap doInBackground(Void... params) {
                return generateQR(mInvoice.getBIP21due());
            }

            @Override
            protected void onPostExecute(Bitmap bitmap) {
                super.onPostExecute(bitmap);
                qrView.setImageBitmap(bitmap);
                loadingQr.setVisibility(View.GONE);
                showQR.setVisibility(View.GONE);
                qrView.setVisibility(View.VISIBLE);
            }
        }.executeOnExecutor(executor, null, null);
    }
}




Java Source Code List

com.bitpay.sdk.android.BitPayAndroid.java
com.bitpay.sdk.android.InvoiceActivity.java
com.bitpay.sdk.android.interfaces.BitpayPromiseCallback.java
com.bitpay.sdk.android.interfaces.InvoiceCreationCallback.java
com.bitpay.sdk.android.interfaces.InvoicePromiseCallback.java
com.bitpay.sdk.android.interfaces.PromiseCallback.java
com.bitpay.sdk.android.interfaces.RatesPromiseCallback.java
com.bitpay.sdk.android.promises.BitpayPromise.java
com.bitpay.sdk.controller.BitPayException.java
com.bitpay.sdk.controller.BitPay.java
com.bitpay.sdk.controller.KeyUtils.java
com.bitpay.sdk.model.BuyerInfo.java
com.bitpay.sdk.model.InvoicePaymentUrls.java
com.bitpay.sdk.model.InvoiceTransaction.java
com.bitpay.sdk.model.Invoice.java
com.bitpay.sdk.model.Policy.java
com.bitpay.sdk.model.Rate.java
com.bitpay.sdk.model.Rates.java
com.bitpay.sdk.model.Token.java