piuk.blockchain.android.ui.dialogs.TransactionSummaryDialog.java Source code

Java tutorial

Introduction

Here is the source code for piuk.blockchain.android.ui.dialogs.TransactionSummaryDialog.java

Source

/*
 * Copyright 2011-2012 the original author or authors.
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
 */

package piuk.blockchain.android.ui.dialogs;

import java.lang.ref.WeakReference;
import java.math.BigInteger;
import java.net.HttpURLConnection;
import java.net.URL;
import java.text.DateFormat;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;

import org.apache.commons.io.IOUtils;
import org.json.simple.JSONObject;
import org.json.simple.parser.JSONParser;
import org.spongycastle.util.encoders.Hex;

import com.google.bitcoin.core.Transaction;
import com.google.bitcoin.core.TransactionConfidence.ConfidenceType;
import com.google.bitcoin.core.TransactionInput;
import com.google.bitcoin.core.TransactionOutput;

import android.app.Activity;
import android.app.AlertDialog;
import android.app.Dialog;
import android.app.AlertDialog.Builder;
import android.content.ContentResolver;
import android.content.Intent;
import android.graphics.Color;
import android.graphics.drawable.ColorDrawable;
import android.net.Uri;
import android.os.Bundle;
import android.os.Handler;
import android.support.v4.app.DialogFragment;
import android.support.v4.app.FragmentActivity;
import android.support.v4.app.FragmentManager;
import android.support.v4.app.FragmentTransaction;
import android.text.SpannableString;
import android.text.style.UnderlineSpan;
import android.view.ContextThemeWrapper;
import android.view.LayoutInflater;
import android.view.View;
import android.view.View.OnClickListener;
import android.view.ViewGroup;
import android.view.WindowManager;
import android.widget.Button;
import android.widget.LinearLayout;
import android.widget.TextView;

import piuk.MyRemoteWallet;
import piuk.MyTransaction;
import piuk.MyTransactionInput;
import piuk.blockchain.android.Constants;
import piuk.blockchain.android.R;
import piuk.blockchain.android.WalletApplication;
import piuk.blockchain.android.ui.SuccessCallback;
import piuk.blockchain.android.util.WalletUtils;

/**
 * @author Andreas Schildbach
 */
public final class TransactionSummaryDialog extends DialogFragment {
    private static final String FRAGMENT_TAG = TransactionSummaryDialog.class.getName();
    private static List<WeakReference<TransactionSummaryDialog>> fragmentRefs = new ArrayList<WeakReference<TransactionSummaryDialog>>();

    private WalletApplication application;

    private Transaction tx;

    private static final String WebROOT = "https://" + Constants.BLOCKCHAIN_DOMAIN + "/tx-summary";

    private FragmentActivity activity;

    private DateFormat dateFormat;

    @Override
    public void onAttach(final Activity activity) {
        super.onAttach(activity);

        this.activity = (FragmentActivity) activity;

        dateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm");
    }

    public static void hide() {
        for (WeakReference<TransactionSummaryDialog> fragmentRef : fragmentRefs) {
            if (fragmentRef != null && fragmentRef.get() != null) {
                try {
                    fragmentRef.get().dismissAllowingStateLoss();
                } catch (Exception e) {
                    e.printStackTrace();
                }
            }
        }
    }

    public static TransactionSummaryDialog show(final FragmentManager fm, WalletApplication application,
            Transaction tx) {
        final DialogFragment prev = (DialogFragment) fm.findFragmentById(R.layout.transaction_summary_fragment);

        final FragmentTransaction ft = fm.beginTransaction();

        if (prev != null) {
            prev.dismiss();
            ft.remove(prev);
        }

        ft.addToBackStack(null);

        final TransactionSummaryDialog newFragment = instance();

        newFragment.application = application;

        newFragment.show(ft, FRAGMENT_TAG);

        newFragment.tx = tx;

        return newFragment;
    }

    static TransactionSummaryDialog instance() {
        final TransactionSummaryDialog fragment = new TransactionSummaryDialog();

        fragmentRefs.add(new WeakReference<TransactionSummaryDialog>(fragment));

        return fragment;
    }

    private static String fetchURL(String URL) throws Exception {
        URL url = new URL(URL);

        HttpURLConnection connection = (HttpURLConnection) url.openConnection();

        try {
            connection.setRequestProperty("Accept", "application/json");
            connection.setRequestProperty("charset", "utf-8");
            connection.setRequestMethod("GET");

            connection.setConnectTimeout(30000);
            connection.setReadTimeout(30000);

            connection.setInstanceFollowRedirects(false);

            connection.connect();

            if (connection.getResponseCode() == 200)
                return IOUtils.toString(connection.getInputStream(), "UTF-8");
            else if (connection.getResponseCode() == 500
                    && (connection.getContentType() == null || connection.getContentType().equals("text/plain")))
                throw new Exception("Error From Server: " + IOUtils.toString(connection.getErrorStream(), "UTF-8"));
            else
                throw new Exception("Unknown response from server");

        } finally {
            connection.disconnect();
        }
    }

    public static JSONObject getTransactionSummary(long txIndex, String guid, long result) throws Exception {
        String url = WebROOT + "/" + txIndex + "?guid=" + guid + "&result=" + result + "&format=json";

        String response = fetchURL(url);

        return (JSONObject) new JSONParser().parse(response);
    }

    @Override
    public Dialog onCreateDialog(final Bundle savedInstanceState) {
        super.onCreateDialog(savedInstanceState);

        final FragmentActivity activity = getActivity();

        final LayoutInflater inflater = LayoutInflater.from(activity);

        final Builder dialog = new AlertDialog.Builder(new ContextThemeWrapper(activity, R.style.Theme_Dialog))
                .setTitle(R.string.transaction_summary_title);

        final LinearLayout view = (LinearLayout) inflater.inflate(R.layout.transaction_summary_fragment, null);

        dialog.setView(view);

        try {
            final MyRemoteWallet wallet = application.getRemoteWallet();

            BigInteger totalOutputValue = BigInteger.ZERO;
            for (TransactionOutput output : tx.getOutputs()) {
                totalOutputValue = totalOutputValue.add(output.getValue());
            }

            final TextView resultDescriptionView = (TextView) view.findViewById(R.id.result_description);
            final TextView toView = (TextView) view.findViewById(R.id.transaction_to);
            final TextView toViewLabel = (TextView) view.findViewById(R.id.transaction_to_label);
            final View toViewContainer = (View) view.findViewById(R.id.transaction_to_container);
            final TextView hashView = (TextView) view.findViewById(R.id.transaction_hash);
            final TextView transactionTimeView = (TextView) view.findViewById(R.id.transaction_date);
            final TextView confirmationsView = (TextView) view.findViewById(R.id.transaction_confirmations);
            final TextView noteView = (TextView) view.findViewById(R.id.transaction_note);
            final Button addNoteButton = (Button) view.findViewById(R.id.add_note_button);
            final TextView feeView = (TextView) view.findViewById(R.id.transaction_fee);
            final View feeViewContainer = view.findViewById(R.id.transaction_fee_container);
            final TextView valueNowView = (TextView) view.findViewById(R.id.transaction_value);
            final View valueNowContainerView = view.findViewById(R.id.transaction_value_container);

            String to = null;
            for (TransactionOutput output : tx.getOutputs()) {
                try {
                    String toAddress = output.getScriptPubKey().getToAddress().toString();
                    if (!wallet.isAddressMine(toAddress)) {
                        to = toAddress;
                    }
                } catch (Exception e) {
                    e.printStackTrace();
                }
            }

            String from = null;
            for (TransactionInput input : tx.getInputs()) {
                try {
                    String fromAddress = input.getFromAddress().toString();
                    if (!wallet.isAddressMine(fromAddress)) {
                        from = fromAddress;
                    }
                } catch (Exception e) {
                    e.printStackTrace();
                }
            }

            long realResult = 0;
            int confirmations = 0;

            if (tx instanceof MyTransaction) {
                MyTransaction myTx = (MyTransaction) tx;

                realResult = myTx.getResult().longValue();

                if (wallet.getLatestBlock() != null) {
                    confirmations = wallet.getLatestBlock().getHeight() - myTx.getHeight() + 1;
                }

            } else if (application.isInP2PFallbackMode()) {
                realResult = tx.getValue(application.bitcoinjWallet).longValue();

                if (tx.getConfidence().getConfidenceType() == ConfidenceType.BUILDING)
                    confirmations = tx.getConfidence().getDepthInBlocks();
            }

            final long finalResult = realResult;

            if (realResult <= 0) {
                toViewLabel.setText(R.string.transaction_fragment_to);

                if (to == null) {
                    ((LinearLayout) toViewContainer.getParent()).removeView(toViewContainer);
                } else {
                    toView.setText(to);
                }
            } else {
                toViewLabel.setText(R.string.transaction_fragment_from);

                if (from == null) {
                    ((LinearLayout) toViewContainer.getParent()).removeView(toViewContainer);
                } else {
                    toView.setText(from);
                }
            }

            //confirmations view
            if (confirmations > 0) {
                confirmationsView.setText("" + confirmations);
            } else {
                confirmationsView.setText("Unconfirmed");
            }

            //Hash String view
            final String hashString = new String(Hex.encode(tx.getHash().getBytes()), "UTF-8");

            hashView.setOnClickListener(new OnClickListener() {

                @Override
                public void onClick(View v) {
                    Intent browserIntent = new Intent(Intent.ACTION_VIEW,
                            Uri.parse("https:/" + Constants.BLOCKCHAIN_DOMAIN + "/tx/" + hashString));

                    startActivity(browserIntent);
                }
            });

            //Notes View
            String note = wallet.getTxNotes().get(hashString);

            if (note == null) {
                addNoteButton.setOnClickListener(new OnClickListener() {
                    @Override
                    public void onClick(View v) {
                        dismiss();

                        AddNoteDialog.showDialog(getFragmentManager(), hashString);
                    }
                });

                view.removeView(noteView);
            } else {
                view.removeView(addNoteButton);

                noteView.setText(note);

                noteView.setOnClickListener(new OnClickListener() {
                    @Override
                    public void onClick(View v) {
                        dismiss();

                        AddNoteDialog.showDialog(getFragmentManager(), hashString);
                    }
                });
            }

            addNoteButton.setEnabled(!application.isInP2PFallbackMode());

            SpannableString content = new SpannableString(hashString);
            content.setSpan(new UnderlineSpan(), 0, content.length(), 0);
            hashView.setText(content);

            if (realResult > 0 && from != null)
                resultDescriptionView.setText(this.getString(R.string.transaction_fragment_amount_you_received,
                        WalletUtils.formatValue(BigInteger.valueOf(realResult))));
            else if (realResult < 0 && to != null)
                resultDescriptionView.setText(this.getString(R.string.transaction_fragment_amount_you_sent,
                        WalletUtils.formatValue(BigInteger.valueOf(realResult))));
            else
                resultDescriptionView.setText(this.getString(R.string.transaction_fragment_amount_you_moved,
                        WalletUtils.formatValue(totalOutputValue)));

            final Date time = tx.getUpdateTime();

            transactionTimeView.setText(dateFormat.format(time));

            //These will be made visible again later once information is fetched from server
            feeViewContainer.setVisibility(View.GONE);
            valueNowContainerView.setVisibility(View.GONE);

            if (tx instanceof MyTransaction) {
                MyTransaction myTx = (MyTransaction) tx;

                final long txIndex = myTx.getTxIndex();

                final Handler handler = new Handler();

                new Thread(new Runnable() {
                    @Override
                    public void run() {
                        try {
                            final JSONObject obj = getTransactionSummary(txIndex, wallet.getGUID(), finalResult);

                            handler.post(new Runnable() {
                                @Override
                                public void run() {
                                    try {
                                        if (obj.get("fee") != null) {
                                            feeViewContainer.setVisibility(View.VISIBLE);

                                            feeView.setText(WalletUtils.formatValue(
                                                    BigInteger.valueOf(Long.valueOf(obj.get("fee").toString())))
                                                    + " BTC");
                                        }

                                        if (obj.get("confirmations") != null) {
                                            int confirmations = ((Number) obj.get("confirmations")).intValue();

                                            confirmationsView.setText("" + confirmations);
                                        }

                                        String result_local = (String) obj.get("result_local");
                                        String result_local_historical = (String) obj
                                                .get("result_local_historical");

                                        if (result_local != null && result_local.length() > 0) {
                                            valueNowContainerView.setVisibility(View.VISIBLE);

                                            if (result_local_historical == null
                                                    || result_local_historical.length() == 0
                                                    || result_local_historical.equals(result_local)) {
                                                valueNowView.setText(result_local);
                                            } else {
                                                valueNowView.setText(getString(R.string.value_now_ten, result_local,
                                                        result_local_historical));
                                            }
                                        }
                                    } catch (Exception e) {
                                        e.printStackTrace();
                                    }
                                }
                            });
                        } catch (Exception e) {
                            e.printStackTrace();
                        }
                    }
                }).start();
            }
        } catch (Exception e) {
            e.printStackTrace();
        }

        Dialog d = dialog.create();

        WindowManager.LayoutParams lp = new WindowManager.LayoutParams();

        lp.dimAmount = 0;
        lp.width = WindowManager.LayoutParams.FILL_PARENT;
        lp.height = WindowManager.LayoutParams.WRAP_CONTENT;

        d.show();

        d.getWindow().setAttributes(lp);

        d.getWindow().setBackgroundDrawable(new ColorDrawable(Color.TRANSPARENT));

        return d;
    }
}