piuk.blockchain.android.ui.AbstractWalletActivity.java Source code

Java tutorial

Introduction

Here is the source code for piuk.blockchain.android.ui.AbstractWalletActivity.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;

import java.math.BigInteger;
import java.util.Locale;

import android.app.Activity;
import android.app.AlertDialog;
import android.app.Dialog;
import android.app.AlertDialog.Builder;
import android.content.Context;
import android.content.DialogInterface;
import android.content.Intent;
import android.net.ConnectivityManager;
import android.net.NetworkInfo;
import android.net.Uri;
import android.os.Bundle;
import android.os.Handler;
import android.support.v4.app.FragmentActivity;
import android.text.ClipboardManager;
import android.util.Pair;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.TextView;
import android.widget.Toast;
import piuk.blockchain.android.EventListeners;
import piuk.blockchain.android.MyRemoteWallet;
import piuk.blockchain.android.MyRemoteWallet.SendProgress;
import piuk.blockchain.android.R;
import piuk.blockchain.android.Constants;
import piuk.blockchain.android.SuccessCallback;
import piuk.blockchain.android.WalletApplication;
import piuk.blockchain.android.WalletApplication.AddAddressCallback;
import piuk.blockchain.android.ui.dialogs.RequestPasswordDialog;
//import piuk.blockchain.android.util.ActionBarFragment;
import piuk.blockchain.android.util.WalletUtils;

import com.dm.zbar.android.scanner.ZBarConstants;
import com.dm.zbar.android.scanner.ZBarScannerActivity;
import com.google.android.gcm.GCMRegistrar;
import com.google.bitcoin.core.Address;
import com.google.bitcoin.core.ECKey;
import com.google.bitcoin.core.NetworkParameters;
import com.google.bitcoin.core.Transaction;
import com.google.bitcoin.params.MainNetParams;
import com.google.bitcoin.uri.BitcoinURI;

/**
 * @author Andreas Schildbach
 */
public abstract class AbstractWalletActivity extends FragmentActivity {
    protected WalletApplication application = (WalletApplication) this.getApplication();
    //   protected ActionBarFragment actionBar;
    protected final AbstractWalletActivity self = this;
    protected Handler handler = new Handler();
    protected ActivityDelegate activityDelegate;
    public static long lastDisplayedNetworkError = 0;
    private static final int ZBAR_SCANNER_REQUEST = 0;
    private static final int ZBAR_QR_SCANNER_REQUEST = 1;
    protected boolean dontCheckStatus = false;

    public abstract class QrCodeDelagate implements ActivityDelegate {

        public abstract void didReadQRCode(String data) throws Exception;

        @Override
        public void onActivityResult(final int requestCode, final int resultCode, final Intent intent) {

            //Zxing
            if (resultCode == RESULT_OK) {
                final String raw_code = intent.getStringExtra("SCAN_RESULT");

                try {
                    if (raw_code == null || raw_code.length() == 0)
                        throw new Exception("Null result returned");

                    didReadQRCode(raw_code);
                } catch (Exception e) {
                    e.printStackTrace();

                    longToast(R.string.unknown_error);
                }
            }
        }
    }

    public void registerNotifications() {
        try {
            final String regId = GCMRegistrar.getRegistrationId(this);

            if (regId == null || regId.equals("")) {
                GCMRegistrar.register(this, Constants.SENDER_ID);
            } else {
                application.registerForNotificationsIfNeeded(regId);
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    public static interface ActivityDelegate {
        public void onActivityResult(final int requestCode, final int resultCode, final Intent intent);
    }

    @Override
    public void onActivityResult(final int requestCode, final int resultCode, final Intent intent) {

        if (activityDelegate != null)
            activityDelegate.onActivityResult(requestCode, resultCode, intent);

    }

    public void showQRReader(ActivityDelegate activityDelegate) {
        this.activityDelegate = activityDelegate;

        Intent intent = new Intent(this, ZBarScannerActivity.class);
        startActivityForResult(intent, ZBAR_QR_SCANNER_REQUEST);
    }

    static void handleCopyToClipboard(final Context context, final String address) {
        final ClipboardManager clipboardManager = (ClipboardManager) context
                .getSystemService(Context.CLIPBOARD_SERVICE);
        clipboardManager.setText(address);

        Toast.makeText(context, R.string.wallet_address_fragment_clipboard_msg, Toast.LENGTH_SHORT).show();
    }

    public final boolean hasInternetConnection() {
        ConnectivityManager cm = (ConnectivityManager) getSystemService(Context.CONNECTIVITY_SERVICE);

        if (cm.getActiveNetworkInfo() != null && cm.getActiveNetworkInfo().isAvailable()
                && cm.getActiveNetworkInfo().isConnected()) {
            return true;

        } else {
            return false;
        }
    }

    public final boolean isWifiEnabled() {
        ConnectivityManager cm = (ConnectivityManager) getSystemService(Context.CONNECTIVITY_SERVICE);

        NetworkInfo info = cm.getNetworkInfo(ConnectivityManager.TYPE_WIFI);

        if (info.isConnected()) {
            return true;
        } else {
            return false;
        }
    }

    public void startP2PMode() {
        final MyRemoteWallet remoteWallet = application.getRemoteWallet();

        if (remoteWallet == null)
            return;

        if (remoteWallet.isDoubleEncrypted() == false) {
            application.startBlockchainService();
        } else {
            if (remoteWallet.temporySecondPassword == null) {
                RequestPasswordDialog.show(getSupportFragmentManager(), new SuccessCallback() {

                    public void onSuccess() {
                        application.startBlockchainService();
                    }

                    public void onFail() {
                        Toast.makeText(application, R.string.password_incorrect, Toast.LENGTH_LONG).show();
                    }
                }, RequestPasswordDialog.PasswordTypeSecond);
            } else {
                application.startBlockchainService();
            }
        }
    }

    private EventListeners.EventListener eventListener = new EventListeners.EventListener() {

        @Override
        public String getDescription() {
            return getClass() + " Wallet Check Status";
        }

        @Override
        public void onWalletDidChange() {
            application.checkWalletStatus(self);
        }

        @Override
        public void onMultiAddrError() {
            if (self instanceof WalletActivity) {
                if (lastDisplayedNetworkError > System.currentTimeMillis() - Constants.NetworkErrorDisplayThreshold)
                    return;

                //Don't do anything is we are already running the blockchain service
                if (application.isInP2PFallbackMode())
                    return;

                lastDisplayedNetworkError = System.currentTimeMillis();

                //Only ask for P2P mode when connected to wifi 
                if (!hasInternetConnection() || !isWifiEnabled()) {
                    handler.post(new Runnable() {
                        public void run() {
                            AlertDialog.Builder builder = new AlertDialog.Builder(self);

                            builder.setTitle(R.string.network_error);

                            builder.setMessage(R.string.network_error_description);

                            builder.setPositiveButton(android.R.string.ok, new DialogInterface.OnClickListener() {
                                public void onClick(DialogInterface dialog, int id) {
                                    dialog.dismiss();
                                }
                            });

                            builder.show();
                        }
                    });
                } else {
                    handler.post(new Runnable() {
                        public void run() {
                            AlertDialog.Builder builder = new AlertDialog.Builder(self);

                            builder.setTitle(R.string.blockchain_network_error);

                            builder.setMessage(R.string.blockchain_network_error_description);

                            builder.setNegativeButton(R.string.ignore, new DialogInterface.OnClickListener() {
                                public void onClick(DialogInterface dialog, int id) {
                                    dialog.dismiss();
                                }
                            });

                            builder.setPositiveButton(R.string.start_p2p_mode,
                                    new DialogInterface.OnClickListener() {
                                        public void onClick(DialogInterface dialog, int id) {
                                            startP2PMode();
                                        }
                                    });

                            builder.show();
                        }
                    });
                }
            }
        };
    };

    @Override
    protected void onCreate(final Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);

        application = (WalletApplication) this.getApplication();
    }

    @Override
    protected void onResume() {
        super.onResume();

        EventListeners.addEventListener(eventListener);

        if (!dontCheckStatus) {
            application.checkWalletStatus(self);
        }

        application.connect();
    }

    @Override
    protected void onPause() {
        super.onPause();

        EventListeners.removeEventListener(eventListener);

        application.disconnectSoon();
    }

    @Override
    protected void onStart() {
        super.onStart();

        /*
        if (getActionBarFragment() != null) {
           actionBar.setIcon(Constants.APP_ICON_RESID);
           actionBar.setSecondaryTitle(Constants.TEST ? "[testnet]" : null);
        }
        */
    }

    /*
    public ActionBarFragment getActionBarFragment() {
       if (actionBar == null)
     actionBar = (ActionBarFragment) getSupportFragmentManager()
     .findFragmentById(R.id.action_bar_fragment);
        
       return actionBar;
    }
    */

    public final void toast(final String text, final Object... formatArgs) {
        toast(text, 0, Toast.LENGTH_SHORT, formatArgs);
    }

    public final void longToast(final String text, final Object... formatArgs) {
        toast(text, 0, Toast.LENGTH_LONG, formatArgs);
    }

    public final void toast(final String text, final int imageResId, final int duration,
            final Object... formatArgs) {

        if (text == null)
            return;

        final View view = getLayoutInflater().inflate(R.layout.transient_notification, null);
        TextView tv = (TextView) view.findViewById(R.id.transient_notification_text);
        tv.setText(String.format(text, formatArgs));
        tv.setCompoundDrawablesWithIntrinsicBounds(imageResId, 0, 0, 0);

        final Toast toast = new Toast(this);
        toast.setView(view);
        toast.setDuration(duration);
        toast.show();
    }

    public final void toast(final int textResId, final Object... formatArgs) {
        toast(textResId, 0, Toast.LENGTH_SHORT, formatArgs);
    }

    public final void longToast(final int textResId, final Object... formatArgs) {
        toast(textResId, 0, Toast.LENGTH_LONG, formatArgs);
    }

    public final void toast(final int textResId, final int imageResId, final int duration,
            final Object... formatArgs) {
        final View view = getLayoutInflater().inflate(R.layout.transient_notification, null);
        TextView tv = (TextView) view.findViewById(R.id.transient_notification_text);
        tv.setText(getString(textResId, formatArgs));
        tv.setCompoundDrawablesWithIntrinsicBounds(imageResId, 0, 0, 0);

        final Toast toast = new Toast(this);
        toast.setView(view);
        toast.setDuration(duration);
        toast.show();
    }

    public void errorDialog(final int title, final String message) {
        final Builder dialog = new AlertDialog.Builder(this);
        dialog.setTitle(title);
        dialog.setMessage(message);
        dialog.setNeutralButton(R.string.button_dismiss, null);
        dialog.show();
    }

    public void errorDialog(final int title, final String message, final DialogInterface.OnClickListener dismiss) {
        final Builder dialog = new AlertDialog.Builder(this);
        dialog.setTitle(title);
        dialog.setMessage(message);
        dialog.setNeutralButton(R.string.button_dismiss, dismiss);
        dialog.show();
    }

    protected final static String languagePrefix() {
        final String language = Locale.getDefault().getLanguage();
        if ("de".equals(language))
            return "_de";
        else if ("cs".equals(language))
            return "_cs";
        else if ("el".equals(language))
            return "_el";
        else if ("es".equals(language))
            return "_es";
        else if ("fr".equals(language))
            return "_fr";
        else if ("it".equals(language))
            return "_it";
        else if ("nl".equals(language))
            return "_nl";
        else if ("pl".equals(language))
            return "_pl";
        else if ("ru".equals(language))
            return "_ru";
        else if ("sv".equals(language))
            return "_sv";
        else if ("tr".equals(language))
            return "_tr";
        else if ("zh".equals(language))
            return "_zh";
        else
            return "";
    }

    public void showMarketPage(final String packageName) {
        final Intent marketIntent = new Intent(Intent.ACTION_VIEW,
                Uri.parse(String.format(Constants.MARKET_APP_URL, packageName)));
        if (getPackageManager().resolveActivity(marketIntent, 0) != null)
            startActivity(marketIntent);
        else
            startActivity(new Intent(Intent.ACTION_VIEW,
                    Uri.parse(String.format(Constants.WEBMARKET_APP_URL, packageName))));
    }

    private void handleScanPrivateKeyPair(final ECKey key) throws Exception {
        final AlertDialog.Builder b = new AlertDialog.Builder(this);

        b.setPositiveButton(R.string.sweep_text, null);

        b.setNeutralButton(R.string.import_text, null);

        b.setNegativeButton(android.R.string.no, new DialogInterface.OnClickListener() {
            @Override
            public void onClick(DialogInterface dialog, int which) {
                dialog.dismiss();
            }
        });

        b.setTitle("Scan Private Key");

        b.setMessage("Fetching Balance. Please Wait");

        final AlertDialog dialog = b.show();

        dialog.getButton(Dialog.BUTTON1).setEnabled(false);

        new Thread() {
            public void run() {
                try {
                    final String address;
                    if (key.isCompressed()) {
                        address = key.toAddressCompressed(MainNetParams.get()).toString();
                    } else {
                        address = key.toAddressUnCompressed(MainNetParams.get()).toString();
                    }

                    System.out.println("Scanned PK Address " + address);

                    BigInteger balance = MyRemoteWallet.getAddressBalance(address);

                    final BigInteger finalBalance = balance;

                    handler.post(new Runnable() {
                        @Override
                        public void run() {
                            final MyRemoteWallet remoteWallet = application.getRemoteWallet();

                            if (remoteWallet == null)
                                return;

                            dialog.getButton(Dialog.BUTTON3).setEnabled(true);

                            if (finalBalance.longValue() == 0) {
                                dialog.setMessage("The Balance of address " + address + " is zero.");
                            } else {
                                dialog.getButton(Dialog.BUTTON1).setEnabled(true);
                                dialog.setMessage(
                                        "The Balance of " + address + " is " + WalletUtils.formatValue(finalBalance)
                                                + " BTC. Would you like to sweep it?");
                            }

                            dialog.getButton(Dialog.BUTTON3).setOnClickListener(new OnClickListener() {
                                @Override
                                public void onClick(View v) {

                                    if (remoteWallet.isDoubleEncrypted() == false) {
                                        reallyAddKey(dialog, key);
                                    } else {
                                        if (remoteWallet.temporySecondPassword == null) {
                                            RequestPasswordDialog.show(getSupportFragmentManager(),
                                                    new SuccessCallback() {

                                                        public void onSuccess() {
                                                            reallyAddKey(dialog, key);
                                                        }

                                                        public void onFail() {
                                                        }
                                                    }, RequestPasswordDialog.PasswordTypeSecond);
                                        } else {
                                            reallyAddKey(dialog, key);
                                        }
                                    }
                                }
                            });

                            dialog.getButton(Dialog.BUTTON1).setOnClickListener(new OnClickListener() {
                                @Override
                                public void onClick(View v) {

                                    try {
                                        MyRemoteWallet wallet = new MyRemoteWallet();

                                        wallet.addKey(key, address, null);

                                        Address to = application.determineSelectedAddress();

                                        if (to == null) {
                                            handler.post(new Runnable() {
                                                public void run() {
                                                    dialog.dismiss();
                                                }
                                            });

                                            return;
                                        }

                                        BigInteger baseFee = wallet.getBaseFee();

                                        wallet.simpleSendCoinsAsync(to.toString(), finalBalance.subtract(baseFee),
                                                MyRemoteWallet.FeePolicy.FeeForce, baseFee, new SendProgress() {

                                                    @Override
                                                    public boolean onReady(Transaction tx, BigInteger fee,
                                                            MyRemoteWallet.FeePolicy feePolicy, long priority) {
                                                        return true;
                                                    }

                                                    @Override
                                                    public void onSend(Transaction tx, String message) {
                                                        handler.post(new Runnable() {
                                                            public void run() {
                                                                dialog.dismiss();

                                                                longToast("Private Key Successfully Swept");
                                                            }
                                                        });
                                                    }

                                                    @Override
                                                    public ECKey onPrivateKeyMissing(String address) {
                                                        return null;
                                                    }

                                                    @Override
                                                    public void onError(final String message) {
                                                        handler.post(new Runnable() {
                                                            public void run() {
                                                                dialog.dismiss();

                                                                longToast(message);
                                                            }
                                                        });
                                                    }

                                                    @Override
                                                    public void onProgress(String message) {
                                                    }

                                                    @Override
                                                    public void onStart() {
                                                    }
                                                });

                                    } catch (final Exception e) {
                                        e.getLocalizedMessage();

                                        handler.post(new Runnable() {
                                            public void run() {
                                                dialog.dismiss();

                                                longToast(e.getLocalizedMessage());
                                            }
                                        });
                                    }
                                }
                            });
                        }
                    });
                } catch (final Exception e) {
                    e.printStackTrace();

                    handler.post(new Runnable() {
                        public void run() {
                            dialog.dismiss();

                            longToast(e.getLocalizedMessage());
                        }
                    });
                }
            }
        }.start();
    }

    private void reallyAddKey(final Dialog dialog, final ECKey key) {
        application.addKeyToWallet(key, key.toAddress(MainNetParams.get()).toString(), null, 0,
                new AddAddressCallback() {

                    public void onSavedAddress(String address) {
                        longToast("Private Key Successfully Imported");

                        dialog.dismiss();
                    }

                    public void onError(String reason) {
                        Toast.makeText(self, reason, Toast.LENGTH_LONG).show();

                        dialog.dismiss();
                    }
                });
    }

    public void handleScanPrivateKey(final String data) throws Exception {

        handler.postDelayed(new Runnable() {
            @Override
            public void run() {
                try {
                    final String format = WalletUtils.detectPrivateKeyFormat(data);

                    System.out.println("Scanned Private Key Format " + format);

                    if (format.equals("bip38")) {
                        RequestPasswordDialog.show(getSupportFragmentManager(), new SuccessCallback() {

                            public void onSuccess() {
                                String password = RequestPasswordDialog.getPasswordResult();

                                try {
                                    handleScanPrivateKeyPair(WalletUtils.parsePrivateKey(format, data, password));
                                } catch (Exception e) {
                                    longToast(e.getLocalizedMessage());
                                }
                            }

                            public void onFail() {

                            }
                        }, RequestPasswordDialog.PasswordTypePrivateKey);
                    } else {
                        handleScanPrivateKeyPair(WalletUtils.parsePrivateKey(format, data, null));
                    }
                } catch (Exception e) {
                    e.printStackTrace();
                }
            }
        }, 100);

    }

    public void handleAddWatchOnly(String data) throws Exception {

        String address;
        try {
            address = new Address(Constants.NETWORK_PARAMETERS, data).toString();
        } catch (Exception e) {
            try {
                BitcoinURI uri = new BitcoinURI(data);

                address = uri.getAddress().toString();
            } catch (Exception e1) {
                longToast(R.string.send_coins_fragment_receiving_address_error);

                return;
            }
        }

        final AlertDialog.Builder b = new AlertDialog.Builder(this);

        final String finalAddress = address;
        b.setPositiveButton(android.R.string.yes, new DialogInterface.OnClickListener() {
            @Override
            public void onClick(DialogInterface dialog, int which) {
                if (application.getRemoteWallet() == null)
                    return;

                try {
                    application.getRemoteWallet().addWatchOnly(finalAddress, "android_watch_only");

                    application.saveWallet(new SuccessCallback() {
                        @Override
                        public void onSuccess() {
                            //                     EditAddressBookEntryFragment.edit(getSupportFragmentManager(), finalAddress);
                        }

                        @Override
                        public void onFail() {
                        }
                    });
                } catch (Exception e) {
                    longToast(e.getLocalizedMessage());
                }
            }
        });

        b.setNegativeButton(android.R.string.no, new DialogInterface.OnClickListener() {
            @Override
            public void onClick(DialogInterface dialog, int which) {
                dialog.dismiss();
            }
        });

        b.setTitle("Watch Only Address");

        b.setMessage("Do you wish to add the Watch Only bitcoin address " + address
                + " to your wallet? \n\nYou will not be able to spend any funds in this address unless you have the private key stored elsewhere. You should never add a Watch Only address that you do not have the private key for.");

        b.show();
    }

}