package com.bitcoinlabs.android;
import java.util.Hashtable;
import android.app.Activity;
import android.content.Context;
import android.content.Intent;
import android.content.SharedPreferences;
import android.content.SharedPreferences.Editor;
import android.graphics.Bitmap;
import android.graphics.drawable.BitmapDrawable;
import android.media.AudioManager;
import android.media.ToneGenerator;
import android.net.Uri;
import android.net.Uri.Builder;
import android.os.AsyncTask;
import android.os.Bundle;
import android.view.KeyEvent;
import android.view.Menu;
import android.view.MenuInflater;
import android.view.MenuItem;
import android.view.View;
import android.view.View.OnFocusChangeListener;
import android.view.inputmethod.InputMethodManager;
import android.widget.EditText;
import android.widget.ImageView;
import android.widget.TextView;
import android.widget.TextView.OnEditorActionListener;
import com.google.bitcoin.core.Address;
import com.google.zxing.BarcodeFormat;
import com.google.zxing.EncodeHintType;
import com.google.zxing.WriterException;
import com.google.zxing.common.BitMatrix;
import com.google.zxing.qrcode.QRCodeWriter;
public class Receive extends Activity {
public static final String RECEIVE_VALUE = "RECEIVE_VALUE";
private static final int WHITE = 0xFFFFFFFF;
private static final int BLACK = 0xFF000000;
QRCodeWriter qrCodeWriter = new QRCodeWriter();
protected Address btcAddress;
private EditText amount;
private EditText label;
private EditText message;
private TextView btcAddressView;
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setTitle("Receive Bitcoin");
setContentView(R.layout.receive);
btcAddressView = (TextView)findViewById(R.id.rcv_btcAddress);
amount = (EditText)findViewById(R.id.rcv_amount);
label = (EditText)findViewById(R.id.rcv_label);
message = (EditText)findViewById(R.id.rcv_message);
final SharedPreferences preferences = getPreferences(MODE_PRIVATE);
String receiveLabelValue = preferences.getString("rcv_label", null);
label.setText(receiveLabelValue);
amount.setSelectAllOnFocus(true);
btcAddressView.setText("Address:\n" + "Generating new key...");
new GenerateKeyTask().execute();
OnEditorActionListener onEditorActionListener = new OnEditorActionListener() {
public boolean onEditorAction(TextView v, int actionId, KeyEvent event) {
InputMethodManager imm = (InputMethodManager)getSystemService(Context.INPUT_METHOD_SERVICE);
imm.hideSoftInputFromWindow(v.getWindowToken(), 0);
if (v == label) {
Editor edit = preferences.edit().
putString("rcv_label", label.getText().toString());
edit.commit();
}
updateQRCode();
return true;
}
};
amount.setOnEditorActionListener(onEditorActionListener);
label.setOnEditorActionListener(onEditorActionListener);
message.setOnEditorActionListener(onEditorActionListener);
OnFocusChangeListener onFocusChangeListener = new OnFocusChangeListener() {
public void onFocusChange(View v, boolean hasFocus) {
if (!hasFocus) {
updateQRCode();
}
}
};
amount.setOnFocusChangeListener(onFocusChangeListener);
label.setOnFocusChangeListener(onFocusChangeListener);
message.setOnEditorActionListener(onEditorActionListener);
updateQRCode();
}
@Override
public boolean onCreateOptionsMenu(Menu menu) {
MenuInflater inflater = getMenuInflater();
inflater.inflate(R.menu.rcv_menu, menu);
return true;
}
@Override
public boolean onOptionsItemSelected(MenuItem item) {
// Handle item selection
switch (item.getItemId()) {
case R.id.balance:
finish();
return true;
case R.id.dtmf:
new DTMFTask().execute(btcAddress);
return true;
default:
return super.onOptionsItemSelected(item);
}
}
private void updateQRCode() {
if (btcAddress != null) {
btcAddressView.setText("Address:\n" + btcAddress);
try {
Double receiveAmount = null;
try {
receiveAmount = Double.parseDouble(amount.getText().toString());
} catch (NumberFormatException e) {/*let receiveAmount be null*/}
showQrBitmap(btcAddress.toString(), receiveAmount, label.getText().toString(), message.getText().toString());
} catch (WriterException e) {
e.printStackTrace();
}
}
}
public static void callMe(Context c) {
final Intent intent = new Intent(c, Receive.class);
c.startActivity(intent);
}
private void showQrBitmap(String btcAddress, Double amount, String label, String message) throws WriterException {
Builder builder = new Uri.Builder();
builder.scheme("bitcoin");
builder.authority(btcAddress);
if (amount != null) {
builder.appendQueryParameter("amount", amount+"");
}
if (label != null && label.length() > 0) {
builder.appendQueryParameter("label", label);
}
if (message != null && message.length() > 0) {
builder.appendQueryParameter("message", message);
}
String btcUri = builder.build().toString().replaceAll("//", "");
Hashtable<EncodeHintType, Object> hints = new Hashtable<EncodeHintType, Object>(2);
hints.put(EncodeHintType.CHARACTER_SET, "UTF-8");
BitMatrix result = qrCodeWriter.encode(btcUri, BarcodeFormat.QR_CODE, 0 , 0, hints);
int width = result.getWidth();
int height = result.getHeight();
int[] pixels = new int[width * height];
// All are 0, or black, by default
for (int y = 0; y < height; y++) {
int offset = y * width;
for (int x = 0; x < width; x++) {
pixels[offset + x] = result.get(x, y) ? BLACK : WHITE;
}
}
Bitmap bitmap = Bitmap.createBitmap(width, height, Bitmap.Config.ARGB_8888);
bitmap.setPixels(pixels, 0, width, 0, 0, width, height);
BitmapDrawable drawable = new BitmapDrawable(bitmap);
drawable.setFilterBitmap(false);
final ImageView qrDisplay = (ImageView) findViewById(R.id.qrDisplay);
qrDisplay.setImageDrawable(drawable);
}
private void playTones(Address address) {
ToneGenerator toneGenerator = new ToneGenerator(AudioManager.STREAM_MUSIC, ToneGenerator.MAX_VOLUME);
for (byte b : address.asBytes()) {
toneGenerator.startTone(b >> 4, 45);
try {Thread.sleep(50);} catch (InterruptedException e) {}
toneGenerator.startTone(b & 0x0F, 45);
try {Thread.sleep(50);} catch (InterruptedException e) {}
}
toneGenerator.stopTone();
}
private class GenerateKeyTask extends AsyncTask<Void, Void, Address> {
@Override
protected Address doInBackground(Void... ignored) {
WalletOpenHelper wallet = new WalletOpenHelper(getApplicationContext());
//Address btcAddress = wallet.newKey();
//TODO come up with a more sane key gen/recycle process
Address unusedAddress = wallet.getUnusedAddress();
return unusedAddress;
}
@Override
protected void onPostExecute(Address generatedBtcAddress) {
Receive.this.btcAddress = generatedBtcAddress;
updateQRCode();
}
}
private class DTMFTask extends AsyncTask<Address, Void, Void> {
@Override
protected Void doInBackground(Address... btcAddresses) {
Address btcAddress = btcAddresses[0];
playTones(btcAddress);
return null;
}
}
}