Android Open Source - My-Wallet-Android Wallet Application






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.
 */*ww  w  .  ja va 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;

import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.PrintStream;
import java.net.CookieHandler;
import java.net.CookieManager;
import java.util.ArrayList;
import java.util.Map.Entry;
import java.util.Timer;
import java.util.TimerTask;

import org.apache.commons.io.IOUtils;

import piuk.BitcoinAddress;
import piuk.Hash;
import piuk.MyRemoteWallet;
import piuk.blockchain.R;
import piuk.blockchain.android.util.ErrorReporter;

import android.app.Application;
import android.appwidget.AppWidgetManager;
import android.appwidget.AppWidgetProviderInfo;
import android.content.ComponentName;
import android.content.Context;
import android.content.Intent;
import android.content.ServiceConnection;
import android.content.SharedPreferences;
import android.content.pm.PackageManager.NameNotFoundException;
import android.net.Uri;
import android.os.Handler;
import android.os.IBinder;
import android.preference.PreferenceManager;
import android.widget.Toast;

import com.google.bitcoin.core.AbstractWalletEventListener;
import com.google.bitcoin.core.Address;
import com.google.bitcoin.core.ECKey;
import com.google.bitcoin.core.Wallet;
import com.google.bitcoin.core.WalletEventListener;

/**
 * @author Andreas Schildbach
 */
public class WalletApplication extends Application
{
  private MyRemoteWallet remoteWallet;

  private final Handler handler = new Handler();
  private BlockchainService service;
  private Timer timer ;
  public boolean hasDecryptionError = false;

  private final ServiceConnection serviceConnection = new ServiceConnection()
  {
    public void onServiceConnected(final ComponentName name, final IBinder binder) {
      service = ((BlockchainService.LocalBinder) binder).getService();
    } 

    public void onServiceDisconnected(final ComponentName name) { }
  };

  final private WalletEventListener walletEventListener = new AbstractWalletEventListener()
  {
    @Override
    public void onChange(Wallet wallet)
    {
      handler.post(new Runnable()
      {
        public void run()
        {
          try {
            localSaveWallet();
          } catch (Exception e) {
            e.printStackTrace();
          }
        }
      });
    }
  };

  public boolean isNewWallet() {
    return remoteWallet.isNew();
  }

  public void connect() {
    if (timer != null) {
      try {
        timer.cancel();

        timer.purge();

        timer = null;
      } catch (Exception e) {
        e.printStackTrace();
      }
    }

    bindService(new Intent(this, BlockchainService.class), serviceConnection, Context.BIND_AUTO_CREATE);
  }

  public void diconnectSoon() {
    try {
      if (timer == null) {
        timer = new Timer();

        timer.schedule(new TimerTask() {

          @Override
          public void run() {
            handler.post(new Runnable() {
              public void run() {
                try {
                  unbindService(serviceConnection);
                } catch (Exception e) {
                  e.printStackTrace();
                }
              }
            });
          }
        }, 2000);
      }
    } catch (Exception e) {
      e.printStackTrace();
    }
  }

  @Override
  public void onCreate()
  {
    super.onCreate();

    ErrorReporter.getInstance().init(this);

    try {
      //Need to save session cookie for kaptcha
          @SuppressWarnings("rawtypes")
      Class aClass = getClass().getClassLoader().loadClass("java.net.CookieManager");

          CookieManager cookieManager = (CookieManager) aClass.newInstance();
          
      CookieHandler.setDefault(cookieManager);
    } catch (Exception e) {
      e.printStackTrace();
    }

    //If the User has a saved GUID then we can restore the wallet
    if (getGUID() != null) {

      //Try and read the wallet from the local cache
      if (readLocalWallet()) {
        System.out.println("Read local");

        if(!readLocalMultiAddr())
          doMultiAddr();

      } else {
        Toast.makeText(WalletApplication.this, R.string.toast_downloading_wallet, Toast.LENGTH_LONG).show();

        loadRemoteWallet();
      } 
    }

    //Otherwise wither first load or an error
    if (remoteWallet == null) {
      try {
        this.remoteWallet = new MyRemoteWallet();

        Toast.makeText(WalletApplication.this, R.string.toast_generated_new_wallet, Toast.LENGTH_LONG).show();
      } catch (Exception e) {
        throw new Error("Could not create wallet ", e);
      }
    }

    getWallet().addEventListener(walletEventListener);

    connect();
  }

  public Wallet getWallet() {
    return remoteWallet.getBitcoinJWallet();
  }

  public MyRemoteWallet getRemoteWallet() {
    return remoteWallet;
  }

  public String getPassword() {
    return PreferenceManager.getDefaultSharedPreferences(this).getString("password", null);  
  }

  public String getGUID() {
    return PreferenceManager.getDefaultSharedPreferences(this).getString("guid", null);  
  }

  public String getSharedKey() {
    return PreferenceManager.getDefaultSharedPreferences(this).getString("sharedKey", null);  
  }

  public void notifyWidgets()
  {
    final Context context = getApplicationContext();
 
    // notify widgets
    final AppWidgetManager appWidgetManager = AppWidgetManager.getInstance(context);
    for (final AppWidgetProviderInfo providerInfo : appWidgetManager.getInstalledProviders())
    {
      // limit to own widgets
      if (providerInfo.provider.getPackageName().equals(context.getPackageName()))
      {
        final Intent intent = new Intent(AppWidgetManager.ACTION_APPWIDGET_UPDATE);
        intent.putExtra(AppWidgetManager.EXTRA_APPWIDGET_IDS, appWidgetManager.getAppWidgetIds(providerInfo.provider));
        context.sendBroadcast(intent);
      }
    }
  }

  public synchronized String readExceptionLog()  {
    try {
      FileInputStream multiaddrCacheFile = openFileInput(Constants.EXCEPTION_LOG);

      return IOUtils.toString(multiaddrCacheFile);
      
    } catch (IOException e1) {
      e1.printStackTrace();
      
      return null;
    }
  }

  public synchronized void writeException(Exception e) {
    try {
      FileOutputStream file = openFileOutput(Constants.EXCEPTION_LOG, MODE_APPEND);

      PrintStream stream = new PrintStream(file);

      e.printStackTrace(stream);

      stream.close();

      file.close();
    } catch (IOException e1) {
      e1.printStackTrace();
    }
  }

  public synchronized void writeMultiAddrCache(String repsonse) {
    try {
      FileOutputStream file = openFileOutput(remoteWallet.getGUID() + Constants.MULTIADDR_FILENAME, Constants.WALLET_MODE);


      file.write(repsonse.getBytes());

      file.close();
    } catch (IOException e) {
      // TODO Auto-generated catch block
      e.printStackTrace();
    }
  }

  public synchronized void syncWithMyWallet() {  

    System.out.println("syncWithMyWallet()");
    
    //Can't sync a new wallet
    if (remoteWallet.isNew())
      return;

    loadRemoteWallet();
  }

  public void doMultiAddr() {
    new Thread(new Runnable() {
      public void run() {
        try {        
          writeMultiAddrCache(remoteWallet.doMultiAddr());

          handler.post(new Runnable()   {
            public void run() {
              notifyWidgets();
            }
          });
        } catch (Exception e) {
          e.printStackTrace();

          writeException(e);

          handler.post(new Runnable() {
            public void run() {
              Toast.makeText(WalletApplication.this, R.string.toast_error_downloading_transactions, Toast.LENGTH_LONG).show();
            }
          });
        }
      }
    }).start();
  }

  public synchronized void loadRemoteWallet() {      
    new Thread(new Runnable() {
      public void run() {
        String payload = null; 
        
        System.out.println("loadRemoteWallet()");

        //Retry 3 times
        for (int ii = 0; ii < 3; ++ii) {
          try {
            if (remoteWallet == null)
              payload = MyRemoteWallet.getWalletPayload(getGUID(), getSharedKey());
            else
              payload = MyRemoteWallet.getWalletPayload(getGUID(), getSharedKey(), remoteWallet.getChecksum());
          } catch (final Exception e) {
            e.printStackTrace();

            writeException(e);

            handler.post(new Runnable() {
              public void run() {
                Toast.makeText(WalletApplication.this, e.getLocalizedMessage(), Toast.LENGTH_SHORT).show();
              }
            });

            try {
              Thread.sleep(10000);
            } catch (InterruptedException e1) {
              e1.printStackTrace();
            }
          }
        }


        //Payload will return null when not modified
        if (payload != null) {

          try {
            FileOutputStream file = openFileOutput(Constants.WALLET_FILENAME, Constants.WALLET_MODE);
            file.write(payload.getBytes("UTF-8"));
            file.close();
          } catch (Exception e) {
            e.printStackTrace();
          }

          try {
            
            if (remoteWallet == null) {
              remoteWallet = new MyRemoteWallet(payload, getPassword());
            } else {
              remoteWallet.setTemporyPassword(getPassword());

              remoteWallet.setPayload(payload);
            }

            hasDecryptionError = false; 
            
            getWallet().invokeOnChange();

          } catch (Exception e) {
            hasDecryptionError = true; 
            
            getWallet().invokeOnChange();
            
            e.printStackTrace();

            writeException(e);

            handler.post(new Runnable()
            {
              public void run() {
                Toast.makeText(WalletApplication.this, R.string.toast_wallet_decryption_failed, Toast.LENGTH_LONG).show();
              }
            });

            return;
          }

          try {

            //Copy our labels into the address book
            if (remoteWallet.getLabelMap() != null) {
              for(Entry<String, String> labelObj : remoteWallet.getLabelMap().entrySet()) {
                AddressBookProvider.setLabel(getContentResolver(), labelObj.getKey(), labelObj.getValue());
              }
            }
          } catch (Exception e) {
            e.printStackTrace();

            writeException(e);
          }
        }


        try {
          doMultiAddr();
        } catch (Exception e) {
          e.printStackTrace();

          writeException(e);

          handler.post(new Runnable()
          {
            public void run()
            {
              Toast.makeText(WalletApplication.this, R.string.toast_error_syncing_wallet, Toast.LENGTH_LONG).show();
            }
          });
        }
      }
    }).start();
  }

  public static interface AddAddressCallback {
    public void onSavedAddress(String address);
    public void onError();
  }
  
  public void addKeyToWallet(ECKey key, String label, int tag, final AddAddressCallback callback)
  {
    try {
      remoteWallet.addKey(key, label);
      
      final String address = new BitcoinAddress(new Hash(key.getPubKeyHash()), (short) 0).toString();
      
      if (tag != 0) {
        remoteWallet.setTag(address, tag);
      }
    
      new Thread(){
        @Override
        public void run() {
          try {
            remoteWallet.remoteSave();

            handler.post(new Runnable()
            {
              public void run()
              {
                callback.onSavedAddress(address);
                
                notifyWidgets();
              }
            });

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

            writeException(e);

            handler.post(new Runnable()
            {
              public void run()
              {
                callback.onError();
                
                Toast.makeText(WalletApplication.this, R.string.toast_error_syncing_wallet, Toast.LENGTH_LONG).show();
              }
            });
          }
        }
      }.start();

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

      writeException(e);
    }

    localSaveWallet();
  }

  public void setAddressLabel(String address, String label) {
    try {
      remoteWallet.addLabel(address, label);

      new Thread(){
        @Override
        public void run() {
          try {
            remoteWallet.remoteSave();
          } catch (Exception e) {
            e.printStackTrace();

            writeException(e);

            handler.post(new Runnable()
            {
              public void run()
              {
                Toast.makeText(WalletApplication.this, R.string.toast_error_syncing_wallet, Toast.LENGTH_LONG).show();
              }
            });
          }
        }
      }.start();
    } catch (Exception e) {
      e.printStackTrace();

      Toast.makeText(WalletApplication.this, R.string.error_setting_label, Toast.LENGTH_LONG).show();
    }
  }

  public boolean readLocalMultiAddr() {
    try {
      //Restore the multi address cache
      FileInputStream multiaddrCacheFile = openFileInput(remoteWallet.getGUID() +  Constants.MULTIADDR_FILENAME);

      String multiAddr =  IOUtils.toString(multiaddrCacheFile);

      remoteWallet.parseMultiAddr(multiAddr);

      return true;

    } catch (Exception e) {
      writeException(e);

      e.printStackTrace();

      return false;
    }
  }

  public boolean readLocalWallet() {
    try {
      //Read the wallet from local file
      FileInputStream file = openFileInput(Constants.WALLET_FILENAME);

      String payload = null;

      payload = IOUtils.toString(file, "UTF-8");

      this.remoteWallet = new MyRemoteWallet(payload, getPassword());

      return true;
    } catch (Exception e) {
      writeException(e);

      e.printStackTrace();

      handler.post(new Runnable()
      {
        public void run()
        {
          Toast.makeText(WalletApplication.this, R.string.toast_wallet_decrypt_failed, Toast.LENGTH_LONG).show();
        }
      });
    }

    return false;
  }

  public void localSaveWallet()
  {
    try {
      FileOutputStream file = openFileOutput(Constants.LOCAL_WALLET_FILENAME, Constants.WALLET_MODE);

      file.write(remoteWallet.getPayload().getBytes());

      file.close();
    } catch (Exception e) {
      e.printStackTrace();
    }
  } 

  public Address determineSelectedAddress()
  {
    final ArrayList<ECKey> keychain = getWallet().keychain;

    if (keychain.size() == 0)
      return null;

    final SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(this);
    final String defaultAddress = keychain.get(0).toAddress(Constants.NETWORK_PARAMETERS).toString();
    final String selectedAddress = prefs.getString(Constants.PREFS_KEY_SELECTED_ADDRESS, defaultAddress);

    // sanity check
    for (final ECKey key : keychain)
    {
      final Address address = key.toAddress(Constants.NETWORK_PARAMETERS);
      if (address.toString().equals(selectedAddress))
        return address;
    }

    return null;
  }

  public final int applicationVersionCode()
  {
    try
    {
      return getPackageManager().getPackageInfo(getPackageName(), 0).versionCode;
    }
    catch (NameNotFoundException x)
    {
      return 0;
    }
  }

  public final String applicationVersionName()
  {
    try
    {
      return getPackageManager().getPackageInfo(getPackageName(), 0).versionName;
    }
    catch (NameNotFoundException x)
    {
      return "unknown";
    }
  }
}




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