Android Open Source - My-Wallet-Android Send Coins Fragment






From Project

Back to project page My-Wallet-Android.

License

The source code is released under:

GNU General Public License

If you think the Android project My-Wallet-Android 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

/*
 * Copyright 2011-2012 the original author or authors.
 */*w ww  .jav a 2  s. co m*/
 * 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 android.app.Activity;
import android.app.AlertDialog;
import android.content.Context;
import android.content.DialogInterface;
import android.content.Intent;
import android.database.Cursor;
import android.graphics.Color;
import android.net.Uri;
import android.os.Bundle;
import android.os.Handler;
import android.support.v4.app.DialogFragment;
import android.support.v4.app.Fragment;
import android.support.v4.app.FragmentTransaction;
import android.text.Editable;
import android.text.TextWatcher;
import android.view.LayoutInflater;
import android.view.View;
import android.view.View.OnClickListener;
import android.view.ViewGroup;
import android.widget.AutoCompleteTextView;
import android.widget.Button;
import android.widget.CursorAdapter;
import android.widget.TextView;
import android.widget.Toast;

import com.google.bitcoin.core.Address;
import com.google.bitcoin.core.AddressFormatException;
import com.google.bitcoin.core.ECKey;
import com.google.bitcoin.core.Transaction;
import com.google.bitcoin.core.Wallet.BalanceType;

import piuk.MyRemoteWallet;
import piuk.MyRemoteWallet.SendProgress;
import piuk.blockchain.R;
import piuk.blockchain.android.AddressBookProvider;
import piuk.blockchain.android.Constants;
import piuk.blockchain.android.WalletApplication;
import piuk.blockchain.android.WalletApplication.AddAddressCallback;
import piuk.blockchain.android.ui.CurrencyAmountView.Listener;
import piuk.blockchain.android.ui.SecondPasswordFragment.SuccessCallback;
import piuk.blockchain.android.util.WalletUtils;

/**
 * @author Andreas Schildbach
 */
public final class SendCoinsFragment extends Fragment
{
  private WalletApplication application;
  private final Handler handler = new Handler();
  private Runnable sentRunnable;

  private AutoCompleteTextView receivingAddressView;
  private View receivingAddressErrorView;
  private CurrencyAmountView amountView;
  private Button viewGo;
  private Button viewCancel;
  
  private State state = State.INPUT;

  private enum State
  {
    INPUT, SENDING, SENT
  }

  private final TextWatcher textWatcher = new TextWatcher()
  {
    public void afterTextChanged(final Editable s) {
      updateView();
    }

    public void beforeTextChanged(final CharSequence s, final int start, final int count, final int after)
    {
    }

    public void onTextChanged(final CharSequence s, final int start, final int before, final int count)
    {
    }
  };

  private final Listener listener = new Listener()
  {
    public void changed()
    {
      updateView();
    }

    public void done()
    {
      viewGo.requestFocusFromTouch();
    }
  };

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

    final Activity activity = getActivity();

    application = (WalletApplication) activity.getApplication();

  }



  @Override
  public View onCreateView(final LayoutInflater inflater, final ViewGroup container, final Bundle savedInstanceState)
  {
    final SendCoinsActivity activity = (SendCoinsActivity) getActivity();

    final View view = inflater.inflate(R.layout.send_coins_fragment, container);

    final BigInteger estimated = application.getWallet().getBalance(BalanceType.ESTIMATED);
    final BigInteger available = application.getWallet().getBalance(BalanceType.AVAILABLE);
    final BigInteger pending = estimated.subtract(available);
    
    Button instantDepositButton = (Button) view.findViewById(R.id.instant_deposit);
    
    instantDepositButton.setOnClickListener(new OnClickListener() {
      public void onClick(final View v) {
        WalletApplication application = (WalletApplication) activity.getApplication();
        
        //Don't allow deposits into new wallets
        if (application.getRemoteWallet().isNew())
          return;
        
        ECKey key = application.getWallet().keychain.get(0);
        
        Intent browserIntent = new Intent(Intent.ACTION_VIEW, Uri.parse("https://blockchain.info/deposit?address="+key.toAddress(Constants.NETWORK_PARAMETERS)));
        
        startActivity(browserIntent);
      }
    });

    receivingAddressView = (AutoCompleteTextView) view.findViewById(R.id.send_coins_receiving_address);
    receivingAddressView.setAdapter(new AutoCompleteAdapter(activity, null));
    receivingAddressView.addTextChangedListener(textWatcher);

    receivingAddressErrorView = view.findViewById(R.id.send_coins_receiving_address_error);

    final CurrencyAmountView availableView = (CurrencyAmountView) view.findViewById(R.id.send_coins_available);
    availableView.setAmount(available);

    final TextView pendingView = (TextView) view.findViewById(R.id.send_coins_pending);
    pendingView.setVisibility(pending.signum() > 0 ? View.VISIBLE : View.GONE);
    pendingView.setText(getString(R.string.send_coins_fragment_pending, WalletUtils.formatValue(pending)));

    amountView = (CurrencyAmountView) view.findViewById(R.id.send_coins_amount);
    amountView.setListener(listener);
    amountView.setContextButton(R.drawable.ic_input_calculator, new OnClickListener()
    {
      public void onClick(final View v)
      {
        final FragmentTransaction ft = getFragmentManager().beginTransaction();
        final Fragment prev = getFragmentManager().findFragmentByTag(AmountCalculatorFragment.FRAGMENT_TAG);
        if (prev != null)
          ft.remove(prev);
        ft.addToBackStack(null);
        final DialogFragment newFragment = new AmountCalculatorFragment(new AmountCalculatorFragment.Listener()
        {
          public void use(final BigInteger amount)
          {
            amountView.setAmount(amount);
          }
        });
        newFragment.show(ft, AmountCalculatorFragment.FRAGMENT_TAG);
      }
    });

    viewGo = (Button) view.findViewById(R.id.send_coins_go);
    viewGo.setOnClickListener(new OnClickListener()
    {      
      final SendProgress progress = new SendProgress() {
        public void onSend(final Transaction tx, final String message) {            
          handler.post(new Runnable() {
            public void run() {
              state = State.SENT;

              activity.longToast(message);
            
              Intent intent = activity.getIntent();
              intent.putExtra("tx", tx.getHash());
              activity.setResult(Activity.RESULT_OK, intent);
              
              activity.finish();
            
              updateView();
            }
          });

          try {
            Thread.sleep(2000);
          } catch (InterruptedException e) {
            e.printStackTrace();
          }

          application.syncWithMyWallet();
        }

        public void onError(final String message) {
          handler.post(new Runnable() {
            public void run() {

              System.out.println("On Error");
              
              if (message != null)
                activity.longToast(message);

              state = State.INPUT;

              updateView();
            }
          });              
        } 

        public void onProgress(final String message) {
          handler.post(new Runnable() {
            public void run() {
              state = State.SENDING;
              
              updateView();
            } 
          });
        }

        public boolean onReady(Transaction tx, BigInteger fee, long priority) {      
                    
          if ((priority < 57600000L || tx.bitcoinSerialize().length > 1024) && fee.compareTo(BigInteger.ZERO) == 0) {    

            handler.post(new Runnable() {
              public void run() {
                AlertDialog.Builder builder = new AlertDialog.Builder(getActivity());
                builder.setMessage(R.string.ask_for_fee)
                .setCancelable(false)
                .setPositiveButton(android.R.string.yes, new DialogInterface.OnClickListener() {
                  public void onClick(DialogInterface dialog, int id) {                                            
                    makeTransaction(true);
                  }
                })
                .setNegativeButton(android.R.string.no, new DialogInterface.OnClickListener() {
                  public void onClick(DialogInterface dialog, int id) {
                    dialog.cancel();
                  }
                });
                
                AlertDialog alert = builder.create();
                
                alert.show(); 
              }
            });
            
            handler.post(new Runnable() {
              public void run() {
                state = State.INPUT;
                updateView();
              }
            });
            
            return false;
          }

          return true;
        }

        
        public ECKey onPrivateKeyMissing(final String address) {
          
          System.out.println("onPrivateKeyMissing()");
          
          handler.post(new Runnable() {
            public void run() {
              AlertDialog.Builder builder = new AlertDialog.Builder(getActivity());
              builder.setMessage(getString(R.string.ask_for_private_key, address))
              .setCancelable(false)
              .setPositiveButton(android.R.string.yes, new DialogInterface.OnClickListener() {
                public void onClick(DialogInterface dialog, int id) {    
                  activity.scanPrivateKeyAddress = address;
                  
                  activity.showQRReader();
                }
              })
              .setNegativeButton(android.R.string.no, new DialogInterface.OnClickListener() {
                public void onClick(DialogInterface dialog, int id) {
                  
                  synchronized (activity.temporaryPrivateKeys) {
                    activity.temporaryPrivateKeys.notify();
                  }
                  
                  dialog.cancel();
                }
              });
              
              AlertDialog alert = builder.create();
              
              alert.show();
            }
          });
          
          try {
            synchronized (activity.temporaryPrivateKeys) {
              activity.temporaryPrivateKeys.wait();
            }
          } catch (InterruptedException e) {
            e.printStackTrace();
          }
          
          return activity.temporaryPrivateKeys.get(address);
        }
      };

      public void send(Address receivingAddress, BigInteger fee) {
        final BigInteger amount = amountView.getAmount();
        final WalletApplication application = (WalletApplication) getActivity().getApplication();
        
        application.getRemoteWallet().sendCoinsAsync(receivingAddress.toString(), amount, fee, progress);
      }
      
      public void makeTransaction(boolean forceFee) {
        try {
          final BigInteger fee = forceFee ? BigInteger.valueOf(500000) : BigInteger.ZERO;

          String addressString = receivingAddressView.getText().toString().trim();
          
          try {
            Address receivingAddress = new Address(Constants.NETWORK_PARAMETERS, addressString);
            
            send(receivingAddress, fee);
          } catch (AddressFormatException e) {

            if (isValidEmail(addressString)) {
              
              //Generate a new Archived Address
              application.addKeyToWallet(new ECKey(), "Sent To " + addressString, 2, new AddAddressCallback() {
                public void onSavedAddress(String address) {
                  try {
                    send(new Address(Constants.NETWORK_PARAMETERS, address), fee);
                  } catch (AddressFormatException e) {
                    e.printStackTrace();
                  } 
                }
                public void onError() {
                  System.out.println("Generate Address Failed");
                }  
              });
            }
          }
          
        } catch (Exception e) {
          e.printStackTrace();
        }
      }

      public void onClick(final View v)
      {
                
        MyRemoteWallet remoteWallet = application.getRemoteWallet();

        if (remoteWallet.isDoubleEncrypted() == false) {
          makeTransaction(false);
        } else {
          if (remoteWallet.temporySecondPassword == null) {
            SecondPasswordFragment.show(getFragmentManager(), new SuccessCallback() {

              public void onSuccess() {
                makeTransaction(false);
              }

              public void onFail() {
                Toast.makeText(application, R.string.send_no_password_error, Toast.LENGTH_LONG).show();
              } 
            });
          } else {
            makeTransaction(false);
          }
        }
      }
    });

    viewCancel = (Button) view.findViewById(R.id.send_coins_cancel);
    viewCancel.setOnClickListener(new OnClickListener()
    {
      public void onClick(final View v)
      {
        activity.setResult(Activity.RESULT_CANCELED);

        activity.finish();
      }
    });

    updateView();

    return view;
  }

  protected void onServiceBound()
  {
    System.out.println("service bound");
  }

  protected void onServiceUnbound()
  {
    System.out.println("service unbound");
  }

  @Override
  public void onDestroyView()
  {
    handler.removeCallbacks(sentRunnable);

    super.onDestroyView();
  }

  @Override
  public void onDestroy()
  {
    super.onDestroy();
  }

  public class AutoCompleteAdapter extends CursorAdapter
  {
    public AutoCompleteAdapter(final Context context, final Cursor c)
    {
      super(context, c);
    }

    @Override
    public View newView(final Context context, final Cursor cursor, final ViewGroup parent)
    {
      final LayoutInflater inflater = LayoutInflater.from(context);
      return inflater.inflate(R.layout.simple_dropdown_item_2line, parent, false);
    }

    @Override
    public void bindView(final View view, final Context context, final Cursor cursor)
    {
      final ViewGroup viewGroup = (ViewGroup) view;
      ((TextView) viewGroup.findViewById(android.R.id.text1)).setText(cursor.getString(cursor
          .getColumnIndexOrThrow(AddressBookProvider.KEY_LABEL)));
      ((TextView) viewGroup.findViewById(android.R.id.text2)).setText(cursor.getString(cursor
          .getColumnIndexOrThrow(AddressBookProvider.KEY_ADDRESS)));
    }

    @Override
    public CharSequence convertToString(final Cursor cursor)
    {
      return cursor.getString(cursor.getColumnIndexOrThrow(AddressBookProvider.KEY_ADDRESS));
    }

    @Override
    public Cursor runQueryOnBackgroundThread(final CharSequence constraint)
    {
      final Cursor cursor = getActivity().managedQuery(AddressBookProvider.CONTENT_URI, null, AddressBookProvider.SELECTION_QUERY,
          new String[] { constraint.toString() }, null);
      return cursor;
    }
  }

  private boolean isValidEmail(String email) {
        return android.util.Patterns.EMAIL_ADDRESS.matcher(email).matches();
  }
  
  private void updateView()
  {
    //0 = invalid, 1 = bitcoin, 2 = email
    int AddressType = 0;
    try
    {
      final String address = receivingAddressView.getText().toString().trim();
      if (address.length() > 0) {
        //try {
          new Address(Constants.NETWORK_PARAMETERS, address);
          AddressType = 1;
          receivingAddressErrorView.setVisibility(View.GONE);
        //} catch (AddressFormatException e) {
          //if (isValidEmail(address)) {
          //  AddressType = 2;
          //  receivingAddressErrorView.setVisibility(View.GONE);
          //}
        //}
      }
    }
    catch (final Exception x)
    {
      receivingAddressErrorView.setVisibility(View.VISIBLE);
    }

    final BigInteger amount = amountView.getAmount();
    final boolean validAmount = amount != null && amount.signum() > 0;

    receivingAddressView.setEnabled(state == State.INPUT);

    amountView.setEnabled(state == State.INPUT);

    viewGo.setEnabled(state == State.INPUT && AddressType != 0 && validAmount);
    if (state == State.INPUT)
      viewGo.setText(R.string.send_coins_fragment_button_send);
    else if (state == State.SENDING)
      viewGo.setText(R.string.send_coins_sending_msg);
    else if (state == State.SENT)
      viewGo.setText(R.string.send_coins_sent_msg);

    viewCancel.setEnabled(state != State.SENDING);
    viewCancel.setText(state != State.SENT ? R.string.button_cancel : R.string.send_coins_fragment_button_back);
  }

  public void update(final String receivingAddress, final BigInteger amount)
  {
    receivingAddressView.setText(receivingAddress);
    flashReceivingAddress();

    if (amount != null)
      amountView.setAmount(amount);

    if (receivingAddress != null && amount == null)
      amountView.requestFocus();

    updateView();
  }

  private void showAddAddressDialog(final String address)
  {
    final Activity activity = getActivity();
    final AlertDialog.Builder builder = new AlertDialog.Builder(activity);
    builder.setMessage(R.string.send_coins_add_address_dialog_title);
    builder.setPositiveButton(R.string.send_coins_add_address_dialog_button_add, new DialogInterface.OnClickListener()
    {
      public void onClick(final DialogInterface dialog, final int id)
      {
        EditAddressBookEntryFragment.edit(getFragmentManager(), address.toString());
      }
    });
    builder.setNegativeButton(R.string.button_dismiss, null);
    builder.show();
  }

  private Runnable resetColorRunnable = new Runnable()
  {
    public void run()
    {
      receivingAddressView.setTextColor(Color.parseColor("#888888"));
    }
  };

  public void flashReceivingAddress()
  {
    receivingAddressView.setTextColor(Color.parseColor("#cc5500"));
    handler.removeCallbacks(resetColorRunnable);
    handler.postDelayed(resetColorRunnable, 500);
  }
}




Java Source Code List

piuk.BitcoinAddress.java
piuk.BitcoinScript.java
piuk.Hash.java
piuk.MyBlockChain.java
piuk.MyRemoteWallet.java
piuk.MyTransactionConfidence.java
piuk.MyTransactionInput.java
piuk.MyTransactionOutPoint.java
piuk.MyTransactionOutput.java
piuk.MyTransaction.java
piuk.MyWallet.java
piuk.blockchain.android.AddressBookProvider.java
piuk.blockchain.android.BlockchainService.java
piuk.blockchain.android.Constants.java
piuk.blockchain.android.DetermineFirstSeenThread.java
piuk.blockchain.android.ExchangeRatesProvider.java
piuk.blockchain.android.WalletApplication.java
piuk.blockchain.android.WalletBalanceWidgetProvider.java
piuk.blockchain.android.ui.AbstractWalletActivity.java
piuk.blockchain.android.ui.AmountCalculatorFragment.java
piuk.blockchain.android.ui.CurrencyAmountView.java
piuk.blockchain.android.ui.CurrencyCodeDrawable.java
piuk.blockchain.android.ui.EditAddressBookEntryFragment.java
piuk.blockchain.android.ui.ExchangeRatesFragment.java
piuk.blockchain.android.ui.NewAccountFragment.java
piuk.blockchain.android.ui.PairWalletActivity.java
piuk.blockchain.android.ui.PreferencesActivity.java
piuk.blockchain.android.ui.RequestCoinsActivity.java
piuk.blockchain.android.ui.RequestCoinsFragment.java
piuk.blockchain.android.ui.SecondPasswordFragment.java
piuk.blockchain.android.ui.SendCoinsActivity.java
piuk.blockchain.android.ui.SendCoinsFragment.java
piuk.blockchain.android.ui.SendingAddressesFragment.java
piuk.blockchain.android.ui.TransactionActivity.java
piuk.blockchain.android.ui.TransactionFragment.java
piuk.blockchain.android.ui.WalletActivity.java
piuk.blockchain.android.ui.WalletAddressesFragment.java
piuk.blockchain.android.ui.WalletBalanceFragment.java
piuk.blockchain.android.ui.WalletTransactionsFragment.java
piuk.blockchain.android.ui.WelcomeFragment.java
piuk.blockchain.android.util.ActionBarFragment.java
piuk.blockchain.android.util.Base43.java
piuk.blockchain.android.util.CircularProgressView.java
piuk.blockchain.android.util.ErrorReporter.java
piuk.blockchain.android.util.IOUtils.java
piuk.blockchain.android.util.Iso8601Format.java
piuk.blockchain.android.util.NfcTools.java
piuk.blockchain.android.util.QrDialog.java
piuk.blockchain.android.util.ViewPagerTabs.java
piuk.blockchain.android.util.WalletUtils.java