package com.bitcoinandroid;
import java.math.BigInteger;
import java.util.ArrayList;
import android.app.Activity;
import android.app.Notification;
import android.app.NotificationManager;
import android.app.PendingIntent;
import android.content.Context;
import android.content.Intent;
import android.content.SharedPreferences;
import android.graphics.Color;
import android.os.AsyncTask;
import android.os.Bundle;
import android.util.Log;
import android.view.Gravity;
import android.view.Menu;
import android.view.MenuInflater;
import android.view.MenuItem;
import android.view.View;
import android.view.ViewGroup.LayoutParams;
import android.widget.Button;
import android.widget.ProgressBar;
import android.widget.TableLayout;
import android.widget.TableRow;
import android.widget.TextView;
import com.google.bitcoin.core.Address;
import com.google.bitcoin.core.ScriptException;
import com.google.bitcoin.core.Transaction;
import com.google.bitcoin.core.TransactionInput;
import com.google.bitcoin.core.Utils;
import com.google.bitcoin.core.Wallet;
import com.google.bitcoin.core.Wallet.BalanceType;
import com.google.bitcoin.core.WalletEventListener;
import com.google.zxing.client.android.CaptureActivity;
public class BitcoinWallet extends Activity {
BackgroundTask backgroundTask;
ProgressBar spinner;
ApplicationState appState;
SharedPreferences settings;
/** Called when the activity is first created. */
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
appState = ((ApplicationState) getApplication());
settings = getPreferences(MODE_PRIVATE);
setContentView(R.layout.main);
Button sendButton = (Button) this.findViewById(R.id.send_button);
sendButton.setOnClickListener(new View.OnClickListener() {
public void onClick(View v) {
startActivity(new Intent(BitcoinWallet.this, CaptureActivity.class));
}
});
Button receiveButton = (Button) this.findViewById(R.id.receive_button);
receiveButton.setOnClickListener(new View.OnClickListener() {
public void onClick(View v) {
startActivity(new Intent(BitcoinWallet.this, ReceiveMoney.class));
}
});
updateUI();
updateBlockChain();
appState.wallet.addEventListener(new WalletEventListener() {
public void onCoinsReceived(Wallet w, final Transaction tx, BigInteger prevBalance, BigInteger newBalance) {
runOnUiThread(new Runnable() {
public void run() {
moneyReceived(tx);
Log.d("Wallet", "COINS WE RECEIVED HAVE BEEN CONFIRMED");
}
});
}
public void onCoinsSent(Wallet w, final Transaction tx, BigInteger prevBalance, BigInteger newBalance) {
runOnUiThread(new Runnable() {
public void run() {
updateUI();
appState.saveWallet();
Log.d("Wallet", "COINS WE SENT HAVE BEEN CONFIRMED");
}
});
}
public void onPendingCoinsReceived(Wallet w, final Transaction tx) {
runOnUiThread(new Runnable() {
public void run() {
moneyReceived(tx);
Log.d("Wallet", "PENDING COINS RECEIVED ");
}
});
}
});
}
private void updateBlockChain() {
if (backgroundTask == null || backgroundTask.getStatus() != AsyncTask.Status.RUNNING) {
backgroundTask = new BackgroundTask(this);
backgroundTask.execute();
((ProgressBar)findViewById(R.id.progressBar)).setVisibility(View.VISIBLE);
} else if (backgroundTask.getStatus() == AsyncTask.Status.RUNNING){
backgroundTask.downloadingProgress.show();
}
}
public void hideSpinner() {
((ProgressBar)findViewById(R.id.progressBar)).setVisibility(View.GONE);
}
private void updateUI() {
if (appState == null || appState.wallet == null) {
return;
}
TextView balance = (TextView) findViewById(R.id.balanceLabel);
balance.setText("BTC " + Utils.bitcoinValueToFriendlyString(appState.wallet.getBalance(BalanceType.ESTIMATED)));
TableLayout tl = (TableLayout) findViewById(R.id.transactions);
tl.removeAllViews();
ArrayList<Transaction> transactions = appState.wallet.getAllTransactions();
// Show only the first 100 transaction
if (transactions.size() > 100)
transactions = (ArrayList<Transaction>)transactions.subList(0, 99);
for (Transaction tx : transactions) {
addRowForTransaction(tl, tx);
}
}
private void addRowForTransaction(TableLayout tl, Transaction tx) {
// Create a new row to be added.
TableRow tr = new TableRow(this);
// Create a Button to be the row-content.
TextView description = new TextView(this);
TextView amount = new TextView(this);
description.setTextSize(15);
amount.setTextSize(15);
String text = "";
// check if pending
if (appState.wallet.pending.containsKey(tx.getHash())) {
text += "(Pending) ";
description.setTextColor(Color.GRAY);
amount.setTextColor(Color.GRAY);
} else {
description.setTextColor(Color.BLACK);
amount.setTextColor(Color.BLACK);
}
// check if sent or received
try {
if (tx.sent(appState.wallet)) {
text += "Sent to " + tx.outputs.get(0).getScriptPubKey().getToAddress();
amount.setText("-" + Utils.bitcoinValueToFriendlyString(tx.amount(appState.wallet)));
} else {
text += "Received from " + tx.getInputs().get(0).getFromAddress();
amount.setText("+" + Utils.bitcoinValueToFriendlyString(tx.amount(appState.wallet)));
}
} catch (ScriptException e) {
// don't display this transaction
return;
}
if (text.length() > 30) {
text = text.substring(0, 29) + "...";
}
description.setText(text);
description.setPadding(0, 3, 0, 3);
amount.setPadding(0, 3, 0, 3);
amount.setGravity(Gravity.RIGHT);
tr.addView(description);
tr.addView(amount);
tl.addView(tr, new TableLayout.LayoutParams(LayoutParams.FILL_PARENT, LayoutParams.WRAP_CONTENT));
}
public boolean onCreateOptionsMenu(Menu menu) {
MenuInflater inflater = getMenuInflater();
inflater.inflate(R.menu.main, menu);
return true;
}
@Override
public boolean onOptionsItemSelected(MenuItem item) {
// Handle item selection
switch (item.getItemId()) {
case R.id.refresh_menu_item:
updateBlockChain();
updateUI();
return true;
default:
return super.onOptionsItemSelected(item);
}
}
private void moneyReceived(Transaction tx) {
appState.saveWallet();
updateUI();
if (appState.notifiedUserOfTheseTransactions.contains(tx.getHash())) {
//only call once per transaction
//this could be called multiple times by separate peers
return;
} else {
appState.notifiedUserOfTheseTransactions.add(tx.getHash());
}
TransactionInput input = tx.getInputs().get(0);
Address from;
try {
from = input.getFromAddress();
} catch (ScriptException e) {
return;
}
BigInteger value = tx.getValueSentToMe(appState.wallet);
Log.d("Wallet", "Received " + Utils.bitcoinValueToFriendlyString(value) + " from " + from.toString());
String ticker = Utils.bitcoinValueToFriendlyString(value) + " Bitcoins Received!";
String ns = Context.NOTIFICATION_SERVICE;
NotificationManager notificationManager = (NotificationManager) getSystemService(ns);
Notification notification = new Notification(R.drawable.my_notification_icon, ticker, System.currentTimeMillis());
notification.defaults |= Notification.DEFAULT_SOUND;
notification.defaults |= Notification.DEFAULT_VIBRATE;
notification.flags |= Notification.FLAG_AUTO_CANCEL;
Context context = getApplicationContext();
CharSequence contentTitle = ticker;
CharSequence contentText = "From " + from.toString();
Intent notificationIntent = new Intent(this, BitcoinWallet.class);
//don't open a new one if it's already on top
notificationIntent.setFlags(Intent.FLAG_ACTIVITY_SINGLE_TOP);
PendingIntent contentIntent = PendingIntent.getActivity(this, 0, notificationIntent, 0);
notification.setLatestEventInfo(context, contentTitle, contentText, contentIntent);
notificationManager.notify(1, notification);
}
}